Bug 777732 - Remove compose windows recycling (part 1). r=mkmelin a=jorgk SM CLOSED TREE
--HG-- extra : amend_source : ca1429db926ffc959e12cc064f03e6ee4cbffb4b
This commit is contained in:
Родитель
bc3e45281a
Коммит
9af4160c55
|
@ -171,90 +171,6 @@ function updateEditableFields(aDisable)
|
|||
elements[i].disabled = aDisable;
|
||||
}
|
||||
|
||||
var gComposeRecyclingListener = {
|
||||
onClose: function() {
|
||||
//Clear the subject
|
||||
GetMsgSubjectElement().value = "";
|
||||
// be sure to clear the transaction manager for the subject
|
||||
GetMsgSubjectElement().editor.transactionManager.clear();
|
||||
SetComposeWindowTitle();
|
||||
|
||||
//Reset recipients and attachments
|
||||
awResetAllRows();
|
||||
RemoveAllAttachments();
|
||||
|
||||
// We need to clear the identity popup menu in case the user will change them.
|
||||
// It will be rebuilt later in ComposeStartup
|
||||
ClearIdentityListPopup(document.getElementById("msgIdentityPopup"));
|
||||
var identityElement = document.getElementById("msgIdentity");
|
||||
identityElement.editable = false;
|
||||
identityElement.setAttribute("type", "description");
|
||||
var customizeMenuitem = document.getElementById("cmd_customizeFromAddress");
|
||||
customizeMenuitem.removeAttribute("disabled");
|
||||
customizeMenuitem.setAttribute("checked", "false");
|
||||
|
||||
// Do not listen to changes to spell check dictionary.
|
||||
document.removeEventListener("spellcheck-changed", updateDocumentLanguage);
|
||||
|
||||
// Disconnect the observer, we'll attach a new one when recycling the
|
||||
// window.
|
||||
gLanguageObserver.disconnect();
|
||||
|
||||
// Stop observing dictionary removals.
|
||||
dictionaryRemovalObserver.removeObserver();
|
||||
|
||||
// Stop gSpellChecker so personal dictionary is saved.
|
||||
// We need to do this before disabling the editor.
|
||||
enableInlineSpellCheck(false);
|
||||
// clear any suggestions in the context menu
|
||||
gSpellChecker.clearSuggestionsFromMenu();
|
||||
gSpellChecker.clearDictionaryListFromMenu();
|
||||
|
||||
SetContentAndBodyAsUnmodified();
|
||||
updateEditableFields(true);
|
||||
|
||||
// Clear the focus
|
||||
awGetInputElement(1).removeAttribute('focused');
|
||||
|
||||
//Reset Boxes size
|
||||
document.getElementById("headers-box").removeAttribute("height");
|
||||
document.getElementById("appcontent").removeAttribute("height");
|
||||
document.getElementById("addresses-box").removeAttribute("width");
|
||||
|
||||
//Reset menu options
|
||||
document.getElementById("format_auto").setAttribute("checked", "true");
|
||||
document.getElementById("priority_normal").setAttribute("checked", "true");
|
||||
|
||||
// Reset the Customize Toolbars panel/sheet if open.
|
||||
if (getMailToolbox().customizing && gCustomizeSheet)
|
||||
document.getElementById("customizeToolbarSheetIFrame")
|
||||
.contentWindow.finishToolbarCustomization();
|
||||
|
||||
//Reset editor
|
||||
EditorResetFontAndColorAttributes();
|
||||
EditorCleanup();
|
||||
gAttachmentNotifier.redetectKeywords();
|
||||
|
||||
//Release the nsIMsgComposeParams object
|
||||
if (window.arguments && window.arguments[0])
|
||||
window.arguments[0] = null;
|
||||
document.getElementById("msgcomposeWindow").dispatchEvent(
|
||||
new Event("compose-window-close", { bubbles: false , cancelable: true }));
|
||||
if (gAutoSaveTimeout)
|
||||
clearTimeout(gAutoSaveTimeout);
|
||||
ReleaseGlobalVariables(); // This line must be the last in onClose();
|
||||
},
|
||||
|
||||
onReopen: function(params) {
|
||||
InitializeGlobalVariables();
|
||||
ComposeStartup(true, params);
|
||||
|
||||
var event = document.createEvent('Events');
|
||||
event.initEvent('compose-window-reopen', false, true);
|
||||
document.getElementById("msgcomposeWindow").dispatchEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
var PrintPreviewListener = {
|
||||
getPrintPreviewBrowser: function() {
|
||||
var browser = document.getElementById("cppBrowser");
|
||||
|
@ -379,7 +295,7 @@ var stateListener = {
|
|||
if (gMsgCompose)
|
||||
gMsgCompose.onSendNotPerformed(null, Components.results.NS_ERROR_ABORT);
|
||||
|
||||
MsgComposeCloseWindow(true);
|
||||
MsgComposeCloseWindow();
|
||||
}
|
||||
}
|
||||
// else if we failed to save, and we're autosaving, need to re-mark the editor
|
||||
|
@ -1671,8 +1587,8 @@ function DoCommandClose()
|
|||
if (gMsgCompose)
|
||||
gMsgCompose.onSendNotPerformed(null, Components.results.NS_ERROR_ABORT);
|
||||
|
||||
// note: if we're not caching this window, this destroys it for us
|
||||
MsgComposeCloseWindow(true);
|
||||
// This destroys the window for us.
|
||||
MsgComposeCloseWindow();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -2102,10 +2018,6 @@ var dictionaryRemovalObserver =
|
|||
},
|
||||
|
||||
removeObserver: function() {
|
||||
// We need to protect against double removal:
|
||||
// The window can be recycled and later destroyed (at shutdown or when the
|
||||
// composition style changes from HTML to plain text or vice versa) or
|
||||
// only destroyed if it was never recycled before.
|
||||
if (this.isAdded) {
|
||||
Services.obs.removeObserver(this, "spellcheck-dictionary-remove");
|
||||
this.isAdded = false;
|
||||
|
@ -2113,7 +2025,7 @@ var dictionaryRemovalObserver =
|
|||
}
|
||||
}
|
||||
|
||||
function ComposeStartup(recycled, aParams)
|
||||
function ComposeStartup(aParams)
|
||||
{
|
||||
// Findbar overlay
|
||||
if (!document.getElementById("findbar-replaceButton")) {
|
||||
|
@ -2297,11 +2209,7 @@ function ComposeStartup(recycled, aParams)
|
|||
var editorElement = GetCurrentEditorElement();
|
||||
gMsgCompose = MailServices.compose.initCompose(params, window, editorElement.docShell);
|
||||
|
||||
// Set the close listener.
|
||||
gMsgCompose.recyclingListener = gComposeRecyclingListener;
|
||||
gMsgCompose.addMsgSendListener(gSendListener);
|
||||
// Lets the compose object know that we are dealing with a recycled window.
|
||||
gMsgCompose.recycledWindow = recycled;
|
||||
|
||||
document.getElementById("returnReceiptMenu")
|
||||
.setAttribute('checked', gMsgCompose.compFields.returnReceipt);
|
||||
|
@ -2314,32 +2222,25 @@ function ComposeStartup(recycled, aParams)
|
|||
SetCompositionAsPerDeliveryFormat(gSendFormat);
|
||||
SelectDeliveryFormatMenuOption(gSendFormat);
|
||||
|
||||
// If recycle, editor is already created.
|
||||
if (!recycled)
|
||||
let editortype = gMsgCompose.composeHTML ? "htmlmail" : "textmail";
|
||||
editorElement.makeEditable(editortype, true);
|
||||
|
||||
// setEditorType MUST be called before setContentWindow
|
||||
if (gMsgCompose.composeHTML)
|
||||
{
|
||||
let editortype = gMsgCompose.composeHTML ? "htmlmail" : "textmail";
|
||||
editorElement.makeEditable(editortype, true);
|
||||
|
||||
// setEditorType MUST be called before setContentWindow
|
||||
if (gMsgCompose.composeHTML)
|
||||
{
|
||||
initLocalFontFaceMenu(document.getElementById("FontFacePopup"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are editing in plain text mode.
|
||||
// The SetCompositionAsPerDeliveryFormat call above already hid
|
||||
// the HTML toolbar, format and insert menus.
|
||||
// Also remove the delivery format from the options menu.
|
||||
// We only do that when the window is first created ("!recycled")
|
||||
// as we will never need to restore it since a plain text window will
|
||||
// never be used for a HTML composition.
|
||||
document.getElementById("outputFormatMenu").setAttribute("hidden", true);
|
||||
}
|
||||
|
||||
// Do setup common to Message Composer and Web Composer.
|
||||
EditorSharedStartup();
|
||||
initLocalFontFaceMenu(document.getElementById("FontFacePopup"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are editing in plain text mode.
|
||||
// The SetCompositionAsPerDeliveryFormat call above already hid
|
||||
// the HTML toolbar, format and insert menus.
|
||||
// Also remove the delivery format from the options menu.
|
||||
document.getElementById("outputFormatMenu").setAttribute("hidden", true);
|
||||
}
|
||||
|
||||
// Do setup common to Message Composer and Web Composer.
|
||||
EditorSharedStartup();
|
||||
|
||||
if (params.bodyIsLink)
|
||||
{
|
||||
|
@ -2370,33 +2271,16 @@ function ComposeStartup(recycled, aParams)
|
|||
|
||||
gMsgCompose.RegisterStateListener(stateListener);
|
||||
|
||||
if (recycled)
|
||||
{
|
||||
InitEditor();
|
||||
// Add an observer to be called when document is done loading,
|
||||
// which creates the editor.
|
||||
try {
|
||||
GetCurrentCommandManager().
|
||||
addCommandObserver(gMsgEditorCreationObserver, "obs_documentCreated");
|
||||
|
||||
if (gMsgCompose.composeHTML)
|
||||
{
|
||||
// Force color picker on toolbar to show document colors.
|
||||
onFontColorChange();
|
||||
onBackgroundColorChange();
|
||||
}
|
||||
|
||||
// Reset the priority field for recycled windows.
|
||||
updatePriorityToolbarButton("Normal");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add an observer to be called when document is done loading,
|
||||
// which creates the editor.
|
||||
try {
|
||||
GetCurrentCommandManager().
|
||||
addCommandObserver(gMsgEditorCreationObserver, "obs_documentCreated");
|
||||
|
||||
// Load empty page to create the editor.
|
||||
editorElement.webNavigation.loadURI("about:blank", 0, null, null, null);
|
||||
} catch (e) {
|
||||
Components.utils.reportError(e);
|
||||
}
|
||||
// Load empty page to create the editor.
|
||||
editorElement.webNavigation.loadURI("about:blank", 0, null, null, null);
|
||||
} catch (e) {
|
||||
Components.utils.reportError(e);
|
||||
}
|
||||
|
||||
gEditingDraft = gMsgCompose.compFields.draftId;
|
||||
|
@ -2456,7 +2340,7 @@ function WizCallback(state)
|
|||
else
|
||||
{
|
||||
// The account wizard is still closing so we can't close just yet
|
||||
setTimeout(MsgComposeCloseWindow, 0, false); // Don't recycle a bogus window
|
||||
setTimeout(MsgComposeCloseWindow, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2495,14 +2379,14 @@ function ComposeLoad()
|
|||
selectNode.appendItem(other_headers_Array[i] + ":", "addr_other");
|
||||
}
|
||||
if (state)
|
||||
ComposeStartup(false, null);
|
||||
ComposeStartup(null);
|
||||
}
|
||||
catch (ex) {
|
||||
Components.utils.reportError(ex);
|
||||
Services.prompt.alert(window, getComposeBundle().getString("initErrorDlogTitle"),
|
||||
getComposeBundle().getString("initErrorDlgMessage"));
|
||||
|
||||
MsgComposeCloseWindow(false); // Don't try to recycle a bogus window
|
||||
MsgComposeCloseWindow();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3664,10 +3548,10 @@ function SetContentAndBodyAsUnmodified()
|
|||
gContentChanged = false;
|
||||
}
|
||||
|
||||
function MsgComposeCloseWindow(recycleIt)
|
||||
function MsgComposeCloseWindow()
|
||||
{
|
||||
if (gMsgCompose)
|
||||
gMsgCompose.CloseWindow(recycleIt);
|
||||
gMsgCompose.CloseWindow();
|
||||
else
|
||||
window.close();
|
||||
}
|
||||
|
@ -4993,9 +4877,8 @@ function InitEditor()
|
|||
editor.addOverrideStyleSheet("chrome://messenger/content/composerOverlay.css");
|
||||
gMsgCompose.initEditor(editor, window.content);
|
||||
|
||||
// We always go through this function everytime we init an editor, be it a
|
||||
// recycled editor, or a fresh one. First step is making sure we can spell
|
||||
// check.
|
||||
// We always go through this function everytime we init an editor.
|
||||
// First step is making sure we can spell check.
|
||||
gSpellChecker.init(editor);
|
||||
document.getElementById('menu_inlineSpellCheck')
|
||||
.setAttribute('disabled', !gSpellChecker.canSpellCheck);
|
||||
|
|
|
@ -73,8 +73,7 @@ function onComposerReOpen()
|
|||
|
||||
addEventListener("load", smimeComposeOnLoad, false);
|
||||
|
||||
// this function gets called multiple times,
|
||||
// but only on first open, not on composer recycling
|
||||
// this function gets called multiple times.
|
||||
function smimeComposeOnLoad()
|
||||
{
|
||||
removeEventListener("load", smimeComposeOnLoad, false);
|
||||
|
|
|
@ -554,42 +554,6 @@ function test_disabled_attachment_reminder() {
|
|||
Services.prefs.setBoolPref(kReminderPref, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug 1099866
|
||||
* Check if reminder does not stay open on compose window reopen
|
||||
* due to window recycling.
|
||||
*/
|
||||
function test_recycling_attachment_reminder() {
|
||||
let recycledWindows = Services.prefs.getIntPref("mail.compose.max_recycled_windows");
|
||||
assert_true(recycledWindows > 0);
|
||||
// Open a sample message with no attachment keywords.
|
||||
let cwc = open_compose_new_mail();
|
||||
setupComposeWin(cwc, "test@example.invalid", "Testing recycling a reminder!",
|
||||
"Some body...");
|
||||
|
||||
// There should be no attachment notification.
|
||||
assert_automatic_reminder_state(cwc, false);
|
||||
|
||||
// Add some keyword so the automatic notification
|
||||
// could potentially show up.
|
||||
setupComposeWin(cwc, "", "", " and look for your attachment!");
|
||||
// Give the notification time to appear. It should.
|
||||
wait_for_reminder_state(cwc, true);
|
||||
|
||||
close_compose_window(cwc, true);
|
||||
|
||||
// Another compose window without any keywords.
|
||||
cwc = open_compose_new_mail();
|
||||
setupComposeWin(cwc, "test@example.invalid", "Testing reminder after recycling!",
|
||||
"Some body...");
|
||||
|
||||
// There should be no attachment notification.
|
||||
assert_automatic_reminder_state(cwc, false);
|
||||
|
||||
close_compose_window(cwc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Click the send button and handle the send error dialog popping up.
|
||||
* It will return us back to the compose window.
|
||||
|
|
|
@ -159,8 +159,10 @@ function test_encoding_upgrade_html_compose() {
|
|||
throw new Error("Chinese text not in msg; CHINESE=" + CHINESE +
|
||||
", draftMsg2Content=" + draftMsg2Content);
|
||||
|
||||
// Ctrl+Shift+Return = Send Later
|
||||
compWin.keypress(null, "VK_RETURN", {shiftKey: true, accelKey: true});
|
||||
compWin.window.setTimeout(function() {
|
||||
// Ctrl+Shift+Return = Send Later
|
||||
compWin.keypress(null, "VK_RETURN", {shiftKey: true, accelKey: true});
|
||||
}, 0);
|
||||
|
||||
be_in_folder(outboxFolder);
|
||||
let outMsg = select_click_row(0);
|
||||
|
@ -232,8 +234,10 @@ function test_encoding_upgrade_plaintext_compose() {
|
|||
throw new Error("Chinese text not in msg; CHINESE=" + CHINESE +
|
||||
", draftMsg2Content=" + draftMsg2Content);
|
||||
|
||||
// Ctrl+Shift+Return = Send Later.
|
||||
compWin.keypress(null, "VK_RETURN", {shiftKey: true, accelKey: true});
|
||||
compWin.window.setTimeout(function() {
|
||||
// Ctrl+Shift+Return = Send Later.
|
||||
compWin.keypress(null, "VK_RETURN", {shiftKey: true, accelKey: true});
|
||||
}, 0);
|
||||
|
||||
be_in_folder(outboxFolder);
|
||||
let outMsg = select_click_row(0);
|
||||
|
|
|
@ -143,7 +143,7 @@ function test_save_delivery_format() {
|
|||
close_compose_window(cwc);
|
||||
|
||||
// Open a new composition see if the menu is again at default value, not the one
|
||||
// chosen above, even in a recycled compose window.
|
||||
// chosen above.
|
||||
cwc = open_compose_new_mail();
|
||||
|
||||
assert_format_value("format_auto", Ci.nsIMsgCompSendFormat.AskUser);
|
||||
|
|
|
@ -91,13 +91,6 @@ interface nsIMsgComposeNotificationType
|
|||
native nsString(nsString);
|
||||
[ref] native nsStringRef(nsString);
|
||||
|
||||
/* recycling listener interface */
|
||||
[scriptable, uuid(0b28cc56-1dd2-11b2-bbe4-99e6a314f8ba)]
|
||||
interface nsIMsgComposeRecyclingListener : nsISupports {
|
||||
void onClose();
|
||||
void onReopen(in nsIMsgComposeParams params);
|
||||
};
|
||||
|
||||
[scriptable, uuid(c6544b6b-06dd-43ac-89b5-949d7c81bb7b)]
|
||||
interface nsIMsgCompose : nsIMsgSendListener {
|
||||
|
||||
|
@ -140,7 +133,7 @@ interface nsIMsgCompose : nsIMsgSendListener {
|
|||
in string accountKey);
|
||||
|
||||
/* ... */
|
||||
void CloseWindow(in boolean reclycleIt);
|
||||
void CloseWindow();
|
||||
|
||||
/* ... */
|
||||
void abort();
|
||||
|
@ -284,12 +277,6 @@ interface nsIMsgCompose : nsIMsgSendListener {
|
|||
/* ... */
|
||||
[noscript] void getQuotingToFollow(out boolean quotingToFollow);
|
||||
|
||||
/* ... */
|
||||
attribute nsIMsgComposeRecyclingListener recyclingListener;
|
||||
|
||||
/* ... */
|
||||
attribute boolean recycledWindow;
|
||||
|
||||
readonly attribute string originalMsgURI;
|
||||
|
||||
attribute boolean deleteDraft;
|
||||
|
|
|
@ -46,8 +46,7 @@ interface nsIMsgComposeService : nsISupports {
|
|||
void OpenComposeWindowWithParams(in string msgComposeWindowURL, in nsIMsgComposeParams params);
|
||||
|
||||
/**
|
||||
* Creates an nsIMsgCompose instance, initalizes it, and manages the window
|
||||
* recycling cache.
|
||||
* Creates an nsIMsgCompose instance and initalizes it.
|
||||
*
|
||||
* @param aParams An nsIMsgComposeParams object containing the initial
|
||||
* details for the compose.
|
||||
|
@ -73,8 +72,6 @@ interface nsIMsgComposeService : nsISupports {
|
|||
readonly attribute boolean logComposePerformance;
|
||||
|
||||
[noscript] boolean determineComposeHTML(in nsIMsgIdentity aIdentity, in MSG_ComposeFormat aFormat);
|
||||
[noscript] void cacheWindow(in mozIDOMWindowProxy aWindow, in boolean aComposeHTML, in nsIMsgComposeRecyclingListener listener);
|
||||
boolean isCachedWindow(in mozIDOMWindowProxy aWindow);
|
||||
|
||||
/**
|
||||
* given a mailto url, parse the attributes and turn them into a nsIMsgComposeParams object
|
||||
|
@ -130,7 +127,7 @@ interface nsIMsgComposeService : nsISupports {
|
|||
in nsIMsgCompose aMsgCompose);
|
||||
|
||||
/**
|
||||
* When an editor docShell is being closed (or recycled), you should
|
||||
* When an editor docShell is being closed, you should
|
||||
* unregister it from this service. nsIMsgCompose normally calls this
|
||||
* automatically for items passed to initCompose.
|
||||
*
|
||||
|
|
|
@ -187,7 +187,6 @@ nsMsgCompose::nsMsgCompose()
|
|||
prefBranch->GetBoolPref("converter.html2txt.structs", &mConvertStructs);
|
||||
|
||||
m_composeHTML = false;
|
||||
mRecycledWindow = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -610,17 +609,6 @@ nsMsgCompose::ConvertAndLoadComposeWindow(nsString& aPrefix,
|
|||
TranslateLineEnding(aBuf);
|
||||
TranslateLineEnding(aSignature);
|
||||
|
||||
// We're going to be inserting stuff, and MsgComposeCommands
|
||||
// may have set the editor to readonly in the recycled case.
|
||||
// So set it back to writable.
|
||||
// Note! enableEditableFields in gComposeRecyclingListener::onReopen
|
||||
// will redundantly set this flag to writable, but it gets there
|
||||
// too late.
|
||||
uint32_t flags = 0;
|
||||
m_editor->GetFlags(&flags);
|
||||
flags &= ~nsIPlaintextEditor::eEditorReadonlyMask;
|
||||
m_editor->SetFlags(flags);
|
||||
|
||||
m_editor->EnableUndo(false);
|
||||
|
||||
// Ok - now we need to figure out the charset of the aBuf we are going to send
|
||||
|
@ -1488,34 +1476,6 @@ NS_IMETHODIMP nsMsgCompose::SendMsg(MSG_DeliverMode deliverMode, nsIMsgIdentity
|
|||
return rv;
|
||||
}
|
||||
|
||||
// XXX when do we break this ref to the listener?
|
||||
NS_IMETHODIMP nsMsgCompose::SetRecyclingListener(nsIMsgComposeRecyclingListener *aRecyclingListener)
|
||||
{
|
||||
mRecyclingListener = aRecyclingListener;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMsgCompose::GetRecyclingListener(nsIMsgComposeRecyclingListener **aRecyclingListener)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRecyclingListener);
|
||||
*aRecyclingListener = mRecyclingListener;
|
||||
NS_IF_ADDREF(*aRecyclingListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute boolean recycledWindow; */
|
||||
NS_IMETHODIMP nsMsgCompose::GetRecycledWindow(bool *aRecycledWindow)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRecycledWindow);
|
||||
*aRecycledWindow = mRecycledWindow;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP nsMsgCompose::SetRecycledWindow(bool aRecycledWindow)
|
||||
{
|
||||
mRecycledWindow = aRecycledWindow;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute boolean deleteDraft */
|
||||
NS_IMETHODIMP nsMsgCompose::GetDeleteDraft(bool *aDeleteDraft)
|
||||
{
|
||||
|
@ -1553,7 +1513,7 @@ bool nsMsgCompose::IsLastWindow()
|
|||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMsgCompose::CloseWindow(bool recycleIt)
|
||||
NS_IMETHODIMP nsMsgCompose::CloseWindow(void)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
|
@ -1569,55 +1529,13 @@ NS_IMETHODIMP nsMsgCompose::CloseWindow(bool recycleIt)
|
|||
// temporary files.
|
||||
mMsgSend = nullptr;
|
||||
|
||||
recycleIt = recycleIt && !IsLastWindow();
|
||||
if (recycleIt)
|
||||
{
|
||||
rv = composeService->CacheWindow(m_window, m_composeHTML, mRecyclingListener);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor (do_QueryInterface(m_editor));
|
||||
NS_ASSERTION(htmlEditor, "no editor");
|
||||
if (htmlEditor)
|
||||
{
|
||||
// XXX clear undo txn manager?
|
||||
|
||||
rv = m_editor->EnableUndo(false);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
rv = htmlEditor->RebuildDocumentFromSource(EmptyString());
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
rv = m_editor->EnableUndo(true);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
SetBodyModified(false);
|
||||
}
|
||||
if (mRecyclingListener)
|
||||
{
|
||||
mRecyclingListener->OnClose();
|
||||
|
||||
/**
|
||||
* In order to really free the memory, we need to call the JS garbage collector for our window.
|
||||
* If we don't call GC, the nsIMsgCompose object held by JS will not be released despite we set
|
||||
* the JS global that held it to null. Each time we reopen a recycled window, we allocate a new
|
||||
* nsIMsgCompose that we really need to be released when we recycle the window. In fact despite
|
||||
* we call GC here, the release won't occur right away. But if we don't call it, the release
|
||||
* will happen only when we physically close the window which will happen only on quit.
|
||||
*/
|
||||
nsJSContext::PokeGC(JS::gcreason::NSJSCONTEXT_DESTROY);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
//We are going away for real, we need to do some clean up first
|
||||
if (m_baseWindow)
|
||||
{
|
||||
if (m_editor)
|
||||
{
|
||||
/* The editor will be destroyed during yje close window.
|
||||
* Set it to null to be sure we won't use it anymore
|
||||
*/
|
||||
// The editor will be destroyed during the close window.
|
||||
// Set it to null to be sure we won't use it anymore.
|
||||
m_editor = nullptr;
|
||||
}
|
||||
nsIBaseWindow * window = m_baseWindow;
|
||||
|
@ -1625,6 +1543,7 @@ NS_IMETHODIMP nsMsgCompose::CloseWindow(bool recycleIt)
|
|||
rv = window->Destroy();
|
||||
}
|
||||
|
||||
m_window = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -3759,7 +3678,7 @@ nsresult nsMsgComposeSendListener::OnStopSending(const char *aMsgID, nsresult aS
|
|||
progress->CloseProgressDialog(false);
|
||||
}
|
||||
if (hasDomWindow)
|
||||
msgCompose->CloseWindow(true);
|
||||
msgCompose->CloseWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3772,8 +3691,8 @@ nsresult nsMsgComposeSendListener::OnStopSending(const char *aMsgID, nsresult aS
|
|||
progress->CloseProgressDialog(false);
|
||||
}
|
||||
if (hasDomWindow)
|
||||
msgCompose->CloseWindow(true); // if we fail on the simple GetFcc call, close the window to be safe and avoid
|
||||
// windows hanging around to prevent the app from exiting.
|
||||
msgCompose->CloseWindow(); // if we fail on the simple GetFcc call, close the window to be safe and avoid
|
||||
// windows hanging around to prevent the app from exiting.
|
||||
}
|
||||
|
||||
// Remove the current draft msg when sending draft is done.
|
||||
|
@ -3875,7 +3794,7 @@ nsMsgComposeSendListener::OnStopCopy(nsresult aStatus)
|
|||
msgCompose->SetDeleteDraft(true);
|
||||
RemoveCurrentDraftMessage(msgCompose, true);
|
||||
}
|
||||
msgCompose->CloseWindow(true);
|
||||
msgCompose->CloseWindow();
|
||||
}
|
||||
}
|
||||
msgCompose->ClearMessageSend();
|
||||
|
|
|
@ -113,8 +113,6 @@ protected:
|
|||
QuotingOutputStreamListener *mQuoteStreamListener;
|
||||
nsCOMPtr<nsIOutputStream> mBaseStream;
|
||||
|
||||
nsCOMPtr<nsIMsgComposeRecyclingListener> mRecyclingListener;
|
||||
bool mRecycledWindow;
|
||||
nsCOMPtr<nsIMsgSend> mMsgSend; // for composition back end
|
||||
nsCOMPtr<nsIMsgProgress> mProgress; // use by the back end to report progress to the front end
|
||||
|
||||
|
|
|
@ -72,8 +72,6 @@
|
|||
|
||||
#define DEFAULT_CHROME "chrome://messenger/content/messengercompose/messengercompose.xul"
|
||||
|
||||
#define PREF_MAIL_COMPOSE_MAXRECYCLEDWINDOWS "mail.compose.max_recycled_windows"
|
||||
|
||||
#define PREF_MAILNEWS_REPLY_QUOTING_SELECTION "mailnews.reply_quoting_selection"
|
||||
#define PREF_MAILNEWS_REPLY_QUOTING_SELECTION_MULTI_WORD "mailnews.reply_quoting_selection.multi_word"
|
||||
#define PREF_MAILNEWS_REPLY_QUOTING_SELECTION_ONLY_IF "mailnews.reply_quoting_selection.only_if_chars"
|
||||
|
@ -118,45 +116,21 @@ nsMsgComposeService::nsMsgComposeService()
|
|||
mPreviousTime = mStartTime;
|
||||
#endif
|
||||
|
||||
mMaxRecycledWindows = 0;
|
||||
mCachedWindows = nullptr;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMsgComposeService,
|
||||
nsIMsgComposeService,
|
||||
nsIObserver,
|
||||
ICOMMANDLINEHANDLER,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
nsMsgComposeService::~nsMsgComposeService()
|
||||
{
|
||||
if (mCachedWindows)
|
||||
{
|
||||
DeleteCachedWindows();
|
||||
delete [] mCachedWindows;
|
||||
}
|
||||
|
||||
mOpenComposeWindows.Clear();
|
||||
}
|
||||
|
||||
nsresult nsMsgComposeService::Init()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
// Register observers
|
||||
|
||||
// Register for quit application and profile change, we will need to clear the cache.
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (observerService)
|
||||
{
|
||||
rv = observerService->AddObserver(this, "quit-application", true);
|
||||
rv = observerService->AddObserver(this, "profile-do-change", true);
|
||||
}
|
||||
|
||||
// Register some pref observer
|
||||
nsCOMPtr<nsIPrefBranch> pbi = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (pbi)
|
||||
rv = pbi->AddObserver(PREF_MAIL_COMPOSE_MAXRECYCLEDWINDOWS, this, true);
|
||||
|
||||
Reset();
|
||||
|
||||
|
@ -171,41 +145,11 @@ nsresult nsMsgComposeService::Init()
|
|||
|
||||
void nsMsgComposeService::Reset()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (mCachedWindows)
|
||||
{
|
||||
DeleteCachedWindows();
|
||||
delete [] mCachedWindows;
|
||||
mCachedWindows = nullptr;
|
||||
mMaxRecycledWindows = 0;
|
||||
}
|
||||
|
||||
mOpenComposeWindows.Clear();
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||||
if(prefs)
|
||||
rv = prefs->GetIntPref(PREF_MAIL_COMPOSE_MAXRECYCLEDWINDOWS, &mMaxRecycledWindows);
|
||||
if (NS_SUCCEEDED(rv) && mMaxRecycledWindows > 0)
|
||||
{
|
||||
mCachedWindows = new nsMsgCachedWindowInfo[mMaxRecycledWindows];
|
||||
if (!mCachedWindows)
|
||||
mMaxRecycledWindows = 0;
|
||||
}
|
||||
|
||||
rv = prefs->GetBoolPref("mailnews.logComposePerformance", &mLogComposePerformance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void nsMsgComposeService::DeleteCachedWindows()
|
||||
{
|
||||
int32_t i;
|
||||
for (i = 0; i < mMaxRecycledWindows; i ++)
|
||||
{
|
||||
CloseHiddenCachedWindow(mCachedWindows[i].window);
|
||||
mCachedWindows[i].Clear();
|
||||
}
|
||||
if (prefs)
|
||||
prefs->GetBoolPref("mailnews.logComposePerformance", &mLogComposePerformance);
|
||||
}
|
||||
|
||||
// Function to open a message compose window and pass an nsIMsgComposeParams
|
||||
|
@ -235,38 +179,7 @@ nsMsgComposeService::OpenComposeWindowWithParams(const char *chrome,
|
|||
params->SetIdentity(identity);
|
||||
}
|
||||
|
||||
//if we have a cached window for the default chrome, try to reuse it...
|
||||
if (!chrome || PL_strcasecmp(chrome, DEFAULT_CHROME) == 0)
|
||||
{
|
||||
MSG_ComposeFormat format;
|
||||
params->GetFormat(&format);
|
||||
|
||||
bool composeHTML = true;
|
||||
rv = DetermineComposeHTML(identity, format, &composeHTML);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
int32_t i;
|
||||
for (i = 0; i < mMaxRecycledWindows; i ++)
|
||||
{
|
||||
if (mCachedWindows[i].window && (mCachedWindows[i].htmlCompose == composeHTML) && mCachedWindows[i].listener)
|
||||
{
|
||||
/* We need to save the window pointer as OnReopen will call nsMsgComposeService::InitCompose which will
|
||||
clear the cache entry if everything goes well
|
||||
*/
|
||||
nsCOMPtr<mozIDOMWindowProxy> domWindow(mCachedWindows[i].window);
|
||||
nsCOMPtr<nsIXULWindow> xulWindow(mCachedWindows[i].xulWindow);
|
||||
rv = ShowCachedComposeWindow(domWindow, xulWindow, true);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
mCachedWindows[i].listener->OnReopen(params);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Else, create a new one...
|
||||
// Create a new window.
|
||||
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
|
||||
if (!wwatch)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -286,63 +199,6 @@ nsMsgComposeService::OpenComposeWindowWithParams(const char *chrome,
|
|||
return rv;
|
||||
}
|
||||
|
||||
void nsMsgComposeService::CloseHiddenCachedWindow(mozIDOMWindowProxy *domWindow)
|
||||
{
|
||||
if (domWindow)
|
||||
{
|
||||
nsCOMPtr<nsIDocShell> docshell;
|
||||
if (domWindow)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(domWindow);
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem =
|
||||
do_QueryInterface(window->GetDocShell());
|
||||
|
||||
if (treeItem)
|
||||
{
|
||||
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
|
||||
treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
|
||||
if (treeOwner)
|
||||
{
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow;
|
||||
baseWindow = do_QueryInterface(treeOwner);
|
||||
if (baseWindow) {
|
||||
// HACK ALERT: when we hid this window we fired the "xul-window-destroyed"
|
||||
// notification for it. Now that it's being really-destroyed it will fire that
|
||||
// notification *again* for itself. The appstartup code maintains an internal
|
||||
// reference count of windows that block app shutdown: we want to increment that
|
||||
// count without cancelling app shutdown (so don't use "xul-window-registered").
|
||||
nsCOMPtr<nsIAppStartup> appStartup(do_GetService(NS_APPSTARTUP_CONTRACTID));
|
||||
if (appStartup)
|
||||
appStartup->EnterLastWindowClosingSurvivalArea();
|
||||
|
||||
baseWindow->Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgComposeService::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
|
||||
{
|
||||
if (!strcmp(aTopic, "profile-do-change") || !strcmp(aTopic, "quit-application"))
|
||||
{
|
||||
DeleteCachedWindows();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID))
|
||||
{
|
||||
nsDependentString prefName(someData);
|
||||
if (prefName.EqualsLiteral(PREF_MAIL_COMPOSE_MAXRECYCLEDWINDOWS))
|
||||
Reset();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgComposeService::DetermineComposeHTML(nsIMsgIdentity *aIdentity, MSG_ComposeFormat aFormat, bool *aComposeHTML)
|
||||
{
|
||||
|
@ -714,15 +570,6 @@ NS_IMETHODIMP nsMsgComposeService::InitCompose(nsIMsgComposeParams *aParams,
|
|||
nsIDocShell *aDocShell,
|
||||
nsIMsgCompose **_retval)
|
||||
{
|
||||
// We need to remove the window from the cache.
|
||||
int32_t i;
|
||||
for (i = 0; i < mMaxRecycledWindows; i ++)
|
||||
if (mCachedWindows[i].window == aWindow)
|
||||
{
|
||||
mCachedWindows[i].Clear();
|
||||
break;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIMsgCompose> msgCompose =
|
||||
do_CreateInstance(NS_MSGCOMPOSE_CONTRACTID, &rv);
|
||||
|
@ -790,89 +637,6 @@ NS_IMETHODIMP nsMsgComposeService::TimeStamp(const char * label, bool resetTime)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgComposeService::IsCachedWindow(mozIDOMWindowProxy *aCachedWindow, bool *aIsCachedWindow)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aCachedWindow);
|
||||
NS_ENSURE_ARG_POINTER(aIsCachedWindow);
|
||||
|
||||
int32_t i;
|
||||
for (i = 0; i < mMaxRecycledWindows; i ++)
|
||||
if (mCachedWindows[i].window.get() == aCachedWindow)
|
||||
{
|
||||
*aIsCachedWindow = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aIsCachedWindow = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgComposeService::CacheWindow(mozIDOMWindowProxy *aWindow, bool aComposeHTML, nsIMsgComposeRecyclingListener * aListener)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aWindow);
|
||||
NS_ENSURE_ARG_POINTER(aListener);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(window->GetDocShell(), &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr <nsIDocShellTreeOwner> treeOwner;
|
||||
rv = treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
nsCOMPtr<nsIXULWindow> xulWindow(do_GetInterface(treeOwner, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
int32_t i;
|
||||
int32_t sameTypeId = -1;
|
||||
int32_t oppositeTypeId = -1;
|
||||
|
||||
for (i = 0; i < mMaxRecycledWindows; i ++)
|
||||
{
|
||||
if (!mCachedWindows[i].window)
|
||||
{
|
||||
rv = ShowCachedComposeWindow(aWindow, xulWindow, false);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mCachedWindows[i].Initialize(aWindow, xulWindow, aListener, aComposeHTML);
|
||||
|
||||
return rv;
|
||||
}
|
||||
else
|
||||
if (mCachedWindows[i].htmlCompose == aComposeHTML)
|
||||
{
|
||||
if (sameTypeId == -1)
|
||||
sameTypeId = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (oppositeTypeId == -1)
|
||||
oppositeTypeId = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Looks like the cache is full. In the case we try to cache a type (html or plain text) of compose window which is not
|
||||
already cached, we should replace an opposite one with this new one. That would allow users to be able to take advantage
|
||||
of the cached compose window when they switch from one type to another one
|
||||
*/
|
||||
if (sameTypeId == -1 && oppositeTypeId != -1)
|
||||
{
|
||||
CloseHiddenCachedWindow(mCachedWindows[oppositeTypeId].window);
|
||||
mCachedWindows[oppositeTypeId].Clear();
|
||||
|
||||
rv = ShowCachedComposeWindow(aWindow, xulWindow, false);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mCachedWindows[oppositeTypeId].Initialize(aWindow, xulWindow, aListener, aComposeHTML);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
class nsMsgTemplateReplyHelper final: public nsIStreamListener,
|
||||
public nsIUrlListener
|
||||
{
|
||||
|
@ -1295,74 +1059,6 @@ nsMsgComposeService::ForwardMessage(const nsAString &forwardTo,
|
|||
return folder->AddMessageDispositionState(aMsgHdr, nsIMsgFolder::nsMsgDispositionState_Forwarded);
|
||||
}
|
||||
|
||||
nsresult nsMsgComposeService::ShowCachedComposeWindow(mozIDOMWindowProxy *aComposeWindow, nsIXULWindow *aXULWindow, bool aShow)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs =
|
||||
mozilla::services::GetObserverService();
|
||||
NS_ENSURE_TRUE(obs, NS_ERROR_UNEXPECTED);
|
||||
|
||||
NS_ENSURE_TRUE(aComposeWindow, NS_ERROR_FAILURE);
|
||||
nsCOMPtr <nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aComposeWindow);
|
||||
|
||||
nsIDocShell *docShell = window->GetDocShell();
|
||||
|
||||
nsCOMPtr <nsIDocShellTreeItem> treeItem = do_QueryInterface(docShell, &rv);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
nsCOMPtr <nsIDocShellTreeOwner> treeOwner;
|
||||
rv = treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
if (treeOwner) {
|
||||
// the window need to be sticky before we hide it.
|
||||
nsCOMPtr<nsIContentViewer> contentViewer;
|
||||
rv = docShell->GetContentViewer(getter_AddRefs(contentViewer));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
rv = contentViewer->SetSticky(!aShow);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
// disable (enable) the cached window
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow;
|
||||
baseWindow = do_QueryInterface(treeOwner, &rv);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
baseWindow->SetEnabled(aShow);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
nsCOMPtr<nsIWindowMediator> windowMediator =
|
||||
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
// if showing, reinstate the window with the mediator
|
||||
if (aShow) {
|
||||
rv = windowMediator->RegisterWindow(aXULWindow);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
obs->NotifyObservers(aXULWindow, "xul-window-registered", nullptr);
|
||||
}
|
||||
|
||||
// hide (show) the cached window
|
||||
rv = baseWindow->SetVisibility(aShow);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
// if hiding, remove the window from the mediator,
|
||||
// so that it will be removed from the task list
|
||||
if (!aShow) {
|
||||
rv = windowMediator->UnregisterWindow(aXULWindow);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
obs->NotifyObservers(aXULWindow, "xul-window-destroyed", nullptr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsMsgComposeService::AddGlobalHtmlDomains()
|
||||
{
|
||||
|
||||
|
|
|
@ -17,32 +17,8 @@
|
|||
#include "nsICommandLineHandler.h"
|
||||
#define ICOMMANDLINEHANDLER nsICommandLineHandler
|
||||
|
||||
class nsMsgCachedWindowInfo
|
||||
{
|
||||
public:
|
||||
void Initialize(mozIDOMWindowProxy *aWindow, nsIXULWindow *aXULWindow, nsIMsgComposeRecyclingListener *aListener, bool aHtmlCompose)
|
||||
{
|
||||
window = aWindow;
|
||||
xulWindow = aXULWindow;
|
||||
listener = aListener;
|
||||
htmlCompose = aHtmlCompose;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
window = nullptr;
|
||||
listener = nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIDOMWindowProxy> window;
|
||||
nsCOMPtr<nsIXULWindow> xulWindow;
|
||||
nsCOMPtr<nsIMsgComposeRecyclingListener> listener;
|
||||
bool htmlCompose;
|
||||
};
|
||||
|
||||
class nsMsgComposeService :
|
||||
public nsIMsgComposeService,
|
||||
public nsIObserver,
|
||||
public ICOMMANDLINEHANDLER,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
|
@ -51,7 +27,6 @@ public:
|
|||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMSGCOMPOSESERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSICOMMANDLINEHANDLER
|
||||
|
||||
nsresult Init();
|
||||
|
@ -63,11 +38,6 @@ private:
|
|||
virtual ~nsMsgComposeService();
|
||||
bool mLogComposePerformance;
|
||||
|
||||
int32_t mMaxRecycledWindows;
|
||||
nsMsgCachedWindowInfo *mCachedWindows;
|
||||
|
||||
void CloseHiddenCachedWindow(mozIDOMWindowProxy *domWindow);
|
||||
|
||||
nsresult LoadDraftOrTemplate(const nsACString& aMsgURI, nsMimeOutputType aOutType,
|
||||
nsIMsgIdentity * aIdentity, const char * aOriginalMsgURI,
|
||||
nsIMsgDBHdr * aOrigMsgHdr, bool aForwardInline,
|
||||
|
@ -84,8 +54,6 @@ private:
|
|||
bool overrideComposeFormat,
|
||||
nsIMsgWindow *aMsgWindow);
|
||||
|
||||
nsresult ShowCachedComposeWindow(mozIDOMWindowProxy *aComposeWindow, nsIXULWindow *aXULWindow, bool aShow);
|
||||
|
||||
// hash table mapping dom windows to nsIMsgCompose objects
|
||||
nsInterfaceHashtable<nsISupportsHashKey, nsIWeakReference> mOpenComposeWindows;
|
||||
|
||||
|
|
|
@ -71,8 +71,7 @@ function onComposerReOpen()
|
|||
|
||||
addEventListener("load", smimeComposeOnLoad, false);
|
||||
|
||||
// this function gets called multiple times,
|
||||
// but only on first open, not on composer recycling
|
||||
// this function gets called multiple times
|
||||
function smimeComposeOnLoad()
|
||||
{
|
||||
removeEventListener("load", smimeComposeOnLoad, false);
|
||||
|
|
|
@ -732,8 +732,6 @@ pref("mailnews.ui.select_addresses_results.version", 1);
|
|||
// to hide the non default columns in the advanced directory search dialog
|
||||
// see abCommon.js and ABSearchDialog.js
|
||||
pref("mailnews.ui.advanced_directory_search_results.version", 1);
|
||||
//If set to a number greater than 0, msg compose windows will be recycled in order to open them quickly
|
||||
pref("mail.compose.max_recycled_windows", 1);
|
||||
|
||||
// from/recipient columns will be replaced with correspondents column
|
||||
pref("mailnews.ui.upgrade.correspondents", true);
|
||||
|
|
|
@ -143,87 +143,6 @@ function enableEditableFields()
|
|||
|
||||
}
|
||||
|
||||
var gComposeRecyclingListener = {
|
||||
onClose: function() {
|
||||
//Reset recipients and attachments
|
||||
awResetAllRows();
|
||||
RemoveAllAttachments();
|
||||
|
||||
// We need to clear the identity popup menu in case the user will change them. It will be rebuilded later in ComposeStartup
|
||||
ClearIdentityListPopup(document.getElementById("msgIdentityPopup"));
|
||||
|
||||
// Stop listening to changes in the spell check dictionary.
|
||||
document.removeEventListener("spellcheck-changed", updateDocumentLanguage);
|
||||
|
||||
// Stop InlineSpellCheckerUI so personal dictionary is saved.
|
||||
// We need to do this before disabling the editor.
|
||||
EnableInlineSpellCheck(false);
|
||||
// clear any suggestions in the context menu
|
||||
InlineSpellCheckerUI.clearSuggestionsFromMenu();
|
||||
InlineSpellCheckerUI.clearDictionaryListFromMenu();
|
||||
|
||||
//Clear the subject
|
||||
GetMsgSubjectElement().value = "";
|
||||
SetComposeWindowTitle();
|
||||
|
||||
SetContentAndBodyAsUnmodified();
|
||||
disableEditableFields();
|
||||
ReleaseGlobalVariables();
|
||||
|
||||
// Clear the focus
|
||||
awGetInputElement(1).removeAttribute('focused');
|
||||
|
||||
//Reset Boxes size
|
||||
document.getElementById("compose-toolbox").removeAttribute("height");
|
||||
document.getElementById("appcontent").removeAttribute("height");
|
||||
document.getElementById("addresses-box").removeAttribute("width");
|
||||
document.getElementById("attachments-box").removeAttribute("width");
|
||||
|
||||
//Reset menu options
|
||||
document.getElementById("format_auto").setAttribute("checked", "true");
|
||||
|
||||
//Reset toolbars that could be hidden
|
||||
if (gHideMenus) {
|
||||
document.getElementById("formatMenu").hidden = false;
|
||||
document.getElementById("insertMenu").hidden = false;
|
||||
var showFormat = document.getElementById("menu_showFormatToolbar")
|
||||
showFormat.hidden = false;
|
||||
if (showFormat.getAttribute("checked") == "true")
|
||||
document.getElementById("FormatToolbar").hidden = false;
|
||||
}
|
||||
|
||||
//Reset the Customize Toolbars panel/sheet if open.
|
||||
if (getMailToolbox().customizing && gCustomizeSheet)
|
||||
document.getElementById("customizeToolbarSheetIFrame")
|
||||
.contentWindow.finishToolbarCustomization();
|
||||
|
||||
//Reset editor
|
||||
EditorResetFontAndColorAttributes();
|
||||
EditorCleanup();
|
||||
|
||||
//Release the nsIMsgComposeParams object
|
||||
if (window.arguments && window.arguments[0])
|
||||
window.arguments[0] = null;
|
||||
|
||||
var event = document.createEvent('Events');
|
||||
event.initEvent('compose-window-close', false, true);
|
||||
document.getElementById("msgcomposeWindow").dispatchEvent(event);
|
||||
if (gAutoSaveTimeout)
|
||||
clearTimeout(gAutoSaveTimeout);
|
||||
},
|
||||
|
||||
onReopen: function(params) {
|
||||
// Reset focus to avoid undesirable visual effect when reopening the window
|
||||
|
||||
InitializeGlobalVariables();
|
||||
ComposeStartup(true, params);
|
||||
|
||||
var event = document.createEvent('Events');
|
||||
event.initEvent('compose-window-reopen', false, true);
|
||||
document.getElementById("msgcomposeWindow").dispatchEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
var stateListener = {
|
||||
NotifyComposeFieldsReady: function() {
|
||||
ComposeFieldsReady();
|
||||
|
@ -251,7 +170,7 @@ var stateListener = {
|
|||
if (gMsgCompose)
|
||||
gMsgCompose.onSendNotPerformed(null, Components.results.NS_ERROR_ABORT);
|
||||
|
||||
MsgComposeCloseWindow(true);
|
||||
MsgComposeCloseWindow();
|
||||
}
|
||||
}
|
||||
// else if we failed to save, and we're autosaving, need to re-mark the editor
|
||||
|
@ -734,7 +653,7 @@ function DoCommandClose()
|
|||
gMsgCompose.onSendNotPerformed(null, Components.results.NS_ERROR_ABORT);
|
||||
|
||||
// note: if we're not caching this window, this destroys it for us
|
||||
MsgComposeCloseWindow(true);
|
||||
MsgComposeCloseWindow();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -930,7 +849,7 @@ function handleMailtoArgs(mailtoUrl)
|
|||
return null;
|
||||
}
|
||||
|
||||
function ComposeStartup(recycled, aParams)
|
||||
function ComposeStartup(aParams)
|
||||
{
|
||||
var params = null; // New way to pass parameters to the compose window as a nsIMsgComposeParameters object
|
||||
var args = null; // old way, parameters are passed as a string
|
||||
|
@ -1055,12 +974,6 @@ function ComposeStartup(recycled, aParams)
|
|||
editorElement.docShell);
|
||||
if (gMsgCompose)
|
||||
{
|
||||
// set the close listener
|
||||
gMsgCompose.recyclingListener = gComposeRecyclingListener;
|
||||
|
||||
//Lets the compose object knows that we are dealing with a recycled window
|
||||
gMsgCompose.recycledWindow = recycled;
|
||||
|
||||
if (!editorElement)
|
||||
{
|
||||
dump("Failed to get editor element!\n");
|
||||
|
@ -1076,32 +989,28 @@ function ComposeStartup(recycled, aParams)
|
|||
document.getElementById("menu_inlineSpellCheck")
|
||||
.setAttribute("checked", getPref("mail.spellcheck.inline"));
|
||||
|
||||
// If recycle, editor is already created
|
||||
if (!recycled)
|
||||
try {
|
||||
var editortype = gMsgCompose.composeHTML ? "htmlmail" : "textmail";
|
||||
editorElement.makeEditable(editortype, true);
|
||||
} catch (e) { dump(" FAILED TO START EDITOR: "+e+"\n"); }
|
||||
|
||||
// setEditorType MUST be call before setContentWindow
|
||||
if (gMsgCompose.composeHTML)
|
||||
{
|
||||
try {
|
||||
var editortype = gMsgCompose.composeHTML ? "htmlmail" : "textmail";
|
||||
editorElement.makeEditable(editortype, true);
|
||||
} catch (e) { dump(" FAILED TO START EDITOR: "+e+"\n"); }
|
||||
|
||||
// setEditorType MUST be call before setContentWindow
|
||||
if (gMsgCompose.composeHTML)
|
||||
{
|
||||
initLocalFontFaceMenu(document.getElementById("FontFacePopup"));
|
||||
}
|
||||
else
|
||||
{
|
||||
//Remove HTML toolbar, format and insert menus as we are editing in plain text mode
|
||||
document.getElementById("outputFormatMenu").setAttribute("hidden", true);
|
||||
document.getElementById("FormatToolbar").setAttribute("hidden", true);
|
||||
document.getElementById("formatMenu").setAttribute("hidden", true);
|
||||
document.getElementById("insertMenu").setAttribute("hidden", true);
|
||||
document.getElementById("menu_showFormatToolbar").setAttribute("hidden", true);
|
||||
}
|
||||
|
||||
// Do setup common to Message Composer and Web Composer
|
||||
EditorSharedStartup();
|
||||
initLocalFontFaceMenu(document.getElementById("FontFacePopup"));
|
||||
}
|
||||
else
|
||||
{
|
||||
//Remove HTML toolbar, format and insert menus as we are editing in plain text mode
|
||||
document.getElementById("outputFormatMenu").setAttribute("hidden", true);
|
||||
document.getElementById("FormatToolbar").setAttribute("hidden", true);
|
||||
document.getElementById("formatMenu").setAttribute("hidden", true);
|
||||
document.getElementById("insertMenu").setAttribute("hidden", true);
|
||||
document.getElementById("menu_showFormatToolbar").setAttribute("hidden", true);
|
||||
}
|
||||
|
||||
// Do setup common to Message Composer and Web Composer
|
||||
EditorSharedStartup();
|
||||
|
||||
var msgCompFields = gMsgCompose.compFields;
|
||||
if (msgCompFields)
|
||||
|
@ -1138,35 +1047,20 @@ function ComposeStartup(recycled, aParams)
|
|||
|
||||
gMsgCompose.RegisterStateListener(stateListener);
|
||||
|
||||
if (recycled)
|
||||
{
|
||||
InitEditor(GetCurrentEditor());
|
||||
// Add an observer to be called when document is done loading,
|
||||
// which creates the editor
|
||||
try {
|
||||
GetCurrentCommandManager().
|
||||
addCommandObserver(gMsgEditorCreationObserver, "obs_documentCreated");
|
||||
|
||||
if (gMsgCompose.composeHTML)
|
||||
{
|
||||
// Force color picker on toolbar to show document colors
|
||||
onFontColorChange();
|
||||
onBackgroundColorChange();
|
||||
// XXX todo: reset paragraph select to "Body Text"
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add an observer to be called when document is done loading,
|
||||
// which creates the editor
|
||||
try {
|
||||
GetCurrentCommandManager().
|
||||
addCommandObserver(gMsgEditorCreationObserver, "obs_documentCreated");
|
||||
|
||||
// Load empty page to create the editor
|
||||
editorElement.webNavigation.loadURI("about:blank", // uri string
|
||||
0, // load flags
|
||||
null, // referrer
|
||||
null, // post-data stream
|
||||
null);
|
||||
} catch (e) {
|
||||
dump(" Failed to startup editor: "+e+"\n");
|
||||
}
|
||||
// Load empty page to create the editor
|
||||
editorElement.webNavigation.loadURI("about:blank", // uri string
|
||||
0, // load flags
|
||||
null, // referrer
|
||||
null, // post-data stream
|
||||
null);
|
||||
} catch (e) {
|
||||
dump(" Failed to startup editor: "+e+"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1228,7 +1122,7 @@ function WizCallback(state)
|
|||
else
|
||||
{
|
||||
// The account wizard is still closing so we can't close just yet
|
||||
setTimeout(MsgComposeCloseWindow, 0, false); // Don't recycle a bogus window
|
||||
setTimeout(MsgComposeCloseWindow, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1269,7 +1163,7 @@ function ComposeLoad()
|
|||
var errorMsg = sComposeMsgsBundle.getString("initErrorDlgMessage");
|
||||
Services.prompt.alert(window, errorTitle, errorMsg);
|
||||
|
||||
MsgComposeCloseWindow(false); // Don't try to recycle a bogus window
|
||||
MsgComposeCloseWindow();
|
||||
return;
|
||||
}
|
||||
if (gLogComposePerformance)
|
||||
|
@ -2162,10 +2056,10 @@ function SetContentAndBodyAsUnmodified()
|
|||
gContentChanged = false;
|
||||
}
|
||||
|
||||
function MsgComposeCloseWindow(recycleIt)
|
||||
function MsgComposeCloseWindow()
|
||||
{
|
||||
if (gMsgCompose)
|
||||
gMsgCompose.CloseWindow(recycleIt);
|
||||
gMsgCompose.CloseWindow();
|
||||
else
|
||||
window.close();
|
||||
}
|
||||
|
|
|
@ -283,7 +283,6 @@ nsThunderbirdProfileMigrator::PrefTransform gTransforms[] = {
|
|||
MAKESAMETYPEPREFTRANSFORM("mail.compose.autosaveinterval", Int),
|
||||
MAKESAMETYPEPREFTRANSFORM("mail.compose.dont_attach_source_of_local_network_links", Bool),
|
||||
MAKESAMETYPEPREFTRANSFORM("mail.compose.dontWarnMail2Newsgroup", Bool),
|
||||
MAKESAMETYPEPREFTRANSFORM("mail.compose.max_recycled_windows", Int),
|
||||
MAKESAMETYPEPREFTRANSFORM("mail.compose.other.header", String),
|
||||
MAKESAMETYPEPREFTRANSFORM("mail.compose.wrap_to_window_width", Bool),
|
||||
MAKESAMETYPEPREFTRANSFORM("mail.content_disposition_type", Int),
|
||||
|
|
Загрузка…
Ссылка в новой задаче