Begin filter keywords support
This commit is contained in:
父節點
40b804e8d8
當前提交
9de30ce8e7
@ -33,10 +33,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
void MainWindow::connectSignals()
|
||||
{
|
||||
connect(ui->txtSearch, &QLineEdit::textChanged, this, &MainWindow::lineEditTextChanged);
|
||||
connect(ui->txtSearch, &QLineEdit::returnPressed, this, &MainWindow::lineEditReturnPressed);
|
||||
connect(this, &MainWindow::beginFileSearch, searchWorker, &SearchWorker::searchForFile);
|
||||
connect(this, &MainWindow::beginContentSearch, searchWorker, &SearchWorker::searchForContent);
|
||||
connect(this, &MainWindow::beginSearch, searchWorker, &SearchWorker::search);
|
||||
connect(searchWorker, &SearchWorker::searchResultsReady, this, &MainWindow::handleSearchResults);
|
||||
connect(searchWorker, &SearchWorker::searchCancelled, this, &MainWindow::handleCancelledSearch);
|
||||
connect(ui->treeResultsList, &QTreeWidget::itemActivated, this, &MainWindow::treeSearchItemActivated);
|
||||
@ -98,26 +96,10 @@ void MainWindow::pdfPreviewReceived(PdfPreview preview)
|
||||
}
|
||||
|
||||
void MainWindow::lineEditReturnPressed()
|
||||
{
|
||||
if(pdfTabActive() && pdfDirty)
|
||||
{
|
||||
makePdfPreview();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::lineEditTextChanged()
|
||||
{
|
||||
QString q = ui->txtSearch->text();
|
||||
if(q.startsWith("|"))
|
||||
{
|
||||
q = q.mid(1);
|
||||
emit beginContentSearch(q);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit beginFileSearch(q);
|
||||
}
|
||||
|
||||
//TODO: validate q;
|
||||
emit beginSearch(q);
|
||||
}
|
||||
|
||||
void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
|
||||
@ -147,6 +129,10 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
|
||||
ui->treeResultsList->resizeColumnToContents(0);
|
||||
ui->treeResultsList->resizeColumnToContents(1);
|
||||
pdfDirty = ! this->pdfSearchResults.empty();
|
||||
if(pdfTabActive() && pdfDirty)
|
||||
{
|
||||
makePdfPreview();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,7 @@ public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
signals:
|
||||
void beginFileSearch(const QString &query);
|
||||
void beginContentSearch(const QString &query);
|
||||
void beginSearch(const QString &query);
|
||||
void startPdfPreviewGeneration(QVector<SearchResult> paths, double scalefactor);
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
@ -39,7 +38,6 @@ private:
|
||||
unsigned int processedPdfPreviews;
|
||||
private slots:
|
||||
void lineEditReturnPressed();
|
||||
void lineEditTextChanged();
|
||||
void handleSearchResults(const QVector<SearchResult> &results);
|
||||
void handleCancelledSearch();
|
||||
void treeSearchItemActivated(QTreeWidgetItem *item, int i);
|
||||
|
@ -1,13 +1,15 @@
|
||||
#include "searchworker.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QDebug>
|
||||
#include <QSqlError>
|
||||
SearchWorker::SearchWorker()
|
||||
{
|
||||
|
||||
}
|
||||
SearchWorker::SearchWorker(const QString &dbpath)
|
||||
{
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
|
||||
db = QSqlDatabase::addDatabase("QSQLITE");
|
||||
db.setDatabaseName(dbpath);
|
||||
if(!db.open())
|
||||
{
|
||||
@ -20,12 +22,115 @@ SearchWorker::SearchWorker(const QString &dbpath)
|
||||
queryContent->prepare("SELECT file.path, content.page, file.mtime FROM file INNER JOIN content ON file.id = content.fileid INNER JOIN content_fts ON content.id = content_fts.ROWID WHERE content_fts.content MATCH ? ORDER By file.mtime DESC, content.page ASC");
|
||||
}
|
||||
|
||||
|
||||
QString normalize(QString str)
|
||||
QVector<SearchWorker::Command> SearchWorker::tokenize(QString expression)
|
||||
{
|
||||
str = str.replace(" ", " AND ");
|
||||
str = str.replace("|", " OR ");
|
||||
return str;
|
||||
//TODO: merge lonewords
|
||||
QVector<Command> result;
|
||||
QRegularExpression rx("((?<filtername>(\\.|\\w)+):(?<args>\\((?<innerargs>[^\\)]+)\\)|(\\w)+)|(?<boolean>AND|OR|!)|(?<bracket>\\(|\\))|(?<loneword>\\w+))");
|
||||
QRegularExpressionMatchIterator i = rx.globalMatch(expression);
|
||||
bool wasbool = true;
|
||||
while(i.hasNext())
|
||||
{
|
||||
QRegularExpressionMatch m = i.next();
|
||||
QString boolean = m.captured("boolean");
|
||||
QString filtername = m.captured("filtername");
|
||||
QString bracket = m.captured("bracket");
|
||||
QString loneword = m.captured("loneword");
|
||||
if(boolean != "")
|
||||
{
|
||||
/* if(wasbool)
|
||||
{
|
||||
throw new std::runtime_error("Bool after Bool is invalid");
|
||||
}*/
|
||||
wasbool = true;
|
||||
result.append(Command(boolean));
|
||||
}
|
||||
|
||||
if(bracket != "")
|
||||
{
|
||||
if(!wasbool)
|
||||
{
|
||||
if(bracket == "(")
|
||||
{
|
||||
result.append(Command("AND"));
|
||||
}
|
||||
}
|
||||
result.append(Command(bracket));
|
||||
}
|
||||
|
||||
|
||||
if(loneword != "")
|
||||
{
|
||||
if(!wasbool)
|
||||
{
|
||||
result.append(Command("AND"));
|
||||
}
|
||||
wasbool = false;
|
||||
result.append(Command("contains", loneword));
|
||||
}
|
||||
if(filtername != "")
|
||||
{
|
||||
if(!wasbool)
|
||||
{
|
||||
result.append(Command("AND"));
|
||||
}
|
||||
wasbool = false;
|
||||
QString value = m.captured("innerargs");
|
||||
if(value == "")
|
||||
value = m.captured("args");
|
||||
result.append(Command(filtername, value));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString SearchWorker::createSql(const SearchWorker::Command &cmd)
|
||||
{
|
||||
QString key = cmd.key;
|
||||
QString value = cmd.value;
|
||||
if(key == "AND" || key == "OR" || key=="(" || key==")")
|
||||
{
|
||||
return " " + key + " ";
|
||||
}
|
||||
if(key == "!")
|
||||
{
|
||||
return " NOT ";
|
||||
}
|
||||
if(key == "path.starts")
|
||||
{
|
||||
return " file.path LIKE '" + value + "%' ";
|
||||
}
|
||||
if(key == "path.ends")
|
||||
{
|
||||
return " file.path LIKE '%" + value + "' ";
|
||||
}
|
||||
if(key == "path.contains" || key == "inpath")
|
||||
{
|
||||
return " file.path LIKE '%" + value + "%' ";
|
||||
}
|
||||
if(key == "page")
|
||||
{
|
||||
return " content.page = " + value;
|
||||
}
|
||||
if(key == "contains")
|
||||
{
|
||||
return " ( COALESCE( (SELECT 1 FROM content_fts WHERE content_fts.content MATCH '" + value + "' AND content_fts.ROWID= content.id), 0 ) )";
|
||||
}
|
||||
qDebug() << "NOHIT" << key;
|
||||
//TODO: exception?
|
||||
return "NOTHING";
|
||||
}
|
||||
|
||||
QString SearchWorker::makeSql(const QVector<SearchWorker::Command> &tokens)
|
||||
{
|
||||
QString result;
|
||||
for(const Command &c : tokens)
|
||||
{
|
||||
result += createSql(c);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void SearchWorker::searchForFile(const QString &query)
|
||||
{
|
||||
@ -60,3 +165,25 @@ void SearchWorker::searchForContent(const QString &query)
|
||||
emit searchResultsReady(results);
|
||||
}
|
||||
|
||||
void SearchWorker::search(const QString &query)
|
||||
{
|
||||
QSqlQuery dbquery(db);
|
||||
QVector<SearchResult> results;
|
||||
QString whereSql = makeSql(tokenize(query));
|
||||
QString prep = "SELECT file.path AS path, content.page AS page, file.mtime AS mtime FROM file INNER JOIN content ON file.id = content.fileid INNER JOIN content_fts ON content.id = content_fts.ROWID WHERE 1=1 AND " + whereSql + " ORDER By file.mtime DESC, content.page ASC";
|
||||
dbquery.prepare(prep);
|
||||
dbquery.exec();
|
||||
qDebug() << "prepped: " << prep;
|
||||
qDebug() << dbquery.lastError();
|
||||
while(dbquery.next())
|
||||
{
|
||||
SearchResult result;
|
||||
|
||||
result.path = dbquery.value("path").toString();
|
||||
result.page = dbquery.value("page").toUInt();
|
||||
result.mtime = dbquery.value("mtime").toUInt();
|
||||
results.append(result);
|
||||
}
|
||||
emit searchResultsReady(results);
|
||||
}
|
||||
|
||||
|
@ -9,16 +9,36 @@
|
||||
|
||||
class SearchWorker : public QObject
|
||||
{
|
||||
class Command
|
||||
{
|
||||
public:
|
||||
QString key;
|
||||
QString value;
|
||||
|
||||
Command(QString key="", QString value="")
|
||||
{
|
||||
this->key = key;
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
Q_OBJECT
|
||||
private:
|
||||
QSqlQuery *queryFile;
|
||||
QSqlQuery *queryContent;
|
||||
QVector<Command> tokenize(QString expression);
|
||||
QString createSql(const Command &cmd);
|
||||
QString makeSql(const QVector<Command> &tokens);
|
||||
QSqlDatabase db;
|
||||
public:
|
||||
SearchWorker();
|
||||
SearchWorker(const QString &dbpath);
|
||||
public slots:
|
||||
void searchForFile(const QString &query);
|
||||
void searchForContent(const QString &query);
|
||||
void search(const QString &query);
|
||||
signals:
|
||||
void searchResultsReady(const QVector<SearchResult> &results);
|
||||
void searchCancelled();
|
||||
|
載入中…
新增問題並參考
Block a user