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_sd.hxx" 26 27 #include "FormShellManager.hxx" 28 29 #include "EventMultiplexer.hxx" 30 #include "ViewShell.hxx" 31 #include "ViewShellBase.hxx" 32 #include "ViewShellManager.hxx" 33 #include "Window.hxx" 34 #include <svx/fmshell.hxx> 35 36 namespace sd { 37 38 namespace { 39 40 /** This factory is responsible for creating and deleting the FmFormShell. 41 */ 42 class FormShellManagerFactory 43 : public ::sd::ShellFactory<SfxShell> 44 { 45 public: 46 FormShellManagerFactory (ViewShell& rViewShell, FormShellManager& rManager); 47 virtual FmFormShell* CreateShell (ShellId nId, ::Window* pParentWindow, FrameView* pFrameView); 48 virtual void ReleaseShell (SfxShell* pShell); 49 50 private: 51 ::sd::ViewShell& mrViewShell; 52 FormShellManager& mrFormShellManager; 53 }; 54 55 } // end of anonymous namespace 56 57 58 FormShellManager::FormShellManager (ViewShellBase& rBase) 59 : mrBase(rBase), 60 mpFormShell(NULL), 61 mbFormShellAboveViewShell(false), 62 mpSubShellFactory(), 63 mbIsMainViewChangePending(false), 64 mpMainViewShellWindow(NULL) 65 { 66 // Register at the EventMultiplexer to be informed about changes in the 67 // center pane. 68 Link aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler)); 69 mrBase.GetEventMultiplexer()->AddEventListener( 70 aLink, 71 sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_REMOVED 72 | sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED 73 | sd::tools::EventMultiplexerEvent::EID_CONFIGURATION_UPDATED); 74 75 RegisterAtCenterPane(); 76 } 77 78 79 80 81 FormShellManager::~FormShellManager (void) 82 { 83 SetFormShell(NULL); 84 UnregisterAtCenterPane(); 85 86 // Unregister from the EventMultiplexer. 87 Link aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler)); 88 mrBase.GetEventMultiplexer()->RemoveEventListener(aLink); 89 90 if (mpSubShellFactory.get() != NULL) 91 { 92 ViewShell* pShell = mrBase.GetMainViewShell().get(); 93 if (pShell != NULL) 94 mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell,mpSubShellFactory); 95 } 96 } 97 98 99 100 101 void FormShellManager::SetFormShell (FmFormShell* pFormShell) 102 { 103 if (mpFormShell != pFormShell) 104 { 105 // Disconnect from the old form shell. 106 if (mpFormShell != NULL) 107 { 108 mpFormShell->SetControlActivationHandler(Link()); 109 EndListening(*mpFormShell); 110 mpFormShell->SetView(NULL); 111 } 112 113 mpFormShell = pFormShell; 114 115 // Connect to the new form shell. 116 if (mpFormShell != NULL) 117 { 118 mpFormShell->SetControlActivationHandler( 119 LINK( 120 this, 121 FormShellManager, 122 FormControlActivated)); 123 StartListening(*mpFormShell); 124 125 ViewShell* pMainViewShell = mrBase.GetMainViewShell().get(); 126 if (pMainViewShell != NULL) 127 { 128 // Prevent setting the view twice at the FmFormShell. 129 FmFormView* pFormView = static_cast<FmFormView*>(pMainViewShell->GetView()); 130 if (mpFormShell->GetFormView() != pFormView) 131 mpFormShell->SetView(pFormView); 132 } 133 } 134 135 // Tell the ViewShellManager where on the stack to place the form shell. 136 mrBase.GetViewShellManager()->SetFormShell( 137 mrBase.GetMainViewShell().get(), 138 mpFormShell, 139 mbFormShellAboveViewShell); 140 } 141 } 142 143 144 145 146 FmFormShell* FormShellManager::GetFormShell (void) 147 { 148 return mpFormShell; 149 } 150 151 152 153 154 void FormShellManager::RegisterAtCenterPane (void) 155 { 156 do 157 { 158 ViewShell* pShell = mrBase.GetMainViewShell().get(); 159 if (pShell == NULL) 160 break; 161 162 // No form shell for the slide sorter. Besides that it is not 163 // necessary, using both together results in crashes. 164 if (pShell->GetShellType() == ViewShell::ST_SLIDE_SORTER) 165 break; 166 167 mpMainViewShellWindow = pShell->GetActiveWindow(); 168 if (mpMainViewShellWindow == NULL) 169 break; 170 171 // Register at the window to get informed when to move the form 172 // shell to the bottom of the shell stack. 173 mpMainViewShellWindow->AddEventListener( 174 LINK( 175 this, 176 FormShellManager, 177 WindowEventHandler)); 178 179 // Create a shell factory and with it activate the form shell. 180 OSL_ASSERT(mpSubShellFactory.get()==NULL); 181 mpSubShellFactory.reset(new FormShellManagerFactory(*pShell, *this)); 182 mrBase.GetViewShellManager()->AddSubShellFactory(pShell,mpSubShellFactory); 183 mrBase.GetViewShellManager()->ActivateSubShell(*pShell, RID_FORMLAYER_TOOLBOX); 184 } 185 while (false); 186 } 187 188 189 190 191 void FormShellManager::UnregisterAtCenterPane (void) 192 { 193 do 194 { 195 if (mpMainViewShellWindow != NULL) 196 { 197 // Unregister from the window. 198 mpMainViewShellWindow->RemoveEventListener( 199 LINK( 200 this, 201 FormShellManager, 202 WindowEventHandler)); 203 mpMainViewShellWindow = NULL; 204 } 205 206 // Unregister form at the form shell. 207 SetFormShell(NULL); 208 209 // Deactivate the form shell and destroy the shell factory. 210 ViewShell* pShell = mrBase.GetMainViewShell().get(); 211 if (pShell != NULL) 212 { 213 mrBase.GetViewShellManager()->DeactivateSubShell(*pShell, RID_FORMLAYER_TOOLBOX); 214 mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell, mpSubShellFactory); 215 } 216 217 mpSubShellFactory.reset(); 218 } 219 while (false); 220 } 221 222 223 224 225 IMPL_LINK(FormShellManager, FormControlActivated, FmFormShell*, EMPTYARG) 226 { 227 // The form shell has been actived. To give it priority in reacting to 228 // slot calls the form shell is moved to the top of the object bar shell 229 // stack. 230 ViewShell* pShell = mrBase.GetMainViewShell().get(); 231 if (pShell!=NULL && !mbFormShellAboveViewShell) 232 { 233 mbFormShellAboveViewShell = true; 234 235 ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager()); 236 mrBase.GetViewShellManager()->SetFormShell(pShell,mpFormShell,mbFormShellAboveViewShell); 237 } 238 239 return 0; 240 } 241 242 243 244 245 IMPL_LINK(FormShellManager, ConfigurationUpdateHandler, sd::tools::EventMultiplexerEvent*, pEvent) 246 { 247 switch (pEvent->meEventId) 248 { 249 case sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_REMOVED: 250 UnregisterAtCenterPane(); 251 break; 252 253 case sd::tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED: 254 mbIsMainViewChangePending = true; 255 break; 256 257 case sd::tools::EventMultiplexerEvent::EID_CONFIGURATION_UPDATED: 258 if (mbIsMainViewChangePending) 259 { 260 mbIsMainViewChangePending = false; 261 RegisterAtCenterPane(); 262 } 263 break; 264 265 default: 266 break; 267 } 268 269 return 0; 270 } 271 272 273 274 275 IMPL_LINK(FormShellManager, WindowEventHandler, VclWindowEvent*, pEvent) 276 { 277 if (pEvent != NULL) 278 { 279 switch (pEvent->GetId()) 280 { 281 case VCLEVENT_WINDOW_GETFOCUS: 282 { 283 // The window of the center pane got the focus. Therefore 284 // the form shell is moved to the bottom of the object bar 285 // stack. 286 ViewShell* pShell = mrBase.GetMainViewShell().get(); 287 if (pShell!=NULL && mbFormShellAboveViewShell) 288 { 289 mbFormShellAboveViewShell = false; 290 ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager()); 291 mrBase.GetViewShellManager()->SetFormShell( 292 pShell, 293 mpFormShell, 294 mbFormShellAboveViewShell); 295 } 296 } 297 break; 298 299 case VCLEVENT_WINDOW_LOSEFOCUS: 300 // We follow the sloppy focus policy. Losing the focus is 301 // ignored. We wait for the focus to be placed either in 302 // the window or the form shell. The later, however, is 303 // notified over the FormControlActivated handler, not this 304 // one. 305 break; 306 307 case VCLEVENT_OBJECT_DYING: 308 mpMainViewShellWindow = NULL; 309 break; 310 } 311 } 312 313 return 0; 314 } 315 316 317 318 319 void FormShellManager::Notify(SfxBroadcaster&, const SfxHint& rHint) 320 { 321 const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint); 322 if (pSimpleHint!=NULL && pSimpleHint->GetId()==SFX_HINT_DYING) 323 { 324 // If all goes well this listener is called after the 325 // FormShellManager was notified about the dying form shell by the 326 // FormShellManagerFactory. 327 OSL_ASSERT(mpFormShell==NULL); 328 if (mpFormShell != NULL) 329 { 330 mpFormShell = NULL; 331 mrBase.GetViewShellManager()->SetFormShell( 332 mrBase.GetMainViewShell().get(), 333 NULL, 334 false); 335 } 336 } 337 } 338 339 340 341 342 343 //===== FormShellManagerFactory =============================================== 344 345 namespace { 346 347 FormShellManagerFactory::FormShellManagerFactory ( 348 ::sd::ViewShell& rViewShell, 349 FormShellManager& rManager) 350 : mrViewShell(rViewShell), 351 mrFormShellManager(rManager) 352 { 353 } 354 355 356 357 358 FmFormShell* FormShellManagerFactory::CreateShell ( 359 ::sd::ShellId nId, 360 ::Window*, 361 ::sd::FrameView*) 362 { 363 FmFormShell* pShell = NULL; 364 365 ::sd::View* pView = mrViewShell.GetView(); 366 if (nId == RID_FORMLAYER_TOOLBOX) 367 { 368 pShell = new FmFormShell(&mrViewShell.GetViewShellBase(), pView); 369 mrFormShellManager.SetFormShell(pShell); 370 } 371 372 return pShell; 373 } 374 375 376 377 378 void FormShellManagerFactory::ReleaseShell (SfxShell* pShell) 379 { 380 if (pShell != NULL) 381 { 382 mrFormShellManager.SetFormShell(NULL); 383 delete pShell; 384 } 385 } 386 387 } // end of anonymous namespace 388 389 } // end of namespace sd 390