I was playing around a bit with the simple To-Do app here.
First, in the setup_tasks()
method for the window, I added a sorter to show the tasks ordered by their content label:
fn setup_tasks(&self) {
// Create new model
let model = gio::ListStore::new::<TaskObject>();
// Get state and set model
self.imp().tasks.replace(Some(model));
let sorter = CustomSorter::new(move |obj1, obj2| {
let task_object_1 = obj1
.downcast_ref::<TaskObject>()
.expect("The object needs to be of type TaskObject");
let task_object_2 = obj2
.downcast_ref::<TaskObject>()
.expect("The object needs to be of type TaskObject");
let content_1 = task_object_1.content();
let content_2 = task_object_2.content();
content_1.cmp(&content_2).into()
});
let sort_model = SortListModel::new(Some(self.tasks()), Some(sorter.clone()));
let selection_model = NoSelection::new(Some(sort_model));
self.imp().tasks_list.set_model(Some(&selection_model));
}
I also added a remove_button
to each task row to remove an item from the tasks list.
I also modified the call to the factory.connect_bind()
method to bind an action to the remove_button
:
// Tell factory how to bind `TaskRow` to a `TaskObject`
factory.connect_bind(clone!(
#[weak(rename_to = window)]
self,
move |_, list_item| {
// Get `TaskObject` from `ListItem`
let task_object = list_item
.downcast_ref::<ListItem>()
.expect("Needs to be ListItem")
.item()
.and_downcast::<TaskObject>()
.expect("The item has to be an `TaskObject`.");
// Get `TaskRow` from `ListItem`
let task_row = list_item
.downcast_ref::<ListItem>()
.expect("Needs to be ListItem")
.child()
.and_downcast::<TaskRow>()
.expect("The child has to be a `TaskRow`.");
task_row.bind(&task_object);
let list_item = list_item
.downcast_ref::<ListItem>()
.expect("Needs to be ListItem");
task_row.imp().remove_button.connect_clicked(clone!(
#[weak]
list_item,
move |_| {
let position = list_item.position();
window.remove_task(position);
}
));
The remove_task(position)
method is defined as follows:
impl Window {
// ...
fn remove_task(&self, position: u32) {
println!("remove task at position {}", position);
let tasks = self.tasks();
tasks.remove(position);
}
// ...
The problem is that the position
I define in the line
let position = list_item.position();
is the position of the item as it is shown on screen, whereas
tasks.remove(position)
removes the item at position
in the list store, which is different.
For example, if I add tasks labeled 1
and 0
(in that order) and then I try to delete the uppermost item (labeled 0
because they are ordered by their labels), it removes the item I added first instead.
I understand why that is happening, but I’m not sure how I get access the correct index in the list store, or if it is possible to remove an item “directly”, not via it’s index. I couldn’t solve it by searching the docs. I’m grateful for any kind of help.