]> Creatis software - cpPlugins.git/blob - lib/cpPipelineEditor/Editor.cxx
237bb5815cb76af3a14b05dbca88498be9083c72
[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 void cpPipelineEditor::Editor::\r
152 _createBlock( TFilter* f, const QPointF& pnt )\r
153 {\r
154   if( f == NULL )\r
155     return;\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   // Keep a trace of this visual graph\r
162   this->m_Graph->SetVertex( f->GetName( ), b );\r
163 }\r
164 \r
165 // -------------------------------------------------------------------------\r
166 bool cpPipelineEditor::Editor::\r
167 eventFilter( QObject* o, QEvent* e )\r
168 {\r
169   // Event type\r
170   switch( int( e->type( ) ) )\r
171   {\r
172     cpPipelineEditor_Editor_Callback_SWITCH( ContextMenu, e );\r
173     cpPipelineEditor_Editor_Callback_SWITCH( DragEnter, e );\r
174     cpPipelineEditor_Editor_Callback_SWITCH( DragLeave, e );\r
175     cpPipelineEditor_Editor_Callback_SWITCH( DragMove, e );\r
176     cpPipelineEditor_Editor_Callback_SWITCH( Drop, e );\r
177     cpPipelineEditor_Editor_Callback_SWITCH( Help, e );\r
178     cpPipelineEditor_Editor_Callback_SWITCH( HoverEnter, e );\r
179     cpPipelineEditor_Editor_Callback_SWITCH( HoverLeave, e );\r
180     cpPipelineEditor_Editor_Callback_SWITCH( HoverMove, e );\r
181     cpPipelineEditor_Editor_Callback_SWITCH( MouseDoubleClick, e );\r
182     cpPipelineEditor_Editor_Callback_SWITCH( MouseMove, e );\r
183     cpPipelineEditor_Editor_Callback_SWITCH( MousePress, e );\r
184     cpPipelineEditor_Editor_Callback_SWITCH( MouseRelease, e );\r
185     cpPipelineEditor_Editor_Callback_SWITCH( Move, e );\r
186     cpPipelineEditor_Editor_Callback_SWITCH( Resize, e );\r
187     cpPipelineEditor_Editor_Callback_SWITCH( Wheel, e );\r
188   default:\r
189     break;\r
190   } // hctiws\r
191   return( this->Superclass::eventFilter( o, e ) );\r
192 }\r
193 \r
194 // -------------------------------------------------------------------------\r
195 cpPipelineEditor_Editor_Callback_CODE( ContextMenu )\r
196 {\r
197 }\r
198 \r
199 // -------------------------------------------------------------------------\r
200 cpPipelineEditor_Editor_Callback_CODE( DragEnter )\r
201 {\r
202 }\r
203 \r
204 // -------------------------------------------------------------------------\r
205 cpPipelineEditor_Editor_Callback_CODE( DragLeave )\r
206 {\r
207 }\r
208 \r
209 // -------------------------------------------------------------------------\r
210 cpPipelineEditor_Editor_Callback_CODE( DragMove )\r
211 {\r
212 }\r
213 \r
214 // -------------------------------------------------------------------------\r
215 cpPipelineEditor_Editor_Callback_CODE( Drop )\r
216 {\r
217 }\r
218 \r
219 // -------------------------------------------------------------------------\r
220 cpPipelineEditor_Editor_Callback_CODE( Help )\r
221 {\r
222 }\r
223 \r
224 // -------------------------------------------------------------------------\r
225 cpPipelineEditor_Editor_Callback_CODE( HoverEnter )\r
226 {\r
227 }\r
228 \r
229 // -------------------------------------------------------------------------\r
230 cpPipelineEditor_Editor_Callback_CODE( HoverLeave )\r
231 {\r
232 }\r
233 \r
234 // -------------------------------------------------------------------------\r
235 cpPipelineEditor_Editor_Callback_CODE( HoverMove )\r
236 {\r
237 }\r
238 \r
239 // -------------------------------------------------------------------------\r
240 cpPipelineEditor_Editor_Callback_CODE( MouseDoubleClick )\r
241 {\r
242   QGraphicsItem* item = this->itemAt( evt->scenePos( ) );\r
243   if( item == NULL )\r
244     return;\r
245 \r
246   switch( evt->button( ) )\r
247   {\r
248   case Qt::LeftButton:\r
249   {\r
250     Block* block = dynamic_cast< Block* >( item );\r
251     Port* port = dynamic_cast< Port* >( item );\r
252     Connection* conn = dynamic_cast< Connection* >( item );\r
253 \r
254     if( block != NULL )\r
255     {\r
256       QString old_name = block->namePort( );\r
257       bool ok;\r
258       QString new_name =\r
259         QInputDialog::getText(\r
260           dynamic_cast< QWidget* >( this->parent( ) ),\r
261           "Change filter name",\r
262           "Filter name:",\r
263           QLineEdit::Normal,\r
264           old_name,\r
265           &ok\r
266           );\r
267       if( ok && !new_name.isEmpty( ) && old_name != new_name )\r
268       {\r
269         ok = this->m_Graph->RenameVertex(\r
270           old_name.toStdString( ),\r
271           new_name.toStdString( )\r
272           );\r
273         if( ok )\r
274         {\r
275           block->setNamePort( new_name );\r
276           this->m_Workspace->RenameFilter(\r
277             old_name.toStdString( ),\r
278             new_name.toStdString( )\r
279             );\r
280 \r
281         } // fi\r
282 \r
283       } // fi\r
284     }\r
285     else if( port != NULL )\r
286     {\r
287       if( evt->modifiers( ) == Qt::ControlModifier )\r
288       {\r
289         port->setExtend( !( port->isExtended( ) ) );\r
290         InputPort* in_port = dynamic_cast< InputPort* >( port );\r
291         OutputPort* out_port = dynamic_cast< OutputPort* >( port );\r
292         if( port->isExtended( ) )\r
293         {\r
294           if( in_port != NULL )\r
295           {\r
296             this->m_Workspace->ExposeInputPort(\r
297               in_port->extendedName( ).toStdString( ),\r
298               in_port->block( )->namePort( ).toStdString( ),\r
299               in_port->name( ).toStdString( )\r
300               );\r
301           }\r
302           else if( out_port != NULL )\r
303           {\r
304             this->m_Workspace->ExposeOutputPort(\r
305               out_port->extendedName( ).toStdString( ),\r
306               out_port->block( )->namePort( ).toStdString( ),\r
307               out_port->name( ).toStdString( )\r
308               );\r
309 \r
310           } // fi\r
311         }\r
312         else\r
313         {\r
314           if( in_port != NULL )\r
315             this->m_Workspace->HideInputPort(\r
316               in_port->extendedName( ).toStdString( )\r
317               );\r
318           else if( out_port != NULL )\r
319             this->m_Workspace->HideOutputPort(\r
320               out_port->extendedName( ).toStdString( )\r
321               );\r
322 \r
323         } // fi\r
324         this->m_Scene->update( );\r
325       }\r
326       else if( evt->modifiers( ) == Qt::NoModifier )\r
327       {\r
328         if( port->isExtended( ) )\r
329         {\r
330           QString old_name = port->extendedName( );\r
331           bool ok;\r
332           QString new_name =\r
333             QInputDialog::getText(\r
334               dynamic_cast< QWidget* >( this->parent( ) ),\r
335               "Change filter name",\r
336               "Filter name:",\r
337               QLineEdit::Normal,\r
338               old_name,\r
339               &ok\r
340               );\r
341           if( ok && !new_name.isEmpty( ) && old_name != new_name )\r
342           {\r
343             port->setExtendedName( new_name );\r
344             InputPort* in_port = dynamic_cast< InputPort* >( port );\r
345             OutputPort* out_port = dynamic_cast< OutputPort* >( port );\r
346             if( in_port != NULL )\r
347               this->m_Workspace->\r
348                 RenameExposedInputPort(\r
349                   old_name.toStdString( ),\r
350                   new_name.toStdString( )\r
351                   );\r
352             else if( out_port != NULL )\r
353               this->m_Workspace->\r
354                 RenameExposedOutputPort(\r
355                   old_name.toStdString( ),\r
356                   new_name.toStdString( )\r
357                   );\r
358             this->m_Scene->update( );\r
359 \r
360           } // fi\r
361 \r
362         } // fi\r
363 \r
364       } // fi\r
365     }\r
366     else if( conn != NULL )\r
367     {\r
368     } // fi\r
369   }\r
370   break;\r
371   /* TODO:\r
372      case Qt::RightButton:\r
373      {\r
374      }\r
375      break;\r
376      case Qt::MiddleButton:\r
377      {\r
378      }\r
379      break;\r
380   */\r
381   default:\r
382     break;\r
383   } // hctiws\r
384 }\r
385 \r
386 // -------------------------------------------------------------------------\r
387 cpPipelineEditor_Editor_Callback_CODE( MouseMove )\r
388 {\r
389   if( this->m_ActualConnection != NULL )\r
390   {\r
391     if( this->m_ActualConnection->port1( ) == NULL )\r
392       this->m_ActualConnection->setPos1( evt->scenePos( ) );\r
393     else if( this->m_ActualConnection->port2( ) == NULL )\r
394       this->m_ActualConnection->setPos2( evt->scenePos( ) );\r
395     this->m_ActualConnection->updatePath( );\r
396 \r
397   } // fi\r
398 }\r
399 \r
400 // -------------------------------------------------------------------------\r
401 cpPipelineEditor_Editor_Callback_CODE( MousePress )\r
402 {\r
403   InputPort* in_port =\r
404     dynamic_cast< InputPort* >( this->itemAt( evt->scenePos( ) ) );\r
405   OutputPort* out_port =\r
406     dynamic_cast< OutputPort* >( this->itemAt( evt->scenePos( ) ) );\r
407   if( in_port == NULL && out_port == NULL )\r
408     return;\r
409 \r
410   switch( evt->button( ) )\r
411   {\r
412   case Qt::LeftButton:\r
413   {\r
414     if( out_port != NULL )\r
415     {\r
416       if( out_port->block( ) != NULL )\r
417       {\r
418         // Start new connection\r
419         this->m_ActualConnection = new Connection( 0, this->m_Scene );\r
420         this->m_ActualConnection->setPort1( out_port );\r
421         this->m_ActualConnection->setPos1( out_port->scenePos( ) );\r
422         this->m_ActualConnection->setPos2( evt->scenePos( ) );\r
423         this->m_ActualConnection->updatePosFromPorts( );\r
424         this->m_ActualConnection->updatePath( );\r
425 \r
426       } // fi\r
427 \r
428     } // fi\r
429   }\r
430   break;\r
431   default:\r
432     break;\r
433 \r
434   } // hctiws\r
435 }\r
436 \r
437 // -------------------------------------------------------------------------\r
438 cpPipelineEditor_Editor_Callback_CODE( MouseRelease )\r
439 {\r
440   if( this->m_ActualConnection == NULL )\r
441     return;\r
442 \r
443   switch( evt->button( ) )\r
444   {\r
445   case Qt::LeftButton:\r
446   {\r
447     InputPort* port2 =\r
448       dynamic_cast< InputPort* >( this->itemAt( evt->scenePos( ) ) );\r
449     if( port2 != NULL )\r
450     {\r
451       OutputPort* port1 =\r
452         dynamic_cast< OutputPort* >( this->m_ActualConnection->port1( ) );\r
453       if( port1 != NULL )\r
454       {\r
455         if(\r
456           port1->block( ) != port2->block( ) &&\r
457           !port2->hasConnection( ) &&\r
458           !port1->isConnected( port2 ) &&\r
459           !port2->isExtended( )\r
460           )\r
461         {\r
462           this->m_ActualConnection->setPos2( port2->scenePos( ) );\r
463           this->m_ActualConnection->setPort2( port2 );\r
464           this->m_ActualConnection->updatePosFromPorts( );\r
465           this->m_ActualConnection->updatePath( );\r
466 \r
467           this->m_Workspace->Connect(\r
468             port1->block( )->namePort( ).toStdString( ),\r
469             port2->block( )->namePort( ).toStdString( ),\r
470             port1->name( ).toStdString( ),\r
471             port2->name( ).toStdString( )\r
472             );\r
473           this->m_Graph->AddEdge(\r
474             port1->block( )->namePort( ).toStdString( ),\r
475             port2->block( )->namePort( ).toStdString( ),\r
476             this->m_ActualConnection\r
477             );\r
478         }\r
479         else\r
480           delete this->m_ActualConnection;\r
481       }\r
482       else\r
483         delete this->m_ActualConnection;\r
484     }\r
485     else\r
486       delete this->m_ActualConnection;\r
487     this->m_ActualConnection = NULL;\r
488   }\r
489   break;\r
490   default:\r
491     break;\r
492   } // hctisw\r
493 }\r
494 \r
495 // -------------------------------------------------------------------------\r
496 cpPipelineEditor_Editor_Callback_CODE( Move )\r
497 {\r
498 }\r
499 \r
500 // -------------------------------------------------------------------------\r
501 cpPipelineEditor_Editor_Callback_CODE( Resize )\r
502 {\r
503 }\r
504 \r
505 // -------------------------------------------------------------------------\r
506 cpPipelineEditor_Editor_Callback_CODE( Wheel )\r
507 {\r
508 }\r
509 \r
510 // eof - $RCSfile$\r