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