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