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

Generated by: LCOV version 1.10