Skip to main content

gtk/
tree_store.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::TreeIter;
4use crate::TreeModel;
5use crate::TreeStore;
6use glib::object::{Cast, IsA};
7use glib::translate::*;
8use glib::{ToValue, Type, Value};
9use libc::c_int;
10
11impl TreeStore {
12    /// Creates a new tree store as with `n_columns` columns each of the types passed
13    /// in. Note that only types derived from standard GObject fundamental types
14    /// are supported.
15    ///
16    /// As an example, `gtk_tree_store_new (3, G_TYPE_INT, G_TYPE_STRING,
17    /// GDK_TYPE_PIXBUF);` will create a new [`TreeStore`][crate::TreeStore] with three columns, of type
18    /// `gint`, `gchararray`, and [`gdk_pixbuf::Pixbuf`][crate::gdk_pixbuf::Pixbuf] respectively.
19    /// ## `n_columns`
20    /// number of columns in the tree store
21    ///
22    /// # Returns
23    ///
24    /// a new [`TreeStore`][crate::TreeStore]
25    #[doc(alias = "gtk_tree_store_newv")]
26    pub fn new(column_types: &[Type]) -> TreeStore {
27        assert_initialized_main_thread!();
28        unsafe {
29            let mut column_types = column_types
30                .iter()
31                .map(|t| t.into_glib())
32                .collect::<Vec<_>>();
33            from_glib_full(ffi::gtk_tree_store_newv(
34                column_types.len() as c_int,
35                column_types.as_mut_ptr(),
36            ))
37        }
38    }
39}
40
41mod sealed {
42    pub trait Sealed {}
43    impl<T: glib::IsA<crate::TreeStore>> Sealed for T {}
44}
45
46pub trait TreeStoreExtManual: IsA<TreeStore> + sealed::Sealed + 'static {
47    #[doc(alias = "gtk_tree_store_insert_with_valuesv")]
48    fn insert_with_values(
49        &self,
50        parent: Option<&TreeIter>,
51        position: Option<u32>,
52        columns_and_values: &[(u32, &dyn ToValue)],
53    ) -> TreeIter {
54        unsafe {
55            assert!(
56                position.unwrap_or(0) <= i32::max_value() as u32,
57                "can't have more than {} rows",
58                i32::max_value()
59            );
60            let n_columns = ffi::gtk_tree_model_get_n_columns(
61                self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
62            ) as u32;
63            assert!(
64                columns_and_values.len() <= n_columns as usize,
65                "got values for {} columns but only {n_columns} columns exist",
66                columns_and_values.len(),
67            );
68            for (column, value) in columns_and_values {
69                assert!(
70                    *column < n_columns,
71                    "got column {} which is higher than the number of columns {n_columns}",
72                    *column,
73                );
74                let type_ = from_glib(ffi::gtk_tree_model_get_column_type(
75                    self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
76                    *column as c_int,
77                ));
78                assert!(
79                    Value::type_transformable(value.value_type(), type_),
80                    "column {} is of type {type_} but found value of type {}",
81                    *column,
82                    value.value_type()
83                );
84            }
85
86            let columns = columns_and_values
87                .iter()
88                .map(|(c, _)| *c)
89                .collect::<Vec<_>>();
90            let values = columns_and_values
91                .iter()
92                .map(|(_, v)| v.to_value())
93                .collect::<Vec<_>>();
94
95            let mut iter = TreeIter::uninitialized();
96            ffi::gtk_tree_store_insert_with_valuesv(
97                self.as_ref().to_glib_none().0,
98                iter.to_glib_none_mut().0,
99                mut_override(parent.to_glib_none().0),
100                position.map_or(-1, |n| n as c_int),
101                mut_override(columns.as_ptr() as *const c_int),
102                mut_override(values.as_ptr() as *const glib::gobject_ffi::GValue),
103                columns.len() as c_int,
104            );
105            iter
106        }
107    }
108
109    /// Reorders the children of `parent` in `self` to follow the order
110    /// indicated by `new_order`. Note that this function only works with
111    /// unsorted stores.
112    /// ## `parent`
113    /// A [`TreeIter`][crate::TreeIter], or [`None`]
114    /// ## `new_order`
115    /// an array of integers mapping the new position of each child
116    ///  to its old position before the re-ordering,
117    ///  i.e. `new_order``[newpos] = oldpos`.
118    #[doc(alias = "gtk_tree_store_reorder")]
119    fn reorder(&self, parent: &TreeIter, new_order: &[u32]) {
120        unsafe {
121            let count = ffi::gtk_tree_model_iter_n_children(
122                self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
123                mut_override(parent.to_glib_none().0),
124            );
125            let safe_count = count as usize == new_order.len();
126            debug_assert!(
127                safe_count,
128                "Incorrect `new_order` slice length. Expected `{count}`, found `{}`.",
129                new_order.len()
130            );
131            let safe_values = new_order.iter().max().map_or(true, |&max| {
132                let max = max as i32;
133                max >= 0 && max < count
134            });
135            debug_assert!(
136                safe_values,
137                "Some `new_order` slice values are out of range. Maximum safe value: \
138                 `{}`. The slice contents: `{new_order:?}`",
139                count - 1,
140            );
141            if safe_count && safe_values {
142                ffi::gtk_tree_store_reorder(
143                    self.as_ref().to_glib_none().0,
144                    mut_override(parent.to_glib_none().0),
145                    mut_override(new_order.as_ptr() as *const c_int),
146                );
147            }
148        }
149    }
150
151    /// Sets the value of one or more cells in the row referenced by `iter`.
152    /// The variable argument list should contain integer column numbers,
153    /// each column number followed by the value to be set.
154    /// The list is terminated by a -1. For example, to set column 0 with type
155    /// `G_TYPE_STRING` to “Foo”, you would write
156    /// `gtk_tree_store_set (store, iter, 0, "Foo", -1)`.
157    ///
158    /// The value will be referenced by the store if it is a `G_TYPE_OBJECT`, and it
159    /// will be copied if it is a `G_TYPE_STRING` or `G_TYPE_BOXED`.
160    /// ## `iter`
161    /// A valid [`TreeIter`][crate::TreeIter] for the row being modified
162    #[doc(alias = "gtk_tree_store_set")]
163    #[doc(alias = "gtk_tree_store_set_valuesv")]
164    fn set(&self, iter: &TreeIter, columns_and_values: &[(u32, &dyn ToValue)]) {
165        unsafe {
166            let n_columns = ffi::gtk_tree_model_get_n_columns(
167                self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
168            ) as u32;
169            assert!(
170                columns_and_values.len() <= n_columns as usize,
171                "got values for {} columns but only {} columns exist",
172                columns_and_values.len(),
173                n_columns
174            );
175            for (column, value) in columns_and_values {
176                assert!(
177                    *column < n_columns,
178                    "got column {} which is higher than the number of columns {n_columns}",
179                    *column,
180                );
181                let type_ = from_glib(ffi::gtk_tree_model_get_column_type(
182                    self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
183                    *column as c_int,
184                ));
185                assert!(
186                    Value::type_transformable(value.value_type(), type_),
187                    "column {} is of type {type_} but found value of type {}",
188                    *column,
189                    value.value_type()
190                );
191            }
192
193            let columns = columns_and_values
194                .iter()
195                .map(|(c, _)| *c)
196                .collect::<Vec<_>>();
197            let values = columns_and_values
198                .iter()
199                .map(|(_, v)| v.to_value())
200                .collect::<Vec<_>>();
201
202            ffi::gtk_tree_store_set_valuesv(
203                self.as_ref().to_glib_none().0,
204                mut_override(iter.to_glib_none().0),
205                mut_override(columns.as_ptr() as *const c_int),
206                mut_override(values.as_ptr() as *const glib::gobject_ffi::GValue),
207                columns.len() as c_int,
208            );
209        }
210    }
211
212    /// Sets the data in the cell specified by `iter` and `column`.
213    /// The type of `value` must be convertible to the type of the
214    /// column.
215    /// ## `iter`
216    /// A valid [`TreeIter`][crate::TreeIter] for the row being modified
217    /// ## `column`
218    /// column number to modify
219    /// ## `value`
220    /// new value for the cell
221    #[doc(alias = "gtk_tree_store_set_value")]
222    fn set_value(&self, iter: &TreeIter, column: u32, value: &Value) {
223        unsafe {
224            let columns = ffi::gtk_tree_model_get_n_columns(
225                self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
226            ) as u32;
227            assert!(
228                column < columns,
229                "got column {column} which is higher than the number of columns {columns}",
230            );
231
232            let type_ = from_glib(ffi::gtk_tree_model_get_column_type(
233                self.as_ref().upcast_ref::<TreeModel>().to_glib_none().0,
234                column as c_int,
235            ));
236            assert!(
237                Value::type_transformable(value.type_(), type_),
238                "column {column} is of type {type_} but found value of type {}",
239                value.type_()
240            );
241
242            ffi::gtk_tree_store_set_value(
243                self.as_ref().to_glib_none().0,
244                mut_override(iter.to_glib_none().0),
245                column as c_int,
246                mut_override(value.to_glib_none().0),
247            );
248        }
249    }
250}
251
252impl<O: IsA<TreeStore>> TreeStoreExtManual for O {}