diff options
Diffstat (limited to 'src/CollectionPage.vala')
-rw-r--r-- | src/CollectionPage.vala | 765 |
1 files changed, 765 insertions, 0 deletions
diff --git a/src/CollectionPage.vala b/src/CollectionPage.vala new file mode 100644 index 0000000..070452c --- /dev/null +++ b/src/CollectionPage.vala @@ -0,0 +1,765 @@ +/* Copyright 2009-2014 Yorba Foundation + * + * This software is licensed under the GNU LGPL (version 2.1 or later). + * See the COPYING file in this distribution. + */ + +public class CollectionViewManager : ViewManager { + private CollectionPage page; + + public CollectionViewManager(CollectionPage page) { + this.page = page; + } + + public override DataView create_view(DataSource source) { + return page.create_thumbnail(source); + } +} + +public abstract class CollectionPage : MediaPage { + private const double DESKTOP_SLIDESHOW_TRANSITION_SEC = 2.0; + + protected class CollectionSearchViewFilter : DefaultSearchViewFilter { + public override uint get_criteria() { + return SearchFilterCriteria.TEXT | SearchFilterCriteria.FLAG | + SearchFilterCriteria.MEDIA | SearchFilterCriteria.RATING; + } + } + + private ExporterUI exporter = null; + private CollectionSearchViewFilter search_filter = new CollectionSearchViewFilter(); + + public CollectionPage(string page_name) { + base (page_name); + + get_view().items_altered.connect(on_photos_altered); + + init_item_context_menu("/CollectionContextMenu"); + init_toolbar("/CollectionToolbar"); + + 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"); + + group.add_menu_item("Print"); + group.add_separator(); + group.add_menu_item("Publish"); + group.add_menu_item("SendTo"); + group.add_menu_item("SetBackground"); + + return group; + } + + private static InjectionGroup create_edit_menu_injectables() { + InjectionGroup group = new InjectionGroup("/MenuBar/EditMenu/EditExtrasPlaceholder"); + + group.add_menu_item("Duplicate"); + + return group; + } + + private static InjectionGroup create_view_menu_fullscreen_injectables() { + InjectionGroup group = new InjectionGroup("/MenuBar/ViewMenu/ViewExtrasFullscreenSlideshowPlaceholder"); + + group.add_menu_item("Fullscreen", "CommonFullscreen"); + group.add_separator(); + group.add_menu_item("Slideshow"); + + return group; + } + + private static InjectionGroup create_photos_menu_edits_injectables() { + InjectionGroup group = new InjectionGroup("/MenuBar/PhotosMenu/PhotosExtrasEditsPlaceholder"); + + group.add_menu_item("RotateClockwise"); + group.add_menu_item("RotateCounterclockwise"); + group.add_menu_item("FlipHorizontally"); + group.add_menu_item("FlipVertically"); + group.add_separator(); + group.add_menu_item("Enhance"); + group.add_menu_item("Revert"); + group.add_separator(); + group.add_menu_item("CopyColorAdjustments"); + group.add_menu_item("PasteColorAdjustments"); + + return group; + } + + private static InjectionGroup create_photos_menu_date_injectables() { + InjectionGroup group = new InjectionGroup("/MenuBar/PhotosMenu/PhotosExtrasDateTimePlaceholder"); + + group.add_menu_item("AdjustDateTime"); + + return group; + } + + private static InjectionGroup create_photos_menu_externals_injectables() { + InjectionGroup group = new InjectionGroup("/MenuBar/PhotosMenu/PhotosExtrasExternalsPlaceholder"); + + group.add_menu_item("ExternalEdit"); + group.add_menu_item("ExternalEditRAW"); + group.add_menu_item("PlayVideo"); + + return group; + } + + protected override void init_collect_ui_filenames(Gee.List<string> ui_filenames) { + base.init_collect_ui_filenames(ui_filenames); + + ui_filenames.add("collection.ui"); + } + + protected override Gtk.ActionEntry[] init_collect_action_entries() { + Gtk.ActionEntry[] actions = base.init_collect_action_entries(); + + Gtk.ActionEntry print = { "Print", Gtk.Stock.PRINT, TRANSLATABLE, "<Ctrl>P", + TRANSLATABLE, on_print }; + print.label = Resources.PRINT_MENU; + actions += print; + + Gtk.ActionEntry publish = { "Publish", Resources.PUBLISH, TRANSLATABLE, "<Ctrl><Shift>P", + TRANSLATABLE, on_publish }; + publish.label = Resources.PUBLISH_MENU; + publish.tooltip = Resources.PUBLISH_TOOLTIP; + actions += publish; + + Gtk.ActionEntry rotate_right = { "RotateClockwise", Resources.CLOCKWISE, + TRANSLATABLE, "<Ctrl>R", TRANSLATABLE, on_rotate_clockwise }; + rotate_right.label = Resources.ROTATE_CW_MENU; + rotate_right.tooltip = Resources.ROTATE_CW_TOOLTIP; + actions += rotate_right; + + Gtk.ActionEntry rotate_left = { "RotateCounterclockwise", Resources.COUNTERCLOCKWISE, + TRANSLATABLE, "<Ctrl><Shift>R", TRANSLATABLE, on_rotate_counterclockwise }; + rotate_left.label = Resources.ROTATE_CCW_MENU; + rotate_left.tooltip = Resources.ROTATE_CCW_TOOLTIP; + actions += rotate_left; + + Gtk.ActionEntry hflip = { "FlipHorizontally", Resources.HFLIP, TRANSLATABLE, null, + TRANSLATABLE, on_flip_horizontally }; + hflip.label = Resources.HFLIP_MENU; + actions += hflip; + + Gtk.ActionEntry vflip = { "FlipVertically", Resources.VFLIP, TRANSLATABLE, null, + TRANSLATABLE, on_flip_vertically }; + vflip.label = Resources.VFLIP_MENU; + actions += vflip; + + Gtk.ActionEntry enhance = { "Enhance", Resources.ENHANCE, TRANSLATABLE, "<Ctrl>E", + TRANSLATABLE, on_enhance }; + enhance.label = Resources.ENHANCE_MENU; + enhance.tooltip = Resources.ENHANCE_TOOLTIP; + actions += enhance; + + Gtk.ActionEntry copy_adjustments = { "CopyColorAdjustments", null, TRANSLATABLE, + "<Ctrl><Shift>C", TRANSLATABLE, on_copy_adjustments}; + copy_adjustments.label = Resources.COPY_ADJUSTMENTS_MENU; + copy_adjustments.tooltip = Resources.COPY_ADJUSTMENTS_TOOLTIP; + actions += copy_adjustments; + + Gtk.ActionEntry paste_adjustments = { "PasteColorAdjustments", null, TRANSLATABLE, + "<Ctrl><Shift>V", TRANSLATABLE, on_paste_adjustments}; + paste_adjustments.label = Resources.PASTE_ADJUSTMENTS_MENU; + paste_adjustments.tooltip = Resources.PASTE_ADJUSTMENTS_TOOLTIP; + actions += paste_adjustments; + + Gtk.ActionEntry revert = { "Revert", Gtk.Stock.REVERT_TO_SAVED, TRANSLATABLE, null, + TRANSLATABLE, on_revert }; + revert.label = Resources.REVERT_MENU; + actions += revert; + + Gtk.ActionEntry set_background = { "SetBackground", null, TRANSLATABLE, "<Ctrl>B", + TRANSLATABLE, on_set_background }; + set_background.label = Resources.SET_BACKGROUND_MENU; + set_background.tooltip = Resources.SET_BACKGROUND_TOOLTIP; + actions += set_background; + + Gtk.ActionEntry duplicate = { "Duplicate", null, TRANSLATABLE, "<Ctrl>D", TRANSLATABLE, + on_duplicate_photo }; + duplicate.label = Resources.DUPLICATE_PHOTO_MENU; + duplicate.tooltip = Resources.DUPLICATE_PHOTO_TOOLTIP; + actions += duplicate; + + Gtk.ActionEntry adjust_date_time = { "AdjustDateTime", null, TRANSLATABLE, null, + TRANSLATABLE, on_adjust_date_time }; + adjust_date_time.label = Resources.ADJUST_DATE_TIME_MENU; + actions += adjust_date_time; + + Gtk.ActionEntry external_edit = { "ExternalEdit", Gtk.Stock.EDIT, TRANSLATABLE, "<Ctrl>Return", + TRANSLATABLE, on_external_edit }; + external_edit.label = Resources.EXTERNAL_EDIT_MENU; + actions += external_edit; + + Gtk.ActionEntry edit_raw = { "ExternalEditRAW", null, TRANSLATABLE, "<Ctrl><Shift>Return", + TRANSLATABLE, on_external_edit_raw }; + edit_raw.label = Resources.EXTERNAL_EDIT_RAW_MENU; + actions += edit_raw; + + Gtk.ActionEntry slideshow = { "Slideshow", null, TRANSLATABLE, "F5", TRANSLATABLE, + on_slideshow }; + slideshow.label = _("S_lideshow"); + slideshow.tooltip = _("Play a slideshow"); + actions += slideshow; + + return actions; + } + + protected override InjectionGroup[] init_collect_injection_groups() { + InjectionGroup[] groups = base.init_collect_injection_groups(); + + groups += create_file_menu_injectables(); + groups += create_edit_menu_injectables(); + groups += create_view_menu_fullscreen_injectables(); + groups += create_photos_menu_edits_injectables(); + groups += create_photos_menu_date_injectables(); + groups += create_photos_menu_externals_injectables(); + + return groups; + } + + private bool selection_has_video() { + return MediaSourceCollection.has_video((Gee.Collection<MediaSource>) get_view().get_selected_sources()); + } + + private bool page_has_photo() { + return MediaSourceCollection.has_photo((Gee.Collection<MediaSource>) get_view().get_sources()); + } + + private bool selection_has_photo() { + return MediaSourceCollection.has_photo((Gee.Collection<MediaSource>) get_view().get_selected_sources()); + } + + protected override void init_actions(int selected_count, int count) { + base.init_actions(selected_count, count); + + set_action_short_label("RotateClockwise", Resources.ROTATE_CW_LABEL); + set_action_short_label("RotateCounterclockwise", Resources.ROTATE_CCW_LABEL); + set_action_short_label("Publish", Resources.PUBLISH_LABEL); + + set_action_important("RotateClockwise", true); + set_action_important("RotateCounterclockwise", true); + set_action_important("Enhance", true); + set_action_important("Publish", true); + } + + protected override void update_actions(int selected_count, int count) { + base.update_actions(selected_count, count); + + bool one_selected = selected_count == 1; + bool has_selected = selected_count > 0; + + bool primary_is_video = false; + if (has_selected) + if (get_view().get_selected_at(0).get_source() is Video) + primary_is_video = true; + + bool selection_has_videos = selection_has_video(); + bool page_has_photos = page_has_photo(); + + // don't allow duplication of the selection if it contains a video -- videos are huge and + // and they're not editable anyway, so there seems to be no use case for duplicating them + set_action_sensitive("Duplicate", has_selected && (!selection_has_videos)); + set_action_visible("ExternalEdit", (!primary_is_video)); + set_action_sensitive("ExternalEdit", + one_selected && !is_string_empty(Config.Facade.get_instance().get_external_photo_app())); + set_action_visible("ExternalEditRAW", + one_selected && (!primary_is_video) + && ((Photo) get_view().get_selected_at(0).get_source()).get_master_file_format() == + PhotoFileFormat.RAW + && !is_string_empty(Config.Facade.get_instance().get_external_raw_app())); + set_action_sensitive("Revert", (!selection_has_videos) && can_revert_selected()); + set_action_sensitive("Enhance", (!selection_has_videos) && has_selected); + set_action_sensitive("CopyColorAdjustments", (!selection_has_videos) && one_selected && + ((Photo) get_view().get_selected_at(0).get_source()).has_color_adjustments()); + set_action_sensitive("PasteColorAdjustments", (!selection_has_videos) && has_selected && + PixelTransformationBundle.has_copied_color_adjustments()); + set_action_sensitive("RotateClockwise", (!selection_has_videos) && has_selected); + set_action_sensitive("RotateCounterclockwise", (!selection_has_videos) && has_selected); + set_action_sensitive("FlipHorizontally", (!selection_has_videos) && has_selected); + set_action_sensitive("FlipVertically", (!selection_has_videos) && has_selected); + + // Allow changing of exposure time, even if there's a video in the current + // selection. + set_action_sensitive("AdjustDateTime", has_selected); + + set_action_sensitive("NewEvent", has_selected); + set_action_sensitive("AddTags", has_selected); + set_action_sensitive("ModifyTags", one_selected); + set_action_sensitive("Slideshow", page_has_photos && (!primary_is_video)); + set_action_sensitive("Print", (!selection_has_videos) && has_selected); + set_action_sensitive("Publish", has_selected); + + set_action_sensitive("SetBackground", (!selection_has_videos) && has_selected ); + if (has_selected) { + Gtk.Action? set_background = get_action("SetBackground"); + if (set_background != null) { + set_background.label = one_selected + ? Resources.SET_BACKGROUND_MENU + : Resources.SET_BACKGROUND_SLIDESHOW_MENU; + } + } + } + + private void on_photos_altered(Gee.Map<DataObject, Alteration> altered) { + // only check for revert if the media object is a photo and its image has changed in some + // way and it's in the selection + foreach (DataObject object in altered.keys) { + DataView view = (DataView) object; + + if (!view.is_selected() || !altered.get(view).has_subject("image")) + continue; + + LibraryPhoto? photo = view.get_source() as LibraryPhoto; + if (photo == null) + continue; + + // since the photo can be altered externally to Shotwell now, need to make the revert + // command available appropriately, even if the selection doesn't change + set_action_sensitive("Revert", can_revert_selected()); + set_action_sensitive("CopyColorAdjustments", photo.has_color_adjustments()); + + break; + } + } + + private void on_print() { + if (get_view().get_selected_count() > 0) { + PrintManager.get_instance().spool_photo( + (Gee.Collection<Photo>) get_view().get_selected_sources_of_type(typeof(Photo))); + } + } + + private void on_external_app_changed() { + int selected_count = get_view().get_selected_count(); + + set_action_sensitive("ExternalEdit", selected_count == 1 && Config.Facade.get_instance().get_external_photo_app() != ""); + } + + // see #2020 + // double clcik = switch to photo page + // Super + double click = open in external editor + // Enter = switch to PhotoPage + // Ctrl + Enter = open in external editor (handled with accelerators) + // Shift + Ctrl + Enter = open in external RAW editor (handled with accelerators) + protected override void on_item_activated(CheckerboardItem item, CheckerboardPage.Activator + activator, CheckerboardPage.KeyboardModifiers modifiers) { + Thumbnail thumbnail = (Thumbnail) item; + + // none of the fancy Super, Ctrl, Shift, etc., keyboard accelerators apply to videos, + // since they can't be RAW files or be opened in an external editor, etc., so if this is + // a video, just play it and do a short-circuit return + if (thumbnail.get_media_source() is Video) { + on_play_video(); + return; + } + + LibraryPhoto? photo = thumbnail.get_media_source() as LibraryPhoto; + if (photo == null) + return; + + // switch to full-page view or open in external editor + debug("activating %s", photo.to_string()); + + if (activator == CheckerboardPage.Activator.MOUSE) { + if (modifiers.super_pressed) + on_external_edit(); + else + LibraryWindow.get_app().switch_to_photo_page(this, photo); + } else if (activator == CheckerboardPage.Activator.KEYBOARD) { + if (!modifiers.shift_pressed && !modifiers.ctrl_pressed) + LibraryWindow.get_app().switch_to_photo_page(this, photo); + } + } + + protected override bool on_app_key_pressed(Gdk.EventKey event) { + bool handled = true; + switch (Gdk.keyval_name(event.keyval)) { + case "Page_Up": + case "KP_Page_Up": + case "Page_Down": + case "KP_Page_Down": + case "Home": + case "KP_Home": + case "End": + case "KP_End": + key_press_event(event); + break; + + case "bracketright": + activate_action("RotateClockwise"); + break; + + case "bracketleft": + activate_action("RotateCounterclockwise"); + break; + + default: + handled = false; + break; + } + + return handled ? true : base.on_app_key_pressed(event); + } + + protected override void on_export() { + if (exporter != null) + return; + + Gee.Collection<MediaSource> export_list = + (Gee.Collection<MediaSource>) get_view().get_selected_sources(); + if (export_list.size == 0) + return; + + bool has_some_photos = selection_has_photo(); + bool has_some_videos = selection_has_video(); + assert(has_some_photos || has_some_videos); + + // if we don't have any photos, then everything is a video, so skip displaying the Export + // dialog and go right to the video export operation + if (!has_some_photos) { + exporter = Video.export_many((Gee.Collection<Video>) export_list, on_export_completed); + return; + } + + string title = null; + if (has_some_videos) + title = (export_list.size == 1) ? _("Export Photo/Video") : _("Export Photos/Videos"); + else + title = (export_list.size == 1) ? _("Export Photo") : _("Export Photos"); + ExportDialog export_dialog = new ExportDialog(title); + + // Setting up the parameters object requires a bit of thinking about what the user wants. + // If the selection contains only photos, then we do what we've done in previous versions + // of Shotwell -- we use whatever settings the user selected on his last export operation + // (the thinking here being that if you've been exporting small PNGs for your blog + // for the last n export operations, then it's likely that for your (n + 1)-th export + // operation you'll also be exporting a small PNG for your blog). However, if the selection + // contains any videos, then we set the parameters to the "Current" operating mode, since + // videos can't be saved as PNGs (or any other specific photo format). + ExportFormatParameters export_params = (has_some_videos) ? ExportFormatParameters.current() : + ExportFormatParameters.last(); + + int scale; + ScaleConstraint constraint; + if (!export_dialog.execute(out scale, out constraint, ref export_params)) + return; + + Scaling scaling = Scaling.for_constraint(constraint, scale, false); + + // handle the single-photo case, which is treated like a Save As file operation + if (export_list.size == 1) { + LibraryPhoto photo = null; + foreach (LibraryPhoto p in (Gee.Collection<LibraryPhoto>) export_list) { + photo = p; + break; + } + + File save_as = + ExportUI.choose_file(photo.get_export_basename_for_parameters(export_params)); + if (save_as == null) + return; + + try { + AppWindow.get_instance().set_busy_cursor(); + photo.export(save_as, scaling, export_params.quality, + photo.get_export_format_for_parameters(export_params), export_params.mode == + ExportFormatMode.UNMODIFIED, export_params.export_metadata); + AppWindow.get_instance().set_normal_cursor(); + } catch (Error err) { + AppWindow.get_instance().set_normal_cursor(); + export_error_dialog(save_as, false); + } + + return; + } + + // multiple photos or videos + File export_dir = ExportUI.choose_dir(title); + if (export_dir == null) + return; + + exporter = new ExporterUI(new Exporter(export_list, export_dir, scaling, export_params)); + exporter.export(on_export_completed); + } + + private void on_export_completed() { + exporter = null; + } + + private bool can_revert_selected() { + foreach (DataSource source in get_view().get_selected_sources()) { + LibraryPhoto? photo = source as LibraryPhoto; + if (photo != null && (photo.has_transformations() || photo.has_editable())) + return true; + } + + return false; + } + + private bool can_revert_editable_selected() { + foreach (DataSource source in get_view().get_selected_sources()) { + LibraryPhoto? photo = source as LibraryPhoto; + if (photo != null && photo.has_editable()) + return true; + } + + return false; + } + + private void on_rotate_clockwise() { + if (get_view().get_selected_count() == 0) + return; + + RotateMultipleCommand command = new RotateMultipleCommand(get_view().get_selected(), + Rotation.CLOCKWISE, Resources.ROTATE_CW_FULL_LABEL, Resources.ROTATE_CW_TOOLTIP, + _("Rotating"), _("Undoing Rotate")); + get_command_manager().execute(command); + } + + private void on_publish() { + if (get_view().get_selected_count() > 0) + PublishingUI.PublishingDialog.go( + (Gee.Collection<MediaSource>) get_view().get_selected_sources()); + } + + private void on_rotate_counterclockwise() { + if (get_view().get_selected_count() == 0) + return; + + RotateMultipleCommand command = new RotateMultipleCommand(get_view().get_selected(), + Rotation.COUNTERCLOCKWISE, Resources.ROTATE_CCW_FULL_LABEL, Resources.ROTATE_CCW_TOOLTIP, + _("Rotating"), _("Undoing Rotate")); + get_command_manager().execute(command); + } + + private void on_flip_horizontally() { + if (get_view().get_selected_count() == 0) + return; + + RotateMultipleCommand command = new RotateMultipleCommand(get_view().get_selected(), + Rotation.MIRROR, Resources.HFLIP_LABEL, "", _("Flipping Horizontally"), + _("Undoing Flip Horizontally")); + get_command_manager().execute(command); + } + + private void on_flip_vertically() { + if (get_view().get_selected_count() == 0) + return; + + RotateMultipleCommand command = new RotateMultipleCommand(get_view().get_selected(), + Rotation.UPSIDE_DOWN, Resources.VFLIP_LABEL, "", _("Flipping Vertically"), + _("Undoing Flip Vertically")); + get_command_manager().execute(command); + } + + private void on_revert() { + if (get_view().get_selected_count() == 0) + return; + + if (can_revert_editable_selected()) { + if (!revert_editable_dialog(AppWindow.get_instance(), + (Gee.Collection<Photo>) get_view().get_selected_sources())) { + return; + } + + foreach (DataObject object in get_view().get_selected_sources()) + ((Photo) object).revert_to_master(); + } + + RevertMultipleCommand command = new RevertMultipleCommand(get_view().get_selected()); + get_command_manager().execute(command); + } + + public void on_copy_adjustments() { + if (get_view().get_selected_count() != 1) + return; + Photo photo = (Photo) get_view().get_selected_at(0).get_source(); + PixelTransformationBundle.set_copied_color_adjustments(photo.get_color_adjustments()); + set_action_sensitive("PasteColorAdjustments", true); + } + + public void on_paste_adjustments() { + PixelTransformationBundle? copied_adjustments = PixelTransformationBundle.get_copied_color_adjustments(); + if (get_view().get_selected_count() == 0 || copied_adjustments == null) + return; + + AdjustColorsMultipleCommand command = new AdjustColorsMultipleCommand(get_view().get_selected(), + copied_adjustments, Resources.PASTE_ADJUSTMENTS_LABEL, Resources.PASTE_ADJUSTMENTS_TOOLTIP); + get_command_manager().execute(command); + } + + private void on_enhance() { + if (get_view().get_selected_count() == 0) + return; + + EnhanceMultipleCommand command = new EnhanceMultipleCommand(get_view().get_selected()); + get_command_manager().execute(command); + } + + private void on_duplicate_photo() { + if (get_view().get_selected_count() == 0) + return; + + DuplicateMultiplePhotosCommand command = new DuplicateMultiplePhotosCommand( + get_view().get_selected()); + get_command_manager().execute(command); + } + + private void on_adjust_date_time() { + if (get_view().get_selected_count() == 0) + return; + + bool selected_has_videos = false; + bool only_videos_selected = true; + + foreach (DataView dv in get_view().get_selected()) { + if (dv.get_source() is Video) + selected_has_videos = true; + else + only_videos_selected = false; + } + + Dateable photo_source = (Dateable) get_view().get_selected_at(0).get_source(); + + AdjustDateTimeDialog dialog = new AdjustDateTimeDialog(photo_source, + get_view().get_selected_count(), true, selected_has_videos, only_videos_selected); + + int64 time_shift; + bool keep_relativity, modify_originals; + if (dialog.execute(out time_shift, out keep_relativity, out modify_originals)) { + AdjustDateTimePhotosCommand command = new AdjustDateTimePhotosCommand( + get_view().get_selected(), time_shift, keep_relativity, modify_originals); + get_command_manager().execute(command); + } + } + + private void on_external_edit() { + if (get_view().get_selected_count() != 1) + return; + + Photo photo = (Photo) get_view().get_selected_at(0).get_source(); + try { + AppWindow.get_instance().set_busy_cursor(); + photo.open_with_external_editor(); + AppWindow.get_instance().set_normal_cursor(); + } catch (Error err) { + AppWindow.get_instance().set_normal_cursor(); + open_external_editor_error_dialog(err, photo); + } + } + + private void on_external_edit_raw() { + if (get_view().get_selected_count() != 1) + return; + + Photo photo = (Photo) get_view().get_selected_at(0).get_source(); + if (photo.get_master_file_format() != PhotoFileFormat.RAW) + return; + + try { + AppWindow.get_instance().set_busy_cursor(); + photo.open_with_raw_external_editor(); + AppWindow.get_instance().set_normal_cursor(); + } catch (Error err) { + AppWindow.get_instance().set_normal_cursor(); + AppWindow.error_message(Resources.launch_editor_failed(err)); + } + } + + public void on_set_background() { + Gee.ArrayList<LibraryPhoto> photos = new Gee.ArrayList<LibraryPhoto>(); + MediaSourceCollection.filter_media((Gee.Collection<MediaSource>) get_view().get_selected_sources(), + photos, null); + + if (photos.size == 1) { + AppWindow.get_instance().set_busy_cursor(); + DesktopIntegration.set_background(photos[0]); + AppWindow.get_instance().set_normal_cursor(); + } else if (photos.size > 1) { + SetBackgroundSlideshowDialog dialog = new SetBackgroundSlideshowDialog(); + int delay; + if (dialog.execute(out delay)) { + AppWindow.get_instance().set_busy_cursor(); + DesktopIntegration.set_background_slideshow(photos, delay, + DESKTOP_SLIDESHOW_TRANSITION_SEC); + AppWindow.get_instance().set_normal_cursor(); + } + } + } + + private void on_slideshow() { + if (get_view().get_count() == 0) + return; + + // use first selected photo, else use first photo + Gee.List<DataSource>? sources = (get_view().get_selected_count() > 0) + ? get_view().get_selected_sources_of_type(typeof(LibraryPhoto)) + : get_view().get_sources_of_type(typeof(LibraryPhoto)); + if (sources == null || sources.size == 0) + return; + + Thumbnail? thumbnail = (Thumbnail?) get_view().get_view_for_source(sources[0]); + if (thumbnail == null) + return; + + LibraryPhoto? photo = thumbnail.get_media_source() as LibraryPhoto; + if (photo == null) + return; + + AppWindow.get_instance().go_fullscreen(new SlideshowPage(LibraryPhoto.global, get_view(), + photo)); + } + + protected override bool on_ctrl_pressed(Gdk.EventKey? event) { + Gtk.ToolButton? rotate_button = ui.get_widget("/CollectionToolbar/ToolRotate") + as Gtk.ToolButton; + if (rotate_button != null) + rotate_button.set_related_action(get_action("RotateCounterclockwise")); + + return base.on_ctrl_pressed(event); + } + + protected override bool on_ctrl_released(Gdk.EventKey? event) { + Gtk.ToolButton? rotate_button = ui.get_widget("/CollectionToolbar/ToolRotate") + as Gtk.ToolButton; + if (rotate_button != null) + rotate_button.set_related_action(get_action("RotateClockwise")); + + return base.on_ctrl_released(event); + } + + public override SearchViewFilter get_search_view_filter() { + return search_filter; + } +} + |