objmgr.cpp

来自「Windows CE 6.0 Word Application 源码」· C++ 代码 · 共 1,028 行 · 第 1/2 页

CPP
1,028
字号
{
	DWORD i, count;
	COleObject *pobj;

 	TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::~CObjectMgr");

	count = _objarray.Count();

	for( i = 0; i < count; i++ )
	{
		pobj = *_objarray.Elem(i);
		// we NULL stuff here to try to protect ourselves
		// better in re-entrancy cases.
		*_objarray.Elem(i) = NULL;
		if( pobj )
		{
			pobj->Close(OLECLOSE_NOSAVE);
  			pobj->MakeZombie();
    		SafeReleaseAndNULL((IUnknown**)&pobj);
		}
	}

	if( _precall )
	{
        SafeReleaseAndNULL((IUnknown**)&_precall);
	}
		
	if( _pszApp )
	{
		delete _pszApp;
	}
	if( _pszDoc )
	{
		delete _pszDoc;
	}
}

/*
 *	CObjectMgr::ReplaceRange
 *
 *	@mfunc	handles the deletion of objects from a given range.  This
 *			method _must_ be called before any floating range notifications
 *			are sent.
 *
 *	@rdesc	void
 */
void CObjectMgr::ReplaceRange(
	DWORD cp,				//@parm the cp starting the deletion
	DWORD cchDel,			//@parm the number of characters deleted
	IUndoBuilder *publdr)	//@parm the undo builder for this actions
{
	DWORD	i;
	DWORD	iDel = (DWORD)-1, 
			cDel = 0;	// index at which to delete && number of objects
						// to delete.
	COleObject *pobj;

	// nothing deleted, don't bother doing anything.
	if( !cchDel )
	{
		return;
	}


	// basically, we loop through all of the objects within the
	// range of deleted text and ask them to delete themselves.
	// We remember the range of objects deleted (the starting index
	// and # of objects deleted) so that we can remove them from
	// the array all at once.

	i = FindIndexForCp(cp);

	while( i < _objarray.Count() )
	{
		pobj = *_objarray.Elem(i);

		if( pobj && pobj->GetCp() >= cp)
		{
			if( pobj->GetCp() < (cp + cchDel) )
			{
				if( _pobjactive == pobj )
				{
					// Deactivate the object just to be on the safe side.
					_pobjactive->DeActivateObj();
					_pobjactive = NULL;
				}

				if( iDel == (DWORD)-1 )
				{
					iDel = i;
				}
				cDel++;

				if (_precall)
				{
					IOleObject *poo;
					if (pobj->GetIUnknown()->QueryInterface(IID_IOleObject,
						(void **)&poo) == NOERROR)
					{
						_precall->DeleteObject(poo);
						poo->Release();
					}
				}

				// if the object was selected, then it obviously
				// can't be anymore!
				if( _pobjselect == pobj )
				{
					_pobjselect = NULL;
				}

				pobj->Delete(publdr);
				*_objarray.Elem(i) = NULL;
				pobj->Release();
			}
			else
			{
				break;
			}
		}
		i++;
	}

	if( cDel )
	{
		_objarray.Remove(iDel, cDel, AF_DELETEMEM);
	}

	return;
}

/*
 *	CObjectMgr::ScrollObjects
 *
 *	@mfunc	informs all objects that scrolling has occured so they can
 *			update if necessary
 *
 *	@rdesc	void
 */
void CObjectMgr::ScrollObjects(
	LONG dx,			//@parm change in the x direction
	LONG dy,			//@parm change in the y direction
	LPCRECT prcScroll)	//@parm the rect that is being scrolled
{
	DWORD i, count;
	COleObject *pobj;
	
	count = _objarray.Count();
	
	for( i = 0; i < count; i++ )
	{
		pobj = *_objarray.Elem(i);
		if( pobj )
		{
			pobj->ScrollObject(dx, dy, prcScroll);
		}
	}
} 	

//
//	PRIVATE methods
//

/*
 *	CObjectMgr::FindIndexForCp
 *
 *	@mfunc	does a binary search to find the index at which an object
 *			at the given cp exists or should be inserted.
 *
 *	@rdesc	DWORD, an index
 */
DWORD CObjectMgr::FindIndexForCp(DWORD cp)
{
	LONG l, r;
	COleObject *pobj = NULL;
	DWORD i = 0;
		
	l = 0; 
	r = _objarray.Count() - 1;
	
	while( r >= l )
	{
		i = (l + r)/2;
		
		pobj = *_objarray.Elem(i);
		
		if( !pobj )
		{
			TRACEWARNSZ("null entry in object table.  Recovering...");
			for( i = 0 ; i < _objarray.Count() -1; i++ )
			{
				pobj = *_objarray.Elem(i);
				if( pobj && pobj->GetCp() >= cp )
				{
					return i;
				}
			}
			return i;
		}
			
		if( pobj->GetCp() == cp )
		{
			return i;
		}
		else if( pobj->GetCp() < cp )
		{
			l = i + 1;
		}
		else
		{
			r = i - 1;
		}
	}

	// yikes! nothing was found.  Fixup i so that
	// it points to the correct index for insertion.

	Assert(pobj || (!pobj && i == 0));

	if( pobj  )
	{
		Assert(pobj->GetCp() != cp);
		if( pobj->GetCp() < cp )
		{
			i++;
		}
	}
					
	return i;
}
						
/*
 *	CObjectMgr::HandleDoubleClick
 *	
 *	@mfunc		Handles a double click message, potentially activating
 *				an object.
 *
 *	@rdesc		BOOL-- TRUE if double click-processing is completely
 *				finished.
 */
BOOL CObjectMgr::HandleDoubleClick(
	CTxtEdit *ped,	//@parm edit context
	const POINT &pt,//@parm the point of the click (WM_LBUTTONDBLCLK wparam)
	DWORD flags)	//@parm flags (lparam)
{
	DWORD cp;
	COleObject *pobj;

	TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, 
						"CObjectMgr::HandleDoubleClick");

	cp = ped->_pdp->CpFromPoint(pt, NULL, NULL, NULL, FALSE);


	pobj = FindObjectAtPointNearCp(pt, cp);

	if (!pobj)
	{
		return FALSE;
	}

	if (_pobjactive != pobj)
	{
		//Deactivate currently active object if any.
		if (_pobjactive)
		{
			_pobjactive->DeActivateObj();
		}

		return pobj->ActivateObj(WM_LBUTTONDBLCLK, MAKELONG(pt.x, pt.y), 
					flags);
	}
	
	return TRUE;
}

/*
 *	CObjectMgr::HandleClick
 *	
 *	@mfunc
 *		The position of the caret is changing.  We need to
 *		Deactivate the active object, if any.  If the change is
 *		because of a mouse click and there is an object at this
 *		cp, we set a new individually selected object. Otherwise
 *		we set the individually selected object to NULL.
 *
 *	@rdesc	returns TRUE if this method set the selection.  Otherwise,
 *		returns FALSE;
 */
ClickStatus CObjectMgr::HandleClick(
	CTxtEdit *ped,	//@parm the edit context
	const POINT &pt)//@parm the point of the mouse click 
{
	COleObject *	pobjnew;//, * pobjold;
	CTxtSelection * psel;
	DWORD			cp;
	LONG			cpMin, cpMost;

 	TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::HandleClick");

	
	if( _pobjactive )
	{
		_pobjactive->DeActivateObj();
		return CLICK_OBJDEACTIVATED;
	}

	cp = ped->_pdp->CpFromPoint(pt, NULL, NULL, NULL, FALSE);
	pobjnew = FindObjectAtPointNearCp(pt, cp);

	//If we clicked on an object, set the selection to this object.
	//CTxtSelection::UpdateSelection will be called as a result of this
	//and will determine the highlighting.
	if( pobjnew )
	{
		cp = pobjnew->GetCp();
		psel = ped->GetSel();
		if (psel->GetRange(cpMin, cpMost) > 1 &&
			cpMin <= (LONG) cp &&
			(LONG) cp <= cpMost)
		{
			// There is more than one character in the selection
			// And the object is part of the selection.
			// Do not change the selection
			return CLICK_SHOULDDRAG;
		}
		
		// don't reset the selection if the object is already selected
		if( pobjnew != _pobjselect )
		{
			// Freeze the Display while we handle this click
			CFreezeDisplay fd(ped->_pdp);

			psel->SetSelection(cp, cp+1);
			if (GetSingleSelect())
			{
				// Note thate the call to SetSelection may have set selected object to NULL !!!!
				// This can happen in some strange scenarios where our state is out of whack
				AssertSz(GetSingleSelect() == pobjnew, "Object NOT Selected!!");
				return CLICK_OBJSELECTED;
			}
			return CLICK_IGNORED;
		}
		return CLICK_OBJSELECTED;
	}

	return CLICK_IGNORED;
}

/*
 *	CObjectMgr::HandleSingleSelect
 *	
 *	@mfunc
 *		When an object is selected and it is the only thing selected, we do
 *		not highlight it by inverting it.  We Draw a frame and handles around
 *		it.  This function is called either because an object has been
 *		selected and it is the only thing selected, or because we need to
 *		check for an object that used to be in this state but may no longer be.
 *
 */
void CObjectMgr::HandleSingleSelect(
	CTxtEdit *ped,	//@parm the edit context
	DWORD cp,		//@parm cp of object
	BOOL fHiLite)	//@parm is this a call for hding the selection
{
 	TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::HandleSingleSelect");

	COleObject* pobjnew;

	pobjnew = GetObjectFromCp(cp);

	//This should only be called when we know we have a singley selected
	//object.  However, there are boundary cases (such as inserting an object)
	//where WCH_EMBEDDING is the backing store yet no object exists.  These
	//cases are OK; thus, we check for NULL on pobjnew.
	
	if (pobjnew)
	{
		//The object is the same as the currently selected object (if any)
		//we are deselecting it.  This works like a toggle unless state is messed up.
		//If the object is different, we are replacing the current selected
		//object (if any).
		if (!fHiLite && _pobjselect)
		{
			// This covers _pobjselct == pobjnew  Normal case
			//  and _pobjselect != pobjnew  Degenerate case.
			_pobjselect->SetREOSELECTED(FALSE);
			_pobjselect = NULL;

			//Remove frame/handles from currently selected object.
			ped->_pdp->OnPostReplaceRange(INFINITE, 0, 0, cp, cp + 1);
		}
		else if (fHiLite && pobjnew != _pobjselect)
		{
			// Only do this if we are setting a new selection.
			_pobjselect = pobjnew;
			_pobjselect->SetREOSELECTED(TRUE);

			//Draw frame/handles on newly selected object.
			ped->_pdp->OnPostReplaceRange(INFINITE, 0, 0, cp, cp + 1);
		}
		else
		{
			// We want to hilite the selection but the object is already selected.
			// Or we want to undo hilite on the selection but the selected object is NULL.
			// Do nothing.
		}
	}

	return;
}

/*
 *	CObjectMgr::FindObjectAtPointNearCp
 *
 *	@mfunc		if an object exists at the given point, return
 *				it.  <p cp> is used to help narrow the search
 *				of which objects to look for.
 *
 *	@rdesc		the object, if found.  NULL otherwise
 */
COleObject *CObjectMgr::FindObjectAtPointNearCp(
	const POINT &pt,//@parm the point in question
	DWORD cp)		//@parm hinting cp
{
	LONG i, stop;
	COleObject *pobj;

 	TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, 
				"CObjectMgr::FindObjectAtPointNearCp");

	// the cp tells us roughly where the object should be in the
	// stream; however, it may be one to the left or one to the right.

	i = FindIndexForCp(cp);

	stop = i + 1;
	i--;

	for( ; i <= stop ; i++ )
	{
		if( i >= 0 && i < (LONG)_objarray.Count() )
		{
			pobj = *_objarray.Elem(i);
			if( pobj && PtInRect(pobj->GetPosRect(), pt) && 
				(pobj->GetCp() == cp || pobj->GetCp() == cp - 1) )
			{
				return pobj;
			}
		}
	}

	return NULL;
}

/*
 *	CObjectMgr::ActivateObjectsAs
 *
 *	@mfunc	Handles a request by the user to activate all objects of a particular
 *		class as objects of another class.
 *
 *	@rdesc
 *		HRESULT				Success code.
 */
HRESULT CObjectMgr::ActivateObjectsAs(REFCLSID rclsid, REFCLSID rclsidAs)
{
	TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CObjectMgr::ActivateObjectsAs");

	COleObject * pobj;
	DWORD cobj, iobj;
	HRESULT hr, hrLatest;

	// Tell the system to treat all rclsid objects as rclsidAs
	hr = pCoTreatAsClass(rclsid, rclsidAs);

	if( hr != NOERROR )
	{
		return hr;
	}

	cobj = GetObjectCount();

	//Go through the objects, letting them decide if
	//they have anything to do for this.
	for (iobj = 0; iobj < cobj; iobj++)
	{
		pobj = GetObjectFromIndex(iobj);
		hrLatest = pobj->ActivateAs(rclsid, rclsidAs);
		//Make hr the latest hresult unless we have previously
		//had an error.
		if( hr == NOERROR )
		{
			hr = hrLatest;
		}
	}
	
	return hr;
}

#ifdef DEBUG
void CObjectMgr::DbgDump(void)
{
	Tracef(TRCSEVNONE, "Object Manager %d objects", _objarray.Count());

	for( DWORD i = 0 ; i < _objarray.Count();  i++ )
	{
		COleObject *pobj = *_objarray.Elem(i);
		if( pobj )
		{
			pobj->DbgDump( i );
		}
	}
}
#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?