1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is Sun Microsystems code.
15 *
16 * The Initial Developer of the Original Code is
17 * Philipp Kewisch <mozilla@kewis.ch>
18 * Portions created by the Initial Developer are Copyright (C) 2007
19 * the Initial Developer. All Rights Reserved.
20 *
21 * Contributor(s):
22 *
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
34 *
35 * ***** END LICENSE BLOCK ***** */
36
37 var calendarController = {
38 defaultController: null,
39
40 commands: {
41 // Common commands
42 "calendar_new_event_command": true,
43 "calendar_modify_event_command": true,
44 "calendar_delete_event_command": true,
45
46 "calendar_new_todo_command": true,
47 "calendar_modify_todo_command": true,
48 "calendar_delete_todo_command": true,
49
50 "calendar_new_calendar_command": true,
51 "calendar_edit_calendar_command": true,
52 "calendar_delete_calendar_command": true,
53
54 "calendar_import_command": true,
55 "calendar_export_command": true,
56 "calendar_export_selection_command": true,
57
58 "calendar_publish_selected_calendar_command": true,
59 "calendar_publish_calendar_command": true,
60 "calendar_publish_selected_events_command": true,
61
62 "calendar_reload_remote_calendars": true,
63 "calendar_percentComplete-0_command": true,
64 "calendar_percentComplete-25_command": true,
65 "calendar_percentComplete-50_command": true,
66 "calendar_percentComplete-75_command": true,
67 "calendar_percentComplete-100_command": true,
68 "calendar_percentComplete-100_command2": true,
69 "calendar_priority-0_command": true,
70 "calendar_priority-9_command": true,
71 "calendar_priority-5_command": true,
72 "calendar_priority-1_command": true,
73 "calendar_general-priority_command": true,
74 "calendar_task_category_command": true,
75 "cmd_cut": true,
76 "cmd_copy": true,
77 "cmd_paste": true,
78 "cmd_undo": true,
79 "cmd_redo": true,
80 "cmd_print": true,
81 "cmd_selectAll": true,
82 "cmd_pageSetup": true,
83
84 // Thunderbird commands
85 "cmd_printpreview": true,
86 "button_print": true,
87 "button_delete": true,
88 "cmd_delete": true
89 },
90
cC_updateCommands
91 updateCommands: function cC_updateCommands() {
92 for (var command in this.commands) {
93 goUpdateCommand(command);
94 }
95 },
96
cC_supportsCommand
97 supportsCommand: function cC_supportsCommand(aCommand) {
98 if (aCommand in this.commands) {
99 return true;
100 }
101 if (this.defaultContoller) {
102 return this.defaultContoller.supportsCommand(aCommand);
103 }
104 return false;
105 },
106
cC_isCommandEnabled
107 isCommandEnabled: function cC_isCommandEnabled(aCommand) {
108 switch (aCommand) {
109 case "calendar_new_event_command":
110 return this.writable && this.calendars_support_events;
111 case "calendar_modify_event_command":
112 return this.item_selected;
113 case "calendar_delete_event_command":
114 return this.selected_items_writable;
115 case "calendar_new_todo_command":
116 return this.writable && this.calendars_support_tasks;
117 case "calendar_modify_todo_command":
118 return this.todo_items_selected &&
119 this.todo_tasktree_focused;
120 case "calendar_delete_todo_command":
121 case "calendar_percentComplete-0_command":
122 case "calendar_percentComplete-25_command":
123 case "calendar_percentComplete-50_command":
124 case "calendar_percentComplete-75_command":
125 case "calendar_percentComplete-100_command":
126 case "calendar_percentComplete-100_command2":
127 case "calendar_priority-0_command":
128 case "calendar_priority-9_command":
129 case "calendar_priority-5_command":
130 case "calendar_priority-1_command":
131 case "calendar_task_category_command":
132 case "calendar_general-priority_command":
133 return this.writable &&
134 this.todo_items_selected &&
135 this.todo_items_writable;
136 case "calendar_delete_calendar_command":
137 return !this.last_calendar;
138
139 case "calendar_import_command":
140 return this.writable;
141 case "calendar_export_selection_command":
142 return this.item_selected;
143
144 case "calendar_publish_selected_events_command":
145 return this.item_selected;
146
147 case "calendar_reload_remote_calendar":
148 return !this.no_network_calendars && !this.offline;
149 default:
150 if (this.defaultController && !this.isCalendarInForeground()) {
151 // The delete-button demands a special handling in mail-mode
152 // as it is supposed to delete an element of the focused pane
153 if (aCommand == "cmd_delete" || aCommand == "button_delete") {
154 var focusedElement = document.commandDispatcher.focusedElement;
155 if (focusedElement) {
156 if (focusedElement.getAttribute("id") == "agenda-listbox") {
157 return agendaListbox.isEventSelected();
158 } else if (focusedElement.className == "calendar-task-tree") {
159 return this.writable &&
160 this.todo_items_selected &&
161 this.todo_items_writable;
162 }
163 }
164 }
165
166 // If calendar is not in foreground, let the default controller take
167 // care. If we don't have a default controller (i.e sunbird), just
168 // continue.
169 return this.defaultController.isCommandEnabled(aCommand);
170 }
171 switch (aCommand) {
172 // Thunderbird Commands
173 case "cmd_cut":
174 return this.selected_items_writable;
175 case "cmd_copy":
176 return this.item_selected;
177 case "cmd_paste":
178 return this.writable && canPaste();
179 case "cmd_undo":
180 goSetMenuValue(aCommand, 'valueDefault');
181 return canUndo();
182 case "cmd_redo":
183 goSetMenuValue(aCommand, 'valueDefault');
184 return canRedo();
185 case "cmd_printpreview":
186 return false;
187 case "button_delete":
188 case "cmd_delete":
189 return this.item_selected;
190 }
191 if (aCommand in this.commands) {
192 // All other commands we support should be enabled by default
193 return true;
194 }
195 }
196 return false;
197 },
198
cC_doCommand
199 doCommand: function cC_doCommand(aCommand) {
200 switch (aCommand) {
201 // Common Commands
202 case "calendar_new_event_command":
203 createEventWithDialog(getSelectedCalendar());
204 break;
205 case "calendar_modify_event_command":
206 editSelectedEvents();
207 break;
208 case "calendar_delete_event_command":
209 deleteSelectedEvents();
210 break;
211
212 case "calendar_new_todo_command":
213 createTodoWithDialog(getSelectedCalendar());
214 break;
215 case "calendar_modify_todo_command":
216 var selectedTasks = getFocusedTaskTree().selectedTasks;
217 for each (var task in selectedTasks) {
218 modifyEventWithDialog(task);
219 }
220 break;
221 case "calendar_delete_todo_command":
222 deleteToDoCommand();
223 break;
224
225 case "calendar_new_calendar_command":
226 openCalendarWizard();
227 break;
228 case "calendar_edit_calendar_command":
229 openCalendarProperties(getSelectedCalendar());
230 break;
231 case "calendar_delete_calendar_command":
232 promptDeleteCalendar(getSelectedCalendar());
233 break;
234
235 case "calendar_import_command":
236 loadEventsFromFile();
237 break;
238 case "calendar_export_command":
239 exportEntireCalendar();
240 break;
241 case "calendar_export_selection_command":
242 saveEventsToFile(currentView().getSelectedItems({}));
243 break;
244
245 case "calendar_publish_selected_calendar_command":
246 publishEntireCalendar(getSelectedCalendar());
247 break;
248 case "calendar_publish_calendar_command":
249 publishEntireCalendar();
250 break;
251 case "calendar_publish_selected_events_command":
252 publishCalendarData();
253 break;
254
255 case "calendar_reload_remote_calendars":
256 getCompositeCalendar().refresh();
257 break;
258 case "calendar_percentComplete-0_command":
259 contextChangeTaskProgress(0);
260 break;
261 case "calendar_percentComplete-25_command":
262 contextChangeTaskProgress(25);
263 break;
264 case "calendar_percentComplete-50_command":
265 contextChangeTaskProgress(50);
266 break;
267 case "calendar_percentComplete-75_command":
268 contextChangeTaskProgress(75);
269 break;
270 case "calendar_percentComplete-100_command":
271 contextChangeTaskProgress(100);
272 break;
273 case "calendar_percentComplete-100_command2":
274 contextChangeTaskProgress2(100);
275 break;
276 case "calendar_priority-0_command":
277 contextChangeTaskPriority(0);
278 break;
279 case "calendar_priority-9_command":
280 contextChangeTaskPriority(9);
281 break;
282 case "calendar_priority-5_command":
283 contextChangeTaskPriority(5);
284 break;
285 case "calendar_priority-1_command":
286 contextChangeTaskPriority(1);
287 break;
288 default:
289 if (this.defaultController && !this.isCalendarInForeground()) {
290 // The delete-button demands a special handling in mail-mode
291 // as it is supposed to delete an element of the focused pane
292 if (aCommand == "cmd_delete" || aCommand == "button_delete") {
293 var focusedElement = document.commandDispatcher.focusedElement;
294 if (focusedElement) {
295 if (focusedElement.getAttribute("id") == "agenda-listbox") {
296 agendaListbox.deleteSelectedItem(false);
297 return;
298 } else if (focusedElement.className == "calendar-task-tree") {
299 deleteToDoCommand(false);
300 return;
301 }
302 }
303 }
304
305 // If calendar is not in foreground, let the default controller take
306 // care. If we don't have a default controller (i.e sunbird), just
307 // continue.
308 this.defaultController.doCommand(aCommand);
309 return;
310 }
311 switch (aCommand) {
312 // These commands are overridden in lightning and native in sunbird.
313 case "cmd_cut":
314 cutToClipboard();
315 break;
316 case "cmd_copy":
317 copyToClipboard();
318 break;
319 case "cmd_paste":
320 pasteFromClipboard();
321 break;
322 case "cmd_undo":
323 if (canUndo()) {
324 getTransactionMgr().undo();
325 }
326 break;
327 case "cmd_redo":
328 if (canRedo()) {
329 getTransactionMgr().redo();
330 }
331 break;
332 case "cmd_selectAll":
333 selectAllEvents();
334 break;
335 case "cmd_pageSetup":
336 PrintUtils.showPageSetup();
337 break;
338 case "button_print":
339 case "cmd_print":
340 calPrint();
341 break;
342
343 // Thunderbird commands
344 // For these commands, nothing should happen in calendar mode.
345 case "cmd_printpreview":
346 case "button_delete":
347 case "cmd_delete":
348 default:
349 return;
350 }
351 }
352 return;
353 },
354
cC_onEvent
355 onEvent: function cC_onEvent(aEvent) {
356 },
357
cC_isCalendarInForeground
358 isCalendarInForeground: function cC_isCalendarInForeground() {
359 // For sunbird, calendar is always in foreground. Otherwise check if
360 // we are in the correct mode.
361 return isSunbird() || (gCurrentMode && gCurrentMode != "mail");
362 },
363
364 /**
365 * Condition Helpers
366 */
367
368 // This will be set up manually.
369 item_selected: false,
370 selected_events_readonly: false,
371 selected_events_requires_network: false,
372
get_writable
373 get writable() {
374 return !this.all_readonly &&
375 (!this.offline || (this.has_local_calendars &&
376 !this.all_local_calendars_readonly));
377 },
378
get_offline
379 get offline() {
380 return getIOService().offline;
381 },
382
get_all_readonly
383 get all_readonly () {
384 var calMgr = getCalendarManager();
385 return (calMgr.readOnlyCalendarCount == calMgr.calendarCount);
386 },
387
get_no_network_calendars
388 get no_network_calendars() {
389 return (getCalendarManager().networkCalendarCount == 0);
390 },
391
get_has_local_calendars
392 get has_local_calendars() {
393 var calMgr = getCalendarManager();
394 return (calMgr.networkCalendarCount < calMgr.calendarCount);
395 },
396
get_last_calendar
397 get last_calendar() {
398 return (getCalendarManager().calendarCount < 2);
399 },
400
get_all_local_calendars_readonly
401 get all_local_calendars_readonly() {
402 // We might want to speed this part up by keeping track of this in the
403 // calendar manager.
404 var cals = getCalendarManager().getCalendars({});
405 var count = cals.length;
406 for each (var cal in cals) {
407 if (!isCalendarWritable(cal)) {
408 count--;
409 }
410 }
411 return (count == 0);
412 },
413
get_selected_items_writable
414 get selected_items_writable() {
415 return this.writable &&
416 this.item_selected &&
417 !this.selected_events_readonly &&
418 (!this.offline || !this.selected_events_requires_network);
419 },
420
get_calendars_support_tasks
421 get calendars_support_tasks() {
422 // XXX We might want to cache this
423 var calendars = getCalendarManager().getCalendars({});
424
425 for each (var cal in calendars) {
426 if (isCalendarWritable(cal) &&
427 cal.getProperty("capabilities.tasks.supported") !== false) {
428 return true;
429 }
430 }
431 return false;
432 },
433
get_calendars_support_events
434 get calendars_support_events() {
435 // XXX We might want to cache this
436 var calendars = getCalendarManager().getCalendars({});
437
438 for each (var cal in calendars) {
439 if (isCalendarWritable(cal) &&
440 cal.getProperty("capabilities.events.supported") !== false) {
441 return true;
442 }
443 }
444 return false;
445 },
446
cC_todo_items_selected
447 get todo_items_selected cC_todo_items_selected() {
448 var taskTree = getFocusedTaskTree();
449 if (taskTree) {
450 var selectedTasks = taskTree.selectedTasks;
451 return (selectedTasks.length > 0);
452 }
453 return false;
454 },
455
cC_todo_items_writable
456 get todo_items_writable cC_todo_items_writable() {
457 var taskTree = getFocusedTaskTree();
458 if (taskTree) {
459 var selectedTasks = taskTree.selectedTasks;
460 for each (var task in selectedTasks) {
461 if (isCalendarWritable(task.calendar)) {
462 return true;
463 }
464 }
465 }
466 return false;
467 }
468 };
469
injectCalendarCommandController
470 function injectCalendarCommandController() {
471 if (!isSunbird()) {
472 // We need to put our new command controller *before* the one that
473 // gets installed by thunderbird. Since we get called pretty early
474 // during startup we need to install the function below as a callback
475 // that periodically checks when the original thunderbird controller
476 // gets alive. Please note that setTimeout with a value of 0 means that
477 // we leave the current thread in order to re-enter the message loop.
478
479 var tbController = top.controllers.getControllerForCommand("cmd_undo");
480 if (!tbController) {
481 setTimeout(injectCalendarCommandController, 0);
482 return;
483 } else {
484 calendarController.defaultController = tbController;
485 ltnInitializeMenus();
486 }
487 }
488 top.controllers.insertControllerAt(0, calendarController);
489 document.commandDispatcher.updateCommands("calendar_commands");
490 }
491
removeCalendarCommandController
492 function removeCalendarCommandController() {
493 top.controllers.removeController(calendarController);
494 }