1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sidebar/DeckDescriptor.hxx>
21 #include <sidebar/PanelDescriptor.hxx>
22 #include <sfx2/sidebar/ResourceManager.hxx>
23 #include <sidebar/Tools.hxx>
25 #include <officecfg/Office/Common.hxx>
26 #include <officecfg/Office/UI/Sidebar.hxx>
27 #include <unotools/confignode.hxx>
28 #include <comphelper/lok.hxx>
29 #include <comphelper/processfactory.hxx>
30 #include <comphelper/namedvaluecollection.hxx>
31 #include <comphelper/sequence.hxx>
32 #include <comphelper/types.hxx>
34 #include <comphelper/diagnose_ex.hxx>
35 #include <sal/log.hxx>
36 #include <vcl/EnumContext.hxx>
37 #include <o3tl/string_view.hxx>
39 #include <com/sun/star/frame/ModuleManager.hpp>
40 #include <com/sun/star/ui/XSidebarPanel.hpp>
41 #include <com/sun/star/ui/XUpdateModel.hpp>
46 using namespace css::uno
;
48 namespace sfx2::sidebar
{
53 OUString
getString(utl::OConfigurationNode
const & aNode
, const OUString
& rNodeName
)
55 return comphelper::getString(aNode
.getNodeValue(rNodeName
));
57 sal_Int32
getInt32(utl::OConfigurationNode
const & aNode
, const OUString
& rNodeName
)
59 return comphelper::getINT32(aNode
.getNodeValue(rNodeName
));
61 bool getBool(utl::OConfigurationNode
const & aNode
, const OUString
& rNodeName
)
63 return comphelper::getBOOL(aNode
.getNodeValue(rNodeName
));
66 css::uno::Sequence
<OUString
> BuildContextList (const ContextList
& rContextList
)
68 const ::std::vector
<ContextList::Entry
>& entries
= rContextList
.GetEntries();
70 css::uno::Sequence
<OUString
> result(entries
.size());
71 auto resultRange
= asNonConstRange(result
);
74 for (auto const& entry
: entries
)
76 OUString appName
= entry
.maContext
.msApplication
;
77 OUString contextName
= entry
.maContext
.msContext
;
78 OUString menuCommand
= entry
.msMenuCommand
;
81 if (entry
.mbIsInitiallyVisible
)
82 visibility
= "visible";
84 visibility
= "hidden";
86 OUString element
= appName
+ ", " + contextName
+", " + visibility
;
88 if (!menuCommand
.isEmpty())
89 element
+= ", "+menuCommand
;
91 resultRange
[i
] = element
;
100 } //end anonymous namespace
102 ResourceManager::ResourceManager()
109 ResourceManager::~ResourceManager()
113 void ResourceManager::InitDeckContext(const Context
& rContext
)
115 for (auto const& deck
: maDecks
)
117 const ContextList::Entry
* pMatchingEntry
= deck
->maContextList
.GetMatch(rContext
);
121 bIsEnabled
= pMatchingEntry
->mbIsInitiallyVisible
;
125 deck
->mbIsEnabled
= bIsEnabled
;
129 std::shared_ptr
<DeckDescriptor
> ResourceManager::ImplGetDeckDescriptor(std::u16string_view rsDeckId
) const
131 for (auto const& deck
: maDecks
)
133 if (deck
->mbHiddenInViewerMode
&& officecfg::Office::Common::Misc::ViewerAppMode::get())
135 if (deck
->mbExperimental
&& !officecfg::Office::Common::Misc::ExperimentalMode::get())
137 if (deck
->msId
== rsDeckId
)
143 std::shared_ptr
<DeckDescriptor
> ResourceManager::GetDeckDescriptor(std::u16string_view rsDeckId
) const
145 return ImplGetDeckDescriptor( rsDeckId
);
148 std::shared_ptr
<PanelDescriptor
> ResourceManager::ImplGetPanelDescriptor(std::u16string_view rsPanelId
) const
150 for (auto const& panel
: maPanels
)
152 if (panel
->msId
== rsPanelId
)
158 std::shared_ptr
<PanelDescriptor
> ResourceManager::GetPanelDescriptor(std::u16string_view rsPanelId
) const
160 return ImplGetPanelDescriptor( rsPanelId
);
163 const ResourceManager::DeckContextDescriptorContainer
& ResourceManager::GetMatchingDecks (
164 DeckContextDescriptorContainer
& rDecks
,
165 const Context
& rContext
,
166 const bool bIsDocumentReadOnly
,
167 const Reference
<frame::XController
>& rxController
)
169 ReadLegacyAddons(rxController
);
171 std::multimap
<sal_Int32
,DeckContextDescriptor
> aOrderedIds
;
172 for (auto const& deck
: maDecks
)
174 if (deck
->mbHiddenInViewerMode
&& officecfg::Office::Common::Misc::ViewerAppMode::get())
176 if (deck
->mbExperimental
&& !officecfg::Office::Common::Misc::ExperimentalMode::get())
179 const DeckDescriptor
& rDeckDescriptor (*deck
);
180 if (rDeckDescriptor
.maContextList
.GetMatch(rContext
) == nullptr)
183 DeckContextDescriptor aDeckContextDescriptor
;
184 aDeckContextDescriptor
.msId
= rDeckDescriptor
.msId
;
186 aDeckContextDescriptor
.mbIsEnabled
= (! bIsDocumentReadOnly
|| IsDeckEnabled(rDeckDescriptor
.msId
, rContext
, rxController
) )
187 && rDeckDescriptor
.mbIsEnabled
;
190 aOrderedIds
.emplace(rDeckDescriptor
.mnOrderIndex
, aDeckContextDescriptor
);
193 for (auto const& orderId
: aOrderedIds
)
195 rDecks
.push_back(orderId
.second
);
201 const ResourceManager::PanelContextDescriptorContainer
& ResourceManager::GetMatchingPanels (
202 PanelContextDescriptorContainer
& rPanelIds
,
203 const Context
& rContext
,
204 std::u16string_view sDeckId
,
205 const Reference
<frame::XController
>& rxController
)
207 ReadLegacyAddons(rxController
);
209 std::multimap
<sal_Int32
, PanelContextDescriptor
> aOrderedIds
;
210 for (auto const& panel
: maPanels
)
212 const PanelDescriptor
& rPanelDescriptor (*panel
);
213 if (rPanelDescriptor
.mbExperimental
&& !officecfg::Office::Common::Misc::ExperimentalMode::get())
215 if ( rPanelDescriptor
.msDeckId
!= sDeckId
)
218 const ContextList::Entry
* pEntry
= rPanelDescriptor
.maContextList
.GetMatch(rContext
);
219 if (pEntry
== nullptr)
222 PanelContextDescriptor aPanelContextDescriptor
;
223 aPanelContextDescriptor
.msId
= rPanelDescriptor
.msId
;
224 aPanelContextDescriptor
.msMenuCommand
= pEntry
->msMenuCommand
;
225 aPanelContextDescriptor
.mbIsInitiallyVisible
= pEntry
->mbIsInitiallyVisible
;
226 aPanelContextDescriptor
.mbShowForReadOnlyDocuments
= rPanelDescriptor
.mbShowForReadOnlyDocuments
;
227 aOrderedIds
.emplace(rPanelDescriptor
.mnOrderIndex
, aPanelContextDescriptor
);
230 for (auto const& orderId
: aOrderedIds
)
232 rPanelIds
.push_back(orderId
.second
);
238 const OUString
& ResourceManager::GetLastActiveDeck( const Context
& rContext
)
240 if( maLastActiveDecks
.find( rContext
.msApplication
) == maLastActiveDecks
.end())
241 return maLastActiveDecks
[u
"any"_ustr
];
243 return maLastActiveDecks
[rContext
.msApplication
];
246 void ResourceManager::SetLastActiveDeck( const Context
& rContext
, const OUString
&rsDeckId
)
248 maLastActiveDecks
[rContext
.msApplication
] = rsDeckId
;
251 void ResourceManager::ReadDeckList()
253 const utl::OConfigurationTreeRoot
aDeckRootNode(
254 comphelper::getProcessComponentContext(),
255 u
"org.openoffice.Office.UI.Sidebar/Content/DeckList"_ustr
,
257 if (!aDeckRootNode
.isValid())
260 const Sequence
<OUString
> aDeckNodeNames (aDeckRootNode
.getNodeNames());
262 for (const OUString
& aDeckName
: aDeckNodeNames
)
264 if (comphelper::LibreOfficeKit::isActive())
266 // Hide these decks in LOK as they aren't fully functional.
267 if (aDeckName
== "GalleryDeck" || aDeckName
== "StyleListDeck")
271 const utl::OConfigurationNode
aDeckNode(aDeckRootNode
.openNode(aDeckName
));
272 if (!aDeckNode
.isValid())
275 maDecks
.push_back(std::make_shared
<DeckDescriptor
>());
276 DeckDescriptor
& rDeckDescriptor (*maDecks
.back());
278 rDeckDescriptor
.msTitle
= getString(aDeckNode
, u
"Title"_ustr
);
279 rDeckDescriptor
.msId
= getString(aDeckNode
, u
"Id"_ustr
);
280 rDeckDescriptor
.msIconURL
= getString(aDeckNode
, u
"IconURL"_ustr
);
281 rDeckDescriptor
.msHighContrastIconURL
= getString(aDeckNode
, u
"HighContrastIconURL"_ustr
);
282 rDeckDescriptor
.msTitleBarIconURL
= getString(aDeckNode
, u
"TitleBarIconURL"_ustr
);
283 rDeckDescriptor
.msHighContrastTitleBarIconURL
= getString(aDeckNode
, u
"HighContrastTitleBarIconURL"_ustr
);
284 rDeckDescriptor
.msHelpText
= rDeckDescriptor
.msTitle
;
285 rDeckDescriptor
.msHelpId
= "SIDEBAR_" + rDeckDescriptor
.msId
.toAsciiUpperCase();
286 rDeckDescriptor
.mnOrderIndex
= getInt32(aDeckNode
, u
"OrderIndex"_ustr
);
287 rDeckDescriptor
.mbExperimental
= getBool(aDeckNode
, u
"IsExperimental"_ustr
);
288 rDeckDescriptor
.mbHiddenInViewerMode
= getBool(aDeckNode
, u
"HiddenInViewer"_ustr
);
290 rDeckDescriptor
.msNodeName
= aDeckName
;
294 rDeckDescriptor
.maContextList
,
300 void ResourceManager::SaveDecksSettings(const Context
& rContext
)
302 for (auto const& deck
: maDecks
)
304 const ContextList::Entry
* pMatchingEntry
= deck
->maContextList
.GetMatch(rContext
);
307 std::shared_ptr
<DeckDescriptor
> xDeckDesc
= GetDeckDescriptor(deck
->msId
);
309 SaveDeckSettings(xDeckDesc
.get());
315 void ResourceManager::SaveDeckSettings(const DeckDescriptor
* pDeckDesc
)
317 const utl::OConfigurationTreeRoot
aDeckRootNode(
318 comphelper::getProcessComponentContext(),
319 u
"org.openoffice.Office.UI.Sidebar/Content/DeckList"_ustr
,
321 if (!aDeckRootNode
.isValid())
324 // save deck settings
326 ::uno::Sequence
< OUString
> sContextList
= BuildContextList(pDeckDesc
->maContextList
);
328 utl::OConfigurationNode
aDeckNode (aDeckRootNode
.openNode(pDeckDesc
->msNodeName
));
330 css::uno::Any
aTitle(Any(pDeckDesc
->msTitle
));
331 css::uno::Any
aOrder(Any(pDeckDesc
->mnOrderIndex
));
332 css::uno::Any
aContextList(sContextList
);
334 bool bChanged
= false;
335 if (aTitle
!= aDeckNode
.getNodeValue(u
"Title"_ustr
))
337 aDeckNode
.setNodeValue(u
"Title"_ustr
, aTitle
);
340 if (aOrder
!= aDeckNode
.getNodeValue(u
"OrderIndex"_ustr
))
342 aDeckNode
.setNodeValue(u
"OrderIndex"_ustr
, aOrder
);
345 if (aContextList
!= aDeckNode
.getNodeValue(u
"ContextList"_ustr
))
347 aDeckNode
.setNodeValue(u
"ContextList"_ustr
, aContextList
);
352 aDeckRootNode
.commit();
354 // save panel settings
356 const utl::OConfigurationTreeRoot
aPanelRootNode(
357 comphelper::getProcessComponentContext(),
358 u
"org.openoffice.Office.UI.Sidebar/Content/PanelList"_ustr
,
361 if (!aPanelRootNode
.isValid())
364 if (!pDeckDesc
->mpDeck
) // the deck has not been edited
367 SharedPanelContainer rPanels
= pDeckDesc
->mpDeck
->GetPanels();
370 for (auto const& panel
: rPanels
)
372 OUString panelId
= panel
->GetId();
373 std::shared_ptr
<PanelDescriptor
> xPanelDesc
= GetPanelDescriptor(panelId
);
375 ::uno::Sequence
< OUString
> sPanelContextList
= BuildContextList(xPanelDesc
->maContextList
);
377 utl::OConfigurationNode
aPanelNode (aPanelRootNode
.openNode(xPanelDesc
->msNodeName
));
379 aTitle
<<= xPanelDesc
->msTitle
;
380 aOrder
<<= xPanelDesc
->mnOrderIndex
;
381 aContextList
<<= sPanelContextList
;
383 if (aTitle
!= aPanelNode
.getNodeValue(u
"Title"_ustr
))
385 aPanelNode
.setNodeValue(u
"Title"_ustr
, aTitle
);
388 if (aOrder
!= aPanelNode
.getNodeValue(u
"OrderIndex"_ustr
))
390 aPanelNode
.setNodeValue(u
"OrderIndex"_ustr
, aOrder
);
393 if (aContextList
!= aPanelNode
.getNodeValue(u
"ContextList"_ustr
))
395 aPanelNode
.setNodeValue(u
"ContextList"_ustr
, aContextList
);
401 aPanelRootNode
.commit();
404 void ResourceManager::SaveLastActiveDeck(const Context
& rContext
, const OUString
& rActiveDeck
)
406 maLastActiveDecks
[rContext
.msApplication
] = rActiveDeck
;
408 std::set
<OUString
> aLastActiveDecks
;
409 for ( auto const & rEntry
: maLastActiveDecks
)
410 aLastActiveDecks
.insert( rEntry
.first
+ "," + rEntry
.second
);
412 std::shared_ptr
<comphelper::ConfigurationChanges
> cfgWriter( comphelper::ConfigurationChanges::create() );
414 officecfg::Office::UI::Sidebar::Content::LastActiveDeck::set(comphelper::containerToSequence(aLastActiveDecks
), cfgWriter
);
419 void ResourceManager::ReadPanelList()
421 const utl::OConfigurationTreeRoot
aPanelRootNode(
422 comphelper::getProcessComponentContext(),
423 u
"org.openoffice.Office.UI.Sidebar/Content/PanelList"_ustr
,
425 if (!aPanelRootNode
.isValid())
428 const Sequence
<OUString
> aPanelNodeNames (aPanelRootNode
.getNodeNames());
430 for (const auto& rPanelNodeName
: aPanelNodeNames
)
432 const utl::OConfigurationNode
aPanelNode (aPanelRootNode
.openNode(rPanelNodeName
));
433 if (!aPanelNode
.isValid())
436 if (comphelper::LibreOfficeKit::isActive())
438 // Hide these panels in LOK as they aren't fully functional.
439 OUString aPanelId
= getString(aPanelNode
, u
"Id"_ustr
);
440 if (aPanelId
== "PageStylesPanel" || aPanelId
== "PageHeaderPanel"
441 || aPanelId
== "PageFooterPanel")
445 maPanels
.push_back(std::make_shared
<PanelDescriptor
>());
446 PanelDescriptor
& rPanelDescriptor(*maPanels
.back());
448 rPanelDescriptor
.msTitle
= getString(aPanelNode
, u
"Title"_ustr
);
449 rPanelDescriptor
.mbIsTitleBarOptional
= getBool(aPanelNode
, u
"TitleBarIsOptional"_ustr
);
450 rPanelDescriptor
.msId
= getString(aPanelNode
, u
"Id"_ustr
);
451 rPanelDescriptor
.msDeckId
= getString(aPanelNode
, u
"DeckId"_ustr
);
452 rPanelDescriptor
.msTitleBarIconURL
= getString(aPanelNode
, u
"TitleBarIconURL"_ustr
);
453 rPanelDescriptor
.msHighContrastTitleBarIconURL
= getString(aPanelNode
, u
"HighContrastTitleBarIconURL"_ustr
);
454 rPanelDescriptor
.msImplementationURL
= getString(aPanelNode
, u
"ImplementationURL"_ustr
);
455 rPanelDescriptor
.mnOrderIndex
= getInt32(aPanelNode
, u
"OrderIndex"_ustr
);
456 rPanelDescriptor
.mbShowForReadOnlyDocuments
= getBool(aPanelNode
, u
"ShowForReadOnlyDocument"_ustr
);
457 rPanelDescriptor
.mbWantsCanvas
= getBool(aPanelNode
, u
"WantsCanvas"_ustr
);
458 rPanelDescriptor
.mbWantsAWT
= getBool(aPanelNode
, u
"WantsAWT"_ustr
);
459 rPanelDescriptor
.mbExperimental
= getBool(aPanelNode
, u
"IsExperimental"_ustr
);
460 const OUString
sDefaultMenuCommand(getString(aPanelNode
, u
"DefaultMenuCommand"_ustr
));
462 rPanelDescriptor
.msNodeName
= rPanelNodeName
;
464 ReadContextList(aPanelNode
, rPanelDescriptor
.maContextList
, sDefaultMenuCommand
);
468 void ResourceManager::ReadLastActive()
470 const Sequence
<OUString
> aLastActive (officecfg::Office::UI::Sidebar::Content::LastActiveDeck::get());
472 for (const auto& rDeckInfo
: aLastActive
)
474 sal_Int32 nCharIdx
= rDeckInfo
.lastIndexOf(',');
475 if ( nCharIdx
<= 0 || (nCharIdx
== rDeckInfo
.getLength() - 1) )
477 SAL_WARN("sfx.sidebar", "Expecting 2 values separated by comma");
481 const OUString sApplicationName
= rDeckInfo
.copy( 0, nCharIdx
);
482 vcl::EnumContext::Application
eApplication (vcl::EnumContext::GetApplicationEnum(sApplicationName
));
483 const OUString sLastUsed
= rDeckInfo
.copy( nCharIdx
+ 1 );
485 // guard against garbage in place of application
486 if (eApplication
!= vcl::EnumContext::Application::NONE
)
487 maLastActiveDecks
.insert( std::make_pair(sApplicationName
, sLastUsed
) );
490 // Set up a default for Math - will do nothing if already set
491 maLastActiveDecks
.emplace(
492 vcl::EnumContext::GetApplicationName(vcl::EnumContext::Application::Formula
),
496 void ResourceManager::ReadContextList (
497 const utl::OConfigurationNode
& rParentNode
,
498 ContextList
& rContextList
,
499 const OUString
& rsDefaultMenuCommand
)
501 const Any aValue
= rParentNode
.getNodeValue(u
"ContextList"_ustr
);
502 Sequence
<OUString
> aValues
;
503 if (!(aValue
>>= aValues
))
506 for (const OUString
& sValue
: aValues
)
508 sal_Int32
nCharacterIndex (0);
509 const OUString
sApplicationName (o3tl::trim(o3tl::getToken(sValue
, 0, ',', nCharacterIndex
)));
510 if (nCharacterIndex
< 0)
512 if (sApplicationName
.getLength() == 0)
514 // This is a valid case: in the XML file the separator
515 // was used as terminator. Using it in the last line
516 // creates an additional but empty entry.
521 OSL_FAIL("expecting three or four values per ContextList entry, separated by comma");
526 const OUString
sContextName(o3tl::trim(o3tl::getToken(sValue
, 0, ',', nCharacterIndex
)));
527 if (nCharacterIndex
< 0)
529 OSL_FAIL("expecting three or four values per ContextList entry, separated by comma");
533 const std::u16string_view
sInitialState(o3tl::trim(o3tl::getToken(sValue
, 0, ',', nCharacterIndex
)));
535 // The fourth argument is optional.
536 const OUString
sMenuCommandOverride(
539 : OUString(o3tl::trim(o3tl::getToken(sValue
, 0, ',', nCharacterIndex
))));
541 const OUString
sMenuCommand(
542 sMenuCommandOverride
.getLength() > 0
543 ? (sMenuCommandOverride
== "none"
545 : sMenuCommandOverride
)
546 : rsDefaultMenuCommand
);
548 // Setup a list of application enums. Note that the
549 // application name may result in more than one value (eg
550 // DrawImpress will result in two enums, one for Draw and one
552 std::vector
<vcl::EnumContext::Application
> aApplications
;
553 vcl::EnumContext::Application
eApplication (vcl::EnumContext::GetApplicationEnum(sApplicationName
));
555 if (eApplication
== vcl::EnumContext::Application::NONE
556 && sApplicationName
!= vcl::EnumContext::GetApplicationName(vcl::EnumContext::Application::NONE
))
558 // Handle some special names: abbreviations that make
559 // context descriptions more readable.
560 if (sApplicationName
== "Writer")
561 aApplications
.push_back(vcl::EnumContext::Application::Writer
);
562 else if (sApplicationName
== "Calc")
563 aApplications
.push_back(vcl::EnumContext::Application::Calc
);
564 else if (sApplicationName
== "Draw")
565 aApplications
.push_back(vcl::EnumContext::Application::Draw
);
566 else if (sApplicationName
== "Impress")
567 aApplications
.push_back(vcl::EnumContext::Application::Impress
);
568 else if (sApplicationName
== "Chart")
569 aApplications
.push_back(vcl::EnumContext::Application::Chart
);
570 else if (sApplicationName
== "Math")
571 aApplications
.push_back(vcl::EnumContext::Application::Formula
);
572 else if (sApplicationName
== "DrawImpress")
574 // A special case among the special names: it is
575 // common to use the same context descriptions for
576 // both Draw and Impress. This special case helps to
577 // avoid duplication in the .xcu file.
578 aApplications
.push_back(vcl::EnumContext::Application::Draw
);
579 aApplications
.push_back(vcl::EnumContext::Application::Impress
);
581 else if (sApplicationName
== "WriterVariants")
583 // Another special case for all Writer variants.
584 aApplications
.push_back(vcl::EnumContext::Application::Writer
);
585 aApplications
.push_back(vcl::EnumContext::Application::WriterGlobal
);
586 aApplications
.push_back(vcl::EnumContext::Application::WriterWeb
);
587 aApplications
.push_back(vcl::EnumContext::Application::WriterXML
);
588 aApplications
.push_back(vcl::EnumContext::Application::WriterForm
);
589 aApplications
.push_back(vcl::EnumContext::Application::WriterReport
);
593 SAL_WARN("sfx.sidebar", "application name " << sApplicationName
<< " not recognized");
599 // No conversion of the application name necessary.
600 aApplications
.push_back(eApplication
);
603 // Setup the actual context enum.
604 const vcl::EnumContext::Context
eContext (vcl::EnumContext::GetContextEnum(sContextName
));
605 if (eContext
== vcl::EnumContext::Context::Unknown
)
607 SAL_WARN("sfx.sidebar", "context name " << sContextName
<< " not recognized");
611 // Setup the flag that controls whether a deck/pane is
612 // initially visible/expanded.
613 bool bIsInitiallyVisible
;
614 if (sInitialState
== u
"visible")
615 bIsInitiallyVisible
= true;
616 else if (sInitialState
== u
"hidden")
617 bIsInitiallyVisible
= false;
620 OSL_FAIL("unrecognized state");
625 // Add context descriptors.
626 for (auto const& application
: aApplications
)
628 if (application
!= vcl::EnumContext::Application::NONE
)
630 rContextList
.AddContextDescription(
632 vcl::EnumContext::GetApplicationName(application
),
633 vcl::EnumContext::GetContextName(eContext
)),
641 void ResourceManager::ReadLegacyAddons (const Reference
<frame::XController
>& rxController
)
643 // Get module name for given frame.
644 OUString
sModuleName (Tools::GetModuleName(rxController
));
645 if (sModuleName
.getLength() == 0)
647 if (maProcessedApplications
.find(sModuleName
) != maProcessedApplications
.end())
649 // Addons for this application have already been read.
650 // There is nothing more to do.
654 // Mark module as processed. Even when there is an error that
655 // prevents the configuration data from being read, this error
656 // will not be triggered a second time.
657 maProcessedApplications
.insert(sModuleName
);
659 // Get access to the configuration root node for the application.
660 utl::OConfigurationTreeRoot
aLegacyRootNode (GetLegacyAddonRootNode(sModuleName
));
661 if (!aLegacyRootNode
.isValid())
664 // Process child nodes.
665 std::vector
<OUString
> aMatchingNodeNames
;
666 GetToolPanelNodeNames(aMatchingNodeNames
, aLegacyRootNode
);
667 const sal_Int32
nCount (aMatchingNodeNames
.size());
668 for (sal_Int32
nReadIndex(0); nReadIndex
<nCount
; ++nReadIndex
)
670 const OUString
& rsNodeName (aMatchingNodeNames
[nReadIndex
]);
671 const utl::OConfigurationNode
aChildNode (aLegacyRootNode
.openNode(rsNodeName
));
672 if (!aChildNode
.isValid())
675 if ( rsNodeName
== "private:resource/toolpanel/DrawingFramework/CustomAnimations" ||
676 rsNodeName
== "private:resource/toolpanel/DrawingFramework/Layouts" ||
677 rsNodeName
== "private:resource/toolpanel/DrawingFramework/MasterPages" ||
678 rsNodeName
== "private:resource/toolpanel/DrawingFramework/SlideTransitions" ||
679 rsNodeName
== "private:resource/toolpanel/DrawingFramework/TableDesign" )
682 maDecks
.push_back(std::make_shared
<DeckDescriptor
>());
683 DeckDescriptor
& rDeckDescriptor(*maDecks
.back());
684 rDeckDescriptor
.msTitle
= getString(aChildNode
, u
"UIName"_ustr
);
685 rDeckDescriptor
.msId
= rsNodeName
;
686 rDeckDescriptor
.msIconURL
= getString(aChildNode
, u
"ImageURL"_ustr
);
687 rDeckDescriptor
.msHighContrastIconURL
= rDeckDescriptor
.msIconURL
;
688 rDeckDescriptor
.msTitleBarIconURL
.clear();
689 rDeckDescriptor
.msHighContrastTitleBarIconURL
.clear();
690 rDeckDescriptor
.msHelpText
= rDeckDescriptor
.msTitle
;
691 rDeckDescriptor
.mbIsEnabled
= true;
692 rDeckDescriptor
.mnOrderIndex
= 100000 + nReadIndex
;
693 rDeckDescriptor
.maContextList
.AddContextDescription(Context(sModuleName
, u
"any"_ustr
), true, OUString());
695 maPanels
.push_back(std::make_shared
<PanelDescriptor
>());
696 PanelDescriptor
& rPanelDescriptor(*maPanels
.back());
697 rPanelDescriptor
.msTitle
= getString(aChildNode
, u
"UIName"_ustr
);
698 rPanelDescriptor
.mbIsTitleBarOptional
= true;
699 rPanelDescriptor
.msId
= rsNodeName
;
700 rPanelDescriptor
.msDeckId
= rsNodeName
;
701 rPanelDescriptor
.msTitleBarIconURL
.clear();
702 rPanelDescriptor
.msHighContrastTitleBarIconURL
.clear();
703 rPanelDescriptor
.msImplementationURL
= rsNodeName
;
704 rPanelDescriptor
.mnOrderIndex
= 100000 + nReadIndex
;
705 rPanelDescriptor
.mbShowForReadOnlyDocuments
= false;
706 rPanelDescriptor
.mbWantsCanvas
= false;
707 rPanelDescriptor
.mbWantsAWT
= true;
708 rPanelDescriptor
.maContextList
.AddContextDescription(Context(sModuleName
, u
"any"_ustr
), true, OUString());
712 void ResourceManager::StorePanelExpansionState (
713 std::u16string_view rsPanelId
,
714 const bool bExpansionState
,
715 const Context
& rContext
)
717 for (auto const& panel
: maPanels
)
719 if (panel
->msId
== rsPanelId
)
721 ContextList::Entry
* pEntry(panel
->maContextList
.GetMatch(rContext
));
722 if (pEntry
!= nullptr)
723 pEntry
->mbIsInitiallyVisible
= bExpansionState
;
728 utl::OConfigurationTreeRoot
ResourceManager::GetLegacyAddonRootNode (const OUString
& rsModuleName
)
732 const Reference
<XComponentContext
>& xContext(comphelper::getProcessComponentContext());
733 const Reference
<frame::XModuleManager2
> xModuleAccess
= frame::ModuleManager::create(xContext
);
734 const comphelper::NamedValueCollection
aModuleProperties(xModuleAccess
->getByName(rsModuleName
));
735 const OUString
sWindowStateRef(aModuleProperties
.getOrDefault(
736 u
"ooSetupFactoryWindowStateConfigRef"_ustr
,
739 OUString aPathComposer
= "org.openoffice.Office.UI." + sWindowStateRef
+
740 "/UIElements/States";
742 return utl::OConfigurationTreeRoot(xContext
, aPathComposer
, false);
744 catch (const Exception
&)
746 DBG_UNHANDLED_EXCEPTION("sfx.sidebar");
749 return utl::OConfigurationTreeRoot();
752 void ResourceManager::GetToolPanelNodeNames (
753 std::vector
<OUString
>& rMatchingNames
,
754 const utl::OConfigurationTreeRoot
& aRoot
)
756 const Sequence
<OUString
> aChildNodeNames (aRoot
.getNodeNames());
757 std::copy_if(aChildNodeNames
.begin(), aChildNodeNames
.end(), std::back_inserter(rMatchingNames
),
758 [](const OUString
& rChildNodeName
) { return rChildNodeName
.startsWith( "private:resource/toolpanel/" ); });
761 bool ResourceManager::IsDeckEnabled (
762 std::u16string_view rsDeckId
,
763 const Context
& rContext
,
764 const Reference
<frame::XController
>& rxController
)
767 // Check if any panel that matches the current context can be
769 PanelContextDescriptorContainer aPanelContextDescriptors
;
771 GetMatchingPanels(aPanelContextDescriptors
, rContext
, rsDeckId
, rxController
);
773 for (auto const& panelContextDescriptor
: aPanelContextDescriptors
)
775 if (panelContextDescriptor
.mbShowForReadOnlyDocuments
)
781 void ResourceManager::UpdateModel(const css::uno::Reference
<css::frame::XModel
>& xModel
)
783 for (auto const& deck
: maDecks
)
788 const SharedPanelContainer
& rContainer
= deck
->mpDeck
->GetPanels();
790 for (auto const& elem
: rContainer
)
792 css::uno::Reference
<css::ui::XUpdateModel
> xPanel(elem
->GetPanelComponent(), css::uno::UNO_QUERY
);
793 if (xPanel
.is()) // tdf#108814 interface is optional
795 xPanel
->updateModel(xModel
);
801 void ResourceManager::disposeDecks()
803 for (auto const& deck
: maDecks
)
805 deck
->mpDeck
.disposeAndClear();
809 } // end of namespace sfx2::sidebar
811 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */