/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: svx_fmundo.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2006/10/27 20:58:25 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#pragma hdrstop

#ifndef _SVX_FMUNDO_HXX
#include "fmundo.hxx"
#endif

#ifndef _COM_SUN_STAR_CONTAINER_XCONTAINER_HPP_
#include <com/sun/star/container/XContainer.hpp>
#endif
#ifndef _COM_SUN_STAR_SCRIPT_XEVENTATTACHERMANAGER_HPP_
#include <com/sun/star/script/XEventAttacherManager.hpp>
#endif

#ifndef _FM_FMMODEL_HXX
#include "fmmodel.hxx"
#endif

#ifndef _SVX_FMTOOLS_HXX
#include "fmtools.hxx"
#endif

#ifndef _SVX_FMPAGE_HXX //autogen
#include <fmpage.hxx>
#endif

#ifndef _SVX_FMRESIDS_HRC
#include "fmresids.hrc"
#endif


#ifndef _SVX_FMUNOPGE_HXX
#include "fmpgeimp.hxx"
#endif






#ifndef _SFX_OBJSH_HXX //autogen
#include <bf_sfx2/objsh.hxx>
#endif


#ifndef _SFXAPP_HXX //autogen
#include <bf_sfx2/app.hxx>
#endif

#ifndef _SFX_HRC
#include <bf_sfx2/sfx.hrc>
#endif

#ifndef _SFXEVENT_HXX //autogen
#include <bf_sfx2/event.hxx>
#endif


#ifndef _SVDITER_HXX //autogen
#include "svditer.hxx"
#endif

#ifndef _SVX_FMOBJ_HXX
#include "fmobj.hxx"
#endif


#ifndef _SVX_FMGLOB_HXX
#include "fmglob.hxx"
#endif
#ifndef _SVX_FMPROP_HRC
#include "fmprop.hrc"
#endif
#ifndef _COMPHELPER_PROPERTY_HXX_
#include <comphelper/property.hxx>
#endif
namespace binfilter {

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::awt;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::script;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::form;
using namespace ::binfilter::svxform;//STRIP008 using namespace ::svxform;

//------------------------------------------------------------------------------
// some helper structs for caching property infos
//------------------------------------------------------------------------------
struct PropertyInfo
{
	BOOL	bIsTransientOrReadOnly		: 1;	// the property is transient or read-only, thus we need no undo action for it
	BOOL	bIsControlSourceProperty	: 1;	// the property is the special control source property, thus it may be handled
												// as if it's transient or persistent
};

struct PropertySetInfo
{
	DECLARE_STL_USTRINGACCESS_MAP(PropertyInfo, AllProperties);

	AllProperties	aProps; 				// all properties of this set which we know so far
	BOOL			bHasEmptyControlSource; // sal_True -> the set has a DataField property, and the current value is an empty string
											// sal_False -> the set has _no_ such property or it's value isn't empty
};


/*?*/ DECLARE_STL_STDKEY_MAP(Reference< XPropertySet >, PropertySetInfo, PropertySetInfoCache);

//------------------------------------------------------------------------------

String static_STR_UNDO_PROPERTY;
//------------------------------------------------------------------------------
/*N*/ DBG_NAME(FmXUndoEnvironment)
//------------------------------------------------------------------------------
/*N*/ FmXUndoEnvironment::FmXUndoEnvironment(FmFormModel& _rModel)
/*N*/ 				   :rModel(_rModel)
/*N*/ 				   ,nLocks(0)
/*N*/ 				   ,bReadOnly(sal_False)
/*N*/ 				   ,m_pPropertySetCache(NULL)
/*N*/ {
/*N*/ 	DBG_CTOR(FmXUndoEnvironment,NULL);
/*N*/ }

//------------------------------------------------------------------------------
/*N*/ FmXUndoEnvironment::~FmXUndoEnvironment()
/*N*/ {
/*N*/ 	DBG_DTOR(FmXUndoEnvironment,NULL);
/*N*/ 	if (m_pPropertySetCache)
/*?*/ 		delete static_cast<PropertySetInfoCache*>(m_pPropertySetCache);
/*N*/ }

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
/*N*/ void FmXUndoEnvironment::ModeChanged()
/*N*/ {
/*N*/ 	if (bReadOnly != (rModel.GetObjectShell()->IsReadOnly() || rModel.GetObjectShell()->IsReadOnlyUI()))
/*N*/ 	{
/*N*/ 		bReadOnly = !bReadOnly;
/*N*/ 
/*N*/ 		sal_uInt16 nCount = rModel.GetPageCount();
/*N*/ 		sal_uInt16 i;
/*N*/ 		for (i = 0; i < nCount; i++)
/*N*/ 		{
/*N*/ 					Reference< XInterface >  xInt(((FmFormPage*)rModel.GetPage(i))->GetForms());
/*N*/ 			AlterPropertyListening(xInt);
/*N*/ 		}
/*N*/ 
/*N*/ 		nCount = rModel.GetMasterPageCount();
/*N*/ 		for (i = 0; i < nCount; i++)
/*N*/ 		{
/*N*/ 			Reference< XInterface >  xInt(((FmFormPage*)rModel.GetMasterPage(i))->GetForms());
/*N*/ 			AlterPropertyListening(xInt);
/*N*/ 		}
/*N*/ 
/*N*/ 		if (!bReadOnly)
/*N*/ 			StartListening(rModel);
/*N*/ 		else
/*?*/ 			EndListening(rModel);
/*N*/ 	}
/*N*/ }

//------------------------------------------------------------------------------
/*N*/ void FmXUndoEnvironment::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
/*N*/ {
/*N*/ 	if (rHint.ISA(SdrHint))
/*N*/ 	{
/*N*/ 		SdrHint* pSdrHint = (SdrHint*)&rHint;
/*N*/ 		switch( pSdrHint->GetKind() )
/*N*/ 		{
/*N*/ 			case HINT_OBJINSERTED:
/*N*/ 			{
/*N*/ 				SdrObject* pSdrObj = (SdrObject*)pSdrHint->GetObject();
/*N*/ 				Inserted( pSdrObj );
/*N*/ 			}	break;
/*N*/ 			case HINT_OBJREMOVED:
/*N*/ 			{
/*N*/ 				SdrObject* pSdrObj = (SdrObject*)pSdrHint->GetObject();
/*N*/ 				Removed( pSdrObj );
/*N*/ 			}
/*N*/ 			break;
/*N*/ 		}
/*N*/ 	}
/*N*/ 	else if (rHint.ISA(SfxSimpleHint))
/*N*/ 	{
/*N*/ 		switch ( ((SfxSimpleHint&)rHint).GetId() )
/*N*/ 		{
/*N*/ 			case SFX_HINT_DYING:
/*?*/				DBG_BF_ASSERT(0, "STRIP"); //STRIP001 /*?*/ 				Clear();
/*?*/ 				break;
/*N*/ 			case SFX_HINT_MODECHANGED:
/*N*/ 				ModeChanged();
/*N*/ 				break;
/*N*/ 		}
/*N*/ 	}
/*N*/ 	else if (rHint.ISA(SfxEventHint))
/*N*/ 	{
/*N*/ 		switch (((SfxEventHint&)rHint).GetEventId())
/*N*/ 		{
/*N*/ 		case SFX_EVENT_CREATEDOC:
/*N*/ 			case SFX_EVENT_OPENDOC:
/*N*/ 				ModeChanged();
/*N*/ 				break;
/*N*/ 		}
/*N*/ 	}
/*N*/ 
/*N*/ }

//------------------------------------------------------------------
/*N*/ void FmXUndoEnvironment::Inserted(SdrObject* pObj)
/*N*/ {
/*N*/ 	if (bReadOnly)
/*N*/ 		return;
/*N*/ 
/*N*/ 	if (pObj->GetObjInventor() == FmFormInventor)
/*N*/ 	{
/*N*/ 		FmFormObj* pFormObj = PTR_CAST(FmFormObj, pObj);
/*N*/ 		Inserted( pFormObj );
/*N*/ 	}
/*N*/ 	else if (pObj->IsGroupObject())
/*N*/ 	{
/*N*/ 		SdrObjListIter aIter(*pObj->GetSubList());
/*N*/ 		while (aIter.IsMore())
/*N*/ 		{
/*?*/ 			SdrObject* pObj = aIter.Next();
/*?*/ 			Inserted(pObj);
/*N*/ 		}
/*N*/ 	}
/*N*/ }

//------------------------------------------------------------------------------
/*N*/ void FmXUndoEnvironment::Inserted(FmFormObj* pObj)
/*N*/ {
/*N*/ 	DBG_ASSERT( pObj, "FmXUndoEnvironment::Inserted: invalid object!" );
/*N*/ 	if ( !pObj )
/*N*/ 		return;
/*N*/ 
/*N*/ 	// ist das Control noch einer Form zugeordnet
/*N*/ 	Reference< XInterface >  xModel = pObj->GetUnoControlModel();
/*N*/ 	Reference< XFormComponent >  xContent(xModel, UNO_QUERY);
/*N*/ 	if (xContent.is() && pObj->GetPage())
/*N*/ 	{
/*N*/ 		// Komponente gehoert noch keiner Form an
/*?*/ 		if (!xContent->getParent().is())
/*?*/ 		{
/*?*/			DBG_BF_ASSERT(0, "STRIP"); //STRIP001 /*?*/ 			// Einfuegen in den Parent falls noetig
/*?*/ 		}
/*?*/ 
/*?*/ 		// FormObject zuruecksetzen
/*?*/ 		pObj->SetObjEnv(Reference< XIndexContainer > ());
/*N*/ 	}
/*N*/ }

//------------------------------------------------------------------
/*N*/ void FmXUndoEnvironment::Removed(SdrObject* pObj)
/*N*/ {
/*N*/ 	if (bReadOnly)
/*N*/ 		return;
/*N*/ 
/*N*/ 	if (pObj->GetObjInventor() == FmFormInventor)
/*N*/ 	{
/*N*/ 		FmFormObj* pFormObj = PTR_CAST(FmFormObj, pObj);
/*N*/ 		Removed(pFormObj);
/*N*/ 	}
/*N*/ 	else if (pObj->IsGroupObject())
/*N*/ 	{
/*N*/ 		SdrObjListIter aIter(*pObj->GetSubList());
/*N*/ 		while (aIter.IsMore())
/*N*/ 		{
/*N*/ 			SdrObject* pObj = aIter.Next();
/*N*/ 			Removed(pObj);
/*N*/ 		}
/*N*/ 	}
/*N*/ }

//------------------------------------------------------------------------------
/*N*/ void FmXUndoEnvironment::Removed(FmFormObj* pObj)
/*N*/ {
/*N*/ 	DBG_ASSERT( pObj, "FmXUndoEnvironment::Removed: invalid object!" );
/*N*/ 	if ( !pObj )
/*N*/ 		return;
/*N*/ 
/*N*/ 	// ist das Control noch einer Form zugeordnet
/*N*/ 	Reference< XInterface >  xModel = pObj->GetUnoControlModel();
/*N*/ 	Reference< XFormComponent >  xContent(xModel, UNO_QUERY);
/*N*/ 	if (xContent.is())
/*N*/ 	{
/*N*/ 		// das Object wird aus einer Liste herausgenommen
/*N*/ 		// existiert ein Vater wird das Object beim beim Vater entfernt und
/*N*/ 		// am FormObject gemerkt!
/*N*/ 
/*N*/ 		// wird das Object wieder eingefuegt und ein Parent existiert, so wird dieser
/*N*/ 		// Parent wiederum gesetzt
/*N*/ 		Reference< XIndexContainer >  xForm(xContent->getParent(), UNO_QUERY);
/*N*/ 		if (xForm.is())
/*N*/ 		{
/*N*/ 			Reference< XIndexAccess >  xIndexAccess((XIndexContainer*)xForm.get());
/*N*/ 			// Feststellen an welcher Position sich das Kind befunden hat
/*N*/ 			sal_Int32 nPos = getElementPos(xIndexAccess, xContent);
/*N*/ 			if (nPos >= 0)
/*N*/ 			{
/*N*/ 				Sequence< ScriptEventDescriptor > aEvts;
/*N*/ 				Reference< XEventAttacherManager >	xManager(xForm, UNO_QUERY);
/*N*/ 				if (xManager.is())
/*N*/ 					aEvts = xManager->getScriptEvents(nPos);
/*N*/ 
/*N*/ 				try
/*N*/ 				{
/*N*/ 					pObj->SetObjEnv(xForm, nPos, aEvts);
/*N*/ 					xForm->removeByIndex(nPos);
/*N*/ 				}
/*N*/ 				catch(Exception&)
/*N*/ 				{
/*N*/ 				}
/*N*/ 
/*N*/ 			}
/*N*/ 		}
/*N*/ 	}
/*N*/ }

//	XEventListener
//------------------------------------------------------------------------------
/*?*/ void SAL_CALL FmXUndoEnvironment::disposing(const EventObject& e) throw( RuntimeException )
/*?*/ {
/*?*/	DBG_BF_ASSERT(0, "STRIP"); //STRIP001 	// check if it's an object we have cached informations about
/*?*/ }

// XPropertyChangeListener
//------------------------------------------------------------------------------
/*?*/ void SAL_CALL FmXUndoEnvironment::propertyChange(const PropertyChangeEvent& evt) throw(::com::sun::star::uno::RuntimeException)
/*?*/ {
/*?*/ DBG_BF_ASSERT(0, "STRIP"); //STRIP001 //STRIP001 	::vos::OClearableGuard aGuard( Application::GetSolarMutex() );
/*?*/ }

// XContainerListener
//------------------------------------------------------------------------------
/*N*/ void SAL_CALL FmXUndoEnvironment::elementInserted(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException)
/*N*/ {
/*N*/ 	::vos::OClearableGuard aGuard( Application::GetSolarMutex() );
/*N*/ 	// neues Object zum lauschen
/*N*/ 	Reference< XInterface >  xIface;
/*N*/ 	evt.Element >>= xIface;
/*N*/ 	OSL_ENSURE(xIface.is(), "FmXUndoEnvironment::elementInserted: invalid container notification!");
/*N*/ 	AddElement(xIface);
/*N*/ 
/*N*/ 	if (!IsLocked() && rModel.GetObjectShell())
/*N*/ 	{
/*N*/ 		rModel.GetObjectShell()->SetModified(sal_True);
/*N*/ 	}
/*N*/ }

//------------------------------------------------------------------------------
/*?*/ void SAL_CALL FmXUndoEnvironment::elementReplaced(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException)
/*?*/ {
/*?*/ DBG_BF_ASSERT(0, "STRIP"); //STRIP001 //STRIP001 	::vos::OClearableGuard aGuard( Application::GetSolarMutex() );
/*?*/ }

//------------------------------------------------------------------------------
/*N*/ void SAL_CALL FmXUndoEnvironment::elementRemoved(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException)
/*N*/ {
/*N*/ 	::vos::OClearableGuard aGuard( Application::GetSolarMutex() );
/*N*/ 	Reference< XInterface >  xIface;
/*N*/ 	evt.Element >>= xIface;
/*N*/ 	OSL_ENSURE(xIface.is(), "FmXUndoEnvironment::elementRemoved: invalid container notification!");
/*N*/ 	RemoveElement(xIface);
/*N*/ 
/*N*/ 	if (!IsLocked() && rModel.GetObjectShell())
/*N*/ 	{
/*?*/ 		rModel.GetObjectShell()->SetModified(sal_True);
/*N*/ 	}
/*N*/ }

//------------------------------------------------------------------------------
/*N*/ void FmXUndoEnvironment::AddForms(const Reference< XNameContainer > & rForms)
/*N*/ {
/*N*/ 	Lock();
/*N*/ 	Reference< XInterface >  xInt = rForms;
/*N*/ 	AddElement(xInt);
/*N*/ 	UnLock();
/*N*/ }

//------------------------------------------------------------------------------
/*N*/ void FmXUndoEnvironment::RemoveForms(const Reference< XNameContainer > & rForms)
/*N*/ {
/*N*/ 	Lock();
/*N*/ 	Reference< XInterface >  xInt = rForms;
/*N*/ 	RemoveElement(xInt);
/*N*/ 	UnLock();
/*N*/ }

//------------------------------------------------------------------------------
/*N*/ void FmXUndoEnvironment::AlterPropertyListening(const Reference< XInterface > & Element)
/*N*/ {
/*N*/ 	// am Container horchen
/*N*/ 	Reference< XIndexContainer >  xContainer(Element, UNO_QUERY);
/*N*/ 	if (xContainer.is())
/*N*/ 	{
/*N*/ 		sal_uInt32 nCount = xContainer->getCount();
/*N*/ 		Reference< XInterface >  xIface;
/*N*/ 		for (sal_uInt32 i = 0; i < nCount; i++)
/*N*/ 		{
/*N*/ 			xContainer->getByIndex(i) >>= xIface;
/*N*/ 			AlterPropertyListening(xIface);
/*N*/ 		}
/*N*/ 	}
/*N*/ 
/*N*/ 	Reference< XPropertySet >  xSet(Element, UNO_QUERY);
/*N*/ 	if (xSet.is())
/*N*/ 	{
/*N*/ 		if (!bReadOnly)
/*N*/ 			xSet->addPropertyChangeListener(::rtl::OUString(), (XPropertyChangeListener*)this);
/*N*/ 		else
/*N*/ 			xSet->removePropertyChangeListener(::rtl::OUString(), (XPropertyChangeListener*)this);
/*N*/ 	}
/*N*/ }


//------------------------------------------------------------------------------
/*N*/ void FmXUndoEnvironment::AddElement(const Reference< XInterface > & Element)
/*N*/ {
/*N*/ 	// am Container horchen
/*N*/ 	Reference< XIndexContainer >  xContainer(Element, UNO_QUERY);
/*N*/ 	if (xContainer.is())
/*N*/ 	{
/*N*/ 		// Wenn der Container ein EventAttachManager ist, mussen wir uns
/*N*/ 		// auch noch als ScriptListener anmelden.
/*N*/ 		Reference< XEventAttacherManager >	xEAManager(Element, UNO_QUERY);
/*N*/ 		if( xEAManager.is() )
/*N*/ 			xEAManager->addScriptListener( (XScriptListener*)this );
/*N*/ 
/*N*/ 		sal_uInt32 nCount = xContainer->getCount();
/*N*/ 		Reference< XInterface >  xIface;
/*N*/ 		for (sal_uInt32 i = 0; i < nCount; i++)
/*N*/ 		{
/*N*/ 			xContainer->getByIndex(i) >>= xIface;
/*N*/ 			AddElement(xIface);
/*N*/ 		}
/*N*/ 
/*N*/ 		Reference< XContainer >  xCont(Element, UNO_QUERY);
/*N*/ 		if (xCont.is())
/*N*/ 			xCont->addContainerListener((XContainerListener*)this);
/*N*/ 	}
/*N*/ 
/*N*/ 	if (!bReadOnly)
/*N*/ 	{
/*N*/ 		// auf Properties horchen
/*N*/ 		Reference< XPropertySet >  xSet(Element, UNO_QUERY);
/*N*/ 		if (xSet.is())
/*N*/ 			xSet->addPropertyChangeListener(::rtl::OUString(), (XPropertyChangeListener*)this);
/*N*/ 	}
/*N*/ }

//------------------------------------------------------------------------------
/*N*/ void FmXUndoEnvironment::RemoveElement(const Reference< XInterface > & Element)
/*N*/ {
/*N*/ 	if (!bReadOnly)
/*N*/ 	{
/*N*/ 		// Verbindung zu PropertySet aufheben
/*N*/ 		Reference< XPropertySet >  xSet(Element, UNO_QUERY);
/*N*/ 		if (xSet.is())
/*N*/ 		{
/*N*/ 			xSet->removePropertyChangeListener(::rtl::OUString(), (XPropertyChangeListener*)this);
/*N*/ 
/*N*/ 			Reference< XForm >	xForm(xSet, UNO_QUERY);
/*N*/ 			if (xForm.is())
/*N*/ 			{
/*N*/ 				// reset the ActiveConnection if the form is to be removed. This will (should) free the resources
/*N*/ 				// associated with this connection
/*N*/ 				// 86299 - 05/02/2001 - frank.schoenheit@germany.sun.com
/*N*/ 				xSet->setPropertyValue(FM_PROP_ACTIVE_CONNECTION, Any());
/*N*/ 			}
/*N*/ 		}
/*N*/ 	}
/*N*/ 
/*N*/ 	// Verbindung zu Kindern aufheben
/*N*/ 	Reference< XIndexContainer >  xContainer(Element, UNO_QUERY);
/*N*/ 	if (xContainer.is())
/*N*/ 	{
/*N*/ 		Reference< XContainer >  xCont(Element, UNO_QUERY);
/*N*/ 		if (xCont.is())
/*N*/ 			xCont->removeContainerListener((XContainerListener*)this);
/*N*/ 
/*N*/ 		// Wenn der Container ein EventAttachManager ist, mussen wir uns
/*N*/ 		// auch noch als ScriptListener anmelden.
/*N*/ 		Reference< XEventAttacherManager >	xEAManager(Element, UNO_QUERY);
/*N*/ 		if( xEAManager.is() )
/*N*/ 			xEAManager->removeScriptListener( (XScriptListener*)this );
/*N*/ 
/*N*/ 		sal_uInt32 nCount = xContainer->getCount();
/*N*/ 		Reference< XInterface >  xIface;
/*N*/ 		for (sal_uInt32 i = 0; i < nCount; i++)
/*N*/ 		{
/*N*/ 			xContainer->getByIndex(i) >>= xIface;
/*N*/ 			RemoveElement(xIface);
/*N*/ 		}
/*N*/ 	}
/*N*/ }


// XScriptListener

/*?*/ void SAL_CALL FmXUndoEnvironment::firing(const ScriptEvent& evt) throw(::com::sun::star::uno::RuntimeException)
/*?*/ {
/*?*/ DBG_BF_ASSERT(0, "STRIP"); //STRIP001 //STRIP001 	firing_Impl( evt );
/*?*/ }

//------------------------------------------------------------------------------
/*?*/ Any SAL_CALL FmXUndoEnvironment::approveFiring(const ScriptEvent& evt) throw(::com::sun::star::reflection::InvocationTargetException, ::com::sun::star::uno::RuntimeException)
/*?*/ {
/*?*/ DBG_BF_ASSERT(0, "STRIP"); Any aRet; return aRet; //STRIP001 	Any aRet;
/*?*/ //STRIP001 	firing_Impl( evt, &aRet );
/*?*/ //STRIP001 	return aRet;
/*?*/ }

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------


DBG_NAME(FmUndoContainerAction)
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------




}
