mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 10:20:32 -06:00
fix(comments): previews lift a stamp whatever its replies' locks; Delete greys out over a locked reply
The locked-reply check in delete_annotation also reached stamp_preview and signature_image, which only take the annotation off a copy to draw the page beneath it: an unlocked stamp with a locked reply lost its drag preview. They now use lift_annotation, which checks no locks. The Comments panel's Delete (comment and reply menus) and the page's context menu are greyed out while a reply below is locked (comments::locked_below), rather than refusing after the click. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
72edd945e5
commit
28a31aebc0
@@ -70,11 +70,23 @@ pub(crate) fn touch(d: &mut Dict, meta: &Meta) {
|
||||
}
|
||||
|
||||
/// Delete a comment together with its pop-up and its replies (and theirs), as Acrobat does.
|
||||
/// Refused while it, or a reply that would go with it, is locked.
|
||||
pub fn delete_annotation(doc: &mut Document, page: usize, index: usize) -> Result<(), AnnotError> {
|
||||
remove_with_replies(doc, page, index, true)
|
||||
}
|
||||
|
||||
/// Take the annotation at `(page, index)` out of its page with its pop-up and replies, as
|
||||
/// [`delete_annotation`] does but whatever their locks: for drawing the page beneath it on a
|
||||
/// copy of the document (a stamp or signature being dragged), which changes nothing.
|
||||
pub fn lift_annotation(doc: &mut Document, page: usize, index: usize) -> Result<(), AnnotError> {
|
||||
remove_with_replies(doc, page, index, false)
|
||||
}
|
||||
|
||||
fn remove_with_replies(doc: &mut Document, page: usize, index: usize, check_locks: bool) -> Result<(), AnnotError> {
|
||||
let p = page_ref(doc, page)?;
|
||||
let list = annots(doc, p);
|
||||
let target = list.get(index).cloned().ok_or(AnnotError::NoSuchAnnotation { page, index })?;
|
||||
if let Some(r) = target.as_ref() {
|
||||
if check_locks && let Some(r) = target.as_ref() {
|
||||
unlocked(doc, r)?;
|
||||
}
|
||||
// An inline comment has no reference to collect; the pop-up it names still goes.
|
||||
@@ -82,12 +94,14 @@ pub fn delete_annotation(doc: &mut Document, page: usize, index: usize) -> Resul
|
||||
let doomed = with_replies_and_popups(doc, &list, seed);
|
||||
// A locked reply can't be deleted on its own, so it doesn't go with the comment or reply it
|
||||
// answers either. Pop-ups follow their comment.
|
||||
for (_, e) in list.iter().enumerate().filter(|(i, e)| *i != index && goes_with(e, &doomed)) {
|
||||
let obj = doc.resolve(e);
|
||||
if let Some(d) = obj.as_dict().filter(|d| d.name(b"Subtype") != Some(b"Popup".as_slice()))
|
||||
&& annotation_flags(doc, d) & FLAG_LOCKED != 0
|
||||
{
|
||||
return Err(AnnotError::Invalid("a reply to it is locked".into()));
|
||||
if check_locks {
|
||||
for (_, e) in list.iter().enumerate().filter(|(i, e)| *i != index && goes_with(e, &doomed)) {
|
||||
let obj = doc.resolve(e);
|
||||
if let Some(d) = obj.as_dict().filter(|d| d.name(b"Subtype") != Some(b"Popup".as_slice()))
|
||||
&& annotation_flags(doc, d) & FLAG_LOCKED != 0
|
||||
{
|
||||
return Err(AnnotError::Invalid("a reply to it is locked".into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
let kept: Vec<Object> = list.into_iter().enumerate().filter(|(i, e)| *i != index && !goes_with(e, &doomed)).map(|(_, e)| e).collect();
|
||||
|
||||
Reference in New Issue
Block a user