#ifndef lint static char rcsid[] = "@(#$Id: advsearch_w.cpp,v 1.18 2007-08-31 09:04:23 dockes Exp $ (C) 2005 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "advsearch_w.h" #include #include #include #include #include #include #if (QT_VERSION < 0x040000) #include #include #else #include #include #endif #include #include #include #include #include #include #include #include #ifndef NO_NAMESPACES using std::list; using std::string; using std::map; #endif /* NO_NAMESPACES */ #include "recoll.h" #include "rclconfig.h" #include "debuglog.h" #include "searchdata.h" #include "guiutils.h" extern RclConfig *rclconfig; static const int initclausetypes[] = {1, 3, 0, 2, 5}; static const unsigned int iclausescnt = sizeof(initclausetypes) / sizeof(int); static map cat_translations; static map cat_rtranslations; void AdvSearch::init() { // signals and slots connections connect(delFiltypPB, SIGNAL(clicked()), this, SLOT(delFiltypPB_clicked())); connect(searchPB, SIGNAL(clicked()), this, SLOT(runSearch())); connect(restrictFtCB, SIGNAL(toggled(bool)), this, SLOT(restrictFtCB_toggled(bool))); connect(restrictCtCB, SIGNAL(toggled(bool)), this, SLOT(restrictCtCB_toggled(bool))); connect(dismissPB, SIGNAL(clicked()), this, SLOT(close())); connect(browsePB, SIGNAL(clicked()), this, SLOT(browsePB_clicked())); connect(addFiltypPB, SIGNAL(clicked()), this, SLOT(addFiltypPB_clicked())); connect(delAFiltypPB, SIGNAL(clicked()), this, SLOT(delAFiltypPB_clicked())); connect(addAFiltypPB, SIGNAL(clicked()), this, SLOT(addAFiltypPB_clicked())); connect(saveFileTypesPB, SIGNAL(clicked()), this, SLOT(saveFileTypes())); connect(addClausePB, SIGNAL(clicked()), this, SLOT(addClause())); connect(delClausePB, SIGNAL(clicked()), this, SLOT(delClause())); conjunctCMB->insertItem(tr("All clauses")); conjunctCMB->insertItem(tr("Any clause")); // Create preconfigured clauses for (unsigned int i = 0; i < iclausescnt; i++) { addClause(initclausetypes[i]); } // Tune initial state according to last saved { std::list::iterator cit = m_clauseWins.begin(); for (vector::iterator it = prefs.advSearchClauses.begin(); it != prefs.advSearchClauses.end(); it++) { if (cit != m_clauseWins.end()) { (*cit)->tpChange(*it); cit++; } else { addClause(*it); } } } // Initialize lists of accepted and ignored mime types from config // and settings m_ignTypes = prefs.asearchIgnFilTyps; m_ignByCats = prefs.fileTypesByCats; restrictCtCB->setEnabled(false); restrictCtCB->setChecked(m_ignByCats); fillFileTypes(); subtreeCMB->insertStringList(prefs.asearchSubdirHist); subtreeCMB->setEditText(""); // The clauseline frame is needed to force designer to accept a // vbox to englobe the base clauses grid and 'something else' (the // vbox is so that we can then insert SearchClauseWs), but we // don't want to see it. clauseline->close(); // Translations for known categories cat_translations[QString::fromUtf8("texts")] = tr("texts"); cat_rtranslations[tr("texts")] = QString::fromUtf8("texts"); cat_translations[QString::fromUtf8("spreadsheets")] = tr("spreadsheets"); cat_rtranslations[tr("spreadsheets")] = QString::fromUtf8("spreadsheets"); cat_translations[QString::fromUtf8("presentations")] = tr("presentations"); cat_rtranslations[tr("presentations")] =QString::fromUtf8("presentations"); cat_translations[QString::fromUtf8("media")] = tr("media"); cat_rtranslations[tr("media")] = QString::fromUtf8("media"); cat_translations[QString::fromUtf8("messages")] = tr("messages"); cat_rtranslations[tr("messages")] = QString::fromUtf8("messages"); cat_translations[QString::fromUtf8("other")] = tr("other"); cat_rtranslations[tr("other")] = QString::fromUtf8("other"); } void AdvSearch::saveCnf() { // Save my state prefs.advSearchClauses.clear(); for (std::list::iterator cit = m_clauseWins.begin(); cit != m_clauseWins.end(); cit++) { prefs.advSearchClauses.push_back((*cit)->sTpCMB->currentItem()); } } bool AdvSearch::close() { saveCnf(); return QWidget::close(); } #if (QT_VERSION >= 0x040000) #define QListBoxItem Q3ListBoxItem #define clauseVBox Ui::AdvSearchBase::clauseVBox #define AdvSearchBaseLayout Ui::AdvSearchBase::AdvSearchBaseLayout #endif void AdvSearch::delAFiltypPB_clicked() { for (unsigned int i = 0; i < yesFiltypsLB->count();i++) { yesFiltypsLB->setSelected(i, true); } delFiltypPB_clicked(); } void AdvSearch::addClause() { addClause(0); } #define HORADJ 50 #define VERTADJ 30 void AdvSearch::addClause(int tp) { SearchClauseW *w = new SearchClauseW(clauseFRM); m_clauseWins.push_back(w); ((QVBoxLayout *)(clauseFRM->layout()))->addWidget(w); w->show(); w->tpChange(tp); if (m_clauseWins.size() > iclausescnt) { delClausePB->setEnabled(true); } else { delClausePB->setEnabled(false); } // Have to adjust the size else we lose the bottom buttons! Why? QSize sz = layout()->sizeHint(); resize(QSize(sz.width()+HORADJ, sz.height()+VERTADJ)); } void AdvSearch::delClause() { if (m_clauseWins.size() <= iclausescnt) return; delete m_clauseWins.back(); m_clauseWins.pop_back(); if (m_clauseWins.size() > iclausescnt) { delClausePB->setEnabled(true); } else { delClausePB->setEnabled(false); } QSize sz = layout()->sizeHint(); resize(QSize(sz.width()+HORADJ, sz.height()+VERTADJ)); } #if (QT_VERSION < 0x040000) void AdvSearch::polish() { AdvSearchBase::polish(); QSize sz = sizeHint(); resize(QSize(sz.width()+HORADJ+10, sz.height()+VERTADJ-20)); } #endif // Move selected file types from the searched to the ignored box void AdvSearch::delFiltypPB_clicked() { list trl; QStringList moved; for (unsigned int i = 0; i < yesFiltypsLB->count();i++) { QListBoxItem *item = yesFiltypsLB->item(i); if (item && item->isSelected()) { moved.push_back(item->text()); trl.push_front(i); } } if (!moved.empty()) { noFiltypsLB->insertStringList(moved); for (list::iterator it = trl.begin();it != trl.end(); it++) yesFiltypsLB->removeItem(*it); } yesFiltypsLB->sort(); noFiltypsLB->sort(); m_ignTypes.clear(); for (unsigned int i = 0; i < noFiltypsLB->count();i++) { QListBoxItem *item = noFiltypsLB->item(i); m_ignTypes.append(item->text()); } } // Move selected file types from the ignored to the searched box void AdvSearch::addFiltypPB_clicked() { list trl; QStringList moved; for (unsigned int i = 0; i < noFiltypsLB->count(); i++) { QListBoxItem *item = noFiltypsLB->item(i); if (item && item->isSelected()) { moved.push_back(item->text()); trl.push_front(i); } } if (!moved.empty()) { yesFiltypsLB->insertStringList(moved); for (list::iterator it = trl.begin();it != trl.end(); it++) noFiltypsLB->removeItem(*it); } yesFiltypsLB->sort(); noFiltypsLB->sort(); m_ignTypes.clear(); for (unsigned int i = 0; i < noFiltypsLB->count();i++) { QListBoxItem *item = noFiltypsLB->item(i); m_ignTypes.append(item->text()); } } void AdvSearch::addAFiltypPB_clicked() { for (unsigned int i = 0; i < noFiltypsLB->count();i++) { noFiltypsLB->setSelected(i, true); } addFiltypPB_clicked(); } // Activate file type selection void AdvSearch::restrictFtCB_toggled(bool on) { restrictCtCB->setEnabled(on); yesFiltypsLB->setEnabled(on); delFiltypPB->setEnabled(on); addFiltypPB->setEnabled(on); delAFiltypPB->setEnabled(on); addAFiltypPB->setEnabled(on); noFiltypsLB->setEnabled(on); saveFileTypesPB->setEnabled(on); } void AdvSearch::restrictCtCB_toggled(bool on) { m_ignByCats = on; // Only reset the list if we're enabled. Else this is init from prefs if (restrictCtCB->isEnabled()) m_ignTypes.clear(); fillFileTypes(); } void AdvSearch::fillFileTypes() { noFiltypsLB->clear(); yesFiltypsLB->clear(); noFiltypsLB->insertStringList(m_ignTypes); QStringList ql; if (m_ignByCats == false) { list types = rclconfig->getAllMimeTypes(); for (list::iterator it = types.begin(); it != types.end(); it++) { QString qs = QString::fromUtf8(it->c_str()); if (m_ignTypes.findIndex(qs) < 0) ql.append(qs); } } else { list cats; rclconfig->getMimeCategories(cats); for (list::const_iterator it = cats.begin(); it != cats.end(); it++) { map::const_iterator it1; QString cat; if ((it1 = cat_translations.find(QString::fromUtf8(it->c_str()))) != cat_translations.end()) { cat = it1->second; } else { cat = QString::fromUtf8(it->c_str()); } if (m_ignTypes.findIndex(cat) < 0) ql.append(cat); } } yesFiltypsLB->insertStringList(ql); } // Save current list of ignored file types to prefs void AdvSearch::saveFileTypes() { prefs.asearchIgnFilTyps = m_ignTypes; prefs.fileTypesByCats = m_ignByCats; rwSettings(true); } using namespace Rcl; void AdvSearch::runSearch() { RefCntr sdata(new SearchData(conjunctCMB->currentItem() == 0 ? SCLT_AND : SCLT_OR)); bool hasnotnot = false; bool hasnot = false; for (list::iterator it = m_clauseWins.begin(); it != m_clauseWins.end(); it++) { SearchDataClause *cl; if ((cl = (*it)->getClause())) { switch (cl->getTp()) { case SCLT_EXCL: hasnot = true; break; default: hasnotnot = true; break; } sdata->addClause(cl); } } if (!hasnotnot) { if (!hasnot) return; QMessageBox::warning(0, "Recoll", tr("Cannot execute pure negative" "query. Please enter common terms" " in the 'any words' field")); return; } if (restrictFtCB->isOn() && noFiltypsLB->count() > 0) { for (unsigned int i = 0; i < yesFiltypsLB->count(); i++) { if (restrictCtCB->isOn()) { QString qcat = yesFiltypsLB->item(i)->text(); map::const_iterator qit; string cat; if ((qit = cat_rtranslations.find(qcat)) != cat_rtranslations.end()) { cat = (const char *)qit->second.utf8(); } else { cat = (const char *)qcat.utf8(); } list types; rclconfig->getMimeCatTypes(cat, types); for (list::const_iterator it = types.begin(); it != types.end(); it++) { sdata->addFiletype(*it); } } else { sdata->addFiletype((const char *) yesFiltypsLB->item(i)->text().utf8()); } } } if (!subtreeCMB->currentText().isEmpty()) { QString current = subtreeCMB->currentText(); sdata->setTopdir((const char*)subtreeCMB->currentText().utf8()); // Keep history list clean and sorted. Maybe there would be a // simpler way to do this list entries; for (int i = 0; i < subtreeCMB->count(); i++) { entries.push_back(subtreeCMB->text(i)); } entries.push_back(subtreeCMB->currentText()); entries.sort(); unique(entries.begin(), entries.end()); subtreeCMB->clear(); for (list::iterator it = entries.begin(); it != entries.end(); it++) { subtreeCMB->insertItem(*it); } subtreeCMB->setCurrentText(current); prefs.asearchSubdirHist.clear(); for (int index = 0; index < subtreeCMB->count(); index++) prefs.asearchSubdirHist.push_back(subtreeCMB->text(index)); } saveCnf(); emit startSearch(sdata); } void AdvSearch::browsePB_clicked() { QString dir = QFileDialog::getExistingDirectory(); subtreeCMB->setEditText(dir); }