From 989a06ea63d51f8ece7b53807e329f47778f9c27 Mon Sep 17 00:00:00 2001 From: Alex Tran <56737137+xelathan@users.noreply.github.com> Date: Tue, 15 Apr 2025 23:29:07 -0700 Subject: [PATCH] App: Running FreeCAD in verbose mode information to reflect Gui -> Help -> About Dialog info (#20487) --- src/App/Application.cpp | 289 ++++++++++++++++++++++++++++++++--- src/App/Application.h | 11 ++ src/Gui/Application.cpp | 42 +++++ src/Gui/Application.h | 3 + src/Gui/Dialogs/DlgAbout.cpp | 278 +-------------------------------- src/Main/MainCmd.cpp | 13 ++ src/Main/MainGui.cpp | 11 ++ 7 files changed, 354 insertions(+), 293 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 8fdaf9f2d2..3acf6856ad 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -64,7 +64,9 @@ #include #include #include +#include #include +#include #include #include @@ -172,6 +174,7 @@ FC_LOG_LEVEL_INIT("App", true, true) using namespace App; namespace sp = std::placeholders; +namespace fs = std::filesystem; //========================================================================== // Application @@ -2384,28 +2387,10 @@ void parseProgramOptions(int ac, char ** av, const std::string& exe, boost::prog void processProgramOptions(const boost::program_options::variables_map& vm, std::map& mConfig) { - if (vm.count("version")) { + if (vm.count("version") && !vm.count("verbose")) { std::stringstream str; str << mConfig["ExeName"] << " " << mConfig["ExeVersion"] << " Revision: " << mConfig["BuildRevision"] << '\n'; - if (vm.count("verbose")) { - str << "\nLibrary versions:\n"; - str << "boost " << BOOST_LIB_VERSION << '\n'; - str << "Coin3D " << fcCoin3dVersion << '\n'; - str << "Eigen3 " << fcEigen3Version << '\n'; -#ifdef OCC_VERSION_STRING_EXT - str << "OCC " << OCC_VERSION_STRING_EXT << '\n'; -#endif - str << "Qt " << QT_VERSION_STR << '\n'; - str << "Python " << PY_VERSION << '\n'; - str << "PySide " << fcPysideVersion << '\n'; - str << "shiboken " << fcShibokenVersion << '\n'; -#ifdef SMESH_VERSION_STR - str << "SMESH " << SMESH_VERSION_STR << '\n'; -#endif - str << "VTK " << fcVtkVersion << '\n'; - str << "xerces-c " << fcXercescVersion << '\n'; - } throw Base::ProgramInformation(str.str()); } @@ -2535,6 +2520,7 @@ void processProgramOptions(const boost::program_options::variables_map& vm, std: } } } + } // clang-format on @@ -2670,7 +2656,7 @@ void Application::initConfig(int argc, char ** argv) _pConsoleObserverFile = nullptr; // Banner =========================================================== - if (mConfig["RunMode"] != "Cmd") { + if (mConfig["RunMode"] != "Cmd" && !(vm.count("verbose") && vm.count("version"))) { // Remove banner if FreeCAD is invoked via the -c command as regular // Python interpreter if (mConfig["Verbose"] != "Strict") @@ -2781,6 +2767,11 @@ void Application::initConfig(int argc, char ** argv) logStatus(); + + if (vm.count("verbose") && vm.count("version")) { + Application::_pcSingleton = new Application(mConfig); + throw Base::ProgramInformation(Application::verboseVersionEmitMessage); + } } void Application::SaveEnv(const char* s) @@ -3549,3 +3540,261 @@ std::string Application::FindHomePath(const char* sCall) #else # error "std::string Application::FindHomePath(const char*) not implemented" #endif + +QString Application::prettyProductInfoWrapper() +{ + auto productName = QSysInfo::prettyProductName(); +#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0) +#ifdef FC_OS_MACOSX + auto macosVersionFile = + QStringLiteral("/System/Library/CoreServices/.SystemVersionPlatform.plist"); + auto fi = QFileInfo(macosVersionFile); + if (fi.exists() && fi.isReadable()) { + auto plistFile = QFile(macosVersionFile); + plistFile.open(QIODevice::ReadOnly); + while (!plistFile.atEnd()) { + auto line = plistFile.readLine(); + if (line.contains("ProductUserVisibleVersion")) { + auto nextLine = plistFile.readLine(); + if (nextLine.contains("")) { + QRegularExpression re(QStringLiteral("\\s*(.*)")); + auto matches = re.match(QString::fromUtf8(nextLine)); + if (matches.hasMatch()) { + productName = QStringLiteral("macOS ") + matches.captured(1); + break; + } + } + } + } + } +#endif +#endif +#ifdef FC_OS_WIN64 + QSettings regKey { + QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), + QSettings::NativeFormat}; + if (regKey.contains(QStringLiteral("CurrentBuildNumber"))) { + auto buildNumber = regKey.value(QStringLiteral("CurrentBuildNumber")).toInt(); + if (buildNumber > 0) { + if (buildNumber < 9200) { + productName = QStringLiteral("Windows 7 build %1").arg(buildNumber); + } + else if (buildNumber < 10240) { + productName = QStringLiteral("Windows 8 build %1").arg(buildNumber); + } + else if (buildNumber < 22000) { + productName = QStringLiteral("Windows 10 build %1").arg(buildNumber); + } + else { + productName = QStringLiteral("Windows 11 build %1").arg(buildNumber); + } + } + } +#endif + return productName; +} + +void Application::addModuleInfo(QTextStream& str, const QString& modPath, bool& firstMod) +{ + QFileInfo mod(modPath); + if (mod.isHidden()) { // Ignore hidden directories + return; + } + if (firstMod) { + firstMod = false; + str << "Installed mods: \n"; + } + str << " * " << (mod.isDir() ? QDir(modPath).dirName() : mod.fileName()); + try { + auto metadataFile = + std::filesystem::path(mod.absoluteFilePath().toStdString()) / "package.xml"; + if (std::filesystem::exists(metadataFile)) { + App::Metadata metadata(metadataFile); + if (metadata.version() != App::Meta::Version()) { + str << QLatin1String(" ") + QString::fromStdString(metadata.version().str()); + } + } + } + catch (const Base::Exception& e) { + auto what = QString::fromUtf8(e.what()).trimmed().replace(QChar::fromLatin1('\n'), + QChar::fromLatin1(' ')); + str << " (Malformed metadata: " << what << ")"; + } + QFileInfo disablingFile(mod.absoluteFilePath(), QStringLiteral("ADDON_DISABLED")); + if (disablingFile.exists()) { + str << " (Disabled)"; + } + + str << "\n"; +} + +QString Application::getValueOrEmpty(const std::map& map, const std::string& key) { + auto it = map.find(key); + return (it != map.end()) ? QString::fromStdString(it->second) : QString(); +} + +void Application::getVerboseCommonInfo(QTextStream& str, const std::map& mConfig) +{ + std::map::iterator it; + const QString deskEnv = + QProcessEnvironment::systemEnvironment().value(QStringLiteral("XDG_CURRENT_DESKTOP"), + QString()); + const QString deskSess = + QProcessEnvironment::systemEnvironment().value(QStringLiteral("DESKTOP_SESSION"), + QString()); + + const QString major = getValueOrEmpty(mConfig, "BuildVersionMajor"); + const QString minor = getValueOrEmpty(mConfig, "BuildVersionMinor"); + const QString point = getValueOrEmpty(mConfig, "BuildVersionPoint"); + const QString suffix = getValueOrEmpty(mConfig, "BuildVersionSuffix"); + const QString build = getValueOrEmpty(mConfig, "BuildRevision"); + const QString buildDate = getValueOrEmpty(mConfig, "BuildRevisionDate"); + + QStringList deskInfoList; + QString deskInfo; + + if (!deskEnv.isEmpty()) { + deskInfoList.append(deskEnv); + } + if (!deskSess.isEmpty()) { + deskInfoList.append(deskSess); + } + + const QString sysType = QSysInfo::productType(); + if (sysType != QLatin1String("windows") && sysType != QLatin1String("macos")) { + QString sessionType = QProcessEnvironment::systemEnvironment().value(QStringLiteral("XDG_SESSION_TYPE"), + QString()); + if (sessionType == QLatin1String("x11")) { + sessionType = QStringLiteral("xcb"); + } + deskInfoList.append(sessionType); + } + if (!deskInfoList.isEmpty()) { + deskInfo = QLatin1String(" (") + deskInfoList.join(QLatin1String("/")) + QLatin1String(")"); + } + + str << "OS: " << prettyProductInfoWrapper() << deskInfo << '\n'; + if (QSysInfo::buildCpuArchitecture() == QSysInfo::currentCpuArchitecture()) { + str << "Architecture: " << QSysInfo::buildCpuArchitecture() << "\n"; + } + else { + str << "Architecture: " << QSysInfo::buildCpuArchitecture() + << "(running on: " << QSysInfo::currentCpuArchitecture() << ")\n"; + } + str << "Version: " << major << "." << minor << "." << point << suffix << "." << build; + +#ifdef FC_CONDA + str << " Conda"; +#endif +#ifdef FC_FLATPAK + str << " Flatpak"; +#endif + const char* appimage = getenv("APPIMAGE"); + if (appimage) { + str << " AppImage"; + } + const char* snap = getenv("SNAP_REVISION"); + if (snap) { + str << " Snap " << snap; + } + str << '\n'; + str << "Build date: " << buildDate << "\n"; + +#if defined(_DEBUG) || defined(DEBUG) + str << "Build type: Debug\n"; +#elif defined(NDEBUG) + str << "Build type: Release\n"; +#elif defined(CMAKE_BUILD_TYPE) + str << "Build type: " << CMAKE_BUILD_TYPE << '\n'; +#else + str << "Build type: Unknown\n"; +#endif + const QString buildRevisionBranch = getValueOrEmpty(mConfig, "BuildRevisionBranch"); + if (!buildRevisionBranch.isEmpty()) { + str << "Branch: " << buildRevisionBranch << '\n'; + } + const QString buildRevisionHash = getValueOrEmpty(mConfig, "BuildRevisionHash"); + if (!buildRevisionHash.isEmpty()) { + str << "Hash: " << buildRevisionHash << '\n'; + } + // report also the version numbers of the most important libraries in FreeCAD + str << "Python " << PY_VERSION << ", "; + str << "Qt " << QT_VERSION_STR << ", "; + str << "Coin " << COIN_VERSION << ", "; + str << "Vtk " << fcVtkVersion << ", "; + str << "boost " << BOOST_LIB_VERSION << ", "; + str << "Eigen3 " << fcEigen3Version << ", "; + str << "PySide " << fcPysideVersion << '\n'; + str << "shiboken " << fcShibokenVersion << ", "; +#ifdef SMESH_VERSION_STR + str << "SMESH " << SMESH_VERSION_STR << ", "; +#endif + str << "xerces-c " << fcXercescVersion << ", "; + + const char* cmd = "import ifcopenshell\n" + "version = ifcopenshell.version"; + PyObject * ifcopenshellVer = nullptr; + + try { + ifcopenshellVer = Base::Interpreter().getValue(cmd, "version"); + } + catch (const Base::Exception& e) { + Base::Console().Log("%s (safe to ignore, unless using the BIM workbench and IFC).\n", e.what()); + } + + if (ifcopenshellVer) { + const char* ifcopenshellVerAsStr = PyUnicode_AsUTF8(ifcopenshellVer); + + if (ifcopenshellVerAsStr) { + str << "IfcOpenShell " << ifcopenshellVerAsStr << ", "; + } + Py_DECREF(ifcopenshellVer); + } + +#if defined(HAVE_OCC_VERSION) + str << "OCC " << OCC_VERSION_MAJOR << "." << OCC_VERSION_MINOR << "." << OCC_VERSION_MAINTENANCE +#ifdef OCC_VERSION_DEVELOPMENT + << "." OCC_VERSION_DEVELOPMENT +#endif + << '\n'; +#endif + QLocale loc; + str << "Locale: " << QLocale::languageToString(loc.language()) << "/" +#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) + << QLocale::countryToString(loc.country()) +#else + << QLocale::territoryToString(loc.territory()) +#endif + << " (" << loc.name() << ")"; + if (loc != QLocale::system()) { + loc = QLocale::system(); + str << " [ OS: " << QLocale::languageToString(loc.language()) << "/" +#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) + << QLocale::countryToString(loc.country()) +#else + << QLocale::territoryToString(loc.territory()) +#endif + << " (" << loc.name() << ") ]"; + } + str << "\n"; +} + +void Application::getVerboseAddOnsInfo(QTextStream& str, const std::map& mConfig) { + // Add installed module information: + const auto modDir = fs::path(Application::getUserAppDataDir()) / "Mod"; + bool firstMod = true; + if (fs::exists(modDir) && fs::is_directory(modDir)) { + for (const auto& mod : fs::directory_iterator(modDir)) { + auto dirName = mod.path().string(); + addModuleInfo(str, QString::fromStdString(dirName), firstMod); + } + } + const QString additionalModules = getValueOrEmpty(mConfig, "AdditionalModulePaths"); + + if (!additionalModules.isEmpty()) { + auto mods = additionalModules.split(QChar::fromLatin1(';')); + for (const auto& mod : mods) { + addModuleInfo(str, mod, firstMod); + } + } +} \ No newline at end of file diff --git a/src/App/Application.h b/src/App/Application.h index 93ea57171b..f6eef0365a 100644 --- a/src/App/Application.h +++ b/src/App/Application.h @@ -25,6 +25,7 @@ #define SRC_APP_APPLICATION_H_ #include +#include #include #include @@ -433,6 +434,16 @@ public: static std::string getHelpDir(); //@} + /** @name Verbose Information */ + //@{ + static void getVerboseCommonInfo(QTextStream& str, const std::map& mConfig); + static void getVerboseAddOnsInfo(QTextStream& str, const std::map& mConfig); + static void addModuleInfo(QTextStream& str, const QString& modPath, bool& firstMod); + static QString prettyProductInfoWrapper(); + static QString getValueOrEmpty(const std::map& map, const std::string& key); + static constexpr const char* verboseVersionEmitMessage{"verbose_version"}; + //@} + /** @name Link handling */ //@{ diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 24c5bceea4..f7680c8b91 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -2631,3 +2632,44 @@ App::Document* Application::reopen(App::Document* doc) } return doc; } + +void Application::getVerboseDPIStyleInfo(QTextStream& str) { + // Add Stylesheet/Theme/Qtstyle information + std::string styleSheet = + App::GetApplication() + .GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow") + ->GetASCII("StyleSheet"); + std::string theme = + App::GetApplication() + .GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow") + ->GetASCII("Theme"); +#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0) + std::string style = qApp->style()->name().toStdString(); +#else + std::string style = + App::GetApplication() + .GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow") + ->GetASCII("QtStyle"); + if (style.empty()) { + style = "Qt default"; + } +#endif + if (styleSheet.empty()) { + styleSheet = "unset"; + } + if (theme.empty()) { + theme = "unset"; + } + + str << "Stylesheet/Theme/QtStyle: " << QString::fromStdString(styleSheet) << "/" + << QString::fromStdString(theme) << "/" << QString::fromStdString(style) << "\n"; + + // Add DPI information + str << "Logical DPI/Physical DPI/Pixel Ratio: " + << QApplication::primaryScreen()->logicalDotsPerInch() + << "/" + << QApplication::primaryScreen()->physicalDotsPerInch() + << "/" + << QApplication::primaryScreen()->devicePixelRatio() + << "\n"; +} \ No newline at end of file diff --git a/src/Gui/Application.h b/src/Gui/Application.h index 54f7c4dd15..3cece3a157 100644 --- a/src/Gui/Application.h +++ b/src/Gui/Application.h @@ -252,6 +252,9 @@ public: void tryClose( QCloseEvent * e ); //@} + /// get verbose DPI and style info + static void getVerboseDPIStyleInfo(QTextStream& str); + /// whenever GUI is about to start with the main window hidden static bool hiddenMainWindow(); /// return the status bits diff --git a/src/Gui/Dialogs/DlgAbout.cpp b/src/Gui/Dialogs/DlgAbout.cpp index bc8d661407..12b54089a2 100644 --- a/src/Gui/Dialogs/DlgAbout.cpp +++ b/src/Gui/Dialogs/DlgAbout.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -62,59 +63,6 @@ using namespace Gui; using namespace Gui::Dialog; namespace fs = std::filesystem; -static QString prettyProductInfoWrapper() -{ - auto productName = QSysInfo::prettyProductName(); -#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0) -#ifdef FC_OS_MACOSX - auto macosVersionFile = - QStringLiteral("/System/Library/CoreServices/.SystemVersionPlatform.plist"); - auto fi = QFileInfo(macosVersionFile); - if (fi.exists() && fi.isReadable()) { - auto plistFile = QFile(macosVersionFile); - plistFile.open(QIODevice::ReadOnly); - while (!plistFile.atEnd()) { - auto line = plistFile.readLine(); - if (line.contains("ProductUserVisibleVersion")) { - auto nextLine = plistFile.readLine(); - if (nextLine.contains("")) { - QRegularExpression re(QStringLiteral("\\s*(.*)")); - auto matches = re.match(QString::fromUtf8(nextLine)); - if (matches.hasMatch()) { - productName = QStringLiteral("macOS ") + matches.captured(1); - break; - } - } - } - } - } -#endif -#endif -#ifdef FC_OS_WIN64 - QSettings regKey { - QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), - QSettings::NativeFormat}; - if (regKey.contains(QStringLiteral("CurrentBuildNumber"))) { - auto buildNumber = regKey.value(QStringLiteral("CurrentBuildNumber")).toInt(); - if (buildNumber > 0) { - if (buildNumber < 9200) { - productName = QStringLiteral("Windows 7 build %1").arg(buildNumber); - } - else if (buildNumber < 10240) { - productName = QStringLiteral("Windows 8 build %1").arg(buildNumber); - } - else if (buildNumber < 22000) { - productName = QStringLiteral("Windows 10 build %1").arg(buildNumber); - } - else { - productName = QStringLiteral("Windows 11 build %1").arg(buildNumber); - } - } - } -#endif - return productName; -} - // ------------------------------------------------------------------------------ AboutDialogFactory* AboutDialogFactory::factory = nullptr; @@ -296,7 +244,7 @@ void AboutDialog::setupLabels() ui->labelBuildDate->setText(date); QString os = ui->labelBuildOS->text(); - os.replace(QStringLiteral("Unknown"), prettyProductInfoWrapper()); + os.replace(QStringLiteral("Unknown"), App::Application::prettyProductInfoWrapper()); ui->labelBuildOS->setText(os); QString architecture = ui->labelBuildRunArchitecture->text(); @@ -527,230 +475,14 @@ void AboutDialog::linkActivated(const QUrl& link) licenseView->setSource(link); } -void AboutDialog::addModuleInfo(QTextStream& str, const QString& modPath, bool& firstMod) -{ - QFileInfo mod(modPath); - if (mod.isHidden()) { // Ignore hidden directories - return; - } - if (firstMod) { - firstMod = false; - str << "Installed mods: \n"; - } - str << " * " << (mod.isDir() ? QDir(modPath).dirName() : mod.fileName()); - try { - auto metadataFile = - std::filesystem::path(mod.absoluteFilePath().toStdString()) / "package.xml"; - if (std::filesystem::exists(metadataFile)) { - App::Metadata metadata(metadataFile); - if (metadata.version() != App::Meta::Version()) { - str << QLatin1String(" ") + QString::fromStdString(metadata.version().str()); - } - } - } - catch (const Base::Exception& e) { - auto what = QString::fromUtf8(e.what()).trimmed().replace(QChar::fromLatin1('\n'), - QChar::fromLatin1(' ')); - str << " (Malformed metadata: " << what << ")"; - } - QFileInfo disablingFile(mod.absoluteFilePath(), QStringLiteral("ADDON_DISABLED")); - if (disablingFile.exists()) { - str << " (Disabled)"; - } - - str << "\n"; -} - void AboutDialog::copyToClipboard() { QString data; QTextStream str(&data); std::map& config = App::Application::Config(); - std::map::iterator it; - QString exe = QString::fromStdString(App::Application::getExecutableName()); - - QString major = QString::fromStdString(config["BuildVersionMajor"]); - QString minor = QString::fromStdString(config["BuildVersionMinor"]); - QString point = QString::fromStdString(config["BuildVersionPoint"]); - QString suffix = QString::fromStdString(config["BuildVersionSuffix"]); - QString build = QString::fromStdString(config["BuildRevision"]); - QString buildDate = QString::fromStdString(config["BuildRevisionDate"]); - - QString deskEnv = - QProcessEnvironment::systemEnvironment().value(QStringLiteral("XDG_CURRENT_DESKTOP"), - QString()); - QString deskSess = - QProcessEnvironment::systemEnvironment().value(QStringLiteral("DESKTOP_SESSION"), - QString()); - QStringList deskInfoList; - QString deskInfo; - - if (!deskEnv.isEmpty()) { - deskInfoList.append(deskEnv); - } - if (!deskSess.isEmpty()) { - deskInfoList.append(deskSess); - } - if (qGuiApp->platformName() != QLatin1String("windows") - && qGuiApp->platformName() != QLatin1String("cocoa")) { - deskInfoList.append(qGuiApp->platformName()); - } - if (!deskInfoList.isEmpty()) { - deskInfo = QLatin1String(" (") + deskInfoList.join(QLatin1String("/")) + QLatin1String(")"); - } - - str << "OS: " << prettyProductInfoWrapper() << deskInfo << '\n'; - if (QSysInfo::buildCpuArchitecture() == QSysInfo::currentCpuArchitecture()) { - str << "Architecture: " << QSysInfo::buildCpuArchitecture() << "\n"; - } - else { - str << "Architecture: " << QSysInfo::buildCpuArchitecture() - << "(running on: " << QSysInfo::currentCpuArchitecture() << ")\n"; - } - str << "Version: " << major << "." << minor << "." << point << suffix << "." << build; -#ifdef FC_CONDA - str << " Conda"; -#endif -#ifdef FC_FLATPAK - str << " Flatpak"; -#endif - char* appimage = getenv("APPIMAGE"); - if (appimage) { - str << " AppImage"; - } - char* snap = getenv("SNAP_REVISION"); - if (snap) { - str << " Snap " << snap; - } - str << '\n'; - str << "Build date: " << buildDate << "\n"; - -#if defined(_DEBUG) || defined(DEBUG) - str << "Build type: Debug\n"; -#elif defined(NDEBUG) - str << "Build type: Release\n"; -#elif defined(CMAKE_BUILD_TYPE) - str << "Build type: " << CMAKE_BUILD_TYPE << '\n'; -#else - str << "Build type: Unknown\n"; -#endif - it = config.find("BuildRevisionBranch"); - if (it != config.end()) { - str << "Branch: " << QString::fromStdString(it->second) << '\n'; - } - it = config.find("BuildRevisionHash"); - if (it != config.end()) { - str << "Hash: " << QString::fromStdString(it->second) << '\n'; - } - // report also the version numbers of the most important libraries in FreeCAD - str << "Python " << PY_VERSION << ", "; - str << "Qt " << QT_VERSION_STR << ", "; - str << "Coin " << COIN_VERSION << ", "; - str << "Vtk " << fcVtkVersion << ", "; - - const char* cmd = "import ifcopenshell\n" - "version = ifcopenshell.version"; - PyObject * ifcopenshellVer = nullptr; - - try { - ifcopenshellVer = Base::Interpreter().getValue(cmd, "version"); - } - catch (const Base::Exception& e) { - Base::Console().Log("%s (safe to ignore, unless using the BIM workbench and IFC).\n", e.what()); - } - - if (ifcopenshellVer) { - const char* ifcopenshellVerAsStr = PyUnicode_AsUTF8(ifcopenshellVer); - - if (ifcopenshellVerAsStr) { - str << "IfcOpenShell " << ifcopenshellVerAsStr << ", "; - } - Py_DECREF(ifcopenshellVer); - } - -#if defined(HAVE_OCC_VERSION) - str << "OCC " << OCC_VERSION_MAJOR << "." << OCC_VERSION_MINOR << "." << OCC_VERSION_MAINTENANCE -#ifdef OCC_VERSION_DEVELOPMENT - << "." OCC_VERSION_DEVELOPMENT -#endif - << '\n'; -#endif - QLocale loc; - str << "Locale: " << QLocale::languageToString(loc.language()) << "/" -#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) - << QLocale::countryToString(loc.country()) -#else - << QLocale::territoryToString(loc.territory()) -#endif - << " (" << loc.name() << ")"; - if (loc != QLocale::system()) { - loc = QLocale::system(); - str << " [ OS: " << QLocale::languageToString(loc.language()) << "/" -#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) - << QLocale::countryToString(loc.country()) -#else - << QLocale::territoryToString(loc.territory()) -#endif - << " (" << loc.name() << ") ]"; - } - str << "\n"; - - // Add Stylesheet/Theme/Qtstyle information - std::string styleSheet = - App::GetApplication() - .GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow") - ->GetASCII("StyleSheet"); - std::string theme = - App::GetApplication() - .GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow") - ->GetASCII("Theme"); -#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0) - std::string style = qApp->style()->name().toStdString(); -#else - std::string style = - App::GetApplication() - .GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow") - ->GetASCII("QtStyle"); - if (style.empty()) { - style = "Qt default"; - } -#endif - if (styleSheet.empty()) { - styleSheet = "unset"; - } - if (theme.empty()) { - theme = "unset"; - } - - str << "Stylesheet/Theme/QtStyle: " << QString::fromStdString(styleSheet) << "/" - << QString::fromStdString(theme) << "/" << QString::fromStdString(style) << "\n"; - - // Add DPI information - str << "Logical DPI/Physical DPI/Pixel Ratio: " - << QApplication::primaryScreen()->logicalDotsPerInch() - << "/" - << QApplication::primaryScreen()->physicalDotsPerInch() - << "/" - << QApplication::primaryScreen()->devicePixelRatio() - << "\n"; - - // Add installed module information: - auto modDir = fs::path(App::Application::getUserAppDataDir()) / "Mod"; - bool firstMod = true; - if (fs::exists(modDir) && fs::is_directory(modDir)) { - for (const auto& mod : fs::directory_iterator(modDir)) { - auto dirName = mod.path().string(); - addModuleInfo(str, QString::fromStdString(dirName), firstMod); - } - } - auto additionalModules = config.find("AdditionalModulePaths"); - - if (additionalModules != config.end()) { - auto mods = QString::fromStdString(additionalModules->second).split(QChar::fromLatin1(';')); - for (const auto& mod : mods) { - addModuleInfo(str, mod, firstMod); - } - } + App::Application::getVerboseCommonInfo(str, config); + Gui::Application::getVerboseDPIStyleInfo(str); + App::Application::getVerboseAddOnsInfo(str, config); QClipboard* cb = QApplication::clipboard(); cb->setText(data); diff --git a/src/Main/MainCmd.cpp b/src/Main/MainCmd.cpp index 01ffa7bd78..515d726845 100644 --- a/src/Main/MainCmd.cpp +++ b/src/Main/MainCmd.cpp @@ -38,6 +38,8 @@ #include #include +#include + // FreeCAD Base header #include #include @@ -91,6 +93,17 @@ int main(int argc, char** argv) exit(1); } catch (const Base::ProgramInformation& e) { + if (std::strcmp(e.what(), App::Application::verboseVersionEmitMessage) == 0) { + QString data; + QTextStream str(&data); + const std::map config = App::Application::Config(); + + App::Application::getVerboseCommonInfo(str, config); + App::Application::getVerboseAddOnsInfo(str, config); + + std::cout << data.toStdString(); + exit(0); + } std::cout << e.what(); exit(0); } diff --git a/src/Main/MainGui.cpp b/src/Main/MainGui.cpp index 8d37610671..912c16570c 100644 --- a/src/Main/MainGui.cpp +++ b/src/Main/MainGui.cpp @@ -250,6 +250,17 @@ int main(int argc, char** argv) catch (const Base::ProgramInformation& e) { QApplication app(argc, argv); QString msg = QString::fromUtf8(e.what()); + if (msg == QLatin1String(App::Application::verboseVersionEmitMessage)) { + QString data; + QTextStream str(&data); + const std::map config = App::Application::Config(); + + App::Application::getVerboseCommonInfo(str, config); + Gui::Application::getVerboseDPIStyleInfo(str); + App::Application::getVerboseAddOnsInfo(str, config); + + msg = data; + } DisplayInfo(msg); exit(0); }