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 &regexp) 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