Blame editor/registry-search.vala

Packit Service f2b131
/*
Packit Service f2b131
  This file is part of Dconf Editor
Packit Service f2b131
Packit Service f2b131
  Dconf Editor is free software: you can redistribute it and/or modify
Packit Service f2b131
  it under the terms of the GNU General Public License as published by
Packit Service f2b131
  the Free Software Foundation, either version 3 of the License, or
Packit Service f2b131
  (at your option) any later version.
Packit Service f2b131
Packit Service f2b131
  Dconf Editor is distributed in the hope that it will be useful,
Packit Service f2b131
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f2b131
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service f2b131
  GNU General Public License for more details.
Packit Service f2b131
Packit Service f2b131
  You should have received a copy of the GNU General Public License
Packit Service f2b131
  along with Dconf Editor.  If not, see <https://www.gnu.org/licenses/>.
Packit Service f2b131
*/
Packit Service f2b131
Packit Service f2b131
using Gtk;
Packit Service f2b131
Packit Service f2b131
class RegistrySearch : RegistryList
Packit Service f2b131
{
Packit Service f2b131
    private string current_path;
Packit Service f2b131
    private string [] bookmarks;
Packit Service f2b131
    private SortingOptions sorting_options;
Packit Service f2b131
Packit Service f2b131
    public ModificationsHandler modifications_handler { private get; set; }
Packit Service f2b131
Packit Service f2b131
    construct
Packit Service f2b131
    {
Packit Service f2b131
        placeholder.label = _("No matches");
Packit Service f2b131
        key_list_box.set_header_func (update_search_results_header);
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    /*\
Packit Service f2b131
    * * Updating
Packit Service f2b131
    \*/
Packit Service f2b131
Packit Service f2b131
    private void ensure_selection ()
Packit Service f2b131
    {
Packit Service f2b131
        ListBoxRow? row = key_list_box.get_selected_row ();
Packit Service f2b131
        if (row == null)
Packit Service f2b131
            select_first_row ();
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    public override void select_first_row ()
Packit Service f2b131
    {
Packit Service f2b131
        ListBoxRow? row = key_list_box.get_row_at_index (0);
Packit Service f2b131
        if (row != null)
Packit Service f2b131
            key_list_box.select_row ((!) row);
Packit Service f2b131
        key_list_box.get_adjustment ().set_value (0);
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    /*\
Packit Service f2b131
    * * Key ListBox
Packit Service f2b131
    \*/
Packit Service f2b131
Packit Service f2b131
    private Widget new_list_box_row (Object item)
Packit Service f2b131
    {
Packit Service f2b131
        ClickableListBoxRow row;
Packit Service f2b131
        SettingObject setting_object = (SettingObject) item;
Packit Service f2b131
        string full_name = setting_object.full_name;
Packit Service f2b131
        string parent_path = SettingsModel.get_parent_path (full_name);
Packit Service f2b131
        bool is_local_result = parent_path == current_path;
Packit Service f2b131
Packit Service f2b131
        if (setting_object is Directory)
Packit Service f2b131
        {
Packit Service f2b131
            row = new FolderListBoxRow (setting_object.name, setting_object.full_name, setting_object.parent_path, !is_local_result);
Packit Service f2b131
        }
Packit Service f2b131
        else
Packit Service f2b131
        {
Packit Service f2b131
            if (setting_object is GSettingsKey)
Packit Service f2b131
                row = new KeyListBoxRowEditable ((GSettingsKey) setting_object, modifications_handler, !is_local_result);
Packit Service f2b131
            else
Packit Service f2b131
                row = new KeyListBoxRowEditableNoSchema ((DConfKey) setting_object, modifications_handler, !is_local_result);
Packit Service f2b131
Packit Service f2b131
            KeyListBoxRow key_row = (KeyListBoxRow) row;
Packit Service f2b131
            key_row.small_keys_list_rows = _small_keys_list_rows;
Packit Service f2b131
Packit Service f2b131
            ulong delayed_modifications_changed_handler = modifications_handler.delayed_changes_changed.connect (() => key_row.set_delayed_icon ());
Packit Service f2b131
            key_row.set_delayed_icon ();
Packit Service f2b131
            row.destroy.connect (() => modifications_handler.disconnect (delayed_modifications_changed_handler));
Packit Service f2b131
        }
Packit Service f2b131
Packit Service f2b131
        ulong button_press_event_handler = row.button_press_event.connect (on_button_pressed);
Packit Service f2b131
        row.destroy.connect (() => row.disconnect (button_press_event_handler));
Packit Service f2b131
Packit Service f2b131
        /* Wrapper ensures max width for rows */
Packit Service f2b131
        ListBoxRowWrapper wrapper = new ListBoxRowWrapper ();
Packit Service f2b131
Packit Service f2b131
        wrapper.set_halign (Align.CENTER);
Packit Service f2b131
        wrapper.add (row);
Packit Service f2b131
        if (row is FolderListBoxRow)
Packit Service f2b131
        {
Packit Service f2b131
            wrapper.get_style_context ().add_class ("folder-row");
Packit Service f2b131
            wrapper.action_name = "ui.open-folder";
Packit Service f2b131
            wrapper.set_action_target ("s", setting_object.full_name);
Packit Service f2b131
        }
Packit Service f2b131
        else
Packit Service f2b131
        {
Packit Service f2b131
            wrapper.get_style_context ().add_class ("key-row");
Packit Service f2b131
            wrapper.action_name = "ui.open-object";
Packit Service f2b131
            string context = (setting_object is GSettingsKey) ? ((GSettingsKey) setting_object).schema_id : ".dconf";
Packit Service f2b131
            wrapper.set_action_target ("(ss)", setting_object.full_name, context);
Packit Service f2b131
        }
Packit Service f2b131
Packit Service f2b131
        return wrapper;
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private bool on_button_pressed (Widget widget, Gdk.EventButton event)
Packit Service f2b131
    {
Packit Service f2b131
        ListBoxRow list_box_row = (ListBoxRow) widget.get_parent ();
Packit Service f2b131
        Container list_box = (Container) list_box_row.get_parent ();
Packit Service f2b131
        key_list_box.select_row (list_box_row);
Packit Service f2b131
Packit Service f2b131
        if (event.button == Gdk.BUTTON_SECONDARY)
Packit Service f2b131
        {
Packit Service f2b131
            if (list_box.get_focus_child () != null)
Packit Service f2b131
                list_box_row.grab_focus ();
Packit Service f2b131
Packit Service f2b131
            ClickableListBoxRow row = (ClickableListBoxRow) widget;
Packit Service f2b131
Packit Service f2b131
            int event_x = (int) event.x;
Packit Service f2b131
            if (event.window != widget.get_window ())   // boolean value switch
Packit Service f2b131
            {
Packit Service f2b131
                int widget_x, unused;
Packit Service f2b131
                event.window.get_position (out widget_x, out unused);
Packit Service f2b131
                event_x += widget_x;
Packit Service f2b131
            }
Packit Service f2b131
Packit Service f2b131
            row.show_right_click_popover (event_x);
Packit Service f2b131
            rows_possibly_with_popover.append (row);
Packit Service f2b131
        }
Packit Service f2b131
        else
Packit Service f2b131
            list_box_row.grab_focus ();
Packit Service f2b131
Packit Service f2b131
        return false;
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    public bool return_pressed ()
Packit Service f2b131
    {
Packit Service f2b131
        ListBoxRow? selected_row = (ListBoxRow?) key_list_box.get_selected_row ();
Packit Service f2b131
        if (selected_row == null)
Packit Service f2b131
            return false;
Packit Service f2b131
Packit Service f2b131
        ((!) selected_row).activate ();
Packit Service f2b131
        return true;
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    public override bool up_or_down_pressed (bool is_down)
Packit Service f2b131
    {
Packit Service f2b131
        ListBoxRow? selected_row = key_list_box.get_selected_row ();
Packit Service f2b131
        uint n_items = list_model.get_n_items ();
Packit Service f2b131
Packit Service f2b131
        if (selected_row != null)
Packit Service f2b131
        {
Packit Service f2b131
            Widget? row_content = ((!) selected_row).get_child ();
Packit Service f2b131
            if (row_content != null && ((ClickableListBoxRow) (!) row_content).right_click_popover_visible ())
Packit Service f2b131
                return false;
Packit Service f2b131
Packit Service f2b131
            int position = ((!) selected_row).get_index ();
Packit Service f2b131
            ListBoxRow? row = null;
Packit Service f2b131
            if (!is_down && (position >= 1))
Packit Service f2b131
                row = key_list_box.get_row_at_index (position - 1);
Packit Service f2b131
            if (is_down && (position < n_items - 1))
Packit Service f2b131
                row = key_list_box.get_row_at_index (position + 1);
Packit Service f2b131
Packit Service f2b131
            if (row != null)
Packit Service f2b131
            {
Packit Service f2b131
                Container list_box = (Container) ((!) selected_row).get_parent ();
Packit Service f2b131
                scroll_to_row ((!) row, list_box.get_focus_child () != null);
Packit Service f2b131
            }
Packit Service f2b131
Packit Service f2b131
            return true;
Packit Service f2b131
        }
Packit Service f2b131
        else if (n_items >= 1)
Packit Service f2b131
        {
Packit Service f2b131
            key_list_box.select_row (key_list_box.get_row_at_index (is_down ? 0 : (int) n_items - 1));
Packit Service f2b131
            return true;
Packit Service f2b131
        }
Packit Service f2b131
        return false;
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    /*\
Packit Service f2b131
    * * Keyboard calls
Packit Service f2b131
    \*/
Packit Service f2b131
Packit Service f2b131
    public string? get_copy_path_text ()
Packit Service f2b131
    {
Packit Service f2b131
        ListBoxRow? selected_row = key_list_box.get_selected_row ();
Packit Service f2b131
        if (selected_row == null)
Packit Service f2b131
            return null;
Packit Service f2b131
Packit Service f2b131
        Variant variant = ((!) selected_row).get_action_target_value ();
Packit Service f2b131
        string action_target;
Packit Service f2b131
        if (((!) variant).get_type_string () == "s")    // directory
Packit Service f2b131
            action_target = ((!) variant).get_string ();
Packit Service f2b131
        else
Packit Service f2b131
        {
Packit Service f2b131
            string unused;
Packit Service f2b131
            ((!) variant).get ("(ss)", out action_target, out unused);
Packit Service f2b131
        }
Packit Service f2b131
        return action_target;
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    /*\
Packit Service f2b131
    * * Search
Packit Service f2b131
    \*/
Packit Service f2b131
Packit Service f2b131
    private string? old_term;
Packit Service f2b131
    // indices for the start of each section. used to know where to insert search hits and to update the headers
Packit Service f2b131
    // must be updated before changing the list model, so that the header function works correctly
Packit Service f2b131
    private int post_local;
Packit Service f2b131
    private int post_bookmarks;
Packit Service f2b131
    private int post_folders;
Packit Service f2b131
    private uint? search_source = null;
Packit Service f2b131
    private GLib.Queue<Directory> search_nodes = new GLib.Queue<Directory> ();
Packit Service f2b131
Packit Service f2b131
    public void clean ()
Packit Service f2b131
    {
Packit Service f2b131
        key_list_box.bind_model (null, null);
Packit Service f2b131
        stop_global_search ();
Packit Service f2b131
        list_model.remove_all ();
Packit Service f2b131
        post_local = -1;
Packit Service f2b131
        post_bookmarks = -1;
Packit Service f2b131
        post_folders = -1;
Packit Service f2b131
        old_term = null;
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    public void start_search (string term)
Packit Service f2b131
    {
Packit Service f2b131
        if (old_term != null && term == (!) old_term)
Packit Service f2b131
        {
Packit Service f2b131
            ensure_selection ();
Packit Service f2b131
            return;
Packit Service f2b131
        }
Packit Service f2b131
Packit Service f2b131
        SettingsModel model = modifications_handler.model;
Packit Service f2b131
        if (old_term != null && term.has_prefix ((!) old_term))
Packit Service f2b131
        {
Packit Service f2b131
            pause_global_search ();
Packit Service f2b131
            refine_local_results (term);
Packit Service f2b131
            refine_bookmarks_results (term);
Packit Service f2b131
            if ((!) old_term == "")
Packit Service f2b131
                start_global_search (model, current_path, term);
Packit Service f2b131
            else
Packit Service f2b131
            {
Packit Service f2b131
                refine_global_results (term);
Packit Service f2b131
                resume_global_search (current_path, term); // update search term
Packit Service f2b131
            }
Packit Service f2b131
Packit Service f2b131
            ensure_selection ();
Packit Service f2b131
        }
Packit Service f2b131
        else
Packit Service f2b131
        {
Packit Service f2b131
            stop_global_search ();
Packit Service f2b131
            list_model.remove_all ();
Packit Service f2b131
            post_local = -1;
Packit Service f2b131
            post_folders = -1;
Packit Service f2b131
Packit Service f2b131
            local_search (model, sorting_options, SettingsModel.get_base_path (current_path), term);
Packit Service f2b131
            bookmark_search (model, current_path, term, bookmarks);
Packit Service f2b131
            key_list_box.bind_model (list_model, new_list_box_row);
Packit Service f2b131
Packit Service f2b131
            select_first_row ();
Packit Service f2b131
Packit Service f2b131
            if (term != "")
Packit Service f2b131
                start_global_search (model, current_path, term);
Packit Service f2b131
        }
Packit Service f2b131
        old_term = term;
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private void refine_local_results (string term)
Packit Service f2b131
    {
Packit Service f2b131
        for (int i = post_local - 1; i >= 0; i--)
Packit Service f2b131
        {
Packit Service f2b131
            SettingObject item = (SettingObject) list_model.get_item (i);
Packit Service f2b131
            if (!(term in item.name))
Packit Service f2b131
            {
Packit Service f2b131
                post_local--;
Packit Service f2b131
                post_bookmarks--;
Packit Service f2b131
                post_folders--;
Packit Service f2b131
                list_model.remove (i);
Packit Service f2b131
            }
Packit Service f2b131
        }
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private void refine_bookmarks_results (string term)
Packit Service f2b131
    {
Packit Service f2b131
        for (int i = post_bookmarks - 1; i >= post_local; i--)
Packit Service f2b131
        {
Packit Service f2b131
            SettingObject item = (SettingObject) list_model.get_item (i);
Packit Service f2b131
            if (!(term in item.name))
Packit Service f2b131
            {
Packit Service f2b131
                post_bookmarks--;
Packit Service f2b131
                post_folders--;
Packit Service f2b131
                list_model.remove (i);
Packit Service f2b131
            }
Packit Service f2b131
        }
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private void refine_global_results (string term)
Packit Service f2b131
    {
Packit Service f2b131
        for (int i = (int) list_model.get_n_items () - 1; i >= post_folders; i--)
Packit Service f2b131
        {
Packit Service f2b131
            SettingObject item = (SettingObject) list_model.get_item (i);
Packit Service f2b131
            if (!(term in item.name))
Packit Service f2b131
                list_model.remove (i);
Packit Service f2b131
        }
Packit Service f2b131
        for (int i = post_folders - 1; i >= post_local; i--)
Packit Service f2b131
        {
Packit Service f2b131
            SettingObject item = (SettingObject) list_model.get_item (i);
Packit Service f2b131
            if (!(term in item.name))
Packit Service f2b131
            {
Packit Service f2b131
                post_folders--;
Packit Service f2b131
                list_model.remove (i);
Packit Service f2b131
            }
Packit Service f2b131
        }
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private bool local_search (SettingsModel model, SortingOptions sorting_options, string current_path, string term)
Packit Service f2b131
    {
Packit Service f2b131
        SettingComparator comparator = sorting_options.get_comparator ();
Packit Service f2b131
        GLib.CompareDataFunc compare = (a, b) => comparator.compare((SettingObject) a, (SettingObject) b);
Packit Service f2b131
Packit Service f2b131
        if (!SettingsModel.is_key_path (current_path))
Packit Service f2b131
        {
Packit Service f2b131
            GLib.ListStore? key_model = model.get_children (current_path);
Packit Service f2b131
            for (uint i = 0; i < ((!) key_model).get_n_items (); i++)
Packit Service f2b131
            {
Packit Service f2b131
                SettingObject item = (SettingObject) ((!) key_model).get_item (i);
Packit Service f2b131
                if (term in item.name)
Packit Service f2b131
                    list_model.insert_sorted (item, compare);
Packit Service f2b131
            }
Packit Service f2b131
        }
Packit Service f2b131
        post_local = (int) list_model.get_n_items ();
Packit Service f2b131
        post_bookmarks = post_local;
Packit Service f2b131
        post_folders = post_local;
Packit Service f2b131
Packit Service f2b131
        if (term == "")
Packit Service f2b131
            return false;
Packit Service f2b131
        return true;
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private bool bookmark_search (SettingsModel model, string current_path, string term, string [] bookmarks)
Packit Service f2b131
    {
Packit Service f2b131
        string [] installed_bookmarks = {}; // TODO move check in Bookmarks
Packit Service f2b131
        foreach (string bookmark in bookmarks)
Packit Service f2b131
        {
Packit Service f2b131
            if (bookmark in installed_bookmarks)
Packit Service f2b131
                continue;
Packit Service f2b131
            installed_bookmarks += bookmark;
Packit Service f2b131
Packit Service f2b131
            if (bookmark == current_path)
Packit Service f2b131
                continue;
Packit Service f2b131
            if (SettingsModel.get_parent_path (bookmark) == current_path)
Packit Service f2b131
                continue;
Packit Service f2b131
Packit Service f2b131
            SettingObject? setting_object = model.get_object (bookmark);
Packit Service f2b131
            if (setting_object == null)
Packit Service f2b131
                continue;
Packit Service f2b131
Packit Service f2b131
            if (term in ((!) setting_object).name)
Packit Service f2b131
            {
Packit Service f2b131
                post_bookmarks++;
Packit Service f2b131
                post_folders++;
Packit Service f2b131
                list_model.insert (post_bookmarks - 1, (!) setting_object);
Packit Service f2b131
            }
Packit Service f2b131
        }
Packit Service f2b131
Packit Service f2b131
        return true;
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private void stop_global_search ()
Packit Service f2b131
    {
Packit Service f2b131
        pause_global_search ();
Packit Service f2b131
        search_nodes.clear ();
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private void start_global_search (SettingsModel model, string current_path, string term)
Packit Service f2b131
    {
Packit Service f2b131
        search_nodes.push_head (model.get_root_directory ());
Packit Service f2b131
        resume_global_search (current_path, term);
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private void pause_global_search ()
Packit Service f2b131
    {
Packit Service f2b131
        if (search_source == null)
Packit Service f2b131
            return;
Packit Service f2b131
        Source.remove ((!) search_source);
Packit Service f2b131
        search_source = null;
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private void resume_global_search (string current_path, string term)
Packit Service f2b131
    {
Packit Service f2b131
        search_source = Idle.add (() => {
Packit Service f2b131
                if (global_search_step (current_path, term))
Packit Service f2b131
                    return true;
Packit Service f2b131
                search_source = null;
Packit Service f2b131
                return false;
Packit Service f2b131
            });
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private bool global_search_step (string current_path, string term)
Packit Service f2b131
    {
Packit Service f2b131
        SettingsModel model = modifications_handler.model;
Packit Service f2b131
        if (!search_nodes.is_empty ())
Packit Service f2b131
        {
Packit Service f2b131
            Directory next = (!) search_nodes.pop_head ();
Packit Service f2b131
            bool local_again = next.full_name == current_path;
Packit Service f2b131
Packit Service f2b131
            GLib.ListStore? next_key_model = model.get_children (next.full_name);
Packit Service f2b131
            if (next_key_model == null)
Packit Service f2b131
                return true;
Packit Service f2b131
Packit Service f2b131
            for (uint i = 0; i < ((!) next_key_model).get_n_items (); i++)
Packit Service f2b131
            {
Packit Service f2b131
                SettingObject item = (SettingObject) ((!) next_key_model).get_item (i);
Packit Service f2b131
                if (item is Directory)
Packit Service f2b131
                {
Packit Service f2b131
                    if (!local_again && term in item.name)
Packit Service f2b131
                        list_model.insert (post_folders++, item);
Packit Service f2b131
                    search_nodes.push_tail ((Directory) item); // we still search local children
Packit Service f2b131
                }
Packit Service f2b131
                else
Packit Service f2b131
                {
Packit Service f2b131
                    if (!local_again && term in item.name)
Packit Service f2b131
                        list_model.append (item);
Packit Service f2b131
                }
Packit Service f2b131
            }
Packit Service f2b131
Packit Service f2b131
            ensure_selection ();
Packit Service f2b131
Packit Service f2b131
            return true;
Packit Service f2b131
        }
Packit Service f2b131
Packit Service f2b131
        return false;
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    private void update_search_results_header (ListBoxRow row, ListBoxRow? before)
Packit Service f2b131
    {
Packit Service f2b131
        string? label_text = null;
Packit Service f2b131
        if (before == null && post_local > 0)
Packit Service f2b131
            label_text = _("Current folder");
Packit Service f2b131
        else if (row.get_index () == post_local && post_local != post_bookmarks)
Packit Service f2b131
            label_text = _("Bookmarks");
Packit Service f2b131
        else if (row.get_index () == post_bookmarks && post_bookmarks != post_folders)
Packit Service f2b131
            label_text = _("Folders");
Packit Service f2b131
        else if (row.get_index () == post_folders)
Packit Service f2b131
            label_text = _("Keys");
Packit Service f2b131
Packit Service f2b131
        ListBoxRowHeader header = new ListBoxRowHeader (before == null, label_text);
Packit Service f2b131
        row.set_header (header);
Packit Service f2b131
    }
Packit Service f2b131
Packit Service f2b131
    public void set_search_parameters (string current_path, string [] bookmarks, SortingOptions sorting_options)
Packit Service f2b131
    {
Packit Service f2b131
        clean ();
Packit Service f2b131
        this.current_path = current_path;
Packit Service f2b131
        this.bookmarks = bookmarks;
Packit Service f2b131
        this.sorting_options = sorting_options;
Packit Service f2b131
    }
Packit Service f2b131
}