Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/common/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,39 @@ bool Configuration::getShowQuickFilter() const
return s.value("showQuickFilter", true).toBool();
}

bool Configuration::getQuickFilterCaseSensitive() const
{
return s.value("quickFilterCaseSensitive", false).toBool();
}

void Configuration::setQuickFilterCaseSensitive(bool caseSensitive)
{
s.setValue("quickFilterCaseSensitive", caseSensitive);
emit quickFilterCaseSensitiveChanged(caseSensitive);
}

bool Configuration::getQuickFilterWholeWords() const
{
return s.value("quickFilterWholeWords", false).toBool();
}

void Configuration::setQuickFilterWholeWords(bool wholeWords)
{
s.setValue("quickFilterWholeWords", wholeWords);
emit quickFilterWholeWordsChanged(wholeWords);
}

bool Configuration::getQuickFilterRegex() const
{
return s.value("quickFilterRegex", false).toBool();
}

void Configuration::setQuickFilterRegex(bool regex)
{
s.setValue("quickFilterRegex", regex);
emit quickFilterRegexChanged(regex);
}

void Configuration::setItemCountVisible(bool visible)
{
s.setValue("itemCountVisible", visible);
Expand Down
12 changes: 12 additions & 0 deletions src/common/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,15 @@ class CUTTER_EXPORT Configuration : public QObject
*/
bool getShowQuickFilter() const;

bool getQuickFilterCaseSensitive() const;
void setQuickFilterCaseSensitive(bool caseSensitive);

bool getQuickFilterWholeWords() const;
void setQuickFilterWholeWords(bool wholeWords);

bool getQuickFilterRegex() const;
void setQuickFilterRegex(bool regex);

/**
* @brief Enable or disable the visibility of the item count label within the Quick Filter
* @param visible Set to true to show the item count, false to hide it
Expand Down Expand Up @@ -411,6 +420,9 @@ public slots:
void interfaceThemeChanged();
void itemCountOptionsChanged();
void quickFilterOptionsChanged();
void quickFilterCaseSensitiveChanged(bool caseSensitive);
void quickFilterWholeWordsChanged(bool wholeWords);
void quickFilterRegexChanged(bool regex);
void functionsOptionsChanged();
#ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING
void kSyntaxHighlightingThemeChanged();
Expand Down
2 changes: 2 additions & 0 deletions src/common/CutterSearchable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

#include <QAbstractScrollArea>
#include <QObject>
#include <QRegularExpression>
#include <QScrollBar>
#include <QSortFilterProxyModel>

void CutterSearchableHelper::setupConnections(QWidget *parent, SearchBarWidget *searchBar)
{
Expand Down
4 changes: 3 additions & 1 deletion src/common/CutterSearchable.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "CutterCommon.h"

class QString;
class QSortFilterProxyModel;
class SearchBarWidget;
class QWidget;

Expand Down Expand Up @@ -81,6 +82,7 @@ void setupConnections(QWidget *parent, SearchBarWidget *bar);
*/
void positionSearchBar(QWidget *parent, SearchBarWidget *searchBar, QWidget *searchArea,
int hPadding, int vPadding);
};

} // namespace CutterSearchableHelper

#endif // CUTTERSEARCHABLE_H
45 changes: 45 additions & 0 deletions src/common/Helpers.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "common/Helpers.h"

#include "Configuration.h"
#include "CutterSearchable.h"

#include <QAbstractButton>
#include <QAbstractItemView>
Expand All @@ -10,6 +11,8 @@
#include <QFileInfo>
#include <QMenu>
#include <QPlainTextEdit>
#include <QRegularExpression>
#include <QSortFilterProxyModel>
#include <QString>
#include <QTextEdit>
#include <QTreeWidget>
Expand Down Expand Up @@ -296,6 +299,48 @@ bool filterStringContains(const QString &string, const QSortFilterProxyModel *mo
#endif
}

void applyFilter(QSortFilterProxyModel *proxyModel, const QString &filterText, int options)
{
if (!proxyModel) {
return;
}

if (filterText.isEmpty()) {
proxyModel->setFilterFixedString(QString());
return;
}

QRegularExpression::PatternOptions patternOptions = QRegularExpression::NoPatternOption;
if (!(options & CaseSensitive)) {
patternOptions |= QRegularExpression::CaseInsensitiveOption;
}

if (options & RegExp) {
const QRegularExpression regExp(filterText, patternOptions);
if (regExp.isValid()) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
proxyModel->setFilterRegularExpression(regExp);
#else
proxyModel->setFilterRegExp(regExp.pattern());
#endif
}
} else if (options & WholeWords) {
const QString pattern = QString("\\b%1\\b").arg(QRegularExpression::escape(filterText));
const QRegularExpression regExp(pattern, patternOptions);
if (regExp.isValid()) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
proxyModel->setFilterRegularExpression(regExp);
#else
proxyModel->setFilterRegExp(regExp.pattern());
#endif
}
} else {
proxyModel->setFilterCaseSensitivity((options & CaseSensitive) ? Qt::CaseSensitive
: Qt::CaseInsensitive);
proxyModel->setFilterWildcard(filterText);
}
}

QPointF mouseEventPos(QMouseEvent *ev)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
Expand Down
9 changes: 9 additions & 0 deletions src/common/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ CUTTER_EXPORT void emitColumnChanged(QAbstractItemModel *model, int column);

CUTTER_EXPORT bool filterStringContains(const QString &string, const QSortFilterProxyModel *model);

/**
* @brief Applies filter options to a proxy model
* @param proxyModel The proxy model to filter
* @param filterText The text to filter by
* @param options Bitwise combination of SearchOption flags (CaseSensitive, WholeWords, RegExp)
*/
CUTTER_EXPORT void applyFilter(QSortFilterProxyModel *proxyModel, const QString &filterText,
int options);

#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
using ColorFloat = float;
using KeyComb = QKeyCombination;
Expand Down
9 changes: 6 additions & 3 deletions src/dialogs/TypesVariablesDialog.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "TypesVariablesDialog.h"

#include "Cutter.h"
#include "common/CutterSearchable.h"
#include "ui_TypesVariablesDialog.h"

QString toString(VariableScope scope)
Expand Down Expand Up @@ -168,9 +169,11 @@ TypesVariablesDialog::TypesVariablesDialog(QWidget *parent, const QString &typeN

auto updateCount = [this]() { ui->quickFilterView->setItemCount(proxyModel->rowCount()); };

connect(ui->quickFilterView, &ComboQuickFilterView::filterTextChanged, proxyModel,
&TypesVariablesProxyModel::setFilterFixedString);
connect(ui->quickFilterView, &ComboQuickFilterView::filterTextChanged, this, updateCount);
connect(ui->quickFilterView, &ComboQuickFilterView::filterChanged, this,
[this](const QString &text, int options) {
qhelpers::applyFilter(proxyModel, text, options);
});
connect(ui->quickFilterView, &ComboQuickFilterView::filterChanged, this, updateCount);

connect(scopeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
[this, scopeCombo, updateCount](int index) {
Expand Down
12 changes: 8 additions & 4 deletions src/dialogs/XrefsDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,14 @@ XrefsDialog::XrefsDialog(MainWindow *parent, bool hideXrefFrom)
&XrefsDialog::onToTreeWidgetItemSelectionChanged);
connect(ui->fromTreeWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&XrefsDialog::onFromTreeWidgetItemSelectionChanged);
connect(ui->fromQuickFilter, &QuickFilterView::filterTextChanged, &fromProxyModel,
&QSortFilterProxyModel::setFilterWildcard);
connect(ui->toQuickFilter, &QuickFilterView::filterTextChanged, &toProxyModel,
&QSortFilterProxyModel::setFilterWildcard);
connect(ui->fromQuickFilter, &QuickFilterView::filterChanged, this,
[this](const QString &text, int options) {
qhelpers::applyFilter(&fromProxyModel, text, options);
});
connect(ui->toQuickFilter, &QuickFilterView::filterChanged, this,
[this](const QString &text, int options) {
qhelpers::applyFilter(&toProxyModel, text, options);
});

// SearchWidget shortcuts

Expand Down
11 changes: 11 additions & 0 deletions src/dialogs/preferences/InterfaceOptionsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ void InterfaceOptionsWidget::setUpQuickFilter()
connect(ui->quickFilterCheckBox, &QCheckBox::toggled, Config(),
&Configuration::setShowQuickFilter);

ui->caseSensitiveCheckBox->setChecked(Config()->getQuickFilterCaseSensitive());
connect(ui->caseSensitiveCheckBox, &QCheckBox::toggled, Config(),
&Configuration::setQuickFilterCaseSensitive);

ui->wholeWordsCheckBox->setChecked(Config()->getQuickFilterWholeWords());
connect(ui->wholeWordsCheckBox, &QCheckBox::toggled, Config(),
&Configuration::setQuickFilterWholeWords);

ui->regexCheckBox->setChecked(Config()->getQuickFilterRegex());
connect(ui->regexCheckBox, &QCheckBox::toggled, Config(), &Configuration::setQuickFilterRegex);

ui->itemCountCheckBox->setChecked(Config()->getItemCountVisible());
connect(ui->itemCountCheckBox, &QCheckBox::toggled, this, [this](bool checked) {
Config()->setItemCountVisible(checked);
Expand Down
21 changes: 21 additions & 0 deletions src/dialogs/preferences/InterfaceOptionsWidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,27 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="caseSensitiveCheckBox">
<property name="text">
<string>Use case sensitive by default</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="wholeWordsCheckBox">
<property name="text">
<string>Match whole words by default</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="regexCheckBox">
<property name="text">
<string>Use regex by default</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="itemCountCheckBox">
<property name="text">
Expand Down
2 changes: 1 addition & 1 deletion src/dialogs/preferences/RizinConfigOptionsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ RizinConfigOptionsWidget::RizinConfigOptionsWidget(PreferencesDialog *parent)
}
});

connect(ui->comboQuickFilter, &ComboQuickFilterView::filterTextChanged, this,
connect(ui->comboQuickFilter, &ComboQuickFilterView::filterChanged, this,
[this](const QString &text) {
proxyModel->setFilterWildcard(text);
updateItemCount();
Expand Down
57 changes: 56 additions & 1 deletion src/widgets/AbstractFilterView.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,57 @@
#include "AbstractFilterView.h"

#include "common/CutterSearchable.h"
#include "common/Helpers.h"
#include "common/Configuration.h"

#include <QAction>
#include <QIcon>
#include <QMenu>

AbstractFilterView::AbstractFilterView(QWidget *parent) : QWidget(parent) {}

void AbstractFilterView::setupSharedConnections()
{
auto *optionsMenu = new QMenu(this);
caseSensitiveAction = optionsMenu->addAction(tr("&Case Sensitive"));
caseSensitiveAction->setCheckable(true);
caseSensitiveAction->setChecked(Config()->getQuickFilterCaseSensitive());

wholeWordsAction = optionsMenu->addAction(tr("&Exact Match"));
wholeWordsAction->setCheckable(true);
Comment on lines +15 to +21

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works, but in my opinion there should be options in "Edit->Preferences->Interface" under the "Quick Filter" tab for these three things:

  • Use case sensitive by default
  • Match whole words by default
  • Use regex by default

User preference should be saved, just so that if a user always prefers case sensitive search they don't have to manually change it each time cutter is opened

The actions will be added/handled in "InterfaceOptionsWidget"

wholeWordsAction->setChecked(Config()->getQuickFilterWholeWords());

regexAction = optionsMenu->addAction(tr("&Regular Expression"));
regexAction->setCheckable(true);
Comment on lines +15 to +25

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're going to use the "&" shortcut then you should use them for all three actions, currently it's only being used on "Case sensitive" action

Also, there should be a shortcut key in my opinion that opens the actions menu. Default shortcuts are defined in "shortcuts/DefaultShortcuts.cpp"

regexAction->setChecked(Config()->getQuickFilterRegex());

auto emitFilterChanged = [this]() { emit filterChanged(lineEdit()->text(), filterOptions()); };

connect(caseSensitiveAction, &QAction::toggled, this, emitFilterChanged);
connect(Config(), &Configuration::quickFilterCaseSensitiveChanged, caseSensitiveAction, &QAction::setChecked);

connect(wholeWordsAction, &QAction::toggled, this, emitFilterChanged);
connect(Config(), &Configuration::quickFilterWholeWordsChanged, wholeWordsAction, &QAction::setChecked);

connect(regexAction, &QAction::toggled, this, emitFilterChanged);
connect(Config(), &Configuration::quickFilterRegexChanged, regexAction, &QAction::setChecked);

auto *optionsAction = new QAction(this);
const int lineEditHeight = lineEdit()->fontMetrics().height();
const int targetIconSize = qRound(lineEditHeight * 0.8);
const QIcon cogIcon(":/img/icons/cog_light.svg");
const qreal dpr = qhelpers::devicePixelRatio(this);
QPixmap pixmap = cogIcon.pixmap(qRound(targetIconSize * dpr), qRound(targetIconSize * dpr));
pixmap.setDevicePixelRatio(dpr);
optionsAction->setIcon(pixmap);
optionsAction->setMenu(optionsMenu);
lineEdit()->addAction(optionsAction, QLineEdit::LeadingPosition);

debounceTimer = new QTimer(this);
debounceTimer->setSingleShot(true);

connect(debounceTimer, &QTimer::timeout, this,
[this]() { emit filterTextChanged(lineEdit()->text()); });
[this]() { emit filterChanged(lineEdit()->text(), filterOptions()); });

connect(lineEdit(), &QLineEdit::textChanged, this, [this]() { debounceTimer->start(150); });
}
Expand Down Expand Up @@ -44,6 +84,21 @@ void AbstractFilterView::closeFilter()
emit filterClosed();
}

int AbstractFilterView::filterOptions() const
{
int options = 0;
if (caseSensitiveAction->isChecked()) {
options |= SearchOption::CaseSensitive;
}
if (wholeWordsAction->isChecked()) {
options |= SearchOption::WholeWords;
}
if (regexAction->isChecked()) {
options |= SearchOption::RegExp;
}
return options;
}

void AbstractFilterView::showCustomContextMenu(const QPoint &pos)
{
const QWidget *child = this->childAt(pos);
Expand Down
15 changes: 12 additions & 3 deletions src/widgets/AbstractFilterView.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include "ItemCountLineEdit.h"

#include <QAction>
#include <QPoint>
#include <QTimer>
#include <QWidget>

Expand All @@ -15,17 +17,18 @@ class AbstractFilterView : public QWidget
Q_OBJECT
public:
explicit AbstractFilterView(QWidget *parent = nullptr);
virtual ~AbstractFilterView() = default;

virtual void setItemCount(int count);
virtual void showItemCount(bool show);

void showFilter();
void clearFilter();
virtual void clearFilter();

virtual void closeFilter();

signals:
void filterTextChanged(const QString &text);
void filterChanged(const QString &text, int options);
void filterClosed();

protected:
Expand All @@ -34,7 +37,13 @@ class AbstractFilterView : public QWidget
void setupSharedConnections();
void showCustomContextMenu(const QPoint &pos);

QTimer *debounceTimer;
int filterOptions() const;

QTimer *debounceTimer = nullptr;

QAction *caseSensitiveAction = nullptr;
QAction *wholeWordsAction = nullptr;
QAction *regexAction = nullptr;
};

#endif // ABSTRACTFILTERVIEW_H
Loading