1/* 2* Copyright (c) 2010-2013 Yorba Foundation 3* 4* This program is free software; you can redistribute it and/or 5* modify it under the terms of the GNU Lesser General Public 6* License as published by the Free Software Foundation; either 7* version 2.1 of the License, or (at your option) any later version. 8* 9* This program is distributed in the hope that it will be useful, 10* but WITHOUT ANY WARRANTY; without even the implied warranty of 11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12* General Public License for more details. 13* 14* You should have received a copy of the GNU General Public 15* License along with this program; if not, write to the 16* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17* Boston, MA 02110-1301 USA 18*/ 19 20public class OfflinePage : CheckerboardPage { 21 public const string NAME = _ ("Missing Files"); 22 23 private class OfflineView : Thumbnail { 24 public OfflineView (MediaSource source) { 25 base (source); 26 27 assert (source.is_offline ()); 28 } 29 } 30 31 private class OfflineSearchViewFilter : DefaultSearchViewFilter { 32 public override uint get_criteria () { 33 return SearchFilterCriteria.TEXT | SearchFilterCriteria.FLAG | 34 SearchFilterCriteria.MEDIA; 35 } 36 } 37 38 private OfflineSearchViewFilter search_filter = new OfflineSearchViewFilter (); 39 private MediaViewTracker tracker; 40 private Gtk.Menu page_context_menu; 41 private Gtk.Menu page_sidebar_menu; 42 43 public OfflinePage () { 44 base (NAME); 45 46 tracker = new MediaViewTracker (get_view ()); 47 48 // monitor offline and initialize view with all items in it 49 LibraryPhoto.global.offline_contents_altered.connect (on_offline_contents_altered); 50 Video.global.offline_contents_altered.connect (on_offline_contents_altered); 51 52 on_offline_contents_altered (LibraryPhoto.global.get_offline_bin_contents (), null); 53 on_offline_contents_altered (Video.global.get_offline_bin_contents (), null); 54 } 55 56 ~OfflinePage () { 57 LibraryPhoto.global.offline_contents_altered.disconnect (on_offline_contents_altered); 58 Video.global.offline_contents_altered.disconnect (on_offline_contents_altered); 59 } 60 61 public override void add_toolbar_widgets (Gtk.ActionBar toolbar) { 62 var remove_button = new Gtk.Button.with_mnemonic (Resources.REMOVE_FROM_LIBRARY_MENU); 63 remove_button.margin_start = remove_button.margin_end = 3; 64 remove_button.tooltip_text = Resources.DELETE_FROM_LIBRARY_TOOLTIP; 65 var remove_tool = new Gtk.ToolItem (); 66 remove_tool.add (remove_button); 67 toolbar.pack_start (remove_tool); 68 var remove_action = get_action ("RemoveFromLibrary"); 69 remove_action.bind_property ("sensitive", remove_button, "sensitive", BindingFlags.SYNC_CREATE); 70 remove_button.clicked.connect (() => remove_action.activate ()); 71 base.add_toolbar_widgets (toolbar); 72 } 73 74 public override Gtk.Menu? get_page_sidebar_menu () { 75 if (page_sidebar_menu == null) { 76 page_sidebar_menu = new Gtk.Menu (); 77 78 var remove_menu_item = new Gtk.CheckMenuItem.with_mnemonic (Resources.REMOVE_FROM_LIBRARY_MENU); 79 var remove_action = get_action ("RemoveFromLibrary"); 80 remove_action.bind_property ("sensitive", remove_menu_item, "sensitive", BindingFlags.SYNC_CREATE); 81 remove_menu_item.activate.connect (() => remove_action.activate ()); 82 83 page_sidebar_menu.add (remove_menu_item); 84 page_sidebar_menu.show_all (); 85 } 86 87 return page_sidebar_menu; 88 } 89 90 public override Gtk.Menu? get_page_context_menu () { 91 if (page_context_menu == null) { 92 page_context_menu = new Gtk.Menu (); 93 94 var sidebar_menu_item = new Gtk.CheckMenuItem.with_mnemonic (_("S_idebar")); 95 var sidebar_action = get_common_action ("CommonDisplaySidebar"); 96 sidebar_action.bind_property ("active", sidebar_menu_item, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); 97 98 var metadata_menu_item = new Gtk.CheckMenuItem.with_mnemonic (_("Edit Photo In_fo")); 99 var metadata_action = get_common_action ("CommonDisplayMetadataSidebar"); 100 metadata_action.bind_property ("active", metadata_menu_item, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); 101 102 var sort_menu_item = new Gtk.MenuItem.with_mnemonic (_("Sort _Events")); 103 104 var ascending_menu_item = new Gtk.RadioMenuItem.with_mnemonic (null, _("_Ascending")); 105 var ascending_action = get_common_action ("CommonSortEventsAscending"); 106 ascending_action.bind_property ("active", ascending_menu_item, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); 107 ascending_menu_item.activate.connect (() => { 108 if (ascending_menu_item.active) { 109 ascending_action.activate (); 110 } 111 }); 112 113 var descending_menu_item = new Gtk.RadioMenuItem.with_mnemonic_from_widget (ascending_menu_item, _("D_escending")); 114 var descending_action = get_common_action ("CommonSortEventsDescending"); 115 descending_action.bind_property ("active", descending_menu_item, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); 116 descending_menu_item.activate.connect (() => { 117 if (descending_menu_item.active) { 118 descending_action.activate (); 119 } 120 }); 121 122 var sort_menu = new Gtk.Menu (); 123 sort_menu.add (ascending_menu_item); 124 sort_menu.add (descending_menu_item); 125 sort_menu_item.set_submenu (sort_menu); 126 127 var select_menu_item = new Gtk.MenuItem.with_mnemonic (Resources.SELECT_ALL_MENU); 128 129 var select_action = AppWindow.get_instance ().lookup_action (AppWindow.ACTION_SELECT_ALL); 130 select_action.bind_property ("enabled", select_menu_item, "sensitive", BindingFlags.SYNC_CREATE); 131 select_menu_item.activate.connect (() => select_action.activate (null)); 132 133 page_context_menu.add (sidebar_menu_item); 134 page_context_menu.add (metadata_menu_item); 135 page_context_menu.add (new Gtk.SeparatorMenuItem ()); 136 page_context_menu.add (sort_menu_item); 137 page_context_menu.add (new Gtk.SeparatorMenuItem ()); 138 page_context_menu.add (select_menu_item); 139 page_context_menu.show_all (); 140 } 141 142 return page_context_menu; 143 } 144 145 protected override Gtk.ActionEntry[] init_collect_action_entries () { 146 Gtk.ActionEntry[] actions = base.init_collect_action_entries (); 147 148 Gtk.ActionEntry remove = { "RemoveFromLibrary", null, Resources.REMOVE_FROM_LIBRARY_MENU, "Delete", 149 Resources.DELETE_FROM_LIBRARY_TOOLTIP, on_remove_from_library 150 }; 151 actions += remove; 152 153 return actions; 154 } 155 156 public override Core.ViewTracker? get_view_tracker () { 157 return tracker; 158 } 159 160 protected override void update_actions (int selected_count, int count) { 161 set_action_sensitive ("RemoveFromLibrary", selected_count > 0); 162 163 base.update_actions (selected_count, count); 164 } 165 166 private void on_offline_contents_altered (Gee.Collection<MediaSource>? added, 167 Gee.Collection<MediaSource>? removed) { 168 if (added != null) { 169 foreach (MediaSource source in added) 170 get_view ().add (new OfflineView (source)); 171 } 172 173 if (removed != null) { 174 Marker marker = get_view ().start_marking (); 175 foreach (MediaSource source in removed) 176 marker.mark (get_view ().get_view_for_source (source)); 177 get_view ().remove_marked (marker); 178 } 179 } 180 181 private void on_remove_from_library () { 182 Gee.Collection<MediaSource> sources = 183 (Gee.Collection<MediaSource>) get_view ().get_selected_sources (); 184 if (sources.size == 0) 185 return; 186 187 if (!remove_offline_dialog (AppWindow.get_instance (), sources.size)) 188 return; 189 190 AppWindow.get_instance ().set_busy_cursor (); 191 192 ProgressDialog progress = null; 193 if (sources.size >= 20) 194 progress = new ProgressDialog (AppWindow.get_instance (), _ ("Deleting…")); 195 196 Gee.ArrayList<LibraryPhoto> photos = new Gee.ArrayList<LibraryPhoto> (); 197 Gee.ArrayList<Video> videos = new Gee.ArrayList<Video> (); 198 MediaSourceCollection.filter_media (sources, photos, videos); 199 200 if (progress != null) { 201 LibraryPhoto.global.remove_from_app (photos, false, progress.monitor); 202 Video.global.remove_from_app (videos, false, progress.monitor); 203 } else { 204 LibraryPhoto.global.remove_from_app (photos, false); 205 Video.global.remove_from_app (videos, false); 206 } 207 208 if (progress != null) 209 progress.close (); 210 211 AppWindow.get_instance ().set_normal_cursor (); 212 } 213 214 public override SearchViewFilter get_search_view_filter () { 215 return search_filter; 216 } 217} 218