arcsxmlhandler.cpp
1 /*
2  name: lib/arcsxmlhandler.cpp
3 
4  This file is part of ARCS - Augmented Reality Component System
5  (version 2-current), written by Jean-Yves Didier
6  for IBISC Laboratory (http://www.ibisc.univ-evry.fr)
7 
8  Copyright (C) 2013 Université d'Evry-Val d'Essonne
9 
10  This program is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 2 of the License, or
13  (at your option) any later version.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program. If not, see <http://www.gnu.org/licenses/>.
22 
23 
24  Please send bugreports with examples or suggestions to
25  jean-yves.didier__at__ibisc.univ-evry.fr
26 */
27 
28 
29 #include <arcs/arcsxmlhandler.h>
30 
31 #include <arcs/arcsstatemachine.h>
32 #include <arcs/arcsapplicationcomponent.h>
33 #include <arcs/arcscompositecomponent.h>
34 #include <arcs/arcs.h>
35 #include <arcs/arcslog.h>
36 
37 #include <iostream>
38 
39 #include <QFile>
40 #include <QFileInfo>
41 #include <QTextStream>
42 #include <QDir>
43 
44 
45 
47 {
48  factory = ARCSFactory::getInstance();
49 }
50 
51 ARCSXMLHandler::~ARCSXMLHandler()
52 {
53 }
54 
55 
56 bool ARCSXMLHandler::openFile(QString fileName)
57 {
58  QFileInfo fi(fileName);
59  this->fileName = fi.canonicalFilePath();
60 
61  if (!fi.exists())
62  {
63  ARCSLog::logCritical(logSource(), "file " + this->fileName + " does not exist.");
64  return false;
65  }
66 
67 
68  QFile file(this->fileName);
69 
70  if (!file.open(QIODevice::ReadOnly))
71  {
72  ARCSLog::logCritical(logSource(),"cannot open file " +
73  this->fileName);
74  return false;
75  }
76 
77  QString error;
78  int line, col;
79  bool ok = doc.setContent(&file, &error, &line, &col);
80 
81  if(!ok)
82  {
83  ARCSLog::logCritical(logSource(line),
84  QString("malformed xml: (line: ")+ line +
85  ", col:" + col + ") "+ error);
86  return false;
87  }
88 
89  file.close();
90  reset();
91  return true;
92 }
93 
94 
95 bool ARCSXMLHandler::setContents(QString contents)
96 {
97  QString error;
98  int line, col;
99 
100  bool ok = doc.setContent(contents, &error, &line, &col);
101 
102 
103  if(!ok)
104  {
105  ARCSLog::logCritical(logSource(line), QString("malformed xml: (line: ")+ line +", col:" + col + ") "+ error);
106  return false;
107  }
108 
109  reset();
110  return true;
111 }
112 
113 
114 QString ARCSXMLHandler::getContents()
115 {
116  return doc.toString();
117 }
118 
119 
121 {
122  QFileInfo fi(s);
123  this->fileName = QDir::cleanPath(fi.absoluteFilePath());
124  QFile file(this->fileName);
125 
126  if (!file.open(QIODevice::WriteOnly))
127  {
128  std::cerr << "[SaveFile] Cannot open file " << qPrintable(this->fileName) << std::endl;
129  return false;
130  }
131 
132  computeRelativePaths(this->fileName);
133 
134  QTextStream ts(&file);
135 
136  doc.save(ts,4);
137  ts.flush();
138  if (ts.status() != QTextStream::Ok)
139  return false;
140 
141  file.close();
142  return true;
143 }
144 
145 
147 {
148  int i;
149 
150  ctx->reset();
151 
152  QDomNodeList contexts = doc.elementsByTagName(QString("context"));
153 
154  if (contexts.isEmpty())
155  {
156  ARCSLog::logWarning(logSource(),"\"context\" tag undefined.");
157  return true;
158  }
159 
160  if (!contexts.at(0).hasChildNodes())
161  {
162  ARCSLog::logWarning(logSource(contexts.at(0).lineNumber()),"\"context\" tag is empty.");
163  return true;
164  }
165 
166  QDomNodeList contextChildren = contexts.at(0).childNodes();
167 
168  for (i=0; i < contextChildren.count() ; i++)
169  {
170  QDomNode e = contextChildren.at(i);
171  if (e.isElement())
172  {
173  QDomElement elt = e.toElement();
174  if (elt.tagName() == "libraries" )
175  {
176  bool ok;
177  parseLibraries(elt,&ok);
178  if (!ok)
179  return false;
180 
181  }
182  if (elt.tagName() == "components" )
183  parseComponents(elt,ctx);
184  if (elt.tagName() == "constants" )
185  parseConstants(elt,ctx);
186  }
187  }
188  return true;
189 }
190 
192 bool ARCSXMLHandler::parseSheet(ARCSSheet* sheet, QDomElement father)
193 {
194  int i,j,k;
195  // father contient déjà l'élément sheet
196  if (father.hasAttribute("id"))
197  sheet->setName(father.attribute("id"));
198 
199 
200  QDomNodeList children = father.childNodes();
201 
202  for(i = 0; i< children.count(); i++)
203  {
204  QDomElement element = children.at(i).toElement();
205  if (element.tagName() == "connections")
206  {
207  QDomNodeList eltChildren = element.childNodes();
208  for (j=0; j < eltChildren.count(); j++)
209  {
210  QDomElement elt = eltChildren.at(j).toElement();
211  if (elt.tagName() == "link" )
212  {
213  if (elt.hasAttribute("source") &&
214  elt.hasAttribute("destination") &&
215  elt.hasAttribute("signal") &&
216  elt.hasAttribute("slot") )
217  {
218  bool b = false;
219  if (elt.hasAttribute("queued"))
220  {
221  QString sQueued = elt.attribute("queued").toLower();
222  if (sQueued == "t" || sQueued == "1" || sQueued == "true")
223  b = true;
224  }
225 
226  ARCSConnection& connect = sheet->addConnection(elt.attribute("source"), elt.attribute("signal"),
227  elt.attribute("destination"), elt.attribute("slot"),b);
228  if (!connect.isComplete())
229  ARCSLog::logError(logSource(elt.lineNumber()),"could not create complete link." );
230 
232  if (elt.hasAttribute("coords"))
233  {
234  QList<QPointF> coords;
235  QStringList coordStrings = elt.attribute("coords").split(' ');
236  for (k=0; k < coordStrings.count(); k++)
237  {
238  coords.append(QPointF(coordStrings[k].section(',',0,0).toFloat(),
239  coordStrings[k].section(',',1,1).toFloat()));
240  }
241  connect.setCoordinates(coords);
242 
243  }
244 
245  }
246  else
247  ARCSLog::logWarning(logSource(elt.lineNumber()),"\"link\" tag is missing either \"source\", \"destination\", \"signal\" or \"slot\" attributes.");
248  }
249  }
250  }
251  if (element.tagName() == "preconnections")
252  parseInvocation(element, sheet, &ARCSSheet::addPreconnect);
253 
254  if (element.tagName() == "postconnections")
255  parseInvocation(element, sheet, &ARCSSheet::addPostconnect);
256 
257  if (element.tagName() == "cleanups")
258  parseInvocation(element, sheet, &ARCSSheet::addCleanup);
259 
260  if (element.tagName() == "properties")
261  parseSheetProperties(element,sheet);
262 
263  }
264 
265  return true;
266 }
267 
268 
269 void ARCSXMLHandler::parseSheetProperties(QDomElement elt, ARCSSheet *sheet)
270 {
271  int j;
272  QDomNodeList eltChildren = elt.childNodes();
273  for (j=0; j< eltChildren.count(); j++)
274  {
275  QDomElement element = eltChildren.at(j).toElement();
276  if (element.tagName() == "property")
277  {
278  if (element.hasAttribute("id"))
279  sheet->setProperty(element.attribute("id"),nodeInternalsToText(element));
280  else
281  ARCSLog::logError(logSource(element.lineNumber())," \"property\" tag is missing \"id\" attribute.");
282  }
283  }
284 }
285 
286 
287 
289 void ARCSXMLHandler::parseInvocation(QDomElement element,ARCSSheet* sheet, ARCSSheet::AddInvocationMethod method)
290 {
291  int j;
292  QDomNodeList eltChildren = element.childNodes();
293  for (j=0; j< eltChildren.count(); j++)
294  {
295  QDomElement elt = eltChildren.at(j).toElement();
296  if (elt.tagName() == "invoke")
297  {
298  if (elt.hasAttribute("destination") &&
299  elt.hasAttribute("slot") &&
300  elt.hasAttribute("type") )
301  {
302  if (!(sheet->*method)(elt.attribute("destination"), elt.attribute("slot"),
303  elt.attribute("type"), nodeInternalsToText(elt)).isComplete())
304  {
305  ARCSLog::logError(logSource(elt.lineNumber()),"could not create invocation.");
306  }
307  }
308  else
309  ARCSLog::logError(logSource(elt.lineNumber()),"\"invoke\" tag is missing either \"destination\", \"slot\" or \"type\" attribute." );
310  }
311  }
312 }
313 
314 QStringList ARCSXMLHandler::parseLibraries(QDomElement libraries,bool* ok)
315 {
316  QStringList result;
317 
318  QDomNodeList librariesList = libraries.childNodes();
319  if (ok) *ok = true;
320 
321  for(int i = 0 ; i < librariesList.count(); i++)
322  {
323  if (librariesList.at(i).isElement())
324  {
325  QDomElement element = librariesList.at(i).toElement();
326  if( element.tagName() == "library")
327  {
328  if(element.hasAttribute("path"))
329  {
330  QString path = element.attribute("path");
331  QString finalPath = solveRelativePath(path) ; //pushPath?pathStack.topAbsolutePathWith(path):path;
332 
333  if (finalPath.isEmpty())
334  {
335  ARCSLog::logError(logSource(element.lineNumber()), "library "+finalPath + " not found.");
336  if (ok) *ok = *ok && false;
337  }
338  else
339  {
340  if (factory->loadLibrary(finalPath))
341  result << path ;
342  else
343  {
344  ARCSLog::logError(logSource(element.lineNumber()), "failed to load library "+finalPath);
345  if (ok) *ok = *ok && false;
346  }
347  }
348  }
349  else
350  ARCSLog::logWarning(logSource(element.lineNumber()),"\"library\" tag is missing \"path\" attribute.");
351  }
352  }
353  }
354  return result;
355 }
356 
357 
358 bool ARCSXMLHandler::parseStateMachine(ARCSStateMachine* sm)
359 {
360  int i,j;
361  if (doc.documentElement().tagName() != "statemachine" )
362  {
363  ARCSLog::logCritical(logSource(doc.documentElement().lineNumber()), "\"statemachine\" tag expected.");
364  return false;
365  }
366 
367  QDomNodeList elements = doc.documentElement().childNodes();
368  bool noerror = true ;
369  bool hasTransitions = false;
370 
371  for ( i=0; i < elements.count() ; i++)
372  {
373  if (elements.at(i).isElement())
374  {
375  QDomElement element = elements.at(i).toElement();
376  if (element.tagName() == "transitions")
377  {
378  hasTransitions = true;
379  QDomNodeList transitions = element.childNodes();
380  for ( j = 0; j < transitions.count(); j++)
381  {
382  if (transitions.at(j).isElement())
383  {
384  QDomElement transition = transitions.at(j).toElement();
385  if (transition.tagName() == "transition")
386  {
387  if ( transition.hasAttribute("source") &&
388  transition.hasAttribute("token" ) &&
389  transition.hasAttribute("destination") )
390  {
391  noerror = noerror && true;
392  sm->addTransition(transition.attribute("source"),
393  transition.attribute("token"),
394  transition.attribute("destination"));
395  }
396  else
397  {
398  noerror = noerror && false;
399  ARCSLog::logWarning(logSource(transition.lineNumber()), "\"transition\" tag is missing either \"source\", \"token\", or \"destination\" attribute.");
400  }
401  }
402  }
403  }
404  }
405 
406  if (element.tagName() == "first")
407  {
408  if (element.hasAttribute("name"))
409  sm->setFirstSheetName(element.attribute("name"));
410  else
411  ARCSLog::logWarning(logSource(element.lineNumber()),"\"first\" tag is missing \"name\" attribute.");
412  }
413 
414  if (element.tagName() == "last" )
415  {
416  if (element.hasAttribute("name"))
417  sm->setLastSheetName(element.attribute("name"));
418  else
419  ARCSLog::logWarning(logSource(element.lineNumber()),"\"last\" tag is missing \"name\" attribute.");
420  }
421  }
422  }
423 
424  if (!hasTransitions)
425  ARCSLog::logWarning(logSource(doc.documentElement().lineNumber()),"statemachine without any transition.");
426 
427 
428  return ( noerror && hasTransitions ) ;
429 }
430 
431 
432 
433 bool ARCSXMLHandler::parseProcess(ARCSProcess* ap, QDomElement processNode)
434 {
435  if (processNode.tagName() != "process")
436  {
437  ARCSLog::logError(logSource(processNode.lineNumber()),"\"process\" tag expected.");
438  return false;
439  }
440 
441  if (processNode.hasAttribute("controller"))
442  if (!ap->setController(processNode.attribute("controller")))
443  {
444  ARCSLog::logError(logSource(processNode.lineNumber()),"undefined controller: "+ processNode.attribute("controller"));
445  return false;
446  }
447 
448  QDomNodeList lst = processNode.elementsByTagName("sheet");
449  if (lst.count() <= 0)
450  {
451  ARCSLog::logError(logSource(processNode.lineNumber()),"\"process\" tag does not contain any \"sheets\" tag.");
452  return false;
453  }
454 
455  for (int i=0; i< lst.count(); i++)
456  {
457  ARCSSheet sh(ap->getContext());
458  if (!parseSheet(&sh,lst.at(i).toElement()))
459  {
460  ARCSLog::logError(logSource(lst.at(i).lineNumber()), "failed to parse sheet.");
461  return false;
462  }
464  ap->addSheet(sh.getName(),sh);
465  }
466 
467  return true;
468 }
469 
470 
471 bool ARCSXMLHandler::parseProfile(ARCSContext* ctx)
472 {
473  QDomElement app = doc.documentElement();
474 
475  if (app.tagName() != "profile")
476  {
477  ARCSLog::logError(logSource(doc.documentElement().lineNumber()),"\"profile\" tag expected.");
478  return false;
479  }
480 
481  parseContextElement(app, ctx, "constant", &ARCSContext::modifyConstant );
482  return true;
483 }
484 
485 
486 
487 bool ARCSXMLHandler::parseApplication(ARCSApplicationComponent* aac)
488 {
489  QDomElement app = doc.documentElement();
490 
491  if (app.tagName() != "application")
492  {
493  ARCSLog::logError(logSource(doc.documentElement().lineNumber()),"\"application\" tag expected.");
494  return false;
495  }
496 
497  if (app.hasAttribute("mode") && aac->getCurrentMode() == ARCS::ARCS_APP_NONE)
498  {
499  QString mode = app.attribute("mode").toLower();
500 
501  if (mode == "base")
503  else
504  if (mode == "thread")
506  else
507  if (mode == "threadevent")
509  else
510  if (mode == "gui")
512  else
514  }
515 
516  ARCSProcess* process0 = new ARCSProcess();
517  process0->setApplicationMode(aac->getCurrentMode());
518  ARCSContext* context = aac->getContext();
519 
520  if (!parseContext(context))
521  {
522  ARCSLog::logError(logSource(),"could not parse context.");
523  return false;
524  }
525 
526  QDomNodeList lst = doc.elementsByTagName(QString("process"));
527  if (lst.count() <= 0)
528  {
529  ARCSLog::logError(logSource(),"undefined \"process\" tag for application.");
530  return false;
531  }
532 
533  ARCSProcess* process;
534 
535  for (int i=0; i < lst.count(); i++)
536  {
537  if (i != 0)
538  process = new ARCSProcess();
539  else
540  process = process0;
541  process->setContext(context);
542  if (!parseProcess(process, lst.at(i).toElement()))
543  {
544  ARCSLog::logError(logSource(lst.at(i).lineNumber()),"could not parse \"process\" tag.");
545  return false;
546  }
547  aac->addProcess(process);
548  }
549 
550  return true;
551 }
552 
553 
554 
555 bool ARCSXMLHandler::parseCompositeComponent(ARCSCompositeComponent* acc)
556 {
557  QDomElement cmp = doc.documentElement();
558 
559  if (cmp.tagName() != "composite")
560  {
561  ARCSLog::logError(logSource(doc.documentElement().lineNumber()),"\"composite\" tag expected.");
562  return false;
563  }
564 
565  ARCSContext* context= new ARCSContext();
566  if (!parseContext(context))
567  {
568  ARCSLog::logError(logSource(),"could not parse context.");
569  return false;
570  }
571 
572  QDomNodeList lst = doc.elementsByTagName(QString("sheet"));
573 
574  if (lst.count() != 1)
575  {
576  ARCSLog::logError(logSource(lst.at(1).lineNumber()),"wrong number of sheets in composite component.");
577  return false;
578  }
579 
580  QDomElement sheetNode = lst.at(0).toElement();
581  ARCSSheet sheet(context);
582 
583  parseSheet(&sheet, sheetNode);
584  acc->setSheet(sheet);
585 
586  QDomNodeList _lst2 = doc.elementsByTagName(QString("interface"));
587  if (_lst2.count() != 1)
588  {
589  ARCSLog::logWarning(logSource(_lst2.at(1).lineNumber()),"wrong number of interfaces in composite component.");
590  return true;
591  }
592 
593  QDomElement ifNode = _lst2.at(0).toElement();
594 
595  if (!parseInterface(acc, ifNode))
596  {
597  ARCSLog::logError(logSource(ifNode.lineNumber()),"could not parse \"interface\" tag.");
598  return false;
599  }
600  return true;
601 }
602 
603 
605 {
606  QDomElement root;
607  int i ,j ;
608 
609  if (node.isNull())
610  root = doc.documentElement();
611  else
612  if (node.isElement())
613  root = node.toElement();
614 
615  if (root.tagName() != "interface")
616  {
617  ARCSLog::logError(logSource(root.lineNumber()),"\"interface\" tag expected.");
618  return false;
619  }
620 
621  QStringList signalAliases ;
622  QStringList slotAliases;
623  QStringList sourceComponents;
624  QStringList destinationComponents ;
625  QStringList signalMethods ;
626  QStringList slotMethods;
627 
628  QDomNodeList dnl = root.childNodes();
629  for (i = 0; i < dnl.count(); i++)
630  {
631  QDomElement elt = dnl.at(i).toElement();
632  if (elt.tagName() == "signals")
633  parseMethodList(elt, signalAliases, sourceComponents, signalMethods);
634 
635  if (elt.tagName() == "slots")
636  parseMethodList(elt, slotAliases, destinationComponents, slotMethods);
637  }
638 
639 
640  ARCSCompositeComponent* acc = dynamic_cast<ARCSCompositeComponent*>(aac);
641 
642  if (acc != 0)
643  {
644  if (signalAliases.count() != sourceComponents.count() )
645  {
646  ARCSLog::logError(logSource(),"signal count mismatch.");
647  return false;
648  }
649 
650  if (slotAliases.count() != destinationComponents.count())
651  {
652  ARCSLog::logError(logSource(),"slot count mismatch.");
653  return false;
654  }
655 
656  for (j=0; j < signalAliases.count(); j++)
657  acc->addProxySignal(signalAliases.at(j), sourceComponents.at(j), signalMethods.at(j));
658 
659  for (j=0; j < slotAliases.count(); j++)
660  acc->addProxySlot(slotAliases.at(j), destinationComponents.at(j), slotMethods.at(j));
661 
662  }
663  else
664  return false;
665 
666  return true;
667 }
668 
669 
670 
671 void ARCSXMLHandler::parseMethodList(QDomElement elt, QStringList & aliases, QStringList & components, QStringList & methods)
672 {
673  QDomNodeList list = elt.childNodes();
674 
675  aliases.clear();
676  components.clear();
677  methods.clear();
678 
679  for(int i = 0; i< list.count(); i++)
680  {
681  if (list.at(i).isElement())
682  {
683  QDomElement element = list.at(i).toElement();
684  if (element.tagName() == "method")
685  {
686  if (element.hasAttribute("alias"))
687  {
688  aliases << element.attribute("alias");
689  if (element.hasAttribute("component") && element.hasAttribute("method"))
690  {
691  components << element.attribute("component");
692  methods << element.attribute("method");
693  }
694  else
695  ARCSLog::logWarning(logSource(element.lineNumber()),"pure method detected.");
696  }
697  else
698  {
699  ARCSLog::logWarning(logSource(element.lineNumber()),"\"method\" tag is missing \"alias\" attribute.");
700  }
701  }
702  }
703  }
704 }
705 
706 void ARCSXMLHandler::parseContextElement(QDomElement elt, ARCSContext* ctx, QString tagName, ARCSContext::AddPoolMethod method)
707 {
708  if (! elt.hasChildNodes())
709  {
710  // uniquely used for constants.
711  ARCSLog::logWarning(logSource(elt.lineNumber()),"empty \"constants\" part");
712  return ;
713  }
714 
715  QDomNodeList list = elt.childNodes();
716 
717  for (int i=0; i < list.count(); i++)
718  {
719  if (list.at(i).isElement())
720  {
721  QDomElement e = list.at(i).toElement();
722  if (e.tagName() == tagName)
723  {
724  if (!e.hasAttribute("id") || !e.hasAttribute("type"))
725  {
726  ARCSLog::logWarning(logSource(e.lineNumber()),"\"constant\" tag is missing either \"id\" or \"type\" attributes.");
727  return ;
728  }
729  }
730 
731  QString id = e.attribute("id");
732  QString type = e.attribute("type");
733  QString contents = nodeInternalsToText(e);
734  if (!(ctx->*method)(id, type, contents))
735  ARCSLog::logWarning(logSource(e.lineNumber()),"could not parse \"constant\" tag.");
736  }
737  }
738 }
739 
740 
741 bool ARCSXMLHandler::parseComponents(QDomElement elt, ARCSContext* ctx)
742 {
743  if (! elt.hasChildNodes())
744  {
745  ARCSLog::logError(logSource(elt.lineNumber()),"empty \"component\" list.");
746  return false;
747  }
748 
749  QDomNodeList list = elt.childNodes();
750 
751  for (int i=0; i < list.count(); i++)
752  {
753  if (list.at(i).isElement())
754  {
755  QDomElement e = list.at(i).toElement();
756  if (e.tagName() == "component")
757  {
758  if (!e.hasAttribute("id") || !e.hasAttribute("type"))
759  {
760 
761  ARCSLog::logWarning(logSource(e.lineNumber()),
762  "\"component\" tag is missing either \"id\" of \"type\" attributes.");
763  return false;
764  }
765  QString id = e.attribute("id");
766  QString type = e.attribute("type");
767  QString filename = solveRelativePath(e.attribute("file"));
768  if (! filename.isEmpty())
769  {
770  ARCSAbstractComponent* aac = ctx->createComponent(id,type);
771  if (!aac)
772  {
773  ARCSLog::logError(logSource(e.lineNumber()),
774  "could not create component with id "+id +" and type "+type) ;
775  return false;
776  }
777  aac->setProperty("filename",filename);
778  if (QFileInfo(filename).exists())
779  {
780  if (!aac->loadFile(filename))
781  ARCSLog::logWarning(logSource(e.lineNumber()),
782  "failed to parse component.");
783  }
784  else
785  {
786  ARCSLog::logError(logSource(e.lineNumber()),
787  "component description "+ filename + " not found.");
788  }
789  //pathStack.popPath();
790  }
791  else
792  {
793  QString contents = nodeInternalsToText(e);
794  if (!ctx->addComponent(id,type,contents))
795  ARCSLog::logWarning(logSource(e.lineNumber()),
796  "could not parse component.");
797  }
798  }
799  }
800  }
801  return true;
802 }
803 
804 void ARCSXMLHandler::computeRelativePaths(QString basePath)
805 {
806  QFileInfo fi1(basePath);
807  QDir dir;
808 
809  if (fi1.isDir())
810  dir = QDir();
811  else
812  dir = fi1.absoluteDir();
813 
814  // here fileAttributes should have absolute path value.
815  for (int i=0; i < fileAttributes.count(); i++)
816  {
817  fileAttributes[i].setValue(
818  dir.relativeFilePath(
819  QFileInfo(fileAttributes[i].value()).absoluteFilePath()
820  )
821  );
822  }
823 }
824 
825 QString ARCSXMLHandler::solveRelativePath(QString path)
826 {
827  if (path.isEmpty())
828  return QString::null;
829 
830  if (fileName.isEmpty())
831  return path;
832 
833  if (QFileInfo(path).isAbsolute())
834  return path;
835 
836  QFileInfo fi1(fileName);
837  QDir dir;
838 
839  if (fi1.isDir())
840  dir = QDir();
841  else
842  dir = fi1.absoluteDir();
843 
844  return QDir::cleanPath(dir.absoluteFilePath(path));
845 }
846 
847 
848 void ARCSXMLHandler::storeSheet(ARCSSheet* sheet,QDomElement father, QString id)
849 {
850  int i,j;
851 
852  bool bPres,bPosts, bCons, bCleanups;
853  bPres = bPosts = bCons = bCleanups = false;
854 
855  QDomElement sheetNode = doc.createElement("sheet");
856  QDomElement pres = doc.createElement("preconnections");
857  QDomElement posts = doc.createElement("postconnections");
858  QDomElement cons = doc.createElement("connections");
859  QDomElement cleanups = doc.createElement("cleanups");
860 
861  if (!id.isEmpty())
862  sheetNode.setAttribute("id",id);
863 
864  QStringList sources;
865  QStringList sgnls;
866  QStringList destinations;
867  QStringList slts;
868 
869 
870  storeSheetProperties(sheet,sheetNode);
871  bPres = storeInvocations(sheet, &ARCSSheet::getPreconnects, pres);
872  bPosts = storeInvocations(sheet, &ARCSSheet::getPostconnects, posts);
873  bCleanups = storeInvocations(sheet, &ARCSSheet::getCleanups, cleanups);
874 
875  sheet->getConnections(sources, sgnls, destinations, slts);
876  bCons = sources.count() > 0;
877  for (i=0; i < sources.count(); i++)
878  {
879  QDomElement link = doc.createElement("link");
880  link.setAttribute("source", sources[i]);
881  link.setAttribute("destination", destinations[i]);
882  link.setAttribute("signal", sgnls[i]);
883  link.setAttribute("slot", slts[i]);
884  ARCSConnection &connection = sheet->getConnection(
885  sources[i],sgnls[i],destinations[i],slts[i]
886  );
887  QList<QPointF>& coords = connection.getCoordinates();
888  QStringList coordStrings;
889  if (coords.count() != 0)
890  {
891  for (j=0; j < coords.count(); j++)
892  coordStrings.append(QString::number(coords[j].x()) + "," + QString::number(coords[j].y()));
893  link.setAttribute("coords",coordStrings.join(" "));
894  }
895  cons.appendChild(link);
896 
897  }
898 
899 
900  father.appendChild(sheetNode);
901  if (bPres)
902  sheetNode.appendChild(pres);
903  if (bPosts)
904  sheetNode.appendChild(posts);
905  if (bCleanups)
906  sheetNode.appendChild(cleanups);
907 
908  sheetNode.appendChild(cons);
909 }
910 
911 
912 void ARCSXMLHandler::storeSheetProperties(ARCSSheet *sheet, QDomElement root)
913 {
914  QStringList propertyKeys = sheet->getPropertyList();
915  if (propertyKeys.count() <= 0)
916  return;
917 
918  QDomElement properties = doc.createElement("properties");
919  root.appendChild(properties);
920  for (int i=0; i<propertyKeys.count(); i++)
921  {
922  QDomElement property = doc.createElement("property");
923  property.setAttribute("id",propertyKeys[i]);
924  QDomText txt=doc.createTextNode(sheet->getProperty(propertyKeys[i]));
925  properties.appendChild(property);
926  property.appendChild(txt);
927  }
928 }
929 
930 
931 bool ARCSXMLHandler::storeInvocations(ARCSSheet* sheet,
932  ARCSSheet::GetInvocationsMethod method,
933  QDomElement root)
934 {
935  QStringList destinations;
936  QStringList slts;
937  QStringList types;
938  QStringList values;
939  int i;
940 
941  (sheet->*method)(destinations, slts, types, values);
942 
943  if (destinations.count() <= 0)
944  return false;
945 
946  for (i=0; i < destinations.count(); i++)
947  {
948  QDomElement invoke = doc.createElement("invoke");
949  if (! values[i].isEmpty())
950  {
951  QDomText txt = doc.createTextNode(values[i]);
952  invoke.appendChild(txt);
953  }
954  invoke.setAttribute("destination", destinations[i]);
955  invoke.setAttribute("slot", slts[i]);
956  invoke.setAttribute("type", types[i]);
957  root.appendChild(invoke);
958  }
959  return true;
960 }
961 
962 
963 void ARCSXMLHandler::storeStateMachine(ARCSStateMachine* sm)
964 {
965  type = XML_STATEMACHINE;
966 
967  QDomElement smNode = doc.createElement("statemachine");
968  QDomElement trsNode = doc.createElement("transitions");
969 
970  doc.appendChild(smNode);
971  smNode.appendChild(trsNode);
972 
973  QDomElement fstNode = doc.createElement("first");
974  fstNode.setAttribute("name", sm->getFirstSheetName());
975  smNode.appendChild(fstNode);
976 
977 
978  if (!sm->getLastSheetName().isEmpty())
979  {
980  QDomElement lstNode = doc.createElement("last");
981  lstNode.setAttribute("name", sm->getLastSheetName());
982  smNode.appendChild(lstNode);
983  }
984 
985 
986  QStringList sources;
987  QStringList tokens;
988  QStringList destinations;
989  sm->getTransitions(sources, tokens, destinations);
990 
991  for (int i=0; i < sources.count(); i++)
992  {
993  QDomElement trNode = doc.createElement("transition");
994  trNode.setAttribute("source",sources[i]);
995  trNode.setAttribute("token", tokens[i]);
996  trNode.setAttribute("destination", destinations[i]);
997  trsNode.appendChild(trNode);
998  }
999 }
1000 
1001 
1002 void ARCSXMLHandler::storeProfile(ARCSContext* ctx)
1003 {
1004  type = XML_PROFILE ;
1005 
1006  QDomElement app = doc.createElement("profile");
1007  doc.appendChild(app);
1008 
1009  QStringList lst = ctx->getConstantList();
1010 
1011  for (int i=0; i < lst.count(); i++)
1012  {
1013  QDomElement cstNode = doc.createElement("constant");
1014  QString t,r;
1015 
1016  if (ctx->serializeConstant(lst[i],t,r))
1017  {
1018  cstNode.setAttribute("id",lst[i]);
1019  cstNode.setAttribute("type",t);
1020 
1021  QDomText cstTxt = doc.createTextNode(r);
1022  cstNode.appendChild(cstTxt);
1023  app.appendChild(cstNode);
1024  }
1025  }
1026 }
1027 
1028 
1029 void ARCSXMLHandler::storeContext(ARCSContext* ctx)
1030 {
1031  int i;
1032 
1033  QDomElement ctxNode = doc.createElement("context");
1034  QDomElement libsNode = doc.createElement("libraries");
1035  QDomElement cmpsNode = doc.createElement("components");
1036  QDomElement cstsNode = doc.createElement("constants");
1037 
1038 
1039  QStringList lst = ctx->getComponentList();
1040 
1041  for (i=0; i < lst.count(); i++)
1042  {
1043  QDomElement cmpNode = doc.createElement("component");
1044  ARCSAbstractComponent* aac = ctx->getComponent(lst[i]);
1045  cmpNode.setAttribute("id",lst[i]);
1046  cmpNode.setAttribute("type",aac->getType());
1047 
1048  QString filename = aac->getProperty("filename").toString();
1049  if (filename.isEmpty() || QFileInfo(filename).isRelative())
1050  {
1051  // very dirty hack. I still do not know if it works.
1052  QDomDocument cmpTMP;
1053  if (cmpTMP.setContent(aac->toString()))
1054  cmpNode.appendChild(cmpTMP);
1055  else
1056  cmpNode.appendChild(doc.createTextNode(aac->toString()));
1057  // end of hack
1058  }
1059  else
1060  {
1061  QDomAttr fAttr = doc.createAttribute("file");
1062  fAttr.setValue(filename);
1063  //cmpNode.appendChild(fAttr);
1064  cmpNode.setAttributeNode(fAttr);
1065  fileAttributes.push_back(fAttr);
1066  }
1067 
1068  cmpsNode.appendChild(cmpNode);
1069  }
1070 
1071  lst = ctx->getConstantList();
1072 
1073  for (i=0; i < lst.count(); i++)
1074  {
1075  QDomElement cstNode = doc.createElement("constant");
1076  QString t,r;
1077 
1078  if (ctx->serializeConstant(lst[i],t,r))
1079  {
1080  cstNode.setAttribute("id",lst[i]);
1081  cstNode.setAttribute("type",t);
1082 
1083  QDomText cstTxt = doc.createTextNode(r);
1084  cstNode.appendChild(cstTxt);
1085  cstsNode.appendChild(cstNode);
1086  }
1087  }
1088 
1089  lst = ctx->computeLibraryList();
1090 
1091  for (i=0; i < lst.count(); i++)
1092  {
1093  QDomElement libNode = doc.createElement("library");
1094 
1095  //QString relPath = pushPath?pathStack.relativePath(lst[i]):lst[i];
1096  //libNode.setAttribute("path",relPath);
1097  QDomAttr fAttr = doc.createAttribute("path");
1098  fAttr.setValue(lst[i]);
1099  //libNode.appendChild(fAttr);
1100  libNode.setAttributeNode(fAttr);
1101  fileAttributes.push_back(fAttr);
1102  libsNode.appendChild(libNode);
1103  }
1104 
1105  ctxNode.appendChild(libsNode);
1106  ctxNode.appendChild(cmpsNode);
1107  ctxNode.appendChild(cstsNode);
1108  doc.documentElement().appendChild(ctxNode);
1109 }
1110 
1111 
1112 
1113 void ARCSXMLHandler::storeApplication(ARCSApplicationComponent* aac)
1114 {
1115  type = XML_APPLICATION ;
1116 
1117  QDomElement app = doc.createElement("application");
1118  doc.appendChild(app);
1119 
1120  switch(aac->getCurrentMode())
1121  {
1122  case ARCS::ARCS_APP_BASE:
1123  app.setAttribute("mode","base");
1124  break;
1125  case ARCS::ARCS_APP_THREAD:
1126  app.setAttribute("mode","thread");
1127  break;
1129  app.setAttribute("mode", "threadevent");
1130  break;
1131  case ARCS::ARCS_APP_GUI:
1132  app.setAttribute("mode", "gui");
1133  break;
1134  default:
1135  app.setAttribute("mode", "event");
1136 
1137  }
1138 
1139  storeContext(aac->getContext());
1140 
1141  QDomElement prcs = doc.createElement("processes");
1142  app.appendChild(prcs);
1143  int nProc = aac->getProcessCount();
1144 
1145  for (int i = 0; i < nProc; i++)
1146  storeProcess(aac->getProcess(i), prcs);
1147 }
1148 
1149 
1150 void ARCSXMLHandler::storeProcess(ARCSProcess* proc,QDomElement father)
1151 {
1152  QDomElement process = doc.createElement("process");
1153 
1154  process.setAttribute("controller", proc->getControllerId());
1155 
1156  QStringList sheetNames = proc->getSheetNames();
1157 
1158  for(int i=0; i< sheetNames.count(); i++)
1159  {
1160  ARCSSheet& as = proc->getSheet(sheetNames[i]);
1161  storeSheet(&as,process,sheetNames[i]);
1162  }
1163  father.appendChild(process);
1164 }
1165 
1166 
1167 
1168 void ARCSXMLHandler::storeCompositeComponent(ARCSCompositeComponent* acc)
1169 {
1170  type = XML_COMPOSITE;
1171 
1172  QDomElement composite = doc.createElement("composite");
1173  doc.appendChild(composite);
1174 
1175  ARCSContext ctx = acc->getContext();
1176 
1177  storeContext(&ctx);
1178 
1179  storeSheet( acc->getSheet(), composite);
1180 
1181  storeInterface( acc, composite);
1182 }
1183 
1186 {
1187  int i;
1188 
1189  QDomElement interfaceARCS = doc.createElement("interface");
1190  elt.appendChild(interfaceARCS);
1191 
1192  ARCSCompositeComponent* acc = dynamic_cast<ARCSCompositeComponent*>(aac);
1193  if (acc != NULL)
1194  {
1195 
1196  QStringList signalNames;
1197  QStringList slotNames;
1198  QStringList methodNames;
1199  QStringList componentNames;
1200  acc->getProxySignals(methodNames, componentNames, signalNames);
1201  if (methodNames.count() == componentNames.count() &&
1202  methodNames.count() == signalNames.count())
1203  {
1204  QDomElement signalRoot = doc.createElement("signals");
1205  interfaceARCS.appendChild(signalRoot);
1206  for (i=0; i< methodNames.count(); i++)
1207  {
1208  QDomElement method = doc.createElement("method");
1209  method.setAttribute("alias",methodNames[i]);
1210  method.setAttribute("component", componentNames[i]);
1211  method.setAttribute("method",signalNames[i]);
1212  signalRoot.appendChild(method);
1213  }
1214  }
1215 
1216  acc->getProxySlots(methodNames, componentNames, slotNames);
1217  if (methodNames.count() == componentNames.count() &&
1218  methodNames.count() == slotNames.count())
1219  {
1220  QDomElement slotRoot = doc.createElement("slots");
1221  interfaceARCS.appendChild(slotRoot);
1222  for (i=0; i< methodNames.count(); i++)
1223  {
1224  QDomElement method = doc.createElement("method");
1225  method.setAttribute("alias",methodNames[i]);
1226  method.setAttribute("component", componentNames[i]);
1227  method.setAttribute("method",signalNames[i]);
1228  slotRoot.appendChild(method);
1229  }
1230  }
1231  }
1232 }
1233 
1234 
1235 void ARCSXMLHandler::reset()
1236 {
1237  libraryStrings.clear();
1238 }
1239 
1240 
1241 
1242 
1243 QString ARCSXMLHandler::nodeInternalsToText(QDomNode node)
1244 {
1245  QString res;
1246 
1247  QTextStream ts(&res);
1248 
1249  if (node.hasChildNodes())
1250  {
1251  QDomNodeList children = node.childNodes();
1252  for (int i = 0 ; i < children.count() ; i++)
1253  ts << children.at(i) ;
1254  }
1255 
1256  return res;
1257 }
1258 
1259 
void getProxySignals(QStringList &proxies, QStringList &objects, QStringList &signalNames)
void storeInterface(ARCSAbstractComponent *aac, QDomElement father=QDomElement())
XML representation of a statemachine.
QStringList getSheetNames()
Definition: arcsprocess.h:94
bool setContents(QString s)
Gives the content to parse.
void getProxySlots(QStringList &proxies, QStringList &objects, QStringList &slotNames)
ARCSInit & addCleanup(QString dst, QString slt, QString t, QString val)
Adds a cleanup invocation to the sheet structure.
Definition: arcssheet.h:98
Class defining a composite component i.e. a component made of components.
bool serializeConstant(QString name, QString &type, QString &representation)
Serializes constants.
XML representation of an application.
virtual QString toString()=0
Defines a basic seralization mechanism.
For applications running with Qt Widgets.
Definition: arcs.h:48
bool parseInterface(ARCSAbstractComponent *aac, QDomNode node=QDomNode())
bool parseContext(ARCSContext *)
Parses a context.
void setSheet(ARCSSheet ref)
Sets the sheet to use as an internal description of embedded components.
QString getProperty(QString name)
Definition: arcssheet.h:216
This class represents an application.
bool addProxySlot(QString proxy, QString id, QString slot)
Adds a wrapper to an internal component and its slot.
This class is representing a process under ARCS.
Definition: arcsprocess.h:52
QString getFirstSheetName()
Returns the name of the first state activated in the statemachine.
void setCurrentMode(ARCS::ARCSAppFlag flag)
QStringList getComponentList()
bool modifyConstant(QString name, QString representation)
Modifies a constant of the list.
ARCSSheet * getSheet()
Returns the internal structure of this composite component described as a sheet.
bool openFile(QString s)
Opens a file given its path. The file should describe either an application or a composite component...
ARCSInit & addPreconnect(QString dst, QString slt, QString t, QString val)
Adds a pre-connection initialisation to the sheet structure.
Definition: arcssheet.h:76
bool addComponent(QString name, QString className, QString contents=QString::null)
Adds a component to the list.
QStringList getPropertyList()
Definition: arcssheet.h:237
void setContext(ARCSContext *ctx)
Definition: arcsprocess.h:61
static ARCSFactory * getInstance()
Returns the instance of the singleton ARCSFactory.
XML representation of a composite component.
Describes a connection.
void setApplicationMode(ARCS::ARCSAppFlag flag)
Definition: arcsprocess.h:109
None of the application mode has been selected so far.
Definition: arcs.h:43
void setProperty(QString name, QString value)
Definition: arcssheet.h:214
bool setController(QString s=QString::null)
void addProcess(ARCSProcess *ap)
ARCSContext getContext()
Returns the internal context of the composite component.
QVariant getProperty(QString name)
Gets a meta-property from this component.
ARCS::ARCSAppFlag getCurrentMode()
For applications nested in a thread.
Definition: arcs.h:46
void getCleanups(QStringList &destinations, QStringList &slts, QStringList &types, QStringList &values)
Allows to retrieve cleanup invocations.
Definition: arcssheet.h:176
Class handling the generic description of a component.
ARCSContext * getContext()
Definition: arcsprocess.h:138
virtual bool loadFile(QString fn)
Defines a way to load a component description from a file.
XML representation of a profile.
void storeSheet(ARCSSheet *as, QDomElement father, QString id=QString::null)
Stores the xml description of a sheet.
QString getLastSheetName()
Returns the name of the last state activated in the statemachine.
void setFirstSheetName(QString s)
Sets the name of the first sheet i.e. the starting node of the statemachine.
ARCSAbstractComponent * getComponent(QString name)
Retrieves a component by its id.
void getConnections(QStringList &sources, QStringList &signls, QStringList &destinations, QStringList &slts)
Allows to retrieve connections.
Definition: arcssheet.cpp:248
bool parseProcess(ARCSProcess *ap, QDomElement processNode)
Parses the xml description of a process.
void getPostconnects(QStringList &destinations, QStringList &slts, QStringList &types, QStringList &values)
Allows to retrieve postconnection invocations.
Definition: arcssheet.h:165
bool saveFile(QString s)
Saves a file given its path. The file will describe either an application or a composite component...
QStringList computeLibraryList()
Definition: arcscontext.cpp:65
ARCSXMLHandler()
Constructor.
This class manages components and constants in a given context.
Definition: arcscontext.h:45
ARCSConnection & addConnection(QString src, QString sgn, QString dst, QString slt, bool q=false, bool head=false)
Adds a connection to the sheet structure.
Definition: arcssheet.cpp:183
QStringList getConstantList()
Definition: arcscontext.cpp:95
bool loadLibrary(QString path)
Loads a library given the path to it.
void reset()
Resets the component and constant lists.
bool parseSheet(ARCSSheet *as, QDomElement father)
Parses the xml descriptions of a sheet.
ARCSProcess * getProcess(int idx)
Class describing a state machine in order to control an application.
void setProperty(QString name, QVariant value)
Sets a meta-property on this component.
void setName(QString s)
Definition: arcssheet.h:244
ARCSConnection & getConnection(QString source, QString sgn, QString dst, QString slt)
returns a reference to a connection in the sheet structure
Definition: arcssheet.cpp:206
ARCSInit & addPostconnect(QString dst, QString slt, QString t, QString val)
Adds a post-connection initialisation to the sheet structure.
Definition: arcssheet.h:87
ARCSSheet & getSheet(QString s)
Definition: arcsprocess.h:86
For applications nested in a thread running with an event loop.
Definition: arcs.h:47
For applications requiring event loops.
Definition: arcs.h:45
Maintains connections between objects.
Definition: arcssheet.h:48
void getPreconnects(QStringList &destinations, QStringList &slts, QStringList &types, QStringList &values)
Allows to retrieve preconnection invocations.
Definition: arcssheet.h:154
bool addProxySignal(QString proxy, QString id, QString signal)
Adds a wrapper to an internal component and its signal.
For basic applications.
Definition: arcs.h:44
void setLastSheetName(QString s)
Sets the name of the last sheet i.e. the node ending the statemachine.
QString getControllerId()
Definition: arcsprocess.h:96
void addSheet(QString s, ARCSSheet sh)