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