"Fossies" - the Fresh Open Source Software Archive

Member "recoll-1.26.3/qtgui/advsearch_w.cpp" (4 Sep 2019, 17631 Bytes) of package /linux/privat/recoll-1.26.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "advsearch_w.cpp" see the Fossies "Dox" file reference documentation.

    1 /* Copyright (C) 2005 J.F.Dockes 
    2  *   This program is free software; you can redistribute it and/or modify
    3  *   it under the terms of the GNU General Public License as published by
    4  *   the Free Software Foundation; either version 2 of the License, or
    5  *   (at your option) any later version.
    6  *
    7  *   This program is distributed in the hope that it will be useful,
    8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
    9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10  *   GNU General Public License for more details.
   11  *
   12  *   You should have received a copy of the GNU General Public License
   13  *   along with this program; if not, write to the
   14  *   Free Software Foundation, Inc.,
   15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   16  */
   17 #include "autoconfig.h"
   18 
   19 #include "advsearch_w.h"
   20 
   21 #include <qvariant.h>
   22 #include <qpushbutton.h>
   23 #include <qlabel.h>
   24 #include <qlineedit.h>
   25 #include <qframe.h>
   26 #include <qcheckbox.h>
   27 #include <qevent.h>
   28 #include <qlayout.h>
   29 #include <qtooltip.h>
   30 #include <qwhatsthis.h>
   31 #include <qmessagebox.h>
   32 #include <QShortcut>
   33 
   34 #include <string>
   35 #include <map>
   36 #include <algorithm>
   37 using namespace std;
   38 
   39 #include "recoll.h"
   40 #include "rclconfig.h"
   41 #include "log.h"
   42 #include "searchdata.h"
   43 #include "guiutils.h"
   44 #include "rclhelp.h"
   45 
   46 static const int initclausetypes[] = {1, 3, 0, 2, 5};
   47 static const unsigned int iclausescnt = sizeof(initclausetypes) / sizeof(int);
   48 static map<QString,QString> cat_translations;
   49 static map<QString,QString> cat_rtranslations;
   50 
   51 void AdvSearch::init()
   52 {
   53     (void)new HelpClient(this);
   54     HelpClient::installMap((const char *)objectName().toUtf8(), 
   55                "RCL.SEARCH.GUI.COMPLEX");
   56 
   57     // signals and slots connections
   58     connect(delFiltypPB, SIGNAL(clicked()), this, SLOT(delFiltypPB_clicked()));
   59     connect(searchPB, SIGNAL(clicked()), this, SLOT(runSearch()));
   60     connect(filterDatesCB, SIGNAL(toggled(bool)), 
   61         this, SLOT(filterDatesCB_toggled(bool)));
   62     connect(filterSizesCB, SIGNAL(toggled(bool)), 
   63         this, SLOT(filterSizesCB_toggled(bool)));
   64     connect(restrictFtCB, SIGNAL(toggled(bool)), 
   65         this, SLOT(restrictFtCB_toggled(bool)));
   66     connect(restrictCtCB, SIGNAL(toggled(bool)), 
   67         this, SLOT(restrictCtCB_toggled(bool)));
   68     connect(dismissPB, SIGNAL(clicked()), this, SLOT(close()));
   69     connect(browsePB, SIGNAL(clicked()), this, SLOT(browsePB_clicked()));
   70     connect(addFiltypPB, SIGNAL(clicked()), this, SLOT(addFiltypPB_clicked()));
   71 
   72     connect(delAFiltypPB, SIGNAL(clicked()), 
   73         this, SLOT(delAFiltypPB_clicked()));
   74     connect(addAFiltypPB, SIGNAL(clicked()), 
   75         this, SLOT(addAFiltypPB_clicked()));
   76     connect(saveFileTypesPB, SIGNAL(clicked()), 
   77         this, SLOT(saveFileTypes()));
   78     connect(addClausePB, SIGNAL(clicked()), this, SLOT(addClause()));
   79     connect(delClausePB, SIGNAL(clicked()), this, SLOT(delClause()));
   80 
   81     new QShortcut(QKeySequence(Qt::Key_Up), this, SLOT(slotHistoryNext()));;
   82     new QShortcut(QKeySequence(Qt::Key_Down), this, SLOT(slotHistoryPrev()));
   83 
   84     conjunctCMB->insertItem(1, tr("All clauses"));
   85     conjunctCMB->insertItem(2, tr("Any clause"));
   86 
   87     // Create preconfigured clauses
   88     for (unsigned int i = 0; i < iclausescnt; i++) {
   89     addClause(initclausetypes[i], false);
   90     }
   91     // Tune initial state according to last saved
   92     {
   93     vector<SearchClauseW *>::iterator cit = m_clauseWins.begin();
   94         unsigned int existing = m_clauseWins.size();
   95     for (unsigned int i = 0; i < prefs.advSearchClauses.size(); i++) {
   96         if (i < existing) {
   97         (*cit)->tpChange(prefs.advSearchClauses[i]);
   98         cit++;
   99         } else {
  100         addClause(prefs.advSearchClauses[i], false);
  101         }
  102     }
  103     }
  104     (*m_clauseWins.begin())->wordsLE->setFocus();
  105 
  106     // Initialize min/max mtime from extrem values in the index
  107     int minyear, maxyear;
  108     if (rcldb) {
  109     rcldb->maxYearSpan(&minyear, &maxyear);
  110     minDateDTE->setDisplayFormat("yyyy-MM-dd");
  111     maxDateDTE->setDisplayFormat("yyyy-MM-dd");
  112     minDateDTE->setDate(QDate(minyear, 1, 1));
  113     maxDateDTE->setDate(QDate(maxyear, 12, 31));
  114     }
  115 
  116     // Initialize lists of accepted and ignored mime types from config
  117     // and settings
  118     m_ignTypes = prefs.asearchIgnFilTyps;
  119     m_ignByCats = prefs.fileTypesByCats;
  120     restrictCtCB->setEnabled(false);
  121     restrictCtCB->setChecked(m_ignByCats);
  122     fillFileTypes();
  123 
  124     subtreeCMB->insertItems(0, prefs.asearchSubdirHist);
  125     subtreeCMB->setEditText("");
  126 
  127     // The clauseline frame is needed to force designer to accept a
  128     // vbox to englobe the base clauses grid and 'something else' (the
  129     // vbox is so that we can then insert SearchClauseWs), but we
  130     // don't want to see it.
  131     clauseline->close();
  132 
  133     bool calpop = 0;
  134     minDateDTE->setCalendarPopup(calpop);
  135     maxDateDTE->setCalendarPopup(calpop);
  136 
  137     // Translations for known categories
  138     cat_translations[QString::fromUtf8("texts")] = tr("text");
  139     cat_rtranslations[tr("texts")] = QString::fromUtf8("text"); 
  140 
  141     cat_translations[QString::fromUtf8("spreadsheet")] = tr("spreadsheet");
  142     cat_rtranslations[tr("spreadsheets")] = QString::fromUtf8("spreadsheet");
  143 
  144     cat_translations[QString::fromUtf8("presentation")] = tr("presentation");
  145     cat_rtranslations[tr("presentation")] =QString::fromUtf8("presentation");
  146 
  147     cat_translations[QString::fromUtf8("media")] = tr("media");
  148     cat_rtranslations[tr("media")] = QString::fromUtf8("media"); 
  149 
  150     cat_translations[QString::fromUtf8("message")] = tr("message");
  151     cat_rtranslations[tr("message")] = QString::fromUtf8("message"); 
  152 
  153     cat_translations[QString::fromUtf8("other")] = tr("other");
  154     cat_rtranslations[tr("other")] = QString::fromUtf8("other"); 
  155 }
  156 
  157 void AdvSearch::saveCnf()
  158 {
  159     // Save my state
  160     prefs.advSearchClauses.clear(); 
  161     for (const auto& clause : m_clauseWins) {
  162     prefs.advSearchClauses.push_back(clause->sTpCMB->currentIndex());
  163     }
  164 }
  165 
  166 void AdvSearch::addClause(bool updsaved)
  167 {
  168     addClause(0, updsaved);
  169 }
  170 
  171 void AdvSearch::addClause(int tp, bool updsaved)
  172 {
  173     SearchClauseW *w = new SearchClauseW(clauseFRM);
  174     m_clauseWins.push_back(w);
  175     ((QVBoxLayout *)(clauseFRM->layout()))->addWidget(w);
  176     w->show();
  177     w->tpChange(tp);
  178     if (m_clauseWins.size() > iclausescnt) {
  179     delClausePB->setEnabled(true);
  180     } else {
  181     delClausePB->setEnabled(false);
  182     }
  183     if (updsaved) {
  184         saveCnf();
  185     }
  186 }
  187 
  188 void AdvSearch::delClause(bool updsaved)
  189 {
  190     if (m_clauseWins.size() <= iclausescnt)
  191     return;
  192     delete m_clauseWins.back();
  193     m_clauseWins.pop_back();
  194     if (m_clauseWins.size() > iclausescnt) {
  195     delClausePB->setEnabled(true);
  196     } else {
  197     delClausePB->setEnabled(false);
  198     }
  199     if (updsaved) {
  200         saveCnf();
  201     }
  202 }
  203 
  204 void AdvSearch::delAFiltypPB_clicked()
  205 {
  206     yesFiltypsLB->selectAll();
  207     delFiltypPB_clicked();
  208 }
  209 
  210 // Move selected file types from the searched to the ignored box
  211 void AdvSearch::delFiltypPB_clicked()
  212 {
  213     QList<QListWidgetItem *> items = yesFiltypsLB->selectedItems();
  214     for (QList<QListWidgetItem *>::iterator it = items.begin(); 
  215      it != items.end(); it++) {
  216     int row = yesFiltypsLB->row(*it);
  217     QListWidgetItem *item = yesFiltypsLB->takeItem(row);
  218     noFiltypsLB->insertItem(0, item);
  219     }
  220     guiListsToIgnTypes();
  221 }
  222 
  223 // Move selected file types from the ignored to the searched box
  224 void AdvSearch::addFiltypPB_clicked()
  225 {
  226     QList<QListWidgetItem *> items = noFiltypsLB->selectedItems();
  227     for (QList<QListWidgetItem *>::iterator it = items.begin(); 
  228      it != items.end(); it++) {
  229     int row = noFiltypsLB->row(*it);
  230     QListWidgetItem *item = noFiltypsLB->takeItem(row);
  231     yesFiltypsLB->insertItem(0, item);
  232     }
  233     guiListsToIgnTypes();
  234  }
  235 
  236 // Compute list of ignored mime type from widget lists
  237 void AdvSearch::guiListsToIgnTypes()
  238 {
  239     yesFiltypsLB->sortItems();
  240     noFiltypsLB->sortItems();
  241     m_ignTypes.clear();
  242     for (int i = 0; i < noFiltypsLB->count();i++) {
  243     QListWidgetItem *item = noFiltypsLB->item(i);
  244     m_ignTypes.append(item->text());
  245     }
  246 }
  247 void AdvSearch::addAFiltypPB_clicked()
  248 {
  249     noFiltypsLB->selectAll();
  250     addFiltypPB_clicked();
  251 }
  252 
  253 // Activate file type selection
  254 void AdvSearch::restrictFtCB_toggled(bool on)
  255 {
  256     restrictCtCB->setEnabled(on);
  257     yesFiltypsLB->setEnabled(on);
  258     delFiltypPB->setEnabled(on);
  259     addFiltypPB->setEnabled(on);
  260     delAFiltypPB->setEnabled(on);
  261     addAFiltypPB->setEnabled(on);
  262     noFiltypsLB->setEnabled(on);
  263     saveFileTypesPB->setEnabled(on);
  264 }
  265 
  266 // Activate file type selection
  267 void AdvSearch::filterSizesCB_toggled(bool on)
  268 {
  269     minSizeLE->setEnabled(on);
  270     maxSizeLE->setEnabled(on);
  271 }
  272 // Activate file type selection
  273 void AdvSearch::filterDatesCB_toggled(bool on)
  274 {
  275     minDateDTE->setEnabled(on);
  276     maxDateDTE->setEnabled(on);
  277 }
  278 
  279 void AdvSearch::restrictCtCB_toggled(bool on)
  280 {
  281     m_ignByCats = on;
  282     // Only reset the list if we're enabled. Else this is init from prefs
  283     if (restrictCtCB->isEnabled())
  284     m_ignTypes.clear();
  285     fillFileTypes();
  286 }
  287 
  288 void AdvSearch::fillFileTypes()
  289 {
  290     noFiltypsLB->clear();
  291     yesFiltypsLB->clear();
  292     noFiltypsLB->insertItems(0, m_ignTypes); 
  293 
  294     QStringList ql;
  295     if (m_ignByCats == false) {
  296     vector<string> types = theconfig->getAllMimeTypes();
  297     rcldb->getAllDbMimeTypes(types);
  298     sort(types.begin(), types.end());
  299     types.erase(unique(types.begin(), types.end()), types.end());
  300     for (vector<string>::iterator it = types.begin(); 
  301          it != types.end(); it++) {
  302         QString qs = QString::fromUtf8(it->c_str());
  303         if (m_ignTypes.indexOf(qs) < 0)
  304         ql.append(qs);
  305     }
  306     } else {
  307     vector<string> cats;
  308     theconfig->getMimeCategories(cats);
  309     for (vector<string>::const_iterator it = cats.begin();
  310          it != cats.end(); it++) {
  311         map<QString, QString>::const_iterator it1;
  312         QString cat;
  313         if ((it1 = cat_translations.find(QString::fromUtf8(it->c_str())))
  314         != cat_translations.end()) {
  315         cat = it1->second;
  316         } else {
  317         cat = QString::fromUtf8(it->c_str());
  318         } 
  319         if (m_ignTypes.indexOf(cat) < 0)
  320         ql.append(cat);
  321     }
  322     }
  323     yesFiltypsLB->insertItems(0, ql);
  324 }
  325 
  326 // Save current set of ignored file types to prefs
  327 void AdvSearch::saveFileTypes()
  328 {
  329     prefs.asearchIgnFilTyps = m_ignTypes;
  330     prefs.fileTypesByCats = m_ignByCats;
  331     rwSettings(true);
  332 }
  333 
  334 void AdvSearch::browsePB_clicked()
  335 {
  336     QString dir = myGetFileName(true);
  337 #ifdef _WIN32
  338     string s = qs2utf8s(dir);
  339     for (string::size_type i = 0; i < s.size(); i++) {
  340         if (s[i] == '\\') {
  341             s[i] = '/';
  342         }
  343     }
  344     if (s.size() >= 2 && isalpha(s[0]) && s[1] == ':') {
  345         s.erase(1,1);
  346         s = string("/") + s;
  347     }
  348     dir = u8s2qs(s);
  349 #endif
  350     subtreeCMB->setEditText(dir);
  351 }
  352 
  353 size_t AdvSearch::stringToSize(QString qsize)
  354 {
  355     size_t size = size_t(-1);
  356     qsize.replace(QRegExp("[\\s]+"), "");
  357     if (!qsize.isEmpty()) {
  358     string csize(qs2utf8s(qsize));
  359     char *cp;
  360     size = strtoll(csize.c_str(), &cp, 10);
  361     if (*cp != 0) {
  362         switch (*cp) {
  363         case 'k': case 'K': size *= 1E3;break;
  364         case 'm': case 'M': size *= 1E6;break;
  365         case 'g': case 'G': size *= 1E9;break;
  366         case 't': case 'T': size *= 1E12;break;
  367         default: 
  368         QMessageBox::warning(0, "Recoll", 
  369                  tr("Bad multiplier suffix in size filter"));
  370         size = size_t(-1);
  371         }
  372     }
  373     }
  374     return size;
  375 }
  376 
  377 using namespace Rcl;
  378 void AdvSearch::runSearch()
  379 {
  380     string stemLang = prefs.stemlang();
  381     std::shared_ptr<SearchData> sdata(new SearchData(conjunctCMB->currentIndex() == 0 ?
  382                          SCLT_AND : SCLT_OR, stemLang));
  383     bool hasclause = false;
  384 
  385     for (vector<SearchClauseW*>::iterator it = m_clauseWins.begin();
  386      it != m_clauseWins.end(); it++) {
  387     SearchDataClause *cl;
  388     if ((cl = (*it)->getClause())) {
  389         sdata->addClause(cl);
  390             hasclause = true;
  391     }
  392     }
  393     if (!hasclause)
  394         return;
  395 
  396     if (restrictFtCB->isChecked() && noFiltypsLB->count() > 0) {
  397     for (int i = 0; i < yesFiltypsLB->count(); i++) {
  398         if (restrictCtCB->isChecked()) {
  399         QString qcat = yesFiltypsLB->item(i)->text();
  400         map<QString,QString>::const_iterator qit;
  401         string cat;
  402         if ((qit = cat_rtranslations.find(qcat)) != 
  403             cat_rtranslations.end()) {
  404             cat = qs2utf8s(qit->second);
  405         } else {
  406             cat = qs2utf8s(qcat);
  407         }
  408         vector<string> types;
  409         theconfig->getMimeCatTypes(cat, types);
  410         for (vector<string>::const_iterator it = types.begin();
  411              it != types.end(); it++) {
  412             sdata->addFiletype(*it);
  413         }
  414         } else {
  415         sdata->addFiletype(qs2utf8s(yesFiltypsLB->item(i)->text()));
  416         }
  417     }
  418     }
  419 
  420     if (filterDatesCB->isChecked()) {
  421     QDate mindate = minDateDTE->date();
  422     QDate maxdate = maxDateDTE->date();
  423     DateInterval di;
  424     di.y1 = mindate.year();
  425     di.m1 = mindate.month();
  426     di.d1 = mindate.day();
  427     di.y2 = maxdate.year();
  428     di.m2 = maxdate.month();
  429     di.d2 = maxdate.day();
  430     sdata->setDateSpan(&di);
  431     }
  432     if (filterSizesCB->isChecked()) {
  433     size_t size = stringToSize(minSizeLE->text());
  434     sdata->setMinSize(size);
  435     size = stringToSize(maxSizeLE->text());
  436     sdata->setMaxSize(size);
  437     }
  438 
  439     if (!subtreeCMB->currentText().isEmpty()) {
  440     QString current = subtreeCMB->currentText();
  441 
  442         Rcl::SearchDataClausePath *pathclause = 
  443             new Rcl::SearchDataClausePath((const char*)current.toLocal8Bit(), 
  444                                           direxclCB->isChecked());
  445         if (sdata->getTp() == SCLT_AND) {
  446             sdata->addClause(pathclause);
  447         } else {
  448             std::shared_ptr<SearchData> 
  449                 nsdata(new SearchData(SCLT_AND, stemLang));
  450             nsdata->addClause(new Rcl::SearchDataClauseSub(sdata));
  451             nsdata->addClause(pathclause);
  452             sdata = nsdata;
  453         }
  454 
  455     // Keep history clean and sorted. Maybe there would be a
  456     // simpler way to do this
  457     list<QString> entries;
  458     for (int i = 0; i < subtreeCMB->count(); i++) {
  459         entries.push_back(subtreeCMB->itemText(i));
  460     }
  461     entries.push_back(subtreeCMB->currentText());
  462     entries.sort();
  463     entries.unique();
  464     LOGDEB("Subtree list now has "  << (entries.size()) << " entries\n" );
  465     subtreeCMB->clear();
  466     for (list<QString>::iterator it = entries.begin(); 
  467          it != entries.end(); it++) {
  468         subtreeCMB->addItem(*it);
  469     }
  470     subtreeCMB->setCurrentIndex(subtreeCMB->findText(current));
  471     prefs.asearchSubdirHist.clear();
  472     for (int index = 0; index < subtreeCMB->count(); index++)
  473         prefs.asearchSubdirHist.push_back(subtreeCMB->itemText(index));
  474     }
  475     saveCnf();
  476     g_advshistory && g_advshistory->push(sdata);
  477     emit setDescription("");
  478     emit startSearch(sdata, false);
  479 }
  480 
  481 
  482 // Set up fields from existing search data, which must be compatible
  483 // with what we can do...
  484 void AdvSearch::fromSearch(std::shared_ptr<SearchData> sdata)
  485 {
  486     if (sdata->m_tp == SCLT_OR)
  487     conjunctCMB->setCurrentIndex(1);
  488     else
  489     conjunctCMB->setCurrentIndex(0);
  490 
  491     while (sdata->m_query.size() > m_clauseWins.size()) {
  492     addClause();
  493     }
  494 
  495     subtreeCMB->setEditText("");
  496     direxclCB->setChecked(0);
  497 
  498     for (unsigned int i = 0; i < sdata->m_query.size(); i++) {
  499     // Set fields from clause
  500     if (sdata->m_query[i]->getTp() == SCLT_SUB) {
  501         LOGERR("AdvSearch::fromSearch: SUB clause found !\n" );
  502         continue;
  503     }
  504     if (sdata->m_query[i]->getTp() == SCLT_PATH) {
  505         SearchDataClausePath *cs = 
  506         dynamic_cast<SearchDataClausePath*>(sdata->m_query[i]);
  507         // We can only use one such clause. There should be only one too 
  508         // if this is sfrom aved search data.
  509         QString qdir = QString::fromLocal8Bit(cs->gettext().c_str());
  510         subtreeCMB->setEditText(qdir);
  511         direxclCB->setChecked(cs->getexclude());
  512         continue;
  513     }
  514     SearchDataClauseSimple *cs = 
  515         dynamic_cast<SearchDataClauseSimple*>(sdata->m_query[i]);
  516     m_clauseWins[i]->setFromClause(cs);
  517     }
  518     for (unsigned int i = sdata->m_query.size(); i < m_clauseWins.size(); i++) {
  519     m_clauseWins[i]->clear();
  520     }
  521 
  522     restrictCtCB->setChecked(0);
  523     if (!sdata->m_filetypes.empty()) {
  524     restrictFtCB_toggled(1);
  525     delAFiltypPB_clicked();
  526     for (unsigned int i = 0; i < sdata->m_filetypes.size(); i++) {
  527         QString ft = QString::fromUtf8(sdata->m_filetypes[i].c_str());
  528         QList<QListWidgetItem *> lst = 
  529         noFiltypsLB->findItems(ft, Qt::MatchExactly);
  530         if (!lst.isEmpty()) {
  531         int row = noFiltypsLB->row(lst[0]);
  532         QListWidgetItem *item = noFiltypsLB->takeItem(row);
  533         yesFiltypsLB->insertItem(0, item);
  534         }
  535     }
  536     yesFiltypsLB->sortItems();
  537     } else {
  538     addAFiltypPB_clicked();
  539     restrictFtCB_toggled(0);
  540     }
  541 
  542     if (sdata->m_haveDates) {
  543     filterDatesCB->setChecked(1);
  544     DateInterval &di(sdata->m_dates);
  545     QDate mindate(di.y1, di.m1, di.d1);
  546     QDate maxdate(di.y2, di.m2, di.d2);
  547         minDateDTE->setDate(mindate);
  548         maxDateDTE->setDate(maxdate);
  549     } else {
  550     filterDatesCB->setChecked(0);
  551     QDate date;
  552     minDateDTE->setDate(date);
  553     maxDateDTE->setDate(date);
  554     }
  555 
  556     if (sdata->m_maxSize != (size_t)-1 || sdata->m_minSize != (size_t)-1) {
  557     filterSizesCB->setChecked(1);
  558     QString sz;
  559     if (sdata->m_minSize != (size_t)-1) {
  560         sz.setNum(sdata->m_minSize);
  561         minSizeLE->setText(sz);
  562     } else {
  563         minSizeLE->setText("");
  564     }
  565     if (sdata->m_maxSize != (size_t)-1) {
  566         sz.setNum(sdata->m_maxSize);
  567         maxSizeLE->setText(sz);
  568     } else {
  569         maxSizeLE->setText("");
  570     }
  571     } else {
  572     filterSizesCB->setChecked(0);
  573     minSizeLE->setText("");
  574     maxSizeLE->setText("");
  575     }
  576 }
  577 
  578 void AdvSearch::slotHistoryNext()
  579 {
  580     if (g_advshistory == 0)
  581     return;
  582     std::shared_ptr<Rcl::SearchData> sd = g_advshistory->getnewer();
  583     if (!sd)
  584     return;
  585     fromSearch(sd);
  586 }
  587 
  588 void AdvSearch::slotHistoryPrev()
  589 {
  590     if (g_advshistory == 0)
  591     return;
  592     std::shared_ptr<Rcl::SearchData> sd = g_advshistory->getolder();
  593     if (!sd)
  594     return;
  595     fromSearch(sd);
  596 }
  597 
  598