def run(): eventbus = EventBus() canvas_model = CanvasModel(eventbus) canvas_model.elems = [Ellipse(20, 30, 40, 50), Rectangle(30, 40, 10, 20)] eventbus.register(Undo_Requested, lambda _: canvas_model.undo()) eventbus.register(Redo_Requested, lambda _: canvas_model.redo()) cvs_view_1, cvs_states_1, cvs_trans_1 = widgets.canvas.make(eventbus, canvas_model) cvs_view_2, cvs_states_2, cvs_trans_2 = widgets.canvas.make(eventbus, canvas_model) app_states = { 'top': { 'canvas_displayed': State([ (cvs_states_1, cvs_trans_1), (cvs_states_2, cvs_trans_2), #(toolbar_states, toolbar_trans), ]), } } app_trans = { 'top': { Initial: T('canvas_displayed'), } } hsm = HSM(app_states, app_trans) hsm.start(eventbus) app_frame = AppFrame(eventbus) canvases = JPanel() canvases.layout = BoxLayout(canvases, BoxLayout.PAGE_AXIS) canvases.add(cvs_view_1) canvases.add(cvs_view_2) app_frame.add(canvases, BorderLayout.CENTER) cvs_view_2.background = Color.GRAY app_frame.size = (1100, 1000)
class Test_commit(object): def setup_class(self): self.elems = [ R(1, 1, 10, 10), R(2, 2, 20, 20), R(3, 3, 30, 30), ] self.changelog = [ ['some', 'old'], ['changes', 'here'], ] self.counter = 0 self.received_events = [] def on_change(event): self.counter += 1 self.received_events += [event] self.eb = EventBus() self.eb.register(Model_Changed, on_change) # insert def test_insert(self): cl = [ Insert(R(10, 5, -5, 5)), # fix Insert(R(4, 4, 4, 4)), ] _commit(cl, self.changelog, self.eb, self.elems) assert self.elems == [ R(1, 1, 10, 10), R(2, 2, 20, 20), R(3, 3, 30, 30), R(5, 5, 5, 5), R(4, 4, 4, 4), ] def test_received_event_after_insert(self): assert self.counter == 1 assert len(self.received_events) == 1 assert isinstance(self.received_events[0], Model_Changed) def test_event_data_contains_insert_changes(self): assert self.received_events[0].data == [ Insert(R(5, 5, 5, 5)), Insert(R(4, 4, 4, 4)), ] def test_changes_appended_to_changelog_after_insert(self): assert self.changelog == [ ['some', 'old'], ['changes', 'here'], self.received_events[0].data, ] # modify def test_modify(self): cl = [ Modify(R(1, 1, 10, 10), R(100, 1100, 1000, -1000)), # fix Modify(R(5, 5, 5, 5), R(55, 5, 5, 5)), ] _commit(cl, self.changelog, self.eb, self.elems) assert self.elems == [ R(100, 100, 1000, 1000), R(2, 2, 20, 20), R(3, 3, 30, 30), R(55, 5, 5, 5), R(4, 4, 4, 4), ] def test_received_event_after_modify(self): assert self.counter == 2 assert len(self.received_events) == 2 assert isinstance(self.received_events[1], Model_Changed) def test_event_data_contains_modify_changes(self): assert self.received_events[1].data == [ Modify(R(1, 1, 10, 10), R(100, 100, 1000, 1000)), Modify(R(5, 5, 5, 5), R(55, 5, 5, 5)), ] def test_changes_appended_to_changelog_after_modify(self): assert self.changelog == [ ['some', 'old'], ['changes', 'here'], self.received_events[0].data, self.received_events[1].data, ] # remove def test_remove(self): cl = [ Remove(R(3, 3, 30, 30)), Remove(R(2, 2, 20, 20)), ] _commit(cl, self.changelog, self.eb, self.elems) assert self.elems == [ R(100, 100, 1000, 1000), R(55, 5, 5, 5), R(4, 4, 4, 4), ] def test_received_event_after_remove(self): assert self.counter == 3 assert len(self.received_events) == 3 assert isinstance(self.received_events[2], Model_Changed) def test_event_data_contains_remove_changes(self): assert self.received_events[2].data == [ Remove(R(3, 3, 30, 30)), Remove(R(2, 2, 20, 20)), ] def test_changes_appended_to_changelog_after_remove(self): assert self.changelog == [ ['some', 'old'], ['changes', 'here'], self.received_events[0].data, self.received_events[1].data, self.received_events[2].data, ]
class Test_CanvasModel(object): def setup_class(self): self.initial_elements = [ R(1, 1, 10, 10), R(2, 2, 20, 20), R(3, 3, 30, 30), ] self.changelist = [ Insert(R(4, 4, 40, 40)) ] # used for commit later self.counter = 0 self.received_events = [] def on_change(event): self.counter += 1 self.received_events += [event] self.eb = EventBus() self.model = CanvasModel(self.eb) self.eb.register(Model_Changed, on_change) def test_setting_elems_updates_elems(self): to_give = self.initial_elements[:] # copy self.model.elems = to_give assert to_give == self.initial_elements # model didn't change given assert self.model.elems == self.initial_elements assert self.model._elems == self.initial_elements def test_setting_elems_updates_changelog(self): assert self.model._changelog == [ [ Insert(R(1, 1, 10, 10)), Insert(R(2, 2, 20, 20)), Insert(R(3, 3, 30, 30)), ], ] def test_setting_elems_informs_listeners(self): assert self.counter == 1 assert len(self.received_events) == 1 assert self.received_events[0].data == self.model._changelog[0] def test_cant_modify_elems_through_getter(self): self.model.elems[1] = 'abc' self.model.elems.pop(0) assert self.model.elems == self.initial_elements def test_cant_inject_changes_to_changelog_through_event(self): evt = self.received_events[0] backup = evt.data[0] evt.data[0] == 'abc' assert self.model._changelog == [ [ Insert(R(1, 1, 10, 10)), Insert(R(2, 2, 20, 20)), Insert(R(3, 3, 30, 30)), ], ] evt.data[0] = backup def test_commit(self): self.model.commit(self.changelist) def test_commit_informs_listeners(self): assert self.counter == 2 assert len(self.received_events) == 2 assert self.received_events[1].data == [ Insert(R(4, 4, 40, 40)) ] def test_commit_updates_elems(self): assert self.model._elems == [ R(1, 1, 10, 10), R(2, 2, 20, 20), R(3, 3, 30, 30), R(4, 4, 40, 40), ] assert self.model.elems == self.model._elems def test_commit_updates_changelog(self): assert self.model._changelog == [ [ Insert(R(1, 1, 10, 10)), Insert(R(2, 2, 20, 20)), Insert(R(3, 3, 30, 30)), ], [ Insert(R(4, 4, 40, 40)), ] ] def test_modify_changes_in_changelog_through_commit_argument(self): self.changelist[0] = 'abc' assert self.model._changelog == [ [ Insert(R(1, 1, 10, 10)), Insert(R(2, 2, 20, 20)), Insert(R(3, 3, 30, 30)), ], [ Insert(R(4, 4, 40, 40)), ] ] self.changelist.pop(0) assert self.model._changelog == [ [ Insert(R(1, 1, 10, 10)), Insert(R(2, 2, 20, 20)), Insert(R(3, 3, 30, 30)), ], [ Insert(R(4, 4, 40, 40)), ] ] assert self.received_events[1].data == [ Insert(R(4, 4, 40, 40)) ]
class Test_undo: def setup_class(self): self.eb = EventBus() self.event_log = [] def append_to_event_log(e): self.event_log += [e] self.eb.register(Model_Changed, append_to_event_log) def test_undo_one_insert(self): change_log = [ [ 'previous' ], [ 'changes' ], # these remain untouched [ Insert(R(1, 1, 1, 1)) ], # undoes only last changelist ] model_elems = [ R(3, 3, 3, 3), R(1, 1, 1, 1), R(2, 2, 2, 2) ] redo_log = [ [ 'future' ], [ 'changes'] ] _undo(change_log, redo_log, self.eb, model_elems) assert change_log == [ [ 'previous' ], [ 'changes' ], ] assert redo_log == [ [ Insert(R(1, 1, 1, 1)) ], [ 'future' ], [ 'changes'], ] assert model_elems == [ R(3, 3, 3, 3), R(2, 2, 2, 2) ] assert len(self.event_log) == 1 assert self.event_log[-1].data == [ Remove(R(1, 1, 1, 1)) ] # inverted def test_undo_one_remove(self): change_log = [ [ 'previous' ], [ 'changes' ], [ Remove(R(1, 1, 1, 1)) ], ] model_elems = [ R(2, 2, 2, 2) ] redo_log = [ [ 'future' ], [ 'changes'] ] _undo(change_log, redo_log, self.eb, model_elems) assert change_log == [ [ 'previous' ], [ 'changes' ], ] assert redo_log == [ [ Remove(R(1, 1, 1, 1)) ], [ 'future' ], [ 'changes'], ] assert model_elems == [ R(2, 2, 2, 2), R(1, 1, 1, 1) ] assert len(self.event_log) == 2 assert self.event_log[-1].data == [ Insert(R(1, 1, 1, 1)) ] # inverted def test_undo_one_modify(self): change_log = [ [ 'previous' ], [ 'changes' ], [ Modify(R(3, 3, 3, 3), R(1, 1, 1, 1)) ], ] model_elems = [ R(1, 1, 1, 1), R(2, 2, 2, 2) ] redo_log = [ [ 'future' ], [ 'changes'] ] _undo(change_log, redo_log, self.eb, model_elems) assert change_log == [ [ 'previous' ], [ 'changes' ], ] assert redo_log == [ [ Modify(R(3, 3, 3, 3), R(1, 1, 1, 1)) ], [ 'future' ], [ 'changes'], ] assert model_elems == [ R(3, 3, 3, 3), R(2, 2, 2, 2) ] assert len(self.event_log) == 3 assert self.event_log[-1].data == [ Modify(R(1, 1, 1, 1), R(3, 3, 3, 3)) ] # inverted
class Test_redo: def setup_class(self): self.eb = EventBus() self.event_log = [] def append_to_event_log(e): self.event_log += [e] self.eb.register(Model_Changed, append_to_event_log) def test_redo_one_insert(self): change_log = [ [ 'previous' ], [ 'changes' ] ] model_elems = [ R(2, 2, 2, 2) ] redo_log = [ [ Insert(R(1, 1, 1, 1)) ], [ 'future' ], [ 'changes'] ] _redo(change_log, redo_log, self.eb, model_elems) assert change_log == [ [ 'previous' ], [ 'changes' ], [ Insert(R(1, 1, 1, 1)) ], ] assert redo_log == [ [ 'future' ], [ 'changes'] ] assert model_elems == [ R(2, 2, 2, 2), R(1, 1, 1, 1) ] assert len(self.event_log) == 1 assert self.event_log[-1].data == [ Insert(R(1, 1, 1, 1)) ] def test_redo_one_remove(self): change_log = [ [ 'previous' ], [ 'changes' ] ] model_elems = [ R(1, 1, 1, 1), R(2, 2, 2, 2) ] redo_log = [ [ Remove(R(1, 1, 1, 1)) ], [ 'future' ], [ 'changes'] ] _redo(change_log, redo_log, self.eb, model_elems) assert change_log == [ [ 'previous' ], [ 'changes' ], [ Remove(R(1, 1, 1, 1)) ], ] assert redo_log == [ [ 'future' ], [ 'changes'] ] assert model_elems == [ R(2, 2, 2, 2) ] assert len(self.event_log) == 2 assert self.event_log[-1].data == [ Remove(R(1, 1, 1, 1)) ] def test_redo_one_modify(self): change_log = [ [ 'previous' ], [ 'changes' ] ] model_elems = [ R(1, 1, 1, 1), R(2, 2, 2, 2) ] redo_log = [ [ Modify(R(1, 1, 1, 1), R(3, 3, 3, 3)) ], [ 'future' ], [ 'changes'] ] _redo(change_log, redo_log, self.eb, model_elems) assert change_log == [ [ 'previous' ], [ 'changes' ], [ Modify(R(1, 1, 1, 1), R(3, 3, 3, 3)) ], ] assert redo_log == [ [ 'future' ], [ 'changes'] ] assert model_elems == [ R(3, 3, 3, 3), R(2, 2, 2, 2) ] assert len(self.event_log) == 3 assert self.event_log[-1].data == [ Modify(R(1, 1, 1, 1), R(3, 3, 3, 3)) ] def test_model_one_undo_redo(self): model = CanvasModel(self.eb) model.commit([ Insert(R(1, 1, 1, 1)) ]) assert model._elems == [ R(1, 1, 1, 1) ] assert model._changelog == [ [ Insert(R(1, 1, 1, 1)) ] ] assert model._redolog == [] model.undo() assert model._elems == [] assert model._changelog == [] assert model._redolog == [ [ Insert(R(1, 1, 1, 1)) ] ] model.redo() assert model._elems == [ R(1, 1, 1, 1) ] assert model._changelog == [ [ Insert(R(1, 1, 1, 1)) ] ] assert model._redolog == [] def test_model_two_undo_redos(self): model = CanvasModel(self.eb) model.commit([ Insert(R(1, 1, 1, 1)) ]) model.commit([ Insert(R(2, 2, 2, 2)) ]) assert model._elems == [ R(1, 1, 1, 1), R(2, 2, 2, 2) ] assert model._changelog == [ [Insert(R(1, 1, 1, 1))], [Insert(R(2, 2, 2, 2))] ] assert model._redolog == [] model.undo() assert model._elems == [ R(1, 1, 1, 1) ] assert model._changelog == [ [ Insert(R(1, 1, 1, 1)) ] ] assert model._redolog == [ [ Insert(R(2, 2, 2, 2)) ] ] model.undo() assert model._elems == [] assert model._changelog == [] assert model._redolog == [ [ Insert(R(1, 1, 1, 1)) ], [ Insert(R(2, 2, 2, 2)) ], ] model.redo() assert model._elems == [ R(1, 1, 1, 1) ] assert model._changelog == [ [ Insert(R(1, 1, 1, 1)) ] ] assert model._redolog == [ [ Insert(R(2, 2, 2, 2)) ] ] model.redo() assert model._elems == [ R(1, 1, 1, 1), R(2, 2, 2, 2) ] assert model._changelog == [ [Insert(R(1, 1, 1, 1))], [Insert(R(2, 2, 2, 2))] ] assert model._redolog == [] def test_model_commit_clears_redo_log(self): model = CanvasModel(self.eb) model.commit([ Insert(R(1, 1, 1, 1)) ]) model.commit([ Insert(R(2, 2, 2, 2)) ]) model.undo() model.commit([ Insert(R(3, 3, 3, 3)) ]) # this one clears redo log assert model._elems == [ R(1, 1, 1, 1), R(3, 3, 3, 3) ] assert model._changelog == [ [Insert(R(1, 1, 1, 1))], [Insert(R(3, 3, 3, 3))] ] assert model._redolog == []