1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "ViewTabBar.hxx"
23 #include "ViewShell.hxx"
24 #include "ViewShellBase.hxx"
25 #include "DrawViewShell.hxx"
26 #include "FrameView.hxx"
27 #include "EventMultiplexer.hxx"
28 #include "framework/FrameworkHelper.hxx"
29 #include "framework/Pane.hxx"
30 #include "DrawController.hxx"
32 #include "sdresid.hxx"
33 #include "strings.hrc"
36 #include <vcl/svapp.hxx>
37 #include <vcl/tabpage.hxx>
38 #include <osl/mutex.hxx>
39 #include <sfx2/viewfrm.hxx>
40 #include <com/sun/star/drawing/framework/ResourceId.hpp>
41 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
42 #include <com/sun/star/lang/XUnoTunnel.hpp>
43 #include <com/sun/star/lang/DisposedException.hpp>
44 #include <comphelper/processfactory.hxx>
45 #include <comphelper/servicehelper.hxx>
46 #include <tools/diagnose_ex.h>
48 using namespace ::com::sun::star
;
49 using namespace ::com::sun::star::uno
;
50 using namespace ::com::sun::star::drawing::framework
;
51 using ::sd::framework::FrameworkHelper
;
52 using ::sd::tools::EventMultiplexerEvent
;
57 bool IsEqual (const TabBarButton
& rButton1
, const TabBarButton
& rButton2
)
60 (rButton1
.ResourceId
.is()
61 && rButton2
.ResourceId
.is()
62 && rButton1
.ResourceId
->compareTo(rButton2
.ResourceId
)==0)
63 || rButton1
.ButtonLabel
== rButton2
.ButtonLabel
);
66 class TabBarControl
: public ::TabControl
70 ::Window
* pParentWindow
,
71 const ::rtl::Reference
<ViewTabBar
>& rpViewTabBar
);
72 virtual void Paint (const Rectangle
& rRect
);
73 virtual void ActivatePage (void);
75 ::rtl::Reference
<ViewTabBar
> mpViewTabBar
;
78 } // end of anonymous namespace
84 class ViewTabPage
: public TabPage
87 ViewTabPage (Window
* pParent
) : TabPage(pParent
) {}
88 virtual void Resize (void)
89 { SetPosSizePixel(Point(0,0),GetParent()->GetOutputSizePixel()); }
95 //===== ViewTabBar ============================================================
97 ViewTabBar::ViewTabBar (
98 const Reference
<XResourceId
>& rxViewTabBarId
,
99 const Reference
<frame::XController
>& rxController
)
100 : ViewTabBarInterfaceBase(maMutex
),
101 mpTabControl(new TabBarControl(GetAnchorWindow(rxViewTabBarId
,rxController
), this)),
102 mxController(rxController
),
105 mxViewTabBarId(rxViewTabBarId
),
106 mpViewShellBase(NULL
)
108 // Set one new tab page for all tab entries. We need it only to
109 // determine the height of the tab bar.
110 mpTabPage
.reset(new TabPage (mpTabControl
.get()));
113 // add some space before the tabitems
114 mpTabControl
->SetItemsOffset(Point(5, 3));
116 // Tunnel through the controller and use the ViewShellBase to obtain the
120 Reference
<lang::XUnoTunnel
> xTunnel (mxController
, UNO_QUERY_THROW
);
121 DrawController
* pController
= reinterpret_cast<DrawController
*>(
122 xTunnel
->getSomething(DrawController::getUnoTunnelId()));
123 mpViewShellBase
= pController
->GetViewShellBase();
125 catch (const RuntimeException
&)
129 // Register as listener at XConfigurationController.
130 Reference
<XControllerManager
> xControllerManager (mxController
, UNO_QUERY
);
131 if (xControllerManager
.is())
133 mxConfigurationController
= xControllerManager
->getConfigurationController();
134 if (mxConfigurationController
.is())
136 mxConfigurationController
->addConfigurationChangeListener(
138 FrameworkHelper::msResourceActivationEvent
,
143 mpTabControl
->Show();
145 if (mpViewShellBase
!= NULL
146 && rxViewTabBarId
->isBoundToURL(
147 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
149 mpViewShellBase
->SetViewTabBar(this);
156 ViewTabBar::~ViewTabBar (void)
163 void ViewTabBar::disposing (void)
165 if (mpViewShellBase
!= NULL
166 && mxViewTabBarId
->isBoundToURL(
167 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
169 mpViewShellBase
->SetViewTabBar(NULL
);
172 if (mxConfigurationController
.is())
174 // Unregister listener from XConfigurationController.
177 mxConfigurationController
->removeConfigurationChangeListener(this);
179 catch (const lang::DisposedException
&)
181 // Receiving a disposed exception is the normal case. Is there
182 // a way to avoid it?
184 mxConfigurationController
= NULL
;
188 const SolarMutexGuard aSolarGuard
;
189 // Set all references to the one tab page to NULL and delete the page.
190 for (sal_uInt16 nIndex
=0; nIndex
<mpTabControl
->GetPageCount(); ++nIndex
)
191 mpTabControl
->SetTabPage(nIndex
, NULL
);
193 mpTabControl
.reset();
202 ::boost::shared_ptr
< ::TabControl
> ViewTabBar::GetTabControl (void) const
210 ::Window
* ViewTabBar::GetAnchorWindow(
211 const Reference
<XResourceId
>& rxViewTabBarId
,
212 const Reference
<frame::XController
>& rxController
)
214 ::Window
* pWindow
= NULL
;
215 ViewShellBase
* pBase
= NULL
;
217 // Tunnel through the controller and use the ViewShellBase to obtain the
221 Reference
<lang::XUnoTunnel
> xTunnel (rxController
, UNO_QUERY_THROW
);
222 DrawController
* pController
= reinterpret_cast<DrawController
*>(
223 xTunnel
->getSomething(DrawController::getUnoTunnelId()));
224 pBase
= pController
->GetViewShellBase();
226 catch (const RuntimeException
&)
230 // The ViewTabBar supports at the moment only the center pane.
231 if (rxViewTabBarId
.is()
232 && rxViewTabBarId
->isBoundToURL(
233 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
235 if (pBase
!= NULL
&& pBase
->GetViewFrame() != NULL
)
236 pWindow
= &pBase
->GetViewFrame()->GetWindow();
239 // The rest is (at the moment) just for the emergency case.
242 Reference
<XPane
> xPane
;
245 Reference
<XControllerManager
> xControllerManager (rxController
, UNO_QUERY_THROW
);
246 Reference
<XConfigurationController
> xCC (
247 xControllerManager
->getConfigurationController());
249 xPane
= Reference
<XPane
>(xCC
->getResource(rxViewTabBarId
->getAnchor()), UNO_QUERY
);
251 catch (const RuntimeException
&)
255 // Tunnel through the XWindow to the VCL side.
258 Reference
<lang::XUnoTunnel
> xTunnel (xPane
, UNO_QUERY_THROW
);
259 framework::Pane
* pPane
= reinterpret_cast<framework::Pane
*>(
260 xTunnel
->getSomething(framework::Pane::getUnoTunnelId()));
262 pWindow
= pPane
->GetWindow()->GetParent();
264 catch (const RuntimeException
&)
275 //----- XConfigurationChangeListener ------------------------------------------
277 void SAL_CALL
ViewTabBar::notifyConfigurationChange (
278 const ConfigurationChangeEvent
& rEvent
)
279 throw (RuntimeException
)
281 if (rEvent
.Type
.equals(FrameworkHelper::msResourceActivationEvent
)
282 && rEvent
.ResourceId
->getResourceURL().match(FrameworkHelper::msViewURLPrefix
)
283 && rEvent
.ResourceId
->isBoundTo(mxViewTabBarId
->getAnchor(), AnchorBindingMode_DIRECT
))
285 UpdateActiveButton();
292 //----- XEventListener --------------------------------------------------------
294 void SAL_CALL
ViewTabBar::disposing(
295 const lang::EventObject
& rEvent
)
296 throw (RuntimeException
)
298 if (rEvent
.Source
== mxConfigurationController
)
300 mxConfigurationController
= NULL
;
308 //----- XTabBar ---------------------------------------------------------------
310 void SAL_CALL
ViewTabBar::addTabBarButtonAfter (
311 const TabBarButton
& rButton
,
312 const TabBarButton
& rAnchor
)
313 throw (::com::sun::star::uno::RuntimeException
)
315 const SolarMutexGuard aSolarGuard
;
316 AddTabBarButton(rButton
, rAnchor
);
322 void SAL_CALL
ViewTabBar::appendTabBarButton (const TabBarButton
& rButton
)
323 throw (::com::sun::star::uno::RuntimeException
)
325 const SolarMutexGuard aSolarGuard
;
326 AddTabBarButton(rButton
);
331 void SAL_CALL
ViewTabBar::removeTabBarButton (const TabBarButton
& rButton
)
332 throw (::com::sun::star::uno::RuntimeException
)
334 const SolarMutexGuard aSolarGuard
;
335 RemoveTabBarButton(rButton
);
341 sal_Bool SAL_CALL
ViewTabBar::hasTabBarButton (const TabBarButton
& rButton
)
342 throw (::com::sun::star::uno::RuntimeException
)
344 const SolarMutexGuard aSolarGuard
;
345 return HasTabBarButton(rButton
);
351 Sequence
<TabBarButton
> SAL_CALL
ViewTabBar::getTabBarButtons (void)
352 throw (::com::sun::star::uno::RuntimeException
)
354 const SolarMutexGuard aSolarGuard
;
355 return GetTabBarButtons();
361 //----- XResource -------------------------------------------------------------
363 Reference
<XResourceId
> SAL_CALL
ViewTabBar::getResourceId (void)
364 throw (RuntimeException
)
366 return mxViewTabBarId
;
372 sal_Bool SAL_CALL
ViewTabBar::isAnchorOnly (void)
373 throw (RuntimeException
)
381 //----- XUnoTunnel ------------------------------------------------------------
385 class theViewTabBarUnoTunnelId
: public rtl::Static
< UnoTunnelIdInit
, theViewTabBarUnoTunnelId
> {};
388 const Sequence
<sal_Int8
>& ViewTabBar::getUnoTunnelId (void)
390 return theViewTabBarUnoTunnelId::get().getSeq();
393 sal_Int64 SAL_CALL
ViewTabBar::getSomething (const Sequence
<sal_Int8
>& rId
)
394 throw (RuntimeException
)
396 sal_Int64 nResult
= 0;
398 if (rId
.getLength() == 16
399 && memcmp(getUnoTunnelId().getConstArray(), rId
.getConstArray(), 16) == 0)
401 nResult
= reinterpret_cast<sal_Int64
>(this);
410 //-----------------------------------------------------------------------------
412 bool ViewTabBar::ActivatePage (void)
416 Reference
<XControllerManager
> xControllerManager (mxController
,UNO_QUERY_THROW
);
417 Reference
<XConfigurationController
> xConfigurationController (
418 xControllerManager
->getConfigurationController());
419 if ( ! xConfigurationController
.is())
420 throw RuntimeException();
421 Reference
<XView
> xView
;
424 xView
= Reference
<XView
>(xConfigurationController
->getResource(
426 ::comphelper::getProcessComponentContext(),
427 FrameworkHelper::msCenterPaneURL
)),
430 catch (const DeploymentException
&)
434 Client
* pIPClient
= NULL
;
435 if (mpViewShellBase
!= NULL
)
436 pIPClient
= dynamic_cast<Client
*>(mpViewShellBase
->GetIPClient());
437 if (pIPClient
==NULL
|| ! pIPClient
->IsObjectInPlaceActive())
439 sal_uInt16
nIndex (mpTabControl
->GetCurPageId() - 1);
440 if (nIndex
< maTabBarButtons
.size())
442 xConfigurationController
->requestResourceActivation(
443 maTabBarButtons
[nIndex
].ResourceId
,
444 ResourceActivationMode_REPLACE
);
451 // When we run into this else branch then we have an active OLE
452 // object. We ignore the request to switch views. Additionally
453 // we put the active tab back to the one for the current view.
454 UpdateActiveButton();
457 catch (const RuntimeException
&)
459 DBG_UNHANDLED_EXCEPTION();
468 int ViewTabBar::GetHeight (void)
472 if (!maTabBarButtons
.empty())
474 TabPage
* pActivePage (mpTabControl
->GetTabPage(
475 mpTabControl
->GetCurPageId()));
476 if (pActivePage
!=NULL
&& mpTabControl
->IsReallyVisible())
477 nHeight
= pActivePage
->GetPosPixel().Y();
480 // Using a default when the real height can not be determined.
481 // To get correct height this method should be called when the
482 // control is visible.
492 void ViewTabBar::AddTabBarButton (
493 const ::com::sun::star::drawing::framework::TabBarButton
& rButton
,
494 const ::com::sun::star::drawing::framework::TabBarButton
& rAnchor
)
498 if ( ! rAnchor
.ResourceId
.is()
499 || (rAnchor
.ResourceId
->getResourceURL().isEmpty()
500 && rAnchor
.ButtonLabel
.isEmpty()))
506 for (nIndex
=0; nIndex
<maTabBarButtons
.size(); ++nIndex
)
508 if (IsEqual(maTabBarButtons
[nIndex
], rAnchor
))
516 AddTabBarButton(rButton
,nIndex
);
522 void ViewTabBar::AddTabBarButton (
523 const ::com::sun::star::drawing::framework::TabBarButton
& rButton
)
525 AddTabBarButton(rButton
, maTabBarButtons
.size());
531 void ViewTabBar::AddTabBarButton (
532 const ::com::sun::star::drawing::framework::TabBarButton
& rButton
,
536 && nPosition
<=mpTabControl
->GetPageCount())
538 sal_uInt16
nIndex ((sal_uInt16
)nPosition
);
540 // Insert the button into our local array.
541 maTabBarButtons
.insert(maTabBarButtons
.begin()+nIndex
, rButton
);
542 UpdateTabBarButtons();
543 UpdateActiveButton();
550 void ViewTabBar::RemoveTabBarButton (
551 const ::com::sun::star::drawing::framework::TabBarButton
& rButton
)
554 for (nIndex
=0; nIndex
<maTabBarButtons
.size(); ++nIndex
)
556 if (IsEqual(maTabBarButtons
[nIndex
], rButton
))
558 maTabBarButtons
.erase(maTabBarButtons
.begin()+nIndex
);
559 UpdateTabBarButtons();
560 UpdateActiveButton();
569 bool ViewTabBar::HasTabBarButton (
570 const ::com::sun::star::drawing::framework::TabBarButton
& rButton
)
572 bool bResult (false);
574 for (sal_uInt32 nIndex
=0; nIndex
<maTabBarButtons
.size(); ++nIndex
)
576 if (IsEqual(maTabBarButtons
[nIndex
], rButton
))
589 ::com::sun::star::uno::Sequence
<com::sun::star::drawing::framework::TabBarButton
>
590 ViewTabBar::GetTabBarButtons (void)
592 sal_uInt32
nCount (maTabBarButtons
.size());
593 ::com::sun::star::uno::Sequence
<com::sun::star::drawing::framework::TabBarButton
>
596 for (sal_uInt32 nIndex
=0; nIndex
<nCount
; ++nIndex
)
597 aList
[nIndex
] = maTabBarButtons
[nIndex
];
605 void ViewTabBar::UpdateActiveButton (void)
607 Reference
<XView
> xView
;
608 if (mpViewShellBase
!= NULL
)
609 xView
= FrameworkHelper::Instance(*mpViewShellBase
)->GetView(
610 mxViewTabBarId
->getAnchor());
613 Reference
<XResourceId
> xViewId (xView
->getResourceId());
614 for (sal_uInt16 nIndex
=0; nIndex
<maTabBarButtons
.size(); ++nIndex
)
616 if (maTabBarButtons
[nIndex
].ResourceId
->compareTo(xViewId
) == 0)
618 mpTabControl
->SetCurPageId(nIndex
+1);
619 mpTabControl
->::TabControl::ActivatePage();
629 void ViewTabBar::UpdateTabBarButtons (void)
631 TabBarButtonList::const_iterator iTab
;
632 sal_uInt16
nPageCount (mpTabControl
->GetPageCount());
634 for (iTab
=maTabBarButtons
.begin(),nIndex
=1; iTab
!=maTabBarButtons
.end(); ++iTab
,++nIndex
)
636 // Create a new tab when there are not enough.
637 if (nPageCount
< nIndex
)
638 mpTabControl
->InsertPage(nIndex
, iTab
->ButtonLabel
);
641 mpTabControl
->SetPageText(nIndex
, iTab
->ButtonLabel
);
642 mpTabControl
->SetHelpText(nIndex
, iTab
->HelpText
);
643 mpTabControl
->SetTabPage(nIndex
, mpTabPage
.get());
646 // Delete tabs that are no longer used.
647 for (; nIndex
<=nPageCount
; ++nIndex
)
648 mpTabControl
->RemovePage(nIndex
);
656 //===== TabBarControl =========================================================
658 TabBarControl::TabBarControl (
659 ::Window
* pParentWindow
,
660 const ::rtl::Reference
<ViewTabBar
>& rpViewTabBar
)
661 : ::TabControl(pParentWindow
),
662 mpViewTabBar(rpViewTabBar
)
669 void TabBarControl::Paint (const Rectangle
& rRect
)
671 Color
aOriginalFillColor (GetFillColor());
672 Color
aOriginalLineColor (GetLineColor());
674 // Because the actual window background is transparent--to avoid
675 // flickering due to multiple background paintings by this and by child
676 // windows--we have to paint the background for this control explicitly:
677 // the actual control is not painted over its whole bounding box.
678 SetFillColor (GetSettings().GetStyleSettings().GetDialogColor());
681 ::TabControl::Paint (rRect
);
683 SetFillColor (aOriginalFillColor
);
684 SetLineColor (aOriginalLineColor
);
690 void TabBarControl::ActivatePage (void)
692 if (mpViewTabBar
->ActivatePage())
694 // Call the parent so that the correct tab is highlighted.
695 this->::TabControl::ActivatePage();
699 } // end of namespace sd
701 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */