NCL Composer  0.1.5
 All Classes Functions Variables Pages
MessageControl.cpp
1 /* Copyright (c) 2011 Telemidia/PUC-Rio.
2  * All rights reserved. This program and the accompanying materials
3  * are made available under the terms of the Eclipse Public License v1.0
4  * which accompanies this distribution, and is available at
5  * http://www.eclipse.org/legal/epl-v10.html
6  *
7  * Contributors:
8  * Telemidia/PUC-Rio - initial API and implementation
9  */
10 #include "modules/MessageControl.h"
11 #include "modules/PluginControl.h"
12 
13 #include <QMetaObject>
14 #include <QMetaMethod>
15 #include <QApplication>
16 
17 #include "util/Commands.h"
18 
19 namespace composer {
20 namespace core {
21 
23 {
24  this->project = project;
25 
26  //Register MetaType allowing to be used by invoke
27  qRegisterMetaType<void *>("Entity *");
28 
29  qUndoStack = new QUndoStack(this);
30 }
31 
33 {
34 
35 }
36 
38  QString parentEntityId,
39  QMap<QString,QString>& atts,
40  bool force,
41  bool notifyPlugins)
42 {
43  Entity *ent = NULL;
44 
45  try
46  {
47  ent = new Entity(atts);
48  ent->setType(type);
49  //TODO - calll validator to check
50  project->addEntity(ent, parentEntityId);
51 
52  //send message to All PLUGINS interested in this message.
53  if(notifyPlugins)
54  sendEntityAddedMessageToPlugins("", ent);
55  }
56  catch(exception& e)
57  {
58  delete ent;
59  ent = NULL;
60 
61  return;
62  }
63 }
64 
66  QString parentEntityId,
67  bool force,
68  bool notifyPlugins)
69 {
70  try
71  {
72  // \todo call validator to check
73  project->addEntity(entity, parentEntityId);
74 
75  //send message to All PLUGINS interested in this message.
76  if(notifyPlugins)
77  sendEntityAddedMessageToPlugins("", entity);
78  }
79  catch(exception& e)
80  {
81  // \todo notify error
82  return;
83  }
84 }
85 
86 void MessageControl::anonymousRemoveEntity( QString entityUniqueId, bool force,
87  bool notifyPlugins)
88 {
89  try
90  {
91  Entity *entity = project->getEntityById(entityUniqueId);
92  if(entity != NULL)
93  {
94  //send message to All PLUGINS interested in this message.
95  if(notifyPlugins)
96  sendEntityRemovedMessageToPlugins("", entity);
97 
98  QApplication::processEvents();
99  // \todo call validator to check
100  project->removeEntity(entity, false);
101  }
102  }
103  catch(exception& e)
104  {
105  // \todo notify error
106  return;
107  }
108 }
109 
111  QMap<QString,QString>& atts,
112  bool force,
113  bool notifyPlugins)
114 {
115  Entity *ent = project->getEntityById(entityId);
116  if(ent != NULL)
117  {
118  ent->setAtrributes(atts); //do it!
119 
120  //send message to All PLUGINS interested in this message.
121  if(notifyPlugins)
122  sendEntityChangedMessageToPlugins("", ent);
123  }
124 }
125 
127 {
128  QList<IPlugin*>::iterator it;
129  QList<IPlugin*> instances =
130  PluginControl::getInstance()->getPluginInstances(this->project);
131 
132  QString slotName("updateFromModel()");
133  for (it = instances.begin(); it != instances.end(); it++)
134  {
135  IPlugin *inst = *it;
136  int idxSlot = inst->metaObject()
137  ->indexOfSlot(slotName.toStdString().c_str());
138  if(idxSlot != -1)
139  {
140  QMetaMethod method = inst->metaObject()->method(idxSlot);
141  method.invoke(inst, Qt::DirectConnection);
142  }
143  }
144 }
145 
146 void MessageControl::onAddEntity( QString type, QString parentEntityId,
147  QMap<QString,QString>& atts, bool force)
148 {
149  /* Cast to IPlugin to make sure it's a plugin */
150  IPlugin *plugin = qobject_cast<IPlugin *> (QObject::sender());
151  IDocumentParser *parser = qobject_cast<IDocumentParser*>
152  (QObject::sender());
153  QString pluginID;
154 
155  if(plugin) pluginID = plugin->getPluginInstanceID();
156  else if (parser) pluginID = parser->getParserName();
157 
158  Entity *ent = NULL;
159 
160  try
161  {
162  ent = new Entity(atts);
163  ent->setType(type);
164  qUndoStack->push(new AddCommand(project, ent, parentEntityId));
165 
166  //send message to All PLUGINS interested in this message.
167  sendEntityAddedMessageToPlugins(pluginID, ent);
168  }
169  catch(exception& e)
170  {
171  if (plugin)
172  plugin->errorMessage(e.what());
173  else if (parser)
174  parser->onEntityAddError(e.what());
175 
176  delete ent;
177  ent = NULL;
178 
179  return;
180  }
181 }
182 
183 void MessageControl::onEditEntity(Entity *entity, QMap<QString,QString> atts,
184  bool force)
185 {
186  IPlugin *plugin = qobject_cast<IPlugin *>(QObject::sender());
187 
188  if(plugin) {
189  QString pluginID = plugin->getPluginInstanceID();
190 
191  try
192  {
193  qUndoStack->push(new EditCommand(project, entity, atts));
194 
196  entity->setAtrributes(atts); //do it!
197 
198  // send message to all plugins interested in this message.
199  sendEntityChangedMessageToPlugins(pluginID, entity);
200  }
201  catch(exception e)
202  {
203  plugin->errorMessage(e.what());
204  return;
205  }
206  } else {
207  //TODO -- erro on casting
208  return;
209  }
210 
211 }
212 
213 void MessageControl::onRemoveEntity(Entity *entity, bool force)
214 {
215  IPlugin *plugin = qobject_cast<IPlugin *> (QObject::sender());
216  if(plugin)
217  {
218  QString pluginID = plugin->getPluginInstanceID();
219  try
220  {
221  if(entity)
222  {
223  // Send message to all plugins interested in this message.
224  // This message is send before the real delete to try to avoid
225  // the plugins keep pointers to invalid memory location.
226  QList <Entity*> willBeRemoved;
227  QStack <Entity*> stack;
228 
229  //remove all children
233  stack.push(entity);
234  while(stack.size())
235  {
236  Entity *currentEntity = stack.top();
237 
238  // \fixme While sending messages to plugins it is possible that plugin
239  // itself remove the entity (and in future we could get a trash.
240  // That is the reason why we keep a clone here!!
241  willBeRemoved.push_back(currentEntity->cloneEntity());
242 
243  stack.pop();
244 
245  QVector <Entity *> children = currentEntity->getChildren();
246  for(int i = 0; i < children.size(); i++)
247  {
248  stack.push(children.at(i));
249  }
250  }
251 
256  for(int i = willBeRemoved.size()-1; i >= 0; i--)
257  {
258  sendEntityRemovedMessageToPlugins(pluginID, willBeRemoved[i]);
259 
260  delete willBeRemoved[i]; // We do not need it anymore!!!
261  }
262 
263 // This function will release the entity instance and its children
264  // \fixme Since the plugin itself could already removed entity we can
265  // get a trash here!!!
266  qUndoStack->push(new RemoveCommand(project, entity));
267 // project->removeEntity(entity, true);
268  }
269  else
270  {
271  plugin->errorMessage(tr("You have tried to remove a NULL entity!!"));
272  }
273  }
274  catch(exception e)
275  {
276  plugin->errorMessage(e.what());
277  return;
278  }
279  }
280  else
281  {
284  return;
285  }
286 }
287 
288 void MessageControl::setListenFilter(QStringList entityList)
289 {
290  IPlugin *plugin = qobject_cast<IPlugin *> (QObject::sender());
291  if(plugin)
292  {
293  listenEntities[plugin->getPluginInstanceID()] = entityList;
294  }
295 }
296 
297 /*
298  * \todo The implementation of the folling three implementations should be
299  * merged into only one function.
300  */
301 void MessageControl::sendEntityAddedMessageToPlugins( QString pluginInstanceId,
302  Entity *entity)
303 {
304  QList<IPlugin*>::iterator it;
305  QList<IPlugin*> instances =
306  PluginControl::getInstance()->getPluginInstances(this->project);
307 
308  QString slotName("onEntityAdded(QString,Entity*)");
309 
310  for (it = instances.begin(); it != instances.end(); it++)
311  {
312  IPlugin *inst = *it;
313 
314  if(pluginIsInterestedIn(inst, entity))
315  {
316  int idxSlot = inst->metaObject()
317  ->indexOfSlot(slotName.toStdString().c_str());
318  if(idxSlot != -1)
319  {
320  QMetaMethod method = inst->metaObject()->method(idxSlot);
321  method.invoke(inst, Qt::DirectConnection,
322  Q_ARG(QString, pluginInstanceId),
323  Q_ARG(Entity*, entity));
324  }
325  }
326  }
327 
328  emit entityAdded(pluginInstanceId, entity);
329 }
330 
331 
332 void MessageControl::sendEntityChangedMessageToPlugins(QString pluginInstanceId,
333  Entity *entity)
334 {
335  QList<IPlugin*>::iterator it;
336  QList<IPlugin*> instances =
337  PluginControl::getInstance()->getPluginInstances(this->project);
338 
339  QString slotName("onEntityChanged(QString,Entity*)");
340 
341  for (it = instances.begin(); it != instances.end(); it++)
342  {
343  IPlugin *inst = *it;
344 
345  if(pluginIsInterestedIn(inst, entity))
346  {
347  int idxSlot = inst->metaObject()
348  ->indexOfSlot(slotName.toStdString().c_str());
349  if(idxSlot != -1)
350  {
351  QMetaMethod method = inst->metaObject()->method(idxSlot);
352  method.invoke(inst, Qt::DirectConnection,
353  Q_ARG(QString, pluginInstanceId),
354  Q_ARG(Entity*, entity));
355  }
356  }
357  }
358 }
359 
360 void MessageControl::sendEntityRemovedMessageToPlugins(QString pluginInstanceId,
361  Entity *entity)
362 {
363  QList<IPlugin*>::iterator it;
364  QList<IPlugin*> instances =
365  PluginControl::getInstance()->getPluginInstances(this->project);
366 
367  QString slotName("onEntityRemoved(QString,QString)");
368  QString entityId = entity->getUniqueId();
369 
370  for (it = instances.begin(); it != instances.end(); it++)
371  {
372  IPlugin *inst = *it;
373 
374  if(pluginIsInterestedIn(inst, entity))
375  {
376  int idxSlot = inst->metaObject()
377  ->indexOfSlot(slotName.toStdString().c_str());
378  if(idxSlot != -1)
379  {
380  QMetaMethod method = inst->metaObject()->method(idxSlot);
381  method.invoke(inst, Qt::DirectConnection,
382  Q_ARG(QString, pluginInstanceId),
383  Q_ARG(QString, entityId));
384  }
385  }
386  }
387 }
388 
389 bool MessageControl::pluginIsInterestedIn(IPlugin *plugin, Entity *entity)
390 {
391  if(!listenEntities.contains(plugin->getPluginInstanceID()))
392  {
393  // \todo An empty Entity should means ALL entities too?
394  // Default: Plugin is interested in ALL entities
395  return true;
396  }
397 
398  if(listenEntities.value(
399  plugin->getPluginInstanceID()).contains(entity->getType())
400  )
401  return true;
402 
403  return false;
404 }
405 
406 void MessageControl::setPluginData(QByteArray data)
407 {
408  IPlugin *plugin = qobject_cast<IPlugin *> (QObject::sender());
409 
410  // The plugin instance ID is composed of: pluginID#UniqueID
411  // So, we have to take just the pluginID of that String:
412  QString pluginId = plugin->getPluginInstanceID().left(
413  plugin->getPluginInstanceID().indexOf("#"));
414 
415  project->setPluginData(pluginId, data);
416 }
417 
419 {
420  project->setDirty(true);
421 }
422 
423 void MessageControl::undo()
424 {
425  qUndoStack->undo();
426 }
427 
428 void MessageControl::redo()
429 {
430  qUndoStack->redo();
431 }
432 
433 } } //end namespace