forked from qt-creator/qt-creator
Add a menu entry for copying system information
Which outputs the information from qtdiag, installed plugins, and general Qt Creator build information. Task-number: QTCREATORBUG-16135 Change-Id: I618b9883369bae45006bb109f8757e89b091b882 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QLibrary>
|
#include <QLibrary>
|
||||||
|
#include <QLibraryInfo>
|
||||||
#include <QMetaProperty>
|
#include <QMetaProperty>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
@@ -47,7 +48,9 @@
|
|||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/executeondestruction.h>
|
#include <utils/executeondestruction.h>
|
||||||
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/synchronousprocess.h>
|
||||||
|
|
||||||
#ifdef WITH_TESTS
|
#ifdef WITH_TESTS
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
@@ -270,6 +273,7 @@ enum { debugLeaks = 0 };
|
|||||||
|
|
||||||
using namespace ExtensionSystem;
|
using namespace ExtensionSystem;
|
||||||
using namespace ExtensionSystem::Internal;
|
using namespace ExtensionSystem::Internal;
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
static Internal::PluginManagerPrivate *d = 0;
|
static Internal::PluginManagerPrivate *d = 0;
|
||||||
static PluginManager *m_instance = 0;
|
static PluginManager *m_instance = 0;
|
||||||
@@ -420,6 +424,33 @@ void PluginManager::shutdown()
|
|||||||
d->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.
|
The list of paths were the plugin manager searches for plugins.
|
||||||
|
|
||||||
@@ -525,7 +556,7 @@ QStringList PluginManager::arguments()
|
|||||||
|
|
||||||
\sa setPluginPaths()
|
\sa setPluginPaths()
|
||||||
*/
|
*/
|
||||||
QList<PluginSpec *> PluginManager::plugins()
|
const QList<PluginSpec *> PluginManager::plugins()
|
||||||
{
|
{
|
||||||
return d->pluginSpecs;
|
return d->pluginSpecs;
|
||||||
}
|
}
|
||||||
@@ -1019,7 +1050,7 @@ static int executeTestPlan(const TestPlan &testPlan)
|
|||||||
<< QLatin1String("-maxwarnings") << QLatin1String("0"); // unlimit output
|
<< QLatin1String("-maxwarnings") << QLatin1String("0"); // unlimit output
|
||||||
qExecArguments << functions;
|
qExecArguments << functions;
|
||||||
// avoid being stuck in QTBUG-24925
|
// avoid being stuck in QTBUG-24925
|
||||||
if (!Utils::HostOsInfo::isWindowsHost())
|
if (!HostOsInfo::isWindowsHost())
|
||||||
qExecArguments << "-nocrashhandler";
|
qExecArguments << "-nocrashhandler";
|
||||||
failedTests += QTest::qExec(testObject, qExecArguments);
|
failedTests += QTest::qExec(testObject, qExecArguments);
|
||||||
}
|
}
|
||||||
@@ -1123,7 +1154,7 @@ void PluginManagerPrivate::startTests()
|
|||||||
continue; // plugin not loaded
|
continue; // plugin not loaded
|
||||||
|
|
||||||
const QList<QObject *> testObjects = plugin->createTestObjects();
|
const QList<QObject *> testObjects = plugin->createTestObjects();
|
||||||
Utils::ExecuteOnDestruction deleteTestObjects([&]() { qDeleteAll(testObjects); });
|
ExecuteOnDestruction deleteTestObjects([&]() { qDeleteAll(testObjects); });
|
||||||
Q_UNUSED(deleteTestObjects)
|
Q_UNUSED(deleteTestObjects)
|
||||||
|
|
||||||
const bool hasDuplicateTestObjects = testObjects.size() != testObjects.toSet().size();
|
const bool hasDuplicateTestObjects = testObjects.size() != testObjects.toSet().size();
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ public:
|
|||||||
static void setPluginPaths(const QStringList &paths);
|
static void setPluginPaths(const QStringList &paths);
|
||||||
static QString pluginIID();
|
static QString pluginIID();
|
||||||
static void setPluginIID(const QString &iid);
|
static void setPluginIID(const QString &iid);
|
||||||
static QList<PluginSpec *> plugins();
|
static const QList<PluginSpec *> plugins();
|
||||||
static QHash<QString, QList<PluginSpec *>> pluginCollections();
|
static QHash<QString, QList<PluginSpec *>> pluginCollections();
|
||||||
static bool hasError();
|
static bool hasError();
|
||||||
static QSet<PluginSpec *> pluginsRequiringPlugin(PluginSpec *spec);
|
static QSet<PluginSpec *> pluginsRequiringPlugin(PluginSpec *spec);
|
||||||
@@ -150,6 +150,8 @@ public:
|
|||||||
void remoteArguments(const QString &serializedArguments, QObject *socket);
|
void remoteArguments(const QString &serializedArguments, QObject *socket);
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
|
QString systemInformation() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void objectAdded(QObject *obj);
|
void objectAdded(QObject *obj);
|
||||||
void aboutToRemoveObject(QObject *obj);
|
void aboutToRemoveObject(QObject *obj);
|
||||||
|
|||||||
@@ -563,7 +563,6 @@ void ICore::openFiles(const QStringList &arguments, ICore::OpenFilesFlags flags)
|
|||||||
m_mainwindow->openFiles(arguments, flags);
|
m_mainwindow->openFiles(arguments, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn ICore::addCloseCoreListener
|
\fn ICore::addCloseCoreListener
|
||||||
|
|
||||||
@@ -580,6 +579,20 @@ void ICore::addPreCloseListener(const std::function<bool ()> &listener)
|
|||||||
m_mainwindow->addPreCloseListener(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()
|
void ICore::saveSettings()
|
||||||
{
|
{
|
||||||
emit m_instance->saveSettingsRequested();
|
emit m_instance->saveSettingsRequested();
|
||||||
|
|||||||
@@ -130,6 +130,8 @@ public:
|
|||||||
|
|
||||||
static void addPreCloseListener(const std::function<bool()> &listener);
|
static void addPreCloseListener(const std::function<bool()> &listener);
|
||||||
|
|
||||||
|
static QString systemInformation();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
static void saveSettings();
|
static void saveSettings();
|
||||||
|
|
||||||
|
|||||||
@@ -79,9 +79,12 @@
|
|||||||
#include <utils/theme/theme.h>
|
#include <utils/theme/theme.h>
|
||||||
#include <utils/tooltip/tooltip.h>
|
#include <utils/tooltip/tooltip.h>
|
||||||
|
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QDialog>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
#include <qplugin.h>
|
#include <qplugin.h>
|
||||||
@@ -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);
|
ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
|
||||||
connect(action, &QAction::triggered, this, &HelpPlugin::slotReportBug);
|
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)) {
|
if (ActionContainer *windowMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW)) {
|
||||||
// reuse EditorManager constants to avoid a second pair of menu actions
|
// reuse EditorManager constants to avoid a second pair of menu actions
|
||||||
// Goto Previous In History Action
|
// Goto Previous In History Action
|
||||||
@@ -647,6 +655,54 @@ void HelpPlugin::slotReportBug()
|
|||||||
QDesktopServices::openUrl(QUrl("https://bugreports.qt.io"));
|
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<QKeyEvent *>(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()
|
void HelpPlugin::doSetupIfNeeded()
|
||||||
{
|
{
|
||||||
LocalHelpManager::setupGuiHelpEngine();
|
LocalHelpManager::setupGuiHelpEngine();
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ private:
|
|||||||
|
|
||||||
void slotOpenSupportPage();
|
void slotOpenSupportPage();
|
||||||
void slotReportBug();
|
void slotReportBug();
|
||||||
|
void slotSystemInformation();
|
||||||
|
|
||||||
void resetFilter();
|
void resetFilter();
|
||||||
void activateHelpMode();
|
void activateHelpMode();
|
||||||
|
|||||||
Reference in New Issue
Block a user