mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-10 01:40:17 +01:00
815 lines
25 KiB
JavaScript
815 lines
25 KiB
JavaScript
|
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|||
|
* ***** BEGIN LICENSE BLOCK *****
|
|||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|||
|
*
|
|||
|
* The contents of this file are subject to the Mozilla 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/MPL/
|
|||
|
*
|
|||
|
* 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 the Initial Developer are Copyright (C) 1998-1999
|
|||
|
* the Initial Developer. All Rights Reserved.
|
|||
|
*
|
|||
|
* Contributor(s):
|
|||
|
* H<EFBFBD>kan Waara <hwaara@chello.se>
|
|||
|
*
|
|||
|
* Alternatively, the contents of this file may be used under the terms of
|
|||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|||
|
* of those above. If you wish to allow use of your version of this file only
|
|||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|||
|
* use your version of this file under the terms of the MPL, indicate your
|
|||
|
* decision by deleting the provisions above and replace them with the notice
|
|||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|||
|
* the provisions above, a recipient may use your version of this file under
|
|||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|||
|
*
|
|||
|
* ***** END LICENSE BLOCK ***** */
|
|||
|
|
|||
|
var rdfDatasourcePrefix = "@mozilla.org/rdf/datasource;1?name=";
|
|||
|
var rdfServiceContractID = "@mozilla.org/rdf/rdf-service;1";
|
|||
|
var searchSessionContractID = "@mozilla.org/messenger/searchSession;1";
|
|||
|
var folderDSContractID = rdfDatasourcePrefix + "mailnewsfolders";
|
|||
|
var gSearchView;
|
|||
|
var gSearchSession;
|
|||
|
var gCurrentFolder;
|
|||
|
|
|||
|
var nsIMsgFolder = Components.interfaces.nsIMsgFolder;
|
|||
|
var nsIMsgWindow = Components.interfaces.nsIMsgWindow;
|
|||
|
var nsIMsgRDFDataSource = Components.interfaces.nsIMsgRDFDataSource;
|
|||
|
var nsMsgSearchScope = Components.interfaces.nsMsgSearchScope;
|
|||
|
|
|||
|
var gFolderDatasource;
|
|||
|
var gFolderPicker;
|
|||
|
var gStatusBar = null;
|
|||
|
var gStatusFeedback = new nsMsgStatusFeedback();
|
|||
|
var gTimelineEnabled = false;
|
|||
|
var gMessengerBundle = null;
|
|||
|
var RDF;
|
|||
|
var gSearchBundle;
|
|||
|
var gNextMessageViewIndexAfterDelete = -2;
|
|||
|
|
|||
|
// Datasource search listener -- made global as it has to be registered
|
|||
|
// and unregistered in different functions.
|
|||
|
var gDataSourceSearchListener;
|
|||
|
var gViewSearchListener;
|
|||
|
|
|||
|
var gSearchStopButton;
|
|||
|
var gMailSession;
|
|||
|
|
|||
|
var MSG_FOLDER_FLAG_VIRTUAL = 0x0020;
|
|||
|
|
|||
|
// Controller object for search results thread pane
|
|||
|
var nsSearchResultsController =
|
|||
|
{
|
|||
|
supportsCommand: function(command)
|
|||
|
{
|
|||
|
switch(command) {
|
|||
|
case "cmd_delete":
|
|||
|
case "cmd_shiftDelete":
|
|||
|
case "button_delete":
|
|||
|
case "cmd_open":
|
|||
|
case "file_message_button":
|
|||
|
case "goto_folder_button":
|
|||
|
case "saveas_vf_button":
|
|||
|
case "cmd_selectAll":
|
|||
|
return true;
|
|||
|
default:
|
|||
|
return false;
|
|||
|
}
|
|||
|
},
|
|||
|
|
|||
|
// this controller only handles commands
|
|||
|
// that rely on items being selected in
|
|||
|
// the search results pane.
|
|||
|
isCommandEnabled: function(command)
|
|||
|
{
|
|||
|
var enabled = true;
|
|||
|
|
|||
|
switch (command) {
|
|||
|
case "goto_folder_button":
|
|||
|
if (GetNumSelectedMessages() != 1)
|
|||
|
enabled = false;
|
|||
|
break;
|
|||
|
case "cmd_delete":
|
|||
|
case "cmd_shiftDelete":
|
|||
|
case "button_delete":
|
|||
|
// this assumes that advanced searches don't cross accounts
|
|||
|
if (GetNumSelectedMessages() <= 0 || isNewsURI(gSearchView.getURIForViewIndex(0)))
|
|||
|
enabled = false;
|
|||
|
break;
|
|||
|
case "saveas_vf_button":
|
|||
|
// need someway to see if there are any search criteria...
|
|||
|
return true;
|
|||
|
case "cmd_selectAll":
|
|||
|
return GetDBView() != null;
|
|||
|
default:
|
|||
|
if (GetNumSelectedMessages() <= 0)
|
|||
|
enabled = false;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return enabled;
|
|||
|
},
|
|||
|
|
|||
|
doCommand: function(command)
|
|||
|
{
|
|||
|
switch(command) {
|
|||
|
case "cmd_open":
|
|||
|
MsgOpenSelectedMessages();
|
|||
|
return true;
|
|||
|
|
|||
|
case "cmd_delete":
|
|||
|
case "button_delete":
|
|||
|
MsgDeleteSelectedMessages(nsMsgViewCommandType.deleteMsg);
|
|||
|
return true;
|
|||
|
case "cmd_shiftDelete":
|
|||
|
MsgDeleteSelectedMessages(nsMsgViewCommandType.deleteNoTrash);
|
|||
|
return true;
|
|||
|
|
|||
|
case "goto_folder_button":
|
|||
|
GoToFolder();
|
|||
|
return true;
|
|||
|
|
|||
|
case "saveas_vf_button":
|
|||
|
saveAsVirtualFolder();
|
|||
|
return true;
|
|||
|
|
|||
|
case "cmd_selectAll":
|
|||
|
// move the focus to the search results pane
|
|||
|
GetThreadTree().focus();
|
|||
|
GetDBView().doCommand(nsMsgViewCommandType.selectAll)
|
|||
|
return true;
|
|||
|
|
|||
|
default:
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
},
|
|||
|
|
|||
|
onEvent: function(event)
|
|||
|
{
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function UpdateMailSearch(caller)
|
|||
|
{
|
|||
|
//dump("XXX update mail-search " + caller + "\n");
|
|||
|
document.commandDispatcher.updateCommands('mail-search');
|
|||
|
}
|
|||
|
|
|||
|
function SetAdvancedSearchStatusText(aNumHits)
|
|||
|
{
|
|||
|
var statusMsg;
|
|||
|
// if there are no hits, it means no matches were found in the search.
|
|||
|
if (aNumHits == 0)
|
|||
|
statusMsg = gSearchBundle.getString("searchFailureMessage");
|
|||
|
else
|
|||
|
{
|
|||
|
if (aNumHits == 1)
|
|||
|
statusMsg = gSearchBundle.getString("searchSuccessMessage");
|
|||
|
else
|
|||
|
statusMsg = gSearchBundle.getFormattedString("searchSuccessMessages", [aNumHits]);
|
|||
|
}
|
|||
|
|
|||
|
gStatusFeedback.showStatusString(statusMsg);
|
|||
|
}
|
|||
|
|
|||
|
// nsIMsgSearchNotify object
|
|||
|
var gSearchNotificationListener =
|
|||
|
{
|
|||
|
onSearchHit: function(header, folder)
|
|||
|
{
|
|||
|
// XXX TODO
|
|||
|
// update status text?
|
|||
|
},
|
|||
|
|
|||
|
onSearchDone: function(status)
|
|||
|
{
|
|||
|
gSearchStopButton.setAttribute("label", gSearchBundle.getString("labelForSearchButton"));
|
|||
|
gSearchStopButton.setAttribute("accesskey", gSearchBundle.getString("labelForSearchButton.accesskey"));
|
|||
|
gStatusFeedback._stopMeteors();
|
|||
|
SetAdvancedSearchStatusText(gSearchView.QueryInterface(Components.interfaces.nsITreeView).rowCount);
|
|||
|
},
|
|||
|
|
|||
|
onNewSearch: function()
|
|||
|
{
|
|||
|
gSearchStopButton.setAttribute("label", gSearchBundle.getString("labelForStopButton"));
|
|||
|
gSearchStopButton.setAttribute("accesskey", gSearchBundle.getString("labelForStopButton.accesskey"));
|
|||
|
UpdateMailSearch("new-search");
|
|||
|
gStatusFeedback._startMeteors();
|
|||
|
gStatusFeedback.showStatusString(gSearchBundle.getString("searchingMessage"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// the folderListener object
|
|||
|
var gFolderListener = {
|
|||
|
OnItemAdded: function(parentItem, item) {},
|
|||
|
|
|||
|
OnItemRemoved: function(parentItem, item){},
|
|||
|
|
|||
|
OnItemPropertyChanged: function(item, property, oldValue, newValue) {},
|
|||
|
|
|||
|
OnItemIntPropertyChanged: function(item, property, oldValue, newValue) {},
|
|||
|
|
|||
|
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.toString();
|
|||
|
|
|||
|
if (eventType == "DeleteOrMoveMsgCompleted") {
|
|||
|
HandleDeleteOrMoveMessageCompleted(folder);
|
|||
|
}
|
|||
|
else if (eventType == "DeleteOrMoveMsgFailed") {
|
|||
|
HandleDeleteOrMoveMessageFailed(folder);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function HideSearchColumn(id)
|
|||
|
{
|
|||
|
var col = document.getElementById(id);
|
|||
|
if (col) {
|
|||
|
col.setAttribute("hidden","true");
|
|||
|
col.setAttribute("ignoreincolumnpicker","true");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function ShowSearchColumn(id)
|
|||
|
{
|
|||
|
var col = document.getElementById(id);
|
|||
|
if (col) {
|
|||
|
col.removeAttribute("hidden");
|
|||
|
col.removeAttribute("ignoreincolumnpicker");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function searchOnLoad()
|
|||
|
{
|
|||
|
initializeSearchWidgets();
|
|||
|
initializeSearchWindowWidgets();
|
|||
|
CreateMessenger();
|
|||
|
|
|||
|
gSearchBundle = document.getElementById("bundle_search");
|
|||
|
gSearchStopButton.setAttribute("label", gSearchBundle.getString("labelForSearchButton"));
|
|||
|
gSearchStopButton.setAttribute("accesskey", gSearchBundle.getString("labelForSearchButton.accesskey"));
|
|||
|
gMessengerBundle = document.getElementById("bundle_messenger");
|
|||
|
setupDatasource();
|
|||
|
setupSearchListener();
|
|||
|
|
|||
|
if (window.arguments && window.arguments[0])
|
|||
|
selectFolder(window.arguments[0].folder);
|
|||
|
|
|||
|
onMore(null);
|
|||
|
UpdateMailSearch("onload");
|
|||
|
|
|||
|
// hide and remove these columns from the column picker. you can't thread search results
|
|||
|
HideSearchColumn("threadCol"); // since you can't thread search results
|
|||
|
HideSearchColumn("totalCol"); // since you can't thread search results
|
|||
|
HideSearchColumn("unreadCol"); // since you can't thread search results
|
|||
|
HideSearchColumn("unreadButtonColHeader");
|
|||
|
HideSearchColumn("statusCol");
|
|||
|
HideSearchColumn("flaggedCol");
|
|||
|
HideSearchColumn("idCol");
|
|||
|
HideSearchColumn("junkStatusCol");
|
|||
|
HideSearchColumn("accountCol");
|
|||
|
|
|||
|
// we want to show the location column for search
|
|||
|
ShowSearchColumn("locationCol");
|
|||
|
}
|
|||
|
|
|||
|
function searchOnUnload()
|
|||
|
{
|
|||
|
// unregister listeners
|
|||
|
gSearchSession.unregisterListener(gViewSearchListener);
|
|||
|
gSearchSession.unregisterListener(gSearchNotificationListener);
|
|||
|
|
|||
|
gMailSession.RemoveFolderListener(gFolderListener);
|
|||
|
|
|||
|
if (gSearchView) {
|
|||
|
gSearchView.close();
|
|||
|
gSearchView = null;
|
|||
|
}
|
|||
|
|
|||
|
// release this early because msgWindow holds a weak reference
|
|||
|
msgWindow.rootDocShell = null;
|
|||
|
}
|
|||
|
|
|||
|
function initializeSearchWindowWidgets()
|
|||
|
{
|
|||
|
gFolderPicker = document.getElementById("searchableFolders");
|
|||
|
gSearchStopButton = document.getElementById("search-button");
|
|||
|
gStatusBar = document.getElementById('statusbar-icon');
|
|||
|
hideMatchAllItem();
|
|||
|
|
|||
|
msgWindow = Components.classes[msgWindowContractID].createInstance(nsIMsgWindow);
|
|||
|
msgWindow.statusFeedback = gStatusFeedback;
|
|||
|
msgWindow.SetDOMWindow(window);
|
|||
|
msgWindow.rootDocShell.appType = Components.interfaces.nsIDocShell.APP_TYPE_MAIL;
|
|||
|
|
|||
|
// functionality to enable/disable buttons using nsSearchResultsController
|
|||
|
// depending of whether items are selected in the search results thread pane.
|
|||
|
top.controllers.insertControllerAt(0, nsSearchResultsController);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
function onSearchStop() {
|
|||
|
gSearchSession.interruptSearch();
|
|||
|
}
|
|||
|
|
|||
|
function onResetSearch(event) {
|
|||
|
onReset(event);
|
|||
|
|
|||
|
var tree = GetThreadTree();
|
|||
|
tree.treeBoxObject.view = null;
|
|||
|
gStatusFeedback.showStatusString("");
|
|||
|
}
|
|||
|
|
|||
|
function selectFolder(folder)
|
|||
|
{
|
|||
|
var folderURI;
|
|||
|
|
|||
|
// if we can't search messages on this folder, just select the first one
|
|||
|
if (!folder || !folder.server.canSearchMessages || (folder.flags & MSG_FOLDER_FLAG_VIRTUAL)) {
|
|||
|
// find first item in our folder picker menu list
|
|||
|
folderURI = gFolderPicker.firstChild.tree.builderView.getResourceAtIndex(0).Value;
|
|||
|
} else {
|
|||
|
folderURI = folder.URI;
|
|||
|
}
|
|||
|
updateSearchFolderPicker(folderURI);
|
|||
|
}
|
|||
|
|
|||
|
function updateSearchFolderPicker(folderURI)
|
|||
|
{
|
|||
|
SetFolderPicker(folderURI, gFolderPicker.id);
|
|||
|
|
|||
|
// use the URI to get the real folder
|
|||
|
gCurrentFolder =
|
|||
|
RDF.GetResource(folderURI).QueryInterface(nsIMsgFolder);
|
|||
|
|
|||
|
var searchLocalSystem = document.getElementById("checkSearchLocalSystem");
|
|||
|
if (searchLocalSystem)
|
|||
|
searchLocalSystem.disabled = gCurrentFolder.server.searchScope == nsMsgSearchScope.offlineMail;
|
|||
|
setSearchScope(GetScopeForFolder(gCurrentFolder));
|
|||
|
}
|
|||
|
|
|||
|
function updateSearchLocalSystem()
|
|||
|
{
|
|||
|
setSearchScope(GetScopeForFolder(gCurrentFolder));
|
|||
|
}
|
|||
|
|
|||
|
function UpdateAfterCustomHeaderChange()
|
|||
|
{
|
|||
|
updateSearchAttributes();
|
|||
|
}
|
|||
|
|
|||
|
function onChooseFolder(event) {
|
|||
|
var folderURI = event.id;
|
|||
|
if (folderURI) {
|
|||
|
updateSearchFolderPicker(folderURI);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function onEnterInSearchTerm()
|
|||
|
{
|
|||
|
// on enter
|
|||
|
// if not searching, start the search
|
|||
|
// if searching, stop and then start again
|
|||
|
if (gSearchStopButton.getAttribute("label") == gSearchBundle.getString("labelForSearchButton")) {
|
|||
|
onSearch();
|
|||
|
}
|
|||
|
else {
|
|||
|
onSearchStop();
|
|||
|
onSearch();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function onSearch()
|
|||
|
{
|
|||
|
// set the view. do this on every search, to
|
|||
|
// allow the tree to reset itself
|
|||
|
var treeView = gSearchView.QueryInterface(Components.interfaces.nsITreeView);
|
|||
|
if (treeView)
|
|||
|
{
|
|||
|
var tree = GetThreadTree();
|
|||
|
tree.treeBoxObject.view = treeView;
|
|||
|
}
|
|||
|
|
|||
|
gSearchSession.clearScopes();
|
|||
|
// tell the search session what the new scope is
|
|||
|
if (!gCurrentFolder.isServer && !gCurrentFolder.noSelect)
|
|||
|
gSearchSession.addScopeTerm(GetScopeForFolder(gCurrentFolder),
|
|||
|
gCurrentFolder);
|
|||
|
|
|||
|
var searchSubfolders = document.getElementById("checkSearchSubFolders").checked;
|
|||
|
if (gCurrentFolder && (searchSubfolders || gCurrentFolder.isServer || gCurrentFolder.noSelect))
|
|||
|
{
|
|||
|
AddSubFolders(gCurrentFolder);
|
|||
|
}
|
|||
|
// reflect the search widgets back into the search session
|
|||
|
saveSearchTerms(gSearchSession.searchTerms, gSearchSession);
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
gSearchSession.search(msgWindow);
|
|||
|
}
|
|||
|
catch(ex)
|
|||
|
{
|
|||
|
dump("Search Exception\n");
|
|||
|
}
|
|||
|
// refresh the tree after the search starts, because initiating the
|
|||
|
// search will cause the datasource to clear itself
|
|||
|
}
|
|||
|
|
|||
|
function AddSubFolders(folder) {
|
|||
|
if (folder.hasSubFolders)
|
|||
|
{
|
|||
|
var subFolderEnumerator = folder.GetSubFolders();
|
|||
|
var done = false;
|
|||
|
while (!done)
|
|||
|
{
|
|||
|
var next = subFolderEnumerator.currentItem();
|
|||
|
if (next)
|
|||
|
{
|
|||
|
var nextFolder = next.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|||
|
if (nextFolder && ! (nextFolder.flags & MSG_FOLDER_FLAG_VIRTUAL))
|
|||
|
{
|
|||
|
if (!nextFolder.noSelect)
|
|||
|
gSearchSession.addScopeTerm(GetScopeForFolder(nextFolder), nextFolder);
|
|||
|
AddSubFolders(nextFolder);
|
|||
|
}
|
|||
|
}
|
|||
|
try
|
|||
|
{
|
|||
|
subFolderEnumerator.next();
|
|||
|
}
|
|||
|
catch (ex)
|
|||
|
{
|
|||
|
done = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function AddSubFoldersToURI(folder)
|
|||
|
{
|
|||
|
var returnString = "";
|
|||
|
if (folder.hasSubFolders)
|
|||
|
{
|
|||
|
var subFolderEnumerator = folder.GetSubFolders();
|
|||
|
var done = false;
|
|||
|
while (!done)
|
|||
|
{
|
|||
|
var next = subFolderEnumerator.currentItem();
|
|||
|
if (next)
|
|||
|
{
|
|||
|
var nextFolder = next.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|||
|
if (nextFolder && ! (nextFolder.flags & MSG_FOLDER_FLAG_VIRTUAL))
|
|||
|
{
|
|||
|
if (!nextFolder.noSelect && !nextFolder.isServer)
|
|||
|
{
|
|||
|
if (returnString.length > 0)
|
|||
|
returnString += '|';
|
|||
|
returnString += nextFolder.URI;
|
|||
|
}
|
|||
|
var subFoldersString = AddSubFoldersToURI(nextFolder);
|
|||
|
if (subFoldersString.length > 0)
|
|||
|
{
|
|||
|
if (returnString.length > 0)
|
|||
|
returnString += '|';
|
|||
|
returnString += subFoldersString;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
try
|
|||
|
{
|
|||
|
subFolderEnumerator.next();
|
|||
|
}
|
|||
|
catch (ex)
|
|||
|
{
|
|||
|
done = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return returnString;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
function GetScopeForFolder(folder)
|
|||
|
{
|
|||
|
var searchLocalSystem = document.getElementById("checkSearchLocalSystem");
|
|||
|
return searchLocalSystem && searchLocalSystem.checked ? nsMsgSearchScope.offlineMail : folder.server.searchScope;
|
|||
|
}
|
|||
|
|
|||
|
var nsMsgViewSortType = Components.interfaces.nsMsgViewSortType;
|
|||
|
var nsMsgViewSortOrder = Components.interfaces.nsMsgViewSortOrder;
|
|||
|
var nsMsgViewFlagsType = Components.interfaces.nsMsgViewFlagsType;
|
|||
|
var nsMsgViewCommandType = Components.interfaces.nsMsgViewCommandType;
|
|||
|
|
|||
|
function goUpdateSearchItems(commandset)
|
|||
|
{
|
|||
|
for (var i = 0; i < commandset.childNodes.length; i++)
|
|||
|
{
|
|||
|
var commandID = commandset.childNodes[i].getAttribute("id");
|
|||
|
if (commandID)
|
|||
|
{
|
|||
|
goUpdateCommand(commandID);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function nsMsgSearchCommandUpdater()
|
|||
|
{}
|
|||
|
|
|||
|
nsMsgSearchCommandUpdater.prototype =
|
|||
|
{
|
|||
|
updateCommandStatus : function()
|
|||
|
{
|
|||
|
// the back end is smart and is only telling us to update command status
|
|||
|
// when the # of items in the selection has actually changed.
|
|||
|
document.commandDispatcher.updateCommands('mail-search');
|
|||
|
},
|
|||
|
displayMessageChanged : function(aFolder, aSubject, aKeywords)
|
|||
|
{
|
|||
|
},
|
|||
|
|
|||
|
updateNextMessageAfterDelete : function()
|
|||
|
{
|
|||
|
SetNextMessageAfterDelete();
|
|||
|
},
|
|||
|
|
|||
|
QueryInterface : function(iid)
|
|||
|
{
|
|||
|
if (iid.equals(Components.interfaces.nsIMsgDBViewCommandUpdater) ||
|
|||
|
iid.equals(Components.interfaces.nsISupports))
|
|||
|
return this;
|
|||
|
|
|||
|
throw Components.results.NS_NOINTERFACE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function setupDatasource() {
|
|||
|
|
|||
|
RDF = Components.classes[rdfServiceContractID].getService(Components.interfaces.nsIRDFService);
|
|||
|
gSearchView = Components.classes["@mozilla.org/messenger/msgdbview;1?type=search"].createInstance(Components.interfaces.nsIMsgDBView);
|
|||
|
var count = new Object;
|
|||
|
var cmdupdator = new nsMsgSearchCommandUpdater();
|
|||
|
|
|||
|
gSearchView.init(messenger, msgWindow, cmdupdator);
|
|||
|
gSearchView.open(null, nsMsgViewSortType.byId, nsMsgViewSortOrder.ascending, nsMsgViewFlagsType.kNone, count);
|
|||
|
|
|||
|
// the thread pane needs to use the search datasource (to get the
|
|||
|
// actual list of messages) and the message datasource (to get any
|
|||
|
// attributes about each message)
|
|||
|
gSearchSession = Components.classes[searchSessionContractID].createInstance(Components.interfaces.nsIMsgSearchSession);
|
|||
|
|
|||
|
gMailSession = Components.classes[mailSessionContractID].getService(Components.interfaces.nsIMsgMailSession);
|
|||
|
var nsIFolderListener = Components.interfaces.nsIFolderListener;
|
|||
|
var notifyFlags = nsIFolderListener.event;
|
|||
|
gMailSession.AddFolderListener(gFolderListener, notifyFlags);
|
|||
|
|
|||
|
// the datasource is a listener on the search results
|
|||
|
gViewSearchListener = gSearchView.QueryInterface(Components.interfaces.nsIMsgSearchNotify);
|
|||
|
gSearchSession.registerListener(gViewSearchListener);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
function setupSearchListener()
|
|||
|
{
|
|||
|
// Setup the javascript object as a listener on the search results
|
|||
|
gSearchSession.registerListener(gSearchNotificationListener);
|
|||
|
}
|
|||
|
|
|||
|
// stuff after this is implemented to make the thread pane work
|
|||
|
function GetFolderDatasource()
|
|||
|
{
|
|||
|
if (!gFolderDatasource)
|
|||
|
gFolderDatasource = Components.classes[folderDSContractID].getService(Components.interfaces.nsIRDFDataSource);
|
|||
|
return gFolderDatasource;
|
|||
|
}
|
|||
|
|
|||
|
// used to determine if we should try to load a message
|
|||
|
function IsThreadAndMessagePaneSplitterCollapsed()
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
// used to toggle functionality for Search/Stop button.
|
|||
|
function onSearchButton(event)
|
|||
|
{
|
|||
|
if (event.target.label == gSearchBundle.getString("labelForSearchButton"))
|
|||
|
onSearch();
|
|||
|
else
|
|||
|
onSearchStop();
|
|||
|
}
|
|||
|
|
|||
|
// threadPane.js will be needing this, too
|
|||
|
function GetNumSelectedMessages()
|
|||
|
{
|
|||
|
try {
|
|||
|
return gSearchView.numSelected;
|
|||
|
}
|
|||
|
catch (ex) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function GetDBView()
|
|||
|
{
|
|||
|
return gSearchView;
|
|||
|
}
|
|||
|
|
|||
|
function MsgDeleteSelectedMessages(aCommandType)
|
|||
|
{
|
|||
|
// we don't delete news messages, we just return in that case
|
|||
|
if (isNewsURI(gSearchView.getURIForViewIndex(0)))
|
|||
|
return;
|
|||
|
|
|||
|
// if mail messages delete
|
|||
|
SetNextMessageAfterDelete();
|
|||
|
gSearchView.doCommand(aCommandType);
|
|||
|
}
|
|||
|
|
|||
|
function SetNextMessageAfterDelete()
|
|||
|
{
|
|||
|
gNextMessageViewIndexAfterDelete = gSearchView.msgToSelectAfterDelete;
|
|||
|
}
|
|||
|
|
|||
|
function HandleDeleteOrMoveMessageFailed(folder)
|
|||
|
{
|
|||
|
gNextMessageViewIndexAfterDelete = -2;
|
|||
|
}
|
|||
|
|
|||
|
function HandleDeleteOrMoveMessageCompleted(folder)
|
|||
|
{
|
|||
|
var treeView = gSearchView.QueryInterface(Components.interfaces.nsITreeView);
|
|||
|
var treeSelection = treeView.selection;
|
|||
|
var viewSize = treeView.rowCount;
|
|||
|
|
|||
|
if (gNextMessageViewIndexAfterDelete == -2) {
|
|||
|
// a move or delete can cause our selection can change underneath us.
|
|||
|
// this can happen when the user
|
|||
|
// deletes message from the stand alone msg window
|
|||
|
// or the three pane
|
|||
|
if (!treeSelection) {
|
|||
|
// this can happen if you open the search window
|
|||
|
// and before you do any searches
|
|||
|
// and you do delete from another mail window
|
|||
|
return;
|
|||
|
}
|
|||
|
else if (treeSelection.count == 0) {
|
|||
|
// this can happen if you double clicked a message
|
|||
|
// in the thread pane, and deleted it from the stand alone msg window
|
|||
|
// see bug #185147
|
|||
|
treeSelection.clearSelection();
|
|||
|
|
|||
|
UpdateMailSearch("delete from another view, 0 rows now selected");
|
|||
|
}
|
|||
|
else if (treeSelection.count == 1) {
|
|||
|
// this can happen if you had two messages selected
|
|||
|
// in the search results pane, and you deleted one of them from another view
|
|||
|
// (like the view in the stand alone msg window or the three pane)
|
|||
|
// since one item is selected, we should load it.
|
|||
|
var startIndex = {};
|
|||
|
var endIndex = {};
|
|||
|
treeSelection.getRangeAt(0, startIndex, endIndex);
|
|||
|
|
|||
|
// select the selected item, so we'll load it
|
|||
|
treeSelection.select(startIndex.value);
|
|||
|
treeView.selectionChanged();
|
|||
|
|
|||
|
EnsureRowInThreadTreeIsVisible(startIndex.value);
|
|||
|
UpdateMailSearch("delete from another view, 1 row now selected");
|
|||
|
}
|
|||
|
else {
|
|||
|
// this can happen if you have more than 2 messages selected
|
|||
|
// in the search results pane, and you deleted one of them from another view
|
|||
|
// (like the view in the stand alone msg window or the three pane)
|
|||
|
// since multiple messages are still selected, do nothing.
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
if (gNextMessageViewIndexAfterDelete != nsMsgViewIndex_None && gNextMessageViewIndexAfterDelete >= viewSize)
|
|||
|
{
|
|||
|
if (viewSize > 0)
|
|||
|
gNextMessageViewIndexAfterDelete = viewSize - 1;
|
|||
|
else
|
|||
|
{
|
|||
|
gNextMessageViewIndexAfterDelete = nsMsgViewIndex_None;
|
|||
|
|
|||
|
// there is nothing to select since viewSize is 0
|
|||
|
treeSelection.clearSelection();
|
|||
|
|
|||
|
UpdateMailSearch("delete from current view, 0 rows left");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 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)
|
|||
|
{
|
|||
|
treeSelection.select(gNextMessageViewIndexAfterDelete);
|
|||
|
// since gNextMessageViewIndexAfterDelete probably has the same value
|
|||
|
// as the last index we had selected, the tree isn't generating a new
|
|||
|
// selectionChanged notification for the tree view. So we aren't loading the
|
|||
|
// next message. to fix this, force the selection changed update.
|
|||
|
if (treeView)
|
|||
|
treeView.selectionChanged();
|
|||
|
|
|||
|
EnsureRowInThreadTreeIsVisible(gNextMessageViewIndexAfterDelete);
|
|||
|
|
|||
|
// XXX TODO
|
|||
|
// 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?
|
|||
|
UpdateMailSearch("delete from current view, at least one row selected");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// default value after delete/move/copy is over
|
|||
|
gNextMessageViewIndexAfterDelete = -2;
|
|||
|
|
|||
|
// something might have been deleted, so update the status text
|
|||
|
SetAdvancedSearchStatusText(viewSize);
|
|||
|
}
|
|||
|
|
|||
|
function MoveMessageInSearch(destFolder)
|
|||
|
{
|
|||
|
try {
|
|||
|
// get the msg folder we're moving messages into
|
|||
|
// if the id (uri) is not set, use file-uri which is set for
|
|||
|
// "File Here"
|
|||
|
var destUri = destFolder.getAttribute('id');
|
|||
|
if (destUri.length == 0) {
|
|||
|
destUri = destFolder.getAttribute('file-uri')
|
|||
|
}
|
|||
|
|
|||
|
var destResource = RDF.GetResource(destUri);
|
|||
|
|
|||
|
var destMsgFolder = destResource.QueryInterface(Components.interfaces.nsIMsgFolder);
|
|||
|
|
|||
|
// we don't move news messages, we copy them
|
|||
|
if (isNewsURI(gSearchView.getURIForViewIndex(0))) {
|
|||
|
gSearchView.doCommandWithFolder(nsMsgViewCommandType.copyMessages, destMsgFolder);
|
|||
|
}
|
|||
|
else {
|
|||
|
SetNextMessageAfterDelete();
|
|||
|
gSearchView.doCommandWithFolder(nsMsgViewCommandType.moveMessages, destMsgFolder);
|
|||
|
}
|
|||
|
}
|
|||
|
catch (ex) {
|
|||
|
dump("MsgMoveMessage failed: " + ex + "\n");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function GoToFolder()
|
|||
|
{
|
|||
|
MsgOpenNewWindowForMsgHdr(gSearchView.hdrForFirstSelectedMessage);
|
|||
|
}
|
|||
|
|
|||
|
function BeginDragThreadPane(event)
|
|||
|
{
|
|||
|
// no search pane dnd yet
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
function saveAsVirtualFolder()
|
|||
|
{
|
|||
|
var preselectedURI = gCurrentFolder.URI;
|
|||
|
searchFolderURIs = preselectedURI;
|
|||
|
|
|||
|
var searchSubfolders = document.getElementById("checkSearchSubFolders").checked;
|
|||
|
if (gCurrentFolder && (searchSubfolders || gCurrentFolder.isServer || gCurrentFolder.noSelect))
|
|||
|
{
|
|||
|
var subFolderURIs = AddSubFoldersToURI(gCurrentFolder);
|
|||
|
if (subFolderURIs.length > 0)
|
|||
|
searchFolderURIs += '|' + subFolderURIs;
|
|||
|
}
|
|||
|
|
|||
|
var dialog = window.openDialog("chrome://messenger/content/virtualFolderProperties.xul", "",
|
|||
|
"chrome,titlebar,modal,centerscreen",
|
|||
|
{preselectedURI:preselectedURI,
|
|||
|
searchTerms:gSearchSession.searchTerms,
|
|||
|
searchFolderURIs: searchFolderURIs});
|
|||
|
}
|
|||
|
|