home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2002 January
/
01_02.iso
/
software
/
netscape62win
/
mail.xpi
/
bin
/
chrome
/
messenger.jar
/
content
/
messenger
/
SearchDialog.js
< prev
next >
Wrap
Text File
|
2001-08-07
|
19KB
|
613 lines
/* -*- 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):
* Hσkan Waara <hwaara@chello.se>
*/
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 gNumOfSearchHits = 0;
var RDF;
var gSearchBundle;
var gNextMessageViewIndexAfterDelete = -1;
// Datasource search listener -- made global as it has to be registered
// and unregistered in different functions.
var gDataSourceSearchListener;
var gViewSearchListener;
var gSearchStopButton;
var gSearchSessionFolderListener;
var gMailSession;
// Controller object for search results thread pane
var nsSearchResultsController =
{
supportsCommand: function(command)
{
switch(command) {
case "button_delete":
case "cmd_open":
case "file_message_button":
return true;
default:
return false;
}
},
// this controller only handles commands
// that rely on items being selected in
// the threadpane.
isCommandEnabled: function(command)
{
var enabled = true;
if (GetNumSelectedMessages() <= 0)
enabled = false;
return enabled;
},
doCommand: function(command)
{
switch(command) {
case "cmd_open":
MsgOpenSelectedMessages(gSearchView);
return true;
case "button_delete":
MsgDeleteSelectedMessages();
return true;
default:
return false;
}
},
onEvent: function(event)
{
}
}
// nsIMsgSearchNotify object
var gSearchNotificationListener =
{
onSearchHit: function(header, folder)
{
gNumOfSearchHits++;
},
onSearchDone: function(status)
{
gSearchStopButton.setAttribute("label", gSearchBundle.getString("labelForSearchButton"));
var statusMsg;
// if there are no hits, it means no matches were found in the search.
if (gNumOfSearchHits == 0) {
statusMsg = gSearchBundle.getString("searchFailureMessage");
}
else
{
if (gNumOfSearchHits == 1)
statusMsg = gSearchBundle.getString("searchSuccessMessage");
else
statusMsg = gSearchBundle.getFormattedString("searchSuccessMessages", [gNumOfSearchHits]);
gNumOfSearchHits = 0;
}
gStatusFeedback.showProgress(100);
gStatusFeedback.showStatusString(statusMsg);
gStatusBar.setAttribute("mode","normal");
},
onNewSearch: function()
{
gSearchStopButton.setAttribute("label", gSearchBundle.getString("labelForStopButton"));
document.commandDispatcher.updateCommands('mail-search');
gStatusFeedback.showProgress(0);
gStatusFeedback.showStatusString(gSearchBundle.getString("searchingMessage"));
gStatusBar.setAttribute("mode","undetermined");
}
}
// the folderListener object
var gFolderListener = {
OnItemAdded: function(parentItem, item, view) {},
OnItemRemoved: function(parentItem, item, view){},
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.GetUnicode();
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();
gSearchBundle = document.getElementById("bundle_search");
setupDatasource();
setupSearchListener();
if (window.arguments && window.arguments[0])
selectFolder(window.arguments[0].folder);
onMore(null);
document.commandDispatcher.updateCommands('mail-search');
moveToAlertPosition();
// 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("sizeCol");
HideSearchColumn("flaggedCol");
// we want to show the location column for search
ShowSearchColumn("locationCol");
}
function searchOnUnload()
{
// unregister listeners
gSearchSession.unregisterListener(gViewSearchListener);
gSearchSession.unregisterListener(gSearchNotificationListener);
gMailSession.RemoveFolderListener(gSearchSessionFolderListener);
gSearchSession.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');
msgWindow = Components.classes[msgWindowContractID].createInstance(nsIMsgWindow);
msgWindow.statusFeedback = gStatusFeedback;
msgWindow.SetDOMWindow(window);
// 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 onReset() {
}
function getFirstItemByTag(root, tag)
{
var node;
if (root.localName == tag)
return root;
if (root.childNodes) {
for (node = root.firstChild; node; node=node.nextSibling) {
if (node.localName != "template") {
result = getFirstItemByTag(node, tag);
if (result) return result;
}
}
}
return null;
}
function selectFolder(folder) {
var folderURI;
if (!folder) {
// walk folders to find first item
var firstItem = getFirstItemByTag(gFolderPicker, "menu");
folderURI = firstItem.id;
} 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);
setSearchScope(GetScopeForFolder(gCurrentFolder));
}
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 outliner to reset itself
var outlinerView = gSearchView.QueryInterface(Components.interfaces.nsIOutlinerView);
if (outlinerView)
{
var outliner = GetThreadOutliner();
outliner.boxObject.QueryInterface(Components.interfaces.nsIOutlinerBoxObject).view = outlinerView;
}
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)
{
if (!nextFolder.noSelect)
gSearchSession.addScopeTerm(GetScopeForFolder(nextFolder), nextFolder);
AddSubFolders(nextFolder);
}
}
try
{
subFolderEnumerator.next();
}
catch (ex)
{
done = true;
}
}
}
}
function GetScopeForFolder(folder)
{
return 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)
{
},
QueryInterface : function(iid)
{
if(iid.equals(Components.interfaces.nsIMsgDBViewCommandUpdater))
return this;
throw Components.results.NS_NOINTERFACE;
return null;
}
}
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);
gSearchSessionFolderListener = gSearchSession.QueryInterface(Components.interfaces.nsIFolderListener);
gMailSession = Components.classes[mailSessionContractID].getService(Components.interfaces.nsIMsgMailSession);
gMailSession.AddFolderListener(gSearchSessionFolderListener);
// the datasource is a listener on the search results
gViewSearchListener = gSearchView.QueryInterface(Components.interfaces.nsIMsgSearchNotify);
gSearchSession.registerListener(gViewSearchListener);
gSearchSession.addFolderListener(gFolderListener);
}
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].createInstance(Components.interfaces.nsIRDFDataSource);
return gFolderDatasource;
}
// used to determine if we should try to load a message
function IsThreadAndMessagePaneSplitterCollapsed()
{
return true;
}
function setMsgDatasourceWindow(ds, msgwindow)
{
try {
var msgDatasource = ds.QueryInterface(nsIMsgRDFDataSource);
msgDatasource.window = msgwindow;
} catch (ex) {
dump("error setting DS on " + ds + ": " + ex + "\n");
}
}
// 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()
{
// 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(nsMsgViewCommandType.deleteMsg);
}
function SetNextMessageAfterDelete()
{
dump("setting next msg view index after delete to " + gSearchView.msgToSelectAfterDelete + "\n");
gNextMessageViewIndexAfterDelete = gSearchView.msgToSelectAfterDelete;
}
function HandleDeleteOrMoveMessageFailed(folder)
{
gNextMessageViewIndexAfterDelete = -1;
}
function HandleDeleteOrMoveMessageCompleted(folder)
{
var outlinerView = gSearchView.QueryInterface(Components.interfaces.nsIOutlinerView);
var outlinerSelection = outlinerView.selection;
viewSize = outlinerView.rowCount;
if (gNextMessageViewIndexAfterDelete >= viewSize)
{
if (viewSize > 0)
gNextMessageViewIndexAfterDelete = viewSize - 1;
else
gNextMessageViewIndexAfterDelete = -1;
}
// 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 != -1) {
outlinerSelection.select(gNextMessageViewIndexAfterDelete);
// since gNextMessageViewIndexAfterDelete probably has the same value
// as the last index we had selected, the outliner isn't generating a new
// selectionChanged notification for the outliner view. So we aren't loading the
// next message. to fix this, force the selection changed update.
var outlinerView = gSearchView.QueryInterface(Components.interfaces.nsIOutlinerView);
if (outlinerView)
outlinerView.selectionChanged();
EnsureRowInThreadOutlinerIsVisible(gNextMessageViewIndexAfterDelete);
}
else
outlinerSelection.clearSelection(); /* clear selection in either case */
}
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 BeginDragThreadPane(event)
{
// no search pane dnd yet
return false;
}