Przeglądaj źródła

FileManager: focus_dependent_delete_action is correctly enabled/disabled

The focus_dependent_delete_action that sits in the file manager's
toolbar would always remain enabled, even if nothing was selected,
activating it if nothing was selected would then crash the application.

The action is now correctly enabled/disabled, but due to the way
selection works in TreeViews, something is always selected, what really
matters is if the TreeView has something selected, and it has focus.
As it currently stands, there is no way to know when the TreeView's
is_focused status changes. In order for this to work I added a callback
to the Widget class which fires when a widget receives or looses focus.
In that callback, the focus_dependent_delete_action's enabled value is
recalculated.
Zac 4 lat temu
rodzic
commit
dea399ff08

+ 11 - 1
Applications/FileManager/main.cpp

@@ -456,6 +456,7 @@ int run_in_windowed_mode(RefPtr<Core::ConfigFile> config, String initial_locatio
             directory_view.delete_action().activate();
         refresh_tree_view();
     });
+    focus_dependent_delete_action->set_enabled(false);
 
     auto mkdir_action = GUI::Action::create("New directory...", { Mod_Ctrl | Mod_Shift, Key_N }, Gfx::Bitmap::load_from_file("/res/icons/16x16/mkdir.png"), [&](const GUI::Action&) {
         directory_view.mkdir_action().activate();
@@ -579,9 +580,10 @@ int run_in_windowed_mode(RefPtr<Core::ConfigFile> config, String initial_locatio
     };
 
     directory_view.on_selection_change = [&](GUI::AbstractView& view) {
-        // FIXME: Figure out how we can enable/disable the paste action, based on clipboard contents.
         auto& selection = view.selection();
         copy_action->set_enabled(!selection.is_empty());
+        focus_dependent_delete_action->set_enabled((!tree_view.selection().is_empty() && tree_view.is_focused())
+            || !directory_view.current_view().selection().is_empty());
     };
 
     directory_context_menu->add_action(copy_action);
@@ -681,6 +683,9 @@ int run_in_windowed_mode(RefPtr<Core::ConfigFile> config, String initial_locatio
     };
 
     tree_view.on_selection_change = [&] {
+        focus_dependent_delete_action->set_enabled((!tree_view.selection().is_empty() && tree_view.is_focused())
+            || !directory_view.current_view().selection().is_empty());
+
         if (tree_view.selection().is_empty())
             return;
         auto path = directories_model->full_path(tree_view.selection().first());
@@ -692,6 +697,11 @@ int run_in_windowed_mode(RefPtr<Core::ConfigFile> config, String initial_locatio
         directory_view.delete_action().set_enabled(!tree_view.selection().is_empty());
     };
 
+    tree_view.on_focus_change = [&]([[ maybe_unused ]] const bool has_focus, [[ maybe_unused ]] const GUI::FocusSource source) {
+        focus_dependent_delete_action->set_enabled((!tree_view.selection().is_empty() && has_focus)
+                                                   || !directory_view.current_view().selection().is_empty());
+    };
+
     tree_view.on_context_menu_request = [&](const GUI::ModelIndex& index, const GUI::ContextMenuEvent& event) {
         if (index.is_valid()) {
             tree_view_directory_context_menu->popup(event.screen_position());

+ 2 - 0
Libraries/LibGUI/Widget.h

@@ -165,6 +165,8 @@ public:
     bool is_focused() const;
     void set_focus(bool, FocusSource = FocusSource::Programmatic);
 
+    Function<void(const bool, const FocusSource)> on_focus_change;
+
     // Returns true if this widget or one of its descendants is focused.
     bool has_focus_within() const;
 

+ 11 - 4
Libraries/LibGUI/Window.cpp

@@ -558,14 +558,21 @@ void Window::set_focused_widget(Widget* widget, FocusSource source)
 {
     if (m_focused_widget == widget)
         return;
-    if (m_focused_widget) {
-        Core::EventLoop::current().post_event(*m_focused_widget, make<FocusEvent>(Event::FocusOut, source));
-        m_focused_widget->update();
-    }
+
+    WeakPtr<Widget> previously_focused_widget = m_focused_widget;
     m_focused_widget = widget;
+
+    if (previously_focused_widget) {
+        Core::EventLoop::current().post_event(*previously_focused_widget, make<FocusEvent>(Event::FocusOut, source));
+        previously_focused_widget->update();
+        if (previously_focused_widget && previously_focused_widget->on_focus_change)
+            previously_focused_widget->on_focus_change(previously_focused_widget->is_focused(), source);
+    }
     if (m_focused_widget) {
         Core::EventLoop::current().post_event(*m_focused_widget, make<FocusEvent>(Event::FocusIn, source));
         m_focused_widget->update();
+        if (m_focused_widget && m_focused_widget->on_focus_change)
+            m_focused_widget->on_focus_change(m_focused_widget->is_focused(), source);
     }
 }