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