/*=========================================================================

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/VolViewCopyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkContourSegmentationFrame.h"
#include "vtkObjectFactory.h"
#include "vtkKWMenuButton.h"
#include "vtkKWEntryWithLabel.h"
#include "vtkContourSegmentationFilter.h"
#include "vtkKWInternationalization.h"
#include "vtkVVWindowBase.h"
#include "vtkKWEntry.h"
#include "vtkKWPushButton.h"
#include "vtkKWMenu.h"
#include "vtkKWIcon.h"
#include "vtkVVInteractorWidgetSelector.h"
#include "vtkKWRenderWidgetPro.h"
#include "vtkKWVolumeWidget.h"
#include "vtkKWProbeImageWidget.h"
#include "vtkImageReslice.h"
#include "vtkKWImageWidget.h"
#include "vtkContourRepresentation.h"
#include "vtkKWImageMapToWindowLevelColors.h"
#include "vtkPolyData.h"
#include "vtkImageData.h"
#include "vtkKWContourWidget.h"
#include "vtkOrientedGlyphFocalPlaneContourRepresentation.h"
#include "vtkMatrix4x4.h"
#include "vtkCamera.h"
#include "vtkRenderer.h"
#include "vtkKWApplication.h"
#include "vtkKWMessageDialog.h"
//#include "vtkMetaImageWriter.h"
#include <vtksys/SystemTools.hxx>
#include "vtkKWLabel.h"
#include "vtkKWProgressCommand.h" 

const char *vtkContourSegmentationFrame::SegmentationWarningDialogName 
                                    = "PromptBeforeSegmentation";

//---------------------------------------------------------------------------
vtkStandardNewMacro(vtkContourSegmentationFrame);
vtkCxxRevisionMacro(vtkContourSegmentationFrame, "$Revision: 1.26 $");

//---------------------------------------------------------------------------
vtkContourSegmentationFrame::vtkContourSegmentationFrame()
{
  this->SegmentationReplaceValueEntry = NULL;
  this->SegmentationTypeMenuButton1   = NULL;
  this->SegmentationTypeMenuButton2   = NULL;
  this->SegmentButton                 = NULL;
  this->InteractorWidgetSelector      = NULL;
  this->ContourSegmentationFilter     = vtkContourSegmentationFilter::New();
  this->HasValidImageData             = 0;
  this->HasValidPolyData              = 0;
  this->RenderWidget                  = NULL;
  this->PromptBeforeSegmentation      = 1;
}

//---------------------------------------------------------------------------
vtkContourSegmentationFrame::~vtkContourSegmentationFrame()
{
  if (this->SegmentationReplaceValueEntry)
    {
    this->SegmentationReplaceValueEntry->Delete();
    this->SegmentationReplaceValueEntry = NULL;
    }
  if (this->SegmentationTypeMenuButton1)
    {
    this->SegmentationTypeMenuButton1->Delete();
    this->SegmentationTypeMenuButton1 = NULL;
    }
  if (this->SegmentationTypeMenuButton2)
    {
    this->SegmentationTypeMenuButton2->Delete();
    this->SegmentationTypeMenuButton2 = NULL;
    }
   if (this->SegmentButton)
    {
    this->SegmentButton->Delete();
    this->SegmentButton = NULL;
    }
  this->SetInteractorWidgetSelector( NULL );

  this->ContourSegmentationFilter->Delete();
}

//---------------------------------------------------------------------------
void vtkContourSegmentationFrame::CreateWidget()
{
  if (this->IsCreated())
    {
    vtkErrorMacro("The widget is already created.");
    return;
    }

  this->Superclass::CreateWidget();

  ostrstream tk_cmd;

  // Frame properties
  this->SetLabelText(k_("Segmentation"));
  this->SetEnabled(0);

  // Segmentation: buttons 
  // 1. Replace Value entry
  
  if (!this->SegmentationReplaceValueEntry)
    {
    this->SegmentationReplaceValueEntry = vtkKWEntryWithLabel::New();
    }

  this->SegmentationReplaceValueEntry->SetParent(this->Frame);
  this->SegmentationReplaceValueEntry->Create();
  this->SegmentationReplaceValueEntry->SetLabelText(
    ks_("Segmentation Mode|Replace"));
  this->SegmentationReplaceValueEntry->GetWidget()->SetValueAsDouble(0.0); 
  // Should really be the scalar type of the dataset, we will round this value
  // appropriately.
  this->SegmentationReplaceValueEntry->GetWidget()->SetWidth(6);
  this->SegmentationReplaceValueEntry->GetWidget()->SetCommand(
                 this, "SegmentationReplaceValueCallback");
  this->SegmentationReplaceValueEntry->SetBalloonHelpString(
    k_("The regions segmented out by the contour will have their intensity "
       "values replaced with this."));
  
  tk_cmd << "pack " << this->SegmentationReplaceValueEntry->GetWidgetName()
         << " -side left -anchor nw -fill x -expand t -padx 2 -pady 2" << endl;
  this->SegmentationReplaceValueEntry->SetEnabled(0);
  
  // 2. Segment inside or outside ? 
  //    Segment whole volume or slice ?
  
  if (!this->SegmentationTypeMenuButton1)
    {
    this->SegmentationTypeMenuButton1 = vtkKWMenuButton::New();
    }
  this->SegmentationTypeMenuButton1->SetParent(this->Frame);
  this->SegmentationTypeMenuButton1->Create();

  tk_cmd << "pack " << this->SegmentationTypeMenuButton1->GetWidgetName()
         << " -side left -anchor nw -fill x -expand t -padx 2 -pady 2" << endl;

  this->SegmentationTypeMenuButton1->SetEnabled(0);

  if (!this->SegmentationTypeMenuButton2)
    {
    this->SegmentationTypeMenuButton2 = vtkKWMenuButton::New();
    }
  this->SegmentationTypeMenuButton2->SetParent(this->Frame);
  this->SegmentationTypeMenuButton2->Create();

  tk_cmd << "pack " << this->SegmentationTypeMenuButton2->GetWidgetName()
         << " -side left -anchor nw -fill x -expand t -padx 2 -pady 2" << endl;

  this->SegmentationTypeMenuButton2->SetEnabled(0);

  // 2. The button that does the segmentation.

  if (!this->SegmentButton)
    {
    this->SegmentButton = vtkKWPushButton::New();
    }
  char command[256];
  this->SegmentButton->SetParent(this->Frame);
  this->SegmentButton->Create();
  sprintf(command, "ContourSegmentCallback");
  this->SegmentButton->SetCommand(this, command);
  this->SegmentButton->SetText("Segment using contour");
  this->SegmentButton->SetImageToPredefinedIcon(
    vtkKWIcon::IconNuvola16x16ActionsEditCut);
  this->SegmentButton->SetBalloonHelpString(
    ks_("Segmentation|Segment the contour."));
  
  tk_cmd << "pack " << this->SegmentButton->GetWidgetName()
         << " -side left -anchor nw -fill both -expand n -padx 2 -pady 2" << endl;
  
  this->SegmentButton->SetEnabled(0);

  // Pack

  tk_cmd << ends;
  this->Script(tk_cmd.str());
  tk_cmd.rdbuf()->freeze(0);

}

//---------------------------------------------------------------------------
void vtkContourSegmentationFrame::SetInteractorWidgetSelector( 
                            vtkVVInteractorWidgetSelector * i )
{
  // TODO
  // The method should really be replaced by the SetObjectMacro, so we know
  // who's referencing what.. but I can't seem to get the Garbage collector
  // to shut-up when reference counting loops, by overriding the 
  // ReportReferences method. (The InteractorWidgetSelector reference counts
  // this class, this class is also supposed to maintain a reference to 
  // the InteractorWidgetSelector, but right now it does not. It just holds
  // a raw pointer to it).
  if (i != NULL  && this->InteractorWidgetSelector != i )
    {
    this->InteractorWidgetSelector = i;
    this->Modified();
    }
}

//---------------------------------------------------------------------------
void vtkContourSegmentationFrame::SegmentationReplaceValueCallback( const char * )
{
  if (!this->SegmentationReplaceValueEntry)
    {
    return;
    }
  
  this->ContourSegmentationFilter->SetReplaceValue( 
      this->SegmentationReplaceValueEntry->GetWidget()->GetValueAsDouble() );
}

//---------------------------------------------------------------------------
void vtkContourSegmentationFrame::SegmentationTypeCallback()
{
  if (!this->SegmentationTypeMenuButton1 || !this->SegmentationTypeMenuButton2)
    {
    return;
    }

  const char *segmentOrientation = 
    this->SegmentationTypeMenuButton1->GetValue();
  if (!strcmp(segmentOrientation, ks_("Segmentation|Outside")))
    {
    this->ContourSegmentationFilter->SegmentInsideOn();
    }
  else
    {
    this->ContourSegmentationFilter->SegmentInsideOff();
    }
   
  const char *segmentType = 
    this->SegmentationTypeMenuButton2->GetValue();
  if (!strcmp(segmentType, ks_("Segmentation|Volume")))
    {
    this->ContourSegmentationFilter->SetSegmentationExtentToImageExtent();
    }
  else // Only on the slice
    {
    // slice by slice segmentation makes sense only for 2D widgets.
    vtkKW2DRenderWidget *rw2d = vtkKW2DRenderWidget::SafeDownCast( 
                                              this->RenderWidget );
    if (!rw2d) 
      {
      return;
      }
    
    int segmentationExtent[6];
    rw2d->GetSliceDisplayExtent( rw2d->GetSlice(), segmentationExtent );
    this->ContourSegmentationFilter->SetSegmentationExtent( segmentationExtent );
    }
}

//----------------------------------------------------------------------------
// Get the widget currently selected by the InteractorWidgetSelector, check
// if its a contour widget, get the contour representation from the widget, 
// check if its closed, set the polydata and the render widget on which the 
// contour was drawn (from which the image data, extent etc will be obtained)
// and segment.
//
void vtkContourSegmentationFrame::ContourSegmentCallback()
{
  if (!this->InteractorWidgetSelector)
    {
    return;
    }

  vtkAbstractWidget *interactor = this->InteractorWidgetSelector->GetPresetInteractorWidget(this->InteractorWidgetSelector->GetIdOfSelectedPreset());
  if (!interactor)
    {
    return;
    }

  vtkKWContourWidget *contour_widget = 
    vtkKWContourWidget::SafeDownCast(interactor);
  
  if ( !contour_widget ) 
    {
    return;
    }

  vtkContourRepresentation *rep = vtkContourRepresentation::SafeDownCast(
      contour_widget->GetRepresentation());

  if ( rep && rep->GetClosedLoop() )
    {
    this->SetContourRepresentation( rep );
    
    if ( !this->HasValidImageData || !this->HasValidPolyData ) 
      {
      this->EnableContourSegmentationGUI(0); 
      return;
      }

    if (this->PromptBeforeSegmentation && !this->DisplayWarningDialog() )
      {
      this->SetEnabled( 1 );
      return;
      }

    // Disable the segmentation frame during and after the update. No sense in 
    // segmenting with the same contour twice unless the contour changes.
    // NOTE: this is confusing, sorry.
    // this->EnableContourSegmentationGUI(0); 
  
    // Set up progress reporting ..
   
    vtkKWProgressCommand *cb = vtkKWProgressCommand::New();
    cb->SetWindow( this->InteractorWidgetSelector->GetWindow() );
    cb->SetStartMessage( "Segmenting.." ); // Do the internationalization.
    cb->SetRetrieveProgressMethodToCallData();
    this->ContourSegmentationFilter->AddObserver( vtkCommand::StartEvent,    cb );
    this->ContourSegmentationFilter->AddObserver( vtkCommand::ProgressEvent, cb );
    this->ContourSegmentationFilter->AddObserver( vtkCommand::EndEvent,      cb );
    
    
    if (this->Segment()) // Does the actual segmentation
      {
      // Input has changed.. update relevant render widgets 
      vtkContourSegmentationFrame::UpdateRenderWidgetsUsingSelectedDataItem(
          this->InteractorWidgetSelector->GetWindow() );
      }

    this->ContourSegmentationFilter->RemoveObserver(cb);
    cb->Delete();

    }
}

//---------------------------------------------------------------------------
int vtkContourSegmentationFrame::EnableContourSegmentationGUI( int enabled )
{
  if ( enabled && this->RenderWidget )
    {
    // Activate the segmentation GUI
    this->ExpandFrame();
    this->SetEnabled(1);

    // If the button is being enabled now, set reasonable defaults. Set the 
    // replace value as the min of the dataset.
    if (!(this->SegmentationReplaceValueEntry->GetEnabled()))
      {
      this->SegmentationReplaceValueEntry->SetEnabled(1);
      double *range = this->RenderWidget->GetInput()->GetScalarRange();
      this->SegmentationReplaceValueEntry->GetWidget()->SetValueAsDouble(range[0]);
      this->ContourSegmentationFilter->SetReplaceValue(range[0]);
      }
    
    // If the button is being enabled now, set reasonable defaults. 
    if (   !this->SegmentationTypeMenuButton1->GetEnabled() )
      {
      
      // Add buttons ..
      this->SegmentationTypeMenuButton1->GetMenu()->DeleteAllItems();
      this->SegmentationTypeMenuButton2->GetMenu()->DeleteAllItems();
      this->EnableSupportedSegmentationOptions();
      
      this->ContourSegmentationFilter->SegmentInsideOn();
      this->ContourSegmentationFilter->SetSegmentationExtentToImageExtent();
      }

    this->SegmentButton->SetEnabled(1);

    return 1;
    }
  
  this->SegmentationTypeMenuButton1->SetEnabled(0);
  this->SegmentationTypeMenuButton2->SetEnabled(0);
  this->SegmentationReplaceValueEntry->SetEnabled(0);
  this->SegmentButton->SetEnabled(0);
  this->SetEnabled(0);
  return 0;
}

//---------------------------------------------------------------------------
// The following two methods set appropriate parameters for the segmentation 
// filter. They use the vtkContourSegmentationFilter to do the segmentation.
// 
// The inputs to the filter are slightly different depending on whether its 
// drawn on the image/ oblique or volume widget. If drawn on the image widgets,
// the filter needs just the input data, the contour polydata and the 
// ObtainSliceFromContourPolyDataOn() flag.
// 
// If drawn on the oblique widget, the filter must be supplied with the resliced 
// image along with its direction cosines in addition to the input image and 
// contour.
// 
// If drawn on the volume widget, the filter needs the direction cosines of the
// focal plane (the plane on which the contour lies on) in addition to the input 
// image and contour polydata.
//
void vtkContourSegmentationFrame::SetRenderWidget( vtkKWRenderWidgetPro * rwp )
{
  this->HasValidImageData = 0;
  
  if (!vtkContourSegmentationFrame::RenderWidgetSupportSegmentation( rwp ))
    {
    this->RenderWidget = NULL;
    return;
    }
  
  this->RenderWidget = rwp;
  
  vtkKW2DRenderWidget *rw2d = 
    vtkKW2DRenderWidget::SafeDownCast( rwp );
  vtkKWVolumeWidget *vw = vtkKWVolumeWidget::SafeDownCast( rwp );

  // Drawn on the 2D widget
  if (rw2d)
    {
    vtkKWImageMapToWindowLevelColors *imageMapToRGBA 
                          = rw2d->GetImageMapToRGBA();
    this->ContourSegmentationFilter->SetImage((vtkImageData *)
                                   (rw2d->GetInput()));
    this->ContourSegmentationFilter->SetInput((vtkImageData *)
        (imageMapToRGBA->GetInput()));
    
    // For the oblique probe, 
    //
    // we must set the projection axes, for the
    // other image widgets, the contour polydata can tell us the contour
    // orientation. The ContourSegmentationFilter is not smart enough to 
    // determine the orientation of the contour from the polydata unless 
    // it lies along one of the axis aligned directions. 
    
    vtkKWProbeImageWidget *probeImage2DWidget = 
                vtkKWProbeImageWidget::SafeDownCast(rw2d);
    
    if (probeImage2DWidget)
      {
      vtkImageReslice *reslice = probeImage2DWidget->GetImageReslice();
      if (reslice)
        {
        this->ContourSegmentationFilter->SetStencilAxes(
                                reslice->GetResliceAxes());
        this->ContourSegmentationFilter->ObtainOrientationFromContourPolyDataOff();
        }
      }
    else 
      {
      this->ContourSegmentationFilter->ObtainOrientationFromContourPolyDataOn();
      }
    
    }
  else if (vw) // Contour drawn on the volume widget
    {
    this->ContourSegmentationFilter->SetInput( (vtkImageData *)
                                             (vw->GetInput()));
    this->ContourSegmentationFilter->SetImage( (vtkImageData *)
                                             (vw->GetInput()));
    this->ContourSegmentationFilter->ObtainOrientationFromContourPolyDataOff();
    }

  this->HasValidImageData = 1;
}

//---------------------------------------------------------------------------
// You should have called SetRenderWidget first.
void vtkContourSegmentationFrame::SetContourRepresentation( 
     vtkContourRepresentation *rep )
{
  this->HasValidPolyData = 0;

  if (!this->RenderWidget)
    {
    return;
    }
  
  vtkKW2DRenderWidget *rw2d = 
    vtkKW2DRenderWidget::SafeDownCast( this->RenderWidget );
  vtkKWVolumeWidget *vw = vtkKWVolumeWidget::SafeDownCast( this->RenderWidget );

  if (!rw2d && !vw) // Not a volume or image widget.. 
    {
    return;
    } 

  // Drawn on the 2D widget
  if (rw2d)
    {
    this->ContourSegmentationFilter->SetContourPolyData(
      const_cast< vtkPolyData * >(rep->GetContourRepresentationAsPolyData()));
    }
  else if (vw) // Contour drawn on the volume widget
    {
    this->ContourSegmentationFilter->VolumetricProjectionOn();
    this->ContourSegmentationFilter->SetRenderer( rep->GetRenderer() );
      
    vtkOrientedGlyphFocalPlaneContourRepresentation *repogfp = 
      vtkOrientedGlyphFocalPlaneContourRepresentation::SafeDownCast(rep);
            
    this->ContourSegmentationFilter->SetContourPolyData(
            repogfp->GetContourRepresentationAsPolyData());
    }

  this->HasValidPolyData = 1;
}

//---------------------------------------------------------------------------
int vtkContourSegmentationFrame::Segment()
{
  // Any vtkImageInPlaceFilter must Set the release data flag on its input to 
  // on, to prevent reallocation of data. See 
  // vtkImageInPlaceFilter::RequestData().
  
  vtkImageData *image = this->ContourSegmentationFilter->GetImage();
  if (image)
    {
    int old_flag = image->GetReleaseDataFlag();
    image->ReleaseDataFlagOn();
  
    this->ContourSegmentationFilter->Update();
  
    // Get the output. The input is now gone.

    vtkImageData *output = vtkImageData::SafeDownCast( 
         this->ContourSegmentationFilter->GetOutput());
    if (!output)
      {
      vtkErrorMacro( << "Contour segmentation failed to generate any output !" );
      }

    //vtkMetaImageWriter *w = vtkMetaImageWriter::New();
    //w->SetInput(output);
    //w->SetFileName("segmentedImage.mha");
    //w->Write();

    image->ShallowCopy( output );
    image->SetReleaseDataFlag(old_flag);
    }
  
  return 1;
}

//---------------------------------------------------------------------------
// Contours are supported on the image widgets and the oblique probe
//
int vtkContourSegmentationFrame::RenderWidgetSupportSegmentation(
                                          vtkKWRenderWidgetPro * rwp)
{
  if (   rwp && 
      
       ( vtkKWImageWidget::SafeDownCast(  rwp )
         
       // UNCOMMENT THIS LINE IF YOU WANT CONTOUR SEGMENTATION TO BE ENABLED 
       // ON THE VOLUME WIDGET
       // 
        || vtkKWVolumeWidget::SafeDownCast( rwp )  
         
         )

       // COMMENT THIS LINE TO DISABLE IT ON THE OBLIQUE PROBE
       //&& !vtkKWProbeImageWidget::SafeDownCast( rwp ) 
       )
    {
    return 1;
    }
  
  return 0;
}

//---------------------------------------------------------------------------
void vtkContourSegmentationFrame::UpdateRenderWidgetsUsingSelectedDataItem( 
    vtkVVWindowBase * window)
{
  // Once the filter runs, we need to update the render windows 
  // according to the segmented data. The ContourSegmentationFilter is
  // a vtkInPlaceFilter, so the image_data ivar remains the same, hence
  // we need to force an update.
  int nb_rw = window->GetNumberOfRenderWidgetsUsingSelectedDataItem();
  for (int i = 0; i < nb_rw; i++)
    {
    vtkKWRenderWidgetPro *rwp = vtkKWRenderWidgetPro::SafeDownCast(
      window->GetNthRenderWidgetUsingSelectedDataItem(i));
    if (!rwp)
      {
      return;
      }
    
    // For some wierd reason, the image widgets do not update their 
    // display when UpdateAccordingToInput() is called. Manually 
    // call Modified on the image data. Somethings wrong !
    // TODO: The Histogram widget etc is still the old one.. needs
    // to update itself... 
    if (vtkKWImageWidget::SafeDownCast(rwp))
      {
      rwp->GetInput()->Modified();
      }
    
    // Manually force the update.
    rwp->UpdateAccordingToInput();
    rwp->Render();
    }

  window->Update();
 
}

//---------------------------------------------------------------------------
void vtkContourSegmentationFrame::EnableSupportedSegmentationOptions()
{
  if (!this->RenderWidget)
    {
    return;
    }

  if ( vtkContourSegmentationFrame::
      RenderWidgetSupportSegmentation( this->RenderWidget ) )
    {
    this->SegmentationTypeMenuButton1->GetMenu()->AddRadioButton(
      ks_("Segmentation|Outside"), this, "SegmentationTypeCallback");
    this->SegmentationTypeMenuButton1->GetMenu()->AddRadioButton(
      ks_("Segmentation|Inside"), this, "SegmentationTypeCallback");
    this->SegmentationTypeMenuButton1->GetMenu()->SetBalloonHelpString(
      k_("Inside sets pixels inside the contour to the replacement value. "
         "Outside does the opposite."));
    this->SegmentationTypeMenuButton1->SetValue(ks_("Segmentation|Outside"));
    this->SegmentationTypeMenuButton1->SetEnabled(1);
    }
  else
    {
    this->SegmentationTypeMenuButton1->SetEnabled(0);
    }
  
  if ( vtkContourSegmentationFrame::
      RenderWidgetSupportSegmentation( this->RenderWidget )
      && ( vtkKWProbeImageWidget::SafeDownCast( this->RenderWidget ) ||
           vtkKWVolumeWidget::SafeDownCast( this->RenderWidget ) ) )
    {
    this->SegmentationTypeMenuButton2->GetMenu()->AddRadioButton( 
      ks_("Segmentation|Volume"));
    this->SegmentationTypeMenuButton2->SetValue("Volume");
    this->SegmentationTypeMenuButton2->SetEnabled(0);
    this->SegmentationTypeMenuButton2->SetBalloonHelpString(
      k_("Segments the entire volume via an extrusion along the normal to "
         "the contour."));
    }
  else if ( vtkContourSegmentationFrame::
      RenderWidgetSupportSegmentation( this->RenderWidget )
      && vtkKWImageWidget::SafeDownCast( this->RenderWidget ) )
    {
    this->SegmentationTypeMenuButton2->GetMenu()->AddRadioButton(
      ks_("Segmentation|Volume"), this, "SegmentationTypeCallback");
    this->SegmentationTypeMenuButton2->GetMenu()->AddRadioButton(
      ks_("Segmentation|Slice"), this, "SegmentationTypeCallback");
    this->SegmentationTypeMenuButton2->SetEnabled(1);
    this->SegmentationTypeMenuButton2->SetValue( "Volume" );
    this->SegmentationTypeMenuButton2->SetBalloonHelpString(
      k_("'Volume' segments the entire volume via an extrusion along the "
         "normal to the contour. 'Slice' restricts segmentation to the "
         "current slice."));
    }
  else
    {
    this->SegmentationTypeMenuButton2->SetEnabled(0);
    }   
}

//----------------------------------------------------------------------------
int vtkContourSegmentationFrame::DisplayWarningDialog()
{
  vtksys_stl::string title = this->GetLabel()->GetText();

  vtksys_stl::string msg = 
    k_("This will modify the existing data. The only way to retrieve this "
       "data is to reopen it using the File->Open dialog. Proceed ?");
  
  vtkKWApplication *app = 
    this->InteractorWidgetSelector->GetWindow()->GetApplication();
  vtkKWMessageDialog *dialog = vtkKWMessageDialog::New();
  dialog->SetApplication(app);
  dialog->SetStyleToYesNo();
  dialog->SetMasterWindow(app->GetNthWindow(0));
  dialog->SetOptions(
    vtkKWMessageDialog::QuestionIcon | 
    vtkKWMessageDialog::RememberYes |
    vtkKWMessageDialog::Beep | 
    vtkKWMessageDialog::YesDefault);
  dialog->SetDialogName(
      vtkContourSegmentationFrame::SegmentationWarningDialogName);
  dialog->Create();
  dialog->SetText(msg.c_str());
  dialog->SetTitle(title.c_str());

  int ret = dialog->Invoke();
  dialog->Delete();

  // This UI interface usually displays a checkbox offering the choice
  // to prompt for exit or not. Update that UI.

  for (int i = 0; i < app->GetNumberOfWindows(); i++)
    {
    app->GetNthWindow(i)->Update();
    }

  return ret;
}

//---------------------------------------------------------------------------
void vtkContourSegmentationFrame::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "HasValidPolyData:  " << this->HasValidPolyData  << endl;
  os << indent << "HasValidImageData: " << this->HasValidImageData << endl;
}

