dialog/backends/
kdialog.rs1use std::process;
6
7use crate::{
8 Choice, Error, FileSelection, FileSelectionMode, Input, Message, Password, Question, Result,
9};
10
11const OK: i32 = 0;
20const CANCEL: i32 = 1;
21
22#[derive(Debug, Default)]
26pub struct KDialog {
27 icon: Option<String>,
28 }
30
31impl KDialog {
32 pub fn new() -> KDialog {
34 Default::default()
35 }
36
37 pub fn set_icon(&mut self, icon: impl Into<String>) {
44 self.icon = Some(icon.into());
45 }
46
47 pub(crate) fn is_available() -> bool {
48 super::is_available("kdialog")
49 }
50
51 fn execute(&self, args: Vec<&str>, title: &Option<String>) -> Result<process::Output> {
52 let mut command = process::Command::new("kdialog");
53
54 if let Some(ref icon) = self.icon {
55 command.arg("--icon");
56 command.arg(icon);
57 }
58 if let Some(ref title) = title {
59 command.arg("--title");
60 command.arg(title);
61 }
62
63 command.args(args);
64 command.output().map_err(Error::IoError)
65 }
66}
67
68impl AsRef<KDialog> for KDialog {
69 fn as_ref(&self) -> &Self {
70 self
71 }
72}
73
74fn require_success(status: process::ExitStatus) -> Result<()> {
75 if status.success() {
76 Ok(())
77 } else if let Some(code) = status.code() {
78 match code {
79 CANCEL => Ok(()),
80 _ => Err(Error::from(("kdialog", status))),
81 }
82 } else {
83 Err(Error::from(("kdialog", status)))
84 }
85}
86
87fn get_choice(status: process::ExitStatus) -> Result<Choice> {
88 if let Some(code) = status.code() {
89 match code {
90 OK => Ok(Choice::Yes),
91 CANCEL => Ok(Choice::No),
92 _ => Err(Error::from(("kdialog", status))),
93 }
94 } else {
95 Err(Error::from(("kdialog", status)))
96 }
97}
98
99fn get_stdout(output: process::Output) -> Result<Option<String>> {
100 if output.status.success() {
101 String::from_utf8(output.stdout)
102 .map(|s| Some(s.trim_end_matches('\n').to_string()))
103 .map_err(Error::from)
104 } else if let Some(code) = output.status.code() {
105 match code {
106 OK => Ok(None),
107 CANCEL => Ok(None),
108 _ => Err(Error::from(("kdialog", output.status))),
109 }
110 } else {
111 Err(Error::from(("kdialog", output.status)))
112 }
113}
114
115impl super::Backend for KDialog {
116 fn show_input(&self, input: &Input) -> Result<Option<String>> {
117 let mut args = vec!["--inputbox", &input.text];
118 if let Some(ref default) = input.default {
119 args.push(default);
120 }
121 self.execute(args, &input.title).and_then(get_stdout)
122 }
123
124 fn show_message(&self, message: &Message) -> Result<()> {
125 let args = vec!["--msgbox", &message.text];
126 self.execute(args, &message.title)
127 .and_then(|output| require_success(output.status))
128 .map(|_| ())
129 }
130
131 fn show_password(&self, password: &Password) -> Result<Option<String>> {
132 let args = vec!["--password", &password.text];
133 self.execute(args, &password.title).and_then(get_stdout)
134 }
135
136 fn show_question(&self, question: &Question) -> Result<Choice> {
137 let args = vec!["--yesno", &question.text];
138 self.execute(args, &question.title)
139 .and_then(|output| get_choice(output.status))
140 }
141
142 fn show_file_selection(&self, file_selection: &FileSelection) -> Result<Option<String>> {
143 let dir = file_selection.path_to_string().ok_or("path not valid")?;
144 let option = match file_selection.mode {
145 FileSelectionMode::Open => "--getopenfilename",
146 FileSelectionMode::Save => "--getsavefilename",
147 };
148 let args = vec![option, &dir];
149 self.execute(args, &file_selection.title)
150 .and_then(get_stdout)
151 }
152}