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 OEone Calendar Code, released October 31st, 2001.
15 *
16 * The Initial Developer of the Original Code is
17 * OEone Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2001
19 * the Initial Developer. All Rights Reserved.
20 *
21 * Contributor(s): Garth Smedley <garths@oeone.com>
22 * Mike Potter <mikep@oeone.com>
23 * Colin Phillips <colinp@oeone.com>
24 * Karl Guertin <grayrest@grayrest.com>
25 * Mike Norton <xor@ivwnet.com>
26 * ArentJan Banck <ajbanck@planet.nl>
27 * Eric Belhaire <belhaire@ief.u-psud.fr>
28 * Matthew Willis <lilmatt@mozilla.com>
29 * Joey Minta <jminta@gmail.com>
30 * Dan Mosedale <dan.mosedale@oracle.com>
31 * Philipp Kewisch <mozilla@kewis.ch>
32 *
33 * Alternatively, the contents of this file may be used under the terms of
34 * either the GNU General Public License Version 2 or later (the "GPL"), or
35 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
36 * in which case the provisions of the GPL or the LGPL are applicable instead
37 * of those above. If you wish to allow use of your version of this file only
38 * under the terms of either the GPL or the LGPL, and not to allow others to
39 * use your version of this file under the terms of the MPL, indicate your
40 * decision by deleting the provisions above and replace them with the notice
41 * and other provisions required by the GPL or the LGPL. If you do not delete
42 * the provisions above, a recipient may use your version of this file under
43 * the terms of any one of the MPL, the GPL or the LGPL.
44 *
45 * ***** END LICENSE BLOCK ***** */
46
47 /***** calendar
48 * AUTHOR
49 * Garth Smedley
50 *
51 * NOTES
52 * Code for the calendar.
53 *
54 * What is in this file:
55 * - Global variables and functions - Called directly from the XUL
56 * - Several classes:
57 *
58 * IMPLEMENTATION NOTES
59 *
60 **********
61 */
62
63 // single global instance of CalendarWindow
64 var gCalendarWindow;
65
66 // store the current selection in the global scope to workaround bug 351747
67 var gXXXEvilHackSavedSelection;
68
69 /*-----------------------------------------------------------------
70 * G L O B A L C A L E N D A R F U N C T I O N S
71 */
72
73 /**
74 * Called from calendar.xul window onload.
75 */
calendarInit
76 function calendarInit() {
77 // set up the CalendarWindow instance
78 gCalendarWindow = new CalendarWindow();
79
80 // set up the views
81 initializeViews();
82 currentView().goToDay(currentView().selectedDay);
83
84 // set up the unifinder
85 prepareCalendarToDoUnifinder();
86
87 scheduleMidnightUpdate(refreshUIBits);
88
89 loadCalendarManager();
90
91 // fire up the alarm service
92 var alarmSvc = Components.classes["@mozilla.org/calendar/alarm-service;1"]
93 .getService(Components.interfaces.calIAlarmService);
94 alarmSvc.timezone = calendarDefaultTimezone();
95 alarmSvc.startup();
96
97 // a bit of a hack since the menulist doesn't remember the selected value
98 var value = document.getElementById('event-filter-menulist').value;
99 document.getElementById('event-filter-menulist').selectedItem =
100 document.getElementById('event-filter-' + value);
101
102 var toolbox = document.getElementById("calendar-toolbox");
103 toolbox.customizeDone = CalendarToolboxCustomizeDone;
104
105 getViewDeck().addEventListener("dayselect", observeViewDaySelect, false);
106 getViewDeck().addEventListener("itemselect", onSelectionChanged, true);
107
108 // Setup undo/redo menu for additional main windows
109 updateUndoRedoMenu();
110
111 // Setup the offline manager
112 calendarOfflineManager.init();
113
114 // Handle commandline args
115 for (var i = 0; i < window.arguments.length; i++) {
116 try {
117 var cl = window.arguments[i].QueryInterface(Components.interfaces.nsICommandLine);
118 } catch (ex) {
119 dump("unknown argument passed to main window\n");
120 continue;
121 }
122 handleCommandLine(cl);
123 }
124
125 // Setup the command controller
126 injectCalendarCommandController();
127 }
128
handleCommandLine
129 function handleCommandLine(aComLine) {
130 var comLine = aComLine;
131 var calurl = [];
132
133 var validFlags = ["showdate", "subscribe", "url"];
134 var flagsToProcess = [];
135
136 for each (var flag in validFlags) {
137 if (comLine.findFlag(flag, false) >= 0) {
138 flagsToProcess.push(flag);
139 }
140 }
141
142 for each (var flag in flagsToProcess) {
143 var param = comLine.handleFlagWithParam(flag, false);
144
145 switch (flag) {
146 case "showdate":
147 currentView().goToDay(jsDateToDateTime(new Date(param)));
148 break;
149 case "subscribe":
150 case "url":
151 // Double-clicking an .ics file on the Mac causes
152 // LaunchServices to launch Sunbird with the -url command line
153 // switch like so:
154 // sunbird-bin -url file://localhost/Users/foo/mycal.ics -foreground
155 calurl.push(param);
156 break;
157 default:
158 // no-op
159 break;
160 }
161 }
162
163 //Look for arguments without a flag.
164 //This is needed to handle double-click on Windows and Linux.
165 if (comLine.length >= 1) {
166 for (var i = 0; i < comLine.length; i++) {
167 if (!comLine.getArgument(i).match(/^-/) &&
168 !comLine.getArgument(i).match(/^\s/)) {
169 calurl.push( comLine.getArgument(i) );
170 } else {
171 comLine.removeArguments(i, i);
172 }
173 }
174 }
175
176 //subscribe to all files in the calurl array
177 for (var i = 0; i < calurl.length; i++) {
178 var uri = comLine.resolveURI(calurl[i]);
179 var cal = getCalendarManager().createCalendar("ics", uri);
180 getCalendarManager().registerCalendar(cal);
181
182 // Strip ".ics" from filename for use as calendar name
183 var fullPathRegEx = new RegExp("([^/:]+)[.]ics$");
184 var path = uri.path;
185 var prettyName = path.match(fullPathRegEx);
186
187 var name;
188 if (prettyName && prettyName.length >= 1) {
189 name = decodeURIComponent(prettyName[1]);
190 } else {
191 name = calGetString("calendar", "untitledCalendarName");
192 }
193 cal.name = name;
194 }
195 }
196
197 /* Called at midnight to tell us to update the views and other ui bits */
refreshUIBits
198 function refreshUIBits() {
199 currentView().goToDay(now());
200 refreshEventTree();
201
202 // and schedule again...
203 scheduleMidnightUpdate(refreshUIBits);
204 }
205
206 /**
207 * Called from calendar.xul window onunload.
208 */
209
calendarFinish
210 function calendarFinish()
211 {
212 // Workaround to make the selected tab persist. See bug 249552.
213 var tabbox = document.getElementById("tablist");
214 tabbox.setAttribute("selectedIndex", tabbox.selectedIndex);
215
216 unloadCalendarManager();
217
218 // Finish the offline manager
219 calendarOfflineManager.uninit();
220
221 removeCalendarCommandController();
222 }
223
closeCalendar
224 function closeCalendar()
225 {
226 self.close();
227 }
228
onSelectionChanged
229 function onSelectionChanged(aEvent) {
230 var selectedItems = aEvent.detail;
231 gXXXEvilHackSavedSelection = selectedItems;
232
233 // Tell the commands that events were selected.
234 calendarController.item_selected = (selectedItems.length > 0);
235 var selected_events_readonly = 0;
236 var selected_events_requires_network = 0;
237
238 for each (var item in selectedItems) {
239 if (item.calendar.readOnly) {
240 selected_events_readonly++;
241 }
242 if (item.calendar.getProperty("requiresNetwork")) {
243 selected_events_requires_network++;
244 }
245 }
246
247 calendarController.selected_events_readonly =
248 (selected_events_readonly == selectedItems.length);
249
250 calendarController.selected_events_requires_network =
251 (selected_events_requires_network == selectedItems.length);
252
253 document.commandDispatcher.updateCommands("calendar_commands");
254 }
255
openPreferences
256 function openPreferences() {
257 // Check to see if the prefwindow is already open
258 var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
259 .getService(Components.interfaces.nsIWindowMediator);
260
261 var win = wm.getMostRecentWindow("Calendar:Preferences");
262
263 if (win) {
264 win.focus();
265 } else {
266 // The prefwindow should only be modal on non-instant-apply platforms
267 var instApply = getPrefSafe("browser.preferences.instantApply", false);
268
269 var features = "chrome,titlebar,toolbar,centerscreen," +
270 (instApply ? "dialog=no" : "modal");
271
272 var url = "chrome://calendar/content/preferences/preferences.xul";
273
274 openDialog(url, "Preferences", features);
275 }
276 }
277
CalendarCustomizeToolbar
278 function CalendarCustomizeToolbar()
279 {
280 // Disable the toolbar context menu items
281 var menubar = document.getElementById("main-menubar");
282 for (var i = 0; i < menubar.childNodes.length; ++i)
283 menubar.childNodes[i].setAttribute("disabled", true);
284
285 var cmd = document.getElementById("cmd_CustomizeToolbars");
286 cmd.setAttribute("disabled", "true");
287
288 #ifdef MOZILLA_1_8_BRANCH
289 window.openDialog("chrome://calendar/content/customizeToolbar.xul", "CustomizeToolbar",
290 "chrome,all,dependent", document.getElementById("calendar-toolbox"));
291 #else
292 window.openDialog("chrome://global/content/customizeToolbar.xul", "CustomizeToolbar",
293 "chrome,all,dependent", document.getElementById("calendar-toolbox"));
CalendarToolboxCustomizeDone
294 #endif
295 }
296
297 function CalendarToolboxCustomizeDone(aToolboxChanged)
298 {
299 // Re-enable parts of the UI we disabled during the dialog
300 var menubar = document.getElementById("main-menubar");
301 for (var i = 0; i < menubar.childNodes.length; ++i)
302 menubar.childNodes[i].setAttribute("disabled", false);
303 var cmd = document.getElementById("cmd_CustomizeToolbars");
304 cmd.removeAttribute("disabled");
305
306 // XXX Shouldn't have to do this, but I do
307 window.focus();
308 }
309
310 /**
311 * Update the undo and redo menu items
312 */
313 function updateUndoRedoMenu() {
314 goUpdateCommand("cmd_undo");
315 goUpdateCommand("cmd_redo");
316 }