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



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

#include <svx/svdpage.hxx>

// HACK
#include <sot/storage.hxx>
#include <sot/clsids.hxx>
#include <sot/storage.hxx>
#include <svx/svdview.hxx>
#include <string.h>
#ifndef _STRING_H
#define _STRING_H
#endif
#include <vcl/svapp.hxx>

#include <tools/diagnose_ex.h>

#include <svx/svdetc.hxx>
#include <svx/svdobj.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdograf.hxx> // fuer SwapInAll()
#include <svx/svdoedge.hxx> // Zum kopieren der Konnektoren
#include <svx/svdoole2.hxx> // Sonderbehandlung OLE beim SdrExchangeFormat
#include "svx/svditer.hxx"
#include <svx/svdmodel.hxx>
#include <svx/svdlayer.hxx>
#include <svx/svdotext.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdundo.hxx>
#include <svx/fmglob.hxx>
#include <svx/polysc3d.hxx>

#include <svx/fmdpage.hxx>

#include <sfx2/objsh.hxx>
#include <vcl/salbtype.hxx>		// FRound
#include <svx/sdr/contact/viewcontactofsdrpage.hxx>
#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <algorithm>
#include <svl/smplhint.hxx>

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

namespace {
void DumpObjectList (const ::std::vector<SdrObjectWeakRef>& rContainer)
{
    ::std::vector<SdrObjectWeakRef>::const_iterator iObject (rContainer.begin());
    ::std::vector<SdrObjectWeakRef>::const_iterator iEnd (rContainer.end());
    for (int nIndex=0 ; iObject!=iEnd; ++iObject,++nIndex)
    {
        const SdrObject* pObject = iObject->get();
        OSL_TRACE("%d : %x, %s", nIndex,
            pObject,
            ::rtl::OUStringToOString(pObject->GetName(),RTL_TEXTENCODING_UTF8).getStr());
    }
}
}


class SdrObjList::WeakSdrObjectContainerType
    : public ::std::vector<SdrObjectWeakRef>
{
public:
    WeakSdrObjectContainerType (const sal_Int32 nInitialSize)
        : ::std::vector<SdrObjectWeakRef>(nInitialSize) {};
};



static const sal_Int32 InitialObjectContainerCapacity (64);
DBG_NAME(SdrObjList)

TYPEINIT0(SdrObjList);

SdrObjList::SdrObjList(SdrModel* pNewModel, SdrPage* pNewPage, SdrObjList* pNewUpList):
	maList(),
    mpNavigationOrder(),
    mbIsNavigationOrderDirty(false)
{
	DBG_CTOR(SdrObjList,NULL);
	maList.reserve(InitialObjectContainerCapacity);
	pModel=pNewModel;
	pPage=pNewPage;
	pUpList=pNewUpList;
	bObjOrdNumsDirty=sal_False;
	bRectsDirty=sal_False;
	pOwnerObj=NULL;
	eListKind=SDROBJLIST_UNKNOWN;
}

SdrObjList::SdrObjList(const SdrObjList& rSrcList):
	maList(),
    mpNavigationOrder(),
    mbIsNavigationOrderDirty(false)
{
	DBG_CTOR(SdrObjList,NULL);
	maList.reserve(InitialObjectContainerCapacity);
	pModel=NULL;
	pPage=NULL;
	pUpList=NULL;
	bObjOrdNumsDirty=sal_False;
	bRectsDirty=sal_False;
	pOwnerObj=NULL;
	eListKind=SDROBJLIST_UNKNOWN;
	*this=rSrcList;
}

SdrObjList::~SdrObjList()
{
	DBG_DTOR(SdrObjList,NULL);

	// #111111#
	// To avoid that the Clear() method will broadcast changes when in destruction
	// which would call virtual methos (not allowed in destructor), the model is set
	// to NULL here.
	pModel = 0L;

	Clear(); // Containerinhalt loeschen!
}

void SdrObjList::operator=(const SdrObjList& rSrcList)
{
	Clear();
	eListKind=rSrcList.eListKind;
	CopyObjects(rSrcList);
}

void SdrObjList::CopyObjects(const SdrObjList& rSrcList)
{
	Clear();
	bObjOrdNumsDirty=sal_False;
	bRectsDirty     =sal_False;
	sal_uIntPtr nCloneErrCnt=0;
	sal_uIntPtr nAnz=rSrcList.GetObjCount();
	SdrInsertReason aReason(SDRREASON_COPY);
	sal_uIntPtr no;
	for (no=0; no<nAnz; no++) {
		SdrObject* pSO=rSrcList.GetObj(no);

		// #116235#
		//SdrObject* pDO=pSO->Clone(pPage,pModel);
		SdrObject* pDO = pSO->Clone();
		pDO->SetModel(pModel);
		pDO->SetPage(pPage);

		if (pDO!=NULL) {
			NbcInsertObject(pDO,CONTAINER_APPEND,&aReason);
		} else {
			nCloneErrCnt++;
		}
	}
	// und nun zu den Konnektoren
	// Die neuen Objekte werden auf die der rSrcList abgebildet
	// und so die Objektverbindungen hergestellt.
	// Aehnliche Implementation an folgenden Stellen:
	//    void SdrObjList::CopyObjects(const SdrObjList& rSrcList)
	//    SdrModel* SdrExchangeView::GetMarkedObjModel() const
	//    FASTBOOL SdrExchangeView::Paste(const SdrModel& rMod,...)
	//    void SdrEditView::CopyMarked()
	if (nCloneErrCnt==0) {
		for (no=0; no<nAnz; no++) {
			const SdrObject* pSrcOb=rSrcList.GetObj(no);
			SdrEdgeObj* pSrcEdge=PTR_CAST(SdrEdgeObj,pSrcOb);
			if (pSrcEdge!=NULL) {
				SdrObject* pSrcNode1=pSrcEdge->GetConnectedNode(sal_True);
				SdrObject* pSrcNode2=pSrcEdge->GetConnectedNode(sal_False);
				if (pSrcNode1!=NULL && pSrcNode1->GetObjList()!=pSrcEdge->GetObjList()) pSrcNode1=NULL; // Listenuebergreifend
				if (pSrcNode2!=NULL && pSrcNode2->GetObjList()!=pSrcEdge->GetObjList()) pSrcNode2=NULL; // ist (noch) nicht
				if (pSrcNode1!=NULL || pSrcNode2!=NULL) {
					SdrObject* pEdgeObjTmp=GetObj(no);
					SdrEdgeObj* pDstEdge=PTR_CAST(SdrEdgeObj,pEdgeObjTmp);
					if (pDstEdge!=NULL) {
						if (pSrcNode1!=NULL) {
							sal_uIntPtr nDstNode1=pSrcNode1->GetOrdNum();
							SdrObject* pDstNode1=GetObj(nDstNode1);
							if (pDstNode1!=NULL) { // Sonst grober Fehler!
								pDstEdge->ConnectToNode(sal_True,pDstNode1);
							} else {
								DBG_ERROR("SdrObjList::operator=(): pDstNode1==NULL!");
							}
						}
						if (pSrcNode2!=NULL) {
							sal_uIntPtr nDstNode2=pSrcNode2->GetOrdNum();
							SdrObject* pDstNode2=GetObj(nDstNode2);
							if (pDstNode2!=NULL) { // Node war sonst wohl nicht markiert
								pDstEdge->ConnectToNode(sal_False,pDstNode2);
							} else {
								DBG_ERROR("SdrObjList::operator=(): pDstNode2==NULL!");
							}
						}
					} else {
						DBG_ERROR("SdrObjList::operator=(): pDstEdge==NULL!");
					}
				}
			}
		}
	} else {
#ifdef DBG_UTIL
		ByteString aStr("SdrObjList::operator=(): Fehler beim Clonen ");

		if(nCloneErrCnt == 1)
		{
			aStr += "eines Zeichenobjekts.";
		}
		else
		{
			aStr += "von ";
			aStr += ByteString::CreateFromInt32( nCloneErrCnt );
			aStr += " Zeichenobjekten.";
		}

		aStr += " Objektverbindungen werden nicht mitkopiert.";

		DBG_ERROR(aStr.GetBuffer());
#endif
	}
}

void SdrObjList::Clear()
{
	sal_Bool bObjectsRemoved(sal_False);

	while( ! maList.empty())
	{
		// remove last object from list
		SdrObject* pObj = maList.back();
        RemoveObjectFromContainer(maList.size()-1);

		// flushViewObjectContacts() is done since SdrObject::Free is not guaranteed
		// to delete the object and thus refresh visualisations
        pObj->GetViewContact().flushViewObjectContacts(true);

		bObjectsRemoved = sal_True;

		// sent remove hint (after removal, see RemoveObject())
		if(pModel)
		{
			SdrHint aHint(*pObj);
			aHint.SetKind(HINT_OBJREMOVED);
			aHint.SetPage(pPage);
			pModel->Broadcast(aHint);
		}

		// delete the object itself
		SdrObject::Free( pObj );
	}

	if(pModel && bObjectsRemoved)
	{
		pModel->SetChanged();
	}
}

SdrPage* SdrObjList::GetPage() const
{
	return pPage;
}

void SdrObjList::SetPage(SdrPage* pNewPage)
{
	if (pPage!=pNewPage) {
		pPage=pNewPage;
		sal_uIntPtr nAnz=GetObjCount();
		for (sal_uIntPtr no=0; no<nAnz; no++) {
			SdrObject* pObj=GetObj(no);
			pObj->SetPage(pPage);
		}
	}
}

SdrModel* SdrObjList::GetModel() const
{
	return pModel;
}

void SdrObjList::SetModel(SdrModel* pNewModel)
{
	if (pModel!=pNewModel) {
		pModel=pNewModel;
		sal_uIntPtr nAnz=GetObjCount();
		for (sal_uIntPtr i=0; i<nAnz; i++) {
			SdrObject* pObj=GetObj(i);
			pObj->SetModel(pModel);
		}
	}
}

void SdrObjList::RecalcObjOrdNums()
{
	sal_uIntPtr nAnz=GetObjCount();
	for (sal_uIntPtr no=0; no<nAnz; no++) {
		SdrObject* pObj=GetObj(no);
		pObj->SetOrdNum(no);
	}
	bObjOrdNumsDirty=sal_False;
}

void SdrObjList::RecalcRects()
{
	aOutRect=Rectangle();
	aSnapRect=aOutRect;
	sal_uIntPtr nAnz=GetObjCount();
	sal_uIntPtr i;
	for (i=0; i<nAnz; i++) {
		SdrObject* pObj=GetObj(i);
		if (i==0) {
			aOutRect=pObj->GetCurrentBoundRect();
			aSnapRect=pObj->GetSnapRect();
		} else {
			aOutRect.Union(pObj->GetCurrentBoundRect());
			aSnapRect.Union(pObj->GetSnapRect());
		}
	}
}

void SdrObjList::SetRectsDirty()
{
	bRectsDirty=sal_True;
	if (pUpList!=NULL) pUpList->SetRectsDirty();
}

void SdrObjList::impChildInserted(SdrObject& rChild) const
{
	sdr::contact::ViewContact* pParent = rChild.GetViewContact().GetParentContact();
	
	if(pParent)
	{
		pParent->ActionChildInserted(rChild.GetViewContact());
	}
}

void SdrObjList::NbcInsertObject(SdrObject* pObj, sal_uIntPtr nPos, const SdrInsertReason* /*pReason*/)
{
	DBG_ASSERT(pObj!=NULL,"SdrObjList::NbcInsertObject(NULL)");
	if (pObj!=NULL) {
		DBG_ASSERT(!pObj->IsInserted(),"ZObjekt hat bereits Inserted-Status");
		sal_uIntPtr nAnz=GetObjCount();
		if (nPos>nAnz) nPos=nAnz;
        InsertObjectIntoContainer(*pObj,nPos);

		if (nPos<nAnz) bObjOrdNumsDirty=sal_True;
		pObj->SetOrdNum(nPos);
		pObj->SetObjList(this);
		pObj->SetPage(pPage);

		// #110094# Inform the parent about change to allow invalidations at
		// evtl. existing parent visualisations
		impChildInserted(*pObj);

		if (!bRectsDirty) {
			aOutRect.Union(pObj->GetCurrentBoundRect());
			aSnapRect.Union(pObj->GetSnapRect());
		}
		pObj->SetInserted(sal_True); // Ruft u.a. den UserCall
	}
}

void SdrObjList::InsertObject(SdrObject* pObj, sal_uIntPtr nPos, const SdrInsertReason* pReason)
{
	DBG_ASSERT(pObj!=NULL,"SdrObjList::InsertObject(NULL)");

	if(pObj)
	{
		// #69055# if anchor is used, reset it before grouping
		if(GetOwnerObj())
		{
			const Point& rAnchorPos = pObj->GetAnchorPos();
			if(rAnchorPos.X() || rAnchorPos.Y())
				pObj->NbcSetAnchorPos(Point());
		}

		// do insert to new group
		NbcInsertObject(pObj, nPos, pReason);

		// Falls das Objekt in eine Gruppe eingefuegt wird
		// und nicht mit seinen Bruedern ueberlappt, muss es
		// einen eigenen Redraw bekommen
		if(pOwnerObj)
		{
			// only repaint here
			pOwnerObj->ActionChanged();
		}

		if(pModel)
		{
			// Hier muss ein anderer Broadcast her!
			// Repaint ab Objekt Nummer ... (Achtung: GroupObj)
			if(pObj->GetPage())
			{
				SdrHint aHint(*pObj);

				aHint.SetKind(HINT_OBJINSERTED);
				pModel->Broadcast(aHint);
			}

			pModel->SetChanged();
		}
	}
}

SdrObject* SdrObjList::NbcRemoveObject(sal_uIntPtr nObjNum)
{
    if (nObjNum >= maList.size())
    {
        OSL_ASSERT(nObjNum<maList.size());
        return NULL;
    }

	sal_uIntPtr nAnz=GetObjCount();
	SdrObject* pObj=maList[nObjNum];
    RemoveObjectFromContainer(nObjNum);

	// flushViewObjectContacts() clears the VOC's and those invalidate
    pObj->GetViewContact().flushViewObjectContacts(true);

	DBG_ASSERT(pObj!=NULL,"Object zum Removen nicht gefunden");
	if (pObj!=NULL) {
		DBG_ASSERT(pObj->IsInserted(),"ZObjekt hat keinen Inserted-Status");
		pObj->SetInserted(sal_False); // Ruft u.a. den UserCall
		pObj->SetObjList(NULL);
		pObj->SetPage(NULL);
		if (!bObjOrdNumsDirty) { // Optimierung fuer den Fall, dass das letzte Obj rausgenommen wird
			if (nObjNum!=sal_uIntPtr(nAnz-1)) {
				bObjOrdNumsDirty=sal_True;
			}
		}
		SetRectsDirty();
	}
	return pObj;
}

SdrObject* SdrObjList::RemoveObject(sal_uIntPtr nObjNum)
{
    if (nObjNum >= maList.size())
    {
        OSL_ASSERT(nObjNum<maList.size());
        return NULL;
    }

	sal_uIntPtr nAnz=GetObjCount();
	SdrObject* pObj=maList[nObjNum];
    RemoveObjectFromContainer(nObjNum);

	DBG_ASSERT(pObj!=NULL,"Object zum Removen nicht gefunden");
	if(pObj) 
	{
		// flushViewObjectContacts() clears the VOC's and those invalidate
        pObj->GetViewContact().flushViewObjectContacts(true);

		DBG_ASSERT(pObj->IsInserted(),"ZObjekt hat keinen Inserted-Status");
		if (pModel!=NULL) {
			// Hier muss ein anderer Broadcast her!
			if (pObj->GetPage()!=NULL) {
				SdrHint aHint(*pObj);
				aHint.SetKind(HINT_OBJREMOVED);
				pModel->Broadcast(aHint);
			}
			pModel->SetChanged();
		}
		pObj->SetInserted(sal_False); // Ruft u.a. den UserCall
		pObj->SetObjList(NULL);
		pObj->SetPage(NULL);
		if (!bObjOrdNumsDirty) { // Optimierung fuer den Fall, dass das letzte Obj rausgenommen wird
			if (nObjNum!=sal_uIntPtr(nAnz-1)) {
				bObjOrdNumsDirty=sal_True;
			}
		}
		SetRectsDirty();

		if(pOwnerObj && !GetObjCount())
		{
			// empty group created; it needs to be repainted since it's
			// visualisation changes
			pOwnerObj->ActionChanged();
		}
	}
	return pObj;
}

SdrObject* SdrObjList::NbcReplaceObject(SdrObject* pNewObj, sal_uIntPtr nObjNum)
{
    if (nObjNum >= maList.size() || pNewObj == NULL)
    {
        OSL_ASSERT(nObjNum<maList.size());
        OSL_ASSERT(pNewObj!=NULL);
        return NULL;
    }

	SdrObject* pObj=maList[nObjNum];
	DBG_ASSERT(pObj!=NULL,"SdrObjList::ReplaceObject: Object zum Removen nicht gefunden");
	if (pObj!=NULL) {
		DBG_ASSERT(pObj->IsInserted(),"SdrObjList::ReplaceObject: ZObjekt hat keinen Inserted-Status");
		pObj->SetInserted(sal_False);
		pObj->SetObjList(NULL);
		pObj->SetPage(NULL);
        ReplaceObjectInContainer(*pNewObj,nObjNum);

		// flushViewObjectContacts() clears the VOC's and those invalidate
        pObj->GetViewContact().flushViewObjectContacts(true);

		pNewObj->SetOrdNum(nObjNum);
		pNewObj->SetObjList(this);
		pNewObj->SetPage(pPage);

		// #110094#  Inform the parent about change to allow invalidations at
		// evtl. existing parent visualisations
		impChildInserted(*pNewObj);

		pNewObj->SetInserted(sal_True);
		SetRectsDirty();
	}
	return pObj;
}

SdrObject* SdrObjList::ReplaceObject(SdrObject* pNewObj, sal_uIntPtr nObjNum)
{
	if (nObjNum >= maList.size())
    {
        OSL_ASSERT(nObjNum<maList.size());
        return NULL;
    }
    if (pNewObj == NULL)
    {
        OSL_ASSERT(pNewObj!=NULL);
        return NULL;
    }
    
	SdrObject* pObj=maList[nObjNum];
	DBG_ASSERT(pObj!=NULL,"SdrObjList::ReplaceObject: Object zum Removen nicht gefunden");
	if (pObj!=NULL) {
		DBG_ASSERT(pObj->IsInserted(),"SdrObjList::ReplaceObject: ZObjekt hat keinen Inserted-Status");
		if (pModel!=NULL) {
			// Hier muss ein anderer Broadcast her!
			if (pObj->GetPage()!=NULL) {
				SdrHint aHint(*pObj);
				aHint.SetKind(HINT_OBJREMOVED);
				pModel->Broadcast(aHint);
			}
		}
		pObj->SetInserted(sal_False);
		pObj->SetObjList(NULL);
		pObj->SetPage(NULL);
		ReplaceObjectInContainer(*pNewObj,nObjNum);

		// flushViewObjectContacts() clears the VOC's and those invalidate
        pObj->GetViewContact().flushViewObjectContacts(true);

		pNewObj->SetOrdNum(nObjNum);
		pNewObj->SetObjList(this);
		pNewObj->SetPage(pPage);

		// #110094#  Inform the parent about change to allow invalidations at
		// evtl. existing parent visualisations
		impChildInserted(*pNewObj);

		pNewObj->SetInserted(sal_True);
		if (pModel!=NULL) {
			// Hier muss ein anderer Broadcast her!
			if (pNewObj->GetPage()!=NULL) {
				SdrHint aHint(*pNewObj);
				aHint.SetKind(HINT_OBJINSERTED);
				pModel->Broadcast(aHint);
			}
			pModel->SetChanged();
		}
		SetRectsDirty();
	}
	return pObj;
}

SdrObject* SdrObjList::NbcSetObjectOrdNum(sal_uIntPtr nOldObjNum, sal_uIntPtr nNewObjNum)
{
    if (nOldObjNum >= maList.size() || nNewObjNum >= maList.size())
    {
        OSL_ASSERT(nOldObjNum<maList.size());
        OSL_ASSERT(nNewObjNum<maList.size());
        return NULL;
    }

	SdrObject* pObj=maList[nOldObjNum];
	if (nOldObjNum==nNewObjNum) return pObj;
	DBG_ASSERT(pObj!=NULL,"SdrObjList::NbcSetObjectOrdNum: Object nicht gefunden");
	if (pObj!=NULL) {
		DBG_ASSERT(pObj->IsInserted(),"SdrObjList::NbcSetObjectOrdNum: ZObjekt hat keinen Inserted-Status");
        RemoveObjectFromContainer(nOldObjNum);

        InsertObjectIntoContainer(*pObj,nNewObjNum);

		// #110094# No need to delete visualisation data since same object
		// gets inserted again. Also a single ActionChanged is enough
		pObj->ActionChanged();

		pObj->SetOrdNum(nNewObjNum);
		bObjOrdNumsDirty=sal_True;
	}
	return pObj;
}

SdrObject* SdrObjList::SetObjectOrdNum(sal_uIntPtr nOldObjNum, sal_uIntPtr nNewObjNum)
{
    if (nOldObjNum >= maList.size() || nNewObjNum >= maList.size())
    {
        OSL_ASSERT(nOldObjNum<maList.size());
        OSL_ASSERT(nNewObjNum<maList.size());
        return NULL;
    }

	SdrObject* pObj=maList[nOldObjNum];
	if (nOldObjNum==nNewObjNum) return pObj;
	DBG_ASSERT(pObj!=NULL,"SdrObjList::SetObjectOrdNum: Object nicht gefunden");
	if (pObj!=NULL) {
		DBG_ASSERT(pObj->IsInserted(),"SdrObjList::SetObjectOrdNum: ZObjekt hat keinen Inserted-Status");
		RemoveObjectFromContainer(nOldObjNum);
		InsertObjectIntoContainer(*pObj,nNewObjNum);

		// #110094#No need to delete visualisation data since same object
		// gets inserted again. Also a single ActionChanged is enough
		pObj->ActionChanged();

		pObj->SetOrdNum(nNewObjNum);
		bObjOrdNumsDirty=sal_True;
		if (pModel!=NULL) 
		{
			// Hier muss ein anderer Broadcast her!
			if (pObj->GetPage()!=NULL) pModel->Broadcast(SdrHint(*pObj));
			pModel->SetChanged();
		}
	}
	return pObj;
}

const Rectangle& SdrObjList::GetAllObjSnapRect() const
{
	if (bRectsDirty) {
		((SdrObjList*)this)->RecalcRects();
		((SdrObjList*)this)->bRectsDirty=sal_False;
	}
	return aSnapRect;
}

const Rectangle& SdrObjList::GetAllObjBoundRect() const
{
    // #i106183# for deep group hierarchies like in chart2, the invalidates
    // through the hierarchy are not correct; use a 2nd hint for the needed
    // recalculation. Future versions will have no bool flag at all, but
    // just aOutRect in empty state to representate an invalid state, thus
    // it's a step in the right direction.
	if (bRectsDirty || aOutRect.IsEmpty())
    {
		((SdrObjList*)this)->RecalcRects();
		((SdrObjList*)this)->bRectsDirty=sal_False;
	}
	return aOutRect;
}

void SdrObjList::NbcReformatAllTextObjects()
{
	sal_uIntPtr nAnz=GetObjCount();
	sal_uIntPtr nNum=0;

	Printer* pPrinter = NULL;

	if (pModel)
	{
		if (pModel->GetRefDevice() && pModel->GetRefDevice()->GetOutDevType() == OUTDEV_PRINTER)
		{
			// Kein RefDevice oder RefDevice kein Printer
			pPrinter = (Printer*) pModel->GetRefDevice();
		}
	}

	while (nNum<nAnz)
	{
		SdrObject* pObj = GetObj(nNum);
		if (pPrinter &&
			pObj->GetObjInventor() == SdrInventor &&
			pObj->GetObjIdentifier() == OBJ_OLE2  &&
			!( (SdrOle2Obj*) pObj )->IsEmpty() )
		{
			//const SvInPlaceObjectRef& xObjRef = ((SdrOle2Obj*) pObj)->GetObjRef();
            //TODO/LATER: PrinterChangeNotification needed
			//if( xObjRef.Is() && ( xObjRef->GetMiscStatus() & SVOBJ_MISCSTATUS_RESIZEONPRINTERCHANGE ) )
			//	xObjRef->OnDocumentPrinterChanged(pPrinter);
		}

		pObj->NbcReformatText();
		nAnz=GetObjCount();			    // ReformatText may delete an object
		nNum++;
	}

}

void SdrObjList::ReformatAllTextObjects()
{
    NbcReformatAllTextObjects();
}

/** steps over all available objects and reformats all
	edge objects that are connected to other objects so that
	they may reposition itselfs.
	#103122#
*/
void SdrObjList::ReformatAllEdgeObjects()
{
    // #120437# go over whole hierarchy, not only over object level null (seen from grouping)
	SdrObjListIter aIter(*this, IM_DEEPNOGROUPS);

    while(aIter.IsMore())
	{
		SdrEdgeObj* pSdrEdgeObj = dynamic_cast< SdrEdgeObj* >(aIter.Next());
		
        if(pSdrEdgeObj)
        {
			pSdrEdgeObj->Reformat();
        }
	}
}

void SdrObjList::BurnInStyleSheetAttributes()
{
	for(sal_uInt32 a(0L); a < GetObjCount(); a++)
	{
		GetObj(a)->BurnInStyleSheetAttributes();
	}
}

sal_uIntPtr SdrObjList::GetObjCount() const
{
    return maList.size();
}




SdrObject* SdrObjList::GetObj(sal_uIntPtr nNum) const
{
    if (nNum >= maList.size())
    {
        OSL_ASSERT(nNum<maList.size());
        return NULL;
    }
    else
        return maList[nNum];
}




FASTBOOL SdrObjList::IsReadOnly() const
{
	FASTBOOL bRet=sal_False;
	if (pPage!=NULL && pPage!=this) bRet=pPage->IsReadOnly();
	return bRet;
}

sal_uIntPtr SdrObjList::CountAllObjects() const
{
	sal_uIntPtr nCnt=GetObjCount();
	sal_uIntPtr nAnz=nCnt;
	for (sal_uInt16 nNum=0; nNum<nAnz; nNum++) {
		SdrObjList* pSubOL=GetObj(nNum)->GetSubList();
		if (pSubOL!=NULL) {
			nCnt+=pSubOL->CountAllObjects();
		}
	}
	return nCnt;
}

void SdrObjList::ForceSwapInObjects() const
{
	sal_uIntPtr nObjAnz=GetObjCount();
	for (sal_uIntPtr nObjNum=nObjAnz; nObjNum>0;) {
		SdrObject* pObj=GetObj(--nObjNum);
		SdrGrafObj* pGrafObj=PTR_CAST(SdrGrafObj,pObj);
		if (pGrafObj!=NULL) {
			pGrafObj->ForceSwapIn();
		}
		SdrObjList* pOL=pObj->GetSubList();
		if (pOL!=NULL) {
			pOL->ForceSwapInObjects();
		}
	}
}

void SdrObjList::ForceSwapOutObjects() const
{
	sal_uIntPtr nObjAnz=GetObjCount();
	for (sal_uIntPtr nObjNum=nObjAnz; nObjNum>0;) {
		SdrObject* pObj=GetObj(--nObjNum);
		SdrGrafObj* pGrafObj=PTR_CAST(SdrGrafObj,pObj);
		if (pGrafObj!=NULL) {
			pGrafObj->ForceSwapOut();
		}
		SdrObjList* pOL=pObj->GetSubList();
		if (pOL!=NULL) {
			pOL->ForceSwapOutObjects();
		}
	}
}

void SdrObjList::FlattenGroups()
{
    sal_Int32 nObj = GetObjCount();
    sal_Int32 i;
    for( i=nObj-1; i>=0; --i)
        UnGroupObj(i);
}

void SdrObjList::UnGroupObj( sal_uIntPtr nObjNum )
{
    // if the given object is no group, this method is a noop
    SdrObject* pUngroupObj = GetObj( nObjNum );
    if( pUngroupObj )
    {
        SdrObjList* pSrcLst = pUngroupObj->GetSubList();
        //sal_Int32 nCount( 0 );
        if( pUngroupObj->ISA( SdrObjGroup ) && pSrcLst )
        {
            SdrObjGroup* pUngroupGroup = static_cast< SdrObjGroup* > (pUngroupObj);

            // ungroup recursively (has to be head recursion,
            // otherwise our indices will get trashed when doing it in
            // the loop)
            pSrcLst->FlattenGroups();

            // the position at which we insert the members of rUngroupGroup
            sal_Int32 nInsertPos( pUngroupGroup->GetOrdNum() );

            SdrObject* pObj;
            sal_Int32 i, nAnz = pSrcLst->GetObjCount();
            for( i=0; i<nAnz; ++i )
            {
                pObj = pSrcLst->RemoveObject(0);
                SdrInsertReason aReason(SDRREASON_VIEWCALL, pUngroupGroup);
                InsertObject(pObj, nInsertPos, &aReason);
                ++nInsertPos;
            }

            RemoveObject(nInsertPos);
        }
    }
#ifdef DBG_UTIL
    else
        DBG_ERROR("SdrObjList::UnGroupObj: object index invalid");
#endif
}




bool SdrObjList::HasObjectNavigationOrder (void) const
{
    return mpNavigationOrder.get() != NULL;
}




void SdrObjList::SetObjectNavigationPosition (
    SdrObject& rObject,
    const sal_uInt32 nNewPosition)
{
    // When the navigation order container has not yet been created then
    // create one now.  It is initialized with the z-order taken from
    // maList.
    if (mpNavigationOrder.get() == NULL)
    {
        mpNavigationOrder.reset(new WeakSdrObjectContainerType(maList.size()));
        ::std::copy(
            maList.begin(),
            maList.end(),
            mpNavigationOrder->begin());
    }
    OSL_ASSERT(mpNavigationOrder.get()!=NULL);
    OSL_ASSERT( mpNavigationOrder->size() == maList.size());

    SdrObjectWeakRef aReference (&rObject);

    // Look up the object whose navigation position is to be changed.
    WeakSdrObjectContainerType::iterator iObject (::std::find(
        mpNavigationOrder->begin(),
        mpNavigationOrder->end(),
        aReference));
    if (iObject == mpNavigationOrder->end())
    {
        // The given object is not a member of the navigation order.
        return;
    }

    // Move the object to its new position.
    const sal_uInt32 nOldPosition = ::std::distance(mpNavigationOrder->begin(), iObject);
    if (nOldPosition != nNewPosition)
    {
        mpNavigationOrder->erase(iObject);
        sal_uInt32 nInsertPosition (nNewPosition);
        // Adapt insertion position for the just erased object.
        if (nNewPosition >= nOldPosition)
            nInsertPosition -= 1;
        if (nInsertPosition >= mpNavigationOrder->size())
            mpNavigationOrder->push_back(aReference);
        else
            mpNavigationOrder->insert(mpNavigationOrder->begin()+nInsertPosition, aReference);

        mbIsNavigationOrderDirty = true;

        // The navigation order is written out to file so mark the model as modified.
        if (pModel != NULL)
            pModel->SetChanged();
    }
}




SdrObject* SdrObjList::GetObjectForNavigationPosition (const sal_uInt32 nNavigationPosition) const
{
    if (HasObjectNavigationOrder())
    {
        // There is a user defined navigation order.  Make sure the object
        // index is correct and look up the object in mpNavigationOrder.
        if (nNavigationPosition >= mpNavigationOrder->size())
        {
            OSL_ASSERT(nNavigationPosition < mpNavigationOrder->size());
        }
        else
            return (*mpNavigationOrder)[nNavigationPosition].get();
    }
    else
    {
        // There is no user defined navigation order.  Use the z-order
        // instead.
        if (nNavigationPosition >= maList.size())
        {
            OSL_ASSERT(nNavigationPosition < maList.size());
        }
        else
            return maList[nNavigationPosition];
    }
    return NULL;
}




void SdrObjList::ClearObjectNavigationOrder (void)
{
    mpNavigationOrder.reset();
    mbIsNavigationOrderDirty = true;
}




bool SdrObjList::RecalcNavigationPositions (void)
{
    bool bUpToDate (false);

    if (mbIsNavigationOrderDirty)
    {
        if (mpNavigationOrder.get() != NULL)
        {
            mbIsNavigationOrderDirty = false;
            
            WeakSdrObjectContainerType::iterator iObject;
            WeakSdrObjectContainerType::const_iterator iEnd (mpNavigationOrder->end());
            sal_uInt32 nIndex (0);
            for (iObject=mpNavigationOrder->begin(); iObject!=iEnd; ++iObject,++nIndex)
                (*iObject)->SetNavigationPosition(nIndex);

            bUpToDate = true;
        }
    }

    return mpNavigationOrder.get() != NULL;
}




void SdrObjList::SetNavigationOrder (const uno::Reference<container::XIndexAccess>& rxOrder)
{
    if (rxOrder.is())
    {
        const sal_Int32 nCount = rxOrder->getCount();
        if ((sal_uInt32)nCount != maList.size())
            return;

        if (mpNavigationOrder.get() == NULL)
            mpNavigationOrder.reset(new WeakSdrObjectContainerType(nCount));
        
        for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
        {
            uno::Reference<uno::XInterface> xShape (rxOrder->getByIndex(nIndex), uno::UNO_QUERY);
            SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xShape);
            if (pObject == NULL)
                break;
            (*mpNavigationOrder)[nIndex] = pObject;
        }

        mbIsNavigationOrderDirty = true;
    }
    else
        ClearObjectNavigationOrder();
}




void SdrObjList::InsertObjectIntoContainer (
    SdrObject& rObject,
    const sal_uInt32 nInsertPosition)
{
    OSL_ASSERT(nInsertPosition<=maList.size());

    // Update the navigation positions.
    if (HasObjectNavigationOrder())
    {
        // The new object does not have a user defined position so append it
        // to the list.
        rObject.SetNavigationPosition(mpNavigationOrder->size());
        mpNavigationOrder->push_back(&rObject);
    }

    // Insert object into object list.  Because the insert() method requires
    // a valid iterator as insertion position, we have to use push_back() to
    // insert at the end of the list.
    if (nInsertPosition >= maList.size())
        maList.push_back(&rObject);
    else
        maList.insert(maList.begin()+nInsertPosition, &rObject);
    bObjOrdNumsDirty=sal_True;
}




void SdrObjList::ReplaceObjectInContainer (
    SdrObject& rNewObject,
    const sal_uInt32 nObjectPosition)
{
    if (nObjectPosition >= maList.size())
    {
        OSL_ASSERT(nObjectPosition<maList.size());
        return;
    }

    // Update the navigation positions.
    if (HasObjectNavigationOrder())
    {
        // A user defined position of the object that is to be replaced is
        // not transferred to the new object so erase the former and append
        // the later object from/to the navigation order.
        OSL_ASSERT(nObjectPosition < maList.size());
        SdrObjectWeakRef aReference (maList[nObjectPosition]);
        WeakSdrObjectContainerType::iterator iObject (::std::find(
            mpNavigationOrder->begin(),
            mpNavigationOrder->end(),
            aReference));
        if (iObject != mpNavigationOrder->end())
            mpNavigationOrder->erase(iObject);
        
        mpNavigationOrder->push_back(&rNewObject);
        
        mbIsNavigationOrderDirty = true;
    }

    maList[nObjectPosition] = &rNewObject;
    bObjOrdNumsDirty=sal_True;
}




void SdrObjList::RemoveObjectFromContainer (
    const sal_uInt32 nObjectPosition)
{
    if (nObjectPosition >= maList.size())
    {
        OSL_ASSERT(nObjectPosition<maList.size());
        return;
    }

    // Update the navigation positions.
    if (HasObjectNavigationOrder())
    {
        SdrObjectWeakRef aReference (maList[nObjectPosition]);
        WeakSdrObjectContainerType::iterator iObject (::std::find(
            mpNavigationOrder->begin(),
            mpNavigationOrder->end(),
            aReference));
        if (iObject != mpNavigationOrder->end())
            mpNavigationOrder->erase(iObject);
        mbIsNavigationOrderDirty = true;
    }

    maList.erase(maList.begin()+nObjectPosition);
    bObjOrdNumsDirty=sal_True;
}




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

void SdrPageGridFrameList::Clear()
{
	sal_uInt16 nAnz=GetCount();
	for (sal_uInt16 i=0; i<nAnz; i++) {
		delete GetObject(i);
	}
	aList.Clear();
}

//////////////////////////////////////////////////////////////////////////////
// #111111# PageUser section

void SdrPage::AddPageUser(sdr::PageUser& rNewUser)
{
	maPageUsers.push_back(&rNewUser);
}

void SdrPage::RemovePageUser(sdr::PageUser& rOldUser)
{
	const ::sdr::PageUserVector::iterator aFindResult = ::std::find(maPageUsers.begin(), maPageUsers.end(), &rOldUser);
	if(aFindResult != maPageUsers.end())
	{
		maPageUsers.erase(aFindResult);
	}
}

//////////////////////////////////////////////////////////////////////////////
// #110094# DrawContact section

sdr::contact::ViewContact* SdrPage::CreateObjectSpecificViewContact()
{
	return new sdr::contact::ViewContactOfSdrPage(*this);
}

sdr::contact::ViewContact& SdrPage::GetViewContact() const
{
	if(!mpViewContact)
	{
		const_cast< SdrPage* >(this)->mpViewContact = 
            const_cast< SdrPage* >(this)->CreateObjectSpecificViewContact();
	}

	return *mpViewContact;
}

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

void SdrPageProperties::ImpRemoveStyleSheet()
{
    if(mpStyleSheet)
    {
		EndListening(*mpStyleSheet);
        mpProperties->SetParent(0);
        mpStyleSheet = 0;
    }
}

void SdrPageProperties::ImpAddStyleSheet(SfxStyleSheet& rNewStyleSheet)
{
    if(mpStyleSheet != &rNewStyleSheet)
    {
    	ImpRemoveStyleSheet();
        mpStyleSheet = &rNewStyleSheet;
	    StartListening(rNewStyleSheet);
	    mpProperties->SetParent(&rNewStyleSheet.GetItemSet());
    }
}

void ImpPageChange(SdrPage& rSdrPage)
{
    rSdrPage.ActionChanged();

    if(rSdrPage.GetModel())
    {
        rSdrPage.GetModel()->SetChanged(true);
        SdrHint aHint(HINT_PAGEORDERCHG);
        aHint.SetPage(&rSdrPage);
        rSdrPage.GetModel()->Broadcast(aHint);
    }
}

SdrPageProperties::SdrPageProperties(SdrPage& rSdrPage)
:   SfxListener(),
    mpSdrPage(&rSdrPage),
    mpStyleSheet(0),
    mpProperties(new SfxItemSet(mpSdrPage->GetModel()->GetItemPool(), XATTR_FILL_FIRST, XATTR_FILL_LAST))
{
    if(!rSdrPage.IsMasterPage())
    {
        mpProperties->Put(XFillStyleItem(XFILL_NONE));
    }
}

SdrPageProperties::~SdrPageProperties()
{
	ImpRemoveStyleSheet();
    delete mpProperties;
}

void SdrPageProperties::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
{
	const SfxSimpleHint* pSimpleHint = dynamic_cast< const SfxSimpleHint* >(&rHint);

	if(pSimpleHint)
	{
		switch(pSimpleHint->GetId())
		{
			case SFX_HINT_DATACHANGED :
			{
				// notify change, broadcast
                ImpPageChange(*mpSdrPage);
				break;
			}
			case SFX_HINT_DYING :
			{
				// Style needs to be forgotten
            	ImpRemoveStyleSheet();
				break;
			}
		}
    }
}

const SfxItemSet& SdrPageProperties::GetItemSet() const
{
    return *mpProperties;
}

void SdrPageProperties::PutItemSet(const SfxItemSet& rSet)
{
    OSL_ENSURE(!mpSdrPage->IsMasterPage(), "Item set at MasterPage Attributes (!)");
    mpProperties->Put(rSet);
    ImpPageChange(*mpSdrPage);
}

void SdrPageProperties::PutItem(const SfxPoolItem& rItem)
{
    OSL_ENSURE(!mpSdrPage->IsMasterPage(), "Item set at MasterPage Attributes (!)");
    mpProperties->Put(rItem);
    ImpPageChange(*mpSdrPage);
}

void SdrPageProperties::ClearItem(const sal_uInt16 nWhich)
{
    mpProperties->ClearItem(nWhich);
    ImpPageChange(*mpSdrPage);
}

void SdrPageProperties::SetStyleSheet(SfxStyleSheet* pStyleSheet)
{
    if(pStyleSheet)
    {
        ImpAddStyleSheet(*pStyleSheet);
    }
    else
    {
        ImpRemoveStyleSheet();
    }

    ImpPageChange(*mpSdrPage);
}

SfxStyleSheet* SdrPageProperties::GetStyleSheet() const
{
    return mpStyleSheet;
}

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

TYPEINIT1(SdrPage,SdrObjList);
DBG_NAME(SdrPage)
SdrPage::SdrPage(SdrModel& rNewModel, bool bMasterPage)
:	SdrObjList(&rNewModel, this),
	mpViewContact(0L),
	nWdt(10L),
	nHgt(10L),
	nBordLft(0L),
	nBordUpp(0L),
	nBordRgt(0L),
	nBordLwr(0L),
	pLayerAdmin(new SdrLayerAdmin(&rNewModel.GetLayerAdmin())),
    mpSdrPageProperties(0),
	mpMasterPageDescriptor(0L),
	nPageNum(0L),
	mbMaster(bMasterPage),
	mbInserted(false),
	mbObjectsNotPersistent(false),
	mbSwappingLocked(false),
    mbPageBorderOnlyLeftRight(false)
{
    DBG_CTOR(SdrPage,NULL);    
	aPrefVisiLayers.SetAll();
	eListKind = (bMasterPage) ? SDROBJLIST_MASTERPAGE : SDROBJLIST_DRAWPAGE;

    mpSdrPageProperties = new SdrPageProperties(*this);
}

SdrPage::SdrPage(const SdrPage& rSrcPage)
:	SdrObjList(rSrcPage.pModel, this),
	tools::WeakBase< SdrPage >(),
	mpViewContact(0L),
	nWdt(rSrcPage.nWdt),
	nHgt(rSrcPage.nHgt),
	nBordLft(rSrcPage.nBordLft),
	nBordUpp(rSrcPage.nBordUpp),
	nBordRgt(rSrcPage.nBordRgt),
	nBordLwr(rSrcPage.nBordLwr),
	pLayerAdmin(new SdrLayerAdmin(rSrcPage.pModel->GetLayerAdmin())),
    mpSdrPageProperties(0),
	mpMasterPageDescriptor(0L),
	nPageNum(rSrcPage.nPageNum),
	mbMaster(rSrcPage.mbMaster),
	mbInserted(false),
	mbObjectsNotPersistent(rSrcPage.mbObjectsNotPersistent),
	mbSwappingLocked(rSrcPage.mbSwappingLocked),
    mbPageBorderOnlyLeftRight(rSrcPage.mbPageBorderOnlyLeftRight)
{
    DBG_CTOR(SdrPage,NULL);    
	aPrefVisiLayers.SetAll();
	eListKind = (mbMaster) ? SDROBJLIST_MASTERPAGE : SDROBJLIST_DRAWPAGE;

	// copy things from source
    // Warning: this leads to slicing (see issue 93186) and has to be
    // removed as soon as possible.
	*this = rSrcPage;
    OSL_ENSURE(mpSdrPageProperties, 
        "SdrPage::SdrPage: operator= did not create needed SdrPageProperties (!)");

	// be careful and correct eListKind, a member of SdrObjList which
	// will be changed by the SdrOIbjList::operator= before...
	eListKind = (mbMaster) ? SDROBJLIST_MASTERPAGE : SDROBJLIST_DRAWPAGE;

    // The previous assignment to *this may have resulted in a call to
    // createUnoPage at a partially initialized (sliced) SdrPage object.
    // Due to the vtable being not yet fully set-up at this stage,
    // createUnoPage() may have been called at the wrong class.
    // To force a call to the right createUnoPage() at a later time when the
    // new object is full constructed mxUnoPage is disposed now.
    uno::Reference<lang::XComponent> xComponent (mxUnoPage, uno::UNO_QUERY);
    if (xComponent.is())
    {
        mxUnoPage = NULL;
        xComponent->dispose();
    }
}

SdrPage::~SdrPage()
{
    if( mxUnoPage.is() ) try
    {
        uno::Reference< lang::XComponent > xPageComponent( mxUnoPage, uno::UNO_QUERY_THROW );
        mxUnoPage.clear();
	    xPageComponent->dispose();
    }
    catch( const uno::Exception& )
    {
    	DBG_UNHANDLED_EXCEPTION();
    }

	// #111111#
	// tell all the registered PageUsers that the page is in destruction
    // This causes some (all?) PageUsers to remove themselves from the list
    // of page users.  Therefore we have to use a copy of the list for the
    // iteration.
	::sdr::PageUserVector aListCopy (maPageUsers.begin(), maPageUsers.end());
	for(::sdr::PageUserVector::iterator aIterator = aListCopy.begin(); aIterator != aListCopy.end(); aIterator++)
	{
		sdr::PageUser* pPageUser = *aIterator;
		DBG_ASSERT(pPageUser, "SdrPage::~SdrPage: corrupt PageUser list (!)");
		pPageUser->PageInDestruction(*this);
	}

	// #111111#
	// Clear the vector. This means that user do not need to call RemovePageUser()
	// when they get called from PageInDestruction().
	maPageUsers.clear();

	delete pLayerAdmin;

	TRG_ClearMasterPage();

	// #110094#
	if(mpViewContact)
	{
		delete mpViewContact;
		mpViewContact = 0L;
	}

    {
        delete mpSdrPageProperties;
        mpSdrPageProperties = 0;
    }

	DBG_DTOR(SdrPage,NULL);    
}

void SdrPage::operator=(const SdrPage& rSrcPage)
{
	if(mpViewContact)
	{
		delete mpViewContact;
		mpViewContact = 0L;
	}

	// Joe also sets some parameters for the class this one
	// is derived from. SdrObjList does the same bad handling of
	// copy constructor and operator=, so i better let it stand here.
	pPage = this;

	// copy all the local parameters to make this instance
	// a valid copy od source page before copying and inserting
	// the contained objects
	mbMaster = rSrcPage.mbMaster;
	mbSwappingLocked = rSrcPage.mbSwappingLocked;
    mbPageBorderOnlyLeftRight = rSrcPage.mbPageBorderOnlyLeftRight;
	aPrefVisiLayers = rSrcPage.aPrefVisiLayers;
	nWdt = rSrcPage.nWdt;
	nHgt = rSrcPage.nHgt;
	nBordLft = rSrcPage.nBordLft;
	nBordUpp = rSrcPage.nBordUpp;
	nBordRgt = rSrcPage.nBordRgt;
	nBordLwr = rSrcPage.nBordLwr;
	nPageNum = rSrcPage.nPageNum;
	
	if(rSrcPage.TRG_HasMasterPage())
	{
		TRG_SetMasterPage(rSrcPage.TRG_GetMasterPage());
		TRG_SetMasterPageVisibleLayers(rSrcPage.TRG_GetMasterPageVisibleLayers());
	}
	else
	{
		TRG_ClearMasterPage();
	}
	//aMasters = rSrcPage.aMasters;
	
	mbObjectsNotPersistent = rSrcPage.mbObjectsNotPersistent;

    {
        // #i111122# delete SdrPageProperties when model is different
        if(mpSdrPageProperties && GetModel() != rSrcPage.GetModel())
        {
            delete mpSdrPageProperties;
            mpSdrPageProperties = 0;
        }

        if(!mpSdrPageProperties)
        {
            mpSdrPageProperties = new SdrPageProperties(*this);
        }
        else
        {
            mpSdrPageProperties->ClearItem(0);
        }

        if(!IsMasterPage())
        {
            mpSdrPageProperties->PutItemSet(rSrcPage.getSdrPageProperties().GetItemSet());
        }

        mpSdrPageProperties->SetStyleSheet(rSrcPage.getSdrPageProperties().GetStyleSheet());
    }

    // Now copy the contained obejcts (by cloning them)
	SdrObjList::operator=(rSrcPage);
}

SdrPage* SdrPage::Clone() const
{
	return Clone(NULL);
}

SdrPage* SdrPage::Clone(SdrModel* pNewModel) const
{
	if (pNewModel==NULL) pNewModel=pModel;
	SdrPage* pPage2=new SdrPage(*pNewModel);
	*pPage2=*this;
	return pPage2;
}

void SdrPage::SetSize(const Size& aSiz)
{
    bool bChanged(false);

    if(aSiz.Width() != nWdt)
    {
    	nWdt = aSiz.Width();
        bChanged = true;
    }

    if(aSiz.Height() != nHgt)
    {
    	nHgt = aSiz.Height();
        bChanged = true;
    }

    if(bChanged)
    {
    	SetChanged();
    }
}

Size SdrPage::GetSize() const
{
	return Size(nWdt,nHgt);
}

sal_Int32 SdrPage::GetWdt() const
{
	return nWdt;
}

void SdrPage::SetOrientation(Orientation eOri)
{
	// Quadratisch ist und bleibt immer Portrait
	Size aSiz(GetSize());
	if (aSiz.Width()!=aSiz.Height()) {
		if ((eOri==ORIENTATION_PORTRAIT) == (aSiz.Width()>aSiz.Height())) {
			SetSize(Size(aSiz.Height(),aSiz.Width()));
		}
	}
}

Orientation SdrPage::GetOrientation() const
{
	// Quadratisch ist Portrait
	Orientation eRet=ORIENTATION_PORTRAIT;
	Size aSiz(GetSize());
	if (aSiz.Width()>aSiz.Height()) eRet=ORIENTATION_LANDSCAPE;
	return eRet;
}

sal_Int32 SdrPage::GetHgt() const
{
	return nHgt;
}

void  SdrPage::SetBorder(sal_Int32 nLft, sal_Int32 nUpp, sal_Int32 nRgt, sal_Int32 nLwr)
{
    bool bChanged(false);

    if(nBordLft != nLft)
    {
        nBordLft = nLft;
        bChanged = true;
    }

	if(nBordUpp != nUpp)
    {
    	nBordUpp = nUpp;
        bChanged = true;
    }

	if(nBordRgt != nRgt)
    {
	    nBordRgt = nRgt;
        bChanged = true;
    }

	if(nBordLwr != nLwr)
    {
	    nBordLwr =  nLwr;
        bChanged = true;
    }

    if(bChanged)
    {
    	SetChanged();
    }
}

void  SdrPage::SetLftBorder(sal_Int32 nBorder)
{
	if(nBordLft != nBorder)
    {
    	nBordLft = nBorder;
	    SetChanged();
    }
}

void  SdrPage::SetUppBorder(sal_Int32 nBorder)
{
	if(nBordUpp != nBorder)
    {
    	nBordUpp = nBorder;
	    SetChanged();
    }
}

void  SdrPage::SetRgtBorder(sal_Int32 nBorder)
{
	if(nBordRgt != nBorder)
    {
    	nBordRgt=nBorder;
	    SetChanged();
    }
}

void  SdrPage::SetLwrBorder(sal_Int32 nBorder)
{
	if(nBordLwr != nBorder)
    {
    	nBordLwr=nBorder;
	    SetChanged();
    }
}

sal_Int32 SdrPage::GetLftBorder() const
{
	return nBordLft;
}

sal_Int32 SdrPage::GetUppBorder() const
{
	return nBordUpp;
}

sal_Int32 SdrPage::GetRgtBorder() const
{
	return nBordRgt;
}

sal_Int32 SdrPage::GetLwrBorder() const
{
	return nBordLwr;
}

void SdrPage::SetModel(SdrModel* pNewModel)
{
	SdrModel* pOldModel=pModel;
	SdrObjList::SetModel(pNewModel);
	if (pNewModel!=pOldModel)
	{
		if (pNewModel!=NULL) {
			pLayerAdmin->SetParent(&pNewModel->GetLayerAdmin());
		} else {
			pLayerAdmin->SetParent(NULL);
		}
		pLayerAdmin->SetModel(pNewModel);

        // create new SdrPageProperties with new model (due to SfxItemSet there)
        // and copy ItemSet and StyleSheet
        SdrPageProperties *pNew = new SdrPageProperties(*this);

        if(!IsMasterPage())
        {
            pNew->PutItemSet(getSdrPageProperties().GetItemSet());
        }

        pNew->SetStyleSheet(getSdrPageProperties().GetStyleSheet());

        delete mpSdrPageProperties;
        mpSdrPageProperties = pNew;
	}

	// update listeners at possible api wrapper object
	if( pOldModel != pNewModel )
	{
		if( mxUnoPage.is() )
		{
			SvxDrawPage* pPage2 = SvxDrawPage::getImplementation( mxUnoPage );
			if( pPage2 )
				pPage2->ChangeModel( pNewModel );
		}
	}
}

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

// #i68775# React on PageNum changes (from Model in most cases)
void SdrPage::SetPageNum(sal_uInt16 nNew)
{
	if(nNew != nPageNum)
	{
		// change
		nPageNum = nNew;

		// notify visualisations, also notifies e.g. buffered MasterPages
		ActionChanged();
	}
}

sal_uInt16 SdrPage::GetPageNum() const
{
	if (!mbInserted) 
        return 0;

	if (mbMaster) {
		if (pModel && pModel->IsMPgNumsDirty())
			((SdrModel*)pModel)->RecalcPageNums(sal_True);
	} else {
		if (pModel && pModel->IsPagNumsDirty())
			((SdrModel*)pModel)->RecalcPageNums(sal_False);
	}
	return nPageNum;
}

void SdrPage::SetChanged()
{
	// #110094#-11
	// For test purposes, use the new ViewContact for change
	// notification now.
	ActionChanged();

	if( pModel )
	{
		pModel->SetChanged();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// MasterPage interface

void SdrPage::TRG_SetMasterPage(SdrPage& rNew)
{
	if(mpMasterPageDescriptor && &(mpMasterPageDescriptor->GetUsedPage()) == &rNew)
		return;

	if(mpMasterPageDescriptor)
		TRG_ClearMasterPage();

	mpMasterPageDescriptor = new ::sdr::MasterPageDescriptor(*this, rNew);
	GetViewContact().ActionChanged();
}

void SdrPage::TRG_ClearMasterPage()
{
	if(mpMasterPageDescriptor)
	{
		SetChanged();

		// the flushViewObjectContacts() will do needed invalidates by deleting the involved VOCs
        mpMasterPageDescriptor->GetUsedPage().GetViewContact().flushViewObjectContacts(true);

		delete mpMasterPageDescriptor;
		mpMasterPageDescriptor = 0L;
	}
}

SdrPage& SdrPage::TRG_GetMasterPage() const
{
	DBG_ASSERT(mpMasterPageDescriptor != 0L, "TRG_GetMasterPage(): No MasterPage available. Use TRG_HasMasterPage() before access (!)");
        if (mpMasterPageDescriptor == NULL) {
            throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No master page descriptor")), NULL);
        }
	return mpMasterPageDescriptor->GetUsedPage();
}

const SetOfByte& SdrPage::TRG_GetMasterPageVisibleLayers() const
{
	DBG_ASSERT(mpMasterPageDescriptor != 0L, "TRG_GetMasterPageVisibleLayers(): No MasterPage available. Use TRG_HasMasterPage() before access (!)");
        if (mpMasterPageDescriptor == NULL) {
            throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No master page descriptor")), NULL);
        }
	return mpMasterPageDescriptor->GetVisibleLayers();
}

void SdrPage::TRG_SetMasterPageVisibleLayers(const SetOfByte& rNew)
{
	DBG_ASSERT(mpMasterPageDescriptor != 0L, "TRG_SetMasterPageVisibleLayers(): No MasterPage available. Use TRG_HasMasterPage() before access (!)");
        if (mpMasterPageDescriptor == NULL) {
            throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No master page descriptor")), NULL);
        }
	mpMasterPageDescriptor->SetVisibleLayers(rNew);
}

sdr::contact::ViewContact& SdrPage::TRG_GetMasterPageDescriptorViewContact() const
{
	DBG_ASSERT(mpMasterPageDescriptor != 0L, "TRG_GetMasterPageDescriptorViewContact(): No MasterPage available. Use TRG_HasMasterPage() before access (!)");
        if (mpMasterPageDescriptor == NULL) {
            throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No master page descriptor")), NULL);
        }
	return mpMasterPageDescriptor->GetViewContact();
}

// #115423# used from SdrModel::RemoveMasterPage
void SdrPage::TRG_ImpMasterPageRemoved(const SdrPage& rRemovedPage)
{
	if(TRG_HasMasterPage())
	{
		if(&TRG_GetMasterPage() == &rRemovedPage)
		{
			TRG_ClearMasterPage();
		}
	}
}

const SdrPageGridFrameList* SdrPage::GetGridFrameList(const SdrPageView* /*pPV*/, const Rectangle* /*pRect*/) const
{
	return NULL;
}

XubString SdrPage::GetLayoutName() const
{
	// Die wollte Dieter haben.
	return String();
}

void SdrPage::SetInserted( bool bIns )
{
	if( mbInserted != bIns )
	{
		mbInserted = bIns;

        // #120437# go over whole hierarchy, not only over object level null (seen from grouping)
		SdrObjListIter aIter(*this, IM_DEEPNOGROUPS);

 		while ( aIter.IsMore() )
		{
			SdrObject* pObj = aIter.Next();
			if ( pObj->ISA(SdrOle2Obj) )
			{
				if( mbInserted )
					( (SdrOle2Obj*) pObj)->Connect();
				else
					( (SdrOle2Obj*) pObj)->Disconnect();
			}
		}
	}
}


uno::Reference< uno::XInterface > SdrPage::getUnoPage()
{
	// try weak reference first
	if( !mxUnoPage.is() )
	{
		// create one
		mxUnoPage = createUnoPage();
	}

	return mxUnoPage;
}

uno::Reference< uno::XInterface > SdrPage::createUnoPage()
{
	::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xInt =
		static_cast<cppu::OWeakObject*>( new SvxFmDrawPage( this ) );
	return xInt;
}

SfxStyleSheet* SdrPage::GetTextStyleSheetForObject( SdrObject* pObj ) const
{
	return pObj->GetStyleSheet();
}

FASTBOOL SdrPage::HasTransparentObjects( sal_Bool bCheckForAlphaChannel ) const
{
	FASTBOOL bRet = sal_False;

	for( sal_uIntPtr n = 0, nCount = GetObjCount(); ( n < nCount ) && !bRet; n++ )
		if( GetObj( n )->IsTransparent( bCheckForAlphaChannel ) )
			bRet = sal_True;

	return bRet;
}

/** returns an averaged background color of this page */
// #i75566# GetBackgroundColor -> GetPageBackgroundColor and bScreenDisplay hint value
Color SdrPage::GetPageBackgroundColor( SdrPageView* pView, bool bScreenDisplay ) const
{
	Color aColor;

	if(bScreenDisplay && (!pView || pView->GetApplicationDocumentColor() == COL_AUTO))
	{
        svtools::ColorConfig aColorConfig;
        aColor = aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor;
	}
	else
	{
		aColor = pView->GetApplicationDocumentColor();
	}

    const SfxItemSet* pBackgroundFill = &getSdrPageProperties().GetItemSet();

    if(!IsMasterPage() && TRG_HasMasterPage())
    {
    	if(XFILL_NONE == ((const XFillStyleItem&)pBackgroundFill->Get(XATTR_FILLSTYLE)).GetValue())
        {
		    pBackgroundFill = &TRG_GetMasterPage().getSdrPageProperties().GetItemSet();
        }
    }

	GetDraftFillColor(*pBackgroundFill, aColor);

	return aColor;
}

/** *deprecated, use GetBackgroundColor with SdrPageView */
Color SdrPage::GetPageBackgroundColor() const
// #i75566# GetBackgroundColor -> GetPageBackgroundColor
{
	return GetPageBackgroundColor( NULL, true );
}

/** this method returns true if the object from the ViewObjectContact should
	be visible on this page while rendering.
	bEdit selects if visibility test is for an editing view or a final render,
	like printing.
*/
bool SdrPage::checkVisibility( 
	const sdr::contact::ViewObjectContact& /*rOriginal*/, 
	const sdr::contact::DisplayInfo& /*rDisplayInfo*/, 
	bool /*bEdit*/)
{
	// this will be handled in the application if needed
	return true;
}

// #110094# DrawContact support: Methods for handling Page changes
void SdrPage::ActionChanged() const
{
	// Do necessary ViewContact actions
	GetViewContact().ActionChanged();

	// #i48535# also handle MasterPage change
	if(TRG_HasMasterPage())
	{
		TRG_GetMasterPageDescriptorViewContact().ActionChanged();
	}
}

// NYI: Dummy implementations for declarations in svdpage.hxx
Bitmap      SdrPage::GetBitmap(const SetOfByte& /*rVisibleLayers*/, FASTBOOL /*bTrimBorders*/) const
{
	DBG_ASSERT(0, "SdrPage::GetBitmap(): not yet implemented.");
	return Bitmap();
}
GDIMetaFile SdrPage::GetMetaFile(const SetOfByte& /*rVisibleLayers*/, FASTBOOL /*bTrimBorders*/) 
{
	DBG_ASSERT(0, "SdrPage::GetMetaFile(): not yet implemented.");
	return GDIMetaFile();
}

bool SdrPage::isHandoutMasterPage() const 
{ 
    return mbMaster && GetModel() && GetModel()->GetMasterPageCount() 
        && GetModel()->GetMasterPage(0) == this;
}

//////////////////////////////////////////////////////////////////////////////
// sdr::Comment interface

const sdr::Comment& SdrPage::GetCommentByIndex(sal_uInt32 nIndex)
{
	DBG_ASSERT(nIndex < maComments.size(), "SdrPage::GetCommentByIndex: Access out of range (!)");
	return maComments[nIndex];
}

void SdrPage::AddComment(const sdr::Comment& rNew)
{
	maComments.push_back(rNew);
    ::std::sort(maComments.begin(), maComments.end());
}

void SdrPage::ReplaceCommentByIndex(sal_uInt32 nIndex, const sdr::Comment& rNew)
{
	DBG_ASSERT(nIndex < maComments.size(), "SdrPage::GetCommentByIndex: Access out of range (!)");

	if(maComments[nIndex] != rNew)
	{
		maComments[nIndex] = rNew;
		::std::sort(maComments.begin(), maComments.end());
	}
}

const SdrPageProperties* SdrPage::getCorrectSdrPageProperties() const
{
    if(mpMasterPageDescriptor)
    {
        return mpMasterPageDescriptor->getCorrectSdrPageProperties();
    }
    else
    {
        return &getSdrPageProperties();
    }
}

//////////////////////////////////////////////////////////////////////////////
// use new redirector instead of pPaintProc

StandardCheckVisisbilityRedirector::StandardCheckVisisbilityRedirector() 
:	ViewObjectContactRedirector() 
{
}

StandardCheckVisisbilityRedirector::~StandardCheckVisisbilityRedirector()
{
}

drawinglayer::primitive2d::Primitive2DSequence StandardCheckVisisbilityRedirector::createRedirectedPrimitive2DSequence(
	const sdr::contact::ViewObjectContact& rOriginal, 
	const sdr::contact::DisplayInfo& rDisplayInfo)
{
	SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();

	if(pObject)
	{
		if(pObject->GetPage())
		{
			if(pObject->GetPage()->checkVisibility(rOriginal, rDisplayInfo, false))
			{
				return ::sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo);
			}
		}

		return drawinglayer::primitive2d::Primitive2DSequence();
	}
	else
	{
		// not an object, maybe a page
		return ::sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo);
	}
}

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