Compare commits

..

No commits in common. "31f0568a876530fe42943f4685d64db717721a87" and "10d61acbd07e837cbc25600ddbad5c0e7a0dc2f8" have entirely different histories.

8 changed files with 62 additions and 220 deletions

View File

@ -1,50 +1,16 @@
#include <QtConcurrent> #include <QtConcurrent>
#include "ipcpreviewworker.h" #include "ipcpreviewworker.h"
#include "previewgeneratormapfunctor.h" #include "previewgeneratormapfunctor.h"
IPCPreviewWorker::IPCPreviewWorker(QLocalSocket *peer) IPCPreviewWorker::IPCPreviewWorker()
{ {
this->peer = peer;
this->connect(&previewWorkerWatcher, &QFutureWatcher<QByteArray>::resultReadyAt, this, this->connect(&previewWorkerWatcher, &QFutureWatcher<QByteArray>::resultReadyAt, this,
[this](int index) [this](int index) { emit previewGenerated(previewWorkerWatcher.resultAt(index)); });
{ connect(&previewWorkerWatcher, &QFutureWatcher<QByteArray>::finished, this, [this] { emit finished(); });
if(this->peer != nullptr)
{
QDataStream stream{this->peer};
stream << previewWorkerWatcher.resultAt(index);
this->peer->flush();
}
});
connect(&previewWorkerWatcher, &QFutureWatcher<QByteArray>::finished, this, &IPCPreviewWorker::shutdownSocket);
connect(this->peer, &QLocalSocket::disconnected, this, &IPCPreviewWorker::shutdownSocket);
} }
void IPCPreviewWorker::shutdownSocket() void IPCPreviewWorker::start(RenderConfig config, const QVector<RenderTarget> &targets, QLocalSocket *peer)
{
if(cleaned)
{
return;
}
cleaned = true;
if(this->peer != nullptr)
{
if(this->peer->state() == QLocalSocket::ConnectedState)
{
this->peer->flush();
this->peer->waitForBytesWritten();
this->peer->disconnectFromServer();
if(this->peer->state() != QLocalSocket::UnconnectedState)
{
this->peer->waitForDisconnected();
}
}
delete this->peer;
this->peer = nullptr;
}
emit finished();
}
void IPCPreviewWorker::start(RenderConfig config, const QVector<RenderTarget> &targets)
{ {
stop();
auto mapFunctor = PreviewGeneratorMapFunctor(); auto mapFunctor = PreviewGeneratorMapFunctor();
mapFunctor.setRenderConfig(config); mapFunctor.setRenderConfig(config);

View File

@ -11,21 +11,13 @@ class IPCPreviewWorker : public QObject
Q_OBJECT Q_OBJECT
private: private:
QFutureWatcher<QByteArray> previewWorkerWatcher; QFutureWatcher<QByteArray> previewWorkerWatcher;
QLocalSocket *peer;
bool cleaned = false;
public: public:
IPCPreviewWorker(QLocalSocket *peer); IPCPreviewWorker();
void start(RenderConfig config, const QVector<RenderTarget> &targets); void start(RenderConfig config, const QVector<RenderTarget> &targets, QLocalSocket *peer);
void stop(); void stop();
~IPCPreviewWorker()
{
delete this->peer;
}
private slots:
void shutdownSocket();
signals: signals:
void previewGenerated(QByteArray);
void finished(); void finished();
}; };

View File

@ -18,6 +18,8 @@ IpcServer::IpcServer()
/* Only 1, we are doing work for the GUI, not a service for general availability */ /* Only 1, we are doing work for the GUI, not a service for general availability */
this->spawningServer.setMaxPendingConnections(1); this->spawningServer.setMaxPendingConnections(1);
connect(&this->spawningServer, &QLocalServer::newConnection, this, &IpcServer::spawnerNewConnection); connect(&this->spawningServer, &QLocalServer::newConnection, this, &IpcServer::spawnerNewConnection);
connect(&this->previewWorker, &IPCPreviewWorker::previewGenerated, this, &IpcServer::handlePreviewGenerated);
connect(&this->previewWorker, &IPCPreviewWorker::finished, this, [this] { this->currentSocket->flush(); });
} }
bool IpcServer::startSpawner(QString socketPath) bool IpcServer::startSpawner(QString socketPath)
@ -29,6 +31,8 @@ bool IpcServer::startSpawner(QString socketPath)
void IpcServer::spawnerNewConnection() void IpcServer::spawnerNewConnection()
{ {
QLocalSocket *socket = this->spawningServer.nextPendingConnection(); QLocalSocket *socket = this->spawningServer.nextPendingConnection();
connect(socket, &QLocalSocket::disconnected, socket, &QLocalSocket::deleteLater);
this->currentSocket = socket;
if(socket != nullptr) if(socket != nullptr)
{ {
if(!socket->waitForReadyRead()) if(!socket->waitForReadyRead())
@ -49,22 +53,21 @@ void IpcServer::spawnerNewConnection()
stream.startTransaction(); stream.startTransaction();
stream >> renderConfig >> targets; stream >> renderConfig >> targets;
} while(!stream.commitTransaction() && socket->state() == QLocalSocket::ConnectedState); } while(!stream.commitTransaction() && socket->state() == QLocalSocket::ConnectedState);
if(socket->state() == QLocalSocket::ConnectedState)
{ stream << targets.count();
stream << targets.count(); socket->flush();
socket->flush(); previewWorker.start(renderConfig, targets, socket);
IPCPreviewWorker *previewWorker = new IPCPreviewWorker(socket);
connect(previewWorker, &IPCPreviewWorker::finished, this, [previewWorker] { delete previewWorker; });
previewWorker->start(renderConfig, targets);
}
else
{
delete socket;
}
} }
if(command == StopGeneratePreviews) if(command == StopGeneratePreviews)
{ {
/* TODO: implement */ previewWorker.stop();
} }
} }
} }
void IpcServer::handlePreviewGenerated(QByteArray ba)
{
QDataStream stream{this->currentSocket};
stream << ba;
this->currentSocket->flush();
}

View File

@ -10,10 +10,13 @@ class IpcServer : public QObject
{ {
Q_OBJECT Q_OBJECT
private: private:
IPCPreviewWorker previewWorker;
QLocalServer spawningServer; QLocalServer spawningServer;
QLocalSocket *currentSocket = nullptr;
SaveFileResult addFile(QString file); SaveFileResult addFile(QString file);
private slots: private slots:
void spawnerNewConnection(); void spawnerNewConnection();
void handlePreviewGenerated(QByteArray ba);
public: public:
IpcServer(); IpcServer();

View File

@ -15,7 +15,6 @@
#include <QFileDialog> #include <QFileDialog>
#include <QScreen> #include <QScreen>
#include <QProgressDialog> #include <QProgressDialog>
#include <QDesktopWidget>
#include "mainwindow.h" #include "mainwindow.h"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include "clicklabel.h" #include "clicklabel.h"
@ -648,7 +647,6 @@ void MainWindow::previewReceived(QSharedPointer<PreviewResult> preview, unsigned
headerLabel->setText(QString("Path: ") + preview->getDocumentPath()); headerLabel->setText(QString("Path: ") + preview->getDocumentPath());
ClickLabel *label = dynamic_cast<ClickLabel *>(preview->createPreviewWidget()); ClickLabel *label = dynamic_cast<ClickLabel *>(preview->createPreviewWidget());
label->setMaximumWidth(QApplication::desktop()->availableGeometry().width() - 200);
QVBoxLayout *previewLayout = new QVBoxLayout(); QVBoxLayout *previewLayout = new QVBoxLayout();
@ -680,7 +678,6 @@ void MainWindow::previewReceived(QSharedPointer<PreviewResult> preview, unsigned
previewLayout->setMargin(0); previewLayout->setMargin(0);
previewLayout->insertStretch(0, 1); previewLayout->insertStretch(0, 1);
previewLayout->insertStretch(-1, 1); previewLayout->insertStretch(-1, 1);
previewLayout->setAlignment(Qt::AlignCenter);
QWidget *previewWidget = new QWidget(); QWidget *previewWidget = new QWidget();
previewWidget->setLayout(previewLayout); previewWidget->setLayout(previewLayout);
@ -809,7 +806,6 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
ui->comboPreviewFiles->clear(); ui->comboPreviewFiles->clear();
ui->comboPreviewFiles->addItem("All previews"); ui->comboPreviewFiles->addItem("All previews");
ui->comboPreviewFiles->setVisible(true); ui->comboPreviewFiles->setVisible(true);
ui->lblTotalPreviewPagesCount->setText("");
bool hasDeleted = false; bool hasDeleted = false;
QHash<QString, bool> seenMap; QHash<QString, bool> seenMap;
@ -820,6 +816,7 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
if(!seenMap.contains(absPath)) if(!seenMap.contains(absPath))
{ {
seenMap[absPath] = true;
QString fileName = pathInfo.fileName(); QString fileName = pathInfo.fileName();
QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeResultsList); QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeResultsList);
@ -833,18 +830,17 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
bool exists = pathInfo.exists(); bool exists = pathInfo.exists();
if(exists) if(exists)
{ {
if(result.wasContentSearch) if(!result.wasContentSearch)
{ {
if(!pathInfo.suffix().contains("htm")) // hack until we can preview them properly... continue;
}
if(!pathInfo.suffix().contains("htm")) // hack until we can preview them properly...
{
if(PreviewGenerator::get(pathInfo) != nullptr)
{ {
if(PreviewGenerator::get(pathInfo) != nullptr) this->previewableSearchResults.append(result);
{ ui->comboPreviewFiles->addItem(result.fileData.absPath);
this->previewableSearchResults.append(result);
if(!seenMap.contains(result.fileData.absPath))
{
ui->comboPreviewFiles->addItem(result.fileData.absPath);
}
}
} }
} }
} }
@ -852,7 +848,6 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
{ {
hasDeleted = true; hasDeleted = true;
} }
seenMap[absPath] = true;
} }
ui->treeResultsList->resizeColumnToContents(0); ui->treeResultsList->resizeColumnToContents(0);
@ -868,7 +863,6 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
} }
QString statusText = "Results: " + QString::number(results.size()) + " files"; QString statusText = "Results: " + QString::number(results.size()) + " files";
statusText += ", previewable: " + QString::number(this->previewableSearchResults.count());
if(hasDeleted) if(hasDeleted)
{ {
statusText += " WARNING: Some files are inaccessible. No preview available for those. Index may be out of sync"; statusText += " WARNING: Some files are inaccessible. No preview available for those. Index may be out of sync";

View File

@ -1,6 +1,5 @@
#include <QMutexLocker> #include <QMutexLocker>
#include <QPainter> #include <QPainter>
#include <QRegularExpression>
#include "previewgeneratorpdf.h" #include "previewgeneratorpdf.h"
static QMutex cacheMutex; static QMutex cacheMutex;
@ -18,7 +17,6 @@ Poppler::Document *PreviewGeneratorPdf::document(QString path)
return nullptr; return nullptr;
} }
result->setRenderHint(Poppler::Document::TextAntialiasing); result->setRenderHint(Poppler::Document::TextAntialiasing);
QMutexLocker locker(&cacheMutex); QMutexLocker locker(&cacheMutex);
documentcache.insert(path, result); documentcache.insert(path, result);
locker.unlock(); locker.unlock();
@ -47,12 +45,7 @@ QSharedPointer<PreviewResult> PreviewGeneratorPdf::generate(RenderConfig config,
QImage img = pdfPage->renderToImage(config.scaleX, config.scaleY); QImage img = pdfPage->renderToImage(config.scaleX, config.scaleY);
for(QString &word : config.wordsToHighlight) for(QString &word : config.wordsToHighlight)
{ {
QList<QRectF> rects = QList<QRectF> rects = pdfPage->search(word, Poppler::Page::SearchFlag::IgnoreCase);
pdfPage->search(word, Poppler::Page::SearchFlag::IgnoreCase | Poppler::Page::SearchFlag::WholeWords);
if(rects.empty())
{
rects = pdfPage->search(word, Poppler::Page::SearchFlag::IgnoreCase);
}
for(QRectF &rect : rects) for(QRectF &rect : rects)
{ {
QPainter painter(&img); QPainter painter(&img);

View File

@ -1,5 +1,4 @@
#include <QTextStream> #include <QTextStream>
#include <QRegularExpression>
#include "previewgeneratorplaintext.h" #include "previewgeneratorplaintext.h"
#include "previewresultplaintext.h" #include "previewresultplaintext.h"
@ -58,7 +57,6 @@ QString PreviewGeneratorPlainText::generatePreviewText(QString content, RenderCo
++i; ++i;
} }
resulText = resulText.toHtmlEscaped();
QString header = "<b>" + fileName + "</b> "; QString header = "<b>" + fileName + "</b> ";
for(QString &word : config.wordsToHighlight) for(QString &word : config.wordsToHighlight)
{ {
@ -76,19 +74,10 @@ QString PreviewGeneratorPlainText::generatePreviewText(QString content, RenderCo
return header + resulText.replace("\n", "<br>").mid(0, 1000); return header + resulText.replace("\n", "<br>").mid(0, 1000);
} }
struct Snippet
{
/* Contains each line number and line of the snippet*/
QString snippetText;
/* How many times a word occurs in the snippetText */
QHash<QString, int> wordCountMap;
};
QString PreviewGeneratorPlainText::generateLineBasedPreviewText(QTextStream &in, RenderConfig config, QString fileName) QString PreviewGeneratorPlainText::generateLineBasedPreviewText(QTextStream &in, RenderConfig config, QString fileName)
{ {
QVector<Snippet> snippets; QString resultText;
const int contextLinesCount = 2; const unsigned int contextLinesCount = 2;
LimitQueue<QString> queue(contextLinesCount); LimitQueue<QString> queue(contextLinesCount);
QString currentLine; QString currentLine;
currentLine.reserve(512); currentLine.reserve(512);
@ -96,73 +85,38 @@ QString PreviewGeneratorPlainText::generateLineBasedPreviewText(QTextStream &in,
/* How many lines to read after a line with a match (like grep -A ) */ /* How many lines to read after a line with a match (like grep -A ) */
int justReadLinesCount = -1; int justReadLinesCount = -1;
struct Snippet currentSnippet; auto appendLine = [&resultText](int lineNumber, QString &line)
{ resultText.append(QString("<b>%1</b>%2<br>").arg(lineNumber).arg(line)); };
auto appendLine = [&currentSnippet, &config](int lineNumber, QString &line) QHash<QString, int> countmap;
{ QString header = "<b>" + fileName + "</b> ";
int foundWordsCount = 0;
for(QString &word : config.wordsToHighlight)
{
QRegularExpression searchRegex("\\b" + word + "\\b");
bool containsRegex = line.contains(searchRegex);
bool contains = false;
if(!containsRegex)
{
contains = line.contains(word, Qt::CaseInsensitive);
}
if(containsRegex || contains)
{
currentSnippet.wordCountMap[word] = currentSnippet.wordCountMap.value(word, 0) + 1;
QString replacementString = "<span style=\"background-color: yellow;\">" + word + "</span>";
if(containsRegex)
{
line.replace(searchRegex, replacementString);
}
else
{
line.replace(word, replacementString, Qt::CaseInsensitive);
}
++foundWordsCount;
}
}
currentSnippet.snippetText.append(QString("<b>%1</b>%2<br>").arg(lineNumber).arg(line));
return foundWordsCount;
};
unsigned int snippetsCount = 0;
unsigned int lineCount = 0; unsigned int lineCount = 0;
while(in.readLineInto(&currentLine)) while(in.readLineInto(&currentLine) && snippetsCount < MAX_SNIPPETS)
{ {
currentLine = currentLine.toHtmlEscaped();
++lineCount; ++lineCount;
bool matched = false; bool matched = false;
if(justReadLinesCount > 0) if(justReadLinesCount > 0)
{ {
appendLine(lineCount, currentLine);
int result = appendLine(lineCount, currentLine); --justReadLinesCount;
if(justReadLinesCount == 1 && result > 0)
{
justReadLinesCount = contextLinesCount;
}
else
{
--justReadLinesCount;
}
continue; continue;
} }
if(justReadLinesCount == 0) if(justReadLinesCount == 0)
{ {
currentSnippet.snippetText += "---<br>"; resultText += "---<br>";
justReadLinesCount = -1; justReadLinesCount = -1;
snippets.append(currentSnippet); ++snippetsCount;
currentSnippet = {};
} }
for(QString &word : config.wordsToHighlight) for(QString &word : config.wordsToHighlight)
{ {
if(currentLine.contains(word, Qt::CaseInsensitive)) if(currentLine.contains(word, Qt::CaseInsensitive))
{ {
countmap[word] = countmap.value(word, 0) + 1;
matched = true; matched = true;
break; currentLine.replace(word, "<span style=\"background-color: yellow;\">" + word + "</span>",
Qt::CaseInsensitive);
} }
} }
if(matched) if(matched)
@ -171,6 +125,7 @@ QString PreviewGeneratorPlainText::generateLineBasedPreviewText(QTextStream &in,
{ {
int queuedLineCount = lineCount - queue.size(); int queuedLineCount = lineCount - queue.size();
QString queuedLine = queue.dequeue(); QString queuedLine = queue.dequeue();
appendLine(queuedLineCount, queuedLine); appendLine(queuedLineCount, queuedLine);
} }
appendLine(lineCount, currentLine); appendLine(lineCount, currentLine);
@ -182,77 +137,13 @@ QString PreviewGeneratorPlainText::generateLineBasedPreviewText(QTextStream &in,
} }
} }
if(!currentSnippet.snippetText.isEmpty())
{
currentSnippet.snippetText += "---<br>";
snippets.append(currentSnippet);
}
std::sort(snippets.begin(), snippets.end(),
[](Snippet &a, Snippet &b)
{
int differentWordsA = 0;
int totalWordsA = 0;
int differentWordsB = 0;
int totalWordsB = 0;
for(int count : a.wordCountMap.values())
{
if(count > 0)
{
++differentWordsA;
}
totalWordsA += count;
}
for(int count : b.wordCountMap.values())
{
if(count > 0)
{
++differentWordsB;
}
totalWordsB += count;
}
if(differentWordsA > differentWordsB)
{
return true;
}
if(differentWordsA == differentWordsB)
{
return totalWordsA > totalWordsB;
}
return false;
});
QString resultText = "";
unsigned int snippetsCount = 0;
QString header = "<b>" + fileName + "</b> ";
QHash<QString, int> totalWordCountMap;
bool isTruncated = false;
for(Snippet &snippet : snippets)
{
if(snippetsCount++ < MAX_SNIPPETS)
{
resultText += snippet.snippetText;
}
else
{
isTruncated = true;
}
for(auto it = snippet.wordCountMap.keyValueBegin(); it != snippet.wordCountMap.keyValueEnd(); it++)
{
totalWordCountMap[it->first] = totalWordCountMap.value(it->first, 0) + it->second;
}
}
if(isTruncated)
{
header += "(truncated) ";
}
for(QString &word : config.wordsToHighlight) for(QString &word : config.wordsToHighlight)
{ {
header += word + ": " + QString::number(totalWordCountMap[word]) + " "; header += word + ": " + QString::number(countmap[word]) + " ";
}
if(snippetsCount == MAX_SNIPPETS)
{
header += "(truncated)";
} }
header += "<hr>"; header += "<hr>";

View File

@ -6,11 +6,11 @@ template <class T> class LimitQueue
{ {
protected: protected:
QQueue<T> queue; QQueue<T> queue;
int limit = 0; unsigned int limit = 0;
public: public:
LimitQueue(); LimitQueue();
LimitQueue(int limit) LimitQueue(unsigned int limit)
{ {
this->limit = limit; this->limit = limit;
} }
@ -34,7 +34,7 @@ template <class T> class LimitQueue
return queue.dequeue(); return queue.dequeue();
} }
void setLimit(int limit) void setLimit(unsigned int limit)
{ {
this->limit = limit; this->limit = limit;
} }