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