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