Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | import Pmw |
2 | ||
3 | _ORIGINAL = 0 | |
4 | _MODIFIED = 1 | |
5 | _DISPLAY = 2 | |
6 | ||
7 | class HistoryText(Pmw.ScrolledText): | |
8 | ||
9 | def __init__(self, parent = None, **kw): | |
10 | ||
11 | # Define the megawidget options. | |
12 | optiondefs = ( | |
13 | ('compressany', 1, None), | |
14 | ('compresstail', 1, None), | |
15 | ('historycommand', None, None), | |
16 | ) | |
17 | self.defineoptions(kw, optiondefs) | |
18 | ||
19 | # Initialise the base class (after defining the options). | |
20 | Pmw.ScrolledText.__init__(self, parent) | |
21 | ||
22 | # Initialise instance variables. | |
23 | self._list = [] | |
24 | self._currIndex = 0 | |
25 | self._pastIndex = None | |
26 | self._lastIndex = 0 # pointer to end of history list | |
27 | ||
28 | # Check keywords and initialise options. | |
29 | self.initialiseoptions() | |
30 | ||
31 | def addhistory(self): | |
32 | text = self.get() | |
33 | if text[-1] == '\n': | |
34 | text = text[:-1] | |
35 | ||
36 | if len(self._list) == 0: | |
37 | # This is the first history entry. Add it. | |
38 | self._list.append([text, text, _MODIFIED]) | |
39 | return | |
40 | ||
41 | currentEntry = self._list[self._currIndex] | |
42 | if text == currentEntry[_ORIGINAL]: | |
43 | # The current history entry has not been modified. Check if | |
44 | # we need to add it again. | |
45 | ||
46 | if self['compresstail'] and self._currIndex == self._lastIndex: | |
47 | return | |
48 | ||
49 | if self['compressany']: | |
50 | return | |
51 | ||
52 | # Undo any changes for the current history entry, since they | |
53 | # will now be available in the new entry. | |
54 | currentEntry[_MODIFIED] = currentEntry[_ORIGINAL] | |
55 | ||
56 | historycommand = self['historycommand'] | |
57 | if self._currIndex == self._lastIndex: | |
58 | # The last history entry is currently being displayed, | |
59 | # so disable the special meaning of the 'Next' button. | |
60 | self._pastIndex = None | |
61 | nextState = 'disabled' | |
62 | else: | |
63 | # A previous history entry is currently being displayed, | |
64 | # so allow the 'Next' button to go to the entry after this one. | |
65 | self._pastIndex = self._currIndex | |
66 | nextState = 'normal' | |
67 | if callable(historycommand): | |
68 | historycommand('normal', nextState) | |
69 | ||
70 | # Create the new history entry. | |
71 | self._list.append([text, text, _MODIFIED]) | |
72 | ||
73 | # Move the pointer into the history entry list to the end. | |
74 | self._lastIndex = self._lastIndex + 1 | |
75 | self._currIndex = self._lastIndex | |
76 | ||
77 | def next(self): | |
78 | if self._currIndex == self._lastIndex and self._pastIndex is None: | |
79 | self.bell() | |
80 | else: | |
81 | self._modifyDisplay('next') | |
82 | ||
83 | def prev(self): | |
84 | self._pastIndex = None | |
85 | if self._currIndex == 0: | |
86 | self.bell() | |
87 | else: | |
88 | self._modifyDisplay('prev') | |
89 | ||
90 | def undo(self): | |
91 | if len(self._list) != 0: | |
92 | self._modifyDisplay('undo') | |
93 | ||
94 | def redo(self): | |
95 | if len(self._list) != 0: | |
96 | self._modifyDisplay('redo') | |
97 | ||
98 | def gethistory(self): | |
99 | return self._list | |
100 | ||
101 | def _modifyDisplay(self, command): | |
102 | # Modify the display to show either the next or previous | |
103 | # history entry (next, prev) or the original or modified | |
104 | # version of the current history entry (undo, redo). | |
105 | ||
106 | # Save the currently displayed text. | |
107 | currentText = self.get() | |
108 | if currentText[-1] == '\n': | |
109 | currentText = currentText[:-1] | |
110 | ||
111 | currentEntry = self._list[self._currIndex] | |
112 | if currentEntry[_DISPLAY] == _MODIFIED: | |
113 | currentEntry[_MODIFIED] = currentText | |
114 | elif currentEntry[_ORIGINAL] != currentText: | |
115 | currentEntry[_MODIFIED] = currentText | |
116 | if command in ('next', 'prev'): | |
117 | currentEntry[_DISPLAY] = _MODIFIED | |
118 | ||
119 | if command in ('next', 'prev'): | |
120 | prevstate = 'normal' | |
121 | nextstate = 'normal' | |
122 | if command == 'next': | |
123 | if self._pastIndex is not None: | |
124 | self._currIndex = self._pastIndex | |
125 | self._pastIndex = None | |
126 | self._currIndex = self._currIndex + 1 | |
127 | if self._currIndex == self._lastIndex: | |
128 | nextstate = 'disabled' | |
129 | elif command == 'prev': | |
130 | self._currIndex = self._currIndex - 1 | |
131 | if self._currIndex == 0: | |
132 | prevstate = 'disabled' | |
133 | historycommand = self['historycommand'] | |
134 | if callable(historycommand): | |
135 | historycommand(prevstate, nextstate) | |
136 | currentEntry = self._list[self._currIndex] | |
137 | else: | |
138 | if command == 'undo': | |
139 | currentEntry[_DISPLAY] = _ORIGINAL | |
140 | elif command == 'redo': | |
141 | currentEntry[_DISPLAY] = _MODIFIED | |
142 | ||
143 | # Display the new text. | |
144 | self.delete('1.0', 'end') | |
145 | self.insert('end', currentEntry[currentEntry[_DISPLAY]]) |