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