Skip to main content

gtk4/
tree_store.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{Type, Value, translate::*};
4use libc::c_int;
5
6use crate::{TreeIter, TreeModel, TreeStore, ffi, prelude::*};
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().is_none_or(|&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    /// , you would
188    /// write
189    ///
190    /// **⚠️ The following code is in c ⚠️**
191    ///
192    /// ```c
193    /// gtk_tree_store_set (store, iter, 0, "Foo", -1);
194    /// ```
195    ///
196    /// The value will be referenced by the store if it is a `G_TYPE_OBJECT`, and it
197    /// will be copied if it is a `G_TYPE_STRING` or `G_TYPE_BOXED`.
198    ///
199    /// # Deprecated since 4.10
200    ///
201    /// Use [`TreeListModel`][crate::TreeListModel] instead
202    /// ## `iter`
203    /// A valid [`TreeIter`][crate::TreeIter] for the row being modified
204    #[doc(alias = "gtk_tree_store_set")]
205    #[doc(alias = "gtk_tree_store_set_valuesv")]
206    #[doc(alias = "gtk_tree_store_set_valist")]
207    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
208    #[allow(deprecated)]
209    pub fn set(&self, iter: &TreeIter, columns_and_values: &[(u32, &dyn ToValue)]) {
210        unsafe {
211            let n_columns =
212                ffi::gtk_tree_model_get_n_columns(self.upcast_ref::<TreeModel>().to_glib_none().0)
213                    as u32;
214            assert!(
215                columns_and_values.len() <= n_columns as usize,
216                "got values for {} columns but only {n_columns} columns exist",
217                columns_and_values.len(),
218            );
219            for (column, value) in columns_and_values {
220                assert!(
221                    *column < n_columns,
222                    "got column {column} which is higher than the number of columns {n_columns}",
223                );
224                let type_ = from_glib(ffi::gtk_tree_model_get_column_type(
225                    self.upcast_ref::<TreeModel>().to_glib_none().0,
226                    *column as c_int,
227                ));
228                assert!(
229                    Value::type_transformable(value.value_type(), type_),
230                    "column {column} is of type {type_} but found value of type {}",
231                    value.value_type()
232                );
233            }
234
235            let columns = columns_and_values
236                .iter()
237                .map(|(c, _)| *c)
238                .collect::<Vec<_>>();
239            let values = columns_and_values
240                .iter()
241                .map(|(_, v)| v.to_value())
242                .collect::<Vec<_>>();
243
244            ffi::gtk_tree_store_set_valuesv(
245                self.to_glib_none().0,
246                mut_override(iter.to_glib_none().0),
247                mut_override(columns.as_ptr() as *const c_int),
248                mut_override(values.as_ptr() as *const glib::gobject_ffi::GValue),
249                columns.len() as c_int,
250            );
251        }
252    }
253
254    /// Sets the type of the columns in a tree store.
255    ///
256    /// This function is meant primarily for types that inherit from
257    /// [`TreeStore`][crate::TreeStore], and should only be used when constructing a new
258    /// [`TreeStore`][crate::TreeStore].
259    ///
260    /// This functions cannot be called after a row has been added,
261    /// or a method on the [`TreeModel`][crate::TreeModel] interface is called on the
262    /// tree store.
263    ///
264    /// # Deprecated since 4.10
265    ///
266    /// Use [`TreeListModel`][crate::TreeListModel] instead
267    /// ## `types`
268    /// An array of `GType` types, one for each column
269    #[doc(alias = "gtk_tree_store_set_column_types")]
270    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
271    #[allow(deprecated)]
272    pub fn set_column_types(&self, types: &[glib::Type]) {
273        unsafe {
274            let types_ptr: Vec<glib::ffi::GType> = types.iter().map(|t| t.into_glib()).collect();
275            ffi::gtk_tree_store_set_column_types(
276                self.to_glib_none().0,
277                types.len() as i32,
278                mut_override(types_ptr.as_ptr()),
279            )
280        }
281    }
282
283    /// Sets the data in the cell specified by @iter and @column.
284    ///
285    /// The type of @value must be convertible to the type of the
286    /// column.
287    ///
288    /// # Deprecated since 4.10
289    ///
290    /// Use [`TreeListModel`][crate::TreeListModel] instead
291    /// ## `iter`
292    /// A valid [`TreeIter`][crate::TreeIter] for the row being modified
293    /// ## `column`
294    /// column number to modify
295    /// ## `value`
296    /// new value for the cell
297    #[doc(alias = "gtk_tree_store_set_value")]
298    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
299    #[allow(deprecated)]
300    pub fn set_value(&self, iter: &TreeIter, column: u32, value: &Value) {
301        unsafe {
302            let columns =
303                ffi::gtk_tree_model_get_n_columns(self.upcast_ref::<TreeModel>().to_glib_none().0)
304                    as u32;
305            assert!(
306                column < columns,
307                "got column {column} which is higher than the number of columns {columns}",
308            );
309
310            let type_ = from_glib(ffi::gtk_tree_model_get_column_type(
311                self.upcast_ref::<TreeModel>().to_glib_none().0,
312                column as c_int,
313            ));
314            assert!(
315                Value::type_transformable(value.type_(), type_),
316                "column {column} is of type {type_} but found value of type {}",
317                value.type_()
318            );
319
320            ffi::gtk_tree_store_set_value(
321                self.to_glib_none().0,
322                mut_override(iter.to_glib_none().0),
323                column as c_int,
324                mut_override(value.to_glib_none().0),
325            );
326        }
327    }
328}