比较提交
18 次代码提交
v0.6
...
31f0568a87
作者 | SHA1 | 提交日期 | |
---|---|---|---|
31f0568a87 | |||
238f9add49 | |||
7c63ee9178 | |||
1edfcc8f23 | |||
2df273dee3 | |||
5a47f5949f | |||
e6a0c0daee | |||
11b070ed42 | |||
47874b3706 | |||
10d61acbd0 | |||
eef0fae137 | |||
d8205a0da4 | |||
877224b6e1 | |||
14730ed208 | |||
fe610d3068 | |||
0c1b57d911 | |||
2885e40a3a | |||
c0f4087937 |
@ -33,11 +33,18 @@ int CommandSearch::handle(QStringList arguments)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
|
QHash<QString, bool> seenMap;
|
||||||
auto results = dbService->search(query);
|
auto results = dbService->search(query);
|
||||||
|
|
||||||
for(SearchResult &result : results)
|
for(const SearchResult &result : results)
|
||||||
{
|
{
|
||||||
Logger::info() << result.fileData.absPath << Qt::endl;
|
const QString &absPath = result.fileData.absPath;
|
||||||
|
if(!seenMap.contains(absPath))
|
||||||
|
{
|
||||||
|
seenMap[absPath] = true;
|
||||||
|
Logger::info() << absPath << Qt::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(LooqsGeneralException &e)
|
catch(LooqsGeneralException &e)
|
||||||
|
@ -1,16 +1,50 @@
|
|||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
#include "ipcpreviewworker.h"
|
#include "ipcpreviewworker.h"
|
||||||
#include "previewgeneratormapfunctor.h"
|
#include "previewgeneratormapfunctor.h"
|
||||||
IPCPreviewWorker::IPCPreviewWorker()
|
IPCPreviewWorker::IPCPreviewWorker(QLocalSocket *peer)
|
||||||
{
|
{
|
||||||
|
this->peer = peer;
|
||||||
this->connect(&previewWorkerWatcher, &QFutureWatcher<QByteArray>::resultReadyAt, this,
|
this->connect(&previewWorkerWatcher, &QFutureWatcher<QByteArray>::resultReadyAt, this,
|
||||||
[this](int index) { emit previewGenerated(previewWorkerWatcher.resultAt(index)); });
|
[this](int 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::start(RenderConfig config, const QVector<RenderTarget> &targets, QLocalSocket *peer)
|
void IPCPreviewWorker::shutdownSocket()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
@ -11,13 +11,21 @@ class IPCPreviewWorker : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
QFutureWatcher<QByteArray> previewWorkerWatcher;
|
QFutureWatcher<QByteArray> previewWorkerWatcher;
|
||||||
|
QLocalSocket *peer;
|
||||||
|
bool cleaned = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IPCPreviewWorker();
|
IPCPreviewWorker(QLocalSocket *peer);
|
||||||
void start(RenderConfig config, const QVector<RenderTarget> &targets, QLocalSocket *peer);
|
void start(RenderConfig config, const QVector<RenderTarget> &targets);
|
||||||
void stop();
|
void stop();
|
||||||
|
~IPCPreviewWorker()
|
||||||
|
{
|
||||||
|
delete this->peer;
|
||||||
|
}
|
||||||
|
private slots:
|
||||||
|
void shutdownSocket();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void previewGenerated(QByteArray);
|
|
||||||
void finished();
|
void finished();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@ 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)
|
||||||
@ -31,8 +29,6 @@ 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())
|
||||||
@ -53,21 +49,22 @@ 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();
|
{
|
||||||
socket->flush();
|
stream << targets.count();
|
||||||
previewWorker.start(renderConfig, targets, socket);
|
socket->flush();
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
previewWorker.stop();
|
/* TODO: implement */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IpcServer::handlePreviewGenerated(QByteArray ba)
|
|
||||||
{
|
|
||||||
QDataStream stream{this->currentSocket};
|
|
||||||
stream << ba;
|
|
||||||
this->currentSocket->flush();
|
|
||||||
}
|
|
||||||
|
@ -10,13 +10,10 @@ 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();
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#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"
|
||||||
@ -60,6 +61,10 @@ MainWindow::MainWindow(QWidget *parent, QString socketPath)
|
|||||||
QString ignorePatterns = settings.value("ignorePatterns").toString();
|
QString ignorePatterns = settings.value("ignorePatterns").toString();
|
||||||
ui->txtIgnorePatterns->setText(ignorePatterns);
|
ui->txtIgnorePatterns->setText(ignorePatterns);
|
||||||
|
|
||||||
|
QStringList searchHistoryList = settings.value(SETTINGS_KEY_SEARCHHISTORY).toStringList();
|
||||||
|
this->searchHistory = searchHistoryList.toVector();
|
||||||
|
this->currentSearchHistoryIndex = this->searchHistory.size();
|
||||||
|
|
||||||
ui->spinPreviewPage->setValue(1);
|
ui->spinPreviewPage->setValue(1);
|
||||||
ui->spinPreviewPage->setMinimum(1);
|
ui->spinPreviewPage->setMinimum(1);
|
||||||
|
|
||||||
@ -70,6 +75,9 @@ MainWindow::MainWindow(QWidget *parent, QString socketPath)
|
|||||||
policy.setRetainSizeWhenHidden(true);
|
policy.setRetainSizeWhenHidden(true);
|
||||||
ui->btnOpenFailed->setSizePolicy(policy);
|
ui->btnOpenFailed->setSizePolicy(policy);
|
||||||
|
|
||||||
|
ui->txtSearch->installEventFilter(this);
|
||||||
|
ui->scrollArea->viewport()->installEventFilter(this);
|
||||||
|
|
||||||
this->ipcClientThread.start();
|
this->ipcClientThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +199,14 @@ void MainWindow::connectSignals()
|
|||||||
connect(ui->btnSaveSettings, &QPushButton::clicked, this, &MainWindow::saveSettings);
|
connect(ui->btnSaveSettings, &QPushButton::clicked, this, &MainWindow::saveSettings);
|
||||||
connect(ui->btnOpenFailed, &QPushButton::clicked, this, &MainWindow::exportFailedPaths);
|
connect(ui->btnOpenFailed, &QPushButton::clicked, this, &MainWindow::exportFailedPaths);
|
||||||
connect(
|
connect(
|
||||||
ui->comboPreviewFiles, qOverload<int>(&QComboBox::currentIndexChanged), this, [&]() { makePreviews(1); },
|
ui->comboPreviewFiles, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
|
[&]()
|
||||||
|
{
|
||||||
|
if(this->previewTabActive())
|
||||||
|
{
|
||||||
|
makePreviews(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
connect(&ipcPreviewClient, &IPCPreviewClient::previewReceived, this, &MainWindow::previewReceived,
|
connect(&ipcPreviewClient, &IPCPreviewClient::previewReceived, this, &MainWindow::previewReceived,
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
@ -201,6 +216,7 @@ void MainWindow::connectSignals()
|
|||||||
this->ui->previewProcessBar->setValue(this->ui->previewProcessBar->maximum());
|
this->ui->previewProcessBar->setValue(this->ui->previewProcessBar->maximum());
|
||||||
this->ui->spinPreviewPage->setEnabled(true);
|
this->ui->spinPreviewPage->setEnabled(true);
|
||||||
this->ui->comboPreviewFiles->setEnabled(true);
|
this->ui->comboPreviewFiles->setEnabled(true);
|
||||||
|
ui->txtSearch->setEnabled(true);
|
||||||
});
|
});
|
||||||
connect(&ipcPreviewClient, &IPCPreviewClient::error, this,
|
connect(&ipcPreviewClient, &IPCPreviewClient::error, this,
|
||||||
[this](QString msg)
|
[this](QString msg)
|
||||||
@ -437,6 +453,86 @@ void MainWindow::processShortcut(int key)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainWindow::eventFilter(QObject *object, QEvent *event)
|
||||||
|
{
|
||||||
|
if(object == ui->txtSearch && !searchHistory.empty())
|
||||||
|
{
|
||||||
|
if(event->type() == QEvent::KeyPress)
|
||||||
|
{
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||||
|
if(keyEvent->key() == Qt::Key_Up)
|
||||||
|
{
|
||||||
|
if(this->currentSavedSearchText.isEmpty())
|
||||||
|
{
|
||||||
|
this->currentSavedSearchText = ui->txtSearch->text();
|
||||||
|
}
|
||||||
|
if(this->currentSearchHistoryIndex <= 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
--this->currentSearchHistoryIndex;
|
||||||
|
QString text = this->searchHistory.at(this->currentSearchHistoryIndex);
|
||||||
|
ui->txtSearch->setText(text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(keyEvent->key() == Qt::Key_Down)
|
||||||
|
{
|
||||||
|
if(this->currentSearchHistoryIndex == searchHistory.size() - 1)
|
||||||
|
{
|
||||||
|
if(!this->currentSavedSearchText.isEmpty())
|
||||||
|
{
|
||||||
|
ui->txtSearch->setText(this->currentSavedSearchText);
|
||||||
|
this->currentSavedSearchText.clear();
|
||||||
|
++this->currentSearchHistoryIndex;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(this->currentSearchHistoryIndex < searchHistory.size() - 1)
|
||||||
|
{
|
||||||
|
++this->currentSearchHistoryIndex;
|
||||||
|
QString text = this->searchHistory.at(this->currentSearchHistoryIndex);
|
||||||
|
ui->txtSearch->setText(text);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->currentSavedSearchText.clear();
|
||||||
|
/* Off by one on purpose so Key_Up decrements it again and lands at
|
||||||
|
* the last entry */
|
||||||
|
this->currentSearchHistoryIndex = this->searchHistory.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(object == ui->scrollArea->viewport())
|
||||||
|
{
|
||||||
|
if(event->type() == QEvent::Wheel)
|
||||||
|
{
|
||||||
|
QWheelEvent *wheelEvent = static_cast<QWheelEvent *>(event);
|
||||||
|
if(wheelEvent->modifiers() & Qt::ControlModifier)
|
||||||
|
{
|
||||||
|
if(wheelEvent->angleDelta().y() > 0)
|
||||||
|
{
|
||||||
|
if(ui->comboScale->currentIndex() < ui->comboScale->count() - 1)
|
||||||
|
{
|
||||||
|
ui->comboScale->setCurrentIndex(ui->comboScale->currentIndex() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(ui->comboScale->currentIndex() > 0)
|
||||||
|
{
|
||||||
|
ui->comboScale->setCurrentIndex(ui->comboScale->currentIndex() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QMainWindow::eventFilter(object, event);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::keyPressEvent(QKeyEvent *event)
|
void MainWindow::keyPressEvent(QKeyEvent *event)
|
||||||
{
|
{
|
||||||
bool quit =
|
bool quit =
|
||||||
@ -498,6 +594,9 @@ void MainWindow::initSettingsTabs()
|
|||||||
ui->txtSettingMountPaths->setText(mountPaths);
|
ui->txtSettingMountPaths->setText(mountPaths);
|
||||||
ui->spinSettingNumerPerPages->setValue(numPagesPerPreview);
|
ui->spinSettingNumerPerPages->setValue(numPagesPerPreview);
|
||||||
ui->txtSettingDatabasePath->setText(databasePath);
|
ui->txtSettingDatabasePath->setText(databasePath);
|
||||||
|
bool horizontalScroll = settings.value(SETTINGS_KEY_PREVIEWS_SCROLL_HORIZONTALLY).toBool();
|
||||||
|
ui->radioScrollHorizontally->setChecked(horizontalScroll);
|
||||||
|
ui->radioScrollVertically->setChecked(!horizontalScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::saveSettings()
|
void MainWindow::saveSettings()
|
||||||
@ -525,6 +624,7 @@ void MainWindow::saveSettings()
|
|||||||
settings.setValue(SETTINGS_KEY_MOUNTPATHS, mountPaths);
|
settings.setValue(SETTINGS_KEY_MOUNTPATHS, mountPaths);
|
||||||
settings.setValue(SETTINGS_KEY_PREVIEWSPERPAGE, ui->spinSettingNumerPerPages->value());
|
settings.setValue(SETTINGS_KEY_PREVIEWSPERPAGE, ui->spinSettingNumerPerPages->value());
|
||||||
settings.setValue(SETTINGS_KEY_DBPATH, databasePath);
|
settings.setValue(SETTINGS_KEY_DBPATH, databasePath);
|
||||||
|
settings.setValue(SETTINGS_KEY_PREVIEWS_SCROLL_HORIZONTALLY, ui->radioScrollHorizontally->isChecked());
|
||||||
|
|
||||||
settings.sync();
|
settings.sync();
|
||||||
|
|
||||||
@ -548,6 +648,7 @@ 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();
|
||||||
|
|
||||||
@ -579,6 +680,7 @@ 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);
|
||||||
@ -600,6 +702,14 @@ void MainWindow::lineEditReturnPressed()
|
|||||||
ui->tabWidget->setCurrentIndex(0);
|
ui->tabWidget->setCurrentIndex(0);
|
||||||
}
|
}
|
||||||
// TODO: validate q;
|
// TODO: validate q;
|
||||||
|
while(this->searchHistory.size() > 30)
|
||||||
|
{
|
||||||
|
this->searchHistory.removeFirst();
|
||||||
|
}
|
||||||
|
this->searchHistory.append(q);
|
||||||
|
this->currentSearchHistoryIndex = this->searchHistory.size();
|
||||||
|
this->currentSavedSearchText.clear();
|
||||||
|
|
||||||
ui->treeResultsList->clear();
|
ui->treeResultsList->clear();
|
||||||
ui->lblSearchResults->setText("Searching...");
|
ui->lblSearchResults->setText("Searching...");
|
||||||
this->ui->txtSearch->setEnabled(false);
|
this->ui->txtSearch->setEnabled(false);
|
||||||
@ -699,35 +809,42 @@ 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;
|
||||||
for(const SearchResult &result : results)
|
for(const SearchResult &result : results)
|
||||||
{
|
{
|
||||||
QFileInfo pathInfo(result.fileData.absPath);
|
const QString &absPath = result.fileData.absPath;
|
||||||
|
QFileInfo pathInfo(absPath);
|
||||||
|
|
||||||
QString fileName = pathInfo.fileName();
|
if(!seenMap.contains(absPath))
|
||||||
QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeResultsList);
|
{
|
||||||
|
QString fileName = pathInfo.fileName();
|
||||||
|
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, 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));
|
||||||
|
}
|
||||||
bool exists = pathInfo.exists();
|
bool exists = pathInfo.exists();
|
||||||
if(exists)
|
if(exists)
|
||||||
{
|
{
|
||||||
if(!result.wasContentSearch)
|
if(result.wasContentSearch)
|
||||||
{
|
{
|
||||||
continue;
|
if(!pathInfo.suffix().contains("htm")) // hack until we can preview them properly...
|
||||||
}
|
|
||||||
|
|
||||||
if(!pathInfo.suffix().contains("htm")) // hack until we can preview them properly...
|
|
||||||
{
|
|
||||||
if(PreviewGenerator::get(pathInfo) != nullptr)
|
|
||||||
{
|
{
|
||||||
this->previewableSearchResults.append(result);
|
if(PreviewGenerator::get(pathInfo) != nullptr)
|
||||||
ui->comboPreviewFiles->addItem(result.fileData.absPath);
|
{
|
||||||
|
this->previewableSearchResults.append(result);
|
||||||
|
if(!seenMap.contains(result.fileData.absPath))
|
||||||
|
{
|
||||||
|
ui->comboPreviewFiles->addItem(result.fileData.absPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -735,7 +852,9 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
|
|||||||
{
|
{
|
||||||
hasDeleted = true;
|
hasDeleted = true;
|
||||||
}
|
}
|
||||||
|
seenMap[absPath] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->treeResultsList->resizeColumnToContents(0);
|
ui->treeResultsList->resizeColumnToContents(0);
|
||||||
ui->treeResultsList->resizeColumnToContents(1);
|
ui->treeResultsList->resizeColumnToContents(1);
|
||||||
ui->treeResultsList->resizeColumnToContents(2);
|
ui->treeResultsList->resizeColumnToContents(2);
|
||||||
@ -749,6 +868,7 @@ 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";
|
||||||
@ -771,7 +891,17 @@ void MainWindow::makePreviews(int page)
|
|||||||
}
|
}
|
||||||
qDeleteAll(ui->scrollAreaWidgetContents->children());
|
qDeleteAll(ui->scrollAreaWidgetContents->children());
|
||||||
|
|
||||||
ui->scrollAreaWidgetContents->setLayout(new QHBoxLayout());
|
QSettings settings;
|
||||||
|
bool horizontalScroll = settings.value(SETTINGS_KEY_PREVIEWS_SCROLL_HORIZONTALLY, false).toBool();
|
||||||
|
if(horizontalScroll)
|
||||||
|
{
|
||||||
|
ui->scrollAreaWidgetContents->setLayout(new QHBoxLayout());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->scrollAreaWidgetContents->setLayout(new QVBoxLayout());
|
||||||
|
ui->scrollAreaWidgetContents->layout()->setAlignment(Qt::AlignCenter);
|
||||||
|
}
|
||||||
ui->previewProcessBar->setMaximum(this->previewableSearchResults.size());
|
ui->previewProcessBar->setMaximum(this->previewableSearchResults.size());
|
||||||
processedPdfPreviews = 0;
|
processedPdfPreviews = 0;
|
||||||
|
|
||||||
@ -820,12 +950,8 @@ void MainWindow::makePreviews(int page)
|
|||||||
}
|
}
|
||||||
RenderTarget renderTarget;
|
RenderTarget renderTarget;
|
||||||
renderTarget.path = sr.fileData.absPath;
|
renderTarget.path = sr.fileData.absPath;
|
||||||
|
renderTarget.page = (int)sr.page;
|
||||||
for(unsigned int pagenum : sr.pages)
|
targets.append(renderTarget);
|
||||||
{
|
|
||||||
renderTarget.page = (int)pagenum;
|
|
||||||
targets.append(renderTarget);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
int numpages = ceil(static_cast<double>(targets.size()) / previewsPerPage);
|
int numpages = ceil(static_cast<double>(targets.size()) / previewsPerPage);
|
||||||
ui->spinPreviewPage->setMaximum(numpages);
|
ui->spinPreviewPage->setMaximum(numpages);
|
||||||
@ -839,6 +965,7 @@ void MainWindow::makePreviews(int page)
|
|||||||
++this->currentPreviewGeneration;
|
++this->currentPreviewGeneration;
|
||||||
this->ui->spinPreviewPage->setEnabled(false);
|
this->ui->spinPreviewPage->setEnabled(false);
|
||||||
this->ui->comboPreviewFiles->setEnabled(false);
|
this->ui->comboPreviewFiles->setEnabled(false);
|
||||||
|
this->ui->txtSearch->setEnabled(false);
|
||||||
emit startIpcPreviews(renderConfig, targets);
|
emit startIpcPreviews(renderConfig, targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -925,3 +1052,11 @@ MainWindow::~MainWindow()
|
|||||||
delete this->indexer;
|
delete this->indexer;
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
QStringList list = this->searchHistory.toList();
|
||||||
|
QSettings settings;
|
||||||
|
settings.setValue(SETTINGS_KEY_SEARCHHISTORY, list);
|
||||||
|
settings.sync();
|
||||||
|
}
|
||||||
|
@ -30,6 +30,9 @@ class MainWindow : public QMainWindow
|
|||||||
void beginSearch(const QString &query);
|
void beginSearch(const QString &query);
|
||||||
void startPdfPreviewGeneration(QVector<SearchResult> paths, double scalefactor);
|
void startPdfPreviewGeneration(QVector<SearchResult> paths, double scalefactor);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DatabaseFactory *dbFactory;
|
DatabaseFactory *dbFactory;
|
||||||
SqliteDbService *dbService;
|
SqliteDbService *dbService;
|
||||||
@ -64,7 +67,11 @@ class MainWindow : public QMainWindow
|
|||||||
void initSettingsTabs();
|
void initSettingsTabs();
|
||||||
int currentSelectedScale();
|
int currentSelectedScale();
|
||||||
void processShortcut(int key);
|
void processShortcut(int key);
|
||||||
private slots:
|
bool eventFilter(QObject *object, QEvent *event);
|
||||||
|
QVector<QString> searchHistory;
|
||||||
|
int currentSearchHistoryIndex = 0;
|
||||||
|
QString currentSavedSearchText;
|
||||||
|
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);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1280</width>
|
<width>1280</width>
|
||||||
<height>855</height>
|
<height>888</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<enum>QTabWidget::South</enum>
|
<enum>QTabWidget::South</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>1</number>
|
<number>3</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="resultsTab">
|
<widget class="QWidget" name="resultsTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
@ -82,7 +82,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1244</width>
|
<width>1244</width>
|
||||||
<height>565</height>
|
<height>598</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout"/>
|
<layout class="QHBoxLayout" name="horizontalLayout"/>
|
||||||
@ -542,6 +542,19 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="Misc">
|
<widget class="QGroupBox" name="Misc">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -551,7 +564,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="lblMaxNumbersPreviewPages">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Max number of previews per 'page' in 'Previews' tab: </string>
|
<string>Max number of previews per 'page' in 'Previews' tab: </string>
|
||||||
</property>
|
</property>
|
||||||
@ -575,22 +588,47 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblScrollModeForPreviews">
|
||||||
|
<property name="text">
|
||||||
|
<string>Scroll mode for previews:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="radioScrollVertically">
|
||||||
|
<property name="text">
|
||||||
|
<string>Vertically</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="radioScrollHorizontally">
|
||||||
|
<property name="text">
|
||||||
|
<string>Horizontally</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_6">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="btnSaveSettings">
|
<widget class="QPushButton" name="btnSaveSettings">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include "previewgeneratorpdf.h"
|
#include "previewgeneratorpdf.h"
|
||||||
|
|
||||||
static QMutex cacheMutex;
|
static QMutex cacheMutex;
|
||||||
@ -17,6 +18,7 @@ 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();
|
||||||
@ -45,7 +47,12 @@ 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 = pdfPage->search(word, Poppler::Page::SearchFlag::IgnoreCase);
|
QList<QRectF> rects =
|
||||||
|
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);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "previewgeneratorplaintext.h"
|
#include "previewgeneratorplaintext.h"
|
||||||
#include "previewresultplaintext.h"
|
#include "previewresultplaintext.h"
|
||||||
@ -57,6 +58,7 @@ 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)
|
||||||
{
|
{
|
||||||
@ -74,10 +76,19 @@ 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)
|
||||||
{
|
{
|
||||||
QString resultText;
|
QVector<Snippet> snippets;
|
||||||
const unsigned int contextLinesCount = 2;
|
const int contextLinesCount = 2;
|
||||||
LimitQueue<QString> queue(contextLinesCount);
|
LimitQueue<QString> queue(contextLinesCount);
|
||||||
QString currentLine;
|
QString currentLine;
|
||||||
currentLine.reserve(512);
|
currentLine.reserve(512);
|
||||||
@ -85,38 +96,73 @@ 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;
|
||||||
|
|
||||||
auto appendLine = [&resultText](int lineNumber, QString &line)
|
struct Snippet currentSnippet;
|
||||||
{ resultText.append(QString("<b>%1</b>%2<br>").arg(lineNumber).arg(line)); };
|
|
||||||
|
|
||||||
QHash<QString, int> countmap;
|
auto appendLine = [¤tSnippet, &config](int lineNumber, QString &line)
|
||||||
QString header = "<b>" + fileName + "</b> ";
|
|
||||||
|
|
||||||
unsigned int snippetsCount = 0;
|
|
||||||
unsigned int lineCount = 0;
|
|
||||||
while(in.readLineInto(¤tLine) && snippetsCount < MAX_SNIPPETS)
|
|
||||||
{
|
{
|
||||||
|
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 lineCount = 0;
|
||||||
|
while(in.readLineInto(¤tLine))
|
||||||
|
{
|
||||||
|
currentLine = currentLine.toHtmlEscaped();
|
||||||
++lineCount;
|
++lineCount;
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
if(justReadLinesCount > 0)
|
if(justReadLinesCount > 0)
|
||||||
{
|
{
|
||||||
appendLine(lineCount, currentLine);
|
|
||||||
--justReadLinesCount;
|
int result = appendLine(lineCount, currentLine);
|
||||||
|
if(justReadLinesCount == 1 && result > 0)
|
||||||
|
{
|
||||||
|
justReadLinesCount = contextLinesCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
--justReadLinesCount;
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(justReadLinesCount == 0)
|
if(justReadLinesCount == 0)
|
||||||
{
|
{
|
||||||
resultText += "---<br>";
|
currentSnippet.snippetText += "---<br>";
|
||||||
justReadLinesCount = -1;
|
justReadLinesCount = -1;
|
||||||
++snippetsCount;
|
snippets.append(currentSnippet);
|
||||||
|
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;
|
||||||
currentLine.replace(word, "<span style=\"background-color: yellow;\">" + word + "</span>",
|
break;
|
||||||
Qt::CaseInsensitive);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(matched)
|
if(matched)
|
||||||
@ -125,7 +171,6 @@ 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);
|
||||||
@ -137,13 +182,77 @@ 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(countmap[word]) + " ";
|
header += word + ": " + QString::number(totalWordCountMap[word]) + " ";
|
||||||
}
|
|
||||||
if(snippetsCount == MAX_SNIPPETS)
|
|
||||||
{
|
|
||||||
header += "(truncated)";
|
|
||||||
}
|
}
|
||||||
header += "<hr>";
|
header += "<hr>";
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#define SETTINGS_KEY_EXCLUDEDPATHS "excludedpaths"
|
#define SETTINGS_KEY_EXCLUDEDPATHS "excludedpaths"
|
||||||
#define SETTINGS_KEY_MOUNTPATHS "mountpaths"
|
#define SETTINGS_KEY_MOUNTPATHS "mountpaths"
|
||||||
#define SETTINGS_KEY_PREVIEWSPERPAGE "previewsPerPage"
|
#define SETTINGS_KEY_PREVIEWSPERPAGE "previewsPerPage"
|
||||||
|
#define SETTINGS_KEY_SEARCHHISTORY "searchhistory"
|
||||||
|
#define SETTINGS_KEY_PREVIEWS_SCROLL_HORIZONTALLY "horizontalscroll"
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
|
@ -6,11 +6,11 @@ template <class T> class LimitQueue
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
QQueue<T> queue;
|
QQueue<T> queue;
|
||||||
unsigned int limit = 0;
|
int limit = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LimitQueue();
|
LimitQueue();
|
||||||
LimitQueue(unsigned int limit)
|
LimitQueue(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(unsigned int limit)
|
void setLimit(int limit)
|
||||||
{
|
{
|
||||||
this->limit = limit;
|
this->limit = limit;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ class SearchResult
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FileData fileData;
|
FileData fileData;
|
||||||
QVector<unsigned int> pages;
|
unsigned int page;
|
||||||
bool wasContentSearch = false;
|
bool wasContentSearch = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,12 +78,17 @@ QString SqliteSearch::escapeFtsArgument(QString ftsArg)
|
|||||||
if(value.isEmpty())
|
if(value.isEmpty())
|
||||||
{
|
{
|
||||||
value = m.captured(2);
|
value = m.captured(2);
|
||||||
|
if(value.endsWith('*'))
|
||||||
|
{
|
||||||
|
value = value.mid(0, value.size() - 1);
|
||||||
|
}
|
||||||
|
result += "\"" + value + "\"*";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
value = "\"\"" + value + "\"\"";
|
value = "\"\"" + value + "\"\"";
|
||||||
|
result += "\"" + value + "\" ";
|
||||||
}
|
}
|
||||||
result += "\"" + value + "\" ";
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -189,10 +194,9 @@ QSqlQuery SqliteSearch::makeSqlQuery(const LooqsQuery &query)
|
|||||||
sortSql = "ORDER BY rank";
|
sortSql = "ORDER BY rank";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prepSql =
|
prepSql = "SELECT file.path AS path, content.page AS page, file.mtime AS mtime, file.size AS size, "
|
||||||
"SELECT file.path AS path, group_concat(content.page) AS pages, file.mtime AS mtime, file.size AS size, "
|
"file.filetype AS filetype FROM file INNER JOIN content ON file.id = content.fileid " +
|
||||||
"file.filetype AS filetype FROM file INNER JOIN content ON file.id = content.fileid " +
|
joinSql + " WHERE 1=1 AND " + whereSql + " " + sortSql;
|
||||||
joinSql + " WHERE 1=1 AND " + whereSql + " GROUP BY file.path " + sortSql;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -200,7 +204,7 @@ QSqlQuery SqliteSearch::makeSqlQuery(const LooqsQuery &query)
|
|||||||
{
|
{
|
||||||
sortSql = "ORDER BY file.mtime DESC";
|
sortSql = "ORDER BY file.mtime DESC";
|
||||||
}
|
}
|
||||||
prepSql = "SELECT file.path AS path, '0' as pages, file.mtime AS mtime, file.size AS size, file.filetype AS "
|
prepSql = "SELECT file.path AS path, '0' as page, file.mtime AS mtime, file.size AS size, file.filetype AS "
|
||||||
"filetype FROM file WHERE 1=1 AND " +
|
"filetype FROM file WHERE 1=1 AND " +
|
||||||
whereSql + " " + sortSql;
|
whereSql + " " + sortSql;
|
||||||
}
|
}
|
||||||
@ -243,15 +247,7 @@ QVector<SearchResult> SqliteSearch::search(const LooqsQuery &query)
|
|||||||
result.fileData.mtime = dbQuery.value("mtime").toUInt();
|
result.fileData.mtime = dbQuery.value("mtime").toUInt();
|
||||||
result.fileData.size = dbQuery.value("size").toUInt();
|
result.fileData.size = dbQuery.value("size").toUInt();
|
||||||
result.fileData.filetype = dbQuery.value("filetype").toChar();
|
result.fileData.filetype = dbQuery.value("filetype").toChar();
|
||||||
QString pages = dbQuery.value("pages").toString();
|
result.page = dbQuery.value("page").toUInt();
|
||||||
QStringList pagesList = pages.split(",");
|
|
||||||
for(QString &page : pagesList)
|
|
||||||
{
|
|
||||||
if(page != "")
|
|
||||||
{
|
|
||||||
result.pages.append(page.toUInt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.wasContentSearch = contentSearch;
|
result.wasContentSearch = contentSearch;
|
||||||
results.append(result);
|
results.append(result);
|
||||||
}
|
}
|
||||||
|
在新工单中引用
屏蔽一个用户