mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-20 02:50:46 -06:00
Regexp filters
This adds support for the REGEXP operator using the syntax /regexp/ in the filter line boxes. A new helper option for a not-containing filter is added using this new syntax. This could be simplified using a NOT LIKE filter, but we don't currently support that. The "Use in Filter Expression > Containing" option escapes a possible slash in the beginning, so it is not interpreted as a regexp filter. See issue #1522
This commit is contained in:
@@ -72,6 +72,10 @@ QString CondFormat::filterToSqlCondition(const QString& value, const QString& en
|
||||
op = "IS";
|
||||
numeric = true;
|
||||
}
|
||||
} else if(value.left(1) == "/" && value.right(1) == "/" && value.length() > 2) {
|
||||
val = value.mid(1, value.length() - 2);
|
||||
op = "REGEXP";
|
||||
numeric = false;
|
||||
} else {
|
||||
// Keep the default LIKE operator
|
||||
|
||||
|
||||
@@ -194,12 +194,14 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
|
||||
|
||||
QAction* filterAction = new QAction(tr("Use as Exact Filter"), m_contextMenu);
|
||||
QAction* containingAction = new QAction(tr("Containing"), m_contextMenu);
|
||||
QAction* notContainingAction = new QAction(tr("Not containing"), m_contextMenu);
|
||||
QAction* notEqualToAction = new QAction(tr("Not equal to"), m_contextMenu);
|
||||
QAction* greaterThanAction = new QAction(tr("Greater than"), m_contextMenu);
|
||||
QAction* lessThanAction = new QAction(tr("Less than"), m_contextMenu);
|
||||
QAction* greaterEqualAction = new QAction(tr("Greater or equal"), m_contextMenu);
|
||||
QAction* lessEqualAction = new QAction(tr("Less or equal"), m_contextMenu);
|
||||
QAction* inRangeAction = new QAction(tr("Between this and..."), m_contextMenu);
|
||||
QAction* regexpAction = new QAction(tr("Regular expression"), m_contextMenu);
|
||||
|
||||
QAction* nullAction = new QAction(tr("Set to NULL"), m_contextMenu);
|
||||
QAction* copyAction = new QAction(QIcon(":/icons/copy"), tr("Copy"), m_contextMenu);
|
||||
@@ -211,12 +213,14 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
|
||||
m_contextMenu->addAction(filterAction);
|
||||
QMenu* filterMenu = m_contextMenu->addMenu(tr("Use in Filter Expression"));
|
||||
filterMenu->addAction(containingAction);
|
||||
filterMenu->addAction(notContainingAction);
|
||||
filterMenu->addAction(notEqualToAction);
|
||||
filterMenu->addAction(greaterThanAction);
|
||||
filterMenu->addAction(lessThanAction);
|
||||
filterMenu->addAction(greaterEqualAction);
|
||||
filterMenu->addAction(lessEqualAction);
|
||||
filterMenu->addAction(inRangeAction);
|
||||
filterMenu->addAction(regexpAction);
|
||||
|
||||
m_contextMenu->addSeparator();
|
||||
m_contextMenu->addAction(nullAction);
|
||||
@@ -274,6 +278,10 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
|
||||
connect(containingAction, &QAction::triggered, [&]() {
|
||||
useAsFilter(QString (""));
|
||||
});
|
||||
// Use a regular expression for the not containing filter. Simplify this if we ever support the NOT LIKE filter.
|
||||
connect(notContainingAction, &QAction::triggered, [&]() {
|
||||
useAsFilter(QString ("/^((?!"), /* binary */ false, QString (").)*$/"));
|
||||
});
|
||||
connect(notEqualToAction, &QAction::triggered, [&]() {
|
||||
useAsFilter(QString ("<>"));
|
||||
});
|
||||
@@ -292,6 +300,9 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
|
||||
connect(inRangeAction, &QAction::triggered, [&]() {
|
||||
useAsFilter(QString ("~"), /* binary */ true);
|
||||
});
|
||||
connect(regexpAction, &QAction::triggered, [&]() {
|
||||
useAsFilter(QString ("/"), /* binary */ false, QString ("/"));
|
||||
});
|
||||
|
||||
connect(nullAction, &QAction::triggered, [&]() {
|
||||
for(const QModelIndex& index : selectedIndexes())
|
||||
@@ -611,7 +622,7 @@ void ExtendedTableWidget::paste()
|
||||
}
|
||||
}
|
||||
|
||||
void ExtendedTableWidget::useAsFilter(const QString& filterOperator, bool binary)
|
||||
void ExtendedTableWidget::useAsFilter(const QString& filterOperator, bool binary, const QString& operatorSuffix)
|
||||
{
|
||||
QModelIndex index = selectionModel()->currentIndex();
|
||||
SqliteTableModel* m = qobject_cast<SqliteTableModel*>(model());
|
||||
@@ -632,14 +643,14 @@ void ExtendedTableWidget::useAsFilter(const QString& filterOperator, bool binary
|
||||
// When Containing filter is requested (empty operator) and the value starts with
|
||||
// an operator character, the character is escaped.
|
||||
if (filterOperator.isEmpty())
|
||||
value.replace(QRegExp("^(<|>|=)"), Settings::getValue("databrowser", "filter_escape").toString() + QString("\\1"));
|
||||
value.replace(QRegExp("^(<|>|=|/)"), Settings::getValue("databrowser", "filter_escape").toString() + QString("\\1"));
|
||||
|
||||
// If binary operator, the cell data is used as first value and
|
||||
// the second value must be added by the user.
|
||||
if (binary)
|
||||
m_tableHeader->setFilter(index.column(), value + filterOperator);
|
||||
else
|
||||
m_tableHeader->setFilter(index.column(), filterOperator + value);
|
||||
m_tableHeader->setFilter(index.column(), filterOperator + value + operatorSuffix);
|
||||
}
|
||||
|
||||
void ExtendedTableWidget::duplicateUpperCell()
|
||||
|
||||
@@ -69,7 +69,7 @@ private:
|
||||
void copy(const bool withHeaders, const bool inSQL);
|
||||
void paste();
|
||||
|
||||
void useAsFilter(const QString& filterOperator, bool binary = false);
|
||||
void useAsFilter(const QString& filterOperator, bool binary = false, const QString& operatorSuffix = "");
|
||||
void duplicateUpperCell();
|
||||
|
||||
typedef QList<QByteArray> QByteArrayList;
|
||||
|
||||
@@ -32,7 +32,8 @@ FilterLineEdit::FilterLineEdit(QWidget* parent, QList<FilterLineEdit*>* filters,
|
||||
"<=\tEqual to or less\n"
|
||||
"=\tEqual to: exact match\n"
|
||||
"<>\tUnequal: exact inverse match\n"
|
||||
"x~y\tRange: values between x and y"));
|
||||
"x~y\tRange: values between x and y\n"
|
||||
"/regexp/\tValues matching the regular expression"));
|
||||
|
||||
// Immediately emit the delayed filter value changed signal if the user presses the enter or the return key or
|
||||
// the line edit widget loses focus
|
||||
@@ -94,11 +95,11 @@ void FilterLineEdit::setText(const QString& text)
|
||||
delayedSignalTimerTriggered();
|
||||
}
|
||||
|
||||
void FilterLineEdit::setFilterHelper(const QString& filterOperator)
|
||||
void FilterLineEdit::setFilterHelper(const QString& filterOperator, const QString& operatorSuffix)
|
||||
{
|
||||
setText(filterOperator + "?");
|
||||
setText(filterOperator + "?" + operatorSuffix);
|
||||
// Select the value for easy editing of the expression
|
||||
setSelection(filterOperator.length(), filterOperator.length());
|
||||
setSelection(filterOperator.length(), 1);
|
||||
}
|
||||
|
||||
void FilterLineEdit::showContextMenu(const QPoint &pos)
|
||||
@@ -143,7 +144,11 @@ void FilterLineEdit::showContextMenu(const QPoint &pos)
|
||||
connect(isNotEmptyAction, &QAction::triggered, [&]() {
|
||||
setText("<>''");
|
||||
});
|
||||
|
||||
// Simplify this if we ever support a NOT LIKE filter
|
||||
QAction* notContainingAction = new QAction(tr("Not containing..."), editContextMenu);
|
||||
connect(notContainingAction, &QAction::triggered, [&]() {
|
||||
setFilterHelper(QString ("/^((?!"), QString(").)*$/"));
|
||||
});
|
||||
QAction* equalToAction = new QAction(tr("Equal to..."), editContextMenu);
|
||||
connect(equalToAction, &QAction::triggered, [&]() {
|
||||
setFilterHelper(QString ("="));
|
||||
@@ -173,6 +178,11 @@ void FilterLineEdit::showContextMenu(const QPoint &pos)
|
||||
setFilterHelper(QString ("?~"));
|
||||
});
|
||||
|
||||
QAction* regexpAction = new QAction(tr("Regular expression..."), editContextMenu);
|
||||
connect(regexpAction, &QAction::triggered, [&]() {
|
||||
setFilterHelper(QString ("/"), QString ("/"));
|
||||
});
|
||||
|
||||
editContextMenu->addAction(conditionalFormatAction);
|
||||
|
||||
filterMenu->addAction(whatsThisAction);
|
||||
@@ -182,6 +192,7 @@ void FilterLineEdit::showContextMenu(const QPoint &pos)
|
||||
filterMenu->addAction(isEmptyAction);
|
||||
filterMenu->addAction(isNotEmptyAction);
|
||||
filterMenu->addSeparator();
|
||||
filterMenu->addAction(notContainingAction);
|
||||
filterMenu->addAction(equalToAction);
|
||||
filterMenu->addAction(notEqualToAction);
|
||||
filterMenu->addAction(greaterThanAction);
|
||||
@@ -189,6 +200,6 @@ void FilterLineEdit::showContextMenu(const QPoint &pos)
|
||||
filterMenu->addAction(greaterEqualAction);
|
||||
filterMenu->addAction(lessEqualAction);
|
||||
filterMenu->addAction(inRangeAction);
|
||||
|
||||
filterMenu->addAction(regexpAction);
|
||||
editContextMenu->exec(mapToGlobal(pos));
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ signals:
|
||||
|
||||
protected:
|
||||
void keyReleaseEvent(QKeyEvent* event) override;
|
||||
void setFilterHelper(const QString& filterOperator);
|
||||
void setFilterHelper(const QString& filterOperator, const QString& operatorSuffix = "");
|
||||
|
||||
private:
|
||||
QList<FilterLineEdit*>* filterList;
|
||||
|
||||
Reference in New Issue
Block a user