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