You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1697 lines
48 KiB
1697 lines
48 KiB
// wordpvw.cpp : implementation of the CWordPadView class
|
|
//
|
|
// Copyright (C) 1992-1999 Microsoft Corporation
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "wordpad.h"
|
|
#include "cntritem.h"
|
|
#include "srvritem.h"
|
|
|
|
#include "wordpdoc.h"
|
|
#include "wordpvw.h"
|
|
#include "formatta.h"
|
|
#include "datedial.h"
|
|
#include "formatpa.h"
|
|
#include "formatba.h"
|
|
#include "ruler.h"
|
|
#include "strings.h"
|
|
#include "colorlis.h"
|
|
#include "pageset.h"
|
|
#include <penwin.h>
|
|
#include "fixhelp.h"
|
|
|
|
#include <afxprntx.h>
|
|
#include "dlgprnt2.cpp"
|
|
#ifndef PD_CURRENTPAGE
|
|
#define PD_CURRENTPAGE 0x00400000
|
|
#define PD_NOCURRENTPAGE 0x00800000
|
|
#endif
|
|
|
|
extern CLIPFORMAT cfEmbeddedObject;
|
|
extern CLIPFORMAT cfRTO;
|
|
|
|
BOOL g_fInternalDragDrop = FALSE ;
|
|
BOOL g_fRightButtonDrag = FALSE;
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
#endif
|
|
|
|
|
|
BOOL CWordPadView::m_bIsMirrored = FALSE;
|
|
|
|
|
|
BOOL CCharFormat::operator==(CCharFormat& cf)
|
|
{
|
|
return
|
|
dwMask == cf.dwMask
|
|
&& dwEffects == cf.dwEffects
|
|
&& yHeight == cf.yHeight
|
|
&& yOffset == cf.yOffset
|
|
&& crTextColor == cf.crTextColor
|
|
&& bPitchAndFamily == cf.bPitchAndFamily
|
|
&& (lstrcmp(szFaceName, cf.szFaceName) == 0);
|
|
}
|
|
|
|
BOOL CParaFormat::operator==(PARAFORMAT& pf)
|
|
{
|
|
if(
|
|
dwMask != pf.dwMask
|
|
|| wNumbering != pf.wNumbering
|
|
|| wReserved != pf.wReserved
|
|
|| dxStartIndent != pf.dxStartIndent
|
|
|| dxRightIndent != pf.dxRightIndent
|
|
|| dxOffset != pf.dxOffset
|
|
|| cTabCount != pf.cTabCount
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
for (int i=0;i<pf.cTabCount;i++)
|
|
{
|
|
if (rgxTabs[i] != pf.rgxTabs[i])
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWordPadView
|
|
|
|
IMPLEMENT_DYNCREATE(CWordPadView, CRichEdit2View)
|
|
|
|
//WM_WININICHANGE -- default printer might have changed
|
|
//WM_FONTCHANGE -- pool of fonts changed
|
|
//WM_DEVMODECHANGE -- printer settings changes
|
|
|
|
BEGIN_MESSAGE_MAP(CWordPadView, CRichEdit2View)
|
|
ON_COMMAND(ID_OLE_INSERT_NEW, OnInsertObject)
|
|
ON_COMMAND(ID_CANCEL_EDIT_CNTR, OnCancelEditCntr)
|
|
ON_COMMAND(ID_CANCEL_EDIT_SRVR, OnCancelEditSrvr)
|
|
//{{AFX_MSG_MAP(CWordPadView)
|
|
ON_COMMAND(ID_PAGE_SETUP, OnPageSetup)
|
|
ON_COMMAND(ID_CHAR_BOLD, OnCharBold)
|
|
ON_UPDATE_COMMAND_UI(ID_CHAR_BOLD, OnUpdateCharBold)
|
|
ON_COMMAND(ID_CHAR_ITALIC, OnCharItalic)
|
|
ON_UPDATE_COMMAND_UI(ID_CHAR_ITALIC, OnUpdateCharItalic)
|
|
ON_COMMAND(ID_CHAR_UNDERLINE, OnCharUnderline)
|
|
ON_UPDATE_COMMAND_UI(ID_CHAR_UNDERLINE, OnUpdateCharUnderline)
|
|
ON_COMMAND(ID_PARA_CENTER, OnParaCenter)
|
|
ON_UPDATE_COMMAND_UI(ID_PARA_CENTER, OnUpdateParaCenter)
|
|
ON_COMMAND(ID_PARA_LEFT, OnParaLeft)
|
|
ON_UPDATE_COMMAND_UI(ID_PARA_LEFT, OnUpdateParaLeft)
|
|
ON_COMMAND(ID_PARA_RIGHT, OnParaRight)
|
|
ON_UPDATE_COMMAND_UI(ID_PARA_RIGHT, OnUpdateParaRight)
|
|
ON_WM_CREATE()
|
|
ON_COMMAND(ID_INSERT_DATE_TIME, OnInsertDateTime)
|
|
ON_COMMAND(ID_FORMAT_PARAGRAPH, OnFormatParagraph)
|
|
ON_COMMAND(ID_FORMAT_FONT, OnFormatFont)
|
|
ON_COMMAND(ID_EDIT_PASTE_SPECIAL, OnEditPasteSpecial)
|
|
ON_COMMAND(ID_OLE_EDIT_PROPERTIES, OnEditProperties)
|
|
ON_COMMAND(ID_EDIT_FIND, OnEditFind)
|
|
ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
|
|
ON_COMMAND(ID_FORMAT_TABS, OnFormatTabs)
|
|
ON_COMMAND(ID_COLOR16, OnColorDefault)
|
|
ON_WM_TIMER()
|
|
ON_WM_DESTROY()
|
|
ON_WM_MEASUREITEM()
|
|
ON_COMMAND(ID_PEN_BACKSPACE, OnPenBackspace)
|
|
ON_COMMAND(ID_PEN_NEWLINE, OnPenNewline)
|
|
ON_COMMAND(ID_PEN_PERIOD, OnPenPeriod)
|
|
ON_COMMAND(ID_PEN_SPACE, OnPenSpace)
|
|
ON_WM_SIZE()
|
|
ON_WM_KEYDOWN()
|
|
ON_COMMAND(ID_FILE_PRINT, OnFilePrint)
|
|
ON_COMMAND(ID_FILE_PRINT_DIRECT, OnFilePrint)
|
|
ON_WM_DROPFILES()
|
|
ON_COMMAND(ID_PEN_LENS, OnPenLens)
|
|
ON_COMMAND(ID_PEN_TAB, OnPenTab)
|
|
ON_COMMAND(ID_DELAYED_INVALIDATE, OnDelayedInvalidate)
|
|
ON_WM_PALETTECHANGED()
|
|
ON_WM_QUERYNEWPALETTE()
|
|
ON_WM_WININICHANGE()
|
|
//}}AFX_MSG_MAP
|
|
// Standard printing commands
|
|
ON_COMMAND(ID_INSERT_BULLET, CRichEdit2View::OnBullet)
|
|
ON_UPDATE_COMMAND_UI(ID_INSERT_BULLET, CRichEdit2View::OnUpdateBullet)
|
|
ON_COMMAND(ID_FILE_PRINT_PREVIEW, OnFilePrintPreview)
|
|
ON_COMMAND_RANGE(ID_COLOR0, ID_COLOR16, OnColorPick)
|
|
ON_EN_CHANGE(AFX_IDW_PANE_FIRST, OnEditChange)
|
|
ON_WM_MOUSEACTIVATE()
|
|
ON_REGISTERED_MESSAGE(CWordPadApp::m_nPrinterChangedMsg, OnPrinterChangedMsg)
|
|
ON_NOTIFY(FN_GETFORMAT, ID_VIEW_FORMATBAR, OnGetCharFormat)
|
|
ON_NOTIFY(FN_SETFORMAT, ID_VIEW_FORMATBAR, OnSetCharFormat)
|
|
ON_NOTIFY(NM_SETFOCUS, ID_VIEW_FORMATBAR, OnBarSetFocus)
|
|
ON_NOTIFY(NM_KILLFOCUS, ID_VIEW_FORMATBAR, OnBarKillFocus)
|
|
ON_NOTIFY(NM_RETURN, ID_VIEW_FORMATBAR, OnBarReturn)
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWordPadView construction/destruction
|
|
|
|
CWordPadView::CWordPadView()
|
|
{
|
|
m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
|
|
m_uTimerID = 0;
|
|
m_bDelayUpdateItems = FALSE;
|
|
m_bOnBar = FALSE;
|
|
m_bInPrint = FALSE;
|
|
m_nPasteType = 0;
|
|
m_rectMargin = theApp.m_rectPageMargin;
|
|
}
|
|
|
|
BOOL CWordPadView::PreCreateWindow(CREATESTRUCT& cs)
|
|
{
|
|
BOOL bRes = CRichEdit2View::PreCreateWindow(cs);
|
|
cs.style |= ES_SELECTIONBAR;
|
|
return bRes;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWordPadView attributes
|
|
|
|
BOOL CWordPadView::IsFormatText()
|
|
{
|
|
// this function checks to see if any formatting is not default text
|
|
BOOL bRes = FALSE;
|
|
CHARRANGE cr;
|
|
CCharFormat cf;
|
|
CParaFormat pf;
|
|
GetRichEditCtrl().GetSel(cr);
|
|
GetRichEditCtrl().HideSelection(TRUE, FALSE);
|
|
GetRichEditCtrl().SetSel(0,-1);
|
|
|
|
if (!(GetRichEditCtrl().GetSelectionType() & (SEL_OBJECT|SEL_MULTIOBJECT)))
|
|
{
|
|
GetRichEditCtrl().GetSelectionCharFormat(cf);
|
|
|
|
//
|
|
// Richedit sometimes returns these masks which are not important to us
|
|
//
|
|
|
|
cf.dwMask &= ~(CFM_LINK | CFM_CHARSET) ;
|
|
|
|
//
|
|
// Richedit sometimes returns the wrong thing here. This is not that
|
|
// important for the CHARFORMAT comparison, but it fouls things up if
|
|
// we don't work around it.
|
|
//
|
|
|
|
CCharFormat defCF;
|
|
GetDefaultFont(defCF, TRUE);
|
|
|
|
cf.bPitchAndFamily = defCF.bPitchAndFamily ;
|
|
|
|
if (cf == defCF)
|
|
{
|
|
GetRichEditCtrl().GetParaFormat(pf);
|
|
|
|
// These get reset in SetDefaultFont so be symmetric.
|
|
pf.dwMask &= ~ (PFM_RTLPARA | PFM_ALIGNMENT);
|
|
|
|
if (pf == m_defParaFormat)
|
|
bRes = TRUE;
|
|
}
|
|
}
|
|
|
|
GetRichEditCtrl().SetSel(cr);
|
|
GetRichEditCtrl().HideSelection(FALSE, FALSE);
|
|
return bRes;
|
|
}
|
|
|
|
HMENU CWordPadView::GetContextMenu(WORD, LPOLEOBJECT, CHARRANGE* )
|
|
{
|
|
CRichEdit2CntrItem* pItem = GetSelectedItem();
|
|
if (pItem == NULL || !pItem->IsInPlaceActive())
|
|
{
|
|
CMenu menuText;
|
|
menuText.LoadMenu(IDR_TEXT_POPUP);
|
|
CMenu* pMenuPopup = menuText.GetSubMenu(0);
|
|
menuText.RemoveMenu(0, MF_BYPOSITION);
|
|
if (!GetSystemMetrics(SM_PENWINDOWS))
|
|
{
|
|
//delete pen specific stuff
|
|
// remove Insert Keystrokes
|
|
pMenuPopup->DeleteMenu(ID_PEN_LENS, MF_BYCOMMAND);
|
|
int nIndex = pMenuPopup->GetMenuItemCount()-1; //index of last item
|
|
// remove Edit Text...
|
|
pMenuPopup->DeleteMenu(nIndex, MF_BYPOSITION);
|
|
// remove separator
|
|
pMenuPopup->DeleteMenu(nIndex-1, MF_BYPOSITION);
|
|
}
|
|
return pMenuPopup->Detach();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWordPadView operations
|
|
void CWordPadView::MirrorTheContainer(BOOL bMirror)
|
|
{
|
|
// if WordPad not mirrored, then don't do anything
|
|
LONG lExStyle;
|
|
if (!m_bIsMirrored)
|
|
return;
|
|
|
|
CWnd *pWnd = AfxGetMainWnd() ;
|
|
if (NULL == pWnd)
|
|
return ;
|
|
lExStyle = (LONG)::GetWindowLongPtr(pWnd->m_hWnd , GWL_EXSTYLE);
|
|
if (bMirror)
|
|
lExStyle |= WS_EX_LAYOUTRTL;
|
|
else
|
|
lExStyle &= ~WS_EX_LAYOUTRTL;
|
|
::SetWindowLongPtr(pWnd->m_hWnd , GWL_EXSTYLE , lExStyle);
|
|
}
|
|
|
|
void CWordPadView::WrapChanged()
|
|
{
|
|
CWaitCursor wait;
|
|
CFrameWnd* pFrameWnd = GetParentFrame();
|
|
ASSERT(pFrameWnd != NULL);
|
|
pFrameWnd->SetMessageText(IDS_FORMATTING);
|
|
CWnd* pBarWnd = pFrameWnd->GetMessageBar();
|
|
if (pBarWnd != NULL)
|
|
pBarWnd->UpdateWindow();
|
|
|
|
CRichEdit2View::WrapChanged();
|
|
|
|
pFrameWnd->SetMessageText(AFX_IDS_IDLEMESSAGE);
|
|
if (pBarWnd != NULL)
|
|
pBarWnd->UpdateWindow();
|
|
}
|
|
|
|
void CWordPadView::SetUpdateTimer()
|
|
{
|
|
if (m_uTimerID != 0) // if outstanding timer kill it
|
|
KillTimer(m_uTimerID);
|
|
m_uTimerID = SetTimer(1, 1000, NULL); //set a timer for 1000 milliseconds
|
|
if (m_uTimerID == 0) // no timer available so force update now
|
|
GetDocument()->UpdateAllItems(NULL);
|
|
else
|
|
m_bDelayUpdateItems = TRUE;
|
|
}
|
|
|
|
void CWordPadView::DeleteContents()
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(m_hWnd != NULL);
|
|
CRichEdit2View::DeleteContents();
|
|
SetDefaultFont(IsTextType(GetDocument()->m_nNewDocType));
|
|
}
|
|
|
|
void CWordPadView::SetDefaultFont(BOOL bText)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(m_hWnd != NULL);
|
|
|
|
CCharFormat cf;
|
|
|
|
m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
|
|
// set the default character format -- the FALSE makes it the default
|
|
GetDefaultFont(cf, bText);
|
|
GetRichEditCtrl().SetSel(0,-1);
|
|
GetRichEditCtrl().SetDefaultCharFormat(cf);
|
|
GetRichEditCtrl().SetSelectionCharFormat(cf);
|
|
|
|
//
|
|
// Setting the charformat with a NULL font name automagically sets
|
|
// the reading direction and alignment. Don't muck with it.
|
|
//
|
|
|
|
m_defParaFormat.dwMask &= ~ (PFM_RTLPARA | PFM_ALIGNMENT);
|
|
|
|
GetRichEditCtrl().SetParaFormat(m_defParaFormat);
|
|
|
|
GetRichEditCtrl().SetSel(0,0);
|
|
GetRichEditCtrl().EmptyUndoBuffer();
|
|
GetRichEditCtrl().SetModify(FALSE);
|
|
ASSERT_VALID(this);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWordPadView drawing
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWordPadView printing
|
|
|
|
void CWordPadView::OnBeginPrinting(CDC* pDC, CPrintInfo* printInfo)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT_VALID(pDC);
|
|
// initialize page start vector
|
|
ASSERT(m_aPageStart.GetSize() == 0);
|
|
ASSERT(NULL != printInfo);
|
|
ASSERT(NULL != printInfo->m_pPD);
|
|
|
|
OnPrinterChanged(*pDC);
|
|
|
|
//
|
|
// Copy some flags from PRINTDLGEX to PRINTDLG that mfc doesn't
|
|
//
|
|
|
|
C_PrintDialogEx *pPDEx = (C_PrintDialogEx *) printInfo->m_pPD;
|
|
pPDEx->m_pd.Flags |= pPDEx->m_pdex.Flags & PD_SELECTION;
|
|
|
|
m_aPageStart.Add(0);
|
|
ASSERT(m_aPageStart.GetSize() > 0);
|
|
|
|
if (printInfo->m_pPD->PrintSelection())
|
|
{
|
|
CHARRANGE range;
|
|
|
|
GetRichEditCtrl().GetSel(range);
|
|
m_aPageStart[0] = range.cpMin;
|
|
}
|
|
|
|
GetRichEditCtrl().FormatRange(NULL, FALSE); // required by RichEdit to clear out cache
|
|
|
|
ASSERT_VALID(this);
|
|
}
|
|
|
|
void CWordPadView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT_VALID(pDC);
|
|
ASSERT(pInfo != NULL);
|
|
ASSERT(pInfo->m_bContinuePrinting);
|
|
ASSERT(NULL != pInfo->m_pPD);
|
|
|
|
UINT nPage = pInfo->m_nCurPage;
|
|
ASSERT(nPage <= (UINT)m_aPageStart.GetSize());
|
|
|
|
long nIndex = (long) m_aPageStart[nPage-1];
|
|
BOOL bPrintSelection = pInfo->m_pPD->PrintSelection();
|
|
long nFinalCharIndex;
|
|
|
|
if (bPrintSelection)
|
|
{
|
|
CHARRANGE range;
|
|
|
|
GetRichEditCtrl().GetSel(range);
|
|
|
|
nFinalCharIndex = range.cpMax;
|
|
}
|
|
else
|
|
{
|
|
GETTEXTLENGTHEX textlen;
|
|
|
|
textlen.flags = GTL_DEFAULT;
|
|
#ifdef UNICODE
|
|
textlen.codepage = 1200; // Unicode code page
|
|
#else
|
|
textlen.codepage = CP_ACP;
|
|
#endif
|
|
|
|
nFinalCharIndex = (long)this->SendMessage(
|
|
EM_GETTEXTLENGTHEX,
|
|
(WPARAM) &textlen,
|
|
0);
|
|
}
|
|
|
|
// print as much as possible in the current page.
|
|
nIndex = PrintPage(pDC, nIndex, nFinalCharIndex);
|
|
|
|
if (nIndex >= nFinalCharIndex)
|
|
{
|
|
TRACE0("End of Document\n");
|
|
pInfo->SetMaxPage(nPage);
|
|
pInfo->m_bContinuePrinting = FALSE;
|
|
}
|
|
|
|
// update pagination information for page just printed
|
|
if (nPage == (UINT)m_aPageStart.GetSize())
|
|
{
|
|
if (nIndex < nFinalCharIndex)
|
|
m_aPageStart.Add(nIndex);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(nPage+1 <= (UINT)m_aPageStart.GetSize());
|
|
ASSERT(nIndex == (long)m_aPageStart[nPage+1-1]);
|
|
}
|
|
|
|
if (pInfo != NULL && pInfo->m_bPreview)
|
|
DrawMargins(pDC);
|
|
}
|
|
|
|
void CWordPadView::DrawMargins(CDC* pDC)
|
|
{
|
|
if (pDC->m_hAttribDC != NULL)
|
|
{
|
|
CRect rect;
|
|
rect.left = m_rectMargin.left;
|
|
rect.right = m_sizePaper.cx - m_rectMargin.right;
|
|
rect.top = m_rectMargin.top;
|
|
rect.bottom = m_sizePaper.cy - m_rectMargin.bottom;
|
|
//rect in twips
|
|
int logx = ::GetDeviceCaps(pDC->m_hDC, LOGPIXELSX);
|
|
int logy = ::GetDeviceCaps(pDC->m_hDC, LOGPIXELSY);
|
|
rect.left = MulDiv(rect.left, logx, 1440);
|
|
rect.right = MulDiv(rect.right, logx, 1440);
|
|
rect.top = MulDiv(rect.top, logy, 1440);
|
|
rect.bottom = MulDiv(rect.bottom, logy, 1440);
|
|
CPen pen(PS_DOT, 0, pDC->GetTextColor());
|
|
CPen* ppen = pDC->SelectObject(&pen);
|
|
pDC->MoveTo(0, rect.top);
|
|
pDC->LineTo(10000, rect.top);
|
|
pDC->MoveTo(rect.left, 0);
|
|
pDC->LineTo(rect.left, 10000);
|
|
pDC->MoveTo(0, rect.bottom);
|
|
pDC->LineTo(10000, rect.bottom);
|
|
pDC->MoveTo(rect.right, 0);
|
|
pDC->LineTo(rect.right, 10000);
|
|
pDC->SelectObject(ppen);
|
|
}
|
|
}
|
|
|
|
BOOL CWordPadView::OnPreparePrinting(CPrintInfo* pInfo)
|
|
{
|
|
CWordPadApp *pApp = NULL ;
|
|
|
|
//
|
|
// Swap out the default print dialog with the new PrintDlgEx version.
|
|
// Hopefully MFC will come up with a better way to do this sometime.
|
|
//
|
|
|
|
C_PrintDialogEx *pPDEx = new C_PrintDialogEx(FALSE, PD_RETURNDC | PD_ALLPAGES | PD_NOSELECTION | PD_NOCURRENTPAGE | PD_USEDEVMODECOPIESANDCOLLATE);
|
|
|
|
if (NULL == pPDEx)
|
|
return FALSE;
|
|
|
|
m_oldprintdlg = pInfo->m_pPD;
|
|
pInfo->m_pPD = pPDEx;
|
|
pInfo->SetMinPage(1);
|
|
pInfo->SetMaxPage(0xffff);
|
|
|
|
pInfo->m_pPD->m_pd.nFromPage = 1;
|
|
pInfo->m_pPD->m_pd.nToPage = 1;
|
|
|
|
pApp = (CWordPadApp *) AfxGetApp() ;
|
|
|
|
if (NULL != pApp)
|
|
{
|
|
if ( (pApp->cmdInfo.m_nShellCommand == CCommandLineInfo::FilePrintTo) ||
|
|
(pApp->cmdInfo.m_nShellCommand == CCommandLineInfo::FilePrint) )
|
|
{
|
|
if (pInfo->m_pPD->m_pd.hDevNames == NULL)
|
|
{
|
|
HGLOBAL hDn = pApp->GetDevNames() ;
|
|
|
|
if (hDn != NULL)
|
|
{
|
|
pInfo->m_pPD->m_pd.hDevNames = hDn ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SEL_EMPTY != GetRichEditCtrl().GetSelectionType())
|
|
{
|
|
pInfo->m_pPD->m_pd.Flags = pInfo->m_pPD->m_pd.Flags & ~PD_NOSELECTION;
|
|
pPDEx->m_pdex.Flags = pPDEx->m_pdex.Flags & ~PD_NOSELECTION;
|
|
}
|
|
|
|
return DoPreparePrinting(pInfo);
|
|
}
|
|
|
|
void CWordPadView::OnEndPrinting(CDC*dc, CPrintInfo*pInfo)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
//
|
|
// Swap the original print dlg back
|
|
//
|
|
|
|
delete (C_PrintDialogEx *) pInfo->m_pPD;
|
|
pInfo->m_pPD = m_oldprintdlg;
|
|
m_oldprintdlg = NULL;
|
|
|
|
CRichEdit2View::OnEndPrinting(dc, pInfo);
|
|
}
|
|
|
|
void CWordPadView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT_VALID(pDC);
|
|
ASSERT(pInfo != NULL); // overriding OnPaint -- never get this.
|
|
|
|
if (!pInfo->m_bContinuePrinting)
|
|
return;
|
|
|
|
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);
|
|
}
|
|
|
|
BOOL CWordPadView::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());
|
|
pDC->IntersectClipRect(0, 0, 0, 0);
|
|
pInfo->m_nCurPage = (UINT)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;
|
|
pInfo->m_nCurPage = nPageSave;
|
|
pInfo->m_rectDraw = rectSave;
|
|
pDC->SelectClipRgn(NULL) ;
|
|
ASSERT_VALID(this);
|
|
return bResult;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// OLE Client support and commands
|
|
|
|
inline int roundleast(int n)
|
|
{
|
|
int mod = n%10;
|
|
n -= mod;
|
|
if (mod >= 5)
|
|
n += 10;
|
|
else if (mod <= -5)
|
|
n -= 10;
|
|
return n;
|
|
}
|
|
|
|
static void RoundRect(FAR UNALIGNED RECT *r1)
|
|
{
|
|
r1->left = roundleast(r1->left);
|
|
r1->right = roundleast(r1->right);
|
|
r1->top = roundleast(r1->top);
|
|
r1->bottom = roundleast(r1->bottom);
|
|
}
|
|
|
|
static void MulDivRect(FAR UNALIGNED RECT *r1, FAR UNALIGNED RECT * r2, int num, int div)
|
|
{
|
|
r1->left = MulDiv(r2->left, num, div);
|
|
r1->top = MulDiv(r2->top, num, div);
|
|
r1->right = MulDiv(r2->right, num, div);
|
|
r1->bottom = MulDiv(r2->bottom, num, div);
|
|
}
|
|
|
|
void CWordPadView::OnPageSetup()
|
|
{
|
|
theApp.EnsurePrinterIsInitialized();
|
|
|
|
CPageSetupDialog dlg;
|
|
PAGESETUPDLG& psd = dlg.m_psd;
|
|
BOOL bMetric = theApp.GetUnits() == 1; //centimeters
|
|
BOOL fUpdateWrap = FALSE ;
|
|
psd.Flags |= PSD_MARGINS | (bMetric ? PSD_INHUNDREDTHSOFMILLIMETERS :
|
|
PSD_INTHOUSANDTHSOFINCHES);
|
|
int nUnitsPerInch = bMetric ? 2540 : 1000;
|
|
MulDivRect(&psd.rtMargin, m_rectMargin, nUnitsPerInch, 1440);
|
|
RoundRect(&psd.rtMargin);
|
|
// get the current device from the app
|
|
PRINTDLG pd;
|
|
pd.hDevNames = NULL;
|
|
pd.hDevMode = NULL;
|
|
theApp.GetPrinterDeviceDefaults(&pd);
|
|
psd.hDevNames = pd.hDevNames;
|
|
psd.hDevMode = pd.hDevMode;
|
|
|
|
SetHelpFixHook() ;
|
|
|
|
if (dlg.DoModal() == IDOK)
|
|
{
|
|
RoundRect(&psd.rtMargin);
|
|
MulDivRect(m_rectMargin, &psd.rtMargin, 1440, nUnitsPerInch);
|
|
theApp.m_rectPageMargin = m_rectMargin;
|
|
|
|
//
|
|
// SelectPrinter will free the existing devnames and devmodes if the
|
|
// third parameter is TRUE. We don't want to do that because the
|
|
// print dialog frees them and allocates new ones.
|
|
//
|
|
|
|
theApp.SelectPrinter(psd.hDevNames, psd.hDevMode, FALSE);
|
|
theApp.NotifyPrinterChanged();
|
|
fUpdateWrap = TRUE ;
|
|
}
|
|
|
|
RemoveHelpFixHook() ;
|
|
|
|
// PageSetupDlg failed
|
|
if (CommDlgExtendedError() != 0)
|
|
{
|
|
CPageSetupDlg dlg;
|
|
dlg.m_nBottomMargin = m_rectMargin.bottom;
|
|
dlg.m_nLeftMargin = m_rectMargin.left;
|
|
dlg.m_nRightMargin = m_rectMargin.right;
|
|
dlg.m_nTopMargin = m_rectMargin.top;
|
|
if (dlg.DoModal() == IDOK)
|
|
{
|
|
m_rectMargin.SetRect(dlg.m_nLeftMargin, dlg.m_nTopMargin,
|
|
dlg.m_nRightMargin, dlg.m_nBottomMargin);
|
|
// m_page will be changed at this point
|
|
theApp.m_rectPageMargin = m_rectMargin;
|
|
theApp.NotifyPrinterChanged();
|
|
fUpdateWrap = TRUE ;
|
|
}
|
|
}
|
|
|
|
if (fUpdateWrap)
|
|
{
|
|
CRichEdit2View::WrapChanged();
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// OLE Server support
|
|
|
|
// The following command handler provides the standard keyboard
|
|
// user interface to cancel an in-place editing session. Here,
|
|
// the server (not the container) causes the deactivation.
|
|
void CWordPadView::OnCancelEditSrvr()
|
|
{
|
|
GetDocument()->OnDeactivateUI(FALSE);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWordPadView diagnostics
|
|
|
|
#ifdef _DEBUG
|
|
void CWordPadView::AssertValid() const
|
|
{
|
|
CRichEdit2View::AssertValid();
|
|
}
|
|
|
|
void CWordPadView::Dump(CDumpContext& dc) const
|
|
{
|
|
CRichEdit2View::Dump(dc);
|
|
}
|
|
|
|
CWordPadDoc* CWordPadView::GetDocument() // non-debug version is inline
|
|
{
|
|
return (CWordPadDoc*)m_pDocument;
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWordPadView message helpers
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWordPadView message handlers
|
|
|
|
int CWordPadView::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{
|
|
if (CRichEdit2View::OnCreate(lpCreateStruct) == -1)
|
|
return -1;
|
|
theApp.m_listPrinterNotify.AddTail(m_hWnd);
|
|
|
|
if (theApp.m_bWordSel)
|
|
GetRichEditCtrl().SetOptions(ECOOP_OR, ECO_AUTOWORDSELECTION);
|
|
else
|
|
GetRichEditCtrl().SetOptions(ECOOP_AND, ~(DWORD)ECO_AUTOWORDSELECTION);
|
|
// GetRichEditCtrl().SetOptions(ECOOP_OR, ECO_SELECTIONBAR);
|
|
|
|
GetRichEditCtrl().GetParaFormat(m_defParaFormat);
|
|
m_defParaFormat.cTabCount = 0;
|
|
|
|
//
|
|
// Insert our own wrapper interface callback here to get around MFC defaults
|
|
//
|
|
|
|
VERIFY(GetRichEditCtrl().SetOLECallback(&m_xWordPadRichEditOleCallback));
|
|
|
|
|
|
if (::GetWindowLongPtr(::GetParent(m_hWnd) , GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
|
|
m_bIsMirrored = TRUE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CWordPadView::GetDefaultFont(CCharFormat& cf, BOOL bText)
|
|
{
|
|
USES_CONVERSION;
|
|
CString strDefFont;
|
|
if (bText)
|
|
VERIFY(strDefFont.LoadString(IDS_DEFAULTTEXTFONT));
|
|
ASSERT(cf.cbSize == sizeof(CHARFORMAT));
|
|
cf.dwMask = CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT|CFM_SIZE|
|
|
CFM_COLOR|CFM_OFFSET|CFM_PROTECTED;
|
|
cf.dwEffects = CFE_AUTOCOLOR;
|
|
cf.yHeight = 200; //10pt
|
|
cf.yOffset = 0;
|
|
cf.crTextColor = RGB(0, 0, 0);
|
|
cf.bCharSet = 0;
|
|
cf.bPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
|
|
EVAL(StringCchCopy(cf.szFaceName, ARRAYSIZE(cf.szFaceName), strDefFont) == S_OK);
|
|
cf.dwMask |= CFM_FACE;
|
|
}
|
|
|
|
void CWordPadView::OnInsertDateTime()
|
|
{
|
|
// When changing the paragraph direction by Ctrl+Shift the m_bSyncParaFormat
|
|
// will not reset. we reset it to force GetParaFormatSelection read current
|
|
// paragraph direction by calling GetRichEditCtrl().GetParaFormat()
|
|
m_bSyncParaFormat = TRUE;
|
|
|
|
CDateDialog dlg(NULL , GetParaFormatSelection());
|
|
if (dlg.DoModal() == IDOK)
|
|
{
|
|
GetRichEditCtrl().ReplaceSel(dlg.m_strSel, TRUE);
|
|
}
|
|
}
|
|
|
|
void CWordPadView::OnFormatParagraph()
|
|
{
|
|
CFormatParaDlg dlg(GetParaFormatSelection());
|
|
dlg.m_nWordWrap = m_nWordWrap;
|
|
if (dlg.DoModal() == IDOK)
|
|
SetParaFormat(dlg.m_pf);
|
|
}
|
|
|
|
void CWordPadView::OnFormatTabs()
|
|
{
|
|
CFormatTabDlg dlg(GetParaFormatSelection());
|
|
if (dlg.DoModal() == IDOK)
|
|
SetParaFormat(dlg.m_pf);
|
|
}
|
|
|
|
void CWordPadView::OnTextNotFound(LPCTSTR /* UNREF lpStr */)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// HACKHACK:
|
|
//
|
|
// When AfxMessageBox is called MFC disables the find dialog and pops up
|
|
// the message box. After the user dismisses it, User tries to set the
|
|
// focus back to the window that had it before the message box, however
|
|
// this window is disabled so eventually what ends up happening is that
|
|
// the find dialog, and not any control in it, has the focus. This screws
|
|
// up alt hotkeys for buttons and such.
|
|
|
|
HWND h = ::GetFocus();
|
|
AfxMessageBox(IDS_FINISHED_SEARCH,MB_OK|MB_ICONINFORMATION);
|
|
::SetFocus(h);
|
|
}
|
|
|
|
void CWordPadView::OnColorPick(UINT nID)
|
|
{
|
|
CRichEdit2View::OnColorPick(CColorMenu::GetColor(nID));
|
|
}
|
|
|
|
void CWordPadView::OnTimer(UINT_PTR nIDEvent)
|
|
{
|
|
if (m_uTimerID != nIDEvent) // not our timer
|
|
CRichEdit2View::OnTimer(nIDEvent);
|
|
else
|
|
{
|
|
KillTimer(m_uTimerID); // kill one-shot timer
|
|
m_uTimerID = 0;
|
|
if (m_bDelayUpdateItems)
|
|
GetDocument()->UpdateAllItems(NULL);
|
|
m_bDelayUpdateItems = FALSE;
|
|
}
|
|
}
|
|
|
|
void CWordPadView::OnEditChange()
|
|
{
|
|
SetUpdateTimer();
|
|
}
|
|
|
|
void CWordPadView::OnDestroy()
|
|
{
|
|
POSITION pos = theApp.m_listPrinterNotify.Find(m_hWnd);
|
|
ASSERT(pos != NULL);
|
|
theApp.m_listPrinterNotify.RemoveAt(pos);
|
|
|
|
if (m_uTimerID != 0) // if outstanding timer kill it
|
|
OnTimer(m_uTimerID);
|
|
ASSERT(m_uTimerID == 0);
|
|
|
|
CRichEdit2View::OnDestroy();
|
|
|
|
CWnd *pWnd = AfxGetMainWnd() ;
|
|
|
|
if (NULL == pWnd)
|
|
{
|
|
return ;
|
|
}
|
|
|
|
pWnd = pWnd->GetTopLevelParent() ;
|
|
|
|
if (NULL == pWnd)
|
|
{
|
|
return ;
|
|
}
|
|
|
|
::WinHelp(pWnd->m_hWnd, WORDPAD_HELP_FILE, HELP_QUIT, 0) ;
|
|
}
|
|
|
|
void CWordPadView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
|
|
{
|
|
CRichEdit2View::CalcWindowRect(lpClientRect, nAdjustType);
|
|
|
|
if (theApp.m_bWin4 && nAdjustType != 0 && (GetStyle() & WS_VSCROLL))
|
|
lpClientRect->right--;
|
|
|
|
// if the ruler is visible then slide the view up under the ruler to avoid
|
|
// showing the top border of the view
|
|
if (GetExStyle() & WS_EX_CLIENTEDGE)
|
|
{
|
|
CFrameWnd* pFrame = GetParentFrame();
|
|
if (pFrame != NULL)
|
|
{
|
|
CRulerBar* pBar = (CRulerBar*)pFrame->GetControlBar(ID_VIEW_RULER);
|
|
if (pBar != NULL)
|
|
{
|
|
BOOL bVis = pBar->IsVisible();
|
|
if (pBar->m_bDeferInProgress)
|
|
bVis = !bVis;
|
|
if (bVis)
|
|
lpClientRect->top -= 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWordPadView::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMIS)
|
|
{
|
|
lpMIS->itemID = (UINT)(WORD)lpMIS->itemID;
|
|
CRichEdit2View::OnMeasureItem(nIDCtl, lpMIS);
|
|
}
|
|
|
|
void CWordPadView::OnPenBackspace()
|
|
{
|
|
SendMessage(WM_KEYDOWN, VK_BACK, 0);
|
|
SendMessage(WM_KEYUP, VK_BACK, 0);
|
|
}
|
|
|
|
void CWordPadView::OnPenNewline()
|
|
{
|
|
SendMessage(WM_CHAR, '\n', 0);
|
|
}
|
|
|
|
void CWordPadView::OnPenPeriod()
|
|
{
|
|
SendMessage(WM_CHAR, '.', 0);
|
|
}
|
|
|
|
void CWordPadView::OnPenSpace()
|
|
{
|
|
SendMessage(WM_CHAR, ' ', 0);
|
|
}
|
|
|
|
void CWordPadView::OnPenTab()
|
|
{
|
|
SendMessage(WM_CHAR, VK_TAB, 0);
|
|
}
|
|
|
|
void CWordPadView::OnDelayedInvalidate()
|
|
{
|
|
Invalidate() ;
|
|
}
|
|
|
|
void CWordPadView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
if (nChar == VK_F10 && GetKeyState(VK_SHIFT) < 0)
|
|
{
|
|
long nStart, nEnd;
|
|
GetRichEditCtrl().GetSel(nStart, nEnd);
|
|
CPoint pt = GetRichEditCtrl().GetCharPos(nEnd);
|
|
SendMessage(WM_CONTEXTMENU, (WPARAM)m_hWnd, MAKELPARAM(pt.x, pt.y));
|
|
}
|
|
|
|
CRichEdit2View::OnKeyDown(nChar, nRepCnt, nFlags);
|
|
}
|
|
|
|
HRESULT CWordPadView::GetClipboardData(CHARRANGE* lpchrg, DWORD /*reco*/,
|
|
LPDATAOBJECT lpRichDataObj, LPDATAOBJECT* lplpdataobj)
|
|
{
|
|
CHARRANGE& cr = *lpchrg;
|
|
|
|
if (NULL == lpRichDataObj)
|
|
return E_INVALIDARG;
|
|
|
|
if ((cr.cpMax - cr.cpMin == 1) &&
|
|
GetRichEditCtrl().GetSelectionType() == SEL_OBJECT)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
BeginWaitCursor();
|
|
//create the data source
|
|
COleDataSource* pDataSource = new COleDataSource;
|
|
|
|
// put the formats into the data source
|
|
LPENUMFORMATETC lpEnumFormatEtc;
|
|
lpRichDataObj->EnumFormatEtc(DATADIR_GET, &lpEnumFormatEtc);
|
|
if (lpEnumFormatEtc != NULL)
|
|
{
|
|
FORMATETC etc;
|
|
while (lpEnumFormatEtc->Next(1, &etc, NULL) == S_OK)
|
|
{
|
|
STGMEDIUM stgMedium;
|
|
lpRichDataObj->GetData(&etc, &stgMedium);
|
|
pDataSource->CacheData(etc.cfFormat, &stgMedium, &etc);
|
|
}
|
|
lpEnumFormatEtc->Release();
|
|
}
|
|
|
|
CEmbeddedItem item(GetDocument(), cr.cpMin, cr.cpMax);
|
|
item.m_lpRichDataObj = lpRichDataObj;
|
|
// get wordpad formats
|
|
item.GetClipboardData(pDataSource);
|
|
|
|
// get the IDataObject from the data source
|
|
*lplpdataobj = (LPDATAOBJECT)pDataSource->GetInterface(&IID_IDataObject);
|
|
|
|
EndWaitCursor();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CWordPadView::PasteHDROPFormat(HDROP hDrop)
|
|
{
|
|
HRESULT hr = S_OK ;
|
|
UINT i ;
|
|
TCHAR szFile[MAX_PATH + 1] ;
|
|
CHARRANGE cr ;
|
|
LONG tmp ;
|
|
UINT cFiles ;
|
|
|
|
cFiles = DragQueryFile(hDrop, (UINT) -1, NULL, 0) ;
|
|
|
|
GetRichEditCtrl().GetSel(cr);
|
|
|
|
tmp = cr.cpMin ;
|
|
|
|
for (i=0; i<cFiles; i++)
|
|
{
|
|
::DragQueryFile(hDrop, i, szFile, MAX_PATH) ;
|
|
|
|
if (FILE_ATTRIBUTE_DIRECTORY == GetFileAttributes(szFile))
|
|
{
|
|
continue ;
|
|
}
|
|
|
|
//
|
|
// Fix the selection state up so that multiple objects insert
|
|
// at the right spot
|
|
//
|
|
|
|
cr.cpMin = cr.cpMax ;
|
|
|
|
GetRichEditCtrl().SetSel(cr);
|
|
|
|
//
|
|
// Insert from file
|
|
//
|
|
|
|
InsertFileAsObject(szFile) ;
|
|
}
|
|
|
|
GetRichEditCtrl().SetSel(cr);
|
|
|
|
return hr ;
|
|
}
|
|
|
|
HRESULT CWordPadView::QueryAcceptData(LPDATAOBJECT lpdataobj,
|
|
CLIPFORMAT* lpcfFormat, DWORD reco, BOOL bReally,
|
|
HGLOBAL hMetaPict)
|
|
{
|
|
HRESULT hr = S_OK ;
|
|
|
|
if (!bReally)
|
|
{
|
|
g_fRightButtonDrag = 0x8000 & GetAsyncKeyState(
|
|
GetSystemMetrics(SM_SWAPBUTTON)
|
|
? VK_LBUTTON
|
|
: VK_RBUTTON);
|
|
}
|
|
|
|
//
|
|
// If we are doing an inproc drag-drop, we want our drop
|
|
// effect to be DROPEFFECT_MOVE but if we are drag-dropping
|
|
// from another application, we want our effect to be
|
|
// DROPEFFECT_COPY -- in particular so that we don't delete
|
|
// icons dragged from the explorer or text dragged from Word!
|
|
//
|
|
// The reason for this hack is that richedit doesn't supply
|
|
// any mechanism for us to determine whether or not we are
|
|
// both the drop source and the drop target.
|
|
//
|
|
|
|
if (!bReally)
|
|
{
|
|
LPUNKNOWN pUnk = NULL ;
|
|
|
|
if (S_OK == lpdataobj->QueryInterface(
|
|
IID_IProxyManager,
|
|
(LPVOID *) &pUnk))
|
|
{
|
|
//
|
|
// We got an IProxyManager pointer, so we are NOT doing an
|
|
// inproc drag drop
|
|
//
|
|
|
|
pUnk->Release() ;
|
|
|
|
g_fInternalDragDrop = FALSE ;
|
|
}
|
|
else
|
|
{
|
|
g_fInternalDragDrop = TRUE ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_fInternalDragDrop = FALSE ;
|
|
}
|
|
|
|
//
|
|
// Check for native data first
|
|
//
|
|
|
|
if (bReally && *lpcfFormat == 0 && (m_nPasteType == 0))
|
|
{
|
|
COleDataObject dataobj;
|
|
dataobj.Attach(lpdataobj, FALSE);
|
|
if (!dataobj.IsDataAvailable(cfRTO)) // native avail, let richedit do as it wants
|
|
{
|
|
if (dataobj.IsDataAvailable(cfEmbeddedObject))
|
|
{
|
|
if (PasteNative(lpdataobj))
|
|
{
|
|
hr = S_FALSE ;
|
|
|
|
goto errRet ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// We need to support HDROP format from the explorer
|
|
// and the desktop
|
|
//
|
|
|
|
if (bReally)
|
|
{
|
|
FORMATETC fe ;
|
|
|
|
fe.cfFormat = CF_HDROP ;
|
|
fe.ptd = NULL ;
|
|
fe.dwAspect = DVASPECT_CONTENT ;
|
|
fe.lindex = -1 ;
|
|
fe.tymed = TYMED_HGLOBAL ;
|
|
|
|
if (S_OK == lpdataobj->QueryGetData(&fe))
|
|
{
|
|
STGMEDIUM sm ;
|
|
|
|
sm.tymed = TYMED_NULL ;
|
|
sm.hGlobal = (HGLOBAL) 0 ;
|
|
sm.pUnkForRelease = NULL ;
|
|
|
|
if (S_OK == lpdataobj->GetData(&fe, &sm))
|
|
{
|
|
//
|
|
// If we have a single file in our HDROP data then
|
|
// embed source might *also* be available in which case we
|
|
// should just use the default richedit logic and
|
|
// skip PasteHDROPFormat(). We should not ever get
|
|
// embed source AND an HDROP data block containing
|
|
// multiple files because OLE only supports one drop
|
|
// source per drag-drop operation. The default richedit
|
|
// logic should handle all cases while dropping a single
|
|
// file, we just have to special case things while dropping
|
|
// multiple files.
|
|
//
|
|
|
|
if (DragQueryFile((HDROP) sm.hGlobal, (UINT) -1, NULL, 0) > 1)
|
|
{
|
|
PasteHDROPFormat((HDROP) sm.hGlobal) ;
|
|
hr = S_FALSE ;
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK ;
|
|
}
|
|
|
|
::ReleaseStgMedium(&sm) ;
|
|
|
|
if (S_FALSE == hr)
|
|
{
|
|
goto errRet ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If all else fails, let richedit give it a try
|
|
//
|
|
|
|
hr = CRichEdit2View::QueryAcceptData(lpdataobj, lpcfFormat, reco, bReally,
|
|
hMetaPict);
|
|
|
|
errRet:
|
|
|
|
if (bReally)
|
|
{
|
|
//
|
|
// We post a message to ourselves here instead of just calling
|
|
// ::Invalidate() because the richedit control doesn't always
|
|
// repaint unless it is completely done with the data transfer operation.
|
|
//
|
|
|
|
PostMessage(WM_COMMAND, ID_DELAYED_INVALIDATE, 0) ;
|
|
}
|
|
|
|
return hr ;
|
|
}
|
|
|
|
|
|
BOOL CWordPadView::PasteNative(LPDATAOBJECT lpdataobj)
|
|
{
|
|
// check data object for wordpad object
|
|
// if true, pull out RTF directly
|
|
|
|
FORMATETC etc = {NULL, NULL, DVASPECT_CONTENT, -1, TYMED_ISTORAGE};
|
|
etc.cfFormat = (CLIPFORMAT)cfEmbeddedObject;
|
|
STGMEDIUM stgMedium = {TYMED_ISTORAGE, 0, NULL};
|
|
|
|
// create an IStorage to transfer the data in
|
|
LPLOCKBYTES lpLockBytes;
|
|
if (FAILED(::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes)))
|
|
return FALSE;
|
|
ASSERT(lpLockBytes != NULL);
|
|
|
|
HRESULT hr = ::StgCreateDocfileOnILockBytes(lpLockBytes,
|
|
STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &stgMedium.pstg);
|
|
lpLockBytes->Release(); //storage addref'd
|
|
if (FAILED(hr))
|
|
return FALSE;
|
|
|
|
ASSERT(stgMedium.pstg != NULL);
|
|
|
|
CLSID clsid;
|
|
|
|
BOOL bRes = FALSE; //let richedit do what it wants
|
|
|
|
if (SUCCEEDED(lpdataobj->GetDataHere(&etc, &stgMedium)) &&
|
|
SUCCEEDED(ReadClassStg(stgMedium.pstg, &clsid)) &&
|
|
clsid == GetDocument()->GetClassID())
|
|
{
|
|
//pull out RTF now
|
|
// open Contents stream
|
|
|
|
COleStreamFile file;
|
|
CFileException fe;
|
|
if (file.OpenStream(stgMedium.pstg, szContents,
|
|
CFile::modeReadWrite|CFile::shareExclusive, &fe))
|
|
{
|
|
CRichEdit2Doc *doc = GetDocument();
|
|
BOOL bRTF = doc->m_bRTF;
|
|
BOOL bUnicode = doc->m_bUnicode;
|
|
|
|
// Force the "current" stream type to be rtf
|
|
|
|
doc->m_bRTF = TRUE;
|
|
doc->m_bUnicode = FALSE;
|
|
|
|
// load it with CArchive (loads from Contents stream)
|
|
CArchive loadArchive(&file, CArchive::load |
|
|
CArchive::bNoFlushOnDelete);
|
|
Stream(loadArchive, TRUE); //stream in selection
|
|
|
|
// Restore the "current" stream type
|
|
|
|
doc->m_bRTF = bRTF;
|
|
doc->m_bUnicode = bUnicode;
|
|
|
|
bRes = TRUE; // don't let richedit do anything
|
|
}
|
|
}
|
|
::ReleaseStgMedium(&stgMedium);
|
|
return bRes;
|
|
}
|
|
|
|
// things to fix
|
|
// if format==0 we are doing a straight EM_PASTE
|
|
// look for native formats
|
|
// richedit specific -- allow richedit to handle (these will be first)
|
|
// look for RTF, CF_TEXT. If there paste special as these
|
|
// Do standard OLE scenario
|
|
|
|
// if pasting a particular format (format != 0)
|
|
// if richedit specific, allow through
|
|
// if RTF, CF_TEXT. paste special
|
|
// if OLE format, do standard OLE scenario
|
|
|
|
|
|
void CWordPadView::OnFilePrint()
|
|
{
|
|
theApp.EnsurePrinterIsInitialized();
|
|
|
|
// don't allow winini changes to occur while printing
|
|
m_bInPrint = TRUE;
|
|
|
|
SetHelpFixHook() ;
|
|
|
|
CRichEdit2View::OnFilePrint();
|
|
|
|
RemoveHelpFixHook() ;
|
|
|
|
// printer may have changed
|
|
theApp.NotifyPrinterChanged(); // this will cause a GetDocument()->PrinterChanged();
|
|
m_bInPrint = FALSE;
|
|
}
|
|
|
|
void CWordPadView::OnFilePrintPreview()
|
|
{
|
|
theApp.EnsurePrinterIsInitialized();
|
|
|
|
CRichEdit2View::OnFilePrintPreview();
|
|
}
|
|
|
|
int CWordPadView::OnMouseActivate(CWnd* pWnd, UINT nHitTest, UINT message)
|
|
{
|
|
if (m_bOnBar)
|
|
{
|
|
SetFocus();
|
|
return MA_ACTIVATEANDEAT;
|
|
}
|
|
else
|
|
return CRichEdit2View::OnMouseActivate(pWnd, nHitTest, message);
|
|
}
|
|
|
|
typedef BOOL (WINAPI *PCWPROC)(HWND, LPSTR, UINT, LPVOID, DWORD, DWORD);
|
|
void CWordPadView::OnPenLens()
|
|
{
|
|
USES_CONVERSION;
|
|
HINSTANCE hLib = LoadLibrary(L"PENWIN32.DLL");
|
|
if (hLib == NULL)
|
|
return;
|
|
PCWPROC pCorrectWriting = (PCWPROC)GetProcAddress(hLib, "CorrectWriting");
|
|
ASSERT(pCorrectWriting != NULL);
|
|
if (pCorrectWriting != NULL)
|
|
{
|
|
CHARRANGE cr;
|
|
GetRichEditCtrl().GetSel(cr);
|
|
int nCnt = 2*(cr.cpMax-cr.cpMin);
|
|
BOOL bSel = (nCnt != 0);
|
|
nCnt = max(1024, nCnt);
|
|
char* pBuf = new char[nCnt];
|
|
if (pBuf)
|
|
{
|
|
pBuf[0] = 0;
|
|
if (bSel)
|
|
{
|
|
GetRichEditCtrl().GetSelText(pBuf);
|
|
}
|
|
|
|
if (pCorrectWriting(m_hWnd, pBuf, nCnt, 0, bSel ? 0 : CWR_INSERT, 0))
|
|
{
|
|
LPWSTR pwszBuf = AnsiToWideNewArray(pBuf);
|
|
if (pwszBuf)
|
|
{
|
|
GetRichEditCtrl().ReplaceSel(pwszBuf);
|
|
delete [] pwszBuf;
|
|
}
|
|
}
|
|
delete [] pBuf;
|
|
}
|
|
}
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
LONG CWordPadView::OnPrinterChangedMsg(UINT, LONG)
|
|
{
|
|
CDC dc;
|
|
AfxGetApp()->CreatePrinterDC(dc);
|
|
OnPrinterChanged(dc);
|
|
return 0;
|
|
}
|
|
|
|
static void ForwardPaletteChanged(HWND hWndParent, HWND hWndFocus)
|
|
{
|
|
// this is a quick and dirty hack to send the WM_QUERYNEWPALETTE to a window that is interested
|
|
HWND hWnd = NULL;
|
|
for (hWnd = ::GetWindow(hWndParent, GW_CHILD); hWnd != NULL; hWnd = ::GetWindow(hWnd, GW_HWNDNEXT))
|
|
{
|
|
if (hWnd != hWndFocus)
|
|
{
|
|
::SendMessage(hWnd, WM_PALETTECHANGED, (WPARAM)hWndFocus, 0L);
|
|
ForwardPaletteChanged(hWnd, hWndFocus);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWordPadView::OnPaletteChanged(CWnd* pFocusWnd)
|
|
{
|
|
ForwardPaletteChanged(m_hWnd, pFocusWnd->GetSafeHwnd());
|
|
// allow the richedit control to realize its palette
|
|
// remove this if if richedit fixes their code so that
|
|
// they don't realize their palette into foreground
|
|
if (::GetWindow(m_hWnd, GW_CHILD) == NULL)
|
|
CRichEdit2View::OnPaletteChanged(pFocusWnd);
|
|
}
|
|
|
|
static BOOL FindQueryPalette(HWND hWndParent)
|
|
{
|
|
// this is a quick and dirty hack to send the WM_QUERYNEWPALETTE to a window that is interested
|
|
HWND hWnd = NULL;
|
|
for (hWnd = ::GetWindow(hWndParent, GW_CHILD); hWnd != NULL; hWnd = ::GetWindow(hWnd, GW_HWNDNEXT))
|
|
{
|
|
if (::SendMessage(hWnd, WM_QUERYNEWPALETTE, 0, 0L))
|
|
return TRUE;
|
|
else if (FindQueryPalette(hWnd))
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CWordPadView::OnQueryNewPalette()
|
|
{
|
|
if(FindQueryPalette(m_hWnd))
|
|
return TRUE;
|
|
return CRichEdit2View::OnQueryNewPalette();
|
|
}
|
|
|
|
void CWordPadView::OnWinIniChange(LPCTSTR lpszSection)
|
|
{
|
|
CRichEdit2View::OnWinIniChange(lpszSection);
|
|
//printer might have changed
|
|
if (!m_bInPrint)
|
|
{
|
|
if (lstrcmpi(lpszSection, _T("windows")) == 0)
|
|
theApp.NotifyPrinterChanged(TRUE); // force update to defaults
|
|
}
|
|
}
|
|
|
|
void CWordPadView::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CRichEdit2View::OnSize(nType, cx, cy);
|
|
CRect rect(HORZ_TEXTOFFSET, VERT_TEXTOFFSET, cx, cy);
|
|
GetRichEditCtrl().SetRect(rect);
|
|
}
|
|
|
|
void CWordPadView::OnGetCharFormat(NMHDR* pNMHDR, LRESULT* pRes)
|
|
{
|
|
ASSERT(pNMHDR != NULL);
|
|
ASSERT(pRes != NULL);
|
|
|
|
((CHARHDR*)pNMHDR)->cf = GetCharFormatSelection();
|
|
*pRes = 1;
|
|
}
|
|
|
|
void CWordPadView::OnSetCharFormat(NMHDR* pNMHDR, LRESULT* pRes)
|
|
{
|
|
ASSERT(pNMHDR != NULL);
|
|
ASSERT(pRes != NULL);
|
|
SetCharFormat(((CHARHDR*)pNMHDR)->cf);
|
|
*pRes = 1;
|
|
}
|
|
|
|
void CWordPadView::OnBarSetFocus(NMHDR*, LRESULT*)
|
|
{
|
|
m_bOnBar = TRUE;
|
|
}
|
|
|
|
void CWordPadView::OnBarKillFocus(NMHDR*, LRESULT*)
|
|
{
|
|
m_bOnBar = FALSE;
|
|
}
|
|
|
|
void CWordPadView::OnBarReturn(NMHDR*, LRESULT* )
|
|
{
|
|
SetFocus();
|
|
}
|
|
|
|
void CWordPadView::OnFormatFont()
|
|
{
|
|
SetHelpFixHook() ;
|
|
|
|
CRichEdit2View::OnFormatFont() ;
|
|
|
|
RemoveHelpFixHook() ;
|
|
}
|
|
|
|
void CWordPadView::OnInsertObject()
|
|
{
|
|
g_fDisableStandardHelp = TRUE ;
|
|
|
|
SetHelpFixHook() ;
|
|
|
|
CRichEdit2View::OnInsertObject() ;
|
|
|
|
RemoveHelpFixHook() ;
|
|
|
|
g_fDisableStandardHelp = FALSE ;
|
|
}
|
|
|
|
void CWordPadView::OnEditPasteSpecial()
|
|
{
|
|
g_fDisableStandardHelp = TRUE ;
|
|
|
|
SetHelpFixHook() ;
|
|
|
|
CRichEdit2View::OnEditPasteSpecial() ;
|
|
|
|
RemoveHelpFixHook() ;
|
|
|
|
g_fDisableStandardHelp = FALSE ;
|
|
}
|
|
|
|
void CWordPadView::OnEditFind()
|
|
{
|
|
SetHelpFixHook() ;
|
|
|
|
CRichEdit2View::OnEditFind() ;
|
|
|
|
RemoveHelpFixHook() ;
|
|
}
|
|
|
|
void CWordPadView::OnEditReplace()
|
|
{
|
|
SetHelpFixHook() ;
|
|
|
|
CRichEdit2View::OnEditReplace() ;
|
|
|
|
RemoveHelpFixHook() ;
|
|
}
|
|
|
|
void CWordPadView::OnEditProperties()
|
|
{
|
|
g_fDisableStandardHelp = TRUE ;
|
|
|
|
SetHelpFixHook() ;
|
|
|
|
CRichEdit2View::OnEditProperties() ;
|
|
|
|
RemoveHelpFixHook() ;
|
|
|
|
g_fDisableStandardHelp = FALSE ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWordPadView::XRichEditOleCallback
|
|
//
|
|
// We implement this so we can override the defaults that MFC has set up. For
|
|
// the most part, we just delegate to MFC.
|
|
//
|
|
|
|
BEGIN_INTERFACE_MAP(CWordPadView, CCtrlView)
|
|
// we use IID_IUnknown because richedit doesn't define an IID
|
|
INTERFACE_PART(CWordPadView, IID_IUnknown, WordPadRichEditOleCallback)
|
|
END_INTERFACE_MAP()
|
|
|
|
STDMETHODIMP_(ULONG) CWordPadView::XWordPadRichEditOleCallback::AddRef()
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
return pThis->m_xRichEditOleCallback.AddRef() ;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CWordPadView::XWordPadRichEditOleCallback::Release()
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
return pThis->m_xRichEditOleCallback.Release() ;
|
|
}
|
|
|
|
STDMETHODIMP CWordPadView::XWordPadRichEditOleCallback::QueryInterface(
|
|
REFIID iid, LPVOID* ppvObj)
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
return pThis->m_xRichEditOleCallback.QueryInterface(iid, ppvObj) ;
|
|
}
|
|
|
|
STDMETHODIMP CWordPadView::XWordPadRichEditOleCallback::GetNewStorage(LPSTORAGE* ppstg)
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
return pThis->m_xRichEditOleCallback.GetNewStorage(ppstg) ;
|
|
}
|
|
|
|
STDMETHODIMP CWordPadView::XWordPadRichEditOleCallback::GetInPlaceContext(
|
|
LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc,
|
|
LPOLEINPLACEFRAMEINFO lpFrameInfo)
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
// Turn off the mirroring so the server can do the caculation without any problem.
|
|
// We turn it on again in ShowContainerUI
|
|
MirrorTheContainer(FALSE);
|
|
|
|
return pThis->m_xRichEditOleCallback.GetInPlaceContext(lplpFrame, lplpDoc, lpFrameInfo) ;
|
|
}
|
|
|
|
STDMETHODIMP CWordPadView::XWordPadRichEditOleCallback::ShowContainerUI(BOOL fShow)
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
// Turn on the mirroring if object UI gonna deactivate.
|
|
if (fShow)
|
|
MirrorTheContainer(fShow);
|
|
|
|
return pThis->m_xRichEditOleCallback.ShowContainerUI(fShow) ;
|
|
}
|
|
|
|
STDMETHODIMP CWordPadView::XWordPadRichEditOleCallback::QueryInsertObject(
|
|
LPCLSID lpclsid, LPSTORAGE pstg, LONG cp)
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
return pThis->m_xRichEditOleCallback.QueryInsertObject(lpclsid, pstg, cp) ;
|
|
}
|
|
|
|
STDMETHODIMP CWordPadView::XWordPadRichEditOleCallback::DeleteObject(LPOLEOBJECT lpoleobj)
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
return pThis->m_xRichEditOleCallback.DeleteObject(lpoleobj) ;
|
|
}
|
|
|
|
STDMETHODIMP CWordPadView::XWordPadRichEditOleCallback::QueryAcceptData(
|
|
LPDATAOBJECT lpdataobj, CLIPFORMAT* lpcfFormat, DWORD reco,
|
|
BOOL fReally, HGLOBAL hMetaPict)
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
return pThis->m_xRichEditOleCallback.QueryAcceptData(lpdataobj, lpcfFormat, reco,
|
|
fReally, hMetaPict) ;
|
|
}
|
|
|
|
STDMETHODIMP CWordPadView::XWordPadRichEditOleCallback::ContextSensitiveHelp(BOOL fEnterMode)
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
return pThis->m_xRichEditOleCallback.ContextSensitiveHelp(fEnterMode) ;
|
|
}
|
|
|
|
STDMETHODIMP CWordPadView::XWordPadRichEditOleCallback::GetClipboardData(
|
|
CHARRANGE* lpchrg, DWORD reco, LPDATAOBJECT* lplpdataobj)
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
return pThis->m_xRichEditOleCallback.GetClipboardData(lpchrg, reco, lplpdataobj) ;
|
|
}
|
|
|
|
STDMETHODIMP CWordPadView::XWordPadRichEditOleCallback::GetDragDropEffect(
|
|
BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect)
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
if (!fDrag) // allowable dest effects
|
|
{
|
|
DWORD dwEffect;
|
|
|
|
// check for force link
|
|
#ifndef _MAC
|
|
if ((grfKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
|
|
#else
|
|
if ((grfKeyState & (MK_OPTION|MK_SHIFT)) == (MK_OPTION|MK_SHIFT))
|
|
#endif
|
|
dwEffect = DROPEFFECT_LINK;
|
|
// check for force copy
|
|
#ifndef _MAC
|
|
else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
|
|
#else
|
|
else if ((grfKeyState & MK_OPTION) == MK_OPTION)
|
|
#endif
|
|
dwEffect = DROPEFFECT_COPY;
|
|
// check for force move
|
|
else if ((grfKeyState & MK_ALT) == MK_ALT)
|
|
dwEffect = DROPEFFECT_MOVE;
|
|
// default -- recommended action is 'copy' (overridden from MFC default)
|
|
else
|
|
{
|
|
if (g_fInternalDragDrop)
|
|
{
|
|
dwEffect = DROPEFFECT_MOVE ;
|
|
}
|
|
else
|
|
{
|
|
dwEffect = DROPEFFECT_COPY;
|
|
}
|
|
}
|
|
|
|
pThis->m_nPasteType = 0;
|
|
|
|
if (dwEffect & *pdwEffect) // make sure allowed type
|
|
{
|
|
*pdwEffect = dwEffect;
|
|
|
|
if (DROPEFFECT_LINK == dwEffect)
|
|
pThis->m_nPasteType = COlePasteSpecialDialog::pasteLink;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CWordPadView::XWordPadRichEditOleCallback::GetContextMenu(
|
|
WORD seltype, LPOLEOBJECT lpoleobj, CHARRANGE* lpchrg,
|
|
HMENU* lphmenu)
|
|
{
|
|
METHOD_PROLOGUE_EX_(CWordPadView, WordPadRichEditOleCallback)
|
|
|
|
HRESULT hr;
|
|
|
|
if (g_fRightButtonDrag)
|
|
hr = E_FAIL;
|
|
else
|
|
hr = pThis->m_xRichEditOleCallback.GetContextMenu(
|
|
seltype,
|
|
lpoleobj,
|
|
lpchrg,
|
|
lphmenu);
|
|
|
|
g_fRightButtonDrag = FALSE;
|
|
|
|
return hr;
|
|
}
|