File indexing completed on 2024-05-12 05:42:59

0001 #include "autogen/cutehmi.metadata.hpp"
0002 #include "autogen/cutehmi.dirs.hpp"
0003 #include "cutehmi/console/logging.hpp"
0004 #include "cutehmi/console/Exception.hpp"
0005 #include "cutehmi/console/Interpreter.hpp"
0006 #include "cutehmi/console/InputHandler.hpp"
0007 
0008 #include <cutehmi/Internationalizer.hpp>
0009 #include <cutehmi/Messenger.hpp>
0010 
0011 #include <QCoreApplication>
0012 #include <QQmlApplicationEngine>
0013 #include <QDir>
0014 #include <QCommandLineParser>
0015 #include <QLocale>
0016 #include <QLibraryInfo>
0017 #include <QtGlobal>
0018 #include <QThread>
0019 
0020 using namespace cutehmi::console;
0021 
0022 /**
0023  * Main function.
0024  * @param argc number of arguments passed to the program.
0025  * @param argv list of arguments passed to the program.
0026  * @return return code.
0027  */
0028 int main(int argc, char * argv[])
0029 {
0030     static constexpr const char * DEFAULT_COMPONENT = "Console";
0031     static constexpr const char * DEFAULT_MINOR = "0";
0032 
0033     // Set up application.
0034 
0035     QCoreApplication::setOrganizationName(CUTEHMI_CONSOLE_VENDOR);
0036     QCoreApplication::setOrganizationDomain(CUTEHMI_CONSOLE_DOMAIN);
0037     QCoreApplication::setApplicationName(CUTEHMI_CONSOLE_FRIENDLY_NAME);
0038     QCoreApplication::setApplicationVersion(CUTEHMI_CONSOLE_VERSION);
0039 
0040     try {
0041         //<Qt-Qt_5_7_0_Reference_Documentation-Threads_and_QObjects-QObject_Reentrancy-creating_QObjects_before_QApplication.assumption>
0042         // "In general, creating QObjects before the QApplication is not supported and can lead to weird crashes on exit, depending on the
0043         //  platform. This means static instances of QObject are also not supported. A properly structured single or multi-threaded application
0044         //  should make the QApplication be the first created, and last destroyed QObject."
0045 
0046         QCoreApplication app(argc, argv);
0047 
0048 
0049         // Translations initial setup.
0050 
0051         QString language = QLocale::system().name();
0052 #ifdef CUTEHMI_CONSOLE_DEFAULT_LANGUAGE
0053         language = CUTEHMI_CONSOLE_DEFAULT_LANGUAGE;
0054 #endif
0055         if (!qEnvironmentVariableIsEmpty("CUTEHMI_LANGUAGE")) {
0056             language = qgetenv("CUTEHMI_LANGUAGE");
0057             CUTEHMI_DEBUG("Default language set by 'CUTEHMI_LANGUAGE' environmental variable: " << qgetenv("CUTEHMI_LANGUAGE"));
0058         }
0059         cutehmi::Internationalizer::Instance().setUILanguage(language);
0060         cutehmi::Internationalizer::Instance().loadQtTranslation();
0061         cutehmi::Internationalizer::Instance().loadTranslation(CUTEHMI_CONSOLE_NAME);
0062 
0063 
0064         // Configure command line parser and process arguments.
0065 
0066         QCommandLineParser cmd;
0067         cmd.setApplicationDescription(CUTEHMI_CONSOLE_TRANSLATED_FRIENDLY_NAME + "\n" + CUTEHMI_CONSOLE_TRANSLATED_DESCRIPTION);
0068         cmd.addHelpOption();
0069         cmd.addVersionOption();
0070 
0071         QCommandLineOption langOption("lang", QCoreApplication::translate("main", "Choose application <language>."), QCoreApplication::translate("main", "language"));
0072         langOption.setDefaultValue(language);
0073         cmd.addOption(langOption);
0074 
0075         QCommandLineOption basedirOption("basedir", QCoreApplication::translate("main", "Set base directory to <dir>."), QCoreApplication::translate("main", "dir"));
0076         cmd.addOption(basedirOption);
0077 
0078         QCommandLineOption minorOption({"m", "minor"}, QCoreApplication::translate("main", "Use <version> for extension minor version to import."), QCoreApplication::translate("main", "version"));
0079         minorOption.setDefaultValue(DEFAULT_MINOR);
0080         cmd.addOption(minorOption);
0081 
0082         cmd.addPositionalArgument("extension", QCoreApplication::translate("main", "Extension to import."), "[extension]");
0083 
0084         cmd.addPositionalArgument("component", QCoreApplication::translate("main", "Component to create. Defaults to '%1'.").arg(DEFAULT_COMPONENT), "[component]");
0085 
0086         cmd.process(app);
0087 
0088 
0089         // Handle l8n options.
0090 
0091         CUTEHMI_DEBUG("Default locale: " << QLocale());
0092 
0093         CUTEHMI_DEBUG("Language: " << cmd.value(langOption));
0094         cutehmi::Internationalizer::Instance().setUILanguage(cmd.value(langOption)); // Reset language according to 'lang' option.
0095 
0096 
0097         // Prepare QML engine.
0098 
0099         QDir baseDir(QCoreApplication::applicationDirPath() + "/..");
0100         if (cmd.isSet(basedirOption))
0101             baseDir.setPath(cmd.value(basedirOption));
0102         QString baseDirPath = baseDir.absolutePath() + "/";
0103         CUTEHMI_DEBUG("Base directory: " << baseDirPath);
0104 
0105         QString extensionsDirPath = QDir::cleanPath(QCoreApplication::applicationDirPath() + "/" + QDir("/" CUTEHMI_DIRS_TOOLS_INSTALL_SUBDIR).relativeFilePath("/" CUTEHMI_DIRS_EXTENSIONS_INSTALL_SUBDIR));
0106         CUTEHMI_DEBUG("Extensions directory: " << extensionsDirPath);
0107 
0108         QCoreApplication::addLibraryPath(extensionsDirPath);
0109         CUTEHMI_DEBUG("Library paths: " << QCoreApplication::libraryPaths());
0110 
0111         std::unique_ptr<QQmlApplicationEngine> engine(new QQmlApplicationEngine);
0112 
0113         engine->addImportPath(extensionsDirPath);
0114         CUTEHMI_DEBUG("QML import paths: " << engine->importPathList());
0115 
0116         CUTEHMI_INFO(QCoreApplication::translate("main", "Welcome to %1 %2. Type \\help to see the list of commands.").arg(CUTEHMI_CONSOLE_VENDOR).arg(CUTEHMI_CONSOLE_FRIENDLY_NAME));
0117 
0118         QStringList positionalArguments = cmd.positionalArguments();
0119         if (positionalArguments.length() > 0) {
0120             QString extension = positionalArguments.at(0);
0121             QString extensionBaseName = extension.left(extension.lastIndexOf('.'));
0122             QString extensionMajor = extension.right(extension.length() - extension.lastIndexOf('.') - 1);
0123             {
0124                 bool ok;
0125                 extensionMajor.toUInt(& ok);
0126                 if (!ok)
0127                     throw Exception(QCoreApplication::translate("main", "Command line argument error: please specify extension with major version number after the last dot."));
0128             }
0129 
0130             QString extensionMinor = cmd.value(minorOption);
0131             if (!extensionMinor.isEmpty()) {
0132                 bool ok;
0133                 extensionMinor.toUInt(& ok);
0134                 if (!ok)
0135                     throw Exception(QCoreApplication::translate("main", "Command line argument error: value of '%1' option must be a number.").arg(minorOption.names().last()));
0136             }
0137 
0138             QString extensionComponent;
0139             if (positionalArguments.length() == 2)
0140                 extensionComponent = positionalArguments.at(1);
0141             else
0142                 extensionComponent = DEFAULT_COMPONENT;
0143 
0144             QString extensionImportStatement;
0145             if (!extension.isEmpty()) {
0146                 if (!extensionMinor.isEmpty())
0147                     extensionImportStatement = QString("import %1 %2.%3").arg(extensionBaseName).arg(extensionMajor).arg(extensionMinor);
0148                 else
0149                     extensionImportStatement = QString("import %1 %2").arg(extensionBaseName).arg(extensionMajor);
0150             }
0151 
0152             CUTEHMI_INFO(QCoreApplication::translate("main", "Extension: '%1 %2.%3'").arg(extensionBaseName).arg(extensionMajor).arg(extensionMinor));
0153             CUTEHMI_INFO(QCoreApplication::translate("main", "Component: '%1'").arg(extensionComponent));
0154 
0155             // Load extension translation and connect uiLanguageChanged() signal to retranslate() slot.
0156             if (!extension.isEmpty())
0157                 cutehmi::Internationalizer::Instance().loadTranslation(extension);
0158             QObject::connect(& cutehmi::Internationalizer::Instance(), & cutehmi::Internationalizer::uiLanguageChanged, engine.get(), & QQmlApplicationEngine::retranslate);
0159 
0160             engine->loadData((extensionImportStatement + "\n" + extensionComponent + "{}").toLocal8Bit());
0161         }
0162 
0163         InputHandler inputHandler;
0164         Interpreter interpreter(engine.get());
0165         QObject::connect(& inputHandler, & InputHandler::lineRead, & interpreter, & Interpreter::interperetLine, Qt::QueuedConnection);
0166         QObject::connect(& interpreter, & Interpreter::lineInterpreted, & inputHandler, & InputHandler::readLine, Qt::QueuedConnection);
0167         inputHandler.readLine();
0168 
0169         return app.exec();
0170         //</Qt-Qt_5_7_0_Reference_Documentation-Threads_and_QObjects-QObject_Reentrancy-creating_QObjects_before_QApplication.assumption>
0171     } catch (const cutehmi::Messenger::NoAdvertiserException & e) {
0172         CUTEHMI_CRITICAL("Dialog message: " << e.message()->text());
0173         if (!e.message()->informativeText().isEmpty())
0174             CUTEHMI_CRITICAL("Informative text: " << e.message()->informativeText());
0175         if (!e.message()->detailedText().isEmpty())
0176             CUTEHMI_CRITICAL("Detailed text: " << e.message()->detailedText());
0177         CUTEHMI_CRITICAL("Available buttons: " << e.message()->buttons());
0178     } catch (const QException & e) {
0179         CUTEHMI_CRITICAL(e.what());
0180     } catch (const std::exception & e) {
0181         CUTEHMI_CRITICAL(e.what());
0182     } catch (...) {
0183         CUTEHMI_CRITICAL("Caught unrecognized exception.");
0184         throw;
0185     }
0186 
0187     return EXIT_FAILURE;
0188 }
0189 
0190 //(c)C: Copyright © 2020-2024, Michał Policht <michal@policht.pl>. All rights reserved.
0191 //(c)C: SPDX-License-Identifier: LGPL-3.0-or-later OR MIT
0192 //(c)C: This file is a part of CuteHMI.
0193 //(c)C: CuteHMI is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
0194 //(c)C: CuteHMI 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 Lesser General Public License for more details.
0195 //(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI.  If not, see <https://www.gnu.org/licenses/>.
0196 //(c)C: Additionally, this file is licensed under terms of MIT license as expressed below.
0197 //(c)C: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
0198 //(c)C: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
0199 //(c)C: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.