/**************************************************************
 * 
 * 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 <editeng/protitem.hxx>
#include <svx/svdpagv.hxx>
#include <svx/fmmodel.hxx>
#include <sot/exchange.hxx>
#include <svx/sdrundomanager.hxx>
#include <editeng/outliner.hxx>
#include <com/sun/star/embed/EmbedMisc.hpp>

#include "swtypes.hxx"
#include "pagefrm.hxx"
#include "rootfrm.hxx"
#include "cntfrm.hxx"
#include "flyfrm.hxx"
#include "frmfmt.hxx"
#include "dflyobj.hxx"
#include "dcontact.hxx"
#include "frmatr.hxx"
#include "viewsh.hxx"
#include "viewimp.hxx"
#include "dview.hxx"
#include "dpage.hxx"
#include "doc.hxx"
#include "mdiexp.hxx"
#include <ndole.hxx>
#include <fmtanchr.hxx>
#include "shellres.hxx"
#include <IDocumentUndoRedo.hxx>
#include <vector>
#include <sortedobjs.hxx>
#include <flyfrms.hxx>
#include <UndoManager.hxx>

using namespace com::sun::star;

class SwSdrHdl : public SdrHdl
{
public:
    SwSdrHdl(const Point& rPnt, bool bTopRight ) :
        SdrHdl( rPnt, bTopRight ? HDL_ANCHOR_TR : HDL_ANCHOR ) {}
    virtual sal_Bool IsFocusHdl() const;
};

sal_Bool SwSdrHdl::IsFocusHdl() const
{
    if( HDL_ANCHOR == eKind || HDL_ANCHOR_TR == eKind )
        return sal_True;
    return SdrHdl::IsFocusHdl();
}

const SwFrm *lcl_FindAnchor( const SdrObject *pObj, sal_Bool bAll )
{
	const SwVirtFlyDrawObj *pVirt = pObj->ISA(SwVirtFlyDrawObj) ?
											(SwVirtFlyDrawObj*)pObj : 0;
	if ( pVirt )
	{
		if ( bAll || !pVirt->GetFlyFrm()->IsFlyInCntFrm() )
            return pVirt->GetFlyFrm()->GetAnchorFrm();
	}
	else
	{
        const SwDrawContact *pCont = (const SwDrawContact*)GetUserCall(pObj);
		if ( pCont )
            return pCont->GetAnchorFrm( pObj );
	}
	return 0;
}

/*************************************************************************
|*
|*	SwDrawView::Ctor
|*
|*	Ersterstellung		OK 18.11.94
|*	Letzte Aenderung	MA 22. Jul. 96
|*
*************************************************************************/



SwDrawView::SwDrawView( SwViewImp &rI, SdrModel *pMd, OutputDevice *pOutDev) :
	FmFormView( (FmFormModel*)pMd, pOutDev ),
	rImp( rI )
{
	SetPageVisible( sal_False );
	SetBordVisible( sal_False );
	SetGridVisible( sal_False );
	SetHlplVisible( sal_False );
	SetGlueVisible( sal_False );
	SetFrameDragSingles( sal_True );
	SetVirtualObjectBundling( sal_True );
	SetSwapAsynchron( sal_True );

	EnableExtendedKeyInputDispatcher( sal_False );
	EnableExtendedMouseEventDispatcher( sal_False );
	EnableExtendedCommandEventDispatcher( sal_False );

	SetHitTolerancePixel( GetMarkHdlSizePixel()/2 );

	SetPrintPreview( rI.GetShell()->IsPreView() );

	// #i73602# Use default from the configuration
	SetBufferedOverlayAllowed(getOptionsDrawinglayer().IsOverlayBuffer_Writer());

	// #i74769#, #i75172# Use default from the configuration
	SetBufferedOutputAllowed(getOptionsDrawinglayer().IsPaintBuffer_Writer());
}

// --> OD 2009-03-05 #i99665#
sal_Bool SwDrawView::IsAntiAliasing() const
{
    return getOptionsDrawinglayer().IsAntiAliasing();
}
// <--

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

SdrObject* impLocalHitCorrection(SdrObject* pRetval, const Point& rPnt, sal_uInt16 nTol, const SdrMarkList &rMrkList)
{
    if(!nTol)
    {
        // the old method forced back to outer bounds test when nTol == 0, so
        // do not try to correct when nTol is not set (used from HelpContent)
    }
    else
    {
        // rebuild logic from former SwVirtFlyDrawObj::CheckSdrObjectHit. This is needed since
        // the SdrObject-specific CheckHit implementations are now replaced with primitives and
        // 'tricks' like in the old implementation (e.g. using a view from a model-data class to
        // detect if object is selected) are no longer valid.
        // The standard primitive hit-test for SwVirtFlyDrawObj now is the outer bound. The old
        // implementation reduced this excluding the inner bound when the object was not selected.
        SwVirtFlyDrawObj* pSwVirtFlyDrawObj = dynamic_cast< SwVirtFlyDrawObj* >(pRetval);

        if(pSwVirtFlyDrawObj)
        {
            if(pSwVirtFlyDrawObj->GetFlyFrm()->Lower() && pSwVirtFlyDrawObj->GetFlyFrm()->Lower()->IsNoTxtFrm())
			{
                // the old method used IsNoTxtFrm (should be for SW's own OLE and
                // graphic's) to accept hit only based on outer bounds; nothing to do
            }
            else
            {
                // check if the object is selected in this view
                const sal_uInt32 nMarkCount(rMrkList.GetMarkCount());
                bool bSelected(false);

                for(sal_uInt32 a(0); !bSelected && a < nMarkCount; a++)
                {
                    if(pSwVirtFlyDrawObj == rMrkList.GetMark(a)->GetMarkedSdrObj())
                    {
                        bSelected = true;
                    }
                }

                if(!bSelected)
                {
                    // when not selected, the object is not hit when hit position is inside
                    // inner range. Get and shrink inner range
                    basegfx::B2DRange aInnerBound(pSwVirtFlyDrawObj->getInnerBound());

                    aInnerBound.grow(-1.0 * nTol);

                    if(aInnerBound.isInside(basegfx::B2DPoint(rPnt.X(), rPnt.Y())))
                    {
                        // exclude this hit
                        pRetval = 0;
                    }
                }
            }
        }
    }

    return pRetval;
}

SdrObject* SwDrawView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, sal_uLong nOptions, const SetOfByte* pMVisLay) const
{
    // call parent
    SdrObject* pRetval = FmFormView::CheckSingleSdrObjectHit(rPnt, nTol, pObj, pPV, nOptions, pMVisLay);

    if(pRetval)
    {
        // overloaded to allow extra handling when picking SwVirtFlyDrawObj's
        pRetval = impLocalHitCorrection(pRetval, rPnt, nTol, GetMarkedObjectList());
    }

    return pRetval;
}

/*************************************************************************
|*
|*	SwDrawView::AddCustomHdl()
|*
|*  Gets called every time the handles need to be build
|*
|*	Ersterstellung		AW 06. Sep. 99
|*	Letzte Aenderung	AW 06. Sep. 99
|*
*************************************************************************/

void SwDrawView::AddCustomHdl()
{
	const SdrMarkList &rMrkList = GetMarkedObjectList();

	if(rMrkList.GetMarkCount() != 1 || !GetUserCall(rMrkList.GetMark( 0 )->GetMarkedSdrObj()))
		return;

	SdrObject *pObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
    // --> OD 2006-11-06 #130889# - make code robust
//    const SwFmtAnchor &rAnchor = ::FindFrmFmt(pObj)->GetAnchor();
    SwFrmFmt* pFrmFmt( ::FindFrmFmt( pObj ) );
    if ( !pFrmFmt )
    {
        ASSERT( false, "<SwDrawView::AddCustomHdl()> - missing frame format!" );
        return;
    }
    const SwFmtAnchor &rAnchor = pFrmFmt->GetAnchor();
    // <--

    if (FLY_AS_CHAR == rAnchor.GetAnchorId())
		return;

	const SwFrm* pAnch;
	if(0 == (pAnch = CalcAnchor()))
		return;

    Point aPos(aAnchorPoint);

    if ( FLY_AT_CHAR == rAnchor.GetAnchorId() )
	{
        // --> OD 2004-06-24 #i28701# - use last character rectangle saved at object
        // in order to avoid a format of the anchor frame
        SwAnchoredObject* pAnchoredObj = ::GetUserCall( pObj )->GetAnchoredObj( pObj );
        SwRect aAutoPos = pAnchoredObj->GetLastCharRect();
        if ( aAutoPos.Height() )
        {
            aPos = aAutoPos.Pos();
        }
	}

	// add anchor handle:
    //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
    aHdl.AddHdl( new SwSdrHdl( aPos, ( pAnch->IsVertical() && !pAnch->IsVertLR() ) ||
                                     pAnch->IsRightToLeft() ) );	
}

/*************************************************************************
|*
|*	SwDrawView::GetMaxToTopObj(), _GetMaxToTopObj()
|*
|*	Ersterstellung		MA 13. Jan. 95
|*	Letzte Aenderung	MA 18. Mar. 97
|*
*************************************************************************/


SdrObject* SwDrawView::GetMaxToTopObj( SdrObject* pObj ) const
{
	if ( GetUserCall(pObj) )
	{
		const SwFrm *pAnch = ::lcl_FindAnchor( pObj, sal_False );
		if ( pAnch )
		{
			//Das oberste Obj innerhalb des Ankers darf nicht ueberholt
			//werden.
			const SwFlyFrm *pFly = pAnch->FindFlyFrm();
			if ( pFly )
			{
				const SwPageFrm *pPage = pFly->FindPageFrm();
				if ( pPage->GetSortedObjs() )
				{
					sal_uInt32 nOrdNum = 0;
					for ( sal_uInt16 i = 0; i < pPage->GetSortedObjs()->Count(); ++i )
					{
                        const SdrObject *pO =
                                    (*pPage->GetSortedObjs())[i]->GetDrawObj();

                        if ( pO->GetOrdNumDirect() > nOrdNum )
						{
                            const SwFrm *pTmpAnch = ::lcl_FindAnchor( pO, sal_False );
                            if ( pFly->IsAnLower( pTmpAnch ) )
							{
								nOrdNum = pO->GetOrdNumDirect();
							}
						}
					}
					if ( nOrdNum )
					{
                        SdrPage *pTmpPage = GetModel()->GetPage( 0 );
						++nOrdNum;
                        if ( nOrdNum < pTmpPage->GetObjCount() )
						{
                            return pTmpPage->GetObj( nOrdNum );
						}
					}
				}
			}
		}
	}
	return 0;
}

/*************************************************************************
|*
|*	SwDrawView::GetMaxToBtmObj()
|*
|*	Ersterstellung		MA 13. Jan. 95
|*	Letzte Aenderung	MA 05. Sep. 96
|*
*************************************************************************/


SdrObject* SwDrawView::GetMaxToBtmObj(SdrObject* pObj) const
{
	if ( GetUserCall(pObj) )
	{
		const SwFrm *pAnch = ::lcl_FindAnchor( pObj, sal_False );
		if ( pAnch )
		{
			//Der Fly des Ankers darf nicht "unterflogen" werden.
			const SwFlyFrm *pFly = pAnch->FindFlyFrm();
			if ( pFly )
			{
				SdrObject *pRet = (SdrObject*)pFly->GetVirtDrawObj();
				return pRet != pObj ? pRet : 0;
			}
		}
	}
	return 0;
}

/*************************************************************************
|*
|*	SwDrawView::ObjOrderChanged()
|*
|*	Ersterstellung		MA 31. Jul. 95
|*	Letzte Aenderung	MA 18. Mar. 97
|*
*************************************************************************/

inline sal_Bool lcl_IsChild( SdrObject *pParent, SdrObject *pChild )
{
	if ( pParent->ISA(SwVirtFlyDrawObj) )
	{
		const SwFrm *pAnch = lcl_FindAnchor( pChild, sal_False );
		if ( pAnch && ((SwVirtFlyDrawObj*)pParent)->GetFlyFrm()->IsAnLower( pAnch ))
		{
			return sal_True;
		}
	}
	return sal_False;
}

inline SdrObject *lcl_FindParent( SdrObject *pObj )
{
	const SwFrm *pAnch = lcl_FindAnchor( pObj, sal_False );
	if ( pAnch && pAnch->IsInFly() )
		return (SdrObject*)pAnch->FindFlyFrm()->GetVirtDrawObj();
	return 0;
}

/** determine maximal order number for a 'child' object of given 'parent' object

    OD 2004-08-20 #110810#

    @author OD
*/
sal_uInt32 SwDrawView::_GetMaxChildOrdNum( const SwFlyFrm& _rParentObj,
                                           const SdrObject* _pExclChildObj ) const
{
    sal_uInt32 nMaxChildOrdNum = _rParentObj.GetDrawObj()->GetOrdNum();

    const SdrPage* pDrawPage = _rParentObj.GetDrawObj()->GetPage();
    ASSERT( pDrawPage,
            "<SwDrawView::_GetMaxChildOrdNum(..) - missing drawing page at parent object - crash!" );

    sal_uInt32 nObjCount = pDrawPage->GetObjCount();
    for ( sal_uInt32 i = nObjCount-1; i > _rParentObj.GetDrawObj()->GetOrdNum() ; --i )
    {
        const SdrObject* pObj = pDrawPage->GetObj( i );

        // Don't consider 'child' object <_pExclChildObj>
        if ( pObj == _pExclChildObj )
        {
            continue;
        }

        if ( pObj->GetOrdNum() > nMaxChildOrdNum &&
             _rParentObj.IsAnLower( lcl_FindAnchor( pObj, sal_True ) ) )
        {
            nMaxChildOrdNum = pObj->GetOrdNum();
            break;
        }
    }

    return nMaxChildOrdNum;
}

/** method to move 'repeated' objects of the given moved object to the
    according level

    OD 2004-08-23 #110810#

    @author OD
*/
void SwDrawView::_MoveRepeatedObjs( const SwAnchoredObject& _rMovedAnchoredObj,
                                    const std::vector<SdrObject*>& _rMovedChildObjs ) const
{
    // determine 'repeated' objects of already moved object <_rMovedAnchoredObj>
    std::list<SwAnchoredObject*> aAnchoredObjs;
    {
        const SwContact* pContact = ::GetUserCall( _rMovedAnchoredObj.GetDrawObj() );
        ASSERT( pContact,
                "SwDrawView::_MoveRepeatedObjs(..) - missing contact object -> crash." );
        pContact->GetAnchoredObjs( aAnchoredObjs );
    }

    // check, if 'repeated' objects exists.
    if ( aAnchoredObjs.size() > 1 )
    {
        SdrPage* pDrawPage = GetModel()->GetPage( 0 );

        // move 'repeated' ones to the same order number as the already moved one.
        sal_uInt32 nNewPos = _rMovedAnchoredObj.GetDrawObj()->GetOrdNum();
        while ( !aAnchoredObjs.empty() )
        {
            SwAnchoredObject* pAnchoredObj = aAnchoredObjs.back();
            if ( pAnchoredObj != &_rMovedAnchoredObj )
            {
                pDrawPage->SetObjectOrdNum( pAnchoredObj->GetDrawObj()->GetOrdNum(),
                                            nNewPos );
                pDrawPage->RecalcObjOrdNums();
                // adjustments for accessibility API
                if ( pAnchoredObj->ISA(SwFlyFrm) )
                {
                    const SwFlyFrm *pTmpFlyFrm = static_cast<SwFlyFrm*>(pAnchoredObj);
                    rImp.DisposeAccessibleFrm( pTmpFlyFrm );
                    rImp.AddAccessibleFrm( pTmpFlyFrm );
                }
                else
                {
                    rImp.DisposeAccessibleObj( pAnchoredObj->GetDrawObj() );
                    rImp.AddAccessibleObj( pAnchoredObj->GetDrawObj() );
                }
            }
            aAnchoredObjs.pop_back();
        }

        // move 'repeated' ones of 'child' objects
        for ( std::vector<SdrObject*>::const_iterator aObjIter = _rMovedChildObjs.begin();
              aObjIter != _rMovedChildObjs.end(); ++aObjIter )
        {
            SdrObject* pChildObj = (*aObjIter);
            {
                const SwContact* pContact = ::GetUserCall( pChildObj );
                ASSERT( pContact,
                        "SwDrawView::_MoveRepeatedObjs(..) - missing contact object -> crash." );
                pContact->GetAnchoredObjs( aAnchoredObjs );
            }
            // move 'repeated' ones to the same order number as the already moved one.
            const sal_uInt32 nTmpNewPos = pChildObj->GetOrdNum();
            while ( !aAnchoredObjs.empty() )
            {
                SwAnchoredObject* pAnchoredObj = aAnchoredObjs.back();
                if ( pAnchoredObj->GetDrawObj() != pChildObj )
                {
                    pDrawPage->SetObjectOrdNum( pAnchoredObj->GetDrawObj()->GetOrdNum(),
                                                nTmpNewPos );
                    pDrawPage->RecalcObjOrdNums();
                    // adjustments for accessibility API
                    if ( pAnchoredObj->ISA(SwFlyFrm) )
                    {
                        const SwFlyFrm *pTmpFlyFrm = static_cast<SwFlyFrm*>(pAnchoredObj);
                        rImp.DisposeAccessibleFrm( pTmpFlyFrm );
                        rImp.AddAccessibleFrm( pTmpFlyFrm );
                    }
                    else
                    {
                        rImp.DisposeAccessibleObj( pAnchoredObj->GetDrawObj() );
                        rImp.AddAccessibleObj( pAnchoredObj->GetDrawObj() );
                    }
                }
                aAnchoredObjs.pop_back();
            }
        }
    }
}

// --> OD 2004-08-20 #110810# - adjustment and re-factoring of method
void SwDrawView::ObjOrderChanged( SdrObject* pObj, sal_uLong nOldPos,
										  sal_uLong nNewPos )
{
    // --> OD 2004-08-17 #110810# - nothing to do for group members
    if ( pObj->GetUpGroup() )
    {
        return;
    }
    // <--

    // determine drawing page and assure that the order numbers are correct.
    SdrPage* pDrawPage = GetModel()->GetPage( 0 );
    if ( pDrawPage->IsObjOrdNumsDirty() )
        pDrawPage->RecalcObjOrdNums();
    const sal_uInt32 nObjCount = pDrawPage->GetObjCount();

    SwAnchoredObject* pMovedAnchoredObj =
                                ::GetUserCall( pObj )->GetAnchoredObj( pObj );
    const SwFlyFrm* pParentAnchoredObj =
                                pMovedAnchoredObj->GetAnchorFrm()->FindFlyFrm();

    const bool bMovedForward = nOldPos < nNewPos;

    // assure for a 'child' object, that it doesn't exceed the limits of its 'parent'
    if ( pParentAnchoredObj )
    {
        if ( bMovedForward )
        {
            sal_uInt32 nMaxChildOrdNumWithoutMoved =
                    _GetMaxChildOrdNum( *pParentAnchoredObj, pMovedAnchoredObj->GetDrawObj() );
            if ( nNewPos > nMaxChildOrdNumWithoutMoved+1 )
            {
                // set position to the top of the 'child' object group
                pDrawPage->SetObjectOrdNum( nNewPos, nMaxChildOrdNumWithoutMoved+1 );
                nNewPos = nMaxChildOrdNumWithoutMoved+1;
            }
        }
        else
        {
            const sal_uInt32 nParentOrdNum = pParentAnchoredObj->GetDrawObj()->GetOrdNum();
            if ( nNewPos < nParentOrdNum )
            {
                // set position to the bottom of the 'child' object group
                pDrawPage->SetObjectOrdNum( nNewPos, nParentOrdNum );
                nNewPos = nParentOrdNum;
            }
        }
        if ( pDrawPage->IsObjOrdNumsDirty() )
            pDrawPage->RecalcObjOrdNums();
    }

    // Assure, that object isn't positioned between 'repeated' ones
    if ( ( bMovedForward && nNewPos < nObjCount - 1 ) ||
         ( !bMovedForward && nNewPos > 0 ) )
    {
        const SdrObject* pTmpObj =
                pDrawPage->GetObj( bMovedForward ? nNewPos - 1 : nNewPos + 1 );
        if ( pTmpObj )
        {
            sal_uInt32 nTmpNewPos( nNewPos );
            if ( bMovedForward )
            {
                // move before the top 'repeated' object
                const sal_uInt32 nTmpMaxOrdNum =
                                    ::GetUserCall( pTmpObj )->GetMaxOrdNum();
                if ( nTmpMaxOrdNum > nNewPos )
                    nTmpNewPos = nTmpMaxOrdNum;
            }
            else
            {
                // move behind the bottom 'repeated' object
                const sal_uInt32 nTmpMinOrdNum =
                                    ::GetUserCall( pTmpObj )->GetMinOrdNum();
                if ( nTmpMinOrdNum < nNewPos )
                    nTmpNewPos = nTmpMinOrdNum;
            }
            if ( nTmpNewPos != nNewPos )
            {
                pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
                nNewPos = nTmpNewPos;
                pDrawPage->RecalcObjOrdNums();
            }
        }
    }

    // On move forward, assure that object is moved before its own childs.
    // Only Writer fly frames can have childs.
    if ( pMovedAnchoredObj->ISA(SwFlyFrm) &&
         bMovedForward && nNewPos < nObjCount - 1 )
    {
        sal_uInt32 nMaxChildOrdNum =
                    _GetMaxChildOrdNum( *(static_cast<const SwFlyFrm*>(pMovedAnchoredObj)) );
        if ( nNewPos < nMaxChildOrdNum )
        {
            // determine position before the object before its top 'child' object
            const SdrObject* pTmpObj = pDrawPage->GetObj( nMaxChildOrdNum );
            sal_uInt32 nTmpNewPos = ::GetUserCall( pTmpObj )->GetMaxOrdNum() + 1;
            if ( nTmpNewPos >= nObjCount )
            {
                --nTmpNewPos;
            }
            // assure, that determined position isn't between 'repeated' objects
            pTmpObj = pDrawPage->GetObj( nTmpNewPos );
            nTmpNewPos = ::GetUserCall( pTmpObj )->GetMaxOrdNum();
            // apply new position
            pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
            nNewPos = nTmpNewPos;
            pDrawPage->RecalcObjOrdNums();
        }
    }

    // Assure, that object isn't positioned between nested objects
    if ( ( bMovedForward && nNewPos < nObjCount - 1 ) ||
         ( !bMovedForward && nNewPos > 0 ) )
    {
        sal_uInt32 nTmpNewPos( nNewPos );
        const SwFrmFmt* pParentFrmFmt =
                pParentAnchoredObj ? &(pParentAnchoredObj->GetFrmFmt()) : 0L;
        const SdrObject* pTmpObj = pDrawPage->GetObj( nNewPos + 1 );
        while ( pTmpObj )
        {
            // --> OD 2004-12-07 #i38563# - assure, that anchor frame exists.
            // If object is anchored inside a invisible part of the document
            // (e.g. page header, whose page style isn't applied, or hidden
            // section), no anchor frame exists.
            const SwFrm* pTmpAnchorFrm = lcl_FindAnchor( pTmpObj, sal_True );
            const SwFlyFrm* pTmpParentObj = pTmpAnchorFrm
                                            ? pTmpAnchorFrm->FindFlyFrm() : 0L;
            // <--
            if ( pTmpParentObj &&
                 &(pTmpParentObj->GetFrmFmt()) != pParentFrmFmt )
            {
                if ( bMovedForward )
                {
                    nTmpNewPos = ::GetUserCall( pTmpObj )->GetMaxOrdNum();
                    pTmpObj = pDrawPage->GetObj( nTmpNewPos + 1 );
                }
                else
                {
                    nTmpNewPos = ::GetUserCall( pTmpParentObj->GetDrawObj() )
                                                            ->GetMinOrdNum();
                    pTmpObj = pTmpParentObj->GetDrawObj();
                }
            }
            else
                break;
        }
        if ( nTmpNewPos != nNewPos )
        {
            pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
            nNewPos = nTmpNewPos;
            pDrawPage->RecalcObjOrdNums();
        }
    }

    // setup collection of moved 'child' objects to move its 'repeated' objects.
    std::vector< SdrObject* > aMovedChildObjs;

    // move 'childs' accordingly
    if ( pMovedAnchoredObj->ISA(SwFlyFrm) )
    {
        const SwFlyFrm* pFlyFrm = static_cast<SwFlyFrm*>(pMovedAnchoredObj);

        // adjustments for accessibility API
        rImp.DisposeAccessibleFrm( pFlyFrm );
        rImp.AddAccessibleFrm( pFlyFrm );

        const sal_uInt32 nChildNewPos = bMovedForward ? nNewPos : nNewPos+1;
        sal_uInt32 i = bMovedForward ? nOldPos : nObjCount-1;
        do
        {
            SdrObject* pTmpObj = pDrawPage->GetObj( i );
            if ( pTmpObj == pObj )
                break;

            // --> OD 2004-12-07 #i38563# - assure, that anchor frame exists.
            // If object is anchored inside a invisible part of the document
            // (e.g. page header, whose page style isn't applied, or hidden
            // section), no anchor frame exists.
            const SwFrm* pTmpAnchorFrm = lcl_FindAnchor( pTmpObj, sal_True );
            const SwFlyFrm* pTmpParentObj = pTmpAnchorFrm
                                            ? pTmpAnchorFrm->FindFlyFrm() : 0L;
            // <--
            if ( pTmpParentObj &&
                 ( ( pTmpParentObj == pFlyFrm ) ||
                   ( pFlyFrm->IsUpperOf( *pTmpParentObj ) ) ) )
            {
                // move child object.,
                pDrawPage->SetObjectOrdNum( i, nChildNewPos );
                pDrawPage->RecalcObjOrdNums();
                // collect 'child' object
                aMovedChildObjs.push_back( pTmpObj );
                // adjustments for accessibility API
                if ( pTmpObj->ISA(SwVirtFlyDrawObj) )
                {
                    const SwFlyFrm *pTmpFlyFrm =
                        static_cast<SwVirtFlyDrawObj*>(pTmpObj)->GetFlyFrm();
                    rImp.DisposeAccessibleFrm( pTmpFlyFrm );
                    rImp.AddAccessibleFrm( pTmpFlyFrm );
                }
                else
                {
                    rImp.DisposeAccessibleObj( pTmpObj );
                    rImp.AddAccessibleObj( pTmpObj );
                }
            }
            else
            {
                // adjust loop counter
                if ( bMovedForward )
                    ++i;
                else if ( !bMovedForward && i > 0 )
                    --i;
            }

        } while ( ( bMovedForward && i < ( nObjCount - aMovedChildObjs.size() ) ) ||
                  ( !bMovedForward && i > ( nNewPos + aMovedChildObjs.size() ) ) );
    }
	else
	{
        // adjustments for accessibility API
		rImp.DisposeAccessibleObj( pObj );
		rImp.AddAccessibleObj( pObj );
	}

    _MoveRepeatedObjs( *pMovedAnchoredObj, aMovedChildObjs );
}
// <--

/*************************************************************************
|*
|*	SwDrawView::TakeDragLimit()
|*
|*	Ersterstellung		AMA 26. Apr. 96
|*	Letzte Aenderung	MA 03. May. 96
|*
*************************************************************************/


sal_Bool SwDrawView::TakeDragLimit( SdrDragMode eMode,
											Rectangle& rRect ) const
{
	const SdrMarkList &rMrkList = GetMarkedObjectList();
	sal_Bool bRet = sal_False;
	if( 1 == rMrkList.GetMarkCount() )
	{
		const SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
		SwRect aRect;
		if( ::CalcClipRect( pObj, aRect, eMode == SDRDRAG_MOVE ) )
		{
			rRect = aRect.SVRect();
		 	bRet = sal_True;
		}
	}
	return bRet;
}

/*************************************************************************
|*
|*	SwDrawView::CalcAnchor()
|*
|*	Ersterstellung		MA 13. Jan. 95
|*	Letzte Aenderung	MA 08. Nov. 96
|*
*************************************************************************/


const SwFrm* SwDrawView::CalcAnchor()
{
	const SdrMarkList &rMrkList = GetMarkedObjectList();
	if ( rMrkList.GetMarkCount() != 1 )
		return NULL;

    SdrObject* pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();

	//Fuer Absatzgebundene Objekte suchen, andernfalls einfach nur
	//der aktuelle Anker. Nur suchen wenn wir gerade draggen.
    const SwFrm* pAnch;
    Rectangle aMyRect;
	const sal_Bool bFly = pObj->ISA(SwVirtFlyDrawObj);
	if ( bFly )
	{
        pAnch = ((SwVirtFlyDrawObj*)pObj)->GetFlyFrm()->GetAnchorFrm();
        aMyRect = ((SwVirtFlyDrawObj*)pObj)->GetFlyFrm()->Frm().SVRect();
	}
	else
	{
        SwDrawContact *pC = (SwDrawContact*)GetUserCall(pObj);
        // OD 17.06.2003 #108784# - determine correct anchor position for
        // 'virtual' drawing objects.
        // OD 2004-03-25 #i26791#
        pAnch = pC->GetAnchorFrm( pObj );
		if( !pAnch )
		{
			pC->ConnectToLayout();
            // OD 17.06.2003 #108784# - determine correct anchor position for
            // 'virtual' drawing objects.
            // OD 2004-03-25 #i26791#
            pAnch = pC->GetAnchorFrm( pObj );
		}
        aMyRect = pObj->GetSnapRect();
	}

	//Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
    const sal_Bool bTopRight = pAnch && ( ( pAnch->IsVertical() && 
    										!pAnch->IsVertLR() ) ||
                                         	pAnch->IsRightToLeft() );
    const Point aMyPt = bTopRight ? aMyRect.TopRight() : aMyRect.TopLeft();

    Point aPt;
    if ( IsAction() )
    {
        if ( !TakeDragObjAnchorPos( aPt, bTopRight ) )
            return NULL;
    }
    else
    {
        Rectangle aRect = pObj->GetSnapRect();
        aPt = bTopRight ? aRect.TopRight() : aRect.TopLeft();
    }

    if ( aPt != aMyPt )
	{
		if ( pAnch->IsCntntFrm() )
        {
            // OD 26.06.2003 #108784# - allow drawing objects in header/footer,
            // but exclude control objects.
            bool bBodyOnly = CheckControlLayer( pObj );
            pAnch = ::FindAnchor( (SwCntntFrm*)pAnch, aPt, bBodyOnly );
        }
		else if ( !bFly )
        {
            const SwRect aRect( aPt.X(), aPt.Y(), 1, 1 );

            SwDrawContact* pContact = (SwDrawContact*)GetUserCall(pObj);
            if ( pContact->GetAnchorFrm( pObj ) &&
                 pContact->GetAnchorFrm( pObj )->IsPageFrm() )
                pAnch = pContact->GetPageFrm();
			else
				pAnch = pContact->FindPage( aRect );
		}
	}
	if( pAnch && !pAnch->IsProtected() )
        aAnchorPoint = pAnch->GetFrmAnchorPos( ::HasWrap( pObj ) );
	else
		pAnch = 0;
	return pAnch;
}

/*************************************************************************
|*
|*	SwDrawView::ShowDragXor(), HideDragXor()
|*
|*	Ersterstellung		MA 17. Jan. 95
|*	Letzte Aenderung	MA 27. Jan. 95
|*
*************************************************************************/


void SwDrawView::ShowDragAnchor()
{
	SdrHdl* pHdl = aHdl.GetHdl(HDL_ANCHOR);
	if ( ! pHdl )
		pHdl = aHdl.GetHdl(HDL_ANCHOR_TR);

	if(pHdl)
	{
		CalcAnchor();
		pHdl->SetPos(aAnchorPoint);
		//OLMRefreshAllIAOManagers();
	}
}

/*************************************************************************
|*
|*	SwDrawView::MarkListHasChanged()
|*
|*	Ersterstellung		OM 02. Feb. 95
|*	Letzte Aenderung	OM 07. Jul. 95
|*
*************************************************************************/


void SwDrawView::MarkListHasChanged()
{
    Imp().GetShell()->DrawSelChanged();
	FmFormView::MarkListHasChanged();
}

// #i7672#
void SwDrawView::ModelHasChanged()
{
	// The ModelHasChanged() call in DrawingLayer also updates
	// a eventually active text edit view (OutlinerView). This also leads
	// to newly setting the background color for that edit view. Thus,
	// this method rescues the current background color if a OutlinerView
	// exists and re-establishes it then. To be more safe, the OutlinerView
	// will be fetched again (maybe textedit has ended).
	OutlinerView* pView = GetTextEditOutlinerView();
	Color aBackColor;
	sal_Bool bColorWasSaved(sal_False);

	if(pView)
	{
		aBackColor = pView->GetBackgroundColor();
		bColorWasSaved = sal_True;
	}

	// call parent
	FmFormView::ModelHasChanged();

	if(bColorWasSaved)
	{
		pView = GetTextEditOutlinerView();

		if(pView)
		{
			pView->SetBackgroundColor(aBackColor);
		}
	}
}

void SwDrawView::MakeVisible( const Rectangle &rRect, Window & )
{
    ASSERT( rImp.GetShell()->GetWin(), "MakeVisible, unknown Window");
	rImp.GetShell()->MakeVisible( SwRect( rRect ) );
}

void SwDrawView::CheckPossibilities()
{
	FmFormView::CheckPossibilities();

	//Zusaetzlich zu den bestehenden Flags der Objekte selbst, die von der
	//DrawingEngine ausgewertet werden, koennen weitere Umstaende zu einem
	//Schutz fuehren.
	//Objekte, die in Rahmen verankert sind, muessen genau dann geschuetzt
	//sein, wenn der Inhalt des Rahmens geschuetzt ist.
	//OLE-Objekte konnen selbst einen Resize-Schutz wuenschen (StarMath)

	const SdrMarkList &rMrkList = GetMarkedObjectList();
	sal_Bool bProtect = sal_False,
			 bSzProtect = sal_False;
	for ( sal_uInt16 i = 0; !bProtect && i < rMrkList.GetMarkCount(); ++i )
	{
		const SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
		const SwFrm *pFrm = NULL;
		if ( pObj->ISA(SwVirtFlyDrawObj) )
		{
			const SwFlyFrm *pFly = ((SwVirtFlyDrawObj*)pObj)->GetFlyFrm();
			if ( pFly  )
			{
                pFrm = pFly->GetAnchorFrm();
				if ( pFly->Lower() && pFly->Lower()->IsNoTxtFrm() )
				{
					SwOLENode *pNd = ((SwCntntFrm*)pFly->Lower())->GetNode()->GetOLENode();
					if ( pNd )
					{
                        uno::Reference < embed::XEmbeddedObject > xObj = pNd->GetOLEObj().GetOleRef();
                        if ( xObj.is() )
						{
                            // --> OD 2004-08-16 #110810# - improvement for
                            // the future, when more than one Writer fly frame
                            // can be selected.

                            // TODO/LATER: retrieve Aspect - from where?!
                            bSzProtect |= ( embed::EmbedMisc::EMBED_NEVERRESIZE & xObj->getStatus( embed::Aspects::MSOLE_CONTENT ) ) ? sal_True : sal_False;

                            // <--

                            // #i972: protect position if it is a Math object anchored 'as char' and baseline alignment is activated
                        	SwDoc* pDoc = Imp().GetShell()->GetDoc();
                            const bool bProtectMathPos = SotExchange::IsMath( xObj->getClassID() ) 
                                    && FLY_AS_CHAR == pFly->GetFmt()->GetAnchor().GetAnchorId() 
                                    && pDoc->get( IDocumentSettingAccess::MATH_BASELINE_ALIGNMENT );
                            if (bProtectMathPos)
                                bMoveProtect = true;
                        }
					}
				}
			}
		}
		else
		{
			SwDrawContact *pC = (SwDrawContact*)GetUserCall(pObj);
            if ( pC )
                pFrm = pC->GetAnchorFrm( pObj );
		}
		if ( pFrm )
			bProtect = pFrm->IsProtected(); //Rahmen, Bereiche usw.
        {
            SwFrmFmt* pFrmFmt( ::FindFrmFmt( const_cast<SdrObject*>(pObj) ) );
            if ( !pFrmFmt )
            {
                ASSERT( false,
                        "<SwDrawView::CheckPossibilities()> - missing frame format" );
                bProtect = sal_True;
            }
            else if ((FLY_AS_CHAR == pFrmFmt->GetAnchor().GetAnchorId()) &&
                      rMrkList.GetMarkCount() > 1 )
            {
                bProtect = sal_True;
            }
        }
	}
	bMoveProtect	|= bProtect;
	bResizeProtect	|= bProtect | bSzProtect;
}

/** replace marked <SwDrawVirtObj>-objects by its reference object for delete
    marked objects.

    OD 18.06.2003 #108784#

    @author OD
*/
void SwDrawView::ReplaceMarkedDrawVirtObjs( SdrMarkView& _rMarkView )
{
    SdrPageView* pDrawPageView = _rMarkView.GetSdrPageView();
    const SdrMarkList& rMarkList = _rMarkView.GetMarkedObjectList();

    if( rMarkList.GetMarkCount() )
    {
        // collect marked objects in a local data structure
        std::vector<SdrObject*> aMarkedObjs;
        for( sal_uInt32 i = 0; i < rMarkList.GetMarkCount(); ++i )
        {
            SdrObject* pMarkedObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
            aMarkedObjs.push_back( pMarkedObj );
        }
        // unmark all objects
        _rMarkView.UnmarkAllObj();
        // re-mark objects, but for marked <SwDrawVirtObj>-objects marked its
        // reference object.
        while ( !aMarkedObjs.empty() )
        {
            SdrObject* pMarkObj = aMarkedObjs.back();
            if ( pMarkObj->ISA(SwDrawVirtObj) )
            {
                SdrObject* pRefObj = &(static_cast<SwDrawVirtObj*>(pMarkObj)->ReferencedObj());
                if ( !_rMarkView.IsObjMarked( pRefObj )  )
                {
                    _rMarkView.MarkObj( pRefObj, pDrawPageView );
                }
            }
            else
            {
                _rMarkView.MarkObj( pMarkObj, pDrawPageView );
            }

            aMarkedObjs.pop_back();
        }
        // sort marked list in order to assure consistent state in drawing layer
        _rMarkView.SortMarkedObjects();
    }
}

void SwDrawView::DeleteMarked()
{
	SwDoc* pDoc = Imp().GetShell()->GetDoc();
	SwRootFrm *pTmpRoot = pDoc->GetCurrentLayout();//swmod 080317
    if ( pTmpRoot )
		pTmpRoot->StartAllAction();	
    pDoc->GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
    // OD 18.06.2003 #108784# - replace marked <SwDrawVirtObj>-objects by its
    // reference objects.
    {
        SdrPageView* pDrawPageView = rImp.GetPageView();
        if ( pDrawPageView )
        {
            SdrMarkView* pMarkView = PTR_CAST( SdrMarkView, &(pDrawPageView->GetView()) );
            if ( pMarkView )
            {
                ReplaceMarkedDrawVirtObjs( *pMarkView );
            }
        }
    }
    if ( pDoc->DeleteSelection( *this ) )
	{
		FmFormView::DeleteMarked();
		::FrameNotify( Imp().GetShell(), FLY_DRAG_END );
	}
    pDoc->GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
	if( pTmpRoot )
		pTmpRoot->EndAllAction();	//swmod 080218
}

// support enhanced text edit for draw objects
SdrUndoManager* SwDrawView::getSdrUndoManagerForEnhancedTextEdit() const
{
	SwDoc* pDoc = Imp().GetShell()->GetDoc();

    return pDoc ? dynamic_cast< SdrUndoManager* >(&(pDoc->GetUndoManager())) : 0;
}

// eof
