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