PADITEM.CPP

//=------------------------------------------------------------------------= 
// PadItem.Cpp
//=------------------------------------------------------------------------=
// Copyright 1992-1997 Microsoft Corporation. All Rights Reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//=--------------------------------------------------------------------------=
//
// implementation of the CEmbeddedItem class
//

#include "stdafx.h"
#include "padview.h"
#include "paddoc.h"
#include "paditem.h"
#include <limits.h>
#include <winnls.h>

IMPLEMENT_DYNAMIC(CEmbeddedItem, COleServerItem)

CEmbeddedItem::CEmbeddedItem(CPadDoc* pContainerDoc)
: COleServerItem(pContainerDoc, TRUE)
{
m_nBeg = 0;
m_nEnd = UINT_MAX;

// support CF_TEXT format
GetDataSource()->DelayRenderFileData(CF_TEXT);
}

BOOL CEmbeddedItem::OnRenderFileData(LPFORMATETC lpFormatEtc, CFile* pFile)
{
ASSERT(lpFormatEtc != NULL);
if (lpFormatEtc->cfFormat != CF_TEXT)
return COleServerItem::OnRenderFileData(lpFormatEtc, pFile);

BOOL bResult = FALSE;
TRY
{
// save contents of this item to the file
SaveToFile(pFile);

// CF_TEXT has NUL termination
char chZero = '\0';
pFile->Write(&chZero, sizeof(char));

bResult = TRUE; // success
}
END_TRY

return bResult;
}

CPadView* CEmbeddedItem::GetView() const
{
CDocument* pDoc = GetDocument();
ASSERT_VALID(pDoc);
POSITION pos = pDoc->GetFirstViewPosition();
if (pos == NULL)
return NULL;

CPadView* pView = (CPadView*)pDoc->GetNextView(pos);
ASSERT_VALID(pView);
ASSERT_KINDOF(CPadView, pView);
return pView;
}

void CEmbeddedItem::SaveToFile(CFile* pFile)
{
CPadView* pView = GetView();
LPCTSTR lpszText = NULL;

TRY
{
// get access to the edit buffer
lpszText = pView->LockBuffer();

// get range (make sure inside of text length)
UINT nEnd = pView->GetWindowTextLength();
UINT nBeg = min(m_nBeg, nEnd);
nEnd = min(m_nEnd, nEnd);
#ifdef _UNICODE
// copy to temp buffer, convert, then write to file
int nLen = WideCharToMultiByte(CP_ACP, 0, lpszText+nBeg, nEnd-nBeg,
NULL, 0, NULL, NULL);
char* pszTemp = new char[nLen];
WideCharToMultiByte(CP_ACP, 0, lpszText+nBeg, nEnd-nBeg,
pszTemp, nLen, NULL, NULL);
pFile->Write(pszTemp, nLen);
delete[] pszTemp;
#else
// write it out to the file
pFile->Write(lpszText+nBeg, (nEnd-nBeg) * sizeof(char));
#endif
}
END_TRY

// release access to edit buffer
if (lpszText != NULL)
pView->UnlockBuffer();
}

void CEmbeddedItem::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// save just the portion this item refers to
ar.Flush();
CFile* pFile = ar.GetFile();
SaveToFile(pFile);
}
else
{
// otherwise, read in the entire file
GetDocument()->Serialize(ar);
}
}

BOOL CEmbeddedItem::OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize)
{
if (dwDrawAspect != DVASPECT_CONTENT)
return COleServerItem::OnGetExtent(dwDrawAspect, rSize);

// no drawing will happen if cliprect is NULL
CClientDC dc(NULL);
dc.IntersectClipRect(0, 0, 0, 0);
return OnDraw(&dc, rSize);
}

BOOL CEmbeddedItem::OnDraw(CDC* pDC, CSize& rSize)
{
// get view attached to the item
CPadView* pView = GetView();

// In some situations, OLE1 servers will ask for the presentation data
// during shutdown, even though it is not necessary (since the picture
// has not changed). This will happen when closing a frame window
// for example. By this time all the views are gone and there is no
// way to produce the metafile data, since the actual text is
// stored by the edit control (the view). In this case, we simply
// fail the call.
if (pView == NULL)
return FALSE;

// edit controls have a border around them
CRect rectClient;
CRect margin;

{ // Calculate correct ClientRect
pView->GetClientRect(&rectClient);
rectClient.InflateRect(-1,-1);

if (pView->GetStyle() & WS_HSCROLL)
rectClient.bottom++;
if (pView->GetStyle() & WS_VSCROLL)
rectClient.right++;
}

{ // Calculate margins
CRect rectEdit;
pView->GetEditCtrl().GetRect(&rectEdit);

if (rectEdit.IsRectEmpty())
rectEdit.SetRect(4,4,4,4);

int HorzMargin = rectEdit.left - rectClient.left;
int VertMargin = rectEdit.top - rectClient.top;

margin.SetRect(HorzMargin,VertMargin,HorzMargin,VertMargin);

if (pView->GetStyle() & WS_HSCROLL)
margin.bottom++;
if (pView->GetStyle() & WS_VSCROLL)
margin.right++;
}

// get the font from the CEditView
CFont* pFont = pView->GetFont();
CFont* pOldFont = NULL;
if (pFont != NULL)
pOldFont = pDC->SelectObject(pFont);

// get formatting rectangle
CRect rect(rectClient);
rect.left += margin.left;
rect.top += margin.top;
rect.right -= margin.right;
rect.bottom = INT_MAX;

pDC->SetBkMode(TRANSPARENT);

// first just determine the correct extents of the text
pDC->SaveDC();
pDC->IntersectClipRect(0, 0, 0, 0); // no drawing with NULL clipping
if (pView->PrintInsideRect(pDC, rect, m_nBeg, m_nEnd) == 0)
{
TEXTMETRIC tm;
pDC->GetTextMetrics(&tm);
rect.bottom = rect.top + tm.tmHeight + tm.tmExternalLeading;
}
pDC->RestoreDC(-1);

// then, really output the text
pDC->SetWindowOrg(rect.left-margin.left,rect.top-margin.top);
pDC->SetWindowExt(margin.left + rect.Width() + margin.right,
margin.top + rect.Height() + margin.bottom);
pView->PrintInsideRect(pDC, rect, m_nBeg, m_nEnd);

// adjust for border (rect.left is already adjusted)
rect.left -= margin.left;
rect.top -= margin.top;
rect.right += margin.right;
rect.bottom += margin.bottom;

// select previous font
if (pOldFont != NULL)
pDC->SelectObject(pOldFont);

// return HIMETRIC size
rSize = rect.Size();
pDC->LPtoHIMETRIC(&rSize);
return TRUE;
}

/////////////////////////////////////////////////////////////////////////////