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