mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
558 lines
14 KiB
C++
558 lines
14 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) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
/* COMPMISC.CPP - Contains controls which are utilized in the compose
|
|
* window address/attachment block. Also contains the resizer control
|
|
* which resizes the text edit control
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "compmisc.h"
|
|
#include "compfrm.h"
|
|
#include "compbar.h"
|
|
#include "findrepl.h"
|
|
#include "spellcli.h" // spell checker client
|
|
#include "prefapi.h"
|
|
|
|
#ifdef XP_WIN32
|
|
#define EDIT_CONTROL_BUFFER_SIZE UINT_MAX
|
|
#else
|
|
#define EDIT_CONTROL_BUFFER_SIZE ((UINT)(32*1024))
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CBlankWnd - resizes the edit control and restores focus to the appropriate
|
|
// field.
|
|
|
|
BEGIN_MESSAGE_MAP(CBlankWnd,CWnd)
|
|
ON_EN_CHANGE(IDC_COMPOSEEDITOR,OnChange)
|
|
ON_WM_ERASEBKGND()
|
|
ON_WM_SIZE()
|
|
ON_WM_SETFOCUS()
|
|
ON_WM_PAINT()
|
|
ON_WM_CREATE()
|
|
ON_WM_DESTROY()
|
|
END_MESSAGE_MAP()
|
|
|
|
#define INDICATOR_WIDTH 5
|
|
#define INDICATOR_COLOR RGB(113,113,255)
|
|
|
|
PR_CALLBACK PrefSetWrapCol(const char *pPref, void *pData)
|
|
{
|
|
int32 iCol;
|
|
PREF_GetIntPref("mailnews.wraplength", &iCol);
|
|
|
|
CBlankWnd * pEditorWindow = (CBlankWnd *)pData;
|
|
pEditorWindow->SetWrapCol(iCol);
|
|
pEditorWindow->Invalidate(TRUE);// must pass TRUE
|
|
}
|
|
|
|
int CBlankWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{
|
|
if (CWnd::OnCreate(lpCreateStruct) == -1)
|
|
return -1;
|
|
|
|
m_lWrapCol = 0L;
|
|
|
|
//register call back for wrap long line
|
|
PREF_RegisterCallback("mailnews.wraplength", PrefSetWrapCol, (void *)this);
|
|
PREF_GetIntPref("mailnews.wraplength",&m_lWrapCol);
|
|
return 0;
|
|
}
|
|
|
|
void CBlankWnd::OnDestroy()
|
|
{
|
|
PREF_UnregisterCallback("mailnews.wraplength", PrefSetWrapCol, this);
|
|
CWnd::OnDestroy();
|
|
}
|
|
|
|
void CBlankWnd::OnPaint()
|
|
{
|
|
CPaintDC dc(this);
|
|
CComposeFrame * pFrame = (CComposeFrame*)GetParentFrame();
|
|
if (pFrame->GetWrapLongLines())
|
|
{
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
int iPos = ((int)GetWrapCol()) * pFrame->GetCharWidth();
|
|
if (iPos < rect.Width())
|
|
{
|
|
CPen pen(PS_SOLID,1,INDICATOR_COLOR);
|
|
CPen * pOldPen = dc.SelectObject(&pen);
|
|
iPos -= (INDICATOR_WIDTH/2);
|
|
dc.MoveTo(iPos,1);
|
|
dc.LineTo(iPos+INDICATOR_WIDTH,1);
|
|
dc.MoveTo(iPos+1,2);
|
|
dc.LineTo((iPos+INDICATOR_WIDTH)-1,2);
|
|
dc.SetPixel(iPos+2,3,INDICATOR_COLOR);
|
|
dc.SelectObject(pOldPen);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CBlankWnd::OnSetFocus(CWnd *)
|
|
{
|
|
// when focus is given to this window... focus is passed off to the
|
|
// last field which had focus.
|
|
CComposeFrame * pFrame = (CComposeFrame*)GetParentFrame();
|
|
if (pFrame->GetFocusField() && IsWindow(pFrame->GetFocusField()->m_hWnd))
|
|
pFrame->GetFocusField()->SetFocus();
|
|
}
|
|
|
|
void CBlankWnd::OnChange(void)
|
|
{
|
|
// the backend should be notified that the text has been
|
|
// changed whener an edit occurs
|
|
CComposeFrame * pFrame = (CComposeFrame*)GetParentFrame();
|
|
m_bModified = TRUE;
|
|
}
|
|
|
|
BOOL CBlankWnd::OnEraseBkgnd (CDC * pdc)
|
|
{
|
|
// erase the background with the default brush
|
|
CRect rect;
|
|
CBrush Brush(GetSysColor(COLOR_WINDOW));
|
|
GetClientRect (&rect);
|
|
pdc->FillRect (rect, &Brush);
|
|
return TRUE;
|
|
}
|
|
|
|
void CBlankWnd::OnSize ( UINT nType, int cx, int cy )
|
|
{
|
|
// resize the editor whenver this window is resized.
|
|
// a border is given on the left so that the cursor doesn't
|
|
// but right up against the edge (looks bad)
|
|
CWnd::OnSize ( nType, cx, cy );
|
|
CRect rect ( EDIT_MARGIN_OFFSET, EDIT_TOP_MARGIN, cx, cy );
|
|
CComposeFrame * pFrame = (CComposeFrame*)GetParent()->GetParent();
|
|
if (IsWindow(pFrame->GetEditor()->m_hWnd))
|
|
pFrame->GetEditor()->MoveWindow ( rect );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CComposeEdit - This is the regular text edit control. This is probably
|
|
//
|
|
|
|
BEGIN_MESSAGE_MAP(CComposeEdit, CGenericEdit)
|
|
ON_WM_KEYDOWN()
|
|
ON_WM_CREATE()
|
|
ON_WM_SETFOCUS()
|
|
ON_COMMAND(ID_CHECK_SPELLING, OnCheckSpelling)
|
|
// edit menu
|
|
ON_COMMAND(ID_EDIT_CUT,OnCut)
|
|
ON_COMMAND(ID_EDIT_COPY,OnCopy)
|
|
ON_COMMAND(ID_EDIT_PASTE,OnPaste)
|
|
ON_COMMAND(ID_EDIT_UNDO,OnUndo)
|
|
ON_COMMAND(idm_redo,OnRedo)
|
|
ON_COMMAND(ID_EDIT_DELETE,OnDelete)
|
|
ON_COMMAND(IDM_SELECTALL,OnSelectAll)
|
|
ON_COMMAND(IDM_FINDAGAIN,OnFindAgain)
|
|
ON_COMMAND(IDM_FINDINMESSAGE,OnFindInMessage)
|
|
ON_REGISTERED_MESSAGE(WM_FINDREPLACE, OnFindReplace)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_CUT,OnUpdateCut)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_COPY,OnUpdateCopy)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE,OnUpdatePaste)
|
|
ON_UPDATE_COMMAND_UI(IDM_PASTEASQUOTE,OnUpdatePasteAsQuote)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO,OnUpdateUndo)
|
|
ON_UPDATE_COMMAND_UI(ID_EDIT_DELETE,OnUpdateDelete)
|
|
ON_UPDATE_COMMAND_UI(IDM_SELECTALL,OnUpdateSelectAll)
|
|
ON_UPDATE_COMMAND_UI(IDM_FINDINMESSAGE,OnUpdateFindInMessage)
|
|
ON_UPDATE_COMMAND_UI(IDM_FINDAGAIN,OnUpdateFindAgain)
|
|
END_MESSAGE_MAP()
|
|
|
|
CComposeEdit::CComposeEdit(CComposeFrame * pFrame)
|
|
{
|
|
m_pComposeFrame = pFrame;
|
|
m_cxChar = 1;
|
|
#ifdef XP_WIN16
|
|
// win16 edit control's memory is by default, allocated from the heap.. which is
|
|
// usually not enough.... so create a 32K message buffer
|
|
m_hTextElementSegment = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, EDIT_CONTROL_BUFFER_SIZE);
|
|
#endif
|
|
}
|
|
|
|
CComposeEdit::~CComposeEdit()
|
|
{
|
|
#ifdef XP_WIN16
|
|
// free up the 16bit memory buffer
|
|
if (m_hTextElementSegment)
|
|
GlobalFree(m_hTextElementSegment);
|
|
#endif
|
|
}
|
|
|
|
#ifdef XP_WIN16
|
|
//
|
|
// The creator of this form element should have created a segment for
|
|
// us to live in before we got here. Tell Windows to use that
|
|
// segment rather than the application's so that we don't run out of
|
|
// DGROUP space
|
|
//
|
|
BOOL CComposeEdit::PreCreateWindow( CREATESTRUCT& cs )
|
|
{
|
|
// during a precreate in happy 16bit land, lock the edit data
|
|
// buffer and tell the control to use it.
|
|
if (CGenericEdit::PreCreateWindow(cs)) {
|
|
|
|
ASSERT(m_hTextElementSegment);
|
|
|
|
if(!m_hTextElementSegment)
|
|
return TRUE;
|
|
|
|
LPVOID lpEditDC = (LPVOID) GlobalLock(m_hTextElementSegment);
|
|
|
|
if (lpEditDC) {
|
|
UINT uSegment = HIWORD((LONG) lpEditDC);
|
|
if (LocalInit((UINT)uSegment,0,(WORD)(GlobalSize(m_hTextElementSegment)-16))) {
|
|
cs.hInstance = (HINSTANCE) uSegment;
|
|
UnlockSegment(uSegment);
|
|
}
|
|
else
|
|
GlobalUnlock(m_hTextElementSegment);
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
void CComposeEdit::OnSetFocus(CWnd * pWnd)
|
|
{
|
|
// When focus is set to the edit field, tell the parent
|
|
CGenericEdit::OnSetFocus(pWnd);
|
|
CComposeFrame * pFrame = (CComposeFrame*)GetParentFrame();
|
|
pFrame->SetFocusField(this);
|
|
}
|
|
|
|
int CComposeEdit::OnCreate ( LPCREATESTRUCT lpcs )
|
|
{
|
|
// set up the fonts, get the character size
|
|
int iRet = CGenericEdit::OnCreate ( lpcs );
|
|
|
|
LimitText(EDIT_CONTROL_BUFFER_SIZE);
|
|
|
|
CClientDC dc ( this );
|
|
LOGFONT lf;
|
|
XP_MEMSET(&lf,0,sizeof(LOGFONT));
|
|
CComposeFrame * pFrame = (CComposeFrame*)GetParentFrame();
|
|
lf.lfPitchAndFamily = FF_MODERN | FIXED_PITCH;
|
|
strcpy(lf.lfFaceName, IntlGetUIFixFaceName(pFrame->m_iCSID));
|
|
lf.lfCharSet = IntlGetLfCharset(pFrame->m_iCSID);
|
|
lf.lfHeight = -MulDiv(9,dc.GetDeviceCaps(LOGPIXELSY), 72);
|
|
lf.lfQuality = PROOF_QUALITY;
|
|
|
|
if (m_cfRegFont) {
|
|
theApp.ReleaseAppFont(m_cfRegFont);
|
|
}
|
|
m_cfRegFont = theApp.CreateAppFont( lf );
|
|
|
|
TEXTMETRIC tm;
|
|
CFont * pOldFont = dc.SelectObject(CFont::FromHandle(m_cfRegFont));
|
|
dc.GetTextMetrics(&tm);
|
|
dc.SelectObject(pOldFont);
|
|
m_cxChar = tm.tmAveCharWidth;
|
|
::SendMessage(GetSafeHwnd(), WM_SETFONT, (WPARAM)m_cfRegFont, FALSE);
|
|
|
|
return iRet;
|
|
}
|
|
|
|
void CComposeEdit::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags )
|
|
{
|
|
// process the tab key so that it properly tabs between the
|
|
// address block and the editor.
|
|
if ((nChar==VK_TAB)&&(GetKeyState(VK_SHIFT)&0x8000)) {
|
|
CComposeFrame * pFrame = (CComposeFrame*)GetParentFrame();
|
|
MSG msg;
|
|
while (PeekMessage(&msg,m_hWnd,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE))
|
|
;
|
|
CComposeBar * pBar = pFrame->GetComposeBar();
|
|
ASSERT(pBar);
|
|
if (pBar)
|
|
pBar->m_pSubjectEdit->SetFocus();
|
|
}
|
|
else
|
|
{
|
|
CGenericEdit::OnKeyDown(nChar,nRepCnt,nFlags);
|
|
}
|
|
}
|
|
|
|
void CComposeEdit::OnCheckSpelling()
|
|
{
|
|
CPlainTextSpellChecker SpellChecker(this);
|
|
|
|
if (SpellChecker.ProcessDocument() != 0)
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
void CComposeEdit::OnCut()
|
|
{
|
|
Cut();
|
|
}
|
|
|
|
void CComposeEdit::OnCopy()
|
|
{
|
|
Copy();
|
|
}
|
|
|
|
void CComposeEdit::OnPaste()
|
|
{
|
|
Paste();
|
|
}
|
|
|
|
void CComposeEdit::OnUndo()
|
|
{
|
|
Undo();
|
|
}
|
|
|
|
void CComposeEdit::OnRedo()
|
|
{
|
|
}
|
|
|
|
void CComposeEdit::OnDelete()
|
|
{
|
|
if (GetFocus() == this)
|
|
Clear();
|
|
}
|
|
|
|
void CComposeEdit::OnFindInMessage()
|
|
{
|
|
CNetscapeFindReplaceDialog *dlg;
|
|
dlg = new CNetscapeFindReplaceDialog();
|
|
dlg->Create(TRUE,
|
|
theApp.m_csFindString,
|
|
NULL,
|
|
FR_DOWN | FR_NOWHOLEWORD | FR_HIDEWHOLEWORD | FR_NOUPDOWN,
|
|
GetParentFrame());
|
|
}
|
|
|
|
void CComposeEdit::OnFindAgain()
|
|
{
|
|
FindText();
|
|
}
|
|
|
|
void CComposeEdit::OnUpdateCut(CCmdUI * pCmdUI)
|
|
{
|
|
if (GetFocus() == this)
|
|
pCmdUI->Enable(IsSelection());
|
|
}
|
|
|
|
void CComposeEdit::OnUpdateCopy(CCmdUI * pCmdUI)
|
|
{
|
|
if (GetFocus() == this)
|
|
pCmdUI->Enable(IsSelection());
|
|
}
|
|
|
|
void CComposeEdit::OnUpdatePaste(CCmdUI * pCmdUI)
|
|
{
|
|
if (GetFocus() == this)
|
|
pCmdUI->Enable(IsClipboardData());
|
|
}
|
|
|
|
BOOL CComposeEdit::IsSelection()
|
|
{
|
|
int nStart, nEnd;
|
|
GetSel(nStart,nEnd);
|
|
return ((nEnd-nStart)>0);
|
|
}
|
|
|
|
BOOL CComposeEdit::IsClipboardData()
|
|
{
|
|
BOOL retVal = FALSE;
|
|
OpenClipboard();
|
|
|
|
if (GetClipboardData(CF_TEXT)) {
|
|
retVal = TRUE;
|
|
}
|
|
CloseClipboard();
|
|
return retVal;
|
|
}
|
|
|
|
void CComposeEdit::OnUpdatePasteAsQuote(CCmdUI * pCmdUI)
|
|
{
|
|
if (GetFocus() == this)
|
|
pCmdUI->Enable(IsClipboardData());
|
|
}
|
|
|
|
void CComposeEdit::OnUpdateUndo(CCmdUI * pCmdUI)
|
|
{
|
|
if (GetFocus() == this)
|
|
pCmdUI->Enable(CanUndo());
|
|
}
|
|
|
|
void CComposeEdit::OnUpdateDelete(CCmdUI * pCmdUI)
|
|
{
|
|
if (GetFocus() == this)
|
|
pCmdUI->Enable(IsSelection());
|
|
}
|
|
|
|
void CComposeEdit::OnUpdateFindInMessage(CCmdUI * pCmdUI)
|
|
{
|
|
if ( GetWindowTextLength() > 0 && (GetFocus() == this))
|
|
pCmdUI->Enable(TRUE);
|
|
else
|
|
pCmdUI->Enable(FALSE);
|
|
}
|
|
|
|
void CComposeEdit::OnUpdateFindAgain(CCmdUI * pCmdUI)
|
|
{
|
|
if ((theApp.m_csFindString && strlen(theApp.m_csFindString)) && (GetFocus() == this))
|
|
pCmdUI->Enable(TRUE);
|
|
else
|
|
pCmdUI->Enable(FALSE);
|
|
}
|
|
|
|
void CComposeEdit::OnSelectAll()
|
|
{
|
|
SetSel(0,-1);
|
|
SetFocus();
|
|
}
|
|
|
|
void CComposeEdit::OnUpdateSelectAll(CCmdUI *pCmdUI)
|
|
{
|
|
pCmdUI->Enable(TRUE);
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(CComposeSubjectEdit, CGenericEdit)
|
|
ON_WM_SETFOCUS()
|
|
ON_WM_KILLFOCUS()
|
|
END_MESSAGE_MAP()
|
|
|
|
void CComposeSubjectEdit::OnSetFocus(CWnd * pWnd)
|
|
{
|
|
// When focus is set to the edit field, tell the parent
|
|
CGenericEdit::OnSetFocus(pWnd);
|
|
CComposeFrame * pFrame = (CComposeFrame*)GetParentFrame();
|
|
pFrame->SetFocusField(this);
|
|
}
|
|
|
|
void CComposeSubjectEdit::OnKillFocus(CWnd * pWnd)
|
|
{
|
|
CGenericEdit::OnKillFocus(pWnd);
|
|
CComposeFrame * pFrame = (CComposeFrame*)GetParentFrame();
|
|
CString cs;
|
|
GetWindowText(cs);
|
|
if (cs.GetLength())
|
|
pFrame->GetChrome()->SetDocumentTitle(cs);
|
|
}
|
|
|
|
BOOL CComposeSubjectEdit::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
if (pMsg->message == WM_KEYDOWN)
|
|
{
|
|
if (pMsg->wParam == VK_RETURN)
|
|
{
|
|
CComposeFrame * pFrame = (CComposeFrame*)GetParentFrame();
|
|
pFrame->GetComposeBar()->TabControl(FALSE,FALSE,this);
|
|
return TRUE;
|
|
}
|
|
|
|
if (pMsg->wParam == 'v' || pMsg->wParam == 'V')
|
|
{
|
|
if (GetKeyState(VK_CONTROL)&0x8000)
|
|
{
|
|
Paste();
|
|
return TRUE;
|
|
}
|
|
}
|
|
else if (pMsg->wParam == VK_INSERT)
|
|
{
|
|
if (GetKeyState(VK_SHIFT)&0x8000)
|
|
{
|
|
Paste();
|
|
return TRUE;
|
|
}
|
|
else if (GetKeyState(VK_CONTROL)&0x8000)
|
|
{
|
|
Copy();
|
|
return TRUE;
|
|
}
|
|
}
|
|
else if (pMsg->wParam == 'x' || pMsg->wParam == 'X')
|
|
{
|
|
if (GetKeyState(VK_CONTROL)&0x8000)
|
|
{
|
|
Cut();
|
|
return TRUE;
|
|
}
|
|
}
|
|
else if (pMsg->wParam == 'c' || pMsg->wParam == 'C')
|
|
{
|
|
if (GetKeyState(VK_CONTROL)&0x8000)
|
|
{
|
|
Copy();
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return CEdit::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
LRESULT CComposeEdit::OnFindReplace(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CFindReplaceDialog * dlg = ::CFindReplaceDialog::GetNotifier(lParam);
|
|
if (!dlg)
|
|
return NULL;
|
|
|
|
FINDREPLACE findstruct = dlg->m_fr;
|
|
|
|
if (dlg->IsTerminating()) {
|
|
return NULL;
|
|
}
|
|
|
|
// Something wrong or user cancelled dialog box
|
|
if(!(findstruct.Flags & FR_FINDNEXT))
|
|
return NULL;
|
|
|
|
// remember this string for next time
|
|
theApp.m_csFindString = findstruct.lpstrFindWhat;
|
|
theApp.m_csReplaceString = findstruct.lpstrReplaceWith;
|
|
theApp.m_bMatchCase = dlg->MatchCase();
|
|
theApp.m_bSearchDown = dlg->SearchDown();
|
|
|
|
return (LRESULT) FindText();
|
|
}
|
|
|
|
BOOL CComposeEdit::FindText()
|
|
{
|
|
CString cs, csSearch = theApp.m_csFindString;
|
|
GetWindowText(cs);
|
|
|
|
int nStart, nEnd;
|
|
GetSel(nStart,nEnd);
|
|
|
|
if (!theApp.m_bMatchCase)
|
|
{
|
|
cs.MakeLower();
|
|
csSearch.MakeLower();
|
|
}
|
|
if (!cs.IsEmpty())
|
|
{
|
|
int ipos = nEnd;
|
|
int ipos2;
|
|
LPCSTR lpcstr = cs;
|
|
if ((ipos2 = CString(&lpcstr[ipos]).Find(csSearch)) != -1)
|
|
{
|
|
SetSel(ipos + ipos2, ipos + ipos2 + strlen(csSearch));
|
|
return(TRUE);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|