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