OpenWalnut  1.5.0dev
WQtNetworkEditor.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut 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 Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <cstdlib>
26 #include <iostream>
27 #include <memory>
28 #include <string>
29 
30 #include <QGraphicsItem>
31 #include <QGraphicsItemGroup>
32 #include <QGraphicsView>
33 #include <QKeyEvent>
34 
35 #include "../WMainWindow.h"
36 #include "../controlPanel/WQtControlPanel.h"
37 #include "../events/WEventTypes.h"
38 #include "../events/WModuleAssocEvent.h"
39 #include "../events/WModuleConnectEvent.h"
40 #include "../events/WModuleCrashEvent.h"
41 #include "../events/WModuleDeleteEvent.h"
42 #include "../events/WModuleDisconnectEvent.h"
43 #include "../events/WModuleReadyEvent.h"
44 #include "../events/WModuleRemovedEvent.h"
45 #include "WQtNetworkEditor.h"
46 #include "WQtNetworkEditorProjectFileIO.h"
47 #include "WQtNetworkItemGrid.h"
48 #include "WQtNetworkPort.h"
49 #include "core/kernel/WKernel.h"
50 #include "core/kernel/WModule.h"
51 #include "core/kernel/WModuleFactory.h"
52 #include "core/kernel/WProjectFile.h"
53 #include "core/kernel/combiner/WDisconnectCombiner.h"
54 
56  WQtDockWidget( "Modules", parent )
57 {
58  // register network editor project IO parser
60 
61  setObjectName( "Module Graph Dock" );
62  m_mainWindow = parent;
63 
64  setAcceptDrops( true ); // enable drag and drop events
65 
66  m_view = new WQtNetworkEditorView( this );
67  m_view->setMinimumSize( 20, 20 );
68  this->setFocusProxy( m_view );
69 
70  m_scene = new WQtNetworkScene( this );
71 
72  // our virtual grid used to place items
74 
75  m_scene->addItem( m_grid );
76 
77  // QGraphicsScene provides no virtual methods for adding/removing items, thus we use a separate layouter instead of implementing this in
78  // WQtNetworkScene
80 
81  // update view rect whenever the grid updates its dimensions
82  connect( m_grid, SIGNAL( updatedBounds() ), this, SLOT( updateSceneRect() ) );
83 
84  m_view->setScene( m_scene );
85 
86  setWidget( m_view );
87  connect( m_scene, SIGNAL( selectionChanged() ), this, SLOT( selectItem() ) );
88  connect( m_view, SIGNAL( loadAction() ), m_mainWindow, SLOT( openLoadDialog() ) );
89 
90  // as the QGraphicsItems are not derived from QObject, they cannot utilize the event system. We need to provide some possibility to update
91  // them regularly. We use a timer here.
92  QTimer* updater = new QTimer( this );
93  updater->start( 100 );
94  connect( updater, SIGNAL( timeout() ), this, SLOT( updateCycle() ) );
95 }
96 
98 {
99 }
100 
102 {
103  return m_scene->selectedItems();
104 }
105 
107 {
108  m_scene->clearSelection();
109 }
110 
112 {
113  WQtNetworkItem* item = findItemByModule( module );
114  if( item && !item->isSelected() )
115  {
116  m_scene->clearSelection();
117  item->setSelected( true );
118  }
119 }
120 
122 {
123  std::shared_ptr< WModule > module;
124  if( m_scene->selectedItems().size() != 0 &&
125  m_scene->selectedItems().at( 0 )->type() == WQtNetworkItem::Type )
126  {
127  if( m_scene->selectedItems().at( 0 )->type() == WQtNetworkItem::Type )
128  {
129  module = ( static_cast< WQtNetworkItem* >( m_scene->selectedItems().at( 0 ) ) )->getModule();
131  return;
132  }
133  }
134 
136 }
137 
139 {
140  for( QList< WQtNetworkItem* >::const_iterator i = m_items.begin(); i != m_items.end(); ++i )
141  {
142  ( *i )->updater();
143  }
144 }
145 
147 {
148  // list to store the connectors temporarily
151 
152  // a module got associated with the root container -> add it to the list
153  if( event->type() == WQT_ASSOC_EVENT )
154  {
155  // convert event to assoc event
156  WModuleAssocEvent* e1 = dynamic_cast< WModuleAssocEvent* >( event ); // NOLINT
157  if( e1 )
158  {
159  WLogger::getLogger()->addLogMessage( "Inserting \"" + e1->getModule()->getName() + "\".",
160  "NetworkEditor", LL_DEBUG );
161  WQtNetworkItem *item = new WQtNetworkItem( this, e1->getModule() );
162  m_items.push_back( item );
163  m_scene->addItem( item );
164  m_layout->addItem( item );
165 
166  // This is needed here for some reason. You know how to make this better? Tell us.
167  // REASON: although the WQtNetworkItemGrid updates its bounding box, the ensureVisible call does not move to the new item.
168  // Also calling the next method directly from the grid causes seg-faults when leaving the widget area while dragging the item.
169  m_scene->setSceneRect( m_layout->getBoundingBox() );
170 
171  // make visible
172  QList< QGraphicsView* > allViews = m_scene->views();
173  foreach( QGraphicsView* v, allViews )
174  {
175  WQtNetworkEditorView* nv = dynamic_cast< WQtNetworkEditorView* >( v );
176  if( nv )
177  {
178  nv->focusOn( item );
179  }
180  else
181  {
182  v->ensureVisible( item );
183  }
184  }
185  }
186  return true;
187  }
188 
189  // a module changed its state to "ready" -> activate it in dataset browser
190  if( event->type() == WQT_READY_EVENT )
191  {
192  // convert event to ready event
193  WModuleReadyEvent* e = dynamic_cast< WModuleReadyEvent* >( event ); // NOLINT
194  if( !e )
195  {
196  // this should never happen, since the type is set to WQT_READY_EVENT.
197  WLogger::getLogger()->addLogMessage( "Event is not an WModueReadyEvent although its type claims it. Ignoring event.",
198  "NetworkEditor", LL_WARNING );
199 
200  return true;
201  }
202 
203  WLogger::getLogger()->addLogMessage( "Activating \"" + e->getModule()->getName() + "\".",
204  "NetworkEditor", LL_DEBUG );
205 
206  // search all the item matching the module
207  WQtNetworkItem *item = findItemByModule( e->getModule() );
208  if( item != 0 )
209  {
210  item->activate( true );
211  }
212 
213  return true;
214  }
215 
216  // a module tree item was connected to another one
217  if( event->type() == WQT_MODULE_CONNECT_EVENT )
218  {
219  WModuleConnectEvent* e = dynamic_cast< WModuleConnectEvent* >( event ); // NOLINT
220  if( !e )
221  {
222  // this should never happen, since the type is set to WQT_MODULE_CONNECT_EVENT.
223  WLogger::getLogger()->addLogMessage( "Event is not an WModuleConnectEvent although its type claims it. Ignoring event.",
224  "NetworkEditor", LL_WARNING );
225  return true;
226  }
227 
228  WLogger::getLogger()->addLogMessage( "Connecting \"" + e->getInput()->getModule()->getName() +
229  "\" and \"" + e->getOutput()->getModule()->getName() + "\".", "NetworkEditor", LL_DEBUG );
230 
231  std::shared_ptr< WModule > mIn;
232  std::shared_ptr< WModule > mOut;
233 
234  if( e->getInput()->isInputConnector() == true &&
235  e->getOutput()->isOutputConnector() == true )
236  {
237  mIn = e->getInput()->getModule();
238  mOut = e->getOutput()->getModule();
239  }
240  else if( e->getInput()->isOutputConnector() == true &&
241  e->getOutput()->isInputConnector() == true )
242  {
243  mIn = e->getOutput()->getModule();
244  mOut = e->getInput()->getModule();
245  }
246  else
247  {
248  return true;
249  }
250 
251  WQtNetworkItem *inItem = findItemByModule( mIn );
252  WQtNetworkItem *outItem = findItemByModule( mOut );
253 
254  WQtNetworkInputPort *ip = NULL;
255  WQtNetworkOutputPort *op = NULL;
256 
257  tmpIn = inItem->getInPorts();
258  for( QList< WQtNetworkInputPort* >::const_iterator iter = tmpIn.begin();
259  iter != tmpIn.end();
260  ++iter )
261  {
262  WQtNetworkInputPort* inP = *iter;
263  if( e->getInput() == inP->getConnector() )
264  {
265  ip = inP;
266  }
267  }
268 
269  tmpOut = outItem->getOutPorts();
270  for( QList< WQtNetworkOutputPort* >::const_iterator iter = tmpOut.begin();
271  iter != tmpOut.end();
272  ++iter )
273  {
274  WQtNetworkOutputPort* outP = *iter;
275  if( e->getOutput() == outP->getConnector() )
276  {
277  op = outP;
278  }
279  }
280 
281  if( ip != NULL &&
282  op != NULL )
283  {
284  WQtNetworkArrow *arrow = new WQtNetworkArrow( op, ip );
285 
286  arrow->setZValue( -1000.0 );
287  op->addArrow( arrow );
288  ip->addArrow( arrow );
289  arrow->updatePosition();
290 
291  m_scene->addItem( arrow );
292 
293  // also update the layouter
294  m_layout->connection( outItem, inItem );
295  }
296  }
297 
298  // a module tree item was disconnected from another one
299  if( event->type() == WQT_MODULE_DISCONNECT_EVENT )
300  {
301  WModuleDisconnectEvent* e = dynamic_cast< WModuleDisconnectEvent* >( event ); // NOLINT
302  if( !e )
303  {
304  // this should never happen, since the type is set to WQT_MODULE_DISCONNECT_EVENT.
305  WLogger::getLogger()->addLogMessage( "Event is not an WModuleDisconnectEvent although its type claims it. Ignoring event.",
306  "NetworkEditor", LL_WARNING );
307  return true;
308  }
309 
310  WLogger::getLogger()->addLogMessage( "Disconnecting \"" + e->getInput()->getCanonicalName() +
311  "\" and \"" + e->getOutput()->getCanonicalName() +
312  "\"." , "NetworkEditor", LL_DEBUG );
313 
314  std::shared_ptr< WModule > mIn;
315  std::shared_ptr< WModule > mOut;
316 
317  if( e->getInput()->isInputConnector() == true &&
318  e->getOutput()->isOutputConnector() == true )
319  {
320  mIn = e->getInput()->getModule();
321  mOut = e->getOutput()->getModule();
322  }
323  else if( e->getInput()->isOutputConnector() == true &&
324  e->getOutput()->isInputConnector() == true )
325  {
326  mIn = e->getOutput()->getModule();
327  mOut = e->getInput()->getModule();
328  }
329  else
330  {
331  return true;
332  }
333 
334 
335  WQtNetworkItem *inItem = findItemByModule( mIn );
336  WQtNetworkItem *outItem = findItemByModule( mOut );
337 
338  WQtNetworkInputPort *ip = NULL;
339  WQtNetworkOutputPort *op = NULL;
340 
341  tmpIn = inItem->getInPorts();
342  for( QList< WQtNetworkInputPort* >::const_iterator iter = tmpIn.begin();
343  iter != tmpIn.end();
344  ++iter )
345  {
346  WQtNetworkInputPort *inP = *iter;
347  if( e->getInput() == inP->getConnector() )
348  {
349  ip = inP;
350  }
351  }
352  tmpOut = outItem->getOutPorts();
353  for( QList< WQtNetworkOutputPort* >::const_iterator iter = tmpOut.begin();
354  iter != tmpOut.end();
355  ++iter )
356  {
357  WQtNetworkOutputPort *outP = *iter;
358  if( e->getOutput() == outP->getConnector() )
359  {
360  op = outP;
361  }
362  }
363 
364  WQtNetworkArrow *ar = NULL;
365 
366  QList< QGraphicsItem* > tmpItems = m_scene->items();
367  for( QList< QGraphicsItem* >::const_iterator iter = tmpItems.begin();
368  iter != tmpItems.end();
369  ++iter )
370  {
371  ar = dynamic_cast< WQtNetworkArrow* >( *iter );
372  if( ar &&
373  ar->getStartPort() == op &&
374  ar->getEndPort() == ip )
375  {
376  break;
377  }
378  }
379  if( ar )
380  {
381  op->removeArrow( ar );
382  ip->removeArrow( ar );
383  if( ar->scene() != NULL )
384  {
385  m_scene->removeItem( ar );
386  }
387  delete ar;
388  }
389  else
390  {
391  WLogger::getLogger()->addLogMessage( "Arrow not found!.", "NetworkEditor", LL_ERROR );
392  }
393 
394  // update layouter
395  m_layout->disconnection( outItem, inItem );
396 
397  return true;
398  }
399 
400  // a module was removed from the container
401  if( event->type() == WQT_MODULE_REMOVE_EVENT )
402  {
403  WModuleRemovedEvent* e = dynamic_cast< WModuleRemovedEvent* >( event );
404  if( !e )
405  {
406  // this should never happen, since the type is set to WQT_MODULE_REMOVE_EVENT.
407  WLogger::getLogger()->addLogMessage( "Event is not an WModuleRemovedEvent although its type claims it. Ignoring event.",
408  "NetworkEditor", LL_WARNING );
409  return true;
410  }
411 
412  WLogger::getLogger()->addLogMessage( "Removing \"" + e->getModule()->getName() + "\".",
413  "NetworkEditor", LL_DEBUG );
414 
415 
416  WQtNetworkItem *item = findItemByModule( e->getModule() );
417  if( item != 0 )
418  {
419  item->activate( false );
420  e->getModule()->requestStop();
421  }
422 
423  return true;
424  }
425 
426  // a module tree item should be deleted
427  if( event->type() == WQT_MODULE_DELETE_EVENT )
428  {
429  WModuleDeleteEvent* e = dynamic_cast< WModuleDeleteEvent* >( event );
430  if( !e )
431  {
432  // this should never happen, since the type is set to WQT_MODULE_REMOVE_EVENT.
433  WLogger::getLogger()->addLogMessage( "Event is not an WModuleRemovedEvent although"
434  "its type claims it. Ignoring event.",
435  "NetworkEditor", LL_WARNING );
436  return true;
437  }
438 
439  WLogger::getLogger()->addLogMessage( "Deleting \"" + e->getTreeItem()->getModule()->getName() + "\".",
440  "NetworkEditor", LL_DEBUG );
441 
443 
444  if( item != 0 )
445  {
446  m_items.removeAll( item );
447  // NOTE: the die-animation also removes the item from the layout. (in WQtNetworkItem::removalAnimationDone )
448  item->die();
449  }
450 
451  return true;
452  }
453 
454  if( event->type() == WQT_CRASH_EVENT )
455  {
456  // change module state
457  WModuleCrashEvent* e = dynamic_cast< WModuleCrashEvent* >( event );
458  if( !e )
459  {
460  // this should never happen, since the type is set to WQT_MODULE_REMOVE_EVENT.
461  WLogger::getLogger()->addLogMessage( "Event is not an WModuleCrashEvent although"
462  "its type claims it. Ignoring event.",
463  "NetworkEditor", LL_WARNING );
464  return true;
465  }
466 
467  WLogger::getLogger()->addLogMessage( "Marking \"" + e->getModule()->getName() + "\" as crashed.",
468  "NetworkEditor", LL_DEBUG );
469 
470  WQtNetworkItem *item = findItemByModule( e->getModule() );
471  item->setCrashed();
472 
473  return true;
474  }
475 
476  return WQtDockWidget::event( event );
477 }
478 
479 WQtNetworkItem* WQtNetworkEditor::findItemByModule( std::shared_ptr< WModule > module )
480 {
481  for( QList< WQtNetworkItem* >::const_iterator iter = m_items.begin(); iter != m_items.end(); ++iter )
482  {
483  WQtNetworkItem *itemModule = dynamic_cast< WQtNetworkItem* >( *iter );
484  // pointers are compared, not realy a good idea but atm. there is no better way to do this
485  if( itemModule && itemModule->getModule().get() == module.get() )
486  {
487  return itemModule;
488  }
489  }
490  return NULL;
491 }
492 
494 {
495  return m_scene;
496 }
497 
499 {
500  return m_view;
501 }
502 
504 {
505  return m_layout;
506 }
507 
509 {
510  m_scene->setSceneRect( m_layout->getBoundingBox() );
511 }
void addLogMessage(std::string message, std::string source="", LogLevel level=LL_DEBUG)
Appends a log message to the logging queue.
Definition: WLogger.cpp:84
static WLogger * getLogger()
Returns pointer to the currently running logger instance.
Definition: WLogger.cpp:64
This class contains the main window and the layout of the widgets within the window.
Definition: WMainWindow.h:66
WQtControlPanel * getControlPanel()
Returns a pointer to the control panel object.
Event signalling a new module has been associated with the root container in the kernel.
std::shared_ptr< WModule > getModule()
Getter for the module that got associated.
Event signalling a module connection was established.
std::shared_ptr< WModuleConnector > getOutput() const
Gets the output connector involved in this connection event.
std::shared_ptr< WModuleConnector > getInput() const
Gets the input connector involved in this connection event.
Event signalling a new module has been associated with the root container in the kernel.
std::shared_ptr< WModule > getModule()
Getter for the module that got associated.
Event signalling a module item should be deleted.
WQtTreeItem * getTreeItem()
Getter for the tree item that got outdated.
Event signalling a module connection was closed.
std::shared_ptr< WModuleConnector > getInput() const
Gets the input connector involved in this connection event.
std::shared_ptr< WModuleConnector > getOutput() const
Gets the output connector involved in this connection event.
Event signalling a new module has been associated with the root container in the kernel.
std::shared_ptr< WModule > getModule()
Getter for the module that got associated.
Event signalling a module was removed from the kernel root container.
std::shared_ptr< WModule > getModule()
Getter for the module that got removed.
std::shared_ptr< WModule > SPtr
Shared pointer to a WModule.
Definition: WModule.h:106
std::shared_ptr< WProjectFileIO > SPtr
Abbreviation for a shared pointer.
static void registerParser(WProjectFileIO::SPtr parser)
Register a custom project file parser.
void deactivateModuleSelection(bool selectTopmost=true)
Used to clean the GUI from any module specify widgets.
void setActiveModule(WModule::SPtr module, bool forceUpdate=false)
Sets the module which is now active.
Advanced QDockWidget.
Definition: WQtDockWidget.h:50
This Class is needed for connecting two ports and drawing a line between them.
WQtNetworkInputPort * getEndPort()
Returns the WQtNetworkInputPort where the arrow ends.
void updatePosition(QPointF deviate=QPointF())
Calculated the new position of the lines endpoints in the scene.
WQtNetworkOutputPort * getStartPort()
Returns the WQtNetworkOutputPort where the arrow starts.
IO class for writing the network editor meta data for the modules.
This class extends the basic functionality of QGraphicsView to allow comfortable panning and zooming.
void focusOn(QGraphicsItem *item)
The Item to focus on.
void selectByModule(WModule::SPtr module)
Select the item representing the given module.
void updateCycle()
Called by a timer to allow updates of all module items.
virtual bool event(QEvent *event)
Everytime a module is associated, ready, connected, disconnected, removed or deleted the kernels emit...
void selectItem()
Determines possible Connections and the propertytab.
WQtNetworkItem * findItemByModule(std::shared_ptr< WModule > module)
Simple search the WQtNetworkItem that belongs to the WModule.
WQtNetworkEditorView * getView()
Get the view handling the scene.
WQtNetworkScene * m_scene
the scene managing the items
void clearSelection()
Clears the selection.
void updateSceneRect()
Set new scene rect.
WQtNetworkSceneLayout * m_layout
the layouter of the scene
WMainWindow * m_mainWindow
Reference to the main window of the application.
QList< QGraphicsItem * > selectedItems() const
Query a list of selected items.
QList< WQtNetworkItem * > m_items
a list of the WQtNetworkItems in the WQtNetworkScene
WQtNetworkScene * getScene()
Returns the current scene.
WQtNetworkSceneLayout * getLayout()
Get the layouter of the scene.
WQtNetworkItemGrid * m_grid
we use a grid to place the items
WQtNetworkEditorView * m_view
The view controlling several scene transformations.
virtual ~WQtNetworkEditor()
destructor.
WQtNetworkEditor(WMainWindow *parent=0)
constructor
This class represents the ports a module have.
std::shared_ptr< WModuleInputConnector > getConnector()
Returns the WModuleInputConnecter that belongs to this object.
Implement a virtual grid for placing QGraphicsItems.
This class represents a WModule as QGraphicsItem and contains a reference to its in- and outports.
void activate(bool active)
Here the module can be enabled when the WModule is ready.
std::shared_ptr< WModule > getModule()
Get the WModule represented by this object.
QList< WQtNetworkInputPort * > getInPorts()
Returns the item inports.
void setCrashed()
Mark this module as crashed.
QTimeLine * die()
Animate removal and finally, instruct the owning network editor to remove the item.
QList< WQtNetworkOutputPort * > getOutPorts()
Returns the item outports.
This class represents the ports a module have.
std::shared_ptr< WModuleOutputConnector > getConnector()
Returns the WModuleOutputConnecter that belongs to this object.
virtual void removeArrow(WQtNetworkArrow *arrow)
Removes a specific arrow.
virtual void addArrow(WQtNetworkArrow *arrow)
Adds an arrow to the port.
Layout manager class for a QGraphicsScene.
virtual void addItem(WQtNetworkItem *item)
Add an item to the layout.
virtual void connection(WQtNetworkItem *outItem, WQtNetworkItem *inItem)
Two module got connected.
void disconnection(WQtNetworkItem *outItem, WQtNetworkItem *inItem)
Two modules got disconnected.
QRectF getBoundingBox()
Return the bounding box of this layout.
The scene containing the whole graph.
WModule::SPtr getModule()
Get for the module pointer.