blocking_dialog/linux/
save_file.rs1use super::is_kdialog_available;
5use crate::{BlockingDialogError, BlockingPickFilesDialogFilter, BlockingSaveFileDialog};
6use raw_window_handle::HasWindowHandle;
7use std::path::PathBuf;
8use std::process::Command;
9
10fn get_kdialog_filter(filter: &[BlockingPickFilesDialogFilter]) -> String {
11 filter
12 .iter()
13 .map(|entry| {
14 format!(
15 "{} ({})",
16 entry.name,
17 entry
18 .extensions
19 .iter()
20 .map(|ext| format!("*.{ext}"))
21 .collect::<Vec<_>>()
22 .join(" "),
23 )
24 })
25 .collect::<Vec<_>>()
26 .join(" ")
27}
28
29impl<'a, W: HasWindowHandle> BlockingSaveFileDialog<'a, W> {
30 pub fn show(&self) -> Result<Option<PathBuf>, BlockingDialogError> {
31 if is_kdialog_available() {
32 let filter = get_kdialog_filter(self.filter);
33
34 let mut args = vec!["--getsavefilename", "--title", self.title];
35
36 if let Some(default_filename) = self.default_filename {
37 args.push(default_filename);
38 }
39
40 if !self.filter.is_empty() {
41 args.push(":label1");
42 args.push(&filter);
43 }
44
45 let output = Command::new("kdialog").args(args).output()?;
46 let stdout = String::from_utf8_lossy(&output.stdout);
47 let trimmed = stdout.trim();
48
49 if trimmed.is_empty() {
50 Ok(None)
51 } else {
52 Ok(Some(PathBuf::from(trimmed)))
53 }
54 } else {
55 let mut filter_args = Vec::new();
56
57 for entry in self.filter {
58 let patterns = entry
59 .extensions
60 .iter()
61 .map(|ext| format!("*.{ext}"))
62 .collect::<Vec<_>>()
63 .join(" ");
64 filter_args.push(format!("{} | {}", entry.name, patterns));
65 }
66
67 let mut args = vec!["--file-selection", "--save", "--title", self.title];
68
69 if let Some(default_filename) = self.default_filename {
70 args.push("--filename");
71 args.push(default_filename);
72 }
73
74 for filter_arg in &filter_args {
75 args.push("--file-filter");
76 args.push(filter_arg.as_str());
77 }
78
79 let output = Command::new("zenity").args(args).output()?;
80 let stdout = String::from_utf8_lossy(&output.stdout);
81 let trimmed = stdout.trim();
82
83 if trimmed.is_empty() {
84 Ok(None)
85 } else {
86 Ok(Some(PathBuf::from(trimmed)))
87 }
88 }
89 }
90}