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