]> Creatis software - cpPlugins.git/blob - appli/ImageMPR/ImageMPR.cxx
Widget integration (step 6/6): Interactive architecture finished. Needs to be tested...
[cpPlugins.git] / appli / ImageMPR / ImageMPR.cxx
1 #include "ImageMPR.h"
2 #include "ui_ImageMPR.h"
3
4 // -------------------------------------------------------------------------
5 #define ImageMPR_ConnectAction( ACTION )                \
6   QObject::connect(                                     \
7     this->m_UI->a##ACTION, SIGNAL( triggered( ) ),      \
8     this, SLOT( _a##ACTION( ) )                         \
9     )
10
11 // -------------------------------------------------------------------------
12 ImageMPR::
13 ImageMPR( QWidget* parent )
14   : QMainWindow( parent ),
15     m_UI( new Ui::ImageMPR ),
16     m_ImageLoaded( "" ),
17     m_Flooding( false )
18 {
19   this->m_UI->setupUi( this );
20
21   // Associate callbacks
22   this->m_UI->MPR->AddCursorCommand( Self::_CursorCommand, this );
23
24   // Connect actions
25   ImageMPR_ConnectAction( OpenImage );
26   ImageMPR_ConnectAction( OpenSegmentation );
27   ImageMPR_ConnectAction( OpenPolyData );
28   ImageMPR_ConnectAction( SaveImage );
29   ImageMPR_ConnectAction( SaveSegmentation );
30   ImageMPR_ConnectAction( SavePolyData );
31   ImageMPR_ConnectAction( Undo );
32   ImageMPR_ConnectAction( Redo );
33   ImageMPR_ConnectAction( LoadPlugins );
34   ImageMPR_ConnectAction( ShowPlugins );
35
36   // Try to load default plugins
37   this->m_UI->MPR->LoadPlugins( );
38   this->m_UI->MPR->AssociatePluginsToMenu(
39     this->m_UI->MenuFilters, this, SLOT( _execPlugin( ) )
40     );
41 }
42
43 // -------------------------------------------------------------------------
44 ImageMPR::
45 ~ImageMPR( )
46 {
47   delete this->m_UI;
48 }
49
50 // -------------------------------------------------------------------------
51 void ImageMPR::
52 _aOpenImage( )
53 {
54   if( this->m_ImageLoaded != "" )
55     this->m_UI->MPR->ClearAll( );
56   this->m_ImageLoaded = this->m_UI->MPR->LoadImage( );
57 }
58
59 // -------------------------------------------------------------------------
60 void ImageMPR::
61 _aOpenSegmentation( )
62 {
63   if( this->m_ImageLoaded != "" )
64     this->m_ImageLoaded = this->m_UI->MPR->LoadImage( );
65 }
66
67 // -------------------------------------------------------------------------
68 void ImageMPR::
69 _aOpenPolyData( )
70 {
71 }
72
73 // -------------------------------------------------------------------------
74 void ImageMPR::
75 _aSaveImage( )
76 {
77 }
78
79 // -------------------------------------------------------------------------
80 void ImageMPR::
81 _aSaveSegmentation( )
82 {
83 }
84
85 // -------------------------------------------------------------------------
86 void ImageMPR::
87 _aSavePolyData( )
88 {
89 }
90
91 // -------------------------------------------------------------------------
92 void ImageMPR::
93 _aUndo( )
94 {
95 }
96
97 // -------------------------------------------------------------------------
98 void ImageMPR::
99 _aRedo( )
100 {
101 }
102
103 // -------------------------------------------------------------------------
104 void ImageMPR::
105 _aLoadPlugins( )
106 {
107   this->m_UI->MPR->DialogLoadPlugins( );
108   this->m_UI->MPR->AssociatePluginsToMenu(
109     this->m_UI->MenuFilters, this, SLOT( _execPlugin( ) )
110     );
111 }
112
113 // -------------------------------------------------------------------------
114 void ImageMPR::
115 _aShowPlugins( )
116 {
117 }
118
119 // -------------------------------------------------------------------------
120 void ImageMPR::
121 _execPlugin( )
122 {
123   // Get filter name
124   QAction* action = dynamic_cast< QAction* >( this->sender( ) );
125   if( action == NULL )
126     return;
127   std::string name = action->text( ).toStdString( );
128
129   if( name == "cpPlugins::BasicFilters::FloodFillImageFilter" )
130   {
131     this->m_Flooding = true;
132   }
133   else
134   {
135     this->m_Flooding = false;
136     this->m_UI->MPR->ExecuteFilter(
137       name, this->m_ImageLoaded, "SegmentedImage"
138       );
139
140   } // fi
141
142   // Configure filter
143   /*
144     TPluginFilter::Pointer filter =
145     this->m_Plugins.CreateProcessObject( name );
146     bool dlg_ok = filter->ExecConfigurationDialog( NULL );
147     if( !dlg_ok )
148     return;
149
150     // Execute filter
151     QApplication::setOverrideCursor( Qt::WaitCursor );
152     this->setEnabled( false );
153     filter->SetInput( 0, this->m_Image );
154     std::string err = filter->Update( );
155     QApplication::restoreOverrideCursor( );
156     this->setEnabled( true );
157
158     // Update image
159     if( err == "" )
160     {
161     TPluginImage* result = filter->GetOutput< TPluginImage >( 0 );
162     result->DisconnectPipeline( );
163     this->m_Image = result;
164     if( this->m_Image.IsNotNull( ) )
165     this->m_MPRObjects->SetImage(
166     this->m_Image->GetVTK< vtkImageData >( )
167     );
168     MementoState(this->m_state, this->m_Image);
169     this->m_state++;
170     if (this->m_state > this->m_max_state)
171     {
172     this->m_max_state = this->m_state;
173     }
174     }
175     else
176     QMessageBox::critical(
177     this,
178     tr( "Error executing filter" ),
179     tr( err.c_str( ) )
180     );
181   */
182 }
183
184 // -------------------------------------------------------------------------
185 void ImageMPR::
186 _CursorCommand( double* pos, int axis, void* data )
187 {
188   Self* app = reinterpret_cast< Self* >( data );
189   if( app == NULL )
190     return;
191   if( !( app->m_Flooding ) )
192     return;
193
194   cpPlugins::Interface::ProcessObject::Pointer filter =
195     app->m_UI->MPR->CreateFilter(
196       "cpPlugins::BasicFilters::FloodFillImageFilter"
197       );
198   if( filter.IsNull( ) )
199     return;
200
201   cpPlugins::Interface::Parameters* params = filter->GetParameters( );
202   params->SetPoint( "Seed", 3, pos );
203   params->SetReal( "Window", app->m_UI->MPR->GetWindow( ) );
204   params->SetReal( "Level", app->m_UI->MPR->GetLevel( ) );
205   params->SetUint( "InsideValue", 1 );
206   params->SetUint( "OutsideValue", 0 );
207   filter->SetInput( "Input", app->m_UI->MPR->GetImage( app->m_ImageLoaded ) );
208   app->m_UI->MPR->Block( );
209   std::string err = filter->Update( );
210   cpPlugins::Interface::BaseMPRWindow::TImage::Pointer image = filter->GetOutput< cpPlugins::Interface::BaseMPRWindow::TImage >( "Output" );
211   filter->DisconnectOutputs( );
212   app->m_UI->MPR->AddImage( "Segmentation", image );
213   app->m_UI->MPR->Unblock( );
214
215
216
217   /* TODO
218      std::cout
219      << "CursorCommand ==> "
220      << pos[ 0 ] << " "
221      << pos[ 1 ] << " "
222     << pos[ 2 ] << " : "
223     << axis << " "
224     << data << std::endl;
225   */
226 }
227
228 /*
229 #include "MementoState.h"
230
231 #include <vtkProperty.h>
232 #include <vtkRenderWindow.h>
233 #include <vtkMetaImageReader.h>
234
235 #include <QFileDialog>
236 #include <QMessageBox>
237
238 #ifdef _WIN32
239 #  define PLUGIN_PREFIX ""
240 #  define PLUGIN_EXT "dll"
241 #  define PLUGIN_REGEX "Plugins file (*.dll);;All files (*)"
242 #else
243 #  define PLUGIN_PREFIX "lib"
244 #  define PLUGIN_EXT "so"
245 #  define PLUGIN_REGEX "Plugins file (*.so);;All files (*)"
246 #endif // _WIN32
247
248 // -------------------------------------------------------------------------
249 ImageMPR::ImageMPR( QWidget* parent )
250   : QMainWindow( parent ),
251     m_UI( new Ui::ImageMPR ),
252     m_ImageReaderClass( "" ),
253     m_ImageWriterClass( "" ),
254     m_MeshReaderClass( "" ),
255     m_MeshWriterClass( "" ),
256     m_MeshCutterClass( "" ),
257     m_Image( NULL ),
258         m_state(0),
259         m_max_state(0)
260 {
261   this->m_UI->setupUi( this );
262
263   // Create and associate renderers
264   this->m_MPRObjects = vtkSmartPointer< TMPRObjects >::New( );
265   this->m_MPRObjects->SetRenderWindows(
266     this->m_UI->m_XPlaneVTK->GetRenderWindow( ),
267     this->m_UI->m_YPlaneVTK->GetRenderWindow( ),
268     this->m_UI->m_ZPlaneVTK->GetRenderWindow( ),
269     this->m_UI->m_3DVTK->GetRenderWindow( )
270     );
271
272   // signals <-> slots
273   QObject::connect(
274     this->m_UI->actionOpenPlugins, SIGNAL( triggered( ) ),
275     this, SLOT( _triggered_actionOpenPlugins( ) )
276     );
277   QObject::connect(
278     this->m_UI->actionOpenInputImage, SIGNAL( triggered( ) ),
279     this, SLOT( _triggered_actionOpenInputImage( ) )
280     );
281   QObject::connect(
282     this->m_UI->actionOpenSegmentation, SIGNAL( triggered( ) ),
283     this, SLOT( _triggered_actionOpenSegmentation( ) )
284     );
285   QObject::connect(
286     this->m_UI->actionOpenInputPolyData, SIGNAL( triggered( ) ),
287     this, SLOT( _triggered_actionOpenInputPolyData( ) )
288     );
289   QObject::connect(
290         this->m_UI->actionUndo, SIGNAL(triggered()),
291         this, SLOT(_triggered_actionUndo())
292         );
293   QObject::connect(
294         this->m_UI->actionRedo, SIGNAL(triggered()),
295         this, SLOT(_triggered_actionRedo())
296         );
297
298   // Start: load all disponible plugins
299   this->_LoadPlugins(
300     std::string( PLUGIN_PREFIX ) +
301     std::string( "cpPluginsIO." ) +
302     std::string( PLUGIN_EXT )
303     );
304   this->_LoadPlugins(
305     std::string( PLUGIN_PREFIX ) +
306     std::string( "cpPluginsBasicFilters." ) +
307     std::string( PLUGIN_EXT )
308     );
309 }
310
311 // -------------------------------------------------------------------------
312 ImageMPR::
313 ~ImageMPR( )
314 {
315   // Close all connections
316   this->m_Plugins.UnloadAll( );
317
318   // Delete objects
319   delete this->m_UI;
320 }
321
322 // -------------------------------------------------------------------------
323 bool ImageMPR::
324 _LoadPlugins( const std::string& filename )
325 {
326   QApplication::setOverrideCursor( Qt::WaitCursor );
327   this->setEnabled( false );
328
329   this->m_ImageReaderClass = "";
330   this->m_ImageWriterClass = "";
331   this->m_MeshReaderClass = "";
332   this->m_MeshWriterClass = "";
333   this->m_MeshCutterClass = "";
334   this->m_UI->MenuImageToImage->clear( );
335   this->m_UI->MenuImageToMesh->clear( );
336
337   if( !( this->m_Plugins.Load( filename ) ) )
338     return( false );
339
340   typedef TPluginsInterface::TClasses _TClasses;
341   _TClasses::const_iterator cIt = this->m_Plugins.GetClasses( ).begin( );
342   for( ; cIt != this->m_Plugins.GetClasses( ).end( ); ++cIt )
343   {
344     TPluginFilter::Pointer o =
345       this->m_Plugins.CreateProcessObject( cIt->first );
346     std::string name = o->GetClassName( );
347     std::string category = o->GetClassCategory( );
348     if( category == "ImageReader" )
349       this->m_ImageReaderClass = name;
350     else if( category == "ImageWriter" )
351       this->m_ImageWriterClass = name;
352     else if( category == "MeshReader" )
353       this->m_MeshReaderClass = name;
354     else if( category == "MeshWriter" )
355       this->m_MeshWriterClass = name;
356     else if( category == "MeshToMeshFilter" )
357     {
358       if( name.find_last_of( "Cutter" ) != std::string::npos )
359         this->m_MeshCutterClass = name;
360     }
361     else if( category == "ImageToImageFilter" )
362     {
363       QAction* action =
364         this->m_UI->MenuImageToImage->addAction( QString( name.c_str( ) ) );
365       QObject::connect(
366         action, SIGNAL( triggered( ) ),
367         this, SLOT( _triggered_actionImageToImage( ) )
368         );
369     }
370     else if( category == "ImageToMeshFilter" )
371     {
372       QAction* action =
373         this->m_UI->MenuImageToMesh->addAction( QString( name.c_str( ) ) );
374       QObject::connect(
375         action, SIGNAL( triggered( ) ),
376         this, SLOT( _triggered_actionImageToMesh( ) )
377         );
378
379     } // fi
380
381   } // rof
382   QApplication::restoreOverrideCursor( );
383   this->setEnabled( true );
384
385   return( true );
386 }
387
388 // -------------------------------------------------------------------------
389 std::string ImageMPR::
390 _LoadImage( TPluginImage::Pointer& image )
391 {
392   std::string ret = "";
393   image = NULL;
394
395   // Get a reader from loaded plugins
396   TPluginFilter::Pointer reader =
397     this->m_Plugins.CreateProcessObject( this->m_ImageReaderClass );
398   if( reader.IsNotNull( ) )
399   {
400     if( reader->ExecConfigurationDialog( this ) )
401     {
402       // Block application
403       QApplication::setOverrideCursor( Qt::WaitCursor );
404       this->setEnabled( false );
405
406       // Execute and get error message, if any
407       ret = reader->Update( );
408
409       // Assign fresh image, if any
410       if( ret == "" )
411       {
412         image = reader->GetOutput< TPluginImage >( 0 );
413         reader->DisconnectOutputs( );
414
415       } // fi
416
417       // Unblock application
418       QApplication::restoreOverrideCursor( );
419       this->setEnabled( true );
420
421     } // fi
422   }
423   else
424     ret = "No suitable reader object found in loaded plugins.";
425   
426   return( ret );
427 }
428
429 // -------------------------------------------------------------------------
430 std::string ImageMPR::
431 _ConfigureMeshActors( )
432 {
433   if( this->m_Mesh.IsNull( ) )
434     return( "Valid mesh not found." );
435
436   this->m_Mesh->CreateVTKActor( );
437   vtkActor* vtk_actor = this->m_Mesh->GetVTKActor( );
438   if( vtk_actor != NULL )
439   {
440     this->m_MPRObjects->Get3DRenderer( )->AddActor( vtk_actor );
441     this->m_MPRObjects->Render( 4 );
442
443   } // fi
444
445   TMPRObjects::TMPRActors* mprActors = this->m_MPRObjects->GetMPRActors( );
446
447   std::string err = "";
448   for( unsigned int i = 0; i < 3; ++i )
449   {
450     this->m_Cutters[ i ] = this->m_Plugins.CreateProcessObject( this->m_MeshCutterClass );
451     this->m_Planes[ i ] = TPluginImplicitFunction::New( );
452     this->m_Planes[ i ]->SetFunction( mprActors->GetSliceActors( i )->GetPlaneFunction( ) );
453     this->m_Cutters[ i ]->SetInput( 0, this->m_Mesh );
454     this->m_Cutters[ i ]->SetInput( 1, this->m_Planes[ i ] );
455     std::string lerr = this->m_Cutters[ i ]->Update( );
456     if( lerr == "" )
457     {
458       this->m_Cutters[ i ]->GetOutput< TPluginMesh >( 0 )->CreateVTKActor( );
459       vtkActor* actor = this->m_Cutters[ i ]->GetOutput< TPluginMesh >( 0 )->GetVTKActor( );
460       mprActors->GetSliceActors( i )->AddActor( this->m_Cutters[ i ]->GetVTK< vtkAlgorithm >( ), actor );
461       if( i == 0 )
462         this->m_MPRObjects->GetXRenderer( )->AddActor( actor );
463       else if( i == 1 )
464         this->m_MPRObjects->GetYRenderer( )->AddActor( actor );
465       else if( i == 2 )
466         this->m_MPRObjects->GetZRenderer( )->AddActor( actor );
467
468     } // fi
469     err += lerr;
470
471   } // rof
472   this->m_MPRObjects->RenderAll( );
473   return( err );
474 }
475
476 // -------------------------------------------------------------------------
477 void ImageMPR::
478 _triggered_actionOpenPlugins( )
479 {
480   // Show dialog and check if it was accepted
481   QFileDialog dialog( this );
482   dialog.setFileMode( QFileDialog::ExistingFile );
483   dialog.setDirectory( "." );
484   dialog.setNameFilter( tr( PLUGIN_REGEX ) );
485   dialog.setDefaultSuffix( tr( PLUGIN_EXT ) );
486   if( !( dialog.exec( ) ) )
487     return;
488   
489   std::string fname = dialog.selectedFiles( ).at( 0 ).toStdString( );
490   if( !( _LoadPlugins( fname ) ) )
491     QMessageBox::critical(
492       this,
493       tr( "Ignoring plugin" ),
494       tr( fname.c_str( ) )
495       );
496 }
497
498 // -------------------------------------------------------------------------
499 void ImageMPR::
500 _triggered_actionOpenInputImage( )
501 {
502   // Read image
503   std::string err = this->_LoadImage( this->m_Image );
504   if( err == "" )
505   {
506     vtkImageData* vtk_id = this->m_Image->GetVTK< vtkImageData >( );
507     if( vtk_id != NULL )
508     {
509       this->m_MPRObjects->SetImage( vtk_id );
510       this->m_MPRObjects->ActivateInteractors( );
511       this->m_MPRObjects->ResetCameras( );
512       this->m_MPRObjects->RenderAll( );
513
514           MementoState(m_state, this->m_Image);  
515           this->m_state++;
516     }
517     else
518       QMessageBox::critical(
519         this,
520         tr( "Error message" ),
521         tr( "Read image does not have a valid VTK converter." )
522         );
523   }
524   else
525     QMessageBox::critical(
526       this,
527       tr( "Error reading single image" ),
528       tr( err.c_str( ) )
529       );
530 }
531
532 // -------------------------------------------------------------------------
533 void ImageMPR::
534 _triggered_actionOpenSegmentation( )
535 {
536   if( this->m_Image.IsNull( ) )
537   {
538     QMessageBox::critical(
539       this,
540       tr( "Error message" ),
541       tr( "Before reading a segmentation, first load a raw image." )
542       );
543     return;
544
545   } // fi
546
547   // Read image
548   std::string err = this->_LoadImage( this->m_Segmentation );
549   if( err == "" )
550   {
551     vtkImageData* vtk_id = this->m_Segmentation->GetVTK< vtkImageData >( );
552     if( vtk_id != NULL )
553     {
554       this->m_MPRObjects->AddAuxiliaryImage( vtk_id );
555       this->m_MPRObjects->RenderAll( );
556     }
557     else
558       QMessageBox::critical(
559         this,
560         tr( "Error message" ),
561         tr( "Read image does not have a valid VTK converter." )
562         );
563   }
564   else
565     QMessageBox::critical(
566       this,
567       tr( "Error reading single image" ),
568       tr( err.c_str( ) )
569       );
570 }
571
572 // -------------------------------------------------------------------------
573 void ImageMPR::
574 _triggered_actionOpenInputPolyData( )
575 {
576   this->m_Mesh = NULL;
577
578   // Get a reader from plugins
579   TPluginFilter::Pointer reader =
580     this->m_Plugins.CreateProcessObject( this->m_MeshReaderClass );
581
582   if( reader.IsNotNull( ) )
583   {
584     // Configure reader
585     if( reader->ExecConfigurationDialog( this ) )
586     {
587       // Execute and get error message, if any
588       QApplication::setOverrideCursor( Qt::WaitCursor );
589       this->setEnabled( false );
590       std::string err = reader->Update( );
591       QApplication::restoreOverrideCursor( );
592       this->setEnabled( true );
593
594       // Assign fresh mesh, if any
595       if( err == "" )
596       {
597         this->m_Mesh = reader->GetOutput< TPluginMesh >( 0 );
598         reader->DisconnectOutputs( );
599         err = this->_ConfigureMeshActors( );
600         if( err != "" )
601           QMessageBox::critical(
602             this,
603             tr( "Error message" ),
604             tr( err.c_str( ) )
605             );
606       }
607       else
608         QMessageBox::critical(
609           this,
610           tr( "Error reading mesh" ),
611           tr( err.c_str( ) )
612           );
613
614     } // fi
615   }
616   else
617     QMessageBox::critical(
618       this,
619       tr( "Error reading single mesh" ),
620       tr( "No suitable mesh reader found in loaded plugins." )
621       );
622 }
623
624 // -------------------------------------------------------------------------
625 void ImageMPR::
626 _triggered_actionImageToImage( )
627 {
628   if( this->m_Image.IsNull( ) )
629     return;
630
631   // Get filter name
632   QAction* action = dynamic_cast< QAction* >( this->sender( ) );
633   if( action == NULL )
634     return;
635   std::string name = action->text( ).toStdString( );
636
637   // Configure filter
638   TPluginFilter::Pointer filter =
639     this->m_Plugins.CreateProcessObject( name );
640   bool dlg_ok = filter->ExecConfigurationDialog( NULL );
641   if( !dlg_ok )
642     return;
643
644   // Execute filter
645   QApplication::setOverrideCursor( Qt::WaitCursor );
646   this->setEnabled( false );
647   filter->SetInput( 0, this->m_Image );
648   std::string err = filter->Update( );
649   QApplication::restoreOverrideCursor( );
650   this->setEnabled( true );
651
652   // Update image
653   if( err == "" )
654   {
655     TPluginImage* result = filter->GetOutput< TPluginImage >( 0 );
656     result->DisconnectPipeline( );
657     this->m_Image = result;
658     if( this->m_Image.IsNotNull( ) )
659       this->m_MPRObjects->SetImage(
660         this->m_Image->GetVTK< vtkImageData >( )
661
662                 );
663         
664         
665         MementoState(this->m_state, this->m_Image);
666         this->m_state++;
667         if (this->m_state > this->m_max_state)
668         {
669                 this->m_max_state = this->m_state;
670         }
671   }
672   else
673     QMessageBox::critical(
674       this,
675       tr( "Error executing filter" ),
676       tr( err.c_str( ) )
677       );
678 }
679
680 // -------------------------------------------------------------------------
681 void ImageMPR::
682 _triggered_actionImageToMesh( )
683 {
684   if( this->m_Image.IsNull( ) )
685     return;
686
687   // Get filter name
688   QAction* action = dynamic_cast< QAction* >( this->sender( ) );
689   if( action == NULL )
690     return;
691   std::string name = action->text( ).toStdString( );
692
693   // Configure filter
694   TPluginFilter::Pointer filter =
695     this->m_Plugins.CreateProcessObject( name );
696   bool dlg_ok = filter->ExecConfigurationDialog( NULL );
697   if( !dlg_ok )
698     return;
699
700   // Execute filter
701   QApplication::setOverrideCursor( Qt::WaitCursor );
702   this->setEnabled( false );
703   filter->SetInput( 0, this->m_Image );
704   std::string err = filter->Update( );
705   QApplication::restoreOverrideCursor( );
706   this->setEnabled( true );
707
708   // Update image
709   if( err == "" )
710   {
711     TPluginMesh* result = filter->GetOutput< TPluginMesh >( 0 );
712     result->DisconnectPipeline( );
713     this->m_Mesh = result;
714     err = this->_ConfigureMeshActors( );
715     if( err != "" )
716       QMessageBox::critical(
717         this,
718         tr( "Error message" ),
719         tr( err.c_str( ) )
720         );
721   }
722   else
723     QMessageBox::critical(
724       this,
725       tr( "Error executing filter" ),
726       tr( err.c_str( ) )
727       );
728 }
729
730 // -------------------------------------------------------------------------
731 void ImageMPR::
732 _triggered_actionUndo()
733 {
734         MementoState memento = MementoState();
735     
736         if (this->m_state>1)
737         {
738                 this->m_state--;
739                 this->m_MPRObjects->SetImage(
740                         memento.getMemento(this->m_state)->GetOutput()
741                         );
742         } else
743         {
744                 QMessageBox::warning(
745                         this,
746                         tr("message"),
747                         tr("No history to undo")
748                         );
749         }
750
751 }
752
753 // -------------------------------------------------------------------------
754 void ImageMPR::
755 _triggered_actionRedo()
756 {
757         MementoState memento = MementoState();
758                 if (this->m_state + 1 <= m_max_state)
759                 {
760                         this->m_state++;
761                         this->m_MPRObjects->SetImage(
762                                 memento.getMemento(this->m_state)->GetOutput()
763                                 );
764                 } else
765                 {
766                         QMessageBox::warning(
767                                 this,
768                                 tr("message"),
769                                 tr("No history to redo")
770                                 );
771                 }
772         
773 }
774         
775 */
776
777 // eof - $RCSfile$