diff options
Diffstat (limited to 'src/Page.vala')
-rw-r--r-- | src/Page.vala | 400 |
1 files changed, 237 insertions, 163 deletions
diff --git a/src/Page.vala b/src/Page.vala index 4877a47..13caae6 100644 --- a/src/Page.vala +++ b/src/Page.vala @@ -6,50 +6,60 @@ public class InjectionGroup { public class Element { + public enum ItemType { + MENUITEM, + MENU, + SEPARATOR + } public string name; public string action; - public Gtk.UIManagerItemType kind; - - public Element(string name, string? action, Gtk.UIManagerItemType kind) { + public string? accellerator; + public ItemType kind; + + public Element(string name, string? action, string? accellerator, ItemType kind) { this.name = name; this.action = action != null ? action : name; + this.accellerator = accellerator; this.kind = kind; } } - + private string path; private Gee.ArrayList<Element?> elements = new Gee.ArrayList<Element?>(); private int separator_id = 0; - + public InjectionGroup(string path) { this.path = path; } - + public string get_path() { return path; } - + public Gee.List<Element?> get_elements() { return elements; } - - public void add_menu_item(string name, string? action = null) { - elements.add(new Element(name, action, Gtk.UIManagerItemType.MENUITEM)); + + public void add_menu_item(string name, string? action = null, string? + accellerator = null) { + elements.add(new Element(name, action, accellerator, Element.ItemType.MENUITEM)); } - + public void add_menu(string name, string? action = null) { - elements.add(new Element(name, action, Gtk.UIManagerItemType.MENU)); + elements.add(new Element(name, action, null, Element.ItemType.MENU)); } - + public void add_separator() { - elements.add(new Element("%d-separator".printf(separator_id++), null, Gtk.UIManagerItemType.SEPARATOR)); + elements.add(new Element("%d-separator".printf(separator_id++), null, + null, + Element.ItemType.SEPARATOR)); } } public abstract class Page : Gtk.ScrolledWindow { private const int CONSIDER_CONFIGURE_HALTED_MSEC = 400; - protected Gtk.UIManager ui; + protected Gtk.Builder builder = new Gtk.Builder (); protected Gtk.Toolbar toolbar; protected bool in_view = false; @@ -76,10 +86,6 @@ public abstract class Page : Gtk.ScrolledWindow { private int cursor_hide_time_cached = 0; private bool are_actions_attached = false; private OneShotScheduler? update_actions_scheduler = null; - private Gtk.ActionGroup? action_group = null; - private Gtk.ActionGroup[]? common_action_groups = null; - - private uint[] merge_ids = new uint[0]; protected Page(string page_name) { this.page_name = page_name; @@ -155,7 +161,6 @@ public abstract class Page : Gtk.ScrolledWindow { assert(this.container == null); this.container = container; - ui = ((PageWindow) container).get_ui_manager(); } public virtual void clear_container() { @@ -199,22 +204,58 @@ public abstract class Page : Gtk.ScrolledWindow { public Gtk.Widget? get_event_source() { return event_source; } - - public virtual Gtk.MenuBar get_menubar() { - Gtk.MenuBar? menubar = ui.get_widget("/MenuBar") as Gtk.MenuBar; - assert(menubar != null); - - return menubar; - } - public virtual unowned Gtk.Widget get_page_ui_widget(string path) { - return ui.get_widget(path); + private bool menubar_injected = false; + public GLib.MenuModel get_menubar() { + var model = builder.get_object ("MenuBar") as GLib.Menu; + + if (!menubar_injected) { + // Collect injected UI elements and add them to the UI manager + InjectionGroup[] injection_groups = init_collect_injection_groups(); + foreach (InjectionGroup group in injection_groups) { + var items = model.get_n_items (); + for (int i = 0; i < items; i++) { + var submenu = model.get_item_link (i, GLib.Menu.LINK_SUBMENU); + + var section = this.find_extension_point (submenu, + group.get_path ()); + + if (section == null) { + continue; + } + + foreach (var element in group.get_elements ()) { + var menu = section as GLib.Menu; + switch (element.kind) { + case InjectionGroup.Element.ItemType.MENUITEM: + var item = new GLib.MenuItem (element.name, + "win." + element.action); + if (element.accellerator != null) { + item.set_attribute ("accel", + "s", + element.accellerator); + } + + menu.append_item (item); + break; + default: + break; + } + } + } + } + + this.menubar_injected = true; + } + + return model; } public virtual Gtk.Toolbar get_toolbar() { if (toolbar == null) { toolbar = toolbar_path == null ? new Gtk.Toolbar() : - ui.get_widget(toolbar_path) as Gtk.Toolbar; + builder.get_object (toolbar_path) + as Gtk.Toolbar; toolbar.get_style_context().add_class("bottom-toolbar"); // for elementary theme toolbar.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR); } @@ -227,7 +268,6 @@ public abstract class Page : Gtk.ScrolledWindow { public virtual void switching_from() { in_view = false; - remove_ui(); if (toolbar_path != null) toolbar = null; } @@ -250,77 +290,59 @@ public abstract class Page : Gtk.ScrolledWindow { public virtual void returning_from_fullscreen(FullscreenWindow fsw) { } - - public Gtk.Action? get_action(string name) { - if (action_group == null) - return null; - - Gtk.Action? action = action_group.get_action(name); - if (action == null) - action = get_common_action(name, false); - - if (action == null) - warning("Page %s: Unable to locate action %s", get_page_name(), name); - - return action; + + public GLib.Action? get_action (string name) { + var aw = AppWindow.get_instance (); + + if (aw != null) { + return aw.lookup_action (name); + } + + return null; } public void set_action_sensitive(string name, bool sensitive) { - Gtk.Action? action = get_action(name); + GLib.SimpleAction? action = get_action(name) as GLib.SimpleAction; if (action != null) - action.sensitive = sensitive; + action.set_enabled (sensitive); } public void set_action_important(string name, bool important) { - Gtk.Action? action = get_action(name); - if (action != null) - action.is_important = important; + set_action_sensitive (name, important); } public void set_action_visible(string name, bool visible) { - Gtk.Action? action = get_action(name); - if (action == null) - return; - - action.visible = visible; - action.sensitive = visible; + set_action_sensitive (name, visible); } public void set_action_short_label(string name, string short_label) { - Gtk.Action? action = get_action(name); - if (action != null) - action.short_label = short_label; + debug ("=> Set action short_label called for %s", name); } public void set_action_details(string name, string? label, string? tooltip, bool sensitive) { - Gtk.Action? action = get_action(name); + GLib.SimpleAction? action = get_action(name) as GLib.SimpleAction; + if (action == null) return; - + if (label != null) - action.label = label; - - if (tooltip != null) - action.tooltip = tooltip; - - action.sensitive = sensitive; + this.update_menu_item_label (name, label); + + action.set_enabled (sensitive); } public void activate_action(string name) { - Gtk.Action? action = get_action(name); + var action = get_action(name); + if (action != null) - action.activate(); + action.activate (null); } - public Gtk.Action? get_common_action(string name, bool log_warning = true) { - if (common_action_groups == null) - return null; - - foreach (Gtk.ActionGroup group in common_action_groups) { - Gtk.Action? action = group.get_action(name); - if (action != null) - return action; - } + public GLib.Action? get_common_action(string name, bool log_warning = true) { + var action = get_action (name); + + if (action != null) + return action; if (log_warning) warning("Page %s: Unable to locate common action %s", get_page_name(), name); @@ -329,27 +351,23 @@ public abstract class Page : Gtk.ScrolledWindow { } public void set_common_action_sensitive(string name, bool sensitive) { - Gtk.Action? action = get_common_action(name); + var action = get_common_action(name) as GLib.SimpleAction; if (action != null) - action.sensitive = sensitive; + action.set_enabled (sensitive); } public void set_common_action_label(string name, string label) { - Gtk.Action? action = get_common_action(name); - if (action != null) - action.set_label(label); + debug ("Trying to set common action label for %s", name); } public void set_common_action_important(string name, bool important) { - Gtk.Action? action = get_common_action(name); - if (action != null) - action.is_important = important; + debug ("Setting action to important: %s", name); } public void activate_common_action(string name) { - Gtk.Action? action = get_common_action(name); + var action = get_common_action(name) as GLib.SimpleAction; if (action != null) - action.activate(); + action.activate(null); } public bool get_ctrl_pressed() { @@ -367,7 +385,14 @@ public abstract class Page : Gtk.ScrolledWindow { public bool get_super_pressed() { return super_pressed; } - + + protected void set_action_active (string name, bool active) { + var action = get_action (name) as GLib.SimpleAction; + if (action != null) { + action.set_state (active); + } + } + private bool get_modifiers(out bool ctrl, out bool alt, out bool shift, out bool super) { if (AppWindow.get_instance().get_window() == null) { ctrl = false; @@ -440,27 +465,20 @@ public abstract class Page : Gtk.ScrolledWindow { public CommandManager get_command_manager() { return AppWindow.get_command_manager(); } - + + protected virtual void add_actions () { } + + protected void on_action_toggle (GLib.Action action, Variant? value) { + Variant new_state = ! (bool) action.get_state (); + action.change_state (new_state); + } + + protected void on_action_radio (GLib.Action action, Variant? value) { + action.change_state (value); + } + private void init_ui() { - action_group = new Gtk.ActionGroup("PageActionGroup"); - - // Collect all Gtk.Actions and add them to the Page's Gtk.ActionGroup - Gtk.ActionEntry[] action_entries = init_collect_action_entries(); - if (action_entries.length > 0) - action_group.add_actions(action_entries, this); - - // Collect all Gtk.ToggleActionEntries and add them to the Gtk.ActionGroup - Gtk.ToggleActionEntry[] toggle_entries = init_collect_toggle_action_entries(); - if (toggle_entries.length > 0) - action_group.add_toggle_actions(toggle_entries, this); - - // Collect all Gtk.RadioActionEntries and add them to the Gtk.ActionGroup - // (Would use a similar collection scheme as the other calls, but there is a binding - // problem with Gtk.RadioActionCallback that doesn't allow it to be stored in a struct) - register_radio_actions(action_group); - - // Get global (common) action groups from the application window - common_action_groups = AppWindow.get_instance().get_common_action_groups(); + add_actions (); } private void add_ui() { @@ -472,34 +490,10 @@ public abstract class Page : Gtk.ScrolledWindow { foreach (string ui_filename in ui_filenames) init_load_ui(ui_filename); - - ui.insert_action_group(action_group, 0); - - // Collect injected UI elements and add them to the UI manager - InjectionGroup[] injection_groups = init_collect_injection_groups(); - foreach (InjectionGroup group in injection_groups) { - foreach (InjectionGroup.Element element in group.get_elements()) { - uint merge_id = ui.new_merge_id(); - ui.add_ui(merge_id, group.get_path(), element.name, element.action, - element.kind, false); - merge_ids += merge_id; - } - } - - AppWindow.get_instance().replace_common_placeholders(ui); - - ui.ensure_update(); - } - - private void remove_ui() { - for (int i = merge_ids.length - 1 ; i >= 0 ; --i) - ui.remove_ui(merge_ids[i]); - ui.remove_action_group(action_group); - merge_ids.resize(0); - - ui.ensure_update(); + + //ui.insert_action_group(action_group, 0); } - + public void init_toolbar(string path) { toolbar_path = path; } @@ -558,7 +552,7 @@ public abstract class Page : Gtk.ScrolledWindow { File ui_file = Resources.get_ui(ui_filename); try { - merge_ids += ui.add_ui_from_file(ui_file.get_path()); + builder.add_from_file(ui_file.get_path()); } catch (Error err) { AppWindow.error_message("Error loading UI file %s: %s".printf( ui_file.get_path(), err.message)); @@ -571,21 +565,7 @@ public abstract class Page : Gtk.ScrolledWindow { // classes' filename. protected virtual void init_collect_ui_filenames(Gee.List<string> ui_filenames) { } - - // This is called during init_ui() to collect all Gtk.ActionEntries for the page. - protected virtual Gtk.ActionEntry[] init_collect_action_entries() { - return new Gtk.ActionEntry[0]; - } - - // This is called during init_ui() to collect all Gtk.ToggleActionEntries for the page - protected virtual Gtk.ToggleActionEntry[] init_collect_toggle_action_entries() { - return new Gtk.ToggleActionEntry[0]; - } - - // This is called during init_ui() to collect all Gtk.RadioActionEntries for the page - protected virtual void register_radio_actions(Gtk.ActionGroup action_group) { - } - + // This is called during init_ui() to collect all Page.InjectedUIElements for the page. They // should be added to the MultiSet using the injection path as the key. protected virtual InjectionGroup[] init_collect_injection_groups() { @@ -1134,8 +1114,10 @@ public abstract class Page : Gtk.ScrolledWindow { protected virtual void set_page_cursor(Gdk.CursorType cursor_type) { last_cursor = cursor_type; - if (!cursor_hidden && event_source != null) - event_source.get_window().set_cursor(new Gdk.Cursor(cursor_type)); + if (!cursor_hidden && event_source != null) { + var display = event_source.get_window ().get_display (); + event_source.get_window().set_cursor(new Gdk.Cursor.for_display(display, cursor_type)); + } } private void check_cursor_hiding() { @@ -1154,14 +1136,94 @@ public abstract class Page : Gtk.ScrolledWindow { private bool on_hide_cursor() { cursor_hidden = true; - if (event_source != null) - event_source.get_window().set_cursor(new Gdk.Cursor(Gdk.CursorType.BLANK_CURSOR)); + if (event_source != null) { + var display = event_source.get_window().get_display (); + event_source.get_window().set_cursor(new Gdk.Cursor.for_display(display, Gdk.CursorType.BLANK_CURSOR)); + } // We remove the timeout so reset the id last_timeout_id = 0; return false; } + + protected void update_menu_item_label (string id, + string new_label) { + var bar = this.builder.get_object ("MenuBar") as GLib.Menu; + + if (bar == null) { + return; + } + + var items = bar.get_n_items (); + for (var i = 0; i< items; i++) { + var model = bar.get_item_link (i, GLib.Menu.LINK_SUBMENU); + if (bar == null) { + continue; + } + + var model_items = model.get_n_items (); + for (var j = 0; j < model_items; j++) { + var subsection = model.get_item_link (j, GLib.Menu.LINK_SECTION); + + if (subsection == null) + continue; + + // Recurse into submenus + var sub_items = subsection.get_n_items (); + for (var k = 0; k < sub_items; k++) { + var it = subsection.iterate_item_attributes (k); + while (it.next ()) { + if (it.get_name () == "id") { + if (it.get_value ().get_string () == id) { + var md = subsection as GLib.Menu; + var m = new GLib.MenuItem.from_model + (subsection, k); + m.set_label (new_label); + md.remove (k); + md.insert_item (k, m); + + return; + } + } + } + } + } + } + } + + protected GLib.MenuModel? find_extension_point (GLib.MenuModel model, + string extension_point) { + var items = model.get_n_items (); + GLib.MenuModel? section = null; + + for (int i = 0; i < items && section == null; i++) { + string? name = null; + model.get_item_attribute (i, "id", "s", out name); + if (name == extension_point) { + section = model.get_item_link (i, GLib.Menu.LINK_SECTION); + } else { + var subsection = model.get_item_link (i, GLib.Menu.LINK_SECTION); + + if (subsection == null) + continue; + + // Recurse into submenus + var sub_items = subsection.get_n_items (); + for (int j = 0; j < sub_items && section == null; j++) { + var submenu = subsection.get_item_link + (j, GLib.Menu.LINK_SUBMENU); + if (submenu != null) { + section = this.find_extension_point (submenu, + extension_point); + } + } + } + } + + return section; + } + } public abstract class CheckerboardPage : Page { @@ -1244,18 +1306,28 @@ public abstract class CheckerboardPage : Page { get_page_context_menu(); } + private Gtk.Menu item_context_menu; public virtual Gtk.Menu? get_item_context_menu() { - Gtk.Menu menu = (Gtk.Menu) ui.get_widget(item_context_menu_path); - assert(menu != null); - return menu; + if (item_context_menu == null) { + var model = this.builder.get_object (item_context_menu_path) + as GLib.MenuModel; + item_context_menu = new Gtk.Menu.from_model (model); + item_context_menu.attach_to_widget (this, null); + } + + return item_context_menu; } + private Gtk.Menu page_context_menu; public override Gtk.Menu? get_page_context_menu() { - if (page_context_menu_path == null) - return null; - Gtk.Menu menu = (Gtk.Menu) ui.get_widget(page_context_menu_path); - assert(menu != null); - return menu; + if (page_context_menu == null) { + var model = this.builder.get_object (page_context_menu_path) + as GLib.MenuModel; + page_context_menu = new Gtk.Menu.from_model (model); + page_context_menu.attach_to_widget (this, null); + } + + return page_context_menu; } protected override bool on_context_keypress() { @@ -2593,4 +2665,6 @@ public class DragAndDropHandler { private void on_export_completed() { exporter = null; } + + } |