~timo-jyrinki/ubuntu/trusty/pitivi/backport_utopic_fixes

« back to all changes in this revision

Viewing changes to pitivi/ui/ripple_update_group.py

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2011-05-26 15:29:58 UTC
  • mfrom: (3.1.20 experimental)
  • Revision ID: james.westby@ubuntu.com-20110526152958-90je1myzzjly26vw
Tags: 0.13.9.90-1ubuntu1
* Resynchronize on Debian
* debian/control:
  - Depend on python-launchpad-integration
  - Drop hal from Recommends to Suggests. This version has the patch applied
    to not crash without hal.
* debian/patches/01_lpi.patch:
  - launchpad integration  
* debian/rules:
  - Use gnome.mk so a translation template is built

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# PiTiVi , Non-linear video editor
 
2
#
 
3
#       ui/projectsettings.py
 
4
#
 
5
# Copyright (c) 2010, Brandon Lewis <brandon.lewis@collabora.co.uk>
 
6
#
 
7
# This program is free software; you can redistribute it and/or
 
8
# modify it under the terms of the GNU Lesser General Public
 
9
# License as published by the Free Software Foundation; either
 
10
# version 2.1 of the License, or (at your option) any later version.
 
11
#
 
12
# This program is distributed in the hope that it will be useful,
 
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
# Lesser General Public License for more details.
 
16
#
 
17
# You should have received a copy of the GNU Lesser General Public
 
18
# License along with this program; if not, write to the
 
19
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
20
# Boston, MA 02111-1307, USA.
 
21
 
 
22
 
 
23
class RippleUpdateGroup(object):
 
24
 
 
25
    """Allows for event-driven spreadsheet-like ripple updates without
 
26
    infinite loops.
 
27
 
 
28
    This class allows you to express an event-driven sequence of operations in
 
29
    terms of a directed graph. It is not a constraint solver: The goal is to
 
30
    allow the programmer to reduce complex logic to a set of simple functions
 
31
    and predicates combined declaratively.
 
32
 
 
33
    Events propagate through the graph in breadth first order. During an
 
34
    update cycle, each vertex is visited only once, so cycles can exist in the
 
35
    graph without creating infinite loops.
 
36
 
 
37
    Each vertex represents a unique object. The following may also be
 
38
    associated with a vertex:
 
39
 
 
40
        - the name of a signal on the object. when this signal fires, it
 
41
          triggers an update cycle beginning at this object. during an update
 
42
          cycle, further signal emissions from this or any other vertex will
 
43
          be ignored to prevent infinite loops.
 
44
 
 
45
        - an update function, which will be called when the vertex is visited
 
46
          as part of an update cycle. It will not be called when the object
 
47
          emits a signal.
 
48
 
 
49
        - zero or more user-specified arguments, passed to the
 
50
          update_function.
 
51
 
 
52
    An edge between two verticies represents a sequence of operations. If an
 
53
    edge exists from object A to object B, then whenever A is perfomred, B
 
54
    should be performed too -- unless it has already been visited as part of
 
55
    this update cycle.
 
56
 
 
57
    In addition to a a pair of objects, each edge also has the following
 
58
    assoicated with it:
 
59
 
 
60
        - a predicate function. called during an update cycle when this edge
 
61
          is reached, and before any other processing is done. If this
 
62
          function returns false, it will be as if this edge otherwise did not
 
63
          exist.
 
64
 
 
65
        - a function to be called whenver the edge is visited during an update
 
66
          cycle. this function will not be called if the condition function
 
67
          returns False."""
 
68
 
 
69
    def __init__(self, *widgets):
 
70
        self.arcs = {}
 
71
        self.update_funcs = {}
 
72
        self.ignore_new_signals = False
 
73
        for widget in widgets:
 
74
            self.add_vertex(*widget)
 
75
 
 
76
    def add_vertex(self, widget, update_func=None, signal=None, *args):
 
77
        if signal:
 
78
            widget.connect(signal, self._widget_value_changed)
 
79
        self.update_funcs[widget] = (update_func, args)
 
80
        self.arcs[widget] = []
 
81
 
 
82
    def add_edge(self, a, b, predicate = None,
 
83
        edge_func = None):
 
84
        self.arcs[a].append((b, predicate, edge_func))
 
85
 
 
86
    def add_bi_edge(self, a, b, predicate = None,
 
87
        edge_func = None):
 
88
        self.add_edge(a, b, predicate, edge_func)
 
89
        self.add_edge(b, a, predicate, edge_func)
 
90
 
 
91
    def _widget_value_changed(self, widget, *unused):
 
92
        if self.ignore_new_signals:
 
93
            return
 
94
 
 
95
        self.ignore_new_signals = True
 
96
        self._updateValues(widget)
 
97
        self.ignore_new_signals = False
 
98
 
 
99
    def _updateValues(self, widget):
 
100
        queue = [(widget, v) for v in self.arcs[widget]]
 
101
        visited = set([widget])
 
102
        while queue:
 
103
            parent, (cur, predicate, edge_func) = queue.pop(0)
 
104
 
 
105
            # ignore nodes we've seen
 
106
            if cur in visited:
 
107
                continue
 
108
 
 
109
            # check whether conditions permit this edge to be followed
 
110
            if predicate and (not predicate()):
 
111
                continue
 
112
 
 
113
            # if so call the edge function
 
114
            if edge_func:
 
115
                edge_func()
 
116
 
 
117
            # visit node
 
118
            update_func, args = self.update_funcs[cur]
 
119
            if update_func:
 
120
                update_func(parent, cur, *args)
 
121
            visited.add(cur)
 
122
 
 
123
            # enqueue children
 
124
            queue.extend(((cur, v) for v in self.arcs[cur]))
 
125