比較提交
28 次程式碼提交
759d2a7924
...
5f19328679
作者 | SHA1 | 日期 | |
---|---|---|---|
5f19328679 | |||
5ffd7ae97e | |||
9ed28df09c | |||
69e028daf5 | |||
d4b0c1feae | |||
990888efc1 | |||
3f8c147182 | |||
ba030169aa | |||
1636e39c5b | |||
bda23670e3 | |||
d0fe51c666 | |||
a561032668 | |||
b8006bde7b | |||
614238edda | |||
83ed935790 | |||
69837ed60f | |||
2ad99699bf | |||
b6b3e2f3c0 | |||
cf0c940b15 | |||
9c41d531b0 | |||
780318db6d | |||
9fd48d4664 | |||
e99b2ba091 | |||
0867ab294d | |||
01a6a499c5 | |||
b3c6ce3899 | |||
72dae1f7be | |||
e01f5d6490 |
14
CHANGELOG.md
14
CHANGELOG.md
@ -1,5 +1,19 @@
|
||||
# looqs: Release notes
|
||||
|
||||
## 2022-06-29 - v0.4
|
||||
This release makes several minor improvements and begins prebuilt binaries of looqs that (should) run
|
||||
on any recent Linux distribution.
|
||||
|
||||
- General: Begin new, experimental distro-agnostic tarball containing prebuilt binaries and libs. See the README for more information.
|
||||
- GUI: In the "Previews" tab, allow filtering by file, to only show previews for a specific file.
|
||||
- GUI: Add "Show previews" context menu option to files in result (if available)
|
||||
- General: Fix build with libquazip 1.X
|
||||
- General: Properly report access errors as a failure during indexing
|
||||
- GUI: Add button to export a list of all paths that failed
|
||||
- General: Improve dir scan threading
|
||||
- CLI: Improve helptext
|
||||
- General: Add voidlinux build instructions
|
||||
|
||||
## 2022-06-14 - v0.3
|
||||
CHANGES:
|
||||
- GUI: Add settings tab to configure various settings
|
||||
|
1119
LICENSE-3RD-PARTY
Normal file
1119
LICENSE-3RD-PARTY
Normal file
檔案差異因為檔案過大而無法顯示
載入差異
37
README.md
37
README.md
@ -3,8 +3,6 @@ looqs is a tool that creates a full-text search index for your files. It allows
|
||||
search terms have been found, as shown in the screenshots below.
|
||||
|
||||
## 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 of the GUI.
|
||||
|
||||
### Preview
|
||||
looqs allow you to look inside files. It marks what you have searched for.
|
||||
|
||||
@ -28,9 +26,10 @@ There is no need to write the long form of filters. There are also booleans avai
|
||||
|
||||
![Screenshot looqs results](https://garage.quitesimple.org/assets/looqs/looqs_beatles_marley.png)
|
||||
|
||||
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 of the GUI.
|
||||
|
||||
## Current status
|
||||
Last version: 2022-06-14, v0.3
|
||||
Latest version: 2022-06-29, v0.4
|
||||
|
||||
Please see [Changelog](CHANGELOG.md) for a human readable list of changes.
|
||||
|
||||
@ -58,6 +57,8 @@ Linux (on amd64) is currently the main focus. Currently, I don't plan on support
|
||||
### Licence
|
||||
GPLv3.
|
||||
|
||||
For the dependencies/third-party libraries, see: LICENSE-3RD-PARTY
|
||||
|
||||
### Contributing
|
||||
Please see the [Contribution guidelines](CONTRIBUTING.md) file.
|
||||
|
||||
@ -106,7 +107,35 @@ sudo apt-get update
|
||||
sudo apt-get install looqs
|
||||
```
|
||||
|
||||
### Prebuilt tarball (distro-agnostic) (EXPERIMENTAL)
|
||||
looqs is also distributed as a tarball containing prebuilt binaries and its library dependencies. The tarball is
|
||||
built using the Gentoo Hardened toolchain and the Qt version is smaller than what distributions usually
|
||||
include. It does not include libraries that should mess with fontrendering or the graphics stack. The binaries should run on any recent Linux distribution (requires glibc 2.34 or newer at least) and expects
|
||||
dependencies such as libGL to be provided by your distribution already (should be the case).
|
||||
|
||||
It's considered experimental for two reasons. Firstly, looqs has no updater (yet). You will have to manually check for updates. Secondly, I can't guarantee that I'll be quick with updates of the tarball specifically if the library versions become outdated between looqs updates.
|
||||
|
||||
You are therefore encouraged to use distro-native packages or to build it yourself if possible.
|
||||
|
||||
The tarball can be obtained here: https://repo.quitesimple.org/tarball/looqs
|
||||
|
||||
Quick start:
|
||||
|
||||
```
|
||||
# Verify sig, see the end of this document: gpg --verify looqs-v0.4.tar.xz.sig
|
||||
tar xf looqs-v0.4.tar.xz # Replace with the actual version you have obtained
|
||||
cd looqs-v0.4
|
||||
./looqs-gui # or ./looqs for the CLI
|
||||
```
|
||||
|
||||
An AppImage may accompany the tarball in the future.
|
||||
|
||||
|
||||
### Other distros
|
||||
I'll probably add a package for voidlinux at some point and maybe will provide a Gentoo ebuild. However, I would appreciate help for others distros. If you create a package, let me know!
|
||||
|
||||
As for distro-agnostic packages, I will also take a look into appimage / flatpak etc. and/or maybe just provide a self-contained archive.
|
||||
|
||||
### Signature verification
|
||||
Release tags can be verified with [my PGP public key](https://quitesimple.org/share/pubkey). For what little it's worth, its fingerprint is: `C342 CA02 D2EC 2E14 F3C3 D5FF 7F7B 4C08 02CD 02F2`
|
||||
|
||||
Packages can be verified with the [repo-specific public key](https://repo.quitesimple.org/repo.quitesimple.org.asc). For what little it's worth, its fingerprint is: `1B49 45B3 16B2 468A 3DAC C1E0 75EF 3FE8 D753 C8F9`
|
||||
|
@ -47,7 +47,8 @@ int CommandAdd::handle(QStringList arguments)
|
||||
{{"t", "threads"}, "Number of threads to use.", "threads"}});
|
||||
|
||||
parser.addHelpOption();
|
||||
parser.addPositionalArgument("add", "Add paths to the index", "add [paths...]");
|
||||
parser.addPositionalArgument("add", "Add paths to the index",
|
||||
"add [paths...]. If no path is given, read from stdin, one path per line.");
|
||||
|
||||
parser.process(arguments);
|
||||
this->keepGoing = parser.isSet("continue");
|
||||
|
@ -30,6 +30,7 @@
|
||||
void printUsage(QString argv0)
|
||||
{
|
||||
qInfo() << "Usage:" << argv0 << "command";
|
||||
qInfo() << "Valid commands: add, update, delete, search, list. Each command has a --help option.";
|
||||
}
|
||||
|
||||
Command *commandFromName(QString name, SqliteDbService &dbService)
|
||||
@ -97,7 +98,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
QString file = args.at(1);
|
||||
SandboxedProcessor processor(file);
|
||||
return processor.process();
|
||||
return static_cast<int>(processor.process());
|
||||
}
|
||||
Command *cmd = commandFromName(commandName, dbService);
|
||||
if(cmd != nullptr)
|
||||
@ -116,7 +117,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error() << "Unknown command:" << commandName << Qt::endl;
|
||||
printUsage(argv0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
74
gui/aboutdialog.cpp
Normal file
74
gui/aboutdialog.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include <QTabWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QTextBrowser>
|
||||
#include <QPushButton>
|
||||
#include "aboutdialog.h"
|
||||
#include "common.h"
|
||||
|
||||
AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
QTabWidget *tabWidget = new QTabWidget(this);
|
||||
|
||||
this->setWindowTitle("About looqs");
|
||||
|
||||
QHBoxLayout *closeLayout = new QHBoxLayout();
|
||||
QPushButton *closeButton = new QPushButton(this);
|
||||
closeButton->setText("Close");
|
||||
closeButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
connect(closeButton, &QPushButton::clicked, this, &QDialog::close);
|
||||
|
||||
closeLayout->setMargin(10);
|
||||
closeLayout->addStretch(10);
|
||||
closeLayout->addWidget(closeButton);
|
||||
|
||||
layout->addWidget(tabWidget);
|
||||
layout->addLayout(closeLayout);
|
||||
QFrame *frame = new QFrame(this);
|
||||
QVBoxLayout *aboutLayout = new QVBoxLayout(frame);
|
||||
frame->setLayout(aboutLayout);
|
||||
|
||||
QLabel *aboutLooqs = new QLabel(this);
|
||||
QString html = "<h2>looqs</h2>";
|
||||
html += "Full-text search with previews for your files<br><br>";
|
||||
html += "Copyright (c) 2018-2022: Albert Schwarzkopf<br><br>";
|
||||
html += QString("Version: %1<br><br>").arg(Common::versionText());
|
||||
html += "Contact: looqs at quitesimple dot org<br><br>";
|
||||
html += "Website: <a href=\"https://quitesimple.org\">https://quitesimple.org</a><br><br>";
|
||||
html += "Source code: <a "
|
||||
"href=\"https://github.com/quitesimpleorg/looqs\">https://github.com/quitesimpleorg/looqs</a><br><br>";
|
||||
html += "License: GPLv3<br><br>";
|
||||
html += "looqs is open source and free of charge in the hope it will be useful. The author(s) do not "
|
||||
"give any warranty. In the unlikely event of any damage, the author(s) cannot be held responsible. "
|
||||
"You are using looqs at your own risk<br><br>";
|
||||
html += "looqs uses third-party libraries, please see the corresponding tab.";
|
||||
aboutLooqs->setText(html);
|
||||
aboutLooqs->setTextFormat(Qt::RichText);
|
||||
|
||||
QLabel *logo = new QLabel(this);
|
||||
QImage image(QString(":/looqs.svg"));
|
||||
logo->setPixmap(QPixmap::fromImage(image));
|
||||
|
||||
aboutLayout->addWidget(logo);
|
||||
aboutLayout->addWidget(aboutLooqs);
|
||||
|
||||
tabWidget->addTab(frame, "About");
|
||||
|
||||
QFile license(QString(":/LICENSE"));
|
||||
license.open(QIODevice::ReadOnly);
|
||||
QString licenseText = license.readAll();
|
||||
|
||||
QFile thirdPartyLicense(QString(":./LICENSE-3RD-PARTY"));
|
||||
thirdPartyLicense.open(QIODevice::ReadOnly);
|
||||
QString thirdPartyLicenseInfo = thirdPartyLicense.readAll();
|
||||
|
||||
QTextBrowser *licenseTextBrowser = new QTextBrowser(this);
|
||||
licenseTextBrowser->setText(licenseText);
|
||||
|
||||
QTextBrowser *thirdPartyLicenceTextBrowser = new QTextBrowser(this);
|
||||
thirdPartyLicenceTextBrowser->setText(thirdPartyLicenseInfo);
|
||||
|
||||
tabWidget->addTab(licenseTextBrowser, "License");
|
||||
tabWidget->addTab(thirdPartyLicenceTextBrowser, "Third-party libraries");
|
||||
}
|
12
gui/aboutdialog.h
Normal file
12
gui/aboutdialog.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef ABOUTDIALOG_H
|
||||
#define ABOUTDIALOG_H
|
||||
#include <QDialog>
|
||||
|
||||
class AboutDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AboutDialog(QWidget *parent = nullptr);
|
||||
};
|
||||
|
||||
#endif // ABOUTDIALOG_H
|
@ -27,6 +27,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
aboutdialog.cpp \
|
||||
ipcpreviewclient.cpp \
|
||||
ipcpreviewworker.cpp \
|
||||
ipcserver.cpp \
|
||||
@ -44,6 +45,7 @@ SOURCES += \
|
||||
rendertarget.cpp
|
||||
|
||||
HEADERS += \
|
||||
aboutdialog.h \
|
||||
ipc.h \
|
||||
ipcpreviewclient.h \
|
||||
ipcpreviewworker.h \
|
||||
|
@ -114,7 +114,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
QString file = args.at(2);
|
||||
SandboxedProcessor processor(file);
|
||||
return processor.process();
|
||||
return static_cast<int>(processor.process());
|
||||
}
|
||||
}
|
||||
QString ipcSocketPath = Common::ipcSocketPath();
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "../shared/common.h"
|
||||
#include "ipcpreviewclient.h"
|
||||
#include "previewgenerator.h"
|
||||
#include "aboutdialog.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent, QString socketPath)
|
||||
: QMainWindow(parent), ui(new Ui::MainWindow), progressDialog(this)
|
||||
@ -40,6 +41,7 @@ MainWindow::MainWindow(QWidget *parent, QString socketPath)
|
||||
{
|
||||
this->ui->previewProcessBar->setValue(this->ui->previewProcessBar->maximum());
|
||||
this->ui->spinPreviewPage->setEnabled(true);
|
||||
this->ui->comboPreviewFiles->setEnabled(true);
|
||||
});
|
||||
connect(&ipcPreviewClient, &IPCPreviewClient::error, this,
|
||||
[this](QString msg)
|
||||
@ -82,6 +84,13 @@ MainWindow::MainWindow(QWidget *parent, QString socketPath)
|
||||
|
||||
ui->spinPreviewPage->setValue(1);
|
||||
ui->spinPreviewPage->setMinimum(1);
|
||||
|
||||
ui->btnOpenFailed->setVisible(false);
|
||||
ui->comboPreviewFiles->setVisible(false);
|
||||
|
||||
auto policy = ui->btnOpenFailed->sizePolicy();
|
||||
policy.setRetainSizeWhenHidden(true);
|
||||
ui->btnOpenFailed->setSizePolicy(policy);
|
||||
}
|
||||
|
||||
void MainWindow::addPathToIndex()
|
||||
@ -172,26 +181,13 @@ void MainWindow::connectSignals()
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(
|
||||
ui->menuAboutAction, &QAction::triggered, this,
|
||||
[this](bool checked)
|
||||
{
|
||||
QString html = "<h2>looqs</h2>";
|
||||
html += "Full-text search with previews for your files<br><br>";
|
||||
html += "Copyright (c) 2018-2022: Albert Schwarzkopf<br><br>";
|
||||
html += QString("Version: %1<br><br>").arg(Common::versionText());
|
||||
html += "Contact: looqs at quitesimple dot org<br><br>";
|
||||
html += "Website: <a href=\"https://quitesimple.org\">https://quitesimple.org</a><br><br>";
|
||||
html +=
|
||||
"Source code: <a "
|
||||
"href=\"https://github.com/quitesimpleorg/looqs\">https://github.com/quitesimpleorg/looqs</a><br><br>";
|
||||
html += "License: GPLv3<br><br><br>";
|
||||
html += "looqs is open source and free of charge in the hope it will be useful. The author(s) do not "
|
||||
"give any warranty. In the unlikely event of any damage, the author(s) cannot be held responsible. "
|
||||
"You are using looqs at your own risk";
|
||||
connect(ui->menuAboutAction, &QAction::triggered, this,
|
||||
[this](bool checked)
|
||||
{
|
||||
AboutDialog aboutDialog(this);
|
||||
|
||||
QMessageBox::about(this, "About looqs", html);
|
||||
});
|
||||
aboutDialog.exec();
|
||||
});
|
||||
connect(ui->menuAboutQtAction, &QAction::triggered, this,
|
||||
[this](bool checked) { QMessageBox::aboutQt(this, "About Qt"); });
|
||||
connect(ui->menuSyncIndexAction, &QAction::triggered, this, &MainWindow::startIndexSync);
|
||||
@ -210,6 +206,35 @@ void MainWindow::connectSignals()
|
||||
connect(this, &MainWindow::beginIndexSync, indexSyncer, &IndexSyncer::sync);
|
||||
connect(&this->progressDialog, &QProgressDialog::canceled, indexSyncer, &IndexSyncer::cancel);
|
||||
connect(ui->btnSaveSettings, &QPushButton::clicked, this, &MainWindow::saveSettings);
|
||||
connect(ui->btnOpenFailed, &QPushButton::clicked, this, &MainWindow::exportFailedPaths);
|
||||
connect(
|
||||
ui->comboPreviewFiles, qOverload<int>(&QComboBox::currentIndexChanged), this, [&]() { makePreviews(1); },
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void MainWindow::exportFailedPaths()
|
||||
{
|
||||
|
||||
QString filename =
|
||||
QString("/tmp/looqs_indexresult_failed_%1").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hhmmss"));
|
||||
QFile outFile(filename);
|
||||
if(!outFile.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
{
|
||||
QMessageBox::critical(this, "Failed to write log file", "An error occured while trying to create log file");
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream stream(&outFile);
|
||||
|
||||
IndexResult result = this->indexer->getResult();
|
||||
|
||||
stream << "Failed to index the following paths:\n";
|
||||
for(FileScanResult &fsr : result.failedResults())
|
||||
{
|
||||
stream << fsr.first << " " << SaveFileResultToString(fsr.second) << '\n';
|
||||
}
|
||||
|
||||
QDesktopServices::openUrl(filename);
|
||||
}
|
||||
|
||||
void MainWindow::startIndexSync()
|
||||
@ -254,6 +279,7 @@ void MainWindow::startIndexing()
|
||||
ui->txtSearch->setEnabled(false);
|
||||
ui->previewProcessBar->setValue(0);
|
||||
ui->previewProcessBar->setVisible(true);
|
||||
ui->btnOpenFailed->setVisible(false);
|
||||
|
||||
QVector<QString> paths;
|
||||
QStringList pathSettingsValue;
|
||||
@ -289,6 +315,10 @@ void MainWindow::finishIndexing()
|
||||
ui->settingsTab->setEnabled(true);
|
||||
ui->txtPathScanAdd->setEnabled(true);
|
||||
ui->txtSearch->setEnabled(true);
|
||||
if(result.erroredPaths > 0)
|
||||
{
|
||||
ui->btnOpenFailed->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::comboScaleChanged(int i)
|
||||
@ -477,6 +507,9 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
|
||||
{
|
||||
this->previewableSearchResults.clear();
|
||||
ui->treeResultsList->clear();
|
||||
ui->comboPreviewFiles->clear();
|
||||
ui->comboPreviewFiles->addItem("All previews");
|
||||
ui->comboPreviewFiles->setVisible(true);
|
||||
|
||||
bool hasDeleted = false;
|
||||
for(const SearchResult &result : results)
|
||||
@ -505,6 +538,7 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
|
||||
if(PreviewGenerator::get(pathInfo) != nullptr)
|
||||
{
|
||||
this->previewableSearchResults.append(result);
|
||||
ui->comboPreviewFiles->addItem(result.fileData.absPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -582,6 +616,13 @@ void MainWindow::makePreviews(int page)
|
||||
QVector<RenderTarget> targets;
|
||||
for(SearchResult &sr : this->previewableSearchResults)
|
||||
{
|
||||
if(ui->comboPreviewFiles->currentIndex() != 0)
|
||||
{
|
||||
if(sr.fileData.absPath != ui->comboPreviewFiles->currentText())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
RenderTarget renderTarget;
|
||||
renderTarget.path = sr.fileData.absPath;
|
||||
|
||||
@ -602,6 +643,7 @@ void MainWindow::makePreviews(int page)
|
||||
ui->previewProcessBar->setVisible(this->previewableSearchResults.size() > 0);
|
||||
++this->currentPreviewGeneration;
|
||||
this->ui->spinPreviewPage->setEnabled(false);
|
||||
this->ui->comboPreviewFiles->setEnabled(false);
|
||||
emit startIpcPreviews(renderConfig, targets);
|
||||
}
|
||||
|
||||
@ -617,6 +659,20 @@ void MainWindow::createSearchResutlMenu(QMenu &menu, const QFileInfo &fileInfo)
|
||||
menu.addAction("Copy full path to clipboard",
|
||||
[&fileInfo] { QGuiApplication::clipboard()->setText(fileInfo.absoluteFilePath()); });
|
||||
menu.addAction("Open containing folder", [this, &fileInfo] { this->openFile(fileInfo.absolutePath()); });
|
||||
|
||||
auto result =
|
||||
std::find_if(this->previewableSearchResults.begin(), this->previewableSearchResults.end(),
|
||||
[this, &fileInfo](SearchResult &a) { return fileInfo.absoluteFilePath() == a.fileData.absPath; });
|
||||
|
||||
if(result != this->previewableSearchResults.end())
|
||||
{
|
||||
menu.addAction("Show previews for this file",
|
||||
[this, &fileInfo]
|
||||
{
|
||||
ui->tabWidget->setCurrentIndex(1);
|
||||
this->ui->comboPreviewFiles->setCurrentText(fileInfo.absoluteFilePath());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::openDocument(QString path, int num)
|
||||
|
@ -75,6 +75,7 @@ class MainWindow : public QMainWindow
|
||||
void addPathToIndex();
|
||||
void startIndexSync();
|
||||
void saveSettings();
|
||||
void exportFailedPaths();
|
||||
|
||||
signals:
|
||||
void startIpcPreviews(RenderConfig config, const QVector<RenderTarget> &targets);
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1280</width>
|
||||
<height>736</height>
|
||||
<height>855</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -27,7 +27,7 @@
|
||||
<enum>QTabWidget::South</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>3</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="resultsTab">
|
||||
<attribute name="title">
|
||||
@ -82,7 +82,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1244</width>
|
||||
<height>446</height>
|
||||
<height>565</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout"/>
|
||||
@ -162,6 +162,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboPreviewFiles">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
@ -184,6 +194,16 @@
|
||||
<string>Index</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLineEdit" name="txtIgnorePatterns"/>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QPushButton" name="btnStartIndexing">
|
||||
<property name="text">
|
||||
<string>Start indexing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="groupBoxPaths">
|
||||
<property name="title">
|
||||
@ -243,6 +263,12 @@
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblPathsFound">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Paths found:</string>
|
||||
</property>
|
||||
@ -250,17 +276,42 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblPathsFoundValue">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<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>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblAdded">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
@ -274,17 +325,42 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblAddedValue">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<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>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblSkipped">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
@ -298,17 +374,42 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblSkippedValue">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<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>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblFailed">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
@ -322,26 +423,35 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblFailedValue">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnOpenFailed">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open log of failed paths</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLineEdit" name="txtIgnorePatterns"/>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QPushButton" name="btnStartIndexing">
|
||||
<property name="text">
|
||||
<string>Start indexing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="settingsTab">
|
||||
|
@ -17,6 +17,7 @@
|
||||
inline void initResources()
|
||||
{
|
||||
Q_INIT_RESOURCE(migrations);
|
||||
Q_INIT_RESOURCE(plaintexts);
|
||||
}
|
||||
|
||||
bool Common::initSqliteDatabase(QString path)
|
||||
@ -68,11 +69,11 @@ void Common::setPdfViewer()
|
||||
}
|
||||
else if(evincePath != "")
|
||||
{
|
||||
value = evincePath + "-i %p %f";
|
||||
value = evincePath + " -i %p %f";
|
||||
}
|
||||
else if(qpdfviewPath != "")
|
||||
{
|
||||
value = qpdfviewPath + "%f#%p";
|
||||
value = qpdfviewPath + " %f#%p";
|
||||
}
|
||||
|
||||
QSettings settings;
|
||||
|
@ -19,9 +19,12 @@ void DirScanWorker::run()
|
||||
QString path;
|
||||
/* TODO: if we have e. g. only one path, then only one thread will scan this path.
|
||||
*
|
||||
* Thus, we must resubmit to the queue directories so other threads can help
|
||||
the current one (requires a new logic for threads in ParallelDirScanner). Alterantively,
|
||||
start new DirScanWorkers ourselves here... */
|
||||
* Thus, we must submit new directory paths to the queue so other threads can help
|
||||
the current one.
|
||||
|
||||
It also may not be guaranteed enqueuing new paths is faster than just scanning them,
|
||||
at least not for dirs with a small number of files
|
||||
*/
|
||||
while(queue->dequeue(path))
|
||||
{
|
||||
if(wildcardMatcher.match(path))
|
||||
|
@ -87,6 +87,10 @@ int FileSaver::processFiles(const QVector<QString> paths, std::function<SaveFile
|
||||
{
|
||||
Logger::info() << "Saved" << path << Qt::endl;
|
||||
}
|
||||
else if(result == OK_WASEMPTY)
|
||||
{
|
||||
Logger::info() << "Saved (but content was empty)" << path << Qt::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -98,7 +102,12 @@ SaveFileResult FileSaver::saveFile(const QFileInfo &fileInfo)
|
||||
QVector<PageData> pageData;
|
||||
QString canonicalPath = fileInfo.canonicalFilePath();
|
||||
|
||||
int status = -1;
|
||||
int processorReturnCode = -1;
|
||||
|
||||
if(!fileInfo.isReadable())
|
||||
{
|
||||
return NOACCESS;
|
||||
}
|
||||
|
||||
if(!fileInfo.exists())
|
||||
{
|
||||
@ -115,44 +124,45 @@ SaveFileResult FileSaver::saveFile(const QFileInfo &fileInfo)
|
||||
}
|
||||
}
|
||||
|
||||
QProcess process;
|
||||
QStringList args;
|
||||
args << "process" << canonicalPath;
|
||||
process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
|
||||
process.start("/proc/self/exe", args);
|
||||
process.waitForStarted();
|
||||
process.waitForFinished();
|
||||
|
||||
/* TODO: This is suboptimal as it eats lots of mem
|
||||
* but avoids a weird QDataStream/QProcess behaviour
|
||||
* where it thinks the process has ended when it has not...
|
||||
*
|
||||
* Also, there seem to be issues with reads not being blocked, so
|
||||
* the only reliable way appears to be waiting until the process
|
||||
* finishes.
|
||||
*/
|
||||
QDataStream in(process.readAllStandardOutput());
|
||||
while(!in.atEnd())
|
||||
if(fileInfo.size() > 0)
|
||||
{
|
||||
PageData pd;
|
||||
in >> pd;
|
||||
pageData.append(pd);
|
||||
}
|
||||
status = process.exitCode();
|
||||
if(status != 0 && status != NOTHING_PROCESSED)
|
||||
{
|
||||
Logger::error() << "FileSaver::saveFile(): Error while processing" << canonicalPath << ":"
|
||||
<< "Exit code " << status << Qt::endl;
|
||||
QProcess process;
|
||||
QStringList args;
|
||||
args << "process" << canonicalPath;
|
||||
process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
|
||||
process.start("/proc/self/exe", args);
|
||||
process.waitForStarted();
|
||||
process.waitForFinished();
|
||||
|
||||
return PROCESSFAIL;
|
||||
/* TODO: This is suboptimal as it eats lots of mem
|
||||
* but avoids a weird QDataStream/QProcess behaviour
|
||||
* where it thinks the process has ended when it has not...
|
||||
*
|
||||
* Also, there seem to be issues with reads not being blocked, so
|
||||
* the only reliable way appears to be waiting until the process
|
||||
* finishes.
|
||||
*/
|
||||
QDataStream in(process.readAllStandardOutput());
|
||||
while(!in.atEnd())
|
||||
{
|
||||
PageData pd;
|
||||
in >> pd;
|
||||
pageData.append(pd);
|
||||
}
|
||||
processorReturnCode = process.exitCode();
|
||||
if(processorReturnCode != OK && processorReturnCode != OK_WASEMPTY)
|
||||
{
|
||||
Logger::error() << "FileSaver::saveFile(): Error while processing" << canonicalPath << ":"
|
||||
<< "Exit code " << processorReturnCode << Qt::endl;
|
||||
|
||||
return static_cast<SaveFileResult>(processorReturnCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Could happen if a file corrupted for example
|
||||
if(pageData.isEmpty() && status != NOTHING_PROCESSED)
|
||||
SaveFileResult result = this->dbService->saveFile(fileInfo, pageData);
|
||||
if(result == OK && processorReturnCode == OK_WASEMPTY)
|
||||
{
|
||||
Logger::error() << "Could not get any content for " << canonicalPath << Qt::endl;
|
||||
return OK_WASEMPTY;
|
||||
}
|
||||
|
||||
return this->dbService->saveFile(fileInfo, pageData);
|
||||
return result;
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ void Indexer::dirScanProgress(int current, int total)
|
||||
|
||||
void Indexer::processFileScanResult(FileScanResult result)
|
||||
{
|
||||
if(result.second == DBFAIL || result.second == PROCESSFAIL || result.second == NOTFOUND)
|
||||
if(result.second != OK || result.second != OK_WASEMPTY || result.second != SKIPPED)
|
||||
{
|
||||
this->currentIndexResult.results.append(result);
|
||||
if(!keepGoing)
|
||||
@ -138,7 +138,8 @@ void Indexer::processFileScanResult(FileScanResult result)
|
||||
}
|
||||
}
|
||||
|
||||
if(result.second == OK)
|
||||
/* TODO: OK_WASEMPTY might need a special list */
|
||||
if(result.second == OK || result.second == OK_WASEMPTY)
|
||||
{
|
||||
++this->currentIndexResult.addedPaths;
|
||||
}
|
||||
|
@ -22,19 +22,30 @@ class IndexResult
|
||||
return addedPaths + skippedPaths + erroredPaths;
|
||||
}
|
||||
|
||||
QVector<QString> failedPaths() const
|
||||
QVector<FileScanResult> failedResults() const
|
||||
{
|
||||
QVector<QString> result;
|
||||
QVector<FileScanResult> result;
|
||||
std::for_each(results.begin(), results.end(),
|
||||
[&result](FileScanResult res)
|
||||
{
|
||||
if(res.second == DBFAIL || res.second == PROCESSFAIL || res.second == NOTFOUND)
|
||||
if(res.second == DBFAIL || res.second == PROCESSFAIL || res.second == NOTFOUND ||
|
||||
res.second == NOACCESS)
|
||||
{
|
||||
result.append(res.first);
|
||||
result.append(res);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
QVector<QString> failedPaths() const
|
||||
{
|
||||
QVector<QString> result;
|
||||
|
||||
QVector<FileScanResult> results = failedResults();
|
||||
|
||||
std::for_each(results.begin(), results.end(), [&result](FileScanResult res) { result.append(res.first); });
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
class Indexer : public QObject
|
||||
|
@ -71,7 +71,35 @@ void ParallelDirScanner::scan()
|
||||
this->targetPathsQueue.clear();
|
||||
this->resultPathsQueue.clear();
|
||||
|
||||
this->targetPathsQueue.enqueue(this->paths);
|
||||
/* First scan without subdirs. This way we collect paths for the threads */
|
||||
WildcardMatcher matcher;
|
||||
matcher.setPatterns(this->ignorePatterns);
|
||||
for(QString &path : this->paths)
|
||||
{
|
||||
QDirIterator iterator(path, QStringList{}, QDir::Dirs | QDir::QDir::Files | QDir::NoDotAndDotDot);
|
||||
while(iterator.hasNext())
|
||||
{
|
||||
QString path = iterator.next();
|
||||
if(matcher.match(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QFileInfo info = iterator.fileInfo();
|
||||
if(!info.isSymLink())
|
||||
{
|
||||
if(info.isDir())
|
||||
{
|
||||
this->targetPathsQueue.enqueue(info.absoluteFilePath());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->resultPathsQueue.enqueue(info.absoluteFilePath());
|
||||
this->processedPaths += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
emit this->progress(this->processedPaths, this->processedPaths);
|
||||
int threadsNum = getThreadsNum();
|
||||
if(threadsNum == 0)
|
||||
{
|
||||
|
6
shared/plaintexts.qrc
Normal file
6
shared/plaintexts.qrc
Normal file
@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource>
|
||||
<file>../LICENSE</file>
|
||||
<file>../LICENSE-3RD-PARTY</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -10,8 +10,6 @@ enum DataSource
|
||||
ARRAY
|
||||
};
|
||||
|
||||
#define NOTHING_PROCESSED 4
|
||||
|
||||
class Processor
|
||||
{
|
||||
public:
|
||||
|
@ -80,7 +80,7 @@ void SandboxedProcessor::printResults(const QVector<PageData> &pageData)
|
||||
fsstdout.close();
|
||||
}
|
||||
|
||||
int SandboxedProcessor::process()
|
||||
SaveFileResult SandboxedProcessor::process()
|
||||
{
|
||||
QFileInfo fileInfo(this->filePath);
|
||||
Processor *processor = processors.value(fileInfo.suffix(), nullptr);
|
||||
@ -92,10 +92,14 @@ int SandboxedProcessor::process()
|
||||
processor = defaultTextProcessor;
|
||||
}
|
||||
}
|
||||
if(!fileInfo.isReadable())
|
||||
{
|
||||
return NOACCESS;
|
||||
}
|
||||
if(processor == nullptr || processor == nothingProcessor)
|
||||
{
|
||||
/* Nothing to do */
|
||||
return NOTHING_PROCESSED;
|
||||
return OK;
|
||||
}
|
||||
|
||||
QVector<PageData> pageData;
|
||||
@ -119,9 +123,9 @@ int SandboxedProcessor::process()
|
||||
catch(LooqsGeneralException &e)
|
||||
{
|
||||
Logger::error() << "SandboxedProcessor: Error while processing" << absPath << ":" << e.message << Qt::endl;
|
||||
return 3 /* PROCESSFAIL */;
|
||||
return PROCESSFAIL;
|
||||
}
|
||||
|
||||
printResults(pageData);
|
||||
return 0;
|
||||
return pageData.isEmpty() ? OK_WASEMPTY : OK;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <QString>
|
||||
#include <QMimeDatabase>
|
||||
#include "pagedata.h"
|
||||
#include "savefileresult.h"
|
||||
|
||||
class SandboxedProcessor
|
||||
{
|
||||
@ -19,7 +20,7 @@ class SandboxedProcessor
|
||||
this->filePath = filepath;
|
||||
}
|
||||
|
||||
int process();
|
||||
SaveFileResult process();
|
||||
};
|
||||
|
||||
#endif // SANDBOXEDPROCESSOR_H
|
||||
|
33
shared/savefileresult.h
Normal file
33
shared/savefileresult.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef SAVEFILERESULT_H
|
||||
#define SAVEFILERESULT_H
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
enum SaveFileResult
|
||||
{
|
||||
OK,
|
||||
OK_WASEMPTY, /* The file was successfully read but no content could be extracted. Might be just an empty document or
|
||||
so*/
|
||||
SKIPPED, /* The file was not processed/saved, because it has not changed */
|
||||
DBFAIL, /* A database error occured */
|
||||
PROCESSFAIL, /* General processor failure */
|
||||
NOTFOUND, /* The file was not found */
|
||||
NOACCESS /* The process can't read the file */
|
||||
};
|
||||
|
||||
static inline QString SaveFileResultToString(SaveFileResult sfr)
|
||||
{
|
||||
QStringList SaveFileResultStr;
|
||||
|
||||
SaveFileResultStr << "OK"
|
||||
<< "OK_WASEMPTY"
|
||||
<< "SKIPPED"
|
||||
<< "DBFAIL"
|
||||
<< "PROCESSFAIL"
|
||||
<< "NOTFOUND"
|
||||
<< "NOACCESS";
|
||||
|
||||
return SaveFileResultStr[(int)sfr];
|
||||
}
|
||||
|
||||
#endif // SAVEFILERESULT_H
|
@ -88,6 +88,7 @@ HEADERS += sqlitesearch.h \
|
||||
pdfprocessor.h \
|
||||
processor.h \
|
||||
sandboxedprocessor.h \
|
||||
savefileresult.h \
|
||||
searchresult.h \
|
||||
sqlitedbservice.h \
|
||||
tagstripperprocessor.h \
|
||||
@ -100,3 +101,4 @@ unix {
|
||||
INSTALLS += target
|
||||
}
|
||||
RESOURCES = migrations/migrations.qrc
|
||||
RESOURCES += plaintexts.qrc
|
||||
|
@ -7,14 +7,7 @@
|
||||
#include "filedata.h"
|
||||
#include "../shared/sqlitesearch.h"
|
||||
#include "../shared/token.h"
|
||||
enum SaveFileResult
|
||||
{
|
||||
OK,
|
||||
SKIPPED,
|
||||
DBFAIL,
|
||||
PROCESSFAIL,
|
||||
NOTFOUND
|
||||
};
|
||||
#include "savefileresult.h"
|
||||
|
||||
class SqliteDbService
|
||||
{
|
||||
|
載入中…
新增問題並參考
Block a user