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