xref: /trunk/main/sd/source/ui/view/ViewTabBar.cxx (revision 79aad27f)
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 "ViewTabBar.hxx"
28 
29 #define USE_TAB_CONTROL
30 
31 #include "ViewShell.hxx"
32 #include "ViewShellBase.hxx"
33 #include "DrawViewShell.hxx"
34 #include "FrameView.hxx"
35 #include "EventMultiplexer.hxx"
36 #include "framework/FrameworkHelper.hxx"
37 #include "framework/Pane.hxx"
38 #include "DrawController.hxx"
39 
40 #include "sdresid.hxx"
41 #include "strings.hrc"
42 #include "helpids.h"
43 #include "Client.hxx"
44 #include <vcl/svapp.hxx>
45 #include <vcl/tabpage.hxx>
46 #include <vos/mutex.hxx>
47 #include <sfx2/viewfrm.hxx>
48 #include <com/sun/star/drawing/framework/ResourceId.hpp>
49 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
50 #include <com/sun/star/lang/XUnoTunnel.hpp>
51 #include <com/sun/star/lang/DisposedException.hpp>
52 #include <comphelper/processfactory.hxx>
53 #include <tools/diagnose_ex.h>
54 
55 using namespace ::com::sun::star;
56 using namespace ::com::sun::star::uno;
57 using namespace ::com::sun::star::drawing::framework;
58 using ::sd::framework::FrameworkHelper;
59 using ::sd::tools::EventMultiplexerEvent;
60 using ::rtl::OUString;
61 
62 namespace sd {
63 
64 namespace {
IsEqual(const TabBarButton & rButton1,const TabBarButton & rButton2)65 bool IsEqual (const TabBarButton& rButton1, const TabBarButton& rButton2)
66 {
67     return (
68         (rButton1.ResourceId.is()
69             && rButton2.ResourceId.is()
70             && rButton1.ResourceId->compareTo(rButton2.ResourceId)==0)
71         || rButton1.ButtonLabel == rButton2.ButtonLabel);
72 }
73 
74 class TabBarControl : public ::TabControl
75 {
76 public:
77     TabBarControl (
78         ::Window* pParentWindow,
79         const ::rtl::Reference<ViewTabBar>& rpViewTabBar);
80     virtual void Paint (const Rectangle& rRect);
81     virtual void ActivatePage (void);
82 private:
83     ::rtl::Reference<ViewTabBar> mpViewTabBar;
84 };
85 
86 } // end of anonymous namespace
87 
88 
89 
90 
91 
92 class ViewTabPage : public TabPage
93 {
94 public:
ViewTabPage(Window * pParent)95     ViewTabPage (Window* pParent) : TabPage(pParent) {}
Resize(void)96     virtual void Resize (void)
97     { SetPosSizePixel(Point(0,0),GetParent()->GetOutputSizePixel()); }
98 };
99 
100 
101 
102 
103 //===== ViewTabBar ============================================================
104 
ViewTabBar(const Reference<XResourceId> & rxViewTabBarId,const Reference<frame::XController> & rxController)105 ViewTabBar::ViewTabBar (
106     const Reference<XResourceId>& rxViewTabBarId,
107     const Reference<frame::XController>& rxController)
108     : ViewTabBarInterfaceBase(maMutex),
109       mpTabControl(new TabBarControl(GetAnchorWindow(rxViewTabBarId,rxController), this)),
110       mxController(rxController),
111       maTabBarButtons(),
112       mpTabPage(NULL),
113       mxViewTabBarId(rxViewTabBarId),
114       mpViewShellBase(NULL)
115 {
116     // Set one new tab page for all tab entries.  We need it only to
117     // determine the height of the tab bar.
118     mpTabPage.reset(new TabPage (mpTabControl.get()));
119     mpTabPage->Hide();
120 
121     // add some space before the tabitems
122     mpTabControl->SetItemsOffset(Point(5, 3));
123 
124     // Tunnel through the controller and use the ViewShellBase to obtain the
125     // view frame.
126     try
127     {
128         Reference<lang::XUnoTunnel> xTunnel (mxController, UNO_QUERY_THROW);
129         DrawController* pController = reinterpret_cast<DrawController*>(
130             xTunnel->getSomething(DrawController::getUnoTunnelId()));
131         mpViewShellBase = pController->GetViewShellBase();
132     }
133     catch(RuntimeException&)
134     {}
135 
136     // Register as listener at XConfigurationController.
137     Reference<XControllerManager> xControllerManager (mxController, UNO_QUERY);
138     if (xControllerManager.is())
139     {
140         mxConfigurationController = xControllerManager->getConfigurationController();
141         if (mxConfigurationController.is())
142         {
143             mxConfigurationController->addConfigurationChangeListener(
144                 this,
145                     FrameworkHelper::msResourceActivationEvent,
146                 Any());
147         }
148     }
149 
150     mpTabControl->Show();
151 
152     if (mpViewShellBase != NULL
153         && rxViewTabBarId->isBoundToURL(
154             FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
155     {
156         mpViewShellBase->SetViewTabBar(this);
157     }
158 }
159 
160 
161 
162 
~ViewTabBar(void)163 ViewTabBar::~ViewTabBar (void)
164 {
165 }
166 
167 
168 
169 
disposing(void)170 void ViewTabBar::disposing (void)
171 {
172     if (mpViewShellBase != NULL
173         && mxViewTabBarId->isBoundToURL(
174             FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
175     {
176         mpViewShellBase->SetViewTabBar(NULL);
177     }
178 
179     if (mxConfigurationController.is())
180     {
181         // Unregister listener from XConfigurationController.
182         try
183         {
184             mxConfigurationController->removeConfigurationChangeListener(this);
185         }
186         catch (lang::DisposedException e)
187         {
188             // Receiving a disposed exception is the normal case.  Is there
189             // a way to avoid it?
190         }
191         mxConfigurationController = NULL;
192     }
193 
194     {
195         const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
196         // Set all references to the one tab page to NULL and delete the page.
197         for (sal_uInt16 nIndex=0; nIndex<mpTabControl->GetPageCount(); ++nIndex)
198             mpTabControl->SetTabPage(nIndex, NULL);
199         mpTabPage.reset();
200         mpTabControl.reset();
201     }
202 
203     mxController = NULL;
204 }
205 
206 
207 
208 
GetTabControl(void) const209 ::boost::shared_ptr< ::TabControl> ViewTabBar::GetTabControl (void) const
210 {
211     return mpTabControl;
212 }
213 
214 
215 
216 
GetAnchorWindow(const Reference<XResourceId> & rxViewTabBarId,const Reference<frame::XController> & rxController)217 ::Window* ViewTabBar::GetAnchorWindow(
218     const Reference<XResourceId>& rxViewTabBarId,
219     const Reference<frame::XController>& rxController)
220 {
221     ::Window* pWindow = NULL;
222     ViewShellBase* pBase = NULL;
223 
224     // Tunnel through the controller and use the ViewShellBase to obtain the
225     // view frame.
226     try
227     {
228         Reference<lang::XUnoTunnel> xTunnel (rxController, UNO_QUERY_THROW);
229         DrawController* pController = reinterpret_cast<DrawController*>(
230             xTunnel->getSomething(DrawController::getUnoTunnelId()));
231         pBase = pController->GetViewShellBase();
232     }
233     catch(RuntimeException&)
234     {}
235 
236     // The ViewTabBar supports at the moment only the center pane.
237     if (rxViewTabBarId.is()
238         && rxViewTabBarId->isBoundToURL(
239             FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
240     {
241         if (pBase != NULL && pBase->GetViewFrame() != NULL)
242             pWindow = &pBase->GetViewFrame()->GetWindow();
243     }
244 
245     // The rest is (at the moment) just for the emergency case.
246     if (pWindow == NULL)
247     {
248         Reference<XPane> xPane;
249         try
250         {
251             Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY_THROW);
252             Reference<XConfigurationController> xCC (
253                 xControllerManager->getConfigurationController());
254             if (xCC.is())
255                 xPane = Reference<XPane>(xCC->getResource(rxViewTabBarId->getAnchor()), UNO_QUERY);
256         }
257         catch (RuntimeException&)
258         {}
259 
260         // Tunnel through the XWindow to the VCL side.
261         try
262         {
263             Reference<lang::XUnoTunnel> xTunnel (xPane, UNO_QUERY_THROW);
264             framework::Pane* pPane = reinterpret_cast<framework::Pane*>(
265                 xTunnel->getSomething(framework::Pane::getUnoTunnelId()));
266             if (pPane != NULL)
267                 pWindow = pPane->GetWindow()->GetParent();
268         }
269         catch (RuntimeException&)
270         {}
271     }
272 
273     return pWindow;
274 }
275 
276 
277 
278 
279 //----- XConfigurationChangeListener ------------------------------------------
280 
notifyConfigurationChange(const ConfigurationChangeEvent & rEvent)281 void SAL_CALL  ViewTabBar::notifyConfigurationChange (
282     const ConfigurationChangeEvent& rEvent)
283     throw (RuntimeException)
284 {
285     if (rEvent.Type.equals(FrameworkHelper::msResourceActivationEvent)
286         && rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix)
287         && rEvent.ResourceId->isBoundTo(mxViewTabBarId->getAnchor(), AnchorBindingMode_DIRECT))
288     {
289         UpdateActiveButton();
290     }
291 }
292 
293 
294 
295 
296 //----- XEventListener --------------------------------------------------------
297 
disposing(const lang::EventObject & rEvent)298 void SAL_CALL ViewTabBar::disposing(
299     const lang::EventObject& rEvent)
300     throw (RuntimeException)
301 {
302     if (rEvent.Source == mxConfigurationController)
303     {
304         mxConfigurationController = NULL;
305         mxController = NULL;
306     }
307 }
308 
309 
310 
311 
312 //----- XTabBar ---------------------------------------------------------------
313 
addTabBarButtonAfter(const TabBarButton & rButton,const TabBarButton & rAnchor)314 void SAL_CALL ViewTabBar::addTabBarButtonAfter (
315     const TabBarButton& rButton,
316     const TabBarButton& rAnchor)
317     throw (::com::sun::star::uno::RuntimeException)
318 {
319     const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
320     AddTabBarButton(rButton, rAnchor);
321 }
322 
323 
324 
325 
appendTabBarButton(const TabBarButton & rButton)326 void SAL_CALL ViewTabBar::appendTabBarButton (const TabBarButton& rButton)
327     throw (::com::sun::star::uno::RuntimeException)
328 {
329     const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
330     AddTabBarButton(rButton);
331 }
332 
333 
334 
removeTabBarButton(const TabBarButton & rButton)335 void SAL_CALL ViewTabBar::removeTabBarButton (const TabBarButton& rButton)
336     throw (::com::sun::star::uno::RuntimeException)
337 {
338     const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
339     RemoveTabBarButton(rButton);
340 }
341 
342 
343 
344 
hasTabBarButton(const TabBarButton & rButton)345 sal_Bool SAL_CALL ViewTabBar::hasTabBarButton (const TabBarButton& rButton)
346     throw (::com::sun::star::uno::RuntimeException)
347 {
348     const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
349     return HasTabBarButton(rButton);
350 }
351 
352 
353 
354 
getTabBarButtons(void)355 Sequence<TabBarButton> SAL_CALL ViewTabBar::getTabBarButtons (void)
356     throw (::com::sun::star::uno::RuntimeException)
357 {
358     const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
359     return GetTabBarButtons();
360 }
361 
362 
363 
364 
365 //----- XResource -------------------------------------------------------------
366 
getResourceId(void)367 Reference<XResourceId> SAL_CALL ViewTabBar::getResourceId (void)
368     throw (RuntimeException)
369 {
370     return mxViewTabBarId;
371 }
372 
373 
374 
375 
isAnchorOnly(void)376 sal_Bool SAL_CALL ViewTabBar::isAnchorOnly (void)
377     throw (RuntimeException)
378 {
379     return false;
380 }
381 
382 
383 
384 
385 //----- XUnoTunnel ------------------------------------------------------------
386 
getUnoTunnelId(void)387 const Sequence<sal_Int8>& ViewTabBar::getUnoTunnelId (void)
388 {
389 	static Sequence<sal_Int8>* pSequence = NULL;
390 	if (pSequence == NULL)
391 	{
392         const ::vos::OGuard aSolarGuard (Application::GetSolarMutex());
393 		if (pSequence == NULL)
394 		{
395 			static ::com::sun::star::uno::Sequence<sal_Int8> aSequence (16);
396 			rtl_createUuid((sal_uInt8*)aSequence.getArray(), 0, sal_True);
397 			pSequence = &aSequence;
398 		}
399 	}
400 	return *pSequence;
401 }
402 
403 
404 
405 
getSomething(const Sequence<sal_Int8> & rId)406 sal_Int64 SAL_CALL ViewTabBar::getSomething (const Sequence<sal_Int8>& rId)
407     throw (RuntimeException)
408 {
409     sal_Int64 nResult = 0;
410 
411     if (rId.getLength() == 16
412         && rtl_compareMemory(getUnoTunnelId().getConstArray(), rId.getConstArray(), 16) == 0)
413 	{
414 		nResult = reinterpret_cast<sal_Int64>(this);
415 	}
416 
417     return nResult;
418 }
419 
420 
421 
422 
423 //-----------------------------------------------------------------------------
424 
ActivatePage(void)425 bool ViewTabBar::ActivatePage (void)
426 {
427     try
428     {
429         Reference<XControllerManager> xControllerManager (mxController,UNO_QUERY_THROW);
430         Reference<XConfigurationController> xConfigurationController (
431             xControllerManager->getConfigurationController());
432         if ( ! xConfigurationController.is())
433             throw RuntimeException();
434         Reference<XView> xView;
435         try
436         {
437             xView = Reference<XView>(xConfigurationController->getResource(
438                 ResourceId::create(
439                     ::comphelper::getProcessComponentContext(),
440                     FrameworkHelper::msCenterPaneURL)),
441                 UNO_QUERY);
442         }
443         catch (DeploymentException)
444         {
445         }
446 
447         Client* pIPClient = NULL;
448         if (mpViewShellBase != NULL)
449             pIPClient = dynamic_cast<Client*>(mpViewShellBase->GetIPClient());
450         if (pIPClient==NULL || ! pIPClient->IsObjectInPlaceActive())
451         {
452             sal_uInt16 nIndex (mpTabControl->GetCurPageId() - 1);
453             if (nIndex < maTabBarButtons.size())
454             {
455                 xConfigurationController->requestResourceActivation(
456                     maTabBarButtons[nIndex].ResourceId,
457                     ResourceActivationMode_REPLACE);
458             }
459 
460             return true;
461         }
462         else
463         {
464             // When we run into this else branch then we have an active OLE
465             // object.  We ignore the request to switch views.  Additionally
466             // we put the active tab back to the one for the current view.
467             UpdateActiveButton();
468         }
469     }
470     catch (RuntimeException&)
471     {
472         DBG_UNHANDLED_EXCEPTION();
473     }
474 
475     return false;
476 }
477 
478 
479 
480 
GetHeight(void)481 int ViewTabBar::GetHeight (void)
482 {
483     int nHeight (0);
484 
485     if (!maTabBarButtons.empty())
486     {
487         TabPage* pActivePage (mpTabControl->GetTabPage(
488             mpTabControl->GetCurPageId()));
489         if (pActivePage!=NULL && mpTabControl->IsReallyVisible())
490             nHeight = pActivePage->GetPosPixel().Y();
491 
492         if (nHeight <= 0)
493             // Using a default when the real height can not be determined.
494             // To get correct height this method should be called when the
495             // control is visible.
496             nHeight = 21;
497     }
498 
499     return nHeight;
500 }
501 
502 
503 
504 
AddTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton,const::com::sun::star::drawing::framework::TabBarButton & rAnchor)505 void ViewTabBar::AddTabBarButton (
506     const ::com::sun::star::drawing::framework::TabBarButton& rButton,
507     const ::com::sun::star::drawing::framework::TabBarButton& rAnchor)
508 {
509     sal_uInt32 nIndex;
510 
511     if ( ! rAnchor.ResourceId.is()
512         || (rAnchor.ResourceId->getResourceURL().getLength() == 0
513             && rAnchor.ButtonLabel.getLength() == 0))
514     {
515         nIndex = 0;
516     }
517     else
518     {
519         for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
520         {
521             if (IsEqual(maTabBarButtons[nIndex], rAnchor))
522             {
523                 ++nIndex;
524                 break;
525             }
526         }
527     }
528 
529     AddTabBarButton(rButton,nIndex);
530 }
531 
532 
533 
534 
AddTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton)535 void ViewTabBar::AddTabBarButton (
536     const ::com::sun::star::drawing::framework::TabBarButton& rButton)
537 {
538     AddTabBarButton(rButton, maTabBarButtons.size());
539 }
540 
541 
542 
543 
AddTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton,sal_Int32 nPosition)544 void ViewTabBar::AddTabBarButton (
545     const ::com::sun::star::drawing::framework::TabBarButton& rButton,
546     sal_Int32 nPosition)
547 {
548     if (nPosition>=0
549         && nPosition<=mpTabControl->GetPageCount())
550     {
551         sal_uInt16 nIndex ((sal_uInt16)nPosition);
552 
553         // Insert the button into our local array.
554         maTabBarButtons.insert(maTabBarButtons.begin()+nIndex, rButton);
555         UpdateTabBarButtons();
556         UpdateActiveButton();
557     }
558 }
559 
560 
561 
562 
RemoveTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton)563 void ViewTabBar::RemoveTabBarButton (
564     const ::com::sun::star::drawing::framework::TabBarButton& rButton)
565 {
566     sal_uInt16 nIndex;
567     for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
568     {
569         if (IsEqual(maTabBarButtons[nIndex], rButton))
570         {
571             maTabBarButtons.erase(maTabBarButtons.begin()+nIndex);
572             UpdateTabBarButtons();
573             UpdateActiveButton();
574             break;
575         }
576     }
577 }
578 
579 
580 
581 
HasTabBarButton(const::com::sun::star::drawing::framework::TabBarButton & rButton)582 bool ViewTabBar::HasTabBarButton (
583     const ::com::sun::star::drawing::framework::TabBarButton& rButton)
584 {
585     bool bResult (false);
586 
587     for (sal_uInt32 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
588     {
589         if (IsEqual(maTabBarButtons[nIndex], rButton))
590         {
591             bResult = true;
592             break;
593         }
594     }
595 
596     return bResult;
597 }
598 
599 
600 
601 
602 ::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton>
GetTabBarButtons(void)603     ViewTabBar::GetTabBarButtons (void)
604 {
605     sal_uInt32 nCount (maTabBarButtons.size());
606     ::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton>
607           aList (nCount);
608 
609     for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex)
610         aList[nIndex] = maTabBarButtons[nIndex];
611 
612     return aList;
613 }
614 
615 
616 
617 
UpdateActiveButton(void)618 void ViewTabBar::UpdateActiveButton (void)
619 {
620     Reference<XView> xView;
621     if (mpViewShellBase != NULL)
622         xView = FrameworkHelper::Instance(*mpViewShellBase)->GetView(
623             mxViewTabBarId->getAnchor());
624     if (xView.is())
625     {
626         Reference<XResourceId> xViewId (xView->getResourceId());
627         for (sal_uInt16 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex)
628         {
629             if (maTabBarButtons[nIndex].ResourceId->compareTo(xViewId) == 0)
630             {
631                 mpTabControl->SetCurPageId(nIndex+1);
632                 mpTabControl->::TabControl::ActivatePage();
633                 break;
634             }
635         }
636     }
637 }
638 
639 
640 
641 
UpdateTabBarButtons(void)642 void ViewTabBar::UpdateTabBarButtons (void)
643 {
644     TabBarButtonList::const_iterator iTab;
645     sal_uInt16 nPageCount (mpTabControl->GetPageCount());
646     sal_uInt16 nIndex;
647     for (iTab=maTabBarButtons.begin(),nIndex=1; iTab!=maTabBarButtons.end(); ++iTab,++nIndex)
648     {
649         // Create a new tab when there are not enough.
650         if (nPageCount < nIndex)
651             mpTabControl->InsertPage(nIndex, iTab->ButtonLabel);
652 
653         // Update the tab.
654         mpTabControl->SetPageText(nIndex, iTab->ButtonLabel);
655         mpTabControl->SetHelpText(nIndex, iTab->HelpText);
656         mpTabControl->SetTabPage(nIndex, mpTabPage.get());
657     }
658 
659     // Delete tabs that are no longer used.
660     for (; nIndex<=nPageCount; ++nIndex)
661         mpTabControl->RemovePage(nIndex);
662 
663     mpTabPage->Hide();
664 }
665 
666 
667 
668 
669 //===== TabBarControl =========================================================
670 
TabBarControl(::Window * pParentWindow,const::rtl::Reference<ViewTabBar> & rpViewTabBar)671 TabBarControl::TabBarControl (
672     ::Window* pParentWindow,
673     const ::rtl::Reference<ViewTabBar>& rpViewTabBar)
674     : ::TabControl(pParentWindow),
675       mpViewTabBar(rpViewTabBar)
676 {
677 }
678 
679 
680 
681 
Paint(const Rectangle & rRect)682 void TabBarControl::Paint (const Rectangle& rRect)
683 {
684     Color aOriginalFillColor (GetFillColor());
685     Color aOriginalLineColor (GetLineColor());
686 
687     // Because the actual window background is transparent--to avoid
688     // flickering due to multiple background paintings by this and by child
689     // windows--we have to paint the background for this control explicitly:
690     // the actual control is not painted over its whole bounding box.
691     SetFillColor (GetSettings().GetStyleSettings().GetDialogColor());
692     SetLineColor ();
693     DrawRect (rRect);
694     ::TabControl::Paint (rRect);
695 
696     SetFillColor (aOriginalFillColor);
697     SetLineColor (aOriginalLineColor);
698 }
699 
700 
701 
702 
ActivatePage(void)703 void TabBarControl::ActivatePage (void)
704 {
705     if (mpViewTabBar->ActivatePage())
706     {
707         // Call the parent so that the correct tab is highlighted.
708         this->::TabControl::ActivatePage();
709     }
710 }
711 
712 } // end of namespace sd
713