NCL Composer  0.1.5
 All Classes Functions Variables Pages
PluginControl.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/PluginControl.h"
11 
12 #include <QUuid>
13 #include <QMetaObject>
14 #include <QMetaMethod>
15 
16 namespace composer {
17 namespace core {
18 
19 INIT_SINGLETON(PluginControl)
20 
22 {
23  //Register MetaType allowing to be used by invoke
24  qRegisterMetaType<void *>("const void *");
25 }
26 
27 PluginControl::~PluginControl()
28 {
29  //FIXME: BUG WHEN CLOSING ON WINDOWS
30  QMultiHash<Project*,IPlugin*>::iterator itInst;
31  QHash<QString,IPluginFactory*>::iterator itFac;
32 
33  IPlugin *inst = NULL;
34  IPluginFactory *fac = NULL;
35 
36  for (itInst = pluginInstances.begin();
37  itInst != pluginInstances.end(); itInst++)
38  {
39  QList<IPlugin*> instances = pluginInstances.values(itInst.key());
40  QList<IPlugin*>::iterator it;
41 
42  for (it = instances.begin(); it != instances.end(); it++)
43  {
44  inst = *it;
45  fac = factoryByPlugin.value(inst);
46  factoryByPlugin.remove(inst);
47  fac->releasePluginInstance(inst);
48  pluginInstances.remove(itInst.key(),inst);
49  }
50  }
51 
52  for (itFac = pluginFactories.begin() ; itFac != pluginFactories.end();
53  itFac++)
54  {
55  fac = itFac.value();
56  delete fac;
57  fac = NULL;
58  }
59 
60  pluginFactories.clear();
61  pluginInstances.clear();
62  pluginsByType.clear();
63  factoryByPlugin.clear();
64  messageControls.clear();
65 }
66 
68 {
69  IPluginFactory *pluginFactory = NULL;
70  QPluginLoader loader(fileName);
71  QObject *plugin = loader.instance();
72 
73  // qDebug() << "loadingPlugin( " << fileName << ")";
74  if (plugin)
75  {
76  pluginFactory = qobject_cast<IPluginFactory*> (plugin);
77  if (pluginFactory)
78  {
79  QString pluginID = pluginFactory->id();
80  if (!pluginFactories.contains(pluginID))
81  {
82  pluginFactories[pluginID] = pluginFactory;
83  QList<LanguageType> types = pluginFactory->getSupportedLanguages();
84 
85  QList<LanguageType>::iterator it;
86 
87  for (it = types.begin() ; it!= types.end(); it++)
88  {
89  pluginsByType.insert(*it, pluginFactory->id());
90  }
91  }
92  }
93  }//end load OK
94  else
95  {
96  qDebug() << "PluginControl::loadPlugins failed to load"
97  << "(" << fileName << ")" << " -- " << loader.errorString();
98  }
99 
100  return pluginFactory;
101 }
102 
103 /*bool PluginControl::unLoadPlugin(QString fileName)
104 {
105  // \todo: Verify if there is some instance of the IPlugin
106  QPluginLoader loader(fileName);
107  return loader.unload();
108 }*/
109 
110 void PluginControl::loadPlugins(QString pluginsDirPath)
111 {
112  QDir pluginsDir = QDir(pluginsDirPath);
113  pluginsDir.setFilter(QDir::Files | QDir::NoSymLinks);
114 
115  if(!pluginsDir.exists())
116  {
117  emit notifyError(tr("The Plugin Directory (%1) does not exist").
118  arg(pluginsDirPath));
119  return;
120  }
121 
122  QStringList filter;
123  filter.append("*.so");
124  filter.append("*.dylib");
125  filter.append("*.dll");
126  pluginsDir.setNameFilters(filter);
127 
128  foreach (QString fileName, pluginsDir.entryList(QDir::Files
129  | QDir::NoSymLinks))
130  {
131  loadPlugin(pluginsDir.absoluteFilePath(fileName));
132  } //end foreach
133 
134 } //end function
135 
137 {
138  MessageControl *msgControl;
139  IPluginFactory *factory;
140  LanguageType type = project->getProjectType();
141 
142  msgControl = new MessageControl(project);
143  messageControls[project] = msgControl;
144 
145  QList<QString>::iterator it;
146  QList<QString> plugIDs = pluginsByType.values(type);
147  for (it = plugIDs.begin() ; it != plugIDs.end() ;
148  it++)
149  {
150  factory = pluginFactories[*it];
151 
152  GlobalSettings settings;
153  settings.beginGroup("loadPlugins");
154  if(!settings.contains(*it) || settings.value(*it).toBool() == true)
155  {
156  launchNewPlugin(factory, project);
157  }
158  settings.endGroup();
159  }
160 }
161 
162 void PluginControl::launchNewPlugin(IPluginFactory *factory, Project *project)
163 {
164  IPlugin *pluginInstance = factory->createPluginInstance();
165  QString location = project->getLocation();
166  if (pluginInstance)
167  {
168  pluginInstance->setPluginInstanceID(
169  factory->id() + "#" +QUuid::createUuid().toString());
170  pluginInstance->setProject(project);
171  launchNewPlugin(pluginInstance, messageControls[project]);
172 
173  pluginInstances.insert(project, pluginInstance);
174  factoryByPlugin.insert(pluginInstance, factory);
175 
176  emit addPluginWidgetToWindow(factory, pluginInstance, project,
177  factoryByPlugin.size());
178 
179  //TODO: CREATE A NEW FUNCTION TO UPDATE FROM SAVED CONTENT
180  pluginInstance->init();
181  }
182  else {
183  emit notifyError(tr("Could not create an instance for the"
184  "plugin (%1)").arg(factory->id()));
185  }
186 
187 }
188 
189 void PluginControl::launchNewPlugin(IPlugin *plugin, MessageControl *mControl)
190 {
191  /* Connect signals from the core to slots in the plugins */
192  /*
193  \deprecated
194 
195  Today, the message control is reponsible to call this slots directly.
196 
197  connect(mControl,SIGNAL(entityAdded(QString, Entity*)),
198  plugin, SLOT(onEntityAdded(QString, Entity*)));
199  connect(mControl,SIGNAL(entityChanged(QString, Entity*)),
200  plugin,SLOT(onEntityChanged(QString, Entity*)));
201  connect(mControl,SIGNAL(entityRemoved(QString, QString)),
202  plugin,SLOT(onEntityRemoved(QString, QString)));
203  */
204 
205  /* Connect signals from the plugin to slots of the core */
206  connect(plugin,
207  SIGNAL(addEntity(QString, QString, QMap<QString,QString>&, bool)),
208  mControl,
209  SLOT(onAddEntity(QString, QString, QMap<QString,QString>&, bool)),
210  Qt::DirectConnection);
211 
212  connect(plugin, SIGNAL(setAttributes(Entity*, QMap<QString,QString>, bool)),
213  mControl,
214  SLOT(onEditEntity(Entity*, QMap<QString,QString>, bool)),
215  Qt::DirectConnection);
216 
217  connect(plugin,
218  SIGNAL(removeEntity(Entity*,bool)),
219  mControl,
220  SLOT(onRemoveEntity(Entity*,bool)),
221  Qt::DirectConnection);
222 
223  connect(plugin,
224  SIGNAL(setListenFilter(QStringList)),
225  mControl,
226  SLOT(setListenFilter(QStringList)),
227  Qt::DirectConnection);
228 
229  connect(plugin,
230  SIGNAL(setCurrentProjectAsDirty()),
231  mControl,
232  SLOT(setCurrentProjectAsDirty()),
233  Qt::DirectConnection);
234 
235  // broadcastMessage
236  connect(plugin, SIGNAL(sendBroadcastMessage(const char*, void *)),
237  this, SLOT(sendBroadcastMessage(const char*, void*)),
238  Qt::DirectConnection);
239 
240  /* setPluginData */
241  connect(plugin, SIGNAL(setPluginData(QByteArray)),
242  mControl, SLOT(setPluginData(QByteArray)),
243  Qt::DirectConnection);
244 }
245 
247  MessageControl *mControl)
248 {
249  connect(parser,
250  SIGNAL(addEntity(QString, QString, QMap<QString,QString>&, bool)),
251  mControl,
252  SLOT(onAddEntity(QString, QString, QMap<QString,QString>&, bool)));
253 
254  connect(mControl,SIGNAL(entityAdded(QString, Entity*)),
255  parser, SLOT(onEntityAdded(QString, Entity*)));
256 }
257 
258 QList<IPluginFactory*> PluginControl::getLoadedPlugins()
259 {
260  QHash<QString,IPluginFactory*>::iterator it;
261  QList<IPluginFactory*> pList;
262  for (it = pluginFactories.begin() ; it != pluginFactories.end(); it++)
263  {
264  pList.append(it.value());
265  }
266  return pList;
267 }
268 
270 {
271  if (!project) {
272  qDebug() << "Project is NULL";
273  return false;
274  }
275 
276  if (!messageControls.contains(project))
277  {
278  qDebug() << "Message Control does not know the project";
279  return false;
280  }
281 
282  // if (!pluginInstances.contains(project->getLocation()))
283  // {
284  // qDebug() << "There is no plugin instance for this project";
285  // return false;
286  // }
287 
288  MessageControl *t = messageControls.value(project);
289  if (t)
290  {
291  delete t;
292  t = NULL;
293  messageControls.remove(project);
294  }
295 
296  QList<IPlugin*> instances = pluginInstances.values(project);
297 
298  QList<IPlugin*>::iterator it;
299  for (it = instances.begin(); it != instances.end(); it++)
300  {
301  IPlugin *inst = *it;
302  inst->saveSubsession();
303  IPluginFactory *fac = factoryByPlugin.value(inst);
304  factoryByPlugin.remove(inst);
305  fac->releasePluginInstance(inst);
306  }
307  pluginInstances.remove(project);
308 
309  return true;
310 }
311 
312 void PluginControl::sendBroadcastMessage(const char* slot, void *obj)
313 {
314  IPlugin *plugin = qobject_cast<IPlugin *> (QObject::sender());
315 
316  QList<IPlugin*>::iterator it;
317  QList<IPlugin*> instances = pluginInstances.values(plugin->getProject());
318 
319  QString slotName(slot);
320  slotName.append("(QString,void*)");
321  for (it = instances.begin(); it != instances.end(); it++)
322  {
323  IPlugin *inst = *it;
324  int idxSlot = inst->metaObject()
325  ->indexOfSlot( slotName.toStdString().c_str() );
326  if(idxSlot != -1)
327  {
328  QMetaMethod method = inst->metaObject()->method(idxSlot);
329  method.invoke(inst, Qt::DirectConnection,
330  Q_ARG(QString, plugin->getPluginInstanceID()),
331  Q_ARG(void *, obj));
332  }
333  }
334 }
335 
337 {
338  QList<IPlugin*>::iterator it;
339  QList<IPlugin*> instances = pluginInstances.values(project);
340 
341  for (it = instances.begin(); it != instances.end(); it++)
342  {
343  IPlugin *inst = *it;
344  inst->saveSubsession();
345  }
346 }
347 
349 {
350  return messageControls.value(project);
351 }
352 
353 QList <IPlugin*> PluginControl::getPluginInstances(Project *project)
354 {
355  QList<IPlugin*> instances;
356  if(pluginInstances.contains(project))
357  instances = pluginInstances.values(project);
358 
359  return instances;
360 }
361 
362 } }//end namespace