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/.
10 #include <sfx2/bindings.hxx>
11 #include <sfx2/viewsh.hxx>
12 #include <sfx2/dispatch.hxx>
13 #include <sfx2/notebookbar/SfxNotebookBar.hxx>
14 #include <vcl/syswin.hxx>
15 #include <sfx2/viewfrm.hxx>
16 #include <sfx2/sfxsids.hrc>
17 #include <sfx2/weldutils.hxx>
18 #include <comphelper/processfactory.hxx>
19 #include <comphelper/lok.hxx>
20 #include <com/sun/star/frame/UnknownModuleException.hpp>
21 #include <com/sun/star/frame/XLayoutManager.hpp>
22 #include <officecfg/Office/UI/ToolbarMode.hxx>
23 #include <com/sun/star/frame/XModuleManager.hpp>
24 #include <com/sun/star/frame/ModuleManager.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <unotools/confignode.hxx>
27 #include <comphelper/types.hxx>
28 #include <framework/addonsoptions.hxx>
29 #include <vcl/notebookbar/NotebookBarAddonsMerger.hxx>
31 #include <unordered_map>
32 #include <vcl/WeldedTabbedNotebookbar.hxx>
35 using namespace css::uno
;
36 using namespace css::ui
;
39 constexpr OUString MENUBAR_STR
= u
"private:resource/menubar/menubar"_ustr
;
41 const char MERGE_NOTEBOOKBAR_URL
[] = "URL";
43 bool SfxNotebookBar::m_bLock
= false;
44 bool SfxNotebookBar::m_bHide
= false;
49 /** View specific notebook bar data */
50 struct NotebookBarViewData
52 std::unique_ptr
<WeldedTabbedNotebookbar
> m_pWeldedWrapper
;
53 VclPtr
<NotebookBar
> m_pNotebookBar
;
54 std::unique_ptr
<ToolbarUnoDispatcher
> m_pToolbarUnoDispatcher
;
56 ~NotebookBarViewData()
59 m_pNotebookBar
.disposeAndClear();
63 /** Notebookbar instance manager is a singleton that is used for track the
64 * per-view instances of view specific data contained in NotebookBarViewData
67 class NotebookBarViewManager final
70 // map contains a view data instance for a view (SfxViewShell pointer)
71 std::unordered_map
<const SfxViewShell
*, std::unique_ptr
<NotebookBarViewData
>> m_pViewDataList
;
73 // private constructor to prevent any other instantiation outside of get() method
74 NotebookBarViewManager() = default;
76 // prevent class copying
77 NotebookBarViewManager(const NotebookBarViewManager
&) = delete;
78 NotebookBarViewManager
& operator=(const NotebookBarViewManager
&) = delete;
81 // Singleton get method - creates an instance on first get() call
82 static NotebookBarViewManager
& get()
84 static NotebookBarViewManager gNotebookBarManager
;
85 return gNotebookBarManager
;
88 NotebookBarViewData
& getViewData(const SfxViewShell
* pViewShell
)
90 auto aFound
= m_pViewDataList
.find(pViewShell
);
91 if (aFound
!= m_pViewDataList
.end()) // found
92 return *aFound
->second
;
94 // Create new view data instance
95 NotebookBarViewData
* pViewData
= new NotebookBarViewData
;
96 m_pViewDataList
.emplace(pViewShell
, std::unique_ptr
<NotebookBarViewData
>(pViewData
));
100 void removeViewData(const SfxViewShell
* pViewShell
)
102 m_pViewDataList
.erase(pViewShell
);
106 } // end anonymous namespace
108 static void NotebookbarAddonValues(
109 std::vector
<Image
>& aImageValues
,
110 std::vector
<css::uno::Sequence
<css::uno::Sequence
<css::beans::PropertyValue
>>>&
113 if (comphelper::LibreOfficeKit::isActive())
116 framework::AddonsOptions aAddonsItems
;
118 for (int nIdx
= 0; nIdx
< aAddonsItems
.GetAddonsNotebookBarCount(); nIdx
++)
120 const css::uno::Sequence
<css::uno::Sequence
<css::beans::PropertyValue
>> aExtension
121 = aAddonsItems
.GetAddonsNotebookBarPart(nIdx
);
122 for (const css::uno::Sequence
<css::beans::PropertyValue
>& rExtensionVal
: aExtension
)
125 bool isBigImage
= true;
126 for (const auto& rProp
: rExtensionVal
)
128 if (rProp
.Name
== MERGE_NOTEBOOKBAR_URL
)
131 rProp
.Value
>>= sImage
;
132 aImage
= Image(aAddonsItems
.GetImageFromURL(sImage
, isBigImage
));
135 aImageValues
.push_back(aImage
);
137 aExtensionValues
.push_back(aExtension
);
141 static Reference
<frame::XLayoutManager
> lcl_getLayoutManager( const Reference
<frame::XFrame
>& xFrame
)
143 css::uno::Reference
<css::frame::XLayoutManager
> xLayoutManager
;
147 Reference
<css::beans::XPropertySet
> xPropSet(xFrame
, UNO_QUERY
);
151 Any aValue
= xPropSet
->getPropertyValue("LayoutManager");
152 aValue
>>= xLayoutManager
;
156 return xLayoutManager
;
159 static OUString
lcl_getAppName( vcl::EnumContext::Application eApp
)
163 case vcl::EnumContext::Application::Writer
:
165 case vcl::EnumContext::Application::Calc
:
167 case vcl::EnumContext::Application::Impress
:
169 case vcl::EnumContext::Application::Draw
:
171 case vcl::EnumContext::Application::Formula
:
178 static void lcl_setNotebookbarFileName( vcl::EnumContext::Application eApp
, const OUString
& sFileName
)
180 std::shared_ptr
<comphelper::ConfigurationChanges
> aBatch(
181 comphelper::ConfigurationChanges::create() );
184 case vcl::EnumContext::Application::Writer
:
185 officecfg::Office::UI::ToolbarMode::ActiveWriter::set( sFileName
, aBatch
);
187 case vcl::EnumContext::Application::Calc
:
188 officecfg::Office::UI::ToolbarMode::ActiveCalc::set( sFileName
, aBatch
);
190 case vcl::EnumContext::Application::Impress
:
191 officecfg::Office::UI::ToolbarMode::ActiveImpress::set( sFileName
, aBatch
);
193 case vcl::EnumContext::Application::Draw
:
194 officecfg::Office::UI::ToolbarMode::ActiveDraw::set( sFileName
, aBatch
);
202 static OUString
lcl_getNotebookbarFileName( vcl::EnumContext::Application eApp
)
206 case vcl::EnumContext::Application::Writer
:
207 return officecfg::Office::UI::ToolbarMode::ActiveWriter::get();
208 case vcl::EnumContext::Application::Calc
:
209 return officecfg::Office::UI::ToolbarMode::ActiveCalc::get();
210 case vcl::EnumContext::Application::Impress
:
211 return officecfg::Office::UI::ToolbarMode::ActiveImpress::get();
212 case vcl::EnumContext::Application::Draw
:
213 return officecfg::Office::UI::ToolbarMode::ActiveDraw::get();
221 static utl::OConfigurationTreeRoot
lcl_getCurrentImplConfigRoot()
223 return utl::OConfigurationTreeRoot(::comphelper::getProcessComponentContext(),
224 "org.openoffice.Office.UI.ToolbarMode/",
228 static utl::OConfigurationNode
lcl_getCurrentImplConfigNode(const Reference
<css::frame::XFrame
>& xFrame
,
229 utl::OConfigurationTreeRoot
const & rNotebookbarNode
)
231 if (!rNotebookbarNode
.isValid())
232 return utl::OConfigurationNode();
234 const Reference
<frame::XModuleManager
> xModuleManager
= frame::ModuleManager::create( ::comphelper::getProcessComponentContext() );
236 vcl::EnumContext::Application eApp
= vcl::EnumContext::GetApplicationEnum( xModuleManager
->identify( xFrame
) );
237 OUString aActive
= lcl_getNotebookbarFileName( eApp
);
239 const utl::OConfigurationNode aImplsNode
= rNotebookbarNode
.openNode("Applications/" + lcl_getAppName( eApp
) + "/Modes");
240 const Sequence
<OUString
> aModeNodeNames( aImplsNode
.getNodeNames() );
242 for ( const auto& rModeNodeName
: aModeNodeNames
)
244 const utl::OConfigurationNode
aImplNode( aImplsNode
.openNode( rModeNodeName
) );
245 if ( !aImplNode
.isValid() )
248 OUString aCommandArg
= comphelper::getString( aImplNode
.getNodeValue( "CommandArg" ) );
250 if ( aCommandArg
== aActive
)
256 return utl::OConfigurationNode();
259 void SfxNotebookBar::RemoveCurrentLOKWrapper()
261 const SfxViewShell
* pViewShell
= SfxViewShell::Current();
262 auto& rViewData
= NotebookBarViewManager::get().getViewData(pViewShell
);
264 if (rViewData
.m_pNotebookBar
)
266 // Calls STATIC_LINK SfxNotebookBar -> VclDisposeHdl
267 // which clears the whole InstanceManager
268 rViewData
.m_pNotebookBar
.disposeAndClear();
272 void SfxNotebookBar::CloseMethod(SfxBindings
& rBindings
)
274 SfxFrame
& rFrame
= rBindings
.GetDispatcher_Impl()->GetFrame()->GetFrame();
275 CloseMethod(rFrame
.GetSystemWindow());
278 void SfxNotebookBar::CloseMethod(SystemWindow
* pSysWindow
)
280 if (comphelper::LibreOfficeKit::isActive())
282 RemoveCurrentLOKWrapper();
288 if(pSysWindow
->GetNotebookBar())
289 pSysWindow
->CloseNotebookBar();
290 if (SfxViewFrame
* pViewFrm
= SfxViewFrame::Current())
291 SfxNotebookBar::ShowMenubar(pViewFrm
, true);
295 void SfxNotebookBar::LockNotebookBar()
301 void SfxNotebookBar::UnlockNotebookBar()
307 bool SfxNotebookBar::IsActive(bool bConsiderSingleToolbar
)
312 vcl::EnumContext::Application eApp
= vcl::EnumContext::Application::Any
;
314 if (SfxViewFrame
* pViewFrm
= SfxViewFrame::Current())
316 const Reference
<frame::XFrame
>& xFrame
= pViewFrm
->GetFrame().GetFrameInterface();
320 const Reference
<frame::XModuleManager
> xModuleManager
= frame::ModuleManager::create( ::comphelper::getProcessComponentContext() );
323 eApp
= vcl::EnumContext::GetApplicationEnum(xModuleManager
->identify(xFrame
));
325 catch (css::frame::UnknownModuleException
& e
)
327 SAL_WARN("sfx.appl", "SfxNotebookBar::IsActive(): " + e
.Message
);
334 OUString
appName(lcl_getAppName( eApp
));
336 if (appName
.isEmpty())
340 OUString aPath
= "org.openoffice.Office.UI.ToolbarMode/Applications/" + appName
;
342 const utl::OConfigurationTreeRoot
aAppNode(
343 ::comphelper::getProcessComponentContext(),
346 if ( !aAppNode
.isValid() )
349 OUString aActive
= comphelper::getString( aAppNode
.getNodeValue( "Active" ) );
351 if (bConsiderSingleToolbar
&& aActive
== "Single")
354 if (comphelper::LibreOfficeKit::isActive() && aActive
== "notebookbar_online.ui")
357 const utl::OConfigurationNode aModesNode
= aAppNode
.openNode("Modes");
358 const Sequence
<OUString
> aModeNodeNames( aModesNode
.getNodeNames() );
360 for ( const auto& rModeNodeName
: aModeNodeNames
)
362 const utl::OConfigurationNode
aModeNode( aModesNode
.openNode( rModeNodeName
) );
363 if ( !aModeNode
.isValid() )
366 OUString aCommandArg
= comphelper::getString( aModeNode
.getNodeValue( "CommandArg" ) );
368 if ( aCommandArg
== aActive
)
370 return comphelper::getBOOL( aModeNode
.getNodeValue( "HasNotebookbar" ) );
376 void SfxNotebookBar::ResetActiveToolbarModeToDefault(vcl::EnumContext::Application eApp
)
378 const OUString
appName( lcl_getAppName( eApp
) );
380 if ( appName
.isEmpty() )
383 const OUString aPath
= "org.openoffice.Office.UI.ToolbarMode/Applications/" + appName
;
385 utl::OConfigurationTreeRoot
aAppNode(
386 ::comphelper::getProcessComponentContext(),
389 if ( !aAppNode
.isValid() )
392 aAppNode
.setNodeValue( "Active", Any( OUString( "Default" ) ) );
396 void SfxNotebookBar::ExecMethod(SfxBindings
& rBindings
, const OUString
& rUIName
)
398 // Save active UI file name
399 if (!rUIName
.isEmpty())
401 if (SfxViewFrame
* pViewFrm
= SfxViewFrame::Current())
403 const Reference
<frame::XFrame
>& xFrame
= pViewFrm
->GetFrame().GetFrameInterface();
406 const Reference
<frame::XModuleManager
> xModuleManager
= frame::ModuleManager::create( ::comphelper::getProcessComponentContext() );
407 vcl::EnumContext::Application eApp
= vcl::EnumContext::GetApplicationEnum(xModuleManager
->identify(xFrame
));
408 lcl_setNotebookbarFileName( eApp
, rUIName
);
413 // trigger the StateMethod
414 rBindings
.Invalidate(SID_NOTEBOOKBAR
);
418 bool SfxNotebookBar::StateMethod(SfxBindings
& rBindings
, std::u16string_view rUIFile
,
419 bool bReloadNotebookbar
)
421 SfxFrame
& rFrame
= rBindings
.GetDispatcher_Impl()->GetFrame()->GetFrame();
422 return StateMethod(rFrame
.GetSystemWindow(), rFrame
.GetFrameInterface(), rUIFile
,
426 bool SfxNotebookBar::StateMethod(SystemWindow
* pSysWindow
,
427 const Reference
<css::frame::XFrame
>& xFrame
,
428 std::u16string_view rUIFile
, bool bReloadNotebookbar
)
432 SfxViewFrame
* pViewFrm
= SfxViewFrame::Current();
433 if (pViewFrm
&& pViewFrm
->GetWindow().GetSystemWindow())
434 pSysWindow
= pViewFrm
->GetWindow().GetSystemWindow();
439 const SfxViewShell
* pViewShell
= SfxViewShell::Current();
440 auto& rViewData
= NotebookBarViewManager::get().getViewData(pViewShell
);
441 bool hasWeldedWrapper
= bool(rViewData
.m_pWeldedWrapper
);
445 css::uno::Reference
<css::uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
446 const Reference
<frame::XModuleManager
> xModuleManager
= frame::ModuleManager::create( xContext
);
447 OUString aModuleName
= xModuleManager
->identify( xFrame
);
448 vcl::EnumContext::Application eApp
= vcl::EnumContext::GetApplicationEnum( aModuleName
);
449 bool bIsLOK
= comphelper::LibreOfficeKit::isActive();
453 sFile
= "notebookbar_online.ui";
455 sFile
= lcl_getNotebookbarFileName( eApp
);
457 OUString sNewFile
= rUIFile
+ sFile
;
458 OUString sCurrentFile
;
459 VclPtr
<NotebookBar
> pNotebookBar
= pSysWindow
->GetNotebookBar();
461 sCurrentFile
= pNotebookBar
->GetUIFilePath();
463 bool bChangedFile
= sNewFile
!= sCurrentFile
;
466 (!sFile
.isEmpty() && bChangedFile
) ||
467 (!pNotebookBar
|| !pNotebookBar
->IsVisible()) ||
469 ) || (bIsLOK
&& !hasWeldedWrapper
))
471 OUString aBuf
= rUIFile
+ sFile
;
473 //Addons For Notebookbar
474 std::vector
<Image
> aImageValues
;
475 std::vector
<css::uno::Sequence
< css::uno::Sequence
< css::beans::PropertyValue
> > > aExtensionValues
;
476 NotebookBarAddonsItem aNotebookBarAddonsItem
;
477 NotebookbarAddonValues(aImageValues
, aExtensionValues
);
478 aNotebookBarAddonsItem
.aAddonValues
= aExtensionValues
;
479 aNotebookBarAddonsItem
.aImageValues
= aImageValues
;
486 // Notebookbar was loaded too early what caused:
487 // * in LOK: Paste Special feature was incorrectly initialized
488 // Skip first request so Notebookbar will be initialized after document was loaded
489 static std::map
<const void*, bool> bSkippedFirstInit
;
490 if (eApp
== vcl::EnumContext::Application::Writer
491 && bSkippedFirstInit
.find(pViewShell
) == bSkippedFirstInit
.end())
493 bSkippedFirstInit
[pViewShell
] = true;
494 ResetActiveToolbarModeToDefault(eApp
);
498 // update the current LOK language and locale for the dialog tunneling
499 comphelper::LibreOfficeKit::setLanguageTag(pViewShell
->GetLOKLanguageTag());
500 comphelper::LibreOfficeKit::setLocale(pViewShell
->GetLOKLocale());
502 pNotebookBar
= VclPtr
<NotebookBar
>::Create(pSysWindow
, "NotebookBar", aBuf
, xFrame
, aNotebookBarAddonsItem
);
503 rViewData
.m_pNotebookBar
= pNotebookBar
;
504 assert(pNotebookBar
->IsWelded());
506 sal_uInt64 nWindowId
= reinterpret_cast<sal_uInt64
>(pViewShell
);
507 rViewData
.m_pWeldedWrapper
.reset(
508 new WeldedTabbedNotebookbar(pNotebookBar
->GetMainContainer(),
509 pNotebookBar
->GetUIFilePath(),
511 pNotebookBar
->SetDisposeCallback(LINK(nullptr, SfxNotebookBar
, VclDisposeHdl
), pViewShell
);
513 rViewData
.m_pToolbarUnoDispatcher
.reset(
514 new ToolbarUnoDispatcher(rViewData
.m_pWeldedWrapper
->getWeldedToolbar(),
515 rViewData
.m_pWeldedWrapper
->getBuilder(), xFrame
));
520 RemoveListeners(pSysWindow
);
522 pSysWindow
->SetNotebookBar(aBuf
, xFrame
, aNotebookBarAddonsItem
, bReloadNotebookbar
);
523 pNotebookBar
= pSysWindow
->GetNotebookBar();
524 pNotebookBar
->Show();
526 pNotebookBar
->GetParent()->Resize();
528 utl::OConfigurationTreeRoot
aRoot(lcl_getCurrentImplConfigRoot());
529 const utl::OConfigurationNode
aModeNode(lcl_getCurrentImplConfigNode(xFrame
, aRoot
));
530 SfxNotebookBar::ShowMenubar( comphelper::getBOOL( aModeNode
.getNodeValue( "HasMenubar" ) ) );
532 SfxViewFrame
* pView
= SfxViewFrame::Current();
536 pNotebookBar
->SetupListener(true);
542 else if (comphelper::LibreOfficeKit::isActive())
544 // don't do anything to not close notebookbar of other session
545 return hasWeldedWrapper
;
547 else if (auto pNotebookBar
= pSysWindow
->GetNotebookBar())
549 vcl::Window
* pParent
= pNotebookBar
->GetParent();
550 pSysWindow
->CloseNotebookBar();
552 SfxNotebookBar::ShowMenubar(true);
558 void SfxNotebookBar::RemoveListeners(SystemWindow
const * pSysWindow
)
560 if (auto pNotebookBar
= pSysWindow
->GetNotebookBar())
562 pNotebookBar
->SetupListener(false);
566 void SfxNotebookBar::ShowMenubar(bool bShow
)
573 Reference
<frame::XFrame
> xFrame
;
574 vcl::EnumContext::Application eCurrentApp
= vcl::EnumContext::Application::NONE
;
575 uno::Reference
< uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
576 const Reference
<frame::XModuleManager
> xModuleManager
= frame::ModuleManager::create( xContext
);
578 if (SfxViewFrame
* pViewFrm
= SfxViewFrame::Current())
580 xFrame
= pViewFrm
->GetFrame().GetFrameInterface();
581 eCurrentApp
= vcl::EnumContext::GetApplicationEnum( xModuleManager
->identify( xFrame
) );
584 SfxViewFrame
* pViewFrame
= SfxViewFrame::GetFirst();
587 xFrame
= pViewFrame
->GetFrame().GetFrameInterface();
590 vcl::EnumContext::Application eApp
=
591 vcl::EnumContext::GetApplicationEnum( xModuleManager
->identify( xFrame
) );
593 if ( eApp
== eCurrentApp
)
595 const Reference
<frame::XLayoutManager
>& xLayoutManager
=
596 lcl_getLayoutManager( xFrame
);
598 if (xLayoutManager
.is())
600 if (xLayoutManager
->getElement(MENUBAR_STR
).is())
602 if (xLayoutManager
->isElementVisible(MENUBAR_STR
) && !bShow
)
603 xLayoutManager
->hideElement(MENUBAR_STR
);
604 else if(!xLayoutManager
->isElementVisible(MENUBAR_STR
) && bShow
)
605 xLayoutManager
->showElement(MENUBAR_STR
);
611 pViewFrame
= SfxViewFrame::GetNext( *pViewFrame
);
616 void SfxNotebookBar::ShowMenubar(SfxViewFrame
const * pViewFrame
, bool bShow
)
623 Reference
<frame::XFrame
> xFrame
= pViewFrame
->GetFrame().GetFrameInterface();
626 const Reference
<frame::XLayoutManager
>& xLayoutManager
= lcl_getLayoutManager(xFrame
);
627 if (xLayoutManager
.is())
629 if (xLayoutManager
->getElement(MENUBAR_STR
).is())
631 if (xLayoutManager
->isElementVisible(MENUBAR_STR
) && !bShow
)
632 xLayoutManager
->hideElement(MENUBAR_STR
);
633 else if (!xLayoutManager
->isElementVisible(MENUBAR_STR
) && bShow
)
634 xLayoutManager
->showElement(MENUBAR_STR
);
641 void SfxNotebookBar::ToggleMenubar()
643 SfxViewFrame
* pViewFrm
= SfxViewFrame::Current();
647 const Reference
<frame::XFrame
>& xFrame
= pViewFrm
->GetFrame().GetFrameInterface();
651 const Reference
<frame::XLayoutManager
>& xLayoutManager
=
652 lcl_getLayoutManager(xFrame
);
655 if (xLayoutManager
.is() && xLayoutManager
->getElement(MENUBAR_STR
).is())
657 if (xLayoutManager
->isElementVisible(MENUBAR_STR
))
659 SfxNotebookBar::ShowMenubar(false);
663 SfxNotebookBar::ShowMenubar(true);
666 // Save menubar settings
669 utl::OConfigurationTreeRoot
aRoot(lcl_getCurrentImplConfigRoot());
670 utl::OConfigurationNode
aModeNode(lcl_getCurrentImplConfigNode(xFrame
, aRoot
));
671 aModeNode
.setNodeValue( "HasMenubar", toAny
<bool>( bShow
) );
676 void SfxNotebookBar::ReloadNotebookBar(std::u16string_view sUIPath
)
678 if (!SfxNotebookBar::IsActive())
680 SfxViewShell
* pViewShell
= SfxViewShell::Current();
683 sfx2::SfxNotebookBar::StateMethod(pViewShell
->GetViewFrame().GetBindings(), sUIPath
, true);
686 IMPL_STATIC_LINK(SfxNotebookBar
, VclDisposeHdl
, const SfxViewShell
*, pViewShell
, void)
688 NotebookBarViewManager::get().removeViewData(pViewShell
);
691 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */