Bug 23394 Quote just the selected portion of a message during Reply. p=Jeff Beckley <beckley@qualcomm.com>,r=smontagu,sr=dmose

This commit is contained in:
bugzilla%standard8.plus.com 2008-06-11 07:53:15 +00:00
Родитель 533ffa92cb
Коммит d3d18d81e2
9 изменённых файлов: 195 добавлений и 9 удалений

Просмотреть файл

@ -74,7 +74,7 @@ interface nsIMsgCompFormat {
};
[scriptable, uuid(f59cf090-98d4-43fa-bc53-db4922c8370e)]
[scriptable, uuid(930895f2-d610-43f4-9e3c-25e1d1fe4143)]
interface nsIMsgComposeParams : nsISupports {
attribute MSG_ComposeType type;
attribute MSG_ComposeFormat format;
@ -87,4 +87,11 @@ interface nsIMsgComposeParams : nsISupports {
attribute nsIMsgSendListener sendListener;
attribute string smtpPassword;
attribute nsIMsgDBHdr origMsgHdr;
/**
* HTML-formatted content to quote in the body of the message.
* Set this to get different content than what would normally
* appear in the body, e.g. the original message body in a reply.
*/
attribute AUTF8String htmlToQuote;
};

Просмотреть файл

@ -59,6 +59,7 @@ REQUIRES = xpcom \
mime \
pref \
intl \
lwbrk \
uconv \
locale \
unicharutil \

Просмотреть файл

@ -26,6 +26,7 @@
* Pierre Phaneuf <pp@ludusdesign.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* Olivier Parniere BT Global Services / Etat francais Ministere de la Defense
* Jeff Beckley <beckley@qualcomm.com>
*
* 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"),
@ -111,6 +112,7 @@
#include "nsIMsgProgress.h"
#include "nsMsgFolderFlags.h"
#include "nsIMsgDatabase.h"
#include "nsStringStream.h"
#include "nsIMutableArray.h"
#include "nsArrayUtils.h"
@ -850,6 +852,8 @@ nsMsgCompose::Initialize(nsIDOMWindowInternal *aWindow, nsIMsgComposeParams *par
params->GetSmtpPassword(getter_Copies(smtpPassword));
mSmtpPassword = smtpPassword;
params->GetHtmlToQuote(mHtmlToQuote);
if (aWindow)
{
// register the compose object with the compose service
@ -2087,7 +2091,8 @@ QuotingOutputStreamListener::QuotingOutputStreamListener(const char * originalMs
nsIMsgIdentity *identity,
const char *charset,
PRBool charetOverride,
PRBool quoteOriginal)
PRBool quoteOriginal,
const nsACString& htmlToQuote)
{
nsresult rv;
mQuoteHeaders = quoteHeaders;
@ -2096,8 +2101,9 @@ QuotingOutputStreamListener::QuotingOutputStreamListener(const char * originalMs
mUnicodeBufferCharacterLength = 0;
mUnicodeConversionBuffer = nsnull;
mQuoteOriginal = quoteOriginal;
mHtmlToQuote = htmlToQuote;
if (! mHeadersOnly)
if (!mHeadersOnly || !mHtmlToQuote.IsEmpty())
{
nsString replyHeaderOriginalmessage;
// For the built message body...
@ -2318,11 +2324,24 @@ NS_IMETHODIMP QuotingOutputStreamListener::OnStartRequest(nsIRequest *request, n
return NS_OK;
}
NS_IMETHODIMP QuotingOutputStreamListener::OnStopRequest(nsIRequest *request, nsISupports * /* ctxt */, nsresult status)
NS_IMETHODIMP QuotingOutputStreamListener::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult status)
{
nsresult rv = NS_OK;
nsAutoString aCharset;
if (!mHtmlToQuote.IsEmpty())
{
// If we had a selection in the original message to quote, we can add
// it now that we are done ignoring the original body of the message
nsCOMPtr<nsIInputStream> stream;
rv = NS_NewCStringInputStream(getter_AddRefs(stream), mHtmlToQuote);
NS_ENSURE_SUCCESS(rv, rv);
mHeadersOnly = PR_FALSE;
rv = OnDataAvailable(request, ctxt, stream, 0, mHtmlToQuote.Length());
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIMsgCompose> compose = do_QueryReferent(mWeakComposeObj);
if (compose)
{
@ -2833,8 +2852,9 @@ nsMsgCompose::QuoteMessage(const char *msgURI)
// Create the consumer output stream.. this will receive all the HTML from libmime
mQuoteStreamListener =
new QuotingOutputStreamListener(msgURI, msgHdr, PR_FALSE, PR_FALSE, m_identity,
m_compFields->GetCharacterSet(), mCharsetOverride, PR_FALSE);
new QuotingOutputStreamListener(msgURI, msgHdr, PR_FALSE, !mHtmlToQuote.IsEmpty(), m_identity,
m_compFields->GetCharacterSet(), mCharsetOverride, PR_FALSE,
mHtmlToQuote);
if (!mQuoteStreamListener)
{
@ -2876,8 +2896,9 @@ nsMsgCompose::QuoteOriginalMessage(const char *originalMsgURI, PRInt32 what) //
// Create the consumer output stream.. this will receive all the HTML from libmime
mQuoteStreamListener =
new QuotingOutputStreamListener(originalMsgURI, originalMsgHdr, what != 1, !bAutoQuote, m_identity,
mQuoteCharset.get(), mCharsetOverride, PR_TRUE);
new QuotingOutputStreamListener(originalMsgURI, originalMsgHdr, what != 1,
!bAutoQuote || !mHtmlToQuote.IsEmpty(), m_identity,
mQuoteCharset.get(), mCharsetOverride, PR_TRUE, mHtmlToQuote);
if (!mQuoteStreamListener)
{

Просмотреть файл

@ -160,6 +160,7 @@ private:
nsCOMPtr <nsIMsgDBHdr> mOrigMsgHdr;
nsCString mSmtpPassword;
nsCString mHtmlToQuote;
nsTObserverArray<nsCOMPtr<nsIMsgComposeStateListener> > mStateListeners;
nsTObserverArray<nsCOMPtr<nsIMsgSendListener> > mExternalSendListeners;
@ -184,7 +185,8 @@ public:
nsIMsgIdentity *identity,
const char *charset,
PRBool charetOverride,
PRBool quoteOriginal);
PRBool quoteOriginal,
const nsACString& htmlToQuote);
virtual ~QuotingOutputStreamListener(void);
NS_DECL_ISUPPORTS
@ -211,6 +213,7 @@ private:
PRInt32 mUnicodeBufferCharacterLength;
PRUnichar* mUnicodeConversionBuffer;
PRBool mQuoteOriginal;
nsCString mHtmlToQuote;
};
////////////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -121,6 +121,18 @@ NS_IMETHODIMP nsMsgComposeParams::GetOrigMsgHdr(nsIMsgDBHdr * *aMsgHdr)
return NS_OK;
}
/* attribute ACString htmlToQuote; */
NS_IMETHODIMP nsMsgComposeParams::GetHtmlToQuote(nsACString& aHtmlToQuote)
{
aHtmlToQuote = mHtmlToQuote;
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::SetHtmlToQuote(const nsACString& aHtmlToQuote)
{
mHtmlToQuote = aHtmlToQuote;
return NS_OK;
}
/* attribute nsIMsgCompFields composeFields; */
NS_IMETHODIMP nsMsgComposeParams::GetComposeFields(nsIMsgCompFields * *aComposeFields)
{

Просмотреть файл

@ -57,4 +57,5 @@ public:
nsCOMPtr<nsIMsgSendListener> mSendListener;
nsCString mSMTPPassword;
nsCOMPtr<nsIMsgDBHdr> mOrigMsgHdr;
nsCString mHtmlToQuote;
};

Просмотреть файл

@ -23,6 +23,7 @@
* Jean-Francois Ducarroz <ducarroz@netscape.com>
* Pierre Phaneuf <pp@ludusdesign.com>
* Seth Spitzer <sspitzer@netscape.com>
* Jeff Beckley <beckley@qualcomm.com>
*
* 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"),
@ -62,6 +63,7 @@
#include "nsIDocShell.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMDocument.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMElement.h"
#include "nsIXULWindow.h"
#include "nsIWindowMediator.h"
@ -81,6 +83,12 @@
#include "nsIMsgMailNewsUrl.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIMsgDatabase.h"
#include "nsIDocumentEncoder.h"
#include "nsContentCID.h"
#include "nsISelection.h"
#include "nsUTF8Utils.h"
#include "nsILineBreaker.h"
#include "nsLWBrkCIID.h"
#ifdef MSGCOMP_TRACE_PERFORMANCE
#include "prlog.h"
@ -115,6 +123,10 @@ static PRBool _just_to_be_sure_we_create_only_one_compose_service_ = PR_FALSE;
#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"
#define MAIL_ROOT_PREF "mail."
#define MAILNEWS_ROOT_PREF "mailnews."
#define HTMLDOMAINUPDATE_VERSION_PREF_NAME "global_html_domains.version"
@ -413,6 +425,114 @@ nsMsgComposeService::DetermineComposeHTML(nsIMsgIdentity *aIdentity, MSG_Compose
return NS_OK;
}
nsresult
nsMsgComposeService::GetOrigWindowSelection(MSG_ComposeType type, nsIMsgWindow *aMsgWindow, nsACString& aSelHTML)
{
nsresult rv;
// Good hygiene
aSelHTML.Truncate();
// Get the pref to see if we even should do reply quoting selection
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
PRBool replyQuotingSelection;
rv = prefs->GetBoolPref(PREF_MAILNEWS_REPLY_QUOTING_SELECTION, &replyQuotingSelection);
NS_ENSURE_SUCCESS(rv, rv);
if (!replyQuotingSelection)
return NS_ERROR_ABORT;
// Now delve down in to the message to get the HTML representation of the selection
nsCOMPtr<nsIDocShell> rootDocShell;
rv = aMsgWindow->GetRootDocShell(getter_AddRefs(rootDocShell));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocShellTreeNode> rootDocShellAsNode(do_QueryInterface(rootDocShell, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocShellTreeItem> childAsItem;
rv = rootDocShellAsNode->FindChildWithName(NS_LITERAL_STRING("messagepane").get(),
PR_TRUE, PR_FALSE, nsnull, nsnull, getter_AddRefs(childAsItem));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(childAsItem, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(childAsItem, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISelection> sel;
rv = domWindow->GetSelection(getter_AddRefs(sel));
NS_ENSURE_SUCCESS(rv, rv);
PRBool requireMultipleWords = PR_TRUE;
nsCAutoString charsOnlyIf;
prefs->GetBoolPref(PREF_MAILNEWS_REPLY_QUOTING_SELECTION_MULTI_WORD, &requireMultipleWords);
prefs->GetCharPref(PREF_MAILNEWS_REPLY_QUOTING_SELECTION_ONLY_IF, getter_Copies(charsOnlyIf));
if (requireMultipleWords || !charsOnlyIf.IsEmpty())
{
nsAutoString selPlain;
rv = sel->ToString(getter_Copies(selPlain));
NS_ENSURE_SUCCESS(rv, rv);
// If "mailnews.reply_quoting_selection.multi_word" is on, then there must be at least
// two words selected in order to quote just the selected text
if (requireMultipleWords)
{
nsCOMPtr<nsILineBreaker> lineBreaker = do_GetService(NS_LBRK_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
{
const nsPromiseFlatString& tString = PromiseFlatString(selPlain);
const PRUint32 length = tString.Length();
const PRUnichar* unicodeStr = tString.get();
PRInt32 endWordPos = lineBreaker->Next(unicodeStr, length, 0);
// If there's not even one word, then there's not multiple words
if (endWordPos == NS_LINEBREAKER_NEED_MORE_TEXT)
return NS_ERROR_ABORT;
// If after the first word is only space, then there's not multiple words
const PRUnichar* end;
for (end = unicodeStr + endWordPos; NS_IsSpace(*end); end++)
;
if (!*end)
return NS_ERROR_ABORT;
}
}
if (!charsOnlyIf.IsEmpty())
{
if (selPlain.FindCharInSet(NS_ConvertUTF8toUTF16(charsOnlyIf)) < 0)
return NS_ERROR_ABORT;
}
}
nsCOMPtr<nsIContentViewer> contentViewer;
rv = docShell->GetContentViewer(getter_AddRefs(contentViewer));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMDocument> domDocument;
rv = contentViewer->GetDOMDocument(getter_AddRefs(domDocument));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocumentEncoder> docEncoder(do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = docEncoder->Init(domDocument, NS_LITERAL_STRING("text/html"), 0);
NS_ENSURE_SUCCESS(rv, rv);
rv = docEncoder->SetSelection(sel);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString selHTML;
rv = docEncoder->EncodeToString(selHTML);
NS_ENSURE_SUCCESS(rv, rv);
aSelHTML = NS_ConvertUTF16toUTF8(selHTML);
return rv;
}
NS_IMETHODIMP
nsMsgComposeService::OpenComposeWindow(const char *msgComposeWindowURL, const char *originalMsgURI,
MSG_ComposeType type, MSG_ComposeFormat format, nsIMsgIdentity * aIdentity, nsIMsgWindow *aMsgWindow)
@ -448,6 +568,19 @@ nsMsgComposeService::OpenComposeWindow(const char *msgComposeWindowURL, const ch
pMsgComposeParams->SetFormat(format);
pMsgComposeParams->SetIdentity(identity);
// When doing a reply (except with a template) see if there's a selection that we should quote
if (type == nsIMsgCompType::Reply ||
type == nsIMsgCompType::ReplyAll ||
type == nsIMsgCompType::ReplyToSender ||
type == nsIMsgCompType::ReplyToGroup ||
type == nsIMsgCompType::ReplyToSenderAndGroup ||
type == nsIMsgCompType::ReplyToList)
{
nsCAutoString selHTML;
if (NS_SUCCEEDED(GetOrigWindowSelection(type, aMsgWindow, selHTML)))
pMsgComposeParams->SetHtmlToQuote(selHTML);
}
if (originalMsgURI && *originalMsgURI)
{
if (type == nsIMsgCompType::NewsPost)

Просмотреть файл

@ -109,6 +109,10 @@ private:
// hash table mapping dom windows to nsIMsgCompose objects
nsInterfaceHashtable<nsISupportsHashKey, nsIWeakReference> mOpenComposeWindows;
// When doing a reply and the settings are enabled, get the HTML of the selected text
// in the original message window so that it can be quoted instead of the entire message.
nsresult GetOrigWindowSelection(MSG_ComposeType type, nsIMsgWindow *aMsgWindow, nsACString& aSelHTML);
#ifdef MSGCOMP_TRACE_PERFORMANCE
PRIntervalTime mStartTime;
PRIntervalTime mPreviousTime;

Просмотреть файл

@ -279,6 +279,10 @@ pref("mailnews.reply_header_originalmessage", "chrome://messenger/locale/messe
pref("mailnews.reply_to_self_check_all_ident", false);
pref("mailnews.reply_quoting_selection", true);
pref("mailnews.reply_quoting_selection.only_if_chars", "");
pref("mailnews.reply_quoting_selection.multi_word", true);
pref("mail.purge_threshhold", 100);
pref("mail.prompt_purge_threshhold", false);
pref("mail.purge.ask", true);