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
//! Selection model for tracking selections in Model/View views.
//!
//! Wraps [`QItemSelectionModel`](https://doc.qt.io/qt-6/qitemselectionmodel.html).
use crate::ffi;
use crate::signal::{self, SignalHandle};
/// A non-owning wrapper around `QItemSelectionModel`.
///
/// The C++ object is owned by the view — do not use this wrapper after the
/// view is dropped. Signals are disconnected in [`Drop`] but the C++ object
/// is **not** deleted.
///
/// Obtained from the view's internal selection model. For now, constructed
/// manually via [`from_raw`](Self::from_raw).
///
/// # Signals
///
/// | Method | Qt signal |
/// |---|---|
/// | [`connect_selection_changed`](Self::connect_selection_changed) | `selectionChanged` |
/// | [`connect_current_changed`](Self::connect_current_changed) | `currentChanged` |
pub struct ItemSelectionModel {
ptr: *mut ffi::QItemSelectionModel,
signal_handles: Vec<SignalHandle>,
}
impl ItemSelectionModel {
/// Wrap an existing `QItemSelectionModel*`.
///
/// # Safety
///
/// The pointer must be valid and the underlying view must outlive
/// this wrapper.
#[doc(hidden)]
pub unsafe fn from_raw(ptr: *mut ffi::QItemSelectionModel) -> Self {
Self { ptr, signal_handles: Vec::new() }
}
/// Returns `true` if the model has any selection.
pub fn has_selection(&self) -> bool {
debug_assert!(!self.ptr.is_null());
unsafe { ffi::QItemSelectionModel_hasSelection(self.ptr) }
}
/// Connect a callback that fires when the selection changes.
pub fn connect_selection_changed<F: Fn()>(&mut self, f: F) {
debug_assert!(!self.ptr.is_null());
let handle = signal::leak_void(f);
unsafe { ffi::QItemSelectionModel_onSelectionChanged(self.ptr, handle.token); }
self.signal_handles.push(handle);
}
/// Connect a callback that fires when the current (focused) item changes.
pub fn connect_current_changed<F: Fn()>(&mut self, f: F) {
debug_assert!(!self.ptr.is_null());
let handle = signal::leak_void(f);
unsafe { ffi::QItemSelectionModel_onCurrentChanged(self.ptr, handle.token); }
self.signal_handles.push(handle);
}
}
impl Drop for ItemSelectionModel {
fn drop(&mut self) {
if self.ptr.is_null() { return; }
// Disconnect signals to prevent use-after-free.
// The C++ object is NOT deleted — the view owns it.
unsafe { ffi::QObject_disconnectAll(self.ptr as *mut _); }
for h in self.signal_handles.drain(..) {
unsafe { h.reclaim(); }
}
self.ptr = std::ptr::null_mut();
}
}