Changeset 1310
- Timestamp:
- 05/23/07 22:44:28 (2 years ago)
- Files:
-
- gaphor/trunk/doc/actions.txt (modified) (4 diffs)
- gaphor/trunk/gaphor/adapters/editors.py (modified) (3 diffs)
- gaphor/trunk/gaphor/adapters/tests/test_editor.py (modified) (1 diff)
- gaphor/trunk/gaphor/diagram/association.py (modified) (3 diffs)
- gaphor/trunk/gaphor/diagram/classifier.py (modified) (5 diffs)
- gaphor/trunk/gaphor/diagram/diagramitem.py (modified) (1 diff)
- gaphor/trunk/gaphor/diagram/interfaces.py (modified) (1 diff)
- gaphor/trunk/gaphor/diagram/items.py (modified) (1 diff)
- gaphor/trunk/gaphor/diagram/tests/test_class.py (modified) (5 diffs)
- gaphor/trunk/gaphor/services/adapterloader.py (modified) (1 diff)
- gaphor/trunk/gaphor/ui/diagramtab.py (modified) (1 diff)
- gaphor/trunk/gaphor/ui/diagramtools.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
gaphor/trunk/doc/actions.txt
r1252 r1310 27 27 28 28 * Each window has it's own action group (every item with a menu?) 29 * One action group for the application/gui_manager (new/load/save/quit)30 29 * One toplevel UIManager per window or one per application/gui_manager? 31 ? Actions should inherit from gtk.Action. 32 Depends on the structure. Preferbly not, since it ties actions to GTK+ 33 (which is not a good thing for testing) 34 ? Actions should be modeled as functions (methods) with action as 35 first (sec) parameter. 36 Normal actions can be modeled as functions. If an action is sensitive or 30 * Normal actions can be modeled as functions. If an action is sensitive or 37 31 visible depends on the state in the action. Hence we require the update() 38 32 method. 39 33 40 * some sort of factory mechanism (MultiAction?). 41 - contains an ActionGroup and menu-XML. 42 - RecentFiles will manage up to 10 recent files entries. 43 - same for stereotypes: should be managed by one "ObjectAction". 44 - can Placeholders play a role here? Yes, they can be used to identify the 45 section where the actions should be put. 46 - In some cases multiple menu items may refer to the same action: 47 radio actions may (but this is not always the case) and the Recent files 48 functionality. 34 * create services for for "dynamic" menus (e.g. recent files/stereotypes) 49 35 50 36 51 37 Solution for simple actions 52 =========================== 38 --------------------------- 53 39 54 40 For an action to actually be useful a piece of menu xml is needed. … … 59 45 menu_xml = interface.Attribute("The menu XML") 60 46 action_group = interface.Attribute("The accompanying ActionGroup") 61 def update(self)?62 47 63 48 Support for actions can be arranged by decorating actions with an @action … … 80 65 81 66 Solution for context sensitive menus 82 ==================================== 67 ------------------------------------ 83 68 84 69 Context sensitive menus, such as popup menus, should be generated and switched … … 93 78 like that for text around association ends). 94 79 80 Scheme: 81 1. User selects an item and presses the rigth mouse button: a popup menu 82 should be displayed. 83 2. find the actual item (this may be a composite item of the element drawn). 84 Use an IItemPicker adapter for that (if no such interface is available, 85 use the item itself). 86 2. Find a IActionProvider adapters for the selected (focused) item. 87 3. update the popup menu context (actions) for the selected item. 88 gaphor/trunk/gaphor/adapters/editors.py
r1270 r1310 44 44 45 45 class NamedItemEditor(object): 46 """Text edit support for Named items. 46 """ 47 Text edit support for Named items. 47 48 """ 48 49 interface.implements(IEditor) … … 138 139 139 140 class ClassifierItemEditor(object): 141 """ 142 Text editor support for Classifiers. Also features contained in Classifiers' 143 compartments are edited through this interface. 144 """ 140 145 interface.implements(IEditor) 141 146 component.adapts(items.ClassifierItem) … … 146 151 147 152 def is_editable(self, x, y): 148 """Find out what's located at point (x, y), is it in the 153 """ 154 Find out what's located at point (x, y), is it in the 149 155 name part or is it text in some compartment 150 156 """ 151 if self._item.drawing_style not in (items.ClassifierItem.DRAW_COMPARTMENT, items.ClassifierItem.DRAW_COMPARTMENT_ICON): 152 self._edit = self._item 153 return True 154 155 self._edit = None 156 # Edit is in name compartment -> edit name 157 name_comp_height = self._item.get_name_size()[1] 158 if y < name_comp_height: 159 self._edit = self._item 160 return True 161 162 padding = self._item.style.compartment_padding 163 vspacing = self._item.style.compartment_vspacing 164 165 # place offset at top of first comparement 166 y -= name_comp_height 167 y += vspacing / 2.0 168 for comp in self._item.compartments: 169 if not comp.visible: 170 continue 171 y -= padding[0] 172 for item in comp: 173 if y < item.height: 174 self._edit = item 175 return True 176 y -= item.height 177 y -= vspacing 178 y -= padding[2] 179 # Compensate for last substraction action 180 y += vspacing 181 return False 157 self._edit = self._item.item_at(x, y) 158 return bool(self._edit and self._edit.subject) 182 159 183 160 def get_text(self): gaphor/trunk/gaphor/adapters/tests/test_editor.py
r1247 r1310 68 68 69 69 70 def test_classifier_editor(self): 71 """ 72 Test classifier editor 73 """ 74 diagram = self.factory.create(UML.Diagram) 75 klass = diagram.create(items.ClassItem, subject=self.factory.create(UML.Class)) 76 klass.subject.name = 'Class1' 77 78 diagram.canvas.update() 79 80 attr = self.factory.create(UML.Property) 81 attr.name = "blah" 82 klass.subject.ownedAttribute = attr 83 84 oper = self.factory.create(UML.Operation) 85 oper.name = 'method' 86 klass.subject.ownedOperation = oper 87 88 diagram.canvas.update() 89 90 edit = IEditor(klass) 91 92 self.assertEqual('ClassifierItemEditor', edit.__class__.__name__) 93 94 self.assertEqual(True, edit.is_editable(10, 10)) 95 96 # Test the inner working of the editor 97 self.assertEqual(klass, edit._edit) 98 self.assertEqual('Class1', edit.get_text()) 99 100 # The attribute: 101 y = klass.get_name_size()[1] + klass.style.compartment_padding[0] + 3 102 self.assertEqual(True, edit.is_editable(4, y)) 103 self.assertEqual(attr, edit._edit.subject) 104 self.assertEqual('+ blah', edit.get_text()) 105 106 y += klass.compartments[0].height 107 # The operation 108 self.assertEqual(True, edit.is_editable(3, y)) 109 self.assertEqual(oper, edit._edit.subject) 110 self.assertEqual('+ method()', edit.get_text()) 111 112 gaphor/trunk/gaphor/diagram/association.py
r1241 r1310 19 19 from gaphas.state import reversible_property 20 20 from gaphas import Item 21 from gaphas.geometry import Rectangle 21 from gaphas.geometry import Rectangle, distance_point_point_fast 22 22 from gaphas.geometry import distance_rectangle_point, distance_line_point 23 23 … … 340 340 self.subject.name or '', align_x=1, align_y=1) 341 341 342 342 def item_at(self, x, y): 343 if distance_point_point_fast(self._handles[0].pos, (x, y)) < 10: 344 return self._head_end 345 elif distance_point_point_fast(self._handles[-1].pos, (x, y)) < 10: 346 return self._tail_end 347 return self 348 349 343 350 class AssociationEnd(SubjectSupport): 344 351 """ … … 461 468 462 469 def set_navigable(self, navigable): 463 """Change the AssociationEnd's navigability. 470 """ 471 Change the AssociationEnd's navigability. 464 472 465 473 A warning is issued if the subject or opposite property is missing. gaphor/trunk/gaphor/diagram/classifier.py
r1210 r1310 59 59 for item in self: 60 60 item.pre_update(context) 61 61 62 if self: 63 # self (=list) contains items 62 64 sizes = [f.get_size(True) for f in self] 63 65 self.width = max(map(lambda p: p[0], sizes)) … … 65 67 vspacing = self.owner.style.compartment_vspacing 66 68 self.height += vspacing * (len(sizes) - 1) 69 67 70 padding = self.owner.style.compartment_padding 68 71 self.width += padding[1] + padding[3] … … 72 75 for item in self: 73 76 item.update(context) 74 75 77 76 78 def draw(self, context): … … 90 92 cr.restore() 91 93 94 def item_at(self, x, y): 95 if 0 > x > self.width: 96 return None 97 98 padding = self.owner.style.compartment_padding 99 height = padding[0] 100 if y < height: 101 return None 102 103 vspacing = self.owner.style.compartment_vspacing 104 for f in self: 105 w, h = f.get_size(True) 106 height += h + vspacing 107 if y < height: 108 return f 109 return None 110 92 111 93 112 class ClassifierItem(NamedItem): … … 396 415 cr.translate(0, comp.height) 397 416 417 def item_at(self, x, y): 418 """ 419 Find the composite item (attribute or operation) for the classifier. 420 """ 421 422 if self.drawing_style not in (ClassifierItem.DRAW_COMPARTMENT, ClassifierItem.DRAW_COMPARTMENT_ICON): 423 return self 424 425 # Edit is in name compartment -> edit name 426 name_comp_height = self.get_name_size()[1] 427 if y < name_comp_height: 428 return self 429 430 padding = self.style.compartment_padding 431 vspacing = self.style.compartment_vspacing 432 433 # place offset at top of first comparement 434 y -= name_comp_height 435 y += vspacing / 2.0 436 for comp in self.compartments: 437 if not comp.visible: 438 continue 439 item = comp.item_at(x, y) 440 if item: 441 return item 442 y -= comp.height 443 return None 398 444 399 445 # vim:sw=4:et gaphor/trunk/gaphor/diagram/diagramitem.py
r1292 r1310 323 323 super(DiagramItem, self).unlink() 324 324 325 def item_at(self, x, y): 326 return self 327 325 328 def get_popup_menu(self): 326 329 """In the popup menu a submenu is created with Stereotypes than can be gaphor/trunk/gaphor/diagram/interfaces.py
r1121 r1310 94 94 """ 95 95 96 class IPopupMenu(interface.Interface):97 """98 Interface for providing popup menus for diagram items.99 """100 101 def get_popup_menu(self):102 """103 Return the popup menu for the adapted diagram item.104 """105 106 96 107 97 # vim: sw=4:et:ai gaphor/trunk/gaphor/diagram/items.py
r1121 r1310 16 16 17 17 # Classes: 18 from gaphor.diagram.feature import AttributeItem, OperationItem18 from gaphor.diagram.feature import FeatureItem, AttributeItem, OperationItem 19 19 from gaphor.diagram.klass import ClassItem 20 20 from gaphor.diagram.interface import InterfaceItem gaphor/trunk/gaphor/diagram/tests/test_class.py
r1121 r1310 17 17 """Test creation of classes and working of compartments. 18 18 """ 19 diagram = UML.create(UML.Diagram) 20 klass = diagram.create(ClassItem, subject=UML.create(UML.Class)) 19 element_factory = UML.ElementFactory() 20 diagram = element_factory.create(UML.Diagram) 21 klass = diagram.create(ClassItem, subject=element_factory.create(UML.Class)) 21 22 22 23 self.assertEqual(2, len(klass._compartments)) … … 28 29 29 30 self.assertEqual((10, 10), klass._compartments[0].get_size()) 30 self.assertEqual( 55, float(klass.min_height)) # 35 +2 * 1031 self.assertEqual( 10, float(klass.min_width))31 self.assertEqual(20, float(klass.min_height)) # 2 * 10 32 self.assertEqual(20, float(klass.min_width)) 32 33 33 attr = UML.create(UML.Property)34 attr = element_factory.create(UML.Property) 34 35 attr.name = "blah" 35 36 klass.subject.ownedAttribute = attr … … 39 40 self.assertEqual((43.0, 18.0), klass._compartments[0].get_size()) 40 41 41 oper = UML.create(UML.Operation)42 oper = element_factory.create(UML.Operation) 42 43 oper.name = 'method' 43 44 klass.subject.ownedOperation = oper … … 47 48 self.assertEqual((43.0, 18.0), klass._compartments[0].get_size()) 48 49 49 def test_editable(self): 50 """Test classifier editor 50 def test_item_at(self): 51 51 """ 52 diagram = UML.create(UML.Diagram) 53 klass = diagram.create(ClassItem, subject=UML.create(UML.Class)) 52 Test working of item_at method. 53 """ 54 element_factory = UML.ElementFactory() 55 diagram = element_factory.create(UML.Diagram) 56 klass = diagram.create(ClassItem, subject=element_factory.create(UML.Class)) 54 57 klass.subject.name = 'Class1' 55 58 56 59 diagram.canvas.update() 57 60 58 attr = UML.create(UML.Property)61 attr = element_factory.create(UML.Property) 59 62 attr.name = "blah" 60 63 klass.subject.ownedAttribute = attr 61 64 62 oper = UML.create(UML.Operation)65 oper = element_factory.create(UML.Operation) 63 66 oper.name = 'method' 64 67 klass.subject.ownedOperation = oper … … 66 69 diagram.canvas.update() 67 70 68 edit = IEditor(klass) 71 assert len(klass.compartments[0]) == 1 72 assert len(klass.compartments[1]) == 1 69 73 70 self.assertEqual('ClassifierItemEditor', edit.__class__.__name__) 74 name_size = klass.get_name_size() 75 assert klass.item_at(10, 10) is klass 76 assert klass.item_at(name_size[0] - 1, name_size[1] - 1) is klass 71 77 72 self.assertEqual(True, edit.is_editable(10, 10)) 73 74 # Test the inner working of the editor 75 self.assertEqual(klass, edit._edit) 76 self.assertEqual('Class1', edit.get_text()) 77 78 # The attribute: 79 y = klass.NAME_COMPARTMENT_HEIGHT + 8 80 self.assertEqual(True, edit.is_editable(30, y)) 81 self.assertEqual(attr, edit._edit.subject) 82 self.assertEqual('+ blah', edit.get_text()) 83 84 y += klass.compartments[0].height 85 # The operation 86 self.assertEqual(True, edit.is_editable(30, y)) 87 self.assertEqual(oper, edit._edit.subject) 88 self.assertEqual('+ method()', edit.get_text()) 89 78 padding = klass.style.compartment_padding 79 vspacing = klass.style.compartment_vspacing 80 x = padding[-1] + 1 81 y = name_size[1] + padding[0] + 2 82 assert klass.item_at(x, y) is not None, klass.item_at(x, y) 83 assert klass.item_at(x, y).subject is attr, klass.item_at(x, y).subject 84 85 y = name_size[1] + klass.compartments[0].height + padding[0] + 2 86 assert klass.item_at(x, y) is not None, klass.item_at(x, y) 87 assert klass.item_at(x, y).subject is oper, klass.item_at(x, y).subject 90 88 91 89 # vim:sw=4:et:ai gaphor/trunk/gaphor/services/adapterloader.py
r1217 r1310 16 16 import gaphor.adapters.connectors 17 17 import gaphor.adapters.editors 18 #for ep in pkg_resources.iter_entry_points('gaphor.adapters'):19 #log.debug('Loading adapters for %s' % ep.name)20 #ep.load()21 18 22 19 def shutdown(self): gaphor/trunk/gaphor/ui/diagramtab.py
r1301 r1310 7 7 from gaphor import UML 8 8 from gaphor.core import _, inject, transactional, action, build_action_group 9 from gaphor.diagram.interfaces import IPopupMenu10 9 from gaphor.diagram import get_diagram_item 11 10 from gaphor.transaction import Transaction gaphor/trunk/gaphor/ui/diagramtools.py
r1292 r1310 122 122 123 123 if item: 124 x, y = context.view.transform_point_c2i(item, event.x, event.y) 125 log.debug('Item at cursor: %s' % item.item_at(x, y)) 124 126 menu = self.action_manager.ui_manager.get_widget('item-popup') 125 127 if menu:
