|
@@ -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 ¶meter, 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"
|