1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Automatic gtk::ListStore struct derive for Rust.
//!
//! # Example
//!
//! ```
//! use gtk::prelude::*;
//!
//! use gladis::Gladis;
//! use gtk_liststore_item::ListStoreItem;
//!
//! const GLADE_SRC: &str = r#"
//! <?xml version="1.0" encoding="UTF-8"?>
//! <!-- Generated with glade 3.22.2 -->
//! <interface>
//!   <requires lib="gtk+" version="3.20"/>
//!   <object class="GtkListStore" id="list_store">
//!     <columns>
//!       <!-- column-name name -->
//!       <column type="gchararray"/>
//!       <!-- column-name value -->
//!       <column type="guint"/>
//!     </columns>
//!   </object>
//! </interface>
//! "#;
//!
//! #[derive(Gladis)]
//! struct Glade {
//!     list_store: gtk::ListStore,
//! }
//!
//! #[derive(ListStoreItem)]
//! struct Item {
//!     name: String,
//!     value: u32,
//! }
//!
//! fn main() {
//!     gtk::init().unwrap();
//!
//!     let glade = Glade::from_string(GLADE_SRC).unwrap();
//!
//!     let item = Item { name: "foobar".into(), value: 42 };
//!     item.insert_into_liststore(glade.list_store);
//! }
//! ```

use gtk::prelude::*;

/// A trait to ease interraction with a [ListStore](gtk::ListStore) using an intermediate struct.
///
/// If we want to interact with a table defined this way:
///
/// | number | name  | type         |
/// |--------|-------|--------------|
/// | 0      | name  | `gchararray` |
/// | 1      | value | `guint32`    |
///
/// We can create a struct that represent the columns in the order that they appear, and then
/// implement this trait to interact with the table's entries.
///
/// # Automatic implementation
/// ```
/// use gtk::prelude::*;
/// use gtk_liststore_item::ListStoreItem;
///
/// #[derive(ListStoreItem)]
/// struct Item {
///     name: String,
///     value: u32,
/// }
/// ```
///
/// # Manual implementation
/// ```
/// use gtk::prelude::*;
/// use gtk_liststore_item::ListStoreItem;
///
/// struct Item {
///     name: String,
///     value: u32,
/// }
///
/// impl ListStoreItem for Item {
///     fn from_liststore_iter<S>(list_store: S, iter: &gtk::TreeIter) -> Option<Self>
///         where S: TreeModelExt
///     {
///         Some(Item {
///             name: list_store.get_value(&iter, 0).get::<String>().ok()??,
///             value: list_store.get_value(&iter, 1).get::<u32>().ok()??,
///         })
///     }
///
///     // from_liststore_path is already implemented to call from_liststore_iter
///
///     fn insert_into_liststore<S>(&self, list_store: S) -> gtk::TreeIter
///         where S: GtkListStoreExtManual
///     {
///         list_store.insert_with_values(
///             None,
///             &[0, 1],
///             &[&self.name, &self.value])
///     }
/// }
/// ```
pub trait ListStoreItem {
    fn from_liststore_iter<S>(list_store: S, iter: &gtk::TreeIter) -> Option<Self>
    where
        S: TreeModelExt,
        Self: std::marker::Sized;

    /// Construct an item from a `ListStore` and a `TreePath`.
    ///
    /// The `ListStore` is where the data is stored, and the `TreePath` is a pointer to the
    /// location of the data in the table.
    fn from_liststore_path<S>(list_store: S, tp: &gtk::TreePath) -> Option<Self>
    where
        S: TreeModelExt,
        Self: std::marker::Sized,
    {
        list_store
            .get_iter(tp)
            .and_then(|iter| ListStoreItem::from_liststore_iter(list_store, &iter))
    }

    /// Instert an item into a `ListStore` as a new entry.
    fn insert_into_liststore<S>(&self, list_store: S) -> gtk::TreeIter
    where
        S: GtkListStoreExtManual;
}

// Re-export #[derive(ListStoreItem)].
#[cfg(feature = "derive")]
#[doc(hidden)]
pub use gtk_liststore_item_derive::ListStoreItem;