Procházet zdrojové kódy

ENH: Added ctkTestApplication and ctkAddRemoveComboBox

Jean-Christophe Fillion-Robin před 15 roky
rodič
revize
985dd2d06c

+ 9 - 2
Libs/Widgets/CMakeLists.txt

@@ -12,12 +12,16 @@ SET(KIT_include_directories
   
 # Source files
 SET(KIT_SRCS
+  ctkAddRemoveComboBox.cpp
+  ctkAddRemoveComboBox.h
   ctkColorPickerButton.cpp
   ctkColorPickerButton.h
   ctkMatrixWidget.cpp
   ctkMatrixWidget.h
   ctkSettings.cpp
   ctkSettings.h
+  ctkTestApplication.cpp
+  ctkTestApplication.h
   ctkTransferFunctionItems.cpp
   ctkTransferFunctionItems.h
   ctkTransferFunctionWidget.cpp
@@ -26,20 +30,23 @@ SET(KIT_SRCS
 
 # Headers that should run through moc
 SET(KIT_MOC_SRCS
+  ctkAddRemoveComboBox.h
   ctkColorPickerButton.h
   ctkMatrixWidget.h
   ctkSettings.h
+  ctkTestApplication.h
   ctkTransferFunctionItems.h
   ctkTransferFunctionWidget.h
   )
 
 # UI files
 SET(KIT_UI_FORMS
-)
+  Resources/UI/ctkAddRemoveComboBox.ui
+  )
 
 # Resources
 SET(KIT_resources
-)
+  )
 
 # Target libraries - See CMake/ctkMacroGetTargetLibraries.cmake
 # The following macro will read the target libraries from the file 'target_libraries.cmake'

+ 1 - 1
Libs/Widgets/Plugins/CMakeLists.txt

@@ -68,7 +68,7 @@ SET(PLUGIN_MOC_SRCS
 
 # Resources
 SET(PLUGIN_resources
-  Resources/ctkVisualizationVTKWidgetsPlugins.qrc
+  Resources/CTKWidgetsPlugins.qrc
 )
 
 # Target libraries

Libs/Widgets/Plugins/Resources/ctkVisualizationVTKWidgetsPlugins.qrc → Libs/Widgets/Plugins/Resources/CTKWidgetsPlugins.qrc


+ 9 - 0
Libs/Widgets/Resources/CTKWidgets.qrc

@@ -0,0 +1,9 @@
+<!DOCTYPE RCC><RCC version="1.0">
+  <qresource>
+    <file>Icons/edit.png</file>
+    <file>Icons/minus-16.png</file>
+    <file>Icons/plus-16.png</file>
+    <file>Icons/expand-down.png</file>
+    <file>Icons/expand-up.png</file>
+  </qresource>
+</RCC>

binární
Libs/Widgets/Resources/Icons/edit.png


binární
Libs/Widgets/Resources/Icons/expand-down.png


binární
Libs/Widgets/Resources/Icons/expand-up.png


binární
Libs/Widgets/Resources/Icons/minus-16.png


binární
Libs/Widgets/Resources/Icons/plus-16.png


+ 105 - 0
Libs/Widgets/Resources/UI/ctkAddRemoveComboBox.ui

@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ctkAddRemoveComboBox</class>
+ <widget class="QWidget" name="ctkAddRemoveComboBox">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>251</width>
+    <height>23</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>ctkAddRemoveComboBox</string>
+  </property>
+  <layout class="QHBoxLayout">
+   <property name="spacing">
+    <number>2</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QComboBox" name="ComboBox">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="AddPushButton">
+     <property name="toolTip">
+      <string>Add an object</string>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+     <property name="icon">
+      <iconset resource="../CTKWidgets.qrc">
+       <normaloff>:/Icons/plus-16.png</normaloff>:/Icons/plus-16.png</iconset>
+     </property>
+     <property name="iconSize">
+      <size>
+       <width>8</width>
+       <height>8</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="RemovePushButton">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="toolTip">
+      <string>Remove select object</string>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+     <property name="icon">
+      <iconset resource="../CTKWidgets.qrc">
+       <normaloff>:/Icons/minus-16.png</normaloff>:/Icons/minus-16.png</iconset>
+     </property>
+     <property name="iconSize">
+      <size>
+       <width>8</width>
+       <height>8</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="EditPushButton">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="toolTip">
+      <string>Edit selected object</string>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+     <property name="icon">
+      <iconset resource="../CTKWidgets.qrc">
+       <normaloff>:/Icons/edit.png</normaloff>:/Icons/edit.png</iconset>
+     </property>
+     <property name="iconSize">
+      <size>
+       <width>8</width>
+       <height>8</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../CTKWidgets.qrc"/>
+ </resources>
+ <connections/>
+</ui>

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

@@ -1,8 +1,9 @@
 SET(KIT ${PROJECT_NAME})
 
 CREATE_TEST_SOURCELIST(Tests ${KIT}CppTests.cxx
-  ctkColorPickerButtonTest1.cxx
-  ctkMatrixWidgetTest1.cxx
+  ctkAddRemoveComboBoxTest1.cpp
+  ctkColorPickerButtonTest1.cpp
+  ctkMatrixWidgetTest1.cpp
   #EXTRA_INCLUDE TestingMacros.h
   )
 
@@ -28,5 +29,6 @@ ENDMACRO( SIMPLE_TEST  )
 # Add Tests
 #
 
+SIMPLE_TEST( ctkAddRemoveComboBoxTest1 )
 SIMPLE_TEST( ctkColorPickerButtonTest1 )
 SIMPLE_TEST( ctkMatrixWidgetTest1 )

+ 151 - 0
Libs/Widgets/Testing/Cpp/ctkAddRemoveComboBoxTest1.cpp

@@ -0,0 +1,151 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc. 
+  All rights reserved.
+  Distributed under a BSD License. See LICENSE.txt file.
+
+  This software is distributed "AS IS" WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the above copyright notice for more information.
+
+=========================================================================*/
+
+// Qt includes
+#include <QSignalSpy>
+
+// CTK includes
+#include "ctkAddRemoveComboBox.h"
+#include "ctkTestApplication.h"
+
+// STD includes
+#include <cstdlib>
+#include <iostream>
+
+//-----------------------------------------------------------------------------
+QCTK_DECLARE_TEST(ctkAddRemoveComboBoxTest1)
+{
+  ctkAddRemoveComboBox ctkObject;
+  
+  int currentCount = ctkObject.count();
+  if (currentCount != 0)
+    {
+    ctkObject.printAdditionalInfo();
+    std::cerr << __LINE__ << " - Error in count() - Expected: 0, current:" << currentCount << std::endl;
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+
+  // Add items
+  ctkObject.addItem("Item1");
+  ctkObject.addItem("Item2");
+  ctkObject.addItem("Item3");
+
+  currentCount = ctkObject.count();
+  if (currentCount != 3)
+    {
+    ctkObject.printAdditionalInfo();
+    std::cerr << __LINE__ << " - Error in count() - Expected: 3, current:" << currentCount << std::endl;
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+
+  if (ctkObject.itemText(0) != "Item1" ||
+      ctkObject.itemText(1) != "Item2" ||
+      ctkObject.itemText(2) != "Item3")
+    {
+    ctkObject.printAdditionalInfo();
+    std::cerr << __LINE__ << " - Error in itemText()" << std::endl
+              << " Expected items [Item1, Item2, Item3]" << std::endl
+              << " Current items [" << qPrintable(ctkObject.itemText(0)) << ", "
+                                    << qPrintable(ctkObject.itemText(1)) << ", "
+                                    << qPrintable(ctkObject.itemText(2)) << "]" << std::endl;
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+
+  ctkObject.removeItem(1);
+
+  currentCount = ctkObject.count();
+  if (currentCount != 2)
+    {
+    ctkObject.printAdditionalInfo();
+    std::cerr << __LINE__ << " - Error in count() - Expected: 2, current:" << currentCount << std::endl;
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+
+  if (ctkObject.itemText(0) != "Item1" ||
+      ctkObject.itemText(1) != "Item3")
+    {
+    ctkObject.printAdditionalInfo();
+    std::cerr << __LINE__ << " - Error in itemText()" << std::endl
+              << " Expected items [Item1, Item3]" << std::endl
+              << " Current items [" << qPrintable(ctkObject.itemText(0)) << ", "
+                                    << qPrintable(ctkObject.itemText(1)) << "]" << std::endl;
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+
+  ctkObject.addItem("Item4");
+
+  currentCount = ctkObject.count();
+  if (currentCount != 3)
+    {
+    ctkObject.printAdditionalInfo();
+    std::cerr << __LINE__ << " - Error in count() - Expected: 3, current:" << currentCount << std::endl;
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+
+  if (ctkObject.itemText(0) != "Item1" ||
+      ctkObject.itemText(1) != "Item3" ||
+      ctkObject.itemText(2) != "Item4")
+    {
+    ctkObject.printAdditionalInfo();
+    std::cerr << __LINE__ << " - Error in itemText()" << std::endl
+              << " Expected items [Item1, Item3, Item4]" << std::endl
+              << " Current items [" << qPrintable(ctkObject.itemText(0)) << ", "
+                                    << qPrintable(ctkObject.itemText(1)) << ", "
+                                    << qPrintable(ctkObject.itemText(2)) << "]" << std::endl;
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+
+  ctkObject.clear();
+
+  currentCount = ctkObject.count();
+  if (currentCount != 0)
+    {
+    ctkObject.printAdditionalInfo();
+    std::cerr << __LINE__ << " - Error in count() - Expected: 0, current:" << currentCount << std::endl;
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+
+  ctkObject.addItem("Item5");
+
+  currentCount = ctkObject.count();
+  if (currentCount != 1)
+    {
+    ctkObject.printAdditionalInfo();
+    std::cerr << __LINE__ << " - Error in count() - Expected: 1, current:" << currentCount << std::endl;
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+
+  if (ctkObject.itemText(0) != "Item5")
+    {
+    ctkObject.printAdditionalInfo();
+    std::cerr << __LINE__ << " - Error in itemText()" << std::endl
+              << " Expected items [Item5]" << std::endl
+              << " Current items [" << qPrintable(ctkObject.itemText(0)) << "]" << std::endl;
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+
+  ctkObject.clear();
+
+  currentCount = ctkObject.count();
+  if (currentCount != 0)
+    {
+    ctkObject.printAdditionalInfo();
+    std::cerr << __LINE__ << " - Error in count() - Expected: 0, current:" << currentCount << std::endl;
+    QCTK_EXIT_TEST(EXIT_FAILURE);
+    }
+    
+  QCTK_EXIT_TEST(EXIT_SUCCESS);
+}
+
+QCTK_RUN_TEST(ctkAddRemoveComboBoxTest1);

Libs/Widgets/Testing/Cpp/ctkColorPickerButtonTest1.cxx → Libs/Widgets/Testing/Cpp/ctkColorPickerButtonTest1.cpp


Libs/Widgets/Testing/Cpp/ctkMatrixWidgetTest1.cxx → Libs/Widgets/Testing/Cpp/ctkMatrixWidgetTest1.cpp


+ 533 - 0
Libs/Widgets/ctkAddRemoveComboBox.cpp

@@ -0,0 +1,533 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc. 
+  All rights reserved.
+  Distributed under a BSD License. See LICENSE.txt file.
+
+  This software is distributed "AS IS" WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the above copyright notice for more information.
+
+=========================================================================*/
+
+// Qt includes
+#include <QDebug>
+
+// CTK includes
+#include <ctkPimpl.h>
+#include "ctkAddRemoveComboBox.h"
+#include "ui_ctkAddRemoveComboBox.h"
+
+//-----------------------------------------------------------------------------
+class ctkAddRemoveComboBoxPrivate : public ctkPrivate<ctkAddRemoveComboBox>,
+                                    public Ui_ctkAddRemoveComboBox
+{
+public:
+  ctkAddRemoveComboBoxPrivate();
+
+  /// 
+  /// Insert 'None' item
+  /// Note: Also make sure that no signal is emitted while the item is inserted
+  /// That function doesn't prevent from inserting multiple time the 'None' item
+  void insertEmptyItem();
+
+  void connectComboBox(QComboBox* combobox);
+
+public:
+  /// Empty item
+  QString EmptyText;
+
+  /// Set to true when inserting the 'None' item.
+  /// Will prevent the itemAdded signal from being sent
+  bool    AddingEmptyItem; 
+
+  /// Set to true when removing the 'None' item.
+  /// Will prevent the itemRemoved signal from being sent
+  bool    RemovingEmptyItem;
+
+  /// Actions state
+  bool    AddEnabled;
+  bool    RemoveEnabled;
+  bool    EditEnabled;
+
+  /// If true, it means there is no item beside of the 'None' one
+  bool    HasEmptyItem;
+};
+
+// --------------------------------------------------------------------------
+// ctkAddRemoveComboBoxPrivate methods
+
+// --------------------------------------------------------------------------
+ctkAddRemoveComboBoxPrivate::ctkAddRemoveComboBoxPrivate()
+{
+  this->EmptyText = "None";
+
+  this->AddingEmptyItem = false;
+  this->RemovingEmptyItem = false;
+
+  this->AddEnabled = true;
+  this->RemoveEnabled = true;
+  this->EditEnabled = true;
+
+  this->HasEmptyItem = false;
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBoxPrivate::insertEmptyItem()
+{
+  if (!this->HasEmptyItem )
+    {
+    this->AddingEmptyItem = true;
+    this->ComboBox->insertItem(0, this->EmptyText);
+    this->AddingEmptyItem = false;
+    this->HasEmptyItem = true;
+    }
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBoxPrivate::connectComboBox(QComboBox* comboBox)
+{
+  CTK_P(ctkAddRemoveComboBox);
+  QObject::connect(comboBox, SIGNAL(activated(int)),
+                p, SIGNAL(activated(int)));
+  QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)),
+                p, SIGNAL(currentIndexChanged(int)));
+  /*
+  this->connect(ctk_d()->ComboBox->model(),
+  SIGNAL(rowsAboutToBeInserted(const QModelIndex & _parent, int start, int end )),
+  SLOT(onRowsAboutToBeInserted(const QModelIndex & _parent, int start, int end )));
+  */
+  QObject::connect(comboBox->model(),
+                SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
+                p, SLOT(onRowsAboutToBeRemoved(const QModelIndex & , int , int  )));
+
+  QObject::connect(comboBox->model(),
+                SIGNAL(rowsInserted(const QModelIndex &, int, int )),
+                p, SLOT(onRowsInserted(const QModelIndex &, int, int)));
+  QObject::connect(comboBox->model(),
+                SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
+                p, SLOT(onRowsRemoved(const QModelIndex &, int, int )));
+}
+
+// --------------------------------------------------------------------------
+// ctkAddRemoveComboBox methods
+
+// --------------------------------------------------------------------------
+ctkAddRemoveComboBox::ctkAddRemoveComboBox(QWidget* _parent) : Superclass(_parent)
+{
+  CTK_INIT_PRIVATE(ctkAddRemoveComboBox);
+  CTK_D(ctkAddRemoveComboBox);
+  d->setupUi(this);
+  
+  // connect
+  d->connectComboBox(d->ComboBox);
+    
+  this->connect(d->AddPushButton, SIGNAL(pressed()), SLOT(onAdd()));
+  this->connect(d->RemovePushButton, SIGNAL(pressed()), SLOT(onRemove()));
+  this->connect(d->EditPushButton, SIGNAL(pressed()), SLOT(onEdit()));
+
+  // Add default 'empty item'
+  d->insertEmptyItem();
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::printAdditionalInfo()
+{
+  CTK_D(ctkAddRemoveComboBox);
+  qDebug() << "ctkAddRemoveComboBox:" << this << endl
+           << " EmptyText:" << d->EmptyText << endl
+           << " AddingEmptyItem:" << d->AddingEmptyItem << endl
+           << " RemovingEmptyItem:" << d->RemovingEmptyItem << endl
+           << " AddEnabled:" << d->AddEnabled << endl
+           << " RemoveEnabled:" << d->RemoveEnabled << endl
+           << " EditEnabled:" << d->EditEnabled << endl
+           << " HasEmptyItem:" << d->HasEmptyItem;
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::setComboBox(QComboBox* comboBox)
+{
+  CTK_D(ctkAddRemoveComboBox);
+  if ((comboBox == d->ComboBox) ||
+      comboBox->count())
+    {
+    return;
+    }
+  
+  QLayoutItem* oldComboBoxItem = this->layout()->takeAt(0);
+  QComboBox* oldComboBox = qobject_cast<QComboBox*>(oldComboBoxItem->widget());
+  comboBox->setSizePolicy(oldComboBox->sizePolicy());
+  comboBox->setEnabled(this->comboBoxEnabled());
+
+  delete oldComboBoxItem;
+
+  dynamic_cast<QBoxLayout*>(this->layout())->insertWidget(0, comboBox);
+  d->connectComboBox(comboBox);
+  d->ComboBox = comboBox;
+  delete oldComboBox;
+
+  // Add default 'empty item'
+  d->insertEmptyItem();
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::setEmptyText(const QString& text)
+{
+  CTK_D(ctkAddRemoveComboBox);
+  
+  if (d->HasEmptyItem)
+    {
+    Q_ASSERT(d->ComboBox->count() == 1);
+    this->setItemText(0, text);
+    }
+  d->EmptyText = text;
+}
+
+// --------------------------------------------------------------------------
+CTK_GET_CXX(ctkAddRemoveComboBox, QString, emptyText, EmptyText);
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::onRowsInserted(const QModelIndex & _parent, int start, int end)
+{
+  CTK_D(ctkAddRemoveComboBox);
+  
+  if (_parent != d->ComboBox->rootModelIndex())
+    {// Rows that are to be added in the model are not displayed by the combobox
+    return;
+    }
+    
+  if (d->HasEmptyItem && !d->AddingEmptyItem)
+    {
+    // Remove the Empty item as some real items have been added
+    d->HasEmptyItem = false;
+    d->RemovingEmptyItem = true;
+    d->ComboBox->removeItem(start == 0 ? end + 1 : 0);
+    d->RemovingEmptyItem = false;
+    
+    if (d->RemoveEnabled)
+      {
+      d->RemovePushButton->setEnabled(true);
+      }
+    if (d->EditEnabled)
+      {
+      d->EditPushButton->setEnabled(true);
+      }
+    // Since we just removed the empty item, we need to shift the start/end items if needed
+    if (start > 0 )
+      {
+      --start;
+      --end;
+      }
+    }
+
+  // Emit signal only if the items added is *NOT* the Empty item
+  if (!d->AddingEmptyItem)
+    {
+    for (int i = start; i <= end; ++i)
+      {
+      emit this->itemAdded(i);
+      }
+    }
+ }
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::onRowsAboutToBeRemoved(const QModelIndex & _parent, int start, int end)
+{
+  CTK_D(ctkAddRemoveComboBox);
+
+  if (_parent != d->ComboBox->rootModelIndex())
+    {//rows that are to be added in the model are not displayed by the combobox
+    return;
+    }
+
+  // if the user try to remove the Empty item, don't send event
+  if (d->RemovingEmptyItem)
+    {
+    return;
+    }
+  for (int i = start; i <= end; ++i)
+    {
+    emit this->itemAboutToBeRemoved(i);
+    }
+}
+
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::onRowsRemoved(const QModelIndex & _parent, int start, int end)
+{
+  CTK_D(ctkAddRemoveComboBox);
+  
+  if (_parent != d->ComboBox->rootModelIndex())
+    {//rows that are to be added in the model are not displayed by the combobox
+    return;
+    }
+  // the combobox is now empty, add the EmptyItem if needed
+  if (d->ComboBox->count() == 0)
+    {
+    // Add default 'empty item'
+    d->insertEmptyItem();
+   
+    if (d->RemoveEnabled)
+      {
+      d->RemovePushButton->setEnabled(false);
+      }
+    if (d->EditEnabled)
+      {
+      d->EditPushButton->setEnabled(false);
+      }
+    }
+
+  if (!d->RemovingEmptyItem)
+    {
+    for (int i = start; i <= end; ++i)
+      {
+      emit this->itemRemoved(i);
+      }
+    }
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::setComboBoxEnabled(bool enable)
+{
+  ctk_d()->ComboBox->setEnabled(enable);
+}
+
+// --------------------------------------------------------------------------
+bool ctkAddRemoveComboBox::comboBoxEnabled()const
+{
+  //const cast as I'm not sure why isEnabledTo doesn't take a const
+  return ctk_d()->ComboBox->isEnabledTo(const_cast<ctkAddRemoveComboBox*>(this));
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::setAddEnabled(bool enable)
+{
+  CTK_D(ctkAddRemoveComboBox);
+  
+  d->AddPushButton->setEnabled(enable);
+  d->AddEnabled = enable;
+}
+
+// --------------------------------------------------------------------------
+bool ctkAddRemoveComboBox::addEnabled()const
+{
+  return ctk_d()->AddEnabled;
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::setRemoveEnabled(bool enable)
+{
+  CTK_D(ctkAddRemoveComboBox);
+  
+  if (this->count() > 0)
+    {
+    d->RemovePushButton->setEnabled(enable);
+    }
+  d->RemoveEnabled = enable;
+}
+
+// --------------------------------------------------------------------------
+bool ctkAddRemoveComboBox::removeEnabled()const
+{
+  return ctk_d()->RemoveEnabled;
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::setEditEnabled(bool enable)
+{
+  CTK_D(ctkAddRemoveComboBox);
+  
+  if (this->count() > 0)
+    { 
+    d->EditPushButton->setEnabled(enable);
+    }
+  d->EditEnabled = enable;
+}
+
+// --------------------------------------------------------------------------
+bool ctkAddRemoveComboBox::editEnabled()const
+{
+  return ctk_d()->EditEnabled;
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::onAdd()
+{
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::onRemove()
+{
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::onEdit()
+{
+}
+
+// --------------------------------------------------------------------------
+int ctkAddRemoveComboBox::count()const
+{
+  CTK_D(const ctkAddRemoveComboBox);
+  return (d->HasEmptyItem ? 0 : d->ComboBox->count());
+}
+
+// --------------------------------------------------------------------------
+CTK_GET_CXX(ctkAddRemoveComboBox, bool, empty, HasEmptyItem);
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::setCurrentIndex(int index)
+{
+  return ctk_d()->ComboBox->setCurrentIndex(index);
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::insertItem(int index, const QString &text, const QVariant &userDataVariable)
+{
+  //qDebug() << __FUNCTION__ << " " << index <<  " " << text << " " << userDataVariable ;
+  ctk_d()->ComboBox->insertItem(index, text, userDataVariable);
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::insertItem(int index, const QIcon &icon, const QString &text, const QVariant &userDataVariable)
+{
+  ctk_d()->ComboBox->insertItem(index, icon, text, userDataVariable);
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::insertItems(int index, const QStringList &texts)
+{
+  ctk_d()->ComboBox->insertItems(index, texts);
+}
+  
+// --------------------------------------------------------------------------
+int ctkAddRemoveComboBox::findText(const QString & text, Qt::MatchFlags flags)const
+{
+  CTK_D(const ctkAddRemoveComboBox);
+  
+  if (d->HasEmptyItem)
+    { // if the scene is empty, don't even try to find the text (it could be the
+      // one of the EmptyText prop.
+    return -1;
+    }
+  return d->ComboBox->findText(text, flags);
+}
+
+// --------------------------------------------------------------------------
+int ctkAddRemoveComboBox::findData(const QVariant &dataVariable, int role, Qt::MatchFlags flags)const
+{
+  CTK_D(const ctkAddRemoveComboBox);
+  
+  if (d->HasEmptyItem)
+    { // if the scene is empty, don't even try to find the dataVariable 
+    return -1;
+    }
+  return d->ComboBox->findData(dataVariable, role, flags);
+}
+
+// --------------------------------------------------------------------------
+QString ctkAddRemoveComboBox::itemText(int index) const
+{
+  CTK_D(const ctkAddRemoveComboBox);
+  
+  if (d->HasEmptyItem)
+    {
+    return QString();
+    }
+  return d->ComboBox->itemText(index);
+}
+  
+// --------------------------------------------------------------------------
+QVariant ctkAddRemoveComboBox::itemData(int index, int role) const
+{
+  CTK_D(const ctkAddRemoveComboBox);
+  
+  if (d->HasEmptyItem)
+    {
+    return QVariant();
+    }
+  return d->ComboBox->itemData(index,role);
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::setItemText(int index, const QString& text)
+{
+  CTK_D(ctkAddRemoveComboBox);
+  
+  if (d->HasEmptyItem)
+    {
+    return;
+    }
+  return d->ComboBox->setItemText(index, text);
+}
+  
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::setItemData(int index, const QVariant& dataVariable, int role)
+{
+  CTK_D(ctkAddRemoveComboBox);
+  
+  if (d->HasEmptyItem)
+    {
+    return;
+    }
+  d->ComboBox->setItemData(index, dataVariable, role);
+}
+
+// --------------------------------------------------------------------------
+int ctkAddRemoveComboBox::currentIndex() const
+{
+  CTK_D(const ctkAddRemoveComboBox);
+  
+  return d->HasEmptyItem ? -1 : d->ComboBox->currentIndex();
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::removeItem(int index)
+{
+  CTK_D(ctkAddRemoveComboBox);
+  
+  if (d->HasEmptyItem)
+    {
+    return; 
+    }
+  d->ComboBox->removeItem(index);
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::clear()
+{
+  CTK_D(ctkAddRemoveComboBox);
+  
+  if (d->HasEmptyItem)
+    {
+    return;
+    }
+  d->ComboBox->clear();
+}
+
+// --------------------------------------------------------------------------
+QModelIndex ctkAddRemoveComboBox::rootModelIndex()const
+{
+  return ctk_d()->ComboBox->rootModelIndex();
+}
+
+// --------------------------------------------------------------------------
+void ctkAddRemoveComboBox::setRootModelIndex(const QModelIndex& root)
+{
+  ctk_d()->ComboBox->setRootModelIndex(root);
+}
+
+// --------------------------------------------------------------------------
+int ctkAddRemoveComboBox::modelColumn()const
+{
+  return ctk_d()->ComboBox->modelColumn();
+}
+
+// --------------------------------------------------------------------------
+QAbstractItemModel* ctkAddRemoveComboBox::model()const
+{
+  return ctk_d()->ComboBox->model();
+}
+

+ 160 - 0
Libs/Widgets/ctkAddRemoveComboBox.h

@@ -0,0 +1,160 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc. 
+  All rights reserved.
+  Distributed under a BSD License. See LICENSE.txt file.
+
+  This software is distributed "AS IS" WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the above copyright notice for more information.
+
+=========================================================================*/
+
+#ifndef __ctkAddRemoveComboBox_h
+#define __ctkAddRemoveComboBox_h
+
+// Qt includes
+#include <QWidget>
+#include <QVariant>
+#include <QModelIndex>
+
+// CTK includes
+#include <ctkPimpl.h>
+
+#include "CTKWidgetsExport.h"
+
+class QComboBox;
+class ctkAddRemoveComboBoxPrivate;
+
+class CTK_WIDGETS_EXPORT ctkAddRemoveComboBox : public QWidget
+{
+  Q_OBJECT
+  Q_PROPERTY(QString emptyText READ emptyText WRITE setEmptyText)
+  Q_PROPERTY(bool addEnabled READ addEnabled WRITE setAddEnabled)
+  Q_PROPERTY(bool removeEnabled READ removeEnabled WRITE setRemoveEnabled)
+  Q_PROPERTY(bool editEnabled READ editEnabled WRITE setEditEnabled)
+  
+public:
+  /// Superclass typedef
+  typedef QWidget Superclass;
+  
+  /// Constructors
+  explicit ctkAddRemoveComboBox(QWidget* parent = 0);
+  virtual ~ctkAddRemoveComboBox(){}
+  virtual void printAdditionalInfo();
+  
+  /// 
+  /// Set text that should be displayed in the comboBox when it is empty
+  void setEmptyText(const QString& text); 
+  QString emptyText()const;
+  
+  /// 
+  /// Enable/Disable the add button. 
+  void setComboBoxEnabled(bool enable);
+  bool comboBoxEnabled()const; 
+  
+  /// 
+  /// Enable/Disable the add button. 
+  void setAddEnabled(bool enable);
+  bool addEnabled()const; 
+  
+  /// 
+  /// Enable/Disable the add button. 
+  void setRemoveEnabled(bool enable);
+  bool removeEnabled()const;
+  
+  /// 
+  /// Enable/Disable the edit button. 
+  void setEditEnabled(bool enable); 
+  bool editEnabled()const;
+  
+  inline void addItem(const QString &text, const QVariant &userDataVariable = QVariant() )
+    {this->insertItem(this->count(), text, userDataVariable);}
+  inline void addItem(const QIcon &icon, const QString &text, const QVariant &userDataVariable = QVariant() )
+    {this->insertItem(this->count(), icon, text, userDataVariable);}
+  inline void addItems(const QStringList &texts )
+    {this->insertItems(this->count(), texts);}
+    
+  void insertItem(int index, const QString &text, const QVariant &userDataVariable = QVariant() );
+  void insertItem(int index, const QIcon &icon, const QString &text, const QVariant &userDataVariable = QVariant() );
+  void insertItems(int index, const QStringList &texts);  
+  
+  /// 
+  /// Return the number of item
+  int count()const;
+  bool empty()const;
+    
+  /// 
+  /// Returns the index of the item containing the given text; otherwise returns -1.
+  /// The flags specify how the items in the combobox are searched.
+  int findText(const QString& text, Qt::MatchFlags flags = Qt::MatchExactly | Qt::MatchCaseSensitive ) const;
+  int findData(const QVariant & data, int role = Qt::UserRole, Qt::MatchFlags flags = Qt::MatchExactly | Qt::MatchCaseSensitive ) const;
+
+  /// 
+  QString   itemText(int index) const;
+  QVariant  itemData(int index, int role = Qt::UserRole) const;
+
+  void setItemText(int index, const QString& text);
+  void setItemData(int index, const QVariant& data, int role = Qt::UserRole);
+
+  /// 
+  /// Return the current item
+  int       currentIndex() const;
+  inline QString  currentText() const
+    {return this->itemText(this->currentIndex());}
+  inline QVariant currentData(int role = Qt::UserRole) const
+    {return this->itemData(this->currentIndex(), role);}
+
+  /// 
+  /// Remove the item currently selected. See signal 'itemRemoved'
+  void removeItem(int index);
+  inline void removeCurrentItem()
+    {this->removeItem(this->currentIndex());}
+
+  /// 
+  /// Remove all the items
+  void clear();
+
+signals:
+  void currentIndexChanged(int index);
+  void activated(int index);
+
+  /// 
+  /// This signal is sent after the method 'addItem' has been called programmatically
+  void itemAdded(int index);
+  
+  /// 
+  void itemAboutToBeRemoved(int index);
+  void itemRemoved(int index);
+    
+public slots:
+  /// 
+  /// Select the current index
+  void setCurrentIndex(int index);
+
+protected slots:
+  /// 
+  virtual void onAdd();
+  virtual void onRemove();
+  virtual void onEdit();
+
+protected:
+  void setComboBox(QComboBox* comboBox);
+  QModelIndex rootModelIndex()const;
+  void setRootModelIndex(const QModelIndex& root);
+  int modelColumn()const;
+  QAbstractItemModel* model()const;
+
+private slots:
+  //void onRowsAboutToBeInserted(const QModelIndex & parent, int start, int end );
+  void onRowsAboutToBeRemoved(const QModelIndex & parent, int start, int end);
+  void onRowsInserted(const QModelIndex & parent, int start, int end);
+  void onRowsRemoved(const QModelIndex & parent, int start, int end);
+
+private:
+  CTK_DECLARE_PRIVATE(ctkAddRemoveComboBox);
+};
+
+#endif

+ 251 - 0
Libs/Widgets/ctkTestApplication.cpp

@@ -0,0 +1,251 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc. 
+  All rights reserved.
+  Distributed under a BSD License. See LICENSE.txt file.
+
+  This software is distributed "AS IS" WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the above copyright notice for more information.
+
+=========================================================================*/
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    $RCSfile: ctkTestApplication.cxx,v $
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+/*-------------------------------------------------------------------------
+  Copyright 2008 Sandia Corporation.
+  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+  the U.S. Government retains certain rights in this software.
+-------------------------------------------------------------------------*/
+
+// Qt includes
+#include <QTimer>
+#include <QWidget>
+#include <QKeyEvent>
+#include <QMouseEvent>
+
+// CTK includes
+#include "ctkTestApplication.h"
+
+// STD includes
+#include <iostream>
+
+int ctkTestApplication::Error = 0;
+
+//-----------------------------------------------------------------------------
+ctkTestApplication::ctkTestApplication(int _argc, char** _argv)
+{
+  qInstallMsgHandler(ctkTestApplication::messageHandler);
+  
+  // CMake generated driver removes argv[0], 
+  // so let's put a dummy back in
+  this->Argv.append("ctkTestApplication");
+  for(int i=0; i<_argc; i++)
+    {
+    this->Argv.append(_argv[i]);
+    }
+  for(int j=0; j<this->Argv.size(); j++)
+    {
+    this->Argvp.append(this->Argv[j].data());
+    }
+  this->Argc = this->Argvp.size();
+  this->App = new QApplication(this->Argc, this->Argvp.data());
+}
+
+//-----------------------------------------------------------------------------
+ctkTestApplication::~ctkTestApplication()
+{
+  delete this->App;
+  qInstallMsgHandler(0);
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::runTestSlot()
+{
+  this->runTest();
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::runTest()
+{
+}
+
+//-----------------------------------------------------------------------------
+int ctkTestApplication::exec(bool reportErrorsOnExit)
+{
+  if(QCoreApplication::arguments().contains("--exit"))
+    {
+    QTimer::singleShot(100, QApplication::instance(), 
+                       SLOT(quit()));
+    }
+    
+  int ret = QApplication::exec();
+  if (reportErrorsOnExit)
+    {
+    return Error + ret;
+    }
+  else
+    {
+    return ret;
+    }
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::messageHandler(QtMsgType type, const char *msg)
+{
+  switch(type)
+  {
+  case QtDebugMsg:
+    std::cerr << "Debug: " << msg << std::endl;
+    break;
+  case QtWarningMsg:
+    std::cerr << "Warning: " << msg << std::endl;
+    Error++;
+    break;
+  case QtCriticalMsg:
+    std::cerr << "Critical: " << msg << std::endl;
+    Error++;
+    break;
+  case QtFatalMsg:
+    std::cerr << "Fatal: " << msg << std::endl;
+    abort();
+  }
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::delay(int ms)
+{
+  if(ms > 0)
+  {
+    QTimer::singleShot(ms, QApplication::instance(), SLOT(quit()));
+    QApplication::exec();
+  }
+}
+
+//-----------------------------------------------------------------------------
+bool ctkTestApplication::simulateEvent(QWidget* w, QEvent* e)
+{
+  bool status = QApplication::sendEvent(w, e);
+  QApplication::processEvents();
+  return status;
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::keyUp(QWidget* w, Qt::Key key, Qt::KeyboardModifiers mod, int ms)
+{
+  if(!w)
+    return;
+  delay(ms);
+  QString text;
+  char off = 'a';
+  if(mod & Qt::ShiftModifier)
+    off = 'A';
+  if(key >= Qt::Key_A && key <= Qt::Key_Z)
+    {
+    text.append(QChar::fromAscii(key - Qt::Key_A + off));
+    }
+  QKeyEvent e(QEvent::KeyRelease, key, mod, text);
+  if(!simulateEvent(w, &e))
+    {
+    qWarning("keyUp not handled\n");
+    }
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::keyDown(QWidget* w, Qt::Key key, Qt::KeyboardModifiers mod, int ms)
+{
+  if(!w)
+    return;
+  delay(ms);
+  QString text;
+  char off = 'a';
+  if(mod & Qt::ShiftModifier)
+    off = 'A';
+  if(key >= Qt::Key_A && key <= Qt::Key_Z)
+    {
+    text.append(QChar::fromAscii(key - Qt::Key_A + off));
+    }
+  QKeyEvent e(QEvent::KeyPress, key, mod, text);
+  if(!simulateEvent(w, &e))
+    {
+    qWarning("keyDown not handled\n");
+    }
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::keyClick(QWidget* w, Qt::Key key, Qt::KeyboardModifiers mod, int ms)
+{
+  delay(ms);
+  keyDown(w, key, mod, 0);
+  keyUp(w, key, mod, 0);
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::mouseDown(QWidget* w, QPoint pos, Qt::MouseButton btn,
+                        Qt::KeyboardModifiers mod, int ms)
+{
+  delay(ms);
+  QMouseEvent e(QEvent::MouseButtonPress, pos, btn, btn, mod);
+  if(!simulateEvent(w, &e))
+    {
+    qWarning("mouseDown not handled\n");
+    }
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::mouseUp(QWidget* w, QPoint pos, Qt::MouseButton btn,
+                      Qt::KeyboardModifiers mod, int ms)
+{
+  delay(ms);
+  QMouseEvent e(QEvent::MouseButtonRelease, pos, btn, btn, mod);
+  if(!simulateEvent(w, &e))
+    {
+    qWarning("mouseUp not handled\n");
+    }
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::mouseMove(QWidget* w, QPoint pos, Qt::MouseButton btn,
+                        Qt::KeyboardModifiers mod, int ms)
+{
+  delay(ms);
+  QMouseEvent e(QEvent::MouseMove, pos, btn, btn, mod);
+  if(!simulateEvent(w, &e))
+    {
+    qWarning("mouseMove not handled\n");
+    }
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::mouseClick(QWidget* w, QPoint pos, Qt::MouseButton btn,
+                         Qt::KeyboardModifiers mod, int ms)
+{
+  delay(ms);
+  mouseDown(w, pos, btn, mod, 0);
+  mouseUp(w, pos, btn, mod, 0);
+}
+
+//-----------------------------------------------------------------------------
+void ctkTestApplication::mouseDClick(QWidget* w, QPoint pos, Qt::MouseButton btn,
+                         Qt::KeyboardModifiers mod, int ms)
+{
+  delay(ms);
+  QMouseEvent e(QEvent::MouseButtonDblClick, pos, btn, btn, mod);
+  if(!simulateEvent(w, &e))
+    {
+    qWarning("mouseMove not handled\n");
+    }
+}

+ 135 - 0
Libs/Widgets/ctkTestApplication.h

@@ -0,0 +1,135 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc. 
+  All rights reserved.
+  Distributed under a BSD License. See LICENSE.txt file.
+
+  This software is distributed "AS IS" WITHOUT ANY WARRANTY; without even
+  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the above copyright notice for more information.
+
+=========================================================================*/
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    $RCSfile: QTestApp.h,v $
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+/*-------------------------------------------------------------------------
+  Copyright 2008 Sandia Corporation.
+  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
+  the U.S. Government retains certain rights in this software.
+-------------------------------------------------------------------------*/
+
+#ifndef __ctkTestApplication_h
+#define __ctkTestApplication_h
+
+// Qt includes
+#include <QApplication>
+#include <QVector>
+#include <QByteArray>
+#include <QTimer>
+
+/// Helper macro allowing to declare a test
+#define QCTK_DECLARE_TEST(TEST_NAME)                \
+namespace                                           \
+{                                                   \
+class _TEST_NAME : public ctkTestApplication       \
+{                                                   \
+public:                                             \
+  _TEST_NAME(int _argc, char * _argv []):           \
+    ctkTestApplication(_argc, _argv){}             \
+  virtual void runTest();                           \
+};                                                  \
+                                                    \
+void _TEST_NAME::runTest()                          \
+
+/// Helper macro allowing to define a test
+#define QCTK_RUN_TEST(TEST_NAME)                      \
+}                                                     \
+                                                      \
+int TEST_NAME(int _argc, char * _argv [] )            \
+{                                                     \
+  _TEST_NAME app(_argc, _argv);                       \
+  QTimer::singleShot(0, &app, SLOT(runTestSlot()));   \
+  return _TEST_NAME::exec();                          \
+}
+
+/// Helper macro allowing to exit the event loop specifying a return code
+#define QCTK_EXIT_TEST(_status)    \
+  QCoreApplication::exit(_status); \
+  return;
+  
+#include "CTKWidgetsExport.h"
+  
+
+class CTK_WIDGETS_EXPORT ctkTestApplication : public QObject
+{
+  Q_OBJECT
+  
+public:
+  ctkTestApplication(int _argc, char** _argv);
+  ~ctkTestApplication();
+
+  /// This function could be overloaded to implement test that required
+  /// an active event loop
+  virtual void runTest();
+  
+  /// 
+  /// If reportErrorsOnExit is true, then the return value will
+  /// be the number of warning messages plus the number of error messages
+  /// produced by QDebug during execution.
+  static int exec(bool reportErrorsOnExit=false);
+
+  static void messageHandler(QtMsgType type, const char *msg);
+
+  static void delay(int ms);
+
+  static bool simulateEvent(QWidget* w, QEvent* e);
+
+  static void keyUp(QWidget* w, Qt::Key key, Qt::KeyboardModifiers mod, int ms);
+
+  static void keyDown(QWidget* w, Qt::Key key, Qt::KeyboardModifiers mod, int ms);
+
+  static void keyClick(QWidget* w, Qt::Key key, Qt::KeyboardModifiers mod, int ms);
+
+  static void mouseDown(QWidget* w, QPoint pos, Qt::MouseButton btn, 
+                        Qt::KeyboardModifiers mod, int ms);
+  
+  static void mouseUp(QWidget* w, QPoint pos, Qt::MouseButton btn, 
+                      Qt::KeyboardModifiers mod, int ms);
+  
+  static void mouseMove(QWidget* w, QPoint pos, Qt::MouseButton btn, 
+                        Qt::KeyboardModifiers mod, int ms);
+
+  static void mouseClick(QWidget* w, QPoint pos, Qt::MouseButton btn, 
+                         Qt::KeyboardModifiers mod, int ms);
+
+  static void mouseDClick(QWidget* w, QPoint pos, Qt::MouseButton btn, 
+                          Qt::KeyboardModifiers mod, int ms);
+
+public slots:
+
+  /// Slot responsible to invoke the virtual function 'runTest'.
+  /// The typical use case consists in calling that slot using a singleShot QTimer
+  void runTestSlot(); 
+
+private:
+  QApplication*     App;
+  static int        Error;
+  QList<QByteArray> Argv;
+  QVector<char*>    Argvp;
+  int               Argc;
+};
+
+#endif