Commit 365df30a authored by Adam Dingle's avatar Adam Dingle

Fixed #4562 (single shared menu for all Shotwell views) and #4841 (sidebar and...

Fixed #4562 (single shared menu for all Shotwell views) and #4841 (sidebar and menu flash during import).

With this change the LibraryWindow's UI Manager is shared by all pages in the window.  When you switch to any page, it swaps the menus and toolbars it needs into the shared UI manager, and then swaps them back out when you leave the page.

Many of the changes here were because pages were assuming that their widgets existed even when pages were not in view.  With these changes, pages can access widgets only when they are active.
parent b002e909
......@@ -15,7 +15,6 @@ public class FullscreenWindow : PageWindow {
public const int TOOLBAR_CHECK_DISMISSAL_MSEC = 500;
private Gtk.Window toolbar_window = new Gtk.Window(Gtk.WindowType.POPUP);
private Gtk.UIManager ui = new Gtk.UIManager();
private Gtk.ToolButton close_button = new Gtk.ToolButton.from_stock(Gtk.Stock.LEAVE_FULLSCREEN);
private Gtk.ToggleToolButton pin_button = new Gtk.ToggleToolButton.from_stock(Resources.PIN_TOOLBAR);
private bool is_toolbar_shown = false;
......@@ -40,13 +39,6 @@ public class FullscreenWindow : PageWindow {
ui.insert_action_group(action_group, 0);
ui.ensure_update();
// add the accelerators for the hosted page as well
Gtk.AccelGroup hosted_accel_group = page.ui.get_accel_group();
if (hosted_accel_group != null)
add_accel_group(hosted_accel_group);
// the local accelerator group must come after host accelerator group so that they cover the
// old accelerator group bindings
Gtk.AccelGroup accel_group = ui.get_accel_group();
if (accel_group != null)
add_accel_group(accel_group);
......@@ -311,6 +303,8 @@ public class FullscreenWindow : PageWindow {
// various notifications. It is the responsibility of the subclass to notify Pages when they're
// switched to and from, and other aspects of the Page interface.
public abstract class PageWindow : Gtk.Window {
protected Gtk.UIManager ui = new Gtk.UIManager();
private Page current_page = null;
private int busy_counter = 0;
......@@ -325,6 +319,10 @@ public abstract class PageWindow : Gtk.Window {
set_has_resize_grip(false);
}
public Gtk.UIManager get_ui_manager() {
return ui;
}
public Page? get_current_page() {
return current_page;
}
......@@ -431,7 +429,6 @@ public abstract class AppWindow : PageWindow {
// the AppWindow maintains its own UI manager because the first UIManager an action group is
// added to is the one that claims its accelerators
protected Gtk.UIManager ui = new Gtk.UIManager();
protected Gtk.ActionGroup[] common_action_groups;
protected bool maximized = false;
protected Dimensions dimensions;
......
......@@ -37,29 +37,37 @@ public abstract class CollectionPage : MediaPage {
init_item_context_menu("/CollectionContextMenu");
init_toolbar("/CollectionToolbar");
// separator to force slider to right side of toolbar
Gtk.SeparatorToolItem separator = new Gtk.SeparatorToolItem();
separator.set_expand(true);
separator.set_draw(false);
get_toolbar().insert(separator, -1);
Gtk.SeparatorToolItem drawn_separator = new Gtk.SeparatorToolItem();
drawn_separator.set_expand(false);
drawn_separator.set_draw(true);
get_toolbar().insert(drawn_separator, -1);
// zoom slider assembly
MediaPage.ZoomSliderAssembly zoom_slider_assembly = create_zoom_slider_assembly();
connect_slider(zoom_slider_assembly);
get_toolbar().insert(zoom_slider_assembly, -1);
show_all();
// watch for updates to the external app settings
Config.Facade.get_instance().external_app_changed.connect(on_external_app_changed);
}
public override Gtk.Toolbar get_toolbar() {
if (toolbar == null) {
base.get_toolbar();
// separator to force slider to right side of toolbar
Gtk.SeparatorToolItem separator = new Gtk.SeparatorToolItem();
separator.set_expand(true);
separator.set_draw(false);
get_toolbar().insert(separator, -1);
Gtk.SeparatorToolItem drawn_separator = new Gtk.SeparatorToolItem();
drawn_separator.set_expand(false);
drawn_separator.set_draw(true);
get_toolbar().insert(drawn_separator, -1);
// zoom slider assembly
MediaPage.ZoomSliderAssembly zoom_slider_assembly = create_zoom_slider_assembly();
connect_slider(zoom_slider_assembly);
get_toolbar().insert(zoom_slider_assembly, -1);
}
return toolbar;
}
private static InjectionGroup create_file_menu_injectables() {
InjectionGroup group = new InjectionGroup("/MenuBar/FileMenu/FileExtrasPlaceholder");
......
......@@ -225,7 +225,6 @@ public abstract class MediaPage : CheckerboardPage {
tracker = new MediaViewTracker(get_view());
get_view().set_comparator(get_sort_comparator(), get_sort_comparator_predicate());
get_view().items_altered.connect(on_media_altered);
get_view().freeze_notifications();
......@@ -269,10 +268,6 @@ public abstract class MediaPage : CheckerboardPage {
protected override Gtk.ActionEntry[] init_collect_action_entries() {
Gtk.ActionEntry[] actions = base.init_collect_action_entries();
Gtk.ActionEntry file = { "FileMenu", null, TRANSLATABLE, null, null, null };
file.label = _("_File");
actions += file;
Gtk.ActionEntry export = { "Export", Gtk.Stock.SAVE_AS, TRANSLATABLE, "<Ctrl><Shift>E",
TRANSLATABLE, on_export };
export.label = Resources.EXPORT_MENU;
......@@ -283,10 +278,6 @@ public abstract class MediaPage : CheckerboardPage {
send_to.label = Resources.SEND_TO_MENU;
actions += send_to;
Gtk.ActionEntry edit = { "EditMenu", null, TRANSLATABLE, null, null, null };
edit.label = _("_Edit");
actions += edit;
Gtk.ActionEntry remove_from_library = { "RemoveFromLibrary", Gtk.Stock.REMOVE, TRANSLATABLE,
"<Shift>Delete", TRANSLATABLE, on_remove_from_library };
remove_from_library.label = Resources.REMOVE_FROM_LIBRARY_MENU;
......@@ -297,18 +288,6 @@ public abstract class MediaPage : CheckerboardPage {
move_to_trash.label = Resources.MOVE_TO_TRASH_MENU;
actions += move_to_trash;
Gtk.ActionEntry photos = { "PhotosMenu", null, TRANSLATABLE, null, null, null };
photos.label = _("_Photos");
actions += photos;
Gtk.ActionEntry event = { "EventsMenu", null, TRANSLATABLE, null, null, null };
event.label = _("Even_ts");
actions += event;
Gtk.ActionEntry tags = { "TagsMenu", null, TRANSLATABLE, null, null, null };
tags.label = _("Ta_gs");
actions += tags;
Gtk.ActionEntry new_event = { "NewEvent", Gtk.Stock.NEW, TRANSLATABLE, "<Ctrl>N",
TRANSLATABLE, on_new_event };
new_event.label = Resources.NEW_EVENT_MENU;
......@@ -394,10 +373,6 @@ public abstract class MediaPage : CheckerboardPage {
edit_title.label = Resources.EDIT_TITLE_MENU;
actions += edit_title;
Gtk.ActionEntry view = { "ViewMenu", null, TRANSLATABLE, null, null, null };
view.label = _("_View");
actions += view;
Gtk.ActionEntry sort_photos = { "SortPhotos", null, TRANSLATABLE, null, null, null };
sort_photos.label = _("Sort _Photos");
actions += sort_photos;
......@@ -406,10 +381,6 @@ public abstract class MediaPage : CheckerboardPage {
filter_photos.label = Resources.FILTER_PHOTOS_MENU;
actions += filter_photos;
Gtk.ActionEntry help = { "HelpMenu", null, TRANSLATABLE, null, null, null };
help.label = _("_Help");
actions += help;
Gtk.ActionEntry play = { "PlayVideo", Gtk.Stock.MEDIA_PLAY, TRANSLATABLE, "<Ctrl>Y",
TRANSLATABLE, on_play_video };
play.label = _("_Play Video");
......@@ -1044,10 +1015,12 @@ public abstract class MediaPage : CheckerboardPage {
protected abstract void set_config_photos_sort(bool sort_order, int sort_by);
protected virtual void on_sort_changed() {
get_view().set_comparator(get_sort_comparator(), get_sort_comparator_predicate());
set_config_photos_sort(get_sort_order() == SORT_ORDER_ASCENDING, get_sort_criteria());
public virtual void on_sort_changed() {
int sort_by = get_menu_sort_by();
bool sort_order = get_menu_sort_order();
set_view_comparator(sort_by, sort_order);
set_config_photos_sort(sort_order, sort_by);
}
public void on_raw_developer_shotwell(Gtk.Action action) {
......@@ -1083,73 +1056,70 @@ public abstract class MediaPage : CheckerboardPage {
action.set_active(display);
}
protected int get_sort_criteria() {
// any member of the group knows the current value
Gtk.RadioAction action = (Gtk.RadioAction) ui.get_action(
"/MenuBar/ViewMenu/SortPhotos/SortByTitle");
private Gtk.RadioAction sort_by_title_action() {
Gtk.RadioAction action = (Gtk.RadioAction) get_action("SortByTitle");
assert(action != null);
int value = action.get_current_value();
return action;
}
return value;
private Gtk.RadioAction sort_ascending_action() {
Gtk.RadioAction action = (Gtk.RadioAction) get_action("SortAscending");
assert(action != null);
return action;
}
protected int get_sort_order() {
protected int get_menu_sort_by() {
// any member of the group knows the current value
Gtk.RadioAction action = (Gtk.RadioAction) ui.get_action(
"/MenuBar/ViewMenu/SortPhotos/SortAscending");
assert(action != null);
int value = action.get_current_value();
return value;
return sort_by_title_action().get_current_value();
}
protected bool is_sort_ascending() {
return get_sort_order() == SORT_ORDER_ASCENDING;
protected void set_menu_sort_by(int val) {
sort_by_title_action().set_current_value(val);
}
protected Comparator get_sort_comparator() {
switch (get_sort_criteria()) {
case SortBy.TITLE:
if (is_sort_ascending())
return Thumbnail.title_ascending_comparator;
else
return Thumbnail.title_descending_comparator;
case SortBy.EXPOSURE_DATE:
if (is_sort_ascending())
return Thumbnail.exposure_time_ascending_comparator;
else
return Thumbnail.exposure_time_desending_comparator;
case SortBy.RATING:
if (is_sort_ascending())
return Thumbnail.rating_ascending_comparator;
else
return Thumbnail.rating_descending_comparator;
default:
error("Unknown sort criteria: %s", get_sort_criteria().to_string());
}
protected bool get_menu_sort_order() {
// any member of the group knows the current value
return sort_ascending_action().get_current_value() == SORT_ORDER_ASCENDING;
}
protected void set_menu_sort_order(bool ascending) {
sort_ascending_action().set_current_value(
ascending ? SORT_ORDER_ASCENDING : SORT_ORDER_DESCENDING);
}
protected ComparatorPredicate get_sort_comparator_predicate() {
switch (get_sort_criteria()) {
void set_view_comparator(int sort_by, bool ascending) {
Comparator comparator;
ComparatorPredicate predicate;
switch (sort_by) {
case SortBy.TITLE:
return Thumbnail.title_comparator_predicate;
if (ascending)
comparator = Thumbnail.title_ascending_comparator;
else comparator = Thumbnail.title_descending_comparator;
predicate = Thumbnail.title_comparator_predicate;
break;
case SortBy.EXPOSURE_DATE:
return Thumbnail.exposure_time_comparator_predicate;
if (ascending)
comparator = Thumbnail.exposure_time_ascending_comparator;
else comparator = Thumbnail.exposure_time_desending_comparator;
predicate = Thumbnail.exposure_time_comparator_predicate;
break;
case SortBy.RATING:
return Thumbnail.rating_comparator_predicate;
if (ascending)
comparator = Thumbnail.rating_ascending_comparator;
else comparator = Thumbnail.rating_descending_comparator;
predicate = Thumbnail.rating_comparator_predicate;
break;
default:
error("Unknown sort criteria: %s", get_sort_criteria().to_string());
error("Unknown sort criteria: %s", get_menu_sort_by().to_string());
}
get_view().set_comparator(comparator, predicate);
}
protected string get_sortby_path(int sort_by) {
switch(sort_by) {
case SortBy.TITLE:
......@@ -1180,7 +1150,15 @@ public abstract class MediaPage : CheckerboardPage {
// Although this means we pay for a re-sort every time, in practice,
// this isn't terribly expensive - it _might_ take as long as .5 sec.
// with a media page containing over 15000 items on a modern CPU.
get_view().set_comparator(get_sort_comparator(), get_sort_comparator_predicate());
bool sort_ascending;
int sort_by;
get_config_photos_sort(out sort_ascending, out sort_by);
set_menu_sort_by(sort_by);
set_menu_sort_order(sort_ascending);
set_view_comparator(sort_by, sort_ascending);
}
public override void destroy() {
......
......@@ -48,16 +48,17 @@ public class InjectionGroup {
public abstract class Page : Gtk.ScrolledWindow {
private const int CONSIDER_CONFIGURE_HALTED_MSEC = 400;
public Gtk.UIManager ui = new Gtk.UIManager();
protected Gtk.UIManager ui;
protected Gtk.Toolbar toolbar;
protected bool in_view = false;
private string page_name;
private ViewCollection view = null;
private Gtk.Window container = null;
private Gtk.Toolbar toolbar = new Gtk.Toolbar();
private string toolbar_path;
private Gdk.Rectangle last_position = Gdk.Rectangle();
private Gtk.Widget event_source = null;
private bool dnd_enabled = false;
private bool in_view = false;
private ulong last_configure_ms = 0;
private bool report_move_finished = false;
private bool report_resize_finished = false;
......@@ -77,6 +78,8 @@ public abstract class Page : Gtk.ScrolledWindow {
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;
......@@ -101,12 +104,6 @@ public abstract class Page : Gtk.ScrolledWindow {
#endif
}
private void destroy_ui_manager_widgets(Gtk.UIManagerItemType item_type) {
SList<weak Gtk.Widget> toplevels = ui.get_toplevels(item_type);
for (int ctr = 0; ctr < toplevels.length(); ctr++)
toplevels.nth(ctr).data.destroy();
}
// This is called by the page controller when it has removed this page ... pages should override
// this (or the signal) to clean up
public override void destroy() {
......@@ -121,19 +118,8 @@ public abstract class Page : Gtk.ScrolledWindow {
// remove refs to external objects which may be pointing to the Page
clear_container();
// Without destroying the menubar, Gtk spits out an assertion related to
// a Gtk.AccelLabel being unable to disconnect a signal from the UI Manager's
// Gtk.AccelGroup because the AccelGroup has already been finalized. This only
// happens during a drag-and-drop operation where the Page is destroyed.
// Destroying the menubar explicitly solves this problem. These calls go through and
// ensure *all* widgets created by the UI manager are destroyed.
destroy_ui_manager_widgets(Gtk.UIManagerItemType.MENUBAR);
destroy_ui_manager_widgets(Gtk.UIManagerItemType.TOOLBAR);
destroy_ui_manager_widgets(Gtk.UIManagerItemType.POPUP);
// toolbars (as of yet) are not created by the UI Manager and need to be destroyed
// explicitly
toolbar.destroy();
if (toolbar != null)
toolbar.destroy();
// halt any pending callbacks
if (update_actions_scheduler != null)
......@@ -170,6 +156,7 @@ public abstract class Page : Gtk.ScrolledWindow {
assert(this.container == null);
this.container = container;
ui = ((PageWindow) container).get_ui_manager();
}
public virtual void clear_container() {
......@@ -226,6 +213,9 @@ public abstract class Page : Gtk.ScrolledWindow {
}
public virtual Gtk.Toolbar get_toolbar() {
if (toolbar == null)
toolbar = toolbar_path == null ? new Gtk.Toolbar() :
ui.get_widget(toolbar_path) as Gtk.Toolbar;
return toolbar;
}
......@@ -235,10 +225,14 @@ public abstract class Page : Gtk.ScrolledWindow {
public virtual void switching_from() {
in_view = false;
remove_ui();
if (toolbar_path != null)
toolbar = null;
}
public virtual void switched_to() {
in_view = true;
add_ui();
update_modifiers();
}
......@@ -443,15 +437,6 @@ public abstract class Page : Gtk.ScrolledWindow {
}
private void init_ui() {
// Collect all UI filenames and load them into the UI manager
Gee.List<string> ui_filenames = new Gee.ArrayList<string>();
init_collect_ui_filenames(ui_filenames);
if (ui_filenames.size == 0)
message("No UI file specified for %s", get_page_name());
foreach (string ui_filename in ui_filenames)
init_load_ui(ui_filename);
action_group = new Gtk.ActionGroup("PageActionGroup");
// Collect all Gtk.Actions and add them to the Page's Gtk.ActionGroup
......@@ -471,18 +456,28 @@ public abstract class Page : Gtk.ScrolledWindow {
// Get global (common) action groups from the application window
common_action_groups = AppWindow.get_instance().get_common_action_groups();
}
private void add_ui() {
// Collect all UI filenames and load them into the UI manager
Gee.List<string> ui_filenames = new Gee.ArrayList<string>();
init_collect_ui_filenames(ui_filenames);
if (ui_filenames.size == 0)
message("No UI file specified for %s", get_page_name());
// Add all ActionGroups to the UIManager
foreach (string ui_filename in ui_filenames)
init_load_ui(ui_filename);
ui.insert_action_group(action_group, 0);
foreach (Gtk.ActionGroup group in common_action_groups)
ui.insert_action_group(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()) {
ui.add_ui(ui.new_merge_id(), group.get_path(), element.name, element.action,
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;
}
}
......@@ -491,11 +486,17 @@ public abstract class Page : Gtk.ScrolledWindow {
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();
}
public void init_toolbar(string path) {
// safely replace existing toolbar (so get_toolbar() never returns null)
Gtk.Toolbar? ui_toolbar = ui.get_widget(path) as Gtk.Toolbar;
if (ui_toolbar != null)
toolbar = ui_toolbar;
toolbar_path = path;
}
// Called from "realize"
......@@ -552,7 +553,7 @@ public abstract class Page : Gtk.ScrolledWindow {
File ui_file = Resources.get_ui(ui_filename);
try {
ui.add_ui_from_file(ui_file.get_path());
merge_ids += ui.add_ui_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));
......@@ -1160,8 +1161,8 @@ public abstract class CheckerboardPage : Page {
private const int AUTOSCROLL_TICKS_MSEC = 50;
private CheckerboardLayout layout;
private Gtk.Menu item_context_menu = null;
private Gtk.Menu page_context_menu = null;
private string item_context_menu_path = null;
private string page_context_menu_path = null;
private Gtk.Viewport viewport = new Gtk.Viewport(null, null);
protected CheckerboardItem anchor = null;
protected CheckerboardItem cursor = null;
......@@ -1226,11 +1227,11 @@ public abstract class CheckerboardPage : Page {
}
public void init_item_context_menu(string path) {
item_context_menu = (Gtk.Menu) ui.get_widget(path);
item_context_menu_path = path;
}
public void init_page_context_menu(string path) {
page_context_menu = (Gtk.Menu) ui.get_widget(path);
page_context_menu_path = path;
}
public Gtk.Menu? get_context_menu() {
......@@ -1240,11 +1241,17 @@ public abstract class CheckerboardPage : Page {
}
public virtual Gtk.Menu? get_item_context_menu() {
return item_context_menu;
Gtk.Menu menu = (Gtk.Menu) ui.get_widget(item_context_menu_path);
assert(menu != null);
return menu;
}
public override Gtk.Menu? get_page_context_menu() {
return 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;
}
protected override bool on_context_keypress() {
......
......@@ -2267,7 +2267,6 @@ public class LibraryPhotoPage : EditingHostPage {
}
}
private Gtk.Menu context_menu;
#if ENABLE_FACES
private Gtk.ToggleToolButton faces_button = null;
#endif
......@@ -2278,8 +2277,6 @@ public class LibraryPhotoPage : EditingHostPage {
public LibraryPhotoPage() {
base(LibraryPhoto.global, "Photo");
context_menu = (Gtk.Menu) ui.get_widget("/PhotoContextMenu");
// monitor view to update UI elements
get_view().items_altered.connect(on_photos_altered);
......@@ -2317,16 +2314,13 @@ public class LibraryPhotoPage : EditingHostPage {
protected override void init_collect_ui_filenames(Gee.List<string> ui_filenames) {
base.init_collect_ui_filenames(ui_filenames);
ui_filenames.add("photo_context.ui");
ui_filenames.add("photo.ui");
}
protected override Gtk.ActionEntry[] init_collect_action_entries() {
Gtk.ActionEntry[] actions = base.init_collect_action_entries();
Gtk.ActionEntry file = { "FileMenu", null, TRANSLATABLE, null, null, null };
file.label = _("_File");
actions += file;
Gtk.ActionEntry export = { "Export", Gtk.Stock.SAVE_AS, TRANSLATABLE, "<Ctrl><Shift>E",
TRANSLATABLE, on_export };
export.label = Resources.EXPORT_MENU;
......@@ -2343,10 +2337,6 @@ public class LibraryPhotoPage : EditingHostPage {
publish.tooltip = Resources.PUBLISH_TOOLTIP;
actions += publish;
Gtk.ActionEntry edit = { "EditMenu", null, TRANSLATABLE, null, null, null };
edit.label = _("_Edit");
actions += edit;
Gtk.ActionEntry remove_from_library = { "RemoveFromLibrary", Gtk.Stock.REMOVE, TRANSLATABLE,
"<Shift>Delete", TRANSLATABLE, on_remove_from_library };
remove_from_library.label = Resources.REMOVE_FROM_LIBRARY_MENU;
......@@ -2361,10 +2351,6 @@ public class LibraryPhotoPage : EditingHostPage {
view.label = _("_View");
actions += view;
Gtk.ActionEntry photo = { "PhotoMenu", null, TRANSLATABLE, null, null, null };
photo.label = _("_Photo");
actions += photo;
Gtk.ActionEntry tools = { "Tools", null, TRANSLATABLE, null, null, null };
tools.label = _("T_ools");
actions += tools;
......@@ -2522,10 +2508,6 @@ public class LibraryPhotoPage : EditingHostPage {
rate_five.label = Resources.rating_menu(Rating.FIVE);
actions += rate_five;
Gtk.ActionEntry help = { "HelpMenu", null, TRANSLATABLE, null, null, null };
help.label = _("_Help");
actions += help;
Gtk.ActionEntry increase_size = { "IncreaseSize", Gtk.Stock.ZOOM_IN, TRANSLATABLE,
"<Ctrl>plus", TRANSLATABLE, on_increase_size };
increase_size.label = _("Zoom _In");
......@@ -2556,10 +2538,6 @@ public class LibraryPhotoPage : EditingHostPage {
max_size.tooltip = _("Zoom the photo to 200% magnification");
actions += max_size;
Gtk.ActionEntry tags = { "TagsMenu", null, TRANSLATABLE, null, null, null };
tags.label = _("Ta_gs");
actions += tags;
Gtk.ActionEntry add_tags = { "AddTags", null, TRANSLATABLE, "<Ctrl>T", TRANSLATABLE,
on_add_tags };
add_tags.label = Resources.ADD_TAGS_MENU;
......@@ -2979,14 +2957,20 @@ public class LibraryPhotoPage : EditingHostPage {
return base.on_left_released(event);
}
private Gtk.Menu get_context_menu() {
Gtk.Menu menu = (Gtk.Menu) ui.get_widget("/PhotoContextMenu");
assert(menu != null);
return menu;
}
protected override bool on_context_buttonpress(Gdk.EventButton event) {
popup_context_menu(context_menu, event);
popup_context_menu(get_context_menu(), event);
return true;
}
protected override bool on_context_keypress() {
popup_context_menu(context_menu);
popup_context_menu(get_context_menu());
return true;
}
......
......@@ -726,64 +726,6 @@ public class ImportPage : CheckerboardPage {
init_item_context_menu("/ImportContextMenu");
init_page_context_menu("/ImportContextMenu");
// Set up toolbar
Gtk.Toolbar toolbar = get_toolbar();
// hide duplicates checkbox
hide_imported = new Gtk.CheckButton.with_label(_("Hide photos already imported"));
hide_imported.set_tooltip_text(_("Only display photos that have not been imported"));
hide_imported.clicked.connect(on_hide_imported);
hide_imported.sensitive = false;
hide_imported.active = Config.Facade.get_instance().get_hide_photos_already_imported();
Gtk.ToolItem hide_item = new Gtk.ToolItem();
hide_item.is_important = true;
hide_item.add(hide_imported);
toolbar.insert(hide_item, -1);
// separator to force buttons to right side of toolbar
Gtk.SeparatorToolItem separator = new Gtk.SeparatorToolItem();
separator.set_draw(false);
toolbar.insert(separator, -1);
// progress bar in center of toolbar
progress_bar.set_orientation(Gtk.Orientation.HORIZONTAL);
progress_bar.visible = false;
Gtk.ToolItem progress_item = new Gtk.ToolItem();
progress_item.set_expand(true);
progress_item.add(progress_bar);
progress_bar.set_show_text(true);
toolbar.insert(progress_item, -1);
// Find button
Gtk.ToggleToolButton find_button = new Gtk.ToggleToolButton();
find_button.set_related_action(get_action("CommonDisplaySearchbar"));
toolbar.insert(find_button, -1);
// Separator
toolbar.insert(new Gtk.SeparatorToolItem(), -1);
// Import selected
Gtk.ToolButton import_selected_button = new Gtk.ToolButton.from_stock(Resources.IMPORT);
import_selected_button.set_related_action(get_action("ImportSelected"));
toolbar.insert(import_selected_button, -1);
// Import all
Gtk.ToolButton import_all_button = new Gtk.ToolButton.from_stock(Resources.IMPORT_ALL);
import_all_button.set_related_action(get_action("ImportAll"));
toolbar.insert(import_all_button, -1);
// restrain the recalcitrant rascal! prevents the progress bar from being added to the
// show_all queue so we have more control over its visibility
progress_bar.set_no_show_all(true);
show_all();
}
~ImportPage() {
......@@ -791,6 +733,71 @@ public class ImportPage : CheckerboardPage {
Video.global.contents_altered.disconnect(on_media_added_removed);
}
public override Gtk.Toolbar get_toolbar() {
if (toolbar == null) {
base.get_toolbar();
// hide duplicates checkbox
hide_imported = new Gtk.CheckButton.with_label(_("Hide photos already imported"));
hide_imported.set_tooltip_text(_("Only display photos that have not been imported"));
hide_imported.clicked.connect(on_hide_imported);
hide_imported.sensitive = false;
hide_imported.active = Config.Facade.get_instance().get_hide_photos_already_imported();
Gtk.ToolItem hide_item = new Gtk.ToolItem();
hide_item.is_important = true;
hide_item.add(hide_imported);
toolbar.insert(hide_item, -1);
// separator to force buttons to right side of toolbar
Gtk.SeparatorToolItem separator = new Gtk.SeparatorToolItem();