Changeset 1310

Show
Ignore:
Timestamp:
05/23/07 22:44:28 (2 years ago)
Author:
arj..@yirdis.nl
Message:
  • Added item_at(x, y) method to diagram items.
  • updated class editor to use item_at()
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • gaphor/trunk/doc/actions.txt

    r1252 r1310  
    2727 
    2828 * 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) 
    3029 * 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 
    3731   visible depends on the state in the action. Hence we require the update() 
    3832   method. 
    3933 
    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) 
    4935 
    5036 
    5137Solution for simple actions 
    52 =========================== 
     38--------------------------- 
    5339 
    5440For an action to actually be useful a piece of menu xml is needed. 
     
    5945        menu_xml = interface.Attribute("The menu XML") 
    6046        action_group = interface.Attribute("The accompanying ActionGroup") 
    61         def update(self)? 
    6247 
    6348Support for actions can be arranged by decorating actions with an @action 
     
    8065 
    8166Solution for context sensitive menus 
    82 ==================================== 
     67------------------------------------ 
    8368 
    8469Context sensitive menus, such as popup menus, should be generated and switched 
     
    9378like that for text around association ends). 
    9479 
     80Scheme: 
     811. User selects an item and presses the rigth mouse button: a popup menu 
     82   should be displayed. 
     832. 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). 
     862. Find a IActionProvider adapters for the selected (focused) item. 
     873. update the popup menu context (actions) for the selected item. 
     88 
  • gaphor/trunk/gaphor/adapters/editors.py

    r1270 r1310  
    4444 
    4545class NamedItemEditor(object): 
    46     """Text edit support for Named items. 
     46    """ 
     47    Text edit support for Named items. 
    4748    """ 
    4849    interface.implements(IEditor) 
     
    138139 
    139140class ClassifierItemEditor(object): 
     141    """ 
     142    Text editor support for Classifiers. Also features contained in Classifiers' 
     143    compartments are edited through this interface. 
     144    """ 
    140145    interface.implements(IEditor) 
    141146    component.adapts(items.ClassifierItem) 
     
    146151 
    147152    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 
    149155        name part or is it text in some compartment 
    150156        """ 
    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) 
    182159 
    183160    def get_text(self): 
  • gaphor/trunk/gaphor/adapters/tests/test_editor.py

    r1247 r1310  
    6868 
    6969 
     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  
    1919from gaphas.state import reversible_property 
    2020from gaphas import Item 
    21 from gaphas.geometry import Rectangle 
     21from gaphas.geometry import Rectangle, distance_point_point_fast 
    2222from gaphas.geometry import distance_rectangle_point, distance_line_point 
    2323 
     
    340340                       self.subject.name or '', align_x=1, align_y=1) 
    341341 
    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         
    343350class AssociationEnd(SubjectSupport): 
    344351    """ 
     
    461468 
    462469    def set_navigable(self, navigable): 
    463         """Change the AssociationEnd's navigability. 
     470        """ 
     471        Change the AssociationEnd's navigability. 
    464472 
    465473        A warning is issued if the subject or opposite property is missing. 
  • gaphor/trunk/gaphor/diagram/classifier.py

    r1210 r1310  
    5959        for item in self: 
    6060            item.pre_update(context) 
     61         
    6162        if self: 
     63            # self (=list) contains items 
    6264            sizes = [f.get_size(True) for f in self] 
    6365            self.width = max(map(lambda p: p[0], sizes)) 
     
    6567            vspacing = self.owner.style.compartment_vspacing 
    6668            self.height += vspacing * (len(sizes) - 1) 
     69 
    6770        padding = self.owner.style.compartment_padding 
    6871        self.width += padding[1] + padding[3] 
     
    7275        for item in self: 
    7376            item.update(context) 
    74  
    7577 
    7678    def draw(self, context): 
     
    9092                cr.restore() 
    9193 
     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 
    92111 
    93112class ClassifierItem(NamedItem): 
     
    396415            cr.translate(0, comp.height) 
    397416 
     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 
    398444 
    399445# vim:sw=4:et 
  • gaphor/trunk/gaphor/diagram/diagramitem.py

    r1292 r1310  
    323323        super(DiagramItem, self).unlink() 
    324324 
     325    def item_at(self, x, y): 
     326        return self 
     327 
    325328    def get_popup_menu(self): 
    326329        """In the popup menu a submenu is created with Stereotypes than can be 
  • gaphor/trunk/gaphor/diagram/interfaces.py

    r1121 r1310  
    9494        """ 
    9595 
    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  
    10696 
    10797# vim: sw=4:et:ai 
  • gaphor/trunk/gaphor/diagram/items.py

    r1121 r1310  
    1616 
    1717# Classes: 
    18 from gaphor.diagram.feature import AttributeItem, OperationItem 
     18from gaphor.diagram.feature import FeatureItem, AttributeItem, OperationItem 
    1919from gaphor.diagram.klass import ClassItem 
    2020from gaphor.diagram.interface import InterfaceItem 
  • gaphor/trunk/gaphor/diagram/tests/test_class.py

    r1121 r1310  
    1717        """Test creation of classes and working of compartments. 
    1818        """ 
    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)) 
    2122 
    2223        self.assertEqual(2, len(klass._compartments)) 
     
    2829 
    2930        self.assertEqual((10, 10), klass._compartments[0].get_size()) 
    30         self.assertEqual(55, float(klass.min_height)) # 35 + 2 * 10 
    31         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)) 
    3233 
    33         attr = UML.create(UML.Property) 
     34        attr = element_factory.create(UML.Property) 
    3435        attr.name = "blah" 
    3536        klass.subject.ownedAttribute = attr 
     
    3940        self.assertEqual((43.0, 18.0), klass._compartments[0].get_size()) 
    4041 
    41         oper = UML.create(UML.Operation) 
     42        oper = element_factory.create(UML.Operation) 
    4243        oper.name = 'method' 
    4344        klass.subject.ownedOperation = oper 
     
    4748        self.assertEqual((43.0, 18.0), klass._compartments[0].get_size()) 
    4849 
    49     def test_editable(self): 
    50         """Test classifier editor 
     50    def test_item_at(self): 
    5151        """ 
    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)) 
    5457        klass.subject.name = 'Class1' 
    5558 
    5659        diagram.canvas.update() 
    5760 
    58         attr = UML.create(UML.Property) 
     61        attr = element_factory.create(UML.Property) 
    5962        attr.name = "blah" 
    6063        klass.subject.ownedAttribute = attr 
    6164 
    62         oper = UML.create(UML.Operation) 
     65        oper = element_factory.create(UML.Operation) 
    6366        oper.name = 'method' 
    6467        klass.subject.ownedOperation = oper 
     
    6669        diagram.canvas.update() 
    6770 
    68         edit = IEditor(klass) 
     71        assert len(klass.compartments[0]) == 1 
     72        assert len(klass.compartments[1]) == 1 
    6973 
    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 
    7177 
    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 
    9088 
    9189# vim:sw=4:et:ai 
  • gaphor/trunk/gaphor/services/adapterloader.py

    r1217 r1310  
    1616        import gaphor.adapters.connectors 
    1717        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() 
    2118         
    2219    def shutdown(self): 
  • gaphor/trunk/gaphor/ui/diagramtab.py

    r1301 r1310  
    77from gaphor import UML 
    88from gaphor.core import _, inject, transactional, action, build_action_group 
    9 from gaphor.diagram.interfaces import IPopupMenu 
    109from gaphor.diagram import get_diagram_item 
    1110from gaphor.transaction import Transaction 
  • gaphor/trunk/gaphor/ui/diagramtools.py

    r1292 r1310  
    122122 
    123123            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)) 
    124126                menu = self.action_manager.ui_manager.get_widget('item-popup') 
    125127                if menu: