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