Skip to main content

ferroui_dialogs/
managed_file_chooser_overwrite_prompt.rs

1use ferroui_base::input::InputElementImpl;
2use ferroui_base::interactivity::InteractiveImpl;
3use ferroui_base::layout::LayoutableImpl;
4use ferroui_base::reactive::{Disposable, IDisposable};
5use ferroui_base::utilities::HandlerList;
6use ferroui_base::{
7    ferro_class, ferro_class_info, ferro_impl_classes, ferro_properties, ferro_property, instantiate, DirectProperty,
8    FerroObjectImpl, FerroProperty, Ref, StyledElementImpl, VisualImpl,
9};
10use ferroui_controls::primitives::{TemplatedControl, TemplatedControlImpl};
11use ferroui_controls::ControlImpl;
12use std::cell::RefCell;
13use std::rc::Rc;
14
15/// Asks whether to replace an existing file: the content of the flyout the
16/// managed storage provider shows when the user saves to a file that
17/// exists.
18#[repr(C)]
19pub struct ManagedFileChooserOverwritePrompt {
20    base: TemplatedControl,
21    result: Rc<HandlerList<dyn Fn(bool)>>,
22    file_name: RefCell<String>,
23}
24
25ferro_class!(ManagedFileChooserOverwritePrompt: TemplatedControl);
26ferro_impl_classes!(
27    ManagedFileChooserOverwritePrompt: FerroObjectImpl,
28    StyledElementImpl,
29    VisualImpl,
30    LayoutableImpl,
31    InteractiveImpl,
32    InputElementImpl,
33    ControlImpl,
34    TemplatedControlImpl
35);
36ferro_class_info!(ManagedFileChooserOverwritePrompt {
37    new: ManagedFileChooserOverwritePrompt::new,
38    markup: {
39        methods: [
40            fn Confirm() => ManagedFileChooserOverwritePrompt::confirm,
41            fn Cancel() => ManagedFileChooserOverwritePrompt::cancel,
42        ],
43    },
44});
45
46ferro_properties! { impl ManagedFileChooserOverwritePrompt {
47    ferro_property!(
48        /// Defines the `FileName` property.
49        pub fn file_name_property() -> DirectProperty<ManagedFileChooserOverwritePrompt, String> {
50            FerroProperty::register_direct::<ManagedFileChooserOverwritePrompt, _>(
51                "FileName",
52                |o| o.file_name(),
53                Some(|o, v| o.set_file_name(v)),
54                String::new(),
55            )
56        }
57    );
58} }
59
60impl ManagedFileChooserOverwritePrompt {
61    pub fn construct() -> Self {
62        Self { base: TemplatedControl::construct(), result: Rc::new(HandlerList::new()), file_name: RefCell::new(String::new()) }
63    }
64
65    pub fn new() -> Ref<Self> {
66        instantiate(Self::construct())
67    }
68
69    /// Raised with the answer of the user: `true` to replace the file.
70    pub fn result(&self, handler: impl Fn(bool) + 'static) -> Rc<dyn IDisposable> {
71        let token = self.result.add(Rc::new(handler));
72        let handlers = self.result.clone();
73        Disposable::create(move || {
74            handlers.remove(token);
75        })
76    }
77
78    fn raise_result(&self, value: bool) {
79        for (_, handler) in self.result.snapshot().iter() {
80            handler(value);
81        }
82    }
83
84    /// The name of the file that exists.
85    pub fn file_name(&self) -> String {
86        self.file_name.borrow().clone()
87    }
88
89    pub fn set_file_name(&self, value: String) {
90        self.set_and_raise(Self::file_name_property(), &self.file_name, value);
91    }
92
93    /// Answers that the file is to be replaced.
94    pub fn confirm(&self) {
95        self.raise_result(true);
96    }
97
98    /// Answers that the file is to be kept.
99    pub fn cancel(&self) {
100        self.raise_result(false);
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    // Not from upstream: the upstream project has no tests.
107    use super::*;
108    use std::cell::RefCell;
109
110    #[test]
111    fn confirm_and_cancel_raise_the_result() {
112        let prompt = ManagedFileChooserOverwritePrompt::new();
113        let results = Rc::new(RefCell::new(Vec::new()));
114        let sink = results.clone();
115        let subscription = prompt.result(move |result| sink.borrow_mut().push(result));
116
117        prompt.confirm();
118        prompt.cancel();
119        subscription.dispose();
120        prompt.confirm();
121
122        assert_eq!(vec![true, false], *results.borrow());
123    }
124
125    #[test]
126    fn file_name_is_a_direct_property() {
127        let prompt = ManagedFileChooserOverwritePrompt::new();
128        assert_eq!("", prompt.file_name());
129
130        prompt.set_file_name("a.txt".to_string());
131
132        assert_eq!("a.txt", prompt.get_direct_value(ManagedFileChooserOverwritePrompt::file_name_property()));
133    }
134}