From 4e7ee4687ba19e8b5e5a33fe457a92ebf0c55a61 Mon Sep 17 00:00:00 2001 From: Samuel Ghinet Date: Thu, 26 Aug 2021 20:02:55 +0300 Subject: [PATCH] Allow the NewDialog to be overridden by other plugins So that Qt Design Studio can set its own implementation for the New Project dialog box. Task-number: QDS-4490 Change-Id: Ie04b041a5b6e25b38416f53b0ee4943839c2f64f Reviewed-by: Eike Ziller --- src/plugins/coreplugin/CMakeLists.txt | 1 + src/plugins/coreplugin/coreplugin.pro | 2 + src/plugins/coreplugin/coreplugin.qbs | 1 + src/plugins/coreplugin/dialogs/newdialog.cpp | 489 +---------------- src/plugins/coreplugin/dialogs/newdialog.h | 72 +-- .../coreplugin/dialogs/newdialogwidget.cpp | 511 ++++++++++++++++++ .../coreplugin/dialogs/newdialogwidget.h | 96 ++++ src/plugins/coreplugin/icore.cpp | 16 +- src/plugins/coreplugin/icore.h | 5 + src/plugins/coreplugin/mainwindow.cpp | 2 +- 10 files changed, 653 insertions(+), 542 deletions(-) create mode 100644 src/plugins/coreplugin/dialogs/newdialogwidget.cpp create mode 100644 src/plugins/coreplugin/dialogs/newdialogwidget.h diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt index eabae35f2a3..c74ce4b3ae9 100644 --- a/src/plugins/coreplugin/CMakeLists.txt +++ b/src/plugins/coreplugin/CMakeLists.txt @@ -23,6 +23,7 @@ add_qtc_plugin(Core dialogs/filepropertiesdialog.cpp dialogs/filepropertiesdialog.h dialogs/filepropertiesdialog.ui dialogs/ioptionspage.cpp dialogs/ioptionspage.h dialogs/newdialog.cpp dialogs/newdialog.h dialogs/newdialog.ui + dialogs/newdialogwidget.cpp dialogs/newdialogwidget.h dialogs/openwithdialog.cpp dialogs/openwithdialog.h dialogs/openwithdialog.ui dialogs/promptoverwritedialog.cpp dialogs/promptoverwritedialog.h dialogs/readonlyfilesdialog.cpp dialogs/readonlyfilesdialog.h dialogs/readonlyfilesdialog.ui diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro index a16dbfa0388..39f2476a30e 100644 --- a/src/plugins/coreplugin/coreplugin.pro +++ b/src/plugins/coreplugin/coreplugin.pro @@ -44,6 +44,7 @@ SOURCES += corejsextensions.cpp \ actionmanager/actioncontainer.cpp \ actionmanager/commandsfile.cpp \ dialogs/saveitemsdialog.cpp \ + dialogs/newdialogwidget.cpp \ dialogs/newdialog.cpp \ dialogs/settingsdialog.cpp \ actionmanager/commandmappings.cpp \ @@ -148,6 +149,7 @@ HEADERS += corejsextensions.h \ actionmanager/actioncontainer_p.h \ actionmanager/commandsfile.h \ dialogs/saveitemsdialog.h \ + dialogs/newdialogwidget.h \ dialogs/newdialog.h \ dialogs/settingsdialog.h \ actionmanager/commandmappings.h \ diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index c88226fa320..177ed1a1f53 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -199,6 +199,7 @@ Project { "filepropertiesdialog.cpp", "filepropertiesdialog.h", "filepropertiesdialog.ui", "ioptionspage.cpp", "ioptionspage.h", "newdialog.cpp", "newdialog.h", "newdialog.ui", + "newdialogwidget.cpp", "newdialogwidget.h", "openwithdialog.cpp", "openwithdialog.h", "openwithdialog.ui", "promptoverwritedialog.cpp", "promptoverwritedialog.h", "readonlyfilesdialog.cpp", "readonlyfilesdialog.h", "readonlyfilesdialog.ui", diff --git a/src/plugins/coreplugin/dialogs/newdialog.cpp b/src/plugins/coreplugin/dialogs/newdialog.cpp index a8b5ae55a64..2f09933e73c 100644 --- a/src/plugins/coreplugin/dialogs/newdialog.cpp +++ b/src/plugins/coreplugin/dialogs/newdialog.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -23,504 +23,21 @@ ** ****************************************************************************/ -#include "newdialog.h" -#include "ui_newdialog.h" - -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -Q_DECLARE_METATYPE(Core::IWizardFactory*) - -using namespace Utils; - -namespace { - -const int ICON_SIZE = 48; -const char LAST_CATEGORY_KEY[] = "Core/NewDialog/LastCategory"; -const char LAST_PLATFORM_KEY[] = "Core/NewDialog/LastPlatform"; -const char ALLOW_ALL_TEMPLATES[] = "Core/NewDialog/AllowAllTemplates"; -const char SHOW_PLATOFORM_FILTER[] = "Core/NewDialog/ShowPlatformFilter"; -const char BLACKLISTED_CATEGORIES_KEY[] = "Core/NewDialog/BlacklistedCategories"; -const char ALTERNATIVE_WIZARD_STYLE[] = "Core/NewDialog/AlternativeWizardStyle"; +#include "newdialog.h" using namespace Core; -using namespace Core::Internal; -class WizardFactoryContainer -{ -public: - WizardFactoryContainer() = default; - WizardFactoryContainer(Core::IWizardFactory *w, int i): wizard(w), wizardOption(i) {} - Core::IWizardFactory *wizard = nullptr; - int wizardOption = 0; -}; - -inline Core::IWizardFactory *factoryOfItem(const QStandardItem *item = nullptr) -{ - if (!item) - return nullptr; - return item->data(Qt::UserRole).value().wizard; -} - -class PlatformFilterProxyModel : public QSortFilterProxyModel -{ -// Q_OBJECT -public: - PlatformFilterProxyModel(QObject *parent = nullptr): QSortFilterProxyModel(parent) - { - m_blacklistedCategories = - Id::fromStringList(ICore::settings()->value(BLACKLISTED_CATEGORIES_KEY).toStringList()); - } - - void setPlatform(Id platform) - { - m_platform = platform; - invalidateFilter(); - } - - void manualReset() - { - beginResetModel(); - endResetModel(); - } - - bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override - { - if (!sourceParent.isValid()) - return true; - - if (!sourceParent.parent().isValid()) { // category - const QModelIndex sourceCategoryIndex = sourceModel()->index(sourceRow, 0, sourceParent); - for (int i = 0; i < sourceModel()->rowCount(sourceCategoryIndex); ++i) - if (filterAcceptsRow(i, sourceCategoryIndex)) - return true; - return false; - } - - QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent); - Core::IWizardFactory *wizard = - factoryOfItem(qobject_cast(sourceModel())->itemFromIndex(sourceIndex)); - - if (wizard) { - if (m_blacklistedCategories.contains(Id::fromString(wizard->category()))) - return false; - return wizard->isAvailable(m_platform); - } - - return true; - } -private: - Id m_platform; - QSet m_blacklistedCategories; -}; - -#define ROW_HEIGHT 24 - -class FancyTopLevelDelegate : public QItemDelegate -{ -public: - FancyTopLevelDelegate(QObject *parent = nullptr) - : QItemDelegate(parent) {} - - void drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const override - { - QStyleOptionViewItem newoption = option; - if (!(option.state & QStyle::State_Enabled)) { - QLinearGradient gradient(rect.topLeft(), rect.bottomLeft()); - gradient.setColorAt(0, option.palette.window().color().lighter(106)); - gradient.setColorAt(1, option.palette.window().color().darker(106)); - painter->fillRect(rect, gradient); - painter->setPen(option.palette.window().color().darker(130)); - if (rect.top()) - painter->drawLine(rect.topRight(), rect.topLeft()); - painter->drawLine(rect.bottomRight(), rect.bottomLeft()); - - // Fake enabled state - newoption.state |= newoption.state | QStyle::State_Enabled; - } - - QItemDelegate::drawDisplay(painter, newoption, rect, text); - } - - QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override - { - QSize size = QItemDelegate::sizeHint(option, index); - - size = size.expandedTo(QSize(0, ROW_HEIGHT)); - - return size; - } -}; - -} - -Q_DECLARE_METATYPE(WizardFactoryContainer) - -using namespace Core; -using namespace Core::Internal; - -QWidget *NewDialog::m_currentDialog = nullptr; - -NewDialog::NewDialog(QWidget *parent) : - QDialog(parent), - m_ui(new Ui::NewDialog) +NewDialog::NewDialog() { QTC_CHECK(m_currentDialog == nullptr); m_currentDialog = this; - - setAttribute(Qt::WA_DeleteOnClose); - ICore::registerWindow(this, Context("Core.NewDialog")); - m_ui->setupUi(this); - QPalette p = m_ui->frame->palette(); - p.setColor(QPalette::Window, p.color(QPalette::Base)); - m_ui->frame->setPalette(p); - m_okButton = m_ui->buttonBox->button(QDialogButtonBox::Ok); - m_okButton->setDefault(true); - m_okButton->setText(tr("Choose...")); - - m_model = new QStandardItemModel(this); - - m_filterProxyModel = new PlatformFilterProxyModel(this); - m_filterProxyModel->setSourceModel(m_model); - - m_ui->templateCategoryView->setModel(m_filterProxyModel); - m_ui->templateCategoryView->setEditTriggers(QAbstractItemView::NoEditTriggers); - m_ui->templateCategoryView->setItemDelegate(new FancyTopLevelDelegate(this)); - - m_ui->templatesView->setModel(m_filterProxyModel); - m_ui->templatesView->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); - - const bool alternativeWizardStyle = ICore::settings()->value(ALTERNATIVE_WIZARD_STYLE, false).toBool(); - - if (alternativeWizardStyle) { - m_ui->templatesView->setGridSize(QSize(256, 128)); - m_ui->templatesView->setIconSize(QSize(96, 96)); - m_ui->templatesView->setSpacing(4); - - m_ui->templatesView->setViewMode(QListView::IconMode); - m_ui->templatesView->setMovement(QListView::Static); - m_ui->templatesView->setResizeMode(QListView::Adjust); - m_ui->templatesView->setSelectionRectVisible(false); - m_ui->templatesView->setWrapping(true); - m_ui->templatesView->setWordWrap(true); - } - - connect(m_ui->templateCategoryView->selectionModel(), &QItemSelectionModel::currentChanged, - this, &NewDialog::currentCategoryChanged); - - connect(m_ui->templatesView->selectionModel(), &QItemSelectionModel::currentChanged, - this, &NewDialog::currentItemChanged); - - connect(m_ui->templatesView, &QListView::doubleClicked, this, &NewDialog::accept); - connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &NewDialog::accept); - connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &NewDialog::reject); - - connect(m_ui->comboBox, QOverload::of(&QComboBox::currentIndexChanged), - this, &NewDialog::setSelectedPlatform); -} - -// Sort by category. id -static bool wizardFactoryLessThan(const IWizardFactory *f1, const IWizardFactory *f2) -{ - if (const int cc = f1->category().compare(f2->category())) - return cc < 0; - return f1->id().toString().compare(f2->id().toString()) < 0; -} - -void NewDialog::setWizardFactories(QList factories, - const FilePath &defaultLocation, - const QVariantMap &extraVariables) -{ - m_defaultLocation = defaultLocation; - m_extraVariables = extraVariables; - std::stable_sort(factories.begin(), factories.end(), wizardFactoryLessThan); - - m_model->clear(); - QStandardItem *parentItem = m_model->invisibleRootItem(); - - QStandardItem *projectKindItem = new QStandardItem(tr("Projects")); - projectKindItem->setData(IWizardFactory::ProjectWizard, Qt::UserRole); - projectKindItem->setFlags({}); // disable item to prevent focus - QStandardItem *filesKindItem = new QStandardItem(tr("Files and Classes")); - filesKindItem->setData(IWizardFactory::FileWizard, Qt::UserRole); - filesKindItem->setFlags({}); // disable item to prevent focus - - parentItem->appendRow(projectKindItem); - parentItem->appendRow(filesKindItem); - - if (m_dummyIcon.isNull()) - m_dummyIcon = QIcon(":/utils/images/wizardicon-file.png"); - - const QSet availablePlatforms = IWizardFactory::allAvailablePlatforms(); - - const bool allowAllTemplates = ICore::settings()->value(ALLOW_ALL_TEMPLATES, true).toBool(); - if (allowAllTemplates) - m_ui->comboBox->addItem(tr("All Templates"), Id().toSetting()); - - for (Id platform : availablePlatforms) { - const QString displayNameForPlatform = IWizardFactory::displayNameForPlatform(platform); - m_ui->comboBox->addItem(tr("%1 Templates").arg(displayNameForPlatform), platform.toSetting()); - } - - m_ui->comboBox->setCurrentIndex(0); // "All templates" - m_ui->comboBox->setEnabled(!availablePlatforms.isEmpty()); - - const bool showPlatformFilter = ICore::settings()->value(SHOW_PLATOFORM_FILTER, true).toBool(); - if (!showPlatformFilter) - m_ui->comboBox->hide(); - - for (IWizardFactory *factory : qAsConst(factories)) { - QStandardItem *kindItem; - switch (factory->kind()) { - case IWizardFactory::ProjectWizard: - kindItem = projectKindItem; - break; - case IWizardFactory::FileWizard: - default: - kindItem = filesKindItem; - break; - } - addItem(kindItem, factory); - } - if (projectKindItem->columnCount() == 0) - parentItem->removeRow(0); -} - -void NewDialog::showDialog() -{ - QModelIndex idx; - - QString lastPlatform = ICore::settings()->value(QLatin1String(LAST_PLATFORM_KEY)).toString(); - QString lastCategory = ICore::settings()->value(QLatin1String(LAST_CATEGORY_KEY)).toString(); - - if (!lastPlatform.isEmpty()) { - int index = m_ui->comboBox->findData(lastPlatform); - if (index != -1) - m_ui->comboBox->setCurrentIndex(index); - } - - static_cast(m_filterProxyModel)->manualReset(); - - if (!lastCategory.isEmpty()) - for (QStandardItem *item : qAsConst(m_categoryItems)) { - if (item->data(Qt::UserRole) == lastCategory) - idx = m_filterProxyModel->mapFromSource(m_model->indexFromItem(item)); - } - if (!idx.isValid()) - idx = m_filterProxyModel->index(0,0, m_filterProxyModel->index(0,0)); - - m_ui->templateCategoryView->setCurrentIndex(idx); - - // We need to set ensure that the category has default focus - m_ui->templateCategoryView->setFocus(Qt::NoFocusReason); - - for (int row = 0; row < m_filterProxyModel->rowCount(); ++row) - m_ui->templateCategoryView->setExpanded(m_filterProxyModel->index(row, 0), true); - - // Ensure that item description is visible on first show - currentItemChanged(m_filterProxyModel->index(0, 0, m_ui->templatesView->rootIndex())); - - updateOkButton(); - show(); -} - -Id NewDialog::selectedPlatform() const -{ - const int index = m_ui->comboBox->currentIndex(); - return Id::fromSetting(m_ui->comboBox->itemData(index)); -} - -QWidget *NewDialog::currentDialog() -{ - return m_currentDialog; -} - -bool NewDialog::event(QEvent *event) -{ - if (event->type() == QEvent::ShortcutOverride) { - auto ke = static_cast(event); - if (ke->key() == Qt::Key_Escape && !ke->modifiers()) { - ke->accept(); - return true; - } - } - return QDialog::event(event); } NewDialog::~NewDialog() { QTC_CHECK(m_currentDialog != nullptr); m_currentDialog = nullptr; - - delete m_ui; -} - -IWizardFactory *NewDialog::currentWizardFactory() const -{ - QModelIndex index = m_filterProxyModel->mapToSource(m_ui->templatesView->currentIndex()); - return factoryOfItem(m_model->itemFromIndex(index)); -} - -static QIcon iconWithText(const QIcon &icon, const QString &text) -{ - if (text.isEmpty()) - return icon; - QIcon iconWithText; - for (const QSize &pixmapSize : icon.availableSizes()) { - QPixmap pixmap = icon.pixmap(pixmapSize); - const int fontSize = pixmap.height() / 4; - const int margin = pixmap.height() / 8; - QFont font; - font.setPixelSize(fontSize); - font.setStretch(85); - QPainter p(&pixmap); - p.setFont(font); - QTextOption textOption(Qt::AlignHCenter | Qt::AlignBottom); - textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); - p.drawText(pixmap.rect().adjusted(margin, margin, -margin, -margin), text, textOption); - iconWithText.addPixmap(pixmap); - } - return iconWithText; -} - -void NewDialog::addItem(QStandardItem *topLevelCategoryItem, IWizardFactory *factory) -{ - const QString categoryName = factory->category(); - QStandardItem *categoryItem = nullptr; - for (int i = 0; i < topLevelCategoryItem->rowCount(); i++) { - if (topLevelCategoryItem->child(i, 0)->data(Qt::UserRole) == categoryName) - categoryItem = topLevelCategoryItem->child(i, 0); - } - if (!categoryItem) { - categoryItem = new QStandardItem(); - topLevelCategoryItem->appendRow(categoryItem); - m_categoryItems.append(categoryItem); - categoryItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); - categoryItem->setText(QLatin1String(" ") + factory->displayCategory()); - categoryItem->setData(factory->category(), Qt::UserRole); - } - - QStandardItem *wizardItem = new QStandardItem(factory->displayName()); - QIcon wizardIcon; - - // spacing hack. Add proper icons instead - if (factory->icon().isNull()) - wizardIcon = m_dummyIcon; - else - wizardIcon = factory->icon(); - wizardItem->setIcon(iconWithText(wizardIcon, factory->iconText())); - wizardItem->setData(QVariant::fromValue(WizardFactoryContainer(factory, 0)), Qt::UserRole); - wizardItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); - categoryItem->appendRow(wizardItem); - -} - -void NewDialog::currentCategoryChanged(const QModelIndex &index) -{ - if (index.parent() != m_model->invisibleRootItem()->index()) { - QModelIndex sourceIndex = m_filterProxyModel->mapToSource(index); - sourceIndex = m_filterProxyModel->mapFromSource(sourceIndex); - m_ui->templatesView->setRootIndex(sourceIndex); - // Focus the first item by default - m_ui->templatesView->setCurrentIndex( - m_filterProxyModel->index(0, 0, m_ui->templatesView->rootIndex())); - } -} - -void NewDialog::currentItemChanged(const QModelIndex &index) -{ - QModelIndex sourceIndex = m_filterProxyModel->mapToSource(index); - QStandardItem* cat = (m_model->itemFromIndex(sourceIndex)); - if (const IWizardFactory *wizard = factoryOfItem(cat)) { - QString desciption = wizard->description(); - QStringList displayNamesForSupportedPlatforms; - foreach (Id platform, wizard->supportedPlatforms()) - displayNamesForSupportedPlatforms << IWizardFactory::displayNameForPlatform(platform); - Utils::sort(displayNamesForSupportedPlatforms); - if (!Qt::mightBeRichText(desciption)) - desciption.replace(QLatin1Char('\n'), QLatin1String("
")); - desciption += QLatin1String("

"); - if (wizard->flags().testFlag(IWizardFactory::PlatformIndependent)) - desciption += tr("Platform independent") + QLatin1String(""); - else - desciption += tr("Supported Platforms") - + QLatin1String(":
    ") - + "
  • " + displayNamesForSupportedPlatforms.join("
  • ") + "
  • " - + QLatin1String("
"); - - m_ui->templateDescription->setHtml(desciption); - - if (!wizard->descriptionImage().isEmpty()) { - m_ui->imageLabel->setVisible(true); - m_ui->imageLabel->setPixmap(wizard->descriptionImage()); - } else { - m_ui->imageLabel->setVisible(false); - } - - } else { - m_ui->templateDescription->clear(); - } - updateOkButton(); -} - -void NewDialog::saveState() -{ - const QModelIndex filterIdx = m_ui->templateCategoryView->currentIndex(); - const QModelIndex idx = m_filterProxyModel->mapToSource(filterIdx); - QStandardItem *currentItem = m_model->itemFromIndex(idx); - if (currentItem) - ICore::settings()->setValue(LAST_CATEGORY_KEY, currentItem->data(Qt::UserRole)); - ICore::settings()->setValueWithDefault(LAST_PLATFORM_KEY, - m_ui->comboBox->currentData().toString()); -} - -static void runWizard(IWizardFactory *wizard, const QString &defaultLocation, Id platform, - const QVariantMap &variables) -{ - QString path = wizard->runPath(defaultLocation); - wizard->runWizard(path, ICore::dialogParent(), platform, variables); -} - -void NewDialog::accept() -{ - saveState(); - if (m_ui->templatesView->currentIndex().isValid()) { - IWizardFactory *wizard = currentWizardFactory(); - if (QTC_GUARD(wizard)) { - QMetaObject::invokeMethod(wizard, std::bind(&runWizard, wizard, m_defaultLocation.toString(), - selectedPlatform(), m_extraVariables), Qt::QueuedConnection); - } - } - QDialog::accept(); -} - -void NewDialog::reject() -{ - saveState(); - QDialog::reject(); -} - -void NewDialog::updateOkButton() -{ - m_okButton->setEnabled(currentWizardFactory() != nullptr); -} - -void NewDialog::setSelectedPlatform(int /*platform*/) -{ - //The static cast allows us to keep PlatformFilterProxyModel anonymous - static_cast(m_filterProxyModel)->setPlatform(selectedPlatform()); } diff --git a/src/plugins/coreplugin/dialogs/newdialog.h b/src/plugins/coreplugin/dialogs/newdialog.h index 07af7648423..a8c5c67a4e0 100644 --- a/src/plugins/coreplugin/dialogs/newdialog.h +++ b/src/plugins/coreplugin/dialogs/newdialog.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -25,72 +25,38 @@ #pragma once -#include "../iwizardfactory.h" +#include #include -#include -#include -#include -#include +#include "../core_global.h" QT_BEGIN_NAMESPACE -class QModelIndex; -class QSortFilterProxyModel; -class QPushButton; -class QStandardItem; -class QStandardItemModel; +class QWidget; QT_END_NAMESPACE namespace Core { -namespace Internal { - -namespace Ui { class NewDialog; } - -class NewDialog : public QDialog -{ - Q_OBJECT +class IWizardFactory; +class CORE_EXPORT NewDialog { public: - explicit NewDialog(QWidget *parent); - ~NewDialog() override; + NewDialog(); + virtual ~NewDialog() = 0; + virtual QWidget *widget() = 0; + virtual void setWizardFactories(QList factories, + const Utils::FilePath &defaultLocation, + const QVariantMap &extraVariables) = 0; + virtual void setWindowTitle(const QString &title) = 0; + virtual void showDialog() = 0; - void setWizardFactories(QList factories, - const Utils::FilePath &defaultLocation, - const QVariantMap &extraVariables); - - void showDialog(); - Utils::Id selectedPlatform() const; - - static QWidget *currentDialog(); - -protected: - bool event(QEvent *) override; + static QWidget *currentDialog() + { + return m_currentDialog ? m_currentDialog->widget() : nullptr; + } private: - void currentCategoryChanged(const QModelIndex &); - void currentItemChanged(const QModelIndex &); - void accept() override; - void reject() override; - void updateOkButton(); - void setSelectedPlatform(int index); - - Core::IWizardFactory *currentWizardFactory() const; - void addItem(QStandardItem *topLevelCategoryItem, IWizardFactory *factory); - void saveState(); - - static QWidget *m_currentDialog; - - Ui::NewDialog *m_ui; - QStandardItemModel *m_model; - QSortFilterProxyModel *m_filterProxyModel; - QPushButton *m_okButton = nullptr; - QIcon m_dummyIcon; - QList m_categoryItems; - Utils::FilePath m_defaultLocation; - QVariantMap m_extraVariables; + inline static NewDialog *m_currentDialog = nullptr; }; -} // namespace Internal } // namespace Core diff --git a/src/plugins/coreplugin/dialogs/newdialogwidget.cpp b/src/plugins/coreplugin/dialogs/newdialogwidget.cpp new file mode 100644 index 00000000000..c075442d8ee --- /dev/null +++ b/src/plugins/coreplugin/dialogs/newdialogwidget.cpp @@ -0,0 +1,511 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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 "newdialogwidget.h" +#include "ui_newdialog.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(Core::IWizardFactory*) + +using namespace Utils; + +namespace { + +const int ICON_SIZE = 48; +const char LAST_CATEGORY_KEY[] = "Core/NewDialog/LastCategory"; +const char LAST_PLATFORM_KEY[] = "Core/NewDialog/LastPlatform"; +const char ALLOW_ALL_TEMPLATES[] = "Core/NewDialog/AllowAllTemplates"; +const char SHOW_PLATOFORM_FILTER[] = "Core/NewDialog/ShowPlatformFilter"; +const char BLACKLISTED_CATEGORIES_KEY[] = "Core/NewDialog/BlacklistedCategories"; +const char ALTERNATIVE_WIZARD_STYLE[] = "Core/NewDialog/AlternativeWizardStyle"; + +using namespace Core; +using namespace Core::Internal; + +class WizardFactoryContainer +{ +public: + WizardFactoryContainer() = default; + WizardFactoryContainer(Core::IWizardFactory *w, int i): wizard(w), wizardOption(i) {} + Core::IWizardFactory *wizard = nullptr; + int wizardOption = 0; +}; + +inline Core::IWizardFactory *factoryOfItem(const QStandardItem *item = nullptr) +{ + if (!item) + return nullptr; + return item->data(Qt::UserRole).value().wizard; +} + +class PlatformFilterProxyModel : public QSortFilterProxyModel +{ +public: + PlatformFilterProxyModel(QObject *parent = nullptr): QSortFilterProxyModel(parent) + { + m_blacklistedCategories = + Id::fromStringList(ICore::settings()->value(BLACKLISTED_CATEGORIES_KEY).toStringList()); + } + + void setPlatform(Id platform) + { + m_platform = platform; + invalidateFilter(); + } + + void manualReset() + { + beginResetModel(); + endResetModel(); + } + + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override + { + if (!sourceParent.isValid()) + return true; + + if (!sourceParent.parent().isValid()) { // category + const QModelIndex sourceCategoryIndex = sourceModel()->index(sourceRow, 0, sourceParent); + for (int i = 0; i < sourceModel()->rowCount(sourceCategoryIndex); ++i) + if (filterAcceptsRow(i, sourceCategoryIndex)) + return true; + return false; + } + + QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent); + Core::IWizardFactory *wizard = + factoryOfItem(qobject_cast(sourceModel())->itemFromIndex(sourceIndex)); + + if (wizard) { + if (m_blacklistedCategories.contains(Id::fromString(wizard->category()))) + return false; + return wizard->isAvailable(m_platform); + } + + return true; + } +private: + Id m_platform; + QSet m_blacklistedCategories; +}; + +#define ROW_HEIGHT 24 + +class FancyTopLevelDelegate : public QItemDelegate +{ +public: + FancyTopLevelDelegate(QObject *parent = nullptr) + : QItemDelegate(parent) {} + + void drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const override + { + QStyleOptionViewItem newoption = option; + if (!(option.state & QStyle::State_Enabled)) { + QLinearGradient gradient(rect.topLeft(), rect.bottomLeft()); + gradient.setColorAt(0, option.palette.window().color().lighter(106)); + gradient.setColorAt(1, option.palette.window().color().darker(106)); + painter->fillRect(rect, gradient); + painter->setPen(option.palette.window().color().darker(130)); + if (rect.top()) + painter->drawLine(rect.topRight(), rect.topLeft()); + painter->drawLine(rect.bottomRight(), rect.bottomLeft()); + + // Fake enabled state + newoption.state |= newoption.state | QStyle::State_Enabled; + } + + QItemDelegate::drawDisplay(painter, newoption, rect, text); + } + + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override + { + QSize size = QItemDelegate::sizeHint(option, index); + + size = size.expandedTo(QSize(0, ROW_HEIGHT)); + + return size; + } +}; + +} + +Q_DECLARE_METATYPE(WizardFactoryContainer) + +using namespace Core; +using namespace Core::Internal; + +NewDialogWidget::NewDialogWidget(QWidget *parent) : + QDialog(parent), + m_ui(new Ui::NewDialog) +{ + setAttribute(Qt::WA_DeleteOnClose); + ICore::registerWindow(this, Context("Core.NewDialog")); + m_ui->setupUi(this); + QPalette p = m_ui->frame->palette(); + p.setColor(QPalette::Window, p.color(QPalette::Base)); + m_ui->frame->setPalette(p); + m_okButton = m_ui->buttonBox->button(QDialogButtonBox::Ok); + m_okButton->setDefault(true); + m_okButton->setText(tr("Choose...")); + + m_model = new QStandardItemModel(this); + + m_filterProxyModel = new PlatformFilterProxyModel(this); + m_filterProxyModel->setSourceModel(m_model); + + m_ui->templateCategoryView->setModel(m_filterProxyModel); + m_ui->templateCategoryView->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_ui->templateCategoryView->setItemDelegate(new FancyTopLevelDelegate(this)); + + m_ui->templatesView->setModel(m_filterProxyModel); + m_ui->templatesView->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); + + const bool alternativeWizardStyle = ICore::settings()->value(ALTERNATIVE_WIZARD_STYLE, false).toBool(); + + if (alternativeWizardStyle) { + m_ui->templatesView->setGridSize(QSize(256, 128)); + m_ui->templatesView->setIconSize(QSize(96, 96)); + m_ui->templatesView->setSpacing(4); + + m_ui->templatesView->setViewMode(QListView::IconMode); + m_ui->templatesView->setMovement(QListView::Static); + m_ui->templatesView->setResizeMode(QListView::Adjust); + m_ui->templatesView->setSelectionRectVisible(false); + m_ui->templatesView->setWrapping(true); + m_ui->templatesView->setWordWrap(true); + } + + connect(m_ui->templateCategoryView->selectionModel(), &QItemSelectionModel::currentChanged, + this, &NewDialogWidget::currentCategoryChanged); + + connect(m_ui->templatesView->selectionModel(), &QItemSelectionModel::currentChanged, + this, &NewDialogWidget::currentItemChanged); + + connect(m_ui->templatesView, &QListView::doubleClicked, this, &NewDialogWidget::accept); + connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &NewDialogWidget::accept); + connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &NewDialogWidget::reject); + + connect(m_ui->comboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &NewDialogWidget::setSelectedPlatform); +} + +// Sort by category. id +static bool wizardFactoryLessThan(const IWizardFactory *f1, const IWizardFactory *f2) +{ + if (const int cc = f1->category().compare(f2->category())) + return cc < 0; + return f1->id().toString().compare(f2->id().toString()) < 0; +} + +void NewDialogWidget::setWizardFactories(QList factories, + const FilePath &defaultLocation, + const QVariantMap &extraVariables) +{ + m_defaultLocation = defaultLocation; + m_extraVariables = extraVariables; + std::stable_sort(factories.begin(), factories.end(), wizardFactoryLessThan); + + m_model->clear(); + QStandardItem *parentItem = m_model->invisibleRootItem(); + + QStandardItem *projectKindItem = new QStandardItem(tr("Projects")); + projectKindItem->setData(IWizardFactory::ProjectWizard, Qt::UserRole); + projectKindItem->setFlags({}); // disable item to prevent focus + QStandardItem *filesKindItem = new QStandardItem(tr("Files and Classes")); + filesKindItem->setData(IWizardFactory::FileWizard, Qt::UserRole); + filesKindItem->setFlags({}); // disable item to prevent focus + + parentItem->appendRow(projectKindItem); + parentItem->appendRow(filesKindItem); + + if (m_dummyIcon.isNull()) + m_dummyIcon = QIcon(":/utils/images/wizardicon-file.png"); + + const QSet availablePlatforms = IWizardFactory::allAvailablePlatforms(); + + const bool allowAllTemplates = ICore::settings()->value(ALLOW_ALL_TEMPLATES, true).toBool(); + if (allowAllTemplates) + m_ui->comboBox->addItem(tr("All Templates"), Id().toSetting()); + + for (Id platform : availablePlatforms) { + const QString displayNameForPlatform = IWizardFactory::displayNameForPlatform(platform); + m_ui->comboBox->addItem(tr("%1 Templates").arg(displayNameForPlatform), platform.toSetting()); + } + + m_ui->comboBox->setCurrentIndex(0); // "All templates" + m_ui->comboBox->setEnabled(!availablePlatforms.isEmpty()); + + const bool showPlatformFilter = ICore::settings()->value(SHOW_PLATOFORM_FILTER, true).toBool(); + if (!showPlatformFilter) + m_ui->comboBox->hide(); + + for (IWizardFactory *factory : qAsConst(factories)) { + QStandardItem *kindItem; + switch (factory->kind()) { + case IWizardFactory::ProjectWizard: + kindItem = projectKindItem; + break; + case IWizardFactory::FileWizard: + default: + kindItem = filesKindItem; + break; + } + addItem(kindItem, factory); + } + if (projectKindItem->columnCount() == 0) + parentItem->removeRow(0); +} + +void NewDialogWidget::showDialog() +{ + QModelIndex idx; + + QString lastPlatform = ICore::settings()->value(QLatin1String(LAST_PLATFORM_KEY)).toString(); + QString lastCategory = ICore::settings()->value(QLatin1String(LAST_CATEGORY_KEY)).toString(); + + if (!lastPlatform.isEmpty()) { + int index = m_ui->comboBox->findData(lastPlatform); + if (index != -1) + m_ui->comboBox->setCurrentIndex(index); + } + + static_cast(m_filterProxyModel)->manualReset(); + + if (!lastCategory.isEmpty()) + for (QStandardItem *item : qAsConst(m_categoryItems)) { + if (item->data(Qt::UserRole) == lastCategory) + idx = m_filterProxyModel->mapFromSource(m_model->indexFromItem(item)); + } + if (!idx.isValid()) + idx = m_filterProxyModel->index(0,0, m_filterProxyModel->index(0,0)); + + m_ui->templateCategoryView->setCurrentIndex(idx); + + // We need to ensure that the category has default focus + m_ui->templateCategoryView->setFocus(Qt::NoFocusReason); + + for (int row = 0; row < m_filterProxyModel->rowCount(); ++row) + m_ui->templateCategoryView->setExpanded(m_filterProxyModel->index(row, 0), true); + + // Ensure that item description is visible on first show + currentItemChanged(m_filterProxyModel->index(0, 0, m_ui->templatesView->rootIndex())); + + updateOkButton(); + show(); +} + +Id NewDialogWidget::selectedPlatform() const +{ + const int index = m_ui->comboBox->currentIndex(); + return Id::fromSetting(m_ui->comboBox->itemData(index)); +} + +bool NewDialogWidget::event(QEvent *event) +{ + if (event->type() == QEvent::ShortcutOverride) { + auto ke = static_cast(event); + if (ke->key() == Qt::Key_Escape && !ke->modifiers()) { + ke->accept(); + return true; + } + } + return QDialog::event(event); +} + +NewDialogWidget::~NewDialogWidget() +{ + delete m_ui; +} + +IWizardFactory *NewDialogWidget::currentWizardFactory() const +{ + QModelIndex index = m_filterProxyModel->mapToSource(m_ui->templatesView->currentIndex()); + return factoryOfItem(m_model->itemFromIndex(index)); +} + +static QIcon iconWithText(const QIcon &icon, const QString &text) +{ + if (text.isEmpty()) + return icon; + QIcon iconWithText; + for (const QSize &pixmapSize : icon.availableSizes()) { + QPixmap pixmap = icon.pixmap(pixmapSize); + const int fontSize = pixmap.height() / 4; + const int margin = pixmap.height() / 8; + QFont font; + font.setPixelSize(fontSize); + font.setStretch(85); + QPainter p(&pixmap); + p.setFont(font); + QTextOption textOption(Qt::AlignHCenter | Qt::AlignBottom); + textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + p.drawText(pixmap.rect().adjusted(margin, margin, -margin, -margin), text, textOption); + iconWithText.addPixmap(pixmap); + } + return iconWithText; +} + +void NewDialogWidget::addItem(QStandardItem *topLevelCategoryItem, IWizardFactory *factory) +{ + const QString categoryName = factory->category(); + QStandardItem *categoryItem = nullptr; + for (int i = 0; i < topLevelCategoryItem->rowCount(); i++) { + if (topLevelCategoryItem->child(i, 0)->data(Qt::UserRole) == categoryName) + categoryItem = topLevelCategoryItem->child(i, 0); + } + if (!categoryItem) { + categoryItem = new QStandardItem(); + topLevelCategoryItem->appendRow(categoryItem); + m_categoryItems.append(categoryItem); + categoryItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); + categoryItem->setText(QLatin1String(" ") + factory->displayCategory()); + categoryItem->setData(factory->category(), Qt::UserRole); + } + + QStandardItem *wizardItem = new QStandardItem(factory->displayName()); + QIcon wizardIcon; + + // spacing hack. Add proper icons instead + if (factory->icon().isNull()) + wizardIcon = m_dummyIcon; + else + wizardIcon = factory->icon(); + wizardItem->setIcon(iconWithText(wizardIcon, factory->iconText())); + wizardItem->setData(QVariant::fromValue(WizardFactoryContainer(factory, 0)), Qt::UserRole); + wizardItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); + categoryItem->appendRow(wizardItem); + +} + +void NewDialogWidget::currentCategoryChanged(const QModelIndex &index) +{ + if (index.parent() != m_model->invisibleRootItem()->index()) { + QModelIndex sourceIndex = m_filterProxyModel->mapToSource(index); + sourceIndex = m_filterProxyModel->mapFromSource(sourceIndex); + m_ui->templatesView->setRootIndex(sourceIndex); + // Focus the first item by default + m_ui->templatesView->setCurrentIndex( + m_filterProxyModel->index(0, 0, m_ui->templatesView->rootIndex())); + } +} + +void NewDialogWidget::currentItemChanged(const QModelIndex &index) +{ + QModelIndex sourceIndex = m_filterProxyModel->mapToSource(index); + QStandardItem* cat = (m_model->itemFromIndex(sourceIndex)); + if (const IWizardFactory *wizard = factoryOfItem(cat)) { + QString desciption = wizard->description(); + QStringList displayNamesForSupportedPlatforms; + foreach (Id platform, wizard->supportedPlatforms()) + displayNamesForSupportedPlatforms << IWizardFactory::displayNameForPlatform(platform); + Utils::sort(displayNamesForSupportedPlatforms); + if (!Qt::mightBeRichText(desciption)) + desciption.replace(QLatin1Char('\n'), QLatin1String("
")); + desciption += QLatin1String("

"); + if (wizard->flags().testFlag(IWizardFactory::PlatformIndependent)) + desciption += tr("Platform independent") + QLatin1String(""); + else + desciption += tr("Supported Platforms") + + QLatin1String(":
    ") + + "
  • " + displayNamesForSupportedPlatforms.join("
  • ") + "
  • " + + QLatin1String("
"); + + m_ui->templateDescription->setHtml(desciption); + + if (!wizard->descriptionImage().isEmpty()) { + m_ui->imageLabel->setVisible(true); + m_ui->imageLabel->setPixmap(wizard->descriptionImage()); + } else { + m_ui->imageLabel->setVisible(false); + } + + } else { + m_ui->templateDescription->clear(); + } + updateOkButton(); +} + +void NewDialogWidget::saveState() +{ + const QModelIndex filterIdx = m_ui->templateCategoryView->currentIndex(); + const QModelIndex idx = m_filterProxyModel->mapToSource(filterIdx); + QStandardItem *currentItem = m_model->itemFromIndex(idx); + if (currentItem) + ICore::settings()->setValue(LAST_CATEGORY_KEY, currentItem->data(Qt::UserRole)); + ICore::settings()->setValueWithDefault(LAST_PLATFORM_KEY, + m_ui->comboBox->currentData().toString()); +} + +static void runWizard(IWizardFactory *wizard, const QString &defaultLocation, Id platform, + const QVariantMap &variables) +{ + QString path = wizard->runPath(defaultLocation); + wizard->runWizard(path, ICore::dialogParent(), platform, variables); +} + +void NewDialogWidget::accept() +{ + saveState(); + if (m_ui->templatesView->currentIndex().isValid()) { + IWizardFactory *wizard = currentWizardFactory(); + if (QTC_GUARD(wizard)) { + QMetaObject::invokeMethod(wizard, std::bind(&runWizard, wizard, m_defaultLocation.toString(), + selectedPlatform(), m_extraVariables), Qt::QueuedConnection); + } + } + QDialog::accept(); +} + +void NewDialogWidget::reject() +{ + saveState(); + QDialog::reject(); +} + +void NewDialogWidget::updateOkButton() +{ + m_okButton->setEnabled(currentWizardFactory() != nullptr); +} + +void NewDialogWidget::setSelectedPlatform(int /*platform*/) +{ + //The static cast allows us to keep PlatformFilterProxyModel anonymous + static_cast(m_filterProxyModel)->setPlatform(selectedPlatform()); +} diff --git a/src/plugins/coreplugin/dialogs/newdialogwidget.h b/src/plugins/coreplugin/dialogs/newdialogwidget.h new file mode 100644 index 00000000000..505c8ade222 --- /dev/null +++ b/src/plugins/coreplugin/dialogs/newdialogwidget.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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 "../iwizardfactory.h" +#include "newdialog.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QModelIndex; +class QSortFilterProxyModel; +class QPushButton; +class QStandardItem; +class QStandardItemModel; +QT_END_NAMESPACE + +namespace Core { + +namespace Internal { + +namespace Ui { class NewDialog; } + +class NewDialogWidget : public QDialog, public NewDialog +{ + Q_OBJECT + +public: + explicit NewDialogWidget(QWidget *parent); + ~NewDialogWidget() override; + + void setWizardFactories(QList factories, + const Utils::FilePath &defaultLocation, + const QVariantMap &extraVariables) override; + + void showDialog() override; + Utils::Id selectedPlatform() const; + QWidget *widget() override { return this; } + + void setWindowTitle(const QString &title) override { + QDialog::setWindowTitle(title); + } + +protected: + bool event(QEvent *) override; + +private: + void currentCategoryChanged(const QModelIndex &); + void currentItemChanged(const QModelIndex &); + void accept() override; + void reject() override; + void updateOkButton(); + void setSelectedPlatform(int index); + + Core::IWizardFactory *currentWizardFactory() const; + void addItem(QStandardItem *topLevelCategoryItem, IWizardFactory *factory); + void saveState(); + + Ui::NewDialog *m_ui; + QStandardItemModel *m_model; + QSortFilterProxyModel *m_filterProxyModel; + QPushButton *m_okButton = nullptr; + QIcon m_dummyIcon; + QList m_categoryItems; + Utils::FilePath m_defaultLocation; + QVariantMap m_extraVariables; +}; + +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index b8c19111267..c118533426a 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -141,6 +141,7 @@ from the focus object as well as the additional context. */ +#include "dialogs/newdialogwidget.h" #include "dialogs/newdialog.h" #include "iwizardfactory.h" #include "mainwindow.h" @@ -164,6 +165,9 @@ namespace Core { // The Core Singleton static ICore *m_instance = nullptr; static MainWindow *m_mainwindow = nullptr; +std::function ICore::m_newDialogFactory = [](QWidget *parent) { + return new NewDialogWidget(parent); +}; /*! Returns the pointer to the instance. Only use for connecting to signals. @@ -249,8 +253,8 @@ void ICore::showNewItemDialog(const QString &title, const QVariantMap &extraVariables) { QTC_ASSERT(!isNewItemDialogRunning(), return); - auto newDialog = new NewDialog(dialogParent()); - connect(newDialog, &QObject::destroyed, m_instance, &ICore::updateNewItemDialogState); + NewDialog *newDialog = ICore::m_newDialogFactory(dialogParent()); + connect(newDialog->widget(), &QObject::destroyed, m_instance, &ICore::updateNewItemDialogState); newDialog->setWizardFactories(factories, defaultLocation, extraVariables); newDialog->setWindowTitle(title); newDialog->showDialog(); @@ -944,4 +948,12 @@ void ICore::updateNewItemDialogState() emit instance()->newItemDialogStateChanged(); } +/*! + \internal +*/ +void ICore::setNewDialogFactory(const std::function &newFactory) +{ + m_newDialogFactory = newFactory; +} + } // namespace Core diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h index 321b030caff..589cf49765e 100644 --- a/src/plugins/coreplugin/icore.h +++ b/src/plugins/coreplugin/icore.h @@ -56,6 +56,8 @@ class SettingsDatabase; namespace Internal { class MainWindow; } +class NewDialog; + class CORE_EXPORT ICore : public QObject { Q_OBJECT @@ -174,9 +176,12 @@ public: static QStatusBar *statusBar(); static void saveSettings(SaveSettingsReason reason); + static void setNewDialogFactory(const std::function &newFactory); private: static void updateNewItemDialogState(); + + static std::function m_newDialogFactory; }; } // namespace Core diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 9157a448205..bc8e438dcfc 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -55,7 +55,7 @@ #include #include #include -#include +#include #include #include #include