Changeset 1149

Show
Ignore:
Timestamp:
03/07/07 23:33:51 (2 years ago)
Author:
arjanmol
Message:

added state observer documentation (state.txt)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • gaphas/trunk/demo.py

    r1145 r1149  
    1919from gaphas.painter import ItemPainter 
    2020 
     21from gaphas import state 
     22 
     23 
    2124class MyBox(Box): 
    2225    """Box with an example connection protocol. 
     
    125128    b.connect('clicked', on_clicked) 
    126129    v.add(b) 
     130 
     131    v.add(gtk.Label('Export:')) 
    127132 
    128133    b = gtk.Button('Write demo.png') 
     
    255260c.add(t) 
    256261 
     262## 
     263## State handling (a.k.a. undo handlers) 
     264## 
     265 
     266# First, activate the revert handler: 
     267state.subscribers.append(state.revert_handler) 
     268 
     269def print_handler(event): 
     270    print 'event:', event 
     271 
     272state.observers.append(print_handler) 
     273 
     274 
     275## 
     276## Start the main application 
     277## 
    257278 
    258279gtk.main() 
  • gaphas/trunk/ez_setup.py

    r945 r1149  
    1515""" 
    1616import sys 
    17 DEFAULT_VERSION = "0.6b4
     17DEFAULT_VERSION = "0.6c5
    1818DEFAULT_URL     = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3] 
    1919 
     
    2727    'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 
    2828    'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 
     29    'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 
     30    'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 
     31    'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 
     32    'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 
     33    'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 
     34    'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 
     35    'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 
     36    'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 
     37    'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 
     38    'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 
     39    'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 
     40    'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 
     41    'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', 
    2942} 
    3043 
     
    7689        pkg_resources.require("setuptools>="+version) 
    7790 
    78     except pkg_resources.VersionConflict
     91    except pkg_resources.VersionConflict, e
    7992        # XXX could we install in a subprocess here? 
    8093        print >>sys.stderr, ( 
    8194            "The required version of setuptools (>=%s) is not available, and\n" 
    8295            "can't be installed while this script is running. Please install\n" 
    83             " a more recent version first.
    84         ) % version 
     96            " a more recent version first.\n\n(Currently using %r)
     97        ) % (version, e.args[0]) 
    8598        sys.exit(2) 
    8699 
     
    138151        import setuptools 
    139152    except ImportError: 
    140         import tempfile, shutil 
    141         tmpdir = tempfile.mkdtemp(prefix="easy_install-") 
     153        egg = None 
    142154        try: 
    143             egg = download_setuptools(version, to_dir=tmpdir, delay=0) 
     155            egg = download_setuptools(version, delay=0) 
    144156            sys.path.insert(0,egg) 
    145157            from setuptools.command.easy_install import main 
    146158            return main(list(argv)+[egg])   # we're done here 
    147159        finally: 
    148             shutil.rmtree(tmpdir) 
     160            if egg and os.path.exists(egg): 
     161                os.unlink(egg) 
    149162    else: 
    150163        if setuptools.__version__ == '0.0.1': 
  • gaphas/trunk/gaphas/canvas.py

    r1136 r1149  
    1616from gaphas.geometry import Matrix 
    1717from gaphas.decorators import async, PRIORITY_HIGH_IDLE 
     18from state import observed, reversible_pair 
    1819 
    1920class Context(object): 
     
    5354    solver = property(lambda s: s._solver) 
    5455 
     56    @observed 
    5557    def add(self, item, parent=None): 
    5658        """ 
     
    7072        self._tree.add(item, parent) 
    7173        self.request_update(item) 
    72         #self._dirty_items.add(item) 
    73         #self._dirty_matrix_items.add(item) 
    74  
     74 
     75    @observed 
    7576    def remove(self, item): 
    7677        """ 
     
    302303            0 
    303304        """ 
    304         if True: #not self._in_update: 
     305        if True: 
    305306            self._dirty_items.add(item) 
    306307            self._dirty_matrix_items.add(item) 
     
    311312                self._dirty_items.add(parent) 
    312313                parent = self._tree.get_parent(parent) 
    313  
    314         # TODO: Schedule update, directly or through a view. 
    315314        self.update() 
    316315 
     
    382381            self.update_matrices() 
    383382 
    384             #for item in dirty_items: 
    385             #    item.update(context_map[item]) 
    386383            for item in dirty_items: 
    387384                c = Context(parent=self._tree.get_parent(item), 
  • gaphas/trunk/gaphas/item.py

    r1136 r1149  
    1111from solver import solvable, WEAK, NORMAL, STRONG 
    1212from constraint import EqualsConstraint, LessThanConstraint 
     13from state import observed, reversible_pair, reversible_property 
     14 
    1315 
    1416class Handle(object): 
     
    2123    """ 
    2224     
    23     x = solvable() 
    24     y = solvable() 
     25    _x = solvable() 
     26    _y = solvable() 
    2527 
    2628    def __init__(self, x=0, y=0, strength=NORMAL, connectable=False, movable=True): 
    27         self.x = x 
    28         self.y = y 
    29         self.x.strength = strength 
    30         self.y.strength = strength 
     29        self._x = x 
     30        self._y = y 
     31        self._x.strength = strength 
     32        self._y.strength = strength 
     33 
    3134        # Flags.. can't have enough of those 
    32         self.connectable = connectable 
    33         self.movable = movable 
    34         self.visible = True 
    35         self.connected_to = None 
     35        self._connectable = connectable 
     36        self._movable = movable 
     37        self._visible = True 
     38        self._connected_to = None 
     39 
    3640        # The constraint used to keep the handle visually connected 
    37         self.disconnect = lambda: 0 
    38  
     41        self._disconnect = lambda: 0 
     42 
     43    @observed 
     44    def _set_x(self, x): 
     45        self._x = x 
     46 
     47    x = reversible_property(lambda s: s._x, _set_x) 
     48 
     49    @observed 
     50    def _set_y(self, y): 
     51        self._y = y 
     52 
     53    y = reversible_property(lambda s: s._y, _set_y) 
     54 
     55    @observed 
     56    def _set_connectable(self, connectable): 
     57        self._connectable = connectable 
     58 
     59    connectable = reversible_property(lambda s: s._connectable, _set_connectable) 
     60 
     61    @observed 
     62    def _set_movable(self, movable): 
     63        self._movable = movable 
     64 
     65    movable = reversible_property(lambda s: s._movable, _set_movable) 
     66 
     67    @observed 
     68    def _set_visible(self, visible): 
     69        self._visible = visible 
     70 
     71    visible = reversible_property(lambda s: s._visible, _set_visible) 
     72 
     73    @observed 
     74    def _set_connected_to(self, connected_to): 
     75        self._connected_to = connected_to 
     76 
     77    connected_to = reversible_property(lambda s: s._connected_to, _set_connected_to) 
     78 
     79    @observed 
     80    def _set_disconnect(self, disconnect): 
     81        self._disconnect = disconnect 
     82 
     83    disconnect = reversible_property(lambda s: s._disconnect, _set_disconnect) 
     84 
     85    @observed 
    3986    def _set_pos(self, pos): 
    4087        """ 
     
    71118        self._matrix = Matrix() 
    72119 
     120    @observed 
    73121    def _set_canvas(self, canvas): 
    74122        """ 
     
    86134        Unset the canvas. 
    87135        """ 
    88         self.teardown_canvas() 
    89         self._canvas = None 
    90  
    91     canvas = property(lambda s: s._canvas, _set_canvas, _del_canvas) 
     136        self._set_canvas(None) 
     137 
     138    canvas = reversible_property(lambda s: s._canvas, _set_canvas, _del_canvas) 
    92139 
    93140    def setup_canvas(self): 
     
    105152        pass 
    106153 
     154    @observed 
    107155    def _set_matrix(self, matrix): 
    108156        """ 
     
    113161        self._matrix = matrix 
    114162 
    115     matrix = property(lambda s: s._matrix, _set_matrix) 
     163    matrix = reversible_property(lambda s: s._matrix, _set_matrix) 
    116164 
    117165    def request_update(self): 
     
    220268        Variable(0, 30) 
    221269        >>> b._handles[SE].y 
    222         Variable(20, 30) 
     270        Variable(10, 30) 
    223271        """ 
    224272        if height < self.min_height: 
     
    236284    height = property(_get_height, _set_height) 
    237285 
     286    @observed 
    238287    def _set_min_width(self, min_width): 
    239288        """ 
     
    243292            self.width = min_width 
    244293 
    245     min_width = property(lambda s: s._min_width, _set_min_width) 
    246  
     294    min_width = reversible_property(lambda s: s._min_width, _set_min_width) 
     295 
     296    @observed 
    247297    def _set_min_height(self, min_height): 
    248298        """ 
     
    252302            self.height = min_height 
    253303 
    254     min_height = property(lambda s: s._min_height, _set_min_height) 
     304    min_height = reversible_property(lambda s: s._min_height, _set_min_height) 
    255305 
    256306    def setup_canvas(self): 
     
    267317        8 
    268318        >>> len(c.solver._marked_cons) 
    269         8 
     319        0 
    270320        >>> c.solver.solve() 
    271321        >>> len(c.solver._constraints) 
     
    311361        >>> len(c.solver._constraints) 
    312362        8 
    313         >>> b.teardown() 
     363        >>> b.teardown_canvas() 
    314364        >>> len(c.solver._constraints) 
    315365        0 
     
    387437        self._handles = [Handle(connectable=True), Handle(10, 10, connectable=True)] 
    388438 
    389         self.line_width = 2 
    390         self.fuzzyness = 0 
     439        self._line_width = 2 
     440        self._fuzzyness = 0 
    391441        self._orthogonal = [] 
    392442        self._horizontal = False 
    393443        self._head_angle = self._tail_angle = 0 
    394444 
     445    @observed 
     446    def _set_line_width(self, line_width): 
     447        self._line_width = line_width 
     448 
     449    line_width = reversible_property(lambda s: s._line_width, _set_line_width) 
     450 
     451    @observed 
     452    def _set_fuzzyness(self, fuzzyness): 
     453        self._fuzzyness = fuzzyness 
     454 
     455    fuzzyness = reversible_property(lambda s: s._fuzzyness, _set_fuzzyness) 
     456 
     457    @observed 
    395458    def _set_orthogonal(self, orthogonal): 
    396459        """ 
     
    421484        self.request_update() 
    422485 
    423     orthogonal = property(lambda s: s._orthogonal != [], _set_orthogonal) 
    424  
     486    orthogonal = reversible_property(lambda s: s._orthogonal != [], _set_orthogonal) 
     487 
     488    @observed 
    425489    def _set_horizontal(self, horizontal): 
    426490        self._horizontal = horizontal 
    427491        self._set_orthogonal(self._orthogonal) 
    428492 
    429     horizontal = property(lambda s: s._horizontal != [], _set_horizontal) 
     493    horizontal = reversible_property(lambda s: s._horizontal != [], _set_horizontal) 
    430494 
    431495    def setup_canvas(self): 
     
    442506            self.canvas.solver.remove_constraint(c) 
    443507 
     508    @observed 
    444509    def split_segment(self, segment, parts=2): 
    445510        """ 
    446         Split one segment in the Line in @parts pieces. 
     511        Split one segment in the Line in @parts equal pieces. 
    447512        @segment 0 is the first segment (between handles 0 and 1). 
    448513        The min number of parts is 2. 
     
    481546        self.orthogonal = self.orthogonal 
    482547 
    483     def merge_segment(self, segment): 
     548    @observed 
     549    def merge_segment(self, segment, parts=2): 
    484550        """ 
    485551        Merge the @segment and the next. 
     552        The parts parameter indicates how many segments should be merged 
    486553 
    487554        >>> a = Line() 
     
    500567        if 0 >= segment > len(self._handles) - 1: 
    501568            raise IndexError("index out of range (0 > %d > %d)" % (segment, len(self._handles) - 1)) 
    502         # TODO: recreate constraints that use self._handles[segment + 1] 
    503569        if segment == 0: segment = 1 
    504570        del self._handles[segment] 
    505         self.orthogonal = self.orthogonal 
     571        if parts > 2: 
     572            merge_segment(segment, parts - 1) 
     573        else: 
     574            # Force orthogonal constraints to be recreated 
     575            self.orthogonal = self.orthogonal 
     576 
     577    reversible_pair(split_segment, merge_segment) 
    506578 
    507579    def handles(self): 
  • gaphas/trunk/gaphas/state.py

    r1148 r1149  
    5050 decorator is called from within the decorator it's hard to find out where 
    5151 the decorated function lives (is it even possible?). 
     52Solution: add a special __observer__ attribute to the inner function. 
    5253""" 
    5354 
     
    6364subscribers = list() 
    6465 
    65 class StateChange(object): 
    66     """ 
    67     Simple StateChange event 
    68     """ 
    69  
    70     def __init__(self, func, spec, args, kwargs): 
    71         self.func = func 
    72         self.spec = spec 
    73         self.args = args 
    74         self.kwargs = kwargs 
    75  
    76     def __call__(self): 
    77         pass 
    78  
    7966 
    8067# Subscribe to low-level change events: 
    8168observers = list() 
    82  
    83 #def decorator(func): 
    84 #    def _apply(*args, **kwargs): 
    85 #        print 'DECORATOR', func 
    86 #        return func(*args, **kwargs) 
    87 #    return _apply 
    8869 
    8970 
     
    9778    """ 
    9879    def wrapper(func, *args, **kwargs): 
    99         #print 'DISPATCHING', func, func.__observer__ 
    10080        dispatch((func.__observer__, args, kwargs), queue=observers) 
    10181        return func(*args, **kwargs) 
    10282    dec = decorator(wrapper, func) 
    103      
    10483    func.__observer__ = dec 
    10584    return dec 
     
    135114def reversible_pair(func1, func2, bind1={}, bind2={}): 
    136115    global _reverse 
    137     #print 'reversible_pair' ,func1, dir(func1), func1.im_func, func1.im_func 
    138     #print func1, type(func1), func1.im_func, type(func1.im_func) 
    139116    # We need the funcion, since that's what's in the events 
    140117    if isinstance(func1, types.UnboundMethodType): func1 = func1.im_func 
     
    143120    _reverse[func2] = (func1, inspect.getargspec(func1), bind1) 
    144121 
    145 def reverse_handler(event): 
     122 
     123def reversible_property(fget=None, fset=None, fdel=None, doc=None): 
     124    """ 
     125    Replacement for the property descriptor. In addition to creating a 
     126    property instance, the property is registered as reversible and  
     127    reverse events can be send out when changes occur. 
     128    """ 
     129    # given fset, read the value argument name (second arg) and create a 
     130    # bind {value: lambda self: fget(self)} 
     131 
     132    # TODO! 
     133 
     134    return property(fget=fget, fset=fset, fdel=fdel, doc=doc) 
     135 
     136 
     137def revert_handler(event): 
    146138    """ 
    147139    Event handler, generates undoable statements and puts them on the 
    148140    subscribers queue. 
    149141 
     142    First thing to do is to actually enable the revert_handler: 
     143    >>> observers.append(revert_handler) 
     144     
    150145    First let's define our simple list: 
    151146    >>> class SList(object): 
     
    202197    dispatch((reverse, kwargs)) 
    203198 
    204 observers.append(reverse_handler) 
    205  
    206199 
    207200def saveapply(func, kw): 
  • gaphas/trunk/gaphas/tree.py

    r1013 r1149  
    66__version__ = "$Revision$" 
    77# $HeadURL$ 
     8 
     9from state import observed, reversible_pair 
    810 
    911 
     
    4143        """ 
    4244        parent = self.get_parent(node) 
    43         return self._children[parent] #[ n for n in self._children[parent] if not n is node ] 
     45        return self._children[parent] 
    4446 
    4547    def get_next_sibling(self, node): 
     
    9193            nodes.append(node) 
    9294 
     95    @observed 
    9396    def add(self, node, parent=None): 
    9497        """Add @node to the tree. @parent is the parent node, which may 
     
    102105        self._children[node] = [] 
    103106 
     107    @observed 
    104108    def remove(self, node): 
    105109        """Remove @node from the tree. 
     
    115119        self._nodes.remove(node) 
    116120 
     121    reversible_pair(add, remove, 
     122                    bind1={'parent': lambda self, node: self.get_parent(node) }) 
     123 
    117124 
    118125def test_add():