Skip to content

Commit

Permalink
switch most things over from HierarchySelection to TreeSelection
Browse files Browse the repository at this point in the history
  • Loading branch information
misson20000 committed Sep 19, 2023
1 parent 689056b commit a32b1f9
Show file tree
Hide file tree
Showing 9 changed files with 507 additions and 152 deletions.
4 changes: 2 additions & 2 deletions src/model/selection/listing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub enum Change {
SelectAll,
ConvertToStructure,
ConvertToAddress,
AssignFromHierarchy(sync::Arc<super::HierarchySelection>),
AssignFromTree(sync::Arc<super::TreeSelection>),
AssignStructure(StructureRange),
AssignAddress(addr::Extent),
UnionStructure(StructureRange),
Expand Down Expand Up @@ -161,7 +161,7 @@ impl versioned::Change<Selection> for Change {
Mode::Address(addr::unit::UNBOUNDED),
},
Change::AssignFromHierarchy(sync::Arc<super::HierarchySelection>) => todo!(),
Change::AssignFromTree(sync::Arc<super::TreeSelection>) => todo!(),
*/
};

Expand Down
181 changes: 178 additions & 3 deletions src/model/selection/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,32 @@ impl Selection {
child_index: None,
}
}


/// Returns whether or not the node at the specified path is selected.
pub fn path_selected(&self, path: structure::PathSlice) -> bool {
self.root.path_selected(path)
}

/// Returns whether or not the root node is selected. Equivalent to calling `path_selected(&[])`.
pub fn root_selected(&self) -> bool {
self.root.self_selected
}

/// Returns true if the selection is not completely empty.
pub fn any_selected(&self) -> bool {
self.root.any_selected(&self.document.root)
}

/// If only one node is selected, returns the path to it.
pub fn single_selected(&self) -> Option<structure::Path> {
self.root.single_selected(&self.document.root, vec![])
}

/// If a contiguous range of siblings within a single node (and either none or all of their grandchildren) are selected, return their common parent and the start and end (inclusive) indices of the range of siblings.
pub fn siblings_selected(&self) -> Option<(structure::Path, usize, usize)> {
self.root.siblings_selected(&self.document.root, vec![])
}

fn update_document(&mut self, new_doc: &sync::Arc<document::Document>) -> ChangeRecord {
if self.document.is_outdated(new_doc) {
let from_generation = self.document.generation();
Expand Down Expand Up @@ -110,8 +135,22 @@ impl Selection {
}
}

fn port_doc_change(&mut self, _new_doc: &sync::Arc<document::Document>, _change: &doc_change::Change) -> bool {
todo!();
fn port_doc_change(&mut self, new_doc: &sync::Arc<document::Document>, change: &doc_change::Change) -> bool {
self.document = new_doc.clone();

match change.ty {
doc_change::ChangeType::AlterNode { .. } => false,

_ => {
// TODO: actually handle structural changes
self.root = SparseNode {
self_selected: false,
children_selected: ChildrenMode::None,
};

true
}
}
}
}

Expand Down Expand Up @@ -521,6 +560,142 @@ impl SparseNode {
}
}
}

fn path_selected(&self, remaining_path: structure::PathSlice) -> bool {
if remaining_path.len() == 0 {
self.self_selected
} else {
match &self.children_selected {
ChildrenMode::None => false,
ChildrenMode::Mixed(vec) => vec[remaining_path[0]].path_selected(&remaining_path[1..]),
ChildrenMode::AllDirect if remaining_path.len() == 1 => true,
ChildrenMode::AllDirect => false,
ChildrenMode::AllGrandchildren => true,
}
}
}

fn any_selected(&self, node: &structure::Node) -> bool {
self.self_selected || match &self.children_selected {
ChildrenMode::None => false,
ChildrenMode::Mixed(vec) => vec.iter().zip(node.children.iter()).any(|(sp, st)| sp.any_selected(&st.node)),
ChildrenMode::AllDirect => node.children.len() > 0,
ChildrenMode::AllGrandchildren => node.children.len() > 0,
}
}

fn none_selected(&self, node: &structure::Node) -> bool {
!self.any_selected(node)
}

fn single_selected(&self, node: &structure::Node, mut path: structure::Path) -> Option<structure::Path> {
match (self.self_selected, &self.children_selected) {
(true, ChildrenMode::None) => Some(path),
(true, _) if node.children.len() == 0 => Some(path),

(false, ChildrenMode::AllDirect) if node.children.len() == 1 => {
path.push(0);
Some(path)
},

(false, ChildrenMode::AllGrandchildren) if node.children.len() == 1 && node.children[0].node.children.len() == 0 => {
path.push(0);
Some(path)
},

(false, ChildrenMode::Mixed(vec)) => {
let mut single_found = None;
for (i, (sparse_child, struct_child)) in vec.iter().zip(node.children.iter()).enumerate() {
if sparse_child.self_selected || sparse_child.descendants_maybe_selected(&struct_child.node) {
if single_found.is_some() {
/* More than one child was selected. */
return None;
} else {
single_found = Some((i, sparse_child, &struct_child.node));
}
}
}

single_found.and_then(|(i, sparse_child, struct_child)| {
path.push(i);
sparse_child.single_selected(struct_child, path)
})
},

_ => None,
}
}

fn siblings_selected(&self, node: &structure::Node, mut path: structure::Path) -> Option<(structure::Path, usize, usize)> {
if self.self_selected {
None
} else {
match &self.children_selected {
ChildrenMode::None => None,
ChildrenMode::Mixed(vec) => {
let mut start = None;
let mut end = None;

for (i, (sparse_child, struct_child)) in vec.iter().zip(node.children.iter()).enumerate() {
match start {
None => {
if !sparse_child.self_selected && sparse_child.descendants_maybe_selected(&struct_child.node) {
path.push(i);
return sparse_child.siblings_selected(&struct_child.node, path);
}

if sparse_child.self_selected {
if !match &sparse_child.children_selected {
/* Is this sparse child suitable for being part of a sibling range? */
ChildrenMode::None => true,
ChildrenMode::Mixed(_) => false,
ChildrenMode::AllDirect => false,
ChildrenMode::AllGrandchildren => true,
} {
return None;
}

start = Some((i, sparse_child.children_selected.is_all_grandchildren()));
}
},
Some((_, all_grandchildren)) => {
/* If we think we've already found the end of the range, we need to make sure nothing beyond that end is selected. */
if end.is_some() {
if sparse_child.self_selected || sparse_child.descendants_maybe_selected(&struct_child.node) {
return None;
} else {
continue;
}
}

if sparse_child.self_selected {
/* Is this sparse child suitable for being part of the sibling range we already started? */
if !match &sparse_child.children_selected {
ChildrenMode::None => !all_grandchildren,
ChildrenMode::Mixed(_) => false,
ChildrenMode::AllDirect => false,
ChildrenMode::AllGrandchildren => all_grandchildren || struct_child.node.children.len() == 0,
} {
return None;
}
} else if !sparse_child.any_selected(&struct_child.node) {
/* Not selected, and none of its children are. Must be the end. */
end = Some(i-1);
} else {
/* Not selected, but some children were, so invalid. */
return None;
}
},
}
}

start.map(|(begin, _)| (path, begin, end.unwrap_or(node.children.len()-1)))
},
ChildrenMode::AllDirect => Some((path, 0, node.children.len()-1)),
ChildrenMode::AllGrandchildren => Some((path, 0, node.children.len()-1)),
}
}
}
}

impl ChildrenMode {
Expand Down
33 changes: 10 additions & 23 deletions src/view/action/delete_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ use crate::view::window;

struct DeleteNodeAction {
document_host: sync::Arc<document::DocumentHost>,
selection_host: sync::Arc<selection::hierarchy::Host>,
selection: cell::RefCell<sync::Arc<selection::HierarchySelection>>,
selection_host: sync::Arc<selection::tree::Host>,
selection: cell::RefCell<sync::Arc<selection::TreeSelection>>,

subscriber: once_cell::unsync::OnceCell<helpers::AsyncSubscriber>,
}

pub fn create_action(window_context: &window::WindowContext) -> gio::SimpleAction {
let selection = window_context.hierarchy_selection_host.get();
let selection = window_context.tree_selection_host.get();

let action_impl = rc::Rc::new(DeleteNodeAction {
document_host: window_context.document_host.clone(),
selection_host: window_context.hierarchy_selection_host.clone(),
selection_host: window_context.tree_selection_host.clone(),
selection: cell::RefCell::new(selection.clone()),
subscriber: Default::default(),
});
Expand All @@ -41,30 +41,17 @@ pub fn create_action(window_context: &window::WindowContext) -> gio::SimpleActio
action
}

fn update_enabled(action: &gio::SimpleAction, selection: &selection::HierarchySelection) {
action.set_enabled(match &selection.mode {
selection::hierarchy::Mode::Empty => false,
selection::hierarchy::Mode::Single(path) => !path.is_empty(),
selection::hierarchy::Mode::SiblingRange(_, _, _) => true,
selection::hierarchy::Mode::All => false,
});
fn update_enabled(action: &gio::SimpleAction, selection: &selection::TreeSelection) {
action.set_enabled(selection.any_selected() && !selection.root_selected());
}

impl DeleteNodeAction {
fn activate(&self) {
let selection = self.selection.borrow();

let (parent, first_sibling, last_sibling) = match &selection.mode {
selection::hierarchy::Mode::Empty => return,
selection::hierarchy::Mode::Single(path) if !path.is_empty() => (&path[0..path.len()-1], *path.last().unwrap(), *path.last().unwrap()),
selection::hierarchy::Mode::SiblingRange(path, begin, end) => (&path[..], *begin, *end),
selection::hierarchy::Mode::All | selection::hierarchy::Mode::Single(_) => {
// TODO: find a way to issue a warning for this
return;
}
};
//let selection = self.selection.borrow();

todo!();

// TODO: failure feedback
let _ = self.document_host.change(selection.document.delete_range(parent.to_vec(), first_sibling, last_sibling));
//let _ = self.document_host.change(selection.document.delete_range(parent.to_vec(), first_sibling, last_sibling));
}
}
66 changes: 29 additions & 37 deletions src/view/action/destructure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,70 +7,62 @@ use gtk::glib::clone;
use gtk::gio;

use crate::model::document;
use crate::model::document::structure;
use crate::model::selection;
use crate::view::helpers;
use crate::view::window;

struct DestructureAction {
document_host: sync::Arc<document::DocumentHost>,
selection_host: sync::Arc<selection::hierarchy::Host>,
selection: cell::RefCell<sync::Arc<selection::HierarchySelection>>,
selection_host: sync::Arc<selection::tree::Host>,
path: cell::RefCell<(sync::Arc<selection::TreeSelection>, Option<structure::Path>)>,
window: rc::Weak<window::CharmWindow>,

subscriber: once_cell::unsync::OnceCell<helpers::AsyncSubscriber>,
}

pub fn create_action(window_context: &window::WindowContext) -> gio::SimpleAction {
let selection = window_context.hierarchy_selection_host.get();
let selection = window_context.tree_selection_host.get();

let action_impl = rc::Rc::new(DestructureAction {
document_host: window_context.document_host.clone(),
selection_host: window_context.hierarchy_selection_host.clone(),
selection: cell::RefCell::new(selection.clone()),
selection_host: window_context.tree_selection_host.clone(),
path: cell::RefCell::new((selection.clone(), selection.single_selected())),
window: window_context.window.clone(),
subscriber: Default::default(),
});

let action = helpers::create_simple_action_strong(action_impl.clone(), "destructure", |action| action.activate());

update_enabled(&action, &selection);
action.set_enabled(action_impl.enabled());

action_impl.subscriber.set(helpers::subscribe_to_updates(rc::Rc::downgrade(&action_impl), action_impl.selection_host.clone(), selection, clone!(@weak action => move |action_impl, selection| {
*action_impl.selection.borrow_mut() = selection.clone();
update_enabled(&action, selection);
action_impl.update_path(selection.clone());
action.set_enabled(action_impl.enabled());
}))).unwrap();

action
}

fn update_enabled(action: &gio::SimpleAction, selection: &selection::HierarchySelection) {
action.set_enabled(match &selection.mode {
selection::hierarchy::Mode::Empty => false,
selection::hierarchy::Mode::Single(path) => !path.is_empty(),
selection::hierarchy::Mode::SiblingRange(_, _, _) => false,
selection::hierarchy::Mode::All => false,
});
}

impl DestructureAction {
impl DestructureAction {
fn enabled(&self) -> bool {
self.path.borrow().1.as_ref().map_or(false, |path| path.len() > 0)
}

fn update_path(&self, selection: sync::Arc<selection::TreeSelection>) {
let single = selection.single_selected();
*self.path.borrow_mut() = (selection, single);
}

fn activate(&self) {
let selection = self.selection.borrow();

let path = match &selection.mode {
selection::hierarchy::Mode::Single(path) if !path.is_empty() => path,
_ => {
// TODO: find a way to issue a warning for this
return;
}
};

let _ = match self.document_host.change(selection.document.destructure(path).unwrap()) {
Ok(new_doc) => new_doc,
Err(e) => {
// TODO: better failure feedback
println!("failed to change document: {:?}", e);
return;
}
};
if let (selection, Some(path)) = &*self.path.borrow() {
let _ = match self.document_host.change(selection.document.destructure(path).unwrap()) {
Ok(new_doc) => new_doc,
Err(e) => {
// TODO: better failure feedback
println!("failed to change document: {:?}", e);
return;
}
};
}
}
}
Loading

0 comments on commit a32b1f9

Please sign in to comment.