diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp index e354928a7a4bcf4c0e47cac52a8838864525f265..3f2790a35489ec9a400d6e9afa40cfb380c92122 100644 --- a/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -63,6 +63,8 @@ const int categoryIconSize = 24; namespace Core { namespace Internal { +QPointer<SettingsDialog> SettingsDialog::m_instance = 0; + // ----------- Category model class Category { @@ -253,18 +255,20 @@ static inline QList<Core::IOptionsPage*> sortedOptionsPages() return rc; } -SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, - const QString &pageId) : +SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), m_pages(sortedOptionsPages()), m_proxyModel(new CategoryFilterModel(this)), m_model(new CategoryModel(this)), - m_applied(false), m_stackedLayout(new QStackedLayout), m_filterLineEdit(new Utils::FilterLineEdit), m_categoryList(new CategoryListView), - m_headerLabel(new QLabel) + m_headerLabel(new QLabel), + m_running(false), + m_applied(false) { + m_applied = false; + createGui(); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); #ifdef Q_OS_MAC @@ -275,31 +279,16 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, m_model->setPages(m_pages); - QString initialCategory = categoryId; - QString initialPage = pageId; - if (initialCategory.isEmpty() && initialPage.isEmpty()) { - QSettings *settings = ICore::instance()->settings(); - initialCategory = settings->value(QLatin1String(categoryKeyC), QVariant(QString())).toString(); - initialPage = settings->value(QLatin1String(pageKeyC), QVariant(QString())).toString(); - } - - int initialCategoryIndex = -1; - int initialPageIndex = -1; - // Create the tab widgets with the pages in each category const QList<Category*> &categories = m_model->categories(); for (int i = 0; i < categories.size(); ++i) { Category *category = categories.at(i); - if (category->id == initialCategory) - initialCategoryIndex = i; QTabWidget *tabWidget = new QTabWidget; for (int j = 0; j < category->pages.size(); ++j) { IOptionsPage *page = category->pages.at(j); QWidget *widget = page->createPage(0); tabWidget->addTab(widget, page->displayName()); - if (initialCategoryIndex == i && page->id() == initialPage) - initialPageIndex = j; } connect(tabWidget, SIGNAL(currentChanged(int)), @@ -319,18 +308,46 @@ SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, connect(m_categoryList->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(currentChanged(QModelIndex))); + // The order of the slot connection matters here, the filter slot + // opens the matching page after the model has filtered. + connect(m_filterLineEdit, SIGNAL(filterChanged(QString)), + m_proxyModel, SLOT(setFilterFixedString(QString))); + connect(m_filterLineEdit, SIGNAL(filterChanged(QString)), this, SLOT(filter(QString))); + m_categoryList->setFocus(); + setAttribute(Qt::WA_DeleteOnClose); +} + +void SettingsDialog::showPage(const QString &categoryId, const QString &pageId) +{ + // handle the case of "show last page" + QString initialCategory = categoryId; + QString initialPage = pageId; + if (initialCategory.isEmpty() && initialPage.isEmpty()) { + QSettings *settings = ICore::instance()->settings(); + initialCategory = settings->value(QLatin1String(categoryKeyC), QVariant(QString())).toString(); + initialPage = settings->value(QLatin1String(pageKeyC), QVariant(QString())).toString(); + } + + int initialCategoryIndex = -1; + int initialPageIndex = -1; + const QList<Category*> &categories = m_model->categories(); + for (int i = 0; i < categories.size(); ++i) { + Category *category = categories.at(i); + if (category->id == initialCategory) { + initialCategoryIndex = i; + for (int j = 0; j < category->pages.size(); ++j) { + IOptionsPage *page = category->pages.at(j); + if (page->id() == initialPage) + initialPageIndex = j; + } + } + } if (initialCategoryIndex != -1) { const QModelIndex modelIndex = m_proxyModel->mapFromSource(m_model->index(initialCategoryIndex)); m_categoryList->setCurrentIndex(modelIndex); if (initialPageIndex != -1) categories.at(initialCategoryIndex)->tabWidget->setCurrentIndex(initialPageIndex); } - - // The order of the slot connection matters here, the filter slot - // opens the matching page after the model has filtered. - connect(m_filterLineEdit, SIGNAL(filterChanged(QString)), - m_proxyModel, SLOT(setFilterFixedString(QString))); - connect(m_filterLineEdit, SIGNAL(filterChanged(QString)), this, SLOT(filter(QString))); } void SettingsDialog::createGui() @@ -464,19 +481,20 @@ void SettingsDialog::apply() m_applied = true; } -bool SettingsDialog::execDialog() -{ - m_categoryList->setFocus(); - m_applied = false; - exec(); - return m_applied; -} - void SettingsDialog::done(int val) { QSettings *settings = ICore::instance()->settings(); settings->setValue(QLatin1String(categoryKeyC), m_currentCategory); settings->setValue(QLatin1String(pageKeyC), m_currentPage); + + // exit all additional event loops, see comment in execDialog() + QListIterator<QEventLoop *> it(m_eventLoops); + it.toBack(); + while (it.hasPrevious()) { + QEventLoop *loop = it.previous(); + loop->exit(); + } + QDialog::done(val); } @@ -488,5 +506,38 @@ QSize SettingsDialog::sizeHint() const return minimumSize(); } +SettingsDialog *SettingsDialog::getSettingsDialog(QWidget *parent, + const QString &initialCategory, + const QString &initialPage) +{ + if (!m_instance) { + m_instance = new SettingsDialog(parent); + } + m_instance->showPage(initialCategory, initialPage); + return m_instance; +} + +bool SettingsDialog::execDialog() +{ + if (!m_running) { + m_running = true; + exec(); + } else { + // exec dialog is called while the instance is already running + // this can happen when a event triggers a code path that wants to + // show the settings dialog again + // e.g. when starting the debugger (with non-built debugging helpers), + // and manually opening the settings dialog, after the debugger hit + // a break point it will complain about missing helper, and offer the + // option to open the settings dialog. + // Keep the UI running by creating another event loop. + QEventLoop *loop = new QEventLoop(this); + m_eventLoops.append(loop); + loop->exec(); + } + return m_applied; +} + + } // namespace Internal } // namespace Core diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.h b/src/plugins/coreplugin/dialogs/settingsdialog.h index 632be74da0172c2adb210eb470648416f6816014..4172f036f871c8dc0e6d4eee858b3398c879d88c 100644 --- a/src/plugins/coreplugin/dialogs/settingsdialog.h +++ b/src/plugins/coreplugin/dialogs/settingsdialog.h @@ -34,6 +34,8 @@ #include <QtCore/QList> #include <QtCore/QSet> +#include <QtCore/QPointer> +#include <QtCore/QEventLoop> #include <QtGui/QDialog> QT_BEGIN_NAMESPACE @@ -59,13 +61,15 @@ class SettingsDialog : public QDialog Q_OBJECT public: - SettingsDialog(QWidget *parent, - const QString &initialCategory = QString(), - const QString &initialPage = QString()); - ~SettingsDialog(); - // Run the dialog and return true if 'Ok' was chosen or 'Apply' was invoked - // at least once + // Returns a settings dialog. This makes sure that always only + // a single settings dialog instance is running. + // The dialog will be deleted automatically on close. + static SettingsDialog *getSettingsDialog(QWidget *parent, + const QString &initialCategory = QString(), + const QString &initialPage = QString()); + // Run the dialog and wait for it to finish. + // Returns if the changes have been applied. bool execDialog(); virtual QSize sizeHint() const; @@ -82,8 +86,12 @@ private slots: void filter(const QString &text); private: + SettingsDialog(QWidget *parent); + ~SettingsDialog(); + void createGui(); void showCategory(int index); + void showPage(const QString &categoryId, const QString &pageId); void updateEnabledTabs(Category *category, const QString &searchText); const QList<Core::IOptionsPage*> m_pages; @@ -91,13 +99,16 @@ private: QSet<Core::IOptionsPage*> m_visitedPages; QSortFilterProxyModel *m_proxyModel; CategoryModel *m_model; - bool m_applied; QString m_currentCategory; QString m_currentPage; QStackedLayout *m_stackedLayout; Utils::FilterLineEdit *m_filterLineEdit; QListView *m_categoryList; QLabel *m_headerLabel; + bool m_running; + bool m_applied; + QList<QEventLoop *> m_eventLoops; + static QPointer<SettingsDialog> m_instance; }; } // namespace Internal diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index e20d9cde4e1ddc2e85b72d382e4841db57b39ace..e2edbfce8b50a16cf48fff233533d19b0b6fee4c 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -928,8 +928,8 @@ bool MainWindow::showOptionsDialog(const QString &category, emit m_coreImpl->optionsDialogRequested(); if (!parent) parent = this; - SettingsDialog dlg(parent, category, page); - return dlg.execDialog(); + SettingsDialog *dialog = SettingsDialog::getSettingsDialog(parent, category, page); + return dialog->execDialog(); } void MainWindow::saveAll()