xref: /trunk/main/svx/source/form/fmundo.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 
31 #include "fmundo.hxx"
32 #include "fmpgeimp.hxx"
33 #include "svx/dbtoolsclient.hxx"
34 #include "svx/svditer.hxx"
35 #include "fmobj.hxx"
36 #include "fmprop.hrc"
37 #include "svx/fmresids.hrc"
38 #include "svx/fmglob.hxx"
39 #include "svx/dialmgr.hxx"
40 #include "svx/fmmodel.hxx"
41 #include "svx/fmpage.hxx"
42 
43 /** === begin UNO includes === **/
44 #include <com/sun/star/util/XModifyBroadcaster.hpp>
45 #include <com/sun/star/beans/PropertyAttribute.hpp>
46 #include <com/sun/star/container/XContainer.hpp>
47 #include <com/sun/star/container/XContainerListener.hpp>
48 #include <com/sun/star/script/XEventAttacherManager.hpp>
49 #include <com/sun/star/form/binding/XBindableValue.hpp>
50 #include <com/sun/star/form/binding/XListEntrySink.hpp>
51 #include <com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp>
52 /** === end UNO includes === **/
53 
54 #include "svx/fmtools.hxx"
55 #include <rtl/logfile.hxx>
56 #include <svl/macitem.hxx>
57 #include <tools/shl.hxx>
58 #include <tools/diagnose_ex.h>
59 #include <sfx2/objsh.hxx>
60 #include <sfx2/docfile.hxx>
61 #include <sfx2/app.hxx>
62 #include <sfx2/sfx.hrc>
63 #include <sfx2/event.hxx>
64 #include <osl/mutex.hxx>
65 #include <vos/mutex.hxx>
66 #include <comphelper/property.hxx>
67 #include <comphelper/uno3.hxx>
68 #include <comphelper/stl_types.hxx>
69 #include <comphelper/componentcontext.hxx>
70 
71 using namespace ::com::sun::star::uno;
72 using namespace ::com::sun::star::awt;
73 using namespace ::com::sun::star::beans;
74 using namespace ::com::sun::star::container;
75 using namespace ::com::sun::star::script;
76 using namespace ::com::sun::star::lang;
77 using namespace ::com::sun::star::form;
78 using namespace ::com::sun::star::util;
79 using namespace ::com::sun::star::reflection;
80 using namespace ::com::sun::star::form::binding;
81 using namespace ::svxform;
82 
83 
84 #include <com/sun/star/script/XScriptListener.hdl>
85 #include <comphelper/processfactory.hxx>
86 #include <cppuhelper/implbase1.hxx>
87 
88 typedef cppu::WeakImplHelper1< XScriptListener > ScriptEventListener_BASE;
89 class ScriptEventListenerWrapper : public ScriptEventListener_BASE
90 {
91 public:
92 	ScriptEventListenerWrapper( FmFormModel& _rModel) throw ( RuntimeException )
93 		:m_rModel( _rModel )
94 		,m_attemptedListenerCreation( false )
95 	{
96 
97 	}
98     // XEventListener
99     virtual void SAL_CALL disposing(const EventObject& ) throw( RuntimeException ){}
100 
101     // XScriptListener
102     virtual void SAL_CALL firing(const  ScriptEvent& evt) throw(RuntimeException)
103 	{
104 		attemptListenerCreation();
105 		if ( m_vbaListener.is() )
106 		{
107 			m_vbaListener->firing( evt );
108 		}
109 	}
110 
111     virtual Any SAL_CALL approveFiring(const ScriptEvent& evt) throw( com::sun::star::reflection::InvocationTargetException, RuntimeException)
112 	{
113 		attemptListenerCreation();
114 		if ( m_vbaListener.is() )
115 		{
116 			return m_vbaListener->approveFiring( evt );
117 		}
118 		return Any();
119 	}
120 
121 private:
122 	void attemptListenerCreation()
123 	{
124 		if ( m_attemptedListenerCreation )
125 			return;
126 		m_attemptedListenerCreation = true;
127 
128 		try
129 		{
130 			::comphelper::ComponentContext const aContext( ::comphelper::getProcessServiceFactory() );
131 			Reference< XScriptListener > const xScriptListener( aContext.createComponent( "ooo.vba.EventListener" ), UNO_QUERY_THROW );
132 			Reference< XPropertySet > const xListenerProps( xScriptListener, UNO_QUERY_THROW );
133             // SfxObjectShellRef is good here since the model controls the lifetime of the shell
134 			SfxObjectShellRef const xObjectShell = m_rModel.GetObjectShell();
135 			ENSURE_OR_THROW( xObjectShell.Is(), "no object shell!" );
136 			xListenerProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Model" ) ), makeAny( xObjectShell->GetModel() ) );
137 
138 			m_vbaListener = xScriptListener;
139 		}
140 		catch( Exception const & )
141 		{
142 			DBG_UNHANDLED_EXCEPTION();
143 		}
144 	}
145     FmFormModel&					m_rModel;
146 	Reference< XScriptListener >	m_vbaListener;
147 	bool							m_attemptedListenerCreation;
148 
149 
150 };
151 
152 //------------------------------------------------------------------------------
153 // some helper structs for caching property infos
154 //------------------------------------------------------------------------------
155 struct PropertyInfo
156 {
157 	sal_Bool	bIsTransientOrReadOnly	: 1;	// the property is transient or read-only, thus we need no undo action for it
158 	sal_Bool	bIsValueProperty	    : 1;	// the property is the special value property, thus it may be handled
159 										    // as if it's transient or persistent
160 };
161 
162 struct PropertySetInfo
163 {
164 	DECLARE_STL_USTRINGACCESS_MAP(PropertyInfo, AllProperties);
165 
166 	AllProperties	aProps; 				// all properties of this set which we know so far
167 	sal_Bool			bHasEmptyControlSource; // sal_True -> the set has a DataField property, and the current value is an empty string
168 											// sal_False -> the set has _no_ such property or it's value isn't empty
169 };
170 
171 sal_Bool operator < (const Reference< XPropertySet >& lhs,
172 				 const Reference< XPropertySet >& rhs)
173 {
174 	return lhs.get() < rhs.get();
175 }
176 
177 DECLARE_STL_STDKEY_MAP(Reference< XPropertySet >, PropertySetInfo, PropertySetInfoCache);
178 
179 //------------------------------------------------------------------------------
180 
181 String static_STR_UNDO_PROPERTY;
182 //------------------------------------------------------------------------------
183 DBG_NAME(FmXUndoEnvironment)
184 //------------------------------------------------------------------------------
185 FmXUndoEnvironment::FmXUndoEnvironment(FmFormModel& _rModel)
186 				   :rModel( _rModel )
187                    ,m_pPropertySetCache( NULL )
188                    ,m_pScriptingEnv( ::svxform::createDefaultFormScriptingEnvironment( _rModel ) )
189 				   ,m_Locks( 0 )
190 				   ,bReadOnly( sal_False )
191                    ,m_bDisposed( false )
192 {
193     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::FmXUndoEnvironment" );
194 	DBG_CTOR(FmXUndoEnvironment,NULL);
195 	try
196 	{
197 		m_vbaListener =  new ScriptEventListenerWrapper( _rModel );
198 	}
199 	catch( Exception& )
200 	{
201 	}
202 }
203 
204 //------------------------------------------------------------------------------
205 FmXUndoEnvironment::~FmXUndoEnvironment()
206 {
207 	DBG_DTOR(FmXUndoEnvironment,NULL);
208 	if (m_pPropertySetCache)
209 		delete static_cast<PropertySetInfoCache*>(m_pPropertySetCache);
210 }
211 
212 //------------------------------------------------------------------------------
213 void FmXUndoEnvironment::dispose()
214 {
215     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::dispose" );
216     OSL_ENSURE( !m_bDisposed, "FmXUndoEnvironment::dispose: disposed twice?" );
217     if ( !m_bDisposed )
218         return;
219 
220 	Lock();
221 
222     sal_uInt16 nCount = rModel.GetPageCount();
223 	sal_uInt16 i;
224 	for (i = 0; i < nCount; i++)
225 	{
226         FmFormPage* pPage = PTR_CAST( FmFormPage, rModel.GetPage(i) );
227         if ( pPage )
228         {
229             Reference< XInterface > xForms = pPage->GetForms( false ).get();
230             if ( xForms.is() )
231 		        RemoveElement( xForms );
232         }
233 	}
234 
235 	nCount = rModel.GetMasterPageCount();
236 	for (i = 0; i < nCount; i++)
237 	{
238         FmFormPage* pPage = PTR_CAST( FmFormPage, rModel.GetMasterPage(i) );
239         if ( pPage )
240         {
241             Reference< XInterface > xForms = pPage->GetForms( false ).get();
242             if ( xForms.is() )
243 		        RemoveElement( xForms );
244         }
245 	}
246 
247     UnLock();
248 
249     OSL_PRECOND( rModel.GetObjectShell(), "FmXUndoEnvironment::dispose: no object shell anymore!" );
250     if ( rModel.GetObjectShell() )
251 	    EndListening( *rModel.GetObjectShell() );
252 
253 	if ( IsListening( rModel ) )
254 		EndListening( rModel );
255 
256     m_pScriptingEnv->dispose();
257 
258     m_bDisposed = true;
259 }
260 
261 //------------------------------------------------------------------------------
262 void FmXUndoEnvironment::ModeChanged()
263 {
264     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::ModeChanged" );
265     OSL_PRECOND( rModel.GetObjectShell(), "FmXUndoEnvironment::ModeChanged: no object shell anymore!" );
266     if ( !rModel.GetObjectShell() )
267         return;
268 
269 	if (bReadOnly != (rModel.GetObjectShell()->IsReadOnly() || rModel.GetObjectShell()->IsReadOnlyUI()))
270 	{
271 		bReadOnly = !bReadOnly;
272 
273 		sal_uInt16 nCount = rModel.GetPageCount();
274 		sal_uInt16 i;
275 		for (i = 0; i < nCount; i++)
276 		{
277             FmFormPage* pPage = PTR_CAST( FmFormPage, rModel.GetPage(i) );
278             if ( pPage )
279             {
280                 Reference< XInterface > xForms = pPage->GetForms( false ).get();
281                 if ( xForms.is() )
282                     TogglePropertyListening( xForms );
283             }
284 		}
285 
286 		nCount = rModel.GetMasterPageCount();
287 		for (i = 0; i < nCount; i++)
288 		{
289             FmFormPage* pPage = PTR_CAST( FmFormPage, rModel.GetMasterPage(i) );
290             if ( pPage )
291             {
292                 Reference< XInterface > xForms = pPage->GetForms( false ).get();
293                 if ( xForms.is() )
294 		            TogglePropertyListening( xForms );
295             }
296 		}
297 
298 		if (!bReadOnly)
299 			StartListening(rModel);
300 		else
301 			EndListening(rModel);
302 	}
303 }
304 
305 //------------------------------------------------------------------------------
306 void FmXUndoEnvironment::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
307 {
308     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::Notify" );
309 	if (rHint.ISA(SdrHint))
310 	{
311 		SdrHint* pSdrHint = (SdrHint*)&rHint;
312 		switch( pSdrHint->GetKind() )
313 		{
314 			case HINT_OBJINSERTED:
315 			{
316 				SdrObject* pSdrObj = (SdrObject*)pSdrHint->GetObject();
317 				Inserted( pSdrObj );
318 			}	break;
319 			case HINT_OBJREMOVED:
320 			{
321 				SdrObject* pSdrObj = (SdrObject*)pSdrHint->GetObject();
322 				Removed( pSdrObj );
323 			}
324 			break;
325             default:
326                 break;
327 		}
328 	}
329 	else if (rHint.ISA(SfxSimpleHint))
330 	{
331 		switch ( ((SfxSimpleHint&)rHint).GetId() )
332 		{
333 			case SFX_HINT_DYING:
334 				dispose();
335                 rModel.SetObjectShell( NULL );
336 				break;
337 			case SFX_HINT_MODECHANGED:
338 				ModeChanged();
339 				break;
340 		}
341 	}
342 	else if (rHint.ISA(SfxEventHint))
343 	{
344 		switch (((SfxEventHint&)rHint).GetEventId())
345 		{
346 		case SFX_EVENT_CREATEDOC:
347 			case SFX_EVENT_OPENDOC:
348 				ModeChanged();
349 				break;
350 		}
351 	}
352 
353 }
354 
355 //------------------------------------------------------------------
356 void FmXUndoEnvironment::Inserted(SdrObject* pObj)
357 {
358     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::Inserted" );
359 	if (pObj->GetObjInventor() == FmFormInventor)
360 	{
361 		FmFormObj* pFormObj = PTR_CAST(FmFormObj, pObj);
362 		Inserted( pFormObj );
363 	}
364 	else if (pObj->IsGroupObject())
365 	{
366 		SdrObjListIter aIter(*pObj->GetSubList());
367 		while ( aIter.IsMore() )
368 			Inserted( aIter.Next() );
369 	}
370 }
371 
372 //------------------------------------------------------------------------------
373 namespace
374 {
375     sal_Bool lcl_searchElement(const Reference< XIndexAccess>& xCont, const Reference< XInterface >& xElement)
376     {
377 	    if (!xCont.is() || !xElement.is())
378 		    return sal_False;
379 
380 	    sal_Int32 nCount = xCont->getCount();
381 	    Reference< XInterface > xComp;
382 	    for (sal_Int32 i = 0; i < nCount; i++)
383 	    {
384 		    try
385 		    {
386 			    xCont->getByIndex(i) >>= xComp;
387 			    if (xComp.is())
388 			    {
389 				    if ( xElement == xComp )
390 					    return sal_True;
391 				    else
392 				    {
393 					    Reference< XIndexAccess> xCont2(xComp, UNO_QUERY);
394 					    if (xCont2.is() && lcl_searchElement(xCont2, xElement))
395 						    return sal_True;
396 				    }
397 			    }
398 		    }
399 		    catch(const Exception&)
400 		    {
401                 DBG_UNHANDLED_EXCEPTION();
402 		    }
403 	    }
404 	    return sal_False;
405     }
406 }
407 
408 //------------------------------------------------------------------------------
409 void FmXUndoEnvironment::Inserted(FmFormObj* pObj)
410 {
411     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::Inserted" );
412 	DBG_ASSERT( pObj, "FmXUndoEnvironment::Inserted: invalid object!" );
413 	if ( !pObj )
414 		return;
415 
416 	// ist das Control noch einer Form zugeordnet
417 	Reference< XInterface >  xModel(pObj->GetUnoControlModel(), UNO_QUERY);
418 	Reference< XFormComponent >  xContent(xModel, UNO_QUERY);
419 	if (xContent.is() && pObj->GetPage())
420 	{
421 		// if the component doesn't belong to a form, yet, find one to insert into
422 		if (!xContent->getParent().is())
423 		{
424             try
425             {
426 			    Reference< XIndexContainer > xObjectParent = pObj->GetOriginalParent();
427 
428                 FmFormPage& rPage = dynamic_cast< FmFormPage& >( *pObj->GetPage() );
429 			    Reference< XIndexAccess >  xForms( rPage.GetForms(), UNO_QUERY_THROW );
430 
431 			    Reference< XIndexContainer > xNewParent;
432                 Reference< XForm >           xForm;
433 			    sal_Int32 nPos = -1;
434 			    if ( lcl_searchElement( xForms, xObjectParent ) )
435                 {
436                     // the form which was the parent of the object when it was removed is still
437                     // part of the form component hierachy of the current page
438 				    xNewParent = xObjectParent;
439                     xForm.set( xNewParent, UNO_QUERY_THROW );
440                     nPos = ::std::min( pObj->GetOriginalIndex(), xNewParent->getCount() );
441                 }
442 			    else
443 			    {
444 				    xForm.set( rPage.GetImpl().findPlaceInFormComponentHierarchy( xContent ), UNO_SET_THROW );
445 				    xNewParent.set( xForm, UNO_QUERY_THROW );
446                     nPos = xNewParent->getCount();
447 			    }
448 
449                 rPage.GetImpl().setUniqueName( xContent, xForm );
450 			    xNewParent->insertByIndex( nPos, makeAny( xContent ) );
451 
452                 Reference< XEventAttacherManager >	xManager( xNewParent, UNO_QUERY_THROW );
453 			    xManager->registerScriptEvents( nPos, pObj->GetOriginalEvents() );
454             }
455             catch( const Exception& )
456             {
457             	DBG_UNHANDLED_EXCEPTION();
458             }
459 		}
460 
461 		// FormObject zuruecksetzen
462 		pObj->ClearObjEnv();
463 	}
464 }
465 
466 //------------------------------------------------------------------
467 void FmXUndoEnvironment::Removed(SdrObject* pObj)
468 {
469     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::Removed" );
470     if ( pObj->IsVirtualObj() )
471         // for virtual objects, we've already been notified of the removal of the master
472         // object, which is sufficient here
473         return;
474 
475 	if (pObj->GetObjInventor() == FmFormInventor)
476 	{
477 		FmFormObj* pFormObj = PTR_CAST(FmFormObj, pObj);
478 		Removed(pFormObj);
479 	}
480 	else if (pObj->IsGroupObject())
481 	{
482 		SdrObjListIter aIter(*pObj->GetSubList());
483 		while ( aIter.IsMore() )
484 			Removed( aIter.Next() );
485 	}
486 }
487 
488 //------------------------------------------------------------------------------
489 void FmXUndoEnvironment::Removed(FmFormObj* pObj)
490 {
491     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::Removed" );
492 	DBG_ASSERT( pObj, "FmXUndoEnvironment::Removed: invalid object!" );
493 	if ( !pObj )
494 		return;
495 
496 	// ist das Control noch einer Form zugeordnet
497 	Reference< XFormComponent >  xContent(pObj->GetUnoControlModel(), UNO_QUERY);
498 	if (xContent.is())
499 	{
500 		// das Object wird aus einer Liste herausgenommen
501 		// existiert ein Vater wird das Object beim beim Vater entfernt und
502 		// am FormObject gemerkt!
503 
504 		// wird das Object wieder eingefuegt und ein Parent existiert, so wird dieser
505 		// Parent wiederum gesetzt
506 		Reference< XIndexContainer >  xForm(xContent->getParent(), UNO_QUERY);
507 		if (xForm.is())
508 		{
509 			Reference< XIndexAccess >  xIndexAccess((XIndexContainer*)xForm.get());
510 			// Feststellen an welcher Position sich das Kind befunden hat
511 			const sal_Int32 nPos = getElementPos(xIndexAccess, xContent);
512 			if (nPos >= 0)
513 			{
514 				Sequence< ScriptEventDescriptor > aEvts;
515 				Reference< XEventAttacherManager >	xManager(xForm, UNO_QUERY);
516 				if (xManager.is())
517 					aEvts = xManager->getScriptEvents(nPos);
518 
519 				try
520 				{
521 					pObj->SetObjEnv(xForm, nPos, aEvts);
522 					xForm->removeByIndex(nPos);
523 				}
524 				catch(Exception&)
525 				{
526                     DBG_UNHANDLED_EXCEPTION();
527 				}
528 
529 			}
530 		}
531 	}
532 }
533 
534 //	XEventListener
535 //------------------------------------------------------------------------------
536 void SAL_CALL FmXUndoEnvironment::disposing(const EventObject& e) throw( RuntimeException )
537 {
538     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::disposing" );
539 	// check if it's an object we have cached informations about
540 	if (m_pPropertySetCache)
541 	{
542 		Reference< XPropertySet > xSourceSet(e.Source, UNO_QUERY);
543 		if (xSourceSet.is())
544 		{
545 			PropertySetInfoCache* pCache = static_cast<PropertySetInfoCache*>(m_pPropertySetCache);
546 			PropertySetInfoCacheIterator aSetPos = pCache->find(xSourceSet);
547 			if (aSetPos != pCache->end())
548 				pCache->erase(aSetPos);
549 		}
550 	}
551 }
552 
553 // XPropertyChangeListener
554 //------------------------------------------------------------------------------
555 void SAL_CALL FmXUndoEnvironment::propertyChange(const PropertyChangeEvent& evt) throw(::com::sun::star::uno::RuntimeException)
556 {
557     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::propertyChange" );
558     ::osl::ClearableMutexGuard aGuard( m_aMutex );
559 
560 	if (!IsLocked())
561 	{
562 		Reference< XPropertySet >  xSet(evt.Source, UNO_QUERY);
563 		if (!xSet.is())
564 			return;
565 
566 		// if it's a "default value" property of a control model, set the according "value" property
567 		static ::rtl::OUString pDefaultValueProperties[] = {
568 			FM_PROP_DEFAULT_TEXT, FM_PROP_DEFAULTCHECKED, FM_PROP_DEFAULT_DATE, FM_PROP_DEFAULT_TIME,
569 			FM_PROP_DEFAULT_VALUE, FM_PROP_DEFAULT_SELECT_SEQ, FM_PROP_EFFECTIVE_DEFAULT
570 		};
571 		const ::rtl::OUString aValueProperties[] = {
572 			FM_PROP_TEXT, FM_PROP_STATE, FM_PROP_DATE, FM_PROP_TIME,
573 			FM_PROP_VALUE, FM_PROP_SELECT_SEQ, FM_PROP_EFFECTIVE_VALUE
574 		};
575 		sal_Int32 nDefaultValueProps = sizeof(pDefaultValueProperties)/sizeof(pDefaultValueProperties[0]);
576 		OSL_ENSURE(sizeof(aValueProperties)/sizeof(aValueProperties[0]) == nDefaultValueProps,
577 			"FmXUndoEnvironment::propertyChange: inconsistence!");
578 		for (sal_Int32 i=0; i<nDefaultValueProps; ++i)
579 		{
580 			if (0 == evt.PropertyName.compareTo(pDefaultValueProperties[i]))
581 			{
582 				try
583 				{
584 					xSet->setPropertyValue(aValueProperties[i], evt.NewValue);
585 				}
586 				catch(const Exception&)
587 				{
588 					OSL_ENSURE(sal_False, "FmXUndoEnvironment::propertyChange: could not adjust the value property!");
589 				}
590 			}
591 		}
592 
593 		// no Undo for transient and readonly props. But unfortunately "transient" is not only that the
594 		// "transient" flag is set for the property in question, instead is is somewhat more complex
595         // Transience criterions are:
596         // - the "transient" flag is set for the property
597         // - OR the control has a non-empty COntrolSource property, i.e. is intended to be bound
598         //   to a database column. Note that it doesn't matter here whether the control actually
599         //   *is* bound to a column
600         // - OR the control is bound to an external value via XBindableValue/XValueBinding
601         //   which does not have a "ExternalData" property being <TRUE/>
602 
603 		if (!m_pPropertySetCache)
604 			m_pPropertySetCache = new PropertySetInfoCache;
605 		PropertySetInfoCache* pCache = static_cast<PropertySetInfoCache*>(m_pPropertySetCache);
606 
607 		// let's see if we know something about the set
608 		PropertySetInfoCacheIterator aSetPos = pCache->find(xSet);
609 		if (aSetPos == pCache->end())
610 		{
611 			PropertySetInfo aNewEntry;
612 			if (!::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xSet))
613 			{
614 				aNewEntry.bHasEmptyControlSource = sal_False;
615 			}
616 			else
617 			{
618 				try
619 				{
620 					Any aCurrentControlSource = xSet->getPropertyValue(FM_PROP_CONTROLSOURCE);
621 					aNewEntry.bHasEmptyControlSource = !aCurrentControlSource.hasValue() || (::comphelper::getString(aCurrentControlSource).getLength() == 0);
622 				}
623 				catch(const Exception&)
624 				{
625                     DBG_UNHANDLED_EXCEPTION();
626 				}
627 			}
628 			aSetPos = pCache->insert(PropertySetInfoCache::value_type(xSet,aNewEntry)).first;
629 			DBG_ASSERT(aSetPos != pCache->end(), "FmXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?");
630 		}
631 		else
632 		{	// is it the DataField property ?
633 			if (evt.PropertyName.equals(FM_PROP_CONTROLSOURCE))
634 			{
635 				aSetPos->second.bHasEmptyControlSource = !evt.NewValue.hasValue() || (::comphelper::getString(evt.NewValue).getLength() == 0);
636 			}
637 		}
638 
639 		// now we have access to the cached info about the set
640 		// let's see what we know about the property
641 		PropertySetInfo::AllProperties& rPropInfos = aSetPos->second.aProps;
642 		PropertySetInfo::AllPropertiesIterator aPropertyPos = rPropInfos.find(evt.PropertyName);
643 		if (aPropertyPos == rPropInfos.end())
644 		{	// nothing 'til now ... have to change this ....
645 			PropertyInfo aNewEntry;
646 
647 			// the attributes
648 			sal_Int32 nAttributes = xSet->getPropertySetInfo()->getPropertyByName(evt.PropertyName).Attributes;
649 			aNewEntry.bIsTransientOrReadOnly = ((nAttributes & PropertyAttribute::READONLY) != 0) || ((nAttributes & PropertyAttribute::TRANSIENT) != 0);
650 
651 			// check if it is the special "DataFieldProperty"
652 			aNewEntry.bIsValueProperty = sal_False;
653 			try
654 			{
655 				if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCEPROPERTY, xSet))
656 				{
657 					Any aControlSourceProperty = xSet->getPropertyValue(FM_PROP_CONTROLSOURCEPROPERTY);
658 					::rtl::OUString sControlSourceProperty;
659 					aControlSourceProperty >>= sControlSourceProperty;
660 
661 					aNewEntry.bIsValueProperty = (sControlSourceProperty.equals(evt.PropertyName));
662 				}
663 			}
664 			catch(const Exception&)
665 			{
666                 DBG_UNHANDLED_EXCEPTION();
667 			}
668 
669 			// insert the new entry
670 			aPropertyPos = rPropInfos.insert(PropertySetInfo::AllProperties::value_type(evt.PropertyName,aNewEntry)).first;
671 			DBG_ASSERT(aPropertyPos != rPropInfos.end(), "FmXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?");
672 		}
673 
674 		// now we have access to the cached info about the property affected
675 		// and are able to decide wether or not we need an undo action
676 
677         bool bAddUndoAction = rModel.IsUndoEnabled();
678         // no UNDO for transient/readonly properties
679         if ( bAddUndoAction && aPropertyPos->second.bIsTransientOrReadOnly )
680             bAddUndoAction = false;
681 
682 		if ( bAddUndoAction && aPropertyPos->second.bIsValueProperty )
683 		{
684             // no UNDO when the "value" property changes, but the ControlSource is non-empty
685             // (in this case the control is intended to be bound to a database column)
686             if ( !aSetPos->second.bHasEmptyControlSource )
687                 bAddUndoAction = false;
688 
689             // no UNDO if the control is currently bound to an external value
690             if ( bAddUndoAction )
691             {
692                 Reference< XBindableValue > xBindable( evt.Source, UNO_QUERY );
693                 Reference< XValueBinding > xBinding;
694                 if ( xBindable.is() )
695                     xBinding = xBindable->getValueBinding();
696 
697                 Reference< XPropertySet > xBindingProps;
698                 Reference< XPropertySetInfo > xBindingPropsPSI;
699                 if ( xBindable.is() )
700                     xBindingProps.set( xBinding, UNO_QUERY );
701                 if ( xBindingProps.is() )
702                     xBindingPropsPSI = xBindingProps->getPropertySetInfo();
703                 // TODO: we should cache all those things, else this might be too expensive.
704                 // However, this requires we're notified of changes in the value binding
705 
706                 static const ::rtl::OUString s_sExternalData( RTL_CONSTASCII_USTRINGPARAM( "ExternalData" ) );
707                 if ( xBindingPropsPSI.is() && xBindingPropsPSI->hasPropertyByName( s_sExternalData ) )
708                 {
709                     sal_Bool bExternalData = sal_True;
710                     OSL_VERIFY( xBindingProps->getPropertyValue( s_sExternalData ) >>= bExternalData );
711                     bAddUndoAction = !bExternalData;
712                 }
713                 else
714                     bAddUndoAction = !xBinding.is();
715             }
716         }
717 
718         if ( bAddUndoAction && ( evt.PropertyName == FM_PROP_STRINGITEMLIST ) )
719         {
720             Reference< XListEntrySink > xSink( evt.Source, UNO_QUERY );
721             if ( xSink.is() && xSink->getListEntrySource().is() )
722                 // #i41029# / 2005-01-31 / frank.schoenheit@sun.com
723                 bAddUndoAction = false;
724         }
725 
726         if ( bAddUndoAction )
727         {
728             aGuard.clear();
729             // TODO: this is a potential race condition: two threads here could in theory
730             // add their undo actions out-of-order
731 
732             ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() );
733             rModel.AddUndo(new FmUndoPropertyAction(rModel, evt));
734         }
735 	}
736 	else
737 	{
738 		// if it's the DataField property we may have to adjust our cache
739 		if (m_pPropertySetCache && evt.PropertyName.equals(FM_PROP_CONTROLSOURCE))
740 		{
741 			Reference< XPropertySet >  xSet(evt.Source, UNO_QUERY);
742 			PropertySetInfoCache* pCache = static_cast<PropertySetInfoCache*>(m_pPropertySetCache);
743 			PropertySetInfo& rSetInfo = (*pCache)[xSet];
744 			rSetInfo.bHasEmptyControlSource = !evt.NewValue.hasValue() || (::comphelper::getString(evt.NewValue).getLength() == 0);
745 		}
746 	}
747 }
748 
749 // XContainerListener
750 //------------------------------------------------------------------------------
751 void SAL_CALL FmXUndoEnvironment::elementInserted(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException)
752 {
753     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::elementInserted" );
754 	::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() );
755     ::osl::MutexGuard aGuard( m_aMutex );
756 
757 	// neues Object zum lauschen
758 	Reference< XInterface >  xIface;
759 	evt.Element >>= xIface;
760 	OSL_ENSURE(xIface.is(), "FmXUndoEnvironment::elementInserted: invalid container notification!");
761 	AddElement(xIface);
762 
763     implSetModified();
764 }
765 
766 //------------------------------------------------------------------------------
767 void FmXUndoEnvironment::implSetModified()
768 {
769     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::implSetModified" );
770 	if ( !IsLocked() && rModel.GetObjectShell() )
771 	{
772 		rModel.GetObjectShell()->SetModified( sal_True );
773 	}
774 }
775 
776 //------------------------------------------------------------------------------
777 void SAL_CALL FmXUndoEnvironment::elementReplaced(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException)
778 {
779     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::elementReplaced" );
780 	::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() );
781     ::osl::MutexGuard aGuard( m_aMutex );
782 
783     Reference< XInterface >  xIface;
784 	evt.ReplacedElement >>= xIface;
785 	OSL_ENSURE(xIface.is(), "FmXUndoEnvironment::elementReplaced: invalid container notification!");
786 	RemoveElement(xIface);
787 
788 	evt.Element >>= xIface;
789 	AddElement(xIface);
790 
791     implSetModified();
792 }
793 
794 //------------------------------------------------------------------------------
795 void SAL_CALL FmXUndoEnvironment::elementRemoved(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException)
796 {
797     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::elementRemoved" );
798 	::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() );
799     ::osl::MutexGuard aGuard( m_aMutex );
800 
801     Reference< XInterface >  xIface( evt.Element, UNO_QUERY );
802 	OSL_ENSURE(xIface.is(), "FmXUndoEnvironment::elementRemoved: invalid container notification!");
803 	RemoveElement(xIface);
804 
805     implSetModified();
806 }
807 
808 //------------------------------------------------------------------------------
809 void SAL_CALL FmXUndoEnvironment::modified( const EventObject& /*aEvent*/ ) throw (RuntimeException)
810 {
811     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::modified" );
812     implSetModified();
813 }
814 
815 //------------------------------------------------------------------------------
816 void FmXUndoEnvironment::AddForms(const Reference< XNameContainer > & rForms)
817 {
818     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::AddForms" );
819 	Lock();
820 	Reference< XInterface >  xInt(rForms, UNO_QUERY);
821 	AddElement(xInt);
822 	UnLock();
823 }
824 
825 //------------------------------------------------------------------------------
826 void FmXUndoEnvironment::RemoveForms(const Reference< XNameContainer > & rForms)
827 {
828     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::RemoveForms" );
829 	Lock();
830 	Reference< XInterface >  xInt(rForms, UNO_QUERY);
831 	RemoveElement(xInt);
832 	UnLock();
833 }
834 
835 //------------------------------------------------------------------------------
836 void FmXUndoEnvironment::TogglePropertyListening(const Reference< XInterface > & Element)
837 {
838     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::TogglePropertyListening" );
839 	// am Container horchen
840 	Reference< XIndexContainer >  xContainer(Element, UNO_QUERY);
841 	if (xContainer.is())
842 	{
843 		sal_uInt32 nCount = xContainer->getCount();
844 		Reference< XInterface >  xIface;
845 		for (sal_uInt32 i = 0; i < nCount; i++)
846 		{
847 			xContainer->getByIndex(i) >>= xIface;
848 			TogglePropertyListening(xIface);
849 		}
850 	}
851 
852 	Reference< XPropertySet >  xSet(Element, UNO_QUERY);
853 	if (xSet.is())
854 	{
855 		if (!bReadOnly)
856 			xSet->addPropertyChangeListener( ::rtl::OUString(), this );
857 		else
858 			xSet->removePropertyChangeListener( ::rtl::OUString(), this );
859 	}
860 }
861 
862 
863 //------------------------------------------------------------------------------
864 void FmXUndoEnvironment::switchListening( const Reference< XIndexContainer >& _rxContainer, bool _bStartListening ) SAL_THROW(())
865 {
866     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::switchListening" );
867     OSL_PRECOND( _rxContainer.is(), "FmXUndoEnvironment::switchListening: invalid container!" );
868     if ( !_rxContainer.is() )
869         return;
870 
871     try
872     {
873 	    // if it's an EventAttacherManager, then we need to listen for
874         // script events
875 	    Reference< XEventAttacherManager > xManager( _rxContainer, UNO_QUERY );
876 	    if ( xManager.is() )
877 	    {
878             if ( _bStartListening )
879             {
880 		        m_pScriptingEnv->registerEventAttacherManager( xManager );
881                 if ( m_vbaListener.is() )
882                     xManager->addScriptListener( m_vbaListener );
883             }
884             else
885             {
886 		        m_pScriptingEnv->revokeEventAttacherManager( xManager );
887                 if ( m_vbaListener.is() )
888                     xManager->removeScriptListener( m_vbaListener );
889             }
890 		}
891 
892         // also handle all children of this element
893 	    sal_uInt32 nCount = _rxContainer->getCount();
894 	    Reference< XInterface > xInterface;
895 	    for ( sal_uInt32 i = 0; i < nCount; ++i )
896 	    {
897 		    _rxContainer->getByIndex( i ) >>= xInterface;
898             if ( _bStartListening )
899 		        AddElement( xInterface );
900             else
901 		        RemoveElement( xInterface );
902 	    }
903 
904         // be notified of any changes in the container elements
905 	    Reference< XContainer > xSimpleContainer( _rxContainer, UNO_QUERY );
906         OSL_ENSURE( xSimpleContainer.is(), "FmXUndoEnvironment::switchListening: how are we expected to be notified of changes in the container?" );
907 	    if ( xSimpleContainer.is() )
908 	    {
909             if ( _bStartListening )
910 		        xSimpleContainer->addContainerListener( this );
911             else
912 		        xSimpleContainer->removeContainerListener( this );
913 	    }
914     }
915     catch( const Exception& )
916     {
917     	OSL_ENSURE( sal_False, "FmXUndoEnvironment::switchListening: caught an exception!" );
918     }
919 }
920 
921 //------------------------------------------------------------------------------
922 void FmXUndoEnvironment::switchListening( const Reference< XInterface >& _rxObject, bool _bStartListening ) SAL_THROW(())
923 {
924     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::switchListening" );
925     OSL_PRECOND( _rxObject.is(), "FmXUndoEnvironment::switchListening: how should I listen at a NULL object?" );
926 
927     try
928     {
929         if ( !bReadOnly )
930         {
931             Reference< XPropertySet > xProps( _rxObject, UNO_QUERY );
932 	        if ( xProps.is() )
933 	        {
934                 if ( _bStartListening )
935     		        xProps->addPropertyChangeListener( ::rtl::OUString(), this );
936                 else
937     	    	    xProps->removePropertyChangeListener( ::rtl::OUString(), this );
938 	        }
939         }
940 
941         Reference< XModifyBroadcaster > xBroadcaster( _rxObject, UNO_QUERY );
942         if ( xBroadcaster.is() )
943         {
944             if ( _bStartListening )
945                 xBroadcaster->addModifyListener( this );
946             else
947                 xBroadcaster->removeModifyListener( this );
948         }
949     }
950     catch( const Exception& )
951     {
952     	OSL_ENSURE( sal_False, "FmXUndoEnvironment::switchListening: caught an exception!" );
953     }
954 }
955 
956 //------------------------------------------------------------------------------
957 void FmXUndoEnvironment::AddElement(const Reference< XInterface >& _rxElement )
958 {
959     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::AddElement" );
960     OSL_ENSURE( !m_bDisposed, "FmXUndoEnvironment::AddElement: not when I'm already disposed!" );
961 
962     // am Container horchen
963 	Reference< XIndexContainer > xContainer( _rxElement, UNO_QUERY );
964 	if ( xContainer.is() )
965         switchListening( xContainer, true );
966 
967     switchListening( _rxElement, true );
968 }
969 
970 //------------------------------------------------------------------------------
971 void FmXUndoEnvironment::RemoveElement(const Reference< XInterface >& _rxElement)
972 {
973     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::RemoveElement" );
974     if ( m_bDisposed )
975         return;
976 
977     switchListening( _rxElement, false );
978 
979 	if (!bReadOnly)
980     {
981 		// reset the ActiveConnection if the form is to be removed. This will (should) free the resources
982 		// associated with this connection
983 		// 86299 - 05/02/2001 - frank.schoenheit@germany.sun.com
984         Reference< XForm > xForm( _rxElement, UNO_QUERY );
985         Reference< XPropertySet > xFormProperties( xForm, UNO_QUERY );
986 		if ( xFormProperties.is() )
987             if ( !::svxform::OStaticDataAccessTools().isEmbeddedInDatabase( _rxElement ) )
988                 // (if there is a connection in the context of the component, setting
989                 // a new connection would be vetoed, anyway)
990                 // #i34196# - 2004-09-21 - fs@openoffice.org
991 			    xFormProperties->setPropertyValue( FM_PROP_ACTIVE_CONNECTION, Any() );
992 	}
993 
994 	Reference< XIndexContainer > xContainer( _rxElement, UNO_QUERY );
995     if ( xContainer.is() )
996         switchListening( xContainer, false );
997 }
998 
999 
1000 //------------------------------------------------------------------------------
1001 FmUndoPropertyAction::FmUndoPropertyAction(FmFormModel& rNewMod, const PropertyChangeEvent& evt)
1002 					 :SdrUndoAction(rNewMod)
1003 					 ,xObj(evt.Source, UNO_QUERY)
1004 					 ,aPropertyName(evt.PropertyName)
1005 					 ,aNewValue(evt.NewValue)
1006 					 ,aOldValue(evt.OldValue)
1007 {
1008     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoPropertyAction::FmUndoPropertyAction" );
1009 	if (rNewMod.GetObjectShell())
1010 		rNewMod.GetObjectShell()->SetModified(sal_True);
1011 	if(static_STR_UNDO_PROPERTY.Len() == 0)
1012 		static_STR_UNDO_PROPERTY = SVX_RES(RID_STR_UNDO_PROPERTY);
1013 }
1014 
1015 
1016 //------------------------------------------------------------------------------
1017 void FmUndoPropertyAction::Undo()
1018 {
1019     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoPropertyAction::Undo" );
1020 	FmXUndoEnvironment& rEnv = ((FmFormModel&)rMod).GetUndoEnv();
1021 
1022 	if (xObj.is() && !rEnv.IsLocked())
1023 	{
1024 		rEnv.Lock();
1025         try
1026         {
1027 		    xObj->setPropertyValue( aPropertyName, aOldValue );
1028         }
1029         catch( const Exception& )
1030         {
1031         	OSL_ENSURE( sal_False, "FmUndoPropertyAction::Undo: caught an exception!" );
1032         }
1033 		rEnv.UnLock();
1034 	}
1035 }
1036 
1037 //------------------------------------------------------------------------------
1038 void FmUndoPropertyAction::Redo()
1039 {
1040     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoPropertyAction::Redo" );
1041 	FmXUndoEnvironment& rEnv = ((FmFormModel&)rMod).GetUndoEnv();
1042 
1043 	if (xObj.is() && !rEnv.IsLocked())
1044 	{
1045 		rEnv.Lock();
1046         try
1047         {
1048 		    xObj->setPropertyValue( aPropertyName, aNewValue );
1049         }
1050         catch( const Exception& )
1051         {
1052         	OSL_ENSURE( sal_False, "FmUndoPropertyAction::Redo: caught an exception!" );
1053         }
1054 		rEnv.UnLock();
1055 	}
1056 }
1057 
1058 //------------------------------------------------------------------------------
1059 String FmUndoPropertyAction::GetComment() const
1060 {
1061     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoPropertyAction::GetComment" );
1062 	String aStr(static_STR_UNDO_PROPERTY);
1063 
1064 	aStr.SearchAndReplace( '#', aPropertyName );
1065 	return aStr;
1066 }
1067 
1068 
1069 DBG_NAME(FmUndoContainerAction);
1070 //------------------------------------------------------------------------------
1071 FmUndoContainerAction::FmUndoContainerAction(FmFormModel& _rMod,
1072 											 Action _eAction,
1073 											 const Reference< XIndexContainer > & xCont,
1074 											 const Reference< XInterface > & xElem,
1075 											 sal_Int32 nIdx)
1076 					  :SdrUndoAction( _rMod )
1077 					  ,m_xContainer( xCont )
1078 					  ,m_nIndex( nIdx )
1079 					  ,m_eAction( _eAction )
1080 {
1081     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoContainerAction::FmUndoContainerAction" );
1082     OSL_ENSURE( nIdx >= 0, "FmUndoContainerAction::FmUndoContainerAction: invalid index!" );
1083         // some old code suggested this could be a valid argument. However, this code was
1084         // buggy, and it *seemed* that nobody used it - so it was removed.
1085 
1086 	DBG_CTOR(FmUndoContainerAction,NULL);
1087 	if ( xCont.is() && xElem.is() )
1088 	{
1089 		// normalize
1090         m_xElement = m_xElement.query( xElem );
1091         if ( m_eAction == Removed )
1092         {
1093 			if (m_nIndex >= 0)
1094 			{
1095 				Reference< XEventAttacherManager >	xManager( xCont, UNO_QUERY );
1096 				if ( xManager.is() )
1097 					m_aEvents = xManager->getScriptEvents(m_nIndex);
1098 			}
1099 			else
1100 				m_xElement = NULL;
1101 
1102             // we now own the element
1103 			m_xOwnElement = m_xElement;
1104         }
1105 	}
1106 }
1107 
1108 //------------------------------------------------------------------------------
1109 FmUndoContainerAction::~FmUndoContainerAction()
1110 {
1111     // if we own the object ....
1112 	DisposeElement( m_xOwnElement );
1113 	DBG_DTOR(FmUndoContainerAction,NULL);
1114 }
1115 
1116 //------------------------------------------------------------------------------
1117 
1118 void FmUndoContainerAction::DisposeElement( const Reference< XInterface > & xElem )
1119 {
1120 	Reference< XComponent > xComp( xElem, UNO_QUERY );
1121 	if ( xComp.is() )
1122 	{
1123         // and the object does not have a parent
1124 		Reference< XChild >  xChild( xElem, UNO_QUERY );
1125 		if ( xChild.is() && !xChild->getParent().is() )
1126             // -> dispose it
1127 			xComp->dispose();
1128 	}
1129 }
1130 
1131 //------------------------------------------------------------------------------
1132 void FmUndoContainerAction::implReInsert( ) SAL_THROW( ( Exception ) )
1133 {
1134     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoContainerAction::implReInsert" );
1135 	if ( m_xContainer->getCount() >= m_nIndex )
1136 	{
1137         // insert the element
1138 		Any aVal;
1139 		if ( m_xContainer->getElementType() == ::getCppuType( static_cast< const Reference< XFormComponent >* >( NULL ) ) )
1140 		{
1141 			aVal <<= Reference< XFormComponent >( m_xElement, UNO_QUERY );
1142 		}
1143 		else
1144 		{
1145 			aVal <<= Reference< XForm >( m_xElement, UNO_QUERY );
1146 		}
1147 		m_xContainer->insertByIndex( m_nIndex, aVal );
1148 
1149         OSL_ENSURE( getElementPos( m_xContainer.get(), m_xElement ) == m_nIndex, "FmUndoContainerAction::implReInsert: insertion did not work!" );
1150 
1151         // register the events
1152         Reference< XEventAttacherManager >	xManager( m_xContainer, UNO_QUERY );
1153 		if ( xManager.is() )
1154 			xManager->registerScriptEvents( m_nIndex, m_aEvents );
1155 
1156         // we don't own the object anymore
1157 		m_xOwnElement = NULL;
1158 	}
1159 }
1160 
1161 //------------------------------------------------------------------------------
1162 void FmUndoContainerAction::implReRemove( ) SAL_THROW( ( Exception ) )
1163 {
1164     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoContainerAction::implReRemove" );
1165     Reference< XInterface > xElement;
1166     if ( ( m_nIndex >= 0 ) && ( m_nIndex < m_xContainer->getCount() ) )
1167     	m_xContainer->getByIndex( m_nIndex ) >>= xElement;
1168 
1169 	if ( xElement != m_xElement )
1170     {
1171         // the indexes in the container changed. Okay, so go the long way and
1172         // manually determine the index
1173         m_nIndex = getElementPos( m_xContainer.get(), m_xElement );
1174         if ( m_nIndex != -1 )
1175             xElement = m_xElement;
1176     }
1177 
1178     OSL_ENSURE( xElement == m_xElement, "FmUndoContainerAction::implReRemove: cannot find the element which I'm responsible for!" );
1179     if ( xElement == m_xElement )
1180 	{
1181 		Reference< XEventAttacherManager >	xManager( m_xContainer, UNO_QUERY );
1182 		if ( xManager.is() )
1183 			m_aEvents = xManager->getScriptEvents( m_nIndex );
1184 		m_xContainer->removeByIndex( m_nIndex );
1185         // from now on, we own this object
1186 		m_xOwnElement = m_xElement;
1187 	}
1188 }
1189 
1190 //------------------------------------------------------------------------------
1191 void FmUndoContainerAction::Undo()
1192 {
1193     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoContainerAction::Undo" );
1194 	FmXUndoEnvironment& rEnv = static_cast< FmFormModel& >( rMod ).GetUndoEnv();
1195 
1196 	if ( m_xContainer.is() && !rEnv.IsLocked() && m_xElement.is() )
1197 	{
1198 		rEnv.Lock();
1199         try
1200         {
1201 		    switch ( m_eAction )
1202 		    {
1203 			case Inserted:
1204                 implReRemove();
1205                 break;
1206 
1207 			case Removed:
1208                 implReInsert();
1209                 break;
1210     	    }
1211         }
1212         catch( const Exception& )
1213         {
1214         	OSL_ENSURE( sal_False, "FmUndoContainerAction::Undo: caught an exception!" );
1215         }
1216 		rEnv.UnLock();
1217 	}
1218 }
1219 
1220 //------------------------------------------------------------------------------
1221 void FmUndoContainerAction::Redo()
1222 {
1223     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoContainerAction::Redo" );
1224 	FmXUndoEnvironment& rEnv = static_cast< FmFormModel& >( rMod ).GetUndoEnv();
1225 	if ( m_xContainer.is() && !rEnv.IsLocked() && m_xElement.is() )
1226 	{
1227 		rEnv.Lock();
1228         try
1229         {
1230 	    	switch ( m_eAction )
1231 		    {
1232 			case Inserted:
1233                 implReInsert();
1234                 break;
1235 
1236 			case Removed:
1237                 implReRemove();
1238 			    break;
1239     		}
1240         }
1241         catch( const Exception& )
1242         {
1243         	OSL_ENSURE( sal_False, "FmUndoContainerAction::Redo: caught an exception!" );
1244         }
1245 		rEnv.UnLock();
1246 	}
1247 }
1248 
1249 //------------------------------------------------------------------------------
1250 FmUndoModelReplaceAction::FmUndoModelReplaceAction(FmFormModel& _rMod, SdrUnoObj* _pObject, const Reference< XControlModel > & _xReplaced)
1251 	:SdrUndoAction(_rMod)
1252 	,m_xReplaced(_xReplaced)
1253 	,m_pObject(_pObject)
1254 {
1255     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoModelReplaceAction::FmUndoModelReplaceAction" );
1256 }
1257 
1258 //------------------------------------------------------------------------------
1259 FmUndoModelReplaceAction::~FmUndoModelReplaceAction()
1260 {
1261 	// dispose our element if nobody else is responsible for
1262 	DisposeElement(m_xReplaced);
1263 }
1264 
1265 //------------------------------------------------------------------------------
1266 
1267 void FmUndoModelReplaceAction::DisposeElement( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel>& xReplaced )
1268 {
1269 	Reference< XComponent >  xComp(xReplaced, UNO_QUERY);
1270 	if (xComp.is())
1271 	{
1272 		Reference< XChild >  xChild(xReplaced, UNO_QUERY);
1273 		if (!xChild.is() || !xChild->getParent().is())
1274 			xComp->dispose();
1275 	}
1276 }
1277 
1278 //------------------------------------------------------------------------------
1279 void FmUndoModelReplaceAction::Undo()
1280 {
1281     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoModelReplaceAction::Undo" );
1282 	try
1283 	{
1284 		Reference< XControlModel > xCurrentModel( m_pObject->GetUnoControlModel() );
1285 
1286 		// replace the model within the parent
1287 		Reference< XChild > xCurrentAsChild( xCurrentModel, UNO_QUERY );
1288 		Reference< XNameContainer > xCurrentsParent;
1289 		if ( xCurrentAsChild.is() )
1290 			xCurrentsParent = xCurrentsParent.query( xCurrentAsChild->getParent() );
1291 		DBG_ASSERT( xCurrentsParent.is(), "FmUndoModelReplaceAction::Undo: invalid current model!" );
1292 
1293 		if ( xCurrentsParent.is() )
1294 		{
1295 			// the form container works with FormComponents
1296 			Reference< XFormComponent > xComponent( m_xReplaced, UNO_QUERY );
1297 			DBG_ASSERT( xComponent.is(), "FmUndoModelReplaceAction::Undo: the new model is no form component !" );
1298 
1299 			Reference< XPropertySet > xCurrentAsSet( xCurrentModel, UNO_QUERY );
1300 			DBG_ASSERT( ::comphelper::hasProperty(FM_PROP_NAME, xCurrentAsSet ), "FmUndoModelReplaceAction::Undo : one of the models is invalid !");
1301 
1302 			::rtl::OUString sName;
1303 			xCurrentAsSet->getPropertyValue( FM_PROP_NAME ) >>= sName;
1304 			xCurrentsParent->replaceByName( sName, makeAny( xComponent ) );
1305 
1306 			m_pObject->SetUnoControlModel(m_xReplaced);
1307 			m_pObject->SetChanged();
1308 
1309 			m_xReplaced = xCurrentModel;
1310 		}
1311 	}
1312 	catch(Exception&)
1313 	{
1314 		DBG_ERROR("FmUndoModelReplaceAction::Undo : could not replace the model !");
1315 	}
1316 }
1317 
1318 //------------------------------------------------------------------------------
1319 String FmUndoModelReplaceAction::GetComment() const
1320 {
1321     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoModelReplaceAction::GetComment" );
1322 	return SVX_RES(RID_STR_UNDO_MODEL_REPLACE);
1323 }
1324