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 #include "vbaeventshelper.hxx" 25 26 #include <com/sun/star/awt/XTopWindow.hpp> 27 #include <com/sun/star/awt/XTopWindowListener.hpp> 28 #include <com/sun/star/awt/XWindowListener.hpp> 29 #include <com/sun/star/frame/XBorderResizeListener.hpp> 30 #include <com/sun/star/frame/XControllerBorder.hpp> 31 #include <com/sun/star/script/ModuleType.hpp> 32 #include <com/sun/star/script/vba/VBAEventId.hpp> 33 #include <com/sun/star/sheet/XCellRangeAddressable.hpp> 34 #include <com/sun/star/sheet/XSheetCellRangeContainer.hpp> 35 #include <com/sun/star/table/XCellRange.hpp> 36 #include <com/sun/star/util/XChangesListener.hpp> 37 #include <com/sun/star/util/XChangesNotifier.hpp> 38 39 #include <cppuhelper/implbase4.hxx> 40 #include <toolkit/unohlp.hxx> 41 #include <unotools/eventcfg.hxx> 42 #include <vbahelper/helperdecl.hxx> 43 #include <vcl/svapp.hxx> 44 #include <vcl/window.hxx> 45 46 #include "cellsuno.hxx" 47 #include "convuno.hxx" 48 #include "vbaapplication.hxx" 49 50 using namespace ::com::sun::star; 51 using namespace ::com::sun::star::script::vba::VBAEventId; 52 using namespace ::ooo::vba; 53 54 using ::rtl::OUString; 55 56 // ============================================================================ 57 58 namespace { 59 60 /** Extracts a sheet index from the specified element of the passed sequence. 61 The element may be an integer, a Calc range or ranges object, or a VBA Range object. */ 62 SCTAB lclGetTabFromArgs( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) throw (lang::IllegalArgumentException) 63 { 64 VbaEventsHelperBase::checkArgument( rArgs, nIndex ); 65 66 // first try to extract a sheet index 67 sal_Int32 nTab = -1; 68 if( rArgs[ nIndex ] >>= nTab ) 69 { 70 if( (nTab < 0) || (nTab > MAXTAB) ) 71 throw lang::IllegalArgumentException(); 72 return static_cast< SCTAB >( nTab ); 73 } 74 75 // try VBA Range object 76 uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex ); 77 if( xVbaRange.is() ) 78 { 79 uno::Reference< XHelperInterface > xVbaHelper( xVbaRange, uno::UNO_QUERY_THROW ); 80 // TODO: in the future, the parent may be an excel::XChart (chart sheet) -> will there be a common base interface? 81 uno::Reference< excel::XWorksheet > xVbaSheet( xVbaHelper->getParent(), uno::UNO_QUERY_THROW ); 82 // VBA sheet index is 1-based 83 return static_cast< SCTAB >( xVbaSheet->getIndex() - 1 ); 84 } 85 86 // try single UNO range object 87 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable = getXSomethingFromArgs< sheet::XCellRangeAddressable >( rArgs, nIndex ); 88 if( xCellRangeAddressable.is() ) 89 return xCellRangeAddressable->getRangeAddress().Sheet; 90 91 // at last, try UNO range list 92 uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex ); 93 if( xRanges.is() ) 94 { 95 uno::Sequence< table::CellRangeAddress > aRangeAddresses = xRanges->getRangeAddresses(); 96 if( aRangeAddresses.getLength() > 0 ) 97 return aRangeAddresses[ 0 ].Sheet; 98 } 99 100 throw lang::IllegalArgumentException(); 101 } 102 103 /** Returns the AWT container window of the passed controller. */ 104 uno::Reference< awt::XWindow > lclGetWindowForController( const uno::Reference< frame::XController >& rxController ) 105 { 106 if( rxController.is() ) try 107 { 108 uno::Reference< frame::XFrame > xFrame( rxController->getFrame(), uno::UNO_SET_THROW ); 109 return xFrame->getContainerWindow(); 110 } 111 catch( uno::Exception& ) 112 { 113 } 114 return 0; 115 } 116 117 } // namespace 118 119 // ============================================================================ 120 121 typedef ::cppu::WeakImplHelper4< awt::XTopWindowListener, awt::XWindowListener, frame::XBorderResizeListener, util::XChangesListener > ScVbaEventListener_BASE; 122 123 // This class is to process Workbook window related event 124 class ScVbaEventListener : public ScVbaEventListener_BASE 125 { 126 public : 127 ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ); 128 virtual ~ScVbaEventListener(); 129 130 /** Starts listening to the passed document controller. */ 131 void startControllerListening( const uno::Reference< frame::XController >& rxController ); 132 /** Stops listening to the passed document controller. */ 133 void stopControllerListening( const uno::Reference< frame::XController >& rxController ); 134 135 // XTopWindowListener 136 virtual void SAL_CALL windowOpened( const lang::EventObject& rEvent ) throw (uno::RuntimeException); 137 virtual void SAL_CALL windowClosing( const lang::EventObject& rEvent ) throw (uno::RuntimeException); 138 virtual void SAL_CALL windowClosed( const lang::EventObject& rEvent ) throw (uno::RuntimeException); 139 virtual void SAL_CALL windowMinimized( const lang::EventObject& rEvent ) throw (uno::RuntimeException); 140 virtual void SAL_CALL windowNormalized( const lang::EventObject& rEvent ) throw (uno::RuntimeException); 141 virtual void SAL_CALL windowActivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException); 142 virtual void SAL_CALL windowDeactivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException); 143 144 // XWindowListener 145 virtual void SAL_CALL windowResized( const awt::WindowEvent& rEvent ) throw (uno::RuntimeException); 146 virtual void SAL_CALL windowMoved( const awt::WindowEvent& rEvent ) throw (uno::RuntimeException); 147 virtual void SAL_CALL windowShown( const lang::EventObject& rEvent ) throw (uno::RuntimeException); 148 virtual void SAL_CALL windowHidden( const lang::EventObject& rEvent ) throw (uno::RuntimeException); 149 150 // XBorderResizeListener 151 virtual void SAL_CALL borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& aNewSize ) throw (uno::RuntimeException); 152 153 // XChangesListener 154 virtual void SAL_CALL changesOccurred( const util::ChangesEvent& rEvent ) throw (uno::RuntimeException); 155 156 // XEventListener 157 virtual void SAL_CALL disposing( const lang::EventObject& rEvent ) throw (uno::RuntimeException); 158 159 private: 160 /** Starts listening to the document model. */ 161 void startModelListening(); 162 /** Stops listening to the document model. */ 163 void stopModelListening(); 164 165 /** Returns the controller for the passed VCL window. */ 166 uno::Reference< frame::XController > getControllerForWindow( Window* pWindow ) const; 167 168 /** Calls the Workbook_Window[Activate|Deactivate] event handler. */ 169 void processWindowActivateEvent( Window* pWindow, bool bActivate ); 170 /** Posts a Workbook_WindowResize user event. */ 171 void postWindowResizeEvent( Window* pWindow ); 172 /** Callback link for Application::PostUserEvent(). */ 173 DECL_LINK( processWindowResizeEvent, Window* ); 174 175 private: 176 typedef ::std::map< Window*, uno::Reference< frame::XController > > WindowControllerMap; 177 178 ::osl::Mutex maMutex; 179 ScVbaEventsHelper& mrVbaEvents; 180 uno::Reference< frame::XModel > mxModel; 181 ScDocShell* mpDocShell; 182 WindowControllerMap maControllers; /// Maps VCL top windows to their controllers. 183 Window* mpActiveWindow; /// Currently activated window, to prevent multiple (de)activation. 184 bool mbWindowResized; /// True = window resize system event processed. 185 bool mbBorderChanged; /// True = borders changed system event processed. 186 bool mbDisposed; 187 }; 188 189 // ---------------------------------------------------------------------------- 190 191 ScVbaEventListener::ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ) : 192 mrVbaEvents( rVbaEvents ), 193 mxModel( rxModel ), 194 mpDocShell( pDocShell ), 195 mpActiveWindow( 0 ), 196 mbWindowResized( false ), 197 mbBorderChanged( false ), 198 mbDisposed( !rxModel.is() ) 199 { 200 if( !mxModel.is() ) 201 return; 202 203 startModelListening(); 204 try 205 { 206 uno::Reference< frame::XController > xController( mxModel->getCurrentController(), uno::UNO_QUERY_THROW ); 207 startControllerListening( xController ); 208 } 209 catch( uno::Exception& ) 210 { 211 } 212 } 213 214 ScVbaEventListener::~ScVbaEventListener() 215 { 216 } 217 218 void ScVbaEventListener::startControllerListening( const uno::Reference< frame::XController >& rxController ) 219 { 220 ::osl::MutexGuard aGuard( maMutex ); 221 222 uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController ); 223 if( xWindow.is() ) 224 try { xWindow->addWindowListener( this ); } catch( uno::Exception& ) {} 225 226 uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY ); 227 if( xTopWindow.is() ) 228 try { xTopWindow->addTopWindowListener( this ); } catch( uno::Exception& ) {} 229 230 uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY ); 231 if( xControllerBorder.is() ) 232 try { xControllerBorder->addBorderResizeListener( this ); } catch( uno::Exception& ) {} 233 234 if( Window* pWindow = VCLUnoHelper::GetWindow( xWindow ) ) 235 maControllers[ pWindow ] = rxController; 236 } 237 238 void ScVbaEventListener::stopControllerListening( const uno::Reference< frame::XController >& rxController ) 239 { 240 ::osl::MutexGuard aGuard( maMutex ); 241 242 uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController ); 243 if( xWindow.is() ) 244 try { xWindow->removeWindowListener( this ); } catch( uno::Exception& ) {} 245 246 uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY ); 247 if( xTopWindow.is() ) 248 try { xTopWindow->removeTopWindowListener( this ); } catch( uno::Exception& ) {} 249 250 uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY ); 251 if( xControllerBorder.is() ) 252 try { xControllerBorder->removeBorderResizeListener( this ); } catch( uno::Exception& ) {} 253 254 if( Window* pWindow = VCLUnoHelper::GetWindow( xWindow ) ) 255 { 256 maControllers.erase( pWindow ); 257 if( pWindow == mpActiveWindow ) 258 mpActiveWindow = 0; 259 } 260 } 261 262 void SAL_CALL ScVbaEventListener::windowOpened( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException) 263 { 264 } 265 266 void SAL_CALL ScVbaEventListener::windowClosing( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException) 267 { 268 } 269 270 void SAL_CALL ScVbaEventListener::windowClosed( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException) 271 { 272 } 273 274 void SAL_CALL ScVbaEventListener::windowMinimized( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException) 275 { 276 } 277 278 void SAL_CALL ScVbaEventListener::windowNormalized( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException) 279 { 280 } 281 282 void SAL_CALL ScVbaEventListener::windowActivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException) 283 { 284 ::osl::MutexGuard aGuard( maMutex ); 285 286 if( !mbDisposed ) 287 { 288 uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); 289 Window* pWindow = VCLUnoHelper::GetWindow( xWindow ); 290 OSL_TRACE( "ScVbaEventListener::windowActivated - pWindow = 0x%x, mpActiveWindow = 0x%x", pWindow, mpActiveWindow ); 291 // do not fire activation event multiple time for the same window 292 if( pWindow && (pWindow != mpActiveWindow) ) 293 { 294 // if another window is active, fire deactivation event first 295 if( mpActiveWindow ) 296 processWindowActivateEvent( mpActiveWindow, false ); 297 // fire activation event for the new window 298 processWindowActivateEvent( pWindow, true ); 299 mpActiveWindow = pWindow; 300 } 301 } 302 } 303 304 void SAL_CALL ScVbaEventListener::windowDeactivated( const lang::EventObject& rEvent ) throw (uno::RuntimeException) 305 { 306 ::osl::MutexGuard aGuard( maMutex ); 307 308 if( !mbDisposed ) 309 { 310 uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); 311 Window* pWindow = VCLUnoHelper::GetWindow( xWindow ); 312 OSL_TRACE( "ScVbaEventListener::windowDeactivated - pWindow = 0x%x, mpActiveWindow = 0x%x", pWindow, mpActiveWindow ); 313 // do not fire the deactivation event, if the window is not active (prevent multiple deactivation) 314 if( pWindow && (pWindow == mpActiveWindow) ) 315 processWindowActivateEvent( pWindow, false ); 316 // forget pointer to the active window 317 mpActiveWindow = 0; 318 } 319 } 320 321 void SAL_CALL ScVbaEventListener::windowResized( const awt::WindowEvent& rEvent ) throw (uno::RuntimeException) 322 { 323 ::osl::MutexGuard aGuard( maMutex ); 324 325 mbWindowResized = true; 326 if( !mbDisposed && mbBorderChanged ) 327 { 328 uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); 329 postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) ); 330 } 331 } 332 333 void SAL_CALL ScVbaEventListener::windowMoved( const awt::WindowEvent& /*rEvent*/ ) throw (uno::RuntimeException) 334 { 335 } 336 337 void SAL_CALL ScVbaEventListener::windowShown( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException) 338 { 339 } 340 341 void SAL_CALL ScVbaEventListener::windowHidden( const lang::EventObject& /*rEvent*/ ) throw (uno::RuntimeException) 342 { 343 } 344 345 void SAL_CALL ScVbaEventListener::borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& /*aNewSize*/ ) throw (uno::RuntimeException) 346 { 347 ::osl::MutexGuard aGuard( maMutex ); 348 349 mbBorderChanged = true; 350 if( !mbDisposed && mbWindowResized ) 351 { 352 uno::Reference< frame::XController > xController( rSource, uno::UNO_QUERY ); 353 uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( xController ); 354 postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) ); 355 } 356 } 357 358 void SAL_CALL ScVbaEventListener::changesOccurred( const util::ChangesEvent& rEvent ) throw (uno::RuntimeException) 359 { 360 ::osl::MutexGuard aGuard( maMutex ); 361 362 sal_Int32 nCount = rEvent.Changes.getLength(); 363 if( mbDisposed || !mpDocShell || (nCount == 0) ) 364 return; 365 366 util::ElementChange aChange = rEvent.Changes[ 0 ]; 367 OUString sOperation; 368 aChange.Accessor >>= sOperation; 369 if( !sOperation.equalsIgnoreAsciiCaseAscii("cell-change") ) 370 return; 371 372 if( nCount == 1 ) 373 { 374 uno::Reference< table::XCellRange > xRangeObj; 375 aChange.ReplacedElement >>= xRangeObj; 376 if( xRangeObj.is() ) 377 { 378 uno::Sequence< uno::Any > aArgs( 1 ); 379 aArgs[0] <<= xRangeObj; 380 mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs ); 381 } 382 return; 383 } 384 385 ScRangeList aRangeList; 386 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) 387 { 388 aChange = rEvent.Changes[ nIndex ]; 389 aChange.Accessor >>= sOperation; 390 uno::Reference< table::XCellRange > xRangeObj; 391 aChange.ReplacedElement >>= xRangeObj; 392 if( xRangeObj.is() && sOperation.equalsIgnoreAsciiCaseAscii("cell-change") ) 393 { 394 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( xRangeObj, uno::UNO_QUERY ); 395 if( xCellRangeAddressable.is() ) 396 { 397 ScRange aRange; 398 ScUnoConversion::FillScRange( aRange, xCellRangeAddressable->getRangeAddress() ); 399 aRangeList.Append( aRange ); 400 } 401 } 402 } 403 404 if( aRangeList.Count() > 0 ) 405 { 406 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( mpDocShell, aRangeList ) ); 407 uno::Sequence< uno::Any > aArgs(1); 408 aArgs[0] <<= xRanges; 409 mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs ); 410 } 411 } 412 413 void SAL_CALL ScVbaEventListener::disposing( const lang::EventObject& rEvent ) throw (uno::RuntimeException) 414 { 415 ::osl::MutexGuard aGuard( maMutex ); 416 417 uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY ); 418 if( xModel.is() ) 419 { 420 OSL_ENSURE( xModel.get() == mxModel.get(), "ScVbaEventListener::disposing - disposing from unknown model" ); 421 stopModelListening(); 422 mbDisposed = true; 423 return; 424 } 425 426 uno::Reference< frame::XController > xController( rEvent.Source, uno::UNO_QUERY ); 427 if( xController.is() ) 428 { 429 stopControllerListening( xController ); 430 return; 431 } 432 } 433 434 // private -------------------------------------------------------------------- 435 436 void ScVbaEventListener::startModelListening() 437 { 438 try 439 { 440 uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW ); 441 xChangesNotifier->addChangesListener( this ); 442 } 443 catch( uno::Exception& ) 444 { 445 } 446 } 447 448 void ScVbaEventListener::stopModelListening() 449 { 450 try 451 { 452 uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW ); 453 xChangesNotifier->removeChangesListener( this ); 454 } 455 catch( uno::Exception& ) 456 { 457 } 458 } 459 460 uno::Reference< frame::XController > ScVbaEventListener::getControllerForWindow( Window* pWindow ) const 461 { 462 WindowControllerMap::const_iterator aIt = maControllers.find( pWindow ); 463 return (aIt == maControllers.end()) ? uno::Reference< frame::XController >() : aIt->second; 464 } 465 466 void ScVbaEventListener::processWindowActivateEvent( Window* pWindow, bool bActivate ) 467 { 468 uno::Reference< frame::XController > xController = getControllerForWindow( pWindow ); 469 if( xController.is() ) 470 { 471 uno::Sequence< uno::Any > aArgs( 1 ); 472 aArgs[ 0 ] <<= xController; 473 mrVbaEvents.processVbaEventNoThrow( bActivate ? WORKBOOK_WINDOWACTIVATE : WORKBOOK_WINDOWDEACTIVATE, aArgs ); 474 } 475 } 476 477 void ScVbaEventListener::postWindowResizeEvent( Window* pWindow ) 478 { 479 // check that the passed window is still alive (it must be registered in maControllers) 480 if( pWindow && (maControllers.count( pWindow ) > 0) ) 481 { 482 mbWindowResized = mbBorderChanged = false; 483 acquire(); // ensure we don't get deleted before the timer fires 484 Application::PostUserEvent( LINK( this, ScVbaEventListener, processWindowResizeEvent ), pWindow ); 485 } 486 } 487 488 IMPL_LINK( ScVbaEventListener, processWindowResizeEvent, Window*, EMPTYARG pWindow ) 489 { 490 ::osl::MutexGuard aGuard( maMutex ); 491 492 /* Check that the passed window is still alive (it must be registered in 493 maControllers). While closing a document, postWindowResizeEvent() may 494 be called on the last window which posts a user event via 495 Application::PostUserEvent to call this event handler. VCL will trigger 496 the handler some time later. Sometimes, the window gets deleted before. 497 This is handled via the disposing() function which removes the window 498 pointer from the member maControllers. Thus, checking whether 499 maControllers contains pWindow ensures that the window is still alive. */ 500 if( !mbDisposed && pWindow && (maControllers.count( pWindow ) > 0) ) 501 { 502 // do not fire event unless all mouse buttons have been released 503 Window::PointerState aPointerState = pWindow->GetPointerState(); 504 if( (aPointerState.mnState & (MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)) == 0 ) 505 { 506 uno::Reference< frame::XController > xController = getControllerForWindow( pWindow ); 507 if( xController.is() ) 508 { 509 uno::Sequence< uno::Any > aArgs( 1 ); 510 aArgs[ 0 ] <<= xController; 511 // #163419# do not throw exceptions into application core 512 mrVbaEvents.processVbaEventNoThrow( WORKBOOK_WINDOWRESIZE, aArgs ); 513 } 514 } 515 } 516 release(); 517 return 0; 518 } 519 520 // ============================================================================ 521 522 ScVbaEventsHelper::ScVbaEventsHelper( const uno::Sequence< uno::Any >& rArgs, const uno::Reference< uno::XComponentContext >& xContext ) : 523 VbaEventsHelperBase( rArgs, xContext ), 524 mbOpened( false ) 525 { 526 mpDocShell = dynamic_cast< ScDocShell* >( mpShell ); // mpShell from base class 527 mpDoc = mpDocShell ? mpDocShell->GetDocument() : 0; 528 529 if( !mxModel.is() || !mpDocShell || !mpDoc ) 530 return; 531 532 #define REGISTER_EVENT( eventid, moduletype, classname, eventname, cancelindex, worksheet ) \ 533 registerEventHandler( eventid, moduletype, classname "_" eventname, cancelindex, uno::Any( worksheet ) ) 534 #define REGISTER_AUTO_EVENT( eventid, eventname ) \ 535 REGISTER_EVENT( AUTO_##eventid, script::ModuleType::NORMAL, "Auto", eventname, -1, false ) 536 #define REGISTER_WORKBOOK_EVENT( eventid, eventname, cancelindex ) \ 537 REGISTER_EVENT( WORKBOOK_##eventid, script::ModuleType::DOCUMENT, "Workbook", eventname, cancelindex, false ) 538 #define REGISTER_WORKSHEET_EVENT( eventid, eventname, cancelindex ) \ 539 REGISTER_EVENT( WORKSHEET_##eventid, script::ModuleType::DOCUMENT, "Worksheet", eventname, cancelindex, true ); \ 540 REGISTER_EVENT( (USERDEFINED_START + WORKSHEET_##eventid), script::ModuleType::DOCUMENT, "Workbook", "Sheet" eventname, (((cancelindex) >= 0) ? ((cancelindex) + 1) : -1), false ) 541 542 // global 543 REGISTER_AUTO_EVENT( OPEN, "Open" ); 544 REGISTER_AUTO_EVENT( CLOSE, "Close" ); 545 546 // Workbook 547 REGISTER_WORKBOOK_EVENT( ACTIVATE, "Activate", -1 ); 548 REGISTER_WORKBOOK_EVENT( DEACTIVATE, "Deactivate", -1 ); 549 REGISTER_WORKBOOK_EVENT( OPEN, "Open", -1 ); 550 REGISTER_WORKBOOK_EVENT( BEFORECLOSE, "BeforeClose", 0 ); 551 REGISTER_WORKBOOK_EVENT( BEFOREPRINT, "BeforePrint", 0 ); 552 REGISTER_WORKBOOK_EVENT( BEFORESAVE, "BeforeSave", 1 ); 553 REGISTER_WORKBOOK_EVENT( AFTERSAVE, "AfterSave", -1 ); 554 REGISTER_WORKBOOK_EVENT( NEWSHEET, "NewSheet", -1 ); 555 REGISTER_WORKBOOK_EVENT( WINDOWACTIVATE, "WindowActivate", -1 ); 556 REGISTER_WORKBOOK_EVENT( WINDOWDEACTIVATE, "WindowDeactivate", -1 ); 557 REGISTER_WORKBOOK_EVENT( WINDOWRESIZE, "WindowResize", -1 ); 558 559 // Worksheet events. All events have a corresponding workbook event. 560 REGISTER_WORKSHEET_EVENT( ACTIVATE, "Activate", -1 ); 561 REGISTER_WORKSHEET_EVENT( DEACTIVATE, "Deactivate", -1 ); 562 REGISTER_WORKSHEET_EVENT( BEFOREDOUBLECLICK, "BeforeDoubleClick", 1 ); 563 REGISTER_WORKSHEET_EVENT( BEFORERIGHTCLICK, "BeforeRightClick", 1 ); 564 REGISTER_WORKSHEET_EVENT( CALCULATE, "Calculate", -1 ); 565 REGISTER_WORKSHEET_EVENT( CHANGE, "Change", -1 ); 566 REGISTER_WORKSHEET_EVENT( SELECTIONCHANGE, "SelectionChange", -1 ); 567 REGISTER_WORKSHEET_EVENT( FOLLOWHYPERLINK, "FollowHyperlink", -1 ); 568 569 #undef REGISTER_WORKSHEET_EVENT 570 #undef REGISTER_WORKBOOK_EVENT 571 #undef REGISTER_AUTO_EVENT 572 #undef REGISTER_EVENT 573 } 574 575 ScVbaEventsHelper::~ScVbaEventsHelper() 576 { 577 } 578 579 void SAL_CALL ScVbaEventsHelper::notifyEvent( const css::document::EventObject& rEvent ) throw (css::uno::RuntimeException) 580 { 581 static const uno::Sequence< uno::Any > saEmptyArgs; 582 if( (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_OPENDOC )) || 583 (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_CREATEDOC )) ) // CREATEDOC triggered e.g. during VBA Workbooks.Add 584 { 585 processVbaEventNoThrow( WORKBOOK_OPEN, saEmptyArgs ); 586 } 587 else if( rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_ACTIVATEDOC ) ) 588 { 589 processVbaEventNoThrow( WORKBOOK_ACTIVATE, saEmptyArgs ); 590 } 591 else if( rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_DEACTIVATEDOC ) ) 592 { 593 processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs ); 594 } 595 else if( (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVEDOCDONE )) || 596 (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVEASDOCDONE )) || 597 (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVETODOCDONE )) ) 598 { 599 uno::Sequence< uno::Any > aArgs( 1 ); 600 aArgs[ 0 ] <<= true; 601 processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs ); 602 } 603 else if( (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVEDOCFAILED )) || 604 (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVEASDOCFAILED )) || 605 (rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_SAVETODOCFAILED )) ) 606 { 607 uno::Sequence< uno::Any > aArgs( 1 ); 608 aArgs[ 0 ] <<= false; 609 processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs ); 610 } 611 else if( rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_CLOSEDOC ) ) 612 { 613 /* Trigger the WORKBOOK_WINDOWDEACTIVATE and WORKBOOK_DEACTIVATE 614 events and stop listening to the model (done in base class). */ 615 uno::Reference< frame::XController > xController( mxModel->getCurrentController() ); 616 if( xController.is() ) 617 { 618 uno::Sequence< uno::Any > aArgs( 1 ); 619 aArgs[ 0 ] <<= xController; 620 processVbaEventNoThrow( WORKBOOK_WINDOWDEACTIVATE, aArgs ); 621 } 622 processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs ); 623 } 624 else if( rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_VIEWCREATED ) ) 625 { 626 uno::Reference< frame::XController > xController( mxModel->getCurrentController() ); 627 if( mxListener.get() && xController.is() ) 628 mxListener->startControllerListening( xController ); 629 } 630 VbaEventsHelperBase::notifyEvent( rEvent ); 631 } 632 633 // protected ------------------------------------------------------------------ 634 635 bool ScVbaEventsHelper::implPrepareEvent( EventQueue& rEventQueue, 636 const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs ) throw (uno::RuntimeException) 637 { 638 // document and document shell are needed during event processing 639 if( !mpShell || !mpDoc ) 640 throw uno::RuntimeException(); 641 642 /* For document events: check if events are enabled via the 643 Application.EnableEvents symbol (this is an Excel-only attribute). 644 Check this again for every event, as the event handler may change the 645 state of the EnableEvents symbol. Global events such as AUTO_OPEN and 646 AUTO_CLOSE are always enabled. */ 647 bool bExecuteEvent = (rInfo.mnModuleType != script::ModuleType::DOCUMENT) || ScVbaApplication::getDocumentEventsEnabled(); 648 649 // framework and Calc fire a few events before 'OnLoad', ignore them 650 if( bExecuteEvent ) 651 bExecuteEvent = (rInfo.mnEventId == WORKBOOK_OPEN) ? !mbOpened : mbOpened; 652 653 // special handling for some events 654 if( bExecuteEvent ) switch( rInfo.mnEventId ) 655 { 656 case WORKBOOK_OPEN: 657 { 658 // execute delayed Activate event too (see above) 659 rEventQueue.push_back( WORKBOOK_ACTIVATE ); 660 uno::Sequence< uno::Any > aArgs( 1 ); 661 aArgs[ 0 ] <<= mxModel->getCurrentController(); 662 rEventQueue.push_back( EventQueueEntry( WORKBOOK_WINDOWACTIVATE, aArgs ) ); 663 rEventQueue.push_back( AUTO_OPEN ); 664 // remember initial selection 665 maOldSelection <<= mxModel->getCurrentSelection(); 666 } 667 break; 668 case WORKSHEET_SELECTIONCHANGE: 669 // if selection is not changed, then do not fire the event 670 bExecuteEvent = isSelectionChanged( rArgs, 0 ); 671 break; 672 } 673 674 if( bExecuteEvent ) 675 { 676 // add workbook event associated to a sheet event 677 bool bSheetEvent = false; 678 if( (rInfo.maUserData >>= bSheetEvent) && bSheetEvent ) 679 rEventQueue.push_back( EventQueueEntry( rInfo.mnEventId + USERDEFINED_START, rArgs ) ); 680 } 681 682 return bExecuteEvent; 683 } 684 685 uno::Sequence< uno::Any > ScVbaEventsHelper::implBuildArgumentList( const EventHandlerInfo& rInfo, 686 const uno::Sequence< uno::Any >& rArgs ) throw (lang::IllegalArgumentException) 687 { 688 // fill arguments for workbook events associated to sheet events according to sheet events, sheet will be added below 689 bool bSheetEventAsBookEvent = rInfo.mnEventId > USERDEFINED_START; 690 sal_Int32 nEventId = bSheetEventAsBookEvent ? (rInfo.mnEventId - USERDEFINED_START) : rInfo.mnEventId; 691 692 uno::Sequence< uno::Any > aVbaArgs; 693 switch( nEventId ) 694 { 695 // *** Workbook *** 696 697 // no arguments 698 case WORKBOOK_ACTIVATE: 699 case WORKBOOK_DEACTIVATE: 700 case WORKBOOK_OPEN: 701 break; 702 // 1 arg: cancel 703 case WORKBOOK_BEFORECLOSE: 704 case WORKBOOK_BEFOREPRINT: 705 aVbaArgs.realloc( 1 ); 706 // current cancel state will be inserted by caller 707 break; 708 // 2 args: saveAs, cancel 709 case WORKBOOK_BEFORESAVE: 710 aVbaArgs.realloc( 2 ); 711 checkArgumentType< bool >( rArgs, 0 ); 712 aVbaArgs[ 0 ] = rArgs[ 0 ]; 713 // current cancel state will be inserted by caller 714 break; 715 // 1 arg: success 716 case WORKBOOK_AFTERSAVE: 717 aVbaArgs.realloc( 1 ); 718 checkArgumentType< bool >( rArgs, 0 ); 719 aVbaArgs[ 0 ] = rArgs[ 0 ]; 720 break; 721 // 1 arg: window 722 case WORKBOOK_WINDOWACTIVATE: 723 case WORKBOOK_WINDOWDEACTIVATE: 724 case WORKBOOK_WINDOWRESIZE: 725 aVbaArgs.realloc( 1 ); 726 aVbaArgs[ 0 ] = createWindow( rArgs, 0 ); 727 break; 728 // 1 arg: worksheet 729 case WORKBOOK_NEWSHEET: 730 aVbaArgs.realloc( 1 ); 731 aVbaArgs[ 0 ] = createWorksheet( rArgs, 0 ); 732 break; 733 734 // *** Worksheet *** 735 736 // no arguments 737 case WORKSHEET_ACTIVATE: 738 case WORKSHEET_CALCULATE: 739 case WORKSHEET_DEACTIVATE: 740 break; 741 // 1 arg: range 742 case WORKSHEET_CHANGE: 743 case WORKSHEET_SELECTIONCHANGE: 744 aVbaArgs.realloc( 1 ); 745 aVbaArgs[ 0 ] = createRange( rArgs, 0 ); 746 break; 747 // 2 args: range, cancel 748 case WORKSHEET_BEFOREDOUBLECLICK: 749 case WORKSHEET_BEFORERIGHTCLICK: 750 aVbaArgs.realloc( 2 ); 751 aVbaArgs[ 0 ] = createRange( rArgs, 0 ); 752 // current cancel state will be inserted by caller 753 break; 754 // 1 arg: hyperlink 755 case WORKSHEET_FOLLOWHYPERLINK: 756 aVbaArgs.realloc( 1 ); 757 aVbaArgs[ 0 ] = createHyperlink( rArgs, 0 ); 758 break; 759 } 760 761 /* For workbook events associated to sheet events, the workbook event gets 762 the same arguments but with a Worksheet object in front of them. */ 763 if( bSheetEventAsBookEvent ) 764 { 765 sal_Int32 nLength = aVbaArgs.getLength(); 766 uno::Sequence< uno::Any > aVbaArgs2( nLength + 1 ); 767 aVbaArgs2[ 0 ] = createWorksheet( rArgs, 0 ); 768 for( sal_Int32 nIndex = 0; nIndex < nLength; ++nIndex ) 769 aVbaArgs2[ nIndex + 1 ] = aVbaArgs[ nIndex ]; 770 aVbaArgs = aVbaArgs2; 771 } 772 773 return aVbaArgs; 774 } 775 776 void ScVbaEventsHelper::implPostProcessEvent( EventQueue& rEventQueue, 777 const EventHandlerInfo& rInfo, bool bCancel ) throw (uno::RuntimeException) 778 { 779 switch( rInfo.mnEventId ) 780 { 781 case WORKBOOK_OPEN: 782 mbOpened = true; 783 // register the listeners 784 if( !mxListener.is() ) 785 mxListener = new ScVbaEventListener( *this, mxModel, mpDocShell ); 786 break; 787 case WORKBOOK_BEFORECLOSE: 788 /* Execute Auto_Close only if not cancelled by event handler, but 789 before UI asks user whether to cancel closing the document. */ 790 if( !bCancel ) 791 rEventQueue.push_back( AUTO_CLOSE ); 792 break; 793 } 794 } 795 796 OUString ScVbaEventsHelper::implGetDocumentModuleName( const EventHandlerInfo& rInfo, 797 const uno::Sequence< uno::Any >& rArgs ) const throw (lang::IllegalArgumentException) 798 { 799 bool bSheetEvent = false; 800 rInfo.maUserData >>= bSheetEvent; 801 SCTAB nTab = bSheetEvent ? lclGetTabFromArgs( rArgs, 0 ) : -1; 802 if( bSheetEvent && (nTab < 0) ) 803 throw lang::IllegalArgumentException(); 804 805 String aCodeName; 806 if( bSheetEvent ) 807 mpDoc->GetCodeName( nTab, aCodeName ); 808 else 809 aCodeName = mpDoc->GetCodeName(); 810 return aCodeName; 811 } 812 813 // private -------------------------------------------------------------------- 814 815 namespace { 816 817 /** Compares the passed range lists representing sheet selections. Ignores 818 selections that refer to different sheets (returns false in this case). */ 819 bool lclSelectionChanged( const ScRangeList& rLeft, const ScRangeList& rRight ) 820 { 821 // one of the range lists empty? -> return false, if both lists empty 822 bool bLeftEmpty = rLeft.Count() == 0; 823 bool bRightEmpty = rRight.Count() == 0; 824 if( bLeftEmpty || bRightEmpty ) 825 return !(bLeftEmpty && bRightEmpty); 826 827 // check sheet indexes of the range lists (assuming that all ranges in a list are on the same sheet) 828 if( rLeft.GetObject( 0 )->aStart.Tab() != rRight.GetObject( 0 )->aStart.Tab() ) 829 return false; 830 831 // compare all ranges 832 return rLeft != rRight; 833 } 834 835 } // namespace 836 837 bool ScVbaEventsHelper::isSelectionChanged( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) throw (lang::IllegalArgumentException, uno::RuntimeException) 838 { 839 uno::Reference< uno::XInterface > xOldSelection( maOldSelection, uno::UNO_QUERY ); 840 uno::Reference< uno::XInterface > xNewSelection = getXSomethingFromArgs< uno::XInterface >( rArgs, nIndex, false ); 841 ScCellRangesBase* pOldCellRanges = ScCellRangesBase::getImplementation( xOldSelection ); 842 ScCellRangesBase* pNewCellRanges = ScCellRangesBase::getImplementation( xNewSelection ); 843 bool bChanged = !pOldCellRanges || !pNewCellRanges || lclSelectionChanged( pOldCellRanges->GetRangeList(), pNewCellRanges->GetRangeList() ); 844 maOldSelection <<= xNewSelection; 845 return bChanged; 846 } 847 848 uno::Any ScVbaEventsHelper::createWorksheet( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const 849 throw (lang::IllegalArgumentException, uno::RuntimeException) 850 { 851 // extract sheet index, will throw, if parameter is invalid 852 SCTAB nTab = lclGetTabFromArgs( rArgs, nIndex ); 853 return uno::Any( excel::getUnoSheetModuleObj( mxModel, nTab ) ); 854 } 855 856 uno::Any ScVbaEventsHelper::createRange( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const 857 throw (lang::IllegalArgumentException, uno::RuntimeException) 858 { 859 // it is possible to pass an existing VBA Range object 860 uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex ); 861 if( !xVbaRange.is() ) 862 { 863 uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex ); 864 uno::Reference< table::XCellRange > xRange = getXSomethingFromArgs< table::XCellRange >( rArgs, nIndex ); 865 if ( !xRanges.is() && !xRange.is() ) 866 throw lang::IllegalArgumentException(); 867 868 uno::Sequence< uno::Any > aArgs( 2 ); 869 if ( xRanges.is() ) 870 { 871 aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRanges ); 872 aArgs[ 1 ] <<= xRanges; 873 } 874 else 875 { 876 aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRange ); 877 aArgs[ 1 ] <<= xRange; 878 } 879 xVbaRange.set( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Range", aArgs ), uno::UNO_QUERY_THROW ); 880 } 881 return uno::Any( xVbaRange ); 882 } 883 884 uno::Any ScVbaEventsHelper::createHyperlink( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const 885 throw (lang::IllegalArgumentException, uno::RuntimeException) 886 { 887 uno::Reference< table::XCell > xCell = getXSomethingFromArgs< table::XCell >( rArgs, nIndex, false ); 888 uno::Sequence< uno::Any > aArgs( 2 ); 889 aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xCell ); 890 aArgs[ 1 ] <<= xCell; 891 uno::Reference< uno::XInterface > xHyperlink( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Hyperlink", aArgs ), uno::UNO_SET_THROW ); 892 return uno::Any( xHyperlink ); 893 } 894 895 uno::Any ScVbaEventsHelper::createWindow( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const 896 throw (lang::IllegalArgumentException, uno::RuntimeException) 897 { 898 uno::Sequence< uno::Any > aArgs( 3 ); 899 aArgs[ 0 ] <<= getVBADocument( mxModel ); 900 aArgs[ 1 ] <<= mxModel; 901 aArgs[ 2 ] <<= getXSomethingFromArgs< frame::XController >( rArgs, nIndex, false ); 902 uno::Reference< uno::XInterface > xWindow( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Window", aArgs ), uno::UNO_SET_THROW ); 903 return uno::Any( xWindow ); 904 } 905 906 // ============================================================================ 907 908 namespace vbaeventshelper 909 { 910 namespace sdecl = comphelper::service_decl; 911 sdecl::class_<ScVbaEventsHelper, sdecl::with_args<true> > serviceImpl; 912 extern sdecl::ServiceDecl const serviceDecl( 913 serviceImpl, 914 "ScVbaEventsHelper", 915 "com.sun.star.script.vba.VBASpreadsheetEventProcessor" ); 916 } 917 918 // ============================================================================ 919