/**************************************************************
 * 
 * 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_sw.hxx"
#include "hintids.hxx"
#include <svx/svdtrans.hxx>
#include <editeng/protitem.hxx>
#include <editeng/opaqitem.hxx>
#include <svx/svdpage.hxx>


#include <fmtclds.hxx>
#include <fmtornt.hxx>
#include <fmtfsize.hxx>
#include <fmturl.hxx>
#include "viewsh.hxx"
#include "viewimp.hxx"
#include "cntfrm.hxx"
#include "frmatr.hxx"
#include "doc.hxx"
#include <IDocumentUndoRedo.hxx>
#include "dview.hxx"
#include "dflyobj.hxx"
#include "flyfrm.hxx"
#include "frmfmt.hxx"
#include "viewopt.hxx"
#include "frmtool.hxx"
#include "flyfrms.hxx"
#include "ndnotxt.hxx"
#include "grfatr.hxx"
#include "pagefrm.hxx"
#include "rootfrm.hxx"


using namespace ::com::sun::star;


// --> OD 2004-11-22 #117958#
#include <svx/sdr/properties/defaultproperties.hxx>
// <--
#include <basegfx/range/b2drange.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>

// AW: For VCOfDrawVirtObj and stuff
#include <svx/sdr/contact/viewcontactofvirtobj.hxx>
#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
#include <sw_primitivetypes2d.hxx>
#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>

using namespace ::com::sun::star;

static sal_Bool bInResize = sal_False;

TYPEINIT1( SwFlyDrawObj, SdrObject )
TYPEINIT1( SwVirtFlyDrawObj, SdrVirtObj )

/*************************************************************************
|*
|*	SwFlyDrawObj::Ctor
|*
|*	Ersterstellung		MA 18. Apr. 95
|*	Letzte Aenderung	MA 28. May. 96
|*
*************************************************************************/

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

namespace sdr
{
	namespace contact
	{
        // #i95264# currently needed since createViewIndependentPrimitive2DSequence()
        // is called when RecalcBoundRect() is used. There should currently no VOCs being
        // constructed since it gets not visualized (instead the corresponding SwVirtFlyDrawObj's
        // referencing this one are visualized).
		class VCOfSwFlyDrawObj : public ViewContactOfSdrObj
		{
        protected:
			// This method is responsible for creating the graphical visualisation data
            // ONLY based on model data
			virtual drawinglayer::primitive2d::Primitive2DSequence createViewIndependentPrimitive2DSequence() const;

        public:
			// basic constructor, used from SdrObject.
            VCOfSwFlyDrawObj(SwFlyDrawObj& rObj)
            :   ViewContactOfSdrObj(rObj)
            {
            }
			virtual ~VCOfSwFlyDrawObj();
		};

        drawinglayer::primitive2d::Primitive2DSequence VCOfSwFlyDrawObj::createViewIndependentPrimitive2DSequence() const
        {
            // currently gets not visualized, return empty sequence
            return drawinglayer::primitive2d::Primitive2DSequence();
        }

        VCOfSwFlyDrawObj::~VCOfSwFlyDrawObj()
        {
        }
	} // end of namespace contact
} // end of namespace sdr

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

sdr::properties::BaseProperties* SwFlyDrawObj::CreateObjectSpecificProperties()
{
    // --> OD 2004-11-22 #117958# - create default properties
    return new sdr::properties::DefaultProperties(*this);
    // <--
}

sdr::contact::ViewContact* SwFlyDrawObj::CreateObjectSpecificViewContact()
{
    // #i95264# needs an own VC since createViewIndependentPrimitive2DSequence()
    // is called when RecalcBoundRect() is used
	return new sdr::contact::VCOfSwFlyDrawObj(*this);
}

SwFlyDrawObj::SwFlyDrawObj()
{
}

SwFlyDrawObj::~SwFlyDrawObj()
{
}

/*************************************************************************
|*
|*	SwFlyDrawObj::Factory-Methoden
|*
|*	Ersterstellung		MA 23. Feb. 95
|*	Letzte Aenderung	MA 23. Feb. 95
|*
*************************************************************************/

sal_uInt32 __EXPORT SwFlyDrawObj::GetObjInventor() const
{
	return SWGInventor;
}


sal_uInt16 __EXPORT SwFlyDrawObj::GetObjIdentifier()	const
{
	return SwFlyDrawObjIdentifier;
}


sal_uInt16 __EXPORT SwFlyDrawObj::GetObjVersion() const
{
	return SwDrawFirst;
}

/*************************************************************************
|*
|*	SwVirtFlyDrawObj::CToren, Dtor
|*
|*	Ersterstellung		MA 08. Dec. 94
|*	Letzte Aenderung	MA 28. May. 96
|*
*************************************************************************/

//////////////////////////////////////////////////////////////////////////////////////
// AW: Need own primitive to get the FlyFrame paint working

namespace drawinglayer
{
	namespace primitive2d
	{
		class SwVirtFlyDrawObjPrimitive : public BufferedDecompositionPrimitive2D
		{
        private:
            const SwVirtFlyDrawObj&                 mrSwVirtFlyDrawObj;
			const basegfx::B2DRange					maOuterRange;

		protected:
			// method which is to be used to implement the local decomposition of a 2D primitive
			virtual Primitive2DSequence create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const;

		public:
			SwVirtFlyDrawObjPrimitive(
				const SwVirtFlyDrawObj& rSwVirtFlyDrawObj,
				const basegfx::B2DRange &rOuterRange)
            :   BufferedDecompositionPrimitive2D(),
                mrSwVirtFlyDrawObj(rSwVirtFlyDrawObj),
				maOuterRange(rOuterRange)
            {
            }

			// compare operator
			virtual bool operator==(const BasePrimitive2D& rPrimitive) const;

			// get range
			virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const;

			// overloaded to allow callbacks to wrap_DoPaintObject
			virtual Primitive2DSequence get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const;

			// data read access
			const SwVirtFlyDrawObj& getSwVirtFlyDrawObj() const { return mrSwVirtFlyDrawObj; }
			const basegfx::B2DRange& getOuterRange() const { return maOuterRange; }

			// provide unique ID
			DeclPrimitrive2DIDBlock()
		};
	} // end of namespace primitive2d
} // end of namespace drawinglayer

namespace drawinglayer
{
	namespace primitive2d
	{
		Primitive2DSequence SwVirtFlyDrawObjPrimitive::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
        {
			Primitive2DSequence aRetval;

			if(!getOuterRange().isEmpty())
			{
				// currently this SW object has no primitive representation. As long as this is the case,
				// create invisible geometry to allow corfect HitTest and BoundRect calculations for the 
                // object. Use a filled primitive to get 'inside' as default object hit. The special cases from
                // the old SwVirtFlyDrawObj::CheckHit implementation are handled now in SwDrawView::PickObj;
                // this removed the 'hack' to get a view from inside model data or to react on null-tolerance
                // as it was done in the old implementation
                const Primitive2DReference aHitTestReference(
                    createHiddenGeometryPrimitives2D(
                        true, 
                        getOuterRange()));

				aRetval = Primitive2DSequence(&aHitTestReference, 1);
			}

			return aRetval;
        }

		bool SwVirtFlyDrawObjPrimitive::operator==(const BasePrimitive2D& rPrimitive) const
        {
			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
			{
				const SwVirtFlyDrawObjPrimitive& rCompare = (SwVirtFlyDrawObjPrimitive&)rPrimitive;

				return (&getSwVirtFlyDrawObj() == &rCompare.getSwVirtFlyDrawObj()
					&& getOuterRange() == rCompare.getOuterRange());
			}

			return false;
        }

		basegfx::B2DRange SwVirtFlyDrawObjPrimitive::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
        {
            return getOuterRange();
        }

		Primitive2DSequence SwVirtFlyDrawObjPrimitive::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
		{
            // This is the callback to keep the FlyFrame painting in SW alive as long as it
            // is not changed to primitives. This is the method which will be called by the processors
            // when they do not know this primitive (and they do not). Inside wrap_DoPaintObject
            // there needs to be a test that paint is only done during SW repaints (see there).
            // Using this mechanism guarantees the correct Z-Order of the VirtualObject-based FlyFrames.
            getSwVirtFlyDrawObj().wrap_DoPaintObject();

            // call parent
            return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
		}

        // provide unique ID
		ImplPrimitrive2DIDBlock(SwVirtFlyDrawObjPrimitive, PRIMITIVE2D_ID_SWVIRTFLYDRAWOBJPRIMITIVE2D)

    } // end of namespace primitive2d
} // end of namespace drawinglayer

//////////////////////////////////////////////////////////////////////////////////////
// AW: own sdr::contact::ViewContact (VC) sdr::contact::ViewObjectContact (VOC) needed
// since offset is defined different from SdrVirtObj's sdr::contact::ViewContactOfVirtObj.
// For paint, that offset is used by setting at the OutputDevice; for primitives this is
// not possible since we have no OutputDevice, but define the geometry itself.

namespace sdr
{
	namespace contact
	{
		class VCOfSwVirtFlyDrawObj : public ViewContactOfVirtObj
		{
        protected:
			// This method is responsible for creating the graphical visualisation data
            // ONLY based on model data
			virtual drawinglayer::primitive2d::Primitive2DSequence createViewIndependentPrimitive2DSequence() const;

        public:
			// basic constructor, used from SdrObject.
            VCOfSwVirtFlyDrawObj(SwVirtFlyDrawObj& rObj)
            :   ViewContactOfVirtObj(rObj)
            {
            }
			virtual ~VCOfSwVirtFlyDrawObj();

            // access to SwVirtFlyDrawObj
            SwVirtFlyDrawObj& GetSwVirtFlyDrawObj() const
            {
			    return (SwVirtFlyDrawObj&)mrObject;
            }
		};
	} // end of namespace contact
} // end of namespace sdr

namespace sdr
{
	namespace contact
	{
		drawinglayer::primitive2d::Primitive2DSequence VCOfSwVirtFlyDrawObj::createViewIndependentPrimitive2DSequence() const
        {
            drawinglayer::primitive2d::Primitive2DSequence xRetval;
            const SdrObject& rReferencedObject = GetSwVirtFlyDrawObj().GetReferencedObj();

            if(rReferencedObject.ISA(SwFlyDrawObj))
            {
                // create an own specialized primitive which is used as repaint callpoint and HitTest
				// for HitTest processor (see primitive implementation above)
                const basegfx::B2DRange aOuterRange(GetSwVirtFlyDrawObj().getOuterBound());

                if(!aOuterRange.isEmpty())
                {
					const drawinglayer::primitive2d::Primitive2DReference xPrimitive(
						new drawinglayer::primitive2d::SwVirtFlyDrawObjPrimitive(
							GetSwVirtFlyDrawObj(),
							aOuterRange));

					xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xPrimitive, 1);
				}
            }

            return xRetval;
        }

        VCOfSwVirtFlyDrawObj::~VCOfSwVirtFlyDrawObj()
        {
        }
	} // end of namespace contact
} // end of namespace sdr

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

basegfx::B2DRange SwVirtFlyDrawObj::getOuterBound() const
{
    basegfx::B2DRange aOuterRange;
    const SdrObject& rReferencedObject = GetReferencedObj();

    if(rReferencedObject.ISA(SwFlyDrawObj))
    {
		const SwFlyFrm* pFlyFrame = GetFlyFrm();

        if(pFlyFrame)
        {
		    const Rectangle aOuterRectangle(pFlyFrame->Frm().Pos(), pFlyFrame->Frm().SSize());

		    if(!aOuterRectangle.IsEmpty()
			    && RECT_EMPTY != aOuterRectangle.Right()
			    && RECT_EMPTY != aOuterRectangle.Bottom())
		    {
                aOuterRange.expand(basegfx::B2DTuple(aOuterRectangle.Left(), aOuterRectangle.Top()));
                aOuterRange.expand(basegfx::B2DTuple(aOuterRectangle.Right(), aOuterRectangle.Bottom()));
            }
        }
    }

    return aOuterRange;
}

basegfx::B2DRange SwVirtFlyDrawObj::getInnerBound() const
{
    basegfx::B2DRange aInnerRange;
    const SdrObject& rReferencedObject = GetReferencedObj();

    if(rReferencedObject.ISA(SwFlyDrawObj))
    {
		const SwFlyFrm* pFlyFrame = GetFlyFrm();

        if(pFlyFrame)
        {
			const Rectangle aInnerRectangle(pFlyFrame->Frm().Pos() + pFlyFrame->Prt().Pos(), pFlyFrame->Prt().SSize());

            if(!aInnerRectangle.IsEmpty()
			    && RECT_EMPTY != aInnerRectangle.Right()
			    && RECT_EMPTY != aInnerRectangle.Bottom())
		    {
			    aInnerRange.expand(basegfx::B2DTuple(aInnerRectangle.Left(), aInnerRectangle.Top()));
			    aInnerRange.expand(basegfx::B2DTuple(aInnerRectangle.Right(), aInnerRectangle.Bottom()));
            }
        }
    }

    return aInnerRange;
}

sdr::contact::ViewContact* SwVirtFlyDrawObj::CreateObjectSpecificViewContact()
{
    // need an own ViewContact (VC) to allow creation of a specialized primitive
    // for being able to visualize the FlyFrames in primitive renderers
	return new sdr::contact::VCOfSwVirtFlyDrawObj(*this);
}

SwVirtFlyDrawObj::SwVirtFlyDrawObj(SdrObject& rNew, SwFlyFrm* pFly) :
	SdrVirtObj( rNew ),
	pFlyFrm( pFly )
{
	//#110094#-1
	// bNotPersistent = bNeedColorRestore = bWriterFlyFrame = sal_True;
	const SvxProtectItem &rP = pFlyFrm->GetFmt()->GetProtect();
	bMovProt = rP.IsPosProtected();
	bSizProt = rP.IsSizeProtected();
}


__EXPORT SwVirtFlyDrawObj::~SwVirtFlyDrawObj()
{
	if ( GetPage() )	//Der SdrPage die Verantwortung entziehen.
		GetPage()->RemoveObject( GetOrdNum() );
}

/*************************************************************************
|*
|*	SwVirtFlyDrawObj::GetFmt()
|*
|*	Ersterstellung		MA 08. Dec. 94
|*	Letzte Aenderung	MA 08. Dec. 94
|*
*************************************************************************/

const SwFrmFmt *SwVirtFlyDrawObj::GetFmt() const
{
	return GetFlyFrm()->GetFmt();
}


SwFrmFmt *SwVirtFlyDrawObj::GetFmt()
{
	return GetFlyFrm()->GetFmt();
}

/*************************************************************************
|*
|*	SwVirtFlyDrawObj::Paint()
|*
|*	Ersterstellung		MA 20. Dec. 94
|*	Letzte Aenderung	MA 18. Dec. 95
|*
*************************************************************************/

// --> OD #i102707#
namespace
{
    class RestoreMapMode
    {
        public:
            explicit RestoreMapMode( ViewShell* pViewShell )
                : mbMapModeRestored( false )
                , mpOutDev( pViewShell->GetOut() )                    
            {
                if ( pViewShell->getPrePostMapMode() != mpOutDev->GetMapMode() )
                {
                    mpOutDev->Push(PUSH_MAPMODE);
                    
                    GDIMetaFile* pMetaFile = mpOutDev->GetConnectMetaFile();
                    if ( pMetaFile && 
                         pMetaFile->IsRecord() && !pMetaFile->IsPause() )
                    {
                        ASSERT( false,
                                "MapMode restoration during meta file creation is somehow suspect - using <SetRelativeMapMode(..)>, but not sure, if correct." )
                        mpOutDev->SetRelativeMapMode( pViewShell->getPrePostMapMode() );
                    }
                    else
                    {
                        mpOutDev->SetMapMode( pViewShell->getPrePostMapMode() );
                    }
                    
                    mbMapModeRestored = true;
                }
            };

            ~RestoreMapMode()
            {
                if ( mbMapModeRestored )
                {
                    mpOutDev->Pop();
                }
            };            

        private:
            bool mbMapModeRestored;
            OutputDevice* mpOutDev;
    };
}
// <--

void SwVirtFlyDrawObj::wrap_DoPaintObject() const
{
    ViewShell* pShell = pFlyFrm->getRootFrm()->GetCurrShell();

    // Only paint when we have a current shell and a DrawingLayer paint is in progress.
    // This avcoids evtl. problems with renderers which do processing stuff,
    // but no paints. IsPaintInProgress() depends on SW repaint, so, as long
    // as SW paints self and calls DrawLayer() for Heaven and Hell, this will
    // be correct
    if ( pShell && pShell->IsDrawingLayerPaintInProgress() )
    {
        sal_Bool bDrawObject(sal_True);

        if ( !SwFlyFrm::IsPaint( (SdrObject*)this, pShell ) )
	    {
		    bDrawObject = sal_False;
	    }

        if ( bDrawObject )
	    {
            if ( !pFlyFrm->IsFlyInCntFrm() )
		    {
				// it is also necessary to restore the VCL MapMode from ViewInformation since e.g.
				// the VCL PixelRenderer resets it at the used OutputDevice. Unfortunately, this
				// excludes shears and rotates which are not expressable in MapMode.
                // OD #i102707# 
                // new helper class to restore MapMode - restoration, only if 
                // needed and consideration of paint for meta file creation .
                RestoreMapMode aRestoreMapModeIfNeeded( pShell );

				// paint the FlyFrame (use standard VCL-Paint)
                pFlyFrm->Paint( GetFlyFrm()->Frm() );
		    }
	    }
    }
}

/*************************************************************************
|*
|*	SwVirtFlyDrawObj::TakeObjInfo()
|*
|*	Ersterstellung		MA 03. May. 95
|*	Letzte Aenderung	MA 03. May. 95
|*
*************************************************************************/

void __EXPORT SwVirtFlyDrawObj::TakeObjInfo( SdrObjTransformInfoRec& rInfo ) const
{
	rInfo.bSelectAllowed	 = rInfo.bMoveAllowed =
	rInfo.bResizeFreeAllowed = rInfo.bResizePropAllowed = sal_True;

	rInfo.bRotateFreeAllowed = rInfo.bRotate90Allowed =
	rInfo.bMirrorFreeAllowed = rInfo.bMirror45Allowed =
	rInfo.bMirror90Allowed   = rInfo.bShearAllowed	  =
	rInfo.bCanConvToPath	 = rInfo.bCanConvToPoly	  =
	rInfo.bCanConvToPathLineToArea = rInfo.bCanConvToPolyLineToArea = sal_False;
}


/*************************************************************************
|*
|*	SwVirtFlyDrawObj::Groessenermittlung
|*
|*	Ersterstellung		MA 12. Jan. 95
|*	Letzte Aenderung	MA 10. Nov. 95
|*
*************************************************************************/

void SwVirtFlyDrawObj::SetRect() const
{
	if ( GetFlyFrm()->Frm().HasArea() )
		((SwVirtFlyDrawObj*)this)->aOutRect = GetFlyFrm()->Frm().SVRect();
	else
		((SwVirtFlyDrawObj*)this)->aOutRect = Rectangle();
}


const Rectangle& __EXPORT SwVirtFlyDrawObj::GetCurrentBoundRect() const
{
	SetRect();
	return aOutRect;
}

const Rectangle& __EXPORT SwVirtFlyDrawObj::GetLastBoundRect() const
{
    return GetCurrentBoundRect();
}


void __EXPORT SwVirtFlyDrawObj::RecalcBoundRect()
{
	SetRect();
}


void __EXPORT SwVirtFlyDrawObj::RecalcSnapRect()
{
	SetRect();
}


const Rectangle& __EXPORT SwVirtFlyDrawObj::GetSnapRect()  const
{
	SetRect();
	return aOutRect;
}


void __EXPORT SwVirtFlyDrawObj::SetSnapRect(const Rectangle& )
{
	Rectangle aTmp( GetLastBoundRect() );
	SetRect();
	SetChanged();
	BroadcastObjectChange();
	if (pUserCall!=NULL)
		pUserCall->Changed(*this, SDRUSERCALL_RESIZE, aTmp);
}


void __EXPORT SwVirtFlyDrawObj::NbcSetSnapRect(const Rectangle& )
{
	SetRect();
}


const Rectangle& __EXPORT SwVirtFlyDrawObj::GetLogicRect() const
{
	SetRect();
	return aOutRect;
}


void __EXPORT SwVirtFlyDrawObj::SetLogicRect(const Rectangle& )
{
	Rectangle aTmp( GetLastBoundRect() );
	SetRect();
	SetChanged();
	BroadcastObjectChange();
	if (pUserCall!=NULL)
		pUserCall->Changed(*this, SDRUSERCALL_RESIZE, aTmp);
}


void __EXPORT SwVirtFlyDrawObj::NbcSetLogicRect(const Rectangle& )
{
	SetRect();
}


::basegfx::B2DPolyPolygon SwVirtFlyDrawObj::TakeXorPoly() const
{
	const Rectangle aSourceRectangle(GetFlyFrm()->Frm().SVRect());
	const ::basegfx::B2DRange aSourceRange(aSourceRectangle.Left(), aSourceRectangle.Top(), aSourceRectangle.Right(), aSourceRectangle.Bottom());
	::basegfx::B2DPolyPolygon aRetval;

	aRetval.append(::basegfx::tools::createPolygonFromRect(aSourceRange));

	return aRetval;
}

/*************************************************************************
|*
|*	SwVirtFlyDrawObj::Move() und Resize()
|*
|*	Ersterstellung		MA 12. Jan. 95
|*	Letzte Aenderung	MA 26. Jul. 96
|*
*************************************************************************/

void __EXPORT SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
{
	MoveRect( aOutRect, rSiz );
	const Point aOldPos( GetFlyFrm()->Frm().Pos() );
	const Point aNewPos( aOutRect.TopLeft() );
	const SwRect aFlyRect( aOutRect );

	//Wenn der Fly eine automatische Ausrichtung hat (rechts oder oben),
	//so soll die Automatik erhalten bleiben
	SwFrmFmt *pFmt = GetFlyFrm()->GetFmt();
    const sal_Int16 eHori = pFmt->GetHoriOrient().GetHoriOrient();
    const sal_Int16 eVert = pFmt->GetVertOrient().GetVertOrient();
    const sal_Int16 eRelHori = pFmt->GetHoriOrient().GetRelationOrient();
    const sal_Int16 eRelVert = pFmt->GetVertOrient().GetRelationOrient();
	//Bei Absatzgebundenen Flys muss ausgehend von der neuen Position ein
	//neuer Anker gesetzt werden. Anker und neue RelPos werden vom Fly selbst
	//berechnet und gesetzt.
    if( GetFlyFrm()->IsFlyAtCntFrm() )
		((SwFlyAtCntFrm*)GetFlyFrm())->SetAbsPos( aNewPos );
	else
	{
        const SwFrmFmt *pTmpFmt = GetFmt();
        const SwFmtVertOrient &rVert = pTmpFmt->GetVertOrient();
        const SwFmtHoriOrient &rHori = pTmpFmt->GetHoriOrient();
		long lXDiff = aNewPos.X() - aOldPos.X();
        if( rHori.IsPosToggle() && text::HoriOrientation::NONE == eHori &&
			!GetFlyFrm()->FindPageFrm()->OnRightPage() )
			lXDiff = -lXDiff;

        if( GetFlyFrm()->GetAnchorFrm()->IsRightToLeft() &&
            text::HoriOrientation::NONE == eHori )
            lXDiff = -lXDiff;

        long lYDiff = aNewPos.Y() - aOldPos.Y();
        if( GetFlyFrm()->GetAnchorFrm()->IsVertical() )
        {
            //lXDiff -= rVert.GetPos();
            //lYDiff += rHori.GetPos();
            //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
            if ( GetFlyFrm()->GetAnchorFrm()->IsVertLR() )
	    	{
	    		lXDiff += rVert.GetPos();
	    		lXDiff = -lXDiff;
	    	}
	    	else 
	    	{
				lXDiff -= rVert.GetPos();
            	lYDiff += rHori.GetPos();
			}
        }
        else
        {
            lXDiff += rHori.GetPos();
            lYDiff += rVert.GetPos();
        }

        if( GetFlyFrm()->GetAnchorFrm()->IsRightToLeft() &&
            text::HoriOrientation::NONE != eHori )
            lXDiff = GetFlyFrm()->GetAnchorFrm()->Frm().Width() -
					 aFlyRect.Width() - lXDiff;

        const Point aTmp( lXDiff, lYDiff );
		GetFlyFrm()->ChgRelPos( aTmp );
	}

	SwAttrSet aSet( pFmt->GetDoc()->GetAttrPool(),
											RES_VERT_ORIENT, RES_HORI_ORIENT );
	SwFmtHoriOrient aHori( pFmt->GetHoriOrient() );
	SwFmtVertOrient aVert( pFmt->GetVertOrient() );
	sal_Bool bPut = sal_False;

	if( !GetFlyFrm()->IsFlyLayFrm() &&
		::GetHtmlMode(pFmt->GetDoc()->GetDocShell()) )
	{
		//Im HTML-Modus sind nur automatische Ausrichtungen erlaubt.
		//Einzig einen Snap auf Links/Rechts bzw. Linker-/Rechter-Rand koennen
		//wir versuchen.
        const SwFrm* pAnch = GetFlyFrm()->GetAnchorFrm();
		sal_Bool bNextLine = sal_False;

        if( !GetFlyFrm()->IsAutoPos() || text::RelOrientation::PAGE_FRAME != aHori.GetRelationOrient() )
		{
            if( text::RelOrientation::CHAR == eRelHori )
			{
                aHori.SetHoriOrient( text::HoriOrientation::LEFT );
                aHori.SetRelationOrient( text::RelOrientation::CHAR );
			}
			else
			{
				bNextLine = sal_True;
				//Horizontale Ausrichtung:
				const sal_Bool bLeftFrm =
					aFlyRect.Left() < pAnch->Frm().Left() + pAnch->Prt().Left(),
					bLeftPrt = aFlyRect.Left() + aFlyRect.Width() <
							   pAnch->Frm().Left() + pAnch->Prt().Width()/2;
				if ( bLeftFrm || bLeftPrt )
				{
                    aHori.SetHoriOrient( text::HoriOrientation::LEFT );
                    aHori.SetRelationOrient( bLeftFrm ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
				}
				else
				{
					const sal_Bool bRightFrm = aFlyRect.Left() >
									   pAnch->Frm().Left() + pAnch->Prt().Width();
                    aHori.SetHoriOrient( text::HoriOrientation::RIGHT );
                    aHori.SetRelationOrient( bRightFrm ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
				}
			}
			aSet.Put( aHori );
		}
		//Vertikale Ausrichtung bleibt grundsaetzlich schlicht erhalten,
		//nur bei nicht automatischer Ausrichtung wird umgeschaltet.
        sal_Bool bRelChar = text::RelOrientation::CHAR == eRelVert;
        aVert.SetVertOrient( eVert != text::VertOrientation::NONE ? eVert :
                GetFlyFrm()->IsFlyInCntFrm() ? text::VertOrientation::CHAR_CENTER :
                bRelChar && bNextLine ? text::VertOrientation::CHAR_TOP : text::VertOrientation::TOP );
		if( bRelChar )
            aVert.SetRelationOrient( text::RelOrientation::CHAR );
		else
            aVert.SetRelationOrient( text::RelOrientation::PRINT_AREA );
		aSet.Put( aVert );
		bPut = sal_True;
	}

	//Automatische Ausrichtungen wollen wir moeglichst nicht verlieren.
	if ( !bPut && bInResize )
	{
        if ( text::HoriOrientation::NONE != eHori )
		{
			aHori.SetHoriOrient( eHori );
			aHori.SetRelationOrient( eRelHori );
			aSet.Put( aHori );
			bPut = sal_True;
		}
        if ( text::VertOrientation::NONE != eVert )
		{
			aVert.SetVertOrient( eVert );
			aVert.SetRelationOrient( eRelVert );
			aSet.Put( aVert );
			bPut = sal_True;
		}
	}
	if ( bPut )
        pFmt->SetFmtAttr( aSet );
}


void __EXPORT SwVirtFlyDrawObj::NbcResize(const Point& rRef,
			const Fraction& xFact, const Fraction& yFact)
{
	ResizeRect( aOutRect, rRef, xFact, yFact );

    const SwFrm* pTmpFrm = GetFlyFrm()->GetAnchorFrm();
    if( !pTmpFrm )
        pTmpFrm = GetFlyFrm();
    const bool bVertX = pTmpFrm->IsVertical();

    const sal_Bool bRTL = pTmpFrm->IsRightToLeft();

	//Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
	const bool bVertL2RX = pTmpFrm->IsVertLR();
    const Point aNewPos( ( bVertX && !bVertL2RX ) || bRTL ?
						 aOutRect.Right() + 1 :
						 aOutRect.Left(),
                         aOutRect.Top() );

	Size aSz( aOutRect.Right() - aOutRect.Left() + 1,
			  aOutRect.Bottom()- aOutRect.Top()  + 1 );
	if( aSz != GetFlyFrm()->Frm().SSize() )
	{
		//Die Breite darf bei Spalten nicht zu schmal werden
		if ( GetFlyFrm()->Lower() && GetFlyFrm()->Lower()->IsColumnFrm() )
		{
			SwBorderAttrAccess aAccess( SwFrm::GetCache(), GetFlyFrm() );
			const SwBorderAttrs &rAttrs = *aAccess.Get();
			long nMin = rAttrs.CalcLeftLine()+rAttrs.CalcRightLine();
			const SwFmtCol& rCol = rAttrs.GetAttrSet().GetCol();
			if ( rCol.GetColumns().Count() > 1 )
			{
				for ( sal_uInt16 i = 0; i < rCol.GetColumns().Count(); ++i )
				{
					nMin += rCol.GetColumns()[i]->GetLeft() +
							rCol.GetColumns()[i]->GetRight() +
							MINFLY;
				}
				nMin -= MINFLY;
			}
			aSz.Width() = Max( aSz.Width(), nMin );
		}

        SwFrmFmt *pFmt = GetFmt();
		const SwFmtFrmSize aOldFrmSz( pFmt->GetFrmSize() );
		GetFlyFrm()->ChgSize( aSz );
		SwFmtFrmSize aFrmSz( pFmt->GetFrmSize() );
		if ( aFrmSz.GetWidthPercent() || aFrmSz.GetHeightPercent() )
		{
			long nRelWidth, nRelHeight;
			const SwFrm *pRel = GetFlyFrm()->IsFlyLayFrm() ?
                                GetFlyFrm()->GetAnchorFrm() :
                                GetFlyFrm()->GetAnchorFrm()->GetUpper();
			const ViewShell *pSh = GetFlyFrm()->getRootFrm()->GetCurrShell();
            if ( pSh && pRel->IsBodyFrm() &&
                 pSh->GetViewOptions()->getBrowseMode() &&
                 pSh->VisArea().HasArea() )
			{
				nRelWidth  = pSh->GetBrowseWidth();
				nRelHeight = pSh->VisArea().Height();
				const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() );
				nRelHeight -= 2*aBorder.Height();
			}
			else
			{
				nRelWidth  = pRel->Prt().Width();
				nRelHeight = pRel->Prt().Height();
			}
			if ( aFrmSz.GetWidthPercent() && aFrmSz.GetWidthPercent() != 0xFF &&
				 aOldFrmSz.GetWidth() != aFrmSz.GetWidth() )
				aFrmSz.SetWidthPercent( sal_uInt8(aSz.Width() * 100L / nRelWidth + 0.5) );
			if ( aFrmSz.GetHeightPercent() && aFrmSz.GetHeightPercent() != 0xFF &&
				 aOldFrmSz.GetHeight() != aFrmSz.GetHeight() )
				aFrmSz.SetHeightPercent( sal_uInt8(aSz.Height() * 100L / nRelHeight + 0.5) );
			pFmt->GetDoc()->SetAttr( aFrmSz, *pFmt );
		}
	}

	//Position kann auch veraendert sein!
	const Point aOldPos( ( bVertX && !bVertL2RX ) || bRTL ?
                         GetFlyFrm()->Frm().TopRight() :
                         GetFlyFrm()->Frm().Pos() );
    if ( aNewPos != aOldPos )
	{
		//Kann sich durch das ChgSize veraendert haben!
        if( bVertX || bRTL )
        {
            if( aOutRect.TopRight() != aNewPos )
            {
                //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
                SwTwips nDeltaX;
				if ( bVertL2RX )
                	nDeltaX = aNewPos.X() - aOutRect.Left();
                else
                	nDeltaX = aNewPos.X() - aOutRect.Right();
                SwTwips nDeltaY = aNewPos.Y() - aOutRect.Top();
                MoveRect( aOutRect, Size( nDeltaX, nDeltaY ) );
            }
        }
        else if ( aOutRect.TopLeft() != aNewPos )
			aOutRect.SetPos( aNewPos );
		bInResize = sal_True;
		NbcMove( Size( 0, 0 ) );
		bInResize = sal_False;
	}
}


void __EXPORT SwVirtFlyDrawObj::Move(const Size& rSiz)
{
	NbcMove( rSiz );
	SetChanged();
    GetFmt()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
}


void __EXPORT SwVirtFlyDrawObj::Resize(const Point& rRef,
					const Fraction& xFact, const Fraction& yFact)
{
	NbcResize( rRef, xFact, yFact );
	SetChanged();
    GetFmt()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
}


Pointer  __EXPORT SwVirtFlyDrawObj::GetMacroPointer(
    const SdrObjMacroHitRec& ) const
{
	return Pointer( POINTER_REFHAND );
}


FASTBOOL __EXPORT SwVirtFlyDrawObj::HasMacro() const
{
	const SwFmtURL &rURL = pFlyFrm->GetFmt()->GetURL();
	return rURL.GetMap() || rURL.GetURL().Len();
}


SdrObject* SwVirtFlyDrawObj::CheckMacroHit( const SdrObjMacroHitRec& rRec ) const
{
	const SwFmtURL &rURL = pFlyFrm->GetFmt()->GetURL();
	if( rURL.GetMap() || rURL.GetURL().Len() )
	{
		SwRect aRect;
		if ( pFlyFrm->Lower() && pFlyFrm->Lower()->IsNoTxtFrm() )
		{
			aRect = pFlyFrm->Prt();
			aRect += pFlyFrm->Frm().Pos();
		}
		else
			aRect = pFlyFrm->Frm();

		if( aRect.IsInside( rRec.aPos ) )
		{
			SwRect aActRect( aRect );
			Size aActSz( aRect.SSize() );
			aRect.Pos().X() += rRec.nTol;
			aRect.Pos().Y() += rRec.nTol;
			aRect.SSize().Height()-= 2 * rRec.nTol;
			aRect.SSize().Width() -= 2 * rRec.nTol;

			if( aRect.IsInside( rRec.aPos ) )
			{
				if( !rURL.GetMap() ||
					pFlyFrm->GetFmt()->GetIMapObject( rRec.aPos, pFlyFrm ))
					return (SdrObject*)this;

				return 0;
			}
		}
	}
	return SdrObject::CheckMacroHit( rRec );
}

bool SwVirtFlyDrawObj::supportsFullDrag() const
{
    // call parent
    return SdrVirtObj::supportsFullDrag();
}

SdrObject* SwVirtFlyDrawObj::getFullDragClone() const
{
    // call parent
    return SdrVirtObj::getFullDragClone();
}

// eof
