/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * 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 #include #include #include #include #include #include #include #include #include #include using namespace css; using namespace css::uno; namespace sfx2 { namespace sidebar { namespace { OUString getString(utl::OConfigurationNode const & aNode, const char* pNodeName) { return comphelper::getString(aNode.getNodeValue(pNodeName)); } sal_Int32 getInt32(utl::OConfigurationNode const & aNode, const char* pNodeName) { return comphelper::getINT32(aNode.getNodeValue(pNodeName)); } bool getBool(utl::OConfigurationNode const & aNode, const char* pNodeName) { return comphelper::getBOOL(aNode.getNodeValue(pNodeName)); } css::uno::Sequence BuildContextList (ContextList rContextList) { const ::std::vector& entries = rContextList.GetEntries(); css::uno::Sequence result(entries.size()); long i = 0; for (::std::vector::const_iterator iEntry(entries.begin()), iEnd(entries.end()); iEntry!=iEnd; ++iEntry) { OUString appName = iEntry->maContext.msApplication; OUString contextName = iEntry->maContext.msContext; OUString menuCommand = iEntry->msMenuCommand; OUString visibility; if (iEntry->mbIsInitiallyVisible) visibility = "visible"; else visibility = "hidden"; OUString element = appName + ", " + contextName +", " + visibility; if (!menuCommand.isEmpty()) element += ", "+menuCommand; result[i] = element; i++; } return result; } } //end anonymous namespace ResourceManager::ResourceManager() : maDecks(), maPanels(), maProcessedApplications(), maMiscOptions() { ReadDeckList(); ReadPanelList(); } ResourceManager::~ResourceManager() { } void ResourceManager::InitDeckContext(const Context& rContext) { DeckContainer::iterator iDeck; for (iDeck = maDecks.begin(); iDeck != maDecks.end(); ++iDeck) { bool bIsEnabled; const ContextList::Entry* pMatchingEntry = iDeck->maContextList.GetMatch(rContext); if (pMatchingEntry) bIsEnabled = pMatchingEntry->mbIsInitiallyVisible; else bIsEnabled = false; iDeck->mbIsEnabled = bIsEnabled; } } const DeckDescriptor* ResourceManager::ImplGetDeckDescriptor(const OUString& rsDeckId) const { DeckContainer::const_iterator iDeck; for (iDeck = maDecks.begin(); iDeck != maDecks.end(); ++iDeck) { if (iDeck->mbExperimental && !maMiscOptions.IsExperimentalMode()) continue; if (iDeck->msId.equals(rsDeckId)) return &*iDeck; } return nullptr; } const DeckDescriptor* ResourceManager::GetDeckDescriptor(const OUString& rsDeckId) const { return ImplGetDeckDescriptor( rsDeckId ); } DeckDescriptor* ResourceManager::GetDeckDescriptor(const OUString& rsDeckId) { const ResourceManager* constMe = this; return const_cast( constMe->ImplGetDeckDescriptor(rsDeckId) ); } const PanelDescriptor* ResourceManager::ImplGetPanelDescriptor(const OUString& rsPanelId) const { PanelContainer::const_iterator iPanel; for (iPanel = maPanels.begin(); iPanel != maPanels.end(); ++iPanel) { if (iPanel->msId.equals(rsPanelId)) return &*iPanel; } return nullptr; } const PanelDescriptor* ResourceManager::GetPanelDescriptor(const OUString& rsPanelId) const { return ImplGetPanelDescriptor( rsPanelId ); } PanelDescriptor* ResourceManager::GetPanelDescriptor(const OUString& rsPanelId) { const ResourceManager* constMe = this; return const_cast( constMe->ImplGetPanelDescriptor(rsPanelId) ); } const ResourceManager::DeckContextDescriptorContainer& ResourceManager::GetMatchingDecks ( DeckContextDescriptorContainer& rDecks, const Context& rContext, const bool bIsDocumentReadOnly, const Reference& rxController) { ReadLegacyAddons(rxController); std::multimap aOrderedIds; DeckContainer::const_iterator iDeck; for (iDeck = maDecks.begin(); iDeck != maDecks.end(); ++iDeck) { if (iDeck->mbExperimental && !maMiscOptions.IsExperimentalMode()) continue; const DeckDescriptor& rDeckDescriptor (*iDeck); if (rDeckDescriptor.maContextList.GetMatch(rContext) == nullptr) continue; DeckContextDescriptor aDeckContextDescriptor; aDeckContextDescriptor.msId = rDeckDescriptor.msId; aDeckContextDescriptor.mbIsEnabled = (! bIsDocumentReadOnly || IsDeckEnabled(rDeckDescriptor.msId, rContext, rxController) ) && rDeckDescriptor.mbIsEnabled; aOrderedIds.insert(::std::multimap::value_type( rDeckDescriptor.mnOrderIndex, aDeckContextDescriptor)); } std::multimap::const_iterator iId; for (iId = aOrderedIds.begin(); iId != aOrderedIds.end(); ++iId) { rDecks.push_back(iId->second); } return rDecks; } const ResourceManager::PanelContextDescriptorContainer& ResourceManager::GetMatchingPanels ( PanelContextDescriptorContainer& rPanelIds, const Context& rContext, const OUString& rsDeckId, const Reference& rxController) { ReadLegacyAddons(rxController); std::multimap aOrderedIds; PanelContainer::const_iterator iPanel; for (iPanel = maPanels.begin(); iPanel != maPanels.end(); ++iPanel) { const PanelDescriptor& rPanelDescriptor (*iPanel); if (rPanelDescriptor.mbExperimental && !maMiscOptions.IsExperimentalMode()) continue; if ( ! rPanelDescriptor.msDeckId.equals(rsDeckId)) continue; const ContextList::Entry* pEntry = rPanelDescriptor.maContextList.GetMatch(rContext); if (pEntry == nullptr) continue; PanelContextDescriptor aPanelContextDescriptor; aPanelContextDescriptor.msId = rPanelDescriptor.msId; aPanelContextDescriptor.msMenuCommand = pEntry->msMenuCommand; aPanelContextDescriptor.mbIsInitiallyVisible = pEntry->mbIsInitiallyVisible; aPanelContextDescriptor.mbShowForReadOnlyDocuments = rPanelDescriptor.mbShowForReadOnlyDocuments; aOrderedIds.insert(std::multimap::value_type( rPanelDescriptor.mnOrderIndex, aPanelContextDescriptor)); } std::multimap::const_iterator iId; for (iId = aOrderedIds.begin(); iId != aOrderedIds.end(); ++iId) { rPanelIds.push_back(iId->second); } return rPanelIds; } void ResourceManager::ReadDeckList() { const utl::OConfigurationTreeRoot aDeckRootNode( comphelper::getProcessComponentContext(), OUString("org.openoffice.Office.UI.Sidebar/Content/DeckList"), false); if (!aDeckRootNode.isValid()) return; const Sequence aDeckNodeNames (aDeckRootNode.getNodeNames()); const sal_Int32 nCount(aDeckNodeNames.getLength()); maDecks.resize(nCount); sal_Int32 nWriteIndex(0); for (sal_Int32 nReadIndex(0); nReadIndexmaContextList.GetMatch(rContext); if (pMatchingEntry) { const DeckDescriptor* pDeckDesc = GetDeckDescriptor(iDeck->msId); if (pDeckDesc) SaveDeckSettings(pDeckDesc); } } } void ResourceManager::SaveDeckSettings(const DeckDescriptor* pDeckDesc) { const utl::OConfigurationTreeRoot aDeckRootNode( comphelper::getProcessComponentContext(), OUString("org.openoffice.Office.UI.Sidebar/Content/DeckList"), true); if (!aDeckRootNode.isValid()) return; // save deck settings ::uno::Sequence< OUString > sContextList = BuildContextList(pDeckDesc->maContextList); utl::OConfigurationNode aDeckNode (aDeckRootNode.openNode(pDeckDesc->msNodeName)); aDeckNode.setNodeValue("Title", makeAny(pDeckDesc->msTitle)); aDeckNode.setNodeValue("OrderIndex", makeAny(pDeckDesc->mnOrderIndex)); aDeckNode.setNodeValue("ContextList", makeAny( sContextList )); aDeckRootNode.commit(); // save panel settings const utl::OConfigurationTreeRoot aPanelRootNode( comphelper::getProcessComponentContext(), OUString("org.openoffice.Office.UI.Sidebar/Content/PanelList"), true); if (!aPanelRootNode.isValid()) return; if (!pDeckDesc->mpDeck) // the deck has not been edited return; SharedPanelContainer rPanels = pDeckDesc->mpDeck->GetPanels(); for ( SharedPanelContainer::iterator iPanel(rPanels.begin()), iEnd(rPanels.end()); iPanel!=iEnd; ++iPanel) { Panel* aPanel = *iPanel; OUString panelId = aPanel->GetId(); const PanelDescriptor* pPanelDesc = GetPanelDescriptor(panelId); ::uno::Sequence< OUString > sPanelContextList = BuildContextList(pPanelDesc->maContextList); utl::OConfigurationNode aPanelNode (aPanelRootNode.openNode(pPanelDesc->msNodeName)); aPanelNode.setNodeValue("Title", makeAny(pPanelDesc->msTitle)); aPanelNode.setNodeValue("OrderIndex", makeAny(pPanelDesc->mnOrderIndex)); aPanelNode.setNodeValue("ContextList", makeAny( sPanelContextList )); } aPanelRootNode.commit(); } void ResourceManager::ReadPanelList() { const utl::OConfigurationTreeRoot aPanelRootNode( comphelper::getProcessComponentContext(), OUString("org.openoffice.Office.UI.Sidebar/Content/PanelList"), false); if (!aPanelRootNode.isValid()) return; const Sequence aPanelNodeNames (aPanelRootNode.getNodeNames()); const sal_Int32 nCount (aPanelNodeNames.getLength()); maPanels.resize(nCount); sal_Int32 nWriteIndex (0); for (sal_Int32 nReadIndex(0); nReadIndex aValues; sal_Int32 nCount; if (aValue >>= aValues) nCount = aValues.getLength(); else nCount = 0; for (sal_Int32 nIndex=0; nIndex 0 ? (sMenuCommandOverride == "none" ? OUString() : sMenuCommandOverride) : rsDefaultMenuCommand); // Setup a list of application enums. Note that the // application name may result in more than one value (eg // DrawImpress will result in two enums, one for Draw and one // for Impress). std::vector aApplications; EnumContext::Application eApplication (EnumContext::GetApplicationEnum(sApplicationName)); 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 == "Writer") aApplications.push_back(EnumContext::Application_Writer); else if (sApplicationName == "Calc") aApplications.push_back(EnumContext::Application_Calc); else if (sApplicationName == "Draw") aApplications.push_back(EnumContext::Application_Draw); else if (sApplicationName == "Impress") aApplications.push_back(EnumContext::Application_Impress); else if (sApplicationName == "Chart") aApplications.push_back(EnumContext::Application_Chart); else if (sApplicationName == "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. aApplications.push_back(EnumContext::Application_Draw); aApplications.push_back(EnumContext::Application_Impress); } else if (sApplicationName == "WriterVariants") { // Another special case for all Writer variants. aApplications.push_back(EnumContext::Application_Writer); aApplications.push_back(EnumContext::Application_WriterGlobal); aApplications.push_back(EnumContext::Application_WriterWeb); aApplications.push_back(EnumContext::Application_WriterXML); aApplications.push_back(EnumContext::Application_WriterForm); aApplications.push_back(EnumContext::Application_WriterReport); } else { SAL_WARN("sfx.sidebar", "application name " << sApplicationName << " not recognized"); continue; } } else { // No conversion of the application name necessary. aApplications.push_back(eApplication); } // Setup the actual context enum. const EnumContext::Context eContext (EnumContext::GetContextEnum(sContextName)); if (eContext == EnumContext::Context_Unknown) { SAL_WARN("sfx.sidebar", "context name " << sContextName << " not recognized"); continue; } // Setup the flag that controls whether a deck/pane is // initially visible/expanded. bool bIsInitiallyVisible; if (sInitialState == "visible") bIsInitiallyVisible = true; else if (sInitialState == "hidden") bIsInitiallyVisible = false; else { OSL_FAIL("unrecognized state"); continue; } // Add context descriptors. std::vector::const_iterator iApplication; for (iApplication = aApplications.begin(); iApplication != aApplications.end(); ++iApplication) { if (*iApplication != EnumContext::Application_None) { rContextList.AddContextDescription( Context( EnumContext::GetApplicationName(*iApplication), EnumContext::GetContextName(eContext)), bIsInitiallyVisible, sMenuCommand); } } } } void ResourceManager::ReadLegacyAddons (const Reference& rxController) { // Get module name for given frame. OUString sModuleName (Tools::GetModuleName(rxController)); 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 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); nReadIndexmsId.equals(rsPanelId)) { ContextList::Entry* pEntry(iPanel->maContextList.GetMatch(rContext)); if (pEntry != nullptr) pEntry->mbIsInitiallyVisible = bExpansionState; } } } utl::OConfigurationTreeRoot ResourceManager::GetLegacyAddonRootNode (const OUString& rsModuleName) { try { const Reference xContext(comphelper::getProcessComponentContext()); const Reference xModuleAccess = frame::ModuleManager::create(xContext); const comphelper::NamedValueCollection aModuleProperties(xModuleAccess->getByName(rsModuleName)); const OUString sWindowStateRef(aModuleProperties.getOrDefault( "ooSetupFactoryWindowStateConfigRef", OUString())); OUStringBuffer aPathComposer; aPathComposer.append("org.openoffice.Office.UI."); aPathComposer.append(sWindowStateRef); aPathComposer.append("/UIElements/States"); return utl::OConfigurationTreeRoot(xContext, aPathComposer.makeStringAndClear(), false); } catch (const Exception&) { DBG_UNHANDLED_EXCEPTION(); } return utl::OConfigurationTreeRoot(); } void ResourceManager::GetToolPanelNodeNames ( std::vector& rMatchingNames, const utl::OConfigurationTreeRoot& aRoot) { Sequence aChildNodeNames (aRoot.getNodeNames()); const sal_Int32 nCount (aChildNodeNames.getLength()); for (sal_Int32 nIndex(0); nIndex& rxController) { // Check if any panel that matches the current context can be // displayed. PanelContextDescriptorContainer aPanelContextDescriptors; GetMatchingPanels(aPanelContextDescriptors, rContext, rsDeckId, rxController); PanelContextDescriptorContainer::const_iterator iPanel; for (iPanel = aPanelContextDescriptors.begin(); iPanel != aPanelContextDescriptors.end(); ++iPanel) { if (iPanel->mbShowForReadOnlyDocuments) return true; } return false; } void ResourceManager::UpdateModel(css::uno::Reference xModel) { for (DeckContainer::iterator itr = maDecks.begin(); itr != maDecks.end(); ++itr) { if (!itr->mpDeck) continue; const SharedPanelContainer& rContainer = itr->mpDeck->GetPanels(); for (SharedPanelContainer::const_iterator it = rContainer.begin(); it != rContainer.end(); ++it) { css::uno::Reference xPanel((*it)->GetPanelComponent(), css::uno::UNO_QUERY); xPanel->updateModel(xModel); } } } void ResourceManager::disposeDecks() { for (DeckContainer::iterator itr = maDecks.begin(); itr != maDecks.end(); ++itr) itr->mpDeck.disposeAndClear(); } } } // end of namespace sfx2::sidebar /* vim:set shiftwidth=4 softtabstop=4 expandtab: */