# vPresent is an immersive presentation creation and display application.
# Copyright (C) 2007-2008 by Infiscape Corporation
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

from PyQt4 import QtCore, QtGui

import editdialogui
import spherebackground
import opendocument

class UndoStackHelper(QtCore.QObject):
   """
   Helper class that allows us to capture all undo/redo commands as they are
   added to a QUndoStack. We can then later create a macro that contains all
   of these commands.
   """
   def __init__(self, undoStack):
      self.undoStack = undoStack
      self.commandList = []

   def push(self, cmd):
      self.commandList = self.commandList[:self.undoStack.index()]
      self.commandList.append(cmd)
      assert cmd is not None
      self.undoStack.push(cmd)

   def index(self):
      return self.undoStack.index()

   def setIndex(self, idx):
      self.undoStack.setIndex(idx)

   def createMacro(self, otherUndoStack, macroName):
      # Trim tailing commands.
      self.commandList = self.commandList[:self.undoStack.index()]

      if 0 == len(self.commandList):
         return

      # XXX: Pushing these changes onto the stack causes redo() to be
      #      called a second time.
      otherUndoStack.beginMacro(macroName)
      for cmd in self.commandList:
         assert cmd is not None
         clone = cmd.clone()
         assert clone is not None
         otherUndoStack.push(clone)
      otherUndoStack.endMacro()


class EditDialog(QtGui.QDialog, editdialogui.Ui_EditDialogBase):
   def __init__(self, curDocument, pageStyle, parent=None):
      QtGui.QDialog.__init__(self, parent)

      self.curDocument = curDocument
      self.mPageStyle = pageStyle
      # NOTE: We do not need an undo group because this dialog box will have
      # only one undo stack.
      self.undoStack = QtGui.QUndoStack(self)
      self.undoStackHelper = UndoStackHelper(self.undoStack)
      #self.connect(self.undoStack, QtCore.SIGNAL("cleanChanged(bool)"),
      #             self.cleanStateChanged)

      self.setupUi(self)

      self.undoAction = self.undoStack.createUndoAction(self)
      self.undoAction.setIcon(QtGui.QIcon(":/vpresent/gui/images/undo32.png"))
      self.undoAction.setShortcut(self.tr("Ctrl+Z"))

      self.redoAction = self.undoStack.createRedoAction(self)
      self.redoAction.setIcon(QtGui.QIcon(":/vpresent/gui/images/redo32.png"))
      self.redoAction.setShortcut(self.tr("Ctrl+Shift+Z"))

      self.addAction(self.undoAction)
      self.addAction(self.redoAction)



   def setupUi(self, widget):
      editdialogui.Ui_EditDialogBase.setupUi(self, widget)

      self.mWidget = self.mPlaceholder

      # Get the background from the page style.
      sphere_background = self.mPageStyle.find('./vpresent:page3d-properties/vpresent:sphere-background')

      # Select the correct combox item and show the correct UI.
      if sphere_background.vpresent_type == 'mercator':
         new_widget = spherebackground.SphereBackground(self.curDocument,
            self.undoStackHelper, sphere_background, True, self)
      else:
         new_widget = spherebackground.SphereBackground(self.curDocument,
            self.undoStackHelper, sphere_background, False, self)

      # If the widget changed update our layout.
      if self.mWidget != new_widget:
         assert self.mWidget is not None
         self.vboxlayout.removeWidget(self.mWidget)
         self.mWidget.setParent(None)
         self.mWidget = new_widget
         self.vboxlayout.insertWidget(self.vboxlayout.count()-1, self.mWidget)

   def done(self, result):
      """ Closes the dialog and sets its result code to result. """
      QtGui.QDialog.done(self, result)

PAGE_STYLE_CREATE = 0

class InsertPageStyle(QtGui.QUndoCommand):
   def __init__(self, document, styleName, styleDisplayName, changeCallback, parent=None):
      QtGui.QUndoCommand.__init__(self, "Add Page Style", parent)
      self.mDocument = document
      self.mChangeCb = changeCallback
      self.mMerged = None

      self.mPageStyle = opendocument.createNode('style:style', style_name=styleName,
                                                style_family='page3d',
                                                style_display_name=styleDisplayName)
      self.mPage3dProps = opendocument.createNode('vpresent:page3d-properties')

      self.mBackground = opendocument.createNode('vpresent:sphere-background', vpresent_type='cubic')
      sphere = opendocument.createNode('dr3d:sphere', dr3d_size=100.0)
      self.mBackground.addChild(sphere)

   def id(self):
      return PAGE_STYLE_CREATE

   def mergeWith(self, command):
      '''
      Determines if the given command can be merged with this command. This
      is allows if the command is a AssignPageStyle instance. In that case, we
      treat the two-step process of creating a page style and assigning it to
      the current page a single command.
      '''
      result = False

      if command.id() == self.id():
         # We only merge the given command if we do not already have a merged
         # command.
         if self.mMerged is None and command.__class__ == AssignPageStyle:
            self.mMerged = command
            result = True

      return result

   def redo(self):
      auto_styles_node = self.mDocument.content.find('./office:automatic-styles')
      auto_styles_node.addChild(self.mPageStyle)
      self.mPageStyle.addChild(self.mPage3dProps)
      self.mPage3dProps.addChild(self.mBackground)

      self.mDocument.addStyle(self.mPageStyle)
      self.mChangeCb()

      if self.mMerged is not None:
         self.mMerged.redo()

   def undo(self):
      if self.mMerged is not None:
         self.mMerged.undo()

      auto_styles_node = self.mDocument.content.find('./office:automatic-styles')
      auto_styles_node.subChild(self.mPageStyle)
      self.mPageStyle.subChild(self.mPage3dProps)
      self.mPage3dProps.subChild(self.mBackground)

      self.mDocument.removeStyle(self.mPageStyle)
      self.mChangeCb()

class ChangeBackgroundType(QtGui.QUndoCommand):
   def __init__(self, background, backgroundType, changeCallback, parent=None):
      title = "Change background type '%s'" % backgroundType
      QtGui.QUndoCommand.__init__(self, title, parent)
      self.mBackground = background
      self.mBackgroundType = backgroundType
      self.mChangeCallback = changeCallback

      self.mOldBackgroundType = background.vpresent_type

   def id(self):
      return PAGE_STYLE_CREATE

   def redo(self):
      self.mBackground.vpresent_type = self.mBackgroundType
      self.mChangeCallback()

   def undo(self):
      self.mBackground.vpresent_type = self.mOldBackgroundType
      self.mChangeCallback()

import vpresent_rc


if __name__ == "__main__":
   import sys
   app = QtGui.QApplication(sys.argv)
   dialog = EditDialog()
   dialog.show()
   sys.exit(app.exec_())
