1 /*
2  * Copyright (C) 2019-2021 Ashar Khan <ashar786khan@gmail.com>
3  *
4  * This file is part of CP Editor.
5  *
6  * CP Editor is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * I will not be responsible if CP Editor behaves in unexpected way and
12  * causes your ratings to go down and or lose any important contest.
13  *
14  * Believe Software is "Software" and it isn't immune to bugs.
15  *
16  */
17 
18 /*
19  * This is an abstract base class for a page in the preferences.
20  *
21  * It provides the basic buttons: Default, Reset, and Apply.
22  *
23  * Default: Set the setting in the current page to default.
24  * Reset: Clear unsaved settings.
25  * Apply: Save settings without exiting.
26  *
27  * When the user is about to leave the current page, if there are unsaved changes, the user will
28  * be asked whether to save the changes, discard the changes, or stay in the current page.
29  */
30 
31 #ifndef PREFERENCESPAGE_HPP
32 #define PREFERENCESPAGE_HPP
33 
34 #include <QWidget>
35 
36 class QHBoxLayout;
37 class QLabel;
38 class QLayoutItem;
39 class QPushButton;
40 class QScrollArea;
41 class QVBoxLayout;
42 class ValueWidget;
43 
44 class PreferencesPage : public QWidget
45 {
46     Q_OBJECT
47 
48   private:
49     /**
50      * @brief query for whether the settings are different from the UI
51      */
52     virtual bool areSettingsChanged() = 0;
53 
54     /**
55      * @brief update the UI, make it the same as the default values
56      * @note you don't need to call updateButtons() in this function
57      */
58     virtual void makeUITheSameAsDefault() = 0;
59 
60     /**
61      * @brief update the UI, make it the same as the settings
62      * @note you don't need to call updateButtons() in this function
63      */
64     virtual void makeUITheSameAsSettings() = 0;
65 
66     /**
67      * @brief update the settings, make it the same as the UI
68      * @note you don't need to call updateButtons() in this function
69      */
70     virtual void makeSettingsTheSameAsUI() = 0;
71 
72   public:
73     /**
74      * @brief construct a PreferencesPage
75      */
76     explicit PreferencesPage(QWidget *parent = nullptr);
77 
78     /**
79      * @brief a virtual destructor that does nothing
80      * @note the widgets are destructed by Qt, so we shouldn't destruct them in the codes
81      */
~PreferencesPage()82     virtual ~PreferencesPage(){};
83 
84     /**
85      * @brief ask the user whether to save, discard or cancel if there are unsaved changes
86      * @return return true if there is no unsaved change or the changes are saved/discarded
87      */
88     bool aboutToExit();
89 
90     /**
91      * @brief get the path to this page in the preferences window
92      */
93     QString path() const;
94 
95     /**
96      * @brief get the translation of the path
97      */
98     QString trPath() const;
99 
100     /**
101      * @brief set the path to this page in the preferences window
102      */
103     virtual void setPath(const QString &path, const QString &trPath);
104 
105     /**
106      * @brief set the title of the page
107      */
108     void setTitle(const QString &title);
109 
110     /**
111      * @brief get the content
112      */
113     virtual QStringList content();
114 
115   public slots:
116     /**
117      * @brief update the UI, make it the same as the settings, and update buttons
118      */
119     void loadSettings();
120 
121   signals:
122 
123     /**
124      * @brief the path are changed
125      * @param pagePath the path to this page
126      */
127 
128     void pathChanged(const QString &pagePath);
129 
130     /**
131      * @brief the settings are applied
132      * @param pagePath the path to this page
133      */
134     void settingsApplied(const QString &pagePath);
135 
136   protected:
137     /**
138      * @brief add a layout in the UI
139      */
140     void addLayout(QLayout *layout);
141 
142     /**
143      * @brief add a widget in the UI
144      */
145     void addWidget(QWidget *widget);
146 
147     /**
148      * @brief add an item in the UI
149      */
150     void addItem(QLayoutItem *item);
151 
152     void registerWidget(const QString &key, ValueWidget *widget) const;
153 
154   protected slots:
155     /**
156      * @brief enable/disable the reset button and the apply button
157      * @note this should be invoked when the UI/the settings are changed
158      */
159     void updateButtons();
160 
161   private slots:
162     /**
163      * @brief update the UI, make it the same as the default values, and update buttons
164      */
165     void loadDefault();
166 
167     /**
168      * @brief update the settings, make it the same as the UI, and update buttons
169      */
170     void applySettings();
171 
172   private:
173     /**
174      * The UI structure:
175      *
176      * mainLayout:
177      *  - titleLabel
178      *  - scrollArea
179      *    - scrollAreaWidget
180      *      - settingsLayout
181      *  - buttonsLayout
182      *    - defaultButton
183      *    - resetButton
184      *    - (stretch)
185      *    - applyButton
186      */
187 
188     QLabel *titleLabel = nullptr;          // The title of the page
189     QScrollArea *scrollArea = nullptr;     // The scroll area to place the settings
190     QWidget *scrollAreaWidget = nullptr;   // The widget in the scroll area with settingsLayout as its layout
191     QVBoxLayout *settingsLayout = nullptr; // The layout for the settings
192     QPushButton *defaultButton = nullptr;  // The button to set the UI to the default values
193     QPushButton *resetButton = nullptr;    // The button to set the UI to the saved settings
194     QPushButton *applyButton = nullptr;    // The button to save the UI to the settings
195 
196     QString m_path;   // The path to this page in the preferences window
197     QString m_trPath; // The translation of the path
198 };
199 
200 #endif // PREFERENCESPAGE_HPP
201