aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhjk <hjk@qt.io>2023-11-21 14:52:14 +0100
committerhjk <hjk@qt.io>2023-11-21 17:09:02 +0000
commit00e3c59981b8266f6f6b415efeab0631f497e462 (patch)
tree91289154ef509ca9a9e68c42bdfc93395da4278b
parentea7de2ec51ac841f1658ab9b80fd96e4a27ad315 (diff)
Todo: Merge optionsdialog to settings file pair
First babystep towards aspectified settings. Change-Id: I05647f758066acf132331b58b43979f114069140 Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
-rw-r--r--src/plugins/todo/CMakeLists.txt1
-rw-r--r--src/plugins/todo/optionsdialog.cpp257
-rw-r--r--src/plugins/todo/optionsdialog.h19
-rw-r--r--src/plugins/todo/settings.cpp262
-rw-r--r--src/plugins/todo/settings.h8
-rw-r--r--src/plugins/todo/todo.qbs2
-rw-r--r--src/plugins/todo/todoplugin.cpp4
7 files changed, 264 insertions, 289 deletions
diff --git a/src/plugins/todo/CMakeLists.txt b/src/plugins/todo/CMakeLists.txt
index ac9b61e3096..a50e3982daf 100644
--- a/src/plugins/todo/CMakeLists.txt
+++ b/src/plugins/todo/CMakeLists.txt
@@ -7,7 +7,6 @@ add_qtc_plugin(Todo
keyword.cpp keyword.h
keyworddialog.cpp keyworddialog.h
lineparser.cpp lineparser.h
- optionsdialog.cpp optionsdialog.h
qmljstodoitemsscanner.cpp qmljstodoitemsscanner.h
settings.cpp settings.h
todoicons.cpp todoicons.h
diff --git a/src/plugins/todo/optionsdialog.cpp b/src/plugins/todo/optionsdialog.cpp
deleted file mode 100644
index 3b300a7d10c..00000000000
--- a/src/plugins/todo/optionsdialog.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright (C) 2016 Dmitry Savchenko
-// Copyright (C) 2016 Vasiliy Sorokin
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "optionsdialog.h"
-
-#include "constants.h"
-#include "keyword.h"
-#include "keyworddialog.h"
-#include "settings.h"
-#include "todotr.h"
-
-#include <utils/layoutbuilder.h>
-
-#include <QGroupBox>
-#include <QListWidget>
-#include <QPushButton>
-#include <QRadioButton>
-
-namespace Todo::Internal {
-
-class OptionsDialog final : public Core::IOptionsPageWidget
-{
-public:
- OptionsDialog(Settings *settings, const std::function<void ()> &onApply);
-
- void apply() final;
-
- void setSettings(const Settings &settings);
-
-private:
- void addKeywordButtonClicked();
- void editKeywordButtonClicked();
- void removeKeywordButtonClicked();
- void resetKeywordsButtonClicked();
- void setKeywordsButtonsEnabled();
- Settings settingsFromUi();
- void addToKeywordsList(const Keyword &keyword);
- void editKeyword(QListWidgetItem *item);
- QSet<QString> keywordNames();
-
- Settings *m_settings = nullptr;
- std::function<void()> m_onApply;
-
- QListWidget *m_keywordsList;
- QPushButton *m_editKeywordButton;
- QPushButton *m_removeKeywordButton;
- QPushButton *resetKeywordsButton;
- QRadioButton *m_scanInProjectRadioButton;
- QRadioButton *m_scanInCurrentFileRadioButton;
- QRadioButton *m_scanInSubprojectRadioButton;
-};
-
-OptionsDialog::OptionsDialog(Settings *settings, const std::function<void ()> &onApply)
- : m_settings(settings), m_onApply(onApply)
-{
- m_keywordsList = new QListWidget;
- m_keywordsList->setDragDropMode(QAbstractItemView::DragDrop);
- m_keywordsList->setDefaultDropAction(Qt::MoveAction);
- m_keywordsList->setSelectionBehavior(QAbstractItemView::SelectRows);
- m_keywordsList->setSortingEnabled(false);
-
- auto addKeywordButton = new QPushButton(Tr::tr("Add"));
- m_editKeywordButton = new QPushButton(Tr::tr("Edit"));
- m_removeKeywordButton = new QPushButton(Tr::tr("Remove"));
- resetKeywordsButton = new QPushButton(Tr::tr("Reset"));
-
- m_scanInProjectRadioButton = new QRadioButton(Tr::tr("Scan the whole active project"));
- m_scanInProjectRadioButton->setEnabled(true);
-
- m_scanInCurrentFileRadioButton = new QRadioButton(Tr::tr("Scan only the currently edited document"));
- m_scanInCurrentFileRadioButton->setChecked(true);
-
- m_scanInSubprojectRadioButton = new QRadioButton(Tr::tr("Scan the current subproject"));
-
- using namespace Layouting;
-
- Column {
- Group {
- title(Tr::tr("Keywords")),
- Row {
- m_keywordsList,
- Column {
- addKeywordButton,
- m_editKeywordButton,
- m_removeKeywordButton,
- resetKeywordsButton,
- st
- }
- }
- },
- Group {
- title(Tr::tr("Scanning scope")),
- Column {
- m_scanInProjectRadioButton,
- m_scanInCurrentFileRadioButton,
- m_scanInSubprojectRadioButton
- }
- }
- }.attachTo(this);
-
- m_keywordsList->setIconSize(QSize(16, 16));
- setKeywordsButtonsEnabled();
- connect(addKeywordButton, &QAbstractButton::clicked,
- this, &OptionsDialog::addKeywordButtonClicked);
- connect(m_removeKeywordButton, &QAbstractButton::clicked,
- this, &OptionsDialog::removeKeywordButtonClicked);
- connect(m_editKeywordButton, &QAbstractButton::clicked,
- this, &OptionsDialog::editKeywordButtonClicked);
- connect(resetKeywordsButton, &QAbstractButton::clicked,
- this, &OptionsDialog::resetKeywordsButtonClicked);
- connect(m_keywordsList, &QListWidget::itemDoubleClicked,
- this, &OptionsDialog::editKeyword);
- connect(m_keywordsList, &QListWidget::itemSelectionChanged,
- this, &OptionsDialog::setKeywordsButtonsEnabled);
-
- setSettings(*m_settings);
-}
-
-void OptionsDialog::addToKeywordsList(const Keyword &keyword)
-{
- auto item = new QListWidgetItem(icon(keyword.iconType), keyword.name);
- item->setData(Qt::UserRole, static_cast<int>(keyword.iconType));
- item->setForeground(keyword.color);
- m_keywordsList->addItem(item);
-}
-
-QSet<QString> OptionsDialog::keywordNames()
-{
- const KeywordList keywords = settingsFromUi().keywords;
-
- QSet<QString> result;
- for (const Keyword &keyword : keywords)
- result << keyword.name;
-
- return result;
-}
-
-void OptionsDialog::addKeywordButtonClicked()
-{
- Keyword keyword;
- KeywordDialog keywordDialog(keyword, keywordNames(), this);
- if (keywordDialog.exec() == QDialog::Accepted) {
- keyword = keywordDialog.keyword();
- addToKeywordsList(keyword);
- }
-}
-
-void OptionsDialog::editKeywordButtonClicked()
-{
- QListWidgetItem *item = m_keywordsList->currentItem();
- editKeyword(item);
-}
-
-void OptionsDialog::editKeyword(QListWidgetItem *item)
-{
- Keyword keyword;
- keyword.name = item->text();
- keyword.iconType = static_cast<IconType>(item->data(Qt::UserRole).toInt());
- keyword.color = item->foreground().color();
-
- QSet<QString> keywordNamesButThis = keywordNames();
- keywordNamesButThis.remove(keyword.name);
-
- KeywordDialog keywordDialog(keyword, keywordNamesButThis, this);
- if (keywordDialog.exec() == QDialog::Accepted) {
- keyword = keywordDialog.keyword();
- item->setIcon(icon(keyword.iconType));
- item->setText(keyword.name);
- item->setData(Qt::UserRole, static_cast<int>(keyword.iconType));
- item->setForeground(keyword.color);
- }
-}
-
-void OptionsDialog::removeKeywordButtonClicked()
-{
- delete m_keywordsList->takeItem(m_keywordsList->currentRow());
-}
-
-void OptionsDialog::resetKeywordsButtonClicked()
-{
- Settings newSettings;
- newSettings.setDefault();
- setSettings(newSettings);
-}
-
-void OptionsDialog::setKeywordsButtonsEnabled()
-{
- const bool isSomethingSelected = !m_keywordsList->selectedItems().isEmpty();
- m_removeKeywordButton->setEnabled(isSomethingSelected);
- m_editKeywordButton->setEnabled(isSomethingSelected);
-}
-
-void OptionsDialog::setSettings(const Settings &settings)
-{
- m_scanInCurrentFileRadioButton->setChecked(settings.scanningScope == ScanningScopeCurrentFile);
- m_scanInProjectRadioButton->setChecked(settings.scanningScope == ScanningScopeProject);
- m_scanInSubprojectRadioButton->setChecked(settings.scanningScope == ScanningScopeSubProject);
-
- m_keywordsList->clear();
- for (const Keyword &keyword : std::as_const(settings.keywords))
- addToKeywordsList(keyword);
-}
-
-Settings OptionsDialog::settingsFromUi()
-{
- Settings settings;
-
- if (m_scanInCurrentFileRadioButton->isChecked())
- settings.scanningScope = ScanningScopeCurrentFile;
- else if (m_scanInSubprojectRadioButton->isChecked())
- settings.scanningScope = ScanningScopeSubProject;
- else
- settings.scanningScope = ScanningScopeProject;
-
- settings.keywords.clear();
- for (int i = 0; i < m_keywordsList->count(); ++i) {
- QListWidgetItem *item = m_keywordsList->item(i);
-
- Keyword keyword;
- keyword.name = item->text();
- keyword.iconType = static_cast<IconType>(item->data(Qt::UserRole).toInt());
- keyword.color = item->foreground().color();
-
- settings.keywords << keyword;
- }
-
- return settings;
-}
-
-void OptionsDialog::apply()
-{
- Settings newSettings = settingsFromUi();
-
- // "apply" itself is interpreted as "use these keywords, also for other themes".
- newSettings.keywordsEdited = true;
-
- if (newSettings == *m_settings)
- return;
-
- *m_settings = newSettings;
- m_onApply();
-}
-
-// TodoOptionsPage
-
-TodoOptionsPage::TodoOptionsPage(Settings *settings, const std::function<void ()> &onApply)
-{
- setId(Constants::TODO_SETTINGS);
- setDisplayName(Tr::tr("To-Do"));
- setCategory("To-Do");
- setDisplayCategory(Tr::tr("To-Do"));
- setCategoryIconPath(":/todoplugin/images/settingscategory_todo.png");
- setWidgetCreator([settings, onApply] { return new OptionsDialog(settings, onApply); });
-}
-
-} // Todo::Internal
diff --git a/src/plugins/todo/optionsdialog.h b/src/plugins/todo/optionsdialog.h
deleted file mode 100644
index 609fa56d9cb..00000000000
--- a/src/plugins/todo/optionsdialog.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (C) 2016 Dmitry Savchenko
-// Copyright (C) 2016 Vasiliy Sorokin
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include <coreplugin/dialogs/ioptionspage.h>
-
-namespace Todo::Internal {
-
-class Settings;
-
-class TodoOptionsPage final : public Core::IOptionsPage
-{
-public:
- TodoOptionsPage(Settings *settings, const std::function<void()> &onApply);
-};
-
-} // Todo::Internal
diff --git a/src/plugins/todo/settings.cpp b/src/plugins/todo/settings.cpp
index d5aafadd37f..ebe9a6f7cac 100644
--- a/src/plugins/todo/settings.cpp
+++ b/src/plugins/todo/settings.cpp
@@ -3,17 +3,27 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "settings.h"
+
#include "constants.h"
+#include "keyword.h"
+#include "keyworddialog.h"
+#include "todotr.h"
#include <coreplugin/coreconstants.h>
+#include <coreplugin/dialogs/ioptionspage.h>
+#include <utils/layoutbuilder.h>
#include <utils/qtcsettings.h>
#include <utils/theme/theme.h>
+#include <QGroupBox>
+#include <QListWidget>
+#include <QPushButton>
+#include <QRadioButton>
+
using namespace Utils;
-namespace Todo {
-namespace Internal {
+namespace Todo::Internal {
void Settings::save(QtcSettings *settings) const
{
@@ -133,6 +143,250 @@ bool operator !=(const Settings &s1, const Settings &s2)
return !s1.equals(s2);
}
-} // namespace Internal
-} // namespace Todo
+
+class OptionsDialog final : public Core::IOptionsPageWidget
+{
+public:
+ OptionsDialog(Settings *settings, const std::function<void ()> &onApply);
+
+ void apply() final;
+
+ void setSettings(const Settings &settings);
+
+private:
+ void addKeywordButtonClicked();
+ void editKeywordButtonClicked();
+ void removeKeywordButtonClicked();
+ void resetKeywordsButtonClicked();
+ void setKeywordsButtonsEnabled();
+ Settings settingsFromUi();
+ void addToKeywordsList(const Keyword &keyword);
+ void editKeyword(QListWidgetItem *item);
+ QSet<QString> keywordNames();
+
+ Settings *m_settings = nullptr;
+ std::function<void()> m_onApply;
+
+ QListWidget *m_keywordsList;
+ QPushButton *m_editKeywordButton;
+ QPushButton *m_removeKeywordButton;
+ QPushButton *resetKeywordsButton;
+ QRadioButton *m_scanInProjectRadioButton;
+ QRadioButton *m_scanInCurrentFileRadioButton;
+ QRadioButton *m_scanInSubprojectRadioButton;
+};
+
+OptionsDialog::OptionsDialog(Settings *settings, const std::function<void ()> &onApply)
+ : m_settings(settings), m_onApply(onApply)
+{
+ m_keywordsList = new QListWidget;
+ m_keywordsList->setDragDropMode(QAbstractItemView::DragDrop);
+ m_keywordsList->setDefaultDropAction(Qt::MoveAction);
+ m_keywordsList->setSelectionBehavior(QAbstractItemView::SelectRows);
+ m_keywordsList->setSortingEnabled(false);
+
+ auto addKeywordButton = new QPushButton(Tr::tr("Add"));
+ m_editKeywordButton = new QPushButton(Tr::tr("Edit"));
+ m_removeKeywordButton = new QPushButton(Tr::tr("Remove"));
+ resetKeywordsButton = new QPushButton(Tr::tr("Reset"));
+
+ m_scanInProjectRadioButton = new QRadioButton(Tr::tr("Scan the whole active project"));
+ m_scanInProjectRadioButton->setEnabled(true);
+
+ m_scanInCurrentFileRadioButton = new QRadioButton(Tr::tr("Scan only the currently edited document"));
+ m_scanInCurrentFileRadioButton->setChecked(true);
+
+ m_scanInSubprojectRadioButton = new QRadioButton(Tr::tr("Scan the current subproject"));
+
+ using namespace Layouting;
+
+ Column {
+ Group {
+ title(Tr::tr("Keywords")),
+ Row {
+ m_keywordsList,
+ Column {
+ addKeywordButton,
+ m_editKeywordButton,
+ m_removeKeywordButton,
+ resetKeywordsButton,
+ st
+ }
+ }
+ },
+ Group {
+ title(Tr::tr("Scanning scope")),
+ Column {
+ m_scanInProjectRadioButton,
+ m_scanInCurrentFileRadioButton,
+ m_scanInSubprojectRadioButton
+ }
+ }
+ }.attachTo(this);
+
+ m_keywordsList->setIconSize(QSize(16, 16));
+ setKeywordsButtonsEnabled();
+ connect(addKeywordButton, &QAbstractButton::clicked,
+ this, &OptionsDialog::addKeywordButtonClicked);
+ connect(m_removeKeywordButton, &QAbstractButton::clicked,
+ this, &OptionsDialog::removeKeywordButtonClicked);
+ connect(m_editKeywordButton, &QAbstractButton::clicked,
+ this, &OptionsDialog::editKeywordButtonClicked);
+ connect(resetKeywordsButton, &QAbstractButton::clicked,
+ this, &OptionsDialog::resetKeywordsButtonClicked);
+ connect(m_keywordsList, &QListWidget::itemDoubleClicked,
+ this, &OptionsDialog::editKeyword);
+ connect(m_keywordsList, &QListWidget::itemSelectionChanged,
+ this, &OptionsDialog::setKeywordsButtonsEnabled);
+
+ setSettings(*m_settings);
+}
+
+void OptionsDialog::addToKeywordsList(const Keyword &keyword)
+{
+ auto item = new QListWidgetItem(icon(keyword.iconType), keyword.name);
+ item->setData(Qt::UserRole, static_cast<int>(keyword.iconType));
+ item->setForeground(keyword.color);
+ m_keywordsList->addItem(item);
+}
+
+QSet<QString> OptionsDialog::keywordNames()
+{
+ const KeywordList keywords = settingsFromUi().keywords;
+
+ QSet<QString> result;
+ for (const Keyword &keyword : keywords)
+ result << keyword.name;
+
+ return result;
+}
+
+void OptionsDialog::addKeywordButtonClicked()
+{
+ Keyword keyword;
+ KeywordDialog keywordDialog(keyword, keywordNames(), this);
+ if (keywordDialog.exec() == QDialog::Accepted) {
+ keyword = keywordDialog.keyword();
+ addToKeywordsList(keyword);
+ }
+}
+
+void OptionsDialog::editKeywordButtonClicked()
+{
+ QListWidgetItem *item = m_keywordsList->currentItem();
+ editKeyword(item);
+}
+
+void OptionsDialog::editKeyword(QListWidgetItem *item)
+{
+ Keyword keyword;
+ keyword.name = item->text();
+ keyword.iconType = static_cast<IconType>(item->data(Qt::UserRole).toInt());
+ keyword.color = item->foreground().color();
+
+ QSet<QString> keywordNamesButThis = keywordNames();
+ keywordNamesButThis.remove(keyword.name);
+
+ KeywordDialog keywordDialog(keyword, keywordNamesButThis, this);
+ if (keywordDialog.exec() == QDialog::Accepted) {
+ keyword = keywordDialog.keyword();
+ item->setIcon(icon(keyword.iconType));
+ item->setText(keyword.name);
+ item->setData(Qt::UserRole, static_cast<int>(keyword.iconType));
+ item->setForeground(keyword.color);
+ }
+}
+
+void OptionsDialog::removeKeywordButtonClicked()
+{
+ delete m_keywordsList->takeItem(m_keywordsList->currentRow());
+}
+
+void OptionsDialog::resetKeywordsButtonClicked()
+{
+ Settings newSettings;
+ newSettings.setDefault();
+ setSettings(newSettings);
+}
+
+void OptionsDialog::setKeywordsButtonsEnabled()
+{
+ const bool isSomethingSelected = !m_keywordsList->selectedItems().isEmpty();
+ m_removeKeywordButton->setEnabled(isSomethingSelected);
+ m_editKeywordButton->setEnabled(isSomethingSelected);
+}
+
+void OptionsDialog::setSettings(const Settings &settings)
+{
+ m_scanInCurrentFileRadioButton->setChecked(settings.scanningScope == ScanningScopeCurrentFile);
+ m_scanInProjectRadioButton->setChecked(settings.scanningScope == ScanningScopeProject);
+ m_scanInSubprojectRadioButton->setChecked(settings.scanningScope == ScanningScopeSubProject);
+
+ m_keywordsList->clear();
+ for (const Keyword &keyword : std::as_const(settings.keywords))
+ addToKeywordsList(keyword);
+}
+
+Settings OptionsDialog::settingsFromUi()
+{
+ Settings settings;
+
+ if (m_scanInCurrentFileRadioButton->isChecked())
+ settings.scanningScope = ScanningScopeCurrentFile;
+ else if (m_scanInSubprojectRadioButton->isChecked())
+ settings.scanningScope = ScanningScopeSubProject;
+ else
+ settings.scanningScope = ScanningScopeProject;
+
+ settings.keywords.clear();
+ for (int i = 0; i < m_keywordsList->count(); ++i) {
+ QListWidgetItem *item = m_keywordsList->item(i);
+
+ Keyword keyword;
+ keyword.name = item->text();
+ keyword.iconType = static_cast<IconType>(item->data(Qt::UserRole).toInt());
+ keyword.color = item->foreground().color();
+
+ settings.keywords << keyword;
+ }
+
+ return settings;
+}
+
+void OptionsDialog::apply()
+{
+ Settings newSettings = settingsFromUi();
+
+ // "apply" itself is interpreted as "use these keywords, also for other themes".
+ newSettings.keywordsEdited = true;
+
+ if (newSettings == *m_settings)
+ return;
+
+ *m_settings = newSettings;
+ m_onApply();
+}
+
+// TodoSettingsPage
+
+class TodoSettingsPage final : public Core::IOptionsPage
+{
+public:
+ TodoSettingsPage(Settings *settings, const std::function<void()> &onApply)
+ {
+ setId(Constants::TODO_SETTINGS);
+ setDisplayName(Tr::tr("To-Do"));
+ setCategory("To-Do");
+ setDisplayCategory(Tr::tr("To-Do"));
+ setCategoryIconPath(":/todoplugin/images/settingscategory_todo.png");
+ setWidgetCreator([settings, onApply] { return new OptionsDialog(settings, onApply); });
+ }
+};
+
+void setupTodoSettingsPage(Settings *settings, const std::function<void()> &onApply)
+{
+ static TodoSettingsPage theTodoSettingsPage(settings, onApply);
+}
+
+} // Todo::Internal
diff --git a/src/plugins/todo/settings.h b/src/plugins/todo/settings.h
index 534b1a1b0ca..b5b70a8a35c 100644
--- a/src/plugins/todo/settings.h
+++ b/src/plugins/todo/settings.h
@@ -8,8 +8,7 @@
namespace Utils { class QtcSettings; }
-namespace Todo {
-namespace Internal {
+namespace Todo::Internal {
enum ScanningScope {
ScanningScopeCurrentFile,
@@ -34,7 +33,8 @@ public:
bool operator ==(const Settings &s1, const Settings &s2);
bool operator !=(const Settings &s1, const Settings &s2);
-} // namespace Internal
-} // namespace Todo
+void setupTodoSettingsPage(Settings *settings, const std::function<void()> &onApply);
+
+} // Todo::Internal
Q_DECLARE_METATYPE(Todo::Internal::ScanningScope)
diff --git a/src/plugins/todo/todo.qbs b/src/plugins/todo/todo.qbs
index f3ea7fc96fa..f0c038c4755 100644
--- a/src/plugins/todo/todo.qbs
+++ b/src/plugins/todo/todo.qbs
@@ -22,8 +22,6 @@ QtcPlugin {
"keyworddialog.h",
"lineparser.cpp",
"lineparser.h",
- "optionsdialog.cpp",
- "optionsdialog.h",
"todoprojectsettingswidget.cpp",
"todoprojectsettingswidget.h",
"qmljstodoitemsscanner.cpp",
diff --git a/src/plugins/todo/todoplugin.cpp b/src/plugins/todo/todoplugin.cpp
index 6da4a2bd8e5..df8acc1af8c 100644
--- a/src/plugins/todo/todoplugin.cpp
+++ b/src/plugins/todo/todoplugin.cpp
@@ -2,7 +2,6 @@
// Copyright (C) 2016 Vasiliy Sorokin
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-#include "optionsdialog.h"
#include "todooutputpane.h"
#include "todoitemsprovider.h"
#include "todoprojectsettingswidget.h"
@@ -31,7 +30,6 @@ public:
Settings m_settings;
TodoOutputPane *m_todoOutputPane = nullptr;
- TodoOptionsPage m_optionsPage{&m_settings, [this] { settingsChanged(m_settings); }};
TodoItemsProvider *m_todoItemsProvider = nullptr;
};
@@ -42,6 +40,8 @@ TodoPluginPrivate::TodoPluginPrivate()
createItemsProvider();
createTodoOutputPane();
+ setupTodoSettingsPage(&m_settings, [this] { settingsChanged(m_settings); });
+
setupTodoSettingsProjectPanel(m_todoItemsProvider);
connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested,