Skip to content

Commit

Permalink
Fix #1159. Relax undo check to ignore changes outside display item (c…
Browse files Browse the repository at this point in the history
…omputations) after adding graphics.
  • Loading branch information
cmeyer committed Oct 19, 2024
1 parent b8ef844 commit 9c43597
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 24 deletions.
29 changes: 5 additions & 24 deletions nion/swift/DisplayPanel.py
Original file line number Diff line number Diff line change
Expand Up @@ -1161,10 +1161,6 @@ def __init__(self, document_controller: DocumentController.DocumentController,
self.__document_controller = document_controller
self.__display_item_proxy = display_item.create_proxy()
self.__graphics = graphics # only used for perform
workspace_controller = self.__document_controller.workspace_controller
assert workspace_controller
self.__old_workspace_layout: typing.Optional[Persistence.PersistentDictType] = workspace_controller.deconstruct()
self.__new_workspace_layout: typing.Optional[Persistence.PersistentDictType] = None
self.__graphics_properties = None
self.__graphic_proxies = [graphic.create_proxy() for graphic in existing_graphics or list()]
self.__undelete_logs: typing.List[Changes.UndeleteLog] = list()
Expand All @@ -1173,8 +1169,6 @@ def __init__(self, document_controller: DocumentController.DocumentController,
def close(self) -> None:
self.__graphics_properties = None
self.__document_controller = typing.cast(typing.Any, None)
self.__old_workspace_layout = None
self.__new_workspace_layout = None
for undelete_log in self.__undelete_logs:
undelete_log.close()
self.__undelete_logs = typing.cast(typing.Any, None)
Expand All @@ -1198,39 +1192,26 @@ def perform(self) -> None:
def _get_modified_state(self) -> typing.Any:
display_item = self.__display_item_proxy.item
display_item_modified_state = display_item.modified_state if display_item else None
workspace_controller = self.__document_controller.workspace_controller
document_model_modified_state = workspace_controller.document_model.modified_state if workspace_controller else None
return display_item_modified_state, document_model_modified_state
return display_item_modified_state

def _set_modified_state(self, modified_state: typing.Any) -> None:
display_item = self.__display_item_proxy.item
if display_item:
display_item.modified_state = modified_state[0]
workspace_controller = self.__document_controller.workspace_controller
if workspace_controller:
workspace_controller.document_model.modified_state = modified_state[1]
display_item.modified_state = modified_state

def _redo(self) -> None:
for undelete_log in reversed(self.__undelete_logs):
self.__document_controller.document_model.undelete_all(undelete_log)
undelete_log.close()
self.__undelete_logs.clear()
workspace_controller = self.__document_controller.workspace_controller
if workspace_controller and self.__new_workspace_layout is not None:
workspace_controller.reconstruct(self.__new_workspace_layout)

def _undo(self) -> None:
display_item = self.__display_item_proxy.item
if display_item:
graphics = [graphic_proxy.item for graphic_proxy in self.__graphic_proxies]
workspace_controller = self.__document_controller.workspace_controller
if workspace_controller:
self.__new_workspace_layout = workspace_controller.deconstruct()
for graphic in graphics:
if graphic:
self.__undelete_logs.append(display_item.remove_graphic(graphic, safe=True))
if self.__old_workspace_layout is not None:
workspace_controller.reconstruct(self.__old_workspace_layout)
for graphic in graphics:
if graphic:
self.__undelete_logs.append(display_item.remove_graphic(graphic, safe=True))


class AppendDisplayDataChannelCommand(Undo.UndoableCommand):
Expand Down
38 changes: 38 additions & 0 deletions nion/swift/test/DisplayPanel_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3220,6 +3220,44 @@ def test_adding_fourier_filter_is_undoable_via_menu_items(self):
# undo
document_controller.perform_action("window.redo")
self.assertEqual(1, len(display_item.graphics))
# clean up by clearing out the periodic queue
document_controller.periodic()

def test_adding_fourier_filter_to_data_item_with_computation_is_undoable_via_menu_items(self):
with TestContext.create_memory_context() as test_context:
# set up the layout
document_controller = test_context.create_document_controller()
document_model = document_controller.document_model
# add data item
data_item = DataItem.DataItem(numpy.zeros((10, 10)))
document_model.append_data_item(data_item)
display_item = document_model.get_display_item_for_data_item(data_item)
# add computation
document_model.get_fft_new(display_item, display_item.data_item)
# put data item in display panel
display_panel = document_controller.selected_display_panel
display_panel.set_display_panel_display_item(display_item)
display_panel.root_container.layout_immediate(Geometry.IntSize(1000 + display_panel.header_canvas_item.header_height, 1000))
document_controller.periodic()
# focus click
display_panel.root_container.canvas_widget.simulate_mouse_click(500, 500, CanvasItem.KeyboardModifiers())
# recompute initial
document_controller.periodic()
document_controller.document_model.recompute_all()
# add fourier graphic
document_controller.perform_action("graphics.add_spot_graphic")
self.assertEqual(1, len(display_item.graphics))
# recompute after filter
document_controller.periodic()
document_controller.document_model.recompute_all()
# undo
document_controller.perform_action("window.undo")
self.assertEqual(0, len(display_item.graphics))
# undo
document_controller.perform_action("window.redo")
self.assertEqual(1, len(display_item.graphics))
# clean up by clearing out the periodic queue
document_controller.periodic()


if __name__ == '__main__':
Expand Down

0 comments on commit 9c43597

Please sign in to comment.