Browse Source

Added additional "DisplayRole" enum and a role argument to setValue().

Sascha Zelzer 12 years ago
parent
commit
32066e17ce

+ 8 - 4
Libs/CommandLineModules/Core/CMakeLists.txt

@@ -53,14 +53,18 @@ set(KIT_SRCS
 set(KIT_MOC_SRCS
   ctkCmdLineModuleDirectoryWatcher.h
   ctkCmdLineModuleDirectoryWatcher_p.h
-  ctkCmdLineModuleFrontend.h
   ctkCmdLineModuleFutureWatcher.h
   ctkCmdLineModuleManager.h
 )
 
-qt4_wrap_cpp(_dummy ctkCmdLineModuleXmlProgressWatcher.h)
-set_source_files_properties(ctkCmdLineModuleXmlProgressWatcher.cpp
-  PROPERTIES OBJECT_DEPENDS ${_dummy})
+QT4_GENERATE_MOCS(
+  ctkCmdLineModuleFrontend.h
+  ctkCmdLineModuleXmlProgressWatcher.h
+)
+
+#list(APPEND KIT_SRCS
+#  ${CMAKE_CURRENT_BINARY_DIR}/moc_ctkCmdLineModuleXmlProgressWatcher.h
+#)
 
 # UI files
 set(KIT_UI_FORMS

+ 35 - 6
Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h

@@ -45,6 +45,7 @@ struct ctkCmdLineModuleFrontendPrivate;
 class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject
 {
   Q_OBJECT
+  Q_ENUMS(ParamterValueRole)
 
 public:
 
@@ -55,15 +56,28 @@ public:
      * QVariant by default. For complex parameter types (like file, image,
      * geometry, etc.) the data must be convertible to a QString pointing
      * to a local resource.
+     *
+     * This role is usually used by backends for retrieving data and is mainly
+     * important for data which acts as a handle to the real data (e.g. a
+     * backend usually needs to get the absolute path to a local file for the
+     * current value of an input image parameter, instead of the image label
+     * displayed in a GUI).
      */
     LocalResourceRole = 0,
 
     /**
+     * Describes data suitable for displaying in a GUI. For many parameter types
+     * (e.g. scalar and vector parameters) data returned by this role will be
+     * the same as returned by the LocalResourceRole role.
+     **/
+    DisplayRole = 1,
+
+    /**
      * This role can be used in custom frontends to return a QVariant
      * containing for example an in-memory representation of a complex object.
      * One can then either convert the in-memory representation to a local
      * resource before running a module such that arbitrary backends relying on
-     * the LocalResourceRole can process the data. Or one creates a custom
+     * the LocalResourceRole role can process the data. Or one creates a custom
      * backend which knows how to handle QVariants returned by this role.
      */
     UserRole = 8
@@ -89,18 +103,24 @@ public:
   /**
    * @brief GUIs will need to be able to read parameters,
    * here we retrieve by role.
+   *
    * @return QVariant
    * @see ParameterValueRole
    */
   virtual QVariant value(const QString& parameter,
-      int role = LocalResourceRole) const = 0;
+                         int role = LocalResourceRole) const = 0;
 
   /**
-   * @brief Set the value of a certain parameters
+   * @brief Set the value of a certain parameter.
+   *
    * @param parameter The name of the parameter, as defined in the XML.
    * @param value The value for that parameter.
+   * @param role The role for which to set the data.
+   *
+   * @see ParameterValueRole
    */
-  virtual void setValue(const QString& parameter, const QVariant& value) = 0;
+  virtual void setValue(const QString& parameter, const QVariant& value,
+                        int role = DisplayRole) = 0;
 
   /**
    * @brief Return the ctkCmdLineModuleFuture, derived from QFuture to
@@ -159,8 +179,6 @@ public:
    */
   bool isPaused() const;
 
-  Q_SIGNAL void valueChanged(const QString& parameter, const QVariant& value);
-
   // convenience methods
 
   /**
@@ -180,6 +198,17 @@ public:
 Q_SIGNALS:
 
   /**
+   * @brief This signal is emitted whenever a parameter value is changed by using
+   *        the ctkCmdLineModuleFrontent class.
+   * @param parameter The parameter name.
+   * @param value The new parameter value.
+   *
+   * Please note that this signal is not emitted if a parameter value is
+   * changed in the generated GUI.
+   */
+  void valueChanged(const QString& parameter, const QVariant& value);
+
+  /**
    * @brief This signal is emitted when the frontend is run.
    *
    * You can use this signal to get the ctkCmdLineModuleFuture instance

+ 7 - 2
Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/CMakeLists.txt

@@ -2,6 +2,7 @@ set(KIT ${PROJECT_NAME})
 set(LIBRARY_NAME ${PROJECT_NAME})
 
 create_test_sourcelist(Tests ${KIT}CppTests.cpp
+  ctkCmdLineModuleFrontendQtGuiTest.cpp
   ctkCmdLineModuleQtXslTransformTest.cpp
   )
 
@@ -9,10 +10,13 @@ set(TestsToRun ${Tests})
 remove(TestsToRun ${KIT}CppTests.cpp)
 
 set(Tests_SRCS ${Tests_SRCS}
-
 )
+
 set(Tests_MOC_SRCS ${Tests_MOC_SRCS}
+)
 
+set(Tests_RESOURCES
+  ctkCmdLineModuleFrontendQtGuiTestResources.qrc
 )
 
 include_directories(
@@ -23,6 +27,7 @@ include_directories(
 set(Tests_MOC_CPP)
 QT4_WRAP_CPP(Tests_MOC_CPP ${Tests_MOC_SRCS})
 QT4_GENERATE_MOCS(
+  ctkCmdLineModuleFrontendQtGuiTest.cpp
   ctkCmdLineModuleQtXslTransformTest.cpp
   )
 set(Tests_UI_CPP)
@@ -40,4 +45,4 @@ target_link_libraries(${KIT}CppTests ${LIBRARY_NAME} ${CTK_BASE_LIBRARIES})
 #
 
 SIMPLE_TEST(ctkCmdLineModuleQtXslTransformTest)
-
+SIMPLE_TEST(ctkCmdLineModuleFrontendQtGuiTest)

+ 234 - 0
Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTest.cpp

@@ -0,0 +1,234 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 <QSpinBox>
+#include <QComboBox>
+
+// CTK includes
+#include "ctkCmdLineModuleManager.h"
+#include "ctkCmdLineModuleBackend.h"
+#include "ctkCmdLineModuleFrontendQtGui.h"
+#include "ctkCmdLineModuleFuture.h"
+#include "ctkCmdLineModuleDescription.h"
+#include "ctkCmdLineModuleParameter.h"
+
+#include "ctkTest.h"
+
+namespace {
+
+class BackendMockUp : public ctkCmdLineModuleBackend
+{
+
+public:
+
+  void addModule(const QUrl& location, const QByteArray& xml)
+  {
+    this->UrlToXml[location] = xml;
+  }
+
+  virtual QString name() const { return "Mockup"; }
+  virtual QString description() const { return "Test Mock-up"; }
+  virtual QList<QString> schemes() const { return QList<QString>() << "test"; }
+  virtual qint64 timeStamp(const QUrl& /*location*/) const { return 0; }
+  virtual QByteArray rawXmlDescription(const QUrl& location)
+  {
+    return UrlToXml[location];
+  }
+
+protected:
+
+  virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend* /*frontend*/)
+  {
+    return ctkCmdLineModuleFuture();
+  }
+
+private:
+
+  QHash<QUrl, QByteArray> UrlToXml;
+};
+
+}
+
+// ----------------------------------------------------------------------------
+class ctkCmdLineModuleFrontendQtGuiTester: public QObject
+{
+  Q_OBJECT
+
+private:
+
+  QScopedPointer<ctkCmdLineModuleBackend> Backend;
+  ctkCmdLineModuleManager Manager;
+
+  ctkCmdLineModuleReference ModuleRef;
+
+  QString ChangedParameter;
+  QVariant ChangedParameterValue;
+
+private Q_SLOTS:
+
+  void valueChanged(const QString& parameter, const QVariant& value);
+
+private Q_SLOTS:
+
+  void initTestCase();
+
+  void init();
+
+  void testValueSetterAndGetter();
+  void testValueSetterAndGetter_data();
+
+};
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleFrontendQtGuiTester::valueChanged(const QString &parameter, const QVariant &value)
+{
+  this->ChangedParameter = parameter;
+  this->ChangedParameterValue = value;
+}
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleFrontendQtGuiTester::initTestCase()
+{
+  BackendMockUp* backend = new BackendMockUp;
+  this->Backend.reset(backend);
+
+  QFile xmlFile(":/ctkCmdLineModuleFrontendQtGuiTestModule1.xml");
+  QVERIFY(xmlFile.open(QIODevice::ReadOnly));
+
+  backend->addModule(QUrl("test://module1"), xmlFile.readAll());
+
+  this->Manager.registerBackend(backend);
+
+  this->ModuleRef = this->Manager.registerModule(QUrl("test://module1"));
+  QVERIFY(this->ModuleRef);
+}
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleFrontendQtGuiTester::init()
+{
+  this->ChangedParameter.clear();
+  this->ChangedParameterValue.clear();
+}
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleFrontendQtGuiTester::testValueSetterAndGetter()
+{
+
+  QScopedPointer<ctkCmdLineModuleFrontend> frontend(new ctkCmdLineModuleFrontendQtGui(this->ModuleRef));
+  // force the creation of the frontend gui
+  frontend->guiHandle();
+
+  connect(frontend.data(), SIGNAL(valueChanged(QString,QVariant)), SLOT(valueChanged(QString,QVariant)));
+
+  QFETCH(QString, parameter);
+  QFETCH(QVariant, currentValue);
+  QFETCH(QVariant, newValue);
+  QFETCH(QVariant, expectedValue);
+  QFETCH(int, role);
+
+  if (role == -1)
+  {
+    // test with default role argument
+    QCOMPARE(frontend->value(parameter), currentValue);
+  }
+  else
+  {
+    QCOMPARE(frontend->value(parameter, role), currentValue);
+  }
+
+  // test setting values
+  if (newValue.isValid())
+  {
+    frontend->setValue(parameter, newValue);
+    if (role == -1)
+    {
+      QCOMPARE(frontend->value(parameter), expectedValue);
+    }
+    else
+    {
+      QCOMPARE(frontend->value(parameter, role), expectedValue);
+      if (role == ctkCmdLineModuleFrontend::DisplayRole)
+      {
+        QWidget* widget = frontend->guiHandle()->findChild<QWidget*>("parameter:" + parameter);
+        QVERIFY(widget != NULL);
+        QString tag = this->ModuleRef.description().parameter(parameter).tag();
+        if (tag == "integer")
+        {
+          QSpinBox* spinBox = qobject_cast<QSpinBox*>(widget);
+          QVERIFY(spinBox);
+          QCOMPARE(spinBox->value(), expectedValue.toInt());
+        }
+        else if (tag.endsWith("enumeration"))
+        {
+          QComboBox* comboBox = qobject_cast<QComboBox*>(widget);
+          QVERIFY(comboBox);
+          QCOMPARE(comboBox->currentText(), expectedValue.toString());
+        }
+        else
+        {
+          QFAIL("Missing widget sub-class test code.");
+        }
+      }
+    }
+
+    QCOMPARE(this->ChangedParameter, parameter);
+    QCOMPARE(this->ChangedParameterValue, expectedValue);
+  }
+
+}
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleFrontendQtGuiTester::testValueSetterAndGetter_data()
+{
+  QTest::addColumn<QString>("parameter");
+  QTest::addColumn<QVariant>("currentValue");
+  QTest::addColumn<QVariant>("newValue");
+  QTest::addColumn<QVariant>("expectedValue");
+  QTest::addColumn<int>("role");
+
+  QTest::newRow("intParamDefaultDefaultRole") << "intParam" << QVariant(1) << QVariant(2) << QVariant(2) << -1;
+  QTest::newRow("intParamDefaultDisplayRole") << "intParam" << QVariant(1) << QVariant(2) << QVariant(2) << static_cast<int>(ctkCmdLineModuleFrontend::DisplayRole);
+  QTest::newRow("intParmaDefaultLRRole") << "intParam" << QVariant(1) << QVariant(2) << QVariant(2) << static_cast<int>(ctkCmdLineModuleFrontend::LocalResourceRole);
+
+  // newValue too low
+  QTest::newRow("intParamTooLowDefaultRole") << "intParam" << QVariant(1) << QVariant(-6) << QVariant(-5) << -1;
+  QTest::newRow("intParamTooLowDisplayRole") << "intParam" << QVariant(1) << QVariant(-6) << QVariant(-5) << static_cast<int>(ctkCmdLineModuleFrontend::DisplayRole);
+  QTest::newRow("intParmaTooLowLRRole") << "intParam" << QVariant(1) << QVariant(-6) << QVariant(-5) << static_cast<int>(ctkCmdLineModuleFrontend::LocalResourceRole);
+
+  // newValue too high
+  QTest::newRow("intParamTooHighDefaultRole") << "intParam" << QVariant(1) << QVariant(200) << QVariant(60) << -1;
+  QTest::newRow("intParamTooHighDisplayRole") << "intParam" << QVariant(1) << QVariant(200) << QVariant(60) << static_cast<int>(ctkCmdLineModuleFrontend::DisplayRole);
+  QTest::newRow("intParmaTooHighLRRole") << "intParam" << QVariant(1) << QVariant(200) << QVariant(60) << static_cast<int>(ctkCmdLineModuleFrontend::LocalResourceRole);
+
+  QTest::newRow("stringEnumDefaultRole") << "stringEnumParam" << QVariant("yes") << QVariant("no") << QVariant("no") << -1;
+  QTest::newRow("stringEnumDisplayRole") << "stringEnumParam" << QVariant("yes") << QVariant("no") << QVariant("no") << static_cast<int>(ctkCmdLineModuleFrontend::DisplayRole);
+  QTest::newRow("stringEnumLRRole") << "stringEnumParam" << QVariant("yes") << QVariant("no") << QVariant("no") << static_cast<int>(ctkCmdLineModuleFrontend::LocalResourceRole);
+
+  QTest::newRow("intOutputParamDefaultRole") << "intOutputParam" << QVariant(0) << QVariant(3) << QVariant(3) << -1;
+  QTest::newRow("intOutputParamDisplayRole") << "intOutputParam" << QVariant(0) << QVariant(3) << QVariant(3) << static_cast<int>(ctkCmdLineModuleFrontend::DisplayRole);
+  QTest::newRow("intOutputParamLRRole") << "intOutputParam" << QVariant(0) << QVariant(3) << QVariant(3) << static_cast<int>(ctkCmdLineModuleFrontend::LocalResourceRole);
+}
+
+
+// ----------------------------------------------------------------------------
+CTK_TEST_MAIN(ctkCmdLineModuleFrontendQtGuiTest)
+#include "moc_ctkCmdLineModuleFrontendQtGuiTest.cpp"

+ 36 - 0
Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTestModule1.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<executable>
+  <title>Test Module</title>
+  <description>Test Module.</description>
+  <parameters>
+    <label>Test parameters</label>
+    <description>Test parameters.</description>
+    <integer>
+      <name>intParam</name>
+      <flag>i</flag>
+      <description>Integer</description>
+      <label>Integer</label>
+      <default>1</default>
+      <constraints>
+        <minimum>-5</minimum>
+        <maximum>60</maximum>
+        <step>1</step>
+      </constraints>
+    </integer>
+    <string-enumeration>
+      <name>stringEnumParam</name>
+      <index>0</index>
+      <description>Enumeration parameter</description>
+      <label>Enumeration</label>
+      <element>yes</element>
+      <element>no</element>
+    </string-enumeration>
+    <integer>
+      <name>intOutputParam</name>
+      <index>1000</index>
+      <description>Integer</description>
+      <label>Integer</label>
+      <channel>output</channel>
+    </integer>
+  </parameters>
+</executable>

+ 5 - 0
Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTestResources.qrc

@@ -0,0 +1,5 @@
+<RCC>
+    <qresource prefix="/">
+        <file>ctkCmdLineModuleFrontendQtGuiTestModule1.xml</file>
+    </qresource>
+</RCC>

+ 30 - 9
Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp

@@ -105,6 +105,22 @@ QVariant ctkCmdLineModuleFrontendQtGui::customValue(const QString& parameter, co
   return QVariant();
 }
 
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleFrontendQtGui::setCustomValue(const QString& parameter, const QVariant &value,
+                                                   const QString& propertyName)
+{
+  if (!d->Widget) return;
+
+  ctkCmdLineModuleObjectTreeWalker walker(d->Widget);
+  while(walker.readNextParameter())
+  {
+    if(walker.name() == parameter && walker.value(propertyName) != value)
+    {
+      walker.setValue(value, propertyName);
+      break;
+    }
+  }
+}
 
 //-----------------------------------------------------------------------------
 QObject* ctkCmdLineModuleFrontendQtGui::guiHandle() const
@@ -146,23 +162,28 @@ QVariant ctkCmdLineModuleFrontendQtGui::value(const QString &parameter, int role
 {
   Q_UNUSED(role)
 
+  // This will always return data using the default property for parameter values,
+  // which holds the data for the DisplayRole.
   return customValue(parameter);
 }
 
 
 //-----------------------------------------------------------------------------
-void ctkCmdLineModuleFrontendQtGui::setValue(const QString &parameter, const QVariant &value)
+void ctkCmdLineModuleFrontendQtGui::setValue(const QString &parameter, const QVariant &value, int role)
 {
-  if (!d->Widget) return;
+  if (role != DisplayRole) return;
 
-  ctkCmdLineModuleObjectTreeWalker walker(d->Widget);
-  while(walker.readNextParameter())
+  QVariant oldValue = this->customValue(parameter);
+
+  // This sets the value of the default QObject property for the DisplayRole.
+  this->setCustomValue(parameter, value);
+
+  // Before emitting the signal, get the actual value because it might be different
+  // (Widgets with constraints on the value domain might adapt the value).
+  QVariant currentValue = this->customValue(parameter);
+  if (currentValue != oldValue)
   {
-    if(walker.name() == parameter && walker.value() != value)
-    {
-      walker.setValue(value);
-      emit valueChanged(parameter, value);
-    }
+    emit valueChanged(parameter, currentValue);
   }
 }
 

+ 27 - 1
Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h

@@ -51,8 +51,33 @@ public:
 
   virtual QObject* guiHandle() const;
 
+  /**
+   * @brief Retrieves the current parameter value using the default QObject property for
+   *        parameter values.
+   * @param parameter
+   * @param role
+   *
+   * This implementation ignores the <code>role</code> argument and always returns
+   * the value held by the default property, which usually correspongs to the
+   * DisplayRole.
+   *
+   * @see ctkCmdLineModuleFrontend::value()
+   */
   virtual QVariant value(const QString& parameter, int role = LocalResourceRole) const;
-  virtual void setValue(const QString& parameter, const QVariant& value);
+
+  /**
+   * @brief Sets the parameter value.
+   * @param parameter
+   * @param value
+   * @param role
+   *
+   * This implementation does nothing if the <code>role</code> parameter does not equal
+   * ctkCmdLineModuleFrontend::DisplayRole. If it does, it sets the value of the default
+   * QObject property to the provided value.
+   *
+   * @see ctkCmdLiineModuleFrontend::setValue()
+   */
+  virtual void setValue(const QString& parameter, const QVariant& value, int role = DisplayRole);
 
   virtual QList<QString> parameterNames() const;
 
@@ -62,6 +87,7 @@ protected:
   virtual ctkCmdLineModuleXslTransform* xslTransform() const;
 
   QVariant customValue(const QString& parameter, const QString& propertyName = QString()) const;
+  void setCustomValue(const QString& parameter, const QVariant& value, const QString& propertyName = QString()) ;
 
 private:
 

+ 9 - 4
Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp

@@ -116,12 +116,17 @@ QVariant ctkCmdLineModuleObjectTreeWalker::value(const QString &propertyName) co
 }
 
 //----------------------------------------------------------------------------
-void ctkCmdLineModuleObjectTreeWalker::setValue(const QVariant& value)
+void ctkCmdLineModuleObjectTreeWalker::setValue(const QVariant& value, const QString &propertyName)
 {
-  QVariant valProp = property("valueProperty");
-  if (valProp.isValid())
+  QString valProp = propertyName;
+  if (valProp.isEmpty())
+  {
+    valProp = property("valueProperty").toString();
+  }
+
+  if (!valProp.isEmpty())
   {
-    CurrentObject->setProperty(qPrintable(valProp.toString()), value);
+    CurrentObject->setProperty(qPrintable(valProp), value);
   }
 }
 

+ 1 - 1
Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h

@@ -60,7 +60,7 @@ public:
   QString label() const;
   QVariant value(const QString& propertyName = QString()) const;
 
-  void setValue(const QVariant& value);
+  void setValue(const QVariant& value, const QString& propertyName = QString());
 
   QString flag() const;
   QString longFlag() const;

+ 2 - 2
Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp

@@ -80,9 +80,9 @@ QVariant ctkCmdLineModuleFrontendQtWebKit::value(const QString &parameter, int r
 }
 
 //----------------------------------------------------------------------------
-void ctkCmdLineModuleFrontendQtWebKit::setValue(const QString &parameter, const QVariant &value)
+void ctkCmdLineModuleFrontendQtWebKit::setValue(const QString &parameter, const QVariant &value, int role)
 {
-  if (!this->WebView) return;
+  if (!this->WebView || role != DisplayRole) return;
 
   QWebElement webElement = this->WebView->page()->currentFrame()->findFirstElement("input[name=" + parameter + "]");
   if (webElement.isNull()) return;

+ 1 - 1
Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h

@@ -43,7 +43,7 @@ public:
   virtual QObject* guiHandle() const;
 
   virtual QVariant value(const QString& parameter, int role = LocalResourceRole) const;
-  virtual void setValue(const QString& parameter, const QVariant& value);
+  virtual void setValue(const QString& parameter, const QVariant& value, int role = DisplayRole);
 
   //virtual QList<QString> parameterNames() const;
 

+ 2 - 1
Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp

@@ -64,8 +64,9 @@ public:
         return value;
       }
 
-      virtual void setValue(const QString& parameter, const QVariant& value)
+      virtual void setValue(const QString& parameter, const QVariant& value, int role = DisplayRole)
       {
+        Q_UNUSED(role)
         currentValues[parameter] = value;
       }
 

+ 45 - 6
Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp

@@ -44,6 +44,7 @@ struct MyImageData : public ctk::CmdLineModuleBackendFunctionPointer::ImageType
     : Path(path)
   {}
 
+  QString Label;
   QString Path;
 };
 
@@ -69,7 +70,8 @@ class MyImageComboBox : public QComboBox
 
 public:
 
-  Q_PROPERTY(QString currentValue READ currentValue WRITE setCurrentValue)
+  Q_PROPERTY(QString currentLabel READ currentLabel WRITE setCurrentLabel)
+  Q_PROPERTY(QString currentPath READ currentPath WRITE setCurrentPath)
   Q_PROPERTY(const MyImageData* currentImage READ currentImage)
 
   MyImageComboBox(QWidget* parent = 0)
@@ -84,12 +86,29 @@ public:
     this->addItem("Image 3");
   }
 
-  QString currentValue() const
+  QString currentLabel() const
+  {
+    return this->imageData.at(this->currentIndex()).Label;
+  }
+
+  void setCurrentLabel(const QString& label)
+  {
+    for(int i = 0; i < imageData.size(); ++i)
+    {
+      if (imageData[i].Label == label)
+      {
+        this->setCurrentIndex(i);
+        break;
+      }
+    }
+  }
+
+  QString currentPath() const
   {
     return this->imageData.at(this->currentIndex()).Path;
   }
 
-  void setCurrentValue(const QString& path)
+  void setCurrentPath(const QString& path)
   {
     this->imageData[this->currentIndex()].Path = path;
   }
@@ -143,6 +162,7 @@ public:
     if (!initialized)
     {
       transform->bindVariable("imageInputWidget", "MyImageComboBox");
+      transform->bindVariable("imageValueProperty", "currentLabel");
       static QFile extraXsl(":/MyImageComboBoxTest.xsl");
       transform->setXslExtraTransformation(&extraXsl);
       initialized = true;
@@ -150,7 +170,7 @@ public:
     return transform;
   }
 
-  QVariant value(const QString &parameter, int role) const
+  QVariant value(const QString &parameter, int role = LocalResourceRole) const
   {
     if (role == UserRole)
     {
@@ -161,7 +181,26 @@ public:
       }
       return QVariant();
     }
-    return ctkCmdLineModuleFrontendQtGui::value(parameter, role);
+    else if (role == LocalResourceRole)
+    {
+      return this->customValue(parameter, "currentPath");
+    }
+    else
+    {
+      return ctkCmdLineModuleFrontendQtGui::value(parameter, role);
+    }
+  }
+
+  void setValue(const QString &parameter, const QVariant &value, int role = DisplayRole)
+  {
+    if (role == LocalResourceRole)
+    {
+      this->setCustomValue(parameter, value, "currentPath");
+    }
+    else
+    {
+      ctkCmdLineModuleFrontendQtGui::setValue(parameter, value, role);
+    }
   }
 };
 
@@ -235,7 +274,7 @@ void ctkCmdLineModuleQtCustomizationTester::testCustomization()
 
   // now set the property for the "LocalResourceRole" (the default property) to something else
   expectedImageValue = "/tmp/path/to/image2";
-  fpFrontend->setValue("param0", expectedImageValue);
+  fpFrontend->setValue("param0", expectedImageValue, ctkCmdLineModuleFrontend::LocalResourceRole);
   QCOMPARE(fpFrontend->value("param0").toString(), expectedImageValue);
 
   QVERIFY(CustomImageDataPath.isEmpty());