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 Sun Microsystems.
17 * Portions created by the Initial Developer are Copyright (C) 2007
18 * the Initial Developer. All Rights Reserved.
19 *
20 * Contributor(s):
21 * Michael Buettner <michael.buettner@sun.com>
22 * Philipp Kewisch <mozilla@kewis.ch>
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37
38 /**
39 * Global variables
40 */
41 var gCustomizeId;
42
43 /**
44 * the current mode is set to a string defining the current
45 * mode we're in. allowed values are:
46 * - 'mode'
47 * - 'mail'
48 * - 'calendar'
49 * - 'task'
50 */
51 var gCurrentMode = 'mail';
52
53 /**
54 * Helper function to get the view deck in a neutral way, regardless of whether
55 * we're in Thunderbird 1.x, 2.x or SeaMonkey
56 */
getMailBar
57 function getMailBar() {
58 return document.getElementById("mail-bar2") ||
59 document.getElementById("mail-bar") ||
60 document.getElementById("msgToolbar");
61 }
62
63 /**
64 * Ensure that switching to the messenger window also switches to mail mode.
65 * We probably should also catch this from other windows (compose, addressbook),
66 * but for now we'll keep it here. This function overrides the toMessengerWindow
67 * function in /mail/base/content/mailCore.js.
68 */
ltnToMessengerWindow
69 var toMessengerWindow = function ltnToMessengerWindow() {
70 var wm = Components.classes['@mozilla.org/appshell/window-mediator;1']
71 .getService(Components.interfaces.nsIWindowMediator);
72
73 var topWindow = wm.getMostRecentWindow("mail:3pane");
74
75 if (topWindow) {
76 var tomail = topWindow.document.getElementById("switch2mail");
77 tomail.doCommand();
78 topWindow.focus();
79 } else {
80 window.open("chrome://messenger/content/messenger.xul",
81 "_blank",
82 "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
83 }
84 };
85
86 /**
87 * ltnSwitch2Mail() switches to the mail mode
88 */
89
ltnSwitch2Mail
90 function ltnSwitch2Mail() {
91 if (gCurrentMode != 'mail') {
92
93 var switch2mail = document.getElementById("switch2mail");
94 var switch2calendar = document.getElementById("switch2calendar");
95 var switch2task = document.getElementById("switch2task");
96 switch2mail.setAttribute("checked", "true");
97 switch2calendar.removeAttribute("checked");
98 switch2task.removeAttribute("checked");
99
100 gCurrentMode = 'mail';
101 swapPopupMenus();
102
103 var mailToolbar = getMailBar();
104 var mailToolbarMenuItem = document.getElementById("menu_showMessengerToolbar");
105 if (mailToolbarMenuItem.getAttribute("checked") == "true") {
106 mailToolbar.removeAttribute("collapsed");
107 }
108
109 var calendarToolbar = document.getElementById("calendar-toolbar");
110 calendarToolbar.setAttribute("collapsed", "true");
111
112 var calendarToolbar = document.getElementById("task-toolbar");
113 calendarToolbar.setAttribute("collapsed", "true");
114
115 // the content panel should display the folder tree
116 var contentDeck = document.getElementById("contentPanel");
117 contentDeck.selectedPanel = document.getElementById("folderPaneBox");
118
119 // display the mail panel on the display deck
120 var viewBox = document.getElementById("calendar-view-box");
121 collapseElement(viewBox);
122
123 // tell thunderbird that it needs to refresh the mail list.
124 // basically, we fake a selection change by directly calling
125 // the appropriate handler while clearing out some internal
126 // variables in order to force a refresh of the mail views.
127 gMsgFolderSelected = null;
128 msgWindow.openFolder = null;
129 ShowThreadPane();
130 FolderPaneSelectionChange();
131
132 document.commandDispatcher.updateCommands('mail-toolbar');
133 document.commandDispatcher.updateCommands('calendar_commands');
134
135 // Disable the rotate view menuitem
136 document.getElementById("calendar_toggle_orientation_command")
137 .setAttribute("disabled", "true");
138
139 window.setCursor("auto");
140 }
141 }
142
143 /**
144 * ltnSwitch2Calendar() switches to the calendar mode
145 */
146
ltnSwitch2Calendar
147 function ltnSwitch2Calendar() {
148 if (gCurrentMode != 'calendar') {
149
150 var switch2mail = document.getElementById("switch2mail");
151 var switch2calendar = document.getElementById("switch2calendar");
152 var switch2task = document.getElementById("switch2task");
153 switch2mail.removeAttribute("checked");
154 switch2calendar.setAttribute("checked", "true");
155 switch2task.removeAttribute("checked");
156
157 gCurrentMode = 'calendar';
158 swapPopupMenus();
159
160 var mailToolbar = getMailBar();
161 mailToolbar.setAttribute("collapsed", "true");
162
163 toggleControlDisplay("cmd_toggleCalendarToolbar", "calendar-toolbar", "calendar");
164 toggleControlDisplay("cmd_toggleTaskToolbar", "task-toolbar", "task");
165 var taskToolbar = document.getElementById("task-toolbar");
166 taskToolbar.setAttribute("collapsed", "true");
167
168
169 // the content deck should display the calendar panel
170 var contentDeck = document.getElementById("contentPanel");
171 contentDeck.selectedPanel = document.getElementById("ltnSidebar");
172
173 // display the calendar panel on the display deck
174 var viewBox = document.getElementById("calendar-view-box");
175 uncollapseElement(viewBox);
176 var deck = document.getElementById("displayDeck");
177 deck.selectedPanel = viewBox;
178
179 // show the last displayed type of calendar view
180 showCalendarView(gLastShownCalendarView);
181
182 document.commandDispatcher.updateCommands('mail-toolbar');
183 document.commandDispatcher.updateCommands('calendar_commands');
184
185 // always hide the task filter option
186 document.getElementById("task-tree-filter-header")
187 .setAttribute("collapsed", "true");
188 document.getElementById("task-tree-filter")
189 .setAttribute("collapsed", "true");
190
191 window.setCursor("auto");
192 }
193 }
194
195 /**
196 * ltnSwitch2Task() switches to the task mode
197 */
198
ltnSwitch2Task
199 function ltnSwitch2Task() {
200 if (gCurrentMode != 'task') {
201
202 var switch2mail = document.getElementById("switch2mail");
203 var switch2calendar = document.getElementById("switch2calendar");
204 var switch2task = document.getElementById("switch2task");
205 switch2mail.removeAttribute("checked");
206 switch2calendar.removeAttribute("checked");
207 switch2task.setAttribute("checked", "true");
208 toggleControlDisplay("cmd_toggleCalendarToolbar", "calendar-toolbar", "calendar");
209 toggleControlDisplay("cmd_toggleTaskToolbar", "task-toolbar", "task");
210 gCurrentMode = 'task';
211 swapPopupMenus();
212 var mailToolbar = getMailBar();
213 var calendarToolbar = document.getElementById("calendar-toolbar");
214 mailToolbar.setAttribute("collapsed", "true");
215 calendarToolbar.setAttribute("collapsed", "true");
216
217 // the content deck should display the calendar panel
218 var contentDeck = document.getElementById("contentPanel");
219 contentDeck.selectedPanel = document.getElementById("ltnSidebar");
220
221 // display the task panel on the display deck
222 var taskBox = document.getElementById("calendar-task-box");
223 uncollapseElement(taskBox);
224 var deck = document.getElementById("displayDeck");
225 deck.selectedPanel = taskBox;
226
227 document.commandDispatcher.updateCommands('mail-toolbar');
228 document.commandDispatcher.updateCommands('calendar_commands');
229
230 // always show the task filter option
231 var filterHeader = document.getElementById("task-tree-filter-header");
232 filterHeader.removeAttribute("collapsed");
233 var filter = document.getElementById("task-tree-filter");
234 if (filterHeader.getAttribute("checked") != "true") {
235 filter.setAttribute("collapsed", "true");
236 } else {
237 filter.removeAttribute("collapsed");
238 }
239
240 window.setCursor("auto");
241 }
242 }
243
244 /**
245 * CustomizeApplicationToolbar() is called to customize one of the toolbars.
246 * the appropriate identifier is passed as argument to the function.
247 */
248
249 // this shadows CustomizeMailToolbar from mail/base/content/mailCore.js
250 // but adds the specific bits and pieces for lightning.
CustomizeApplicationToolbar
251 function CustomizeApplicationToolbar(id) {
252 // the following code operates different whether
253 // or not we're actually customizing the mode toolbar or
254 // any other toolbar.
255 gCustomizeId = id;
256 var isModeToolbox = (id == 'mode-toolbox');
257 var modeName = isModeToolbox ? 'mode' : gCurrentMode;
258
259 // retrieve the toolbars from the tree
260 var mailbar = getMailBar();
261 var menubar = document.getElementById('mail-menubar');
262 var calendarbar = document.getElementById('calendar-toolbar');
263 var taskbar = document.getElementById('task-toolbar');
264 var mailbox = document.getElementById("mail-toolbox");
265 var modebar = document.getElementById('mode-toolbar');
266 var modebox = document.getElementById('mode-toolbox');
267
268 // install the callback that handles what needs to be
269 // done after a toolbar has been customized.
270 if (modebox) {
271 mailbox.customizeDone = ModeToolboxCustomizeDone;
272 modebox.customizeDone = ModeToolboxCustomizeDone;
273
274 // disable elements on the toolbars
275 if (isModeToolbox) {
276 EnableDisableHierarchy(menubar, true);
277 EnableDisableHierarchy(mailbar, true);
278 EnableDisableHierarchy(calendarbar, true);
279 EnableDisableHierarchy(taskbar, true);
280 } else {
281 EnableDisableHierarchy(modebar, true);
282 }
283 } else {
284 modeName = null;
285 }
286
287 var customizePopup = document.getElementById("CustomizeMailToolbar");
288 customizePopup.setAttribute("disabled", "true");
289
290 var wintype = document.documentElement.getAttribute("windowtype");
291 wintype = wintype.replace(/:/g, "");
292
293 // lightning install a new dropdown list in the customize dialog
294 // which allows to switch to all available toolbars while still
295 // being in the dialog. in case a new entry has been selected this
296 // function will be called. the argument will "mode", "mail",
297 // "calendar" or "task".
298 var onModeSwitch = function switchHandler(aMode) {
299
300 // assume that we're switching to the mode toolbar
301 var toolbox = 'mode-toolbox';
302
303 // check which toolbar is to be customized next
304 // and possibly switch the the appropriate mode.
305 if(aMode == 'mail') {
306 ltnSwitch2Mail();
307 toolbox = 'mail-toolbox';
308 } else if(aMode == 'calendar') {
309 ltnSwitch2Calendar();
310 toolbox = 'mail-toolbox';
311 } else if(aMode == 'task') {
312 ltnSwitch2Task();
313 toolbox = 'mail-toolbox';
314 }
315
316 // enable/disable all toolbar to reflect the new state
317 var isMode = (aMode == 'mode');
318 EnableDisableHierarchy(modebar, !isMode);
319 EnableDisableHierarchy(menubar, isMode);
320 EnableDisableHierarchy(mailbar, isMode);
321 EnableDisableHierarchy(calendarbar, isMode);
322 EnableDisableHierarchy(taskbar, isMode);
323
324 // remember the current toolbox
325 gCustomizeId = toolbox;
326
327 // return this appropriate toolbox element
328 return document.getElementById(toolbox);
329 };
330
331 // open the customize toolbar dialog now...
332 window.openDialog("chrome://global/content/customizeToolbar.xul",
333 "CustomizeToolbar"+wintype,
334 "chrome,all,dependent",
335 document.getElementById(id), // toolbar dom node
336 isModeToolbox, // is mode toolbar yes/no?
337 onModeSwitch, // callback function
338 modeName); // name of this mode
339 }
340
341 /**
342 * ModeToolboxCustomizeDone() is called after the customize toolbar dialog
343 * has been closed by the user. We need to restore the state of all buttons
344 * and commands of all customizable toolbars.
345 */
346
ModeToolboxCustomizeDone
347 function ModeToolboxCustomizeDone(aToolboxChanged) {
348 // the following code operates different whether
349 // or not we're actually customizing the mode toolbar or
350 // any other toolbar.
351 var isModeToolbox = (gCustomizeId == 'mode-toolbox');
352
353 // enable elements on the toolbars
354 if (isModeToolbox) {
355 EnableDisableHierarchy(document.getElementById('mail-menubar'), false);
356 EnableDisableHierarchy(getMailBar(), false);
357 EnableDisableHierarchy(document.getElementById('calendar-toolbar'), false);
358 EnableDisableHierarchy(document.getElementById('task-toolbar'), false);
359 }
360
361 // Unconditionally enable the mode toolbar
362 EnableHierarchy(document.getElementById('mode-toolbar'));
363
364 // Update global UI elements that may have been added or removed
365 MailToolboxCustomizeDone(aToolboxChanged);
366
367 // make sure our toolbar buttons have the correct enabled state restored to them...
368 document.commandDispatcher.updateCommands('calendar_commands');
369 }
370
371 /**
372 * EnableDisableHierarchy() recursively walks the dom tree and enables or disables
373 * all elements it encounters. this function is used by ModeToolboxCustomizeDone()
374 * and CustomizeApplicationToolbar().
375 */
376
377 // step along the hierarchy where the top-node is to be passed
378 // as argument and enable/disable all nodes depending on the given flag.
EnableDisableHierarchy
379 function EnableDisableHierarchy(item, disable) {
380 // iterate all nodes on this particular level
381 for (var i = 0; i < item.childNodes.length; ++i) {
382
383 // retrieve the next node that needs to be processed
384 var child = item.childNodes[i];
385
386 // disable this node if flag indicates this case, enable otherwise
387 if (disable) {
388
389 // in case this node has already been disabled, we remember
390 // this fact in the 'itemdisabled' attribute in order
391 // to restore the original state at the end of the operation.
392 if (child.getAttribute("disabled") == "true") {
393 child.setAttribute("itemdisabled", "true");
394 }
395 child.setAttribute("disabled","true");
396
397 } else {
398
399 // restore the previous state, which means either enable
400 // the node or keep it disabled but remove the
401 // 'itemdisabled' attribute.
402 if(child.hasAttribute("itemdisabled")) {
403 child.removeAttribute("itemdisabled");
404 } else {
405 child.removeAttribute("disabled");
406 }
407 }
408
409 // recursively step down the hierarchy if this node
410 // exposes any further child nodes.
411 if (child.childNodes.length > 0) {
412 EnableDisableHierarchy(child, disable);
413 }
414 }
415 }
416
417 /**
418 * EnableHierarchy() recursively walks the dom tree and enables
419 * all elements it encounters. this function is used by ModeToolboxCustomizeDone().
420 */
421
422 // step along the hierarchy where the top-node is to be passed
423 // as argument and enable all nodes unconditionally.
EnableHierarchy
424 function EnableHierarchy(item) {
425 // iterate all nodes on this particular level
426 for (var i = 0; i < item.childNodes.length; ++i) {
427
428 // retrieve the next node that needs to be processed
429 var child = item.childNodes[i];
430
431 // always enable this node and remove the
432 // 'itemdisabled' attribute.
433 if (child.hasAttribute("itemdisabled")) {
434 child.removeAttribute("itemdisabled");
435 }
436 child.removeAttribute("disabled");
437
438 // recursively step down the hierarchy if this node
439 // exposes any further child nodes.
440 if (child.childNodes.length > 0) {
441 EnableHierarchy(child);
442 }
443 }
444 }