diff --git a/.clang-format b/.clang-format index 548068d..b8140ac 100644 --- a/.clang-format +++ b/.clang-format @@ -31,11 +31,11 @@ BinPackArguments: true BinPackParameters: true BraceWrapping: AfterCaseLabel: false - AfterClass: false + AfterClass: true AfterControlStatement: Never AfterEnum: false - AfterFunction: false - AfterNamespace: false + AfterFunction: true + AfterNamespace: true AfterObjCDeclaration: false AfterStruct: false AfterUnion: false @@ -51,10 +51,6 @@ BraceWrapping: BreakBeforeBinaryOperators: None BreakBeforeConceptDeclarations: true BreakBeforeBraces: Custom -BraceWrapping: - AfterClass: true - AfterFunction: true - AfterNamespace: true BreakBeforeInheritanceComma: false BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: true diff --git a/.gitmodules b/.gitmodules index 672e543..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +0,0 @@ -[submodule "subprojects/nlohmann_json"] - path = subprojects/nlohmann_json - url = https://github.com/nlohmann/json.git -[submodule "subprojects/singleapplication"] - path = subprojects/singleapplication/singleapplication.git - url = https://github.com/itay-grudev/SingleApplication.git -[submodule "subprojects/csv-parser"] - path = subprojects/csv-parser - url = https://github.com/vincentlaucsb/csv-parser.git diff --git a/.vscode/settings.json b/.vscode/settings.json index 43f0c12..41f34ac 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,7 +65,37 @@ "condition_variable": "cpp", "mutex": "cpp", "hash_map": "cpp", - "future": "cpp" + "future": "cpp", + "bit": "cpp", + "compare": "cpp", + "concepts": "cpp", + "forward_list": "cpp", + "map": "cpp", + "set": "cpp", + "string": "cpp", + "unordered_set": "cpp", + "iterator": "cpp", + "memory_resource": "cpp", + "random": "cpp", + "semaphore": "cpp", + "stop_token": "cpp", + "__bit_reference": "cpp", + "__bits": "cpp", + "__config": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__mutex_base": "cpp", + "__node_handle": "cpp", + "__split_buffer": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__tuple": "cpp", + "__verbose_abort": "cpp", + "format": "cpp", + "ios": "cpp", + "locale": "cpp" }, "C_Cpp.clang_format_path": "/usr/bin/clang-format", "cmake.configureOnOpen": true, diff --git a/CMakeLists.txt b/CMakeLists.txt index d17a094..86b072a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,14 @@ -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.30) -project(kima2 VERSION 1.7.1) +project(kima2 VERSION 1.9.2) set(CMAKE_MODULE_PATH "${CMAKE_HOME_DIRECTORY}/cmake") set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) -#include(InstallRequiredSystemLibraries) +# For SingleApplication and nlohmann_json +include(FetchContent) if(MSVC) add_compile_options(/W4 /WX) @@ -17,6 +18,7 @@ else() endif() configure_file(config.h.in ${PROJECT_BINARY_DIR}/config.h) +configure_file(de.rustysoft.kima2.metainfo.xml.in ${PROJECT_BINARY_DIR}/de.rustysoft.kima2.metainfo.xml) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) @@ -28,7 +30,6 @@ if(KIMA2_USE_EXTERNAL_JSON) find_package(nlohmann_json REQUIRED) endif() -add_subdirectory(subprojects) add_subdirectory(src) #if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE MATCHES Debug) @@ -79,6 +80,8 @@ else(WIN32 AND NOT UNIX) DESTINATION share/${PROJECT_NAME}) install(FILES "${CMAKE_SOURCE_DIR}/misc/kima2.svg" DESTINATION share/icons/hicolor/scalable/apps) + install(FILES de.rustysoft.kima2.metainfo.xml + DESTINATION share/metainfo) endif (WIN32 AND NOT UNIX) if( MINGW ) @@ -95,9 +98,9 @@ if( MINGW ) ${MINGW_PATH}/libwinpthread-1.dll ${MINGW_PATH}/libsqlite3-0.dll ${MINGW_PATH}/libusb-1.0.dll - ${MINGW_PATH}/libicuuc71.dll - ${MINGW_PATH}/libicuin71.dll - ${MINGW_PATH}/libicudt71.dll + ${MINGW_PATH}/libicuuc76.dll + ${MINGW_PATH}/libicuin76.dll + ${MINGW_PATH}/libicudt76.dll ${MINGW_PATH}/libpcre2-16-0.dll ${MINGW_PATH}/libpcre2-8-0.dll ${MINGW_PATH}/zlib1.dll @@ -108,13 +111,12 @@ if( MINGW ) ${MINGW_PATH}/libgraphite2.dll ${MINGW_PATH}/libbz2-1.dll ${MINGW_PATH}/libintl-8.dll - ${MINGW_PATH}/libpcre-1.dll ${MINGW_PATH}/libdouble-conversion.dll ${MINGW_PATH}/libzstd.dll ${MINGW_PATH}/libmd4c.dll ${MINGW_PATH}/libbrotlicommon.dll ${MINGW_PATH}/libbrotlidec.dll - ${MINGW_PATH}/libfmt.dll + #${MINGW_PATH}/libfmt.dll ${MINGW_PATH}/libb2-1.dll ${MINGW_PATH}/libiconv-2.dll) install(FILES ${MINGW_PATH}/../share/qt6/plugins/platforms/qwindows.dll @@ -122,14 +124,13 @@ if( MINGW ) DESTINATION bin/platforms) #install(FILES ${MINGW_PATH}/../share/qt6/plugins/printsupport/windowsprintersupport.dll # DESTINATION bin/printsupport) - install(FILES ${MINGW_PATH}/../share/qt5/translations/qtbase_de.qm + install(FILES ${MINGW_PATH}/../share/qt6/translations/qtbase_de.qm ${MINGW_PATH}/../share/qt6/translations/qt_de.qm ${MINGW_PATH}/../share/qt6/translations/qt_help_de.qm ${MINGW_PATH}/../share/qt6/translations/qtmultimedia_de.qm - #${MINGW_PATH}/../share/qt6/translations/qtquickcontrols_de.qm - #${MINGW_PATH}/../share/qt6/translations/qtscript_de.qm - #${MINGW_PATH}/../share/qt6/translations/qtxmlpatterns_de.qm - DESTINATION bin/translations) + DESTINATION bin/share/qt6/translations) + install(FILES ${MINGW_PATH}/../share/qt6/plugins/styles/qmodernwindowsstyle.dll + DESTINATION bin/styles) endif( MINGW ) include(InstallRequiredSystemLibraries) diff --git a/LICENSE b/LICENSE index e6d4fba..0b127da 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright © 2018-2022 Martin Brodbeck +Copyright © 2018-2025 Martin Brodbeck Hiermit wird unentgeltlich jeder Person, die eine Kopie der Software und der zugehörigen Dokumentationen (die "Software") erhält, die Erlaubnis erteilt, diff --git a/README.md b/README.md index 4861890..3c0dd87 100644 --- a/README.md +++ b/README.md @@ -13,20 +13,16 @@ Verkaufsdaten nach dem Verkaufsende auszutauschen. Ebenso können über einen ESC/POS-Drucker Quittungen ausgestellt werden. ## Installation -Auf [rustysoft.de](https://www.rustysoft.de/software/kima2/) werden verschiedene Installationspakete (Arch Linux, -Ubuntu, Windows) angeboten. Bitte die Hinweise dort beachten. +Auf [rustysoft.de](https://www.rustysoft.de/software/kima2/) werden die Installationsmöglichkeiten (Flatpak, Windows-Installer) erläutert. Bitte die Hinweise dort beachten. -### Selbst compilieren +## Selbst compilieren KIMA2 benötigt folgende Libraries: * Qt 6 -* boost >= 1.62 +* boost >= 1.80 * libusb-1.0 -* xlnt >= 1.5.0 * nlohmann-json (als 3rdparty submodule vorhanden) -* csv-parser (als 3rdparty submodule vorhanden) -Da Features aus C++20 verwendet werden sowie std::filesystem, sollte als Compiler mindestens -GCC 12 verwendet werden. +Da Features aus C++20 sowie von neueren Compilern verwendet werden, sollte als Compiler mindestens GCC 14 verwendet werden. Die Installationsschritte unter Linux sind wie folgt: ``` diff --git a/de.rustysoft.kima2.metainfo.xml.in b/de.rustysoft.kima2.metainfo.xml.in new file mode 100644 index 0000000..9f228f7 --- /dev/null +++ b/de.rustysoft.kima2.metainfo.xml.in @@ -0,0 +1,27 @@ + + + de.rustysoft.kima2 + + KIMA2 + A small cash point program for children’s stuff markets + + MIT + GPL-3.0-or-later + + + + + + +

+ A small cash point program for children's stuff markets. German language only. +

+
+ + de.rustysoft.kima2.desktop + + + https://rustysoft.de/images/software/kima2/screenshot.png + + +
diff --git a/manual/Benutzerhandbuch.odt b/manual/Benutzerhandbuch.odt index 189890f..c2defc2 100644 Binary files a/manual/Benutzerhandbuch.odt and b/manual/Benutzerhandbuch.odt differ diff --git a/manual/Benutzerhandbuch.pdf b/manual/Benutzerhandbuch.pdf index 5a27042..793f996 100644 Binary files a/manual/Benutzerhandbuch.pdf and b/manual/Benutzerhandbuch.pdf differ diff --git a/meson.build b/meson.build deleted file mode 100644 index a0f8b23..0000000 --- a/meson.build +++ /dev/null @@ -1,33 +0,0 @@ -project('kima2', 'cpp', default_options : ['cpp_std=c++20'], version : '1.6.1') - -conf_data = configuration_data() -conf_data.set('PROJECT_VERSION', '"' + meson.project_version() + '"') -configure_file(output : 'config.h', - configuration : conf_data) -configuration_inc = include_directories('.') - -#csv = cmake.subproject('csv-parser') -#csv_lib = csv.dependency('csv') - -nlohmann_lib = dependency('nlohmann_json', version : '>=3.5.0', required : false) - -if not nlohmann_lib.found() - nlohmann_inc = include_directories('subprojects/nlohmann_json/single_include') - nlohmann_lib = declare_dependency(include_directories : nlohmann_inc) -endif - -csv_inc = include_directories('subprojects/csv-parser/single_include') -csv_dep = declare_dependency(include_directories : csv_inc) - -singleapp_proj = subproject('singleapplication') -singleapp_lib = singleapp_proj.get_variable('singleapp_lib') -singleapp_dep = singleapp_proj.get_variable('singleapp_dep') - -subdir('src') - -if build_machine.system() == 'linux' - install_data('misc/kima2.svg', install_dir : get_option('datadir') / 'icons/hicolor/scalable/apps') - install_data('misc/kima2.desktop', install_dir : get_option('datadir') / 'applications') - install_data('manual/Benutzerhandbuch.pdf', install_dir : get_option('datadir') / 'kima2') -endif - diff --git a/misc/PKGBUILD b/misc/PKGBUILD index e8b0b27..a50410c 100644 --- a/misc/PKGBUILD +++ b/misc/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: Martin Brodbeck pkgname=kima2 -pkgver=1.7.0 +pkgver=1.7.1 pkgrel=1 pkgdesc="A small cash point program for children's things markets (German only)" arch=('i686' 'x86_64') diff --git a/misc/kima2.desktop b/misc/kima2.desktop index 004ab5f..becabdf 100644 --- a/misc/kima2.desktop +++ b/misc/kima2.desktop @@ -3,8 +3,8 @@ Type=Application Name=KIMA2 GenericName=Cash Point Program GenericName[de]=Kassenprogramm -Comment=A small cash point program -Comment[de]=Ein kleines Kassenprogramm +Comment=A small cash point program for children's stuff markets +Comment[de]=Ein kleines Kassenprogramm für Kindersachenmärkte Exec=kima2 Icon=kima2 Categories=Office; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8aa1e2c..681cf5c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,15 +1,14 @@ set(Boost_USE_STATIC_LIBS ON) -find_package(Boost 1.62 REQUIRED) +find_package(Boost 1.78 REQUIRED) find_package(SQLite3 REQUIRED) -# Because csv-parser needs threads: -set(THREADS_PREFER_PTHREAD_FLAG ON) -find_package(Threads REQUIRED) +FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz) +FetchContent_MakeAvailable(json) -find_package(fmt) +add_library(core STATIC) -set(CORE_SOURCES +target_sources(core PRIVATE database.cpp entity.cpp entityint.cpp @@ -23,14 +22,11 @@ set(CORE_SOURCES utils.cpp ) - -add_library(core STATIC ${CORE_SOURCES}) -target_include_directories(core PRIVATE ${PROJECT_SOURCE_DIR}/subprojects/csv-parser/single_include) if (WIN32) - target_link_libraries(core PRIVATE sqlite3 nlohmann_json::nlohmann_json ${XLNT_LIBRARY} Threads::Threads fmt::fmt) + target_link_libraries(core PRIVATE sqlite3 nlohmann_json::nlohmann_json) target_link_libraries(core PRIVATE bcrypt) else() - target_link_libraries(core PRIVATE sqlite3 nlohmann_json::nlohmann_json ${XLNT_LIBRARIES} Threads::Threads fmt::fmt) + target_link_libraries(core PRIVATE sqlite3 nlohmann_json::nlohmann_json) endif() target_include_directories(core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..) diff --git a/src/core/csvreader.cpp b/src/core/csvreader.cpp index 5e092c9..6c2cdf6 100644 --- a/src/core/csvreader.cpp +++ b/src/core/csvreader.cpp @@ -3,7 +3,8 @@ #include -#include +// #include +#include #ifdef DELETE #undef DELETE @@ -13,17 +14,16 @@ namespace fs = std::filesystem; std::size_t CsvReader::readSellersFromFile(const fs::path &filePath, Marketplace *market) { - csv::CSVFormat format; - format.delimiter(';'); #if defined(_WIN64) || defined(_WIN32) // Windows: Somhow this is necessary in order to open file names with umlauts auto wide = filePath.wstring(); std::string fileName(wide.begin(), wide.end()); - csv::CSVReader csvReader(fileName, format); + std::ifstream infile(fileName); #else - csv::CSVReader csvReader(filePath.string(), format); + // csv::CSVReader csvReader(filePath.string(), format); + std::ifstream infile(filePath.string()); #endif for (auto &seller : market->getSellers()) { @@ -32,28 +32,35 @@ std::size_t CsvReader::readSellersFromFile(const fs::path &filePath, Marketplace market->storeToDb(true); - for (csv::CSVRow &row : csvReader) { - if (!row[0].is_int()) { + std::string line; + + while (getline(infile, line)) { + std::vector strs; + boost::split(strs, line, boost::is_any_of(";")); + + auto seller = std::make_unique(); + + try { + int sellerNo = std::stoi(strs[0]); + seller->setSellerNo(sellerNo); + } catch (std::invalid_argument const &ex) { continue; } - auto seller = std::make_unique(); - seller->setSellerNo(row[0].get()); - if (row[1].is_int()) { - seller->setNumArticlesOffered(row[1].get()); - } else { + if (isNumber(strs[1])) + seller->setNumArticlesOffered(std::stoi(strs[1])); + else seller->setNumArticlesOffered(0); - } // If both, first name and last name, are empty, use N. N. // Else, use the real values. - if (row[2].get().empty() && row[3].get().empty()) { + if (strs[2].empty() && strs[2].empty()) { seller->setFirstName("N."); seller->setLastName("N."); } else { - std::string firstName = row[2].get(); + std::string firstName = strs[2]; seller->setFirstName(trim(firstName)); - std::string lastName = row[3].get(); + std::string lastName = strs[3]; seller->setLastName(trim(lastName)); } diff --git a/src/core/database.cpp b/src/core/database.cpp index 863bc5d..d6b7384 100644 --- a/src/core/database.cpp +++ b/src/core/database.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include @@ -47,7 +47,7 @@ void Database::newDb() fs::path destPath = sourcePath.parent_path() / sourcePath.stem(); auto chronoTime = std::chrono::system_clock::now(); - std::string timeString = fmt::format("{0:%FT%H-%M-%S}", chronoTime); + std::string timeString = std::format("{0:%FT%H-%M-%S}", chronoTime); destPath += std::string("_") += timeString += ".db"; diff --git a/src/core/jsonutil.cpp b/src/core/jsonutil.cpp index bd24b4e..095a7b0 100644 --- a/src/core/jsonutil.cpp +++ b/src/core/jsonutil.cpp @@ -102,8 +102,10 @@ void JsonUtil::importSales(const std::filesystem::path &filePath, Marketplace *m int source_no = jsonValues["source_no"]; if (source_no == cashPointNo) { - throw std::runtime_error("Die Kassen-Nr. der zu imporierenden Daten wird von dieser Kasse " - "hier bereits verwendet."); + std::string ret = "Die Kassen-Nr. "; + ret += std::to_string(source_no); + ret += " der zu imporierenden Daten wird von dieser Kasse hier bereits verwendet."; + throw std::runtime_error(ret); } market->setSalesToDelete(jsonValues["source_no"]); diff --git a/src/core/meson.build b/src/core/meson.build deleted file mode 100644 index b54f484..0000000 --- a/src/core/meson.build +++ /dev/null @@ -1,13 +0,0 @@ -boost = dependency('boost', modules: ['date_time'], static: true) -xlnt = dependency('xlnt') -sqlite = dependency('sqlite3') - -src = ['database.cpp', 'entity.cpp', 'entityint.cpp', 'entityuuid.cpp', - 'seller.cpp', 'article.cpp', 'sale.cpp', 'marketplace.cpp', - 'excelreader.cpp', 'csvreader.cpp', 'jsonutil.cpp', 'utils.cpp'] - -core_inc = include_directories('..') - -core_lib = static_library('core', src, dependencies: [boost, xlnt, sqlite, nlohmann_lib, csv_dep]) - -core_dep = declare_dependency(link_with: core_lib, include_directories : core_inc) diff --git a/src/core/utils.cpp b/src/core/utils.cpp index 75242f3..1725924 100644 --- a/src/core/utils.cpp +++ b/src/core/utils.cpp @@ -2,13 +2,13 @@ #include #include -#include +#include #include #include #include -using namespace fmt; +//using namespace fmt; std::string formatCentAsEuroString(const int cent, int width) { @@ -32,7 +32,7 @@ std::string formatCentAsEuroString(const int cent, int width) #else std::locale myLocale{"de_DE.utf8"}; #endif - return fmt::format(myLocale, "{:{}.2Lf} €", cent / 100.0L, width); + return std::format(myLocale, "{:{}.2Lf} €", cent / 100.0L, width); } std::string <rim(std::string &str, const std::string &chars) @@ -61,3 +61,10 @@ bool case_insensitive_match(std::string s1, std::string s2) return true; // The strings are same return false; // not matched } + +bool isNumber(const std::string &str) +{ + return !str.empty() && std::find_if(str.begin(), str.end(), [](unsigned char c) { + return !std::isdigit(c); + }) == str.end(); +} \ No newline at end of file diff --git a/src/core/utils.h b/src/core/utils.h index 3a9ac21..0adfd75 100644 --- a/src/core/utils.h +++ b/src/core/utils.h @@ -10,5 +10,6 @@ std::string <rim(std::string &str, const std::string &chars = "\t\n\v\f\r "); std::string &rtrim(std::string &str, const std::string &chars = "\t\n\v\f\r "); std::string &trim(std::string &str, const std::string &chars = "\t\n\v\f\r "); bool case_insensitive_match(std::string s1, std::string s2); +bool isNumber(const std::string &str); #endif diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index bde8dfc..edd2102 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -9,40 +9,43 @@ set(CMAKE_AUTORCC ON) # Find the QtWidgets library find_package(Qt6 COMPONENTS Widgets Network PrintSupport CONFIG REQUIRED) -#find_package(Qt5Widgets CONFIG REQUIRED) -#find_package(Qt5PrintSupport CONFIG REQUIRED) # For SingleApplication: -#find_package(Qt5Network CONFIG REQUIRED) -set(QAPPLICATION_CLASS QApplication) +set(QT_DEFAULT_MAJOR_VERSION 6 CACHE STRING "Qt version to use, defaults to 6") +set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication") +FetchContent_Declare( + SingleApplication + GIT_REPOSITORY https://github.com/itay-grudev/SingleApplication + GIT_TAG v3.5.2 +) +FetchContent_MakeAvailable(SingleApplication) add_compile_definitions(QAPPLICATION_CLASS=${QAPPLICATION_CLASS}) -set(GUI_SOURCES - kima2.cpp - mainwindow.cpp - mainwindow.ui - sellerdialog.cpp - sellerdialog.ui - sellermodel.cpp - pricedialog.cpp - pricedialog.ui - basketmodel.cpp - salemodel.cpp - reportdialog.cpp - reportdialog.ui - reportmodel.cpp - settingsdialog.cpp - settingsdialog.ui - ../../kima2.qrc - ${PROJECT_SOURCE_DIR}/subprojects/singleapplication/singleapplication.git/singleapplication.cpp - ${PROJECT_SOURCE_DIR}/subprojects/singleapplication/singleapplication.git/singleapplication_p.cpp +add_executable(kima2) + +target_sources(kima2 PRIVATE + kima2.cpp + mainwindow.cpp + mainwindow.ui + sellerdialog.cpp + sellerdialog.ui + sellermodel.cpp + pricedialog.cpp + pricedialog.ui + basketmodel.cpp + salemodel.cpp + reportdialog.cpp + reportdialog.ui + reportmodel.cpp + settingsdialog.cpp + settingsdialog.ui + ../../kima2.qrc + kima2.rc ) -add_executable(kima2 ${GUI_SOURCES} kima2.rc) target_include_directories(kima2 PRIVATE ${PROJECT_BINARY_DIR}) -target_include_directories(kima2 PRIVATE ${PROJECT_SOURCE_DIR}/subprojects/singleapplication/singleapplication.git) -# target_link_libraries(kima2 core printer Qt5::Widgets Qt5::PrintSupport Qt5::Network stdc++fs) -target_link_libraries(kima2 core printer Qt::Core Qt::PrintSupport Qt::Network stdc++fs) + +target_link_libraries(kima2 core printer Qt::Core Qt::PrintSupport Qt::Network SingleApplication::SingleApplication) if(WIN32) set_target_properties(kima2 PROPERTIES LINK_FLAGS "-mwindows") diff --git a/src/gui/kima2.cpp b/src/gui/kima2.cpp index b5ecc97..d2826bd 100644 --- a/src/gui/kima2.cpp +++ b/src/gui/kima2.cpp @@ -13,9 +13,11 @@ #include #include +using namespace Qt::Literals::StringLiterals; + int main(int argc, char *argv[]) { - SingleApplication kimaApp(argc, argv); + SingleApplication kimaApp(argc, argv, false, SingleApplication::Mode::User | SingleApplication::ExcludeAppPath | SingleApplication::ExcludeAppVersion); // QCoreApplication::setOrganizationName("RustySoft"); QCoreApplication::setOrganizationDomain("rustysoft.de"); @@ -23,7 +25,7 @@ int main(int argc, char *argv[]) QTranslator qtTranslator; - if (qtTranslator.load(QLocale::system(), u"qtbase"_qs, u"_"_qs, + if (qtTranslator.load(QLocale::system(), u"qtbase"_s, u"_"_s, QLibraryInfo::path(QLibraryInfo::TranslationsPath))) { kimaApp.installTranslator(&qtTranslator); } diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 4874700..ca9031e 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -99,14 +99,13 @@ MainWindow::MainWindow() for (auto location : locations) { if (QFile::exists(location + QString("/Benutzerhandbuch.pdf"))) { QDesktopServices::openUrl( - QUrl(QString("file:///") + location + QString("/Benutzerhandbuch.pdf"), - QUrl::TolerantMode)); + QUrl::fromLocalFile(location + QString("/Benutzerhandbuch.pdf"))); } } }); connect(m_ui.licenseAction, &QAction::triggered, this, [this]() { QString licenseText( - "Copyright © 2018-2022 Martin Brodbeck\n\n" + "Copyright © 2018-2025 Martin Brodbeck\n\n" "Hiermit wird unentgeltlich jeder Person, die eine Kopie der Software und der " "zugehörigen Dokumentationen (die \"Software\") erhält, die Erlaubnis erteilt, " "sie uneingeschränkt zu nutzen, inklusive und ohne Ausnahme mit dem Recht, " @@ -505,27 +504,30 @@ void MainWindow::onImportSalesJsonActionTriggered() { QSettings settings; - auto filename = QFileDialog::getOpenFileName(this, "Umsätze/Transaktionen importieren", + auto filenames = QFileDialog::getOpenFileNames(this, "Umsätze/Transaktionen importieren", QString(), "JSON Dateien (*.json)"); - if (filename.isEmpty()) + if (filenames.isEmpty()) return; + for(auto filename: filenames) { #if defined(_WIN64) || defined(_WIN32) - fs::path filePath(filename.toStdWString()); + fs::path filePath(filename.toStdWString()); #else - fs::path filePath(filename.toStdString()); + fs::path filePath(filename.toStdString()); #endif - delete m_ui.salesView->model(); - try { - JsonUtil::importSales(filePath, m_marketplace.get(), - settings.value("global/cashPointNo").toInt()); - } catch (std::runtime_error &err) { - QMessageBox(QMessageBox::Icon::Warning, "Import nicht möglich", err.what(), QMessageBox::Ok, - this) - .exec(); + delete m_ui.salesView->model(); + try { + JsonUtil::importSales(filePath, m_marketplace.get(), + settings.value("global/cashPointNo").toInt()); + } catch (std::runtime_error &err) { + QMessageBox(QMessageBox::Icon::Warning, "Import nicht möglich", err.what(), QMessageBox::Ok, + this) + .exec(); + } } + setSaleModel(); updateStatLabel(); } diff --git a/src/gui/meson.build b/src/gui/meson.build deleted file mode 100644 index 18bfcee..0000000 --- a/src/gui/meson.build +++ /dev/null @@ -1,23 +0,0 @@ -qt5 = import('qt5') -qt5_dep = dependency('qt5', modules: ['Core', 'Gui', 'PrintSupport', 'Network']) - -thread_dep = dependency('threads') - - -src = ['kima2.cpp', 'mainwindow.cpp', 'sellerdialog.cpp', 'sellermodel.cpp', - 'pricedialog.cpp', 'basketmodel.cpp', 'salemodel.cpp', 'reportdialog.cpp', - 'reportmodel.cpp', 'settingsdialog.cpp'] - -ui = ['mainwindow.ui', 'sellerdialog.ui', 'pricedialog.ui', 'reportdialog.ui', 'settingsdialog.ui'] - -processed = qt5.preprocess(moc_headers : ['basketmodel.h', 'mainwindow.h', 'pricedialog.h', - 'reportdialog.h', 'sellerdialog.h', 'settingsdialog.h', - 'sellermodel.h', 'salemodel.h'], - ui_files : ui, - qresources : '../../kima2.qrc', - dependencies: qt5_dep) - -kima2 = executable('kima2', sources : [src, processed], - dependencies : [qt5_dep, singleapp_dep, core_dep, printer_dep, thread_dep], - include_directories : [configuration_inc], - install : true) diff --git a/src/gui/reportdialog.cpp b/src/gui/reportdialog.cpp index 682c737..2c13baf 100644 --- a/src/gui/reportdialog.cpp +++ b/src/gui/reportdialog.cpp @@ -201,7 +201,7 @@ void ReportDialog::onPrintSellerReceiptButtonClicked() return; auto indexes = selModel->selectedRows(); - auto &seller = m_market->getSellers().at(indexes[0].row()); + std::ranges::sort(indexes); auto printerDevice = convertToPosPrinterDevice(posPrinterDevice.toStdString(), posPrinterEndpoint.toStdString()); @@ -214,10 +214,14 @@ void ReportDialog::onPrintSellerReceiptButtonClicked() printer = std::make_unique(); } - if (printer->isValid()) - printer->printSellerReceipt( - seller.get(), feeInPercent, maxFeeInEuro * 100, - settings.value("global/commune", "Dettingen").toString().toStdString()); + if (printer->isValid()) { + for (const auto &index : indexes) { + auto &seller = m_market->getSellers().at(index.row()); + printer->printSellerReceipt( + seller.get(), feeInPercent, maxFeeInEuro * 100, + settings.value("global/commune", "Dettingen").toString().toStdString()); + } + } } void ReportDialog::onReportViewSelectionChanged(const QItemSelection &selected, diff --git a/src/gui/reportdialog.ui b/src/gui/reportdialog.ui index d5d27b6..5ac21c8 100644 --- a/src/gui/reportdialog.ui +++ b/src/gui/reportdialog.ui @@ -19,7 +19,7 @@ - QAbstractItemView::SingleSelection + QAbstractItemView::ExtendedSelection QAbstractItemView::SelectRows diff --git a/src/meson.build b/src/meson.build deleted file mode 100644 index 439c81e..0000000 --- a/src/meson.build +++ /dev/null @@ -1,3 +0,0 @@ -subdir('core') -subdir('printer') -subdir('gui') diff --git a/src/printer/CMakeLists.txt b/src/printer/CMakeLists.txt index 9dfaa3e..6205d41 100644 --- a/src/printer/CMakeLists.txt +++ b/src/printer/CMakeLists.txt @@ -1,6 +1,6 @@ set(Boost_USE_STATIC_LIBS ON) -find_package(Boost 1.62 REQUIRED) +find_package(Boost 1.78 REQUIRED) if(WIN32) find_package(LIBUSB REQUIRED) @@ -9,15 +9,15 @@ else() pkg_check_modules(LibUSB REQUIRED libusb-1.0) endif() -set(PRINTER_SOURCES - posprinter.cpp - utils.cpp +add_library(printer STATIC) +target_sources(printer PRIVATE + posprinter.cpp + utils.cpp ) -add_library(printer STATIC ${PRINTER_SOURCES}) if(WIN32) target_link_libraries(printer core ${LIBUSB_1_LIBRARIES}) else() target_link_libraries(printer core ${LibUSB_LIBRARIES}) endif() -target_include_directories(printer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..) +target_include_directories(printer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/.. ${Boost_INCLUDE_DIRS}) diff --git a/src/printer/meson.build b/src/printer/meson.build deleted file mode 100644 index 64f0602..0000000 --- a/src/printer/meson.build +++ /dev/null @@ -1,9 +0,0 @@ -libusb = dependency('libusb-1.0') - -src = ['posprinter.cpp', 'utils.cpp'] - -printer_inc = include_directories('..') - -printer_lib = static_library('printer', src, dependencies: [libusb, core_dep]) - -printer_dep = declare_dependency(link_with : printer_lib, include_directories : printer_inc) diff --git a/src/printer/posprinter.cpp b/src/printer/posprinter.cpp index 368d483..61926fc 100644 --- a/src/printer/posprinter.cpp +++ b/src/printer/posprinter.cpp @@ -19,6 +19,8 @@ const std::string PosPrinter::Command::RIGHT_ALIGN = {0x1b, 0x61, 0x02}; const std::string PosPrinter::Command::FONT_SIZE_BIG = {0x1b, 0x21, 0x10}; const std::string PosPrinter::Command::FONT_SIZE_NORMAL = {0x1b, 0x21, 0x00}; const std::string PosPrinter::Command::FEED = {0x1b, 0x64, 0x03}; +const std::string PosPrinter::Command::PARTIAL_CUT = {0x1b, 0x69}; +const std::string PosPrinter::Command::FULL_CUT = {0x1b, 0x6d}; PosPrinter::PosPrinter() : PosPrinter(PrinterDevice()) {} @@ -202,7 +204,7 @@ void PosPrinter::printSellerReceipt(Seller* seller, const int percent, const int << marketFeeAsString(seller->sumInCents(), percent, maxFeeInCent) << "\n"; commandStream << "\nAuszahlung............. " << paymentAsString(seller->sumInCents(), percent, maxFeeInCent) << "\n"; - commandStream << Command::FEED; + commandStream << Command::FEED << Command::FEED; write(commandStream.str()); } diff --git a/src/printer/posprinter.h b/src/printer/posprinter.h index 4ddd083..1cdbff6 100644 --- a/src/printer/posprinter.h +++ b/src/printer/posprinter.h @@ -49,6 +49,8 @@ class PosPrinter static const std::string FONT_SIZE_BIG; static const std::string FONT_SIZE_NORMAL; static const std::string FEED; + static const std::string PARTIAL_CUT; + static const std::string FULL_CUT; }; private: diff --git a/subprojects/CMakeLists.txt b/subprojects/CMakeLists.txt deleted file mode 100644 index 6ef42eb..0000000 --- a/subprojects/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -if(NOT KIMA2_USE_EXTERNAL_JSON) - set(JSON_BuildTests OFF CACHE INTERNAL "") - add_subdirectory(nlohmann_json EXCLUDE_FROM_ALL) -endif() -#add_subdirectory(csv-parser) diff --git a/subprojects/csv-parser b/subprojects/csv-parser deleted file mode 160000 index ea547fd..0000000 --- a/subprojects/csv-parser +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ea547fdb16c7baf99bd9ced5febba52cc5da3ca3 diff --git a/subprojects/nlohmann_json b/subprojects/nlohmann_json deleted file mode 160000 index bc889af..0000000 --- a/subprojects/nlohmann_json +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bc889afb4c5bf1c0d8ee29ef35eaaf4c8bef8a5d diff --git a/subprojects/singleapplication/meson.build b/subprojects/singleapplication/meson.build deleted file mode 100644 index 1b43463..0000000 --- a/subprojects/singleapplication/meson.build +++ /dev/null @@ -1,27 +0,0 @@ -project('singleapplication') - -qt5 = import('qt5') -dep_qt5 = dependency('qt5', modules: ['Core', 'Widgets', 'Network']) - -singleapp_inc = include_directories('singleapplication.git') - -singleapp_moc = qt5.preprocess( - moc_headers: ['singleapplication.git/singleapplication.h', 'singleapplication.git/singleapplication_p.h'], - moc_extra_arguments: ['-DQAPPLICATION_CLASS=QApplication'], - dependencies: dep_qt5 -) - -singleapp_lib = static_library('SingleApplication', - ['singleapplication.git/singleapplication.cpp', 'singleapplication.git/singleapplication_p.cpp', singleapp_moc], - include_directories: singleapp_inc, - cpp_args : '-DQAPPLICATION_CLASS=QApplication', - dependencies: dep_qt5 -) - -singleapp_dep = declare_dependency( - include_directories: singleapp_inc, - link_with: singleapp_lib -) - -# On windows, SingleApplication needs to be linked against advapi32. This is -# done by adding 'advapi32' to cpp_winlibs, where it should be by default. diff --git a/subprojects/singleapplication/singleapplication.git b/subprojects/singleapplication/singleapplication.git deleted file mode 160000 index a3ed916..0000000 --- a/subprojects/singleapplication/singleapplication.git +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a3ed916f591c300e97b873fde36863fa37b49fa9