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
use super::{DataFormat, DataFormatOf, DataTransferItemExtensions, IDataTransfer, IDataTransferItem};
use crate::media::imaging::Bitmap;
use crate::platform::storage::IStorageItem;
use std::rc::Rc;
/// The items of a data transfer that support a format, in order.
pub struct DataTransferItems {
items: Rc<[Rc<dyn IDataTransferItem>]>,
format: DataFormat,
index: usize,
}
impl Iterator for DataTransferItems {
type Item = Rc<dyn IDataTransferItem>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(item) = self.items.get(self.index) {
self.index += 1;
if item.contains(&self.format) {
return Some(item.clone());
}
}
None
}
}
// Keep the `try_get_xxx` methods in sync with the `try_get_xxx_async` ones
// of `AsyncDataTransferExtensions`.
/// Contains extension methods for [`IDataTransfer`].
pub trait DataTransferExtensions: IDataTransfer {
/// Gets whether the data transfer supports a specific format.
fn contains(&self, format: &DataFormat) -> bool {
self.formats().iter().any(|candidate| candidate == format)
}
/// Gets the list of [`IDataTransferItem`] contained in the data
/// transfer, filtered by a given format.
///
/// Some platforms (such as Windows and X11) may only support a single
/// data item for all formats except files.
fn get_items(&self, format: &DataFormat) -> DataTransferItems {
DataTransferItems { items: self.items(), format: format.clone(), index: 0 }
}
/// Tries to get a value for a given format from the data transfer.
/// Returns `None` if the format is not supported.
///
/// If the data transfer contains several items supporting the format,
/// the first matching one will be returned.
fn try_get_value<T: Clone + 'static>(&self, format: &DataFormatOf<T>) -> Option<T> {
self.get_items(format).next().and_then(|item| item.try_get_value(format))
}
/// Tries to get multiple values for a given format from the data
/// transfer. Returns `None` if the format is not supported.
fn try_get_values<T: Clone + 'static>(&self, format: &DataFormatOf<T>) -> Option<Vec<T>> {
let mut results: Option<Vec<T>> = None;
for item in self.get_items(format) {
let Some(result) = item.try_get_value(format) else { continue };
results.get_or_insert_with(Vec::new).push(result);
}
results
}
/// Returns a text, if available, from the data transfer.
///
/// If the data transfer contains several items supporting
/// [`DataFormat::text`], the first matching one will be returned.
fn try_get_text(&self) -> Option<String> {
self.try_get_value(&DataFormat::text())
}
/// Returns a bitmap, if available, from the data transfer.
///
/// If the data transfer contains several items supporting
/// [`DataFormat::bitmap`], the first matching one will be returned.
fn try_get_bitmap(&self) -> Option<Rc<Bitmap>> {
self.try_get_value(&DataFormat::bitmap())
}
/// Returns a file (or folder), if available, from the data transfer.
///
/// See [`DataFormat::file`].
fn try_get_file(&self) -> Option<Rc<dyn IStorageItem>> {
self.try_get_value(&DataFormat::file())
}
/// Returns the files (or folders), if available, from the data
/// transfer.
///
/// See [`DataFormat::file`].
fn try_get_files(&self) -> Option<Vec<Rc<dyn IStorageItem>>> {
self.try_get_values(&DataFormat::file())
}
}
impl<I: IDataTransfer + ?Sized> DataTransferExtensions for I {}