diff --git a/krusader/Filter/generalfilter.cpp b/krusader/Filter/generalfilter.cpp
index 5f9ff209..d15199b7 100644
--- a/krusader/Filter/generalfilter.cpp
+++ b/krusader/Filter/generalfilter.cpp
@@ -1,666 +1,666 @@
/*****************************************************************************
* Copyright (C) 2003 Shie Erlich *
* Copyright (C) 2003 Rafi Yanai *
* Copyright (C) 2003 Csaba Karai *
* Copyright (C) 2004-2019 Krusader Krew [https://krusader.org] *
* *
* This file is part of Krusader [https://krusader.org]. *
* *
* Krusader 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. *
* *
* Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. *
*****************************************************************************/
#include "generalfilter.h"
#include "filtertabs.h"
#include "../krglobal.h"
#include "../krservices.h"
#include "../FileSystem/filesystem.h"
// QtWidgets
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct {
const char *description;
const char *regExp;
int cursorAdjustment;
} term;
static const term items[] = {
{ I18N_NOOP("Any Character"), ".", 0 },
{ I18N_NOOP("Start of Line"), "^", 0 },
{ I18N_NOOP("End of Line"), "$", 0 },
{ I18N_NOOP("Set of Characters"), "[]", -1 },
{ I18N_NOOP("Repeats, Zero or More Times"), "*", 0 },
{ I18N_NOOP("Repeats, One or More Times"), "+", 0 },
{ I18N_NOOP("Optional"), "?", 0 },
{ I18N_NOOP("Escape"), "\\", 0 },
{ I18N_NOOP("TAB"), "\\t", 0 },
{ I18N_NOOP("Newline"), "\\n", 0 },
{ I18N_NOOP("Carriage Return"), "\\r", 0 },
{ I18N_NOOP("White Space"), "\\s", 0 },
{ I18N_NOOP("Digit"), "\\d", 0 },
};
class RegExpAction : public QAction
{
public:
RegExpAction(QObject *parent, const QString &text, const QString ®Exp, int cursor)
: QAction(text, parent), mText(text), mRegExp(regExp), mCursor(cursor) {
}
QString text() const {
return mText;
}
QString regExp() const {
return mRegExp;
}
int cursor() const {
return mCursor;
}
private:
QString mText;
QString mRegExp;
int mCursor;
};
GeneralFilter::GeneralFilter(FilterTabs *tabs, int properties, QWidget *parent,
QStringList extraOptions) :
QWidget(parent),
profileManager(nullptr), fltTabs(tabs)
{
auto *filterLayout = new QGridLayout(this);
filterLayout->setSpacing(6);
filterLayout->setContentsMargins(11, 11, 11, 11);
this->properties = properties;
// Options for name filtering
auto *nameGroup = new QGroupBox(this);
nameGroup->setTitle(i18n("File Name"));
auto *nameGroupLayout = new QGridLayout(nameGroup);
nameGroupLayout->setAlignment(Qt::AlignTop);
nameGroupLayout->setSpacing(6);
nameGroupLayout->setContentsMargins(11, 11, 11, 11);
searchForCase = new QCheckBox(nameGroup);
searchForCase->setText(i18n("&Case sensitive"));
searchForCase->setChecked(false);
nameGroupLayout->addWidget(searchForCase, 1, 2);
QLabel *searchForLabel = new QLabel(nameGroup);
searchForLabel->setText(i18n("Search &for:"));
nameGroupLayout->addWidget(searchForLabel, 0, 0);
- searchFor = new KHistoryComboBox(false, nameGroup/*, "searchFor"*/);
+ searchFor = new KrHistoryComboBox(false, nameGroup/*, "searchFor"*/);
QSizePolicy searchForPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
searchForPolicy.setHeightForWidth(searchFor->sizePolicy().hasHeightForWidth());
searchFor->setSizePolicy(searchForPolicy);
searchFor->setEditable(true);
searchFor->setDuplicatesEnabled(false);
searchFor->setMaxCount(25);
searchFor->setMinimumContentsLength(10);
searchForLabel->setBuddy(searchFor);
nameGroupLayout->addWidget(searchFor, 0, 1, 1, 2);
const QString s = ""
+ i18n("The filename filtering criteria is defined here.
"
"You can make use of wildcards. Multiple patterns are separated by "
"space (means logical OR) and patterns are excluded from the search "
"using the pipe symbol.
"
"If the pattern is ended with a slash (*pattern*/
), "
"that means that pattern relates to recursive search of folders."
"
pattern
- means to search those files/folders "
"that name is pattern
, recursive search goes through all "
"subfolders independently of the value of pattern
"
"pattern/
- means to search all files/folders, but "
"recursive search goes through/excludes the folders that name is "
"pattern
"
"It is allowed to use quotation marks for names that contain space."
" Filter \"Program Files\"
searches out those "
"files/folders that name is Program Files
.
"
"Examples:
"
"*.o
"
"*.h *.c\?\?
"
"*.cpp *.h | *.moc.cpp
"
"* | .svn/ .git/
"
"Note: the search term 'text
' is equivalent to "
"'*text*
'.
");
searchFor->setWhatsThis(s);
searchForLabel->setWhatsThis(s);
QLabel *searchType = new QLabel(nameGroup);
searchType->setText(i18n("&Of type:"));
nameGroupLayout->addWidget(searchType, 1, 0);
ofType = new KComboBox(false, nameGroup);
ofType->setObjectName("ofType");
QSizePolicy ofTypePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
ofTypePolicy.setHeightForWidth(ofType->sizePolicy().hasHeightForWidth());
ofType->setSizePolicy(ofTypePolicy);
ofType->setEditable(false);
searchType->setBuddy(ofType);
ofType->addItem(i18n("All Files"));
ofType->addItem(i18n("Archives"));
ofType->addItem(i18n("Folders"));
ofType->addItem(i18n("Image Files"));
ofType->addItem(i18n("Text Files"));
ofType->addItem(i18n("Video Files"));
ofType->addItem(i18n("Audio Files"));
connect(ofType, QOverload::of(&KComboBox::currentIndexChanged), this, &GeneralFilter::slotDisable);
nameGroupLayout->addWidget(ofType, 1, 1);
filterLayout->addWidget(nameGroup, 0, 0);
middleLayout = new QHBoxLayout();
middleLayout->setSpacing(6);
middleLayout->setContentsMargins(0, 0, 0, 0);
if (properties & FilterTabs::HasProfileHandler) {
// The profile handler
auto *profileHandler = new QGroupBox(this);
profileHandler->setTitle(i18n("&Profile handler"));
auto *profileLayout = new QGridLayout(profileHandler);
profileLayout->setAlignment(Qt::AlignTop);
profileLayout->setSpacing(6);
profileLayout->setContentsMargins(11, 11, 11, 11);
profileListBox = new KrListWidget(profileHandler);
profileLayout->addWidget(profileListBox, 0, 0, 4, 1);
profileAddBtn = new QPushButton(profileHandler);
KStandardGuiItem::assign(profileAddBtn, KStandardGuiItem::Add);
profileLayout->addWidget(profileAddBtn, 0, 1);
profileLoadBtn = new QPushButton(i18n("&Load"), profileHandler);
profileLoadBtn->setEnabled(false);
profileLayout->addWidget(profileLoadBtn, 1, 1);
profileOverwriteBtn = new QPushButton(profileHandler);
profileOverwriteBtn->setEnabled(false);
KStandardGuiItem::assign(profileOverwriteBtn, KStandardGuiItem::Overwrite);
profileLayout->addWidget(profileOverwriteBtn, 2, 1);
profileRemoveBtn = new QPushButton(profileHandler);
profileRemoveBtn->setEnabled(false);
KStandardGuiItem::assign(profileRemoveBtn, KStandardGuiItem::Remove);
profileLayout->addWidget(profileRemoveBtn, 3, 1);
profileManager = new ProfileManager("SelectionProfile", this);
profileManager->hide();
middleLayout->addWidget(profileHandler);
refreshProfileListBox();
}
if (properties & FilterTabs::HasSearchIn) {
// Options for search in
QGroupBox *searchGroupBox = new QGroupBox(i18n("Searc&h in"), this);
auto *searchLayout = new QGridLayout(searchGroupBox);
searchLayout->setAlignment(Qt::AlignTop);
searchLayout->setSpacing(6);
searchLayout->setContentsMargins(11, 11, 11, 11);
searchIn = new KURLListRequester(KURLListRequester::RequestDirs, searchGroupBox);
searchLayout->addWidget(searchIn, 0, 0);
connect(searchIn, &KURLListRequester::changed, this, &GeneralFilter::slotDisable);
middleLayout->addWidget(searchGroupBox);
}
if (properties & FilterTabs::HasDontSearchIn) {
// Options for don't search in
QGroupBox *searchGroupBox = new QGroupBox(i18n("&Do not search in"), this);
auto *searchLayout = new QGridLayout(searchGroupBox);
searchLayout->setAlignment(Qt::AlignTop);
searchLayout->setSpacing(6);
searchLayout->setContentsMargins(11, 11, 11, 11);
dontSearchIn = new KURLListRequester(KURLListRequester::RequestDirs, searchGroupBox);
searchLayout->addWidget(dontSearchIn, 0, 0, 1, 2);
if (properties & FilterTabs::HasRecurseOptions) {
KConfigGroup group(krConfig, "Search");
useExcludeFolderNames = createExcludeCheckBox(group);
searchLayout->addWidget(useExcludeFolderNames, 1, 0, 1, 1);
excludeFolderNames = createExcludeComboBox(group);
searchLayout->addWidget(excludeFolderNames, 1, 1, 1, 1);
if (!useExcludeFolderNames->isChecked()) {
excludeFolderNames->setDisabled(true);
}
connect(useExcludeFolderNames, &QCheckBox::toggled, excludeFolderNames, &KHistoryComboBox::setEnabled);
}
middleLayout->addWidget(searchGroupBox);
}
filterLayout->addLayout(middleLayout, 1, 0);
// Options for containing text
auto *containsGroup = new QGroupBox(this);
containsGroup->setTitle(i18n("Containing text"));
auto *containsLayout = new QGridLayout(containsGroup);
containsLayout->setAlignment(Qt::AlignTop);
containsLayout->setSpacing(6);
containsLayout->setContentsMargins(11, 11, 11, 11);
auto *containsTextLayout = new QHBoxLayout();
containsTextLayout->setSpacing(6);
containsTextLayout->setContentsMargins(0, 0, 0, 0);
containsLabel = new QLabel(containsGroup);
QSizePolicy containsLabelPolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
containsLabelPolicy.setHeightForWidth(containsLabel->sizePolicy().hasHeightForWidth());
containsLabel->setSizePolicy(containsLabelPolicy);
containsLabel->setText(i18n("&Text:"));
containsTextLayout->addWidget(containsLabel);
containsText = new KHistoryComboBox(false, containsGroup/*, "containsText"*/);
QSizePolicy containsTextPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
containsTextPolicy.setHeightForWidth(containsText->sizePolicy().hasHeightForWidth());
containsText->setSizePolicy(containsTextPolicy);
containsText->setDuplicatesEnabled(false);
containsText->setMaxCount(25);
containsText->setMinimumContentsLength(10);
containsTextLayout->addWidget(containsText);
containsLabel->setBuddy(containsText);
containsRegExp = new QToolButton(containsGroup);
containsRegExp->setPopupMode(QToolButton::MenuButtonPopup);
containsRegExp->setCheckable(true);
containsRegExp->setText(i18n("RegExp"));
// Populate the popup menu.
auto *patterns = new QMenu(containsRegExp);
for (int i = 0; (unsigned)i < sizeof(items) / sizeof(items[0]); i++) {
patterns->addAction(new RegExpAction(patterns, i18n(items[i].description),
items[i].regExp, items[i].cursorAdjustment));
}
connect(containsRegExp, &QToolButton::toggled, this, &GeneralFilter::slotDisable);
connect(containsRegExp, &QToolButton::triggered, this, &GeneralFilter::slotRegExpTriggered);
containsRegExp->setMenu(patterns);
patterns->setEnabled(false);
containsTextLayout->addWidget(containsRegExp);
containsLayout->addLayout(containsTextLayout, 0, 0);
auto *containsCbsLayout = new QHBoxLayout();
containsCbsLayout->setSpacing(6);
containsCbsLayout->setContentsMargins(0, 0, 0, 0);
encLabel = new QLabel(i18n("Encoding:"), containsGroup);
containsCbsLayout->addWidget(encLabel);
contentEncoding = new KComboBox(containsGroup);
contentEncoding->setEditable(false);
contentEncoding->addItem(i18nc("Default encoding", "Default"));
contentEncoding->addItems(KCharsets::charsets()->descriptiveEncodingNames());
containsCbsLayout->addWidget(contentEncoding);
auto* cbSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
containsCbsLayout->addItem(cbSpacer);
containsWholeWord = new QCheckBox(containsGroup);
QSizePolicy containsWholeWordPolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
containsWholeWordPolicy.setHeightForWidth(containsWholeWord->sizePolicy().hasHeightForWidth());
containsWholeWord->setSizePolicy(containsWholeWordPolicy);
containsWholeWord->setText(i18n("&Match whole word only"));
containsWholeWord->setChecked(false);
containsCbsLayout->addWidget(containsWholeWord);
containsTextCase = new QCheckBox(containsGroup);
QSizePolicy containsTextCasePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
containsTextCasePolicy.setHeightForWidth(containsTextCase->sizePolicy().hasHeightForWidth());
containsTextCase->setSizePolicy(containsTextCasePolicy);
containsTextCase->setText(i18n("Cas&e sensitive"));
containsTextCase->setChecked(true);
containsCbsLayout->addWidget(containsTextCase);
containsLayout->addLayout(containsCbsLayout, 1, 0);
filterLayout->addWidget(containsGroup, 2, 0);
auto *recurseLayout = new QHBoxLayout();
recurseLayout->setSpacing(6);
recurseLayout->setContentsMargins(0, 0, 0, 0);
auto* recurseSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
recurseLayout->addItem(recurseSpacer);
if (properties & FilterTabs::HasRecurseOptions) {
// Options for recursive searching
searchInDirs = new QCheckBox(this);
searchInDirs->setText(i18n("Search in s&ub folders"));
searchInDirs->setChecked(true);
recurseLayout->addWidget(searchInDirs);
searchInArchives = new QCheckBox(this);
searchInArchives->setText(i18n("Search in arch&ives"));
recurseLayout->addWidget(searchInArchives);
followLinks = new QCheckBox(this);
followLinks->setText(i18n("Follow &links"));
recurseLayout->addWidget(followLinks);
}
filterLayout->addLayout(recurseLayout, 3, 0);
for(int i = 0; i < extraOptions.length(); i++) {
auto *option = new QCheckBox(this);
option->setText(extraOptions[i]);
recurseLayout->addWidget(option);
this->extraOptions.insert(extraOptions[i], option);
}
// Connection table
if (properties & FilterTabs::HasProfileHandler) {
connect(profileAddBtn, &QPushButton::clicked, this, &GeneralFilter::slotAddBtnClicked);
connect(profileLoadBtn, &QPushButton::clicked, this, &GeneralFilter::slotLoadBtnClicked);
connect(profileOverwriteBtn, &QPushButton::clicked, this, &GeneralFilter::slotOverwriteBtnClicked);
connect(profileRemoveBtn, &QPushButton::clicked, this, &GeneralFilter::slotRemoveBtnClicked);
connect(profileListBox, &KrListWidget::itemDoubleClicked, this, &GeneralFilter::slotProfileDoubleClicked);
connect(profileManager, &ProfileManager::loadFromProfile, fltTabs, &FilterTabs::loadFromProfile);
connect(profileManager, &ProfileManager::saveToProfile, fltTabs, &FilterTabs::saveToProfile);
}
connect(searchFor, QOverload::of(&KHistoryComboBox::activated), searchFor, &KHistoryComboBox::addToHistory);
connect(containsText, QOverload::of(&KHistoryComboBox::activated), containsText, &KHistoryComboBox::addToHistory);
// load the completion and history lists
// ==> search for
KConfigGroup group(krConfig, "Search");
QStringList list = group.readEntry("SearchFor Completion", QStringList());
searchFor->completionObject()->setItems(list);
list = group.readEntry("SearchFor History", QStringList());
searchFor->setHistoryItems(list);
// ==> grep
list = group.readEntry("ContainsText Completion", QStringList());
containsText->completionObject()->setItems(list);
list = group.readEntry("ContainsText History", QStringList());
containsText->setHistoryItems(list);
setTabOrder(searchFor, containsText); // search for -> content
setTabOrder(containsText, searchType); // content -> search type
slotDisable();
}
GeneralFilter::~GeneralFilter()
{
// save the history combos
// ==> search for
QStringList list = searchFor->completionObject()->items();
KConfigGroup group(krConfig, "Search");
group.writeEntry("SearchFor Completion", list);
list = searchFor->historyItems();
group.writeEntry("SearchFor History", list);
// ==> grep text
list = containsText->completionObject()->items();
group.writeEntry("ContainsText Completion", list);
list = containsText->historyItems();
group.writeEntry("ContainsText History", list);
if ((properties & FilterTabs::HasDontSearchIn) && (properties & FilterTabs::HasRecurseOptions)) {
list = excludeFolderNames->historyItems();
group.writeEntry("ExcludeFolderNamesHistory", list);
group.writeEntry("ExcludeFolderNames", excludeFolderNames->currentText());
group.writeEntry("ExcludeFolderNamesUse", static_cast(useExcludeFolderNames->checkState()));
}
krConfig->sync();
}
bool GeneralFilter::isExtraOptionChecked(const QString& name)
{
QCheckBox *option = extraOptions[name];
return option ? option->isChecked() : false;
}
void GeneralFilter::checkExtraOption(const QString& name, bool check)
{
QCheckBox *option = extraOptions[name];
if (option)
option->setChecked(check);
}
void GeneralFilter::queryAccepted()
{
searchFor->addToHistory(searchFor->currentText());
containsText->addToHistory(containsText->currentText());
if ((properties & FilterTabs::HasDontSearchIn) && (properties & FilterTabs::HasRecurseOptions)) {
excludeFolderNames->addToHistory(excludeFolderNames->currentText());
}
}
void GeneralFilter::refreshProfileListBox()
{
profileListBox->clear();
profileListBox->addItems(ProfileManager::availableProfiles("SelectionProfile"));
if (profileListBox->count() != 0) {
profileLoadBtn->setEnabled(true);
profileOverwriteBtn->setEnabled(true);
profileRemoveBtn->setEnabled(true);
} else {
profileLoadBtn->setEnabled(false);
profileOverwriteBtn->setEnabled(false);
profileRemoveBtn->setEnabled(false);
}
}
QCheckBox *GeneralFilter::createExcludeCheckBox(const KConfigGroup &group)
{
auto *excludeCheckBox = new QCheckBox(this);
excludeCheckBox->setText(i18n("Exclude Folder Names"));
excludeCheckBox->setToolTip(i18n("Filters out specified directory names from the results."));
excludeCheckBox->setChecked(static_cast(group.readEntry("ExcludeFolderNamesUse", 0)));
return excludeCheckBox;
}
KHistoryComboBox *GeneralFilter::createExcludeComboBox(const KConfigGroup &group)
{
auto *excludeComboBox = new KHistoryComboBox(false, this);
QSizePolicy excludeFolderNamesPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
excludeFolderNamesPolicy.setHeightForWidth(excludeComboBox->sizePolicy().hasHeightForWidth());
excludeComboBox->setSizePolicy(excludeFolderNamesPolicy);
excludeComboBox->setEditable(true);
excludeComboBox->setDuplicatesEnabled(false);
excludeComboBox->setMaxCount(25);
excludeComboBox->setMinimumContentsLength(10);
excludeComboBox->lineEdit()->setPlaceholderText(i18n("Enter space-separated folder names"));
excludeComboBox->lineEdit()->setWhatsThis(
i18n("You can insert names with escaped spaces or quoted.\nExample: .git \"target "
"build\" build\\ krusader"));
excludeComboBox->setHistoryItems(group.readEntry("ExcludeFolderNamesHistory", QStringList()));
excludeComboBox->setEditText(group.readEntry("ExcludeFolderNames", ""));
return excludeComboBox;
}
void GeneralFilter::slotAddBtnClicked()
{
profileManager->newProfile(searchFor->currentText().simplified());
refreshProfileListBox();
}
void GeneralFilter::slotOverwriteBtnClicked()
{
QListWidgetItem *item = profileListBox->currentItem();
if (item != nullptr)
profileManager->overwriteProfile(item->text());
}
void GeneralFilter::slotRemoveBtnClicked()
{
QListWidgetItem *item = profileListBox->currentItem();
if (item != nullptr) {
profileManager->deleteProfile(item->text());
refreshProfileListBox();
}
}
void GeneralFilter::slotProfileDoubleClicked(QListWidgetItem *item)
{
if (item != nullptr) {
QString profileName = item->text();
profileManager->loadProfile(profileName);
fltTabs->close(true);
}
}
void GeneralFilter::slotLoadBtnClicked()
{
QListWidgetItem *item = profileListBox->currentItem();
if (item != nullptr)
profileManager->loadProfile(item->text());
}
void GeneralFilter::slotDisable()
{
bool state = containsRegExp->isChecked();
bool global = ofType->currentText() != i18n("Folders");
bool remoteOnly = false;
if (properties & FilterTabs::HasSearchIn) {
QList urlList = searchIn->urlList();
remoteOnly = urlList.count() != 0;
foreach(const QUrl &url, urlList)
if (url.scheme() == "file")
remoteOnly = false;
}
containsWholeWord->setEnabled(!state && global);
containsRegExp->menu()->setEnabled(state && global);
encLabel->setEnabled(global);
contentEncoding->setEnabled(global);
containsTextCase->setEnabled(global);
containsRegExp->setEnabled(global);
if (properties & FilterTabs::HasRecurseOptions)
searchInArchives->setEnabled(global && !remoteOnly);
containsLabel->setEnabled(global);
containsText->setEnabled(global);
}
void GeneralFilter::slotRegExpTriggered(QAction * act)
{
if (act == nullptr)
return;
auto *regAct = dynamic_cast(act);
if (regAct == nullptr)
return;
containsText->lineEdit()->insert(regAct->regExp());
containsText->lineEdit()->setCursorPosition(containsText->lineEdit()->cursorPosition() + regAct->cursor());
containsText->lineEdit()->setFocus();
}
bool GeneralFilter::getSettings(FilterSettings &s)
{
// check that we have (at least) what to search, and where to search in
if (searchFor->currentText().simplified().isEmpty()) {
KMessageBox::error(this , i18n("No search criteria entered."));
searchFor->setFocus();
return false;
}
s.searchFor = searchFor->currentText().trimmed();
s.searchForCase = searchForCase->isChecked();
if (ofType->currentText() != i18n("All Files"))
s.mimeType = ofType->currentText();
if (containsText->isEnabled()) {
s.containsText = containsText->currentText();
s.containsTextCase = containsTextCase->isChecked();
s.containsWholeWord = containsWholeWord->isChecked();
s.containsRegExp = containsRegExp->isChecked();
}
if (contentEncoding->currentIndex() != 0)
s.contentEncoding =
KCharsets::charsets()->encodingForName(contentEncoding->currentText());
if (properties & FilterTabs::HasRecurseOptions) {
s.recursive = searchInDirs->isChecked();
s.searchInArchives = searchInArchives->isChecked();
s.followLinks = followLinks->isChecked();
}
if (properties & FilterTabs::HasSearchIn) {
s.searchIn = searchIn->urlList();
if (s.searchIn.isEmpty()) { // we need a place to search in
KMessageBox::error(this , i18n("Please specify a location to search in."));
searchIn->lineEdit()->setFocus();
return false;
}
}
if (properties & FilterTabs::HasDontSearchIn) {
s.dontSearchIn = dontSearchIn->urlList();
if (properties & FilterTabs::HasRecurseOptions) {
if (useExcludeFolderNames->isChecked()) {
s.excludeFolderNames = KShell::splitArgs(excludeFolderNames->currentText());
} else {
s.excludeFolderNames = QStringList();
}
}
}
return true;
}
void GeneralFilter::applySettings(const FilterSettings &s)
{
searchFor->setEditText(s.searchFor);
searchForCase->setChecked(s.searchForCase);
setComboBoxValue(ofType, s.mimeType);
containsText->setEditText(s.containsText);
containsTextCase->setChecked(s.containsTextCase);
containsWholeWord->setChecked(s.containsWholeWord);
containsRegExp->setChecked(s.containsRegExp);
setComboBoxValue(contentEncoding,
KCharsets::charsets()->descriptionForEncoding(s.contentEncoding));
if (properties & FilterTabs::HasRecurseOptions) {
searchInDirs->setChecked(s.recursive);
searchInArchives->setChecked(s.searchInArchives);
followLinks->setChecked(s.followLinks);
}
if (properties & FilterTabs::HasSearchIn) {
searchIn->lineEdit()->clear();
searchIn->listBox()->clear();
searchIn->listBox()->addItems(KrServices::toStringList(s.searchIn));
}
if (properties & FilterTabs::HasDontSearchIn) {
dontSearchIn->lineEdit()->clear();
dontSearchIn->listBox()->clear();
dontSearchIn->listBox()->addItems(KrServices::toStringList(s.dontSearchIn));
}
}
diff --git a/krusader/Filter/generalfilter.h b/krusader/Filter/generalfilter.h
index 2d21b526..83fa26b7 100644
--- a/krusader/Filter/generalfilter.h
+++ b/krusader/Filter/generalfilter.h
@@ -1,118 +1,119 @@
/*****************************************************************************
* Copyright (C) 2003 Csaba Karai *
* Copyright (C) 2004-2019 Krusader Krew [https://krusader.org] *
* *
* This file is part of Krusader [https://krusader.org]. *
* *
* Krusader 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. *
* *
* Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. *
*****************************************************************************/
#ifndef GENERALFILTER_H
#define GENERALFILTER_H
// QtWidgets
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "filterbase.h"
#include "../Dialogs/kurllistrequester.h"
#include "../GUI/profilemanager.h"
#include "../GUI/krlistwidget.h"
+#include "../GUI/krhistorycombobox.h"
class GeneralFilter : public QWidget, public FilterBase
{
Q_OBJECT
public:
GeneralFilter(FilterTabs *tabs, int properties, QWidget *parent = nullptr,
QStringList extraOptions = QStringList());
~GeneralFilter() override;
void queryAccepted() Q_DECL_OVERRIDE;
QString name() Q_DECL_OVERRIDE {
return "GeneralFilter";
}
FilterTabs * filterTabs() Q_DECL_OVERRIDE {
return fltTabs;
}
bool getSettings(FilterSettings&) Q_DECL_OVERRIDE;
void applySettings(const FilterSettings&) Q_DECL_OVERRIDE;
bool isExtraOptionChecked(const QString& name);
void checkExtraOption(const QString& name, bool check);
public slots:
void slotAddBtnClicked();
void slotLoadBtnClicked();
void slotOverwriteBtnClicked();
void slotRemoveBtnClicked();
void slotDisable();
void slotRegExpTriggered(QAction * act);
void slotProfileDoubleClicked(QListWidgetItem *);
void refreshProfileListBox();
public:
KComboBox* contentEncoding;
QCheckBox* searchForCase;
QCheckBox* containsTextCase;
QCheckBox* containsWholeWord;
QCheckBox* useExcludeFolderNames;
QCheckBox* searchInDirs;
QCheckBox* searchInArchives;
QCheckBox* followLinks;
QHash extraOptions;
KURLListRequester *searchIn;
KURLListRequester *dontSearchIn;
QLayout *middleLayout;
- KHistoryComboBox* searchFor;
+ KrHistoryComboBox* searchFor;
KHistoryComboBox* containsText;
KHistoryComboBox* excludeFolderNames;
QToolButton* containsRegExp;
KComboBox* ofType;
QLabel *encLabel;
QLabel *containsLabel;
KShellCompletion completion;
KrListWidget *profileListBox;
QPushButton *profileAddBtn;
QPushButton *profileLoadBtn;
QPushButton *profileOverwriteBtn;
QPushButton *profileRemoveBtn;
ProfileManager *profileManager;
int properties;
FilterTabs *fltTabs;
private:
QCheckBox *createExcludeCheckBox(const KConfigGroup &group);
KHistoryComboBox *createExcludeComboBox(const KConfigGroup &group);
};
#endif /* GENERALFILTER_H */
diff --git a/krusader/GUI/CMakeLists.txt b/krusader/GUI/CMakeLists.txt
index 3e233074..82a4082c 100644
--- a/krusader/GUI/CMakeLists.txt
+++ b/krusader/GUI/CMakeLists.txt
@@ -1,26 +1,27 @@
set(GUI_SRCS
dirhistorybutton.cpp
krusaderstatus.cpp
kfnkeys.cpp
kcmdline.cpp
profilemanager.cpp
+ krhistorycombobox.cpp
krremoteencodingmenu.cpp
krtreewidget.cpp
krstyleproxy.cpp
krlistwidget.cpp
mediabutton.cpp
kcmdmodebutton.cpp
terminaldock.cpp)
add_library(GUI STATIC ${GUI_SRCS})
target_link_libraries(GUI
KF5::ConfigCore
KF5::CoreAddons
KF5::I18n
KF5::IconThemes
KF5::Parts
KF5::Service
KF5::Solid
KF5::WidgetsAddons
)
diff --git a/krusader/GUI/krhistorycombobox.cpp b/krusader/GUI/krhistorycombobox.cpp
new file mode 100755
index 00000000..9cdd77e9
--- /dev/null
+++ b/krusader/GUI/krhistorycombobox.cpp
@@ -0,0 +1,118 @@
+/*****************************************************************************
+ * Copyright (C) 2018-2019 Shie Erlich *
+ * Copyright (C) 2018-2019 Rafi Yanai *
+ * Copyright (C) 2018-2019 Krusader Krew [https://krusader.org] *
+ * *
+ * This file is part of Krusader [https://krusader.org]. *
+ * *
+ * Krusader 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. *
+ * *
+ * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. *
+ *****************************************************************************/
+
+#include "krhistorycombobox.h"
+
+// QtCore
+#include
+// QtGui
+#include
+// QtWidgets
+#include
+
+/**
+ * A KrHistoryComboBox event filter that e.g. deletes the current item when Shift+Del is pressed
+ * There was more information in https://doc.qt.io/qt-5/qobject.html#installEventFilter,
+ * https://forum.qt.io/post/160618 and
+ * https://stackoverflow.com/questions/17820947/remove-items-from-qcombobox-from-ui/52459337#52459337
+ */
+class KHBoxEventFilter : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit KHBoxEventFilter(QObject *parent = nullptr) : QObject(parent) {}
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event) override;
+};
+
+bool KHBoxEventFilter::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::KeyPress) {
+ auto keyEvent = static_cast(event);
+ if (keyEvent->modifiers() == Qt::ShiftModifier && keyEvent->key() == Qt::Key::Key_Delete) {
+ auto comboBox = dynamic_cast(obj);
+ if (comboBox != nullptr) {
+ QString entryToDelete = comboBox->currentText();
+ // Delete the current item
+ comboBox->removeItem(comboBox->currentIndex());
+ // The item has to be deleted also from the completion list
+ comboBox->completionObject()->removeItem(entryToDelete);
+ return true;
+ }
+ }
+ }
+ // Perform the usual event processing
+ return QObject::eventFilter(obj, event);
+}
+
+/**
+ * An event filter for the popup list of a KrHistoryComboBox, e.g. it deletes the current
+ * item when the user presses Shift+Del
+ */
+class KHBoxListEventFilter : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit KHBoxListEventFilter(QObject *parent = nullptr) : QObject(parent) {}
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event) override;
+};
+
+bool KHBoxListEventFilter::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::KeyPress) {
+ auto keyEvent = static_cast(event);
+ if (keyEvent->modifiers() == Qt::ShiftModifier && keyEvent->key() == Qt::Key::Key_Delete) {
+ auto itemView = dynamic_cast(obj);
+ if (itemView->model() != nullptr) {
+ QString entryToDelete = itemView->currentIndex().data().toString();
+ // Delete the current item from the popup list
+ itemView->model()->removeRow(itemView->currentIndex().row());
+ // The item has to be deleted also from the completion list of the KHistoryComboBox
+ if (itemView->parent() != nullptr) {
+ auto comboBox = dynamic_cast(itemView->parent()->parent());
+ if (comboBox != nullptr) {
+ comboBox->completionObject()->removeItem(entryToDelete);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ // Perform the usual event processing
+ return QObject::eventFilter(obj, event);
+}
+
+#include "krhistorycombobox.moc" // required for class definitions with Q_OBJECT macro in implementation files
+
+KrHistoryComboBox::KrHistoryComboBox(bool useCompletion, QWidget *parent)
+ : KHistoryComboBox(useCompletion, parent)
+{
+ installEventFilter(new KHBoxEventFilter(this));
+
+ QAbstractItemView *itemView = view();
+ if (itemView != nullptr)
+ itemView->installEventFilter(new KHBoxListEventFilter(this));
+}
diff --git a/krusader/GUI/krhistorycombobox.h b/krusader/GUI/krhistorycombobox.h
new file mode 100755
index 00000000..49056cd3
--- /dev/null
+++ b/krusader/GUI/krhistorycombobox.h
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * Copyright (C) 2018-2019 Shie Erlich *
+ * Copyright (C) 2018-2019 Rafi Yanai *
+ * Copyright (C) 2018-2019 Krusader Krew [https://krusader.org] *
+ * *
+ * This file is part of Krusader [https://krusader.org]. *
+ * *
+ * Krusader 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. *
+ * *
+ * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. *
+ *****************************************************************************/
+
+#ifndef KRHISTORYCOMBOBOX_H
+#define KRHISTORYCOMBOBOX_H
+
+#include
+
+/**
+ * A specialized version of a KHistoryComboBox, e.g. it deletes the current
+ * item when the user presses Shift+Del
+ */
+class KrHistoryComboBox : public KHistoryComboBox
+{
+ Q_OBJECT
+
+public:
+ explicit KrHistoryComboBox(bool useCompletion, QWidget *parent = nullptr);
+};
+
+#endif // KRHISTORYCOMBOBOX_H