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 .
20 #include "ViewTabBar.hxx"
22 #include "ViewShell.hxx"
23 #include "ViewShellBase.hxx"
24 #include "DrawViewShell.hxx"
25 #include "FrameView.hxx"
26 #include "EventMultiplexer.hxx"
27 #include "framework/FrameworkHelper.hxx"
28 #include "framework/Pane.hxx"
29 #include "DrawController.hxx"
31 #include "sdresid.hxx"
32 #include "strings.hrc"
35 #include <vcl/svapp.hxx>
36 #include <vcl/tabpage.hxx>
37 #include <vcl/settings.hxx>
39 #include <osl/mutex.hxx>
40 #include <sfx2/viewfrm.hxx>
41 #include <com/sun/star/drawing/framework/ResourceId.hpp>
42 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
43 #include <com/sun/star/lang/XUnoTunnel.hpp>
44 #include <com/sun/star/lang/DisposedException.hpp>
45 #include <comphelper/processfactory.hxx>
46 #include <comphelper/servicehelper.hxx>
47 #include <tools/diagnose_ex.h>
49 using namespace ::com::sun::star
;
50 using namespace ::com::sun::star::uno
;
51 using namespace ::com::sun::star::drawing::framework
;
52 using ::sd::framework::FrameworkHelper
;
53 using ::sd::tools::EventMultiplexerEvent
;
58 bool IsEqual (const TabBarButton
& rButton1
, const TabBarButton
& rButton2
)
60 return ((rButton1
.ResourceId
.is()
61 && rButton2
.ResourceId
.is()
62 && rButton1
.ResourceId
->compareTo(rButton2
.ResourceId
) == 0)
63 || rButton1
.ButtonLabel
== rButton2
.ButtonLabel
);
66 class TabBarControl
: public ::TabControl
69 TabBarControl (vcl::Window
* pParentWindow
, const ::rtl::Reference
<ViewTabBar
>& rpViewTabBar
);
70 virtual void Paint (vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
) SAL_OVERRIDE
;
71 virtual void ActivatePage() SAL_OVERRIDE
;
73 ::rtl::Reference
<ViewTabBar
> mpViewTabBar
;
76 } // end of anonymous namespace
78 ViewTabBar::ViewTabBar (
79 const Reference
<XResourceId
>& rxViewTabBarId
,
80 const Reference
<frame::XController
>& rxController
)
81 : ViewTabBarInterfaceBase(maMutex
),
82 mpTabControl(VclPtr
<TabBarControl
>::Create(GetAnchorWindow(rxViewTabBarId
,rxController
), this)),
83 mxController(rxController
),
86 mxViewTabBarId(rxViewTabBarId
),
89 // Set one new tab page for all tab entries. We need it only to
90 // determine the height of the tab bar.
91 mpTabPage
.reset(VclPtr
<TabPage
>::Create(mpTabControl
.get()));
94 // add some space before the tabitems
95 mpTabControl
->SetItemsOffset(Point(5, 3));
97 // Tunnel through the controller and use the ViewShellBase to obtain the
101 Reference
<lang::XUnoTunnel
> xTunnel (mxController
, UNO_QUERY_THROW
);
102 DrawController
* pController
= reinterpret_cast<DrawController
*>(
103 xTunnel
->getSomething(DrawController::getUnoTunnelId()));
104 mpViewShellBase
= pController
->GetViewShellBase();
106 catch (const RuntimeException
&)
110 // Register as listener at XConfigurationController.
111 Reference
<XControllerManager
> xControllerManager (mxController
, UNO_QUERY
);
112 if (xControllerManager
.is())
114 mxConfigurationController
= xControllerManager
->getConfigurationController();
115 if (mxConfigurationController
.is())
117 mxConfigurationController
->addConfigurationChangeListener(
119 FrameworkHelper::msResourceActivationEvent
,
124 mpTabControl
->Show();
126 if (mpViewShellBase
!= NULL
127 && rxViewTabBarId
->isBoundToURL(
128 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
130 mpViewShellBase
->SetViewTabBar(this);
134 ViewTabBar::~ViewTabBar()
138 void ViewTabBar::disposing()
140 if (mpViewShellBase
!= NULL
141 && mxViewTabBarId
->isBoundToURL(
142 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
144 mpViewShellBase
->SetViewTabBar(NULL
);
147 if (mxConfigurationController
.is())
149 // Unregister listener from XConfigurationController.
152 mxConfigurationController
->removeConfigurationChangeListener(this);
154 catch (const lang::DisposedException
&)
156 // Receiving a disposed exception is the normal case. Is there
157 // a way to avoid it?
159 mxConfigurationController
= NULL
;
163 const SolarMutexGuard aSolarGuard
;
164 // Set all references to the one tab page to NULL and delete the page.
165 for (sal_uInt16 nIndex
=0; nIndex
<mpTabControl
->GetPageCount(); ++nIndex
)
166 mpTabControl
->SetTabPage(nIndex
, NULL
);
167 mpTabPage
.disposeAndClear();
168 mpTabControl
.disposeAndClear();
174 vcl::Window
* ViewTabBar::GetAnchorWindow(
175 const Reference
<XResourceId
>& rxViewTabBarId
,
176 const Reference
<frame::XController
>& rxController
)
178 vcl::Window
* pWindow
= NULL
;
179 ViewShellBase
* pBase
= NULL
;
181 // Tunnel through the controller and use the ViewShellBase to obtain the
185 Reference
<lang::XUnoTunnel
> xTunnel (rxController
, UNO_QUERY_THROW
);
186 DrawController
* pController
= reinterpret_cast<DrawController
*>(
187 xTunnel
->getSomething(DrawController::getUnoTunnelId()));
188 pBase
= pController
->GetViewShellBase();
190 catch (const RuntimeException
&)
194 // The ViewTabBar supports at the moment only the center pane.
195 if (rxViewTabBarId
.is()
196 && rxViewTabBarId
->isBoundToURL(
197 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
199 if (pBase
!= NULL
&& pBase
->GetViewFrame() != NULL
)
200 pWindow
= &pBase
->GetViewFrame()->GetWindow();
203 // The rest is (at the moment) just for the emergency case.
206 Reference
<XPane
> xPane
;
209 Reference
<XControllerManager
> xControllerManager (rxController
, UNO_QUERY_THROW
);
210 Reference
<XConfigurationController
> xCC (
211 xControllerManager
->getConfigurationController());
213 xPane
= Reference
<XPane
>(xCC
->getResource(rxViewTabBarId
->getAnchor()), UNO_QUERY
);
215 catch (const RuntimeException
&)
219 // Tunnel through the XWindow to the VCL side.
222 Reference
<lang::XUnoTunnel
> xTunnel (xPane
, UNO_QUERY_THROW
);
223 framework::Pane
* pPane
= reinterpret_cast<framework::Pane
*>(
224 xTunnel
->getSomething(framework::Pane::getUnoTunnelId()));
226 pWindow
= pPane
->GetWindow()->GetParent();
228 catch (const RuntimeException
&)
236 //----- XConfigurationChangeListener ------------------------------------------
238 void SAL_CALL
ViewTabBar::notifyConfigurationChange (
239 const ConfigurationChangeEvent
& rEvent
)
240 throw (RuntimeException
, std::exception
)
242 if (rEvent
.Type
.equals(FrameworkHelper::msResourceActivationEvent
)
243 && rEvent
.ResourceId
->getResourceURL().match(FrameworkHelper::msViewURLPrefix
)
244 && rEvent
.ResourceId
->isBoundTo(mxViewTabBarId
->getAnchor(), AnchorBindingMode_DIRECT
))
246 UpdateActiveButton();
250 //----- XEventListener --------------------------------------------------------
252 void SAL_CALL
ViewTabBar::disposing(
253 const lang::EventObject
& rEvent
)
254 throw (RuntimeException
, std::exception
)
256 if (rEvent
.Source
== mxConfigurationController
)
258 mxConfigurationController
= NULL
;
263 //----- XTabBar ---------------------------------------------------------------
265 void SAL_CALL
ViewTabBar::addTabBarButtonAfter (
266 const TabBarButton
& rButton
,
267 const TabBarButton
& rAnchor
)
268 throw (::com::sun::star::uno::RuntimeException
, std::exception
)
270 const SolarMutexGuard aSolarGuard
;
271 AddTabBarButton(rButton
, rAnchor
);
274 void SAL_CALL
ViewTabBar::appendTabBarButton (const TabBarButton
& rButton
)
275 throw (::com::sun::star::uno::RuntimeException
, std::exception
)
277 const SolarMutexGuard aSolarGuard
;
278 AddTabBarButton(rButton
);
281 void SAL_CALL
ViewTabBar::removeTabBarButton (const TabBarButton
& rButton
)
282 throw (::com::sun::star::uno::RuntimeException
, std::exception
)
284 const SolarMutexGuard aSolarGuard
;
285 RemoveTabBarButton(rButton
);
288 sal_Bool SAL_CALL
ViewTabBar::hasTabBarButton (const TabBarButton
& rButton
)
289 throw (::com::sun::star::uno::RuntimeException
, std::exception
)
291 const SolarMutexGuard aSolarGuard
;
292 return HasTabBarButton(rButton
);
295 Sequence
<TabBarButton
> SAL_CALL
ViewTabBar::getTabBarButtons()
296 throw (::com::sun::star::uno::RuntimeException
, std::exception
)
298 const SolarMutexGuard aSolarGuard
;
299 return GetTabBarButtons();
302 //----- XResource -------------------------------------------------------------
304 Reference
<XResourceId
> SAL_CALL
ViewTabBar::getResourceId()
305 throw (RuntimeException
, std::exception
)
307 return mxViewTabBarId
;
310 sal_Bool SAL_CALL
ViewTabBar::isAnchorOnly()
311 throw (RuntimeException
, std::exception
)
316 //----- XUnoTunnel ------------------------------------------------------------
320 class theViewTabBarUnoTunnelId
: public rtl::Static
< UnoTunnelIdInit
, theViewTabBarUnoTunnelId
> {};
323 const Sequence
<sal_Int8
>& ViewTabBar::getUnoTunnelId()
325 return theViewTabBarUnoTunnelId::get().getSeq();
328 sal_Int64 SAL_CALL
ViewTabBar::getSomething (const Sequence
<sal_Int8
>& rId
)
329 throw (RuntimeException
, std::exception
)
331 sal_Int64 nResult
= 0;
333 if (rId
.getLength() == 16
334 && memcmp(getUnoTunnelId().getConstArray(), rId
.getConstArray(), 16) == 0)
336 nResult
= reinterpret_cast<sal_Int64
>(this);
342 bool ViewTabBar::ActivatePage()
346 Reference
<XControllerManager
> xControllerManager (mxController
,UNO_QUERY_THROW
);
347 Reference
<XConfigurationController
> xConfigurationController (
348 xControllerManager
->getConfigurationController());
349 if ( ! xConfigurationController
.is())
350 throw RuntimeException();
351 Reference
<XView
> xView
;
354 xView
= Reference
<XView
>(xConfigurationController
->getResource(
356 ::comphelper::getProcessComponentContext(),
357 FrameworkHelper::msCenterPaneURL
)),
360 catch (const DeploymentException
&)
364 Client
* pIPClient
= NULL
;
365 if (mpViewShellBase
!= NULL
)
366 pIPClient
= dynamic_cast<Client
*>(mpViewShellBase
->GetIPClient());
367 if (pIPClient
==NULL
|| ! pIPClient
->IsObjectInPlaceActive())
369 sal_uInt16
nIndex (mpTabControl
->GetCurPageId() - 1);
370 if (nIndex
< maTabBarButtons
.size())
372 xConfigurationController
->requestResourceActivation(
373 maTabBarButtons
[nIndex
].ResourceId
,
374 ResourceActivationMode_REPLACE
);
381 // When we run into this else branch then we have an active OLE
382 // object. We ignore the request to switch views. Additionally
383 // we put the active tab back to the one for the current view.
384 UpdateActiveButton();
387 catch (const RuntimeException
&)
389 DBG_UNHANDLED_EXCEPTION();
395 int ViewTabBar::GetHeight()
399 if (!maTabBarButtons
.empty())
401 TabPage
* pActivePage (mpTabControl
->GetTabPage(
402 mpTabControl
->GetCurPageId()));
403 if (pActivePage
!=NULL
&& mpTabControl
->IsReallyVisible())
404 nHeight
= pActivePage
->GetPosPixel().Y();
407 // Using a default when the real height can not be determined.
408 // To get correct height this method should be called when the
409 // control is visible.
416 void ViewTabBar::AddTabBarButton (
417 const ::com::sun::star::drawing::framework::TabBarButton
& rButton
,
418 const ::com::sun::star::drawing::framework::TabBarButton
& rAnchor
)
422 if ( ! rAnchor
.ResourceId
.is()
423 || (rAnchor
.ResourceId
->getResourceURL().isEmpty()
424 && rAnchor
.ButtonLabel
.isEmpty()))
430 for (nIndex
=0; nIndex
<maTabBarButtons
.size(); ++nIndex
)
432 if (IsEqual(maTabBarButtons
[nIndex
], rAnchor
))
440 AddTabBarButton(rButton
,nIndex
);
443 void ViewTabBar::AddTabBarButton (
444 const ::com::sun::star::drawing::framework::TabBarButton
& rButton
)
446 AddTabBarButton(rButton
, maTabBarButtons
.size());
449 void ViewTabBar::AddTabBarButton (
450 const ::com::sun::star::drawing::framework::TabBarButton
& rButton
,
454 && nPosition
<=mpTabControl
->GetPageCount())
456 sal_uInt16
nIndex ((sal_uInt16
)nPosition
);
458 // Insert the button into our local array.
459 maTabBarButtons
.insert(maTabBarButtons
.begin()+nIndex
, rButton
);
460 UpdateTabBarButtons();
461 UpdateActiveButton();
465 void ViewTabBar::RemoveTabBarButton (
466 const ::com::sun::star::drawing::framework::TabBarButton
& rButton
)
469 for (nIndex
=0; nIndex
<maTabBarButtons
.size(); ++nIndex
)
471 if (IsEqual(maTabBarButtons
[nIndex
], rButton
))
473 maTabBarButtons
.erase(maTabBarButtons
.begin()+nIndex
);
474 UpdateTabBarButtons();
475 UpdateActiveButton();
481 bool ViewTabBar::HasTabBarButton (
482 const ::com::sun::star::drawing::framework::TabBarButton
& rButton
)
484 bool bResult (false);
486 for (sal_uInt32 nIndex
=0; nIndex
<maTabBarButtons
.size(); ++nIndex
)
488 if (IsEqual(maTabBarButtons
[nIndex
], rButton
))
498 ::com::sun::star::uno::Sequence
<com::sun::star::drawing::framework::TabBarButton
>
499 ViewTabBar::GetTabBarButtons()
501 sal_uInt32
nCount (maTabBarButtons
.size());
502 ::com::sun::star::uno::Sequence
<com::sun::star::drawing::framework::TabBarButton
>
505 for (sal_uInt32 nIndex
=0; nIndex
<nCount
; ++nIndex
)
506 aList
[nIndex
] = maTabBarButtons
[nIndex
];
511 void ViewTabBar::UpdateActiveButton()
513 Reference
<XView
> xView
;
514 if (mpViewShellBase
!= NULL
)
515 xView
= FrameworkHelper::Instance(*mpViewShellBase
)->GetView(
516 mxViewTabBarId
->getAnchor());
519 Reference
<XResourceId
> xViewId (xView
->getResourceId());
520 for (sal_uInt16 nIndex
=0; nIndex
<maTabBarButtons
.size(); ++nIndex
)
522 if (maTabBarButtons
[nIndex
].ResourceId
->compareTo(xViewId
) == 0)
524 mpTabControl
->SetCurPageId(nIndex
+1);
525 mpTabControl
->::TabControl::ActivatePage();
532 void ViewTabBar::UpdateTabBarButtons()
534 TabBarButtonList::const_iterator iTab
;
535 sal_uInt16
nPageCount (mpTabControl
->GetPageCount());
537 for (iTab
=maTabBarButtons
.begin(),nIndex
=1; iTab
!=maTabBarButtons
.end(); ++iTab
,++nIndex
)
539 // Create a new tab when there are not enough.
540 if (nPageCount
< nIndex
)
541 mpTabControl
->InsertPage(nIndex
, iTab
->ButtonLabel
);
544 mpTabControl
->SetPageText(nIndex
, iTab
->ButtonLabel
);
545 mpTabControl
->SetHelpText(nIndex
, iTab
->HelpText
);
546 mpTabControl
->SetTabPage(nIndex
, mpTabPage
.get());
549 // Delete tabs that are no longer used.
550 for (; nIndex
<=nPageCount
; ++nIndex
)
551 mpTabControl
->RemovePage(nIndex
);
556 //===== TabBarControl =========================================================
558 TabBarControl::TabBarControl (
559 vcl::Window
* pParentWindow
,
560 const ::rtl::Reference
<ViewTabBar
>& rpViewTabBar
)
561 : ::TabControl(pParentWindow
),
562 mpViewTabBar(rpViewTabBar
)
566 void TabBarControl::Paint (vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
)
568 Color
aOriginalFillColor(rRenderContext
.GetFillColor());
569 Color
aOriginalLineColor(rRenderContext
.GetLineColor());
571 // Because the actual window background is transparent--to avoid
572 // flickering due to multiple background paintings by this and by child
573 // windows--we have to paint the background for this control explicitly:
574 // the actual control is not painted over its whole bounding box.
575 rRenderContext
.SetFillColor(rRenderContext
.GetSettings().GetStyleSettings().GetDialogColor());
576 rRenderContext
.SetLineColor();
577 rRenderContext
.DrawRect(rRect
);
579 ::TabControl::Paint(rRenderContext
, rRect
);
581 rRenderContext
.SetFillColor(aOriginalFillColor
);
582 rRenderContext
.SetLineColor(aOriginalLineColor
);
585 void TabBarControl::ActivatePage()
587 if (mpViewTabBar
->ActivatePage())
589 // Call the parent so that the correct tab is highlighted.
590 this->::TabControl::ActivatePage();
594 } // end of namespace sd
596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */