/*========================================================================= 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 #include #include #include #include // 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 Label; QString Path; }; Q_DECLARE_METATYPE(MyImageData) Q_DECLARE_METATYPE(const MyImageData*) // ---------------------------------------------------------------------------- namespace ctk { namespace CmdLineModuleBackendFunctionPointer { template<> QString GetParameterTypeName() { return "image"; } }} // ---------------------------------------------------------------------------- class MyImageComboBox : public QComboBox { Q_OBJECT public: 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) : 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 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 setCurrentPath(const QString& path) { this->imageData[this->currentIndex()].Path = path; } const MyImageData* currentImage() const { return &this->imageData.at(this->currentIndex()); } private: QList 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"); transform->bindVariable("imageValueProperty", "currentLabel"); static QFile extraXsl(":/MyImageComboBoxTest.xsl"); transform->setXslExtraTransformation(&extraXsl); initialized = true; } return transform; } QVariant value(const QString ¶meter, int role = LocalResourceRole) 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(); } else if (role == LocalResourceRole) { return this->customValue(parameter, "currentPath"); } else { return ctkCmdLineModuleFrontendQtGui::value(parameter, role); } } void setValue(const QString ¶meter, const QVariant &value, int role = DisplayRole) { if (role == LocalResourceRole) { this->setCustomValue(parameter, value, "currentPath"); } else { ctkCmdLineModuleFrontendQtGui::setValue(parameter, value, role); } } }; // ---------------------------------------------------------------------------- class MyFpBackend : public ctkCmdLineModuleBackendFunctionPointer { protected: QList arguments(ctkCmdLineModuleFrontend *frontend) const { QList 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*"); 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"; QString actualImageValue = fpFrontend->value("param0").toString(); QCOMPARE(actualImageValue, expectedImageValue); // get a custom QVariant value holding the custom widget QCOMPARE(fpFrontend->value("param0", ctkCmdLineModuleFrontend::UserRole).value()->Path, expectedImageValue); // now set the property for the "LocalResourceRole" (the default property) to something else expectedImageValue = "/tmp/path/to/image2"; fpFrontend->setValue("param0", expectedImageValue, ctkCmdLineModuleFrontend::LocalResourceRole); 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); QTest::qSleep(500); QApplication::processEvents(); future.waitForFinished(); QCOMPARE(CustomImageDataPath, expectedImageValue); } // ---------------------------------------------------------------------------- CTK_TEST_MAIN(ctkCmdLineModuleQtCustomizationTest) #include "moc_ctkCmdLineModuleQtCustomizationTest.cpp"