Refactorize settingspages a bit
[quassel.git] / src / uisupport / settingspage.h
index 2d73e82..b68b78b 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-08 by the Quassel Project                          *
+ *   Copyright (C) 2005-09 by the Quassel Project                          *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 
 #include <QWidget>
 
+class QCheckBox;
+class QComboBox;
+class QSpinBox;
+
 //! A SettingsPage is a page in the settings dialog.
+/** The SettingsDlg provides suitable standard buttons, such as Ok, Apply, Cancel, Restore Defaults and Reset.
+ *  Some pages might also be used in standalone dialogs or other containers. A SettingsPage provides suitable
+ *  slots and signals to allow interaction with the container.
+ *
+ *  A derived class needs to keep track of its changed state. Whenever a child widget changes, it needs to be
+ *  compared to its value in permanent storage, and the changed state updated accordingly by calling setChangedState().
+ *  For most standard widgets, SettingsPage can do this automatically if desired. Such a child widget needs to have
+ *  a dynamic property \c settingsKey that maps to the key in the client configuration file. This key is appended
+ *  to settingsKey(), which must be set to a non-null value in a derived class. If the widget's key starts with '/',
+ *  its key is treated as a global path starting from the root, rather than from settingsKey().
+ *  A second dynamic property \c defaultValue can be defined in child widgets as well.
+ *
+ *  For widgets requiring special ways for storing and saving, define the property settingsKey and leave it empty. In this
+ *  case, the methods saveAutoWidgetValue() and loadAutoWidgetValue() will be called with the widget's objectName as parameter.
+ *
+ *  SettingsPage manages loading, saving, setting to default and setting the changed state for all automatic child widgets.
+ *  Derived classes must be sure to call initAutoWidgets() *after* setupUi(); they also need to call the baseclass implementations
+ *  of load(), save() and defaults() (preferably at the end of the derived function, since they call setChangedState(false)).
+ *
+ *  The following widgets can be handled for now:
+ *    - QGroupBox (isChecked())
+ *    - QAbstractButton (isChecked(), e.g. for QCheckBox and QRadioButton)
+ *    - QLineEdit, QTextEdit (text())
+ *    - QComboBox (currentIndex())
+ *    - QSpinBox (value())
+ */
 class SettingsPage : public QWidget {
   Q_OBJECT
 
-  public:
-    SettingsPage(const QString &category, const QString &name, QWidget *parent = 0);
-    virtual ~SettingsPage() {};
-    virtual QString category() const;
-    virtual QString title() const;
+public:
+  SettingsPage(const QString &category, const QString &name, QWidget *parent = 0);
+  virtual ~SettingsPage() {};
+
+  //! The category of this settings page.
+  inline virtual QString category() const { return _category; }
+
+  //! The title of this settings page.
+  inline virtual QString title() const { return _title; }
+
+  //! Whether the settingspage needs a core connection to be selectable
+  /** This is a hint for the settingspage dialog. Do not rely on the settingspage not being
+   *  visible if disconnected, and care about disabling it yourself.
+   */
+  inline virtual bool needsCoreConnection() const { return false; }
 
-    bool hasChanged() const;
+  //! The key this settings page stores its values under
+  /** This needs to be overriden to enable automatic loading/saving/hasChanged checking of widgets.
+   *  The child widgets' values will be stored in client settings under this key. Every widget that
+   *  should be automatically handled needs to have a \c settingsKey property set, and should also provide
+   *  a \c defaultValue property.
+   *  You can return an empty string (as opposed to a null string) to use the config root as a base, and
+   *  you can override this key for individual widgets by prefixing their SettingsKey with /.
+   */
+  inline virtual QString settingsKey() const { return QString(); }
 
-    //! Called immediately before save() is called.
-    /** Derived classes should return false if saving is not possible (e.g. the current settings are invalid).
-     *  \return false, if the SettingsPage cannot be saved in its current state.
+  //! Derived classes need to define this and return true if they have default settings.
+  /** If this method returns true, the "Restore Defaults" button in the SettingsDlg is
+   *  enabled. You also need to provide an implementation of defaults() then.
+   *
+   * The default implementation returns false.
      */
-    virtual bool aboutToSave();
+  inline virtual bool hasDefaults() const { return false; }
+
+  //! Check if there are changes in the page, compared to the state saved in permanent storage.
+  inline bool hasChanged() const { return _changed || _autoWidgetsChanged; }
+
+  //! Called immediately before save() is called.
+  /** Derived classes should return false if saving is not possible (e.g. the current settings are invalid).
+   *  \return false, if the SettingsPage cannot be saved in its current state.
+   */
+  inline virtual bool aboutToSave() { return true; }
+
+  //! sets checked state depending on \checked and stores the value for later comparision
+  static void load(QCheckBox *box, bool checked);
+  static bool hasChanged(QCheckBox *box);
+  static void load(QComboBox *box, int index);
+  static bool hasChanged(QComboBox *box);
+  static void load(QSpinBox *box, int value);
+  static bool hasChanged(QSpinBox *box);
 
-  public slots:
-    virtual void save() = 0;
-    virtual void load() = 0;
-    virtual void defaults() = 0;
+public slots:
+  //! Save settings to permanent storage.
+  /** This baseclass implementation saves the autoWidgets, so be sure to call it if you use
+   *  this feature in your settingsPage!
+   */
+  virtual void save();
 
-  protected slots:
-    //! Calling this slot is equivalent to calling changeState(true).
-    void changed();
+  //! Load settings from permanent storage, overriding any changes the user might have made in the dialog.
+  /** This baseclass implementation loads the autoWidgets, so be sure to call it if you use
+   *  this feature in your settingsPage!
+   */
+  virtual void load();
 
-  protected:
-    //! This should be called whenever the widget state changes from unchanged to change or the other way round.
-    void changeState(bool hasChanged = true);
+  //! Restore defaults, overriding any changes the user might have made in the dialog.
+  /** This baseclass implementation loads the defaults of the autoWidgets (if available), so be sure
+   *  to call it if you use this feature in your settingsPage!
+   */
+  virtual void defaults();
 
-  signals:
-    //! Emitted whenever the widget state changes.
-    void changed(bool hasChanged);
+protected slots:
+  //! Calling this slot is equivalent to calling setChangedState(true).
+  inline void changed() { setChangedState(true); }
 
-  private:
-    QString _category, _title;
-    bool _changed;
+  //! This should be called whenever the widget state changes from unchanged to change or the other way round.
+  void setChangedState(bool hasChanged = true);
+
+protected:
+  void initAutoWidgets();
+  virtual QVariant loadAutoWidgetValue(const QString &widgetName);
+  virtual void saveAutoWidgetValue(const QString &widgetName, const QVariant &value);
+
+signals:
+  //! Emitted whenever the widget state changes.
+  void changed(bool hasChanged);
+
+private slots:
+  // for auto stuff
+  void autoWidgetHasChanged();
+
+private:
+  void findAutoWidgets(QObject *parent, QObjectList *widgetList) const;
+  QByteArray autoWidgetPropertyName(QObject *widget) const;
+  QString autoWidgetSettingsKey(QObject *widget) const;
+
+  QString _category, _title;
+  bool _changed, _autoWidgetsChanged;
+  QObjectList _autoWidgets;
 };
 
+
+
 #endif