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