diff --git a/CMakeLists.txt b/CMakeLists.txt index 11053b4..0edf84f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,18 +47,25 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ../build) # path/to/build_directory set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ../build) set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ ${CMAKE_EXE_LINKER_FLAGS}") - set(CMAKE_CXX_LINKER_FLAGS "-static-libgcc -static-libstdc++ ${CMAKE_CXX_LINKER_FLAGS}") set(CMAKE_SHARED_LIBRARY_PREFIX "") +list(APPEND CMAKE_PREFIX_PATH "${QT5_DIR}") +list(APPEND CMAKE_PREFIX_PATH "${OPEN_XLSX_DIR}") + set(QT_COMPONENTS Core Gui Widgets Sql PrintSupport Network) find_package( - Qt5 - COMPONENTS - ${QT_COMPONENTS} - REQUIRED + Qt5 + COMPONENTS + ${QT_COMPONENTS} + REQUIRED +) + +find_package( + OpenXLSX + REQUIRED ) function(find_files dir type result) @@ -71,57 +78,48 @@ find_files(${UI_DIRECTORY} "ui" UI_FILES) include_directories(source) -add_library( - image_downloader SHARED - source/services/image-downloader/image_downloader.cpp -) - set(CONSOLE_FLAG) if (${CMAKE_BUILD_TYPE} MATCHES "Release") set(CONSOLE_FLAG WIN32) endif () add_executable( - ${PROJECT_NAME} - ${CONSOLE_FLAG} - source/main.cpp - source/interfaces/font-editor/font_editor.cpp - source/interfaces/font-editor/font_editor.h - source/interfaces/options/options.cpp - source/interfaces/options/options.h - source/interfaces/mainwindow/mainwindow.cpp - source/interfaces/mainwindow/mainwindow.h - source/interfaces/text-position-selector/text_position_selector.cpp - source/interfaces/text-position-selector/text_position_selector.h - source/interfaces/database-settings/database_settings.cpp - source/interfaces/database-settings/database_settings.h - source/interfaces/password-form/password_form.cpp - source/interfaces/password-form/password_form.h - source/interfaces/records-amount-form/records_amount_form.cpp - source/interfaces/records-amount-form/records_amount_form.h - ${UI_FILES} - source/services/settings/settings_manager.cpp - source/services/text-painter/text_painter.cpp - source/services/theme-loader/theme_loader.cpp - source/services/image-printer/image_printer.cpp - source/resources/icon.rc + ${PROJECT_NAME} + ${CONSOLE_FLAG} + source/main.cpp + source/interfaces/font-editor/font_editor.cpp + source/interfaces/font-editor/font_editor.h + source/interfaces/options/options.cpp + source/interfaces/options/options.h + source/interfaces/mainwindow/mainwindow.cpp + source/interfaces/mainwindow/mainwindow.h + source/interfaces/text-position-selector/text_position_selector.cpp + source/interfaces/text-position-selector/text_position_selector.h + source/interfaces/database-settings/database_settings.cpp + source/interfaces/database-settings/database_settings.h + source/interfaces/password-form/password_form.cpp + source/interfaces/password-form/password_form.h + source/interfaces/records-amount-form/records_amount_form.cpp + source/interfaces/records-amount-form/records_amount_form.h + ${UI_FILES} + source/services/settings/settings_manager.cpp + source/services/text-painter/text_painter.cpp + source/services/theme-loader/theme_loader.cpp + source/services/image-printer/image_printer.cpp + source/resources/icon.rc ) target_link_libraries( - image_downloader - PUBLIC - Qt5::Network -) - -target_link_libraries( - ${PROJECT_NAME} - PUBLIC - Qt5::Core - Qt5::Gui - Qt5::Widgets - Qt5::Sql - Qt5::PrintSupport - image_downloader + ${PROJECT_NAME} + PUBLIC + Qt5::Core + Qt5::Gui + Qt5::Widgets + Qt5::Sql + Qt5::PrintSupport + Qt5::Network + + OpenXLSX::OpenXLSX ) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) @@ -129,11 +127,19 @@ set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC ON AUTORCC ON AUTOUIC O # Копирование содержимого папки reference в build add_custom_command( - TARGET ${PROJECT_NAME} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/build_folder_reference/ - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + TARGET ${PROJECT_NAME} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/build_folder_reference/ + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} +) + +add_custom_command( + TARGET ${PROJECT_NAME} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${OPEN_XLSX_DIR}/bin/libOpenXLSX.dll" + + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) # Qt autoDLL @@ -142,7 +148,7 @@ if (WIN32 AND NOT DEFINED CMAKE_TOOLCHAIN_FILE) if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug") set(DEBUG_SUFFIX "d") endif () - set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}") + set(QT_INSTALL_PATH ${QT5_DIR}) if (NOT EXISTS "${QT_INSTALL_PATH}/bin") set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..") if (NOT EXISTS "${QT_INSTALL_PATH}/bin") @@ -151,38 +157,53 @@ if (WIN32 AND NOT DEFINED CMAKE_TOOLCHAIN_FILE) endif () if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll") add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory - "$/plugins/platforms/") + COMMAND ${CMAKE_COMMAND} -E make_directory + "$/plugins/platforms/") add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll" - "$/plugins/platforms/") + COMMAND ${CMAKE_COMMAND} -E copy + "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll" + "$/plugins/platforms/") endif () if (EXISTS "${QT_INSTALL_PATH}/plugins/sqldrivers/qsqlpsql${DEBUG_SUFFIX}.dll") add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory - "$/plugins/sqldrivers/") + COMMAND ${CMAKE_COMMAND} -E make_directory + "$/plugins/sqldrivers/") add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - "${QT_INSTALL_PATH}/plugins/sqldrivers/qsqlpsql${DEBUG_SUFFIX}.dll" - "$/plugins/sqldrivers/") + COMMAND ${CMAKE_COMMAND} -E copy + "${QT_INSTALL_PATH}/plugins/sqldrivers/qsqlpsql${DEBUG_SUFFIX}.dll" + "$/plugins/sqldrivers/") add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - "${QT_INSTALL_PATH}/plugins/printsupport" - "$/plugins/printsupport") + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${QT_INSTALL_PATH}/plugins/printsupport" + "$/plugins/printsupport") endif () + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + "${QT_INSTALL_PATH}/plugins/imageformats/qjpeg.dll" + "$/plugins/imageformats/qjpeg.dll" + ) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + "${QT_INSTALL_PATH}/plugins/imageformats/qwbmp.dll" + "$/plugins/imageformats/qwbmp.dll" + ) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + "${QT_INSTALL_PATH}/plugins/imageformats/qwebp.dll" + "$/plugins/imageformats/qwebp.dll" + ) foreach (QT_LIB ${QT_COMPONENTS}) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - "${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}${DEBUG_SUFFIX}.dll" - "$") + COMMAND ${CMAKE_COMMAND} -E copy + "${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}${DEBUG_SUFFIX}.dll" + "$") endforeach (QT_LIB) - if (DEFINED DEPLOY_DEPENDENCY) + if (DEFINED DEPLOY_DEPENDENCY) set(DEPLOY_COMMAND deployment/deploy_windows.bat ${DEPLOY_DEPENDENCY}) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${DEPLOY_COMMAND} - COMMENT "Running Inno Setup Compiler" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${DEPLOY_COMMAND} + COMMENT "Running Inno Setup Compiler" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) endif () endif () diff --git a/README.md b/README.md index 76b4be8..a298fc2 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ 1. Install Cmake 2. Download & Install **[Qt5][4]** 3. ```sh - cmake -DCMAKE_BUILD_TYPE={type} -DCMAKE_PREFIX_PATH=path/to/Qt5 -G {generator} -B ./cmake-build-{type} + cmake -DCMAKE_BUILD_TYPE={type} -QT5_DIR=path/to/Qt5 -DOPEN_XLSX_DIR=path/to/OpenXLSX -G {generator} -B ./cmake-build-{type} cmake --build ./cmake-build-{type} --target TIP -j 14 ``` @@ -32,7 +32,7 @@ 2. Install **[Inno Download Plugin][6]** 3. To activate deployment mode, add the following flag to the CMake configuration: ```sh - cmake -DCMAKE_BUILD_TYPE={type} -DCMAKE_PREFIX_PATH=path/to/Qt5 "-DDEPLOY_DEPENDENCY=\"path/to/idp.iss\"" -G {generator} -B ./cmake-build-{type} + cmake -DCMAKE_BUILD_TYPE={type} -QT5_DIR=path/to/Qt5 -DOPEN_XLSX_DIR=path/to/OpenXLSX "-DDEPLOY_DEPENDENCY=\"path/to/idp.iss\"" -G {generator} -B ./cmake-build-{type} cmake --build ./cmake-build-{type} --target TIP -j 14 ``` or run [windows_deploy.bat][8] after building the project and enter `"path/to/idp.iss"` as an argument. diff --git a/build_folder_reference/settings/settings.ini b/build_folder_reference/settings/settings.ini deleted file mode 100644 index ef64603..0000000 --- a/build_folder_reference/settings/settings.ini +++ /dev/null @@ -1,11 +0,0 @@ -[general] -path_to=default -theme=Darkeum - -[database] -host=localhost -port=5432 -username=postgres -password=root -name=tip -schema=main diff --git a/deployment/database/insert_default_records.sql b/deployment/database/insert_default_records.sql index b65e021..afb510b 100644 --- a/deployment/database/insert_default_records.sql +++ b/deployment/database/insert_default_records.sql @@ -20,5 +20,5 @@ VALUES (DEFAULT, 'Arial', '#000000', 0, 0, 50, false), (DEFAULT, 'Arial', '#000000', 100, 100, 50, false), (DEFAULT, 'Arial', '#000000', 200, 200, 50, false); -INSERT INTO main.image (url, id, format) -VALUES (null, DEFAULT, null); \ No newline at end of file +INSERT INTO main.image (base64, id) +VALUES (null, DEFAULT); \ No newline at end of file diff --git a/deployment/database/tables_creation.sql b/deployment/database/tables_creation.sql index f4d38d0..dac9c18 100644 --- a/deployment/database/tables_creation.sql +++ b/deployment/database/tables_creation.sql @@ -30,11 +30,10 @@ create table if not exists main.font_settings create table if not exists main.image ( - url text, + base64 bytea, id serial constraint image_pk primary key, - format text ); create table if not exists main.advanced_settings_passwords diff --git a/deployment/windows_installer/tip_setup_offline.iss b/deployment/windows_installer/tip_setup_offline.iss index a7aa207..326ad3d 100644 --- a/deployment/windows_installer/tip_setup_offline.iss +++ b/deployment/windows_installer/tip_setup_offline.iss @@ -16,7 +16,7 @@ ; along with this program. If not, see . #define MyAppName "TIP" -#define MyAppVersion "8.0" +#define MyAppVersion "8.1" #define MyAppPublisher "Pavel Remdenok" #define MyAppURL "https://github.com/pavel-cpp" #define MyAppExeName "TIP.exe" diff --git a/deployment/windows_installer/tip_setup_online.iss b/deployment/windows_installer/tip_setup_online.iss index ad5ea1c..e289411 100644 --- a/deployment/windows_installer/tip_setup_online.iss +++ b/deployment/windows_installer/tip_setup_online.iss @@ -16,7 +16,7 @@ ; along with this program. If not, see . #define MyAppName "TIP" -#define MyAppVersion "8.0" +#define MyAppVersion "8.1" #define MyAppPublisher "Pavel Remdenok" #define MyAppURL "https://github.com/pavel-cpp" #define MyAppExeName "TIP.exe" diff --git a/source/interfaces/mainwindow/mainwindow.cpp b/source/interfaces/mainwindow/mainwindow.cpp index 891e6bc..cfa2c9b 100644 --- a/source/interfaces/mainwindow/mainwindow.cpp +++ b/source/interfaces/mainwindow/mainwindow.cpp @@ -21,7 +21,6 @@ #include // Services -#include #include #include @@ -31,22 +30,25 @@ // Qt #include +#include #include #include #include +#include #include #include -#include +// XLSX +#include QString operator ""_qs(const char *text, size_t len) { return {text}; } MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent), ui(std::make_unique()), - settings_manager_("mainwindow"), - database_(settings_manager_.GetSettings().database) { + : QMainWindow(parent), ui(std::make_unique()), + settings_manager_("mainwindow"), + database_(settings_manager_.GetSettings().database) { ui->setupUi(this); this->setStyleSheet(Theme::Load(settings_manager_.GetSettings().theme)); @@ -70,10 +72,18 @@ MainWindow::MainWindow(QWidget *parent) log_.Info("DatabaseModel table_model_ initialized"); - connect(table_model_.get(), SIGNAL(dataChanged( - const QModelIndex &, const QModelIndex &, const QVector &)), - this, SLOT(database_table_view_data_changed( - const QModelIndex&))); + connect( + table_model_.get(), + SIGNAL( + dataChanged( + const QModelIndex &, const QModelIndex &, const QVector &) + ), + this, + SLOT( + database_table_view_data_changed( + const QModelIndex&) + ) + ); ui->database_table_view->setModel(table_model_.get()); ui->database_table_view->setColumnHidden(0, true); @@ -81,31 +91,13 @@ MainWindow::MainWindow(QWidget *parent) ui->database_table_view->addActions(ui->menubar->actions()); - if (!ImageDownloader::FetchImage( - settings_manager_.GetSettings().consts.source_image_path + "." + - settings_manager_.GetSettings().image.format, - settings_manager_.GetSettings().image.url - )) { - QMessageBox::warning(this, "Предупреждение!", "Не удалось загрузить изображение!\nНе верно указана ссылка"); - } - - QImage image; - - if (!image.load(settings_manager_.GetSettings().consts.source_image_path + "." + - settings_manager_.GetSettings().image.format)) { - QMessageBox::warning(this, "Предупреждение!", - "Не удалось открыть изображение!\nНе верно указан формат изображения или ссылка" ); - } - - text_painter_.SetImage( - image - ); + text_painter_.SetImage(settings_manager_.GetSettings().image); for (int i = 0; i < 3; ++i) { items_[i].options = settings_manager_.GetSettings().font_settings[i]; } - for (const auto &item: items_) { + for (const auto& item : items_) { text_painter_.DrawText(item); } @@ -147,16 +139,17 @@ void MainWindow::on_save_image_triggered() { return; } bool status = text_painter_.GetResultImage().save( - settings_manager_.GetSettings().output_folder - + "/image_" - + items_[0].content - + "." - + settings_manager_.GetSettings().image.format + settings_manager_.GetSettings().output_folder + + "/image_" + + items_[0].content + + ".jpeg" ); if (status) { - ui->statusbar->showMessage("image_" - + items_[0].content - + " успешно сохранена!"); + ui->statusbar->showMessage( + "image_" + + items_[0].content + + " успешно сохранена!" + ); } else { ui->statusbar->showMessage("Ошибка сохранения картинки!"); } @@ -176,26 +169,32 @@ void MainWindow::on_print_triggered() { log_.Info("Printer rejected"); return; } - ImagePrinter image_printer({ImagePrinter::FromCentimetersToPixels(7, printer.resolution()), - ImagePrinter::FromCentimetersToPixels(4, printer.resolution())}, - &printer); - for (const auto &index: indexes) { - + ImagePrinter image_printer( + { + ImagePrinter::FromCentimetersToPixels(7, printer.resolution()), + ImagePrinter::FromCentimetersToPixels(4, printer.resolution()) + }, + &printer + ); + for (const auto& index : indexes) { table_model_->setData( - table_model_->index(index.row(), table_model_->fieldIndex("status")), - true, - Qt::EditRole + table_model_->index(index.row(), table_model_->fieldIndex("status")), + true, + Qt::EditRole ); if (!table_model_->submit()) { - QMessageBox::critical(this, "Ошибка!", - "Ошибка при отправке изменений в базу данных:" + table_model_->lastError().text()); + QMessageBox::critical( + this, + "Ошибка!", + "Ошибка при отправке изменений в базу данных:" + table_model_->lastError().text() + ); break; } SetContents(index); text_painter_.Clear(); - for (const auto &item: items_) { + for (const auto& item : items_) { text_painter_.DrawText(item); } @@ -204,7 +203,7 @@ void MainWindow::on_print_triggered() { log_.Info("Print started"); } -void MainWindow::on_database_table_view_clicked(const QModelIndex &index) { +void MainWindow::on_database_table_view_clicked(const QModelIndex& index) { log_.Info("On table clicked"); SetContents(index); ReDrawImage(); @@ -276,32 +275,35 @@ void MainWindow::on_save_some_images_triggered() { ui->progress_bar->setVisible(true); int progress_index = 0; - for (const auto &selected_row: selected_rows) { + for (const auto& selected_row : selected_rows) { ui->progress_bar->setValue(progress_index); QCoreApplication::processEvents(); SetContents(selected_row); text_painter_.Clear(); - for (const auto &item: items_) { + for (const auto& item : items_) { text_painter_.DrawText(item); } if (text_painter_.GetResultImage().save( - settings_manager_.GetSettings().output_folder - + "/image_" - + items_[0].content - + "." - + settings_manager_.GetSettings().image.format + settings_manager_.GetSettings().output_folder + + "/image_" + + items_[0].content + + ".jpeg" )) { - ui->statusbar->showMessage("image_" - + items_[0].content - + " успешно сохранена!"); + ui->statusbar->showMessage( + "image_" + + items_[0].content + + " успешно сохранена!" + ); ++progress_index; } else { - ui->statusbar->showMessage("image_" - + items_[0].content - + " не сохранена!"); + ui->statusbar->showMessage( + "image_" + + items_[0].content + + " не сохранена!" + ); } } @@ -317,13 +319,46 @@ void MainWindow::on_save_some_images_triggered() { void MainWindow::ReDrawImage() { text_painter_.Clear(); - for (const auto &item: items_) { + for (const auto& item : items_) { text_painter_.DrawText(item); } ui->screen->setPixmap(text_painter_.GetResultPixmap().scaled(current_image_size_, Qt::KeepAspectRatioByExpanding)); } -void MainWindow::database_table_view_data_changed(const QModelIndex &index) { +void MainWindow::on_export_database_triggered() { + QFileInfo file_info = QFileDialog::getSaveFileName( + this, + tr("Экспортировать"), + "", + "Excel(*.xlsx);" + ); + if(file_info.absoluteFilePath().isEmpty()) { + return; + } + try { + OpenXLSX::XLDocument document; + document.create(file_info.absoluteFilePath().toStdString()); + document.workbook().addWorksheet("Report"); + document.workbook().deleteSheet("Sheet1"); + auto worksheet = document.workbook().worksheet("Report"); + + size_t rows = table_model_->rowCount(); + size_t cols = table_model_->columnCount(); + for (size_t row = 0; row < rows; ++row) { + for (size_t col = 0; col < cols; ++col) { + worksheet.cell(row + 1, col + 1).value() = table_model_->index(row, col).data().toString().toStdString(); + } + } + + document.save(); + ui->statusbar->showMessage("Таблица успешно экспортирована"); + } catch (const std::exception& e) { + // Обработать исключение (например, показать сообщение об ошибке) + QMessageBox::warning(this, "Ошибка!", tr("Ошибка: ") + e.what()); + } +} + +void MainWindow::database_table_view_data_changed(const QModelIndex& index) { table_model_->submit(); table_model_->select(); SetContents(index); @@ -349,8 +384,11 @@ void MainWindow::on_insert_same_records_triggered() { ui->progress_bar->setMaximum(amount - 1); ui->progress_bar->setVisible(true); for (int i = 0; i < amount; ++i) { - query.exec(QString("INSERT INTO %1.clients (name, phone_number, status) VALUES ('', '', false);").arg( - database_.schema)); + query.exec( + QString("INSERT INTO %1.clients (name, phone_number, status) VALUES ('', '', false);").arg( + database_.schema + ) + ); ui->progress_bar->setValue(i); QCoreApplication::processEvents(); } @@ -360,31 +398,35 @@ void MainWindow::on_insert_same_records_triggered() { } } -void MainWindow::SetContents(const QModelIndex &index) { +void MainWindow::SetContents(const QModelIndex& index) { for (int i = 0; i < 3; ++i) { items_[i].content = table_model_->index(index.row(), i).data().toString(); } } void MainWindow::on_clear_database_triggered() { - if (PasswordForm(settings_manager_.GetSettings().passwords, this).exec() != QDialog::Accepted){ + if (PasswordForm(settings_manager_.GetSettings().passwords, this).exec() != QDialog::Accepted) { return; } QSqlQuery query(database_.db); QString drop_table("DROP TABLE IF EXISTS %1.%2;"); - QString create_table("CREATE TABLE IF NOT EXISTS %1.%2\n" - "(\n" - " ID SERIAL\n" - " PRIMARY KEY,\n" - " name VARCHAR(255),\n" - " phone_number VARCHAR(255),\n" - " status BOOLEAN DEFAULT false\n" - ");"); + QString create_table( + "CREATE TABLE IF NOT EXISTS %1.%2\n" + "(\n" + " ID SERIAL\n" + " PRIMARY KEY,\n" + " name VARCHAR(255),\n" + " phone_number VARCHAR(255),\n" + " status BOOLEAN DEFAULT false\n" + ");" + ); query.exec(drop_table.arg(database_.schema).arg("clients_backup")); query.exec(create_table.arg(database_.schema).arg("clients_backup")); - query.exec("INSERT INTO %1.clients_backup (id, name, phone_number, status) " - "SELECT * FROM %1.clients"_qs.arg(database_.schema)); + query.exec( + "INSERT INTO %1.clients_backup (id, name, phone_number, status) " + "SELECT * FROM %1.clients"_qs.arg(database_.schema) + ); query.exec(drop_table.arg(database_.schema).arg("clients")); query.exec(create_table.arg(database_.schema).arg("clients")); diff --git a/source/interfaces/mainwindow/mainwindow.h b/source/interfaces/mainwindow/mainwindow.h index 1ec71d7..c6e9f73 100644 --- a/source/interfaces/mainwindow/mainwindow.h +++ b/source/interfaces/mainwindow/mainwindow.h @@ -152,6 +152,8 @@ private slots: */ void on_clear_database_triggered(); + void on_export_database_triggered(); + /** * @brief Slot for handling changes in the database table view data. * diff --git a/source/interfaces/options/options.cpp b/source/interfaces/options/options.cpp index e5736b4..828b97e 100644 --- a/source/interfaces/options/options.cpp +++ b/source/interfaces/options/options.cpp @@ -62,8 +62,6 @@ Options::Options(QWidget *parent) : ui->example_3->setStyleSheet(QString("color: %1;\nfont-size: %2px;").arg( settings_buffer_.font_settings[2].color.name(QColor::HexRgb)).arg( settings_buffer_.font_settings[2].font.pixelSize())); - ui->image_url_edit->setText(settings_buffer_.image.url.toString()); - ui->image_format_edit->setText(settings_buffer_.image.format); SetAdvancedSettingsVisible(false); } @@ -137,7 +135,7 @@ void Options::on_database_edit_button_clicked() { } void Options::on_save_button_clicked() { - if (settings_manager_.GetSettings().image.url != settings_buffer_.image.url || + if (settings_manager_.GetSettings().image != settings_buffer_.image || settings_manager_.GetSettings().database.host != settings_buffer_.database.host || settings_manager_.GetSettings().database.port != settings_buffer_.database.port || settings_manager_.GetSettings().database.schema != settings_buffer_.database.schema) { @@ -148,21 +146,32 @@ void Options::on_save_button_clicked() { close(); } +void Options::on_upload_button_clicked() { + QString path = QFileDialog::getOpenFileName( + this, + "Загрузить изображение", + QDir::homePath(), + "All files(*.*);;" + "JPEG(*.jpg *.jpeg);;" + "PNG(*.png);;" + "BITMAP(*.bmp);;" + "WEBP(*.webp)" + ); + if (path.isEmpty()) { + return; + } + if (!settings_buffer_.image.load(path)) { + QMessageBox::critical(this, "Ошибка", "Файл не загружен." + "\nНе верно указан путь." + "\nИли не верное имя файла."); + }; +} + void Options::on_path_to_edit_textChanged(const QString &text) { settings_buffer_.output_folder = text; save_type_ |= SettingsManager::SaveType::SAVE_GENERAL; } -void Options::on_image_url_edit_textChanged(const QString &text) { - settings_buffer_.image.url = text; - save_type_ |= SettingsManager::SaveType::SAVE_SYNCING; -} - -void Options::on_image_format_edit_textChanged(const QString &text) { - settings_buffer_.image.format = text; - save_type_ |= SettingsManager::SaveType::SAVE_SYNCING; -} - void Options::SetAdvancedSettingsVisible(bool state) { ui->formatting_label->setVisible(state); ui->formatting_line->setVisible(state); @@ -185,10 +194,7 @@ void Options::SetAdvancedSettingsVisible(bool state) { ui->image_line->setVisible(state); ui->image_label->setVisible(state); - ui->image_format_label->setVisible(state); - ui->image_format_edit->setVisible(state); - ui->image_url_label->setVisible(state); - ui->image_url_edit->setVisible(state); + ui->upload_button->setVisible(state); } void Options::on_advanced_settings_button_clicked() { diff --git a/source/interfaces/options/options.h b/source/interfaces/options/options.h index 939bc42..2d0a194 100644 --- a/source/interfaces/options/options.h +++ b/source/interfaces/options/options.h @@ -106,18 +106,9 @@ private slots: void on_save_button_clicked(); /** - * @brief Slot for handling changes in the image_url_edit field. - * - * @param text The new text in the image_url_edit field. - */ - void on_image_url_edit_textChanged(const QString &text); - - /** - * @brief Slot for handling changes in the image_format_edit field. - * - * @param text The new text in the image_format_edit field. + * @brief Slot for handling the upload_button click event. */ - void on_image_format_edit_textChanged(const QString &text); + void on_upload_button_clicked(); /** * @brief Slot for handling the advanced_settings_button click event. diff --git a/source/services/database/models.h b/source/services/database/models.h index e2570d7..e7b23b5 100644 --- a/source/services/database/models.h +++ b/source/services/database/models.h @@ -22,5 +22,4 @@ // Local #include "models/database_options_model.h" #include "models/font_settings_model.h" -#include "models/image_model.h" #include "models/passwords_model.h" diff --git a/source/services/database/models/image_model.h b/source/services/database/models/image_model.h deleted file mode 100644 index 087ba05..0000000 --- a/source/services/database/models/image_model.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - "Text Insertion Program (TIP)" is a software - for client management and generating unique images for each client. - Copyright (C) 2024 Pavel Remdenok - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#pragma once - -// Qt -#include - -namespace Models { - struct Image { - QUrl url; - QString format; - }; -} diff --git a/source/services/image-downloader/image_downloader.cpp b/source/services/image-downloader/image_downloader.cpp deleted file mode 100644 index bc93017..0000000 --- a/source/services/image-downloader/image_downloader.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - "Text Insertion Program (TIP)" is a software - for client management and generating unique images for each client. - Copyright (C) 2024 Pavel Remdenok - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "image_downloader.h" - -// Qt -#include -#include - -// QtNetwork -#include -#include -#include - -bool ImageDownloader::FetchImage(const QString &path, const QUrl &url) { - QNetworkAccessManager manager; - QNetworkRequest request(url); - - QNetworkReply *reply = manager.get(request); - - QEventLoop loop; - QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); - - if (reply->error() == QNetworkReply::NoError) { - QFile file(path); - if (file.open(QIODevice::WriteOnly)) { - file.write(reply->readAll()); - file.close(); - } else { - return false; - } - } else { - return false; - } - - reply->deleteLater(); - return true; -} - diff --git a/source/services/image-downloader/image_downloader.h b/source/services/image-downloader/image_downloader.h deleted file mode 100644 index 1c8b23b..0000000 --- a/source/services/image-downloader/image_downloader.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - "Text Insertion Program (TIP)" is a software - for client management and generating unique images for each client. - Copyright (C) 2024 Pavel Remdenok - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#pragma once - -// Qt -#include -#include - -/** - * @class ImageDownloader - * @brief The ImageDownloader class provides a static method for downloading images. - * - * This class provides a static method for downloading images from a given URL and saving them to a specified path. - */ -class ImageDownloader { -public: - /** - * @brief Fetch an image from a URL and save it to a specified path. - * - * @param path The path where the image will be saved. - * @param url The URL from which the image will be downloaded. - * @return true if the image was successfully downloaded and saved, false otherwise. - */ - static bool FetchImage(const QString &path, const QUrl &url); -}; \ No newline at end of file diff --git a/source/services/image-printer/image_printer.cpp b/source/services/image-printer/image_printer.cpp index 51d65fa..19f7f98 100644 --- a/source/services/image-printer/image_printer.cpp +++ b/source/services/image-printer/image_printer.cpp @@ -19,6 +19,8 @@ #include "image_printer.h" +#include + ImagePrinter::ImagePrinter(QSize size_of_images, QPrinter *printer) : frame_(SPACING, SPACING, size_of_images.width(), size_of_images.height()), printer_(printer), diff --git a/source/services/settings/settings_manager.cpp b/source/services/settings/settings_manager.cpp index c34bf77..348a565 100644 --- a/source/services/settings/settings_manager.cpp +++ b/source/services/settings/settings_manager.cpp @@ -19,6 +19,10 @@ #include "settings_manager.h" +#include +#include +#include +#include #include #include #include @@ -28,7 +32,9 @@ using std::string; // Qt #include -SettingsManager::SettingsManager(const QString &connection_name) { +constexpr char EXTENSION[] = "WEBP"; + +SettingsManager::SettingsManager(const QString& connection_name) { LoadFromIni(connection_name); LoadFromDatabase(); } @@ -37,12 +43,12 @@ SettingsManager::Settings SettingsManager::GetSettings() { return settings_; } -void SettingsManager::SetSettings(const SettingsManager::Settings &settings) { +void SettingsManager::SetSettings(const SettingsManager::Settings& settings) { settings_ = settings; } void SettingsManager::Save(int type) { - if(type == SaveType::SAVE_NONE){ + if (type == SaveType::SAVE_NONE) { return; } if (~(type ^ SaveType::SAVE_GENERAL)) { @@ -61,7 +67,7 @@ void SettingsManager::Save(int type) { settings_file_.save(SETTINGS_FILE_PATH_); - if(!(~(type ^ SaveType::SAVE_SYNCING))){ + if (!(~(type ^ SaveType::SAVE_SYNCING))) { return; } database_.db.open(); @@ -75,31 +81,32 @@ void SettingsManager::Save(int type) { { QSqlQuery query(database_.db); QString sql_request = UPDATE_FONT_SETTINGS.arg(database_.schema); - for (const auto &font: settings_.font_settings) { + for (const auto& font : settings_.font_settings) { query.prepare( - sql_request - .arg("\'" + font.font.family() + "\'") - .arg("\'" + font.color.name(QColor::HexRgb) + "\'") - .arg(font.position.x()) - .arg(font.position.y()) - .arg(font.font.pixelSize()) - .arg(font.font.bold() ? "true" : "false") - .arg(index++) + sql_request + .arg("\'" + font.font.family() + "\'") + .arg("\'" + font.color.name(QColor::HexRgb) + "\'") + .arg(font.position.x()) + .arg(font.position.y()) + .arg(font.font.pixelSize()) + .arg(font.font.bold() ? "true" : "false") + .arg(index++) ); query.exec(); } + QByteArray image_as_bytes; + QBuffer buffer(&image_as_bytes); + buffer.open(QIODevice::WriteOnly); + settings_.image.save(&buffer, EXTENSION); query.prepare( - UPDATE_IMAGE - .arg(database_.schema) - .arg("\'" + settings_.image.url.toString() + "\'") - .arg("\'" + settings_.image.format + "\'") + UPDATE_IMAGE.arg(settings_.database.schema) ); + query.bindValue(":img", image_as_bytes); query.exec(); } database_.db.close(); - } void SettingsManager::ReloadSettings() { @@ -108,7 +115,6 @@ void SettingsManager::ReloadSettings() { } void SettingsManager::LoadFromDatabase() { - database_.db.open(); if (!database_.connect()) { @@ -122,7 +128,7 @@ void SettingsManager::LoadFromDatabase() { if (!query.exec()) { assert(false); } - for (auto &item: settings_.font_settings) { + for (auto& item : settings_.font_settings) { if (!query.next()) { break; } @@ -140,11 +146,10 @@ void SettingsManager::LoadFromDatabase() { if (!query.next()) { assert(false); } - { - QSqlRecord rec = query.record(); - settings_.image.url = rec.value("url").toUrl(); - settings_.image.format = rec.value("format").toString(); - } + settings_.image.loadFromData( + query.value("base64").toByteArray(), + EXTENSION + ); query.prepare(SELECT_PASSWORDS.arg(database_.schema)); query.exec(); @@ -159,22 +164,28 @@ void SettingsManager::LoadFromDatabase() { } database_.db.close(); - } -void SettingsManager::LoadFromIni(const QString &connection_name) { +void SettingsManager::LoadFromIni(const QString& connection_name) { + QFileInfo file_info(QString::fromStdString(SETTINGS_FILE_PATH_)); + if (!file_info.exists()) { + file_info.dir().mkdir(file_info.absolutePath()); + std::ofstream file(SETTINGS_FILE_PATH_); + file << DEFAULT_SETTINGS_; + } + settings_file_.load(SETTINGS_FILE_PATH_); settings_.output_folder = QString::fromStdString(settings_file_["general"]["path_to"].as()); settings_.theme = QString::fromStdString(settings_file_["general"]["theme"].as()); settings_.database = { - QString::fromStdString(settings_file_["database"]["host"].as()), - settings_file_["database"]["port"].as(), - QString::fromStdString(settings_file_["database"]["username"].as()), - QString::fromStdString(settings_file_["database"]["password"].as()), - QString::fromStdString(settings_file_["database"]["name"].as()), - QString::fromStdString(settings_file_["database"]["schema"].as()) + QString::fromStdString(settings_file_["database"]["host"].as()), + settings_file_["database"]["port"].as(), + QString::fromStdString(settings_file_["database"]["username"].as()), + QString::fromStdString(settings_file_["database"]["password"].as()), + QString::fromStdString(settings_file_["database"]["name"].as()), + QString::fromStdString(settings_file_["database"]["schema"].as()) }; database_ = Database(settings_.database, connection_name); diff --git a/source/services/settings/settings_manager.h b/source/services/settings/settings_manager.h index 56fd94c..fc603dd 100644 --- a/source/services/settings/settings_manager.h +++ b/source/services/settings/settings_manager.h @@ -26,6 +26,7 @@ // Qt #include #include +#include #include #include @@ -39,7 +40,6 @@ class SettingsManager { public: - enum SaveType { SAVE_NONE = 0b000, SAVE_DATABASE = 0b001, @@ -55,10 +55,10 @@ class SettingsManager { QString theme; std::array font_settings; Models::Database database; - Models::Image image; + QImage image; Models::Passwords passwords; - Settings &operator=(const Settings &other) { + Settings& operator=(const Settings& other) { output_folder = other.output_folder; theme = other.theme; font_settings = other.font_settings; @@ -67,24 +67,22 @@ class SettingsManager { passwords = other.passwords; return *this; } - }; - explicit SettingsManager(const QString &connection_name = "default"); + explicit SettingsManager(const QString& connection_name = "default"); void ReloadSettings(); Settings GetSettings(); - void SetSettings(const Settings &settings); + void SetSettings(const Settings& settings); void Save(int type = SaveType::SAVE_ALL); private: - void LoadFromDatabase(); - void LoadFromIni(const QString &connection_name); + void LoadFromIni(const QString& connection_name); Database database_; @@ -93,16 +91,27 @@ class SettingsManager { const QString SELECT_FONT_SETTINGS = "SELECT * FROM %1.font_settings;"; - const QString UPDATE_FONT_SETTINGS = "UPDATE %1.font_settings SET font = %2, color = %3, position_x = %4, position_y = %5, size = %6, bold = %7 WHERE id = %8;"; + const QString UPDATE_FONT_SETTINGS = + "UPDATE %1.font_settings SET font = %2, color = %3, position_x = %4, position_y = %5, size = %6, bold = %7 WHERE id = %8;"; - const QString SELECT_IMAGE = "SELECT url, format FROM %1.image WHERE id = 1;"; + const QString SELECT_IMAGE = "SELECT base64 FROM %1.image WHERE id = 1;"; - const QString UPDATE_IMAGE = "UPDATE %1.image SET url = %2, format = %3 WHERE id = 1;"; + const QString UPDATE_IMAGE = "UPDATE %1.image SET base64 = :img WHERE id = 1;"; const QString SELECT_PASSWORDS = "SELECT * FROM %1.advanced_settings_passwords;"; const std::string SETTINGS_FILE_PATH_ = "./settings/settings.ini"; + const std::string DEFAULT_SETTINGS_ = { + "[general]\n" + "path_to=default\n" + "theme=Darkeum\n\n" + "[database]\n" + "host=localhost\n" + "port=5432\n" + "username=postgres\n" + "password=root\n" + "name=tip\n" + "schema=main\n" + }; }; - - diff --git a/source/ui/mainwindow.ui b/source/ui/mainwindow.ui index b0c81be..9cf9fb0 100644 --- a/source/ui/mainwindow.ui +++ b/source/ui/mainwindow.ui @@ -87,6 +87,7 @@ + @@ -489,6 +490,11 @@ Очистить базу данных + + + Экспортировать + + diff --git a/source/ui/options.ui b/source/ui/options.ui index e0da1fa..22b6f26 100644 --- a/source/ui/options.ui +++ b/source/ui/options.ui @@ -7,7 +7,7 @@ 0 0 666 - 500 + 575 @@ -17,7 +17,7 @@ :/YandexDisk/Work/Заказы/(7)/Beta 1.3/icon.png:/YandexDisk/Work/Заказы/(7)/Beta 1.3/icon.png - + @@ -32,318 +32,291 @@ - + + + Qt::Horizontal + + + + 62 + 20 + + + + + + + + <html><head/><body><p align="center"><br/></p></body></html> + + + <html><head/><body><p align="center">Основные</p></body></html> + + + + + + + Qt::Horizontal + + + + + + + <html><head/><body><p>Путь к папке с результатом</p></body></html> + + + + + + + + + + 400 + 0 + + + + + + + + ... + + + + + + + + + + + Тема: + + + + + + + + + + + + Расширенные настройки + + + + + - + + + <html><head/><body><p align="center">Форматирование текста</p></body></html> + + + + + + + Qt::Horizontal + + + + + - - - <html><head/><body><p align="center"><br/></p></body></html> - + - <html><head/><body><p align="center">Основные</p></body></html> + 12345 - - - Qt::Horizontal + + + + 100 + 16777215 + + + + Изменить - - - - - - <html><head/><body><p>Путь к папке с результатом</p></body></html> - - - - - - - - 400 - 0 - - - - - - - - ... - - - - - - - - - - - Тема: - - - - - - - - - - - Расширенные настройки - - - - - + - + - <html><head/><body><p align="center">Форматирование текста</p></body></html> + Фамилия Имя - - - Qt::Horizontal + + + + 100 + 16777215 + + + + Изменить - - - - - - 12345 - - - - - - - - 100 - 16777215 - - - - Изменить - - - - - - - - - - - Фамилия Имя - - - - - - - - 100 - 16777215 - - - - Изменить - - - - - - - - - - - +1 (123) 456-78-12 - - - - - - - - 100 - 16777215 - - - - Изменить - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - + - + - <html><head/><body><p align="center">Расположение текста</p></body></html> + +1 (123) 456-78-12 - - - Qt::Horizontal + + + + 100 + 16777215 + + + + Изменить - - - - - - Расположение текста - - - - - - - - 100 - 16777215 - - - - Изменить - - - - - + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + <html><head/><body><p align="center">Расположение текста</p></body></html> + + + - + + + Qt::Horizontal + + + + + - + - <html><head/><body><p align="center">База данных</p></body></html> + Расположение текста - - - Qt::Horizontal + + + + 100 + 16777215 + + + + Изменить - - - - - - База данных: - - - - - - - - 100 - 16777215 - - - - Изменить - - - - - + + + + + + + + <html><head/><body><p align="center">База данных</p></body></html> + + + + + + + Qt::Horizontal + + + - + - + - <html><head/><body><p align="center">Изображение</p></body></html> + База данных: - - - Qt::Horizontal + + + + 100 + 16777215 + + + + Изменить - - - - - - Ссылка на изображение: - - - - - - - - - - - - - - Формат: - - - - - - - png, jpg, bmp и т.д. - - - - - + + + + + + + + <html><head/><body><p align="center">Изображение</p></body></html> + + + + + + + Qt::Horizontal + + + - + - + Qt::Horizontal @@ -356,14 +329,14 @@ - + - Сохранить + Загрузить - + Qt::Horizontal @@ -380,22 +353,52 @@ - + Qt::Horizontal - - - 62 - 20 - - - + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Сохранить + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - path_to_edit path_to_button theme_combo_box change_button_ex_1 diff --git a/source/ui/password_form.ui b/source/ui/password_form.ui index 6a048e3..b876652 100644 --- a/source/ui/password_form.ui +++ b/source/ui/password_form.ui @@ -25,7 +25,20 @@ - + + + false + + + QLineEdit::Password + + + Пароль + + + false + +