зеркало из https://github.com/mozilla/gecko-dev.git
2238 строки
62 KiB
C++
2238 строки
62 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1996 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
|
|
|
|
// CMailComposeWindow.cp
|
|
|
|
#include "CMailComposeWindow.h"
|
|
#include "rosetta.h"
|
|
|
|
#include "CSimpleTextView.h"
|
|
#include "CEditView.h"
|
|
#include "CThreadWindow.h"
|
|
#include "CBrowserWindow.h"
|
|
#include "CMessageWindow.h"
|
|
|
|
//#include <LTextModel.h>
|
|
//#include <LTextSelection.h>
|
|
//#include <LTextEngine.h>
|
|
#include <LUndoer.h>
|
|
#include <UDrawingState.h>
|
|
#include <LPane.h>
|
|
#include <LView.h>
|
|
#include <LWindow.h>
|
|
#include <LArrayIterator.h>
|
|
#include <LString.h>
|
|
#include <UTextTraits.h>
|
|
#include <UMemoryMgr.h>
|
|
#include <UReanimator.h>
|
|
#include <LDragAndDrop.h>
|
|
#include <LSharable.h>
|
|
|
|
#include <PP_KeyCodes.h>
|
|
#include <LGAIconSuiteControl.h>
|
|
|
|
#include "UOffline.h"
|
|
#include "macutil.h"
|
|
#include "resgui.h"
|
|
#include "uapp.h"
|
|
#include "MailNewsgroupWindow_Defines.h"
|
|
#include "CComposeSession.h"
|
|
#include "UStdDialogs.h"
|
|
#include "URobustCreateWindow.h"
|
|
#include "LGACheckbox.h"
|
|
#include "edt.h"
|
|
#include "macgui.h" // MakeLOColor
|
|
#include "xpgetstr.h" // for XP_GetString
|
|
#include "secnav.h"
|
|
#define WANT_ENUM_STRING_IDS
|
|
#include "allxpstr.h"
|
|
#undef WANT_ENUM_STRING_IDS
|
|
#include "CTabControl.h"
|
|
#include "meditor.h" // HandleModalDialog
|
|
#include "UGraphicGizmos.h"
|
|
#include "CPatternButtonPopup.h"
|
|
#include "CMailNewsContext.h"
|
|
#include "CLargeEditField.h"
|
|
#include "CPasteSnooper.h"
|
|
#include "UDeferredTask.h"
|
|
|
|
#include "MailNewsAddressBook.h"
|
|
#include "ABcom.h"
|
|
#ifdef MOZ_NEWADDR
|
|
#include "CAddressPickerWindow.h"
|
|
#endif
|
|
|
|
#define cmd_CheckSpelling 'ChSp'
|
|
|
|
const Uint32 cDefaultLineWrapLength = 78;
|
|
const ResIDT COMPOSEDLG_SAVE_BEFORE_QUIT = 10621;
|
|
const MessageT msg_NoSave = 3;
|
|
|
|
#include "msg_srch.h" // needed for priority
|
|
#define UPDATE_WINDOW_TITLE_ON_IDLE 1
|
|
|
|
|
|
#pragma mark -- libmsg callbacks --
|
|
|
|
#include "prefapi.h" // temporarily include this until MacFE prefs for ComposeHTML are added
|
|
|
|
//-----------------------------------
|
|
MSG_Pane* FE_CreateCompositionPane(
|
|
MWContext* old_context,
|
|
MSG_CompositionFields* fields,
|
|
const char* initialText,
|
|
MSG_EditorType editorType)
|
|
//-----------------------------------
|
|
{
|
|
MSG_Pane* result = nil;
|
|
CMailComposeWindow *win = nil;
|
|
try
|
|
{
|
|
CMailNewsContext::ThrowUnlessPrefsSet(MWContextMessageComposition);
|
|
XP_Bool useHtmlEditor;
|
|
PREF_GetBoolPref( "mail.html_compose", &useHtmlEditor );
|
|
// override if
|
|
if (MSG_HTML_EDITOR == editorType)
|
|
useHtmlEditor = TRUE;
|
|
else if (MSG_PLAINTEXT_EDITOR == editorType)
|
|
useHtmlEditor = FALSE;
|
|
else if (IsThisKeyDown(kCtlKey))
|
|
useHtmlEditor = !useHtmlEditor;
|
|
|
|
ResIDT id = useHtmlEditor ?
|
|
CMailComposeWindow::res_ID
|
|
: CMailComposeWindow::text_res_ID;
|
|
|
|
win = dynamic_cast<CMailComposeWindow*>(
|
|
URobustCreateWindow::CreateWindow(
|
|
id,
|
|
LCommander::GetTopCommander()));
|
|
if (win)
|
|
{
|
|
// Now here's a hidden meaning I bet you didn't know. Opening from the sent or
|
|
// drafts folder is indicated by the value editorType != MSG_DEFAULT!
|
|
Boolean openingAsDraft = editorType != MSG_DEFAULT;
|
|
result = win->CreateSession(old_context, fields, initialText, openingAsDraft);
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
if (win)
|
|
win->DoClose();
|
|
}
|
|
return result;
|
|
} // FE_CreateCompositionPane
|
|
|
|
void FE_UpdateCompToolbar(MSG_Pane* msgpane) // in
|
|
{
|
|
if (msgpane)
|
|
{
|
|
void *fedata = MSG_GetFEData(msgpane);
|
|
if (fedata)
|
|
{
|
|
CMailComposeWindow *window = (CMailComposeWindow *)fedata;
|
|
window->HandleUpdateCompToolbar();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FE_DestroyMailCompositionContext(MWContext* context)
|
|
{
|
|
MSG_Pane* msgpane;
|
|
msgpane = MSG_FindPane(context, MSG_COMPOSITIONPANE);
|
|
if (msgpane)
|
|
{
|
|
void *fedata = MSG_GetFEData(msgpane);
|
|
if (fedata)
|
|
{
|
|
CMailComposeWindow *window = (CMailComposeWindow *)fedata;
|
|
if (window->IsVisible())
|
|
{
|
|
if (window->GetComposeSession())
|
|
window->GetComposeSession()->MarkMSGPaneDestroyed();
|
|
// window->BroadcastMessage(msg_NSCAllConnectionsComplete, nil);
|
|
window->DoCloseLater();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FE_SecurityOptionsChanged( MWContext* context)
|
|
{
|
|
MSG_Pane* msgpane = MSG_FindPane(context, MSG_COMPOSITIONPANE);
|
|
if (msgpane)
|
|
{
|
|
void *fedata = MSG_GetFEData( msgpane );
|
|
if (fedata)
|
|
{
|
|
CMailComposeWindow *window = (CMailComposeWindow *)fedata;
|
|
USecurityIconHelpers::UpdateComposeButton( window );
|
|
CMailOptionTabContainer *optionTab= dynamic_cast <CMailOptionTabContainer*> (window->FindPaneByID('OpTC') );
|
|
if ( optionTab ) // if the option tab is visible update it
|
|
window-> ListenToMessage( msg_ActivatingOptionTab, optionTab );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
void UComposeUtilities::WordWrap(Handle& inText,
|
|
Uint32 inTextLength,
|
|
LHandleStream& outTextStream)
|
|
{
|
|
Int32 lineWrapLength = cDefaultLineWrapLength;
|
|
|
|
PREF_GetIntPref("mailnews.wraplength", &lineWrapLength);
|
|
|
|
try {
|
|
StHandleLocker lock(inText);
|
|
char *scanner = *inText,
|
|
*startOfLine = *inText,
|
|
*lastSpace = *inText,
|
|
*end = *inText + inTextLength;
|
|
while (startOfLine < end)
|
|
{
|
|
// if line starts with "> " skip to next line
|
|
if (*startOfLine == '>' && *(startOfLine + 1) == ' ')
|
|
{ // move to next line
|
|
while (scanner < end && *scanner != '\r')
|
|
++scanner;
|
|
// move past '\r'
|
|
++scanner;
|
|
// copy text into stream
|
|
outTextStream.WriteBlock(startOfLine, scanner - startOfLine);
|
|
// set startOfLine to scanner
|
|
startOfLine = scanner;
|
|
}
|
|
else
|
|
{
|
|
// find ' ' in text stream
|
|
while (scanner < end && *scanner != '\r' && *scanner != ' ')
|
|
++scanner;
|
|
// we spit out a line of text if a) we hit the end of the text,
|
|
// b) have enough text to fill a line, or c) hit a carriage return
|
|
if (scanner - startOfLine > lineWrapLength ||
|
|
scanner == end ||
|
|
*scanner == '\r')
|
|
{
|
|
if (*scanner == '\r' || scanner == end)
|
|
outTextStream.WriteBlock(startOfLine, scanner - startOfLine);
|
|
else
|
|
outTextStream.WriteBlock(startOfLine, lastSpace - startOfLine);
|
|
if (scanner < end)
|
|
{
|
|
outTextStream << (unsigned char) '\r';
|
|
if (*scanner == '\r')
|
|
startOfLine = scanner + 1;
|
|
else
|
|
startOfLine = lastSpace + 1;
|
|
}
|
|
else
|
|
startOfLine = scanner;
|
|
}
|
|
lastSpace = scanner;
|
|
++scanner;
|
|
}
|
|
}
|
|
} catch (...) {
|
|
}
|
|
}
|
|
|
|
MSG_HEADER_SET UComposeUtilities::GetMsgHeaderMaskFromAddressType(EAddressType inAddressType)
|
|
{
|
|
MSG_HEADER_SET result = 0;
|
|
switch (inAddressType)
|
|
{
|
|
case eToType:
|
|
result = MSG_TO_HEADER_MASK;
|
|
break;
|
|
case eCcType:
|
|
result = MSG_CC_HEADER_MASK;
|
|
break;
|
|
case eBccType:
|
|
result = MSG_BCC_HEADER_MASK;
|
|
break;
|
|
case eReplyType:
|
|
result = MSG_REPLY_TO_HEADER_MASK;
|
|
break;
|
|
case eNewsgroupType:
|
|
result = MSG_NEWSGROUPS_HEADER_MASK;
|
|
break;
|
|
case eFollowupType:
|
|
result = MSG_FOLLOWUP_TO_HEADER_MASK;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
MSG_PRIORITY UComposeUtilities::GetMsgPriorityFromMenuItem(Int32 inMenuItem)
|
|
{
|
|
// These are mapped to MSG_LowPriority, MSG_NormalPriority, MSG_HighPriority,
|
|
// and MSG_HighestPriority, respectively.
|
|
return (MSG_PRIORITY)(inMenuItem - 1 + MSG_LowestPriority);
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
|
|
//#define REGISTER_(letter,root) \
|
|
// RegisterClass_(letter##root::class_ID, \
|
|
// (ClassCreatorFunc)letter##root::Create##root##Stream);
|
|
|
|
#define REGISTER_(letter,root) \
|
|
RegisterClass_(letter##root);
|
|
|
|
#define REGISTERC(root) REGISTER_(C,root)
|
|
#define REGISTERL(root) REGISTER_(L,root)
|
|
|
|
//-----------------------------------
|
|
void UComposeUtilities::RegisterComposeClasses()
|
|
//-----------------------------------
|
|
{
|
|
REGISTERC(MailComposeWindow)
|
|
REGISTERC(MailEditView)
|
|
REGISTERC(MailComposeTabContainer)
|
|
REGISTERC(MailOptionTabContainer)
|
|
REGISTERC(MailAttachmentTabContainer)
|
|
REGISTERC(ComposeAddressTableView)
|
|
REGISTERC(ComposeTabSwitcher)
|
|
REGISTERC(MailAddressEditField)
|
|
#ifdef MOZ_NEWADDR
|
|
REGISTERC(AddressPickerWindow);
|
|
#endif
|
|
}
|
|
|
|
//-----------------------------------
|
|
CMailEditView::CMailEditView(LStream * inStream) : CEditView(inStream)
|
|
//-----------------------------------
|
|
{
|
|
mEditorDoneLoading = false;
|
|
mHasAutoQuoted = false;
|
|
mHasInsertSignature =false;
|
|
mCursorSet = false;
|
|
mComposeSession = nil;
|
|
mInitialText = nil;
|
|
mStartQuoteOffset = 0;
|
|
mEndQuoteOffset = 0;
|
|
}
|
|
|
|
//-----------------------------------
|
|
void CMailEditView::InstallBackgroundColor()
|
|
// Overridden to use a white background
|
|
//-----------------------------------
|
|
{
|
|
memset(&mBackgroundColor, 0xFF, sizeof(mBackgroundColor)); // white is default
|
|
}
|
|
|
|
void CMailEditView::GetDefaultBackgroundColor(LO_Color* outColor) const
|
|
{
|
|
// if the editor is not done initializing then set the color to mBackgroundColor (white)
|
|
// we do this to keep the window from changing colors (potentially)
|
|
if ( !IsDoneLoading() )
|
|
*outColor = UGraphics::MakeLOColor(mBackgroundColor);
|
|
// else
|
|
// if the editor has completed initialization then we don't want to change outColor
|
|
}
|
|
|
|
//-----------------------------------
|
|
void CMailEditView::SetInitialText( const char *textp )
|
|
//-----------------------------------
|
|
{
|
|
if ( mInitialText )
|
|
{
|
|
XP_FREE( mInitialText );
|
|
mInitialText = nil;
|
|
}
|
|
|
|
if ( textp )
|
|
{
|
|
mInitialText = XP_STRDUP( textp );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------
|
|
void CMailEditView::InitMailCompose()
|
|
//-----------------------------------
|
|
{
|
|
MWContext *context;
|
|
if (GetContext())
|
|
context = *(GetContext());
|
|
else
|
|
return;
|
|
|
|
XP_Bool composeDirty = EDT_DirtyFlag(context);
|
|
|
|
MSG_Pane *msgpane = MSG_FindPane( context, MSG_COMPOSITIONPANE );
|
|
|
|
if (!mEditorDoneLoading)
|
|
{
|
|
mEditorDoneLoading = true;
|
|
MSG_SetHTMLMarkup( msgpane, true );
|
|
|
|
// do InstallBackgroundColor again to set the editor background color
|
|
// we need to do this one last time to set the backend editor data to
|
|
// have the correct (white) background color
|
|
InstallBackgroundColor();
|
|
// if mInitalText is nonNull it means that the message is a draft/Edit Message
|
|
// and there fore quoting should not be done.
|
|
if (mComposeSession->ShouldAutoQuote() && !mInitialText)
|
|
{
|
|
mHasAutoQuoted = true;
|
|
mStartQuoteOffset = EDT_GetInsertPointOffset( context );
|
|
EDT_EndOfDocument( context, false );
|
|
mComposeSession->QuoteMessage();
|
|
// Then eventually CComposeSession::QuoteInHTMLMessage will be called.
|
|
}
|
|
else
|
|
{
|
|
EDT_EndOfDocument( context, false );
|
|
mHasInsertSignature = true;
|
|
/* insert signature here!!!! and Drafts too*/
|
|
DisplayDefaultTextBody();
|
|
EDT_BeginOfDocument( context, false );
|
|
//mCursorSet = true;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
mEndQuoteOffset = EDT_GetInsertPointOffset( context );
|
|
if ( !mHasInsertSignature )
|
|
{
|
|
mHasInsertSignature = true;
|
|
EDT_EndOfDocument( context, false );
|
|
|
|
/* insert signature here!!!! and Drafts too*/
|
|
DisplayDefaultTextBody();
|
|
// EDT_BeginOfDocument( context, false );
|
|
// mCursorSet = true;
|
|
}
|
|
|
|
if ( !mCursorSet )
|
|
{
|
|
mCursorSet = true;
|
|
if( mHasAutoQuoted )
|
|
{
|
|
int32 eReplyOnTop = 1;
|
|
if ( PREF_NOERROR == PREF_GetIntPref("mailnews.reply_on_top", &eReplyOnTop) )
|
|
{
|
|
switch (eReplyOnTop)
|
|
{
|
|
case 0:
|
|
EDT_SetInsertPointToOffset( context, mEndQuoteOffset, 0 );
|
|
break;
|
|
case 1:
|
|
default:
|
|
EDT_SetInsertPointToOffset( context, mStartQuoteOffset, 0 );
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
EDT_SetInsertPointToOffset( context, mStartQuoteOffset,
|
|
mEndQuoteOffset - mStartQuoteOffset );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EDT_BeginOfDocument( context, false );
|
|
mCursorSet = true;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (!composeDirty)
|
|
EDT_SetDirtyFlag( context , false );
|
|
|
|
} // CMailEditView::InitMailCompose
|
|
|
|
|
|
// Taken from X11
|
|
void CMailEditView::InsertMessageCompositionText(const char* text,
|
|
XP_Bool leaveCursorBeginning, XP_Bool isHTML)
|
|
{
|
|
|
|
Boolean noTagsP = false;
|
|
MWContext *context;
|
|
if (GetContext())
|
|
context = *(GetContext());
|
|
else
|
|
return;
|
|
|
|
ED_BufferOffset ins = -1;
|
|
|
|
if ( leaveCursorBeginning ){
|
|
ins = EDT_GetInsertPointOffset( context );
|
|
}
|
|
|
|
if (isHTML) {
|
|
//
|
|
// NOTE: let's try to see if they really have any HTML tags
|
|
// in the text they've given us... [ poor man's parser ]
|
|
//
|
|
if (XP_STRCASESTR(text, "<HTML>") ||
|
|
XP_STRCASESTR(text, "</A>") ||
|
|
XP_STRCASESTR(text, "<PRE>") ||
|
|
XP_STRCASESTR(text, "<HR") ||
|
|
XP_STRCASESTR(text, "<IMG") ||
|
|
XP_STRCASESTR(text, "<TABLE")
|
|
) {
|
|
noTagsP = false;
|
|
}
|
|
else {
|
|
noTagsP = true;
|
|
}
|
|
|
|
EDT_PasteQuoteBegin( context, isHTML );
|
|
if (noTagsP)
|
|
EDT_PasteQuote( context, "<PRE>\n");
|
|
|
|
EDT_PasteQuote( context, (char *) text );
|
|
|
|
if (noTagsP)
|
|
EDT_PasteQuote( context, "</PRE>\n" );
|
|
EDT_PasteQuoteEnd( context );
|
|
}
|
|
else {
|
|
EDT_PasteText( context, (char *) text );
|
|
}
|
|
|
|
if ( leaveCursorBeginning && ins != -1 ) {
|
|
EDT_SetInsertPointToOffset( context, ins, 0 );
|
|
}
|
|
}
|
|
|
|
void CMailEditView::DisplayDefaultTextBody()
|
|
{
|
|
|
|
const char *pBody = MSG_GetCompBody(mComposeSession->GetMSG_Pane());
|
|
|
|
if ( mInitialText && strlen(mInitialText) ) {
|
|
InsertMessageCompositionText( mInitialText, false, true);
|
|
InsertMessageCompositionText( "\n", false, true);
|
|
|
|
MSG_SetCompBody(mComposeSession->GetMSG_Pane(), "");
|
|
|
|
XP_FREEIF(mInitialText);
|
|
}
|
|
else if ( pBody && strlen(pBody) ) {
|
|
XP_Bool isHTML =XP_STRCASESTR( pBody,"<HTML>") ? true:false;
|
|
// To prevent quoting the SIG. Is there a more correct way to do this?
|
|
EDT_ReturnKey( *GetContext() );
|
|
InsertMessageCompositionText( pBody, true, isHTML );
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
//-----------------------------------
|
|
CMailComposeWindow::CMailComposeWindow(LStream* inStream) :
|
|
//-----------------------------------
|
|
CMailNewsWindow(inStream, WindowType_Compose),
|
|
mComposeSession(nil),
|
|
mAddressTableView(nil),
|
|
mProgressListener(nil),
|
|
mAttachmentList(nil),
|
|
mAttachmentView(nil),
|
|
mHTMLEditView(nil),
|
|
mPlainEditView(nil),
|
|
mInitializeState(eUninitialized),
|
|
mHeadersDirty( false ),
|
|
mOnlineLastFindCommandStatus( true ),
|
|
mDefaultWebAttachmentURL("\p"),
|
|
mCurrentSaveCommand(cmd_SaveDraft)
|
|
{
|
|
} // CMailComposeWindow::CMailComposeWindow
|
|
|
|
//-----------------------------------
|
|
CMailComposeWindow::~CMailComposeWindow()
|
|
//-----------------------------------
|
|
{
|
|
StopListening();
|
|
if (mPlainEditView && mPlainEditView->IsOnDuty() ) // for a TSM problem, we have deactivate it first
|
|
SwitchTarget(this);
|
|
|
|
delete mComposeSession;
|
|
|
|
if (mAttachmentView)
|
|
mAttachmentView->SetAttachList(nil);
|
|
|
|
delete mAttachmentList;
|
|
|
|
delete mProgressListener;
|
|
RemoveAllAttachments();
|
|
// Kludgy, but prevents crash in LUndoer caused by view being destroyed before
|
|
// attachments.
|
|
} // CMailComposeWindow::~CMailComposeWindow
|
|
|
|
//-----------------------------------
|
|
ResIDT CMailComposeWindow::GetStatusResID() const
|
|
//-----------------------------------
|
|
{
|
|
return mHTMLEditView ?
|
|
CMailComposeWindow::res_ID
|
|
: CMailComposeWindow::text_res_ID;
|
|
} // CMailComposeWindow::GetStatusResID
|
|
|
|
//-----------------------------------
|
|
void CMailComposeWindow::FinishCreateSelf()
|
|
//-----------------------------------
|
|
{
|
|
mPlainEditView = dynamic_cast<CSimpleTextView*>(FindPaneByID('text'));
|
|
if (mPlainEditView)
|
|
{
|
|
|
|
// mPlainEditView->BuildTextObjects(this); // sets the super model
|
|
|
|
// SetDefaultSubModel(mPlainEditView->GetTextModel());
|
|
|
|
// LTextSelection* theSelection = mPlainEditView->GetTextSelection();
|
|
// if (theSelection)
|
|
// theSelection->SetSelectionRange(LTextEngine::sTextStart);
|
|
|
|
mPlainEditView->SetSelection( 0, 0 );
|
|
mPlainEditView->SetTabSelectsAll( false );
|
|
}
|
|
else
|
|
mHTMLEditView = (CMailEditView *)FindPaneByID(CMailEditView::pane_ID);
|
|
|
|
try {
|
|
// make the window the undoer. typing actions end up there.
|
|
LUndoer* theUndoAttachment = new LUndoer;
|
|
AddAttachment(theUndoAttachment); // attach to window
|
|
// create attachment list
|
|
mAttachmentList = new CAttachmentList;
|
|
mHaveInitializedAttachmentsFromBE = false;
|
|
} catch (...) {
|
|
}
|
|
|
|
// link up compose window to addressing table view and vice versa
|
|
CComposeAddressTableView* tableView = dynamic_cast<CComposeAddressTableView*>(FindPaneByID('Addr'));
|
|
mAddressTableView = tableView;
|
|
mAddressTableView->AddListener( this );
|
|
|
|
// add an attachment to the subject edit field to strip out CRs
|
|
LEditField* subjectField = dynamic_cast<LEditField*>(FindPaneByID('Subj'));
|
|
Assert_( subjectField );
|
|
subjectField->AddAttachment(new CPasteSnooper(MAKE_RETURNS_SPACES));
|
|
|
|
|
|
// // set subject as latent sub
|
|
// jrm 97/02/04 removed this, now done more subtly in CreateSession.
|
|
// LEditField* subjectField = dynamic_cast<LEditField*>(FindPaneByID('Subj'));
|
|
// if (subjectField)
|
|
// SetLatentSub(subjectField);
|
|
|
|
UReanimator::LinkListenerToControls(this, this, COMPOSE_BUTTON_BAR_ID);
|
|
|
|
CComposeTabSwitcher* tabSwitcher =
|
|
dynamic_cast<CComposeTabSwitcher*>(FindPaneByID('TbSw'));
|
|
if (tabSwitcher)
|
|
tabSwitcher->AddListener(this);
|
|
|
|
USecurityIconHelpers::AddListenerToSmallButton(
|
|
this /*LWindow**/,
|
|
this /*LListener**/);
|
|
|
|
LGAIconSuiteControl* offlineButton
|
|
= dynamic_cast<LGAIconSuiteControl*>(FindPaneByID(kOfflineButtonPaneID));
|
|
if (offlineButton)
|
|
offlineButton->AddListener(CFrontApp::GetApplication());
|
|
|
|
#if UPDATE_WINDOW_TITLE_ON_IDLE
|
|
StartIdling();
|
|
#endif
|
|
CSaveWindowStatus::FinishCreateWindow();
|
|
// Build the priority Menu
|
|
LMenu* priorityMenu = new LMenu(10620,"\pPriority");
|
|
for( MSG_PRIORITY priorityToInsert = MSG_LowestPriority; priorityToInsert <= MSG_HighestPriority; priorityToInsert=MSG_PRIORITY(priorityToInsert+1) )
|
|
{
|
|
char priorityString[255];
|
|
MSG_GetPriorityName ( priorityToInsert, priorityString, sizeof( priorityString ) );
|
|
priorityMenu->InsertCommand(CStr255(priorityString ),0, Int16(priorityToInsert)-2 );
|
|
}
|
|
CPatternButtonPopup* button = dynamic_cast<CPatternButtonPopup*>(FindPaneByID('Prio'));
|
|
if( button )
|
|
button->AdoptMenu( priorityMenu );
|
|
|
|
SetDefaultWebAttachmentURL();
|
|
|
|
} // CMailComposeWindow::FinishCreateSelf
|
|
|
|
//-----------------------------------
|
|
void CMailComposeWindow::SetDefaultWebAttachmentURL (void)
|
|
//-----------------------------------
|
|
{
|
|
CWindowIterator lookForIt(WindowType_Any);
|
|
CMediatedWindow *parentWindow;
|
|
do {
|
|
lookForIt.Next(parentWindow); // skip over invisible progress dialog and compose window itself
|
|
} while (
|
|
parentWindow &&
|
|
(parentWindow->GetWindowType() == WindowType_Progress) ||
|
|
(parentWindow->GetWindowType() == WindowType_Compose));
|
|
|
|
cstring defaultURL = "\p";
|
|
|
|
if (parentWindow) {
|
|
switch (parentWindow->GetWindowType()) {
|
|
case WindowType_MailThread:
|
|
{
|
|
CThreadWindow *threadParent = dynamic_cast<CThreadWindow *>(parentWindow);
|
|
if (threadParent)
|
|
defaultURL = threadParent->GetCurrentURL();
|
|
}
|
|
case WindowType_Message:
|
|
{
|
|
CMessageWindow *messageParent = dynamic_cast<CMessageWindow *>(parentWindow);
|
|
if (messageParent)
|
|
defaultURL = messageParent->GetCurrentURL();
|
|
}
|
|
case WindowType_Browser:
|
|
{
|
|
CBrowserWindow *browserParent = dynamic_cast<CBrowserWindow *>(parentWindow);
|
|
if (browserParent)
|
|
defaultURL = browserParent->GetWindowContext()->GetCurrentURL();
|
|
}
|
|
}
|
|
}
|
|
mDefaultWebAttachmentURL = (char *)defaultURL;
|
|
}
|
|
|
|
//-----------------------------------
|
|
MSG_Pane* CMailComposeWindow::CreateSession(
|
|
MWContext* old_context,
|
|
MSG_CompositionFields* inCompositionFields,
|
|
const char* initialText,
|
|
Boolean inOpeningDraft)
|
|
//-----------------------------------
|
|
{
|
|
MSG_Pane* result = nil;
|
|
try {
|
|
mComposeSession = new CComposeSession(inOpeningDraft);
|
|
mComposeSession->AddListener(this);
|
|
mProgressListener = new CProgressListener(this, mComposeSession);
|
|
|
|
result = mComposeSession->CreateBackendData(old_context, inCompositionFields);
|
|
if (result)
|
|
{
|
|
|
|
// now pull data out from backend
|
|
// mHTMLEditView will be the flag if we are doing HTML mail or plain text
|
|
// if we have an editView we have an HTML mail window
|
|
// if we have an editor window, we need to init/load a blank page
|
|
// we do this after obtaining the subject and addressees so those
|
|
// fields are properly updated
|
|
SetSensibleTarget();
|
|
if ( !mHTMLEditView )
|
|
{
|
|
//-----------------------------------
|
|
// JRM: NOTE THE ORDERING. EACH ONE OF THESE CALLS WILL SET ITSELF AS
|
|
// THE TARGET IF IT IS EMPTY. SO THE ORDERING SHOULD BE MESSAGE, SUBJECT,
|
|
// ADDRESSEES.
|
|
//-----------------------------------
|
|
// check to see if we need to quote message at startup
|
|
mComposeSession->CheckForAutoQuote();
|
|
const char* body =nil;
|
|
body = initialText? initialText:MSG_GetCompBody(mComposeSession->GetMSG_Pane());
|
|
InsertMessageCompositionText( body, true );
|
|
}
|
|
else
|
|
{
|
|
mHTMLEditView->SetInitialText(initialText);
|
|
// SwitchTarget(mHTMLEditView);
|
|
}
|
|
|
|
// get subject
|
|
GetSubjectFromBackend();
|
|
// get addresses
|
|
GetAllCompHeaders();
|
|
|
|
// Get priority
|
|
GetPriorityFromBackend();
|
|
// Set up security button
|
|
USecurityIconHelpers::UpdateComposeButton( this );
|
|
|
|
// set fe data
|
|
mComposeSession->SetCompositionPaneFEData(this);
|
|
// make sure there is at least an empty addressee
|
|
EnsureAtLeastOneAddressee();
|
|
|
|
// we initialize the editor which will take care of calling the necessary
|
|
// functions for quoting, signatures, etc. (once the editor is done loading)
|
|
if ( mHTMLEditView )
|
|
this->InitializeHTMLEditor( mHTMLEditView );
|
|
// Set the default encodings
|
|
SetDefaultCSID( DefaultCSIDForNewWindow() );
|
|
}
|
|
} catch (...) {
|
|
// what do we do if we can't create compose session or backend data?
|
|
if (mComposeSession)
|
|
mComposeSession->Stop();
|
|
}
|
|
|
|
// now that everything is set up, show the window
|
|
Show();
|
|
|
|
return result;
|
|
} // CMailComposeWindow::CreateSession
|
|
|
|
//-----------------------------------
|
|
void CMailComposeWindow::FindCommandStatus(
|
|
CommandT inCommand,
|
|
Boolean &outEnabled,
|
|
Boolean &outUsesMark,
|
|
Char16 &outMark,
|
|
Str255 outName)
|
|
//-----------------------------------
|
|
{
|
|
switch(inCommand)
|
|
{
|
|
case cmd_Toggle_Paragraph_Toolbar:
|
|
if (mHTMLEditView != nil) {
|
|
outEnabled = true;
|
|
outUsesMark = false;
|
|
if (mToolbarShown[CMailComposeWindow::FORMATTING_TOOLBAR])
|
|
::GetIndString(outName, CEditView::STRPOUND_EDITOR_MENUS,
|
|
CEditView::EDITOR_MENU_HIDE_FORMAT_TOOLBAR);
|
|
else
|
|
::GetIndString(outName, CEditView::STRPOUND_EDITOR_MENUS,
|
|
CEditView:: EDITOR_MENU_SHOW_FORMAT_TOOLBAR);
|
|
} else {
|
|
outEnabled = false;
|
|
outUsesMark = false;
|
|
}
|
|
break;
|
|
case cmd_ToggleToolbar:
|
|
outEnabled = true;
|
|
outUsesMark = false;
|
|
if (mToolbarShown[CMailComposeWindow::MESSAGE_TOOLBAR])
|
|
::GetIndString(outName, BROWSER_MENU_TOGGLE_STRINGS_ID, HIDE_MESSAGE_TOOLBAR_STRING);
|
|
else
|
|
::GetIndString(outName, BROWSER_MENU_TOGGLE_STRINGS_ID, SHOW_MESSAGE_TOOLBAR_STRING);
|
|
break;
|
|
case cmd_SendMessage:
|
|
case cmd_SendMessageLater:
|
|
outEnabled = (
|
|
(!mHTMLEditView || mHTMLEditView->IsDoneLoading()) // HTML edit case
|
|
&& !mComposeSession->GetDeliveryInProgress()
|
|
);
|
|
outUsesMark = false;
|
|
if ( mOnlineLastFindCommandStatus != UOffline::AreCurrentlyOnline( ) )
|
|
UpdateSendButton();
|
|
break;
|
|
case cmd_Save:
|
|
if (mCurrentSaveCommand == cmd_SaveDraft)
|
|
::GetIndString(outName, BROWSER_MENU_TOGGLE_STRINGS_ID,
|
|
SAVE_DRAFT_STRING);
|
|
else
|
|
::GetIndString(outName, BROWSER_MENU_TOGGLE_STRINGS_ID,
|
|
SAVE_TEMPLATE_STRING);
|
|
// and fall through
|
|
case cmd_SaveDraft:
|
|
case cmd_SaveTemplate:
|
|
case cmd_QuoteMessage:
|
|
case cmd_Attach:
|
|
case msg_AttachWeb:
|
|
case msg_AttachFile:
|
|
case cmd_SecurityInfo:
|
|
case cmd_AddressBookWindow:
|
|
outEnabled = (
|
|
(!mHTMLEditView || mHTMLEditView->IsDoneLoading()) // HTML edit case
|
|
&& !mComposeSession->GetDeliveryInProgress()
|
|
);
|
|
outUsesMark = false;
|
|
break;
|
|
case cmd_AttachMyAddressBookCard:
|
|
outEnabled = (
|
|
(!mHTMLEditView || mHTMLEditView->IsDoneLoading()) // HTML edit case
|
|
&& !mComposeSession->GetDeliveryInProgress() );
|
|
outUsesMark = true;
|
|
outMark = mComposeSession->GetCompBoolHeader( MSG_ATTACH_VCARD_BOOL_HEADER_MASK)
|
|
? checkMark: noMark;
|
|
break;
|
|
case cmd_PasteQuote:
|
|
Int32 offset;
|
|
outEnabled = (
|
|
(!mHTMLEditView || mHTMLEditView->IsDoneLoading()) // HTML edit case
|
|
&& !mComposeSession->GetDeliveryInProgress()
|
|
&& ::GetScrap(nil, 'TEXT', &offset) > 0);
|
|
break;
|
|
case cmd_SaveAs:
|
|
if( !mHTMLEditView )
|
|
outEnabled = true;
|
|
else
|
|
Inherited::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
|
|
break;
|
|
default:
|
|
if(inCommand >= ENCODING_BASE && inCommand < ENCODING_CEILING)
|
|
{
|
|
outEnabled = true;
|
|
outUsesMark = true;
|
|
|
|
int16 csid = CPrefs::CmdNumToDocCsid( inCommand );
|
|
outMark = (csid == mComposeSession->GetDefaultCSID()) ? checkMark : ' ';
|
|
} else {
|
|
Inherited::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
|
|
}
|
|
break;
|
|
}
|
|
} // CMailComposeWindow::FindCommandStatus
|
|
|
|
//-----------------------------------
|
|
void CMailComposeWindow::HandleUpdateCompToolbar()
|
|
// called from FE_UpdateCompToolbar.
|
|
//-----------------------------------
|
|
{
|
|
if (mInitializeState == eComposeSessionIsSet)
|
|
{
|
|
CMailCompositionContext* context = mComposeSession->GetCompositionContext();
|
|
if (context)
|
|
{
|
|
URL_Struct* url = NET_CreateURLStruct( "about:editfilenew", NET_NORMAL_RELOAD );
|
|
mInitializeState = eAboutURLLoading;
|
|
context->SwitchLoadURL( url, FO_CACHE_AND_PRESENT );
|
|
}
|
|
}
|
|
} // CMailComposeWindow::HandleUpdateCompToolbar
|
|
|
|
//-----------------------------------
|
|
Boolean CMailComposeWindow::HandleTabKey(const EventRecord &inKeyEvent)
|
|
//-----------------------------------
|
|
{
|
|
Boolean keyHandled = true;
|
|
LCommander *body = NULL;
|
|
|
|
if ( mHTMLEditView )
|
|
body = dynamic_cast<LCommander*>( mHTMLEditView );
|
|
else if ( mPlainEditView )
|
|
body = dynamic_cast<LCommander*>( mPlainEditView );
|
|
|
|
Assert_( body != NULL );
|
|
|
|
Boolean tabBack = (inKeyEvent.modifiers & shiftKey) != 0;
|
|
|
|
LEditField *subjectBar = dynamic_cast<LEditField*>( FindPaneByID('Subj') );
|
|
|
|
Assert_( subjectBar != NULL );
|
|
Assert_( mAddressTableView != NULL );
|
|
|
|
LCommander *curTarget = NULL, *tempTarget = nil;
|
|
|
|
// we have to handle the following things here:
|
|
// 1. Collapsed drag bars
|
|
// 2. Reordering of drag bars
|
|
Boolean addressVisible = true, subjectVisible = true;
|
|
|
|
// find out ordering in window of subject bar and address panel
|
|
SPoint32 subjectLocation, addressLocation;
|
|
|
|
subjectBar->GetFrameLocation( subjectLocation );
|
|
mAddressTableView->GetFrameLocation( addressLocation );
|
|
|
|
Int32 curItem = 1;
|
|
Int32 curTargetIndex = 1; //assume first item has focus for now
|
|
Int32 newTargetIndex, numTargets = 0;
|
|
LArray *targetList = new LArray();
|
|
|
|
if (addressVisible )
|
|
{
|
|
tempTarget = dynamic_cast<LCommander*>( mAddressTableView );
|
|
targetList->InsertItemsAt(1, LArray::index_Last, &tempTarget, sizeof( LCommander *) );
|
|
if (tempTarget->IsOnDuty())
|
|
curTarget = tempTarget;
|
|
}
|
|
|
|
if ( subjectVisible )
|
|
{
|
|
tempTarget = dynamic_cast<LCommander*>( subjectBar );
|
|
targetList->InsertItemsAt(1, LArray::index_Last, &tempTarget, sizeof( LCommander *) );
|
|
if (tempTarget->IsOnDuty())
|
|
curTarget = tempTarget;
|
|
}
|
|
|
|
if (addressVisible && subjectVisible)
|
|
{
|
|
if ( addressLocation.v >= subjectLocation.v ) // address below subject
|
|
targetList->SwapItems(1, 2);
|
|
}
|
|
|
|
targetList->InsertItemsAt(1, LArray::index_Last, &body, sizeof( LCommander *) );
|
|
if (body->IsOnDuty())
|
|
curTarget = body;
|
|
|
|
Assert_(curTarget != NULL); // something should always have focus.
|
|
|
|
// now let's work out who is on duty, and get forward and backward
|
|
curTargetIndex = targetList->FetchIndexOf(&curTarget, sizeof(LCommander *));
|
|
Assert_( curTargetIndex != LArray::index_Bad);
|
|
|
|
// not so stupid as it seems, when we have collapsed bars
|
|
numTargets = targetList->GetCount();
|
|
|
|
// choose which one to go to
|
|
if ( tabBack ) {
|
|
newTargetIndex = curTargetIndex - 1;
|
|
if (newTargetIndex < 1) //arrays are 1-based
|
|
newTargetIndex += numTargets;
|
|
} else {
|
|
newTargetIndex = curTargetIndex + 1;
|
|
if (newTargetIndex > numTargets) //arrays are 1-based
|
|
newTargetIndex -= numTargets;
|
|
}
|
|
|
|
LCommander *newTarget = NULL;
|
|
|
|
if ( targetList->FetchItemAt( newTargetIndex, &newTarget) && (newTarget != curTarget) )
|
|
{
|
|
if ( newTarget->ProcessCommand(msg_TabSelect) )
|
|
{
|
|
// ProcessCommand sets the correct target for the mAddressTAbleView so Don't do it here
|
|
if( newTarget != mAddressTableView )
|
|
SwitchTarget( newTarget );
|
|
}
|
|
else
|
|
SwitchTarget( body );
|
|
}
|
|
|
|
delete targetList;
|
|
|
|
return keyHandled; // always true for now
|
|
}
|
|
|
|
//-----------------------------------
|
|
Boolean CMailComposeWindow::HandleKeyPress(const EventRecord &inKeyEvent)
|
|
//-----------------------------------
|
|
{
|
|
Boolean keyHandled = true;
|
|
Char16 theKey = inKeyEvent.message & charCodeMask;
|
|
|
|
if ( theKey == char_Tab )
|
|
keyHandled = HandleTabKey( inKeyEvent );
|
|
else
|
|
keyHandled = LCommander::HandleKeyPress(inKeyEvent);
|
|
|
|
return keyHandled;
|
|
}
|
|
|
|
//-----------------------------------
|
|
void CMailComposeWindow::InitializeHTMLEditor( CMailEditView* inEditorView )
|
|
//-----------------------------------
|
|
{
|
|
// initialize editor by loading url: "about:editfilenew"
|
|
if ( inEditorView )
|
|
{
|
|
|
|
CMailCompositionContext* context = mComposeSession->GetCompositionContext();
|
|
inEditorView->SetContext( context );
|
|
|
|
// we need to set the compose session for auto-quoting (later)
|
|
inEditorView->SetComposeSession( mComposeSession );
|
|
mInitializeState = eComposeSessionIsSet;
|
|
|
|
if (!XP_IsContextBusy(*context))
|
|
{
|
|
// we won't get an FE_UpdateCompToolbar call, so do it ourselves!
|
|
if (mInitializeState == eComposeSessionIsSet)
|
|
{
|
|
HandleUpdateCompToolbar();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//-----------------------------------
|
|
void CMailComposeWindow::ListenToMessage(MessageT inMessage, void* ioParam)
|
|
//-----------------------------------
|
|
{
|
|
CAttachmentView* attachView;
|
|
MSG_HTMLComposeAction action;
|
|
switch (inMessage)
|
|
{
|
|
// cmd's sent from toolbar buttons
|
|
case cmd_SendMessage:
|
|
SetSensibleTarget();
|
|
XP_Bool sendNow;
|
|
PREF_GetBoolPref("network.online" , &sendNow);
|
|
SendMessage( sendNow );
|
|
break;
|
|
case cmd_SendMessageLater:
|
|
SetSensibleTarget();
|
|
SendMessage(false);
|
|
break;
|
|
case cmd_Save:
|
|
// This does a "save as template/draft according to last command.
|
|
inMessage = mCurrentSaveCommand;
|
|
// FALL THROUGH
|
|
case cmd_SaveDraft:
|
|
case cmd_SaveTemplate:
|
|
mCurrentSaveCommand = inMessage;
|
|
mComposeSession->SetMessage(inMessage); //needed for a relatively clean Drafts imp.
|
|
SetSensibleTarget();
|
|
SaveDraftOrTemplate(inMessage);
|
|
break;
|
|
case cmd_QuoteMessage:
|
|
SetSensibleTarget();
|
|
mComposeSession->QuoteMessage();
|
|
break;
|
|
case cmd_Stop:
|
|
SetSensibleTarget();
|
|
mComposeSession->Stop();
|
|
// EnableButtons();
|
|
break;
|
|
// messages from CComposeSession
|
|
case CComposeSession::msg_InsertQuoteText:
|
|
//SetSensibleTarget();
|
|
InsertMessageCompositionText(reinterpret_cast<const char*>(ioParam));
|
|
break;
|
|
case CComposeSession::msg_AutoQuoteDone:
|
|
int32 eReplyOnTop = 1;
|
|
|
|
// LTextEngine* theTextEngine = mPlainEditView->GetTextEngine();
|
|
// LTextSelection* theSelection = mPlainEditView->GetTextSelection();
|
|
// TextRangeT theBeforeRange = theSelection->GetSelectionRange();
|
|
|
|
SInt32 selStart = 0;
|
|
SInt32 selEnd = 0;
|
|
|
|
mPlainEditView->GetSelection( &selStart, &selEnd );
|
|
|
|
if ( PREF_NOERROR ==PREF_GetIntPref("mailnews.reply_on_top", &eReplyOnTop) )
|
|
{
|
|
switch (eReplyOnTop)
|
|
{
|
|
case 0:
|
|
// Cursor is in the right spot
|
|
break;
|
|
case 1:
|
|
default:
|
|
|
|
// theBeforeRange.SetStart( 0 );
|
|
// theSelection->SetSelectionRange(theBeforeRange);
|
|
|
|
selEnd = selEnd - selStart;
|
|
selStart = 0;
|
|
|
|
mPlainEditView->SetSelection( selStart, selEnd );
|
|
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
|
|
// long end = theBeforeRange.Start();
|
|
// theBeforeRange.SetStart( 0 );
|
|
// theBeforeRange.SetEnd( end );
|
|
// theSelection->SetSelectionRange(theBeforeRange);
|
|
|
|
selEnd = selStart;
|
|
selStart = 0;
|
|
|
|
mPlainEditView->SetSelection( selStart, selEnd );
|
|
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case cmd_CheckSpelling:
|
|
if( mHTMLEditView )
|
|
mHTMLEditView->ObeyCommand( inMessage, ioParam );
|
|
else
|
|
{
|
|
if( mPlainEditView )
|
|
mPlainEditView->ObeyCommand( inMessage, ioParam );
|
|
}
|
|
break;
|
|
// message from CComposeTabSwitcher
|
|
// This is the only semi-clean way that I know of to synchronize
|
|
// the attachment list with the CAttachmentView.
|
|
case msg_ActivatingAttachTab:
|
|
SetSensibleTarget();
|
|
attachView = reinterpret_cast<CAttachmentView*>(ioParam);
|
|
if (mAttachmentList && !attachView->GetAttachList())
|
|
{
|
|
GetAttachmentsFromBackend();
|
|
mHaveInitializedAttachmentsFromBE = true;
|
|
attachView->SetAttachList(mAttachmentList);
|
|
mAttachmentView = attachView;
|
|
mAttachmentView->AddListener( this );
|
|
}
|
|
attachView->AddDropAreaToWindow(this);
|
|
break;
|
|
case msg_DeactivatingAttachTab:
|
|
SetSensibleTarget();
|
|
attachView = reinterpret_cast<CAttachmentView*>(ioParam);
|
|
attachView->RemoveDropAreaFromWindow(this);
|
|
break;
|
|
case msg_ActivatingAddressTab:
|
|
SetSensibleTarget();
|
|
mAddressTableView->AddDropAreaToWindow(this);
|
|
break;
|
|
case msg_DeactivatingAddressTab:
|
|
SetSensibleTarget();
|
|
mAddressTableView->RemoveDropAreaFromWindow(this);
|
|
break;
|
|
case msg_ActivatingOptionTab:
|
|
SetSensibleTarget();
|
|
CMailOptionTabContainer* optionView = reinterpret_cast<CMailOptionTabContainer*>(ioParam);
|
|
|
|
LGACheckbox *control=dynamic_cast <LGACheckbox *> (optionView-> FindPaneByID( 'OtRe' ));
|
|
Assert_(control);
|
|
control->SetValue( mComposeSession->GetCompBoolHeader( MSG_RETURN_RECEIPT_BOOL_HEADER_MASK) );
|
|
|
|
HG43287
|
|
|
|
LGAPopup *popup = dynamic_cast<LGAPopup*>( optionView->FindPaneByID('OtHa') );
|
|
Assert_( popup != nil );
|
|
if( mHTMLEditView )
|
|
{
|
|
action = MSG_GetHTMLAction( mComposeSession->GetMSG_Pane() );
|
|
Int32 popupValue = 0;
|
|
switch( action)
|
|
{
|
|
case MSG_HTMLAskUser:
|
|
popupValue = 1;
|
|
break;
|
|
case MSG_HTMLConvertToPlaintext:
|
|
popupValue = 2;
|
|
break;
|
|
case MSG_HTMLSendAsHTML:
|
|
popupValue = 3;
|
|
break;
|
|
case MSG_HTMLUseMultipartAlternative:
|
|
popupValue = 4;
|
|
break;
|
|
}
|
|
popup->SetValue( popupValue );
|
|
}
|
|
else
|
|
popup->Disable(); // Not used for plain text editing
|
|
break;
|
|
case cmd_SecurityInfo:
|
|
SetSensibleTarget();
|
|
// Update Header fields
|
|
try
|
|
{
|
|
SyncAddressLists();
|
|
SECNAV_SecurityAdvisor((MWContext*)*(mComposeSession->GetCompositionContext()),
|
|
(URL_Struct_*)nil);
|
|
} catch (...) {
|
|
// couldn't allocate memory for buffer
|
|
}
|
|
break;
|
|
case cmd_AddressBookWindow:
|
|
SetSensibleTarget();
|
|
#ifdef MOZ_NEWADDR
|
|
CAddressPickerWindow::DoPickerDialog( mAddressTableView );
|
|
#else
|
|
CAddressBookManager::ShowAddressBookWindow( );
|
|
#endif
|
|
break;
|
|
// Option Tab
|
|
case msg_ReturnRecipt:
|
|
mComposeSession->SetCompBoolHeader( MSG_RETURN_RECEIPT_BOOL_HEADER_MASK, *(Int32*)ioParam);
|
|
break;
|
|
case msg_Garbled:
|
|
HG43288
|
|
break;
|
|
case msg_Signed:
|
|
mComposeSession->SetCompBoolHeader( MSG_SIGNED_BOOL_HEADER_MASK, *(Int32*)ioParam);
|
|
USecurityIconHelpers::UpdateComposeButton( this);
|
|
break;
|
|
case msg_UUEncode:
|
|
mComposeSession->SetCompBoolHeader( MSG_UUENCODE_BINARY_BOOL_HEADER_MASK, *(Int32*)ioParam);
|
|
break;
|
|
#if 0
|
|
case msg_8BitEncoding:
|
|
MIME_ConformToStandard( value ? 0 : 1 );
|
|
break;
|
|
#endif //0
|
|
case msg_HTMLAction:
|
|
switch( *(Int32*)ioParam )
|
|
{
|
|
case 1:
|
|
action = MSG_HTMLAskUser;
|
|
break;
|
|
case 2:
|
|
action = MSG_HTMLConvertToPlaintext;
|
|
break;
|
|
case 3:
|
|
action = MSG_HTMLSendAsHTML;
|
|
break;
|
|
case 4:
|
|
action = MSG_HTMLUseMultipartAlternative;
|
|
break;
|
|
}
|
|
MSG_SetHTMLAction( mComposeSession->GetMSG_Pane(), action );
|
|
break;
|
|
// Attachments
|
|
case msg_AttachFile:
|
|
case msg_AttachWeb:
|
|
// Create an attachment view by switching to it and then switch back
|
|
CComposeTabSwitcher* tabSwitcher =
|
|
dynamic_cast<CComposeTabSwitcher*>(FindPaneByID('TbSw'));
|
|
tabSwitcher->ManuallySwitchToTab( 2 );
|
|
mAttachmentView->ListenToMessage( inMessage, (void *)((unsigned char *)mDefaultWebAttachmentURL));
|
|
break;
|
|
|
|
case cmd_AttachMyAddressBookCard:
|
|
mComposeSession->SetCompBoolHeader(MSG_ATTACH_VCARD_BOOL_HEADER_MASK ,
|
|
!mComposeSession->GetCompBoolHeader( MSG_ATTACH_VCARD_BOOL_HEADER_MASK));
|
|
break;
|
|
// mDirtyHeaders
|
|
case msg_AddressChanged:
|
|
case CAttachmentView::msg_AttachmentsAdded:
|
|
case CAttachmentView::msg_AttachmentsRemoved:
|
|
mHeadersDirty = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CMailComposeWindow::UpdateSendButton()
|
|
{
|
|
mOnlineLastFindCommandStatus = UOffline::AreCurrentlyOnline( );
|
|
|
|
CPatternButton *sendNowButton = dynamic_cast<CPatternButton *>(FindPaneByID(cSendButtonPaneID));
|
|
const ResIDT kSendNowGraphicID = 15319, kSendLaterGraphicID = 15323;
|
|
sendNowButton->SetGraphicID(
|
|
mOnlineLastFindCommandStatus
|
|
? kSendNowGraphicID
|
|
: kSendLaterGraphicID);
|
|
sendNowButton->Refresh();
|
|
}
|
|
|
|
Boolean CMailComposeWindow::ObeyCommand(CommandT inCommand, void *ioParam)
|
|
{
|
|
Boolean cmdHandled = true;
|
|
|
|
switch (inCommand)
|
|
{
|
|
case cmd_ToggleToolbar:
|
|
ToggleDragBar(cMessageToolbar, CMailNewsWindow::MESSAGE_TOOLBAR);
|
|
cmdHandled = true;
|
|
break;
|
|
|
|
case cmd_Toggle_Paragraph_Toolbar:
|
|
ToggleDragBar(cFormattingToolbar, CMailComposeWindow::FORMATTING_TOOLBAR);
|
|
cmdHandled = true;
|
|
break;
|
|
|
|
case cmd_PasteQuote:
|
|
SetSensibleTarget();
|
|
int32 textLen;
|
|
textLen = LClipboard::GetClipboard()->GetData( 'TEXT', nil );
|
|
if (textLen > 0)
|
|
{
|
|
Handle textHandle = ::NewHandle(textLen + 1);
|
|
if (textHandle)
|
|
{
|
|
LClipboard::GetClipboard()->GetData( 'TEXT', textHandle );
|
|
::HLock(textHandle);
|
|
(*textHandle)[textLen] = '\0';
|
|
if( mHTMLEditView )
|
|
MSG_PastePlaintextQuotation(mComposeSession->GetMSG_Pane(), *textHandle);
|
|
else
|
|
{ //plain text case
|
|
char *quotedText = MSG_ConvertToQuotation (*textHandle);
|
|
if( quotedText )
|
|
{
|
|
InsertMessageCompositionText( quotedText );
|
|
XP_FREE( quotedText );
|
|
}
|
|
}
|
|
::DisposeHandle(textHandle);
|
|
}
|
|
}
|
|
break;
|
|
case cmd_SaveAs:
|
|
if( mHTMLEditView )
|
|
cmdHandled =false;
|
|
else
|
|
{
|
|
StandardFileReply reply;
|
|
short format;
|
|
CStr31 defaultFileName;
|
|
GetDescriptor( defaultFileName );
|
|
UStdDialogs::AskSaveAsSource( reply, defaultFileName , format );
|
|
if ( reply.sfGood )
|
|
mPlainEditView->Save( reply.sfFile );
|
|
}
|
|
break;
|
|
// Commands that have button bar equivalents
|
|
case cmd_SendMessage:
|
|
case cmd_SendMessageLater:
|
|
case cmd_QuoteMessage:
|
|
case cmd_SaveDraft:
|
|
case cmd_SaveTemplate:
|
|
case msg_AttachWeb:
|
|
case msg_AttachFile:
|
|
case cmd_AttachMyAddressBookCard:
|
|
ListenToMessage( inCommand, ioParam);
|
|
break;
|
|
default:
|
|
if(inCommand >= ENCODING_BASE && inCommand < ENCODING_CEILING)
|
|
{
|
|
SetDefaultCSID(CPrefs::CmdNumToDocCsid(inCommand));
|
|
cmdHandled = true;
|
|
} else {
|
|
cmdHandled = Inherited::ObeyCommand(inCommand, ioParam);
|
|
}
|
|
break;
|
|
}
|
|
return cmdHandled;
|
|
}
|
|
void CMailComposeWindow::SetDefaultCSID(Int16 defaultcsid)
|
|
{
|
|
Assert_(mComposeSession);
|
|
if(mComposeSession)
|
|
{
|
|
|
|
int16 wincsid = INTL_DocToWinCharSetID(defaultcsid);
|
|
ResIDT textTraitID = CPrefs::GetTextFieldTextResIDs(wincsid);
|
|
|
|
// Set the HTML editor, if present
|
|
if (mHTMLEditView)
|
|
{
|
|
if( !mHTMLEditView->SetDefaultCSID(defaultcsid) )
|
|
return;
|
|
}
|
|
// Set the plain text editor, if present
|
|
if ( mPlainEditView ) {
|
|
mPlainEditView->SetInitialTraits(textTraitID);
|
|
mPlainEditView->ResetModCount(); // fix for bug # 104805 ask save on close
|
|
}
|
|
|
|
// Set The Subject Font
|
|
if(LEditField* subjectField = dynamic_cast<LEditField*>(FindPaneByID('Subj')))
|
|
{
|
|
subjectField->SetTextTraitsID(textTraitID);
|
|
subjectField->Refresh();
|
|
}
|
|
|
|
// Set The Address Font
|
|
if( mAddressTableView )
|
|
mAddressTableView->SetTextTraits( textTraitID );
|
|
|
|
// Set the Session
|
|
mComposeSession->SetDefaultCSID(defaultcsid);
|
|
|
|
#if 0
|
|
// To Work Around Our TSMTE problem
|
|
Int32 dummyVer;
|
|
if( (defaultcsid & MULTIBYTE ) &&
|
|
(noErr == ::Gestalt(gestaltTSMTEAttr, &dummyVer)) &&
|
|
((dummyVer & (1 << gestaltTSMTEPresent) ) != 0)
|
|
) {
|
|
this->SetSensibleTarget();
|
|
}
|
|
#endif //0
|
|
}
|
|
}
|
|
|
|
|
|
void CMailComposeWindow::SyncAddressLists()
|
|
{
|
|
|
|
// Clear the comp headers in case entries were deleted from the
|
|
// address view
|
|
// Save & Restore the (Reply To) and (Followup To) fields
|
|
char* replyto = nil;
|
|
replyto = XP_STRDUP(
|
|
mComposeSession->GetMessageHeaderData( MSG_REPLY_TO_HEADER_MASK ) );
|
|
FailNIL_(replyto);
|
|
char* followupto = nil;
|
|
followupto = XP_STRDUP(
|
|
mComposeSession->GetMessageHeaderData( MSG_FOLLOWUP_TO_HEADER_MASK ) );
|
|
FailNIL_(followupto);
|
|
MSG_ClearComposeHeaders ( mComposeSession->GetMSG_Pane() );
|
|
MSG_SetCompHeader( mComposeSession->GetMSG_Pane(),
|
|
MSG_REPLY_TO_HEADER_MASK, replyto );
|
|
MSG_SetCompHeader( mComposeSession->GetMSG_Pane(),
|
|
MSG_FOLLOWUP_TO_HEADER_MASK, followupto );
|
|
XP_FREE( replyto );
|
|
XP_FREE( followupto );
|
|
|
|
// set composition headers
|
|
for (int type = eToType; type <= eFollowupType; type++)
|
|
SetCompHeader((EAddressType)type);
|
|
}
|
|
|
|
Boolean CMailComposeWindow::PrepareMessage( Boolean isDraft)
|
|
{
|
|
// disable all toolbar buttons except stop
|
|
//DisableAllButtonsExceptStop();
|
|
if (mComposeSession)
|
|
{
|
|
SyncAddressLists();
|
|
// set subject
|
|
char* subject = GetSubject();
|
|
// if (**teHandle).teLength == 0, we should probably ask the user
|
|
// if they want to enter a subject right about here
|
|
if (subject && XP_STRLEN( subject ))
|
|
{
|
|
// Copy subject out of TEHandle in edit field and pass it to
|
|
// msglib. Don't forget to dispose of buffer.
|
|
MSG_SetCompHeader(mComposeSession->GetMSG_Pane(),MSG_SUBJECT_HEADER_MASK, subject);
|
|
|
|
XP_FREE( subject );
|
|
}
|
|
#if 1 // This is a temporary hack till we really fix bug #42878.
|
|
else if( !isDraft )
|
|
{
|
|
LEditField* subjectField = dynamic_cast<LEditField*>(FindPaneByID('Subj')); // use CTSMEditField to support Asian Inline input
|
|
SysBeep(1);
|
|
SwitchTarget(subjectField);
|
|
CStr255 errorSubject(XP_GetString(MK_MIME_NO_SUBJECT));
|
|
subjectField->SetDescriptor(errorSubject);
|
|
subjectField->SelectAll();
|
|
return false;
|
|
}
|
|
#endif
|
|
// set priority
|
|
// pkc -- 10/8/96 priority isn't ready in backend
|
|
LControl* priorityMenu = dynamic_cast<LControl*>(FindPaneByID('Prio'));
|
|
Int32 priority = priorityMenu->GetValue();
|
|
mComposeSession->SetPriority(UComposeUtilities::GetMsgPriorityFromMenuItem(priority));
|
|
|
|
// set body
|
|
if ( mPlainEditView )
|
|
{
|
|
// LTextEngine* textEngine = dynamic_cast<LTextEngine*>(mPlainEditView->GetTextEngine());
|
|
|
|
Handle msgBody = mPlainEditView->GetTextHandle();
|
|
if (msgBody)
|
|
{
|
|
try {
|
|
LHandleStream handleStream;
|
|
// preallocate handle
|
|
handleStream.SetLength(1024);
|
|
|
|
// TextRangeT textRange = textEngine->GetTotalRange();
|
|
UInt32 textLength = mPlainEditView->GetTextLength();
|
|
|
|
UComposeUtilities::WordWrap(msgBody, textLength, handleStream);
|
|
handleStream << (unsigned char) '\0';
|
|
mComposeSession->SetMessageBody(handleStream);
|
|
} catch (...) {
|
|
// couldn't allocate memory for LHandleStream
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// send HTML text
|
|
// all of the HTML is gotten from the MWContext
|
|
mComposeSession->SetHTMLMessageBody();
|
|
}
|
|
}
|
|
if( !mHaveInitializedAttachmentsFromBE )
|
|
{
|
|
GetAttachmentsFromBackend();
|
|
mHaveInitializedAttachmentsFromBE = true;
|
|
}
|
|
|
|
return true;
|
|
} // CMailComposeWindow::PrepareMessage
|
|
|
|
extern "C" void MSG_ResetUUEncode(MSG_Pane *pane);
|
|
|
|
void CMailComposeWindow::SaveDraftOrTemplate(CommandT inCommand, Boolean inCloseWindow)
|
|
{
|
|
mComposeSession->SetMessage( inCommand );
|
|
MSG_AttachmentData* attachList = nil;
|
|
try {
|
|
|
|
// ### mwelch Reset the uuencode UI state so the
|
|
// dialog pops up once per send attempt.
|
|
MSG_ResetUUEncode(mComposeSession->GetMSG_Pane());
|
|
|
|
PrepareMessage( true );
|
|
// set attachments
|
|
attachList = mAttachmentList->NewXPAttachmentList();
|
|
if (mComposeSession->NeedToSyncAttachmentList(attachList))
|
|
{ // send attachments
|
|
// there's no need to call mComposeSession->SaveDraftOrTemplate()
|
|
// because the compose session will catch the FE_AllConnectionsComplete
|
|
// callback when loading the attachments and will SaveDraft then
|
|
mComposeSession->SetAttachmentList(attachList);
|
|
mComposeSession->SetCloseWindow( inCloseWindow );
|
|
XP_FREE(attachList);
|
|
}
|
|
else
|
|
{
|
|
// just save the Draft
|
|
mComposeSession->SaveDraftOrTemplate(inCommand, inCloseWindow);
|
|
}
|
|
} catch (...) {
|
|
XP_FREEIF(attachList);
|
|
// most likely, couldn't allocate memory for attachList
|
|
}
|
|
mHeadersDirty = false;
|
|
if( mPlainEditView )
|
|
{
|
|
|
|
// LTextEngine* theTextEngine = mPlainEditView->GetTextEngine();
|
|
// theTextEngine->SetTextChanged( false );
|
|
|
|
mPlainEditView->ResetModCount();
|
|
|
|
}
|
|
}
|
|
|
|
void CMailComposeWindow::SendMessage(Boolean inSendNow)
|
|
{
|
|
// See if we have to spell check
|
|
XP_Bool needToSpellCheck = false;
|
|
PREF_GetBoolPref("mail.SpellCheckBeforeSend", &needToSpellCheck);
|
|
if ( needToSpellCheck )
|
|
{
|
|
ListenToMessage( cmd_CheckSpelling, NULL );
|
|
ObeyCommand( cmd_CheckSpelling, NULL );
|
|
}
|
|
|
|
MSG_AttachmentData* attachList = nil;
|
|
//Boolean needToSave = NeedToSave();
|
|
if( PrepareMessage( false ) )
|
|
{
|
|
// set attachments
|
|
try {
|
|
// ### mwelch. Reset the uuencode UI state so the
|
|
// dialog pops up once per send attempt.
|
|
MSG_ResetUUEncode(mComposeSession->GetMSG_Pane());
|
|
|
|
attachList = mAttachmentList->NewXPAttachmentList();
|
|
if (mComposeSession->NeedToSyncAttachmentList(attachList))
|
|
{ // send attachments
|
|
// there's no need to call mComposeSession->SendMessage()
|
|
// because the compose session will catch the FE_AllConnectionsComplete
|
|
// callback when loading the attachments and will call SendMessage then
|
|
mComposeSession->SetAttachmentList(attachList);
|
|
XP_FREE(attachList);
|
|
mComposeSession->SetSendNow(inSendNow);
|
|
}
|
|
else
|
|
{
|
|
// just send message
|
|
mComposeSession->SendMessage(inSendNow);
|
|
}
|
|
} catch (...) {
|
|
XP_FREEIF(attachList);
|
|
// ### mwelch. We can get exceptions by running out of memory
|
|
// or if the user hit "Cancel" to a uuencode confirmation
|
|
// dialog. (Yes, the back end throws an exception here.)
|
|
// See MSG_DeliverMimeAttachment::SnarfAttachment in
|
|
// ns/lib/libmsg/msgsend.cpp.
|
|
}
|
|
}
|
|
//mHeadersDirty = needToSave; // if send fails, dirty flag is still preserved
|
|
}
|
|
|
|
void CMailComposeWindow::SetCompHeader(EAddressType inAddressType)
|
|
{
|
|
if (mComposeSession && mAddressTableView)
|
|
{
|
|
try {
|
|
LHandleStream stream;
|
|
// preallocate handle
|
|
stream.SetLength(512);
|
|
stream.SetMarker(0, streamFrom_Start);
|
|
mAddressTableView->CreateCompHeader(inAddressType, stream);
|
|
if (stream.GetMarker() > 0)
|
|
mComposeSession->SetMessageHeaderData(
|
|
UComposeUtilities::GetMsgHeaderMaskFromAddressType(inAddressType),
|
|
stream);
|
|
} catch (...) {
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------
|
|
void CMailComposeWindow::GetCompHeader(EAddressType inAddressType)
|
|
//-----------------------------------
|
|
{
|
|
Assert_(mAddressTableView && mComposeSession);
|
|
char* scanner = (char *)mComposeSession->GetMessageHeaderData(
|
|
UComposeUtilities::GetMsgHeaderMaskFromAddressType(inAddressType));
|
|
MSG_HeaderEntry *returnList=nil;
|
|
Int32 numberItems= MSG_ExplodeHeaderField( inAddressType, scanner, &returnList );
|
|
if ( numberItems!=-1 )
|
|
{
|
|
for(Int32 currentItem=0; currentItem<numberItems; currentItem++ )
|
|
{
|
|
mAddressTableView->InsertNewRow(EAddressType(returnList[currentItem].header_type),
|
|
returnList[currentItem].header_value );
|
|
XP_FREE( returnList[currentItem].header_value );
|
|
}
|
|
XP_FREE ( returnList );
|
|
}
|
|
|
|
#if 0 // MSGComh. has a better function
|
|
if (scanner)
|
|
{
|
|
// now parse comma delimited string
|
|
char *addr = scanner;
|
|
while (*scanner != nil)
|
|
{
|
|
// find end of address
|
|
while (*scanner != nil && *scanner != ',')
|
|
++scanner;
|
|
try {
|
|
char* addrStr = new char[scanner - addr + 1];
|
|
::BlockMoveData(addr, addrStr, scanner - addr);
|
|
addrStr[scanner - addr] = '\0';
|
|
mAddressTableView->InsertNewRow(inAddressType, addrStr);
|
|
delete [] addrStr;
|
|
} catch (...) {
|
|
}
|
|
while (*scanner != nil && (*scanner == ',' || *scanner == ' ' || *scanner == '\t'))
|
|
++scanner;
|
|
addr = scanner;
|
|
}
|
|
}
|
|
#endif //0
|
|
} // CMailComposeWindow::GetCompHeader
|
|
|
|
//-----------------------------------
|
|
Int16 CMailComposeWindow::DefaultCSIDForNewWindow()
|
|
//-----------------------------------
|
|
{
|
|
if(mComposeSession)
|
|
return mComposeSession->GetDefaultCSID(); // Delgate to mComposeSession
|
|
else
|
|
return 0;
|
|
} // CMailComposeWindow::DefaultCSIDForNewWindow()
|
|
|
|
//-----------------------------------
|
|
void CMailComposeWindow::GetAllCompHeaders()
|
|
//-----------------------------------
|
|
{
|
|
for (int i = eToType; i <= eFollowupType; i++)
|
|
if (i != eReplyType)
|
|
GetCompHeader((EAddressType)i);
|
|
}
|
|
|
|
//-----------------------------------
|
|
char* CMailComposeWindow::GetSubject()
|
|
// Caller responsible for freeing return value
|
|
//-----------------------------------
|
|
{
|
|
char* result = nil;
|
|
CLargeEditField* subjectField = dynamic_cast<CLargeEditField*>(FindPaneByID('Subj')); // use CTSMEditField to support Asian Inline input
|
|
if (subjectField)
|
|
result = subjectField->GetLongDescriptor();
|
|
Assert_(result);
|
|
return result;
|
|
} // CMailComposeWindow::GetSubjectTEHandle
|
|
|
|
//-----------------------------------
|
|
void CMailComposeWindow::GetSubjectFromBackend()
|
|
//-----------------------------------
|
|
{
|
|
Assert_(mComposeSession);
|
|
const char* subject = mComposeSession->GetSubject();
|
|
|
|
// We need to set up the TextTrait of Subject according to the csid.
|
|
CLargeEditField* subjectField = dynamic_cast<CLargeEditField*>(FindPaneByID('Subj'));
|
|
|
|
if (subject && *subject)
|
|
subjectField->SetLongDescriptor( subject );
|
|
else
|
|
{
|
|
SwitchTarget( subjectField );
|
|
}
|
|
} // CMailComposeWindow::GetSubjectFromBackend
|
|
|
|
|
|
void CMailComposeWindow::GetPriorityFromBackend()
|
|
{
|
|
LControl *priority = dynamic_cast<LControl*>( FindPaneByID('Prio') );
|
|
if( priority )
|
|
{
|
|
// Need to do this to ensure that we refresh the menu with new value
|
|
priority->SetValue( 1 );
|
|
MSG_PRIORITY backendPriority = mComposeSession->GetPriority();
|
|
if( backendPriority == MSG_NoPriority )
|
|
backendPriority = MSG_NormalPriority;
|
|
// MSG_NoPriority isn't a popup item so all numbers off by 1
|
|
Int32 value = Int32( backendPriority) - Int32( MSG_NoPriority );
|
|
priority->SetValue( value );
|
|
}
|
|
}
|
|
//-----------------------------------
|
|
void CMailComposeWindow::GetAttachmentsFromBackend()
|
|
//-----------------------------------
|
|
{
|
|
Assert_(mComposeSession);
|
|
const struct MSG_AttachmentData* attachData =
|
|
mComposeSession->GetAttachmentData();
|
|
if (attachData)
|
|
{
|
|
Assert_(mAttachmentList);
|
|
mAttachmentList->InitializeFromXPAttachmentList(attachData);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------
|
|
void CMailComposeWindow::EnsureAtLeastOneAddressee()
|
|
//-----------------------------------
|
|
{
|
|
Assert_(mAddressTableView);
|
|
TableIndexT numRows;
|
|
mAddressTableView->GetNumRows(numRows);
|
|
Boolean insertNewRow = true;
|
|
while ( numRows )
|
|
{
|
|
EAddressType addressType = mAddressTableView->GetRowAddressType( numRows );
|
|
if( addressType != eBccType)
|
|
{
|
|
insertNewRow = false;
|
|
break;
|
|
}
|
|
numRows--;
|
|
}
|
|
|
|
if ( insertNewRow )
|
|
{
|
|
mAddressTableView->InsertNewRow( true, true);
|
|
}
|
|
|
|
}
|
|
|
|
//-----------------------------------
|
|
void CMailComposeWindow::SetSensibleTarget()
|
|
//-----------------------------------
|
|
{
|
|
|
|
if (mPlainEditView)
|
|
{
|
|
SwitchTarget(mPlainEditView);
|
|
}
|
|
if (mHTMLEditView)
|
|
SwitchTarget(mHTMLEditView);
|
|
}
|
|
|
|
//-----------------------------------
|
|
ExceptionCode CMailComposeWindow::InsertMessageCompositionText(const char* text, Boolean leaveCursorinFront)
|
|
// this code taken straight from mailmac.cp
|
|
// Actually seems to be called only for plain-text quoting.
|
|
//-----------------------------------
|
|
{
|
|
#define SUCCESS 0
|
|
ExceptionCode err = SUCCESS;
|
|
// if (text == nil) // Don't do this.
|
|
// Even if text is nil, this function must set the target to the appropriate text view.
|
|
// return err;
|
|
|
|
StWatchCursor watchCursor;
|
|
|
|
try // TextReplaceByPtr can throw
|
|
{
|
|
|
|
Assert_(mPlainEditView); // seems to be called only for simple text.
|
|
if (mPlainEditView)
|
|
{
|
|
// SwitchTarget(mPlainEditView);
|
|
if (!text || !*text)
|
|
return SUCCESS;
|
|
|
|
Boolean textChanged = (mPlainEditView->GetModCount() > 0);
|
|
|
|
|
|
//
|
|
// Blast the text into the text field.
|
|
//
|
|
// We must first ensure that the field is not marked
|
|
// read-only (which is likely since we've probably been
|
|
// asked by XP to disable toolbar buttons, at which
|
|
// point we also disable the body field).
|
|
//
|
|
// Save the field's attributes, mark it writable,
|
|
// blast the text, restore the attributes.
|
|
//
|
|
|
|
Boolean isReadOnly = mPlainEditView->IsReadOnly();
|
|
|
|
if ( isReadOnly )
|
|
mPlainEditView->SetReadOnly( false );
|
|
|
|
SInt32 oldSelStart = 0;
|
|
SInt32 oldSelEnd = 0;
|
|
|
|
mPlainEditView->GetSelection( &oldSelStart, &oldSelEnd );
|
|
|
|
SInt32 textLen = text ? XP_STRLEN(text) : 0;
|
|
|
|
if (text != NULL)
|
|
mPlainEditView->InsertPtr( const_cast<char *>(text), textLen, NULL, NULL, false, false );
|
|
|
|
// We need to move the selection range manually
|
|
|
|
if ( !leaveCursorinFront )
|
|
{
|
|
oldSelStart = oldSelStart + textLen;
|
|
|
|
if ( oldSelEnd < oldSelStart )
|
|
oldSelEnd = oldSelStart;
|
|
}
|
|
|
|
mPlainEditView->SetSelection( oldSelStart, oldSelEnd );
|
|
|
|
if (! textChanged)
|
|
mPlainEditView->ResetModCount();
|
|
}
|
|
|
|
}
|
|
catch (ExceptionCode inErr)
|
|
{
|
|
err = inErr;
|
|
}
|
|
|
|
return err;
|
|
} // CMailComposeWindow::InsertMessageCompositionText
|
|
|
|
Boolean CMailComposeWindow::NeedToSave()
|
|
{
|
|
|
|
// attachments and addresses broadcast when changed
|
|
SetSensibleTarget();
|
|
if( mHeadersDirty )
|
|
return true;
|
|
Boolean dirty = true;
|
|
|
|
// Subject
|
|
CStr255 subject( mComposeSession->GetSubject() );
|
|
LEditField* subjectField = dynamic_cast<LEditField*>(FindPaneByID('Subj'));
|
|
CStr255 currentText;
|
|
if (subjectField)
|
|
subjectField->GetDescriptor(currentText);
|
|
dirty = (currentText != subject);
|
|
if (dirty)
|
|
return dirty;
|
|
//Body
|
|
|
|
if (mHTMLEditView)
|
|
dirty = EDT_DirtyFlag( mComposeSession->GetCompositionContext() ->operator MWContext*() );
|
|
else
|
|
{
|
|
|
|
// LTextEngine* theTextEngine = mPlainEditView->GetTextEngine();
|
|
|
|
dirty = (mPlainEditView->GetModCount() > 0);
|
|
|
|
}
|
|
return dirty;
|
|
|
|
} // CMailComposeWindow::NeedToSave
|
|
|
|
Boolean CMailComposeWindow::AskIfUserWantsToClose()
|
|
{
|
|
MessageT itemHit = HandleModalDialog( COMPOSEDLG_SAVE_BEFORE_QUIT, nil, nil );
|
|
if (itemHit == cancel)
|
|
return false;
|
|
|
|
if (itemHit == ok)
|
|
{
|
|
SaveDraftOrTemplate(cmd_SaveDraft, true );
|
|
return false ; // Drafts will close the window Clean up for 4.02
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CMailComposeWindow::AttemptClose()
|
|
{
|
|
Select(); // This helps for "close all"
|
|
if (mComposeSession->GetDownloadingAttachments()
|
|
|| XP_IsContextBusy(*mComposeSession->GetCompositionContext()))
|
|
{
|
|
mComposeSession->Stop();
|
|
return; // do we really want to return here? See bug #73544
|
|
// need this return to cancel close of aborted send
|
|
// but it might leave open a window with partially
|
|
// loaded attachments, which could cause us to send
|
|
// bad data.
|
|
// see also bug 107078 that prompted this comment.
|
|
}
|
|
else
|
|
{
|
|
if (NeedToSave() && !AskIfUserWantsToClose())
|
|
return;
|
|
}
|
|
Inherited::AttemptClose();
|
|
} // CMailComposeWindow::AttemptClose()
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
Boolean CMailComposeWindow::AttemptQuitSelf(Int32 inSaveOption)
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
if (mComposeSession->GetDownloadingAttachments()
|
|
|| XP_IsContextBusy(*mComposeSession->GetCompositionContext()))
|
|
{
|
|
mComposeSession->Stop();
|
|
return false;
|
|
}
|
|
|
|
if (NeedToSave() && !AskIfUserWantsToClose())
|
|
return false;
|
|
return Inherited::AttemptQuitSelf(inSaveOption);
|
|
} // CMailComposeWindow::AttemptQuitSelf
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
void CMailComposeWindow::DoCloseLater()
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
CDeferredCloseTask::DeferredClose(this);
|
|
} // CMailComposeWindow::DoCloseLater
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
void CMailComposeWindow::SpendTime(const EventRecord &/*inMacEvent*/)
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
// Update the window title to match the subject
|
|
LEditField* subjectField = dynamic_cast<LEditField*>(FindPaneByID('Subj'));
|
|
CStr255 currentSubject;
|
|
if (subjectField)
|
|
{
|
|
subjectField->GetDescriptor(currentSubject);
|
|
// Leave the default window title until they've typed something.
|
|
if (currentSubject != CStr255::sEmptyString)
|
|
{
|
|
CStr255 windowTitle;
|
|
this->GetDescriptor(windowTitle);
|
|
// Test for equality to avoid flickering.
|
|
if (windowTitle != currentSubject)
|
|
this->SetDescriptor(currentSubject);
|
|
}
|
|
}
|
|
} // CMailComposeWindow::SpendTime
|
|
|
|
#pragma mark -
|
|
|
|
CTabContainer::CTabContainer(LStream* inStream) :
|
|
CPatternBevelView(inStream)
|
|
{
|
|
}
|
|
|
|
void CTabContainer::DrawBeveledFrame(void)
|
|
{
|
|
// Overridden to draw a partial-rect border
|
|
Rect theFrame;
|
|
CalcLocalFrameRect(theFrame);
|
|
SBooleanRect theBevelSides = { true, false, true, true };
|
|
UGraphicGizmos::BevelTintPartialRect(theFrame, mMainBevel, 0x4000, 0x4000, theBevelSides);
|
|
}
|
|
|
|
void CTabContainer::DrawSelf()
|
|
{
|
|
#if 0
|
|
Inherited::DrawSelf();
|
|
Rect theFrame;
|
|
if (CalcLocalFrameRect(theFrame))
|
|
{
|
|
StColorPenState theSaver;
|
|
theSaver.Normalize();
|
|
|
|
SBevelColorDesc theDesc;
|
|
UGraphicGizmos::LoadBevelTraits(5000, theDesc);
|
|
|
|
StClipRgnState theClipSaver(theFrame);
|
|
StColorState::Normalize();
|
|
|
|
theFrame.left-=5;
|
|
::FrameRect(&theFrame);
|
|
|
|
SBooleanRect theBevelSides = { false, true, true, true };
|
|
UGraphicGizmos::BevelPartialRect(theFrame, 1, eStdGrayBlack, eStdGrayBlack, theBevelSides);
|
|
::InsetRect(&theFrame, 1, 1);
|
|
UGraphicGizmos::BevelPartialRect(theFrame, 2, theDesc.topBevelColor, theDesc.bottomBevelColor, theBevelSides);
|
|
}
|
|
#endif
|
|
Inherited::DrawSelf();
|
|
Rect theFrame;
|
|
if (CalcLocalFrameRect(theFrame))
|
|
{
|
|
StColorPenState theSaver;
|
|
theSaver.Normalize();
|
|
|
|
StClipRgnState theClipSaver(theFrame);
|
|
StColorState::Normalize();
|
|
|
|
theFrame.top -= 5; // to hide the top
|
|
::FrameRect(&theFrame);
|
|
}
|
|
}
|
|
|
|
CMailTabContainer::CMailTabContainer(LStream* inStream) : CTabContainer( inStream )
|
|
{
|
|
}
|
|
|
|
void CMailTabContainer::DrawBeveledFrame(void)
|
|
{
|
|
// Overridden to draw a partial-rect border
|
|
Rect theFrame;
|
|
CalcLocalFrameRect(theFrame);
|
|
SBooleanRect theBevelSides = { false, true, true, true };
|
|
UGraphicGizmos::BevelTintPartialRect(theFrame, mMainBevel, 0x4000, 0x4000, theBevelSides);
|
|
}
|
|
|
|
void CMailTabContainer::DrawSelf()
|
|
{
|
|
Inherited::DrawSelf();
|
|
Rect theFrame;
|
|
if (CalcLocalFrameRect(theFrame))
|
|
{
|
|
StColorPenState theSaver;
|
|
theSaver.Normalize();
|
|
|
|
StClipRgnState theClipSaver(theFrame);
|
|
StColorState::Normalize();
|
|
|
|
theFrame.left -= 5; // to hide the left
|
|
::FrameRect(&theFrame);
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
CMailComposeTabContainer::CMailComposeTabContainer(LStream* inStream) :
|
|
CMailTabContainer(inStream)
|
|
{
|
|
}
|
|
|
|
void CMailComposeTabContainer::FinishCreateSelf()
|
|
{
|
|
//UReanimator::LinkListenerToControls(dynamic_cast<CComposeAddressTableView*>(FindPaneByID('Addr')),this,10611);
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
|
|
CMailAttachmentTabContainer::CMailAttachmentTabContainer(LStream* inStream) :
|
|
CMailTabContainer(inStream)
|
|
{
|
|
}
|
|
|
|
void CMailAttachmentTabContainer::FinishCreateSelf()
|
|
{
|
|
// CAttachmentView* attachView = dynamic_cast<CAttachmentView*>(FindPaneByID('Attv'));
|
|
// try {
|
|
// attachView->SetAttachList(new CAttachmentList);
|
|
// } catch (...) {
|
|
// }
|
|
UReanimator::LinkListenerToControls(dynamic_cast<CAttachmentView*>(FindPaneByID('Attv')),this,10612);
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
CMailCompositionContext::CMailCompositionContext() :
|
|
CBrowserContext(MWContextMessageComposition)
|
|
{
|
|
MWContext *mwcontext = operator MWContext*();
|
|
if ( mwcontext )
|
|
{
|
|
mwcontext->is_editor = true;
|
|
mwcontext->bIsComposeWindow = true;
|
|
}
|
|
}
|
|
|
|
void CMailCompositionContext::AllConnectionsComplete()
|
|
{
|
|
StSharer share(this);
|
|
CBrowserContext::AllConnectionsComplete();
|
|
}
|
|
|
|
void CMailCompositionContext::CreateContextProgress()
|
|
{
|
|
try {
|
|
mProgress = new CContextProgress;
|
|
mProgress->AddUser(this);
|
|
} catch (...) {
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
CComposeTabSwitcher::CComposeTabSwitcher(LStream* inStream) :
|
|
CTabSwitcher(inStream)
|
|
{
|
|
}
|
|
|
|
void CComposeTabSwitcher::ManuallySwitchToTab( int32 tabID)
|
|
{
|
|
CTabControl* theTabControl = (CTabControl*)FindPaneByID(mTabControlID);
|
|
theTabControl->SetValue( tabID );
|
|
}
|
|
void CComposeTabSwitcher::DoPostLoad(LView* inLoadedPage, Boolean /*inWillCache*/)
|
|
{
|
|
|
|
LView* view = (LView*)inLoadedPage->FindPaneByID('Attv');
|
|
if (view)
|
|
{
|
|
CAttachmentView* attachView = dynamic_cast<CAttachmentView*>(view);
|
|
BroadcastMessage(msg_ActivatingAttachTab, attachView);
|
|
}
|
|
else if ((LView*)inLoadedPage->FindPaneByID('Addr'))
|
|
{
|
|
BroadcastMessage(msg_ActivatingAddressTab,nil);
|
|
}
|
|
|
|
view = ( LView*)inLoadedPage->FindPaneByID('OpTC');
|
|
if( view )
|
|
{
|
|
CMailOptionTabContainer* optionView = dynamic_cast<CMailOptionTabContainer*>(view);
|
|
BroadcastMessage( msg_ActivatingOptionTab, optionView );
|
|
}
|
|
|
|
}
|
|
|
|
void CComposeTabSwitcher::DoPreDispose(LView* inLeavingPage, Boolean /*inWillCache*/)
|
|
{
|
|
LView* view = (LView*)inLeavingPage->FindPaneByID('Attv');
|
|
if (view)
|
|
BroadcastMessage(msg_DeactivatingAttachTab, view);
|
|
else if ((LView*)inLeavingPage->FindPaneByID('Addr'))
|
|
{
|
|
BroadcastMessage(msg_DeactivatingAddressTab, nil);
|
|
}
|
|
}
|
|
|
|
//======================================
|
|
// class CMailOptionTabContainer : public CTabContainer
|
|
//======================================
|
|
CMailOptionTabContainer::CMailOptionTabContainer(LStream* inStream):CMailTabContainer(inStream)
|
|
{
|
|
|
|
}
|
|
|
|
void CMailOptionTabContainer::FinishCreateSelf()
|
|
{
|
|
CMailComposeWindow* window
|
|
= dynamic_cast<CMailComposeWindow*>(LWindow::FetchWindowObject(GetMacPort()));
|
|
if( window )
|
|
{
|
|
UReanimator::LinkListenerToControls( window, this, 10617);
|
|
}
|
|
}
|