mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-20 11:00:44 -06:00
Add a find tool bar to the Browse Data tab
This adds a find tool bar to the Browse Data tab which allows the user to search for values in the current table view. It only looks in non-filtered rows and in non-hidden columns. It respected display formats and sort order, too. The idea is to provide an additional level of searching: the first one is done by using the filters and actually reduces the number of rows in the view; the second level is done by using the new find tool bar and allows you to look for values in the remaining rows (or all rows if there is no filter). See issue #1608.
This commit is contained in:
@@ -127,6 +127,41 @@ TableBrowser::TableBrowser(QWidget* parent) :
|
||||
connect(ui->dataTable->verticalHeader(), &QHeaderView::customContextMenuRequested, this, &TableBrowser::showRecordPopupMenu);
|
||||
connect(ui->dataTable, &ExtendedTableWidget::openFileFromDropEvent, this, &TableBrowser::requestFileOpen);
|
||||
connect(ui->dataTable, &ExtendedTableWidget::selectedRowsToBeDeleted, this, &TableBrowser::deleteRecord);
|
||||
|
||||
// Set up find frame
|
||||
ui->frameFind->hide();
|
||||
|
||||
QShortcut* shortcutHideFindFrame = new QShortcut(QKeySequence("ESC"), ui->editFindExpression);
|
||||
connect(shortcutHideFindFrame, &QShortcut::activated, ui->buttonFindClose, &QToolButton::click);
|
||||
|
||||
connect(ui->actionFind, &QAction::triggered, [this](bool checked) {
|
||||
if(checked)
|
||||
{
|
||||
ui->frameFind->show();
|
||||
ui->editFindExpression->setFocus();
|
||||
} else {
|
||||
ui->buttonFindClose->click();
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->editFindExpression, &QLineEdit::returnPressed, ui->buttonFindNext, &QToolButton::click);
|
||||
connect(ui->editFindExpression, &QLineEdit::textChanged, this, [this]() {
|
||||
// When the text has changed but neither Return nor F3 or similar nor any buttons were pressed, we want to include the current
|
||||
// cell in the search as well. This makes sure the selected cell does not jump around every time the text is changed but only
|
||||
// when the current cell does not match the search expression anymore.
|
||||
find(ui->editFindExpression->text(), true, true);
|
||||
});
|
||||
connect(ui->buttonFindClose, &QToolButton::clicked, this, [this](){
|
||||
ui->dataTable->setFocus();
|
||||
ui->frameFind->hide();
|
||||
ui->actionFind->setChecked(false);
|
||||
});
|
||||
connect(ui->buttonFindPrevious, &QToolButton::clicked, this, [this](){
|
||||
find(ui->editFindExpression->text(), false);
|
||||
});
|
||||
connect(ui->buttonFindNext, &QToolButton::clicked, this, [this](){
|
||||
find(ui->editFindExpression->text(), true);
|
||||
});
|
||||
}
|
||||
|
||||
TableBrowser::~TableBrowser()
|
||||
@@ -219,6 +254,7 @@ void TableBrowser::setEnabled(bool enable)
|
||||
ui->actionRefresh->setEnabled(enable);
|
||||
ui->actionPrintTable->setEnabled(enable);
|
||||
ui->editGlobalFilter->setEnabled(enable);
|
||||
ui->actionFind->setEnabled(enable);
|
||||
|
||||
updateInsertDeleteRecordButton();
|
||||
}
|
||||
@@ -270,7 +306,7 @@ void TableBrowser::updateTable()
|
||||
}
|
||||
statusMessage += tr(". Sum: %1; Average: %2; Min: %3; Max: %4").arg(sum).arg(sum/sel.count()).arg(min).arg(max);
|
||||
}
|
||||
};
|
||||
}
|
||||
emit statusMessageRequested(statusMessage);
|
||||
});
|
||||
}
|
||||
@@ -1162,3 +1198,53 @@ void TableBrowser::jumpToRow(const sqlb::ObjectIdentifier& table, QString column
|
||||
ui->dataTable->filterHeader()->setFilter(static_cast<size_t>(column_index-obj->fields.begin()+1), QString("=") + value);
|
||||
updateTable();
|
||||
}
|
||||
|
||||
void TableBrowser::find(const QString& expr, bool forward, bool include_first)
|
||||
{
|
||||
// Get the cell from which the search should be started. If there is a selected cell, use that. If there is no selected cell, start at the first cell.
|
||||
QModelIndex start;
|
||||
if(ui->dataTable->selectionModel()->hasSelection())
|
||||
start = ui->dataTable->selectionModel()->selectedIndexes().front();
|
||||
else
|
||||
start = m_browseTableModel->index(0, 0);
|
||||
|
||||
// Prepare the match flags with all the search settings
|
||||
Qt::MatchFlags flags = Qt::MatchWrap;
|
||||
|
||||
if(ui->checkFindCaseSensitive->isChecked())
|
||||
flags |= Qt::MatchCaseSensitive;
|
||||
|
||||
if(ui->checkFindWholeCell->isChecked())
|
||||
flags |= Qt::MatchFixedString;
|
||||
else
|
||||
flags |= Qt::MatchContains;
|
||||
|
||||
if(ui->checkFindRegEx->isChecked())
|
||||
flags |= Qt::MatchRegExp;
|
||||
|
||||
// Prepare list of columns to search in. We only search in non-hidden rows
|
||||
std::vector<int> column_list;
|
||||
sqlb::ObjectIdentifier tableName = currentlyBrowsedTableName();
|
||||
if(browseTableSettings[tableName].showRowid)
|
||||
column_list.push_back(0);
|
||||
for(int i=1;i<m_browseTableModel->columnCount();i++)
|
||||
{
|
||||
if(browseTableSettings[tableName].hiddenColumns.contains(i) == false)
|
||||
column_list.push_back(i);
|
||||
else if(browseTableSettings[tableName].hiddenColumns[i] == false)
|
||||
column_list.push_back(i);
|
||||
}
|
||||
|
||||
// Perform the actual search using the model class
|
||||
const auto match = m_browseTableModel->nextMatch(start, column_list, expr, flags, !forward, include_first);
|
||||
|
||||
// Select the next match if we found one
|
||||
if(match.isValid())
|
||||
ui->dataTable->setCurrentIndex(match);
|
||||
|
||||
// Make the expression control red if no results were found
|
||||
if(match.isValid() || expr == "")
|
||||
ui->editFindExpression->setStyleSheet("");
|
||||
else
|
||||
ui->editFindExpression->setStyleSheet("QLineEdit {color: white; background-color: rgb(255, 102, 102)}");
|
||||
}
|
||||
|
||||
@@ -150,6 +150,9 @@ private slots:
|
||||
void browseDataSetTableEncoding(bool forAllTables = false);
|
||||
void browseDataSetDefaultTableEncoding();
|
||||
|
||||
private:
|
||||
void find(const QString& expr, bool forward, bool include_first = false);
|
||||
|
||||
private:
|
||||
Ui::TableBrowser* ui;
|
||||
QIntValidator* gotoValidator;
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>552</width>
|
||||
<height>362</height>
|
||||
<width>617</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -74,6 +74,8 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionNewRecord"/>
|
||||
<addaction name="actionDeleteRecord"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionFind"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -125,6 +127,152 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frameFind">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>31</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="2">
|
||||
<widget class="QToolButton" name="buttonFindNext">
|
||||
<property name="toolTip">
|
||||
<string>Find next match [Enter, F3]</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Find next match with wrapping</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/down</normaloff>:/icons/down</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F3</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QToolButton" name="buttonFindPrevious">
|
||||
<property name="toolTip">
|
||||
<string>Find previous match [Shift+F3]</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Find previous match with mapping</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/up</normaloff>:/icons/up</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Shift+F3</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QCheckBox" name="checkFindRegEx">
|
||||
<property name="toolTip">
|
||||
<string>Interpret search pattern as a regular expression</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Regular Expression</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QCheckBox" name="checkFindWholeCell">
|
||||
<property name="whatsThis">
|
||||
<string>The found pattern must be a whole word</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Whole Cell</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLineEdit" name="editFindExpression">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::DefaultContextMenu</enum>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Text pattern to find considering the checks in this frame</string>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Find in table</string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="8">
|
||||
<widget class="QToolButton" name="buttonFindClose">
|
||||
<property name="toolTip">
|
||||
<string>Close Find Bar</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close Find Bar</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/close</normaloff>:/icons/close</iconset>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="6">
|
||||
<spacer name="horizontalSpacer_1">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QCheckBox" name="checkFindCaseSensitive">
|
||||
<property name="whatsThis">
|
||||
<string>The found pattern must match in letter case</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Case Sensitive</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
@@ -507,6 +655,24 @@
|
||||
<enum>Qt::WidgetShortcut</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFind">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons/icons.qrc">
|
||||
<normaloff>:/icons/find</normaloff>:/icons/find</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Find in cells</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Open the find tool bar which allows you to search for values in the table view below.</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+F</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
@@ -527,6 +693,14 @@
|
||||
<tabstops>
|
||||
<tabstop>comboBrowseTable</tabstop>
|
||||
<tabstop>dataTable</tabstop>
|
||||
<tabstop>editGlobalFilter</tabstop>
|
||||
<tabstop>editFindExpression</tabstop>
|
||||
<tabstop>buttonFindPrevious</tabstop>
|
||||
<tabstop>buttonFindNext</tabstop>
|
||||
<tabstop>checkFindCaseSensitive</tabstop>
|
||||
<tabstop>checkFindWholeCell</tabstop>
|
||||
<tabstop>checkFindRegEx</tabstop>
|
||||
<tabstop>buttonFindClose</tabstop>
|
||||
<tabstop>buttonBegin</tabstop>
|
||||
<tabstop>buttonPrevious</tabstop>
|
||||
<tabstop>buttonNext</tabstop>
|
||||
@@ -545,8 +719,8 @@
|
||||
<slot>updateTable()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>118</x>
|
||||
<y>141</y>
|
||||
<x>159</x>
|
||||
<y>31</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>399</x>
|
||||
@@ -561,8 +735,8 @@
|
||||
<slot>navigatePrevious()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>86</x>
|
||||
<y>539</y>
|
||||
<x>54</x>
|
||||
<y>358</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>399</x>
|
||||
@@ -577,8 +751,8 @@
|
||||
<slot>navigateNext()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>183</x>
|
||||
<y>539</y>
|
||||
<x>139</x>
|
||||
<y>358</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>399</x>
|
||||
@@ -593,8 +767,8 @@
|
||||
<slot>navigateGoto()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>365</x>
|
||||
<y>539</y>
|
||||
<x>403</x>
|
||||
<y>360</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>399</x>
|
||||
@@ -609,8 +783,8 @@
|
||||
<slot>navigateGoto()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>506</x>
|
||||
<y>538</y>
|
||||
<x>550</x>
|
||||
<y>360</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>399</x>
|
||||
@@ -625,8 +799,8 @@
|
||||
<slot>navigateEnd()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>223</x>
|
||||
<y>539</y>
|
||||
<x>169</x>
|
||||
<y>358</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>499</x>
|
||||
@@ -641,8 +815,8 @@
|
||||
<slot>navigateBegin()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>50</x>
|
||||
<y>539</y>
|
||||
<x>24</x>
|
||||
<y>358</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>499</x>
|
||||
@@ -886,7 +1060,7 @@
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>326</x>
|
||||
<y>347</y>
|
||||
<y>291</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <QUrl>
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include <QProgressDialog>
|
||||
#include <QRegularExpression>
|
||||
#include <json.hpp>
|
||||
|
||||
#include "RowLoader.h"
|
||||
@@ -1004,3 +1005,108 @@ void SqliteTableModel::waitUntilIdle () const
|
||||
{
|
||||
worker->waitUntilIdle();
|
||||
}
|
||||
|
||||
QModelIndex SqliteTableModel::nextMatch(const QModelIndex& start, const std::vector<int>& column_list, const QString& value, Qt::MatchFlags flags, bool reverse, bool dont_skip_to_next_field) const
|
||||
{
|
||||
// Extract flags
|
||||
bool whole_cell = !(flags & Qt::MatchContains);
|
||||
bool regex = flags & Qt::MatchRegExp;
|
||||
Qt::CaseSensitivity case_sensitive = ((flags & Qt::MatchCaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive);
|
||||
bool wrap = flags & Qt::MatchWrap;
|
||||
int increment = (reverse ? -1 : 1);
|
||||
|
||||
// Prepare the regular expression for regex mode
|
||||
QRegularExpression reg_exp;
|
||||
if(regex)
|
||||
{
|
||||
reg_exp = QRegularExpression(value, (case_sensitive ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption));
|
||||
if(!reg_exp.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
if(whole_cell)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
|
||||
reg_exp.setPattern("\\A(" + reg_exp.pattern() + ")\\Z");
|
||||
#else
|
||||
reg_exp.setPattern(QRegularExpression::anchoredPattern(reg_exp.pattern()));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until the row count is there
|
||||
waitUntilIdle();
|
||||
|
||||
// Make sure the start position starts in a column from the list of columns to search in
|
||||
QModelIndex pos = start;
|
||||
if(std::find(column_list.begin(), column_list.end(), pos.column()) == column_list.end())
|
||||
{
|
||||
// If for some weird reason the start index is not in the column list, we simply use the first column of the column list instead
|
||||
pos = pos.sibling(pos.row(), reverse ? column_list.back() : column_list.front());
|
||||
}
|
||||
|
||||
// Get the last cell to search in. If wrapping is enabled, we search until we hit the start cell again. If wrapping is not enabled, we start at the last
|
||||
// cell of the table.
|
||||
QModelIndex end = (wrap ? pos : index(rowCount(), column_list.back()));
|
||||
|
||||
// Loop through all cells for the search
|
||||
while(true)
|
||||
{
|
||||
// Go to the next cell and skip all columns in between which we do not care about. This is done as the first step in order
|
||||
// to skip the start index when matching the first cell is disabled.
|
||||
if(dont_skip_to_next_field == false)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
// Next cell position
|
||||
int next_row = pos.row();
|
||||
int next_column = pos.column() + increment;
|
||||
|
||||
// Have we reached the end of the row? Then go to the next one
|
||||
if(next_column < 0 || next_column >= static_cast<int>(m_headers.size()))
|
||||
{
|
||||
next_row += increment;
|
||||
next_column = (reverse ? column_list.back() : column_list.front());
|
||||
}
|
||||
|
||||
// Have we reached the last row? Then wrap around to the first one
|
||||
if(wrap && (next_row < 0 || next_row >= rowCount()))
|
||||
next_row = (reverse ? rowCount()-1 : 0);
|
||||
|
||||
// Set next index for search
|
||||
pos = pos.sibling(next_row, next_column);
|
||||
|
||||
// Have we hit the last column? We have not found anything then
|
||||
if(pos == end)
|
||||
return QModelIndex();
|
||||
|
||||
// Is this a column which we are supposed to search in? If so, stop looking for the next cell and start comparing
|
||||
if(std::find(column_list.begin(), column_list.end(), next_column) != column_list.end())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the next time we hit the above check, we actuall move on to the next cell and do not skip the loop again.
|
||||
dont_skip_to_next_field = false;
|
||||
|
||||
// Get row from cache. If it is not in the cache, load the next chunk from the database
|
||||
const size_t row = static_cast<size_t>(pos.row());
|
||||
if(!m_cache.count(row))
|
||||
{
|
||||
triggerCacheLoad(static_cast<int>(row));
|
||||
waitUntilIdle();
|
||||
}
|
||||
const Row* row_data = &m_cache.at(row);
|
||||
|
||||
// Get cell data
|
||||
const size_t column = static_cast<size_t>(pos.column());
|
||||
QString data = row_data->at(column);
|
||||
|
||||
// Perform comparison
|
||||
if(whole_cell && !regex && data.compare(value, case_sensitive) == 0)
|
||||
return pos;
|
||||
else if(!whole_cell && !regex && data.contains(value, case_sensitive))
|
||||
return pos;
|
||||
else if(regex && reg_exp.match(data).hasMatch())
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,19 @@ public:
|
||||
void addCondFormat(int column, const CondFormat& condFormat);
|
||||
void setCondFormats(int column, const std::vector<CondFormat>& condFormats);
|
||||
|
||||
// Search for the specified expression in the given cells. This intended as a replacement for QAbstractItemModel::match() even though
|
||||
// it does not override it, which - because of the different parameters - is not possible.
|
||||
// start contains the index to start with, column_list contains the ordered list of the columns to look in, value is the value to search for,
|
||||
// flags allows to modify the search process (Qt::MatchContains, Qt::MatchRegExp, Qt::MatchCaseSensitive, and Qt::MatchWrap are understood),
|
||||
// reverse can be set to true to progress through the cells in backwards direction, and dont_skip_to_next_field can be set to true if the current
|
||||
// cell can be matched as well.
|
||||
QModelIndex nextMatch(const QModelIndex& start,
|
||||
const std::vector<int>& column_list,
|
||||
const QString& value,
|
||||
Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchContains),
|
||||
bool reverse = false,
|
||||
bool dont_skip_to_next_field = false) const;
|
||||
|
||||
DBBrowserDB& db() { return m_db; }
|
||||
|
||||
public slots:
|
||||
|
||||
Reference in New Issue
Block a user