WindowsXP-SP1/windows/richedit/re41/object.cpp
2020-09-30 16:53:49 +02:00

599 lines
14 KiB
C++

/*
* @doc INTERNAL
*
* @module object.cpp IRichEditOle implementation |
*
* Author: alexgo 8/15/95
*
* Copyright (c) 1995-2000, Microsoft Corporation. All rights reserved.
*/
#include "_common.h"
#include "_edit.h"
#include "_objmgr.h"
#include "_coleobj.h"
#include "_rtext.h"
#include "_select.h"
#include "_m_undo.h"
#include "_disp.h"
// IUnknown is implemented elsewhere
/*
* CTxtEdit::GetClientSite (lplpolesite)
*
* @mfunc returns the client site
*/
STDMETHODIMP CTxtEdit::GetClientSite(
LPOLECLIENTSITE FAR * lplpolesite) //@parm where to return
//the client site
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::GetClientSite");
if(!lplpolesite)
return E_INVALIDARG;
COleObject *pobj = new COleObject(this);
// should start with a ref count of 1.
if(pobj)
{
*lplpolesite = (IOleClientSite *)pobj;
return NOERROR;
}
*lplpolesite = NULL;
return E_OUTOFMEMORY;
}
/*
* CTxtEdit::GetObjectCount
*
* @mfunc return the number of objects in this edit instance
*/
STDMETHODIMP_(LONG) CTxtEdit::GetObjectCount()
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::GetObjectCount");
return _pobjmgr ? _pobjmgr->GetObjectCount() : 0;
}
/*
* CTxtEdit::GetLinkCount
*
* @mfunc return the number of likns in this edit instance
*/
STDMETHODIMP_(LONG) CTxtEdit::GetLinkCount()
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::GetLinkCount");
CObjectMgr *pobjmgr = GetObjectMgr();
return pobjmgr ? pobjmgr->GetLinkCount() : 0;
}
/*
* CTxtEdit::GetObject(iob, preobj, dwFlags)
*
* @mfunc returns an object structure for the indicated object
*/
STDMETHODIMP CTxtEdit::GetObject(
LONG iob, //@parm index of the object
REOBJECT * preobj, //@parm where to put object info
DWORD dwFlags) //@parm flags
{
COleObject *pobj = NULL;
CCallMgr callmgr(this);
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::GetObject");
if(!preobj || preobj->cbStruct != sizeof(REOBJECT))
return E_INVALIDARG;
CObjectMgr *pobjmgr = GetObjectMgr();
if(!pobjmgr)
return E_OUTOFMEMORY;
// There are three cases of intestest; get the object at
// an index, at a given cp, or at the selection.
if(iob == REO_IOB_USE_CP || iob == REO_IOB_SELECTION)
{
if((Get10Mode() && preobj->cp == REO_CP_SELECTION) || iob == REO_IOB_SELECTION)
{
// Use selection cp
CTxtSelection *psel = GetSel();
if(psel)
pobj = pobjmgr->GetObjectFromCp(psel->GetCpMin());
}
else
pobj = pobjmgr->GetObjectFromCp(Get10Mode() ? GetCpFromAcp(preobj->cp): preobj->cp);
}
else if (iob >= 0)
pobj = pobjmgr->GetObjectFromIndex(iob);
if(pobj)
{
HRESULT hResult = pobj->GetObjectData(preobj, dwFlags);
if (Get10Mode())
preobj->cp = GetAcpFromCp(preobj->cp);
return hResult;
}
// This return code is a bit of stretch, but basially
return E_INVALIDARG;
}
/*
* CTxtEdit::InsertObject (preobj)
*
* @mfunc inserts a new object
*
* @rdesc
* HRESULT
*/
STDMETHODIMP CTxtEdit::InsertObject(
REOBJECT * preobj) //@parm object info
{
CCallMgr callmgr(this);
CTxtRange rg(this, 0);
IUndoBuilder * publdr;
CGenUndoBuilder undobldr(this, UB_AUTOCOMMIT, &publdr);
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::InsertObject");
// Do some boundary case checking
if(!preobj)
return E_INVALIDARG;
CTxtSelection *psel = GetSel();
if(!psel)
return E_OUTOFMEMORY;
// The following code gives Outlook major fits if you click on a name in
// the To:, Cc:, or Bcc: fields, so I've commented it out. In principle,
// Outlook's EN_PROTECTION handler should say it's OK to insert in this case.
//
// if(!IsntProtectedOrReadOnly(0, 0, 0))
// return E_ACCESSDENIED;
// If the insertion of this character would cause
// us to exceed the text limit, fail
if((DWORD)(GetAdjustedTextLength() + 1) > TxGetMaxLength())
{
// If we're not replacing a selection (or the
// selection is degenerate, then we will have exceeded
// our limit
if(preobj->cp != REO_CP_SELECTION || psel->GetCch() == 0)
{
GetCallMgr()->SetMaxText();
return E_OUTOFMEMORY;
}
}
CObjectMgr *pobjmgr = GetObjectMgr();
if(pobjmgr)
{
LONG cch = 0;
LONG cp;
undobldr.StopGroupTyping();
if(preobj->cp == REO_CP_SELECTION)
{
LONG cpFormat;
LONG cpMost;
psel->AdjustEndEOP(NEWCHARS);
cch = psel->GetRange(cp, cpMost);
// Get cp of active end of selection from which we
// will obtain CF for object.
cpFormat = psel->GetCp();
if(publdr)
HandleSelectionAEInfo(this, publdr, cpFormat, cch,
cp + 1, 0, SELAE_FORCEREPLACE);
// Get format for ReplaceRange: for cp semantics, use format
// at the cp; for selection semantics, use the format at the
// active end of the selection.
rg.SetCp(cpFormat, FALSE);
LONG iFormat = rg.Get_iCF();
rg.Set(cp, -cch);
rg.Set_iCF(iFormat); // Use _iFormat at sel active end
rg.SetUseiFormat(TRUE);
ReleaseFormats(iFormat, -1);
}
else
{
cp = Get10Mode() ? GetCpFromAcp(preobj->cp): preobj->cp;
rg.SetCp(cp, FALSE); // Updates rg._iFormat
}
if(preobj->dwFlags & REO_USEASBACKGROUND)
{
CDocInfo *pDocInfo = GetDocInfo();
if(pDocInfo)
pDocInfo->InitBackground();
}
HRESULT hr = pobjmgr->InsertObject(&rg, preobj, publdr);
CNotifyMgr *pnm = GetNotifyMgr(); // Get notification mgr
if(pnm) // Notify interested parties
pnm->NotifyPostReplaceRange(NULL, CP_INFINITE, 0, 0, cp, cp + 1);
// Don't want object selected
psel->SetSelection(cp + 1, cp + 1);
if(preobj->dwFlags & REO_USEASBACKGROUND)
_pdp->UpdateView();
TxUpdateWindow();
return hr;
}
return E_OUTOFMEMORY;
}
/*
* CTxtEdit::ConvertObject(iob, rclsidNew, lpstrUserTypeNew)
*
* @mfunc Converts the specified object to the specified class. Does reload
* the object but does NOT force an update (caller must do this).
*
* @rdesc
* HRESULT Success code.
*/
STDMETHODIMP CTxtEdit::ConvertObject(
LONG iob, //@parm index of the object
REFCLSID rclsidNew, //@parm the destination clsid
LPCSTR lpstrUserTypeNew) //@parm the new user type name
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::ConvertObject");
CCallMgr callmgr(this);
// If iob was invalid return
COleObject * pobj = ObjectFromIOB(iob);
if(!pobj)
return E_INVALIDARG;
//Delegate to the object.
return pobj->Convert(rclsidNew, lpstrUserTypeNew);
}
/*
* CTxtEdit::ActivateAs(rclsid, rclsidAs)
*
* @mfunc Handles a request by the user to activate all objects of a
* particular class as objects of another class.
*
* @rdesc
* HRESULT Success code.
*/
STDMETHODIMP CTxtEdit::ActivateAs(
REFCLSID rclsid, //@parm clsid which we're going to change
REFCLSID rclsidAs) //@parm clsid to activate as
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::ActivateAs");
CCallMgr callmgr(this);
CObjectMgr * pobjmgr = GetObjectMgr();
if(!pobjmgr)
return E_OUTOFMEMORY;
return pobjmgr->ActivateObjectsAs(rclsid, rclsidAs);
}
/*
* CTxtEdit::SetHostNames(lpstrContainerApp, lpstrContainerDoc)
*
* @mfunc Sets the host names for this instance
*/
STDMETHODIMP CTxtEdit::SetHostNames(
LPCSTR lpstrContainerApp, //@parm App name
LPCSTR lpstrContainerDoc) //@parm Container Object (doc) name
{
CCallMgr callmgr(this);
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::SetHostNames");
WCHAR *pwsContainerApp = W32->ConvertToWideChar(lpstrContainerApp);
WCHAR *pwsContainerDoc = W32->ConvertToWideChar(lpstrContainerDoc);
CObjectMgr *pobjmgr = GetObjectMgr();
if(pobjmgr && pwsContainerApp && pwsContainerDoc)
{
HRESULT hr = pobjmgr->SetHostNames(pwsContainerApp, pwsContainerDoc);
delete pwsContainerApp;
delete pwsContainerDoc;
return hr;
}
return E_OUTOFMEMORY;
}
/*
* CTxtEdit::SetLinkAvailable(iob, fAvailable)
*
* @mfunc
* Allows client to tell us whether the link is available or not.
*/
STDMETHODIMP CTxtEdit::SetLinkAvailable(
LONG iob, //@parm index of the object
BOOL fAvailable) //@parm if TRUE, make object linkable
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::SetLinkAvailable");
COleObject * pobj = ObjectFromIOB(iob);
// If iob was invalid, return
if (!pobj)
return E_INVALIDARG;
// Delegate this to the object.
return pobj->SetLinkAvailable(fAvailable);
}
/*
* CTxtEdit::SetDvaspect(iob, dvaspect)
*
* @mfunc Allows client to tell us which aspect to use and force us
* to recompute positioning and redraw.
*
* @rdesc
* HRESULT Success code.
*/
STDMETHODIMP CTxtEdit::SetDvaspect(
LONG iob, //@parm index of the object
DWORD dvaspect) //@parm the aspect to use
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::SetDvaspect");
CCallMgr callmgr(this);
COleObject * pobj = ObjectFromIOB(iob);
// If iob was invalid, return
if (!pobj)
return E_INVALIDARG;
// Delegate this to the object.
pobj->SetDvaspect(dvaspect);
return NOERROR;
}
/*
* CTxtEdit::HandsOffStorage(iob)
*
* @mfunc see IPersistStorage::HandsOffStorage
*
* @rdesc
* HRESULT Success code.
*/
STDMETHODIMP CTxtEdit::HandsOffStorage(
LONG iob) //@parm index of the object
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::HandsOffStorage");
CCallMgr callmgr(this);
COleObject * pobj = ObjectFromIOB(iob);
// If iob was invalid, return
if (!pobj)
return E_INVALIDARG;
// Delegate this to the object.
pobj->HandsOffStorage();
return NOERROR;
}
/*
* CTxtEdit::SaveCompleted(iob, lpstg)
*
* @mfunc see IPersistStorage::SaveCompleted
*
* @rdesc
* HRESULT Success code.
*/
STDMETHODIMP CTxtEdit::SaveCompleted(
LONG iob, //@parm index of the object
LPSTORAGE lpstg) //@parm new storage
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::SaveCompleted");
CCallMgr callmgr(this);
COleObject * pobj = ObjectFromIOB(iob);
// If iob was invalid, return
if (!pobj)
return E_INVALIDARG;
// Delegate this to the object.
pobj->SaveCompleted(lpstg);
return NOERROR;
}
/*
* CTxtEdit::InPlaceDeactivate()
*
* @mfunc Deactivate
*/
STDMETHODIMP CTxtEdit::InPlaceDeactivate()
{
COleObject *pobj;
HRESULT hr = NOERROR;
CCallMgr callmgr(this);
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::InPlaceDeactivate");
CObjectMgr *pobjmgr = GetObjectMgr();
if(pobjmgr)
{
pobj = pobjmgr->GetInPlaceActiveObject();
if(pobj)
hr = pobj->DeActivateObj();
}
return hr;
}
/*
* CTxtEdit::ContextSensitiveHelp(fEnterMode)
*
* @mfunc enter/leave ContextSensitiveHelp mode
*
* @rdesc
* HRESULT Success code.
*/
STDMETHODIMP CTxtEdit::ContextSensitiveHelp(
BOOL fEnterMode) //@parm enter/exit mode
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::ContextSensitiveHelp");
HRESULT hr = NOERROR;
CCallMgr callmgr(this);
CObjectMgr * pobjmgr = GetObjectMgr();
if(!pobjmgr)
return E_OUTOFMEMORY;
// If the mode changes
if(pobjmgr->GetHelpMode() != fEnterMode)
{
pobjmgr->SetHelpMode(fEnterMode);
COleObject * pobj = pobjmgr->GetInPlaceActiveObject();
if(pobj)
{
IOleWindow *pow;
hr = pobj->GetIUnknown()->QueryInterface(IID_IOleWindow,
(void **)&pow);
if(hr == NOERROR)
{
hr = pow->ContextSensitiveHelp(fEnterMode);
pow->Release();
}
}
}
return hr;
}
/*
* CTxtEdit::GetClipboardData(lpchrg, reco, lplpdataobj)
*
* @mfunc return an data transfer object for the indicated
* range
*
* @rdesc
* HRESULT Success code.
*/
STDMETHODIMP CTxtEdit::GetClipboardData(
CHARRANGE *lpchrg, //@parm the range of text to use
DWORD reco, //@parm operation the data is for
LPDATAOBJECT *lplpdataobj) //@parm where to put the data object
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::GetClipboardData");
CCallMgr callmgr(this);
HRESULT hr;
LONG cpMin, cpMost;
CLightDTEngine * pldte = GetDTE();
//Make sure cpMin and cpMost are within the current text limits.
//Interpret neg. value for cpMin as the beginning of the text,
//and neg. value for cpMax as the end of the text. If a char range
//is not given use the current selection.
if(lpchrg)
{
LONG cchText = GetTextLength();
cpMin = max(0, lpchrg->cpMin);
cpMin = min(cchText, lpchrg->cpMin);
cpMost = lpchrg->cpMost;
if(lpchrg->cpMost < 0 || lpchrg->cpMost > cchText)
cpMost = cchText;
}
else
{
CTxtSelection * psel = GetSel();
psel->GetRange(cpMin, cpMost);
}
//Make sure this is a valid range.
if(cpMin >= cpMost)
{
*lplpdataobj = NULL;
return cpMin == cpMost
? NOERROR
: ResultFromScode(E_INVALIDARG);
}
CTxtRange rg(this, cpMin, cpMin-cpMost);
//We don't use reco for anything.
hr = pldte->RangeToDataObject(&rg, SF_RTF, lplpdataobj);
#if !defined(NOFULLDEBUG) && defined(DEBUG)
if(hr != NOERROR)
TRACEERRSZSC("GetClipboardData", E_OUTOFMEMORY);
#endif
return hr;
}
/*
* CTxtEdit::ImportDataObject(lpdataobj, cf, hMetaPict)
*
* @mfunc morally equivalent to paste, but with a data object
*
* @rdesc
* HRESULT Success code.
*/
STDMETHODIMP CTxtEdit::ImportDataObject(
LPDATAOBJECT lpdataobj, //@parm Data object to use
CLIPFORMAT cf, //@parm Clibpoard format to use
HGLOBAL hMetaPict) //@parm Metafile to use
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CTxtEdit::ImportDataObject");
CCallMgr callmgr(this);
IUndoBuilder * publdr;
REPASTESPECIAL rps = {DVASPECT_CONTENT, NULL};
CGenUndoBuilder undobldr(this, UB_AUTOCOMMIT, &publdr);
if(hMetaPict)
{
rps.dwAspect = DVASPECT_ICON;
rps.dwParam = (DWORD_PTR) hMetaPict;
}
return PasteDataObjectToRange(lpdataobj, GetSel(), cf,
&rps, publdr, PDOR_NOQUERY);
}
/*
* CTxtEdit::ObjectFromIOB(iob)
*
* @mfunc Gets an object based on an IOB type index.
*
* @rdesc:
* pointer to COleObject or NULL if none.
*/
COleObject * CTxtEdit::ObjectFromIOB(
LONG iob)
{
CObjectMgr * pobjmgr = GetObjectMgr();
if(!pobjmgr)
return NULL;
COleObject * pobj = NULL;
// Figure out the index of the selection
if (iob == REO_IOB_SELECTION)
{
CTxtSelection * psel = GetSel();
pobj = pobjmgr->GetFirstObjectInRange(psel->GetCpMin(),
psel->GetCpMost());
}
else
{
// Make sure the IOB is in range
if(0 <= iob && iob < GetObjectCount())
pobj = pobjmgr->GetObjectFromIndex(iob);
}
return pobj;
}