1use crate::{FileFilterFlags, ffi};
4use glib::translate::*;
5use std::ffi::CStr;
6
7#[repr(transparent)]
10#[doc(alias = "GtkFileFilterInfo")]
11pub struct FileFilterInfo(ffi::GtkFileFilterInfo);
12
13impl FileFilterInfo {
14 pub fn new(
15 filename: Option<&str>,
16 uri: Option<&str>,
17 display_name: Option<&str>,
18 mime_type: Option<&str>,
19 ) -> Self {
20 skip_assert_initialized!();
21 let mut contains = FileFilterFlags::empty();
22 for (value, bit) in [
23 (filename, FileFilterFlags::FILENAME),
24 (uri, FileFilterFlags::URI),
25 (display_name, FileFilterFlags::DISPLAY_NAME),
26 (mime_type, FileFilterFlags::MIME_TYPE),
27 ] {
28 if value.is_some() {
29 contains |= bit;
30 }
31 }
32
33 Self(ffi::GtkFileFilterInfo {
34 contains: contains.bits(),
35 filename: filename.to_glib_full(),
36 uri: uri.to_glib_full(),
37 display_name: display_name.to_glib_full(),
38 mime_type: mime_type.to_glib_full(),
39 })
40 }
41
42 #[doc(alias = "get_contains")]
43 pub fn contains(&self) -> FileFilterFlags {
44 FileFilterFlags::from_bits_truncate(self.0.contains)
45 }
46
47 #[doc(alias = "get_filename")]
48 pub fn filename(&self) -> Option<&str> {
49 unsafe {
50 if self.0.filename.is_null() {
51 None
52 } else {
53 Some(
54 CStr::from_ptr(self.0.filename)
55 .to_str()
56 .expect("filename was not valid UTF-8"),
57 )
58 }
59 }
60 }
61
62 #[doc(alias = "get_uri")]
63 pub fn uri(&self) -> Option<&str> {
64 unsafe {
65 if self.0.uri.is_null() {
66 None
67 } else {
68 Some(
69 CStr::from_ptr(self.0.uri)
70 .to_str()
71 .expect("uri was not valid UTF-8"),
72 )
73 }
74 }
75 }
76
77 #[doc(alias = "get_display_name")]
78 pub fn display_name(&self) -> Option<&str> {
79 unsafe {
80 if self.0.display_name.is_null() {
81 None
82 } else {
83 Some(
84 CStr::from_ptr(self.0.display_name)
85 .to_str()
86 .expect("display_name was not valid UTF-8"),
87 )
88 }
89 }
90 }
91
92 #[doc(alias = "get_mime_type")]
93 pub fn mime_type(&self) -> Option<&str> {
94 unsafe {
95 if self.0.mime_type.is_null() {
96 None
97 } else {
98 Some(
99 CStr::from_ptr(self.0.mime_type)
100 .to_str()
101 .expect("mime_type was not valid UTF-8"),
102 )
103 }
104 }
105 }
106}
107
108impl Drop for FileFilterInfo {
109 fn drop(&mut self) {
110 for ptr in [
111 self.0.filename,
112 self.0.uri,
113 self.0.display_name,
114 self.0.mime_type,
115 ] {
116 unsafe {
117 glib::ffi::g_free(ptr as *mut _);
118 }
119 }
120 }
121}
122
123#[doc(hidden)]
124impl FromGlibPtrNone<*const ffi::GtkFileFilterInfo> for FileFilterInfo {
125 unsafe fn from_glib_none(ptr: *const ffi::GtkFileFilterInfo) -> Self {
126 unsafe {
127 assert!(!ptr.is_null());
128 Self(ffi::GtkFileFilterInfo {
129 contains: (*ptr).contains,
130 filename: glib::ffi::g_strdup((*ptr).filename),
131 uri: glib::ffi::g_strdup((*ptr).uri),
132 display_name: glib::ffi::g_strdup((*ptr).display_name),
133 mime_type: glib::ffi::g_strdup((*ptr).mime_type),
134 })
135 }
136 }
137}
138
139#[doc(hidden)]
140impl FromGlibPtrBorrow<*const ffi::GtkFileFilterInfo> for FileFilterInfo {
141 unsafe fn from_glib_borrow(ptr: *const ffi::GtkFileFilterInfo) -> Borrowed<Self> {
142 unsafe {
143 assert!(!ptr.is_null());
144 Borrowed::new(FileFilterInfo(*ptr))
145 }
146 }
147}
148
149#[doc(hidden)]
150impl<'a> ToGlibPtr<'a, *const ffi::GtkFileFilterInfo> for FileFilterInfo {
151 type Storage = (ffi::GtkFileFilterInfo, &'a FileFilterInfo);
152
153 #[inline]
154 fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GtkFileFilterInfo, Self> {
155 Stash(&self.0, (self.0, self))
156 }
157}
158
159#[cfg(test)]
160mod test {
161 use super::*;
162 use crate::TEST_THREAD_WORKER;
163
164 const TEST_FILENAME: &str = "testfile.txt";
165 const TEST_URI: &str = "file:///foo/bar/testfile.txt";
166 const TEST_DISPLAY_NAME: &str = "testfile";
167 const TEST_MIME_TYPE: &str = "text/plain";
168
169 #[test]
170 fn custom_filter() {
171 TEST_THREAD_WORKER
172 .push(|| {
173 let _ = crate::init();
174
175 let filter = crate::FileFilter::new();
176 filter.add_custom(FileFilterFlags::all(), |filter_info| {
177 assert_eq![filter_info.filename(), Some(TEST_FILENAME)];
178 assert_eq![filter_info.uri(), Some(TEST_URI)];
179 assert_eq![filter_info.display_name(), Some(TEST_DISPLAY_NAME)];
180 assert_eq![filter_info.mime_type(), Some(TEST_MIME_TYPE)];
181 true
182 });
183
184 let filter_info = FileFilterInfo::new(
185 Some(TEST_FILENAME),
186 Some(TEST_URI),
187 Some(TEST_DISPLAY_NAME),
188 Some(TEST_MIME_TYPE),
189 );
190 filter.filter(&filter_info);
191 })
192 .expect("Failed to schedule a test call");
193 while TEST_THREAD_WORKER.unprocessed() > 0 {}
194 }
195}