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
5import '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)
50class 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