1 | // Copyright 2021 The AccessKit Authors. All rights reserved. |
2 | // Licensed under the Apache License, Version 2.0 (found in |
3 | // the LICENSE-APACHE file) or the MIT license (found in |
4 | // the LICENSE-MIT file), at your option. |
5 | |
6 | use accesskit::{Live, Node as NodeData, NodeId, Tree as TreeData, TreeUpdate}; |
7 | use std::collections::{HashMap, HashSet}; |
8 | |
9 | use crate::node::{DetachedNode, Node, NodeState, ParentAndIndex}; |
10 | |
11 | #[derive (Clone)] |
12 | pub struct State { |
13 | pub(crate) nodes: HashMap<NodeId, NodeState>, |
14 | pub(crate) data: TreeData, |
15 | focus: NodeId, |
16 | is_host_focused: bool, |
17 | } |
18 | |
19 | struct InternalFocusChange { |
20 | old_focus: Option<DetachedNode>, |
21 | new_focus_old_node: Option<DetachedNode>, |
22 | } |
23 | |
24 | #[derive (Default)] |
25 | struct InternalChanges { |
26 | added_node_ids: HashSet<NodeId>, |
27 | updated_nodes: HashMap<NodeId, DetachedNode>, |
28 | focus_change: Option<InternalFocusChange>, |
29 | removed_nodes: HashMap<NodeId, DetachedNode>, |
30 | } |
31 | |
32 | impl State { |
33 | fn validate_global(&self) { |
34 | assert!(self.nodes.contains_key(&self.data.root)); |
35 | assert!(self.nodes.contains_key(&self.focus)); |
36 | } |
37 | |
38 | fn update( |
39 | &mut self, |
40 | update: TreeUpdate, |
41 | is_host_focused: bool, |
42 | mut changes: Option<&mut InternalChanges>, |
43 | ) { |
44 | // First, if we're collecting changes, get the accurate state |
45 | // of any updated nodes. |
46 | if let Some(changes) = &mut changes { |
47 | for (node_id, _) in &update.nodes { |
48 | if let Some(old_node) = self.node_by_id(*node_id) { |
49 | let old_node = old_node.detached(); |
50 | changes.updated_nodes.insert(*node_id, old_node); |
51 | } |
52 | } |
53 | } |
54 | |
55 | let mut orphans = HashSet::new(); |
56 | let old_focus_id = self.is_host_focused.then_some(self.focus); |
57 | let old_root_id = self.data.root; |
58 | |
59 | if let Some(tree) = update.tree { |
60 | if tree.root != self.data.root { |
61 | orphans.insert(self.data.root); |
62 | } |
63 | self.data = tree; |
64 | } |
65 | |
66 | let root = self.data.root; |
67 | let mut pending_nodes: HashMap<NodeId, _> = HashMap::new(); |
68 | let mut pending_children = HashMap::new(); |
69 | |
70 | fn add_node( |
71 | nodes: &mut HashMap<NodeId, NodeState>, |
72 | changes: &mut Option<&mut InternalChanges>, |
73 | parent_and_index: Option<ParentAndIndex>, |
74 | id: NodeId, |
75 | data: NodeData, |
76 | ) { |
77 | let state = NodeState { |
78 | id, |
79 | parent_and_index, |
80 | data, |
81 | }; |
82 | nodes.insert(id, state); |
83 | if let Some(changes) = changes { |
84 | changes.added_node_ids.insert(id); |
85 | } |
86 | } |
87 | |
88 | for (node_id, node_data) in update.nodes { |
89 | orphans.remove(&node_id); |
90 | |
91 | let mut seen_child_ids = HashSet::new(); |
92 | for (child_index, child_id) in node_data.children().iter().enumerate() { |
93 | assert!(!seen_child_ids.contains(child_id)); |
94 | orphans.remove(child_id); |
95 | let parent_and_index = ParentAndIndex(node_id, child_index); |
96 | if let Some(child_state) = self.nodes.get_mut(child_id) { |
97 | if child_state.parent_and_index != Some(parent_and_index) { |
98 | child_state.parent_and_index = Some(parent_and_index); |
99 | } |
100 | } else if let Some(child_data) = pending_nodes.remove(child_id) { |
101 | add_node( |
102 | &mut self.nodes, |
103 | &mut changes, |
104 | Some(parent_and_index), |
105 | *child_id, |
106 | child_data, |
107 | ); |
108 | } else { |
109 | pending_children.insert(*child_id, parent_and_index); |
110 | } |
111 | seen_child_ids.insert(child_id); |
112 | } |
113 | |
114 | if let Some(node_state) = self.nodes.get_mut(&node_id) { |
115 | if node_id == root { |
116 | node_state.parent_and_index = None; |
117 | } |
118 | for child_id in node_state.data.children().iter() { |
119 | if !seen_child_ids.contains(child_id) { |
120 | orphans.insert(*child_id); |
121 | } |
122 | } |
123 | node_state.data = node_data; |
124 | } else if let Some(parent_and_index) = pending_children.remove(&node_id) { |
125 | add_node( |
126 | &mut self.nodes, |
127 | &mut changes, |
128 | Some(parent_and_index), |
129 | node_id, |
130 | node_data, |
131 | ); |
132 | } else if node_id == root { |
133 | add_node(&mut self.nodes, &mut changes, None, node_id, node_data); |
134 | } else { |
135 | pending_nodes.insert(node_id, node_data); |
136 | } |
137 | } |
138 | |
139 | assert_eq!(pending_nodes.len(), 0); |
140 | assert_eq!(pending_children.len(), 0); |
141 | |
142 | if update.focus != self.focus || is_host_focused != self.is_host_focused { |
143 | let old_focus = old_focus_id.map(|id| self.node_by_id(id).unwrap().detached()); |
144 | let new_focus = is_host_focused.then_some(update.focus); |
145 | if let Some(changes) = &mut changes { |
146 | changes.focus_change = Some(InternalFocusChange { |
147 | old_focus, |
148 | new_focus_old_node: new_focus |
149 | .and_then(|id| { |
150 | (!changes.updated_nodes.contains_key(&id)) |
151 | .then(|| self.node_by_id(id).map(|node| node.detached())) |
152 | }) |
153 | .flatten(), |
154 | }); |
155 | } |
156 | self.focus = update.focus; |
157 | self.is_host_focused = is_host_focused; |
158 | } |
159 | |
160 | if !orphans.is_empty() { |
161 | let mut to_remove = HashSet::new(); |
162 | |
163 | fn traverse_orphan( |
164 | nodes: &HashMap<NodeId, NodeState>, |
165 | to_remove: &mut HashSet<NodeId>, |
166 | id: NodeId, |
167 | ) { |
168 | to_remove.insert(id); |
169 | let node = nodes.get(&id).unwrap(); |
170 | for child_id in node.data.children().iter() { |
171 | traverse_orphan(nodes, to_remove, *child_id); |
172 | } |
173 | } |
174 | |
175 | for id in orphans { |
176 | traverse_orphan(&self.nodes, &mut to_remove, id); |
177 | } |
178 | |
179 | for id in to_remove { |
180 | if let Some(old_node_state) = self.nodes.remove(&id) { |
181 | if let Some(changes) = &mut changes { |
182 | let old_node = DetachedNode { |
183 | state: old_node_state, |
184 | is_focused: old_focus_id == Some(id), |
185 | is_root: old_root_id == id, |
186 | name: None, |
187 | value: None, |
188 | live: Live::Off, |
189 | supports_text_ranges: false, |
190 | }; |
191 | changes.removed_nodes.insert(id, old_node); |
192 | } |
193 | } |
194 | } |
195 | } |
196 | |
197 | self.validate_global(); |
198 | } |
199 | |
200 | fn update_host_focus_state( |
201 | &mut self, |
202 | is_host_focused: bool, |
203 | changes: Option<&mut InternalChanges>, |
204 | ) { |
205 | let update = TreeUpdate { |
206 | nodes: vec![], |
207 | tree: None, |
208 | focus: self.focus, |
209 | }; |
210 | self.update(update, is_host_focused, changes); |
211 | } |
212 | |
213 | pub fn serialize(&self) -> TreeUpdate { |
214 | let mut nodes = Vec::new(); |
215 | |
216 | fn traverse(state: &State, nodes: &mut Vec<(NodeId, NodeData)>, id: NodeId) { |
217 | let node = state.nodes.get(&id).unwrap(); |
218 | nodes.push((id, node.data.clone())); |
219 | |
220 | for child_id in node.data.children().iter() { |
221 | traverse(state, nodes, *child_id); |
222 | } |
223 | } |
224 | |
225 | traverse(self, &mut nodes, self.data.root); |
226 | assert_eq!(nodes.len(), self.nodes.len()); |
227 | |
228 | TreeUpdate { |
229 | nodes, |
230 | tree: Some(self.data.clone()), |
231 | focus: self.focus, |
232 | } |
233 | } |
234 | |
235 | pub fn has_node(&self, id: NodeId) -> bool { |
236 | self.nodes.contains_key(&id) |
237 | } |
238 | |
239 | pub fn node_by_id(&self, id: NodeId) -> Option<Node<'_>> { |
240 | self.nodes.get(&id).map(|node_state| Node { |
241 | tree_state: self, |
242 | state: node_state, |
243 | }) |
244 | } |
245 | |
246 | pub fn root_id(&self) -> NodeId { |
247 | self.data.root |
248 | } |
249 | |
250 | pub fn root(&self) -> Node<'_> { |
251 | self.node_by_id(self.root_id()).unwrap() |
252 | } |
253 | |
254 | pub fn focus_id(&self) -> Option<NodeId> { |
255 | self.is_host_focused.then_some(self.focus) |
256 | } |
257 | |
258 | pub fn focus(&self) -> Option<Node<'_>> { |
259 | self.focus_id().map(|id| self.node_by_id(id).unwrap()) |
260 | } |
261 | |
262 | pub fn app_name(&self) -> Option<String> { |
263 | self.data.app_name.clone() |
264 | } |
265 | |
266 | pub fn toolkit_name(&self) -> Option<String> { |
267 | self.data.toolkit_name.clone() |
268 | } |
269 | |
270 | pub fn toolkit_version(&self) -> Option<String> { |
271 | self.data.toolkit_version.clone() |
272 | } |
273 | } |
274 | |
275 | pub trait ChangeHandler { |
276 | fn node_added(&mut self, node: &Node); |
277 | fn node_updated(&mut self, old_node: &DetachedNode, new_node: &Node); |
278 | fn focus_moved( |
279 | &mut self, |
280 | old_node: Option<&DetachedNode>, |
281 | new_node: Option<&Node>, |
282 | current_state: &State, |
283 | ); |
284 | /// The tree update process doesn't currently collect all possible information |
285 | /// about removed nodes. The following methods don't accurately reflect |
286 | /// the full state of the old node: |
287 | /// |
288 | /// * [`DetachedNode::name`] |
289 | /// * [`DetachedNode::live`] |
290 | /// * [`DetachedNode::supports_text_ranges`] |
291 | fn node_removed(&mut self, node: &DetachedNode, current_state: &State); |
292 | } |
293 | |
294 | pub struct Tree { |
295 | state: State, |
296 | } |
297 | |
298 | impl Tree { |
299 | pub fn new(mut initial_state: TreeUpdate, is_host_focused: bool) -> Self { |
300 | let mut state = State { |
301 | nodes: HashMap::new(), |
302 | data: initial_state.tree.take().unwrap(), |
303 | focus: initial_state.focus, |
304 | is_host_focused, |
305 | }; |
306 | state.update(initial_state, is_host_focused, None); |
307 | Self { state } |
308 | } |
309 | |
310 | pub fn update(&mut self, update: TreeUpdate) { |
311 | self.state.update(update, self.state.is_host_focused, None); |
312 | } |
313 | |
314 | pub fn update_and_process_changes( |
315 | &mut self, |
316 | update: TreeUpdate, |
317 | handler: &mut impl ChangeHandler, |
318 | ) { |
319 | let mut changes = InternalChanges::default(); |
320 | self.state |
321 | .update(update, self.state.is_host_focused, Some(&mut changes)); |
322 | self.process_changes(changes, handler); |
323 | } |
324 | |
325 | pub fn update_host_focus_state(&mut self, is_host_focused: bool) { |
326 | self.state.update_host_focus_state(is_host_focused, None); |
327 | } |
328 | |
329 | pub fn update_host_focus_state_and_process_changes( |
330 | &mut self, |
331 | is_host_focused: bool, |
332 | handler: &mut impl ChangeHandler, |
333 | ) { |
334 | let mut changes = InternalChanges::default(); |
335 | self.state |
336 | .update_host_focus_state(is_host_focused, Some(&mut changes)); |
337 | self.process_changes(changes, handler); |
338 | } |
339 | |
340 | fn process_changes(&self, changes: InternalChanges, handler: &mut impl ChangeHandler) { |
341 | for id in &changes.added_node_ids { |
342 | let node = self.state.node_by_id(*id).unwrap(); |
343 | handler.node_added(&node); |
344 | } |
345 | for (id, old_node) in &changes.updated_nodes { |
346 | let new_node = self.state.node_by_id(*id).unwrap(); |
347 | handler.node_updated(old_node, &new_node); |
348 | } |
349 | if let Some(focus_change) = changes.focus_change { |
350 | if let Some(old_node) = &focus_change.old_focus { |
351 | let id = old_node.id(); |
352 | if !changes.updated_nodes.contains_key(&id) |
353 | && !changes.removed_nodes.contains_key(&id) |
354 | { |
355 | if let Some(old_node_new_version) = self.state.node_by_id(id) { |
356 | handler.node_updated(old_node, &old_node_new_version); |
357 | } |
358 | } |
359 | } |
360 | let new_node = self.state.focus(); |
361 | if let Some(new_node) = new_node { |
362 | let id = new_node.id(); |
363 | if !changes.added_node_ids.contains(&id) && !changes.updated_nodes.contains_key(&id) |
364 | { |
365 | if let Some(new_node_old_version) = focus_change.new_focus_old_node { |
366 | handler.node_updated(&new_node_old_version, &new_node); |
367 | } |
368 | } |
369 | } |
370 | handler.focus_moved( |
371 | focus_change.old_focus.as_ref(), |
372 | new_node.as_ref(), |
373 | &self.state, |
374 | ); |
375 | } |
376 | for node in changes.removed_nodes.values() { |
377 | handler.node_removed(node, &self.state); |
378 | } |
379 | } |
380 | |
381 | pub fn state(&self) -> &State { |
382 | &self.state |
383 | } |
384 | } |
385 | |
386 | #[cfg (test)] |
387 | mod tests { |
388 | use accesskit::{NodeBuilder, NodeClassSet, NodeId, Role, Tree, TreeUpdate}; |
389 | |
390 | #[test ] |
391 | fn init_tree_with_root_node() { |
392 | let mut classes = NodeClassSet::new(); |
393 | let update = TreeUpdate { |
394 | nodes: vec![( |
395 | NodeId(0), |
396 | NodeBuilder::new(Role::Window).build(&mut classes), |
397 | )], |
398 | tree: Some(Tree::new(NodeId(0))), |
399 | focus: NodeId(0), |
400 | }; |
401 | let tree = super::Tree::new(update, false); |
402 | assert_eq!(NodeId(0), tree.state().root().id()); |
403 | assert_eq!(Role::Window, tree.state().root().role()); |
404 | assert!(tree.state().root().parent().is_none()); |
405 | } |
406 | |
407 | #[test ] |
408 | fn root_node_has_children() { |
409 | let mut classes = NodeClassSet::new(); |
410 | let update = TreeUpdate { |
411 | nodes: vec![ |
412 | (NodeId(0), { |
413 | let mut builder = NodeBuilder::new(Role::Window); |
414 | builder.set_children(vec![NodeId(1), NodeId(2)]); |
415 | builder.build(&mut classes) |
416 | }), |
417 | ( |
418 | NodeId(1), |
419 | NodeBuilder::new(Role::Button).build(&mut classes), |
420 | ), |
421 | ( |
422 | NodeId(2), |
423 | NodeBuilder::new(Role::Button).build(&mut classes), |
424 | ), |
425 | ], |
426 | tree: Some(Tree::new(NodeId(0))), |
427 | focus: NodeId(0), |
428 | }; |
429 | let tree = super::Tree::new(update, false); |
430 | let state = tree.state(); |
431 | assert_eq!( |
432 | NodeId(0), |
433 | state.node_by_id(NodeId(1)).unwrap().parent().unwrap().id() |
434 | ); |
435 | assert_eq!( |
436 | NodeId(0), |
437 | state.node_by_id(NodeId(2)).unwrap().parent().unwrap().id() |
438 | ); |
439 | assert_eq!(2, state.root().children().count()); |
440 | } |
441 | |
442 | #[test ] |
443 | fn add_child_to_root_node() { |
444 | let mut classes = NodeClassSet::new(); |
445 | let root_builder = NodeBuilder::new(Role::Window); |
446 | let first_update = TreeUpdate { |
447 | nodes: vec![(NodeId(0), root_builder.clone().build(&mut classes))], |
448 | tree: Some(Tree::new(NodeId(0))), |
449 | focus: NodeId(0), |
450 | }; |
451 | let mut tree = super::Tree::new(first_update, false); |
452 | assert_eq!(0, tree.state().root().children().count()); |
453 | let second_update = TreeUpdate { |
454 | nodes: vec![ |
455 | (NodeId(0), { |
456 | let mut builder = root_builder; |
457 | builder.push_child(NodeId(1)); |
458 | builder.build(&mut classes) |
459 | }), |
460 | ( |
461 | NodeId(1), |
462 | NodeBuilder::new(Role::RootWebArea).build(&mut classes), |
463 | ), |
464 | ], |
465 | tree: None, |
466 | focus: NodeId(0), |
467 | }; |
468 | struct Handler { |
469 | got_new_child_node: bool, |
470 | got_updated_root_node: bool, |
471 | } |
472 | fn unexpected_change() { |
473 | panic!("expected only new child node and updated root node" ); |
474 | } |
475 | impl super::ChangeHandler for Handler { |
476 | fn node_added(&mut self, node: &crate::Node) { |
477 | if node.id() == NodeId(1) { |
478 | self.got_new_child_node = true; |
479 | return; |
480 | } |
481 | unexpected_change(); |
482 | } |
483 | fn node_updated(&mut self, old_node: &crate::DetachedNode, new_node: &crate::Node) { |
484 | if new_node.id() == NodeId(0) |
485 | && old_node.data().children().is_empty() |
486 | && new_node.data().children() == [NodeId(1)] |
487 | { |
488 | self.got_updated_root_node = true; |
489 | return; |
490 | } |
491 | unexpected_change(); |
492 | } |
493 | fn focus_moved( |
494 | &mut self, |
495 | _old_node: Option<&crate::DetachedNode>, |
496 | _new_node: Option<&crate::Node>, |
497 | _current_state: &crate::TreeState, |
498 | ) { |
499 | unexpected_change(); |
500 | } |
501 | fn node_removed( |
502 | &mut self, |
503 | _node: &crate::DetachedNode, |
504 | _current_state: &crate::TreeState, |
505 | ) { |
506 | unexpected_change(); |
507 | } |
508 | } |
509 | let mut handler = Handler { |
510 | got_new_child_node: false, |
511 | got_updated_root_node: false, |
512 | }; |
513 | tree.update_and_process_changes(second_update, &mut handler); |
514 | assert!(handler.got_new_child_node); |
515 | assert!(handler.got_updated_root_node); |
516 | let state = tree.state(); |
517 | assert_eq!(1, state.root().children().count()); |
518 | assert_eq!(NodeId(1), state.root().children().next().unwrap().id()); |
519 | assert_eq!( |
520 | NodeId(0), |
521 | state.node_by_id(NodeId(1)).unwrap().parent().unwrap().id() |
522 | ); |
523 | } |
524 | |
525 | #[test ] |
526 | fn remove_child_from_root_node() { |
527 | let mut classes = NodeClassSet::new(); |
528 | let root_builder = NodeBuilder::new(Role::Window); |
529 | let first_update = TreeUpdate { |
530 | nodes: vec![ |
531 | (NodeId(0), { |
532 | let mut builder = root_builder.clone(); |
533 | builder.push_child(NodeId(1)); |
534 | builder.build(&mut classes) |
535 | }), |
536 | ( |
537 | NodeId(1), |
538 | NodeBuilder::new(Role::RootWebArea).build(&mut classes), |
539 | ), |
540 | ], |
541 | tree: Some(Tree::new(NodeId(0))), |
542 | focus: NodeId(0), |
543 | }; |
544 | let mut tree = super::Tree::new(first_update, false); |
545 | assert_eq!(1, tree.state().root().children().count()); |
546 | let second_update = TreeUpdate { |
547 | nodes: vec![(NodeId(0), root_builder.build(&mut classes))], |
548 | tree: None, |
549 | focus: NodeId(0), |
550 | }; |
551 | struct Handler { |
552 | got_updated_root_node: bool, |
553 | got_removed_child_node: bool, |
554 | } |
555 | fn unexpected_change() { |
556 | panic!("expected only removed child node and updated root node" ); |
557 | } |
558 | impl super::ChangeHandler for Handler { |
559 | fn node_added(&mut self, _node: &crate::Node) { |
560 | unexpected_change(); |
561 | } |
562 | fn node_updated(&mut self, old_node: &crate::DetachedNode, new_node: &crate::Node) { |
563 | if new_node.id() == NodeId(0) |
564 | && old_node.data().children() == [NodeId(1)] |
565 | && new_node.data().children().is_empty() |
566 | { |
567 | self.got_updated_root_node = true; |
568 | return; |
569 | } |
570 | unexpected_change(); |
571 | } |
572 | fn focus_moved( |
573 | &mut self, |
574 | _old_node: Option<&crate::DetachedNode>, |
575 | _new_node: Option<&crate::Node>, |
576 | _current_state: &crate::TreeState, |
577 | ) { |
578 | unexpected_change(); |
579 | } |
580 | fn node_removed( |
581 | &mut self, |
582 | node: &crate::DetachedNode, |
583 | _current_state: &crate::TreeState, |
584 | ) { |
585 | if node.id() == NodeId(1) { |
586 | self.got_removed_child_node = true; |
587 | return; |
588 | } |
589 | unexpected_change(); |
590 | } |
591 | } |
592 | let mut handler = Handler { |
593 | got_updated_root_node: false, |
594 | got_removed_child_node: false, |
595 | }; |
596 | tree.update_and_process_changes(second_update, &mut handler); |
597 | assert!(handler.got_updated_root_node); |
598 | assert!(handler.got_removed_child_node); |
599 | assert_eq!(0, tree.state().root().children().count()); |
600 | assert!(tree.state().node_by_id(NodeId(1)).is_none()); |
601 | } |
602 | |
603 | #[test ] |
604 | fn move_focus_between_siblings() { |
605 | let mut classes = NodeClassSet::new(); |
606 | let first_update = TreeUpdate { |
607 | nodes: vec![ |
608 | (NodeId(0), { |
609 | let mut builder = NodeBuilder::new(Role::Window); |
610 | builder.set_children(vec![NodeId(1), NodeId(2)]); |
611 | builder.build(&mut classes) |
612 | }), |
613 | ( |
614 | NodeId(1), |
615 | NodeBuilder::new(Role::Button).build(&mut classes), |
616 | ), |
617 | ( |
618 | NodeId(2), |
619 | NodeBuilder::new(Role::Button).build(&mut classes), |
620 | ), |
621 | ], |
622 | tree: Some(Tree::new(NodeId(0))), |
623 | focus: NodeId(1), |
624 | }; |
625 | let mut tree = super::Tree::new(first_update, true); |
626 | assert!(tree.state().node_by_id(NodeId(1)).unwrap().is_focused()); |
627 | let second_update = TreeUpdate { |
628 | nodes: vec![], |
629 | tree: None, |
630 | focus: NodeId(2), |
631 | }; |
632 | struct Handler { |
633 | got_old_focus_node_update: bool, |
634 | got_new_focus_node_update: bool, |
635 | got_focus_change: bool, |
636 | } |
637 | fn unexpected_change() { |
638 | panic!("expected only focus change" ); |
639 | } |
640 | impl super::ChangeHandler for Handler { |
641 | fn node_added(&mut self, _node: &crate::Node) { |
642 | unexpected_change(); |
643 | } |
644 | fn node_updated(&mut self, old_node: &crate::DetachedNode, new_node: &crate::Node) { |
645 | if old_node.id() == NodeId(1) |
646 | && new_node.id() == NodeId(1) |
647 | && old_node.is_focused() |
648 | && !new_node.is_focused() |
649 | { |
650 | self.got_old_focus_node_update = true; |
651 | return; |
652 | } |
653 | if old_node.id() == NodeId(2) |
654 | && new_node.id() == NodeId(2) |
655 | && !old_node.is_focused() |
656 | && new_node.is_focused() |
657 | { |
658 | self.got_new_focus_node_update = true; |
659 | return; |
660 | } |
661 | unexpected_change(); |
662 | } |
663 | fn focus_moved( |
664 | &mut self, |
665 | old_node: Option<&crate::DetachedNode>, |
666 | new_node: Option<&crate::Node>, |
667 | _current_state: &crate::TreeState, |
668 | ) { |
669 | if let (Some(old_node), Some(new_node)) = (old_node, new_node) { |
670 | if old_node.id() == NodeId(1) && new_node.id() == NodeId(2) { |
671 | self.got_focus_change = true; |
672 | return; |
673 | } |
674 | } |
675 | unexpected_change(); |
676 | } |
677 | fn node_removed( |
678 | &mut self, |
679 | _node: &crate::DetachedNode, |
680 | _current_state: &crate::TreeState, |
681 | ) { |
682 | unexpected_change(); |
683 | } |
684 | } |
685 | let mut handler = Handler { |
686 | got_old_focus_node_update: false, |
687 | got_new_focus_node_update: false, |
688 | got_focus_change: false, |
689 | }; |
690 | tree.update_and_process_changes(second_update, &mut handler); |
691 | assert!(handler.got_old_focus_node_update); |
692 | assert!(handler.got_new_focus_node_update); |
693 | assert!(handler.got_focus_change); |
694 | assert!(tree.state().node_by_id(NodeId(2)).unwrap().is_focused()); |
695 | assert!(!tree.state().node_by_id(NodeId(1)).unwrap().is_focused()); |
696 | } |
697 | |
698 | #[test ] |
699 | fn update_node() { |
700 | let mut classes = NodeClassSet::new(); |
701 | let child_builder = NodeBuilder::new(Role::Button); |
702 | let first_update = TreeUpdate { |
703 | nodes: vec![ |
704 | (NodeId(0), { |
705 | let mut builder = NodeBuilder::new(Role::Window); |
706 | builder.set_children(vec![NodeId(1)]); |
707 | builder.build(&mut classes) |
708 | }), |
709 | (NodeId(1), { |
710 | let mut builder = child_builder.clone(); |
711 | builder.set_name("foo" ); |
712 | builder.build(&mut classes) |
713 | }), |
714 | ], |
715 | tree: Some(Tree::new(NodeId(0))), |
716 | focus: NodeId(0), |
717 | }; |
718 | let mut tree = super::Tree::new(first_update, false); |
719 | assert_eq!( |
720 | Some("foo" .into()), |
721 | tree.state().node_by_id(NodeId(1)).unwrap().name() |
722 | ); |
723 | let second_update = TreeUpdate { |
724 | nodes: vec![(NodeId(1), { |
725 | let mut builder = child_builder; |
726 | builder.set_name("bar" ); |
727 | builder.build(&mut classes) |
728 | })], |
729 | tree: None, |
730 | focus: NodeId(0), |
731 | }; |
732 | struct Handler { |
733 | got_updated_child_node: bool, |
734 | } |
735 | fn unexpected_change() { |
736 | panic!("expected only updated child node" ); |
737 | } |
738 | impl super::ChangeHandler for Handler { |
739 | fn node_added(&mut self, _node: &crate::Node) { |
740 | unexpected_change(); |
741 | } |
742 | fn node_updated(&mut self, old_node: &crate::DetachedNode, new_node: &crate::Node) { |
743 | if new_node.id() == NodeId(1) |
744 | && old_node.name() == Some("foo" .into()) |
745 | && new_node.name() == Some("bar" .into()) |
746 | { |
747 | self.got_updated_child_node = true; |
748 | return; |
749 | } |
750 | unexpected_change(); |
751 | } |
752 | fn focus_moved( |
753 | &mut self, |
754 | _old_node: Option<&crate::DetachedNode>, |
755 | _new_node: Option<&crate::Node>, |
756 | _current_state: &crate::TreeState, |
757 | ) { |
758 | unexpected_change(); |
759 | } |
760 | fn node_removed( |
761 | &mut self, |
762 | _node: &crate::DetachedNode, |
763 | _current_state: &crate::TreeState, |
764 | ) { |
765 | unexpected_change(); |
766 | } |
767 | } |
768 | let mut handler = Handler { |
769 | got_updated_child_node: false, |
770 | }; |
771 | tree.update_and_process_changes(second_update, &mut handler); |
772 | assert!(handler.got_updated_child_node); |
773 | assert_eq!( |
774 | Some("bar" .into()), |
775 | tree.state().node_by_id(NodeId(1)).unwrap().name() |
776 | ); |
777 | } |
778 | } |
779 | |