mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 11:12:45 +00:00 
			
		
		
		
	LibGUI: Add allowed file types to FilePicker
This patch adds a ComboBox to `FilePicker` where the user can select which file types to show, all files that doesn't have an extension that's in the selected file type will be hidden. When creating a FilePicker with `FilePicker::construct` or `FilePicker::get_open_filepath`, allowed file types can be specified as the last argument. If no file types are provided then there will be no visual change in the GUI. 'All Files' and 'Image Files' have shorthands with `GUI::FileTypeFilter::all_files()` and `GUI::FileTypeFilter::image_files()`, respectively.
This commit is contained in:
		
							parent
							
								
									fe5dfe4cd5
								
							
						
					
					
						commit
						be464c357a
					
				
					 4 changed files with 85 additions and 13 deletions
				
			
		|  | @ -16,7 +16,9 @@ | |||
| #include <LibGUI/FilePicker.h> | ||||
| #include <LibGUI/FilePickerDialogGML.h> | ||||
| #include <LibGUI/FileSystemModel.h> | ||||
| #include <LibGUI/FileTypeFilter.h> | ||||
| #include <LibGUI/InputBox.h> | ||||
| #include <LibGUI/ItemListModel.h> | ||||
| #include <LibGUI/Label.h> | ||||
| #include <LibGUI/Menu.h> | ||||
| #include <LibGUI/MessageBox.h> | ||||
|  | @ -25,6 +27,7 @@ | |||
| #include <LibGUI/TextBox.h> | ||||
| #include <LibGUI/Toolbar.h> | ||||
| #include <LibGUI/Tray.h> | ||||
| #include <LibGUI/Widget.h> | ||||
| #include <LibGfx/Font/FontDatabase.h> | ||||
| #include <LibGfx/Palette.h> | ||||
| #include <string.h> | ||||
|  | @ -32,9 +35,9 @@ | |||
| 
 | ||||
| namespace GUI { | ||||
| 
 | ||||
| Optional<DeprecatedString> FilePicker::get_open_filepath(Window* parent_window, DeprecatedString const& window_title, StringView path, bool folder, ScreenPosition screen_position) | ||||
| Optional<DeprecatedString> FilePicker::get_open_filepath(Window* parent_window, DeprecatedString const& window_title, StringView path, bool folder, ScreenPosition screen_position, Optional<Vector<FileTypeFilter>> allowed_file_types) | ||||
| { | ||||
|     auto picker = FilePicker::construct(parent_window, folder ? Mode::OpenFolder : Mode::Open, ""sv, path, screen_position); | ||||
|     auto picker = FilePicker::construct(parent_window, folder ? Mode::OpenFolder : Mode::Open, ""sv, path, screen_position, move(allowed_file_types)); | ||||
| 
 | ||||
|     if (!window_title.is_null()) | ||||
|         picker->set_title(window_title); | ||||
|  | @ -65,9 +68,10 @@ Optional<DeprecatedString> FilePicker::get_save_filepath(Window* parent_window, | |||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| FilePicker::FilePicker(Window* parent_window, Mode mode, StringView filename, StringView path, ScreenPosition screen_position) | ||||
| FilePicker::FilePicker(Window* parent_window, Mode mode, StringView filename, StringView path, ScreenPosition screen_position, Optional<Vector<FileTypeFilter>> allowed_file_types) | ||||
|     : Dialog(parent_window, screen_position) | ||||
|     , m_model(FileSystemModel::create(path)) | ||||
|     , m_allowed_file_types(move(allowed_file_types)) | ||||
|     , m_mode(mode) | ||||
| { | ||||
|     switch (m_mode) { | ||||
|  | @ -112,6 +116,36 @@ FilePicker::FilePicker(Window* parent_window, Mode mode, StringView filename, St | |||
|         set_path(m_location_textbox->text()); | ||||
|     }; | ||||
| 
 | ||||
|     auto* file_types_filters_combo = widget->find_descendant_of_type_named<GUI::ComboBox>("allowed_file_type_filters_combo"); | ||||
| 
 | ||||
|     if (m_allowed_file_types.has_value()) { | ||||
|         for (auto& filter : *m_allowed_file_types) { | ||||
|             if (!filter.extensions.has_value()) { | ||||
|                 m_allowed_file_types_names.append(filter.name); | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             StringBuilder extension_list; | ||||
|             extension_list.join("; "sv, *filter.extensions); | ||||
|             m_allowed_file_types_names.append(DeprecatedString::formatted("{} ({})", filter.name, extension_list.to_deprecated_string())); | ||||
|         } | ||||
| 
 | ||||
|         file_types_filters_combo->set_model(*GUI::ItemListModel<DeprecatedString, Vector<DeprecatedString>>::create(m_allowed_file_types_names)); | ||||
|         file_types_filters_combo->on_change = [this](DeprecatedString const&, GUI::ModelIndex const& index) { | ||||
|             m_model->set_allowed_file_extensions((*m_allowed_file_types)[index.row()].extensions); | ||||
|         }; | ||||
|         file_types_filters_combo->set_selected_index(0); | ||||
|     } else { | ||||
|         auto* file_types_filter_label = widget->find_descendant_of_type_named<GUI::Label>("allowed_file_types_label"); | ||||
|         auto& spacer = file_types_filter_label->parent_widget()->add<GUI::Widget>(); | ||||
|         spacer.set_fixed_height(22); | ||||
|         file_types_filter_label->remove_from_parent(); | ||||
| 
 | ||||
|         file_types_filters_combo->parent_widget()->insert_child_before(GUI::Widget::construct(), *file_types_filters_combo); | ||||
| 
 | ||||
|         file_types_filters_combo->remove_from_parent(); | ||||
|     } | ||||
| 
 | ||||
|     auto open_parent_directory_action = Action::create( | ||||
|         "Open parent directory", { Mod_Alt, Key_Up }, Gfx::Bitmap::load_from_file("/res/icons/16x16/open-parent-directory.png"sv).release_value_but_fixme_should_propagate_errors(), [this](Action const&) { | ||||
|             set_path(DeprecatedString::formatted("{}/..", m_model->root_path())); | ||||
|  |  | |||
|  | @ -8,8 +8,11 @@ | |||
| 
 | ||||
| #include <AK/LexicalPath.h> | ||||
| #include <AK/Optional.h> | ||||
| #include <AK/String.h> | ||||
| #include <LibCore/StandardPaths.h> | ||||
| #include <LibGUI/ComboBox.h> | ||||
| #include <LibGUI/Dialog.h> | ||||
| #include <LibGUI/FileTypeFilter.h> | ||||
| #include <LibGUI/ImageWidget.h> | ||||
| #include <LibGUI/Model.h> | ||||
| 
 | ||||
|  | @ -28,7 +31,7 @@ public: | |||
|         Save | ||||
|     }; | ||||
| 
 | ||||
|     static Optional<DeprecatedString> get_open_filepath(Window* parent_window, DeprecatedString const& window_title = {}, StringView path = Core::StandardPaths::home_directory(), bool folder = false, ScreenPosition screen_position = Dialog::ScreenPosition::CenterWithinParent); | ||||
|     static Optional<DeprecatedString> get_open_filepath(Window* parent_window, DeprecatedString const& window_title = {}, StringView path = Core::StandardPaths::home_directory(), bool folder = false, ScreenPosition screen_position = Dialog::ScreenPosition::CenterWithinParent, Optional<Vector<FileTypeFilter>> allowed_file_types = {}); | ||||
|     static Optional<DeprecatedString> get_save_filepath(Window* parent_window, DeprecatedString const& title, DeprecatedString const& extension, StringView path = Core::StandardPaths::home_directory(), ScreenPosition screen_position = Dialog::ScreenPosition::CenterWithinParent); | ||||
| 
 | ||||
|     virtual ~FilePicker() override; | ||||
|  | @ -43,7 +46,7 @@ private: | |||
|     // ^GUI::ModelClient
 | ||||
|     virtual void model_did_update(unsigned) override; | ||||
| 
 | ||||
|     FilePicker(Window* parent_window, Mode type = Mode::Open, StringView filename = "Untitled"sv, StringView path = Core::StandardPaths::home_directory(), ScreenPosition screen_position = Dialog::ScreenPosition::CenterWithinParent); | ||||
|     FilePicker(Window* parent_window, Mode type = Mode::Open, StringView filename = "Untitled"sv, StringView path = Core::StandardPaths::home_directory(), ScreenPosition screen_position = Dialog::ScreenPosition::CenterWithinParent, Optional<Vector<FileTypeFilter>> allowed_file_types = {}); | ||||
| 
 | ||||
|     static DeprecatedString ok_button_name(Mode mode) | ||||
|     { | ||||
|  | @ -68,6 +71,9 @@ private: | |||
|     NonnullRefPtr<FileSystemModel> m_model; | ||||
|     DeprecatedString m_selected_file; | ||||
| 
 | ||||
|     Vector<DeprecatedString> m_allowed_file_types_names; | ||||
|     Optional<Vector<FileTypeFilter>> m_allowed_file_types; | ||||
| 
 | ||||
|     RefPtr<GUI::Label> m_error_label; | ||||
| 
 | ||||
|     RefPtr<TextBox> m_filename_textbox; | ||||
|  |  | |||
|  | @ -25,11 +25,14 @@ | |||
|         @GUI::Label { | ||||
|             text: "Filename:" | ||||
|             text_alignment: "CenterRight" | ||||
|             fixed_height: 24 | ||||
|             fixed_height: 22 | ||||
|         } | ||||
| 
 | ||||
|         @GUI::Widget { | ||||
|             fixed_height: 20 | ||||
|         @GUI::Label { | ||||
|             name: "allowed_file_types_label" | ||||
|             text: "Files of Type:" | ||||
|             text_alignment: "CenterRight" | ||||
|             fixed_height: 22 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -68,10 +71,6 @@ | |||
|                     name: "filename_textbox" | ||||
|                 } | ||||
| 
 | ||||
|                 @GUI::Widget { | ||||
|                     fixed_width: 20 | ||||
|                 } | ||||
| 
 | ||||
|                 @GUI::DialogButton { | ||||
|                     name: "ok_button" | ||||
|                     text: "OK" | ||||
|  | @ -82,7 +81,10 @@ | |||
|                 fixed_height: 22 | ||||
|                 layout: @GUI::HorizontalBoxLayout {} | ||||
| 
 | ||||
|                 @GUI::Layout::Spacer {} | ||||
|                 @GUI::ComboBox { | ||||
|                     name: "allowed_file_type_filters_combo" | ||||
|                     model_only: true | ||||
|                 } | ||||
| 
 | ||||
|                 @GUI::DialogButton { | ||||
|                     name: "cancel_button" | ||||
|  |  | |||
							
								
								
									
										30
									
								
								Userland/Libraries/LibGUI/FileTypeFilter.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Userland/Libraries/LibGUI/FileTypeFilter.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2023, Marcus Nilsson <marcus.nilsson@genarp.com> | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <AK/DeprecatedString.h> | ||||
| #include <AK/Optional.h> | ||||
| #include <AK/Vector.h> | ||||
| 
 | ||||
| namespace GUI { | ||||
| 
 | ||||
| struct FileTypeFilter { | ||||
|     DeprecatedString name; | ||||
|     Optional<Vector<DeprecatedString>> extensions; | ||||
| 
 | ||||
|     static FileTypeFilter all_files() | ||||
|     { | ||||
|         return FileTypeFilter { "All Files", {} }; | ||||
|     } | ||||
| 
 | ||||
|     static FileTypeFilter image_files() | ||||
|     { | ||||
|         return FileTypeFilter { "Image Files", Vector<DeprecatedString> { "png", "gif", "bmp", "dip", "pbm", "pgm", "ppm", "ico", "jpeg", "jpg", "dds", "qoi" } }; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Marcus Nilsson
						Marcus Nilsson