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 "precompiled_sd.hxx" 25 26 #include "BasicPaneFactory.hxx" 27 28 #include "ChildWindowPane.hxx" 29 #include "FrameWindowPane.hxx" 30 #include "FullScreenPane.hxx" 31 32 #include "framework/FrameworkHelper.hxx" 33 #include "ViewShellBase.hxx" 34 #include "PaneChildWindows.hxx" 35 #include "DrawController.hxx" 36 #include "DrawDocShell.hxx" 37 #include <com/sun/star/drawing/framework/XControllerManager.hpp> 38 #include <boost/bind.hpp> 39 40 41 using namespace ::com::sun::star; 42 using namespace ::com::sun::star::uno; 43 using namespace ::com::sun::star::lang; 44 using namespace ::com::sun::star::drawing::framework; 45 46 using ::rtl::OUString; 47 using ::sd::framework::FrameworkHelper; 48 49 namespace { 50 enum PaneId { 51 CenterPaneId, 52 FullScreenPaneId, 53 LeftImpressPaneId, 54 LeftDrawPaneId, 55 RightPaneId 56 }; 57 58 static const sal_Int32 gnConfigurationUpdateStartEvent(0); 59 static const sal_Int32 gnConfigurationUpdateEndEvent(1); 60 } 61 62 namespace sd { namespace framework { 63 64 65 /** Store URL, XPane reference and (local) PaneId for every pane factory 66 that is registered at the PaneController. 67 */ 68 class BasicPaneFactory::PaneDescriptor 69 { 70 public: 71 OUString msPaneURL; 72 Reference<XResource> mxPane; 73 PaneId mePaneId; 74 /** The mbReleased flag is set when the pane has been released. Some 75 panes are just hidden and destroyed. When the pane is reused this 76 flag is reset. 77 */ 78 bool mbIsReleased; 79 bool mbIsChildWindow; 80 81 bool CompareURL (const OUString& rsPaneURL) { return msPaneURL.equals(rsPaneURL); } 82 bool ComparePane (const Reference<XResource>& rxPane) { return mxPane==rxPane; } 83 }; 84 85 86 class BasicPaneFactory::PaneContainer 87 : public ::std::vector<PaneDescriptor> 88 { 89 public: 90 PaneContainer (void) {} 91 }; 92 93 94 95 Reference<XInterface> SAL_CALL BasicPaneFactory_createInstance ( 96 const Reference<XComponentContext>& rxContext) 97 { 98 return Reference<XInterface>(static_cast<XWeak*>(new BasicPaneFactory(rxContext))); 99 } 100 101 102 103 104 ::rtl::OUString BasicPaneFactory_getImplementationName (void) throw(RuntimeException) 105 { 106 return ::rtl::OUString( 107 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.Draw.framework.BasicPaneFactory")); 108 } 109 110 111 112 113 Sequence<rtl::OUString> SAL_CALL BasicPaneFactory_getSupportedServiceNames (void) 114 throw (RuntimeException) 115 { 116 static const ::rtl::OUString sServiceName( 117 ::rtl::OUString::createFromAscii("com.sun.star.drawing.framework.BasicPaneFactory")); 118 return Sequence<rtl::OUString>(&sServiceName, 1); 119 } 120 121 122 123 124 //===== PaneFactory =========================================================== 125 126 BasicPaneFactory::BasicPaneFactory ( 127 const Reference<XComponentContext>& rxContext) 128 : BasicPaneFactoryInterfaceBase(m_aMutex), 129 mxComponentContext(rxContext), 130 mxConfigurationControllerWeak(), 131 mpViewShellBase(NULL), 132 mpPaneContainer(new PaneContainer), 133 mbFirstUpdateSeen(false), 134 mpUpdateLockManager() 135 { 136 } 137 138 139 140 141 142 BasicPaneFactory::~BasicPaneFactory (void) 143 { 144 } 145 146 147 148 149 void SAL_CALL BasicPaneFactory::disposing (void) 150 { 151 Reference<XConfigurationController> xCC (mxConfigurationControllerWeak); 152 if (xCC.is()) 153 { 154 xCC->removeResourceFactoryForReference(this); 155 xCC->removeConfigurationChangeListener(this); 156 mxConfigurationControllerWeak = Reference<XConfigurationController>(); 157 } 158 159 for (PaneContainer::const_iterator iDescriptor = mpPaneContainer->begin(); 160 iDescriptor != mpPaneContainer->end(); 161 ++iDescriptor) 162 { 163 if (iDescriptor->mbIsReleased) 164 { 165 Reference<XComponent> xComponent (iDescriptor->mxPane, UNO_QUERY); 166 if (xComponent.is()) 167 { 168 xComponent->removeEventListener(this); 169 xComponent->dispose(); 170 } 171 } 172 } 173 } 174 175 176 177 178 void SAL_CALL BasicPaneFactory::initialize (const Sequence<Any>& aArguments) 179 throw (Exception, RuntimeException) 180 { 181 if (aArguments.getLength() > 0) 182 { 183 try 184 { 185 // Get the XController from the first argument. 186 Reference<frame::XController> xController (aArguments[0], UNO_QUERY_THROW); 187 mxControllerWeak = xController; 188 189 // Tunnel through the controller to obtain access to the ViewShellBase. 190 try 191 { 192 Reference<lang::XUnoTunnel> xTunnel (xController, UNO_QUERY_THROW); 193 DrawController* pController 194 = reinterpret_cast<DrawController*>( 195 (sal::static_int_cast<sal_uIntPtr>( 196 xTunnel->getSomething(DrawController::getUnoTunnelId())))); 197 mpViewShellBase = pController->GetViewShellBase(); 198 mpUpdateLockManager = mpViewShellBase->GetUpdateLockManager(); 199 } 200 catch(RuntimeException&) 201 {} 202 203 Reference<XControllerManager> xCM (xController, UNO_QUERY_THROW); 204 Reference<XConfigurationController> xCC (xCM->getConfigurationController()); 205 mxConfigurationControllerWeak = xCC; 206 207 // Add pane factories for the two left panes (one for Impress and one for 208 // Draw), the center pane, and the right pane. 209 if (xController.is() && xCC.is()) 210 { 211 PaneDescriptor aDescriptor; 212 aDescriptor.msPaneURL = FrameworkHelper::msCenterPaneURL; 213 aDescriptor.mePaneId = CenterPaneId; 214 aDescriptor.mbIsReleased = false; 215 aDescriptor.mbIsChildWindow = false; 216 mpPaneContainer->push_back(aDescriptor); 217 xCC->addResourceFactory(aDescriptor.msPaneURL, this); 218 219 aDescriptor.msPaneURL = FrameworkHelper::msFullScreenPaneURL; 220 aDescriptor.mePaneId = FullScreenPaneId; 221 mpPaneContainer->push_back(aDescriptor); 222 xCC->addResourceFactory(aDescriptor.msPaneURL, this); 223 224 aDescriptor.msPaneURL = FrameworkHelper::msLeftImpressPaneURL; 225 aDescriptor.mePaneId = LeftImpressPaneId; 226 aDescriptor.mbIsChildWindow = true; 227 mpPaneContainer->push_back(aDescriptor); 228 xCC->addResourceFactory(aDescriptor.msPaneURL, this); 229 230 aDescriptor.msPaneURL = FrameworkHelper::msLeftDrawPaneURL; 231 aDescriptor.mePaneId = LeftDrawPaneId; 232 mpPaneContainer->push_back(aDescriptor); 233 xCC->addResourceFactory(aDescriptor.msPaneURL, this); 234 235 aDescriptor.msPaneURL = FrameworkHelper::msRightPaneURL; 236 aDescriptor.mePaneId = RightPaneId; 237 mpPaneContainer->push_back(aDescriptor); 238 xCC->addResourceFactory(aDescriptor.msPaneURL, this); 239 } 240 241 // Register as configuration change listener. 242 if (xCC.is()) 243 { 244 xCC->addConfigurationChangeListener( 245 this, 246 FrameworkHelper::msConfigurationUpdateStartEvent, 247 makeAny(gnConfigurationUpdateStartEvent)); 248 xCC->addConfigurationChangeListener( 249 this, 250 FrameworkHelper::msConfigurationUpdateEndEvent, 251 makeAny(gnConfigurationUpdateEndEvent)); 252 } 253 } 254 catch (RuntimeException&) 255 { 256 Reference<XConfigurationController> xCC (mxConfigurationControllerWeak); 257 if (xCC.is()) 258 xCC->removeResourceFactoryForReference(this); 259 } 260 } 261 } 262 263 264 265 266 //===== XPaneFactory ========================================================== 267 268 Reference<XResource> SAL_CALL BasicPaneFactory::createResource ( 269 const Reference<XResourceId>& rxPaneId) 270 throw (RuntimeException, IllegalArgumentException, WrappedTargetException) 271 { 272 ThrowIfDisposed(); 273 274 Reference<XResource> xPane; 275 276 // Based on the ResourceURL of the given ResourceId look up the 277 // corresponding factory descriptor. 278 PaneContainer::iterator iDescriptor ( 279 ::std::find_if ( 280 mpPaneContainer->begin(), 281 mpPaneContainer->end(), 282 ::boost::bind(&PaneDescriptor::CompareURL, _1, rxPaneId->getResourceURL()))); 283 284 if (iDescriptor != mpPaneContainer->end()) 285 { 286 if (iDescriptor->mxPane.is()) 287 { 288 // The pane has already been created and is still active (has 289 // not yet been released). This should not happen. 290 xPane = iDescriptor->mxPane; 291 } 292 else 293 { 294 // Create a new pane. 295 switch (iDescriptor->mePaneId) 296 { 297 case CenterPaneId: 298 xPane = CreateFrameWindowPane(rxPaneId); 299 break; 300 301 case FullScreenPaneId: 302 xPane = CreateFullScreenPane(mxComponentContext, rxPaneId); 303 break; 304 305 case LeftImpressPaneId: 306 case LeftDrawPaneId: 307 case RightPaneId: 308 xPane = CreateChildWindowPane( 309 rxPaneId, 310 *iDescriptor); 311 break; 312 } 313 iDescriptor->mxPane = xPane; 314 315 // Listen for the pane being disposed. 316 Reference<lang::XComponent> xComponent (xPane, UNO_QUERY); 317 if (xComponent.is()) 318 xComponent->addEventListener(this); 319 } 320 iDescriptor->mbIsReleased = false; 321 } 322 else 323 { 324 // The requested pane can not be created by any of the factories 325 // managed by the called BasicPaneFactory object. 326 throw lang::IllegalArgumentException( 327 ::rtl::OUString::createFromAscii( 328 "BasicPaneFactory::createPane() called for unknown resource id"), 329 NULL, 330 0); 331 } 332 333 return xPane; 334 } 335 336 337 338 339 340 void SAL_CALL BasicPaneFactory::releaseResource ( 341 const Reference<XResource>& rxPane) 342 throw (RuntimeException) 343 { 344 ThrowIfDisposed(); 345 346 // Based on the given XPane reference look up the corresponding factory 347 // descriptor. 348 PaneContainer::iterator iDescriptor ( 349 ::std::find_if( 350 mpPaneContainer->begin(), 351 mpPaneContainer->end(), 352 ::boost::bind(&PaneDescriptor::ComparePane, _1, rxPane))); 353 354 if (iDescriptor != mpPaneContainer->end()) 355 { 356 // The given pane was created by one of the factories. Child 357 // windows are just hidden and will be reused when requested later. 358 // Other windows are disposed and their reference is reset so that 359 // on the next createPane() call for the same pane type the pane is 360 // created anew. 361 ChildWindowPane* pChildWindowPane = dynamic_cast<ChildWindowPane*>(rxPane.get()); 362 if (pChildWindowPane != NULL) 363 { 364 iDescriptor->mbIsReleased = true; 365 pChildWindowPane->Hide(); 366 } 367 else 368 { 369 iDescriptor->mxPane = NULL; 370 Reference<XComponent> xComponent (rxPane, UNO_QUERY); 371 if (xComponent.is()) 372 { 373 // We are disposing the pane and do not have to be informed of 374 // that. 375 xComponent->removeEventListener(this); 376 xComponent->dispose(); 377 } 378 } 379 } 380 else 381 { 382 // The given XPane reference is either empty or the pane was not 383 // created by any of the factories managed by the called 384 // BasicPaneFactory object. 385 throw lang::IllegalArgumentException( 386 ::rtl::OUString::createFromAscii( 387 "BasicPaneFactory::releasePane() called for pane that that was not created by same factory."), 388 NULL, 389 0); 390 } 391 } 392 393 394 395 396 //===== XConfigurationChangeListener ========================================== 397 398 void SAL_CALL BasicPaneFactory::notifyConfigurationChange ( 399 const ConfigurationChangeEvent& rEvent) 400 throw (RuntimeException) 401 { 402 sal_Int32 nEventType = 0; 403 rEvent.UserData >>= nEventType; 404 switch (nEventType) 405 { 406 case gnConfigurationUpdateStartEvent: 407 // Lock UI updates while we are switching the views except for 408 // the first time after creation. Outherwise this leads to 409 // problems after reload (missing resizes for the side panes). 410 if (mbFirstUpdateSeen) 411 { 412 if (mpUpdateLockManager.get()!=NULL) 413 { 414 // ::osl::Guard< ::osl::Mutex > aGuard (::osl::Mutex::getGlobalMutex()); 415 // mpUpdateLockManager->Lock(); 416 } 417 } 418 else 419 mbFirstUpdateSeen = true; 420 break; 421 422 case gnConfigurationUpdateEndEvent: 423 // Unlock the update lock here when only the visibility of 424 // windows but not the view shells displayed in them have 425 // changed. Otherwise the UpdateLockManager takes care of 426 // unlocking at the right time. 427 if (mpUpdateLockManager.get() != NULL) 428 { 429 ::osl::Guard< ::osl::Mutex > aGuard (::osl::Mutex::getGlobalMutex()); 430 // if (mpUpdateLockManager->IsLocked()) 431 // mpUpdateLockManager->Unlock(); 432 } 433 break; 434 } 435 } 436 437 438 439 440 //===== lang::XEventListener ================================================== 441 442 void SAL_CALL BasicPaneFactory::disposing ( 443 const lang::EventObject& rEventObject) 444 throw (RuntimeException) 445 { 446 if (mxConfigurationControllerWeak == rEventObject.Source) 447 { 448 mxConfigurationControllerWeak = Reference<XConfigurationController>(); 449 } 450 else 451 { 452 // Has one of the panes been disposed? If so, then release the 453 // reference to that pane, but not the pane descriptor. 454 Reference<XResource> xPane (rEventObject.Source, UNO_QUERY); 455 PaneContainer::iterator iDescriptor ( 456 ::std::find_if ( 457 mpPaneContainer->begin(), 458 mpPaneContainer->end(), 459 ::boost::bind(&PaneDescriptor::ComparePane, _1, xPane))); 460 if (iDescriptor != mpPaneContainer->end()) 461 { 462 iDescriptor->mxPane = NULL; 463 } 464 } 465 } 466 467 468 469 470 //----------------------------------------------------------------------------- 471 472 Reference<XResource> BasicPaneFactory::CreateFrameWindowPane ( 473 const Reference<XResourceId>& rxPaneId) 474 { 475 Reference<XResource> xPane; 476 477 if (mpViewShellBase != NULL) 478 { 479 xPane = new FrameWindowPane(rxPaneId, mpViewShellBase->GetViewWindow()); 480 } 481 482 return xPane; 483 } 484 485 486 487 488 Reference<XResource> BasicPaneFactory::CreateFullScreenPane ( 489 const Reference<XComponentContext>& rxComponentContext, 490 const Reference<XResourceId>& rxPaneId) 491 { 492 Reference<XResource> xPane ( 493 new FullScreenPane( 494 rxComponentContext, 495 rxPaneId, 496 mpViewShellBase->GetViewWindow())); 497 498 return xPane; 499 } 500 501 502 503 504 Reference<XResource> BasicPaneFactory::CreateChildWindowPane ( 505 const Reference<XResourceId>& rxPaneId, 506 const PaneDescriptor& rDescriptor) 507 { 508 Reference<XResource> xPane; 509 510 if (mpViewShellBase != NULL) 511 { 512 // Create the corresponding shell and determine the id of the child window. 513 sal_uInt16 nChildWindowId = 0; 514 ::std::auto_ptr<SfxShell> pShell; 515 switch (rDescriptor.mePaneId) 516 { 517 case LeftImpressPaneId: 518 pShell.reset(new LeftImpressPaneShell()); 519 nChildWindowId = ::sd::LeftPaneImpressChildWindow::GetChildWindowId(); 520 break; 521 522 case LeftDrawPaneId: 523 pShell.reset(new LeftDrawPaneShell()); 524 nChildWindowId = ::sd::LeftPaneDrawChildWindow::GetChildWindowId(); 525 break; 526 527 case RightPaneId: 528 pShell.reset(new ToolPanelPaneShell()); 529 nChildWindowId = ::sd::ToolPanelChildWindow::GetChildWindowId(); 530 break; 531 532 default: 533 break; 534 } 535 536 // With shell and child window id create the ChildWindowPane 537 // wrapper. 538 if (pShell.get() != NULL) 539 { 540 xPane = new ChildWindowPane( 541 rxPaneId, 542 nChildWindowId, 543 *mpViewShellBase, 544 pShell); 545 } 546 } 547 548 return xPane; 549 } 550 551 void BasicPaneFactory::ThrowIfDisposed (void) const 552 throw (lang::DisposedException) 553 { 554 if (rBHelper.bDisposed || rBHelper.bInDispose) 555 { 556 throw lang::DisposedException ( 557 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 558 "BasicPaneFactory object has already been disposed")), 559 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this))); 560 } 561 } 562 563 564 } } // end of namespace sd::framework 565