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/notebookbar.hxx>
15 #include <vcl/syswin.hxx>
16 #include <sfx2/viewfrm.hxx>
17 #include <sfx2/sfxsids.hrc>
18 #include <comphelper/processfactory.hxx>
19 #include <comphelper/lok.hxx>
20 #include <com/sun/star/frame/UnknownModuleException.hpp>
21 #include <com/sun/star/ui/ContextChangeEventMultiplexer.hpp>
22 #include <com/sun/star/ui/XContextChangeEventMultiplexer.hpp>
23 #include <com/sun/star/frame/XLayoutManager.hpp>
24 #include <officecfg/Office/UI/ToolbarMode.hxx>
25 #include <com/sun/star/frame/XModuleManager.hpp>
26 #include <com/sun/star/frame/ModuleManager.hpp>
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <unotools/confignode.hxx>
29 #include <comphelper/types.hxx>
30 #include <framework/addonsoptions.hxx>
31 #include <vcl/NotebookBarAddonsMerger.hxx>
34 #include <vcl/WeldedTabbedNotebookbar.hxx>
37 using namespace css::uno
;
38 using namespace css::ui
;
41 #define MENUBAR_STR "private:resource/menubar/menubar"
43 const char MERGE_NOTEBOOKBAR_URL
[] = "URL";
45 bool SfxNotebookBar::m_bLock
= false;
46 bool SfxNotebookBar::m_bHide
= false;
47 std::map
<const SfxViewShell
*, std::shared_ptr
<WeldedTabbedNotebookbar
>> SfxNotebookBar::m_pNotebookBarWeldedWrapper
;
49 static void NotebookbarAddonValues(
50 std::vector
<Image
>& aImageValues
,
51 std::vector
<css::uno::Sequence
<css::uno::Sequence
<css::beans::PropertyValue
>>>&
54 framework::AddonsOptions aAddonsItems
;
56 for (int nIdx
= 0; nIdx
< aAddonsItems
.GetAddonsNotebookBarCount(); nIdx
++)
58 const css::uno::Sequence
<css::uno::Sequence
<css::beans::PropertyValue
>> aExtension
59 = aAddonsItems
.GetAddonsNotebookBarPart(nIdx
);
60 for (const css::uno::Sequence
<css::beans::PropertyValue
>& rExtensionVal
: aExtension
)
63 bool isBigImage
= true;
64 for (const auto& rProp
: rExtensionVal
)
66 if (rProp
.Name
== MERGE_NOTEBOOKBAR_URL
)
69 rProp
.Value
>>= sImage
;
70 aImage
= Image(framework::AddonsOptions().GetImageFromURL(sImage
, isBigImage
));
73 aImageValues
.push_back(aImage
);
75 aExtensionValues
.push_back(aExtension
);
79 static Reference
<frame::XLayoutManager
> lcl_getLayoutManager( const Reference
<frame::XFrame
>& xFrame
)
81 css::uno::Reference
<css::frame::XLayoutManager
> xLayoutManager
;
85 Reference
<css::beans::XPropertySet
> xPropSet(xFrame
, UNO_QUERY
);
89 Any aValue
= xPropSet
->getPropertyValue("LayoutManager");
90 aValue
>>= xLayoutManager
;
94 return xLayoutManager
;
97 static OUString
lcl_getAppName( vcl::EnumContext::Application eApp
)
101 case vcl::EnumContext::Application::Writer
:
104 case vcl::EnumContext::Application::Calc
:
107 case vcl::EnumContext::Application::Impress
:
110 case vcl::EnumContext::Application::Draw
:
113 case vcl::EnumContext::Application::Formula
:
122 static void lcl_setNotebookbarFileName( vcl::EnumContext::Application eApp
, const OUString
& sFileName
)
124 std::shared_ptr
<comphelper::ConfigurationChanges
> aBatch(
125 comphelper::ConfigurationChanges::create( ::comphelper::getProcessComponentContext() ) );
128 case vcl::EnumContext::Application::Writer
:
129 officecfg::Office::UI::ToolbarMode::ActiveWriter::set( sFileName
, aBatch
);
131 case vcl::EnumContext::Application::Calc
:
132 officecfg::Office::UI::ToolbarMode::ActiveCalc::set( sFileName
, aBatch
);
134 case vcl::EnumContext::Application::Impress
:
135 officecfg::Office::UI::ToolbarMode::ActiveImpress::set( sFileName
, aBatch
);
137 case vcl::EnumContext::Application::Draw
:
138 officecfg::Office::UI::ToolbarMode::ActiveDraw::set( sFileName
, aBatch
);
146 static OUString
lcl_getNotebookbarFileName( vcl::EnumContext::Application eApp
)
150 case vcl::EnumContext::Application::Writer
:
151 return officecfg::Office::UI::ToolbarMode::ActiveWriter::get();
153 case vcl::EnumContext::Application::Calc
:
154 return officecfg::Office::UI::ToolbarMode::ActiveCalc::get();
156 case vcl::EnumContext::Application::Impress
:
157 return officecfg::Office::UI::ToolbarMode::ActiveImpress::get();
159 case vcl::EnumContext::Application::Draw
:
160 return officecfg::Office::UI::ToolbarMode::ActiveDraw::get();
169 static utl::OConfigurationTreeRoot
lcl_getCurrentImplConfigRoot()
171 return utl::OConfigurationTreeRoot(::comphelper::getProcessComponentContext(),
172 "org.openoffice.Office.UI.ToolbarMode/",
176 static utl::OConfigurationNode
lcl_getCurrentImplConfigNode(const Reference
<css::frame::XFrame
>& xFrame
,
177 utl::OConfigurationTreeRoot
const & rNotebookbarNode
)
179 if (!rNotebookbarNode
.isValid())
180 return utl::OConfigurationNode();
182 const Reference
<frame::XModuleManager
> xModuleManager
= frame::ModuleManager::create( ::comphelper::getProcessComponentContext() );
184 vcl::EnumContext::Application eApp
= vcl::EnumContext::GetApplicationEnum( xModuleManager
->identify( xFrame
) );
185 OUString aActive
= lcl_getNotebookbarFileName( eApp
);
187 const utl::OConfigurationNode aImplsNode
= rNotebookbarNode
.openNode("Applications/" + lcl_getAppName( eApp
) + "/Modes");
188 const Sequence
<OUString
> aModeNodeNames( aImplsNode
.getNodeNames() );
190 for ( const auto& rModeNodeName
: aModeNodeNames
)
192 const utl::OConfigurationNode
aImplNode( aImplsNode
.openNode( rModeNodeName
) );
193 if ( !aImplNode
.isValid() )
196 OUString aCommandArg
= comphelper::getString( aImplNode
.getNodeValue( "CommandArg" ) );
198 if ( aCommandArg
== aActive
)
204 return utl::OConfigurationNode();
207 void SfxNotebookBar::CloseMethod(SfxBindings
& rBindings
)
209 SfxFrame
& rFrame
= rBindings
.GetDispatcher_Impl()->GetFrame()->GetFrame();
210 CloseMethod(rFrame
.GetSystemWindow());
213 void SfxNotebookBar::CloseMethod(SystemWindow
* pSysWindow
)
217 RemoveListeners(pSysWindow
);
218 if(pSysWindow
->GetNotebookBar())
219 pSysWindow
->CloseNotebookBar();
220 if (SfxViewFrame::Current())
221 SfxNotebookBar::ShowMenubar(SfxViewFrame::Current(), true);
225 void SfxNotebookBar::LockNotebookBar()
231 void SfxNotebookBar::UnlockNotebookBar()
237 bool SfxNotebookBar::IsActive()
242 vcl::EnumContext::Application eApp
= vcl::EnumContext::Application::Any
;
244 if (SfxViewFrame::Current())
246 const Reference
<frame::XFrame
>& xFrame
= SfxViewFrame::Current()->GetFrame().GetFrameInterface();
250 const Reference
<frame::XModuleManager
> xModuleManager
= frame::ModuleManager::create( ::comphelper::getProcessComponentContext() );
253 eApp
= vcl::EnumContext::GetApplicationEnum(xModuleManager
->identify(xFrame
));
255 catch (css::frame::UnknownModuleException
& e
)
257 SAL_WARN("sfx.appl", "SfxNotebookBar::IsActive(): " + e
.Message
);
264 OUString
appName(lcl_getAppName( eApp
));
266 if (appName
.isEmpty())
270 OUString aPath
= "org.openoffice.Office.UI.ToolbarMode/Applications/" + appName
;
272 const utl::OConfigurationTreeRoot
aAppNode(
273 ::comphelper::getProcessComponentContext(),
276 if ( !aAppNode
.isValid() )
279 OUString aActive
= comphelper::getString( aAppNode
.getNodeValue( "Active" ) );
281 const utl::OConfigurationNode aModesNode
= aAppNode
.openNode("Modes");
282 const Sequence
<OUString
> aModeNodeNames( aModesNode
.getNodeNames() );
284 for ( const auto& rModeNodeName
: aModeNodeNames
)
286 const utl::OConfigurationNode
aModeNode( aModesNode
.openNode( rModeNodeName
) );
287 if ( !aModeNode
.isValid() )
290 OUString aCommandArg
= comphelper::getString( aModeNode
.getNodeValue( "CommandArg" ) );
292 if ( aCommandArg
== aActive
)
294 return comphelper::getBOOL( aModeNode
.getNodeValue( "HasNotebookbar" ) );
300 void SfxNotebookBar::ExecMethod(SfxBindings
& rBindings
, const OUString
& rUIName
)
302 // Save active UI file name
303 if ( !rUIName
.isEmpty() && SfxViewFrame::Current() )
305 const Reference
<frame::XFrame
>& xFrame
= SfxViewFrame::Current()->GetFrame().GetFrameInterface();
308 const Reference
<frame::XModuleManager
> xModuleManager
= frame::ModuleManager::create( ::comphelper::getProcessComponentContext() );
309 vcl::EnumContext::Application eApp
= vcl::EnumContext::GetApplicationEnum(xModuleManager
->identify(xFrame
));
310 lcl_setNotebookbarFileName( eApp
, rUIName
);
314 // trigger the StateMethod
315 rBindings
.Invalidate(SID_NOTEBOOKBAR
);
319 bool SfxNotebookBar::StateMethod(SfxBindings
& rBindings
, const OUString
& rUIFile
,
320 bool bReloadNotebookbar
)
322 SfxFrame
& rFrame
= rBindings
.GetDispatcher_Impl()->GetFrame()->GetFrame();
323 return StateMethod(rFrame
.GetSystemWindow(), rFrame
.GetFrameInterface(), rUIFile
,
327 bool SfxNotebookBar::StateMethod(SystemWindow
* pSysWindow
,
328 const Reference
<css::frame::XFrame
>& xFrame
,
329 const OUString
& rUIFile
, bool bReloadNotebookbar
)
333 if (SfxViewFrame::Current() && SfxViewFrame::Current()->GetWindow().GetSystemWindow())
334 pSysWindow
= SfxViewFrame::Current()->GetWindow().GetSystemWindow();
341 css::uno::Reference
<css::uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
342 const Reference
<frame::XModuleManager
> xModuleManager
= frame::ModuleManager::create( xContext
);
343 OUString aModuleName
= xModuleManager
->identify( xFrame
);
344 vcl::EnumContext::Application eApp
= vcl::EnumContext::GetApplicationEnum( aModuleName
);
345 OUString sFile
= lcl_getNotebookbarFileName( eApp
);
346 OUString sNewFile
= rUIFile
+ sFile
;
347 OUString sCurrentFile
;
348 VclPtr
<NotebookBar
> pNotebookBar
= pSysWindow
->GetNotebookBar();
350 sCurrentFile
= pNotebookBar
->GetUIFilePath();
352 bool bChangedFile
= sNewFile
!= sCurrentFile
;
354 if ((!sFile
.isEmpty() && bChangedFile
) || !pNotebookBar
|| !pNotebookBar
->IsVisible()
355 || bReloadNotebookbar
|| comphelper::LibreOfficeKit::isActive())
357 const SfxViewShell
* pViewShell
= SfxViewShell::Current();
359 // Notebookbar was loaded too early what caused:
360 // * in LOK: Paste Special feature was incorrectly initialized
361 // Skip first request so Notebookbar will be initialized after document was loaded
362 static std::map
<const void*, bool> bSkippedFirstInit
;
363 if (comphelper::LibreOfficeKit::isActive()
364 && bSkippedFirstInit
.find(pViewShell
) == bSkippedFirstInit
.end())
366 bSkippedFirstInit
[pViewShell
] = true;
370 RemoveListeners(pSysWindow
);
372 OUString aBuf
= rUIFile
+ sFile
;
374 //Addons For Notebookbar
375 std::vector
<Image
> aImageValues
;
376 std::vector
<css::uno::Sequence
< css::uno::Sequence
< css::beans::PropertyValue
> > > aExtensionValues
;
377 NotebookBarAddonsItem aNotebookBarAddonsItem
;
378 NotebookbarAddonValues(aImageValues
, aExtensionValues
);
379 aNotebookBarAddonsItem
.aAddonValues
= aExtensionValues
;
380 aNotebookBarAddonsItem
.aImageValues
= aImageValues
;
382 // setup if necessary
383 if (comphelper::LibreOfficeKit::isActive())
385 // update the current LOK language and locale for the dialog tunneling
386 comphelper::LibreOfficeKit::setLanguageTag(pViewShell
->GetLOKLanguageTag());
387 comphelper::LibreOfficeKit::setLocale(pViewShell
->GetLOKLocale());
390 pSysWindow
->SetNotebookBar(aBuf
, xFrame
, aNotebookBarAddonsItem
, bReloadNotebookbar
);
391 pNotebookBar
= pSysWindow
->GetNotebookBar();
392 pNotebookBar
->Show();
395 bool hasWeldedWrapper
= m_pNotebookBarWeldedWrapper
.find(pViewShell
) != m_pNotebookBarWeldedWrapper
.end();
396 if ((!hasWeldedWrapper
|| bReloadNotebookbar
) && pNotebookBar
->IsWelded())
398 sal_uInt64 nWindowId
= reinterpret_cast<sal_uInt64
>(pViewShell
);
399 m_pNotebookBarWeldedWrapper
.emplace(std::make_pair(pViewShell
,
400 new WeldedTabbedNotebookbar(pNotebookBar
->GetMainContainer(),
401 pNotebookBar
->GetUIFilePath(),
404 pNotebookBar
->SetDisposeCallback(LINK(nullptr, SfxNotebookBar
, VclDisposeHdl
), pViewShell
);
407 pNotebookBar
->GetParent()->Resize();
409 utl::OConfigurationTreeRoot
aRoot(lcl_getCurrentImplConfigRoot());
410 const utl::OConfigurationNode
aModeNode(lcl_getCurrentImplConfigNode(xFrame
, aRoot
));
411 SfxNotebookBar::ShowMenubar( comphelper::getBOOL( aModeNode
.getNodeValue( "HasMenubar" ) ) );
413 SfxViewFrame
* pView
= SfxViewFrame::Current();
417 pNotebookBar
->ControlListenerForCurrentController(true);
423 else if (auto pNotebookBar
= pSysWindow
->GetNotebookBar())
425 pNotebookBar
->Hide();
426 pNotebookBar
->GetParent()->Resize();
427 SfxNotebookBar::ShowMenubar(true);
433 void SfxNotebookBar::RemoveListeners(SystemWindow
const * pSysWindow
)
435 if (auto pNotebookBar
= pSysWindow
->GetNotebookBar())
437 pNotebookBar
->StopListeningAllControllers();
441 void SfxNotebookBar::ShowMenubar(bool bShow
)
448 Reference
<frame::XFrame
> xFrame
;
449 vcl::EnumContext::Application eCurrentApp
= vcl::EnumContext::Application::NONE
;
450 uno::Reference
< uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
451 const Reference
<frame::XModuleManager
> xModuleManager
= frame::ModuleManager::create( xContext
);
453 if ( SfxViewFrame::Current() )
455 xFrame
= SfxViewFrame::Current()->GetFrame().GetFrameInterface();
456 eCurrentApp
= vcl::EnumContext::GetApplicationEnum( xModuleManager
->identify( xFrame
) );
459 SfxViewFrame
* pViewFrame
= SfxViewFrame::GetFirst();
462 xFrame
= pViewFrame
->GetFrame().GetFrameInterface();
465 vcl::EnumContext::Application eApp
=
466 vcl::EnumContext::GetApplicationEnum( xModuleManager
->identify( xFrame
) );
468 if ( eApp
== eCurrentApp
)
470 const Reference
<frame::XLayoutManager
>& xLayoutManager
=
471 lcl_getLayoutManager( xFrame
);
473 if (xLayoutManager
.is())
475 xLayoutManager
->lock();
477 if (xLayoutManager
->getElement(MENUBAR_STR
).is())
479 if (xLayoutManager
->isElementVisible(MENUBAR_STR
) && !bShow
)
480 xLayoutManager
->hideElement(MENUBAR_STR
);
481 else if(!xLayoutManager
->isElementVisible(MENUBAR_STR
) && bShow
)
482 xLayoutManager
->showElement(MENUBAR_STR
);
485 xLayoutManager
->unlock();
490 pViewFrame
= SfxViewFrame::GetNext( *pViewFrame
);
495 void SfxNotebookBar::ShowMenubar(SfxViewFrame
const * pViewFrame
, bool bShow
)
502 Reference
<frame::XFrame
> xFrame
= pViewFrame
->GetFrame().GetFrameInterface();
505 const Reference
<frame::XLayoutManager
>& xLayoutManager
= lcl_getLayoutManager(xFrame
);
506 if (xLayoutManager
.is())
508 xLayoutManager
->lock();
510 if (xLayoutManager
->getElement(MENUBAR_STR
).is())
512 if (xLayoutManager
->isElementVisible(MENUBAR_STR
) && !bShow
)
513 xLayoutManager
->hideElement(MENUBAR_STR
);
514 else if (!xLayoutManager
->isElementVisible(MENUBAR_STR
) && bShow
)
515 xLayoutManager
->showElement(MENUBAR_STR
);
518 xLayoutManager
->unlock();
524 void SfxNotebookBar::ToggleMenubar()
526 if (!SfxViewFrame::Current())
529 const Reference
<frame::XFrame
>& xFrame
= SfxViewFrame::Current()->GetFrame().GetFrameInterface();
533 const Reference
<frame::XLayoutManager
>& xLayoutManager
=
534 lcl_getLayoutManager(xFrame
);
537 if (xLayoutManager
.is() && xLayoutManager
->getElement(MENUBAR_STR
).is())
539 if (xLayoutManager
->isElementVisible(MENUBAR_STR
))
541 SfxNotebookBar::ShowMenubar(false);
545 SfxNotebookBar::ShowMenubar(true);
548 // Save menubar settings
551 utl::OConfigurationTreeRoot
aRoot(lcl_getCurrentImplConfigRoot());
552 utl::OConfigurationNode
aModeNode(lcl_getCurrentImplConfigNode(xFrame
, aRoot
));
553 aModeNode
.setNodeValue( "HasMenubar", toAny
<bool>( bShow
) );
558 void SfxNotebookBar::ReloadNotebookBar(const OUString
& sUIPath
)
560 if (SfxNotebookBar::IsActive())
562 SfxViewShell
* pViewShell
= SfxViewShell::Current();
563 sfx2::SfxNotebookBar::StateMethod(pViewShell
->GetViewFrame()->GetBindings(), sUIPath
, true);
567 IMPL_STATIC_LINK(SfxNotebookBar
, VclDisposeHdl
, const SfxViewShell
*, pViewShell
, void)
569 m_pNotebookBarWeldedWrapper
.erase(pViewShell
);
572 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */