Browse Source

Add ctkSettingsWidget and ctkSettingsPanel

Widgets to control/display QSettings
Julien Finet 14 years ago
parent
commit
d5cb870f60

+ 7 - 0
Libs/Widgets/CMakeLists.txt

@@ -73,6 +73,10 @@ SET(KIT_SRCS
   ctkScreenshotDialog_p.h
   ctkSettings.cpp
   ctkSettings.h
+  ctkSettingsPanel.cpp
+  ctkSettingsPanel.h
+  ctkSettingsWidget.cpp
+  ctkSettingsWidget.h
   ctkSliderWidget.cpp
   ctkSliderWidget.h
   ctkTestApplication.cpp
@@ -142,6 +146,8 @@ SET(KIT_MOC_SRCS
   ctkScreenshotDialog.h
   ctkScreenshotDialog_p.h
   ctkSettings.h
+  ctkSettingsPanel.h
+  ctkSettingsWidget.h
   ctkSliderWidget.h
   ctkTestApplication.h
   ctkTransferFunctionBarsItem.h
@@ -168,6 +174,7 @@ SET(KIT_UI_FORMS
   Resources/UI/ctkDateRangeWidget.ui
   Resources/UI/ctkMaterialPropertyWidget.ui
   Resources/UI/ctkScreenshotDialog.ui
+  Resources/UI/ctkSettingsWidget.ui
   Resources/UI/ctkSliderWidget.ui
   Resources/UI/ctkWorkflowGroupBox.ui
   )

+ 39 - 0
Libs/Widgets/Resources/UI/ctkSettingsWidget.ui

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ctkSettingsWidget</class>
+ <widget class="QWidget" name="ctkSettingsWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>693</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Settings</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QTreeWidget" name="SettingsTreeWidget">
+     <property name="headerHidden">
+      <bool>true</bool>
+     </property>
+     <column>
+      <property name="text">
+       <string notr="true">1</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+   <item>
+    <widget class="QStackedWidget" name="SettingsStackedWidget"/>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 4 - 0
Libs/Widgets/Testing/Cpp/CMakeLists.txt

@@ -30,7 +30,9 @@ CREATE_TEST_SOURCELIST(Tests ${KIT}CppTests.cxx
   ctkRangeSliderTest1.cpp
   ctkRangeWidgetTest1.cpp
   ctkDateRangeWidgetTest1.cpp
+  ctkSettingsPanelTest1.cpp
   ctkSettingsTest1.cpp
+  ctkSettingsWidgetTest1.cpp
   ctkSliderWidgetTest1.cpp
   ctkTreeComboBoxTest1.cpp
   ctkWorkflowWidgetTest1.cpp
@@ -102,7 +104,9 @@ SIMPLE_TEST( ctkMenuButtonTest1 )
 SIMPLE_TEST( ctkRangeSliderTest1 )
 SIMPLE_TEST( ctkRangeWidgetTest1 )
 SIMPLE_TEST( ctkDateRangeWidgetTest1 )
+SIMPLE_TEST( ctkSettingsPanelTest1 )
 SIMPLE_TEST( ctkSettingsTest1 )
+SIMPLE_TEST( ctkSettingsWidgetTest1 )
 SIMPLE_TEST( ctkSliderWidgetTest1 )
 SIMPLE_TEST( ctkTreeComboBoxTest1 )
 SIMPLE_TEST( ctkWorkflowWidgetTest1 )

+ 72 - 0
Libs/Widgets/Testing/Cpp/ctkSettingsPanelTest1.cpp

@@ -0,0 +1,72 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+// Qt includes
+#include <QApplication>
+#include <QCheckBox>
+#include <QSettings>
+#include <QTimer>
+
+// CTK includes
+#include "ctkSettingsPanel.h"
+
+// STD includes
+#include <stdlib.h>
+#include <iostream>
+
+//-----------------------------------------------------------------------------
+int ctkSettingsPanelTest1(int argc, char * argv [] )
+{
+  QApplication app(argc, argv);
+  
+  QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Common ToolKit", "CTK");
+
+  ctkSettingsPanel settingsPanel;
+  settingsPanel.setSettings(&settings);
+
+  QCheckBox* box = new QCheckBox(&settingsPanel);
+
+  settingsPanel.registerProperty("key 1", box, "checked",
+                                  SIGNAL(toggled(bool)));
+  
+  QVariant boxVal = settings.value("key 1");
+  if (!boxVal.isValid() || boxVal.toBool() != false)
+    {
+    std::cerr << "Saving to settings failed" << std::endl;
+    return EXIT_FAILURE;
+    }
+  box->setChecked(true);
+  boxVal = settings.value("key 1");
+  if (!boxVal.isValid() || boxVal.toBool() != true)
+    {
+    std::cerr << "Saving to settings failed" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  settingsPanel.show();
+      
+  if (argc < 2 || QString(argv[1]) != "-I" )
+    {
+    QTimer::singleShot(200, &app, SLOT(quit()));
+    }
+
+  return app.exec();
+}
+

+ 87 - 0
Libs/Widgets/Testing/Cpp/ctkSettingsWidgetTest1.cpp

@@ -0,0 +1,87 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+// Qt includes
+#include <QApplication>
+#include <QCheckBox>
+#include <QSettings>
+#include <QTimer>
+
+// CTK includes
+#include "ctkSettingsPanel.h"
+#include "ctkSettingsWidget.h"
+
+// STD includes
+#include <stdlib.h>
+#include <iostream>
+
+//-----------------------------------------------------------------------------
+int ctkSettingsWidgetTest1(int argc, char * argv [] )
+{
+  QApplication app(argc, argv);
+  
+  QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Common ToolKit", "CTK");
+
+  ctkSettingsWidget settingsWidget;
+  settingsWidget.setSettings(&settings);
+
+  ctkSettingsPanel* panel1 = new ctkSettingsPanel;
+  settingsWidget.addPanel("Panel 1", panel1); 
+  if (panel1->settings() != &settings)
+    {
+    std::cerr << "ctkSettingsWidget::addPanel settings failed" << panel1->settings() << std::endl;
+    return EXIT_FAILURE;
+    }
+  settingsWidget.addPanel("Panel 2", new ctkSettingsPanel);
+  settingsWidget.addPanel("Panel 3", new ctkSettingsPanel);
+  ctkSettingsPanel* panel4 = new ctkSettingsPanel;
+  settingsWidget.addPanel("Panel 4", panel4, panel1);
+
+  QCheckBox* box = new QCheckBox(panel4);
+  box->setChecked(false); // false by default but we just want to make sure
+  panel4->registerProperty("key 1", box, "checked",
+                           SIGNAL(toggled(bool)));
+  
+  QVariant boxVal = settings.value("key 1");
+  if (!boxVal.isValid() || boxVal.toBool() != false)
+    {
+    std::cerr << "Saving to settings failed" << std::endl;
+    return EXIT_FAILURE;
+    }
+  box->setChecked(true);
+  boxVal = settings.value("key 1");
+  if (!boxVal.isValid() || boxVal.toBool() != true)
+    {
+    std::cerr << "Saving to settings failed" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  settingsWidget.setCurrentPanel("Panel 4");
+
+  settingsWidget.show();
+      
+  if (argc < 2 || QString(argv[1]) != "-I" )
+    {
+    QTimer::singleShot(200, &app, SLOT(quit()));
+    }
+
+  return app.exec();
+}
+

+ 191 - 0
Libs/Widgets/ctkSettingsPanel.cpp

@@ -0,0 +1,191 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+// Qt includes
+#include <QDebug>
+#include <QSettings>
+#include <QSignalMapper>
+
+// CTK includes
+#include "ctkSettingsPanel.h"
+#include "ctkLogger.h"
+
+static ctkLogger logger("org.commontk.libs.widgets.ctkSettingsPanel");
+
+typedef QPair<QObject*, QString> PropertyType;
+
+//-----------------------------------------------------------------------------
+class ctkSettingsPanelPrivate
+{
+  Q_DECLARE_PUBLIC(ctkSettingsPanel);
+protected:
+  ctkSettingsPanel* const q_ptr;
+
+public:
+  ctkSettingsPanelPrivate(ctkSettingsPanel& object);
+  void init();
+
+  PropertyType property(const QString& key);
+  QVariant propertyValue(const PropertyType& property)const;
+  bool setPropertyValue(const PropertyType& property, const QVariant& val);
+
+  QSettings*                   Settings;
+  QMap<QString, PropertyType > Properties;
+  QSignalMapper*               SignalMapper;
+  bool                         SaveToSettingsWhenRegister;
+};
+
+// --------------------------------------------------------------------------
+ctkSettingsPanelPrivate::ctkSettingsPanelPrivate(ctkSettingsPanel& object)
+  :q_ptr(&object)
+{
+  this->Settings = 0;
+  this->SignalMapper = 0;
+  this->SaveToSettingsWhenRegister = true;
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsPanelPrivate::init()
+{
+  Q_Q(ctkSettingsPanel);
+  
+  this->SignalMapper = new QSignalMapper(q);
+  QObject::connect(this->SignalMapper, SIGNAL(mapped(const QString&)),
+                   q, SLOT(updateSetting(const QString&)));
+}
+
+// --------------------------------------------------------------------------
+PropertyType ctkSettingsPanelPrivate::property(const QString& key)
+{
+  PropertyType defaultProp(0, QString());
+  return this->Properties.value(key, defaultProp);
+}
+
+// --------------------------------------------------------------------------
+QVariant ctkSettingsPanelPrivate::propertyValue(const PropertyType& prop)const
+{
+  if (prop.first == 0 ||
+      prop.second.isEmpty())
+    {
+    return QVariant();
+    }
+  return prop.first->property(prop.second.toLatin1());
+}
+
+// --------------------------------------------------------------------------
+bool ctkSettingsPanelPrivate::setPropertyValue(const PropertyType& prop, const QVariant& val)
+{
+  if (prop.first == 0 ||
+      prop.second.isEmpty())
+    {
+    return false;
+    }
+  // the following return true if the property has been added using Q_PROPERTY
+  // false otherwise (and the property is then a dynamic property)
+  return prop.first->setProperty(prop.second.toLatin1(), val);
+}
+
+// --------------------------------------------------------------------------
+ctkSettingsPanel::ctkSettingsPanel(QWidget* _parent)
+  : Superclass(_parent)
+  , d_ptr(new ctkSettingsPanelPrivate(*this))
+{
+  Q_D(ctkSettingsPanel);
+  d->init();
+}
+
+// --------------------------------------------------------------------------
+ctkSettingsPanel::~ctkSettingsPanel()
+{
+}
+
+// --------------------------------------------------------------------------
+QSettings* ctkSettingsPanel::settings()const
+{
+  Q_D(const ctkSettingsPanel);
+  return d->Settings;
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsPanel::setSettings(QSettings* settings)
+{
+  Q_D(ctkSettingsPanel);
+  d->Settings = settings;
+  this->updateProperties();
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsPanel::updateProperties()
+{
+  Q_D(ctkSettingsPanel);
+  if (!d->Settings)
+    {
+    return;
+    }
+  foreach(const QString& key, d->Properties.keys())
+    {
+    QVariant value = d->Settings->contains(key);
+    if (value.isValid())
+      {
+      bool res = d->setPropertyValue(d->property(key), value);
+      Q_ASSERT(res);
+      Q_UNUSED(res);
+      }
+    }
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsPanel::registerProperty(const QString& key,
+                                        QObject* object,
+                                        const QString& property,
+                                        const char* signal)
+{
+  Q_D(ctkSettingsPanel);
+  d->Properties[key] = PropertyType(object, property);
+  d->SignalMapper->setMapping(object, key);
+  connect(object, signal, d->SignalMapper, SLOT(map()));
+  if (d->SaveToSettingsWhenRegister)
+    {
+    this->updateSetting(key);
+    }
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsPanel::updateSetting(const QString& key)
+{
+  Q_D(ctkSettingsPanel);
+  if (!d->Settings)
+    {
+    return;
+    }
+  QVariant oldVal = d->Settings->value(key);
+  QVariant newVal = d->propertyValue(d->property(key));
+  d->Settings->setValue(key, newVal);
+  if (d->Settings->status() != QSettings::NoError)
+    {
+    logger.warn( QString("Error %1 while writing setting %1")
+      .arg(d->Settings->status())
+      .arg(key));
+    }
+  if (oldVal != newVal)
+    {
+    emit settingChanged(key, newVal);
+    }
+}

+ 68 - 0
Libs/Widgets/ctkSettingsPanel.h

@@ -0,0 +1,68 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+#ifndef __ctkSettingsPanel_h
+#define __ctkSettingsPanel_h
+
+// Qt includes
+#include <QWidget>
+
+// CTK includes
+#include "ctkWidgetsExport.h"
+
+class QSettings;
+class ctkSettingsPanelPrivate;
+
+class CTK_WIDGETS_EXPORT ctkSettingsPanel : public QWidget
+{
+  Q_OBJECT
+public:
+  /// Superclass typedef
+  typedef QWidget Superclass;
+
+  /// Constructor
+  explicit ctkSettingsPanel(QWidget* parent = 0);
+
+  /// Destructor
+  virtual ~ctkSettingsPanel();
+
+  QSettings* settings()const;
+  void setSettings(QSettings* settings);
+
+  void registerProperty(const QString& key,
+                        QObject* object,
+                        const QString& property,
+                        const char* signal);
+signals:
+  void settingChanged(const QString& key, const QVariant& value);
+
+protected slots:
+  void updateSetting(const QString& key);
+
+protected:
+  QScopedPointer<ctkSettingsPanelPrivate> d_ptr;
+
+  virtual void updateProperties();
+private:
+  Q_DECLARE_PRIVATE(ctkSettingsPanel);
+  Q_DISABLE_COPY(ctkSettingsPanel);
+};
+
+#endif

+ 217 - 0
Libs/Widgets/ctkSettingsWidget.cpp

@@ -0,0 +1,217 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+// Qt includes
+#include <QDebug>
+#include <QMap>
+#include <QSettings>
+
+// CTK includes
+#include "ctkSettingsPanel.h"
+#include "ctkSettingsWidget.h"
+#include "ui_ctkSettingsWidget.h"
+#include "ctkLogger.h"
+
+static ctkLogger logger("org.commontk.libs.widgets.ctkSettingsWidget");
+
+//-----------------------------------------------------------------------------
+class ctkSettingsWidgetPrivate: public Ui_ctkSettingsWidget
+{
+  Q_DECLARE_PUBLIC(ctkSettingsWidget);
+protected:
+  ctkSettingsWidget* const q_ptr;
+public:
+  ctkSettingsWidgetPrivate(ctkSettingsWidget& object);
+  void init();
+
+  ctkSettingsPanel* panel(QTreeWidgetItem* item)const;
+  QTreeWidgetItem* item(ctkSettingsPanel* panel)const;
+  QTreeWidgetItem* item(const QString& label)const;
+
+  void beginGroup(ctkSettingsPanel* panel);
+  void endGroup(ctkSettingsPanel* panel);
+
+  QSettings* Settings;
+
+protected:
+  QMap<QTreeWidgetItem*, ctkSettingsPanel*> Panels;
+};
+
+// --------------------------------------------------------------------------
+ctkSettingsWidgetPrivate::ctkSettingsWidgetPrivate(ctkSettingsWidget& object)
+  :q_ptr(&object)
+{
+  this->Settings = 0;
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsWidgetPrivate::init()
+{
+  Q_Q(ctkSettingsWidget);
+  this->setupUi(q);
+
+  QObject::connect(this->SettingsTreeWidget,
+    SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
+    q, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
+}
+
+// --------------------------------------------------------------------------
+ctkSettingsPanel* ctkSettingsWidgetPrivate::panel(QTreeWidgetItem* item)const
+{
+  return this->Panels.value(item, 0);
+}
+
+// --------------------------------------------------------------------------
+QTreeWidgetItem* ctkSettingsWidgetPrivate::item(ctkSettingsPanel* panel)const
+{
+  return this->Panels.key(panel, this->SettingsTreeWidget->invisibleRootItem());
+}
+
+// --------------------------------------------------------------------------
+QTreeWidgetItem* ctkSettingsWidgetPrivate::item(const QString& label)const
+{
+  QMap<QTreeWidgetItem*, ctkSettingsPanel*>::const_iterator it;
+  for (it = this->Panels.constBegin(); it != this->Panels.constEnd(); ++it)
+    {
+    if (it.value()->windowTitle() == label)
+      {
+      return it.key();
+      }
+    }
+  return this->SettingsTreeWidget->invisibleRootItem();
+}
+
+// --------------------------------------------------------------------------
+ctkSettingsWidget::ctkSettingsWidget(QWidget* _parent)
+  : Superclass(_parent)
+  , d_ptr(new ctkSettingsWidgetPrivate(*this))
+{
+  Q_D(ctkSettingsWidget);
+  d->init();
+}
+
+// --------------------------------------------------------------------------
+ctkSettingsWidget::~ctkSettingsWidget()
+{
+}
+
+// --------------------------------------------------------------------------
+QSettings* ctkSettingsWidget::settings()const
+{
+  Q_D(const ctkSettingsWidget);
+  return d->Settings;
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsWidget::setSettings(QSettings* settings)
+{
+  Q_D(ctkSettingsWidget);
+
+  d->Settings = settings;
+  foreach(ctkSettingsPanel* panel, d->Panels.values())
+    {
+    panel->setSettings(settings);
+    }
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsWidget
+::addPanel(ctkSettingsPanel* panel, ctkSettingsPanel* parentPanel)
+{
+  Q_D(ctkSettingsWidget);
+  QTreeWidgetItem* newPanelItem = new QTreeWidgetItem;
+  newPanelItem->setText(0, panel->windowTitle());
+  newPanelItem->setIcon(0, panel->windowIcon());
+
+  d->Panels[newPanelItem] = panel;
+  QTreeWidgetItem* parentItem = d->item(parentPanel);
+  parentItem->addChild(newPanelItem);
+  d->SettingsStackedWidget->addWidget(panel);
+
+  connect(panel, SIGNAL(settingChanged(const QString&, const QVariant&)),
+          this, SIGNAL(settingChanged(const QString&, const QVariant&)));
+  panel->setSettings(this->settings());
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsWidget
+::addPanel(const QString& label, ctkSettingsPanel* panel, 
+           ctkSettingsPanel* parentPanel)
+{
+  panel->setWindowTitle(label);
+  this->addPanel(panel, parentPanel);
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsWidget
+::addPanel(const QString& label, const QIcon& icon,
+           ctkSettingsPanel* panel, ctkSettingsPanel* parentPanel)
+{
+  panel->setWindowTitle(label);
+  panel->setWindowIcon(icon);
+  this->addPanel(panel, parentPanel);
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsWidget::setCurrentPanel(ctkSettingsPanel* panel)
+{
+  Q_D(ctkSettingsWidget);
+  // eventually calls onCurrentItemChanged() where all the work is done
+  d->SettingsTreeWidget->setCurrentItem(d->item(panel));
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsWidget::setCurrentPanel(const QString& label)
+{
+  Q_D(ctkSettingsWidget);
+  // eventually calls onCurrentItemChanged() where all the work is done
+  d->SettingsTreeWidget->setCurrentItem(d->item(label));
+}
+
+// --------------------------------------------------------------------------
+ctkSettingsPanel* ctkSettingsWidget::currentPanel()const
+{
+  Q_D(const ctkSettingsWidget);
+  return d->panel(d->SettingsTreeWidget->currentItem());
+}
+
+// --------------------------------------------------------------------------
+ctkSettingsPanel* ctkSettingsWidget::panel(const QString& label)const
+{
+  Q_D(const ctkSettingsWidget);
+  foreach(ctkSettingsPanel* settingsPanel, d->Panels.values())
+    {
+    if (settingsPanel->windowTitle() == label)
+      {
+      return settingsPanel;
+      }
+    }
+  return 0;
+}
+
+// --------------------------------------------------------------------------
+void ctkSettingsWidget
+::onCurrentItemChanged(QTreeWidgetItem* currentItem, QTreeWidgetItem* previousItem)
+{
+  Q_D(ctkSettingsWidget);
+  Q_UNUSED(previousItem);
+  d->SettingsStackedWidget->setCurrentWidget(
+    d->panel(currentItem));
+}

+ 78 - 0
Libs/Widgets/ctkSettingsWidget.h

@@ -0,0 +1,78 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+#ifndef __ctkSettingsWidget_h
+#define __ctkSettingsWidget_h
+
+// Qt includes
+#include <QWidget>
+
+// CTK includes
+#include "ctkWidgetsExport.h"
+
+class ctkSettingsWidgetPrivate;
+class QTreeWidgetItem;
+class ctkSettingsPanel;
+class QSettings;
+
+class CTK_WIDGETS_EXPORT ctkSettingsWidget : public QWidget
+{
+  Q_OBJECT
+public:
+  /// Superclass typedef
+  typedef QWidget Superclass;
+
+  /// Constructor
+  explicit ctkSettingsWidget(QWidget* parent = 0);
+
+  /// Destructor
+  virtual ~ctkSettingsWidget();
+
+  QSettings* settings()const;
+  void setSettings(QSettings* settings);
+
+  ctkSettingsPanel* panel(const QString& panel)const;
+  ctkSettingsPanel* currentPanel()const;
+
+  /// Uses the ctkSettingsPanel::windowTitle property to show in the list
+  void addPanel(ctkSettingsPanel* panel, ctkSettingsPanel* parentPanel = 0);
+  /// Utility function 
+  void addPanel(const QString& label, ctkSettingsPanel* panel, ctkSettingsPanel* parentPanel = 0);
+  void addPanel(const QString& label, const QIcon& icon, ctkSettingsPanel* panel, ctkSettingsPanel* parentPanel = 0);
+
+public slots:
+  void setCurrentPanel(ctkSettingsPanel* panel);
+  void setCurrentPanel(const QString& label);
+
+signals:
+  void settingChanged(const QString& key, const QVariant& value);
+
+protected slots:
+  void onCurrentItemChanged(QTreeWidgetItem* currentItem, QTreeWidgetItem* previous);
+
+protected:
+  QScopedPointer<ctkSettingsWidgetPrivate> d_ptr;
+
+private:
+  Q_DECLARE_PRIVATE(ctkSettingsWidget);
+  Q_DISABLE_COPY(ctkSettingsWidget);
+};
+
+#endif