File: include.py

package info (click to toggle)
python-enaml 0.19.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,284 kB
  • sloc: python: 31,443; cpp: 4,499; makefile: 140; javascript: 68; lisp: 53; sh: 20
file content (128 lines) | stat: -rw-r--r-- 4,966 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#------------------------------------------------------------------------------
# Copyright (c) 2013-2025, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
from atom.api import ContainerList, Bool

from .declarative import Declarative, d_
from .object import Object


class Include(Declarative):
    """ An object which dynamically inserts children into its parent.

    The 'Include' object is used to cleanly and easily insert objects
    into the children of its parent. 'Object' instances assigned to the
    'objects' list of the 'Include' will be parented with the parent of
    the 'Include'. Creating an 'Include' with no parent is a programming
    error.

    """
    #: The list of objects belonging to this Include. Objects in this
    #: list will be automatically parented with the Include's parent.
    objects = d_(ContainerList(Object))

    #: A boolean flag indicating whether to destroy the old objects that
    #: are removed from the parent. The default is True.
    destroy_old = d_(Bool(True))

    def initialize(self):
        """ A reimplemented initializer.

        This method will add the include objects to the parent of the
        include and ensure that they are initialized.

        """
        super(Include, self).initialize()
        self.parent.insert_children(self, self.objects)
        for obj in self.objects:
            obj.initialize()

    def destroy(self):
        """ A reimplemented destructor.

        The Include will destroy all of its objects if the 'destroy_old'
        flag is set and the parent is not also being destroyed.

        """
        destroy_items = self.destroy_old
        if destroy_items:
            parent = self.parent
            destroy_items = parent is None or not parent.is_destroyed
        super(Include, self).destroy()
        if destroy_items:
            for item in self.objects:
                if not item.is_destroyed:
                    item.destroy()
        del self.objects

    def _observe_objects(self, change):
        """ A change handler for the 'objects' list of the Include.

        If the object is initialized objects which are removed will be
        unparented and objects which are added will be reparented. Old
        objects will be destroyed if the 'destroy_old' flag is True.

        """
        # TODO clean this up
        if self.is_initialized:
            if change['type'] == 'update':
                oldvalue = change['oldvalue']
                newvalue = change['value']
                newset = set(newvalue)
                if self.destroy_old:
                    for obj in oldvalue:
                        if obj not in newset:
                            obj.destroy()
                else:
                    for obj in oldvalue:
                        if obj not in newset:
                            obj.set_parent(None)
                if newvalue:
                    self.parent.insert_children(self, newvalue)
            elif change['type'] == 'container':
                added = []
                removed = []
                op = change['operation']
                if op == '__delitem__':
                    item = change['item']
                    if isinstance(item, list):
                        removed.extend(item)
                    else:
                        removed.append(item)
                elif op == '__iadd__':
                    added.extend(change['items'])
                elif op == '__setitem__':
                    olditem = change['olditem']
                    newitem = change['newitem']
                    if isinstance(olditem, list):
                        removed.extend(olditem)
                    else:
                        removed.append(olditem)
                    if isinstance(newitem, list):
                        added.extend(newitem)
                    else:
                        added.append(newitem)
                elif op == 'append':
                    added.append(change['item'])
                elif op == 'extend':
                    added.extend(change['items'])
                elif op == 'insert':
                    added.append(change['item'])
                elif op == 'pop':
                    removed.append(change['item'])
                elif op == 'remove':
                    removed.append(change['item'])
                addset = set(added)
                if self.destroy_old:
                    for obj in removed:
                        if obj not in addset:
                            obj.destroy()
                else:
                    for obj in removed:
                        if obj not in addset:
                            obj.set_parent(None)
                self.parent.insert_children(self, change['value'])