]> 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   return( false );\r
136 }\r
137 \r
138 // -------------------------------------------------------------------------\r
139 bool cpPipelineEditor::Editor::\r
140 deleteConnection(\r
141   const std::string& src, const std::string& des,\r
142   const std::string& in, const std::string& out\r
143   )\r
144 {\r
145   std::cout\r
146     << src << " "\r
147     << des << " "\r
148     << in << " "\r
149     << out << std::endl;\r
150   return( false );\r
151 }\r
152 \r
153 // -------------------------------------------------------------------------\r
154 void cpPipelineEditor::Editor::\r
155 install( QGraphicsScene* s )\r
156 {\r
157   s->installEventFilter( this );\r
158   this->m_Scene = s;\r
159 }\r
160 \r
161 // -------------------------------------------------------------------------\r
162 QGraphicsItem* cpPipelineEditor::Editor::\r
163 itemAt( const QPointF& pos )\r
164 {\r
165   QList< QGraphicsItem* > items =\r
166     this->m_Scene->items( QRectF( pos - QPointF( 1, 1 ), QSize( 3, 3 ) ) );\r
167 \r
168   foreach( QGraphicsItem* item, items )\r
169     if( item->type( ) > QGraphicsItem::UserType )\r
170       return( item );\r
171   return( NULL );\r
172 }\r
173 \r
174 // -------------------------------------------------------------------------\r
175 cpPipelineEditor::Block* cpPipelineEditor::Editor::\r
176 _createBlock( TFilter* f, const QPointF& pnt )\r
177 {\r
178   if( f == NULL )\r
179     return( NULL );\r
180 \r
181   // Add block\r
182   Block* b = new Block( f, 0, this->m_Scene );\r
183   b->setEditor( this );\r
184   b->setPos( pnt );\r
185 \r
186   // Mark exposed inputs\r
187   auto& e_in = this->m_Workspace->GetExposedInputPorts( );\r
188   auto f_in = f->GetInputsNames( );\r
189   for( auto iIt = f_in.begin( ); iIt != f_in.end( ); ++iIt )\r
190   {\r
191     auto eIt = e_in.begin( );\r
192     auto fIt = e_in.end( );\r
193     for( ; eIt != e_in.end( ) && fIt == e_in.end( ); ++eIt )\r
194       if( eIt->second.second == *iIt )\r
195         fIt = eIt;\r
196     if( fIt == e_in.end( ) )\r
197       continue;\r
198     \r
199     auto port = b->inputPort( iIt->c_str( ) );\r
200     port->setExtendedName( fIt->first.c_str( ) );\r
201     port->setExtend( true );\r
202 \r
203   } // rof\r
204 \r
205   // Mark exposed outputs\r
206   auto& e_out = this->m_Workspace->GetExposedOutputPorts( );\r
207   auto f_out = f->GetOutputsNames( );\r
208   for( auto iIt = f_out.begin( ); iIt != f_out.end( ); ++iIt )\r
209   {\r
210     auto eIt = e_out.begin( );\r
211     auto fIt = e_out.end( );\r
212     for( ; eIt != e_out.end( ) && fIt == e_out.end( ); ++eIt )\r
213       if( eIt->second.second == *iIt )\r
214         fIt = eIt;\r
215     if( fIt == e_out.end( ) )\r
216       continue;\r
217     \r
218     auto port = b->outputPort( iIt->c_str( ) );\r
219     port->setExtendedName( fIt->first.c_str( ) );\r
220     port->setExtend( true );\r
221 \r
222   } // rof\r
223 \r
224   // Keep a trace of this visual graph\r
225   this->m_Graph->SetVertex( f->GetName( ), b );\r
226   return( b );\r
227 }\r
228 \r
229 // -------------------------------------------------------------------------\r
230 bool cpPipelineEditor::Editor::\r
231 eventFilter( QObject* o, QEvent* e )\r
232 {\r
233   // Event type\r
234   switch( int( e->type( ) ) )\r
235   {\r
236     cpPipelineEditor_Editor_Callback_SWITCH( ContextMenu, e );\r
237     cpPipelineEditor_Editor_Callback_SWITCH( DragEnter, e );\r
238     cpPipelineEditor_Editor_Callback_SWITCH( DragLeave, e );\r
239     cpPipelineEditor_Editor_Callback_SWITCH( DragMove, e );\r
240     cpPipelineEditor_Editor_Callback_SWITCH( Drop, e );\r
241     cpPipelineEditor_Editor_Callback_SWITCH( Help, e );\r
242     cpPipelineEditor_Editor_Callback_SWITCH( HoverEnter, e );\r
243     cpPipelineEditor_Editor_Callback_SWITCH( HoverLeave, e );\r
244     cpPipelineEditor_Editor_Callback_SWITCH( HoverMove, e );\r
245     cpPipelineEditor_Editor_Callback_SWITCH( MouseDoubleClick, e );\r
246     cpPipelineEditor_Editor_Callback_SWITCH( MouseMove, e );\r
247     cpPipelineEditor_Editor_Callback_SWITCH( MousePress, e );\r
248     cpPipelineEditor_Editor_Callback_SWITCH( MouseRelease, e );\r
249     cpPipelineEditor_Editor_Callback_SWITCH( Move, e );\r
250     cpPipelineEditor_Editor_Callback_SWITCH( Resize, e );\r
251     cpPipelineEditor_Editor_Callback_SWITCH( Wheel, e );\r
252   default:\r
253     break;\r
254   } // hctiws\r
255   return( this->Superclass::eventFilter( o, e ) );\r
256 }\r
257 \r
258 // -------------------------------------------------------------------------\r
259 void cpPipelineEditor::Editor::\r
260 updateFilter( const std::string& filter_name )\r
261 {\r
262   emit execFilter( filter_name );\r
263 }\r
264 \r
265 // -------------------------------------------------------------------------\r
266 void cpPipelineEditor::Editor::\r
267 showOutputData(\r
268   const std::string& filter_name, const std::string& output_name\r
269   )\r
270 {\r
271   emit showFilterOutput( filter_name, output_name );\r
272 }\r
273 \r
274 // -------------------------------------------------------------------------\r
275 cpPipelineEditor_Editor_Callback_CODE( ContextMenu )\r
276 {\r
277 }\r
278 \r
279 // -------------------------------------------------------------------------\r
280 cpPipelineEditor_Editor_Callback_CODE( DragEnter )\r
281 {\r
282 }\r
283 \r
284 // -------------------------------------------------------------------------\r
285 cpPipelineEditor_Editor_Callback_CODE( DragLeave )\r
286 {\r
287 }\r
288 \r
289 // -------------------------------------------------------------------------\r
290 cpPipelineEditor_Editor_Callback_CODE( DragMove )\r
291 {\r
292 }\r
293 \r
294 // -------------------------------------------------------------------------\r
295 cpPipelineEditor_Editor_Callback_CODE( Drop )\r
296 {\r
297 }\r
298 \r
299 // -------------------------------------------------------------------------\r
300 cpPipelineEditor_Editor_Callback_CODE( Help )\r
301 {\r
302 }\r
303 \r
304 // -------------------------------------------------------------------------\r
305 cpPipelineEditor_Editor_Callback_CODE( HoverEnter )\r
306 {\r
307 }\r
308 \r
309 // -------------------------------------------------------------------------\r
310 cpPipelineEditor_Editor_Callback_CODE( HoverLeave )\r
311 {\r
312 }\r
313 \r
314 // -------------------------------------------------------------------------\r
315 cpPipelineEditor_Editor_Callback_CODE( HoverMove )\r
316 {\r
317 }\r
318 \r
319 // -------------------------------------------------------------------------\r
320 cpPipelineEditor_Editor_Callback_CODE( MouseDoubleClick )\r
321 {\r
322   QGraphicsItem* item = this->itemAt( evt->scenePos( ) );\r
323   if( item == NULL )\r
324     return;\r
325 \r
326   switch( evt->button( ) )\r
327   {\r
328   case Qt::LeftButton:\r
329   {\r
330     Block* block = dynamic_cast< Block* >( item );\r
331     Port* port = dynamic_cast< Port* >( item );\r
332     Connection* conn = dynamic_cast< Connection* >( item );\r
333 \r
334     if( block != NULL )\r
335     {\r
336       QString old_name = block->namePort( );\r
337       bool ok;\r
338       QString new_name =\r
339         QInputDialog::getText(\r
340           dynamic_cast< QWidget* >( this->parent( ) ),\r
341           "Change filter name",\r
342           "Filter name:",\r
343           QLineEdit::Normal,\r
344           old_name,\r
345           &ok\r
346           );\r
347       if( ok && !new_name.isEmpty( ) && old_name != new_name )\r
348       {\r
349         ok = this->m_Graph->RenameVertex(\r
350           old_name.toStdString( ),\r
351           new_name.toStdString( )\r
352           );\r
353         if( ok )\r
354         {\r
355           block->setNamePort( new_name );\r
356           this->m_Workspace->RenameFilter(\r
357             old_name.toStdString( ),\r
358             new_name.toStdString( )\r
359             );\r
360 \r
361         } // fi\r
362 \r
363       } // fi\r
364     }\r
365     else if( port != NULL )\r
366     {\r
367       if( evt->modifiers( ) == Qt::ControlModifier )\r
368       {\r
369         port->setExtend( !( port->isExtended( ) ) );\r
370         InputPort* in_port = dynamic_cast< InputPort* >( port );\r
371         OutputPort* out_port = dynamic_cast< OutputPort* >( port );\r
372         if( port->isExtended( ) )\r
373         {\r
374           if( in_port != NULL )\r
375           {\r
376             this->m_Workspace->ExposeInputPort(\r
377               in_port->extendedName( ).toStdString( ),\r
378               in_port->block( )->namePort( ).toStdString( ),\r
379               in_port->name( ).toStdString( )\r
380               );\r
381           }\r
382           else if( out_port != NULL )\r
383           {\r
384             this->m_Workspace->ExposeOutputPort(\r
385               out_port->extendedName( ).toStdString( ),\r
386               out_port->block( )->namePort( ).toStdString( ),\r
387               out_port->name( ).toStdString( )\r
388               );\r
389 \r
390           } // fi\r
391         }\r
392         else\r
393         {\r
394           if( in_port != NULL )\r
395             this->m_Workspace->HideInputPort(\r
396               in_port->extendedName( ).toStdString( )\r
397               );\r
398           else if( out_port != NULL )\r
399             this->m_Workspace->HideOutputPort(\r
400               out_port->extendedName( ).toStdString( )\r
401               );\r
402 \r
403         } // fi\r
404         this->m_Scene->update( );\r
405       }\r
406       else if( evt->modifiers( ) == Qt::NoModifier )\r
407       {\r
408         if( port->isExtended( ) )\r
409         {\r
410           QString old_name = port->extendedName( );\r
411           bool ok;\r
412           QString new_name =\r
413             QInputDialog::getText(\r
414               dynamic_cast< QWidget* >( this->parent( ) ),\r
415               "Change filter name",\r
416               "Filter name:",\r
417               QLineEdit::Normal,\r
418               old_name,\r
419               &ok\r
420               );\r
421           if( ok && !new_name.isEmpty( ) && old_name != new_name )\r
422           {\r
423             port->setExtendedName( new_name );\r
424             InputPort* in_port = dynamic_cast< InputPort* >( port );\r
425             OutputPort* out_port = dynamic_cast< OutputPort* >( port );\r
426             if( in_port != NULL )\r
427               this->m_Workspace->\r
428                 RenameExposedInputPort(\r
429                   old_name.toStdString( ),\r
430                   new_name.toStdString( )\r
431                   );\r
432             else if( out_port != NULL )\r
433               this->m_Workspace->\r
434                 RenameExposedOutputPort(\r
435                   old_name.toStdString( ),\r
436                   new_name.toStdString( )\r
437                   );\r
438             this->m_Scene->update( );\r
439 \r
440           } // fi\r
441 \r
442         } // fi\r
443 \r
444       } // fi\r
445     }\r
446     else if( conn != NULL )\r
447     {\r
448     } // fi\r
449   }\r
450   break;\r
451   /* TODO:\r
452      case Qt::RightButton:\r
453      {\r
454      }\r
455      break;\r
456      case Qt::MiddleButton:\r
457      {\r
458      }\r
459      break;\r
460   */\r
461   default:\r
462     break;\r
463   } // hctiws\r
464 }\r
465 \r
466 // -------------------------------------------------------------------------\r
467 cpPipelineEditor_Editor_Callback_CODE( MouseMove )\r
468 {\r
469   if( this->m_ActualConnection != NULL )\r
470   {\r
471     if( this->m_ActualConnection->port1( ) == NULL )\r
472       this->m_ActualConnection->setPos1( evt->scenePos( ) );\r
473     else if( this->m_ActualConnection->port2( ) == NULL )\r
474       this->m_ActualConnection->setPos2( evt->scenePos( ) );\r
475     this->m_ActualConnection->updatePath( );\r
476 \r
477   } // fi\r
478 }\r
479 \r
480 // -------------------------------------------------------------------------\r
481 cpPipelineEditor_Editor_Callback_CODE( MousePress )\r
482 {\r
483   InputPort* in_port =\r
484     dynamic_cast< InputPort* >( this->itemAt( evt->scenePos( ) ) );\r
485   OutputPort* out_port =\r
486     dynamic_cast< OutputPort* >( this->itemAt( evt->scenePos( ) ) );\r
487   if( in_port == NULL && out_port == NULL )\r
488     return;\r
489 \r
490   switch( evt->button( ) )\r
491   {\r
492   case Qt::LeftButton:\r
493   {\r
494     if( out_port != NULL )\r
495     {\r
496       if( out_port->block( ) != NULL )\r
497       {\r
498         // Start new connection\r
499         this->m_ActualConnection = new Connection( 0, this->m_Scene );\r
500         this->m_ActualConnection->setPort1( out_port );\r
501         this->m_ActualConnection->setPos1( out_port->scenePos( ) );\r
502         this->m_ActualConnection->setPos2( evt->scenePos( ) );\r
503         this->m_ActualConnection->updatePosFromPorts( );\r
504         this->m_ActualConnection->updatePath( );\r
505 \r
506       } // fi\r
507 \r
508     } // fi\r
509   }\r
510   break;\r
511   default:\r
512     break;\r
513 \r
514   } // hctiws\r
515 }\r
516 \r
517 // -------------------------------------------------------------------------\r
518 cpPipelineEditor_Editor_Callback_CODE( MouseRelease )\r
519 {\r
520   if( this->m_ActualConnection == NULL )\r
521     return;\r
522 \r
523   switch( evt->button( ) )\r
524   {\r
525   case Qt::LeftButton:\r
526   {\r
527     InputPort* port2 =\r
528       dynamic_cast< InputPort* >( this->itemAt( evt->scenePos( ) ) );\r
529     if( port2 != NULL )\r
530     {\r
531       OutputPort* port1 =\r
532         dynamic_cast< OutputPort* >( this->m_ActualConnection->port1( ) );\r
533       if( port1 != NULL )\r
534       {\r
535         if(\r
536           port1->block( ) != port2->block( ) &&\r
537           !port2->hasConnection( ) &&\r
538           !port1->isConnected( port2 ) &&\r
539           !port2->isExtended( )\r
540           )\r
541         {\r
542           this->m_ActualConnection->setPos2( port2->scenePos( ) );\r
543           this->m_ActualConnection->setPort2( port2 );\r
544           this->m_ActualConnection->updatePosFromPorts( );\r
545           this->m_ActualConnection->updatePath( );\r
546 \r
547           this->m_Workspace->Connect(\r
548             port1->block( )->namePort( ).toStdString( ),\r
549             port2->block( )->namePort( ).toStdString( ),\r
550             port1->name( ).toStdString( ),\r
551             port2->name( ).toStdString( )\r
552             );\r
553           this->m_Graph->AddEdge(\r
554             port1->block( )->namePort( ).toStdString( ),\r
555             port2->block( )->namePort( ).toStdString( ),\r
556             this->m_ActualConnection\r
557             );\r
558         }\r
559         else\r
560           delete this->m_ActualConnection;\r
561       }\r
562       else\r
563         delete this->m_ActualConnection;\r
564     }\r
565     else\r
566       delete this->m_ActualConnection;\r
567     this->m_ActualConnection = NULL;\r
568   }\r
569   break;\r
570   default:\r
571     break;\r
572   } // hctisw\r
573 }\r
574 \r
575 // -------------------------------------------------------------------------\r
576 cpPipelineEditor_Editor_Callback_CODE( Move )\r
577 {\r
578 }\r
579 \r
580 // -------------------------------------------------------------------------\r
581 cpPipelineEditor_Editor_Callback_CODE( Resize )\r
582 {\r
583 }\r
584 \r
585 // -------------------------------------------------------------------------\r
586 cpPipelineEditor_Editor_Callback_CODE( Wheel )\r
587 {\r
588 }\r
589 \r
590 // eof - $RCSfile$\r