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 SidebarPaneId 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) and the center 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 236 // Register as configuration change listener. 237 if (xCC.is()) 238 { 239 xCC->addConfigurationChangeListener( 240 this, 241 FrameworkHelper::msConfigurationUpdateStartEvent, 242 makeAny(gnConfigurationUpdateStartEvent)); 243 xCC->addConfigurationChangeListener( 244 this, 245 FrameworkHelper::msConfigurationUpdateEndEvent, 246 makeAny(gnConfigurationUpdateEndEvent)); 247 } 248 } 249 catch (RuntimeException&) 250 { 251 Reference<XConfigurationController> xCC (mxConfigurationControllerWeak); 252 if (xCC.is()) 253 xCC->removeResourceFactoryForReference(this); 254 } 255 } 256 } 257 258 259 260 261 //===== XPaneFactory ========================================================== 262 263 Reference<XResource> SAL_CALL BasicPaneFactory::createResource ( 264 const Reference<XResourceId>& rxPaneId) 265 throw (RuntimeException, IllegalArgumentException, WrappedTargetException) 266 { 267 ThrowIfDisposed(); 268 269 Reference<XResource> xPane; 270 271 // Based on the ResourceURL of the given ResourceId look up the 272 // corresponding factory descriptor. 273 PaneContainer::iterator iDescriptor ( 274 ::std::find_if ( 275 mpPaneContainer->begin(), 276 mpPaneContainer->end(), 277 ::boost::bind(&PaneDescriptor::CompareURL, _1, rxPaneId->getResourceURL()))); 278 279 if (iDescriptor != mpPaneContainer->end()) 280 { 281 if (iDescriptor->mxPane.is()) 282 { 283 // The pane has already been created and is still active (has 284 // not yet been released). This should not happen. 285 xPane = iDescriptor->mxPane; 286 } 287 else 288 { 289 // Create a new pane. 290 switch (iDescriptor->mePaneId) 291 { 292 case CenterPaneId: 293 xPane = CreateFrameWindowPane(rxPaneId); 294 break; 295 296 case FullScreenPaneId: 297 xPane = CreateFullScreenPane(mxComponentContext, rxPaneId); 298 break; 299 300 case LeftImpressPaneId: 301 case LeftDrawPaneId: 302 xPane = CreateChildWindowPane( 303 rxPaneId, 304 *iDescriptor); 305 break; 306 } 307 iDescriptor->mxPane = xPane; 308 309 // Listen for the pane being disposed. 310 Reference<lang::XComponent> xComponent (xPane, UNO_QUERY); 311 if (xComponent.is()) 312 xComponent->addEventListener(this); 313 } 314 iDescriptor->mbIsReleased = false; 315 } 316 else 317 { 318 // The requested pane can not be created by any of the factories 319 // managed by the called BasicPaneFactory object. 320 throw lang::IllegalArgumentException( 321 ::rtl::OUString::createFromAscii( 322 "BasicPaneFactory::createPane() called for unknown resource id"), 323 NULL, 324 0); 325 } 326 327 return xPane; 328 } 329 330 331 332 333 334 void SAL_CALL BasicPaneFactory::releaseResource ( 335 const Reference<XResource>& rxPane) 336 throw (RuntimeException) 337 { 338 ThrowIfDisposed(); 339 340 // Based on the given XPane reference look up the corresponding factory 341 // descriptor. 342 PaneContainer::iterator iDescriptor ( 343 ::std::find_if( 344 mpPaneContainer->begin(), 345 mpPaneContainer->end(), 346 ::boost::bind(&PaneDescriptor::ComparePane, _1, rxPane))); 347 348 if (iDescriptor != mpPaneContainer->end()) 349 { 350 // The given pane was created by one of the factories. Child 351 // windows are just hidden and will be reused when requested later. 352 // Other windows are disposed and their reference is reset so that 353 // on the next createPane() call for the same pane type the pane is 354 // created anew. 355 ChildWindowPane* pChildWindowPane = dynamic_cast<ChildWindowPane*>(rxPane.get()); 356 if (pChildWindowPane != NULL) 357 { 358 iDescriptor->mbIsReleased = true; 359 pChildWindowPane->Hide(); 360 } 361 else 362 { 363 iDescriptor->mxPane = NULL; 364 Reference<XComponent> xComponent (rxPane, UNO_QUERY); 365 if (xComponent.is()) 366 { 367 // We are disposing the pane and do not have to be informed of 368 // that. 369 xComponent->removeEventListener(this); 370 xComponent->dispose(); 371 } 372 } 373 } 374 else 375 { 376 // The given XPane reference is either empty or the pane was not 377 // created by any of the factories managed by the called 378 // BasicPaneFactory object. 379 throw lang::IllegalArgumentException( 380 ::rtl::OUString::createFromAscii( 381 "BasicPaneFactory::releasePane() called for pane that that was not created by same factory."), 382 NULL, 383 0); 384 } 385 } 386 387 388 389 390 //===== XConfigurationChangeListener ========================================== 391 392 void SAL_CALL BasicPaneFactory::notifyConfigurationChange ( 393 const ConfigurationChangeEvent& rEvent) 394 throw (RuntimeException) 395 { 396 sal_Int32 nEventType = 0; 397 rEvent.UserData >>= nEventType; 398 switch (nEventType) 399 { 400 case gnConfigurationUpdateStartEvent: 401 // Lock UI updates while we are switching the views except for 402 // the first time after creation. Outherwise this leads to 403 // problems after reload (missing resizes for the side panes). 404 if (mbFirstUpdateSeen) 405 { 406 if (mpUpdateLockManager.get()!=NULL) 407 { 408 // ::osl::Guard< ::osl::Mutex > aGuard (::osl::Mutex::getGlobalMutex()); 409 // mpUpdateLockManager->Lock(); 410 } 411 } 412 else 413 mbFirstUpdateSeen = true; 414 break; 415 416 case gnConfigurationUpdateEndEvent: 417 // Unlock the update lock here when only the visibility of 418 // windows but not the view shells displayed in them have 419 // changed. Otherwise the UpdateLockManager takes care of 420 // unlocking at the right time. 421 if (mpUpdateLockManager.get() != NULL) 422 { 423 ::osl::Guard< ::osl::Mutex > aGuard (::osl::Mutex::getGlobalMutex()); 424 // if (mpUpdateLockManager->IsLocked()) 425 // mpUpdateLockManager->Unlock(); 426 } 427 break; 428 } 429 } 430 431 432 433 434 //===== lang::XEventListener ================================================== 435 436 void SAL_CALL BasicPaneFactory::disposing ( 437 const lang::EventObject& rEventObject) 438 throw (RuntimeException) 439 { 440 if (mxConfigurationControllerWeak == rEventObject.Source) 441 { 442 mxConfigurationControllerWeak = Reference<XConfigurationController>(); 443 } 444 else 445 { 446 // Has one of the panes been disposed? If so, then release the 447 // reference to that pane, but not the pane descriptor. 448 Reference<XResource> xPane (rEventObject.Source, UNO_QUERY); 449 PaneContainer::iterator iDescriptor ( 450 ::std::find_if ( 451 mpPaneContainer->begin(), 452 mpPaneContainer->end(), 453 ::boost::bind(&PaneDescriptor::ComparePane, _1, xPane))); 454 if (iDescriptor != mpPaneContainer->end()) 455 { 456 iDescriptor->mxPane = NULL; 457 } 458 } 459 } 460 461 462 463 464 //----------------------------------------------------------------------------- 465 466 Reference<XResource> BasicPaneFactory::CreateFrameWindowPane ( 467 const Reference<XResourceId>& rxPaneId) 468 { 469 Reference<XResource> xPane; 470 471 if (mpViewShellBase != NULL) 472 { 473 xPane = new FrameWindowPane(rxPaneId, mpViewShellBase->GetViewWindow()); 474 } 475 476 return xPane; 477 } 478 479 480 481 482 Reference<XResource> BasicPaneFactory::CreateFullScreenPane ( 483 const Reference<XComponentContext>& rxComponentContext, 484 const Reference<XResourceId>& rxPaneId) 485 { 486 Reference<XResource> xPane ( 487 new FullScreenPane( 488 rxComponentContext, 489 rxPaneId, 490 mpViewShellBase->GetViewWindow())); 491 492 return xPane; 493 } 494 495 496 497 498 Reference<XResource> BasicPaneFactory::CreateChildWindowPane ( 499 const Reference<XResourceId>& rxPaneId, 500 const PaneDescriptor& rDescriptor) 501 { 502 Reference<XResource> xPane; 503 504 if (mpViewShellBase != NULL) 505 { 506 // Create the corresponding shell and determine the id of the child window. 507 sal_uInt16 nChildWindowId = 0; 508 ::std::auto_ptr<SfxShell> pShell; 509 switch (rDescriptor.mePaneId) 510 { 511 case LeftImpressPaneId: 512 pShell.reset(new LeftImpressPaneShell()); 513 nChildWindowId = ::sd::LeftPaneImpressChildWindow::GetChildWindowId(); 514 break; 515 516 case LeftDrawPaneId: 517 pShell.reset(new LeftDrawPaneShell()); 518 nChildWindowId = ::sd::LeftPaneDrawChildWindow::GetChildWindowId(); 519 break; 520 521 default: 522 break; 523 } 524 525 // With shell and child window id create the ChildWindowPane 526 // wrapper. 527 if (pShell.get() != NULL) 528 { 529 xPane = new ChildWindowPane( 530 rxPaneId, 531 nChildWindowId, 532 *mpViewShellBase, 533 pShell); 534 } 535 } 536 537 return xPane; 538 } 539 540 void BasicPaneFactory::ThrowIfDisposed (void) const 541 throw (lang::DisposedException) 542 { 543 if (rBHelper.bDisposed || rBHelper.bInDispose) 544 { 545 throw lang::DisposedException ( 546 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 547 "BasicPaneFactory object has already been disposed")), 548 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this))); 549 } 550 } 551 552 553 } } // end of namespace sd::framework 554