diff --git a/querying/CMakeLists.txt b/querying/CMakeLists.txt index 67a860a34ba7e4c3de4872a6b40c56d8bd81f01f..80325d48cbe97ea68d150be8f11ebe1a573cfe52 100644 --- a/querying/CMakeLists.txt +++ b/querying/CMakeLists.txt @@ -1,12 +1,46 @@ -cmake_minimum_required(VERSION 3.15) -project(Querying) +cmake_minimum_required(VERSION 3.0) set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_FLAGS "-g -Wall -pedantic -Wextra") +set(TARGET_NAME Querying) -add_executable(main +project(${TARGET_NAME}) + +# Check the build type and ask the user to set concrete one +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo) + message(WARNING "CMAKE_BUILD_TYPE is not set, forcing to RelWithDebInfo") +endif () + +# Set compiler flags +if (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU" OR ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") + set(CMAKE_CXX_FLAGS "-std=c++17 -Wall -Wextra") + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3") + set(CMAKE_CXX_FLAGS_RELEASE "-O3") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g3") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") +endif () + +find_package(Qt5Widgets REQUIRED) +find_package(Qt5Network REQUIRED) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# Instruct CMake to run moc automatically when needed +set(CMAKE_AUTOMOC ON) + +# Add subdirectory SQLiteCpp with all necessary files +add_subdirectory(lib/SQLiteCpp) + + +# Source files +set(SOURCES src/main.cpp + src/ui/forms/mainform.cpp + src/ui/widgets/textedit.cpp src/calculation/InvertedIndex.cpp src/calculation/InvertedIndex.h src/util/InvertedIndexJSONParser.cpp src/util/InvertedIndexJSONParser.h src/calculation/Space.cpp src/calculation/Space.h @@ -14,6 +48,37 @@ add_executable(main src/calculation/Computor.cpp src/calculation/Computor.h src/calculation/Document.cpp src/calculation/Document.h src/util/QueryJSONParser.cpp src/util/QueryJSONParser.h - src/exceptions/Exceptions.h) + src/exceptions/Exceptions.h + src/CollectionFetcher.cpp src/CollectionFetcher.h) + +# User interface files +set(FORMS + src/ui/forms/mainform.ui + ) + +# Resource files +set(RESOURCES + resources.qrc + ) + +# Shared libraries +set(LIBRARIES + Qt5::Widgets + Qt5::Network + SQLiteCpp + ) + +# Generate additional sources with MOC and UIC +qt5_wrap_ui(UIC_SOURCES ${FORMS}) +qt5_add_resources(RCC_SOURCES ${RESOURCES}) + +# Set target +add_executable(${TARGET_NAME} ${SOURCES} ${HEADERS} ${UIC_SOURCES} ${RCC_SOURCES}) + +# Link with libraries +target_link_libraries(${TARGET_NAME} ${LIBRARIES}) -target_link_libraries(main) +# Installation +install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION bin) +install(FILES resources/${TARGET_NAME}.png DESTINATION share/icons/hicolor/48x48/apps) +install(FILES ${TARGET_NAME}.desktop DESTINATION share/applications) diff --git a/querying/resources.qrc b/querying/resources.qrc new file mode 100644 index 0000000000000000000000000000000000000000..f71680fbb8074d60c5ed7bae63fb45082785f826 --- /dev/null +++ b/querying/resources.qrc @@ -0,0 +1,10 @@ +<RCC> + <qresource prefix="/"> + <file>resources/add-tab.png</file> + <file>resources/close-hover.png</file> + <file>resources/close.png</file> + <file>resources/main-icon.png</file> + <file>resources/swap.png</file> + <file>resources/settings.png</file> + </qresource> +</RCC> diff --git a/querying/resources/add-tab.png b/querying/resources/add-tab.png new file mode 100644 index 0000000000000000000000000000000000000000..5115b7169594979eb0861c9c800887f884dddb85 Binary files /dev/null and b/querying/resources/add-tab.png differ diff --git a/querying/resources/close-hover.png b/querying/resources/close-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..8a801d7b234c02cb5620259436a1ceacb16ace5b Binary files /dev/null and b/querying/resources/close-hover.png differ diff --git a/querying/resources/close.png b/querying/resources/close.png new file mode 100644 index 0000000000000000000000000000000000000000..04962ed0b24bde6525bdb740b9ab2a00419c616b Binary files /dev/null and b/querying/resources/close.png differ diff --git a/querying/resources/main-icon.png b/querying/resources/main-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b457af5274cb0d0cca7485c5c225e0f693bf082f Binary files /dev/null and b/querying/resources/main-icon.png differ diff --git a/querying/resources/settings.png b/querying/resources/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..c3b978f231ab4a2b45465df157919827507689b0 Binary files /dev/null and b/querying/resources/settings.png differ diff --git a/querying/resources/swap.png b/querying/resources/swap.png new file mode 100644 index 0000000000000000000000000000000000000000..61c63b0c8a66f86fef405a74f41ca2d762495252 Binary files /dev/null and b/querying/resources/swap.png differ diff --git a/querying/src/CollectionFetcher.cpp b/querying/src/CollectionFetcher.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c295cdb5573fbdf236da5b14fe7ba476c43974ce --- /dev/null +++ b/querying/src/CollectionFetcher.cpp @@ -0,0 +1,17 @@ +#include "CollectionFetcher.h" +#include <SQLiteCpp/SQLiteCpp.h> + +using namespace std; + +vector<string> CollectionFetcher::fetchCollection(const string &databasePath) { + SQLite::Database db(databasePath); + SQLite::Statement query(db, "SELECT filename FROM Document"); + + vector<string> result; + + while (query.executeStep()) + result.emplace_back(query.getColumn(0)); + + + return result; +} diff --git a/querying/src/CollectionFetcher.h b/querying/src/CollectionFetcher.h new file mode 100644 index 0000000000000000000000000000000000000000..7974e18101299981d5002ee78e5851ea3448c80b --- /dev/null +++ b/querying/src/CollectionFetcher.h @@ -0,0 +1,17 @@ +// +// Created by tomas on 3/31/20. +// + +#ifndef QUERYING_COLLECTIONFETCHER_H +#define QUERYING_COLLECTIONFETCHER_H + +#include <vector> +#include <string> + +class CollectionFetcher { +public: + static std::vector<std::string> fetchCollection(const std::string &databasePath); +}; + + +#endif //QUERYING_COLLECTIONFETCHER_H diff --git a/querying/src/main.cpp b/querying/src/main.cpp index 77aeb1416b8fb32964bab5ecc0200b2e5f514084..974544f4d72ab9095adb85483e94569ded99c11e 100644 --- a/querying/src/main.cpp +++ b/querying/src/main.cpp @@ -1,16 +1,25 @@ + #include <iostream> +#include <map> + +#include <QApplication> +#include "../lib/cxxopts.hpp" #include "calculation/Query.h" #include "calculation/Space.h" #include "calculation/Computor.h" -#include "../lib/cxxopts.hpp" #include "util/QueryJSONParser.h" #include "util/InvertedIndexJSONParser.h" +#include "src/ui/forms/mainform.h" +#include "CollectionFetcher.h" +static const int HELP_INDICATOR = 1; +static const int SUCCESS_INDICATOR = 0; +static const int FAILURE_INDICATOR = 2; using namespace std; using namespace cxxopts; -int main(int argc, char **argv) { +pair<int, string> parseArguments(int argc, char **argv) { Options options("Information retrieval - querying", "Queries against a collection."); options.add_options() ("c,collection", "Document collection", cxxopts::value<string>()) @@ -18,13 +27,52 @@ int main(int argc, char **argv) { auto result = options.parse(argc, argv); - if (result.count("help")) { - cout << options.help() << std::endl; - return EXIT_SUCCESS; - } + if (result.count("help")) + return {HELP_INDICATOR, options.help()}; if (!result.count("collection")) - return EXIT_FAILURE; + return {FAILURE_INDICATOR, ""}; + + return {SUCCESS_INDICATOR, result["collection"].as<string>()}; +} + +int main(int argc, char *argv[]) { + + auto arg = parseArguments(argc, argv); + switch (arg.first) { + case SUCCESS_INDICATOR: { + break; + } + case HELP_INDICATOR : { + cout << arg.second << endl; + return EXIT_SUCCESS; + + } + case FAILURE_INDICATOR: { + //todo error message + return EXIT_FAILURE; + } + } + + Space space(InvertedIndexJSONParser(arg.second).parse()); + + auto availableDocuments = CollectionFetcher::fetchCollection("../../data/persistence/docs_and_terms.db"); + + QApplication application(argc, argv); + + MainForm mainForm; + mainForm + .setAvailableDocuments(availableDocuments) + .setResults({"a", "b", "c"}) + .setOpenedDocument(availableDocuments[0]); + mainForm.show(); + + + return QApplication::exec(); +} + +/* +int main(int argc, char **argv) { auto collectionPath = result["collection"].as<string>(); Space space(InvertedIndexJSONParser(collectionPath).parse()); @@ -47,3 +95,4 @@ int main(int argc, char **argv) { return EXIT_SUCCESS; } +*/ diff --git a/querying/src/ui/forms/mainform.cpp b/querying/src/ui/forms/mainform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..204dc8d1b66203c8f8bcaa9e123e5443551a643d --- /dev/null +++ b/querying/src/ui/forms/mainform.cpp @@ -0,0 +1,101 @@ +#include "mainform.h" +#include "ui_mainform.h" + +#include <QMenu> +#include <QToolButton> +#include <QtCore/QFile> +#include <QtCore/QTextStream> + + +MainForm::MainForm(QWidget *parent) : + QMainWindow(parent), + UI(new Ui::MainForm), + documentsList(new QListWidget()), + resultsList(new QListWidget()), + openedDocument(new QTextBrowser()) { + setupUi(); +} + + +MainForm::~MainForm() { + delete UI; + delete documentsList; + delete resultsList; + delete openedDocument; +} + + +void MainForm::setupUi() { + UI->setupUi(this); + + setWindowIcon(QIcon(":/resources/main-icon.png")); + setWindowTitle("Querying: Vector model of information retrieval"); + + trayIcon.setIcon(QIcon(":/resources/main-icon.png")); + trayIcon.show(); + + connect(&trayIcon, + SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + SLOT(onTrayIconActivated(QSystemTrayIcon::ActivationReason))); + + UI->statusBar->hide(); + + UI->toolBar->setIconSize(QSize(24, 24)); + UI->toolBar->setFloatable(false); + UI->toolBar->setMovable(false); +} + + +void MainForm::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason) { + if (reason == QSystemTrayIcon::Trigger) { + setVisible(!isVisible()); + } else if (reason == QSystemTrayIcon::Context) { + QMenu menu; + + if (isVisible()) { + menu.addAction("Minimize", this, SLOT(hide())); + } else { + menu.addAction("Restore", this, SLOT(show())); + } + + menu.addAction(settingsAction); + + menu.addSeparator(); + menu.addAction("Quit", qApp, SLOT(quit())); + menu.exec(QCursor::pos()); + } +} + +MainForm &MainForm::setAvailableDocuments(const std::vector<std::string> &documents) { + QStringList dummy; + + for (const auto &doc : documents) + dummy.append(QString(doc.data())); + + UI->documentsList->addItems(dummy); + return *this; +} + +MainForm &MainForm::setResults(const std::vector<std::string> &results) { + QStringList dummy; + + for (const auto &result : results) + dummy.append(QString(result.data())); + + UI->resultsList->addItems(dummy); + + return *this; +} + +MainForm &MainForm::setOpenedDocument(const std::string &documentPath) { + QString path = QString::fromStdString(documentPath); + + QFile file(path); + + file.open(QIODevice::ReadOnly); + UI->documentBrowser->setText(QTextStream(&file).readAll()); + file.close(); + + + return *this; +} diff --git a/querying/src/ui/forms/mainform.h b/querying/src/ui/forms/mainform.h new file mode 100644 index 0000000000000000000000000000000000000000..e68b179b8d4968dbf43ba4115b6180ea38fed165 --- /dev/null +++ b/querying/src/ui/forms/mainform.h @@ -0,0 +1,51 @@ +#ifndef MAINFORM_H +#define MAINFORM_H + +#include <QMainWindow> +#include <QSystemTrayIcon> + +#include <string> +#include <vector> +#include <QtWidgets/QListView> +#include <QtCore/QStringListModel> +#include <QtWidgets/QListWidget> +#include <QtWidgets/QTextBrowser> + +namespace Ui { + class MainForm; +} + + +class MainForm : public QMainWindow { +Q_OBJECT +public: + explicit MainForm(QWidget *parent = nullptr); + + ~MainForm() override; + + MainForm &setAvailableDocuments(const std::vector<std::string> &documents); + + MainForm &setResults(const std::vector<std::string> &results); + + MainForm &setOpenedDocument(const std::string &documentPath); + +private: + Ui::MainForm *UI; + QSystemTrayIcon trayIcon; + + QAction *settingsAction; + + QListWidget *documentsList; + QListWidget *resultsList; + QTextBrowser *openedDocument; + + void setupUi(); + +private slots: + + void onTrayIconActivated(QSystemTrayIcon::ActivationReason reason); + +}; + + +#endif // MAINFORM_H diff --git a/querying/src/ui/forms/mainform.ui b/querying/src/ui/forms/mainform.ui new file mode 100644 index 0000000000000000000000000000000000000000..24e6779dd540cc38d12c07ae29ed78ec8ce5f8b3 --- /dev/null +++ b/querying/src/ui/forms/mainform.ui @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainForm</class> + <widget class="QMainWindow" name="MainForm"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>430</width> + <height>447</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainForm</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QVBoxLayout" name="horizontalLayout"> + <property name="leftMargin"> + <number>2</number> + </property> + <property name="topMargin"> + <number>2</number> + </property> + <property name="rightMargin"> + <number>2</number> + </property> + <property name="bottomMargin"> + <number>2</number> + </property> + <item> + <widget class="QListWidget" name="documentsList"/> + </item> + <item> + <widget class="QTextBrowser" name="documentBrowser"/> + </item> + <item> + <widget class="QListWidget" name="resultsList"/> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menuBar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>430</width> + <height>25</height> + </rect> + </property> + </widget> + <widget class="QToolBar" name="toolBar"> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + </widget> + <widget class="QStatusBar" name="statusBar"/> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources/> + <connections/> +</ui> diff --git a/querying/src/ui/widgets/textedit.cpp b/querying/src/ui/widgets/textedit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9cc63dd1ca13b0f7ab94d858e96adbd73ec1521 --- /dev/null +++ b/querying/src/ui/widgets/textedit.cpp @@ -0,0 +1,29 @@ +#include "textedit.h" + +#include <QDebug> +#include <QKeyEvent> + + +TextEdit::TextEdit(QWidget* parent) : + QPlainTextEdit(parent) +{ + +} + + +TextEdit::~TextEdit() +{ + +} + + +void TextEdit::keyPressEvent(QKeyEvent* e) +{ + if(e->key() == Qt::Key_Escape) { + clear(); + } + else { + QPlainTextEdit::keyPressEvent(e); + } +} + diff --git a/querying/src/ui/widgets/textedit.h b/querying/src/ui/widgets/textedit.h new file mode 100644 index 0000000000000000000000000000000000000000..ee3bae7f5c3cc086ca2791ebd30365ff5bad9f21 --- /dev/null +++ b/querying/src/ui/widgets/textedit.h @@ -0,0 +1,18 @@ +#ifndef TEXTEDIT_H +#define TEXTEDIT_H + +#include <QPlainTextEdit> + + +class TextEdit : public QPlainTextEdit { + Q_OBJECT +public: + TextEdit(QWidget* parent = nullptr); + ~TextEdit(); + +private: + void keyPressEvent(QKeyEvent* e); +}; + + +#endif // TEXTEDIT_H