Developer Documentation

context.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42
43
44 //== INCLUDES =================================================================
45 #include <QBuffer>
46 #include <QXmlQuery>
47 #include <QXmlResultItems>
48
49 #include "context.hh"
50 #include "input.hh"
51 #include "output.hh"
52 #include "type.hh"
53 #include "function.hh"
54
55 #include "types/number.hh"
56 #include "types/string.hh"
57 #include "types/bool.hh"
58 #include "types/filename.hh"
59 #include "types/selection.hh"
60 #include "types/vec3d.hh"
61 #include "types/vec4d.hh"
62 #include "types/matrix4x4.hh"
63 #include "types/objectId/objectId.hh"
64 #include "types/any.hh"
65
66 #define DATA_NAME "DataFlow"
67
68 //== NAMESPACES ===============================================================
69 namespace VSI {
70
71 //=============================================================================
72 //
73 // CLASS VSI::Context - IMPLEMENTATION
74 //
75 //=============================================================================
76
78 Context::Context (QScriptEngine *_engine) :
79 scriptEngine_ (_engine)
80 {
81 // add start element
82 Element *e = new Element (this, "start");
83 elements_.append (e);
84
85 e->category_ = "Undefined";
86
87 e->shortDesc_ = "Start";
88 e->longDesc_ = "Start";
89
90 e->dataOut_ = new Output (e);
91 e->dataOut_->name_ = "data";
92 e->dataOut_->type_ = "data";
93
94 e->dataOut_->shortDesc_ = DATA_NAME;
95 e->dataOut_->longDesc_ = DATA_NAME;
96
97 e->flags_ = ELEMENT_FLAG_NO_DELETE | ELEMENT_FLAG_SKIP_TOOLBOX;
98
99 // add end element
100 e = new Element (this, "end");
101 elements_.append (e);
102
103 e->category_ = "Undefined";
104
105 e->shortDesc_ = "End";
106 e->longDesc_ = "End";
107
108 e->dataIn_ = new Input (e);
109 e->dataIn_->name_ = "data";
110 e->dataIn_->type_ = "data";
111
112 e->dataIn_->shortDesc_ = DATA_NAME;
113 e->dataIn_->longDesc_ = DATA_NAME;
114
115 e->flags_ = ELEMENT_FLAG_NO_DELETE | ELEMENT_FLAG_SKIP_TOOLBOX;
116
117
118 // Register default types
119 registerType (new TypeNumber ());
120 registerType (new TypeBool ());
121 registerType (new TypeString ());
122 registerType (new TypeFilename ());
123 registerType (new TypeSelection ());
124 registerType (new TypeVec3D ());
125 registerType (new TypeVec4D ());
126 registerType (new TypeMatrix4x4 ());
127 registerType (new TypeObjectId ());
128 registerType (new TypeAny ());
129 }
130
131 //------------------------------------------------------------------------------
132
134 Context::~Context ()
135 {
136 foreach (Element *e, elements_)
137 delete e;
138 foreach (Type *t, types_)
139 delete t;
140 }
141
142 //------------------------------------------------------------------------------
143
145 QVector <Element *> Context::elements (QString _category)
146 {
147 QVector <Element *> rv;
148 foreach (Element *e, elements_)
149 if (e->category () == _category)
150 rv.append (e);
151 return rv;
152 }
153
154 //------------------------------------------------------------------------------
155
157 Element * Context::element (QString _name)
158 {
159 foreach (Element *e, elements_)
160 if (e->name () == _name)
161 return e;
162 return NULL;
163 }
164
165 //------------------------------------------------------------------------------
166
168 QStringList Context::categories ()
169 {
170 QStringList sl;
171
172 foreach (Element *e, elements_)
173 if (!sl.contains (e->category ()) && !(e->flags () & ELEMENT_FLAG_SKIP_TOOLBOX))
174 sl << e->category ();
175
176 return sl;
177 }
178
179 //------------------------------------------------------------------------------
180
182 void Context::parse (QByteArray _xml)
183 {
184 QBuffer device (&_xml);
185 device.open(QIODevice::ReadOnly);
186
187 QXmlQuery query;
188 query.setFocus (&device);
189
190 // for each OpenFlipper/element
191 query.setQuery ("OpenFlipper//element");
192
193 QXmlResultItems elements;
194
195 if (query.isValid ())
196 {
197 query.evaluateTo (&elements);
198 QXmlItem item (elements.next ());
199 while (!item.isNull ())
200 {
201 QXmlQuery q (query);
202 q.setFocus (item);
203 parseElement (q);
204 item = elements.next ();
205 }
206
207 }
208
209 }
210
211 //------------------------------------------------------------------------------
212
213 // parse element from xml
214 void Context::parseElement (QXmlQuery &_xml)
215 {
216 if (getXmlString (_xml, "string(@name)").isEmpty ())
217 return;
218
219 Element *e = new Element (this, getXmlString (_xml, "string(@name)"));
220
221 elements_.append (e);
222
223 e->category_ = getXmlString (_xml, "category/string(text())", "Undefined");
224
225 e->shortDesc_ = getXmlString (_xml, "short/string(text())", e->name ());
226 e->longDesc_ = getXmlString (_xml, "long/string(text())", e->shortDesc_);
227
228 // scene graph in/output for scenegraph elements
229 if (strToBool (getXmlString (_xml, "dataflow/string(text())")))
230 {
231
232 e->dataIn_ = new Input (e);
233 e->dataIn_->name_ = "data";
234 e->dataIn_->type_ = QVariant::Invalid;
235
236 e->dataIn_->shortDesc_ = DATA_NAME;
237 e->dataIn_->longDesc_ = DATA_NAME;
238 e->dataIn_->setState (Input::NoRuntimeUserInput | Input::NoUserInput);
239
240 e->dataOut_ = new Output (e);
241 e->dataOut_->name_ = "data";
242 e->dataOut_->type_ = QVariant::Invalid;
243
244 e->dataOut_->shortDesc_ = DATA_NAME;
245 e->dataOut_->longDesc_ = DATA_NAME;
246 }
247
248 // parse all inputs
249 _xml.setQuery ("inputs/input");
250
251 QXmlResultItems inouts;
252
253 if (_xml.isValid ())
254 {
255 _xml.evaluateTo (&inouts);
256 QXmlItem item (inouts.next ());
257 while (!item.isNull ())
258 {
259 QXmlQuery q (_xml);
260 q.setFocus (item);
261 Input *i = parseInput (q, e);
262 if (i)
263 {
264 e->inputs_.append (i);
265 }
266 item = inouts.next ();
267 }
268
269 }
270
271 // parse all outputs
272 _xml.setQuery ("outputs/output");
273
274 if (_xml.isValid ())
275 {
276 _xml.evaluateTo (&inouts);
277 QXmlItem item (inouts.next ());
278 while (!item.isNull ())
279 {
280 QXmlQuery q (_xml);
281 q.setFocus (item);
282 Output *o = parseOutput (q, e);
283 if (o)
284 {
285 o->element_ = e;
286 e->outputs_.append (o);
287 }
288 item = inouts.next ();
289 }
290
291 }
292
293 // parse all functions
294 _xml.setQuery ("functions/function");
295
296 if (_xml.isValid ())
297 {
298 _xml.evaluateTo (&inouts);
299 QXmlItem item (inouts.next ());
300 while (!item.isNull ())
301 {
302 QXmlQuery q (_xml);
303 q.setFocus (item);
304 Function *f = parseFunction (q, e);
305 if (f)
306 {
307 e->functions_.append (f);
308 }
309 item = inouts.next ();
310 }
311
312 }
313
314 // get code & precode segment
315 e->precode_ = getXmlString (_xml, "precode/string(text())", "");
316 e->code_ = getXmlString (_xml, "code/string(text())", "");
317
318 // remove spaces at line begin
319 e->precode_ = e->precode_.replace (QRegExp ("\\n\\s*"),"\n");
320 e->code_ = e->code_.replace (QRegExp ("\\n\\s*"),"\n");
321
322 }
323
324 //------------------------------------------------------------------------------
325
326 // parse element input from xml
327 Input* Context::parseInput (QXmlQuery &_xml, Element *_e)
328 {
329 Input *i = new Input (_e);
330
331 // common part
332 if (!parseInOutBase (_xml, i))
333 {
334 delete i;
335 return NULL;
336 }
337
338 // input states
339 QString stateStr = getXmlString (_xml, "string(@external)");
340 unsigned int state = 0;
341
342 if (!stateStr.isEmpty () && !strToBool (stateStr))
343 state |= Input::NoExternalInput;
344
345 stateStr = getXmlString (_xml, "string(@user)");
346
347 if (!stateStr.isEmpty () && !strToBool (stateStr))
348 state |= Input::NoUserInput;
349
350 stateStr = getXmlString (_xml, "string(@runtime)");
351
352 if (!stateStr.isEmpty () && !strToBool (stateStr))
353 state |= Input::NoRuntimeUserInput;
354
355 stateStr = getXmlString (_xml, "string(@optional)");
356
357 if (!stateStr.isEmpty () && strToBool (stateStr))
358 state |= Input::Optional;
359
360 i->state_ = state;
361
362 return i;
363 }
364
365 //------------------------------------------------------------------------------
366
367 // parse element output from xml
368 Output* Context::parseOutput (QXmlQuery &_xml, Element *_e)
369 {
370 Output *o = new Output (_e);
371
372 // common part
373 if (!parseInOutBase (_xml, o))
374 {
375 delete o;
376 return NULL;
377 }
378
379 return o;
380 }
381
382 //------------------------------------------------------------------------------
383
384 // parse common input and output parts from xml
385 bool Context::parseInOutBase (QXmlQuery &_xml, InOut *_io)
386 {
387 QString type = getXmlString (_xml, "string(@type)");
388
389 if (getXmlString (_xml, "string(@name)").isEmpty () ||
390 type.isEmpty ())
391 return false;
392
393 _io->name_ = getXmlString (_xml, "string(@name)");
394 _io->type_ = type;
395
396 _io->shortDesc_ = getXmlString (_xml, "short/string(text())", _io->name ());
397 _io->longDesc_ = getXmlString (_xml, "long/string(text())", _io->shortDesc_);
398
399 // get type hints for supported types
400 if (typeSupported (type))
401 {
402 foreach (QString hint, supportedTypes_[type]->supportedHints ())
403 {
404 QString value = getXmlString (_xml, hint + "/string(text())", "");
405 if (!value.isEmpty ())
406 _io->hints_[hint] = value;
407 }
408 }
409
410 return true;
411 }
412
413 //------------------------------------------------------------------------------
414
415 // parse element function from xml
416 Function* Context::parseFunction (QXmlQuery &_xml, Element *_e)
417 {
418 QString name = getXmlString (_xml, "string(@name)");
419 if (name.isEmpty ())
420 return NULL;
421
422 Function *f = new Function (_e, name);
423
424 f->shortDesc_ = getXmlString (_xml, "short/string(text())", f->name ());
425 f->longDesc_ = getXmlString (_xml, "long/string(text())", f->shortDesc_);
426
427 // add start element
428 f->start_ = new Element (_e->context (), "start_" + _e->name () + "_" + name);
429
430 f->start_->category_ = "Undefined";
431
432 f->start_->shortDesc_ = "Start";
433 f->start_->longDesc_ = "Start";
434
435 f->start_->dataOut_ = new Output (f->start_);
436 f->start_->dataOut_->name_ = "data";
437 f->start_->dataOut_->type_ = "data";
438
439 f->start_->dataOut_->shortDesc_ = DATA_NAME;
440 f->start_->dataOut_->longDesc_ = DATA_NAME;
441
442 f->start_->flags_ = ELEMENT_FLAG_NO_DELETE | ELEMENT_FLAG_SKIP_TOOLBOX;
443
444 elements_.append (f->start_);
445
446 // add end element
447 f->end_ = new Element (_e->context (), "end_" + _e->name () + "_" + name);
448
449 f->end_->category_ = "Undefined";
450
451 f->end_->shortDesc_ = "End";
452 f->end_->longDesc_ = "End";
453
454 f->end_->dataIn_ = new Input (f->end_);
455 f->end_->dataIn_->name_ = "data";
456 f->end_->dataIn_->type_ = "data";
457
458 f->end_->dataIn_->shortDesc_ = DATA_NAME;
459 f->end_->dataIn_->longDesc_ = DATA_NAME;
460
461 f->end_->flags_ = ELEMENT_FLAG_NO_DELETE | ELEMENT_FLAG_SKIP_TOOLBOX;
462
463 elements_.append (f->end_);
464
465 // inputs
466 _xml.setQuery ("inputs/input");
467
468 QXmlResultItems inouts;
469
470 if (_xml.isValid ())
471 {
472 _xml.evaluateTo (&inouts);
473 QXmlItem item (inouts.next ());
474 while (!item.isNull ())
475 {
476 QXmlQuery q (_xml);
477 q.setFocus (item);
478 Output *o = new Output (f->start_);
479 if (parseInOutBase(q, o))
480 {
481 f->start_->outputs_.append (o);
482 }
483 else
484 delete o;
485 item = inouts.next ();
486 }
487
488 }
489
490 // outputs
491 _xml.setQuery ("outputs/output");
492
493 if (_xml.isValid ())
494 {
495 _xml.evaluateTo (&inouts);
496 QXmlItem item (inouts.next ());
497 while (!item.isNull ())
498 {
499 QXmlQuery q (_xml);
500 q.setFocus (item);
501 Input *i = new Input (f->end_);
502 if (parseInOutBase(q, i))
503 {
504 i->state_ = Input::NoUserInput | Input::NoRuntimeUserInput;
505 f->end_->inputs_.append (i);
506 }
507 else
508 delete i;
509 item = inouts.next ();
510 }
511
512 }
513
514 // add end node only if we have outputs
515 if (!f->end_->inputs ().isEmpty ())
516 {
517 // Generate end node return code
518
519 QString endCode = "return { ";
520 foreach (Input *i, f->end_->inputs ())
521 endCode += i->name () + " : [input=\"" + i->name () + "\"], ";
522 endCode.remove (endCode.length () - 2, 2);
523 endCode += " };\n";
524
525 f->end_->code_ = endCode;
526 }
527
528 return f;
529 }
530
531 //------------------------------------------------------------------------------
532
534 QString Context::getXmlString (QXmlQuery &_xml, QString _expr, QString _default)
535 {
536 QStringList sl;
537
538 _xml.setQuery (_expr);
539
540 if (_xml.isValid () && _xml.evaluateTo (&sl) && sl.length () == 1)
541 return sl[0];
542
543 return _default;
544 }
545
546 //------------------------------------------------------------------------------
547
549 bool Context::strToBool (QString _str)
550 {
551 if (_str == "1" || _str == "true" || _str == "True" || _str == "TRUE" ||
552 _str == "yes" || _str == "Yes" || _str == "YES")
553 return true;
554 return false;
555 }
556
557 //------------------------------------------------------------------------------
558
560 void Context::registerType(Type * _type)
561 {
562 types_.append (_type);
563
564 foreach (const QString &s, _type->supportedTypes())
565 supportedTypes_.insert (s, _type);
566 }
567
568 //------------------------------------------------------------------------------
569
571 bool Context::typeSupported(QString _type)
572 {
573 return supportedTypes_.contains (_type);
574 }
575
576 //------------------------------------------------------------------------------
577
579 bool Context::canConvert(QString _type1, QString _type2)
580 {
581 if (!typeSupported (_type1) || !typeSupported (_type2))
582 return false;
583 return supportedTypes_[_type1]->canConvertTo (_type2) ||
584 supportedTypes_[_type2]->canConvertTo (_type1);
585 }
586
587 //------------------------------------------------------------------------------
588
590 Type * Context::getType(QString _type)
591 {
592 if (typeSupported (_type))
593 return supportedTypes_[_type];
594 return NULL;
595 }
596
597 //------------------------------------------------------------------------------
598
599 }
VSI::Element::flags
unsigned int flags() const
Flags.
Definition: element.hh:109
VSI::TypeMatrix4x4
Definition: matrix4x4.hh:58
VSI::Type
Definition: type.hh:65
VSI::TypeObjectId
Definition: objectId.hh:58
VSI::InOut::name
const QString & name() const
Name.
Definition: inout.hh:70
VSI::TypeVec3D
Definition: vec3d.hh:58
VSI::Context::registerType
void registerType(Type *_type)
Registers a supported datatype.
Definition: context.cc:560
VSI::Context::getXmlString
static QString getXmlString(QXmlQuery &_xml, QString _expr, QString _default="")
Gets the string of a xml query.
Definition: context.cc:534
VSI::Context::typeSupported
bool typeSupported(QString _type)
Is the given type supported.
Definition: context.cc:571
VSI::Function::name
QString name() const
Name.
Definition: function.hh:81
VSI::Context::canConvert
bool canConvert(QString _type1, QString _type2)
Can the given types be converted to each other.
Definition: context.cc:579
VSI::Context::getType
Type * getType(QString _type)
Get type object for given type name.
Definition: context.cc:590
VSI::Element::inputs
const QVector< Input * > & inputs() const
Inputs.
Definition: element.hh:94
VSI::Context::strToBool
static bool strToBool(QString _str)
Converts the given string to bool.
Definition: context.cc:549
VSI::Input::setState
void setState(unsigned int _state)
Sets the state.
Definition: input.hh:79
VSI::Type::supportedTypes
virtual QStringList supportedTypes()
Names of Types.
Definition: type.cc:71
VSI::TypeVec4D
Definition: vec4d.hh:57
VSI::TypeAny
Definition: any.hh:58
VSI::TypeBool
Definition: bool.hh:58
VSI::Context::elements
const QVector< Element * > & elements() const
Returns all available elements.
Definition: context.hh:83
VSI::Context::parse
void parse(QByteArray _xml)
Parse xml content.
Definition: context.cc:182
VSI::InOut
Definition: inout.hh:62
VSI::TypeFilename
Definition: filename.hh:58
VSI::Element::context
Context * context() const
Context of element.
Definition: element.hh:79
VSI::Context::element
Element * element(QString _name)
Returns the element with a given name.
Definition: context.cc:157
VSI::Element::name
QString name() const
Element name.
Definition: element.hh:82
VSI::Context::Context
Context(QScriptEngine *_engine)
Constructor.
Definition: context.cc:78
VSI::Context::~Context
~Context()
Destructor.
Definition: context.cc:134
VSI::TypeSelection
Definition: selection.hh:58
VSI
Definition: baseWidget.cc:72
VSI::Output
Definition: output.hh:60
VSI::Function
Definition: function.hh:67
VSI::Element
Definition: element.hh:68
VSI::Input
Definition: input.hh:60
VSI::TypeString
Definition: string.hh:58
VSI::Element::category
const QString & category() const
Element category.
Definition: element.hh:85
VSI::Context::categories
QStringList categories()
List of categories.
Definition: context.cc:168
VSI::TypeNumber
Definition: number.hh:58