arcsabstractcomponent.cpp
1 /*
2  name: lib/arcsabstractcomponent.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/arcsabstractcomponent.h>
30 #include <arcs/arcsqdynamicobject.h>
31 #include <arcs/arcsfactory.h>
32 #include <QtDebug>
33 #include <iostream>
34 #include <QFile>
35 #include <QTextStream>
36 #include <QMetaObject>
37 
38 
39 const QString ARCSAbstractComponent::slotPrefix = "1" ;
40 const QString ARCSAbstractComponent::signalPrefix = "2" ;
41 
42 
43 ARCSAbstractComponent::ARCSAbstractComponent()
44 {
45  instanciated =false;
46 }
47 
48 ARCSAbstractComponent::~ARCSAbstractComponent()
49 {
50 }
51 
52 
54 {
56  res->parseString(this->toString());
57 
58  if (res == 0)
59  return res;
60 
61  res->setType(this->getType());
62  res->setFamily(this->getFamily());
63 
64  QStringList lst = getProperties();
65 
66  for (int i = 0; i < lst.count(); i++)
67  {
68  res->setProperty(lst[i], this->getProperty(lst[i]));
69  }
70  return res;
71 }
72 
73 
75 {
76  QFile file(fn);
77 
78  if (! file.open(QIODevice::ReadOnly))
79  return false;
80 
81  QTextStream ts(&file);
82  QString contents = ts.readAll();
83  if (!parseString(contents))
84  return false;
85 
86  file.close();
87  return true;
88 }
89 
91 {
92  QFile file(fn);
93  if (!file.open(QIODevice::WriteOnly))
94  return false;
95 
96  QTextStream ts(&file);
97  QString contents = toString();
98  ts << contents ;
99  ts.flush();
100 
101  file.close();
102  return true;
103 }
104 
105 
106 void ARCSAbstractComponent::setProperty(QString name, QVariant value)
107 {
108  properties.insert(name, value);
109 }
110 
111 
113 {
114  QVariant prop;
115 
116  if (properties.contains(name))
117  prop = properties[name];
118 
119  return prop;
120 }
121 
122 
124 {
125  properties.remove(name);
126 }
127 
128 
130 {
131  properties.clear();
132 }
133 
134 
136 {
137  return properties.keys();
138 }
139 
140 
141 bool ARCSAbstractComponent::init(QString slt, QVariant* var)
142 {
143  if (!isInstanciated())
144  return false;
145 
146  QObjectList sources;
147  QStringList slotNames;
148  QString realName;
149  this->getProxySlot(slt, sources, slotNames);
150 
151  if (sources.isEmpty())
152  {
153  return false;
154  }
155 
156  bool res = true;
157 
158  for (int i=0; i < sources.size(); i++)
159  {
160  realName = slotNames[i].left(slotNames[i].indexOf('('));
161  // insérer des choses ici
162  ARCSQDynamicObject* ado = dynamic_cast<ARCSQDynamicObject*>(sources[i]);
163  if (ado)
164  {
165  int id = ado->prepareSlotConnect(slotNames[i], slotNames[i],QString::null, slotNames[i], false);
166  void * args[2];
167  args[0] = 0;
168  args[1] = var->data();
169 
170  ado->qt_metacall(QMetaObject::InvokeMetaMethod, id, args);
171  ado->cleanSlotConnect(slotNames[i], slotNames[i], QString::null, slotNames[i]);
172  res = res && true;
173 
174  }
175  else
176  {
177  res = res && QMetaObject::invokeMethod(sources[i], qPrintable(realName),
178  Qt::DirectConnection,
179  QGenericArgument((var->typeName()),(var->data())) );
180  }
181  }
182  return res;
183 
184 }
185 
187 bool ARCSAbstractComponent::connect(QString sig, ARCSAbstractComponent* dst, QString slt, bool queued)
188 {
189  /* The lines below are a twisted hack around scripts */
190  /*if (this->getType() == "Script")
191  return genuineConnect(sig,dst,slt, false);
192  if (dst->getType() == "Script" )
193  return dst->genuineConnect(sig, this ,slt, true);*/
194  /* end of twisted hack */
195 
196  if ( this->getFamily() == dst->getFamily() )
197  if (genuineConnect(sig, dst, slt, queued))
198  return true;
199 
200  ObjectList sources;
201  ObjectList destinations;
202  QStringList signalNames;
203  QStringList slotNames;
204 
205  dst->getProxySlot(slt,destinations, slotNames);
206  this->getProxySignal(sig, sources, signalNames);
207 
208  if (sources.isEmpty() || destinations.isEmpty() )
209  return false;
210 
211  bool res = true;
212  int i,j;
213  Qt::ConnectionType contype = queued? Qt::QueuedConnection: Qt::DirectConnection ;
214 
215  for (i = 0; i < sources.size(); i++)
216  {
217  for (j = 0; j < destinations.size(); j++)
218  {
219  ARCSQDynamicObject* dynSrc = dynamic_cast<ARCSQDynamicObject*>(sources[i]);
220  ARCSQDynamicObject* dynDst = dynamic_cast<ARCSQDynamicObject*>(destinations[j]);
221 
222  if (dynSrc || dynDst)
223  {
224  int dynSltId ;
225  int dynSigId ;
226 
227  if (dynSrc)
228  {
229  dynSigId = dynSrc->prepareSignalConnect(signalNames[i], slotNames[j] , dst->getProperty("id").toString(), slt);
230  }
231  else
232  {
233  const QMetaObject* base = sources[i]->metaObject();
234  dynSigId = base->indexOfSignal(base->normalizedSignature(qPrintable(signalNames[i])));
235  }
236 
237  if (dynDst)
238  {
239  dynSltId = dynDst->prepareSlotConnect(signalNames[i], slotNames[j], this->getProperty("id").toString(), sig );
240  }
241  else
242  {
243  const QMetaObject* base = destinations[j]->metaObject();
244  dynSltId = base->indexOfSlot(base->normalizedSignature(qPrintable(slotNames[j])));
245  }
246 
247  if ( dynSigId == -1 || dynSltId == -1 )
248  return false;
249 
250  res = res && QMetaObject::connect(sources[i], dynSigId, destinations[j], dynSltId, contype );
251 
252  }
253  else
254  res = res && QObject::connect(sources[i], qPrintable(signalPrefix + signalNames[i]),
255  destinations[j], qPrintable(slotPrefix + slotNames[j]),
256  contype);
257  }
258  }
259  return res;
260 }
261 
262 
263 bool ARCSAbstractComponent::disconnect(QString sig, ARCSAbstractComponent* dst, QString slt)
264 {
265  /* The lines below are a twisted hack around scripts */
266  // this may not be needed anymore
267  /*if (this->getType() == "Script")
268  {
269  this->setProperty("destination", false);
270  return genuineDisconnect(sig,dst,slt);
271  }
272  if (dst->getType() == "Script" )
273  {
274  this->setProperty("destination", true);
275  return dst->genuineDisconnect(sig, this ,slt);
276  }*/
277  /* end of twisted hack */
278 
279  if (genuineDisconnect(sig, dst, slt))
280  return true;
281 
282 
283  ObjectList sources;
284  ObjectList destinations;
285  QStringList signalNames;
286  QStringList slotNames;
287 
288  dst->getProxySlot(slt,destinations, slotNames);
289  this->getProxySignal(sig, sources, signalNames);
290 
291  if (sources.isEmpty() || destinations.isEmpty() )
292  return false;
293 
294  bool res = true;
295  int i,j;
296 
297  for (i = 0; i < sources.size(); i++)
298  {
299  for (j = 0; j < destinations.size(); j++)
300  {
301  ARCSQDynamicObject* dynSrc = dynamic_cast<ARCSQDynamicObject*>(sources[i]);
302  ARCSQDynamicObject* dynDst = dynamic_cast<ARCSQDynamicObject*>(destinations[j]);
303 
304  if (dynSrc || dynDst)
305  {
306  int dynSltId ;
307  int dynSigId ;
308 
309  if (dynSrc)
310  {
311  dynSigId = dynSrc->cleanSignalConnect(signalNames[i], slotNames[j], this->getProperty("id").toString(), slt );
312  }
313  else
314  {
315  const QMetaObject* base = sources[i]->metaObject();
316  dynSigId = base->indexOfSignal(base->normalizedSignature(qPrintable(signalNames[i])));
317  }
318 
319  if (dynDst)
320  {
321  dynSltId = dynDst->cleanSlotConnect(signalNames[i], slotNames[j], dst->getProperty("id").toString(), sig );
322  }
323  else
324  {
325  const QMetaObject* base = destinations[j]->metaObject();
326  dynSltId = base->indexOfSlot(base->normalizedSignature(qPrintable(slotNames[j])));
327  }
328 
329  if ( dynSigId == -1 || dynSltId == -1 )
330  return false;
331 
332  res = res && QMetaObject::disconnect(sources[i], dynSigId, destinations[j], dynSltId );
333 
334  }
335  else
336  {
337  res = res && QObject::disconnect(sources[i], qPrintable(signalPrefix + signalNames[i]),
338  destinations[j], qPrintable(slotPrefix + slotNames[j]));
339  }
340  }
341  }
342  return res;
343 }
344 
345 
346 QStringList ARCS::getMethodList(const QMetaObject *object, QMetaMethod::MethodType type)
347 {
348  QStringList answer;
349 
350  for (int i=0; i < object->methodCount(); i++)
351  {
352  QMetaMethod mmo = object->method(i);
353  if (mmo.methodType() == type)
354 #if QT_VERSION >= 0x050000
355  answer << mmo.methodSignature();
356 #else
357  answer << mmo.signature();
358 #endif
359  }
360  return answer;
361 }
virtual int qt_metacall(QMetaObject::Call call, int id, void **arguments)=0
Method performing the actual callback task.
void removeProperty(QString name)
Removes a meta-property from this component.
bool disconnect(QString sig, ARCSAbstractComponent *dst, QString slt)
This method disconnects two components by the indicated signals and slots.
virtual QString toString()=0
Defines a basic seralization mechanism.
virtual void getProxySignal(QString signal, ObjectList &obj, QStringList &proxySignal)=0
Creates a proxy signal to interface a component to native ARCS components.
bool init(QString slt, QVariant *var)
Initializes a component.
virtual bool genuineDisconnect(QString, ARCSAbstractComponent *, QString)
This method disconnects two components by the indicated signals and slots.
virtual void getProxySlot(QString slot, ObjectList &obj, QStringList &proxySlot)=0
Creates a proxy slot to interface a component to native ARCS components.
virtual int prepareSignalConnect(QString sigName, QString sltName, QString objectName, QString actualSlot, bool simulate=false)=0
Prepares a connection with a slot which does not belong to this object.
ARCSAbstractComponent * clone()
Kage bunshin no jutsu !
static ARCSFactory * getInstance()
Returns the instance of the singleton ARCSFactory.
QVariant getProperty(QString name)
Gets a meta-property from this component.
Class handling the generic description of a component.
virtual bool loadFile(QString fn)
Defines a way to load a component description from a file.
QStringList getMethodList(const QMetaObject *object, QMetaMethod::MethodType type)
Helper method for components.
ARCSAbstractComponent * createComponent(QString componentType)
Creates a component given its class name.
virtual bool saveFile(QString fn)
Defines a way to save a component description inside a file.
Interface to extend QObject functionnalities in order to make objects with dynamic signals or slots...
void setProperty(QString name, QVariant value)
Sets a meta-property on this component.
virtual int cleanSignalConnect(QString signame, QString sltName, QString objectName, QString actualSlot)=0
virtual bool genuineConnect(QString, ARCSAbstractComponent *, QString, bool=false)
This method connects two components by the indicated signals and slots.
bool isInstanciated()
Determines wether the component is instanciated or not.
virtual bool parseString(QString s)=0
Defines a basic seralization mechanism.
void resetProperties()
Sets the property list to a blank list.
virtual int cleanSlotConnect(QString sigName, QString sltName, QString objectName, QString actualSignal)=0
virtual bool connect(QString sig, ARCSAbstractComponent *dst, QString slt, bool queued=false)
This method connects two components by the indicated signals and slots.
virtual int prepareSlotConnect(QString sigName, QString sltName, QString objectName, QString actualSignal, bool simulate=false)=0
Prepares a connection with a slot which is belonging to this object.