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