LCOV - code coverage report
Current view: top level - svx/source/form - fmundo.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 376 540 69.6 %
Date: 2015-06-13 12:38:46 Functions: 43 57 75.4 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.11