]> Creatis software - cpPlugins.git/blob - appli/cpPipelineEditor/QNodesEditor.cxx
46508ca6fb92cbfe69c34430d3e1e9260126e8d4
[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 #include <QInputDialog>\r
40 \r
41 #include "QNEPort.h"\r
42 #include "QNEConnection.h"\r
43 #include "QNEBlock.h"\r
44 \r
45 // -------------------------------------------------------------------------\r
46 #define PipelineEditor_QNodesEditor_Callback_SWITCH( E, e )             \\r
47   case QEvent::E:                                                       \\r
48   {                                                                     \\r
49     Q##E##Event* evt = dynamic_cast< Q##E##Event* >( e );               \\r
50     if( evt != NULL )                                                   \\r
51       this->_##E##_cbk( evt );                                          \\r
52   }                                                                     \\r
53   break\r
54 \r
55 // -------------------------------------------------------------------------\r
56 #define PipelineEditor_QNodesEditor_Callback_CODE( E )                  \\r
57   void PipelineEditor::QNodesEditor::_##E##_cbk( Q##E##Event* evt )\r
58 \r
59 // -------------------------------------------------------------------------\r
60 PipelineEditor::QNodesEditor::\r
61 QNodesEditor( QObject* parent )\r
62  : Superclass( parent ),\r
63    m_Conn( NULL ),\r
64    m_Workspace( NULL )\r
65 {\r
66 }\r
67 \r
68 // -------------------------------------------------------------------------\r
69 PipelineEditor::QNodesEditor::\r
70 ~QNodesEditor( )\r
71 {\r
72 }\r
73 \r
74 // -------------------------------------------------------------------------\r
75 PipelineEditor::QNodesEditor::\r
76 TWorkspace* PipelineEditor::QNodesEditor::\r
77 workspace( )\r
78 {\r
79   return( this->m_Workspace );\r
80 }\r
81 \r
82 // -------------------------------------------------------------------------\r
83 const PipelineEditor::QNodesEditor::\r
84 TWorkspace* PipelineEditor::QNodesEditor::\r
85 workspace( ) const\r
86 {\r
87   return( this->m_Workspace );\r
88 }\r
89 \r
90 // -------------------------------------------------------------------------\r
91 void PipelineEditor::QNodesEditor::\r
92 setWorkspace( TWorkspace* ws )\r
93 {\r
94   this->m_Workspace = ws;\r
95   this->m_Graph = TGraph::New( );\r
96 \r
97   // Create blocks\r
98   auto vIt = this->m_Workspace->GetGraph( )->BeginVertices( );\r
99   auto vIt_end = this->m_Workspace->GetGraph( )->EndVertices( );\r
100   for( ; vIt != vIt_end; ++vIt )\r
101   {\r
102     this->_CreateBlock(\r
103       dynamic_cast< TFilter* >( vIt->second.GetPointer( ) ),\r
104       QPointF( vIt->second->GetViewX( ), vIt->second->GetViewY( ) )\r
105       );\r
106 \r
107   } // rof\r
108 \r
109   // Add edges\r
110   auto rIt = this->m_Workspace->GetGraph( )->BeginEdgesRows( );\r
111   auto rIt_end = this->m_Workspace->GetGraph( )->EndEdgesRows( );\r
112   for( ; rIt != rIt_end; ++rIt )\r
113   {\r
114     QNEBlock* orig = this->m_Graph->GetVertex( rIt->first );\r
115     auto cIt = rIt->second.begin( );\r
116     for( ; cIt != rIt->second.end( ); ++cIt )\r
117     {\r
118       QNEBlock* dest = this->m_Graph->GetVertex( cIt->first );\r
119       auto eIt = cIt->second.begin( );\r
120       for( ; eIt != cIt->second.end( ); ++eIt )\r
121       {\r
122         QNEOutputPort* op = orig->outputPort( eIt->first.c_str( ) );\r
123         QNEInputPort* ip = dest->inputPort( eIt->second.c_str( ) );\r
124         if( op == NULL || ip == NULL )\r
125           continue;\r
126 \r
127         QNEConnection* c = new QNEConnection( 0, this->m_Scene );\r
128         c->setPort1( op );\r
129         c->setPort2( ip );\r
130         c->updatePosFromPorts( );\r
131         c->updatePath( );\r
132         this->m_Graph->AddConnection( rIt->first, cIt->first, c );\r
133 \r
134       } // rof\r
135 \r
136     } // rof\r
137 \r
138   } // rof\r
139 }\r
140 \r
141 // -------------------------------------------------------------------------\r
142 std::string PipelineEditor::QNodesEditor::\r
143 createFilter( const std::string& filter, const QPointF& pnt )\r
144 {\r
145   std::string name = filter;\r
146   while( this->m_Workspace->HasFilter( name ) )\r
147     name += std::string( "_" );\r
148   if( this->m_Workspace->CreateFilter( filter, name ) )\r
149   {\r
150     this->_CreateBlock( this->m_Workspace->GetFilter( name ), pnt );\r
151     return( name );\r
152   }\r
153   else\r
154     return( "" );\r
155 }\r
156 \r
157 // -------------------------------------------------------------------------\r
158 void PipelineEditor::QNodesEditor::\r
159 install( QGraphicsScene* s )\r
160 {\r
161   s->installEventFilter( this );\r
162   this->m_Scene = s;\r
163 }\r
164 \r
165 // -------------------------------------------------------------------------\r
166 QGraphicsItem* PipelineEditor::QNodesEditor::\r
167 itemAt( const QPointF& pos )\r
168 {\r
169   QList< QGraphicsItem* > items =\r
170     this->m_Scene->items( QRectF( pos - QPointF( 1, 1 ), QSize( 3, 3 ) ) );\r
171 \r
172   foreach( QGraphicsItem* item, items )\r
173     if( item->type( ) > QGraphicsItem::UserType )\r
174       return( item );\r
175   return( NULL );\r
176 }\r
177 \r
178 // -------------------------------------------------------------------------\r
179 void PipelineEditor::QNodesEditor::\r
180 _CreateBlock( TFilter* f, const QPointF& pnt )\r
181 {\r
182   if( f == NULL )\r
183     return;\r
184 \r
185   // Add block\r
186   QNEBlock* b = new QNEBlock( f, 0, this->m_Scene );\r
187   b->setPos( pnt );\r
188 \r
189   // Keep a trace of this visual graph\r
190   this->m_Graph->SetVertex( f->GetName( ), b );\r
191 }\r
192 \r
193 // -------------------------------------------------------------------------\r
194 /* TODO\r
195 void PipelineEditor::QNodesEditor::\r
196 _DoubleClick( QGraphicsSceneMouseEvent* evt, QGraphicsItem* item )\r
197 {\r
198   switch( evt->button( ) )\r
199   {\r
200   case Qt::LeftButton:\r
201   {\r
202     QNEBlock* block = dynamic_cast< QNEBlock* >( item );\r
203     QNEPort* port = dynamic_cast< QNEPort* >( item );\r
204     QNEConnection* conn = dynamic_cast< QNEConnection* >( item );\r
205 \r
206     if( block != NULL )\r
207     {\r
208       QString old_name = block->namePort( );\r
209       bool ok;\r
210       QString new_name =\r
211         QInputDialog::getText(\r
212           dynamic_cast< QWidget* >( this->parent( ) ),\r
213           "Change filter name",\r
214           "Filter name:",\r
215           QLineEdit::Normal,\r
216           old_name,\r
217           &ok\r
218           );\r
219       if( ok && !new_name.isEmpty( ) && old_name != new_name )\r
220       {\r
221         ok = this->m_Graph->RenameVertex(\r
222           old_name.toStdString( ),\r
223           new_name.toStdString( )\r
224           );\r
225         if( ok )\r
226         {\r
227           block->setNamePort( new_name );\r
228           this->m_Workspace->GetGraph( )->RenameVertex(\r
229             old_name.toStdString( ),\r
230             new_name.toStdString( )\r
231             );\r
232 \r
233         } // fi\r
234 \r
235       } // fi\r
236     }\r
237     else if( port != NULL )\r
238     {\r
239     }\r
240     else if( conn != NULL )\r
241     {\r
242     } // fi\r
243   }\r
244   break;\r
245      case Qt::RightButton:\r
246      {\r
247      }\r
248      break;\r
249      case Qt::MiddleButton:\r
250      {\r
251      }\r
252      break;\r
253   default:\r
254     break;\r
255   } // hctiws\r
256 }\r
257   */\r
258 \r
259 // -------------------------------------------------------------------------\r
260 bool PipelineEditor::QNodesEditor::\r
261 eventFilter( QObject* o, QEvent* e )\r
262 {\r
263   // Event type\r
264   switch( int( e->type( ) ) )\r
265   {\r
266     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneContextMenu, e );\r
267     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneDragEnter, e );\r
268     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneDragLeave, e );\r
269     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneDragMove, e );\r
270     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneDrop, e );\r
271     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneHelp, e );\r
272     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneHoverEnter, e );\r
273     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneHoverLeave, e );\r
274     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneHoverMove, e );\r
275     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneMouseDoubleClick, e );\r
276     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneMouseMove, e );\r
277     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneMousePress, e );\r
278     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneMouseRelease, e );\r
279     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneMove, e );\r
280     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneResize, e );\r
281     PipelineEditor_QNodesEditor_Callback_SWITCH( GraphicsSceneWheel, e );\r
282   default:\r
283     break;\r
284   } // hctiws\r
285 \r
286   return( this->Superclass::eventFilter( o, e ) );\r
287 }\r
288 \r
289 // -------------------------------------------------------------------------\r
290 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneContextMenu )\r
291 {\r
292 }\r
293 \r
294 // -------------------------------------------------------------------------\r
295 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneDragEnter )\r
296 {\r
297 }\r
298 \r
299 // -------------------------------------------------------------------------\r
300 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneDragLeave )\r
301 {\r
302 }\r
303 \r
304 // -------------------------------------------------------------------------\r
305 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneDragMove )\r
306 {\r
307 }\r
308 \r
309 // -------------------------------------------------------------------------\r
310 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneDrop )\r
311 {\r
312 }\r
313 \r
314 // -------------------------------------------------------------------------\r
315 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneHelp )\r
316 {\r
317 }\r
318 \r
319 // -------------------------------------------------------------------------\r
320 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneHoverEnter )\r
321 {\r
322 }\r
323 \r
324 // -------------------------------------------------------------------------\r
325 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneHoverLeave )\r
326 {\r
327 }\r
328 \r
329 // -------------------------------------------------------------------------\r
330 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneHoverMove )\r
331 {\r
332 }\r
333 \r
334 // -------------------------------------------------------------------------\r
335 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneMouseDoubleClick )\r
336 {\r
337   QGraphicsItem* item = this->itemAt( evt->scenePos( ) );\r
338   if( item == NULL )\r
339     return;\r
340 \r
341   switch( evt->button( ) )\r
342   {\r
343   case Qt::LeftButton:\r
344   {\r
345     QNEBlock* block = dynamic_cast< QNEBlock* >( item );\r
346     QNEPort* port = dynamic_cast< QNEPort* >( item );\r
347     QNEConnection* conn = dynamic_cast< QNEConnection* >( item );\r
348 \r
349     if( block != NULL )\r
350     {\r
351       QString old_name = block->namePort( );\r
352       bool ok;\r
353       QString new_name =\r
354         QInputDialog::getText(\r
355           dynamic_cast< QWidget* >( this->parent( ) ),\r
356           "Change filter name",\r
357           "Filter name:",\r
358           QLineEdit::Normal,\r
359           old_name,\r
360           &ok\r
361           );\r
362       if( ok && !new_name.isEmpty( ) && old_name != new_name )\r
363       {\r
364         ok = this->m_Graph->RenameVertex(\r
365           old_name.toStdString( ),\r
366           new_name.toStdString( )\r
367           );\r
368         if( ok )\r
369         {\r
370           block->setNamePort( new_name );\r
371           this->m_Workspace->GetGraph( )->RenameVertex(\r
372             old_name.toStdString( ),\r
373             new_name.toStdString( )\r
374             );\r
375 \r
376         } // fi\r
377 \r
378       } // fi\r
379     }\r
380     else if( port != NULL )\r
381     {\r
382       if( evt->modifiers( ) == Qt::ControlModifier )\r
383       {\r
384         port->setExtend( !( port->isExtended( ) ) );\r
385         QNEInputPort* in_port = dynamic_cast< QNEInputPort* >( port );\r
386         QNEOutputPort* out_port = dynamic_cast< QNEOutputPort* >( port );\r
387         if( port->isExtended( ) )\r
388         {\r
389           if( in_port != NULL )\r
390           {\r
391             this->m_Workspace->AddInputPort(\r
392               in_port->extendedName( ).toStdString( ),\r
393               in_port->block( )->namePort( ).toStdString( ),\r
394               in_port->name( ).toStdString( )\r
395               );\r
396           }\r
397           else if( out_port != NULL )\r
398           {\r
399           } // fi\r
400         }\r
401         else\r
402         {\r
403           if( in_port != NULL )\r
404           {\r
405           }\r
406           else if( out_port != NULL )\r
407           {\r
408           } // fi\r
409 \r
410         } // fi\r
411         this->m_Scene->update( );\r
412       }\r
413       else if( evt->modifiers( ) == Qt::NoModifier )\r
414       {\r
415         if( port->isExtended( ) )\r
416         {\r
417           QString old_name = port->extendedName( );\r
418           bool ok;\r
419           QString new_name =\r
420             QInputDialog::getText(\r
421               dynamic_cast< QWidget* >( this->parent( ) ),\r
422               "Change filter name",\r
423               "Filter name:",\r
424               QLineEdit::Normal,\r
425               old_name,\r
426               &ok\r
427               );\r
428           if( ok && !new_name.isEmpty( ) && old_name != new_name )\r
429           {\r
430             // TODO: port->setExtendedName( new_name );\r
431             /* TODO\r
432                ok = this->m_Graph->RenameVertex(\r
433                old_name.toStdString( ),\r
434                new_name.toStdString( )\r
435                );\r
436                if( ok )\r
437                {\r
438                block->setNamePort( new_name );\r
439                this->m_Workspace->GetGraph( )->RenameVertex(\r
440                old_name.toStdString( ),\r
441                new_name.toStdString( )\r
442                );\r
443 \r
444                } // fi\r
445             */\r
446           } // fi\r
447 \r
448         } // fi\r
449 \r
450       } // fi\r
451     }\r
452     else if( conn != NULL )\r
453     {\r
454     } // fi\r
455   }\r
456   break;\r
457   /* TODO:\r
458      case Qt::RightButton:\r
459      {\r
460      }\r
461      break;\r
462      case Qt::MiddleButton:\r
463      {\r
464      }\r
465      break;\r
466   */\r
467   default:\r
468     break;\r
469   } // hctiws\r
470 }\r
471 \r
472 // -------------------------------------------------------------------------\r
473 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneMouseMove )\r
474 {\r
475   if( this->m_Conn != NULL )\r
476   {\r
477     if( this->m_Conn->port1( ) == NULL )\r
478       this->m_Conn->setPos1( evt->scenePos( ) );\r
479     else if( this->m_Conn->port2( ) == NULL )\r
480       this->m_Conn->setPos2( evt->scenePos( ) );\r
481     this->m_Conn->updatePath( );\r
482 \r
483   } // fi\r
484 }\r
485 \r
486 // -------------------------------------------------------------------------\r
487 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneMousePress )\r
488 {\r
489   QNEInputPort* in_port =\r
490     dynamic_cast< QNEInputPort* >( this->itemAt( evt->scenePos( ) ) );\r
491   QNEOutputPort* out_port =\r
492     dynamic_cast< QNEOutputPort* >( this->itemAt( evt->scenePos( ) ) );\r
493   if( in_port == NULL && out_port == NULL )\r
494     return;\r
495 \r
496   switch( evt->button( ) )\r
497   {\r
498   case Qt::LeftButton:\r
499   {\r
500     if( out_port != NULL )\r
501     {\r
502       if( out_port->block( ) != NULL )\r
503       {\r
504         // Start new connection\r
505         this->m_Conn = new QNEConnection( 0, this->m_Scene );\r
506         this->m_Conn->setPort1( out_port );\r
507         this->m_Conn->setPos1( out_port->scenePos( ) );\r
508         this->m_Conn->setPos2( evt->scenePos( ) );\r
509         this->m_Conn->updatePosFromPorts( );\r
510         this->m_Conn->updatePath( );\r
511 \r
512       } // fi\r
513 \r
514     } // fi\r
515   }\r
516   break;\r
517   default:\r
518     break;\r
519 \r
520   } // hctiws\r
521 }\r
522 \r
523 // -------------------------------------------------------------------------\r
524 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneMouseRelease )\r
525 {\r
526   if( this->m_Conn == NULL )\r
527     return;\r
528 \r
529   switch( evt->button( ) )\r
530   {\r
531   case Qt::LeftButton:\r
532   {\r
533     QNEInputPort* port2 =\r
534       dynamic_cast< QNEInputPort* >( this->itemAt( evt->scenePos( ) ) );\r
535     if( port2 != NULL )\r
536     {\r
537       QNEOutputPort* port1 =\r
538         dynamic_cast< QNEOutputPort* >( this->m_Conn->port1( ) );\r
539       if( port1 != NULL )\r
540       {\r
541         if(\r
542           port1->block( ) != port2->block( ) &&\r
543           !port2->hasConnection( ) &&\r
544           !port1->isConnected( port2 ) &&\r
545           !port2->isExtended( )\r
546           )\r
547         {\r
548           this->m_Conn->setPos2( port2->scenePos( ) );\r
549           this->m_Conn->setPort2( port2 );\r
550           this->m_Conn->updatePosFromPorts( );\r
551           this->m_Conn->updatePath( );\r
552 \r
553           this->m_Workspace->Connect(\r
554             port1->block( )->namePort( ).toStdString( ),\r
555             port2->block( )->namePort( ).toStdString( ),\r
556             port1->name( ).toStdString( ),\r
557             port2->name( ).toStdString( )\r
558             );\r
559           this->m_Graph->AddConnection(\r
560             port1->block( )->namePort( ).toStdString( ),\r
561             port2->block( )->namePort( ).toStdString( ),\r
562             this->m_Conn\r
563             );\r
564         }\r
565         else\r
566           delete this->m_Conn;\r
567       }\r
568       else\r
569         delete this->m_Conn;\r
570     }\r
571     else\r
572       delete this->m_Conn;\r
573     this->m_Conn = NULL;\r
574   }\r
575   break;\r
576   default:\r
577     break;\r
578   } // hctisw\r
579 }\r
580 \r
581 // -------------------------------------------------------------------------\r
582 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneMove )\r
583 {\r
584 }\r
585 \r
586 // -------------------------------------------------------------------------\r
587 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneResize )\r
588 {\r
589 }\r
590 \r
591 // -------------------------------------------------------------------------\r
592 PipelineEditor_QNodesEditor_Callback_CODE( GraphicsSceneWheel )\r
593 {\r
594 }\r
595 \r
596 // eof - $RCSfile$\r