EventsDirectoryPage.vala 9.75 KB
Newer Older
1
/* Copyright 2009-2012 Yorba Foundation
2 3 4 5
 *
 * This software is licensed under the GNU LGPL (version 2.1 or later).
 * See the COPYING file in this distribution. 
 */
6

7
public abstract class EventsDirectoryPage : CheckerboardPage {
8
    public class EventDirectoryManager : ViewManager {
9 10
        public override DataView create_view(DataSource source) {
            return new EventDirectoryItem((Event) source);
11 12
        }
    }
13 14 15 16 17 18 19 20 21 22
    
    private class EventsDirectorySearchViewFilter : SearchViewFilter {
        public override uint get_criteria() {
            return SearchFilterCriteria.TEXT;
        }

        public override bool predicate(DataView view) {
            assert(view.get_source() is Event);
            if (is_string_empty(get_search_filter()))
                return true;
23
            
24
            Event source = (Event) view.get_source();
25 26
            unowned string? event_keywords = source.get_indexable_keywords();
            if (is_string_empty(event_keywords))
27
                return false;
28 29 30 31 32 33 34
            
            // Return false if the word isn't found, true otherwise.
            foreach (unowned string word in get_search_filter_words()) {
                if (!event_keywords.contains(word))
                    return false;
            }
            
35 36 37
            return true;
        }
    }
38
   
39 40
    private const int MIN_PHOTOS_FOR_PROGRESS_WINDOW = 50;

41
    protected ViewManager view_manager;
42 43
    
    private EventsDirectorySearchViewFilter search_filter = new EventsDirectorySearchViewFilter();
44

45
    public EventsDirectoryPage(string page_name, ViewManager view_manager,
46
        Gee.Collection<Event>? initial_events) {
47
        base (page_name);
48 49
        
        // set comparator before monitoring source collection, to prevent a re-sort
Lucas Beeler's avatar
Lucas Beeler committed
50
        get_view().set_comparator(get_event_comparator(Config.Facade.get_instance().get_events_sort_ascending()), 
51
            event_comparator_predicate);
52
        get_view().monitor_source_collection(Event.global, view_manager, null, initial_events);
53
        
54
        init_item_context_menu("/EventsDirectoryContextMenu");
55 56

        this.view_manager = view_manager;
57 58

        // set up page's toolbar (used by AppWindow for layout and FullscreenWindow as a popup)
59 60
        Gtk.Toolbar toolbar = get_toolbar();
        
61
        // merge tool
62
        Gtk.ToolButton merge_button = new Gtk.ToolButton.from_stock(Resources.MERGE);
63
        merge_button.set_related_action(get_action("Merge"));
64
        
65 66
        toolbar.insert(merge_button, -1);
    }
67
    
68 69 70 71 72 73
    ~EventsDirectoryPage() {
        Gtk.RadioAction? action = get_action("CommonSortEventsAscending") as Gtk.RadioAction;
        assert(action != null);
        action.changed.disconnect(on_sort_changed);
    }
    
74 75 76 77 78 79
    protected override void init_collect_ui_filenames(Gee.List<string> ui_filenames) {
        ui_filenames.add("events_directory.ui");
        
        base.init_collect_ui_filenames(ui_filenames);
    }

80 81 82 83
    protected static bool event_comparator_predicate(DataObject object, Alteration alteration) {
        return alteration.has_detail("metadata", "time");
    }
    
84
    private static int64 event_ascending_comparator(void *a, void *b) {
85 86 87 88 89 90
        time_t start_a = ((EventDirectoryItem *) a)->event.get_start_time();
        time_t start_b = ((EventDirectoryItem *) b)->event.get_start_time();
        
        return start_a - start_b;
    }
    
91
    private static int64 event_descending_comparator(void *a, void *b) {
92 93 94
        return event_ascending_comparator(b, a);
    }
    
95 96
    private static Comparator get_event_comparator(bool ascending) {
        if (ascending)
97 98 99 100 101
            return event_ascending_comparator;
        else
            return event_descending_comparator;
    }
    
102 103
    protected override Gtk.ActionEntry[] init_collect_action_entries() {
        Gtk.ActionEntry[] actions = base.init_collect_action_entries();
104 105 106 107
        
        Gtk.ActionEntry file = { "FileMenu", null, TRANSLATABLE, null, null, null };
        file.label = _("_File");
        actions += file;
108
        
109
        Gtk.ActionEntry view = { "ViewMenu", null, TRANSLATABLE, null, null, null };
110 111 112 113 114 115 116
        view.label = _("_View");
        actions += view;

        Gtk.ActionEntry help = { "HelpMenu", null, TRANSLATABLE, null, null, null };
        help.label = _("_Help");
        actions += help;

117
        Gtk.ActionEntry edit = { "EditMenu", null, TRANSLATABLE, null, null, null };
118 119 120
        edit.label = _("_Edit");
        actions += edit;

121
        Gtk.ActionEntry event = { "EventsMenu", null, TRANSLATABLE, null, null, null };
122 123 124
        event.label = _("Even_ts");
        actions += event;

125
        Gtk.ActionEntry rename = { "Rename", null, TRANSLATABLE, "F2", TRANSLATABLE, on_rename };
126
        rename.label = Resources.RENAME_EVENT_MENU;
127 128
        actions += rename;
       
129
        Gtk.ActionEntry merge = { "Merge", Resources.MERGE, TRANSLATABLE, null, TRANSLATABLE,
Lucas Beeler's avatar
Lucas Beeler committed
130
            on_merge };
131
        merge.label = Resources.MERGE_MENU;
132
        actions += merge;
133
        
134 135 136
        return actions;
    }
    
137 138 139 140 141 142 143 144
    protected override void init_actions(int selected_count, int count) {
        base.init_actions(selected_count, count);
        
        Gtk.RadioAction? action = get_action("CommonSortEventsAscending") as Gtk.RadioAction;
        assert(action != null);
        action.changed.connect(on_sort_changed);
    }
    
145 146 147 148 149 150 151
    protected override void update_actions(int selected_count, int count) {
        set_action_sensitive("Merge", selected_count > 1);
        set_action_important("Merge", true);
        set_action_sensitive("Rename", selected_count == 1);
        
        base.update_actions(selected_count, count);
    }
152 153 154 155 156 157 158 159

    protected override string get_view_empty_message() {
        return _("No events");
    }

    protected override string get_filter_no_match_message() {
        return _("No events found");
    }
160
    
161 162
    public override void on_item_activated(CheckerboardItem item, CheckerboardPage.Activator 
        activator, CheckerboardPage.KeyboardModifiers modifiers) {
163 164
        EventDirectoryItem event = (EventDirectoryItem) item;
        LibraryWindow.get_app().switch_to_event(event.event);
165
    }
166
    
167 168 169 170 171 172
    private void on_sort_changed(Gtk.Action action, Gtk.Action c) {
        Gtk.RadioAction current = (Gtk.RadioAction) c;
        
        get_view().set_comparator(
            get_event_comparator(current.current_value == LibraryWindow.SORT_EVENTS_ORDER_ASCENDING),
            event_comparator_predicate);
173 174
    }
    
175
    private void on_rename() {
176
        // only rename one at a time
177
        if (get_view().get_selected_count() != 1)
178 179 180
            return;
        
        EventDirectoryItem item = (EventDirectoryItem) get_view().get_selected_at(0);
181
        
182
        EventRenameDialog rename_dialog = new EventRenameDialog(item.event.get_raw_name());
183 184 185 186 187 188
        string? new_name = rename_dialog.execute();
        if (new_name == null)
            return;
        
        RenameEventCommand command = new RenameEventCommand(item.event, new_name);
        get_command_manager().execute(command);
189
    }
190 191 192 193
    
    private void on_merge() {
        if (get_view().get_selected_count() <= 1)
            return;
194 195 196
        
        MergeEventsCommand command = new MergeEventsCommand(get_view().get_selected());
        get_command_manager().execute(command);
197
    }
198 199 200 201
    
    public override SearchViewFilter get_search_view_filter() {
       return search_filter;
    }
202 203
}

204
public class MasterEventsDirectoryPage : EventsDirectoryPage {
205
    public const string NAME = _("Events");
206
    
207 208
    public MasterEventsDirectoryPage() {
        base (NAME, new EventDirectoryManager(), (Gee.Collection<Event>) Event.global.get_all());
209
    }
210 211 212
}

public class SubEventsDirectoryPage : EventsDirectoryPage {
213
    public enum DirectoryType {
214
        YEAR,
215 216
        MONTH,
        UNDATED;
217
    }
218
    
219 220 221
    public const string UNDATED_PAGE_NAME = _("Undated");
    public const string YEAR_FORMAT = _("%Y");
    public const string MONTH_FORMAT = _("%B");
222
    
223 224 225
    private class SubEventDirectoryManager : EventsDirectoryPage.EventDirectoryManager {
        private int month = 0;
        private int year = 0;
226
        DirectoryType type;
227

228
        public SubEventDirectoryManager(DirectoryType type, Time time) {
229 230
            base();
            
231
            if (type == DirectoryType.MONTH)
232 233 234 235 236 237
                month = time.month;
            this.type = type;
            year = time.year; 
        }

        public override bool include_in_view(DataSource source) {
Jim Nelson's avatar
Jim Nelson committed
238 239 240
            if (!base.include_in_view(source))
                return false;
            
241
            EventSource event = (EventSource) source;
242 243
            Time event_time = Time.local(event.get_start_time());
            if (event_time.year == year) {
244
                if (type == DirectoryType.MONTH) {
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
                    return (event_time.month == month);
                }
                return true;
            }
            return false;
        }

        public int get_month() {
            return month;
        }

        public int get_year() {
            return year;
        }

260
        public DirectoryType get_event_directory_type() {
261 262 263 264
            return type;
        }
    }

265
    public SubEventsDirectoryPage(DirectoryType type, Time time) {
266
        string page_name;
267
        if (type == SubEventsDirectoryPage.DirectoryType.UNDATED) {
268
            page_name = UNDATED_PAGE_NAME;
269
        } else {
270
            page_name = time.format((type == DirectoryType.YEAR) ? YEAR_FORMAT : MONTH_FORMAT);
271 272 273
        }

        base(page_name, new SubEventDirectoryManager(type, time), null); 
274
    }
275
    
276 277 278 279 280 281 282 283
    public int get_month() {
        return ((SubEventDirectoryManager) view_manager).get_month();
    }

    public int get_year() {
        return ((SubEventDirectoryManager) view_manager).get_year();
    }

284
    public DirectoryType get_event_directory_type() {
285 286 287
        return ((SubEventDirectoryManager) view_manager).get_event_directory_type();
    }
}
288