1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'package:meta/meta.dart' ; |
6 | |
7 | // This file gets mutated by //dev/devicelab/bin/tasks/flutter_test_performance.dart |
8 | // during device lab performance tests. When editing this file, check to make sure |
9 | // that it didn't break that test. |
10 | |
11 | /// Deprecated. Unused by the framework and will be removed in a future version |
12 | /// of Flutter. If needed, inline any required functionality of this class |
13 | /// directly in the subclass. |
14 | /// |
15 | /// An abstract node in a tree. |
16 | /// |
17 | /// AbstractNode has as notion of depth, attachment, and parent, but does not |
18 | /// have a model for children. |
19 | /// |
20 | /// When a subclass is changing the parent of a child, it should call either |
21 | /// `parent.adoptChild(child)` or `parent.dropChild(child)` as appropriate. |
22 | /// Subclasses can expose an API for manipulating the tree if desired (e.g. a |
23 | /// setter for a `child` property, or an `add()` method to manipulate a list). |
24 | /// |
25 | /// The current parent node is exposed by the [parent] property. |
26 | /// |
27 | /// The current attachment state is exposed by [attached]. The root of any tree |
28 | /// that is to be considered attached should be manually attached by calling |
29 | /// [attach]. Other than that, the [attach] and [detach] methods should not be |
30 | /// called directly; attachment is managed automatically by the aforementioned |
31 | /// [adoptChild] and [dropChild] methods. |
32 | /// |
33 | /// Subclasses that have children must override [attach] and [detach] as |
34 | /// described in the documentation for those methods. |
35 | /// |
36 | /// Nodes always have a [depth] greater than their ancestors'. There's no |
37 | /// guarantee regarding depth between siblings. The depth of a node is used to |
38 | /// ensure that nodes are processed in depth order. The [depth] of a child can |
39 | /// be more than one greater than the [depth] of the parent, because the [depth] |
40 | /// values are never decreased: all that matters is that it's greater than the |
41 | /// parent. Consider a tree with a root node A, a child B, and a grandchild C. |
42 | /// Initially, A will have [depth] 0, B [depth] 1, and C [depth] 2. If C is |
43 | /// moved to be a child of A, sibling of B, then the numbers won't change. C's |
44 | /// [depth] will still be 2. The [depth] is automatically maintained by the |
45 | /// [adoptChild] and [dropChild] methods. |
46 | @Deprecated( |
47 | 'If needed, inline any required functionality of AbstractNode in your class directly. ' |
48 | 'This feature was deprecated after v3.12.0-4.0.pre.' , |
49 | ) |
50 | class AbstractNode { |
51 | /// The depth of this node in the tree. |
52 | /// |
53 | /// The depth of nodes in a tree monotonically increases as you traverse down |
54 | /// the tree. |
55 | int get depth => _depth; |
56 | int _depth = 0; |
57 | |
58 | /// Adjust the [depth] of the given [child] to be greater than this node's own |
59 | /// [depth]. |
60 | /// |
61 | /// Only call this method from overrides of [redepthChildren]. |
62 | @protected |
63 | void redepthChild(AbstractNode child) { |
64 | assert(child.owner == owner); |
65 | if (child._depth <= _depth) { |
66 | child._depth = _depth + 1; |
67 | child.redepthChildren(); |
68 | } |
69 | } |
70 | |
71 | /// Adjust the [depth] of this node's children, if any. |
72 | /// |
73 | /// Override this method in subclasses with child nodes to call [redepthChild] |
74 | /// for each child. Do not call this method directly. |
75 | void redepthChildren() { } |
76 | |
77 | /// The owner for this node (null if unattached). |
78 | /// |
79 | /// The entire subtree that this node belongs to will have the same owner. |
80 | Object? get owner => _owner; |
81 | Object? _owner; |
82 | |
83 | /// Whether this node is in a tree whose root is attached to something. |
84 | /// |
85 | /// This becomes true during the call to [attach]. |
86 | /// |
87 | /// This becomes false during the call to [detach]. |
88 | bool get attached => _owner != null; |
89 | |
90 | /// Mark this node as attached to the given owner. |
91 | /// |
92 | /// Typically called only from the [parent]'s [attach] method, and by the |
93 | /// [owner] to mark the root of a tree as attached. |
94 | /// |
95 | /// Subclasses with children should override this method to |
96 | /// [attach] all their children to the same [owner] |
97 | /// after calling the inherited method, as in `super.attach(owner)`. |
98 | @mustCallSuper |
99 | void attach(covariant Object owner) { |
100 | assert(_owner == null); |
101 | _owner = owner; |
102 | } |
103 | |
104 | /// Mark this node as detached. |
105 | /// |
106 | /// Typically called only from the [parent]'s [detach], and by the [owner] to |
107 | /// mark the root of a tree as detached. |
108 | /// |
109 | /// Subclasses with children should override this method to |
110 | /// [detach] all their children after calling the inherited method, |
111 | /// as in `super.detach()`. |
112 | @mustCallSuper |
113 | void detach() { |
114 | assert(_owner != null); |
115 | _owner = null; |
116 | assert(parent == null || attached == parent!.attached); |
117 | } |
118 | |
119 | /// The parent of this node in the tree. |
120 | AbstractNode? get parent => _parent; |
121 | AbstractNode? _parent; |
122 | |
123 | /// Mark the given node as being a child of this node. |
124 | /// |
125 | /// Subclasses should call this function when they acquire a new child. |
126 | @protected |
127 | @mustCallSuper |
128 | void adoptChild(covariant AbstractNode child) { |
129 | assert(child._parent == null); |
130 | assert(() { |
131 | AbstractNode node = this; |
132 | while (node.parent != null) { |
133 | node = node.parent!; |
134 | } |
135 | assert(node != child); // indicates we are about to create a cycle |
136 | return true; |
137 | }()); |
138 | child._parent = this; |
139 | if (attached) { |
140 | child.attach(_owner!); |
141 | } |
142 | redepthChild(child); |
143 | } |
144 | |
145 | /// Disconnect the given node from this node. |
146 | /// |
147 | /// Subclasses should call this function when they lose a child. |
148 | @protected |
149 | @mustCallSuper |
150 | void dropChild(covariant AbstractNode child) { |
151 | assert(child._parent == this); |
152 | assert(child.attached == attached); |
153 | child._parent = null; |
154 | if (attached) { |
155 | child.detach(); |
156 | } |
157 | } |
158 | } |
159 | |