1/* Copyright 2016 Software Freedom Conservancy Inc.
2 *
3 * This software is licensed under the GNU LGPL (version 2.1 or later).
4 * See the COPYING file in this distribution.
5 */
6
7public class Searches.Branch : Sidebar.Branch {
8    private Gee.HashMap<SavedSearch, Searches.SidebarEntry> entry_map =
9        new Gee.HashMap<SavedSearch, Searches.SidebarEntry>();
10
11    public Branch() {
12        base (new Searches.Header(),
13            Sidebar.Branch.Options.HIDE_IF_EMPTY
14                | Sidebar.Branch.Options.AUTO_OPEN_ON_NEW_CHILD
15                | Sidebar.Branch.Options.STARTUP_EXPAND_TO_FIRST_CHILD,
16            comparator);
17
18        // seed the branch with existing searches
19        foreach (SavedSearch search in SavedSearchTable.get_instance().get_all())
20            on_saved_search_added(search);
21
22        // monitor collection for future events
23        SavedSearchTable.get_instance().search_added.connect(on_saved_search_added);
24        SavedSearchTable.get_instance().search_removed.connect(on_saved_search_removed);
25    }
26
27    ~Branch() {
28        SavedSearchTable.get_instance().search_added.disconnect(on_saved_search_added);
29        SavedSearchTable.get_instance().search_removed.disconnect(on_saved_search_removed);
30    }
31
32    public Searches.SidebarEntry? get_entry_for_saved_search(SavedSearch search) {
33        return entry_map.get(search);
34    }
35
36    private static int comparator(Sidebar.Entry a, Sidebar.Entry b) {
37        if (a == b)
38            return 0;
39
40        return SavedSearch.compare_names(((Searches.SidebarEntry) a).for_saved_search(),
41            ((Searches.SidebarEntry) b).for_saved_search());
42    }
43
44    private void on_saved_search_added(SavedSearch search) {
45        debug("search added");
46        Searches.SidebarEntry entry = new Searches.SidebarEntry(search);
47        entry_map.set(search, entry);
48        graft(get_root(), entry);
49    }
50
51    private void on_saved_search_removed(SavedSearch search) {
52        debug("search removed");
53        Searches.SidebarEntry? entry = entry_map.get(search);
54        assert(entry != null);
55
56        bool is_removed = entry_map.unset(search);
57        assert(is_removed);
58
59        prune(entry);
60    }
61}
62
63public class Searches.Header : Sidebar.Header, Sidebar.Contextable {
64    private Gtk.Builder builder;
65    private Gtk.Menu? context_menu = null;
66
67    public Header() {
68        base (_("Saved Searches"), _("Organize your saved searches"));
69        setup_context_menu();
70    }
71
72    private void setup_context_menu() {
73        this.builder = new Gtk.Builder ();
74        try {
75            this.builder.add_from_resource(Resources.get_ui("search_sidebar_context.ui"));
76            var model = builder.get_object ("popup-menu") as GLib.MenuModel;
77            this.context_menu = new Gtk.Menu.from_model (model);
78        } catch (Error error) {
79            AppWindow.error_message("Error loading UI resource: %s".printf(
80                error.message));
81            Application.get_instance().panic();
82        }
83    }
84
85    public Gtk.Menu? get_sidebar_context_menu(Gdk.EventButton? event) {
86        return context_menu;
87    }
88}
89
90public class Searches.SidebarEntry : Sidebar.SimplePageEntry, Sidebar.RenameableEntry,
91    Sidebar.DestroyableEntry {
92    private static string single_search_icon = "edit-find-symbolic";
93
94    private SavedSearch search;
95
96    public SidebarEntry(SavedSearch search) {
97        this.search = search;
98    }
99
100    internal static void init() {
101    }
102
103    internal static void terminate() {
104    }
105
106    public SavedSearch for_saved_search() {
107        return search;
108    }
109
110    public override string get_sidebar_name() {
111        return search.get_name();
112    }
113
114    public override string? get_sidebar_icon() {
115        return single_search_icon;
116    }
117
118    protected override Page create_page() {
119        return new SavedSearchPage(search);
120    }
121
122    public bool is_user_renameable() {
123        return true;
124    }
125
126    public void rename(string new_name) {
127        if (!SavedSearchTable.get_instance().exists(new_name))
128            AppWindow.get_command_manager().execute(new RenameSavedSearchCommand(search, new_name));
129        else if (new_name != search.get_name())
130            AppWindow.error_message(Resources.rename_search_exists_message(new_name));
131    }
132
133    public void destroy_source() {
134        if (Dialogs.confirm_delete_saved_search(search))
135            AppWindow.get_command_manager().execute(new DeleteSavedSearchCommand(search));
136    }
137}
138