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

  Program:   Visualization Toolkit
  Module:    vtkPVAnimationInterface.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1998-2000 Kitware Inc. 469 Clifton Corporate Parkway,
Clifton Park, NY, 12065, USA.

All rights reserved. No part of this software may be reproduced, distributed,
or modified, in any form or by any means, without permission in writing from
Kitware Inc.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkPVAnimationInterface.h"

#include "vtkKWCheckButton.h"
#include "vtkKWEntry.h"
#include "vtkKWFrame.h"
#include "vtkKWLabel.h"
#include "vtkKWLabeledEntry.h"
#include "vtkKWLabeledFrame.h"
#include "vtkKWMenu.h"
#include "vtkKWMenuButton.h"
#include "vtkKWPushButton.h"
#include "vtkKWScale.h"
#include "vtkKWText.h"
#include "vtkKWView.h"
#include "vtkObjectFactory.h"
#include "vtkPVApplication.h"
#include "vtkPVRenderView.h"
#include "vtkPVSource.h"
#include "vtkPVSourceCollection.h"
#include "vtkPVWidget.h"
#include "vtkPVWidgetCollection.h"
#include "vtkPVWindow.h"
#include "vtkKWLoadSaveDialog.h"
#include "vtkWindowToImageFilter.h"
#include "vtkJPEGWriter.h"
#include "vtkTIFFWriter.h"
#include "vtkPNGWriter.h"
#include "vtkRenderWindow.h"
#include "vtkPVProcessModule.h"
#include "vtkPVPart.h"
#include "vtkPVPartDisplay.h"
#include "vtkCompleteArrays.h"

#include "vtkPVAnimationInterfaceEntry.h"
#include "vtkCollectionIterator.h"
#include "vtkString.h"
#include "vtkKWRange.h"
#include "vtkCommand.h"
#include "vtkKWEvent.h"

#include <vtkstd/string>
#include <vtkstd/map>

// We need to:
// Format min/max/resolution entries better.
// Add callbacks to take the place of accept button.
// Handle methods with multiple entries.
// Handle special sources (contour, probe, threshold).

/* 
 * This part was generated by ImageConvert from image:
 *    play.png (zlib, base64)
 */
#define image_play_width         16
#define image_play_height        16
#define image_play_pixel_size    4
#define image_play_buffer_length 108

static unsigned char image_play[] = 
  "eNr7//8/w/9BhoFACYgFGbAAIvW7APEZbGaQoP8/NjNI1I9hBhn6UcwgUz/cDAr0g3AoBf"
  "rTKHB/GgXhl0ZB/KVRkH7SyE2/9MQARXskxQ==";

/* 
 * This part was generated by ImageConvert from image:
 *    stop.png (zlib, base64)
 */
#define image_stop_width         16
#define image_stop_height        16
#define image_stop_pixel_size    4
#define image_stop_buffer_length 64

static unsigned char image_stop[] = 
  "eNr7//8/w/9hgoFACYhdCGAlPPrLgfg/AVw+qn/Y6k8D4t0EcNr/YZRnAMXDIoM=";

/* 
 * This part was generated by ImageConvert from image:
 *    loop.png (zlib, base64)
 */
#define image_loop_width         16
#define image_loop_height        16
#define image_loop_pixel_size    4
#define image_loop_buffer_length 212

static unsigned char image_loop[] = 
  "eNrNk1ENwCAMRLGAhVnAAhZmYRZqYRawMAtYwMIszEJHk9tCSMuWfe2S+6H3CLTAzI5/4K"
  "pQTY2jG0jhRUlKMH3g5wd+QUbjffUBLhk8IeMVXmp7kw3G0SVDCp+rV/csyWSDpxc8Gbzc"
  "eXvBSyYp/NX7acBOyMzG/OQOBbPo5VHLg/lfmQN9ivCKtXtvg297VJq3VPre8k/+3QkrPX"
  "VE";

/* 
 * This part was generated by ImageConvert from image:
 *    goto_beginning.png (zlib, base64)
 */
#define image_goto_beginning_width         16
#define image_goto_beginning_height        16
#define image_goto_beginning_pixel_size    4
#define image_goto_beginning_buffer_length 188

static unsigned char image_goto_beginning[] = 
  "eNrN00ENgDAMBdBZmAUsYAELWJiFWcBCPaFlFkq30KQpLesNlpTDz94nwEDEhB8PrX7Z0n"
  "MVJ19p6sQXJ++2TTxbnbPFFy+tzKX1vLaca2v5w7B4dzYj136nOZ37Q8D3fdno4OeHgE9G"
  "h3z/EPC6Q39/CHjZYZ0/UL7SLMa+7OTjPOAP/r0LX11aGw==";

/* 
 * This part was generated by ImageConvert from image:
 *    goto_end.png (zlib, base64)
 */
#define image_goto_end_width         16
#define image_goto_end_height        16
#define image_goto_end_pixel_size    4
#define image_goto_end_buffer_length 184

static unsigned char image_goto_end[] = 
  "eNrNk1sNgDAMRWcBC1jAAhawMAuzgIV6QgsWykbSpCn3bvxBk/vT7Jy9VTXpx6lVapb0rL"
  "Umk74G/gSOexxwIF6Bw/joYHx0eN47erx3RN4cI94cGfRb9he8kPmPmm3AC9l/Y6fB+oWc"
  "v7G98xNy/55lvJB3FlnEo7fbagas9Yv+4O9dh3laGw==";


//===========================================================================
//***************************************************************************
class vtkPVAnimationInterfaceObserver: public vtkCommand
{
public:
  static vtkPVAnimationInterfaceObserver *New() 
    {return new vtkPVAnimationInterfaceObserver;};

  vtkPVAnimationInterfaceObserver()
    {
      this->AnimationInterface = 0;
    }

  virtual void Execute(vtkObject* wdg, unsigned long event,  
                       void* calldata)
    {
      if ( this->AnimationInterface)
        {
        this->AnimationInterface->ExecuteEvent(wdg, event, calldata);
        }
    }

  vtkPVAnimationInterface* AnimationInterface;
};

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

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkPVAnimationInterface);
vtkCxxRevisionMacro(vtkPVAnimationInterface, "1.72.2.10");

vtkCxxSetObjectMacro(vtkPVAnimationInterface,ControlledWidget, vtkPVWidget);

int vtkPVAnimationInterfaceCommand(ClientData cd, Tcl_Interp *interp,
                           int argc, char *argv[]);

//-----------------------------------------------------------------------------
vtkPVAnimationInterface::vtkPVAnimationInterface()
{
  this->Observer = vtkPVAnimationInterfaceObserver::New();
  this->Observer->AnimationInterface = this;
  this->ErrorEventTag = 0;

  this->CommandFunction = vtkPVAnimationInterfaceCommand;

  this->NumberOfFrames = 100;

  this->StopFlag = 0;
  this->InPlay = 0;
  this->Loop = 0;

  this->PVSource = NULL;

  this->View = NULL;
  this->Window = NULL;

  // Animation control
  //
  this->TopFrame = vtkKWFrame::New();

  this->ControlFrame = vtkKWLabeledFrame::New();

  this->ControlButtonFrame = vtkKWWidget::New();

  this->PlayButton = vtkKWPushButton::New();

  this->StopButton = vtkKWPushButton::New();

  this->GoToBeginningButton = vtkKWPushButton::New();

  this->GoToEndButton = vtkKWPushButton::New();

  this->LoopCheckButton = vtkKWCheckButton::New();

  this->TimeFrame = vtkKWWidget::New();

  this->NumberOfFramesEntry = vtkKWLabeledEntry::New();

  this->TimeScale = vtkKWScale::New();
  this->TimeRange = vtkKWRange::New();

  // Action and script editing

  this->ActionFrame = vtkKWLabeledFrame::New();

  this->ScriptCheckButtonFrame = vtkKWWidget::New();

  this->ScriptCheckButton = vtkKWCheckButton::New();

  this->ScriptEditor = vtkKWText::New();

  this->ControlledWidget = NULL;

  // Save button frame
  this->SaveFrame = vtkKWLabeledFrame::New();
  this->SaveButtonFrame = vtkKWWidget::New();
  this->SaveImagesButton = vtkKWPushButton::New();
  this->SaveGeometryButton = vtkKWPushButton::New();
  this->CacheGeometryCheck = vtkKWCheckButton::New();

  this->AnimationEntries = vtkCollection::New();
  this->AnimationEntriesIterator = this->AnimationEntries->NewIterator();
  this->AnimationEntriesFrame = vtkKWLabeledFrame::New();
  this->AddItemButton = vtkKWPushButton::New();
  this->DeleteItemButton = vtkKWPushButton::New();
  this->NewScriptString = 0;
  this->InShowEntryInFrame = 0;

  this->AnimationEntryInformation = vtkKWFrame::New();
  this->AnimationEntriesMenu = vtkKWMenuButton::New();

  this->Dirty = 1;
  this->ScriptAvailable = 0;
  this->UpdatingScript = 0;
}

//-----------------------------------------------------------------------------
vtkPVAnimationInterface::~vtkPVAnimationInterface()
{
  this->Observer->Delete();

  if ( this->TopFrame )
    {
    this->TopFrame->Delete();
    this->TopFrame = 0;
    }
  if (this->ControlFrame)
    {
    this->ControlFrame->Delete();
    this->ControlFrame = NULL;
    }
  if (this->ControlButtonFrame)
    {
    this->ControlButtonFrame->Delete();
    this->ControlButtonFrame = NULL;
    }
  if (this->PlayButton)
    {
    this->PlayButton->Delete();
    this->PlayButton = NULL;
    }
  if (this->StopButton)
    {
    this->StopButton->Delete();
    this->StopButton = NULL;
    }
  if (this->GoToBeginningButton)
    {
    this->GoToBeginningButton->Delete();
    this->GoToBeginningButton = NULL;
    }
  if (this->GoToEndButton)
    {
    this->GoToEndButton->Delete();
    this->GoToEndButton = NULL;
    }
  if (this->LoopCheckButton)
    {
    this->LoopCheckButton->Delete();
    this->LoopCheckButton = NULL;
    }
  if (this->TimeScale)
    {
    this->TimeScale->Delete();
    this->TimeScale = NULL;
    }
  if (this->TimeFrame)
    {
    this->TimeFrame->Delete();
    this->TimeFrame = NULL;
    }
  if (this->NumberOfFramesEntry)
    {
    this->NumberOfFramesEntry->Delete();
    this->NumberOfFramesEntry = NULL;
    }
  if (this->TimeRange)
    {
    this->TimeRange->Delete();
    this->TimeRange = 0;
    }

  if (this->ScriptEditor)
    {
    this->ScriptEditor->Delete();
    this->ScriptEditor = NULL;
    }
  
  if (this->ActionFrame)
    {
    this->ActionFrame->Delete();
    this->ActionFrame = NULL;
    }
  if (this->ScriptCheckButtonFrame)
    {
    this->ScriptCheckButtonFrame->Delete();
    this->ScriptCheckButtonFrame = NULL;
    }
  if (this->ScriptCheckButton)
    {
    this->ScriptCheckButton->Delete();
    this->ScriptCheckButton = NULL;
    }

  this->SaveFrame->Delete();
  this->SaveFrame = NULL;
  this->SaveButtonFrame->Delete();
  this->SaveButtonFrame = NULL;
  this->SaveImagesButton->Delete();
  this->SaveImagesButton = NULL;
  this->SaveGeometryButton->Delete();
  this->SaveGeometryButton = NULL;
  this->CacheGeometryCheck->Delete();
  this->CacheGeometryCheck = NULL;

  if ( this->AnimationEntries )
    {
    this->AnimationEntries->Delete();
    }
  this->AnimationEntries = 0;
  if ( this->AnimationEntriesIterator )
    {
    this->AnimationEntriesIterator->Delete();
    }
  this->AnimationEntriesIterator = 0;
  this->AnimationEntriesFrame->Delete();
  this->AnimationEntriesFrame = 0;
  this->AddItemButton->Delete();
  this->AddItemButton = 0;
  this->DeleteItemButton->Delete();
  this->DeleteItemButton = 0;
  this->AnimationEntryInformation->Delete();
  this->AnimationEntryInformation = 0;
  this->AnimationEntriesMenu->Delete();
  this->AnimationEntriesMenu = 0;

  this->SetControlledWidget(NULL);
  this->SetView(NULL);
  this->SetWindow(NULL);

  this->SetNewScriptString(0);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::Create(vtkKWApplication *app, char *frameArgs)
{  
  vtkPVApplication *pvApp = vtkPVApplication::SafeDownCast(app);

  if (this->Application)
    {
    vtkErrorMacro("Widget has already been created.");
    return;
    }

  if (pvApp == NULL)
    {
    vtkErrorMacro("Need the subclass vtkPVApplication to create this object.");
    return;
    }

  this->SetApplication(app);

  // Create the frame for this widget.

  this->Script("frame %s %s", this->GetWidgetName(), frameArgs);

  this->TopFrame->SetParent(this);
  this->TopFrame->ScrollableOn();
  this->TopFrame->Create(this->Application, 0);
  this->Script("pack %s -side top -fill both -expand t -anchor center", 
               this->TopFrame->GetWidgetName());

  // Animation Control

  this->ControlFrame->SetParent(this->TopFrame->GetFrame());
  this->ControlFrame->ShowHideFrameOn();
  this->ControlFrame->Create(this->Application, 0);
  this->ControlFrame->SetLabel("Animation Control");

  this->ControlButtonFrame->SetParent(this->ControlFrame->GetFrame());
  this->ControlButtonFrame->Create(this->Application, "frame", "");

  this->Script("pack %s -side top -fill none -expand t -anchor center", 
               this->ControlButtonFrame->GetWidgetName());

  // Animation Control: Play button to start the animation.

  this->PlayButton->SetParent(this->ControlButtonFrame);
  this->PlayButton->Create(this->Application, "");
  this->PlayButton->SetCommand(this, "Play");

  this->PlayButton->SetImageOption(image_play, 
                                   image_play_width, 
                                   image_play_height, 
                                   image_play_pixel_size,
                                   image_play_buffer_length);
  
  // Animation Control: Stop button to stop the animation.

  this->StopButton->SetParent(this->ControlButtonFrame);
  this->StopButton->Create(this->Application, "");
  this->StopButton->SetCommand(this, "Stop");
  
  this->StopButton->SetImageOption(image_stop, 
                                   image_stop_width, 
                                   image_stop_height, 
                                   image_stop_pixel_size,
                                   image_stop_buffer_length);

  // Animation Control: "go to beginning" button.

  this->GoToBeginningButton->SetParent(this->ControlButtonFrame);
  this->GoToBeginningButton->Create(this->Application, "");
  this->GoToBeginningButton->SetCommand(this, "GoToBeginning");

  this->GoToBeginningButton->SetImageOption(
    image_goto_beginning, 
    image_goto_beginning_width, 
    image_goto_beginning_height, 
    image_goto_beginning_pixel_size,
    image_goto_beginning_buffer_length);

  // Animation Control: "go to beginning" button.

  this->GoToEndButton->SetParent(this->ControlButtonFrame);
  this->GoToEndButton->Create(this->Application, "");
  this->GoToEndButton->SetCommand(this, "GoToEnd");

  this->GoToEndButton->SetImageOption(image_goto_end, 
                                      image_goto_end_width, 
                                      image_goto_end_height, 
                                      image_goto_end_pixel_size,
                                      image_goto_end_buffer_length);

  //  Animation Control: loop button to loop the animation.

  this->LoopCheckButton->SetParent(this->ControlButtonFrame);
  this->LoopCheckButton->Create(this->Application, "");
  this->LoopCheckButton->SetCommand(this, "LoopCheckButtonCallback");
  this->LoopCheckButton->SetState(this->Loop ? 1 : 0);
  this->LoopCheckButton->SetIndicator(0);

  this->LoopCheckButton->SetImageOption(image_loop, 
                                        image_loop_width, 
                                        image_loop_height, 
                                        image_loop_pixel_size,
                                        image_loop_buffer_length);

  //  Animation Control: pack the transport buttons

  this->Script("pack %s %s %s %s %s -side left -fill both -padx 1", 
               this->GoToBeginningButton->GetWidgetName(), 
               this->PlayButton->GetWidgetName(), 
               this->StopButton->GetWidgetName(),
               this->GoToEndButton->GetWidgetName(), 
               this->LoopCheckButton->GetWidgetName());

  // Animation Control: Time scale

  this->TimeScale->SetParent(this->ControlFrame->GetFrame());
  this->TimeScale->Create(this->Application, "");
  this->TimeScale->DisplayEntry();
  this->TimeScale->DisplayEntryAndLabelOnTopOff();
  this->TimeScale->DisplayLabel("Frame:");
  this->TimeScale->SetEndCommand(this, "TimeScaleCallback");
  this->TimeScale->SetEntryCommand(this, "TimeScaleCallback");

  this->Script("pack %s -side top -expand t -fill x", 
               this->TimeScale->GetWidgetName());

  this->TimeFrame->SetParent(this->ControlFrame->GetFrame());
  this->TimeFrame->Create(this->Application, "frame", "");

  this->Script("pack %s -side top -expand t -fill x", 
               this->TimeFrame->GetWidgetName());

  this->NumberOfFramesEntry->SetParent(this->TimeFrame);
  this->NumberOfFramesEntry->Create(this->Application);
  this->NumberOfFramesEntry->GetEntry()->SetWidth(6);
  this->NumberOfFramesEntry->SetLabel("Number Of Frames:");
  this->NumberOfFramesEntry->SetValue(this->NumberOfFrames);


  this->Script("bind %s <KeyPress-Return> {%s NumberOfFramesEntryCallback}",
               this->NumberOfFramesEntry->GetEntry()->GetWidgetName(),
               this->GetTclName());

  this->Script("bind %s <FocusOut> {%s NumberOfFramesEntryCallback}",
               this->NumberOfFramesEntry->GetEntry()->GetWidgetName(),
               this->GetTclName());

  this->Script("pack %s -side left -expand t -fill x", 
               this->NumberOfFramesEntry->GetWidgetName());

  this->TimeRange->SetParent(this->ControlFrame->GetFrame());
  this->TimeRange->ShowEntriesOn();
  this->TimeRange->Create(this->Application, 0);

  //this->Script("pack %s -side top -expand t -fill x", 
  //             this->TimeRange->GetWidgetName());

  // New Interface ----------------------------------------------------
  this->AnimationEntriesFrame->SetParent(this->TopFrame->GetFrame());
  this->AnimationEntriesFrame->ShowHideFrameOn();
  this->AnimationEntriesFrame->Create(this->Application, 0);
  this->AnimationEntriesFrame->SetLabel("Actions");
  this->AnimationEntryInformation->SetParent(this->AnimationEntriesFrame->GetFrame());
  this->AnimationEntryInformation->Create(this->Application, 0);
  this->AnimationEntriesMenu->SetParent(this->AnimationEntriesFrame->GetFrame());
  this->AnimationEntriesMenu->Create(this->Application, 0);
  vtkKWFrame* frame = vtkKWFrame::New();
  frame->SetParent(this->AnimationEntriesFrame->GetFrame());
  frame->Create(this->Application, 0);
  this->AddItemButton->SetParent(frame->GetFrame());
  this->AddItemButton->Create(this->Application, 0);
  this->AddItemButton->SetLabel("Add Action");
  this->DeleteItemButton->SetParent(frame->GetFrame());
  this->DeleteItemButton->Create(this->Application, 0);
  this->DeleteItemButton->SetLabel("Delete Action");
  this->Script("pack %s %s %s -side top -fill both -expand 1", 
    this->AnimationEntriesMenu->GetWidgetName(),
    this->AnimationEntryInformation->GetWidgetName(),
    frame->GetWidgetName());


  vtkKWFrame* fr = vtkKWFrame::New();
  fr->SetParent(frame->GetFrame());
  fr->Create(this->Application, 0);
  this->Script("pack %s -side left -fill both -expand 0", 
    this->AddItemButton->GetWidgetName());
  this->Script("pack %s -side left -fill both -expand 1", 
    fr->GetWidgetName());
  this->Script("pack %s -side left -fill both -expand 0", 
    this->DeleteItemButton->GetWidgetName());
  fr->Delete();
  //this->Script("%s configure -bg red", this->AnimationEntryInformation->GetWidgetName());
  frame->Delete();
  this->AddItemButton->SetCommand(this, "AddEmptySourceItem");

  // New Interface ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  // Action frame

  this->ActionFrame->SetParent(this->TopFrame->GetFrame());
  this->ActionFrame->ShowHideFrameOn();
  this->ActionFrame->Create(this->Application, 0);
  this->ActionFrame->SetLabel("Script");

  // Action frame: Script check button and script editor

  this->ScriptCheckButtonFrame->SetParent(this->ActionFrame->GetFrame());
  this->ScriptCheckButtonFrame->Create(this->Application, "frame", "");


  //this->Script("pack %s -side top -expand t -fill x", 
  //             this->ScriptCheckButtonFrame->GetWidgetName());

  this->ScriptCheckButton->SetParent(this->ScriptCheckButtonFrame);
  this->ScriptCheckButton->Create(this->Application, "-text {Script Editor}");
  this->ScriptCheckButton->SetCommand(this, "ScriptCheckButtonCallback");

  this->Script("pack %s -side left -expand f", 
               this->ScriptCheckButton->GetWidgetName());

  this->ScriptEditor->SetParent(this->ActionFrame->GetFrame());
  this->ScriptEditor->Create(this->Application, "-relief sunken -bd 2");

  this->Script("bind %s <FocusOut> {%s ScriptEditorCallback}",
    this->ScriptEditor->GetWidgetName(), this->GetTclName());
  this->Script("bind %s <KeyPress-Return> {%s ScriptEditorCallback}",
    this->ScriptEditor->GetWidgetName(), this->GetTclName());

  // Save frame stuff
  this->SaveFrame->SetParent(this->TopFrame->GetFrame());
  this->SaveFrame->ShowHideFrameOn();
  this->SaveFrame->SetLabel("Save");
  this->SaveFrame->Create(this->Application, 0);
  this->SaveButtonFrame->SetParent(this->SaveFrame->GetFrame());
  this->SaveButtonFrame->Create(this->Application, "frame", 0);
  this->SaveImagesButton->SetParent(this->SaveButtonFrame);
  this->SaveImagesButton->Create(this->Application, 0);
  this->SaveImagesButton->SetLabel("Save Images");
  this->SaveImagesButton->SetCommand(this, "SaveImagesCallback");
  this->SaveGeometryButton->SetParent(this->SaveButtonFrame);
  this->SaveGeometryButton->Create(this->Application, 0);
  this->SaveGeometryButton->SetLabel("Save Geometry");
  this->SaveGeometryButton->SetCommand(this, "SaveGeometryCallback");
  this->Script("pack %s %s -side left -expand t -fill x -padx 2 -pady 2", 
               this->SaveImagesButton->GetWidgetName(),
               this->SaveGeometryButton->GetWidgetName());

  this->CacheGeometryCheck->SetParent(this->SaveFrame->GetFrame());
  this->CacheGeometryCheck->Create(this->Application, 0);
  this->CacheGeometryCheck->SetText("Cache Geometry");
  this->CacheGeometryCheck->SetCommand(this, "CacheGeometryCheckCallback");

  this->Script("pack %s %s -side top -expand t -fill x -padx 2 -pady 2", 
               this->SaveButtonFrame->GetWidgetName(),
               this->CacheGeometryCheck->GetWidgetName());

  // Pack frames

  this->Script("pack %s %s -side top -expand t -fill x -padx 2 -pady 2", 
               this->ControlFrame->GetWidgetName(),
               this->AnimationEntriesFrame->GetWidgetName());

  //this->Script("pack %s -side top -expand t -fill x -padx 2 -pady 2", 
  //             this->ActionFrame->GetWidgetName());

  this->Script("pack %s -side top -expand t -fill x -padx 2 -pady 2", 
               this->SaveFrame->GetWidgetName());

  this->TimeRange->SetWholeRange(0, this->NumberOfFrames-1);
  this->TimeRange->SetRange(0, this->NumberOfFrames-1);
  this->UpdateInterface();

  this->AddEmptySourceItem();

  this->PlayButton->SetBalloonHelpString("Play animation.");
  this->StopButton->SetBalloonHelpString("Stop animation.");
  this->GoToBeginningButton->SetBalloonHelpString(
    "Go to the beginning of the animation.");
  this->GoToEndButton->SetBalloonHelpString(
    "Go to the end of the animation.");
  this->LoopCheckButton->SetBalloonHelpString(
    "Enable/Disable animation loop.");
  this->TimeScale->SetBalloonHelpString(
    "Current frame of the animation.");
  this->NumberOfFramesEntry->SetBalloonHelpString(
    "Total number of frames for the animation.");
  this->AnimationEntriesMenu->SetBalloonHelpString(
    "Select an animation action to edit.");
  this->AddItemButton->SetBalloonHelpString(
    "Add new action to the animation.");
  this->DeleteItemButton->SetBalloonHelpString(
    "Delete current action from the animation.");
  this->ScriptCheckButtonFrame->SetBalloonHelpString(
    "Open/Close the editor for manually editing the action Tcl script.");
  this->SaveImagesButton->SetBalloonHelpString(
    "Save each animation frame as an image.");
  this->SaveGeometryButton->SetBalloonHelpString(
    "Save geometry from each frame. This will create a series of .vtp files.");
  this->CacheGeometryCheck->SetBalloonHelpString(
    "Cache geometry when doing animation. This will "
    "speedup animation after the initial run at the cost "
    "of memory.");


}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::PrepareAnimationInterface(vtkPVWindow* win)
{
  int cc;
  for ( cc = 0; cc < this->AnimationEntries->GetNumberOfItems(); cc ++ )
    {
    this->UpdateSourceMenu(cc);
    }
  (void)win;
  // Try to find a good default value for the source.
  /*
  if (this->AnimationInterface->GetPVSource() == NULL)
    {
    vtkPVSource *pvs = this->GetCurrentPVSource();
    if (pvs == NULL && this->GetSourceList("Sources")->GetNumberOfItems() > 0)
      {
      pvs = (vtkPVSource*)this->GetSourceList("Sources")->GetItemAsObject(0);
      }
    this->AnimationInterface->SetPVSource(pvs);
    }
*/
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::UpdateInterface()
{
  if ( !this->AnimationEntries )
    {
    return;
    }
  if (this->PlayButton && this->PlayButton->IsCreated())
    {
    if (this->InPlay)
      {
      this->PlayButton->EnabledOff();
      }
    else
      {
      this->PlayButton->EnabledOn();
      }
    }

  if (this->StopButton && this->StopButton->IsCreated())
    {
    if (this->InPlay)
      {
      this->StopButton->EnabledOn();
      }
    else
      {
      this->StopButton->EnabledOff();
      }
    }

  if (this->GoToBeginningButton && this->GoToBeginningButton->IsCreated())
    {
    if (this->InPlay)
      {
      this->GoToBeginningButton->EnabledOff();
      }
    else
      {
      this->GoToBeginningButton->EnabledOn();
      }
    }

  if (this->GoToEndButton && this->GoToEndButton->IsCreated())
    {
    if (this->InPlay)
      {
      this->GoToEndButton->EnabledOff();
      }
    else
      {
      this->GoToEndButton->EnabledOn();
      }
    }

  if (this->NumberOfFramesEntry && this->NumberOfFramesEntry->IsCreated())
    {
    this->NumberOfFramesEntry->SetValue(this->NumberOfFrames);
    if (this->InPlay)
      {
      this->NumberOfFramesEntry->EnabledOff();
      }
    else
      {
      this->NumberOfFramesEntry->EnabledOn();
      }
    }

  if (this->TimeScale && this->TimeScale->IsCreated())
    {
    this->TimeScale->SetRange(0, this->NumberOfFrames-1);
    this->TimeScale->SetResolution(1);
    this->TimeRange->SetWholeRange(0, this->NumberOfFrames-1);
    this->TimeRange->SetResolution(1);
    if (this->InPlay)
      {
      // We do not disable it so that the slider will still be updated
      // during "Play"
      this->TimeScale->UnBind();
      }
    else
      {
      this->TimeScale->Bind();
      }
    }

  if (this->LoopCheckButton && this->LoopCheckButton->IsCreated())
    {
    this->LoopCheckButton->SetState(this->Loop);
    }
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetNumberOfFrames(int t)
{
  //cout << "Set NumberOfFrames: " << t << endl;
  this->NumberOfFrames= t;
  this->NumberOfFramesEntry->SetValue(t);
  float range[2];
  this->TimeRange->SetWholeRange(0, t);
  this->TimeRange->GetRange(range);
  this->TimeRange->SetRange(range[0], t);
  this->TimeScale->GetRange(range);
  this->TimeScale->SetRange(0, t-1);
  if ( !this->IsCreated() )
    {
    return;
    }
  this->AddTraceEntry("$kw(%s) SetNumberOfFrames %d", this->GetTclName(), t);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::NumberOfFramesEntryCallback()
{
  //cout << "NumberOfFramesEntryCallback" << endl;
  this->SetNumberOfFrames(static_cast<int>(this->NumberOfFramesEntry->GetValueAsFloat()));
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::EntryCallback()
{
  this->NumberOfFramesEntryCallback();
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetLoop(int v)
{
  if (this->Loop == v)
    {
    return;
    }
  this->Loop = v;
  this->Modified();

  this->AddTraceEntry("$kw(%s) SetLoop %d",
                      this->GetTclName(), this->GetLoop());
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::LoopCheckButtonCallback()
{
  this->SetLoop(this->LoopCheckButton->GetState());
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::ScriptCheckButtonCallback()
{
  if (this->ScriptCheckButton->GetState())
    {
    this->AddTraceEntry("$kw(%s) SetScriptCheckButtonState 1", 
                        this->GetTclName());
    this->Script("pack %s -side top -expand yes -fill x -padx 2",
                 this->ScriptEditor->GetWidgetName());
    }
  else
    {
    this->AddTraceEntry("$kw(%s) SetScriptCheckButtonState 0", 
                        this->GetTclName());
    this->Script("pack forget %s", 
                 this->ScriptEditor->GetWidgetName());
    }
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetScriptCheckButtonState(int val)
{
  if (this->ScriptCheckButton->GetState() == val)
    {
    return;
    }

  this->ScriptCheckButton->SetState(val);
  this->ScriptCheckButtonCallback();
}

//-----------------------------------------------------------------------------
int vtkPVAnimationInterface::GetCurrentTime()
{
  return static_cast<int>(this->TimeScale->GetValue());
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetCurrentTime(int time)
{
  this->TimeScale->SetValue(time);

  vtkPVApplication *pvApp = vtkPVApplication::SafeDownCast(this->Application);
  if (pvApp)
    {
    float ctime = static_cast<float>(this->GetCurrentTime()) / 
      static_cast<float>(this->NumberOfFrames-1);
    const char* script = this->ScriptEditor->GetValue();
    pvApp->BroadcastScript(
      "set globalPVTime %g\n"
      "%s", ctime, script);

    if (this->ControlledWidget)
      {
      this->ControlledWidget->ModifiedCallback();
      this->ControlledWidget->Reset();
      }
    
    // Generate the cache, or use previous cache.
    if (this->GetCacheGeometry())
      {
      this->Window->CacheUpdate(time, this->NumberOfFrames);
      }
    else
      {
      if (this->PVSource)
        {
        this->PVSource->MarkSourcesForUpdate(1);
        }
      vtkCollectionIterator* it = this->AnimationEntriesIterator;
      for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem() )
        {
        vtkPVAnimationInterfaceEntry* entry
          = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
        if ( entry->GetPVSource() )
          {
          entry->GetPVSource()->MarkSourcesForUpdate(1);
          }
        }
      }

    if (this->View)
      {
      this->View->EventuallyRender();
      }

    this->AddTraceEntry("$kw(%s) SetCurrentTime %d", 
                        this->GetTclName(), this->GetCurrentTime());

    // Allow the application GUI to be refreshed (ex: in a trace file)

    this->Script("update");
    }
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::TimeScaleCallback()
{
  this->SetCurrentTime(static_cast<int>(this->TimeScale->GetValue()));
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::Play()
{  
  // If playing, do not do anything

  if (this->InPlay)
    {
    return;
    }
  this->InPlay = 1;

  // Make sure we have the up to date entries for end and step.

  this->EntryCallback();

  // Make sure script is up to date
  
  this->UpdateNewScript();

  // Update the buttons according to the play status

  this->UpdateInterface();

  // We need a different end test if the step is negative.

  int t;

  // NOTE: the object registers itself for the following reason. The call
  // to "update" in the loop below (through SetCurrentTime()) enables the
  // user to exit the application. 
  // In that case all objects, including this one, are deleted, and this 
  // object's ivars will be trashed, resulting in a crash.
  // To prevent this object from being deleted, it registers itself before
  // the loop, and unregisters itself after the loop. If objects deletion
  // were scheduled, they will happen When UnRegister() is called.
  // Of course, the loop has to end, so the parent of this object should
  // make a call to Stop() before deleting it.

  this->Register(this);

  this->StopFlag = 0;
  do
    {
    //cout << "T: " << t << endl;
    t = this->GetCurrentTime();
    if (t >= this->GetGlobalEnd())
      {
      this->SetCurrentTime(this->GetGlobalStart());
      t = this->GetCurrentTime();
      }
    while (t < this->GetGlobalEnd() && !this->StopFlag)
      {
      ++t;
      if (t > this->GetGlobalEnd())
        {
        t = this->GetGlobalEnd();
        }
      this->SetCurrentTime(t);
      // The stop button can be used here because SetCurrentTime()
      // makes a call to "update"
      }
    } while (this->Loop && !this->StopFlag);

  this->InPlay = 0;
  this->StopFlag = 0;
  this->UpdateInterface();

  this->UnRegister(this);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::Stop()
{  
  this->StopFlag = 1;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::GoToBeginning()
{  
  this->SetCurrentTime(0);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::GoToEnd()
{  
  this->SetCurrentTime(this->GetNumberOfFrames()-1);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::UpdateSourceMenu(int idx)
{
  char methodAndArgString[1024];
  int sourceValid = 0;

  vtkPVAnimationInterfaceEntry* entry = this->GetSourceEntry(idx);

  // Remove all previous items form the menu.
  vtkKWMenu* menu = entry->GetSourceMenuButton()->GetMenu();
  menu->DeleteAllMenuItems();

  if (this->Window == NULL)
    {
    return;
    }

  // Update the selection menu.
  vtkPVSourceCollection* col = this->Window->GetSourceList("Sources");
  if (col)
    {
    vtkPVSource *source;
    col->InitTraversal();
    while ( (source = col->GetNextPVSource()) )
      {
      sprintf(methodAndArgString, "SetPVSource %s", source->GetTclName());
      menu->AddCommand(source->GetName(), entry, methodAndArgString);
      if (entry->GetPVSource() == source)
        {
        sourceValid = 1;
        }
      }
    }

  // The source may have been deleted. If so, then set our source to NULL.
  if ( ! sourceValid)
    {
    entry->SetPVSource(0);
    this->Dirty = 1;
    }
}

//-----------------------------------------------------------------------------
const char* vtkPVAnimationInterface::GetScript()
{
  return this->ScriptEditor->GetValue();
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetWindow(vtkPVWindow *window)
{
  if ( this->Window == window )
    {
    return;
    }
  if ( this->Window )
    {
    this->Window->RemoveObservers(this->ErrorEventTag);
    }
  this->Window = window;
  if ( this->Window )
    {
    this->ErrorEventTag = this->Window->AddObserver(vtkKWEvent::ErrorMessageEvent, this->Observer);
    }
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetView(vtkPVRenderView *renderView)
{
  this->View = renderView;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveImagesCallback()
{
  vtkPVProcessModule* pm = this->GetPVApplication()->GetProcessModule();
  vtkKWLoadSaveDialog* saveDialog = pm->NewLoadSaveDialog();
  this->GetWindow()->RetrieveLastPath(saveDialog, "SaveAnimationFile");
  saveDialog->SetParent(this);
  saveDialog->SaveDialogOn();
  saveDialog->Create(this->Application, 0);
  saveDialog->SetTitle("Save Animation Images");
  saveDialog->SetDefaultExtension(".jpg");
  saveDialog->SetFileTypes("{{jpeg} {.jpg}} {{tiff} {.tif}} {{Portable Network Graphics} {.png}}");

  if ( saveDialog->Invoke() &&
       strlen(saveDialog->GetFileName())>0 )
    {
    this->GetWindow()->SaveLastPath(saveDialog, "SaveAnimationFile");
    const char* filename = saveDialog->GetFileName();  

    // Split into root and extension.
    char* fileRoot;
    char* ptr;
    char* ext = NULL;
    fileRoot = new char[strlen(filename)+1];
    strcpy(fileRoot, filename);
    // Find extension (last .)
    ptr = fileRoot;
    while (*ptr != '\0')
      {
      if (*ptr == '.')
        {
        ext = ptr;
        }
      ++ptr;
      }
    if (ext == NULL)
      {
      vtkErrorMacro(<< "Could not find extension in " << filename);
      delete [] fileRoot;
      fileRoot = NULL;
      saveDialog->Delete();
      saveDialog = NULL;
      return;
      }
    // Separate the root from the extension.
    *ext = '\0';
    ++ext;

    this->SaveImages(fileRoot, ext);
    delete [] fileRoot;
    fileRoot = NULL;
    ext = NULL;
    }

  saveDialog->Delete();
  saveDialog = NULL;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveImages(const char* fileRoot, 
                                         const char* ext) 
{
  vtkWindowToImageFilter* winToImage;
  vtkImageWriter* writer;
  char *fileName;
  int fileCount;
  int t;

  winToImage = vtkWindowToImageFilter::New();
  winToImage->SetInput(this->View->GetRenderWindow());
  if (strcmp(ext,"jpg") == 0)
    {
    writer = vtkJPEGWriter::New();
    }
  else if (strcmp(ext,"tif") == 0)
    {
    writer = vtkTIFFWriter::New();
    }
  else if (strcmp(ext,"png") == 0)
    {
    writer = vtkPNGWriter::New();
    }
  else
    {
    vtkErrorMacro("Unknown extension " << ext << ", try: jpg, tif or png.");
    return;
    }
  writer->SetInput(winToImage->GetOutput());
  fileName = new char[strlen(fileRoot) + strlen(ext) + 25];      

  // Loop through all of the time steps.
  t = this->GetGlobalStart();
  fileCount = 0;
  while (t <= this->GetGlobalEnd())
    {
    this->SetCurrentTime(t);
    this->View->EventuallyRender();
    this->Script("update");

    // Create a file name for this image.
    sprintf(fileName, "%s%04d.%s", fileRoot, fileCount, ext);
    writer->SetFileName(fileName);
    winToImage->Modified();
    writer->Write();
    
    ++fileCount;
    ++t;
    }

  winToImage->Delete();
  winToImage = NULL;
  writer->Delete();
  writer = NULL;
  delete [] fileName;
  fileName = NULL;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveGeometryCallback()
{
  vtkPVProcessModule* pm = this->GetPVApplication()->GetProcessModule();
  int numPartitions = pm->GetNumberOfPartitions();
  
  vtkKWLoadSaveDialog* saveDialog = pm->NewLoadSaveDialog();
  this->GetWindow()->RetrieveLastPath(saveDialog, "SaveGeometryFile");
  saveDialog->SetParent(this);
  saveDialog->SaveDialogOn();
  saveDialog->Create(this->Application, 0);
  saveDialog->SetTitle("Save Animation Geometry");
  saveDialog->SetDefaultExtension(".pvd");
  saveDialog->SetFileTypes("{{ParaView Data Files} {.pvd}}");
  if(saveDialog->Invoke() && (strlen(saveDialog->GetFileName()) > 0))
    {
    this->GetWindow()->SaveLastPath(saveDialog, "SaveGeometryFile");
    this->SaveGeometry(saveDialog->GetFileName(), numPartitions);
    }

  saveDialog->Delete();
  saveDialog = NULL;
}


//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveGeometry(const char* fileName, 
                                           int numPartitions) 
{
  vtkPVProcessModule* pm = this->GetPVApplication()->GetProcessModule();
  vtkPVSourceCollection* sources = this->GetWindow()->GetSourceList("Sources");
  
  // Create the animation writer pipeline.
  pm->ServerScript(
    "vtkXMLPVAnimationWriter pvAnimWriter\n"
    "pvAnimWriter SetFileName {%s}\n"
    "pvAnimWriter SetNumberOfPieces {%d}\n"
    "pvAnimWriter SetPiece [[$Application GetProcessModule] GetPartitionId]\n",
    fileName, numPartitions);
  
  if(numPartitions > 1)
    {
    vtkPVSource* source;
    sources->InitTraversal();
    while((source = sources->GetNextPVSource()))
      {
      if(source->GetVisibility())
        {
        const char* sourceName = source->GetName();
        int numParts = source->GetNumberOfParts();
        for(int partIdx = 0; partIdx < numParts; ++partIdx)
          {
          vtkPVPart* part = source->GetPart(partIdx);
          pm->ServerScript(
            "set pvAnimCompleteArrays {pvAnimCompleteArrays%s_%d}\n"
            "vtkCompleteArrays ${pvAnimCompleteArrays}\n"
            "${pvAnimCompleteArrays} SetInput [%s GetOutput]\n"
            "pvAnimWriter AddInput [${pvAnimCompleteArrays} GetOutput] {%s}",
            sourceName, partIdx, part->GetGeometryTclName(), sourceName);
          }
        }
      }
    
    // Only write the animation file once on each disk.
    pm->ServerScript(
      "vtkPVSummaryHelper pvAnimHelper\n"
      "pvAnimHelper SetWriter pvAnimWriter\n"
      "pvAnimHelper SetController [$Application GetController]\n"
      "pvAnimHelper SynchronizeSummaryFiles\n"
      "pvAnimHelper Delete");
    }
  else
    {
    vtkPVSource* source;
    sources->InitTraversal();
    while((source = sources->GetNextPVSource()))
      {
      if(source->GetVisibility())
        {
        const char* sourceName = source->GetName();
        int numParts = source->GetNumberOfParts();
        for(int partIdx = 0; partIdx < numParts; ++partIdx)
          {
          vtkPVPart* part = source->GetPart(partIdx);
          pm->ServerScript("pvAnimWriter AddInput [%s GetOutput] {%s}",
                           part->GetGeometryTclName(), sourceName);
          }
        }
      }
    }
  
  // Start the animation.
  pm->ServerScript("pvAnimWriter Start");
  
  // Loop through all of the time steps.
  for(int t = this->GetGlobalStart(); t <= this->GetGlobalEnd(); ++t)
    {
    // Update the animation to this time step.
    this->SetCurrentTime(t);
    this->View->EventuallyRender();
    this->Script("update");
    
    // Write this time step.
    pm->ServerScript("pvAnimWriter WriteTime {%d}", t);
    }
  
  // Finish the animation.
  pm->ServerScript("pvAnimWriter Finish");
  
  // Cleanup the writer pipeline.
  pm->ServerScript("pvAnimWriter Delete");
  
  if(numPartitions > 1)
    {
    vtkPVSource* source;
    sources->InitTraversal();
    while((source = sources->GetNextPVSource()))
      {
      if(source->GetVisibility())
        {
        const char* sourceName = source->GetName();
        int numParts = source->GetNumberOfParts();
        for(int partIdx = 0; partIdx < numParts; ++partIdx)
          {
          pm->ServerScript("pvAnimCompleteArrays%s_%d Delete\n",
                           sourceName, partIdx);
          }
        }
      }
    }  
}


//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveInBatchScript(ofstream *file, 
                                                const char* imageFileName,
                                                const char* geometryFileName)
{
  char *root;
  char *ext;
  char *ptr;
  int t;
  int timeIdx;
  char countStr[10];

  // Loop through all of the time steps.
  t = this->GetGlobalStart();
  timeIdx = 0;
  while (t < this->GetGlobalEnd())
    {
    float ctime = static_cast<float>(t) / 
      static_cast<float>(this->NumberOfFrames-1);

    *file << "set globalPVTime " << ctime << "\n";
    *file << this->GetScript() << endl;
    sprintf(countStr, "%05d", (int)(timeIdx));
    if (imageFileName)
      {
      *file << "RenWin1 Render\n";
      *file << "compManager Composite\n";
      *file << "if {$myProcId == 0} {\n";  
      root = new char[strlen(imageFileName)+1];
      strcpy(root, imageFileName);
      ext = NULL;
      ptr = root;
      while(*ptr)
        { // Find the extenstion
        if (*ptr == '.')
          {
          ext = ptr;
          }
        ++ptr;
        }
      if (ext)
        {
        *ext = '\0';
        ++ext;
        *file << "\t" << "ImageWriter SetFileName {" << root << countStr
              << "." << ext << "}\n";
        }
      else
        {
        *file << "\t" << "ImageWriter SetFileName {" << root << countStr << "}\n";
        }
      *file << "\t" << "ImageWriter Write\n";
      *file << "}\n";
      delete [] root;
      }
    if (geometryFileName)
      {
      this->GetWindow()->SaveGeometryInBatchFile(file, 
                                                 geometryFileName,
                                                 timeIdx);
      }
    *file << endl;
    ++timeIdx;
    ++t;
    }
}


//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::CacheGeometryCheckCallback()
{
  if ( ! this->GetCacheGeometry())
    {
    this->Window->RemoveAllCaches();
    }
}

//-----------------------------------------------------------------------------
int vtkPVAnimationInterface::GetCacheGeometry()
{
  return this->CacheGeometryCheck->GetState();
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetCacheGeometry(int flag)
{
  this->CacheGeometryCheck->SetState(flag);
  this->CacheGeometryCheckCallback();
}

//-----------------------------------------------------------------------------
vtkPVApplication* vtkPVAnimationInterface::GetPVApplication()
{
  return vtkPVApplication::SafeDownCast(this->Application);
}

//-----------------------------------------------------------------------------
vtkPVAnimationInterfaceEntry* vtkPVAnimationInterface::AddEmptySourceItem()
{
  vtkPVAnimationInterfaceEntry* entry = vtkPVAnimationInterfaceEntry::New();
  entry->SetApplication(this->Application);
  entry->SetParent(this);
  this->AnimationEntries->AddItem(entry);
  entry->SetParent(this->AnimationEntryInformation->GetFrame());
  entry->SetTraceReferenceObject(this);
  int idx = this->AnimationEntries->GetNumberOfItems()-1;
  entry->SetCurrentIndex(idx);
  entry->Create(this->GetPVApplication(), 0);
  this->UpdateEntries();
  this->ShowEntryInFrame(idx);
  this->AddTraceEntry("$kw(%s) AddEmptySourceItem", this->GetTclName());
  entry->Delete();
  this->Dirty = 1;
  return entry;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::DeleteSourceItem(int item)
{
  this->AnimationEntries->InitTraversal();
  if ( item < 0 && item >= this->AnimationEntries->GetNumberOfItems() )
    {
    vtkErrorMacro(<< "Item " << item << " is not in the collection (" 
      << this->AnimationEntries->GetNumberOfItems() << ")");
    return;
    }
  
  this->Dirty = 1;
  this->AnimationEntries->RemoveItem(item);
  this->AddTraceEntry("$kw(%s) DeleteSourceItem %d", this->GetTclName(), item);
  this->UpdateEntries();
  this->ShowEntryInFrame(0);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::EmptyEntryFrame()
{
  vtkKWWidget* frame = this->AnimationEntryInformation->GetFrame();
  this->Script("catch {eval pack forget [pack slaves %s]}",
    frame->GetWidgetName());
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::ShowEntryInFrame(int idx)
{
  vtkPVAnimationInterfaceEntry* entry = this->GetSourceEntry(idx);
  this->ShowEntryInFrame(entry, idx);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::ShowEntryInFrame(
  vtkPVAnimationInterfaceEntry* entry, int in_idx)
{
  this->EmptyEntryFrame();
  if ( !entry )
    {
    this->AnimationEntriesMenu->SetButtonText("");
    this->DeleteItemButton->EnabledOff();
    return;
    }
  this->Script("pack %s -side top -expand 1 -fill both", entry->GetWidgetName());
  int idx = in_idx;
  if ( idx < 0 )
    {
    idx = this->GetSourceEntryIndex(entry);
    }
  if ( idx < 0 )
    {
    return;
    }
  char buffer[1024];
  sprintf(buffer, "DeleteSourceItem %d", idx);
  if ( this->AnimationEntries->GetNumberOfItems() <= 1 )
    {
    this->DeleteItemButton->EnabledOff();
    }
  else
    {
    this->DeleteItemButton->SetCommand(this, buffer);
    this->DeleteItemButton->EnabledOn();
    }
  entry->CreateLabel(idx);
  this->AnimationEntriesMenu->SetButtonText(entry->GetLabel());
  this->UpdateEntries();
  if ( this->InShowEntryInFrame )
    {
    return;
    }
  this->InShowEntryInFrame = 1;
  this->UpdateSourceMenu(idx);
  entry->UpdateMethodMenu();
  this->InShowEntryInFrame = 0;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::UpdateEntries()
{
  vtkCollectionIterator* it = this->AnimationEntriesIterator;
  char* command = vtkString::Duplicate("ShowEntryInFrame XXXXXXXXXXXXXXXXX");
  int idx = 0;
  this->AnimationEntriesMenu->GetMenu()->DeleteAllMenuItems();
  for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem() )
    {
    vtkPVAnimationInterfaceEntry* entry
      = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
    entry->CreateLabel(idx);
    const char* label = entry->GetLabel();
    sprintf(command, "ShowEntryInFrame %d", idx);
    this->AnimationEntriesMenu->AddCommand(label, this, command); 
    idx ++;
    }
  delete [] command;
  this->UpdateNewScript();
}

//-----------------------------------------------------------------------------
int vtkPVAnimationInterface::GetSourceEntryIndex(vtkPVAnimationInterfaceEntry* entry)
{
  this->AnimationEntries->InitTraversal();
  int cc;
  for ( cc = 0; cc < this->AnimationEntries->GetNumberOfItems(); cc ++ )
    {
    vtkObject* o = this->AnimationEntries->GetItemAsObject(cc);
    if ( o == entry )
      {
      return cc;
      }
    }
  return -1;
}

//-----------------------------------------------------------------------------
vtkPVAnimationInterfaceEntry* vtkPVAnimationInterface::GetSourceEntry(int idx)
{
  this->AnimationEntries->InitTraversal();
  if ( idx < 0 && idx >= this->AnimationEntries->GetNumberOfItems() )
    {
    vtkErrorMacro(<< "Item " << idx << " is not in the collection (" 
      << this->AnimationEntries->GetNumberOfItems() << ")");
    return 0;
    }

  vtkPVAnimationInterfaceEntry* entry
    = vtkPVAnimationInterfaceEntry::SafeDownCast(
      this->AnimationEntries->GetItemAsObject(idx));
  if ( entry )
    {
    entry->SetCurrentIndex(idx);
    }
  return entry;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::UpdateNewScript()
{
  if ( !this->AnimationEntriesIterator )
    {
    return;
    }
  if ( this->UpdatingScript )
    {
    return;
    }
  this->UpdatingScript = 1;
  ostrstream str;
  ostrstream cstr;
  //str << "puts \"------------- start --------------\"" << endl;
  str << "# globalPVTime is provided by the animation " << endl;
  str << "# interface for convenience. " << endl;
  str << "# It varies linearly between 0 and 1 (0 at the " << endl;
  str << "# first frame, 1 at the last frame).\n" << endl;
  vtkCollectionIterator* it = this->AnimationEntriesIterator;
  int cnt = 0;
  int script_available = 0;
  if ( this->AnimationEntries->GetNumberOfItems() > 0 )
    {
    typedef vtkstd::map<vtkstd::string, int> smaptype;
    smaptype smap;


    for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem() )
      {
      vtkPVAnimationInterfaceEntry* entry
        = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
      entry->Prepare();
      if ( entry->GetPVSource() && entry->GetPVSource()->GetVTKSourceTclName() )
        {
        smap[entry->GetPVSource()->GetVTKSourceTclName()] = 1;
        cnt ++;
        }
      if ( entry->GetDirty() )
        {
        this->Dirty = 1;
        //cout << "Entry changed" << endl;
        }
      }
    if ( cnt )
      {
      str << "# The available sources are:" << endl;
      str << "# ";

      smaptype::iterator sit;
      for ( sit = smap.begin(); sit != smap.end(); ++sit )
        {
        str << sit->first.c_str() << " ";
        }
      str << endl;
      script_available = 1;
      }
    }
  if ( !cnt )
    {
    str << "# The available sources are: none." << endl;
    }
  str << "# Note: Only sources listed above can be used in the script." << endl
      << "# Other sources will not be updated during the animation. " << endl;
  if ( !this->Dirty)
    {
    //cout << " \\- No change" << endl;
    this->UpdatingScript = 0;
    return;
    }
  str << endl;
  for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem() )
    {
    vtkPVAnimationInterfaceEntry* entry
      = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
    if ( entry->GetScript() )
      {
      str << entry->GetTimeEquation(this->NumberOfFrames) << endl;
      str << entry->GetScript() << endl;
      script_available = 1;
      }
    entry->SetDirty(0);
    }
  //str << "puts \"-------------- end ---------------\"" << endl;
  str << ends;
  cstr << ends;
  this->SetNewScriptString(str.str());
  str.rdbuf()->freeze(0);
  cstr.rdbuf()->freeze(0);
  this->ScriptEditor->SetValue(this->NewScriptString);
  this->Dirty = 0;

  this->ScriptAvailable = script_available;
  this->UpdatingScript = 0;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::ScriptEditorCallback()
{
  const char* script = this->ScriptEditor->GetValue();
  unsigned int cc;
  ostrstream str;
  str << "SetScript {";
  for ( cc = 0; cc< strlen(script); cc ++ )
    {
    int ch = script[cc];
    switch ( ch )
      {
      case '\"': str << "\\\""; break;
      case '{': str << "\\{"; break;
      case '}': str << "\\}"; break;
      case '\n': str << "\\\n"; break;
      case '\\': str << "\\\\"; break;
    default: str << (char)ch; break;
      }
    }
  str << "}" << ends;
  //cout << "Script: " << str.str() << endl;
  str.rdbuf()->freeze(0);
}

//-----------------------------------------------------------------------------
int vtkPVAnimationInterface::GetGlobalStart()
{
  float range[2];
  this->TimeRange->GetRange(range);
  return static_cast<int>(range[0]);
}

//-----------------------------------------------------------------------------
int vtkPVAnimationInterface::GetGlobalEnd()
{
  float range[2];
  this->TimeRange->GetRange(range);
  return static_cast<int>(range[1]);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::PrepareForDelete()
{
  this->Stop();
  this->AnimationEntriesIterator->Delete();
  this->AnimationEntriesIterator = 0;
  this->AnimationEntries->Delete();
  this->AnimationEntries = 0;
}

//----------------------------------------------------------------------------
void vtkPVAnimationInterface::DeleteSource(vtkPVSource* src)
{
  vtkCollectionIterator* it = this->AnimationEntriesIterator;
  int cc = 0;
  for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem(), cc++ )
    {
    vtkPVAnimationInterfaceEntry* entry
      = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
    if ( entry->GetPVSource() == src )
      {
      this->DeleteSourceItem(cc);
      it->InitTraversal();
      cc = 0;
      }
    }
  if ( this->AnimationEntries->GetNumberOfItems() == 0 )
    {
    this->AddEmptySourceItem();
    }
}

//----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveState(ofstream* file)
{
  int numberFrames = this->NumberOfFramesEntry->GetValueAsInt();
  int frame = static_cast<int>(this->TimeScale->GetValue());

  int cc;
  for ( cc = 0; cc < this->AnimationEntries->GetNumberOfItems(); cc ++ )
    {
    vtkPVAnimationInterfaceEntry* entry = this->GetSourceEntry(cc);
    *file << "set kw(" << entry->GetTclName() << ") [$kw(" << this->GetTclName() 
          << ") AddEmptySourceItem]" << endl;
    entry->SaveState(file);
    }

  *file << "$kw(" << this->GetTclName() << ") SetNumberOfFrames " << numberFrames << endl;
  *file << "$kw(" << this->GetTclName() << ") SetCurrentTime " << frame << endl;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::ExecuteEvent(vtkObject *, unsigned long event, 
  void*)
{
  if ( event == vtkKWEvent::ErrorMessageEvent )
    {
    this->Stop();
    }
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "ControlledWidget: " << this->GetControlledWidget() << endl;
  os << indent << "NumberOfFrames: " << this->GetNumberOfFrames() << endl;
  os << indent << "Loop: " << this->GetLoop() << endl;
  os << indent << "View: " << this->GetView() << endl;
  os << indent << "Window: " << this->GetWindow() << endl;
  os << indent << "ScriptAvailable: " << this->ScriptAvailable << endl;
}





