paging for pdfpreviews

This commit is contained in:
Albert S. 2019-08-26 09:20:21 +02:00
parent fae104d094
commit 582abc333f
3 changed files with 227 additions and 189 deletions

View File

@ -17,260 +17,277 @@
#include "../shared/sqlitesearch.h" #include "../shared/sqlitesearch.h"
#include "../shared/qssgeneralexception.h" #include "../shared/qssgeneralexception.h"
MainWindow::MainWindow(QWidget *parent) : MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::MainWindow) ui(new Ui::MainWindow)
{ {
ui->setupUi(this); ui->setupUi(this);
QSettings settings;
db = QSqlDatabase::addDatabase("QSQLITE"); db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(QSettings().value("dbpath").toString()); db.setDatabaseName(settings.value("dbpath").toString());
if(!db.open()) if(!db.open())
{ {
qDebug() << "failed to open database"; qDebug() << "failed to open database";
throw std::runtime_error("Failed to open database"); throw std::runtime_error("Failed to open database");
} }
connectSignals(); connectSignals();
ui->treeResultsList->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu); ui->treeResultsList->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
ui->tabWidget->setCurrentIndex(0); ui->tabWidget->setCurrentIndex(0);
ui->statusBar->addWidget(ui->lblSearchResults); ui->statusBar->addWidget(ui->lblSearchResults);
ui->statusBar->addWidget(ui->pdfProcessBar); ui->statusBar->addWidget(ui->pdfProcessBar);
ui->pdfProcessBar->hide(); ui->pdfProcessBar->hide();
QSettings settings; ui->comboScale->setCurrentText(settings.value("currentScale").toString());
ui->comboScale->setCurrentText(settings.value("currentScale").toString()); pdfPreviewsPerPage = settings.value("pdfPreviewsPerPage", 20).toInt();
ui->spinPdfPreviewPage->setMinimum(1);
} }
void MainWindow::connectSignals() void MainWindow::connectSignals()
{ {
connect(ui->txtSearch, &QLineEdit::returnPressed, this, &MainWindow::lineEditReturnPressed); connect(ui->txtSearch, &QLineEdit::returnPressed, this, &MainWindow::lineEditReturnPressed);
connect(&searchWatcher, &QFutureWatcher<SearchResult>::finished, this, [&]{ connect(&searchWatcher, &QFutureWatcher<SearchResult>::finished, this, [&]{
try try
{ {
auto results = searchWatcher.future().result(); auto results = searchWatcher.future().result();
handleSearchResults(results); handleSearchResults(results);
} }
catch(QSSGeneralException &e) catch(QSSGeneralException &e)
{ {
handleSearchError(e.message); handleSearchError(e.message);
} }
}); });
connect(&pdfWorkerWatcher, &QFutureWatcher<PdfPreview>::resultReadyAt, this, [&](int index) { connect(&pdfWorkerWatcher, &QFutureWatcher<PdfPreview>::resultReadyAt, this, [&](int index) {
pdfPreviewReceived(pdfWorkerWatcher.resultAt(index)); pdfPreviewReceived(pdfWorkerWatcher.resultAt(index));
}); });
connect(&pdfWorkerWatcher, &QFutureWatcher<PdfPreview>::progressValueChanged, ui->pdfProcessBar, &QProgressBar::setValue); connect(&pdfWorkerWatcher, &QFutureWatcher<PdfPreview>::progressValueChanged, ui->pdfProcessBar, &QProgressBar::setValue);
connect(ui->treeResultsList, &QTreeWidget::itemActivated, this, &MainWindow::treeSearchItemActivated); connect(ui->treeResultsList, &QTreeWidget::itemActivated, this, &MainWindow::treeSearchItemActivated);
connect(ui->treeResultsList, &QTreeWidget::customContextMenuRequested, this, &MainWindow::showSearchResultsContextMenu); connect(ui->treeResultsList, &QTreeWidget::customContextMenuRequested, this, &MainWindow::showSearchResultsContextMenu);
connect(ui->tabWidget, &QTabWidget::currentChanged, this, &MainWindow::tabChanged); connect(ui->tabWidget, &QTabWidget::currentChanged, this, &MainWindow::tabChanged);
connect(ui->comboScale, qOverload<const QString &>(&QComboBox::currentIndexChanged), this, &MainWindow::comboScaleChanged); connect(ui->comboScale, qOverload<const QString &>(&QComboBox::currentIndexChanged), this, &MainWindow::comboScaleChanged);
connect(ui->spinPdfPreviewPage, qOverload<int>(&QSpinBox::valueChanged), this, &MainWindow::spinPdfPreviewPageValueChanged);
}
void MainWindow::spinPdfPreviewPageValueChanged(int val)
{
makePdfPreview(val);
} }
void MainWindow::comboScaleChanged(QString text) void MainWindow::comboScaleChanged(QString text)
{ {
QSettings scaleSetting; QSettings scaleSetting;
scaleSetting.setValue("currentScale", ui->comboScale->currentText()); scaleSetting.setValue("currentScale", ui->comboScale->currentText());
makePdfPreview(); makePdfPreview(ui->spinPdfPreviewPage->value());
} }
bool MainWindow::pdfTabActive() bool MainWindow::pdfTabActive()
{ {
return ui->tabWidget->currentIndex() == 1; return ui->tabWidget->currentIndex() == 1;
} }
void MainWindow::keyPressEvent(QKeyEvent *event) void MainWindow::keyPressEvent(QKeyEvent *event)
{ {
bool quit = ((event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Q) || event->key() == Qt::Key_Escape); bool quit = ((event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Q) || event->key() == Qt::Key_Escape);
if(quit) if(quit)
{ {
qApp->quit(); qApp->quit();
} }
if(event->modifiers() & Qt::ControlModifier) if(event->modifiers() & Qt::ControlModifier)
{ {
if(event->key() == Qt::Key_L) if(event->key() == Qt::Key_L)
{ {
ui->txtSearch->setFocus(); ui->txtSearch->setFocus();
ui->txtSearch->selectAll(); ui->txtSearch->selectAll();
} }
} }
QWidget::keyPressEvent(event); QWidget::keyPressEvent(event);
} }
void MainWindow::tabChanged() void MainWindow::tabChanged()
{ {
if(pdfTabActive()) if(pdfTabActive())
{ {
if(pdfDirty) if(pdfDirty)
{ {
makePdfPreview(); makePdfPreview(ui->spinPdfPreviewPage->value());
} }
ui->pdfProcessBar->show(); ui->pdfProcessBar->show();
} }
else else
{ {
ui->pdfProcessBar->hide(); ui->pdfProcessBar->hide();
} }
} }
void MainWindow::pdfPreviewReceived(PdfPreview preview) void MainWindow::pdfPreviewReceived(PdfPreview preview)
{ {
if(preview.hasPreviewImage()) if(preview.hasPreviewImage())
{ {
ClickLabel *label = new ClickLabel(); ClickLabel *label = new ClickLabel();
label->setPixmap(QPixmap::fromImage(preview.previewImage)); label->setPixmap(QPixmap::fromImage(preview.previewImage));
label->setToolTip(preview.documentPath); label->setToolTip(preview.documentPath);
ui->scrollAreaWidgetContents->layout()->addWidget(label); ui->scrollAreaWidgetContents->layout()->addWidget(label);
connect(label, &ClickLabel::leftClick, [=]() { connect(label, &ClickLabel::leftClick, [=]() {
QSettings settings; QSettings settings;
QString command = settings.value("pdfviewer").toString(); QString command = settings.value("pdfviewer").toString();
if(command != "" && command.contains("%p") && command.contains("%f")) if(command != "" && command.contains("%p") && command.contains("%f"))
{ {
QStringList splitted = command.split(" "); QStringList splitted = command.split(" ");
if(splitted.size() > 1) if(splitted.size() > 1)
{ {
QString cmd = splitted[0]; QString cmd = splitted[0];
QStringList args = splitted.mid(1); QStringList args = splitted.mid(1);
args.replaceInStrings("%f", preview.documentPath); args.replaceInStrings("%f", preview.documentPath);
args.replaceInStrings("%p", QString::number(preview.page)); args.replaceInStrings("%p", QString::number(preview.page));
QProcess::startDetached(cmd, args); QProcess::startDetached(cmd, args);
} }
} }
else else
{ {
QDesktopServices::openUrl(QUrl::fromLocalFile(preview.documentPath)); QDesktopServices::openUrl(QUrl::fromLocalFile(preview.documentPath));
} }
}); });
} }
} }
void MainWindow::lineEditReturnPressed() void MainWindow::lineEditReturnPressed()
{ {
QString q = ui->txtSearch->text(); QString q = ui->txtSearch->text();
if(!QSSQuery::checkParanthesis(q)) if(!QSSQuery::checkParanthesis(q))
{ {
ui->lblSearchResults->setText("Invalid paranthesis"); ui->lblSearchResults->setText("Invalid paranthesis");
return; return;
} }
//TODO: validate q; //TODO: validate q;
ui->lblSearchResults->setText("Searching..."); ui->lblSearchResults->setText("Searching...");
searchWatcher.cancel(); searchWatcher.cancel();
searchWatcher.waitForFinished(); searchWatcher.waitForFinished();
QFuture<QVector<SearchResult>> searchFuture = QtConcurrent::run([&, q]() { QFuture<QVector<SearchResult>> searchFuture = QtConcurrent::run([&, q]() {
SqliteSearch searcher(db); SqliteSearch searcher(db);
this->currentQuery = QSSQuery::build(q); this->currentQuery = QSSQuery::build(q);
return searcher.search(this->currentQuery); return searcher.search(this->currentQuery);
}); });
searchWatcher.setFuture(searchFuture); searchWatcher.setFuture(searchFuture);
} }
void MainWindow::handleSearchResults(const QVector<SearchResult> &results) void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
{ {
this->pdfSearchResults.clear(); this->pdfSearchResults.clear();
ui->treeResultsList->clear(); ui->treeResultsList->clear();
ui->lblSearchResults->setText("Results: " + QString::number(results.size())); ui->lblSearchResults->setText("Results: " + QString::number(results.size()));
for(const SearchResult &result : results) for(const SearchResult &result : results)
{ {
QFileInfo pathInfo(result.fileData.absPath); QFileInfo pathInfo(result.fileData.absPath);
QString fileName =pathInfo.fileName(); QString fileName =pathInfo.fileName();
QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeResultsList); QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeResultsList);
QDateTime dt = QDateTime::fromSecsSinceEpoch(result.fileData.mtime); QDateTime dt = QDateTime::fromSecsSinceEpoch(result.fileData.mtime);
item->setIcon(0, iconProvider.icon(pathInfo)); item->setIcon(0, iconProvider.icon(pathInfo));
item->setText(0, fileName); item->setText(0, fileName);
item->setText(1, result.fileData.absPath); item->setText(1, result.fileData.absPath);
item->setText(2, dt.toString(Qt::ISODate)); item->setText(2, dt.toString(Qt::ISODate));
item->setText(3, this->locale().formattedDataSize(result.fileData.size)); item->setText(3, this->locale().formattedDataSize(result.fileData.size));
if(result.fileData.absPath.endsWith(".pdf")) if(result.fileData.absPath.endsWith(".pdf"))
{ {
this->pdfSearchResults.append(result); this->pdfSearchResults.append(result);
} }
} }
ui->treeResultsList->resizeColumnToContents(0); ui->treeResultsList->resizeColumnToContents(0);
ui->treeResultsList->resizeColumnToContents(1); ui->treeResultsList->resizeColumnToContents(1);
pdfDirty = ! this->pdfSearchResults.empty(); pdfDirty = ! this->pdfSearchResults.empty();
if(pdfTabActive() && pdfDirty)
{ int numpages = ceil(static_cast<double>(this->pdfSearchResults.size()) / pdfPreviewsPerPage);
makePdfPreview(); ui->spinPdfPreviewPage->setMinimum(1);
} ui->spinPdfPreviewPage->setMaximum(numpages);
ui->spinPdfPreviewPage->setValue(1);
if(pdfTabActive() && pdfDirty)
{
makePdfPreview(1);
}
} }
void MainWindow::makePdfPreview() void MainWindow::makePdfPreview(int page)
{ {
this->pdfWorkerWatcher.cancel(); this->pdfWorkerWatcher.cancel();
this->pdfWorkerWatcher.waitForFinished(); this->pdfWorkerWatcher.waitForFinished();
QCoreApplication::processEvents(); //Maybe not necessary anymore, depends on whether it's possible that a slot is still to be fired. QCoreApplication::processEvents(); //Maybe not necessary anymore, depends on whether it's possible that a slot is still to be fired.
qDeleteAll(ui->scrollAreaWidgetContents->children()); qDeleteAll(ui->scrollAreaWidgetContents->children());
ui->scrollAreaWidgetContents->setLayout(new QHBoxLayout()); ui->scrollAreaWidgetContents->setLayout(new QHBoxLayout());
ui->pdfProcessBar->setMaximum(this->pdfSearchResults.size()); ui->pdfProcessBar->setMaximum(this->pdfSearchResults.size());
processedPdfPreviews = 0; processedPdfPreviews = 0;
QString scaleText = ui->comboScale->currentText(); QString scaleText = ui->comboScale->currentText();
scaleText.chop(1); scaleText.chop(1);
QVector<QString> wordsToHighlight; QVector<QString> wordsToHighlight;
QRegularExpression extractor(R"#("([^"]*)"|(\w+))#"); QRegularExpression extractor(R"#("([^"]*)"|(\w+))#");
for(const Token &token : this->currentQuery.getTokens()) for(const Token &token : this->currentQuery.getTokens())
{ {
if(token.type == FILTER_CONTENT_CONTAINS) if(token.type == FILTER_CONTENT_CONTAINS)
{ {
QRegularExpressionMatchIterator i = extractor.globalMatch(token.value); QRegularExpressionMatchIterator i = extractor.globalMatch(token.value);
while(i.hasNext()) while(i.hasNext())
{ {
QRegularExpressionMatch m = i.next(); QRegularExpressionMatch m = i.next();
QString value = m.captured(1); QString value = m.captured(1);
if(value.isEmpty()) if(value.isEmpty())
{ {
value = m.captured(2); value = m.captured(2);
} }
wordsToHighlight.append(value); wordsToHighlight.append(value);
} }
} }
} }
PdfWorker worker; PdfWorker worker;
this->pdfWorkerWatcher.setFuture(worker.generatePreviews(this->pdfSearchResults, wordsToHighlight, scaleText.toInt() / 100.)); int end = pdfPreviewsPerPage;
ui->pdfProcessBar->setMaximum(this->pdfWorkerWatcher.progressMaximum()); int begin = page * pdfPreviewsPerPage - pdfPreviewsPerPage;
ui->pdfProcessBar->setMinimum(this->pdfWorkerWatcher.progressMinimum()); this->pdfWorkerWatcher.setFuture(worker.generatePreviews(this->pdfSearchResults.mid(begin, end), wordsToHighlight, scaleText.toInt() / 100.));
ui->pdfProcessBar->setMaximum(this->pdfWorkerWatcher.progressMaximum());
ui->pdfProcessBar->setMinimum(this->pdfWorkerWatcher.progressMinimum());
} }
void MainWindow::handleSearchError(QString error) void MainWindow::handleSearchError(QString error)
{ {
ui->lblSearchResults->setText("Error:" + error); ui->lblSearchResults->setText("Error:" + error);
} }
void MainWindow::treeSearchItemActivated(QTreeWidgetItem *item, int i) void MainWindow::treeSearchItemActivated(QTreeWidgetItem *item, int i)
{ {
QDesktopServices::openUrl(QUrl::fromLocalFile(item->text(1))); QDesktopServices::openUrl(QUrl::fromLocalFile(item->text(1)));
} }
void MainWindow::showSearchResultsContextMenu(const QPoint &point) void MainWindow::showSearchResultsContextMenu(const QPoint &point)
{ {
QTreeWidgetItem *item = ui->treeResultsList->itemAt(point); QTreeWidgetItem *item = ui->treeResultsList->itemAt(point);
if(item == nullptr) if(item == nullptr)
{ {
return; return;
} }
QMenu menu("SearchResult", this); QMenu menu("SearchResult", this);
menu.addAction("Copy filename to clipboard", [&] { QGuiApplication::clipboard()->setText(item->text(0));}); menu.addAction("Copy filename to clipboard", [&] { QGuiApplication::clipboard()->setText(item->text(0));});
menu.addAction("Copy full path to clipboard", [&] { QGuiApplication::clipboard()->setText(item->text(1)); }); menu.addAction("Copy full path to clipboard", [&] { QGuiApplication::clipboard()->setText(item->text(1)); });
menu.addAction("Open containing folder", [&] { menu.addAction("Open containing folder", [&] {
QFileInfo pathinfo(item->text(1)); QFileInfo pathinfo(item->text(1));
QString dir = pathinfo.absolutePath(); QString dir = pathinfo.absolutePath();
QDesktopServices::openUrl(QUrl::fromLocalFile(dir)); QDesktopServices::openUrl(QUrl::fromLocalFile(dir));
}); });
menu.exec(QCursor::pos()); menu.exec(QCursor::pos());
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
delete ui; delete ui;
} }

View File

@ -34,13 +34,14 @@ private:
void add(QString path, unsigned int page); void add(QString path, unsigned int page);
QVector<SearchResult> pdfSearchResults; QVector<SearchResult> pdfSearchResults;
void connectSignals(); void connectSignals();
void makePdfPreview(); void makePdfPreview(int page);
bool pdfTabActive(); bool pdfTabActive();
void keyPressEvent(QKeyEvent *event) override; void keyPressEvent(QKeyEvent *event) override;
unsigned int processedPdfPreviews; unsigned int processedPdfPreviews;
void handleSearchResults(const QVector<SearchResult> &results); void handleSearchResults(const QVector<SearchResult> &results);
void handleSearchError(QString error); void handleSearchError(QString error);
QSSQuery currentQuery; QSSQuery currentQuery;
int pdfPreviewsPerPage;
private slots: private slots:
void lineEditReturnPressed(); void lineEditReturnPressed();
void treeSearchItemActivated(QTreeWidgetItem *item, int i); void treeSearchItemActivated(QTreeWidgetItem *item, int i);
@ -48,7 +49,7 @@ private slots:
void tabChanged(); void tabChanged();
void pdfPreviewReceived(PdfPreview preview); void pdfPreviewReceived(PdfPreview preview);
void comboScaleChanged(QString text); void comboScaleChanged(QString text);
void spinPdfPreviewPageValueChanged(int val);
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View File

@ -148,6 +148,26 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QLabel" name="lblPdfPreviewPage">
<property name="text">
<string>Page:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinPdfPreviewPage">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::PlusMinus</enum>
</property>
<property name="accelerated">
<bool>false</bool>
</property>
<property name="showGroupSeparator" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>