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