diff options
Diffstat (limited to 'sd/source/ui/view/ViewTabBar.cxx')
-rw-r--r-- | sd/source/ui/view/ViewTabBar.cxx | 719 |
1 files changed, 719 insertions, 0 deletions
diff --git a/sd/source/ui/view/ViewTabBar.cxx b/sd/source/ui/view/ViewTabBar.cxx new file mode 100644 index 000000000000..49d3a6bd4baf --- /dev/null +++ b/sd/source/ui/view/ViewTabBar.cxx @@ -0,0 +1,719 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" + +#include "ViewTabBar.hxx" + +#define USE_TAB_CONTROL + +#include "ViewShell.hxx" +#include "ViewShellBase.hxx" +#include "DrawViewShell.hxx" +#include "FrameView.hxx" +#include "EventMultiplexer.hxx" +#include "framework/FrameworkHelper.hxx" +#include "framework/Pane.hxx" +#include "DrawController.hxx" + +#include "sdresid.hxx" +#include "strings.hrc" +#include "helpids.h" +#include "Client.hxx" +#include <vcl/svapp.hxx> +#include <vcl/tabpage.hxx> +#include <osl/mutex.hxx> +#include <sfx2/viewfrm.hxx> +#include <com/sun/star/drawing/framework/ResourceId.hpp> +#include <com/sun/star/drawing/framework/XControllerManager.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <comphelper/processfactory.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; +using ::sd::framework::FrameworkHelper; +using ::sd::tools::EventMultiplexerEvent; +using ::rtl::OUString; + +namespace sd { + +namespace { +bool IsEqual (const TabBarButton& rButton1, const TabBarButton& rButton2) +{ + return ( + (rButton1.ResourceId.is() + && rButton2.ResourceId.is() + && rButton1.ResourceId->compareTo(rButton2.ResourceId)==0) + || rButton1.ButtonLabel == rButton2.ButtonLabel); +} + +class TabBarControl : public ::TabControl +{ +public: + TabBarControl ( + ::Window* pParentWindow, + const ::rtl::Reference<ViewTabBar>& rpViewTabBar); + virtual void Paint (const Rectangle& rRect); + virtual void ActivatePage (void); +private: + ::rtl::Reference<ViewTabBar> mpViewTabBar; +}; + +} // end of anonymous namespace + + + + + +class ViewTabPage : public TabPage +{ +public: + ViewTabPage (Window* pParent) : TabPage(pParent) {} + virtual void Resize (void) + { SetPosSizePixel(Point(0,0),GetParent()->GetOutputSizePixel()); } +}; + + + + +//===== ViewTabBar ============================================================ + +ViewTabBar::ViewTabBar ( + const Reference<XResourceId>& rxViewTabBarId, + const Reference<frame::XController>& rxController) + : ViewTabBarInterfaceBase(maMutex), + mpTabControl(new TabBarControl(GetAnchorWindow(rxViewTabBarId,rxController), this)), + mxController(rxController), + maTabBarButtons(), + mpTabPage(NULL), + mxViewTabBarId(rxViewTabBarId), + mpViewShellBase(NULL) +{ + // Set one new tab page for all tab entries. We need it only to + // determine the height of the tab bar. + mpTabPage.reset(new TabPage (mpTabControl.get())); + mpTabPage->Hide(); + + // add some space before the tabitems + mpTabControl->SetItemsOffset(Point(5, 3)); + + // Tunnel through the controller and use the ViewShellBase to obtain the + // view frame. + try + { + Reference<lang::XUnoTunnel> xTunnel (mxController, UNO_QUERY_THROW); + DrawController* pController = reinterpret_cast<DrawController*>( + xTunnel->getSomething(DrawController::getUnoTunnelId())); + mpViewShellBase = pController->GetViewShellBase(); + } + catch(RuntimeException&) + {} + + // Register as listener at XConfigurationController. + Reference<XControllerManager> xControllerManager (mxController, UNO_QUERY); + if (xControllerManager.is()) + { + mxConfigurationController = xControllerManager->getConfigurationController(); + if (mxConfigurationController.is()) + { + mxConfigurationController->addConfigurationChangeListener( + this, + FrameworkHelper::msResourceActivationEvent, + Any()); + } + } + + mpTabControl->Show(); + + if (mpViewShellBase != NULL + && rxViewTabBarId->isBoundToURL( + FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)) + { + mpViewShellBase->SetViewTabBar(this); + } +} + + + + +ViewTabBar::~ViewTabBar (void) +{ +} + + + + +void ViewTabBar::disposing (void) +{ + if (mpViewShellBase != NULL + && mxViewTabBarId->isBoundToURL( + FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)) + { + mpViewShellBase->SetViewTabBar(NULL); + } + + if (mxConfigurationController.is()) + { + // Unregister listener from XConfigurationController. + try + { + mxConfigurationController->removeConfigurationChangeListener(this); + } + catch (lang::DisposedException e) + { + // Receiving a disposed exception is the normal case. Is there + // a way to avoid it? + } + mxConfigurationController = NULL; + } + + { + const SolarMutexGuard aSolarGuard; + // Set all references to the one tab page to NULL and delete the page. + for (sal_uInt16 nIndex=0; nIndex<mpTabControl->GetPageCount(); ++nIndex) + mpTabControl->SetTabPage(nIndex, NULL); + mpTabPage.reset(); + mpTabControl.reset(); + } + + mxController = NULL; +} + + + + +::boost::shared_ptr< ::TabControl> ViewTabBar::GetTabControl (void) const +{ + return mpTabControl; +} + + + + +::Window* ViewTabBar::GetAnchorWindow( + const Reference<XResourceId>& rxViewTabBarId, + const Reference<frame::XController>& rxController) +{ + ::Window* pWindow = NULL; + ViewShellBase* pBase = NULL; + + // Tunnel through the controller and use the ViewShellBase to obtain the + // view frame. + try + { + Reference<lang::XUnoTunnel> xTunnel (rxController, UNO_QUERY_THROW); + DrawController* pController = reinterpret_cast<DrawController*>( + xTunnel->getSomething(DrawController::getUnoTunnelId())); + pBase = pController->GetViewShellBase(); + } + catch(RuntimeException&) + {} + + // The ViewTabBar supports at the moment only the center pane. + if (rxViewTabBarId.is() + && rxViewTabBarId->isBoundToURL( + FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)) + { + if (pBase != NULL && pBase->GetViewFrame() != NULL) + pWindow = &pBase->GetViewFrame()->GetWindow(); + } + + // The rest is (at the moment) just for the emergency case. + if (pWindow == NULL) + { + Reference<XPane> xPane; + try + { + Reference<XControllerManager> xControllerManager (rxController, UNO_QUERY_THROW); + Reference<XConfigurationController> xCC ( + xControllerManager->getConfigurationController()); + if (xCC.is()) + xPane = Reference<XPane>(xCC->getResource(rxViewTabBarId->getAnchor()), UNO_QUERY); + } + catch (RuntimeException&) + {} + + // Tunnel through the XWindow to the VCL side. + try + { + Reference<lang::XUnoTunnel> xTunnel (xPane, UNO_QUERY_THROW); + framework::Pane* pPane = reinterpret_cast<framework::Pane*>( + xTunnel->getSomething(framework::Pane::getUnoTunnelId())); + if (pPane != NULL) + pWindow = pPane->GetWindow()->GetParent(); + } + catch (RuntimeException&) + {} + } + + return pWindow; +} + + + + +//----- XConfigurationChangeListener ------------------------------------------ + +void SAL_CALL ViewTabBar::notifyConfigurationChange ( + const ConfigurationChangeEvent& rEvent) + throw (RuntimeException) +{ + if (rEvent.Type.equals(FrameworkHelper::msResourceActivationEvent) + && rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix) + && rEvent.ResourceId->isBoundTo(mxViewTabBarId->getAnchor(), AnchorBindingMode_DIRECT)) + { + UpdateActiveButton(); + } +} + + + + +//----- XEventListener -------------------------------------------------------- + +void SAL_CALL ViewTabBar::disposing( + const lang::EventObject& rEvent) + throw (RuntimeException) +{ + if (rEvent.Source == mxConfigurationController) + { + mxConfigurationController = NULL; + mxController = NULL; + } +} + + + + +//----- XTabBar --------------------------------------------------------------- + +void SAL_CALL ViewTabBar::addTabBarButtonAfter ( + const TabBarButton& rButton, + const TabBarButton& rAnchor) + throw (::com::sun::star::uno::RuntimeException) +{ + const SolarMutexGuard aSolarGuard; + AddTabBarButton(rButton, rAnchor); +} + + + + +void SAL_CALL ViewTabBar::appendTabBarButton (const TabBarButton& rButton) + throw (::com::sun::star::uno::RuntimeException) +{ + const SolarMutexGuard aSolarGuard; + AddTabBarButton(rButton); +} + + + +void SAL_CALL ViewTabBar::removeTabBarButton (const TabBarButton& rButton) + throw (::com::sun::star::uno::RuntimeException) +{ + const SolarMutexGuard aSolarGuard; + RemoveTabBarButton(rButton); +} + + + + +sal_Bool SAL_CALL ViewTabBar::hasTabBarButton (const TabBarButton& rButton) + throw (::com::sun::star::uno::RuntimeException) +{ + const SolarMutexGuard aSolarGuard; + return HasTabBarButton(rButton); +} + + + + +Sequence<TabBarButton> SAL_CALL ViewTabBar::getTabBarButtons (void) + throw (::com::sun::star::uno::RuntimeException) +{ + const SolarMutexGuard aSolarGuard; + return GetTabBarButtons(); +} + + + + +//----- XResource ------------------------------------------------------------- + +Reference<XResourceId> SAL_CALL ViewTabBar::getResourceId (void) + throw (RuntimeException) +{ + return mxViewTabBarId; +} + + + + +sal_Bool SAL_CALL ViewTabBar::isAnchorOnly (void) + throw (RuntimeException) +{ + return false; +} + + + + +//----- XUnoTunnel ------------------------------------------------------------ + +const Sequence<sal_Int8>& ViewTabBar::getUnoTunnelId (void) +{ + static Sequence<sal_Int8>* pSequence = NULL; + if (pSequence == NULL) + { + const SolarMutexGuard aSolarGuard; + if (pSequence == NULL) + { + static ::com::sun::star::uno::Sequence<sal_Int8> aSequence (16); + rtl_createUuid((sal_uInt8*)aSequence.getArray(), 0, sal_True); + pSequence = &aSequence; + } + } + return *pSequence; +} + + + + +sal_Int64 SAL_CALL ViewTabBar::getSomething (const Sequence<sal_Int8>& rId) + throw (RuntimeException) +{ + sal_Int64 nResult = 0; + + if (rId.getLength() == 16 + && rtl_compareMemory(getUnoTunnelId().getConstArray(), rId.getConstArray(), 16) == 0) + { + nResult = reinterpret_cast<sal_Int64>(this); + } + + return nResult; +} + + + + +//----------------------------------------------------------------------------- + +bool ViewTabBar::ActivatePage (void) +{ + try + { + Reference<XControllerManager> xControllerManager (mxController,UNO_QUERY_THROW); + Reference<XConfigurationController> xConfigurationController ( + xControllerManager->getConfigurationController()); + if ( ! xConfigurationController.is()) + throw RuntimeException(); + Reference<XView> xView; + try + { + xView = Reference<XView>(xConfigurationController->getResource( + ResourceId::create( + ::comphelper::getProcessComponentContext(), + FrameworkHelper::msCenterPaneURL)), + UNO_QUERY); + } + catch (DeploymentException) + { + } + + Client* pIPClient = NULL; + if (mpViewShellBase != NULL) + pIPClient = dynamic_cast<Client*>(mpViewShellBase->GetIPClient()); + if (pIPClient==NULL || ! pIPClient->IsObjectInPlaceActive()) + { + sal_uInt16 nIndex (mpTabControl->GetCurPageId() - 1); + if (nIndex < maTabBarButtons.size()) + { + xConfigurationController->requestResourceActivation( + maTabBarButtons[nIndex].ResourceId, + ResourceActivationMode_REPLACE); + } + + return true; + } + else + { + // When we run into this else branch then we have an active OLE + // object. We ignore the request to switch views. Additionally + // we put the active tab back to the one for the current view. + UpdateActiveButton(); + } + } + catch (RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return false; +} + + + + +int ViewTabBar::GetHeight (void) +{ + int nHeight (0); + + if (maTabBarButtons.size() > 0) + { + TabPage* pActivePage (mpTabControl->GetTabPage( + mpTabControl->GetCurPageId())); + if (pActivePage!=NULL && mpTabControl->IsReallyVisible()) + nHeight = pActivePage->GetPosPixel().Y(); + + if (nHeight <= 0) + // Using a default when the real height can not be determined. + // To get correct height this method should be called when the + // control is visible. + nHeight = 21; + } + + return nHeight; +} + + + + +void ViewTabBar::AddTabBarButton ( + const ::com::sun::star::drawing::framework::TabBarButton& rButton, + const ::com::sun::star::drawing::framework::TabBarButton& rAnchor) +{ + sal_uInt32 nIndex; + + if ( ! rAnchor.ResourceId.is() + || (rAnchor.ResourceId->getResourceURL().getLength() == 0 + && rAnchor.ButtonLabel.getLength() == 0)) + { + nIndex = 0; + } + else + { + for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) + { + if (IsEqual(maTabBarButtons[nIndex], rAnchor)) + { + ++nIndex; + break; + } + } + } + + AddTabBarButton(rButton,nIndex); +} + + + + +void ViewTabBar::AddTabBarButton ( + const ::com::sun::star::drawing::framework::TabBarButton& rButton) +{ + AddTabBarButton(rButton, maTabBarButtons.size()); +} + + + + +void ViewTabBar::AddTabBarButton ( + const ::com::sun::star::drawing::framework::TabBarButton& rButton, + sal_Int32 nPosition) +{ + if (nPosition>=0 + && nPosition<=mpTabControl->GetPageCount()) + { + sal_uInt16 nIndex ((sal_uInt16)nPosition); + + // Insert the button into our local array. + maTabBarButtons.insert(maTabBarButtons.begin()+nIndex, rButton); + UpdateTabBarButtons(); + UpdateActiveButton(); + } +} + + + + +void ViewTabBar::RemoveTabBarButton ( + const ::com::sun::star::drawing::framework::TabBarButton& rButton) +{ + sal_uInt16 nIndex; + for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) + { + if (IsEqual(maTabBarButtons[nIndex], rButton)) + { + maTabBarButtons.erase(maTabBarButtons.begin()+nIndex); + UpdateTabBarButtons(); + UpdateActiveButton(); + break; + } + } +} + + + + +bool ViewTabBar::HasTabBarButton ( + const ::com::sun::star::drawing::framework::TabBarButton& rButton) +{ + bool bResult (false); + + for (sal_uInt32 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) + { + if (IsEqual(maTabBarButtons[nIndex], rButton)) + { + bResult = true; + break; + } + } + + return bResult; +} + + + + +::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton> + ViewTabBar::GetTabBarButtons (void) +{ + sal_uInt32 nCount (maTabBarButtons.size()); + ::com::sun::star::uno::Sequence<com::sun::star::drawing::framework::TabBarButton> + aList (nCount); + + for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex) + aList[nIndex] = maTabBarButtons[nIndex]; + + return aList; +} + + + + +void ViewTabBar::UpdateActiveButton (void) +{ + Reference<XView> xView; + if (mpViewShellBase != NULL) + xView = FrameworkHelper::Instance(*mpViewShellBase)->GetView( + mxViewTabBarId->getAnchor()); + if (xView.is()) + { + Reference<XResourceId> xViewId (xView->getResourceId()); + for (sal_uInt16 nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) + { + if (maTabBarButtons[nIndex].ResourceId->compareTo(xViewId) == 0) + { + mpTabControl->SetCurPageId(nIndex+1); + mpTabControl->::TabControl::ActivatePage(); + break; + } + } + } +} + + + + +void ViewTabBar::UpdateTabBarButtons (void) +{ + TabBarButtonList::const_iterator iTab; + sal_uInt16 nPageCount (mpTabControl->GetPageCount()); + sal_uInt16 nIndex; + for (iTab=maTabBarButtons.begin(),nIndex=1; iTab!=maTabBarButtons.end(); ++iTab,++nIndex) + { + // Create a new tab when there are not enough. + if (nPageCount < nIndex) + mpTabControl->InsertPage(nIndex, iTab->ButtonLabel); + + // Update the tab. + mpTabControl->SetPageText(nIndex, iTab->ButtonLabel); + mpTabControl->SetHelpText(nIndex, iTab->HelpText); + mpTabControl->SetTabPage(nIndex, mpTabPage.get()); + } + + // Delete tabs that are no longer used. + for (; nIndex<=nPageCount; ++nIndex) + mpTabControl->RemovePage(nIndex); + + mpTabPage->Hide(); +} + + + + +//===== TabBarControl ========================================================= + +TabBarControl::TabBarControl ( + ::Window* pParentWindow, + const ::rtl::Reference<ViewTabBar>& rpViewTabBar) + : ::TabControl(pParentWindow), + mpViewTabBar(rpViewTabBar) +{ +} + + + + +void TabBarControl::Paint (const Rectangle& rRect) +{ + Color aOriginalFillColor (GetFillColor()); + Color aOriginalLineColor (GetLineColor()); + + // Because the actual window background is transparent--to avoid + // flickering due to multiple background paintings by this and by child + // windows--we have to paint the background for this control explicitly: + // the actual control is not painted over its whole bounding box. + SetFillColor (GetSettings().GetStyleSettings().GetDialogColor()); + SetLineColor (); + DrawRect (rRect); + ::TabControl::Paint (rRect); + + SetFillColor (aOriginalFillColor); + SetLineColor (aOriginalLineColor); +} + + + + +void TabBarControl::ActivatePage (void) +{ + if (mpViewTabBar->ActivatePage()) + { + // Call the parent so that the correct tab is highlighted. + this->::TabControl::ActivatePage(); + } +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |