]> Creatis software - cpPlugins.git/blob - appli/cpPipelineEditor/QNodesEditor.cxx
Kind of bored: graph editor debugged
[cpPlugins.git] / appli / cpPipelineEditor / QNodesEditor.cxx
1 /* Copyright (c) 2012, STANISLAW ADASZEWSKI\r
2    All rights reserved.\r
3 \r
4    Redistribution and use in source and binary forms, with or without\r
5    modification, are permitted provided that the following conditions are met:\r
6    * Redistributions of source code must retain the above copyright\r
7    notice, this list of conditions and the following disclaimer.\r
8    * Redistributions in binary form must reproduce the above copyright\r
9    notice, this list of conditions and the following disclaimer in the\r
10    documentation and/or other materials provided with the distribution.\r
11    * Neither the name of STANISLAW ADASZEWSKI nor the\r
12    names of its contributors may be used to endorse or promote products\r
13    derived from this software without specific prior written permission.\r
14 \r
15    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
16    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
17    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
18    DISCLAIMED. IN NO EVENT SHALL STANISLAW ADASZEWSKI BE LIABLE FOR ANY\r
19    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
20    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
21    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
22    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
23    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
24    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
25 */\r
26 \r
27 #include "QNodesEditor.h"\r
28 \r
29 #include <QGraphicsScene>\r
30 #include <QEvent>\r
31 #include <QGraphicsSceneContextMenuEvent>\r
32 #include <QGraphicsSceneDragDropEvent>\r
33 #include <QGraphicsSceneHelpEvent>\r
34 #include <QGraphicsSceneHoverEvent>\r
35 #include <QGraphicsSceneMouseEvent>\r
36 #include <QGraphicsSceneMoveEvent>\r
37 #include <QGraphicsSceneResizeEvent>\r
38 #include <QGraphicsSceneWheelEvent>\r
39 \r
40 #include "QNEPort.h"\r
41 #include "QNEConnection.h"\r
42 #include "QNEBlock.h"\r
43 \r
44 // -------------------------------------------------------------------------\r
45 PipelineEditor::QNodesEditor::\r
46 QNodesEditor( QObject* parent )\r
47  : Superclass( parent ),\r
48    m_Conn( NULL ),\r
49    m_Workspace( NULL )\r
50 {\r
51 }\r
52 \r
53 // -------------------------------------------------------------------------\r
54 PipelineEditor::QNodesEditor::\r
55 ~QNodesEditor( )\r
56 {\r
57 }\r
58 \r
59 // -------------------------------------------------------------------------\r
60 PipelineEditor::QNodesEditor::\r
61 TWorkspace* PipelineEditor::QNodesEditor::\r
62 workspace( )\r
63 {\r
64   return( this->m_Workspace );\r
65 }\r
66 \r
67 // -------------------------------------------------------------------------\r
68 const PipelineEditor::QNodesEditor::\r
69 TWorkspace* PipelineEditor::QNodesEditor::\r
70 workspace( ) const\r
71 {\r
72   return( this->m_Workspace );\r
73 }\r
74 \r
75 // -------------------------------------------------------------------------\r
76 void PipelineEditor::QNodesEditor::\r
77 setWorkspace( TWorkspace* ws )\r
78 {\r
79   if( this->m_Workspace == ws )\r
80     return;\r
81   this->m_Workspace = ws;\r
82   this->m_Graph = TGraph::New( );\r
83 \r
84   // Create blocks\r
85   auto vIt = this->m_Workspace->GetGraph( )->BeginVertices( );\r
86   auto vIt_end = this->m_Workspace->GetGraph( )->EndVertices( );\r
87   for( ; vIt != vIt_end; ++vIt )\r
88   {\r
89     this->_CreateBlock(\r
90       dynamic_cast< TFilter* >( vIt->second.GetPointer( ) ),\r
91       QPointF( )\r
92       );\r
93 \r
94   } // rof\r
95 \r
96   // Add edges\r
97   auto rIt = this->m_Workspace->GetGraph( )->BeginEdgesRows( );\r
98   auto rIt_end = this->m_Workspace->GetGraph( )->EndEdgesRows( );\r
99   for( ; rIt != rIt_end; ++rIt )\r
100   {\r
101     if( !this->m_Graph->HasVertexIndex( rIt->first ) )\r
102       continue;\r
103     QNEBlock* orig = this->m_Graph->GetVertex( rIt->first );\r
104     if( orig == NULL )\r
105       continue;\r
106     QVector< QNEOutputPort* >& oPorts = orig->outputPorts( );\r
107 \r
108     auto cIt = rIt->second.begin( );\r
109     for( ; cIt != rIt->second.end( ); ++cIt )\r
110     {\r
111       if( !this->m_Graph->HasVertexIndex( cIt->first ) )\r
112         continue;\r
113       QNEBlock* dest = this->m_Graph->GetVertex( cIt->first );\r
114       if( dest == NULL )\r
115         continue;\r
116       QVector< QNEInputPort* >& iPorts = dest->inputPorts( );\r
117 \r
118       auto eIt = cIt->second.begin( );\r
119       for( ; eIt != cIt->second.end( ); ++eIt )\r
120       {\r
121         QNEOutputPort* op = NULL;\r
122         auto opIt = oPorts.begin( );\r
123         for( ; opIt != oPorts.end( ) && op == NULL; ++opIt )\r
124           if( ( *opIt )->name( ).toStdString( ) == eIt->first )\r
125             op = *opIt;\r
126 \r
127         QNEInputPort* ip = NULL;\r
128         auto ipIt = iPorts.begin( );\r
129         for( ; ipIt != iPorts.end( ) && ip == NULL; ++ipIt )\r
130           if( ( *ipIt )->name( ).toStdString( ) == eIt->second )\r
131             ip = *ipIt;\r
132 \r
133         if( op == NULL || ip == NULL )\r
134           continue;\r
135 \r
136         QNEConnection* conn = new QNEConnection( 0, this->m_Scene );\r
137         conn->setPort1( op );\r
138         conn->setPort2( ip );\r
139         conn->updatePosFromPorts( );\r
140         conn->updatePath( );\r
141         this->m_Graph->AddConnection( rIt->first, cIt->first, conn );\r
142 \r
143       } // rof\r
144 \r
145     } // rof\r
146 \r
147   } // rof\r
148 }\r
149 \r
150 // -------------------------------------------------------------------------\r
151 std::string PipelineEditor::QNodesEditor::\r
152 createFilter( const std::string& filter, const QPointF& pnt )\r
153 {\r
154   std::string name = filter;\r
155   while( this->m_Workspace->HasFilter( name ) )\r
156     name += std::string( "_" );\r
157   if( this->m_Workspace->CreateFilter( filter, name ) )\r
158   {\r
159     this->_CreateBlock( this->m_Workspace->GetFilter( name ), pnt );\r
160     return( name );\r
161   }\r
162   else\r
163     return( "" );\r
164 }\r
165 \r
166 // -------------------------------------------------------------------------\r
167 void PipelineEditor::QNodesEditor::\r
168 install( QGraphicsScene* s )\r
169 {\r
170   s->installEventFilter( this );\r
171   this->m_Scene = s;\r
172 }\r
173 \r
174 // -------------------------------------------------------------------------\r
175 QGraphicsItem* PipelineEditor::QNodesEditor::\r
176 itemAt( const QPointF& pos )\r
177 {\r
178   QList< QGraphicsItem* > items =\r
179     this->m_Scene->items( QRectF( pos - QPointF( 1, 1 ), QSize( 3, 3 ) ) );\r
180 \r
181   foreach( QGraphicsItem* item, items )\r
182     if( item->type( ) > QGraphicsItem::UserType )\r
183       return( item );\r
184   return( NULL );\r
185 }\r
186 \r
187 #include <iostream>\r
188 \r
189 // -------------------------------------------------------------------------\r
190 void PipelineEditor::QNodesEditor::\r
191 _CreateBlock( TFilter* f, const QPointF& pnt )\r
192 {\r
193   if( f == NULL )\r
194     return;\r
195 \r
196   // Add block\r
197   QNEBlock* b = new QNEBlock( 0, this->m_Scene );\r
198   b->setNamePort( f->GetName( ) );\r
199   b->setTypePort( f->GetClassName( ).c_str( ) );\r
200   // TODO: b->setScenePos( pnt );\r
201 \r
202   // Add input ports\r
203   std::set< std::string > inputs;\r
204   f->GetInputsNames( inputs );\r
205   for( auto iIt = inputs.begin( ); iIt != inputs.end( ); ++iIt )\r
206     b->addInputPort( iIt->c_str( ) );\r
207 \r
208   // Add output ports\r
209   std::set< std::string > outputs;\r
210   f->GetOutputsNames( outputs );\r
211   for( auto oIt = outputs.begin( ); oIt != outputs.end( ); ++oIt )\r
212     b->addOutputPort( oIt->c_str( ) );\r
213 \r
214   // Keep a trace of this visual graph\r
215   this->m_Graph->InsertVertex( f->GetName( ), b );\r
216 }\r
217 \r
218 // -------------------------------------------------------------------------\r
219 void PipelineEditor::QNodesEditor::\r
220 _DoubleClick( QGraphicsSceneMouseEvent* evt, QGraphicsItem* item )\r
221 {\r
222   switch( evt->button( ) )\r
223   {\r
224   case Qt::LeftButton:\r
225   {\r
226     QNEBlock* block = dynamic_cast< QNEBlock* >( item );\r
227     QNEPort* port = dynamic_cast< QNEPort* >( item );\r
228     QNEConnection* conn = dynamic_cast< QNEConnection* >( item );\r
229 \r
230     if( block != NULL )\r
231     {\r
232       /* TODO\r
233          auto ports = block->ports( );\r
234          std::string name = "";\r
235          for(\r
236          auto pIt = ports.begin( );\r
237          pIt != ports.end( ) && name == "";\r
238          ++pIt\r
239          )\r
240          if(\r
241          ( *pIt )->portFlags( ) && QNEPort::NamePort == QNEPort::NamePort\r
242          )\r
243          name = ( *pIt )->portName( ).toStdString( );\r
244          if( name == "" )\r
245          return;\r
246          TFilter* filter = this->m_Workspace->GetFilter( name );\r
247          if( filter != NULL )\r
248          {\r
249          } // fi\r
250       */\r
251     }\r
252     else if( port != NULL )\r
253     {\r
254     }\r
255     else if( conn != NULL )\r
256     {\r
257     } // fi\r
258   }\r
259   break;\r
260   /* TODO:\r
261      case Qt::RightButton:\r
262      {\r
263      }\r
264      break;\r
265      case Qt::MiddleButton:\r
266      {\r
267      }\r
268      break;\r
269   */\r
270   default:\r
271     break;\r
272   } // hctiws\r
273 }\r
274 \r
275 // -------------------------------------------------------------------------\r
276 bool PipelineEditor::QNodesEditor::\r
277 eventFilter( QObject* o, QEvent* e )\r
278 {\r
279   // Event type\r
280   switch( int( e->type( ) ) )\r
281   {\r
282   case QEvent::GraphicsSceneContextMenu:\r
283   {\r
284     QGraphicsSceneContextMenuEvent* evt =\r
285       dynamic_cast< QGraphicsSceneContextMenuEvent* >( e );\r
286     if( evt != NULL )\r
287     {\r
288     } // fi\r
289   }\r
290   break;\r
291   case QEvent::GraphicsSceneDragEnter:\r
292   {\r
293     QGraphicsSceneDragDropEvent* evt =\r
294       dynamic_cast< QGraphicsSceneDragDropEvent* >( e );\r
295     if( evt != NULL )\r
296     {\r
297     } // fi\r
298   }\r
299   break;\r
300   case QEvent::GraphicsSceneDragLeave:\r
301   {\r
302     QGraphicsSceneDragDropEvent* evt =\r
303       dynamic_cast< QGraphicsSceneDragDropEvent* >( e );\r
304     if( evt != NULL )\r
305     {\r
306     } // fi\r
307   }\r
308   break;\r
309   case QEvent::GraphicsSceneDragMove:\r
310   {\r
311     QGraphicsSceneDragDropEvent* evt =\r
312       dynamic_cast< QGraphicsSceneDragDropEvent* >( e );\r
313     if( evt != NULL )\r
314     {\r
315     } // fi\r
316   }\r
317   break;\r
318   case QEvent::GraphicsSceneDrop:\r
319   {\r
320     QGraphicsSceneDragDropEvent* evt =\r
321       dynamic_cast< QGraphicsSceneDragDropEvent* >( e );\r
322     if( evt != NULL )\r
323     {\r
324     } // fi\r
325   }\r
326   break;\r
327   case QEvent::GraphicsSceneHelp:\r
328   {\r
329     QGraphicsSceneHelpEvent* evt =\r
330       dynamic_cast< QGraphicsSceneHelpEvent* >( e );\r
331     if( evt != NULL )\r
332     {\r
333     } // fi\r
334   }\r
335   break;\r
336   case QEvent::GraphicsSceneHoverEnter:\r
337   {\r
338     QGraphicsSceneHoverEvent* evt =\r
339       dynamic_cast< QGraphicsSceneHoverEvent* >( e );\r
340     if( evt != NULL )\r
341     {\r
342     } // fi\r
343   }\r
344   break;\r
345   case QEvent::GraphicsSceneHoverLeave:\r
346   {\r
347     QGraphicsSceneHoverEvent* evt =\r
348       dynamic_cast< QGraphicsSceneHoverEvent* >( e );\r
349     if( evt != NULL )\r
350     {\r
351     } // fi\r
352   }\r
353   break;\r
354   case QEvent::GraphicsSceneHoverMove:\r
355   {\r
356     QGraphicsSceneHoverEvent* evt =\r
357       dynamic_cast< QGraphicsSceneHoverEvent* >( e );\r
358     if( evt != NULL )\r
359     {\r
360     } // fi\r
361   }\r
362   break;\r
363   case QEvent::GraphicsSceneMouseDoubleClick:\r
364   {\r
365     QGraphicsSceneMouseEvent* evt =\r
366       dynamic_cast< QGraphicsSceneMouseEvent* >( e );\r
367     if( evt != NULL )\r
368     {\r
369       QGraphicsItem* item = this->itemAt( evt->scenePos( ) );\r
370       if( item != NULL )\r
371       {\r
372         this->_DoubleClick( evt, item );\r
373         return( true );\r
374 \r
375       } // fi\r
376 \r
377     } // fi\r
378   }\r
379   break;\r
380   case QEvent::GraphicsSceneMouseMove:\r
381   {\r
382     QGraphicsSceneMouseEvent* evt =\r
383       dynamic_cast< QGraphicsSceneMouseEvent* >( e );\r
384     if( evt != NULL )\r
385     {\r
386       if( this->m_Conn )\r
387       {\r
388         this->m_Conn->setPos2( evt->scenePos( ) );\r
389         this->m_Conn->updatePath( );\r
390         return( true );\r
391 \r
392       } // fi\r
393 \r
394     } // fi\r
395   }\r
396   break;\r
397   case QEvent::GraphicsSceneMousePress:\r
398   {\r
399     QGraphicsSceneMouseEvent* evt =\r
400       dynamic_cast< QGraphicsSceneMouseEvent* >( e );\r
401     if( evt != NULL )\r
402     {\r
403       switch( evt->button( ) )\r
404       {\r
405       case Qt::LeftButton:\r
406       {\r
407         QNEOutputPort* port =\r
408           dynamic_cast< QNEOutputPort* >( this->itemAt( evt->scenePos( ) ) );\r
409         if( port != NULL )\r
410         {\r
411           this->m_Conn = new QNEConnection( 0, this->m_Scene );\r
412           this->m_Conn->setPort1( port );\r
413           this->m_Conn->setPos1( port->scenePos( ) );\r
414           this->m_Conn->setPos2( evt->scenePos( ) );\r
415           this->m_Conn->updatePath( );\r
416           return( true );\r
417 \r
418         } // fi\r
419       }\r
420       break;\r
421       default:\r
422         break;\r
423 \r
424       } // hctiws\r
425 \r
426     } // fi\r
427   }\r
428   break;\r
429   case QEvent::GraphicsSceneMouseRelease:\r
430   {\r
431     QGraphicsSceneMouseEvent* evt =\r
432       dynamic_cast< QGraphicsSceneMouseEvent* >( e );\r
433     if( evt != NULL )\r
434     {\r
435       if( this->m_Conn != NULL && evt->button( ) == Qt::LeftButton )\r
436       {\r
437         QNEInputPort* port2 =\r
438           dynamic_cast< QNEInputPort* >( this->itemAt( evt->scenePos( ) ) );\r
439         if( port2 != NULL )\r
440         {\r
441           QNEOutputPort* port1 =\r
442             dynamic_cast< QNEOutputPort* >( this->m_Conn->port1( ) );\r
443           if( port1 != NULL )\r
444           {\r
445             if(\r
446               port1->block( ) != port2->block( ) &&\r
447               !port2->hasConnection( ) &&\r
448               !port1->isConnected( port2 )\r
449               )\r
450             {\r
451               this->m_Conn->setPos2( port2->scenePos( ) );\r
452               this->m_Conn->setPort2( port2 );\r
453               this->m_Conn->updatePath( );\r
454 \r
455               this->m_Workspace->Connect(\r
456                 port1->block( )->namePort( )->name( ).toStdString( ),\r
457                 port2->block( )->namePort( )->name( ).toStdString( ),\r
458                 port1->name( ).toStdString( ),\r
459                 port2->name( ).toStdString( )\r
460                 );\r
461               this->m_Graph->AddConnection(\r
462                 port1->block( )->namePort( )->name( ).toStdString( ),\r
463                 port2->block( )->namePort( )->name( ).toStdString( ),\r
464                 this->m_Conn\r
465                 );\r
466 \r
467               this->m_Conn = NULL;\r
468               return( true );\r
469 \r
470             } // fi\r
471 \r
472           } // fi\r
473 \r
474         } // fi\r
475         delete this->m_Conn;\r
476         this->m_Conn = NULL;\r
477         return( true );\r
478 \r
479       } // fi\r
480 \r
481     } // fi\r
482   }\r
483   break;\r
484   case QEvent::GraphicsSceneMove:\r
485   {\r
486     QGraphicsSceneMoveEvent* evt =\r
487       dynamic_cast< QGraphicsSceneMoveEvent* >( e );\r
488     if( evt != NULL )\r
489     {\r
490     } // fi\r
491   }\r
492   break;\r
493   case QEvent::GraphicsSceneResize:\r
494   {\r
495     QGraphicsSceneResizeEvent* evt =\r
496       dynamic_cast< QGraphicsSceneResizeEvent* >( e );\r
497     if( evt != NULL )\r
498     {\r
499     } // fi\r
500   }\r
501   break;\r
502   case QEvent::GraphicsSceneWheel:\r
503   {\r
504     QGraphicsSceneWheelEvent* evt =\r
505       dynamic_cast< QGraphicsSceneWheelEvent* >( e );\r
506     if( evt != NULL )\r
507     {\r
508     } // fi\r
509   }\r
510   break;\r
511   default:\r
512     break;\r
513   } // hctiws\r
514 \r
515   // Mouse event\r
516   /*\r
517     QGraphicsSceneMouseEvent* me =\r
518     dynamic_cast< QGraphicsSceneMouseEvent* >( e );\r
519     if( me != NULL )\r
520     {\r
521     } // fi\r
522   */\r
523 \r
524   /* TODO\r
525      switch( ( int ) e->type( ) )\r
526      {\r
527      case QEvent::GraphicsSceneMouseMove:\r
528      {\r
529      if( this->m_Conn )\r
530      {\r
531      this->m_Conn->setPos2( me->scenePos( ) );\r
532      this->m_Conn->updatePath( );\r
533      return( true );\r
534      }\r
535      break;\r
536      }\r
537      case QEvent::GraphicsSceneMouseRelease:\r
538      {\r
539      if( this->m_Conn && me->button( ) == Qt::LeftButton )\r
540      {\r
541      QGraphicsItem* item = itemAt( me->scenePos( ) );\r
542      if( item && item->type( ) == QNEPort::Type )\r
543      {\r
544      QNEPort* port1 = this->m_Conn->port1( );\r
545      QNEPort* port2 = ( QNEPort* ) item;\r
546      if( port1->block( ) != port2->block( ) && port1->isOutput( ) != port2->isOutput( ) && !port1->isConnected( port2 ) )\r
547      {\r
548      this->m_Conn->setPos2( port2->scenePos( ) );\r
549      this->m_Conn->setPort2( port2 );\r
550      this->m_Conn->updatePath( );\r
551      this->m_Conn = NULL;\r
552      return( true );\r
553      }\r
554      }\r
555 \r
556      delete this->m_Conn;\r
557      this->m_Conn = NULL;\r
558      return( true );\r
559      }\r
560      break;\r
561      }\r
562      } // hctiws\r
563   */\r
564 \r
565   return( this->Superclass::eventFilter( o, e ) );\r
566 }\r
567 \r
568 // eof - $RCSfile$\r