gtk4/
tree_store.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{translate::*, Type, Value};
4use libc::c_int;
5
6use crate::{ffi, prelude::*, TreeIter, TreeModel, TreeStore};
7
8impl TreeStore {
9    /// Creates a new tree store.
10    ///
11    /// The tree store will have @n_columns, with each column using the
12    /// corresponding type passed to this function.
13    ///
14    /// Note that only types derived from standard GObject fundamental types
15    /// are supported.
16    ///
17    /// As an example:
18    ///
19    /// **⚠️ The following code is in c ⚠️**
20    ///
21    /// ```c
22    /// gtk_tree_store_new (3, G_TYPE_INT, G_TYPE_STRING, GDK_TYPE_TEXTURE);
23    /// ```
24    ///
25    /// will create a new [`TreeStore`][crate::TreeStore] with three columns of type
26    /// `int`, `gchararray`, and [`gdk::Texture`][crate::gdk::Texture] respectively.
27    ///
28    /// # Deprecated since 4.10
29    ///
30    /// Use [`TreeListModel`][crate::TreeListModel] instead
31    ///
32    /// # Returns
33    ///
34    /// a new [`TreeStore`][crate::TreeStore]
35    #[doc(alias = "gtk_tree_store_newv")]
36    #[doc(alias = "gtk_tree_store_new")]
37    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
38    #[allow(deprecated)]
39    pub fn new(column_types: &[Type]) -> Self {
40        assert_initialized_main_thread!();
41        unsafe {
42            let mut column_types = column_types
43                .iter()
44                .map(|t| t.into_glib())
45                .collect::<Vec<_>>();
46            from_glib_full(ffi::gtk_tree_store_newv(
47                column_types.len() as c_int,
48                column_types.as_mut_ptr(),
49            ))
50        }
51    }
52
53    /// A variant of gtk_tree_store_insert_with_values() which takes
54    /// the columns and values as two arrays, instead of varargs.
55    ///
56    /// This function is mainly intended for language bindings.
57    ///
58    /// # Deprecated since 4.10
59    ///
60    /// Use [`TreeListModel`][crate::TreeListModel] instead
61    /// ## `parent`
62    /// A valid [`TreeIter`][crate::TreeIter]
63    /// ## `position`
64    /// position to insert the new row, or -1 for last
65    /// ## `columns`
66    /// an array of column numbers
67    /// ## `values`
68    /// an array of GValues
69    ///
70    /// # Returns
71    ///
72    ///
73    /// ## `iter`
74    /// An unset [`TreeIter`][crate::TreeIter] to set the new row
75    #[doc(alias = "gtk_tree_store_insert_with_values")]
76    #[doc(alias = "gtk_tree_store_insert_with_valuesv")]
77    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
78    #[allow(deprecated)]
79    pub fn insert_with_values(
80        &self,
81        parent: Option<&TreeIter>,
82        position: Option<u32>,
83        columns_and_values: &[(u32, &dyn ToValue)],
84    ) -> TreeIter {
85        unsafe {
86            assert!(
87                position.unwrap_or(0) <= i32::MAX as u32,
88                "can't have more than {} rows",
89                i32::MAX
90            );
91            let n_columns =
92                ffi::gtk_tree_model_get_n_columns(self.upcast_ref::<TreeModel>().to_glib_none().0)
93                    as u32;
94            assert!(
95                columns_and_values.len() <= n_columns as usize,
96                "got values for {} columns but only {n_columns} columns exist",
97                columns_and_values.len(),
98            );
99            for (column, value) in columns_and_values {
100                assert!(
101                    *column < n_columns,
102                    "got column {column} which is higher than the number of columns {n_columns}",
103                );
104                let type_ = from_glib(ffi::gtk_tree_model_get_column_type(
105                    self.upcast_ref::<TreeModel>().to_glib_none().0,
106                    *column as c_int,
107                ));
108                assert!(
109                    Value::type_transformable(value.value_type(), type_),
110                    "column {column} is of type {} but found value of type {type_}",
111                    value.value_type()
112                );
113            }
114
115            let columns = columns_and_values
116                .iter()
117                .map(|(c, _)| *c)
118                .collect::<Vec<_>>();
119            let values = columns_and_values
120                .iter()
121                .map(|(_, v)| v.to_value())
122                .collect::<Vec<_>>();
123
124            let mut iter = TreeIter::uninitialized();
125            ffi::gtk_tree_store_insert_with_valuesv(
126                self.to_glib_none().0,
127                iter.to_glib_none_mut().0,
128                mut_override(parent.to_glib_none().0),
129                position.map_or(-1, |n| n as c_int),
130                mut_override(columns.as_ptr() as *const c_int),
131                mut_override(values.as_ptr() as *const glib::gobject_ffi::GValue),
132                columns.len() as c_int,
133            );
134            iter
135        }
136    }
137
138    /// Reorders the children of @parent in @self to follow the order
139    /// indicated by @new_order.
140    ///
141    /// Note that this function only works with unsorted stores.
142    ///
143    /// # Deprecated since 4.10
144    ///
145    /// Use [`TreeListModel`][crate::TreeListModel] instead
146    /// ## `parent`
147    /// the parent of the children to re-order
148    /// ## `new_order`
149    /// an array of integers mapping the new position
150    ///   of each child to its old position before the re-ordering,
151    ///   i.e. `new_order[newpos] = oldpos`
152    #[doc(alias = "gtk_tree_store_reorder")]
153    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
154    #[allow(deprecated)]
155    pub fn reorder(&self, parent: &TreeIter, new_order: &[u32]) {
156        unsafe {
157            let count = ffi::gtk_tree_model_iter_n_children(
158                self.upcast_ref::<TreeModel>().to_glib_none().0,
159                mut_override(parent.to_glib_none().0),
160            );
161            let safe_count = count as usize == new_order.len();
162            debug_assert!(
163                safe_count,
164                "Incorrect `new_order` slice length. Expected `{count}`, found `{}`.",
165                new_order.len()
166            );
167            let safe_values = new_order.iter().max().map_or(true, |&max| {
168                let max = max as i32;
169                max >= 0 && max < count
170            });
171            debug_assert!(
172                safe_values,
173                "Some `new_order` slice values are out of range. Maximum safe value: \
174                 `{}`. The slice contents: `{new_order:?}`",
175                count - 1,
176            );
177            if safe_count && safe_values {
178                ffi::gtk_tree_store_reorder(
179                    self.to_glib_none().0,
180                    mut_override(parent.to_glib_none().0),
181                    mut_override(new_order.as_ptr() as *const c_int),
182                );
183            }
184        }
185    }
186
187    /// Sets the value of one or more cells in the row referenced by @iter.
188    ///
189    /// The variable argument list should contain integer column numbers,
190    /// each column number followed by the value to be set.
191    ///
192    /// The list is terminated by a value of `-1`.
193    ///
194    /// For example, to set column 0 with type `G_TYPE_STRING` to “Foo”, you would
195    /// write
196    ///
197    /// **⚠️ The following code is in c ⚠️**
198    ///
199    /// ```c
200    /// gtk_tree_store_set (store, iter, 0, "Foo", -1);
201    /// ```
202    ///
203    /// The value will be referenced by the store if it is a `G_TYPE_OBJECT`, and it
204    /// will be copied if it is a `G_TYPE_STRING` or `G_TYPE_BOXED`.
205    ///
206    /// # Deprecated since 4.10
207    ///
208    /// Use [`TreeListModel`][crate::TreeListModel] instead
209    /// ## `iter`
210    /// A valid [`TreeIter`][crate::TreeIter] for the row being modified
211    #[doc(alias = "gtk_tree_store_set")]
212    #[doc(alias = "gtk_tree_store_set_valuesv")]
213    #[doc(alias = "gtk_tree_store_set_valist")]
214    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
215    #[allow(deprecated)]
216    pub fn set(&self, iter: &TreeIter, columns_and_values: &[(u32, &dyn ToValue)]) {
217        unsafe {
218            let n_columns =
219                ffi::gtk_tree_model_get_n_columns(self.upcast_ref::<TreeModel>().to_glib_none().0)
220                    as u32;
221            assert!(
222                columns_and_values.len() <= n_columns as usize,
223                "got values for {} columns but only {n_columns} columns exist",
224                columns_and_values.len(),
225            );
226            for (column, value) in columns_and_values {
227                assert!(
228                    *column < n_columns,
229                    "got column {column} which is higher than the number of columns {n_columns}",
230                );
231                let type_ = from_glib(ffi::gtk_tree_model_get_column_type(
232                    self.upcast_ref::<TreeModel>().to_glib_none().0,
233                    *column as c_int,
234                ));
235                assert!(
236                    Value::type_transformable(value.value_type(), type_),
237                    "column {column} is of type {type_} but found value of type {}",
238                    value.value_type()
239                );
240            }
241
242            let columns = columns_and_values
243                .iter()
244                .map(|(c, _)| *c)
245                .collect::<Vec<_>>();
246            let values = columns_and_values
247                .iter()
248                .map(|(_, v)| v.to_value())
249                .collect::<Vec<_>>();
250
251            ffi::gtk_tree_store_set_valuesv(
252                self.to_glib_none().0,
253                mut_override(iter.to_glib_none().0),
254                mut_override(columns.as_ptr() as *const c_int),
255                mut_override(values.as_ptr() as *const glib::gobject_ffi::GValue),
256                columns.len() as c_int,
257            );
258        }
259    }
260
261    /// Sets the type of the columns in a tree store.
262    ///
263    /// This function is meant primarily for types that inherit from
264    /// [`TreeStore`][crate::TreeStore], and should only be used when constructing a new
265    /// [`TreeStore`][crate::TreeStore].
266    ///
267    /// This functions cannot be called after a row has been added,
268    /// or a method on the [`TreeModel`][crate::TreeModel] interface is called on the
269    /// tree store.
270    ///
271    /// # Deprecated since 4.10
272    ///
273    /// Use [`TreeListModel`][crate::TreeListModel] instead
274    /// ## `types`
275    /// An array of `GType` types, one for each column
276    #[doc(alias = "gtk_tree_store_set_column_types")]
277    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
278    #[allow(deprecated)]
279    pub fn set_column_types(&self, types: &[glib::Type]) {
280        unsafe {
281            let types_ptr: Vec<glib::ffi::GType> = types.iter().map(|t| t.into_glib()).collect();
282            ffi::gtk_tree_store_set_column_types(
283                self.to_glib_none().0,
284                types.len() as i32,
285                mut_override(types_ptr.as_ptr()),
286            )
287        }
288    }
289
290    /// Sets the data in the cell specified by @iter and @column.
291    ///
292    /// The type of @value must be convertible to the type of the
293    /// column.
294    ///
295    /// # Deprecated since 4.10
296    ///
297    /// Use [`TreeListModel`][crate::TreeListModel] instead
298    /// ## `iter`
299    /// A valid [`TreeIter`][crate::TreeIter] for the row being modified
300    /// ## `column`
301    /// column number to modify
302    /// ## `value`
303    /// new value for the cell
304    #[doc(alias = "gtk_tree_store_set_value")]
305    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
306    #[allow(deprecated)]
307    pub fn set_value(&self, iter: &TreeIter, column: u32, value: &Value) {
308        unsafe {
309            let columns =
310                ffi::gtk_tree_model_get_n_columns(self.upcast_ref::<TreeModel>().to_glib_none().0)
311                    as u32;
312            assert!(
313                column < columns,
314                "got column {column} which is higher than the number of columns {columns}",
315            );
316
317            let type_ = from_glib(ffi::gtk_tree_model_get_column_type(
318                self.upcast_ref::<TreeModel>().to_glib_none().0,
319                column as c_int,
320            ));
321            assert!(
322                Value::type_transformable(value.type_(), type_),
323                "column {column} is of type {type_} but found value of type {}",
324                value.type_()
325            );
326
327            ffi::gtk_tree_store_set_value(
328                self.to_glib_none().0,
329                mut_override(iter.to_glib_none().0),
330                column as c_int,
331                mut_override(value.to_glib_none().0),
332            );
333        }
334    }
335}