From 461319954882f25743a78e747cfb27805726aa20 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 3 Jun 2020 15:56:43 +0200 Subject: [PATCH] Extract plugin install wizard It will become more complicated, so pull it into its own files. Change-Id: If362f0775cc9d97a3c715c046d32d6a20c30a1f9 Reviewed-by: Alessandro Portale --- src/plugins/coreplugin/CMakeLists.txt | 1 + src/plugins/coreplugin/coreplugin.pro | 6 +- src/plugins/coreplugin/coreplugin.qbs | 2 + src/plugins/coreplugin/plugindialog.cpp | 220 +------------- .../coreplugin/plugininstallwizard.cpp | 270 ++++++++++++++++++ src/plugins/coreplugin/plugininstallwizard.h | 42 +++ 6 files changed, 322 insertions(+), 219 deletions(-) create mode 100644 src/plugins/coreplugin/plugininstallwizard.cpp create mode 100644 src/plugins/coreplugin/plugininstallwizard.h diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt index 10b580ba257..c0a9682cbba 100644 --- a/src/plugins/coreplugin/CMakeLists.txt +++ b/src/plugins/coreplugin/CMakeLists.txt @@ -130,6 +130,7 @@ add_qtc_plugin(Core outputwindow.cpp outputwindow.h patchtool.cpp patchtool.h plugindialog.cpp plugindialog.h + plugininstallwizard.cpp plugininstallwizard.h progressmanager/futureprogress.cpp progressmanager/futureprogress.h progressmanager/progressbar.cpp progressmanager/progressbar.h progressmanager/progressmanager.cpp progressmanager/progressmanager.h progressmanager/progressmanager_p.h diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro index 495d02028a8..36c774a57e1 100644 --- a/src/plugins/coreplugin/coreplugin.pro +++ b/src/plugins/coreplugin/coreplugin.pro @@ -113,7 +113,8 @@ SOURCES += corejsextensions.cpp \ diffservice.cpp \ menubarfilter.cpp \ welcomepagehelper.cpp \ - dialogs/codecselector.cpp + dialogs/codecselector.cpp \ + plugininstallwizard.cpp HEADERS += corejsextensions.h \ mainwindow.h \ @@ -230,7 +231,8 @@ HEADERS += corejsextensions.h \ menubarfilter.h \ editormanager/ieditorfactory_p.h \ welcomepagehelper.h \ - dialogs/codecselector.h + dialogs/codecselector.h \ + plugininstallwizard.h FORMS += dialogs/newdialog.ui \ dialogs/saveitemsdialog.ui \ diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index 63dcd4ab6f3..3816c44113b 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -153,6 +153,8 @@ Project { "patchtool.h", "plugindialog.cpp", "plugindialog.h", + "plugininstallwizard.cpp", + "plugininstallwizard.h", "reaper.cpp", "reaper.h", "reaper_p.h", diff --git a/src/plugins/coreplugin/plugindialog.cpp b/src/plugins/coreplugin/plugindialog.cpp index 03c840eccce..d86930cd654 100644 --- a/src/plugins/coreplugin/plugindialog.cpp +++ b/src/plugins/coreplugin/plugindialog.cpp @@ -28,6 +28,7 @@ #include "icore.h" #include "dialogs/restartdialog.h" +#include "plugininstallwizard.h" #include @@ -37,24 +38,15 @@ #include #include -#include #include -#include -#include -#include -#include -#include #include #include #include #include -#include -#include #include #include #include -#include #include using namespace Utils; @@ -64,163 +56,6 @@ namespace Internal { static bool s_isRestartRequired = false; -const char kPath[] = "Path"; -const char kApplicationInstall[] = "ApplicationInstall"; - -static bool hasLibSuffix(const FilePath &path) -{ - return (HostOsInfo().isWindowsHost() && path.endsWith(".dll")) - || (HostOsInfo().isLinuxHost() && path.toFileInfo().completeSuffix().startsWith(".so")) - || (HostOsInfo().isMacHost() && path.endsWith(".dylib")); -} - -class SourcePage : public WizardPage -{ -public: - SourcePage(QWidget *parent) - : WizardPage(parent) - { - setTitle(PluginDialog::tr("Source")); - auto vlayout = new QVBoxLayout; - setLayout(vlayout); - - auto label = new QLabel( - "

" - + PluginDialog::tr( - "Choose source location. This can be a plugin library file or a zip file.") - + "

"); - label->setWordWrap(true); - vlayout->addWidget(label); - - auto path = new PathChooser; - path->setExpectedKind(PathChooser::Any); - vlayout->addWidget(path); - registerFieldWithName(kPath, path, "path", SIGNAL(pathChanged(QString))); - connect(path, &PathChooser::pathChanged, this, &SourcePage::updateWarnings); - - m_info = new InfoLabel; - m_info->setType(InfoLabel::Error); - m_info->setVisible(false); - vlayout->addWidget(m_info); - } - - void updateWarnings() - { - m_info->setVisible(!isComplete()); - emit completeChanged(); - } - - bool isComplete() const - { - const auto path = FilePath::fromVariant(field(kPath)); - if (!QFile::exists(path.toString())) { - m_info->setText(PluginDialog::tr("File does not exist.")); - return false; - } - if (hasLibSuffix(path)) - return true; - - QString error; - if (!Archive::supportsFile(path, &error)) { - m_info->setText(error); - return false; - } - return true; - } - - InfoLabel *m_info = nullptr; -}; - -class InstallLocationPage : public WizardPage -{ -public: - InstallLocationPage(QWidget *parent) - : WizardPage(parent) - { - setTitle(PluginDialog::tr("Install Location")); - auto vlayout = new QVBoxLayout; - setLayout(vlayout); - - auto label = new QLabel("

" + PluginDialog::tr("Choose install location.") + "

"); - label->setWordWrap(true); - vlayout->addWidget(label); - vlayout->addSpacing(10); - - auto localInstall = new QRadioButton(PluginDialog::tr("User plugins")); - localInstall->setChecked(true); - auto localLabel = new QLabel( - PluginDialog::tr("The plugin will be available to all compatible %1 " - "installations, but only for the current user.") - .arg(Constants::IDE_DISPLAY_NAME)); - localLabel->setWordWrap(true); - localLabel->setAttribute(Qt::WA_MacSmallSize, true); - - vlayout->addWidget(localInstall); - vlayout->addWidget(localLabel); - vlayout->addSpacing(10); - - auto appInstall = new QRadioButton( - PluginDialog::tr("%1 installation").arg(Constants::IDE_DISPLAY_NAME)); - auto appLabel = new QLabel( - PluginDialog::tr("The plugin will be available only to this %1 " - "installation, but for all users that can access it.") - .arg(Constants::IDE_DISPLAY_NAME)); - appLabel->setWordWrap(true); - appLabel->setAttribute(Qt::WA_MacSmallSize, true); - vlayout->addWidget(appInstall); - vlayout->addWidget(appLabel); - - auto group = new QButtonGroup(this); - group->addButton(localInstall); - group->addButton(appInstall); - - registerFieldWithName(kApplicationInstall, this); - setField(kApplicationInstall, false); - connect(appInstall, &QRadioButton::toggled, this, [this](bool toggled) { - setField(kApplicationInstall, toggled); - }); - } -}; - -static FilePath pluginInstallPath(QWizard *wizard) -{ - return FilePath::fromString(wizard->field(kApplicationInstall).toBool() - ? ICore::pluginPath() - : ICore::userPluginPath()); -} - -static FilePath pluginFilePath(QWizard *wizard) -{ - return FilePath::fromVariant(wizard->field(kPath)); -} - -class SummaryPage : public WizardPage -{ -public: - SummaryPage(QWidget *parent) - : WizardPage(parent) - { - setTitle(PluginDialog::tr("Summary")); - - auto vlayout = new QVBoxLayout; - setLayout(vlayout); - - m_summaryLabel = new QLabel(this); - m_summaryLabel->setWordWrap(true); - vlayout->addWidget(m_summaryLabel); - } - - void initializePage() - { - m_summaryLabel->setText(PluginDialog::tr("\"%1\" will be installed into \"%2\".") - .arg(pluginFilePath(wizard()).toUserOutput(), - pluginInstallPath(wizard()).toUserOutput())); - } - -private: - QLabel *m_summaryLabel; -}; - PluginDialog::PluginDialog(QWidget *parent) : QDialog(parent), m_view(new ExtensionSystem::PluginView(this)) @@ -298,59 +133,10 @@ void PluginDialog::closeDialog() accept(); } -static bool copyPluginFile(const FilePath &src, const FilePath &dest) -{ - const FilePath destFile = dest.pathAppended(src.fileName()); - if (QFile::exists(destFile.toString())) { - QMessageBox box(QMessageBox::Question, - PluginDialog::tr("Overwrite File"), - PluginDialog::tr("The file \"%1\" exists. Overwrite?") - .arg(destFile.toUserOutput()), - QMessageBox::Cancel, - ICore::dialogParent()); - QPushButton *acceptButton = box.addButton(PluginDialog::tr("Overwrite"), QMessageBox::AcceptRole); - box.setDefaultButton(acceptButton); - box.exec(); - if (box.clickedButton() != acceptButton) - return false; - QFile::remove(destFile.toString()); - } - QDir(dest.toString()).mkpath("."); - if (!QFile::copy(src.toString(), destFile.toString())) { - QMessageBox::warning(ICore::dialogParent(), - PluginDialog::tr("Failed to Write File"), - PluginDialog::tr("Failed to write file \"%1\".") - .arg(destFile.toUserOutput())); - return false; - } - return true; -} - void PluginDialog::showInstallWizard() { - Wizard wizard(ICore::dialogParent()); - wizard.setWindowTitle(tr("Install Plugin")); - - auto filePage = new SourcePage(&wizard); - wizard.addPage(filePage); - - auto installLocationPage = new InstallLocationPage(&wizard); - wizard.addPage(installLocationPage); - - auto summaryPage = new SummaryPage(&wizard); - wizard.addPage(summaryPage); - - if (wizard.exec()) { - const FilePath path = pluginFilePath(&wizard); - const FilePath installPath = pluginInstallPath(&wizard); - if (hasLibSuffix(path)) { - if (copyPluginFile(path, installPath)) - updateRestartRequired(); - } else if (Archive::supportsFile(path)) { - if (Archive::unarchive(path, installPath, ICore::dialogParent())) - updateRestartRequired(); - } - } + if (PluginInstallWizard::exec()) + updateRestartRequired(); } void PluginDialog::updateRestartRequired() diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp new file mode 100644 index 00000000000..9fa2ac76109 --- /dev/null +++ b/src/plugins/coreplugin/plugininstallwizard.cpp @@ -0,0 +1,270 @@ +/**************************************************************************** +** +** 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 "plugininstallwizard.h" + +#include "icore.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Utils; + +const char kPath[] = "Path"; +const char kApplicationInstall[] = "ApplicationInstall"; + +static bool hasLibSuffix(const FilePath &path) +{ + return (HostOsInfo().isWindowsHost() && path.endsWith(".dll")) + || (HostOsInfo().isLinuxHost() && path.toFileInfo().completeSuffix().startsWith(".so")) + || (HostOsInfo().isMacHost() && path.endsWith(".dylib")); +} + +namespace Core { +namespace Internal { + +class SourcePage : public WizardPage +{ +public: + SourcePage(QWidget *parent) + : WizardPage(parent) + { + setTitle(PluginInstallWizard::tr("Source")); + auto vlayout = new QVBoxLayout; + setLayout(vlayout); + + auto label = new QLabel( + "

" + + PluginInstallWizard::tr( + "Choose source location. This can be a plugin library file or a zip file.") + + "

"); + label->setWordWrap(true); + vlayout->addWidget(label); + + auto path = new PathChooser; + path->setExpectedKind(PathChooser::Any); + vlayout->addWidget(path); + registerFieldWithName(kPath, path, "path", SIGNAL(pathChanged(QString))); + connect(path, &PathChooser::pathChanged, this, &SourcePage::updateWarnings); + + m_info = new InfoLabel; + m_info->setType(InfoLabel::Error); + m_info->setVisible(false); + vlayout->addWidget(m_info); + } + + void updateWarnings() + { + m_info->setVisible(!isComplete()); + emit completeChanged(); + } + + bool isComplete() const + { + const auto path = FilePath::fromVariant(field(kPath)); + if (!QFile::exists(path.toString())) { + m_info->setText(PluginInstallWizard::tr("File does not exist.")); + return false; + } + if (hasLibSuffix(path)) + return true; + + QString error; + if (!Archive::supportsFile(path, &error)) { + m_info->setText(error); + return false; + } + return true; + } + + InfoLabel *m_info = nullptr; +}; + +class InstallLocationPage : public WizardPage +{ +public: + InstallLocationPage(QWidget *parent) + : WizardPage(parent) + { + setTitle(PluginInstallWizard::tr("Install Location")); + auto vlayout = new QVBoxLayout; + setLayout(vlayout); + + auto label = new QLabel("

" + PluginInstallWizard::tr("Choose install location.") + + "

"); + label->setWordWrap(true); + vlayout->addWidget(label); + vlayout->addSpacing(10); + + auto localInstall = new QRadioButton(PluginInstallWizard::tr("User plugins")); + localInstall->setChecked(true); + auto localLabel = new QLabel( + PluginInstallWizard::tr("The plugin will be available to all compatible %1 " + "installations, but only for the current user.") + .arg(Constants::IDE_DISPLAY_NAME)); + localLabel->setWordWrap(true); + localLabel->setAttribute(Qt::WA_MacSmallSize, true); + + vlayout->addWidget(localInstall); + vlayout->addWidget(localLabel); + vlayout->addSpacing(10); + + auto appInstall = new QRadioButton( + PluginInstallWizard::tr("%1 installation").arg(Constants::IDE_DISPLAY_NAME)); + auto appLabel = new QLabel( + PluginInstallWizard::tr("The plugin will be available only to this %1 " + "installation, but for all users that can access it.") + .arg(Constants::IDE_DISPLAY_NAME)); + appLabel->setWordWrap(true); + appLabel->setAttribute(Qt::WA_MacSmallSize, true); + vlayout->addWidget(appInstall); + vlayout->addWidget(appLabel); + + auto group = new QButtonGroup(this); + group->addButton(localInstall); + group->addButton(appInstall); + + registerFieldWithName(kApplicationInstall, this); + setField(kApplicationInstall, false); + connect(appInstall, &QRadioButton::toggled, this, [this](bool toggled) { + setField(kApplicationInstall, toggled); + }); + } +}; + +static FilePath pluginInstallPath(QWizard *wizard) +{ + return FilePath::fromString(wizard->field(kApplicationInstall).toBool() + ? ICore::pluginPath() + : ICore::userPluginPath()); +} + +static FilePath pluginFilePath(QWizard *wizard) +{ + return FilePath::fromVariant(wizard->field(kPath)); +} + +class SummaryPage : public WizardPage +{ +public: + SummaryPage(QWidget *parent) + : WizardPage(parent) + { + setTitle(PluginInstallWizard::tr("Summary")); + + auto vlayout = new QVBoxLayout; + setLayout(vlayout); + + m_summaryLabel = new QLabel(this); + m_summaryLabel->setWordWrap(true); + vlayout->addWidget(m_summaryLabel); + } + + void initializePage() + { + m_summaryLabel->setText(PluginInstallWizard::tr("\"%1\" will be installed into \"%2\".") + .arg(pluginFilePath(wizard()).toUserOutput(), + pluginInstallPath(wizard()).toUserOutput())); + } + +private: + QLabel *m_summaryLabel; +}; + +static bool copyPluginFile(const FilePath &src, const FilePath &dest) +{ + const FilePath destFile = dest.pathAppended(src.fileName()); + if (QFile::exists(destFile.toString())) { + QMessageBox box(QMessageBox::Question, + PluginInstallWizard::tr("Overwrite File"), + PluginInstallWizard::tr("The file \"%1\" exists. Overwrite?") + .arg(destFile.toUserOutput()), + QMessageBox::Cancel, + ICore::dialogParent()); + QPushButton *acceptButton = box.addButton(PluginInstallWizard::tr("Overwrite"), + QMessageBox::AcceptRole); + box.setDefaultButton(acceptButton); + box.exec(); + if (box.clickedButton() != acceptButton) + return false; + QFile::remove(destFile.toString()); + } + QDir(dest.toString()).mkpath("."); + if (!QFile::copy(src.toString(), destFile.toString())) { + QMessageBox::warning(ICore::dialogParent(), + PluginInstallWizard::tr("Failed to Write File"), + PluginInstallWizard::tr("Failed to write file \"%1\".") + .arg(destFile.toUserOutput())); + return false; + } + return true; +} + +bool PluginInstallWizard::exec() +{ + Wizard wizard(ICore::dialogParent()); + wizard.setWindowTitle(tr("Install Plugin")); + + auto filePage = new SourcePage(&wizard); + wizard.addPage(filePage); + + auto installLocationPage = new InstallLocationPage(&wizard); + wizard.addPage(installLocationPage); + + auto summaryPage = new SummaryPage(&wizard); + wizard.addPage(summaryPage); + + if (wizard.exec()) { + const FilePath path = pluginFilePath(&wizard); + const FilePath installPath = pluginInstallPath(&wizard); + if (hasLibSuffix(path)) { + if (copyPluginFile(path, installPath)) + return true; + } else if (Archive::supportsFile(path)) { + if (Archive::unarchive(path, installPath, ICore::dialogParent())) + return true; + } + } + return false; +} + +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/plugininstallwizard.h b/src/plugins/coreplugin/plugininstallwizard.h new file mode 100644 index 00000000000..b3c75e3189d --- /dev/null +++ b/src/plugins/coreplugin/plugininstallwizard.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** 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 + +namespace Core { +namespace Internal { + +class PluginInstallWizard +{ + Q_DECLARE_TR_FUNCTIONS(Core::Internal::PluginInstallWizard) + +public: + static bool exec(); +}; + +} // namespace Internal +} // namespace Core