diff options
Diffstat (limited to 'sfx2/source/sidebar')
68 files changed, 10848 insertions, 0 deletions
diff --git a/sfx2/source/sidebar/AsynchronousCall.cxx b/sfx2/source/sidebar/AsynchronousCall.cxx new file mode 100644 index 000000000000..54f5883622bd --- /dev/null +++ b/sfx2/source/sidebar/AsynchronousCall.cxx @@ -0,0 +1,87 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "AsynchronousCall.hxx" + +#include <vcl/svapp.hxx> + + +namespace sfx2 { namespace sidebar { + +AsynchronousCall::AsynchronousCall (const Action& rAction) + : maAction(rAction), + mnCallId(0) +{ +} + + + + +AsynchronousCall::~AsynchronousCall (void) +{ + CancelRequest(); +} + + + + +void AsynchronousCall::RequestCall (const Action& rAction) +{ + CancelRequest(); + maAction = rAction; + RequestCall(); +} + + + + +void AsynchronousCall::RequestCall (void) +{ + if (mnCallId == 0) + { + Link aLink (LINK(this, AsynchronousCall, HandleUserCall)); + mnCallId = Application::PostUserEvent(aLink); + } +} + + + + +void AsynchronousCall::CancelRequest (void) +{ + if (mnCallId != 0) + { + Application::RemoveUserEvent(mnCallId); + mnCallId = -1; + } +} + + + + +IMPL_LINK(AsynchronousCall, HandleUserCall, void*, EMPTYARG ) +{ + mnCallId = 0; + if (maAction) + maAction(); + + return sal_True; +} + + +} } // end of namespace sfx2::sidebar + diff --git a/sfx2/source/sidebar/AsynchronousCall.hxx b/sfx2/source/sidebar/AsynchronousCall.hxx new file mode 100644 index 000000000000..a1d0e2a883ef --- /dev/null +++ b/sfx2/source/sidebar/AsynchronousCall.hxx @@ -0,0 +1,51 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_ASYNCHRONOUS_CALL_HXX +#define SFX_SIDEBAR_ASYNCHRONOUS_CALL_HXX + +#include <boost/function.hpp> +#include <tools/solar.h> +#include <tools/link.hxx> + +namespace sfx2 { namespace sidebar { + +/** A simple asynchronous call via Application::PostUserCall. +*/ +class AsynchronousCall +{ +public: + typedef ::boost::function<void(void)> Action; + + AsynchronousCall (const Action& rAction); + ~AsynchronousCall (void); + + void RequestCall (const Action& rAction); + void RequestCall (void); + void CancelRequest (void); + +private: + Action maAction; + sal_uLong mnCallId; + + DECL_LINK(HandleUserCall, void*); +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/Context.cxx b/sfx2/source/sidebar/Context.cxx new file mode 100644 index 000000000000..99edf6d82a14 --- /dev/null +++ b/sfx2/source/sidebar/Context.cxx @@ -0,0 +1,116 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "Context.hxx" + +#define AnyApplicationName "any" +#define AnyContextName "any" + +namespace sfx2 { namespace sidebar { + +const sal_Int32 Context::NoMatch = 4; +const sal_Int32 Context::ApplicationWildcardMatch = 1; +const sal_Int32 Context::ContextWildcardMatch = 2; +const sal_Int32 Context::OptimalMatch = 0; // Neither application nor context name is "any". + +#define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString))) + +Context::Context (void) + : msApplication(A2S(AnyApplicationName)), + msContext(A2S(AnyContextName)) +{ +} + + + + +Context::Context ( + const ::rtl::OUString& rsApplication, + const ::rtl::OUString& rsContext) + : msApplication(rsApplication), + msContext(rsContext) +{ +} + + + + +sal_Int32 Context::EvaluateMatch ( + const Context& rOther) const +{ + const bool bApplicationNameIsAny (rOther.msApplication.equalsAscii(AnyApplicationName)); + if (rOther.msApplication.equals(msApplication) || bApplicationNameIsAny) + { + // Application name matches. + const bool bContextNameIsAny (rOther.msContext.equalsAscii(AnyContextName)); + if (rOther.msContext.equals(msContext) || bContextNameIsAny) + { + // Context name matches. + return (bApplicationNameIsAny ? ApplicationWildcardMatch : 0) + + (bContextNameIsAny ? ContextWildcardMatch : 0); + } + } + return NoMatch; +} + + + + +sal_Int32 Context::EvaluateMatch (const ::std::vector<Context>& rOthers) const +{ + sal_Int32 nBestMatch (NoMatch); + + for (::std::vector<Context>::const_iterator + iContext(rOthers.begin()), + iEnd(rOthers.end()); + iContext!=iEnd; + ++iContext) + { + const sal_Int32 nMatch (EvaluateMatch(*iContext)); + if (nMatch < nBestMatch) + { + if (nMatch == OptimalMatch) + { + // We will find no better match so stop searching. + return OptimalMatch; + } + nBestMatch = nMatch; + } + } + return nBestMatch; +} + + + + +bool Context::operator== (const Context& rOther) const +{ + return msApplication.equals(rOther.msApplication) + && msContext.equals(rOther.msContext); +} + + + + +bool Context::operator!= (const Context& rOther) const +{ + return ( ! msApplication.equals(rOther.msApplication)) + || ( ! msContext.equals(rOther.msContext)); +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/Context.hxx b/sfx2/source/sidebar/Context.hxx new file mode 100644 index 000000000000..df6fa631e64a --- /dev/null +++ b/sfx2/source/sidebar/Context.hxx @@ -0,0 +1,65 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_CONTEXT_HXX +#define SFX_SIDEBAR_CONTEXT_HXX + +#include "rtl/ustring.hxx" + +#include <vector> + +namespace sfx2 { namespace sidebar { + +class Context +{ +public: + ::rtl::OUString msApplication; + ::rtl::OUString msContext; + + Context (void); + Context ( + const ::rtl::OUString& rsApplication, + const ::rtl::OUString& rsContext); + + /** When two contexts are matched against each other then + application or context name may have the wildcard value 'any'. + In order to prefer matches without wildcards over matches with + wildcards we introduce a integer evaluation for matches. + */ + const static sal_Int32 NoMatch; + const static sal_Int32 OptimalMatch; + const static sal_Int32 ApplicationWildcardMatch; + const static sal_Int32 ContextWildcardMatch; + + /** Return the numeric value that describes how good the match + between two contexts is. + Smaller values represent better matches. + */ + sal_Int32 EvaluateMatch (const Context& rOther) const; + + /** Return the best match against the given list of contexts. + */ + sal_Int32 EvaluateMatch (const ::std::vector<Context>& rOthers) const; + + bool operator== (const Context& rOther) const; + bool operator!= (const Context& rOther) const; +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/ContextChangeBroadcaster.cxx b/sfx2/source/sidebar/ContextChangeBroadcaster.cxx new file mode 100644 index 000000000000..463d1512df9a --- /dev/null +++ b/sfx2/source/sidebar/ContextChangeBroadcaster.cxx @@ -0,0 +1,134 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "sfx2/sidebar/ContextChangeBroadcaster.hxx" +#include "sfx2/sidebar/EnumContext.hxx" +#include <com/sun/star/ui/ContextChangeEventObject.hpp> +#include <com/sun/star/ui/ContextChangeEventMultiplexer.hpp> +#include <com/sun/star/frame/XModuleManager.hpp> +#include <comphelper/componentcontext.hxx> +#include <comphelper/processfactory.hxx> + + +using ::rtl::OUString; +using namespace css; +using namespace cssu; + +namespace sfx2 { namespace sidebar { + + +ContextChangeBroadcaster::ContextChangeBroadcaster (void) + : msContextName(), + mbIsContextActive(false) +{ +} + + + +ContextChangeBroadcaster::~ContextChangeBroadcaster (void) +{ +} + + + + +void ContextChangeBroadcaster::Initialize (const ::rtl::OUString& rsContextName) +{ + OSL_ASSERT( ! mbIsContextActive); + + msContextName = rsContextName; +} + + + + +void ContextChangeBroadcaster::Activate (const cssu::Reference<css::frame::XFrame>& rxFrame) +{ + if (msContextName.getLength() > 0) + BroadcastContextChange(rxFrame, GetModuleName(rxFrame), msContextName); +} + + + + +void ContextChangeBroadcaster::Deactivate (const cssu::Reference<css::frame::XFrame>& rxFrame) +{ + if (msContextName.getLength() > 0) + { + BroadcastContextChange( + rxFrame, + GetModuleName(rxFrame), + EnumContext::GetContextName(EnumContext::Context_Default)); + } +} + + + + +void ContextChangeBroadcaster::BroadcastContextChange ( + const cssu::Reference<css::frame::XFrame>& rxFrame, + const ::rtl::OUString& rsModuleName, + const ::rtl::OUString& rsContextName) +{ + if (rsContextName.getLength() == 0) + return; + + if ( ! rxFrame.is() || ! rxFrame->getController().is()) + { + // Frame is (probably) being deleted. Broadcasting context + // changes is not necessary anymore. + return; + } + + const css::ui::ContextChangeEventObject aEvent( + rxFrame->getController(), + rsModuleName, + rsContextName); + + cssu::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer ( + css::ui::ContextChangeEventMultiplexer::get( + ::comphelper::getProcessComponentContext())); + if (xMultiplexer.is()) + xMultiplexer->broadcastContextChangeEvent(aEvent, rxFrame->getController()); +} + + + + +OUString ContextChangeBroadcaster::GetModuleName (const cssu::Reference<css::frame::XFrame>& rxFrame) +{ + if ( ! rxFrame.is() || ! rxFrame->getController().is()) + return OUString(); + OUString sModuleName; + try + { + const ::comphelper::ComponentContext aContext (::comphelper::getProcessServiceFactory()); + const Reference<frame::XModuleManager> xModuleManager ( + aContext.createComponent("com.sun.star.frame.ModuleManager" ), + UNO_QUERY_THROW ); + return xModuleManager->identify(rxFrame); + } + catch (const Exception&) + { + OSL_ENSURE(false, "can not determine module name"); + } + return OUString(); +} + + + +} } // end of namespace ::sd::sidebar diff --git a/sfx2/source/sidebar/ContextList.cxx b/sfx2/source/sidebar/ContextList.cxx new file mode 100644 index 000000000000..aebfdbd1897d --- /dev/null +++ b/sfx2/source/sidebar/ContextList.cxx @@ -0,0 +1,100 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "ContextList.hxx" +#include "Context.hxx" + +using ::rtl::OUString; + +namespace sfx2 { namespace sidebar { + + +ContextList::ContextList (void) + : maEntries() +{ +} + + + + +ContextList::~ContextList (void) +{ +} + + + + +const ContextList::Entry* ContextList::GetMatch (const Context& rContext) const +{ + const ::std::vector<Entry>::const_iterator iEntry = FindBestMatch(rContext); + if (iEntry != maEntries.end()) + return &*iEntry; + else + return NULL; +} + + + + +::std::vector<ContextList::Entry>::const_iterator ContextList::FindBestMatch (const Context& rContext) const +{ + sal_Int32 nBestMatch (Context::NoMatch); + ::std::vector<Entry>::const_iterator iBestMatch (maEntries.end()); + + for (::std::vector<Entry>::const_iterator + iEntry(maEntries.begin()), + iEnd(maEntries.end()); + iEntry!=iEnd; + ++iEntry) + { + const sal_Int32 nMatch (rContext.EvaluateMatch(iEntry->maContext)); + if (nMatch < nBestMatch) + { + nBestMatch = nMatch; + iBestMatch = iEntry; + } + if (nBestMatch == Context::OptimalMatch) + return iEntry; + } + + return iBestMatch; +} + + + + +void ContextList::AddContextDescription ( + const Context& rContext, + const bool bIsInitiallyVisible, + const OUString& rsMenuCommand) +{ + maEntries.push_back(Entry()); + maEntries.back().maContext = rContext; + maEntries.back().mbIsInitiallyVisible = bIsInitiallyVisible; + maEntries.back().msMenuCommand = rsMenuCommand; +} + + + + +bool ContextList::IsEmpty (void) +{ + return maEntries.empty(); +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/ContextList.hxx b/sfx2/source/sidebar/ContextList.hxx new file mode 100644 index 000000000000..f026ff9d3305 --- /dev/null +++ b/sfx2/source/sidebar/ContextList.hxx @@ -0,0 +1,69 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_CONTEXT_LIST_HXX +#define SFX_SIDEBAR_CONTEXT_LIST_HXX + +#include "Context.hxx" +#include <sal/types.h> +#include <rtl/ustring.hxx> + +#include <vector> + + +namespace sfx2 { namespace sidebar { + + +class ContextList +{ +public: + ContextList (void); + ~ContextList (void); + + class Entry + { + public: + Context maContext; + bool mbIsInitiallyVisible; + ::rtl::OUString msMenuCommand; + }; + + /** Return <TRUE/> when the given context matches any of the stored contexts. + */ + const Entry* GetMatch ( + const Context& rContext) const; + + void AddContextDescription ( + const Context& rContext, + const bool bIsInitiallyVisible, + const ::rtl::OUString& rsMenuCommand); + + /** Returns <TRUE/> when no call to AddContextDescription() was made before. + */ + bool IsEmpty (void); + + +private: + ::std::vector<Entry> maEntries; + + ::std::vector<Entry>::const_iterator FindBestMatch (const Context& rContext) const; +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/ContextMatcher.cxx b/sfx2/source/sidebar/ContextMatcher.cxx new file mode 100644 index 000000000000..9de3567d8da1 --- /dev/null +++ b/sfx2/source/sidebar/ContextMatcher.cxx @@ -0,0 +1,136 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "precompiled_sfx2.hxx" + +#include "ContextMatcher.hxx" +#include "Context.hxx" + +using ::rtl::OUString; + +namespace sfx2 { namespace sidebar { + +namespace { + static const sal_Char* gsAny = "any"; +} + + + +ContextMatcher::ContextMatcher (void) + : maEntries() +{ +} + + + + +ContextMatcher::~ContextMatcher (void) +{ +} + + + + +sal_Int32 ContextMatcher::EvaluateMatch ( + const Context& rContext) const +{ + sal_Int32 nBestMatch (Context::NoMatch); + + for (::std::vector<Entry>::const_iterator + iEntry(maEntries.begin()), + iEnd(maEntries.end()); + iEntry!=iEnd; + ++iEntry) + { + const sal_Int32 nMatch (EvaluateMatch(rContext, *iEntry)); + if (nMatch < nBestMatch) + nBestMatch = nMatch; + if (nBestMatch == Context::OptimalMatch) + break; + } + + return nBestMatch; +} + + + + +sal_Int32 ContextMatcher::EvaluateMatch ( + const Context& rContext, + const Entry& rEntry) const +{ + sal_Int32 nApplicationMatch (Context::NoMatch); + if (rContext.msApplication.equals(rEntry.msApplicationName)) + nApplicationMatch = 0; + else if (rEntry.msApplicationName.equalsAscii(gsAny)) + nApplicationMatch = Context::ApplicationWildcardMatch; + else + return Context::NoMatch; + + sal_Int32 nBestContextMatch (Context::NoMatch); + for (::std::vector<OUString>::const_iterator + iContext(rEntry.maContextNames.begin()), + iEnd(rEntry.maContextNames.end()); + iContext!=iEnd; + ++iContext) + { + sal_Int32 nContextMatch (Context::NoMatch); + if (rContext.msContext.equals(*iContext)) + nContextMatch = 0; + else if (iContext->equalsAscii(gsAny)) + nContextMatch = Context::ContextWildcardMatch; + else + continue; + if (nContextMatch < nBestContextMatch) + nBestContextMatch = nContextMatch; + } + + if (rEntry.mbIsContextListNegated) + nBestContextMatch = Context::NoMatch - nBestContextMatch; + + return nApplicationMatch + nBestContextMatch; +} + + + + +void ContextMatcher::AddMatcher ( + const ::rtl::OUString& rsApplicationName, + const ::std::vector<rtl::OUString>& rContextNames, + const bool bIsContextListNegated) +{ + maEntries.push_back(Entry()); + maEntries.back().msApplicationName = rsApplicationName; + maEntries.back().maContextNames = rContextNames; + maEntries.back().mbIsContextListNegated = bIsContextListNegated; +} + + + + +void ContextMatcher::AddMatcher ( + const ::rtl::OUString& rsApplicationName, + const ::rtl::OUString& rsContextName) +{ + maEntries.push_back(Entry()); + maEntries.back().msApplicationName = rsApplicationName; + maEntries.back().maContextNames.push_back(rsContextName); + maEntries.back().mbIsContextListNegated = false; +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/ContextMatcher.hxx b/sfx2/source/sidebar/ContextMatcher.hxx new file mode 100644 index 000000000000..f34c078702bf --- /dev/null +++ b/sfx2/source/sidebar/ContextMatcher.hxx @@ -0,0 +1,71 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_CONTEXT_MATCHER_HXX +#define SFX_SIDEBAR_CONTEXT_MATCHER_HXX + +#include <sal/types.h> +#include <rtl/ustring.hxx> + +#include <vector> + + +namespace sfx2 { namespace sidebar { + +class Context; + + +/** Data read from the configuration for matching contexts. +*/ +class ContextMatcher +{ +public: + ContextMatcher (void); + ~ContextMatcher (void); + + sal_Int32 EvaluateMatch ( + const Context& rContext) const; + + void AddMatcher ( + const ::rtl::OUString& rsApplicationName, + const ::std::vector<rtl::OUString>& rContextNames, + const bool mbIsContextListNegated); + void AddMatcher ( + const ::rtl::OUString& rsApplicationName, + const ::rtl::OUString& rsContextName); + +private: + class Entry + { + public: + ::rtl::OUString msApplicationName; + ::std::vector<rtl::OUString> maContextNames; + bool mbIsContextListNegated; + }; + ::std::vector<Entry> maEntries; + + sal_Int32 EvaluateMatch ( + const Context& rContext, + const Entry& rEntry) const; + +}; +static bool IsMatchBetterThan (const sal_Int32 nMatchA, const sal_Int32 nMatchB); + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/ControlFactory.cxx b/sfx2/source/sidebar/ControlFactory.cxx new file mode 100644 index 000000000000..43946e0cd061 --- /dev/null +++ b/sfx2/source/sidebar/ControlFactory.cxx @@ -0,0 +1,82 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "sidebar/ControlFactory.hxx" + +#include "MenuButton.hxx" +#include "TabItem.hxx" +#include "SidebarToolBox.hxx" +#include "ToolBoxBackground.hxx" +#include "CustomImageRadioButton.hxx" +#include <vcl/toolbox.hxx> + + +namespace sfx2 { namespace sidebar { + + +CheckBox* ControlFactory::CreateMenuButton (Window* pParentWindow) +{ + return new MenuButton(pParentWindow); +} + + + + +ImageRadioButton* ControlFactory::CreateTabItem (Window* pParentWindow) +{ + return new TabItem(pParentWindow); +} + + + + +ToolBox* ControlFactory::CreateToolBox ( + Window* pParentWindow, + const ResId& rResId) +{ + SidebarToolBox* pToolBox = new SidebarToolBox(pParentWindow, rResId); + pToolBox->SetBorderWindow(pParentWindow); + + pToolBox->Invalidate(); + + return pToolBox; +} + + + + +Window* ControlFactory::CreateToolBoxBackground ( + Window* pParentWindow) +{ + ToolBoxBackground* pBorderWindow = new ToolBoxBackground(pParentWindow); + pBorderWindow->Show(); + return pBorderWindow; +} + + + + +ImageRadioButton* ControlFactory::CreateCustomImageRadionButton( + Window* pParentWindow, + const ResId& rResId ) +{ + return new CustomImageRadioButton( + pParentWindow, + rResId ); +} + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/ControllerItem.cxx b/sfx2/source/sidebar/ControllerItem.cxx new file mode 100644 index 000000000000..e00241250227 --- /dev/null +++ b/sfx2/source/sidebar/ControllerItem.cxx @@ -0,0 +1,54 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "sidebar/ControllerItem.hxx" + +namespace sfx2 { namespace sidebar { + +ControllerItem::ControllerItem ( + const sal_uInt16 nInId, + SfxBindings &rBindings, + ItemUpdateReceiverInterface& rItemUpdateReceiver) + : SfxControllerItem(nInId, rBindings), + mrItemUpdateReceiver(rItemUpdateReceiver) +{ +} + + + + +ControllerItem::~ControllerItem (void) +{ +} + + + + +void ControllerItem::StateChanged ( + sal_uInt16 nSID, + SfxItemState eState, + const SfxPoolItem* pState) +{ + mrItemUpdateReceiver.NotifyItemUpdate(nSID, eState, pState); +} + +ControllerItem::ItemUpdateReceiverInterface::~ItemUpdateReceiverInterface() +{ +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/CustomImageRadioButton.cxx b/sfx2/source/sidebar/CustomImageRadioButton.cxx new file mode 100644 index 000000000000..adc0eed9cc97 --- /dev/null +++ b/sfx2/source/sidebar/CustomImageRadioButton.cxx @@ -0,0 +1,74 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "CustomImageRadioButton.hxx" + +#include "DrawHelper.hxx" +#include "Paint.hxx" +#include "Tools.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +namespace sfx2 { namespace sidebar { + + +CustomImageRadioButton::CustomImageRadioButton ( + Window* pParentWindow, + const ResId& rResId ) + : ImageRadioButton( pParentWindow, rResId ) +{ + SetStyle( GetStyle() | WB_NOPOINTERFOCUS ); +} + + +CustomImageRadioButton::~CustomImageRadioButton (void) +{ +} + + +void CustomImageRadioButton::Paint (const Rectangle& /*rUpdateArea*/) +{ + Rectangle aPaintRect( Rectangle(Point(0,0), GetSizePixel() ) ); + SetMouseRect( aPaintRect ); + SetStateRect( aPaintRect ); + + const Theme::ThemeItem eBackground = + IsMouseOver() + ? Theme::Paint_TabItemBackgroundHighlight + : Theme::Paint_PanelBackground; + DrawHelper::DrawRoundedRectangle( + *this, + aPaintRect, + Theme::GetInteger(Theme::Int_ButtonCornerRadius), + IsChecked() || IsMouseOver() ? Theme::GetColor(Theme::Color_TabItemBorder) : Color(0xffffffff), + Theme::GetPaint( eBackground ) ); + + const Image& rIcon = GetModeRadioImage(); + const Size aIconSize (rIcon.GetSizePixel()); + const Point aIconLocation( + (GetSizePixel().Width() - aIconSize.Width())/2, + (GetSizePixel().Height() - aIconSize.Height())/2 ); + DrawImage( + aIconLocation, + rIcon, + IsEnabled() ? 0 : IMAGE_DRAW_DISABLE ); +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/CustomImageRadioButton.hxx b/sfx2/source/sidebar/CustomImageRadioButton.hxx new file mode 100644 index 000000000000..a0e9614610f2 --- /dev/null +++ b/sfx2/source/sidebar/CustomImageRadioButton.hxx @@ -0,0 +1,45 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_CUSTOM_IMAGE_RADIO_BUTTON_HXX +#define SFX_SIDEBAR_CUSTOM_IMAGE_RADIO_BUTTON_HXX + +#include "vcl/button.hxx" + +#include "sfx2/sidebar/Theme.hxx" + +namespace sfx2 { namespace sidebar { + +/** A custom image radion button with more control over used colors for sidebar +*/ +class CustomImageRadioButton + : public ImageRadioButton +{ +public: + CustomImageRadioButton( + Window* pParentWindow, + const ResId& rResId ); + + virtual ~CustomImageRadioButton(void); + + virtual void Paint( const Rectangle& rUpdateArea ); +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/Deck.cxx b/sfx2/source/sidebar/Deck.cxx new file mode 100644 index 000000000000..a1f32ebed59b --- /dev/null +++ b/sfx2/source/sidebar/Deck.cxx @@ -0,0 +1,384 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "Deck.hxx" +#include "DeckDescriptor.hxx" +#include "DeckLayouter.hxx" +#include "DrawHelper.hxx" +#include "DeckTitleBar.hxx" +#include "Paint.hxx" +#include "Panel.hxx" +#include "ToolBoxBackground.hxx" +#include "Tools.hxx" +#include "sfx2/sidebar/Theme.hxx" + +#include <vcl/dockwin.hxx> +#include <vcl/scrbar.hxx> +#include <tools/svborder.hxx> + +#include <boost/bind.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +namespace sfx2 { namespace sidebar { + + +namespace { + static const sal_Int32 MinimalPanelHeight (25); +} + + +Deck::Deck ( + const DeckDescriptor& rDeckDescriptor, + Window* pParentWindow, + const ::boost::function<void(void)>& rCloserAction) + : Window(pParentWindow, 0), + msId(rDeckDescriptor.msId), + maIcon(), + msIconURL(rDeckDescriptor.msIconURL), + msHighContrastIconURL(rDeckDescriptor.msHighContrastIconURL), + maPanels(), + mpTitleBar(new DeckTitleBar(rDeckDescriptor.msTitle, this, rCloserAction)), + mpScrollClipWindow(new Window(this)), + mpScrollContainer(new ScrollContainerWindow(mpScrollClipWindow.get())), + mpFiller(new Window(this)), + mpVerticalScrollBar(new ScrollBar(this)) +{ + SetBackground(Wallpaper()); + + mpScrollClipWindow->SetBackground(Wallpaper()); + mpScrollClipWindow->Show(); + + mpScrollContainer->SetStyle(mpScrollContainer->GetStyle() | WB_DIALOGCONTROL); + mpScrollContainer->SetBackground(Wallpaper()); + mpScrollContainer->Show(); + + mpVerticalScrollBar->SetScrollHdl(LINK(this, Deck, HandleVerticalScrollBarChange)); + +#ifdef DEBUG + SetText(A2S("Deck")); + mpScrollClipWindow->SetText(A2S("ScrollClipWindow")); + mpFiller->SetText(A2S("Filler")); + mpVerticalScrollBar->SetText(A2S("VerticalScrollBar")); +#endif +} + + + + +Deck::~Deck (void) +{ + Dispose(); + + // We have to explicitly trigger the destruction of panels. + // Otherwise that is done by one of our base class destructors + // without updating maPanels. + maPanels.clear(); +} + + + + +void Deck::Dispose (void) +{ + SharedPanelContainer aPanels; + aPanels.swap(maPanels); + for (SharedPanelContainer::iterator + iPanel(aPanels.begin()), + iEnd(aPanels.end()); + iPanel!=iEnd; + ++iPanel) + { + if (*iPanel) + { + (*iPanel)->Dispose(); + OSL_ASSERT(iPanel->unique()); + iPanel->reset(); + } + } + + mpTitleBar.reset(); + mpFiller.reset(); + mpVerticalScrollBar.reset(); +} + + + + +const ::rtl::OUString& Deck::GetId (void) const +{ + return msId; +} + + + + +DeckTitleBar* Deck::GetTitleBar (void) const +{ + return mpTitleBar.get(); +} + + + + +Rectangle Deck::GetContentArea (void) const +{ + const Size aWindowSize (GetSizePixel()); + const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize)); + + return Rectangle( + Theme::GetInteger(Theme::Int_DeckLeftPadding) + nBorderSize, + Theme::GetInteger(Theme::Int_DeckTopPadding) + nBorderSize, + aWindowSize.Width() - 1 - Theme::GetInteger(Theme::Int_DeckRightPadding) - nBorderSize, + aWindowSize.Height() - 1 - Theme::GetInteger(Theme::Int_DeckBottomPadding) - nBorderSize); +} + + + + +::rtl::OUString Deck::GetIconURL (const bool bIsHighContrastModeActive) const +{ + if (bIsHighContrastModeActive) + return msHighContrastIconURL; + else + return msIconURL; +} + + + + +void Deck::Paint (const Rectangle& rUpdateArea) +{ + (void) rUpdateArea; + + const Size aWindowSize (GetSizePixel()); + const SvBorder aPadding ( + Theme::GetInteger(Theme::Int_DeckLeftPadding), + Theme::GetInteger(Theme::Int_DeckTopPadding), + Theme::GetInteger(Theme::Int_DeckRightPadding), + Theme::GetInteger(Theme::Int_DeckBottomPadding)); + + // Paint deck background outside the border. + Rectangle aBox( + 0, + 0, + aWindowSize.Width() - 1, + aWindowSize.Height() - 1); + DrawHelper::DrawBorder( + *this, + aBox, + aPadding, + Theme::GetPaint(Theme::Paint_DeckBackground), + Theme::GetPaint(Theme::Paint_DeckBackground)); + + // Paint the border. + const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize)); + aBox.Left() += aPadding.Left(); + aBox.Top() += aPadding.Top(); + aBox.Right() -= aPadding.Right(); + aBox.Bottom() -= aPadding.Bottom(); + const sfx2::sidebar::Paint& rHorizontalBorderPaint (Theme::GetPaint(Theme::Paint_HorizontalBorder)); + DrawHelper::DrawBorder( + *this, + aBox, + SvBorder(nBorderSize, nBorderSize, nBorderSize, nBorderSize), + rHorizontalBorderPaint, + Theme::GetPaint(Theme::Paint_VerticalBorder)); +} + + + + +void Deck::DataChanged (const DataChangedEvent& rEvent) +{ + (void)rEvent; + RequestLayout(); +} + + + + +void Deck::SetPanels (const SharedPanelContainer& rPanels) +{ + maPanels = rPanels; + + RequestLayout(); +} + + + + +const SharedPanelContainer& Deck::GetPanels (void) const +{ + return maPanels; +} + + + + +void Deck::RequestLayout (void) +{ + // PrintWindowTree(); + + DeckLayouter::LayoutDeck( + GetContentArea(), + maPanels, + *GetTitleBar(), + *mpScrollClipWindow, + *mpScrollContainer, + *mpFiller, + *mpVerticalScrollBar); + + Invalidate(); +} + + + + +::Window* Deck::GetPanelParentWindow (void) +{ + return mpScrollContainer.get(); +} + + + + +const char* GetWindowClassification (const Window* pWindow) +{ + const String& rsName (pWindow->GetText()); + if (rsName.Len() > 0) + { + return ::rtl::OUStringToOString(rsName, RTL_TEXTENCODING_ASCII_US).getStr(); + } + else + { + static char msWindow[] = "window"; + return msWindow; + } +} + + +void Deck::PrintWindowSubTree (Window* pRoot, int nIndentation) +{ + static const char* sIndentation = " "; + const Point aLocation (pRoot->GetPosPixel()); + const Size aSize (pRoot->GetSizePixel()); + const char* sClassification = GetWindowClassification(pRoot); + const char* sVisible = pRoot->IsVisible() ? "visible" : "hidden"; + OSL_TRACE("%s%x %s %s +%d+%d x%dx%d", + sIndentation+strlen(sIndentation)-nIndentation*4, + pRoot, + sClassification, + sVisible, + aLocation.X(),aLocation.Y(), + aSize.Width(),aSize.Height()); + + const sal_uInt16 nChildCount (pRoot->GetChildCount()); + for (sal_uInt16 nIndex=0; nIndex<nChildCount; ++nIndex) + PrintWindowSubTree(pRoot->GetChild(nIndex), nIndentation+1); +} + + + + +void Deck::PrintWindowTree (void) +{ + PrintWindowSubTree(this, 0); +} + + + + +void Deck::PrintWindowTree (const ::std::vector<Panel*>& rPanels) +{ + (void)rPanels; + + PrintWindowTree(); +} + + + + +IMPL_LINK(Deck, HandleVerticalScrollBarChange,void*, EMPTYARG) +{ + const sal_Int32 nYOffset (-mpVerticalScrollBar->GetThumbPos()); + mpScrollContainer->SetPosPixel( + Point( + mpScrollContainer->GetPosPixel().X(), + nYOffset)); + return sal_True; +} + + + + +//----- Deck::ScrollContainerWindow ------------------------------------------- + +Deck::ScrollContainerWindow::ScrollContainerWindow (Window* pParentWindow) + : Window(pParentWindow), + maSeparators() +{ +#ifdef DEBUG + SetText(A2S("ScrollContainerWindow")); +#endif +} + + + + +Deck::ScrollContainerWindow::~ScrollContainerWindow (void) +{ +} + + + + +void Deck::ScrollContainerWindow::Paint (const Rectangle& rUpdateArea) +{ + (void)rUpdateArea; + + // Paint the separators. + const sal_Int32 nSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight)); + const sal_Int32 nLeft (0); + const sal_Int32 nRight (GetSizePixel().Width()-1); + const sfx2::sidebar::Paint& rHorizontalBorderPaint (Theme::GetPaint(Theme::Paint_HorizontalBorder)); + for (::std::vector<sal_Int32>::const_iterator iY(maSeparators.begin()), iEnd(maSeparators.end()); + iY!=iEnd; + ++iY) + { + DrawHelper::DrawHorizontalLine( + *this, + nLeft, + nRight, + *iY, + nSeparatorHeight, + rHorizontalBorderPaint); + } +} + + + + +void Deck::ScrollContainerWindow::SetSeparators (const ::std::vector<sal_Int32>& rSeparators) +{ + maSeparators = rSeparators; +} + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/Deck.hxx b/sfx2/source/sidebar/Deck.hxx new file mode 100644 index 000000000000..ae1cf196ad42 --- /dev/null +++ b/sfx2/source/sidebar/Deck.hxx @@ -0,0 +1,101 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_DECK_HXX +#define SFX_SIDEBAR_DECK_HXX + +#include "Panel.hxx" + +#include <vcl/window.hxx> +#include <vcl/image.hxx> +#include <com/sun/star/ui/LayoutSize.hpp> + +#include <boost/function.hpp> +#include <boost/scoped_ptr.hpp> + +class ScrollBar; + +namespace css = ::com::sun::star; + +namespace sfx2 { namespace sidebar { + +class DeckDescriptor; +class DeckTitleBar; + + +/** This is the parent window of the panels. + It displays the deck title. +*/ +class Deck + : public Window +{ +public: + Deck ( + const DeckDescriptor& rDeckDescriptor, + Window* pParentWindow, + const ::boost::function<void(void)>& rCloserAction); + virtual ~Deck (void); + + void Dispose (void); + + const ::rtl::OUString& GetId (void) const; + DeckTitleBar* GetTitleBar (void) const; + Rectangle GetContentArea (void) const; + ::rtl::OUString GetIconURL (const bool bIsHighContrastModeActive) const; + void SetPanels (const SharedPanelContainer& rPanels); + const SharedPanelContainer& GetPanels (void) const; + void RequestLayout (void); + ::Window* GetPanelParentWindow (void); + + virtual void Paint (const Rectangle& rUpdateArea); + virtual void DataChanged (const DataChangedEvent& rEvent); + + void PrintWindowTree (void); + void PrintWindowTree (const ::std::vector<Panel*>& rPanels); + static void PrintWindowSubTree (Window* pRoot, int nIndentation); + + class ScrollContainerWindow : public Window + { + public: + ScrollContainerWindow (Window* pParentWindow); + virtual ~ScrollContainerWindow (void); + virtual void Paint (const Rectangle& rUpdateArea); + void SetSeparators (const ::std::vector<sal_Int32>& rSeparators); + private: + ::std::vector<sal_Int32> maSeparators; + }; + +private: + const ::rtl::OUString msTitle; + const ::rtl::OUString msId; + Image maIcon; + const ::rtl::OUString msIconURL; + const ::rtl::OUString msHighContrastIconURL; + SharedPanelContainer maPanels; + ::boost::scoped_ptr<DeckTitleBar> mpTitleBar; + ::boost::scoped_ptr<Window> mpScrollClipWindow; + ::boost::scoped_ptr<ScrollContainerWindow> mpScrollContainer; + ::boost::scoped_ptr<Window> mpFiller; + ::boost::scoped_ptr<ScrollBar> mpVerticalScrollBar; + + DECL_LINK(HandleVerticalScrollBarChange,void*); +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/DeckConfiguration.cxx b/sfx2/source/sidebar/DeckConfiguration.cxx new file mode 100644 index 000000000000..7e87e04b0897 --- /dev/null +++ b/sfx2/source/sidebar/DeckConfiguration.cxx @@ -0,0 +1,51 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "precompiled_sfx2.hxx" + +#include "DeckConfiguration.hxx" +#include "Deck.hxx" + + +namespace sfx2 { namespace sidebar { + +DeckConfiguration::DeckConfiguration (void) + : mpDeck(NULL), + maPanels() +{ +} + + + + +void DeckConfiguration::Dispose (void) +{ + if (mpDeck != NULL) + { + mpDeck->Dispose(); + + Deck* pDeck = mpDeck; + mpDeck = NULL; + OSL_TRACE("deleting deck window subtree"); + pDeck->PrintWindowTree(); + delete pDeck; + } +} + + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/DeckConfiguration.hxx b/sfx2/source/sidebar/DeckConfiguration.hxx new file mode 100644 index 000000000000..8b118cbd6a37 --- /dev/null +++ b/sfx2/source/sidebar/DeckConfiguration.hxx @@ -0,0 +1,45 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_DECK_CONFIGURATION_HXX +#define SFX_SIDEBAR_DECK_CONFIGURATION_HXX + +#include <vector> + +namespace sfx2 { namespace sidebar { + +class Deck; +class Panel; + + +class DeckConfiguration +{ +public: + Deck* mpDeck; + ::std::vector<Panel*> maPanels; + + DeckConfiguration (void); + + void Dispose (void); +}; + + + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/DeckDescriptor.cxx b/sfx2/source/sidebar/DeckDescriptor.cxx new file mode 100644 index 000000000000..be0c77d088a3 --- /dev/null +++ b/sfx2/source/sidebar/DeckDescriptor.cxx @@ -0,0 +1,57 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DeckDescriptor.hxx" + +namespace sfx2 { namespace sidebar { + +DeckDescriptor::DeckDescriptor (void) + : msTitle(), + msId(), + msIconURL(), + msHighContrastIconURL(), + msHelpURL(), + msHelpText(), + maContextList(), + mnOrderIndex(10000) // Default value as defined in Sidebar.xcs +{ +} + + + + +DeckDescriptor::DeckDescriptor (const DeckDescriptor& rOther) + : msTitle(rOther.msTitle), + msId(rOther.msId), + msIconURL(rOther.msIconURL), + msHighContrastIconURL(rOther.msHighContrastIconURL), + msHelpURL(rOther.msHelpURL), + msHelpText(rOther.msHelpText), + maContextList(rOther.maContextList), + mnOrderIndex(rOther.mnOrderIndex) +{ +} + + + + +DeckDescriptor::~DeckDescriptor (void) +{ +} + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/DeckDescriptor.hxx b/sfx2/source/sidebar/DeckDescriptor.hxx new file mode 100644 index 000000000000..2c5a3d481f65 --- /dev/null +++ b/sfx2/source/sidebar/DeckDescriptor.hxx @@ -0,0 +1,49 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_DECK_DESCRIPTOR_HXX +#define SFX_SIDEBAR_DECK_DESCRIPTOR_HXX + +#include "sfx2/sidebar/EnumContext.hxx" +#include "ContextList.hxx" +#include <boost/shared_ptr.hpp> + + +namespace sfx2 { namespace sidebar { + +class DeckDescriptor +{ +public: + ::rtl::OUString msTitle; + ::rtl::OUString msId; + ::rtl::OUString msIconURL; + ::rtl::OUString msHighContrastIconURL; + ::rtl::OUString msHelpURL; + ::rtl::OUString msHelpText; + ContextList maContextList; + bool mbIsEnabled; + sal_Int32 mnOrderIndex; + + DeckDescriptor (void); + DeckDescriptor (const DeckDescriptor& rOther); + ~DeckDescriptor (void); +}; +typedef ::boost::shared_ptr<DeckDescriptor> SharedDeckDescriptor; + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/DeckLayouter.cxx b/sfx2/source/sidebar/DeckLayouter.cxx new file mode 100644 index 000000000000..b04f83b633d4 --- /dev/null +++ b/sfx2/source/sidebar/DeckLayouter.cxx @@ -0,0 +1,511 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DeckLayouter.hxx" +#include "sfx2/sidebar/Theme.hxx" +#include "Panel.hxx" +#include "TitleBar.hxx" +#include "Deck.hxx" + +#include <vcl/window.hxx> +#include <vcl/scrbar.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +namespace sfx2 { namespace sidebar { + + +namespace { + static const sal_Int32 MinimalPanelHeight (25); +} + +#define IterateLayoutItems(iterator_name,container) \ + for(::std::vector<LayoutItem>::iterator \ + iterator_name(container.begin()), \ + iEnd(container.end()); \ + iterator_name!=iEnd; \ + ++iterator_name) + + + +void DeckLayouter::LayoutDeck ( + const Rectangle aContentArea, + SharedPanelContainer& rPanels, + Window& rDeckTitleBar, + Window& rScrollClipWindow, + Window& rScrollContainer, + Window& rFiller, + ScrollBar& rVerticalScrollBar) +{ + if (aContentArea.GetWidth()<=0 || aContentArea.GetHeight()<=0) + return; + Rectangle aBox (PlaceDeckTitle(rDeckTitleBar, aContentArea)); + + if ( ! rPanels.empty()) + { + // Prepare the layout item container. + ::std::vector<LayoutItem> aLayoutItems; + aLayoutItems.resize(rPanels.size()); + for (sal_Int32 nIndex(0),nCount(rPanels.size()); nIndex<nCount; ++nIndex) + { + aLayoutItems[nIndex].mpPanel = rPanels[nIndex]; + aLayoutItems[nIndex].mnPanelIndex = nIndex; + } + aBox = LayoutPanels( + aBox, + aLayoutItems, + rScrollClipWindow, + rScrollContainer, + rVerticalScrollBar, + false); + } + UpdateFiller(rFiller, aBox); +} + + + + +Rectangle DeckLayouter::LayoutPanels ( + const Rectangle aContentArea, + ::std::vector<LayoutItem>& rLayoutItems, + Window& rScrollClipWindow, + Window& rScrollContainer, + ScrollBar& rVerticalScrollBar, + const bool bShowVerticalScrollBar) +{ + Rectangle aBox (PlaceVerticalScrollBar(rVerticalScrollBar, aContentArea, bShowVerticalScrollBar)); + + const sal_Int32 nWidth (aBox.GetWidth()); + + // Get the requested heights of the panels and the available + // height that is left when all panel titles and separators are + // taken into account. + sal_Int32 nAvailableHeight (aBox.GetHeight()); + GetRequestedSizes(rLayoutItems, nAvailableHeight, aBox); + const sal_Int32 nTotalDecorationHeight (aBox.GetHeight() - nAvailableHeight); + + // Analyze the requested heights. + // Determine the height that is available for panel content + // and count the different layouts. + sal_Int32 nTotalPreferredHeight (0); + sal_Int32 nTotalMinimumHeight (0); + IterateLayoutItems(iItem,rLayoutItems) + { + nTotalMinimumHeight += iItem->maLayoutSize.Minimum; + nTotalPreferredHeight += iItem->maLayoutSize.Preferred; + } + + if (nTotalMinimumHeight > nAvailableHeight + && ! bShowVerticalScrollBar) + { + // Not enough space, even when all panels are shrunk to their + // minimum height. + // Show a vertical scrollbar. + return LayoutPanels( + aContentArea, + rLayoutItems, + rScrollClipWindow, + rScrollContainer, + rVerticalScrollBar, + true); + } + + // We are now in one of three modes. + // - The preferred height fits into the available size: + // Use the preferred size, distribute the remaining height bei + // enlarging panels. + // - The total minimum height fits into the available size: + // Use the minimum size, distribute the remaining height bei + // enlarging panels. + // - The total minimum height does not fit into the available + // size: + // Use the unmodified preferred height for all panels. + + LayoutMode eMode (MinimumOrLarger); + if (bShowVerticalScrollBar) + eMode = Preferred; + else if (nTotalPreferredHeight <= nAvailableHeight) + eMode = PreferredOrLarger; + else + eMode = MinimumOrLarger; + + if (eMode != Preferred) + { + const sal_Int32 nTotalHeight (eMode==MinimumOrLarger ? nTotalMinimumHeight : nTotalPreferredHeight); + + DistributeHeights( + rLayoutItems, + nAvailableHeight-nTotalHeight, + aBox.GetHeight(), + eMode==MinimumOrLarger); + } + + // Set position and size of the mpScrollClipWindow to the available + // size. Its child, the mpScrollContainer, may have a bigger + // height. + rScrollClipWindow.setPosSizePixel(aBox.Left(), aBox.Top(), aBox.GetWidth(), aBox.GetHeight()); + + const sal_Int32 nContentHeight ( + eMode==Preferred + ? nTotalPreferredHeight + nTotalDecorationHeight + : aBox.GetHeight()); + sal_Int32 nY = rVerticalScrollBar.GetThumbPos(); + if (nContentHeight-nY < aBox.GetHeight()) + nY = nContentHeight-aBox.GetHeight(); + if (nY < 0) + nY = 0; + rScrollContainer.setPosSizePixel( + 0, + -nY, + nWidth, + nContentHeight); + + if (bShowVerticalScrollBar) + SetupVerticalScrollBar(rVerticalScrollBar, nContentHeight, aBox.GetHeight()); + + const sal_Int32 nUsedHeight (PlacePanels(rLayoutItems, nWidth, eMode, rScrollContainer)); + aBox.Top() += nUsedHeight; + return aBox; +} + + + + +sal_Int32 DeckLayouter::PlacePanels ( + ::std::vector<LayoutItem>& rLayoutItems, + const sal_Int32 nWidth, + const LayoutMode eMode, + Window& rScrollContainer) +{ + ::std::vector<sal_Int32> aSeparators; + const sal_Int32 nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight)); + const sal_Int32 nPanelTitleBarHeight (Theme::GetInteger(Theme::Int_PanelTitleBarHeight)); + sal_Int32 nY (0); + + // Assign heights and places. + IterateLayoutItems(iItem,rLayoutItems) + { + if (iItem->mpPanel == NULL) + continue; + + Panel& rPanel (*iItem->mpPanel); + + // Separator above the panel title bar. + aSeparators.push_back(nY); + nY += nDeckSeparatorHeight; + + // Place the title bar. + TitleBar* pTitleBar = rPanel.GetTitleBar(); + if (pTitleBar != NULL) + { + if (iItem->mbShowTitleBar) + { + pTitleBar->setPosSizePixel(0, nY, nWidth, nPanelTitleBarHeight); + pTitleBar->Show(); + nY += nPanelTitleBarHeight; + } + else + { + pTitleBar->Hide(); + } + } + + if (rPanel.IsExpanded()) + { + rPanel.Show(); + + // Determine the height of the panel depending on layout + // mode and distributed heights. + sal_Int32 nPanelHeight (0); + switch(eMode) + { + case MinimumOrLarger: + nPanelHeight = iItem->maLayoutSize.Minimum + iItem->mnDistributedHeight; + break; + case PreferredOrLarger: + nPanelHeight = iItem->maLayoutSize.Preferred + iItem->mnDistributedHeight; + break; + case Preferred: + nPanelHeight = iItem->maLayoutSize.Preferred; + break; + default: + OSL_ASSERT(false); + break; + } + + // Place the panel. + rPanel.setPosSizePixel(0, nY, nWidth, nPanelHeight); + + nY += nPanelHeight; + } + else + { + rPanel.Hide(); + + // Add a separator below the collapsed panel, if it is the + // last panel in the deck. + if (iItem == rLayoutItems.end()-1) + { + // Separator below the panel title bar. + aSeparators.push_back(nY); + nY += nDeckSeparatorHeight; + } + } + } + + Deck::ScrollContainerWindow* pScrollContainerWindow + = dynamic_cast<Deck::ScrollContainerWindow*>(&rScrollContainer); + if (pScrollContainerWindow != NULL) + pScrollContainerWindow->SetSeparators(aSeparators); + + return nY; +} + + + + +void DeckLayouter::GetRequestedSizes ( + ::std::vector<LayoutItem>& rLayoutItems, + sal_Int32& rAvailableHeight, + const Rectangle& rContentBox) +{ + rAvailableHeight = rContentBox.GetHeight(); + + const sal_Int32 nPanelTitleBarHeight (Theme::GetInteger(Theme::Int_PanelTitleBarHeight)); + const sal_Int32 nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight)); + + IterateLayoutItems(iItem,rLayoutItems) + { + ui::LayoutSize aLayoutSize (ui::LayoutSize(0,0,0)); + if (iItem->mpPanel != NULL) + { + if (rLayoutItems.size() == 1 + && iItem->mpPanel->IsTitleBarOptional()) + { + // There is only one panel and its title bar is + // optional => hide it. + rAvailableHeight -= nDeckSeparatorHeight; + iItem->mbShowTitleBar = false; + } + else + { + // Show the title bar and a separator above and below + // the title bar. + rAvailableHeight -= nPanelTitleBarHeight; + rAvailableHeight -= nDeckSeparatorHeight; + } + + if (iItem->mpPanel->IsExpanded()) + { + Reference<ui::XSidebarPanel> xPanel (iItem->mpPanel->GetPanelComponent()); + if (xPanel.is()) + aLayoutSize = xPanel->getHeightForWidth(rContentBox.GetWidth()); + else + aLayoutSize = ui::LayoutSize(MinimalPanelHeight, 0, -1); + } + } + iItem->maLayoutSize = aLayoutSize; + } +} + + + + +void DeckLayouter::DistributeHeights ( + ::std::vector<LayoutItem>& rLayoutItems, + const sal_Int32 nHeightToDistribute, + const sal_Int32 nContainerHeight, + const bool bMinimumHeightIsBase) +{ + if (nHeightToDistribute <= 0) + return; + + sal_Int32 nRemainingHeightToDistribute (nHeightToDistribute); + + // Compute the weights as difference between panel base height + // (either its minimum or preferred height) and the container height. + sal_Int32 nTotalWeight (0); + sal_Int32 nNoMaximumCount (0); + IterateLayoutItems(iItem,rLayoutItems) + { + if (iItem->maLayoutSize.Maximum == 0) + continue; + if (iItem->maLayoutSize.Maximum < 0) + ++nNoMaximumCount; + + const sal_Int32 nBaseHeight ( + bMinimumHeightIsBase + ? iItem->maLayoutSize.Minimum + : iItem->maLayoutSize.Preferred); + if (nBaseHeight < nContainerHeight) + { + iItem->mnWeight = nContainerHeight - nBaseHeight; + nTotalWeight += iItem->mnWeight; + } + } + + if (nTotalWeight == 0) + return; + + // First pass of height distribution. + IterateLayoutItems(iItem,rLayoutItems) + { + const sal_Int32 nBaseHeight ( + bMinimumHeightIsBase + ? iItem->maLayoutSize.Minimum + : iItem->maLayoutSize.Preferred); + sal_Int32 nDistributedHeight (iItem->mnWeight * nHeightToDistribute / nTotalWeight); + if (nBaseHeight+nDistributedHeight > iItem->maLayoutSize.Maximum + && iItem->maLayoutSize.Maximum >= 0) + { + nDistributedHeight = ::std::max<sal_Int32>(0,iItem->maLayoutSize.Maximum - nBaseHeight); + } + iItem->mnDistributedHeight = nDistributedHeight; + nRemainingHeightToDistribute -= nDistributedHeight; + } + + if (nRemainingHeightToDistribute == 0) + return; + OSL_ASSERT(nRemainingHeightToDistribute > 0); + + // It is possible that not all of the height could be distributed + // because of Maximum heights being smaller than expected. + // Distribute the remaining height between the panels that have no + // Maximum (ie Maximum==-1). + if (nNoMaximumCount == 0) + { + // There are no panels with unrestricted height. + return; + } + const sal_Int32 nAdditionalHeightPerPanel (nRemainingHeightToDistribute / nNoMaximumCount); + // Handle rounding error. + sal_Int32 nAdditionalHeightForFirstPanel (nRemainingHeightToDistribute + - nNoMaximumCount*nAdditionalHeightPerPanel); + IterateLayoutItems(iItem,rLayoutItems) + { + if (iItem->maLayoutSize.Maximum < 0) + { + iItem->mnDistributedHeight += nAdditionalHeightPerPanel + nAdditionalHeightForFirstPanel; + nRemainingHeightToDistribute -= nAdditionalHeightPerPanel + nAdditionalHeightForFirstPanel; + } + } + + OSL_ASSERT(nRemainingHeightToDistribute==0); +} + + + + +Rectangle DeckLayouter::PlaceDeckTitle ( + Window& rDeckTitleBar, + const Rectangle& rAvailableSpace) +{ + if (static_cast<DockingWindow*>(rDeckTitleBar.GetParent()->GetParent())->IsFloatingMode()) + { + // When the side bar is undocked then the outer system window displays the deck title. + rDeckTitleBar.Hide(); + return rAvailableSpace; + } + else + { + const sal_Int32 nDeckTitleBarHeight (Theme::GetInteger(Theme::Int_DeckTitleBarHeight)); + rDeckTitleBar.setPosSizePixel( + rAvailableSpace.Left(), + rAvailableSpace.Top(), + rAvailableSpace.GetWidth(), + nDeckTitleBarHeight); + rDeckTitleBar.Show(); + return Rectangle( + rAvailableSpace.Left(), + rAvailableSpace.Top() + nDeckTitleBarHeight, + rAvailableSpace.Right(), + rAvailableSpace.Bottom()); + } +} + + + + +Rectangle DeckLayouter::PlaceVerticalScrollBar ( + ScrollBar& rVerticalScrollBar, + const Rectangle& rAvailableSpace, + const bool bShowVerticalScrollBar) +{ + if (bShowVerticalScrollBar) + { + const sal_Int32 nScrollBarWidth (rVerticalScrollBar.GetSizePixel().Width()); + rVerticalScrollBar.setPosSizePixel( + rAvailableSpace.Right() - nScrollBarWidth + 1, + rAvailableSpace.Top(), + nScrollBarWidth, + rAvailableSpace.GetHeight()); + rVerticalScrollBar.Show(); + return Rectangle( + rAvailableSpace.Left(), + rAvailableSpace.Top(), + rAvailableSpace.Right() - nScrollBarWidth, + rAvailableSpace.Bottom()); + } + else + { + rVerticalScrollBar.Hide(); + return rAvailableSpace; + } +} + + + + +void DeckLayouter::SetupVerticalScrollBar( + ScrollBar& rVerticalScrollBar, + const sal_Int32 nContentHeight, + const sal_Int32 nVisibleHeight) +{ + OSL_ASSERT(nContentHeight > nVisibleHeight); + + rVerticalScrollBar.SetRangeMin(0); + rVerticalScrollBar.SetRangeMax(nContentHeight-1); + rVerticalScrollBar.SetVisibleSize(nVisibleHeight); +} + + + + +void DeckLayouter::UpdateFiller ( + Window& rFiller, + const Rectangle& rBox) +{ + if (rBox.GetHeight() > 0) + { + // Show the filler. + rFiller.SetBackground(Theme::GetPaint(Theme::Paint_PanelBackground).GetWallpaper()); + rFiller.SetPosSizePixel(rBox.TopLeft(), rBox.GetSize()); + rFiller.Show(); + } + else + { + // Hide the filler. + rFiller.Hide(); + } +} + + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/DeckLayouter.hxx b/sfx2/source/sidebar/DeckLayouter.hxx new file mode 100644 index 000000000000..e1df7f277ec4 --- /dev/null +++ b/sfx2/source/sidebar/DeckLayouter.hxx @@ -0,0 +1,119 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_DECK_LAYOUTER_HXX +#define SFX_SIDEBAR_DECK_LAYOUTER_HXX + +#include "Panel.hxx" + +#include <tools/gen.hxx> + +#include <com/sun/star/ui/LayoutSize.hpp> + +#include <vector> + +class ScrollBar; +class Window; + +namespace css = ::com::sun::star; + +namespace sfx2 { namespace sidebar { + +class Panel; + + +/** Helper class for layouting the direct and indirect children of a + deck like title bars, panels, and scroll bars. +*/ +class DeckLayouter +{ +public: + static void LayoutDeck ( + const Rectangle aContentArea, + SharedPanelContainer& rPanels, + Window& pDeckTitleBar, + Window& pScrollClipWindow, + Window& pScrollContainer, + Window& pFiller, + ScrollBar& pVerticalScrollBar); + +private: + // Do not use constructor or destructor. + DeckLayouter (void); + ~DeckLayouter (void); + + enum LayoutMode + { + MinimumOrLarger, + PreferredOrLarger, + Preferred + }; + class LayoutItem + { + public: + SharedPanel mpPanel; + css::ui::LayoutSize maLayoutSize; + sal_Int32 mnDistributedHeight; + sal_Int32 mnWeight; + sal_Int32 mnPanelIndex; + bool mbShowTitleBar; + + LayoutItem (void) + : mpPanel(),maLayoutSize(0,0,0),mnDistributedHeight(0),mnWeight(0),mnPanelIndex(0),mbShowTitleBar(true) + {} + }; + static Rectangle LayoutPanels ( + const Rectangle aContentArea, + ::std::vector<LayoutItem>& rLayoutItems, + Window& rScrollClipWindow, + Window& rScrollContainer, + ScrollBar& pVerticalScrollBar, + const bool bShowVerticalScrollBar); + static void GetRequestedSizes ( + ::std::vector<LayoutItem>& rLayoutItem, + sal_Int32& rAvailableHeight, + const Rectangle& rContentBox); + static void DistributeHeights ( + ::std::vector<LayoutItem>& rLayoutItems, + const sal_Int32 nHeightToDistribute, + const sal_Int32 nContainerHeight, + const bool bMinimumHeightIsBase); + static sal_Int32 PlacePanels ( + ::std::vector<LayoutItem>& rLayoutItems, + const sal_Int32 nWidth, + const LayoutMode eMode, + Window& rScrollContainer); + static Rectangle PlaceDeckTitle ( + Window& rTittleBar, + const Rectangle& rAvailableSpace); + static Rectangle PlaceVerticalScrollBar ( + ScrollBar& rVerticalScrollBar, + const Rectangle& rAvailableSpace, + const bool bShowVerticalScrollBar); + static void SetupVerticalScrollBar( + ScrollBar& rVerticalScrollBar, + const sal_Int32 nContentHeight, + const sal_Int32 nVisibleHeight); + static void UpdateFiller ( + Window& rFiller, + const Rectangle& rBox); +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/DeckTitleBar.cxx b/sfx2/source/sidebar/DeckTitleBar.cxx new file mode 100644 index 000000000000..008da73ba1ea --- /dev/null +++ b/sfx2/source/sidebar/DeckTitleBar.cxx @@ -0,0 +1,143 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DeckTitleBar.hxx" +#include "sfx2/sidebar/Theme.hxx" + +#include <vcl/image.hxx> + +#ifdef DEBUG +#include "Tools.hxx" +#endif + + +namespace sfx2 { namespace sidebar { + +static const sal_Int32 gaLeftGripPadding (3); +static const sal_Int32 gaRightGripPadding (3); + + +DeckTitleBar::DeckTitleBar ( + const ::rtl::OUString& rsTitle, + Window* pParentWindow, + const ::boost::function<void(void)>& rCloserAction) + : TitleBar(rsTitle, pParentWindow, GetBackgroundPaint()), + mnCloserItemIndex(1), + maCloserAction(rCloserAction), + mbIsCloserVisible(rCloserAction) +{ + OSL_ASSERT(pParentWindow != NULL); + + if (maCloserAction) + { + maToolBox.InsertItem( + mnCloserItemIndex, + Theme::GetImage(Theme::Image_Closer)); + } + +#ifdef DEBUG + SetText(A2S("DeckTitleBar")); +#endif +} + + + + +DeckTitleBar::~DeckTitleBar (void) +{ +} + + + + +void DeckTitleBar::SetCloserVisible (const bool bIsCloserVisible) +{ + if (mbIsCloserVisible != bIsCloserVisible) + { + mbIsCloserVisible = bIsCloserVisible; + + if (mbIsCloserVisible) + maToolBox.InsertItem( + mnCloserItemIndex, + Theme::GetImage(Theme::Image_Closer)); + else + maToolBox.RemoveItem( + maToolBox.GetItemPos(mnCloserItemIndex)); + } +} + + + + +Rectangle DeckTitleBar::GetTitleArea (const Rectangle& rTitleBarBox) +{ + Image aGripImage (Theme::GetImage(Theme::Image_Grip)); + return Rectangle( + aGripImage.GetSizePixel().Width() + gaLeftGripPadding + gaRightGripPadding, + rTitleBarBox.Top(), + rTitleBarBox.Right(), + rTitleBarBox.Bottom()); +} + + + + +void DeckTitleBar::PaintDecoration (const Rectangle& rTitleBarBox) +{ + (void)rTitleBarBox; +} + + + + +sidebar::Paint DeckTitleBar::GetBackgroundPaint (void) +{ + return Theme::GetPaint(Theme::Paint_DeckTitleBarBackground); +} + + + + +Color DeckTitleBar::GetTextColor (void) +{ + return Theme::GetColor(Theme::Color_DeckTitleFont); +} + + + + +void DeckTitleBar::HandleToolBoxItemClick (const sal_uInt16 nItemIndex) +{ + if (nItemIndex == mnCloserItemIndex) + if (maCloserAction) + maCloserAction(); +} + + + + +void DeckTitleBar::DataChanged (const DataChangedEvent& rEvent) +{ + maToolBox.SetItemImage( + mnCloserItemIndex, + Theme::GetImage(Theme::Image_Closer)); + TitleBar::DataChanged(rEvent); +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/DeckTitleBar.hxx b/sfx2/source/sidebar/DeckTitleBar.hxx new file mode 100644 index 000000000000..aab05648fe93 --- /dev/null +++ b/sfx2/source/sidebar/DeckTitleBar.hxx @@ -0,0 +1,57 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_DECK_TITLE_BAR_HXX +#define SFX_SIDEBAR_DECK_TITLE_BAR_HXX + +#include "TitleBar.hxx" + +#include <boost/function.hpp> + + +namespace sfx2 { namespace sidebar { + +class DeckTitleBar + : public TitleBar +{ +public: + DeckTitleBar ( + const ::rtl::OUString& rsTitle, + Window* pParentWindow, + const ::boost::function<void(void)>& rCloserAction); + virtual ~DeckTitleBar (void); + + void SetCloserVisible (const bool bIsCloserVisible); + + virtual void DataChanged (const DataChangedEvent& rEvent); + +protected: + virtual Rectangle GetTitleArea (const Rectangle& rTitleBarBox); + virtual void PaintDecoration (const Rectangle& rTitleBarBox); + virtual sidebar::Paint GetBackgroundPaint (void); + virtual Color GetTextColor (void); + virtual void HandleToolBoxItemClick (const sal_uInt16 nItemIndex); + +private: + const sal_uInt16 mnCloserItemIndex; + const ::boost::function<void(void)> maCloserAction; + bool mbIsCloserVisible; +}; + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/DrawHelper.cxx b/sfx2/source/sidebar/DrawHelper.cxx new file mode 100644 index 000000000000..f8172b2cf52c --- /dev/null +++ b/sfx2/source/sidebar/DrawHelper.cxx @@ -0,0 +1,244 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DrawHelper.hxx" +#include "Paint.hxx" + +#include <vcl/lineinfo.hxx> + + +namespace sfx2 { namespace sidebar { + +void DrawHelper::DrawBorder ( + OutputDevice& rDevice, + const Rectangle rBox, + const SvBorder aBorderSize, + const Paint& rHorizontalPaint, + const Paint& rVerticalPaint) +{ + // Draw top line. + DrawHorizontalLine( + rDevice, + rBox.Left(), + rBox.Right(), + rBox.Top(), + aBorderSize.Top(), + rHorizontalPaint); + // Draw bottom line. + DrawHorizontalLine( + rDevice, + rBox.Left()+aBorderSize.Left(), + rBox.Right(), + rBox.Bottom()-aBorderSize.Bottom()+1, + aBorderSize.Bottom(), + rHorizontalPaint); + // Draw left line. + DrawVerticalLine( + rDevice, + rBox.Top()+aBorderSize.Top(), + rBox.Bottom(), + rBox.Left(), + aBorderSize.Left(), + rVerticalPaint); + // Draw right line. + DrawVerticalLine( + rDevice, + rBox.Top()+aBorderSize.Top(), + rBox.Bottom()-aBorderSize.Bottom(), + rBox.Right()-aBorderSize.Right()+1, + aBorderSize.Right(), + rVerticalPaint); +} + + + + +void DrawHelper::DrawBevelBorder ( + OutputDevice& rDevice, + const Rectangle rBox, + const SvBorder aBorderSize, + const Paint& rTopLeftPaint, + const Paint& rCenterPaint, + const Paint& rBottomRightPaint) +{ + // Draw top line. + DrawHorizontalLine( + rDevice, + rBox.Left(), + rBox.Right() - aBorderSize.Right(), + rBox.Top(), + aBorderSize.Top(), + rTopLeftPaint); + // Draw bottom line. + DrawHorizontalLine( + rDevice, + rBox.Left()+aBorderSize.Left(), + rBox.Right(), + rBox.Bottom()-aBorderSize.Bottom()+1, + aBorderSize.Bottom(), + rBottomRightPaint); + // Draw left line. + DrawVerticalLine( + rDevice, + rBox.Top()+aBorderSize.Top(), + rBox.Bottom() - aBorderSize.Bottom(), + rBox.Left(), + aBorderSize.Left(), + rTopLeftPaint); + // Draw right line. + DrawVerticalLine( + rDevice, + rBox.Top()+aBorderSize.Top(), + rBox.Bottom()-aBorderSize.Bottom(), + rBox.Right()-aBorderSize.Right()+1, + aBorderSize.Right(), + rBottomRightPaint); + // Draw top right corner. + DrawVerticalLine( + rDevice, + rBox.Top(), + rBox.Top()+aBorderSize.Top()-1, + rBox.Right()-aBorderSize.Right()+1, + aBorderSize.Right(), + rCenterPaint); + // Draw bottom right corner. + DrawVerticalLine( + rDevice, + rBox.Bottom() - aBorderSize.Bottom()+1, + rBox.Bottom(), + rBox.Left(), + aBorderSize.Left(), + rCenterPaint); +} + + + + +void DrawHelper::DrawHorizontalLine( + OutputDevice& rDevice, + const sal_Int32 nLeft, + const sal_Int32 nRight, + const sal_Int32 nY, + const sal_Int32 nHeight, + const Paint& rPaint) +{ + switch (rPaint.GetType()) + { + case Paint::NoPaint: + default: + break; + + case Paint::ColorPaint: + { + const Color aColor (rPaint.GetColor()); + rDevice.SetLineColor(aColor); + for (sal_Int32 nYOffset=0; nYOffset<nHeight; ++nYOffset) + rDevice.DrawLine( + Point(nLeft,nY+nYOffset), + Point(nRight,nY+nYOffset)); + break; + } + case Paint::GradientPaint: + rDevice.DrawGradient( + Rectangle( + nLeft, + nY, + nRight, + nY+nHeight-1), + rPaint.GetGradient()); + break; + } +} + + + + +void DrawHelper::DrawVerticalLine( + OutputDevice& rDevice, + const sal_Int32 nTop, + const sal_Int32 nBottom, + const sal_Int32 nX, + const sal_Int32 nWidth, + const Paint& rPaint) +{ + switch (rPaint.GetType()) + { + case Paint::NoPaint: + default: + break; + + case Paint::ColorPaint: + { + const Color aColor (rPaint.GetColor()); + rDevice.SetLineColor(aColor); + for (sal_Int32 nXOffset=0; nXOffset<nWidth; ++nXOffset) + rDevice.DrawLine( + Point(nX+nXOffset, nTop), + Point(nX+nXOffset, nBottom)); + break; + } + case Paint::GradientPaint: + rDevice.DrawGradient( + Rectangle( + nX, + nTop, + nX+nWidth-1, + nBottom), + rPaint.GetGradient()); + break; + } +} + + + + +void DrawHelper::DrawRoundedRectangle ( + OutputDevice& rDevice, + const Rectangle& rBox, + const sal_Int32 nCornerRadius, + const Color& rBorderColor, + const Paint& rFillPaint) +{ + rDevice.SetLineColor(rBorderColor); + switch(rFillPaint.GetType()) + { + case Paint::NoPaint: + default: + rDevice.SetFillColor(); + rDevice.DrawRect(rBox, nCornerRadius, nCornerRadius); + break; + + case Paint::ColorPaint: + rDevice.SetFillColor(rFillPaint.GetColor()); + rDevice.DrawRect(rBox, nCornerRadius, nCornerRadius); + break; + + case Paint::GradientPaint: + rDevice.DrawGradient( + rBox, + rFillPaint.GetGradient()); + rDevice.SetFillColor(); + rDevice.DrawRect(rBox, nCornerRadius, nCornerRadius); + break; + } +} + + + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/DrawHelper.hxx b/sfx2/source/sidebar/DrawHelper.hxx new file mode 100644 index 000000000000..45bf7ea9c25b --- /dev/null +++ b/sfx2/source/sidebar/DrawHelper.hxx @@ -0,0 +1,74 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_DRAW_HELPER_HXX +#define SFX_SIDEBAR_DRAW_HELPER_HXX + +#include "vcl/window.hxx" + +#include <tools/svborder.hxx> + +class Color; + +namespace sfx2 { namespace sidebar { + +class Paint; + +/** Some convenience functions for painting backgrounds and borders. +*/ +class DrawHelper +{ +public: + static void DrawBorder ( + OutputDevice& rDevice, + const Rectangle rBox, + const SvBorder aBorderSize, + const Paint& rHorizontalPaint, + const Paint& rVerticalPaint); + static void DrawBevelBorder ( + OutputDevice& rDevice, + const Rectangle rBox, + const SvBorder aBorderSize, + const Paint& rTopLeftPaint, + const Paint& rCenterPaint, + const Paint& rBottomRightPaint); + static void DrawHorizontalLine( + OutputDevice& rDevice, + const sal_Int32 nLeft, + const sal_Int32 nRight, + const sal_Int32 nY, + const sal_Int32 nHeight, + const Paint& rPaint); + static void DrawVerticalLine( + OutputDevice& rDevice, + const sal_Int32 nTop, + const sal_Int32 nBottom, + const sal_Int32 nX, + const sal_Int32 nWidth, + const Paint& rPaint); + static void DrawRoundedRectangle ( + OutputDevice& rDevice, + const Rectangle& rBox, + const sal_Int32 nCornerRadius, + const Color& rBorderColor, + const Paint& rFillPaint); +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/EnumContext.cxx b/sfx2/source/sidebar/EnumContext.cxx new file mode 100644 index 000000000000..d8d39fb75aac --- /dev/null +++ b/sfx2/source/sidebar/EnumContext.cxx @@ -0,0 +1,326 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "sidebar/EnumContext.hxx" + +#include <map> + +namespace sfx2 { namespace sidebar { + +#define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString))) + +namespace { + +typedef ::std::map<rtl::OUString,EnumContext::Application> ApplicationMap; +typedef ::std::vector<rtl::OUString> ApplicationVector; +static ApplicationMap maApplicationMap; +static ApplicationVector maApplicationVector; + +typedef ::std::map<rtl::OUString,EnumContext::Context> ContextMap; +typedef ::std::vector<rtl::OUString> ContextVector; +static ContextMap maContextMap; +static ContextVector maContextVector; + +} + +const sal_Int32 EnumContext::NoMatch = 4; +const sal_Int32 EnumContext::OptimalMatch = 0; // Neither application nor context name is "any". + + +EnumContext::EnumContext (void) + : meApplication(Application_None), + meContext(Context_Unknown) +{ +} + + + + +EnumContext::EnumContext ( + const Application eApplication, + const Context eContext) + : meApplication(eApplication), + meContext(eContext) +{ +} + + + + +EnumContext::EnumContext ( + const ::rtl::OUString& rsApplicationName, + const ::rtl::OUString& rsContextName) + : meApplication(GetApplicationEnum(rsApplicationName)), + meContext(GetContextEnum(rsContextName)) +{ +} + + + + +sal_Int32 EnumContext::GetCombinedContext (void) const +{ + return CombinedEnumContext(meApplication, meContext); +} + + + + +sal_Int32 EnumContext::GetCombinedContext_DI (void) const +{ + switch (meApplication) + { + case Application_Draw: + case Application_Impress: + return CombinedEnumContext(Application_DrawImpress, meContext); + + case Application_Writer: + case Application_WriterWeb: + return CombinedEnumContext(Application_WriterAndWeb, meContext); + + default: + return CombinedEnumContext(meApplication, meContext); + } +} + + + + +const ::rtl::OUString& EnumContext::GetApplicationName (void) const +{ + return EnumContext::GetApplicationName(meApplication); +} + + + + +const ::rtl::OUString& EnumContext::GetContextName (void) const +{ + return EnumContext::GetContextName(meContext); +} + + + + +bool EnumContext::operator== (const EnumContext aOther) +{ + return meApplication==aOther.meApplication + && meContext==aOther.meContext; +} + + + + +bool EnumContext::operator!= (const EnumContext aOther) +{ + return meApplication!=aOther.meApplication + || meContext!=aOther.meContext; +} + + + + +void EnumContext::AddEntry (const ::rtl::OUString& rsName, const Application eApplication) +{ + maApplicationMap[rsName] = eApplication; + OSL_ASSERT(eApplication<=__LastApplicationEnum); + if (maApplicationVector.size() <= size_t(eApplication)) + maApplicationVector.resize(eApplication+1); + maApplicationVector[eApplication]=rsName; +} + + + + +void EnumContext::ProvideApplicationContainers (void) +{ + if (maApplicationMap.empty()) + { + maApplicationVector.resize(static_cast<size_t>(EnumContext::__LastApplicationEnum)+1); + AddEntry(A2S("com.sun.star.text.TextDocument"), EnumContext::Application_Writer); + AddEntry(A2S("com.sun.star.text.WebDocument"), EnumContext::Application_WriterWeb); + AddEntry(A2S("com.sun.star.sheet.SpreadsheetDocument"), EnumContext::Application_Calc); + AddEntry(A2S("com.sun.star.drawing.DrawingDocument"), EnumContext::Application_Draw); + AddEntry(A2S("com.sun.star.presentation.PresentationDocument"), EnumContext::Application_Impress); + + AddEntry(A2S("any"), EnumContext::Application_Any); + AddEntry(A2S("none"), EnumContext::Application_None); + } +} + + + + +EnumContext::Application EnumContext::GetApplicationEnum (const ::rtl::OUString& rsApplicationName) +{ + ProvideApplicationContainers(); + + ApplicationMap::const_iterator iApplication( + maApplicationMap.find(rsApplicationName)); + if (iApplication != maApplicationMap.end()) + return iApplication->second; + else + return EnumContext::Application_None; +} + + + + +const ::rtl::OUString& EnumContext::GetApplicationName (const Application eApplication) +{ + ProvideApplicationContainers(); + + const sal_Int32 nIndex (eApplication); + if (nIndex<0 || nIndex>= __LastApplicationEnum) + return maApplicationVector[Application_None]; + else + return maApplicationVector[nIndex]; +} + + + + +void EnumContext::AddEntry (const ::rtl::OUString& rsName, const Context eApplication) +{ + maContextMap[rsName] = eApplication; + OSL_ASSERT(eApplication<=__LastContextEnum); + if (maContextVector.size() <= size_t(eApplication)) + maContextVector.resize(eApplication+1); + maContextVector[eApplication] = rsName; +} + + + + +void EnumContext::ProvideContextContainers (void) +{ + if (maContextMap.empty()) + { + maContextVector.resize(static_cast<size_t>(__LastContextEnum)+1); + AddEntry(A2S("any"), Context_Any); + AddEntry(A2S("default"), Context_Default); + AddEntry(A2S("empty"), Context_Empty); +#define AddContext(context) AddEntry(A2S(#context), Context_##context); + AddContext(3DObject); + AddContext(Annotation); + AddContext(Auditing); + AddContext(Cell); + AddContext(Chart); + AddContext(Chart); + AddContext(Draw); + AddContext(DrawPage); + AddContext(DrawText); + AddContext(EditCell); + AddContext(Form); + AddContext(Frame); + AddContext(Graphic); + AddContext(HandoutPage); + AddContext(MasterPage); + AddContext(Media); + AddContext(MultiObject); + AddContext(NotesPage); + AddContext(OLE); + AddContext(OutlineText); + AddContext(Pivot); + AddContext(SlidesorterPage); + AddContext(Table); + AddContext(Text); + AddContext(TextObject); +#undef AddContext + } +} + + + + +EnumContext::Context EnumContext::GetContextEnum (const ::rtl::OUString& rsContextName) +{ + ProvideContextContainers(); + + ContextMap::const_iterator iContext( + maContextMap.find(rsContextName)); + if (iContext != maContextMap.end()) + return iContext->second; + else + return EnumContext::Context_Unknown; +} + + + + +const ::rtl::OUString& EnumContext::GetContextName (const Context eContext) +{ + ProvideContextContainers(); + + const sal_Int32 nIndex (eContext); + if (nIndex<0 || nIndex>= __LastContextEnum) + return maContextVector[Context_Unknown]; + else + return maContextVector[nIndex]; +} + + + + +sal_Int32 EnumContext::EvaluateMatch ( + const EnumContext& rOther) const +{ + const bool bApplicationNameIsAny (rOther.meApplication == Application_Any); + if (rOther.meApplication==meApplication || bApplicationNameIsAny) + { + // Application name matches. + const bool bContextNameIsAny (rOther.meContext == Context_Any); + if (rOther.meContext==meContext || bContextNameIsAny) + { + // Context name matches. + return (bApplicationNameIsAny ? 1 : 0) + + (bContextNameIsAny ? 2 : 0); + } + } + return NoMatch; +} + + + + +sal_Int32 EnumContext::EvaluateMatch (const ::std::vector<EnumContext>& rOthers) const +{ + sal_Int32 nBestMatch (NoMatch); + + for (::std::vector<EnumContext>::const_iterator + iContext(rOthers.begin()), + iEnd(rOthers.end()); + iContext!=iEnd; + ++iContext) + { + const sal_Int32 nMatch (EvaluateMatch(*iContext)); + if (nMatch < nBestMatch) + { + if (nMatch == OptimalMatch) + { + // We will find no better match so stop searching. + return OptimalMatch; + } + nBestMatch = nMatch; + } + } + return nBestMatch; +} + + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/FocusManager.cxx b/sfx2/source/sidebar/FocusManager.cxx new file mode 100644 index 000000000000..b5c2ec552333 --- /dev/null +++ b/sfx2/source/sidebar/FocusManager.cxx @@ -0,0 +1,559 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "FocusManager.hxx" +#include "Panel.hxx" +#include "Tools.hxx" +#include "TitleBar.hxx" +#include <vcl/button.hxx> +#include <vcl/toolbox.hxx> +#include <toolkit/helper/vclunohelper.hxx> + + +namespace sfx2 { namespace sidebar { + +namespace +{ + enum PanelComponent + { + PC_TitleBar, + PC_ToolBox, + PC_Content, + PC_None + }; + + PanelComponent GetFocusedComponent (const Panel& rPanel) + { + if (rPanel.HasFocus()) + return PC_Content; + else if (rPanel.GetTitleBar() != NULL) + { + if (rPanel.GetTitleBar()->HasFocus()) + return PC_TitleBar; + else if (rPanel.GetTitleBar()->GetToolBox().HasFocus()) + return PC_ToolBox; + } + return PC_None; + } +} + + +FocusManager::FocusManager (void) + : maPanels(), + maButtons(), + mpTopLevelWindow(NULL) +{ +} + + + + +FocusManager::~FocusManager (void) +{ + Clear(); +} + + + + +void FocusManager::GrabFocus (void) +{ + if ( ! maPanels.empty()) + FocusPanel(0); +} + + + + +void FocusManager::Clear (void) +{ + ClearPanels(); + ClearButtons(); +} + + + +void FocusManager::ClearPanels (void) +{ + SetTopLevelWindow(NULL); + + ::std::vector<Panel*> aPanels; + aPanels.swap(maPanels); + for (::std::vector<Panel*>::iterator iPanel(aPanels.begin()),iEnd(aPanels.end()); + iPanel!=iEnd; + ++iPanel) + { + UnregisterWindow(**iPanel); + if ((*iPanel)->GetTitleBar() != NULL) + { + UnregisterWindow(*(*iPanel)->GetTitleBar()); + UnregisterWindow((*iPanel)->GetTitleBar()->GetToolBox()); + } + } +} + + + + +void FocusManager::ClearButtons (void) +{ + ::std::vector<Window*> aButtons; + for (::std::vector<Window*>::iterator iButton(aButtons.begin()),iEnd(aButtons.end()); + iButton!=iEnd; + ++iButton) + { + UnregisterWindow(**iButton); + } +} + + + + +void FocusManager::SetPanels (const SharedPanelContainer& rPanels) +{ + ClearPanels(); + for(SharedPanelContainer::const_iterator iPanel(rPanels.begin()),iEnd(rPanels.end()); + iPanel!=iEnd; + ++iPanel) + { + RegisterWindow(**iPanel); + if ((*iPanel)->GetTitleBar() != NULL) + { + RegisterWindow(*(*iPanel)->GetTitleBar()); + RegisterWindow((*iPanel)->GetTitleBar()->GetToolBox()); + } + maPanels.push_back(iPanel->get()); + } + + RegisterTopLevelListener(); +} + + + + +void FocusManager::SetButtons (const ::std::vector<Button*>& rButtons) +{ + ClearButtons(); + for (::std::vector<Button*>::const_iterator iButton(rButtons.begin()),iEnd(rButtons.end()); + iButton!=iEnd; + ++iButton) + { + RegisterWindow(**iButton); + maButtons.push_back(*iButton); + } +} + + + + +void FocusManager::RegisterWindow (Window& rWindow) +{ + rWindow.AddEventListener(LINK(this, FocusManager, WindowEventListener)); +} + + + + +void FocusManager::UnregisterWindow (Window& rWindow) +{ + rWindow.RemoveEventListener(LINK(this, FocusManager, WindowEventListener)); +} + + + + +void FocusManager::RegisterTopLevelListener (void) +{ + if (maPanels.empty()) + return; + Window* pWindow = maPanels.front(); + while (pWindow != NULL && pWindow->GetParent()!=NULL) + { + pWindow = pWindow->GetParent(); + } + SetTopLevelWindow(pWindow); +} + + + + +void FocusManager::SetTopLevelWindow (Window* pWindow) +{ + if (mpTopLevelWindow != pWindow) + { + if (mpTopLevelWindow != NULL) + { + UnregisterWindow(*mpTopLevelWindow); + mpTopLevelWindow->RemoveChildEventListener(LINK(this, FocusManager, WindowEventListener)); + } + mpTopLevelWindow = pWindow; + if (mpTopLevelWindow != NULL) + { + RegisterWindow(*mpTopLevelWindow); + mpTopLevelWindow->AddChildEventListener(LINK(this, FocusManager, WindowEventListener)); + } + } +} + + + + +sal_Int32 FocusManager::GetPanelIndex (const Window& rWindow) const +{ + for (sal_Int32 nIndex=0,nCount(maPanels.size()); nIndex<nCount; ++nIndex) + { + if (maPanels[nIndex] == &rWindow) + return nIndex; + TitleBar* pTitleBar = maPanels[nIndex]->GetTitleBar(); + if (pTitleBar == &rWindow) + return nIndex; + if (pTitleBar!=NULL && &pTitleBar->GetToolBox()==&rWindow) + return nIndex; + } + return -1; +} + + + + +sal_Int32 FocusManager::GetButtonIndex (const Window& rWindow) const +{ + for (sal_Int32 nIndex=0,nCount(maButtons.size()); nIndex<nCount; ++nIndex) + if (maButtons[nIndex] == &rWindow) + return nIndex; + return -1; +} + + + + +bool FocusManager::IsAnyPanelFocused (void) const +{ + for (::std::vector<Panel*>::const_iterator iPanel(maPanels.begin()),iEnd(maPanels.end()); + iPanel!=iEnd; + ++iPanel) + { + if ((*iPanel)->HasFocus()) + return true; + else if ((*iPanel)->HasChildPathFocus()) + return true; + } + return false; +} + + + + +bool FocusManager::IsAnyButtonFocused (void) const +{ + for (::std::vector<Button*>::const_iterator iButton(maButtons.begin()),iEnd(maButtons.end()); + iButton!=iEnd; + ++iButton) + { + if ((*iButton)->HasFocus()) + return true; + } + return false; +} + + + + +void FocusManager::FocusPanel (const sal_Int32 nPanelIndex) +{ + Panel& rPanel (*maPanels[nPanelIndex]); + TitleBar* pTitleBar = rPanel.GetTitleBar(); + if (pTitleBar!=NULL && pTitleBar->IsVisible()) + { + rPanel.SetExpanded(true); + pTitleBar->GrabFocus(); + } + else + FocusPanelContent(nPanelIndex); +} + + + + +void FocusManager::FocusPanelContent (const sal_Int32 nPanelIndex) +{ + Window* pWindow = VCLUnoHelper::GetWindow(maPanels[nPanelIndex]->GetElementWindow()); + if (pWindow != NULL) + pWindow->GrabFocus(); +} + + + + +void FocusManager::FocusButton (const sal_Int32 nButtonIndex) +{ + maButtons[nButtonIndex]->GrabFocus(); + maButtons[nButtonIndex]->Invalidate(); +} + + + + +void FocusManager::ClickButton (const sal_Int32 nButtonIndex) +{ + maButtons[nButtonIndex]->Click(); + if (nButtonIndex > 0) + if ( ! maPanels.empty()) + FocusPanel(0); + maButtons[nButtonIndex]->GetParent()->Invalidate(); +} + + + + +void FocusManager::RemoveWindow (Window& rWindow) +{ + ::std::vector<Panel*>::iterator iPanel (::std::find(maPanels.begin(), maPanels.end(), &rWindow)); + if (iPanel != maPanels.end()) + { + UnregisterWindow(rWindow); + if ((*iPanel)->GetTitleBar() != NULL) + { + UnregisterWindow(*(*iPanel)->GetTitleBar()); + UnregisterWindow((*iPanel)->GetTitleBar()->GetToolBox()); + } + maPanels.erase(iPanel); + return; + } + + ::std::vector<Button*>::iterator iButton (::std::find(maButtons.begin(), maButtons.end(), &rWindow)); + if (iButton != maButtons.end()) + { + UnregisterWindow(rWindow); + maButtons.erase(iButton); + return; + } +} + + + + +bool FocusManager::MoveFocusInsidePanel ( + const sal_Int32 nPanelIndex, + const sal_Int32 nDirection) +{ + Panel& rPanel (*maPanels[nPanelIndex]); + switch (GetFocusedComponent(rPanel)) + { + case PC_TitleBar: + if (nDirection > 0) + rPanel.GetTitleBar()->GetToolBox().GrabFocus(); + else + FocusPanelContent(nPanelIndex); + return true; + + case PC_ToolBox: + if (nDirection > 0) + FocusPanelContent(nPanelIndex); + else + rPanel.GetTitleBar()->GrabFocus(); + return true; + + default: + return false; + } +} + + + + +long FocusManager::NotifyDockingWindowEvent (const KeyEvent& rKeyEvent) +{ + switch(rKeyEvent.GetKeyCode().GetCode()) + { + case KEY_F6: + if (rKeyEvent.GetKeyCode().IsShift()) + { + if (IsAnyButtonFocused()) + { + FocusPanel(0); + return 1; + } + } + else + { + if (IsAnyPanelFocused()) + { + FocusButton(0); + return 1; + } + } + break; + } + return 0; +} + + + + +void FocusManager::HandleKeyEvent ( + const KeyCode& rKeyCode, + const Window& rWindow) +{ + if (rKeyCode.GetModifier() != 0) + return; + + const sal_Int32 nPanelIndex (GetPanelIndex(rWindow)); + sal_Int32 nButtonIndex (nPanelIndex==-1 ? GetButtonIndex(rWindow) : -1); + + switch (rKeyCode.GetCode()) + { + case KEY_F6: + if (nPanelIndex >= 0) + FocusButton(0); + else + return; + break; + + case KEY_SPACE: + if (nPanelIndex >= 0) + { + if (GetFocusedComponent(*maPanels[nPanelIndex]) == PC_TitleBar) + { + // Toggle the expansion state. + maPanels[nPanelIndex]->SetExpanded( ! maPanels[nPanelIndex]->IsExpanded()); + } + } + else if (nButtonIndex >= 0) + { + // Activate the button. + ClickButton(nButtonIndex); + } + return; + + case KEY_RETURN: + if (nPanelIndex >= 0) + { + if (GetFocusedComponent(*maPanels[nPanelIndex]) == PC_TitleBar) + { + // Enter the panel. + FocusPanelContent(nPanelIndex); + } + } + else if (nButtonIndex >= 0) + { + // Activate the button. + ClickButton(nButtonIndex); + } + return; + + case KEY_TAB: + if (nPanelIndex >= 0) + { + if (rKeyCode.IsShift()) + MoveFocusInsidePanel(nPanelIndex, -1); + else + MoveFocusInsidePanel(nPanelIndex, +1); + } + break; + + case KEY_LEFT: + case KEY_UP: + // Go to previous element in focus ring. + if (nPanelIndex >= 0) + { + FocusPanel((nPanelIndex + maPanels.size() - 1) % maPanels.size()); + } + else if (nButtonIndex >= 0) + { + FocusButton((nButtonIndex + maButtons.size() - 1) % maButtons.size()); + } + break; + + case KEY_RIGHT: + case KEY_DOWN: + // Go to next element in focus ring. + if (nPanelIndex >= 0) + { + FocusPanel((nPanelIndex + 1) % maPanels.size()); + } + else if (nButtonIndex >= 0) + { + FocusButton((nButtonIndex + 1) % maButtons.size()); + } + break; + } +} + + + + +void FocusManager::HandleTopLevelEvent (VclWindowEvent& rEvent) +{ + switch (rEvent.GetId()) + { + case VCLEVENT_WINDOW_KEYINPUT: + { + KeyEvent* pKeyEvent = static_cast<KeyEvent*>(rEvent.GetData()); + switch (pKeyEvent->GetKeyCode().GetCode()) + { + case KEY_F6: + OSL_TRACE(""); + break; + } + } + } +} + + + + +IMPL_LINK(FocusManager, WindowEventListener, VclSimpleEvent*, pEvent) +{ + if (pEvent == NULL) + return 0; + + if ( ! pEvent->ISA(VclWindowEvent)) + return 0; + + VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent); + Window* pSource = pWindowEvent->GetWindow(); + if (pSource == NULL) + return 0; + + if (pSource == mpTopLevelWindow) + HandleTopLevelEvent(*pWindowEvent); + else + switch (pWindowEvent->GetId()) + { + case VCLEVENT_WINDOW_KEYINPUT: + { + KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData()); + HandleKeyEvent(pKeyEvent->GetKeyCode(), *pSource); + return 1; + } + + case VCLEVENT_OBJECT_DYING: + RemoveWindow(*pSource); + return 1; + + case VCLEVENT_WINDOW_GETFOCUS: + case VCLEVENT_WINDOW_LOSEFOCUS: + pSource->Invalidate(); + } + return 0; +} + + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/FocusManager.hxx b/sfx2/source/sidebar/FocusManager.hxx new file mode 100644 index 000000000000..f811f5ef4ea4 --- /dev/null +++ b/sfx2/source/sidebar/FocusManager.hxx @@ -0,0 +1,108 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_FOCUS_MANAGER_HXX +#define SFX_SIDEBAR_FOCUS_MANAGER_HXX + +#include "Panel.hxx" +#include <tools/link.hxx> + +class Button; +class KeyCode; +class VclSimpleEvent; + +namespace sfx2 { namespace sidebar { + +/** Concentrate all focus handling in this class. + There are two rings of windows that accept the input focus: panels + and tab bar buttons. + Arrow keys move the focus between them. Tab moves focus between rings. +*/ +class FocusManager +{ +public: + FocusManager (void); + ~FocusManager (void); + + /** Forget all panels and buttons. Remove all window listeners. + */ + void Clear (void); + + /** Transfer the focus into the sidebar tree of windows. This is + typically called from the SidebarChildWindow as result of + pressing the F6 key. + */ + void GrabFocus (void); + + /** Handle the key event that was sent to the docking window. + */ + long NotifyDockingWindowEvent (const KeyEvent& rKeyEvent); + + void SetPanels (const SharedPanelContainer& rPanels); + + void SetButtons (const ::std::vector<Button*>& rButtons); + +private: + ::std::vector<Panel*> maPanels; + ::std::vector<Button*> maButtons; + Window* mpTopLevelWindow; + + /** Listen for key events for panels and buttons. + */ + DECL_LINK(WindowEventListener, VclSimpleEvent*); + + void ClearPanels (void); + void ClearButtons (void); + + /** Let the focus manager listen for window events for the given + window. + */ + void RegisterWindow (Window& rWindow); + void UnregisterWindow (Window& rWindow); + void RegisterTopLevelListener (void); + + /** Remove the window from the panel or the button container. + */ + void RemoveWindow (Window& rWindow); + + sal_Int32 GetPanelIndex (const Window& rWindow) const; + sal_Int32 GetButtonIndex (const Window& rWindow) const; + bool IsAnyPanelFocused (void) const; + bool IsAnyButtonFocused (void) const; + + /** Set the focus to the title bar of the panel or, if the the + title bar is not visible, directly to the panel. + */ + void FocusPanel (const sal_Int32 nPanelIndex); + void FocusPanelContent (const sal_Int32 nPanelIndex); + void FocusButton (const sal_Int32 nButtonIndex); + void ClickButton (const sal_Int32 nButtonIndex); + bool MoveFocusInsidePanel ( + const sal_Int32 nPanelIndex, + const sal_Int32 nDirection); + + void HandleKeyEvent ( + const KeyCode& rKeyCode, + const Window& rWindow); + + void SetTopLevelWindow (Window* pWindow); + void HandleTopLevelEvent (VclWindowEvent& rEvent); +}; + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/MenuButton.cxx b/sfx2/source/sidebar/MenuButton.cxx new file mode 100644 index 000000000000..5b28220b8637 --- /dev/null +++ b/sfx2/source/sidebar/MenuButton.cxx @@ -0,0 +1,150 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "MenuButton.hxx" + +#include "DrawHelper.hxx" +#include "Paint.hxx" +#include "Tools.hxx" +#include "sfx2/sidebar/Theme.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +namespace sfx2 { namespace sidebar { + + +MenuButton::MenuButton (Window* pParentWindow) + : CheckBox(pParentWindow), + mbIsLeftButtonDown(false), + mePaintType(PT_Theme) +{ +#ifdef DEBUG + SetText(A2S("MenuButton")); +#endif +} + + + + +MenuButton::~MenuButton (void) +{ +} + + + + +void MenuButton::Paint (const Rectangle& rUpdateArea) +{ + switch(mePaintType) + { + case PT_Theme: + default: + { + const bool bIsSelected (IsChecked()); + const bool bIsHighlighted (IsMouseOver() || HasFocus()); + DrawHelper::DrawRoundedRectangle( + *this, + Rectangle(Point(0,0), GetSizePixel()), + 3, + bIsHighlighted||bIsSelected + ? Theme::GetColor(Theme::Color_TabItemBorder) + : Color(0xffffffff), + bIsHighlighted + ? Theme::GetPaint(Theme::Paint_TabItemBackgroundHighlight) + : Theme::GetPaint(Theme::Paint_TabItemBackgroundNormal)); + + const Image aIcon(Button::GetModeImage()); + const Size aIconSize (aIcon.GetSizePixel()); + const Point aIconLocation( + (GetSizePixel().Width() - aIconSize.Width())/2, + (GetSizePixel().Height() - aIconSize.Height())/2); + DrawImage( + aIconLocation, + aIcon); + break; + } + case PT_Native: + Button::Paint(rUpdateArea); + // DrawImage(maIconPosition, maIcon); + break; + } +} + + + + +void MenuButton::MouseMove (const MouseEvent& rEvent) +{ + if (rEvent.IsEnterWindow() || rEvent.IsLeaveWindow()) + Invalidate(); + CheckBox::MouseMove(rEvent); +} + + + + +void MenuButton::MouseButtonDown (const MouseEvent& rMouseEvent) +{ +#if 0 + Hide(); + CheckBox::MouseButtonDown(rMouseEvent); + Show(); +#else + if (rMouseEvent.IsLeft()) + { + mbIsLeftButtonDown = true; + CaptureMouse(); + Invalidate(); + } +#endif +} + + + + +void MenuButton::MouseButtonUp (const MouseEvent& rMouseEvent) +{ +#if 0 + Hide(); + CheckBox::MouseButtonUp(rMouseEvent); + Show(); +#else + if (IsMouseCaptured()) + ReleaseMouse(); + + if (rMouseEvent.IsLeft()) + { + if (mbIsLeftButtonDown) + { + Check(); + Click(); + GetParent()->Invalidate(); + } + } + if (mbIsLeftButtonDown) + { + mbIsLeftButtonDown = false; + Invalidate(); + } +#endif +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/MenuButton.hxx b/sfx2/source/sidebar/MenuButton.hxx new file mode 100644 index 000000000000..13587dd312ce --- /dev/null +++ b/sfx2/source/sidebar/MenuButton.hxx @@ -0,0 +1,52 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_MENU_BUTTON_HXX +#define SFX_SIDEBAR_MENU_BUTTON_HXX + +#include "vcl/button.hxx" + + +namespace sfx2 { namespace sidebar { + +class MenuButton + : public CheckBox +{ +public: + MenuButton (Window* pParentWindow); + virtual ~MenuButton (void); + + virtual void Paint (const Rectangle& rUpdateArea); + virtual void MouseMove (const MouseEvent& rEvent); + virtual void MouseButtonDown (const MouseEvent& rMouseEvent); + virtual void MouseButtonUp (const MouseEvent& rMouseEvent); + +protected: + using CheckBox::FillLayoutData; + +private: + bool mbIsLeftButtonDown; + enum PaintType { + PT_Native, + PT_Theme + } mePaintType; +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/Paint.cxx b/sfx2/source/sidebar/Paint.cxx new file mode 100644 index 000000000000..20f9bb938113 --- /dev/null +++ b/sfx2/source/sidebar/Paint.cxx @@ -0,0 +1,136 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "Paint.hxx" +#include "Tools.hxx" +#include <com/sun/star/awt/Gradient.hpp> + + +using namespace ::com::sun::star; + +namespace sfx2 { namespace sidebar { + +Paint::Paint (void) + : meType(NoPaint) +{ +} + + + + +Paint::Paint (const Color& rColor) + : meType(ColorPaint), + maValue(rColor) +{ +} + + + + +Paint::Paint (const Gradient& rGradient) + : meType(GradientPaint), + maValue(rGradient) +{ +} + + + + +Paint Paint::Create (const cssu::Any& rValue) +{ + ColorData aColor (0); + if (rValue >>= aColor) + return Paint(Color(aColor)); + + awt::Gradient aAwtGradient; + if (rValue >>= aAwtGradient) + return Paint(Tools::AwtToVclGradient(aAwtGradient)); + + return Paint(); +} + + + + +void Paint::Set (const Paint& rOther) +{ + meType = rOther.meType; + maValue = rOther.maValue; +} + + + + +Paint::Type Paint::GetType (void) const +{ + return meType; +} + + + + +const Color& Paint::GetColor (void) const +{ + if (meType != ColorPaint) + { + assert(meType==ColorPaint); + static Color aErrorColor; + return aErrorColor; + } + else + return ::boost::get<Color>(maValue); +} + + + + +const Gradient& Paint::GetGradient (void) const +{ + if (meType != GradientPaint) + { + assert(meType==GradientPaint); + static Gradient aErrorGradient; + return aErrorGradient; + } + else + return ::boost::get<Gradient>(maValue); +} + + + + +Wallpaper Paint::GetWallpaper (void) const +{ + switch (meType) + { + case Paint::NoPaint: + default: + return Wallpaper(); + break; + + case Paint::ColorPaint: + return Wallpaper(GetColor()); + break; + + case Paint::GradientPaint: + return Wallpaper(GetGradient()); + break; + } +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/Paint.hxx b/sfx2/source/sidebar/Paint.hxx new file mode 100644 index 000000000000..e6840a9533e5 --- /dev/null +++ b/sfx2/source/sidebar/Paint.hxx @@ -0,0 +1,80 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_PAINT_HXX +#define SFX_SIDEBAR_PAINT_HXX + +#include <tools/color.hxx> +#include <vcl/gradient.hxx> +#include <vcl/wall.hxx> +#include <com/sun/star/awt/Gradient.hpp> + +#include <boost/variant.hpp> + +namespace cssu = ::com::sun::star::uno; + +namespace sfx2 { namespace sidebar { + +/** Abstraction of different ways to fill outlines. + Can be + - none (empty: outline is not filled) + - singular color + - gradient +*/ +class Paint +{ +public: + enum Type + { + NoPaint, + ColorPaint, + GradientPaint + }; + + // Create a Paint object for an Any that may contain a color, a + // awt::Gradient, or nothing. + static Paint Create (const cssu::Any& rValue); + + // Create paint with type NoPaint. + explicit Paint (void); + + // Create a Paint object for the given color. + explicit Paint (const Color& rColor); + + // Create a Paint object for the given gradient. + explicit Paint (const Gradient& rGradient); + + void Set (const ::sfx2::sidebar::Paint& rOther); + + Type GetType (void) const; + const Color& GetColor (void) const; + const Gradient& GetGradient (void) const; + + Wallpaper GetWallpaper (void) const; + +private: + Type meType; + ::boost::variant< + Color, + Gradient + > maValue; +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/Panel.cxx b/sfx2/source/sidebar/Panel.cxx new file mode 100644 index 000000000000..5389b4ff444b --- /dev/null +++ b/sfx2/source/sidebar/Panel.cxx @@ -0,0 +1,267 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "Panel.hxx" +#include "PanelTitleBar.hxx" +#include "PanelDescriptor.hxx" +#include "sfx2/sidebar/Theme.hxx" +#include "Paint.hxx" + +#ifdef DEBUG +#include "Tools.hxx" +#include "Deck.hxx" +#endif + +#include <tools/svborder.hxx> +#include <toolkit/helper/vclunohelper.hxx> + +#include <com/sun/star/awt/XWindowPeer.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/ui/XToolPanel.hpp> + +#include <boost/bind.hpp> + + +using namespace css; +using namespace cssu; + + + +namespace sfx2 { namespace sidebar { + +Panel::Panel ( + const PanelDescriptor& rPanelDescriptor, + Window* pParentWindow, + const ::boost::function<void(void)>& rDeckLayoutTrigger, + const ::boost::function<void(void)>& rShowMenuFunctor) + : Window(pParentWindow), + msPanelId(rPanelDescriptor.msId), + mpTitleBar(new PanelTitleBar( + rPanelDescriptor.msTitle, + pParentWindow, + this, + rShowMenuFunctor)), + mbIsTitleBarOptional(rPanelDescriptor.mbIsTitleBarOptional), + mxElement(), + mxPanelComponent(), + mbIsExpanded(true), + maDeckLayoutTrigger(rDeckLayoutTrigger) +{ + SetBackground(Theme::GetPaint(Theme::Paint_PanelBackground).GetWallpaper()); + +#ifdef DEBUG + OSL_TRACE("creating Panel at %x", this); + SetText(A2S("Panel")); +#endif +} + + + + +Panel::~Panel (void) +{ + OSL_TRACE("destroying Panel at %x", this); + Dispose(); +} + + + + +void Panel::Dispose (void) +{ + mxPanelComponent = NULL; + + if (mxElement.is()) + { + Reference<lang::XComponent> xComponent (mxElement->getRealInterface(), UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); + } + + { + Reference<lang::XComponent> xComponent (mxElement, UNO_QUERY); + mxElement = NULL; + if (xComponent.is()) + xComponent->dispose(); + } + + { + Reference<lang::XComponent> xComponent (GetElementWindow(), UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); + } + + mpTitleBar.reset(); +} + + + + +TitleBar* Panel::GetTitleBar (void) const +{ + return mpTitleBar.get(); +} + + + + +bool Panel::IsTitleBarOptional (void) const +{ + return mbIsTitleBarOptional; +} + + + + +void Panel::SetUIElement (const Reference<ui::XUIElement>& rxElement) +{ + mxElement = rxElement; + if (mxElement.is()) + { + mxPanelComponent.set(mxElement->getRealInterface(), UNO_QUERY); + } +} + + + + +void Panel::SetExpanded (const bool bIsExpanded) +{ + if (mbIsExpanded != bIsExpanded) + { + mbIsExpanded = bIsExpanded; + maDeckLayoutTrigger(); + } +} + + + + +bool Panel::IsExpanded (void) const +{ + return mbIsExpanded; +} + + + + +bool Panel::HasIdPredicate (const ::rtl::OUString& rsId) const +{ + if (this == NULL) + return false; + else + return msPanelId.equals(rsId); +} + + + + +const ::rtl::OUString& Panel::GetId (void) const +{ + return msPanelId; +} + + + + +void Panel::Paint (const Rectangle& rUpdateArea) +{ + Window::Paint(rUpdateArea); +} + + + + +void Panel::Resize (void) +{ + Window::Resize(); + + // Forward new size to window of XUIElement. + Reference<awt::XWindow> xElementWindow (GetElementWindow()); + if (xElementWindow.is()) + { + const Size aSize (GetSizePixel()); + xElementWindow->setPosSize( + 0, + 0, + aSize.Width(), + aSize.Height(), + awt::PosSize::POSSIZE); + } +} + + + + +void Panel::Activate (void) +{ + Window::Activate(); +} + + + + + +void Panel::DataChanged (const DataChangedEvent& rEvent) +{ + (void)rEvent; + SetBackground(Theme::GetPaint(Theme::Paint_PanelBackground).GetWallpaper()); +} + + + + +Reference<ui::XSidebarPanel> Panel::GetPanelComponent (void) const +{ + return mxPanelComponent; +} + + + + +void Panel::PrintWindowTree (void) +{ +#ifdef DEBUG + Window* pElementWindow = VCLUnoHelper::GetWindow(GetElementWindow()); + if (pElementWindow != NULL) + { + OSL_TRACE("panel parent is %x", pElementWindow->GetParent()); + Deck::PrintWindowSubTree(pElementWindow, 2); + } + else + OSL_TRACE(" panel is empty"); +#endif +} + + + + +Reference<awt::XWindow> Panel::GetElementWindow (void) +{ + if (mxElement.is()) + { + Reference<ui::XToolPanel> xToolPanel(mxElement->getRealInterface(), UNO_QUERY); + if (xToolPanel.is()) + return xToolPanel->getWindow(); + } + + return NULL; +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/Panel.hxx b/sfx2/source/sidebar/Panel.hxx new file mode 100644 index 000000000000..ce6cb3c12eb6 --- /dev/null +++ b/sfx2/source/sidebar/Panel.hxx @@ -0,0 +1,86 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_PANEL_HXX +#define SFX_SIDEBAR_PANEL_HXX + +#include <vcl/window.hxx> + +#include <com/sun/star/ui/XUIElement.hpp> +#include <com/sun/star/ui/XSidebarPanel.hpp> + +#include <boost/function.hpp> +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> +#include <vector> + +namespace css = ::com::sun::star; +namespace cssu = ::com::sun::star::uno; + +namespace sfx2 { namespace sidebar { + +class PanelDescriptor; +class TitleBar; + + +class Panel + : public Window +{ +public: + Panel ( + const PanelDescriptor& rPanelDescriptor, + Window* pParentWindow, + const ::boost::function<void(void)>& rDeckLayoutTrigger, + const ::boost::function<void(void)>& rShowMenuFunctor); + virtual ~Panel (void); + + void Dispose (void); + + TitleBar* GetTitleBar (void) const; + bool IsTitleBarOptional (void) const; + void SetUIElement (const cssu::Reference<css::ui::XUIElement>& rxElement); + cssu::Reference<css::ui::XSidebarPanel> GetPanelComponent (void) const; + cssu::Reference<css::awt::XWindow> GetElementWindow (void); + void SetExpanded (const bool bIsExpanded); + bool IsExpanded (void) const; + bool HasIdPredicate (const ::rtl::OUString& rsId) const; + const ::rtl::OUString& GetId (void) const; + + virtual void Paint (const Rectangle& rUpdateArea); + virtual void Resize (void); + virtual void DataChanged (const DataChangedEvent& rEvent); + virtual void Activate (void); + + void PrintWindowTree (void); + +private: + const ::rtl::OUString msPanelId; + ::boost::scoped_ptr<TitleBar> mpTitleBar; + const bool mbIsTitleBarOptional; + cssu::Reference<css::ui::XUIElement> mxElement; + cssu::Reference<css::ui::XSidebarPanel> mxPanelComponent; + bool mbIsExpanded; + const ::boost::function<void(void)> maDeckLayoutTrigger; + Rectangle maBoundingBox; +}; +typedef ::boost::shared_ptr<Panel> SharedPanel; +typedef ::std::vector<SharedPanel> SharedPanelContainer; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/PanelDescriptor.cxx b/sfx2/source/sidebar/PanelDescriptor.cxx new file mode 100644 index 000000000000..31e3b9e3c139 --- /dev/null +++ b/sfx2/source/sidebar/PanelDescriptor.cxx @@ -0,0 +1,60 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "PanelDescriptor.hxx" + + +namespace sfx2 { namespace sidebar { + +PanelDescriptor::PanelDescriptor (void) + : msTitle(), + mbIsTitleBarOptional(false), + msId(), + msDeckId(), + msHelpURL(), + maContextList(), + msImplementationURL(), + mnOrderIndex(10000), // Default value as defined in Sidebar.xcs + mbWantsCanvas(false) +{ +} + + + + +PanelDescriptor::PanelDescriptor (const PanelDescriptor& rOther) + : msTitle(rOther.msTitle), + mbIsTitleBarOptional(rOther.mbIsTitleBarOptional), + msId(rOther.msId), + msDeckId(rOther.msDeckId), + msHelpURL(rOther.msHelpURL), + maContextList(rOther.maContextList), + msImplementationURL(rOther.msImplementationURL), + mnOrderIndex(rOther.mnOrderIndex), + mbWantsCanvas(rOther.mbWantsCanvas) +{ +} + + + +PanelDescriptor::~PanelDescriptor (void) +{ +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/PanelDescriptor.hxx b/sfx2/source/sidebar/PanelDescriptor.hxx new file mode 100644 index 000000000000..a9b34456d762 --- /dev/null +++ b/sfx2/source/sidebar/PanelDescriptor.hxx @@ -0,0 +1,49 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_PANEL_DESCRIPTOR_HXX +#define SFX_SIDEBAR_PANEL_DESCRIPTOR_HXX + +#include "sfx2/sidebar/EnumContext.hxx" +#include "ContextList.hxx" +#include <boost/shared_ptr.hpp> + + +namespace sfx2 { namespace sidebar { + +class PanelDescriptor +{ +public: + ::rtl::OUString msTitle; + sal_Bool mbIsTitleBarOptional; + ::rtl::OUString msId; + ::rtl::OUString msDeckId; + ::rtl::OUString msHelpURL; + ContextList maContextList; + ::rtl::OUString msImplementationURL; + sal_Int32 mnOrderIndex; + bool mbWantsCanvas; + + PanelDescriptor (void); + PanelDescriptor (const PanelDescriptor& rPanelDescriptor); + ~PanelDescriptor (void); +}; +typedef ::boost::shared_ptr<PanelDescriptor> SharedPanelDescriptor; + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/PanelTitleBar.cxx b/sfx2/source/sidebar/PanelTitleBar.cxx new file mode 100644 index 000000000000..ded65fb8a458 --- /dev/null +++ b/sfx2/source/sidebar/PanelTitleBar.cxx @@ -0,0 +1,185 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "PanelTitleBar.hxx" + +#include "Paint.hxx" +#include "Panel.hxx" +#include "sfx2/sidebar/Theme.hxx" + +#include <tools/svborder.hxx> +#include <vcl/gradient.hxx> +#include <vcl/image.hxx> + +#ifdef DEBUG +#include "Tools.hxx" +#endif + + +namespace sfx2 { namespace sidebar { + + +static const sal_Int32 gaLeftIconPadding (5); +static const sal_Int32 gaRightIconPadding (5); + + +PanelTitleBar::PanelTitleBar ( + const ::rtl::OUString& rsTitle, + Window* pParentWindow, + Panel* pPanel, + const ::boost::function<void(void)>& rMenuAction) + : TitleBar(rsTitle, pParentWindow, GetBackgroundPaint()), + mbIsLeftButtonDown(false), + mpPanel(pPanel), + mnMenuItemIndex(1), + maMenuAction(rMenuAction) +{ + OSL_ASSERT(mpPanel != NULL); + + if (maMenuAction) + { + maToolBox.InsertItem( + mnMenuItemIndex, + Theme::GetImage(Theme::Image_PanelMenu)); + maToolBox.SetOutStyle(TOOLBOX_STYLE_FLAT); + } + +#ifdef DEBUG + SetText(A2S("PanelTitleBar")); +#endif +} + + + + +PanelTitleBar::~PanelTitleBar (void) +{ +} + + + + +Rectangle PanelTitleBar::GetTitleArea (const Rectangle& rTitleBarBox) +{ + if (mpPanel != NULL) + { + Image aImage (mpPanel->IsExpanded() + ? Theme::GetImage(Theme::Image_Expand) + : Theme::GetImage(Theme::Image_Collapse)); + return Rectangle( + aImage.GetSizePixel().Width() + gaLeftIconPadding + gaRightIconPadding, + rTitleBarBox.Top(), + rTitleBarBox.Right(), + rTitleBarBox.Bottom()); + } + else + return rTitleBarBox; +} + + + + +void PanelTitleBar::PaintDecoration (const Rectangle& rTitleBarBox) +{ + (void)rTitleBarBox; + + if (mpPanel != NULL) + { + Image aImage (mpPanel->IsExpanded() + ? Theme::GetImage(Theme::Image_Collapse) + : Theme::GetImage(Theme::Image_Expand)); + const Point aTopLeft ( + gaLeftIconPadding, + (GetSizePixel().Height()-aImage.GetSizePixel().Height())/2); + DrawImage(aTopLeft, aImage); + } +} + + + + +Paint PanelTitleBar::GetBackgroundPaint (void) +{ + return Theme::GetPaint(Theme::Paint_PanelTitleBarBackground); +} + + + + +Color PanelTitleBar::GetTextColor (void) +{ + return Theme::GetColor(Theme::Color_PanelTitleFont); +} + + + + +void PanelTitleBar::HandleToolBoxItemClick (const sal_uInt16 nItemIndex) +{ + if (nItemIndex == mnMenuItemIndex) + if (maMenuAction) + maMenuAction(); +} + + + + +void PanelTitleBar::MouseButtonDown (const MouseEvent& rMouseEvent) +{ + if (rMouseEvent.IsLeft()) + { + mbIsLeftButtonDown = true; + CaptureMouse(); + } +} + + + + +void PanelTitleBar::MouseButtonUp (const MouseEvent& rMouseEvent) +{ + if (IsMouseCaptured()) + ReleaseMouse(); + + if (rMouseEvent.IsLeft()) + { + if (mbIsLeftButtonDown) + { + if (mpPanel != NULL) + { + mpPanel->SetExpanded( ! mpPanel->IsExpanded()); + Invalidate(); + } + } + } + if (mbIsLeftButtonDown) + mbIsLeftButtonDown = false; +} + + + + +void PanelTitleBar::DataChanged (const DataChangedEvent& rEvent) +{ + maToolBox.SetItemImage( + mnMenuItemIndex, + Theme::GetImage(Theme::Image_PanelMenu)); + TitleBar::DataChanged(rEvent); +} + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/PanelTitleBar.hxx b/sfx2/source/sidebar/PanelTitleBar.hxx new file mode 100644 index 000000000000..f76edcb4eaad --- /dev/null +++ b/sfx2/source/sidebar/PanelTitleBar.hxx @@ -0,0 +1,62 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_PANEL_TITLE_BAR_HXX +#define SFX_SIDEBAR_PANEL_TITLE_BAR_HXX + +#include "TitleBar.hxx" + +#include <boost/function.hpp> + + +namespace sfx2 { namespace sidebar { + +class Panel; + +class PanelTitleBar + : public TitleBar +{ +public: + PanelTitleBar ( + const ::rtl::OUString& rsTitle, + Window* pParentWindow, + Panel* pPanel, + const ::boost::function<void(void)>& rMenuAction); + virtual ~PanelTitleBar (void); + + virtual void DataChanged (const DataChangedEvent& rEvent); + virtual void MouseButtonDown (const MouseEvent& rMouseEvent); + virtual void MouseButtonUp (const MouseEvent& rMouseEvent); + +protected: + virtual Rectangle GetTitleArea (const Rectangle& rTitleBarBox); + virtual void PaintDecoration (const Rectangle& rTitleBarBox); + virtual sidebar::Paint GetBackgroundPaint (void); + virtual Color GetTextColor (void); + virtual void HandleToolBoxItemClick (const sal_uInt16 nItemIndex); + +private: + bool mbIsLeftButtonDown; + Panel* mpPanel; + const sal_uInt16 mnMenuItemIndex; + const ::boost::function<void(void)> maMenuAction; +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/PopupContainer.cxx b/sfx2/source/sidebar/PopupContainer.cxx new file mode 100644 index 000000000000..adf55a1b2a9c --- /dev/null +++ b/sfx2/source/sidebar/PopupContainer.cxx @@ -0,0 +1,50 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "precompiled_sfx2.hxx" + +#include "sfx2/sidebar/PopupContainer.hxx" + +namespace sfx2 { namespace sidebar { + +PopupContainer::PopupContainer (Window* pParent) + : FloatingWindow(pParent, WB_SYSTEMWINDOW | WB_3DLOOK) +{ +} + + + + +PopupContainer::~PopupContainer (void) +{ +} + + + + +long PopupContainer::Notify (NotifyEvent& rEvent) +{ + if (rEvent.GetType() == EVENT_LOSEFOCUS) + { + if( ! HasChildPathFocus(sal_True)) + EndPopupMode(); + } + return FloatingWindow::Notify(rEvent); +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/ResourceManager.cxx b/sfx2/source/sidebar/ResourceManager.cxx new file mode 100644 index 000000000000..efb1fa134820 --- /dev/null +++ b/sfx2/source/sidebar/ResourceManager.cxx @@ -0,0 +1,621 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ResourceManager.hxx" +#include "Tools.hxx" + +#include <unotools/confignode.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/types.hxx> +#include <comphelper/stlunosequence.hxx> + +#include <rtl/ustrbuf.hxx> +#include <tools/diagnose_ex.h> + +#include <com/sun/star/frame/XModuleManager.hpp> + +#include <map> + + + +using ::rtl::OUString; +using namespace css; +using namespace cssu; + +namespace sfx2 { namespace sidebar { + +class ResourceManager::Deleter +{ +public: + void operator() (ResourceManager* pObject) + { + delete pObject; + } +}; + + +ResourceManager& ResourceManager::Instance (void) +{ + static ResourceManager maInstance; + return maInstance; +} + + + + +ResourceManager::ResourceManager (void) + : maDecks(), + maPanels(), + maProcessedApplications() +{ + ReadDeckList(); + ReadPanelList(); +} + + + + +ResourceManager::~ResourceManager (void) +{ + maPanels.clear(); + maDecks.clear(); +} + + + + +const DeckDescriptor* ResourceManager::GetBestMatchingDeck ( + const Context& rContext, + const Reference<frame::XFrame>& rxFrame) +{ + ReadLegacyAddons(rxFrame); + + for (DeckContainer::const_iterator iDeck(maDecks.begin()), iEnd(maDecks.end()); + iDeck!=iEnd; + ++iDeck) + { + if (iDeck->maContextList.GetMatch(rContext) != NULL) + return &*iDeck; + } + return NULL; +} + + + + +const DeckDescriptor* ResourceManager::GetDeckDescriptor ( + const ::rtl::OUString& rsDeckId) const +{ + for (DeckContainer::const_iterator + iDeck(maDecks.begin()), + iEnd(maDecks.end()); + iDeck!=iEnd; + ++iDeck) + { + if (iDeck->msId.equals(rsDeckId)) + return &*iDeck; + } + return NULL; +} + + + + +const PanelDescriptor* ResourceManager::GetPanelDescriptor ( + const ::rtl::OUString& rsPanelId) const +{ + for (PanelContainer::const_iterator + iPanel(maPanels.begin()), + iEnd(maPanels.end()); + iPanel!=iEnd; + ++iPanel) + { + if (iPanel->msId.equals(rsPanelId)) + return &*iPanel; + } + return NULL; +} + + + + +void ResourceManager::SetIsDeckEnabled ( + const ::rtl::OUString& rsDeckId, + const bool bIsEnabled) +{ + for (DeckContainer::iterator + iDeck(maDecks.begin()), + iEnd(maDecks.end()); + iDeck!=iEnd; + ++iDeck) + { + if (iDeck->msId.equals(rsDeckId)) + { + iDeck->mbIsEnabled = bIsEnabled; + return; + } + } +} + + + + +const ResourceManager::IdContainer& ResourceManager::GetMatchingDecks ( + IdContainer& rDeckIds, + const Context& rContext, + const Reference<frame::XFrame>& rxFrame) +{ + ReadLegacyAddons(rxFrame); + + ::std::multimap<sal_Int32,OUString> aOrderedIds; + for (DeckContainer::const_iterator + iDeck(maDecks.begin()), + iEnd (maDecks.end()); + iDeck!=iEnd; + ++iDeck) + { + const DeckDescriptor& rDeckDescriptor (*iDeck); + if (rDeckDescriptor.maContextList.GetMatch(rContext) != NULL) + aOrderedIds.insert(::std::multimap<sal_Int32,OUString>::value_type( + rDeckDescriptor.mnOrderIndex, + rDeckDescriptor.msId)); + } + + for (::std::multimap<sal_Int32,OUString>::const_iterator + iId(aOrderedIds.begin()), + iEnd(aOrderedIds.end()); + iId!=iEnd; + ++iId) + { + rDeckIds.push_back(iId->second); + } + + return rDeckIds; +} + + + + +const ResourceManager::PanelContextDescriptorContainer& ResourceManager::GetMatchingPanels ( + PanelContextDescriptorContainer& rPanelIds, + const Context& rContext, + const ::rtl::OUString& rsDeckId, + const Reference<frame::XFrame>& rxFrame) +{ + ReadLegacyAddons(rxFrame); + + ::std::multimap<sal_Int32,PanelContextDescriptor> aOrderedIds; + for (PanelContainer::const_iterator + iPanel(maPanels.begin()), + iEnd(maPanels.end()); + iPanel!=iEnd; + ++iPanel) + { + const PanelDescriptor& rPanelDescriptor (*iPanel); + if (rPanelDescriptor.msDeckId.equals(rsDeckId)) + { + const ContextList::Entry* pEntry = rPanelDescriptor.maContextList.GetMatch(rContext); + if (pEntry != NULL) + { + PanelContextDescriptor aPanelContextDescriptor; + aPanelContextDescriptor.msId = rPanelDescriptor.msId; + aPanelContextDescriptor.msMenuCommand = pEntry->msMenuCommand; + aPanelContextDescriptor.mbIsInitiallyVisible = pEntry->mbIsInitiallyVisible; + aOrderedIds.insert(::std::multimap<sal_Int32,PanelContextDescriptor>::value_type( + rPanelDescriptor.mnOrderIndex, + aPanelContextDescriptor)); + } + } + } + + for (::std::multimap<sal_Int32,PanelContextDescriptor>::const_iterator + iId(aOrderedIds.begin()), + iEnd(aOrderedIds.end()); + iId!=iEnd; + ++iId) + { + rPanelIds.push_back(iId->second); + } + + return rPanelIds; +} + + + + +void ResourceManager::ReadDeckList (void) +{ + const ::utl::OConfigurationTreeRoot aDeckRootNode ( + ::comphelper::getProcessComponentContext(), + A2S("org.openoffice.Office.UI.Sidebar/Content/DeckList"), + false); + if ( ! aDeckRootNode.isValid() ) + return; + + const Sequence<OUString> aDeckNodeNames (aDeckRootNode.getNodeNames()); + const sal_Int32 nCount (aDeckNodeNames.getLength()); + maDecks.resize(nCount); + sal_Int32 nWriteIndex(0); + for (sal_Int32 nReadIndex(0); nReadIndex<nCount; ++nReadIndex) + { + const ::utl::OConfigurationNode aDeckNode (aDeckRootNode.openNode(aDeckNodeNames[nReadIndex])); + if ( ! aDeckNode.isValid()) + continue; + + DeckDescriptor& rDeckDescriptor (maDecks[nWriteIndex++]); + + rDeckDescriptor.msTitle = ::comphelper::getString( + aDeckNode.getNodeValue("Title")); + rDeckDescriptor.msId = ::comphelper::getString( + aDeckNode.getNodeValue("Id")); + rDeckDescriptor.msIconURL = ::comphelper::getString( + aDeckNode.getNodeValue("IconURL")); + rDeckDescriptor.msHighContrastIconURL = ::comphelper::getString( + aDeckNode.getNodeValue("HighContrastIconURL")); + rDeckDescriptor.msHelpURL = ::comphelper::getString( + aDeckNode.getNodeValue("HelpURL")); + rDeckDescriptor.msHelpText = rDeckDescriptor.msTitle; + rDeckDescriptor.mbIsEnabled = true; + rDeckDescriptor.mnOrderIndex = ::comphelper::getINT32( + aDeckNode.getNodeValue("OrderIndex")); + + ReadContextList( + aDeckNode, + rDeckDescriptor.maContextList, + OUString()); + } + + // When there where invalid nodes then we have to adapt the size + // of the deck vector. + if (nWriteIndex<nCount) + maDecks.resize(nWriteIndex); +} + + + + +void ResourceManager::ReadPanelList (void) +{ + const ::utl::OConfigurationTreeRoot aPanelRootNode ( + ::comphelper::getProcessComponentContext(), + A2S("org.openoffice.Office.UI.Sidebar/Content/PanelList"), + false); + if ( ! aPanelRootNode.isValid() ) + return; + + const Sequence<OUString> aPanelNodeNames (aPanelRootNode.getNodeNames()); + const sal_Int32 nCount (aPanelNodeNames.getLength()); + maPanels.resize(nCount); + sal_Int32 nWriteIndex (0); + for (sal_Int32 nReadIndex(0); nReadIndex<nCount; ++nReadIndex) + { + const ::utl::OConfigurationNode aPanelNode (aPanelRootNode.openNode(aPanelNodeNames[nReadIndex])); + if ( ! aPanelNode.isValid()) + continue; + + PanelDescriptor& rPanelDescriptor (maPanels[nWriteIndex++]); + + rPanelDescriptor.msTitle = ::comphelper::getString( + aPanelNode.getNodeValue("Title")); + rPanelDescriptor.mbIsTitleBarOptional = ::comphelper::getBOOL( + aPanelNode.getNodeValue("TitleBarIsOptional")); + rPanelDescriptor.msId = ::comphelper::getString( + aPanelNode.getNodeValue("Id")); + rPanelDescriptor.msDeckId = ::comphelper::getString( + aPanelNode.getNodeValue("DeckId")); + rPanelDescriptor.msHelpURL = ::comphelper::getString( + aPanelNode.getNodeValue("HelpURL")); + rPanelDescriptor.msImplementationURL = ::comphelper::getString( + aPanelNode.getNodeValue("ImplementationURL")); + rPanelDescriptor.mnOrderIndex = ::comphelper::getINT32( + aPanelNode.getNodeValue("OrderIndex")); + rPanelDescriptor.mbWantsCanvas = ::comphelper::getBOOL( + aPanelNode.getNodeValue("WantsCanvas")); + const OUString sDefaultMenuCommand (::comphelper::getString( + aPanelNode.getNodeValue("DefaultMenuCommand"))); + + ReadContextList( + aPanelNode, + rPanelDescriptor.maContextList, + sDefaultMenuCommand); + } + + // When there where invalid nodes then we have to adapt the size + // of the deck vector. + if (nWriteIndex<nCount) + maPanels.resize(nWriteIndex); +} + + + + +void ResourceManager::ReadContextList ( + const ::utl::OConfigurationNode& rParentNode, + ContextList& rContextList, + const OUString& rsDefaultMenuCommand) const +{ + const Any aValue = rParentNode.getNodeValue("ContextList"); + Sequence<OUString> aValues; + sal_Int32 nCount; + if (aValue >>= aValues) + nCount = aValues.getLength(); + else + nCount = 0; + + for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex) + { + const OUString sValue (aValues[nIndex]); + sal_Int32 nCharacterIndex (0); + const OUString sApplicationName (sValue.getToken(0, ',', nCharacterIndex).trim()); + if (nCharacterIndex < 0) + { + if (sApplicationName.getLength() == 0) + { + // This is a valid case: in the XML file the separator + // was used as terminator. Using it in the last line + // creates an additional but empty entry. + break; + } + else + { + OSL_ASSERT("expecting three or four values per ContextList entry, separated by comma"); + continue; + } + } + + const OUString sContextName (sValue.getToken(0, ',', nCharacterIndex).trim()); + if (nCharacterIndex < 0) + { + OSL_ASSERT("expecting three or four values per ContextList entry, separated by comma"); + continue; + } + + const OUString sInitialState (sValue.getToken(0, ',', nCharacterIndex).trim()); + + // The fourth argument is optional. + const OUString sMenuCommandOverride ( + nCharacterIndex<0 + ? OUString() + : sValue.getToken(0, ',', nCharacterIndex).trim()); + const OUString sMenuCommand ( + sMenuCommandOverride.getLength()>0 + ? (sMenuCommandOverride.equalsAscii("none") + ? OUString() + : sMenuCommandOverride) + : rsDefaultMenuCommand); + + EnumContext::Application eApplication (EnumContext::GetApplicationEnum(sApplicationName)); + EnumContext::Application eApplication2 (EnumContext::Application_None); + if (eApplication == EnumContext::Application_None + && !sApplicationName.equals(EnumContext::GetApplicationName(EnumContext::Application_None))) + { + // Handle some special names: abbreviations that make + // context descriptions more readable. + if (sApplicationName.equalsAscii("Writer")) + eApplication = EnumContext::Application_Writer; + else if (sApplicationName.equalsAscii("Calc")) + eApplication = EnumContext::Application_Calc; + else if (sApplicationName.equalsAscii("Draw")) + eApplication = EnumContext::Application_Draw; + else if (sApplicationName.equalsAscii("Impress")) + eApplication = EnumContext::Application_Impress; + else if (sApplicationName.equalsAscii("DrawImpress")) + { + // A special case among the special names: it is + // common to use the same context descriptions for + // both Draw and Impress. This special case helps to + // avoid duplication in the .xcu file. + eApplication = EnumContext::Application_Draw; + eApplication2 = EnumContext::Application_Impress; + } + else if (sApplicationName.equalsAscii("WriterAndWeb")) + { + // Another special case for Writer and WriterWeb. + eApplication = EnumContext::Application_Writer; + eApplication2 = EnumContext::Application_WriterWeb; + } + else + { + OSL_ASSERT("application name not recognized"); + continue; + } + } + + const EnumContext::Context eContext (EnumContext::GetContextEnum(sContextName)); + if (eContext == EnumContext::Context_Unknown) + { + OSL_ASSERT("context name not recognized"); + continue; + } + + bool bIsInitiallyVisible; + if (sInitialState.equalsAscii("visible")) + bIsInitiallyVisible = true; + else if (sInitialState.equalsAscii("hidden")) + bIsInitiallyVisible = false; + else + { + OSL_ASSERT("unrecognized state"); + continue; + } + + if (eApplication != EnumContext::Application_None) + rContextList.AddContextDescription( + Context( + EnumContext::GetApplicationName(eApplication), + EnumContext::GetContextName(eContext)), + bIsInitiallyVisible, + sMenuCommand); + if (eApplication2 != EnumContext::Application_None) + rContextList.AddContextDescription( + Context( + EnumContext::GetApplicationName(eApplication2), + EnumContext::GetContextName(eContext)), + bIsInitiallyVisible, + sMenuCommand); + } +} + + + + +void ResourceManager::ReadLegacyAddons (const Reference<frame::XFrame>& rxFrame) +{ + // Get module name for given frame. + ::rtl::OUString sModuleName (GetModuleName(rxFrame)); + if (sModuleName.getLength() == 0) + return; + if (maProcessedApplications.find(sModuleName) != maProcessedApplications.end()) + { + // Addons for this application have already been read. + // There is nothing more to do. + return; + } + + // Mark module as processed. Even when there is an error that + // prevents the configuration data from being read, this error + // will not be triggered a second time. + maProcessedApplications.insert(sModuleName); + + // Get access to the configuration root node for the application. + ::utl::OConfigurationTreeRoot aLegacyRootNode (GetLegacyAddonRootNode(sModuleName)); + if ( ! aLegacyRootNode.isValid()) + return; + + // Process child nodes. + ::std::vector<OUString> aMatchingNodeNames; + GetToolPanelNodeNames(aMatchingNodeNames, aLegacyRootNode); + const sal_Int32 nCount (aMatchingNodeNames.size()); + size_t nDeckWriteIndex (maDecks.size()); + size_t nPanelWriteIndex (maPanels.size()); + maDecks.resize(maDecks.size() + nCount); + maPanels.resize(maPanels.size() + nCount); + for (sal_Int32 nReadIndex(0); nReadIndex<nCount; ++nReadIndex) + { + const OUString& rsNodeName (aMatchingNodeNames[nReadIndex]); + const ::utl::OConfigurationNode aChildNode (aLegacyRootNode.openNode(rsNodeName)); + if ( ! aChildNode.isValid()) + continue; + + DeckDescriptor& rDeckDescriptor (maDecks[nDeckWriteIndex++]); + rDeckDescriptor.msTitle = ::comphelper::getString(aChildNode.getNodeValue("UIName")); + rDeckDescriptor.msId = rsNodeName; + rDeckDescriptor.msIconURL = ::comphelper::getString(aChildNode.getNodeValue("ImageURL")); + rDeckDescriptor.msHighContrastIconURL = rDeckDescriptor.msIconURL; + rDeckDescriptor.msHelpURL = ::comphelper::getString(aChildNode.getNodeValue("HelpURL")); + rDeckDescriptor.msHelpText = rDeckDescriptor.msTitle; + rDeckDescriptor.maContextList.AddContextDescription(Context(sModuleName, A2S("any")), true, OUString()); + rDeckDescriptor.mbIsEnabled = true; + + PanelDescriptor& rPanelDescriptor (maPanels[nPanelWriteIndex++]); + rPanelDescriptor.msTitle = ::comphelper::getString(aChildNode.getNodeValue("UIName")); + rPanelDescriptor.mbIsTitleBarOptional = true; + rPanelDescriptor.msId = rsNodeName; + rPanelDescriptor.msDeckId = rsNodeName; + rPanelDescriptor.msHelpURL = ::comphelper::getString(aChildNode.getNodeValue("HelpURL")); + rPanelDescriptor.maContextList.AddContextDescription(Context(sModuleName, A2S("any")), true, OUString()); + rPanelDescriptor.msImplementationURL = rsNodeName; + } + + // When there where invalid nodes then we have to adapt the size + // of the deck and panel vectors. + if (nDeckWriteIndex < maDecks.size()) + maDecks.resize(nDeckWriteIndex); + if (nPanelWriteIndex < maPanels.size()) + maPanels.resize(nPanelWriteIndex); +} + + + + +::rtl::OUString ResourceManager::GetModuleName ( + const cssu::Reference<css::frame::XFrame>& rxFrame) +{ + if ( ! rxFrame.is() || ! rxFrame->getController().is()) + return OUString(); + + try + { + const ::comphelper::ComponentContext aContext (::comphelper::getProcessServiceFactory()); + const Reference<frame::XModuleManager> xModuleManager ( + aContext.createComponent("com.sun.star.frame.ModuleManager"), + UNO_QUERY_THROW); + return xModuleManager->identify(rxFrame); + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + return OUString(); +} + + + + +::utl::OConfigurationTreeRoot ResourceManager::GetLegacyAddonRootNode ( + const ::rtl::OUString& rsModuleName) const +{ + try + { + const ::comphelper::ComponentContext aContext (::comphelper::getProcessServiceFactory()); + const Reference<container::XNameAccess> xModuleAccess ( + aContext.createComponent("com.sun.star.frame.ModuleManager"), + UNO_QUERY_THROW); + const ::comphelper::NamedValueCollection aModuleProperties (xModuleAccess->getByName(rsModuleName)); + const ::rtl::OUString sWindowStateRef (aModuleProperties.getOrDefault( + "ooSetupFactoryWindowStateConfigRef", + ::rtl::OUString())); + + ::rtl::OUStringBuffer aPathComposer; + aPathComposer.appendAscii("org.openoffice.Office.UI."); + aPathComposer.append(sWindowStateRef); + aPathComposer.appendAscii("/UIElements/States"); + + return ::utl::OConfigurationTreeRoot(::comphelper::getProcessComponentContext(), + aPathComposer.makeStringAndClear(), false); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return ::utl::OConfigurationTreeRoot(); +} + + + + +void ResourceManager::GetToolPanelNodeNames ( + ::std::vector<OUString>& rMatchingNames, + const ::utl::OConfigurationTreeRoot aRoot) const +{ + Sequence<OUString> aChildNodeNames (aRoot.getNodeNames()); + const sal_Int32 nCount (aChildNodeNames.getLength()); + for (sal_Int32 nIndex(0); nIndex<nCount; ++nIndex) + { + if (aChildNodeNames[nIndex].matchAsciiL( + RTL_CONSTASCII_STRINGPARAM( "private:resource/toolpanel/"))) + rMatchingNames.push_back(aChildNodeNames[nIndex]); + } +} + + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/ResourceManager.hxx b/sfx2/source/sidebar/ResourceManager.hxx new file mode 100644 index 000000000000..cc9093c34b92 --- /dev/null +++ b/sfx2/source/sidebar/ResourceManager.hxx @@ -0,0 +1,121 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_RESOURCE_MANAGER_HXX +#define SFX_SIDEBAR_RESOURCE_MANAGER_HXX + +#include "DeckDescriptor.hxx" +#include "PanelDescriptor.hxx" +#include "Context.hxx" +#include <unotools/confignode.hxx> +#include <com/sun/star/frame/XFrame.hpp> +#include <set> +#include <boost/shared_ptr.hpp> + + +namespace css = ::com::sun::star; +namespace cssu = ::com::sun::star::uno; + +namespace sfx2 { namespace sidebar { + +class Context; +class ContextList; + +/** Read the content of the Sidebar.xcu file and provide access + methods so that the sidebar can easily decide which content panels + to display for a certain context. +*/ +class ResourceManager +{ +public: + static ResourceManager& Instance (void); + + const DeckDescriptor* GetBestMatchingDeck ( + const Context& rContext, + const cssu::Reference<css::frame::XFrame>& rxFrame); + + const DeckDescriptor* GetDeckDescriptor ( + const ::rtl::OUString& rsDeckId) const; + const PanelDescriptor* GetPanelDescriptor ( + const ::rtl::OUString& rsPanelId) const; + + /** Excluded or include a deck from being displayed in the tab + bar. + Note that this value is not persistent. + The flag can not be set directly at a DeckDescriptor object + because the ResourceManager gives access to to them only + read-only. + */ + void SetIsDeckEnabled ( + const ::rtl::OUString& rsDeckId, + const bool bIsEnabled); + + typedef ::std::vector<rtl::OUString> IdContainer; + class PanelContextDescriptor + { + public: + ::rtl::OUString msId; + ::rtl::OUString msMenuCommand; + bool mbIsInitiallyVisible; + }; + typedef ::std::vector<PanelContextDescriptor> PanelContextDescriptorContainer; + + const IdContainer& GetMatchingDecks ( + IdContainer& rDeckDescriptors, + const Context& rContext, + const cssu::Reference<css::frame::XFrame>& rxFrame); + + const PanelContextDescriptorContainer& GetMatchingPanels ( + PanelContextDescriptorContainer& rPanelDescriptors, + const Context& rContext, + const ::rtl::OUString& rsDeckId, + const cssu::Reference<css::frame::XFrame>& rxFrame); + + static ::rtl::OUString GetModuleName ( + const cssu::Reference<css::frame::XFrame>& rxFrame); + +private: + ResourceManager (void); + ~ResourceManager (void); + class Deleter; + friend class Deleter; + + typedef ::std::vector<DeckDescriptor> DeckContainer; + DeckContainer maDecks; + typedef ::std::vector<PanelDescriptor> PanelContainer; + PanelContainer maPanels; + mutable ::std::set<rtl::OUString> maProcessedApplications; + + void ReadDeckList (void); + void ReadPanelList (void); + void ReadContextList ( + const ::utl::OConfigurationNode& rNode, + ContextList& rContextList, + const ::rtl::OUString& rsDefaultMenuCommand) const; + void ReadLegacyAddons ( + const cssu::Reference<css::frame::XFrame>& rxFrame); + ::utl::OConfigurationTreeRoot GetLegacyAddonRootNode ( + const ::rtl::OUString& rsModuleName) const; + void GetToolPanelNodeNames ( + ::std::vector<rtl::OUString>& rMatchingNames, + const ::utl::OConfigurationTreeRoot aRoot) const; +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/Sidebar.cxx b/sfx2/source/sidebar/Sidebar.cxx new file mode 100644 index 000000000000..af3797a2b49a --- /dev/null +++ b/sfx2/source/sidebar/Sidebar.cxx @@ -0,0 +1,77 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "precompiled_sfx2.hxx" + +#include "Sidebar.hxx" +#include "ResourceManager.hxx" + +using namespace css; +using namespace cssu; + +namespace sfx2 { namespace sidebar { + +Sidebar::Sidebar( + Window& rParentWindow, + const Reference<frame::XFrame>& rxDocumentFrame) + : Window(&rParentWindow, WB_DIALOGCONTROL) +{ + ContentPanelManager::Instance(); +} + + + + +Sidebar::~Sidebar (void) +{ +} + + + + +void Sidebar::Resize (void) +{ + Window::Resize(); + // m_pImpl->OnResize(); +} + + + + +void Sidebar::GetFocus (void) +{ + Window::GetFocus(); + // m_pImpl->OnGetFocus(); +} + + + + +void Sidebar::DataChanged (const DataChangedEvent& rDataChangedEvent) +{ + if (rDataChangedEvent.GetType() == DATACHANGED_SETTINGS + && (rDataChangedEvent.GetFlags() & SETTINGS_STYLE)!= 0) + { + Invalidate(); + } + else + Window::DataChanged(rDataChangedEvent); +} + + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/Sidebar.hrc b/sfx2/source/sidebar/Sidebar.hrc new file mode 100644 index 000000000000..852648c6a929 --- /dev/null +++ b/sfx2/source/sidebar/Sidebar.hrc @@ -0,0 +1,53 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include <sfx2/sfx.hrc> + +#define RID_SIDEBAR_RESOURCE (RID_SFX_SIDEBAR_START + 0) + +#define IMAGE_SIDEBAR_PLUS 1 +#define IMAGE_SIDEBAR_MINUS 3 +#define IMAGE_SIDEBAR_GRIP 5 +#define IMAGE_SIDEBAR_MENU 7 +#define IMAGE_SIDEBAR_DETAIL_DIALOG 9 +#define IMAGE_SIDEBAR_TOOLBOX_SEPARATOR 11 +#define IMAGE_SIDEBAR_DECK_3D_LARGE 20 +#define IMAGE_SIDEBAR_DECK_3D_SMALL 22 +#define IMAGE_SIDEBAR_DECK_ANIMATION_LARGE 30 +#define IMAGE_SIDEBAR_DECK_ANIMATION_SMALL 32 +#define IMAGE_SIDEBAR_DECK_COLORS_LARGE 40 +#define IMAGE_SIDEBAR_DECK_COLORS_SMALL 42 +#define IMAGE_SIDEBAR_DECK_EYEDROPPER_LARGE 50 +#define IMAGE_SIDEBAR_DECK_EYEDROPPER_SMALL 52 +#define IMAGE_SIDEBAR_DECK_GALLERY_LARGE 60 +#define IMAGE_SIDEBAR_DECK_GALLERY_SMALL 62 +#define IMAGE_SIDEBAR_DECK_IMGANIM_LARGE 70 +#define IMAGE_SIDEBAR_DECK_IMGANIM_SMALL 72 +#define IMAGE_SIDEBAR_DECK_NAVIGATOR_LARGE 80 +#define IMAGE_SIDEBAR_DECK_NAVIGATOR_SMALL 82 +#define IMAGE_SIDEBAR_PROPERTIES_DECK_LARGE 90 +#define IMAGE_SIDEBAR_PROPERTIES_DECK_SMALL 92 +#define IMAGE_SIDEBAR_DECK_STYLE_LARGE 100 +#define IMAGE_SIDEBAR_DECK_STYLE_SMALL 102 +#define IMAGE_SIDEBAR_DECK_TEMPLATE_LARGE 110 +#define IMAGE_SIDEBAR_DECK_TEMPLATE_SMALL 112 +#define IMAGE_SIDEBAR_DECK_TRANSITION_LARGE 120 +#define IMAGE_SIDEBAR_DECK_TRANSITION_SMALL 122 +#define IMAGE_SIDEBAR_DECK_FUNCTIONS_LARGE 130 +#define IMAGE_SIDEBAR_DECK_FUNCTIONS_SMALL 132 +#define STRING_CUSTOMIZATION 200 +#define STRING_RESTORE 201 diff --git a/sfx2/source/sidebar/Sidebar.hxx b/sfx2/source/sidebar/Sidebar.hxx new file mode 100644 index 000000000000..e225bdf8aaa8 --- /dev/null +++ b/sfx2/source/sidebar/Sidebar.hxx @@ -0,0 +1,64 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_HXX +#define SFX_SIDEBAR_HXX + +#include "sfx2/dllapi.h" +#include <vcl/window.hxx> +#include <com/sun/star/frame/XFrame.hpp> + + +namespace css = ::com::sun::star; +namespace cssu = ::com::sun::star::uno; + +namespace sfx2 { namespace sidebar { + + +/** SFX-less version of a module dependent task pane, filled with tool panels as specified in the respective + module's configuration +*/ +class SFX2_DLLPUBLIC Sidebar + : public Window +{ +public: + /** creates a new instance + @param i_rParentWindow + the parent window + @param i_rDocumentFrame + the frame to which the task pane belongs. Will be passed to any custom tool panels created + via an XUIElementFactory. Also, it is used to determine the module which the task pane is + responsible for, thus controlling which tool panels are actually available. + */ + Sidebar( + Window& rParentWindow, + const cssu::Reference<css::frame::XFrame>& rxDocumentFrame); + + + virtual ~Sidebar (void); + +protected: + virtual void Resize (void); + virtual void GetFocus (void); + +private: +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/Sidebar.src b/sfx2/source/sidebar/Sidebar.src new file mode 100644 index 000000000000..64eef88e3a23 --- /dev/null +++ b/sfx2/source/sidebar/Sidebar.src @@ -0,0 +1,158 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "Sidebar.hrc" + +Resource RID_SIDEBAR_RESOURCE +{ + Image IMAGE_SIDEBAR_PLUS + { + ImageBitmap = Bitmap { File = "plus.png" ;}; + }; + + Image IMAGE_SIDEBAR_MINUS + { + ImageBitmap = Bitmap { File = "minus.png" ;}; + }; + + Image IMAGE_SIDEBAR_GRIP + { + ImageBitmap = Bitmap { File = "grip.png" ;}; + }; + + Image IMAGE_SIDEBAR_MENU + { + ImageBitmap = Bitmap { File = "symphony/open_more.png" ;}; + }; + + Image IMAGE_SIDEBAR_DETAIL_DIALOG + { + ImageBitmap = Bitmap { File = "symphony/morebutton.png" ;}; + }; + + Image IMAGE_SIDEBAR_TOOLBOX_SEPARATOR + { + ImageBitmap = Bitmap { File = "separator.png" ;}; + }; + + Image IMAGE_SIDEBAR_DECK_3D_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-3d-large.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_3D_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-3d-small.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_ANIMATION_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-animation-large.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_ANIMATION_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-animation-small.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_COLORS_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-colors-large.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_COLORS_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-colors-small.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_EYEDROPPER_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-eyedropper-large.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_EYEDROPPER_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-eyedropper-small.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_GALLERY_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-gallery-large.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_GALLERY_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-gallery-small.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_IMGANIM_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-imganim-large.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_IMGANIM_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-imganim-small.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_NAVIGATOR_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-navigator-large.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_NAVIGATOR_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-navigator-small.png" ;}; + }; + Image IMAGE_SIDEBAR_PROPERTIES_DECK_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-property-large.png" ;}; + }; + Image IMAGE_SIDEBAR_PROPERTIES_DECK_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-property-small.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_STYLE_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-style-large.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_STYLE_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-style-small.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_TEMPLATE_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-template-large.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_TEMPLATE_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-template-small.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_TRANSITION_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-transition-large.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_TRANSITION_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-transition-small.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_FUNCTIONS_LARGE + { + ImageBitmap = Bitmap { File = "symphony/sidebar-functions-large.png" ;}; + }; + Image IMAGE_SIDEBAR_DECK_FUNCTIONS_SMALL + { + ImageBitmap = Bitmap { File = "symphony/sidebar-functions-small.png" ;}; + }; + String STRING_CUSTOMIZATION + { + Text [en-US] = "Customization"; + }; + String STRING_RESTORE + { + Text [en-US] = "Restore Default"; + }; +}; + + diff --git a/sfx2/source/sidebar/SidebarChildWindow.cxx b/sfx2/source/sidebar/SidebarChildWindow.cxx new file mode 100644 index 000000000000..2fdf0a23d865 --- /dev/null +++ b/sfx2/source/sidebar/SidebarChildWindow.cxx @@ -0,0 +1,56 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "sfx2/sidebar/SidebarChildWindow.hxx" +#include "SidebarDockingWindow.hxx" +#include "sfx2/sfxsids.hrc" +#include "helpid.hrc" +#include "sfx2/dockwin.hxx" +#include <sfx2/sidebar/ResourceDefinitions.hrc> + + +namespace sfx2 { namespace sidebar { + + +SFX_IMPL_DOCKINGWINDOW_WITHID(SidebarChildWindow, SID_SIDEBAR); + + +SidebarChildWindow::SidebarChildWindow ( + Window* pSidebarParent, + sal_uInt16 nId, + SfxBindings* pBindings, + SfxChildWinInfo* pInfo ) + : SfxChildWindow(pSidebarParent, nId) +{ + this->pWindow = new SidebarDockingWindow( + pBindings, + *this, + pSidebarParent, + WB_STDDOCKWIN | WB_OWNERDRAWDECORATION | WB_CLIPCHILDREN | WB_SIZEABLE | WB_3DLOOK | WB_ROLLABLE); + eChildAlignment = SFX_ALIGN_RIGHT; + + this->pWindow->SetHelpId(HID_SIDEBAR_WINDOW); + this->pWindow->SetOutputSizePixel(Size(300, 450)); + + dynamic_cast<SfxDockingWindow*>(pWindow)->Initialize(pInfo); + SetHideNotDelete(sal_True); + + this->pWindow->Show(); +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/SidebarController.cxx b/sfx2/source/sidebar/SidebarController.cxx new file mode 100644 index 000000000000..08e1e6d420ff --- /dev/null +++ b/sfx2/source/sidebar/SidebarController.cxx @@ -0,0 +1,927 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "SidebarController.hxx" +#include "Deck.hxx" +#include "DeckTitleBar.hxx" +#include "Panel.hxx" +#include "SidebarPanel.hxx" +#include "SidebarResource.hxx" +#include "TabBar.hxx" +#include "sfx2/sidebar/Theme.hxx" +#include "SidebarDockingWindow.hxx" +#include "Context.hxx" +#include "Tools.hxx" + +#include "sfxresid.hxx" +#include "sfx2/sfxsids.hrc" +#include "sfx2/titledockwin.hxx" +#include "sfxlocal.hrc" +#include <vcl/floatwin.hxx> +#include "splitwin.hxx" +#include <svl/smplhint.hxx> +#include <tools/link.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/namedvaluecollection.hxx> + +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/ui/ContextChangeEventMultiplexer.hpp> +#include <com/sun/star/ui/ContextChangeEventObject.hpp> +#include <com/sun/star/ui/XUIElementFactory.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/util/URL.hpp> + +#include <boost/bind.hpp> +#include <boost/function.hpp> +#include <boost/scoped_array.hpp> + + +using namespace css; +using namespace cssu; +using ::rtl::OUString; + + + +namespace sfx2 { namespace sidebar { + +namespace { + enum MenuId + { + MID_UNLOCK_TASK_PANEL = 1, + MID_LOCK_TASK_PANEL, + MID_CUSTOMIZATION, + MID_RESTORE_DEFAULT, + MID_FIRST_PANEL, + MID_FIRST_HIDE = 1000 + }; +} + + +SidebarController::SidebarController ( + SidebarDockingWindow* pParentWindow, + const cssu::Reference<css::frame::XFrame>& rxFrame) + : SidebarControllerInterfaceBase(m_aMutex), + mpCurrentDeck(), + mpParentWindow(pParentWindow), + mpTabBar(new TabBar( + mpParentWindow, + rxFrame, + ::boost::bind(&SidebarController::SwitchToDeck, this, _1), + ::boost::bind(&SidebarController::ShowPopupMenu, this, _1,_2,_3))), + mxFrame(rxFrame), + maCurrentContext(OUString(), OUString()), + msCurrentDeckId(A2S("PropertyDeck")), + maPropertyChangeForwarder(::boost::bind(&SidebarController::BroadcastPropertyChange, this)), + mbIsDeckClosed(false), + mnSavedSidebarWidth(pParentWindow->GetSizePixel().Width()) +{ + if (pParentWindow == NULL) + { + OSL_ASSERT(pParentWindow!=NULL); + return; + } + + // Listen for context change events. + cssu::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer ( + css::ui::ContextChangeEventMultiplexer::get( + ::comphelper::getProcessComponentContext())); + if (xMultiplexer.is()) + xMultiplexer->addContextChangeEventListener( + static_cast<css::ui::XContextChangeEventListener*>(this), + mxFrame->getController()); + + // Listen for window events. + mpParentWindow->AddEventListener(LINK(this, SidebarController, WindowEventHandler)); + + // Listen for theme property changes. + Theme::GetPropertySet()->addPropertyChangeListener( + A2S(""), + static_cast<css::beans::XPropertyChangeListener*>(this)); + + SwitchToDeck(A2S("default")); +} + + + + +SidebarController::~SidebarController (void) +{ +} + + + + +void SAL_CALL SidebarController::disposing (void) +{ + maFocusManager.Clear(); + + cssu::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer ( + css::ui::ContextChangeEventMultiplexer::get( + ::comphelper::getProcessComponentContext())); + if (xMultiplexer.is()) + xMultiplexer->removeAllContextChangeEventListeners( + static_cast<css::ui::XContextChangeEventListener*>(this)); + + if (mpParentWindow != NULL) + { + mpParentWindow->RemoveEventListener(LINK(this, SidebarController, WindowEventHandler)); + mpParentWindow = NULL; + } + + if (mpCurrentDeck) + { + mpCurrentDeck->Dispose(); + OSL_TRACE("deleting deck window subtree"); + mpCurrentDeck->PrintWindowTree(); + mpCurrentDeck.reset(); + } + + mpTabBar.reset(); + + Theme::GetPropertySet()->removePropertyChangeListener( + A2S(""), + static_cast<css::beans::XPropertyChangeListener*>(this)); +} + + + + +void SAL_CALL SidebarController::notifyContextChangeEvent (const css::ui::ContextChangeEventObject& rEvent) + throw(cssu::RuntimeException) +{ + UpdateConfigurations( + Context( + rEvent.ApplicationName, + rEvent.ContextName)); +} + + + + +void SAL_CALL SidebarController::disposing (const css::lang::EventObject& rEventObject) + throw(cssu::RuntimeException) +{ + (void)rEventObject; + + dispose(); +} + + + + +void SAL_CALL SidebarController::propertyChange (const css::beans::PropertyChangeEvent& rEvent) + throw(cssu::RuntimeException) +{ + (void)rEvent; + + maPropertyChangeForwarder.RequestCall(); +} + + + + +void SAL_CALL SidebarController::requestLayout (void) + throw(cssu::RuntimeException) +{ + if (mpCurrentDeck) + mpCurrentDeck->RequestLayout(); + RestrictWidth(); +} + + + + +void SidebarController::BroadcastPropertyChange (void) +{ + DataChangedEvent aEvent (DATACHANGED_USER); + mpParentWindow->NotifyAllChildren(aEvent); + mpParentWindow->Invalidate(INVALIDATE_CHILDREN); +} + + + + +void SidebarController::NotifyResize (void) +{ + if (mpTabBar == NULL) + { + OSL_ASSERT(mpTabBar!=NULL); + return; + } + + Window* pParentWindow = mpTabBar->GetParent(); + + const sal_Int32 nWidth (pParentWindow->GetSizePixel().Width()); + const sal_Int32 nHeight (pParentWindow->GetSizePixel().Height()); + + // Place the deck. + if (mpCurrentDeck) + { + mpCurrentDeck->setPosSizePixel(0,0, nWidth-TabBar::GetDefaultWidth(), nHeight); + mpCurrentDeck->Show(); + mpCurrentDeck->RequestLayout(); + } + + // Place the tab bar. + mpTabBar->setPosSizePixel(nWidth-TabBar::GetDefaultWidth(),0,TabBar::GetDefaultWidth(),nHeight); + mpTabBar->Show(); + + // Determine if the closer of the deck can be shown. + if (mpCurrentDeck) + { + DeckTitleBar* pTitleBar = mpCurrentDeck->GetTitleBar(); + if (pTitleBar != NULL && pTitleBar->IsVisible()) + pTitleBar->SetCloserVisible(CanModifyChildWindowWidth()); + } + + if (nWidth > TabBar::GetDefaultWidth()) + mnSavedSidebarWidth = nWidth; + + RestrictWidth(); +#ifdef DEBUG + if (mpCurrentDeck) + { + mpCurrentDeck->PrintWindowTree(); + sal_Int32 nPanelIndex (0); + for (SharedPanelContainer::const_iterator + iPanel(mpCurrentDeck->GetPanels().begin()), + iEnd(mpCurrentDeck->GetPanels().end()); + iPanel!=iEnd; + ++iPanel,++nPanelIndex) + { + OSL_TRACE("panel %d:", nPanelIndex); + (*iPanel)->PrintWindowTree(); + } + } +#endif +} + + + + +void SidebarController::UpdateConfigurations (const Context& rContext) +{ + if (maCurrentContext != rContext) + { + maCurrentContext = rContext; + + // Notify the tab bar about the updated set of decks. + ResourceManager::IdContainer aDeckIds; + ResourceManager::Instance().GetMatchingDecks ( + aDeckIds, + rContext, + mxFrame); + mpTabBar->SetDecks(aDeckIds); + + // Check if the current deck is among the matching decks. + bool bCurrentDeckMatches (false); + for (ResourceManager::IdContainer::const_iterator + iDeck(aDeckIds.begin()), + iEnd(aDeckIds.end()); + iDeck!=iEnd; + ++iDeck) + { + if (iDeck->equals(msCurrentDeckId)) + { + bCurrentDeckMatches = true; + break; + } + } + + DeckDescriptor const* pDeckDescriptor = NULL; + if ( ! bCurrentDeckMatches) + pDeckDescriptor = ResourceManager::Instance().GetBestMatchingDeck(rContext, mxFrame); + else + pDeckDescriptor = ResourceManager::Instance().GetDeckDescriptor(msCurrentDeckId); + if (pDeckDescriptor != NULL) + { + msCurrentDeckId = pDeckDescriptor->msId; + SwitchToDeck(*pDeckDescriptor, rContext); + } + +#ifdef DEBUG + // Show the context name in the deck title bar. + if (mpCurrentDeck) + { + DeckTitleBar* pTitleBar = mpCurrentDeck->GetTitleBar(); + if (pTitleBar != NULL) + pTitleBar->SetTitle(msCurrentDeckTitle+A2S(" (")+rContext.msContext+A2S(")")); + } +#endif + } +} + + + + +void SidebarController::SwitchToDeck ( + const ::rtl::OUString& rsDeckId) +{ + if ( ! msCurrentDeckId.equals(rsDeckId) || mbIsDeckClosed) + { + const DeckDescriptor* pDeckDescriptor = ResourceManager::Instance().GetDeckDescriptor(rsDeckId); + if (pDeckDescriptor != NULL) + SwitchToDeck(*pDeckDescriptor, maCurrentContext); + } +} + + + + +void SidebarController::SwitchToDeck ( + const DeckDescriptor& rDeckDescriptor, + const Context& rContext) +{ + maFocusManager.Clear(); + + if ( ! msCurrentDeckId.equals(rDeckDescriptor.msId)) + { + // When the deck changes then destroy the deck and all panels + // and create everything new. + if (mpCurrentDeck) + { + mpCurrentDeck->Dispose(); + mpCurrentDeck.reset(); + } + + msCurrentDeckId = rDeckDescriptor.msId; + } + + // Reopen the deck when necessary. + OpenDeck(); + + // Determine the panels to display in the deck. + ResourceManager::PanelContextDescriptorContainer aPanelContextDescriptors; + ResourceManager::Instance().GetMatchingPanels( + aPanelContextDescriptors, + rContext, + rDeckDescriptor.msId, + mxFrame); + + if (aPanelContextDescriptors.empty()) + { + // There are no panels to be displayed in the current context. + if (EnumContext::GetContextEnum(rContext.msContext) != EnumContext::Context_Empty) + { + // Switch to the "empty" context and try again. + SwitchToDeck( + rDeckDescriptor, + Context( + rContext.msApplication, + EnumContext::GetContextName(EnumContext::Context_Empty))); + return; + } + else + { + // This is already the "empty" context. Looks like we have + // to live with an empty deck. + } + } + + if (mpCurrentDeck + && ArePanelSetsEqual(mpCurrentDeck->GetPanels(), aPanelContextDescriptors)) + { + // Requested set of panels is identical to the current set of + // panels => Nothing to do. + return; + } + + // Provide a configuration and Deck object. + if ( ! mpCurrentDeck) + { + mpCurrentDeck.reset( + new Deck( + rDeckDescriptor, + mpParentWindow, + ::boost::bind(&SidebarController::CloseDeck, this))); + msCurrentDeckTitle = rDeckDescriptor.msTitle; + } + if ( ! mpCurrentDeck) + return; + + // Update the panel list. + const sal_Int32 nNewPanelCount (aPanelContextDescriptors.size()); + SharedPanelContainer aNewPanels; + const SharedPanelContainer& rCurrentPanels (mpCurrentDeck->GetPanels()); + aNewPanels.resize(nNewPanelCount); + sal_Int32 nWriteIndex (0); + bool bHasPanelSetChanged (false); + for (sal_Int32 nReadIndex=0; nReadIndex<nNewPanelCount; ++nReadIndex) + { + const ResourceManager::PanelContextDescriptor& rPanelContexDescriptor ( + aPanelContextDescriptors[nReadIndex]); + + // Find the corresponding panel among the currently active + // panels. + SharedPanelContainer::const_iterator iPanel (::std::find_if( + rCurrentPanels.begin(), + rCurrentPanels.end(), + ::boost::bind(&Panel::HasIdPredicate, _1, ::boost::cref(rPanelContexDescriptor.msId)))); + if (iPanel != rCurrentPanels.end()) + { + // Panel already exists in current deck. Reuse it. + aNewPanels[nWriteIndex] = *iPanel; + OSL_TRACE(" reusing panel %s", S2A(rPanelContexDescriptor.msId)); + } + else + { + // Panel does not yet exist. Create it. + aNewPanels[nWriteIndex] = CreatePanel( + rPanelContexDescriptor.msId, + mpCurrentDeck->GetPanelParentWindow(), + rPanelContexDescriptor.msMenuCommand); + OSL_TRACE(" creating panel %s", S2A(rPanelContexDescriptor.msId)); + bHasPanelSetChanged = true; + } + if (aNewPanels[nWriteIndex] != NULL) + { + // Depending on the context we have to collapse the panel. + aNewPanels[nWriteIndex]->SetExpanded(rPanelContexDescriptor.mbIsInitiallyVisible); + + ++nWriteIndex; + } + + } + aNewPanels.resize(nWriteIndex); + + // Activate the deck and the new set of panels. + mpCurrentDeck->setPosSizePixel( + 0, + 0, + mpParentWindow->GetSizePixel().Width()-TabBar::GetDefaultWidth(), + mpParentWindow->GetSizePixel().Height()); + mpCurrentDeck->SetPanels(aNewPanels); + mpCurrentDeck->Show(); + + // Tell the tab bar to highlight the button associated with the + // deck. + mpTabBar->HighlightDeck(rDeckDescriptor.msId); + + mpParentWindow->SetText(rDeckDescriptor.msTitle); + + if (bHasPanelSetChanged) + NotifyResize(); + + // Tell the focus manager about the new panels and tab bar + // buttons. + maFocusManager.SetPanels(aNewPanels); + mpTabBar->UpdateFocusManager(maFocusManager); +} + + + + +bool SidebarController::ArePanelSetsEqual ( + const SharedPanelContainer& rCurrentPanels, + const ResourceManager::PanelContextDescriptorContainer& rRequestedPanels) +{ + OSL_TRACE("current panel list:"); + for (SharedPanelContainer::const_iterator + iPanel(rCurrentPanels.begin()), + iEnd(rCurrentPanels.end()); + iPanel!=iEnd; + ++iPanel) + { + OSL_TRACE(" panel %s", S2A((*iPanel)->GetId())); + } + + OSL_TRACE("requested panels: "); + for (ResourceManager::PanelContextDescriptorContainer::const_iterator + iId(rRequestedPanels.begin()), + iEnd(rRequestedPanels.end()); + iId!=iEnd; + ++iId) + { + OSL_TRACE(" panel %s", S2A(iId->msId)); + } + + if (rCurrentPanels.size() != rRequestedPanels.size()) + return false; + for (sal_Int32 nIndex=0,nCount=rCurrentPanels.size(); nIndex<nCount; ++nIndex) + { + if (rCurrentPanels[nIndex] == NULL) + return false; + if ( ! rCurrentPanels[nIndex]->GetId().equals(rRequestedPanels[nIndex].msId)) + return false; + } + return true; +} + + + + +SharedPanel SidebarController::CreatePanel ( + const OUString& rsPanelId, + ::Window* pParentWindow, + const OUString& rsMenuCommand) +{ + const PanelDescriptor* pPanelDescriptor = ResourceManager::Instance().GetPanelDescriptor(rsPanelId); + if (pPanelDescriptor == NULL) + return SharedPanel(); + +#ifdef DEBUG + // Prevent the panel not being created in the same memory of an old panel. + ::boost::scoped_array<char> pUnused (new char[sizeof(Panel)]); + OSL_TRACE("allocated memory at %x", pUnused.get()); +#endif + + // Create the panel which is the parent window of the UIElement. + SharedPanel pPanel (new Panel( + *pPanelDescriptor, + pParentWindow, + ::boost::bind(&Deck::RequestLayout, mpCurrentDeck.get()), + rsMenuCommand.getLength()>0 + ? ::boost::bind(&SidebarController::ShowDetailMenu,this,rsMenuCommand) + : ::boost::function<void(void)>())); + + // Create the XUIElement. + Reference<ui::XUIElement> xUIElement (CreateUIElement( + pPanel->GetComponentInterface(), + pPanelDescriptor->msImplementationURL)); + if (xUIElement.is()) + { + // Initialize the panel and add it to the active deck. + pPanel->SetUIElement(xUIElement); + } + else + { + pPanel.reset(); + } + + return pPanel; +} + + + + +Reference<ui::XUIElement> SidebarController::CreateUIElement ( + const Reference<awt::XWindowPeer>& rxWindow, + const ::rtl::OUString& rsImplementationURL) +{ + try + { + const ::comphelper::ComponentContext aComponentContext (::comphelper::getProcessServiceFactory()); + const Reference<ui::XUIElementFactory> xUIElementFactory ( + aComponentContext.createComponent("com.sun.star.ui.UIElementFactoryManager"), + UNO_QUERY_THROW); + + // Create the XUIElement. + ::comphelper::NamedValueCollection aCreationArguments; + aCreationArguments.put("Frame", makeAny(mxFrame)); + aCreationArguments.put("ParentWindow", makeAny(rxWindow)); + SfxDockingWindow* pSfxDockingWindow = dynamic_cast<SfxDockingWindow*>(mpParentWindow); + if (pSfxDockingWindow != NULL) + aCreationArguments.put("SfxBindings", makeAny(sal_uInt64(&pSfxDockingWindow->GetBindings()))); + aCreationArguments.put("Theme", Theme::GetPropertySet()); + aCreationArguments.put("Sidebar", makeAny(Reference<ui::XSidebar>(static_cast<ui::XSidebar*>(this)))); + + Reference<ui::XUIElement> xUIElement( + xUIElementFactory->createUIElement( + rsImplementationURL, + Sequence<beans::PropertyValue>(aCreationArguments.getPropertyValues())), + UNO_QUERY_THROW); + + return xUIElement; + } + catch(Exception& rException) + { + OSL_TRACE("caught exception: %s", + OUStringToOString(rException.Message, RTL_TEXTENCODING_ASCII_US).getStr()); + // For some reason we can not create the actual panel. + // Probably because its factory was not properly registered. + // TODO: provide feedback to developer to better pinpoint the + // source of the error. + + return NULL; + } +} + + + + +IMPL_LINK(SidebarController, WindowEventHandler, VclWindowEvent*, pEvent) +{ + if (pEvent != NULL) + { + switch (pEvent->GetId()) + { + case VCLEVENT_WINDOW_GETFOCUS: + case VCLEVENT_WINDOW_LOSEFOCUS: + break; + + case VCLEVENT_WINDOW_SHOW: + case VCLEVENT_WINDOW_RESIZE: + NotifyResize(); + break; + + case VCLEVENT_WINDOW_DATACHANGED: + // Force an update of deck and tab bar to reflect + // changes in theme (high contrast mode). + Theme::HandleDataChange(); + mpParentWindow->Invalidate(); + break; + + case SFX_HINT_DYING: + dispose(); + break; + + default: + break; + } + } + + return sal_True; +} + + + + +void SidebarController::ShowPopupMenu ( + const Rectangle& rButtonBox, + const ::std::vector<TabBar::DeckMenuData>& rDeckSelectionData, + const ::std::vector<TabBar::DeckMenuData>& rDeckShowData) const +{ + ::boost::shared_ptr<PopupMenu> pMenu = CreatePopupMenu(rDeckSelectionData, rDeckShowData); + pMenu->SetSelectHdl(LINK(this, SidebarController, OnMenuItemSelected)); + + // pass toolbox button rect so the menu can stay open on button up + Rectangle aBox (rButtonBox); + aBox.Move(mpTabBar->GetPosPixel().X(), 0); + pMenu->Execute(mpParentWindow, aBox, POPUPMENU_EXECUTE_DOWN); +} + + + + +void SidebarController::ShowDetailMenu (const ::rtl::OUString& rsMenuCommand) const +{ + try + { + util::URL aURL; + aURL.Complete = rsMenuCommand; + + const ::comphelper::ComponentContext aComponentContext (::comphelper::getProcessServiceFactory()); + const Reference<util::XURLTransformer> xParser ( + aComponentContext.createComponent("com.sun.star.util.URLTransformer"), + UNO_QUERY_THROW); + xParser->parseStrict(aURL); + Reference<frame::XDispatchProvider> xProvider (mxFrame, UNO_QUERY_THROW); + Reference<frame::XDispatch> xDispatch (xProvider->queryDispatch(aURL, OUString(), 0)); + if (xDispatch.is()) + xDispatch->dispatch(aURL, Sequence<beans::PropertyValue>()); + } + catch(Exception& rException) + { + OSL_TRACE("caught exception: %s", + OUStringToOString(rException.Message, RTL_TEXTENCODING_ASCII_US).getStr()); + } +} + + + + +::boost::shared_ptr<PopupMenu> SidebarController::CreatePopupMenu ( + const ::std::vector<TabBar::DeckMenuData>& rDeckSelectionData, + const ::std::vector<TabBar::DeckMenuData>& rDeckShowData) const +{ + ::boost::shared_ptr<PopupMenu> pMenu (new PopupMenu()); + FloatingWindow* pMenuWindow = dynamic_cast<FloatingWindow*>(pMenu->GetWindow()); + if (pMenuWindow != NULL) + { + pMenuWindow->SetPopupModeFlags(pMenuWindow->GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE); + } + + SidebarResource aLocalResource; + + // Add one entry for every tool panel element to individually make + // them visible or hide them. + { + sal_Int32 nIndex (MID_FIRST_PANEL); + for(::std::vector<TabBar::DeckMenuData>::const_iterator + iItem(rDeckSelectionData.begin()), + iEnd(rDeckSelectionData.end()); + iItem!=iEnd; + ++iItem) + { + pMenu->InsertItem(nIndex, iItem->get<0>(), MIB_RADIOCHECK); + pMenu->CheckItem(nIndex, iItem->get<2>()); + ++nIndex; + } + } + + pMenu->InsertSeparator(); + + // Add entry for docking or un-docking the tool panel. + if (mpParentWindow->IsFloatingMode()) + pMenu->InsertItem(MID_LOCK_TASK_PANEL, String(SfxResId(STR_SFX_DOCK))); + else + pMenu->InsertItem(MID_UNLOCK_TASK_PANEL, String(SfxResId(STR_SFX_UNDOCK))); + + // Add sub menu for customization (hiding of deck tabs.) + PopupMenu* pCustomizationMenu = new PopupMenu(); + { + sal_Int32 nIndex (MID_FIRST_HIDE); + for(::std::vector<TabBar::DeckMenuData>::const_iterator + iItem(rDeckShowData.begin()), + iEnd(rDeckShowData.end()); + iItem!=iEnd; + ++iItem) + { + pCustomizationMenu->InsertItem(nIndex, iItem->get<0>(), MIB_CHECKABLE); + pCustomizationMenu->CheckItem(nIndex, iItem->get<2>()); + ++nIndex; + } + } + + pCustomizationMenu->InsertSeparator(); + pCustomizationMenu->InsertItem(MID_RESTORE_DEFAULT, String(SfxResId(STRING_RESTORE))); + + pMenu->InsertItem(MID_CUSTOMIZATION, String(SfxResId(STRING_CUSTOMIZATION))); + pMenu->SetPopupMenu(MID_CUSTOMIZATION, pCustomizationMenu); + + pMenu->RemoveDisabledEntries(sal_False, sal_False); + + return pMenu; +} + + + + +IMPL_LINK(SidebarController, OnMenuItemSelected, Menu*, pMenu) +{ + if (pMenu == NULL) + { + OSL_ENSURE(pMenu!=NULL, "sfx2::sidebar::SidebarController::OnMenuItemSelected: illegal menu!"); + return 0; + } + + pMenu->Deactivate(); + const sal_Int32 nIndex (pMenu->GetCurItemId()); + switch (nIndex) + { + case MID_UNLOCK_TASK_PANEL: + mpParentWindow->SetFloatingMode(sal_True); + break; + + case MID_LOCK_TASK_PANEL: + mpParentWindow->SetFloatingMode(sal_False); + break; + + case MID_RESTORE_DEFAULT: + mpTabBar->RestoreHideFlags(); + break; + + default: + { + try + { + if (nIndex >= MID_FIRST_PANEL && nIndex<MID_FIRST_HIDE) + SwitchToDeck(mpTabBar->GetDeckIdForIndex(nIndex - MID_FIRST_PANEL)); + else if (nIndex >=MID_FIRST_HIDE) + mpTabBar->ToggleHideFlag(nIndex-MID_FIRST_HIDE); + } + catch (RuntimeException&) + { + } + } + break; + } + + return 1; +} + + + + +void SidebarController::CloseDeck (void) +{ + if ( ! mbIsDeckClosed) + { + mbIsDeckClosed = true; + if ( ! mpParentWindow->IsFloatingMode()) + mnSavedSidebarWidth = SetChildWindowWidth(TabBar::GetDefaultWidth()); + mpParentWindow->SetStyle(mpParentWindow->GetStyle() & ~WB_SIZEABLE); + + if (mpCurrentDeck) + mpCurrentDeck->Hide(); + + NotifyResize(); + } +} + + + + +void SidebarController::OpenDeck (void) +{ + if (mbIsDeckClosed) + { + mbIsDeckClosed = false; + SetChildWindowWidth(mnSavedSidebarWidth); + + if (mpCurrentDeck) + mpCurrentDeck->Show(); + + NotifyResize(); + } +} + + + + +FocusManager& SidebarController::GetFocusManager (void) +{ + return maFocusManager; +} + + + + +bool SidebarController::CanModifyChildWindowWidth (void) const +{ + SfxSplitWindow* pSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent()); + if (pSplitWindow == NULL) + { + OSL_ASSERT(pSplitWindow!=NULL); + return 0; + } + + sal_uInt16 nRow (0xffff); + sal_uInt16 nColumn (0xffff); + pSplitWindow->GetWindowPos(mpParentWindow, nColumn, nRow); + + sal_uInt16 nRowCount (pSplitWindow->GetWindowCount(nColumn)); + + return nRowCount == 1; +} + + + + +sal_Int32 SidebarController::SetChildWindowWidth (const sal_Int32 nNewWidth) +{ + SfxSplitWindow* pSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent()); + if (pSplitWindow == NULL) + return 0; + + sal_uInt16 nRow (0xffff); + sal_uInt16 nColumn (0xffff); + pSplitWindow->GetWindowPos(mpParentWindow, nColumn, nRow); + const long nColumnWidth (pSplitWindow->GetLineSize(nColumn)); + + Window* pWindow = mpParentWindow; + const Point aWindowPosition (pWindow->GetPosPixel()); + const Size aWindowSize (pWindow->GetSizePixel()); + + pSplitWindow->MoveWindow( + mpParentWindow, + Size(nNewWidth, aWindowSize.Height()), + nColumn, + nRow); + + return static_cast<sal_Int32>(nColumnWidth); +} + + + + +void SidebarController::RestrictWidth (void) +{ + SfxSplitWindow* pSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent()); + if (pSplitWindow != NULL) + { + const sal_uInt16 nId (pSplitWindow->GetItemId(mpParentWindow)); + const sal_uInt16 nSetId (pSplitWindow->GetSet(nId)); + // Minimum width is always that of the tabbar. + const sal_Int32 nMinimumWidth (TabBar::GetDefaultWidth()); + // Maximum width depends on whether the deck is open or closed. + const sal_Int32 nMaximumWidth ( + mbIsDeckClosed + ? TabBar::GetDefaultWidth() + : 400); + pSplitWindow->SetItemSizeRange( + nSetId, + Range(nMinimumWidth, nMaximumWidth)); + if (nMinimumWidth == nMaximumWidth) + pSplitWindow->SetItemSize(nSetId, nMinimumWidth); + } +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/SidebarController.hxx b/sfx2/source/sidebar/SidebarController.hxx new file mode 100644 index 000000000000..8902a73dd883 --- /dev/null +++ b/sfx2/source/sidebar/SidebarController.hxx @@ -0,0 +1,165 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_CONTROLLER_HXX +#define SFX_SIDEBAR_CONTROLLER_HXX + +#include "AsynchronousCall.hxx" +#include "Context.hxx" +#include "FocusManager.hxx" +#include "Panel.hxx" +#include "ResourceManager.hxx" +#include "TabBar.hxx" + +#include <vcl/menu.hxx> + +#include <com/sun/star/awt/XWindowPeer.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/ui/XContextChangeEventListener.hpp> +#include <com/sun/star/ui/XUIElement.hpp> +#include <com/sun/star/ui/XSidebar.hpp> + +#include <boost/noncopyable.hpp> +#include <cppuhelper/compbase3.hxx> +#include <cppuhelper/basemutex.hxx> + +namespace css = ::com::sun::star; +namespace cssu = ::com::sun::star::uno; + + +namespace +{ + typedef ::cppu::WeakComponentImplHelper3 < + css::ui::XContextChangeEventListener, + css::beans::XPropertyChangeListener, + css::ui::XSidebar + > SidebarControllerInterfaceBase; +} + +namespace sfx2 { namespace sidebar { + +class ContentPanelDescriptor; +class Deck; +class DeckDescriptor; +class SidebarDockingWindow; +class TabBar; +class TabBarConfiguration; + +class SidebarController + : private ::boost::noncopyable, + private ::cppu::BaseMutex, + public SidebarControllerInterfaceBase +{ +public: + SidebarController( + SidebarDockingWindow* pParentWindow, + const cssu::Reference<css::frame::XFrame>& rxFrame); + virtual ~SidebarController (void); + + // ui::XContextChangeEventListener + virtual void SAL_CALL notifyContextChangeEvent (const css::ui::ContextChangeEventObject& rEvent) + throw(cssu::RuntimeException); + + // XEventListener + virtual void SAL_CALL disposing (const css::lang::EventObject& rEventObject) + throw(cssu::RuntimeException); + + // beans::XPropertyChangeListener + virtual void SAL_CALL propertyChange (const css::beans::PropertyChangeEvent& rEvent) + throw(cssu::RuntimeException); + + // ui::XSidebar + virtual void SAL_CALL requestLayout (void) + throw(cssu::RuntimeException); + + void NotifyResize (void); + + void SwitchToDeck ( + const ::rtl::OUString& rsDeckId); + + /** Show only the tab bar, not the deck. + */ + void CloseDeck (void); + + /** Open the deck area and restore the parent window to its old width. + */ + void OpenDeck (void); + + FocusManager& GetFocusManager (void); + +private: + ::boost::scoped_ptr<Deck> mpCurrentDeck; + SidebarDockingWindow* mpParentWindow; + ::boost::scoped_ptr<TabBar> mpTabBar; + cssu::Reference<css::frame::XFrame> mxFrame; + Context maCurrentContext; + ::rtl::OUString msCurrentDeckId; + ::rtl::OUString msCurrentDeckTitle; + AsynchronousCall maPropertyChangeForwarder; + bool mbIsDeckClosed; + /** Before the deck is closed the sidebar width is saved into this variable, + so that it can be restored when the deck is reopended. + */ + sal_Int32 mnSavedSidebarWidth; + FocusManager maFocusManager; + + DECL_LINK(WindowEventHandler, VclWindowEvent*); + void UpdateConfigurations (const Context& rContext); + bool ArePanelSetsEqual ( + const SharedPanelContainer& rCurrentPanels, + const ResourceManager::PanelContextDescriptorContainer& rRequestedPanels); + cssu::Reference<css::ui::XUIElement> CreateUIElement ( + const cssu::Reference<css::awt::XWindowPeer>& rxWindow, + const ::rtl::OUString& rsImplementationURL); + SharedPanel CreatePanel ( + const ::rtl::OUString& rsPanelId, + ::Window* pParentWindow, + const ::rtl::OUString& rsMenuCommand); + void SwitchToDeck ( + const DeckDescriptor& rDeckDescriptor, + const Context& rContext); + void ShowPopupMenu ( + const Rectangle& rButtonBox, + const ::std::vector<TabBar::DeckMenuData>& rDeckSelectionData, + const ::std::vector<TabBar::DeckMenuData>& rDeckShowData) const; + void ShowDetailMenu (const ::rtl::OUString& rsMenuCommand) const; + ::boost::shared_ptr<PopupMenu> CreatePopupMenu ( + const ::std::vector<TabBar::DeckMenuData>& rDeckSelectionData, + const ::std::vector<TabBar::DeckMenuData>& rDeckShowData) const; + DECL_LINK(OnMenuItemSelected, Menu*); + void BroadcastPropertyChange (void); + + /** The close of the deck changes the width of the child window. + That is only possible if there is no other docking window docked above or below the sidebar. + Return whether the width of the child window can be modified. + */ + bool CanModifyChildWindowWidth (void) const; + + /** Set the child window container to a new width. + Return the old width. + */ + sal_Int32 SetChildWindowWidth (const sal_Int32 nNewWidth); + + void RestrictWidth (void); + + virtual void SAL_CALL disposing (void); +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/SidebarDockingWindow.cxx b/sfx2/source/sidebar/SidebarDockingWindow.cxx new file mode 100644 index 000000000000..ccfdbaaa3705 --- /dev/null +++ b/sfx2/source/sidebar/SidebarDockingWindow.cxx @@ -0,0 +1,130 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "SidebarDockingWindow.hxx" +#include "sfx2/sidebar/SidebarChildWindow.hxx" +#include "SidebarController.hxx" + +#include "sfx2/bindings.hxx" +#include "sfx2/dispatch.hxx" +#include <tools/link.hxx> + +using namespace css; +using namespace cssu; + + +namespace sfx2 { namespace sidebar { + + +SidebarDockingWindow::SidebarDockingWindow( + SfxBindings* pSfxBindings, + SidebarChildWindow& rChildWindow, + Window* pParent, + WinBits nBits) + : SfxDockingWindow(pSfxBindings, &rChildWindow, pParent, nBits), + mpSidebarController() +{ + // Get the XFrame from the bindings. + if (pSfxBindings==NULL || pSfxBindings->GetDispatcher()==NULL) + { + OSL_ASSERT(pSfxBindings!=NULL); + OSL_ASSERT(pSfxBindings->GetDispatcher()!=NULL); + } + else + { + const SfxViewFrame* pViewFrame = pSfxBindings->GetDispatcher()->GetFrame(); + const SfxFrame& rFrame = pViewFrame->GetFrame(); + mpSidebarController.set(new sfx2::sidebar::SidebarController(this, rFrame.GetFrameInterface())); + } +} + + + + +SidebarDockingWindow::~SidebarDockingWindow (void) +{ + DoDispose(); +} + + + + +void SidebarDockingWindow::DoDispose (void) +{ +} + + + + +void SidebarDockingWindow::GetFocus() +{ + mpSidebarController->GetFocusManager().GrabFocus(); +} + + + + +long SidebarDockingWindow::PreNotify (NotifyEvent& rEvent) +{ + switch (rEvent.GetType()) + { + case EVENT_KEYINPUT: + { + const KeyEvent* pKeyEvent = rEvent.GetKeyEvent(); + if (pKeyEvent != NULL) + return mpSidebarController->GetFocusManager().NotifyDockingWindowEvent(*pKeyEvent); + else + break; + } + + case EVENT_GETFOCUS: + OSL_TRACE(""); + break; + + } + + return SfxDockingWindow::PreNotify(rEvent); +} + + + + +SfxChildWindow* SidebarDockingWindow::GetChildWindow (void) +{ + return GetChildWindow_Impl(); +} + + + + +sal_Bool SidebarDockingWindow::Close (void) +{ + if (mpSidebarController.is()) + { + // Do not close the floating window. + // Dock it and close just the deck instead. + mpSidebarController->CloseDeck(); + SetFloatingMode(sal_False); + mpSidebarController->NotifyResize(); + return sal_False; + } + else + return SfxDockingWindow::Close(); +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/SidebarDockingWindow.hxx b/sfx2/source/sidebar/SidebarDockingWindow.hxx new file mode 100644 index 000000000000..700ffde16e94 --- /dev/null +++ b/sfx2/source/sidebar/SidebarDockingWindow.hxx @@ -0,0 +1,63 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_DOCKING_WINDOW_HXX +#define SFX_SIDEBAR_DOCKING_WINDOW_HXX + +#include "sfx2/dockwin.hxx" +#include "sfx2/dockwin.hxx" +#include "Sidebar.hxx" + +#include <rtl/ref.hxx> + +namespace sfx2 { namespace sidebar { + +class SidebarChildWindow; + +class SidebarController; + +class SidebarDockingWindow + : public SfxDockingWindow +{ +public: + SidebarDockingWindow( + SfxBindings* pBindings, + SidebarChildWindow& rChildWindow, + Window* pParent, + WinBits nBits); + virtual ~SidebarDockingWindow (void); + + virtual sal_Bool Close (void); + + SfxChildWindow* GetChildWindow (void); + +protected: + // Window overridables + virtual void GetFocus (void); + virtual long PreNotify (NotifyEvent& rEvent); + +private: + ::rtl::Reference<sfx2::sidebar::SidebarController> mpSidebarController; + + void DoDispose (void); +}; + + +} } // end of namespace sfx2::sidebar + + +#endif diff --git a/sfx2/source/sidebar/SidebarPanel.cxx b/sfx2/source/sidebar/SidebarPanel.cxx new file mode 100644 index 000000000000..33c3ef6ff7cf --- /dev/null +++ b/sfx2/source/sidebar/SidebarPanel.cxx @@ -0,0 +1,171 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "precompiled_sfx2.hxx" + +#include "SidebarPanel.hxx" + +#include "Panel.hxx" +#include "sfx2/sidebar/Theme.hxx" + +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +#include <svl/smplhint.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/awt/XWindowPeer.hpp> + + +using namespace css; +using namespace cssu; + +namespace sfx2 { namespace sidebar { + +Reference<css::ui::XSidebarPanel> SidebarPanel::Create (Panel* pPanel) +{ + return Reference<css::ui::XSidebarPanel>(new SidebarPanel(pPanel)); +} + + + + +SidebarPanel::SidebarPanel(Panel* pPanel) + : SidebarPanelInterfaceBase(m_aMutex), + mpPanel(pPanel), + mxCanvas() +{ + if (mpPanel != NULL) + mpPanel->AddEventListener(LINK(this, SidebarPanel, HandleWindowEvent)); + else + { + mpPanel = NULL; + dispose(); + } +} + + + + +SidebarPanel::~SidebarPanel (void) +{ +} + + + + +void SAL_CALL SidebarPanel::disposing (const css::lang::EventObject& rEventObject) + throw(cssu::RuntimeException) +{ + (void)rEventObject; +} + + + + +void SAL_CALL SidebarPanel::disposing (void) +{ + if (mpPanel != NULL) + { + mpPanel->RemoveEventListener(LINK(this, SidebarPanel, HandleWindowEvent)); + mpPanel = NULL; + } +} + + + + +cssu::Reference<css::rendering::XCanvas> SAL_CALL SidebarPanel::getCanvas (void) + throw (cssu::RuntimeException) +{ + if ( ! mxCanvas.is()) + { + Sequence<Any> aArg (5); + + // common: first any is VCL pointer to window (for VCL canvas) + aArg[0] = makeAny(reinterpret_cast<sal_Int64>(mpPanel)); + aArg[1] = Any(); + aArg[2] = makeAny(::com::sun::star::awt::Rectangle()); + aArg[3] = makeAny(sal_False); + aArg[4] = makeAny(mpPanel->GetComponentInterface()); + + const ::comphelper::ComponentContext aComponentContext (::comphelper::getProcessServiceFactory()); + mxCanvas = Reference<rendering::XCanvas>( + aComponentContext.createComponentWithArguments( + "com.sun.star.rendering.VCLCanvas", + aArg), + UNO_QUERY); + } + + return mxCanvas; + +} + + + + +awt::Point SAL_CALL SidebarPanel::getPositionOnScreen (void) + throw (cssu::RuntimeException) +{ + awt::Point aAwtPoint; + + if (mpPanel != NULL) + { + ::vos::OGuard aGuard (Application::GetSolarMutex()); + + // mpPanel->GetPosPixel() + const Point aLocationOnScreen (mpPanel->OutputToAbsoluteScreenPixel(Point(0,0))); + + aAwtPoint.X = aLocationOnScreen.X(); + aAwtPoint.Y = aLocationOnScreen.Y(); + } + + return aAwtPoint; +} + + + + +Reference<beans::XPropertySet> SAL_CALL SidebarPanel::getThemeProperties (void) + throw (RuntimeException) +{ + return Theme::GetPropertySet(); +} + + + + +IMPL_LINK(SidebarPanel, HandleWindowEvent, VclWindowEvent*, pEvent) +{ + if (pEvent != NULL) + { + switch (pEvent->GetId()) + { + case SFX_HINT_DYING: + dispose(); + break; + + default: + break; + } + } + + return sal_True; +} + + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/SidebarPanel.hxx b/sfx2/source/sidebar/SidebarPanel.hxx new file mode 100644 index 000000000000..99a8e8020394 --- /dev/null +++ b/sfx2/source/sidebar/SidebarPanel.hxx @@ -0,0 +1,74 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_SIDEBAR_PANEL_HXX +#define SFX_SIDEBAR_SIDEBAR_PANEL_HXX + +#include <tools/link.hxx> +#include <com/sun/star/ui/XSidebarPanel.hpp> + +#include <boost/noncopyable.hpp> +#include <cppuhelper/compbase1.hxx> +#include <cppuhelper/basemutex.hxx> + +namespace css = ::com::sun::star; +namespace cssu = ::com::sun::star::uno; + +namespace +{ + typedef ::cppu::WeakComponentImplHelper1 < + css::ui::XSidebarPanel + > SidebarPanelInterfaceBase; +} + + +class DockingWindow; +class VclWindowEvent; + +namespace sfx2 { namespace sidebar { + +class Panel; + +class SidebarPanel + : private ::boost::noncopyable, + private ::cppu::BaseMutex, + public SidebarPanelInterfaceBase +{ +public: + static cssu::Reference<css::ui::XSidebarPanel> Create (Panel* pPanel); + +protected: + SidebarPanel( + Panel* pPanel); + virtual ~SidebarPanel (void); + + virtual void SAL_CALL disposing (const css::lang::EventObject& rEventObject) + throw(cssu::RuntimeException); + + virtual void SAL_CALL disposing (void); + +private: + Panel* mpPanel; + cssu::Reference<css::rendering::XCanvas> mxCanvas; + + DECL_LINK(HandleWindowEvent, VclWindowEvent*); +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/SidebarPanelBase.cxx b/sfx2/source/sidebar/SidebarPanelBase.cxx new file mode 100644 index 000000000000..6a17fb70dfcf --- /dev/null +++ b/sfx2/source/sidebar/SidebarPanelBase.cxx @@ -0,0 +1,251 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "sfx2/sidebar/SidebarPanelBase.hxx" +#include "sfx2/sidebar/Theme.hxx" +#include "sfx2/sidebar/ILayoutableWindow.hxx" +#include "sfx2/sidebar/IContextChangeReceiver.hxx" +#include "sfx2/imagemgr.hxx" +#include <vcl/ctrl.hxx> +#include <comphelper/processfactory.hxx> + +#include <com/sun/star/ui/ContextChangeEventMultiplexer.hpp> +#include <com/sun/star/ui/UIElementType.hpp> + +using namespace css; +using namespace cssu; + + +namespace sfx2 { namespace sidebar { + +Reference<ui::XUIElement> SidebarPanelBase::Create ( + const ::rtl::OUString& rsResourceURL, + const cssu::Reference<css::frame::XFrame>& rxFrame, + Window* pWindow, + const css::ui::LayoutSize& rLayoutSize) +{ + Reference<ui::XUIElement> xUIElement ( + new SidebarPanelBase( + rsResourceURL, + rxFrame, + pWindow, + rLayoutSize)); + return xUIElement; +} + + + + +SidebarPanelBase::SidebarPanelBase ( + const ::rtl::OUString& rsResourceURL, + const cssu::Reference<css::frame::XFrame>& rxFrame, + Window* pWindow, + const css::ui::LayoutSize& rLayoutSize) + : SidebarPanelBaseInterfaceBase(m_aMutex), + mxFrame(rxFrame), + mpControl(pWindow), + msResourceURL(rsResourceURL), + maLayoutSize(rLayoutSize) +{ + if (mxFrame.is()) + { + cssu::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer ( + css::ui::ContextChangeEventMultiplexer::get( + ::comphelper::getProcessComponentContext())); + if (xMultiplexer.is()) + xMultiplexer->addContextChangeEventListener(this, mxFrame->getController()); + } + if (mpControl != NULL) + { + mpControl->SetBackground(Theme::GetWallpaper(Theme::Paint_PanelBackground)); + mpControl->Show(); + } +} + + + + +SidebarPanelBase::~SidebarPanelBase (void) +{ +} + + + + +void SAL_CALL SidebarPanelBase::disposing (void) + throw (cssu::RuntimeException) +{ + if (mpControl != NULL) + { + delete mpControl; + mpControl = NULL; + } + + if (mxFrame.is()) + { + cssu::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer ( + css::ui::ContextChangeEventMultiplexer::get( + ::comphelper::getProcessComponentContext())); + if (xMultiplexer.is()) + xMultiplexer->removeAllContextChangeEventListeners(this); + mxFrame = NULL; + } +} + + + + +void SidebarPanelBase::SetControl (::Window* pControl) +{ + mpControl = pControl; +} + + + + +::Window* SidebarPanelBase::GetControl (void) const +{ + return mpControl; +} + + + + +// XContextChangeEventListener +void SAL_CALL SidebarPanelBase::notifyContextChangeEvent ( + const ui::ContextChangeEventObject& rEvent) + throw (cssu::RuntimeException) +{ + IContextChangeReceiver* pContextChangeReceiver + = dynamic_cast<IContextChangeReceiver*>(mpControl); + if (pContextChangeReceiver != NULL) + { + const EnumContext aContext( + EnumContext::GetApplicationEnum(rEvent.ApplicationName), + EnumContext::GetContextEnum(rEvent.ContextName)); + pContextChangeReceiver->HandleContextChange(aContext); + } +} + + + + +void SAL_CALL SidebarPanelBase::disposing ( + const css::lang::EventObject& rEvent) + throw (cssu::RuntimeException) +{ + (void)rEvent; + + mxFrame = NULL; + mpControl = NULL; +} + + + + +cssu::Reference<css::frame::XFrame> SAL_CALL SidebarPanelBase::getFrame (void) + throw(cssu::RuntimeException) +{ + return mxFrame; +} + + + + +::rtl::OUString SAL_CALL SidebarPanelBase::getResourceURL (void) + throw(cssu::RuntimeException) +{ + return msResourceURL; +} + + + + +sal_Int16 SAL_CALL SidebarPanelBase::getType (void) + throw(cssu::RuntimeException) +{ + return ui::UIElementType::TOOLPANEL; +} + + + + +Reference<XInterface> SAL_CALL SidebarPanelBase::getRealInterface (void) + throw(cssu::RuntimeException) +{ + return Reference<XInterface>(static_cast<XWeak*>(this)); +} + + + + +Reference<accessibility::XAccessible> SAL_CALL SidebarPanelBase::createAccessible ( + const Reference<accessibility::XAccessible>& rxParentAccessible) + throw(cssu::RuntimeException) +{ + (void)rxParentAccessible; + + // Not yet implemented. + return NULL; +} + + + + +Reference<awt::XWindow> SAL_CALL SidebarPanelBase::getWindow (void) + throw(cssu::RuntimeException) +{ + if (mpControl != NULL) + return Reference<awt::XWindow>( + mpControl->GetComponentInterface(), + UNO_QUERY); + else + return NULL; +} + + + + +ui::LayoutSize SAL_CALL SidebarPanelBase::getHeightForWidth (const sal_Int32 nWidth) + throw(cssu::RuntimeException) +{ + if (maLayoutSize.Minimum >= 0) + return maLayoutSize; + else + { + ILayoutableWindow* pLayoutableWindow = dynamic_cast<ILayoutableWindow*>(mpControl); + if (pLayoutableWindow != NULL) + return pLayoutableWindow->GetHeightForWidth(nWidth); + else if (mpControl != NULL) + { + const sal_Int32 nHeight (mpControl->GetSizePixel().Height()); + return ui::LayoutSize(nHeight,nHeight,nHeight); + } + } + + return ui::LayoutSize(0,0,0); +} + +IContextChangeReceiver::~IContextChangeReceiver() +{ +} + +ILayoutableWindow::~ILayoutableWindow() +{ +} + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/SidebarResource.hxx b/sfx2/source/sidebar/SidebarResource.hxx new file mode 100644 index 000000000000..be1371ba7ff7 --- /dev/null +++ b/sfx2/source/sidebar/SidebarResource.hxx @@ -0,0 +1,35 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_RESOURCE_HXX +#define SFX_SIDEBAR_RESOURCE_HXX + + +#include "Sidebar.hrc" +#include <sfx2/sfxresid.hxx> +#include <tools/rc.hxx> + + +class SidebarResource : public Resource +{ +public: + SidebarResource (void) : Resource(SfxResId(RID_SIDEBAR_RESOURCE)){} + ~SidebarResource (void) { FreeResource(); } +}; + + +#endif diff --git a/sfx2/source/sidebar/SidebarToolBox.cxx b/sfx2/source/sidebar/SidebarToolBox.cxx new file mode 100644 index 000000000000..6a404dfec2c6 --- /dev/null +++ b/sfx2/source/sidebar/SidebarToolBox.cxx @@ -0,0 +1,153 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "SidebarToolBox.hxx" +#include "ToolBoxBackground.hxx" +#include "sfx2/sidebar/Theme.hxx" +#include "Tools.hxx" + +#include <vcl/gradient.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +namespace sfx2 { namespace sidebar { + + +SidebarToolBox::SidebarToolBox ( + Window* pParentWindow, + const ResId& rResId) + : ToolBox(pParentWindow, rResId), + mbParentIsBorder(false), + maItemSeparator(Theme::GetImage(Theme::Image_ToolBoxItemSeparator)) +{ + SetBackground(Wallpaper()); + SetPaintTransparent(true); +#ifdef DEBUG + SetText(A2S("SidebarToolBox")); +#endif +} + + + + +SidebarToolBox::~SidebarToolBox (void) +{ +} + + + + +void SidebarToolBox::SetBorderWindow (const Window* pBorderWindow) +{ + if (pBorderWindow != GetParent()) + { + OSL_ASSERT("SetBorderWindow can only handle parent as border window"); + return; + } + + if ( ! mbParentIsBorder) + { + mbParentIsBorder = true; + + setPosSizePixel ( + GetPosPixel().X(), + GetPosPixel().Y(), + GetSizePixel().Width(), + GetSizePixel().Height(), + WINDOW_POSSIZE_ALL); + } +} + + + + +void SidebarToolBox::Paint (const Rectangle& rRect) +{ + ToolBox::Paint(rRect); + + if (Theme::GetBoolean(Theme::Bool_UseToolBoxItemSeparator)) + { + const sal_Int32 nSeparatorY ((GetSizePixel().Height() - maItemSeparator.GetSizePixel().Height())/2); + const sal_uInt16 nItemCount (GetItemCount()); + int nLastRight (-1); + for (sal_uInt16 nIndex=0; nIndex<nItemCount; ++nIndex) + { + const Rectangle aItemBoundingBox (GetItemPosRect(nIndex)); + if (nLastRight >= 0) + { + const int nSeparatorX ((nLastRight + aItemBoundingBox.Left() - 1) / 2); + DrawImage(Point(nSeparatorX,nSeparatorY), maItemSeparator); + } + + nLastRight = aItemBoundingBox.Right(); + } + } +} + + + + +Point SidebarToolBox::GetPosPixel (void) const +{ + if (mbParentIsBorder) + { + const Point aParentPoint (GetParent()->GetPosPixel()); + const Point aChildPoint (ToolBox::GetPosPixel()); + return Point( + aParentPoint.X() + aChildPoint.X(), + aParentPoint.Y() + aChildPoint.Y()); + } + else + return ToolBox::GetPosPixel(); +} + + + + +void SidebarToolBox::setPosSizePixel ( + long nX, + long nY, + long nWidth, + long nHeight, + sal_uInt16 nFlags) +{ + if (mbParentIsBorder) + { + const Point aRelativePosition (static_cast<ToolBoxBackground*>(GetParent())->SetToolBoxChild( + this, + nX, + nY, + nWidth, + nHeight, + nFlags)); + ToolBox::setPosSizePixel( + aRelativePosition.X(), + aRelativePosition.Y(), + nWidth, + nHeight, + nFlags); + } + else + ToolBox::setPosSizePixel(nX, nY, nWidth, nHeight, nFlags); +} + + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/SidebarToolBox.hxx b/sfx2/source/sidebar/SidebarToolBox.hxx new file mode 100644 index 000000000000..125839a8a24d --- /dev/null +++ b/sfx2/source/sidebar/SidebarToolBox.hxx @@ -0,0 +1,52 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_TOOLBOX_HXX +#define SFX_SIDEBAR_TOOLBOX_HXX + +#include "vcl/toolbox.hxx" + + +namespace sfx2 { namespace sidebar { + +class SidebarToolBox + : public ToolBox +{ +public: + SidebarToolBox (Window* pParentWindow, const ResId& rResId); + virtual ~SidebarToolBox (void); + + void SetBorderWindow (const Window* pBorderWindow); + virtual void Paint (const Rectangle& rRect); + + virtual Point GetPosPixel (void) const; + virtual void setPosSizePixel ( + long nX, + long nY, + long nWidth, + long nHeight, + sal_uInt16 nFlags); + +private: + bool mbParentIsBorder; + Image maItemSeparator; +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/TabBar.cxx b/sfx2/source/sidebar/TabBar.cxx new file mode 100644 index 000000000000..c30953bbdd94 --- /dev/null +++ b/sfx2/source/sidebar/TabBar.cxx @@ -0,0 +1,385 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "TabBar.hxx" +#include "TabItem.hxx" +#include "sidebar/ControlFactory.hxx" +#include "DeckDescriptor.hxx" +#include "Paint.hxx" +#include "sfx2/sidebar/Theme.hxx" +#include "Tools.hxx" +#include "FocusManager.hxx" + +#include <vcl/gradient.hxx> +#include <vcl/image.hxx> +#include <vcl/wrkwin.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/componentcontext.hxx> +#include <tools/svborder.hxx> + +#include <com/sun/star/graphic/XGraphicProvider.hpp> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + + + +namespace sfx2 { namespace sidebar { + +TabBar::TabBar ( + Window* pParentWindow, + const Reference<frame::XFrame>& rxFrame, + const ::boost::function<void(const ::rtl::OUString&)>& rDeckActivationFunctor, + const PopupMenuProvider& rPopupMenuProvider) + : Window(pParentWindow, WB_DIALOGCONTROL), + mxFrame(rxFrame), + mpMenuButton(ControlFactory::CreateMenuButton(this)), + maItems(), + maDeckActivationFunctor(rDeckActivationFunctor), + maPopupMenuProvider(rPopupMenuProvider) +{ + SetBackground(Theme::GetPaint(Theme::Paint_TabBarBackground).GetWallpaper()); + + mpMenuButton->SetModeImage(Theme::GetImage(Theme::Image_TabBarMenu)); + mpMenuButton->SetClickHdl(LINK(this, TabBar, OnToolboxClicked)); + Layout(); + +#ifdef DEBUG + SetText(A2S("TabBar")); +#endif +} + + + + +TabBar::~TabBar (void) +{ +} + + + + +void TabBar::Paint (const Rectangle& rUpdateArea) +{ + Window::Paint(rUpdateArea); + + const sal_Int32 nHorizontalPadding (Theme::GetInteger(Theme::Int_TabMenuSeparatorPadding)); + SetLineColor(Theme::GetColor(Theme::Color_TabMenuSeparator)); + DrawLine( + Point(nHorizontalPadding, mnMenuSeparatorY), + Point(GetSizePixel().Width()-nHorizontalPadding, mnMenuSeparatorY)); +} + + + + +sal_Int32 TabBar::GetDefaultWidth (void) +{ + return Theme::GetInteger(Theme::Int_TabItemWidth) + + Theme::GetInteger(Theme::Int_TabBarLeftPadding) + + Theme::GetInteger(Theme::Int_TabBarRightPadding); +} + + + + +void TabBar::SetDecks ( + const ResourceManager::IdContainer& rDeckIds) +{ + // Remove the current buttons. + { + for(ItemContainer::iterator + iItem(maItems.begin()), iEnd(maItems.end()); + iItem!=iEnd; + ++iItem) + { + iItem->mpButton.reset(); + } + maItems.clear(); + } + + maItems.resize(rDeckIds.size()); + sal_Int32 nIndex (0); + for (ResourceManager::IdContainer::const_iterator + iDeckId(rDeckIds.begin()), + iEnd(rDeckIds.end()); + iDeckId!=iEnd; + ++iDeckId) + { + const DeckDescriptor* pDescriptor = ResourceManager::Instance().GetDeckDescriptor(*iDeckId); + if (pDescriptor == NULL) + { + OSL_ASSERT(pDescriptor!=NULL); + continue; + } + + Item& rItem (maItems[nIndex++]); + rItem.msDeckId = pDescriptor->msId; + rItem.mpButton.reset(CreateTabItem(*pDescriptor)); + rItem.mpButton->SetClickHdl(LINK(&rItem, TabBar::Item, HandleClick)); + rItem.maDeckActivationFunctor = maDeckActivationFunctor; + rItem.mbIsHiddenByDefault = false; + rItem.mbIsHidden = ! pDescriptor->mbIsEnabled; + } + + UpdateButtonIcons(); + Layout(); +} + + + + +void TabBar::UpdateButtonIcons (void) +{ + mpMenuButton->SetModeImage(Theme::GetImage(Theme::Image_TabBarMenu)); + + for(ItemContainer::const_iterator + iItem(maItems.begin()), iEnd(maItems.end()); + iItem!=iEnd; + ++iItem) + { + const DeckDescriptor* pDeckDescriptor = ResourceManager::Instance().GetDeckDescriptor(iItem->msDeckId); + if (pDeckDescriptor != NULL) + iItem->mpButton->SetModeImage(GetItemImage(*pDeckDescriptor)); + } + + Invalidate(); +} + + + + +void TabBar::Layout (void) +{ + const SvBorder aPadding ( + Theme::GetInteger(Theme::Int_TabBarLeftPadding), + Theme::GetInteger(Theme::Int_TabBarTopPadding), + Theme::GetInteger(Theme::Int_TabBarRightPadding), + Theme::GetInteger(Theme::Int_TabBarBottomPadding)); + sal_Int32 nX (aPadding.Top()); + sal_Int32 nY (aPadding.Left()); + const Size aTabItemSize ( + Theme::GetInteger(Theme::Int_TabItemWidth), + Theme::GetInteger(Theme::Int_TabItemHeight)); + + // Place the menu button and the separator. + if (mpMenuButton != NULL) + { + mpMenuButton->SetPosSizePixel( + Point(nX,nY), + aTabItemSize); + mpMenuButton->Show(); + nY += mpMenuButton->GetSizePixel().Height() + 1 + Theme::GetInteger(Theme::Int_TabMenuPadding); + mnMenuSeparatorY = nY - Theme::GetInteger(Theme::Int_TabMenuPadding)/2 - 1; + } + + // Place the deck selection buttons. + for(ItemContainer::const_iterator + iItem(maItems.begin()), iEnd(maItems.end()); + iItem!=iEnd; + ++iItem) + { + Button& rButton (*iItem->mpButton); + rButton.Show( ! iItem->mbIsHidden); + + if (iItem->mbIsHidden) + continue; + + // Place and size the icon. + rButton.SetPosSizePixel( + Point(nX,nY), + aTabItemSize); + rButton.Show(); + + nY += rButton.GetSizePixel().Height() + 1 + aPadding.Bottom(); + } + Invalidate(); +} + + + + +void TabBar::HighlightDeck (const ::rtl::OUString& rsDeckId) +{ + for (ItemContainer::const_iterator iItem(maItems.begin()),iEnd(maItems.end()); + iItem!=iEnd; + ++iItem) + { + if (iItem->msDeckId.equals(rsDeckId)) + { + iItem->mpButton->Check(); + break; + } + } +} + + + + +void TabBar::DataChanged (const DataChangedEvent& rDataChangedEvent) +{ + SetBackground(Theme::GetPaint(Theme::Paint_TabBarBackground).GetWallpaper()); + UpdateButtonIcons(); + + Window::DataChanged(rDataChangedEvent); +} + + + + +RadioButton* TabBar::CreateTabItem (const DeckDescriptor& rDeckDescriptor) +{ + RadioButton* pItem = ControlFactory::CreateTabItem(this); + pItem->SetHelpText(rDeckDescriptor.msHelpText); + pItem->SetQuickHelpText(rDeckDescriptor.msHelpText); + + return pItem; +} + + + +Image TabBar::GetItemImage (const DeckDescriptor& rDeckDescriptor) const +{ + return Tools::GetImage( + rDeckDescriptor.msIconURL, + rDeckDescriptor.msHighContrastIconURL, + mxFrame); +} + + + + + +IMPL_LINK(TabBar::Item, HandleClick, Button*, EMPTYARG) +{ + maDeckActivationFunctor(msDeckId); + return 1; +} + + + + +const ::rtl::OUString TabBar::GetDeckIdForIndex (const sal_Int32 nIndex) const +{ + if (nIndex<0 || static_cast<size_t>(nIndex)>=maItems.size()) + throw RuntimeException(); + else + return maItems[nIndex].msDeckId; +} + + + + +void TabBar::ToggleHideFlag (const sal_Int32 nIndex) +{ + if (nIndex<0 || static_cast<size_t>(nIndex)>=maItems.size()) + throw RuntimeException(); + else + { + maItems[nIndex].mbIsHidden = ! maItems[nIndex].mbIsHidden; + ResourceManager::Instance().SetIsDeckEnabled( + maItems[nIndex].msDeckId, + maItems[nIndex].mbIsHidden); + Layout(); + } +} + + + + +void TabBar::RestoreHideFlags (void) +{ + bool bNeedsLayout (false); + for(ItemContainer::iterator iItem(maItems.begin()),iEnd(maItems.end()); + iItem!=iEnd; + ++iItem) + { + if (iItem->mbIsHidden != iItem->mbIsHiddenByDefault) + { + iItem->mbIsHidden = iItem->mbIsHiddenByDefault; + bNeedsLayout = true; + } + } + if (bNeedsLayout) + Layout(); +} + + + + +void TabBar::UpdateFocusManager (FocusManager& rFocusManager) +{ + ::std::vector<Button*> aButtons; + aButtons.reserve(maItems.size()+1); + + aButtons.push_back(mpMenuButton.get()); + for(ItemContainer::const_iterator + iItem(maItems.begin()), iEnd(maItems.end()); + iItem!=iEnd; + ++iItem) + { + aButtons.push_back(iItem->mpButton.get()); + } + rFocusManager.SetButtons(aButtons); +} + + + + +IMPL_LINK(TabBar, OnToolboxClicked, void*, EMPTYARG) +{ + ::std::vector<DeckMenuData> aSelectionData; + ::std::vector<DeckMenuData> aShowData; + + for(ItemContainer::const_iterator iItem(maItems.begin()),iEnd(maItems.end()); + iItem!=iEnd; + ++iItem) + { + const DeckDescriptor* pDeckDescriptor = ResourceManager::Instance().GetDeckDescriptor(iItem->msDeckId); + if (pDeckDescriptor != NULL) + { + if ( ! iItem->mbIsHidden) + aSelectionData.push_back( + DeckMenuData( + pDeckDescriptor->msTitle, + pDeckDescriptor->msId, + iItem->mpButton->IsChecked())); + + aShowData.push_back( + DeckMenuData( + pDeckDescriptor->msTitle, + pDeckDescriptor->msId, + !iItem->mbIsHidden)); + } + } + + maPopupMenuProvider( + Rectangle( + mpMenuButton->GetPosPixel(), + mpMenuButton->GetSizePixel()), + aSelectionData, + aShowData); + + return 0; +} + + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/TabBar.hxx b/sfx2/source/sidebar/TabBar.hxx new file mode 100644 index 000000000000..50ea6f3537d0 --- /dev/null +++ b/sfx2/source/sidebar/TabBar.hxx @@ -0,0 +1,120 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_TAB_BAR_HXX +#define SFX_SIDEBAR_TAB_BAR_HXX + +#include "DeckDescriptor.hxx" +#include "ResourceManager.hxx" + +#include <vcl/menu.hxx> +#include <vcl/window.hxx> + +#include <com/sun/star/frame/XFrame.hpp> +#include <boost/function.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/scoped_ptr.hpp> + +class Button; +class RadioButton; + +namespace css = ::com::sun::star; +namespace cssu = ::com::sun::star::uno; + + +namespace sfx2 { namespace sidebar { + +class FocusManager; +class TabBarConfiguration; +class TabItem; + +/** The tab bar is the container for the individual tabs. +*/ +class TabBar + : public Window +{ +public: + /** DeckMenuData has entries for display name, deck id, and a flag: + - isCurrentDeck for the deck selection data + - isEnabled for the show/hide menu + */ + typedef ::boost::tuple<rtl::OUString,rtl::OUString,bool> DeckMenuData; + typedef ::boost::function<void( + const Rectangle&, + const ::std::vector<DeckMenuData>& rDeckSelectionData, + const ::std::vector<DeckMenuData>& rDeckShowData)> PopupMenuProvider; + TabBar ( + Window* pParentWindow, + const cssu::Reference<css::frame::XFrame>& rxFrame, + const ::boost::function<void(const ::rtl::OUString&rsDeckId)>& rDeckActivationFunctor, + const PopupMenuProvider& rPopupMenuProvider); + virtual ~TabBar (void); + + virtual void Paint (const Rectangle& rUpdateArea); + virtual void DataChanged (const DataChangedEvent& rDataChangedEvent); + + static sal_Int32 GetDefaultWidth (void); + + void SetDecks ( + const ResourceManager::IdContainer& rDeckIds); + void HighlightDeck (const ::rtl::OUString& rsDeckId); + void AddPopupMenuEntries ( + PopupMenu& rMenu, + const sal_Int32 nFirstIndex); + void AddCustomizationMenuEntries ( + PopupMenu& rMenu, + const sal_Int32 nFirstIndex); + const ::rtl::OUString GetDeckIdForIndex (const sal_Int32 nIndex) const; + void ToggleHideFlag (const sal_Int32 nIndex); + void RestoreHideFlags (void); + + void UpdateFocusManager (FocusManager& rFocusManager); + +private: + cssu::Reference<css::frame::XFrame> mxFrame; + ::boost::scoped_ptr<Button> mpMenuButton; + class Item + { + public: + DECL_LINK(HandleClick, Button*); + ::boost::shared_ptr<RadioButton> mpButton; + ::rtl::OUString msDeckId; + ::boost::function<void(const ::rtl::OUString&rsDeckId)> maDeckActivationFunctor; + bool mbIsHidden; + bool mbIsHiddenByDefault; + }; + typedef ::std::vector<Item> ItemContainer; + ItemContainer maItems; + const ::boost::function<void(const ::rtl::OUString&rsDeckId)> maDeckActivationFunctor; + sal_Int32 mnMenuSeparatorY; + PopupMenuProvider maPopupMenuProvider; + + RadioButton* CreateTabItem (const DeckDescriptor& rDeckDescriptor); + Image GetItemImage (const DeckDescriptor& rDeskDescriptor) const; + void Layout (void); + void UpdateButtonIcons (void); + + ::boost::shared_ptr<PopupMenu> CreatePopupMenu (void) const; + void ShowPopupMenu (void) const; + DECL_LINK(OnToolboxClicked, void*); + +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/TabItem.cxx b/sfx2/source/sidebar/TabItem.cxx new file mode 100644 index 000000000000..059fabdf6d7b --- /dev/null +++ b/sfx2/source/sidebar/TabItem.cxx @@ -0,0 +1,143 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "TabItem.hxx" + +#include "DrawHelper.hxx" +#include "Paint.hxx" +#include "Tools.hxx" + +#include "sfx2/sidebar/Theme.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +namespace sfx2 { namespace sidebar { + + +TabItem::TabItem (Window* pParentWindow) + : ImageRadioButton(pParentWindow), + mbIsLeftButtonDown(false), + mePaintType(PT_Theme) +{ + SetStyle(GetStyle() | WB_TABSTOP | WB_DIALOGCONTROL | WB_NOPOINTERFOCUS); + SetBackground(Theme::GetPaint(Theme::Paint_TabBarBackground).GetWallpaper()); +#ifdef DEBUG + SetText(A2S("TabItem")); +#endif +} + + + + +TabItem::~TabItem (void) +{ +} + + + + +void TabItem::Paint (const Rectangle& rUpdateArea) +{ + OSL_TRACE("TabItem::Paint"); + switch(mePaintType) + { + case PT_Theme: + default: + { + const bool bIsSelected (IsChecked()); + const bool bIsHighlighted (IsMouseOver() || HasFocus()); + DrawHelper::DrawRoundedRectangle( + *this, + Rectangle(Point(0,0), GetSizePixel()), + Theme::GetInteger(Theme::Int_ButtonCornerRadius), + bIsHighlighted||bIsSelected + ? Theme::GetColor(Theme::Color_TabItemBorder) + : Color(0xffffffff), + bIsHighlighted + ? Theme::GetPaint(Theme::Paint_TabItemBackgroundHighlight) + : Theme::GetPaint(Theme::Paint_TabItemBackgroundNormal)); + + const Image aIcon(Button::GetModeImage()); + const Size aIconSize (aIcon.GetSizePixel()); + const Point aIconLocation( + (GetSizePixel().Width() - aIconSize.Width())/2, + (GetSizePixel().Height() - aIconSize.Height())/2); + DrawImage( + aIconLocation, + aIcon); + break; + } + case PT_Native: + Button::Paint(rUpdateArea); + // DrawImage(maIconPosition, maIcon); + break; + } +} + + + + +void TabItem::MouseMove (const MouseEvent& rEvent) +{ + if (rEvent.IsEnterWindow() || rEvent.IsLeaveWindow()) + Invalidate(); + ImageRadioButton::MouseMove(rEvent); +} + + + + +void TabItem::MouseButtonDown (const MouseEvent& rMouseEvent) +{ + if (rMouseEvent.IsLeft()) + { + mbIsLeftButtonDown = true; + CaptureMouse(); + Invalidate(); + } +} + + + + +void TabItem::MouseButtonUp (const MouseEvent& rMouseEvent) +{ + if (IsMouseCaptured()) + ReleaseMouse(); + + if (rMouseEvent.IsLeft()) + { + if (mbIsLeftButtonDown) + { + Check(); + Click(); + GetParent()->Invalidate(); + } + } + if (mbIsLeftButtonDown) + { + mbIsLeftButtonDown = false; + Invalidate(); + } +} + + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/TabItem.hxx b/sfx2/source/sidebar/TabItem.hxx new file mode 100644 index 000000000000..31898b3e8334 --- /dev/null +++ b/sfx2/source/sidebar/TabItem.hxx @@ -0,0 +1,54 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_TAB_ITEM_HXX +#define SFX_SIDEBAR_TAB_ITEM_HXX + +#include "vcl/button.hxx" + +#include "DeckDescriptor.hxx" + +class Window; + +namespace sfx2 { namespace sidebar { + +/** A single button in the The tab bar. +*/ +class TabItem + : public ImageRadioButton +{ +public: + TabItem (Window* pParentWindow); + virtual ~TabItem (void); + + virtual void Paint (const Rectangle& rUpdateArea); + virtual void MouseMove (const MouseEvent& rEvent); + virtual void MouseButtonDown (const MouseEvent& rMouseEvent); + virtual void MouseButtonUp (const MouseEvent& rMouseEvent); + +private: + bool mbIsLeftButtonDown; + enum PaintType { + PT_Native, + PT_Theme + } mePaintType; +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/Theme.cxx b/sfx2/source/sidebar/Theme.cxx new file mode 100644 index 000000000000..d571885ca525 --- /dev/null +++ b/sfx2/source/sidebar/Theme.cxx @@ -0,0 +1,1148 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "sfx2/sidebar/Theme.hxx" +#include "Paint.hxx" +#include "SidebarResource.hxx" +#include "Tools.hxx" + +#include <tools/svborder.hxx> +#include <tools/rc.hxx> +#include <vcl/svapp.hxx> + +using namespace css; +using namespace cssu; + + +namespace sfx2 { namespace sidebar { + +::rtl::Reference<Theme> Theme::mpInstance; + + + + +Theme& Theme::GetCurrentTheme (void) +{ + if ( ! mpInstance.is()) + { + mpInstance.set(new Theme()); + mpInstance->InitializeTheme(); + } + return *mpInstance; +} + + + + +Theme::Theme (void) + : ThemeInterfaceBase(m_aMutex), + maImages(), + maColors(), + maPaints(), + maIntegers(), + maBooleans(), + mbIsHighContrastMode(Application::GetSettings().GetStyleSettings().GetHighContrastMode()), + mbIsHighContrastModeSetManually(false), + maPropertyNameToIdMap(), + maPropertyIdToNameMap(), + maRawValues(), + maChangeListeners(), + maVetoableListeners() + +{ + SetupPropertyMaps(); +} + + + + +Theme::~Theme (void) +{ +} + + + + +Image Theme::GetImage (const ThemeItem eItem) +{ + const PropertyType eType (GetPropertyType(eItem)); + OSL_ASSERT(eType==PT_Image); + const sal_Int32 nIndex (GetIndex(eItem, eType)); + const Theme& rTheme (GetCurrentTheme()); + return rTheme.maImages[nIndex]; +} + + + + +Color Theme::GetColor (const ThemeItem eItem) +{ + const PropertyType eType (GetPropertyType(eItem)); + OSL_ASSERT(eType==PT_Color || eType==PT_Paint); + const sal_Int32 nIndex (GetIndex(eItem, eType)); + const Theme& rTheme (GetCurrentTheme()); + if (eType == PT_Color) + return rTheme.maColors[nIndex]; + else if (eType == PT_Paint) + return rTheme.maPaints[nIndex].GetColor(); + else + return COL_WHITE; +} + + + + +const Paint& Theme::GetPaint (const ThemeItem eItem) +{ + const PropertyType eType (GetPropertyType(eItem)); + OSL_ASSERT(eType==PT_Paint); + const sal_Int32 nIndex (GetIndex(eItem, eType)); + const Theme& rTheme (GetCurrentTheme()); + return rTheme.maPaints[nIndex]; +} + + + + +const Wallpaper Theme::GetWallpaper (const ThemeItem eItem) +{ + return GetPaint(eItem).GetWallpaper(); +} + + + + +sal_Int32 Theme::GetInteger (const ThemeItem eItem) +{ + const PropertyType eType (GetPropertyType(eItem)); + OSL_ASSERT(eType==PT_Integer); + const sal_Int32 nIndex (GetIndex(eItem, eType)); + const Theme& rTheme (GetCurrentTheme()); + return rTheme.maIntegers[nIndex]; +} + + + + +bool Theme::GetBoolean (const ThemeItem eItem) +{ + const PropertyType eType (GetPropertyType(eItem)); + OSL_ASSERT(eType==PT_Boolean); + const sal_Int32 nIndex (GetIndex(eItem, eType)); + const Theme& rTheme (GetCurrentTheme()); + return rTheme.maBooleans[nIndex]; +} + + + + +Rectangle Theme::GetRectangle (const ThemeItem eItem) +{ + const PropertyType eType (GetPropertyType(eItem)); + OSL_ASSERT(eType==PT_Rectangle); + const sal_Int32 nIndex (GetIndex(eItem, eType)); + const Theme& rTheme (GetCurrentTheme()); + return rTheme.maRectangles[nIndex]; +} + + + + +bool Theme::IsHighContrastMode (void) +{ + const Theme& rTheme (GetCurrentTheme()); + return rTheme.mbIsHighContrastMode; +} + + + + +void Theme::HandleDataChange (void) +{ + Theme& rTheme (GetCurrentTheme()); + + if ( ! rTheme.mbIsHighContrastModeSetManually) + { + // Do not modify mbIsHighContrastMode when it was manually set. + GetCurrentTheme().mbIsHighContrastMode = Application::GetSettings().GetStyleSettings().GetHighContrastMode(); + rTheme.maRawValues[Bool_IsHighContrastModeActive] = Any(GetCurrentTheme().mbIsHighContrastMode); + } + + GetCurrentTheme().UpdateTheme(); +} + + + + +void Theme::InitializeTheme (void) +{ + setPropertyValue( + maPropertyIdToNameMap[Bool_UseSymphonyIcons], + Any(false)); + setPropertyValue( + maPropertyIdToNameMap[Bool_UseSystemColors], + Any(false)); +} + + + + +void Theme::UpdateTheme (void) +{ + SidebarResource aLocalResource; + + try + { + const StyleSettings& rStyle (Application::GetSettings().GetStyleSettings()); + const bool bUseSystemColors (GetBoolean(Bool_UseSystemColors)); + +#define Alternatives(n,hc,sys) (mbIsHighContrastMode ? hc : (bUseSystemColors ? sys : n)) + + const Color aBaseBackgroundColor (rStyle.GetDialogColor()); + Color aBorderColor (aBaseBackgroundColor); + aBorderColor.DecreaseLuminance(15); + Color aSecondColor (aBaseBackgroundColor); + aSecondColor.DecreaseLuminance(15); + + setPropertyValue( + maPropertyIdToNameMap[Paint_DeckBackground], + Any(sal_Int32(rStyle.GetMenuColor().GetRGBColor()))); + + setPropertyValue( + maPropertyIdToNameMap[Paint_DeckTitleBarBackground], + Any(sal_Int32(aBaseBackgroundColor.GetRGBColor()))); + setPropertyValue( + maPropertyIdToNameMap[Int_DeckLeftPadding], + Any(sal_Int32(2))); + setPropertyValue( + maPropertyIdToNameMap[Int_DeckTopPadding], + Any(sal_Int32(2))); + setPropertyValue( + maPropertyIdToNameMap[Int_DeckRightPadding], + Any(sal_Int32(2))); + setPropertyValue( + maPropertyIdToNameMap[Int_DeckBottomPadding], + Any(sal_Int32(2))); + setPropertyValue( + maPropertyIdToNameMap[Int_DeckBorderSize], + Any(sal_Int32(1))); + setPropertyValue( + maPropertyIdToNameMap[Int_DeckSeparatorHeight], + Any(sal_Int32(1))); + setPropertyValue( + maPropertyIdToNameMap[Int_ButtonCornerRadius], + Any(sal_Int32(3))); + setPropertyValue( + maPropertyIdToNameMap[Color_DeckTitleFont], + Any(sal_Int32(rStyle.GetFontColor().GetRGBColor()))); + setPropertyValue( + maPropertyIdToNameMap[Int_DeckTitleBarHeight], + Any(sal_Int32(Alternatives( + 26, + 26, + rStyle.GetFloatTitleHeight())))); + setPropertyValue( + maPropertyIdToNameMap[Paint_PanelBackground], + Any(sal_Int32(rStyle.GetDialogColor().GetRGBColor()))); + // Any(sal_Int32(mbIsHighContrastMode ? 0x000000 : + // 0xffffff))); + + setPropertyValue( + maPropertyIdToNameMap[Paint_PanelTitleBarBackground], + Any(Tools::VclToAwtGradient(Gradient( + GradientStyle_LINEAR, + aSecondColor.GetRGBColor(), + aBaseBackgroundColor.GetRGBColor() + )))); + setPropertyValue( + maPropertyIdToNameMap[Color_PanelTitleFont], + Any(sal_Int32(mbIsHighContrastMode ? 0x00ff00 : 0x262626))); + setPropertyValue( + maPropertyIdToNameMap[Int_PanelTitleBarHeight], + Any(sal_Int32(Alternatives( + 26, + 26, + rStyle.GetTitleHeight())))); + setPropertyValue( + maPropertyIdToNameMap[Paint_TabBarBackground], + Any(sal_Int32(aBaseBackgroundColor.GetRGBColor()))); + setPropertyValue( + maPropertyIdToNameMap[Int_TabBarLeftPadding], + Any(sal_Int32(2))); + setPropertyValue( + maPropertyIdToNameMap[Int_TabBarTopPadding], + Any(sal_Int32(2))); + setPropertyValue( + maPropertyIdToNameMap[Int_TabBarRightPadding], + Any(sal_Int32(2))); + setPropertyValue( + maPropertyIdToNameMap[Int_TabBarBottomPadding], + Any(sal_Int32(2))); + + setPropertyValue( + maPropertyIdToNameMap[Int_TabMenuPadding], + Any(sal_Int32(6))); + setPropertyValue( + maPropertyIdToNameMap[Color_TabMenuSeparator], + Any(sal_Int32(aBorderColor.GetRGBColor()))); + setPropertyValue( + maPropertyIdToNameMap[Int_TabMenuSeparatorPadding], + Any(sal_Int32(7))); + + setPropertyValue( + maPropertyIdToNameMap[Int_TabItemWidth], + Any(sal_Int32(32))); + setPropertyValue( + maPropertyIdToNameMap[Int_TabItemHeight], + Any(sal_Int32(32))); + setPropertyValue( + maPropertyIdToNameMap[Color_TabItemBorder], + Any(sal_Int32(rStyle.GetActiveBorderColor().GetRGBColor()))); + // mbIsHighContrastMode ? 0x00ff00 : 0xbfbfbf))); + + setPropertyValue( + maPropertyIdToNameMap[Paint_DropDownBackground], + Any(sal_Int32(aBaseBackgroundColor.GetRGBColor()))); + setPropertyValue( + maPropertyIdToNameMap[Color_DropDownBorder], + Any(sal_Int32(rStyle.GetActiveBorderColor().GetRGBColor()))); + + setPropertyValue( + maPropertyIdToNameMap[Color_Highlight], + Any(sal_Int32(rStyle.GetHighlightColor().GetRGBColor()))); + setPropertyValue( + maPropertyIdToNameMap[Color_HighlightText], + Any(sal_Int32(rStyle.GetHighlightTextColor().GetRGBColor()))); + + setPropertyValue( + maPropertyIdToNameMap[Paint_TabItemBackgroundNormal], + Any()); + setPropertyValue( + maPropertyIdToNameMap[Paint_TabItemBackgroundHighlight], + Any(sal_Int32(rStyle.GetActiveTabColor().GetRGBColor()))); + // mbIsHighContrastMode ? 0x000000 : 0x00ffffff))); + + setPropertyValue( + maPropertyIdToNameMap[Paint_HorizontalBorder], + Any(sal_Int32(aBorderColor.GetRGBColor()))); + // mbIsHighContrastMode ? 0x00ff00 : 0xe4e4e4))); + setPropertyValue( + maPropertyIdToNameMap[Paint_VerticalBorder], + Any(sal_Int32(aBorderColor.GetRGBColor()))); + setPropertyValue( + maPropertyIdToNameMap[Image_Grip], + Any(A2S("private:graphicrepository/sfx2/res/grip.png"))); + setPropertyValue( + maPropertyIdToNameMap[Image_Expand], + Any(A2S("private:graphicrepository/res/plus.png"))); + setPropertyValue( + maPropertyIdToNameMap[Image_Collapse], + Any(A2S("private:graphicrepository/res/minus.png"))); + setPropertyValue( + maPropertyIdToNameMap[Image_TabBarMenu], + Any(A2S("private:graphicrepository/sfx2/res/symphony/open_more.png"))); + setPropertyValue( + maPropertyIdToNameMap[Image_PanelMenu], + Any(A2S("private:graphicrepository/sfx2/res/symphony/morebutton.png"))); + setPropertyValue( + maPropertyIdToNameMap[Image_Closer], + Any(A2S("private:graphicrepository/sfx2/res/closedoc.png"))); + setPropertyValue( + maPropertyIdToNameMap[Image_ToolBoxItemSeparator], + Any( + A2S("private:graphicrepository/sfx2/res/separator.png"))); + + // ToolBox + + /* + // Separator style + setPropertyValue( + maPropertyIdToNameMap[Paint_ToolBoxBackground], + Any(sal_Int32(rStyle.GetMenuColor().GetRGBColor()))); + setPropertyValue( + maPropertyIdToNameMap[Paint_ToolBoxBorderTopLeft], + Any()); + setPropertyValue( + maPropertyIdToNameMap[Paint_ToolBoxBorderCenterCorners], + Any()); + setPropertyValue( + maPropertyIdToNameMap[Paint_ToolBoxBorderBottomRight], + Any()); + setPropertyValue( + maPropertyIdToNameMap[Rect_ToolBoxPadding], + Any(awt::Rectangle(2,2,2,2))); + setPropertyValue( + maPropertyIdToNameMap[Rect_ToolBoxBorder], + Any(awt::Rectangle(0,0,0,0))); + setPropertyValue( + maPropertyIdToNameMap[Bool_UseToolBoxItemSeparator], + Any(true)); + + */ + + // Gradient style + setPropertyValue( + maPropertyIdToNameMap[Paint_ToolBoxBackground], + Any(Tools::VclToAwtGradient(Gradient( + GradientStyle_LINEAR, + Color(0xf2f2f2), + Color(0xfefefe) + )))); + setPropertyValue( + maPropertyIdToNameMap[Paint_ToolBoxBorderTopLeft], + mbIsHighContrastMode + ? Any(util::Color(sal_uInt32(0x00ff00))) + : Any(util::Color(sal_uInt32(0xf2f2f2)))); + setPropertyValue( + maPropertyIdToNameMap[Paint_ToolBoxBorderCenterCorners], + mbIsHighContrastMode + ? Any(util::Color(sal_uInt32(0x00ff00))) + : Any(util::Color(sal_uInt32(0xf2f2f2)))); + setPropertyValue( + maPropertyIdToNameMap[Paint_ToolBoxBorderBottomRight], + mbIsHighContrastMode + ? Any(util::Color(sal_uInt32(0x00ff00))) + : Any(util::Color(sal_uInt32(0xf2f2f2)))); + setPropertyValue( + maPropertyIdToNameMap[Rect_ToolBoxPadding], + Any(awt::Rectangle(2,2,2,2))); + setPropertyValue( + maPropertyIdToNameMap[Rect_ToolBoxBorder], + Any(awt::Rectangle(1,1,1,1))); + setPropertyValue( + maPropertyIdToNameMap[Bool_UseToolBoxItemSeparator], + Any(false)); + } + catch(beans::UnknownPropertyException& rException) + { + OSL_TRACE("unknown property: %s", + OUStringToOString( + rException.Message, + RTL_TEXTENCODING_ASCII_US).getStr()); + OSL_ASSERT(false); + } +} + + + + +void SAL_CALL Theme::disposing (void) +{ + ChangeListeners aListeners; + maChangeListeners.swap(aListeners); + + const lang::EventObject aEvent (static_cast<XWeak*>(this)); + + for (ChangeListeners::const_iterator + iContainer(maChangeListeners.begin()), + iContainerEnd(maChangeListeners.end()); + iContainerEnd!=iContainerEnd; + ++iContainerEnd) + { + for (ChangeListenerContainer::const_iterator + iListener(iContainer->second.begin()), + iEnd(iContainer->second.end()); + iListener!=iEnd; + ++iListener) + { + try + { + (*iListener)->disposing(aEvent); + } + catch(const Exception&) + { + } + } + } +} + + + + +Reference<beans::XPropertySet> Theme::GetPropertySet (void) +{ + return Reference<beans::XPropertySet>(static_cast<XWeak*>(&GetCurrentTheme()), UNO_QUERY); +} + + + + +Reference<beans::XPropertySetInfo> SAL_CALL Theme::getPropertySetInfo (void) + throw(cssu::RuntimeException) +{ + return Reference<beans::XPropertySetInfo>(this); +} + + + + +void SAL_CALL Theme::setPropertyValue ( + const ::rtl::OUString& rsPropertyName, + const cssu::Any& rValue) + throw(cssu::RuntimeException) +{ + PropertyNameToIdMap::const_iterator iId (maPropertyNameToIdMap.find(rsPropertyName)); + if (iId == maPropertyNameToIdMap.end()) + throw beans::UnknownPropertyException(rsPropertyName, NULL); + + const PropertyType eType (GetPropertyType(iId->second)); + if (eType == PT_Invalid) + throw beans::UnknownPropertyException(rsPropertyName, NULL); + + const ThemeItem eItem (iId->second); + + if (rValue == maRawValues[eItem]) + { + // Value is not different from the one in the property + // set => nothing to do. + return; + } + + const Any aOldValue (maRawValues[eItem]); + + const beans::PropertyChangeEvent aEvent( + static_cast<XWeak*>(this), + rsPropertyName, + sal_False, + eItem, + aOldValue, + rValue); + + if (DoVetoableListenersVeto(GetVetoableListeners(__AnyItem, false), aEvent)) + return; + if (DoVetoableListenersVeto(GetVetoableListeners(eItem, false), aEvent)) + return; + + maRawValues[eItem] = rValue; + ProcessNewValue(rValue, eItem, eType); + + BroadcastPropertyChange(GetChangeListeners(__AnyItem, false), aEvent); + BroadcastPropertyChange(GetChangeListeners(eItem, false), aEvent); +} + + + + +Any SAL_CALL Theme::getPropertyValue ( + const ::rtl::OUString& rsPropertyName) + throw(css::beans::UnknownPropertyException, + css::lang::WrappedTargetException, + cssu::RuntimeException) +{ + PropertyNameToIdMap::const_iterator iId (maPropertyNameToIdMap.find(rsPropertyName)); + if (iId == maPropertyNameToIdMap.end()) + throw beans::UnknownPropertyException(); + + const PropertyType eType (GetPropertyType(iId->second)); + if (eType == PT_Invalid) + throw beans::UnknownPropertyException(); + + const ThemeItem eItem (iId->second); + + return maRawValues[eItem]; +} + + + + +void SAL_CALL Theme::addPropertyChangeListener( + const ::rtl::OUString& rsPropertyName, + const cssu::Reference<css::beans::XPropertyChangeListener>& rxListener) + throw(css::beans::UnknownPropertyException, + css::lang::WrappedTargetException, + cssu::RuntimeException) +{ + ThemeItem eItem (__AnyItem); + if (rsPropertyName.getLength() > 0) + { + PropertyNameToIdMap::const_iterator iId (maPropertyNameToIdMap.find(rsPropertyName)); + if (iId == maPropertyNameToIdMap.end()) + throw beans::UnknownPropertyException(); + + const PropertyType eType (GetPropertyType(iId->second)); + if (eType == PT_Invalid) + throw beans::UnknownPropertyException(); + + eItem = iId->second; + } + ChangeListenerContainer* pListeners = GetChangeListeners(eItem, true); + if (pListeners != NULL) + pListeners->push_back(rxListener); +} + + + + +void SAL_CALL Theme::removePropertyChangeListener( + const ::rtl::OUString& rsPropertyName, + const cssu::Reference<css::beans::XPropertyChangeListener>& rxListener) + throw(css::beans::UnknownPropertyException, + css::lang::WrappedTargetException, + cssu::RuntimeException) +{ + ThemeItem eItem (__AnyItem); + if (rsPropertyName.getLength() > 0) + { + PropertyNameToIdMap::const_iterator iId (maPropertyNameToIdMap.find(rsPropertyName)); + if (iId == maPropertyNameToIdMap.end()) + throw beans::UnknownPropertyException(); + + const PropertyType eType (GetPropertyType(iId->second)); + if (eType == PT_Invalid) + throw beans::UnknownPropertyException(); + + eItem = iId->second; + } + ChangeListenerContainer* pContainer = GetChangeListeners(eItem, false); + if (pContainer != NULL) + { + ChangeListenerContainer::iterator iListener (::std::find(pContainer->begin(), pContainer->end(), rxListener)); + if (iListener != pContainer->end()) + { + pContainer->erase(iListener); + + // Remove the listener container when empty. + if (pContainer->empty()) + maChangeListeners.erase(eItem); + } + } +} + + + + +void SAL_CALL Theme::addVetoableChangeListener( + const ::rtl::OUString& rsPropertyName, + const cssu::Reference<css::beans::XVetoableChangeListener>& rxListener) + throw(css::beans::UnknownPropertyException, + css::lang::WrappedTargetException, + cssu::RuntimeException) +{ + ThemeItem eItem (__AnyItem); + if (rsPropertyName.getLength() > 0) + { + PropertyNameToIdMap::const_iterator iId (maPropertyNameToIdMap.find(rsPropertyName)); + if (iId == maPropertyNameToIdMap.end()) + throw beans::UnknownPropertyException(); + + const PropertyType eType (GetPropertyType(iId->second)); + if (eType == PT_Invalid) + throw beans::UnknownPropertyException(); + + eItem = iId->second; + } + VetoableListenerContainer* pListeners = GetVetoableListeners(eItem, true); + if (pListeners != NULL) + pListeners->push_back(rxListener); +} + + + + +void SAL_CALL Theme::removeVetoableChangeListener( + const ::rtl::OUString& rsPropertyName, + const cssu::Reference<css::beans::XVetoableChangeListener>& rxListener) + throw(css::beans::UnknownPropertyException, + css::lang::WrappedTargetException, + cssu::RuntimeException) +{ + ThemeItem eItem (__AnyItem); + if (rsPropertyName.getLength() > 0) + { + PropertyNameToIdMap::const_iterator iId (maPropertyNameToIdMap.find(rsPropertyName)); + if (iId == maPropertyNameToIdMap.end()) + throw beans::UnknownPropertyException(); + + const PropertyType eType (GetPropertyType(iId->second)); + if (eType == PT_Invalid) + throw beans::UnknownPropertyException(); + + eItem = iId->second; + } + VetoableListenerContainer* pContainer = GetVetoableListeners(eItem, false); + if (pContainer != NULL) + { + VetoableListenerContainer::iterator iListener (::std::find(pContainer->begin(), pContainer->end(), rxListener)); + if (iListener != pContainer->end()) + { + pContainer->erase(iListener); + // Remove container when empty. + if (pContainer->empty()) + maVetoableListeners.erase(eItem); + } + } +} + + + + +cssu::Sequence<css::beans::Property> SAL_CALL Theme::getProperties (void) + throw(cssu::RuntimeException) +{ + ::std::vector<beans::Property> aProperties; + + for (sal_Int32 nItem(__Begin),nEnd(__End); nItem!=nEnd; ++nItem) + { + const ThemeItem eItem (static_cast<ThemeItem>(nItem)); + const PropertyType eType (GetPropertyType(eItem)); + if (eType == PT_Invalid) + continue; + + const beans::Property aProperty( + maPropertyIdToNameMap[eItem], + eItem, + GetCppuType(eType), + 0); + aProperties.push_back(aProperty); + } + + return cssu::Sequence<css::beans::Property>( + &aProperties.front(), + aProperties.size()); +} + + + + +beans::Property SAL_CALL Theme::getPropertyByName (const ::rtl::OUString& rsPropertyName) + throw(css::beans::UnknownPropertyException, + cssu::RuntimeException) +{ + PropertyNameToIdMap::const_iterator iId (maPropertyNameToIdMap.find(rsPropertyName)); + if (iId == maPropertyNameToIdMap.end()) + throw beans::UnknownPropertyException(); + + const PropertyType eType (GetPropertyType(iId->second)); + if (eType == PT_Invalid) + throw beans::UnknownPropertyException(); + + const ThemeItem eItem (iId->second); + + return beans::Property( + rsPropertyName, + eItem, + GetCppuType(eType), + 0); +} + + + + +sal_Bool SAL_CALL Theme::hasPropertyByName (const ::rtl::OUString& rsPropertyName) + throw(cssu::RuntimeException) +{ + PropertyNameToIdMap::const_iterator iId (maPropertyNameToIdMap.find(rsPropertyName)); + if (iId == maPropertyNameToIdMap.end()) + return sal_False; + + const PropertyType eType (GetPropertyType(iId->second)); + if (eType == PT_Invalid) + return sal_False; + + return sal_True; +} + + + + +void Theme::SetupPropertyMaps (void) +{ + maPropertyIdToNameMap.resize(__Post_Rect); + maImages.resize(__Image_Color - __Pre_Image - 1); + maColors.resize(__Color_Paint - __Image_Color - 1); + maPaints.resize(__Paint_Int - __Color_Paint - 1); + maIntegers.resize(__Int_Bool - __Paint_Int - 1); + maBooleans.resize(__Bool_Rect - __Int_Bool - 1); + maRectangles.resize(__Post_Rect - __Bool_Rect - 1); + + #define AddEntry(e) maPropertyNameToIdMap[A2S(#e)]=e; maPropertyIdToNameMap[e]=A2S(#e) + + AddEntry(Image_Grip); + AddEntry(Image_Expand); + AddEntry(Image_Collapse); + AddEntry(Image_TabBarMenu); + AddEntry(Image_PanelMenu); + AddEntry(Image_ToolBoxItemSeparator); + AddEntry(Image_Closer); + + AddEntry(Color_DeckTitleFont); + AddEntry(Color_PanelTitleFont); + AddEntry(Color_TabMenuSeparator); + AddEntry(Color_TabItemBorder); + AddEntry(Color_DropDownBorder); + AddEntry(Color_Highlight); + AddEntry(Color_HighlightText); + + AddEntry(Paint_DeckBackground); + AddEntry(Paint_DeckTitleBarBackground); + AddEntry(Paint_PanelBackground); + AddEntry(Paint_PanelTitleBarBackground); + AddEntry(Paint_TabBarBackground); + AddEntry(Paint_TabItemBackgroundNormal); + AddEntry(Paint_TabItemBackgroundHighlight); + AddEntry(Paint_HorizontalBorder); + AddEntry(Paint_VerticalBorder); + AddEntry(Paint_ToolBoxBackground); + AddEntry(Paint_ToolBoxBorderTopLeft); + AddEntry(Paint_ToolBoxBorderCenterCorners); + AddEntry(Paint_ToolBoxBorderBottomRight); + AddEntry(Paint_DropDownBackground); + + AddEntry(Int_DeckTitleBarHeight); + AddEntry(Int_DeckBorderSize); + AddEntry(Int_DeckSeparatorHeight); + AddEntry(Int_PanelTitleBarHeight); + AddEntry(Int_TabMenuPadding); + AddEntry(Int_TabMenuSeparatorPadding); + AddEntry(Int_TabItemWidth); + AddEntry(Int_TabItemHeight); + AddEntry(Int_DeckLeftPadding); + AddEntry(Int_DeckTopPadding); + AddEntry(Int_DeckRightPadding); + AddEntry(Int_DeckBottomPadding); + AddEntry(Int_TabBarLeftPadding); + AddEntry(Int_TabBarTopPadding); + AddEntry(Int_TabBarRightPadding); + AddEntry(Int_TabBarBottomPadding); + AddEntry(Int_ButtonCornerRadius); + + AddEntry(Bool_UseSymphonyIcons); + AddEntry(Bool_UseSystemColors); + AddEntry(Bool_UseToolBoxItemSeparator); + AddEntry(Bool_IsHighContrastModeActive); + + AddEntry(Rect_ToolBoxPadding); + AddEntry(Rect_ToolBoxBorder); + + #undef AddEntry + + maRawValues.resize(maPropertyIdToNameMap.size()); +} + + + + +Theme::PropertyType Theme::GetPropertyType (const ThemeItem eItem) +{ + switch(eItem) + { + case Image_Grip: + case Image_Expand: + case Image_Collapse: + case Image_TabBarMenu: + case Image_PanelMenu: + case Image_ToolBoxItemSeparator: + case Image_Closer: + return PT_Image; + + case Color_DeckTitleFont: + case Color_PanelTitleFont: + case Color_TabMenuSeparator: + case Color_TabItemBorder: + case Color_DropDownBorder: + case Color_Highlight: + case Color_HighlightText: + return PT_Color; + + case Paint_DeckBackground: + case Paint_DeckTitleBarBackground: + case Paint_PanelBackground: + case Paint_PanelTitleBarBackground: + case Paint_TabBarBackground: + case Paint_TabItemBackgroundNormal: + case Paint_TabItemBackgroundHighlight: + case Paint_HorizontalBorder: + case Paint_VerticalBorder: + case Paint_ToolBoxBackground: + case Paint_ToolBoxBorderTopLeft: + case Paint_ToolBoxBorderCenterCorners: + case Paint_ToolBoxBorderBottomRight: + case Paint_DropDownBackground: + return PT_Paint; + + case Int_DeckTitleBarHeight: + case Int_DeckBorderSize: + case Int_DeckSeparatorHeight: + case Int_PanelTitleBarHeight: + case Int_TabMenuPadding: + case Int_TabMenuSeparatorPadding: + case Int_TabItemWidth: + case Int_TabItemHeight: + case Int_DeckLeftPadding: + case Int_DeckTopPadding: + case Int_DeckRightPadding: + case Int_DeckBottomPadding: + case Int_TabBarLeftPadding: + case Int_TabBarTopPadding: + case Int_TabBarRightPadding: + case Int_TabBarBottomPadding: + case Int_ButtonCornerRadius: + return PT_Integer; + + case Bool_UseSymphonyIcons: + case Bool_UseSystemColors: + case Bool_UseToolBoxItemSeparator: + case Bool_IsHighContrastModeActive: + return PT_Boolean; + + case Rect_ToolBoxBorder: + case Rect_ToolBoxPadding: + return PT_Rectangle; + + default: + return PT_Invalid; + } +} + + + + +cssu::Type Theme::GetCppuType (const PropertyType eType) +{ + switch(eType) + { + case PT_Image: + return getCppuType((rtl::OUString*)NULL); + + case PT_Color: + return getCppuType((sal_uInt32*)NULL); + + case PT_Paint: + return getCppuVoidType(); + + case PT_Integer: + return getCppuType((sal_Int32*)NULL); + + case PT_Boolean: + return getCppuType((sal_Bool*)NULL); + + case PT_Rectangle: + return getCppuType((awt::Rectangle*)NULL); + + case PT_Invalid: + default: + return getCppuVoidType(); + } +} + + + + +sal_Int32 Theme::GetIndex (const ThemeItem eItem, const PropertyType eType) +{ + switch(eType) + { + case PT_Image: + return eItem - __Pre_Image-1; + case PT_Color: + return eItem - __Image_Color-1; + case PT_Paint: + return eItem - __Color_Paint-1; + case PT_Integer: + return eItem - __Paint_Int-1; + case PT_Boolean: + return eItem - __Int_Bool-1; + case PT_Rectangle: + return eItem - __Bool_Rect-1; + + default: + OSL_ASSERT(false); + return 0; + } +} + + + + +Theme::VetoableListenerContainer* Theme::GetVetoableListeners ( + const ThemeItem eItem, + const bool bCreate) +{ + VetoableListeners::iterator iContainer (maVetoableListeners.find(eItem)); + if (iContainer != maVetoableListeners.end()) + return &iContainer->second; + else if (bCreate) + { + maVetoableListeners[eItem] = VetoableListenerContainer(); + return &maVetoableListeners[eItem]; + } + else + return NULL; +} + + + + +Theme::ChangeListenerContainer* Theme::GetChangeListeners ( + const ThemeItem eItem, + const bool bCreate) +{ + ChangeListeners::iterator iContainer (maChangeListeners.find(eItem)); + if (iContainer != maChangeListeners.end()) + return &iContainer->second; + else if (bCreate) + { + maChangeListeners[eItem] = ChangeListenerContainer(); + return &maChangeListeners[eItem]; + } + else + return NULL; +} + + + + +bool Theme::DoVetoableListenersVeto ( + const VetoableListenerContainer* pListeners, + const beans::PropertyChangeEvent& rEvent) const +{ + if (pListeners == NULL) + return false; + + VetoableListenerContainer aListeners (*pListeners); + try + { + for (VetoableListenerContainer::const_iterator + iListener(aListeners.begin()), + iEnd(aListeners.end()); + iListener!=iEnd; + ++iListener) + { + (*iListener)->vetoableChange(rEvent); + } + } + catch(const beans::PropertyVetoException&) + { + return true; + } + catch(const Exception&) + { + // Ignore any other errors (such as disposed listeners). + } + return false; +} + + + + +void Theme::BroadcastPropertyChange ( + const ChangeListenerContainer* pListeners, + const beans::PropertyChangeEvent& rEvent) const +{ + if (pListeners == NULL) + return; + + const ChangeListenerContainer aListeners (*pListeners); + try + { + for (ChangeListenerContainer::const_iterator + iListener(aListeners.begin()), + iEnd(aListeners.end()); + iListener!=iEnd; + ++iListener) + { + (*iListener)->propertyChange(rEvent); + } + } + catch(const Exception&) + { + // Ignore any errors (such as disposed listeners). + } +} + + + + +void Theme::ProcessNewValue ( + const Any& rValue, + const ThemeItem eItem, + const PropertyType eType) +{ + const sal_Int32 nIndex (GetIndex (eItem, eType)); + switch (eType) + { + case PT_Image: + { + ::rtl::OUString sURL; + if (rValue >>= sURL) + { + maImages[nIndex] = Tools::GetImage(sURL, NULL); + } + break; + } + case PT_Color: + { + sal_Int32 nColorValue (0); + if (rValue >>= nColorValue) + { + maColors[nIndex] = Color(nColorValue); + } + break; + } + case PT_Paint: + { + maPaints[nIndex] = Paint::Create(rValue); + break; + } + case PT_Integer: + { + sal_Int32 nValue (0); + if (rValue >>= nValue) + { + maIntegers[nIndex] = nValue; + } + break; + } + case PT_Boolean: + { + sal_Bool nValue (0); + if (rValue >>= nValue) + { + maBooleans[nIndex] = (nValue==sal_True); + if (eItem == Bool_IsHighContrastModeActive) + { + mbIsHighContrastModeSetManually = true; + mbIsHighContrastMode = maBooleans[nIndex]; + HandleDataChange(); + } + else if (eItem == Bool_UseSystemColors) + { + HandleDataChange(); + } + } + break; + } + case PT_Rectangle: + { + awt::Rectangle aBox; + if (rValue >>= aBox) + { + maRectangles[nIndex] = Rectangle( + aBox.X, + aBox.Y, + aBox.Width, + aBox.Height); + } + break; + } + case PT_Invalid: + OSL_ASSERT(eType != PT_Invalid); + throw RuntimeException(); + } +} + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/TitleBar.cxx b/sfx2/source/sidebar/TitleBar.cxx new file mode 100644 index 000000000000..1a48d0308fbf --- /dev/null +++ b/sfx2/source/sidebar/TitleBar.cxx @@ -0,0 +1,193 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "TitleBar.hxx" +#include "Paint.hxx" + +#include <tools/svborder.hxx> +#include <vcl/gradient.hxx> +#include <vcl/lineinfo.hxx> + +ToolbarValue::~ToolbarValue (void) {} + + +namespace sfx2 { namespace sidebar { + +TitleBar::TitleBar ( + const ::rtl::OUString& rsTitle, + Window* pParentWindow, + const sidebar::Paint& rInitialBackgroundPaint) + : Window(pParentWindow), + maToolBox(this), + msTitle(rsTitle) +{ + SetBackground(rInitialBackgroundPaint.GetWallpaper()); + + maToolBox.SetSelectHdl(LINK(this, TitleBar, SelectionHandler)); +} + + + + +TitleBar::~TitleBar (void) +{ +} + + + + +void TitleBar::SetTitle (const ::rtl::OUString& rsTitle) +{ + msTitle = rsTitle; + Invalidate(); +} + + + + +void TitleBar::Paint (const Rectangle& rUpdateArea) +{ + (void)rUpdateArea; + + // Paint title bar background. + Size aWindowSize (GetOutputSizePixel()); + Rectangle aTitleBarBox( + 0, + 0, + aWindowSize.Width(), + aWindowSize.Height() + ); + + PaintDecoration(aTitleBarBox); + const Rectangle aTitleBox (GetTitleArea(aTitleBarBox)); + PaintTitle(aTitleBox); + if (HasFocus()) + PaintFocus(aTitleBox); +} + + + + +void TitleBar::DataChanged (const DataChangedEvent& rEvent) +{ + (void)rEvent; + + SetBackground(GetBackgroundPaint().GetWallpaper()); +} + + + + +void TitleBar::setPosSizePixel ( + long nX, + long nY, + long nWidth, + long nHeight, + sal_uInt16 nFlags) +{ + Window::setPosSizePixel(nX,nY,nWidth,nHeight,nFlags); + + // Place the toolbox. + const sal_Int32 nToolBoxWidth (maToolBox.GetItemPosRect(0).GetWidth()); + maToolBox.setPosSizePixel(nWidth-nToolBoxWidth,0,nToolBoxWidth,nHeight); + maToolBox.Show(); +} + + + + +ToolBox& TitleBar::GetToolBox (void) +{ + return maToolBox; +} + + + + +void TitleBar::HandleToolBoxItemClick (const sal_uInt16 nItemIndex) +{ + (void)nItemIndex; + // Any real processing has to be done in derived class. +} + + + + +void TitleBar::PaintTitle (const Rectangle& rTitleBox) +{ + Push(PUSH_FONT | PUSH_TEXTCOLOR); + + Font aFont(GetFont()); + SetFont(aFont); + + // Paint title bar text. + SetTextColor(GetTextColor()); + DrawText( + rTitleBox, + msTitle, + TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER); + + Pop(); +} + + + + +void TitleBar::PaintFocus (const Rectangle& rFocusBox) +{ + Push(PUSH_FONT | PUSH_TEXTCOLOR | PUSH_LINECOLOR | PUSH_FILLCOLOR); + + const Rectangle aTextBox ( + GetTextRect( + rFocusBox, + msTitle, + TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER)); + const Rectangle aLargerTextBox ( + aTextBox.Left() - 2, + aTextBox.Top() - 2, + aTextBox.Right() + 2, + aTextBox.Bottom() + 2); + + LineInfo aDottedStyle (LINE_DASH); + aDottedStyle.SetDashCount(0); + aDottedStyle.SetDotCount(1); + aDottedStyle.SetDotLen(1); + aDottedStyle.SetDistance(1); + + SetFillColor(); + SetLineColor(COL_BLACK); + DrawPolyLine(Polygon(aLargerTextBox), aDottedStyle); + + Pop(); +} + + + + +IMPL_LINK(TitleBar, SelectionHandler, ToolBox*, pToolBox) +{ + (void)pToolBox; + OSL_ASSERT(&maToolBox==pToolBox); + const sal_uInt16 nItemId (maToolBox.GetHighlightItemId()); + + HandleToolBoxItemClick(nItemId); + + return sal_True; +} + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/TitleBar.hxx b/sfx2/source/sidebar/TitleBar.hxx new file mode 100644 index 000000000000..4f4f67c8b601 --- /dev/null +++ b/sfx2/source/sidebar/TitleBar.hxx @@ -0,0 +1,72 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_TITLE_BAR_HXX +#define SFX_SIDEBAR_TITLE_BAR_HXX + +#include "Paint.hxx" + +#include <vcl/window.hxx> +#include <vcl/toolbox.hxx> + + +namespace sfx2 { namespace sidebar { + +class TitleBar + : public Window +{ +public: + TitleBar ( + const ::rtl::OUString& rsTitle, + Window* pParentWindow, + const sidebar::Paint& rInitialBackgroundPaint); + virtual ~TitleBar (void); + + void SetTitle (const ::rtl::OUString& rsTitle); + + virtual void Paint (const Rectangle& rUpdateArea); + virtual void DataChanged (const DataChangedEvent& rEvent); + virtual void setPosSizePixel ( + long nX, + long nY, + long nWidth, + long nHeight, + sal_uInt16 nFlags = WINDOW_POSSIZE_ALL); + + ToolBox& GetToolBox (void); + +protected: + ToolBox maToolBox; + + virtual Rectangle GetTitleArea (const Rectangle& rTitleBarBox) = 0; + virtual void PaintDecoration (const Rectangle& rTitleBarBox) = 0; + virtual void PaintFocus (const Rectangle& rFocusBox); + virtual sidebar::Paint GetBackgroundPaint (void) = 0; + virtual Color GetTextColor (void) = 0; + virtual void HandleToolBoxItemClick (const sal_uInt16 nItemIndex); + +private: + ::rtl::OUString msTitle; + + void PaintTitle (const Rectangle& rTitleBox); + DECL_LINK(SelectionHandler, ToolBox*); +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/ToolBox.hxx b/sfx2/source/sidebar/ToolBox.hxx new file mode 100644 index 000000000000..8de0a6b003ee --- /dev/null +++ b/sfx2/source/sidebar/ToolBox.hxx @@ -0,0 +1,52 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_TOOLBOX_HXX +#define SFX_SIDEBAR_TOOLBOX_HXX + +#include "vcl/toolbox.hxx" + + +namespace sfx2 { namespace sidebar { + +class ToolBox + : public ::ToolBox +{ +public: + MenuButton (Window* pParentWindow); + virtual ~MenuButton (void); + + virtual void Paint (const Rectangle& rUpdateArea); + virtual void MouseMove (const MouseEvent& rEvent); + virtual void MouseButtonDown (const MouseEvent& rMouseEvent); + virtual void MouseButtonUp (const MouseEvent& rMouseEvent); + +protected: + using CheckBox::FillLayoutData; + +private: + bool mbIsLeftButtonDown; + enum PaintType { + PT_Native, + PT_Theme + } mePaintType; +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/ToolBoxBackground.cxx b/sfx2/source/sidebar/ToolBoxBackground.cxx new file mode 100644 index 000000000000..1336c03478ed --- /dev/null +++ b/sfx2/source/sidebar/ToolBoxBackground.cxx @@ -0,0 +1,148 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include "ToolBoxBackground.hxx" +#include "Paint.hxx" +#include "DrawHelper.hxx" +#include "Tools.hxx" +#include "sfx2/sidebar/Theme.hxx" + +#include <vcl/toolbox.hxx> +#include <vcl/gradient.hxx> +#include <svl/smplhint.hxx> + + +namespace sfx2 { namespace sidebar { + +ToolBoxBackground::ToolBoxBackground (Window* pParentWindow) + : Window(pParentWindow, WB_DIALOGCONTROL), + maPadding(Tools::RectangleToSvBorder(Theme::GetRectangle(Theme::Rect_ToolBoxPadding))) +{ + SetBackground(Theme::GetPaint(Theme::Paint_ToolBoxBackground).GetWallpaper()); + +#ifdef DEBUG + SetText(A2S("ToolBoxBackground")); +#endif +} + + + + +ToolBoxBackground::~ToolBoxBackground (void) +{ + Link aEventListener (LINK(this, ToolBoxBackground, WindowEventHandler)); + if (GetChildCount() > 0) + GetChild(0)->RemoveEventListener(aEventListener); +} + + + + +Point ToolBoxBackground::SetToolBoxChild ( + ToolBox* pChild, + long nX, + long nY, + long nWidth, + long nHeight, + sal_uInt16 nFlags) +{ + if (pChild == NULL) + { + OSL_ASSERT(pChild!=NULL); + return Point(nX, nY); + } + + Link aEventListener (LINK(this, ToolBoxBackground, WindowEventHandler)); + pChild->AddEventListener(aEventListener); + + setPosSizePixel( + nX - maPadding.Left(), + nY - maPadding.Top(), + nWidth + maPadding.Left() + maPadding.Right(), + nHeight + maPadding.Top() + maPadding.Bottom(), + nFlags); + return Point( + maPadding.Left(), + maPadding.Top()); +} + + + + +void ToolBoxBackground::Paint (const Rectangle& rRect) +{ + Window::Paint(rRect); + + Rectangle aBox (Point(0,0), GetSizePixel()); + + const sidebar::Paint aTopLeftBorderPaint (Theme::GetPaint(Theme::Paint_ToolBoxBorderTopLeft)); + const sidebar::Paint aCenterBorderPaint (Theme::GetPaint(Theme::Paint_ToolBoxBorderCenterCorners)); + const sidebar::Paint aBottomRightBorderPaint (Theme::GetPaint(Theme::Paint_ToolBoxBorderBottomRight)); + const Rectangle aBorderSize (Theme::GetRectangle(Theme::Rect_ToolBoxBorder)); + DrawHelper::DrawBevelBorder ( + *this, + aBox, + Tools::RectangleToSvBorder(aBorderSize), + aTopLeftBorderPaint, + aCenterBorderPaint, + aBottomRightBorderPaint); +} + + + + +void ToolBoxBackground::DataChanged (const DataChangedEvent& rEvent) +{ + (void)rEvent; + + SetBackground(Theme::GetPaint(Theme::Paint_ToolBoxBackground).GetWallpaper()); + maPadding = Tools::RectangleToSvBorder(Theme::GetRectangle(Theme::Rect_ToolBoxPadding)); +} + + + + +IMPL_LINK(ToolBoxBackground, WindowEventHandler, VclWindowEvent*, pEvent) +{ + if (pEvent != NULL) + { + switch (pEvent->GetId()) + { + case VCLEVENT_WINDOW_SHOW: + if (GetChild(0)->IsVisible()) + Show(); + break; + + case VCLEVENT_WINDOW_HIDE: + if ( ! GetChild(0)->IsVisible()) + Hide(); + break; + + case SFX_HINT_DYING: + doLazyDelete(); + break; + + default: + break; + } + } + + return sal_True; +} + + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/ToolBoxBackground.hxx b/sfx2/source/sidebar/ToolBoxBackground.hxx new file mode 100644 index 000000000000..e5204b921204 --- /dev/null +++ b/sfx2/source/sidebar/ToolBoxBackground.hxx @@ -0,0 +1,64 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_TOOLBOX_BACKGROUND_HXX +#define SFX_SIDEBAR_TOOLBOX_BACKGROUND_HXX + +#include "vcl/window.hxx" + +#include <tools/svborder.hxx> + + +class ToolBox; + +namespace sfx2 { namespace sidebar { + +class ToolBoxBackground + : public Window +{ +public: + ToolBoxBackground (Window* pParentWindow); + virtual ~ToolBoxBackground (void); + + /** Call this method once to + a) let the ToolBoxBackground object know which ToolBox to + monitor and + b) so that position and sizes can be set up. + @return + The relative position of the child. + */ + Point SetToolBoxChild ( + ToolBox* pChild, + long nX, + long nY, + long nWidth, + long nHeight, + sal_uInt16 nFlags); + + virtual void Paint (const Rectangle& rRect); + virtual void DataChanged (const DataChangedEvent& rEvent); + +private: + SvBorder maPadding; + + DECL_LINK(WindowEventHandler, VclWindowEvent*); +}; + + +} } // end of namespace sfx2::sidebar + +#endif diff --git a/sfx2/source/sidebar/Tools.cxx b/sfx2/source/sidebar/Tools.cxx new file mode 100644 index 000000000000..27956cd6670d --- /dev/null +++ b/sfx2/source/sidebar/Tools.cxx @@ -0,0 +1,150 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "Tools.hxx" + +#include "sfx2/sidebar/Theme.hxx" + +#include "sfx2/imagemgr.hxx" +#include <comphelper/processfactory.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <vcl/gradient.hxx> + +#include <com/sun/star/graphic/XGraphicProvider.hpp> + +#include <cstring> + +using namespace css; +using namespace cssu; + + +namespace sfx2 { namespace sidebar { + +Image Tools::GetImage ( + const ::rtl::OUString& rsImageURL, + const ::rtl::OUString& rsHighContrastImageURL, + const Reference<frame::XFrame>& rxFrame) +{ + if (Theme::IsHighContrastMode()) + return GetImage(rsHighContrastImageURL, rxFrame); + else + return GetImage(rsImageURL, rxFrame); +} + + + + +Image Tools::GetImage ( + const ::rtl::OUString& rsURL, + const Reference<frame::XFrame>& rxFrame) +{ + if (rsURL.getLength() > 0) + { + const sal_Char sUnoCommandPrefix[] = ".uno:"; + const sal_Char sCommandImagePrefix[] = "private:commandimage/"; + const sal_Int32 nCommandImagePrefixLength = strlen(sCommandImagePrefix); + + if (rsURL.startsWith(sUnoCommandPrefix)) + { + const Image aPanelImage (::GetImage(rxFrame, rsURL, sal_False)); + return aPanelImage; + } + else if (rsURL.startsWith(sCommandImagePrefix)) + { + ::rtl::OUStringBuffer aCommandName; + aCommandName.appendAscii(sUnoCommandPrefix); + aCommandName.append(rsURL.copy(nCommandImagePrefixLength)); + const ::rtl::OUString sCommandName (aCommandName.makeStringAndClear()); + + const Image aPanelImage (::GetImage(rxFrame, sCommandName, sal_False)); + return aPanelImage; + } + else + { + const ::comphelper::ComponentContext aContext (::comphelper::getProcessServiceFactory()); + const Reference<graphic::XGraphicProvider> xGraphicProvider ( + aContext.createComponent("com.sun.star.graphic.GraphicProvider"), + UNO_QUERY); + if ( xGraphicProvider.is()) + { + ::comphelper::NamedValueCollection aMediaProperties; + aMediaProperties.put("URL", rsURL); + const Reference<graphic::XGraphic> xGraphic ( + xGraphicProvider->queryGraphic(aMediaProperties.getPropertyValues()), + UNO_QUERY); + if (xGraphic.is()) + return Image(xGraphic); + } + } + } + return Image(); +} + + + + +css::awt::Gradient Tools::VclToAwtGradient (const Gradient aVclGradient) +{ + css::awt::Gradient aAwtGradient ( + awt::GradientStyle(aVclGradient.GetStyle()), + aVclGradient.GetStartColor().GetRGBColor(), + aVclGradient.GetEndColor().GetRGBColor(), + aVclGradient.GetAngle(), + aVclGradient.GetBorder(), + aVclGradient.GetOfsX(), + aVclGradient.GetOfsY(), + aVclGradient.GetStartIntensity(), + aVclGradient.GetEndIntensity(), + aVclGradient.GetSteps()); + return aAwtGradient; +} + + + + +Gradient Tools::AwtToVclGradient (const css::awt::Gradient aAwtGradient) +{ + Gradient aVclGradient ( + GradientStyle(aAwtGradient.Style), + aAwtGradient.StartColor, + aAwtGradient.EndColor); + aVclGradient.SetAngle(aAwtGradient.Angle); + aVclGradient.SetBorder(aAwtGradient.Border); + aVclGradient.SetOfsX(aAwtGradient.XOffset); + aVclGradient.SetOfsY(aAwtGradient.YOffset); + aVclGradient.SetStartIntensity(aAwtGradient.StartIntensity); + aVclGradient.SetEndIntensity(aAwtGradient.EndIntensity); + aVclGradient.SetSteps(aAwtGradient.StepCount); + + return aVclGradient; +} + + + + +SvBorder Tools::RectangleToSvBorder (const Rectangle aBox) +{ + return SvBorder( + aBox.Left(), + aBox.Top(), + aBox.Right(), + aBox.Bottom()); +} + +} } // end of namespace sfx2::sidebar diff --git a/sfx2/source/sidebar/Tools.hxx b/sfx2/source/sidebar/Tools.hxx new file mode 100644 index 000000000000..70bc7f995d0c --- /dev/null +++ b/sfx2/source/sidebar/Tools.hxx @@ -0,0 +1,59 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef SFX_SIDEBAR_TOOLS_HXX +#define SFX_SIDEBAR_TOOLS_HXX + +#include <vcl/image.hxx> +#include <vcl/gradient.hxx> +#include <tools/svborder.hxx> + +#include <com/sun/star/awt/Gradient.hpp> +#include <com/sun/star/frame/XFrame.hpp> + + +#define A2S(s) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s))) +#define S2A(s) rtl::OUStringToOString(s, RTL_TEXTENCODING_ASCII_US).getStr() + +namespace css = ::com::sun::star; +namespace cssu = ::com::sun::star::uno; + + +namespace sfx2 { namespace sidebar { + +class Tools +{ +public: + static Image GetImage ( + const ::rtl::OUString& rsImageURL, + const ::rtl::OUString& rsHighContrastImageURL, + const cssu::Reference<css::frame::XFrame>& rxFrame); + + static Image GetImage ( + const ::rtl::OUString& rsURL, + const cssu::Reference<css::frame::XFrame>& rxFrame); + + static css::awt::Gradient VclToAwtGradient (const Gradient aGradient); + static Gradient AwtToVclGradient (const css::awt::Gradient aGradient); + + static SvBorder RectangleToSvBorder (const Rectangle aBox); +}; + + +} } // end of namespace sfx2::sidebar + +#endif |