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

  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 "vtkVVWindowBase.h"

#include "vtkObjectFactory.h"
#include "vtkXMLDataElement.h"
#include "vtkImageData.h"
#include "vtkMedicalImageReader2.h"

#include "vtkKW2DRenderWidget.h"
#include "vtkKWEvent.h"
#include "vtkKWFrame.h"
#include "vtkKWIcon.h"
#include "vtkKWImageWidget.h"
#include "vtkKWInternationalization.h"
#include "vtkKWLabel.h"
#include "vtkKWLightboxWidget.h"
#include "vtkKWLoadSaveDialog.h"
#include "vtkKWMenu.h"
#include "vtkKWMessageDialog.h"
#include "vtkKWMostRecentFilesManager.h"
#include "vtkKWNotebook.h"
#include "vtkKWOpenWizard.h"
#include "vtkKWOptions.h"
#include "vtkKWProbeImageWidget.h"
#include "vtkKWPushButton.h"
#include "vtkKWRadioButton.h"
#include "vtkKWRenderWidget.h"
#include "vtkKWSplashScreen.h"
#include "vtkKWSplitFrame.h"
#include "vtkKWStartupPageWidget.h"
#include "vtkKWTkUtilities.h"
#include "vtkKWToolbar.h"
#include "vtkKWToolbarSet.h"
#include "vtkKWUserInterfaceManagerNotebook.h"
#include "vtkKWVolumeWidget.h"

#include "XML/vtkXMLObjectReader.h"
#include "XML/vtkXMLObjectWriter.h"

#include "vtkVVApplication.h"
#include "vtkVVApplicationSettingsInterfaceBase.h"
#include "vtkVVDataItemVolume.h"
#include "vtkVVDataItemPool.h"
#include "vtkVVFileInstance.h"
#include "vtkVVFileInstancePool.h"
#include "vtkVVHandleWidget.h"
#include "vtkVVSelectionFrame.h"
#include "vtkVVSelectionFrameLayoutManager.h"
#include "vtkVVSnapshot.h"
#include "vtkVVSnapshotPool.h"
#include "vtkVVSaveDialog.h"
#include "vtkVVSaveFiducialsDialog.h"
#include "vtkVVSaveVolume.h"
#include "vtkVVSaveFiducials.h"

//#include "vtkKWVolViewConfigure.h"
#include "vtkKWWidgetsProConfigure.h" // Needed for KWWidgetsPro_USE_LICENSE

#include <vtksys/stl/vector>
#include <vtksys/stl/string>
#include <vtksys/SystemTools.hxx>

#include <assert.h>
#include <time.h>

//---------------------------------------------------------------------------
vtkCxxRevisionMacro(vtkVVWindowBase, "$Revision: 1.102 $");
vtkStandardNewMacro(vtkVVWindowBase);

#ifdef KWCommonPro_USE_XML_RW
#include "XML/vtkXMLVVWindowBaseReader.h"
#include "XML/vtkXMLVVWindowBaseWriter.h"
#endif
vtkKWGetXMLReaderWriterObjectsImplementationMacro(vtkVVWindowBase, vtkXMLVVWindowBaseReader, vtkXMLVVWindowBaseWriter);

const char *vtkVVWindowBase::PaintbrushNotSavedInSnapshotDialogName = "PaintbrushNotSavedInSnapshot";

//----------------------------------------------------------------------------
vtkVVWindowBase::vtkVVWindowBase()
{  
  this->FileOpenMenuLabel = 
    vtksys::SystemTools::DuplicateString(ks_("Menu|File|&Open File..."));
  this->FileSaveSessionMenuLabel = 
    vtksys::SystemTools::DuplicateString(ks_("Menu|File|Save &Session..."));
  this->FileSaveVolumeMenuLabel = 
    vtksys::SystemTools::DuplicateString(ks_("Menu|File|Save &Volume..."));
  this->FileSaveFiducialsMenuLabel = 
    vtksys::SystemTools::DuplicateString(ks_("Menu|File|Save &Fiducials..."));
  this->FileSaveScreenshotMenuLabel = 
    vtksys::SystemTools::DuplicateString(ks_("Menu|File|Save Screensh&ot..."));
  this->FilePrintAllMenuLabel =
    vtksys::SystemTools::DuplicateString(ks_("Menu|File|&Print All..."));
  this->FilePrintSelectedMenuLabel = 
    vtksys::SystemTools::DuplicateString(ks_("Menu|File|Pri&nt Selected..."));
  this->FileLauncheExternalApplicationMenuLabel = 
    vtksys::SystemTools::DuplicateString(ks_("Menu|File|Launch External Application"));
  this->FileCloseSelectedDataMenuLabel = 
    vtksys::SystemTools::DuplicateString(
      ks_("Menu|File|&Close Selected Data"));
  this->EditCopyScreenshotMenuLabel = 
    vtksys::SystemTools::DuplicateString(ks_("Menu|Edit|&Copy Screenshot"));
  this->HelpRegisterMenuLabel = 
    vtksys::SystemTools::DuplicateString(ks_("Menu|Help|Register..."));
  this->HelpEmailFeedbackMenuLabel = 
    vtksys::SystemTools::DuplicateString(
      ks_("Menu|Help|Email Technical Support"));
  
  // Override the name of some panels for this app

  this->SetHideMainPanelMenuLabel(
    ks_("Menu|Window|Hide &Control Panel"));
  this->SetShowMainPanelMenuLabel(
    ks_("Menu|Window|Show &Control Panel"));

  this->SupportHelp = 1;
  this->SupportPrint = 1;

  this->RenderStatesSaveCount = 0;
  this->MaximumNumberOfSimultaneousDataItems = 100;

  // Dataset layout manager

  this->DataSetWidgetLayoutManager = NULL;

  // Allow the user to interactively resize the properties parent.
  // Set the left panel size (Frame1) for this app. Do it now before
  // the superclass eventually restores the size from the registry

  this->PanelLayout = vtkKWWindow::PanelLayoutSecondaryBelowView;
  this->StatusFramePosition = vtkKWWindow::StatusFramePositionLeftOfDivider;

  if (this->MainSplitFrame)
    {
    this->MainSplitFrame->SetFrame1MinimumSize(350);
    this->MainSplitFrame->SetFrame1Size(
      this->MainSplitFrame->GetFrame1MinimumSize());
    this->MainSplitFrame->SetSeparatorSize(5);
    }

  if (this->SecondarySplitFrame)
    {
    this->SecondarySplitFrame->SetFrame1Visibility(0);
    this->SecondarySplitFrame->SetSeparatorVisibility(0);
    }

  // Toolbars

  this->FileToolbar = vtkKWToolbar::New();
  this->FileToolbar->SetName(ks_("Toolbar|File"));

  this->QuickViewToolbar = vtkKWToolbar::New();
  this->QuickViewToolbar->SetName(ks_("Toolbar|Quick View"));

  this->InteractionMode2DToolbar = vtkKWToolbar::New();
  this->InteractionMode2DToolbar->SetName(ks_("Toolbar|2D Interaction"));

  this->InteractionMode3DToolbar = vtkKWToolbar::New();
  this->InteractionMode3DToolbar->SetName(ks_("Toolbar|3D Interaction"));

  this->ToolsToolbar = vtkKWToolbar::New();
  this->ToolsToolbar->SetName(ks_("Toolbar|Tools"));

  // Open wizard

  this->OpenWizard = vtkKWOpenWizard::New();

  this->StartupPageWidget = vtkKWStartupPageWidget::New();

  this->SupportVolumeWidget = 1;
  this->SupportObliqueProbeWidget = 1;
  this->SupportLightboxWidget = 1;

  // File instances

  this->FileInstancePool = vtkVVFileInstancePool::New();

  // Data pool

  this->DataItemPool = vtkVVDataItemPool::New();

  // Snapshots

  this->SnapshotPool = vtkVVSnapshotPool::New();
}

//----------------------------------------------------------------------------
vtkVVWindowBase::~vtkVVWindowBase()
{
  this->DisableRenderStates();

  if (this->FileToolbar)
    {
    this->FileToolbar->Delete();
    this->FileToolbar = NULL;
    }

  if (this->QuickViewToolbar)
    {
    this->QuickViewToolbar->Delete();
    this->QuickViewToolbar = NULL;
    }

  if (this->ToolsToolbar)
    {
    this->ToolsToolbar->Delete();
    this->ToolsToolbar = NULL;
    }

  if (this->InteractionMode2DToolbar)
    {
    this->InteractionMode2DToolbar->Delete();
    this->InteractionMode2DToolbar = NULL;
    }

  if (this->InteractionMode3DToolbar)
    {
    this->InteractionMode3DToolbar->Delete();
    this->InteractionMode3DToolbar = NULL;
    }

  if (this->DataSetWidgetLayoutManager)
    {
    this->DataSetWidgetLayoutManager->Delete();
    this->DataSetWidgetLayoutManager = NULL;
    }

  if (this->OpenWizard)
    {
    this->OpenWizard->Delete();  
    this->OpenWizard = NULL;
    }

  if (this->StartupPageWidget)
    {
    this->StartupPageWidget->Delete();  
    this->StartupPageWidget = NULL;
    }

  if (this->DataItemPool)
    {
    this->DataItemPool->Delete();
    this->DataItemPool = NULL;
    }

  if (this->FileInstancePool)
    {
    this->FileInstancePool->Delete();
    this->FileInstancePool = NULL;
    }

  if (this->SnapshotPool)
    {
    this->SnapshotPool->Delete();
    this->SnapshotPool = NULL;
    }
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::PrepareForDelete()
{
  this->Superclass::PrepareForDelete();

  this->CloseAllDataItems();
  this->CloseAllFileInstances();

  if (this->OpenWizard)
    {
    //fixme
    this->OpenWizard->Release(0);
    this->OpenWizard->SetMasterWindow(0);  
    }
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::CreateWidget()
{
  if (this->IsCreated())
    {
    vtkErrorMacro("widget already created " << this->GetClassName());
    return;
    }

  // Set the default geometry before creating the window superclass

  int w, h;
  vtkKWTkUtilities::GetScreenSize(
    this->GetApplication()->GetMainInterp(), ".", &w, &h);
  w = (w > 900 ? (int)(0.90 * (double)w) : 900);
  h = (h > 700 ? (int)(0.90 * (double)h) : 700);
  char buffer[50];
  sprintf(buffer, "%dx%d+10+10", w, h);
  this->SetDefaultGeometry(buffer);

  // Invoke super method

  this->Superclass::CreateWidget();

  this->SetWindowClass(this->GetApplication()->GetName());

  // Hide the main window until after all user interface is initialized.

  this->Withdraw();

  this->SetMinimumSize(640, 480);

  // Init

  vtkKWApplication *app = this->GetApplication();
  vtkVVApplication *vvapp = vtkVVApplication::SafeDownCast(app);

  int use_splash = (app->GetSupportSplashScreen() && 
                    app->GetSplashScreenVisibility() && 
                    app->GetNumberOfWindows() == 1);

  if (use_splash)
    {
    app->GetSplashScreen()->SetProgressMessage(
      ks_("Startup|Progress|Creating UI (panels)..."));
    }

  vtkKWUserInterfaceManagerNotebook *uim;

  uim = vtkKWUserInterfaceManagerNotebook::SafeDownCast(
    this->GetMainUserInterfaceManager());
  if (uim)
    {
    uim->EnableDragAndDropOff();
    }
  
  uim = vtkKWUserInterfaceManagerNotebook::SafeDownCast(
    this->GetSecondaryUserInterfaceManager());
  if (uim)
    {
    uim->EnableDragAndDropOff();
    }

  // Layout manager

  vtkVVSelectionFrameLayoutManager *layout_mgr = 
    this->GetDataSetWidgetLayoutManager();
  if (!layout_mgr->IsCreated())
    {
    layout_mgr->SetParent(this->GetViewFrame());
    layout_mgr->Create();
    }
  layout_mgr->SetDoubleClickOnLayoutFrameCommand(this, "Open");

  // Toolbars

  // Create the Open Wizard

  this->OpenWizard->SetMasterWindow(this);
  this->OpenWizard->Create();
  this->OpenWizard->SetTitle(NULL); // updated by Invoke()

  if (vvapp && vvapp->GetSessionFileExtensions())
    {
    vtksys_stl::string ext_desc(app->GetName());
    ext_desc += " Session";
    this->OpenWizard->AddValidFileExtension(
      ext_desc.c_str(), vvapp->GetSessionFileExtensions());
    }

  // Create the Startup page

  this->StartupPageWidget->SetParent(this->GetViewFrame());
  this->StartupPageWidget->Create();
  this->StartupPageWidget->SetOpenCommand(this, "Open");
  this->StartupPageWidget->SetDoubleClickCommand(this, "Open");
  this->StartupPageWidget->SetMostRecentFilesManager(
    this->MostRecentFilesManager);

  // Instead of allowing Drag&Drop only on the startup page, let's allow it
  // everywhere on the window...
  //this->StartupPageWidget->SetDropCommand(this, "Open");
  this->SetDropFileBinding(this, "Open");

  // Get some application settings from the Registry

  if (use_splash)
    {
    app->GetSplashScreen()->SetProgressMessage(
      ks_("Startup|Progress|Creating UI (user settings)..."));
    }

  this->CreateToolbars();

  this->AddCallbackCommandObservers();

  this->Update();
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::PackStartupPageWidget()
{
  vtkVVDataItemPool *data_pool = this->GetDataItemPool();
  int nb_data_items = data_pool->GetNumberOfDataItems();

  vtkVVSelectionFrameLayoutManager *layout_mgr = 
    this->GetDataSetWidgetLayoutManager();

  const char *to_pack, *to_unpack;
  if (nb_data_items)
    {
    to_pack = layout_mgr->GetWidgetName();
    to_unpack = this->StartupPageWidget->GetWidgetName();
    }
  else
    {
    to_pack = this->StartupPageWidget->GetWidgetName();
    to_unpack = layout_mgr->GetWidgetName();
    }

  this->Script(
    "pack %s -side top -fill both -expand yes -padx 0; catch {pack forget %s}",
    to_pack, to_unpack);
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::PopulateFileMenu()
{
  this->Superclass::PopulateFileMenu();

  int tcl_major, tcl_minor, tcl_patch_level;
  Tcl_GetVersion(&tcl_major, &tcl_minor, &tcl_patch_level, NULL);
  int show_icons = (tcl_major > 8 || (tcl_major == 8 && tcl_minor >= 5));

  vtkKWApplication *app = this->GetApplication();
  vtkKWMenu *menu = this->GetFileMenu();
  int idx;

  idx = this->GetFileMenuInsertPosition();
  idx = menu->InsertCommand(
    idx, this->GetFileOpenMenuLabel(), this, "Open");
  menu->SetItemAccelerator(idx, "Ctrl+O");
  menu->SetBindingForItemAccelerator(idx, menu->GetParentTopLevel());
  menu->SetItemHelpString(idx, ks_("Menu|File|Open a file"));
  if (show_icons)
    {
    menu->SetItemImageToPredefinedIcon(
      idx, vtkKWIcon::IconNuvola16x16ActionsFileOpen);
    menu->SetItemCompoundModeToLeft(idx);
    }
  idx++;

  this->InsertRecentFilesMenu(idx++, this);

  this->MostRecentFilesManager->LabelVisibilityInMenuOn();
  this->MostRecentFilesManager->SeparatePathInMenuOn();
  this->MostRecentFilesManager->BaseNameVisibilityInMenuOff();

  menu->DeleteItem(menu->GetIndexOfItem(this->GetFileCloseMenuLabel()));

  idx = menu->GetIndexOfItem(this->GetFileExitMenuLabel());

  idx = menu->InsertCommand(
    idx, this->GetFileLauncheExternalApplicationMenuLabel(), 
    app, "LaunchExternalApplication");
  menu->SetItemHelpString(idx, ks_("Menu|File|Launch External Application"));
  menu->SetBindingForItemAccelerator(idx, menu->GetParentTopLevel());
  idx++;

  menu->InsertSeparator(idx++);

  idx = menu->InsertCommand(
    idx, this->GetFileCloseSelectedDataMenuLabel(), 
    this, "CloseSelectedDataItem");
  menu->SetItemHelpString(
    idx, ks_("Menu|File|Close the data associated to the selected view"));
  if (show_icons)
    {
    menu->SetItemImageToPredefinedIcon(
      idx, vtkKWIcon::IconNuvola16x16ActionsFileClose);
    menu->SetItemCompoundModeToLeft(idx);
    }

  idx = this->GetFileMenuInsertPosition();

  menu->InsertSeparator(idx++);

  idx = menu->InsertCommand(
    idx, this->GetFileSaveSessionMenuLabel(), app, "SaveSession");
  menu->SetItemHelpString(idx, ks_("Menu|File|Save session"));
  menu->SetItemAccelerator(idx, "Ctrl+S");
  menu->SetBindingForItemAccelerator(idx, menu->GetParentTopLevel());
  if (show_icons)
    {
    menu->SetItemImageToPredefinedIcon(
      idx, vtkKWIcon::IconNuvola16x16ActionsFileSave);
    menu->SetItemCompoundModeToLeft(idx);
    }
  idx++;

  idx = menu->InsertCommand(
    idx, this->GetFileSaveVolumeMenuLabel(), this, "SaveSelectedVolume");
  menu->SetItemHelpString(idx, ks_("Menu|File|Save volume"));
  menu->SetItemAccelerator(idx, "Ctrl+Alt+S");
  menu->SetBindingForItemAccelerator(idx, menu->GetParentTopLevel());
  idx++;

  idx = menu->InsertCommand(
    idx, this->GetFileSaveFiducialsMenuLabel(), this, "SaveSelectedVolumeFiducials");
  menu->SetItemHelpString(idx, ks_("Menu|File|Save fiducials"));
  menu->SetItemAccelerator(idx, "Ctrl+F");
  menu->SetBindingForItemAccelerator(idx, menu->GetParentTopLevel());
  idx++;

  vtkVVSelectionFrameLayoutManager *layout_mgr = 
    this->GetDataSetWidgetLayoutManager();
  if (!layout_mgr->GetApplication())
    {
    layout_mgr->SetApplication(this->GetApplication());
    }

  idx = menu->InsertCommand(
    idx, this->GetFileSaveScreenshotMenuLabel(), 
    layout_mgr, "SaveScreenshotAllWidgets");
  menu->SetItemHelpString(idx, ks_("Menu|File|Save screenshot"));
  menu->SetItemAccelerator(idx, "Ctrl+R");
  menu->SetBindingForItemAccelerator(idx, menu->GetParentTopLevel());
  if (show_icons)
    {
    menu->SetItemImageToPredefinedIcon(
      idx, vtkKWIcon::IconNuvola16x16ActionsThumbnail);
    menu->SetItemCompoundModeToLeft(idx);
    }
  idx++;

  menu->InsertSeparator(idx++);

#ifdef _WIN32
  if (this->GetSupportPrint())
    {
    if (menu->HasItem(this->GetPrintOptionsMenuLabel()))
      {
      idx = menu->GetIndexOfItem(this->GetPrintOptionsMenuLabel());
      }
    
    idx = menu->InsertCommand(
      idx, this->GetFilePrintAllMenuLabel(), 
      layout_mgr, "PrintAllWidgets");
    menu->SetItemHelpString(idx, ks_("Menu|File|Print all views"));
    menu->SetItemAccelerator(idx, "Ctrl+P");
    menu->SetBindingForItemAccelerator(idx, menu->GetParentTopLevel());
    if (show_icons)
      {
      menu->SetItemImageToPredefinedIcon(
        idx, vtkKWIcon::IconNuvola16x16ActionsFilePrint);
      menu->SetItemCompoundModeToLeft(idx);
      }
    idx++;

    idx = menu->InsertCommand(
      idx, this->GetFilePrintSelectedMenuLabel(), 
      layout_mgr, "PrintSelectedWidget");
    menu->SetItemHelpString(idx, ks_("Menu|File|Print the selected view"));
    idx++;
    }
#endif  
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::PopulateEditMenu()
{
  this->Superclass::PopulateEditMenu();

#if defined(_WIN32) || (defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4))

  int tcl_major, tcl_minor, tcl_patch_level;
  Tcl_GetVersion(&tcl_major, &tcl_minor, &tcl_patch_level, NULL);
  int show_icons = (tcl_major > 8 || (tcl_major == 8 && tcl_minor >= 5));

  int idx;
  vtkVVSelectionFrameLayoutManager *layout_mgr = 
    this->GetDataSetWidgetLayoutManager();

  vtkKWMenu *edit_menu = this->GetEditMenu();
  idx = edit_menu->AddCommand(
    this->GetEditCopyScreenshotMenuLabel(), 
    layout_mgr, "CopyScreenshotAllWidgetsToClipboard");
  if (show_icons)
    {
    edit_menu->SetItemImageToPredefinedIcon(
      idx, vtkKWIcon::IconNuvola16x16DevicesCamera);
    edit_menu->SetItemCompoundModeToLeft(idx);
    }
#endif
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::PopulateWindowMenu()
{
  this->Superclass::PopulateWindowMenu();

  // We don't use the secondary panel
  vtkKWMenu *menu = this->GetWindowMenu();
  int idx;

  idx = menu->GetIndexOfItem(this->GetHideSecondaryPanelMenuLabel());
  if (idx < 0)                                                        
    {
    idx = menu->GetIndexOfItem(this->GetShowSecondaryPanelMenuLabel());
    }
  menu->RemoveBindingForItemAccelerator(idx, menu->GetParentTopLevel());
  menu->DeleteItem(idx);
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::PopulateHelpMenu()
{
  this->Superclass::PopulateHelpMenu();

  int tcl_major, tcl_minor, tcl_patch_level;
  Tcl_GetVersion(&tcl_major, &tcl_minor, &tcl_patch_level, NULL);
  int show_icons = (tcl_major > 8 || (tcl_major == 8 && tcl_minor >= 5));

  vtkKWApplication *app = this->GetApplication();
  vtkKWApplicationPro *app_pro = vtkKWApplicationPro::SafeDownCast(app);
  vtkKWMenu *menu = this->GetHelpMenu();
  int idx;

  // Update the help menu

  if (app->CanEmailFeedback())
    {
    idx = this->GetHelpMenuInsertPosition();
    idx = menu->InsertCommand(
      idx, this->GetHelpEmailFeedbackMenuLabel(), app, "EmailFeedback");
    if (show_icons)
      {
      menu->SetItemImageToPredefinedIcon(
        idx, vtkKWIcon::IconNuvola16x16AppsEmail);
      menu->SetItemCompoundModeToLeft(idx);
      }
    }
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::Close()
{
  return this->Superclass::Close();
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::CreateToolbars()
{
  if (!this->IsCreated())
    {
    return;
    }

  // This is just not standard, user have a progress in the top right, but
  // need to look in the bottom left to find what it is about
  // this->SetProgressGaugePositionToToolbar();
  // this->SetTrayFramePositionToToolbar();

  // Toolbar : file

  this->CreateFileToolbar();

  // Toolbar : quick view

  this->CreateQuickViewToolbar();

  // Layout manager

  this->CreateLayoutManagerToolbar();

  // Toolbar : interaction mode 2D
  
  this->CreateInteractionMode2DToolbar();

  // Toolbar : interaction mode 3D

  this->CreateInteractionMode3DToolbar();

  // Toolbar : misc tools

  this->CreateToolsToolbar();
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::CreateFileToolbar()
{
  if (!this->FileToolbar->IsCreated())
    {
    this->FileToolbar->SetParent(
      this->GetMainToolbarSet()->GetToolbarsFrame());
    this->FileToolbar->Create();
    }
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::CreateQuickViewToolbar()
{
  if (!this->QuickViewToolbar->IsCreated())
    {
    this->QuickViewToolbar->SetParent(
      this->GetMainToolbarSet()->GetToolbarsFrame());
    this->QuickViewToolbar->Create();
    }

  if (!this->GetMainToolbarSet()->HasToolbar(this->FileToolbar))
    {  
    this->GetMainToolbarSet()->AddToolbar(this->FileToolbar);
    }

  vtkKWPushButton *pb;
  vtkVVApplication *vvapp = 
    vtkVVApplication::SafeDownCast(this->GetApplication());

  // Toolbar : file : open
  
  pb = vtkKWPushButton::New();
  pb->SetParent(this->FileToolbar->GetFrame());
  pb->Create();
  pb->SetCommand(this, "Open");
  pb->SetBalloonHelpString(ks_("Toolbar|File|Open a file"));
  pb->SetImageToPredefinedIcon(vtkKWIcon::IconNuvola16x16ActionsFileOpen);
  this->FileToolbar->AddWidget(pb);
  pb->Delete();

  // Toolbar : file : save session
  
  if (vvapp)
    {
    pb = vtkKWPushButton::New();
    pb->SetParent(this->FileToolbar->GetFrame());
    pb->Create();
    pb->SetCommand(vvapp, "SaveSession");
    pb->SetBalloonHelpString(ks_("Toolbar|File|Save session"));
    pb->SetImageToPredefinedIcon(vtkKWIcon::IconNuvola16x16ActionsFileSave);
    this->FileToolbar->AddWidget(pb);
    pb->Delete();
    }
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::CreateLayoutManagerToolbar()
{
  this->GetDataSetWidgetLayoutManager()->CreateResolutionEntriesToolbar(
    this->GetMainToolbarSet()->GetToolbarsFrame());
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::CreateInteractionMode2DToolbar()
{
  if (!this->InteractionMode2DToolbar->IsCreated())
    {
    this->InteractionMode2DToolbar->SetParent(
      this->GetMainToolbarSet()->GetToolbarsFrame());
    this->InteractionMode2DToolbar->Create();
    }

}

//----------------------------------------------------------------------------
void vtkVVWindowBase::CreateInteractionMode3DToolbar()
{
  if (!this->InteractionMode3DToolbar->IsCreated())
    {
    this->InteractionMode3DToolbar->SetParent(
      this->GetMainToolbarSet()->GetToolbarsFrame());
    this->InteractionMode3DToolbar->Create();
    }

}

//----------------------------------------------------------------------------
void vtkVVWindowBase::CreateToolsToolbar()
{
  if (!this->ToolsToolbar->IsCreated())
    {
    this->ToolsToolbar->SetParent(
      this->GetMainToolbarSet()->GetToolbarsFrame());
    this->ToolsToolbar->Create();
    }

  if (!this->GetMainToolbarSet()->HasToolbar(this->ToolsToolbar))
    {  
    this->GetMainToolbarSet()->AddToolbar(this->ToolsToolbar);
    }

  vtkKWCheckButton *cb;

  // Toolbars : Oblique probe
  
  if (this->SupportObliqueProbeWidget)
    {
    static const unsigned int  image_oblique_probe_width          = 16;
    static const unsigned int  image_oblique_probe_height         = 16;
    static const unsigned int  image_oblique_probe_pixel_size     = 4;
    static const unsigned long image_oblique_probe_length         = 364;
    
    static const unsigned char image_oblique_probe[] = 
      "eNqtkz0KhDAQhdNZ2W0leAIL67SewcLazsLaxmLBQkHBnwvZehMLzxCy88KsiBgWdAMPxJ"
      "ePSWZetNZCPxCvF0nf0Ma8JK348H1fFkWxiot18naGVh6G4TyOo6iqKifNJHEh43VdJ+I4"
      "zombmX9HUaT7vtfk/xT2YT845pckSdK2bVFjIaWW+sabpkkEQbAQlzKPe8gsy0Rd1yvtkR"
      "Z+HYZBep63M8wrkluWJfYokmvhVdM0ruM4O8NS+AeP+SvWeKjxZY5zwJlwNpzRwkvcDXc8"
      "zS5FL9AT7tti4Y2HHqPX6PmfZjcjC8gE5ya31DceMoasIXPH2eED2URGr7J78o6z226+Hb"
      "y5R28X+gDQIXmI";

    cb = vtkKWCheckButton::New();
    cb->SetParent(this->ToolsToolbar->GetFrame());
    cb->Create();
    cb->SetBalloonHelpString(
      ks_("Toolbar|Tools|Display oblique probe in 3D"));
    cb->IndicatorVisibilityOff();
    cb->SetImageToPixels(image_oblique_probe,
                         image_oblique_probe_width, 
                         image_oblique_probe_height, 
                         image_oblique_probe_pixel_size, 
                         image_oblique_probe_length);
    cb->SetText("Oblique Probe");
    this->ToolsToolbar->AddWidget(cb);
    cb->Delete();
    }

  // Toolbars : 3D cursor
  
  if (this->SupportVolumeWidget)
    {
    static const unsigned int  image_cursor_width          = 16;
    static const unsigned int  image_cursor_height         = 16;
    static const unsigned int  image_cursor_pixel_size     = 4;
    static const unsigned long image_cursor_length         = 108;
    //  static const unsigned long image_cursor_decoded_length = 1024;

    static const unsigned char image_cursor[] = 
      "eNr7//8/w38aYyD4/58O9gxm+3G5ASZOgP4P5WBVQ4TfUfSTEXZU048vLIi0H6856OK49G"
      "PzD56wJlk/sjtxAVzux6IGH2AgZAY+AAAi1NdF";

    cb = vtkKWCheckButton::New();
    cb->SetParent(this->ToolsToolbar->GetFrame());
    cb->Create();
    cb->SetBalloonHelpString(
      ks_("Toolbar|Tools|Enable/disable 3D cursor"));
    cb->IndicatorVisibilityOff();
    cb->SetImageToPixels(image_cursor,
                         image_cursor_width, image_cursor_height, 
                         image_cursor_pixel_size, 
                         image_cursor_length);
    cb->SetText("Cursor");
    this->ToolsToolbar->AddWidget(cb);
    cb->Delete();

    // Toolbars : cropping

    cb = vtkKWCheckButton::New();
    cb->SetParent(this->ToolsToolbar->GetFrame());
    cb->Create();
    cb->SetBalloonHelpString(
      ks_(
        "Toolbar|Tools|Display cropping planes in 2D (double-click to reset)"));
    cb->IndicatorVisibilityOff();
    cb->SetImageToPredefinedIcon(vtkKWIcon::IconCropTool);
    cb->SetText("Cropping");
    this->ToolsToolbar->AddWidget(cb);
    cb->Delete();
    }
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::InteractionMode2DCallback(int mode)
{
  // This method calls SetInteractionMode on the render widgets,
  // which triggers InteractionModeChangedEvent, which this instance
  // listen to (see vtkVVDataItemVolume::CreateRenderWidget) in order to call
  // this very callback. Let's try to avoid too many calls.

  static int in_InteractionMode2DCallback = 0;
  if (in_InteractionMode2DCallback)
    {
    return;
    }
  in_InteractionMode2DCallback = 1;

  int nb_widgets = this->GetDataSetWidgetLayoutManager()->GetNumberOfWidgets();
  int need_update = 0, nb_rw2d = 0;
  for (int i = 0; i < nb_widgets; i++)
    {
    vtkVVSelectionFrame *sel_frame = vtkVVSelectionFrame::SafeDownCast(
      this->GetDataSetWidgetLayoutManager()->GetNthWidget(i));
    if (sel_frame)
      {
      vtkKW2DRenderWidget *rw2d = 
        vtkKW2DRenderWidget::SafeDownCast(sel_frame->GetRenderWidget());
      if (rw2d)
        {
        nb_rw2d++;
        if (rw2d->GetInteractionMode() != mode)
          {
          rw2d->SetInteractionMode(mode);
          need_update = 1;
          }
        }
      }
    }

  if (need_update || nb_rw2d == 1)
    {
    this->Update();
    }

  in_InteractionMode2DCallback = 0;
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::InteractionMode3DCallback(int mode)
{
  // This method calls SetInteractionMode on the render widgets,
  // which triggers InteractionModeChangedEvent, which this instance
  // listen to in order to call this very callback. Let's try to avoid
  // too many calls.

  static int in_InteractionMode3DCallback = 0;
  if (in_InteractionMode3DCallback)
    {
    return;
    }
  in_InteractionMode3DCallback = 1;

  int nb_widgets = this->GetDataSetWidgetLayoutManager()->GetNumberOfWidgets();
  int need_update = 0, nb_vw = 0;
  for (int i = 0; i < nb_widgets; i++)
    {
    vtkVVSelectionFrame *sel_frame = vtkVVSelectionFrame::SafeDownCast(
      this->GetDataSetWidgetLayoutManager()->GetNthWidget(i));
    if (sel_frame)
      {
      vtkKWVolumeWidget *vw = 
        vtkKWVolumeWidget::SafeDownCast(sel_frame->GetRenderWidget());
      if (vw)
        {
        nb_vw++;
        if (vw->GetInteractionMode() != mode)
          {
          vw->SetInteractionMode(mode);
          need_update = 1;
          }
        }
      }
    }

  if (need_update || nb_vw == 1)
    {
    this->Update();
    }

  in_InteractionMode3DCallback = 0;
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::QuickViewImageCallback()
{
  vtkKWImageWidget *iw_sel = 
    vtkKWImageWidget::SafeDownCast(this->GetSelectedRenderWidget());
  int nb_frames = this->GetNumberOfSelectionFramesUsingSelectedDataItem();
  for (int i = 0; i < nb_frames; i++)
    {
    vtkVVSelectionFrame *sel_frame = 
      this->GetNthSelectionFrameUsingSelectedDataItem(i);
    if (sel_frame)
      {
      vtkKWImageWidget *iw = 
        vtkKWImageWidget::SafeDownCast(sel_frame->GetRenderWidget());
      if (iw && (!iw_sel || iw_sel == iw))
        {
        this->GetDataSetWidgetLayoutManager()->SelectAndMaximizeWidgetCallback(
          sel_frame);
        return;
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::QuickViewVolumeCallback()
{
  vtkKWVolumeWidget *vw_sel = 
    vtkKWVolumeWidget::SafeDownCast(this->GetSelectedRenderWidget());
  int nb_frames = this->GetNumberOfSelectionFramesUsingSelectedDataItem();
  for (int i = 0; i < nb_frames; i++)
    {
    vtkVVSelectionFrame *sel_frame = 
      this->GetNthSelectionFrameUsingSelectedDataItem(i);
    if (sel_frame)
      {
      vtkKWVolumeWidget *vw = 
        vtkKWVolumeWidget::SafeDownCast(sel_frame->GetRenderWidget());
      if (vw && (!vw_sel || vw_sel == vw))
        {
        this->GetDataSetWidgetLayoutManager()->SelectAndMaximizeWidgetCallback(
          sel_frame);
        return;
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::QuickViewLightboxCallback()
{
  vtkKWLightboxWidget *lw_sel = 
    vtkKWLightboxWidget::SafeDownCast(this->GetSelectedRenderWidget());
  int nb_frames = this->GetNumberOfSelectionFramesUsingSelectedDataItem();
  for (int i = 0; i < nb_frames; i++)
    {
    vtkVVSelectionFrame *sel_frame = 
      this->GetNthSelectionFrameUsingSelectedDataItem(i);
    if (sel_frame)
      {
      vtkKWLightboxWidget *lw = 
        vtkKWLightboxWidget::SafeDownCast(sel_frame->GetRenderWidget());
      if (lw && (!lw_sel || lw_sel == lw))
        {
        this->GetDataSetWidgetLayoutManager()->SelectAndMaximizeWidgetCallback(
          sel_frame);
        return;
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::NewWindowCallback()
{
  vtkVVWindowBase *win = this->NewInstance();
  this->GetApplication()->AddWindow(win);
  win->Delete();
  win->Create();
  win->Display();
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::Render()
{
  this->Superclass::Render();

  int i, nb_widgets = 
    this->GetDataSetWidgetLayoutManager()->GetNumberOfWidgets();

  // Render the 2D widgets first for speed, then the volume widgets

  for (i = 0; i < nb_widgets; i++)
    {
    vtkVVSelectionFrame *sel_frame = vtkVVSelectionFrame::SafeDownCast(
      this->GetDataSetWidgetLayoutManager()->GetNthWidget(i));
    if (sel_frame)
      {
      vtkKWVolumeWidget *vw = vtkKWVolumeWidget::SafeDownCast(
        sel_frame->GetRenderWidget());
      if (!vw)
        {
        sel_frame->GetRenderWidget()->Render();
        }
      }
    }

  for (i = 0; i < nb_widgets; i++)
    {
    vtkVVSelectionFrame *sel_frame = vtkVVSelectionFrame::SafeDownCast(
      this->GetDataSetWidgetLayoutManager()->GetNthWidget(i));
    if (sel_frame)
      {
      vtkKWVolumeWidget *vw = vtkKWVolumeWidget::SafeDownCast(
        sel_frame->GetRenderWidget());
      if (vw)
        {
        sel_frame->GetRenderWidget()->Render();
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::DisableRenderStates()
{
  this->RenderStatesSaveCount++;
  
  if (this->RenderStatesSaveCount != 1)
    {
    return;
    }

  int nb_widgets = this->GetDataSetWidgetLayoutManager()->GetNumberOfWidgets();
  for (int i = 0; i < nb_widgets; i++)
    {
    vtkVVSelectionFrame *sel_frame = vtkVVSelectionFrame::SafeDownCast(
      this->GetDataSetWidgetLayoutManager()->GetNthWidget(i));
    if (sel_frame)
      {
      sel_frame->GetRenderWidget()->RenderStateOff();
      }
    }
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::RestoreRenderStates()
{
  this->RenderStatesSaveCount--;
  
  if (this->RenderStatesSaveCount != 0)
    {
    return;
    }

  int nb_widgets = this->GetDataSetWidgetLayoutManager()->GetNumberOfWidgets();
  for (int i = 0; i < nb_widgets; i++)
    {
    vtkVVSelectionFrame *sel_frame = vtkVVSelectionFrame::SafeDownCast(
      this->GetDataSetWidgetLayoutManager()->GetNthWidget(i));
    if (sel_frame)
      {
      sel_frame->GetRenderWidget()->RenderStateOn();
      }
    }

  this->Render();
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::OpenRecentFile(const char *fname)
{
  return this->Open(fname);
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::Open(const char *fname)
{
  // Clean filename 
  // (Ex: {} are added when a filename with a space is dropped on the window

  char *clean_fname = vtksys::SystemTools::RemoveChars(fname, "{}");

  //this->DisableRenderStates();
  this->RemoveCallbackCommandObservers();

  int enabled = this->GetEnabled();
  this->SetEnabled(0);
  this->Register(NULL); // LoadFromOpenWizard might exit if the app expired

  // If we are running in test mode, make sure we try hard not bring any
  // UI while opening the file...

  int res = 
    (this->OpenWizard && 
     this->OpenWizard->Invoke(clean_fname, vtkKWOpenWizard::INVOKE_QUIET) &&
     this->LoadFromOpenWizard(this->OpenWizard));
  if (!res)
    {
    vtksys_stl::string msg(k_("Error! Could not open file:\n"));
    msg += clean_fname;
    vtkKWMessageDialog::PopupMessage(
      this->GetApplication(), this, 
      k_("Open File"), msg.c_str(), vtkKWMessageDialog::ErrorIcon);
    }

  delete [] clean_fname;

  this->AddCallbackCommandObservers();
  //this->RestoreRenderStates();
  this->SetEnabled(enabled); // this does update the left control-panels
  this->Update(); // part of it will update the control panels a 2nd time :(
  this->UnRegister(NULL);

  return res;
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::Open()
{
  //this->DisableRenderStates();
  this->RemoveCallbackCommandObservers();

  int enabled = this->GetEnabled();
  this->SetEnabled(0);
  this->Register(NULL); // LoadFromOpenWizard might exit if the app expired

  vtkKWLoadSaveDialog *dialog = this->OpenWizard->GetLoadDialog();
  if (dialog)
    {
    dialog->RetrieveLastPathFromRegistry("OpenPath");
    }
  
  int res = 
    (this->OpenWizard && 
     this->OpenWizard->Invoke() &&
     this->LoadFromOpenWizard(this->OpenWizard));
  if (res)
    {
    dialog = this->OpenWizard->GetLoadDialog();
    if (dialog)
      {
      dialog->SaveLastPathToRegistry("OpenPath");
      }
    }

  this->AddCallbackCommandObservers();
  //this->RestoreRenderStates();
  this->SetEnabled(enabled); // this does update the left control-panels
  this->Update(); // part of it will update the control panels a 2nd time :(
  this->UnRegister(NULL);
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::SetMaximumNumberOfSimultaneousDataItems(int val)
{
  if (val <= 0)
    {
    val = 0;
    }
  if (val == this->MaximumNumberOfSimultaneousDataItems)
    {
    return;
    }

  this->MaximumNumberOfSimultaneousDataItems = val;
  this->Modified();
  this->LimitMaximumNumberOfSimultaneousDataItems();
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::LimitMaximumNumberOfSimultaneousDataItems()
{
  vtkVVDataItemPool *data_pool = this->GetDataItemPool();

  // Check if we reached our limit of data items

  int i, nb_items_in_win = 0;
  for (i = 0; i < data_pool->GetNumberOfDataItems(); i++)
    {
    if (data_pool->GetNthDataItem(i)->HasRenderWidgetInWindow(this))
      {
      nb_items_in_win++;
      }
    }

  // Remove some to comply with the limit

  while (nb_items_in_win >= this->MaximumNumberOfSimultaneousDataItems)
    {
    for (i = 0; i < data_pool->GetNumberOfDataItems(); i++)
      {
      if (data_pool->GetNthDataItem(i)->HasRenderWidgetInWindow(this))
        {
        // At this point we should probably try to release the file instance
        // not just the data item (even though releasing a file that has
        // a single data will release that file instance), so that a file
        // that created *multiple* data items does not end up "half-loaded"
        // after releasing some but not all of its data.
        if (!this->ReleaseDataItem(data_pool->GetNthDataItem(i)))
          {
          vtkErrorMacro(
            "Failed loading data, can not unload previous data!");
          return 0;
          }
        this->Update(); // This is needed for more memory to be de-allocated
        nb_items_in_win--;
        break;
        }
      }
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::LoadFromOpenWizard(vtkKWOpenWizard *openwizard)
{
   if (!openwizard)
    {
    vtkErrorMacro("Failed loading data, empty wizard!");
    return 0;
    }

  // Check if the application has expired. Do it each time we open
  // a file to prevent people from leaving VolView running all the time.

  vtkVVApplication *vvapp = 
    vtkVVApplication::SafeDownCast(this->GetApplication());
  if (!vvapp || vvapp->HasExpired())
    {
    return 0;
    }

  vtksys_stl::string file_name(openwizard->GetFileName());

  int res = 0;

  // Session ?

  vtkVVFileInstance *file = NULL;

  vtksys_stl::string ext = 
    vtksys::SystemTools::GetFilenameLastExtension(file_name);
  if (vvapp && vvapp->GetSessionFileExtensions())
    {
    vtksys_stl::vector<vtksys_stl::string> split_elems;
    vtksys::SystemTools::Split(
      vvapp->GetSessionFileExtensions(), split_elems, ' ');
    vtksys_stl::vector<vtksys_stl::string>::iterator it = split_elems.begin();
    vtksys_stl::vector<vtksys_stl::string>::iterator end = split_elems.end();
    for (; it != end; it++)
      {
      if (!strcmp(ext.c_str(), (*it).c_str()))
        {
        res = vvapp->LoadSession(file_name.c_str());
        break;
        }
      }
    }

  if (!res)
    {
    vtkVVFileInstancePool *file_pool = this->GetFileInstancePool();

    // Check if we reached our limit of data items, and release accordingly

    if (!this->LimitMaximumNumberOfSimultaneousDataItems())
      {
      vtkErrorMacro("Failed releasing data, can not load file!");
      return 0;
      }
    
    // We have the data already, just use it
    // We do not have the data, load it
    
    if (!file)
      {
      file = vtkVVFileInstance::New();
      file->SetName(file_pool->SuggestUniqueNameForFileInstanceWithFileName(
                      file_name.c_str()));
      int ok = file->LoadFromOpenWizard(openwizard);
      if (!ok)
        {
        vtkErrorMacro("Failed loading data!");
        file->Delete();
        return 0;
        }
      file_pool->AddFileInstance(file);
      file->Delete();
      }

    // Add the widgets

    file->AddDefaultRenderWidgets(this);
    
    // Make sure the window data pool references *all* the data 
    // from all the files

    for (int i = 0; i < file->GetDataItemPool()->GetNumberOfDataItems(); i++)
      {
      vtkVVDataItem *data = file->GetDataItemPool()->GetNthDataItem(i);
      this->GetDataItemPool()->AddDataItem(data);
      }

    res = 1;
    }

  // Save path

  this->AddRecentFile(file_name.c_str(), this, "OpenRecentFile");
  if (file)
    {
    this->MostRecentFilesManager->SetFileLabel(
      file_name.c_str(), 
      file->GetDataItemPool()->GetNthDataItem(0)->GetDescriptiveName());
    }
  this->MostRecentFilesManager->SaveFilesToRegistry();

  return res;
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::ReleaseFileInstance(vtkVVFileInstance *file)
{
  if (!file)
    {
    vtkErrorMacro("Failed unloading file, empty file!");
    return 0;
    }

  // The code below has many opportunities to unregister the file instance
  // itself. To make sure we are in control, register it first, and unregister
  // at the end, which should finally complete delete the instance, if
  // needed.

  file->Register(this);
  file->CancelAllDataTransfers();

  int has_released_data;
  do
    {
    has_released_data = 0;
    for (int i = 0; i < file->GetDataItemPool()->GetNumberOfDataItems(); i++)
      {
      has_released_data += 
        this->ReleaseDataItem(file->GetDataItemPool()->GetNthDataItem(i));
      }
    } while (has_released_data);

  // Remove the file instance from the main pool
  // Note that this will call UnRegister() on the file instance.

  int removed = 0;
  if (!file->GetDataItemPool()->GetNumberOfDataItems())
    {
    vtkVVApplication *vvapp = vtkVVApplication::SafeDownCast(
      this->GetApplication());
    if (this->GetFileInstancePool()->HasFileInstance(file))
      {
      this->GetFileInstancePool()->RemoveFileInstance(file);
      removed = 1;
      }
    }

  file->UnRegister(this);

  return removed;
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::ReleaseDataItem(vtkVVDataItem *data)
{
  if (!data)
    {
    vtkErrorMacro("Failed unloading data, empty data!");
    return 0;
    }

  if (data->HasRenderWidgetInWindow(this))
    {
    data->RemoveDefaultRenderWidgets(this);
    }

  // Not use by anyone else ? Release
  
  if (!data->GetNumberOfRenderWidgets())
    {
    data->ReleaseData();
    
    // Remove the item from the file instance data pool
    
    vtkVVFileInstance *data_file = data->GetFileInstance();
    if (data_file && data_file->GetDataItemPool()->HasDataItem(data))
      {
      data->SetFileInstance(NULL);
      data_file->GetDataItemPool()->RemoveDataItem(data);
      if (data_file->GetDataItemPool()->GetNumberOfDataItems() == 0)
        {
        this->ReleaseFileInstance(data_file);
        }
      }
    
    // Remove the item from the main pool
    // Note that this should call UnRegister() on data.
    
    if (this->GetDataItemPool()->HasDataItem(data))
      {
      this->GetDataItemPool()->RemoveDataItem(data);
      }
    }

  return 1;
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::CloseAllDataItems()
{
  if (this->GetDataItemPool())
    {
    int done = 0;
    while (!done)
      {
      done = 1;
      for (int i = 0; i < this->GetDataItemPool()->GetNumberOfDataItems(); i++)
        {
        if (this->ReleaseDataItem(this->GetDataItemPool()->GetNthDataItem(i)))
          {
          done = 0;
          break;
          }
        }
      }
    }

  if (this->DataSetWidgetLayoutManager)
    {
    this->DataSetWidgetLayoutManager->RemoveAllWidgets();
    }
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::CloseDataItem(vtkVVDataItem *data)
{
  int res = this->ReleaseDataItem(data);
  this->Update();
  return res;
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::CloseSelectedDataItem()
{
  this->ReleaseDataItem(this->GetSelectedDataItem());
  this->Update();
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::CloseAllFileInstances()
{
  if (this->GetFileInstancePool())
    {
    int done = 0;
    while (!done)
      {
      done = 1;
      for (int i = 0; 
           i < this->GetFileInstancePool()->GetNumberOfFileInstances(); i++)
        {
        if (this->ReleaseFileInstance(
              this->GetFileInstancePool()->GetNthFileInstance(i)))
          {
          done = 0;
          break;
          }
        }
      }
    }
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::SaveSelectedVolume() 
{
  vtkVVDataItem *data_item = this->GetSelectedDataItem();
  if (!data_item)
    {
    vtkKWMessageDialog::PopupMessage( 
      this->GetApplication(), this, 
      k_("Save Error"), 
      k_("A volume must be loaded and selected before you can save it."), 
      vtkKWMessageDialog::ErrorIcon);
    return 0;
    }
  
  vtkVVSaveDialog *dlg = vtkVVSaveDialog::New();
  dlg->SetParent(this);
  dlg->Create();
  dlg->RetrieveLastPathFromRegistry("SavePath");

  int success = 0;
  if (dlg->Invoke() && this->SaveVolume(data_item, dlg->GetFileName()))
    {
    dlg->SaveLastPathToRegistry("SavePath");
    success = 1;
    }

  dlg->Delete();
  return success;
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::SaveVolume(vtkVVDataItem *data_item, const char *fname) 
{
  if (!data_item || !fname)
    {
    return 0;
    }

  vtkVVSaveVolume *sv = vtkVVSaveVolume::New();
  sv->SetWindow(this);
  sv->SetApplication(this->GetApplication());
  sv->SetDataItemVolume(vtkVVDataItemVolume::SafeDownCast(data_item));
  sv->SetFileName(fname);

  int success = 1;
  if (!sv->Write())
    {
    vtkKWMessageDialog::PopupMessage(
      this->GetApplication(), this, 
      k_("Save Error"),
      k_("There was a problem writing the volume file(s).\n"
         "Please check the location and make sure you have write\n"
         "permissions and enough disk space."),
      vtkKWMessageDialog::ErrorIcon);
    success = 0;
    }

  sv->Delete();

  return success;
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::SaveSelectedVolumeFiducials() 
{
  vtkVVDataItem *data_item = this->GetSelectedDataItem();
  if (!data_item)
    {
    vtkKWMessageDialog::PopupMessage( 
      this->GetApplication(), this, 
      k_("Save Error"), 
      k_("A volume must be loaded and selected to save fiducials."), 
      vtkKWMessageDialog::ErrorIcon);
    return 0;
    }
  
  int nb_of_markers = vtkVVHandleWidget::GetNumberOfHandlesInDataItem( data_item );
  if (!nb_of_markers)
    {
    vtkKWMessageDialog::PopupMessage( 
      this->GetApplication(), this, 
      k_("Save Error"), 
      k_("No fiducials defined on this volume."), 
      vtkKWMessageDialog::ErrorIcon);
    return 0;
    }
  
  vtkVVSaveFiducialsDialog *dlg = vtkVVSaveFiducialsDialog::New();
  dlg->SetParent(this);
  dlg->Create();
  dlg->RetrieveLastPathFromRegistry("SavePath");

  int success = 0;
  if (dlg->Invoke() && this->SaveVolumeFiducials(data_item, dlg->GetFileName()))
    {
    dlg->SaveLastPathToRegistry("SavePath");
    success = 1;
    }

  dlg->Delete();
  return success;
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::SaveVolumeFiducials(vtkVVDataItem *data_item, const char *fname) 
{
  if (!data_item || !fname)
    {
    return 0;
    }

  vtkVVSaveFiducials *sv = vtkVVSaveFiducials::New();
  sv->SetWindow(this);
  sv->SetApplication(this->GetApplication());
  sv->SetDataItemVolume(vtkVVDataItemVolume::SafeDownCast(data_item));
  sv->SetFileName(fname);

  int success = 1;
  if (!sv->Write())
    {
    vtkKWMessageDialog::PopupMessage(
      this->GetApplication(), this, 
      k_("Save Error"),
      k_("There was a problem writing the fiducial file.\n"
         "Please check the location and make sure you have write\n"
         "permissions and enough disk space."),
      vtkKWMessageDialog::ErrorIcon);
    success = 0;
    }

  sv->Delete();

  return success;
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::Update()
{
  this->PackStartupPageWidget();

  this->Superclass::Update();

  int has_data = this->GetDataItemPool() 
    && this->GetDataItemPool()->GetNumberOfDataItems();
  vtkVVDataItem* data = this->GetSelectedDataItem();
  vtkVVDataItemVolume* volume_data = vtkVVDataItemVolume::SafeDownCast(data);
  vtkKWRenderWidget *sel_rw = this->GetSelectedRenderWidget();
  char command[256];

  vtkKWCheckButton *cb = NULL;

  // Cropping

  if (this->ToolsToolbar)
    {
    cb = vtkKWCheckButton::SafeDownCast(
      this->ToolsToolbar->GetWidget("Cropping"));
    if (cb)
      {
      if (volume_data)
        {
        cb->SetSelectedState(volume_data->GetCroppingMode(this));
        sprintf(command, "SetCroppingMode %s", this->GetTclName());
        cb->SetCommand(volume_data, command);
        cb->SetEnabled(
          volume_data->GetVolumeWidget(this) ?
          this->ToolsToolbar->GetEnabled() : 0);
        sprintf(command, "ResetCroppingPlanes %s", this->GetTclName());
        cb->SetBinding("<Double-1>", volume_data, command);
        }
      }
    }

  // Cursor

  if (this->ToolsToolbar)
    {
    cb = vtkKWCheckButton::SafeDownCast(
      this->ToolsToolbar->GetWidget("Cursor"));
    if (cb)
      {
      if (volume_data)
        {
        cb->SetSelectedState(volume_data->GetCursorVisibility(this));
        sprintf(command, "SetCursorVisibility %s", this->GetTclName());
        cb->SetCommand(volume_data, command);
        cb->SetEnabled(
          this->GetNumberOfRenderWidgetsUsingSelectedDataItem() > 1 ?
          this->ToolsToolbar->GetEnabled() : 0);
        }
      }
    }

  // Oblique Probe
  
  if (this->ToolsToolbar)
    {
    cb = vtkKWCheckButton::SafeDownCast(
      this->ToolsToolbar->GetWidget("Oblique Probe"));
    if (cb)
      {
      if (volume_data)
        {
        cb->SetSelectedState(volume_data->GetObliqueProbeVisibility(this));
        sprintf(command, "SetObliqueProbeVisibility %s", this->GetTclName());
        cb->SetCommand(volume_data, command);
        cb->SetEnabled(
          volume_data->GetVolumeWidget(this) ?
          this->ToolsToolbar->GetEnabled() : 0);
        }
      }
    }

  if (!has_data)
    {
    this->ToolsToolbar->SetEnabled(0);
    }

  this->UpdateTitle();
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::UpdateEnableState()
{
  this->Superclass::UpdateEnableState();

  this->PropagateEnableState(this->DataSetWidgetLayoutManager);

  this->PropagateEnableState(this->FileToolbar);
  this->PropagateEnableState(this->QuickViewToolbar);
  this->PropagateEnableState(this->ToolsToolbar);
  this->PropagateEnableState(this->InteractionMode2DToolbar);
  this->PropagateEnableState(this->InteractionMode3DToolbar);
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::UpdateMenuState()
{
  this->Superclass::UpdateMenuState();

  int menu_state = this->GetEnabled() 
    ? vtkKWOptions::StateNormal : vtkKWOptions::StateDisabled;

  int has_selected_data_state =
    this->GetSelectedDataItem() ? menu_state : vtkKWOptions::StateDisabled;

  int state = this->GetDataSetWidgetLayoutManager()->GetNumberOfWidgets() 
    ? menu_state : vtkKWOptions::StateDisabled;
  
  // Enable/Disable screenshot/print/open-in-selected if no dataset widgets

  if (this->FileMenu)
    {
    this->FileMenu->SetItemState(
      this->GetFileSaveScreenshotMenuLabel(), state);
    this->FileMenu->SetItemState(
      this->GetFileSaveVolumeMenuLabel(), has_selected_data_state);
    this->FileMenu->SetItemState(
      this->GetFileSaveFiducialsMenuLabel(), has_selected_data_state);
    if (this->GetSupportPrint())
      {
      this->FileMenu->SetItemState(this->GetFilePrintAllMenuLabel(), state);
      this->FileMenu->SetItemState(this->GetFilePrintSelectedMenuLabel(), state);
      }
    this->FileMenu->SetItemState(
      this->GetFileCloseSelectedDataMenuLabel(), has_selected_data_state);
    
    vtkVVApplication *vvapp = vtkVVApplication::SafeDownCast(
      this->GetApplication());
    this->FileMenu->SetItemState(
      this->GetFileLauncheExternalApplicationMenuLabel(), 
      (vvapp && vvapp->GetExternalApplicationPath()) ? menu_state : vtkKWOptions::StateDisabled);
    }
  
  if (this->EditMenu)
    {
    this->EditMenu->SetItemState(
      this->GetEditCopyScreenshotMenuLabel(), state);
    }
}

//----------------------------------------------------------------------------
vtkVVSelectionFrameLayoutManager* 
vtkVVWindowBase::GetDataSetWidgetLayoutManager()
{
  if (!this->DataSetWidgetLayoutManager)
    {
    this->DataSetWidgetLayoutManager = vtkVVSelectionFrameLayoutManager::New();
    }
  return this->DataSetWidgetLayoutManager;
}

//----------------------------------------------------------------------------
vtkVVSelectionFrame* vtkVVWindowBase::GetSelectedSelectionFrame()
{
  return vtkVVSelectionFrame::SafeDownCast(
    this->GetDataSetWidgetLayoutManager()->GetSelectedWidget());
}

//----------------------------------------------------------------------------
vtkVVDataItem* vtkVVWindowBase::GetSelectedDataItem()
{
  vtkVVSelectionFrame *sel_frame = this->GetSelectedSelectionFrame();
  if (sel_frame)
    {
    return sel_frame->GetDataItem();
    }
  return NULL;
}

//----------------------------------------------------------------------------
vtkKWRenderWidget* vtkVVWindowBase::GetSelectedRenderWidget()
{
  vtkVVSelectionFrame *sel_frame = this->GetSelectedSelectionFrame();
  if (sel_frame)
    {
    return sel_frame->GetRenderWidget();
    }
  return NULL;
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::GetNumberOfSelectionFramesUsingSelectedDataItem()
{
  vtkVVDataItem *data = this->GetSelectedDataItem();
  if (data)
    {
    return this->GetDataSetWidgetLayoutManager()->GetNumberOfWidgetsWithGroup(
      data->GetName());
    }
  return 0;
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::GetNumberOfRenderWidgetsUsingSelectedDataItem()
{
  return this->GetNumberOfSelectionFramesUsingSelectedDataItem();
}

//----------------------------------------------------------------------------
vtkVVSelectionFrame* 
vtkVVWindowBase::GetNthSelectionFrameUsingSelectedDataItem(int idx)
{
  vtkVVDataItem *data = this->GetSelectedDataItem();
  if (data)
    {
    return vtkVVSelectionFrame::SafeDownCast(
      this->GetDataSetWidgetLayoutManager()->GetNthWidgetWithGroup(
        idx, data->GetName()));
    }
  return NULL;
}

//----------------------------------------------------------------------------
vtkKWRenderWidget* vtkVVWindowBase::GetNthRenderWidgetUsingSelectedDataItem(
  int idx)
{
  vtkVVSelectionFrame *sel_frame = 
    this->GetNthSelectionFrameUsingSelectedDataItem(idx);
  if (sel_frame)
    {
    return sel_frame->GetRenderWidget();
    }
  return NULL;
}

//----------------------------------------------------------------------------
vtkKWImageWidget* vtkVVWindowBase::GetNthImageWidgetUsingSelectedDataItem(
  int idx)
{
  int nb_rw = this->GetNumberOfRenderWidgetsUsingSelectedDataItem();
  for (int i = 0; i < nb_rw; i++)
    {
    vtkKWImageWidget *iw = vtkKWImageWidget::SafeDownCast(
      this->GetNthRenderWidgetUsingSelectedDataItem(i));
    if (iw && idx-- == 0)
      {
      return iw;
      }
    }
  
  return NULL;
}

//----------------------------------------------------------------------------
vtkKWVolumeWidget* vtkVVWindowBase::GetNthVolumeWidgetUsingSelectedDataItem(
  int idx)
{
  int nb_rw = this->GetNumberOfRenderWidgetsUsingSelectedDataItem();
  for (int i = 0; i < nb_rw; i++)
    {
    vtkKWVolumeWidget *vw = vtkKWVolumeWidget::SafeDownCast(
      this->GetNthRenderWidgetUsingSelectedDataItem(i));
    if (vw && idx-- == 0)
      {
      return vw;
      }
    }
  
  return NULL;
}

//----------------------------------------------------------------------------
vtkKWLightboxWidget* vtkVVWindowBase::GetNthLightboxWidgetUsingSelectedDataItem(
  int idx)
{
  int nb_rw = this->GetNumberOfRenderWidgetsUsingSelectedDataItem();
  for (int i = 0; i < nb_rw; i++)
    {
    vtkKWLightboxWidget *lw = vtkKWLightboxWidget::SafeDownCast(
      this->GetNthRenderWidgetUsingSelectedDataItem(i));
    if (lw && idx-- == 0)
      {
      return lw;
      }
    }
  
  return NULL;
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::RenderAllRenderWidgetsUsingSelectedDataItem()
{
  int nb_rw = this->GetNumberOfRenderWidgetsUsingSelectedDataItem();
  for (int i = 0; i < nb_rw; i++)
    {
    vtkKWRenderWidget *rw = this->GetNthRenderWidgetUsingSelectedDataItem(i);
    if (rw)
      {
      rw->Render();
      }
    }
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::AddCallbackCommandObservers()
{
  this->Superclass::AddCallbackCommandObservers();

  this->AddCallbackCommandObserver(
    this->GetDataSetWidgetLayoutManager(), 
    vtkKWSelectionFrameLayoutManager::SelectionChangedEvent);
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::RemoveCallbackCommandObservers()
{
  this->Superclass::RemoveCallbackCommandObservers();

  this->RemoveCallbackCommandObserver(
    this->GetDataSetWidgetLayoutManager(), 
    vtkKWSelectionFrameLayoutManager::SelectionChangedEvent);
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::ProcessCallbackCommandEvents(vtkObject *caller,
                                                   unsigned long event,
                                                   void *calldata)
{
  vtkKW2DRenderWidget *caller_rw2d = 
    vtkKW2DRenderWidget::SafeDownCast(caller);
  vtkKWVolumeWidget *caller_vw = 
    vtkKWVolumeWidget::SafeDownCast(caller);
  vtkKWSelectionFrameLayoutManager *layout_mgr = 
    vtkKWSelectionFrameLayoutManager::SafeDownCast(caller);

  if (caller_rw2d || caller_vw)
    {
    switch (event)
      {
      case vtkKWEvent::InteractionModeChangedEvent:
        if (caller_rw2d)
          {
          this->InteractionMode2DCallback(caller_rw2d->GetInteractionMode());
          }
        else if (caller_vw)
          {
          this->InteractionMode3DCallback(caller_vw->GetInteractionMode());
          }
        break;
      }
    }

  if (layout_mgr)
    {
    switch (event)
      {
      case vtkKWSelectionFrameLayoutManager::SelectionChangedEvent:
        this->Update();
        break;
      }
    }

  this->Superclass::ProcessCallbackCommandEvents(caller, event, calldata);
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::UpdateTitle()
{
  vtksys_stl::string title(this->GetApplication()->GetName());
  vtkVVDataItem *data_item = this->GetSelectedDataItem();
  if (data_item)
    {
    title += " - ";
    title += data_item->GetDescriptiveName();
    }
  this->SetTitle(title.c_str());
}

//----------------------------------------------------------------------------
vtkKWApplicationSettingsInterface*
vtkVVWindowBase::GetApplicationSettingsInterface()
{
  // If not created, create the application settings interface, connect it
  // to the current window, and manage it with the current interface manager.

  if (!this->ApplicationSettingsInterface)
    {
    this->ApplicationSettingsInterface =
      vtkVVApplicationSettingsInterfaceBase::New();
    this->ApplicationSettingsInterface->SetWindow(this);
    this->ApplicationSettingsInterface->SetUserInterfaceManager(
      this->GetApplicationSettingsUserInterfaceManager());
    }
  return this->ApplicationSettingsInterface;
}

//----------------------------------------------------------------------------
vtkVVSnapshot* vtkVVWindowBase::TakeSnapshot()
{
  vtkVVSnapshot *snapshot = vtkVVSnapshot::New();
  int ok = this->UpdateSnapshot(snapshot);
  if (ok)
    {
    static char buffer[1024];
    time_t t = (time_t)vtksys::SystemTools::GetTime();
    strftime(buffer, sizeof(buffer), "%Y/%m/%d %H:%M:%S", localtime(&t));
    snapshot->SetDescription(buffer);
    this->GetSnapshotPool()->AddSnapshot(snapshot);
    }
  snapshot->Delete();

  return ok ? snapshot : NULL;
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::UpdateSnapshot(vtkVVSnapshot *snapshot)
{
  if (!snapshot)
    {
    return 0;
    }

  int paintbrush_count = 
    this->GetDataSetWidgetLayoutManager()->GetNumberOfPaintbrushWidgets();
  if (paintbrush_count)
    {
    vtkKWMessageDialog *dialog = vtkKWMessageDialog::New();
    dialog->SetApplication(this->GetApplication());
    dialog->SetStyleToMessage();
    dialog->SetMasterWindow(this);
    dialog->SetOptions(
      vtkKWMessageDialog::WarningIcon | 
      vtkKWMessageDialog::RememberYes |
      vtkKWMessageDialog::YesDefault);
    dialog->SetDialogName(
      vtkVVWindowBase::PaintbrushNotSavedInSnapshotDialogName);
    dialog->SetText("Paintbrushes and segmentation maps can not be stored in snapshots at the moment. Make sure to save them separately from the paintbrush panel.");
    dialog->SetTitle("Paintbrush not supported");
    dialog->Invoke();
    dialog->Delete();
    }

  vtkXMLObjectWriter *xmlw = this->GetNewXMLWriter();
  vtkXMLVVWindowBaseWriter *xmlw_win = 
    vtkXMLVVWindowBaseWriter::SafeDownCast(xmlw);
  if (xmlw_win)
    {
    xmlw_win->OutputSnapshotsOff();
    }
  vtkXMLDataElement *elem = xmlw->NewDataElement();
  if (xmlw->Create(elem))
    {
    snapshot->SetSerializedForm(elem);
    }
  xmlw->Delete();
  elem->Delete();

  return 1;
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::RestoreSnapshot(vtkVVSnapshot *snapshot)
{
  if (!snapshot)
    {
    return 0;
    }

  vtkXMLDataElement *elem = snapshot->GetSerializedForm();
  if (!elem)
    {
    return 0;
    }

  this->DisableRenderStates();

  vtkXMLObjectReader *xmlr = this->GetNewXMLReader();
  xmlr->SetObject(this);
  xmlr->Parse(elem);
  xmlr->Delete();

  this->RestoreRenderStates();
  this->Update();

  return 1;
}

//----------------------------------------------------------------------------
int vtkVVWindowBase::GetFileMenuInsertPosition()
{
  int super_idx = this->Superclass::GetFileMenuInsertPosition();

  // Find Close Data Items

  if (this->GetFileMenu()->HasItem(this->GetFileCloseSelectedDataMenuLabel()))
    {
    int idx = this->GetFileMenu()->GetIndexOfItem(
      this->GetFileCloseSelectedDataMenuLabel());
    if (idx < super_idx)
      {
      return idx;
      }
    }
  
  return super_idx;
}

//----------------------------------------------------------------------------
void vtkVVWindowBase::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);

  os << indent << "SupportVolumeWidget: " 
     << (this->SupportVolumeWidget ? "On\n" : "Off\n");
  os << indent << "SupportObliqueProbeWidget: " 
     << (this->SupportObliqueProbeWidget ? "On\n" : "Off\n");
  os << indent << "SupportLightboxWidget: " 
     << (this->SupportLightboxWidget ? "On\n" : "Off\n");
}
