1 /*=========================================================================
2
3 Library: CTK
4
5 Copyright (c) Kitware Inc.
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0.txt
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19 =========================================================================*/
20
21 // Qt includes
22 #include <QList>
23 #include <QString>
24 #include <QComboBox>
25 #include <QUiLoader>
26 #include <QApplication>
27
28 // CTK includes
29 #include "ctkCmdLineModuleManager.h"
30 #include "ctkCmdLineModuleFrontendQtGui.h"
31 #include "ctkCmdLineModuleBackendFunctionPointer.h"
32 #include "ctkCmdLineModuleParameter.h"
33 #include "ctkCmdLineModuleParameterGroup.h"
34 #include "ctkCmdLineModuleDescription.h"
35 #include "ctkCmdLineModuleXslTransform.h"
36 #include "ctkCmdLineModuleFuture.h"
37
38 #include "ctkTest.h"
39
40 // ----------------------------------------------------------------------------
41 struct MyImageData : public ctk::CmdLineModuleBackendFunctionPointer::ImageType
42 {
MyImageDataMyImageData43 MyImageData(const QString& path = QString())
44 : Path(path)
45 {}
46
47 QString Label;
48 QString Path;
49 };
50
51 Q_DECLARE_METATYPE(MyImageData)
52 Q_DECLARE_METATYPE(const MyImageData*)
53
54 // ----------------------------------------------------------------------------
55 namespace ctk {
56 namespace CmdLineModuleBackendFunctionPointer {
57
58 template<>
GetParameterTypeName()59 QString GetParameterTypeName<MyImageData>()
60 {
61 return "image";
62 }
63
64 }}
65
66 // ----------------------------------------------------------------------------
67 class MyImageComboBox : public QComboBox
68 {
69 Q_OBJECT
70
71 public:
72
73 Q_PROPERTY(QString currentLabel READ currentLabel WRITE setCurrentLabel)
74 Q_PROPERTY(QString currentPath READ currentPath WRITE setCurrentPath)
75 Q_PROPERTY(const MyImageData* currentImage READ currentImage)
76
77 MyImageComboBox(QWidget* parent = 0)
78 : QComboBox(parent)
79 {
80 imageData << MyImageData("/path/to/image1")
81 << MyImageData("/path/to/image2")
82 << MyImageData("/path/to/image3");
83
84 this->addItem("Image 1");
85 this->addItem("Image 2");
86 this->addItem("Image 3");
87 }
88
currentLabel() const89 QString currentLabel() const
90 {
91 return this->imageData.at(this->currentIndex()).Label;
92 }
93
setCurrentLabel(const QString & label)94 void setCurrentLabel(const QString& label)
95 {
96 for(int i = 0; i < imageData.size(); ++i)
97 {
98 if (imageData[i].Label == label)
99 {
100 this->setCurrentIndex(i);
101 break;
102 }
103 }
104 }
105
currentPath() const106 QString currentPath() const
107 {
108 return this->imageData.at(this->currentIndex()).Path;
109 }
110
setCurrentPath(const QString & path)111 void setCurrentPath(const QString& path)
112 {
113 this->imageData[this->currentIndex()].Path = path;
114 }
115
currentImage() const116 const MyImageData* currentImage() const
117 {
118 return &this->imageData.at(this->currentIndex());
119 }
120
121 private:
122
123 QList<MyImageData> imageData;
124 };
125
126
127 // ----------------------------------------------------------------------------
128 class MyQtGuiFrontend : public ctkCmdLineModuleFrontendQtGui
129 {
130 public:
MyQtGuiFrontend(const ctkCmdLineModuleReference & moduleRef)131 MyQtGuiFrontend(const ctkCmdLineModuleReference& moduleRef)
132 : ctkCmdLineModuleFrontendQtGui(moduleRef)
133 {}
134
uiLoader() const135 QUiLoader* uiLoader() const
136 {
137 struct MyUiLoader : public QUiLoader {
138 QStringList availableWidgets() const
139 {
140 return QUiLoader::availableWidgets() << "MyImageComboBox";
141 }
142 QWidget* createWidget(const QString& className, QWidget* parent, const QString& name)
143 {
144 if (className == "MyImageComboBox")
145 {
146 MyImageComboBox* comboBox = new MyImageComboBox(parent);
147 comboBox->setObjectName(name);
148 comboBox->setCurrentIndex(1);
149 return comboBox;
150 }
151 return QUiLoader::createWidget(className, parent, name);
152 }
153 };
154 static MyUiLoader myUiLoader;
155 return &myUiLoader;
156 }
157
xslTransform() const158 ctkCmdLineModuleXslTransform* xslTransform() const
159 {
160 static bool initialized = false;
161 ctkCmdLineModuleXslTransform* transform = ctkCmdLineModuleFrontendQtGui::xslTransform();
162 if (!initialized)
163 {
164 transform->bindVariable("imageInputWidget", "MyImageComboBox");
165 transform->bindVariable("imageValueProperty", "currentLabel");
166 static QFile extraXsl(":/MyImageComboBoxTest.xsl");
167 transform->setXslExtraTransformation(&extraXsl);
168 initialized = true;
169 }
170 return transform;
171 }
172
value(const QString & parameter,int role=LocalResourceRole) const173 QVariant value(const QString ¶meter, int role = LocalResourceRole) const
174 {
175 if (role == UserRole)
176 {
177 ctkCmdLineModuleParameter param = this->moduleReference().description().parameter(parameter);
178 if (param.channel() == "input" && param.tag() == "image")
179 {
180 return this->customValue(parameter, "currentImage");
181 }
182 return QVariant();
183 }
184 else if (role == LocalResourceRole)
185 {
186 return this->customValue(parameter, "currentPath");
187 }
188 else
189 {
190 return ctkCmdLineModuleFrontendQtGui::value(parameter, role);
191 }
192 }
193
setValue(const QString & parameter,const QVariant & value,int role=DisplayRole)194 void setValue(const QString ¶meter, const QVariant &value, int role = DisplayRole)
195 {
196 if (role == LocalResourceRole)
197 {
198 this->setCustomValue(parameter, value, "currentPath");
199 }
200 else
201 {
202 ctkCmdLineModuleFrontendQtGui::setValue(parameter, value, role);
203 }
204 }
205 };
206
207 // ----------------------------------------------------------------------------
208 class MyFpBackend : public ctkCmdLineModuleBackendFunctionPointer
209 {
210
211 protected:
212
arguments(ctkCmdLineModuleFrontend * frontend) const213 QList<QVariant> arguments(ctkCmdLineModuleFrontend *frontend) const
214 {
215 QList<QVariant> args;
216 foreach(ctkCmdLineModuleParameter param, frontend->parameters())
217 {
218 QVariant arg = frontend->value(param.name(), ctkCmdLineModuleFrontend::UserRole);
219 if (!arg.isValid())
220 {
221 arg = frontend->value(param.name());
222 }
223 args << arg;
224 }
225
226 return args;
227 }
228 };
229
230 // ----------------------------------------------------------------------------
231 QString CustomImageDataPath;
CustomImageTypeModule(const MyImageData * imageData)232 void CustomImageTypeModule(const MyImageData* imageData)
233 {
234 CustomImageDataPath = imageData->Path;
235 }
236
237 // ----------------------------------------------------------------------------
238 class ctkCmdLineModuleQtCustomizationTester: public QObject
239 {
240 Q_OBJECT
241
242 private Q_SLOTS:
243
244 void testCustomization();
245
246 };
247
248 // ----------------------------------------------------------------------------
testCustomization()249 void ctkCmdLineModuleQtCustomizationTester::testCustomization()
250 {
251 qRegisterMetaType<const MyImageData*>("const MyImageData*");
252
253 ctkCmdLineModuleManager moduleManager;
254
255 MyFpBackend fpBackend;
256 fpBackend.registerFunctionPointer("Image Type Customization", CustomImageTypeModule);
257
258 moduleManager.registerBackend(&fpBackend);
259 QUrl url = fpBackend.registeredFunctionPointers().front();
260 moduleManager.registerModule(url);
261
262 ctkCmdLineModuleReference moduleRef = moduleManager.moduleReference(url);
263
264 ctkCmdLineModuleFrontend* fpFrontend = new MyQtGuiFrontend(moduleRef);
265 // force the creation of the frontend gui
266 fpFrontend->guiHandle();
267
268 QString expectedImageValue = "/path/to/image2";
269 QString actualImageValue = fpFrontend->value("param0").toString();
270 QCOMPARE(actualImageValue, expectedImageValue);
271
272 // get a custom QVariant value holding the custom widget
273 QCOMPARE(fpFrontend->value("param0", ctkCmdLineModuleFrontend::UserRole).value<const MyImageData*>()->Path,
274 expectedImageValue);
275
276 // now set the property for the "LocalResourceRole" (the default property) to something else
277 expectedImageValue = "/tmp/path/to/image2";
278 fpFrontend->setValue("param0", expectedImageValue, ctkCmdLineModuleFrontend::LocalResourceRole);
279 QCOMPARE(fpFrontend->value("param0").toString(), expectedImageValue);
280
281 QVERIFY(CustomImageDataPath.isEmpty());
282
283 // run the module (function pointer) and check that is gets the tmp path
284 ctkCmdLineModuleFuture future = moduleManager.run(fpFrontend);
285 QTest::qSleep(500);
286 QApplication::processEvents();
287 future.waitForFinished();
288
289 QCOMPARE(CustomImageDataPath, expectedImageValue);
290 }
291
292
293 // ----------------------------------------------------------------------------
294 CTK_TEST_MAIN(ctkCmdLineModuleQtCustomizationTest)
295 #include "moc_ctkCmdLineModuleQtCustomizationTest.cpp"
296