]> Creatis software - cpPlugins.git/blob - lib/cpBaseQtApplication/Pipeline/Canvas.cxx
8457187719a91b8cf73799d3afc8ca83f64462ff
[cpPlugins.git] / lib / cpBaseQtApplication / Pipeline / Canvas.cxx
1 #include <cpBaseQtApplication/Pipeline/Canvas.h>
2 #include <cpBaseQtApplication/Pipeline/EventFilter.h>
3 #include <cpBaseQtApplication/Pipeline/Block.h>
4 #include <cpBaseQtApplication/Pipeline/Connection.h>
5 #include <cpBaseQtApplication/Pipeline/Port.h>
6
7 #include <QDragEnterEvent>
8 #include <QInputDialog>
9 #include <QMessageBox>
10 #include <QWheelEvent>
11 #include <QTreeWidget>
12
13 // -------------------------------------------------------------------------
14 cpBaseQtApplication::Pipeline::Canvas::
15 Canvas( QWidget* parent )
16   : Superclass( parent ),
17     m_Workspace( NULL ),
18     m_ActualConnection( NULL ),
19     m_OutputPortReceiver( NULL ),
20     m_OutputPortSlot( "" )
21 {
22   this->m_Scene = new QGraphicsScene( this );
23   this->setScene( this->m_Scene );
24   this->setRenderHint( QPainter::Antialiasing );
25   this->setAcceptDrops( true );
26
27   this->m_EventFilter = new EventFilter( this );
28   this->m_EventFilter->setCanvas( this );
29   this->m_EventFilter->install( this->m_Scene );
30 }
31
32 // -------------------------------------------------------------------------
33 cpBaseQtApplication::Pipeline::Canvas::
34 ~Canvas( )
35 {
36 }
37
38 // -------------------------------------------------------------------------
39 void cpBaseQtApplication::Pipeline::Canvas::
40 clear( )
41 {
42   qDeleteAll( this->m_Scene->items( ) );
43   this->m_Blocks.clear( );
44   this->m_ActualConnection = NULL;
45 }
46
47 // -------------------------------------------------------------------------
48 cpBaseQtApplication::Pipeline::Canvas::
49 TWorkspace* cpBaseQtApplication::Pipeline::Canvas::
50 workspace( )
51 {
52   return( this->m_Workspace );
53 }
54
55 // -------------------------------------------------------------------------
56 const cpBaseQtApplication::Pipeline::Canvas::
57 TWorkspace* cpBaseQtApplication::Pipeline::Canvas::
58 workspace( ) const
59 {
60   return( this->m_Workspace );
61 }
62
63 // -------------------------------------------------------------------------
64 void cpBaseQtApplication::Pipeline::Canvas::
65 setWorkspace( TWorkspace* ws )
66 {
67   if( this->m_Workspace != ws )
68   {
69     this->clear( );
70     this->m_Workspace = ws;
71
72   } // fi
73   this->_redrawWorkspace( );
74 }
75
76 // -------------------------------------------------------------------------
77 std::string cpBaseQtApplication::Pipeline::Canvas::
78 addFilter( const std::string& cat, const std::string& fil, const QPointF& pos )
79 {
80   auto filter = this->m_Workspace->CreateFilter( cat, fil );
81   Block* b = new Block( filter, NULL, this->m_Scene );
82   b->setPos( pos );
83   if( this->m_OutputPortReceiver != NULL )
84     b->connectOutputPortSlot(
85       this->m_OutputPortReceiver, this->m_OutputPortSlot.c_str( )
86       );
87   std::string name = filter->GetName( );
88   this->m_Blocks[ name ] = b;
89   return( name );
90 }
91
92 // -------------------------------------------------------------------------
93 bool cpBaseQtApplication::Pipeline::Canvas::
94 connectOutputPortSlot( QObject* receiver, const char* slot )
95 {
96   this->m_OutputPortReceiver = receiver;
97   this->m_OutputPortSlot = slot;
98   bool ok = true;
99   for( auto b : this->m_Blocks )
100     ok &= b.second->connectOutputPortSlot( receiver, slot );
101   return( ok );
102 }
103
104 // -------------------------------------------------------------------------
105 void cpBaseQtApplication::Pipeline::Canvas::
106 rename( QGraphicsItem* item )
107 {
108   if( this->m_Workspace == NULL )
109     return;
110
111   Block* b = dynamic_cast< Block* >( item );
112   if( b != NULL )
113   {
114     std::string old_n = b->filter( )->GetName( );
115     bool ok;
116     std::string new_n =
117       QInputDialog::getText(
118         dynamic_cast< QWidget* >( this->parent( ) ),
119         "Change filter name",
120         "Filter name:",
121         QLineEdit::Normal,
122         old_n.c_str( ),
123         &ok
124         ).toStdString( );
125     if( ok && new_n != "" && old_n != new_n )
126     {
127       if( this->m_Workspace->RenameFilter( old_n, new_n ) )
128       {
129         auto bIt = this->m_Blocks.find( old_n );
130         this->m_Blocks[ new_n ] = bIt->second;
131         bIt->second->setNamePort( new_n.c_str( ) );
132         this->m_Blocks.erase( bIt );
133
134       } // fi
135
136     } // fi
137
138   } // fi
139 }
140
141 // -------------------------------------------------------------------------
142 void cpBaseQtApplication::Pipeline::Canvas::
143 exposePort( QGraphicsItem* item )
144 {
145 }
146
147 // -------------------------------------------------------------------------
148 void cpBaseQtApplication::Pipeline::Canvas::
149 moveConnection( const QPointF& pnt )
150 {
151   if( this->m_ActualConnection != NULL )
152   {
153      if( this->m_ActualConnection->port1( ) == NULL )
154        this->m_ActualConnection->setPos1( pnt );
155      else if( this->m_ActualConnection->port2( ) == NULL )
156        this->m_ActualConnection->setPos2( pnt );
157      this->m_ActualConnection->updatePath( );
158
159   } // fi
160 }
161
162 // -------------------------------------------------------------------------
163 void cpBaseQtApplication::Pipeline::Canvas::
164 grab( const QPointF& pnt )
165 {
166   QGraphicsItem* item = this->m_Scene->itemAt( pnt );
167   OutputPort* oport = dynamic_cast< OutputPort* >( item );
168   if( oport != NULL )
169   {
170     // Start new connection
171     this->m_ActualConnection = new Connection( 0, this->m_Scene );
172     this->m_ActualConnection->setPort1( oport );
173     this->m_ActualConnection->setPos1( oport->scenePos( ) );
174     this->m_ActualConnection->setPos2( pnt );
175     this->m_ActualConnection->updatePosFromPorts( );
176     this->m_ActualConnection->updatePath( );
177
178   } // fi
179 }
180
181 // -------------------------------------------------------------------------
182 void cpBaseQtApplication::Pipeline::Canvas::
183 release( const QPointF& pnt )
184 {
185   if( this->m_ActualConnection == NULL || this->m_Workspace == NULL )
186     return;
187
188   QGraphicsItem* item = this->m_Scene->itemAt( pnt );
189   InputPort* iport = dynamic_cast< InputPort* >( item );
190   OutputPort* oport =
191     dynamic_cast< OutputPort* >( this->m_ActualConnection->port1( ) );
192   if( iport != NULL && oport != NULL )
193   {
194     Block* iblock = iport->block( );
195     Block* oblock = oport->block( );
196     std::string ofil = oblock->namePort( ).toStdString( );
197     std::string dfil = iblock->namePort( ).toStdString( );
198     std::string oname = oport->name( ).toStdString( );
199     std::string dname = iport->name( ).toStdString( );
200     try
201     {
202       if( this->m_Workspace->Connect( ofil, oname, dfil, dname ) )
203       {
204         this->m_ActualConnection->setPos2( iport->scenePos( ) );
205         this->m_ActualConnection->setPort2( iport );
206         this->m_ActualConnection->updatePosFromPorts( );
207         this->m_ActualConnection->updatePath( );
208       }
209       else
210         delete this->m_ActualConnection;
211     }
212     catch( std::exception& err )
213     {
214       delete this->m_ActualConnection;
215       QMessageBox::critical(
216         NULL,
217         QMessageBox::tr( "Error connecting ports" ),
218         QMessageBox::tr( err.what( ) )
219         );
220
221     } // yrt
222     this->m_ActualConnection = NULL;
223   }
224   else
225   {
226     delete this->m_ActualConnection;
227     this->m_ActualConnection = NULL;
228     
229   } // fi
230 }
231
232 // -------------------------------------------------------------------------
233 void cpBaseQtApplication::Pipeline::Canvas::
234 keyPressEvent( QKeyEvent* event )
235 {
236   static const int del_key = 16777223;
237   if( this->m_Workspace == NULL )
238     return;
239
240   switch( event->key( ) )
241   {
242   case del_key:
243   {
244     // Get items to delete
245     auto _items = this->items( );
246     auto i = _items.begin( );
247     std::set< Block* > blocks_to_delete;
248     std::set< Connection* > connections_to_delete;
249     while( i != _items.end( ) )
250     {
251       if( ( *i )->isSelected( ) )
252       {
253         Block* b = dynamic_cast< Block* >( *i );
254         Connection* c = dynamic_cast< Connection* >( *i );
255         if( b != NULL )
256         {
257           blocks_to_delete.insert( b );
258           auto inputs = b->filter( )->GetInputsNames( );
259           for( auto inIt : inputs )
260           {
261             InputPort* p = b->inputPort( inIt.c_str( ) );
262             for( unsigned int j = 0; j < p->numberOfConnections( ); ++j )
263               connections_to_delete.insert( p->connection( j ) );
264
265           } // rof
266           auto outputs = b->filter( )->GetOutputsNames( );
267           for( auto outIt : outputs )
268           {
269             OutputPort* p = b->outputPort( outIt.c_str( ) );
270             auto& conns = p->connections( );
271             for( unsigned int j = 0; j < conns.size( ); ++j )
272               connections_to_delete.insert( conns[ j ] );
273
274           } // rof
275         }
276         else if( c != NULL )
277           connections_to_delete.insert( c );
278
279       } // fi
280       i++;
281
282     } // elihw
283
284     // Delete connections
285     for( auto conn : connections_to_delete )
286     {
287       OutputPort* oport = conn->port1( );
288       InputPort* iport = conn->port2( );
289       Block* oblock = oport->block( );
290       Block* iblock = iport->block( );
291       if(
292         this->m_Workspace->Disconnect(
293           oblock->namePort( ).toStdString( ),
294           oport->name( ).toStdString( ),
295           iblock->namePort( ).toStdString( ),
296           iport->name( ).toStdString( )
297           )
298         )
299         delete conn;
300
301     } // rof
302
303     // Delete blocks
304     for( auto block : blocks_to_delete )
305       if(
306         this->m_Workspace->RemoveFilter( block->namePort( ).toStdString( ) )
307         )
308         delete block;
309   }
310   break;
311   default:
312     break;
313   } // hctiws
314 }
315
316 // -------------------------------------------------------------------------
317 void cpBaseQtApplication::Pipeline::Canvas::
318 wheelEvent( QWheelEvent* event )
319 {
320   this->_scaleView(
321     std::pow( double( 2 ), event->delta( ) / double( 240 ) )
322     );
323 }
324
325 // -------------------------------------------------------------------------
326 void cpBaseQtApplication::Pipeline::Canvas::
327 dragEnterEvent( QDragEnterEvent* event )
328 {
329   const QMimeData* mime = event->mimeData( );
330   if( mime->hasFormat( "application/x-qabstractitemmodeldatalist" ) )
331     event->acceptProposedAction( );
332 }
333
334 // -------------------------------------------------------------------------
335 void cpBaseQtApplication::Pipeline::Canvas::
336 dragLeaveEvent( QDragLeaveEvent* event )
337 {
338 }
339
340 // -------------------------------------------------------------------------
341 void cpBaseQtApplication::Pipeline::Canvas::
342 dragMoveEvent( QDragMoveEvent* event )
343 {
344 }
345
346 // -------------------------------------------------------------------------
347 void cpBaseQtApplication::Pipeline::Canvas::
348 dropEvent( QDropEvent* event )
349 {
350   if( this->m_Workspace == NULL )
351     return;
352   const QMimeData* mime = event->mimeData( );
353   if( !( mime->hasFormat( "application/x-qabstractitemmodeldatalist" ) ) )
354     return;
355   event->acceptProposedAction( );
356   auto tree = dynamic_cast< QTreeWidget* >( event->source( ) );
357   if( tree == NULL )
358     return;
359
360   QPointF p = this->mapToScene( event->pos( ) );
361   QList< QTreeWidgetItem* > items = tree->selectedItems( );
362   for( auto iIt = items.begin( ); iIt != items.end( ); ++iIt )
363   {
364     auto parent = ( *iIt )->parent( );
365     if( parent != NULL )
366       this->addFilter(
367         parent->text( 0 ).toStdString( ),
368         ( *iIt )->text( 0 ).toStdString( ),
369         p
370         );
371
372   } // rof
373 }
374
375 // -------------------------------------------------------------------------
376 void cpBaseQtApplication::Pipeline::Canvas::
377 _scaleView( qreal scaleFactor )
378 {
379   qreal factor = this->transform( ).
380     scale( scaleFactor, scaleFactor ).
381     mapRect( QRectF( 0, 0, 1, 1 ) ).
382     width( );
383   if( factor < qreal( 0.07 ) || factor > qreal( 100 ) )
384     return;
385   this->scale( scaleFactor, scaleFactor );
386 }
387
388 // -------------------------------------------------------------------------
389 void cpBaseQtApplication::Pipeline::Canvas::
390 _redrawWorkspace( )
391 {
392   // Get filters names
393   if( this->m_Workspace == NULL )
394     return;
395   auto fnames = this->m_Workspace->GetFiltersNames( );
396
397   // Create blocks
398   for( auto fname : fnames )
399   {
400     auto filter = this->m_Workspace->GetFilter( fname );
401     Block* b = new Block( filter, NULL, this->m_Scene );
402     b->setPos( filter->GetViewX( ), filter->GetViewY( ) );
403     if( this->m_OutputPortReceiver != NULL )
404       b->connectOutputPortSlot(
405         this->m_OutputPortReceiver, this->m_OutputPortSlot.c_str( )
406         );
407     this->m_Blocks[ filter->GetName( ) ] = b;
408
409   } // rof
410
411   // Create connections
412   for( auto b : this->m_Blocks )
413   {
414     auto filter = b.second->filter( );
415     auto inputs = filter->GetInputsNames( );
416     for( auto in : inputs )
417     {
418       for( unsigned int id = 0; id < filter->GetInputSize( in ); ++id )
419       {
420         auto inData = filter->GetInput( in, id );
421         if( inData != NULL )
422         {
423           auto src = inData->GetSource( );
424           auto outputs = src->GetOutputsNames( );
425           std::string outName = "";
426           for( auto out : outputs )
427             if( src->GetOutput( out ) == inData )
428               outName = out;
429           auto c = this->m_Blocks.find( src->GetName( ) );
430           auto b_src = c->second;
431           auto b_des = b.second;
432           auto oport = b_src->outputPort( outName.c_str( ) );
433           auto iport = b_des->inputPort( in.c_str( ) );
434
435           auto conn = new Connection( 0, this->m_Scene );
436           conn->setPort1( oport );
437           conn->setPort2( iport );
438           conn->setPos1( oport->scenePos( ) );
439           conn->setPos2( iport->scenePos( ) );
440           conn->updatePosFromPorts( );
441           conn->updatePath( );
442
443         } // fi
444
445       } // rof
446
447     } // rof
448
449   } // rof
450 }
451
452 // eof - $RCSfile$