/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: svdmrkv.cxx,v $
 * $Revision: 1.39.74.1 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"

#include <svx/svdmrkv.hxx>
#include <svx/svdetc.hxx>
#include <svx/svdoedge.hxx>
#include "svdglob.hxx"
#include "svditext.hxx"
#include <svx/svdview.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdpage.hxx>
#include "svddrgm1.hxx"

#ifdef DBG_UTIL
#include <svdibrow.hxx>
#endif

#include <svx/svdoole2.hxx>
#include <svx/xgrad.hxx>
#include <svx/xflgrit.hxx>

#include "gradtrns.hxx"
#include <svx/xflftrit.hxx>

#include <svx/dialmgr.hxx>
#include "svdstr.hrc"
#include <svx/svdundo.hxx>

// #105722#
#include <svx/svdopath.hxx>

// #i13033#
#include <svx/scene3d.hxx>

// OD 30.06.2003 #108784#
#include <svx/svdovirt.hxx>
#include <svx/sdr/overlay/overlayrollingrectangle.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
#include <sdrpaintwindow.hxx>
#include <svx/sdrpagewindow.hxx>

////////////////////////////////////////////////////////////////////////////////////////////////////
// predefines

class SdrUnoControlList;

////////////////////////////////////////////////////////////////////////////////////////////////////
// #114409#-3 Migrate Marking of Objects, Points and GluePoints

class ImplMarkingOverlay
{
	// The OverlayObjects
	::sdr::overlay::OverlayObjectList				maObjects;

	// The remembered second position in logical coodinates
	basegfx::B2DPoint								maSecondPosition;

	// bitfield
	// A flag to remember if the action is for unmarking.
	unsigned										mbUnmarking : 1;

public:
	ImplMarkingOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos, sal_Bool bUnmarking = sal_False);
	~ImplMarkingOverlay();

	void SetSecondPosition(const basegfx::B2DPoint& rNewPosition);
	sal_Bool IsUnmarking() const { return mbUnmarking; }
};

ImplMarkingOverlay::ImplMarkingOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos, sal_Bool bUnmarking)
:	maSecondPosition(rStartPos),
	mbUnmarking(bUnmarking)
{
	for(sal_uInt32 a(0L); a < rView.PaintWindowCount(); a++)
	{
		SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
		::sdr::overlay::OverlayManager* pTargetOverlay = pCandidate->GetOverlayManager();

		if(pTargetOverlay)
		{
			::sdr::overlay::OverlayRollingRectangleStriped* pNew = new ::sdr::overlay::OverlayRollingRectangleStriped(
				rStartPos, rStartPos, sal_False);
			pTargetOverlay->add(*pNew);
			maObjects.append(*pNew);
		}
	}
}

ImplMarkingOverlay::~ImplMarkingOverlay()
{
	// The OverlayObjects are cleared using the destructor of OverlayObjectList.
	// That destructor calls clear() at the list which removes all objects from the
	// OverlayManager and deletes them.
}

void ImplMarkingOverlay::SetSecondPosition(const basegfx::B2DPoint& rNewPosition)
{
	if(rNewPosition != maSecondPosition)
	{
		// apply to OverlayObjects
		for(sal_uInt32 a(0L); a < maObjects.count(); a++)
		{
			::sdr::overlay::OverlayRollingRectangleStriped& rCandidate = (::sdr::overlay::OverlayRollingRectangleStriped&)maObjects.getOverlayObject(a);
			rCandidate.setSecondPosition(rNewPosition);
		}

		// remember new position
		maSecondPosition = rNewPosition;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  @@   @@  @@@@  @@@@@  @@  @@  @@ @@ @@ @@@@@ @@   @@
//  @@@ @@@ @@  @@ @@  @@ @@  @@  @@ @@ @@ @@    @@   @@
//  @@@@@@@ @@  @@ @@  @@ @@ @@   @@ @@ @@ @@    @@ @ @@
//  @@@@@@@ @@@@@@ @@@@@  @@@@    @@@@@ @@ @@@@  @@@@@@@
//  @@ @ @@ @@  @@ @@  @@ @@ @@    @@@  @@ @@    @@@@@@@
//  @@   @@ @@  @@ @@  @@ @@  @@   @@@  @@ @@    @@@ @@@
//  @@   @@ @@  @@ @@  @@ @@  @@    @   @@ @@@@@ @@   @@
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void SdrMarkView::ImpClearVars()
{
	eDragMode=SDRDRAG_MOVE;
	//HMHbHdlShown=FALSE;
	bRefHdlShownOnly=FALSE;
	eEditMode=SDREDITMODE_EDIT;
	eEditMode0=SDREDITMODE_EDIT;
	bDesignMode=FALSE;
	pMarkedObj=NULL;
	pMarkedPV=NULL;
	bForceFrameHandles=FALSE;
	bPlusHdlAlways=FALSE;
	nFrameHandlesLimit=50;
	bInsPolyPoint=FALSE;
	mnInsPointNum = 0L;
	bMarkedObjRectDirty=FALSE;
	bMarkedPointsRectsDirty=FALSE;
	mbMarkHandlesHidden = false;
	bMrkPntDirty=FALSE;
	bMarkHdlWhenTextEdit=FALSE;
	bMarkableObjCountDirty=FALSE; // noch nicht implementiert
	nMarkableObjCount=0;          // noch nicht implementiert

	// #114409#-3 Migrate selections
	BrkMarkObj();
	BrkMarkPoints();
	BrkMarkGluePoints();
}

SdrMarkView::SdrMarkView(SdrModel* pModel1, OutputDevice* pOut)
:	SdrSnapView(pModel1,pOut),
	mpMarkObjOverlay(0L),
	mpMarkPointsOverlay(0L),
	mpMarkGluePointsOverlay(0L),
	aHdl(this),
	mpSdrViewSelection(new sdr::ViewSelection())
{
	ImpClearVars();
	StartListening(*pModel1);
}

SdrMarkView::~SdrMarkView()
{
	// #114409#-3 Migrate selections
	BrkMarkObj();
	BrkMarkPoints();
	BrkMarkGluePoints();
	delete mpSdrViewSelection;
}

void __EXPORT SdrMarkView::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
{
	SdrHint* pSdrHint=PTR_CAST(SdrHint,&rHint);
	if (pSdrHint!=NULL) 
	{
		SdrHintKind eKind=pSdrHint->GetKind();

		if (eKind==HINT_OBJCHG || eKind==HINT_OBJINSERTED || eKind==HINT_OBJREMOVED) 
		{
			bMarkedObjRectDirty=TRUE;
			bMarkedPointsRectsDirty=TRUE;
		}
	}
	SdrSnapView::Notify(rBC,rHint);
}

void SdrMarkView::ModelHasChanged()
{
	SdrPaintView::ModelHasChanged();
	GetMarkedObjectListWriteAccess().SetNameDirty();
	bMarkedObjRectDirty=TRUE;
	bMarkedPointsRectsDirty=TRUE;
	// Es sind beispielsweise Obj markiert und maMarkedObjectListist Sorted.
	// In einer anderen View 2 wird die ObjOrder veraendert
	// (z.B. MovToTop()). Dann ist Neusortieren der MarkList erforderlich.
	GetMarkedObjectListWriteAccess().SetUnsorted();
	SortMarkedObjects();
	bMrkPntDirty=TRUE;
	UndirtyMrkPnt();
	SdrView* pV=(SdrView*)this;
	if (pV!=NULL && !pV->IsDragObj() && !pV->IsInsObjPoint()) { // an dieser Stelle habe ich ein ziemliches Problem !!!
		AdjustMarkHdl();
	}
}

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

BOOL SdrMarkView::IsAction() const
{
	return SdrSnapView::IsAction() || IsMarkObj() || IsMarkPoints() || IsMarkGluePoints();
}

void SdrMarkView::MovAction(const Point& rPnt)
{
	SdrSnapView::MovAction(rPnt);
	
	if(IsMarkObj()) 
	{
		MovMarkObj(rPnt);
	}
	else if(IsMarkPoints()) 
	{
		MovMarkPoints(rPnt);
	}
	else if(IsMarkGluePoints()) 
	{
		MovMarkGluePoints(rPnt);
	}
}

void SdrMarkView::EndAction()
{
	if(IsMarkObj()) 
	{
		EndMarkObj();
	}
	else if(IsMarkPoints()) 
	{
		EndMarkPoints();
	}
	else if(IsMarkGluePoints()) 
	{
		EndMarkGluePoints();
	}

	SdrSnapView::EndAction();
}

void SdrMarkView::BckAction()
{
	SdrSnapView::BckAction();
	BrkMarkObj();
	BrkMarkPoints();
	BrkMarkGluePoints();
}

void SdrMarkView::BrkAction()
{
	SdrSnapView::BrkAction();
	BrkMarkObj();
	BrkMarkPoints();
	BrkMarkGluePoints();
}

void SdrMarkView::TakeActionRect(Rectangle& rRect) const
{
	if(IsMarkObj() || IsMarkPoints() || IsMarkGluePoints()) 
	{
		rRect = Rectangle(aDragStat.GetStart(), aDragStat.GetNow());
	} 
	else 
	{
		SdrSnapView::TakeActionRect(rRect);
	}
}

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

void SdrMarkView::ClearPageView()
{
	UnmarkAllObj();
	SdrSnapView::ClearPageView();
}

void SdrMarkView::HideSdrPage()
{
	bool bMrkChg(false);
	//HMHbool bVis(false);

	if(mpPageView)
	{
		// break all creation actions when hiding page (#75081#)
		BrkAction();
		//HMHbVis = IsMarkHdlShown();

		//HMHif(bVis)
		//HMH{
		//HMH	HideMarkHdl();
		//HMH}

		// Alle Markierungen dieser Seite verwerfen
		bMrkChg = GetMarkedObjectListWriteAccess().DeletePageView(*mpPageView);
	}

	SdrSnapView::HideSdrPage();

	if(bMrkChg)
	{
		MarkListHasChanged();
		AdjustMarkHdl();
	}

	//HMHif(bVis)
	//HMH{
	//HMH	ShowMarkHdl();
	//HMH}
}

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

sal_Bool SdrMarkView::BegMarkObj(const Point& rPnt, sal_Bool bUnmark)
{
	BrkAction();

	DBG_ASSERT(0L == mpMarkObjOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkObjOverlay (!)");
	basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
	mpMarkObjOverlay = new ImplMarkingOverlay(*this, aStartPos, bUnmark);

	aDragStat.Reset(rPnt);
	aDragStat.NextPoint();
	aDragStat.SetMinMove(nMinMovLog);
	
	return sal_True;
}

void SdrMarkView::MovMarkObj(const Point& rPnt)
{
	if(IsMarkObj() && aDragStat.CheckMinMoved(rPnt)) 
	{
		aDragStat.NextMove(rPnt);
		DBG_ASSERT(mpMarkObjOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
		basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
		mpMarkObjOverlay->SetSecondPosition(aNewPos);
	}
}

sal_Bool SdrMarkView::EndMarkObj()
{
	sal_Bool bRetval(sal_False);

	if(IsMarkObj()) 
	{
		if(aDragStat.IsMinMoved()) 
		{
			Rectangle aRect(aDragStat.GetStart(), aDragStat.GetNow());
			aRect.Justify();
			MarkObj(aRect, mpMarkObjOverlay->IsUnmarking());
			bRetval = sal_True;
		}

		// cleanup
		BrkMarkObj();
	}

	return bRetval;
}

void SdrMarkView::BrkMarkObj()
{
	if(IsMarkObj()) 
	{
		DBG_ASSERT(mpMarkObjOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
		delete mpMarkObjOverlay;
		mpMarkObjOverlay = 0L;
	}
}

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

sal_Bool SdrMarkView::BegMarkPoints(const Point& rPnt, sal_Bool bUnmark)
{
	if(HasMarkablePoints()) 
	{
		BrkAction();

		DBG_ASSERT(0L == mpMarkPointsOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkPointsOverlay (!)");
		basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
		mpMarkPointsOverlay = new ImplMarkingOverlay(*this, aStartPos, bUnmark);

		aDragStat.Reset(rPnt);
		aDragStat.NextPoint();
		aDragStat.SetMinMove(nMinMovLog);

		return sal_True;
	} 

	return sal_False;
}

void SdrMarkView::MovMarkPoints(const Point& rPnt)
{
	if(IsMarkPoints() && aDragStat.CheckMinMoved(rPnt)) 
	{
		aDragStat.NextMove(rPnt);

		DBG_ASSERT(mpMarkPointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
		basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
		mpMarkPointsOverlay->SetSecondPosition(aNewPos);
	}
}

sal_Bool SdrMarkView::EndMarkPoints()
{
	sal_Bool bRetval(sal_False);

	if(IsMarkPoints()) 
	{
		if(aDragStat.IsMinMoved())
		{
			Rectangle aRect(aDragStat.GetStart(), aDragStat.GetNow());
			aRect.Justify();
			MarkPoints(aRect, mpMarkPointsOverlay->IsUnmarking());

			bRetval = sal_True;
		}

		// cleanup
		BrkMarkPoints();
	}

	return bRetval;
}

void SdrMarkView::BrkMarkPoints()
{
	if(IsMarkPoints()) 
	{
		DBG_ASSERT(mpMarkPointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
		delete mpMarkPointsOverlay;
		mpMarkPointsOverlay = 0L;
	}
}

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

sal_Bool SdrMarkView::BegMarkGluePoints(const Point& rPnt, sal_Bool bUnmark)
{
	if(HasMarkableGluePoints()) 
	{
		BrkAction();
		
		DBG_ASSERT(0L == mpMarkGluePointsOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkGluePointsOverlay (!)");
		basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
		mpMarkGluePointsOverlay = new ImplMarkingOverlay(*this, aStartPos, bUnmark);

		aDragStat.Reset(rPnt);
		aDragStat.NextPoint();
		aDragStat.SetMinMove(nMinMovLog);
		
		return sal_True;
	} 

	return sal_False;
}

void SdrMarkView::MovMarkGluePoints(const Point& rPnt)
{
	if(IsMarkGluePoints() && aDragStat.CheckMinMoved(rPnt)) 
	{
		aDragStat.NextMove(rPnt);

		DBG_ASSERT(mpMarkGluePointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
		basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
		mpMarkGluePointsOverlay->SetSecondPosition(aNewPos);
	}
}

sal_Bool SdrMarkView::EndMarkGluePoints()
{
	sal_Bool bRetval(sal_False);

	if(IsMarkGluePoints()) 
	{
		if(aDragStat.IsMinMoved())
		{
			Rectangle aRect(aDragStat.GetStart(),aDragStat.GetNow());
			aRect.Justify();
			MarkGluePoints(&aRect, mpMarkGluePointsOverlay->IsUnmarking());

			bRetval = sal_True;
		}

		// cleanup
		BrkMarkGluePoints();
	}

	return bRetval;
}

void SdrMarkView::BrkMarkGluePoints()
{
	if(IsMarkGluePoints()) 
	{
		DBG_ASSERT(mpMarkGluePointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
		delete mpMarkGluePointsOverlay;
		mpMarkGluePointsOverlay = 0L;
	}
}

BOOL SdrMarkView::HasMarkableObj() const
{
	ULONG nCount=0;

	SdrPageView* pPV = GetSdrPageView();
	if(pPV)
	{
		SdrObjList* pOL=pPV->GetObjList();
		ULONG nObjAnz=pOL->GetObjCount();
		for (ULONG nObjNum=0; nObjNum<nObjAnz && nCount==0; nObjNum++) {
			SdrObject* pObj=pOL->GetObj(nObjNum);
			if (IsObjMarkable(pObj,pPV)) {
				nCount++;
			}
		}
	}
	return nCount!=0;
}

ULONG SdrMarkView::GetMarkableObjCount() const
{
	ULONG nCount=0;
	SdrPageView* pPV = GetSdrPageView();

	if(pPV)
	{
		SdrObjList* pOL=pPV->GetObjList();
		ULONG nObjAnz=pOL->GetObjCount();
		for (ULONG nObjNum=0; nObjNum<nObjAnz; nObjNum++) {
			SdrObject* pObj=pOL->GetObj(nObjNum);
			if (IsObjMarkable(pObj,pPV)) {
				nCount++;
			}
		}
	}
	return nCount;
}

//HMHvoid SdrMarkView::ImpShowMarkHdl(bool /*bNoRefHdl*/)
//HMH{
//HMH	bNoRefHdl=FALSE; // geht leider erstmal nicht anders
//HMH	if (!bHdlShown) {
//HMH		bRefHdlShownOnly=FALSE;
//HMH		bHdlShown=TRUE;
//HMH	}
//HMH}

//HMHvoid SdrMarkView::ShowMarkHdl(bool /*bNoRefHdl*/)
//HMH{
//HMH	bNoRefHdl=FALSE; // geht leider erstmal nicht anders
//HMH	ImpShowMarkHdl(bNoRefHdl);
//HMH}


//HMHvoid SdrMarkView::HideMarkHdl(bool /*bNoRefHdl*/)
//HMH{
//HMH	bNoRefHdl=FALSE; // geht leider erstmal nicht anders
//HMH	if (bHdlShown) {
//HMH		bRefHdlShownOnly=bNoRefHdl;
//HMH		bHdlShown=FALSE;
//HMH	}
//HMH}

void SdrMarkView::hideMarkHandles()
{
	if(!mbMarkHandlesHidden)
	{
		mbMarkHandlesHidden = true;
		AdjustMarkHdl();
	}
}

void SdrMarkView::showMarkHandles()
{
	if(mbMarkHandlesHidden)
	{
		mbMarkHandlesHidden = false;
		AdjustMarkHdl();
	}
}

BOOL SdrMarkView::ImpIsFrameHandles() const
{
	ULONG nMarkAnz=GetMarkedObjectCount();
	BOOL bFrmHdl=nMarkAnz>nFrameHandlesLimit || bForceFrameHandles;
	BOOL bStdDrag=eDragMode==SDRDRAG_MOVE;
	if (nMarkAnz==1 && bStdDrag && bFrmHdl)
	{
		const SdrObject* pObj=GetMarkedObjectByIndex(0);
		if (pObj->GetObjInventor()==SdrInventor)
		{
			UINT16 nIdent=pObj->GetObjIdentifier();
			if (nIdent==OBJ_LINE || nIdent==OBJ_EDGE || nIdent==OBJ_CAPTION || nIdent==OBJ_MEASURE || nIdent==OBJ_CUSTOMSHAPE || nIdent==OBJ_TABLE )
			{
				bFrmHdl=FALSE;
			}
		}
	}
	if (!bStdDrag && !bFrmHdl) {
		// Grundsaetzlich erstmal alle anderen Dragmodi nur mit FrameHandles
		bFrmHdl=TRUE;
		if (eDragMode==SDRDRAG_ROTATE) {
			// bei Rotate ObjOwn-Drag, wenn mind. 1 PolyObj
			for (ULONG nMarkNum=0; nMarkNum<nMarkAnz && bFrmHdl; nMarkNum++) {
				const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
				const SdrObject* pObj=pM->GetMarkedSdrObj();
				bFrmHdl=!pObj->IsPolyObj();
			}
		}
	}
	if (!bFrmHdl) {
		// FrameHandles, wenn wenigstens 1 Obj kein SpecialDrag kann
		for (ULONG nMarkNum=0; nMarkNum<nMarkAnz && !bFrmHdl; nMarkNum++) {
			const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
			const SdrObject* pObj=pM->GetMarkedSdrObj();
			bFrmHdl=!pObj->hasSpecialDrag();
		}
	}
	return bFrmHdl;
}

void SdrMarkView::SetMarkHandles()
{
	// #105722# remember old focus handle values to search for it again
	const SdrHdl* pSaveOldFocusHdl = aHdl.GetFocusHdl();
	sal_Bool bSaveOldFocus(sal_False);
	sal_uInt32 nSavePolyNum(0L), nSavePointNum(0L);
	SdrHdlKind eSaveKind(HDL_MOVE);
	SdrObject* pSaveObj = NULL;

	if(pSaveOldFocusHdl
		&& pSaveOldFocusHdl->GetObj()
		&& pSaveOldFocusHdl->GetObj()->ISA(SdrPathObj)
		&& (pSaveOldFocusHdl->GetKind() == HDL_POLY || pSaveOldFocusHdl->GetKind() == HDL_BWGT))
	{
		bSaveOldFocus = sal_True;
		nSavePolyNum = pSaveOldFocusHdl->GetPolyNum();
		nSavePointNum = pSaveOldFocusHdl->GetPointNum();
		pSaveObj = pSaveOldFocusHdl->GetObj();
		eSaveKind = pSaveOldFocusHdl->GetKind();
	}

	// delete/clear all handles. This will always be done, even with areMarkHandlesHidden()
	aHdl.Clear();
	aHdl.SetRotateShear(eDragMode==SDRDRAG_ROTATE);
	aHdl.SetDistortShear(eDragMode==SDRDRAG_SHEAR);
	pMarkedObj=NULL;
	pMarkedPV=NULL;
	
	// are handles enabled at all? Create only then
	if(!areMarkHandlesHidden())
	{
		ULONG nMarkAnz=GetMarkedObjectCount();
		BOOL bStdDrag=eDragMode==SDRDRAG_MOVE;
		BOOL bSingleTextObjMark=FALSE;

		if (nMarkAnz==1) 
		{
			pMarkedObj=GetMarkedObjectByIndex(0);
            bSingleTextObjMark = 
                pMarkedObj && 
                pMarkedObj->ISA(SdrTextObj) &&
                static_cast<SdrTextObj*>(pMarkedObj)->IsTextFrame();
		}
		
		BOOL bFrmHdl=ImpIsFrameHandles();
		
		if (nMarkAnz>0) 
		{
			pMarkedPV=GetSdrPageViewOfMarkedByIndex(0);
			
			for (ULONG nMarkNum=0; nMarkNum<nMarkAnz && (pMarkedPV!=NULL || !bFrmHdl); nMarkNum++) 
			{
				const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
			
				if (pMarkedPV!=pM->GetPageView()) 
				{
					pMarkedPV=NULL;
				}
			}
		}
		
		if (bFrmHdl) 
		{
			Rectangle aRect(GetMarkedObjRect());

			// #i33755#
			const sal_Bool bHideHandlesWhenInTextEdit(
				((SdrView*)this)->IsTextEdit()
				&& pMarkedObj 
				&& pMarkedObj->ISA(SdrTextObj) 
				&& ((SdrTextObj*)pMarkedObj)->IsInEditMode());
			
			if(!aRect.IsEmpty() && !bHideHandlesWhenInTextEdit) 
			{ // sonst nix gefunden
                if( bSingleTextObjMark )
                {
                    const ULONG nSiz0=aHdl.GetHdlCount();
                    pMarkedObj->AddToHdlList(aHdl);
                    const ULONG nSiz1=aHdl.GetHdlCount();
                    for (ULONG i=nSiz0; i<nSiz1; i++) 
                    {
                        SdrHdl* pHdl=aHdl.GetHdl(i);
                        pHdl->SetObj(pMarkedObj);
                        pHdl->SetPageView(pMarkedPV);
                        pHdl->SetObjHdlNum(USHORT(i-nSiz0));
                    }
                }
                else if( eDragMode==SDRDRAG_CROP )
				{
					aHdl.AddHdl(new SdrCropHdl(aRect.TopLeft()     ,HDL_UPLFT));
					aHdl.AddHdl(new SdrCropHdl(aRect.TopCenter()   ,HDL_UPPER));
					aHdl.AddHdl(new SdrCropHdl(aRect.TopRight()    ,HDL_UPRGT));
					aHdl.AddHdl(new SdrCropHdl(aRect.LeftCenter()  ,HDL_LEFT ));
					aHdl.AddHdl(new SdrCropHdl(aRect.RightCenter() ,HDL_RIGHT));
					aHdl.AddHdl(new SdrCropHdl(aRect.BottomLeft()  ,HDL_LWLFT));
					aHdl.AddHdl(new SdrCropHdl(aRect.BottomCenter(),HDL_LOWER));
					aHdl.AddHdl(new SdrCropHdl(aRect.BottomRight() ,HDL_LWRGT));
				}
				else
				{
					BOOL bWdt0=aRect.Left()==aRect.Right();
					BOOL bHgt0=aRect.Top()==aRect.Bottom();
					if (bWdt0 && bHgt0) 
					{
						aHdl.AddHdl(new SdrHdl(aRect.TopLeft(),HDL_UPLFT));
					} 
					else if (!bStdDrag && (bWdt0 || bHgt0)) 
					{
						aHdl.AddHdl(new SdrHdl(aRect.TopLeft()    ,HDL_UPLFT));
						aHdl.AddHdl(new SdrHdl(aRect.BottomRight(),HDL_LWRGT));
					} 
					else 
					{
						if (!bWdt0 && !bHgt0) aHdl.AddHdl(new SdrHdl(aRect.TopLeft()     ,HDL_UPLFT));
						if (          !bHgt0) aHdl.AddHdl(new SdrHdl(aRect.TopCenter()   ,HDL_UPPER));
						if (!bWdt0 && !bHgt0) aHdl.AddHdl(new SdrHdl(aRect.TopRight()    ,HDL_UPRGT));
						if (!bWdt0          ) aHdl.AddHdl(new SdrHdl(aRect.LeftCenter()  ,HDL_LEFT ));
						if (!bWdt0          ) aHdl.AddHdl(new SdrHdl(aRect.RightCenter() ,HDL_RIGHT));
						if (!bWdt0 && !bHgt0) aHdl.AddHdl(new SdrHdl(aRect.BottomLeft()  ,HDL_LWLFT));
						if (          !bHgt0) aHdl.AddHdl(new SdrHdl(aRect.BottomCenter(),HDL_LOWER));
						if (!bWdt0 && !bHgt0) aHdl.AddHdl(new SdrHdl(aRect.BottomRight() ,HDL_LWRGT));
					}
				}
			}
		} 
		else 
		{
			for (ULONG nMarkNum=0; nMarkNum<nMarkAnz; nMarkNum++) 
			{
				const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
				SdrObject* pObj=pM->GetMarkedSdrObj();
				SdrPageView* pPV=pM->GetPageView();
				const ULONG nSiz0=aHdl.GetHdlCount();
				pObj->AddToHdlList(aHdl);
				const ULONG nSiz1=aHdl.GetHdlCount();
				bool bPoly=pObj->IsPolyObj();
				const SdrUShortCont* pMrkPnts=pM->GetMarkedPoints();
				for (ULONG i=nSiz0; i<nSiz1; i++) 
				{
					SdrHdl* pHdl=aHdl.GetHdl(i);
					pHdl->SetObj(pObj);
					pHdl->SetPageView(pPV);
					pHdl->SetObjHdlNum(USHORT(i-nSiz0));
					if (bPoly) 
					{
						BOOL bSelected=pMrkPnts!=NULL && pMrkPnts->Exist(USHORT(i-nSiz0));
						pHdl->SetSelected(bSelected);
						//BOOL bPlus=bPlusHdlAlways;
						if (bPlusHdlAlways || bSelected) 
						{
							sal_uInt32 nPlusAnz=pObj->GetPlusHdlCount(*pHdl);
							for (sal_uInt32 nPlusNum=0; nPlusNum<nPlusAnz; nPlusNum++) 
							{
								SdrHdl* pPlusHdl=pObj->GetPlusHdl(*pHdl,nPlusNum);
								if (pPlusHdl!=NULL) 
								{
									pPlusHdl->SetObj(pObj);
									pPlusHdl->SetPageView(pPV);
									pPlusHdl->SetPlusHdl(TRUE);
									aHdl.AddHdl(pPlusHdl);
								}
							}
						}
					}
				}
			} // for nMarkNum
		} // if bFrmHdl else

		// GluePoint-Handles
		for (ULONG nMarkNum=0; nMarkNum<nMarkAnz; nMarkNum++) 
		{
			const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
			SdrObject* pObj=pM->GetMarkedSdrObj();
			SdrPageView* pPV=pM->GetPageView();
			const SdrUShortCont* pMrkGlue=pM->GetMarkedGluePoints();
			if (pMrkGlue!=NULL) 
			{
				const SdrGluePointList* pGPL=pObj->GetGluePointList();
				if (pGPL!=NULL) 
				{
					//USHORT nGlueAnz=pGPL->GetCount();
					USHORT nAnz=(USHORT)pMrkGlue->GetCount();
					for (USHORT nNum=0; nNum<nAnz; nNum++) 
					{
						USHORT nId=pMrkGlue->GetObject(nNum);
						//nNum changed to nNumGP because already used in for loop
						USHORT nNumGP=pGPL->FindGluePoint(nId);
						if (nNumGP!=SDRGLUEPOINT_NOTFOUND) 
						{
							const SdrGluePoint& rGP=(*pGPL)[nNumGP];
							Point aPos(rGP.GetAbsolutePos(*pObj));
							SdrHdl* pGlueHdl=new SdrHdl(aPos,HDL_GLUE);
							pGlueHdl->SetObj(pObj);
							pGlueHdl->SetPageView(pPV);
							pGlueHdl->SetObjHdlNum(nId);
							aHdl.AddHdl(pGlueHdl);
						}
					}
				}
			}
		}

		// Drehpunkt/Spiegelachse
		AddDragModeHdl(eDragMode);

		// add custom handles (used by other apps, e.g. AnchorPos)
		AddCustomHdl();

		// sort handles
		aHdl.Sort();

		// #105722# try to restore focus handle index from remembered values
		if(bSaveOldFocus)
		{
			for(sal_uInt32 a(0); a < aHdl.GetHdlCount(); a++)
			{
				SdrHdl* pCandidate = aHdl.GetHdl(a);

				if(pCandidate->GetObj()
					&& pCandidate->GetObj() == pSaveObj
					&& pCandidate->GetKind() == eSaveKind
					&& pCandidate->GetPolyNum() == nSavePolyNum
					&& pCandidate->GetPointNum() == nSavePointNum)
				{
					aHdl.SetFocusHdl(pCandidate);
					break;
				}
			}
		}
	}
}

void SdrMarkView::AddCustomHdl()
{
	// add custom handles (used by other apps, e.g. AnchorPos)
}

void SdrMarkView::SetDragMode(SdrDragMode eMode)
{
	SdrDragMode eMode0=eDragMode;
	eDragMode=eMode;
	if (eDragMode==SDRDRAG_RESIZE) eDragMode=SDRDRAG_MOVE;
	if (eDragMode!=eMode0) {
		//HMHBOOL bVis=IsMarkHdlShown();
		//HMHif (bVis) HideMarkHdl();
		ForceRefToMarked();
		SetMarkHandles();
		//HMHif (bVis) ShowMarkHdl();
		{
			if (AreObjectsMarked()) MarkListHasChanged();
		}
	}
}

void SdrMarkView::AddDragModeHdl(SdrDragMode eMode)
{
	switch(eMode)
	{
		case SDRDRAG_ROTATE:
		{
			// add rotation center
			SdrHdl* pHdl = new SdrHdl(aRef1, HDL_REF1);

			aHdl.AddHdl(pHdl);

			break;
		}
		case SDRDRAG_MIRROR:
		{
			// add mirror axis
			SdrHdl* pHdl3 = new SdrHdl(aRef2, HDL_REF2);
			SdrHdl* pHdl2 = new SdrHdl(aRef1, HDL_REF1);
			SdrHdl* pHdl1 = new SdrHdlLine(*pHdl2, *pHdl3, HDL_MIRX);

			pHdl1->SetObjHdlNum(1); // fuer Sortierung
			pHdl2->SetObjHdlNum(2); // fuer Sortierung
			pHdl3->SetObjHdlNum(3); // fuer Sortierung

			aHdl.AddHdl(pHdl1); // Linie als erstes, damit als letztes im HitTest
			aHdl.AddHdl(pHdl2);
			aHdl.AddHdl(pHdl3);

			break;
		}
		case SDRDRAG_TRANSPARENCE:
		{
			// add interactive transparence handle
			ULONG nMarkAnz = GetMarkedObjectCount();
			if(nMarkAnz == 1)
			{
				SdrObject* pObj = GetMarkedObjectByIndex(0);
				SdrModel* pModel = GetModel();
				const SfxItemSet& rSet = pObj->GetMergedItemSet();

				if(SFX_ITEM_SET != rSet.GetItemState(XATTR_FILLFLOATTRANSPARENCE, FALSE))
				{
					// add this item, it's not yet there
					XFillFloatTransparenceItem aNewItem(
						(const XFillFloatTransparenceItem&)rSet.Get(XATTR_FILLFLOATTRANSPARENCE));
					XGradient aGrad = aNewItem.GetGradientValue();

					aNewItem.SetEnabled(TRUE);
					aGrad.SetStartIntens(100);
					aGrad.SetEndIntens(100);
					aNewItem.SetGradientValue(aGrad);

					// add undo to allow user to take back this step
					pModel->BegUndo(SVX_RESSTR(SIP_XA_FILLTRANSPARENCE));
					pModel->AddUndo(pModel->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
					pModel->EndUndo();
					
					//pObj->SetItemAndBroadcast(aNewItem);
					SfxItemSet aNewSet(pModel->GetItemPool());
					aNewSet.Put(aNewItem);
					pObj->SetMergedItemSetAndBroadcast(aNewSet);
				}

				// set values and transform to vector set
				GradTransformer aGradTransformer;
				GradTransVector aGradTransVector;
				GradTransGradient aGradTransGradient;

				aGradTransGradient.aGradient = ((XFillFloatTransparenceItem&)rSet.Get(XATTR_FILLFLOATTRANSPARENCE)).GetGradientValue();
				aGradTransformer.GradToVec(aGradTransGradient, aGradTransVector, pObj);

				// build handles
				const Point aTmpPos1(basegfx::fround(aGradTransVector.maPositionA.getX()), basegfx::fround(aGradTransVector.maPositionA.getY()));
				const Point aTmpPos2(basegfx::fround(aGradTransVector.maPositionB.getX()), basegfx::fround(aGradTransVector.maPositionB.getY()));
				SdrHdlColor* pColHdl1 = new SdrHdlColor(aTmpPos1, aGradTransVector.aCol1, SDR_HANDLE_COLOR_SIZE_NORMAL, TRUE);
				SdrHdlColor* pColHdl2 = new SdrHdlColor(aTmpPos2, aGradTransVector.aCol2, SDR_HANDLE_COLOR_SIZE_NORMAL, TRUE);
				SdrHdlGradient* pGradHdl = new SdrHdlGradient(aTmpPos1, aTmpPos2, FALSE);
				DBG_ASSERT(pColHdl1 && pColHdl2 && pGradHdl, "Got not all necessary handles!!");

				// link them
				pGradHdl->SetColorHandles(pColHdl1, pColHdl2);
				pGradHdl->SetObj(pObj);
				pColHdl1->SetColorChangeHdl(LINK(pGradHdl, SdrHdlGradient, ColorChangeHdl));
				pColHdl2->SetColorChangeHdl(LINK(pGradHdl, SdrHdlGradient, ColorChangeHdl));

				// insert them
				aHdl.AddHdl(pColHdl1);
				aHdl.AddHdl(pColHdl2);
				aHdl.AddHdl(pGradHdl);
			}
			break;
		}
		case SDRDRAG_GRADIENT:
		{
			// add interactive gradient handle
			ULONG nMarkAnz = GetMarkedObjectCount();
			if(nMarkAnz == 1)
			{
				SdrObject* pObj = GetMarkedObjectByIndex(0);
				const SfxItemSet& rSet = pObj->GetMergedItemSet();
				XFillStyle eFillStyle = ((XFillStyleItem&)(rSet.Get(XATTR_FILLSTYLE))).GetValue();

				if(eFillStyle == XFILL_GRADIENT)
				{
					// set values and transform to vector set
					GradTransformer aGradTransformer;
					GradTransVector aGradTransVector;
					GradTransGradient aGradTransGradient;
					Size aHdlSize(15, 15);

					aGradTransGradient.aGradient = ((XFillGradientItem&)rSet.Get(XATTR_FILLGRADIENT)).GetGradientValue();
					aGradTransformer.GradToVec(aGradTransGradient, aGradTransVector, pObj);

					// build handles
					const Point aTmpPos1(basegfx::fround(aGradTransVector.maPositionA.getX()), basegfx::fround(aGradTransVector.maPositionA.getY()));
					const Point aTmpPos2(basegfx::fround(aGradTransVector.maPositionB.getX()), basegfx::fround(aGradTransVector.maPositionB.getY()));
					SdrHdlColor* pColHdl1 = new SdrHdlColor(aTmpPos1, aGradTransVector.aCol1, aHdlSize, FALSE);
					SdrHdlColor* pColHdl2 = new SdrHdlColor(aTmpPos2, aGradTransVector.aCol2, aHdlSize, FALSE);
					SdrHdlGradient* pGradHdl = new SdrHdlGradient(aTmpPos1, aTmpPos2, TRUE);
					DBG_ASSERT(pColHdl1 && pColHdl2 && pGradHdl, "Got not all necessary handles!!");

					// link them
					pGradHdl->SetColorHandles(pColHdl1, pColHdl2);
					pGradHdl->SetObj(pObj);
					pColHdl1->SetColorChangeHdl(LINK(pGradHdl, SdrHdlGradient, ColorChangeHdl));
					pColHdl2->SetColorChangeHdl(LINK(pGradHdl, SdrHdlGradient, ColorChangeHdl));

					// insert them
					aHdl.AddHdl(pColHdl1);
					aHdl.AddHdl(pColHdl2);
					aHdl.AddHdl(pGradHdl);
				}
			}
			break;
		}
		case SDRDRAG_CROP:
		{
			// todo
			break;
		}
		default: break;
	}
}

void SdrMarkView::ForceRefToMarked()
{
	switch(eDragMode)
	{
		case SDRDRAG_ROTATE:
		{
			Rectangle aR(GetMarkedObjRect());
			aRef1 = aR.Center();

			break;
		}

		case SDRDRAG_MIRROR:
		{
			// Erstmal die laenge der Spiegelachsenlinie berechnen
			long nOutMin=0;
			long nOutMax=0;
			long nMinLen=0;
			long nObjDst=0;
			long nOutHgt=0;
			OutputDevice* pOut=GetFirstOutputDevice();
			//OutputDevice* pOut=GetWin(0);
			if (pOut!=NULL) {
				// Mindestlaenge 50 Pixel
				nMinLen=pOut->PixelToLogic(Size(0,50)).Height();
				// 20 Pixel fuer RefPt-Abstand vom Obj
				nObjDst=pOut->PixelToLogic(Size(0,20)).Height();
				// MinY/MaxY
				// Abstand zum Rand = Mindestlaenge = 10 Pixel
				long nDst=pOut->PixelToLogic(Size(0,10)).Height();
				nOutMin=-pOut->GetMapMode().GetOrigin().Y();
				nOutMax=pOut->GetOutputSize().Height()-1+nOutMin;
				nOutMin+=nDst;
				nOutMax-=nDst;
				// Absolute Mindestlaenge jedoch 10 Pixel
				if (nOutMax-nOutMin<nDst) {
					nOutMin+=nOutMax+1;
					nOutMin/=2;
					nOutMin-=(nDst+1)/2;
					nOutMax=nOutMin+nDst;
				}
				nOutHgt=nOutMax-nOutMin;
				// Sonst Mindestlaenge = 1/4 OutHgt
				long nTemp=nOutHgt/4;
				if (nTemp>nMinLen) nMinLen=nTemp;
			}

			Rectangle aR(GetMarkedObjBoundRect());
			Point aCenter(aR.Center());
			long nMarkHgt=aR.GetHeight()-1;
			long nHgt=nMarkHgt+nObjDst*2;       // 20 Pixel obej und unten ueberstehend
			if (nHgt<nMinLen) nHgt=nMinLen;     // Mindestlaenge 50 Pixel bzw. 1/4 OutHgt

			long nY1=aCenter.Y()-(nHgt+1)/2;
			long nY2=nY1+nHgt;

			if (pOut!=NULL && nMinLen>nOutHgt) nMinLen=nOutHgt; // evtl. noch etwas verkuerzen

			if (pOut!=NULL) { // nun vollstaendig in den sichtbaren Bereich schieben
				if (nY1<nOutMin) {
					nY1=nOutMin;
					if (nY2<nY1+nMinLen) nY2=nY1+nMinLen;
				}
				if (nY2>nOutMax) {
					nY2=nOutMax;
					if (nY1>nY2-nMinLen) nY1=nY2-nMinLen;
				}
			}

			aRef1.X()=aCenter.X();
			aRef1.Y()=nY1;
			aRef2.X()=aCenter.X();
			aRef2.Y()=nY2;

			break;
		}

		case SDRDRAG_TRANSPARENCE:
		case SDRDRAG_GRADIENT:
		case SDRDRAG_CROP:
		{
			Rectangle aRect(GetMarkedObjBoundRect());
			aRef1 = aRect.TopLeft();
			aRef2 = aRect.BottomRight();
			break;
		}
		default: break;
	}
}

void SdrMarkView::SetRef1(const Point& rPt)
{
	if(eDragMode == SDRDRAG_ROTATE || eDragMode == SDRDRAG_MIRROR)
	{
		aRef1 = rPt;
		SdrHdl* pH = aHdl.GetHdl(HDL_REF1);
		if(pH)
			pH->SetPos(rPt);
		//HMHShowMarkHdl();
	}
}

void SdrMarkView::SetRef2(const Point& rPt)
{
	if(eDragMode == SDRDRAG_MIRROR)
	{
		aRef2 = rPt;
		SdrHdl* pH = aHdl.GetHdl(HDL_REF2);
		if(pH)
			pH->SetPos(rPt);
		//HMHShowMarkHdl();
	}
}

void SdrMarkView::CheckMarked()
{
	for (ULONG nm=GetMarkedObjectCount(); nm>0;) {
		nm--;
		SdrMark* pM=GetSdrMarkByIndex(nm);
		SdrObject* pObj=pM->GetMarkedSdrObj();
		SdrPageView* pPV=pM->GetPageView();
		SdrLayerID nLay=pObj->GetLayer();
		BOOL bRaus=!pObj->IsInserted(); // Obj geloescht?
		if (!pObj->Is3DObj()) {
			bRaus=bRaus || pObj->GetPage()!=pPV->GetPage();   // Obj ploetzlich in anderer Page oder Group
		}
		bRaus=bRaus || pPV->GetLockedLayers().IsSet(nLay) ||  // Layer gesperrt?
					   !pPV->GetVisibleLayers().IsSet(nLay);  // Layer nicht sichtbar?
		if (!bRaus) {
			// Joe am 9.3.1997: Gruppierte Objekten koennen nun auch
			// markiert werden. Nach EnterGroup muessen aber die Objekte
			// der hoeheren Ebene deselektiert werden.
			const SdrObjList* pOOL=pObj->GetObjList();
			const SdrObjList* pVOL=pPV->GetObjList();
			while (pOOL!=NULL && pOOL!=pVOL) {
				pOOL=pOOL->GetUpList();
			}
			bRaus=pOOL!=pVOL;
		}

		if (bRaus) 
		{
			GetMarkedObjectListWriteAccess().DeleteMark(nm);
		} 
		else 
		{
			if (!IsGluePointEditMode()) { // Markierte GluePoints nur im GlueEditMode
				SdrUShortCont* pPts=pM->GetMarkedGluePoints();
				if (pPts!=NULL && pPts->GetCount()!=0) {
					pPts->Clear();
				}
			}
		}
	}

	// #97995# at least reset the remembered BoundRect to prevent handle
	// generation if bForceFrameHandles is TRUE.
	bMarkedObjRectDirty = TRUE;
}

void SdrMarkView::SetMarkRects()
{
	SdrPageView* pPV = GetSdrPageView();
	
	if(pPV)
	{
		pPV->SetHasMarkedObj(GetSnapRectFromMarkedObjects(pPV, pPV->MarkSnap()));
		GetBoundRectFromMarkedObjects(pPV, pPV->MarkBound());
	}
}

void SdrMarkView::SetFrameHandles(BOOL bOn)
{
	if (bOn!=bForceFrameHandles) {
		BOOL bOld=ImpIsFrameHandles();
		bForceFrameHandles=bOn;
		BOOL bNew=ImpIsFrameHandles();
		if (bNew!=bOld) {
			AdjustMarkHdl(); //HMHTRUE);
			MarkListHasChanged();
		}
	}
}

void SdrMarkView::SetEditMode(SdrViewEditMode eMode)
{
	if (eMode!=eEditMode) {
		BOOL bGlue0=eEditMode==SDREDITMODE_GLUEPOINTEDIT;
		BOOL bEdge0=((SdrCreateView*)this)->IsEdgeTool();
		eEditMode0=eEditMode;
		eEditMode=eMode;
		BOOL bGlue1=eEditMode==SDREDITMODE_GLUEPOINTEDIT;
		BOOL bEdge1=((SdrCreateView*)this)->IsEdgeTool();
		// etwas Aufwand um Flackern zu verhindern beim Umschalten
		// zwischen GlueEdit und EdgeTool
		if (bGlue1 && !bGlue0) ImpSetGlueVisible2(bGlue1);
		if (bEdge1!=bEdge0) ImpSetGlueVisible3(bEdge1);
		if (!bGlue1 && bGlue0) ImpSetGlueVisible2(bGlue1);
		if (bGlue0 && !bGlue1) UnmarkAllGluePoints();
	}
}

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

BOOL SdrMarkView::IsObjMarkable(SdrObject* pObj, SdrPageView* pPV) const
{
	if (pObj)
	{
		if (pObj->IsMarkProtect() ||
			(!bDesignMode && pObj->IsUnoObj()))
		{
			// Objekt nicht selektierbar oder
			// SdrUnoObj nicht im DesignMode
			return FALSE;
		}
	}
	return pPV!=NULL ? pPV->IsObjMarkable(pObj) : TRUE;
}

BOOL SdrMarkView::IsMarkedObjHit(const Point& rPnt, short nTol) const
{
	BOOL bRet=FALSE;
	nTol=ImpGetHitTolLogic(nTol,NULL);
	Point aPt(rPnt);
	for (ULONG nm=0; nm<GetMarkedObjectCount() && !bRet; nm++) {
		SdrMark* pM=GetSdrMarkByIndex(nm);
		bRet=ImpIsObjHit(aPt,USHORT(nTol),pM->GetMarkedSdrObj(),pM->GetPageView(),0);
	}
	return bRet;
}

SdrHdl* SdrMarkView::PickHandle(const Point& rPnt, ULONG nOptions, SdrHdl* pHdl0) const
{
	if (bSomeObjChgdFlag) { // ggf. Handles neu berechnen lassen!
		FlushComeBackTimer();
	}
	BOOL bBack=(nOptions & SDRSEARCH_BACKWARD) !=0;
	BOOL bNext=(nOptions & SDRSEARCH_NEXT) !=0;
	Point aPt(rPnt);
	return aHdl.IsHdlListHit(aPt,bBack,bNext,pHdl0);
}

BOOL SdrMarkView::MarkObj(const Point& rPnt, short nTol, BOOL bToggle, BOOL bDeep)
{
	SdrObject* pObj;
	SdrPageView* pPV;
	nTol=ImpGetHitTolLogic(nTol,NULL);
	ULONG nOptions=SDRSEARCH_PICKMARKABLE;
	if (bDeep) nOptions=nOptions|SDRSEARCH_DEEP;
	BOOL bRet=PickObj(rPnt,(USHORT)nTol,pObj,pPV,nOptions);
	if (bRet) {
		BOOL bUnmark=bToggle && IsObjMarked(pObj);
		MarkObj(pObj,pPV,bUnmark);
	}
	return bRet;
}

BOOL SdrMarkView::MarkNextObj(BOOL bPrev)
{
	SdrPageView* pPageView = GetSdrPageView();
	
	if(!pPageView)
	{
		return FALSE;
	}

	SortMarkedObjects();
	ULONG  nMarkAnz=GetMarkedObjectCount();
	ULONG  nChgMarkNum = ULONG_MAX; // Nummer des zu ersetzenden MarkEntries
	ULONG  nSearchObjNum = bPrev ? 0 : ULONG_MAX;
	if (nMarkAnz!=0) {
		nChgMarkNum=bPrev ? 0 : ULONG(nMarkAnz-1);
		SdrMark* pM=GetSdrMarkByIndex(nChgMarkNum);
        OSL_ASSERT(pM!=NULL);
        if (pM->GetMarkedSdrObj() != NULL)
            nSearchObjNum = pM->GetMarkedSdrObj()->GetNavigationPosition();
	}

	SdrObject* pMarkObj=NULL;
	SdrObjList* pSearchObjList=pPageView->GetObjList();
	ULONG nObjAnz=pSearchObjList->GetObjCount();
	if (nObjAnz!=0) {
		if (nSearchObjNum>nObjAnz) nSearchObjNum=nObjAnz;
		while (pMarkObj==NULL && ((!bPrev && nSearchObjNum>0) || (bPrev && nSearchObjNum<nObjAnz)))
        {
			if (!bPrev)
                nSearchObjNum--;
			SdrObject* pSearchObj = pSearchObjList->GetObjectForNavigationPosition(nSearchObjNum);
			if (IsObjMarkable(pSearchObj,pPageView))
            {
				if (TryToFindMarkedObject(pSearchObj)==CONTAINER_ENTRY_NOTFOUND)
                {
					pMarkObj=pSearchObj;
				}
			}
			if (bPrev) nSearchObjNum++;
		}
	}

	if(!pMarkObj) 
	{
		return FALSE;
	}

	if (nChgMarkNum!=ULONG_MAX) 
	{
		GetMarkedObjectListWriteAccess().DeleteMark(nChgMarkNum);
	}
	MarkObj(pMarkObj,pPageView); // ruft auch MarkListHasChanged(), AdjustMarkHdl()
	return TRUE;
}

BOOL SdrMarkView::MarkNextObj(const Point& rPnt, short nTol, BOOL bPrev)
{
	SortMarkedObjects();
	nTol=ImpGetHitTolLogic(nTol,NULL);
	Point aPt(rPnt);
	SdrMark* pTopMarkHit=NULL;
	SdrMark* pBtmMarkHit=NULL;
	ULONG nTopMarkHit=0;
	ULONG nBtmMarkHit=0;
	// oberstes der markierten Objekte suchen, das von rPnt getroffen wird
	ULONG nMarkAnz=GetMarkedObjectCount();
	ULONG nm=0;
	for (nm=nMarkAnz; nm>0 && pTopMarkHit==NULL;) {
		nm--;
		SdrMark* pM=GetSdrMarkByIndex(nm);
		if (ImpIsObjHit(aPt,USHORT(nTol),pM->GetMarkedSdrObj(),pM->GetPageView(),0)) {
			pTopMarkHit=pM;
			nTopMarkHit=nm;
		}
	}
	// Nichts gefunden, dann ganz normal ein Obj markieren.
	if (pTopMarkHit==NULL) return MarkObj(rPnt,USHORT(nTol),FALSE);

	SdrObject* pTopObjHit=pTopMarkHit->GetMarkedSdrObj();
	SdrObjList* pObjList=pTopObjHit->GetObjList();
	SdrPageView* pPV=pTopMarkHit->GetPageView();
	// unterstes der markierten Objekte suchen, das von rPnt getroffen wird
	// und auf der gleichen PageView liegt wie pTopMarkHit
	for (nm=0; nm<nMarkAnz && pBtmMarkHit==NULL; nm++) {
		SdrMark* pM=GetSdrMarkByIndex(nm);
		SdrPageView* pPV2=pM->GetPageView();
		if (pPV2==pPV && ImpIsObjHit(aPt,USHORT(nTol),pM->GetMarkedSdrObj(),pPV2,0)) {
			pBtmMarkHit=pM;
			nBtmMarkHit=nm;
		}
	}
	if (pBtmMarkHit==NULL) { pBtmMarkHit=pTopMarkHit; nBtmMarkHit=nTopMarkHit; }
	SdrObject* pBtmObjHit=pBtmMarkHit->GetMarkedSdrObj();
	ULONG nObjAnz=pObjList->GetObjCount();

	// #110988#
	//ULONG nSearchBeg=bPrev ? pBtmObjHit->GetOrdNum()+1 : pTopObjHit->GetOrdNum();
	sal_uInt32 nSearchBeg;
	E3dScene* pScene = NULL;
	SdrObject* pObjHit = (bPrev) ? pBtmObjHit : pTopObjHit;
	sal_Bool bRemap = pObjHit->ISA(E3dCompoundObject) 
		? ((E3dCompoundObject*)pObjHit)->IsAOrdNumRemapCandidate(pScene) 
		: sal_False;

	if(bPrev)
	{
		sal_uInt32 nOrdNumBtm(pBtmObjHit->GetOrdNum());

		if(bRemap)
		{
			nOrdNumBtm = pScene->RemapOrdNum(nOrdNumBtm);
		}

		nSearchBeg = nOrdNumBtm + 1;
	}
	else
	{
		sal_uInt32 nOrdNumTop(pTopObjHit->GetOrdNum());

		if(bRemap) 
		{
			nOrdNumTop = pScene->RemapOrdNum(nOrdNumTop);
		}

		nSearchBeg = nOrdNumTop;
	}

	ULONG no=nSearchBeg;
	SdrObject* pFndObj=NULL;
	//SdrObject* pAktObj=NULL;
	while (pFndObj==NULL && ((!bPrev && no>0) || (bPrev && no<nObjAnz))) {
		if (!bPrev) no--;
		SdrObject* pObj;

		if(bRemap)
		{
			pObj = pObjList->GetObj(pScene->RemapOrdNum(no));
		}
		else
		{
			pObj = pObjList->GetObj(no);
		}

		if (ImpIsObjHit(aPt,USHORT(nTol),pObj,pPV,SDRSEARCH_TESTMARKABLE)) {
			if (TryToFindMarkedObject(pObj)==CONTAINER_ENTRY_NOTFOUND) {
				pFndObj=pObj;
			} else {
				// hier wg. Performance ggf. noch no auf Top bzw. auf Btm stellen
			}
		}
		if (bPrev) no++;
	}
	if (pFndObj!=NULL) 
	{
		GetMarkedObjectListWriteAccess().DeleteMark(bPrev?nBtmMarkHit:nTopMarkHit);
		GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pFndObj,pPV));
		MarkListHasChanged();
		AdjustMarkHdl(); //HMHTRUE);
	}
	return pFndObj!=NULL;
}

BOOL SdrMarkView::MarkObj(const Rectangle& rRect, BOOL bUnmark)
{
	BOOL bFnd=FALSE;
	Rectangle aR(rRect);
	SdrObject* pObj;
	SdrObjList* pObjList;
	BrkAction();
	SdrPageView* pPV = GetSdrPageView();
	
	if(pPV)
	{
		pObjList=pPV->GetObjList();
		Rectangle aFrm1(aR);
		ULONG nObjAnz=pObjList->GetObjCount();
		for (ULONG nO=0; nO<nObjAnz; nO++) {
			pObj=pObjList->GetObj(nO);
			Rectangle aRect(pObj->GetCurrentBoundRect());
			if (aFrm1.IsInside(aRect)) {
				if (!bUnmark) {
					if (IsObjMarkable(pObj,pPV)) 
					{
						GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pObj,pPV));
						bFnd=TRUE;
					}
				} else {
					ULONG nPos=TryToFindMarkedObject(pObj);
					if (nPos!=CONTAINER_ENTRY_NOTFOUND) 
					{
						GetMarkedObjectListWriteAccess().DeleteMark(nPos);
						bFnd=TRUE;
					}
				}
			}
		}
	}
	if (bFnd) {
		SortMarkedObjects();
		MarkListHasChanged();
		AdjustMarkHdl(); //HMHTRUE);
		//HMHShowMarkHdl();
	}
	return bFnd;
}

void SdrMarkView::MarkObj(SdrObject* pObj, SdrPageView* pPV, BOOL bUnmark, BOOL bImpNoSetMarkHdl)
{
	if (pObj!=NULL && pPV!=NULL && IsObjMarkable(pObj, pPV)) {
		BrkAction();
		if (!bUnmark) 
		{
			GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pObj,pPV));
		} 
		else 
		{
			ULONG nPos=TryToFindMarkedObject(pObj);
			if (nPos!=CONTAINER_ENTRY_NOTFOUND) 
			{
				GetMarkedObjectListWriteAccess().DeleteMark(nPos);
			}
		}
		if (!bImpNoSetMarkHdl) {
			MarkListHasChanged();
			AdjustMarkHdl(); //HMHTRUE);
			//HMHif (!bSomeObjChgdFlag) {
				// ShowMarkHdl kommt sonst mit dem AfterPaintTimer
				//HMHShowMarkHdl();
			//HMH}
		}
	}
}

BOOL SdrMarkView::IsObjMarked(SdrObject* pObj) const
{
	// nicht so ganz die feine Art: Da FindObject() nicht const ist
	// muss ich mich hier auf non-const casten.
	ULONG nPos=((SdrMarkView*)this)->TryToFindMarkedObject(pObj);
	return nPos!=CONTAINER_ENTRY_NOTFOUND;
}

USHORT SdrMarkView::GetMarkHdlSizePixel() const
{
	return aHdl.GetHdlSize()*2+1;
}

void SdrMarkView::SetSolidMarkHdl(BOOL bOn)
{
	if (bOn!=aHdl.IsFineHdl()) {
		//HMHBOOL bMerk=IsMarkHdlShown();
		//HMHif (bMerk) HideMarkHdl();
		aHdl.SetFineHdl(bOn);
		//HMHif (bMerk) ShowMarkHdl();
	}
}

void SdrMarkView::SetMarkHdlSizePixel(USHORT nSiz)
{
	if (nSiz<3) nSiz=3;
	nSiz/=2;
	if (nSiz!=aHdl.GetHdlSize()) {
		//HMHBOOL bMerk=IsMarkHdlShown();
		//HMHif (bMerk) HideMarkHdl();
		aHdl.SetHdlSize(nSiz);
		//HMHif (bMerk) ShowMarkHdl();
	}
}

#define SDRSEARCH_IMPISMASTER 0x80000000 /* MasterPage wird gerade durchsucht */
SdrObject* SdrMarkView::ImpCheckObjHit(const Point& rPnt, USHORT nTol, SdrObject* pObj, SdrPageView* pPV, ULONG nOptions, const SetOfByte* pMVisLay) const
{
	if((nOptions & SDRSEARCH_IMPISMASTER) && pObj->IsNotVisibleAsMaster()) 
    {
		return NULL;
	}
	
    const bool bCheckIfMarkable(nOptions & SDRSEARCH_TESTMARKABLE);
	const bool bDeep(nOptions & SDRSEARCH_DEEP);
	const bool bOLE(pObj->ISA(SdrOle2Obj));
	const bool bTXT(pObj->ISA(SdrTextObj) && ((SdrTextObj*)pObj)->IsTextFrame());
	SdrObject* pRet=NULL;
	Rectangle aRect(pObj->GetCurrentBoundRect());
	USHORT nTol2(nTol);

    // double tolerance for OLE, text frames and objects in
    // active text edit
	if(bOLE || bTXT || pObj==((SdrObjEditView*)this)->GetTextEditObject()) 
    {
        nTol2*=2;
    }

    aRect.Left  ()-=nTol2; // Einmal Toleranz drauf fuer alle Objekte
	aRect.Top   ()-=nTol2;
	aRect.Right ()+=nTol2;
	aRect.Bottom()+=nTol2;

    if (aRect.IsInside(rPnt)) 
    {
		if ((!bCheckIfMarkable || IsObjMarkable(pObj,pPV))) 
        {
			SdrObjList* pOL=pObj->GetSubList();

            if (pOL!=NULL && pOL->GetObjCount()!=0) 
            {
				SdrObject* pTmpObj;
                // OD 30.06.2003 #108784# - adjustment hit point for virtual
                // objects.
                Point aPnt( rPnt );
                
                if ( pObj->ISA(SdrVirtObj) )
                {
                    Point aOffset = static_cast<SdrVirtObj*>(pObj)->GetOffset();
                    aPnt.Move( -aOffset.X(), -aOffset.Y() );
                }
            
                pRet=ImpCheckObjHit(aPnt,nTol,pOL,pPV,nOptions,pMVisLay,pTmpObj);
			} 
            else 
            {
				SdrLayerID nLay=pObj->GetLayer();
				
                if(pPV->GetVisibleLayers().IsSet(nLay) && (pMVisLay==NULL || pMVisLay->IsSet(nLay)))
				{
					pRet=pObj->CheckHit(rPnt,nTol2,&pPV->GetVisibleLayers());
				}
			}
		}
	}

    if (!bDeep && pRet!=NULL) 
    {
        pRet=pObj;
    }

	return pRet;
}

SdrObject* SdrMarkView::ImpCheckObjHit(const Point& rPnt, USHORT nTol, SdrObjList* pOL, SdrPageView* pPV, ULONG nOptions, const SetOfByte* pMVisLay, SdrObject*& rpRootObj) const
{
	BOOL bBack=(nOptions & SDRSEARCH_BACKWARD)!=0;
	SdrObject* pRet=NULL;
	rpRootObj=NULL;
	if (pOL!=NULL) 
	{
		// #110988#
		sal_Bool bRemap(pOL->GetOwnerObj() && pOL->GetOwnerObj()->ISA(E3dScene));
		E3dScene* pRemapScene = (bRemap ? (E3dScene*)pOL->GetOwnerObj() : 0L);

		ULONG nObjAnz=pOL->GetObjCount();
		ULONG nObjNum=bBack ? 0 : nObjAnz;
		while (pRet==NULL && (bBack ? nObjNum<nObjAnz : nObjNum>0)) {
			if (!bBack) nObjNum--;
			SdrObject* pObj;

			// #110988#
			if(bRemap)
			{
				pObj = pOL->GetObj(pRemapScene->RemapOrdNum(nObjNum));
			}
			else
			{
				pObj = pOL->GetObj(nObjNum);
			}

			pRet=ImpCheckObjHit(rPnt,nTol,pObj,pPV,nOptions,pMVisLay);
			if (pRet!=NULL) rpRootObj=pObj;
			if (bBack) nObjNum++;
		}
	}
	return pRet;
}

BOOL SdrMarkView::PickObj(const Point& rPnt, short nTol, SdrObject*& rpObj, SdrPageView*& rpPV, ULONG nOptions) const
{
	return PickObj(rPnt,nTol,rpObj,rpPV,nOptions,NULL,NULL,NULL);
}

BOOL SdrMarkView::PickObj(const Point& rPnt, short nTol, SdrObject*& rpObj, SdrPageView*& rpPV, ULONG nOptions, SdrObject** ppRootObj, ULONG* pnMarkNum, USHORT* pnPassNum) const
{ // Fehlt noch Pass2,Pass3
	SortMarkedObjects();
	if (ppRootObj!=NULL) *ppRootObj=NULL;
	if (pnMarkNum!=NULL) *pnMarkNum=CONTAINER_ENTRY_NOTFOUND;
	if (pnPassNum!=NULL) *pnPassNum=0;
	rpObj=NULL;
	rpPV=NULL;
	BOOL bWholePage=(nOptions & SDRSEARCH_WHOLEPAGE) !=0;
	BOOL bMarked=(nOptions & SDRSEARCH_MARKED) !=0;
	BOOL bMasters=!bMarked && (nOptions & SDRSEARCH_ALSOONMASTER) !=0;
	BOOL bBack=(nOptions & SDRSEARCH_BACKWARD) !=0;
#if OSL_DEBUG_LEVEL > 0
    BOOL bNext=(nOptions & SDRSEARCH_NEXT) !=0; (void)bNext; // n.i.
    BOOL bBoundCheckOn2ndPass=(nOptions & SDRSEARCH_PASS2BOUND) !=0; (void)bBoundCheckOn2ndPass;// n.i.
    BOOL bCheckNearestOn3rdPass=(nOptions & SDRSEARCH_PASS3NEAREST) !=0; (void)bCheckNearestOn3rdPass;// n.i.
#endif
	if (nTol<0) nTol=ImpGetHitTolLogic(nTol,NULL);
	Point aPt(rPnt);
	SdrObject* pObj=NULL;
	SdrObject* pHitObj=NULL;
	SdrPageView* pPV=NULL;
	if (!bBack && ((SdrObjEditView*)this)->IsTextEditFrameHit(rPnt)) {
		pObj=((SdrObjEditView*)this)->GetTextEditObject();
		pHitObj=pObj;
		pPV=((SdrObjEditView*)this)->GetTextEditPageView();
	}
	if (bMarked) {
		ULONG nMrkAnz=GetMarkedObjectCount();
		ULONG nMrkNum=bBack ? 0 : nMrkAnz;
		while (pHitObj==NULL && (bBack ? nMrkNum<nMrkAnz : nMrkNum>0)) {
			if (!bBack) nMrkNum--;
			SdrMark* pM=GetSdrMarkByIndex(nMrkNum);
			pObj=pM->GetMarkedSdrObj();
			pPV=pM->GetPageView();
			pHitObj=ImpCheckObjHit(aPt,nTol,pObj,pPV,nOptions,NULL);
			if (bBack) nMrkNum++;
		}
	} 
	else 
	{
		pPV = GetSdrPageView();

		if(pPV)
		{
			SdrPage* pPage=pPV->GetPage();
			USHORT nPgAnz=1; 
			
			if(bMasters && pPage->TRG_HasMasterPage()) 
			{
				nPgAnz++;
			}

			BOOL bExtraPassForWholePage=bWholePage && pPage!=pPV->GetObjList();
			if (bExtraPassForWholePage) nPgAnz++; // Suche erst in AktObjList, dann auf der gesamten Page
			USHORT nPgNum=bBack ? 0 : nPgAnz;
			while (pHitObj==NULL && (bBack ? nPgNum<nPgAnz : nPgNum>0)) {
				ULONG nTmpOptions=nOptions;
				if (!bBack) nPgNum--;
				const SetOfByte* pMVisLay=NULL;
				SdrObjList* pObjList=NULL;
				if (pnPassNum!=NULL) *pnPassNum&=~(SDRSEARCHPASS_MASTERPAGE|SDRSEARCHPASS_INACTIVELIST);
				if (nPgNum>=nPgAnz-1 || (bExtraPassForWholePage && nPgNum>=nPgAnz-2)) 
				{
					pObjList=pPV->GetObjList();
					if (bExtraPassForWholePage && nPgNum==nPgAnz-2) {
						pObjList=pPage;
						if (pnPassNum!=NULL) *pnPassNum|=SDRSEARCHPASS_INACTIVELIST;
					}
				} 
				else 
				{ 
					// sonst MasterPage
					SdrPage& rMasterPage = pPage->TRG_GetMasterPage();
					pMVisLay = &pPage->TRG_GetMasterPageVisibleLayers();
					pObjList = &rMasterPage;

					if (pnPassNum!=NULL) *pnPassNum|=SDRSEARCHPASS_MASTERPAGE;
					nTmpOptions=nTmpOptions | SDRSEARCH_IMPISMASTER;
				}
				pHitObj=ImpCheckObjHit(aPt,nTol,pObjList,pPV,nTmpOptions,pMVisLay,pObj);
				if (bBack) nPgNum++;
			}
		}
	}
	if (pHitObj!=NULL) {
		if (ppRootObj!=NULL) *ppRootObj=pObj;
		if ((nOptions & SDRSEARCH_DEEP) !=0) pObj=pHitObj;
		if ((nOptions & SDRSEARCH_TESTTEXTEDIT) !=0) {
			if (!pObj->HasTextEdit() || pPV->GetLockedLayers().IsSet(pObj->GetLayer())) {
				pObj=NULL;
			}
		}
		if (pObj!=NULL && (nOptions & SDRSEARCH_TESTMACRO) !=0) {
			SdrObjMacroHitRec aHitRec;
			aHitRec.aPos=aPt;
			aHitRec.aDownPos=aPt;
			aHitRec.nTol=nTol;
			aHitRec.pVisiLayer=&pPV->GetVisibleLayers();
			aHitRec.pPageView=pPV;
			if (!pObj->HasMacro() || !pObj->IsMacroHit(aHitRec)) pObj=NULL;
		}
		if (pObj!=NULL && (nOptions & SDRSEARCH_WITHTEXT) !=0 && pObj->GetOutlinerParaObject()==NULL) pObj=NULL;
		if (pObj!=NULL && (nOptions & SDRSEARCH_TESTTEXTAREA) !=0) {
			if (!pObj->IsTextEditHit(aPt,0/*nTol*/,NULL)) pObj=NULL;
		}
		if (pObj!=NULL) {
			rpObj=pObj;
			rpPV=pPV;
			if (pnPassNum!=NULL) *pnPassNum|=SDRSEARCHPASS_DIRECT;
		}
	}
	return rpObj!=NULL;
}

BOOL SdrMarkView::PickMarkedObj(const Point& rPnt, SdrObject*& rpObj, SdrPageView*& rpPV, ULONG* pnMarkNum, ULONG nOptions) const
{
	SortMarkedObjects();
	BOOL bBoundCheckOn2ndPass=(nOptions & SDRSEARCH_PASS2BOUND) !=0;
	BOOL bCheckNearestOn3rdPass=(nOptions & SDRSEARCH_PASS3NEAREST) !=0;
	rpObj=NULL;
	rpPV=NULL;
	if (pnMarkNum!=NULL) *pnMarkNum=CONTAINER_ENTRY_NOTFOUND;
	Point aPt(rPnt);
	USHORT nTol=(USHORT)nHitTolLog;
	BOOL bFnd=FALSE;
	ULONG nMarkAnz=GetMarkedObjectCount();
	ULONG nMarkNum;
	for (nMarkNum=nMarkAnz; nMarkNum>0 && !bFnd;) {
		nMarkNum--;
		SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
		SdrPageView* pPV=pM->GetPageView();
		SdrObject* pObj=pM->GetMarkedSdrObj();
		bFnd=ImpIsObjHit(aPt,nTol,pObj,pPV,SDRSEARCH_TESTMARKABLE);
		if (bFnd) {
			rpObj=pObj;
			rpPV=pPV;
			if (pnMarkNum!=NULL) *pnMarkNum=nMarkNum;
		}
	}
	if ((bBoundCheckOn2ndPass || bCheckNearestOn3rdPass) && !bFnd) {
		SdrObject* pBestObj=NULL;
		SdrPageView* pBestPV=NULL;
		ULONG nBestMarkNum=0;
		ULONG nBestDist=ULONG_MAX;
		for (nMarkNum=nMarkAnz; nMarkNum>0 && !bFnd;) {
			nMarkNum--;
			SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
			SdrPageView* pPV=pM->GetPageView();
			SdrObject* pObj=pM->GetMarkedSdrObj();
			Rectangle aRect(pObj->GetCurrentBoundRect());
			aRect.Left  ()-=nTol;
			aRect.Top   ()-=nTol;
			aRect.Right ()+=nTol;
			aRect.Bottom()+=nTol;
			if (aRect.IsInside(aPt)) {
				bFnd=TRUE;
				rpObj=pObj;
				rpPV=pPV;
				if (pnMarkNum!=NULL) *pnMarkNum=nMarkNum;
			} else if (bCheckNearestOn3rdPass) {
				ULONG nDist=0;
				if (aPt.X()<aRect.Left())   nDist+=aRect.Left()-aPt.X();
				if (aPt.X()>aRect.Right())  nDist+=aPt.X()-aRect.Right();
				if (aPt.Y()<aRect.Top())    nDist+=aRect.Top()-aPt.Y();
				if (aPt.Y()>aRect.Bottom()) nDist+=aPt.Y()-aRect.Bottom();
				if (nDist<nBestDist) {
					pBestObj=pObj;
					pBestPV=pPV;
					nBestMarkNum=nMarkNum;
				}
			}
		}
		if (bCheckNearestOn3rdPass && !bFnd) {
			rpObj=pBestObj;
			rpPV=pBestPV;
			if (pnMarkNum!=NULL) *pnMarkNum=nBestMarkNum;
			bFnd=pBestObj!=NULL;
		}
	}
	return bFnd;
}

SdrHitKind SdrMarkView::PickSomething(const Point& rPnt, short nTol) const
{
	nTol=ImpGetHitTolLogic(nTol,NULL);
	SdrHitKind eRet=SDRHIT_NONE;
	Point aPt(rPnt);
	SdrObject* pObj=NULL;
	SdrPageView* pPV=NULL;
	if (eRet==SDRHIT_NONE && PickObj(rPnt,USHORT(nTol),pObj,pPV,SDRSEARCH_PICKMARKABLE)) {
		Rectangle aRct1(aPt-Point(nTol,nTol),aPt+Point(nTol,nTol)); // HitRect fuer Toleranz
		Rectangle aBR(pObj->GetCurrentBoundRect());
		if      (aRct1.IsInside(aBR.TopLeft()))      eRet=SDRHIT_BOUNDTL;
		else if (aRct1.IsInside(aBR.TopCenter()))    eRet=SDRHIT_BOUNDTC;
		else if (aRct1.IsInside(aBR.TopRight()))     eRet=SDRHIT_BOUNDTR;
		else if (aRct1.IsInside(aBR.LeftCenter()))   eRet=SDRHIT_BOUNDCL;
		else if (aRct1.IsInside(aBR.RightCenter()))  eRet=SDRHIT_BOUNDCR;
		else if (aRct1.IsInside(aBR.BottomLeft()))   eRet=SDRHIT_BOUNDBL;
		else if (aRct1.IsInside(aBR.BottomCenter())) eRet=SDRHIT_BOUNDBC;
		else if (aRct1.IsInside(aBR.BottomRight()))  eRet=SDRHIT_BOUNDBR;
		else eRet=SDRHIT_OBJECT;
	}
	return eRet;
}

void SdrMarkView::UnmarkAllObj(SdrPageView* pPV)
{
	if (GetMarkedObjectCount()!=0) {
		BrkAction();
		//HMHBOOL bVis=bHdlShown;
		//HMHif (bVis) HideMarkHdl();
		if (pPV!=NULL) 
		{
			GetMarkedObjectListWriteAccess().DeletePageView(*pPV);
		} 
		else 
		{
			GetMarkedObjectListWriteAccess().Clear();
		}
		pMarkedObj=NULL;
		pMarkedPV=NULL;
		MarkListHasChanged();
		AdjustMarkHdl(); //HMHTRUE);
		//HMHif (bVis) ShowMarkHdl(); // ggf. fuer die RefPoints
	}
}

void SdrMarkView::MarkAllObj(SdrPageView* _pPV)
{
	BrkAction();
	//HMHHideMarkHdl();

	if(!_pPV) 
	{
		_pPV = GetSdrPageView();
	}

	// #i69171# _pPV may still be NULL if there is no SDrPageView (!), e.g. when inserting
	// other files
	if(_pPV)
	{
		const bool bMarkChg(GetMarkedObjectListWriteAccess().InsertPageView(*_pPV));

		if(bMarkChg) 
		{
			MarkListHasChanged();
		}
	}

	if(GetMarkedObjectCount()) 
	{
		AdjustMarkHdl(); //HMHTRUE);
		//HMHShowMarkHdl();
	}
}

void SdrMarkView::AdjustMarkHdl() //HMHBOOL bRestraintPaint)
{
	//HMHBOOL bVis=bHdlShown;
	//HMHif (bVis) HideMarkHdl();
	CheckMarked();
	SetMarkRects();
	SetMarkHandles();
	//HMHif(bRestraintPaint && bVis)
	//HMH{
	//HMH	ShowMarkHdl();
	//HMH}
}

Rectangle SdrMarkView::GetMarkedObjBoundRect() const
{
	Rectangle aRect;
	for (ULONG nm=0; nm<GetMarkedObjectCount(); nm++) {
		SdrMark* pM=GetSdrMarkByIndex(nm);
		SdrObject* pO=pM->GetMarkedSdrObj();
		Rectangle aR1(pO->GetCurrentBoundRect());
		if (aRect.IsEmpty()) aRect=aR1;
		else aRect.Union(aR1);
	}
	return aRect;
}

const Rectangle& SdrMarkView::GetMarkedObjRect() const
{
	if (bMarkedObjRectDirty) {
		((SdrMarkView*)this)->bMarkedObjRectDirty=FALSE;
		Rectangle aRect;
		for (ULONG nm=0; nm<GetMarkedObjectCount(); nm++) {
			SdrMark* pM=GetSdrMarkByIndex(nm);
			SdrObject* pO=pM->GetMarkedSdrObj();
			Rectangle aR1(pO->GetSnapRect());
			if (aRect.IsEmpty()) aRect=aR1;
			else aRect.Union(aR1);
		}
		((SdrMarkView*)this)->aMarkedObjRect=aRect;
	}
	return aMarkedObjRect;
}

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

void SdrMarkView::ImpTakeDescriptionStr(USHORT nStrCacheID, XubString& rStr, USHORT nVal, USHORT nOpt) const
{
	rStr = ImpGetResStr(nStrCacheID);
	xub_StrLen nPos = rStr.SearchAscii("%1");

	if(nPos != STRING_NOTFOUND)
	{
		rStr.Erase(nPos, 2);

		if(nOpt == IMPSDR_POINTSDESCRIPTION)
		{
			rStr.Insert(GetDescriptionOfMarkedPoints(), nPos);
		}
		else if(nOpt == IMPSDR_GLUEPOINTSDESCRIPTION)
		{
			rStr.Insert(GetDescriptionOfMarkedGluePoints(), nPos);
		}
		else
		{
			rStr.Insert(GetDescriptionOfMarkedObjects(), nPos);
		}
	}

	nPos = rStr.SearchAscii("%2");

	if(nPos != STRING_NOTFOUND)
	{
		rStr.Erase(nPos, 2);
		rStr.Insert(UniString::CreateFromInt32(nVal), nPos);
	}
}

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

BOOL SdrMarkView::EnterMarkedGroup()
{
	BOOL bRet=FALSE;
	// Es wird nur die erste gefundene Gruppe (also nur in einer PageView) geentert
	// Weil PageView::EnterGroup ein AdjustMarkHdl ruft.
	// Das muss ich per Flag mal unterbinden  vvvvvvvv
	SdrPageView* pPV = GetSdrPageView();

	if(pPV)
	{
		BOOL bEnter=FALSE;
		for (sal_uInt32 nm(GetMarkedObjectCount()); nm > 0 && !bEnter;) 
		{
			nm--;
			SdrMark* pM=GetSdrMarkByIndex(nm);
			if (pM->GetPageView()==pPV) {
				SdrObject* pObj=pM->GetMarkedSdrObj();
				if (pObj->IsGroupObject()) {
					if (pPV->EnterGroup(pObj)) {
						bRet=TRUE;
						bEnter=TRUE;
					}
				}
			}
		}
	}
	return bRet;
}

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

void SdrMarkView::MarkListHasChanged()
{
	GetMarkedObjectListWriteAccess().SetNameDirty();
	SetEdgesOfMarkedNodesDirty(); // bEdgesOfMarkedNodesDirty=TRUE;

	bMarkedObjRectDirty=TRUE;
	bMarkedPointsRectsDirty=TRUE;
#ifdef DBG_UTIL
	if (pItemBrowser!=NULL) pItemBrowser->SetDirty();
#endif
	BOOL bOneEdgeMarked=FALSE;
	if (GetMarkedObjectCount()==1) {
		const SdrObject* pObj=GetMarkedObjectByIndex(0);
		if (pObj->GetObjInventor()==SdrInventor) {
			UINT16 nIdent=pObj->GetObjIdentifier();
			bOneEdgeMarked=nIdent==OBJ_EDGE;
		}
	}
	ImpSetGlueVisible4(bOneEdgeMarked);
}

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

void SdrMarkView::SetMoveOutside(BOOL bOn)
{
	aHdl.SetMoveOutside(bOn);
}

BOOL SdrMarkView::IsMoveOutside() const                     
{ 
	return aHdl.IsMoveOutside(); 
}

void SdrMarkView::SetDesignMode( BOOL _bOn )
{
    if ( bDesignMode != _bOn )
	{
        bDesignMode = _bOn;
		SdrPageView* pPageView = GetSdrPageView();
        if ( pPageView )
            pPageView->SetDesignMode( _bOn );
	}
}

// MarkHandles Objektaenderung:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// - Bei Notify mit HINT_OBJCHG (oder so) werden die Handles erstmal versteckt
//   (wenn nicht schon wegen Dragging versteckt).
// - XorHdl: Bei ModelHasChanged() werden sie dann wieder angezeigt.
// - PaintEvents kommen nun durch.
//   - Die XorHandles werden z.T. wieder uebermalt.
//   - Xor:  Nach dem Painten werden die Handles im (vom PaintHandler gerufenen)
//           CompleteRedraw per ToggleShownXor bei gesetzter ClipRegion nochmal gemalt
//           und damit ist alles in Butter.
//   - ToggleShownXor macht bei SolidHdl nix weil bHdlShown=FALSE
//   - Der AfterPaintTimer wird gestartet.
// - SolidHdl: Im AfterPaintHandler wird ShowMarkHdl gerufen.
//   Da die Handles zu diesem Zeitpunkt nicht angezeigt sind wird:
//   - SaveBackground durchgefuehrt.
//   - DrawMarkHdl gerufen und bHdlShown gesetzt.
//
// MarkHandles bei sonstigem Invalidate:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// In diesem Fall bekomme ich kein Notify und beim Aufruf des
// PaintHandlers->CompleteRedraw() sind auch die SolidHandles sichtbar.

