Preserve checked status during search (#2212).
authorCarl Hetherington <cth@carlh.net>
Fri, 18 Mar 2022 21:50:12 +0000 (22:50 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 18 Mar 2022 21:50:23 +0000 (22:50 +0100)
src/wx/screens_panel.cc
src/wx/screens_panel.h

index fc63d618d2b01c3e01bbd6adc618a2939d2860e3..34bdadd8ea35b91014c5efcf739ec6d4a5ebc966 100644 (file)
@@ -465,38 +465,77 @@ ScreensPanel::search_changed ()
        }
 
        _ignore_selection_change = false;
+
+       _ignore_check_change = true;
+
+       for (auto const& checked: _checked_screens) {
+               if (auto item = screen_to_item(checked.second)) {
+                       _targets->CheckItem(*item, wxCHK_CHECKED);
+                       setup_cinema_checked_state(*item);
+               }
+       }
+
+       _ignore_check_change = false;
+}
+
+
+void
+ScreensPanel::set_screen_checked (wxTreeListItem item, bool checked)
+{
+       auto current = std::find_if(
+               _checked_screens.begin(), _checked_screens.end(),
+               [item](pair<wxTreeListItem, shared_ptr<Screen>> const& screen) { return screen.first == item; }
+               );
+
+       if (current == _checked_screens.end() && checked) {
+               _checked_screens.push_back({item, item_to_screen(item)});
+       } else if (current != _checked_screens.end() && !checked) {
+               _checked_screens.erase(current);
+       }
+}
+
+
+void
+ScreensPanel::setup_cinema_checked_state (wxTreeListItem screen)
+{
+       auto cinema = _targets->GetItemParent(screen);
+       DCPOMATIC_ASSERT (cinema.IsOk());
+       int checked = 0;
+       int unchecked = 0;
+       for (auto child = _targets->GetFirstChild(cinema); child.IsOk(); child = _targets->GetNextSibling(child)) {
+               if (_targets->GetCheckedState(child) == wxCHK_CHECKED) {
+                   ++checked;
+               } else {
+                   ++unchecked;
+               }
+       }
+       if (checked == 0) {
+               _targets->CheckItem(cinema, wxCHK_UNCHECKED);
+       } else if (unchecked == 0) {
+               _targets->CheckItem(cinema, wxCHK_CHECKED);
+       } else {
+               _targets->CheckItem(cinema, wxCHK_UNDETERMINED);
+       }
 }
 
 
 void
 ScreensPanel::checkbox_changed (wxTreeListEvent& ev)
 {
+       if (_ignore_check_change) {
+               return;
+       }
+
        if (item_to_cinema(ev.GetItem())) {
                /* Cinema: check/uncheck all children */
                auto const checked = _targets->GetCheckedState(ev.GetItem());
                for (auto child = _targets->GetFirstChild(ev.GetItem()); child.IsOk(); child = _targets->GetNextSibling(child)) {
                        _targets->CheckItem(child, checked);
+                       set_screen_checked(child, checked);
                }
        } else {
-               /* Screen: set cinema to checked/unchecked/3state */
-               auto parent = _targets->GetItemParent(ev.GetItem());
-               DCPOMATIC_ASSERT (parent.IsOk());
-               int checked = 0;
-               int unchecked = 0;
-               for (auto child = _targets->GetFirstChild(parent); child.IsOk(); child = _targets->GetNextSibling(child)) {
-                       if (_targets->GetCheckedState(child) == wxCHK_CHECKED) {
-                           ++checked;
-                       } else {
-                           ++unchecked;
-                       }
-               }
-               if (checked == 0) {
-                       _targets->CheckItem(parent, wxCHK_UNCHECKED);
-               } else if (unchecked == 0) {
-                       _targets->CheckItem(parent, wxCHK_CHECKED);
-               } else {
-                       _targets->CheckItem(parent, wxCHK_UNDETERMINED);
-               }
+               set_screen_checked(ev.GetItem(), _targets->GetCheckedState(ev.GetItem()));
+               setup_cinema_checked_state(ev.GetItem());
        }
 
        ScreensChanged ();
index 2567725b85ac87e1afe0717cfd5f1871e70596ed..8c818f441b2a7050af1c62fa026a74b623fd1c1e 100644 (file)
@@ -65,6 +65,8 @@ private:
        void search_changed ();
        void checkbox_changed (wxTreeListEvent& ev);
        boost::optional<std::pair<wxTreeListItem, std::shared_ptr<Cinema>>> cinema_for_operation () const;
+       void set_screen_checked (wxTreeListItem item, bool checked);
+       void setup_cinema_checked_state (wxTreeListItem screen);
 
        typedef std::vector<std::pair<wxTreeListItem, std::shared_ptr<Cinema>>> Cinemas;
        typedef std::vector<std::pair<wxTreeListItem, std::shared_ptr<dcpomatic::Screen>>> Screens;
@@ -85,8 +87,16 @@ private:
 
        Cinemas _cinemas;
        Screens _screens;
+       /* We want to be able to search (and so remove selected things from the view)
+        * but not deselect them, so we maintain lists of selected cinemas and screens.
+        */
        Cinemas _selected_cinemas;
        Screens _selected_screens;
+       /* Likewise with checked screens, except that we can work out which cinemas
+        * are checked from which screens are checked, so we don't need to store the
+        * cinemas.
+        */
+       Screens _checked_screens;
 
        std::map<wxTreeListItem, std::shared_ptr<Cinema>> _item_to_cinema;
        std::map<wxTreeListItem, std::shared_ptr<dcpomatic::Screen>> _item_to_screen;
@@ -94,6 +104,7 @@ private:
        std::map<std::shared_ptr<dcpomatic::Screen>, wxTreeListItem> _screen_to_item;
 
        bool _ignore_selection_change = false;
+       bool _ignore_check_change = false;
 
        class Comparator : public wxTreeListItemComparator
        {