File: undo.py

package info (click to toggle)
bcnc 0.9.14.318%2Bds-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,072 kB
  • sloc: python: 39,148; sh: 45; makefile: 44
file content (145 lines) | stat: -rw-r--r-- 4,941 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#
# Copyright and User License
# ~~~~~~~~~~~~~~~~~~~~~~~~~~
# Copyright Vasilis.Vlachoudis@cern.ch for the
# European Organization for Nuclear Research (CERN)
#
# DISCLAIMER
# ~~~~~~~~~~
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY, OF
# SATISFACTORY QUALITY, AND FITNESS FOR A PARTICULAR PURPOSE
# OR USE ARE DISCLAIMED. THE COPYRIGHT HOLDERS AND THE
# AUTHORS MAKE NO REPRESENTATION THAT THE SOFTWARE AND
# MODIFICATIONS THEREOF, WILL NOT INFRINGE ANY PATENT,
# COPYRIGHT, TRADE SECRET OR OTHER PROPRIETARY RIGHT.
#
# LIMITATION OF LIABILITY
# ~~~~~~~~~~~~~~~~~~~~~~~
# THE COPYRIGHT HOLDERS AND THE AUTHORS SHALL HAVE NO
# LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
# CONSEQUENTIAL, EXEMPLARY, OR PUNITIVE DAMAGES OF ANY
# CHARACTER INCLUDING, WITHOUT LIMITATION, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA OR PROFITS,
# OR BUSINESS INTERRUPTION, HOWEVER CAUSED AND ON ANY THEORY
# OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCT
# LIABILITY OR OTHERWISE, ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
#
# Author:	Vasilis.Vlachoudis@cern.ch


#===============================================================================
# Undo Redo Class
#===============================================================================
class UndoRedo:
	#-----------------------------------------------------------------------
	def __init__(self):
		self.undoList = []
		self.redoList = []

	#-----------------------------------------------------------------------
	def reset(self):
		del self.undoList[:]
		del self.redoList[:]

	#-----------------------------------------------------------------------
	# Add undoinfo as (msg, func/list, args)
	#-----------------------------------------------------------------------
	def add(self, undoinfo, msg=None):
		if not undoinfo: return
		if msg is not None:
			if isinstance(undoinfo[0], str):
				# replace message
				undoinfo = (msg,) + undoinfo[1:]
			elif isinstance(undoinfo,tuple):
				undoinfo = (msg,) + undoinfo
			else:
				undoinfo = (msg,undoinfo)
			f = 1
		else:
			f = int(isinstance(undoinfo[0], str))
		assert isinstance(undoinfo,list) or callable(undoinfo[f]) or isinstance(undoinfo[f],list)
		self.undoList.append(undoinfo)
		del self.redoList[:]

	#-----------------------------------------------------------------------
	# Split the undoinfo into [msg, ]func/list [, args]
	# msg can exists or not check for str/unicode
	# func can be a list or an executable
	# if func is a list then there are no args
	# @return always a tuple of 3 with msg, func, args
	#-----------------------------------------------------------------------
	@staticmethod
	def _split(undoinfo):
		if isinstance(undoinfo, list):
			return None, undoinfo, None
		elif undoinfo[0] is None or isinstance(undoinfo[0], str):
			assert callable(undoinfo[1]) or isinstance(undoinfo[1],list)
			return undoinfo[0], undoinfo[1], undoinfo[2:]
		else:
			assert callable(undoinfo[0]) or isinstance(undoinfo[0],list)
			return None, undoinfo[0], undoinfo[1:]

	#-----------------------------------------------------------------------
	# Execute the undoinfo and return the redoinfo
	#-----------------------------------------------------------------------
	def _execute(self, undoinfo):
		if undoinfo is None: return None
		msg, func, args = UndoRedo._split(undoinfo)
		if isinstance(func, list):
			redolist = []
			while func:
				redolist.append(self._execute(func.pop()))
			if msg:
				return msg, redolist
			else:
				return redolist
		else:
#			print "<<< Undo:", undoinfo
			redoinfo = func(*args)
#			print ">>> Redo:", redoinfo
			if isinstance(redoinfo[0],str):
				return redoinfo
			elif msg:
				return (msg,) + redoinfo
			else:
				return redoinfo

	#-----------------------------------------------------------------------
	def undo(self):
		if not self.undoList: return
		self.redoList.append(self._execute(self.undoList.pop()))

	#-----------------------------------------------------------------------
	def redo(self):
		if not self.redoList: return
		self.undoList.append(self._execute(self.redoList.pop()))

	#-----------------------------------------------------------------------
	def canUndo(self):
		return bool(self.undoList)

	#-----------------------------------------------------------------------
	def canRedo(self):
		return bool(self.redoList)

	#-----------------------------------------------------------------------
	def undoText(self):
		u = self.undoList[-1]
		if isinstance(u[0], str):
			return u[0]
		else:
			return "undo"

	#-----------------------------------------------------------------------
	def undoTextList(self):
		lst = []
		for u in self.undoList:
			if isinstance(u[0], str):
				lst.append(u[0])
			else:
				lst.append("undo")
		lst.reverse()
		return lst