diff options
author | Guido van Rossum <guido@python.org> | 1999-05-03 15:49:52 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1999-05-03 15:49:52 (GMT) |
commit | 318a70d976fbf225de3485bbbc61b7fe1f24f4a2 (patch) | |
tree | 358d6940133c029256a0b4d94bde7ed61fba03e4 /Tools/idle/UndoDelegator.py | |
parent | 2d6a568a0f6c65c76797556bf949b97ede9049e1 (diff) | |
download | cpython-318a70d976fbf225de3485bbbc61b7fe1f24f4a2.zip cpython-318a70d976fbf225de3485bbbc61b7fe1f24f4a2.tar.gz cpython-318a70d976fbf225de3485bbbc61b7fe1f24f4a2.tar.bz2 |
Tim Peters writes:
I'm still unsure, but couldn't stand the virtual event trickery so tried a
different sin (adding undo_block_start/stop methods to the Text instance in
EditorWindow.py). Like it or not, it's efficient and works <wink>. Better
idea?
Give the attached a whirl. Even if you hate the implementation, I think
you'll like the results. Think I caught all the "block edit" cmds,
including Format Paragraph, plus subtler ones involving smart indents and
backspacing.
Diffstat (limited to 'Tools/idle/UndoDelegator.py')
-rw-r--r-- | Tools/idle/UndoDelegator.py | 75 |
1 files changed, 73 insertions, 2 deletions
diff --git a/Tools/idle/UndoDelegator.py b/Tools/idle/UndoDelegator.py index 39c8e63..ec7af81 100644 --- a/Tools/idle/UndoDelegator.py +++ b/Tools/idle/UndoDelegator.py @@ -49,6 +49,7 @@ class UndoDelegator(Delegator): self.was_saved = -1 self.pointer = 0 self.undolist = [] + self.undoblock = 0 # or a CommandSequence instance self.set_saved(1) def set_saved(self, flag): @@ -82,8 +83,40 @@ class UndoDelegator(Delegator): def delete(self, index1, index2=None): self.addcmd(DeleteCommand(index1, index2)) - def addcmd(self, cmd): - cmd.do(self.delegate) + # Clients should call undo_block_start() and undo_block_stop() + # around a sequence of editing cmds to be treated as a unit by + # undo & redo. Nested matching calls are OK, and the inner calls + # then act like nops. OK too if no editing cmds, or only one + # editing cmd, is issued in between: if no cmds, the whole + # sequence has no effect; and if only one cmd, that cmd is entered + # directly into the undo list, as if undo_block_xxx hadn't been + # called. The intent of all that is to make this scheme easy + # to use: all the client has to worry about is making sure each + # _start() call is matched by a _stop() call. + + def undo_block_start(self): + if self.undoblock == 0: + self.undoblock = CommandSequence() + self.undoblock.bump_depth() + + def undo_block_stop(self): + if self.undoblock.bump_depth(-1) == 0: + cmd = self.undoblock + self.undoblock = 0 + if len(cmd) > 0: + if len(cmd) == 1: + # no need to wrap a single cmd + cmd = cmd.getcmd(0) + # this blk of cmds, or single cmd, has already + # been done, so don't execute it again + self.addcmd(cmd, 0) + + def addcmd(self, cmd, execute=1): + if execute: + cmd.do(self.delegate) + if self.undoblock != 0: + self.undoblock.append(cmd) + return if self.can_merge and self.pointer > 0: lastcmd = self.undolist[self.pointer-1] if lastcmd.merge(cmd): @@ -264,6 +297,44 @@ class DeleteCommand(Command): text.see('insert') ##sys.__stderr__.write("undo: %s\n" % self) +class CommandSequence(Command): + + # Wrapper for a sequence of undoable cmds to be undone/redone + # as a unit + + def __init__(self): + self.cmds = [] + self.depth = 0 + + def __repr__(self): + s = self.__class__.__name__ + strs = [] + for cmd in self.cmds: + strs.append(" " + `cmd`) + return s + "(\n" + string.join(strs, ",\n") + "\n)" + + def __len__(self): + return len(self.cmds) + + def append(self, cmd): + self.cmds.append(cmd) + + def getcmd(self, i): + return self.cmds[i] + + def redo(self, text): + for cmd in self.cmds: + cmd.redo(text) + + def undo(self, text): + cmds = self.cmds[:] + cmds.reverse() + for cmd in cmds: + cmd.undo(text) + + def bump_depth(self, incr=1): + self.depth = self.depth + incr + return self.depth def main(): from Percolator import Percolator |