Begin filter keywords support

This commit is contained in:
Albert S. 2018-09-02 12:27:23 +02:00
parent 40b804e8d8
commit 9de30ce8e7
4 changed files with 161 additions and 30 deletions

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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();