Compare commits
6 Commits
431abfe7c0
...
14730ed208
Author | SHA1 | Date | |
---|---|---|---|
14730ed208 | |||
fe610d3068 | |||
0c1b57d911 | |||
2885e40a3a | |||
c0f4087937 | |||
46c52afe59 |
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,8 +1,23 @@
|
|||||||
# looqs: Release notes
|
# looqs: Release notes
|
||||||
|
## 2022-08-14 - v0.6
|
||||||
|
This release features multiple fixes and enhancements.
|
||||||
|
|
||||||
|
Bad news first: It drops a trivial trigger that appeared to work quite fine, but silently may cause "unpredictability" of the sqlite FTS5 index ( [9422a5b494](https://github.com/quitesimpleorg/looqs/commit/9422a5b494dabd0f1324dc2f92a34c3036137414) ). As a result, FTS queries may return weird and unexplainable results. This is not reasonably automatically recoverable by looqs. I strongly recommend creating a clean, new database. All previous versions are affected. To do that, go to "Settings" -> checking "Remove old database on save" -> "Save settings and restart". Alternatively, specify a new path to keep the old database.
|
||||||
|
|
||||||
|
CHANGES:
|
||||||
|
|
||||||
|
- GUI: Add line numbers and context lines to plaintext previews
|
||||||
|
- GUI: Fix case where previews for old queries would have still been visible if new query would not create previews
|
||||||
|
- GUI: Add CTRL + F, CTRL+W, CTRL+Tab, CTRL+Shift+Tab shortcuts (see user manual)
|
||||||
|
- GUI: Add checkbox in "Settings" tab allowing to delete database.
|
||||||
|
- General: Fix wrong regexes that caused query errors with chars like -
|
||||||
|
- General: Drop trigger sending incomplete sqlite fts5 deletion command, causing undefined index behaviour
|
||||||
|
|
||||||
## 2022-07-30 - v0.5.1
|
## 2022-07-30 - v0.5.1
|
||||||
|
|
||||||
CHANGES:
|
CHANGES:
|
||||||
- gui: Fix regression in implicit paths queries introduced in previous version
|
|
||||||
|
- gui: Fix regression in implicit paths queries introduced in previous version
|
||||||
|
|
||||||
## 2022-07-29 - v0.5
|
## 2022-07-29 - v0.5
|
||||||
This release features multiple fixes and enhancements.
|
This release features multiple fixes and enhancements.
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
# looqs - Full-text search with previews for your files
|
# looqs - Full-text search with previews for your files
|
||||||
looqs is a tool that creates a full-text search index for your files. It allows you to look at previews where your
|
looqs is a tool that creates a full-text search index for your files. It allows you to look at previews where your search terms have been found, as shown in the screenshots below.
|
||||||
search terms have been found, as shown in the screenshots below.
|
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
### Preview
|
### Preview
|
||||||
looqs allow you to look inside files. It marks what you have searched for.
|
looqs allows you to look inside files. It highlights what you have searched for.
|
||||||
|
|
||||||
![Screenshot looqs](https://garage.quitesimple.org/assets/looqs/orwell.png)
|
![Screenshot looqs](https://garage.quitesimple.org/assets/looqs/orwell.png)
|
||||||
![Screenshot looqs search fstream](https://garage.quitesimple.org/assets/looqs/fstream_write.png)
|
![Screenshot looqs search fstream](https://garage.quitesimple.org/assets/looqs/fstream_write.png)
|
||||||
@ -29,7 +28,7 @@ There is no need to write the long form of filters. There are also booleans avai
|
|||||||
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.
|
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
|
## Current status
|
||||||
Latest version: 2022-07-30, v0.5.1
|
Latest version: 2022-08-14, v0.6
|
||||||
|
|
||||||
Please see [Changelog](CHANGELOG.md) for a human readable list of changes.
|
Please see [Changelog](CHANGELOG.md) for a human readable list of changes.
|
||||||
|
|
||||||
|
@ -60,6 +60,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 +74,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,6 +444,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 +585,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 +615,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();
|
||||||
|
|
||||||
@ -600,6 +691,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);
|
||||||
@ -771,7 +870,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;
|
||||||
|
|
||||||
@ -925,3 +1034,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">
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user