📄 viewrich.cpp
字号:
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#ifdef AFX_CORE4_SEG
#pragma code_seg(AFX_CORE4_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// CReObject
class CReObject : public _reobject
{
public:
CReObject();
CReObject(CRichEditCntrItem* pItem);
~CReObject();
};
CReObject::CReObject()
{
cbStruct = sizeof(REOBJECT);
memset(&cbStruct+1, 0, sizeof(*this)-sizeof(cbStruct));
}
CReObject::CReObject(CRichEditCntrItem* pItem)
{
ASSERT(pItem != NULL);
cbStruct = sizeof(REOBJECT);
pItem->GetClassID(&clsid);
poleobj = pItem->m_lpObject;
pstg = pItem->m_lpStorage;
polesite = pItem->m_lpClientSite;
ASSERT(poleobj != NULL);
ASSERT(pstg != NULL);
ASSERT(polesite != NULL);
poleobj->AddRef();
pstg->AddRef();
polesite->AddRef();
sizel.cx = sizel.cy = 0; // let richedit determine initial size
dvaspect = pItem->GetDrawAspect();
dwFlags = REO_RESIZABLE;
dwUser = 0;
}
CReObject::~CReObject()
{
if (poleobj != NULL)
poleobj->Release();
if (pstg != NULL)
pstg->Release();
if (polesite != NULL)
polesite->Release();
}
/////////////////////////////////////////////////////////////////////////////
// CRichEditView
AFX_STATIC const UINT _afxMsgFindReplace2 = ::RegisterWindowMessage(FINDMSGSTRING);
BEGIN_MESSAGE_MAP(CRichEditView, CCtrlView)
//{{AFX_MSG_MAP(CRichEditView)
ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateNeedSel)
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateNeedClip)
ON_UPDATE_COMMAND_UI(ID_EDIT_FIND, OnUpdateNeedText)
ON_UPDATE_COMMAND_UI(ID_EDIT_REPEAT, OnUpdateNeedFind)
ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE_SPECIAL, OnUpdateEditPasteSpecial)
ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_PROPERTIES, OnUpdateEditProperties)
ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateNeedSel)
ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateNeedSel)
ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateNeedText)
ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACE, OnUpdateNeedText)
ON_COMMAND(ID_EDIT_CUT, OnEditCut)
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
ON_COMMAND(ID_EDIT_FIND, OnEditFind)
ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
ON_COMMAND(ID_EDIT_REPEAT, OnEditRepeat)
ON_COMMAND(ID_EDIT_PASTE_SPECIAL, OnEditPasteSpecial)
ON_COMMAND(ID_OLE_EDIT_PROPERTIES, OnEditProperties)
ON_COMMAND(ID_OLE_INSERT_NEW, OnInsertObject)
ON_COMMAND(ID_FORMAT_FONT, OnFormatFont)
ON_WM_SIZE()
ON_WM_CREATE()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
ON_NOTIFY_REFLECT(EN_SELCHANGE, OnSelChange)
ON_REGISTERED_MESSAGE(_afxMsgFindReplace2, OnFindReplaceCmd)
END_MESSAGE_MAP()
// richedit buffer limit -- let's set it at 16M
AFX_DATADEF ULONG CRichEditView::lMaxSize = 0xffffff;
/////////////////////////////////////////////////////////////////////////////
// CRichEditView construction/destruction
CRichEditView::CRichEditView() : CCtrlView(_T("RICHEDIT"), AFX_WS_DEFAULT_VIEW |
WS_HSCROLL | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL |
ES_MULTILINE | ES_NOHIDESEL | ES_SAVESEL | ES_SELECTIONBAR)
{
m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
m_lpRichEditOle = NULL;
m_nBulletIndent = 720; // 1/2 inch
m_nWordWrap = WrapToWindow;
m_nPasteType = 0;
SetPaperSize(CSize(8*1440+720, 11*1440));
SetMargins(CRect(0,0,0,0));
m_charformat.cbSize = sizeof(CHARFORMAT);
m_paraformat.cbSize = sizeof(PARAFORMAT);
}
BOOL CRichEditView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!AfxInitRichEdit())
return FALSE;
CCtrlView::PreCreateWindow(cs);
cs.lpszName = _T("");
cs.cx = cs.cy = 100; // necessary to avoid bug with ES_SELECTIONBAR and zero for cx and cy
cs.style |= WS_CLIPSIBLINGS;
return TRUE;
}
int CRichEditView::OnCreate(LPCREATESTRUCT lpcs)
{
if (CCtrlView::OnCreate(lpcs) != 0)
return -1;
GetRichEditCtrl().LimitText(lMaxSize);
GetRichEditCtrl().SetEventMask(ENM_SELCHANGE | ENM_CHANGE | ENM_SCROLL);
VERIFY(GetRichEditCtrl().SetOLECallback(&m_xRichEditOleCallback));
m_lpRichEditOle = GetRichEditCtrl().GetIRichEditOle();
DragAcceptFiles();
GetRichEditCtrl().SetOptions(ECOOP_OR, ECO_AUTOWORDSELECTION);
WrapChanged();
ASSERT(m_lpRichEditOle != NULL);
return 0;
}
void CRichEditView::OnInitialUpdate()
{
CCtrlView::OnInitialUpdate();
m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CRichEditView document like functions
void CRichEditView::DeleteContents()
{
ASSERT_VALID(this);
ASSERT(m_hWnd != NULL);
SetWindowText(_T(""));
GetRichEditCtrl().EmptyUndoBuffer();
m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
ASSERT_VALID(this);
}
void CRichEditView::WrapChanged()
{
CWaitCursor wait;
CRichEditCtrl& ctrl = GetRichEditCtrl();
if (m_nWordWrap == WrapNone)
ctrl.SetTargetDevice(NULL, 1);
else if (m_nWordWrap == WrapToWindow)
ctrl.SetTargetDevice(NULL, 0);
else if (m_nWordWrap == WrapToTargetDevice) // wrap to ruler
{
AfxGetApp()->CreatePrinterDC(m_dcTarget);
if (m_dcTarget.m_hDC == NULL)
m_dcTarget.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
ctrl.SetTargetDevice(m_dcTarget, GetPrintWidth());
}
}
/////////////////////////////////////////////////////////////////////////////
// CRichEditView serialization support
class _afxRichEditCookie
{
public:
CArchive& m_ar;
DWORD m_dwError;
_afxRichEditCookie(CArchive& ar) : m_ar(ar) {m_dwError=0;}
};
void CRichEditView::Serialize(CArchive& ar)
// Read and write CRichEditView object to archive, with length prefix.
{
ASSERT_VALID(this);
ASSERT(m_hWnd != NULL);
Stream(ar, FALSE);
ASSERT_VALID(this);
}
void CRichEditView::Stream(CArchive& ar, BOOL bSelection)
{
EDITSTREAM es = {0, 0, EditStreamCallBack};
_afxRichEditCookie cookie(ar);
es.dwCookie = (DWORD)&cookie;
int nFormat = GetDocument()->GetStreamFormat();
if (bSelection)
nFormat |= SFF_SELECTION;
if (ar.IsStoring())
GetRichEditCtrl().StreamOut(nFormat, es);
else
{
GetRichEditCtrl().StreamIn(nFormat, es);
Invalidate();
}
if (cookie.m_dwError != 0)
AfxThrowFileException(cookie.m_dwError);
}
// return 0 for no error, otherwise return error code
DWORD CALLBACK CRichEditView::EditStreamCallBack(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
_afxRichEditCookie* pCookie = (_afxRichEditCookie*)dwCookie;
CArchive& ar = pCookie->m_ar;
ar.Flush();
DWORD dw = 0;
*pcb = cb;
TRY
{
if (ar.IsStoring())
ar.GetFile()->WriteHuge(pbBuff, cb);
else
*pcb = ar.GetFile()->ReadHuge(pbBuff, cb);
}
CATCH(CFileException, e)
{
*pcb = 0;
pCookie->m_dwError = (DWORD)e->m_cause;
dw = 1;
DELETE_EXCEPTION(e);
}
AND_CATCH_ALL(e)
{
*pcb = 0;
pCookie->m_dwError = (DWORD)CFileException::generic;
dw = 1;
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
return dw;
}
/////////////////////////////////////////////////////////////////////////////
// CRichEditView Printing support
void CRichEditView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo*)
{
ASSERT_VALID(this);
// ASSERT_VALID(pDC);
// initialize page start vector
ASSERT(m_aPageStart.GetSize() == 0);
m_aPageStart.Add(0);
ASSERT(m_aPageStart.GetSize() > 0);
GetRichEditCtrl().FormatRange(NULL, FALSE); // required by RichEdit to clear out cache
ASSERT_VALID(this);
}
BOOL CRichEditView::PaginateTo(CDC* pDC, CPrintInfo* pInfo)
// attempts pagination to pInfo->m_nCurPage, TRUE == success
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
CRect rectSave = pInfo->m_rectDraw;
UINT nPageSave = pInfo->m_nCurPage;
ASSERT(nPageSave > 1);
ASSERT(nPageSave >= (UINT)m_aPageStart.GetSize());
VERIFY(pDC->SaveDC() != 0);
pDC->IntersectClipRect(0, 0, 0, 0);
pInfo->m_nCurPage = m_aPageStart.GetSize();
while (pInfo->m_nCurPage < nPageSave)
{
ASSERT(pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize());
OnPrepareDC(pDC, pInfo);
ASSERT(pInfo->m_bContinuePrinting);
pInfo->m_rectDraw.SetRect(0, 0,
pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
pDC->DPtoLP(&pInfo->m_rectDraw);
OnPrint(pDC, pInfo);
if (pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize())
break;
++pInfo->m_nCurPage;
}
BOOL bResult = pInfo->m_nCurPage == nPageSave;
pDC->RestoreDC(-1);
pInfo->m_nCurPage = nPageSave;
pInfo->m_rectDraw = rectSave;
ASSERT_VALID(this);
return bResult;
}
void CRichEditView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
ASSERT(pInfo != NULL); // overriding OnPaint -- never get this.
pDC->SetMapMode(MM_TEXT);
if (pInfo->m_nCurPage > (UINT)m_aPageStart.GetSize() &&
!PaginateTo(pDC, pInfo))
{
// can't paginate to that page, thus cannot print it.
pInfo->m_bContinuePrinting = FALSE;
}
ASSERT_VALID(this);
}
long CRichEditView::PrintPage(CDC* pDC, long nIndexStart, long nIndexStop)
// worker function for laying out text in a rectangle.
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
FORMATRANGE fr;
// offset by printing offset
pDC->SetViewportOrg(-pDC->GetDeviceCaps(PHYSICALOFFSETX),
-pDC->GetDeviceCaps(PHYSICALOFFSETY));
// adjust DC because richedit doesn't do things like MFC
if (::GetDeviceCaps(pDC->m_hDC, TECHNOLOGY) != DT_METAFILE && pDC->m_hAttribDC != NULL)
{
::ScaleWindowExtEx(pDC->m_hDC,
::GetDeviceCaps(pDC->m_hDC, LOGPIXELSX),
::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSX),
::GetDeviceCaps(pDC->m_hDC, LOGPIXELSY),
::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSY), NULL);
}
fr.hdcTarget = pDC->m_hAttribDC;
fr.hdc = pDC->m_hDC;
fr.rcPage = GetPageRect();
fr.rc = GetPrintRect();
fr.chrg.cpMin = nIndexStart;
fr.chrg.cpMax = nIndexStop;
long lRes = GetRichEditCtrl().FormatRange(&fr,TRUE);
return lRes;
}
long CRichEditView::PrintInsideRect(CDC* pDC, RECT& rectLayout,
long nIndexStart, long nIndexStop, BOOL bOutput)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
FORMATRANGE fr;
// adjust DC because richedit doesn't do things like MFC
if (::GetDeviceCaps(pDC->m_hDC, TECHNOLOGY) != DT_METAFILE && pDC->m_hAttribDC != NULL)
{
::ScaleWindowExtEx(pDC->m_hDC,
::GetDeviceCaps(pDC->m_hDC, LOGPIXELSX),
::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSX),
::GetDeviceCaps(pDC->m_hDC, LOGPIXELSY),
::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSY), NULL);
}
fr.hdcTarget = pDC->m_hAttribDC;
fr.hdc = pDC->m_hDC;
// convert rect to twips
fr.rcPage = rectLayout;
fr.rc = rectLayout;
fr.chrg.cpMin = nIndexStart;
fr.chrg.cpMax = nIndexStop;
GetRichEditCtrl().FormatRange(NULL, FALSE); // required by RichEdit to clear out cache
// if bOutput is FALSE, we only measure
long lres = GetRichEditCtrl().FormatRange(&fr, bOutput);
GetRichEditCtrl().FormatRange(NULL, FALSE); // required by RichEdit to clear out cache
rectLayout = fr.rc;
return lres;
}
void CRichEditView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
ASSERT(pInfo != NULL);
ASSERT(pInfo->m_bContinuePrinting);
UINT nPage = pInfo->m_nCurPage;
ASSERT(nPage <= (UINT)m_aPageStart.GetSize());
long nIndex = (long) m_aPageStart[nPage-1];
// print as much as possible in the current page.
nIndex = PrintPage(pDC, nIndex, 0xFFFFFFFF);
if (nIndex >= GetTextLength())
{
TRACE0("End of Document\n");
pInfo->SetMaxPage(nPage);
}
// update pagination information for page just printed
if (nPage == (UINT)m_aPageStart.GetSize())
{
if (nIndex < GetTextLength())
m_aPageStart.Add(nIndex);
}
else
{
ASSERT(nPage+1 <= (UINT)m_aPageStart.GetSize());
ASSERT(nIndex == (long)m_aPageStart[nPage+1-1]);
}
}
void CRichEditView::OnEndPrinting(CDC*, CPrintInfo*)
{
ASSERT_VALID(this);
GetRichEditCtrl().FormatRange(NULL, FALSE); // required by RichEdit to clear out cache
m_aPageStart.RemoveAll();
}
/////////////////////////////////////////////////////////////////////////////
// CRichEditView::XRichEditOleCallback
BEGIN_INTERFACE_MAP(CRichEditView, CCtrlView)
// we use IID_IUnknown because richedit doesn't define an IID
INTERFACE_PART(CRichEditView, IID_IUnknown, RichEditOleCallback)
END_INTERFACE_MAP()
STDMETHODIMP_(ULONG) CRichEditView::XRichEditOleCallback::AddRef()
{
METHOD_PROLOGUE_EX_(CRichEditView, RichEditOleCallback)
return (ULONG)pThis->InternalAddRef();
}
STDMETHODIMP_(ULONG) CRichEditView::XRichEditOleCallback::Release()
{
METHOD_PROLOGUE_EX_(CRichEditView, RichEditOleCallback)
return (ULONG)pThis->InternalRelease();
}
STDMETHODIMP CRichEditView::XRichEditOleCallback::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(CRichEditView, RichEditOleCallback)
return (HRESULT)pThis->InternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP CRichEditView::XRichEditOleCallback::GetNewStorage(LPSTORAGE* ppstg)
{
METHOD_PROLOGUE_EX_(CRichEditView, RichEditOleCallback)
// Create a flat storage and steal it from the client item
// the client item is only used for creating the storage
COleClientItem item;
item.GetItemStorageFlat();
*ppstg = item.m_lpStorage;
HRESULT hRes = E_OUTOFMEMORY;
if (item.m_lpStorage != NULL)
{
item.m_lpStorage = NULL;
hRes = S_OK;
}
pThis->GetDocument()->InvalidateObjectCache();
return hRes;
}
STDMETHODIMP CRichEditView::XRichEditOleCallback::GetInPlaceContext(
LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc,
LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
METHOD_PROLOGUE_EX(CRichEditView, RichEditOleCallback)
return pThis->GetWindowContext(lplpFrame, lplpDoc, lpFrameInfo);
}
STDMETHODIMP CRichEditView::XRichEditOleCallback::ShowContainerUI(BOOL fShow)
{
METHOD_PROLOGUE_EX(CRichEditView, RichEditOleCallback)
return pThis->ShowContainerUI(fShow);
}
STDMETHODIMP CRichEditView::XRichEditOleCallback::QueryInsertObject(
LPCLSID /*lpclsid*/, LPSTORAGE /*pstg*/, LONG /*cp*/)
{
METHOD_PROLOGUE_EX(CRichEditView, RichEditOleCallback)
pThis->GetDocument()->InvalidateObjectCache();
return S_OK;
}
STDMETHODIMP CRichEditView::XRichEditOleCallback::DeleteObject(LPOLEOBJECT /*lpoleobj*/)
{
METHOD_PROLOGUE_EX_(CRichEditView, RichEditOleCallback)
pThis->GetDocument()->InvalidateObjectCache();
return S_OK;
}
STDMETHODIMP CRichEditView::XRichEditOleCallback::QueryAcceptData(
LPDATAOBJECT lpdataobj, CLIPFORMAT* lpcfFormat, DWORD reco,
BOOL fReally, HGLOBAL hMetaPict)
{
METHOD_PROLOGUE_EX(CRichEditView, RichEditOleCallback)
return pThis->QueryAcceptData(lpdataobj, lpcfFormat, reco,
fReally, hMetaPict);
}
STDMETHODIMP CRichEditView::XRichEditOleCallback::ContextSensitiveHelp(BOOL /*fEnterMode*/)
{
return E_NOTIMPL;
}
STDMETHODIMP CRichEditView::XRichEditOleCallback::GetClipboardData(
CHARRANGE* lpchrg, DWORD reco, LPDATAOBJECT* lplpdataobj)
{
METHOD_PROLOGUE_EX(CRichEditView, RichEditOleCallback)
LPDATAOBJECT lpOrigDataObject = NULL;
// get richedit's data object
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -