/**************************************************************
 * 
 * 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 "svddrgm1.hxx"
#include <math.h>

#ifndef _MATH_H
#define _MATH_H
#endif
#include <tools/bigint.hxx>
#include <vcl/svapp.hxx>
#include "svx/xattr.hxx"
#include <svx/xpoly.hxx>
#include <svx/svdetc.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svdundo.hxx>
#include <svx/svdmark.hxx>
#include <svx/svdocapt.hxx>
#include <svx/svdpagv.hxx>
#include "svx/svdstr.hrc"   // Namen aus der Resource
#include "svx/svdglob.hxx"  // StringCache
#include <svx/svddrgv.hxx>
#include <svx/svdundo.hxx>
#include <svx/svdograf.hxx>
#include <svx/dialogs.hrc>
#include <svx/dialmgr.hxx>
#include <svx/sdgcpitm.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <svx/sdr/overlay/overlaypolypolygon.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
#include <svx/sdr/overlay/overlayrollingrectangle.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
#include <svx/sdr/contact/objectcontact.hxx>
#include "svx/svditer.hxx"
#include <svx/svdopath.hxx>
#include <svx/polypolygoneditor.hxx>
#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
#include <svx/sdr/primitive2d/sdrattributecreator.hxx>
#include <svx/sdr/primitive2d/sdrdecompositiontools.hxx>
#include <svx/svdoole2.hxx>
#include <svx/svdovirt.hxx>
#include <svx/svdouno.hxx>
#include <svx/sdr/primitive2d/sdrprimitivetools.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <drawinglayer/attribute/sdrlineattribute.hxx>
#include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
#include <map>
#include <vector>

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

SdrDragEntry::SdrDragEntry()
:	mbAddToTransparent(false)
{
}

SdrDragEntry::~SdrDragEntry()
{
}

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

SdrDragEntryPolyPolygon::SdrDragEntryPolyPolygon(const basegfx::B2DPolyPolygon& rOriginalPolyPolygon)
:   SdrDragEntry(),
    maOriginalPolyPolygon(rOriginalPolyPolygon)
{
}

SdrDragEntryPolyPolygon::~SdrDragEntryPolyPolygon()
{
}

drawinglayer::primitive2d::Primitive2DSequence SdrDragEntryPolyPolygon::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
{
	drawinglayer::primitive2d::Primitive2DSequence aRetval;

	if(maOriginalPolyPolygon.count())
	{
	    basegfx::B2DPolyPolygon aCopy(maOriginalPolyPolygon);
		const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;

		rDragMethod.applyCurrentTransformationToPolyPolygon(aCopy);
		basegfx::BColor aColA(aSvtOptionsDrawinglayer.GetStripeColorA().getBColor());
		basegfx::BColor aColB(aSvtOptionsDrawinglayer.GetStripeColorB().getBColor());
		const double fStripeLength(aSvtOptionsDrawinglayer.GetStripeLength());

		if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
		{
			aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
			aColB.invert();
		}

        aRetval.realloc(2);
        aRetval[0] = new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D(
            aCopy, 
            aColA, 
            aColB, 
            fStripeLength);

        const basegfx::BColor aHilightColor(aSvtOptionsDrawinglayer.getHilightColor().getBColor());
        const double fTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01);

        aRetval[1] = new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D(
            aCopy,
            aHilightColor,
            fTransparence,
            3.0,
            false);
	}

	return aRetval;
}

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

SdrDragEntrySdrObject::SdrDragEntrySdrObject(const SdrObject& rOriginal, sdr::contact::ObjectContact& rObjectContact, bool bModify)
:   SdrDragEntry(),
    maOriginal(rOriginal),
    mpClone(0),
    mrObjectContact(rObjectContact),
	mbModify(bModify)
{
	// add SdrObject parts to transparent overlay stuff
	setAddToTransparent(true);
}

SdrDragEntrySdrObject::~SdrDragEntrySdrObject()
{
    if(mpClone)
    {
        SdrObject::Free(mpClone);
    }
}

void SdrDragEntrySdrObject::prepareCurrentState(SdrDragMethod& rDragMethod)
{
	// for the moment, i need to re-create the clone in all cases. I need to figure
	// out when clone and original have the same class, so that i can use operator=
	// in those cases

    //        // copy all other needed stuff
    //        basegfx::B2DHomMatrix aMatrix;
    //        basegfx::B2DPolyPolygon aPolyPolygon;
    //	    pOleObject->TRGetBaseGeometry(aMatrix, aPolyPolygon);
    //        pClone->TRSetBaseGeometry(aMatrix, aPolyPolygon);

	if(mpClone)
    {
        SdrObject::Free(mpClone);
		mpClone = 0;
    }

	if(mbModify)
	{
		if(!mpClone)
		{
			mpClone = maOriginal.getFullDragClone();
		}
		
		// apply original transformation, implemented at the DragMethods
		rDragMethod.applyCurrentTransformationToSdrObject(*mpClone);
	}
}

drawinglayer::primitive2d::Primitive2DSequence SdrDragEntrySdrObject::createPrimitive2DSequenceInCurrentState(SdrDragMethod& /* rDragMethod */)
{
	const SdrObject* pSource = &maOriginal;

	if(mbModify && mpClone)
	{
		// choose source for geometry data
		pSource = mpClone;
	}

    // get VOC and Primitive2DSequence
    sdr::contact::ViewContact& rVC = pSource->GetViewContact();
    sdr::contact::ViewObjectContact& rVOC = rVC.GetViewObjectContact(mrObjectContact);
    sdr::contact::DisplayInfo aDisplayInfo;

    // Do not use the last ViewPort set at the OC from the last ProcessDisplay(),
    // here we want the complete primitive sequence without visibility clippings
    mrObjectContact.resetViewPort();

    return rVOC.getPrimitive2DSequenceHierarchy(aDisplayInfo);
}

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

SdrDragEntryPrimitive2DSequence::SdrDragEntryPrimitive2DSequence(
    const drawinglayer::primitive2d::Primitive2DSequence& rSequence,
    bool bAddToTransparent)
:   SdrDragEntry(),
    maPrimitive2DSequence(rSequence)
{
	// add parts to transparent overlay stuff eventually
	setAddToTransparent(bAddToTransparent);
}

SdrDragEntryPrimitive2DSequence::~SdrDragEntryPrimitive2DSequence()
{
}

drawinglayer::primitive2d::Primitive2DSequence SdrDragEntryPrimitive2DSequence::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
{
	drawinglayer::primitive2d::Primitive2DReference aTransformPrimitive2D(
        new drawinglayer::primitive2d::TransformPrimitive2D(
            rDragMethod.getCurrentTransformation(), 
            maPrimitive2DSequence));

    return drawinglayer::primitive2d::Primitive2DSequence(&aTransformPrimitive2D, 1);
}

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

SdrDragEntryPointGlueDrag::SdrDragEntryPointGlueDrag(const std::vector< basegfx::B2DPoint >& rPositions, bool bIsPointDrag)
:   maPositions(rPositions),
    mbIsPointDrag(bIsPointDrag)
{
	// add SdrObject parts to transparent overlay stuff
	setAddToTransparent(true);
}

SdrDragEntryPointGlueDrag::~SdrDragEntryPointGlueDrag()
{
}

drawinglayer::primitive2d::Primitive2DSequence SdrDragEntryPointGlueDrag::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
{
	drawinglayer::primitive2d::Primitive2DSequence aRetval;

    if(!maPositions.empty())
    {
        basegfx::B2DPolygon aPolygon;
        sal_uInt32 a(0);

        for(a = 0; a < maPositions.size(); a++)
        {
            aPolygon.append(maPositions[a]);
        }

        basegfx::B2DPolyPolygon aPolyPolygon(aPolygon);
        
        rDragMethod.applyCurrentTransformationToPolyPolygon(aPolyPolygon);

        const basegfx::B2DPolygon aTransformed(aPolyPolygon.getB2DPolygon(0));
        std::vector< basegfx::B2DPoint > aTransformedPositions;

        aTransformedPositions.reserve(aTransformed.count());

        for(a = 0; a < aTransformed.count(); a++)
        {
            aTransformedPositions.push_back(aTransformed.getB2DPoint(a));
        }

        if(mbIsPointDrag)
        {
		    const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
		    basegfx::BColor aColor(aSvtOptionsDrawinglayer.GetStripeColorA().getBColor());

		    if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
		    {
			    aColor = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
		    }

            drawinglayer::primitive2d::Primitive2DReference aMarkerArrayPrimitive2D(
			    new drawinglayer::primitive2d::MarkerArrayPrimitive2D(aTransformedPositions, 
					drawinglayer::primitive2d::createDefaultCross_3x3(aColor)));

		    aRetval = drawinglayer::primitive2d::Primitive2DSequence(&aMarkerArrayPrimitive2D, 1);
        }
        else
        {
			const basegfx::BColor aBackPen(1.0, 1.0, 1.0);
			const basegfx::BColor aRGBFrontColor(0.0, 0.0, 1.0); // COL_LIGHTBLUE
            drawinglayer::primitive2d::Primitive2DReference aMarkerArrayPrimitive2D(
			    new drawinglayer::primitive2d::MarkerArrayPrimitive2D(aTransformedPositions, 
					drawinglayer::primitive2d::createDefaultGluepoint_7x7(aBackPen, aRGBFrontColor)));

		    aRetval = drawinglayer::primitive2d::Primitive2DSequence(&aMarkerArrayPrimitive2D, 1);
        }
    }

    return aRetval;
}

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

TYPEINIT0(SdrDragMethod);

void SdrDragMethod::resetSdrDragEntries()
{
    // clear entries; creation is on demand
    clearSdrDragEntries();
}

basegfx::B2DRange SdrDragMethod::getCurrentRange() const
{
    return getB2DRangeFromOverlayObjectList();
}

void SdrDragMethod::clearSdrDragEntries() 
{ 
    for(sal_uInt32 a(0); a < maSdrDragEntries.size(); a++) 
    { 
        delete maSdrDragEntries[a]; 
    } 

    maSdrDragEntries.clear(); 
}

void SdrDragMethod::addSdrDragEntry(SdrDragEntry* pNew) 
{ 
    if(pNew) 
    { 
        maSdrDragEntries.push_back(pNew); 
    }
}

void SdrDragMethod::createSdrDragEntries()
{
	if(getSdrDragView().GetSdrPageView() && getSdrDragView().GetSdrPageView()->HasMarkedObjPageView())
	{
	    if(getSdrDragView().IsDraggingPoints()) 
	    {
            createSdrDragEntries_PointDrag();
	    }
	    else if(getSdrDragView().IsDraggingGluePoints()) 
	    {
            createSdrDragEntries_GlueDrag();
	    }
	    else
	    {
            if(getSolidDraggingActive())
            {
                createSdrDragEntries_SolidDrag();
            }
            else
            {
                createSdrDragEntries_PolygonDrag();
            }
        }
    }
}

void SdrDragMethod::createSdrDragEntryForSdrObject(const SdrObject& rOriginal, sdr::contact::ObjectContact& rObjectContact, bool bModify)
{
    // add full obejct drag; Clone() at the object has to work
    // for this
    addSdrDragEntry(new SdrDragEntrySdrObject(rOriginal, rObjectContact, bModify));
}

void SdrDragMethod::createSdrDragEntries_SolidDrag()
{
    const sal_uInt32 nMarkAnz(getSdrDragView().GetMarkedObjectCount());
    SdrPageView* pPV = getSdrDragView().GetSdrPageView();

    if(pPV)
    {
        for(sal_uInt32 a(0); a < nMarkAnz; a++)
        {
		    SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(a);
    		
		    if(pM->GetPageView() == pPV) 
		    {
			    const SdrObject* pObject = pM->GetMarkedSdrObj();

                if(pObject)
                {
                    if(pPV->PageWindowCount())
                    {
	                    sdr::contact::ObjectContact& rOC = pPV->GetPageWindow(0)->GetObjectContact();
                        SdrObjListIter aIter(*pObject);
                		
                        while(aIter.IsMore())
                        {
                            SdrObject* pCandidate = aIter.Next();

                            if(pCandidate)
                            {
                                const bool bSuppressFullDrag(!pCandidate->supportsFullDrag());
                                bool bAddWireframe(bSuppressFullDrag);

                                if(!bAddWireframe && !pCandidate->HasLineStyle())
                                {
									// add wireframe for objects without outline
                                    bAddWireframe = true;
                                }

                                if(!bSuppressFullDrag)
                                {
                                    // add full obejct drag; Clone() at the object has to work
                                    // for this
                                    createSdrDragEntryForSdrObject(*pCandidate, rOC, true);
                                }

                                if(bAddWireframe)
                                {
                                    // when dragging a 50% transparent copy of a filled or not filled object without 
                                    // outline, this is normally hard to see. Add extra wireframe in that case. This
                                    // works nice e.g. with thext frames etc.
                                    addSdrDragEntry(new SdrDragEntryPolyPolygon(pCandidate->TakeXorPoly()));
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

void SdrDragMethod::createSdrDragEntries_PolygonDrag()
{
    const sal_uInt32 nMarkAnz(getSdrDragView().GetMarkedObjectCount());
    bool bNoPolygons(getSdrDragView().IsNoDragXorPolys() || nMarkAnz > getSdrDragView().GetDragXorPolyLimit());
    basegfx::B2DPolyPolygon aResult;
    sal_uInt32 nPointCount(0);

    for(sal_uInt32 a(0); !bNoPolygons && a < nMarkAnz; a++)
    {
		SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(a);
		
		if(pM->GetPageView() == getSdrDragView().GetSdrPageView()) 
		{
			const basegfx::B2DPolyPolygon aNewPolyPolygon(pM->GetMarkedSdrObj()->TakeXorPoly());

            for(sal_uInt32 b(0); b < aNewPolyPolygon.count(); b++)
            {
                nPointCount += aNewPolyPolygon.getB2DPolygon(b).count();
            }

            if(nPointCount > getSdrDragView().GetDragXorPointLimit())
            {
                bNoPolygons = true;
            }

            if(!bNoPolygons)
            {
                aResult.append(aNewPolyPolygon);
            }
        }
    }

    if(bNoPolygons)
    {
	    const Rectangle aR(getSdrDragView().GetSdrPageView()->MarkSnap());
	    const basegfx::B2DRange aNewRectangle(aR.Left(), aR.Top(), aR.Right(), aR.Bottom());
	    basegfx::B2DPolygon aNewPolygon(basegfx::tools::createPolygonFromRect(aNewRectangle));
	    
        aResult = basegfx::B2DPolyPolygon(basegfx::tools::expandToCurve(aNewPolygon));
    }

    if(aResult.count())
    {
        addSdrDragEntry(new SdrDragEntryPolyPolygon(aResult));
    }
}

void SdrDragMethod::createSdrDragEntries_PointDrag()
{
    const sal_uInt32 nMarkAnz(getSdrDragView().GetMarkedObjectCount());
    std::vector< basegfx::B2DPoint > aPositions;
	
    for(sal_uInt32 nm(0); nm < nMarkAnz; nm++)
	{
		SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(nm);

        if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
		{
			const SdrUShortCont* pPts = pM->GetMarkedPoints();

            if(pPts && pPts->GetCount()) 
			{
				const SdrObject* pObj = pM->GetMarkedSdrObj();
				const SdrPathObj* pPath = dynamic_cast< const SdrPathObj* >(pObj);

                if(pPath)
                {
				    const basegfx::B2DPolyPolygon aPathXPP = pPath->GetPathPoly();
				    
                    if(aPathXPP.count()) 
				    {
				        const sal_uInt32 nPtAnz(pPts->GetCount());

				        for(sal_uInt32 nPtNum(0); nPtNum < nPtAnz; nPtNum++)
				        {
					        sal_uInt32 nPolyNum, nPointNum;
					        const sal_uInt16 nObjPt(pPts->GetObject(nPtNum));

                            if(sdr::PolyPolygonEditor::GetRelativePolyPoint(aPathXPP, nObjPt, nPolyNum, nPointNum)) 
					        {
                                aPositions.push_back(aPathXPP.getB2DPolygon(nPolyNum).getB2DPoint(nPointNum));
					        }
					    }
				    }
                }
			}
		}
    }

    if(!aPositions.empty())
    {
        addSdrDragEntry(new SdrDragEntryPointGlueDrag(aPositions, true));
    }
}

void SdrDragMethod::createSdrDragEntries_GlueDrag()
{
    const sal_uInt32 nMarkAnz(getSdrDragView().GetMarkedObjectCount());
    std::vector< basegfx::B2DPoint > aPositions;
	
    for(sal_uInt32 nm(0); nm < nMarkAnz; nm++)
	{
		SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(nm);

        if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
		{
			const SdrUShortCont* pPts = pM->GetMarkedGluePoints();

            if(pPts && pPts->GetCount()) 
			{
				const SdrObject* pObj = pM->GetMarkedSdrObj();
    			const SdrGluePointList* pGPL = pObj->GetGluePointList();
	
                if(pGPL) 
				{
				    const sal_uInt32 nPtAnz(pPts->GetCount());

				    for(sal_uInt32 nPtNum(0); nPtNum < nPtAnz; nPtNum++)
				    {
					    const sal_uInt16 nObjPt(pPts->GetObject(nPtNum));
					    const sal_uInt16 nGlueNum(pGPL->FindGluePoint(nObjPt));

					    if(SDRGLUEPOINT_NOTFOUND != nGlueNum) 
					    {
						    const Point aPoint((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
                            aPositions.push_back(basegfx::B2DPoint(aPoint.X(), aPoint.Y()));
					    }
				    }
                }
			}
		}
    }

    if(!aPositions.empty())
    {
        addSdrDragEntry(new SdrDragEntryPointGlueDrag(aPositions, false));
    }
}

void SdrDragMethod::ImpTakeDescriptionStr(sal_uInt16 nStrCacheID, XubString& rStr, sal_uInt16 nVal) const
{
	sal_uInt16 nOpt=0;
	if (IsDraggingPoints()) {
		nOpt=IMPSDR_POINTSDESCRIPTION;
	} else if (IsDraggingGluePoints()) {
		nOpt=IMPSDR_GLUEPOINTSDESCRIPTION;
	}
	getSdrDragView().ImpTakeDescriptionStr(nStrCacheID,rStr,nVal,nOpt);
}

SdrObject* SdrDragMethod::GetDragObj() const
{
	SdrObject* pObj=NULL;
	if (getSdrDragView().pDragHdl!=NULL) pObj=getSdrDragView().pDragHdl->GetObj();
	if (pObj==NULL) pObj=getSdrDragView().pMarkedObj;
	return pObj;
}

SdrPageView* SdrDragMethod::GetDragPV() const
{
	SdrPageView* pPV=NULL;
	if (getSdrDragView().pDragHdl!=NULL) pPV=getSdrDragView().pDragHdl->GetPageView();
	if (pPV==NULL) pPV=getSdrDragView().pMarkedPV;
	return pPV;
}

void SdrDragMethod::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
    // the original applies the transformation using TRGetBaseGeometry/TRSetBaseGeometry.
	// Later this should be the only needed one for linear transforms (not for SdrDragCrook and
	// SdrDragDistort, those are NOT linear). Currently, this can not yet be used since the 
	// special handling of rotate/mirror due to the not-being-able to handle it in the old
	// drawinglayer stuff. Text would currently not correctly be mirrored in the preview.
	basegfx::B2DHomMatrix aObjectTransform;
	basegfx::B2DPolyPolygon aObjectPolyPolygon;
	bool bPolyUsed(rTarget.TRGetBaseGeometry(aObjectTransform, aObjectPolyPolygon));

	// apply transform to object transform
	aObjectTransform *= getCurrentTransformation();

	if(bPolyUsed)
	{
		// do something special since the object size is in the polygon
		// break up matrix to get the scale
		basegfx::B2DTuple aScale;
		basegfx::B2DTuple aTranslate;
		double fRotate, fShearX;
		aObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);

		// get polygon's pos and size
		const basegfx::B2DRange aPolyRange(aObjectPolyPolygon.getB2DRange());

		// get the scaling factors (do not mirror, this is in the object transformation)
		const double fScaleX(fabs(aScale.getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth()));
		const double fScaleY(fabs(aScale.getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight()));

		// prepare transform matrix for polygon
        basegfx::B2DHomMatrix aPolyTransform(basegfx::tools::createTranslateB2DHomMatrix(
            -aPolyRange.getMinX(), -aPolyRange.getMinY()));
		aPolyTransform.scale(fScaleX, fScaleY);

		// normally the poly should be moved back, but the translation is in the object 
		// transformation and thus does not need to be done
		// aPolyTransform.translate(-aPolyRange.getMinX(), -aPolyRange.getMinY());

		// transform the polygon
		aObjectPolyPolygon.transform(aPolyTransform);
	}

	rTarget.TRSetBaseGeometry(getCurrentTransformation() * aObjectTransform, aObjectPolyPolygon);
}

void SdrDragMethod::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
{
	// original uses CurrentTransformation
	rTarget.transform(getCurrentTransformation());
}

SdrDragMethod::SdrDragMethod(SdrDragView& rNewView)
:	maSdrDragEntries(),
    maOverlayObjectList(),
    mrSdrDragView(rNewView),
	mbMoveOnly(false),
	mbSolidDraggingActive(getSdrDragView().IsSolidDragging())
{
	if(mbSolidDraggingActive && Application::GetSettings().GetStyleSettings().GetHighContrastMode())
    {
        // fallback to wireframe when high contrast is used
        mbSolidDraggingActive = false;
    }
}

SdrDragMethod::~SdrDragMethod()
{
    clearSdrDragEntries();
}

void SdrDragMethod::Show()
{
	getSdrDragView().ShowDragObj();
}

void SdrDragMethod::Hide()
{
	getSdrDragView().HideDragObj();
}

basegfx::B2DHomMatrix SdrDragMethod::getCurrentTransformation()
{
	return basegfx::B2DHomMatrix();
}

void SdrDragMethod::CancelSdrDrag()
{
	Hide();
}

struct compareConstSdrObjectRefs
{
    bool operator()(const SdrObject* p1, const SdrObject* p2) const
    {
        return (p1 < p2);
    }
};

typedef std::map< const SdrObject*, SdrObject*, compareConstSdrObjectRefs> SdrObjectAndCloneMap;

void SdrDragMethod::CreateOverlayGeometry(sdr::overlay::OverlayManager& rOverlayManager)
{
    // create SdrDragEntries on demand
    if(maSdrDragEntries.empty())
    {
        createSdrDragEntries();
    }

    // if there are entries, derive OverlayObjects from the entries, including
    // modification from current interactive state
    if(!maSdrDragEntries.empty())
    {
        // #54102# SdrDragEntrySdrObject creates clones of SdrObjects as base for creating the needed
        // primitives, holding the original and the clone. If connectors (Edges) are involved,
        // the cloned connectors need to be connected to the cloned SdrObjects (after cloning
        // they are connected to the original SdrObjects). To do so, trigger the preparation
        // steps for SdrDragEntrySdrObject, save an association of (orig, clone) in a helper
        // and evtl. remember if it was an edge
        SdrObjectAndCloneMap aOriginalAndClones;
        std::vector< SdrEdgeObj* > aEdges;
        sal_uInt32 a;
		
        // #54102# execute prepareCurrentState for all SdrDragEntrySdrObject, register pair of original and
        // clone, remember edges
		for(a = 0; a < maSdrDragEntries.size(); a++)
        {
            SdrDragEntrySdrObject* pSdrDragEntrySdrObject = dynamic_cast< SdrDragEntrySdrObject*>(maSdrDragEntries[a]);

            if(pSdrDragEntrySdrObject)
            {
                pSdrDragEntrySdrObject->prepareCurrentState(*this);

                SdrEdgeObj* pSdrEdgeObj = dynamic_cast< SdrEdgeObj* >(pSdrDragEntrySdrObject->getClone());

                if(pSdrEdgeObj)
                {
                    aEdges.push_back(pSdrEdgeObj);
                }

                if(pSdrDragEntrySdrObject->getClone())
                {
                    aOriginalAndClones[&pSdrDragEntrySdrObject->getOriginal()] = pSdrDragEntrySdrObject->getClone();
                }
            }
        }

        // #54102# if there are edges, reconnect their ends to the corresponding clones (if found)
        if(aEdges.size())
        {
            for(a = 0; a < aEdges.size(); a++)
            {
                SdrEdgeObj* pSdrEdgeObj = aEdges[a];
                SdrObject* pConnectedTo = pSdrEdgeObj->GetConnectedNode(true);

                if(pConnectedTo)
                {
                    SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);

                    if(aEntry != aOriginalAndClones.end())
                    {
                        pSdrEdgeObj->ConnectToNode(true, aEntry->second);
                    }
                }

                pConnectedTo = pSdrEdgeObj->GetConnectedNode(false);

                if(pConnectedTo)
                {
                    SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);

                    if(aEntry != aOriginalAndClones.end())
                    {
                        pSdrEdgeObj->ConnectToNode(false, aEntry->second);
                    }
                }
            }
        }

        // collect primitives for visualisation
		drawinglayer::primitive2d::Primitive2DSequence aResult;
		drawinglayer::primitive2d::Primitive2DSequence aResultTransparent;

        for(a = 0; a < maSdrDragEntries.size(); a++)
        {
            SdrDragEntry* pCandidate = maSdrDragEntries[a];

            if(pCandidate)
            {
				const drawinglayer::primitive2d::Primitive2DSequence aCandidateResult(pCandidate->createPrimitive2DSequenceInCurrentState(*this));

				if(aCandidateResult.hasElements())
				{
					if(pCandidate->getAddToTransparent())
					{
						drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aResultTransparent, aCandidateResult);
					}
					else
					{
						drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aResult, aCandidateResult);
					}
				}
			}
		}

		if(DoAddConnectorOverlays())
		{
			const drawinglayer::primitive2d::Primitive2DSequence aConnectorOverlays(AddConnectorOverlays());

			if(aConnectorOverlays.hasElements())
			{
				// add connector overlays to transparent part
				drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(aResultTransparent, aConnectorOverlays);
			}
		}

		if(aResult.hasElements())
		{
	        sdr::overlay::OverlayObject* pNewOverlayObject = new sdr::overlay::OverlayPrimitive2DSequenceObject(aResult);
            rOverlayManager.add(*pNewOverlayObject);
			addToOverlayObjectList(*pNewOverlayObject);
		}
                
		if(aResultTransparent.hasElements())
		{
			drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(aResultTransparent, 0.5));
			aResultTransparent = drawinglayer::primitive2d::Primitive2DSequence(&aUnifiedTransparencePrimitive2D, 1);
	        
			sdr::overlay::OverlayObject* pNewOverlayObject = new sdr::overlay::OverlayPrimitive2DSequenceObject(aResultTransparent);
            rOverlayManager.add(*pNewOverlayObject);
			addToOverlayObjectList(*pNewOverlayObject);
		}
	}

	// evtl add DragStripes (help lines cross the page when dragging)
	if(getSdrDragView().IsDragStripes())
	{
		Rectangle aActionRectangle;
		getSdrDragView().TakeActionRect(aActionRectangle);

		const basegfx::B2DPoint aTopLeft(aActionRectangle.Left(), aActionRectangle.Top());
		const basegfx::B2DPoint aBottomRight(aActionRectangle.Right(), aActionRectangle.Bottom());
		sdr::overlay::OverlayRollingRectangleStriped* pNew = new sdr::overlay::OverlayRollingRectangleStriped(
			aTopLeft, aBottomRight, true, false);

		rOverlayManager.add(*pNew);
		addToOverlayObjectList(*pNew);
	}
}

void SdrDragMethod::destroyOverlayGeometry()
{
	clearOverlayObjectList();
}

bool SdrDragMethod::DoAddConnectorOverlays()
{
	// these conditions are translated from SdrDragView::ImpDrawEdgeXor
	const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();

	if(!rMarkedNodes.GetMarkCount())
	{
		return false;
	}

	if(!getSdrDragView().IsRubberEdgeDragging() && !getSdrDragView().IsDetailedEdgeDragging())
	{
		return false;
	}
	
	if(getSdrDragView().IsDraggingPoints() || getSdrDragView().IsDraggingGluePoints())
	{
		return false;
	}

	if(!getMoveOnly() && !(
		IS_TYPE(SdrDragMove, this) || IS_TYPE(SdrDragResize, this) ||
		IS_TYPE(SdrDragRotate,this) || IS_TYPE(SdrDragMirror,this)))
	{
		return false;
	}

	const bool bDetail(getSdrDragView().IsDetailedEdgeDragging() && getMoveOnly());

	if(!bDetail && !getSdrDragView().IsRubberEdgeDragging())
	{
		return false;
	}

	// one more migrated from SdrEdgeObj::NspToggleEdgeXor
	if(IS_TYPE(SdrDragObjOwn, this) || IS_TYPE(SdrDragMovHdl, this))
	{
		return false;
	}

	return true;
}

drawinglayer::primitive2d::Primitive2DSequence SdrDragMethod::AddConnectorOverlays()
{
	drawinglayer::primitive2d::Primitive2DSequence aRetval;
	const bool bDetail(getSdrDragView().IsDetailedEdgeDragging() && getMoveOnly());
	const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();

	for(sal_uInt16 a(0); a < rMarkedNodes.GetMarkCount(); a++)
	{
		SdrMark* pEM = rMarkedNodes.GetMark(a);

		if(pEM && pEM->GetMarkedSdrObj())
		{
			SdrEdgeObj* pEdge = dynamic_cast< SdrEdgeObj* >(pEM->GetMarkedSdrObj());

			if(pEdge)
			{
				const basegfx::B2DPolygon aEdgePolygon(pEdge->ImplAddConnectorOverlay(*this, pEM->IsCon1(), pEM->IsCon2(), bDetail));

				if(aEdgePolygon.count())
				{
					// this polygon is a temporary calculated connector path, so it is not possible to fetch
					// the needed primitives directly from the pEdge object which does not get changed. If full
					// drag is on, use the SdrObjects ItemSet to create a adequate representation
                    bool bUseSolidDragging(getSolidDraggingActive());

                    if(bUseSolidDragging)
                    {
                        // switch off solid dragging if connector is not visible
                        if(!pEdge->HasLineStyle())
                        {
                            bUseSolidDragging = false;
                        }
                    }

		            if(bUseSolidDragging)
					{
						const SfxItemSet& rItemSet = pEdge->GetMergedItemSet();
						const drawinglayer::attribute::SdrLineAttribute aLine(
							drawinglayer::primitive2d::createNewSdrLineAttribute(rItemSet));

						if(!aLine.isDefault())
						{
							const drawinglayer::attribute::SdrLineStartEndAttribute aLineStartEnd(
								drawinglayer::primitive2d::createNewSdrLineStartEndAttribute(
									rItemSet, 
									aLine.getWidth()));
						
							drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
								aRetval, drawinglayer::primitive2d::createPolygonLinePrimitive(
									aEdgePolygon, 
									basegfx::B2DHomMatrix(), 
									aLine, 
									aLineStartEnd));
						}
					}
					else
					{
						const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
						basegfx::BColor aColA(aSvtOptionsDrawinglayer.GetStripeColorA().getBColor());
						basegfx::BColor aColB(aSvtOptionsDrawinglayer.GetStripeColorB().getBColor());
						const double fStripeLength(aSvtOptionsDrawinglayer.GetStripeLength());

						if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
						{
							aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
							aColB.invert();
						}

						drawinglayer::primitive2d::Primitive2DReference aPolyPolygonMarkerPrimitive2D(
							new drawinglayer::primitive2d::PolygonMarkerPrimitive2D(
								aEdgePolygon, aColA, aColB, fStripeLength));
				        drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, aPolyPolygonMarkerPrimitive2D);
					}
				}
			}
		}
	}

	return aRetval;
}

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

TYPEINIT1(SdrDragMovHdl,SdrDragMethod);

SdrDragMovHdl::SdrDragMovHdl(SdrDragView& rNewView)
:	SdrDragMethod(rNewView), 
	bMirrObjShown(false) 
{
}

void SdrDragMovHdl::createSdrDragEntries()
{
    // SdrDragMovHdl does not use the default drags,
    // but creates nothing
}

void SdrDragMovHdl::TakeSdrDragComment(XubString& rStr) const
{
	rStr=ImpGetResStr(STR_DragMethMovHdl);
	if (getSdrDragView().IsDragWithCopy()) rStr+=ImpGetResStr(STR_EditWithCopy);
}

bool SdrDragMovHdl::BeginSdrDrag()
{
	if( !GetDragHdl() )
		return false;

	DragStat().Ref1()=GetDragHdl()->GetPos();
	DragStat().SetShown(!DragStat().IsShown());
	SdrHdlKind eKind=GetDragHdl()->GetKind();
	SdrHdl* pH1=GetHdlList().GetHdl(HDL_REF1);
	SdrHdl* pH2=GetHdlList().GetHdl(HDL_REF2);

	if (eKind==HDL_MIRX) 
	{
		if (pH1==NULL || pH2==NULL) 
		{
			DBG_ERROR("SdrDragMovHdl::BeginSdrDrag(): Verschieben der Spiegelachse: Referenzhandles nicht gefunden");
			return false;
		}
		
		DragStat().SetActionRect(Rectangle(pH1->GetPos(),pH2->GetPos()));
	} 
	else 
	{
		Point aPt(GetDragHdl()->GetPos());
		DragStat().SetActionRect(Rectangle(aPt,aPt));
	}
	
	return true;
}

void SdrDragMovHdl::MoveSdrDrag(const Point& rNoSnapPnt)
{
	Point aPnt(rNoSnapPnt);
	
	if ( GetDragHdl() && DragStat().CheckMinMoved(rNoSnapPnt)) 
	{
		if (GetDragHdl()->GetKind()==HDL_MIRX) 
		{
			SdrHdl* pH1=GetHdlList().GetHdl(HDL_REF1);
			SdrHdl* pH2=GetHdlList().GetHdl(HDL_REF2);
		
			if (pH1==NULL || pH2==NULL) 
				return;
			
			if (!DragStat().IsNoSnap()) 
			{
				long nBestXSnap=0;
				long nBestYSnap=0;
				bool bXSnapped=false;
				bool bYSnapped=false;
				Point aDif(aPnt-DragStat().GetStart());
				getSdrDragView().CheckSnap(Ref1()+aDif,NULL,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
				getSdrDragView().CheckSnap(Ref2()+aDif,NULL,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
				aPnt.X()+=nBestXSnap;
				aPnt.Y()+=nBestYSnap;
			}
			
			if (aPnt!=DragStat().GetNow()) 
			{
				Hide();
				DragStat().NextMove(aPnt);
				Point aDif(DragStat().GetNow()-DragStat().GetStart());
				pH1->SetPos(Ref1()+aDif);
				pH2->SetPos(Ref2()+aDif);

				SdrHdl* pHM = GetHdlList().GetHdl(HDL_MIRX);
		
				if(pHM)
					pHM->Touch();

				Show();
				DragStat().SetActionRect(Rectangle(pH1->GetPos(),pH2->GetPos()));
			}
		} 
		else 
		{
			if (!DragStat().IsNoSnap()) SnapPos(aPnt);
			long nSA=0;

			if (getSdrDragView().IsAngleSnapEnabled()) 
				nSA=getSdrDragView().GetSnapAngle();

			if (getSdrDragView().IsMirrorAllowed(true,true)) 
			{ // eingeschraenkt
				if (!getSdrDragView().IsMirrorAllowed(false,false)) nSA=4500;
				if (!getSdrDragView().IsMirrorAllowed(true,false)) nSA=9000;
			}

			if (getSdrDragView().IsOrtho() && nSA!=9000) 
				nSA=4500;

			if (nSA!=0) 
			{ // Winkelfang
				SdrHdlKind eRef=HDL_REF1;
			
				if (GetDragHdl()->GetKind()==HDL_REF1) 
					eRef=HDL_REF2;

				SdrHdl* pH=GetHdlList().GetHdl(eRef);
				
				if (pH!=NULL) 
				{
					Point aRef(pH->GetPos());
					long nWink=NormAngle360(GetAngle(aPnt-aRef));
					long nNeuWink=nWink;
					nNeuWink+=nSA/2;
					nNeuWink/=nSA;
					nNeuWink*=nSA;
					nNeuWink=NormAngle360(nNeuWink);
					double a=(nNeuWink-nWink)*nPi180;
					double nSin=sin(a);
					double nCos=cos(a);
					RotatePoint(aPnt,aRef,nSin,nCos);
				
					// Bei bestimmten Werten Rundungsfehler ausschliessen:
					if (nSA==9000) 
					{
						if (nNeuWink==0    || nNeuWink==18000) aPnt.Y()=aRef.Y();
						if (nNeuWink==9000 || nNeuWink==27000) aPnt.X()=aRef.X();
					}
					
					if (nSA==4500) 
						OrthoDistance8(aRef,aPnt,true);
				}
			}

			if (aPnt!=DragStat().GetNow()) 
			{
				Hide();
				DragStat().NextMove(aPnt);
				GetDragHdl()->SetPos(DragStat().GetNow());
				SdrHdl* pHM = GetHdlList().GetHdl(HDL_MIRX);
			
				if(pHM)
					pHM->Touch();
				
				Show();
				DragStat().SetActionRect(Rectangle(aPnt,aPnt));
			}
		}
	}
}

bool SdrDragMovHdl::EndSdrDrag(bool /*bCopy*/)
{
	if( GetDragHdl() )
	{
		switch (GetDragHdl()->GetKind()) 
		{
			case HDL_REF1: 
				Ref1()=DragStat().GetNow(); 
				break;
		
			case HDL_REF2: 
				Ref2()=DragStat().GetNow(); 
				break;

			case HDL_MIRX: 
				Ref1()+=DragStat().GetNow()-DragStat().GetStart();
				Ref2()+=DragStat().GetNow()-DragStat().GetStart();
				break;

			default: break;
		}
	}

	return true;
}

void SdrDragMovHdl::CancelSdrDrag()
{
	Hide();

	SdrHdl* pHdl = GetDragHdl();
	if( pHdl )
		pHdl->SetPos(DragStat().GetRef1());
	
	SdrHdl* pHM = GetHdlList().GetHdl(HDL_MIRX);

	if(pHM)
		pHM->Touch();
}

Pointer SdrDragMovHdl::GetSdrDragPointer() const
{
	const SdrHdl* pHdl = GetDragHdl();

	if (pHdl!=NULL) 
	{
		return pHdl->GetPointer();
	}
	
	return Pointer(POINTER_REFHAND);
}

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

TYPEINIT1(SdrDragObjOwn,SdrDragMethod);

SdrDragObjOwn::SdrDragObjOwn(SdrDragView& rNewView)
:	SdrDragMethod(rNewView),
	mpClone(0)
{
    const SdrObject* pObj = GetDragObj();

    if(pObj)
    {
		// suppress full drag for some object types
		setSolidDraggingActive(pObj->supportsFullDrag());
	}
}

SdrDragObjOwn::~SdrDragObjOwn()
{
	if(mpClone)
	{
		SdrObject::Free(mpClone);
	}
}

void SdrDragObjOwn::createSdrDragEntries()
{
    if(mpClone)
    {
        basegfx::B2DPolyPolygon aDragPolyPolygon;
		bool bAddWireframe(true);

		if(getSolidDraggingActive())
		{
			SdrPageView* pPV = getSdrDragView().GetSdrPageView();

			if(pPV && pPV->PageWindowCount())
			{
				sdr::contact::ObjectContact& rOC = pPV->GetPageWindow(0)->GetObjectContact();
				addSdrDragEntry(new SdrDragEntrySdrObject(*mpClone, rOC, false));

                // potentially no wireframe needed, full drag works
				bAddWireframe = false;
			}
		}

        if(!bAddWireframe)
        {
            // check for extra conditions for wireframe, e.g. no border at
            // objects
            if(!mpClone->HasLineStyle())
            {
                bAddWireframe = true;
            }
        }

		if(bAddWireframe)
		{
            // use wireframe poly when full drag is off or did not work
            aDragPolyPolygon = mpClone->TakeXorPoly();
        }

        // add evtl. extra DragPolyPolygon
    	const basegfx::B2DPolyPolygon aSpecialDragPolyPolygon(mpClone->getSpecialDragPoly(DragStat()));

        if(aSpecialDragPolyPolygon.count())
        {
            aDragPolyPolygon.append(aSpecialDragPolyPolygon);
        }

		if(aDragPolyPolygon.count())
		{
			addSdrDragEntry(new SdrDragEntryPolyPolygon(aDragPolyPolygon));
		}
	}
}

void SdrDragObjOwn::TakeSdrDragComment(XubString& rStr) const
{
    // #i103058# get info string from the clone preferred, the original will
    // not be changed. For security, use original as fallback
    if(mpClone)
    {
		rStr = mpClone->getSpecialDragComment(DragStat());
    }
    else
    {
        const SdrObject* pObj = GetDragObj();

        if(pObj)
        {
		    rStr = pObj->getSpecialDragComment(DragStat());
	    }
    }
}

bool SdrDragObjOwn::BeginSdrDrag()
{
	if(!mpClone)
	{
		const SdrObject* pObj = GetDragObj();

		if(pObj && !pObj->IsResizeProtect())
		{
			if(pObj->beginSpecialDrag(DragStat()))
			{
				// create nitial clone to have a start visualisation
				mpClone = pObj->getFullDragClone();
				mpClone->applySpecialDrag(DragStat());
				
				return true;
			}
		}
	}

    return false;
}

void SdrDragObjOwn::MoveSdrDrag(const Point& rNoSnapPnt)
{
	const SdrObject* pObj = GetDragObj();

	if(pObj) 
	{
		Point aPnt(rNoSnapPnt);
		SdrPageView* pPV = GetDragPV();
		
		if(pPV) 
		{
			if(!DragStat().IsNoSnap()) 
			{
				SnapPos(aPnt);
			}

			if(getSdrDragView().IsOrtho()) 
			{
				if (DragStat().IsOrtho8Possible()) 
				{
					OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
				}
				else if (DragStat().IsOrtho4Possible()) 
				{
					OrthoDistance4(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
				}
			}

			if(DragStat().CheckMinMoved(rNoSnapPnt)) 
			{
				if(aPnt != DragStat().GetNow()) 
				{
					Hide();
					DragStat().NextMove(aPnt);

					// since SdrDragObjOwn currently supports no transformation of
					// existing SdrDragEntries but only their recreation, a recreation 
					// after every move is needed in this mode. Delete existing 
					// SdrDragEntries here  to force their recreation in the following Show().
					clearSdrDragEntries();

					// delete current clone (after the last reference to it is deleted above)
					if(mpClone)
					{
						SdrObject::Free(mpClone);
						mpClone = 0;
					}

					// create a new clone and modify to current drag state
					if(!mpClone)
					{
						mpClone = pObj->getFullDragClone();
						mpClone->applySpecialDrag(DragStat());

                        // #120999# AutoGrowWidth may change for SdrTextObj due to the automatism used
                        // with bDisableAutoWidthOnDragging, so not only geometry changes but
                        // also this (pretty indirect) property change is possible. If it gets
                        // changed, it needs to be copied to the original since nothing will
                        // happen when it only changes in the drag clone
                        const bool bOldAutoGrowWidth(((SdrTextAutoGrowWidthItem&)pObj->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH)).GetValue());
                        const bool bNewAutoGrowWidth(((SdrTextAutoGrowWidthItem&)mpClone->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH)).GetValue());

                        if(bOldAutoGrowWidth != bNewAutoGrowWidth)
                        {
                            GetDragObj()->SetMergedItem(SdrTextAutoGrowWidthItem(bNewAutoGrowWidth));
                        }
					}

					Show();
				}
			}
		}
	}
}

bool SdrDragObjOwn::EndSdrDrag(bool /*bCopy*/)
{
	Hide();
	SdrUndoAction* pUndo = NULL;
	SdrUndoAction* pUndo2 = NULL;
	std::vector< SdrUndoAction* > vConnectorUndoActions;
	bool bRet = false;
	SdrObject* pObj = GetDragObj();

	if(pObj)
	{
		const bool bUndo = getSdrDragView().IsUndoEnabled();

		if( bUndo )
		{
			if(!getSdrDragView().IsInsObjPoint() && pObj->IsInserted() ) 
			{
				if (DragStat().IsEndDragChangesAttributes())
				{
					pUndo=getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj);
				
					if (DragStat().IsEndDragChangesGeoAndAttributes())
					{
						vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );					
						pUndo2 = getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
					}
				}
				else
				{
					vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );					
					pUndo= getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
				}
			}

			if( pUndo )
			{
				getSdrDragView().BegUndo( pUndo->GetComment() );
			}
			else
			{
				getSdrDragView().BegUndo();
			}
		}

        // evtl. use opertator= for setting changed object data (do not change selection in
        // view, this will destroy the interactor). This is possible since a clone is now
        // directly modified by the modifiers. Only SdrTableObj is adding own UNDOs
        // in it's SdrTableObj::endSpecialDrag, so currently not possible. OTOH it uses
        // a CreateUndoGeoObject() so maybe setting SetEndDragChangesAttributes is okay. I
        // will test this now
        Rectangle aBoundRect0;

        if(pObj->GetUserCall())
        {
            aBoundRect0 = pObj->GetLastBoundRect();
        }

        bRet = pObj->applySpecialDrag(DragStat());
		
        if(bRet)
        {
	        pObj->SetChanged();
	        pObj->BroadcastObjectChange();
	        pObj->SendUserCall( SDRUSERCALL_RESIZE, aBoundRect0 );
        }

        if(bRet)
		{
			if( bUndo )
			{
				getSdrDragView().AddUndoActions( vConnectorUndoActions );
				
				if ( pUndo )
				{
					getSdrDragView().AddUndo(pUndo);
				}

				if ( pUndo2 ) 
				{
					getSdrDragView().AddUndo(pUndo2);
				}
			}
		}
		else
		{
			if( bUndo )
			{
				std::vector< SdrUndoAction* >::iterator vConnectorUndoIter( vConnectorUndoActions.begin() );
				
				while( vConnectorUndoIter != vConnectorUndoActions.end() )
				{
					delete *vConnectorUndoIter++;
				}
				
				delete pUndo;
				delete pUndo2;
			}
		}

		if( bUndo )
			getSdrDragView().EndUndo();
	}

    return bRet;
}

Pointer SdrDragObjOwn::GetSdrDragPointer() const
{
	const SdrHdl* pHdl=GetDragHdl();

	if (pHdl) 
	{
		return pHdl->GetPointer();
	}
	
	return Pointer(POINTER_MOVE);
}

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

TYPEINIT1(SdrDragMove,SdrDragMethod);

void SdrDragMove::createSdrDragEntryForSdrObject(const SdrObject& rOriginal, sdr::contact::ObjectContact& rObjectContact, bool /*bModify*/)
{
    // for SdrDragMove, use current Primitive2DSequence of SdrObject visualisation
    // in given ObjectContact directly
    sdr::contact::ViewContact& rVC = rOriginal.GetViewContact();
    sdr::contact::ViewObjectContact& rVOC = rVC.GetViewObjectContact(rObjectContact);
    sdr::contact::DisplayInfo aDisplayInfo;

    // Do not use the last ViewPort set at the OC from the last ProcessDisplay(),
    // here we want the complete primitive sequence without visibility clippings
    rObjectContact.resetViewPort();

    addSdrDragEntry(new SdrDragEntryPrimitive2DSequence(rVOC.getPrimitive2DSequenceHierarchy(aDisplayInfo), true));
}

void SdrDragMove::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
	rTarget.Move(Size(DragStat().GetDX(), DragStat().GetDY()));
}

SdrDragMove::SdrDragMove(SdrDragView& rNewView)
:	SdrDragMethod(rNewView) 
{
	setMoveOnly(true);
}

void SdrDragMove::TakeSdrDragComment(XubString& rStr) const
{
	XubString aStr;

	ImpTakeDescriptionStr(STR_DragMethMove, rStr);
	rStr.AppendAscii(" (x=");
	getSdrDragView().GetModel()->TakeMetricStr(DragStat().GetDX(), aStr);
	rStr += aStr;
	rStr.AppendAscii(" y=");
	getSdrDragView().GetModel()->TakeMetricStr(DragStat().GetDY(), aStr);
	rStr += aStr;
	rStr += sal_Unicode(')');
	
	if(getSdrDragView().IsDragWithCopy()) 
	{
		if(!getSdrDragView().IsInsObjPoint() && !getSdrDragView().IsInsGluePoint()) 
		{
			rStr += ImpGetResStr(STR_EditWithCopy);
		}
	}
}

bool SdrDragMove::BeginSdrDrag()
{
	DragStat().SetActionRect(GetMarkedRect());
	Show();

	return true;
}

basegfx::B2DHomMatrix SdrDragMove::getCurrentTransformation()
{
    return basegfx::tools::createTranslateB2DHomMatrix(DragStat().GetDX(), DragStat().GetDY());
}

void SdrDragMove::ImpCheckSnap(const Point& rPt)
{
	Point aPt(rPt);
	sal_uInt16 nRet=SnapPos(aPt);
	aPt-=rPt;

	if ((nRet & SDRSNAP_XSNAPPED) !=0) 
	{
		if (bXSnapped) 
		{
			if (Abs(aPt.X())<Abs(nBestXSnap)) 
			{
				nBestXSnap=aPt.X();
			}
		} 
		else 
		{
			nBestXSnap=aPt.X();
			bXSnapped=true;
		}
	}

	if ((nRet & SDRSNAP_YSNAPPED) !=0) 
	{
		if (bYSnapped) 
		{
			if (Abs(aPt.Y())<Abs(nBestYSnap)) 
			{
				nBestYSnap=aPt.Y();
			}
		} 
		else 
		{
			nBestYSnap=aPt.Y();
			bYSnapped=true;
		}
	}
}

void SdrDragMove::MoveSdrDrag(const Point& rNoSnapPnt_)
{
	nBestXSnap=0;
	nBestYSnap=0;
	bXSnapped=false;
	bYSnapped=false;
	Point aNoSnapPnt(rNoSnapPnt_);
	const Rectangle& aSR=GetMarkedRect();
	long nMovedx=aNoSnapPnt.X()-DragStat().GetStart().X();
	long nMovedy=aNoSnapPnt.Y()-DragStat().GetStart().Y();
	Point aLO(aSR.TopLeft());      aLO.X()+=nMovedx; aLO.Y()+=nMovedy;
	Point aRU(aSR.BottomRight());  aRU.X()+=nMovedx; aRU.Y()+=nMovedy;
	Point aLU(aLO.X(),aRU.Y());
	Point aRO(aRU.X(),aLO.Y());
	ImpCheckSnap(aLO);

	if (!getSdrDragView().IsMoveSnapOnlyTopLeft()) 
	{
		ImpCheckSnap(aRO);
		ImpCheckSnap(aLU);
		ImpCheckSnap(aRU);
	}
	
	Point aPnt(aNoSnapPnt.X()+nBestXSnap,aNoSnapPnt.Y()+nBestYSnap);
	bool bOrtho=getSdrDragView().IsOrtho();
	
	if (bOrtho) 
		OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());

	if (DragStat().CheckMinMoved(aNoSnapPnt)) 
	{
		Point aPt1(aPnt);
		Rectangle aLR(getSdrDragView().GetWorkArea());
		bool bWorkArea=!aLR.IsEmpty();
		bool bDragLimit=IsDragLimit();
	
		if (bDragLimit || bWorkArea) 
		{
			Rectangle aSR2(GetMarkedRect());
			Point aD(aPt1-DragStat().GetStart());
		
			if (bDragLimit) 
			{
				Rectangle aR2(GetDragLimitRect());
			
				if (bWorkArea) 
					aLR.Intersection(aR2);
				else 
					aLR=aR2;
			}

			if (aSR2.Left()>aLR.Left() || aSR2.Right()<aLR.Right()) 
			{ // ist ueberhaupt Platz zum verschieben?
				aSR2.Move(aD.X(),0);
			
				if (aSR2.Left()<aLR.Left()) 
				{
					aPt1.X()-=aSR2.Left()-aLR.Left();
				} 
				else if (aSR2.Right()>aLR.Right()) 
				{
					aPt1.X()-=aSR2.Right()-aLR.Right();
				}
			} 
			else 
				aPt1.X()=DragStat().GetStart().X(); // kein Platz zum verschieben

			if (aSR2.Top()>aLR.Top() || aSR2.Bottom()<aLR.Bottom()) 
			{ // ist ueberhaupt Platz zum verschieben?
				aSR2.Move(0,aD.Y());
			
				if (aSR2.Top()<aLR.Top()) 
				{
					aPt1.Y()-=aSR2.Top()-aLR.Top();
				} 
				else if (aSR2.Bottom()>aLR.Bottom()) 
				{
					aPt1.Y()-=aSR2.Bottom()-aLR.Bottom();
				}
			} 
			else 
				aPt1.Y()=DragStat().GetStart().Y(); // kein Platz zum verschieben
		}

		if (getSdrDragView().IsDraggingGluePoints()) 
		{ // Klebepunkte aufs BoundRect des Obj limitieren
			aPt1-=DragStat().GetStart();
			const SdrMarkList& rML=GetMarkedObjectList();
			sal_uLong nMarkAnz=rML.GetMarkCount();
		
			for (sal_uLong nMarkNum=0; nMarkNum<nMarkAnz; nMarkNum++) 
			{
				const SdrMark* pM=rML.GetMark(nMarkNum);
				const SdrUShortCont* pPts=pM->GetMarkedGluePoints();
				sal_uLong nPtAnz=pPts==NULL ? 0 : pPts->GetCount();
			
				if (nPtAnz!=0) 
				{
					const SdrObject* pObj=pM->GetMarkedSdrObj();
					const SdrGluePointList* pGPL=pObj->GetGluePointList();
					Rectangle aBound(pObj->GetCurrentBoundRect());

					for (sal_uLong nPtNum=0; nPtNum<nPtAnz; nPtNum++) 
					{
						sal_uInt16 nId=pPts->GetObject(nPtNum);
						sal_uInt16 nGlueNum=pGPL->FindGluePoint(nId);
					
						if (nGlueNum!=SDRGLUEPOINT_NOTFOUND) 
						{
							Point aPt((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
							aPt+=aPt1; // soviel soll verschoben werden
							if (aPt.X()<aBound.Left()  ) aPt1.X()-=aPt.X()-aBound.Left()  ;
							if (aPt.X()>aBound.Right() ) aPt1.X()-=aPt.X()-aBound.Right() ;
							if (aPt.Y()<aBound.Top()   ) aPt1.Y()-=aPt.Y()-aBound.Top()   ;
							if (aPt.Y()>aBound.Bottom()) aPt1.Y()-=aPt.Y()-aBound.Bottom();
						}
					}
				}
			}

			aPt1+=DragStat().GetStart();
		}

		if (bOrtho) 
			OrthoDistance8(DragStat().GetStart(),aPt1,false);

		if (aPt1!=DragStat().GetNow()) 
		{
			Hide();
			DragStat().NextMove(aPt1);
			Rectangle aAction(GetMarkedRect());
			aAction.Move(DragStat().GetDX(),DragStat().GetDY());
			DragStat().SetActionRect(aAction);
			Show();
		}
	}
}

bool SdrDragMove::EndSdrDrag(bool bCopy)
{
	Hide();

	if (getSdrDragView().IsInsObjPoint() || getSdrDragView().IsInsGluePoint()) 
		bCopy=false;

	if (IsDraggingPoints()) 
	{
		getSdrDragView().MoveMarkedPoints(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
	} 
	else if (IsDraggingGluePoints()) 
	{
		getSdrDragView().MoveMarkedGluePoints(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
	} 
	else 
	{
		getSdrDragView().MoveMarkedObj(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
	}
	
	return true;
}

Pointer SdrDragMove::GetSdrDragPointer() const
{
	if (IsDraggingPoints() || IsDraggingGluePoints()) 
	{
		return Pointer(POINTER_MOVEPOINT);
	} 
	else 
	{
		return Pointer(POINTER_MOVE);
	}
}

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

TYPEINIT1(SdrDragResize,SdrDragMethod);

SdrDragResize::SdrDragResize(SdrDragView& rNewView)
:	SdrDragMethod(rNewView), 
	aXFact(1,1), 
	aYFact(1,1) 
{
}

void SdrDragResize::TakeSdrDragComment(XubString& rStr) const
{
	ImpTakeDescriptionStr(STR_DragMethResize, rStr);
	bool bEqual(aXFact == aYFact);
	Fraction aFact1(1,1);
	Point aStart(DragStat().GetStart());
	Point aRef(DragStat().GetRef1());
	sal_Int32 nXDiv(aStart.X() - aRef.X()); 
	
	if(!nXDiv) 
		nXDiv = 1;

	sal_Int32 nYDiv(aStart.Y() - aRef.Y()); 
	
	if(!nYDiv) 
		nYDiv = 1;

	bool bX(aXFact != aFact1 && Abs(nXDiv) > 1);
	bool bY(aYFact != aFact1 && Abs(nYDiv) > 1);
	
	if(bX || bY) 
	{
		XubString aStr;

		rStr.AppendAscii(" (");
		
		if(bX) 
		{
			if(!bEqual) 
				rStr.AppendAscii("x=");

			getSdrDragView().GetModel()->TakePercentStr(aXFact, aStr);
			rStr += aStr;
		}

		if(bY && !bEqual) 
		{
			if(bX) 
				rStr += sal_Unicode(' ');

			rStr.AppendAscii("y=");
			getSdrDragView().GetModel()->TakePercentStr(aYFact, aStr);
			rStr += aStr;
		}

		rStr += sal_Unicode(')');
	}

	if(getSdrDragView().IsDragWithCopy()) 
		rStr += ImpGetResStr(STR_EditWithCopy);
}

bool SdrDragResize::BeginSdrDrag()
{
	SdrHdlKind eRefHdl=HDL_MOVE;
	SdrHdl* pRefHdl=NULL;

	switch (GetDragHdlKind()) 
	{
		case HDL_UPLFT: eRefHdl=HDL_LWRGT; break;
		case HDL_UPPER: eRefHdl=HDL_LOWER; DragStat().SetHorFixed(true); break;
		case HDL_UPRGT: eRefHdl=HDL_LWLFT; break;
		case HDL_LEFT : eRefHdl=HDL_RIGHT; DragStat().SetVerFixed(true); break;
		case HDL_RIGHT: eRefHdl=HDL_LEFT ; DragStat().SetVerFixed(true); break;
		case HDL_LWLFT: eRefHdl=HDL_UPRGT; break;
		case HDL_LOWER: eRefHdl=HDL_UPPER; DragStat().SetHorFixed(true); break;
		case HDL_LWRGT: eRefHdl=HDL_UPLFT; break;
		default: break;
	}
	
	if (eRefHdl!=HDL_MOVE) 
		pRefHdl=GetHdlList().GetHdl(eRefHdl);

	if (pRefHdl!=NULL && !getSdrDragView().IsResizeAtCenter()) 
	{
		DragStat().Ref1()=pRefHdl->GetPos();
	} 
	else 
	{
		SdrHdl* pRef1=GetHdlList().GetHdl(HDL_UPLFT);
		SdrHdl* pRef2=GetHdlList().GetHdl(HDL_LWRGT);
	
		if (pRef1!=NULL && pRef2!=NULL) 
		{
			DragStat().Ref1()=Rectangle(pRef1->GetPos(),pRef2->GetPos()).Center();
		} 
		else 
		{
			DragStat().Ref1()=GetMarkedRect().Center();
		}
	}

	Show();

	return true;
}

basegfx::B2DHomMatrix SdrDragResize::getCurrentTransformation()
{
    basegfx::B2DHomMatrix aRetval(basegfx::tools::createTranslateB2DHomMatrix(
        -DragStat().Ref1().X(), -DragStat().Ref1().Y()));
	aRetval.scale(aXFact, aYFact);
	aRetval.translate(DragStat().Ref1().X(), DragStat().Ref1().Y());

	return aRetval;
}

void SdrDragResize::MoveSdrDrag(const Point& rNoSnapPnt)
{
	Point aPnt(GetSnapPos(rNoSnapPnt));
	Point aStart(DragStat().GetStart());
	Point aRef(DragStat().GetRef1());
	Fraction aMaxFact(0x7FFFFFFF,1);
	Rectangle aLR(getSdrDragView().GetWorkArea());
	bool bWorkArea=!aLR.IsEmpty();
	bool bDragLimit=IsDragLimit();

	if (bDragLimit || bWorkArea) 
	{
		Rectangle aSR(GetMarkedRect());
	
		if (bDragLimit) 
		{
			Rectangle aR2(GetDragLimitRect());
		
			if (bWorkArea) 
				aLR.Intersection(aR2);
			else 
				aLR=aR2;
		}

		if (aPnt.X()<aLR.Left()) 
			aPnt.X()=aLR.Left();
		else if (aPnt.X()>aLR.Right()) 
			aPnt.X()=aLR.Right();

		if (aPnt.Y()<aLR.Top()) 
			aPnt.Y()=aLR.Top();
		else if (aPnt.Y()>aLR.Bottom()) 
			aPnt.Y()=aLR.Bottom();

		if (aRef.X()>aSR.Left()) 
		{
			Fraction aMax(aRef.X()-aLR.Left(),aRef.X()-aSR.Left());
		
			if (aMax<aMaxFact) 
				aMaxFact=aMax;
		}

		if (aRef.X()<aSR.Right()) 
		{
			Fraction aMax(aLR.Right()-aRef.X(),aSR.Right()-aRef.X());
		
			if (aMax<aMaxFact) 
				aMaxFact=aMax;
		}

		if (aRef.Y()>aSR.Top()) 
		{
			Fraction aMax(aRef.Y()-aLR.Top(),aRef.Y()-aSR.Top());
			
			if (aMax<aMaxFact) 
				aMaxFact=aMax;
		}

		if (aRef.Y()<aSR.Bottom()) 
		{
			Fraction aMax(aLR.Bottom()-aRef.Y(),aSR.Bottom()-aRef.Y());
		
			if (aMax<aMaxFact) 
				aMaxFact=aMax;
		}
	}

	long nXDiv=aStart.X()-aRef.X(); if (nXDiv==0) nXDiv=1;
	long nYDiv=aStart.Y()-aRef.Y(); if (nYDiv==0) nYDiv=1;
	long nXMul=aPnt.X()-aRef.X();
	long nYMul=aPnt.Y()-aRef.Y();

	if (nXDiv<0) 
	{ 
		nXDiv=-nXDiv; 
		nXMul=-nXMul; 
	}

	if (nYDiv<0) 
	{ 
		nYDiv=-nYDiv; 
		nYMul=-nYMul; 
	}

	bool bXNeg=nXMul<0; if (bXNeg) nXMul=-nXMul;
	bool bYNeg=nYMul<0; if (bYNeg) nYMul=-nYMul;
	bool bOrtho=getSdrDragView().IsOrtho() || !getSdrDragView().IsResizeAllowed(false);
	
	if (!DragStat().IsHorFixed() && !DragStat().IsVerFixed()) 
	{
		if (Abs(nXDiv)<=1 || Abs(nYDiv)<=1) 
			bOrtho=false;

		if (bOrtho) 
		{
			if ((Fraction(nXMul,nXDiv)>Fraction(nYMul,nYDiv)) !=getSdrDragView().IsBigOrtho()) 
			{
				nXMul=nYMul;
				nXDiv=nYDiv;
			} 
			else 
			{
				nYMul=nXMul;
				nYDiv=nXDiv;
			}
		}
	} 
	else 
	{
		if (bOrtho) 
		{
			if (DragStat().IsHorFixed()) 
			{ 
				bXNeg=false; 
				nXMul=nYMul; 
				nXDiv=nYDiv; 
			}
			
			if (DragStat().IsVerFixed()) 
			{ 
				bYNeg=false; 
				nYMul=nXMul; 
				nYDiv=nXDiv; 
			}
		} 
		else 
		{
			if (DragStat().IsHorFixed()) 
			{ 
				bXNeg=false; 
				nXMul=1; 
				nXDiv=1; 
			}
			
			if (DragStat().IsVerFixed()) 
			{ 
				bYNeg=false; 
				nYMul=1; 
				nYDiv=1; 
			}
		}
	}

	Fraction aNeuXFact(nXMul,nXDiv);
	Fraction aNeuYFact(nYMul,nYDiv);

	if (bOrtho) 
	{
		if (aNeuXFact>aMaxFact) 
		{
			aNeuXFact=aMaxFact;
			aNeuYFact=aMaxFact;
		}
		
		if (aNeuYFact>aMaxFact) 
		{
			aNeuXFact=aMaxFact;
			aNeuYFact=aMaxFact;
		}
	}

	if (bXNeg) 
		aNeuXFact=Fraction(-aNeuXFact.GetNumerator(),aNeuXFact.GetDenominator());

	if (bYNeg) 
		aNeuYFact=Fraction(-aNeuYFact.GetNumerator(),aNeuYFact.GetDenominator());

	if (DragStat().CheckMinMoved(aPnt)) 
	{
		if ((!DragStat().IsHorFixed() && aPnt.X()!=DragStat().GetNow().X()) ||
			(!DragStat().IsVerFixed() && aPnt.Y()!=DragStat().GetNow().Y())) 
		{
			Hide();
			DragStat().NextMove(aPnt);
			aXFact=aNeuXFact;
			aYFact=aNeuYFact;
			Show();
		}
	}
}

void SdrDragResize::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
    rTarget.Resize(DragStat().Ref1(),aXFact,aYFact);
}

bool SdrDragResize::EndSdrDrag(bool bCopy)
{
	Hide();

	if (IsDraggingPoints()) 
	{
		getSdrDragView().ResizeMarkedPoints(DragStat().Ref1(),aXFact,aYFact,bCopy);
	} 
	else if (IsDraggingGluePoints()) 
	{
		getSdrDragView().ResizeMarkedGluePoints(DragStat().Ref1(),aXFact,aYFact,bCopy);
	} 
	else 
	{
		getSdrDragView().ResizeMarkedObj(DragStat().Ref1(),aXFact,aYFact,bCopy);
	}

	return true;
}

Pointer SdrDragResize::GetSdrDragPointer() const
{
	const SdrHdl* pHdl=GetDragHdl();

	if (pHdl!=NULL) 
	{
		return pHdl->GetPointer();
	}
	
	return Pointer(POINTER_MOVE);
}

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

TYPEINIT1(SdrDragRotate,SdrDragMethod);

void SdrDragRotate::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
	rTarget.Rotate(DragStat().GetRef1(), nWink, sin(nWink*nPi180), cos(nWink*nPi180));
}

SdrDragRotate::SdrDragRotate(SdrDragView& rNewView)
:	SdrDragMethod(rNewView),
	nSin(0.0),
	nCos(1.0),
	nWink0(0),
	nWink(0),
	bRight(false) 
{
}

void SdrDragRotate::TakeSdrDragComment(XubString& rStr) const
{
	ImpTakeDescriptionStr(STR_DragMethRotate, rStr);
	rStr.AppendAscii(" (");
	XubString aStr;
	sal_Int32 nTmpWink(NormAngle360(nWink));
	
	if(bRight && nWink) 
	{
		nTmpWink -= 36000;
	}

	getSdrDragView().GetModel()->TakeWinkStr(nTmpWink, aStr);
	rStr += aStr;
	rStr += sal_Unicode(')');

	if(getSdrDragView().IsDragWithCopy()) 
		rStr += ImpGetResStr(STR_EditWithCopy);
}

bool SdrDragRotate::BeginSdrDrag()
{
	SdrHdl* pH=GetHdlList().GetHdl(HDL_REF1);

	if (pH!=NULL) 
	{
		Show();
		DragStat().Ref1()=pH->GetPos();
		nWink0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
		return true;
	} 
	else 
	{
		DBG_ERROR("SdrDragRotate::BeginSdrDrag(): Kein Referenzpunkt-Handle gefunden");
		return false;
	}
}

basegfx::B2DHomMatrix SdrDragRotate::getCurrentTransformation()
{
    return basegfx::tools::createRotateAroundPoint(
        DragStat().GetRef1().X(), DragStat().GetRef1().Y(),
        -atan2(nSin, nCos));
}

void SdrDragRotate::MoveSdrDrag(const Point& rPnt_)
{
	Point aPnt(rPnt_);
	if (DragStat().CheckMinMoved(aPnt)) 
	{
		long nNeuWink=NormAngle360(GetAngle(aPnt-DragStat().GetRef1())-nWink0);
		long nSA=0;
	
		if (getSdrDragView().IsAngleSnapEnabled()) 
			nSA=getSdrDragView().GetSnapAngle();

		if (!getSdrDragView().IsRotateAllowed(false)) 
			nSA=9000;

		if (nSA!=0) 
		{ // Winkelfang
			nNeuWink+=nSA/2;
			nNeuWink/=nSA;
			nNeuWink*=nSA;
		}
		
		nNeuWink=NormAngle180(nNeuWink);
		
		if (nWink!=nNeuWink) 
		{
			sal_uInt16 nSekt0=GetAngleSector(nWink);
			sal_uInt16 nSekt1=GetAngleSector(nNeuWink);
		
			if (nSekt0==0 && nSekt1==3) 
				bRight=true;

			if (nSekt0==3 && nSekt1==0) 
				bRight=false;

			nWink=nNeuWink;
			double a=nWink*nPi180;
			double nSin1=sin(a); // schonmal berechnen, damit mgl. wenig Zeit
			double nCos1=cos(a); // zwischen Hide() und Show() vergeht
			Hide();
			nSin=nSin1;
			nCos=nCos1;
			DragStat().NextMove(aPnt);
			Show();
		}
	}
}

bool SdrDragRotate::EndSdrDrag(bool bCopy)
{
	Hide();

	if (nWink!=0) 
	{
		if (IsDraggingPoints()) 
		{
			getSdrDragView().RotateMarkedPoints(DragStat().GetRef1(),nWink,bCopy);
		} 
		else if (IsDraggingGluePoints()) 
		{
			getSdrDragView().RotateMarkedGluePoints(DragStat().GetRef1(),nWink,bCopy);
		} 
		else 
		{
			getSdrDragView().RotateMarkedObj(DragStat().GetRef1(),nWink,bCopy);
		}
	}
	return true;
}

Pointer SdrDragRotate::GetSdrDragPointer() const
{
	return Pointer(POINTER_ROTATE);
}

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

TYPEINIT1(SdrDragShear,SdrDragMethod);

SdrDragShear::SdrDragShear(SdrDragView& rNewView, bool bSlant1)
:	SdrDragMethod(rNewView),
	aFact(1,1),
	nWink0(0),
	nWink(0),
	nTan(0.0),
	bVertical(false),
	bResize(false),
	bUpSideDown(false),
	bSlant(bSlant1) 
{
}

void SdrDragShear::TakeSdrDragComment(XubString& rStr) const
{
	ImpTakeDescriptionStr(STR_DragMethShear, rStr);
	rStr.AppendAscii(" (");
	
	sal_Int32 nTmpWink(nWink);
	
	if(bUpSideDown) 
		nTmpWink += 18000;

	nTmpWink = NormAngle180(nTmpWink);

	XubString aStr;
	
	getSdrDragView().GetModel()->TakeWinkStr(nTmpWink, aStr);
	rStr += aStr;
	rStr += sal_Unicode(')');
	
	if(getSdrDragView().IsDragWithCopy()) 
		rStr += ImpGetResStr(STR_EditWithCopy);
}

bool SdrDragShear::BeginSdrDrag()
{
	SdrHdlKind eRefHdl=HDL_MOVE;
	SdrHdl* pRefHdl=NULL;

	switch (GetDragHdlKind()) 
	{
		case HDL_UPPER: eRefHdl=HDL_LOWER; break;
		case HDL_LOWER: eRefHdl=HDL_UPPER; break;
		case HDL_LEFT : eRefHdl=HDL_RIGHT; bVertical=true; break;
		case HDL_RIGHT: eRefHdl=HDL_LEFT ; bVertical=true; break;
		default: break;
	}
	
	if (eRefHdl!=HDL_MOVE) 
		pRefHdl=GetHdlList().GetHdl(eRefHdl);

	if (pRefHdl!=NULL) 
	{
		DragStat().Ref1()=pRefHdl->GetPos();
		nWink0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
	} 
	else 
	{
		DBG_ERROR("SdrDragShear::BeginSdrDrag(): Kein Referenzpunkt-Handle fuer Shear gefunden");
		return false;
	}
	
	Show();
	return true;
}

basegfx::B2DHomMatrix SdrDragShear::getCurrentTransformation()
{
    basegfx::B2DHomMatrix aRetval(basegfx::tools::createTranslateB2DHomMatrix(
        -DragStat().GetRef1().X(), -DragStat().GetRef1().Y()));

	if (bResize) 
	{
		if (bVertical) 
		{
			aRetval.scale(aFact, 1.0);
			aRetval.shearY(-nTan);
		} 
		else 
		{
			aRetval.scale(1.0, aFact);
			aRetval.shearX(-nTan);
		}
	}

	aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());

	return aRetval;
}

void SdrDragShear::MoveSdrDrag(const Point& rPnt)
{
	if (DragStat().CheckMinMoved(rPnt)) 
	{
		bResize=!getSdrDragView().IsOrtho();
		long nSA=0;
	
		if (getSdrDragView().IsAngleSnapEnabled()) 
			nSA=getSdrDragView().GetSnapAngle();

		Point aP0(DragStat().GetStart());
		Point aPnt(rPnt);
		Fraction aNeuFact(1,1);
		
		// Wenn kein Winkelfang, dann ggf. Rasterfang (ausser bei Slant)
		if (nSA==0 && !bSlant) 
			aPnt=GetSnapPos(aPnt);

		if (!bSlant && !bResize) 
		{ // Shear ohne Resize
			if (bVertical) 
				aPnt.X()=aP0.X(); 
			else 
				aPnt.Y()=aP0.Y();
		}

		Point aRef(DragStat().GetRef1());
		Point aDif(aPnt-aRef);

		long nNeuWink=0;

		if (bSlant) 
		{
			nNeuWink=NormAngle180(-(GetAngle(aDif)-nWink0));

			if (bVertical) 
				nNeuWink=NormAngle180(-nNeuWink);
		} 
		else 
		{
			if (bVertical) 
				nNeuWink=NormAngle180(GetAngle(aDif));
			else 
				nNeuWink=NormAngle180(-(GetAngle(aDif)-9000));

			if (nNeuWink<-9000 || nNeuWink>9000) 
				nNeuWink=NormAngle180(nNeuWink+18000);

			if (bResize) 
			{
				Point aPt2(aPnt);
			
				if (nSA!=0) 
					aPt2=GetSnapPos(aPnt); // den also in jedem Falle fangen

				if (bVertical) 
				{
					aNeuFact=Fraction(aPt2.X()-aRef.X(),aP0.X()-aRef.X());
				} 
				else 
				{
					aNeuFact=Fraction(aPt2.Y()-aRef.Y(),aP0.Y()-aRef.Y());
				}
			}
		}

		bool bNeg=nNeuWink<0;

		if (bNeg) 
			nNeuWink=-nNeuWink;

		if (nSA!=0) 
		{ // Winkelfang
			nNeuWink+=nSA/2;
			nNeuWink/=nSA;
			nNeuWink*=nSA;
		}

		nNeuWink=NormAngle360(nNeuWink);
		bUpSideDown=nNeuWink>9000 && nNeuWink<27000;

		if (bSlant) 
		{ // Resize fuer Slant berechnen
			// Mit Winkelfang jedoch ohne 89deg Begrenzung
			long nTmpWink=nNeuWink;
			if (bUpSideDown) nNeuWink-=18000;
			if (bNeg) nTmpWink=-nTmpWink;
			bResize=true;
			double nCos=cos(nTmpWink*nPi180);
			aNeuFact=nCos;
			Kuerzen(aFact,10); // 3 Dezimalstellen sollten reichen
		}

		if (nNeuWink>8900) 
			nNeuWink=8900;

		if (bNeg) 
			nNeuWink=-nNeuWink;

		if (nWink!=nNeuWink || aFact!=aNeuFact) 
		{
			nWink=nNeuWink;
			aFact=aNeuFact;
			double a=nWink*nPi180;
			double nTan1=0.0;
			nTan1=tan(a); // schonmal berechnen, damit mgl. wenig Zeit zwischen Hide() und Show() vergeht
			Hide();
			nTan=nTan1;
			DragStat().NextMove(rPnt);
			Show();
		}
	}
}

void SdrDragShear::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
	if (bResize) 
	{
		if (bVertical) 
		{
            rTarget.Resize(DragStat().GetRef1(),aFact,Fraction(1,1));
		} 
		else 
		{
            rTarget.Resize(DragStat().GetRef1(),Fraction(1,1),aFact);
		}
	}

	if (nWink!=0) 
	{
		rTarget.Shear(DragStat().GetRef1(),nWink,tan(nWink*nPi180),bVertical);
	}
}

bool SdrDragShear::EndSdrDrag(bool bCopy)
{
	Hide();

	if (bResize && aFact==Fraction(1,1)) 
		bResize=false;
	
	if (nWink!=0 || bResize) 
	{
		if (nWink!=0 && bResize) 
		{
			XubString aStr;
			ImpTakeDescriptionStr(STR_EditShear,aStr);
		
			if (bCopy) 
				aStr+=ImpGetResStr(STR_EditWithCopy);

			getSdrDragView().BegUndo(aStr);
		}

		if (bResize) 
		{
			if (bVertical) 
			{
				getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),aFact,Fraction(1,1),bCopy);
			} 
			else 
			{
				getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),Fraction(1,1),aFact,bCopy);
			}
			
			bCopy=false;
		}

		if (nWink!=0) 
		{
			getSdrDragView().ShearMarkedObj(DragStat().GetRef1(),nWink,bVertical,bCopy);
		}

		if (nWink!=0 && bResize) 
			getSdrDragView().EndUndo();

		return true;
	}

	return false;
}

Pointer SdrDragShear::GetSdrDragPointer() const
{
	if (bVertical) 
		return Pointer(POINTER_VSHEAR);
	else 
		return Pointer(POINTER_HSHEAR);
}

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

TYPEINIT1(SdrDragMirror,SdrDragMethod);

void SdrDragMirror::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
	if(bMirrored) 
	{
        rTarget.Mirror(DragStat().GetRef1(), DragStat().GetRef2());
	}
}

SdrDragMirror::SdrDragMirror(SdrDragView& rNewView)
:	SdrDragMethod(rNewView),
	nWink(0),
	bMirrored(false),
	bSide0(false) 
{
}

bool SdrDragMirror::ImpCheckSide(const Point& rPnt) const
{
	long nWink1=GetAngle(rPnt-DragStat().GetRef1());
	nWink1-=nWink;
	nWink1=NormAngle360(nWink1);

	return nWink1<18000;
}

void SdrDragMirror::TakeSdrDragComment(XubString& rStr) const
{
	if (aDif.X()==0) 
		ImpTakeDescriptionStr(STR_DragMethMirrorHori,rStr);
	else if (aDif.Y()==0) 
		ImpTakeDescriptionStr(STR_DragMethMirrorVert,rStr);
	else if (Abs(aDif.X())==Abs(aDif.Y())) 
		ImpTakeDescriptionStr(STR_DragMethMirrorDiag,rStr);
	else 
		ImpTakeDescriptionStr(STR_DragMethMirrorFree,rStr);
	
	if (getSdrDragView().IsDragWithCopy()) 
		rStr+=ImpGetResStr(STR_EditWithCopy);
}

bool SdrDragMirror::BeginSdrDrag()
{
	SdrHdl* pH1=GetHdlList().GetHdl(HDL_REF1);
	SdrHdl* pH2=GetHdlList().GetHdl(HDL_REF2);

	if (pH1!=NULL && pH2!=NULL) 
	{
		DragStat().Ref1()=pH1->GetPos();
		DragStat().Ref2()=pH2->GetPos();
		Ref1()=pH1->GetPos();
		Ref2()=pH2->GetPos();
		aDif=pH2->GetPos()-pH1->GetPos();
		bool b90=(aDif.X()==0) || aDif.Y()==0;
		bool b45=b90 || (Abs(aDif.X())==Abs(aDif.Y()));
		nWink=NormAngle360(GetAngle(aDif));
	
		if (!getSdrDragView().IsMirrorAllowed(false,false) && !b45) 
			return false; // freier Achsenwinkel nicht erlaubt

		if (!getSdrDragView().IsMirrorAllowed(true,false) && !b90) 
			return false;  // 45deg auch nicht erlaubt

		bSide0=ImpCheckSide(DragStat().GetStart());
		Show();
		return true;
	} 
	else 
	{
		DBG_ERROR("SdrDragMirror::BeginSdrDrag(): Spiegelachse nicht gefunden");
		return false;
	}
}

basegfx::B2DHomMatrix SdrDragMirror::getCurrentTransformation()
{
	basegfx::B2DHomMatrix aRetval;

    if (bMirrored) 
	{
	    const double fDeltaX(DragStat().GetRef2().X() - DragStat().GetRef1().X());
	    const double fDeltaY(DragStat().GetRef2().Y() - DragStat().GetRef1().Y());
	    const double fRotation(atan2(fDeltaY, fDeltaX));

        aRetval = basegfx::tools::createTranslateB2DHomMatrix(-DragStat().GetRef1().X(), -DragStat().GetRef1().Y());
	    aRetval.rotate(-fRotation);
	    aRetval.scale(1.0, -1.0);
	    aRetval.rotate(fRotation);
	    aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
    }

	return aRetval;
}

void SdrDragMirror::MoveSdrDrag(const Point& rPnt)
{
	if (DragStat().CheckMinMoved(rPnt)) 
	{
		bool bNeuSide=ImpCheckSide(rPnt);
		bool bNeuMirr=bSide0!=bNeuSide;
	
		if (bMirrored!=bNeuMirr) 
		{
			Hide();
			bMirrored=bNeuMirr;
			DragStat().NextMove(rPnt);
			Show();
		}
	}
}

bool SdrDragMirror::EndSdrDrag(bool bCopy)
{
	Hide();

	if (bMirrored) 
	{
		getSdrDragView().MirrorMarkedObj(DragStat().GetRef1(),DragStat().GetRef2(),bCopy);
	}
	
	return true;
}

Pointer SdrDragMirror::GetSdrDragPointer() const
{
	return Pointer(POINTER_MIRROR);
}

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

TYPEINIT1(SdrDragGradient, SdrDragMethod);

SdrDragGradient::SdrDragGradient(SdrDragView& rNewView, bool bGrad)
:	SdrDragMethod(rNewView),
	pIAOHandle(NULL),
	bIsGradient(bGrad)
{
}

void SdrDragGradient::TakeSdrDragComment(XubString& rStr) const
{
	if(IsGradient())
		ImpTakeDescriptionStr(STR_DragMethGradient, rStr);
	else
		ImpTakeDescriptionStr(STR_DragMethTransparence, rStr);
}

bool SdrDragGradient::BeginSdrDrag()
{
	bool bRetval(false);

	pIAOHandle = (SdrHdlGradient*)GetHdlList().GetHdl(IsGradient() ? HDL_GRAD : HDL_TRNS);
	
	if(pIAOHandle) 
	{
		// save old values
		DragStat().Ref1() = pIAOHandle->GetPos();
		DragStat().Ref2() = pIAOHandle->Get2ndPos();

		// what was hit?
		bool bHit(false);
		SdrHdlColor* pColHdl = pIAOHandle->GetColorHdl1();
		
		// init handling flags
		pIAOHandle->SetMoveSingleHandle(false);
		pIAOHandle->SetMoveFirstHandle(false);

		// test first color handle
		if(pColHdl)
		{
			basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());

			if(pColHdl->getOverlayObjectList().isHitLogic(aPosition))
			{
				bHit = true;
				pIAOHandle->SetMoveSingleHandle(true);
				pIAOHandle->SetMoveFirstHandle(true);
			}
		}

		// test second color handle
		pColHdl = pIAOHandle->GetColorHdl2();
	
		if(!bHit && pColHdl)
		{
			basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());

			if(pColHdl->getOverlayObjectList().isHitLogic(aPosition))
			{
				bHit = true;
				pIAOHandle->SetMoveSingleHandle(true);
			}
		}

		// test gradient handle itself
		if(!bHit)
		{
			basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());

			if(pIAOHandle->getOverlayObjectList().isHitLogic(aPosition))
			{
				bHit = true;
			}
		}

		// everything up and running :o}
		bRetval = bHit;
	} 
	else 
	{
		DBG_ERROR("SdrDragGradient::BeginSdrDrag(): IAOGradient nicht gefunden");
	}

	return bRetval;
}

void SdrDragGradient::MoveSdrDrag(const Point& rPnt)
{
	if(pIAOHandle && DragStat().CheckMinMoved(rPnt)) 
	{
		DragStat().NextMove(rPnt);
		
		// Do the Move here!!! DragStat().GetStart()
		Point aMoveDiff = rPnt - DragStat().GetStart();

		if(pIAOHandle->IsMoveSingleHandle())
		{
			if(pIAOHandle->IsMoveFirstHandle())
			{
				pIAOHandle->SetPos(DragStat().Ref1() + aMoveDiff);
				if(pIAOHandle->GetColorHdl1())
					pIAOHandle->GetColorHdl1()->SetPos(DragStat().Ref1() + aMoveDiff);
			}
			else
			{
				pIAOHandle->Set2ndPos(DragStat().Ref2() + aMoveDiff);
				if(pIAOHandle->GetColorHdl2())
					pIAOHandle->GetColorHdl2()->SetPos(DragStat().Ref2() + aMoveDiff);
			}
		}
		else
		{
			pIAOHandle->SetPos(DragStat().Ref1() + aMoveDiff);
			pIAOHandle->Set2ndPos(DragStat().Ref2() + aMoveDiff);
			
			if(pIAOHandle->GetColorHdl1())
				pIAOHandle->GetColorHdl1()->SetPos(DragStat().Ref1() + aMoveDiff);
			
			if(pIAOHandle->GetColorHdl2())
				pIAOHandle->GetColorHdl2()->SetPos(DragStat().Ref2() + aMoveDiff);
		}
		
		// new state
		pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), false, false);
	}
}

bool SdrDragGradient::EndSdrDrag(bool /*bCopy*/)
{
	// here the result is clear, do something with the values
	Ref1() = pIAOHandle->GetPos();
	Ref2() = pIAOHandle->Get2ndPos();

	// new state
	pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), true, true);

	return true;
}

void SdrDragGradient::CancelSdrDrag()
{
	// restore old values
	pIAOHandle->SetPos(DragStat().Ref1());
	pIAOHandle->Set2ndPos(DragStat().Ref2());

	if(pIAOHandle->GetColorHdl1())
		pIAOHandle->GetColorHdl1()->SetPos(DragStat().Ref1());

	if(pIAOHandle->GetColorHdl2())
		pIAOHandle->GetColorHdl2()->SetPos(DragStat().Ref2());

	// new state
	pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), true, false);
}

Pointer SdrDragGradient::GetSdrDragPointer() const
{
	return Pointer(POINTER_REFHAND);
}

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

TYPEINIT1(SdrDragCrook,SdrDragMethod);

SdrDragCrook::SdrDragCrook(SdrDragView& rNewView)
:	SdrDragMethod(rNewView),
	aFact(1,1),
	bContortionAllowed(false),
	bNoContortionAllowed(false),
	bContortion(false),
	bResizeAllowed(false),
	bResize(false),
	bRotateAllowed(false),
	bRotate(false),
	bVertical(false),
	bValid(false),
	bLft(false),
	bRgt(false),
	bUpr(false),
	bLwr(false),
	bAtCenter(false),
	nWink(0),
	nMarkSize(0),
	eMode(SDRCROOK_ROTATE) 
{
}

void SdrDragCrook::TakeSdrDragComment(XubString& rStr) const
{
	ImpTakeDescriptionStr(!bContortion ? STR_DragMethCrook : STR_DragMethCrookContortion, rStr);

	if(bValid) 
	{
		rStr.AppendAscii(" (");
		
		XubString aStr;
		sal_Int32 nVal(nWink);
		
		if(bAtCenter) 
			nVal *= 2;

		nVal = Abs(nVal);
		getSdrDragView().GetModel()->TakeWinkStr(nVal, aStr);
		rStr += aStr;
		rStr += sal_Unicode(')');
	}

	if(getSdrDragView().IsDragWithCopy()) 
		rStr += ImpGetResStr(STR_EditWithCopy);
}

// #96920# These defines parametrise the created raster
// for interactions
#define DRAG_CROOK_RASTER_MINIMUM	(4)
#define DRAG_CROOK_RASTER_MAXIMUM	(15)
#define DRAG_CROOK_RASTER_DISTANCE	(30)

basegfx::B2DPolyPolygon impCreateDragRaster(SdrPageView& rPageView, const Rectangle& rMarkRect)
{
    basegfx::B2DPolyPolygon aRetval;

	if(rPageView.PageWindowCount())
	{
		OutputDevice& rOut = (rPageView.GetPageWindow(0)->GetPaintWindow().GetOutputDevice());
		Rectangle aPixelSize = rOut.LogicToPixel(rMarkRect);
		sal_uInt32 nHorDiv(aPixelSize.GetWidth() / DRAG_CROOK_RASTER_DISTANCE);
		sal_uInt32 nVerDiv(aPixelSize.GetHeight() / DRAG_CROOK_RASTER_DISTANCE);

		if(nHorDiv > DRAG_CROOK_RASTER_MAXIMUM)
			nHorDiv = DRAG_CROOK_RASTER_MAXIMUM;
		if(nHorDiv < DRAG_CROOK_RASTER_MINIMUM)
			nHorDiv = DRAG_CROOK_RASTER_MINIMUM;

		if(nVerDiv > DRAG_CROOK_RASTER_MAXIMUM)
			nVerDiv = DRAG_CROOK_RASTER_MAXIMUM;
		if(nVerDiv < DRAG_CROOK_RASTER_MINIMUM)
			nVerDiv = DRAG_CROOK_RASTER_MINIMUM;

	    const double fXLen(rMarkRect.GetWidth() / (double)nHorDiv);
	    const double fYLen(rMarkRect.GetHeight() / (double)nVerDiv);
	    double fYPos(rMarkRect.Top());
	    sal_uInt32 a, b;

	    for(a = 0; a <= nVerDiv; a++)
	    {
		    // hor lines
		    for(b = 0; b < nHorDiv; b++)
		    {
			    basegfx::B2DPolygon aHorLineSegment;

			    const double fNewX(rMarkRect.Left() + (b * fXLen));
			    aHorLineSegment.append(basegfx::B2DPoint(fNewX, fYPos));
			    aHorLineSegment.appendBezierSegment(
				    basegfx::B2DPoint(fNewX + (fXLen * (1.0 / 3.0)), fYPos),
				    basegfx::B2DPoint(fNewX + (fXLen * (2.0 / 3.0)), fYPos),
				    basegfx::B2DPoint(fNewX + fXLen, fYPos));
			    aRetval.append(aHorLineSegment);
		    }

		    // increments
		    fYPos += fYLen;
	    }

	    double fXPos(rMarkRect.Left());

	    for(a = 0; a <= nHorDiv; a++)
	    {
		    // ver lines
		    for(b = 0; b < nVerDiv; b++)
		    {
			    basegfx::B2DPolygon aVerLineSegment;

			    const double fNewY(rMarkRect.Top() + (b * fYLen));
			    aVerLineSegment.append(basegfx::B2DPoint(fXPos, fNewY));
			    aVerLineSegment.appendBezierSegment(
				    basegfx::B2DPoint(fXPos, fNewY + (fYLen * (1.0 / 3.0))),
				    basegfx::B2DPoint(fXPos, fNewY + (fYLen * (2.0 / 3.0))),
				    basegfx::B2DPoint(fXPos, fNewY + fYLen));
			    aRetval.append(aVerLineSegment);
		    }

		    // increments
		    fXPos += fXLen;
	    }
    }

    return aRetval;
}

void SdrDragCrook::createSdrDragEntries()
{
	// Add extended frame raster first, so it will be behind objects
    if(getSdrDragView().GetSdrPageView())
    {
        const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect()));

        if(aDragRaster.count())
        {
            addSdrDragEntry(new SdrDragEntryPolyPolygon(aDragRaster));
        }
    }

    // call parent
    SdrDragMethod::createSdrDragEntries();
}

bool SdrDragCrook::BeginSdrDrag()
{
	bContortionAllowed=getSdrDragView().IsCrookAllowed(false);
	bNoContortionAllowed=getSdrDragView().IsCrookAllowed(true);
	bResizeAllowed=getSdrDragView().IsResizeAllowed(false);
	bRotateAllowed=getSdrDragView().IsRotateAllowed(false);

	if (bContortionAllowed || bNoContortionAllowed) 
	{
		bVertical=(GetDragHdlKind()==HDL_LOWER || GetDragHdlKind()==HDL_UPPER);
		aMarkRect=GetMarkedRect();
		aMarkCenter=aMarkRect.Center();
		nMarkSize=bVertical ? (aMarkRect.GetHeight()-1) : (aMarkRect.GetWidth()-1);
		aCenter=aMarkCenter;
		aStart=DragStat().GetStart();
		Show();
		return true;
	} 
	else 
	{
		return false;
	}
}

void SdrDragCrook::_MovAllPoints(basegfx::B2DPolyPolygon& rTarget)
{
	SdrPageView* pPV = getSdrDragView().GetSdrPageView();

	if(pPV)
	{
		XPolyPolygon aTempPolyPoly(rTarget);

		if (pPV->HasMarkedObjPageView()) 
		{
			sal_uInt16 nPolyAnz=aTempPolyPoly.Count();

			if (!bContortion && !getSdrDragView().IsNoDragXorPolys()) 
			{
				sal_uInt16 n1st=0,nLast=0;
				Point aC(aCenter);
			
				while (n1st<nPolyAnz) 
				{
					nLast=n1st;
					while (nLast<nPolyAnz && aTempPolyPoly[nLast].GetPointCount()!=0) nLast++;
					Rectangle aBound(aTempPolyPoly[n1st].GetBoundRect());
					sal_uInt16 i;
				
					for (i=n1st+1; i<nLast; i++) 
					{
						aBound.Union(aTempPolyPoly[n1st].GetBoundRect());
					}
					
					Point aCtr0(aBound.Center());
					Point aCtr1(aCtr0);
					
					if (bResize) 
					{
						Fraction aFact1(1,1);
					
						if (bVertical) 
						{
							ResizePoint(aCtr1,aC,aFact1,aFact);
						} 
						else 
						{
							ResizePoint(aCtr1,aC,aFact,aFact1);
						}
					}

					bool bRotOk=false;
					double nSin=0,nCos=0;

					if (aRad.X()!=0 && aRad.Y()!=0) 
					{
						bRotOk=bRotate;

						switch (eMode) 
						{
							case SDRCROOK_ROTATE : CrookRotateXPoint (aCtr1,NULL,NULL,aC,aRad,nSin,nCos,bVertical);           break;
							case SDRCROOK_SLANT  : CrookSlantXPoint  (aCtr1,NULL,NULL,aC,aRad,nSin,nCos,bVertical);           break;
							case SDRCROOK_STRETCH: CrookStretchXPoint(aCtr1,NULL,NULL,aC,aRad,nSin,nCos,bVertical,aMarkRect); break;
						} // switch
					}

					aCtr1-=aCtr0;

					for (i=n1st; i<nLast; i++) 
					{
						if (bRotOk) 
						{
							RotateXPoly(aTempPolyPoly[i],aCtr0,nSin,nCos);
						}
						
						aTempPolyPoly[i].Move(aCtr1.X(),aCtr1.Y());
					}

					n1st=nLast+1;
				}
			} 
			else 
			{
				sal_uInt16 i,j;
			
				for (j=0; j<nPolyAnz; j++) 
				{
					XPolygon& aPol=aTempPolyPoly[j];
					sal_uInt16 nPtAnz=aPol.GetPointCount();
					i=0;
				
					while (i<nPtAnz) 
					{
						Point* pPnt=&aPol[i];
						Point* pC1=NULL;
						Point* pC2=NULL;
					
						if (i+1<nPtAnz && aPol.IsControl(i)) 
						{ // Kontrollpunkt links
							pC1=pPnt;
							i++;
							pPnt=&aPol[i];
						}
						
						i++;
						
						if (i<nPtAnz && aPol.IsControl(i)) 
						{ // Kontrollpunkt rechts
							pC2=&aPol[i];
							i++;
						}
						
						_MovCrookPoint(*pPnt,pC1,pC2);
					}
				}
			}
		}

		rTarget = aTempPolyPoly.getB2DPolyPolygon();
	}
}

void SdrDragCrook::_MovCrookPoint(Point& rPnt, Point* pC1, Point* pC2)
{
	bool bVert=bVertical;
	bool bC1=pC1!=NULL;
	bool bC2=pC2!=NULL;
	Point aC(aCenter);

	if (bResize) 
	{
		Fraction aFact1(1,1);
	
		if (bVert) 
		{
			ResizePoint(rPnt,aC,aFact1,aFact);
		
			if (bC1) 
				ResizePoint(*pC1,aC,aFact1,aFact);

			if (bC2) 
				ResizePoint(*pC2,aC,aFact1,aFact);
		} 
		else 
		{
			ResizePoint(rPnt,aC,aFact,aFact1);
		
			if (bC1) 
				ResizePoint(*pC1,aC,aFact,aFact1);

			if (bC2) 
				ResizePoint(*pC2,aC,aFact,aFact1);
		}
	}

	if (aRad.X()!=0 && aRad.Y()!=0) 
	{
		double nSin,nCos;
	
		switch (eMode) 
		{
			case SDRCROOK_ROTATE : CrookRotateXPoint (rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert);           break;
			case SDRCROOK_SLANT  : CrookSlantXPoint  (rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert);           break;
			case SDRCROOK_STRETCH: CrookStretchXPoint(rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert,aMarkRect); break;
		} // switch
	}
}

void SdrDragCrook::MoveSdrDrag(const Point& rPnt)
{
	if (DragStat().CheckMinMoved(rPnt)) 
	{
		Point aPnt(rPnt);
		bool bNeuMoveOnly=getSdrDragView().IsMoveOnlyDragging();
		bAtCenter=false;
		SdrCrookMode eNeuMode=getSdrDragView().GetCrookMode();
		bool bNeuContortion=!bNeuMoveOnly && ((bContortionAllowed && !getSdrDragView().IsCrookNoContortion()) || !bNoContortionAllowed);
		bResize=!getSdrDragView().IsOrtho() && bResizeAllowed && !bNeuMoveOnly;
		bool bNeuRotate=bRotateAllowed && !bNeuContortion && !bNeuMoveOnly && eNeuMode==SDRCROOK_ROTATE;
		long nSA=0;

		if (nSA==0) 
			aPnt=GetSnapPos(aPnt);

		Point aNeuCenter(aMarkCenter.X(),aStart.Y());
	
		if (bVertical) 
		{ 
			aNeuCenter.X()=aStart.X(); 
			aNeuCenter.Y()=aMarkCenter.Y(); 
		}
		
		if (!getSdrDragView().IsCrookAtCenter()) 
		{
			switch (GetDragHdlKind()) 
			{
				case HDL_UPLFT: aNeuCenter.X()=aMarkRect.Right();  bLft=true; break;
				case HDL_UPPER: aNeuCenter.Y()=aMarkRect.Bottom(); bUpr=true; break;
				case HDL_UPRGT: aNeuCenter.X()=aMarkRect.Left();   bRgt=true; break;
				case HDL_LEFT : aNeuCenter.X()=aMarkRect.Right();  bLft=true; break;
				case HDL_RIGHT: aNeuCenter.X()=aMarkRect.Left();   bRgt=true; break;
				case HDL_LWLFT: aNeuCenter.X()=aMarkRect.Right();  bLft=true; break;
				case HDL_LOWER: aNeuCenter.Y()=aMarkRect.Top();    bLwr=true; break;
				case HDL_LWRGT: aNeuCenter.X()=aMarkRect.Left();   bRgt=true; break;
				default: bAtCenter=true;
			}
		} 
		else 
			bAtCenter=true;

		Fraction aNeuFact(1,1);
		long dx1=aPnt.X()-aNeuCenter.X();
		long dy1=aPnt.Y()-aNeuCenter.Y();
		bValid=bVertical ? dx1!=0 : dy1!=0;
		
		if (bValid) 
		{
			if (bVertical) 
				bValid=Abs(dx1)*100>Abs(dy1);
			else 
				bValid=Abs(dy1)*100>Abs(dx1);
		}

		long nNeuRad=0;
		nWink=0;

		if (bValid) 
		{
			double a=0; // Steigung des Radius
			long nPntWink=0;
		
			if (bVertical) 
			{
				a=((double)dy1)/((double)dx1); // Steigung des Radius
				nNeuRad=((long)(dy1*a)+dx1) /2;
				aNeuCenter.X()+=nNeuRad;
				nPntWink=GetAngle(aPnt-aNeuCenter);
			} 
			else 
			{
				a=((double)dx1)/((double)dy1); // Steigung des Radius
				nNeuRad=((long)(dx1*a)+dy1) /2;
				aNeuCenter.Y()+=nNeuRad;
				nPntWink=GetAngle(aPnt-aNeuCenter)-9000;
			}
			
			if (!bAtCenter) 
			{
				if (nNeuRad<0) 
				{
					if (bRgt) nPntWink+=18000;
					if (bLft) nPntWink=18000-nPntWink;
					if (bLwr) nPntWink=-nPntWink;
				} 
				else 
				{
					if (bRgt) nPntWink=-nPntWink;
					if (bUpr) nPntWink=18000-nPntWink;
					if (bLwr) nPntWink+=18000;
				}
				
				nPntWink=NormAngle360(nPntWink);
			} 
			else 
			{
				if (nNeuRad<0) nPntWink+=18000;
				if (bVertical) nPntWink=18000-nPntWink;
				nPntWink=NormAngle180(nPntWink);
				nPntWink=Abs(nPntWink);
			}

			double nUmfang=2*Abs(nNeuRad)*nPi;

			if (bResize) 
			{
				if (nSA!=0) 
				{ // Winkelfang
					long nWink0=nPntWink;
					nPntWink+=nSA/2;
					nPntWink/=nSA;
					nPntWink*=nSA;
					BigInt a2(nNeuRad);
					a2*=BigInt(nWink);
					a2/=BigInt(nWink0);
					nNeuRad=long(a2);
				
					if (bVertical) 
						aNeuCenter.X()=aStart.X()+nNeuRad;
					else 
						aNeuCenter.Y()=aStart.Y()+nNeuRad;
				}

				long nMul=(long)(nUmfang*NormAngle360(nPntWink)/36000);

				if (bAtCenter) 
					nMul*=2;

				aNeuFact=Fraction(nMul,nMarkSize);
				nWink=nPntWink;
			} 
			else 
			{
				nWink=(long)((nMarkSize*360/nUmfang)*100)/2;
			
				if (nWink==0) 
					bValid=false;

				if (bValid && nSA!=0) 
				{ // Winkelfang
					long nWink0=nWink;
					nWink+=nSA/2;
					nWink/=nSA;
					nWink*=nSA;
					BigInt a2(nNeuRad);
					a2*=BigInt(nWink);
					a2/=BigInt(nWink0);
					nNeuRad=long(a2);
				
					if (bVertical) 
						aNeuCenter.X()=aStart.X()+nNeuRad;
					else 
						aNeuCenter.Y()=aStart.Y()+nNeuRad;
				}
			}
		}

		if (nWink==0 || nNeuRad==0) 
			bValid=false;
		
		if (!bValid) 
			nNeuRad=0;

		if (!bValid && bResize) 
		{
			long nMul=bVertical ? dy1 : dx1;
		
			if (bLft || bUpr) 
				nMul=-nMul;

			long nDiv=nMarkSize;
			
			if (bAtCenter) 
			{ 
				nMul*=2; 
				nMul=Abs(nMul); 
			}
			
			aNeuFact=Fraction(nMul,nDiv);
		}

		if (aNeuCenter!=aCenter || bNeuContortion!=bContortion || aNeuFact!=aFact ||
			bNeuMoveOnly != getMoveOnly() || bNeuRotate!=bRotate || eNeuMode!=eMode)
		{
			Hide();
			setMoveOnly(bNeuMoveOnly);
			bRotate=bNeuRotate;
			eMode=eNeuMode;
			bContortion=bNeuContortion;
			aCenter=aNeuCenter;
			aFact=aNeuFact;
			aRad=Point(nNeuRad,nNeuRad);
			bResize=aFact!=Fraction(1,1) && aFact.GetDenominator()!=0 && aFact.IsValid();
			DragStat().NextMove(aPnt);
			Show();
		}
	}
}

void SdrDragCrook::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
    const bool bDoResize(aFact!=Fraction(1,1));
	const bool bDoCrook(aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0);
	
	if (bDoCrook || bDoResize) 
	{
		if (bDoResize) 
		{
			Fraction aFact1(1,1);
		
			if (bContortion) 
			{
				if (bVertical) 
                {
                    rTarget.Resize(aCenter,aFact1,aFact);
                }
				else 
                {
                    rTarget.Resize(aCenter,aFact,aFact1);
                }
			} 
			else 
			{
				Point aCtr0(rTarget.GetSnapRect().Center());
				Point aCtr1(aCtr0);
			
				if (bVertical) 
                {
					ResizePoint(aCtr1,aCenter,aFact1,aFact);
                }
				else 
                {
					ResizePoint(aCtr1,aCenter,aFact,aFact1);
                }

				Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y());

                rTarget.Move(aSiz);
			}
		}

		if (bDoCrook) 
		{
        	const Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect());
        	const bool bLocalRotate(!bContortion && eMode == SDRCROOK_ROTATE && getSdrDragView().IsRotateAllowed(false));

			getSdrDragView().ImpCrookObj(&rTarget,aCenter,aRad,eMode,bVertical,!bContortion,bLocalRotate,aLocalMarkRect);
		}
    }
}

void SdrDragCrook::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
{
	// use helper derived from old stuff
	_MovAllPoints(rTarget);
}

bool SdrDragCrook::EndSdrDrag(bool bCopy)
{
	Hide();
	
	if (bResize && aFact==Fraction(1,1)) 
		bResize=false;

	const bool bUndo = getSdrDragView().IsUndoEnabled();

	bool bDoCrook=aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0;
	
	if (bDoCrook || bResize) 
	{
		if (bResize && bUndo) 
		{
			XubString aStr;
			ImpTakeDescriptionStr(!bContortion?STR_EditCrook:STR_EditCrookContortion,aStr);
		
			if (bCopy) 
				aStr+=ImpGetResStr(STR_EditWithCopy);

			getSdrDragView().BegUndo(aStr);
		}

		if (bResize) 
		{
			Fraction aFact1(1,1);
		
			if (bContortion) 
			{
				if (bVertical) 
					getSdrDragView().ResizeMarkedObj(aCenter,aFact1,aFact,bCopy);
				else 
					getSdrDragView().ResizeMarkedObj(aCenter,aFact,aFact1,bCopy);
			} 
			else 
			{
				if (bCopy) 
					getSdrDragView().CopyMarkedObj();

				sal_uLong nMarkAnz=getSdrDragView().GetMarkedObjectList().GetMarkCount();
				
				for (sal_uLong nm=0; nm<nMarkAnz; nm++) 
				{
					SdrMark* pM=getSdrDragView().GetMarkedObjectList().GetMark(nm);
					SdrObject* pO=pM->GetMarkedSdrObj();
					Point aCtr0(pO->GetSnapRect().Center());
					Point aCtr1(aCtr0);
				
					if (bVertical) 
						ResizePoint(aCtr1,aCenter,aFact1,aFact);
					else 
						ResizePoint(aCtr1,aCenter,aFact,aFact1);

					Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y());
					if( bUndo )
						AddUndo(getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoMoveObject(*pO,aSiz));
					pO->Move(aSiz);
				}
			}

			bCopy=false;
		}

		if (bDoCrook) 
		{
			getSdrDragView().CrookMarkedObj(aCenter,aRad,eMode,bVertical,!bContortion,bCopy);
			getSdrDragView().SetLastCrookCenter(aCenter);
		}
		
		if (bResize && bUndo) 
			getSdrDragView().EndUndo();

		return true;
	}

	return false;
}

Pointer SdrDragCrook::GetSdrDragPointer() const
{
	return Pointer(POINTER_CROOK);
}

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

TYPEINIT1(SdrDragDistort,SdrDragMethod);

SdrDragDistort::SdrDragDistort(SdrDragView& rNewView)
:	SdrDragMethod(rNewView),
	nPolyPt(0),
	bContortionAllowed(false),
	bNoContortionAllowed(false),
	bContortion(false) 
{
}

void SdrDragDistort::TakeSdrDragComment(XubString& rStr) const
{
	ImpTakeDescriptionStr(STR_DragMethDistort, rStr);

	XubString aStr;
	
	rStr.AppendAscii(" (x=");
	getSdrDragView().GetModel()->TakeMetricStr(DragStat().GetDX(), aStr);
	rStr += aStr;
	rStr.AppendAscii(" y=");
	getSdrDragView().GetModel()->TakeMetricStr(DragStat().GetDY(), aStr);
	rStr += aStr;
	rStr += sal_Unicode(')');
	
	if(getSdrDragView().IsDragWithCopy()) 
		rStr += ImpGetResStr(STR_EditWithCopy);
}

void SdrDragDistort::createSdrDragEntries()
{
	// Add extended frame raster first, so it will be behind objects
    if(getSdrDragView().GetSdrPageView())
    {
        const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect()));

        if(aDragRaster.count())
        {
            addSdrDragEntry(new SdrDragEntryPolyPolygon(aDragRaster));
        }
    }

    // call parent
    SdrDragMethod::createSdrDragEntries();
}

bool SdrDragDistort::BeginSdrDrag()
{
	bContortionAllowed=getSdrDragView().IsDistortAllowed(false);
	bNoContortionAllowed=getSdrDragView().IsDistortAllowed(true);

	if (bContortionAllowed || bNoContortionAllowed) 
	{
		SdrHdlKind eKind=GetDragHdlKind();
		nPolyPt=0xFFFF;
	
		if (eKind==HDL_UPLFT) nPolyPt=0;
		if (eKind==HDL_UPRGT) nPolyPt=1;
		if (eKind==HDL_LWRGT) nPolyPt=2;
		if (eKind==HDL_LWLFT) nPolyPt=3;
		if (nPolyPt>3) return false;

		aMarkRect=GetMarkedRect();
		aDistortedRect=XPolygon(aMarkRect);
		Show();
		return true;
	} 
	else 
	{
		return false;
	}
}

void SdrDragDistort::_MovAllPoints(basegfx::B2DPolyPolygon& rTarget)
{
	if (bContortion) 
	{
		SdrPageView* pPV = getSdrDragView().GetSdrPageView();

		if(pPV)
		{
			if (pPV->HasMarkedObjPageView()) 
			{
				basegfx::B2DPolyPolygon aDragPolygon(rTarget);
				const basegfx::B2DRange aOriginalRange(aMarkRect.Left(), aMarkRect.Top(), aMarkRect.Right(), aMarkRect.Bottom());
				const basegfx::B2DPoint aTopLeft(aDistortedRect[0].X(), aDistortedRect[0].Y());
				const basegfx::B2DPoint aTopRight(aDistortedRect[1].X(), aDistortedRect[1].Y());
				const basegfx::B2DPoint aBottomLeft(aDistortedRect[3].X(), aDistortedRect[3].Y());
				const basegfx::B2DPoint aBottomRight(aDistortedRect[2].X(), aDistortedRect[2].Y());
				
                aDragPolygon = basegfx::tools::distort(aDragPolygon, aOriginalRange, aTopLeft, aTopRight, aBottomLeft, aBottomRight);
				rTarget = aDragPolygon;
			}
		}
	}
}

void SdrDragDistort::MoveSdrDrag(const Point& rPnt)
{
	if (DragStat().CheckMinMoved(rPnt)) 
	{
		Point aPnt(GetSnapPos(rPnt));
	
		if (getSdrDragView().IsOrtho()) 
			OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());

		bool bNeuContortion=(bContortionAllowed && !getSdrDragView().IsCrookNoContortion()) || !bNoContortionAllowed;
		
		if (bNeuContortion!=bContortion || aDistortedRect[nPolyPt]!=aPnt) 
		{
			Hide();
			aDistortedRect[nPolyPt]=aPnt;
			bContortion=bNeuContortion;
			DragStat().NextMove(aPnt);
			Show();
		}
	}
}

bool SdrDragDistort::EndSdrDrag(bool bCopy)
{
	Hide();
	bool bDoDistort=DragStat().GetDX()!=0 || DragStat().GetDY()!=0;

	if (bDoDistort) 
	{
		getSdrDragView().DistortMarkedObj(aMarkRect,aDistortedRect,!bContortion,bCopy);
		return true;
	}
	
	return false;
}

Pointer SdrDragDistort::GetSdrDragPointer() const
{
	return Pointer(POINTER_REFHAND);
}

void SdrDragDistort::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
	const bool bDoDistort(DragStat().GetDX()!=0 || DragStat().GetDY()!=0);

	if (bDoDistort) 
	{
		getSdrDragView().ImpDistortObj(&rTarget, aMarkRect, aDistortedRect, !bContortion);
	}
}

void SdrDragDistort::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
{
	// use helper derived from old stuff
	_MovAllPoints(rTarget);
}

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

TYPEINIT1(SdrDragCrop,SdrDragResize);

SdrDragCrop::SdrDragCrop(SdrDragView& rNewView)
:	SdrDragResize(rNewView)
{
	// switch off solid dragging for crop; it just makes no sense since showing
	// a 50% transparent object above the original will not be visible
	setSolidDraggingActive(false);
}

void SdrDragCrop::TakeSdrDragComment(XubString& rStr) const
{
	ImpTakeDescriptionStr(STR_DragMethCrop, rStr);

	XubString aStr;
	
	rStr.AppendAscii(" (x=");
	getSdrDragView().GetModel()->TakeMetricStr(DragStat().GetDX(), aStr);
	rStr += aStr;
	rStr.AppendAscii(" y=");
	getSdrDragView().GetModel()->TakeMetricStr(DragStat().GetDY(), aStr);
	rStr += aStr;
	rStr += sal_Unicode(')');
	
	if(getSdrDragView().IsDragWithCopy()) 
		rStr += ImpGetResStr(STR_EditWithCopy);
}

bool SdrDragCrop::EndSdrDrag(bool bCopy)
{
	Hide();
	
	if( DragStat().GetDX()==0 && DragStat().GetDY()==0 )
		return false;

	const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
	
	if( rMarkList.GetMarkCount() != 1 )
		return false;

	SdrGrafObj* pObj = dynamic_cast<SdrGrafObj*>( rMarkList.GetMark( 0 )->GetMarkedSdrObj() );

	if( !pObj || (pObj->GetGraphicType() == GRAPHIC_NONE) || (pObj->GetGraphicType() == GRAPHIC_DEFAULT) )
		return false;

	const GraphicObject& rGraphicObject = pObj->GetGraphicObject();
	const MapMode aMapMode100thmm(MAP_100TH_MM);
	Size aGraphicSize(rGraphicObject.GetPrefSize());
	
    if( MAP_PIXEL == rGraphicObject.GetPrefMapMode().GetMapUnit() )
        aGraphicSize = Application::GetDefaultDevice()->PixelToLogic( aGraphicSize, aMapMode100thmm );
    else
		aGraphicSize = Application::GetDefaultDevice()->LogicToLogic( aGraphicSize, rGraphicObject.GetPrefMapMode(), aMapMode100thmm);

	if( aGraphicSize.nA == 0 || aGraphicSize.nB == 0 )
		return false;

	const SdrGrafCropItem& rOldCrop = (const SdrGrafCropItem&)pObj->GetMergedItem(SDRATTR_GRAFCROP);

	const bool bUndo = getSdrDragView().IsUndoEnabled();

	if( bUndo )
	{
		String aUndoStr;
		ImpTakeDescriptionStr(STR_DragMethCrop, aUndoStr);

	    getSdrDragView().BegUndo( aUndoStr );
		getSdrDragView().AddUndo( getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoGeoObject( *pObj ) );
	}

	Rectangle aOldRect( pObj->GetLogicRect() );
	getSdrDragView().ResizeMarkedObj(DragStat().Ref1(),aXFact,aYFact,bCopy);
	Rectangle aNewRect( pObj->GetLogicRect() );

	double fScaleX = ( aGraphicSize.Width() - rOldCrop.GetLeft() - rOldCrop.GetRight() ) / (double)aOldRect.GetWidth();
	double fScaleY = ( aGraphicSize.Height() - rOldCrop.GetTop() - rOldCrop.GetBottom() ) / (double)aOldRect.GetHeight();

    // to correct the never working combination of cropped images and mirroring
    // I have to correct the rectangles the calculation is based on here. In the current
    // core geometry stuff a vertical mirror is expressed as 180 degree rotation. All
    // this can be removed again when aw080 will have cleaned up the old 
    // (non-)transformation mess in the core.
    if(18000 == pObj->GetGeoStat().nDrehWink)
    {
        // old notation of vertical mirror, need to correct diffs since both rects
        // are rotated by 180 degrees
        aOldRect = Rectangle(aOldRect.TopLeft() - (aOldRect.BottomRight() - aOldRect.TopLeft()), aOldRect.TopLeft());
        aNewRect = Rectangle(aNewRect.TopLeft() - (aNewRect.BottomRight() - aNewRect.TopLeft()), aNewRect.TopLeft());
    }

	sal_Int32 nDiffLeft = aNewRect.nLeft - aOldRect.nLeft;
	sal_Int32 nDiffTop = aNewRect.nTop - aOldRect.nTop;
	sal_Int32 nDiffRight = aNewRect.nRight - aOldRect.nRight;
	sal_Int32 nDiffBottom = aNewRect.nBottom - aOldRect.nBottom;

	sal_Int32 nLeftCrop = static_cast<sal_Int32>( rOldCrop.GetLeft() + nDiffLeft * fScaleX );
	sal_Int32 nTopCrop = static_cast<sal_Int32>( rOldCrop.GetTop() + nDiffTop * fScaleY );
	sal_Int32 nRightCrop = static_cast<sal_Int32>( rOldCrop.GetRight() - nDiffRight * fScaleX );
	sal_Int32 nBottomCrop = static_cast<sal_Int32>( rOldCrop.GetBottom() - nDiffBottom * fScaleY );

	SfxItemPool& rPool = getSdrDragView().GetModel()->GetItemPool();
	SfxItemSet aSet( rPool, SDRATTR_GRAFCROP, SDRATTR_GRAFCROP );
	aSet.Put( SdrGrafCropItem( nLeftCrop, nTopCrop, nRightCrop, nBottomCrop ) );
	getSdrDragView().SetAttributes( aSet, false );

	if( bUndo )
		getSdrDragView().EndUndo();

	return true;
}

Pointer SdrDragCrop::GetSdrDragPointer() const
{
	return Pointer(POINTER_CROP);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// eof
