1use std::ptr;
2
3use crate::action::{PdfAction, PdfActionLike};
4use crate::action_goto::PdfActionGoTo;
5use crate::action_url::PdfActionUrl;
6use crate::destination::PdfDestination;
7use crate::error::Result;
8use crate::ffi;
9use crate::handle::ObjectHandle;
10use crate::util::{option_c_string, take_string};
11
12#[derive(Debug, Clone)]
13pub struct PdfOutline {
14 handle: ObjectHandle,
15}
16
17impl PdfOutline {
18 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
19 Self { handle }
20 }
21
22 pub fn new() -> Result<Self> {
23 let mut out_outline = ptr::null_mut();
24 let mut out_error = ptr::null_mut();
25 let status = unsafe { ffi::pdf_outline_new(&mut out_outline, &mut out_error) };
26 crate::util::status_result(status, out_error)?;
27 Ok(Self::from_handle(crate::util::required_handle(
28 out_outline,
29 "PDFOutline",
30 )?))
31 }
32
33 #[must_use]
34 pub fn label(&self) -> Option<String> {
35 take_string(unsafe { ffi::pdf_outline_label_string(self.handle.as_ptr()) })
36 }
37
38 pub fn set_label(&self, value: Option<&str>) -> Result<()> {
39 let value = option_c_string(value)?;
40 let mut out_error = ptr::null_mut();
41 let status = unsafe {
42 ffi::pdf_outline_set_label(
43 self.handle.as_ptr(),
44 value.as_ref().map_or(ptr::null(), |value| value.as_ptr()),
45 &mut out_error,
46 )
47 };
48 crate::util::status_result(status, out_error)
49 }
50
51 #[must_use]
52 pub fn child_count(&self) -> usize {
53 unsafe { ffi::pdf_outline_child_count(self.handle.as_ptr()) as usize }
54 }
55
56 #[must_use]
57 pub fn child(&self, index: usize) -> Option<Self> {
58 let ptr = unsafe { ffi::pdf_outline_child_at(self.handle.as_ptr(), index as u64) };
59 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Self::from_handle)
60 }
61
62 #[must_use]
63 pub fn children(&self) -> Vec<Self> {
64 (0..self.child_count())
65 .filter_map(|index| self.child(index))
66 .collect()
67 }
68
69 pub fn insert_child(&self, child: &Self, index: usize) -> Result<()> {
70 let mut out_error = ptr::null_mut();
71 let status = unsafe {
72 ffi::pdf_outline_insert_child(
73 self.handle.as_ptr(),
74 child.handle.as_ptr(),
75 index as u64,
76 &mut out_error,
77 )
78 };
79 crate::util::status_result(status, out_error)
80 }
81
82 pub fn remove_from_parent(&self) {
83 unsafe { ffi::pdf_outline_remove_from_parent(self.handle.as_ptr()) };
84 }
85
86 #[must_use]
87 pub fn index(&self) -> usize {
88 unsafe { ffi::pdf_outline_index(self.handle.as_ptr()) as usize }
89 }
90
91 #[must_use]
92 pub fn is_open(&self) -> bool {
93 unsafe { ffi::pdf_outline_is_open(self.handle.as_ptr()) != 0 }
94 }
95
96 pub fn set_open(&self, value: bool) {
97 unsafe { ffi::pdf_outline_set_open(self.handle.as_ptr(), i32::from(value)) };
98 }
99
100 #[must_use]
101 pub fn destination(&self) -> Option<PdfDestination> {
102 let ptr = unsafe { ffi::pdf_outline_destination(self.handle.as_ptr()) };
103 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfDestination::from_handle)
104 }
105
106 pub fn set_destination(&self, destination: Option<&PdfDestination>) -> Result<()> {
107 let mut out_error = ptr::null_mut();
108 let status = unsafe {
109 ffi::pdf_outline_set_destination(
110 self.handle.as_ptr(),
111 destination.map_or(ptr::null_mut(), PdfDestination::as_handle_ptr),
112 &mut out_error,
113 )
114 };
115 crate::util::status_result(status, out_error)
116 }
117
118 #[must_use]
119 pub fn action(&self) -> Option<PdfAction> {
120 let ptr = unsafe { ffi::pdf_outline_action(self.handle.as_ptr()) };
121 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfAction::from_handle)
122 }
123
124 pub fn set_action<A: PdfActionLike>(&self, action: Option<&A>) -> Result<()> {
125 let mut out_error = ptr::null_mut();
126 let status = unsafe {
127 ffi::pdf_outline_set_action(
128 self.handle.as_ptr(),
129 action.map_or(ptr::null_mut(), PdfActionLike::as_action_handle_ptr),
130 &mut out_error,
131 )
132 };
133 crate::util::status_result(status, out_error)
134 }
135
136 pub fn clear_action(&self) -> Result<()> {
137 self.set_action::<PdfAction>(None)
138 }
139
140 #[must_use]
141 pub fn action_url(&self) -> Option<PdfActionUrl> {
142 let ptr = unsafe { ffi::pdf_outline_action_url(self.handle.as_ptr()) };
143 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfActionUrl::from_handle)
144 }
145
146 pub fn set_action_url(&self, action: Option<&PdfActionUrl>) -> Result<()> {
147 self.set_action(action)
148 }
149
150 #[must_use]
151 pub fn action_goto(&self) -> Option<PdfActionGoTo> {
152 let ptr = unsafe { ffi::pdf_outline_action_goto(self.handle.as_ptr()) };
153 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfActionGoTo::from_handle)
154 }
155
156 pub fn set_action_goto(&self, action: Option<&PdfActionGoTo>) -> Result<()> {
157 self.set_action(action)
158 }
159
160 #[must_use]
161 pub fn parent(&self) -> Option<Self> {
162 let ptr = unsafe { ffi::pdf_outline_parent(self.handle.as_ptr()) };
163 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Self::from_handle)
164 }
165
166 pub(crate) fn as_handle_ptr(&self) -> *mut core::ffi::c_void {
167 self.handle.as_ptr()
168 }
169}