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:
Eike Ziller
2016-08-31 15:39:52 +02:00
parent 9a0a2a7d27
commit f38531effb
6 changed files with 110 additions and 5 deletions

View File

@@ -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();

View File

@@ -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);

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -98,6 +98,7 @@ private:
void slotOpenSupportPage(); void slotOpenSupportPage();
void slotReportBug(); void slotReportBug();
void slotSystemInformation();
void resetFilter(); void resetFilter();
void activateHelpMode(); void activateHelpMode();