1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 #include "precompiled_sfx2.hxx" 23 24 #include "ResourceManager.hxx" 25 #include <unotools/confignode.hxx> 26 #include <comphelper/componentcontext.hxx> 27 #include <comphelper/namedvaluecollection.hxx> 28 #include <tools/diagnose_ex.h> 29 30 31 #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString))) 32 33 using ::rtl::OUString; 34 using namespace css; 35 using namespace cssu; 36 37 namespace sfx2 { namespace sidebar { 38 39 #define gsPrivateResourceToolpanelPrefix "private:resource/toolpanel/" 40 41 42 43 class ResourceManager::Deleter 44 { 45 public: 46 void operator() (ResourceManager* pObject) 47 { 48 delete pObject; 49 } 50 }; 51 52 53 ResourceManager& ResourceManager::Instance (void) 54 { 55 static ResourceManager maInstance; 56 return maInstance; 57 } 58 59 60 61 62 ResourceManager::ResourceManager (void) 63 : maDecks(), 64 maPanels(), 65 maProcessedApplications() 66 { 67 ReadDeckList(); 68 ReadPanelList(); 69 } 70 71 72 73 74 ResourceManager::~ResourceManager (void) 75 { 76 maPanels.clear(); 77 maDecks.clear(); 78 } 79 80 81 82 83 const DeckDescriptor* ResourceManager::GetBestMatchingDeck ( 84 const Context& rContext, 85 const Reference<frame::XFrame>& rxFrame) 86 { 87 ReadLegacyAddons(rxFrame); 88 89 sal_Int32 nBestMatch (Context::NoMatch); 90 const DeckContainer::const_iterator iEnd (maDecks.end()); 91 DeckContainer::const_iterator iBestDeck (iEnd); 92 93 for (DeckContainer::const_iterator iDeck(maDecks.begin()); 94 iDeck!=iEnd; 95 ++iDeck) 96 { 97 const sal_Int32 nMatch (rContext.EvaluateMatch(iDeck->maContexts)); 98 if (nMatch < nBestMatch) 99 { 100 // Found a better matching decks. 101 nBestMatch = nMatch; 102 iBestDeck = iDeck; 103 if (nBestMatch == Context::OptimalMatch) 104 { 105 // We will not find a better match. 106 break; 107 } 108 } 109 } 110 if (iBestDeck != iEnd) 111 return &*iBestDeck; 112 else 113 return NULL; 114 } 115 116 117 118 119 const ResourceManager::DeckContainer& ResourceManager::GetMatchingDecks ( 120 DeckContainer& rDeckDescriptors, 121 const Context& rContext, 122 const Reference<frame::XFrame>& rxFrame) 123 { 124 ReadLegacyAddons(rxFrame); 125 126 for (DeckContainer::const_iterator 127 iDeck(maDecks.begin()), 128 iEnd (maDecks.end()); 129 iDeck!=iEnd; 130 ++iDeck) 131 { 132 if (rContext.EvaluateMatch(iDeck->maContexts) != Context::NoMatch) 133 rDeckDescriptors.push_back(*iDeck); 134 } 135 136 return rDeckDescriptors; 137 } 138 139 140 141 142 const ResourceManager::PanelContainer& ResourceManager::GetMatchingPanels ( 143 PanelContainer& rPanelDescriptors, 144 const Context& rContext, 145 const ::rtl::OUString& rsDeckId, 146 const Reference<frame::XFrame>& rxFrame) 147 { 148 ReadLegacyAddons(rxFrame); 149 150 for (PanelContainer::const_iterator 151 iPanel(maPanels.begin()), 152 iEnd(maPanels.end()); 153 iPanel!=iEnd; 154 ++iPanel) 155 { 156 const PanelDescriptor& rPanelDescriptor (*iPanel); 157 if (rPanelDescriptor.msDeckId.equals(rsDeckId)) 158 if (rContext.EvaluateMatch(rPanelDescriptor.maContexts) != Context::NoMatch) 159 rPanelDescriptors.push_back(*iPanel); 160 } 161 162 return rPanelDescriptors; 163 } 164 165 166 167 168 void ResourceManager::ReadDeckList (void) 169 { 170 const ::comphelper::ComponentContext aContext (::comphelper::getProcessServiceFactory()); 171 const ::utl::OConfigurationTreeRoot aDeckRootNode ( 172 aContext, 173 A2S("org.openoffice.Office.UI.Sidebar/Content/DeckList"), 174 false); 175 if ( ! aDeckRootNode.isValid() ) 176 return; 177 178 const Sequence<OUString> aDeckNodeNames (aDeckRootNode.getNodeNames()); 179 const sal_Int32 nCount (aDeckNodeNames.getLength()); 180 maDecks.resize(nCount); 181 sal_Int32 nWriteIndex(0); 182 for (sal_Int32 nReadIndex(0); nReadIndex<nCount; ++nReadIndex) 183 { 184 const ::utl::OConfigurationNode aDeckNode (aDeckRootNode.openNode(aDeckNodeNames[nReadIndex])); 185 if ( ! aDeckNode.isValid()) 186 continue; 187 188 DeckDescriptor& rDeckDescriptor (maDecks[nWriteIndex++]); 189 190 rDeckDescriptor.msTitle = ::comphelper::getString(aDeckNode.getNodeValue("Title")); 191 rDeckDescriptor.msId = ::comphelper::getString(aDeckNode.getNodeValue("Id")); 192 rDeckDescriptor.msIconURL = ::comphelper::getString(aDeckNode.getNodeValue("IconURL")); 193 rDeckDescriptor.msHighContrastIconURL = ::comphelper::getString(aDeckNode.getNodeValue("HighContrastIconURL")); 194 rDeckDescriptor.msHelpURL = ::comphelper::getString(aDeckNode.getNodeValue("HelpURL")); 195 rDeckDescriptor.msHelpText = rDeckDescriptor.msTitle; 196 ReadContextList(aDeckNode.openNode("ContextList"), rDeckDescriptor.maContexts); 197 } 198 199 // When there where invalid nodes then we have to adapt the size 200 // of the deck vector. 201 if (nWriteIndex<nCount) 202 maDecks.resize(nWriteIndex); 203 } 204 205 206 207 208 void ResourceManager::ReadPanelList (void) 209 { 210 const ::comphelper::ComponentContext aContext (::comphelper::getProcessServiceFactory()); 211 const ::utl::OConfigurationTreeRoot aPanelRootNode ( 212 aContext, 213 A2S("org.openoffice.Office.UI.Sidebar/Content/PanelList"), 214 false); 215 if ( ! aPanelRootNode.isValid() ) 216 return; 217 218 const Sequence<OUString> aPanelNodeNames (aPanelRootNode.getNodeNames()); 219 const sal_Int32 nCount (aPanelNodeNames.getLength()); 220 maPanels.resize(nCount); 221 sal_Int32 nWriteIndex (0); 222 for (sal_Int32 nReadIndex(0); nReadIndex<nCount; ++nReadIndex) 223 { 224 const ::utl::OConfigurationNode aPanelNode (aPanelRootNode.openNode(aPanelNodeNames[nReadIndex])); 225 if ( ! aPanelNode.isValid()) 226 continue; 227 228 PanelDescriptor& rPanelDescriptor (maPanels[nWriteIndex++]); 229 230 rPanelDescriptor.msTitle = ::comphelper::getString( 231 aPanelNode.getNodeValue("Title")); 232 rPanelDescriptor.mbIsTitleBarOptional = ::comphelper::getBOOL( 233 aPanelNode.getNodeValue("TitleBarIsOptional")); 234 rPanelDescriptor.msId = ::comphelper::getString( 235 aPanelNode.getNodeValue("Id")); 236 rPanelDescriptor.msDeckId = ::comphelper::getString( 237 aPanelNode.getNodeValue("DeckId")); 238 rPanelDescriptor.msHelpURL = ::comphelper::getString( 239 aPanelNode.getNodeValue("HelpURL")); 240 rPanelDescriptor.msLayout = ::comphelper::getString( 241 aPanelNode.getNodeValue("Layout")); 242 rPanelDescriptor.msImplementationURL = ::comphelper::getString( 243 aPanelNode.getNodeValue("ImplementationURL")); 244 ReadContextList(aPanelNode.openNode("ContextList"), rPanelDescriptor.maContexts); 245 } 246 247 // When there where invalid nodes then we have to adapt the size 248 // of the deck vector. 249 if (nWriteIndex<nCount) 250 maPanels.resize(nWriteIndex); 251 } 252 253 254 255 256 void ResourceManager::ReadContextList ( 257 const ::utl::OConfigurationNode& rNode, 258 ::std::vector<Context>& rContextContainer) const 259 { 260 const Sequence<OUString> aChildNodeNames (rNode.getNodeNames()); 261 const sal_Int32 nCount (aChildNodeNames.getLength()); 262 rContextContainer.resize(nCount); 263 for (sal_Int32 nIndex(0); nIndex<nCount; ++nIndex) 264 { 265 const ::utl::OConfigurationNode aChildNode (rNode.openNode(aChildNodeNames[nIndex])); 266 Context& rContext (rContextContainer[nIndex]); 267 268 rContext.msApplication = ::comphelper::getString(aChildNode.getNodeValue("Application")); 269 rContext.msContext = ::comphelper::getString(aChildNode.getNodeValue("ApplicationContext")); 270 } 271 } 272 273 274 275 276 void ResourceManager::ReadLegacyAddons (const Reference<frame::XFrame>& rxFrame) 277 { 278 // Get module name for given frame. 279 ::rtl::OUString sModuleName (GetModuleName(rxFrame)); 280 if (sModuleName.getLength() == 0) 281 return; 282 if (maProcessedApplications.find(sModuleName) != maProcessedApplications.end()) 283 { 284 // Addons for this application have already been read. 285 // There is nothing more to do. 286 return; 287 } 288 289 // Mark module as processed. Even when there is an error that 290 // prevents the configuration data from being read, this error 291 // will not be triggered a second time. 292 maProcessedApplications.insert(sModuleName); 293 294 // Get access to the configuration root node for the application. 295 ::utl::OConfigurationTreeRoot aLegacyRootNode (GetLegacyAddonRootNode(sModuleName)); 296 if ( ! aLegacyRootNode.isValid()) 297 return; 298 299 // Process child nodes. 300 ::std::vector<OUString> aMatchingNodeNames; 301 GetToolPanelNodeNames(aMatchingNodeNames, aLegacyRootNode); 302 const sal_Int32 nCount (aMatchingNodeNames.size()); 303 sal_Int32 nDeckWriteIndex (maDecks.size()); 304 sal_Int32 nPanelWriteIndex (maPanels.size()); 305 maDecks.resize(maDecks.size() + nCount); 306 maPanels.resize(maPanels.size() + nCount); 307 for (sal_Int32 nReadIndex(0); nReadIndex<nCount; ++nReadIndex) 308 { 309 const OUString& rsNodeName (aMatchingNodeNames[nReadIndex]); 310 const ::utl::OConfigurationNode aChildNode (aLegacyRootNode.openNode(rsNodeName)); 311 if ( ! aChildNode.isValid()) 312 continue; 313 314 DeckDescriptor& rDeckDescriptor (maDecks[nDeckWriteIndex++]); 315 rDeckDescriptor.msTitle = ::comphelper::getString(aChildNode.getNodeValue("UIName")); 316 rDeckDescriptor.msId = rsNodeName; 317 rDeckDescriptor.msIconURL = ::comphelper::getString(aChildNode.getNodeValue("ImageURL")); 318 rDeckDescriptor.msHighContrastIconURL = rDeckDescriptor.msIconURL; 319 rDeckDescriptor.msHelpURL = ::comphelper::getString(aChildNode.getNodeValue("HelpURL")); 320 rDeckDescriptor.msHelpText = rDeckDescriptor.msTitle; 321 rDeckDescriptor.maContexts.resize(1); 322 rDeckDescriptor.maContexts.front() = Context(A2S("any"), A2S("any")); 323 324 PanelDescriptor& rPanelDescriptor (maPanels[nPanelWriteIndex++]); 325 rPanelDescriptor.msTitle = ::comphelper::getString(aChildNode.getNodeValue("UIName")); 326 rPanelDescriptor.mbIsTitleBarOptional = false; 327 rPanelDescriptor.msId = rsNodeName; 328 rPanelDescriptor.msDeckId = rsNodeName; 329 rPanelDescriptor.msHelpURL = ::comphelper::getString(aChildNode.getNodeValue("HelpURL")); 330 rPanelDescriptor.maContexts.resize(1); 331 rPanelDescriptor.maContexts.front() = Context(A2S("any"), A2S("any")); 332 rPanelDescriptor.msLayout = A2S("full"); 333 rPanelDescriptor.msImplementationURL = rsNodeName; 334 } 335 336 // When there where invalid nodes then we have to adapt the size 337 // of the deck and panel vectors. 338 if (nDeckWriteIndex < maDecks.size()) 339 maDecks.resize(nDeckWriteIndex); 340 if (nPanelWriteIndex < maPanels.size()) 341 maPanels.resize(nPanelWriteIndex); 342 } 343 344 345 346 347 ::rtl::OUString ResourceManager::GetModuleName ( 348 const cssu::Reference<css::frame::XFrame>& rxFrame) const 349 { 350 try 351 { 352 const ::comphelper::ComponentContext aContext (::comphelper::getProcessServiceFactory()); 353 const Reference<frame::XModuleManager> xModuleManager ( 354 aContext.createComponent("com.sun.star.frame.ModuleManager" ), 355 UNO_QUERY_THROW ); 356 return xModuleManager->identify(rxFrame); 357 } 358 catch (const Exception&) 359 { 360 DBG_UNHANDLED_EXCEPTION(); 361 } 362 return OUString(); 363 } 364 365 366 367 368 ::utl::OConfigurationTreeRoot ResourceManager::GetLegacyAddonRootNode ( 369 const ::rtl::OUString& rsModuleName) const 370 { 371 try 372 { 373 const ::comphelper::ComponentContext aContext (::comphelper::getProcessServiceFactory()); 374 const Reference<container::XNameAccess> xModuleAccess ( 375 aContext.createComponent("com.sun.star.frame.ModuleManager"), 376 UNO_QUERY_THROW); 377 const ::comphelper::NamedValueCollection aModuleProperties (xModuleAccess->getByName(rsModuleName)); 378 const ::rtl::OUString sWindowStateRef (aModuleProperties.getOrDefault( 379 "ooSetupFactoryWindowStateConfigRef", 380 ::rtl::OUString())); 381 382 ::rtl::OUStringBuffer aPathComposer; 383 aPathComposer.appendAscii("org.openoffice.Office.UI."); 384 aPathComposer.append(sWindowStateRef); 385 aPathComposer.appendAscii("/UIElements/States"); 386 387 return ::utl::OConfigurationTreeRoot(aContext, aPathComposer.makeStringAndClear(), false); 388 } 389 catch( const Exception& ) 390 { 391 DBG_UNHANDLED_EXCEPTION(); 392 } 393 394 return ::utl::OConfigurationTreeRoot(); 395 } 396 397 398 399 400 void ResourceManager::GetToolPanelNodeNames ( 401 ::std::vector<OUString>& rMatchingNames, 402 const ::utl::OConfigurationTreeRoot aRoot) const 403 { 404 Sequence<OUString> aChildNodeNames (aRoot.getNodeNames()); 405 const sal_Int32 nCount (aChildNodeNames.getLength()); 406 for (sal_Int32 nIndex(0); nIndex<nCount; ++nIndex) 407 { 408 if (aChildNodeNames[nIndex].matchAsciiL( 409 RTL_CONSTASCII_STRINGPARAM( "private:resource/toolpanel/"))) 410 rMatchingNames.push_back(aChildNodeNames[nIndex]); 411 } 412 } 413 414 415 416 } } // end of namespace sfx2::sidebar 417