mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-08 15:21:26 +00:00
Merge pull request #5921 from Hamza0101/fix/find-replace-respects-group-lock
Find and Replace: type inside a locked or hidden group is left alone (#5900)
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
//! commands of the Edit menu (Find and Replace, Find Next, Paste without Formatting).
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_doc::{CharStyle, Document, Justify, NodeId, NodeKind, Quotes, TextKind, TextObject, TextRun};
|
||||
use vectorcraft_doc::{CharStyle, Document, Justify, LockedArtboards, Node, NodeId, NodeKind, Quotes, TextKind, TextObject, TextRun};
|
||||
use vectorcraft_geom::{Affine, Rect, shapes};
|
||||
|
||||
use super::typecmd::refresh_bounds;
|
||||
@@ -650,15 +650,24 @@ pub(crate) fn find_all(hay: &str, needle: &str, match_case: bool, whole_word: bo
|
||||
out
|
||||
}
|
||||
|
||||
/// The text objects Find and Replace and Find Next reach: on visible, unlocked layers, and not
|
||||
/// inside a hidden or locked group, which hides or locks what it holds as a layer does (#5900).
|
||||
fn all_texts(d: &Document) -> Vec<NodeId> {
|
||||
fn visit(n: &Node, locks: &LockedArtboards<'_>, v: &mut Vec<NodeId>) {
|
||||
if !n.visible || n.locked {
|
||||
return;
|
||||
}
|
||||
if matches!(n.kind, NodeKind::Text(_)) && !locks.holds_id(n.id) {
|
||||
v.push(n.id);
|
||||
}
|
||||
for c in n.children().into_iter().flatten() {
|
||||
visit(c, locks, v);
|
||||
}
|
||||
}
|
||||
let mut v = vec![];
|
||||
let locks = d.locked_artboards();
|
||||
for l in d.layers.iter().filter(|l| l.visible && !l.locked) {
|
||||
l.walk(&mut |n| {
|
||||
if matches!(n.kind, NodeKind::Text(_)) && n.visible && !n.locked && !locks.holds_id(n.id) {
|
||||
v.push(n.id);
|
||||
}
|
||||
});
|
||||
for l in &d.layers {
|
||||
visit(l, &locks, &mut v);
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
@@ -2017,6 +2017,32 @@ fn find_and_replace_that_changes_nothing_records_no_undo_step() {
|
||||
assert_eq!((history(&s), plain(&s, a)), ((before.0 + 1, 0, true), "dog dog".to_string()));
|
||||
}
|
||||
|
||||
/// Find and Replace with no ids leaves the type inside a locked or hidden group as it is, however
|
||||
/// deep, as it does for type locked or hidden itself or by its layer (#5900). Find Next skips it
|
||||
/// too. Unlocked and shown again, the group's type is found and replaced.
|
||||
#[test]
|
||||
fn find_and_replace_leaves_type_in_a_locked_or_hidden_group() {
|
||||
for prop in ["locked", "hidden"] {
|
||||
let mut s = session();
|
||||
let free = text(&mut s, "Audit cat");
|
||||
let inner = text(&mut s, "Audit cat");
|
||||
sel(&mut s, &[inner]);
|
||||
let g = id_of(&s.execute("object.group", &json!({})).unwrap());
|
||||
sel(&mut s, &[g]);
|
||||
let outer = id_of(&s.execute("object.group", &json!({})).unwrap());
|
||||
let props = |on: bool| if prop == "locked" { json!({"id": outer.0, "locked": on}) } else { json!({"id": outer.0, "visible": !on}) };
|
||||
s.execute("object.setProps", &props(true)).unwrap();
|
||||
assert!(node(&s, inner).visible && !node(&s, inner).locked, "{prop}: the type itself is shown and unlocked");
|
||||
let r = s.execute("edit.findReplace", &json!({"find": "cat", "replace": "dog"})).unwrap();
|
||||
assert_eq!((r["count"].as_u64(), plain(&s, free), plain(&s, inner)), (Some(1), "Audit dog".to_string(), "Audit cat".to_string()), "{prop}");
|
||||
s.execute("select.none", &json!({})).unwrap();
|
||||
assert!(s.execute("edit.findNext", &json!({"find": "cat"})).unwrap()["id"].is_null(), "{prop}: Find Next skips it");
|
||||
s.execute("object.setProps", &props(false)).unwrap();
|
||||
let r = s.execute("edit.findReplace", &json!({"find": "cat", "replace": "dog"})).unwrap();
|
||||
assert_eq!((r["count"].as_u64(), plain(&s, inner)), (Some(1), "Audit dog".to_string()), "{prop}: once the group is {prop} no more");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn find_next_cycles_through_text_objects() {
|
||||
let mut s = session();
|
||||
|
||||
Reference in New Issue
Block a user