File indexing completed on 2024-04-28 17:06:03

0001 /*
0002     SPDX-FileCopyrightText: 2003 Shie Erlich <krusader@users.sourceforge.net>
0003     SPDX-FileCopyrightText: 2003 Rafi Yanai <krusader@users.sourceforge.net>
0004     SPDX-FileCopyrightText: 2003 Csaba Karai <krusader@users.sourceforge.net>
0005     SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "generalfilter.h"
0011 #include "../FileSystem/filesystem.h"
0012 #include "../compat.h"
0013 #include "../krglobal.h"
0014 #include "../krservices.h"
0015 #include "filtertabs.h"
0016 
0017 // QtWidgets
0018 #include <QGridLayout>
0019 #include <QHBoxLayout>
0020 #include <QLabel>
0021 #include <QMenu>
0022 #include <QPushButton>
0023 
0024 #include <KCodecs/KCharsets>
0025 #include <KConfigCore/KSharedConfig>
0026 #include <KCoreAddons/KShell>
0027 #include <KI18n/KLocalizedString>
0028 #include <KWidgetsAddons/KMessageBox>
0029 
0030 typedef struct {
0031     const char *description;
0032     const char *regExp;
0033     int cursorAdjustment;
0034 } term;
0035 
0036 static const term items[] = {
0037     {I18N_NOOP("Any Character"), ".", 0},
0038     {I18N_NOOP("Start of Line"), "^", 0},
0039     {I18N_NOOP("End of Line"), "$", 0},
0040     {I18N_NOOP("Set of Characters"), "[]", -1},
0041     {I18N_NOOP("Repeats, Zero or More Times"), "*", 0},
0042     {I18N_NOOP("Repeats, One or More Times"), "+", 0},
0043     {I18N_NOOP("Optional"), "?", 0},
0044     {I18N_NOOP("Escape"), "\\", 0},
0045     {I18N_NOOP("TAB"), "\\t", 0},
0046     {I18N_NOOP("Newline"), "\\n", 0},
0047     {I18N_NOOP("Carriage Return"), "\\r", 0},
0048     {I18N_NOOP("White Space"), "\\s", 0},
0049     {I18N_NOOP("Digit"), "\\d", 0},
0050 };
0051 
0052 class RegExpAction : public QAction
0053 {
0054 public:
0055     RegExpAction(QObject *parent, const QString &text, const QString &regExp, int cursor)
0056         : QAction(text, parent)
0057         , mText(text)
0058         , mRegExp(regExp)
0059         , mCursor(cursor)
0060     {
0061     }
0062 
0063     QString text() const
0064     {
0065         return mText;
0066     }
0067     QString regExp() const
0068     {
0069         return mRegExp;
0070     }
0071     int cursor() const
0072     {
0073         return mCursor;
0074     }
0075 
0076 private:
0077     QString mText;
0078     QString mRegExp;
0079     int mCursor;
0080 };
0081 
0082 GeneralFilter::GeneralFilter(FilterTabs *tabs, int properties, QWidget *parent, QStringList extraOptions)
0083     : QWidget(parent)
0084     , profileManager(nullptr)
0085     , fltTabs(tabs)
0086 {
0087     auto *filterLayout = new QGridLayout(this);
0088     filterLayout->setSpacing(6);
0089     filterLayout->setContentsMargins(11, 11, 11, 11);
0090 
0091     this->properties = properties;
0092 
0093     // Options for name filtering
0094 
0095     auto *nameGroup = new QGroupBox(this);
0096     nameGroup->setTitle(i18n("File Name"));
0097     auto *nameGroupLayout = new QGridLayout(nameGroup);
0098     nameGroupLayout->setAlignment(Qt::AlignTop);
0099     nameGroupLayout->setSpacing(6);
0100     nameGroupLayout->setContentsMargins(11, 11, 11, 11);
0101 
0102     searchForCase = new QCheckBox(nameGroup);
0103     searchForCase->setText(i18n("&Case sensitive"));
0104     searchForCase->setChecked(false);
0105     nameGroupLayout->addWidget(searchForCase, 1, 2);
0106 
0107     QLabel *searchForLabel = new QLabel(nameGroup);
0108     searchForLabel->setText(i18n("Search &for:"));
0109     nameGroupLayout->addWidget(searchForLabel, 0, 0);
0110 
0111     searchFor = new KrHistoryComboBox(false, nameGroup /*, "searchFor"*/);
0112     QSizePolicy searchForPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
0113     searchForPolicy.setHeightForWidth(searchFor->sizePolicy().hasHeightForWidth());
0114     searchFor->setSizePolicy(searchForPolicy);
0115     searchFor->setEditable(true);
0116     searchFor->setDuplicatesEnabled(false);
0117     searchFor->setMaxCount(25);
0118     searchFor->setMinimumContentsLength(10);
0119     searchForLabel->setBuddy(searchFor);
0120     nameGroupLayout->addWidget(searchFor, 0, 1, 1, 2);
0121 
0122     const QString s = "<p><img src='toolbar|find'></p>"
0123         + i18n("<p>The filename filtering criteria is defined here.</p>"
0124                "<p>You can make use of wildcards. Multiple patterns are separated by "
0125                "space (means logical OR) and patterns are excluded from the search "
0126                "using the pipe symbol.</p>"
0127                "<p>If the pattern is ended with a slash (<code>*pattern*/</code>), "
0128                "that means that pattern relates to recursive search of folders."
0129                "<ul><li><code>pattern</code> - means to search those files/folders "
0130                "that name is <code>pattern</code>, recursive search goes through all "
0131                "subfolders independently of the value of <code>pattern</code></li>"
0132                "<li><code>pattern/</code> - means to search all files/folders, but "
0133                "recursive search goes through/excludes the folders that name is "
0134                "<code>pattern</code></li></ul></p>"
0135                "<p>It is allowed to use quotation marks for names that contain space."
0136                " Filter <code>\"Program&nbsp;Files\"</code> searches out those "
0137                "files/folders that name is <code>Program&nbsp;Files</code>.</p>"
0138                "<p>Examples:</p><ul>"
0139                "<li><code>*.o</code></li>"
0140                "<li><code>*.h *.c\?\?</code></li>"
0141                "<li><code>*.cpp *.h | *.moc.cpp</code></li>"
0142                "<li><code>* | .svn/ .git/</code></li></ul><p>"
0143                "<b>Note</b>: the search term '<code>text</code>' is equivalent to "
0144                "'<code>*text*</code>'.</p>");
0145     searchFor->setWhatsThis(s);
0146     searchForLabel->setWhatsThis(s);
0147 
0148     QLabel *searchType = new QLabel(nameGroup);
0149     searchType->setText(i18n("&Of type:"));
0150     nameGroupLayout->addWidget(searchType, 1, 0);
0151 
0152     ofType = new KComboBox(false, nameGroup);
0153     ofType->setObjectName("ofType");
0154     QSizePolicy ofTypePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
0155     ofTypePolicy.setHeightForWidth(ofType->sizePolicy().hasHeightForWidth());
0156     ofType->setSizePolicy(ofTypePolicy);
0157     ofType->setEditable(false);
0158     searchType->setBuddy(ofType);
0159     ofType->addItem(i18n("All Files"));
0160     ofType->addItem(i18n("Archives"));
0161     ofType->addItem(i18n("Folders"));
0162     ofType->addItem(i18n("Image Files"));
0163     ofType->addItem(i18n("Text Files"));
0164     ofType->addItem(i18n("Video Files"));
0165     ofType->addItem(i18n("Audio Files"));
0166     connect(ofType, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &GeneralFilter::slotDisable);
0167 
0168     nameGroupLayout->addWidget(ofType, 1, 1);
0169     filterLayout->addWidget(nameGroup, 0, 0);
0170 
0171     middleLayout = new QHBoxLayout();
0172     middleLayout->setSpacing(6);
0173     middleLayout->setContentsMargins(0, 0, 0, 0);
0174 
0175     if (properties & FilterTabs::HasProfileHandler) {
0176         // The profile handler
0177 
0178         auto *profileHandler = new QGroupBox(this);
0179         profileHandler->setTitle(i18n("&Profile handler"));
0180         auto *profileLayout = new QGridLayout(profileHandler);
0181         profileLayout->setAlignment(Qt::AlignTop);
0182         profileLayout->setSpacing(6);
0183         profileLayout->setContentsMargins(11, 11, 11, 11);
0184 
0185         profileListBox = new KrListWidget(profileHandler);
0186         profileLayout->addWidget(profileListBox, 0, 0, 4, 1);
0187 
0188         profileAddBtn = new QPushButton(profileHandler);
0189         KStandardGuiItem::assign(profileAddBtn, KStandardGuiItem::Add);
0190         profileLayout->addWidget(profileAddBtn, 0, 1);
0191 
0192         profileLoadBtn = new QPushButton(i18n("&Load"), profileHandler);
0193         profileLoadBtn->setEnabled(false);
0194         profileLayout->addWidget(profileLoadBtn, 1, 1);
0195 
0196         profileOverwriteBtn = new QPushButton(profileHandler);
0197         profileOverwriteBtn->setEnabled(false);
0198         KStandardGuiItem::assign(profileOverwriteBtn, KStandardGuiItem::Overwrite);
0199         profileLayout->addWidget(profileOverwriteBtn, 2, 1);
0200 
0201         profileRemoveBtn = new QPushButton(profileHandler);
0202         profileRemoveBtn->setEnabled(false);
0203         KStandardGuiItem::assign(profileRemoveBtn, KStandardGuiItem::Remove);
0204         profileLayout->addWidget(profileRemoveBtn, 3, 1);
0205 
0206         profileManager = new ProfileManager("SelectionProfile", this);
0207         profileManager->hide();
0208 
0209         middleLayout->addWidget(profileHandler);
0210 
0211         refreshProfileListBox();
0212     }
0213 
0214     if (properties & FilterTabs::HasSearchIn) {
0215         // Options for search in
0216         QGroupBox *searchGroupBox = new QGroupBox(i18n("Searc&h in"), this);
0217         auto *searchLayout = new QGridLayout(searchGroupBox);
0218         searchLayout->setAlignment(Qt::AlignTop);
0219         searchLayout->setSpacing(6);
0220         searchLayout->setContentsMargins(11, 11, 11, 11);
0221 
0222         searchIn = new KURLListRequester(KURLListRequester::RequestDirs, searchGroupBox);
0223         searchLayout->addWidget(searchIn, 0, 0);
0224         connect(searchIn, &KURLListRequester::changed, this, &GeneralFilter::slotDisable);
0225 
0226         middleLayout->addWidget(searchGroupBox);
0227     }
0228 
0229     if (properties & FilterTabs::HasDontSearchIn) {
0230         // Options for don't search in
0231         QGroupBox *searchGroupBox = new QGroupBox(i18n("&Do not search in"), this);
0232         auto *searchLayout = new QGridLayout(searchGroupBox);
0233         searchLayout->setAlignment(Qt::AlignTop);
0234         searchLayout->setSpacing(6);
0235         searchLayout->setContentsMargins(11, 11, 11, 11);
0236 
0237         dontSearchIn = new KURLListRequester(KURLListRequester::RequestDirs, searchGroupBox);
0238         searchLayout->addWidget(dontSearchIn, 0, 0, 1, 2);
0239 
0240         if (properties & FilterTabs::HasRecurseOptions) {
0241             KConfigGroup group(krConfig, "Search");
0242 
0243             useExcludeFolderNames = createExcludeCheckBox(group);
0244             searchLayout->addWidget(useExcludeFolderNames, 1, 0, 1, 1);
0245 
0246             excludeFolderNames = createExcludeComboBox(group);
0247             searchLayout->addWidget(excludeFolderNames, 1, 1, 1, 1);
0248 
0249             if (!useExcludeFolderNames->isChecked()) {
0250                 excludeFolderNames->setDisabled(true);
0251             }
0252 
0253             connect(useExcludeFolderNames, &QCheckBox::toggled, excludeFolderNames, &KrHistoryComboBox::setEnabled);
0254         }
0255 
0256         middleLayout->addWidget(searchGroupBox);
0257     }
0258 
0259     filterLayout->addLayout(middleLayout, 1, 0);
0260 
0261     // Options for containing text
0262 
0263     auto *containsGroup = new QGroupBox(this);
0264     containsGroup->setTitle(i18n("Containing text"));
0265     auto *containsLayout = new QGridLayout(containsGroup);
0266     containsLayout->setAlignment(Qt::AlignTop);
0267     containsLayout->setSpacing(6);
0268     containsLayout->setContentsMargins(11, 11, 11, 11);
0269 
0270     auto *containsTextLayout = new QHBoxLayout();
0271     containsTextLayout->setSpacing(6);
0272     containsTextLayout->setContentsMargins(0, 0, 0, 0);
0273 
0274     containsLabel = new QLabel(containsGroup);
0275     QSizePolicy containsLabelPolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
0276     containsLabelPolicy.setHeightForWidth(containsLabel->sizePolicy().hasHeightForWidth());
0277     containsLabel->setSizePolicy(containsLabelPolicy);
0278     containsLabel->setText(i18n("&Text:"));
0279     containsTextLayout->addWidget(containsLabel);
0280 
0281     containsText = new KrHistoryComboBox(false, containsGroup /*, "containsText"*/);
0282     QSizePolicy containsTextPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
0283     containsTextPolicy.setHeightForWidth(containsText->sizePolicy().hasHeightForWidth());
0284     containsText->setSizePolicy(containsTextPolicy);
0285     containsText->setDuplicatesEnabled(false);
0286     containsText->setMaxCount(25);
0287     containsText->setMinimumContentsLength(10);
0288     containsTextLayout->addWidget(containsText);
0289     containsLabel->setBuddy(containsText);
0290 
0291     containsRegExp = new QToolButton(containsGroup);
0292     containsRegExp->setPopupMode(QToolButton::MenuButtonPopup);
0293     containsRegExp->setCheckable(true);
0294     containsRegExp->setText(i18n("RegExp"));
0295     // Populate the popup menu.
0296     auto *patterns = new QMenu(containsRegExp);
0297     for (int i = 0; (unsigned)i < sizeof(items) / sizeof(items[0]); i++) {
0298         patterns->addAction(new RegExpAction(patterns, i18n(items[i].description), items[i].regExp, items[i].cursorAdjustment));
0299     }
0300     connect(containsRegExp, &QToolButton::toggled, this, &GeneralFilter::slotDisable);
0301     connect(containsRegExp, &QToolButton::triggered, this, &GeneralFilter::slotRegExpTriggered);
0302     containsRegExp->setMenu(patterns);
0303     patterns->setEnabled(false);
0304 
0305     containsTextLayout->addWidget(containsRegExp);
0306 
0307     containsLayout->addLayout(containsTextLayout, 0, 0);
0308 
0309     auto *containsCbsLayout = new QHBoxLayout();
0310     containsCbsLayout->setSpacing(6);
0311     containsCbsLayout->setContentsMargins(0, 0, 0, 0);
0312 
0313     encLabel = new QLabel(i18n("Encoding:"), containsGroup);
0314     containsCbsLayout->addWidget(encLabel);
0315     contentEncoding = new KComboBox(containsGroup);
0316     contentEncoding->setEditable(false);
0317     contentEncoding->addItem(i18nc("Default encoding", "Default"));
0318     contentEncoding->addItems(KCharsets::charsets()->descriptiveEncodingNames());
0319     containsCbsLayout->addWidget(contentEncoding);
0320 
0321     auto *cbSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
0322     containsCbsLayout->addItem(cbSpacer);
0323 
0324     containsWholeWord = new QCheckBox(containsGroup);
0325     QSizePolicy containsWholeWordPolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
0326     containsWholeWordPolicy.setHeightForWidth(containsWholeWord->sizePolicy().hasHeightForWidth());
0327     containsWholeWord->setSizePolicy(containsWholeWordPolicy);
0328     containsWholeWord->setText(i18n("&Match whole word only"));
0329     containsWholeWord->setChecked(false);
0330     containsCbsLayout->addWidget(containsWholeWord);
0331 
0332     containsTextCase = new QCheckBox(containsGroup);
0333     QSizePolicy containsTextCasePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
0334     containsTextCasePolicy.setHeightForWidth(containsTextCase->sizePolicy().hasHeightForWidth());
0335     containsTextCase->setSizePolicy(containsTextCasePolicy);
0336     containsTextCase->setText(i18n("Cas&e sensitive"));
0337     containsTextCase->setChecked(true);
0338     containsCbsLayout->addWidget(containsTextCase);
0339 
0340     containsLayout->addLayout(containsCbsLayout, 1, 0);
0341 
0342     filterLayout->addWidget(containsGroup, 2, 0);
0343 
0344     auto *recurseLayout = new QHBoxLayout();
0345     recurseLayout->setSpacing(6);
0346     recurseLayout->setContentsMargins(0, 0, 0, 0);
0347     auto *recurseSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
0348     recurseLayout->addItem(recurseSpacer);
0349 
0350     if (properties & FilterTabs::HasRecurseOptions) {
0351         // Options for recursive searching
0352         searchInDirs = new QCheckBox(this);
0353         searchInDirs->setText(i18n("Search in s&ub folders"));
0354         searchInDirs->setChecked(true);
0355         recurseLayout->addWidget(searchInDirs);
0356 
0357         searchInArchives = new QCheckBox(this);
0358         searchInArchives->setText(i18n("Search in arch&ives"));
0359         recurseLayout->addWidget(searchInArchives);
0360 
0361         followLinks = new QCheckBox(this);
0362         followLinks->setText(i18n("Follow &links"));
0363         recurseLayout->addWidget(followLinks);
0364     }
0365     filterLayout->addLayout(recurseLayout, 3, 0);
0366 
0367     for (int i = 0; i < extraOptions.length(); i++) {
0368         auto *option = new QCheckBox(this);
0369         option->setText(extraOptions[i]);
0370         recurseLayout->addWidget(option);
0371         this->extraOptions.insert(extraOptions[i], option);
0372     }
0373 
0374     // Connection table
0375 
0376     if (properties & FilterTabs::HasProfileHandler) {
0377         connect(profileAddBtn, &QPushButton::clicked, this, &GeneralFilter::slotAddBtnClicked);
0378         connect(profileLoadBtn, &QPushButton::clicked, this, &GeneralFilter::slotLoadBtnClicked);
0379         connect(profileOverwriteBtn, &QPushButton::clicked, this, &GeneralFilter::slotOverwriteBtnClicked);
0380         connect(profileRemoveBtn, &QPushButton::clicked, this, &GeneralFilter::slotRemoveBtnClicked);
0381         connect(profileListBox, &KrListWidget::itemDoubleClicked, this, &GeneralFilter::slotProfileDoubleClicked);
0382         connect(profileManager, &ProfileManager::loadFromProfile, fltTabs, &FilterTabs::loadFromProfile);
0383         connect(profileManager, &ProfileManager::saveToProfile, fltTabs, &FilterTabs::saveToProfile);
0384     }
0385 
0386     connect(searchFor, QOverload<const QString &>::of(&KrHistoryComboBox::QCOMBOBOX_ACTIVATED), searchFor, &KrHistoryComboBox::addToHistory);
0387     connect(containsText, QOverload<const QString &>::of(&KrHistoryComboBox::QCOMBOBOX_ACTIVATED), containsText, &KrHistoryComboBox::addToHistory);
0388 
0389     // load the completion and history lists
0390     // ==> search for
0391     KConfigGroup group(krConfig, "Search");
0392     QStringList list = group.readEntry("SearchFor Completion", QStringList());
0393     searchFor->completionObject()->setItems(list);
0394     list = group.readEntry("SearchFor History", QStringList());
0395     searchFor->setHistoryItems(list);
0396     // ==> grep
0397     list = group.readEntry("ContainsText Completion", QStringList());
0398     containsText->completionObject()->setItems(list);
0399     list = group.readEntry("ContainsText History", QStringList());
0400     containsText->setHistoryItems(list);
0401 
0402     setTabOrder(searchFor, containsText); // search for -> content
0403     setTabOrder(containsText, searchType); // content -> search type
0404 
0405     slotDisable();
0406 }
0407 
0408 GeneralFilter::~GeneralFilter()
0409 {
0410     // save the history combos
0411     // ==> search for
0412     QStringList list = searchFor->completionObject()->items();
0413     KConfigGroup group(krConfig, "Search");
0414     group.writeEntry("SearchFor Completion", list);
0415     list = searchFor->historyItems();
0416     group.writeEntry("SearchFor History", list);
0417     // ==> grep text
0418     list = containsText->completionObject()->items();
0419     group.writeEntry("ContainsText Completion", list);
0420     list = containsText->historyItems();
0421     group.writeEntry("ContainsText History", list);
0422     if ((properties & FilterTabs::HasDontSearchIn) && (properties & FilterTabs::HasRecurseOptions)) {
0423         list = excludeFolderNames->historyItems();
0424         group.writeEntry("ExcludeFolderNamesHistory", list);
0425         group.writeEntry("ExcludeFolderNames", excludeFolderNames->currentText());
0426         group.writeEntry("ExcludeFolderNamesUse", static_cast<int>(useExcludeFolderNames->checkState()));
0427     }
0428     krConfig->sync();
0429 }
0430 
0431 bool GeneralFilter::isExtraOptionChecked(const QString &name)
0432 {
0433     QCheckBox *option = extraOptions[name];
0434     return option ? option->isChecked() : false;
0435 }
0436 
0437 void GeneralFilter::checkExtraOption(const QString &name, bool check)
0438 {
0439     QCheckBox *option = extraOptions[name];
0440     if (option)
0441         option->setChecked(check);
0442 }
0443 
0444 void GeneralFilter::queryAccepted()
0445 {
0446     searchFor->addToHistory(searchFor->currentText());
0447     containsText->addToHistory(containsText->currentText());
0448     if ((properties & FilterTabs::HasDontSearchIn) && (properties & FilterTabs::HasRecurseOptions)) {
0449         excludeFolderNames->addToHistory(excludeFolderNames->currentText());
0450     }
0451 }
0452 
0453 void GeneralFilter::refreshProfileListBox()
0454 {
0455     profileListBox->clear();
0456     profileListBox->addItems(ProfileManager::availableProfiles("SelectionProfile"));
0457 
0458     if (profileListBox->count() != 0) {
0459         profileLoadBtn->setEnabled(true);
0460         profileOverwriteBtn->setEnabled(true);
0461         profileRemoveBtn->setEnabled(true);
0462     } else {
0463         profileLoadBtn->setEnabled(false);
0464         profileOverwriteBtn->setEnabled(false);
0465         profileRemoveBtn->setEnabled(false);
0466     }
0467 }
0468 
0469 QCheckBox *GeneralFilter::createExcludeCheckBox(const KConfigGroup &group)
0470 {
0471     auto *excludeCheckBox = new QCheckBox(this);
0472     excludeCheckBox->setText(i18n("Exclude Folder Names"));
0473     excludeCheckBox->setToolTip(i18n("Filters out specified folder names from the results."));
0474     excludeCheckBox->setChecked(static_cast<Qt::CheckState>(group.readEntry("ExcludeFolderNamesUse", 0)));
0475     return excludeCheckBox;
0476 }
0477 
0478 KrHistoryComboBox *GeneralFilter::createExcludeComboBox(const KConfigGroup &group)
0479 {
0480     auto *excludeComboBox = new KrHistoryComboBox(false, this);
0481     QSizePolicy excludeFolderNamesPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
0482     excludeFolderNamesPolicy.setHeightForWidth(excludeComboBox->sizePolicy().hasHeightForWidth());
0483     excludeComboBox->setSizePolicy(excludeFolderNamesPolicy);
0484     excludeComboBox->setEditable(true);
0485     excludeComboBox->setDuplicatesEnabled(false);
0486     excludeComboBox->setMaxCount(25);
0487     excludeComboBox->setMinimumContentsLength(10);
0488     excludeComboBox->lineEdit()->setPlaceholderText(i18n("Enter space-separated folder names"));
0489     excludeComboBox->lineEdit()->setWhatsThis(
0490         i18n("You can insert names with escaped spaces or quoted.\nExample: .git \"target "
0491              "build\" build\\ krusader"));
0492     excludeComboBox->setHistoryItems(group.readEntry("ExcludeFolderNamesHistory", QStringList()));
0493     excludeComboBox->setEditText(group.readEntry("ExcludeFolderNames", ""));
0494     return excludeComboBox;
0495 }
0496 
0497 void GeneralFilter::slotAddBtnClicked()
0498 {
0499     profileManager->newProfile(searchFor->currentText().simplified());
0500     refreshProfileListBox();
0501 }
0502 
0503 void GeneralFilter::slotOverwriteBtnClicked()
0504 {
0505     QListWidgetItem *item = profileListBox->currentItem();
0506     if (item != nullptr)
0507         profileManager->overwriteProfile(item->text());
0508 }
0509 
0510 void GeneralFilter::slotRemoveBtnClicked()
0511 {
0512     QListWidgetItem *item = profileListBox->currentItem();
0513     if (item != nullptr) {
0514         profileManager->deleteProfile(item->text());
0515         refreshProfileListBox();
0516     }
0517 }
0518 
0519 void GeneralFilter::slotProfileDoubleClicked(QListWidgetItem *item)
0520 {
0521     if (item != nullptr) {
0522         QString profileName = item->text();
0523         profileManager->loadProfile(profileName);
0524         fltTabs->close(true);
0525     }
0526 }
0527 
0528 void GeneralFilter::slotLoadBtnClicked()
0529 {
0530     QListWidgetItem *item = profileListBox->currentItem();
0531     if (item != nullptr)
0532         profileManager->loadProfile(item->text());
0533 }
0534 
0535 void GeneralFilter::slotDisable()
0536 {
0537     bool state = containsRegExp->isChecked();
0538     bool global = ofType->currentText() != i18n("Folders");
0539     bool remoteOnly = false;
0540     if (properties & FilterTabs::HasSearchIn) {
0541         QList<QUrl> urlList = searchIn->urlList();
0542         remoteOnly = urlList.count() != 0;
0543         foreach (const QUrl &url, urlList)
0544             if (url.scheme() == "file")
0545                 remoteOnly = false;
0546     }
0547 
0548     containsWholeWord->setEnabled(!state && global);
0549     containsRegExp->menu()->setEnabled(state && global);
0550     encLabel->setEnabled(global);
0551     contentEncoding->setEnabled(global);
0552     containsTextCase->setEnabled(global);
0553     containsRegExp->setEnabled(global);
0554     if (properties & FilterTabs::HasRecurseOptions)
0555         searchInArchives->setEnabled(global && !remoteOnly);
0556     containsLabel->setEnabled(global);
0557     containsText->setEnabled(global);
0558 }
0559 
0560 void GeneralFilter::slotRegExpTriggered(QAction *act)
0561 {
0562     if (act == nullptr)
0563         return;
0564     auto *regAct = dynamic_cast<RegExpAction *>(act);
0565     if (regAct == nullptr)
0566         return;
0567     containsText->lineEdit()->insert(regAct->regExp());
0568     containsText->lineEdit()->setCursorPosition(containsText->lineEdit()->cursorPosition() + regAct->cursor());
0569     containsText->lineEdit()->setFocus();
0570 }
0571 
0572 bool GeneralFilter::getSettings(FilterSettings &s)
0573 {
0574     // check that we have (at least) what to search, and where to search in
0575     if (searchFor->currentText().simplified().isEmpty()) {
0576         KMessageBox::error(this, i18n("No search criteria entered."));
0577         searchFor->setFocus();
0578         return false;
0579     }
0580 
0581     s.searchFor = searchFor->currentText().trimmed();
0582     s.searchForCase = searchForCase->isChecked();
0583 
0584     if (ofType->currentText() != i18n("All Files"))
0585         s.mimeType = ofType->currentText();
0586 
0587     if (containsText->isEnabled()) {
0588         s.containsText = containsText->currentText();
0589         s.containsTextCase = containsTextCase->isChecked();
0590         s.containsWholeWord = containsWholeWord->isChecked();
0591         s.containsRegExp = containsRegExp->isChecked();
0592     }
0593 
0594     if (contentEncoding->currentIndex() != 0)
0595         s.contentEncoding = KCharsets::charsets()->encodingForName(contentEncoding->currentText());
0596 
0597     if (properties & FilterTabs::HasRecurseOptions) {
0598         s.recursive = searchInDirs->isChecked();
0599         s.searchInArchives = searchInArchives->isChecked();
0600         s.followLinks = followLinks->isChecked();
0601     }
0602 
0603     if (properties & FilterTabs::HasSearchIn) {
0604         s.searchIn = searchIn->urlList();
0605         if (s.searchIn.isEmpty()) { // we need a place to search in
0606             KMessageBox::error(this, i18n("Please specify a location to search in."));
0607             searchIn->lineEdit()->setFocus();
0608             return false;
0609         }
0610     }
0611 
0612     if (properties & FilterTabs::HasDontSearchIn) {
0613         s.dontSearchIn = dontSearchIn->urlList();
0614         if (properties & FilterTabs::HasRecurseOptions) {
0615             if (useExcludeFolderNames->isChecked()) {
0616                 s.excludeFolderNames = KShell::splitArgs(excludeFolderNames->currentText());
0617             } else {
0618                 s.excludeFolderNames = QStringList();
0619             }
0620         }
0621     }
0622     return true;
0623 }
0624 
0625 void GeneralFilter::applySettings(const FilterSettings &s)
0626 {
0627     searchFor->setEditText(s.searchFor);
0628     searchForCase->setChecked(s.searchForCase);
0629 
0630     setComboBoxValue(ofType, s.mimeType);
0631 
0632     containsText->setEditText(s.containsText);
0633     containsTextCase->setChecked(s.containsTextCase);
0634     containsWholeWord->setChecked(s.containsWholeWord);
0635     containsRegExp->setChecked(s.containsRegExp);
0636 
0637     setComboBoxValue(contentEncoding, KCharsets::charsets()->descriptionForEncoding(s.contentEncoding));
0638 
0639     if (properties & FilterTabs::HasRecurseOptions) {
0640         searchInDirs->setChecked(s.recursive);
0641         searchInArchives->setChecked(s.searchInArchives);
0642         followLinks->setChecked(s.followLinks);
0643     }
0644 
0645     if (properties & FilterTabs::HasSearchIn) {
0646         searchIn->lineEdit()->clear();
0647         searchIn->listBox()->clear();
0648         searchIn->listBox()->addItems(KrServices::toStringList(s.searchIn));
0649     }
0650 
0651     if (properties & FilterTabs::HasDontSearchIn) {
0652         dontSearchIn->lineEdit()->clear();
0653         dontSearchIn->listBox()->clear();
0654         dontSearchIn->listBox()->addItems(KrServices::toStringList(s.dontSearchIn));
0655     }
0656 }