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