/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



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

#include <svx/svddrgv.hxx>
#include "svx/xattr.hxx"
#include <svx/xpoly.hxx>
#include <svx/svdetc.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svdundo.hxx>
#include <svx/svdocapt.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdopath.hxx>
#include <svx/svdoedge.hxx>
#include "svx/svdstr.hrc"
#include "svx/svdglob.hxx"
#include "svddrgm1.hxx"
#include <svx/obj3d.hxx>
#include <svx/svdoashp.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <svx/polypolygoneditor.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>

using namespace sdr;

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

void SdrDragView::ImpClearVars()
{
	bFramDrag=sal_False;
	eDragMode=SDRDRAG_MOVE;
	bDragLimit=sal_False;
	bMarkedHitMovesAlways=sal_False;
	eDragHdl=HDL_MOVE;
	pDragHdl=NULL;
	bDragHdl=sal_False;
	bDragSpecial=sal_False;
	mpCurrentSdrDragMethod=NULL;
	bDragStripes=sal_False;
	bMirrRefDragObj=sal_True;
	bDragWithCopy=sal_False;
	pInsPointUndo=NULL;
	bInsGluePoint=sal_False;
	bInsObjPointMode=sal_False;
	bInsGluePointMode=sal_False;
	nDragXorPolyLimit=100;
	nDragXorPointLimit=500;
	bNoDragXorPolys=sal_False;
	bAutoVertexCon=sal_True;
	bAutoCornerCon=sal_False;
	bRubberEdgeDragging=sal_True;
	nRubberEdgeDraggingLimit=100;
	bDetailedEdgeDragging=sal_True;
	nDetailedEdgeDraggingLimit=10;
	bResizeAtCenter=sal_False;
	bCrookAtCenter=sal_False;
	bMouseHideWhileDraggingPoints=sal_False;

	// init using default
	mbSolidDragging = getOptionsDrawinglayer().IsSolidDragCreate();
}

void SdrDragView::ImpMakeDragAttr()
{
	ImpDelDragAttr();
}

SdrDragView::SdrDragView(SdrModel* pModel1, OutputDevice* pOut)
:	SdrExchangeView(pModel1,pOut)
{
	ImpClearVars();
	ImpMakeDragAttr();
}

SdrDragView::~SdrDragView()
{
	ImpDelDragAttr();
}

void SdrDragView::ImpDelDragAttr()
{
}

sal_Bool SdrDragView::IsAction() const
{
	return (mpCurrentSdrDragMethod || SdrExchangeView::IsAction());
}

void SdrDragView::MovAction(const Point& rPnt)
{
	SdrExchangeView::MovAction(rPnt);
	if (mpCurrentSdrDragMethod) 
	{
		MovDragObj(rPnt);
	}
}

void SdrDragView::EndAction()
{
	if (mpCurrentSdrDragMethod)
	{
		EndDragObj(sal_False);
	}
	SdrExchangeView::EndAction();
}

void SdrDragView::BckAction()
{
	SdrExchangeView::BckAction();
	BrkDragObj();
}

void SdrDragView::BrkAction()
{
	SdrExchangeView::BrkAction();
	BrkDragObj();
}

void SdrDragView::TakeActionRect(Rectangle& rRect) const
{
	if (mpCurrentSdrDragMethod) 
	{
		rRect=aDragStat.GetActionRect();
		if (rRect.IsEmpty()) 
		{
			SdrPageView* pPV = GetSdrPageView();

			if(pPV&& pPV->HasMarkedObjPageView()) 
			{
                // #i95646# is this used..?
                const basegfx::B2DRange aBoundRange(mpCurrentSdrDragMethod->getCurrentRange());
				rRect = Rectangle(
                    basegfx::fround(aBoundRange.getMinX()), basegfx::fround(aBoundRange.getMinY()), 
                    basegfx::fround(aBoundRange.getMaxX()), basegfx::fround(aBoundRange.getMaxY()));
			}
		}
		if (rRect.IsEmpty()) 
		{
			rRect=Rectangle(aDragStat.GetNow(),aDragStat.GetNow());
		}
	} 
	else 
	{
		SdrExchangeView::TakeActionRect(rRect);
	}
}

sal_Bool SdrDragView::TakeDragObjAnchorPos(Point& rPos, sal_Bool bTR ) const
{
	Rectangle aR;
	TakeActionRect(aR);
	rPos = bTR ? aR.TopRight() : aR.TopLeft();
	if (GetMarkedObjectCount()==1 && IsDragObj() && // nur bei Einzelselektion
		!IsDraggingPoints() && !IsDraggingGluePoints() && // nicht beim Punkteschieben
		!mpCurrentSdrDragMethod->ISA(SdrDragMovHdl)) // nicht beim Handlesschieben
	{
		SdrObject* pObj=GetMarkedObjectByIndex(0);
		if (pObj->ISA(SdrCaptionObj)) 
		{
			Point aPt(((SdrCaptionObj*)pObj)->GetTailPos());
			sal_Bool bTail=eDragHdl==HDL_POLY; // Schwanz wird gedraggt (nicht so ganz feine Abfrage hier)
			sal_Bool bOwn=mpCurrentSdrDragMethod->ISA(SdrDragObjOwn); // Objektspeziefisch
			if (!bTail) 
			{ // bei bTail liefert TakeActionRect schon das richtige
				if (bOwn) 
				{ // bOwn kann sein MoveTextFrame, ResizeTextFrame aber eben nicht mehr DragTail
					rPos=aPt;
				} 
				else 
				{
					// drag the whole Object (Move, Resize, ...)
					const basegfx::B2DPoint aTransformed(mpCurrentSdrDragMethod->getCurrentTransformation() * basegfx::B2DPoint(aPt.X(), aPt.Y()));
					rPos.X() = basegfx::fround(aTransformed.getX());
					rPos.Y() = basegfx::fround(aTransformed.getY());
				}
			}
		}
		return sal_True;
	}
	return sal_False;
}

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

sal_Bool SdrDragView::TakeDragLimit(SdrDragMode /*eMode*/, Rectangle& /*rRect*/) const
{
	return sal_False;
}

sal_Bool SdrDragView::BegDragObj(const Point& rPnt, OutputDevice* pOut, SdrHdl* pHdl, short nMinMov, SdrDragMethod* pForcedMeth)
{
	BrkAction();

	bool bRet=false;
	{
		SetDragWithCopy(sal_False);
		//ForceEdgesOfMarkedNodes();
		//TODO: aAni.Reset();
		mpCurrentSdrDragMethod=NULL;
		bDragSpecial=sal_False;
		bDragLimit=sal_False;
		SdrDragMode eTmpMode=eDragMode;
		if (eTmpMode==SDRDRAG_MOVE && pHdl!=NULL && pHdl->GetKind()!=HDL_MOVE) {
			eTmpMode=SDRDRAG_RESIZE;
		}
		bDragLimit=TakeDragLimit(eTmpMode,aDragLimit);
		bFramDrag=ImpIsFrameHandles();
		if (!bFramDrag &&
			(pMarkedObj==NULL || !pMarkedObj->hasSpecialDrag()) &&
			(pHdl==NULL || pHdl->GetObj()==NULL)) {
			bFramDrag=sal_True;
		}
		
		Point aPnt(rPnt);
		if(pHdl == NULL 
			|| pHdl->GetKind() == HDL_MOVE
			|| pHdl->GetKind() == HDL_MIRX
			|| pHdl->GetKind() == HDL_TRNS
			|| pHdl->GetKind() == HDL_GRAD) 
		{
			aDragStat.Reset(aPnt);
		}
		else 
		{
			aDragStat.Reset(pHdl->GetPos());
		}

		aDragStat.SetView((SdrView*)this);
		aDragStat.SetPageView(pMarkedPV);  // <<-- hier muss die DragPV rein!!!
		aDragStat.SetMinMove(ImpGetMinMovLogic(nMinMov,pOut));
		aDragStat.SetHdl(pHdl);
		aDragStat.NextPoint();
		pDragWin=pOut;
		pDragHdl=pHdl;
		eDragHdl= pHdl==NULL ? HDL_MOVE : pHdl->GetKind();
		bDragHdl=eDragHdl==HDL_REF1 || eDragHdl==HDL_REF2 || eDragHdl==HDL_MIRX;

		// #103894# Expand test for HDL_ANCHOR_TR
		sal_Bool bNotDraggable = (HDL_ANCHOR == eDragHdl || HDL_ANCHOR_TR == eDragHdl);
		
		if(pHdl && (pHdl->GetKind() == HDL_SMARTTAG) && pForcedMeth )
		{
			// just use the forced method for smart tags
		}
		else if(bDragHdl) 
		{
			mpCurrentSdrDragMethod = new SdrDragMovHdl(*this);
		} 
		else if(!bNotDraggable) 
		{
			switch (eDragMode) 
			{
				case SDRDRAG_ROTATE: case SDRDRAG_SHEAR: case SDRDRAG_DISTORT: 
				{
					switch (eDragHdl) 
					{
						case HDL_LEFT:  case HDL_RIGHT:
						case HDL_UPPER: case HDL_LOWER: 
						{
							// Sind 3D-Objekte selektiert?
							sal_Bool b3DObjSelected = sal_False;
							for(sal_uInt32 a=0;!b3DObjSelected && a<GetMarkedObjectCount();a++)
							{
								SdrObject* pObj = GetMarkedObjectByIndex(a);
								if(pObj && pObj->ISA(E3dObject))
									b3DObjSelected = sal_True;
							}
							// Falls ja, Shear auch bei !IsShearAllowed zulassen,
							// da es sich bei 3D-Objekten um eingeschraenkte
							// Rotationen handelt
							if (!b3DObjSelected && !IsShearAllowed())
								return sal_False;
							mpCurrentSdrDragMethod = new SdrDragShear(*this,eDragMode==SDRDRAG_ROTATE);
						} break;
						case HDL_UPLFT: case HDL_UPRGT:
						case HDL_LWLFT: case HDL_LWRGT: 
						{
							if (eDragMode==SDRDRAG_SHEAR || eDragMode==SDRDRAG_DISTORT) 
							{
								if (!IsDistortAllowed(sal_True) && !IsDistortAllowed(sal_False)) return sal_False;
								mpCurrentSdrDragMethod = new SdrDragDistort(*this);
							} 
							else 
							{
								if (!IsRotateAllowed(sal_True)) return sal_False;
								mpCurrentSdrDragMethod = new SdrDragRotate(*this);
							}
						} break;
						default: 
						{
							if (IsMarkedHitMovesAlways() && eDragHdl==HDL_MOVE) 
							{ // HDL_MOVE ist auch wenn Obj direkt getroffen
								if (!IsMoveAllowed()) return sal_False;
								mpCurrentSdrDragMethod = new SdrDragMove(*this);
							} 
							else 
							{
								if (!IsRotateAllowed(sal_True)) return sal_False;
								mpCurrentSdrDragMethod = new SdrDragRotate(*this);
							}
						}
					}
				} break;
				case SDRDRAG_MIRROR: 
				{
					if (eDragHdl==HDL_MOVE && IsMarkedHitMovesAlways()) 
					{
						if (!IsMoveAllowed()) return sal_False;
						mpCurrentSdrDragMethod = new SdrDragMove(*this);
					} 
					else 
					{
						if (!IsMirrorAllowed(sal_True,sal_True)) return sal_False;
						mpCurrentSdrDragMethod = new SdrDragMirror(*this);
					}
				} break;

				case SDRDRAG_CROP:
				{
					if (eDragHdl==HDL_MOVE && IsMarkedHitMovesAlways())
					{
						if (!IsMoveAllowed())
							return sal_False;
						mpCurrentSdrDragMethod = new SdrDragMove(*this);
					}
					else
					{
						if (!IsCrookAllowed(sal_True) && !IsCrookAllowed(sal_False))
							return sal_False;
						mpCurrentSdrDragMethod = new SdrDragCrop(*this);
					}
				}
				break;

				case SDRDRAG_TRANSPARENCE: 
				{
					if(eDragHdl == HDL_MOVE && IsMarkedHitMovesAlways()) 
					{
						if(!IsMoveAllowed()) 
							return sal_False;
						mpCurrentSdrDragMethod = new SdrDragMove(*this);
					} 
					else 
					{
						if(!IsTransparenceAllowed()) 
							return sal_False;

						mpCurrentSdrDragMethod = new SdrDragGradient(*this, sal_False);
					}
					break;
				} 
				case SDRDRAG_GRADIENT: 
				{
					if(eDragHdl == HDL_MOVE && IsMarkedHitMovesAlways()) 
					{
						if(!IsMoveAllowed()) 
							return sal_False;
						mpCurrentSdrDragMethod = new SdrDragMove(*this);
					} 
					else 
					{
						if(!IsGradientAllowed()) 
							return sal_False;

						mpCurrentSdrDragMethod = new SdrDragGradient(*this);
					}
					break;
				} 
				
				case SDRDRAG_CROOK : 
				{
					if (eDragHdl==HDL_MOVE && IsMarkedHitMovesAlways()) 
					{
						if (!IsMoveAllowed()) return sal_False;
						mpCurrentSdrDragMethod = new SdrDragMove(*this);
					} 
					else 
					{
						if (!IsCrookAllowed(sal_True) && !IsCrookAllowed(sal_False)) return sal_False;
						mpCurrentSdrDragMethod = new SdrDragCrook(*this);
					}
				} break;

				default:
				{	
					// SDRDRAG_MOVE
					if((eDragHdl == HDL_MOVE) && !IsMoveAllowed())
					{
						return sal_False;
					}
					else if(eDragHdl == HDL_GLUE)
					{
						mpCurrentSdrDragMethod = new SdrDragMove(*this);
					}
					else
					{
						if(bFramDrag)
						{
							if(eDragHdl == HDL_MOVE)
							{
								mpCurrentSdrDragMethod = new SdrDragMove(*this);
							}
							else
							{
								if(!IsResizeAllowed(sal_True)) 
								{
									return sal_False;
								}

								sal_Bool bSingleTextObjMark = sal_False;	// SJ: #i100490#
								if ( GetMarkedObjectCount() == 1 ) 
								{
									pMarkedObj=GetMarkedObjectByIndex(0);
									if ( pMarkedObj && 
										pMarkedObj->ISA( SdrTextObj ) &&
										static_cast<SdrTextObj*>(pMarkedObj)->IsTextFrame() )
										bSingleTextObjMark = sal_True;
								}
								if ( bSingleTextObjMark )
									mpCurrentSdrDragMethod = new SdrDragObjOwn(*this);
								else
									mpCurrentSdrDragMethod = new SdrDragResize(*this);
							}
						}
						else
						{
							if(HDL_MOVE == eDragHdl)
							{
                                const bool bCustomShapeSelected(1 == GetMarkedObjectCount() && GetMarkedObjectByIndex(0)->ISA(SdrObjCustomShape));

                                if(bCustomShapeSelected)
                                {
    								mpCurrentSdrDragMethod = new SdrDragMove( *this );
                                }
							}
							else if(HDL_POLY == eDragHdl)
                            {
                                const bool bConnectorSelected(1 == GetMarkedObjectCount() && GetMarkedObjectByIndex(0)->ISA(SdrEdgeObj));
                                
                                if(bConnectorSelected)
                                {
                                    // #i97784#
                                    // fallback to old behaviour for connectors (see
                                    // text in task description for more details)
                                }
                                else if(!IsMoveAllowed() || !IsResizeAllowed())
    							{
	    							// #i77187# 
                                    // do not allow move of polygon points if object is move or size protected
		    						return sal_False;
                                }
                            }

                            if(!mpCurrentSdrDragMethod)
                            {
                                // fallback to DragSpecial if no interaction defined
                                bDragSpecial = sal_True;
								mpCurrentSdrDragMethod = new SdrDragObjOwn(*this);
							}
						}
					}
				}
			}
		}
		if (pForcedMeth!=NULL) 
		{
            delete mpCurrentSdrDragMethod;
			mpCurrentSdrDragMethod = pForcedMeth;
		}
		aDragStat.SetDragMethod(mpCurrentSdrDragMethod);
		if (mpCurrentSdrDragMethod) 
		{
			bRet = mpCurrentSdrDragMethod->BeginSdrDrag();
			if (!bRet) 
			{
				if (pHdl==NULL && IS_TYPE(SdrDragObjOwn,mpCurrentSdrDragMethod)) 
				{
					// Aha, Obj kann nicht Move SpecialDrag, also MoveFrameDrag versuchen
                    delete mpCurrentSdrDragMethod;
                    mpCurrentSdrDragMethod = 0;
					bDragSpecial=sal_False;

                    if (!IsMoveAllowed()) 
                        return sal_False;
					
                    bFramDrag=sal_True;
					mpCurrentSdrDragMethod = new SdrDragMove(*this);
					aDragStat.SetDragMethod(mpCurrentSdrDragMethod);
					bRet = mpCurrentSdrDragMethod->BeginSdrDrag();
				}
			}
			if (!bRet) 
			{
                delete mpCurrentSdrDragMethod;
                mpCurrentSdrDragMethod = 0;
				aDragStat.SetDragMethod(mpCurrentSdrDragMethod);
			}
		}
	}

	return bRet;
}

void SdrDragView::MovDragObj(const Point& rPnt)
{
	if (mpCurrentSdrDragMethod) 
	{
		Point aPnt(rPnt);
		ImpLimitToWorkArea(aPnt);
		mpCurrentSdrDragMethod->MoveSdrDrag(aPnt); // this call already makes a Hide()/Show combination
	}
}

sal_Bool SdrDragView::EndDragObj(sal_Bool bCopy)
{
	bool bRet(false);
	
	// #i73341# If insert GluePoint, do not insist on last points being different
	if(mpCurrentSdrDragMethod && aDragStat.IsMinMoved() && (IsInsertGluePoint() || aDragStat.GetNow() != aDragStat.GetPrev())) 
	{
		sal_uIntPtr nHdlAnzMerk=0;

		if (bEliminatePolyPoints) 
		{ // IBM Special
			nHdlAnzMerk=GetMarkablePointCount();
		}
		
		const bool bUndo = IsUndoEnabled();
        if (IsInsertGluePoint() && bUndo) 
		{
			BegUndo(aInsPointUndoStr);
			AddUndo(pInsPointUndo);
		}
		
        bRet = mpCurrentSdrDragMethod->EndSdrDrag(bCopy);

        if( IsInsertGluePoint() && bUndo) 
            EndUndo();
		
        delete mpCurrentSdrDragMethod;
        mpCurrentSdrDragMethod = 0;
		
        if (bEliminatePolyPoints) 
		{ // IBM Special
			if (nHdlAnzMerk!=GetMarkablePointCount()) 
			{
				UnmarkAllPoints();
			}
		}
		
        if (bInsPolyPoint) 
		{
			SetMarkHandles();
			bInsPolyPoint=sal_False;
			if( bUndo )
			{
				BegUndo(aInsPointUndoStr);
				AddUndo(pInsPointUndo);
				EndUndo();
			}
		}

		eDragHdl=HDL_MOVE;
		pDragHdl=NULL;

		if (!bSomeObjChgdFlag)
		{
			// Aha, Obj hat nicht gebroadcastet (z.B. Writer FlyFrames)
			if(!bDragHdl)
			{
				AdjustMarkHdl();
			}
		}
	} 
	else 
	{
		BrkDragObj();
	}

    bInsPolyPoint=sal_False;
	SetInsertGluePoint(sal_False);

	return bRet;
}

void SdrDragView::BrkDragObj()
{
	if (mpCurrentSdrDragMethod) 
	{
		mpCurrentSdrDragMethod->CancelSdrDrag();

        delete mpCurrentSdrDragMethod;
        mpCurrentSdrDragMethod = 0;

        if (bInsPolyPoint) 
		{
			pInsPointUndo->Undo(); // Den eingefuegten Punkt wieder raus
			delete pInsPointUndo;
			pInsPointUndo=NULL;
			SetMarkHandles();
			bInsPolyPoint=sal_False;
		}

        if (IsInsertGluePoint()) 
		{
			pInsPointUndo->Undo(); // Den eingefuegten Klebepunkt wieder raus
			delete pInsPointUndo;
			pInsPointUndo=NULL;
			SetInsertGluePoint(sal_False);
		}

        eDragHdl=HDL_MOVE;
		pDragHdl=NULL;
	}
}

sal_Bool SdrDragView::IsInsObjPointPossible() const
{
	return pMarkedObj!=NULL && pMarkedObj->IsPolyObj();
}

sal_Bool SdrDragView::ImpBegInsObjPoint(sal_Bool bIdxZwang, sal_uInt32 nIdx, const Point& rPnt, sal_Bool bNewObj, OutputDevice* pOut)
{
	sal_Bool bRet(sal_False);

	if(pMarkedObj && pMarkedObj->ISA(SdrPathObj)) 
	{
		SdrPathObj* pMarkedPath = (SdrPathObj*)pMarkedObj;
		BrkAction();
		pInsPointUndo = dynamic_cast< SdrUndoGeoObj* >( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pMarkedObj) );
		DBG_ASSERT( pInsPointUndo, "svx::SdrDragView::BegInsObjPoint(), could not create correct undo object!" );

		XubString aStr(ImpGetResStr(STR_DragInsertPoint));
		XubString aName; 
        pMarkedObj->TakeObjNameSingul(aName);
		xub_StrLen nPos(aStr.SearchAscii("%1"));
		
		if(STRING_NOTFOUND != nPos) 
		{
			aStr.Erase(nPos, 2);
			aStr.Insert(aName, nPos);
		}
		
		aInsPointUndoStr = aStr;
		Point aPt(rPnt);

		if(bNewObj) 
			aPt = GetSnapPos(aPt,pMarkedPV);

		sal_Bool bClosed0(pMarkedPath->IsClosedObj());

		if(bIdxZwang) 
		{
			mnInsPointNum = pMarkedPath->NbcInsPoint(nIdx, aPt, bNewObj, sal_True);
		} 
		else 
		{
			mnInsPointNum = pMarkedPath->NbcInsPointOld(aPt, bNewObj, sal_True);
		}

		if(bClosed0 != pMarkedPath->IsClosedObj())
		{ 
			// Obj was closed implicit
			// object changed
			pMarkedPath->SetChanged();
			pMarkedPath->BroadcastObjectChange();
		}

		if(0xffffffff != mnInsPointNum) 
		{
			bInsPolyPoint = sal_True;
			UnmarkAllPoints();
			AdjustMarkHdl();

			bRet = BegDragObj(rPnt, pOut, aHdl.GetHdl(mnInsPointNum), 0);

			if (bRet) 
			{
				aDragStat.SetMinMoved();
				MovDragObj(rPnt);
			}
		} 
		else 
		{
			delete pInsPointUndo;
			pInsPointUndo = NULL;
		}
	}

	return bRet;
}

sal_Bool SdrDragView::EndInsObjPoint(SdrCreateCmd eCmd)
{
	if(IsInsObjPoint()) 
	{
		sal_uInt32 nNextPnt(mnInsPointNum);
		Point aPnt(aDragStat.GetNow());
		sal_Bool bOk=EndDragObj(sal_False);
		if (bOk==sal_True && eCmd!=SDRCREATE_FORCEEND) 
		{
			// Ret=True bedeutet: Action ist vorbei.
			bOk=!(ImpBegInsObjPoint(sal_True, nNextPnt, aPnt, eCmd == SDRCREATE_NEXTOBJECT, pDragWin));
		}

		return bOk;
	} else return sal_False;
}

sal_Bool SdrDragView::IsInsGluePointPossible() const
{
	sal_Bool bRet=sal_False;
	if (IsInsGluePointMode() && AreObjectsMarked()) 
	{
		if (GetMarkedObjectCount()==1) 
		{
			// sal_False liefern, wenn 1 Objekt und dieses ein Verbinder ist.
			const SdrObject* pObj=GetMarkedObjectByIndex(0);
			if (!HAS_BASE(SdrEdgeObj,pObj)) 
			{
			   bRet=sal_True;
			}
		} 
		else 
		{
			bRet=sal_True;
		}
	}
	return bRet;
}

sal_Bool SdrDragView::BegInsGluePoint(const Point& rPnt)
{
	sal_Bool bRet=sal_False;
	SdrObject* pObj;
	SdrPageView* pPV;
	sal_uIntPtr nMarkNum;
	if (PickMarkedObj(rPnt,pObj,pPV,&nMarkNum,SDRSEARCH_PASS2BOUND)) 
	{
		BrkAction();
		UnmarkAllGluePoints();
		pInsPointUndo= dynamic_cast< SdrUndoGeoObj* >( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj) );
		DBG_ASSERT( pInsPointUndo, "svx::SdrDragView::BegInsObjPoint(), could not create correct undo object!" );
		XubString aStr(ImpGetResStr(STR_DragInsertGluePoint));
		XubString aName; pObj->TakeObjNameSingul(aName);

		aStr.SearchAndReplaceAscii("%1", aName);
		
		aInsPointUndoStr=aStr;
		SdrGluePointList* pGPL=pObj->ForceGluePointList();
		if (pGPL!=NULL) 
		{
			sal_uInt16 nGlueIdx=pGPL->Insert(SdrGluePoint());
			SdrGluePoint& rGP=(*pGPL)[nGlueIdx];
			sal_uInt16 nGlueId=rGP.GetId();
			rGP.SetAbsolutePos(rPnt,*pObj);

			SdrHdl* pHdl=NULL;
			if (MarkGluePoint(pObj,nGlueId,pPV)) 
			{
				pHdl=GetGluePointHdl(pObj,nGlueId);
			}
			if (pHdl!=NULL && pHdl->GetKind()==HDL_GLUE && pHdl->GetObj()==pObj && pHdl->GetObjHdlNum()==nGlueId) 
			{
				SetInsertGluePoint(sal_True);
				bRet=BegDragObj(rPnt,NULL,pHdl,0);
				if (bRet) 
				{
					aDragStat.SetMinMoved();
					MovDragObj(rPnt);
				} 
				else 
				{
					SetInsertGluePoint(sal_False);
					delete pInsPointUndo;
					pInsPointUndo=NULL;
				}
			} 
			else 
			{
				DBG_ERROR("BegInsGluePoint(): GluePoint-Handle nicht gefunden");
			}
		} 
		else 
		{
			// Keine Klebepunkte moeglich bei diesem Objekt (z.B. Edge)
			SetInsertGluePoint(sal_False);
			delete pInsPointUndo;
			pInsPointUndo=NULL;
		}
	}

	return bRet;
}

void SdrDragView::ShowDragObj()
{
	if(mpCurrentSdrDragMethod && !aDragStat.IsShown())
	{
        for(sal_uInt32 a(0); a < PaintWindowCount(); a++)
        {
	        SdrPaintWindow* pCandidate = GetPaintWindow(a);
	        sdr::overlay::OverlayManager* pOverlayManager = pCandidate->GetOverlayManager();

	        if(pOverlayManager)
	        {
		        mpCurrentSdrDragMethod->CreateOverlayGeometry(*pOverlayManager);

				// #i101679# Force changed overlay to be shown
				pOverlayManager->flush();
	        }
        }

		aDragStat.SetShown(sal_True);
	}
}

void SdrDragView::HideDragObj()
{
	if(mpCurrentSdrDragMethod && aDragStat.IsShown())
	{
        mpCurrentSdrDragMethod->destroyOverlayGeometry();
		aDragStat.SetShown(sal_False);
	}
}

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

void SdrDragView::SetNoDragXorPolys(sal_Bool bOn)
{
	if (IsNoDragXorPolys()!=bOn) 
	{
		const bool bDragging(mpCurrentSdrDragMethod);
		const bool bShown(bDragging && aDragStat.IsShown());
		
        if(bShown) 
        {
            HideDragObj();
        }

		bNoDragXorPolys = bOn;

		if(bDragging) 
		{
            // force recreation of drag content
            mpCurrentSdrDragMethod->resetSdrDragEntries();
		}

		if(bShown) 
        {
			ShowDragObj();
        }
	}
}

void SdrDragView::SetDragStripes(sal_Bool bOn)
{
	if (mpCurrentSdrDragMethod && aDragStat.IsShown()) 
	{
		HideDragObj();
		bDragStripes=bOn;
		ShowDragObj();
	} 
	else 
	{
		bDragStripes=bOn;
	}
}

sal_Bool SdrDragView::IsOrthoDesired() const
{
	if(mpCurrentSdrDragMethod && (IS_TYPE(SdrDragObjOwn, mpCurrentSdrDragMethod) || IS_TYPE(SdrDragResize, mpCurrentSdrDragMethod)))
	{
		return bOrthoDesiredOnMarked;
	}

    return sal_False;
}

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

void SdrDragView::SetRubberEdgeDragging(sal_Bool bOn)
{
	if (bOn!=IsRubberEdgeDragging()) 
	{
		sal_uIntPtr nAnz = GetEdgesOfMarkedNodes().GetMarkCount();
		sal_Bool bShowHide=nAnz!=0 && IsDragObj() &&
				 (nRubberEdgeDraggingLimit>=nAnz);
		if (bShowHide) 
			HideDragObj();
		bRubberEdgeDragging=bOn;
		if (bShowHide) 
			ShowDragObj();
	}
}

void SdrDragView::SetRubberEdgeDraggingLimit(sal_uInt16 nEdgeObjAnz)
{
	if (nEdgeObjAnz!=nRubberEdgeDraggingLimit) 
	{
		sal_uIntPtr nAnz = GetEdgesOfMarkedNodes().GetMarkCount();
		sal_Bool bShowHide=IsRubberEdgeDragging() && nAnz!=0 && IsDragObj() &&
				 (nEdgeObjAnz>=nAnz)!=(nRubberEdgeDraggingLimit>=nAnz);
		if (bShowHide) 
			HideDragObj();
		nRubberEdgeDraggingLimit=nEdgeObjAnz;
		if (bShowHide) 
			ShowDragObj();
	}
}

void SdrDragView::SetDetailedEdgeDragging(sal_Bool bOn)
{
	if (bOn!=IsDetailedEdgeDragging()) 
	{
		sal_uIntPtr nAnz = GetEdgesOfMarkedNodes().GetMarkCount();
		sal_Bool bShowHide=nAnz!=0 && IsDragObj() &&
				 (nDetailedEdgeDraggingLimit>=nAnz);
		if (bShowHide) 
			HideDragObj();
		bDetailedEdgeDragging=bOn;
		if (bShowHide) 
			ShowDragObj();
	}
}

void SdrDragView::SetDetailedEdgeDraggingLimit(sal_uInt16 nEdgeObjAnz)
{
	if (nEdgeObjAnz!=nDetailedEdgeDraggingLimit) 
	{
		sal_uIntPtr nAnz = GetEdgesOfMarkedNodes().GetMarkCount();
		sal_Bool bShowHide=IsDetailedEdgeDragging() && nAnz!=0 && IsDragObj() &&
				 (nEdgeObjAnz>=nAnz)!=(nDetailedEdgeDraggingLimit>=nAnz);
		if (bShowHide) 
			HideDragObj();
		nDetailedEdgeDraggingLimit=nEdgeObjAnz;
		if (bShowHide) 
			ShowDragObj();
	}
}

void SdrDragView::SetMarkHandles()
{
	if( pDragHdl )
		pDragHdl = 0;

	SdrExchangeView::SetMarkHandles();
}

void SdrDragView::SetSolidDragging(bool bOn) 
{ 
	if((bool)mbSolidDragging != bOn)
	{
		mbSolidDragging = bOn; 
	}
}

bool SdrDragView::IsSolidDragging() const 
{ 
	// allow each user to disable by having a local setting, but using AND for
	// checking allowance
	return mbSolidDragging && getOptionsDrawinglayer().IsSolidDragCreate(); 
}

// eof
