diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 5296de1c2d8..1a40e15b336 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,9 @@ #include #include +#include #include +#include #ifdef WITH_TESTS #include @@ -270,6 +273,7 @@ enum { debugLeaks = 0 }; using namespace ExtensionSystem; using namespace ExtensionSystem::Internal; +using namespace Utils; static Internal::PluginManagerPrivate *d = 0; static PluginManager *m_instance = 0; @@ -420,6 +424,33 @@ void PluginManager::shutdown() d->shutdown(); } +static QString filled(const QString &s, int min) +{ + return s + QString(qMax(0, min - s.size()), ' '); +} + +QString PluginManager::systemInformation() const +{ + QString result; + const QString qtdiagBinary = HostOsInfo::withExecutableSuffix( + QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qtdiag"); + SynchronousProcess qtdiagProc; + const SynchronousProcessResponse response = qtdiagProc.runBlocking(qtdiagBinary, QStringList()); + if (response.result == SynchronousProcessResponse::Finished) + result += response.allOutput() + "\n"; + result += "Plugin information:\n\n"; + auto longestSpec = std::max_element(plugins().cbegin(), plugins().cend(), + [](const PluginSpec *left, const PluginSpec *right) { + return left->name().size() < right->name().size(); + }); + int size = (*longestSpec)->name().size(); + for (const PluginSpec *spec : plugins()) { + result += (spec->isEffectivelyEnabled() ? "+ " : " ") + filled(spec->name(), size) + + " " + spec->version() + "\n"; + } + return result; +} + /*! The list of paths were the plugin manager searches for plugins. @@ -525,7 +556,7 @@ QStringList PluginManager::arguments() \sa setPluginPaths() */ -QList PluginManager::plugins() +const QList PluginManager::plugins() { return d->pluginSpecs; } @@ -1019,7 +1050,7 @@ static int executeTestPlan(const TestPlan &testPlan) << QLatin1String("-maxwarnings") << QLatin1String("0"); // unlimit output qExecArguments << functions; // avoid being stuck in QTBUG-24925 - if (!Utils::HostOsInfo::isWindowsHost()) + if (!HostOsInfo::isWindowsHost()) qExecArguments << "-nocrashhandler"; failedTests += QTest::qExec(testObject, qExecArguments); } @@ -1123,7 +1154,7 @@ void PluginManagerPrivate::startTests() continue; // plugin not loaded const QList testObjects = plugin->createTestObjects(); - Utils::ExecuteOnDestruction deleteTestObjects([&]() { qDeleteAll(testObjects); }); + ExecuteOnDestruction deleteTestObjects([&]() { qDeleteAll(testObjects); }); Q_UNUSED(deleteTestObjects) const bool hasDuplicateTestObjects = testObjects.size() != testObjects.toSet().size(); diff --git a/src/libs/extensionsystem/pluginmanager.h b/src/libs/extensionsystem/pluginmanager.h index fac52eaf071..57a911ce7de 100644 --- a/src/libs/extensionsystem/pluginmanager.h +++ b/src/libs/extensionsystem/pluginmanager.h @@ -114,7 +114,7 @@ public: static void setPluginPaths(const QStringList &paths); static QString pluginIID(); static void setPluginIID(const QString &iid); - static QList plugins(); + static const QList plugins(); static QHash> pluginCollections(); static bool hasError(); static QSet pluginsRequiringPlugin(PluginSpec *spec); @@ -150,6 +150,8 @@ public: void remoteArguments(const QString &serializedArguments, QObject *socket); void shutdown(); + QString systemInformation() const; + signals: void objectAdded(QObject *obj); void aboutToRemoveObject(QObject *obj); diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 5278a1e19e0..1f3c9728043 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -563,7 +563,6 @@ void ICore::openFiles(const QStringList &arguments, ICore::OpenFilesFlags flags) m_mainwindow->openFiles(arguments, flags); } - /*! \fn ICore::addCloseCoreListener @@ -580,6 +579,20 @@ void ICore::addPreCloseListener(const std::function &listener) m_mainwindow->addPreCloseListener(listener); } +QString ICore::systemInformation() +{ + QString result = PluginManager::instance()->systemInformation() + '\n'; + result += versionString() + '\n'; + result += buildCompatibilityString() + '\n'; +#ifdef IDE_REVISION + result += "From revision %1\n").arg(QString::fromLatin1(Constants::IDE_REVISION_STR).left(10)); +#endif +#ifdef QTC_SHOW_BUILD_DATE + result += "Built on %1 %2\n").arg(QLatin1String(__DATE__), QLatin1String(__TIME__)); +#endif + return result; +} + void ICore::saveSettings() { emit m_instance->saveSettingsRequested(); diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h index 13e14c06f2a..0f6f15d0702 100644 --- a/src/plugins/coreplugin/icore.h +++ b/src/plugins/coreplugin/icore.h @@ -130,6 +130,8 @@ public: static void addPreCloseListener(const std::function &listener); + static QString systemInformation(); + public slots: static void saveSettings(); diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index fc1603a9cf7..f0238a7100c 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -79,9 +79,12 @@ #include #include +#include +#include #include #include #include +#include #include #include #include @@ -208,6 +211,11 @@ bool HelpPlugin::initialize(const QStringList &arguments, QString *error) ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT); connect(action, &QAction::triggered, this, &HelpPlugin::slotReportBug); + action = new QAction(tr("System Information..."), this); + cmd = ActionManager::registerAction(action, "Help.SystemInformation"); + ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT); + connect(action, &QAction::triggered, this, &HelpPlugin::slotSystemInformation); + if (ActionContainer *windowMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW)) { // reuse EditorManager constants to avoid a second pair of menu actions // Goto Previous In History Action @@ -647,6 +655,54 @@ void HelpPlugin::slotReportBug() QDesktopServices::openUrl(QUrl("https://bugreports.qt.io")); } +class DialogClosingOnEscape : public QDialog +{ +public: + DialogClosingOnEscape(QWidget *parent = 0) : QDialog(parent) {} + bool event(QEvent *event) + { + if (event->type() == QEvent::ShortcutOverride) { + QKeyEvent *ke = static_cast(event); + if (ke->key() == Qt::Key_Escape && !ke->modifiers()) { + ke->accept(); + return true; + } + } + return QDialog::event(event); + } +}; + +void HelpPlugin::slotSystemInformation() +{ + auto dialog = new DialogClosingOnEscape(ICore::dialogParent()); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->setModal(true); + dialog->setWindowTitle(tr("System Information")); + auto layout = new QVBoxLayout; + dialog->setLayout(layout); + auto intro = new QLabel(tr("Use the following to provide more detailed information about your system to bug reports:")); + intro->setWordWrap(true); + layout->addWidget(intro); + const QString text = "{noformat}\n" + ICore::systemInformation() + "\n{noformat}"; + auto info = new QPlainTextEdit; + info->setPlainText(text); + layout->addWidget(info); + auto buttonBox = new QDialogButtonBox; + buttonBox->addButton(QDialogButtonBox::Cancel); + buttonBox->addButton(tr("Copy to Clipboard"), QDialogButtonBox::AcceptRole); + connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); + layout->addWidget(buttonBox); + connect(dialog, &QDialog::accepted, info, [info]() { + if (QApplication::clipboard()) + QApplication::clipboard()->setText(info->toPlainText()); + }); + connect(dialog, &QDialog::rejected, dialog, [dialog]{ dialog->close(); }); + dialog->resize(700, 400); + ICore::registerWindow(dialog, Context("Help.SystemInformation")); + dialog->show(); +} + void HelpPlugin::doSetupIfNeeded() { LocalHelpManager::setupGuiHelpEngine(); diff --git a/src/plugins/help/helpplugin.h b/src/plugins/help/helpplugin.h index 7dc4bd6b4bf..e2631afcade 100644 --- a/src/plugins/help/helpplugin.h +++ b/src/plugins/help/helpplugin.h @@ -98,6 +98,7 @@ private: void slotOpenSupportPage(); void slotReportBug(); + void slotSystemInformation(); void resetFilter(); void activateHelpMode();