]> Creatis software - cpPlugins.git/blob - lib/cpBaseQtApplication/Editor.cxx
...
[cpPlugins.git] / lib / cpBaseQtApplication / Editor.cxx
1 #include <cpBaseQtApplication/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 <QGraphicsView>\r
14 #include <QInputDialog>\r
15 #include <QMessageBox>\r
16 \r
17 #include <cpBaseQtApplication/Port.h>\r
18 #include <cpBaseQtApplication/Connection.h>\r
19 #include <cpBaseQtApplication/Block.h>\r
20 #include <cpBaseQtApplication/MainWindow.h>\r
21 \r
22 // -------------------------------------------------------------------------\r
23 #define cpBaseQtApplication_Editor_Callback_SWITCH( E, e )              \\r
24   case QEvent::GraphicsScene##E:                                        \\r
25   {                                                                     \\r
26     QGraphicsScene##E##Event* evt =                                     \\r
27       dynamic_cast< QGraphicsScene##E##Event* >( e );                   \\r
28     if( evt != NULL )                                                   \\r
29       this->_##E##_cbk( evt );                                          \\r
30   }                                                                     \\r
31   break;\r
32 \r
33 // -------------------------------------------------------------------------\r
34 #define cpBaseQtApplication_Editor_Callback_CODE( E )                   \\r
35   void cpBaseQtApplication::Editor::_##E##_cbk( QGraphicsScene##E##Event* evt )\r
36 \r
37 // -------------------------------------------------------------------------\r
38 cpBaseQtApplication::Editor::\r
39 Editor( QObject* parent )\r
40   : Superclass( parent ),\r
41     m_ActualConnection( NULL ),\r
42     m_Workspace( NULL ),\r
43     m_MainWindow( NULL )\r
44 {\r
45   // Infere MainWindow\r
46   QObject* pIt = parent;\r
47   while( pIt != NULL && dynamic_cast< MainWindow* >( pIt ) == NULL )\r
48     pIt = pIt->parent( );\r
49   this->m_MainWindow = dynamic_cast< MainWindow* >( pIt );\r
50 }\r
51 \r
52 // -------------------------------------------------------------------------\r
53 cpBaseQtApplication::Editor::\r
54 ~Editor( )\r
55 {\r
56 }\r
57 \r
58 // -------------------------------------------------------------------------\r
59 cpBaseQtApplication::Editor::\r
60 TWorkspace* cpBaseQtApplication::Editor::\r
61 workspace( )\r
62 {\r
63   return( this->m_Workspace );\r
64 }\r
65 \r
66 // -------------------------------------------------------------------------\r
67 const cpBaseQtApplication::Editor::\r
68 TWorkspace* cpBaseQtApplication::Editor::\r
69 workspace( ) const\r
70 {\r
71   return( this->m_Workspace );\r
72 }\r
73 \r
74 // -------------------------------------------------------------------------\r
75 void cpBaseQtApplication::Editor::\r
76 setWorkspace( TWorkspace* ws )\r
77 {\r
78   this->m_Workspace = ws;\r
79   this->redrawWorkspace( );\r
80 }\r
81 \r
82 // -------------------------------------------------------------------------\r
83 void cpBaseQtApplication::Editor::\r
84 redrawWorkspace( )\r
85 {\r
86   this->clear( );\r
87   if( this->m_Workspace.IsNull( ) )\r
88     return;\r
89 \r
90   // Create blocks\r
91   std::map< std::string, Block* > blocks;\r
92   auto filters = this->m_Workspace->GetFiltersNames( );\r
93   for( auto f = filters.begin( ); f != filters.end( ); ++f )\r
94   {\r
95     auto obj = this->m_Workspace->GetFilter( *f );\r
96     blocks[ *f ] = this->_createBlock(\r
97       obj, f->c_str( ),\r
98       QPointF( obj->GetViewX( ), obj->GetViewY( ) )\r
99       );\r
100 \r
101   } // rof\r
102 \r
103   // Create edges\r
104   for( auto f = filters.begin( ); f != filters.end( ); ++f )\r
105   {\r
106     auto bf = blocks[ *f ];\r
107     for( auto e = filters.begin( ); e != filters.end( ); ++e )\r
108     {\r
109       auto be = blocks[ *e ];\r
110       auto edges = this->m_Workspace->GetConnections( *f, *e );\r
111       for( auto c = edges.begin( ); c != edges.end( ); ++c )\r
112       {\r
113         OutputPort* op = bf->outputPort( c->first.c_str( ) );\r
114         InputPort* ip = be->inputPort( c->second.c_str( ) );\r
115         if( op == NULL || ip == NULL )\r
116           continue;\r
117 \r
118         Connection* conn = new Connection( 0, this->m_Scene );\r
119         conn->setPort1( op );\r
120         conn->setPort2( ip );\r
121         conn->updatePosFromPorts( );\r
122         conn->updatePath( );\r
123 \r
124       } // rof\r
125 \r
126     } // rof\r
127 \r
128   } // rof\r
129 \r
130   // Exposed inputs\r
131   const auto& exp_inputs = this->m_Workspace->GetExposedInputs( );\r
132   for( auto eIt = exp_inputs.begin( ); eIt != exp_inputs.end( ); ++eIt )\r
133   {\r
134     auto bl = blocks[ eIt->second.first ];\r
135     auto ip = bl->inputPort( eIt->second.second.c_str( ) );\r
136     ip->setExtend( true );\r
137     ip->setExtendedName( eIt->first.c_str( ) );\r
138 \r
139   } // rof\r
140 \r
141   // Exposed outputs\r
142   const auto& exp_outputs = this->m_Workspace->GetExposedOutputs( );\r
143   for( auto eIt = exp_outputs.begin( ); eIt != exp_outputs.end( ); ++eIt )\r
144   {\r
145     auto bl = blocks[ eIt->second.first ];\r
146     auto op = bl->outputPort( eIt->second.second.c_str( ) );\r
147     op->setExtend( true );\r
148     op->setExtendedName( eIt->first.c_str( ) );\r
149 \r
150   } // rof\r
151 }\r
152 \r
153 // -------------------------------------------------------------------------\r
154 std::string cpBaseQtApplication::Editor::\r
155 createFilter(\r
156   const std::string& category, const std::string& filter, const QPointF& pnt\r
157   )\r
158 {\r
159   std::string name = filter;\r
160   while( this->m_Workspace->HasFilter( name ) )\r
161     name += std::string( "_" );\r
162 \r
163   auto obj = this->m_Workspace->CreateFilter( category, filter, name );\r
164   if( obj != NULL )\r
165   {\r
166     this->_createBlock( obj, name.c_str( ), pnt );\r
167     return( name );\r
168   }\r
169   else\r
170     return( "" );\r
171 }\r
172 \r
173 // -------------------------------------------------------------------------\r
174 bool cpBaseQtApplication::Editor::\r
175 deleteFilter( const std::string& name )\r
176 {\r
177   if( this->m_Workspace.IsNotNull( ) )\r
178     return( this->m_Workspace->RemoveFilter( name ) );\r
179   else\r
180     return( false );\r
181 }\r
182 \r
183 // -------------------------------------------------------------------------\r
184 bool cpBaseQtApplication::Editor::\r
185 deleteConnection(\r
186   const std::string& src, const std::string& des,\r
187   const std::string& in, const std::string& out\r
188   )\r
189 {\r
190   if( this->m_Workspace.IsNotNull( ) )\r
191   {\r
192     this->m_Workspace->Disconnect( src, des, in, out );\r
193     return( true );\r
194   }\r
195   else\r
196     return( false );\r
197 }\r
198 \r
199 // -------------------------------------------------------------------------\r
200 void cpBaseQtApplication::Editor::\r
201 clear( )\r
202 {\r
203   this->m_Scene->clear( );\r
204   auto views = this->m_Scene->views( );\r
205   for( auto i = views.begin( ); i != views.end( ); ++i )\r
206     ( *i )->viewport( )->update( );\r
207 }\r
208 \r
209 // -------------------------------------------------------------------------\r
210 void cpBaseQtApplication::Editor::\r
211 install( QGraphicsScene* s )\r
212 {\r
213   s->installEventFilter( this );\r
214   this->m_Scene = s;\r
215 }\r
216 \r
217 // -------------------------------------------------------------------------\r
218 QGraphicsItem* cpBaseQtApplication::Editor::\r
219 itemAt( const QPointF& pos )\r
220 {\r
221   QList< QGraphicsItem* > items =\r
222     this->m_Scene->items( QRectF( pos - QPointF( 1, 1 ), QSize( 3, 3 ) ) );\r
223 \r
224   foreach( QGraphicsItem* item, items )\r
225     if( item->type( ) > QGraphicsItem::UserType )\r
226       return( item );\r
227   return( NULL );\r
228 }\r
229 \r
230 // -------------------------------------------------------------------------\r
231 cpBaseQtApplication::Block* cpBaseQtApplication::Editor::\r
232 _createBlock( TFilter* f, const QString& name, const QPointF& pnt )\r
233 {\r
234   if( f == NULL )\r
235     return( NULL );\r
236   Block* b = new Block( f, name, 0, this->m_Scene );\r
237   b->setEditor( this );\r
238   b->setPos( pnt );\r
239   return( b );\r
240 }\r
241 \r
242 // -------------------------------------------------------------------------\r
243 bool cpBaseQtApplication::Editor::\r
244 eventFilter( QObject* o, QEvent* e )\r
245 {\r
246   // Event type\r
247   switch( int( e->type( ) ) )\r
248   {\r
249     cpBaseQtApplication_Editor_Callback_SWITCH( ContextMenu, e );\r
250     cpBaseQtApplication_Editor_Callback_SWITCH( DragEnter, e );\r
251     cpBaseQtApplication_Editor_Callback_SWITCH( DragLeave, e );\r
252     cpBaseQtApplication_Editor_Callback_SWITCH( DragMove, e );\r
253     cpBaseQtApplication_Editor_Callback_SWITCH( Drop, e );\r
254     cpBaseQtApplication_Editor_Callback_SWITCH( Help, e );\r
255     cpBaseQtApplication_Editor_Callback_SWITCH( HoverEnter, e );\r
256     cpBaseQtApplication_Editor_Callback_SWITCH( HoverLeave, e );\r
257     cpBaseQtApplication_Editor_Callback_SWITCH( HoverMove, e );\r
258     cpBaseQtApplication_Editor_Callback_SWITCH( MouseDoubleClick, e );\r
259     cpBaseQtApplication_Editor_Callback_SWITCH( MouseMove, e );\r
260     cpBaseQtApplication_Editor_Callback_SWITCH( MousePress, e );\r
261     cpBaseQtApplication_Editor_Callback_SWITCH( MouseRelease, e );\r
262     cpBaseQtApplication_Editor_Callback_SWITCH( Move, e );\r
263     cpBaseQtApplication_Editor_Callback_SWITCH( Resize, e );\r
264     cpBaseQtApplication_Editor_Callback_SWITCH( Wheel, e );\r
265   default:\r
266     break;\r
267   } // hctiws\r
268   return( this->Superclass::eventFilter( o, e ) );\r
269 }\r
270 \r
271 // -------------------------------------------------------------------------\r
272 void cpBaseQtApplication::Editor::\r
273 updateFilter( const std::string& filter_name )\r
274 {\r
275   if( this->m_MainWindow != NULL )\r
276     this->m_MainWindow->updateFilter( filter_name );\r
277 }\r
278 \r
279 // -------------------------------------------------------------------------\r
280 void cpBaseQtApplication::Editor::\r
281 showData( const std::string& name, const std::string& port )\r
282 {\r
283   if( this->m_MainWindow != NULL )\r
284     this->m_MainWindow->showData( name, port );\r
285 }\r
286 \r
287 // -------------------------------------------------------------------------\r
288 void cpBaseQtApplication::Editor::\r
289 hideData( const std::string& name, const std::string& port )\r
290 {\r
291   /* TODO\r
292      if( this->m_MainWindow != NULL )\r
293      this->m_MainWindow->hideData( name, port );\r
294   */\r
295 }\r
296 \r
297 // -------------------------------------------------------------------------\r
298 void cpBaseQtApplication::Editor::\r
299 dataProperties( const std::string& name, const std::string& port )\r
300 {\r
301   if( this->m_MainWindow != NULL )\r
302     this->m_MainWindow->dataProperties( name, port );\r
303 }\r
304 \r
305 // -------------------------------------------------------------------------\r
306 cpBaseQtApplication_Editor_Callback_CODE( ContextMenu )\r
307 {\r
308 }\r
309 \r
310 // -------------------------------------------------------------------------\r
311 cpBaseQtApplication_Editor_Callback_CODE( DragEnter )\r
312 {\r
313 }\r
314 \r
315 // -------------------------------------------------------------------------\r
316 cpBaseQtApplication_Editor_Callback_CODE( DragLeave )\r
317 {\r
318 }\r
319 \r
320 // -------------------------------------------------------------------------\r
321 cpBaseQtApplication_Editor_Callback_CODE( DragMove )\r
322 {\r
323 }\r
324 \r
325 // -------------------------------------------------------------------------\r
326 cpBaseQtApplication_Editor_Callback_CODE( Drop )\r
327 {\r
328 }\r
329 \r
330 // -------------------------------------------------------------------------\r
331 cpBaseQtApplication_Editor_Callback_CODE( Help )\r
332 {\r
333 }\r
334 \r
335 // -------------------------------------------------------------------------\r
336 cpBaseQtApplication_Editor_Callback_CODE( HoverEnter )\r
337 {\r
338 }\r
339 \r
340 // -------------------------------------------------------------------------\r
341 cpBaseQtApplication_Editor_Callback_CODE( HoverLeave )\r
342 {\r
343 }\r
344 \r
345 // -------------------------------------------------------------------------\r
346 cpBaseQtApplication_Editor_Callback_CODE( HoverMove )\r
347 {\r
348 }\r
349 \r
350 // -------------------------------------------------------------------------\r
351 cpBaseQtApplication_Editor_Callback_CODE( MouseDoubleClick )\r
352 {\r
353   // Get clicked item\r
354   QGraphicsItem* item = this->itemAt( evt->scenePos( ) );\r
355   if( item == NULL )\r
356     return;\r
357   Block* block = dynamic_cast< Block* >( item );\r
358   Port* port = dynamic_cast< Port* >( item );\r
359   Connection* conn = dynamic_cast< Connection* >( item );\r
360 \r
361   if( block != NULL && evt->button( ) == Qt::LeftButton )\r
362   {\r
363     if( evt->modifiers( ) == Qt::NoModifier )\r
364     {\r
365       QString old_name = block->namePort( );\r
366       bool ok;\r
367       QString new_name =\r
368         QInputDialog::getText(\r
369           dynamic_cast< QWidget* >( this->parent( ) ),\r
370           "Change filter name",\r
371           "Filter name:",\r
372           QLineEdit::Normal,\r
373           old_name,\r
374           &ok\r
375           );\r
376       if( ok && !new_name.isEmpty( ) && old_name != new_name )\r
377       {\r
378         if(\r
379           this->m_Workspace->RenameFilter(\r
380             old_name.toStdString( ), new_name.toStdString( )\r
381             )\r
382           )\r
383           block->setNamePort( new_name );\r
384 \r
385       } // fi\r
386 \r
387     } // fi\r
388   }\r
389   else if( port != NULL && evt->button( ) == Qt::LeftButton )\r
390   {\r
391     if( evt->modifiers( ) == Qt::ControlModifier )\r
392     {\r
393       port->setExtend( !( port->isExtended( ) ) );\r
394       InputPort* in_port = dynamic_cast< InputPort* >( port );\r
395       OutputPort* out_port = dynamic_cast< OutputPort* >( port );\r
396       if( port->isExtended( ) )\r
397       {\r
398         auto ename = port->extendedName( ).toStdString( );\r
399         if( ename == "" )\r
400         {\r
401           auto fname = port->block( )->namePort( ).toStdString( );\r
402           auto pname = port->name( ).toStdString( );\r
403           ename = pname + std::string( "@" ) + fname;\r
404           port->setExtendedName( ename.c_str( ) );\r
405 \r
406         } // fi\r
407 \r
408         if( in_port != NULL )\r
409           this->m_Workspace->ExposeInput(\r
410             in_port->extendedName( ).toStdString( ),\r
411             in_port->block( )->namePort( ).toStdString( ),\r
412             in_port->name( ).toStdString( )\r
413             );\r
414         else if( out_port != NULL )\r
415           this->m_Workspace->ExposeOutput(\r
416             out_port->extendedName( ).toStdString( ),\r
417             out_port->block( )->namePort( ).toStdString( ),\r
418             out_port->name( ).toStdString( )\r
419             );\r
420       }\r
421       else\r
422       {\r
423         if( in_port != NULL )\r
424           this->m_Workspace->HideInput(\r
425             in_port->extendedName( ).toStdString( )\r
426             );\r
427         else if( out_port != NULL )\r
428           this->m_Workspace->HideOutput(\r
429             out_port->extendedName( ).toStdString( )\r
430             );\r
431 \r
432       } // fi\r
433     }\r
434     else if( evt->modifiers( ) == Qt::NoModifier )\r
435     {\r
436       if( port->isExtended( ) )\r
437       {\r
438         QString old_name = port->extendedName( );\r
439         bool ok;\r
440         QString new_name =\r
441           QInputDialog::getText(\r
442             dynamic_cast< QWidget* >( this->parent( ) ),\r
443             "Change filter name",\r
444             "Filter name:",\r
445             QLineEdit::Normal,\r
446             old_name,\r
447             &ok\r
448             );\r
449         if( ok && !new_name.isEmpty( ) && old_name != new_name )\r
450         {\r
451           InputPort* in_port = dynamic_cast< InputPort* >( port );\r
452           OutputPort* out_port = dynamic_cast< OutputPort* >( port );\r
453           bool success = false;\r
454           if( in_port != NULL )\r
455             success = this->m_Workspace->RenameExposedInput(\r
456               old_name.toStdString( ), new_name.toStdString( )\r
457               );\r
458           else if( out_port != NULL )\r
459             success = this->m_Workspace->RenameExposedOutput(\r
460               old_name.toStdString( ), new_name.toStdString( )\r
461               );\r
462           if( success )\r
463           {\r
464             port->setExtendedName( new_name );\r
465             this->m_Scene->update( );\r
466 \r
467           } // fi\r
468           \r
469         } // fi\r
470 \r
471       } // fi\r
472 \r
473     } // fi\r
474 \r
475   } // fi\r
476 }\r
477 \r
478 // -------------------------------------------------------------------------\r
479 cpBaseQtApplication_Editor_Callback_CODE( MouseMove )\r
480 {\r
481   if( this->m_ActualConnection != NULL )\r
482   {\r
483     if( this->m_ActualConnection->port1( ) == NULL )\r
484       this->m_ActualConnection->setPos1( evt->scenePos( ) );\r
485     else if( this->m_ActualConnection->port2( ) == NULL )\r
486       this->m_ActualConnection->setPos2( evt->scenePos( ) );\r
487     this->m_ActualConnection->updatePath( );\r
488 \r
489   } // fi\r
490 }\r
491 \r
492 // -------------------------------------------------------------------------\r
493 cpBaseQtApplication_Editor_Callback_CODE( MousePress )\r
494 {\r
495   InputPort* in_port =\r
496     dynamic_cast< InputPort* >( this->itemAt( evt->scenePos( ) ) );\r
497   OutputPort* out_port =\r
498     dynamic_cast< OutputPort* >( this->itemAt( evt->scenePos( ) ) );\r
499   if( in_port == NULL && out_port == NULL )\r
500     return;\r
501 \r
502   switch( evt->button( ) )\r
503   {\r
504   case Qt::LeftButton:\r
505   {\r
506     if( out_port != NULL )\r
507     {\r
508       if( out_port->block( ) != NULL )\r
509       {\r
510         // Start new connection\r
511         this->m_ActualConnection = new Connection( 0, this->m_Scene );\r
512         this->m_ActualConnection->setPort1( out_port );\r
513         this->m_ActualConnection->setPos1( out_port->scenePos( ) );\r
514         this->m_ActualConnection->setPos2( evt->scenePos( ) );\r
515         this->m_ActualConnection->updatePosFromPorts( );\r
516         this->m_ActualConnection->updatePath( );\r
517 \r
518       } // fi\r
519 \r
520     } // fi\r
521   }\r
522   break;\r
523   default:\r
524     break;\r
525 \r
526   } // hctiws\r
527 }\r
528 \r
529 // -------------------------------------------------------------------------\r
530 cpBaseQtApplication_Editor_Callback_CODE( MouseRelease )\r
531 {\r
532   if( this->m_ActualConnection == NULL )\r
533     return;\r
534 \r
535   switch( evt->button( ) )\r
536   {\r
537   case Qt::LeftButton:\r
538   {\r
539     InputPort* in =\r
540       dynamic_cast< InputPort* >( this->itemAt( evt->scenePos( ) ) );\r
541     OutputPort* out =\r
542       dynamic_cast< OutputPort* >( this->m_ActualConnection->port1( ) );\r
543     if( in != NULL && out != NULL )\r
544     {\r
545       if(\r
546         in->block( ) != out->block( ) &&\r
547         ( !in->hasConnection( ) || in->isMultiple( ) ) &&\r
548         !in->isConnected( out ) &&\r
549         !out->isExtended( )\r
550         )\r
551       {\r
552         std::string d_filter = in->block( )->namePort( ).toStdString( );\r
553         std::string o_filter = out->block( )->namePort( ).toStdString( );\r
554         std::string d_port = in->name( ).toStdString( );\r
555         std::string o_port = out->name( ).toStdString( );\r
556         try\r
557         {\r
558           this->m_Workspace->Connect( o_filter, d_filter, o_port, d_port );\r
559           this->m_ActualConnection->setPos2( in->scenePos( ) );\r
560           this->m_ActualConnection->setPort2( in );\r
561           this->m_ActualConnection->updatePosFromPorts( );\r
562           this->m_ActualConnection->updatePath( );\r
563         }\r
564         catch( std::exception& err )\r
565         {\r
566           delete this->m_ActualConnection;\r
567           QMessageBox::critical(\r
568             NULL,\r
569             QMessageBox::tr( "Error connecting ports" ),\r
570             QMessageBox::tr( err.what( ) )\r
571             );\r
572 \r
573         } // yrt\r
574       }\r
575       else\r
576         delete this->m_ActualConnection;\r
577     }\r
578     else\r
579       delete this->m_ActualConnection;\r
580     this->m_ActualConnection = NULL;\r
581   }\r
582   break;\r
583   default:\r
584     break;\r
585   } // hctisw\r
586 }\r
587 \r
588 // -------------------------------------------------------------------------\r
589 cpBaseQtApplication_Editor_Callback_CODE( Move )\r
590 {\r
591 }\r
592 \r
593 // -------------------------------------------------------------------------\r
594 cpBaseQtApplication_Editor_Callback_CODE( Resize )\r
595 {\r
596 }\r
597 \r
598 // -------------------------------------------------------------------------\r
599 cpBaseQtApplication_Editor_Callback_CODE( Wheel )\r
600 {\r
601 }\r
602 \r
603 // eof - $RCSfile$\r