mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-07 02:51:33 +00:00
Form controls: the object commands leave a locked control on a protected sheet alone
control.format and control.assign refused to change a locked control on a protected sheet, but object.move, object.delete, object.setAnchorMode, arrange.bringForward, arrange.sendBackward and arrange.align changed it all the same. They now refuse it with the same message; an unlocked control still moves, and other kinds of objects are unchanged.
This commit is contained in:
1 parent
0fb3ea7a68
commit
14dee9155d
4 files changed
+50
-1
No files matched your search
@@ -8,7 +8,9 @@
|
||||
//! else made asks before it runs anything.
|
||||
|
||||
use gridcraft_core::CellRef;
|
||||
use gridcraft_model::{Anchor, AnchorMode, CONTROL_MAX, ControlAction, ControlKind, FormControl, MAX_MACRO_NAME, MacroInput, Sheet, Workbook};
|
||||
use gridcraft_model::{
|
||||
Anchor, AnchorMode, CONTROL_MAX, ControlAction, ControlKind, FormControl, MAX_MACRO_NAME, MacroInput, ObjKind, Sheet, Workbook,
|
||||
};
|
||||
use serde_json::{Value as Json, json};
|
||||
|
||||
use super::{
|
||||
@@ -298,6 +300,20 @@ fn find(s: &Session, cmd: &str, p: &Json) -> Result<(usize, usize, FormControl)>
|
||||
}
|
||||
|
||||
/// Drawing objects on a protected sheet can't be changed while they are locked.
|
||||
/// For the object commands (`object.move`, `object.delete`, `object.setAnchorMode`, `arrange.*`,
|
||||
/// `arrange.align`): refuses to change form controls `ids` on `sheet` when one is locked and the
|
||||
/// sheet is protected, as `control.format` and `control.assign` do. Other kinds pass.
|
||||
pub(crate) fn check_objects_unlocked(s: &Session, sheet: usize, kind: ObjKind, ids: &[u32]) -> Result<()> {
|
||||
if kind != ObjKind::Control {
|
||||
return Ok(());
|
||||
}
|
||||
let Some(sh) = s.doc()?.wb.sheet(sheet) else { return Ok(()) };
|
||||
if sh.is_protected() && sh.controls.iter().any(|c| c.locked && ids.contains(&c.id)) {
|
||||
return Err(EngineError::Other(PROTECTED.into()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_unlocked(s: &Session, sheet: usize, c: &FormControl) -> Result<()> {
|
||||
if c.locked && s.doc()?.wb.sheet(sheet).is_some_and(Sheet::is_protected) {
|
||||
return Err(EngineError::Other(PROTECTED.into()));
|
||||
|
||||
@@ -36,6 +36,9 @@ pub(super) fn arrange(s: &mut Session, p: &Json, forward: bool) -> Result<Json>
|
||||
let kind = str_param(p, "kind").unwrap_or("shape").to_string();
|
||||
let extreme = bool_param(p, "toFront").or(bool_param(p, "toBack")).unwrap_or(false);
|
||||
let si = s.doc()?.wb.active_sheet();
|
||||
if let Some(k) = gridcraft_model::ObjKind::parse(&kind) {
|
||||
crate::cmd::controls::check_objects_unlocked(s, si, k, &[id])?;
|
||||
}
|
||||
fn reorder<T>(v: &mut Vec<T>, i: usize, forward: bool, extreme: bool) {
|
||||
if i >= v.len() {
|
||||
return;
|
||||
@@ -125,6 +128,9 @@ pub(super) fn align(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
p.get("ids").and_then(Json::as_array).map(|a| a.iter().filter_map(|v| v.as_u64().map(|x| x as u32)).collect()).unwrap_or_default();
|
||||
let how = str_param(p, "align").unwrap_or("left").to_string();
|
||||
let si = s.doc()?.wb.active_sheet();
|
||||
if let Some(k) = gridcraft_model::ObjKind::parse(&kind) {
|
||||
crate::cmd::controls::check_objects_unlocked(s, si, k, &ids)?;
|
||||
}
|
||||
edit(s, |cx| {
|
||||
let sheet = cx.sheet_mut(si)?;
|
||||
let geo: Vec<(u32, f64, f64, f32, f32)> = {
|
||||
|
||||
@@ -1187,6 +1187,8 @@ fn object_param(s: &Session, p: &Json, cmd: &str) -> Result<(usize, ObjRef)> {
|
||||
if !d.wb.sheet(sheet).is_some_and(|sh| sh.has_object(o)) {
|
||||
return Err(bad(cmd, "no such object"));
|
||||
}
|
||||
// A locked form control on a protected sheet stays as it is.
|
||||
super::controls::check_objects_unlocked(s, sheet, kind, &[id])?;
|
||||
Ok((sheet, o))
|
||||
}
|
||||
|
||||
|
||||
@@ -335,6 +335,31 @@ fn links_follow_inserts_deletes_renames_and_cut_moves() {
|
||||
assert_eq!((link(&s, 0, local), link(&s, 0, remote)), ("$G$9".to_string(), "Inputs!$A$1".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_object_commands_leave_a_locked_control_on_a_protected_sheet_alone() {
|
||||
let mut s = s();
|
||||
let locked = id(&s.execute("insert.slider", json!({"at": "D2", "link": "B1"})).unwrap());
|
||||
let other = id(&s.execute("insert.spinButton", json!({"at": "D8"})).unwrap());
|
||||
let free = id(&s.execute("insert.button", json!({"at": "D12"})).unwrap());
|
||||
s.execute("control.format", json!({"id": free, "locked": false})).unwrap();
|
||||
s.execute("review.protectSheet", json!({})).unwrap();
|
||||
let before = s.doc().unwrap().wb.clone();
|
||||
for (cmd, p) in [
|
||||
("object.move", json!({"kind": "control", "id": locked, "at": "H9"})),
|
||||
("object.delete", json!({"kind": "control", "id": locked})),
|
||||
("object.setAnchorMode", json!({"kind": "control", "id": locked, "mode": "absolute"})),
|
||||
("arrange.bringForward", json!({"kind": "control", "id": locked, "toFront": true})),
|
||||
("arrange.sendBackward", json!({"kind": "control", "id": locked})),
|
||||
("arrange.align", json!({"kind": "control", "ids": [locked, other], "align": "left"})),
|
||||
] {
|
||||
assert!(err(s.execute(cmd, p)).contains("protected"), "{cmd}");
|
||||
}
|
||||
assert!(std::sync::Arc::ptr_eq(&s.doc().unwrap().wb, &before), "nothing changed");
|
||||
// An unlocked control still moves, as in Excel.
|
||||
s.execute("object.move", json!({"kind": "control", "id": free, "at": "H12"})).unwrap();
|
||||
assert_eq!(control(&s, free).anchor.cell.a1(), "H12");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_locked_control_on_a_protected_sheet_cannot_be_changed() {
|
||||
let mut s = s();
|
||||
|
||||
Reference in new issue
Block a user