Skip to content

Commit

Permalink
Add file filtering to gtk dialogs. (#903)
Browse files Browse the repository at this point in the history
  • Loading branch information
jneem authored May 10, 2020
1 parent af20c09 commit 3878d31
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ While some features like the clipboard, menus or file dialogs are not yet availa
- GTK: Support disabled menu items. ([#897] by [@jneem])
- X11: Support individual window closing. ([#900] by [@xStrom])
- X11: Support `Application::quit`. ([#900] by [@xStrom])
- GTK: Support file filters in open/save dialogs. ([#903] by [@jneem])

### Visual

Expand Down Expand Up @@ -154,6 +155,7 @@ While some features like the clipboard, menus or file dialogs are not yet availa
[#897]: https://github.com/xi-editor/druid/pull/897
[#898]: https://github.com/xi-editor/druid/pull/898
[#900]: https://github.com/xi-editor/druid/pull/900
[#903]: https://github.com/xi-editor/druid/pull/903
[#909]: https://github.com/xi-editor/druid/pull/909

## [0.5.0] - 2020-04-01
Expand Down
43 changes: 41 additions & 2 deletions druid-shell/src/platform/gtk/dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,20 @@

use std::ffi::OsString;

use gtk::{FileChooserAction, FileChooserExt, NativeDialogExt, ResponseType, Window};
use gtk::{FileChooserAction, FileChooserExt, FileFilter, NativeDialogExt, ResponseType, Window};

use crate::dialog::{FileDialogOptions, FileDialogType};
use crate::dialog::{FileDialogOptions, FileDialogType, FileSpec};
use crate::Error;

fn file_filter(fs: &FileSpec) -> FileFilter {
let ret = FileFilter::new();
ret.set_name(Some(fs.name));
for ext in fs.extensions {
ret.add_pattern(&format!("*.{}", ext));
}
ret
}

pub(crate) fn get_file_dialog_path(
window: &Window,
ty: FileDialogType,
Expand All @@ -45,6 +54,36 @@ pub(crate) fn get_file_dialog_path(

dialog.set_select_multiple(options.multi_selection);

let mut found_default_filter = false;
if let Some(file_types) = &options.allowed_types {
for f in file_types {
let filter = file_filter(f);
dialog.add_filter(&filter);

if let Some(default) = &options.default_type {
if default == f {
// Note that we're providing the same FileFilter object to
// add_filter and set_filter, because gtk checks them for
// identity, not structural equality.
dialog.set_filter(&filter);
found_default_filter = true;
}
}
}
}

if let Some(default_file_type) = &options.default_type {
if options.allowed_types.is_some() && !found_default_filter {
// It's ok to set a default file filter without providing a list of
// allowed filters, but it's not ok (or at least, doesn't work in gtk)
// to provide a default filter that isn't in the (present) list
// of allowed filters.
log::warn!("default file type not found in allowed types");
} else if !found_default_filter {
dialog.set_filter(&file_filter(default_file_type));
}
}

let result = dialog.run();

let result = match result {
Expand Down
106 changes: 106 additions & 0 deletions druid/examples/open_save.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright 2020 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use druid::widget::{Align, Button, Flex, TextBox};
use druid::{
AppDelegate, AppLauncher, Command, DelegateCtx, Env, FileDialogOptions, FileInfo, FileSpec,
LocalizedString, Target, Widget, WindowDesc,
};

struct Delegate;

pub fn main() {
let main_window = WindowDesc::new(ui_builder)
.title(LocalizedString::new("open-save-demo").with_placeholder("Opening/Saving Demo"));
let data = "Type here.".to_owned();
AppLauncher::with_window(main_window)
.delegate(Delegate)
.use_simple_logger()
.launch(data)
.expect("launch failed");
}

fn ui_builder() -> impl Widget<String> {
let rs = FileSpec::new("Rust source", &["rs"]);
let txt = FileSpec::new("Text file", &["txt"]);
let other = FileSpec::new("Bogus file", &["foo", "bar", "baz"]);
let save_dialog_options = FileDialogOptions::new()
.allowed_types(vec![rs, txt, other])
.default_type(txt);
let open_dialog_options = save_dialog_options.clone();

let input = TextBox::new();
let save = Button::new("Save").on_click(move |ctx, _, _| {
ctx.submit_command(
Command::new(
druid::commands::SHOW_SAVE_PANEL,
save_dialog_options.clone(),
),
None,
)
});
let open = Button::new("Open").on_click(move |ctx, _, _| {
ctx.submit_command(
Command::new(
druid::commands::SHOW_OPEN_PANEL,
open_dialog_options.clone(),
),
None,
)
});

let mut col = Flex::column();
col.add_child(input);
col.add_spacer(8.0);
col.add_child(save);
col.add_child(open);
Align::centered(col)
}

impl AppDelegate<String> for Delegate {
fn command(
&mut self,
_ctx: &mut DelegateCtx,
_target: Target,
cmd: &Command,
data: &mut String,
_env: &Env,
) -> bool {
match cmd.selector {
druid::commands::SAVE_FILE => {
if let Ok(file_info) = cmd.get_object::<FileInfo>() {
if let Err(e) = std::fs::write(file_info.path(), &data[..]) {
println!("Error writing file: {}", e);
}
}
true
}
druid::commands::OPEN_FILE => {
if let Ok(file_info) = cmd.get_object::<FileInfo>() {
match std::fs::read_to_string(file_info.path()) {
Ok(s) => {
let first_line = s.lines().next().unwrap_or("");
*data = first_line.to_owned();
}
Err(e) => {
println!("Error opening file: {}", e);
}
}
}
true
}
_ => false,
}
}
}
1 change: 1 addition & 0 deletions druid/examples/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ impl_example!(layout);
impl_example!(lens);
impl_example!(list);
impl_example!(multiwin);
impl_example!(open_save);
impl_example!(panels.unwrap());
impl_example!(parse);
impl_example!(scroll_colors);
Expand Down

0 comments on commit 3878d31

Please sign in to comment.