Provide "Restart Now" functionality

And use it for the plugin dialog and when changing the UI language.

Change-Id: Ic767837d2526409f7ec46d7e4612a1499f19459e
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Eike Ziller
2020-01-03 16:47:15 +01:00
parent ad729a4085
commit be19b00289
17 changed files with 215 additions and 10 deletions

View File

@@ -32,6 +32,7 @@
#include <extensionsystem/pluginspec.h>
#include <qtsingleapplication.h>
#include <utils/algorithm.h>
#include <utils/environment.h>
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
@@ -56,6 +57,7 @@
#include <QApplication>
#include <QMessageBox>
#include <QProcess>
#include <QStandardPaths>
#include <QTemporaryDir>
@@ -356,6 +358,9 @@ struct Options
QString settingsPath;
QString installSettingsPath;
QStringList customPluginPaths;
// list of arguments that were handled and not passed to the application or plugin manager
QStringList preAppArguments;
// list of arguments to be passed to the application or plugin manager
std::vector<char *> appArguments;
Utils::optional<QString> userLibraryPath;
bool hasTestOption = false;
@@ -375,17 +380,22 @@ Options parseCommandLine(int argc, char *argv[])
if (arg == SETTINGS_OPTION && hasNext) {
++it;
options.settingsPath = QDir::fromNativeSeparators(nextArg);
options.preAppArguments << arg << nextArg;
} else if (arg == INSTALL_SETTINGS_OPTION && hasNext) {
++it;
options.installSettingsPath = QDir::fromNativeSeparators(nextArg);
options.preAppArguments << arg << nextArg;
} else if (arg == PLUGINPATH_OPTION && hasNext) {
++it;
options.customPluginPaths += QDir::fromNativeSeparators(nextArg);
options.preAppArguments << arg << nextArg;
} else if (arg == USER_LIBRARY_PATH_OPTION && hasNext) {
++it;
options.userLibraryPath = nextArg;
options.preAppArguments << arg << nextArg;
} else if (arg == TEMPORARY_CLEAN_SETTINGS1 || arg == TEMPORARY_CLEAN_SETTINGS2) {
options.wantsCleanSettings = true;
options.preAppArguments << arg;
} else { // arguments that are still passed on to the application
if (arg == TEST_OPTION)
options.hasTestOption = true;
@@ -396,8 +406,49 @@ Options parseCommandLine(int argc, char *argv[])
return options;
}
class Restarter
{
public:
Restarter(int argc, char *argv[])
{
Q_UNUSED(argc)
m_executable = QString::fromLocal8Bit(argv[0]);
m_workingPath = QDir::currentPath();
}
void setArguments(const QStringList &args) { m_args = args; }
QStringList arguments() const { return m_args; }
int restartOrExit(int exitCode)
{
return qApp->property("restart").toBool() ? restart(exitCode) : exitCode;
}
int restart(int exitCode)
{
QProcess::startDetached(m_executable, m_args, m_workingPath);
return exitCode;
}
private:
QString m_executable;
QStringList m_args;
QString m_workingPath;
};
QStringList lastSessionArgument()
{
// using insider information here is not particularly beautiful, anyhow
const bool hasProjectExplorer = Utils::anyOf(PluginManager::plugins(),
Utils::equal(&PluginSpec::name,
QString("ProjectExplorer")));
return hasProjectExplorer ? QStringList({"-lastsession"}) : QStringList();
}
int main(int argc, char **argv)
{
Restarter restarter(argc, argv);
Utils::Environment::systemEnvironment(); // cache system environment before we do any changes
// Manually determine various command line options
@@ -553,6 +604,8 @@ int main(int argc, char **argv)
return -1;
}
}
restarter.setArguments(options.preAppArguments + PluginManager::argumentsForRestart()
+ lastSessionArgument());
const PluginSpecSet plugins = PluginManager::plugins();
PluginSpec *coreplugin = nullptr;
@@ -638,5 +691,5 @@ int main(int argc, char **argv)
// shutdown plugin manager on the exit
QObject::connect(&app, &QCoreApplication::aboutToQuit, &pluginManager, &PluginManager::shutdown);
return app.exec();
return restarter.restartOrExit(app.exec());
}

View File

@@ -63,6 +63,7 @@ OptionsParser::OptionsParser(const QStringList &args,
if (m_foundAppOptions)
m_foundAppOptions->clear();
m_pmPrivate->arguments.clear();
m_pmPrivate->argumentsForRestart.clear();
}
bool OptionsParser::parse()
@@ -185,6 +186,7 @@ bool OptionsParser::checkForLoadOption()
m_isDependencyRefreshNeeded = true;
}
}
m_pmPrivate->argumentsForRestart << QLatin1String(LOAD_OPTION) << m_currentArg;
}
return true;
}
@@ -213,6 +215,7 @@ bool OptionsParser::checkForNoLoadOption()
m_isDependencyRefreshNeeded = true;
}
}
m_pmPrivate->argumentsForRestart << QLatin1String(NO_LOAD_OPTION) << m_currentArg;
}
return true;
}
@@ -247,8 +250,11 @@ bool OptionsParser::checkForPluginOption()
if (!spec)
return false;
spec->addArgument(m_currentArg);
if (requiresParameter && nextToken(RequiredToken))
m_pmPrivate->argumentsForRestart << m_currentArg;
if (requiresParameter && nextToken(RequiredToken)) {
spec->addArgument(m_currentArg);
m_pmPrivate->argumentsForRestart << m_currentArg;
}
return true;
}

View File

@@ -536,6 +536,17 @@ QStringList PluginManager::arguments()
return d->arguments;
}
/*!
The arguments that should be used when automatically restarting the application.
This includes plugin manager related options for enabling or disabling plugins,
but excludes others, like the arguments returned by arguments() and the appOptions
passed to the parseOptions() method.
*/
QStringList PluginManager::argumentsForRestart()
{
return d->argumentsForRestart;
}
/*!
List of all plugin specifications that have been found in the plugin search paths.
This list is valid directly after the setPluginPaths() call.

View File

@@ -106,6 +106,7 @@ public:
// command line arguments
static QStringList arguments();
static QStringList argumentsForRestart();
static bool parseOptions(const QStringList &args,
const QMap<QString, bool> &appOptions,
QMap<QString, QString> *foundAppOptions,

View File

@@ -118,6 +118,7 @@ public:
QEventLoop *shutdownEventLoop = nullptr; // used for async shutdown
QStringList arguments;
QStringList argumentsForRestart;
QScopedPointer<QElapsedTimer> m_profileTimer;
QHash<const PluginSpec *, int> m_profileTotal;
int m_profileElapsedMS = 0;

View File

@@ -25,6 +25,7 @@ add_qtc_plugin(Core
dialogs/openwithdialog.cpp dialogs/openwithdialog.h dialogs/openwithdialog.ui
dialogs/promptoverwritedialog.cpp dialogs/promptoverwritedialog.h
dialogs/readonlyfilesdialog.cpp dialogs/readonlyfilesdialog.h dialogs/readonlyfilesdialog.ui
dialogs/restartdialog.cpp dialogs/restartdialog.h
dialogs/saveitemsdialog.cpp dialogs/saveitemsdialog.h dialogs/saveitemsdialog.ui
dialogs/settingsdialog.cpp dialogs/settingsdialog.h
dialogs/shortcutsettings.cpp dialogs/shortcutsettings.h

View File

@@ -101,6 +101,7 @@ SOURCES += corejsextensions.cpp \
documentmanager.cpp \
iversioncontrol.cpp \
dialogs/addtovcsdialog.cpp \
dialogs/restartdialog.cpp \
ioutputpane.cpp \
patchtool.cpp \
windowsupport.cpp \
@@ -216,6 +217,7 @@ HEADERS += corejsextensions.h \
textdocument.h \
documentmanager.h \
dialogs/addtovcsdialog.h \
dialogs/restartdialog.h \
patchtool.h \
windowsupport.h \
opendocumentstreeview.h \

View File

@@ -216,6 +216,7 @@ Project {
"openwithdialog.cpp", "openwithdialog.h", "openwithdialog.ui",
"promptoverwritedialog.cpp", "promptoverwritedialog.h",
"readonlyfilesdialog.cpp", "readonlyfilesdialog.h", "readonlyfilesdialog.ui",
"restartdialog.cpp", "restartdialog.h",
"saveitemsdialog.cpp", "saveitemsdialog.h", "saveitemsdialog.ui",
"settingsdialog.cpp", "settingsdialog.h",
"shortcutsettings.cpp", "shortcutsettings.h",

View File

@@ -0,0 +1,49 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "restartdialog.h"
#include <coreplugin/icore.h>
#include <QPushButton>
#include <QTimer>
namespace Core {
RestartDialog::RestartDialog(QWidget *parent, const QString &text)
: QMessageBox(parent)
{
setWindowTitle(tr("Restart Required"));
setText(text);
setIcon(QMessageBox::Information);
addButton(tr("Later"), QMessageBox::NoRole);
addButton(tr("Restart Now"), QMessageBox::YesRole);
connect(this, &QDialog::accepted, this, [] {
QTimer::singleShot(0, ICore::instance(), [] { ICore::restart(); });
});
}
} // namespace Core

View File

@@ -0,0 +1,40 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <coreplugin/core_global.h>
#include <QMessageBox>
namespace Core {
class CORE_EXPORT RestartDialog : public QMessageBox
{
public:
RestartDialog(QWidget *parent, const QString &text);
};
} // namespace Core

View File

@@ -28,6 +28,8 @@
#include "icore.h"
#include "infobar.h"
#include <coreplugin/dialogs/restartdialog.h>
#include <utils/checkablemessagebox.h>
#include <utils/hostosinfo.h>
#include <utils/stylehelper.h>
@@ -199,9 +201,11 @@ QString GeneralSettings::language() const
void GeneralSettings::setLanguage(const QString &locale)
{
QSettings *settings = ICore::settings();
if (settings->value(QLatin1String("General/OverrideLanguage")).toString() != locale)
QMessageBox::information(ICore::mainWindow(), tr("Restart Required"),
tr("The language change will take effect after restart."));
if (settings->value(QLatin1String("General/OverrideLanguage")).toString() != locale) {
RestartDialog dialog(ICore::dialogParent(),
tr("The language change will take effect after restart."));
dialog.exec();
}
if (locale.isEmpty())
settings->remove(QLatin1String("General/OverrideLanguage"));

View File

@@ -710,6 +710,11 @@ void ICore::setupScreenShooter(const QString &name, QWidget *w, const QRect &rc)
new ScreenShooter(w, name, rc);
}
void ICore::restart()
{
m_mainwindow->restart();
}
void ICore::saveSettings(SaveSettingsReason reason)
{
emit m_instance->saveSettingsRequested(reason);

View File

@@ -153,6 +153,8 @@ public:
MainWindowClosing,
};
static void restart();
public slots:
static void saveSettings(SaveSettingsReason reason);

View File

@@ -329,8 +329,24 @@ void MainWindow::extensionsInitialized()
QTimer::singleShot(0, m_coreImpl, &ICore::coreOpened);
}
static void setRestart(bool restart)
{
qApp->setProperty("restart", restart);
}
void MainWindow::restart()
{
setRestart(true);
exit();
}
void MainWindow::closeEvent(QCloseEvent *event)
{
const auto cancelClose = [event] {
event->ignore();
setRestart(false);
};
// work around QTBUG-43344
static bool alreadyClosed = false;
if (alreadyClosed) {
@@ -342,13 +358,13 @@ void MainWindow::closeEvent(QCloseEvent *event)
// Save opened files
if (!DocumentManager::saveAllModifiedDocuments()) {
event->ignore();
cancelClose();
return;
}
foreach (const std::function<bool()> &listener, m_preCloseListeners) {
if (!listener()) {
event->ignore();
cancelClose();
return;
}
}

View File

@@ -108,6 +108,8 @@ public:
void saveSettings();
void restart();
public slots:
void openFileWith();
void exit();

View File

@@ -25,6 +25,10 @@
#include "plugindialog.h"
#include "icore.h"
#include "dialogs/restartdialog.h"
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginview.h>
#include <extensionsystem/plugindetailsview.h>
@@ -116,6 +120,11 @@ PluginDialog::PluginDialog(QWidget *parent)
void PluginDialog::closeDialog()
{
ExtensionSystem::PluginManager::writeSettings();
if (s_isRestartRequired) {
RestartDialog restartDialog(ICore::dialogParent(),
tr("Plugin changes will take effect after restart."));
restartDialog.exec();
}
accept();
}

View File

@@ -28,6 +28,8 @@
#include "manhattanstyle.h"
#include "themechooser.h"
#include "dialogs/restartdialog.h"
#include <utils/algorithm.h>
#include <utils/theme/theme.h>
#include <utils/theme/theme_p.h>
@@ -178,11 +180,11 @@ void ThemeChooser::apply()
QSettings *settings = ICore::settings();
const QString currentThemeId = ThemeEntry::themeSetting().toString();
if (currentThemeId != themeId) {
QMessageBox::information(ICore::mainWindow(), tr("Restart Required"),
tr("The theme change will take effect after restart."));
// save filename of selected theme in global config
settings->setValue(QLatin1String(Constants::SETTINGS_THEME), themeId);
RestartDialog restartDialog(ICore::dialogParent(),
tr("The theme change will take effect after restart."));
restartDialog.exec();
}
}