Преглед изворни кода

Added test for verifying customizability of the Qt Gui frontend.

Sascha Zelzer пре 13 година
родитељ
комит
54428f500f

+ 46 - 9
Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt

@@ -1,9 +1,24 @@
 set(KIT CTKCommandLineModules)
 set(LIBRARY_NAME ${KIT})
 
-create_test_sourcelist(Tests ${KIT}CppTests.cpp
-  ctkCmdLineModuleFutureTest.cpp
-  )
+set(_test_srcs)
+
+if(CTK_LIB_CommandLineModules/Frontend/QtGui)
+  set(QT_USE_QTUITOOLS 1)
+  include(${QT_USE_FILE})
+
+  if(CTK_LIB_CommandLineModules/Backend/LocalProcess)
+    list(APPEND _test_srcs ctkCmdLineModuleFutureTest.cpp)
+  endif()
+  if(CTK_LIB_CommandLineModules/Backend/FunctionPointer)
+    list(APPEND _test_srcs ctkCmdLineModuleQtCustomizationTest.cpp)
+    QT4_GENERATE_MOCS(
+      ctkCmdLineModuleQtCustomizationTest.cpp
+    )
+  endif()
+endif()
+
+create_test_sourcelist(Tests ${KIT}CppTests.cpp ${_test_srcs})
 
 set(TestsToRun ${Tests})
 remove(TestsToRun ${KIT}CppTests.cpp)
@@ -14,6 +29,9 @@ set(Tests_SRCS ${Tests_SRCS}
 set(Tests_MOC_SRCS ${Tests_MOC_SRCS}
   ctkCmdLineModuleSignalTester.h
 )
+set(Tests_RESOURCES
+  ctkCmdLineModuleTestResources.qrc
+)
 
 set(_base_src_include_dir ${CMAKE_SOURCE_DIR}/Libs/CommandLineModules)
 set(_base_bin_include_dir ${CMAKE_BINARY_DIR}/Libs/CommandLineModules)
@@ -23,13 +41,30 @@ include_directories(
   ${CMAKE_CURRENT_BINARY_DIR}
   ${_base_src_include_dir}/Core
   ${_base_bin_include_dir}/Core
-  ${_base_src_include_dir}/Backend/LocalProcess
-  ${_base_bin_include_dir}/Backend/LocalProcess
   )
 
+set(_additional_link_libraries)
+
+if(CTK_LIB_CommandLineModules/Backend/LocalProcess)
+  include_directories(${_base_src_include_dir}/Backend/LocalProcess
+                      ${_base_bin_include_dir}/Backend/LocalProcess)
+  list(APPEND _additional_link_libraries CTKCommandLineModulesBackendLocalProcess)
+endif()
+
+if(CTK_LIB_CommandLineModules/Backend/FunctionPointer)
+  include_directories(${_base_src_include_dir}/Backend/FunctionPointer
+                      ${_base_bin_include_dir}/Backend/FunctionPointer)
+  list(APPEND _additional_link_libraries CTKCommandLineModulesBackendFunctionPointer)
+endif()
+
+if(CTK_LIB_CommandLineModules/Frontend/QtGui)
+  include_directories(${_base_src_include_dir}/Frontend/QtGui
+                      ${_base_bin_include_dir}/Frontend/QtGui)
+  list(APPEND _additional_link_libraries CTKCommandLineModulesFrontendQtGui)
+endif()
+
 set(Tests_MOC_CPP)
 QT4_WRAP_CPP(Tests_MOC_CPP ${Tests_MOC_SRCS})
-
 set(Tests_UI_CPP)
 if(TEST_UI_FORMS)
   QT4_WRAP_UI(Tests_UI_CPP ${Tests_UI_FORMS})
@@ -38,7 +73,7 @@ set(Tests_RESOURCES_SRCS)
 QT4_ADD_RESOURCES(Tests_RESOURCES_SRCS ${Tests_RESOURCES})
 
 add_executable(${KIT}CppTests ${Tests} ${Tests_SRCS} ${Tests_MOC_CPP} ${Tests_UI_CPP} ${Tests_RESOURCES_SRCS})
-target_link_libraries(${KIT}CppTests CTKCommandLineModulesBackendLocalProcess)
+target_link_libraries(${KIT}CppTests ${_additional_link_libraries})
 add_dependencies(${KIT}CppTests ctkCmdLineTestModules)
 
 if(TARGET CTKCommandLineModulesCoreCppTests)
@@ -52,5 +87,7 @@ endif()
 # Add Tests
 #
 
-SIMPLE_TEST(ctkCmdLineModuleFutureTest)
-
+foreach(_src ${_test_srcs})
+  get_filename_component(_test_name ${_src} NAME_WE)
+  SIMPLE_TEST(${_test_name})
+endforeach()

+ 63 - 0
Libs/CommandLineModules/Testing/Cpp/MyImageComboBoxTest.xsl

@@ -0,0 +1,63 @@
+ <!--
+  ============================================================================
+    For an input image, we use MyComboBox and no Browse button.
+    But for output image, we use standard ctkPathLineEdit and a Browse button.
+  ============================================================================
+  -->
+  <xsl:template match="parameters/*[name()=('image')]" priority="2">
+    <xsl:call-template name="gridItemWithLabel"/>
+    <item  row="{position()-1}" column="1">
+      <layout class="QHBoxLayout">
+      <xsl:choose>
+        <xsl:when test="channel = 'input'">
+          <item>
+            <widget class="{$imageInputWidget}"  name="parameter:{name}">
+              <xsl:call-template name="commonWidgetProperties"/>
+              <xsl:call-template name="createQtDesignerStringListProperty"/>
+              <property name="parameter:valueProperty"> <!-- property name containing current value -->
+                <string>currentValue</string>
+              </property>
+            </widget>
+          </item>
+        </xsl:when>
+        <xsl:otherwise>
+          <item>
+            <widget class="{$imageOutputWidget}"  name="parameter:{name}">
+              <xsl:call-template name="commonWidgetProperties"/>
+              <xsl:call-template name="createQtDesignerStringListProperty"/>
+              <property name="filters">
+                <set>ctkPathLineEdit::Files</set>
+              </property>
+            </widget>
+          </item>
+          <item>
+            <widget class="QPushButton"  name="{name}BrowseButton">
+              <property name="text">
+                <string>Browse...</string>
+              </property>
+            </widget>
+          </item>
+        </xsl:otherwise>
+      </xsl:choose>
+      </layout>
+    </item>
+  </xsl:template>
+
+  <!--
+  ============================================================================
+    For an input image, we use MyComboBox and no Browse button.
+    But for output image, we use standard ctkPathLineEdit and a Browse button.
+  ============================================================================
+  -->
+
+  <xsl:template match="parameters/*[name()=('image')]" mode="connections" priority="2">
+    <xsl:if test="channel = 'output'">
+      <connection>
+        <sender><xsl:value-of select="name"/>BrowseButton</sender>
+        <signal>clicked()</signal>
+        <receiver>parameter:<xsl:value-of select="name"/></receiver>
+        <slot>browse()</slot>
+      </connection>
+    </xsl:if>
+  </xsl:template>
+

+ 255 - 0
Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp

@@ -0,0 +1,255 @@
+/*=========================================================================
+
+  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.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 <QList>
+#include <QString>
+#include <QComboBox>
+#include <QUiLoader>
+#include <QApplication>
+
+// CTK includes
+#include "ctkCmdLineModuleManager.h"
+#include "ctkCmdLineModuleFrontendQtGui.h"
+#include "ctkCmdLineModuleBackendFunctionPointer.h"
+#include "ctkCmdLineModuleParameter.h"
+#include "ctkCmdLineModuleParameterGroup.h"
+#include "ctkCmdLineModuleDescription.h"
+#include "ctkCmdLineModuleXslTransform.h"
+#include "ctkCmdLineModuleFuture.h"
+
+#include "ctkTest.h"
+
+// ----------------------------------------------------------------------------
+struct MyImageData : public ctk::CmdLineModuleBackendFunctionPointer::ImageType
+{
+  MyImageData(const QString& path = QString())
+    : Path(path)
+  {}
+
+  QString Path;
+};
+
+Q_DECLARE_METATYPE(MyImageData)
+Q_DECLARE_METATYPE(const MyImageData*)
+
+// ----------------------------------------------------------------------------
+namespace ctk {
+namespace CmdLineModuleBackendFunctionPointer {
+
+template<>
+QString GetParameterTypeName<MyImageData>()
+{
+  return "image";
+}
+
+}}
+
+// ----------------------------------------------------------------------------
+class MyImageComboBox : public QComboBox
+{
+  Q_OBJECT
+
+public:
+
+  Q_PROPERTY(QString currentValue READ currentValue WRITE setCurrentValue)
+  Q_PROPERTY(const MyImageData* currentImage READ currentImage)
+
+  MyImageComboBox(QWidget* parent = 0)
+    : QComboBox(parent)
+  {
+    imageData << MyImageData("/path/to/image1")
+              << MyImageData("/path/to/image2")
+              << MyImageData("/path/to/image3");
+
+    this->addItem("Image 1");
+    this->addItem("Image 2");
+    this->addItem("Image 3");
+  }
+
+  QString currentValue() const
+  {
+    return this->imageData.at(this->currentIndex()).Path;
+  }
+
+  void setCurrentValue(const QString& path)
+  {
+    this->imageData[this->currentIndex()].Path = path;
+  }
+
+  const MyImageData* currentImage() const
+  {
+    return &this->imageData.at(this->currentIndex());
+  }
+
+private:
+
+  QList<MyImageData> imageData;
+};
+
+
+// ----------------------------------------------------------------------------
+class MyQtGuiFrontend : public ctkCmdLineModuleFrontendQtGui
+{
+public:
+  MyQtGuiFrontend(const ctkCmdLineModuleReference& moduleRef)
+    : ctkCmdLineModuleFrontendQtGui(moduleRef)
+  {}
+
+  QUiLoader* uiLoader() const
+  {
+    struct MyUiLoader : public QUiLoader {
+      QStringList availableWidgets() const
+      {
+        return QUiLoader::availableWidgets() << "MyImageComboBox";
+      }
+      QWidget* createWidget(const QString& className, QWidget* parent, const QString& name)
+      {
+        if (className == "MyImageComboBox")
+        {
+          MyImageComboBox* comboBox = new MyImageComboBox(parent);
+          comboBox->setObjectName(name);
+          comboBox->setCurrentIndex(1);
+          return comboBox;
+        }
+        return QUiLoader::createWidget(className, parent, name);
+      }
+    };
+    static MyUiLoader myUiLoader;
+    return &myUiLoader;
+  }
+
+  ctkCmdLineModuleXslTransform* xslTransform() const
+  {
+    static bool initialized = false;
+    ctkCmdLineModuleXslTransform* transform = ctkCmdLineModuleFrontendQtGui::xslTransform();
+    if (!initialized)
+    {
+      transform->bindVariable("imageInputWidget", "MyImageComboBox");
+      static QFile extraXsl(":/MyImageComboBoxTest.xsl");
+      transform->setXslExtraTransformation(&extraXsl);
+      initialized = true;
+    }
+    return transform;
+  }
+
+  QVariant value(const QString &parameter, int role) const
+  {
+    if (role == UserRole)
+    {
+      ctkCmdLineModuleParameter param = this->moduleReference().description().parameter(parameter);
+      if (param.channel() == "input" && param.tag() == "image")
+      {
+        return this->customValue(parameter, "currentImage");
+      }
+      return QVariant();
+    }
+    return ctkCmdLineModuleFrontendQtGui::value(parameter, role);
+  }
+};
+
+// ----------------------------------------------------------------------------
+class MyFpBackend : public ctkCmdLineModuleBackendFunctionPointer
+{
+
+protected:
+
+  QList<QVariant> arguments(ctkCmdLineModuleFrontend *frontend) const
+  {
+    QList<QVariant> args;
+    foreach(ctkCmdLineModuleParameter param, frontend->parameters())
+    {
+      QVariant arg = frontend->value(param.name(), ctkCmdLineModuleFrontend::UserRole);
+      if (!arg.isValid())
+      {
+        arg = frontend->value(param.name());
+      }
+      args << arg;
+    }
+
+    return args;
+  }
+};
+
+// ----------------------------------------------------------------------------
+QString CustomImageDataPath;
+void CustomImageTypeModule(const MyImageData* imageData)
+{
+  CustomImageDataPath = imageData->Path;
+}
+
+// ----------------------------------------------------------------------------
+class ctkCmdLineModuleQtCustomizationTester: public QObject
+{
+  Q_OBJECT
+
+private Q_SLOTS:
+
+  void testCustomization();
+
+};
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleQtCustomizationTester::testCustomization()
+{
+  qRegisterMetaType<const MyImageData*>("const MyImageData*");
+
+  ctkCmdLineModuleManager moduleManager;
+
+  MyFpBackend fpBackend;
+  fpBackend.registerFunctionPointer("Image Type Customization", CustomImageTypeModule);
+
+  moduleManager.registerBackend(&fpBackend);
+  QUrl url = fpBackend.registeredFunctionPointers().front();
+  moduleManager.registerModule(url);
+
+  ctkCmdLineModuleReference moduleRef = moduleManager.moduleReference(url);
+
+  ctkCmdLineModuleFrontend* fpFrontend = new MyQtGuiFrontend(moduleRef);
+  // force the creation of the frontend gui
+  fpFrontend->guiHandle();
+
+  QString expectedImageValue = "/path/to/image2";
+  QCOMPARE(fpFrontend->value("param0").toString(), expectedImageValue);
+
+  // get a custom QVariant value holding the custom widget
+  QCOMPARE(fpFrontend->value("param0", ctkCmdLineModuleFrontend::UserRole).value<const MyImageData*>()->Path,
+           expectedImageValue);
+
+  // now set the property for the "LocalResourceRole" (the default property) to something else
+  expectedImageValue = "/tmp/path/to/image2";
+  fpFrontend->setValue("param0", expectedImageValue);
+  QCOMPARE(fpFrontend->value("param0").toString(), expectedImageValue);
+
+  QVERIFY(CustomImageDataPath.isEmpty());
+
+  // run the module (function pointer) and check that is gets the tmp path
+  ctkCmdLineModuleFuture future = moduleManager.run(fpFrontend);
+  sleep(1);
+  QApplication::processEvents();
+  future.waitForFinished();
+
+  QCOMPARE(CustomImageDataPath, expectedImageValue);
+}
+
+
+// ----------------------------------------------------------------------------
+CTK_TEST_MAIN(ctkCmdLineModuleQtCustomizationTest)
+#include "moc_ctkCmdLineModuleQtCustomizationTest.cpp"

+ 5 - 0
Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleTestResources.qrc

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