Skip to main content

gtk/
file_filter_info.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::{FileFilterFlags, ffi};
4use glib::translate::*;
5use std::ffi::CStr;
6
7/// A [`FileFilterInfo`][crate::FileFilterInfo]-struct is used to pass information about the
8/// tested file to [`FileFilter::filter()`][crate::FileFilter::filter()].
9#[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}