2002-08-16 04:26:44 +04:00
|
|
|
|
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
|
* The contents of this file are subject to the Netscape Public
|
|
|
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
|
* the License at http://www.mozilla.org/NPL/
|
|
|
|
|
*
|
|
|
|
|
* Software distributed under the License is distributed on an "AS
|
|
|
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
|
|
|
* implied. See the License for the specific language governing
|
|
|
|
|
* rights and limitations under the License.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is Mozilla Communicator client code, released
|
|
|
|
|
* March 31, 1998.
|
|
|
|
|
*
|
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
|
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
|
|
|
|
* Rights Reserved.
|
|
|
|
|
*
|
|
|
|
|
* Contributor(s):
|
|
|
|
|
* Jan Varga (varga@utcru.sk)
|
|
|
|
|
* H<EFBFBD>kan Waara (hwaara@chello.se)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* This is where functions related to the 3 pane window are kept */
|
|
|
|
|
|
|
|
|
|
// from MailNewsTypes.h
|
|
|
|
|
const nsMsgViewIndex_None = 0xFFFFFFFF;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var gFolderTree;
|
|
|
|
|
var gMessagePane;
|
|
|
|
|
var gThreadTree;
|
|
|
|
|
var gSearchInput;
|
|
|
|
|
|
|
|
|
|
var gThreadAndMessagePaneSplitter = null;
|
|
|
|
|
var gUnreadCount = null;
|
|
|
|
|
var gTotalCount = null;
|
|
|
|
|
|
2002-08-16 08:07:36 +04:00
|
|
|
|
// cache these services
|
|
|
|
|
var gRDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService().QueryInterface(Components.interfaces.nsIRDFService);
|
|
|
|
|
var gDragService = null;
|
|
|
|
|
var nsIDragService = Components.interfaces.nsIDragService;
|
|
|
|
|
|
|
|
|
|
|
2002-08-16 04:26:44 +04:00
|
|
|
|
var gCurrentLoadingFolderURI;
|
|
|
|
|
var gCurrentFolderToReroot;
|
|
|
|
|
var gCurrentLoadingFolderSortType = 0;
|
|
|
|
|
var gCurrentLoadingFolderSortOrder = 0;
|
|
|
|
|
var gCurrentLoadingFolderViewType = 0;
|
|
|
|
|
var gCurrentLoadingFolderViewFlags = 0;
|
|
|
|
|
var gRerootOnFolderLoad = false;
|
|
|
|
|
var gCurrentDisplayedMessage = null;
|
|
|
|
|
var gNextMessageAfterDelete = null;
|
|
|
|
|
var gNextMessageAfterLoad = null;
|
|
|
|
|
var gNextMessageViewIndexAfterDelete = -2;
|
|
|
|
|
var gCurrentlyDisplayedMessage=nsMsgViewIndex_None;
|
|
|
|
|
var gStartFolderUri = null;
|
|
|
|
|
var gStartMsgKey = -1;
|
|
|
|
|
var gRightMouseButtonDown = false;
|
|
|
|
|
// Global var to keep track of which row in the thread pane has been selected
|
|
|
|
|
// This is used to make sure that the row with the currentIndex has the selection
|
|
|
|
|
// after a Delete or Move of a message that has a row index less than currentIndex.
|
|
|
|
|
var gThreadPaneCurrentSelectedIndex = -1;
|
|
|
|
|
|
|
|
|
|
// Global var to keep track of if the 'Delete Message' or 'Move To' thread pane
|
|
|
|
|
// context menu item was triggered. This helps prevent the tree view from
|
|
|
|
|
// not updating on one of those menu item commands.
|
|
|
|
|
var gThreadPaneDeleteOrMoveOccurred = false;
|
|
|
|
|
|
|
|
|
|
//If we've loaded a message, set to true. Helps us keep the start page around.
|
|
|
|
|
var gHaveLoadedMessage;
|
|
|
|
|
|
|
|
|
|
var gDisplayStartupPage = false;
|
|
|
|
|
|
|
|
|
|
// the folderListener object
|
|
|
|
|
var folderListener = {
|
|
|
|
|
OnItemAdded: function(parentItem, item, view) { },
|
|
|
|
|
|
|
|
|
|
OnItemRemoved: function(parentItem, item, view) { },
|
|
|
|
|
|
|
|
|
|
OnItemPropertyChanged: function(item, property, oldValue, newValue) { },
|
|
|
|
|
|
|
|
|
|
OnItemIntPropertyChanged: function(item, property, oldValue, newValue) {
|
|
|
|
|
var currentLoadedFolder = GetThreadPaneFolder();
|
|
|
|
|
if (!currentLoadedFolder) return;
|
|
|
|
|
var currentURI = currentLoadedFolder.URI;
|
|
|
|
|
|
|
|
|
|
//if we don't have a folder loaded, don't bother.
|
|
|
|
|
if(currentURI) {
|
|
|
|
|
if(property.GetUnicode() == "TotalMessages" || property.GetUnicode() == "TotalUnreadMessages") {
|
|
|
|
|
var folder = item.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
if(folder) {
|
|
|
|
|
var folderResource = folder.QueryInterface(Components.interfaces.nsIRDFResource);
|
|
|
|
|
if(folderResource) {
|
|
|
|
|
var folderURI = folderResource.Value;
|
|
|
|
|
if(currentURI == folderURI) {
|
|
|
|
|
UpdateStatusMessageCounts(folder);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
OnItemBoolPropertyChanged: function(item, property, oldValue, newValue) { },
|
|
|
|
|
|
|
|
|
|
OnItemUnicharPropertyChanged: function(item, property, oldValue, newValue) { },
|
|
|
|
|
OnItemPropertyFlagChanged: function(item, property, oldFlag, newFlag) { },
|
|
|
|
|
|
|
|
|
|
OnItemEvent: function(folder, event) {
|
|
|
|
|
var eventType = event.GetUnicode();
|
|
|
|
|
if (eventType == "FolderLoaded") {
|
|
|
|
|
if (folder) {
|
|
|
|
|
var resource = folder.QueryInterface(Components.interfaces.nsIRDFResource);
|
|
|
|
|
if(resource) {
|
|
|
|
|
var uri = resource.Value;
|
|
|
|
|
if(uri == gCurrentFolderToReroot) {
|
|
|
|
|
gCurrentFolderToReroot="";
|
|
|
|
|
var msgFolder = folder.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
if(msgFolder) {
|
|
|
|
|
msgFolder.endFolderLoading();
|
|
|
|
|
// suppress command updating when rerooting the folder
|
|
|
|
|
// when rerooting, we'll be clearing the selection
|
|
|
|
|
// which will cause us to update commands.
|
|
|
|
|
if (gDBView) {
|
|
|
|
|
gDBView.suppressCommandUpdating = true;
|
|
|
|
|
// if the db's view isn't set, something went wrong and we should reroot
|
|
|
|
|
// the folder, which will re-open the view.
|
|
|
|
|
if (!gDBView.db)
|
|
|
|
|
gRerootOnFolderLoad = true;
|
|
|
|
|
}
|
|
|
|
|
if (gRerootOnFolderLoad)
|
|
|
|
|
RerootFolder(uri, msgFolder, gCurrentLoadingFolderViewType, gCurrentLoadingFolderViewFlags, gCurrentLoadingFolderSortType, gCurrentLoadingFolderSortOrder);
|
|
|
|
|
|
|
|
|
|
var db = msgFolder.getMsgDatabase(msgWindow);
|
|
|
|
|
if (db)
|
|
|
|
|
db.resetHdrCacheSize(100);
|
|
|
|
|
|
|
|
|
|
if (gDBView) {
|
|
|
|
|
gDBView.suppressCommandUpdating = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gIsEditableMsgFolder = IsSpecialFolder(msgFolder, MSG_FOLDER_FLAG_DRAFTS);
|
|
|
|
|
|
|
|
|
|
gCurrentLoadingFolderSortType = 0;
|
|
|
|
|
gCurrentLoadingFolderSortOrder = 0;
|
|
|
|
|
gCurrentLoadingFolderViewType = 0;
|
|
|
|
|
gCurrentLoadingFolderViewFlags = 0;
|
|
|
|
|
|
|
|
|
|
var scrolled = false;
|
|
|
|
|
|
|
|
|
|
LoadCurrentlyDisplayedMessage(); //used for rename folder msg loading after folder is loaded.
|
|
|
|
|
|
|
|
|
|
if (gStartMsgKey != -1) {
|
|
|
|
|
// select the desired message
|
|
|
|
|
gDBView.selectMsgByKey(gStartMsgKey);
|
|
|
|
|
gStartMsgKey = -1;
|
|
|
|
|
|
|
|
|
|
// now scroll to it
|
|
|
|
|
var indicies = GetSelectedIndices(gDBView);
|
|
|
|
|
EnsureRowInThreadTreeIsVisible(indicies[0]);
|
|
|
|
|
scrolled = true;
|
|
|
|
|
}
|
|
|
|
|
if (gNextMessageAfterLoad) {
|
|
|
|
|
var type = gNextMessageAfterLoad;
|
|
|
|
|
gNextMessageAfterLoad = null;
|
|
|
|
|
|
|
|
|
|
// scroll to and select the proper message
|
|
|
|
|
scrolled = ScrollToMessage(type, true, true /* selectMessage */);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(uri == gCurrentLoadingFolderURI) {
|
|
|
|
|
gCurrentLoadingFolderURI = "";
|
|
|
|
|
//Now let's select the first new message if there is one
|
|
|
|
|
if (!scrolled) {
|
|
|
|
|
// if we didn't just scroll, scroll to the first new message
|
|
|
|
|
// don't select it though
|
|
|
|
|
scrolled = ScrollToMessage(nsMsgNavigationType.firstNew, true, false /* selectMessage */);
|
|
|
|
|
|
|
|
|
|
// if we failed to find a new message, scroll to the top
|
|
|
|
|
if (!scrolled) {
|
|
|
|
|
EnsureRowInThreadTreeIsVisible(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SetBusyCursor(window, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (eventType == "ImapHdrDownloaded") {
|
|
|
|
|
if (folder) {
|
|
|
|
|
var imapFolder = folder.QueryInterface(Components.interfaces.nsIMsgImapMailFolder);
|
|
|
|
|
if (imapFolder) {
|
|
|
|
|
var hdrParser = imapFolder.hdrParser;
|
|
|
|
|
if (hdrParser) {
|
|
|
|
|
var msgHdr = hdrParser.GetNewMsgHdr();
|
|
|
|
|
if (msgHdr)
|
|
|
|
|
{
|
|
|
|
|
var hdrs = hdrParser.headers;
|
|
|
|
|
if (hdrs && hdrs.indexOf("X-attachment-size:") > 0) {
|
|
|
|
|
msgHdr.OrFlags(0x10000000); // 0x10000000 is MSG_FLAG_ATTACHMENT
|
|
|
|
|
}
|
|
|
|
|
if (hdrs && hdrs.indexOf("X-image-size:") > 0) {
|
|
|
|
|
msgHdr.setStringProperty("imageSize", "1");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (eventType == "DeleteOrMoveMsgCompleted") {
|
|
|
|
|
HandleDeleteOrMoveMsgCompleted(folder);
|
|
|
|
|
}
|
|
|
|
|
else if (eventType == "DeleteOrMoveMsgFailed") {
|
|
|
|
|
HandleDeleteOrMoveMsgFailed(folder);
|
|
|
|
|
}
|
|
|
|
|
else if (eventType == "CompactCompleted") {
|
|
|
|
|
HandleCompactCompleted(folder);
|
|
|
|
|
}
|
|
|
|
|
else if(eventType == "RenameCompleted") {
|
|
|
|
|
SelectFolder(folder.URI);
|
|
|
|
|
}
|
|
|
|
|
else if (eventType == "msgLoaded") {
|
|
|
|
|
OnMsgLoaded(folder, gCurrentDisplayedMessage);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var folderObserver = {
|
|
|
|
|
canDropOn: function(index)
|
|
|
|
|
{
|
|
|
|
|
return CanDropOnFolderTree(index);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
canDropBeforeAfter: function(index, before)
|
|
|
|
|
{
|
|
|
|
|
return CanDropBeforeAfterFolderTree(index, before);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onDrop: function(row, orientation)
|
|
|
|
|
{
|
|
|
|
|
DropOnFolderTree(row, orientation);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onToggleOpenState: function()
|
|
|
|
|
{
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onCycleHeader: function(colID, elt)
|
|
|
|
|
{
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onCycleCell: function(row, colID)
|
|
|
|
|
{
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onSelectionChanged: function()
|
|
|
|
|
{
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
isEditable: function(row, colID)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onSetCellText: function(row, colID, value)
|
|
|
|
|
{
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onPerformAction: function(action)
|
|
|
|
|
{
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onPerformActionOnRow: function(action, row)
|
|
|
|
|
{
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onPerformActionOnCell: function(action, row, colID)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function HandleDeleteOrMoveMsgFailed(folder)
|
|
|
|
|
{
|
|
|
|
|
gDBView.onDeleteCompleted(false);
|
|
|
|
|
if(IsCurrentLoadedFolder(folder)) {
|
|
|
|
|
if(gNextMessageAfterDelete) {
|
|
|
|
|
gNextMessageAfterDelete = null;
|
|
|
|
|
gNextMessageViewIndexAfterDelete = -2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fix me???
|
|
|
|
|
// ThreadPaneSelectionChange(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function HandleDeleteOrMoveMsgCompleted(folder)
|
|
|
|
|
{
|
|
|
|
|
// you might not have a db view. this can happen if
|
|
|
|
|
// biff fires when the 3 pane is set to account central.
|
|
|
|
|
if (!gDBView)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
gDBView.onDeleteCompleted(true);
|
|
|
|
|
if (gNextMessageViewIndexAfterDelete != -2)
|
|
|
|
|
{
|
|
|
|
|
if (IsCurrentLoadedFolder(folder))
|
|
|
|
|
{
|
|
|
|
|
var treeView = gDBView.QueryInterface(Components.interfaces.nsITreeView);
|
|
|
|
|
var treeSelection = treeView.selection;
|
|
|
|
|
if (gNextMessageViewIndexAfterDelete != nsMsgViewIndex_None)
|
|
|
|
|
{
|
|
|
|
|
viewSize = treeView.rowCount;
|
|
|
|
|
if (gNextMessageViewIndexAfterDelete >= viewSize)
|
|
|
|
|
{
|
|
|
|
|
if (viewSize > 0)
|
|
|
|
|
gNextMessageViewIndexAfterDelete = viewSize - 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gNextMessageViewIndexAfterDelete = nsMsgViewIndex_None;
|
|
|
|
|
|
|
|
|
|
//there is nothing to select viewSize is 0
|
|
|
|
|
|
|
|
|
|
treeSelection.clearSelection();
|
|
|
|
|
setTitleFromFolder(folder,null);
|
|
|
|
|
ClearMessagePane();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if we are about to set the selection with a new element then DON'T clear
|
|
|
|
|
// the selection then add the next message to select. This just generates
|
|
|
|
|
// an extra round of command updating notifications that we are trying to
|
|
|
|
|
// optimize away.
|
|
|
|
|
if (gNextMessageViewIndexAfterDelete != nsMsgViewIndex_None)
|
|
|
|
|
{
|
|
|
|
|
// when deleting a message we don't update the commands when the selection goes to 0
|
|
|
|
|
// (we have a hack in nsMsgDBView which prevents that update) so there is no need to
|
|
|
|
|
// update commands when we select the next message after the delete; the commands already
|
|
|
|
|
// have the right update state...
|
|
|
|
|
gDBView.suppressCommandUpdating = true;
|
|
|
|
|
|
|
|
|
|
// This check makes sure that the tree does not perform a
|
|
|
|
|
// selection on a non selected row (row < 0), else assertions will
|
|
|
|
|
// be thrown.
|
|
|
|
|
if (gNextMessageViewIndexAfterDelete >= 0)
|
|
|
|
|
treeSelection.select(gNextMessageViewIndexAfterDelete);
|
|
|
|
|
|
|
|
|
|
// if gNextMessageViewIndexAfterDelete has the same value
|
|
|
|
|
// as the last index we had selected, the tree won't generate a
|
|
|
|
|
// selectionChanged notification for the tree view. So force a manual
|
|
|
|
|
// selection changed call. (don't worry it's cheap if we end up calling it twice).
|
|
|
|
|
if (treeView)
|
|
|
|
|
treeView.selectionChanged();
|
|
|
|
|
|
|
|
|
|
EnsureRowInThreadTreeIsVisible(gNextMessageViewIndexAfterDelete);
|
|
|
|
|
gDBView.suppressCommandUpdating = false;
|
|
|
|
|
|
|
|
|
|
// hook for extra toolbar items
|
|
|
|
|
// XXX I think there is a bug in the suppression code above.
|
|
|
|
|
// what if I have two rows selected, and I hit delete, and so we load the next row.
|
|
|
|
|
// what if I have commands that only enable where exactly one row is selected?
|
|
|
|
|
var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
|
|
|
|
|
observerService.notifyObservers(window, "mail:updateToolbarItems", null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
gNextMessageViewIndexAfterDelete = -2;
|
|
|
|
|
//default value after delete/move/copy is over
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function HandleCompactCompleted (folder)
|
|
|
|
|
{
|
|
|
|
|
if(folder)
|
|
|
|
|
{
|
|
|
|
|
var resource = folder.QueryInterface(Components.interfaces.nsIRDFResource);
|
|
|
|
|
if(resource)
|
|
|
|
|
{
|
|
|
|
|
var uri = resource.Value;
|
|
|
|
|
var msgFolder = msgWindow.openFolder;
|
|
|
|
|
if (msgFolder && uri == msgFolder.URI)
|
|
|
|
|
{
|
|
|
|
|
var msgdb = msgFolder.getMsgDatabase(msgWindow);
|
|
|
|
|
if (msgdb)
|
|
|
|
|
{
|
|
|
|
|
var dbFolderInfo = msgdb.dBFolderInfo;
|
|
|
|
|
sortType = dbFolderInfo.sortType;
|
|
|
|
|
sortOrder = dbFolderInfo.sortOrder;
|
|
|
|
|
viewFlags = dbFolderInfo.viewFlags;
|
|
|
|
|
viewType = dbFolderInfo.viewType;
|
|
|
|
|
dbFolderInfo = null;
|
|
|
|
|
}
|
|
|
|
|
RerootFolder(uri, msgFolder, viewType, viewFlags, sortType, sortOrder);
|
|
|
|
|
LoadCurrentlyDisplayedMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function LoadCurrentlyDisplayedMessage()
|
|
|
|
|
{
|
|
|
|
|
if (gCurrentlyDisplayedMessage != nsMsgViewIndex_None)
|
|
|
|
|
{
|
|
|
|
|
var treeView = gDBView.QueryInterface(Components.interfaces.nsITreeView);
|
|
|
|
|
var treeSelection = treeView.selection;
|
|
|
|
|
treeSelection.select(gCurrentlyDisplayedMessage);
|
|
|
|
|
if (treeView)
|
|
|
|
|
treeView.selectionChanged();
|
|
|
|
|
EnsureRowInThreadTreeIsVisible(gCurrentlyDisplayedMessage);
|
|
|
|
|
SetFocusThreadPane();
|
|
|
|
|
gCurrentlyDisplayedMessage = nsMsgViewIndex_None; //reset
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function IsCurrentLoadedFolder(folder)
|
|
|
|
|
{
|
|
|
|
|
var msgfolder = folder.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
if(msgfolder)
|
|
|
|
|
{
|
|
|
|
|
var folderResource = msgfolder.QueryInterface(Components.interfaces.nsIRDFResource);
|
|
|
|
|
if(folderResource)
|
|
|
|
|
{
|
|
|
|
|
var folderURI = folderResource.Value;
|
|
|
|
|
var currentLoadedFolder = GetThreadPaneFolder();
|
|
|
|
|
var currentURI = currentLoadedFolder.URI;
|
|
|
|
|
return(currentURI == folderURI);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ServerContainsFolder(server, folder)
|
|
|
|
|
{
|
|
|
|
|
if (!folder || !server)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return server.equals(folder.server);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SelectServer(server)
|
|
|
|
|
{
|
|
|
|
|
SelectFolder(server.rootFolder.URI);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we have this incoming server listener in case we need to
|
|
|
|
|
// alter the folder pane selection when a server is removed
|
|
|
|
|
// or changed (currently, when the real username or real hostname change)
|
|
|
|
|
var gThreePaneIncomingServerListener = {
|
|
|
|
|
onServerLoaded: function(server) {},
|
|
|
|
|
onServerUnloaded: function(server) {
|
|
|
|
|
var selectedFolders = GetSelectedMsgFolders();
|
|
|
|
|
for (var i = 0; i < selectedFolders.length; i++) {
|
|
|
|
|
if (ServerContainsFolder(server, selectedFolders[i])) {
|
|
|
|
|
SelectServer(accountManager.defaultAccount.incomingServer);
|
|
|
|
|
// we've made a new selection, we're done
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if nothing is selected at this point, better go select the default
|
|
|
|
|
// this could happen if nothing was selected when the server was removed
|
|
|
|
|
selectedFolders = GetSelectedMsgFolders();
|
|
|
|
|
if (selectedFolders.length == 0) {
|
|
|
|
|
SelectServer(accountManager.defaultAccount.incomingServer);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onServerChanged: function(server) {
|
|
|
|
|
// if the current selected folder is on the server that changed
|
|
|
|
|
// and that server is an imap or news server,
|
|
|
|
|
// we need to update the selection.
|
|
|
|
|
// on those server types, we'll be reconnecting to the server
|
|
|
|
|
// and our currently selected folder will need to be reloaded
|
|
|
|
|
// or worse, be invalid.
|
|
|
|
|
if (server.type != "imap" && server.type !="nntp")
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var selectedFolders = GetSelectedMsgFolders();
|
|
|
|
|
for (var i = 0; i < selectedFolders.length; i++) {
|
|
|
|
|
// if the selected item is a server, we don't have to update
|
|
|
|
|
// the selection
|
|
|
|
|
if (!(selectedFolders[i].isServer) && ServerContainsFolder(server, selectedFolders[i])) {
|
|
|
|
|
SelectServer(server);
|
|
|
|
|
// we've made a new selection, we're done
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Functions related to startup */
|
|
|
|
|
function OnLoadMessenger()
|
|
|
|
|
{
|
|
|
|
|
setTimeout(delayedLoad, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function delayedLoad() {
|
|
|
|
|
AddMailOfflineObserver();
|
|
|
|
|
CreateMailWindowGlobals();
|
|
|
|
|
Create3PaneGlobals();
|
|
|
|
|
verifyAccounts(null);
|
|
|
|
|
|
|
|
|
|
HideAccountCentral();
|
|
|
|
|
loadStartPage();
|
|
|
|
|
InitMsgWindow();
|
|
|
|
|
|
|
|
|
|
messenger.SetWindow(window, msgWindow);
|
|
|
|
|
|
|
|
|
|
InitializeDataSources();
|
|
|
|
|
InitPanes();
|
|
|
|
|
|
|
|
|
|
accountManager.SetSpecialFoldersForIdentities();
|
|
|
|
|
accountManager.addIncomingServerListener(gThreePaneIncomingServerListener);
|
|
|
|
|
|
|
|
|
|
AddToSession();
|
|
|
|
|
//need to add to session before trying to load start folder otherwise listeners aren't
|
|
|
|
|
//set up correctly.
|
|
|
|
|
// argument[0] --> folder uri
|
|
|
|
|
// argument[1] --> optional message key
|
|
|
|
|
|
|
|
|
|
if ("arguments" in window && window.arguments[0])
|
|
|
|
|
{
|
|
|
|
|
gStartFolderUri = window.arguments[0];
|
|
|
|
|
gStartMsgKey = window.arguments[1];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gStartFolderUri = null;
|
|
|
|
|
gStartMsgKey = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setTimeout("loadStartFolder(gStartFolderUri);", 0);
|
|
|
|
|
|
|
|
|
|
// FIX ME - later we will be able to use onload from the overlay
|
|
|
|
|
OnLoadMsgHeaderPane();
|
|
|
|
|
|
|
|
|
|
gHaveLoadedMessage = false;
|
|
|
|
|
|
|
|
|
|
ThreadPaneOnLoad();
|
|
|
|
|
|
|
|
|
|
//Set focus to the Thread Pane the first time the window is opened.
|
|
|
|
|
SetFocusThreadPane();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function OnUnloadMessenger()
|
|
|
|
|
{
|
|
|
|
|
accountManager.removeIncomingServerListener(gThreePaneIncomingServerListener);
|
|
|
|
|
|
|
|
|
|
// FIX ME - later we will be able to use onload from the overlay
|
|
|
|
|
OnUnloadMsgHeaderPane();
|
|
|
|
|
|
|
|
|
|
OnMailWindowUnload();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Create3PaneGlobals()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// because the "open" state persists, we'll call
|
|
|
|
|
// PerformExpand() for all servers that are open at startup.
|
|
|
|
|
function PerformExpandForAllOpenServers()
|
|
|
|
|
{
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var view = folderTree.treeBoxObject.view;
|
|
|
|
|
for (var i = 0; i < view.rowCount; i++)
|
|
|
|
|
{
|
|
|
|
|
if (view.isContainer(i))
|
|
|
|
|
{
|
|
|
|
|
var folderResource = GetFolderResource(folderTree, i);
|
|
|
|
|
var msgFolder = folderResource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
var isServer = GetFolderAttribute(folderTree, folderResource, "IsServer");
|
|
|
|
|
if (isServer == "true")
|
|
|
|
|
{
|
|
|
|
|
if (view.isContainerOpen(i))
|
|
|
|
|
{
|
|
|
|
|
var server = msgFolder.server;
|
|
|
|
|
// Don't do this for imap servers. See bug #41943
|
|
|
|
|
if (server.type != "imap")
|
|
|
|
|
server.performExpand(msgWindow);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadStartFolder(initialUri)
|
|
|
|
|
{
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var defaultServer = null;
|
|
|
|
|
var startFolderResource = null;
|
|
|
|
|
var isLoginAtStartUpEnabled = false;
|
|
|
|
|
var enabledNewMailCheckOnce = false;
|
|
|
|
|
var mailCheckOncePref = "mail.startup.enabledMailCheckOnce";
|
|
|
|
|
|
|
|
|
|
//First get default account
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if(initialUri)
|
|
|
|
|
startFolderResource = RDF.GetResource(initialUri);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var defaultAccount = accountManager.defaultAccount;
|
|
|
|
|
|
|
|
|
|
defaultServer = defaultAccount.incomingServer;
|
|
|
|
|
var rootMsgFolder = defaultServer.rootMsgFolder;
|
|
|
|
|
|
|
|
|
|
startFolderResource = rootMsgFolder.QueryInterface(Components.interfaces.nsIRDFResource);
|
|
|
|
|
|
|
|
|
|
enabledNewMailCheckOnce = pref.getBoolPref(mailCheckOncePref);
|
|
|
|
|
|
|
|
|
|
// Enable checknew mail once by turning checkmail pref 'on' to bring
|
|
|
|
|
// all users to one plane. This allows all users to go to Inbox. User can
|
|
|
|
|
// always go to server settings panel and turn off "Check for new mail at startup"
|
|
|
|
|
if (!enabledNewMailCheckOnce)
|
|
|
|
|
{
|
|
|
|
|
pref.setBoolPref(mailCheckOncePref, true);
|
|
|
|
|
defaultServer.loginAtStartUp = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the user pref to see if the login at startup is enabled for default account
|
|
|
|
|
isLoginAtStartUpEnabled = defaultServer.loginAtStartUp;
|
|
|
|
|
|
|
|
|
|
// Get Inbox only if when we have to login
|
|
|
|
|
if (isLoginAtStartUpEnabled)
|
|
|
|
|
{
|
|
|
|
|
//now find Inbox
|
|
|
|
|
var outNumFolders = new Object();
|
|
|
|
|
var inboxFolder = rootMsgFolder.getFoldersWithFlag(0x1000, 1, outNumFolders);
|
|
|
|
|
if (!inboxFolder) return;
|
|
|
|
|
|
|
|
|
|
startFolderResource = inboxFolder.QueryInterface(Components.interfaces.nsIRDFResource);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// set the startFolderResource to the server, so we select it
|
|
|
|
|
// so we'll get account central
|
|
|
|
|
startFolderResource = RDF.GetResource(defaultServer.serverURI);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var startFolder = startFolderResource.QueryInterface(Components.interfaces.nsIFolder);
|
|
|
|
|
SelectFolder(startFolder.URI);
|
|
|
|
|
|
|
|
|
|
// only do this on startup, when we pass in null
|
|
|
|
|
if (!initialUri && isLoginAtStartUpEnabled)
|
|
|
|
|
{
|
|
|
|
|
// Perform biff on the server to check for new mail, except for imap
|
|
|
|
|
if (defaultServer.type != "imap")
|
|
|
|
|
defaultServer.PerformBiff();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// because the "open" state persists, we'll call
|
|
|
|
|
// PerformExpand() for all servers that are open at startup.
|
|
|
|
|
// note, because of the "news.persist_server_open_state_in_folderpane" pref
|
|
|
|
|
// we don't persist the "open" state of news servers across sessions,
|
|
|
|
|
// but we do within a session, so if you open another 3 pane
|
|
|
|
|
// and a news server is "open", we'll update the unread counts.
|
|
|
|
|
PerformExpandForAllOpenServers();
|
|
|
|
|
}
|
|
|
|
|
catch(ex)
|
|
|
|
|
{
|
|
|
|
|
dump(ex);
|
|
|
|
|
dump('Exception in LoadStartFolder caused by no default account. We know about this\n');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!initialUri)
|
|
|
|
|
{
|
|
|
|
|
MsgGetMessagesForAllServers(null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function TriggerGetMessages(server)
|
|
|
|
|
{
|
|
|
|
|
// downloadMessagesAtStartup for a given server type indicates whether
|
|
|
|
|
// or not there is a need to Trigger GetMessages action
|
|
|
|
|
if (server.downloadMessagesAtStartup)
|
|
|
|
|
MsgGetMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function AddToSession()
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
var mailSession = Components.classes[mailSessionContractID].getService(Components.interfaces.nsIMsgMailSession);
|
|
|
|
|
|
|
|
|
|
var nsIFolderListener = Components.interfaces.nsIFolderListener;
|
|
|
|
|
var notifyFlags = nsIFolderListener.intPropertyChanged | nsIFolderListener.event;
|
|
|
|
|
mailSession.AddFolderListener(folderListener, notifyFlags);
|
|
|
|
|
} catch (ex) {
|
|
|
|
|
dump("Error adding to session\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function InitPanes()
|
|
|
|
|
{
|
|
|
|
|
OnLoadFolderPane();
|
|
|
|
|
OnLoadThreadPane();
|
|
|
|
|
SetupCommandUpdateHandlers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function InitializeDataSources()
|
|
|
|
|
{
|
|
|
|
|
//Setup common mailwindow stuff.
|
|
|
|
|
AddDataSources();
|
|
|
|
|
|
|
|
|
|
//To threadpane move context menu
|
|
|
|
|
SetupMoveCopyMenus('threadPaneContext-moveMenu', accountManagerDataSource, folderDataSource);
|
|
|
|
|
|
|
|
|
|
//To threadpane copy content menu
|
|
|
|
|
SetupMoveCopyMenus('threadPaneContext-copyMenu', accountManagerDataSource, folderDataSource);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function OnFolderUnreadColAttrModified(event)
|
|
|
|
|
{
|
|
|
|
|
if (event.attrName == "hidden")
|
|
|
|
|
{
|
|
|
|
|
var folderNameCell = document.getElementById("folderNameCell");
|
|
|
|
|
var label = {"true": "?folderTreeName", "false": "?folderTreeSimpleName"};
|
|
|
|
|
folderNameCell.setAttribute("label", label[event.newValue]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// builds prior to 8-14-2001 did not have the unread and total columns
|
|
|
|
|
// in the folder pane. so if a user ran an old build, and then
|
|
|
|
|
// upgraded, they get the new columns, and this causes problems
|
|
|
|
|
// because it looks like all the folder names are gone (see bug #96979)
|
|
|
|
|
// to work around this, we hide those columns once, using the
|
|
|
|
|
// "mail.ui.folderpane.version" pref.
|
|
|
|
|
function UpgradeFolderPaneUI()
|
|
|
|
|
{
|
|
|
|
|
var folderPaneUIVersion = pref.getIntPref("mail.ui.folderpane.version");
|
|
|
|
|
|
|
|
|
|
if (folderPaneUIVersion == 1) {
|
|
|
|
|
var folderUnreadCol = document.getElementById("folderUnreadCol");
|
|
|
|
|
folderUnreadCol.setAttribute("hidden", "true");
|
|
|
|
|
var folderTotalCol = document.getElementById("folderTotalCol");
|
|
|
|
|
folderTotalCol.setAttribute("hidden", "true");
|
|
|
|
|
pref.setIntPref("mail.ui.folderpane.version", 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function OnLoadFolderPane()
|
|
|
|
|
{
|
|
|
|
|
UpgradeFolderPaneUI();
|
|
|
|
|
|
|
|
|
|
var folderUnreadCol = document.getElementById("folderUnreadCol");
|
|
|
|
|
var hidden = folderUnreadCol.getAttribute("hidden");
|
|
|
|
|
if (hidden != "true")
|
|
|
|
|
{
|
|
|
|
|
var folderNameCell = document.getElementById("folderNameCell");
|
|
|
|
|
folderNameCell.setAttribute("label", "?folderTreeSimpleName");
|
|
|
|
|
}
|
|
|
|
|
folderUnreadCol.addEventListener("DOMAttrModified", OnFolderUnreadColAttrModified, false);
|
|
|
|
|
|
|
|
|
|
//Add folderDataSource and accountManagerDataSource to folderPane
|
|
|
|
|
accountManagerDataSource = accountManagerDataSource.QueryInterface(Components.interfaces.nsIRDFDataSource);
|
|
|
|
|
folderDataSource = folderDataSource.QueryInterface(Components.interfaces.nsIRDFDataSource);
|
|
|
|
|
var database = GetFolderDatasource();
|
|
|
|
|
|
|
|
|
|
database.AddDataSource(accountManagerDataSource);
|
|
|
|
|
database.AddDataSource(folderDataSource);
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
folderTree.setAttribute("ref", "msgaccounts:/");
|
|
|
|
|
|
|
|
|
|
var folderTreeBuilder = folderTree.builder.QueryInterface(Components.interfaces.nsIXULTreeBuilder);
|
|
|
|
|
folderTreeBuilder.addObserver(folderObserver);
|
|
|
|
|
folderTree.addEventListener("click",FolderPaneOnClick,true);
|
|
|
|
|
folderTree.addEventListener("mousedown",TreeOnMouseDown,true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// builds prior to 12-08-2001 did not have the labels column
|
|
|
|
|
// in the thread pane. so if a user ran an old build, and then
|
|
|
|
|
// upgraded, they get the new column, and this causes problems.
|
|
|
|
|
// We're trying to avoid a similar problem to bug #96979.
|
|
|
|
|
// to work around this, we hide the column once, using the
|
|
|
|
|
// "mailnews.ui.threadpane.version" pref.
|
|
|
|
|
function UpgradeThreadPaneUI()
|
|
|
|
|
{
|
|
|
|
|
var labelCol;
|
|
|
|
|
var threadPaneUIVersion;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
threadPaneUIVersion = pref.getIntPref("mailnews.ui.threadpane.version");
|
|
|
|
|
if (threadPaneUIVersion == 1) {
|
|
|
|
|
labelCol = document.getElementById("labelCol");
|
|
|
|
|
labelCol.setAttribute("hidden", "true");
|
|
|
|
|
pref.setIntPref("mailnews.ui.threadpane.version", 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
dump("UpgradeThreadPane: ex = " + ex + "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function OnLoadThreadPane()
|
|
|
|
|
{
|
|
|
|
|
UpgradeThreadPaneUI();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetFolderDatasource()
|
|
|
|
|
{
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
return folderTree.database;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Functions for accessing particular parts of the window*/
|
|
|
|
|
function GetFolderTree()
|
|
|
|
|
{
|
|
|
|
|
if (! gFolderTree)
|
|
|
|
|
gFolderTree = document.getElementById("folderTree");
|
|
|
|
|
return gFolderTree;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetSearchInput()
|
|
|
|
|
{
|
|
|
|
|
if (gSearchInput) return gSearchInput;
|
|
|
|
|
gSearchInput = document.getElementById("searchInput");
|
|
|
|
|
return gSearchInput;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetMessagePane()
|
|
|
|
|
{
|
|
|
|
|
if (gMessagePane) return gMessagePane;
|
|
|
|
|
gMessagePane = document.getElementById("messagepanebox");
|
|
|
|
|
return gMessagePane;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetMessagePaneFrame()
|
|
|
|
|
{
|
|
|
|
|
return window.content;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function FindInSidebar(currentWindow, id)
|
|
|
|
|
{
|
|
|
|
|
var item = currentWindow.document.getElementById(id);
|
|
|
|
|
if(item)
|
|
|
|
|
return item;
|
|
|
|
|
|
|
|
|
|
for(var i = 0; i < currentWindow.frames.length; i++)
|
|
|
|
|
{
|
|
|
|
|
var frameItem = FindInSidebar(currentWindow.frames[i], id);
|
|
|
|
|
if(frameItem)
|
|
|
|
|
return frameItem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetThreadAndMessagePaneSplitter()
|
|
|
|
|
{
|
|
|
|
|
if(gThreadAndMessagePaneSplitter) return gThreadAndMessagePaneSplitter;
|
|
|
|
|
var splitter = document.getElementById('threadpane-splitter');
|
|
|
|
|
gThreadAndMessagePaneSplitter = splitter;
|
|
|
|
|
return splitter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetUnreadCountElement()
|
|
|
|
|
{
|
|
|
|
|
if(gUnreadCount) return gUnreadCount;
|
|
|
|
|
var unreadCount = document.getElementById('unreadMessageCount');
|
|
|
|
|
gUnreadCount = unreadCount;
|
|
|
|
|
return unreadCount;
|
|
|
|
|
}
|
|
|
|
|
function GetTotalCountElement()
|
|
|
|
|
{
|
|
|
|
|
if(gTotalCount) return gTotalCount;
|
|
|
|
|
var totalCount = document.getElementById('totalMessageCount');
|
|
|
|
|
gTotalCount = totalCount;
|
|
|
|
|
return totalCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function IsThreadAndMessagePaneSplitterCollapsed()
|
|
|
|
|
{
|
|
|
|
|
var messagePane = GetMessagePane();
|
|
|
|
|
try {
|
|
|
|
|
return (messagePane.getAttribute("collapsed") == "true");
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function IsFolderPaneCollapsed()
|
|
|
|
|
{
|
|
|
|
|
var folderPaneBox = GetFolderTree().parentNode;
|
|
|
|
|
return folderPaneBox.getAttribute("collapsed") == "true"
|
|
|
|
|
|| folderPaneBox.getAttribute("hidden") == "true";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function FindMessenger()
|
|
|
|
|
{
|
|
|
|
|
return messenger;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ClearThreadPaneSelection()
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
if (gDBView) {
|
|
|
|
|
var treeView = gDBView.QueryInterface(Components.interfaces.nsITreeView);
|
|
|
|
|
var treeSelection = treeView.selection;
|
|
|
|
|
if (treeSelection)
|
|
|
|
|
treeSelection.clearSelection();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
dump("ClearThreadPaneSelection: ex = " + ex + "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ClearMessagePane()
|
|
|
|
|
{
|
|
|
|
|
if(gHaveLoadedMessage)
|
|
|
|
|
{
|
|
|
|
|
gHaveLoadedMessage = false;
|
|
|
|
|
gCurrentDisplayedMessage = null;
|
|
|
|
|
if (GetMessagePaneFrame().location != "about:blank")
|
|
|
|
|
GetMessagePaneFrame().location = "about:blank";
|
|
|
|
|
// hide the message header view AND the message pane...
|
|
|
|
|
HideMessageHeaderPane();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function GetSelectedFolderIndex()
|
|
|
|
|
{
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var startIndex = {};
|
|
|
|
|
var endIndex = {};
|
|
|
|
|
folderTree.treeBoxObject.selection.getRangeAt(0, startIndex, endIndex);
|
|
|
|
|
return startIndex.value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Function to change the highlighted row to where the mouse was clicked
|
|
|
|
|
// without loading the contents of the selected row.
|
|
|
|
|
// It will also keep the outline/dotted line in the original row.
|
|
|
|
|
function ChangeSelectionWithoutContentLoad(event, tree)
|
|
|
|
|
{
|
|
|
|
|
var row = {};
|
|
|
|
|
var col = {};
|
|
|
|
|
var elt = {};
|
|
|
|
|
var treeBoxObj = tree.treeBoxObject;
|
|
|
|
|
var treeSelection = treeBoxObj.selection;
|
|
|
|
|
|
|
|
|
|
treeBoxObj.getCellAt(event.clientX, event.clientY, row, col, elt);
|
|
|
|
|
// make sure that row.value is valid so that it doesn't mess up
|
|
|
|
|
// the call to ensureRowIsVisible().
|
|
|
|
|
if((row.value >= 0) && !treeSelection.isSelected(row.value))
|
|
|
|
|
{
|
|
|
|
|
var saveCurrentIndex = treeSelection.currentIndex;
|
|
|
|
|
treeSelection.selectEventsSuppressed = true;
|
|
|
|
|
treeSelection.select(row.value);
|
|
|
|
|
treeSelection.currentIndex = saveCurrentIndex;
|
|
|
|
|
treeBoxObj.ensureRowIsVisible(row.value);
|
|
|
|
|
treeSelection.selectEventsSuppressed = false;
|
|
|
|
|
|
|
|
|
|
// Keep track of which row in the thread pane is currently selected.
|
|
|
|
|
if(tree.id == "threadTree")
|
|
|
|
|
gThreadPaneCurrentSelectedIndex = row.value;
|
|
|
|
|
}
|
|
|
|
|
event.preventBubble();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function TreeOnMouseDown(event)
|
|
|
|
|
{
|
|
|
|
|
// Detect right mouse click and change the highlight to the row
|
|
|
|
|
// where the click happened without loading the message headers in
|
|
|
|
|
// the Folder or Thread Pane.
|
|
|
|
|
if (event.button == 2)
|
|
|
|
|
{
|
|
|
|
|
gRightMouseButtonDown = true;
|
|
|
|
|
ChangeSelectionWithoutContentLoad(event, event.target.parentNode);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
gRightMouseButtonDown = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function FolderPaneOnClick(event)
|
|
|
|
|
{
|
|
|
|
|
// we only care about button 0 (left click) events
|
|
|
|
|
if (event.button != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var row = {};
|
|
|
|
|
var col = {};
|
|
|
|
|
var elt = {};
|
|
|
|
|
folderTree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, elt);
|
|
|
|
|
if (row.value == -1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (elt.value == "twisty")
|
|
|
|
|
{
|
|
|
|
|
var folderResource = GetFolderResource(folderTree, row.value);
|
|
|
|
|
var msgFolder = folderResource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
|
|
|
|
|
if (!(folderTree.treeBoxObject.view.isContainerOpen(row.value)))
|
|
|
|
|
{
|
|
|
|
|
var isServer = GetFolderAttribute(folderTree, folderResource, "IsServer");
|
|
|
|
|
if (isServer == "true")
|
|
|
|
|
{
|
|
|
|
|
var server = msgFolder.server;
|
|
|
|
|
server.performExpand(msgWindow);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var serverType = GetFolderAttribute(folderTree, folderResource, "ServerType");
|
|
|
|
|
if (serverType == "imap")
|
|
|
|
|
{
|
|
|
|
|
var imapFolder = folderResource.QueryInterface(Components.interfaces.nsIMsgImapMailFolder);
|
|
|
|
|
imapFolder.performExpand(msgWindow);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ((event.originalTarget.localName == "treecol") ||
|
|
|
|
|
(event.originalTarget.localName == "slider") ||
|
|
|
|
|
(event.originalTarget.localName == "scrollbarbutton")) {
|
|
|
|
|
// clicking on the name column in the folder pane should not sort
|
|
|
|
|
event.preventBubble();
|
|
|
|
|
}
|
|
|
|
|
else if (event.detail == 2) {
|
|
|
|
|
FolderPaneDoubleClick(row.value, event);
|
|
|
|
|
}
|
|
|
|
|
else if (gDBView && gDBView.isSearchView)
|
|
|
|
|
{
|
|
|
|
|
onClearSearch();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function FolderPaneDoubleClick(folderIndex, event)
|
|
|
|
|
{
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var folderResource = GetFolderResource(folderTree, folderIndex);
|
|
|
|
|
var msgFolder = folderResource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
var isServer = GetFolderAttribute(folderTree, folderResource, "IsServer");
|
|
|
|
|
|
|
|
|
|
if (isServer == "true")
|
|
|
|
|
{
|
|
|
|
|
if (!(folderTree.treeBoxObject.view.isContainerOpen(folderIndex)))
|
|
|
|
|
{
|
|
|
|
|
var server = msgFolder.server;
|
|
|
|
|
server.performExpand(msgWindow);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Open a new msg window only if we are double clicking on
|
|
|
|
|
// folders or newsgroups.
|
|
|
|
|
MsgOpenNewWindowForFolder(folderResource.Value, -1 /* key */);
|
|
|
|
|
|
|
|
|
|
// double clicking should not toggle the open / close state of the
|
|
|
|
|
// folder. this will happen if we don't prevent the event from
|
|
|
|
|
// bubbling to the default handler in tree.xml
|
|
|
|
|
event.preventBubble();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ChangeSelection(tree, newIndex)
|
|
|
|
|
{
|
|
|
|
|
if(newIndex >= 0)
|
|
|
|
|
{
|
|
|
|
|
tree.treeBoxObject.selection.select(newIndex);
|
|
|
|
|
tree.treeBoxObject.ensureRowIsVisible(newIndex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetSelectedFolders()
|
|
|
|
|
{
|
|
|
|
|
var folderArray = [];
|
|
|
|
|
var k = 0;
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var rangeCount = folderTree.treeBoxObject.selection.getRangeCount();
|
|
|
|
|
|
|
|
|
|
for(var i = 0; i < rangeCount; i++)
|
|
|
|
|
{
|
|
|
|
|
var startIndex = {};
|
|
|
|
|
var endIndex = {};
|
|
|
|
|
folderTree.treeBoxObject.selection.getRangeAt(i, startIndex, endIndex);
|
|
|
|
|
for (var j = startIndex.value; j <= endIndex.value; j++)
|
|
|
|
|
{
|
|
|
|
|
var folderResource = GetFolderResource(folderTree, j);
|
|
|
|
|
folderArray[k++] = folderResource.Value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return folderArray;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetSelectedMsgFolders()
|
|
|
|
|
{
|
|
|
|
|
var folderArray = [];
|
|
|
|
|
var k = 0;
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var rangeCount = folderTree.treeBoxObject.selection.getRangeCount();
|
|
|
|
|
|
|
|
|
|
for(var i = 0; i < rangeCount; i++)
|
|
|
|
|
{
|
|
|
|
|
var startIndex = {};
|
|
|
|
|
var endIndex = {};
|
|
|
|
|
folderTree.treeBoxObject.selection.getRangeAt(i, startIndex, endIndex);
|
|
|
|
|
for (var j = startIndex.value; j <= endIndex.value; j++)
|
|
|
|
|
{
|
|
|
|
|
var folderResource = GetFolderResource(folderTree, j);
|
|
|
|
|
if (folderResource.Value != "http://home.netscape.com/NC-rdf#PageTitleFakeAccount") {
|
|
|
|
|
var msgFolder = folderResource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
|
|
|
|
|
if(msgFolder)
|
|
|
|
|
folderArray[k++] = msgFolder;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return folderArray;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetFirstSelectedMessage()
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
// Use this instead of gDBView.URIForFirstSelectedMessage, else it
|
|
|
|
|
// will return the currentIndex message instead of the highlighted
|
|
|
|
|
// message.
|
|
|
|
|
//
|
|
|
|
|
// note, there may not be any selected messages
|
|
|
|
|
//
|
|
|
|
|
// XXX todo
|
|
|
|
|
// is this inefficient when we've got a lot of message selected?
|
|
|
|
|
var selectedMessages = GetSelectedMessages();
|
|
|
|
|
if (selectedMessages)
|
|
|
|
|
return selectedMessages[0];
|
|
|
|
|
else
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetSelectedIndices(dbView)
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
var indicesArray = {};
|
|
|
|
|
var length = {};
|
|
|
|
|
dbView.getIndicesForSelection(indicesArray,length);
|
|
|
|
|
return indicesArray.value;
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
dump("ex = " + ex + "\n");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetSelectedMessages()
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
var messageArray = {};
|
|
|
|
|
var length = {};
|
|
|
|
|
gDBView.getURIsForSelection(messageArray,length);
|
|
|
|
|
return messageArray.value;
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
dump("ex = " + ex + "\n");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetLoadedMsgFolder()
|
|
|
|
|
{
|
|
|
|
|
if (!gDBView) return null;
|
|
|
|
|
return gDBView.msgFolder;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetLoadedMessage()
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
return gDBView.URIForFirstSelectedMessage;
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Clear everything related to the current message. called after load start page.
|
|
|
|
|
function ClearMessageSelection()
|
|
|
|
|
{
|
|
|
|
|
ClearThreadPaneSelection();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetCompositeDataSource(command)
|
|
|
|
|
{
|
|
|
|
|
if (command == "GetNewMessages" || command == "NewFolder" || command == "MarkAllMessagesRead")
|
|
|
|
|
return GetFolderDatasource();
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SetNextMessageAfterDelete()
|
|
|
|
|
{
|
|
|
|
|
var treeSelection = GetThreadTree().treeBoxObject.selection;
|
|
|
|
|
|
|
|
|
|
gThreadPaneDeleteOrMoveOccurred = true;
|
|
|
|
|
if (treeSelection.isSelected(treeSelection.currentIndex))
|
|
|
|
|
gNextMessageViewIndexAfterDelete = gDBView.msgToSelectAfterDelete;
|
|
|
|
|
else if (treeSelection.currentIndex > gThreadPaneCurrentSelectedIndex)
|
|
|
|
|
// Since the currentIndex (the row with the outline/dotted line) is greater
|
|
|
|
|
// than the currently selected row (the row that is highlighted), we need to
|
|
|
|
|
// make sure that upon a Delete or Move of the selected row, the highlight
|
|
|
|
|
// returns to the currentIndex'ed row. It is necessary to subtract 1
|
|
|
|
|
// because the row being deleted is above the row with the currentIndex.
|
|
|
|
|
// If the subtraction is not done, then the highlight will end up on the
|
|
|
|
|
// row listed after the currentIndex'ed row.
|
|
|
|
|
gNextMessageViewIndexAfterDelete = treeSelection.currentIndex - 1;
|
|
|
|
|
else
|
|
|
|
|
gNextMessageViewIndexAfterDelete = treeSelection.currentIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function EnsureAllAncestorsAreExpanded(tree, resource)
|
|
|
|
|
{
|
|
|
|
|
// get the parent of the desired folder, and then try to get
|
|
|
|
|
// the index of the parent in the tree
|
|
|
|
|
var folder = resource.QueryInterface(Components.interfaces.nsIFolder);
|
|
|
|
|
|
|
|
|
|
// if this is a server, there are no ancestors, so stop.
|
|
|
|
|
var msgFolder = folder.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
if (msgFolder.isServer)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var parentFolderResource = RDF.GetResource(folder.parent.URI);
|
|
|
|
|
var folderIndex = GetFolderIndex(tree, parentFolderResource);
|
|
|
|
|
|
|
|
|
|
if (folderIndex == -1) {
|
|
|
|
|
// if we couldn't find the parent, recurse
|
|
|
|
|
EnsureAllAncestorsAreExpanded(tree, parentFolderResource);
|
|
|
|
|
// ok, now we should be able to find the parent
|
|
|
|
|
folderIndex = GetFolderIndex(tree, parentFolderResource);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if the parent isn't open, open it
|
|
|
|
|
if (!(tree.treeBoxObject.view.isContainerOpen(folderIndex)))
|
|
|
|
|
tree.treeBoxObject.view.toggleOpenState(folderIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SelectFolder(folderUri)
|
|
|
|
|
{
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var folderResource = RDF.GetResource(folderUri);
|
|
|
|
|
|
|
|
|
|
// before we can select a folder, we need to make sure it is "visible"
|
|
|
|
|
// in the tree. to do that, we need to ensure that all its
|
|
|
|
|
// ancestors are expanded
|
|
|
|
|
EnsureAllAncestorsAreExpanded(folderTree, folderResource);
|
|
|
|
|
var folderIndex = GetFolderIndex(folderTree, folderResource);
|
|
|
|
|
ChangeSelection(folderTree, folderIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SelectMessage(messageUri)
|
|
|
|
|
{
|
|
|
|
|
var msgHdr = messenger.messageServiceFromURI(messageUri).messageURIToMsgHdr(messageUri);
|
|
|
|
|
if (msgHdr)
|
|
|
|
|
gDBView.selectMsgByKey(msgHdr.messageKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ReloadWithAllParts()
|
|
|
|
|
{
|
|
|
|
|
gDBView.reloadMessageWithAllParts();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ReloadMessage()
|
|
|
|
|
{
|
|
|
|
|
gDBView.reloadMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SetBusyCursor(window, enable)
|
|
|
|
|
{
|
|
|
|
|
// setCursor() is only available for chrome windows.
|
|
|
|
|
// However one of our frames is the start page which
|
|
|
|
|
// is a non-chrome window, so check if this window has a
|
|
|
|
|
// setCursor method
|
|
|
|
|
if ("setCursor" in window) {
|
|
|
|
|
if (enable)
|
|
|
|
|
window.setCursor("wait");
|
|
|
|
|
else
|
|
|
|
|
window.setCursor("auto");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var numFrames = window.frames.length;
|
|
|
|
|
for(var i = 0; i < numFrames; i++)
|
|
|
|
|
SetBusyCursor(window.frames[i], enable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetDBView()
|
|
|
|
|
{
|
|
|
|
|
return gDBView;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetFolderResource(tree, index)
|
|
|
|
|
{
|
|
|
|
|
return tree.builderView.getResourceAtIndex(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetFolderIndex(tree, resource)
|
|
|
|
|
{
|
|
|
|
|
return tree.builderView.getIndexOfResource(resource);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetFolderAttribute(tree, source, attribute)
|
|
|
|
|
{
|
|
|
|
|
var property = RDF.GetResource("http://home.netscape.com/NC-rdf#" + attribute);
|
|
|
|
|
var target = tree.database.GetTarget(source, property, true);
|
|
|
|
|
if (target)
|
|
|
|
|
target = target.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
|
|
|
|
return target;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-16 04:33:05 +04:00
|
|
|
|
// Controller object for folder pane
|
|
|
|
|
var FolderPaneController =
|
|
|
|
|
{
|
|
|
|
|
supportsCommand: function(command)
|
|
|
|
|
{
|
|
|
|
|
switch ( command )
|
|
|
|
|
{
|
|
|
|
|
case "cmd_delete":
|
|
|
|
|
case "button_delete":
|
|
|
|
|
case "cmd_selectAll":
|
|
|
|
|
case "cmd_cut":
|
|
|
|
|
case "cmd_copy":
|
|
|
|
|
case "cmd_paste":
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
isCommandEnabled: function(command)
|
|
|
|
|
{
|
|
|
|
|
if (IsFakeAccount())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
switch ( command )
|
|
|
|
|
{
|
|
|
|
|
case "cmd_selectAll":
|
|
|
|
|
// the folder pane (currently)
|
|
|
|
|
// only handles single selection
|
|
|
|
|
// so we forward select all to the thread pane
|
|
|
|
|
// if there is no DBView
|
|
|
|
|
// don't bother sending to the thread pane
|
|
|
|
|
// this can happen when we've selected a server
|
|
|
|
|
// and account central is displayed
|
|
|
|
|
return (gDBView != null);
|
|
|
|
|
case "cmd_cut":
|
|
|
|
|
case "cmd_copy":
|
|
|
|
|
case "cmd_paste":
|
|
|
|
|
return false;
|
|
|
|
|
case "cmd_delete":
|
|
|
|
|
case "button_delete":
|
|
|
|
|
if ( command == "cmd_delete" )
|
|
|
|
|
goSetMenuValue(command, 'valueFolder');
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var startIndex = {};
|
|
|
|
|
var endIndex = {};
|
|
|
|
|
folderTree.treeBoxObject.selection.getRangeAt(0, startIndex, endIndex);
|
|
|
|
|
if (startIndex.value >= 0) {
|
|
|
|
|
var canDeleteThisFolder;
|
|
|
|
|
var specialFolder = null;
|
|
|
|
|
var isServer = null;
|
|
|
|
|
var serverType = null;
|
|
|
|
|
try {
|
|
|
|
|
var folderResource = GetFolderResource(folderTree, startIndex.value);
|
|
|
|
|
specialFolder = GetFolderAttribute(folderTree, folderResource, "SpecialFolder");
|
|
|
|
|
isServer = GetFolderAttribute(folderTree, folderResource, "IsServer");
|
|
|
|
|
serverType = GetFolderAttribute(folderTree, folderResource, "ServerType");
|
|
|
|
|
if (serverType == "nntp") {
|
|
|
|
|
if ( command == "cmd_delete" ) {
|
|
|
|
|
goSetMenuValue(command, 'valueNewsgroup');
|
|
|
|
|
goSetAccessKey(command, 'valueNewsgroupAccessKey');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
//dump("specialFolder failure: " + ex + "\n");
|
|
|
|
|
}
|
|
|
|
|
if (specialFolder == "Inbox" || specialFolder == "Trash" || specialFolder == "Drafts" || specialFolder == "Sent" || specialFolder == "Templates" || specialFolder == "Unsent Messages" || isServer == "true")
|
|
|
|
|
canDeleteThisFolder = false;
|
|
|
|
|
else
|
|
|
|
|
canDeleteThisFolder = true;
|
|
|
|
|
return canDeleteThisFolder && isCommandEnabled(command);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
doCommand: function(command)
|
|
|
|
|
{
|
|
|
|
|
// if the user invoked a key short cut then it is possible that we got here for a command which is
|
|
|
|
|
// really disabled. kick out if the command should be disabled.
|
|
|
|
|
if (!this.isCommandEnabled(command)) return;
|
|
|
|
|
|
|
|
|
|
switch ( command )
|
|
|
|
|
{
|
|
|
|
|
case "cmd_delete":
|
|
|
|
|
case "button_delete":
|
|
|
|
|
MsgDeleteFolder();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_selectAll":
|
|
|
|
|
// the folder pane (currently)
|
|
|
|
|
// only handles single selection
|
|
|
|
|
// so we forward select all to the thread pane
|
|
|
|
|
SendCommandToThreadPane(command);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onEvent: function(event)
|
|
|
|
|
{
|
|
|
|
|
// on blur events set the menu item texts back to the normal values
|
|
|
|
|
if ( event == 'blur' )
|
|
|
|
|
{
|
|
|
|
|
goSetMenuValue('cmd_delete', 'valueDefault');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Controller object for thread pane
|
|
|
|
|
var ThreadPaneController =
|
|
|
|
|
{
|
|
|
|
|
supportsCommand: function(command)
|
|
|
|
|
{
|
|
|
|
|
switch ( command )
|
|
|
|
|
{
|
|
|
|
|
case "cmd_selectAll":
|
|
|
|
|
case "cmd_cut":
|
|
|
|
|
case "cmd_copy":
|
|
|
|
|
case "cmd_paste":
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
isCommandEnabled: function(command)
|
|
|
|
|
{
|
|
|
|
|
switch ( command )
|
|
|
|
|
{
|
|
|
|
|
case "cmd_selectAll":
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case "cmd_cut":
|
|
|
|
|
case "cmd_copy":
|
|
|
|
|
case "cmd_paste":
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
doCommand: function(command)
|
|
|
|
|
{
|
|
|
|
|
// if the user invoked a key short cut then it is possible that we got here for a command which is
|
|
|
|
|
// really disabled. kick out if the command should be disabled.
|
|
|
|
|
if (!this.isCommandEnabled(command)) return;
|
|
|
|
|
if (!gDBView) return;
|
|
|
|
|
|
|
|
|
|
switch ( command )
|
|
|
|
|
{
|
|
|
|
|
case "cmd_selectAll":
|
|
|
|
|
// if in threaded mode, the view will expand all before selecting all
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.selectAll)
|
|
|
|
|
if (gDBView.numSelected != 1) {
|
|
|
|
|
setTitleFromFolder(gDBView.msgFolder,null);
|
|
|
|
|
ClearMessagePane();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onEvent: function(event)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// DefaultController object (handles commands when one of the trees does not have focus)
|
|
|
|
|
var DefaultController =
|
|
|
|
|
{
|
|
|
|
|
supportsCommand: function(command)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
switch ( command )
|
|
|
|
|
{
|
|
|
|
|
case "cmd_createFilterFromPopup":
|
|
|
|
|
case "cmd_close":
|
|
|
|
|
case "cmd_reply":
|
|
|
|
|
case "button_reply":
|
|
|
|
|
case "cmd_replySender":
|
|
|
|
|
case "cmd_replyGroup":
|
|
|
|
|
case "cmd_replyall":
|
|
|
|
|
case "button_replyall":
|
|
|
|
|
case "cmd_forward":
|
|
|
|
|
case "button_forward":
|
|
|
|
|
case "cmd_forwardInline":
|
|
|
|
|
case "cmd_forwardAttachment":
|
|
|
|
|
case "cmd_editAsNew":
|
|
|
|
|
case "cmd_createFilterFromMenu":
|
|
|
|
|
case "cmd_delete":
|
|
|
|
|
case "button_delete":
|
|
|
|
|
case "cmd_shiftDelete":
|
|
|
|
|
case "cmd_nextMsg":
|
|
|
|
|
case "button_next":
|
|
|
|
|
case "cmd_nextUnreadMsg":
|
|
|
|
|
case "cmd_nextFlaggedMsg":
|
|
|
|
|
case "cmd_nextUnreadThread":
|
|
|
|
|
case "cmd_previousMsg":
|
|
|
|
|
case "cmd_previousUnreadMsg":
|
|
|
|
|
case "cmd_previousFlaggedMsg":
|
|
|
|
|
case "cmd_viewAllMsgs":
|
|
|
|
|
case "cmd_viewUnreadMsgs":
|
|
|
|
|
case "cmd_viewThreadsWithUnread":
|
|
|
|
|
case "cmd_viewWatchedThreadsWithUnread":
|
|
|
|
|
case "cmd_viewIgnoredThreads":
|
|
|
|
|
case "cmd_undo":
|
|
|
|
|
case "cmd_redo":
|
|
|
|
|
case "cmd_expandAllThreads":
|
|
|
|
|
case "cmd_collapseAllThreads":
|
|
|
|
|
case "cmd_renameFolder":
|
|
|
|
|
case "cmd_sendUnsentMsgs":
|
|
|
|
|
case "cmd_openMessage":
|
|
|
|
|
case "button_print":
|
|
|
|
|
case "cmd_print":
|
|
|
|
|
case "cmd_printSetup":
|
|
|
|
|
case "cmd_saveAsFile":
|
|
|
|
|
case "cmd_saveAsTemplate":
|
|
|
|
|
case "cmd_properties":
|
|
|
|
|
case "cmd_viewPageSource":
|
|
|
|
|
case "cmd_setFolderCharset":
|
|
|
|
|
case "cmd_reload":
|
|
|
|
|
case "button_getNewMessages":
|
|
|
|
|
case "cmd_getNewMessages":
|
|
|
|
|
case "cmd_getMsgsForAuthAccounts":
|
|
|
|
|
case "cmd_getNextNMessages":
|
|
|
|
|
case "cmd_find":
|
|
|
|
|
case "cmd_findAgain":
|
|
|
|
|
case "cmd_search":
|
|
|
|
|
case "button_mark":
|
|
|
|
|
case "cmd_markAsRead":
|
|
|
|
|
case "cmd_markAllRead":
|
|
|
|
|
case "cmd_markThreadAsRead":
|
|
|
|
|
case "cmd_markAsFlagged":
|
|
|
|
|
case "cmd_label0":
|
|
|
|
|
case "cmd_label1":
|
|
|
|
|
case "cmd_label2":
|
|
|
|
|
case "cmd_label3":
|
|
|
|
|
case "cmd_label4":
|
|
|
|
|
case "cmd_label5":
|
|
|
|
|
case "button_file":
|
|
|
|
|
case "cmd_file":
|
|
|
|
|
case "cmd_emptyTrash":
|
|
|
|
|
case "cmd_compactFolder":
|
|
|
|
|
case "cmd_sortByThread":
|
|
|
|
|
case "cmd_settingsOffline":
|
|
|
|
|
case "cmd_close":
|
|
|
|
|
case "cmd_selectThread":
|
|
|
|
|
return true;
|
|
|
|
|
case "cmd_downloadFlagged":
|
|
|
|
|
case "cmd_downloadSelected":
|
|
|
|
|
case "cmd_synchronizeOffline":
|
|
|
|
|
return(CheckOnline());
|
|
|
|
|
|
|
|
|
|
case "cmd_watchThread":
|
|
|
|
|
case "cmd_killThread":
|
|
|
|
|
return(isNewsURI(GetFirstSelectedMessage()));
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
isCommandEnabled: function(command)
|
|
|
|
|
{
|
|
|
|
|
var enabled = new Object();
|
|
|
|
|
enabled.value = false;
|
|
|
|
|
var checkStatus = new Object();
|
|
|
|
|
|
|
|
|
|
if (IsFakeAccount())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// note, all commands that get fired on a single key need to check MailAreaHasFocus() as well
|
|
|
|
|
switch ( command )
|
|
|
|
|
{
|
|
|
|
|
case "cmd_delete":
|
|
|
|
|
UpdateDeleteCommand();
|
|
|
|
|
// fall through
|
|
|
|
|
case "button_delete":
|
|
|
|
|
if (gDBView)
|
|
|
|
|
gDBView.getCommandStatus(nsMsgViewCommandType.deleteMsg, enabled, checkStatus);
|
|
|
|
|
return enabled.value;
|
|
|
|
|
case "cmd_shiftDelete":
|
|
|
|
|
if (gDBView)
|
|
|
|
|
gDBView.getCommandStatus(nsMsgViewCommandType.deleteNoTrash, enabled, checkStatus);
|
|
|
|
|
return enabled.value;
|
|
|
|
|
case "cmd_killThread":
|
|
|
|
|
return ((GetNumSelectedMessages() == 1) && MailAreaHasFocus() && IsViewNavigationItemEnabled());
|
|
|
|
|
case "cmd_watchThread":
|
|
|
|
|
if (MailAreaHasFocus() && (GetNumSelectedMessages() == 1) && gDBView)
|
|
|
|
|
gDBView.getCommandStatus(nsMsgViewCommandType.toggleThreadWatched, enabled, checkStatus);
|
|
|
|
|
return enabled.value;
|
|
|
|
|
case "cmd_createFilterFromPopup":
|
|
|
|
|
var loadedFolder = GetLoadedMsgFolder();
|
|
|
|
|
if (!(loadedFolder && loadedFolder.server.canHaveFilters))
|
|
|
|
|
return false;
|
|
|
|
|
case "cmd_createFilterFromMenu":
|
|
|
|
|
loadedFolder = GetLoadedMsgFolder();
|
|
|
|
|
if (!(loadedFolder && loadedFolder.server.canHaveFilters) || !(IsMessageDisplayedInMessagePane()))
|
|
|
|
|
return false;
|
|
|
|
|
case "cmd_reply":
|
|
|
|
|
case "button_reply":
|
|
|
|
|
case "cmd_replySender":
|
|
|
|
|
case "cmd_replyGroup":
|
|
|
|
|
case "cmd_replyall":
|
|
|
|
|
case "button_replyall":
|
|
|
|
|
case "cmd_forward":
|
|
|
|
|
case "button_forward":
|
|
|
|
|
case "cmd_forwardInline":
|
|
|
|
|
case "cmd_forwardAttachment":
|
|
|
|
|
case "cmd_editAsNew":
|
|
|
|
|
case "cmd_openMessage":
|
|
|
|
|
case "button_print":
|
|
|
|
|
case "cmd_print":
|
|
|
|
|
case "cmd_saveAsFile":
|
|
|
|
|
case "cmd_saveAsTemplate":
|
|
|
|
|
case "cmd_viewPageSource":
|
|
|
|
|
case "cmd_reload":
|
|
|
|
|
if ( GetNumSelectedMessages() > 0)
|
|
|
|
|
{
|
|
|
|
|
if (gDBView)
|
|
|
|
|
{
|
|
|
|
|
gDBView.getCommandStatus(nsMsgViewCommandType.cmdRequiringMsgBody, enabled, checkStatus);
|
|
|
|
|
return enabled.value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
case "cmd_printSetup":
|
|
|
|
|
return true;
|
|
|
|
|
case "cmd_markAsFlagged":
|
|
|
|
|
case "button_file":
|
|
|
|
|
case "cmd_file":
|
|
|
|
|
return (GetNumSelectedMessages() > 0 );
|
|
|
|
|
case "button_mark":
|
|
|
|
|
case "cmd_markAsRead":
|
|
|
|
|
case "cmd_markThreadAsRead":
|
|
|
|
|
case "cmd_label0":
|
|
|
|
|
case "cmd_label1":
|
|
|
|
|
case "cmd_label2":
|
|
|
|
|
case "cmd_label3":
|
|
|
|
|
case "cmd_label4":
|
|
|
|
|
case "cmd_label5":
|
|
|
|
|
return(MailAreaHasFocus() && GetNumSelectedMessages() > 0);
|
|
|
|
|
case "button_next":
|
|
|
|
|
return IsViewNavigationItemEnabled();
|
|
|
|
|
case "cmd_nextMsg":
|
|
|
|
|
case "cmd_nextUnreadMsg":
|
|
|
|
|
case "cmd_nextUnreadThread":
|
|
|
|
|
case "cmd_previousMsg":
|
|
|
|
|
case "cmd_previousUnreadMsg":
|
|
|
|
|
return (MailAreaHasFocus() && IsViewNavigationItemEnabled());
|
|
|
|
|
case "cmd_markAllRead":
|
|
|
|
|
return (MailAreaHasFocus() && IsFolderSelected());
|
|
|
|
|
case "cmd_find":
|
|
|
|
|
case "cmd_findAgain":
|
|
|
|
|
return IsMessageDisplayedInMessagePane();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_search":
|
|
|
|
|
return IsCanSearchMessagesEnabled();
|
|
|
|
|
// these are enabled on when we are in threaded mode
|
|
|
|
|
case "cmd_selectThread":
|
|
|
|
|
if (GetNumSelectedMessages() <= 0) return false;
|
|
|
|
|
case "cmd_expandAllThreads":
|
|
|
|
|
case "cmd_collapseAllThreads":
|
|
|
|
|
if (!gDBView) return false;
|
|
|
|
|
return (gDBView.sortType == nsMsgViewSortType.byThread);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_nextFlaggedMsg":
|
|
|
|
|
case "cmd_previousFlaggedMsg":
|
|
|
|
|
return IsViewNavigationItemEnabled();
|
|
|
|
|
case "cmd_viewAllMsgs":
|
|
|
|
|
case "cmd_sortByThread":
|
|
|
|
|
case "cmd_viewUnreadMsgs":
|
|
|
|
|
case "cmd_viewThreadsWithUnread":
|
|
|
|
|
case "cmd_viewWatchedThreadsWithUnread":
|
|
|
|
|
case "cmd_viewIgnoredThreads":
|
|
|
|
|
case "cmd_stop":
|
|
|
|
|
return true;
|
|
|
|
|
case "cmd_undo":
|
|
|
|
|
case "cmd_redo":
|
|
|
|
|
return SetupUndoRedoCommand(command);
|
|
|
|
|
case "cmd_renameFolder":
|
|
|
|
|
return IsRenameFolderEnabled();
|
|
|
|
|
case "cmd_sendUnsentMsgs":
|
|
|
|
|
return IsSendUnsentMsgsEnabled(null);
|
|
|
|
|
case "cmd_properties":
|
|
|
|
|
return IsPropertiesEnabled(command);
|
|
|
|
|
case "button_getNewMessages":
|
|
|
|
|
case "cmd_getNewMessages":
|
|
|
|
|
case "cmd_getMsgsForAuthAccounts":
|
|
|
|
|
return IsGetNewMessagesEnabled();
|
|
|
|
|
case "cmd_getNextNMessages":
|
|
|
|
|
return IsGetNextNMessagesEnabled();
|
|
|
|
|
case "cmd_emptyTrash":
|
|
|
|
|
return IsEmptyTrashEnabled();
|
|
|
|
|
case "cmd_compactFolder":
|
|
|
|
|
return IsCompactFolderEnabled();
|
|
|
|
|
case "cmd_setFolderCharset":
|
|
|
|
|
return IsFolderCharsetEnabled();
|
|
|
|
|
case "cmd_close":
|
|
|
|
|
return true;
|
|
|
|
|
case "cmd_downloadFlagged":
|
|
|
|
|
return(CheckOnline());
|
|
|
|
|
case "cmd_downloadSelected":
|
|
|
|
|
return(MailAreaHasFocus() && IsFolderSelected() && CheckOnline() && GetNumSelectedMessages() > 0);
|
|
|
|
|
case "cmd_synchronizeOffline":
|
|
|
|
|
return CheckOnline() && IsAccountOfflineEnabled();
|
|
|
|
|
case "cmd_settingsOffline":
|
|
|
|
|
return (MailAreaHasFocus() && IsAccountOfflineEnabled());
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
doCommand: function(command)
|
|
|
|
|
{
|
|
|
|
|
// if the user invoked a key short cut then it is possible that we got here for a command which is
|
|
|
|
|
// really disabled. kick out if the command should be disabled.
|
|
|
|
|
if (!this.isCommandEnabled(command)) return;
|
|
|
|
|
|
|
|
|
|
switch ( command )
|
|
|
|
|
{
|
|
|
|
|
case "cmd_close":
|
|
|
|
|
CloseMailWindow();
|
|
|
|
|
break;
|
|
|
|
|
case "button_getNewMessages":
|
|
|
|
|
case "cmd_getNewMessages":
|
|
|
|
|
MsgGetMessage();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_getMsgsForAuthAccounts":
|
|
|
|
|
MsgGetMessagesForAllAuthenticatedAccounts();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_getNextNMessages":
|
|
|
|
|
MsgGetNextNMessages();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_reply":
|
|
|
|
|
MsgReplyMessage(null);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_replySender":
|
|
|
|
|
MsgReplySender(null);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_replyGroup":
|
|
|
|
|
MsgReplyGroup(null);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_replyall":
|
|
|
|
|
MsgReplyToAllMessage(null);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_forward":
|
|
|
|
|
MsgForwardMessage(null);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_forwardInline":
|
|
|
|
|
MsgForwardAsInline(null);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_forwardAttachment":
|
|
|
|
|
MsgForwardAsAttachment(null);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_editAsNew":
|
|
|
|
|
MsgEditMessageAsNew();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_createFilterFromMenu":
|
|
|
|
|
MsgCreateFilter();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_createFilterFromPopup":
|
|
|
|
|
break;// This does nothing because the createfilter is invoked from the popupnode oncommand.
|
|
|
|
|
case "button_delete":
|
|
|
|
|
case "cmd_delete":
|
|
|
|
|
SetNextMessageAfterDelete();
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.deleteMsg);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_shiftDelete":
|
|
|
|
|
SetNextMessageAfterDelete();
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.deleteNoTrash);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_killThread":
|
|
|
|
|
/* kill thread kills the thread and then does a next unread */
|
|
|
|
|
GoNextMessage(nsMsgNavigationType.toggleThreadKilled, true);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_watchThread":
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.toggleThreadWatched);
|
|
|
|
|
break;
|
|
|
|
|
case "button_next":
|
|
|
|
|
case "cmd_nextUnreadMsg":
|
|
|
|
|
MsgNextUnreadMessage();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_nextUnreadThread":
|
|
|
|
|
MsgNextUnreadThread();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_nextMsg":
|
|
|
|
|
MsgNextMessage();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_nextFlaggedMsg":
|
|
|
|
|
MsgNextFlaggedMessage();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_previousMsg":
|
|
|
|
|
MsgPreviousMessage();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_previousUnreadMsg":
|
|
|
|
|
MsgPreviousUnreadMessage();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_previousFlaggedMsg":
|
|
|
|
|
MsgPreviousFlaggedMessage();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_sortByThread":
|
|
|
|
|
MsgSortByThread();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_viewAllMsgs":
|
|
|
|
|
case "cmd_viewThreadsWithUnread":
|
|
|
|
|
case "cmd_viewWatchedThreadsWithUnread":
|
|
|
|
|
case "cmd_viewUnreadMsgs":
|
|
|
|
|
case "cmd_viewIgnoredThreads":
|
|
|
|
|
SwitchView(command);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_undo":
|
|
|
|
|
messenger.Undo(msgWindow);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_redo":
|
|
|
|
|
messenger.Redo(msgWindow);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_expandAllThreads":
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.expandAll);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_collapseAllThreads":
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.collapseAll);
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_renameFolder":
|
|
|
|
|
MsgRenameFolder();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_sendUnsentMsgs":
|
|
|
|
|
MsgSendUnsentMsgs();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_openMessage":
|
|
|
|
|
MsgOpenSelectedMessages();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_printSetup":
|
|
|
|
|
goPageSetup();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_print":
|
|
|
|
|
PrintEnginePrint();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_saveAsFile":
|
|
|
|
|
MsgSaveAsFile();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_saveAsTemplate":
|
|
|
|
|
MsgSaveAsTemplate();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_viewPageSource":
|
|
|
|
|
MsgViewPageSource();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_setFolderCharset":
|
|
|
|
|
MsgSetFolderCharset();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_reload":
|
|
|
|
|
MsgReload();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_find":
|
|
|
|
|
MsgFind();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_findAgain":
|
|
|
|
|
MsgFindAgain();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_properties":
|
|
|
|
|
MsgFolderProperties();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_search":
|
|
|
|
|
MsgSearchMessages();
|
|
|
|
|
case "button_mark":
|
|
|
|
|
case "cmd_markAsRead":
|
|
|
|
|
MsgMarkMsgAsRead(null);
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_markThreadAsRead":
|
|
|
|
|
MsgMarkThreadAsRead();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_markAllRead":
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.markAllRead);
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_stop":
|
|
|
|
|
MsgStop();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_markAsFlagged":
|
|
|
|
|
MsgMarkAsFlagged(null);
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_label0":
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.label0);
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_label1":
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.label1);
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_label2":
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.label2);
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_label3":
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.label3);
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_label4":
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.label4);
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_label5":
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.label5);
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_emptyTrash":
|
|
|
|
|
MsgEmptyTrash();
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_compactFolder":
|
|
|
|
|
MsgCompactFolder(true);
|
|
|
|
|
return;
|
|
|
|
|
case "cmd_downloadFlagged":
|
|
|
|
|
MsgDownloadFlagged();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_downloadSelected":
|
|
|
|
|
MsgDownloadSelected();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_synchronizeOffline":
|
|
|
|
|
MsgSynchronizeOffline();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_settingsOffline":
|
|
|
|
|
MsgSettingsOffline();
|
|
|
|
|
break;
|
|
|
|
|
case "cmd_selectThread":
|
|
|
|
|
gDBView.doCommand(nsMsgViewCommandType.selectThread);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onEvent: function(event)
|
|
|
|
|
{
|
|
|
|
|
// on blur events set the menu item texts back to the normal values
|
|
|
|
|
if ( event == 'blur' )
|
|
|
|
|
{
|
|
|
|
|
goSetMenuValue('cmd_delete', 'valueDefault');
|
|
|
|
|
goSetMenuValue('cmd_undo', 'valueDefault');
|
|
|
|
|
goSetMenuValue('cmd_redo', 'valueDefault');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function MailAreaHasFocus()
|
|
|
|
|
{
|
|
|
|
|
//Input and TextAreas should get access to the keys that cause these commands.
|
|
|
|
|
//Currently if we don't do this then we will steal the key away and you can't type them
|
|
|
|
|
//in these controls. This is a bug that should be fixed and when it is we can get rid of
|
|
|
|
|
//this.
|
|
|
|
|
var focusedElement = top.document.commandDispatcher.focusedElement;
|
|
|
|
|
if (focusedElement)
|
|
|
|
|
{
|
|
|
|
|
var name = focusedElement.localName.toLowerCase();
|
|
|
|
|
return ((name != "input") && (name != "textarea"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check if the message pane has focus
|
|
|
|
|
// see bug #129988
|
|
|
|
|
if (GetMessagePane() == WhichPaneHasFocus())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// if there is no focusedElement,
|
|
|
|
|
// and the message pane doesn't have focus
|
|
|
|
|
// then a mail area can't be focused
|
|
|
|
|
// see bug #128101
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetNumSelectedMessages()
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
return gDBView.numSelected;
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var gLastFocusedElement=null;
|
|
|
|
|
|
|
|
|
|
function FocusRingUpdate_Mail()
|
|
|
|
|
{
|
|
|
|
|
// WhichPaneHasFocus() uses on top.document.commandDispatcher.focusedElement
|
|
|
|
|
// to determine which pane has focus
|
|
|
|
|
// if the focusedElement is null, we're here on a blur.
|
|
|
|
|
// nsFocusController::Blur() calls nsFocusController::SetFocusedElement(null),
|
|
|
|
|
// which will update any commands listening for "focus".
|
|
|
|
|
// we really only care about nsFocusController::Focus() happens,
|
|
|
|
|
// which calls nsFocusController::SetFocusedElement(element)
|
|
|
|
|
var currentFocusedElement = WhichPaneHasFocus();
|
|
|
|
|
if (!currentFocusedElement)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (currentFocusedElement != gLastFocusedElement) {
|
|
|
|
|
currentFocusedElement.setAttribute("focusring", "true");
|
|
|
|
|
|
|
|
|
|
if (gLastFocusedElement)
|
|
|
|
|
gLastFocusedElement.removeAttribute("focusring");
|
|
|
|
|
|
|
|
|
|
gLastFocusedElement = currentFocusedElement;
|
|
|
|
|
|
|
|
|
|
// since we just changed the pane with focus we need to update the toolbar to reflect this
|
|
|
|
|
UpdateMailToolbar("focus");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function WhichPaneHasFocus()
|
|
|
|
|
{
|
|
|
|
|
var threadTree = GetThreadTree();
|
|
|
|
|
var searchInput = GetSearchInput();
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var messagePane = GetMessagePane();
|
|
|
|
|
|
|
|
|
|
if (top.document.commandDispatcher.focusedWindow == GetMessagePaneFrame())
|
|
|
|
|
return messagePane;
|
|
|
|
|
|
|
|
|
|
var currentNode = top.document.commandDispatcher.focusedElement;
|
|
|
|
|
while (currentNode) {
|
|
|
|
|
if (currentNode === threadTree ||
|
|
|
|
|
currentNode === searchInput ||
|
|
|
|
|
currentNode === folderTree ||
|
|
|
|
|
currentNode === messagePane)
|
|
|
|
|
return currentNode;
|
|
|
|
|
|
|
|
|
|
currentNode = currentNode.parentNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SetupCommandUpdateHandlers()
|
|
|
|
|
{
|
|
|
|
|
var widget;
|
|
|
|
|
|
|
|
|
|
// folder pane
|
|
|
|
|
widget = GetFolderTree();
|
|
|
|
|
if ( widget )
|
|
|
|
|
widget.controllers.appendController(FolderPaneController);
|
|
|
|
|
|
|
|
|
|
// thread pane
|
|
|
|
|
widget = GetThreadTree();
|
|
|
|
|
if ( widget )
|
|
|
|
|
widget.controllers.appendController(ThreadPaneController);
|
|
|
|
|
|
|
|
|
|
top.controllers.insertControllerAt(0, DefaultController);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function IsSendUnsentMsgsEnabled(folderResource)
|
|
|
|
|
{
|
|
|
|
|
var identity;
|
|
|
|
|
|
|
|
|
|
if (messenger.sendingUnsentMsgs) // if we're currently sending unsent msgs, disable this cmd.
|
|
|
|
|
return false;
|
|
|
|
|
try {
|
|
|
|
|
if (folderResource) {
|
|
|
|
|
// if folderResource is non-null, it is
|
|
|
|
|
// resource for the "Unsent Messages" folder
|
|
|
|
|
// we're here because we've done a right click on the "Unsent Messages"
|
|
|
|
|
// folder (context menu)
|
|
|
|
|
var msgFolder = folderResource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
return (msgFolder.getTotalMessages(false) > 0);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
var folders = GetSelectedMsgFolders();
|
|
|
|
|
if (folders.length > 0) {
|
|
|
|
|
identity = getIdentityForServer(folders[0].server);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
dump("ex = " + ex + "\n");
|
|
|
|
|
identity = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (!identity) {
|
|
|
|
|
var am = Components.classes["@mozilla.org/messenger/account-manager;1"].getService(Components.interfaces.nsIMsgAccountManager);
|
|
|
|
|
identity = am.defaultAccount.defaultIdentity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var msgSendlater = Components.classes["@mozilla.org/messengercompose/sendlater;1"].getService(Components.interfaces.nsIMsgSendLater);
|
|
|
|
|
var unsentMsgsFolder = msgSendlater.getUnsentMessagesFolder(identity);
|
|
|
|
|
return (unsentMsgsFolder.getTotalMessages(false) > 0);
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
dump("ex = " + ex + "\n");
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function IsRenameFolderEnabled()
|
|
|
|
|
{
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var selection = folderTree.treeBoxObject.selection;
|
|
|
|
|
if (selection.count == 1)
|
|
|
|
|
{
|
|
|
|
|
var startIndex = {};
|
|
|
|
|
var endIndex = {};
|
|
|
|
|
selection.getRangeAt(0, startIndex, endIndex);
|
|
|
|
|
var folderResource = GetFolderResource(folderTree, startIndex.value);
|
|
|
|
|
var canRename = GetFolderAttribute(folderTree, folderResource, "CanRename") == "true";
|
|
|
|
|
return canRename && isCommandEnabled("cmd_renameFolder");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function IsCanSearchMessagesEnabled()
|
|
|
|
|
{
|
|
|
|
|
var folderURI = GetSelectedFolderURI();
|
|
|
|
|
var server = GetServer(folderURI);
|
|
|
|
|
return server.canSearchMessages;
|
|
|
|
|
}
|
|
|
|
|
function IsFolderCharsetEnabled()
|
|
|
|
|
{
|
|
|
|
|
return IsFolderSelected();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function IsPropertiesEnabled(command)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var serverType;
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var folderResource = GetSelectedFolderResource();
|
|
|
|
|
|
|
|
|
|
serverType = GetFolderAttribute(folderTree, folderResource, "ServerType");
|
|
|
|
|
|
|
|
|
|
switch (serverType)
|
|
|
|
|
{
|
|
|
|
|
case "none":
|
|
|
|
|
case "imap":
|
|
|
|
|
case "pop3":
|
|
|
|
|
goSetMenuValue(command, 'valueFolder');
|
|
|
|
|
break;
|
|
|
|
|
case "nntp":
|
|
|
|
|
goSetMenuValue(command, 'valueNewsgroup');
|
|
|
|
|
break
|
|
|
|
|
default:
|
|
|
|
|
goSetMenuValue(command, 'valueGeneric');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (ex)
|
|
|
|
|
{
|
|
|
|
|
//properties menu failure
|
|
|
|
|
}
|
|
|
|
|
return IsFolderSelected();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function IsViewNavigationItemEnabled()
|
|
|
|
|
{
|
|
|
|
|
return IsFolderSelected();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function IsFolderSelected()
|
|
|
|
|
{
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var selection = folderTree.treeBoxObject.selection;
|
|
|
|
|
if (selection.count == 1)
|
|
|
|
|
{
|
|
|
|
|
var startIndex = {};
|
|
|
|
|
var endIndex = {};
|
|
|
|
|
selection.getRangeAt(0, startIndex, endIndex);
|
|
|
|
|
var folderResource = GetFolderResource(folderTree, startIndex.value);
|
|
|
|
|
return GetFolderAttribute(folderTree, folderResource, "IsServer") != "true";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function IsMessageDisplayedInMessagePane()
|
|
|
|
|
{
|
|
|
|
|
return (!IsThreadAndMessagePaneSplitterCollapsed() && (GetNumSelectedMessages() > 0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function MsgDeleteFolder()
|
|
|
|
|
{
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var selectedFolders = GetSelectedMsgFolders();
|
|
|
|
|
for (var i = 0; i < selectedFolders.length; i++)
|
|
|
|
|
{
|
|
|
|
|
var selectedFolder = selectedFolders[i];
|
|
|
|
|
var folderResource = selectedFolder.QueryInterface(Components.interfaces.nsIRDFResource);
|
|
|
|
|
var specialFolder = GetFolderAttribute(folderTree, folderResource, "SpecialFolder");
|
|
|
|
|
if (specialFolder != "Inbox" && specialFolder != "Trash")
|
|
|
|
|
{
|
|
|
|
|
var protocolInfo = Components.classes["@mozilla.org/messenger/protocol/info;1?type=" + selectedFolder.server.type].getService(Components.interfaces.nsIMsgProtocolInfo);
|
|
|
|
|
|
|
|
|
|
// do not allow deletion of special folders on imap accounts
|
|
|
|
|
if ((specialFolder == "Sent" ||
|
|
|
|
|
specialFolder == "Drafts" ||
|
|
|
|
|
specialFolder == "Templates") &&
|
|
|
|
|
!protocolInfo.specialFoldersDeletionAllowed)
|
|
|
|
|
{
|
|
|
|
|
var messengerBundle = document.getElementById("bundle_messenger");
|
|
|
|
|
var errorMessage = messengerBundle.getFormattedString("specialFolderDeletionErr",
|
|
|
|
|
[specialFolder]);
|
|
|
|
|
var specialFolderDeletionErrTitle = gMessengerBundle.getString("specialFolderDeletionErrTitle");
|
|
|
|
|
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
|
|
|
|
|
promptService.alert(window, specialFolderDeletionErrTitle, errorMessage);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if (isNewsURI(folderResource.Value))
|
|
|
|
|
{
|
|
|
|
|
var unsubscribe = ConfirmUnsubscribe(selectedFolder);
|
|
|
|
|
if (unsubscribe)
|
|
|
|
|
UnSubscribe(selectedFolder);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var parentResource = selectedFolder.parent.QueryInterface(Components.interfaces.nsIRDFResource);
|
|
|
|
|
messenger.DeleteFolders(GetFolderDatasource(), parentResource, folderResource);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SetFocusThreadPaneIfNotOnMessagePane()
|
|
|
|
|
{
|
|
|
|
|
var focusedElement = WhichPaneHasFocus();
|
|
|
|
|
|
|
|
|
|
if((focusedElement != GetThreadTree()) &&
|
|
|
|
|
(focusedElement != GetMessagePane()))
|
|
|
|
|
SetFocusThreadPane();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3pane related commands. Need to go in own file. Putting here for the moment.
|
|
|
|
|
function MsgNextMessage()
|
|
|
|
|
{
|
|
|
|
|
GoNextMessage(nsMsgNavigationType.nextMessage, false );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function MsgNextUnreadMessage()
|
|
|
|
|
{
|
|
|
|
|
GoNextMessage(nsMsgNavigationType.nextUnreadMessage, true);
|
|
|
|
|
}
|
|
|
|
|
function MsgNextFlaggedMessage()
|
|
|
|
|
{
|
|
|
|
|
GoNextMessage(nsMsgNavigationType.nextFlagged, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function MsgNextUnreadThread()
|
|
|
|
|
{
|
|
|
|
|
//First mark the current thread as read. Then go to the next one.
|
|
|
|
|
MsgMarkThreadAsRead();
|
|
|
|
|
GoNextMessage(nsMsgNavigationType.nextUnreadThread, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function MsgPreviousMessage()
|
|
|
|
|
{
|
|
|
|
|
GoNextMessage(nsMsgNavigationType.previousMessage, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function MsgPreviousUnreadMessage()
|
|
|
|
|
{
|
|
|
|
|
GoNextMessage(nsMsgNavigationType.previousUnreadMessage, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function MsgPreviousFlaggedMessage()
|
|
|
|
|
{
|
|
|
|
|
GoNextMessage(nsMsgNavigationType.previousFlagged, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function GetFolderNameFromUri(uri, tree)
|
|
|
|
|
{
|
|
|
|
|
var folderResource = RDF.GetResource(uri);
|
|
|
|
|
|
|
|
|
|
var db = tree.database;
|
|
|
|
|
|
|
|
|
|
var nameProperty = RDF.GetResource('http://home.netscape.com/NC-rdf#Name');
|
|
|
|
|
|
|
|
|
|
var nameResult;
|
|
|
|
|
try {
|
|
|
|
|
nameResult = db.GetTarget(folderResource, nameProperty , true);
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nameResult = nameResult.QueryInterface(Components.interfaces.nsIRDFLiteral);
|
|
|
|
|
return nameResult.Value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* XXX hiding the search bar while it is focus kills the keyboard so we focus the thread pane */
|
|
|
|
|
function SearchBarToggled()
|
|
|
|
|
{
|
|
|
|
|
var searchBox = document.getElementById('searchBox');
|
|
|
|
|
if (searchBox)
|
|
|
|
|
{
|
|
|
|
|
var attribValue = searchBox.getAttribute("hidden") ;
|
|
|
|
|
if (attribValue == "true")
|
|
|
|
|
{
|
|
|
|
|
/*come out of quick search view */
|
|
|
|
|
if (gDBView && gDBView.isSearchView)
|
|
|
|
|
onClearSearch();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*we have to initialize searchInput because we cannot do it when searchBox is hidden */
|
|
|
|
|
var searchInput = GetSearchInput();
|
|
|
|
|
searchInput.value="";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (var currentNode = top.document.commandDispatcher.focusedElement; currentNode; currentNode = currentNode.parentNode) {
|
|
|
|
|
if (currentNode.getAttribute("hidden") == "true") {
|
|
|
|
|
SetFocusThreadPane();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SwitchPaneFocus(event)
|
|
|
|
|
{
|
|
|
|
|
var focusedElement = WhichPaneHasFocus();
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var threadTree = GetThreadTree();
|
|
|
|
|
var searchInput = GetSearchInput();
|
|
|
|
|
var messagePane = GetMessagePane();
|
|
|
|
|
|
|
|
|
|
if (event && event.shiftKey)
|
|
|
|
|
{
|
|
|
|
|
if (focusedElement == threadTree && searchInput.parentNode.getAttribute('hidden') != 'true')
|
|
|
|
|
searchInput.focus();
|
|
|
|
|
else if ((focusedElement == threadTree || focusedElement == searchInput) && !IsFolderPaneCollapsed())
|
|
|
|
|
folderTree.focus();
|
|
|
|
|
else if (focusedElement != messagePane && !IsThreadAndMessagePaneSplitterCollapsed())
|
|
|
|
|
SetFocusMessagePane();
|
|
|
|
|
else
|
|
|
|
|
threadTree.focus();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (focusedElement == searchInput)
|
|
|
|
|
threadTree.focus();
|
|
|
|
|
else if (focusedElement == threadTree && !IsThreadAndMessagePaneSplitterCollapsed())
|
|
|
|
|
SetFocusMessagePane();
|
|
|
|
|
else if (focusedElement != folderTree && !IsFolderPaneCollapsed())
|
|
|
|
|
folderTree.focus();
|
|
|
|
|
else if (searchInput.parentNode.getAttribute('hidden') != 'true')
|
|
|
|
|
searchInput.focus();
|
|
|
|
|
else
|
|
|
|
|
threadTree.focus();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SetFocusFolderPane()
|
|
|
|
|
{
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
folderTree.focus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SetFocusThreadPane()
|
|
|
|
|
{
|
|
|
|
|
var threadTree = GetThreadTree();
|
|
|
|
|
threadTree.focus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SetFocusMessagePane()
|
|
|
|
|
{
|
|
|
|
|
var messagePaneFrame = GetMessagePaneFrame();
|
|
|
|
|
messagePaneFrame.focus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function is_collapsed(element)
|
|
|
|
|
{
|
|
|
|
|
return (element.getAttribute('state') == 'collapsed');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isCommandEnabled(cmd)
|
|
|
|
|
{
|
|
|
|
|
var selectedFolders = GetSelectedMsgFolders();
|
|
|
|
|
var numFolders = selectedFolders.length;
|
|
|
|
|
if(numFolders !=1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var folder = selectedFolders[0];
|
|
|
|
|
if (!folder)
|
|
|
|
|
return false;
|
|
|
|
|
else
|
|
|
|
|
return folder.isCommandEnabled(cmd);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function IsFakeAccount() {
|
|
|
|
|
try {
|
|
|
|
|
var folderResource = GetSelectedFolderResource();
|
|
|
|
|
return (folderResource.Value == "http://home.netscape.com/NC-rdf#PageTitleFakeAccount");
|
|
|
|
|
}
|
|
|
|
|
catch(ex) {
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SendCommandToThreadPane(command)
|
|
|
|
|
{
|
|
|
|
|
ThreadPaneController.doCommand(command);
|
|
|
|
|
|
|
|
|
|
// if we are sending the command so the thread pane
|
|
|
|
|
// we should focus the thread pane
|
|
|
|
|
SetFocusThreadPane();
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-16 08:07:36 +04:00
|
|
|
|
function debugDump(msg)
|
|
|
|
|
{
|
|
|
|
|
// uncomment for noise
|
|
|
|
|
//dump(msg+"\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function CanDropOnFolderTree(index)
|
|
|
|
|
{
|
|
|
|
|
if (!gDragService)
|
|
|
|
|
gDragService = Components.classes["@mozilla.org/widget/dragservice;1"].getService().QueryInterface(Components.interfaces.nsIDragService)
|
|
|
|
|
var dragSession = null;
|
|
|
|
|
var dragFolder = false;
|
|
|
|
|
|
|
|
|
|
dragSession = gDragService.getCurrentSession();
|
|
|
|
|
if (! dragSession)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var flavorSupported = dragSession.isDataFlavorSupported("text/x-moz-message") || dragSession.isDataFlavorSupported("text/x-moz-folder");
|
|
|
|
|
|
|
|
|
|
var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
|
|
|
|
|
if (! trans)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
trans.addDataFlavor("text/x-moz-message");
|
|
|
|
|
trans.addDataFlavor("text/x-moz-folder");
|
|
|
|
|
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var targetResource = GetFolderResource(folderTree, index);
|
|
|
|
|
var targetUri = targetResource.Value;
|
|
|
|
|
var targetFolder = targetResource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
var targetServer = targetFolder.server;
|
|
|
|
|
var sourceServer;
|
|
|
|
|
var sourceResource;
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < dragSession.numDropItems; i++)
|
|
|
|
|
{
|
|
|
|
|
dragSession.getData (trans, i);
|
|
|
|
|
var dataObj = new Object();
|
|
|
|
|
var dataFlavor = new Object();
|
|
|
|
|
var len = new Object();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
trans.getAnyTransferData (dataFlavor, dataObj, len );
|
|
|
|
|
}
|
|
|
|
|
catch (ex)
|
|
|
|
|
{
|
|
|
|
|
continue; //no data so continue;
|
|
|
|
|
}
|
|
|
|
|
if (dataObj)
|
|
|
|
|
dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString);
|
|
|
|
|
if (! dataObj)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// pull the URL out of the data object
|
|
|
|
|
var sourceUri = dataObj.data.substring(0, len.value);
|
|
|
|
|
if (! sourceUri)
|
|
|
|
|
continue;
|
|
|
|
|
if (dataFlavor.value == "text/x-moz-message")
|
|
|
|
|
{
|
|
|
|
|
sourceResource = null;
|
|
|
|
|
var isServer = GetFolderAttribute(folderTree, targetResource, "IsServer");
|
|
|
|
|
if (isServer == "true")
|
|
|
|
|
{
|
|
|
|
|
debugDump("***isServer == true\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// canFileMessages checks no select, and acl, for imap.
|
|
|
|
|
var canFileMessages = GetFolderAttribute(folderTree, targetResource, "CanFileMessages");
|
|
|
|
|
if (canFileMessages != "true")
|
|
|
|
|
{
|
|
|
|
|
debugDump("***canFileMessages == false\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
var hdr = messenger.messageServiceFromURI(sourceUri).messageURIToMsgHdr(sourceUri);
|
|
|
|
|
if (hdr.folder == targetFolder)
|
|
|
|
|
return false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we should only get here if we are dragging and dropping folders
|
|
|
|
|
dragFolder = true;
|
|
|
|
|
sourceResource = RDF.GetResource(sourceUri);
|
|
|
|
|
var sourceFolder = sourceResource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
sourceServer = sourceFolder.server;
|
|
|
|
|
|
|
|
|
|
if (targetUri == sourceUri)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//don't allow drop on different imap servers.
|
|
|
|
|
if (sourceServer != targetServer && targetServer.type == "imap")
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//don't allow immediate child to be dropped to it's parent
|
|
|
|
|
if (targetFolder.URI == sourceFolder.parent.URI)
|
|
|
|
|
{
|
|
|
|
|
debugDump(targetFolder.URI + "\n");
|
|
|
|
|
debugDump(sourceFolder.parent.URI + "\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var isAncestor = sourceFolder.isAncestorOf(targetFolder);
|
|
|
|
|
// don't allow parent to be dropped on its ancestors
|
|
|
|
|
if (isAncestor)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dragFolder)
|
|
|
|
|
{
|
|
|
|
|
//first check these conditions then proceed further
|
|
|
|
|
debugDump("***isFolderFlavor == true \n");
|
|
|
|
|
|
|
|
|
|
// no copy for folder drag
|
|
|
|
|
if (dragSession.dragAction == nsIDragService.DRAGDROP_ACTION_COPY)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var canCreateSubfolders = GetFolderAttribute(folderTree, targetResource, "CanCreateSubfolders");
|
|
|
|
|
// if cannot create subfolders then a folder cannot be dropped here
|
|
|
|
|
if (canCreateSubfolders == "false")
|
|
|
|
|
{
|
|
|
|
|
debugDump("***canCreateSubfolders == false \n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
var serverType = GetFolderAttribute(folderTree, targetResource, "ServerType");
|
|
|
|
|
|
|
|
|
|
// if we've got a folder that can't be renamed
|
|
|
|
|
// allow us to drop it if we plan on dropping it on "Local Folders"
|
|
|
|
|
// (but not within the same server, to prevent renaming folders on "Local Folders" that
|
|
|
|
|
// should not be renamed)
|
|
|
|
|
var srcCanRename = GetFolderAttribute(folderTree, sourceResource, "CanRename");
|
|
|
|
|
if (srcCanRename == "false") {
|
|
|
|
|
if (sourceServer == targetServer)
|
|
|
|
|
return false;
|
|
|
|
|
if (serverType != "none")
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//message or folder
|
|
|
|
|
if (flavorSupported)
|
|
|
|
|
{
|
|
|
|
|
dragSession.canDrop = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function CanDropBeforeAfterFolderTree(index, before)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function DropOnFolderTree(row, orientation)
|
|
|
|
|
{
|
|
|
|
|
if (orientation != Components.interfaces.nsITreeView.inDropOn)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var targetResource = GetFolderResource(folderTree, row);
|
|
|
|
|
|
|
|
|
|
var targetUri = targetResource.Value;
|
|
|
|
|
debugDump("***targetUri = " + targetUri + "\n");
|
|
|
|
|
|
|
|
|
|
if (!gDragService)
|
|
|
|
|
gDragService = Components.classes["@mozilla.org/widget/dragservice;1"].getService().QueryInterface(Components.interfaces.nsIDragService);
|
|
|
|
|
var dragSession = gDragService.getCurrentSession();
|
|
|
|
|
if (! dragSession )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
|
|
|
|
|
trans.addDataFlavor("text/x-moz-message");
|
|
|
|
|
trans.addDataFlavor("text/x-moz-folder");
|
|
|
|
|
|
|
|
|
|
var list = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
|
|
|
|
|
|
|
|
|
|
var dropMessage;
|
|
|
|
|
var sourceUri;
|
|
|
|
|
var sourceResource;
|
|
|
|
|
var sourceFolder;
|
|
|
|
|
var sourceServer;
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < dragSession.numDropItems; i++)
|
|
|
|
|
{
|
|
|
|
|
dragSession.getData (trans, i);
|
|
|
|
|
var dataObj = new Object();
|
|
|
|
|
var flavor = new Object();
|
|
|
|
|
var len = new Object();
|
|
|
|
|
trans.getAnyTransferData(flavor, dataObj, len);
|
|
|
|
|
if (dataObj)
|
|
|
|
|
dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString);
|
|
|
|
|
if (! dataObj)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// pull the URL out of the data object
|
|
|
|
|
sourceUri = dataObj.data.substring(0, len.value);
|
|
|
|
|
if (! sourceUri)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
debugDump(" Node #" + i + ": drop " + sourceUri + " to " + targetUri + "\n");
|
|
|
|
|
|
|
|
|
|
// only do this for the first object, either they are all messages or they are all folders
|
|
|
|
|
if (i == 0)
|
|
|
|
|
{
|
|
|
|
|
if (flavor.value == "text/x-moz-folder")
|
|
|
|
|
{
|
|
|
|
|
sourceResource = RDF.GetResource(sourceUri);
|
|
|
|
|
sourceFolder = sourceResource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
dropMessage = false; // we are dropping a folder
|
|
|
|
|
}
|
|
|
|
|
else if (flavor.value == "text/x-moz-message")
|
|
|
|
|
dropMessage = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (!dropMessage)
|
|
|
|
|
dump("drag and drop of multiple folders isn't supported\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dropMessage) {
|
|
|
|
|
// from the message uri, get the appropriate messenger service
|
|
|
|
|
// and then from that service, get the msgDbHdr
|
|
|
|
|
list.AppendElement(messenger.messageServiceFromURI(sourceUri).messageURIToMsgHdr(sourceUri));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Prevent dropping of a node before, after, or on itself
|
|
|
|
|
if (sourceResource == targetResource)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
list.AppendElement(sourceResource);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (list.Count() < 1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var isSourceNews = false;
|
|
|
|
|
isSourceNews = isNewsURI(sourceUri);
|
|
|
|
|
|
|
|
|
|
var targetFolder = targetResource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|
|
|
|
var targetServer = targetFolder.server;
|
|
|
|
|
|
|
|
|
|
if (dropMessage) {
|
|
|
|
|
var sourceMsgHdr = list.GetElementAt(0).QueryInterface(Components.interfaces.nsIMsgDBHdr);
|
|
|
|
|
sourceFolder = sourceMsgHdr.folder;
|
|
|
|
|
sourceServer = sourceFolder.server;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (isSourceNews) {
|
|
|
|
|
// news to pop or imap is always a copy
|
|
|
|
|
messenger.CopyMessages(sourceFolder, targetFolder, list, false);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
var dragAction = dragSession.dragAction;
|
|
|
|
|
if (dragAction == nsIDragService.DRAGDROP_ACTION_COPY)
|
|
|
|
|
messenger.CopyMessages(sourceFolder, targetFolder, list, false);
|
|
|
|
|
else if (dragAction == nsIDragService.DRAGDROP_ACTION_MOVE)
|
|
|
|
|
messenger.CopyMessages(sourceFolder, targetFolder, list, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (ex) {
|
|
|
|
|
dump("failed to copy messages: " + ex + "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
sourceServer = sourceFolder.server;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
messenger.CopyFolders(GetFolderDatasource(), targetResource, list, (sourceServer == targetServer));
|
|
|
|
|
}
|
|
|
|
|
catch(ex)
|
|
|
|
|
{
|
|
|
|
|
dump ("Exception : CopyFolders " + ex + "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function BeginDragFolderTree(event)
|
|
|
|
|
{
|
|
|
|
|
debugDump("BeginDragFolderTree\n");
|
|
|
|
|
|
|
|
|
|
if (event.originalTarget.localName != "treechildren")
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var folderTree = GetFolderTree();
|
|
|
|
|
var row = {};
|
|
|
|
|
var col = {};
|
|
|
|
|
var elt = {};
|
|
|
|
|
folderTree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, elt);
|
|
|
|
|
if (row.value == -1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var folderResource = GetFolderResource(folderTree, row.value);
|
|
|
|
|
|
|
|
|
|
if (GetFolderAttribute(folderTree, folderResource, "IsServer") == "true")
|
|
|
|
|
{
|
|
|
|
|
debugDump("***IsServer == true\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do not allow the drag when news is the source
|
|
|
|
|
if (GetFolderAttribute(folderTree, folderResource, "ServerType") == "nntp")
|
|
|
|
|
{
|
|
|
|
|
debugDump("***ServerType == nntp\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var selectedFolders = GetSelectedFolders();
|
|
|
|
|
return BeginDragTree(event, folderTree, selectedFolders, "text/x-moz-folder");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function BeginDragThreadPane(event)
|
|
|
|
|
{
|
|
|
|
|
debugDump("BeginDragThreadPane\n");
|
|
|
|
|
|
|
|
|
|
var threadTree = GetThreadTree();
|
|
|
|
|
var selectedMessages = GetSelectedMessages();
|
|
|
|
|
|
|
|
|
|
//A message can be dragged from one window and dropped on another window
|
|
|
|
|
//therefore setNextMessageAfterDelete() here
|
|
|
|
|
//no major disadvantage even if it is a copy operation
|
|
|
|
|
|
|
|
|
|
SetNextMessageAfterDelete();
|
|
|
|
|
return BeginDragTree(event, threadTree, selectedMessages, "text/x-moz-message");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function BeginDragTree(event, tree, selArray, flavor)
|
|
|
|
|
{
|
|
|
|
|
var dragStarted = false;
|
|
|
|
|
|
|
|
|
|
var transArray = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
|
|
|
|
|
if ( !transArray )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// let's build the drag region
|
|
|
|
|
var region = null;
|
|
|
|
|
try {
|
|
|
|
|
region = Components.classes["@mozilla.org/gfx/region;1"].createInstance(Components.interfaces.nsIScriptableRegion);
|
|
|
|
|
region.init();
|
|
|
|
|
var obo = tree.treeBoxObject;
|
|
|
|
|
var bo = obo.treeBody.boxObject;
|
|
|
|
|
var obosel= obo.selection;
|
|
|
|
|
|
|
|
|
|
var rowX = bo.x;
|
|
|
|
|
var rowY = bo.y;
|
|
|
|
|
var rowHeight = obo.rowHeight;
|
|
|
|
|
var rowWidth = bo.width;
|
|
|
|
|
|
|
|
|
|
//add a rectangle for each visible selected row
|
|
|
|
|
for (var i = obo.getFirstVisibleRow(); i <= obo.getLastVisibleRow(); i ++)
|
|
|
|
|
{
|
|
|
|
|
if (obosel.isSelected(i))
|
|
|
|
|
region.unionRect(rowX, rowY, rowWidth, rowHeight);
|
|
|
|
|
rowY = rowY + rowHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//and finally, clip the result to be sure we don't spill over...
|
|
|
|
|
if(!region.isEmpty())
|
|
|
|
|
region.intersectRect(bo.x, bo.y, bo.width, bo.height);
|
|
|
|
|
} catch(ex) {
|
|
|
|
|
dump("Error while building selection region: " + ex + "\n");
|
|
|
|
|
region = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var count = selArray.length;
|
|
|
|
|
debugDump("selArray.length = " + count + "\n");
|
|
|
|
|
for (i = 0; i < count; ++i ) {
|
|
|
|
|
var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
|
|
|
|
|
if (!trans)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var genTextData = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
|
|
|
|
|
if (!genTextData)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
trans.addDataFlavor(flavor);
|
|
|
|
|
|
|
|
|
|
// get id (url)
|
|
|
|
|
var id = selArray[i];
|
|
|
|
|
genTextData.data = id;
|
|
|
|
|
debugDump(" ID #" + i + " = " + id + "\n");
|
|
|
|
|
|
|
|
|
|
trans.setTransferData ( flavor, genTextData, id.length * 2 ); // doublebyte byte data
|
|
|
|
|
|
|
|
|
|
// put it into the transferable as an |nsISupports|
|
|
|
|
|
var genTrans = trans.QueryInterface(Components.interfaces.nsISupports);
|
|
|
|
|
transArray.AppendElement(genTrans);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!gDragService)
|
|
|
|
|
gDragService = Components.classes["@mozilla.org/widget/dragservice;1"].getService().QueryInterface(Components.interfaces.nsIDragService);
|
|
|
|
|
gDragService.invokeDragSession ( event.target, transArray, region, nsIDragService.DRAGDROP_ACTION_COPY +
|
|
|
|
|
nsIDragService.DRAGDROP_ACTION_MOVE );
|
|
|
|
|
|
|
|
|
|
dragStarted = true;
|
|
|
|
|
|
|
|
|
|
return(!dragStarted); // don't propagate the event if a drag has begun
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-16 08:11:28 +04:00
|
|
|
|
|
|
|
|
|
|