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