1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2016 Falko Arps
5 ** Copyright (C) 2016 Sven Klein
6 ** Copyright (C) 2016 Giuliano Schneider
7 ** Contact: https://www.qt.io/licensing/
8 **
9 ** This file is part of Qt Creator.
10 **
11 ** Commercial License Usage
12 ** Licensees holding valid commercial Qt licenses may use this file in
13 ** accordance with the commercial license agreement provided with the
14 ** Software or, alternatively, in accordance with the terms contained in
15 ** a written agreement between you and The Qt Company. For licensing terms
16 ** and conditions see https://www.qt.io/terms-conditions. For further
17 ** information use the contact form at https://www.qt.io/contact-us.
18 **
19 ** GNU General Public License Usage
20 ** Alternatively, this file may be used under the terms of the GNU
21 ** General Public License version 3 as published by the Free Software
22 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
23 ** included in the packaging of this file. Please review the following
24 ** information to ensure the GNU General Public License requirements will
25 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
26 **
27 ****************************************************************************/
28
29 #include "ioptionspage.h"
30
31 #include <coreplugin/icore.h>
32
33 #include <utils/aspects.h>
34 #include <utils/qtcassert.h>
35 #include <utils/stringutils.h>
36
37 #include <QCheckBox>
38 #include <QGroupBox>
39 #include <QIcon>
40 #include <QLabel>
41 #include <QPushButton>
42 #include <QRegularExpression>
43
44 using namespace Utils;
45
46 namespace Core {
47
48 /*!
49 \class Core::IOptionsPageProvider
50 \inmodule QtCreator
51 \internal
52 */
53 /*!
54 \class Core::IOptionsPageWidget
55 \inmodule QtCreator
56 \internal
57 */
58
59 /*!
60 \class Core::IOptionsPage
61 \inheaderfile coreplugin/dialogs/ioptionspage.h
62 \ingroup mainclasses
63 \inmodule QtCreator
64
65 \brief The IOptionsPage class is an interface for providing pages for the
66 \uicontrol Options dialog (called \uicontrol Preferences on \macos).
67
68 \image qtcreator-options-dialog.png
69 */
70
71 /*!
72
73 \fn Utils::Id Core::IOptionsPage::id() const
74
75 Returns a unique identifier for referencing the options page.
76 */
77
78 /*!
79 \fn QString Core::IOptionsPage::displayName() const
80
81 Returns the translated display name of the options page.
82 */
83
84 /*!
85 \fn Utils::Id Core::IOptionsPage::category() const
86
87 Returns the unique id for the category that the options page should be displayed in. This id is
88 used for sorting the list on the left side of the \uicontrol Options dialog.
89 */
90
91 /*!
92 \fn QString Core::IOptionsPage::displayCategory() const
93
94 Returns the translated category name of the options page. This name is displayed in the list on
95 the left side of the \uicontrol Options dialog.
96 */
97
98 /*!
99 Returns the category icon of the options page. This icon is displayed in the list on the left
100 side of the \uicontrol Options dialog.
101 */
categoryIcon() const102 QIcon IOptionsPage::categoryIcon() const
103 {
104 return m_categoryIcon.icon();
105 }
106
107 /*!
108 Sets the \a widgetCreator callback to create page widgets on demand. The
109 widget will be destroyed on finish().
110 */
setWidgetCreator(const WidgetCreator & widgetCreator)111 void IOptionsPage::setWidgetCreator(const WidgetCreator &widgetCreator)
112 {
113 m_widgetCreator = widgetCreator;
114 }
115
116 /*!
117 Returns the widget to show in the \uicontrol Options dialog. You should create a widget lazily here,
118 and delete it again in the finish() method. This method can be called multiple times, so you
119 should only create a new widget if the old one was deleted.
120
121 Alternatively, use setWidgetCreator() to set a callback function that is used to
122 lazily create a widget in time.
123
124 Either override this function in a derived class, or set a widget creator.
125 */
126
widget()127 QWidget *IOptionsPage::widget()
128 {
129 if (!m_widget) {
130 if (m_widgetCreator) {
131 m_widget = m_widgetCreator();
132 } else if (m_layouter) {
133 m_widget = new QWidget;
134 m_layouter(m_widget);
135 } else {
136 QTC_CHECK(false);
137 }
138 }
139 return m_widget;
140 }
141
142 /*!
143 Called when selecting the \uicontrol Apply button on the options page dialog.
144 Should detect whether any changes were made and store those.
145
146 Either override this function in a derived class, or set a widget creator.
147
148 \sa setWidgetCreator()
149 */
150
apply()151 void IOptionsPage::apply()
152 {
153 if (auto widget = qobject_cast<IOptionsPageWidget *>(m_widget)) {
154 widget->apply();
155 } else if (m_settings) {
156 if (m_settings->isDirty()) {
157 m_settings->apply();
158 m_settings->writeSettings(ICore::settings());
159 }
160 }
161 }
162
163 /*!
164 Called directly before the \uicontrol Options dialog closes. Here you should
165 delete the widget that was created in widget() to free resources.
166
167 Either override this function in a derived class, or set a widget creator.
168
169 \sa setWidgetCreator()
170 */
171
finish()172 void IOptionsPage::finish()
173 {
174 if (auto widget = qobject_cast<IOptionsPageWidget *>(m_widget))
175 widget->finish();
176 else if (m_settings)
177 m_settings->finish();
178
179 delete m_widget;
180 }
181
182 /*!
183 Sets \a categoryIconPath as the path to the category icon of the options
184 page.
185 */
setCategoryIconPath(const QString & categoryIconPath)186 void IOptionsPage::setCategoryIconPath(const QString &categoryIconPath)
187 {
188 m_categoryIcon = Icon({{categoryIconPath, Theme::PanelTextColorDark}}, Icon::Tint);
189 }
190
setSettings(AspectContainer * settings)191 void IOptionsPage::setSettings(AspectContainer *settings)
192 {
193 m_settings = settings;
194 }
195
setLayouter(const std::function<void (QWidget * w)> & layouter)196 void IOptionsPage::setLayouter(const std::function<void(QWidget *w)> &layouter)
197 {
198 m_layouter = layouter;
199 }
200
201 /*!
202 \fn void Core::IOptionsPage::setId(Utils::Id id)
203
204 Sets the \a id of the options page.
205 */
206
207 /*!
208 \fn void Core::IOptionsPage::setDisplayName(const QString &displayName)
209
210 Sets \a displayName as the display name of the options page.
211 */
212
213 /*!
214 \fn void Core::IOptionsPage::setCategory(Utils::Id category)
215
216 Uses \a category to sort the options pages.
217 */
218
219 /*!
220 \fn void Core::IOptionsPage::setDisplayCategory(const QString &displayCategory)
221
222 Sets \a displayCategory as the display category of the options page.
223 */
224
225 /*!
226 \fn void Core::IOptionsPage::setCategoryIcon(const Utils::Icon &categoryIcon)
227
228 Sets \a categoryIcon as the category icon of the options page.
229 */
230
231 static QList<IOptionsPage *> g_optionsPages;
232
233 /*!
234 Constructs an options page with the given \a parent and registers it
235 at the global options page pool if \a registerGlobally is \c true.
236 */
IOptionsPage(QObject * parent,bool registerGlobally)237 IOptionsPage::IOptionsPage(QObject *parent, bool registerGlobally)
238 : QObject(parent)
239 {
240 if (registerGlobally)
241 g_optionsPages.append(this);
242 }
243
244 /*!
245 \internal
246 */
~IOptionsPage()247 IOptionsPage::~IOptionsPage()
248 {
249 g_optionsPages.removeOne(this);
250 }
251
252 /*!
253 Returns a list of all options pages.
254 */
allOptionsPages()255 const QList<IOptionsPage *> IOptionsPage::allOptionsPages()
256 {
257 return g_optionsPages;
258 }
259
260 /*!
261 Is used by the \uicontrol Options dialog search filter to match \a regexp to this options
262 page. This defaults to take the widget and then looks for all child labels, check boxes, push
263 buttons, and group boxes. Should return \c true when a match is found.
264 */
matches(const QRegularExpression & regexp) const265 bool IOptionsPage::matches(const QRegularExpression ®exp) const
266 {
267 if (!m_keywordsInitialized) {
268 auto that = const_cast<IOptionsPage *>(this);
269 QWidget *widget = that->widget();
270 if (!widget)
271 return false;
272 // find common subwidgets
273 foreach (const QLabel *label, widget->findChildren<QLabel *>())
274 m_keywords << Utils::stripAccelerator(label->text());
275 foreach (const QCheckBox *checkbox, widget->findChildren<QCheckBox *>())
276 m_keywords << Utils::stripAccelerator(checkbox->text());
277 foreach (const QPushButton *pushButton, widget->findChildren<QPushButton *>())
278 m_keywords << Utils::stripAccelerator(pushButton->text());
279 foreach (const QGroupBox *groupBox, widget->findChildren<QGroupBox *>())
280 m_keywords << Utils::stripAccelerator(groupBox->title());
281
282 m_keywordsInitialized = true;
283 }
284 foreach (const QString &keyword, m_keywords)
285 if (keyword.contains(regexp))
286 return true;
287 return false;
288 }
289
290 static QList<IOptionsPageProvider *> g_optionsPagesProviders;
291
IOptionsPageProvider(QObject * parent)292 IOptionsPageProvider::IOptionsPageProvider(QObject *parent)
293 : QObject(parent)
294 {
295 g_optionsPagesProviders.append(this);
296 }
297
~IOptionsPageProvider()298 IOptionsPageProvider::~IOptionsPageProvider()
299 {
300 g_optionsPagesProviders.removeOne(this);
301 }
302
allOptionsPagesProviders()303 const QList<IOptionsPageProvider *> IOptionsPageProvider::allOptionsPagesProviders()
304 {
305 return g_optionsPagesProviders;
306 }
307
categoryIcon() const308 QIcon IOptionsPageProvider::categoryIcon() const
309 {
310 return m_categoryIcon.icon();
311 }
312
313 } // Core
314