Skip to content

Commit 8201f31

Browse files
authored
Merge pull request #3187 from ferdnyc/pending
Add pending_action tracking to update manager
2 parents ddf89b9 + 1e0ecf3 commit 8201f31

File tree

1 file changed

+58
-30
lines changed

1 file changed

+58
-30
lines changed

src/classes/updates.py

+58-30
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,32 @@
2828
"""
2929

3030
from classes.logger import log
31-
from classes import info
3231
import copy
33-
import os
3432
import json
3533

34+
3635
class UpdateWatcher:
3736
""" Interface for classes that listen for 'undo' and 'redo' events. """
3837

3938
def updateStatusChanged(self, undo_status, redo_status):
40-
""" Easily be notified each time there are 'undo' or 'redo' actions available in the UpdateManager. """
39+
""" Easily be notified each time there are 'undo' or 'redo' actions
40+
available in the UpdateManager. """
4141
raise NotImplementedError("updateStatus() not implemented in UpdateWatcher implementer.")
4242

4343

4444
class UpdateInterface:
4545
""" Interface for classes that listen for changes (insert, update, and delete). """
4646

4747
def changed(self, action):
48-
""" This method is invoked each time the UpdateManager is changed. The action contains all the details of what changed,
48+
""" This method is invoked each time the UpdateManager is changed.
49+
The action contains all the details of what changed,
4950
including the type of change (insert, update, or delete). """
5051
raise NotImplementedError("changed() not implemented in UpdateInterface implementer.")
5152

5253

5354
class UpdateAction:
54-
"""A data structure representing a single update manager action, including any necessary data to reverse the action."""
55+
"""A data structure representing a single update manager action,
56+
including any necessary data to reverse the action."""
5557

5658
def __init__(self, type=None, key=[], values=None, partial_update=False):
5759
self.type = type # insert, update, or delete
@@ -121,22 +123,23 @@ def load_json(self, value):
121123

122124

123125
class UpdateManager:
124-
""" This class is used to track and distribute changes to listeners. Typically, only 1 instance of this class is needed,
125-
and many different listeners are connected with the add_listener() method. """
126+
""" This class is used to track and distribute changes to listeners.
127+
Typically, only 1 instance of this class is needed, and many different
128+
listeners are connected with the add_listener() method. """
126129

127130
def __init__(self):
128131
self.statusWatchers = [] # List of watchers
129132
self.updateListeners = [] # List of listeners
130133
self.actionHistory = [] # List of actions performed to current state
131134
self.redoHistory = [] # List of actions undone
132135
self.currentStatus = [None, None] # Status of Undo and Redo buttons (true/false for should be enabled)
133-
self.ignore_history = False # Ignore saving actions to history, to prevent a huge undo/redo list
134-
self.last_action = None
136+
self.ignore_history = False # Ignore saving actions to history, to prevent a huge undo/redo list
137+
self.last_action = None # The last action processed
138+
self.pending_action = None # Last action not added to actionHistory list
135139

136140
def load_history(self, project):
137141
"""Load history from project"""
138-
self.redoHistory.clear()
139-
self.actionHistory.clear()
142+
self.reset()
140143

141144
# Get history from project data
142145
history = project.get("history")
@@ -183,22 +186,24 @@ def save_history(self, project, history_length):
183186
log.info("Saving undo history, skipped key: %s" % str(action.key))
184187

185188
# Set history data in project
186-
self.ignore_history = True
187-
self.update(["history"], { "redo": redo_list, "undo": undo_list})
188-
self.ignore_history = False
189+
self.update_untracked(["history"], {"redo": redo_list, "undo": undo_list})
189190

190191
def reset(self):
191-
""" Reset the UpdateManager, and clear all UpdateActions and History. This does not clear listeners and watchers. """
192+
""" Reset the UpdateManager, and clear all UpdateActions and History.
193+
This does not clear listeners and watchers. """
192194
self.actionHistory.clear()
193195
self.redoHistory.clear()
196+
self.pending_action = None
197+
self.last_action = None
194198

195199
# Notify watchers of new history state
196200
self.update_watchers()
197201

198202
def add_listener(self, listener, index=-1):
199-
""" Add a new listener (which will invoke the changed(action) method each time an UpdateAction is available). """
203+
""" Add a new listener (which will invoke the changed(action) method
204+
each time an UpdateAction is available). """
200205

201-
if not listener in self.updateListeners:
206+
if listener not in self.updateListeners:
202207
if index <= -1:
203208
# Add listener to end of list
204209
self.updateListeners.append(listener)
@@ -209,9 +214,10 @@ def add_listener(self, listener, index=-1):
209214
log.warning("Cannot add existing listener: {}".format(str(listener)))
210215

211216
def add_watcher(self, watcher):
212-
""" Add a new watcher (which will invoke the updateStatusChanged() method each time a 'redo' or 'undo' action is available). """
217+
""" Add a new watcher (which will invoke the updateStatusChanged() method
218+
each time a 'redo' or 'undo' action is available). """
213219

214-
if not watcher in self.statusWatchers:
220+
if watcher not in self.statusWatchers:
215221
self.statusWatchers.append(watcher)
216222
else:
217223
log.warning("Cannot add existing watcher: {}".format(str(watcher)))
@@ -262,6 +268,7 @@ def undo(self):
262268
last_action = copy.deepcopy(self.actionHistory.pop())
263269

264270
self.redoHistory.append(last_action)
271+
self.pending_action = None
265272
# Get reverse of last action and perform it
266273
reverse_action = self.get_reverse_action(last_action)
267274
self.dispatch_action(reverse_action)
@@ -278,6 +285,7 @@ def redo(self):
278285
next_action.key = next_action.key[:-1]
279286

280287
self.actionHistory.append(next_action)
288+
self.pending_action = None
281289
# Perform next redo action
282290
self.dispatch_action(next_action)
283291

@@ -297,55 +305,75 @@ def dispatch_action(self, action):
297305

298306
# Perform load action (loading all project data), clearing history for taking a new path
299307
def load(self, values):
300-
""" Load all project data via an UpdateAction into the UpdateManager (this action will then be distributed to all listeners) """
308+
""" Load all project data via an UpdateAction into the UpdateManager
309+
(this action will then be distributed to all listeners) """
301310

302311
self.last_action = UpdateAction('load', '', values)
303312
self.redoHistory.clear()
304313
self.actionHistory.clear()
314+
self.pending_action = None
305315
self.dispatch_action(self.last_action)
306316

307317
# Perform new actions, clearing redo history for taking a new path
308318
def insert(self, key, values):
309-
""" Insert a new UpdateAction into the UpdateManager (this action will then be distributed to all listeners) """
319+
""" Insert a new UpdateAction into the UpdateManager
320+
(this action will then be distributed to all listeners) """
310321

311322
self.last_action = UpdateAction('insert', key, values)
312-
if not self.ignore_history:
323+
if self.ignore_history:
324+
self.pending_action = self.last_action
325+
else:
313326
self.redoHistory.clear()
327+
self.pending_action = None
314328
self.actionHistory.append(self.last_action)
315329
self.dispatch_action(self.last_action)
316330

317331
def update(self, key, values, partial_update=False):
318-
""" Update the UpdateManager with an UpdateAction (this action will then be distributed to all listeners) """
332+
""" Update the UpdateManager with an UpdateAction
333+
(this action will then be distributed to all listeners) """
319334

320335
self.last_action = UpdateAction('update', key, values, partial_update)
321-
if not self.ignore_history:
336+
if self.ignore_history:
337+
self.pending_action = self.last_action
338+
else:
322339
if self.last_action.key and self.last_action.key[0] != "history":
323340
# Clear redo history for any update except a "history" update
324341
self.redoHistory.clear()
342+
self.pending_action = None
325343
self.actionHistory.append(self.last_action)
326344
self.dispatch_action(self.last_action)
327345

328346
def update_untracked(self, key, values, partial_update=False):
329-
""" Update the UpdateManager with an UpdateAction, without creating a new entry in the history table (this action will then be distributed to all listeners) """
347+
""" Update the UpdateManager with an UpdateAction, without creating
348+
a new entry in the history table
349+
(this action will then be distributed to all listeners) """
330350
previous_ignore = self.ignore_history
351+
previous_pending = self.pending_action
331352
self.ignore_history = True
332353
self.update(key, values, partial_update)
333354
self.ignore_history = previous_ignore
355+
self.pending_action = previous_pending
334356

335357
def delete(self, key):
336-
""" Delete an item from the UpdateManager with an UpdateAction (this action will then be distributed to all listeners) """
358+
""" Delete an item from the UpdateManager with an UpdateAction
359+
(this action will then be distributed to all listeners) """
337360

338361
self.last_action = UpdateAction('delete', key)
339-
if not self.ignore_history:
362+
if self.ignore_history:
363+
self.pending_action = self.last_action
364+
else:
340365
self.redoHistory.clear()
366+
self.pending_action = None
341367
self.actionHistory.append(self.last_action)
342368
self.dispatch_action(self.last_action)
343369

344370
def apply_last_action_to_history(self, previous_value):
345371
""" Apply the last action to the history """
346-
if self.last_action:
347-
self.last_action.set_old_values(previous_value)
348-
self.actionHistory.append(self.last_action)
372+
if self.pending_action:
373+
self.pending_action.set_old_values(previous_value)
374+
self.actionHistory.append(self.pending_action)
375+
self.last_action = self.pending_action
376+
self.pending_action = None
349377

350378
# Notify watchers of new history state
351379
self.update_watchers()

0 commit comments

Comments
 (0)