File indexing completed on 2024-05-12 07:41:25

0001 /*
0002     File                 : LabPlot.cpp
0003     Project              : LabPlot
0004     Description          : main function
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2008 Stefan Gerlach <stefan.gerlach@uni.kn>
0007     SPDX-FileCopyrightText: 2008-2016 Alexander Semke <alexander.semke@web.de>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "MainWin.h"
0012 #include "backend/core/AbstractColumn.h"
0013 #include "backend/core/Settings.h"
0014 #include "backend/lib/macros.h"
0015 
0016 #include <KAboutData>
0017 #include <KColorSchemeManager>
0018 #include <KConfigGroup>
0019 #include <KCrash>
0020 #include <KLocalizedString>
0021 #include <KMessageBox>
0022 #include <kcoreaddons_version.h>
0023 
0024 #include <QApplication>
0025 #include <QCommandLineParser>
0026 #include <QDir>
0027 #include <QFile>
0028 #include <QModelIndex>
0029 #include <QSettings>
0030 #include <QSplashScreen>
0031 #include <QStandardPaths>
0032 #include <QSysInfo>
0033 
0034 #ifdef _WIN32
0035 #include <windows.h>
0036 #endif
0037 
0038 /*
0039  * collect all system info to show in About dialog
0040  */
0041 const QString getSystemInfo() {
0042     // build type
0043 #ifdef NDEBUG
0044     const QString buildType(i18n("Release build ") + QLatin1String(GIT_COMMIT));
0045 #else
0046     const QString buildType(i18n("Debug build ") + QLatin1String(GIT_COMMIT));
0047 #endif
0048     QLocale locale;
0049     const QString numberSystemInfo{QStringLiteral("(") + i18n("Decimal point ") + QLatin1Char('\'') + QString(locale.decimalPoint()) + QLatin1String("\', ")
0050                                    + i18n("Group separator ") + QLatin1Char('\'') + QString(locale.groupSeparator()) + QLatin1Char('\'')};
0051 
0052     const QString numberLocaleInfo{QStringLiteral(" ") + i18n("Decimal point ") + QLatin1Char('\'') + QString(QLocale().decimalPoint()) + QLatin1String("\', ")
0053                                    + i18n("Group separator ") + QLatin1Char('\'') + QString(QLocale().groupSeparator()) + QLatin1String("\', ")
0054                                    + i18n("Exponential ") + QLatin1Char('\'') + QString(QLocale().exponential()) + QLatin1String("\', ") + i18n("Zero digit ")
0055                                    + QLatin1Char('\'') + QString(QLocale().zeroDigit()) + QLatin1String("\', ") + i18n("Percent ") + QLatin1Char('\'')
0056                                    + QString(QLocale().percent()) + QLatin1String("\', ") + i18n("Positive/Negative sign ") + QLatin1Char('\'')
0057                                    + QString(QLocale().positiveSign()) + QLatin1Char('\'') + QLatin1Char('/') + QLatin1Char('\'')
0058                                    + QString(QLocale().negativeSign()) + QLatin1Char('\'')};
0059 
0060     // get language set in 'switch language'
0061     const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
0062     QSettings languageoverride(configPath + QStringLiteral("/klanguageoverridesrc"), QSettings::IniFormat);
0063     languageoverride.beginGroup(QStringLiteral("Language"));
0064     QString usedLocale = languageoverride.value(qAppName(), QString()).toString(); // something like "en_US"
0065     if (!usedLocale.isEmpty())
0066         locale = QLocale(usedLocale);
0067     QString usedLanguage = QLocale::languageToString(locale.language()) + QStringLiteral(",") + QLocale::countryToString(locale.country());
0068 
0069     return buildType + QLatin1Char('\n')
0070 #ifndef REPRODUCIBLE_BUILD
0071         + QStringLiteral("%1, %2").arg(QLatin1String(__DATE__), QLatin1String(__TIME__)) + QLatin1Char('\n')
0072 #endif
0073         + i18n("System: ") + QSysInfo::prettyProductName() + QLatin1Char('\n') + i18n("Locale: ") + usedLanguage + QLatin1Char(' ') + numberSystemInfo
0074         + QLatin1Char('\n') + i18n("Number settings:") + numberLocaleInfo + QLatin1String(" (") + i18n("Updated on restart") + QLatin1Char(')')
0075         + QLatin1Char('\n') + i18n("Architecture: ") + QSysInfo::buildAbi() + QLatin1Char('\n') + i18n("Kernel: ") + QSysInfo::kernelType() + QLatin1Char(' ')
0076         + QSysInfo::kernelVersion() + QLatin1Char('\n') + i18n("C++ Compiler: ") + QLatin1String(CXX_COMPILER) + QLatin1Char('\n')
0077         + i18n("C++ Compiler Flags: ") + QLatin1String(CXX_COMPILER_FLAGS);
0078 }
0079 
0080 int main(int argc, char* argv[]) {
0081 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0082     QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
0083     QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
0084 #endif
0085     QApplication app(argc, argv);
0086     KLocalizedString::setApplicationDomain("labplot2");
0087     KCrash::initialize();
0088 
0089     MainWin::updateLocale();
0090 
0091     QString systemInfo{getSystemInfo()};
0092 
0093     KAboutData aboutData(QStringLiteral("labplot2"),
0094                          QStringLiteral("LabPlot"),
0095                          QLatin1String(LVERSION),
0096                          i18n("LabPlot is a FREE, open-source and cross-platform Data Visualization and Analysis software accessible to everyone."),
0097                          KAboutLicense::GPL,
0098                          i18n("(c) 2007-2024"),
0099                          systemInfo,
0100                          QStringLiteral("https://labplot.kde.org"));
0101     aboutData.addAuthor(i18n("Stefan Gerlach"), i18nc("@info:credit", "Developer"), QStringLiteral("stefan.gerlach@uni.kn"), QString());
0102     aboutData.addAuthor(i18n("Alexander Semke"), i18nc("@info:credit", "Developer"), QStringLiteral("alexander.semke@web.de"), QString());
0103     aboutData.addAuthor(i18n("Fábián Kristóf-Szabolcs"), i18nc("@info:credit", "Developer"), QStringLiteral("f-kristof@hotmail.com"), QString());
0104     aboutData.addAuthor(i18n("Martin Marmsoler"), i18nc("@info:credit", "Developer"), QStringLiteral("martin.marmsoler@gmail.com"), QString());
0105     aboutData.addAuthor(i18n("Dariusz Laska"),
0106                         i18nc("@info:credit", "Conceptual work, documentation, example projects"),
0107                         QStringLiteral("dariuszlaska@gmail.com"),
0108                         QString());
0109     aboutData.addAuthor(i18n("Andreas Kainz"), i18nc("@info:credit", "Icon designer"), QStringLiteral("kainz.a@gmail.com"), QString());
0110     aboutData.addCredit(i18n("Yuri Chornoivan"),
0111                         i18nc("@info:credit", "Help on many questions about the KDE-infrastructure and translation related topics"),
0112                         QStringLiteral("yurchor@ukr.net"),
0113                         QString());
0114     aboutData.addCredit(i18n("Garvit Khatri"),
0115                         i18nc("@info:credit", "Porting LabPlot2 to KF5 and Integration with Cantor"),
0116                         QStringLiteral("garvitdelhi@gmail.com"),
0117                         QString());
0118     aboutData.addCredit(i18n("Christoph Roick"),
0119                         i18nc("@info:credit", "Support import of ROOT (CERN) TH1 histograms"),
0120                         QStringLiteral("chrisito@gmx.de"),
0121                         QString());
0122     aboutData.setOrganizationDomain(QByteArray("kde.org"));
0123     aboutData.setDesktopFileName(QStringLiteral("org.kde.labplot2"));
0124     KAboutData::setApplicationData(aboutData);
0125 
0126     // TODO: add library information (GSL version, etc.) in about dialog
0127 
0128     QCommandLineParser parser;
0129 
0130     QCommandLineOption nosplashOption(QStringLiteral("no-splash"), i18n("Disable splash screen"));
0131     parser.addOption(nosplashOption);
0132 
0133     QCommandLineOption presenterOption(QStringLiteral("presenter"), i18n("Start in the presenter mode"));
0134     parser.addOption(presenterOption);
0135 
0136     parser.addPositionalArgument(QStringLiteral("+[file]"), i18n("Open a project file."));
0137 
0138     aboutData.setupCommandLine(&parser);
0139     parser.process(app);
0140     aboutData.processCommandLine(&parser);
0141 
0142     const QStringList args = parser.positionalArguments();
0143     QString filename;
0144     if (args.count() > 0)
0145         filename = args[0];
0146 
0147     if (!filename.isEmpty()) {
0148         // determine the absolute file path in order to properly save it in MainWin in "Recent Files"
0149         QDir dir;
0150         filename = dir.absoluteFilePath(filename);
0151 
0152         if (!QFile::exists(filename)) {
0153             if (KMessageBox::warningContinueCancel(
0154                     nullptr,
0155                     i18n(R"(Could not open file '%1'. Click 'Continue' to proceed starting or 'Cancel' to exit the application.)", filename),
0156                     i18n("Failed to Open"))
0157                 == KMessageBox::Cancel) {
0158                 exit(-1); //"Cancel" clicked -> exit the application
0159             } else {
0160                 filename.clear(); // Wrong file -> clear the file name and continue
0161             }
0162         }
0163     }
0164 
0165     QSplashScreen* splash = nullptr;
0166     if (!parser.isSet(nosplashOption)) {
0167         const QString& file = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("splash.png"));
0168         splash = new QSplashScreen(QPixmap(file));
0169         splash->show();
0170     }
0171 
0172     // needed in order to have the signals triggered by SignallingUndoCommand
0173     // TODO: redesign/remove this
0174     qRegisterMetaType<const AbstractAspect*>("const AbstractAspect*");
0175     qRegisterMetaType<const AbstractColumn*>("const AbstractColumn*");
0176 
0177 #ifdef _WIN32
0178     // enable debugging on console
0179     if (AttachConsole(ATTACH_PARENT_PROCESS)) {
0180         freopen("CONOUT$", "w", stdout);
0181         freopen("CONOUT$", "w", stderr);
0182     }
0183 #endif
0184     DEBUG("DEBUG debugging enabled")
0185     QDEBUG("QDEBUG debugging enabled")
0186 
0187     DEBUG("Current path: " << STDSTRING(QDir::currentPath()))
0188     const QString applicationPath = QCoreApplication::applicationDirPath();
0189     DEBUG("Application dir: " << STDSTRING(applicationPath))
0190 
0191 #ifdef _WIN32
0192     // append application path to PATH to find Cantor backends
0193     QString path = qEnvironmentVariable("PATH");
0194     DEBUG("OLD PATH = " << STDSTRING(path))
0195     path.append(QLatin1String(";") + applicationPath);
0196     qputenv("PATH", qPrintable(path));
0197     DEBUG("NEW PATH = " << STDSTRING(qEnvironmentVariable("PATH")))
0198 #endif
0199 
0200 #if !defined(NDEBUG) || defined(Q_OS_WIN) || defined(Q_OS_MACOS)
0201     // debugging paths
0202     const auto& appdatapaths = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
0203     WARN("AppDataLocation paths:")
0204     for (const auto& path : appdatapaths)
0205         WARN("  " << STDSTRING(path))
0206     WARN("Icon theme search paths:")
0207     for (const auto& path : QIcon::themeSearchPaths())
0208         WARN("  " << STDSTRING(path))
0209     WARN("Library search paths:")
0210     for (const auto& path : QCoreApplication::libraryPaths())
0211         WARN("  " << STDSTRING(path))
0212 #endif
0213 
0214     const auto& group = Settings::group(QStringLiteral("Settings_General"));
0215 #if KCOREADDONS_VERSION >= QT_VERSION_CHECK(5, 67, 0) // KColorSchemeManager has a system default option
0216     QString schemeName = group.readEntry("ColorScheme");
0217 #else
0218     KConfigGroup generalGlobalsGroup = KSharedConfig::openConfig(QLatin1String("kdeglobals"))->group("General");
0219     QString defaultSchemeName = generalGlobalsGroup.readEntry("ColorScheme", QStringLiteral("Breeze"));
0220     QString schemeName = group.readEntry("ColorScheme", defaultSchemeName);
0221 #endif
0222     KColorSchemeManager manager;
0223     manager.activateScheme(manager.indexForScheme(schemeName));
0224 
0225 #if defined(Q_OS_MACOS) || defined(Q_OS_WIN)
0226     QApplication::setStyle(QStringLiteral("breeze"));
0227 #endif
0228 
0229     auto* window = new MainWin(nullptr, filename);
0230     window->show();
0231 
0232     if (splash) {
0233         splash->finish(window);
0234         delete splash;
0235     }
0236 
0237     if (parser.isSet(presenterOption))
0238         window->showPresenter();
0239 
0240     return app.exec();
0241 }