first commit
This commit is contained in:
commit
f96452d669
90
README.md
Normal file
90
README.md
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
qsRunner
|
||||||
|
========
|
||||||
|
qsRunner is a launcher. It contains user defined entries for applications and also searches
|
||||||
|
system-applications. Using libcalculate, it can also be used as a calculator. It
|
||||||
|
can also search for files (and their contents) by querying a sqlite database, although it itself does
|
||||||
|
not index files.
|
||||||
|
|
||||||
|
If you run a desktop environment like KDE it is questionable whether you will
|
||||||
|
find this useful, since they usually bring applications that are more or less
|
||||||
|
comparable to qsRunner, although much more
|
||||||
|
powerful (like KRunner). It can be useful for users running a window manager like
|
||||||
|
fluxbox etc.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
It has been only tested for Qt 5.7.
|
||||||
|
|
||||||
|
For the calculation engine, libqalculate is needed.
|
||||||
|
For file search, easyindex is necessary.
|
||||||
|
|
||||||
|
Currently no conditional compile flags are supported...
|
||||||
|
|
||||||
|
Getting started
|
||||||
|
----------------
|
||||||
|
Currently it may not be considered a classical GUI application because the
|
||||||
|
configuration must be done outside of it.
|
||||||
|
|
||||||
|
mkdir $HOME/.config/qsRunner
|
||||||
|
In this folder user-defined entries should be put (See "Entry format").
|
||||||
|
|
||||||
|
Config format
|
||||||
|
------------
|
||||||
|
Path: $HOME/.config/qsRunner/qsrunner.config
|
||||||
|
|
||||||
|
```
|
||||||
|
[Search]
|
||||||
|
dbpath="/path/to/database.sqlite"
|
||||||
|
|
||||||
|
[General]
|
||||||
|
systemApplicationsPath="/usr/share/applications/"
|
||||||
|
```
|
||||||
|
|
||||||
|
systemApplicationsPath will default to "/usr/share/applications/",
|
||||||
|
therefore specifying it explicitly is not necessary.
|
||||||
|
|
||||||
|
Entry format
|
||||||
|
------------
|
||||||
|
It rudimentary supports .desktop files, but for user entries, the own format
|
||||||
|
should be preferred.
|
||||||
|
|
||||||
|
It's a simple format: [key] [value].
|
||||||
|
|
||||||
|
Example: quasselclient.qsrun:
|
||||||
|
|
||||||
|
```
|
||||||
|
command quasselclient
|
||||||
|
name Quassel
|
||||||
|
icon /usr/share/icons/hicolor/128x128/apps/quassel.png
|
||||||
|
row 1
|
||||||
|
col 0
|
||||||
|
key I
|
||||||
|
```
|
||||||
|
|
||||||
|
"key" means a shortcut key, you can launch those by pressing Ctrl + "key", so in
|
||||||
|
the example above: CTRL + I.
|
||||||
|
|
||||||
|
Simply pressing Ctrl will show you the associated shortcuts on each individual
|
||||||
|
button.
|
||||||
|
|
||||||
|
|
||||||
|
General usage
|
||||||
|
=============
|
||||||
|
Starting to type will search user defined entries first, followed by system
|
||||||
|
entries. Then the PATH variable will be searched, if there is a single match you can also
|
||||||
|
press TAB for auto completion.
|
||||||
|
|
||||||
|
In general it will launch anything once you press enter, however it won't open a
|
||||||
|
terminal.
|
||||||
|
|
||||||
|
Calculator
|
||||||
|
=========
|
||||||
|
Start by typing "=", followed by your expression, e. g: "=(2+3)^2"
|
||||||
|
|
||||||
|
File searches
|
||||||
|
=============
|
||||||
|
It only queries a sqlite database. It does not index files, this is beyond the
|
||||||
|
scope a launcher. For the file searches functionality, easyindex is necessary.
|
||||||
|
See: git.quitesimple.org/easyindex.
|
||||||
|
|
||||||
|
|
42
calculationengine.cpp
Normal file
42
calculationengine.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include "calculationengine.h"
|
||||||
|
|
||||||
|
|
||||||
|
CalculationEngine::CalculationEngine()
|
||||||
|
{
|
||||||
|
if (!CALCULATOR) {
|
||||||
|
new Calculator();
|
||||||
|
CALCULATOR->terminateThreads();
|
||||||
|
CALCULATOR->setPrecision(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
//stolen from krunner's qalculate engine
|
||||||
|
/*eo.auto_post_conversion = POST_CONVERSION_BEST;
|
||||||
|
eo.keep_zero_units = false;
|
||||||
|
|
||||||
|
eo.parse_options.angle_unit = ANGLE_UNIT_RADIANS;
|
||||||
|
eo.structuring = STRUCTURING_SIMPLIFY;
|
||||||
|
|
||||||
|
// suggested in https://github.com/Qalculate/libqalculate/issues/16
|
||||||
|
// to avoid memory overflow for seemingly innocent calculations (Bug 277011)
|
||||||
|
eo.approximation = APPROXIMATION_APPROXIMATE;
|
||||||
|
|
||||||
|
po.number_fraction_format = FRACTION_DECIMAL;
|
||||||
|
po.indicate_infinite_series = false;
|
||||||
|
po.use_all_prefixes = false;
|
||||||
|
po.use_denominator_prefix = true;
|
||||||
|
po.negative_exponents = false;
|
||||||
|
po.lower_case_e = true;
|
||||||
|
po.base_display = BASE_DISPLAY_NORMAL;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CalculationEngine::evaluate(const QString &expression)
|
||||||
|
{
|
||||||
|
CALCULATOR->terminateThreads();
|
||||||
|
QByteArray ba = expression.toLatin1();
|
||||||
|
const char *ctext = ba.data();
|
||||||
|
MathStructure result = CALCULATOR->calculate(ctext, this->eo);
|
||||||
|
result.format(po);
|
||||||
|
return result.print(po).c_str();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
22
calculationengine.h
Normal file
22
calculationengine.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef CALCULATIONENGINE_H
|
||||||
|
#define CALCULATIONENGINE_H
|
||||||
|
#include <QString>
|
||||||
|
#include <libqalculate/Calculator.h>
|
||||||
|
#include <libqalculate/ExpressionItem.h>
|
||||||
|
#include <libqalculate/Unit.h>
|
||||||
|
#include <libqalculate/Prefix.h>
|
||||||
|
#include <libqalculate/Variable.h>
|
||||||
|
#include <libqalculate/Function.h>
|
||||||
|
|
||||||
|
class CalculationEngine
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
EvaluationOptions eo;
|
||||||
|
PrintOptions po;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CalculationEngine();
|
||||||
|
QString evaluate(const QString &expression);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CALCULATIONENGINE_H
|
151
config.cpp
Normal file
151
config.cpp
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#include <QDirIterator>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
ConfigReader::ConfigReader(QString directory)
|
||||||
|
{
|
||||||
|
this->configDirectory = directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EntryConfig ConfigReader::readFromDesktopFile(const QString &path)
|
||||||
|
{
|
||||||
|
EntryConfig result;
|
||||||
|
QFile file(path);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
|
{
|
||||||
|
//TODO: better exception class
|
||||||
|
throw new std::runtime_error("Failed to open file");
|
||||||
|
}
|
||||||
|
QTextStream stream(&file);
|
||||||
|
QString firstline = stream.readLine();
|
||||||
|
while(firstline[0] == '#')
|
||||||
|
{
|
||||||
|
firstline = stream.readLine();
|
||||||
|
}
|
||||||
|
if(firstline != "[Desktop Entry]")
|
||||||
|
{
|
||||||
|
throw new ConfigFormatException(".desktop file does not start with [Desktop Entry]");
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!stream.atEnd())
|
||||||
|
{
|
||||||
|
QString line = stream.readLine();
|
||||||
|
QStringList splitted = line.split("=");
|
||||||
|
if(splitted.length() >= 2)
|
||||||
|
{
|
||||||
|
qDebug() << splitted [0] + " " + splitted[1];
|
||||||
|
QString key = splitted[0].toLower();
|
||||||
|
if(key == "name")
|
||||||
|
{
|
||||||
|
if(result.name.length() == 0)
|
||||||
|
{
|
||||||
|
result.name = splitted[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(key == "icon")
|
||||||
|
{
|
||||||
|
result.icon = QIcon::fromTheme(splitted[1]);
|
||||||
|
}
|
||||||
|
if(key == "exec")
|
||||||
|
{
|
||||||
|
//TODO: the other arguments may also be relevant... except for %f and so
|
||||||
|
|
||||||
|
QStringList arguments = splitted[1].split(" ");
|
||||||
|
|
||||||
|
result.command = arguments[0];
|
||||||
|
if(arguments.length() > 1)
|
||||||
|
{
|
||||||
|
arguments = arguments.mid(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qsrun own's config file */
|
||||||
|
EntryConfig ConfigReader::readFromFile(const QString &path)
|
||||||
|
{
|
||||||
|
EntryConfig result;
|
||||||
|
QFile file(path);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
|
{
|
||||||
|
//TODO: better exception class
|
||||||
|
throw new std::runtime_error("Failed to open file");
|
||||||
|
}
|
||||||
|
QTextStream stream(&file);
|
||||||
|
while(!stream.atEnd())
|
||||||
|
{
|
||||||
|
QString line = stream.readLine();
|
||||||
|
QStringList splitted = line.split(" ");
|
||||||
|
if(splitted.length() < 2)
|
||||||
|
{
|
||||||
|
// throw new ConfigFormatException("Format must be [key] [value] for every line");
|
||||||
|
|
||||||
|
}
|
||||||
|
qDebug() << splitted [0] + " " + splitted[1];
|
||||||
|
QString key = splitted[0];
|
||||||
|
if(key == "arguments")
|
||||||
|
{
|
||||||
|
result.arguments = splitted.mid(1);
|
||||||
|
}
|
||||||
|
if(key == "name")
|
||||||
|
{
|
||||||
|
result.name = splitted[1];
|
||||||
|
}
|
||||||
|
if(key == "icon")
|
||||||
|
{
|
||||||
|
result.icon = QIcon(splitted[1]);
|
||||||
|
}
|
||||||
|
if(key == "row")
|
||||||
|
{
|
||||||
|
result.row = splitted[1].toInt();
|
||||||
|
}
|
||||||
|
if(key == "col")
|
||||||
|
{
|
||||||
|
result.col = splitted[1].toInt();
|
||||||
|
}
|
||||||
|
if(key == "command")
|
||||||
|
{
|
||||||
|
result.command = splitted[1];
|
||||||
|
}
|
||||||
|
if(key == "key")
|
||||||
|
{
|
||||||
|
//QKeySequence sequence(splitted[1]);
|
||||||
|
//result.keySequence = sequence;
|
||||||
|
result.key = splitted[1].toLower();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<EntryConfig> ConfigReader::readConfig()
|
||||||
|
{
|
||||||
|
QVector<EntryConfig> result;
|
||||||
|
QDirIterator it(this->configDirectory);
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
QString path = it.next();
|
||||||
|
QFileInfo info(path);
|
||||||
|
if(info.isFile())
|
||||||
|
{
|
||||||
|
QString suffix = info.completeSuffix();
|
||||||
|
if(suffix == "desktop")
|
||||||
|
{
|
||||||
|
result.append(readFromDesktopFile(path));
|
||||||
|
|
||||||
|
}
|
||||||
|
if(suffix == "qsrun")
|
||||||
|
{
|
||||||
|
result.append(readFromFile(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
43
config.h
Normal file
43
config.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
#include <exception>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QKeySequence>
|
||||||
|
class EntryConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString key;
|
||||||
|
QString name;
|
||||||
|
QString command;
|
||||||
|
QStringList arguments;
|
||||||
|
QIcon icon;
|
||||||
|
int row=0;
|
||||||
|
int col=0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConfigReader
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
QString configDirectory;
|
||||||
|
EntryConfig readFromFile(const QString &path);
|
||||||
|
EntryConfig readFromDesktopFile(const QString &path);
|
||||||
|
public:
|
||||||
|
ConfigReader(QString path);
|
||||||
|
QVector<EntryConfig> readConfig();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConfigFormatException : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConfigFormatException() : std::runtime_error("Error in configuration file, misformated line?") {};
|
||||||
|
ConfigFormatException(const std::string &str) : std::runtime_error(str) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
48
entrypushbutton.cpp
Normal file
48
entrypushbutton.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "entrypushbutton.h"
|
||||||
|
|
||||||
|
EntryPushButton::EntryPushButton(const EntryConfig &config) : QPushButton()
|
||||||
|
{
|
||||||
|
this->setText(config.name);
|
||||||
|
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
this->setIcon(config.icon);
|
||||||
|
this->setIconSize(config.icon.availableSizes().first());
|
||||||
|
this->config = config;
|
||||||
|
connect(this, SIGNAL(clicked()), this, SLOT(emitOwnClicked()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void EntryPushButton::emitOwnClicked()
|
||||||
|
{
|
||||||
|
emit clicked(this->config);
|
||||||
|
}
|
||||||
|
|
||||||
|
const EntryConfig &EntryPushButton::getEntryConfig()
|
||||||
|
{
|
||||||
|
return this->config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntryPushButton::setEntryConfig(const EntryConfig &config)
|
||||||
|
{
|
||||||
|
this->config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntryPushButton::showShortcut()
|
||||||
|
{
|
||||||
|
this->setText(this->config.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntryPushButton::showName()
|
||||||
|
{
|
||||||
|
this->setText(this->config.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int EntryPushButton::getRow() const { return config.row; }
|
||||||
|
int EntryPushButton::getCol() const { return config.col; }
|
||||||
|
QString EntryPushButton::getName() const { return config.name; }
|
||||||
|
QString EntryPushButton::getShortcutKey() const { return config.key; }
|
||||||
|
void EntryPushButton::setRow(int row) { this->config.row = row; }
|
||||||
|
void EntryPushButton::setCol(int col) { this->config.col = col; }
|
||||||
|
QStringList EntryPushButton::getArguments() const { return this->config.arguments; }
|
||||||
|
QString EntryPushButton::getCommand() const { return this->config.command; }
|
35
entrypushbutton.h
Normal file
35
entrypushbutton.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef ENTRYPUSHBUTTON_H
|
||||||
|
#define ENTRYPUSHBUTTON_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include "config.h"
|
||||||
|
class EntryPushButton : public QPushButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
EntryConfig config;
|
||||||
|
private slots:
|
||||||
|
void emitOwnClicked();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void clicked(const EntryConfig &config);
|
||||||
|
public:
|
||||||
|
EntryPushButton(const EntryConfig &config);
|
||||||
|
const EntryConfig &getEntryConfig();
|
||||||
|
void setEntryConfig(const EntryConfig &config);
|
||||||
|
void showShortcut();
|
||||||
|
void showName();
|
||||||
|
int getRow() const;
|
||||||
|
int getCol() const;
|
||||||
|
QString getName() const;
|
||||||
|
QString getShortcutKey() const;
|
||||||
|
QStringList getArguments() const;
|
||||||
|
QString getCommand() const;
|
||||||
|
void setRow(int row);
|
||||||
|
void setCol(int col);
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ENTRYPUSHBUTTON_H
|
80
main.cpp
Normal file
80
main.cpp
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#include <QApplication>
|
||||||
|
#include <QFuture>
|
||||||
|
#include <QFutureWatcher>
|
||||||
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
#include <QSettings>
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
QString configDirectoryPath;
|
||||||
|
if(argc >= 2)
|
||||||
|
{
|
||||||
|
configDirectoryPath = QCoreApplication::arguments().at(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
configDirectoryPath = QDir::homePath() + "/.config/qsRun/";
|
||||||
|
}
|
||||||
|
qRegisterMetaType<QVector<QString> >("QVector<QString>");
|
||||||
|
|
||||||
|
QDir dir(configDirectoryPath);
|
||||||
|
if(!dir.exists(configDirectoryPath))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(nullptr, "Directory not found", configDirectoryPath + " was not found!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
QSettings settings(configDirectoryPath + "qsrun.config", QSettings::NativeFormat);
|
||||||
|
QString dbpath = settings.value("Search/dbpath").toString();
|
||||||
|
QString systemApplicationsPath = settings.value("General/systemApplicationsPath", "/usr/share/applications/").toString();
|
||||||
|
|
||||||
|
QVector<EntryConfig> configs;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConfigReader reader(configDirectoryPath);
|
||||||
|
configs = reader.readConfig();
|
||||||
|
}
|
||||||
|
catch(std::exception &e)
|
||||||
|
{
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Window w(configs, dbpath);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Reconsider the need
|
||||||
|
* QFuture<void> future = QtConcurrent::run([&w] {
|
||||||
|
ConfigReader systemConfigReader("/usr/share/applications/");
|
||||||
|
QList<EntryConfig> systemconfigs = systemConfigReader.readConfig();
|
||||||
|
if(systemconfigs.count() > 0)
|
||||||
|
{
|
||||||
|
w.setSystemConfig(systemconfigs);
|
||||||
|
w.systemConfigReady();
|
||||||
|
}
|
||||||
|
});*/
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConfigReader systemConfigReader(systemApplicationsPath);
|
||||||
|
QVector<EntryConfig> systemconfigs = systemConfigReader.readConfig();
|
||||||
|
if(systemconfigs.count() > 0)
|
||||||
|
{
|
||||||
|
w.setSystemConfig(systemconfigs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(std::exception &e)
|
||||||
|
{
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
w.showMaximized();
|
||||||
|
return app.exec();
|
||||||
|
}
|
23
qsRun.pro
Normal file
23
qsRun.pro
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
######################################################################
|
||||||
|
# Automatically generated by qmake (3.0) Mon Dec 25 15:21:45 2017
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
TARGET = qsRun
|
||||||
|
INCLUDEPATH += .
|
||||||
|
|
||||||
|
# Input
|
||||||
|
HEADERS += config.h window.h \
|
||||||
|
entrypushbutton.h \
|
||||||
|
calculationengine.h \
|
||||||
|
searchworker.h
|
||||||
|
SOURCES += config.cpp main.cpp window.cpp \
|
||||||
|
entrypushbutton.cpp \
|
||||||
|
calculationengine.cpp \
|
||||||
|
searchworker.cpp
|
||||||
|
QT += widgets sql
|
||||||
|
QT_CONFIG -= no-pkg-config
|
||||||
|
LIBS += -lcln
|
||||||
|
CONFIG += link_pkgconfig
|
||||||
|
PKGCONFIG += libqalculate
|
||||||
|
|
73
searchworker.cpp
Normal file
73
searchworker.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include "searchworker.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QSqlError>
|
||||||
|
//TODO: we have code duplication in the search functions currently.
|
||||||
|
SearchWorker::SearchWorker(const QString &dbpath)
|
||||||
|
{
|
||||||
|
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
|
||||||
|
db.setDatabaseName(dbpath);
|
||||||
|
if(!db.open())
|
||||||
|
{
|
||||||
|
qDebug() << "failed to open database";
|
||||||
|
}
|
||||||
|
queryContent = new QSqlQuery(db);
|
||||||
|
queryFile = new QSqlQuery(db);
|
||||||
|
queryFile->prepare("SELECT path FROM file WHERE path LIKE ? ORDER BY mtime DESC");
|
||||||
|
queryContent->prepare("SELECT file.path FROM file INNER JOIN file_fts ON file.id = file_fts.ROWID WHERE file_fts.content MATCH ? ORDER By file.mtime DESC");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchWorker::searchForFile(const QString &query)
|
||||||
|
{
|
||||||
|
this->isPending = true;
|
||||||
|
this->cancelCurrent = false;
|
||||||
|
QVector<QString> results;
|
||||||
|
queryFile->addBindValue("%" + query + "%");
|
||||||
|
queryFile->exec();
|
||||||
|
while(queryFile->next())
|
||||||
|
{
|
||||||
|
if(cancelCurrent)
|
||||||
|
{
|
||||||
|
this->isPending = false;
|
||||||
|
emit searchCancelled();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString result = queryFile->value(0).toString();
|
||||||
|
qDebug() << "result" << result;
|
||||||
|
results.append(queryFile->value(0).toString());
|
||||||
|
}
|
||||||
|
this->isPending = false;
|
||||||
|
emit searchResultsReady(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchWorker::requestCancellation()
|
||||||
|
{
|
||||||
|
this->cancelCurrent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchWorker::searchForContent(const QString &query)
|
||||||
|
{
|
||||||
|
this->isPending = true;
|
||||||
|
this->cancelCurrent = false;
|
||||||
|
QVector<QString> results;
|
||||||
|
queryContent->addBindValue(query);
|
||||||
|
queryContent->exec();
|
||||||
|
while(queryContent->next())
|
||||||
|
{
|
||||||
|
if(cancelCurrent)
|
||||||
|
{
|
||||||
|
this->isPending = false;
|
||||||
|
emit searchCancelled();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString result = queryContent->value(0).toString();
|
||||||
|
qDebug() << "result" << result;
|
||||||
|
results.append(queryContent->value(0).toString());
|
||||||
|
}
|
||||||
|
this->isPending = false;
|
||||||
|
emit searchResultsReady(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SearchWorker::isOperationPending()
|
||||||
|
{
|
||||||
|
return this->isPending;
|
||||||
|
}
|
32
searchworker.h
Normal file
32
searchworker.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef SEARCHWORKER_H
|
||||||
|
#define SEARCHWORKER_H
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSqlDatabase>
|
||||||
|
#include <QSqlQuery>
|
||||||
|
#include <QString>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
class SearchWorker : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
QSqlQuery *queryFile;
|
||||||
|
QSqlQuery *queryContent;
|
||||||
|
bool isPending = false;
|
||||||
|
bool cancelCurrent = false;
|
||||||
|
public:
|
||||||
|
SearchWorker(const QString &dbpath);
|
||||||
|
bool isOperationPending();
|
||||||
|
void requestCancellation();
|
||||||
|
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void searchForFile(const QString &query);
|
||||||
|
void searchForContent(const QString &query);
|
||||||
|
signals:
|
||||||
|
void searchResultsReady(const QVector<QString> &results);
|
||||||
|
void searchCancelled();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SEARCHWORKER_H
|
423
window.cpp
Normal file
423
window.cpp
Normal file
@ -0,0 +1,423 @@
|
|||||||
|
#include "window.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QProcessEnvironment>
|
||||||
|
#include <QDirIterator>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QKeySequence>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QDate>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
Window::Window(const QVector<EntryConfig> &configs, const QString &dbpath)
|
||||||
|
{
|
||||||
|
this->userEntryButtons = generateEntryButtons(configs);
|
||||||
|
createGui();
|
||||||
|
populateGrid(this->userEntryButtons);
|
||||||
|
searchWorker = new SearchWorker(dbpath);
|
||||||
|
searchWorker->moveToThread(&searchThread);
|
||||||
|
connect(this, &Window::beginFileSearch, searchWorker, &SearchWorker::searchForFile);
|
||||||
|
connect(this, &Window::beginContentSearch, searchWorker, &SearchWorker::searchForContent);
|
||||||
|
connect(searchWorker, &SearchWorker::searchResultsReady, this, &Window::handleSearchResults);
|
||||||
|
searchThread.start();
|
||||||
|
initTreeWidgets();
|
||||||
|
this->lineEdit->installEventFilter(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::~Window()
|
||||||
|
{
|
||||||
|
searchThread.quit();
|
||||||
|
searchThread.wait();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::initTreeWidgets()
|
||||||
|
{
|
||||||
|
QStringList headers;
|
||||||
|
headers << "Filename";
|
||||||
|
headers << "Path";
|
||||||
|
headers << "Modification time";
|
||||||
|
treeFileSearchResults.setHeaderLabels(headers);
|
||||||
|
treeFileSearchResults.header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||||
|
connect(&treeFileSearchResults, &QTreeWidget::itemActivated, this, &Window::treeSearchItemActivated);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<EntryPushButton*> Window::generateEntryButtons(const QVector<EntryConfig> &configs)
|
||||||
|
{
|
||||||
|
QVector<EntryPushButton*> result;
|
||||||
|
for(const EntryConfig &config : configs)
|
||||||
|
{
|
||||||
|
EntryPushButton *button = createEntryButton(config);
|
||||||
|
result.append(button);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::createGui()
|
||||||
|
{
|
||||||
|
QVBoxLayout *vbox = new QVBoxLayout(this);
|
||||||
|
grid = new QGridLayout();
|
||||||
|
lineEdit = new QLineEdit();
|
||||||
|
vbox->setAlignment(Qt::AlignTop);
|
||||||
|
vbox->addWidget(lineEdit);
|
||||||
|
vbox->addLayout(grid);
|
||||||
|
connect(lineEdit, &QLineEdit::textChanged, this, [this](QString newtext) { this->lineEditTextChanged(newtext); });
|
||||||
|
connect(lineEdit, &QLineEdit::returnPressed, this, &Window::lineEditReturnPressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::populateGrid(const QVector<EntryPushButton *> &list)
|
||||||
|
{
|
||||||
|
clearGrid();
|
||||||
|
for(EntryPushButton *button : list)
|
||||||
|
{
|
||||||
|
button->setVisible(true);
|
||||||
|
grid->addWidget(button, button->getRow(), button->getCol());
|
||||||
|
buttonsInGrid.append(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::buttonClick(const EntryPushButton &config)
|
||||||
|
{
|
||||||
|
QProcess::startDetached(config.getCommand(), config.getArguments());
|
||||||
|
qApp->quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList Window::generatePATHSuggestions(const QString &text)
|
||||||
|
{
|
||||||
|
QStringList results;
|
||||||
|
QString pathVar = QProcessEnvironment::systemEnvironment().value("PATH", "/usr/bin/:/bin/:");
|
||||||
|
QStringList paths = pathVar.split(":");
|
||||||
|
for(const QString &path : paths)
|
||||||
|
{
|
||||||
|
QDirIterator it(path);
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
QFileInfo info(it.next());
|
||||||
|
if(info.isFile() && info.isExecutable())
|
||||||
|
{
|
||||||
|
QString entry = info.baseName();
|
||||||
|
if(entry.startsWith(text))
|
||||||
|
{
|
||||||
|
|
||||||
|
results.append(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::addPATHSuggestion(const QString &text)
|
||||||
|
{
|
||||||
|
QStringList suggestions = generatePATHSuggestions(text);
|
||||||
|
if(suggestions.length() == 1)
|
||||||
|
{
|
||||||
|
EntryConfig e;
|
||||||
|
e.name = suggestions[0];
|
||||||
|
e.col=0;
|
||||||
|
e.row=0;
|
||||||
|
e.command = suggestions[0];
|
||||||
|
e.icon = QIcon::fromTheme(suggestions[0]);
|
||||||
|
EntryPushButton *button = createEntryButton(e);
|
||||||
|
clearGrid();
|
||||||
|
grid->addWidget(button, 0, 0);
|
||||||
|
buttonsInGrid.append(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::clearGrid()
|
||||||
|
{
|
||||||
|
int count = grid->count();
|
||||||
|
for(int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
auto item = grid->itemAt(0)->widget();
|
||||||
|
grid->removeWidget(item);
|
||||||
|
item->setVisible(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
buttonsInGrid.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::addCalcResult(const QString &expression)
|
||||||
|
{
|
||||||
|
clearGrid();
|
||||||
|
QString calculationresult = calcEngine.evaluate(expression);
|
||||||
|
QLabel *lbl = new QLabel();
|
||||||
|
lbl->setText(expression + ": " + calculationresult);
|
||||||
|
lbl->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
lbl->setAlignment(Qt::AlignCenter);
|
||||||
|
lbl->setWordWrap(true);
|
||||||
|
QFont font;
|
||||||
|
font.setPointSize(48);
|
||||||
|
font.setBold(true);
|
||||||
|
lbl->setFont(font);
|
||||||
|
grid->addWidget(lbl, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//main problem here there is no easy event compression (clearing emit queue and only processing the last one)
|
||||||
|
void Window::lineEditTextChanged(QString text)
|
||||||
|
{
|
||||||
|
if(text.length() >= 2)
|
||||||
|
{
|
||||||
|
QString input = text.mid(1);
|
||||||
|
if(text[0] == '=')
|
||||||
|
{
|
||||||
|
|
||||||
|
addCalcResult(input);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(text[0] == '/')
|
||||||
|
{
|
||||||
|
if(searchWorker->isOperationPending())
|
||||||
|
{
|
||||||
|
this->queuedFileSearch = input;
|
||||||
|
searchWorker->requestCancellation();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->queuedFileSearch = "";
|
||||||
|
emit beginFileSearch(input);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(text[0] == '|')
|
||||||
|
{
|
||||||
|
if(searchWorker->isOperationPending())
|
||||||
|
{
|
||||||
|
this->queuedContentSearch = input;
|
||||||
|
searchWorker->requestCancellation();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->queuedContentSearch = "";
|
||||||
|
emit beginContentSearch(input);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterGridFor(text);
|
||||||
|
if(this->grid->count() == 0)
|
||||||
|
{
|
||||||
|
addPATHSuggestion(text);
|
||||||
|
if(this->grid->count() == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
QStringList arguments = text.split(" ");
|
||||||
|
EntryConfig e;
|
||||||
|
e.name = "Execute: " + text;
|
||||||
|
if(arguments.length() > 1)
|
||||||
|
{
|
||||||
|
e.arguments = arguments.mid(1);
|
||||||
|
}
|
||||||
|
e.command = arguments[0];
|
||||||
|
e.icon = QIcon::fromTheme("utilities-terminal");
|
||||||
|
|
||||||
|
EntryPushButton *button = createEntryButton(e);
|
||||||
|
clearGrid();
|
||||||
|
grid->addWidget(button, 0, 0);
|
||||||
|
buttonsInGrid.append(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::keyReleaseEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
if(event->key() == Qt::Key_Control)
|
||||||
|
{
|
||||||
|
for(EntryPushButton *button : buttonsInGrid)
|
||||||
|
{
|
||||||
|
button->showName();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
QWidget::keyReleaseEvent(event);
|
||||||
|
|
||||||
|
}
|
||||||
|
void Window::keyPressEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
bool quit = ((event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Q) || event->key() == Qt::Key_Escape);
|
||||||
|
if(quit)
|
||||||
|
{
|
||||||
|
qApp->quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event->modifiers() & Qt::ControlModifier && buttonsInGrid.count() > 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(event->key() == Qt::Key_L)
|
||||||
|
{
|
||||||
|
this->lineEdit->setFocus();
|
||||||
|
this->lineEdit->selectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for(EntryPushButton *button : buttonsInGrid)
|
||||||
|
{
|
||||||
|
button->showShortcut();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QKeySequence seq(event->key());
|
||||||
|
QString key = seq.toString().toLower();
|
||||||
|
|
||||||
|
auto it = std::find_if(userEntryButtons.begin(), userEntryButtons.end(), [&key](const EntryPushButton *y) { return y->getShortcutKey() == key; });
|
||||||
|
if(it != userEntryButtons.end())
|
||||||
|
{
|
||||||
|
buttonClick(**it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QWidget::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::filterGridFor(QString filter)
|
||||||
|
{
|
||||||
|
if(filter.length() > 0)
|
||||||
|
{
|
||||||
|
clearGrid();
|
||||||
|
bool userEntryMatch = false;
|
||||||
|
for(EntryPushButton *button : this->userEntryButtons)
|
||||||
|
{
|
||||||
|
if(button->getName().contains(filter, Qt::CaseInsensitive))
|
||||||
|
{
|
||||||
|
button->setVisible(true);
|
||||||
|
grid->addWidget(button, button->getRow(), button->getCol());
|
||||||
|
this->buttonsInGrid.append(button);
|
||||||
|
userEntryMatch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!userEntryMatch)
|
||||||
|
{
|
||||||
|
int currow = 0;
|
||||||
|
int curcol = 0;
|
||||||
|
int i = 1;
|
||||||
|
for(EntryPushButton *button : this->systemEntryButtons)
|
||||||
|
{
|
||||||
|
if(button->getName().contains(filter, Qt::CaseInsensitive))
|
||||||
|
{
|
||||||
|
button->setVisible(true);
|
||||||
|
button->setShortcut(QString::number(i++));
|
||||||
|
grid->addWidget(button, currow, curcol++);
|
||||||
|
this->buttonsInGrid.append(button);
|
||||||
|
if(curcol == 3)
|
||||||
|
{
|
||||||
|
curcol = 0;
|
||||||
|
++currow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
populateGrid(this->userEntryButtons);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EntryPushButton * Window::createEntryButton(const EntryConfig &entry)
|
||||||
|
{
|
||||||
|
EntryPushButton *button = new EntryPushButton(entry);
|
||||||
|
connect(button, &EntryPushButton::clicked, this, &Window::buttonClick);
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::lineEditReturnPressed()
|
||||||
|
{
|
||||||
|
if(buttonsInGrid.length() > 0 && this->lineEdit->text().length() > 0 )
|
||||||
|
{
|
||||||
|
buttonClick(*buttonsInGrid[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(this->isSearchMode())
|
||||||
|
{
|
||||||
|
treeSearchItemActivated(treeFileSearchResults.topLevelItem(0), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::setSystemConfig(const QVector<EntryConfig> &config)
|
||||||
|
{
|
||||||
|
this->systemEntryButtons = generateEntryButtons(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::handleSearchResults(const QVector<QString> &results)
|
||||||
|
{
|
||||||
|
clearGrid();
|
||||||
|
treeFileSearchResults.clear();
|
||||||
|
for(const QString &path : results)
|
||||||
|
{
|
||||||
|
QFileInfo pathInfo(path);
|
||||||
|
QString fileName =pathInfo.fileName();
|
||||||
|
QString absPath = path;
|
||||||
|
QString datestr = pathInfo.lastModified().toString(Qt::ISODate);
|
||||||
|
QTreeWidgetItem *item = new QTreeWidgetItem(&treeFileSearchResults);
|
||||||
|
item->setText(0, fileName);
|
||||||
|
item->setText(1, absPath);
|
||||||
|
item->setText(2, datestr);
|
||||||
|
|
||||||
|
}
|
||||||
|
treeFileSearchResults.resizeColumnToContents(0);
|
||||||
|
treeFileSearchResults.resizeColumnToContents(2);
|
||||||
|
treeFileSearchResults.setVisible(true);
|
||||||
|
|
||||||
|
this->grid->addWidget(&treeFileSearchResults, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::handleCancelledSearch()
|
||||||
|
{
|
||||||
|
if(this->queuedFileSearch != "")
|
||||||
|
{
|
||||||
|
QString searchFor = this->queuedFileSearch;
|
||||||
|
this->queuedFileSearch = "";
|
||||||
|
emit beginFileSearch(searchFor);
|
||||||
|
}
|
||||||
|
if(this->queuedContentSearch != "")
|
||||||
|
{
|
||||||
|
QString searchFor = this->queuedContentSearch;
|
||||||
|
this->queuedContentSearch = "";
|
||||||
|
emit beginContentSearch(searchFor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::treeSearchItemActivated(QTreeWidgetItem *item, int i)
|
||||||
|
{
|
||||||
|
qDebug() << item->text(1);
|
||||||
|
QDesktopServices::openUrl(QUrl::fromLocalFile(item->text(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Window::eventFilter(QObject *obj, QEvent *event)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(obj == this->lineEdit)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::KeyPress)
|
||||||
|
{
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||||
|
if(keyEvent->key() == Qt::Key_Tab)
|
||||||
|
{
|
||||||
|
QStringList suggestions = generatePATHSuggestions(this->lineEdit->text());
|
||||||
|
if(suggestions.length() == 1)
|
||||||
|
{
|
||||||
|
this->lineEdit->setText(suggestions[0] + " ");
|
||||||
|
this->lineEdit->setCursorPosition(this->lineEdit->text().length()+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return QObject::eventFilter(obj, event);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::isSearchMode()
|
||||||
|
{
|
||||||
|
QChar c = this->lineEdit->text()[0];
|
||||||
|
return c == '/' || c == '|';
|
||||||
|
}
|
68
window.h
Normal file
68
window.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#ifndef WINDOW_H
|
||||||
|
#define WINDOW_H
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QList>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QTreeWidget>
|
||||||
|
#include "config.h"
|
||||||
|
#include "entrypushbutton.h"
|
||||||
|
#include "calculationengine.h"
|
||||||
|
#include "searchworker.h"
|
||||||
|
|
||||||
|
class Window : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
QThread searchThread;
|
||||||
|
SearchWorker *searchWorker;
|
||||||
|
CalculationEngine calcEngine;
|
||||||
|
QVector<EntryPushButton*> userEntryButtons;
|
||||||
|
QVector<EntryPushButton*> systemEntryButtons;
|
||||||
|
QVector<EntryPushButton *> buttonsInGrid;
|
||||||
|
QTreeWidget treeFileSearchResults;
|
||||||
|
QString queuedFileSearch;
|
||||||
|
QString queuedContentSearch;
|
||||||
|
void createGui();
|
||||||
|
void filterGridFor(QString filter);
|
||||||
|
void populateGrid(const QVector<EntryPushButton *> &list);
|
||||||
|
void keyReleaseEvent(QKeyEvent *event);
|
||||||
|
QVector<EntryPushButton *> generateEntryButtons(const QVector<EntryConfig> &userEntryButtons);
|
||||||
|
void keyPressEvent(QKeyEvent *event);
|
||||||
|
void buttonClick(const EntryPushButton &config);
|
||||||
|
QLineEdit *lineEdit;
|
||||||
|
QGridLayout *grid;
|
||||||
|
EntryPushButton *createEntryButton(const EntryConfig &config);
|
||||||
|
void lineEditTextChanged(QString text);
|
||||||
|
void addPATHSuggestion(const QString &text);
|
||||||
|
void clearGrid();
|
||||||
|
void addCalcResult(const QString & expression);
|
||||||
|
void initTreeWidgets();
|
||||||
|
QStringList generatePATHSuggestions(const QString &text);
|
||||||
|
bool isSearchMode();
|
||||||
|
private slots:
|
||||||
|
void lineEditReturnPressed();
|
||||||
|
void handleSearchResults(const QVector<QString> &results);
|
||||||
|
void handleCancelledSearch();
|
||||||
|
void treeSearchItemActivated(QTreeWidgetItem *item, int i);
|
||||||
|
signals:
|
||||||
|
void beginFileSearch(const QString &query);
|
||||||
|
void beginContentSearch(const QString &query);
|
||||||
|
public:
|
||||||
|
Window(const QVector<EntryConfig> &userEntryButtons, const QString &dbpath);
|
||||||
|
void setSystemConfig(const QVector<EntryConfig> &config);
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event);
|
||||||
|
~Window();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Laden…
Verwijs in nieuw issue
Block a user