# -*- coding: latin-1; -*-
#
# PgWorksheet - PostgreSQL Front End
# http://pgworksheet.projects.postgresql.org/
#
# Copyright © 2004-2008 Henri Michelon & CML http://www.e-cml.org/
#
# 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 (read LICENSE.txt).
#
# 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# $Id: Undo.py,v 1.4 2008/03/12 20:26:23 hmichelon Exp $
#

# maxium size of the undo stack
UNDO_MAX = 1000


class UndoAction:
  """A user action : insert or delete"""

  def __init__(self, buffer, type, start, end, value):
    self.buffer = buffer
    self.type = type
    self.start = start
    self.end = end
    self.value = value
    

class Undo:
  """Records user actions and apply or revert them"""

  def __init__(self):
    self.undo_stack = []
    self.redo_stack = []
    # locking is used to avoid recording
    # our own undo/redo actions
    self.lock = False


  def reset(self):
    """empty the stacks to restart the undo action"""
    self.undo_stack = []
    self.redo_stack = []


  def text_inserted(self, buffer, iter, text, length):
    """Called by Gtk when text is inserted in a buffer"""
    if (not self.lock):
      if (len(self.undo_stack) >= UNDO_MAX):
        self.undo_stack.pop(0)
      self.undo_stack.append(UndoAction(buffer, "insert",
                                iter.get_offset(), iter.get_offset() + length,
                                text))


  def text_deleted(self, buffer, start, end):
    """Called by Gtk when text is deleted from a buffer"""
    if (not self.lock):
      if (len(self.undo_stack) >= UNDO_MAX):
        self.undo_stack.pop(0)
      self.undo_stack.append(UndoAction(buffer, "delete",
                                start.get_offset(), end.get_offset(),
                                buffer.get_text(start, end)))

      
  def undo(self):
    """Revert the last action"""
    if (len(self.undo_stack) == 0):
      return
    self.lock = True
    action = self.undo_stack.pop()
    if (action.type == "insert"):
      action.buffer.delete(action.buffer.get_iter_at_offset(action.start),
                           action.buffer.get_iter_at_offset(action.end))
    elif (action.type == "delete"):
      action.buffer.insert(action.buffer.get_iter_at_offset(action.start),
                           action.value)
    self.redo_stack.append(action)
    self.lock = False


  def redo(self):
    """Apply the last reverted action"""
    if (len(self.redo_stack) == 0):
      return
    self.lock = True
    action = self.redo_stack.pop()
    if (action.type == "insert"):
      action.buffer.insert(action.buffer.get_iter_at_offset(action.start),
                           action.value)
    elif (action.type == "delete"):
      action.buffer.delete(action.buffer.get_iter_at_offset(action.start),
                           action.buffer.get_iter_at_offset(action.end))
    self.undo_stack.append(action)
    self.lock = False
