def test_can_undo_connected_generalization(event_manager, element_factory, undo_manager, caplog): caplog.set_level(logging.INFO) with Transaction(event_manager): diagram: Diagram = element_factory.create(Diagram) general = diagram.create(ClassItem, subject=element_factory.create(UML.Class)) specific = diagram.create(ClassItem, subject=element_factory.create(UML.Class)) with Transaction(event_manager): generalization = diagram.create(GeneralizationItem) connect(generalization, generalization.head, general) connect(generalization, generalization.tail, specific) assert not caplog.records undo_manager.undo_transaction() assert not list(diagram.select(GeneralizationItem)) assert not caplog.records undo_manager.redo_transaction() new_generalization_item = next(diagram.select(GeneralizationItem)) new_generalization = next(element_factory.select(UML.Generalization)) assert len(list(diagram.select(GeneralizationItem))) == 1 assert len(element_factory.lselect(UML.Generalization)) == 1 assert new_generalization_item.subject is new_generalization assert not caplog.records
def on_button_press(self, event): assert not self._tx self._tx = Transaction() view = self.view view.unselect_all() if _PlacementTool.on_button_press(self, event): try: opposite = self.new_item.opposite( self.new_item.handles()[self._handle_index]) except (KeyError, AttributeError): pass else: # Connect opposite handle first, using the HandleTool's # mechanisms # First make sure all matrices are updated: view.canvas.update_matrix(self.new_item) view.update_matrix(self.new_item) vpos = event.x, event.y item = self.handle_tool.glue(self.new_item, opposite, vpos) if item: self.handle_tool.connect(self.new_item, opposite, vpos) return True return False
def test_can_undo_connected_association(event_manager, element_factory, undo_manager, caplog): caplog.set_level(logging.INFO) with Transaction(event_manager): diagram: Diagram = element_factory.create(Diagram) parent = diagram.create(ClassItem, subject=element_factory.create(UML.Class)) child = diagram.create(ClassItem, subject=element_factory.create(UML.Class)) with Transaction(event_manager): association = diagram.create(AssociationItem) connect(association, association.head, parent) connect(association, association.tail, child) assert not caplog.records undo_manager.undo_transaction() assert not list(diagram.select(AssociationItem)) assert not caplog.records undo_manager.redo_transaction() new_association_item = next(diagram.select(AssociationItem)) new_association = next(element_factory.select(UML.Association)) assert len(list(diagram.select(AssociationItem))) == 1 assert len(element_factory.lselect(UML.Association)) == 1 assert len(new_association.memberEnd) == 2 assert new_association_item.subject is new_association assert new_association_item.head_subject assert new_association_item.tail_subject assert not caplog.records
class PlacementTool(_PlacementTool): """ PlacementTool is used to place items on the canvas. """ def __init__(self, view, item_factory, after_handler=None, handle_index=-1): """ item_factory is a callable. It is used to create a CanvasItem that is displayed on the diagram. """ _PlacementTool.__init__( self, view, factory=item_factory, handle_tool=ConnectHandleTool(), handle_index=handle_index, ) self.after_handler = after_handler self._tx = None @transactional def create_item(self, pos): return self._create_item(pos) def on_button_press(self, event): assert not self._tx self._tx = Transaction() view = self.view view.unselect_all() if _PlacementTool.on_button_press(self, event): try: opposite = self.new_item.opposite( self.new_item.handles()[self._handle_index] ) except (KeyError, AttributeError): pass else: # Connect opposite handle first, using the HandleTool's # mechanisms # First make sure all matrices are updated: view.canvas.update_matrix(self.new_item) view.update_matrix(self.new_item) vpos = event.x, event.y item = self.handle_tool.glue(self.new_item, opposite, vpos) if item: self.handle_tool.connect(self.new_item, opposite, vpos) return True return False def on_button_release(self, event): try: if self.after_handler: self.after_handler(self.new_item) return _PlacementTool.on_button_release(self, event) finally: self._tx.commit() self._tx = None
class TransactionalToolChain(ToolChain): """ In addition to a normal toolchain, this chain begins an undo-transaction at button-press and commits the transaction at button-release. """ def __init__(self, view=None): super(TransactionalToolChain, self).__init__(view) self._tx = None def handle(self, event): # For double click: button_press, double_click, button_release # print 'event', self.EVENT_HANDLERS.get(event.type) if self.EVENT_HANDLERS.get(event.type) in ("on_button_press",): assert not self._tx self._tx = Transaction() try: super(TransactionalToolChain, self).handle(event) finally: if self._tx and self.EVENT_HANDLERS.get(event.type) in ( "on_button_release", "on_double_click", "on_triple_click", ): self._tx.commit() self._tx = None
def test_line_merge_segment(diagram, undo_manager, event_manager): with Transaction(event_manager): line = diagram.create(LinePresentation) segment = Segment(line, diagram) segment.split((5, 5)) head_handle = line.head tail_handle = line.tail with Transaction(event_manager): segment = Segment(line, diagram) segment.merge_segment(0) assert len(line.handles()) == 2 assert line.head is head_handle assert line.tail is tail_handle undo_manager.undo_transaction() assert len(line.handles()) == 3 assert line.head is head_handle assert line.tail is tail_handle undo_manager.redo_transaction() assert len(line.handles()) == 2
class PlacementTool(_PlacementTool): """ PlacementTool is used to place items on the canvas. """ def __init__(self, view, item_factory, after_handler=None, handle_index=-1): """ item_factory is a callable. It is used to create a CanvasItem that is displayed on the diagram. """ _PlacementTool.__init__(self, view, factory=item_factory, handle_tool=ConnectHandleTool(), handle_index=handle_index) self.after_handler = after_handler self._tx = None @transactional def create_item(self, pos): return self._create_item(pos) def on_button_press(self, event): assert not self._tx self._tx = Transaction() view = self.view view.unselect_all() if _PlacementTool.on_button_press(self, event): try: opposite = self.new_item.opposite( self.new_item.handles()[self._handle_index]) except (KeyError, AttributeError): pass else: # Connect opposite handle first, using the HandleTool's # mechanisms # First make sure all matrices are updated: view.canvas.update_matrix(self.new_item) view.update_matrix(self.new_item) vpos = event.x, event.y item = self.handle_tool.glue(self.new_item, opposite, vpos) if item: self.handle_tool.connect(self.new_item, opposite, vpos) return True return False def on_button_release(self, event): try: if self.after_handler: self.after_handler(self.new_item) return _PlacementTool.on_button_release(self, event) finally: self._tx.commit() self._tx = None
class TransactionalToolChain(ToolChain): """ In addition to a normal toolchain, this chain begins an undo-transaction at button-press and commits the transaction at button-release. """ def __init__(self, event_manager, view=None): super().__init__(view) self.event_manager = event_manager self._tx = None def handle(self, event): # For double click: button_press, double_click, button_release # print 'event', self.EVENT_HANDLERS.get(event.type) if self.EVENT_HANDLERS.get(event.type) in ("on_button_press", ): assert not self._tx self._tx = Transaction(self.event_manager) try: return super().handle(event) finally: if self._tx and self.EVENT_HANDLERS.get(event.type) in ( "on_button_release", "on_double_click", "on_triple_click", ): self._tx.commit() self._tx = None
def test_class_association_undo_redo(event_manager, element_factory, undo_manager): with Transaction(event_manager): diagram = element_factory.create(Diagram) assert 0 == len(diagram.connections.solver.constraints) with Transaction(event_manager): ci1 = diagram.create(ClassItem, subject=element_factory.create(UML.Class)) assert 6 == len(diagram.connections.solver.constraints) with Transaction(event_manager): ci2 = diagram.create(ClassItem, subject=element_factory.create(UML.Class)) assert 12 == len(diagram.connections.solver.constraints) with Transaction(event_manager): a = diagram.create(AssociationItem) connect(a, a.head, ci1) connect(a, a.tail, ci2) # Diagram, Association, 2x Class, Property, LiteralSpecification assert 6 == len(element_factory.lselect()) assert 14 == len(diagram.connections.solver.constraints) undo_manager.clear_undo_stack() assert not undo_manager.can_undo() with Transaction(event_manager): ci2.unlink() assert undo_manager.can_undo() def get_connected(handle): """Get item connected to line via handle.""" cinfo = diagram.connections.get_connection(handle) if cinfo: return cinfo.connected return None assert ci1 == get_connected(a.head) assert None is get_connected(a.tail) for i in range(3): assert 7 == len(diagram.connections.solver.constraints) undo_manager.undo_transaction() assert 14 == len(diagram.connections.solver.constraints) assert ci1 == get_connected(a.head) assert ci2.id == get_connected(a.tail).id undo_manager.redo_transaction()
def test_diagram_item_should_not_end_up_in_element_factory( event_manager, element_factory, undo_manager): with Transaction(event_manager): diagram = element_factory.create(Diagram) with Transaction(event_manager): cls = diagram.create(ClassItem, subject=element_factory.create(UML.Class)) undo_manager.undo_transaction() undo_manager.redo_transaction() assert cls not in element_factory.lselect(), element_factory.lselect()
def handle(self, event): # For double click: button_press, double_click, button_release #print 'event', self.EVENT_HANDLERS.get(event.type) if self.EVENT_HANDLERS.get(event.type) in ('on_button_press',): assert not self._tx self._tx = Transaction() try: super(TransactionalToolChain, self).handle(event) finally: if self._tx and self.EVENT_HANDLERS.get(event.type) in ('on_button_release', 'on_double_click', 'on_triple_click'): self._tx.commit() self._tx = None
def test_line_delete(diagram, undo_manager, event_manager): with Transaction(event_manager): line = LinePresentation(diagram) line.insert_handle(1, Handle((20, 20))) line.matrix.translate(10, 10) with Transaction(event_manager): line.unlink() undo_manager.undo_transaction() line = diagram.ownedPresentation[0] assert len(line.handles()) == 3 assert line.handles()[1].pos.tuple() == (20, 20) assert line.matrix.tuple() == (1, 0, 0, 1, 10, 10)
def test_undo_should_not_cause_warnings(event_manager, element_factory, undo_manager, caplog): caplog.set_level(logging.INFO) with Transaction(event_manager): diagram = element_factory.create(Diagram) with Transaction(event_manager): diagram.create(ClassItem, subject=element_factory.create(UML.Class)) assert not caplog.records undo_manager.undo_transaction() assert not diagram.ownedPresentation assert not caplog.records
def handle(self, event): # For double click: button_press, double_click, button_release if self.EVENT_HANDLERS.get(event.type) in ("on_button_press", ): assert not self._tx self._tx = Transaction(self.event_manager) try: return super().handle(event) finally: if self._tx and self.EVENT_HANDLERS.get(event.type) in ( "on_button_release", "on_double_click", "on_triple_click", ): self._tx.commit() self._tx = None
def test_delete_original_association(class_and_association_with_copy, event_manager): c, a, aa = class_and_association_with_copy assert aa.subject.memberEnd[0].type assert aa.subject.memberEnd[1].type assert aa.subject.memberEnd[0].type is c.subject assert aa.subject.memberEnd[1].type is c.subject assert aa.subject.memberEnd[0] is aa.head_subject assert aa.subject.memberEnd[1] is aa.tail_subject assert aa.subject.memberEnd[0] in aa.subject.memberEnd[ 1].type.ownedAttribute # Now, when the original is deleted, the model is changed and made invalid with Transaction(event_manager): a.unlink() assert aa.subject.memberEnd[0].type assert aa.subject.memberEnd[1].type assert aa.subject.memberEnd[0].type is c.subject assert aa.subject.memberEnd[1].type is c.subject assert aa.subject.memberEnd[0] is aa.head_subject assert aa.subject.memberEnd[1] is aa.tail_subject assert aa.subject.memberEnd[0] in aa.subject.memberEnd[ 1].type.ownedAttribute
def test_delete_copied_associations(class_and_association_with_copy, event_manager): c, a, aa = class_and_association_with_copy assert a.subject.memberEnd[0].type assert a.subject.memberEnd[1].type assert a.subject.memberEnd[0].type is c.subject assert a.subject.memberEnd[1].type is c.subject assert a.subject.memberEnd[0] is a.head_subject assert a.subject.memberEnd[1] is a.tail_subject assert a.subject.memberEnd[0] in a.subject.memberEnd[1].type.ownedAttribute # Delete the copy and all is fine with Transaction(event_manager): aa.unlink() assert a.subject.memberEnd[0].type assert a.subject.memberEnd[1].type assert a.subject.memberEnd[0].type is c.subject assert a.subject.memberEnd[1].type is c.subject assert a.subject.memberEnd[0] is a.head_subject assert a.subject.memberEnd[1] is a.tail_subject assert a.subject.memberEnd[0] in a.subject.memberEnd[1].type.ownedAttribute
def on_button_press(self, event): assert not self._tx self._tx = Transaction() view = self.view view.unselect_all() if _PlacementTool.on_button_press(self, event): try: opposite = self.new_item.opposite(self.new_item.handles()[self._handle_index]) except (KeyError, AttributeError): pass else: # Connect opposite handle first, using the HandleTool's # mechanisms # First make sure all matrices are updated: view.canvas.update_matrix(self.new_item) view.update_matrix(self.new_item) vpos = event.x, event.y item = self.handle_tool.glue(self.new_item, opposite, vpos) if item: self.handle_tool.connect(self.new_item, opposite, vpos) return True return False
def test_diagram_item_can_undo_(event_manager, element_factory, undo_manager, caplog): caplog.set_level(logging.INFO) with Transaction(event_manager): diagram = element_factory.create(Diagram) with Transaction(event_manager): cls = diagram.create(ClassItem, subject=element_factory.create(UML.Class)) cls.matrix.translate(10, 10) undo_manager.undo_transaction() undo_manager.redo_transaction() assert diagram.ownedPresentation[0].matrix.tuple() == (1, 0, 0, 1, 10, 10) assert not caplog.records
def test_placement(view, event_manager): factory = new_item_factory(CommentLineItem) tool = placement_tool(view, factory, event_manager, handle_index=-1) with Transaction(event_manager): click(tool, event_manager) click(tool, event_manager)
def test_line_horizontal_property(diagram, undo_manager, event_manager): with Transaction(event_manager): line = LinePresentation(diagram) line.insert_handle(0, Handle()) with Transaction(event_manager): line.horizontal = True assert line.horizontal undo_manager.undo_transaction() assert not line.horizontal undo_manager.redo_transaction() assert line.horizontal
def test_redo_should_show_item_on_diagram(event_manager, element_factory, undo_manager): with Transaction(event_manager): diagram = element_factory.create(UML.Diagram) view = ViewMock(diagram) with Transaction(event_manager): cls = diagram.create(ClassItem, subject=element_factory.create(UML.Class)) undo_manager.undo_transaction() undo_manager.redo_transaction() items, matrix_items, removed_items = view.updates[-1] assert cls in items, view.updates
def delete_selected_items(view: GtkView, event_manager): with Transaction(event_manager): items = view.selection.selected_items for i in list(items): if isinstance(i, Presentation): i.unlink() else: if i.diagram: i.diagram.remove(i)
def cut_action(self): view = self.diagrams.get_current_view() if view.is_focus(): self.clipboard.set_text("", -1) items = view.selection.selected_items self.copy(items) with Transaction(self.event_manager): for i in list(items): i.unlink()
def test_line_handle_no_events_for_removed_handle(diagram, undo_manager, event_manager): with Transaction(event_manager): line = diagram.create(LinePresentation) # Note that inserting and removing handles is *not* transactional handle = Handle() line.insert_handle(1, handle) line.remove_handle(handle) new_pos = (30, 40) with Transaction(event_manager): handle.pos = new_pos assert tuple(handle.pos) == new_pos undo_manager.undo_transaction() assert handle.pos.tuple() == new_pos
def test_remove_class_with_association(create, diagram, element_factory, event_manager): with Transaction(event_manager): c1 = create(ClassItem, UML.Class) c1.name = "klassitem1" c2 = create(ClassItem, UML.Class) c2.name = "klassitem2" a = create(AssociationItem) assert len(list(diagram.get_all_items())) == 3 connect(a, a.head, c1) connect(a, a.tail, c2) assert a.subject assert element_factory.lselect(UML.Association)[0] is a.subject with Transaction(event_manager): c1.unlink()
def test_matrix_operation(action, diagram, undo_manager, event_manager): with Transaction(event_manager): line = LinePresentation(diagram) line.matrix.translate(10, 0) original = tuple(line.matrix) with Transaction(event_manager): action(line) assert tuple(line.matrix) != original undo_manager.undo_transaction() assert tuple(line.matrix) == original undo_manager.redo_transaction() assert tuple(line.matrix) != original
def test_line_handle_position(diagram, undo_manager, event_manager, index): with Transaction(event_manager): line = diagram.create(LinePresentation) handle = line.handles()[index] old_pos = handle.pos.tuple() new_pos = (30, 40) with Transaction(event_manager): handle.pos = new_pos assert tuple(handle.pos) == new_pos undo_manager.undo_transaction() assert handle.pos.tuple() == old_pos undo_manager.redo_transaction() assert tuple(handle.pos) == new_pos
def test_delete_and_undo_model_element(event_manager, element_factory, undo_manager): with Transaction(event_manager): diagram = element_factory.create(Diagram) with Transaction(event_manager): subject = element_factory.create(UML.Class) subject.name = "Name" diagram.create(ClassItem, subject=subject) with Transaction(event_manager): subject.unlink() undo_manager.undo_transaction() new_cls = diagram.ownedPresentation[0] new_elem = element_factory.lookup(subject.id) assert new_cls in new_elem.presentation assert new_cls.subject assert new_elem.name == "Name"
def test_line_connections(diagram, undo_manager, element_factory, event_manager): with Transaction(event_manager): class_item = diagram.create(ClassItem, subject=element_factory.create(Class)) gen_item = diagram.create(GeneralizationItem) handle = gen_item.handles()[0] with Transaction(event_manager): connect(gen_item, handle, class_item) connections = diagram.connections assert connections.get_connection(handle) undo_manager.undo_transaction() assert not connections.get_connection(handle) undo_manager.redo_transaction() assert connections.get_connection(handle)
def test_unioncache_in_derived_union(diagram, event_manager, element_factory): with Transaction(event_manager): uc1 = diagram.create(diagramitems.UseCaseItem, subject=element_factory.create(UML.UseCase)) uc2 = diagram.create(diagramitems.UseCaseItem, subject=element_factory.create(UML.UseCase)) include = diagram.create(diagramitems.IncludeItem) connect(include, include.handles()[0], uc1) connect(include, include.handles()[1], uc2) assert uc1.subject in include.subject.target assert include.subject.ownedElement == []
def test_line_loading_of_points(diagram, undo_manager, event_manager, element_factory): with Transaction(event_manager): line = diagram.create(LinePresentation) line.load("points", "[(0, 0), (5, 5), (10, 10)]") assert len(line.handles()) == 3 handle = line.handles()[1] old_pos = handle.pos.tuple() new_pos = (30, 40) with Transaction(event_manager): handle.pos = new_pos assert tuple(handle.pos) == new_pos undo_manager.undo_transaction() assert handle.pos.tuple() == old_pos undo_manager.redo_transaction() assert tuple(handle.pos) == new_pos
def paste(self, diagram): """Paste items in the copy-buffer to the diagram.""" with Transaction(self.event_manager): # Create new id's that have to be used to create the items: new_items: Set[Presentation] = paste( copy_buffer, diagram, self.element_factory.lookup ) # move pasted items a bit, so user can see result of his action :) for item in new_items: if item.parent not in new_items: item.matrix.translate(10, 10) return new_items
def test_line_create(diagram, undo_manager, event_manager, caplog): with Transaction(event_manager): diagram.create(LinePresentation) assert diagram.ownedPresentation undo_manager.undo_transaction() assert not caplog.records assert not diagram.ownedPresentation undo_manager.redo_transaction() assert diagram.ownedPresentation