Comparar commits

...

22 Commits

Autor SHA1 Mensagem Data
80a4551f8b update README 2022-05-29 11:12:43 +02:00
fa10cb606b mainwindow: Disable page switcher while generation is running
This prevents 'spam'. User may have scrolled 10 pages forward, while
we are still generating old pages. Then the user wonders why
they arrive so late.

So disable switching pages while the generation is still running

It is unlikely that a user will have to quickly go through search
results like that.
2022-05-29 10:51:48 +02:00
b90ff840d9 gui: init previewProcessBar with 0 on start 2022-05-29 10:44:19 +02:00
86cc16d15d gui: IPCPreviewWorker(): Don't allocate mapfunctor on heap 2022-05-29 10:44:19 +02:00
69c2956a1f gui: Add label showing total number of preview pages 2022-05-29 10:44:19 +02:00
82a4205c23 gui: mainwindow: Fix preview page number calculation
The paging now works on the actual pages to be rendered.
2022-05-29 10:44:19 +02:00
8d96f6e4ce ipc: Place socket in /tmp/.looqs/, remove ipc path settings 2022-05-29 10:44:19 +02:00
d39157b58d gui: main: Enable exile.h for IPC preview generation 2022-05-29 10:44:19 +02:00
a43ab169b5 gui: Begin simple IPC error reporting 2022-05-29 10:44:19 +02:00
ee19692a7a gui: Open files/previews directly without IPC again
Since the main GUI process is not sandboxed again
2022-05-29 10:44:19 +02:00
773325f2de gui: ipc: Support cancellation of preview generation 2022-05-29 10:44:19 +02:00
065dcf8906 gui: main: Kill IPCServer process on exit 2022-05-29 10:44:19 +02:00
13f28c37c6 gui: mainwindow: Use new IPCPreviewClient 2022-05-29 10:44:19 +02:00
8f2e77b152 gui: Introduce IPCPreviewClient 2022-05-29 10:44:19 +02:00
3bdcb76d8e gui: PreviewResult: Add serialization() methods for IPC 2022-05-27 09:29:28 +02:00
ee18142e36 gui: PreviewGenerator*: Wrap PreviewResult in QSharedPointer 2022-05-27 09:28:21 +02:00
3e03fed1a2 gui: IpcServer: Use IPCPreviewWorker 2022-05-27 09:26:37 +02:00
6439adffc6 gui: Begin IPCPreviewWorker 2022-05-27 09:26:03 +02:00
02642a147a gui: Retire IPCClient and PreviewWorker 2022-05-27 09:24:42 +02:00
fe29641d0a IpcServer: Remove docOpen(), fileOpen(). MainWindow will do it
As it is no longer subject to sandboxing as a whole, it is not
restricted and thus, should call these functions itself
2022-05-17 19:23:03 +02:00
830226ae59 RenderConfig: Add serialization, basically for IPC 2022-05-17 19:20:06 +02:00
6a5cb69e27 gui: Add RenderTarget struct, an IPC helper class 2022-05-17 19:19:02 +02:00
35 arquivos alterados com 603 adições e 275 exclusões

Ver arquivo

@ -4,6 +4,8 @@ search terms have been found, as shown in the screenshots below.
## Screenshots ## Screenshots
The screenshots in this section may occasionally be slightly outdated, but they are usually recent enough to get an overall impression of the current state.
### List ### List
![Screenshot looqs results](https://garage.quitesimple.org/assets/looqs/opearting_systems_looqs.png) ![Screenshot looqs results](https://garage.quitesimple.org/assets/looqs/opearting_systems_looqs.png)

Ver arquivo

@ -23,7 +23,8 @@ DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \ SOURCES += \
ipcclient.cpp \ ipcpreviewclient.cpp \
ipcpreviewworker.cpp \
ipcserver.cpp \ ipcserver.cpp \
main.cpp \ main.cpp \
mainwindow.cpp \ mainwindow.cpp \
@ -35,11 +36,13 @@ SOURCES += \
previewresult.cpp \ previewresult.cpp \
previewresultpdf.cpp \ previewresultpdf.cpp \
previewresultplaintext.cpp \ previewresultplaintext.cpp \
previewworker.cpp renderconfig.cpp \
rendertarget.cpp
HEADERS += \ HEADERS += \
ipc.h \ ipc.h \
ipcclient.h \ ipcpreviewclient.h \
ipcpreviewworker.h \
ipcserver.h \ ipcserver.h \
mainwindow.h \ mainwindow.h \
clicklabel.h \ clicklabel.h \
@ -50,8 +53,8 @@ HEADERS += \
previewresult.h \ previewresult.h \
previewresultpdf.h \ previewresultpdf.h \
previewresultplaintext.h \ previewresultplaintext.h \
previewworker.h \ renderconfig.h \
renderconfig.h rendertarget.h
FORMS += \ FORMS += \
mainwindow.ui mainwindow.ui

Ver arquivo

@ -3,8 +3,13 @@
enum IPCCommand enum IPCCommand
{ {
DocOpen, GeneratePreviews = 23,
FileOpen, StopGeneratePreviews,
AddFile,
}; };
enum IPCReply
{
FinishedGeneratePreviews,
};
#endif // IPC_H #endif // IPC_H

Ver arquivo

@ -1,27 +0,0 @@
#include <QDataStream>
#include "ipcclient.h"
IPCClient::IPCClient(QString socketPath)
{
this->socketPath = socketPath;
}
bool IPCClient::sendCommand(IPCCommand command, QStringList args)
{
bool result = false;
QLocalSocket socket;
socket.connectToServer(socketPath);
if(socket.isOpen() && socket.isWritable())
{
QDataStream stream(&socket);
stream << command;
stream << args;
socket.flush();
result = true;
}
else
{
qDebug() << "Not connected to IPC server";
}
return result;
}

Ver arquivo

@ -1,18 +0,0 @@
#ifndef IPCCLIENT_H
#define IPCCLIENT_H
#include <QLocalSocket>
#include <QString>
#include <QStringList>
#include "ipc.h"
class IPCClient
{
private:
QString socketPath;
public:
IPCClient(QString socketPath);
bool sendCommand(IPCCommand command, QStringList args);
};
#endif // IPCCLIENT_H

129
gui/ipcpreviewclient.cpp Arquivo normal
Ver arquivo

@ -0,0 +1,129 @@
#include <QLocalSocket>
#include <QApplication>
#include "ipc.h"
#include "ipcpreviewclient.h"
#include "previewresultpdf.h"
#include "previewresultplaintext.h"
bool IPCPreviewClient::connect()
{
if(socket->state() == QLocalSocket::ConnectedState)
{
socket->disconnectFromServer();
if(socket->state() == QLocalSocket::ConnectedState)
{
socket->waitForDisconnected(100);
}
}
socket->connectToServer(socketPath);
socket->waitForConnected(100);
return socket->state() == QLocalSocket::ConnectedState;
}
QSharedPointer<PreviewResult> IPCPreviewClient::deserialize(QByteArray &array)
{
QDataStream stream{&array, QIODevice::ReadOnly};
PreviewResultType type;
stream >> type;
if(type == PreviewResultType::PDF)
{
return PreviewResultPdf::deserialize(array);
}
if(type == PreviewResultType::PlainText)
{
return PreviewResultPlainText::deserialize(array);
}
return QSharedPointer<PreviewResult>(nullptr);
}
IPCPreviewClient::IPCPreviewClient()
{
this->socket = new QLocalSocket(this);
}
void IPCPreviewClient::setSocketPath(QString socketPath)
{
this->socketPath = socketPath;
}
void IPCPreviewClient::startGeneration(RenderConfig config, const QVector<RenderTarget> &targets)
{
this->start(config, targets);
}
void IPCPreviewClient::start(RenderConfig config, const QVector<RenderTarget> &targets)
{
if(targets.count() == 0)
{
return;
}
if(!connect() || !socket->isOpen())
{
emit error("Could not connect to IPC worker");
return;
}
if(socket->isOpen() && socket->isWritable())
{
QDataStream stream(socket);
stream << GeneratePreviews;
stream << config;
stream << targets;
socket->flush();
int numTarget = 0;
if(socket->isOpen() && socket->isReadable() && socket->state() == QLocalSocket::ConnectedState)
{
do
{
socket->waitForReadyRead(100);
stream.startTransaction();
stream >> numTarget;
} while(!stream.commitTransaction() && socket->state() == QLocalSocket::ConnectedState);
if(numTarget != targets.count())
{
throw std::runtime_error("Server reports less targets than it should");
}
}
else
{
emit error("Error while trying to process previews: " + socket->errorString());
return;
}
int processed = 0;
++this->currentPreviewGeneration;
while(socket->isOpen() && socket->isReadable() && processed < targets.count())
{
QByteArray array;
do
{
socket->waitForReadyRead(100);
stream.startTransaction();
stream >> array;
} while(!stream.commitTransaction() && socket->state() == QLocalSocket::ConnectedState);
emit previewReceived(deserialize(array), this->currentPreviewGeneration);
++processed;
}
if(processed != targets.count())
{
emit error("IPC worker didn't send enough previews. This is a bug, please report");
}
}
socket->disconnectFromServer();
emit finished();
}
void IPCPreviewClient::stopGeneration()
{
if(!connect() || !socket->isOpen())
{
emit error("Could not connect to IPC worker");
return;
}
QDataStream stream(socket);
stream << StopGeneratePreviews;
socket->flush();
}

37
gui/ipcpreviewclient.h Arquivo normal
Ver arquivo

@ -0,0 +1,37 @@
#ifndef IPCPREVIEWCLIENT_H
#define IPCPREVIEWCLIENT_H
#include <QObject>
#include <QLocalSocket>
#include "previewresult.h"
#include "renderconfig.h"
#include "rendertarget.h"
class IPCPreviewClient : public QObject
{
Q_OBJECT
private:
unsigned int currentPreviewGeneration = 1;
QLocalSocket *socket;
QString socketPath;
bool connect();
QSharedPointer<PreviewResult> deserialize(QByteArray &array);
public:
IPCPreviewClient();
~IPCPreviewClient()
{
delete socket;
}
void setSocketPath(QString socketPath);
public slots:
void start(RenderConfig config, const QVector<RenderTarget> &targets);
void startGeneration(RenderConfig config, const QVector<RenderTarget> &targets);
void stopGeneration();
signals:
void previewReceived(QSharedPointer<PreviewResult> previewResult, unsigned int currentPreviewGeneration);
void finished();
void error(QString);
};
#endif // IPCPREVIEWCLIENT_H

24
gui/ipcpreviewworker.cpp Arquivo normal
Ver arquivo

@ -0,0 +1,24 @@
#include <QtConcurrent>
#include "ipcpreviewworker.h"
#include "previewgeneratormapfunctor.h"
IPCPreviewWorker::IPCPreviewWorker()
{
this->connect(&previewWorkerWatcher, &QFutureWatcher<QByteArray>::resultReadyAt, this,
[this](int index) { emit previewGenerated(previewWorkerWatcher.resultAt(index)); });
connect(&previewWorkerWatcher, &QFutureWatcher<QByteArray>::finished, this, [this] { emit finished(); });
}
void IPCPreviewWorker::start(RenderConfig config, const QVector<RenderTarget> &targets, QLocalSocket *peer)
{
stop();
auto mapFunctor = PreviewGeneratorMapFunctor();
mapFunctor.setRenderConfig(config);
previewWorkerWatcher.setFuture(QtConcurrent::mapped(targets, mapFunctor));
}
void IPCPreviewWorker::stop()
{
previewWorkerWatcher.cancel();
previewWorkerWatcher.waitForFinished();
}

24
gui/ipcpreviewworker.h Arquivo normal
Ver arquivo

@ -0,0 +1,24 @@
#ifndef IPCPREVIEWWORKER_H
#define IPCPREVIEWWORKER_H
#include <QLocalSocket>
#include <QFutureWatcher>
#include "renderconfig.h"
#include "rendertarget.h"
#include "previewgenerator.h"
class IPCPreviewWorker : public QObject
{
Q_OBJECT
private:
QFutureWatcher<QByteArray> previewWorkerWatcher;
public:
IPCPreviewWorker();
void start(RenderConfig config, const QVector<RenderTarget> &targets, QLocalSocket *peer);
void stop();
signals:
void previewGenerated(QByteArray);
void finished();
};
#endif // IPCPREVIEWWORKER_H

Ver arquivo

@ -9,13 +9,17 @@
#include "common.h" #include "common.h"
#include "databasefactory.h" #include "databasefactory.h"
#include "../shared/logger.h" #include "../shared/logger.h"
#include "renderconfig.h"
#include "rendertarget.h"
#include "ipcpreviewworker.h"
IpcServer::IpcServer() IpcServer::IpcServer()
{ {
this->dbFactory = QSharedPointer<DatabaseFactory>(new DatabaseFactory(Common::databasePath())); /* Only 1, we are doing work for the GUI, not a service for general availability */
this->dbService = QSharedPointer<SqliteDbService>(new SqliteDbService(*this->dbFactory.get())); this->spawningServer.setMaxPendingConnections(1);
this->fileSaver = QSharedPointer<FileSaver>(new FileSaver(*this->dbService.get()));
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)
@ -24,85 +28,46 @@ bool IpcServer::startSpawner(QString socketPath)
return this->spawningServer.listen(socketPath); return this->spawningServer.listen(socketPath);
} }
bool IpcServer::docOpen(QString path, int pagenum)
{
QSettings settings;
QString command = settings.value("pdfviewer").toString();
if(path.endsWith(".pdf") && command != "" && command.contains("%p") && command.contains("%f"))
{
QStringList splitted = command.split(" ");
if(splitted.size() > 1)
{
QString cmd = splitted[0];
QStringList args = splitted.mid(1);
args.replaceInStrings("%f", path);
args.replaceInStrings("%p", QString::number(pagenum));
QProcess::startDetached(cmd, args);
}
}
else
{
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
return true;
}
bool IpcServer::fileOpen(QString path)
{
return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
SaveFileResult IpcServer::addFile(QString file)
{
try
{
return this->fileSaver->addFile(file);
}
catch(std::exception &e)
{
Logger::error() << e.what() << Qt::endl;
return PROCESSFAIL;
}
}
void IpcServer::spawnerNewConnection() void IpcServer::spawnerNewConnection()
{ {
QScopedPointer<QLocalSocket> socket{this->spawningServer.nextPendingConnection()}; QLocalSocket *socket = this->spawningServer.nextPendingConnection();
if(!socket.isNull()) connect(socket, &QLocalSocket::disconnected, socket, &QLocalSocket::deleteLater);
this->currentSocket = socket;
if(socket != nullptr)
{ {
if(!socket->waitForReadyRead()) if(!socket->waitForReadyRead())
{ {
return; return;
} }
QDataStream stream(socket.get()); QDataStream stream(socket);
IPCCommand command; IPCCommand command;
QStringList args;
stream >> command; stream >> command;
stream >> args; if(command == GeneratePreviews)
if(args.size() < 1)
{ {
stream << "invalid"; RenderConfig renderConfig;
return; QVector<RenderTarget> targets;
} do
if(command == DocOpen)
{
if(args.size() < 2)
{ {
stream << "invalid"; /* TODO: this is not entirely robust */
return; socket->waitForReadyRead(100);
} stream.startTransaction();
docOpen(args[0], args[1].toInt()); stream >> renderConfig >> targets;
} while(!stream.commitTransaction() && socket->state() == QLocalSocket::ConnectedState);
stream << targets.count();
socket->flush();
previewWorker.start(renderConfig, targets, socket);
} }
if(command == FileOpen) if(command == StopGeneratePreviews)
{ {
if(args.size() < 1) previewWorker.stop();
{
stream << "invalid";
return;
}
fileOpen(args[0]);
} }
} }
} }
void IpcServer::handlePreviewGenerated(QByteArray ba)
{
QDataStream stream{this->currentSocket};
stream << ba;
this->currentSocket->flush();
}

Ver arquivo

@ -4,19 +4,19 @@
#include <QLocalServer> #include <QLocalServer>
#include "ipc.h" #include "ipc.h"
#include "filesaver.h" #include "filesaver.h"
#include "ipcpreviewworker.h"
class IpcServer : public QObject class IpcServer : public QObject
{ {
Q_OBJECT Q_OBJECT
private: private:
QSharedPointer<DatabaseFactory> dbFactory; IPCPreviewWorker previewWorker;
QSharedPointer<SqliteDbService> dbService;
QSharedPointer<FileSaver> fileSaver;
QLocalServer spawningServer; QLocalServer spawningServer;
bool docOpen(QString path, int pagenum); QLocalSocket *currentSocket = nullptr;
bool fileOpen(QString path);
SaveFileResult addFile(QString file); SaveFileResult addFile(QString file);
private slots: private slots:
void spawnerNewConnection(); void spawnerNewConnection();
void handlePreviewGenerated(QByteArray ba);
public: public:
IpcServer(); IpcServer();

Ver arquivo

@ -5,6 +5,7 @@
#include <QProcess> #include <QProcess>
#include <QDir> #include <QDir>
#include <QCommandLineParser> #include <QCommandLineParser>
#include <QFileInfo>
#include "mainwindow.h" #include "mainwindow.h"
#include "searchresult.h" #include "searchresult.h"
@ -32,15 +33,46 @@ void enableSandbox()
} }
exile_free_policy(policy); exile_free_policy(policy);
} }
void enableIpcSandbox()
{
struct exile_policy *policy = exile_create_policy();
if(policy == NULL)
{
qCritical() << "Failed to init policy for sandbox";
exit(EXIT_FAILURE);
}
policy->namespace_options = EXILE_UNSHARE_NETWORK | EXILE_UNSHARE_USER;
policy->no_new_privs = 1;
policy->drop_caps = 1;
policy->vow_promises = exile_vows_from_str("thread cpath wpath rpath unix stdio prot_exec proc shm fsnotify ioctl");
QString ipcSocketPath = Common::ipcSocketPath();
QFileInfo info{ipcSocketPath};
QString ipcSocketPathDir = info.absolutePath();
std::string stdIpcSocketPath = ipcSocketPathDir.toStdString();
exile_append_path_policies(policy, EXILE_FS_ALLOW_ALL_READ, "/");
exile_append_path_policies(policy, EXILE_FS_ALLOW_ALL_READ | EXILE_FS_ALLOW_ALL_WRITE, stdIpcSocketPath.c_str());
int ret = exile_enable_policy(policy);
if(ret != 0)
{
qDebug() << "Failed to establish sandbox";
exit(EXIT_FAILURE);
}
exile_free_policy(policy);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QString socketPath = "/tmp/looqs-spawner"; QString socketPath = Common::ipcSocketPath();
if(argc > 1) if(argc > 1)
{ {
QString arg = argv[1]; QString arg = argv[1];
if(arg == "ipc") if(arg == "ipc")
{ {
Common::setupAppInfo(); Common::setupAppInfo();
enableIpcSandbox();
QApplication a(argc, argv); QApplication a(argc, argv);
IpcServer *ipcserver = new IpcServer(); IpcServer *ipcserver = new IpcServer();
@ -70,10 +102,24 @@ int main(int argc, char *argv[])
return processor.process(); return processor.process();
} }
} }
QString ipcSocketPath = Common::ipcSocketPath();
QFileInfo info{ipcSocketPath};
QString ipcSocketPathDir = info.absolutePath();
QDir dir;
if(!dir.mkpath(ipcSocketPathDir))
{
qCritical() << "Failed to create dir for ipc socket" << Qt::endl;
exit(EXIT_FAILURE);
}
QProcess process; QProcess process;
QStringList args; QStringList args;
args << "ipc"; args << "ipc";
if(!process.startDetached("/proc/self/exe", args)) process.setProcessChannelMode(QProcess::ForwardedChannels);
process.start("/proc/self/exe", args);
if(!process.waitForStarted(5000))
{ {
QString errorMsg = "Failed to start IPC server"; QString errorMsg = "Failed to start IPC server";
qDebug() << errorMsg; qDebug() << errorMsg;
@ -108,17 +154,18 @@ int main(int argc, char *argv[])
QMessageBox::critical(nullptr, "Error", e.message); QMessageBox::critical(nullptr, "Error", e.message);
return 1; return 1;
} }
// Keep this post sandbox, afterwards does not work (suspect due to threads, but unconfirmed)
QApplication a(argc, argv); QApplication a(argc, argv);
a.setWindowIcon(QIcon(":/icon.svg")); a.setWindowIcon(QIcon(":/icon.svg"));
QObject::connect(&a, &QApplication::aboutToQuit, &process, &QProcess::kill);
qRegisterMetaType<QVector<SearchResult>>("QVector<SearchResult>"); qRegisterMetaType<QVector<SearchResult>>("QVector<SearchResult>");
qRegisterMetaType<QVector<PreviewResultPdf>>("QVector<PreviewResultPdf>"); qRegisterMetaType<QVector<PreviewResultPdf>>("QVector<PreviewResultPdf>");
qRegisterMetaType<PreviewResultPdf>("PreviewResultPdf"); qRegisterMetaType<PreviewResultPdf>("PreviewResultPdf");
qRegisterMetaType<FileScanResult>("FileScanResult"); qRegisterMetaType<FileScanResult>("FileScanResult");
qRegisterMetaType<RenderConfig>("RenderConfig");
IPCClient client{socketPath}; qRegisterMetaType<QVector<RenderTarget>>("QVector<RenderTarget>");
MainWindow w{0, client}; qRegisterMetaType<QSharedPointer<PreviewResult>>("QSharedPointer<PreviewResult>");
MainWindow w{0, socketPath};
w.showMaximized(); w.showMaximized();
return a.exec(); return a.exec();
} }

Ver arquivo

@ -13,18 +13,43 @@
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
#include <QMessageBox> #include <QMessageBox>
#include <QFileDialog> #include <QFileDialog>
#include <QScreen>
#include "mainwindow.h" #include "mainwindow.h"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include "clicklabel.h" #include "clicklabel.h"
#include "../shared/sqlitesearch.h" #include "../shared/sqlitesearch.h"
#include "../shared/looqsgeneralexception.h" #include "../shared/looqsgeneralexception.h"
#include "../shared/common.h" #include "../shared/common.h"
#include "ipcpreviewclient.h"
#include "previewgenerator.h"
MainWindow::MainWindow(QWidget *parent, IPCClient &client) : QMainWindow(parent), ui(new Ui::MainWindow) MainWindow::MainWindow(QWidget *parent, QString socketPath) : QMainWindow(parent), ui(new Ui::MainWindow)
{ {
ui->setupUi(this); ui->setupUi(this);
setWindowTitle(QCoreApplication::applicationName()); setWindowTitle(QCoreApplication::applicationName());
this->ipcClient = &client; this->ipcPreviewClient.moveToThread(&this->ipcClientThread);
this->ipcPreviewClient.setSocketPath(socketPath);
connect(&ipcPreviewClient, &IPCPreviewClient::previewReceived, this, &MainWindow::previewReceived,
Qt::QueuedConnection);
connect(&ipcPreviewClient, &IPCPreviewClient::finished, this,
[&]
{
this->ui->previewProcessBar->setValue(this->ui->previewProcessBar->maximum());
this->ui->spinPreviewPage->setEnabled(true);
});
connect(&ipcPreviewClient, &IPCPreviewClient::error, this,
[this](QString msg)
{
qCritical() << msg << Qt::endl;
QMessageBox::critical(this, "IPC error", msg);
});
connect(this, &MainWindow::startIpcPreviews, &ipcPreviewClient, &IPCPreviewClient::startGeneration,
Qt::QueuedConnection);
connect(this, &MainWindow::stopIpcPreviews, &ipcPreviewClient, &IPCPreviewClient::stopGeneration,
Qt::QueuedConnection);
this->ipcClientThread.start();
QSettings settings; QSettings settings;
this->dbFactory = new DatabaseFactory(Common::databasePath()); this->dbFactory = new DatabaseFactory(Common::databasePath());
@ -46,6 +71,9 @@ MainWindow::MainWindow(QWidget *parent, IPCClient &client) : QMainWindow(parent)
QStringList indexPaths = settings.value("indexPaths").toStringList(); QStringList indexPaths = settings.value("indexPaths").toStringList();
ui->lstPaths->addItems(indexPaths); ui->lstPaths->addItems(indexPaths);
ui->spinPreviewPage->setValue(1);
ui->spinPreviewPage->setMinimum(1);
} }
void MainWindow::addPathToIndex() void MainWindow::addPathToIndex()
@ -82,16 +110,18 @@ void MainWindow::connectSignals()
handleSearchError(e.message); handleSearchError(e.message);
} }
}); });
connect(&previewWorkerWatcher, &QFutureWatcher<QSharedPointer<PreviewResult>>::resultReadyAt, this,
[&](int index) { previewReceived(previewWorkerWatcher.resultAt(index)); });
connect(&previewWorkerWatcher, &QFutureWatcher<QSharedPointer<PreviewResult>>::progressValueChanged,
ui->previewProcessBar, &QProgressBar::setValue);
connect(&previewWorkerWatcher, &QFutureWatcher<QSharedPointer<PreviewResult>>::started, this,
[&] { ui->indexerTab->setEnabled(false); });
connect(&previewWorkerWatcher, &QFutureWatcher<QSharedPointer<PreviewResult>>::finished, this, /* connect(&previewWorkerWatcher, &QFutureWatcher<QByteArray>::resultReadyAt, this,
[&](int index) {
previewReceived(previewWorkerWatcher.resultAt(index)); });
connect(&previewWorkerWatcher, &QFutureWatcher<QSharedPointer<PreviewResult>>::progressValueChanged,
ui->previewProcessBar, &QProgressBar::setValue);
connect(&previewWorkerWatcher, &QFutureWatcher<QSharedPointer<PreviewResult>>::started, this,
[&] { ui->indexerTab->setEnabled(false); });*/
/*connect(&previewWorkerWatcher, &QFutureWatcher<QSharedPointer<PreviewResult>>::finished, this,
[&] { ui->indexerTab->setEnabled(true); }); [&] { ui->indexerTab->setEnabled(true); });
*/
connect(ui->treeResultsList, &QTreeWidget::itemActivated, this, &MainWindow::treeSearchItemActivated); connect(ui->treeResultsList, &QTreeWidget::itemActivated, this, &MainWindow::treeSearchItemActivated);
connect(ui->treeResultsList, &QTreeWidget::customContextMenuRequested, this, connect(ui->treeResultsList, &QTreeWidget::customContextMenuRequested, this,
&MainWindow::showSearchResultsContextMenu); &MainWindow::showSearchResultsContextMenu);
@ -261,16 +291,21 @@ void MainWindow::tabChanged()
} }
} }
void MainWindow::previewReceived(QSharedPointer<PreviewResult> preview) void MainWindow::previewReceived(QSharedPointer<PreviewResult> preview, unsigned int previewGeneration)
{ {
if(preview->hasPreview()) if(previewGeneration < this->currentPreviewGeneration)
{
return;
}
this->ui->previewProcessBar->setValue(this->ui->previewProcessBar->value() + 1);
if(!preview.isNull() && preview->hasPreview())
{ {
QString docPath = preview->getDocumentPath(); QString docPath = preview->getDocumentPath();
auto previewPage = preview->getPage(); auto previewPage = preview->getPage();
ClickLabel *label = dynamic_cast<ClickLabel *>(preview->createPreviewWidget()); ClickLabel *label = dynamic_cast<ClickLabel *>(preview->createPreviewWidget());
ui->scrollAreaWidgetContents->layout()->addWidget(label); ui->scrollAreaWidgetContents->layout()->addWidget(label);
connect(label, &ClickLabel::leftClick, [this, docPath, previewPage]() { ipcDocOpen(docPath, previewPage); }); connect(label, &ClickLabel::leftClick, [this, docPath, previewPage]() { openDocument(docPath, previewPage); });
connect(label, &ClickLabel::rightClick, connect(label, &ClickLabel::rightClick,
[this, docPath, previewPage]() [this, docPath, previewPage]()
{ {
@ -357,10 +392,8 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
ui->treeResultsList->resizeColumnToContents(1); ui->treeResultsList->resizeColumnToContents(1);
previewDirty = !this->previewableSearchResults.empty(); previewDirty = !this->previewableSearchResults.empty();
int numpages = ceil(static_cast<double>(this->previewableSearchResults.size()) / previewsPerPage);
ui->spinPreviewPage->setMinimum(1);
ui->spinPreviewPage->setMaximum(numpages);
ui->spinPreviewPage->setValue(1); ui->spinPreviewPage->setValue(1);
if(previewTabActive() && previewDirty) if(previewTabActive() && previewDirty)
{ {
makePreviews(1); makePreviews(1);
@ -376,12 +409,10 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
void MainWindow::makePreviews(int page) void MainWindow::makePreviews(int page)
{ {
if(this->previewableSearchResults.empty())
this->previewWorkerWatcher.cancel(); {
this->previewWorkerWatcher.waitForFinished(); return;
}
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());
@ -409,14 +440,43 @@ void MainWindow::makePreviews(int page)
} }
} }
} }
PreviewWorker worker;
int end = previewsPerPage; int end = previewsPerPage;
int begin = page * previewsPerPage - previewsPerPage; int begin = page * previewsPerPage - previewsPerPage;
this->previewWorkerWatcher.setFuture(worker.generatePreviews(this->previewableSearchResults.mid(begin, end), if(begin < 0)
wordsToHighlight, scaleText.toInt() / 100.)); {
ui->previewProcessBar->setMaximum(this->previewWorkerWatcher.progressMaximum()); // Should not happen actually
ui->previewProcessBar->setMinimum(this->previewWorkerWatcher.progressMinimum()); begin = 0;
}
RenderConfig renderConfig;
renderConfig.scaleX = QGuiApplication::primaryScreen()->physicalDotsPerInchX() * (scaleText.toInt() / 100.);
renderConfig.scaleY = QGuiApplication::primaryScreen()->physicalDotsPerInchY() * (scaleText.toInt() / 100.);
renderConfig.wordsToHighlight = wordsToHighlight;
QVector<RenderTarget> targets;
for(SearchResult &sr : this->previewableSearchResults)
{
RenderTarget renderTarget;
renderTarget.path = sr.fileData.absPath;
for(unsigned int pagenum : sr.pages)
{
renderTarget.page = (int)pagenum;
targets.append(renderTarget);
}
}
int numpages = ceil(static_cast<double>(targets.size()) / previewsPerPage);
ui->spinPreviewPage->setMaximum(numpages);
targets = targets.mid(begin, end);
ui->lblTotalPreviewPagesCount->setText(QString::number(numpages));
ui->previewProcessBar->setMaximum(targets.count());
ui->previewProcessBar->setMinimum(0);
ui->previewProcessBar->setValue(0);
ui->previewProcessBar->setVisible(this->previewableSearchResults.size() > 0); ui->previewProcessBar->setVisible(this->previewableSearchResults.size() > 0);
++this->currentPreviewGeneration;
this->ui->spinPreviewPage->setEnabled(false);
emit startIpcPreviews(renderConfig, targets);
} }
void MainWindow::handleSearchError(QString error) void MainWindow::handleSearchError(QString error)
@ -430,27 +490,39 @@ void MainWindow::createSearchResutlMenu(QMenu &menu, const QFileInfo &fileInfo)
[&fileInfo] { QGuiApplication::clipboard()->setText(fileInfo.fileName()); }); [&fileInfo] { QGuiApplication::clipboard()->setText(fileInfo.fileName()); });
menu.addAction("Copy full path to clipboard", menu.addAction("Copy full path to clipboard",
[&fileInfo] { QGuiApplication::clipboard()->setText(fileInfo.absoluteFilePath()); }); [&fileInfo] { QGuiApplication::clipboard()->setText(fileInfo.absoluteFilePath()); });
menu.addAction("Open containing folder", [this, &fileInfo] { this->ipcFileOpen(fileInfo.absolutePath()); }); menu.addAction("Open containing folder", [this, &fileInfo] { this->openFile(fileInfo.absolutePath()); });
} }
void MainWindow::ipcDocOpen(QString path, int num) void MainWindow::openDocument(QString path, int num)
{ {
QStringList args; QSettings settings;
args << path; QString command = settings.value("pdfviewer").toString();
args << QString::number(num); if(path.endsWith(".pdf") && command != "" && command.contains("%p") && command.contains("%f"))
this->ipcClient->sendCommand(DocOpen, args); {
QStringList splitted = command.split(" ");
if(splitted.size() > 1)
{
QString cmd = splitted[0];
QStringList args = splitted.mid(1);
args.replaceInStrings("%f", path);
args.replaceInStrings("%p", QString::number(num));
QProcess::startDetached(cmd, args);
}
}
else
{
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
} }
void MainWindow::ipcFileOpen(QString path) void MainWindow::openFile(QString path)
{ {
QStringList args; QDesktopServices::openUrl(QUrl::fromLocalFile(path));
args << path;
this->ipcClient->sendCommand(FileOpen, args);
} }
void MainWindow::treeSearchItemActivated(QTreeWidgetItem *item, int i) void MainWindow::treeSearchItemActivated(QTreeWidgetItem *item, int i)
{ {
ipcFileOpen(item->text(1)); openFile(item->text(1));
} }
void MainWindow::showSearchResultsContextMenu(const QPoint &point) void MainWindow::showSearchResultsContextMenu(const QPoint &point)

Ver arquivo

@ -9,9 +9,8 @@
#include <QFutureWatcher> #include <QFutureWatcher>
#include <QSqlDatabase> #include <QSqlDatabase>
#include <QLocalSocket> #include <QLocalSocket>
#include "previewworker.h"
#include "../shared/looqsquery.h" #include "../shared/looqsquery.h"
#include "ipcclient.h" #include "ipcpreviewclient.h"
#include "indexer.h" #include "indexer.h"
namespace Ui namespace Ui
{ {
@ -23,7 +22,7 @@ class MainWindow : public QMainWindow
Q_OBJECT Q_OBJECT
public: public:
explicit MainWindow(QWidget *parent, IPCClient &client); explicit MainWindow(QWidget *parent, QString socketPath);
~MainWindow(); ~MainWindow();
signals: signals:
void beginSearch(const QString &query); void beginSearch(const QString &query);
@ -33,13 +32,14 @@ class MainWindow : public QMainWindow
DatabaseFactory *dbFactory; DatabaseFactory *dbFactory;
SqliteDbService *dbService; SqliteDbService *dbService;
Ui::MainWindow *ui; Ui::MainWindow *ui;
IPCClient *ipcClient; IPCPreviewClient ipcPreviewClient;
QThread ipcClientThread;
Indexer *indexer; Indexer *indexer;
QFileIconProvider iconProvider; QFileIconProvider iconProvider;
bool previewDirty; bool previewDirty;
QSqlDatabase db; QSqlDatabase db;
QFutureWatcher<QVector<SearchResult>> searchWatcher; QFutureWatcher<QVector<SearchResult>> searchWatcher;
QFutureWatcher<QSharedPointer<PreviewResult>> previewWorkerWatcher;
void add(QString path, unsigned int page); void add(QString path, unsigned int page);
QVector<SearchResult> previewableSearchResults; QVector<SearchResult> previewableSearchResults;
void connectSignals(); void connectSignals();
@ -53,20 +53,24 @@ class MainWindow : public QMainWindow
LooqsQuery contentSearchQuery; LooqsQuery contentSearchQuery;
int previewsPerPage; int previewsPerPage;
void createSearchResutlMenu(QMenu &menu, const QFileInfo &fileInfo); void createSearchResutlMenu(QMenu &menu, const QFileInfo &fileInfo);
void ipcDocOpen(QString path, int num); void openDocument(QString path, int num);
void ipcFileOpen(QString path); void openFile(QString path);
unsigned int currentPreviewGeneration = 1;
private slots: private slots:
void lineEditReturnPressed(); void lineEditReturnPressed();
void treeSearchItemActivated(QTreeWidgetItem *item, int i); void treeSearchItemActivated(QTreeWidgetItem *item, int i);
void showSearchResultsContextMenu(const QPoint &point); void showSearchResultsContextMenu(const QPoint &point);
void tabChanged(); void tabChanged();
void previewReceived(QSharedPointer<PreviewResult> preview); void previewReceived(QSharedPointer<PreviewResult> preview, unsigned int previewGeneration);
void comboScaleChanged(int i); void comboScaleChanged(int i);
void spinPreviewPageValueChanged(int val); void spinPreviewPageValueChanged(int val);
void startIndexing(); void startIndexing();
void finishIndexing(); void finishIndexing();
void addPathToIndex(); void addPathToIndex();
signals:
void startIpcPreviews(RenderConfig config, const QVector<RenderTarget> &targets);
void stopIpcPreviews();
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

Ver arquivo

@ -27,7 +27,7 @@
<enum>QTabWidget::South</enum> <enum>QTabWidget::South</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>2</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="resultsTab"> <widget class="QWidget" name="resultsTab">
<attribute name="title"> <attribute name="title">
@ -155,6 +155,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="lblTotalPreviewPagesCount">
<property name="text">
<string/>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
@ -349,7 +356,7 @@
<item> <item>
<widget class="QProgressBar" name="previewProcessBar"> <widget class="QProgressBar" name="previewProcessBar">
<property name="value"> <property name="value">
<number>24</number> <number>0</number>
</property> </property>
</widget> </widget>
</item> </item>

Ver arquivo

@ -9,7 +9,7 @@
class PreviewGenerator class PreviewGenerator
{ {
public: public:
virtual PreviewResult *generate(RenderConfig config, QString documentPath, unsigned int page) = 0; virtual QSharedPointer<PreviewResult> generate(RenderConfig config, QString documentPath, unsigned int page) = 0;
virtual ~PreviewGenerator() virtual ~PreviewGenerator()
{ {
} }

Ver arquivo

@ -10,16 +10,15 @@ void PreviewGeneratorMapFunctor::setRenderConfig(RenderConfig config)
this->renderConfig = config; this->renderConfig = config;
} }
QSharedPointer<PreviewResult> PreviewGeneratorMapFunctor::operator()(const QSharedPointer<PreviewResult> &renderResult) QByteArray PreviewGeneratorMapFunctor::operator()(const RenderTarget &renderTarget)
{ {
QFileInfo info{renderResult->getDocumentPath()}; QFileInfo info{renderTarget.path};
PreviewGenerator *previewGenerator = PreviewGenerator::get(info); PreviewGenerator *previewGenerator = PreviewGenerator::get(info);
if(previewGenerator == nullptr) if(previewGenerator == nullptr)
{ {
return QSharedPointer<PreviewResult>(); return QByteArray{};
} }
auto preview = auto preview = previewGenerator->generate(this->renderConfig, renderTarget.path, renderTarget.page);
previewGenerator->generate(this->renderConfig, renderResult->getDocumentPath(), renderResult->getPage());
return QSharedPointer<PreviewResult>(preview); return preview->serialize();
} }

Ver arquivo

@ -2,8 +2,9 @@
#define PREVIEWGENERATORMAPFUNCTOR_H #define PREVIEWGENERATORMAPFUNCTOR_H
#include "renderconfig.h" #include "renderconfig.h"
#include "previewgenerator.h" #include "rendertarget.h"
#include "previewgenerator.h"
class PreviewGeneratorMapFunctor class PreviewGeneratorMapFunctor
{ {
@ -16,13 +17,13 @@ class PreviewGeneratorMapFunctor
RenderConfig renderConfig; RenderConfig renderConfig;
public: public:
typedef QSharedPointer<PreviewResult> result_type; typedef QByteArray result_type;
PreviewGeneratorMapFunctor(); PreviewGeneratorMapFunctor();
void setRenderConfig(RenderConfig config); void setRenderConfig(RenderConfig config);
QSharedPointer<PreviewResult> operator()(const QSharedPointer<PreviewResult> &renderResult); QByteArray operator()(const RenderTarget &renderTarget);
}; };
#endif // PREVIEWGENERATORMAPFUNCTOR_H #endif // PREVIEWGENERATORMAPFUNCTOR_H

Ver arquivo

@ -1,6 +1,5 @@
#include <QMutexLocker> #include <QMutexLocker>
#include <QPainter> #include <QPainter>
#include "previewgeneratorpdf.h" #include "previewgeneratorpdf.h"
static QMutex cacheMutex; static QMutex cacheMutex;
@ -24,18 +23,18 @@ Poppler::Document *PreviewGeneratorPdf::document(QString path)
return result; return result;
} }
PreviewResult *PreviewGeneratorPdf::generate(RenderConfig config, QString documentPath, unsigned int page) QSharedPointer<PreviewResult> PreviewGeneratorPdf::generate(RenderConfig config, QString documentPath,
unsigned int page)
{ {
PreviewResultPdf *result = new PreviewResultPdf(documentPath, page); PreviewResultPdf *result = new PreviewResultPdf(documentPath, page);
Poppler::Document *doc = document(documentPath); Poppler::Document *doc = document(documentPath);
if(doc == nullptr) if(doc == nullptr)
{ {
return result; return QSharedPointer<PreviewResult>(result);
} }
if(doc->isLocked()) if(doc->isLocked())
{ {
return result; return QSharedPointer<PreviewResult>(result);
} }
int p = (int)page - 1; int p = (int)page - 1;
if(p < 0) if(p < 0)
@ -55,5 +54,5 @@ PreviewResult *PreviewGeneratorPdf::generate(RenderConfig config, QString docume
} }
} }
result->previewImage = img; result->previewImage = img;
return result; return QSharedPointer<PreviewResult>(result);
} }

Ver arquivo

@ -13,7 +13,7 @@ class PreviewGeneratorPdf : public PreviewGenerator
public: public:
using PreviewGenerator::PreviewGenerator; using PreviewGenerator::PreviewGenerator;
PreviewResult *generate(RenderConfig config, QString documentPath, unsigned int page); QSharedPointer<PreviewResult> generate(RenderConfig config, QString documentPath, unsigned int page);
~PreviewGeneratorPdf() ~PreviewGeneratorPdf()
{ {

Ver arquivo

@ -3,13 +3,14 @@
#include "previewgeneratorplaintext.h" #include "previewgeneratorplaintext.h"
#include "previewresultplaintext.h" #include "previewresultplaintext.h"
PreviewResult *PreviewGeneratorPlainText::generate(RenderConfig config, QString documentPath, unsigned int page) QSharedPointer<PreviewResult> PreviewGeneratorPlainText::generate(RenderConfig config, QString documentPath,
unsigned int page)
{ {
PreviewResultPlainText *result = new PreviewResultPlainText(documentPath, page); PreviewResultPlainText *result = new PreviewResultPlainText(documentPath, page);
QFile file(documentPath); QFile file(documentPath);
if(!file.open(QFile::ReadOnly | QFile::Text)) if(!file.open(QFile::ReadOnly | QFile::Text))
{ {
return result; return QSharedPointer<PreviewResultPlainText>(result);
} }
QTextStream in(&file); QTextStream in(&file);
@ -77,5 +78,5 @@ PreviewResult *PreviewGeneratorPlainText::generate(RenderConfig config, QString
header += "<hr>"; header += "<hr>";
result->setText(header + resulText.replace("\n", "<br>")); result->setText(header + resulText.replace("\n", "<br>"));
return result; return QSharedPointer<PreviewResultPlainText>(result);
} }

Ver arquivo

@ -6,7 +6,7 @@ class PreviewGeneratorPlainText : public PreviewGenerator
{ {
public: public:
using PreviewGenerator::PreviewGenerator; using PreviewGenerator::PreviewGenerator;
PreviewResult *generate(RenderConfig config, QString documentPath, unsigned int page); QSharedPointer<PreviewResult> generate(RenderConfig config, QString documentPath, unsigned int page);
}; };
#endif // PREVIEWGENERATORPLAINTEXT_H #endif // PREVIEWGENERATORPLAINTEXT_H

Ver arquivo

@ -1,5 +1,4 @@
#include "previewresult.h" #include "previewresult.h"
PreviewResult::PreviewResult() PreviewResult::PreviewResult()
{ {
} }
@ -33,3 +32,11 @@ unsigned int PreviewResult::getPage() const
{ {
return this->page; return this->page;
} }
QByteArray PreviewResult::serialize() const
{
QByteArray result;
QDataStream stream{&result, QIODevice::WriteOnly};
stream << 0 << this->documentPath << this->page;
return result;
}

Ver arquivo

@ -2,6 +2,12 @@
#define PREVIEWRESULT_H #define PREVIEWRESULT_H
#include "clicklabel.h" #include "clicklabel.h"
enum PreviewResultType
{
PDF = 1,
PlainText
};
class PreviewResult class PreviewResult
{ {
protected: protected:
@ -17,6 +23,7 @@ class PreviewResult
virtual bool hasPreview(); virtual bool hasPreview();
QString getDocumentPath() const; QString getDocumentPath() const;
unsigned int getPage() const; unsigned int getPage() const;
virtual QByteArray serialize() const;
}; };
#endif // PREVIEWRESULT_H #endif // PREVIEWRESULT_H

Ver arquivo

@ -1,5 +1,4 @@
#include "previewresultpdf.h" #include "previewresultpdf.h"
PreviewResultPdf::PreviewResultPdf(const PreviewResult &o) PreviewResultPdf::PreviewResultPdf(const PreviewResult &o)
{ {
this->documentPath = o.getDocumentPath(); this->documentPath = o.getDocumentPath();
@ -19,3 +18,27 @@ bool PreviewResultPdf::hasPreview()
bool result = !this->previewImage.isNull(); bool result = !this->previewImage.isNull();
return result; return result;
} }
QByteArray PreviewResultPdf::serialize() const
{
QByteArray result;
QDataStream stream{&result, QIODevice::WriteOnly};
PreviewResultType type = PreviewResultType::PDF;
stream << type << this->documentPath << this->page << this->previewImage;
return result;
}
QSharedPointer<PreviewResultPdf> PreviewResultPdf::deserialize(QByteArray &ba)
{
PreviewResultPdf *result = new PreviewResultPdf();
PreviewResultType type;
QDataStream stream{&ba, QIODevice::ReadOnly};
stream >> type;
if(type != PreviewResultType::PDF)
{
throw std::runtime_error("Invalid byte array: Not a pdf preview");
}
stream >> result->documentPath >> result->page >> result->previewImage;
return QSharedPointer<PreviewResultPdf>(result);
}

Ver arquivo

@ -12,6 +12,10 @@ class PreviewResultPdf : public PreviewResult
QWidget *createPreviewWidget() override; QWidget *createPreviewWidget() override;
bool hasPreview() override; bool hasPreview() override;
QByteArray serialize() const;
static QSharedPointer<PreviewResultPdf> deserialize(QByteArray &ba);
}; };
#endif // PREVIEWRESULTPDF_H #endif // PREVIEWRESULTPDF_H

Ver arquivo

@ -28,3 +28,27 @@ void PreviewResultPlainText::setText(QString text)
{ {
this->text = text; this->text = text;
} }
QByteArray PreviewResultPlainText::serialize() const
{
QByteArray result;
QDataStream stream{&result, QIODevice::WriteOnly};
PreviewResultType type = PreviewResultType::PlainText;
stream << type << this->documentPath << this->page << this->text;
return result;
}
QSharedPointer<PreviewResultPlainText> PreviewResultPlainText::deserialize(QByteArray &ba)
{
PreviewResultPlainText *result = new PreviewResultPlainText();
PreviewResultType type;
QDataStream stream{&ba, QIODevice::ReadOnly};
stream >> type;
if(type != PreviewResultType::PlainText)
{
throw std::runtime_error("Invalid byte array: Not a pdf preview");
}
stream >> result->documentPath >> result->page >> result->text;
return QSharedPointer<PreviewResultPlainText>(result);
}

Ver arquivo

@ -15,6 +15,9 @@ class PreviewResultPlainText : public PreviewResult
bool hasPreview() override; bool hasPreview() override;
void setText(QString text); void setText(QString text);
QByteArray serialize() const;
static QSharedPointer<PreviewResultPlainText> deserialize(QByteArray &ba);
}; };
#endif // PREVIEWRESULTPLAINTEXT_H #endif // PREVIEWRESULTPLAINTEXT_H

Ver arquivo

@ -1,39 +0,0 @@
#include <QApplication>
#include <QScreen>
#include <QScopedPointer>
#include <QMutexLocker>
#include <QtConcurrent/QtConcurrent>
#include <QtConcurrent/QtConcurrentMap>
#include <atomic>
#include "previewworker.h"
PreviewWorker::PreviewWorker()
{
}
QFuture<QSharedPointer<PreviewResult>> PreviewWorker::generatePreviews(const QVector<SearchResult> paths,
QVector<QString> wordsToHighlight,
double scalefactor)
{
QVector<QSharedPointer<PreviewResult>> previews;
for(const SearchResult &sr : paths)
{
for(unsigned int page : sr.pages)
{
QSharedPointer<PreviewResult> ptr =
QSharedPointer<PreviewResult>(new PreviewResult{sr.fileData.absPath, page});
previews.append(ptr);
}
}
RenderConfig renderConfig;
renderConfig.scaleX = QGuiApplication::primaryScreen()->physicalDotsPerInchX() * scalefactor;
renderConfig.scaleY = QGuiApplication::primaryScreen()->physicalDotsPerInchY() * scalefactor;
renderConfig.wordsToHighlight = wordsToHighlight;
auto mapFunctor = new PreviewGeneratorMapFunctor();
mapFunctor->setRenderConfig(renderConfig);
return QtConcurrent::mapped(previews, *mapFunctor);
}

Ver arquivo

@ -1,29 +0,0 @@
#ifndef PREVIEWWORKER_H
#define PREVIEWWORKER_H
#include <QObject>
#include <QImage>
#include <QHash>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QMutex>
#include <QFuture>
#include "previewresultpdf.h"
#include "searchresult.h"
#include "previewgenerator.h"
#include "previewworker.h"
#include "previewgeneratorpdf.h"
#include "previewgeneratormapfunctor.h"
class PreviewWorker : public QObject
{
Q_OBJECT
public:
PreviewWorker();
QSharedPointer<PreviewGenerator> createGenerator(QString path);
QFuture<QSharedPointer<PreviewResult>> generatePreviews(const QVector<SearchResult> paths,
QVector<QString> wordsToHighlight, double scalefactor);
};
#endif // PREVIEWWORKER_H

17
gui/renderconfig.cpp Arquivo normal
Ver arquivo

@ -0,0 +1,17 @@
#include "renderconfig.h"
QDataStream &operator<<(QDataStream &out, const RenderConfig &rc)
{
out << rc.scaleX;
out << rc.scaleY;
out << rc.wordsToHighlight;
return out;
}
QDataStream &operator>>(QDataStream &in, RenderConfig &rc)
{
in >> rc.scaleX;
in >> rc.scaleY;
in >> rc.wordsToHighlight;
return in;
}

Ver arquivo

@ -1,12 +1,17 @@
#ifndef RENDERCONFIG_H #ifndef RENDERCONFIG_H
#define RENDERCONFIG_H #define RENDERCONFIG_H
#include <QVector> #include <QVector>
#include <QDataStream>
struct RenderConfig struct RenderConfig
{ {
double scaleX = 50 / 100.; double scaleX = 50 / 100.;
double scaleY = scaleX; double scaleY = scaleX;
QVector<QString> wordsToHighlight; QVector<QString> wordsToHighlight;
friend QDataStream &operator<<(QDataStream &out, const RenderConfig &rc);
friend QDataStream &operator>>(QDataStream &in, RenderConfig &rc);
}; };
QDataStream &operator<<(QDataStream &out, const RenderConfig &rc);
QDataStream &operator>>(QDataStream &in, RenderConfig &rc);
#endif // RENDERCONFIG_H #endif // RENDERCONFIG_H

14
gui/rendertarget.cpp Arquivo normal
Ver arquivo

@ -0,0 +1,14 @@
#include <QDataStream>
#include "rendertarget.h"
QDataStream &operator<<(QDataStream &out, const RenderTarget &rc)
{
out << rc.path << rc.page;
return out;
}
QDataStream &operator>>(QDataStream &in, RenderTarget &rc)
{
in >> rc.path >> rc.page;
return in;
}

15
gui/rendertarget.h Arquivo normal
Ver arquivo

@ -0,0 +1,15 @@
#ifndef RENDERTARGET_H
#define RENDERTARGET_H
#include <QString>
struct RenderTarget
{
public:
QString path;
int page;
friend QDataStream &operator<<(QDataStream &out, const RenderTarget &rc);
friend QDataStream &operator>>(QDataStream &in, RenderTarget &rc);
};
QDataStream &operator<<(QDataStream &out, const RenderTarget &rc);
QDataStream &operator>>(QDataStream &in, RenderTarget &rc);
#endif // RENDERTARGET_H

Ver arquivo

@ -156,6 +156,9 @@ QString Common::databasePath()
QString Common::ipcSocketPath() QString Common::ipcSocketPath()
{ {
QSettings settings; return "/tmp/.looqs/looqs-ipc-socket";
return settings.value(SETTINGS_KEY_IPCSOCKETPATH, "/tmp/looqs-spawner").toString();
/* May not a good idea to set it in the settings and probably nobody would ever bother to change it anyway */
// QSettings settings;
// return settings.value(SETTINGS_KEY_IPCSOCKETPATH, "/tmp/.looqs/looqs-ipc-socket").toString();
} }