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.