summaryrefslogtreecommitdiffstats
path: root/sfx2/source/appl
diff options
context:
space:
mode:
Diffstat (limited to 'sfx2/source/appl')
-rw-r--r--sfx2/source/appl/app.cxx554
-rw-r--r--sfx2/source/appl/appbas.cxx155
-rw-r--r--sfx2/source/appl/appbaslib.cxx188
-rw-r--r--sfx2/source/appl/appcfg.cxx343
-rw-r--r--sfx2/source/appl/appchild.cxx66
-rw-r--r--sfx2/source/appl/appdata.cxx127
-rw-r--r--sfx2/source/appl/appdde.cxx567
-rw-r--r--sfx2/source/appl/appdispatchprovider.cxx231
-rw-r--r--sfx2/source/appl/appinit.cxx233
-rw-r--r--sfx2/source/appl/appmain.cxx38
-rw-r--r--sfx2/source/appl/appmisc.cxx211
-rw-r--r--sfx2/source/appl/appopen.cxx1154
-rw-r--r--sfx2/source/appl/appquit.cxx103
-rw-r--r--sfx2/source/appl/appreg.cxx105
-rw-r--r--sfx2/source/appl/appserv.cxx1808
-rw-r--r--sfx2/source/appl/appuno.cxx1845
-rw-r--r--sfx2/source/appl/childwin.cxx623
-rw-r--r--sfx2/source/appl/fileobj.cxx435
-rw-r--r--sfx2/source/appl/fileobj.hxx82
-rw-r--r--sfx2/source/appl/flatpak.cxx99
-rw-r--r--sfx2/source/appl/fwkhelper.cxx52
-rw-r--r--sfx2/source/appl/getbasctlfunction.cxx64
-rw-r--r--sfx2/source/appl/getbasctlfunction.hxx38
-rw-r--r--sfx2/source/appl/helpdispatch.cxx106
-rw-r--r--sfx2/source/appl/helpdispatch.hxx47
-rw-r--r--sfx2/source/appl/helpinterceptor.cxx262
-rw-r--r--sfx2/source/appl/helpinterceptor.hxx141
-rw-r--r--sfx2/source/appl/impldde.cxx348
-rw-r--r--sfx2/source/appl/impldde.hxx72
-rw-r--r--sfx2/source/appl/linkmgr2.cxx722
-rw-r--r--sfx2/source/appl/linksrc.cxx418
-rw-r--r--sfx2/source/appl/lnkbase2.cxx604
-rw-r--r--sfx2/source/appl/macroloader.cxx344
-rw-r--r--sfx2/source/appl/module.cxx267
-rw-r--r--sfx2/source/appl/newhelp.cxx2666
-rw-r--r--sfx2/source/appl/newhelp.hxx511
-rw-r--r--sfx2/source/appl/opengrf.cxx286
-rw-r--r--sfx2/source/appl/openuriexternally.cxx141
-rw-r--r--sfx2/source/appl/preventduplicateinteraction.cxx220
-rw-r--r--sfx2/source/appl/sfxhelp.cxx1401
-rw-r--r--sfx2/source/appl/sfxpicklist.cxx227
-rw-r--r--sfx2/source/appl/shutdownicon.cxx684
-rw-r--r--sfx2/source/appl/shutdownicon.hxx158
-rw-r--r--sfx2/source/appl/shutdowniconaqua.mm470
-rw-r--r--sfx2/source/appl/shutdowniconw32.cxx803
-rw-r--r--sfx2/source/appl/workwin.cxx2356
-rw-r--r--sfx2/source/appl/xpackcreator.cxx164
47 files changed, 22539 insertions, 0 deletions
diff --git a/sfx2/source/appl/app.cxx b/sfx2/source/appl/app.cxx
new file mode 100644
index 0000000000..6ae9810345
--- /dev/null
+++ b/sfx2/source/appl/app.cxx
@@ -0,0 +1,554 @@
+/* -*- 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 <sal/log.hxx>
+#include <tools/debug.hxx>
+
+#include <sfx2/app.hxx>
+#include <sfx2/frame.hxx>
+#include <basic/sberrors.hxx>
+
+#include <svl/svdde.hxx>
+#include <unotools/configmgr.hxx>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
+#include <basic/basmgr.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/sfxhelp.hxx>
+#include <sfx2/progress.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <appdata.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/event.hxx>
+#include <workwin.hxx>
+#include <sfx2/sidebar/Theme.hxx>
+#include <sfx2/tbxctrl.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <sfx2/stbitem.hxx>
+#include <sfx2/dockwin.hxx>
+
+#include <officecfg/Office/Common.hxx>
+#include <rtl/strbuf.hxx>
+#include <memory>
+#include <mutex>
+#include <framework/sfxhelperfunctions.hxx>
+#include <fwkhelper.hxx>
+
+#include "getbasctlfunction.hxx"
+
+using namespace ::com::sun::star;
+
+static SfxApplication* g_pSfxApplication = nullptr;
+
+#if HAVE_FEATURE_XMLHELP
+static SfxHelp* pSfxHelp = nullptr;
+#endif
+
+SfxApplication* SfxApplication::Get()
+{
+ return g_pSfxApplication;
+}
+
+void SfxApplication::SetModule(SfxToolsModule nSharedLib, std::unique_ptr<SfxModule> pModule)
+{
+ assert(g_pSfxApplication != nullptr);
+
+ g_pSfxApplication->pImpl->aModules[nSharedLib] = std::move(pModule);
+}
+
+SfxModule* SfxApplication::GetModule(SfxToolsModule nSharedLib)
+{
+ if (!g_pSfxApplication) // It is possible GetModule is called before SfxApplication is initialised via GetOrCreate()
+ return nullptr;
+ return g_pSfxApplication->pImpl->aModules[nSharedLib].get();
+}
+
+SfxApplication* SfxApplication::GetOrCreate()
+{
+ static std::mutex theApplicationMutex;
+
+ // SFX on demand
+ std::unique_lock aGuard(theApplicationMutex);
+ if (!g_pSfxApplication)
+ {
+ SAL_INFO( "sfx.appl", "SfxApplication::SetApp" );
+
+ g_pSfxApplication = new SfxApplication;
+
+ // at the moment a bug may occur when Initialize_Impl returns FALSE,
+ // but this is only temporary because all code that may cause such
+ // a fault will be moved outside the SFX
+ g_pSfxApplication->Initialize_Impl();
+
+ ::framework::SetRefreshToolbars( RefreshToolbars );
+ ::framework::SetToolBoxControllerCreator( SfxToolBoxControllerFactory );
+ ::framework::SetStatusBarControllerCreator( SfxStatusBarControllerFactory );
+ ::framework::SetDockingWindowCreator( SfxDockingWindowFactory );
+ ::framework::SetIsDockingWindowVisible( IsDockingWindowVisible );
+#if HAVE_FEATURE_XMLHELP
+ Application::SetHelp( pSfxHelp );
+#endif
+#if HAVE_FEATURE_XMLHELP || defined(EMSCRIPTEN)
+ bool bHelpTip = officecfg::Office::Common::Help::Tip::get();
+ bool bExtendedHelpTip = officecfg::Office::Common::Help::ExtendedTip::get();
+ if (!utl::ConfigManager::IsFuzzing() && bHelpTip)
+ Help::EnableQuickHelp();
+ else
+ Help::DisableQuickHelp();
+ if (!utl::ConfigManager::IsFuzzing() && bHelpTip && bExtendedHelpTip)
+ Help::EnableBalloonHelp();
+ else
+ Help::DisableBalloonHelp();
+#endif
+ }
+ return g_pSfxApplication;
+}
+
+SfxApplication::SfxApplication()
+ : pImpl( new SfxAppData_Impl )
+{
+ SetName( "StarOffice" );
+
+ SAL_INFO( "sfx.appl", "{ initialize DDE" );
+
+ bool bOk = InitializeDde();
+
+#ifdef DBG_UTIL
+ if( !bOk )
+ {
+ OStringBuffer aStr("No DDE-Service possible. Error: ");
+ if( GetDdeService() )
+ aStr.append(static_cast<sal_Int32>(GetDdeService()->GetError()));
+ else
+ aStr.append('?');
+ SAL_WARN( "sfx.appl", aStr.getStr() );
+ }
+#else
+ (void)bOk;
+#endif
+
+#if HAVE_FEATURE_XMLHELP
+ pSfxHelp = new SfxHelp;
+#endif
+
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::SetGlobalErrorHdl( LINK( this, SfxApplication, GlobalBasicErrorHdl_Impl ) );
+#endif
+
+ SAL_INFO( "sfx.appl", "} initialize DDE" );
+}
+
+SfxApplication::~SfxApplication()
+{
+ SAL_WARN_IF(GetObjectShells_Impl().size() != 0, "sfx.appl", "Memory leak: some object shells were not removed!");
+
+ Broadcast( SfxHint(SfxHintId::Dying) );
+
+ for (auto &module : pImpl->aModules) // Clear modules
+ module.reset();
+
+#if HAVE_FEATURE_XMLHELP
+ delete pSfxHelp;
+ Application::SetHelp();
+#endif
+
+ if ( !pImpl->bDowning )
+ Deinitialize();
+
+ g_pSfxApplication = nullptr;
+}
+
+
+const OUString& SfxApplication::GetLastDir_Impl() const
+
+/* [Description]
+
+ Internal method by which the last set directory with the method
+ <SfxApplication::SetLastDir_Impl()> in SFX is returned.
+
+ This is usually the most recently addressed by the
+ SfxFileDialog directory.
+
+ [Cross-reference]
+ <SfxApplication::SetLastDir_Impl()>
+*/
+
+{
+ return pImpl->aLastDir;
+}
+
+void SfxApplication::SetLastDir_Impl
+(
+ const OUString& rNewDir /* Complete directory path as a string */
+)
+
+/* [Description]
+
+ Internal Method, by which a directory path is set that was last addressed
+ (eg by the SfxFileDialog).
+
+ [Cross-reference]
+ <SfxApplication::GetLastDir_Impl()>
+*/
+
+{
+ pImpl->aLastDir = rNewDir;
+}
+
+
+void SfxApplication::ResetLastDir()
+{
+ pImpl->aLastDir.clear();
+}
+
+
+SfxDispatcher* SfxApplication::GetDispatcher_Impl()
+{
+ return pImpl->pViewFrame ? pImpl->pViewFrame->GetDispatcher() : &*pImpl->pAppDispat;
+}
+
+
+void SfxApplication::SetViewFrame_Impl( SfxViewFrame *pFrame )
+{
+ if ( pFrame != pImpl->pViewFrame )
+ {
+ SfxViewFrame *pOldFrame = pImpl->pViewFrame;
+
+ // DocWinActivate : both frames belong to the same TopWindow
+ // TopWinActivate : both frames belong to different TopWindows
+
+ bool bTaskActivate = pOldFrame != pFrame;
+
+ if ( pOldFrame )
+ {
+ if ( bTaskActivate )
+ NotifyEvent( SfxViewEventHint( SfxEventHintId::DeactivateDoc, GlobalEventConfig::GetEventName(GlobalEventId::DEACTIVATEDOC), pOldFrame->GetObjectShell(), pOldFrame->GetFrame().GetController() ) );
+
+ pOldFrame->DoDeactivate( bTaskActivate, pFrame );
+
+ if( pOldFrame->GetProgress() )
+ pOldFrame->GetProgress()->Suspend();
+ }
+
+ pImpl->pViewFrame = pFrame;
+
+ if( pFrame )
+ {
+ pFrame->DoActivate( bTaskActivate );
+ if ( bTaskActivate && pFrame->GetObjectShell() )
+ {
+ pFrame->GetObjectShell()->PostActivateEvent_Impl( pFrame );
+ NotifyEvent(SfxViewEventHint(SfxEventHintId::ActivateDoc, GlobalEventConfig::GetEventName(GlobalEventId::ACTIVATEDOC), pFrame->GetObjectShell(), pFrame->GetFrame().GetController() ) );
+ }
+
+ SfxProgress *pProgress = pFrame->GetProgress();
+ if ( pProgress )
+ {
+ if( pProgress->IsSuspended() )
+ pProgress->Resume();
+ else
+ pProgress->SetState( pProgress->GetState() );
+ }
+
+ if ( pImpl->pViewFrame->GetViewShell() )
+ {
+ SfxDispatcher* pDisp = pImpl->pViewFrame->GetDispatcher();
+ pDisp->Flush();
+ pDisp->Update_Impl(true);
+ }
+ }
+ }
+
+ // even if the frame actually didn't change, ensure its document is forwarded
+ // to SfxObjectShell::SetCurrentComponent.
+ // Otherwise, the CurrentComponent might not be correct, in case it has meanwhile
+ // been reset to some other document, by some non-SFX component. #i49133#
+ if ( pFrame && pFrame->GetViewShell() )
+ pFrame->GetViewShell()->SetCurrentDocument();
+}
+
+void SfxApplication::SetProgress_Impl
+(
+ SfxProgress *pProgress
+)
+{
+ DBG_ASSERT( ( !pImpl->pProgress && pProgress ) ||
+ ( pImpl->pProgress && !pProgress ),
+ "Progress activation/deactivation mismatch" );
+
+ if ( pImpl->pProgress && pProgress )
+ {
+ pImpl->pProgress->Suspend();
+ delete pImpl->pProgress;
+ }
+
+ pImpl->pProgress = pProgress;
+}
+
+
+sal_uInt16 SfxApplication::GetFreeIndex()
+{
+ return pImpl->aIndexBitSet.GetFreeIndex()+1;
+}
+
+
+void SfxApplication::ReleaseIndex(sal_uInt16 i)
+{
+ pImpl->aIndexBitSet.ReleaseIndex(i-1);
+}
+
+
+weld::Window* SfxApplication::GetTopWindow() const
+{
+ SfxWorkWindow* pWork = GetWorkWindow_Impl( SfxViewFrame::Current() );
+ if (!pWork)
+ return nullptr;
+ vcl::Window* pWindow = pWork->GetWindow();
+ if (!pWindow)
+ return nullptr;
+ return pWindow->GetFrameWeld();
+}
+
+SfxTbxCtrlFactory* SfxApplication::GetTbxCtrlFactory(const std::type_info& rSlotType, sal_uInt16 nSlotID) const
+{
+ // search for a factory with the given slot id
+ for (auto& rFactory : pImpl->maTbxCtrlFactories)
+ if( rFactory.nTypeId == rSlotType && rFactory.nSlotId == nSlotID )
+ return &rFactory;
+
+ // if no factory exists for the given slot id, see if we
+ // have a generic factory with the correct slot type and slot id == 0
+ for (auto& rFactory : pImpl->maTbxCtrlFactories)
+ if( rFactory.nTypeId == rSlotType && rFactory.nSlotId == 0 )
+ return &rFactory;
+
+ return nullptr;
+}
+
+SfxStbCtrlFactory* SfxApplication::GetStbCtrlFactory(const std::type_info& rSlotType, sal_uInt16 nSlotID) const
+{
+ for (auto& rFactory : pImpl->maStbCtrlFactories)
+ if ( rFactory.nTypeId == rSlotType &&
+ ( rFactory.nSlotId == 0 || rFactory.nSlotId == nSlotID ) )
+ return &rFactory;
+ return nullptr;
+}
+
+std::vector<SfxViewFrame*>& SfxApplication::GetViewFrames_Impl() const
+{
+ return pImpl->maViewFrames;
+}
+
+std::vector<SfxViewShell*>& SfxApplication::GetViewShells_Impl() const
+{
+ return pImpl->maViewShells;
+}
+
+std::unordered_map<OUString, css::uno::Reference<css::ui::XAcceleratorConfiguration>>& SfxApplication::GetAcceleratorConfs_Impl() const
+{
+ return pImpl->maAcceleratorConfs;
+}
+
+std::vector<SfxObjectShell*>& SfxApplication::GetObjectShells_Impl() const
+{
+ return pImpl->maObjShells;
+}
+
+void SfxApplication::Invalidate( sal_uInt16 nId )
+{
+ for( SfxViewFrame* pFrame = SfxViewFrame::GetFirst(); pFrame; pFrame = SfxViewFrame::GetNext( *pFrame ) )
+ Invalidate_Impl( pFrame->GetBindings(), nId );
+}
+
+#if HAVE_FEATURE_SCRIPTING
+
+#ifndef DISABLE_DYNLOADING
+
+typedef long (*basicide_handle_basic_error)(void const *);
+typedef void (*basicide_macro_organizer)(void *, void *, sal_Int16);
+
+#else
+
+extern "C" long basicide_handle_basic_error(void const*);
+extern "C" void basicide_macro_organizer(void*, void*, sal_Int16);
+
+#endif
+
+#endif
+
+IMPL_STATIC_LINK( SfxApplication, GlobalBasicErrorHdl_Impl, StarBASIC*, pStarBasic, bool )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) pStarBasic;
+ return false;
+#else
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ OUString aError;
+ ErrCodeMsg nErr = StarBASIC::GetErrorCode();
+ if (ErrorStringFactory::CreateString(nErr, aError))
+ {
+ const SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ std::shared_ptr<weld::MessageDialog> xBox;
+ xBox.reset(Application::CreateMessageDialog(
+ pViewFrame ? pViewFrame->GetFrameWeld() : nullptr,
+ VclMessageType::Error,
+ VclButtonsType::Ok,
+ aError,
+ GetpApp()));
+
+ xBox->runAsync(xBox, [](sal_Int32 /*nResult*/) {});
+ }
+ return true;
+ }
+
+#ifndef DISABLE_DYNLOADING
+ basicide_handle_basic_error pSymbol = reinterpret_cast<basicide_handle_basic_error>(sfx2::getBasctlFunction("basicide_handle_basic_error"));
+
+ // call basicide_handle_basic_error in basctl
+ bool bRet = pSymbol( pStarBasic );
+
+#else
+
+ bool bRet = basicide_handle_basic_error( pStarBasic );
+
+#endif
+
+ return bRet;
+
+#endif
+}
+
+bool SfxApplication::IsXScriptURL( const OUString& rScriptURL )
+{
+ bool result = false;
+
+#if !HAVE_FEATURE_SCRIPTING
+ (void) rScriptURL;
+#else
+ css::uno::Reference< css::uno::XComponentContext > xContext =
+ ::comphelper::getProcessComponentContext();
+
+ css::uno::Reference< css::uri::XUriReferenceFactory >
+ xFactory = css::uri::UriReferenceFactory::create( xContext );
+
+ try
+ {
+ css::uno::Reference< css::uri::XVndSunStarScriptUrl >
+ xUrl( xFactory->parse( rScriptURL ), css::uno::UNO_QUERY );
+
+ if ( xUrl.is() )
+ {
+ result = true;
+ }
+ }
+ catch (const css::uno::RuntimeException&)
+ {
+ // ignore, will just return FALSE
+ }
+#endif
+ return result;
+}
+
+OUString
+SfxApplication::ChooseScript(weld::Window *pParent)
+{
+ OUString aScriptURL;
+
+#if HAVE_FEATURE_SCRIPTING
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ SAL_INFO( "sfx.appl", "create selector dialog");
+
+ const SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ const SfxFrame* pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr;
+ uno::Reference< frame::XFrame > xFrame( pFrame ? pFrame->GetFrameInterface() : uno::Reference< frame::XFrame >() );
+
+ ScopedVclPtr<AbstractScriptSelectorDialog> pDlg(pFact->CreateScriptSelectorDialog(pParent, xFrame));
+
+ SAL_INFO( "sfx.appl", "done, now exec it");
+
+ sal_uInt16 nRet = pDlg->Execute();
+
+ SAL_INFO( "sfx.appl", "has returned");
+
+ if ( nRet == RET_OK )
+ {
+ aScriptURL = pDlg->GetScriptURL();
+ }
+#else
+ (void) pParent;
+#endif
+ return aScriptURL;
+}
+
+void SfxApplication::MacroOrganizer(weld::Window* pParent, const uno::Reference<frame::XFrame>& xDocFrame, sal_Int16 nTabId)
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) pParent;
+ (void) nTabId;
+#else
+
+#ifndef DISABLE_DYNLOADING
+ basicide_macro_organizer pSymbol = reinterpret_cast<basicide_macro_organizer>(sfx2::getBasctlFunction("basicide_macro_organizer"));
+
+ // call basicide_macro_organizer in basctl
+ pSymbol(pParent, xDocFrame.get(), nTabId);
+
+#else
+
+ basicide_macro_organizer(pParent, xDocFrame.get(), nTabId);
+
+#endif
+
+#endif
+}
+
+ErrCode SfxApplication::CallBasic( const OUString& rCode, BasicManager* pMgr, SbxArray* pArgs, SbxValue* pRet )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) rCode;
+ (void) pMgr;
+ (void) pArgs;
+ (void) pRet;
+ return ERRCODE_BASIC_CANNOT_LOAD;
+#else
+ (void) ERRCODE_BASIC_CANNOT_LOAD; // So that the !HAVE_FEATURE_SCRIPTING case isn't broken again by IWYU
+ return pMgr->ExecuteMacro( rCode, pArgs, pRet);
+#endif
+}
+
+sfx2::sidebar::Theme & SfxApplication::GetSidebarTheme()
+{
+ if (!pImpl->m_pSidebarTheme.is())
+ {
+ pImpl->m_pSidebarTheme.set(new sfx2::sidebar::Theme);
+ pImpl->m_pSidebarTheme->InitializeTheme();
+ }
+ return *pImpl->m_pSidebarTheme;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appbas.cxx b/sfx2/source/appl/appbas.cxx
new file mode 100644
index 0000000000..1cedcd9785
--- /dev/null
+++ b/sfx2/source/appl/appbas.cxx
@@ -0,0 +1,155 @@
+/* -*- 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 <config_features.h>
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <com/sun/star/script/XLibraryContainer.hpp>
+#include <officecfg/Office/Common.hxx>
+#include <svl/intitem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/whiter.hxx>
+#include <svl/voiditem.hxx>
+#include <basic/sbstar.hxx>
+
+#include <sfx2/frame.hxx>
+#include <sfx2/dinfdlg.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <appdata.hxx>
+#include <basic/basmgr.hxx>
+#include <unotools/configmgr.hxx>
+#include <sorgitm.hxx>
+#include <appbaslib.hxx>
+#include <basic/basicmanagerrepository.hxx>
+
+#define SFX_TYPEMAP
+#include <sfxslots.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::script;
+
+using ::basic::BasicManagerRepository;
+
+
+void SfxApplication::SaveBasicAndDialogContainer() const
+{
+ if ( pImpl->pBasicManager->isValid() )
+ pImpl->pBasicManager->storeAllLibraries();
+}
+
+BasicManager* SfxApplication::GetBasicManager()
+{
+#if !HAVE_FEATURE_SCRIPTING
+ return nullptr;
+#else
+ if (utl::ConfigManager::IsFuzzing())
+ return nullptr;
+ return BasicManagerRepository::getApplicationBasicManager();
+#endif
+}
+
+XLibraryContainer * SfxApplication::GetDialogContainer()
+{
+#if !HAVE_FEATURE_SCRIPTING
+ return nullptr;
+#else
+ if (utl::ConfigManager::IsFuzzing())
+ return nullptr;
+ if ( !pImpl->pBasicManager->isValid() )
+ GetBasicManager();
+ return pImpl->pBasicManager->getLibraryContainer( SfxBasicManagerHolder::DIALOGS );
+#endif
+}
+
+
+XLibraryContainer * SfxApplication::GetBasicContainer()
+{
+#if !HAVE_FEATURE_SCRIPTING
+ return nullptr;
+#else
+ if (utl::ConfigManager::IsFuzzing())
+ return nullptr;
+ if ( !pImpl->pBasicManager->isValid() )
+ GetBasicManager();
+ return pImpl->pBasicManager->getLibraryContainer( SfxBasicManagerHolder::SCRIPTS );
+#endif
+}
+
+StarBASIC* SfxApplication::GetBasic()
+{
+#if !HAVE_FEATURE_SCRIPTING
+ return nullptr;
+#else
+ if (utl::ConfigManager::IsFuzzing())
+ return nullptr;
+ return GetBasicManager()->GetLib(0);
+#endif
+}
+
+void SfxApplication::PropExec_Impl( SfxRequest const &rReq )
+{
+ sal_uInt16 nSID = rReq.GetSlot();
+ switch ( nSID )
+ {
+ case SID_ATTR_UNDO_COUNT:
+ {
+ if (const SfxUInt16Item* pCountItem = rReq.GetArg<SfxUInt16Item>(nSID))
+ {
+ std::shared_ptr< comphelper::ConfigurationChanges > batch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Undo::Steps::set(
+ pCountItem->GetValue(), batch);
+ batch->commit();
+ }
+ break;
+ }
+
+ default:
+ assert(false);
+ }
+}
+
+void SfxApplication::PropState_Impl( SfxItemSet &rSet )
+{
+ SfxWhichIter aIter(rSet);
+ for ( sal_uInt16 nSID = aIter.FirstWhich(); nSID; nSID = aIter.NextWhich() )
+ {
+ switch ( nSID )
+ {
+ case SID_ATTR_UNDO_COUNT:
+ rSet.Put(
+ SfxUInt16Item(
+ SID_ATTR_UNDO_COUNT,
+ officecfg::Office::Common::Undo::Steps::get()));
+ break;
+
+ default:
+ assert(false);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appbaslib.cxx b/sfx2/source/appl/appbaslib.cxx
new file mode 100644
index 0000000000..bfeafa1b1b
--- /dev/null
+++ b/sfx2/source/appl/appbaslib.cxx
@@ -0,0 +1,188 @@
+/* -*- 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 <config_features.h>
+
+#include <appbaslib.hxx>
+
+#include <sfx2/app.hxx>
+
+#include <basic/basmgr.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::embed;
+
+
+SfxBasicManagerHolder::SfxBasicManagerHolder()
+ :mpBasicManager( nullptr )
+{
+}
+
+void SfxBasicManagerHolder::Notify(SfxBroadcaster& rBC, SfxHint const& rHint)
+{
+ if (!mpBasicManager || &rBC != mpBasicManager)
+ return;
+ if (SfxHintId::Dying == rHint.GetId())
+ {
+ mpBasicManager = nullptr;
+ mxBasicContainer.clear();
+ mxDialogContainer.clear();
+ }
+}
+
+void SfxBasicManagerHolder::reset( BasicManager* _pBasicManager )
+{
+ impl_releaseContainers();
+
+#if !HAVE_FEATURE_SCRIPTING
+ (void) _pBasicManager;
+#else
+ // Note: we do not delete the old BasicManager. BasicManager instances are
+ // nowadays obtained from the BasicManagerRepository, and the ownership is with
+ // the repository.
+ // @see basic::BasicManagerRepository::getApplicationBasicManager
+ // @see basic::BasicManagerRepository::getDocumentBasicManager
+ mpBasicManager = _pBasicManager;
+
+ if ( !mpBasicManager )
+ return;
+
+ StartListening(*mpBasicManager);
+ try
+ {
+ mxBasicContainer.set( mpBasicManager->GetScriptLibraryContainer(), UNO_QUERY_THROW );
+ mxDialogContainer.set( mpBasicManager->GetDialogLibraryContainer(), UNO_QUERY_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("sfx.appl");
+ }
+#endif
+}
+
+void SfxBasicManagerHolder::storeAllLibraries()
+{
+#if HAVE_FEATURE_SCRIPTING
+ OSL_PRECOND( isValid(), "SfxBasicManagerHolder::storeAllLibraries: not initialized!" );
+ try
+ {
+ if ( mxBasicContainer.is() )
+ mxBasicContainer->storeLibraries();
+ if ( mxDialogContainer.is() )
+ mxDialogContainer->storeLibraries();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("sfx.appl");
+ }
+#endif
+}
+
+void SfxBasicManagerHolder::setStorage( const Reference< XStorage >& _rxStorage )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) _rxStorage;
+#else
+ try
+ {
+ if ( mxBasicContainer.is() )
+ mxBasicContainer->setRootStorage( _rxStorage );
+ if ( mxDialogContainer.is() )
+ mxDialogContainer->setRootStorage( _rxStorage );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("sfx.appl");
+ }
+#endif
+}
+
+void SfxBasicManagerHolder::storeLibrariesToStorage( const Reference< XStorage >& _rxStorage )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) _rxStorage;
+#else
+ OSL_PRECOND( isValid(), "SfxBasicManagerHolder::storeLibrariesToStorage: not initialized!" );
+
+ if ( mxBasicContainer.is() )
+ mxBasicContainer->storeLibrariesToStorage( _rxStorage );
+ if ( mxDialogContainer.is() )
+ mxDialogContainer->storeLibrariesToStorage( _rxStorage );
+#endif
+}
+
+XLibraryContainer * SfxBasicManagerHolder::getLibraryContainer( ContainerType _eType )
+{
+ OSL_PRECOND( isValid(), "SfxBasicManagerHolder::getLibraryContainer: not initialized!" );
+
+ switch ( _eType )
+ {
+ case SCRIPTS: return mxBasicContainer.get();
+ case DIALOGS: return mxDialogContainer.get();
+ }
+ OSL_FAIL( "SfxBasicManagerHolder::getLibraryContainer: illegal container type!" );
+ return nullptr;
+}
+
+void SfxBasicManagerHolder::impl_releaseContainers()
+{
+ mxBasicContainer.clear();
+ mxDialogContainer.clear();
+}
+
+bool SfxBasicManagerHolder::ImgVersion12PsswdBinaryLimitExceeded( std::vector< OUString >& sModules )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) sModules;
+#else
+ if ( mpBasicManager )
+ return mpBasicManager->ImgVersion12PsswdBinaryLimitExceeded( sModules );
+#endif
+ return true;
+}
+
+// Service for application library container
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_sfx2_ApplicationDialogLibraryContainer_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ SfxApplication::GetBasicManager();
+ css::uno::XInterface* pRet = SfxGetpApp()->GetDialogContainer();
+ pRet->acquire();
+ return pRet;
+}
+
+// Service for application library container
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_sfx2_ApplicationScriptLibraryContainer_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ SfxApplication::GetBasicManager();
+ css::uno::XInterface* pRet = SfxGetpApp()->GetBasicContainer();
+ pRet->acquire();
+ return pRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appcfg.cxx b/sfx2/source/appl/appcfg.cxx
new file mode 100644
index 0000000000..ee45f9da26
--- /dev/null
+++ b/sfx2/source/appl/appcfg.cxx
@@ -0,0 +1,343 @@
+/* -*- 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 <memory>
+#include <osl/file.hxx>
+
+#include <rtl/ustring.hxx>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <svl/slstitm.hxx>
+#include <svl/stritem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/undo.hxx>
+#include <svl/whiter.hxx>
+
+#include <sfx2/sfxsids.hrc>
+
+#include <officecfg/Inet.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <officecfg/Office/Recovery.hxx>
+#include <unotools/securityoptions.hxx>
+#include <unotools/pathoptions.hxx>
+#include <svtools/miscopt.hxx>
+#include <svtools/imgdef.hxx>
+#include <sal/log.hxx>
+#include <vcl/idle.hxx>
+
+#include <sfx2/app.hxx>
+#include <sfx2/event.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objsh.hxx>
+#include <comphelper/lok.hxx>
+#include <objshimp.hxx>
+#include "shutdownicon.hxx"
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+
+namespace {
+
+class SfxEventAsyncer_Impl : public SfxListener
+{
+ SfxEventHint aHint;
+ std::unique_ptr<Idle> pIdle;
+
+public:
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+ explicit SfxEventAsyncer_Impl(const SfxEventHint& rHint);
+ DECL_LINK( IdleHdl, Timer*, void );
+};
+
+}
+
+void SfxEventAsyncer_Impl::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if( rHint.GetId() == SfxHintId::Dying && pIdle->IsActive() )
+ {
+ pIdle->Stop();
+ delete this;
+ }
+}
+
+
+SfxEventAsyncer_Impl::SfxEventAsyncer_Impl( const SfxEventHint& rHint )
+ : aHint( rHint )
+{
+ if( rHint.GetObjShell() )
+ StartListening( *rHint.GetObjShell() );
+ pIdle.reset( new Idle("sfx::SfxEventAsyncer_Impl pIdle") );
+ pIdle->SetInvokeHandler( LINK(this, SfxEventAsyncer_Impl, IdleHdl) );
+ pIdle->SetPriority( TaskPriority::HIGH_IDLE );
+ pIdle->Start();
+}
+
+
+IMPL_LINK(SfxEventAsyncer_Impl, IdleHdl, Timer*, pAsyncIdle, void)
+{
+ SfxObjectShellRef xRef( aHint.GetObjShell() );
+ pAsyncIdle->Stop();
+ SAL_INFO_IF(!xRef.is(), "sfx.appl", "SfxEvent: " << aHint.GetEventName());
+ SfxGetpApp()->Broadcast( aHint );
+ if ( xRef.is() )
+ xRef->Broadcast( aHint );
+ delete this;
+}
+
+namespace
+{
+template <class Cfg, class Item> bool toSet(SfxItemSet& rSet, TypedWhichId<Item> wid)
+{
+ return rSet.Put(Item(wid, Cfg::get()));
+}
+template <class Cfg, class Item, class Val>
+bool toSet_withDefault(SfxItemSet& rSet, TypedWhichId<Item> wid, Val&& defVal)
+{
+ return rSet.Put(Item(wid, Cfg::get().value_or(std::move(defVal))));
+}
+template <class Cfg, class Item> bool toSet_ifRW(SfxItemSet& rSet, TypedWhichId<Item> wid)
+{
+ return Cfg::isReadOnly() || toSet<Cfg>(rSet, wid);
+}
+
+template <class Cfg, class Item>
+void toCfg_ifSet(const SfxItemSet& rSet, TypedWhichId<Item> wid,
+ std::shared_ptr<comphelper::ConfigurationChanges> const& batch)
+{
+ if (const auto* pItem = rSet.GetItemIfSet(wid))
+ Cfg::set(pItem->GetValue(), batch);
+}
+}
+
+void SfxApplication::GetOptions( SfxItemSet& rSet )
+{
+ SfxWhichIter iter(rSet);
+ for (auto nWhich = iter.FirstWhich(); nWhich; nWhich = iter.NextWhich())
+ {
+ bool bRet = false;
+ switch(nWhich)
+ {
+ case SID_ATTR_BACKUP:
+ bRet = true;
+ if (!officecfg::Office::Common::Save::Document::CreateBackup::isReadOnly())
+ if (!rSet.Put( SfxBoolItem( SID_ATTR_BACKUP,
+ (officecfg::Office::Common::Save::Document::CreateBackup::get() && !comphelper::LibreOfficeKit::isActive()) )))
+ bRet = false;
+ break;
+ case SID_ATTR_BACKUP_BESIDE_ORIGINAL:
+ bRet = toSet_ifRW<officecfg::Office::Common::Save::Document::BackupIntoDocumentFolder>(
+ rSet, SID_ATTR_BACKUP_BESIDE_ORIGINAL);
+ break;
+ case SID_ATTR_PRETTYPRINTING:
+ bRet = toSet_ifRW<officecfg::Office::Common::Save::Document::PrettyPrinting>(
+ rSet, SID_ATTR_PRETTYPRINTING);
+ break;
+ case SID_ATTR_WARNALIENFORMAT:
+ bRet = toSet_ifRW<officecfg::Office::Common::Save::Document::WarnAlienFormat>(
+ rSet, SID_ATTR_WARNALIENFORMAT);
+ break;
+ case SID_ATTR_AUTOSAVE:
+ bRet = toSet_ifRW<officecfg::Office::Recovery::AutoSave::Enabled>(
+ rSet, SID_ATTR_AUTOSAVE);
+ break;
+ case SID_ATTR_AUTOSAVEMINUTE:
+ bRet = toSet_ifRW<officecfg::Office::Recovery::AutoSave::TimeIntervall>(
+ rSet, SID_ATTR_AUTOSAVEMINUTE);
+ break;
+ case SID_ATTR_USERAUTOSAVE:
+ bRet = toSet_ifRW<officecfg::Office::Recovery::AutoSave::UserAutoSaveEnabled>(
+ rSet, SID_ATTR_USERAUTOSAVE);
+ break;
+ case SID_ATTR_DOCINFO:
+ bRet = toSet_ifRW<officecfg::Office::Common::Save::Document::EditProperty>(
+ rSet, SID_ATTR_DOCINFO);
+ break;
+ case SID_ATTR_QUICKLAUNCHER:
+ if ( ShutdownIcon::IsQuickstarterInstalled() )
+ {
+ if ( rSet.Put( SfxBoolItem( SID_ATTR_QUICKLAUNCHER,
+ ShutdownIcon::GetAutostart() ) ) )
+ bRet = true;
+ }
+ else
+ {
+ rSet.DisableItem( SID_ATTR_QUICKLAUNCHER );
+ bRet = true;
+ }
+ break;
+ case SID_SAVEREL_INET:
+ bRet = toSet_ifRW<officecfg::Office::Common::Save::URL::Internet>(
+ rSet, SID_SAVEREL_INET);
+ break;
+ case SID_SAVEREL_FSYS:
+ bRet = toSet_ifRW<officecfg::Office::Common::Save::URL::FileSystem>(
+ rSet, SID_SAVEREL_FSYS);
+ break;
+ case SID_SECURE_URL:
+ bRet = true;
+ if (!SvtSecurityOptions::IsReadOnly(SvtSecurityOptions::EOption::SecureUrls))
+ {
+ std::vector< OUString > seqURLs = SvtSecurityOptions::GetSecureURLs();
+
+ if( !rSet.Put( SfxStringListItem( SID_SECURE_URL, &seqURLs ) ) )
+ bRet = false;
+ }
+ break;
+ case SID_INET_HTTP_PROXY_NAME:
+ bRet = toSet<officecfg::Inet::Settings::ooInetHTTPProxyName>(
+ rSet, SID_INET_HTTP_PROXY_NAME);
+ break;
+ case SID_INET_HTTP_PROXY_PORT:
+ bRet = toSet_withDefault<officecfg::Inet::Settings::ooInetHTTPProxyPort>(
+ rSet, SID_INET_HTTP_PROXY_PORT, 0);
+ break;
+ case SID_INET_NOPROXY:
+ bRet = toSet<officecfg::Inet::Settings::ooInetNoProxy>(rSet, SID_INET_NOPROXY);
+ break;
+
+ default:
+ SAL_INFO( "sfx.appl", "W1:Wrong ID while getting Options!" );
+ break;
+ }
+ SAL_WARN_IF(!bRet, "sfx.appl", "Putting options failed!");
+ }
+}
+
+void SfxApplication::SetOptions(const SfxItemSet &rSet)
+{
+ std::shared_ptr< comphelper::ConfigurationChanges > batch(
+ comphelper::ConfigurationChanges::create());
+
+ // Backup
+ toCfg_ifSet<officecfg::Office::Common::Save::Document::CreateBackup>(
+ rSet, SID_ATTR_BACKUP, batch);
+
+ toCfg_ifSet<officecfg::Office::Common::Save::Document::BackupIntoDocumentFolder>(
+ rSet, SID_ATTR_BACKUP_BESIDE_ORIGINAL, batch);
+
+ // PrettyPrinting
+ toCfg_ifSet<officecfg::Office::Common::Save::Document::PrettyPrinting>(
+ rSet, SID_ATTR_PRETTYPRINTING, batch);
+
+ // WarnAlienFormat
+ toCfg_ifSet<officecfg::Office::Common::Save::Document::WarnAlienFormat>(
+ rSet, SID_ATTR_WARNALIENFORMAT, batch);
+
+ // AutoSave
+ toCfg_ifSet<officecfg::Office::Recovery::AutoSave::Enabled>(rSet, SID_ATTR_AUTOSAVE, batch);
+
+ // AutoSave-Time
+ toCfg_ifSet<officecfg::Office::Recovery::AutoSave::TimeIntervall>(
+ rSet, SID_ATTR_AUTOSAVEMINUTE, batch);
+
+ // UserAutoSave
+ toCfg_ifSet<officecfg::Office::Recovery::AutoSave::UserAutoSaveEnabled>(
+ rSet, SID_ATTR_USERAUTOSAVE, batch);
+
+ // DocInfo
+ toCfg_ifSet<officecfg::Office::Common::Save::Document::EditProperty>(
+ rSet, SID_ATTR_DOCINFO, batch);
+
+ // HelpBalloons
+ toCfg_ifSet<officecfg::Office::Common::Help::ExtendedTip>(rSet, SID_HELPBALLOONS, batch);
+
+ // HelpTips
+ toCfg_ifSet<officecfg::Office::Common::Help::Tip>(rSet, SID_HELPTIPS, batch);
+
+ // SaveRelINet
+ toCfg_ifSet<officecfg::Office::Common::Save::URL::Internet>(rSet, SID_SAVEREL_INET, batch);
+
+ // SaveRelFSys
+ toCfg_ifSet<officecfg::Office::Common::Save::URL::FileSystem>(rSet, SID_SAVEREL_FSYS, batch);
+
+ // Undo-Count
+ if ( const SfxUInt16Item *pItem = rSet.GetItemIfSet(SID_ATTR_UNDO_COUNT))
+ {
+ sal_uInt16 nUndoCount = pItem->GetValue();
+ officecfg::Office::Common::Undo::Steps::set(nUndoCount, batch);
+
+ // To catch all Undo-Managers: Iterate over all Frames
+ for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst();
+ pFrame;
+ pFrame = SfxViewFrame::GetNext(*pFrame) )
+ {
+ // Get the Dispatcher of the Frames
+ SfxDispatcher *pDispat = pFrame->GetDispatcher();
+ pDispat->Flush();
+
+ // Iterate over all SfxShells on the Dispatchers Stack
+ sal_uInt16 nIdx = 0;
+ for ( SfxShell *pSh = pDispat->GetShell(nIdx);
+ pSh;
+ ++nIdx, pSh = pDispat->GetShell(nIdx) )
+ {
+ SfxUndoManager *pShUndoMgr = pSh->GetUndoManager();
+ if ( pShUndoMgr )
+ pShUndoMgr->SetMaxUndoActionCount( nUndoCount );
+ }
+ }
+ }
+
+ // Office autostart
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet(SID_ATTR_QUICKLAUNCHER))
+ {
+ ShutdownIcon::SetAutostart( pItem->GetValue() );
+ }
+
+ toCfg_ifSet<officecfg::Inet::Settings::ooInetProxyType>(rSet, SID_INET_PROXY_TYPE, batch);
+
+ toCfg_ifSet<officecfg::Inet::Settings::ooInetHTTPProxyName>(
+ rSet, SID_INET_HTTP_PROXY_NAME, batch);
+ toCfg_ifSet<officecfg::Inet::Settings::ooInetHTTPProxyPort>(
+ rSet, SID_INET_HTTP_PROXY_PORT, batch);
+ toCfg_ifSet<officecfg::Inet::Settings::ooInetNoProxy>(rSet, SID_INET_NOPROXY, batch);
+
+ // Secure-Referrer
+ if ( const SfxStringListItem *pListItem = rSet.GetItemIfSet(SID_SECURE_URL))
+ {
+ SvtSecurityOptions::SetSecureURLs( std::vector(pListItem->GetList()) );
+ }
+
+ // Store changed data
+ batch->commit();
+}
+
+
+void SfxApplication::NotifyEvent( const SfxEventHint& rEventHint, bool bSynchron )
+{
+ SfxObjectShell *pDoc = rEventHint.GetObjShell();
+ if ( pDoc && ( pDoc->IsPreview() || !pDoc->Get_Impl()->bInitialized ) )
+ return;
+
+ if ( bSynchron )
+ {
+ SAL_INFO_IF(!pDoc, "sfx.appl", "SfxEvent: " << rEventHint.GetEventName());
+ Broadcast(rEventHint);
+ if ( pDoc )
+ pDoc->Broadcast( rEventHint );
+ }
+ else
+ new SfxEventAsyncer_Impl( rEventHint );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appchild.cxx b/sfx2/source/appl/appchild.cxx
new file mode 100644
index 0000000000..246eb44135
--- /dev/null
+++ b/sfx2/source/appl/appchild.cxx
@@ -0,0 +1,66 @@
+/* -*- 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 <sfx2/app.hxx>
+#include <appdata.hxx>
+#include <workwin.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/viewfrm.hxx>
+
+
+void SfxApplication::RegisterChildWindow_Impl( SfxModule *pMod, const SfxChildWinFactory& rFact )
+{
+ if ( pMod )
+ {
+ pMod->RegisterChildWindow( rFact );
+ return;
+ }
+
+ for (size_t nFactory=0; nFactory<pImpl->maFactories.size(); ++nFactory)
+ {
+ if (rFact.nId == pImpl->maFactories[nFactory].nId)
+ {
+ pImpl->maFactories.erase( pImpl->maFactories.begin() + nFactory );
+ }
+ }
+
+ pImpl->maFactories.push_back( rFact );
+}
+
+SfxChildWinFactory* SfxApplication::GetChildWinFactoryById(sal_uInt16 nId) const
+{
+ for (auto& rFactory : pImpl->maFactories)
+ if (rFactory.nId == nId)
+ return &rFactory;
+ return nullptr;
+}
+
+SfxWorkWindow* SfxApplication::GetWorkWindow_Impl(const SfxViewFrame *pFrame) const
+{
+ if ( pFrame )
+ return pFrame->GetFrame().GetWorkWindow_Impl();
+ else if ( pImpl->pViewFrame )
+ return pImpl->pViewFrame->GetFrame().GetWorkWindow_Impl();
+ else
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appdata.cxx b/sfx2/source/appl/appdata.cxx
new file mode 100644
index 0000000000..819d703782
--- /dev/null
+++ b/sfx2/source/appl/appdata.cxx
@@ -0,0 +1,127 @@
+/* -*- 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 <config_features.h>
+
+#include <appdata.hxx>
+#include <sfx2/tbxctrl.hxx>
+#include <sfx2/stbitem.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/doctempl.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/sidebar/Theme.hxx>
+#include <sfx2/objsh.hxx>
+#include <appbaslib.hxx>
+#include <unoctitm.hxx>
+#include <svl/svdde.hxx>
+
+#include <basic/basicmanagerrepository.hxx>
+#include <basic/basmgr.hxx>
+#include <basic/basrdll.hxx>
+
+using ::basic::BasicManagerRepository;
+using ::basic::BasicManagerCreationListener;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::frame::XModel;
+using ::com::sun::star::uno::XInterface;
+
+static BasicDLL* pBasic = nullptr;
+
+class SfxBasicManagerCreationListener : public ::basic::BasicManagerCreationListener
+{
+private:
+ SfxAppData_Impl& m_rAppData;
+
+public:
+ explicit SfxBasicManagerCreationListener(SfxAppData_Impl& _rAppData)
+ : m_rAppData(_rAppData)
+ {
+ }
+
+ virtual ~SfxBasicManagerCreationListener();
+
+ virtual void onBasicManagerCreated( const Reference< XModel >& _rxForDocument, BasicManager& _rBasicManager ) override;
+};
+
+SfxBasicManagerCreationListener::~SfxBasicManagerCreationListener()
+{
+}
+
+void SfxBasicManagerCreationListener::onBasicManagerCreated( const Reference< XModel >& _rxForDocument, BasicManager& _rBasicManager )
+{
+ if ( _rxForDocument == nullptr )
+ m_rAppData.OnApplicationBasicManagerCreated( _rBasicManager );
+}
+
+SfxAppData_Impl::SfxAppData_Impl()
+ : pPool(nullptr)
+ , pProgress(nullptr)
+ , nDocModalMode(0)
+ , nRescheduleLocks(0)
+ , pBasicManager( new SfxBasicManagerHolder )
+ , pBasMgrListener( new SfxBasicManagerCreationListener( *this ) )
+ , pViewFrame( nullptr )
+ , bDowning( true )
+ , bInQuit( false )
+
+{
+ pBasic = new BasicDLL;
+
+#if HAVE_FEATURE_SCRIPTING
+ BasicManagerRepository::registerCreationListener( *pBasMgrListener );
+#endif
+}
+
+SfxAppData_Impl::~SfxAppData_Impl()
+{
+ DeInitDDE();
+ pBasicManager.reset();
+
+#if HAVE_FEATURE_SCRIPTING
+ BasicManagerRepository::revokeCreationListener( *pBasMgrListener );
+ pBasMgrListener.reset();
+#endif
+
+ delete pBasic;
+}
+
+SfxDocumentTemplates* SfxAppData_Impl::GetDocumentTemplates()
+{
+ if ( !pTemplates )
+ pTemplates.emplace();
+ else
+ pTemplates->ReInitFromComponent();
+ return &*pTemplates;
+}
+
+void SfxAppData_Impl::OnApplicationBasicManagerCreated( BasicManager& _rBasicManager )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) _rBasicManager;
+#else
+ pBasicManager->reset( &_rBasicManager );
+
+ // global constants, additionally to the ones already added by createApplicationBasicManager:
+ // ThisComponent
+ Reference< XInterface > xCurrentComponent = SfxObjectShell::GetCurrentComponent();
+ _rBasicManager.SetGlobalUNOConstant( "ThisComponent", css::uno::Any( xCurrentComponent ) );
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appdde.cxx b/sfx2/source/appl/appdde.cxx
new file mode 100644
index 0000000000..2f013cfc63
--- /dev/null
+++ b/sfx2/source/appl/appdde.cxx
@@ -0,0 +1,567 @@
+/* -*- 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 <sal/config.h>
+
+#include <string_view>
+
+#include <config_features.h>
+#include <rtl/character.hxx>
+#include <rtl/malformeduriexception.hxx>
+#include <rtl/uri.hxx>
+#include <sot/exchange.hxx>
+#include <svl/eitem.hxx>
+#include <basic/sbstar.hxx>
+#include <svl/stritem.hxx>
+#include <svl/svdde.hxx>
+#include <sfx2/lnkbase.hxx>
+#include <sfx2/linkmgr.hxx>
+
+#include <tools/debug.hxx>
+#include <tools/urlobj.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <unotools/pathoptions.hxx>
+#include <vcl/svapp.hxx>
+
+#include <sfx2/app.hxx>
+#include <appdata.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/docfile.hxx>
+#include <ucbhelper/content.hxx>
+#include <comphelper/processfactory.hxx>
+
+#if defined(_WIN32)
+
+static OUString SfxDdeServiceName_Impl( const OUString& sIn )
+{
+ OUStringBuffer sReturn(sIn.getLength());
+
+ for ( sal_uInt16 n = sIn.getLength(); n; --n )
+ {
+ sal_Unicode cChar = sIn[n-1];
+ if (rtl::isAsciiAlphanumeric(cChar))
+ sReturn.append(cChar);
+ }
+
+ return sReturn.makeStringAndClear();
+}
+
+namespace {
+
+class ImplDdeService : public DdeService
+{
+public:
+ explicit ImplDdeService( const OUString& rNm )
+ : DdeService( rNm )
+ {}
+ virtual bool MakeTopic( const OUString& );
+
+ virtual OUString Topics();
+
+ virtual bool SysTopicExecute( const OUString* pStr );
+};
+
+ bool lcl_IsDocument( std::u16string_view rContent )
+ {
+ using namespace com::sun::star;
+
+ bool bRet = false;
+ INetURLObject aObj( rContent );
+ DBG_ASSERT( aObj.GetProtocol() != INetProtocol::NotValid, "Invalid URL!" );
+
+ try
+ {
+ ::ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), uno::Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ bRet = aCnt.isDocument();
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "" );
+ }
+
+ return bRet;
+ }
+}
+
+bool ImplDdeService::MakeTopic( const OUString& rNm )
+{
+ // Workaround for Event after Main() under OS/2
+ // happens when exiting starts the App again
+ if ( !Application::IsInExecute() )
+ return false;
+
+ // The Topic rNm is sought, do we have it?
+ // First only loop over the ObjectShells to find those
+ // with the specific name:
+ bool bRet = false;
+ OUString sNm( rNm.toAsciiLowerCase() );
+ SfxObjectShell* pShell = SfxObjectShell::GetFirst();
+ while( pShell )
+ {
+ OUString sTmp( pShell->GetTitle(SFX_TITLE_FULLNAME) );
+ if( sNm == sTmp.toAsciiLowerCase() )
+ {
+ SfxGetpApp()->AddDdeTopic( pShell );
+ bRet = true;
+ break;
+ }
+ pShell = SfxObjectShell::GetNext( *pShell );
+ }
+
+ if( !bRet )
+ {
+ bool abs;
+ OUString url;
+ try {
+ url = rtl::Uri::convertRelToAbs(SvtPathOptions().GetWorkPath(), rNm);
+ abs = true;
+ } catch (rtl::MalformedUriException &) {
+ abs = false;
+ }
+ if ( abs && lcl_IsDocument( url ) )
+ {
+ // File exists? then try to load it:
+ SfxStringItem aName( SID_FILE_NAME, url );
+ SfxBoolItem aNewView(SID_OPEN_NEW_VIEW, true);
+
+ SfxBoolItem aSilent(SID_SILENT, true);
+ const SfxPoolItemHolder aResult(SfxGetpApp()->GetDispatcher_Impl()->ExecuteList(SID_OPENDOC,
+ SfxCallMode::SYNCHRON,
+ { &aName, &aNewView, &aSilent }));
+
+ if( auto const item = dynamic_cast< const SfxViewFrameItem *>(aResult.getItem());
+ item &&
+ item->GetFrame() &&
+ nullptr != ( pShell = item->GetFrame()->GetObjectShell() ) )
+ {
+ SfxGetpApp()->AddDdeTopic( pShell );
+ bRet = true;
+ }
+ }
+ }
+ return bRet;
+}
+
+OUString ImplDdeService::Topics()
+{
+ OUString sRet;
+ if( GetSysTopic() )
+ sRet += GetSysTopic()->GetName();
+
+ SfxObjectShell* pShell = SfxObjectShell::GetFirst();
+ while( pShell )
+ {
+ if( SfxViewFrame::GetFirst( pShell ) )
+ {
+ if( !sRet.isEmpty() )
+ sRet += "\t";
+ sRet += pShell->GetTitle(SFX_TITLE_FULLNAME);
+ }
+ pShell = SfxObjectShell::GetNext( *pShell );
+ }
+ if( !sRet.isEmpty() )
+ sRet += "\r\n";
+ return sRet;
+}
+
+bool ImplDdeService::SysTopicExecute( const OUString* pStr )
+{
+ return SfxApplication::DdeExecute( *pStr );
+}
+#endif
+
+class SfxDdeDocTopic_Impl : public DdeTopic
+{
+#if defined(_WIN32)
+public:
+ SfxObjectShell* pSh;
+ DdeData aData;
+ css::uno::Sequence< sal_Int8 > aSeq;
+
+ explicit SfxDdeDocTopic_Impl( SfxObjectShell* pShell )
+ : DdeTopic( pShell->GetTitle(SFX_TITLE_FULLNAME) ), pSh( pShell )
+ {}
+
+ virtual DdeData* Get( SotClipboardFormatId ) override;
+ virtual bool Put( const DdeData* ) override;
+ virtual bool Execute( const OUString* ) override;
+ virtual bool StartAdviseLoop() override;
+ virtual bool MakeItem( const OUString& rItem ) override;
+#endif
+};
+
+
+#if defined(_WIN32)
+
+namespace {
+
+/* [Description]
+
+ Checks if 'rCmd' of the event 'rEvent' is (without '(') and then assemble
+ this data into a <ApplicationEvent>, which is then executed through
+ <Application::AppEvent()>. If 'rCmd' is the given event 'rEvent', then
+ TRUE is returned, otherwise FALSE.
+
+ [Example]
+
+ rCmd = "Open(\"d:\doc\doc.sdw\")"
+ rEvent = "Open"
+*/
+bool SfxAppEvent_Impl( const OUString& rCmd, std::u16string_view rEvent,
+ ApplicationEvent::Type eType )
+{
+ OUString sEvent(OUString::Concat(rEvent) + "(");
+ if (rCmd.startsWithIgnoreAsciiCase(sEvent))
+ {
+ sal_Int32 start = sEvent.getLength();
+ if ( rCmd.getLength() - start >= 2 )
+ {
+ // Transform into the ApplicationEvent Format
+ //TODO: I /assume/ that rCmd should match the syntax of
+ // <http://msdn.microsoft.com/en-us/library/ms648995.aspx>
+ // "WM_DDE_EXECUTE message" but does not (handle commands enclosed
+ // in [...]; handle commas separating multiple arguments; handle
+ // double "", ((, )), [[, ]] in quoted arguments); see also the mail
+ // thread starting at <http://lists.freedesktop.org/archives/
+ // libreoffice/2013-July/054779.html> "DDE on Windows."
+ std::vector<OUString> aData;
+ for ( sal_Int32 n = start; n < rCmd.getLength() - 1; )
+ {
+ // Resiliently read arguments either starting with " and
+ // spanning to the next " (if any; TODO: do we need to undo any
+ // escaping within the string?) or with neither " nor SPC and
+ // spanning to the next SPC (if any; TODO: is this from not
+ // wrapped in "..." relevant? it would have been parsed by the
+ // original code even if that was only by accident, so I left it
+ // in), with runs of SPCs treated like single ones:
+ switch ( rCmd[n] )
+ {
+ case '"':
+ {
+ sal_Int32 i = rCmd.indexOf('"', ++n);
+ if (i < 0 || i > rCmd.getLength() - 1) {
+ i = rCmd.getLength() - 1;
+ }
+ aData.push_back(rCmd.copy(n, i - n));
+ n = i + 1;
+ break;
+ }
+ case ' ':
+ ++n;
+ break;
+ default:
+ {
+ sal_Int32 i = rCmd.indexOf(' ', n);
+ if (i < 0 || i > rCmd.getLength() - 1) {
+ i = rCmd.getLength() - 1;
+ }
+ aData.push_back(rCmd.copy(n, i - n));
+ n = i + 1;
+ break;
+ }
+ }
+ }
+
+ GetpApp()->AppEvent( ApplicationEvent(eType, std::move(aData)) );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
+
+/* Description]
+
+ This method can be overridden by application developers, to receive
+ DDE-commands directed to their SfxApplication subclass.
+
+ The base implementation understands the API functionality of the
+ relevant SfxApplication subclass in BASIC syntax. Return values can
+ not be transferred, unfortunately.
+*/
+bool SfxApplication::DdeExecute( const OUString& rCmd ) // Expressed in our BASIC-Syntax
+{
+ // Print or Open-Event?
+ if ( !( SfxAppEvent_Impl( rCmd, u"Print", ApplicationEvent::Type::Print ) ||
+ SfxAppEvent_Impl( rCmd, u"Open", ApplicationEvent::Type::Open ) ) )
+ {
+ // all others are BASIC
+ StarBASIC* pBasic = GetBasic();
+ DBG_ASSERT( pBasic, "Where is the Basic???" );
+ SbxVariable* pRet = pBasic->Execute( rCmd );
+ if( !pRet )
+ {
+ SbxBase::ResetError();
+ return false;
+ }
+ }
+ return true;
+}
+
+/* [Description]
+
+ This method can be overridden by application developers, to receive
+ DDE-commands directed to the their SfxApplication subclass.
+
+ The base implementation does nothing and returns 0.
+*/
+bool SfxObjectShell::DdeExecute( const OUString& rCmd ) // Expressed in our BASIC-Syntax
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) rCmd;
+#else
+ StarBASIC* pBasic = GetBasic();
+ DBG_ASSERT( pBasic, "Where is the Basic???" ) ;
+ SbxVariable* pRet = pBasic->Execute( rCmd );
+ if( !pRet )
+ {
+ SbxBase::ResetError();
+ return false;
+ }
+#endif
+ return true;
+}
+
+/* [Description]
+
+ This method can be overridden by application developers, to receive
+ DDE-data-requests directed to their SfxApplication subclass.
+
+ The base implementation provides no data and returns false.
+*/
+bool SfxObjectShell::DdeGetData( const OUString&, // the Item to be addressed
+ const OUString&, // in: Format
+ css::uno::Any& )// out: requested data
+{
+ return false;
+}
+
+
+/* [Description]
+
+ This method can be overridden by application developers, to receive
+ DDE-data directed to their SfxApplication subclass.
+
+ The base implementation is not receiving any data and returns false.
+*/
+bool SfxObjectShell::DdeSetData( const OUString&, // the Item to be addressed
+ const OUString&, // in: Format
+ const css::uno::Any& )// out: requested data
+{
+ return false;
+}
+
+#endif
+
+/* [Description]
+
+ This method can be overridden by application developers, to establish
+ a DDE-hotlink to their SfxApplication subclass.
+
+ The base implementation is not generate a link and returns 0.
+*/
+::sfx2::SvLinkSource* SfxObjectShell::DdeCreateLinkSource( const OUString& ) // the Item to be addressed
+{
+ return nullptr;
+}
+
+void SfxObjectShell::ReconnectDdeLink(SfxObjectShell& /*rServer*/)
+{
+}
+
+void SfxObjectShell::ReconnectDdeLinks(SfxObjectShell& rServer)
+{
+ SfxObjectShell* p = GetFirst(nullptr, false);
+ while (p)
+ {
+ if (&rServer != p)
+ p->ReconnectDdeLink(rServer);
+
+ p = GetNext(*p, nullptr, false);
+ }
+}
+
+bool SfxApplication::InitializeDde()
+{
+ int nError = 0;
+#if defined(_WIN32)
+ DBG_ASSERT( !pImpl->pDdeService,
+ "Dde can not be initialized multiple times" );
+
+ pImpl->pDdeService.reset(new ImplDdeService( Application::GetAppName() ));
+ nError = pImpl->pDdeService->GetError();
+ if( !nError )
+ {
+ // we certainly want to support RTF!
+ pImpl->pDdeService->AddFormat( SotClipboardFormatId::RTF );
+ pImpl->pDdeService->AddFormat( SotClipboardFormatId::RICHTEXT );
+
+ // Config path as a topic because of multiple starts
+ INetURLObject aOfficeLockFile( SvtPathOptions().GetUserConfigPath() );
+ aOfficeLockFile.insertName( u"soffice.lck" );
+ OUString aService( SfxDdeServiceName_Impl(
+ aOfficeLockFile.GetMainURL(INetURLObject::DecodeMechanism::ToIUri) ) );
+ aService = aService.toAsciiUpperCase();
+ pImpl->pDdeService2.reset( new ImplDdeService( aService ));
+ pImpl->pTriggerTopic.reset(new SfxDdeTriggerTopic_Impl);
+ pImpl->pDdeService2->AddTopic( *pImpl->pTriggerTopic );
+ }
+#endif
+ return !nError;
+}
+
+void SfxAppData_Impl::DeInitDDE()
+{
+ pTriggerTopic.reset();
+ pDdeService2.reset();
+ maDocTopics.clear();
+ pDdeService.reset();
+}
+
+#if defined(_WIN32)
+void SfxApplication::AddDdeTopic( SfxObjectShell* pSh )
+{
+ //OV: DDE is disconnected in server mode!
+ if( pImpl->maDocTopics.empty() )
+ return;
+
+ // prevent double submit
+ OUString sShellNm;
+ bool bFnd = false;
+ for (size_t n = pImpl->maDocTopics.size(); n;)
+ {
+ if( pImpl->maDocTopics[ --n ]->pSh == pSh )
+ {
+ // If the document is untitled, is still a new Topic is created!
+ if( !bFnd )
+ {
+ bFnd = true;
+ sShellNm = pSh->GetTitle(SFX_TITLE_FULLNAME).toAsciiLowerCase();
+ }
+ OUString sNm( pImpl->maDocTopics[ n ]->GetName() );
+ if( sShellNm == sNm.toAsciiLowerCase() )
+ return ;
+ }
+ }
+
+ SfxDdeDocTopic_Impl *const pTopic = new SfxDdeDocTopic_Impl(pSh);
+ pImpl->maDocTopics.push_back(pTopic);
+ pImpl->pDdeService->AddTopic( *pTopic );
+}
+#endif
+
+void SfxApplication::RemoveDdeTopic( SfxObjectShell const * pSh )
+{
+#if defined(_WIN32)
+ //OV: DDE is disconnected in server mode!
+ if( pImpl->maDocTopics.empty() )
+ return;
+
+ for (size_t n = pImpl->maDocTopics.size(); n; )
+ {
+ SfxDdeDocTopic_Impl *const pTopic = pImpl->maDocTopics[ --n ];
+ if (pTopic->pSh == pSh)
+ {
+ pImpl->pDdeService->RemoveTopic( *pTopic );
+ delete pTopic;
+ pImpl->maDocTopics.erase( pImpl->maDocTopics.begin() + n );
+ }
+ }
+#else
+ (void) pSh;
+#endif
+}
+
+const DdeService* SfxApplication::GetDdeService() const
+{
+ return pImpl->pDdeService.get();
+}
+
+DdeService* SfxApplication::GetDdeService()
+{
+ return pImpl->pDdeService.get();
+}
+
+#if defined(_WIN32)
+
+DdeData* SfxDdeDocTopic_Impl::Get(SotClipboardFormatId nFormat)
+{
+ OUString sMimeType( SotExchange::GetFormatMimeType( nFormat ));
+ css::uno::Any aValue;
+ bool bRet = pSh->DdeGetData( GetCurItem(), sMimeType, aValue );
+ if( bRet && aValue.hasValue() && ( aValue >>= aSeq ) )
+ {
+ aData = DdeData( aSeq.getConstArray(), aSeq.getLength(), nFormat );
+ return &aData;
+ }
+ aSeq.realloc( 0 );
+ return nullptr;
+}
+
+bool SfxDdeDocTopic_Impl::Put( const DdeData* pData )
+{
+ aSeq = css::uno::Sequence< sal_Int8 >(
+ static_cast<sal_Int8 const *>(pData->getData()), pData->getSize() );
+ bool bRet;
+ if( aSeq.getLength() )
+ {
+ css::uno::Any aValue;
+ aValue <<= aSeq;
+ OUString sMimeType( SotExchange::GetFormatMimeType( pData->GetFormat() ));
+ bRet = pSh->DdeSetData( GetCurItem(), sMimeType, aValue );
+ }
+ else
+ bRet = false;
+ return bRet;
+}
+
+bool SfxDdeDocTopic_Impl::Execute( const OUString* pStr )
+{
+ return pStr && pSh->DdeExecute( *pStr );
+}
+
+bool SfxDdeDocTopic_Impl::MakeItem( const OUString& rItem )
+{
+ AddItem( DdeItem( rItem ) );
+ return true;
+}
+
+bool SfxDdeDocTopic_Impl::StartAdviseLoop()
+{
+ bool bRet = false;
+ ::sfx2::SvLinkSource* pNewObj = pSh->DdeCreateLinkSource( GetCurItem() );
+ if( pNewObj )
+ {
+ // then we also establish a corresponding SvBaseLink
+ OUString sNm, sTmp( Application::GetAppName() );
+ ::sfx2::MakeLnkName( sNm, &sTmp, pSh->GetTitle(SFX_TITLE_FULLNAME), GetCurItem() );
+ new ::sfx2::SvBaseLink( sNm, sfx2::SvBaseLinkObjectType::DdeExternal, pNewObj );
+ bRet = true;
+ }
+ return bRet;
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appdispatchprovider.cxx b/sfx2/source/appl/appdispatchprovider.cxx
new file mode 100644
index 0000000000..363aa391d5
--- /dev/null
+++ b/sfx2/source/appl/appdispatchprovider.cxx
@@ -0,0 +1,231 @@
+/* -*- 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 <sal/config.h>
+
+#include <com/sun/star/frame/XAppDispatchProvider.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/DispatchDescriptor.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/util/URL.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/msgpool.hxx>
+#include <sfx2/sfxbasecontroller.hxx>
+#include <unoctitm.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+class SfxAppDispatchProvider : public ::cppu::WeakImplHelper< css::frame::XAppDispatchProvider,
+ css::lang::XServiceInfo,
+ css::lang::XInitialization >
+{
+ css::uno::WeakReference < css::frame::XFrame > m_xFrame;
+public:
+ SfxAppDispatchProvider() {}
+
+ virtual void SAL_CALL initialize(
+ css::uno::Sequence<css::uno::Any> const & aArguments) override;
+
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
+
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ virtual css::uno::Reference < css::frame::XDispatch > SAL_CALL queryDispatch(
+ const css::util::URL& aURL, const OUString& sTargetFrameName,
+ sal_Int32 eSearchFlags ) override;
+
+ virtual css::uno::Sequence< css::uno::Reference < css::frame::XDispatch > > SAL_CALL queryDispatches(
+ const css::uno::Sequence < css::frame::DispatchDescriptor >& seqDescriptor ) override;
+
+ virtual css::uno::Sequence< sal_Int16 > SAL_CALL getSupportedCommandGroups() override;
+
+ virtual css::uno::Sequence< css::frame::DispatchInformation > SAL_CALL getConfigurableDispatchInformation( sal_Int16 ) override;
+};
+
+void SfxAppDispatchProvider::initialize(
+ css::uno::Sequence<css::uno::Any> const & aArguments)
+{
+ css::uno::Reference<css::frame::XFrame> f;
+ if (aArguments.getLength() != 1 || !(aArguments[0] >>= f)) {
+ throw css::lang::IllegalArgumentException(
+ "SfxAppDispatchProvider::initialize expects one XFrame argument",
+ getXWeak(), 0);
+ }
+ m_xFrame = f;
+}
+
+OUString SAL_CALL SfxAppDispatchProvider::getImplementationName()
+{
+ return "com.sun.star.comp.sfx2.AppDispatchProvider";
+}
+
+sal_Bool SAL_CALL SfxAppDispatchProvider::supportsService( const OUString& sServiceName )
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL SfxAppDispatchProvider::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ProtocolHandler", "com.sun.star.frame.AppDispatchProvider" };
+}
+
+Reference < XDispatch > SAL_CALL SfxAppDispatchProvider::queryDispatch(
+ const util::URL& aURL,
+ const OUString& /*sTargetFrameName*/,
+ sal_Int32 /*eSearchFlags*/ )
+{
+ SolarMutexGuard guard;
+
+ bool bMasterCommand( false );
+ Reference < XDispatch > xDisp;
+ const SfxSlot* pSlot = nullptr;
+ SfxApplication* pApp = SfxGetpApp();
+ if ( !pApp )
+ return xDisp;
+ SfxDispatcher* pAppDisp = pApp->GetAppDispatcher_Impl();
+ if ( aURL.Protocol == "slot:" || aURL.Protocol == "commandId:" )
+ {
+ sal_uInt16 nId = static_cast<sal_uInt16>(aURL.Path.toInt32());
+ SfxShell* pShell;
+ pAppDisp->GetShellAndSlot_Impl( nId, &pShell, &pSlot, true, true );
+ }
+ else if ( aURL.Protocol == ".uno:" )
+ {
+ // Support ".uno" commands. Map commands to slotid
+ bMasterCommand = SfxOfficeDispatch::IsMasterUnoCommand( aURL );
+ if ( bMasterCommand )
+ pSlot = pAppDisp->GetSlot( SfxOfficeDispatch::GetMasterUnoCommand( aURL ) );
+ else
+ pSlot = pAppDisp->GetSlot( aURL.Main );
+ }
+
+ if ( pSlot )
+ {
+ rtl::Reference<SfxOfficeDispatch> pDispatch = new SfxOfficeDispatch( pAppDisp, pSlot, aURL ) ;
+ pDispatch->SetFrame(m_xFrame);
+ pDispatch->SetMasterUnoCommand( bMasterCommand );
+ xDisp = pDispatch;
+ }
+
+ return xDisp;
+}
+
+Sequence< Reference < XDispatch > > SAL_CALL SfxAppDispatchProvider::queryDispatches( const Sequence < DispatchDescriptor >& seqDescriptor )
+{
+ sal_Int32 nCount = seqDescriptor.getLength();
+ uno::Sequence< uno::Reference < frame::XDispatch > > lDispatcher(nCount);
+ std::transform(seqDescriptor.begin(), seqDescriptor.end(), lDispatcher.getArray(),
+ [this](const DispatchDescriptor& rDescr) -> uno::Reference<frame::XDispatch> {
+ return queryDispatch(rDescr.FeatureURL, rDescr.FrameName, rDescr.SearchFlags); });
+ return lDispatcher;
+}
+
+Sequence< sal_Int16 > SAL_CALL SfxAppDispatchProvider::getSupportedCommandGroups()
+{
+ SolarMutexGuard aGuard;
+
+ std::vector< sal_Int16 > aGroupList;
+ SfxSlotPool& rAppSlotPool = SfxGetpApp()->GetAppSlotPool_Impl();
+
+ const SfxSlotMode nMode( SfxSlotMode::TOOLBOXCONFIG|SfxSlotMode::ACCELCONFIG|SfxSlotMode::MENUCONFIG );
+
+ // Select group ( group 0 is internal )
+ for (sal_uInt16 i=0; i< rAppSlotPool.GetGroupCount(); ++i)
+ {
+ rAppSlotPool.SeekGroup(i);
+ const SfxSlot* pSfxSlot = rAppSlotPool.FirstSlot();
+ while ( pSfxSlot )
+ {
+ if ( pSfxSlot->GetMode() & nMode )
+ {
+ sal_Int16 nCommandGroup = MapGroupIDToCommandGroup( pSfxSlot->GetGroupId() );
+ aGroupList.push_back( nCommandGroup );
+ break;
+ }
+ pSfxSlot = rAppSlotPool.NextSlot();
+ }
+ }
+
+ return comphelper::containerToSequence( aGroupList );
+}
+
+Sequence< frame::DispatchInformation > SAL_CALL SfxAppDispatchProvider::getConfigurableDispatchInformation( sal_Int16 nCmdGroup )
+{
+ std::vector< frame::DispatchInformation > aCmdVector;
+
+ SolarMutexGuard aGuard;
+ SfxSlotPool& rAppSlotPool = SfxGetpApp()->GetAppSlotPool_Impl();
+
+ const SfxSlotMode nMode( SfxSlotMode::TOOLBOXCONFIG|SfxSlotMode::ACCELCONFIG|SfxSlotMode::MENUCONFIG );
+
+ // Select group ( group 0 is internal )
+ for (sal_uInt16 i=0; i< rAppSlotPool.GetGroupCount(); ++i)
+ {
+ rAppSlotPool.SeekGroup(i);
+ const SfxSlot* pSfxSlot = rAppSlotPool.FirstSlot();
+ if ( pSfxSlot )
+ {
+ sal_Int16 nCommandGroup = MapGroupIDToCommandGroup( pSfxSlot->GetGroupId() );
+ if ( nCommandGroup == nCmdGroup )
+ {
+ while ( pSfxSlot )
+ {
+ if ( pSfxSlot->GetMode() & nMode )
+ {
+ frame::DispatchInformation aCmdInfo;
+ aCmdInfo.Command = pSfxSlot->GetCommand();
+ aCmdInfo.GroupId = nCommandGroup;
+ aCmdVector.push_back( aCmdInfo );
+ }
+ pSfxSlot = rAppSlotPool.NextSlot();
+ }
+ }
+ }
+ }
+
+ return comphelper::containerToSequence( aCmdVector );
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_sfx2_AppDispatchProvider_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SfxAppDispatchProvider);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appinit.cxx b/sfx2/source/appl/appinit.cxx
new file mode 100644
index 0000000000..52afe118ec
--- /dev/null
+++ b/sfx2/source/appl/appinit.cxx
@@ -0,0 +1,233 @@
+/* -*- 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 <config_features.h>
+
+#include <sfx2/app.hxx>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <basic/sbdef.hxx>
+#include <tools/svlibrary.h>
+#include <svtools/soerr.hxx>
+#include <unotools/configmgr.hxx>
+#include <svtools/ehdl.hxx>
+#include <comphelper/processfactory.hxx>
+#include <osl/module.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <vcl/specialchars.hxx>
+#include <vcl/help.hxx>
+#include <vcl/svapp.hxx>
+
+#include <unoctitm.hxx>
+#include <appdata.hxx>
+#include <sfx2/dispatch.hxx>
+#include <nochaos.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star;
+
+namespace {
+
+class SfxTerminateListener_Impl : public ::cppu::WeakImplHelper< XTerminateListener, XServiceInfo >
+{
+public:
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const EventObject& aEvent ) override;
+ virtual void SAL_CALL notifyTermination( const EventObject& aEvent ) override;
+ virtual void SAL_CALL disposing( const EventObject& Source ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& sServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+}
+
+void SAL_CALL SfxTerminateListener_Impl::disposing( const EventObject& )
+{
+}
+
+void SAL_CALL SfxTerminateListener_Impl::queryTermination( const EventObject& )
+{
+}
+
+void SAL_CALL SfxTerminateListener_Impl::notifyTermination( const EventObject& aEvent )
+{
+ Reference< XDesktop > xDesktop( aEvent.Source, UNO_QUERY );
+ if( xDesktop.is() )
+ xDesktop->removeTerminateListener( this );
+
+ SolarMutexGuard aGuard;
+ utl::ConfigManager::storeConfigItems();
+
+ SfxApplication* pApp = SfxGetpApp();
+ pApp->Broadcast( SfxHint( SfxHintId::Deinitializing ) );
+ pApp->Get_Impl()->mxAppDispatch->ReleaseAll();
+ pApp->Get_Impl()->mxAppDispatch.clear();
+
+ css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ css::uno::Reference< css::document::XDocumentEventListener > xGlobalBroadcaster(css::frame::theGlobalEventBroadcaster::get(xContext), css::uno::UNO_QUERY_THROW);
+
+ css::document::DocumentEvent aEvent2;
+ aEvent2.EventName = "OnCloseApp";
+ xGlobalBroadcaster->documentEventOccured(aEvent2);
+
+ delete pApp;
+ Application::Quit();
+}
+
+OUString SAL_CALL SfxTerminateListener_Impl::getImplementationName()
+{
+ return "com.sun.star.comp.sfx2.SfxTerminateListener";
+}
+
+sal_Bool SAL_CALL SfxTerminateListener_Impl::supportsService( const OUString& sServiceName )
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+Sequence< OUString > SAL_CALL SfxTerminateListener_Impl::getSupportedServiceNames()
+{
+ // Note: That service does not really exists .-)
+ // But this implementation is not thought to be registered really within our service.rdb.
+ // At least we need the implementation name only to identify these service at the global desktop instance.
+ // The desktop must know, which listener will terminate the SfxApplication in real !
+ // It must call this special listener as last one ... otherwise we shutdown the SfxApplication BEFORE other listener
+ // can react ...
+ return { "com.sun.star.frame.TerminateListener" };
+}
+
+
+typedef bool (*PFunc_getSpecialCharsForEdit)(weld::Widget* i_pParent, const vcl::Font& i_rFont, OUString& o_rOutString);
+
+
+// Lazy binding of the GetSpecialCharsForEdit function as it resides in
+// a library above us.
+
+
+#ifndef DISABLE_DYNLOADING
+
+extern "C" { static void thisModule() {} }
+
+#else
+
+extern "C" bool GetSpecialCharsForEdit(weld::Widget* i_pParent, const vcl::Font& i_rFont, OUString& o_rOutString);
+
+#endif
+
+static OUString SfxGetSpecialCharsForEdit(weld::Widget* pParent, const vcl::Font& rFont)
+{
+ static const PFunc_getSpecialCharsForEdit pfunc_getSpecialCharsForEdit = [] {
+ PFunc_getSpecialCharsForEdit pfunc = nullptr;
+#ifndef DISABLE_DYNLOADING
+ osl::Module aMod;
+ aMod.loadRelative(&thisModule, SVLIBRARY("cui"));
+
+ // get symbol
+ pfunc = reinterpret_cast<PFunc_getSpecialCharsForEdit>(aMod.getFunctionSymbol("GetSpecialCharsForEdit"));
+ DBG_ASSERT( pfunc, "GetSpecialCharsForEdit() not found!" );
+ aMod.release();
+#else
+ pfunc = GetSpecialCharsForEdit;
+#endif
+ return pfunc;
+ }();
+
+ OUString aRet;
+ if ( pfunc_getSpecialCharsForEdit )
+ {
+ SolarMutexGuard aGuard;
+ (*pfunc_getSpecialCharsForEdit)( pParent, rFont, aRet );
+ }
+ return aRet;
+}
+
+
+void SfxApplication::Initialize_Impl()
+{
+#ifdef TLX_VALIDATE
+ StgIo::SetErrorLink( LINK( this, SfxStorageErrHdl, Error ) );
+#endif
+
+ Reference < XDesktop2 > xDesktop = Desktop::create ( ::comphelper::getProcessComponentContext() );
+ xDesktop->addTerminateListener( new SfxTerminateListener_Impl );
+
+ pImpl->mxAppDispatch = new SfxStatusDispatcher;
+
+ // SV-Look
+ Help::EnableContextHelp();
+ Help::EnableExtHelp();
+
+ pImpl->m_pToolsErrorHdl.emplace(
+ RID_ERRHDL, ErrCodeArea::Io, ErrCodeArea::Vcl);
+
+ pImpl->m_pSoErrorHdl.emplace(
+ RID_SO_ERROR_HANDLER, ErrCodeArea::So, ErrCodeArea::So, SvtResLocale());
+#if HAVE_FEATURE_SCRIPTING
+ pImpl->m_pSbxErrorHdl.emplace(
+ RID_BASIC_START, ErrCodeArea::Sbx, ErrCodeArea::Sbx, BasResLocale());
+#endif
+
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ SolarMutexGuard aGuard;
+ //ensure instantiation of listener that manages the internal recently-used
+ //list
+ pImpl->mxAppPickList.emplace(*this);
+ }
+
+ DBG_ASSERT( !pImpl->pAppDispat, "AppDispatcher already exists" );
+ pImpl->pAppDispat.emplace();
+ pImpl->pSlotPool.emplace();
+
+ Registrations_Impl();
+
+ // initialize the subclass
+ pImpl->bDowning = false;
+
+ // get CHAOS item pool...
+ pImpl->pPool = NoChaos::GetItemPool();
+ SetPool( pImpl->pPool );
+
+ if ( pImpl->bDowning )
+ return;
+
+ // build the app dispatcher
+ pImpl->pAppDispat->Push(*this);
+ pImpl->pAppDispat->Flush();
+ pImpl->pAppDispat->DoActivate_Impl( true );
+
+ {
+ SolarMutexGuard aGuard;
+ // Set special characters callback on vcl edit control
+ vcl::SetGetSpecialCharsFunction(&SfxGetSpecialCharsForEdit);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appmain.cxx b/sfx2/source/appl/appmain.cxx
new file mode 100644
index 0000000000..5f24bbc8aa
--- /dev/null
+++ b/sfx2/source/appl/appmain.cxx
@@ -0,0 +1,38 @@
+/* -*- 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 <svl/urihelper.hxx>
+
+#include <appdata.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/fcontnr.hxx>
+
+
+SfxFilterMatcher& SfxApplication::GetFilterMatcher()
+{
+ if( !pImpl->pMatcher )
+ {
+ pImpl->pMatcher.emplace();
+ URIHelper::SetMaybeFileHdl( LINK(
+ &*pImpl->pMatcher, SfxFilterMatcher, MaybeFileHdl_Impl ) );
+ }
+ return *pImpl->pMatcher;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appmisc.cxx b/sfx2/source/appl/appmisc.cxx
new file mode 100644
index 0000000000..948a1de40f
--- /dev/null
+++ b/sfx2/source/appl/appmisc.cxx
@@ -0,0 +1,211 @@
+/* -*- 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 <config_folders.h>
+#include <ucbhelper/content.hxx>
+
+#include <vcl/canvastools.hxx>
+#include <vcl/vectorgraphicdata.hxx>
+#include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/graphic/Primitive2DTools.hpp>
+#include <com/sun/star/uno/Reference.h>
+#include <unotools/configmgr.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/processfactory.hxx>
+#include <osl/diagnose.h>
+#include <rtl/bootstrap.hxx>
+#include <svl/stritem.hxx>
+#include <tools/urlobj.hxx>
+
+#include <sfx2/app.hxx>
+#include <appdata.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/msgpool.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/objface.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+
+#define ShellClass_SfxApplication
+#include <sfxslots.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+
+SFX_IMPL_INTERFACE(SfxApplication,SfxShell)
+
+void SfxApplication::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterStatusBar(StatusBarId::GenericStatusBar);
+
+ GetStaticInterface()->RegisterChildWindow(SID_DOCKWIN_0);
+ GetStaticInterface()->RegisterChildWindow(SID_DOCKWIN_1);
+ GetStaticInterface()->RegisterChildWindow(SID_DOCKWIN_2);
+ GetStaticInterface()->RegisterChildWindow(SID_DOCKWIN_3);
+ GetStaticInterface()->RegisterChildWindow(SID_DOCKWIN_4);
+ GetStaticInterface()->RegisterChildWindow(SID_DOCKWIN_5);
+ GetStaticInterface()->RegisterChildWindow(SID_DOCKWIN_6);
+ GetStaticInterface()->RegisterChildWindow(SID_DOCKWIN_7);
+ GetStaticInterface()->RegisterChildWindow(SID_DOCKWIN_8);
+ GetStaticInterface()->RegisterChildWindow(SID_DOCKWIN_9);
+}
+
+/** Returns the running SfxProgress for the entire application or 0 if
+ none is running for the entire application.
+
+ [Cross-reference]
+
+ <SfxProgress::GetActiveProgress(SfxViewFrame*)>
+ <SfxViewFrame::GetProgress()const>
+*/
+SfxProgress* SfxApplication::GetProgress() const
+{
+ return pImpl->pProgress;
+}
+
+SfxModule* SfxApplication::GetModule_Impl()
+{
+ SfxModule* pModule = SfxModule::GetActiveModule();
+ if ( !pModule )
+ pModule = SfxModule::GetActiveModule( SfxViewFrame::GetFirst( nullptr, false ) );
+ if( pModule )
+ return pModule;
+ else
+ {
+ OSL_FAIL( "No module!" );
+ return nullptr;
+ }
+}
+
+bool SfxApplication::IsDowning() const { return pImpl->bDowning; }
+SfxDispatcher* SfxApplication::GetAppDispatcher_Impl() { return &*pImpl->pAppDispat; }
+SfxSlotPool& SfxApplication::GetAppSlotPool_Impl() const { return *pImpl->pSlotPool; }
+
+static bool FileExists( const INetURLObject& rURL )
+{
+ bool bRet = false;
+
+ if( rURL.GetProtocol() != INetProtocol::NotValid )
+ {
+ try
+ {
+ ::ucbhelper::Content aCnt( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), uno::Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ OUString aTitle;
+
+ aCnt.getPropertyValue("Title") >>= aTitle;
+ bRet = ( !aTitle.isEmpty() );
+ }
+ catch(const Exception&)
+ {
+ return false;
+ }
+ }
+
+ return bRet;
+}
+
+bool SfxApplication::loadBrandSvg(const char *pName, BitmapEx &rBitmap, int nWidth)
+{
+ // Load from disk
+
+ OUString aBaseName = "/" + OUString::createFromAscii( pName );
+
+ OUString uri = "$BRAND_BASE_DIR/" LIBO_ETC_FOLDER + aBaseName + ".svg";
+ rtl::Bootstrap::expandMacros( uri );
+
+ INetURLObject aObj( uri );
+ if ( !FileExists(aObj) )
+ return false;
+
+ VectorGraphicData aVectorGraphicData(aObj.PathToFileName(), VectorGraphicDataType::Svg);
+
+ // transform into [0,0,width,width*aspect] std dimensions
+
+ basegfx::B2DRange aRange(aVectorGraphicData.getRange());
+ const double fAspectRatio(
+ aRange.getHeight() == 0.0 ? 1.0 : aRange.getWidth()/aRange.getHeight());
+ basegfx::B2DHomMatrix aTransform(
+ basegfx::utils::createTranslateB2DHomMatrix(
+ -aRange.getMinX(),
+ -aRange.getMinY()));
+ aTransform.scale(
+ aRange.getWidth() == 0.0 ? 1.0 : nWidth / aRange.getWidth(),
+ (aRange.getHeight() == 0.0
+ ? 1.0 : nWidth / fAspectRatio / aRange.getHeight()));
+ const drawinglayer::primitive2d::Primitive2DReference xTransformRef(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aTransform,
+ drawinglayer::primitive2d::Primitive2DContainer(aVectorGraphicData.getPrimitive2DSequence())));
+
+ // UNO dance to render from drawinglayer
+
+ uno::Reference< uno::XComponentContext > xContext(::comphelper::getProcessComponentContext());
+
+ try
+ {
+ const uno::Reference< graphic::XPrimitive2DRenderer > xPrimitive2DRenderer =
+ graphic::Primitive2DTools::create( xContext );
+
+ // cancel out rasterize's mm2pixel conversion
+ // see fFactor100th_mmToInch in
+ // drawinglayer/source/drawinglayeruno/xprimitive2drenderer.cxx
+ const double fFakeDPI=2.54 * 1000.0;
+
+ geometry::RealRectangle2D aRealRect(
+ 0, 0,
+ nWidth, nWidth / fAspectRatio);
+
+ const uno::Reference< rendering::XBitmap > xBitmap(
+ xPrimitive2DRenderer->rasterize(
+ drawinglayer::primitive2d::Primitive2DContainer{xTransformRef}.toSequence(),
+ uno::Sequence< beans::PropertyValue >(),
+ fFakeDPI,
+ fFakeDPI,
+ aRealRect,
+ 500000));
+
+ if(xBitmap.is())
+ {
+ const uno::Reference< rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap, uno::UNO_QUERY_THROW);
+ rBitmap = vcl::unotools::bitmapExFromXBitmap(xIntBmp);
+ return true;
+ }
+ }
+ catch(const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("sfx.appl", "Got no graphic::XPrimitive2DRenderer (!)" );
+ }
+ return false;
+}
+
+/** loads the application logo as used in the impress slideshow pause screen */
+BitmapEx SfxApplication::GetApplicationLogo(tools::Long nWidth)
+{
+ BitmapEx aBitmap;
+ SfxApplication::loadBrandSvg("shell/about", aBitmap, nWidth);
+ return aBitmap;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appopen.cxx b/sfx2/source/appl/appopen.cxx
new file mode 100644
index 0000000000..4e1b06e522
--- /dev/null
+++ b/sfx2/source/appl/appopen.cxx
@@ -0,0 +1,1154 @@
+/* -*- 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 <com/sun/star/uno/Reference.h>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/system/SystemShellExecuteException.hpp>
+#include <com/sun/star/document/XTypeDetection.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/document/UpdateDocMode.hpp>
+#include <com/sun/star/task/ErrorCodeRequest.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/packages/WrongPasswordException.hpp>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <rtl/ustring.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/synchronousdispatch.hxx>
+
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/eitem.hxx>
+#include <sfx2/doctempl.hxx>
+#include <svtools/sfxecode.hxx>
+#include <preventduplicateinteraction.hxx>
+#include <svtools/ehdl.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/securityoptions.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <unotools/extendedsecurityoptions.hxx>
+#include <comphelper/docpasswordhelper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <sfx2/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <sfx2/objitem.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/slstitm.hxx>
+#include <appopen.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxresid.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/strings.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/sfxuno.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/templatedlg.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <o3tl/string_view.hxx>
+#include <openuriexternally.hxx>
+
+#include <officecfg/Office/ProtocolHandler.hxx>
+#include <officecfg/Office/Security.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::container;
+using namespace ::cppu;
+using namespace ::sfx2;
+
+void SetTemplate_Impl( std::u16string_view rFileName,
+ const OUString &rLongName,
+ SfxObjectShell *pDoc)
+{
+ // write TemplateName to DocumentProperties of document
+ // TemplateDate stays as default (=current date)
+ pDoc->ResetFromTemplate( rLongName, rFileName );
+}
+
+namespace {
+
+class SfxDocPasswordVerifier : public ::comphelper::IDocPasswordVerifier
+{
+public:
+ explicit SfxDocPasswordVerifier(SfxMedium& rMedium)
+ : m_rMedium(rMedium)
+ , mxStorage(rMedium.GetStorage())
+ {
+ }
+
+ virtual ::comphelper::DocPasswordVerifierResult
+ verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData ) override;
+ virtual ::comphelper::DocPasswordVerifierResult
+ verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData ) override;
+
+private:
+ SfxMedium & m_rMedium;
+ Reference< embed::XStorage > mxStorage;
+};
+
+}
+
+::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
+{
+ o_rEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( rPassword );
+ return verifyEncryptionData( o_rEncryptionData );
+}
+
+
+::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
+{
+ ::comphelper::DocPasswordVerifierResult eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword;
+ try
+ {
+ // check the encryption data
+ // if the data correct is the stream will be opened successfully
+ // and immediately closed
+ ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( mxStorage, rEncryptionData );
+
+ // for new ODF encryption, try to extract the encrypted inner package
+ // (it will become the SfxObjectShell storage)
+ if (!m_rMedium.TryEncryptedInnerPackage(mxStorage))
+ { // ... old ODF encryption:
+ mxStorage->openStreamElement(
+ "content.xml",
+ embed::ElementModes::READ | embed::ElementModes::NOCREATE );
+ }
+
+ // no exception -> success
+ eResult = ::comphelper::DocPasswordVerifierResult::OK;
+ }
+ catch( const packages::WrongPasswordException& )
+ {
+ eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword;
+ }
+ catch( const uno::Exception& )
+ {
+ // unknown error, report it as wrong password
+ // TODO/LATER: we need an additional way to report unknown problems in this case
+ eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword;
+ }
+ return eResult;
+}
+
+
+ErrCode CheckPasswd_Impl
+(
+ SfxObjectShell* pDoc,
+ SfxMedium* pFile // the Medium and its Password should be obtained
+)
+
+/* [Description]
+
+ Ask for the password for a medium, only works if it concerns storage.
+ If the password flag is set in the Document Info, then the password is
+ requested through a user dialogue and the set at the Set of the medium.
+ If the set does not exist the it is created.
+*/
+{
+ ErrCode nRet = ERRCODE_NONE;
+
+ if( !pFile->GetFilter() || pFile->IsStorage() )
+ {
+ uno::Reference< embed::XStorage > xStorage = pFile->GetStorage();
+ if( xStorage.is() )
+ {
+ uno::Reference< beans::XPropertySet > xStorageProps( xStorage, uno::UNO_QUERY );
+ if ( xStorageProps.is() )
+ {
+ bool bIsEncrypted = false;
+ uno::Sequence< uno::Sequence< beans::NamedValue > > aGpgProperties;
+ try {
+ xStorageProps->getPropertyValue("HasEncryptedEntries")
+ >>= bIsEncrypted;
+ xStorageProps->getPropertyValue("EncryptionGpGProperties")
+ >>= aGpgProperties;
+ } catch( uno::Exception& )
+ {
+ // TODO/LATER:
+ // the storage either has no encrypted elements or it's just
+ // does not allow to detect it, probably it should be implemented later
+ }
+
+ if ( bIsEncrypted )
+ {
+ css::uno::Reference<css::awt::XWindow> xWin(pDoc ? pDoc->GetDialogParent(pFile) : nullptr);
+ if (xWin)
+ xWin->setVisible(true);
+
+ nRet = ERRCODE_SFX_CANTGETPASSWD;
+
+ SfxItemSet& rSet = pFile->GetItemSet();
+ Reference< css::task::XInteractionHandler > xInteractionHandler = pFile->GetInteractionHandler();
+ if( xInteractionHandler.is() )
+ {
+ // use the comphelper password helper to request a password
+ OUString aPassword;
+ const SfxStringItem* pPasswordItem = rSet.GetItem(SID_PASSWORD, false);
+ if ( pPasswordItem )
+ aPassword = pPasswordItem->GetValue();
+
+ uno::Sequence< beans::NamedValue > aEncryptionData;
+ const SfxUnoAnyItem* pEncryptionDataItem = rSet.GetItem(SID_ENCRYPTIONDATA, false);
+ if ( pEncryptionDataItem )
+ pEncryptionDataItem->GetValue() >>= aEncryptionData;
+
+ // try if one of the public key entries is
+ // decryptable, then extract session key
+ // from it
+ if ( !aEncryptionData.hasElements() && aGpgProperties.hasElements() )
+ aEncryptionData = ::comphelper::DocPasswordHelper::decryptGpgSession(aGpgProperties);
+
+ // tdf#93389: if recovering a document, encryption data should contain
+ // entries for the real filter, not only for recovery ODF, to keep it
+ // encrypted. Pass this in encryption data.
+ // TODO: pass here the real filter (from AutoRecovery::implts_openDocs)
+ // to marshal this to requestAndVerifyDocPassword
+ if (rSet.GetItemState(SID_DOC_SALVAGE, false) == SfxItemState::SET)
+ {
+ aEncryptionData = comphelper::concatSequences(
+ aEncryptionData, std::initializer_list<beans::NamedValue>{
+ { "ForSalvage", css::uno::Any(true) } });
+ }
+
+ SfxDocPasswordVerifier aVerifier(*pFile);
+ aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
+ aVerifier, aEncryptionData, aPassword, xInteractionHandler, pFile->GetOrigURL(), comphelper::DocPasswordRequestType::Standard );
+
+ rSet.ClearItem( SID_PASSWORD );
+ rSet.ClearItem( SID_ENCRYPTIONDATA );
+
+ if ( aEncryptionData.hasElements() )
+ {
+ rSet.Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::Any( aEncryptionData ) ) );
+
+ try
+ {
+ // update the version list of the medium using the new password
+ pFile->GetVersionList();
+ }
+ catch( uno::Exception& )
+ {
+ // TODO/LATER: set the error code
+ }
+
+ nRet = ERRCODE_NONE;
+ }
+ else
+ nRet = ERRCODE_IO_ABORT;
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL( "A storage must implement XPropertySet interface!" );
+ nRet = ERRCODE_SFX_CANTGETPASSWD;
+ }
+ }
+ }
+
+ return nRet;
+}
+
+
+ErrCodeMsg SfxApplication::LoadTemplate( SfxObjectShellLock& xDoc, const OUString &rFileName, std::unique_ptr<SfxItemSet> pSet )
+{
+ std::shared_ptr<const SfxFilter> pFilter;
+ SfxMedium aMedium( rFileName, ( StreamMode::READ | StreamMode::SHARE_DENYNONE ) );
+
+ if ( !aMedium.GetStorage( false ).is() )
+ aMedium.GetInStream();
+
+ if ( aMedium.GetErrorIgnoreWarning() )
+ {
+ return aMedium.GetErrorCode();
+ }
+
+ aMedium.UseInteractionHandler( true );
+ ErrCode nErr = GetFilterMatcher().GuessFilter( aMedium, pFilter, SfxFilterFlags::TEMPLATE, SfxFilterFlags::NONE );
+ if ( ERRCODE_NONE != nErr)
+ {
+ return ERRCODE_SFX_NOTATEMPLATE;
+ }
+
+ if( !pFilter || !pFilter->IsAllowedAsTemplate() )
+ {
+ return ERRCODE_SFX_NOTATEMPLATE;
+ }
+
+ if ( pFilter->GetFilterFlags() & SfxFilterFlags::STARONEFILTER )
+ {
+ DBG_ASSERT( !xDoc.Is(), "Sorry, not implemented!" );
+ SfxStringItem aName( SID_FILE_NAME, rFileName );
+ SfxStringItem aReferer( SID_REFERER, "private:user" );
+ SfxStringItem aFlags( SID_OPTIONS, "T" );
+ SfxBoolItem aHidden( SID_HIDDEN, true );
+ const SfxPoolItemHolder aRet(GetDispatcher_Impl()->ExecuteList(
+ SID_OPENDOC, SfxCallMode::SYNCHRON,
+ { &aName, &aHidden, &aReferer, &aFlags } ));
+ const SfxObjectItem* pObj(dynamic_cast<const SfxObjectItem*>(aRet.getItem()));
+ if ( pObj )
+ xDoc = dynamic_cast<SfxObjectShell*>( pObj->GetShell() );
+ else
+ {
+ const SfxViewFrameItem* pView(dynamic_cast<const SfxViewFrameItem*>(aRet.getItem()));
+ if ( pView )
+ {
+ SfxViewFrame *pFrame = pView->GetFrame();
+ if ( pFrame )
+ xDoc = pFrame->GetObjectShell();
+ }
+ }
+
+ if ( !xDoc.Is() )
+ return ERRCODE_SFX_DOLOADFAILED;
+ }
+ else
+ {
+ if ( !xDoc.Is() )
+ xDoc = SfxObjectShell::CreateObject( pFilter->GetServiceName() );
+
+ //pMedium takes ownership of pSet
+ SfxMedium *pMedium = new SfxMedium( rFileName, StreamMode::STD_READ, pFilter, std::move(pSet) );
+ if(!xDoc->DoLoad(pMedium))
+ {
+ ErrCodeMsg nErrCode = xDoc->GetErrorCode();
+ xDoc->DoClose();
+ xDoc.Clear();
+ return nErrCode;
+ }
+ }
+
+ try
+ {
+ // TODO: introduce error handling
+
+ uno::Reference< embed::XStorage > xTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
+ if( !xTempStorage.is() )
+ throw uno::RuntimeException();
+
+ xDoc->GetStorage()->copyToStorage( xTempStorage );
+
+ if ( !xDoc->DoSaveCompleted( new SfxMedium( xTempStorage, OUString() ) ) )
+ throw uno::RuntimeException();
+ }
+ catch( uno::Exception& )
+ {
+ xDoc->DoClose();
+ xDoc.Clear();
+
+ // TODO: transfer correct error outside
+ return ERRCODE_SFX_GENERAL;
+ }
+
+ SetTemplate_Impl( rFileName, OUString(), xDoc );
+
+ xDoc->SetNoName();
+ xDoc->InvalidateName();
+ xDoc->SetModified(false);
+ xDoc->ResetError();
+
+ css::uno::Reference< css::frame::XModel > xModel = xDoc->GetModel();
+ if ( xModel.is() )
+ {
+ std::unique_ptr<SfxItemSet> pNew = xDoc->GetMedium()->GetItemSet().Clone();
+ pNew->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
+ pNew->ClearItem( SID_FILTER_NAME );
+ css::uno::Sequence< css::beans::PropertyValue > aArgs;
+ TransformItems( SID_OPENDOC, *pNew, aArgs );
+ sal_Int32 nLength = aArgs.getLength();
+ aArgs.realloc( nLength + 1 );
+ auto pArgs = aArgs.getArray();
+ pArgs[nLength].Name = "Title";
+ pArgs[nLength].Value <<= xDoc->GetTitle( SFX_TITLE_DETECT );
+ xModel->attachResource( OUString(), aArgs );
+ }
+
+ return xDoc->GetErrorCode();
+}
+
+
+void SfxApplication::NewDocDirectExec_Impl( SfxRequest& rReq )
+{
+ const SfxStringItem* pFactoryItem = rReq.GetArg<SfxStringItem>(SID_NEWDOCDIRECT);
+ OUString aFactName;
+ if ( pFactoryItem )
+ aFactName = pFactoryItem->GetValue();
+ else
+ aFactName = SvtModuleOptions().GetDefaultModuleName();
+
+ SfxRequest aReq( SID_OPENDOC, SfxCallMode::SYNCHRON, GetPool() );
+ aReq.AppendItem( SfxStringItem( SID_FILE_NAME, "private:factory/" + aFactName ) );
+ aReq.AppendItem( SfxFrameItem( SID_DOCFRAME, GetFrame() ) );
+ aReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
+
+ // TODO/LATER: Should the other arguments be transferred as well?
+ const SfxStringItem* pDefaultPathItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILEPATH);
+ if ( pDefaultPathItem )
+ aReq.AppendItem( *pDefaultPathItem );
+ const SfxStringItem* pDefaultNameItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILENAME);
+ if ( pDefaultNameItem )
+ aReq.AppendItem( *pDefaultNameItem );
+
+ SfxGetpApp()->ExecuteSlot( aReq );
+ const SfxViewFrameItem* pItem(dynamic_cast<const SfxViewFrameItem*>(aReq.GetReturnValue().getItem()));
+ if (nullptr != pItem)
+ rReq.SetReturnValue(SfxFrameItem(0, pItem->GetFrame()));
+}
+
+void SfxApplication::NewDocDirectState_Impl( SfxItemSet &rSet )
+{
+ rSet.Put(SfxStringItem(SID_NEWDOCDIRECT, "private:factory/" + SvtModuleOptions().GetDefaultModuleName()));
+}
+
+void SfxApplication::NewDocExec_Impl( SfxRequest& rReq )
+{
+ // No Parameter from BASIC only Factory given?
+ const SfxStringItem* pTemplNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_NAME);
+ const SfxStringItem* pTemplFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
+ const SfxStringItem* pTemplRegionNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_REGIONNAME);
+
+ SfxObjectShellLock xDoc;
+
+ OUString aTemplateRegion, aTemplateName, aTemplateFileName;
+ bool bDirect = false; // through FileName instead of Region/Template
+ SfxErrorContext aEc(ERRCTX_SFX_NEWDOC);
+ if ( !pTemplNameItem && !pTemplFileNameItem )
+ {
+ bool bNewWin = false;
+ weld::Window* pTopWin = GetTopWindow();
+
+ SfxObjectShell* pCurrentShell = SfxObjectShell::Current();
+ Reference<XModel> xModel;
+ if(pCurrentShell)
+ xModel = pCurrentShell->GetModel();
+
+ SfxTemplateManagerDlg aTemplDlg(rReq.GetFrameWeld());
+
+ if (xModel.is())
+ aTemplDlg.setDocumentModel(xModel);
+
+ int nRet = aTemplDlg.run();
+ if ( nRet == RET_OK )
+ {
+ rReq.Done();
+ if ( pTopWin != GetTopWindow() )
+ {
+ // the dialogue opens a document -> a new TopWindow appears
+ pTopWin = GetTopWindow();
+ bNewWin = true;
+ }
+ }
+
+ if (bNewWin && pTopWin)
+ {
+ // after the destruction of the dialogue its parent comes to top,
+ // but we want that the new document is on top
+ pTopWin->present();
+ }
+
+ return;
+ }
+ else
+ {
+ // Template-Name
+ if ( pTemplNameItem )
+ aTemplateName = pTemplNameItem->GetValue();
+
+ // Template-Region
+ if ( pTemplRegionNameItem )
+ aTemplateRegion = pTemplRegionNameItem->GetValue();
+
+ // Template-File-Name
+ if ( pTemplFileNameItem )
+ {
+ aTemplateFileName = pTemplFileNameItem->GetValue();
+ bDirect = true;
+ }
+ }
+
+ ErrCode lErr = ERRCODE_NONE;
+ if ( !bDirect )
+ {
+ SfxDocumentTemplates aTmpFac;
+ if( aTemplateFileName.isEmpty() )
+ aTmpFac.GetFull( aTemplateRegion, aTemplateName, aTemplateFileName );
+
+ if( aTemplateFileName.isEmpty() )
+ lErr = ERRCODE_SFX_TEMPLATENOTFOUND;
+ }
+
+ INetURLObject aObj( aTemplateFileName );
+ SfxErrorContext aEC( ERRCTX_SFX_LOADTEMPLATE, aObj.PathToFileName() );
+
+ if ( lErr != ERRCODE_NONE )
+ {
+ ErrCode lFatalErr = lErr.IgnoreWarning();
+ if ( lFatalErr )
+ ErrorHandler::HandleError(lErr);
+ }
+ else
+ {
+ SfxCallMode eMode = SfxCallMode::SYNCHRON;
+ SfxPoolItemHolder aRet;
+ SfxStringItem aReferer( SID_REFERER, "private:user" );
+ SfxStringItem aTarget( SID_TARGETNAME, "_default" );
+ if ( !aTemplateFileName.isEmpty() )
+ {
+ DBG_ASSERT( aObj.GetProtocol() != INetProtocol::NotValid, "Illegal URL!" );
+
+ SfxStringItem aName( SID_FILE_NAME, aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ SfxStringItem aTemplName( SID_TEMPLATE_NAME, aTemplateName );
+ SfxStringItem aTemplRegionName( SID_TEMPLATE_REGIONNAME, aTemplateRegion );
+ aRet = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode,
+ {&aName, &aTarget, &aReferer, &aTemplName, &aTemplRegionName});
+ }
+ else
+ {
+ SfxStringItem aName( SID_FILE_NAME, "private:factory" );
+ aRet = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode,
+ { &aName, &aTarget, &aReferer } );
+ }
+
+ if ( nullptr != aRet.getItem() )
+ rReq.SetReturnValue( *aRet.getItem() );
+ }
+}
+
+
+namespace {
+
+/**
+ * Check if a given filter type should open the hyperlinked document
+ * natively.
+ *
+ * @param rFilter filter object
+ */
+bool lcl_isFilterNativelySupported(const SfxFilter& rFilter)
+{
+ if (rFilter.IsOwnFormat())
+ return true;
+
+ const OUString& aName = rFilter.GetFilterName();
+ // We can handle all Excel variants natively.
+ return aName.startsWith("MS Excel");
+}
+
+}
+
+void SfxApplication::OpenDocExec_Impl( SfxRequest& rReq )
+{
+ OUString aDocService;
+ const SfxStringItem* pDocSrvItem = rReq.GetArg<SfxStringItem>(SID_DOC_SERVICE);
+ if (pDocSrvItem)
+ aDocService = pDocSrvItem->GetValue();
+
+ sal_uInt16 nSID = rReq.GetSlot();
+ const SfxStringItem* pFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
+ if ( pFileNameItem )
+ {
+ OUString aCommand( pFileNameItem->GetValue() );
+ const SfxSlot* pSlot = GetInterface()->GetSlot( aCommand );
+ if ( pSlot )
+ {
+ pFileNameItem = nullptr;
+ }
+ else
+ {
+ if ( aCommand.startsWith("slot:") )
+ {
+ sal_uInt16 nSlotId = static_cast<sal_uInt16>(o3tl::toInt32(aCommand.subView(5)));
+ if ( nSlotId == SID_OPENDOC )
+ pFileNameItem = nullptr;
+ }
+ }
+ }
+
+ if ( !pFileNameItem )
+ {
+ // get FileName from dialog
+ std::vector<OUString> aURLList;
+ OUString aFilter;
+ std::optional<SfxAllItemSet> pSet;
+ OUString aPath;
+ const SfxStringItem* pFolderNameItem = rReq.GetArg<SfxStringItem>(SID_PATH);
+ if ( pFolderNameItem )
+ aPath = pFolderNameItem->GetValue();
+ else if ( nSID == SID_OPENTEMPLATE )
+ {
+ aPath = SvtPathOptions().GetTemplatePath();
+ if (!aPath.isEmpty()) // if not empty then get last token
+ aPath = aPath.copy(aPath.lastIndexOf(';')+1); // lastIndexOf+copy works whether separator (';') is there or not
+ }
+
+ sal_Int16 nDialog = SFX2_IMPL_DIALOG_CONFIG;
+ const SfxBoolItem* pSystemDialogItem = rReq.GetArg<SfxBoolItem>(SID_FILE_DIALOG);
+ if ( pSystemDialogItem )
+ nDialog = pSystemDialogItem->GetValue() ? SFX2_IMPL_DIALOG_SYSTEM : SFX2_IMPL_DIALOG_OOO;
+
+ const SfxBoolItem* pRemoteDialogItem = rReq.GetArg<SfxBoolItem>(SID_REMOTE_DIALOG);
+ if ( pRemoteDialogItem && pRemoteDialogItem->GetValue())
+ nDialog = SFX2_IMPL_DIALOG_REMOTE;
+
+ sal_Int16 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION;
+ FileDialogFlags eDialogFlags = FileDialogFlags::MultiSelection;
+ const SfxBoolItem* pSignPDFItem = rReq.GetArg<SfxBoolItem>(SID_SIGNPDF);
+ if (pSignPDFItem && pSignPDFItem->GetValue())
+ {
+ eDialogFlags |= FileDialogFlags::SignPDF;
+ nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE;
+ }
+
+ OUString sStandardDir;
+
+ const SfxStringItem* pStandardDirItem = rReq.GetArg<SfxStringItem>(SID_STANDARD_DIR);
+ if ( pStandardDirItem )
+ sStandardDir = pStandardDirItem->GetValue();
+
+ css::uno::Sequence< OUString > aDenyList;
+
+ const SfxStringListItem* pDenyListItem = rReq.GetArg<SfxStringListItem>(SID_DENY_LIST);
+ if ( pDenyListItem )
+ pDenyListItem->GetStringList( aDenyList );
+
+ weld::Window* pTopWindow = GetTopWindow();
+ ErrCode nErr = sfx2::FileOpenDialog_Impl(pTopWindow,
+ nDialogType,
+ eDialogFlags, aURLList,
+ aFilter, pSet, &aPath, nDialog, sStandardDir, aDenyList);
+
+ if ( nErr == ERRCODE_ABORT )
+ {
+ aURLList.clear();
+ return;
+ }
+
+ rReq.SetArgs( *pSet );
+ if ( !aFilter.isEmpty() )
+ rReq.AppendItem( SfxStringItem( SID_FILTER_NAME, aFilter ) );
+ rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
+ rReq.AppendItem( SfxStringItem( SID_REFERER, "private:user" ) );
+ pSet.reset();
+
+ if(!aURLList.empty())
+ {
+ if ( nSID == SID_OPENTEMPLATE )
+ rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) );
+
+ // This helper wraps an existing (or may new created InteractionHandler)
+ // intercept all incoming interactions and provide useful information
+ // later if the following transaction was finished.
+
+ rtl::Reference<sfx2::PreventDuplicateInteraction> pHandler = new sfx2::PreventDuplicateInteraction(comphelper::getProcessComponentContext());
+ uno::Reference<task::XInteractionHandler> xHandler(pHandler);
+ uno::Reference<task::XInteractionHandler> xWrappedHandler;
+
+ // wrap existing handler or create new UUI handler
+ const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER);
+ if (pInteractionItem)
+ {
+ pInteractionItem->GetValue() >>= xWrappedHandler;
+ rReq.RemoveItem( SID_INTERACTIONHANDLER );
+ }
+ if (xWrappedHandler.is())
+ pHandler->setHandler(xWrappedHandler);
+ else
+ pHandler->useDefaultUUIHandler();
+ rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::Any(xHandler)) );
+
+ // define rules for this handler
+ css::uno::Type aInteraction = ::cppu::UnoType<css::task::ErrorCodeRequest>::get();
+ ::sfx2::PreventDuplicateInteraction::InteractionInfo aRule(aInteraction);
+ pHandler->addInteractionRule(aRule);
+
+ if (!aDocService.isEmpty())
+ {
+ rReq.RemoveItem(SID_DOC_SERVICE);
+ rReq.AppendItem(SfxStringItem(SID_DOC_SERVICE, aDocService));
+ }
+
+ for (auto const& url : aURLList)
+ {
+ rReq.RemoveItem( SID_FILE_NAME );
+ rReq.AppendItem( SfxStringItem( SID_FILE_NAME, url ) );
+
+ // Run synchronous, so that not the next document is loaded
+ // when rescheduling
+ // TODO/LATER: use URLList argument and always remove one document after another, each step in asynchronous execution, until finished
+ // but only if reschedule is a problem
+ GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() );
+
+ // check for special interaction "NO MORE DOCUMENTS ALLOWED" and
+ // break loop then. Otherwise we risk showing the same interaction more than once.
+ if ( pHandler->getInteractionInfo(aInteraction, &aRule) )
+ {
+ if (aRule.m_nCallCount > 0)
+ {
+ if (aRule.m_xRequest.is())
+ {
+ css::task::ErrorCodeRequest aRequest;
+ if (aRule.m_xRequest->getRequest() >>= aRequest)
+ {
+ if (aRequest.ErrCode == sal_Int32(sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED)))
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ aURLList.clear();
+ return;
+ }
+ aURLList.clear();
+ }
+
+ bool bHyperlinkUsed = false;
+
+ if ( SID_OPENURL == nSID )
+ {
+ // SID_OPENURL does the same as SID_OPENDOC!
+ rReq.SetSlot( SID_OPENDOC );
+ }
+ else if ( nSID == SID_OPENTEMPLATE )
+ {
+ rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) );
+ }
+ // pass URL to OS by using ShellExecuter or open it internal
+ // if it seems to be an own format.
+ /* Attention!
+ There exist two possibilities to open hyperlinks:
+ a) using SID_OPENHYPERLINK (new)
+ b) using SID_BROWSE (old)
+ */
+ else if ( nSID == SID_OPENHYPERLINK )
+ {
+ rReq.SetSlot( SID_OPENDOC );
+ bHyperlinkUsed = true;
+ }
+
+ // no else here! It's optional ...
+ if (!bHyperlinkUsed)
+ {
+ const SfxBoolItem* pHyperLinkUsedItem = rReq.GetArg<SfxBoolItem>(SID_BROWSE);
+ if ( pHyperLinkUsedItem )
+ bHyperlinkUsed = pHyperLinkUsedItem->GetValue();
+ // no "official" item, so remove it from ItemSet before using UNO-API
+ rReq.RemoveItem( SID_BROWSE );
+ }
+
+ const SfxStringItem* pFileName = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
+ assert(pFileName && "SID_FILE_NAME is required");
+ OUString aFileName = pFileName->GetValue();
+
+ OUString aReferer;
+ const SfxStringItem* pRefererItem = rReq.GetArg<SfxStringItem>(SID_REFERER);
+ if ( pRefererItem )
+ aReferer = pRefererItem->GetValue();
+
+ const SfxStringItem* pFileFlagsItem = rReq.GetArg<SfxStringItem>(SID_OPTIONS);
+ if ( pFileFlagsItem )
+ {
+ const OUString aFileFlags = pFileFlagsItem->GetValue().toAsciiUpperCase();
+ if ( aFileFlags.indexOf('T') >= 0 )
+ {
+ rReq.RemoveItem( SID_TEMPLATE );
+ rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, true ) );
+ }
+
+ if ( aFileFlags.indexOf('H') >= 0 )
+ {
+ rReq.RemoveItem( SID_HIDDEN );
+ rReq.AppendItem( SfxBoolItem( SID_HIDDEN, true ) );
+ }
+
+ if ( aFileFlags.indexOf('R') >= 0 )
+ {
+ rReq.RemoveItem( SID_DOC_READONLY );
+ rReq.AppendItem( SfxBoolItem( SID_DOC_READONLY, true ) );
+ }
+
+ if ( aFileFlags.indexOf('B') >= 0 )
+ {
+ rReq.RemoveItem( SID_PREVIEW );
+ rReq.AppendItem( SfxBoolItem( SID_PREVIEW, true ) );
+ }
+
+ rReq.RemoveItem( SID_OPTIONS );
+ }
+
+ // Mark without URL cannot be handled by hyperlink code
+ if ( bHyperlinkUsed && !aFileName.isEmpty() && aFileName[0] != '#' )
+ {
+ uno::Reference<document::XTypeDetection> xTypeDetection(
+ comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), UNO_QUERY);
+
+ if ( xTypeDetection.is() )
+ {
+ URL aURL;
+
+ aURL.Complete = aFileName;
+ Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
+ xTrans->parseStrict( aURL );
+
+ INetProtocol aINetProtocol = INetURLObject( aURL.Complete ).GetProtocol();
+ auto eMode = officecfg::Office::Security::Hyperlinks::Open::get();
+
+ if ( eMode == SvtExtendedSecurityOptions::OPEN_NEVER && aINetProtocol != INetProtocol::VndSunStarHelp )
+ {
+ SolarMutexGuard aGuard;
+ weld::Window *pWindow = SfxGetpApp()->GetTopWindow();
+
+ std::unique_ptr<weld::MessageDialog> xSecurityWarningBox(Application::CreateMessageDialog(pWindow,
+ VclMessageType::Warning, VclButtonsType::Ok, SfxResId(STR_SECURITY_WARNING_NO_HYPERLINKS)));
+ xSecurityWarningBox->set_title(SfxResId(RID_SECURITY_WARNING_TITLE));
+ xSecurityWarningBox->run();
+ return;
+ }
+
+ std::shared_ptr<const SfxFilter> pFilter{};
+
+ // attempt loading native documents only if they are from a known protocol
+ // it might be sensible to limit the set of protocols even further, but that
+ // may cause regressions, needs further testing
+ // see tdf#136427 for details
+ if (aINetProtocol != INetProtocol::NotValid) {
+ const OUString aTypeName { xTypeDetection->queryTypeByURL( aURL.Main ) };
+ SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
+ pFilter = rMatcher.GetFilter4EA( aTypeName );
+ }
+
+ if (!pFilter || !lcl_isFilterNativelySupported(*pFilter))
+ {
+ // hyperlink does not link to own type => special handling (http, ftp) browser and (other external protocols) OS
+ if ( aINetProtocol == INetProtocol::Mailto )
+ {
+ // don't dispatch mailto hyperlink to desktop dispatcher
+ rReq.RemoveItem( SID_TARGETNAME );
+ rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_self" ) );
+ }
+ else if ( aINetProtocol == INetProtocol::Ftp ||
+ aINetProtocol == INetProtocol::Http ||
+ aINetProtocol == INetProtocol::Https )
+ {
+ sfx2::openUriExternally(aURL.Complete, true, rReq.GetFrameWeld());
+ return;
+ }
+ else
+ {
+ // check for "internal" protocols that should not be forwarded to the system
+ // add special protocols that always should be treated as internal
+ std::vector < OUString > aProtocols { "private:*", "vnd.sun.star.*" };
+
+ // get registered protocol handlers from configuration
+ Reference < XNameAccess > xAccess(officecfg::Office::ProtocolHandler::HandlerSet::get());
+ const Sequence < OUString > aNames = xAccess->getElementNames();
+ for ( const auto& rName : aNames )
+ {
+ Reference < XPropertySet > xSet;
+ Any aRet = xAccess->getByName( rName );
+ aRet >>= xSet;
+ if ( xSet.is() )
+ {
+ // copy protocols
+ aRet = xSet->getPropertyValue("Protocols");
+ Sequence < OUString > aTmp;
+ aRet >>= aTmp;
+
+ aProtocols.insert(aProtocols.end(),std::cbegin(aTmp),std::cend(aTmp));
+ }
+ }
+
+ bool bFound = false;
+ for (const OUString & rProtocol : aProtocols)
+ {
+ WildCard aPattern(rProtocol);
+ if ( aPattern.Matches( aURL.Complete ) )
+ {
+ bFound = true;
+ break;
+ }
+ }
+
+ if ( !bFound )
+ {
+ bool bLoadInternal = false;
+ try
+ {
+ sfx2::openUriExternally(
+ aURL.Complete, pFilter == nullptr, rReq.GetFrameWeld());
+ }
+ catch ( css::system::SystemShellExecuteException& )
+ {
+ rReq.RemoveItem( SID_TARGETNAME );
+ rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
+ bLoadInternal = true;
+ }
+ if ( !bLoadInternal )
+ return;
+ }
+ }
+ }
+ else
+ {
+ // hyperlink document must be loaded into a new frame
+ rReq.RemoveItem( SID_TARGETNAME );
+ rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
+ }
+ }
+ }
+
+ if (!SvtSecurityOptions::isSecureMacroUri(aFileName, aReferer))
+ {
+ SfxErrorContext aCtx( ERRCTX_SFX_OPENDOC, aFileName );
+ ErrorHandler::HandleError( ERRCODE_IO_ACCESSDENIED );
+ return;
+ }
+
+ SfxFrame* pTargetFrame = nullptr;
+ Reference< XFrame > xTargetFrame;
+
+ const SfxFrameItem* pFrameItem = rReq.GetArg<SfxFrameItem>(SID_DOCFRAME);
+ if ( pFrameItem )
+ pTargetFrame = pFrameItem->GetFrame();
+
+ if ( !pTargetFrame )
+ {
+ const SfxUnoFrameItem* pUnoFrameItem = rReq.GetArg<SfxUnoFrameItem>(SID_FILLFRAME);
+ if ( pUnoFrameItem )
+ xTargetFrame = pUnoFrameItem->GetFrame();
+ }
+
+ if (!pTargetFrame && !xTargetFrame.is())
+ {
+ if (const SfxViewFrame* pViewFrame = SfxViewFrame::Current())
+ pTargetFrame = &pViewFrame->GetFrame();
+ }
+
+ // check if caller has set a callback
+ std::unique_ptr<SfxLinkItem> pLinkItem;
+
+ // remove from Itemset, because it confuses the parameter transformation
+ if (auto pParamLinkItem = rReq.GetArg<SfxLinkItem>(SID_DONELINK))
+ pLinkItem.reset(pParamLinkItem->Clone());
+
+ rReq.RemoveItem( SID_DONELINK );
+
+ // check if the view must be hidden
+ bool bHidden = false;
+ const SfxBoolItem* pHidItem = rReq.GetArg<SfxBoolItem>(SID_HIDDEN);
+ if ( pHidItem )
+ bHidden = pHidItem->GetValue();
+
+ // This request is a UI call. We have to set the right values inside the MediaDescriptor
+ // for: InteractionHandler, StatusIndicator, MacroExecutionMode and DocTemplate.
+ // But we have to look for already existing values or for real hidden requests.
+ const SfxBoolItem* pPreviewItem = rReq.GetArg<SfxBoolItem>(SID_PREVIEW);
+ if (!bHidden && ( !pPreviewItem || !pPreviewItem->GetValue() ) )
+ {
+ const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER);
+ const SfxUInt16Item* pMacroExecItem = rReq.GetArg<SfxUInt16Item>(SID_MACROEXECMODE);
+ const SfxUInt16Item* pDocTemplateItem = rReq.GetArg<SfxUInt16Item>(SID_UPDATEDOCMODE);
+
+ if (!pInteractionItem)
+ {
+ Reference < task::XInteractionHandler2 > xHdl = task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr );
+ rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::Any(xHdl)) );
+ }
+ if (!pMacroExecItem)
+ rReq.AppendItem( SfxUInt16Item(SID_MACROEXECMODE,css::document::MacroExecMode::USE_CONFIG) );
+ if (!pDocTemplateItem)
+ rReq.AppendItem( SfxUInt16Item(SID_UPDATEDOCMODE,css::document::UpdateDocMode::ACCORDING_TO_CONFIG) );
+ }
+
+ // extract target name
+ OUString aTarget;
+ const SfxStringItem* pTargetItem = rReq.GetArg<SfxStringItem>(SID_TARGETNAME);
+ if ( pTargetItem )
+ aTarget = pTargetItem->GetValue();
+ else
+ {
+ const SfxBoolItem* pNewViewItem = rReq.GetArg<SfxBoolItem>(SID_OPEN_NEW_VIEW);
+ if ( pNewViewItem && pNewViewItem->GetValue() )
+ aTarget = "_blank" ;
+ }
+
+ if ( bHidden )
+ {
+ aTarget = "_blank";
+ DBG_ASSERT( rReq.IsSynchronCall() || pLinkItem, "Hidden load process must be done synchronously!" );
+ }
+
+ Reference < XController > xController;
+ // if a frame is given, it must be used for the starting point of the targeting mechanism
+ // this code is also used if asynchronous loading is possible, because loadComponent always is synchron
+ if ( !xTargetFrame.is() )
+ {
+ if ( pTargetFrame )
+ {
+ xTargetFrame = pTargetFrame->GetFrameInterface();
+ }
+ else
+ {
+ xTargetFrame = Desktop::create(::comphelper::getProcessComponentContext());
+ }
+ }
+
+ // make URL ready
+ const SfxStringItem* pURLItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
+ aFileName = pURLItem->GetValue();
+ if( aFileName.startsWith("#") ) // Mark without URL
+ {
+ SfxViewFrame *pView = pTargetFrame ? pTargetFrame->GetCurrentViewFrame() : nullptr;
+ if ( !pView )
+ pView = SfxViewFrame::Current();
+ pView->GetViewShell()->JumpToMark( aFileName.copy(1) );
+ rReq.SetReturnValue( SfxViewFrameItem( pView ) );
+ return;
+ }
+
+ // convert items to properties for framework API calls
+ Sequence < PropertyValue > aArgs;
+ TransformItems( SID_OPENDOC, *rReq.GetArgs(), aArgs );
+ // Any Referer (that was relevant in the above call to
+ // SvtSecurityOptions::isSecureMacroUri) is no longer relevant, assuming
+ // this "open" request is initiated directly by the user:
+ auto pArg = std::find_if(std::cbegin(aArgs), std::cend(aArgs),
+ [](const PropertyValue& rArg) { return rArg.Name == "Referer"; });
+ if (pArg != std::cend(aArgs))
+ {
+ auto nIndex = static_cast<sal_Int32>(std::distance(std::cbegin(aArgs), pArg));
+ comphelper::removeElementAt(aArgs, nIndex);
+ }
+
+ // TODO/LATER: either remove LinkItem or create an asynchronous process for it
+ if( bHidden || pLinkItem || rReq.IsSynchronCall() )
+ {
+ // if loading must be done synchron, we must wait for completion to get a return value
+ // find frame by myself; I must know the exact frame to get the controller for the return value from it
+ Reference < XComponent > xComp;
+
+ try
+ {
+ xComp = ::comphelper::SynchronousDispatch::dispatch( xTargetFrame, aFileName, aTarget, aArgs );
+ }
+ catch(const RuntimeException&)
+ {
+ throw;
+ }
+ catch(const css::uno::Exception&)
+ {
+ }
+
+ Reference < XModel > xModel( xComp, UNO_QUERY );
+ if ( xModel.is() )
+ xController = xModel->getCurrentController();
+ else
+ xController.set( xComp, UNO_QUERY );
+
+ }
+ else
+ {
+ URL aURL;
+ aURL.Complete = aFileName;
+ Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
+ xTrans->parseStrict( aURL );
+
+ Reference < XDispatchProvider > xProv( xTargetFrame, UNO_QUERY );
+ Reference < XDispatch > xDisp = xProv.is() ? xProv->queryDispatch( aURL, aTarget, FrameSearchFlag::ALL ) : Reference < XDispatch >();
+ if ( xDisp.is() )
+ xDisp->dispatch( aURL, aArgs );
+ }
+
+ if ( xController.is() )
+ {
+ // try to find the SfxFrame for the controller
+ SfxFrame* pCntrFrame = nullptr;
+ for ( SfxViewShell* pShell = SfxViewShell::GetFirst( false ); pShell; pShell = SfxViewShell::GetNext( *pShell, false ) )
+ {
+ if ( pShell->GetController() == xController )
+ {
+ pCntrFrame = &pShell->GetViewFrame().GetFrame();
+ break;
+ }
+ }
+
+ if ( pCntrFrame )
+ {
+ SfxObjectShell* pSh = pCntrFrame->GetCurrentDocument();
+ DBG_ASSERT( pSh, "Controller without ObjectShell ?!" );
+
+ rReq.SetReturnValue( SfxViewFrameItem( pCntrFrame->GetCurrentViewFrame() ) );
+
+ if ( bHidden )
+ pSh->RestoreNoDelete();
+ }
+ }
+
+ if (pLinkItem)
+ {
+ const SfxPoolItem* pRetValue(rReq.GetReturnValue().getItem());
+ if (pRetValue)
+ {
+ pLinkItem->GetValue().Call(pRetValue);
+ }
+ }
+}
+
+void SfxApplication::OpenRemoteExec_Impl( SfxRequest& rReq )
+{
+ rReq.AppendItem( SfxBoolItem( SID_REMOTE_DIALOG, true ) );
+ GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() );
+}
+
+void SfxApplication::SignPDFExec_Impl(SfxRequest& rReq)
+{
+ rReq.AppendItem(SfxBoolItem(SID_SIGNPDF, true));
+ GetDispatcher_Impl()->Execute(SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appquit.cxx b/sfx2/source/appl/appquit.cxx
new file mode 100644
index 0000000000..b34550dc7f
--- /dev/null
+++ b/sfx2/source/appl/appquit.cxx
@@ -0,0 +1,103 @@
+/* -*- 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 <config_features.h>
+
+#include <basic/sbstar.hxx>
+#include <tools/debug.hxx>
+
+#include <sfx2/app.hxx>
+#include <appdata.hxx>
+#include <sfx2/stbitem.hxx>
+#include <sfx2/tbxctrl.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/dispatch.hxx>
+#include <nochaos.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/objsh.hxx>
+#include <appbaslib.hxx>
+#include <basic/basicmanagerrepository.hxx>
+
+using ::basic::BasicManagerRepository;
+
+void SfxApplication::Deinitialize()
+{
+ if (pImpl->bDowning)
+ return;
+
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::Stop();
+
+ SaveBasicAndDialogContainer();
+#endif
+
+ pImpl->bDowning = true; // due to Timer from DecAliveCount and QueryExit
+
+ pImpl->pTemplates.reset();
+
+ // By definition there shouldn't be any open view frames when we reach
+ // this method. Therefore this call makes no sense and is the source of
+ // some stack traces, which we don't understand.
+ // For more information see:
+ pImpl->bDowning = false;
+ DBG_ASSERT(!SfxViewFrame::GetFirst(), "existing SfxViewFrame after Execute");
+ DBG_ASSERT(!SfxObjectShell::GetFirst(), "existing SfxObjectShell after Execute");
+ pImpl->pAppDispat->Pop(*this, SfxDispatcherPopFlags::POP_UNTIL);
+ pImpl->pAppDispat->Flush();
+ pImpl->bDowning = true;
+ pImpl->pAppDispat->DoDeactivate_Impl(true, nullptr);
+
+ // Release Controller and others
+ // then the remaining components should also disappear ( Beamer! )
+
+#if HAVE_FEATURE_SCRIPTING
+ BasicManagerRepository::resetApplicationBasicManager();
+ pImpl->pBasicManager->reset(nullptr); // this will also delete pBasMgr
+#endif
+
+ DBG_ASSERT(pImpl->pViewFrame == nullptr, "active foreign ViewFrame");
+
+ // free administration managers
+ pImpl->pAppDispat.reset();
+
+ // from here no SvObjects have to exists
+ pImpl->pMatcher.reset();
+
+ pImpl->pSlotPool.reset();
+ pImpl->maFactories.clear();
+
+ pImpl->maTbxCtrlFactories.clear();
+ pImpl->maStbCtrlFactories.clear();
+ pImpl->maViewFrames.clear();
+ pImpl->maViewShells.clear();
+ pImpl->maObjShells.clear();
+
+ //TODO/CLEANUP
+ //ReleaseArgs could be used instead!
+ pImpl->pPool = nullptr;
+ NoChaos::ReleaseItemPool();
+
+#if HAVE_FEATURE_SCRIPTING
+ pImpl->m_pSbxErrorHdl.reset();
+#endif
+ pImpl->m_pSoErrorHdl.reset();
+ pImpl->m_pToolsErrorHdl.reset();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appreg.cxx b/sfx2/source/appl/appreg.cxx
new file mode 100644
index 0000000000..662e485b62
--- /dev/null
+++ b/sfx2/source/appl/appreg.cxx
@@ -0,0 +1,105 @@
+/* -*- 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 <sal/log.hxx>
+
+#include <sfx2/app.hxx>
+#include <appdata.hxx>
+#include <inettbc.hxx>
+#include <sfx2/stbitem.hxx>
+#include <sfx2/infobar.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <partwnd.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <recfloat.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewsh.hxx>
+
+
+void SfxApplication::Registrations_Impl()
+{
+ // Interfaces
+ SfxApplication::RegisterInterface();
+ SfxModule::RegisterInterface();
+ SfxViewFrame::RegisterInterface();
+ SfxObjectShell::RegisterInterface();
+ SfxViewShell::RegisterInterface();
+
+ // ChildWindows
+ SfxRecordingFloatWrapper_Impl::RegisterChildWindow();
+ SfxPartChildWnd_Impl::RegisterChildWindow();
+ SfxDockingWrapper::RegisterChildWindow();
+ SfxInfoBarContainerChild::RegisterChildWindow( true, nullptr, SfxChildWindowFlags::NEVERHIDE );
+
+ // Controller
+ SfxToolBoxControl::RegisterControl(SID_REPEAT);
+ SfxURLToolBoxControl_Impl::RegisterControl(SID_OPENURL);
+}
+
+
+void SfxApplication::RegisterToolBoxControl_Impl( SfxModule *pMod, const SfxTbxCtrlFactory& rFact )
+{
+ if ( pMod )
+ {
+ pMod->RegisterToolBoxControl( rFact );
+ return;
+ }
+
+#ifdef DBG_UTIL
+ for ( size_t n=0; n<pImpl->maTbxCtrlFactories.size(); n++ )
+ {
+ SfxTbxCtrlFactory *pF = &pImpl->maTbxCtrlFactories[n];
+ if ( pF->nTypeId == rFact.nTypeId &&
+ (pF->nSlotId == rFact.nSlotId || pF->nSlotId == 0) )
+ {
+ SAL_INFO("sfx", "TbxController registration is not clearly defined!");
+ }
+ }
+#endif
+
+ pImpl->maTbxCtrlFactories.push_back( rFact );
+}
+
+
+void SfxApplication::RegisterStatusBarControl_Impl( SfxModule *pMod, const SfxStbCtrlFactory& rFact )
+{
+ if ( pMod )
+ {
+ pMod->RegisterStatusBarControl( rFact );
+ return;
+ }
+
+#ifdef DBG_UTIL
+ for ( size_t n=0; n<pImpl->maStbCtrlFactories.size(); n++ )
+ {
+ SfxStbCtrlFactory *pF = &pImpl->maStbCtrlFactories[n];
+ if ( pF->nTypeId == rFact.nTypeId &&
+ (pF->nSlotId == rFact.nSlotId || pF->nSlotId == 0) )
+ {
+ SAL_INFO("sfx", "StbController registration is not clearly defined!");
+ }
+ }
+#endif
+
+ pImpl->maStbCtrlFactories.push_back( rFact );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appserv.cxx b/sfx2/source/appl/appserv.cxx
new file mode 100644
index 0000000000..cccc2abc1a
--- /dev/null
+++ b/sfx2/source/appl/appserv.cxx
@@ -0,0 +1,1808 @@
+/* -*- 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 <config_features.h>
+#include <config_wasm_strip.h>
+
+#include <com/sun/star/drawing/ModuleDispatcher.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/DispatchResultEvent.hpp>
+#include <com/sun/star/frame/DispatchResultState.hpp>
+#include <com/sun/star/frame/DispatchHelper.hpp>
+#include <com/sun/star/frame/UnknownModuleException.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/text/ModuleDispatcher.hpp>
+#include <com/sun/star/task/OfficeRestartManager.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/ui/dialogs/AddressBookSourcePilot.hpp>
+#include <com/sun/star/ui/UIElementType.hpp>
+#include <com/sun/star/ui/XUIElement.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <org/freedesktop/PackageKit/SyncDbusSessionHelper.hpp>
+
+#include <comphelper/dispatchcommand.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <svtools/addresstemplate.hxx>
+#include <svtools/restartdialog.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svl/visitem.hxx>
+
+#include <unotools/configmgr.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <vcl/weld.hxx>
+#include <svl/intitem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/stritem.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/basrdll.hxx>
+#include <basic/sberrors.hxx>
+#include <vcl/help.hxx>
+#include <sal/log.hxx>
+#include <osl/file.hxx>
+#include <vcl/EnumContext.hxx>
+#include <vcl/toolbox.hxx>
+
+#include <unotools/moduleoptions.hxx>
+#include <rtl/bootstrap.hxx>
+
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <sfx2/app.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/minfitem.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/docfac.hxx>
+#include <sfx2/strings.hrc>
+#include <sfx2/sfxresid.hxx>
+#include <appdata.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sorgitm.hxx>
+#include <sfx2/sfxhelp.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <sfx2/templatedlg.hxx>
+#include <sfx2/notebookbar/SfxNotebookBar.hxx>
+#include <sfx2/sidebar/SidebarController.hxx>
+#include <sfx2/safemode.hxx>
+#include <sfx2/sfxuno.hxx>
+#include <sfx2/devtools/DevelopmentToolDockingWindow.hxx>
+
+#include <comphelper/types.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <unotools/confignode.hxx>
+#include <memory>
+
+#include <openuriexternally.hxx>
+
+#include "getbasctlfunction.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ui;
+
+namespace
+{
+ OUString lcl_getAppName( vcl::EnumContext::Application eApp )
+ {
+ switch ( eApp )
+ {
+ case vcl::EnumContext::Application::Writer:
+ return "Writer";
+ case vcl::EnumContext::Application::Calc:
+ return "Calc";
+ case vcl::EnumContext::Application::Impress:
+ return "Impress";
+ case vcl::EnumContext::Application::Draw:
+ return "Draw";
+ case vcl::EnumContext::Application::Formula:
+ return "Formula";
+ case vcl::EnumContext::Application::Base:
+ return "Base";
+ default:
+ return OUString();
+ }
+ }
+
+ // lp#527938, debian#602953, fdo#33266, i#105408
+ bool lcl_isBaseAvailable()
+ {
+ try
+ {
+ // if we get css::sdbc::DriverManager, libsdbc2 is there
+ // and the bibliography is assumed to work
+ return css::sdbc::DriverManager::create(comphelper::getProcessComponentContext()).is();
+ }
+ catch (const Exception &)
+ {
+ TOOLS_INFO_EXCEPTION("sfx.appl", "assuming Base to be missing");
+ return false;
+ }
+ }
+ void lcl_tryLoadBibliography()
+ {
+ // lp#527938, debian#602953, fdo#33266, i#105408
+ // make sure we actually can instantiate services from base first
+ if(!lcl_isBaseAvailable())
+ {
+ if (officecfg::Office::Common::PackageKit::EnableBaseInstallation::get())
+ {
+ try
+ {
+ using namespace org::freedesktop::PackageKit;
+ using namespace svtools;
+ Reference< XSyncDbusSessionHelper > xSyncDbusSessionHelper(SyncDbusSessionHelper::create(comphelper::getProcessComponentContext()));
+ Sequence< OUString > vPackages { "libreoffice-base" };
+ xSyncDbusSessionHelper->InstallPackageNames(vPackages, OUString());
+ // I'll be back (hopefully)!
+ SolarMutexGuard aGuard;
+ executeRestartDialog(comphelper::getProcessComponentContext(), nullptr, RESTART_REASON_BIBLIOGRAPHY_INSTALL);
+ }
+ catch (const Exception &)
+ {
+ TOOLS_INFO_EXCEPTION("sfx.appl", "trying to install LibreOffice Base");
+ }
+ }
+ return;
+ }
+
+ try // fdo#48775
+ {
+ SfxStringItem aURL(SID_FILE_NAME, ".component:Bibliography/View1");
+ SfxStringItem aRef(SID_REFERER, "private:user");
+ SfxStringItem aTarget(SID_TARGETNAME, "_blank");
+ if (const SfxViewFrame* pViewFrame = SfxViewFrame::Current())
+ {
+ pViewFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
+ SfxCallMode::ASYNCHRON, { &aURL, &aRef, &aTarget });
+ }
+ }
+ catch (const Exception &)
+ {
+ TOOLS_INFO_EXCEPTION( "sfx.appl", "trying to load bibliography database");
+ }
+ }
+}
+/// Find the correct location of the document (CREDITS.fodt, etc.), and return
+/// it in rURL if found.
+static bool checkURL( const char *pName, const char *pExt, OUString &rURL )
+{
+ using namespace osl;
+ DirectoryItem aDirItem;
+
+#ifdef MACOSX
+ rURL = "$BRAND_BASE_DIR/Resources/" + OUString::createFromAscii( pName ) +
+ OUString::createFromAscii( pExt );
+#else
+ rURL = "$BRAND_BASE_DIR/" + OUString::createFromAscii( pName ) +
+ OUString::createFromAscii( pExt );
+#endif
+ rtl::Bootstrap::expandMacros( rURL );
+
+ if (!rURL.isEmpty())
+ return DirectoryItem::get( rURL, aDirItem ) == DirectoryItem::E_None;
+ else
+ return false;
+}
+
+/// Displays CREDITS or LICENSE in any of the available version
+static void showDocument( const char* pBaseName )
+{
+ try {
+ Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
+ auto args(::comphelper::InitPropertySequence({
+ {"ViewOnly", Any(true)},
+ {"ReadOnly", Any(true)}
+ }));
+
+ OUString aURL;
+ if ( checkURL ( pBaseName, ".fodt", aURL ) ||
+ checkURL ( pBaseName, ".html", aURL ) ||
+ checkURL ( pBaseName, "", aURL ) ) {
+ xDesktop->loadComponentFromURL( aURL, "_blank", 0, args );
+ }
+ } catch (const css::uno::Exception &) {
+ }
+}
+
+namespace
+{
+ Reference<XFrame> GetRequestFrame(const SfxRequest& rReq)
+ {
+ const SfxItemSet* pArgs = rReq.GetInternalArgs_Impl();
+ const SfxUnoFrameItem* pItem = nullptr;
+ Reference <XFrame> xFrame;
+ if (pArgs && (pItem = pArgs->GetItemIfSet(SID_FILLFRAME, false)))
+ {
+ xFrame = pItem->GetFrame();
+ }
+ return xFrame;
+ }
+
+ Reference<XFrame> GetDocFrame(const SfxRequest& rReq)
+ {
+ const SfxFrameItem* pFrameItem = rReq.GetArg<SfxFrameItem>(SID_DOCFRAME);
+ SfxFrame* pFrame = pFrameItem ? pFrameItem->GetFrame() : nullptr;
+ return pFrame ? pFrame->GetFrameInterface() : nullptr;
+ }
+
+ class LicenseDialog : public weld::GenericDialogController
+ {
+ public:
+ LicenseDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "sfx/ui/licensedialog.ui", "LicenseDialog")
+ {
+ }
+
+ virtual short run() override
+ {
+ short nRet = GenericDialogController::run();
+ if (nRet == RET_OK)
+ showDocument("LICENSE");
+ return nRet;
+ }
+ };
+
+ class SafeModeQueryDialog : public weld::MessageDialogController
+ {
+ public:
+ SafeModeQueryDialog(weld::Window* pParent)
+ : MessageDialogController(pParent, "sfx/ui/safemodequerydialog.ui", "SafeModeQueryDialog")
+ {
+ }
+
+ virtual short run() override
+ {
+ short nRet = MessageDialogController::run();
+ if (nRet == RET_OK)
+ {
+ sfx2::SafeMode::putFlag();
+ uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
+ css::task::OfficeRestartManager::get(xContext)->requestRestart(
+ css::uno::Reference< css::task::XInteractionHandler >());
+ }
+ return nRet;
+ }
+ };
+}
+
+weld::Window* SfxRequest::GetFrameWeld() const
+{
+ const SfxItemSet* pIntArgs = GetInternalArgs_Impl();
+ const SfxUnoAnyItem* pItem = nullptr;
+ if (pIntArgs && (pItem = pIntArgs->GetItemIfSet(SID_DIALOG_PARENT, false)))
+ {
+ auto aAny = pItem->GetValue();
+ Reference<awt::XWindow> xWindow;
+ aAny >>= xWindow;
+ return Application::GetFrameWeld(xWindow);
+ }
+
+ Reference<XFrame> xFrame(GetRequestFrame(*this));
+ if (!xFrame)
+ xFrame = GetDocFrame(*this);
+ if (!xFrame)
+ {
+ SAL_WARN("sfx.appl", "no parent for dialogs");
+ return nullptr;
+ }
+ return Application::GetFrameWeld(xFrame->getContainerWindow());
+}
+
+void SfxApplication::MiscExec_Impl( SfxRequest& rReq )
+{
+ bool bDone = false;
+ switch ( rReq.GetSlot() )
+ {
+ case SID_SETOPTIONS:
+ {
+ if( rReq.GetArgs() )
+ SetOptions( *rReq.GetArgs() );
+ break;
+ }
+
+ case SID_QUITAPP:
+ case SID_LOGOUT:
+ {
+ // protect against reentrant calls
+ if ( pImpl->bInQuit )
+ return;
+
+ if ( rReq.GetSlot() == SID_LOGOUT )
+ {
+ for ( SfxObjectShell *pObjSh = SfxObjectShell::GetFirst();
+ pObjSh; pObjSh = SfxObjectShell::GetNext( *pObjSh ) )
+ {
+ if ( !pObjSh->IsModified() )
+ continue;
+
+ SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pObjSh );
+ if ( !pFrame || !pFrame->GetWindow().IsReallyVisible() )
+ continue;
+
+ if (pObjSh->PrepareClose())
+ pObjSh->SetModified( false );
+ else
+ return;
+ }
+
+ SfxStringItem aNameItem( SID_FILE_NAME, "vnd.sun.star.cmd:logout" );
+ SfxStringItem aReferer( SID_REFERER, "private/user" );
+ pImpl->pAppDispat->ExecuteList(SID_OPENDOC,
+ SfxCallMode::SLOT, { &aNameItem, &aReferer });
+ return;
+ }
+
+ // try from nested requests again after 100ms
+ if( Application::GetDispatchLevel() > 1 )
+ {
+ /* Don't save the request for closing the application and try it later
+ again. This is an UI bound functionality ... and the user will try it again
+ if the dialog is closed. But we should not close the application automatically
+ if this dialog is closed by the user ...
+ So we ignore this request now and wait for a new user decision.
+ */
+ SAL_INFO("sfx.appl", "QueryExit => sal_False, DispatchLevel == " << Application::GetDispatchLevel() );
+ return;
+ }
+
+ // block reentrant calls
+ pImpl->bInQuit = true;
+ Reference < XDesktop2 > xDesktop = Desktop::create ( ::comphelper::getProcessComponentContext() );
+
+ rReq.ForgetAllArgs();
+
+ // if terminate() failed, pImpl->bInQuit will now be sal_False, allowing further calls of SID_QUITAPP
+ bool bTerminated = xDesktop->terminate();
+ if (!bTerminated)
+ // if terminate() was successful, SfxApplication is now dead!
+ pImpl->bInQuit = false;
+
+ // Set return value, terminate if possible
+ rReq.SetReturnValue( SfxBoolItem( rReq.GetSlot(), bTerminated ) );
+ return;
+ }
+
+ case SID_CONFIG:
+ case SID_TOOLBOXOPTIONS:
+ case SID_CONFIGSTATUSBAR:
+ case SID_CONFIGMENU:
+ case SID_CONFIGACCEL:
+ case SID_CONFIGEVENT:
+ {
+ SfxAbstractDialogFactory* pFact =
+ SfxAbstractDialogFactory::Create();
+
+ const SfxStringItem* pStringItem = rReq.GetArg<SfxStringItem>(SID_CONFIG);
+
+ SfxItemSetFixed<SID_CONFIG, SID_CONFIG, SID_MACROINFO, SID_MACROINFO> aSet( GetPool() );
+
+ // SID_CONFIG property will determine the default page shown
+ if ( pStringItem )
+ {
+ aSet.Put( SfxStringItem(
+ SID_CONFIG, pStringItem->GetValue() ) );
+ }
+ else if (rReq.GetSlot() == SID_CONFIGEVENT)
+ {
+ aSet.Put( SfxStringItem(
+ SID_CONFIG, "private:resource/event/" ) );
+ }
+ else if (rReq.GetSlot() == SID_TOOLBOXOPTIONS)
+ {
+ aSet.Put( SfxStringItem(
+ SID_CONFIG, "private:resource/toolbar/" ) );
+ }
+
+#if HAVE_FEATURE_SCRIPTING
+ // Preselect a macro in the 'keyboard' page
+ if (auto const item = rReq.GetArg<SfxMacroInfoItem>(SID_MACROINFO)) {
+ aSet.Put(*item);
+ }
+#endif
+
+ Reference <XFrame> xFrame(GetRequestFrame(rReq));
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateCustomizeTabDialog(rReq.GetFrameWeld(),
+ &aSet, xFrame ));
+
+ const short nRet = pDlg->Execute();
+
+ if ( nRet )
+ bDone = true;
+ break;
+ }
+
+ case SID_CLOSEDOCS:
+ {
+
+ Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
+ Reference< XIndexAccess > xTasks = xDesktop->getFrames();
+ if ( !xTasks.is() )
+ break;
+
+ sal_Int32 n=0;
+ do
+ {
+ if ( xTasks->getCount() <= n )
+ break;
+
+ Any aAny = xTasks->getByIndex(n);
+ Reference < XCloseable > xTask;
+ aAny >>= xTask;
+ try
+ {
+ xTask->close(true);
+ n++;
+ }
+ catch( CloseVetoException& )
+ {
+ }
+ }
+ while( true );
+
+ bool bOk = ( n == 0);
+ rReq.SetReturnValue( SfxBoolItem( 0, bOk ) );
+ bDone = true;
+ break;
+ }
+
+ case SID_SAVEDOCS:
+ {
+ bool bOK = true;
+ for ( SfxObjectShell *pObjSh = SfxObjectShell::GetFirst();
+ pObjSh;
+ pObjSh = SfxObjectShell::GetNext( *pObjSh ) )
+ {
+ SfxRequest aReq( SID_SAVEDOC, SfxCallMode::SLOT, pObjSh->GetPool() );
+ if ( pObjSh->IsModified() && !pObjSh->isSaveLocked())
+ {
+ pObjSh->ExecuteSlot( aReq );
+ const SfxBoolItem* pItem(dynamic_cast<const SfxBoolItem*>(aReq.GetReturnValue().getItem()));
+ if ( !pItem || !pItem->GetValue() )
+ bOK = false;
+ }
+ }
+
+ rReq.SetReturnValue( SfxBoolItem( 0, bOK ) );
+ rReq.Done();
+ break;
+ }
+
+ case SID_SEND_FEEDBACK:
+ {
+ OUString module = SfxHelp::GetCurrentModuleIdentifier();
+ OUString sURL(officecfg::Office::Common::Menus::SendFeedbackURL::get() + //officecfg/registry/data/org/openoffice/Office/Common.xcu => https://hub.libreoffice.org/send-feedback/
+ "?LOversion=" + utl::ConfigManager::getAboutBoxProductVersion() +
+ "&LOlocale=" + utl::ConfigManager::getUILocale() +
+ "&LOmodule=" + module.subView(module.lastIndexOf('.') + 1 ) );
+ sfx2::openUriExternally(sURL, false, rReq.GetFrameWeld());
+ break;
+ }
+
+ case SID_Q_AND_A:
+ {
+ // Askbot has URL's normalized to languages, not locales
+ // Get language from locale: ll or lll or ll-CC or lll-CC
+
+ OUString sURL(officecfg::Office::Common::Menus::QA_URL::get() + //https://hub.libreoffice.org/forum/
+ "?LOlocale=" + utl::ConfigManager::getUILocale());
+ sfx2::openUriExternally(sURL, false, rReq.GetFrameWeld());
+ break;
+ }
+ case SID_DOCUMENTATION:
+ {
+ // Open documentation page based on locales
+ OUString sURL(officecfg::Office::Common::Menus::DocumentationURL::get() + //https://hub.libreoffice.org/documentation/
+ "?LOlocale=" + utl::ConfigManager::getUILocale());
+ sfx2::openUriExternally(sURL, false, rReq.GetFrameWeld());
+ break;
+ }
+#if !ENABLE_WASM_STRIP_PINGUSER
+ case SID_GETINVOLVED:
+ {
+ // Open get involved/join us page based on locales
+ OUString sURL(officecfg::Office::Common::Menus::GetInvolvedURL::get() + //https://hub.libreoffice.org/joinus/
+ "?LOlocale=" + utl::ConfigManager::getUILocale());
+ sfx2::openUriExternally(sURL, false, rReq.GetFrameWeld());
+ break;
+ }
+ case SID_DONATION:
+ {
+ // Open donation page based on language + script (BCP47) with language as fall back.
+ OUString aLang = LanguageTag(utl::ConfigManager::getUILocale()).getLanguage();
+ OUString aBcp47 = LanguageTag(utl::ConfigManager::getUILocale()).getBcp47();
+ OUString sURL(officecfg::Office::Common::Menus::DonationURL::get() + //https://hub.libreoffice.org/donation/
+ "?BCP47=" + aBcp47 + "&LOlang=" + aLang );
+ sfx2::openUriExternally(sURL, false, rReq.GetFrameWeld());
+ break;
+ }
+ case SID_WHATSNEW:
+ {
+ // Open release notes depending on version and locale
+ OUString sURL(officecfg::Office::Common::Menus::ReleaseNotesURL::get() + //https://hub.libreoffice.org/ReleaseNotes/
+ "?LOvers=" + utl::ConfigManager::getProductVersion() +
+ "&LOlocale=" + LanguageTag(utl::ConfigManager::getUILocale()).getBcp47() );
+ sfx2::openUriExternally(sURL, false, rReq.GetFrameWeld());
+ break;
+ }
+ case SID_HYPHENATIONMISSING:
+ {
+ // Open wiki page about hyphenation
+ OUString sURL(officecfg::Office::Common::Menus::HyphenationMissingURL::get() + //https://hub.libreoffice.org/HyphenationMissing/
+ "?LOlocale=" + utl::ConfigManager::getUILocale());
+ sfx2::openUriExternally(sURL, false, rReq.GetFrameWeld());
+ break;
+ }
+#endif
+ case SID_SHOW_LICENSE:
+ {
+ LicenseDialog aDialog(rReq.GetFrameWeld());
+ aDialog.run();
+ break;
+ }
+
+ case SID_SHOW_CREDITS:
+ {
+ showDocument( "CREDITS" );
+ break;
+ }
+
+ case FN_CHANGE_THEME:
+ {
+ const SfxStringItem* pNewThemeArg = rReq.GetArg<SfxStringItem>(FN_PARAM_NEW_THEME);
+ if (!pNewThemeArg)
+ {
+ SAL_WARN("sfx.appl", "FN_CHANGE_THEME: no theme name");
+ break;
+ }
+ const OUString& rSchemeName = pNewThemeArg->GetValue();
+ svtools::EditableColorConfig aEditableConfig;
+ // kit explicitly ignores changes to the global color scheme, except for the current ViewShell,
+ // so an attempted change to the same global color scheme when the now current ViewShell ignored
+ // the last change requires re-sending the change. In which case individual shells will have to
+ // decide if this color-scheme change is a change from their perspective to avoid unnecessary
+ // invalidations.
+ if (aEditableConfig.GetCurrentSchemeName() != rSchemeName || comphelper::LibreOfficeKit::isActive())
+ aEditableConfig.LoadScheme(rSchemeName);
+ break;
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ case SID_HELPINDEX:
+ {
+ Help* pHelp = Application::GetHelp();
+ if ( pHelp )
+ {
+ pHelp->Start(".uno:HelpIndex", rReq.GetFrameWeld()); // show start page
+ bDone = true;
+ }
+ break;
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ case SID_HELPTIPS:
+ {
+ // Evaluate Parameter
+ const SfxBoolItem* pOnItem = rReq.GetArg<SfxBoolItem>(SID_HELPTIPS);
+ bool bOn = pOnItem
+ ? pOnItem->GetValue()
+ : !Help::IsQuickHelpEnabled();
+
+ if ( bOn )
+ Help::EnableQuickHelp();
+ else
+ Help::DisableQuickHelp();
+ auto xChanges = comphelper::ConfigurationChanges::create();
+ officecfg::Office::Common::Help::Tip::set(bOn, xChanges);
+ xChanges->commit();
+ Invalidate(SID_HELPTIPS);
+ bDone = true;
+
+ // Record if possible
+ if ( !rReq.IsAPI() )
+ rReq.AppendItem( SfxBoolItem( SID_HELPTIPS, bOn) );
+ break;
+ }
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ case SID_EXTENDEDHELP:
+ {
+ Help::StartExtHelp();
+ break;
+ }
+ case SID_HELPBALLOONS:
+ {
+ // Evaluate Parameter
+ const SfxBoolItem* pOnItem = rReq.GetArg<SfxBoolItem>(SID_HELPBALLOONS);
+ bool bOn = pOnItem
+ ? pOnItem->GetValue()
+ : !Help::IsBalloonHelpEnabled();
+
+ if ( bOn )
+ Help::EnableBalloonHelp();
+ else
+ Help::DisableBalloonHelp();
+ auto xChanges = comphelper::ConfigurationChanges::create();
+ officecfg::Office::Common::Help::ExtendedTip::set(bOn, xChanges);
+ xChanges->commit();
+ Invalidate(SID_HELPBALLOONS);
+ bDone = true;
+
+ // Record if possible
+ if ( !rReq.IsAPI() )
+ rReq.AppendItem( SfxBoolItem( SID_HELPBALLOONS, bOn) );
+ break;
+ }
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if !ENABLE_WASM_STRIP_PINGUSER
+ case SID_TIPOFTHEDAY:
+ {
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateTipOfTheDayDialog(rReq.GetFrameWeld()));
+ pDlg->StartExecuteAsync(nullptr);
+ bDone = true;
+ break;
+ }
+#endif
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ case SID_WIDGET_TEST_DIALOG:
+ {
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ VclPtr<VclAbstractDialog> pDlg(pFact->CreateWidgetTestDialog(rReq.GetFrameWeld()));
+ pDlg->StartExecuteAsync([pDlg](sal_Int32 /*nResult*/){
+ pDlg->disposeOnce();
+ });
+ bDone = true;
+ break;
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ case SID_ABOUT:
+ {
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateAboutDialog(rReq.GetFrameWeld()));
+ pDlg->StartExecuteAsync(nullptr);
+ bDone = true;
+ break;
+ }
+
+ case SID_TEMPLATE_MANAGER:
+ {
+ SfxTemplateManagerDlg aDialog(rReq.GetFrameWeld());
+ aDialog.run();
+ bDone = true;
+ break;
+ }
+
+ case SID_TEMPLATE_ADDRESSBOOKSOURCE:
+ {
+ svt::AddressBookSourceDialog aDialog(rReq.GetFrameWeld(), ::comphelper::getProcessComponentContext());
+ aDialog.run();
+ bDone = true;
+ break;
+ }
+
+#if HAVE_FEATURE_SCRIPTING
+ case SID_BASICSTOP:
+ StarBASIC::Stop();
+ break;
+
+ case SID_BASICBREAK :
+ BasicDLL::BasicBreak();
+ break;
+#endif
+
+ case SID_ZOOM_50_PERCENT:
+ case SID_ZOOM_75_PERCENT:
+ case SID_ZOOM_100_PERCENT:
+ case SID_ZOOM_150_PERCENT:
+ case SID_ZOOM_200_PERCENT:
+ case SID_ZOOM_OPTIMAL:
+ case SID_ZOOM_ENTIRE_PAGE:
+ case SID_ZOOM_PAGE_WIDTH:
+ {
+ SfxObjectShell* pCurrentShell = SfxObjectShell::Current();
+ if (!pCurrentShell)
+ return;
+
+ // make sure aZoom is initialized with a proper value if SetType
+ // doesn't work
+ SvxZoomItem aZoom( SvxZoomType::PERCENT, 100 );
+
+ switch (rReq.GetSlot())
+ {
+ case SID_ZOOM_50_PERCENT:
+ aZoom.SetValue(50);
+ break;
+ case SID_ZOOM_75_PERCENT:
+ aZoom.SetValue(75);
+ break;
+ case SID_ZOOM_100_PERCENT:
+ aZoom.SetValue(100);
+ break;
+ case SID_ZOOM_150_PERCENT:
+ aZoom.SetValue(150);
+ break;
+ case SID_ZOOM_200_PERCENT:
+ aZoom.SetValue(200);
+ break;
+ case SID_ZOOM_OPTIMAL:
+ aZoom.SetType( SvxZoomType::OPTIMAL );
+ break;
+ case SID_ZOOM_ENTIRE_PAGE:
+ aZoom.SetType( SvxZoomType::WHOLEPAGE );
+ break;
+ case SID_ZOOM_PAGE_WIDTH:
+ aZoom.SetType( SvxZoomType::PAGEWIDTH );
+ break;
+ }
+
+ pCurrentShell->GetDispatcher()->ExecuteList(SID_ATTR_ZOOM, SfxCallMode::ASYNCHRON, { &aZoom });
+
+ break;
+ }
+ case SID_TOOLBAR_MODE:
+ {
+ const SfxStringItem* pModeName = rReq.GetArg<SfxStringItem>( SID_TOOLBAR_MODE );
+
+ if ( !pModeName )
+ {
+ bDone = true;
+ break;
+ }
+
+ OUString aNewName(pModeName->GetValue());
+ uno::Reference< uno::XComponentContext > xContext =
+ ::comphelper::getProcessComponentContext();
+
+ // Get information about current frame and module
+ Reference<XFrame> xCurrentFrame;
+ vcl::EnumContext::Application eCurrentApp = vcl::EnumContext::Application::NONE;
+ OUString aCurrentMode;
+
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (pViewFrame)
+ {
+ xCurrentFrame = pViewFrame->GetFrame().GetFrameInterface();
+
+ const Reference<frame::XModuleManager> xModuleManager = frame::ModuleManager::create( xContext );
+ eCurrentApp = vcl::EnumContext::GetApplicationEnum( xModuleManager->identify( xCurrentFrame ) );
+
+ OUString aPath = "org.openoffice.Office.UI.ToolbarMode/Applications/" +
+ lcl_getAppName( eCurrentApp );
+
+ const utl::OConfigurationTreeRoot aAppNode(
+ xContext,
+ aPath,
+ true);
+ if ( !aAppNode.isValid() )
+ {
+ bDone = true;
+ break;
+ }
+
+ aCurrentMode = comphelper::getString( aAppNode.getNodeValue( "Active" ) );
+
+ if ( !comphelper::LibreOfficeKit::isActive() && aCurrentMode == aNewName )
+ {
+ bDone = true;
+ break;
+ }
+
+ // Save new toolbar mode for a current module
+ aAppNode.setNodeValue( "Active", Any( aNewName ) );
+ aAppNode.commit();
+ }
+
+ // Apply settings for all frames
+ pViewFrame = SfxViewFrame::GetFirst();
+ while( pViewFrame )
+ {
+ // in LOK case we want to apply changes only to the current view
+ if (comphelper::LibreOfficeKit::isActive() &&
+ pViewFrame != &SfxViewShell::Current()->GetViewFrame())
+ {
+ pViewFrame = SfxViewFrame::GetNext( *pViewFrame );
+ continue;
+ }
+
+ Reference<XFrame> xFrame = pViewFrame->GetFrame().GetFrameInterface();
+
+ // We want to change mode only for a current app module, ignore other apps
+ const Reference<frame::XModuleManager> xModuleManager = frame::ModuleManager::create( xContext );
+ vcl::EnumContext::Application eApp = vcl::EnumContext::GetApplicationEnum( xModuleManager->identify( xFrame ) );
+ if ( eApp != eCurrentApp )
+ {
+ pViewFrame = SfxViewFrame::GetNext( *pViewFrame );
+ continue;
+ }
+
+ Reference<css::beans::XPropertySet> xPropSet( xFrame, UNO_QUERY );
+ Reference<css::frame::XLayoutManager> xLayoutManager;
+ if ( xPropSet.is() )
+ {
+ try
+ {
+ Any aValue = xPropSet->getPropertyValue( "LayoutManager" );
+ aValue >>= xLayoutManager;
+ }
+ catch ( const css::uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( css::uno::Exception& )
+ {
+ }
+ }
+
+ if ( xLayoutManager.is() )
+ {
+ css::uno::Sequence<OUString> aMandatoryToolbars;
+ css::uno::Sequence<OUString> aUserToolbars;
+ std::vector<OUString> aBackupList;
+ OUString aSidebarMode;
+
+ OUString aPath = "org.openoffice.Office.UI.ToolbarMode/Applications/" +
+ lcl_getAppName( eApp ) +
+ "/Modes";
+
+ // Read mode settings
+ const utl::OConfigurationTreeRoot aModesNode(
+ xContext,
+ aPath,
+ true);
+ if ( !aModesNode.isValid() )
+ {
+ bDone = true;
+ break;
+ }
+
+ const Sequence<OUString> aModeNodeNames( aModesNode.getNodeNames() );
+
+ for ( const auto& rModeNodeName : aModeNodeNames )
+ {
+ const utl::OConfigurationNode aModeNode( aModesNode.openNode( rModeNodeName ) );
+ if ( !aModeNode.isValid() )
+ continue;
+
+ OUString aCommandArg = comphelper::getString( aModeNode.getNodeValue( "CommandArg" ) );
+
+ if ( aCommandArg == aNewName )
+ {
+ aMandatoryToolbars = aModeNode.getNodeValue( "Toolbars" ).get< uno::Sequence<OUString> >();
+ aUserToolbars = aModeNode.getNodeValue( "UserToolbars" ).get< uno::Sequence<OUString> >();
+ aSidebarMode = comphelper::getString( aModeNode.getNodeValue( "Sidebar" ) );
+ break;
+ }
+ }
+
+ // Backup visible toolbar list and hide all toolbars
+ const Sequence<Reference<XUIElement>> aUIElements = xLayoutManager->getElements();
+ for ( const Reference< XUIElement >& xUIElement : aUIElements )
+ {
+ Reference< XPropertySet > xPropertySet( xUIElement, UNO_QUERY );
+ if ( xPropertySet.is() && xUIElement.is() )
+ {
+ try
+ {
+ OUString aResName;
+ sal_Int16 nType( -1 );
+ xPropertySet->getPropertyValue( "Type" ) >>= nType;
+ xPropertySet->getPropertyValue( "ResourceURL" ) >>= aResName;
+
+ if (( nType == css::ui::UIElementType::TOOLBAR ) &&
+ !aResName.isEmpty() )
+ {
+ if ( xLayoutManager->isElementVisible( aResName ) )
+ {
+ aBackupList.push_back( aResName );
+ }
+ xLayoutManager->hideElement( aResName );
+ }
+ }
+ catch ( const Exception& )
+ {
+ }
+ }
+ }
+
+ // Show/Hide the Notebookbar
+ const SfxStringItem pItem(SID_NOTEBOOKBAR, aNewName);
+ pViewFrame->GetDispatcher()->ExecuteList(SID_NOTEBOOKBAR, SfxCallMode::SYNCHRON, {&pItem});
+ SfxPoolItemHolder aNbItem;
+ pViewFrame->GetDispatcher()->QueryState(SID_NOTEBOOKBAR, aNbItem);
+
+ // Show toolbars
+ for ( const OUString& rName : std::as_const(aMandatoryToolbars) )
+ {
+ xLayoutManager->createElement( rName );
+ xLayoutManager->showElement( rName );
+ }
+
+ for ( const OUString& rName : std::as_const(aUserToolbars) )
+ {
+ xLayoutManager->createElement( rName );
+ xLayoutManager->showElement( rName );
+ }
+
+ // Sidebar
+ pViewFrame->ShowChildWindow( SID_SIDEBAR );
+
+ if (comphelper::LibreOfficeKit::isActive())
+ aSidebarMode = "Opened";
+
+ sfx2::sidebar::SidebarController* pSidebar =
+ sfx2::sidebar::SidebarController::GetSidebarControllerForFrame( xFrame );
+ if ( pSidebar )
+ {
+ if ( aSidebarMode == "Arrow" )
+ {
+ pSidebar->FadeOut();
+ }
+ else if ( aSidebarMode == "Tabs" )
+ {
+ pSidebar->FadeIn();
+ pSidebar->RequestOpenDeck();
+ pSidebar->RequestCloseDeck();
+ }
+ else if ( aSidebarMode == "Opened" )
+ {
+ pSidebar->FadeIn();
+ pSidebar->RequestOpenDeck();
+ }
+ }
+
+ // Save settings
+ if ( pViewFrame == SfxViewFrame::Current() )
+ {
+ css::uno::Sequence<OUString> aBackup( comphelper::containerToSequence(aBackupList) );
+
+ for ( const auto& rModeNodeName : aModeNodeNames )
+ {
+ const utl::OConfigurationNode aModeNode( aModesNode.openNode( rModeNodeName ) );
+ if ( !aModeNode.isValid() )
+ continue;
+
+ OUString aCommandArg = comphelper::getString( aModeNode.getNodeValue( "CommandArg" ) );
+
+ if ( aCommandArg == aCurrentMode )
+ {
+ aModeNode.setNodeValue( "UserToolbars", Any( aBackup ) );
+ break;
+ }
+ }
+ aModesNode.commit();
+ }
+ }
+
+ pViewFrame = SfxViewFrame::GetNext(*pViewFrame);
+ }
+
+ bDone = true;
+ break;
+ }
+ case SID_TOOLBAR_MODE_UI:
+ {
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDlg(
+ pFact->CreateToolbarmodeDialog(rReq.GetFrameWeld()));
+ pDlg->Execute();
+ bDone = true;
+ break;
+ }
+ case SID_AVAILABLE_TOOLBARS:
+ {
+ const SfxStringItem* pToolbarName = rReq.GetArg<SfxStringItem>(SID_AVAILABLE_TOOLBARS);
+
+ if ( pToolbarName )
+ {
+ Reference < XDesktop2 > xDesktop = Desktop::create ( ::comphelper::getProcessComponentContext() );
+ Reference< XFrame > xFrame = xDesktop->getActiveFrame();
+
+ Reference< css::beans::XPropertySet > xPropSet( xFrame, UNO_QUERY );
+ Reference< css::frame::XLayoutManager > xLayoutManager;
+ if ( xPropSet.is() )
+ {
+ try
+ {
+ Any aValue = xPropSet->getPropertyValue("LayoutManager");
+ aValue >>= xLayoutManager;
+ }
+ catch ( const css::uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( css::uno::Exception& )
+ {
+ }
+ }
+
+ if ( xLayoutManager.is() )
+ {
+ OUString aToolbarName = "private:resource/toolbar/" +
+ pToolbarName->GetValue();
+
+ // Evaluate Parameter
+ bool bShow( !xLayoutManager->isElementVisible( aToolbarName ));
+
+ if ( bShow )
+ {
+ xLayoutManager->createElement( aToolbarName );
+ xLayoutManager->showElement( aToolbarName );
+ }
+ else
+ xLayoutManager->hideElement( aToolbarName );
+ }
+ }
+
+ bDone = true;
+ break;
+ }
+ case SID_MENUBAR:
+ {
+ sfx2::SfxNotebookBar::ToggleMenubar();
+ bDone = true;
+ break;
+ }
+ case SID_DEVELOPMENT_TOOLS_DOCKING_WINDOW:
+ {
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+ SfxViewFrame& rViewFrame = pViewShell->GetViewFrame();
+ auto nID = rReq.GetSlot();
+ rViewFrame.ToggleChildWindow(nID);
+
+ bDone = true;
+ break;
+ }
+ case SID_INSPECT_SELECTED_OBJECT:
+ {
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+ SfxViewFrame& rViewFrame = pViewShell->GetViewFrame();
+
+ rViewFrame.ShowChildWindow(SID_DEVELOPMENT_TOOLS_DOCKING_WINDOW, true);
+
+ SfxChildWindow* pChild = rViewFrame.GetChildWindow(SID_DEVELOPMENT_TOOLS_DOCKING_WINDOW);
+ if (!pChild)
+ return;
+
+ auto pDockingWin = dynamic_cast<DevelopmentToolDockingWindow*>(pChild->GetWindow());
+ if (pDockingWin)
+ {
+ pDockingWin->changeToCurrentSelection();
+ }
+
+ bDone = true;
+ break;
+ }
+ case SID_SAFE_MODE:
+ {
+ SafeModeQueryDialog aDialog(rReq.GetFrameWeld());
+ aDialog.run();
+ break;
+ }
+ case SID_TOOLBAR_LOCK:
+ {
+ if (SfxViewFrame* pViewFrame = SfxViewFrame::Current())
+ {
+ Reference<XFrame> xCurrentFrame;
+ uno::Reference<uno::XComponentContext> xContext
+ = ::comphelper::getProcessComponentContext();
+ xCurrentFrame = pViewFrame->GetFrame().GetFrameInterface();
+ const Reference<frame::XModuleManager> xModuleManager
+ = frame::ModuleManager::create(xContext);
+ const utl::OConfigurationTreeRoot aAppNode(
+ xContext, "org.openoffice.Office.UI.GlobalSettings/Toolbars/States", true);
+ if (aAppNode.isValid())
+ {
+ bool isLocked = comphelper::getBOOL(aAppNode.getNodeValue("Locked"));
+ aAppNode.setNodeValue("Locked", Any(!isLocked));
+ aAppNode.commit();
+ //TODO: apply immediately w/o restart needed
+ SolarMutexGuard aGuard;
+ svtools::executeRestartDialog(comphelper::getProcessComponentContext(), nullptr,
+ svtools::RESTART_REASON_UI_CHANGE);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if ( bDone )
+ rReq.Done();
+}
+
+void SfxApplication::MiscState_Impl(SfxItemSet &rSet)
+{
+ const WhichRangesContainer & pRanges = rSet.GetRanges();
+ DBG_ASSERT(!pRanges.empty(), "Set without range");
+ for ( auto const & pRange : pRanges )
+ {
+ for(sal_uInt16 nWhich = pRange.first; nWhich <= pRange.second; ++nWhich)
+ {
+ switch(nWhich)
+ {
+ case SID_TEMPLATE_ADDRESSBOOKSOURCE:
+ if ( !SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::DATABASE) )
+ rSet.Put(SfxVisibilityItem(nWhich, false));
+ break;
+ case SID_QUITAPP:
+ {
+ if ( pImpl->nDocModalMode )
+ rSet.DisableItem(nWhich);
+ else
+ rSet.Put(SfxStringItem(nWhich, SfxResId(STR_QUITAPP)));
+ break;
+ }
+
+ case SID_CONFIG:
+ case SID_TOOLBOXOPTIONS:
+ case SID_CONFIGSTATUSBAR:
+ case SID_CONFIGMENU:
+ case SID_CONFIGACCEL:
+ case SID_CONFIGEVENT:
+ {
+ if( officecfg::Office::Common::Misc::DisableUICustomization::get() )
+ rSet.DisableItem(nWhich);
+ break;
+ }
+
+#if HAVE_FEATURE_SCRIPTING
+ case SID_BASICSTOP:
+ if ( !StarBASIC::IsRunning() )
+ rSet.DisableItem(nWhich);
+ break;
+#endif
+
+ case SID_HELPTIPS:
+ {
+ rSet.Put( SfxBoolItem( SID_HELPTIPS, Help::IsQuickHelpEnabled() ) );
+ }
+ break;
+ case SID_HELPBALLOONS:
+ {
+ rSet.Put( SfxBoolItem( SID_HELPBALLOONS, Help::IsBalloonHelpEnabled() ) );
+ }
+ break;
+
+ case SID_EXTENDEDHELP:
+ {
+ }
+ break;
+
+ case SID_CLOSEDOCS:
+ {
+ Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
+ Reference< XIndexAccess > xTasks = xDesktop->getFrames();
+ if ( !xTasks.is() || !xTasks->getCount() )
+ rSet.DisableItem(nWhich);
+ break;
+ }
+
+ case SID_SAVEDOCS:
+ {
+ bool bModified = false;
+ for ( SfxObjectShell *pObjSh = SfxObjectShell::GetFirst();
+ pObjSh;
+ pObjSh = SfxObjectShell::GetNext( *pObjSh ) )
+ {
+ if ( pObjSh->IsModified() && !pObjSh->isSaveLocked() )
+ {
+ bModified = true;
+ break;
+ }
+ }
+
+ if ( !bModified )
+ rSet.DisableItem( nWhich );
+ break;
+ }
+
+ case SID_TEMPLATE_MANAGER:
+ {
+ if ( !officecfg::Office::Common::Misc::ExperimentalMode::get() )
+ {
+ rSet.DisableItem( nWhich );
+ rSet.Put( SfxVisibilityItem( nWhich, false ) );
+ }
+ }
+ break;
+
+ case SID_ZOOM_50_PERCENT:
+ case SID_ZOOM_75_PERCENT:
+ case SID_ZOOM_100_PERCENT:
+ case SID_ZOOM_150_PERCENT:
+ case SID_ZOOM_200_PERCENT:
+ case SID_ZOOM_OPTIMAL:
+ case SID_ZOOM_ENTIRE_PAGE:
+ case SID_ZOOM_PAGE_WIDTH:
+ {
+ SfxObjectShell* pCurrentShell(SfxObjectShell::Current());
+
+ SfxPoolItemHolder aResult;
+ const SfxItemState aState(pCurrentShell ?
+ pCurrentShell->GetDispatcher()->QueryState(SID_ATTR_ZOOM, aResult) : SfxItemState::DISABLED);
+ if ( aState == SfxItemState::DISABLED )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_MENUBAR:
+ {
+ Reference < XDesktop2 > xDesktop = Desktop::create ( ::comphelper::getProcessComponentContext() );
+ Reference< XFrame > xFrame = xDesktop->getActiveFrame();
+
+ Reference< css::beans::XPropertySet > xPropSet( xFrame, UNO_QUERY );
+ Reference< css::frame::XLayoutManager > xLayoutManager;
+ if ( xPropSet.is() )
+ {
+ try
+ {
+ Any aValue = xPropSet->getPropertyValue("LayoutManager");
+ aValue >>= xLayoutManager;
+ }
+ catch ( const css::uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( css::uno::Exception& )
+ {
+ }
+ }
+
+ if ( xLayoutManager.is() )
+ {
+ const bool bState
+ = xLayoutManager->getElement("private:resource/menubar/menubar").is()
+ && xLayoutManager->isElementVisible(
+ "private:resource/menubar/menubar");
+
+ SfxBoolItem aItem( SID_MENUBAR, bState );
+ rSet.Put( aItem );
+ }
+ break;
+ }
+ case SID_SAFE_MODE:
+ {
+ // no restart in safe mode when already in safe mode
+ if ( Application::IsSafeModeEnabled() )
+ rSet.DisableItem( SID_SAFE_MODE );
+ break;
+ }
+ case SID_DEVELOPMENT_TOOLS_DOCKING_WINDOW:
+ {
+ bool bSuccess = false;
+ auto* pViewShell = SfxViewShell::Current();
+ if (pViewShell)
+ {
+ auto& rViewFrame = pViewShell->GetViewFrame();
+ if (rViewFrame.KnowsChildWindow(nWhich))
+ {
+ rSet.Put(SfxBoolItem(nWhich, rViewFrame.HasChildWindow(nWhich)));
+ bSuccess = true;
+ }
+ }
+
+ if (!bSuccess)
+ rSet.DisableItem(nWhich);
+ }
+ break;
+ case SID_INSPECT_SELECTED_OBJECT:
+ {
+ bool bSuccess = false;
+ auto* pViewShell = SfxViewShell::Current();
+ if (pViewShell)
+ {
+ auto& rViewFrame = pViewShell->GetViewFrame();
+ if (rViewFrame.KnowsChildWindow(SID_DEVELOPMENT_TOOLS_DOCKING_WINDOW))
+ {
+ bSuccess = true;
+ }
+ }
+ if (!bSuccess)
+ rSet.DisableItem(nWhich);
+ }
+ break;
+ case SID_TOOLBAR_LOCK:
+ {
+ rSet.Put( SfxBoolItem( SID_TOOLBAR_LOCK, ToolBox::AlwaysLocked() ));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+#if HAVE_FEATURE_SCRIPTING
+
+#ifndef DISABLE_DYNLOADING
+
+typedef rtl_uString* (*basicide_choose_macro)(void*, void*, void*, sal_Bool);
+
+#else
+
+extern "C" rtl_uString* basicide_choose_macro(void*, void*, void*, sal_Bool);
+
+#endif
+
+static OUString ChooseMacro(weld::Window* pParent, const Reference<XModel>& rxLimitToDocument, const Reference<XFrame>& xDocFrame, bool bChooseOnly)
+{
+#ifndef DISABLE_DYNLOADING
+ basicide_choose_macro pSymbol = reinterpret_cast<basicide_choose_macro>(sfx2::getBasctlFunction("basicide_choose_macro"));
+#else
+#define pSymbol basicide_choose_macro
+#endif
+
+ // call basicide_choose_macro in basctl
+ rtl_uString* pScriptURL = pSymbol(pParent, rxLimitToDocument.get(), xDocFrame.get(), bChooseOnly);
+ OUString aScriptURL( pScriptURL );
+ rtl_uString_release( pScriptURL );
+ return aScriptURL;
+
+#ifdef DISABLE_DYNLOADING
+#undef pSymbol
+#endif
+}
+
+#endif
+
+namespace
+{
+#if HAVE_FEATURE_SCRIPTING
+ weld::Window* lcl_getDialogParent(const Reference<XFrame>& rxFrame)
+ {
+ Reference<awt::XWindow> xContainerWindow;
+ if (rxFrame.is())
+ xContainerWindow = rxFrame->getContainerWindow();
+ return Application::GetFrameWeld(xContainerWindow);
+ }
+
+ SfxViewFrame* lcl_getBasicIDEViewFrame( SfxObjectShell const * i_pBasicIDE )
+ {
+ SfxViewFrame* pView = SfxViewFrame::GetFirst( i_pBasicIDE );
+ while ( pView )
+ {
+ if ( pView->GetObjectShell()->GetFactory().GetDocumentServiceName() == "com.sun.star.script.BasicIDE" )
+ break;
+ pView = SfxViewFrame::GetNext( *pView, i_pBasicIDE );
+ }
+ return pView;
+ }
+ Reference< XFrame > lcl_findStartModuleFrame( const Reference<XComponentContext> & rxContext )
+ {
+ try
+ {
+ Reference < XDesktop2 > xDesktop = Desktop::create( rxContext );
+ Reference < XIndexAccess > xContainer( xDesktop->getFrames(), UNO_QUERY_THROW );
+
+ Reference< XModuleManager2 > xCheck = ModuleManager::create(rxContext);
+
+ sal_Int32 nCount = xContainer->getCount();
+ for ( sal_Int32 i=0; i<nCount; ++i )
+ {
+ try
+ {
+ Reference < XFrame > xFrame( xContainer->getByIndex(i), UNO_QUERY_THROW );
+ OUString sModule = xCheck->identify( xFrame );
+ if ( sModule == "com.sun.star.frame.StartModule" )
+ return xFrame;
+ }
+ catch( const UnknownModuleException& )
+ {
+ // silence
+ }
+ catch(const Exception&)
+ {
+ // re-throw, caught below
+ throw;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("sfx.appl");
+ }
+ return nullptr;
+ }
+#endif // HAVE_FEATURE_SCRIPTING
+}
+
+void SfxApplication::OfaExec_Impl( SfxRequest& rReq )
+{
+ switch ( rReq.GetSlot() )
+ {
+ case SID_OPTIONS_TREEDIALOG:
+ {
+ OUString sPageURL;
+ const SfxStringItem* pURLItem = rReq.GetArg<SfxStringItem>(SID_OPTIONS_PAGEURL);
+ if ( pURLItem )
+ sPageURL = pURLItem->GetValue();
+
+ sal_uInt16 nPageID = 0;
+ const SfxUInt16Item* pIDItem = rReq.GetArg<SfxUInt16Item>(SID_OPTIONS_PAGEID);
+ if (pIDItem)
+ nPageID = pIDItem->GetValue();
+
+ Reference <XFrame> xFrame(GetRequestFrame(rReq));
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ VclPtr<VclAbstractDialog> pDlg =
+ pFact->CreateFrameDialog(rReq.GetFrameWeld(), xFrame, rReq.GetSlot(), nPageID, sPageURL);
+ short nRet = pDlg->Execute();
+ pDlg.disposeAndClear();
+ SfxViewFrame* pView = SfxViewFrame::GetFirst();
+ while ( pView )
+ {
+ if (nRet == RET_OK)
+ {
+ SfxObjectShell* pObjSh = pView->GetObjectShell();
+ if (pObjSh)
+ pObjSh->SetConfigOptionsChecked(false);
+ }
+ pView->GetBindings().InvalidateAll(false);
+ pView = SfxViewFrame::GetNext( *pView );
+ }
+ break;
+ }
+
+ case SID_MORE_DICTIONARIES:
+ {
+ uno::Sequence<beans::PropertyValue> aArgs{ comphelper::makePropertyValue(
+ "AdditionsTag", OUString("Dictionary")) };
+ comphelper::dispatchCommand(".uno:AdditionsDialog", aArgs);
+ break;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ case SID_BASICIDE_APPEAR:
+ {
+ SfxViewFrame* pView = lcl_getBasicIDEViewFrame( nullptr );
+ if ( !pView )
+ {
+ SfxObjectShell* pBasicIDE = SfxObjectShell::CreateObject( "com.sun.star.script.BasicIDE" );
+ pBasicIDE->DoInitNew();
+ pBasicIDE->SetModified( false );
+ try
+ {
+ // load the Basic IDE via direct access to the SFX frame loader. A generic loadComponentFromURL
+ // (which could be done via SfxViewFrame::LoadDocumentIntoFrame) is not feasible here, since the Basic IDE
+ // does not really play nice with the framework's concept. For instance, it is a "singleton document",
+ // which conflicts, at the latest, with the framework's concept of loading into _blank frames.
+ // So, since we know that our frame loader can handle it, we skip the generic framework loader
+ // mechanism, and the type detection (which doesn't know about the Basic IDE).
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference< XSynchronousFrameLoader > xLoader(
+ xContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.office.FrameLoader", xContext),
+ UNO_QUERY_THROW );
+ ::comphelper::NamedValueCollection aLoadArgs;
+ aLoadArgs.put( "Model", pBasicIDE->GetModel() );
+ aLoadArgs.put( "URL", OUString( "private:factory/sbasic" ) );
+
+ Reference< XFrame > xTargetFrame( lcl_findStartModuleFrame( xContext ) );
+ if ( !xTargetFrame.is() )
+ xTargetFrame = SfxFrame::CreateBlankFrame();
+ ENSURE_OR_THROW( xTargetFrame.is(), "could not obtain a frameto load the Basic IDE into!" );
+
+ xLoader->load( aLoadArgs.getPropertyValues(), xTargetFrame );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("sfx.appl");
+ }
+
+ pView = lcl_getBasicIDEViewFrame( pBasicIDE );
+ if ( pView )
+ pView->SetName( "BASIC:1" );
+ }
+
+ if ( pView )
+ pView->GetFrame().Appear();
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if ( pArgs && pView )
+ {
+ SfxViewShell* pViewShell = pView->GetViewShell();
+ SfxObjectShell* pObjShell = pView->GetObjectShell();
+ if ( pViewShell && pObjShell )
+ {
+ SfxRequest aReq( SID_BASICIDE_SHOWWINDOW, SfxCallMode::SYNCHRON, pObjShell->GetPool() );
+ aReq.SetArgs( *pArgs );
+ pViewShell->ExecuteSlot( aReq );
+ }
+ }
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_BASICCHOOSER:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ const SfxBoolItem* pItem;
+ bool bChooseOnly = false;
+ Reference< XModel > xLimitToModel;
+ if(pArgs && (pItem = pArgs->GetItemIfSet(SID_RECORDMACRO, false)) )
+ {
+ bool bRecord = pItem->GetValue();
+ if ( bRecord )
+ {
+ // !Hack
+ bChooseOnly = false;
+ SfxObjectShell* pCurrentShell = SfxObjectShell::Current();
+ OSL_ENSURE( pCurrentShell, "macro recording outside an SFX document?" );
+ if ( pCurrentShell )
+ xLimitToModel = pCurrentShell->GetModel();
+ }
+ }
+
+ Reference <XFrame> xFrame(GetRequestFrame(rReq));
+ rReq.SetReturnValue(SfxStringItem(rReq.GetSlot(), ChooseMacro(rReq.GetFrameWeld(), xLimitToModel, xFrame, bChooseOnly)));
+ rReq.Done();
+ }
+ break;
+
+ case SID_MACROORGANIZER:
+ {
+ SAL_INFO("sfx.appl", "handling SID_MACROORGANIZER");
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ sal_Int16 nTabId = 0;
+ Reference <XFrame> xFrame;
+ if (pArgs)
+ {
+ if (const SfxUInt16Item* pItem = pArgs->GetItemIfSet(SID_MACROORGANIZER, false))
+ nTabId = pItem->GetValue();
+ if (const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_2))
+ {
+ // if set then default to showing the macros of the document associated
+ // with this frame
+ if (pItem->GetValue())
+ xFrame = GetRequestFrame(rReq);
+ }
+ }
+ SfxApplication::MacroOrganizer(rReq.GetFrameWeld(), xFrame, nTabId);
+ rReq.Done();
+ }
+ break;
+
+ case SID_RUNMACRO:
+ {
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ SAL_INFO("sfx.appl", "SfxApplication::OfaExec_Impl: case ScriptOrg");
+
+ Reference <XFrame> xFrame(GetRequestFrame(rReq));
+ if ( !xFrame.is() )
+ {
+ if (const SfxViewFrame* pViewFrame = SfxViewFrame::Current())
+ xFrame = pViewFrame->GetFrame().GetFrameInterface();
+ }
+
+ do // artificial loop for flow control
+ {
+ VclPtr<AbstractScriptSelectorDialog> pDlg(pFact->CreateScriptSelectorDialog(lcl_getDialogParent(xFrame), xFrame));
+ OSL_ENSURE( pDlg, "SfxApplication::OfaExec_Impl( SID_RUNMACRO ): no dialog!" );
+ if ( !pDlg )
+ break;
+ pDlg->SetRunLabel();
+
+ pDlg->StartExecuteAsync([pDlg, xFrame](sal_Int32 nDialogResult) {
+ if ( !nDialogResult )
+ {
+ pDlg->disposeOnce();
+ return;
+ }
+
+ Sequence< Any > args;
+ Sequence< sal_Int16 > outIndex;
+ Sequence< Any > outArgs;
+ Any ret;
+
+ Reference< XInterface > xScriptContext;
+
+ Reference< XController > xController;
+ if ( xFrame.is() )
+ xController = xFrame->getController();
+ if ( xController.is() )
+ xScriptContext = xController->getModel();
+ if ( !xScriptContext.is() )
+ xScriptContext = xController;
+
+ SfxObjectShell::CallXScript( xScriptContext, pDlg->GetScriptURL(), args, ret, outIndex, outArgs );
+ pDlg->disposeOnce();
+ });
+ }
+ while ( false );
+ rReq.Done();
+ }
+ break;
+
+ case SID_SCRIPTORGANIZER:
+ {
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ SAL_INFO("sfx.appl", "SfxApplication::OfaExec_Impl: case ScriptOrg");
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ const SfxScriptOrganizerItem* pItem;
+ OUString aLanguage;
+ if(pArgs && (pItem = pArgs->GetItemIfSet(SID_SCRIPTORGANIZER, false) ))
+ {
+ aLanguage = pItem->getLanguage();
+ }
+
+ OUString aLang( aLanguage );
+ SAL_INFO("sfx.appl", "SfxApplication::OfaExec_Impl: about to create dialog for: " << aLang);
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateSvxScriptOrgDialog(rReq.GetFrameWeld(), aLanguage));
+ if( pDlg )
+ {
+ pDlg->Execute();
+ }
+ else
+ {
+ SAL_WARN("sfx.appl", "no dialog!!!");
+ }
+ rReq.Done();
+ }
+ break;
+#endif // HAVE_FEATURE_SCRIPTING
+
+ case SID_OFFICE_CHECK_PLZ:
+ {
+ bool bRet = false;
+ const SfxStringItem* pStringItem = rReq.GetArg<SfxStringItem>(rReq.GetSlot());
+
+ if ( pStringItem )
+ {
+ bRet = true /*!!!SfxIniManager::CheckPLZ( aPLZ )*/;
+ }
+#if HAVE_FEATURE_SCRIPTING
+ else
+ SbxBase::SetError( ERRCODE_BASIC_WRONG_ARGS );
+#endif
+ rReq.SetReturnValue( SfxBoolItem( rReq.GetSlot(), bRet ) );
+ }
+ break;
+
+ case SID_AUTO_CORRECT_DLG:
+ {
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ SfxItemSetFixed<SID_AUTO_CORRECT_DLG, SID_AUTO_CORRECT_DLG> aSet(GetPool());
+ const SfxPoolItem* pItem=nullptr;
+ const SfxItemSet* pSet = rReq.GetArgs();
+ if ( pSet && pSet->GetItemState( SID_AUTO_CORRECT_DLG, false, &pItem ) == SfxItemState::SET )
+ aSet.Put( *pItem );
+
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateAutoCorrTabDialog(rReq.GetFrameWeld(), &aSet));
+ pDlg->Execute();
+
+ break;
+ }
+
+ case SID_NEWSD :
+ {
+ SvtModuleOptions aModuleOpt;
+ if ( !aModuleOpt.IsImpress() )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(rReq.GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SfxResId(STR_MODULENOTINSTALLED)));
+ xBox->run();
+ return;
+ }
+
+ Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ Reference< frame::XDispatchProvider > xProv = drawing::ModuleDispatcher::create( xContext );
+
+ OUString aCmd = GetInterface()->GetSlot( rReq.GetSlot() )->GetUnoName();
+ Reference< frame::XDispatchHelper > xHelper( frame::DispatchHelper::create(xContext) );
+ Sequence < beans::PropertyValue > aSeq;
+ if ( rReq.GetArgs() )
+ TransformItems( rReq.GetSlot(), *rReq.GetArgs(), aSeq );
+ Any aResult = xHelper->executeDispatch( xProv, aCmd, OUString(), 0, aSeq );
+ frame::DispatchResultEvent aEvent;
+ bool bSuccess = (aResult >>= aEvent) &&
+ (aEvent.State == frame::DispatchResultState::SUCCESS);
+ rReq.SetReturnValue( SfxBoolItem( rReq.GetSlot(), bSuccess ) );
+ }
+ break;
+
+ case FN_LABEL :
+ case FN_BUSINESS_CARD :
+ case FN_XFORMS_INIT :
+ {
+ Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ Reference< frame::XDispatchProvider > xProv = text::ModuleDispatcher::create( xContext );
+
+ OUString aCmd = GetInterface()->GetSlot( rReq.GetSlot() )->GetUnoName();
+ Reference< frame::XDispatchHelper > xHelper( frame::DispatchHelper::create(xContext) );
+ Sequence < beans::PropertyValue > aSeq;
+ if ( rReq.GetArgs() )
+ TransformItems( rReq.GetSlot(), *rReq.GetArgs(), aSeq );
+ Any aResult = xHelper->executeDispatch( xProv, aCmd, OUString(), 0, aSeq );
+ frame::DispatchResultEvent aEvent;
+ bool bSuccess = (aResult >>= aEvent) &&
+ (aEvent.State == frame::DispatchResultState::SUCCESS);
+ rReq.SetReturnValue( SfxBoolItem( rReq.GetSlot(), bSuccess ) );
+ }
+ break;
+
+ case SID_ADDRESS_DATA_SOURCE:
+ {
+ try
+ {
+ Reference< uno::XComponentContext > xORB = ::comphelper::getProcessComponentContext();
+ Reference< ui::dialogs::XExecutableDialog > xDialog = ui::dialogs::AddressBookSourcePilot::createWithParent(xORB, nullptr);
+ xDialog->execute();
+ }
+ catch(const css::uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sfx.appl");
+ }
+ }
+ break;
+
+ case SID_COMP_BIBLIOGRAPHY:
+ lcl_tryLoadBibliography();
+ break;
+ }
+}
+
+void SfxApplication::OfaState_Impl(SfxItemSet &rSet)
+{
+ SvtModuleOptions aModuleOpt;
+
+ if( !aModuleOpt.IsWriter())
+ {
+ rSet.DisableItem( FN_LABEL );
+ rSet.DisableItem( FN_BUSINESS_CARD );
+ rSet.DisableItem( FN_XFORMS_INIT );
+ }
+ if ( comphelper::LibreOfficeKit::isActive() )
+ rSet.DisableItem( SID_AUTO_CORRECT_DLG );
+
+ bool bMacrosDisabled
+ = officecfg::Office::Common::Security::Scripting::DisableMacrosExecution::get();
+ if (bMacrosDisabled)
+ {
+ rSet.DisableItem(SID_RUNMACRO);
+ rSet.DisableItem(SID_MACROORGANIZER);
+ rSet.DisableItem(SID_SCRIPTORGANIZER);
+ rSet.DisableItem(SID_BASICIDE_APPEAR);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/appuno.cxx b/sfx2/source/appl/appuno.cxx
new file mode 100644
index 0000000000..386cce711c
--- /dev/null
+++ b/sfx2/source/appl/appuno.cxx
@@ -0,0 +1,1845 @@
+/* -*- 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 <fltoptint.hxx>
+#include <sfx2/brokenpackageint.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/msgpool.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/sfxuno.hxx>
+#include <sfxslots.hxx>
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+#include <comphelper/interaction.hxx>
+#include <osl/diagnose.h>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itempool.hxx>
+#include <svl/slstitm.hxx>
+#include <svl/stritem.hxx>
+#include <tools/debug.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/document/BrokenPackageRequest.hpp>
+#include <com/sun/star/document/FilterOptionsRequest.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/ucb/XContent.hpp>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::io;
+
+// needs to be converted to a better data structure
+SfxFormalArgument const aFormalArgs[] = {
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "SuggestedSaveAsName", SID_DEFAULTFILENAME },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "SuggestedSaveAsDir", SID_DEFAULTFILEPATH },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "VersionAuthor", SID_DOCINFO_AUTHOR },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "VersionComment", SID_DOCINFO_COMMENTS },
+ { reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "DontTerminateEdit", FN_PARAM_1 },
+ { reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "VersionMajor", SID_DOCINFO_MAJOR },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "FilterOptions", SID_FILE_FILTEROPTIONS },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "FilterName", SID_FILTER_NAME },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "Margin1", SID_RULER_MARGIN1 },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "Margin2", SID_RULER_MARGIN2 },
+// { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "FileName", SID_FILE_NAME },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "URL", SID_FILE_NAME },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "OpenFlags", SID_OPTIONS },
+ { reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "Overwrite", SID_OVERWRITE },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "Password", SID_PASSWORD },
+ { reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "PasswordInteraction", SID_PASSWORDINTERACTION },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "Referer", SID_REFERER },
+ { reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "SaveTo", SID_SAVETO },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "TemplateName", SID_TEMPLATE_NAME },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "TemplateRegion", SID_TEMPLATE_REGIONNAME },
+// { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "Region", SID_TEMPLATE_REGIONNAME },
+// { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "Name", SID_TEMPLATE_NAME },
+ { reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "Unpacked", SID_UNPACK },
+ { reinterpret_cast<SfxType*>(&aSfxInt16Item_Impl), "Version", SID_VERSION },
+ { reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "SaveACopy", SID_SAVEACOPYITEM },
+ { reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "NoFileSync", SID_NO_FILE_SYNC },
+ { reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "NoThumbnail", SID_NO_THUMBNAIL },
+ { reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "NoEmbDataSet", SID_NO_EMBEDDED_DS },
+ { reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "IsRedactMode", SID_IS_REDACT_MODE },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "RedactionStyle", SID_REDACTION_STYLE },
+ { reinterpret_cast<SfxType*>(&aSfxStringItem_Impl), "AdditionsTag", FN_PARAM_ADDITIONS_TAG },
+};
+
+sal_uInt16 const nMediaArgsCount = SAL_N_ELEMENTS(aFormalArgs);
+
+constexpr OUString sTemplateRegionName = u"TemplateRegionName"_ustr;
+constexpr OUString sTemplateName = u"TemplateName"_ustr;
+constexpr OUString sAsTemplate = u"AsTemplate"_ustr;
+constexpr OUString sOpenNewView = u"OpenNewView"_ustr;
+constexpr OUString sViewId = u"ViewId"_ustr;
+constexpr OUString sPluginMode = u"PluginMode"_ustr;
+constexpr OUString sReadOnly = u"ReadOnly"_ustr;
+constexpr OUString sDdeReconnect = u"DDEReconnect"_ustr;
+constexpr OUString sStartPresentation = u"StartPresentation"_ustr;
+constexpr OUString sFrameName = u"FrameName"_ustr;
+constexpr OUString sMediaType = u"MediaType"_ustr;
+constexpr OUString sPostData = u"PostData"_ustr;
+constexpr OUString sCharacterSet = u"CharacterSet"_ustr;
+constexpr OUString sInputStream = u"InputStream"_ustr;
+constexpr OUString sStream = u"Stream"_ustr;
+constexpr OUString sOutputStream = u"OutputStream"_ustr;
+constexpr OUString sHidden = u"Hidden"_ustr;
+constexpr OUString sPreview = u"Preview"_ustr;
+constexpr OUString sViewOnly = u"ViewOnly"_ustr;
+constexpr OUString sDontEdit = u"DontEdit"_ustr;
+constexpr OUString sSilent = u"Silent"_ustr;
+constexpr OUString sJumpMark = u"JumpMark"_ustr;
+constexpr OUString sSalvagedFile = u"SalvagedFile"_ustr;
+constexpr OUString sStatusInd = u"StatusIndicator"_ustr;
+constexpr OUString sModel = u"Model"_ustr;
+constexpr OUString sFrame = u"Frame"_ustr;
+constexpr OUString sViewData = u"ViewData"_ustr;
+constexpr OUString sFilterData = u"FilterData"_ustr;
+constexpr OUString sSelectionOnly = u"SelectionOnly"_ustr;
+constexpr OUString sMacroExecMode = u"MacroExecutionMode"_ustr;
+constexpr OUString sUpdateDocMode = u"UpdateDocMode"_ustr;
+constexpr OUString sMinimized = u"Minimized"_ustr;
+constexpr OUString sInteractionHdl = u"InteractionHandler"_ustr;
+constexpr OUString sUCBContent = u"UCBContent"_ustr;
+constexpr OUString sRepairPackage = u"RepairPackage"_ustr;
+constexpr OUString sDocumentTitle = u"DocumentTitle"_ustr;
+constexpr OUString sComponentData = u"ComponentData"_ustr;
+constexpr OUString sComponentContext = u"ComponentContext"_ustr;
+constexpr OUString sDocumentBaseURL = u"DocumentBaseURL"_ustr;
+constexpr OUString sHierarchicalDocumentName = u"HierarchicalDocumentName"_ustr;
+constexpr OUString sCopyStreamIfPossible = u"CopyStreamIfPossible"_ustr;
+constexpr OUString sNoAutoSave = u"NoAutoSave"_ustr;
+constexpr OUString sFolderName = u"FolderName"_ustr;
+constexpr OUString sUseSystemDialog = u"UseSystemDialog"_ustr;
+constexpr OUString sStandardDir = u"StandardDir"_ustr;
+constexpr OUString sDenyList = u"DenyList"_ustr;
+constexpr OUString sModifyPasswordInfo = u"ModifyPasswordInfo"_ustr;
+constexpr OUString sSuggestedSaveAsDir = u"SuggestedSaveAsDir"_ustr;
+constexpr OUString sSuggestedSaveAsName = u"SuggestedSaveAsName"_ustr;
+constexpr OUString sEncryptionData = u"EncryptionData"_ustr;
+constexpr OUString sFailOnWarning = u"FailOnWarning"_ustr;
+constexpr OUString sDocumentService = u"DocumentService"_ustr;
+constexpr OUString sFilterProvider = u"FilterProvider"_ustr;
+constexpr OUString sImageFilter = u"ImageFilter"_ustr;
+constexpr OUString sLockContentExtraction = u"LockContentExtraction"_ustr;
+constexpr OUString sLockExport = u"LockExport"_ustr;
+constexpr OUString sLockPrint = u"LockPrint"_ustr;
+constexpr OUString sLockSave = u"LockSave"_ustr;
+constexpr OUString sLockEditDoc = u"LockEditDoc"_ustr;
+constexpr OUString sReplaceable = u"Replaceable"_ustr;
+
+static bool isMediaDescriptor( sal_uInt16 nSlotId )
+{
+ return ( nSlotId == SID_OPENDOC || nSlotId == SID_EXPORTDOC ||
+ nSlotId == SID_SAVEASDOC || nSlotId == SID_SAVEDOC ||
+ nSlotId == SID_SAVETO || nSlotId == SID_SAVEACOPY ||
+ nSlotId == SID_EXPORTDOCASPDF || nSlotId == SID_DIRECTEXPORTDOCASPDF ||
+ nSlotId == SID_EXPORTDOCASEPUB || nSlotId == SID_DIRECTEXPORTDOCASEPUB ||
+ nSlotId == SID_REDACTDOC || nSlotId == SID_AUTOREDACTDOC ||
+ nSlotId == SID_SAVEACOPYITEM);
+}
+
+void TransformParameters( sal_uInt16 nSlotId, const uno::Sequence<beans::PropertyValue>& rArgs, SfxAllItemSet& rSet, const SfxSlot* pSlot )
+{
+ if ( !pSlot )
+ pSlot = SFX_SLOTPOOL().GetSlot( nSlotId );
+
+ if ( !pSlot )
+ return;
+
+ if ( nSlotId == SID_OPENURL )
+ nSlotId = SID_OPENDOC;
+
+ const sal_Int32 nCount = rArgs.getLength();
+ if ( !nCount )
+ return;
+
+ const beans::PropertyValue* pPropsVal = rArgs.getConstArray();
+ if ( !pSlot->IsMode(SfxSlotMode::METHOD) )
+ {
+ // slot is a property
+ const SfxType* pType = pSlot->GetType();
+ std::unique_ptr<SfxPoolItem> pItem(pType->CreateItem());
+
+ if ( !pItem )
+ {
+ SAL_WARN( "sfx", "No creator method for item: " << nSlotId );
+ return;
+ }
+
+ sal_uInt16 nWhich = rSet.GetPool()->GetWhich(nSlotId);
+ bool bConvertTwips = ( rSet.GetPool()->GetMetric( nWhich ) == MapUnit::MapTwip );
+ pItem->SetWhich( nWhich );
+ sal_uInt16 nSubCount = pType->nAttribs;
+
+ const beans::PropertyValue& rProp = pPropsVal[0];
+ const OUString& rName = rProp.Name;
+ if ( nCount == 1 && rName == pSlot->pUnoName )
+ {
+ // there is only one parameter and its name matches the name of the property,
+ // so it's either a simple property or a complex property in one single UNO struct
+ if( pItem->PutValue( rProp.Value, bConvertTwips ? CONVERT_TWIPS : 0 ) )
+ // only use successfully converted items
+ rSet.Put( std::move(pItem) );
+ else
+ {
+ SAL_WARN( "sfx", "Property not convertible: " << pSlot->pUnoName );
+ }
+ }
+#ifdef DBG_UTIL
+ else if ( nSubCount == 0 )
+ {
+ // for a simple property there can be only one parameter and its name *must* match
+ SAL_WARN("sfx.appl", "Property name does not match: " << rName);
+ }
+#endif
+ else
+ {
+ // there is more than one parameter and the property is a complex one
+#ifdef DBG_UTIL
+ // if the dispatch API is used for UI purposes or from the testtool,
+ // it is possible to skip some or all arguments,
+ // but it indicates an error for macro recording;
+ // so this should be notified as a warning only
+ if ( nCount != nSubCount )
+ {
+ SAL_INFO("sfx.appl", "MacroPlayer: wrong number of parameters for slot: " << nSlotId );
+ }
+#endif
+ // complex property; collect sub items from the parameter set and reconstruct complex item
+ sal_uInt16 nFound=0;
+ for ( const beans::PropertyValue& rPropValue : rArgs )
+ {
+ sal_uInt16 nSub;
+ for ( nSub=0; nSub<nSubCount; nSub++ )
+ {
+ // search sub item by name
+ OUString aStr = pSlot->pUnoName + "." + OUString::createFromAscii(pType->aAttrib[nSub].pName);
+ if ( rPropValue.Name == aStr )
+ {
+ sal_uInt8 nSubId = static_cast<sal_uInt8>(static_cast<sal_Int8>(pType->aAttrib[nSub].nAID));
+ if ( bConvertTwips )
+ nSubId |= CONVERT_TWIPS;
+ if ( pItem->PutValue( rPropValue.Value, nSubId ) )
+ nFound++;
+ else
+ {
+ SAL_WARN( "sfx.appl", "Property not convertible: " << pSlot->pUnoName);
+ }
+ break;
+ }
+ }
+
+ // there was a parameter with a name that didn't match to any of the members
+ SAL_WARN_IF( nSub >= nSubCount, "sfx.appl", "Property name does not match: " << rPropValue.Name );
+ }
+
+ // at least one part of the complex item must be present; other parts can have default values
+ if ( nFound > 0 )
+ rSet.Put( std::move(pItem) );
+ }
+
+ return;
+ }
+
+#ifdef DBG_UTIL
+ // detect parameters that don't match to any formal argument or one of its members
+ sal_Int32 nFoundArgs = 0;
+#endif
+ // slot is a method
+ bool bIsMediaDescriptor = isMediaDescriptor( nSlotId );
+ sal_uInt16 nMaxArgs = bIsMediaDescriptor ? nMediaArgsCount : pSlot->nArgDefCount;
+ for ( sal_uInt16 nArgs=0; nArgs<nMaxArgs; nArgs++ )
+ {
+ const SfxFormalArgument &rArg = bIsMediaDescriptor ? aFormalArgs[nArgs] : pSlot->GetFormalArgument( nArgs );
+ std::unique_ptr<SfxPoolItem> pItem(rArg.CreateItem());
+ if ( !pItem )
+ {
+ SAL_WARN( "sfx", "No creator method for argument: " << rArg.pName );
+ return;
+ }
+
+ sal_uInt16 nWhich = rSet.GetPool()->GetWhich(rArg.nSlotId);
+ bool bConvertTwips = ( rSet.GetPool()->GetMetric( nWhich ) == MapUnit::MapTwip );
+ pItem->SetWhich( nWhich );
+ const SfxType* pType = rArg.pType;
+ sal_uInt16 nSubCount = pType->nAttribs;
+ if ( nSubCount == 0 )
+ {
+ // "simple" (base type) argument
+ auto pProp = std::find_if(rArgs.begin(), rArgs.end(),
+ [&rArg](const beans::PropertyValue& rProp) { return rProp.Name.equalsAscii(rArg.pName); });
+ if (pProp != rArgs.end())
+ {
+#ifdef DBG_UTIL
+ ++nFoundArgs;
+#endif
+ if( pItem->PutValue( pProp->Value, 0 ) )
+ // only use successfully converted items
+ rSet.Put( std::move(pItem) );
+ else
+ {
+ SAL_WARN( "sfx", "Property not convertible: " << rArg.pName );
+ }
+ }
+ }
+ else
+ {
+ // complex argument, could be passed in one struct
+ bool bAsWholeItem = false;
+ for ( const beans::PropertyValue& rProp : rArgs )
+ {
+ const OUString& rName = rProp.Name;
+ if ( rName == OUString(rArg.pName, strlen(rArg.pName), RTL_TEXTENCODING_UTF8) )
+ {
+ bAsWholeItem = true;
+#ifdef DBG_UTIL
+ ++nFoundArgs;
+#endif
+ if( pItem->PutValue( rProp.Value, 0 ) )
+ // only use successfully converted items
+ rSet.Put( std::move(pItem) );
+ else
+ {
+ SAL_WARN( "sfx", "Property not convertible: " << rArg.pName );
+ }
+ }
+ }
+
+ if ( !bAsWholeItem )
+ {
+ // complex argument; collect sub items from argument array and reconstruct complex item
+ // only put item if at least one member was found and had the correct type
+ // (is this a good idea?! Should we ask for *all* members?)
+ bool bRet = false;
+ for ( const beans::PropertyValue& rProp : rArgs )
+ {
+ for ( sal_uInt16 nSub=0; nSub<nSubCount; nSub++ )
+ {
+ // search sub item by name
+ OString aStr = OString::Concat(rArg.pName) + "." + pType->aAttrib[nSub].pName;
+ if ( rProp.Name.equalsAsciiL(aStr.getStr(), aStr.getLength()) )
+ {
+ // at least one member found ...
+ bRet = true;
+#ifdef DBG_UTIL
+ ++nFoundArgs;
+#endif
+ sal_uInt8 nSubId = static_cast<sal_uInt8>(static_cast<sal_Int8>(pType->aAttrib[nSub].nAID));
+ if ( bConvertTwips )
+ nSubId |= CONVERT_TWIPS;
+ if (!pItem->PutValue( rProp.Value, nSubId ) )
+ {
+ // ... but it was not convertible
+ bRet = false;
+ SAL_WARN( "sfx", "Property not convertible: " << rArg.pName );
+ }
+
+ break;
+ }
+ }
+ }
+
+ if ( bRet )
+ // only use successfully converted items
+ rSet.Put( std::move(pItem) );
+
+ }
+ }
+ }
+
+ // special additional parameters for some slots not seen in the slot definitions
+ // Some of these slots are not considered to be used for macro recording, because they shouldn't be recorded as slots,
+ // but as dispatching or factory or arbitrary URLs to the frame
+ // Some also can use additional arguments that are not recordable (will be changed later,
+ // f.e. "SaveAs" shouldn't support parameters not in the slot definition!)
+ if ( nSlotId == SID_NEWWINDOW )
+ {
+ for ( const beans::PropertyValue& rProp : rArgs )
+ {
+ const OUString& rName = rProp.Name;
+ if ( rName == sFrame )
+ {
+ Reference< XFrame > xFrame;
+ OSL_VERIFY( rProp.Value >>= xFrame );
+ rSet.Put( SfxUnoFrameItem( SID_FILLFRAME, xFrame ) );
+ }
+ else
+ if ( rName == sHidden )
+ {
+ bool bVal = false;
+ if (rProp.Value >>= bVal)
+ rSet.Put( SfxBoolItem( SID_HIDDEN, bVal ) );
+ }
+ }
+ }
+ else if ( bIsMediaDescriptor )
+ {
+ for ( const beans::PropertyValue& rProp : rArgs )
+ {
+#ifdef DBG_UTIL
+ ++nFoundArgs;
+#endif
+ const OUString& aName = rProp.Name;
+ if ( aName == sModel )
+ rSet.Put( SfxUnoAnyItem( SID_DOCUMENT, rProp.Value ) );
+ else if ( aName == sComponentData )
+ {
+ rSet.Put( SfxUnoAnyItem( SID_COMPONENTDATA, rProp.Value ) );
+ }
+ else if ( aName == sComponentContext )
+ {
+ rSet.Put( SfxUnoAnyItem( SID_COMPONENTCONTEXT, rProp.Value ) );
+ }
+ else if ( aName == sStatusInd )
+ {
+ Reference<task::XStatusIndicator> xVal;
+ bool bOK = (rProp.Value >>= xVal);
+ DBG_ASSERT( bOK, "invalid type for StatusIndicator" );
+ if (bOK && xVal.is())
+ rSet.Put( SfxUnoAnyItem( SID_PROGRESS_STATUSBAR_CONTROL, rProp.Value ) );
+ }
+ else if ( aName == sInteractionHdl )
+ {
+ Reference<task::XInteractionHandler> xVal;
+ bool bOK = (rProp.Value >>= xVal);
+ DBG_ASSERT( bOK, "invalid type for InteractionHandler" );
+ if (bOK && xVal.is())
+ rSet.Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, rProp.Value ) );
+ }
+ else if ( aName == sViewData )
+ rSet.Put( SfxUnoAnyItem( SID_VIEW_DATA, rProp.Value ) );
+ else if ( aName == sFilterData )
+ rSet.Put( SfxUnoAnyItem( SID_FILTER_DATA, rProp.Value ) );
+ else if ( aName == sInputStream )
+ {
+ Reference< XInputStream > xVal;
+ bool bOK = ((rProp.Value >>= xVal) && xVal.is());
+ DBG_ASSERT( bOK, "invalid type for InputStream" );
+ if (bOK)
+ rSet.Put( SfxUnoAnyItem( SID_INPUTSTREAM, rProp.Value ) );
+ }
+ else if ( aName == sStream )
+ {
+ Reference< XInputStream > xVal;
+ bool bOK = ((rProp.Value >>= xVal) && xVal.is());
+ DBG_ASSERT( bOK, "invalid type for Stream" );
+ if (bOK)
+ rSet.Put( SfxUnoAnyItem( SID_STREAM, rProp.Value ) );
+ }
+ else if ( aName == sUCBContent )
+ {
+ Reference< XContent > xVal;
+ bool bOK = ((rProp.Value >>= xVal) && xVal.is());
+ DBG_ASSERT( bOK, "invalid type for UCBContent" );
+ if (bOK)
+ rSet.Put( SfxUnoAnyItem( SID_CONTENT, rProp.Value ) );
+ }
+ else if ( aName == sOutputStream )
+ {
+ Reference< XOutputStream > xVal;
+ bool bOK = ((rProp.Value >>= xVal) && xVal.is());
+ DBG_ASSERT( bOK, "invalid type for OutputStream" );
+ if (bOK)
+ rSet.Put( SfxUnoAnyItem( SID_OUTPUTSTREAM, rProp.Value ) );
+ }
+ else if ( aName == sPostData )
+ {
+ Reference< XInputStream > xVal;
+ bool bOK = (rProp.Value >>= xVal);
+ DBG_ASSERT( bOK, "invalid type for PostData" );
+ if (bOK)
+ rSet.Put( SfxUnoAnyItem( SID_POSTDATA, rProp.Value ) );
+ }
+ else if ( aName == sFrame )
+ {
+ Reference< XFrame > xFrame;
+ bool bOK = (rProp.Value >>= xFrame);
+ DBG_ASSERT( bOK, "invalid type for Frame" );
+ if (bOK)
+ rSet.Put( SfxUnoFrameItem( SID_FILLFRAME, xFrame ) );
+ }
+ else if ( aName == sAsTemplate )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for AsTemplate" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_TEMPLATE, bVal ) );
+ }
+ else if ( aName == sOpenNewView )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for OpenNewView" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_OPEN_NEW_VIEW, bVal ) );
+ }
+ else if ( aName == sFailOnWarning )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for FailOnWarning" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_FAIL_ON_WARNING, bVal ) );
+ }
+ else if ( aName == sViewId )
+ {
+ sal_Int16 nVal = -1;
+ bool bOK = ((rProp.Value >>= nVal) && (nVal != -1));
+ DBG_ASSERT( bOK, "invalid type for ViewId" );
+ if (bOK)
+ rSet.Put( SfxUInt16Item( SID_VIEW_ID, nVal ) );
+ }
+ else if ( aName == sPluginMode )
+ {
+ sal_Int16 nVal = -1;
+ bool bOK = ((rProp.Value >>= nVal) && (nVal != -1));
+ DBG_ASSERT( bOK, "invalid type for PluginMode" );
+ if (bOK)
+ rSet.Put( SfxUInt16Item( SID_PLUGIN_MODE, nVal ) );
+ }
+ else if ( aName == sReadOnly )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for ReadOnly" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_DOC_READONLY, bVal ) );
+ }
+ else if ( aName == sDdeReconnect )
+ {
+ bool bVal = true;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for DDEReconnect" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_DDE_RECONNECT_ONLOAD, bVal ) );
+ }
+ else if ( aName == sStartPresentation )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for StartPresentation" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_DOC_STARTPRESENTATION, bVal ) );
+ }
+ else if ( aName == sSelectionOnly )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for SelectionOnly" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_SELECTION, bVal ) );
+ }
+ else if ( aName == sHidden )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for Hidden" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_HIDDEN, bVal ) );
+ }
+ else if ( aName == sMinimized )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for Minimized" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_MINIMIZED, bVal ) );
+ }
+ else if ( aName == sSilent )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for Silent" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_SILENT, bVal ) );
+ }
+ else if ( aName == sPreview )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for Preview" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_PREVIEW, bVal ) );
+ }
+ else if ( aName == sViewOnly )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for ViewOnly" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_VIEWONLY, bVal ) );
+ }
+ else if ( aName == sDontEdit )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for ViewOnly" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_EDITDOC, !bVal ) );
+ }
+ else if ( aName == sUseSystemDialog )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for ViewOnly" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_FILE_DIALOG, bVal ) );
+ }
+ else if ( aName == sStandardDir )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for StandardDir" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_STANDARD_DIR, sVal ) );
+ }
+ else if ( aName == sDenyList )
+ {
+ uno::Sequence<OUString> xVal;
+ bool bOK = (rProp.Value >>= xVal);
+ DBG_ASSERT( bOK, "invalid type or value for DenyList" );
+ if (bOK)
+ {
+ SfxStringListItem stringList(SID_DENY_LIST);
+ stringList.SetStringList( xVal );
+ rSet.Put( stringList );
+ }
+ }
+ else if ( aName == "FileName" )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for FileName" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_FILE_NAME, sVal ) );
+ }
+ else if ( aName == sSalvagedFile )
+ {
+ OUString sVal;
+ bool bOK = (rProp.Value >>= sVal);
+ DBG_ASSERT( bOK, "invalid type or value for SalvagedFile" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_DOC_SALVAGE, sVal ) );
+ }
+ else if ( aName == sFolderName )
+ {
+ OUString sVal;
+ bool bOK = (rProp.Value >>= sVal);
+ DBG_ASSERT( bOK, "invalid type or value for FolderName" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_PATH, sVal ) );
+ }
+ else if ( aName == sFrameName )
+ {
+ OUString sVal;
+ bool bOK = (rProp.Value >>= sVal);
+ DBG_ASSERT( bOK, "invalid type for FrameName" );
+ if (bOK && !sVal.isEmpty())
+ rSet.Put( SfxStringItem( SID_TARGETNAME, sVal ) );
+ }
+ else if ( aName == sMediaType )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for MediaType" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_CONTENTTYPE, sVal ) );
+ }
+ else if ( aName == sTemplateName )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for TemplateName" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_TEMPLATE_NAME, sVal ) );
+ }
+ else if ( aName == sTemplateRegionName )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for TemplateRegionName" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_TEMPLATE_REGIONNAME, sVal ) );
+ }
+ else if ( aName == sJumpMark )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for JumpMark" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_JUMPMARK, sVal ) );
+ }
+ else if ( aName == sCharacterSet )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for CharacterSet" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_CHARSET, sVal ) );
+ }
+ else if ( aName == "FilterFlags" )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for FilterFlags" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_FILE_FILTEROPTIONS, sVal ) );
+ }
+ else if ( aName == sImageFilter )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for FilterFlags" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_CONVERT_IMAGES, sVal ) );
+ }
+ else if ( aName == sMacroExecMode )
+ {
+ sal_Int16 nVal =-1;
+ bool bOK = ((rProp.Value >>= nVal) && (nVal != -1));
+ DBG_ASSERT( bOK, "invalid type for MacroExecMode" );
+ if (bOK)
+ rSet.Put( SfxUInt16Item( SID_MACROEXECMODE, nVal ) );
+ }
+ else if ( aName == sUpdateDocMode )
+ {
+ sal_Int16 nVal =-1;
+ bool bOK = ((rProp.Value >>= nVal) && (nVal != -1));
+ DBG_ASSERT( bOK, "invalid type for UpdateDocMode" );
+ if (bOK)
+ rSet.Put( SfxUInt16Item( SID_UPDATEDOCMODE, nVal ) );
+ }
+ else if ( aName == sRepairPackage )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for RepairPackage" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_REPAIRPACKAGE, bVal ) );
+ }
+ else if ( aName == sDocumentTitle )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for DocumentTitle" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_DOCINFO_TITLE, sVal ) );
+ }
+ else if ( aName == sDocumentBaseURL )
+ {
+ OUString sVal;
+ // the base url can be set to empty ( for embedded objects for example )
+ bool bOK = (rProp.Value >>= sVal);
+ DBG_ASSERT( bOK, "invalid type or value for DocumentBaseURL" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_DOC_BASEURL, sVal ) );
+ }
+ else if ( aName == sHierarchicalDocumentName )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for HierarchicalDocumentName" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_DOC_HIERARCHICALNAME, sVal ) );
+ }
+ else if ( aName == sCopyStreamIfPossible )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for CopyStreamIfPossible" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_COPY_STREAM_IF_POSSIBLE, bVal ) );
+ }
+ else if ( aName == sNoAutoSave )
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for NoAutoSave" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_NOAUTOSAVE, bVal ) );
+ }
+ else if ( aName == sModifyPasswordInfo )
+ {
+ rSet.Put( SfxUnoAnyItem( SID_MODIFYPASSWORDINFO, rProp.Value ) );
+ }
+ else if ( aName == sEncryptionData )
+ {
+ rSet.Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, rProp.Value ) );
+ }
+ else if ( aName == sSuggestedSaveAsDir )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for SuggestedSaveAsDir" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_SUGGESTEDSAVEASDIR, sVal ) );
+ }
+ else if ( aName == sSuggestedSaveAsName )
+ {
+ OUString sVal;
+ bool bOK = ((rProp.Value >>= sVal) && !sVal.isEmpty());
+ DBG_ASSERT( bOK, "invalid type or value for SuggestedSaveAsName" );
+ if (bOK)
+ rSet.Put( SfxStringItem( SID_SUGGESTEDSAVEASNAME, sVal ) );
+ }
+ else if (aName == sDocumentService)
+ {
+ OUString aVal;
+ bool bOK = ((rProp.Value >>= aVal) && !aVal.isEmpty());
+ if (bOK)
+ rSet.Put(SfxStringItem(SID_DOC_SERVICE, aVal));
+ }
+ else if (aName == sFilterProvider)
+ {
+ OUString aVal;
+ bool bOK = ((rProp.Value >>= aVal) && !aVal.isEmpty());
+ if (bOK)
+ rSet.Put(SfxStringItem(SID_FILTER_PROVIDER, aVal));
+ }
+ else if (aName == sLockContentExtraction)
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for LockContentExtraction" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_LOCK_CONTENT_EXTRACTION, bVal ) );
+ }
+ else if (aName == sLockExport)
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for LockExport" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_LOCK_EXPORT, bVal ) );
+ }
+ else if (aName == sLockPrint)
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for LockPrint" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_LOCK_PRINT, bVal ) );
+ }
+ else if (aName == sLockSave)
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for LockSave" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_LOCK_SAVE, bVal ) );
+ }
+ else if (aName == sLockEditDoc)
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT( bOK, "invalid type for LockEditDoc" );
+ if (bOK)
+ rSet.Put( SfxBoolItem( SID_LOCK_EDITDOC, bVal ) );
+ }
+ else if (aName == sReplaceable)
+ {
+ bool bVal = false;
+ bool bOK = (rProp.Value >>= bVal);
+ DBG_ASSERT(bOK, "invalid type for Replaceable");
+ if (bOK)
+ rSet.Put(SfxBoolItem(SID_REPLACEABLE, bVal));
+ }
+#ifdef DBG_UTIL
+ else
+ --nFoundArgs;
+#endif
+ }
+ }
+ // API to raise options dialog with a specified options ab page (#i83757#)
+ else
+ {
+ // transform parameter "OptionsPageURL" of slot "OptionsTreeDialog"
+ if ( "OptionsTreeDialog" == pSlot->pUnoName )
+ {
+ auto pProp = std::find_if(rArgs.begin(), rArgs.end(),
+ [](const PropertyValue& rProp) { return rProp.Name == "OptionsPageURL" || rProp.Name == "OptionsPageID"; });
+ if (pProp != rArgs.end())
+ {
+ OUString sURL;
+ sal_uInt16 nPageID;
+ if ( pProp->Name == "OptionsPageURL" && (pProp->Value >>= sURL) )
+ rSet.Put( SfxStringItem( SID_OPTIONS_PAGEURL, sURL ) );
+ else if ( pProp->Name == "OptionsPageID" && (pProp->Value >>= nPageID) )
+ rSet.Put( SfxUInt16Item( SID_OPTIONS_PAGEID, nPageID ) );
+ }
+ }
+ }
+#ifdef DBG_UTIL
+ if ( nFoundArgs == nCount )
+ {
+ // except for the "special" slots: assure that every argument was convertible
+ SAL_INFO( "sfx.appl", "MacroPlayer: Some properties didn't match to any formal argument for slot: "<< pSlot->pUnoName );
+ }
+#endif
+}
+
+void TransformItems( sal_uInt16 nSlotId, const SfxItemSet& rSet, uno::Sequence<beans::PropertyValue>& rArgs, const SfxSlot* pSlot )
+{
+ if ( !pSlot )
+ pSlot = SFX_SLOTPOOL().GetSlot( nSlotId );
+
+ if ( !pSlot)
+ return;
+
+ if ( nSlotId == SID_OPENURL )
+ nSlotId = SID_OPENDOC;
+ if ( nSlotId == SID_SAVEASREMOTE )
+ nSlotId = SID_SAVEASDOC;
+
+ // find number of properties to avoid permanent reallocations in the sequence
+ sal_Int32 nProps=0;
+
+#ifdef DBG_UTIL
+ // trace number of items and compare with number of properties for debugging purposes
+ sal_Int32 nItems=0;
+#endif
+
+ const SfxType *pType = pSlot->GetType();
+ if ( !pSlot->IsMode(SfxSlotMode::METHOD) )
+ {
+ // slot is a property
+ sal_uInt16 nWhich = rSet.GetPool()->GetWhich(nSlotId);
+ if ( rSet.GetItemState( nWhich ) == SfxItemState::SET ) //???
+ {
+ sal_uInt16 nSubCount = pType->nAttribs;
+ if ( nSubCount )
+ // it's a complex property, we want it split into simple types
+ // so we expect to get as many items as we have (sub) members
+ nProps = nSubCount;
+ else
+ // simple property: we expect to get exactly one item
+ nProps++;
+ }
+ else
+ {
+ // we will not rely on the "toggle" ability of some property slots
+ SAL_WARN( "sfx", "Processing property slot without argument: " << nSlotId );
+ }
+
+#ifdef DBG_UTIL
+ nItems++;
+#endif
+ }
+ else
+ {
+ // slot is a method
+ bool bIsMediaDescriptor = isMediaDescriptor( nSlotId );
+ sal_uInt16 nFormalArgs = bIsMediaDescriptor ? nMediaArgsCount : pSlot->GetFormalArgumentCount();
+ for ( sal_uInt16 nArg=0; nArg<nFormalArgs; ++nArg )
+ {
+ // check every formal argument of the method
+ const SfxFormalArgument &rArg = bIsMediaDescriptor ? aFormalArgs[nArg] : pSlot->GetFormalArgument( nArg );
+
+ sal_uInt16 nWhich = rSet.GetPool()->GetWhich( rArg.nSlotId );
+ if ( rSet.GetItemState( nWhich ) == SfxItemState::SET ) //???
+ {
+ sal_uInt16 nSubCount = rArg.pType->nAttribs;
+ if ( nSubCount )
+ // argument has a complex type, we want it split into simple types
+ // so for this argument we expect to get as many items as we have (sub) members
+ nProps += nSubCount;
+ else
+ // argument of simple type: we expect to get exactly one item for it
+ nProps++;
+#ifdef DBG_UTIL
+ nItems++;
+#endif
+ }
+ }
+
+ // special treatment for slots that are *not* meant to be recorded as slots (except SaveAs/To)
+ if ( bIsMediaDescriptor )
+ {
+ sal_Int32 nAdditional=0;
+ if ( rSet.GetItemState( SID_PROGRESS_STATUSBAR_CONTROL ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_INTERACTIONHANDLER ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_DOC_SALVAGE ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_PATH ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_FILE_DIALOG ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_STANDARD_DIR ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_DENY_LIST ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_CONTENT ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_INPUTSTREAM ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_STREAM ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_OUTPUTSTREAM ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_TEMPLATE ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_OPEN_NEW_VIEW ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_FAIL_ON_WARNING ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_VIEW_ID ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_VIEW_DATA ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_FILTER_DATA ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_PLUGIN_MODE ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_DOC_READONLY ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_DDE_RECONNECT_ONLOAD ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_DOC_STARTPRESENTATION ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_SELECTION ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_CONTENTTYPE ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_POSTDATA ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_FILLFRAME ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_CHARSET ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_TARGETNAME ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_TEMPLATE_NAME ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_TEMPLATE_REGIONNAME ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_HIDDEN ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_MINIMIZED ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_PREVIEW ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_VIEWONLY ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_EDITDOC ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_SILENT ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_JUMPMARK ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_DOCUMENT ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_MACROEXECMODE ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_UPDATEDOCMODE ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_REPAIRPACKAGE ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_DOCINFO_TITLE ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_COMPONENTDATA ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_COMPONENTCONTEXT ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_DOC_BASEURL ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_DOC_HIERARCHICALNAME ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_COPY_STREAM_IF_POSSIBLE ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_NOAUTOSAVE ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_MODIFYPASSWORDINFO ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_SUGGESTEDSAVEASDIR ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_ENCRYPTIONDATA ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_SUGGESTEDSAVEASNAME ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_DOC_SERVICE ) == SfxItemState::SET )
+ nAdditional++;
+ if (rSet.HasItem(SID_FILTER_PROVIDER))
+ ++nAdditional;
+ if ( rSet.GetItemState( SID_CONVERT_IMAGES ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_LOCK_CONTENT_EXTRACTION ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_LOCK_EXPORT ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_LOCK_PRINT ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_LOCK_SAVE ) == SfxItemState::SET )
+ nAdditional++;
+ if ( rSet.GetItemState( SID_LOCK_EDITDOC ) == SfxItemState::SET )
+ nAdditional++;
+ if (rSet.GetItemState(SID_REPLACEABLE) == SfxItemState::SET)
+ nAdditional++;
+
+ // consider additional arguments
+ nProps += nAdditional;
+#ifdef DBG_UTIL
+ nItems += nAdditional;
+#endif
+ }
+ }
+
+#ifdef DBG_UTIL
+ // now check the itemset: is there any item that is not convertible using the list of formal arguments
+ // or the table of additional items?!
+ if ( rSet.Count() != nItems )
+ {
+ // detect unknown item and present error message
+ for ( auto const & rPair : rSet.GetRanges() )
+ {
+ sal_uInt16 nStartWhich = rPair.first;
+ sal_uInt16 nEndWhich = rPair.second;
+ for(sal_uInt16 nId = nStartWhich; nId <= nEndWhich; ++nId)
+ {
+ if ( rSet.GetItemState(nId) < SfxItemState::SET ) //???
+ // not really set
+ continue;
+
+ if ( !pSlot->IsMode(SfxSlotMode::METHOD) && nId == rSet.GetPool()->GetWhich( pSlot->GetSlotId() ) )
+ continue;
+
+ bool bIsMediaDescriptor = isMediaDescriptor( nSlotId );
+ sal_uInt16 nFormalArgs = bIsMediaDescriptor ? nMediaArgsCount : pSlot->nArgDefCount;
+ sal_uInt16 nArg;
+ for ( nArg=0; nArg<nFormalArgs; ++nArg )
+ {
+ const SfxFormalArgument &rArg = bIsMediaDescriptor ? aFormalArgs[nArg] : pSlot->GetFormalArgument( nArg );
+ sal_uInt16 nWhich = rSet.GetPool()->GetWhich( rArg.nSlotId );
+ if ( nId == nWhich )
+ break;
+ }
+
+ if ( nArg<nFormalArgs )
+ continue;
+
+ if ( bIsMediaDescriptor )
+ {
+ if ( nId == SID_DOCFRAME )
+ continue;
+ if ( nId == SID_PROGRESS_STATUSBAR_CONTROL )
+ continue;
+ if ( nId == SID_INTERACTIONHANDLER )
+ continue;
+ if ( nId == SID_VIEW_DATA )
+ continue;
+ if ( nId == SID_FILTER_DATA )
+ continue;
+ if ( nId == SID_DOCUMENT )
+ continue;
+ if ( nId == SID_CONTENT )
+ continue;
+ if ( nId == SID_INPUTSTREAM )
+ continue;
+ if ( nId == SID_STREAM )
+ continue;
+ if ( nId == SID_OUTPUTSTREAM )
+ continue;
+ if ( nId == SID_POSTDATA )
+ continue;
+ if ( nId == SID_FILLFRAME )
+ continue;
+ if ( nId == SID_TEMPLATE )
+ continue;
+ if ( nId == SID_OPEN_NEW_VIEW )
+ continue;
+ if ( nId == SID_VIEW_ID )
+ continue;
+ if ( nId == SID_PLUGIN_MODE )
+ continue;
+ if ( nId == SID_DOC_READONLY )
+ continue;
+ if ( nId == SID_DOC_STARTPRESENTATION )
+ continue;
+ if ( nId == SID_SELECTION )
+ continue;
+ if ( nId == SID_HIDDEN )
+ continue;
+ if ( nId == SID_MINIMIZED )
+ continue;
+ if ( nId == SID_SILENT )
+ continue;
+ if ( nId == SID_PREVIEW )
+ continue;
+ if ( nId == SID_VIEWONLY )
+ continue;
+ if ( nId == SID_EDITDOC )
+ continue;
+ if ( nId == SID_TARGETNAME )
+ continue;
+ if ( nId == SID_DOC_SALVAGE )
+ continue;
+ if ( nId == SID_PATH )
+ continue;
+ if ( nId == SID_FILE_DIALOG )
+ continue;
+ if ( nId == SID_STANDARD_DIR )
+ continue;
+ if ( nId == SID_DENY_LIST )
+ continue;
+ if ( nId == SID_CONTENTTYPE )
+ continue;
+ if ( nId == SID_TEMPLATE_NAME )
+ continue;
+ if ( nId == SID_TEMPLATE_REGIONNAME )
+ continue;
+ if ( nId == SID_JUMPMARK )
+ continue;
+ if ( nId == SID_CHARSET )
+ continue;
+ if ( nId == SID_MACROEXECMODE )
+ continue;
+ if ( nId == SID_UPDATEDOCMODE )
+ continue;
+ if ( nId == SID_REPAIRPACKAGE )
+ continue;
+ if ( nId == SID_DOCINFO_TITLE )
+ continue;
+ if ( nId == SID_COMPONENTDATA )
+ continue;
+ if ( nId == SID_COMPONENTCONTEXT )
+ continue;
+ if ( nId == SID_DOC_BASEURL )
+ continue;
+ if ( nId == SID_DOC_HIERARCHICALNAME )
+ continue;
+ if ( nId == SID_COPY_STREAM_IF_POSSIBLE )
+ continue;
+ if ( nId == SID_NOAUTOSAVE )
+ continue;
+ if ( nId == SID_ENCRYPTIONDATA )
+ continue;
+ if ( nId == SID_DOC_SERVICE )
+ continue;
+ if (nId == SID_FILTER_PROVIDER)
+ continue;
+ if ( nId == SID_CONVERT_IMAGES )
+ continue;
+
+ // used only internally
+ if ( nId == SID_SAVETO )
+ continue;
+ if ( nId == SID_SAVEACOPYITEM )
+ continue;
+ if ( nId == SID_MODIFYPASSWORDINFO )
+ continue;
+ if ( nId == SID_SUGGESTEDSAVEASDIR )
+ continue;
+ if ( nId == SID_SUGGESTEDSAVEASNAME )
+ continue;
+ if ( nId == SID_LOCK_CONTENT_EXTRACTION )
+ continue;
+ if ( nId == SID_LOCK_EXPORT )
+ continue;
+ if ( nId == SID_LOCK_PRINT )
+ continue;
+ if ( nId == SID_LOCK_SAVE )
+ continue;
+ if ( nId == SID_LOCK_EDITDOC )
+ continue;
+ if (nId == SID_REPLACEABLE)
+ continue;
+ }
+
+ OString aDbg = "Unknown item detected: " + OString::number(static_cast<sal_Int32>(nId));
+ DBG_ASSERT(nArg<nFormalArgs, aDbg.getStr());
+ }
+ }
+ }
+#endif
+
+ if ( !nProps )
+ return;
+
+ // convert every item into a property
+ uno::Sequence<beans::PropertyValue> aSequ(nProps);
+ beans::PropertyValue *pValue = aSequ.getArray();
+
+ sal_Int32 nActProp=0;
+ if ( !pSlot->IsMode(SfxSlotMode::METHOD) )
+ {
+ // slot is a property
+ sal_uInt16 nWhich = rSet.GetPool()->GetWhich(nSlotId);
+ bool bConvertTwips = ( rSet.GetPool()->GetMetric( nWhich ) == MapUnit::MapTwip );
+ const SfxPoolItem* pItem = rSet.GetItem<SfxPoolItem>(nWhich, false);
+ if ( pItem ) //???
+ {
+ sal_uInt16 nSubCount = pType->nAttribs;
+ if ( !nSubCount )
+ {
+ pValue[nActProp].Name = pSlot->pUnoName;
+ if ( !pItem->QueryValue( pValue[nActProp].Value ) )
+ {
+ SAL_WARN( "sfx", "Item not convertible: " << nSlotId );
+ }
+ }
+ else
+ {
+ // complex type, add a property value for every member of the struct
+ for ( sal_uInt16 n=1; n<=nSubCount; ++n )
+ {
+ sal_uInt8 nSubId = static_cast<sal_uInt8>(static_cast<sal_Int8>(pType->aAttrib[n-1].nAID));
+ if ( bConvertTwips )
+ nSubId |= CONVERT_TWIPS;
+
+ DBG_ASSERT(( pType->aAttrib[n-1].nAID ) <= 127, "Member ID out of range" );
+ pValue[nActProp].Name = pSlot->pUnoName +
+ "." +
+ OUString::createFromAscii( pType->aAttrib[n-1].pName );
+ if ( !pItem->QueryValue( pValue[nActProp++].Value, nSubId ) )
+ {
+ SAL_WARN( "sfx", "Sub item " << pType->aAttrib[n-1].nAID
+ << " not convertible in slot: " << nSlotId );
+ }
+ }
+ }
+ }
+
+ rArgs = aSequ;
+ return;
+ }
+
+ // slot is a method
+ sal_uInt16 nFormalArgs = pSlot->GetFormalArgumentCount();
+ for ( sal_uInt16 nArg=0; nArg<nFormalArgs; ++nArg )
+ {
+ const SfxFormalArgument &rArg = pSlot->GetFormalArgument( nArg );
+ sal_uInt16 nWhich = rSet.GetPool()->GetWhich( rArg.nSlotId );
+ bool bConvertTwips = ( rSet.GetPool()->GetMetric( nWhich ) == MapUnit::MapTwip );
+ const SfxPoolItem* pItem = rSet.GetItem<SfxPoolItem>(nWhich, false);
+ if ( pItem ) //???
+ {
+ sal_uInt16 nSubCount = rArg.pType->nAttribs;
+ if ( !nSubCount )
+ {
+ pValue[nActProp].Name = OUString::createFromAscii( rArg.pName ) ;
+ if ( !pItem->QueryValue( pValue[nActProp++].Value ) )
+ {
+ SAL_WARN( "sfx", "Item not convertible: " << rArg.nSlotId );
+ }
+ }
+ else
+ {
+ // complex type, add a property value for every member of the struct
+ for ( sal_uInt16 n = 1; n <= nSubCount; ++n )
+ {
+ sal_uInt8 nSubId = static_cast<sal_uInt8>(static_cast<sal_Int8>(rArg.pType->aAttrib[n-1].nAID));
+ if ( bConvertTwips )
+ nSubId |= CONVERT_TWIPS;
+
+ DBG_ASSERT((rArg.pType->aAttrib[n-1].nAID) <= 127, "Member ID out of range" );
+ pValue[nActProp].Name = OUString::createFromAscii( rArg.pName ) +
+ "." +
+ OUString::createFromAscii( rArg.pType->aAttrib[n-1].pName ) ;
+ if ( !pItem->QueryValue( pValue[nActProp++].Value, nSubId ) )
+ {
+ SAL_WARN( "sfx", "Sub item "
+ << rArg.pType->aAttrib[n-1].nAID
+ << " not convertible in slot: "
+ << rArg.nSlotId );
+ }
+ }
+ }
+ }
+ }
+
+ if ( nSlotId == SID_OPENDOC || nSlotId == SID_EXPORTDOC || nSlotId == SID_SAVEASDOC || nSlotId == SID_SAVEDOC ||
+ nSlotId == SID_SAVETO || nSlotId == SID_EXPORTDOCASPDF || nSlotId == SID_DIRECTEXPORTDOCASPDF ||
+ nSlotId == SID_EXPORTDOCASEPUB || nSlotId == SID_DIRECTEXPORTDOCASEPUB ||
+ nSlotId == SID_REDACTDOC || nSlotId == SID_AUTOREDACTDOC || nSlotId == SID_SAVEACOPY )
+ {
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_COMPONENTDATA, false) )
+ {
+ pValue[nActProp].Name = sComponentData;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_COMPONENTCONTEXT, false) )
+ {
+ pValue[nActProp].Name = sComponentContext;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_PROGRESS_STATUSBAR_CONTROL, false) )
+ {
+ pValue[nActProp].Name = sStatusInd;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_INTERACTIONHANDLER, false) )
+ {
+ pValue[nActProp].Name = sInteractionHdl;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_VIEW_DATA, false) )
+ {
+ pValue[nActProp].Name = sViewData;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_FILTER_DATA, false) )
+ {
+ pValue[nActProp].Name = sFilterData;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_DOCUMENT, false) )
+ {
+ pValue[nActProp].Name = sModel;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_CONTENT, false) )
+ {
+ pValue[nActProp].Name = sUCBContent;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_INPUTSTREAM, false) )
+ {
+ pValue[nActProp].Name = sInputStream;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_STREAM, false) )
+ {
+ pValue[nActProp].Name = sStream;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_OUTPUTSTREAM, false) )
+ {
+ pValue[nActProp].Name = sOutputStream;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_POSTDATA, false) )
+ {
+ pValue[nActProp].Name = sPostData;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxPoolItem *pItem = nullptr; SfxItemState::SET == rSet.GetItemState( SID_FILLFRAME, false, &pItem) )
+ {
+ pValue[nActProp].Name = sFrame;
+ if ( auto pUsrAnyItem = dynamic_cast< const SfxUnoAnyItem *>( pItem ) )
+ {
+ OSL_FAIL( "TransformItems: transporting an XFrame via an SfxUnoAnyItem is not deprecated!" );
+ pValue[nActProp++].Value = pUsrAnyItem->GetValue();
+ }
+ else if ( auto pUnoFrameItem = dynamic_cast< const SfxUnoFrameItem *>( pItem ) )
+ pValue[nActProp++].Value <<= pUnoFrameItem->GetFrame();
+ else
+ OSL_FAIL( "TransformItems: invalid item type for SID_FILLFRAME!" );
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_TEMPLATE, false) )
+ {
+ pValue[nActProp].Name = sAsTemplate;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_OPEN_NEW_VIEW, false) )
+ {
+ pValue[nActProp].Name = sOpenNewView;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_FAIL_ON_WARNING, false) )
+ {
+ pValue[nActProp].Name = sFailOnWarning;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxUInt16Item *pItem = rSet.GetItemIfSet( SID_VIEW_ID, false) )
+ {
+ pValue[nActProp].Name = sViewId;
+ pValue[nActProp++].Value <<= static_cast<sal_Int16>(pItem->GetValue());
+ }
+ if ( const SfxUInt16Item *pItem = rSet.GetItemIfSet( SID_PLUGIN_MODE, false) )
+ {
+ pValue[nActProp].Name = sPluginMode;
+ pValue[nActProp++].Value <<= static_cast<sal_Int16>(pItem->GetValue());
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_DOC_READONLY, false) )
+ {
+ pValue[nActProp].Name = sReadOnly;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_DDE_RECONNECT_ONLOAD, false) )
+ {
+ pValue[nActProp].Name = sDdeReconnect;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_DOC_STARTPRESENTATION, false) )
+ {
+ pValue[nActProp].Name = sStartPresentation;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_SELECTION, false) )
+ {
+ pValue[nActProp].Name = sSelectionOnly;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_HIDDEN, false) )
+ {
+ pValue[nActProp].Name = sHidden;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_MINIMIZED, false) )
+ {
+ pValue[nActProp].Name = sMinimized;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_SILENT, false) )
+ {
+ pValue[nActProp].Name = sSilent;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_PREVIEW, false) )
+ {
+ pValue[nActProp].Name = sPreview;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_VIEWONLY, false) )
+ {
+ pValue[nActProp].Name = sViewOnly;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_EDITDOC, false) )
+ {
+ pValue[nActProp].Name = sDontEdit;
+ pValue[nActProp++].Value <<= !pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_FILE_DIALOG, false) )
+ {
+ pValue[nActProp].Name = sUseSystemDialog;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_STANDARD_DIR, false) )
+ {
+ pValue[nActProp].Name = sStandardDir;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringListItem *pItem = rSet.GetItemIfSet( SID_DENY_LIST, false) )
+ {
+ pValue[nActProp].Name = sDenyList;
+
+ css::uno::Sequence< OUString > aList;
+ pItem->GetStringList( aList );
+ pValue[nActProp++].Value <<= aList ;
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_TARGETNAME, false) )
+ {
+ pValue[nActProp].Name = sFrameName;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_DOC_SALVAGE, false) )
+ {
+ pValue[nActProp].Name = sSalvagedFile;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_PATH, false) )
+ {
+ pValue[nActProp].Name = sFolderName;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_CONTENTTYPE, false) )
+ {
+ pValue[nActProp].Name = sMediaType;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_TEMPLATE_NAME, false) )
+ {
+ pValue[nActProp].Name = sTemplateName;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_TEMPLATE_REGIONNAME, false) )
+ {
+ pValue[nActProp].Name = sTemplateRegionName;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_JUMPMARK, false) )
+ {
+ pValue[nActProp].Name = sJumpMark;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_CHARSET, false) )
+ {
+ pValue[nActProp].Name = sCharacterSet;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxUInt16Item *pItem = rSet.GetItemIfSet( SID_MACROEXECMODE, false) )
+ {
+ pValue[nActProp].Name = sMacroExecMode;
+ pValue[nActProp++].Value <<= static_cast<sal_Int16>(pItem->GetValue());
+ }
+ if ( const SfxUInt16Item *pItem = rSet.GetItemIfSet( SID_UPDATEDOCMODE, false) )
+ {
+ pValue[nActProp].Name = sUpdateDocMode;
+ pValue[nActProp++].Value <<= static_cast<sal_Int16>(pItem->GetValue());
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_REPAIRPACKAGE, false) )
+ {
+ pValue[nActProp].Name = sRepairPackage;
+ pValue[nActProp++].Value <<= pItem->GetValue() ;
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_DOCINFO_TITLE, false) )
+ {
+ pValue[nActProp].Name = sDocumentTitle;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_DOC_BASEURL, false) )
+ {
+ pValue[nActProp].Name = sDocumentBaseURL;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_DOC_HIERARCHICALNAME, false) )
+ {
+ pValue[nActProp].Name = sHierarchicalDocumentName;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_COPY_STREAM_IF_POSSIBLE, false) )
+ {
+ pValue[nActProp].Name = sCopyStreamIfPossible;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_NOAUTOSAVE, false) )
+ {
+ pValue[nActProp].Name = sNoAutoSave;
+ pValue[nActProp++].Value <<= pItem->GetValue() ;
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_MODIFYPASSWORDINFO, false) )
+ {
+ pValue[nActProp].Name = sModifyPasswordInfo;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxUnoAnyItem *pItem = rSet.GetItemIfSet( SID_ENCRYPTIONDATA, false) )
+ {
+ pValue[nActProp].Name = sEncryptionData;
+ pValue[nActProp++].Value = pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_SUGGESTEDSAVEASDIR, false) )
+ {
+ pValue[nActProp].Name = sSuggestedSaveAsDir;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_SUGGESTEDSAVEASNAME, false) )
+ {
+ pValue[nActProp].Name = sSuggestedSaveAsName;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxStringItem *pItem = rSet.GetItemIfSet( SID_DOC_SERVICE, false) )
+ {
+ pValue[nActProp].Name = sDocumentService;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if (const SfxStringItem *pItem = rSet.GetItemIfSet(SID_FILTER_PROVIDER))
+ {
+ pValue[nActProp].Name = sFilterProvider;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if (const SfxStringItem *pItem = rSet.GetItemIfSet(SID_CONVERT_IMAGES))
+ {
+ pValue[nActProp].Name = sImageFilter;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_LOCK_CONTENT_EXTRACTION, false) )
+ {
+ pValue[nActProp].Name = sLockContentExtraction;
+ pValue[nActProp++].Value <<= pItem->GetValue() ;
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_LOCK_EXPORT, false) )
+ {
+ pValue[nActProp].Name = sLockExport;
+ pValue[nActProp++].Value <<= pItem->GetValue() ;
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_LOCK_PRINT, false) )
+ {
+ pValue[nActProp].Name = sLockPrint;
+ pValue[nActProp++].Value <<= pItem->GetValue() ;
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_LOCK_SAVE, false) )
+ {
+ pValue[nActProp].Name = sLockSave;
+ pValue[nActProp++].Value <<= pItem->GetValue() ;
+ }
+ if ( const SfxBoolItem *pItem = rSet.GetItemIfSet( SID_LOCK_EDITDOC, false) )
+ {
+ pValue[nActProp].Name = sLockEditDoc;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ if (const SfxBoolItem *pItem = rSet.GetItemIfSet(SID_REPLACEABLE, false))
+ {
+ pValue[nActProp].Name = sReplaceable;
+ pValue[nActProp++].Value <<= pItem->GetValue();
+ }
+ }
+
+ rArgs = aSequ;
+}
+
+void SAL_CALL FilterOptionsContinuation::setFilterOptions(
+ const uno::Sequence<beans::PropertyValue>& rProps )
+{
+ rProperties = rProps;
+}
+
+uno::Sequence< beans::PropertyValue > SAL_CALL
+ FilterOptionsContinuation::getFilterOptions()
+{
+ return rProperties;
+}
+
+
+RequestFilterOptions::RequestFilterOptions( uno::Reference< frame::XModel > const & rModel,
+ const uno::Sequence< beans::PropertyValue >& rProperties )
+{
+ uno::Reference< uno::XInterface > temp2;
+ document::FilterOptionsRequest aOptionsRequest( OUString(),
+ temp2,
+ rModel,
+ rProperties );
+
+ m_aRequest <<= aOptionsRequest;
+
+ m_xAbort = new comphelper::OInteractionAbort;
+ m_xOptions = new FilterOptionsContinuation;
+}
+
+uno::Any SAL_CALL RequestFilterOptions::getRequest()
+{
+ return m_aRequest;
+}
+
+uno::Sequence< uno::Reference< task::XInteractionContinuation > >
+ SAL_CALL RequestFilterOptions::getContinuations()
+{
+ return { m_xAbort, m_xOptions };
+}
+
+
+class RequestPackageReparation_Impl : public ::cppu::WeakImplHelper< task::XInteractionRequest >
+{
+ uno::Any m_aRequest;
+ rtl::Reference<comphelper::OInteractionApprove> m_xApprove;
+ rtl::Reference<comphelper::OInteractionDisapprove> m_xDisapprove;
+
+public:
+ explicit RequestPackageReparation_Impl( const OUString& aName );
+ bool isApproved() const;
+ virtual uno::Any SAL_CALL getRequest() override;
+ virtual uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL getContinuations() override;
+};
+
+RequestPackageReparation_Impl::RequestPackageReparation_Impl( const OUString& aName )
+{
+ uno::Reference< uno::XInterface > temp2;
+ document::BrokenPackageRequest aBrokenPackageRequest( OUString(), temp2, aName );
+ m_aRequest <<= aBrokenPackageRequest;
+ m_xApprove = new comphelper::OInteractionApprove;
+ m_xDisapprove = new comphelper::OInteractionDisapprove;
+}
+
+bool RequestPackageReparation_Impl::isApproved() const
+{
+ return m_xApprove->wasSelected();
+}
+
+uno::Any SAL_CALL RequestPackageReparation_Impl::getRequest()
+{
+ return m_aRequest;
+}
+
+uno::Sequence< uno::Reference< task::XInteractionContinuation > >
+ SAL_CALL RequestPackageReparation_Impl::getContinuations()
+{
+ return { m_xApprove, m_xDisapprove };
+}
+
+RequestPackageReparation::RequestPackageReparation( const OUString& aName )
+ : mxImpl(new RequestPackageReparation_Impl( aName ))
+{
+}
+
+RequestPackageReparation::~RequestPackageReparation()
+{
+}
+
+bool RequestPackageReparation::isApproved() const
+{
+ return mxImpl->isApproved();
+}
+
+css::uno::Reference < task::XInteractionRequest > RequestPackageReparation::GetRequest() const
+{
+ return mxImpl;
+}
+
+
+class NotifyBrokenPackage_Impl : public ::cppu::WeakImplHelper< task::XInteractionRequest >
+{
+ uno::Any m_aRequest;
+ rtl::Reference<comphelper::OInteractionAbort> m_xAbort;
+
+public:
+ explicit NotifyBrokenPackage_Impl(const OUString& rName);
+ virtual uno::Any SAL_CALL getRequest() override;
+ virtual uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL getContinuations() override;
+};
+
+NotifyBrokenPackage_Impl::NotifyBrokenPackage_Impl( const OUString& aName )
+{
+ uno::Reference< uno::XInterface > temp2;
+ document::BrokenPackageRequest aBrokenPackageRequest( OUString(), temp2, aName );
+ m_aRequest <<= aBrokenPackageRequest;
+ m_xAbort = new comphelper::OInteractionAbort;
+}
+
+uno::Any SAL_CALL NotifyBrokenPackage_Impl::getRequest()
+{
+ return m_aRequest;
+}
+
+uno::Sequence< uno::Reference< task::XInteractionContinuation > >
+ SAL_CALL NotifyBrokenPackage_Impl::getContinuations()
+{
+ return { m_xAbort };
+}
+
+NotifyBrokenPackage::NotifyBrokenPackage( const OUString& aName )
+ : mxImpl(new NotifyBrokenPackage_Impl( aName ))
+{
+}
+
+NotifyBrokenPackage::~NotifyBrokenPackage()
+{
+}
+
+css::uno::Reference < task::XInteractionRequest > NotifyBrokenPackage::GetRequest() const
+{
+ return mxImpl;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/childwin.cxx b/sfx2/source/appl/childwin.cxx
new file mode 100644
index 0000000000..6bf2814599
--- /dev/null
+++ b/sfx2/source/appl/childwin.cxx
@@ -0,0 +1,623 @@
+/* -*- 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 <memory>
+#include <unotools/viewoptions.hxx>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <comphelper/string.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+
+#include <vcl/svapp.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/dockwin.hxx>
+#include <sfx2/dispatch.hxx>
+#include <workwin.hxx>
+
+#include <sfx2/sfxsids.hrc>
+#include <o3tl/string_view.hxx>
+
+const sal_uInt16 nVersion = 2;
+
+SfxChildWinFactory::SfxChildWinFactory( SfxChildWinCtor pTheCtor, sal_uInt16 nID,
+ sal_uInt16 n )
+ : pCtor(pTheCtor)
+ , nId( nID )
+ , nPos(n)
+{}
+
+struct SfxChildWindow_Impl
+{
+ css::uno::Reference< css::frame::XFrame > xFrame;
+ css::uno::Reference< css::lang::XEventListener > xListener;
+ SfxChildWinFactory aFact = { nullptr, 0, 0 };
+ bool bHideNotDelete;
+ bool bVisible;
+ bool bWantsFocus;
+ SfxWorkWindow* pWorkWin;
+};
+
+namespace {
+
+class DisposeListener : public ::cppu::WeakImplHelper< css::lang::XEventListener >
+{
+ public:
+ DisposeListener( SfxChildWindow* pOwner ,
+ SfxChildWindow_Impl* pData )
+ : m_pOwner( pOwner )
+ , m_pData ( pData )
+ {}
+
+ virtual void SAL_CALL disposing( const css::lang::EventObject& aSource ) override
+ {
+ css::uno::Reference< css::lang::XEventListener > xSelfHold( this );
+
+ css::uno::Reference< css::lang::XComponent > xComp( aSource.Source, css::uno::UNO_QUERY );
+ if( xComp.is() )
+ xComp->removeEventListener( this );
+
+ if( !m_pOwner || !m_pData )
+ return;
+
+ m_pData->xListener.clear();
+
+ if ( m_pData->pWorkWin )
+ {
+ // m_pOwner and m_pData will be killed
+ m_pData->xFrame.clear();
+ m_pData->pWorkWin->GetBindings().Execute( m_pOwner->GetType() );
+ }
+ else
+ {
+ delete m_pOwner;
+ }
+
+ m_pOwner = nullptr;
+ m_pData = nullptr;
+ }
+
+ private:
+ SfxChildWindow* m_pOwner;
+ SfxChildWindow_Impl* m_pData ;
+};
+
+}
+
+bool GetPosSizeFromString( std::u16string_view rStr, Point& rPos, Size& rSize )
+{
+ if ( comphelper::string::getTokenCount(rStr, '/') != 4 )
+ return false;
+
+ sal_Int32 nIdx = 0;
+ rPos.setX( o3tl::toInt32(o3tl::getToken(rStr, 0, '/', nIdx)) );
+ rPos.setY( o3tl::toInt32(o3tl::getToken(rStr, 0, '/', nIdx)) );
+ rSize.setWidth( o3tl::toInt32(o3tl::getToken(rStr, 0, '/', nIdx)) );
+ rSize.setHeight( o3tl::toInt32(o3tl::getToken(rStr, 0, '/', nIdx)) );
+
+ // negative sizes are invalid
+ return rSize.Width() >= 0 && rSize.Height() >= 0;
+}
+
+bool GetSplitSizeFromString( std::u16string_view rStr, Size& rSize )
+{
+ size_t nIndex = rStr.find( ',' );
+ if ( nIndex != std::u16string_view::npos )
+ {
+ std::u16string_view aStr = rStr.substr( nIndex+1 );
+
+ sal_Int32 nCount = comphelper::string::getTokenCount(aStr, ';');
+ if ( nCount != 2 )
+ return false;
+
+ sal_Int32 nIdx{ 0 };
+ rSize.setWidth( o3tl::toInt32(o3tl::getToken(aStr, 0, ';', nIdx )) );
+ rSize.setHeight( o3tl::toInt32(o3tl::getToken(aStr, 0, ';', nIdx )) );
+
+ // negative sizes are invalid
+ return rSize.Width() >= 0 && rSize.Height() >= 0;
+ }
+
+ return false;
+}
+
+SfxChildWindow::SfxChildWindow(vcl::Window *pParentWindow, sal_uInt16 nId)
+ : pParent(pParentWindow)
+ , pImpl(new SfxChildWindow_Impl)
+ , eChildAlignment(SfxChildAlignment::NOALIGNMENT)
+ , nType(nId)
+{
+ pImpl->bHideNotDelete = false;
+ pImpl->bWantsFocus = true;
+ pImpl->bVisible = true;
+ pImpl->pWorkWin = nullptr;
+}
+
+void SfxChildWindow::Destroy()
+{
+ if ( GetFrame().is() )
+ {
+ ClearWorkwin();
+ try
+ {
+ css::uno::Reference < css::util::XCloseable > xClose( GetFrame(), css::uno::UNO_QUERY );
+ if ( xClose.is() )
+ xClose->close( true );
+ else
+ GetFrame()->dispose();
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+ }
+ else
+ delete this;
+}
+
+void SfxChildWindow::ClearWorkwin()
+{
+ if (pImpl->pWorkWin)
+ {
+ if (pImpl->pWorkWin->GetActiveChild_Impl() == pWindow)
+ pImpl->pWorkWin->SetActiveChild_Impl(nullptr);
+ pImpl->pWorkWin = nullptr;
+ }
+}
+
+SfxChildWindow::~SfxChildWindow()
+{
+ ClearWorkwin();
+ if (xController)
+ {
+ xController->ChildWinDispose();
+ xController.reset();
+ }
+ pWindow.disposeAndClear();
+}
+
+std::unique_ptr<SfxChildWindow> SfxChildWindow::CreateChildWindow( sal_uInt16 nId,
+ vcl::Window *pParent, SfxBindings* pBindings, SfxChildWinInfo const & rInfo)
+{
+ std::unique_ptr<SfxChildWindow> pChild;
+ SfxChildWinFactory* pFact=nullptr;
+ SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
+
+ // First search for ChildWindow in SDT; Overlay windows are realized
+ // by using ChildWindowContext
+ SfxApplication *pApp = SfxGetpApp();
+ {
+ pFact = pApp->GetChildWinFactoryById(nId);
+ if ( pFact )
+ {
+ if ( rInfo.bVisible )
+ {
+ if ( pBindings )
+ pBindings->ENTERREGISTRATIONS();
+ SfxChildWinInfo aInfo = rInfo;
+ Application::SetSystemWindowMode( SystemWindowFlags::NOAUTOMODE );
+ pChild = pFact->pCtor( pParent, nId, pBindings, &aInfo );
+ Application::SetSystemWindowMode( nOldMode );
+ if ( pBindings )
+ pBindings->LEAVEREGISTRATIONS();
+ }
+ }
+ }
+
+ SfxDispatcher *pDisp = pBindings ? pBindings->GetDispatcher_Impl() : nullptr;
+ SfxModule *pMod = pDisp ? SfxModule::GetActiveModule( pDisp->GetFrame() ) : nullptr;
+ if (!pChild && pMod)
+ {
+ pFact = pMod->GetChildWinFactoryById(nId);
+ if ( pFact )
+ {
+ if ( rInfo.bVisible )
+ {
+ if ( pBindings )
+ pBindings->ENTERREGISTRATIONS();
+ SfxChildWinInfo aInfo = rInfo;
+ Application::SetSystemWindowMode( SystemWindowFlags::NOAUTOMODE );
+ pChild = pFact->pCtor( pParent, nId, pBindings, &aInfo );
+ Application::SetSystemWindowMode( nOldMode );
+ if ( pBindings )
+ pBindings->LEAVEREGISTRATIONS();
+ }
+ }
+ }
+
+ if (pChild)
+ {
+ assert(pFact && "pChild is returned by a call on pFact, so pFact cannot be null");
+ pChild->SetFactory_Impl( pFact );
+ }
+
+ DBG_ASSERT(pFact && (pChild || !rInfo.bVisible), "ChildWindow-Typ not registered!");
+
+ if (pChild && (!pChild->pWindow && !pChild->xController))
+ {
+ pChild.reset();
+ SAL_INFO("sfx.appl", "ChildWindow has no Window!");
+ }
+
+ return pChild;
+}
+
+
+void SfxChildWindow::SaveStatus(const SfxChildWinInfo& rInfo)
+{
+ sal_uInt16 nID = GetType();
+
+ OUString aInfoVisible = rInfo.bVisible ? OUString("V") : OUString("H");
+
+ OUString aWinData = "V"
+ + OUString::number(static_cast<sal_Int32>(nVersion))
+ + ","
+ + aInfoVisible
+ + ","
+ + OUString::number(static_cast<sal_Int32>(rInfo.nFlags));
+
+ if ( !rInfo.aExtraString.isEmpty() )
+ aWinData += "," + rInfo.aExtraString;
+
+ OUString sName(OUString::number(nID));
+ //Try and save window state per-module, e.g. sidebar on in one application
+ //but off in another
+ if (!rInfo.aModule.isEmpty())
+ sName = rInfo.aModule + "/" + sName;
+ SvtViewOptions aWinOpt(EViewType::Window, sName);
+ aWinOpt.SetWindowState(rInfo.aWinState);
+
+ css::uno::Sequence < css::beans::NamedValue > aSeq
+ { { "Data", css::uno::Any(aWinData) } };
+ aWinOpt.SetUserData( aSeq );
+
+ // ... but save status at runtime!
+ pImpl->aFact.aInfo = rInfo;
+}
+
+void SfxChildWindow::SetAlignment(SfxChildAlignment eAlign)
+{
+ eChildAlignment = eAlign;
+}
+
+SfxChildWinInfo SfxChildWindow::GetInfo() const
+{
+ SfxChildWinInfo aInfo(pImpl->aFact.aInfo);
+ if (xController)
+ {
+ weld::Dialog* pDialog = xController->getDialog();
+ aInfo.aPos = pDialog->get_position();
+ aInfo.aSize = pDialog->get_size();
+ vcl::WindowDataMask nMask = vcl::WindowDataMask::Pos | vcl::WindowDataMask::State;
+ if (pDialog->get_resizable())
+ nMask |= vcl::WindowDataMask::Size;
+ aInfo.aWinState = pDialog->get_window_state(nMask);
+ }
+ else if (pWindow)
+ {
+ aInfo.aPos = pWindow->GetPosPixel();
+ aInfo.aSize = pWindow->GetSizePixel();
+ if ( pWindow->IsSystemWindow() )
+ {
+ vcl::WindowDataMask nMask = vcl::WindowDataMask::Pos | vcl::WindowDataMask::State;
+ if ( pWindow->GetStyle() & WB_SIZEABLE )
+ nMask |= vcl::WindowDataMask::Size;
+ aInfo.aWinState = static_cast<SystemWindow*>(pWindow.get())->GetWindowState( nMask );
+ }
+ else if (DockingWindow* pDockingWindow = dynamic_cast<DockingWindow*>(pWindow.get()))
+ {
+ if (pDockingWindow->GetFloatingWindow())
+ aInfo.aWinState = pDockingWindow->GetFloatingWindow()->GetWindowState();
+ else if (SfxDockingWindow* pSfxDockingWindow = dynamic_cast<SfxDockingWindow*>(pDockingWindow))
+ {
+ SfxChildWinInfo aTmpInfo;
+ pSfxDockingWindow->FillInfo( aTmpInfo );
+ aInfo.aExtraString = aTmpInfo.aExtraString;
+ }
+ }
+ }
+
+ aInfo.bVisible = pImpl->bVisible;
+ aInfo.nFlags = SfxChildWindowFlags::NONE;
+ return aInfo;
+}
+
+sal_uInt16 SfxChildWindow::GetPosition() const
+{
+ return pImpl->aFact.nPos;
+}
+
+void SfxChildWindow::InitializeChildWinFactory_Impl(sal_uInt16 nId, SfxChildWinInfo& rInfo)
+{
+ // load configuration
+
+ std::optional<SvtViewOptions> xWinOpt;
+ // first see if a module specific id exists
+ if (rInfo.aModule.getLength())
+ xWinOpt.emplace(EViewType::Window, rInfo.aModule + "/" + OUString::number(nId));
+
+ // if not then try the generic id
+ if (!xWinOpt || !xWinOpt->Exists())
+ xWinOpt.emplace(EViewType::Window, OUString::number(nId));
+
+ if (xWinOpt->Exists() && xWinOpt->HasVisible() )
+ rInfo.bVisible = xWinOpt->IsVisible(); // set state from configuration. Can be overwritten by UserData, see below
+
+ css::uno::Sequence < css::beans::NamedValue > aSeq = xWinOpt->GetUserData();
+
+ OUString aTmp;
+ if ( aSeq.hasElements() )
+ aSeq[0].Value >>= aTmp;
+
+ OUString aWinData( aTmp );
+ rInfo.aWinState = xWinOpt->GetWindowState();
+
+ if ( aWinData.isEmpty() )
+ return;
+
+ // Search for version ID
+ if ( aWinData[0] != 0x0056 ) // 'V' = 56h
+ // A version ID, so do not use
+ return;
+
+ // Delete 'V'
+ aWinData = aWinData.copy(1);
+
+ // Read version
+ char cToken = ',';
+ sal_Int32 nPos = aWinData.indexOf( cToken );
+ sal_uInt16 nActVersion = static_cast<sal_uInt16>(o3tl::toInt32(aWinData.subView( 0, nPos + 1 )));
+ if ( nActVersion != nVersion )
+ return;
+
+ aWinData = aWinData.copy(nPos+1);
+
+ // Load Visibility: is coded as a char
+ rInfo.bVisible = (aWinData[0] == 0x0056); // 'V' = 56h
+ aWinData = aWinData.copy(1);
+ nPos = aWinData.indexOf( cToken );
+ if (nPos == -1)
+ return;
+
+ sal_Int32 nNextPos = aWinData.indexOf( cToken, 2 );
+ if ( nNextPos != -1 )
+ {
+ // there is extra information
+ rInfo.nFlags = static_cast<SfxChildWindowFlags>(static_cast<sal_uInt16>(o3tl::toInt32(aWinData.subView( nPos+1, nNextPos - nPos - 1 ))));
+ aWinData = aWinData.replaceAt( nPos, nNextPos-nPos+1, u"" );
+ rInfo.aExtraString = aWinData;
+ }
+ else
+ rInfo.nFlags = static_cast<SfxChildWindowFlags>(static_cast<sal_uInt16>(o3tl::toInt32(aWinData.subView( nPos+1 ))));
+}
+
+bool ParentIsFloatingWindow(const vcl::Window *pParent)
+{
+ if (!pParent)
+ return false;
+ if (pParent->GetType() == WindowType::DOCKINGWINDOW || pParent->GetType() == WindowType::TOOLBOX)
+ return static_cast<const DockingWindow*>(pParent)->GetFloatingWindow() != nullptr;
+ if (pParent->GetType() == WindowType::FLOATINGWINDOW)
+ return true;
+ return false;
+}
+
+void SfxChildWindow::SetFactory_Impl( const SfxChildWinFactory *pF )
+{
+ pImpl->aFact = *pF;
+}
+
+void SfxChildWindow::SetHideNotDelete( bool bOn )
+{
+ pImpl->bHideNotDelete = bOn;
+}
+
+bool SfxChildWindow::IsHideNotDelete() const
+{
+ return pImpl->bHideNotDelete;
+}
+
+void SfxChildWindow::SetWantsFocus( bool bSet )
+{
+ pImpl->bWantsFocus = bSet;
+}
+
+bool SfxChildWindow::WantsFocus() const
+{
+ return pImpl->bWantsFocus;
+}
+
+bool SfxChildWinInfo::GetExtraData_Impl
+(
+ SfxChildAlignment *pAlign
+) const
+{
+ // invalid?
+ if ( aExtraString.isEmpty() )
+ return false;
+ OUString aStr;
+ sal_Int32 nPos = aExtraString.indexOf("AL:");
+ if ( nPos == -1 )
+ return false;
+
+ // Try to read the alignment string "ALIGN :(...)", but if
+ // it is not present, then use an older version
+ sal_Int32 n1 = aExtraString.indexOf('(', nPos);
+ if ( n1 != -1 )
+ {
+ sal_Int32 n2 = aExtraString.indexOf(')', n1);
+ if ( n2 != -1 )
+ {
+ // Cut out Alignment string
+ aStr = aExtraString.copy(nPos, n2 - nPos + 1);
+ aStr = aStr.replaceAt(nPos, n1-nPos+1, u"");
+ }
+ }
+
+ // First extract the Alignment
+ if ( aStr.isEmpty() )
+ return false;
+ if ( pAlign )
+ *pAlign = static_cast<SfxChildAlignment>(static_cast<sal_uInt16>(aStr.toInt32()));
+
+ // then the LastAlignment
+ nPos = aStr.indexOf(',');
+ if ( nPos == -1 )
+ return false;
+ aStr = aStr.copy(nPos+1);
+
+ // Then the splitting information
+ nPos = aStr.indexOf(',');
+ if ( nPos == -1 )
+ // No docking in a Splitwindow
+ return true;
+ aStr = aStr.copy(nPos+1);
+ Point aChildPos;
+ Size aChildSize;
+ return GetPosSizeFromString( aStr, aChildPos, aChildSize );
+}
+
+bool SfxChildWindow::IsVisible() const
+{
+ return pImpl->bVisible;
+}
+
+void SfxChildWindow::SetVisible_Impl( bool bVis )
+{
+ pImpl->bVisible = bVis;
+}
+
+void SfxChildWindow::Hide()
+{
+ if (xController)
+ xController->EndDialog(nCloseResponseToJustHide);
+ else
+ pWindow->Hide();
+}
+
+void SfxChildWindow::Show( ShowFlags nFlags )
+{
+ if (xController)
+ {
+ if (!xController->getDialog()->get_visible())
+ {
+ if (!xController->CloseOnHide())
+ {
+ // tdf#155708 - do not run a new (Async) validation window,
+ // because we already have one in sync mode, just show the running one
+ xController->getDialog()->show();
+ }
+ else
+ {
+ weld::DialogController::runAsync(xController,
+ [this](sal_Int32 nResult) {
+ if (nResult == nCloseResponseToJustHide)
+ return;
+ xController->Close();
+ });
+ }
+ }
+ }
+ else
+ pWindow->Show(true, nFlags);
+}
+
+void SfxChildWindow::SetWorkWindow_Impl( SfxWorkWindow* pWin )
+{
+ pImpl->pWorkWin = pWin;
+ if (pWin)
+ {
+ if ( (xController && xController->getDialog()->has_toplevel_focus()) ||
+ (pWindow && pWindow->HasChildPathFocus()) )
+ {
+ pImpl->pWorkWin->SetActiveChild_Impl( pWindow );
+ }
+ }
+}
+
+void SfxChildWindow::Activate_Impl()
+{
+ if(pImpl->pWorkWin!=nullptr)
+ pImpl->pWorkWin->SetActiveChild_Impl( pWindow );
+}
+
+bool SfxChildWindow::QueryClose()
+{
+ bool bAllow = true;
+
+ if ( pImpl->xFrame.is() )
+ {
+ css::uno::Reference< css::frame::XController > xCtrl = pImpl->xFrame->getController();
+ if ( xCtrl.is() )
+ bAllow = xCtrl->suspend( true );
+ }
+
+ if ( bAllow )
+ {
+ if (GetController())
+ {
+ weld::Dialog* pDialog = GetController()->getDialog();
+ bAllow = !pDialog->get_visible() || !pDialog->get_modal();
+ }
+ else if (GetWindow())
+ bAllow = !GetWindow()->IsInModalMode();
+ }
+
+ return bAllow;
+}
+
+const css::uno::Reference< css::frame::XFrame >& SfxChildWindow::GetFrame() const
+{
+ return pImpl->xFrame;
+}
+
+void SfxChildWindow::SetFrame( const css::uno::Reference< css::frame::XFrame > & rFrame )
+{
+ // Do nothing if nothing will be changed ...
+ if( pImpl->xFrame == rFrame )
+ return;
+
+ // ... but stop listening on old frame, if connection exist!
+ if( pImpl->xFrame.is() )
+ pImpl->xFrame->removeEventListener( pImpl->xListener );
+
+ // If new frame is not NULL -> we must guarantee valid listener for disposing events.
+ // Use already existing or create new one.
+ if( rFrame.is() )
+ if( !pImpl->xListener.is() )
+ pImpl->xListener.set( new DisposeListener( this, pImpl.get() ) );
+
+ // Set new frame in data container
+ // and build new listener connection, if necessary.
+ pImpl->xFrame = rFrame;
+ if( pImpl->xFrame.is() )
+ pImpl->xFrame->addEventListener( pImpl->xListener );
+}
+
+void SfxChildWindow::RegisterChildWindow(SfxModule* pMod, const SfxChildWinFactory& rFact)
+{
+ SfxGetpApp()->RegisterChildWindow_Impl( pMod, rFact );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/fileobj.cxx b/sfx2/source/appl/fileobj.cxx
new file mode 100644
index 0000000000..18aea4a590
--- /dev/null
+++ b/sfx2/source/appl/fileobj.cxx
@@ -0,0 +1,435 @@
+/* -*- 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 <tools/urlobj.hxx>
+#include <tools/stream.hxx>
+#include <sot/formats.hxx>
+#include <sal/log.hxx>
+#include <sfx2/lnkbase.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sot/exchange.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <sfx2/docfac.hxx>
+#include <com/sun/star/document/XTypeDetection.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <unotools/mediadescriptor.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/opengrf.hxx>
+#include <sfx2/sfxresid.hxx>
+#include <sfx2/objsh.hxx>
+#include "fileobj.hxx"
+#include <sfx2/strings.hrc>
+#include <vcl/svapp.hxx>
+
+enum class SvFileObjectType
+{
+ Text = 1, Graphic = 2, Object = 3
+};
+
+SvFileObject::SvFileObject()
+ : nPostUserEventId(nullptr)
+ , nType(SvFileObjectType::Text)
+ , bLoadAgain(true)
+ , bSynchron(false)
+ , bLoadError(false)
+ , bWaitForData(false)
+ , bDataReady(false)
+ , bClearMedium(false)
+ , bStateChangeCalled(false)
+{
+}
+
+SvFileObject::~SvFileObject()
+{
+ if (xMed.is())
+ {
+ xMed->SetDoneLink( Link<void*,void>() );
+ xMed.clear();
+ }
+ if (nPostUserEventId)
+ Application::RemoveUserEvent(nPostUserEventId);
+}
+
+bool SvFileObject::GetData( css::uno::Any & rData,
+ const OUString & rMimeType,
+ bool /*bGetSynchron*/ )
+{
+ SotClipboardFormatId nFmt = SotExchange::RegisterFormatMimeType( rMimeType );
+ switch( nType )
+ {
+ case SvFileObjectType::Text:
+ if( SotClipboardFormatId::SIMPLE_FILE == nFmt )
+ {
+ // The media in the application must be opened to lookup the
+ // relative file links!! This is done through the link manager
+ // of the Storage.
+ rData <<= sFileNm;
+ }
+ break;
+
+ case SvFileObjectType::Graphic:
+ if (SotClipboardFormatId::GDIMETAFILE == nFmt
+ || SotClipboardFormatId::BITMAP == nFmt
+ || SotClipboardFormatId::SVXB == nFmt)
+ {
+ rData <<= sFileNm;
+ }
+ break;
+ case SvFileObjectType::Object:
+ // TODO/LATER: possibility to insert a new object
+ rData <<= sFileNm;
+ break;
+ }
+ return true/*0 != aTypeList.Count()*/;
+}
+
+bool SvFileObject::Connect( sfx2::SvBaseLink* pLink )
+{
+ if( !pLink || !pLink->GetLinkManager() )
+ return false;
+
+ // Test if not another link of the same connection already exists
+ sfx2::LinkManager::GetDisplayNames( pLink, nullptr, &sFileNm, nullptr, &sFilter );
+
+ if( sfx2::SvBaseLinkObjectType::ClientGraphic == pLink->GetObjType() )
+ {
+ SfxObjectShellRef pShell = pLink->GetLinkManager()->GetPersist();
+ if( pShell.is() )
+ {
+ if( pShell->IsAbortingImport() )
+ return false;
+
+ if( pShell->GetMedium() )
+ sReferer = pShell->GetMedium()->GetName();
+ }
+ }
+
+ switch( pLink->GetObjType() )
+ {
+ case sfx2::SvBaseLinkObjectType::ClientGraphic:
+ nType = SvFileObjectType::Graphic;
+ bSynchron = pLink->IsSynchron();
+ break;
+
+ case sfx2::SvBaseLinkObjectType::ClientFile:
+ nType = SvFileObjectType::Text;
+ break;
+
+ case sfx2::SvBaseLinkObjectType::ClientOle:
+ nType = SvFileObjectType::Object;
+ // TODO/LATER: introduce own type to be used for exchanging
+ break;
+
+ default:
+ return false;
+ }
+
+ SetUpdateTimeout( 0 );
+
+ // and now register by this or other found Pseudo-Object
+ AddDataAdvise( pLink, SotExchange::GetFormatMimeType( pLink->GetContentType()), 0 );
+ return true;
+}
+
+bool SvFileObject::LoadFile_Impl()
+{
+ // We are still at Loading!!
+ if( bWaitForData || !bLoadAgain || xMed.is() )
+ return false;
+
+ // at the moment on the current DocShell
+ xMed = new SfxMedium( sFileNm, sReferer, StreamMode::STD_READ );
+ SvLinkSource::StreamToLoadFrom aStreamToLoadFrom =
+ getStreamToLoadFrom();
+ xMed->setStreamToLoadFrom(
+ aStreamToLoadFrom.m_xInputStreamToLoadFrom,
+ aStreamToLoadFrom.m_bIsReadOnly);
+
+ if( !bSynchron )
+ {
+ bLoadAgain = bDataReady = false;
+ bWaitForData = true;
+
+ tools::SvRef<SfxMedium> xTmpMed = xMed;
+ xMed->Download( LINK( this, SvFileObject, LoadGrfReady_Impl ) );
+
+ bClearMedium = !xMed.is();
+ if( bClearMedium )
+ xMed = xTmpMed; // If already finished in Download
+ return bDataReady;
+ }
+
+ bWaitForData = true;
+ bDataReady = false;
+ xMed->Download();
+ bLoadAgain = !xMed->IsRemote();
+ bWaitForData = false;
+
+ // Graphic is finished, also send DataChanged of the Status change:
+ SendStateChg_Impl( xMed->GetInStream() && xMed->GetInStream()->GetError()
+ ? sfx2::LinkManager::STATE_LOAD_ERROR : sfx2::LinkManager::STATE_LOAD_OK );
+ return true;
+}
+
+
+/** detect the filter of the given file
+
+ @param _rURL
+ specifies the URL of the file which filter is to detected.<br/>
+ If the URL doesn't denote a valid (existent and accessible) file, the
+ request is silently dropped.
+*/
+static OUString impl_getFilter( const OUString& _rURL )
+{
+ OUString sFilter;
+ if ( _rURL.isEmpty() )
+ return sFilter;
+
+ try
+ {
+ css::uno::Reference< css::document::XTypeDetection > xTypeDetection(
+ ::comphelper::getProcessServiceFactory()->createInstance( "com.sun.star.document.TypeDetection" ),
+ css::uno::UNO_QUERY );
+ if ( xTypeDetection.is() )
+ {
+ utl::MediaDescriptor aDescr;
+ aDescr[ utl::MediaDescriptor::PROP_URL ] <<= _rURL;
+ css::uno::Sequence< css::beans::PropertyValue > aDescrList =
+ aDescr.getAsConstPropertyValueList();
+ OUString sType = xTypeDetection->queryTypeByDescriptor( aDescrList, true );
+ if ( !sType.isEmpty() )
+ {
+ // Honor a selected/detected filter.
+ for (const auto& rDescr : std::as_const(aDescrList))
+ {
+ if (rDescr.Name == "FilterName")
+ {
+ if (rDescr.Value >>= sFilter)
+ break;
+ }
+ }
+ if (sFilter.isEmpty())
+ {
+ css::uno::Reference< css::container::XNameAccess > xTypeCont( xTypeDetection,
+ css::uno::UNO_QUERY );
+ if ( xTypeCont.is() )
+ {
+ /* XXX: for fdo#69948 scenario the sequence returned by
+ * getByName() contains an empty PreferredFilter
+ * property value (since? expected?) */
+ ::comphelper::SequenceAsHashMap lTypeProps( xTypeCont->getByName( sType ) );
+ sFilter = lTypeProps.getUnpackedValueOrDefault(
+ "PreferredFilter", OUString() );
+ }
+ }
+ }
+ }
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+
+ return sFilter;
+}
+
+void SvFileObject::Edit(weld::Window* pParent, sfx2::SvBaseLink* pLink, const Link<const OUString&, void>& rEndEditHdl)
+{
+ aEndEditLink = rEndEditHdl;
+ OUString sFile, sRange, sTmpFilter;
+ if( !pLink || !pLink->GetLinkManager() )
+ return;
+
+ sfx2::LinkManager::GetDisplayNames( pLink, nullptr, &sFile, &sRange, &sTmpFilter );
+
+ switch( pLink->GetObjType() )
+ {
+ case sfx2::SvBaseLinkObjectType::ClientGraphic:
+ {
+ nType = SvFileObjectType::Graphic; // If not set already
+
+ SvxOpenGraphicDialog aDlg(SfxResId(RID_SVXSTR_EDITGRFLINK), pParent);
+ aDlg.EnableLink(false);
+ aDlg.SetPath( sFile, true );
+ aDlg.SetCurrentFilter( sTmpFilter );
+
+ if( !aDlg.Execute() )
+ {
+ sFile = aDlg.GetPath()
+ + OUStringChar(sfx2::cTokenSeparator)
+ + OUStringChar(sfx2::cTokenSeparator)
+ + aDlg.GetDetectedFilter();
+
+ aEndEditLink.Call( sFile );
+ }
+ else
+ sFile.clear();
+ }
+ break;
+
+ case sfx2::SvBaseLinkObjectType::ClientOle:
+ {
+ nType = SvFileObjectType::Object; // if not set already
+
+ ::sfx2::FileDialogHelper & rFileDlg =
+ pLink->GetInsertFileDialog( OUString() );
+ rFileDlg.SetContext(sfx2::FileDialogHelper::LinkClientOLE);
+ rFileDlg.StartExecuteModal(
+ LINK( this, SvFileObject, DialogClosedHdl ) );
+ }
+ break;
+
+ case sfx2::SvBaseLinkObjectType::ClientFile:
+ {
+ nType = SvFileObjectType::Text; // if not set already
+
+ OUString sFactory;
+ SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
+ if ( pShell )
+ sFactory = pShell->GetFactory().GetFactoryName();
+
+ ::sfx2::FileDialogHelper & rFileDlg =
+ pLink->GetInsertFileDialog(sFactory);
+ rFileDlg.SetContext(sfx2::FileDialogHelper::LinkClientFile);
+ rFileDlg.StartExecuteModal(
+ LINK( this, SvFileObject, DialogClosedHdl ) );
+ }
+ break;
+
+ default:
+ sFile.clear();
+ }
+}
+
+IMPL_LINK_NOARG( SvFileObject, LoadGrfReady_Impl, void*, void )
+{
+ // When we come from here there it can not be an error no more.
+ bLoadError = false;
+ bWaitForData = false;
+
+ if( !bDataReady )
+ {
+ // Graphic is finished, also send DataChanged from Status change
+ bDataReady = true;
+ SendStateChg_Impl( sfx2::LinkManager::STATE_LOAD_OK );
+
+ // and then send the data again
+ NotifyDataChanged();
+ }
+
+ if( bDataReady )
+ {
+ bLoadAgain = true;
+ if( xMed.is() )
+ {
+ xMed->SetDoneLink( Link<void*,void>() );
+ mxDelMed = xMed;
+ nPostUserEventId = Application::PostUserEvent(
+ LINK( this, SvFileObject, DelMedium_Impl ));
+ xMed.clear();
+ }
+ }
+}
+
+IMPL_LINK_NOARG( SvFileObject, DelMedium_Impl, void*, void )
+{
+ nPostUserEventId = nullptr;
+ mxDelMed.clear();
+}
+
+IMPL_LINK( SvFileObject, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void )
+{
+ OUString sFile;
+
+ if ( SvFileObjectType::Text == nType || SvFileObjectType::Object == nType )
+ {
+ if ( _pFileDlg && _pFileDlg->GetError() == ERRCODE_NONE )
+ {
+ OUString sURL( _pFileDlg->GetPath() );
+ sFile = sURL + OUStringChar(sfx2::cTokenSeparator)
+ + OUStringChar(sfx2::cTokenSeparator)
+ + impl_getFilter( sURL );
+ }
+ }
+ else
+ {
+ SAL_WARN( "sfx.appl", "SvFileObject::DialogClosedHdl(): wrong file type" );
+ }
+
+ aEndEditLink.Call( sFile );
+}
+
+/*
+ The method determines whether the data-object can be read from a DDE.
+*/
+bool SvFileObject::IsPending() const
+{
+ return SvFileObjectType::Graphic == nType && !bLoadError && bWaitForData;
+}
+
+bool SvFileObject::IsDataComplete() const
+{
+ bool bRet = false;
+ if( SvFileObjectType::Graphic != nType )
+ bRet = true;
+ else if( !bLoadError && !bWaitForData )
+ {
+ SvFileObject* pThis = const_cast<SvFileObject*>(this);
+ if( bDataReady ||
+ ( bSynchron && pThis->LoadFile_Impl() && xMed.is() ) )
+ bRet = true;
+ else
+ {
+ INetURLObject aUrl( sFileNm );
+ if( aUrl.HasError() ||
+ INetProtocol::NotValid == aUrl.GetProtocol() )
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+
+void SvFileObject::CancelTransfers()
+{
+ // unsubscribe from the cache if in the middle of loading
+ if( !bDataReady )
+ {
+ // Do not set-up again
+ bLoadAgain = false;
+ bDataReady = bLoadError = bWaitForData = true;
+ SendStateChg_Impl( sfx2::LinkManager::STATE_LOAD_ABORT );
+ }
+}
+
+
+void SvFileObject::SendStateChg_Impl( sfx2::LinkManager::LinkState nState )
+{
+ if( !bStateChangeCalled && HasDataLinks() )
+ {
+ DataChanged( SotExchange::GetFormatName(
+ sfx2::LinkManager::RegisterStatusInfoId()), css::uno::Any(OUString::number( nState )) );
+ bStateChangeCalled = true;
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/fileobj.hxx b/sfx2/source/appl/fileobj.hxx
new file mode 100644
index 0000000000..7362f6b1a4
--- /dev/null
+++ b/sfx2/source/appl/fileobj.hxx
@@ -0,0 +1,82 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_SFX2_SOURCE_APPL_FILEOBJ_HXX
+#define INCLUDED_SFX2_SOURCE_APPL_FILEOBJ_HXX
+
+#include <sfx2/linksrc.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/linkmgr.hxx>
+
+class Graphic;
+struct ImplSVEvent;
+namespace sfx2 { class FileDialogHelper; }
+
+enum class SvFileObjectType;
+
+class SvFileObject : public sfx2::SvLinkSource
+{
+ OUString sFileNm;
+ OUString sFilter;
+ OUString sReferer;
+ Link<const OUString&, void> aEndEditLink;
+ tools::SvRef<SfxMedium> xMed;
+ ImplSVEvent* nPostUserEventId;
+ tools::SvRef<SfxMedium> mxDelMed;
+
+ SvFileObjectType nType;
+
+ bool bLoadAgain : 1;
+ bool bSynchron : 1;
+ bool bLoadError : 1;
+ bool bWaitForData : 1;
+ bool bDataReady : 1;
+ bool bClearMedium : 1;
+ bool bStateChangeCalled : 1;
+
+ bool LoadFile_Impl();
+ void SendStateChg_Impl( sfx2::LinkManager::LinkState nState );
+
+ DECL_LINK( DelMedium_Impl, void*, void );
+ DECL_LINK( LoadGrfReady_Impl, void*, void );
+ DECL_LINK( DialogClosedHdl, sfx2::FileDialogHelper*, void );
+
+protected:
+ virtual ~SvFileObject() override;
+
+public:
+ SvFileObject();
+
+ virtual bool GetData( css::uno::Any & rData /*out param*/,
+ const OUString & rMimeType,
+ bool bSynchron = false ) override;
+
+ virtual bool Connect( sfx2::SvBaseLink* ) override;
+ virtual void Edit(weld::Window *, sfx2::SvBaseLink *, const Link<const OUString&, void>& rEndEditHdl) override;
+
+ // Ask whether you can access data directly or whether it has to be triggered
+ virtual bool IsPending() const override;
+ virtual bool IsDataComplete() const override;
+
+ void CancelTransfers();
+};
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/flatpak.cxx b/sfx2/source/appl/flatpak.cxx
new file mode 100644
index 0000000000..c6edf6f232
--- /dev/null
+++ b/sfx2/source/appl/flatpak.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+
+#include <osl/file.hxx>
+#include <osl/thread.h>
+#include <rtl/textcvt.h>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sfx2/flatpak.hxx>
+#include <tools/debug.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbhelper.hxx>
+
+bool flatpak::isFlatpak() {
+ static auto const flatpak = [] { return std::getenv("LIBO_FLATPAK") != nullptr; }();
+ return flatpak;
+}
+
+namespace {
+
+// Must only be accessed with SolarMutex locked:
+struct {
+ bool created = false;
+ OUString url;
+} temporaryHtmlDirectoryStatus;
+
+}
+
+bool flatpak::createTemporaryHtmlDirectory(OUString ** url) {
+ assert(url != nullptr);
+ DBG_TESTSOLARMUTEX();
+ if (!temporaryHtmlDirectoryStatus.created) {
+ // coverity[tainted_return_value] - we trust the contents of this variable
+ auto const env = std::getenv("XDG_CACHE_HOME");
+ if (env == nullptr) {
+ SAL_WARN("sfx.appl", "LIBO_FLATPAK mode but unset XDG_CACHE_HOME");
+ return false;
+ }
+ OUString path;
+ if (!rtl_convertStringToUString(
+ &path.pData, env, std::strlen(env), osl_getThreadTextEncoding(),
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
+ {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure converting XDG_CACHE_HOME \"" << env << "\" encoding");
+ return false;
+ }
+ OUString parent;
+ auto const err = osl::FileBase::getFileURLFromSystemPath(path, parent);
+ if (err != osl::FileBase::E_None) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure converting XDG_CACHE_HOME \"" << path << "\" to URL: "
+ << err);
+ return false;
+ }
+ if (!parent.endsWith("/")) {
+ parent += "/";
+ }
+ temporaryHtmlDirectoryStatus.url = utl::CreateTempURL(&parent, true);
+ if (temporaryHtmlDirectoryStatus.url.isEmpty()) {
+ SAL_WARN(
+ "sfx.appl", "LIBO_FLATPAK mode failure creating temp dir at <" << parent << ">");
+ return false;
+ }
+ temporaryHtmlDirectoryStatus.created = true;
+ }
+ *url = &temporaryHtmlDirectoryStatus.url;
+ return true;
+}
+
+void flatpak::removeTemporaryHtmlDirectory() {
+ DBG_TESTSOLARMUTEX();
+ if (temporaryHtmlDirectoryStatus.created) {
+ if (!utl::UCBContentHelper::Kill(temporaryHtmlDirectoryStatus.url)) {
+ SAL_INFO(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure removing directory <"
+ << temporaryHtmlDirectoryStatus.url << ">");
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sfx2/source/appl/fwkhelper.cxx b/sfx2/source/appl/fwkhelper.cxx
new file mode 100644
index 0000000000..6a7eee8fb8
--- /dev/null
+++ b/sfx2/source/appl/fwkhelper.cxx
@@ -0,0 +1,52 @@
+/* -*- 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 <sal/config.h>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/frame/XFrame.hpp>
+
+#include <vcl/svapp.hxx>
+
+#include <fwkhelper.hxx>
+#include <workwin.hxx>
+#include <sfx2/frame.hxx>
+
+void RefreshToolbars( css::uno::Reference< css::frame::XFrame > const & xFrame )
+{
+ SolarMutexGuard aGuard;
+ if ( !xFrame.is() )
+ return;
+
+ SfxFrame* pFrame=nullptr;
+ for ( pFrame = SfxFrame::GetFirst(); pFrame; pFrame = SfxFrame::GetNext( *pFrame ) )
+ {
+ if ( pFrame->GetFrameInterface() == xFrame )
+ break;
+ }
+
+ if ( pFrame )
+ {
+ SfxWorkWindow* pWrkWin = pFrame->GetWorkWindow_Impl();
+ if ( pWrkWin )
+ pWrkWin->UpdateObjectBars_Impl();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/getbasctlfunction.cxx b/sfx2/source/appl/getbasctlfunction.cxx
new file mode 100644
index 0000000000..fd7f487301
--- /dev/null
+++ b/sfx2/source/appl/getbasctlfunction.cxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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 <sal/config.h>
+
+#include <cassert>
+
+#include <config_features.h>
+#include <config_options.h>
+#include <osl/module.h>
+#include <osl/module.hxx>
+#include <tools/svlibrary.h>
+
+#include "getbasctlfunction.hxx"
+
+#if HAVE_FEATURE_SCRIPTING
+#ifndef DISABLE_DYNLOADING
+
+extern "C" { static void thisModule() {} }
+
+oslGenericFunction sfx2::getBasctlFunction(char const* name)
+{
+ osl::Module aMod;
+
+ // load basctl module
+ auto const ok = aMod.loadRelative(
+ &thisModule,
+#if ENABLE_MERGELIBS
+ SVLIBRARY("merged")
+#else
+ SVLIBRARY("basctl")
+#endif
+ );
+ assert(ok);
+ (void) ok;
+
+ // get symbol
+ auto pSymbol = aMod.getFunctionSymbol(name);
+ assert(pSymbol);
+ aMod.release();
+
+ return pSymbol;
+}
+
+#endif
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sfx2/source/appl/getbasctlfunction.hxx b/sfx2/source/appl/getbasctlfunction.hxx
new file mode 100644
index 0000000000..5fa4bc5570
--- /dev/null
+++ b/sfx2/source/appl/getbasctlfunction.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <config_features.h>
+
+#include <osl/module.h>
+
+#ifndef DISABLE_DYNLOADING
+#if HAVE_FEATURE_SCRIPTING
+
+namespace sfx2
+{
+oslGenericFunction getBasctlFunction(char const* name);
+}
+
+#endif
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sfx2/source/appl/helpdispatch.cxx b/sfx2/source/appl/helpdispatch.cxx
new file mode 100644
index 0000000000..ec6b5dfea0
--- /dev/null
+++ b/sfx2/source/appl/helpdispatch.cxx
@@ -0,0 +1,106 @@
+/* -*- 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 "helpdispatch.hxx"
+#include "newhelp.hxx"
+#include <tools/debug.hxx>
+#include <utility>
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+
+// class HelpInterceptor_Impl --------------------------------------------
+
+HelpDispatch_Impl::HelpDispatch_Impl( HelpInterceptor_Impl& _rInterceptor,
+ css::uno::Reference< css::frame::XDispatch > _xDisp ) :
+
+ m_rInterceptor ( _rInterceptor ),
+ m_xRealDispatch (std::move( _xDisp ))
+
+{
+}
+
+
+HelpDispatch_Impl::~HelpDispatch_Impl()
+{
+}
+
+
+// XDispatch
+
+void SAL_CALL HelpDispatch_Impl::dispatch(
+
+ const URL& aURL, const Sequence< PropertyValue >& aArgs )
+
+{
+ DBG_ASSERT( m_xRealDispatch.is(), "invalid dispatch" );
+
+ // search for a keyword (dispatch from the basic ide)
+ bool bHasKeyword = false;
+ OUString sKeyword;
+ for ( const PropertyValue& rArg : aArgs )
+ {
+ if ( rArg.Name == "HelpKeyword" )
+ {
+ OUString sHelpKeyword;
+ if ( ( rArg.Value >>= sHelpKeyword ) && !sHelpKeyword.isEmpty() )
+ {
+ sKeyword = sHelpKeyword;
+ bHasKeyword = !sKeyword.isEmpty();
+ break;
+ }
+ }
+ }
+
+ // if a keyword was found, then open it
+ SfxHelpWindow_Impl* pHelpWin = m_rInterceptor.GetHelpWindow();
+ DBG_ASSERT( pHelpWin, "invalid HelpWindow" );
+ if ( bHasKeyword )
+ {
+ pHelpWin->OpenKeyword( sKeyword );
+ return;
+ }
+
+ pHelpWin->loadHelpContent(aURL.Complete);
+}
+
+
+void SAL_CALL HelpDispatch_Impl::addStatusListener(
+
+ const Reference< XStatusListener >& xControl, const URL& aURL )
+
+{
+ DBG_ASSERT( m_xRealDispatch.is(), "invalid dispatch" );
+ m_xRealDispatch->addStatusListener( xControl, aURL );
+}
+
+
+void SAL_CALL HelpDispatch_Impl::removeStatusListener(
+
+ const Reference< XStatusListener >& xControl, const URL& aURL )
+
+{
+ DBG_ASSERT( m_xRealDispatch.is(), "invalid dispatch" );
+ m_xRealDispatch->removeStatusListener( xControl, aURL );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/helpdispatch.hxx b/sfx2/source/appl/helpdispatch.hxx
new file mode 100644
index 0000000000..c1e6aa8f98
--- /dev/null
+++ b/sfx2/source/appl/helpdispatch.hxx
@@ -0,0 +1,47 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_SFX2_SOURCE_APPL_HELPDISPATCH_HXX
+#define INCLUDED_SFX2_SOURCE_APPL_HELPDISPATCH_HXX
+
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include "helpinterceptor.hxx"
+
+class HelpDispatch_Impl : public ::cppu::WeakImplHelper< css::frame::XDispatch >
+{
+private:
+ HelpInterceptor_Impl& m_rInterceptor;
+ css::uno::Reference< css::frame::XDispatch >
+ m_xRealDispatch;
+
+public:
+ HelpDispatch_Impl( HelpInterceptor_Impl& _rInterceptor,
+ css::uno::Reference< css::frame::XDispatch > _xDisp );
+ virtual ~HelpDispatch_Impl() override;
+
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue >& aArgs ) override;
+ virtual void SAL_CALL addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xControl, const css::util::URL& aURL ) override;
+ virtual void SAL_CALL removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xControl, const css::util::URL& aURL ) override;
+};
+
+#endif // INCLUDED_SFX2_SOURCE_APPL_HELPDISPATCH_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/helpinterceptor.cxx b/sfx2/source/appl/helpinterceptor.cxx
new file mode 100644
index 0000000000..a9ff761015
--- /dev/null
+++ b/sfx2/source/appl/helpinterceptor.cxx
@@ -0,0 +1,262 @@
+/* -*- 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 "helpinterceptor.hxx"
+#include "helpdispatch.hxx"
+#include "newhelp.hxx"
+#include <tools/urlobj.hxx>
+#include <tools/debug.hxx>
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+
+HelpInterceptor_Impl::HelpInterceptor_Impl() :
+
+ m_pWindow ( nullptr ),
+ m_nCurPos ( 0 )
+
+{
+}
+
+
+HelpInterceptor_Impl::~HelpInterceptor_Impl()
+{
+}
+
+
+void HelpInterceptor_Impl::addURL( const OUString& rURL )
+{
+ size_t nCount = m_vHistoryUrls.size();
+ if ( nCount && m_nCurPos < ( nCount - 1 ) )
+ {
+ m_vHistoryUrls.erase(
+ m_vHistoryUrls.begin() + m_nCurPos + 1,
+ m_vHistoryUrls.end());
+ }
+ Reference<XFrame> xFrame(m_xIntercepted, UNO_QUERY);
+ Reference<XController> xController;
+ if(xFrame.is())
+ xController = xFrame->getController();
+
+ m_aCurrentURL = rURL;
+ m_vHistoryUrls.emplace_back( rURL );
+ m_nCurPos = m_vHistoryUrls.size() - 1;
+// TODO ?
+ if ( m_xListener.is() )
+ {
+ css::frame::FeatureStateEvent aEvent;
+ URL aURL;
+ aURL.Complete = rURL;
+ aEvent.FeatureURL = aURL;
+ aEvent.Source = static_cast<css::frame::XDispatch*>(this);
+ m_xListener->statusChanged( aEvent );
+ }
+
+ m_pWindow->UpdateToolbox();
+}
+
+
+void HelpInterceptor_Impl::setInterception( const Reference< XFrame >& xFrame )
+{
+ m_xIntercepted.set( xFrame, UNO_QUERY );
+
+ if ( m_xIntercepted.is() )
+ m_xIntercepted->registerDispatchProviderInterceptor( static_cast<XDispatchProviderInterceptor*>(this) );
+}
+
+
+bool HelpInterceptor_Impl::HasHistoryPred() const
+{
+ return m_nCurPos > 0;
+}
+
+bool HelpInterceptor_Impl::HasHistorySucc() const
+{
+ return m_nCurPos < ( m_vHistoryUrls.size() - 1 );
+}
+
+
+// XDispatchProvider
+
+Reference< XDispatch > SAL_CALL HelpInterceptor_Impl::queryDispatch(
+
+ const URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags )
+
+{
+ Reference< XDispatch > xResult;
+ if ( m_xSlaveDispatcher.is() )
+ xResult = m_xSlaveDispatcher->queryDispatch( aURL, aTargetFrameName, nSearchFlags );
+
+ bool bHelpURL = aURL.Complete.toAsciiLowerCase().match("vnd.sun.star.help",0);
+
+ if ( bHelpURL )
+ {
+ DBG_ASSERT( xResult.is(), "invalid dispatch" );
+ xResult = new HelpDispatch_Impl( *this, xResult );
+ }
+
+ return xResult;
+}
+
+
+Sequence < Reference < XDispatch > > SAL_CALL HelpInterceptor_Impl::queryDispatches(
+
+ const Sequence< DispatchDescriptor >& aDescripts )
+
+{
+ Sequence< Reference< XDispatch > > aReturn( aDescripts.getLength() );
+ std::transform(aDescripts.begin(), aDescripts.end(), aReturn.getArray(),
+ [this](const DispatchDescriptor& rDescr) -> Reference<XDispatch> {
+ return queryDispatch(rDescr.FeatureURL, rDescr.FrameName, rDescr.SearchFlags); });
+ return aReturn;
+}
+
+
+// XDispatchProviderInterceptor
+
+Reference< XDispatchProvider > SAL_CALL HelpInterceptor_Impl::getSlaveDispatchProvider()
+
+{
+ return m_xSlaveDispatcher;
+}
+
+
+void SAL_CALL HelpInterceptor_Impl::setSlaveDispatchProvider( const Reference< XDispatchProvider >& xNewSlave )
+
+{
+ m_xSlaveDispatcher = xNewSlave;
+}
+
+
+Reference< XDispatchProvider > SAL_CALL HelpInterceptor_Impl::getMasterDispatchProvider()
+
+{
+ return m_xMasterDispatcher;
+}
+
+
+void SAL_CALL HelpInterceptor_Impl::setMasterDispatchProvider( const Reference< XDispatchProvider >& xNewMaster )
+
+{
+ m_xMasterDispatcher = xNewMaster;
+}
+
+
+// XInterceptorInfo
+
+Sequence< OUString > SAL_CALL HelpInterceptor_Impl::getInterceptedURLs()
+
+{
+ Sequence<OUString> aURLList { "vnd.sun.star.help://*" };
+ return aURLList;
+}
+
+
+// XDispatch
+
+void SAL_CALL HelpInterceptor_Impl::dispatch(
+ const URL& aURL, const Sequence< css::beans::PropertyValue >& )
+{
+ bool bBack = aURL.Complete == ".uno:Backward";
+ if ( !bBack && aURL.Complete != ".uno:Forward" )
+ return;
+
+ if ( m_vHistoryUrls.empty() )
+ return;
+
+ size_t nPos = ( bBack && m_nCurPos > 0 ) ? --m_nCurPos
+ : ( !bBack && m_nCurPos < m_vHistoryUrls.size() - 1 )
+ ? ++m_nCurPos
+ : std::numeric_limits<std::size_t>::max();
+
+ if ( nPos < std::numeric_limits<std::size_t>::max() )
+ {
+ m_pWindow->loadHelpContent(m_vHistoryUrls[nPos], false); // false => don't add item to history again!
+ }
+
+ m_pWindow->UpdateToolbox();
+}
+
+
+void SAL_CALL HelpInterceptor_Impl::addStatusListener(
+ const Reference< XStatusListener >& xControl, const URL& )
+{
+ DBG_ASSERT( !m_xListener.is(), "listener already exists" );
+ m_xListener = xControl;
+}
+
+
+void SAL_CALL HelpInterceptor_Impl::removeStatusListener(
+ const Reference< XStatusListener >&, const URL&)
+{
+ m_xListener = nullptr;
+}
+
+// HelpListener_Impl -----------------------------------------------------
+
+HelpListener_Impl::HelpListener_Impl( HelpInterceptor_Impl* pInter )
+{
+ pInterceptor = pInter;
+ pInterceptor->addStatusListener( this, css::util::URL() );
+}
+
+
+void SAL_CALL HelpListener_Impl::statusChanged( const css::frame::FeatureStateEvent& Event )
+{
+ INetURLObject aObj( Event.FeatureURL.Complete );
+ aFactory = aObj.GetHost();
+ aChangeLink.Call( *this );
+}
+
+
+void SAL_CALL HelpListener_Impl::disposing( const css::lang::EventObject& )
+{
+ pInterceptor->removeStatusListener( this, css::util::URL() );
+ pInterceptor = nullptr;
+}
+
+HelpStatusListener_Impl::HelpStatusListener_Impl(
+ Reference < XDispatch > const & aDispatch, URL const & rURL)
+{
+ aDispatch->addStatusListener(this, rURL);
+}
+
+HelpStatusListener_Impl::~HelpStatusListener_Impl()
+{
+ if(xDispatch.is())
+ xDispatch->removeStatusListener(this, css::util::URL());
+}
+
+void HelpStatusListener_Impl::statusChanged(
+ const FeatureStateEvent& rEvent )
+{
+ aStateEvent = rEvent;
+}
+
+void HelpStatusListener_Impl::disposing( const EventObject& )
+{
+ xDispatch->removeStatusListener(this, css::util::URL());
+ xDispatch = nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/helpinterceptor.hxx b/sfx2/source/appl/helpinterceptor.hxx
new file mode 100644
index 0000000000..2f08b1ac3b
--- /dev/null
+++ b/sfx2/source/appl/helpinterceptor.hxx
@@ -0,0 +1,141 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_SFX2_SOURCE_APPL_HELPINTERCEPTOR_HXX
+#define INCLUDED_SFX2_SOURCE_APPL_HELPINTERCEPTOR_HXX
+
+#include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
+#include <com/sun/star/frame/XInterceptorInfo.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XDispatchProviderInterception.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <tools/link.hxx>
+#include <vcl/vclptr.hxx>
+#include "newhelp.hxx"
+#include <vector>
+
+class SfxHelpWindow_Impl;
+class HelpInterceptor_Impl : public ::cppu::WeakImplHelper<
+ css::frame::XDispatchProviderInterceptor,
+ css::frame::XInterceptorInfo,
+ css::frame::XDispatch >
+
+{
+private:
+friend class HelpDispatch_Impl;
+friend class SfxHelpWindow_Impl;
+
+ // the component which's dispatches we're intercepting
+ css::uno::Reference< css::frame::XDispatchProviderInterception > m_xIntercepted;
+
+ // chaining
+ css::uno::Reference< css::frame::XDispatchProvider > m_xSlaveDispatcher;
+ css::uno::Reference< css::frame::XDispatchProvider > m_xMasterDispatcher;
+
+ css::uno::Reference< css::frame::XStatusListener > m_xListener;
+
+ std::vector<OUString> m_vHistoryUrls;
+ VclPtr<SfxHelpWindow_Impl> m_pWindow;
+ size_t m_nCurPos;
+ OUString m_aCurrentURL;
+
+ void addURL( const OUString& rURL );
+
+public:
+ HelpInterceptor_Impl();
+ virtual ~HelpInterceptor_Impl() override;
+
+ void setInterception( const css::uno::Reference< css::frame::XFrame >& xFrame );
+ const OUString& GetCurrentURL() const { return m_aCurrentURL; }
+
+ bool HasHistoryPred() const; // is there a predecessor for the current in the history
+ bool HasHistorySucc() const; // is there a successor for the current in the history
+
+ // XDispatchProvider
+ virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL
+ queryDispatch( const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL
+ queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& aDescripts ) override;
+
+ // XDispatchProviderInterceptor
+ virtual css::uno::Reference< css::frame::XDispatchProvider > SAL_CALL
+ getSlaveDispatchProvider( ) override;
+ virtual void SAL_CALL setSlaveDispatchProvider( const css::uno::Reference< css::frame::XDispatchProvider >& xNewSlave ) override;
+ virtual css::uno::Reference< css::frame::XDispatchProvider > SAL_CALL
+ getMasterDispatchProvider( ) override;
+ virtual void SAL_CALL setMasterDispatchProvider( const css::uno::Reference< css::frame::XDispatchProvider >& xNewMaster ) override;
+
+ // XInterceptorInfo
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getInterceptedURLs( ) override;
+
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue >& aArgs ) override;
+ virtual void SAL_CALL addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xControl, const css::util::URL& aURL ) override;
+ virtual void SAL_CALL removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xControl, const css::util::URL& aURL ) override;
+
+ // extras
+ void InitWaiter( SfxHelpWindow_Impl* pWindow )
+ { m_pWindow = pWindow; }
+ SfxHelpWindow_Impl* GetHelpWindow() const { return m_pWindow; }
+};
+
+// HelpListener_Impl -----------------------------------------------------
+
+class HelpListener_Impl : public ::cppu::WeakImplHelper< css::frame::XStatusListener >
+{
+private:
+ HelpInterceptor_Impl* pInterceptor;
+ Link<HelpListener_Impl&,void> aChangeLink;
+ OUString aFactory;
+
+public:
+ explicit HelpListener_Impl( HelpInterceptor_Impl* pInter );
+
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& obj ) override;
+
+ void SetChangeHdl( const Link<HelpListener_Impl&,void>& rLink ) { aChangeLink = rLink; }
+ const OUString& GetFactory() const { return aFactory; }
+};
+// HelpStatusListener_Impl -----------------------------------------------------
+
+class HelpStatusListener_Impl : public cppu::WeakImplHelper< css::frame::XStatusListener >
+{
+private:
+ css::uno::Reference < css::frame::XDispatch > xDispatch;
+ css::frame::FeatureStateEvent aStateEvent;
+
+public:
+ HelpStatusListener_Impl(
+ css::uno::Reference < css::frame::XDispatch > const & xDispatch,
+ css::util::URL const & rURL);
+ virtual ~HelpStatusListener_Impl() override;
+
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& obj ) override;
+ const css::frame::FeatureStateEvent&
+ GetStateEvent() const {return aStateEvent;}
+};
+
+
+#endif // INCLUDED_SFX2_SOURCE_APPL_HELPINTERCEPTOR_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/impldde.cxx b/sfx2/source/appl/impldde.cxx
new file mode 100644
index 0000000000..c70cb4cb6a
--- /dev/null
+++ b/sfx2/source/appl/impldde.cxx
@@ -0,0 +1,348 @@
+/* -*- 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 .
+ */
+
+
+#if defined(_WIN32)
+#include <prewin.h>
+#include <postwin.h>
+#endif
+
+#include "impldde.hxx"
+
+#include <vcl/weld.hxx>
+#include <sot/exchange.hxx>
+#include <rtl/ustring.hxx>
+
+#include <sfx2/lnkbase.hxx>
+#include <sfx2/linkmgr.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <svl/svdde.hxx>
+#include <sot/formats.hxx>
+
+using namespace ::com::sun::star::uno;
+
+namespace sfx2
+{
+
+namespace {
+
+class SvDDELinkEditDialog : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::Entry> m_xEdDdeApp;
+ std::unique_ptr<weld::Entry> m_xEdDdeTopic;
+ std::unique_ptr<weld::Entry> m_xEdDdeItem;
+ std::unique_ptr<weld::Button> m_xOKButton;
+
+ DECL_LINK(EditHdl_Impl, weld::Entry&, void);
+public:
+ SvDDELinkEditDialog(weld::Window* pParent, SvBaseLink const*);
+ OUString GetCmd() const;
+};
+
+}
+
+SvDDELinkEditDialog::SvDDELinkEditDialog(weld::Window* pParent, SvBaseLink const * pLink)
+ : GenericDialogController(pParent, "sfx/ui/linkeditdialog.ui", "LinkEditDialog")
+ , m_xEdDdeApp(m_xBuilder->weld_entry("app"))
+ , m_xEdDdeTopic(m_xBuilder->weld_entry("file"))
+ , m_xEdDdeItem(m_xBuilder->weld_entry("category"))
+ , m_xOKButton(m_xBuilder->weld_button("ok"))
+{
+ OUString sServer, sTopic, sItem;
+ sfx2::LinkManager::GetDisplayNames( pLink, &sServer, &sTopic, &sItem );
+
+ m_xEdDdeApp->set_text( sServer );
+ m_xEdDdeTopic->set_text( sTopic );
+ m_xEdDdeItem->set_text( sItem );
+
+ m_xEdDdeApp->connect_changed( LINK( this, SvDDELinkEditDialog, EditHdl_Impl));
+ m_xEdDdeTopic->connect_changed( LINK( this, SvDDELinkEditDialog, EditHdl_Impl));
+ m_xEdDdeItem->connect_changed( LINK( this, SvDDELinkEditDialog, EditHdl_Impl));
+
+ m_xOKButton->set_sensitive(!sServer.isEmpty() && !sTopic.isEmpty() && !sItem.isEmpty());
+}
+
+OUString SvDDELinkEditDialog::GetCmd() const
+{
+ OUString sCmd( m_xEdDdeApp->get_text() ), sRet;
+ ::sfx2::MakeLnkName( sRet, &sCmd, m_xEdDdeTopic->get_text(), m_xEdDdeItem->get_text() );
+ return sRet;
+}
+
+IMPL_LINK_NOARG( SvDDELinkEditDialog, EditHdl_Impl, weld::Entry&, void)
+{
+ m_xOKButton->set_sensitive(!m_xEdDdeApp->get_text().isEmpty() &&
+ !m_xEdDdeTopic->get_text().isEmpty() &&
+ !m_xEdDdeItem->get_text().isEmpty() );
+}
+
+SvDDEObject::SvDDEObject()
+ : pGetData( nullptr )
+{
+ SetUpdateTimeout( 100 );
+ bWaitForData = false;
+}
+
+SvDDEObject::~SvDDEObject()
+{
+ pLink.reset();
+ pRequest.reset();
+ pConnection.reset();
+}
+
+bool SvDDEObject::GetData( css::uno::Any & rData /*out param*/,
+ const OUString & rMimeType,
+ bool bSynchron )
+{
+ if( !pConnection )
+ return false;
+
+ if( pConnection->GetError() ) // then we try once more
+ {
+ OUString sServer( pConnection->GetServiceName() );
+ OUString sTopic( pConnection->GetTopicName() );
+
+ pConnection.reset( new DdeConnection( sServer, sTopic ) );
+ }
+
+ if( bWaitForData ) // we are in a recursive loop, get out again
+ return false;
+
+ // Lock against Reentrance
+ bWaitForData = true;
+
+ // if you want to print, we'll wait until the data is available
+ if( bSynchron )
+ {
+ DdeRequest aReq( *pConnection, sItem, 5000 );
+ aReq.SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) );
+ aReq.SetFormat( SotExchange::GetFormatIdFromMimeType( rMimeType ));
+
+ pGetData = &rData;
+
+ do {
+ aReq.Execute();
+ } while( aReq.GetError() && ImplHasOtherFormat( aReq ) );
+
+ bWaitForData = false;
+ }
+ else
+ {
+ // otherwise it will be executed asynchronously
+ {
+ pRequest.reset( new DdeRequest( *pConnection, sItem ) );
+ pRequest->SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) );
+ pRequest->SetDoneHdl( LINK( this, SvDDEObject, ImplDoneDDEData ) );
+ pRequest->SetFormat( SotExchange::GetFormatIdFromMimeType(
+ rMimeType ) );
+ pRequest->Execute();
+ }
+
+ rData <<= OUString();
+ }
+ return 0 == pConnection->GetError();
+}
+
+
+bool SvDDEObject::Connect( SvBaseLink * pSvLink )
+{
+ SfxLinkUpdateMode nLinkType = pSvLink->GetUpdateMode();
+ if( pConnection ) // Connection is already made
+ {
+ // well, then just add it as dependent
+ AddDataAdvise( pSvLink,
+ SotExchange::GetFormatMimeType( pSvLink->GetContentType()),
+ SfxLinkUpdateMode::ONCALL == nLinkType
+ ? ADVISEMODE_ONLYONCE
+ : 0 );
+ AddConnectAdvise( pSvLink );
+
+ return true;
+ }
+
+ if( !pSvLink->GetLinkManager() )
+ return false;
+
+ OUString sServer, sTopic;
+ sfx2::LinkManager::GetDisplayNames( pSvLink, &sServer, &sTopic, &sItem );
+
+ if( sServer.isEmpty() || sTopic.isEmpty() || sItem.isEmpty() )
+ return false;
+
+ pConnection.reset( new DdeConnection( sServer, sTopic ) );
+ if( pConnection->GetError() )
+ {
+ // check if the DDE server knows the "SYSTEM" topic
+ bool bSysTopic = false;
+ if (!sTopic.equalsIgnoreAsciiCase("SYSTEM"))
+ {
+ DdeConnection aTmp(sServer, "SYSTEM");
+ bSysTopic = !aTmp.GetError();
+ }
+
+ if( bSysTopic )
+ {
+ // if the system topic works then the server is up but just doesn't know the original topic
+ return false;
+ }
+ }
+
+ if( SfxLinkUpdateMode::ALWAYS == nLinkType && !pLink && !pConnection->GetError() )
+ {
+ // Setting up Hot Link, Data will be available at some point later on
+ pLink.reset( new DdeHotLink( *pConnection, sItem ) );
+ pLink->SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) );
+ pLink->SetDoneHdl( LINK( this, SvDDEObject, ImplDoneDDEData ) );
+ pLink->SetFormat( pSvLink->GetContentType() );
+ pLink->Execute();
+ }
+
+ if( pConnection->GetError() )
+ return false;
+
+ AddDataAdvise( pSvLink,
+ SotExchange::GetFormatMimeType( pSvLink->GetContentType()),
+ SfxLinkUpdateMode::ONCALL == nLinkType
+ ? ADVISEMODE_ONLYONCE
+ : 0 );
+ AddConnectAdvise( pSvLink );
+ SetUpdateTimeout( 0 );
+ return true;
+}
+
+void SvDDEObject::Edit(weld::Window* pParent, sfx2::SvBaseLink* pBaseLink, const Link<const OUString&, void>& rEndEditHdl)
+{
+ SvDDELinkEditDialog aDlg(pParent, pBaseLink);
+ if (RET_OK == aDlg.run() && rEndEditHdl.IsSet())
+ {
+ OUString sCommand = aDlg.GetCmd();
+ rEndEditHdl.Call( sCommand );
+ }
+}
+
+bool SvDDEObject::ImplHasOtherFormat( DdeTransaction& rReq )
+{
+ SotClipboardFormatId nFmt = SotClipboardFormatId::NONE;
+ switch( rReq.GetFormat() )
+ {
+ case SotClipboardFormatId::RTF:
+ nFmt = SotClipboardFormatId::STRING;
+ break;
+
+ case SotClipboardFormatId::HTML_SIMPLE:
+ case SotClipboardFormatId::HTML:
+ nFmt = SotClipboardFormatId::RTF;
+ break;
+
+ case SotClipboardFormatId::GDIMETAFILE:
+ nFmt = SotClipboardFormatId::BITMAP;
+ break;
+
+ case SotClipboardFormatId::SVXB:
+ nFmt = SotClipboardFormatId::GDIMETAFILE;
+ break;
+
+ // something else?
+ default: break;
+ }
+ if( nFmt != SotClipboardFormatId::NONE )
+ rReq.SetFormat( nFmt ); // try it once more
+ return SotClipboardFormatId::NONE != nFmt;
+}
+
+bool SvDDEObject::IsPending() const
+/*
+ The method determines whether the data-object can be read from a DDE.
+*/
+{
+ return bWaitForData;
+}
+
+bool SvDDEObject::IsDataComplete() const
+{
+ return bWaitForData;
+}
+
+IMPL_LINK( SvDDEObject, ImplGetDDEData, const DdeData*, pData, void )
+{
+ SotClipboardFormatId nFmt = pData->GetFormat();
+ switch( nFmt )
+ {
+ case SotClipboardFormatId::GDIMETAFILE:
+ break;
+
+ case SotClipboardFormatId::BITMAP:
+ break;
+
+ default:
+ {
+ const char* p = static_cast<char const *>(pData->getData());
+ tools::Long nLen = SotClipboardFormatId::STRING == nFmt ? (p ? strlen( p ) : 0) : pData->getSize();
+
+ Sequence< sal_Int8 > aSeq( reinterpret_cast<const sal_Int8*>(p), nLen );
+ if( pGetData )
+ {
+ *pGetData <<= aSeq; // Copy Data
+ pGetData = nullptr; // reset the pointer here
+ }
+ else
+ {
+ Any aVal;
+ aVal <<= aSeq;
+ DataChanged( SotExchange::GetFormatMimeType(
+ pData->GetFormat() ), aVal );
+ bWaitForData = false;
+ }
+ }
+ }
+}
+
+IMPL_LINK( SvDDEObject, ImplDoneDDEData, bool, bValid, void )
+{
+ if( !bValid && ( pRequest || pLink ))
+ {
+ DdeTransaction* pReq = nullptr;
+ if( !pLink || ( pLink && pLink->IsBusy() ))
+ pReq = pRequest.get(); // only the one that is ready
+ else if( pRequest && pRequest->IsBusy() )
+ pReq = pLink.get(); // only the one that is ready
+
+ if( pReq )
+ {
+ if( ImplHasOtherFormat( *pReq ) )
+ {
+ pReq->Execute();
+ }
+ else if( pReq == pRequest.get() )
+ {
+ bWaitForData = false;
+ }
+ }
+ }
+ else
+ // End waiting
+ bWaitForData = false;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/impldde.hxx b/sfx2/source/appl/impldde.hxx
new file mode 100644
index 0000000000..ee2f2ecb92
--- /dev/null
+++ b/sfx2/source/appl/impldde.hxx
@@ -0,0 +1,72 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_SFX2_SOURCE_APPL_IMPLDDE_HXX
+#define INCLUDED_SFX2_SOURCE_APPL_IMPLDDE_HXX
+
+#include <rtl/ustring.hxx>
+#include <sfx2/linksrc.hxx>
+#include <tools/link.hxx>
+
+class DdeConnection;
+class DdeData;
+class DdeLink;
+class DdeRequest;
+class DdeTransaction;
+
+namespace sfx2
+{
+
+class SvDDEObject : public SvLinkSource
+{
+ OUString sItem;
+
+ std::unique_ptr<DdeConnection> pConnection;
+ std::unique_ptr<DdeLink> pLink;
+ std::unique_ptr<DdeRequest> pRequest;
+ css::uno::Any * pGetData;
+
+ bool bWaitForData; // waiting for data?
+
+
+ static bool ImplHasOtherFormat( DdeTransaction& );
+ DECL_LINK( ImplGetDDEData, const DdeData*, void );
+ DECL_LINK( ImplDoneDDEData, bool, void );
+
+protected:
+ virtual ~SvDDEObject() override;
+
+public:
+ SvDDEObject();
+
+ virtual bool GetData( css::uno::Any & rData /*out param*/,
+ const OUString & aMimeType,
+ bool bSynchron = false ) override;
+
+ virtual bool Connect( SvBaseLink * ) override;
+ virtual void Edit(weld::Window* pParent, sfx2::SvBaseLink* pBaseLink, const Link<const OUString&, void>& rEndEditHdl) override;
+
+ virtual bool IsPending() const override;
+ virtual bool IsDataComplete() const override;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/linkmgr2.cxx b/sfx2/source/appl/linkmgr2.cxx
new file mode 100644
index 0000000000..a20501a1ba
--- /dev/null
+++ b/sfx2/source/appl/linkmgr2.cxx
@@ -0,0 +1,722 @@
+/* -*- 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 <comphelper/string.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <com/sun/star/document/UpdateDocMode.hpp>
+#include <officecfg/Office/Common.hxx>
+#include <osl/file.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/urihelper.hxx>
+#include <sot/formats.hxx>
+#include <tools/urlobj.hxx>
+#include <sot/exchange.hxx>
+#include <tools/debug.hxx>
+#include <vcl/filter/SvmReader.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/gdimtf.hxx>
+#include <sfx2/lnkbase.hxx>
+#include <sfx2/app.hxx>
+#include <vcl/graph.hxx>
+#include <svl/stritem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <vcl/dibtools.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/securityoptions.hxx>
+#include <vcl/GraphicLoader.hxx>
+#include <vcl/TypeSerializer.hxx>
+
+#include "fileobj.hxx"
+#include "impldde.hxx"
+#include <sfx2/strings.hrc>
+#include <sfx2/sfxresid.hxx>
+
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::lang::XComponent;
+using ::com::sun::star::util::XCloseable;
+
+namespace sfx2
+{
+
+namespace {
+
+class SvxInternalLink : public sfx2::SvLinkSource
+{
+public:
+ SvxInternalLink() {}
+
+ virtual bool Connect( sfx2::SvBaseLink* ) override;
+};
+
+}
+
+LinkManager::LinkManager(SfxObjectShell* p)
+ : pPersist( p )
+{
+}
+
+LinkManager::~LinkManager()
+{
+ for(tools::SvRef<SvBaseLink> & rTmp : aLinkTbl)
+ {
+ if( rTmp.is() )
+ {
+ rTmp->Disconnect();
+ rTmp->SetLinkManager( nullptr );
+ }
+ }
+}
+
+void LinkManager::InsertCachedComp(const Reference<XComponent>& xComp)
+{
+ maCachedComps.push_back(xComp);
+}
+
+void LinkManager::CloseCachedComps()
+{
+ for (const auto& rxCachedComp : maCachedComps)
+ {
+ Reference<XCloseable> xCloseable(rxCachedComp, UNO_QUERY);
+ if (!xCloseable.is())
+ continue;
+
+ xCloseable->close(true);
+ }
+ maCachedComps.clear();
+}
+
+void LinkManager::Remove( SvBaseLink const *pLink )
+{
+ // No duplicate links inserted
+ bool bFound = false;
+ for( size_t n = 0; n < aLinkTbl.size(); )
+ {
+ tools::SvRef<SvBaseLink>& rTmp = aLinkTbl[ n ];
+ if( pLink == rTmp.get() )
+ {
+ rTmp->Disconnect();
+ rTmp->SetLinkManager( nullptr );
+ rTmp.clear();
+ bFound = true;
+ }
+
+ // Remove empty ones if they exist
+ if( !rTmp.is() )
+ {
+ aLinkTbl.erase( aLinkTbl.begin() + n );
+ if( bFound )
+ return ;
+ }
+ else
+ ++n;
+ }
+}
+
+void LinkManager::Remove( size_t nPos, size_t nCnt )
+{
+ if( !nCnt || nPos >= aLinkTbl.size() )
+ return;
+
+ if (sal::static_int_cast<size_t>(nPos + nCnt) > aLinkTbl.size())
+ nCnt = aLinkTbl.size() - nPos;
+
+ for( size_t n = nPos; n < nPos + nCnt; ++n)
+ {
+ tools::SvRef<SvBaseLink>& rTmp = aLinkTbl[ n ];
+ if( rTmp.is() )
+ {
+ rTmp->Disconnect();
+ rTmp->SetLinkManager( nullptr );
+ }
+ }
+ aLinkTbl.erase( aLinkTbl.begin() + nPos, aLinkTbl.begin() + nPos + nCnt );
+}
+
+bool LinkManager::Insert( SvBaseLink* pLink )
+{
+ for( size_t n = 0; n < aLinkTbl.size(); ++n )
+ {
+ tools::SvRef<SvBaseLink>& rTmp = aLinkTbl[ n ];
+ if( !rTmp.is() )
+ {
+ aLinkTbl.erase( aLinkTbl.begin() + n-- );
+ }
+ else if( pLink == rTmp.get() )
+ return false; // No duplicate links inserted
+ }
+
+ pLink->SetLinkManager( this );
+ aLinkTbl.emplace_back(pLink );
+ return true;
+}
+
+bool LinkManager::InsertLink( SvBaseLink * pLink,
+ SvBaseLinkObjectType nObjType,
+ SfxLinkUpdateMode nUpdateMode,
+ const OUString* pName )
+{
+ // This First
+ pLink->SetObjType( nObjType );
+ if( pName )
+ pLink->SetName( *pName );
+ pLink->SetUpdateMode( nUpdateMode );
+ return Insert( pLink );
+}
+
+void LinkManager::InsertDDELink( SvBaseLink * pLink,
+ const OUString& rServer,
+ std::u16string_view rTopic,
+ std::u16string_view rItem )
+{
+ if( !isClientType( pLink->GetObjType() ) )
+ return;
+
+ OUString sCmd;
+ ::sfx2::MakeLnkName( sCmd, &rServer, rTopic, rItem );
+
+ pLink->SetObjType( SvBaseLinkObjectType::ClientDde );
+ pLink->SetName( sCmd );
+ Insert( pLink );
+}
+
+void LinkManager::InsertDDELink( SvBaseLink * pLink )
+{
+ DBG_ASSERT( isClientType(pLink->GetObjType()), "no OBJECT_CLIENT_SO" );
+ if( !isClientType( pLink->GetObjType() ) )
+ return;
+
+ if( pLink->GetObjType() == SvBaseLinkObjectType::ClientSo )
+ pLink->SetObjType( SvBaseLinkObjectType::ClientDde );
+
+ Insert( pLink );
+}
+
+// Obtain the string for the dialog
+bool LinkManager::GetDisplayNames( const SvBaseLink * pLink,
+ OUString* pType,
+ OUString* pFile,
+ OUString* pLinkStr,
+ OUString* pFilter )
+{
+ bool bRet = false;
+ const OUString& sLNm( pLink->GetLinkSourceName() );
+ if( !sLNm.isEmpty() )
+ {
+ switch( pLink->GetObjType() )
+ {
+ case SvBaseLinkObjectType::ClientFile:
+ case SvBaseLinkObjectType::ClientGraphic:
+ case SvBaseLinkObjectType::ClientOle:
+ {
+ sal_Int32 nPos = 0;
+ OUString sFile( sLNm.getToken( 0, ::sfx2::cTokenSeparator, nPos ) );
+ OUString sRange( sLNm.getToken( 0, ::sfx2::cTokenSeparator, nPos ) );
+
+ if( pFile )
+ *pFile = sFile;
+ if( pLinkStr )
+ *pLinkStr = sRange;
+ if( pFilter )
+ *pFilter = nPos == -1 ? OUString() : sLNm.copy(nPos);
+
+ if( pType )
+ {
+ SvBaseLinkObjectType nObjType = pLink->GetObjType();
+ *pType = SfxResId(
+ ( SvBaseLinkObjectType::ClientFile == nObjType || SvBaseLinkObjectType::ClientOle == nObjType )
+ ? RID_SVXSTR_FILELINK
+ : RID_SVXSTR_GRAPHICLINK);
+ }
+ bRet = true;
+ }
+ break;
+ case SvBaseLinkObjectType::ClientDde:
+ {
+ sal_Int32 nTmp = 0;
+ OUString sServer( sLNm.getToken( 0, cTokenSeparator, nTmp ) );
+ OUString sTopic( sLNm.getToken( 0, cTokenSeparator, nTmp ) );
+
+ if( pType )
+ *pType = sServer;
+ if( pFile )
+ *pFile = sTopic;
+ if( pLinkStr )
+ *pLinkStr = nTmp != -1 ? sLNm.copy(nTmp) : OUString();
+ bRet = true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+void LinkManager::UpdateAllLinks(
+ bool bAskUpdate,
+ bool bUpdateGrfLinks,
+ weld::Window* pParentWin )
+{
+ // when active content is disabled don't bother updating all links
+ // also (when bAskUpdate == true) don't show the pop up.
+ if(officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
+ return;
+
+ // First make a copy of the array in order to update links
+ // links in ... no contact between them!
+ std::vector<SvBaseLink*> aTmpArr;
+ for( size_t n = 0; n < aLinkTbl.size(); ++n )
+ {
+ tools::SvRef<SvBaseLink>& rLink = aLinkTbl[ n ];
+ if( !rLink.is() )
+ {
+ Remove( n-- );
+ continue;
+ }
+ aTmpArr.push_back( rLink.get() );
+ }
+
+ for(SvBaseLink* pLink : aTmpArr)
+ {
+ // search first in the array after the entry
+ bool bFound = false;
+ for(const tools::SvRef<SvBaseLink> & i : aLinkTbl)
+ if( pLink == i.get() )
+ {
+ bFound = true;
+ break;
+ }
+
+ if( !bFound )
+ continue; // was not available!
+
+ // Graphic-Links not to update yet
+ if( !pLink->IsVisible() ||
+ ( !bUpdateGrfLinks && SvBaseLinkObjectType::ClientGraphic == pLink->GetObjType() ))
+ continue;
+
+ if( bAskUpdate )
+ {
+ OUString aMsg = SfxResId(STR_QUERY_UPDATE_LINKS);
+ INetURLObject aURL(pPersist->getDocumentBaseURL());
+ aMsg = aMsg.replaceFirst("%{filename}", aURL.GetLastName());
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pParentWin,
+ VclMessageType::Question, VclButtonsType::YesNo, aMsg));
+ xQueryBox->set_default_response(RET_YES);
+
+ int nRet = xQueryBox->run();
+ if( RET_YES != nRet )
+ {
+ SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
+
+ if(pShell)
+ {
+ comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = pShell->getEmbeddedObjectContainer();
+ rEmbeddedObjectContainer.setUserAllowsLinkUpdate(false);
+ }
+
+ return ; // nothing should be updated
+ }
+ bAskUpdate = false; // once is enough
+ }
+
+ pLink->Update();
+ }
+ CloseCachedComps();
+}
+
+SvLinkSourceRef LinkManager::CreateObj( SvBaseLink const * pLink )
+{
+ switch( pLink->GetObjType() )
+ {
+ case SvBaseLinkObjectType::ClientFile:
+ case SvBaseLinkObjectType::ClientGraphic:
+ case SvBaseLinkObjectType::ClientOle:
+ return new SvFileObject;
+ case SvBaseLinkObjectType::Internal:
+ if(officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
+ return SvLinkSourceRef();
+ return new SvxInternalLink;
+ case SvBaseLinkObjectType::ClientDde:
+ if (officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
+ return SvLinkSourceRef();
+ return new SvDDEObject;
+ default:
+ return SvLinkSourceRef();
+ }
+}
+
+bool LinkManager::InsertServer( SvLinkSource* pObj )
+{
+ // no duplicate inserts
+ if( !pObj )
+ return false;
+
+ return aServerTbl.insert( pObj ).second;
+}
+
+void LinkManager::RemoveServer( SvLinkSource* pObj )
+{
+ aServerTbl.erase( pObj );
+}
+
+void MakeLnkName( OUString& rName, const OUString* pType, std::u16string_view rFile,
+ std::u16string_view rLink, const OUString* pFilter )
+{
+ if( pType )
+ {
+ rName = comphelper::string::strip(*pType, ' ')
+ + OUStringChar(cTokenSeparator);
+ }
+ else
+ rName.clear();
+
+ rName += rFile;
+
+ rName = comphelper::string::strip(rName, ' ')
+ + OUStringChar(cTokenSeparator);
+ rName = comphelper::string::strip(rName, ' ') + rLink;
+ if( pFilter )
+ {
+ rName += OUStringChar(cTokenSeparator) + *pFilter;
+ rName = comphelper::string::strip(rName, ' ');
+ }
+}
+
+void LinkManager::ReconnectDdeLink(SfxObjectShell& rServer)
+{
+ SfxMedium* pMed = rServer.GetMedium();
+ if (!pMed)
+ return;
+
+ const ::sfx2::SvBaseLinks& rLinks = GetLinks();
+ size_t n = rLinks.size();
+
+ for (size_t i = 0; i < n; ++i)
+ {
+ ::sfx2::SvBaseLink* p = rLinks[i].get();
+ OUString aType, aFile, aLink, aFilter;
+ if (!GetDisplayNames(p, &aType, &aFile, &aLink, &aFilter))
+ continue;
+
+ if (aType != "soffice")
+ // DDE connections between OOo apps are always named 'soffice'.
+ continue;
+
+ OUString aTmp;
+ OUString aURL = aFile;
+ if (osl::FileBase::getFileURLFromSystemPath(aFile, aTmp)
+ == osl::FileBase::E_None)
+ aURL = aTmp;
+
+ if (!aURL.equalsIgnoreAsciiCase(pMed->GetName()))
+ // This DDE link is not associated with this server shell... Skip it.
+ continue;
+
+ if (aLink.isEmpty())
+ continue;
+
+ LinkServerShell(aLink, rServer, *p);
+ }
+}
+
+void LinkManager::LinkServerShell(const OUString& rPath, SfxObjectShell& rServer, ::sfx2::SvBaseLink& rLink)
+{
+ ::sfx2::SvLinkSource* pSrvSrc = rServer.DdeCreateLinkSource(rPath);
+ if (pSrvSrc)
+ {
+ css::datatransfer::DataFlavor aFl;
+ SotExchange::GetFormatDataFlavor(rLink.GetContentType(), aFl);
+ rLink.SetObj(pSrvSrc);
+ pSrvSrc->AddDataAdvise(
+ &rLink, aFl.MimeType,
+ SfxLinkUpdateMode::ONCALL == rLink.GetUpdateMode() ? ADVISEMODE_ONLYONCE : 0);
+ }
+}
+
+void LinkManager::InsertFileLink(
+ sfx2::SvBaseLink& rLink, SvBaseLinkObjectType nFileType, std::u16string_view rFileNm,
+ const OUString* pFilterNm, const OUString* pRange)
+{
+ if (!isClientType(rLink.GetObjType()))
+ return;
+
+ OUStringBuffer aBuf(64);
+ aBuf.append(rFileNm + OUStringChar(sfx2::cTokenSeparator));
+
+ if (pRange)
+ aBuf.append(*pRange);
+
+ if (pFilterNm)
+ {
+ aBuf.append(OUStringChar(sfx2::cTokenSeparator) + *pFilterNm);
+ }
+
+ OUString aCmd = aBuf.makeStringAndClear();
+ InsertLink(&rLink, nFileType, SfxLinkUpdateMode::ONCALL, &aCmd);
+}
+
+// A transfer is aborted, so cancel all download media
+// (for now this is only of interest for the file links!)
+void LinkManager::CancelTransfers()
+{
+
+ const sfx2::SvBaseLinks& rLnks = GetLinks();
+ for( size_t n = rLnks.size(); n; )
+ {
+ const sfx2::SvBaseLink& rLnk = *rLnks[--n];
+ if (isClientFileType(rLnk.GetObjType()))
+ {
+ if (SvFileObject* pFileObj = static_cast<SvFileObject*>(rLnk.GetObj()))
+ pFileObj->CancelTransfers();
+ }
+ }
+}
+
+// For the purpose of sending Status information from the file object to
+// the base link, there exist a dedicated ClipBoardId. The SvData-object
+// gets the appropriate information as a string
+// For now this is required for file object in conjunction with JavaScript
+// - needs information about Load/Abort/Error
+SotClipboardFormatId LinkManager::RegisterStatusInfoId()
+{
+ static SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
+
+ if( nFormat == SotClipboardFormatId::NONE )
+ {
+ nFormat = SotExchange::RegisterFormatName(
+ "StatusInfo from SvxInternalLink");
+ }
+ return nFormat;
+}
+
+bool LinkManager::GetGraphicFromAny(std::u16string_view rMimeType,
+ const css::uno::Any & rValue,
+ Graphic& rGraphic,
+ weld::Window* pParentWin)
+{
+ bool bRet = false;
+
+ if (!rValue.hasValue())
+ return bRet;
+
+ if (rValue.has<OUString>())
+ {
+ OUString sReferer;
+ SfxObjectShell* sh = GetPersist();
+ if (sh && sh->HasName())
+ sReferer = sh->GetMedium()->GetName();
+
+ OUString sURL = rValue.get<OUString>();
+ if (!SvtSecurityOptions::isUntrustedReferer(sReferer))
+ rGraphic = vcl::graphic::loadFromURL(sURL, pParentWin);
+ if (rGraphic.IsNone())
+ rGraphic.SetDefaultType();
+ rGraphic.setOriginURL(sURL);
+ return true;
+ }
+ else if (rValue.has<css::uno::Sequence<sal_Int8>>())
+ {
+ auto aSeq = rValue.get<css::uno::Sequence<sal_Int8>>();
+
+ SvMemoryStream aMemStm( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(),
+ StreamMode::READ );
+ aMemStm.Seek( 0 );
+
+ switch( SotExchange::GetFormatIdFromMimeType( rMimeType ) )
+ {
+ case SotClipboardFormatId::SVXB:
+ {
+ TypeSerializer aSerializer(aMemStm);
+ aSerializer.readGraphic(rGraphic);
+ bRet = true;
+ }
+ break;
+ case SotClipboardFormatId::GDIMETAFILE:
+ {
+ GDIMetaFile aMtf;
+ SvmReader aReader( aMemStm );
+ aReader.Read( aMtf );
+ rGraphic = aMtf;
+ bRet = true;
+ }
+ break;
+ case SotClipboardFormatId::BITMAP:
+ {
+ Bitmap aBmp;
+ ReadDIB(aBmp, aMemStm, true);
+ rGraphic = BitmapEx(aBmp);
+ bRet = true;
+ }
+ break;
+ default: break;
+ }
+ }
+ return bRet;
+}
+
+static OUString lcl_DDE_RelToAbs( const OUString& rTopic, std::u16string_view rBaseURL )
+{
+ OUString sRet;
+ INetURLObject aURL( rTopic );
+ if( INetProtocol::NotValid == aURL.GetProtocol() )
+ osl::FileBase::getFileURLFromSystemPath(rTopic, sRet);
+ if( sRet.isEmpty() )
+ sRet = URIHelper::SmartRel2Abs( INetURLObject(rBaseURL), rTopic, URIHelper::GetMaybeFileHdl() );
+ return sRet;
+}
+
+bool SvxInternalLink::Connect( sfx2::SvBaseLink* pLink )
+{
+ SfxObjectShell* pFndShell = nullptr;
+ sal_uInt16 nUpdateMode = css::document::UpdateDocMode::NO_UPDATE;
+ OUString sTopic, sItem, sReferer;
+ LinkManager* pLinkMgr = pLink->GetLinkManager();
+ if (pLinkMgr && sfx2::LinkManager::GetDisplayNames(pLink, nullptr, &sTopic, &sItem) && !sTopic.isEmpty())
+ {
+ // first only loop over the DocumentShells the shells and find those
+ // with the name:
+ CharClass aCC( LanguageTag( LANGUAGE_SYSTEM) );
+
+ bool bFirst = true;
+ SfxObjectShell* pShell = pLinkMgr->GetPersist();
+ if( pShell && pShell->GetMedium() )
+ {
+ sReferer = pShell->GetMedium()->GetBaseURL();
+ const SfxUInt16Item* pItem = pShell->GetMedium()->GetItemSet().GetItem(SID_UPDATEDOCMODE, false);
+ if ( pItem )
+ nUpdateMode = pItem->GetValue();
+ }
+
+ OUString sNmURL(aCC.lowercase(lcl_DDE_RelToAbs(sTopic, sReferer)));
+
+ if ( !pShell )
+ {
+ bFirst = false;
+ pShell = SfxObjectShell::GetFirst( nullptr, false );
+ }
+
+ OUString sTmp;
+ while( pShell )
+ {
+ if( sTmp.isEmpty() )
+ {
+ sTmp = pShell->GetTitle( SFX_TITLE_FULLNAME );
+ sTmp = lcl_DDE_RelToAbs(sTmp, sReferer );
+ }
+
+
+ sTmp = aCC.lowercase( sTmp );
+ if( sTmp == sNmURL ) // we want these
+ {
+ pFndShell = pShell;
+ break;
+ }
+
+ if( bFirst )
+ {
+ bFirst = false;
+ pShell = SfxObjectShell::GetFirst( nullptr, false );
+ }
+ else
+ pShell = SfxObjectShell::GetNext( *pShell, nullptr, false );
+
+ sTmp.clear();
+ }
+ }
+
+ // empty topics are not allowed - which document is it
+ if( sTopic.isEmpty() )
+ return false;
+
+ if (pFndShell)
+ {
+ sfx2::SvLinkSource* pNewSrc = pFndShell->DdeCreateLinkSource( sItem );
+ if( pNewSrc )
+ {
+ css::datatransfer::DataFlavor aFl;
+ SotExchange::GetFormatDataFlavor( pLink->GetContentType(), aFl );
+
+ pLink->SetObj( pNewSrc );
+ pNewSrc->AddDataAdvise( pLink, aFl.MimeType,
+ SfxLinkUpdateMode::ONCALL == pLink->GetUpdateMode()
+ ? ADVISEMODE_ONLYONCE
+ : 0 );
+ return true;
+ }
+ }
+ else
+ {
+ // then try to download the file:
+ INetURLObject aURL( sTopic );
+ INetProtocol eOld = aURL.GetProtocol();
+ sTopic = lcl_DDE_RelToAbs( sTopic, sReferer );
+ aURL.SetURL( sTopic );
+ if( INetProtocol::NotValid != eOld ||
+ INetProtocol::Http != aURL.GetProtocol() )
+ {
+ SfxStringItem aName( SID_FILE_NAME, sTopic );
+ SfxBoolItem aMinimized(SID_MINIMIZED, true);
+ SfxBoolItem aHidden(SID_HIDDEN, true);
+ SfxStringItem aTarget( SID_TARGETNAME, "_blank" );
+ SfxStringItem aReferer( SID_REFERER, sReferer );
+ SfxUInt16Item aUpdate( SID_UPDATEDOCMODE, nUpdateMode );
+ SfxBoolItem aReadOnly(SID_DOC_READONLY, false);
+
+ // Disable automatic re-connection to avoid this link instance
+ // being destroyed at re-connection.
+ SfxBoolItem aDdeConnect(SID_DDE_RECONNECT_ONLOAD, false);
+
+ // #i14200# (DDE-link crashes wordprocessor)
+ SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
+ aArgs.Put(aReferer);
+ aArgs.Put(aTarget);
+ aArgs.Put(aHidden);
+ aArgs.Put(aMinimized);
+ aArgs.Put(aName);
+ aArgs.Put(aUpdate);
+ aArgs.Put(aReadOnly);
+ aArgs.Put(aDdeConnect);
+ Reference<XComponent> xComp = SfxObjectShell::CreateAndLoadComponent(aArgs);
+ pFndShell = SfxObjectShell::GetShellFromComponent(xComp);
+ if (xComp.is() && pFndShell && pLinkMgr)
+ {
+ pLinkMgr->InsertCachedComp(xComp);
+ sfx2::LinkManager::LinkServerShell(sItem, *pFndShell, *pLink);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/linksrc.cxx b/sfx2/source/appl/linksrc.cxx
new file mode 100644
index 0000000000..3a1af228f6
--- /dev/null
+++ b/sfx2/source/appl/linksrc.cxx
@@ -0,0 +1,418 @@
+/* -*- 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 <sfx2/linksrc.hxx>
+#include <sfx2/lnkbase.hxx>
+#include <com/sun/star/uno/Any.hxx>
+
+#include <utility>
+#include <vcl/timer.hxx>
+#include <memory>
+#include <vector>
+#include <algorithm>
+
+
+using namespace ::com::sun::star::uno;
+
+namespace sfx2
+{
+
+namespace {
+
+class SvLinkSourceTimer : public Timer
+{
+ SvLinkSource * pOwner;
+ virtual void Invoke() override;
+public:
+ explicit SvLinkSourceTimer( SvLinkSource * pOwn );
+};
+
+}
+
+SvLinkSourceTimer::SvLinkSourceTimer( SvLinkSource * pOwn )
+ : Timer("sfx2 SvLinkSourceTimer"), pOwner( pOwn )
+{
+}
+
+void SvLinkSourceTimer::Invoke()
+{
+ // Secure against being destroyed in Handler
+ SvLinkSourceRef xHoldAlive( pOwner );
+ pOwner->SendDataChanged();
+}
+
+static void StartTimer( std::unique_ptr<SvLinkSourceTimer>& pTimer, SvLinkSource * pOwner,
+ sal_uInt64 nTimeout )
+{
+ if( !pTimer )
+ {
+ pTimer.reset( new SvLinkSourceTimer( pOwner ) );
+ pTimer->SetTimeout( nTimeout );
+ pTimer->Start();
+ }
+}
+
+namespace {
+
+struct SvLinkSource_Entry_Impl
+{
+ tools::SvRef<SvBaseLink> xSink;
+ OUString aDataMimeType;
+ sal_uInt16 nAdviseModes;
+ bool bIsDataSink;
+
+ SvLinkSource_Entry_Impl( SvBaseLink* pLink, OUString aMimeType,
+ sal_uInt16 nAdvMode )
+ : xSink( pLink ), aDataMimeType(std::move( aMimeType )),
+ nAdviseModes( nAdvMode ), bIsDataSink( true )
+ {}
+
+ explicit SvLinkSource_Entry_Impl( SvBaseLink* pLink )
+ : xSink( pLink ), nAdviseModes( 0 ), bIsDataSink( false )
+ {}
+};
+
+class SvLinkSource_Array_Impl
+{
+friend class SvLinkSource_EntryIter_Impl;
+private:
+ std::vector<std::unique_ptr<SvLinkSource_Entry_Impl>> mvData;
+
+public:
+ SvLinkSource_Array_Impl() {}
+
+ size_t size() const { return mvData.size(); }
+ SvLinkSource_Entry_Impl *operator[](size_t idx) const { return mvData[idx].get(); }
+ void push_back(SvLinkSource_Entry_Impl* rData) { mvData.emplace_back(rData); }
+
+ void DeleteAndDestroy(SvLinkSource_Entry_Impl const * p)
+ {
+ auto it = std::find_if(mvData.begin(), mvData.end(),
+ [&p](const std::unique_ptr<SvLinkSource_Entry_Impl>& rxData) { return rxData.get() == p; });
+ if (it != mvData.end())
+ mvData.erase(it);
+ }
+};
+
+class SvLinkSource_EntryIter_Impl
+{
+ std::vector<SvLinkSource_Entry_Impl*> aArr;
+ const SvLinkSource_Array_Impl& rOrigArr;
+ sal_uInt16 nPos;
+public:
+ explicit SvLinkSource_EntryIter_Impl( const SvLinkSource_Array_Impl& rArr );
+ SvLinkSource_Entry_Impl* Curr()
+ { return nPos < aArr.size() ? aArr[ nPos ] : nullptr; }
+ SvLinkSource_Entry_Impl* Next();
+ bool IsValidCurrValue( SvLinkSource_Entry_Impl const * pEntry );
+};
+
+}
+
+SvLinkSource_EntryIter_Impl::SvLinkSource_EntryIter_Impl(
+ const SvLinkSource_Array_Impl& rArr )
+ : rOrigArr( rArr ), nPos( 0 )
+{
+ for (auto const & i : rArr.mvData)
+ aArr.push_back(i.get());
+}
+
+bool SvLinkSource_EntryIter_Impl::IsValidCurrValue( SvLinkSource_Entry_Impl const * pEntry )
+{
+ if ( nPos >= aArr.size() )
+ return false;
+ if (aArr[nPos] != pEntry)
+ return false;
+ for (auto const & i : rOrigArr.mvData)
+ if (i.get() == pEntry)
+ return true;
+ return false;
+}
+
+SvLinkSource_Entry_Impl* SvLinkSource_EntryIter_Impl::Next()
+{
+ SvLinkSource_Entry_Impl* pRet = nullptr;
+ if( nPos + 1 < static_cast<sal_uInt16>(aArr.size()) )
+ {
+ ++nPos;
+ if( rOrigArr.size() == aArr.size() &&
+ rOrigArr[ nPos ] == aArr[ nPos ] )
+ pRet = aArr[ nPos ];
+ else
+ {
+ // then we must search the current (or the next) in the orig
+ do {
+ pRet = aArr[ nPos ];
+ for (auto const & i : rOrigArr.mvData)
+ if (i.get() == pRet)
+ return pRet;
+ pRet = nullptr;
+ ++nPos;
+ } while( nPos < aArr.size() );
+
+ if( nPos >= aArr.size() )
+ pRet = nullptr;
+ }
+ }
+ return pRet;
+}
+
+struct SvLinkSource_Impl
+{
+ SvLinkSource_Array_Impl aArr;
+ OUString aDataMimeType;
+ std::unique_ptr<SvLinkSourceTimer>
+ pTimer;
+ sal_uInt64 nTimeout;
+ css::uno::Reference<css::io::XInputStream>
+ m_xInputStreamToLoadFrom;
+ bool m_bIsReadOnly;
+
+ SvLinkSource_Impl()
+ : nTimeout(3000)
+ , m_bIsReadOnly(false)
+ {
+ }
+};
+
+SvLinkSource::SvLinkSource()
+ : pImpl( new SvLinkSource_Impl )
+{
+}
+
+SvLinkSource::~SvLinkSource()
+{
+}
+
+
+SvLinkSource::StreamToLoadFrom SvLinkSource::getStreamToLoadFrom()
+{
+ return StreamToLoadFrom(
+ pImpl->m_xInputStreamToLoadFrom,
+ pImpl->m_bIsReadOnly);
+}
+
+void SvLinkSource::setStreamToLoadFrom(const css::uno::Reference<css::io::XInputStream>& xInputStream, bool bIsReadOnly )
+{
+ pImpl->m_xInputStreamToLoadFrom = xInputStream;
+ pImpl->m_bIsReadOnly = bIsReadOnly;
+}
+
+// #i88291#
+void SvLinkSource::clearStreamToLoadFrom()
+{
+ pImpl->m_xInputStreamToLoadFrom.clear();
+}
+
+void SvLinkSource::Closed()
+{
+ SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
+ for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
+ if( !p->bIsDataSink )
+ p->xSink->Closed();
+}
+
+sal_uInt64 SvLinkSource::GetUpdateTimeout() const
+{
+ return pImpl->nTimeout;
+}
+
+void SvLinkSource::SetUpdateTimeout( sal_uInt64 nTimeout )
+{
+ pImpl->nTimeout = nTimeout;
+ if( pImpl->pTimer )
+ pImpl->pTimer->SetTimeout( nTimeout );
+}
+
+void SvLinkSource::SendDataChanged()
+{
+ SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
+ for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
+ {
+ if( p->bIsDataSink )
+ {
+ OUString sDataMimeType( pImpl->aDataMimeType );
+ if( sDataMimeType.isEmpty() )
+ sDataMimeType = p->aDataMimeType;
+
+ Any aVal;
+ if( ( p->nAdviseModes & ADVISEMODE_NODATA ) ||
+ GetData( aVal, sDataMimeType, true ) )
+ {
+ p->xSink->DataChanged( sDataMimeType, aVal );
+
+ if ( !aIter.IsValidCurrValue( p ) )
+ continue;
+
+ if( p->nAdviseModes & ADVISEMODE_ONLYONCE )
+ {
+ pImpl->aArr.DeleteAndDestroy( p );
+ }
+
+ }
+ }
+ }
+ pImpl->pTimer.reset();
+ pImpl->aDataMimeType.clear();
+}
+
+void SvLinkSource::NotifyDataChanged()
+{
+ if( pImpl->nTimeout )
+ StartTimer( pImpl->pTimer, this, pImpl->nTimeout ); // New timeout
+ else
+ {
+ SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
+ for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
+ if( p->bIsDataSink )
+ {
+ Any aVal;
+ if( ( p->nAdviseModes & ADVISEMODE_NODATA ) ||
+ GetData( aVal, p->aDataMimeType, true ) )
+ {
+ tools::SvRef<sfx2::SvBaseLink> xLink(p->xSink);
+ xLink->DataChanged( p->aDataMimeType, aVal );
+
+ if ( !aIter.IsValidCurrValue( p ) )
+ continue;
+
+ if( p->nAdviseModes & ADVISEMODE_ONLYONCE )
+ {
+ pImpl->aArr.DeleteAndDestroy( p );
+ }
+ }
+ }
+
+ pImpl->pTimer.reset();
+ }
+}
+
+// notify the sink, the mime type is not
+// a selection criterion
+void SvLinkSource::DataChanged( const OUString & rMimeType,
+ const css::uno::Any & rVal )
+{
+ if( pImpl->nTimeout && !rVal.hasValue() )
+ { // only when no data was included
+ // fire all data to the sink, independent of the requested format
+ pImpl->aDataMimeType = rMimeType;
+ StartTimer( pImpl->pTimer, this, pImpl->nTimeout ); // New timeout
+ }
+ else
+ {
+ SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
+ for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
+ {
+ if( p->bIsDataSink )
+ {
+ p->xSink->DataChanged( rMimeType, rVal );
+
+ if ( !aIter.IsValidCurrValue( p ) )
+ continue;
+
+ if( p->nAdviseModes & ADVISEMODE_ONLYONCE )
+ {
+ pImpl->aArr.DeleteAndDestroy( p );
+ }
+ }
+ }
+
+ pImpl->pTimer.reset();
+ }
+}
+
+
+// only one link is correct
+void SvLinkSource::AddDataAdvise( SvBaseLink * pLink, const OUString& rMimeType,
+ sal_uInt16 nAdviseModes )
+{
+ SvLinkSource_Entry_Impl* pNew = new SvLinkSource_Entry_Impl(
+ pLink, rMimeType, nAdviseModes );
+ pImpl->aArr.push_back( pNew );
+}
+
+void SvLinkSource::RemoveAllDataAdvise( SvBaseLink const * pLink )
+{
+ SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
+ for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
+ if( p->bIsDataSink && p->xSink.get() == pLink )
+ {
+ pImpl->aArr.DeleteAndDestroy( p );
+ }
+}
+
+// only one link is correct
+void SvLinkSource::AddConnectAdvise( SvBaseLink * pLink )
+{
+ SvLinkSource_Entry_Impl* pNew = new SvLinkSource_Entry_Impl( pLink );
+ pImpl->aArr.push_back( pNew );
+}
+
+void SvLinkSource::RemoveConnectAdvise( SvBaseLink const * pLink )
+{
+ SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
+ for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
+ if( !p->bIsDataSink && p->xSink.get() == pLink )
+ {
+ pImpl->aArr.DeleteAndDestroy( p );
+ }
+}
+
+bool SvLinkSource::HasDataLinks() const
+{
+ bool bRet = false;
+ for( sal_uInt16 n = 0, nEnd = pImpl->aArr.size(); n < nEnd; ++n )
+ if( pImpl->aArr[ n ]->bIsDataSink )
+ {
+ bRet = true;
+ break;
+ }
+ return bRet;
+}
+
+// sal_True => waitinmg for data
+bool SvLinkSource::IsPending() const
+{
+ return false;
+}
+
+// sal_True => data complete loaded
+bool SvLinkSource::IsDataComplete() const
+{
+ return true;
+}
+
+bool SvLinkSource::Connect( SvBaseLink* )
+{
+ return true;
+}
+
+bool SvLinkSource::GetData( css::uno::Any &, const OUString &, bool )
+{
+ return false;
+}
+
+void SvLinkSource::Edit(weld::Window *, SvBaseLink *, const Link<const OUString&, void>&)
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/lnkbase2.cxx b/sfx2/source/appl/lnkbase2.cxx
new file mode 100644
index 0000000000..eea1751cd5
--- /dev/null
+++ b/sfx2/source/appl/lnkbase2.cxx
@@ -0,0 +1,604 @@
+/* -*- 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 <memory>
+#include <sfx2/lnkbase.hxx>
+#include <sot/exchange.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <sfx2/linkmgr.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/strings.hrc>
+#include <sfx2/sfxresid.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <tools/debug.hxx>
+#include <svl/svdde.hxx>
+#include <osl/diagnose.h>
+#include <officecfg/Office/Common.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sfx2
+{
+
+namespace {
+class ImplDdeItem;
+}
+
+// only for internal management
+struct ImplBaseLinkData
+{
+ struct tClientType
+ {
+ // applies for all links
+ SotClipboardFormatId nCntntType; // Update Format
+ // Not Ole-Links
+ bool bIntrnlLnk; // It is an internal link
+ SfxLinkUpdateMode nUpdateMode; // UpdateMode
+ };
+
+ struct tDDEType
+ {
+ ImplDdeItem* pItem;
+ };
+
+ union {
+ tClientType ClientType;
+ tDDEType DDEType;
+ };
+ ImplBaseLinkData()
+ {
+ ClientType.nCntntType = SotClipboardFormatId::NONE;
+ ClientType.bIntrnlLnk = false;
+ ClientType.nUpdateMode = SfxLinkUpdateMode::NONE;
+ DDEType.pItem = nullptr;
+ }
+};
+
+namespace {
+
+class ImplDdeItem : public DdeGetPutItem
+{
+ SvBaseLink* pLink;
+ DdeData aData;
+ Sequence< sal_Int8 > aSeq; // Datacontainer for DdeData !!!
+ bool bIsValidData : 1;
+ bool bIsInDTOR : 1;
+public:
+#if defined(_WIN32)
+ ImplDdeItem( SvBaseLink& rLink, const OUString& rStr )
+ : DdeGetPutItem( rStr ), pLink( &rLink ), bIsValidData( false ),
+ bIsInDTOR( false )
+ {}
+#endif
+ virtual ~ImplDdeItem() override;
+
+ virtual DdeData* Get( SotClipboardFormatId ) override;
+ virtual bool Put( const DdeData* ) override;
+ virtual void AdviseLoop( bool ) override;
+
+ void Notify()
+ {
+ bIsValidData = false;
+ DdeGetPutItem::NotifyClient();
+ }
+
+ bool IsInDTOR() const { return bIsInDTOR; }
+};
+
+}
+
+SvBaseLink::SvBaseLink()
+ : m_pLinkMgr( nullptr )
+ , m_pParentWin( nullptr )
+ , m_bIsConnect( false )
+ , m_bIsReadOnly(false)
+{
+ mnObjType = SvBaseLinkObjectType::ClientSo;
+ pImplData.reset( new ImplBaseLinkData );
+ bVisible = bSynchron = true;
+ bWasLastEditOK = false;
+}
+
+
+SvBaseLink::SvBaseLink( SfxLinkUpdateMode nUpdateMode, SotClipboardFormatId nContentType )
+ : m_pLinkMgr( nullptr )
+ , m_pParentWin( nullptr )
+ , m_bIsConnect( false )
+ , m_bIsReadOnly(false)
+{
+ mnObjType = SvBaseLinkObjectType::ClientSo;
+ pImplData.reset( new ImplBaseLinkData );
+ bVisible = bSynchron = true;
+ bWasLastEditOK = false;
+
+ // It is going to be an OLE-Link,
+ pImplData->ClientType.nUpdateMode = nUpdateMode;
+ pImplData->ClientType.nCntntType = nContentType;
+ pImplData->ClientType.bIntrnlLnk = false;
+}
+
+#if defined(_WIN32)
+
+static DdeTopic* FindTopic( const OUString & rLinkName, sal_uInt16* pItemStt )
+{
+ if( rLinkName.isEmpty() )
+ return nullptr;
+
+ OUString sNm( rLinkName );
+ sal_Int32 nTokenPos = 0;
+ OUString sService( sNm.getToken( 0, cTokenSeparator, nTokenPos ) );
+
+ DdeServices& rSvc = DdeService::GetServices();
+ for (auto const& elem : rSvc)
+ {
+ if(elem->GetName() == sService)
+ {
+ // then we search for the Topic
+ OUString sTopic( sNm.getToken( 0, cTokenSeparator, nTokenPos ) );
+ if( pItemStt )
+ *pItemStt = nTokenPos;
+
+ std::vector<DdeTopic*>& rTopics = elem->GetTopics();
+
+ for (auto const& topic : rTopics)
+ if( topic->GetName() == sTopic )
+ return topic;
+ break;
+ }
+ }
+ return nullptr;
+}
+
+SvBaseLink::SvBaseLink( const OUString& rLinkName, SvBaseLinkObjectType nObjectType, SvLinkSource* pObj )
+ : m_pLinkMgr( nullptr )
+ , m_pParentWin( nullptr )
+ , m_bIsConnect( false )
+ , m_bIsReadOnly(false)
+{
+ bVisible = bSynchron = true;
+ bWasLastEditOK = false;
+ aLinkName = rLinkName;
+ pImplData.reset( new ImplBaseLinkData );
+ mnObjType = nObjectType;
+
+ if( !pObj )
+ {
+ DBG_ASSERT( pObj, "Where is my left-most object" );
+ return;
+ }
+
+ if( SvBaseLinkObjectType::DdeExternal == mnObjType )
+ {
+ sal_uInt16 nItemStt = 0;
+ DdeTopic* pTopic = FindTopic( aLinkName, &nItemStt );
+ if( pTopic )
+ {
+ // then we have it all together
+ // MM_TODO how do I get the name
+ OUString aStr = aLinkName; // xLinkName->GetDisplayName();
+ aStr = aStr.copy( nItemStt );
+ pImplData->DDEType.pItem = new ImplDdeItem( *this, aStr );
+ pTopic->InsertItem( pImplData->DDEType.pItem );
+
+ // store the Advice
+ xObj = pObj;
+ }
+ }
+ else if( pObj->Connect( this ) )
+ xObj = pObj;
+}
+
+#endif
+
+SvBaseLink::~SvBaseLink()
+{
+ Disconnect();
+
+ if( mnObjType == SvBaseLinkObjectType::DdeExternal )
+ {
+ if( !pImplData->DDEType.pItem->IsInDTOR() )
+ delete pImplData->DDEType.pItem;
+ }
+
+ pImplData.reset();
+}
+
+IMPL_LINK( SvBaseLink, EndEditHdl, const OUString&, _rNewName, void )
+{
+ OUString sNewName = _rNewName;
+ if ( !ExecuteEdit( sNewName ) )
+ sNewName.clear();
+ bWasLastEditOK = !sNewName.isEmpty();
+ m_aEndEditLink.Call( *this );
+}
+
+
+void SvBaseLink::SetObjType( SvBaseLinkObjectType mnObjTypeP )
+{
+ DBG_ASSERT( mnObjType != SvBaseLinkObjectType::ClientDde, "type already set" );
+ DBG_ASSERT( !xObj.is(), "object exist" );
+
+ mnObjType = mnObjTypeP;
+}
+
+
+void SvBaseLink::SetName( const OUString & rNm )
+{
+ aLinkName = rNm;
+}
+
+
+void SvBaseLink::SetObj( SvLinkSource * pObj )
+{
+ DBG_ASSERT( (isClientType(mnObjType) &&
+ pImplData->ClientType.bIntrnlLnk) ||
+ mnObjType == SvBaseLinkObjectType::ClientGraphic,
+ "no intern link" );
+ xObj = pObj;
+}
+
+
+void SvBaseLink::SetLinkSourceName( const OUString & rLnkNm )
+{
+ if( aLinkName == rLnkNm )
+ return;
+
+ AddNextRef(); // should be superfluous
+ // remove old connection
+ Disconnect();
+
+ aLinkName = rLnkNm;
+
+ // New Connection
+ GetRealObject_();
+ ReleaseRef(); // should be superfluous
+}
+
+
+void SvBaseLink::SetUpdateMode( SfxLinkUpdateMode nMode )
+{
+ if( isClientType(mnObjType) &&
+ pImplData->ClientType.nUpdateMode != nMode )
+ {
+ AddNextRef();
+ Disconnect();
+
+ pImplData->ClientType.nUpdateMode = nMode;
+ GetRealObject_();
+ ReleaseRef();
+ }
+}
+
+// #i88291#
+void SvBaseLink::clearStreamToLoadFrom()
+{
+ m_xInputStreamToLoadFrom.clear();
+ if( xObj.is() )
+ {
+ xObj->clearStreamToLoadFrom();
+ }
+}
+
+bool SvBaseLink::Update()
+{
+ if(officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
+ return false;
+
+ if( isClientType(mnObjType) )
+ {
+ AddNextRef();
+ Disconnect();
+
+ GetRealObject_();
+ ReleaseRef();
+ if( xObj.is() )
+ {
+ xObj->setStreamToLoadFrom(m_xInputStreamToLoadFrom,m_bIsReadOnly);
+ OUString sMimeType( SotExchange::GetFormatMimeType(
+ pImplData->ClientType.nCntntType ));
+ Any aData;
+
+ if( xObj->GetData( aData, sMimeType ) )
+ {
+ UpdateResult eRes = DataChanged(sMimeType, aData);
+ bool bSuccess = eRes == SUCCESS;
+ //for manual Updates there is no need to hold the ServerObject
+ if( SvBaseLinkObjectType::ClientDde == mnObjType &&
+ SfxLinkUpdateMode::ONCALL == GetUpdateMode() && xObj.is() )
+ xObj->RemoveAllDataAdvise( this );
+ return bSuccess;
+ }
+ if( xObj.is() )
+ {
+ // should be asynchronous?
+ if( xObj->IsPending() )
+ return true;
+
+ // we do not need the object anymore
+ AddNextRef();
+ Disconnect();
+ ReleaseRef();
+ }
+ }
+ }
+ return false;
+}
+
+
+SfxLinkUpdateMode SvBaseLink::GetUpdateMode() const
+{
+ return isClientType(mnObjType)
+ ? pImplData->ClientType.nUpdateMode
+ : SfxLinkUpdateMode::ONCALL;
+}
+
+
+void SvBaseLink::GetRealObject_( bool bConnect)
+{
+ if( !m_pLinkMgr )
+ return;
+
+ DBG_ASSERT( !xObj.is(), "object already exist" );
+
+ if( SvBaseLinkObjectType::ClientDde == mnObjType )
+ {
+ OUString sServer;
+ if( sfx2::LinkManager::GetDisplayNames( this, &sServer ) &&
+ sServer == Application::GetAppName() ) // internal Link !!!
+ {
+ // so that the Internal link can be created!
+ mnObjType = SvBaseLinkObjectType::Internal;
+ xObj = sfx2::LinkManager::CreateObj( this );
+
+ pImplData->ClientType.bIntrnlLnk = true;
+ mnObjType = SvBaseLinkObjectType::ClientDde; // so we know what it once was!
+ }
+ else
+ {
+ pImplData->ClientType.bIntrnlLnk = false;
+ xObj = sfx2::LinkManager::CreateObj( this );
+ }
+ }
+ else if( isClientType(mnObjType) )
+ xObj = sfx2::LinkManager::CreateObj( this );
+
+ if( bConnect && ( !xObj.is() || !xObj->Connect( this ) ) )
+ Disconnect();
+}
+
+SotClipboardFormatId SvBaseLink::GetContentType() const
+{
+ if( isClientType(mnObjType) )
+ return pImplData->ClientType.nCntntType;
+
+ return SotClipboardFormatId::NONE; // all Formats ?
+}
+
+
+void SvBaseLink::SetContentType( SotClipboardFormatId nType )
+{
+ if( isClientType(mnObjType) )
+ {
+ pImplData->ClientType.nCntntType = nType;
+ }
+}
+
+LinkManager* SvBaseLink::GetLinkManager()
+{
+ return m_pLinkMgr;
+}
+
+const LinkManager* SvBaseLink::GetLinkManager() const
+{
+ return m_pLinkMgr;
+}
+
+void SvBaseLink::SetLinkManager( LinkManager* _pMgr )
+{
+ m_pLinkMgr = _pMgr;
+}
+
+void SvBaseLink::Disconnect()
+{
+ if( xObj.is() )
+ {
+ xObj->RemoveAllDataAdvise( this );
+ xObj->RemoveConnectAdvise( this );
+ xObj.clear();
+ }
+}
+
+SvBaseLink::UpdateResult SvBaseLink::DataChanged( const OUString &, const css::uno::Any & )
+{
+ if ( mnObjType == SvBaseLinkObjectType::DdeExternal )
+ {
+ if( pImplData->DDEType.pItem )
+ pImplData->DDEType.pItem->Notify();
+ }
+ return SUCCESS;
+}
+
+void SvBaseLink::Edit(weld::Window* pParent, const Link<SvBaseLink&,void>& rEndEditHdl )
+{
+ m_pParentWin = pParent;
+ m_aEndEditLink = rEndEditHdl;
+ m_bIsConnect = xObj.is();
+ if( !m_bIsConnect )
+ GetRealObject_( xObj.is() );
+
+ bool bAsync = false;
+ Link<const OUString&, void> aLink = LINK( this, SvBaseLink, EndEditHdl );
+
+ if( isClientType(mnObjType) && pImplData->ClientType.bIntrnlLnk )
+ {
+ if( m_pLinkMgr )
+ {
+ SvLinkSourceRef ref = sfx2::LinkManager::CreateObj( this );
+ if( ref.is() )
+ {
+ ref->Edit( pParent, this, aLink );
+ bAsync = true;
+ }
+ }
+ }
+ else
+ {
+ xObj->Edit( pParent, this, aLink );
+ bAsync = true;
+ }
+
+ if ( !bAsync )
+ {
+ ExecuteEdit( OUString() );
+ bWasLastEditOK = false;
+ m_aEndEditLink.Call( *this );
+ }
+}
+
+bool SvBaseLink::ExecuteEdit( const OUString& _rNewName )
+{
+ if( !_rNewName.isEmpty() )
+ {
+ SetLinkSourceName( _rNewName );
+ if( !Update() )
+ {
+ OUString sApp, sTopic, sItem, sError;
+ sfx2::LinkManager::GetDisplayNames( this, &sApp, &sTopic, &sItem );
+ if( mnObjType == SvBaseLinkObjectType::ClientDde )
+ {
+ sError = SfxResId(STR_DDE_ERROR);
+
+ sal_Int32 nFndPos = sError.indexOf( "%1" );
+ if( -1 != nFndPos )
+ {
+ sError = sError.replaceAt( nFndPos, 2, sApp );
+ nFndPos = nFndPos + sApp.getLength();
+
+ if( -1 != ( nFndPos = sError.indexOf( "%2", nFndPos )))
+ {
+ sError = sError.replaceAt( nFndPos, 2, sTopic );
+ nFndPos = nFndPos + sTopic.getLength();
+
+ if( -1 != ( nFndPos = sError.indexOf( "%3", nFndPos )))
+ sError = sError.replaceAt( nFndPos, 2, sItem );
+ }
+ }
+ }
+ else
+ return false;
+
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_pParentWin,
+ VclMessageType::Warning, VclButtonsType::Ok, sError));
+ xBox->run();
+ }
+ }
+ else if( !m_bIsConnect )
+ Disconnect();
+ m_bIsConnect = false;
+ return true;
+}
+
+void SvBaseLink::Closed()
+{
+ if( xObj.is() )
+ xObj->RemoveAllDataAdvise( this );
+}
+
+FileDialogHelper & SvBaseLink::GetInsertFileDialog(const OUString& rFactory)
+{
+ m_pFileDlg.reset( new FileDialogHelper(
+ ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
+ FileDialogFlags::Insert, rFactory, SfxFilterFlags::NONE, SfxFilterFlags::NONE, m_pParentWin) );
+ return *m_pFileDlg;
+}
+
+ImplDdeItem::~ImplDdeItem()
+{
+ bIsInDTOR = true;
+ // So that no-one gets the idea to delete the pointer when Disconnecting!
+ tools::SvRef<SvBaseLink> aRef( pLink );
+ aRef->Disconnect();
+}
+
+DdeData* ImplDdeItem::Get( SotClipboardFormatId nFormat )
+{
+ if( pLink->GetObj() )
+ {
+ // is it still valid?
+ if( bIsValidData && nFormat == aData.GetFormat() )
+ return &aData;
+
+ Any aValue;
+ OUString sMimeType( SotExchange::GetFormatMimeType( nFormat ));
+ if( pLink->GetObj()->GetData( aValue, sMimeType ) )
+ {
+ if( aValue >>= aSeq )
+ {
+ aData = DdeData( aSeq.getConstArray(), aSeq.getLength(), nFormat );
+
+ bIsValidData = true;
+ return &aData;
+ }
+ }
+ }
+ aSeq.realloc( 0 );
+ bIsValidData = false;
+ return nullptr;
+}
+
+
+bool ImplDdeItem::Put( const DdeData* )
+{
+ OSL_FAIL( "ImplDdeItem::Put not implemented" );
+ return false;
+}
+
+
+void ImplDdeItem::AdviseLoop( bool bOpen )
+{
+ // Connection is closed, so also unsubscribe link
+ if( !pLink->GetObj() )
+ return;
+
+ if( bOpen )
+ {
+ // A connection is re-established
+ if( SvBaseLinkObjectType::DdeExternal == pLink->GetObjType() )
+ {
+ pLink->GetObj()->AddDataAdvise( pLink, "text/plain;charset=utf-16", ADVISEMODE_NODATA );
+ pLink->GetObj()->AddConnectAdvise( pLink );
+ }
+ }
+ else
+ {
+ // So that no-one gets the idea to delete the pointer
+ // when Disconnecting!
+ tools::SvRef<SvBaseLink> aRef( pLink );
+ aRef->Disconnect();
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/macroloader.cxx b/sfx2/source/appl/macroloader.cxx
new file mode 100644
index 0000000000..da9f83a2b7
--- /dev/null
+++ b/sfx2/source/appl/macroloader.cxx
@@ -0,0 +1,344 @@
+/* -*- 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 <config_features.h>
+
+#include <macroloader.hxx>
+
+#include <com/sun/star/frame/DispatchResultState.hpp>
+#include <basic/basmgr.hxx>
+#include <basic/sbuno.hxx>
+#include <basic/sberrors.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <framework/documentundoguard.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/objsh.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/svapp.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+
+SfxMacroLoader::SfxMacroLoader(const css::uno::Sequence< css::uno::Any >& aArguments)
+{
+ Reference < XFrame > xFrame;
+ if ( aArguments.hasElements() )
+ {
+ aArguments[0] >>= xFrame;
+ m_xFrame = xFrame;
+ }
+}
+
+OUString SAL_CALL SfxMacroLoader::getImplementationName()
+{
+ return "com.sun.star.comp.sfx2.SfxMacroLoader";
+}
+
+sal_Bool SAL_CALL SfxMacroLoader::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> SAL_CALL SfxMacroLoader::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ProtocolHandler" };
+}
+
+SfxObjectShell* SfxMacroLoader::GetObjectShell(const Reference <XFrame>& xFrame)
+{
+ SfxObjectShell* pDocShell = nullptr;
+
+ if ( xFrame.is() )
+ {
+ SfxFrame* pFrame=nullptr;
+ for ( pFrame = SfxFrame::GetFirst(); pFrame; pFrame = SfxFrame::GetNext( *pFrame ) )
+ {
+ if ( pFrame->GetFrameInterface() == xFrame )
+ break;
+ }
+
+ if ( pFrame )
+ pDocShell = pFrame->GetCurrentDocument();
+ }
+
+ return pDocShell;
+}
+
+SfxObjectShell* SfxMacroLoader::GetObjectShell_Impl()
+{
+ Reference < XFrame > xFrame( m_xFrame.get(), UNO_QUERY );
+ return SfxMacroLoader::GetObjectShell(xFrame);
+}
+
+uno::Reference<frame::XDispatch> SAL_CALL SfxMacroLoader::queryDispatch(
+ const util::URL& aURL ,
+ const OUString& /*sTargetFrameName*/,
+ sal_Int32 /*nSearchFlags*/ )
+{
+ uno::Reference<frame::XDispatch> xDispatcher;
+ if(aURL.Complete.startsWith("macro:"))
+ xDispatcher = this;
+ return xDispatcher;
+}
+
+
+uno::Sequence< uno::Reference<frame::XDispatch> > SAL_CALL
+ SfxMacroLoader::queryDispatches( const uno::Sequence < frame::DispatchDescriptor >& seqDescriptor )
+{
+ sal_Int32 nCount = seqDescriptor.getLength();
+ uno::Sequence< uno::Reference<frame::XDispatch> > lDispatcher(nCount);
+ std::transform(seqDescriptor.begin(), seqDescriptor.end(), lDispatcher.getArray(),
+ [this](const frame::DispatchDescriptor& rDescr) -> uno::Reference<frame::XDispatch> {
+ return queryDispatch(rDescr.FeatureURL, rDescr.FrameName, rDescr.SearchFlags); });
+ return lDispatcher;
+}
+
+
+void SAL_CALL SfxMacroLoader::dispatchWithNotification(
+ const util::URL& aURL, const uno::Sequence<beans::PropertyValue>& /*lArgs*/,
+ const uno::Reference<frame::XDispatchResultListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aAny;
+ ErrCode nErr = loadMacro( aURL.Complete, aAny, GetObjectShell_Impl() );
+ if( !xListener.is() )
+ return;
+
+ // always call dispatchFinished(), because we didn't load a document but
+ // executed a macro instead!
+ frame::DispatchResultEvent aEvent;
+
+ aEvent.Source = getXWeak();
+ if( nErr == ERRCODE_NONE )
+ aEvent.State = frame::DispatchResultState::SUCCESS;
+ else
+ aEvent.State = frame::DispatchResultState::FAILURE;
+
+ xListener->dispatchFinished( aEvent ) ;
+}
+
+uno::Any SAL_CALL SfxMacroLoader::dispatchWithReturnValue(
+ const util::URL& aURL, const uno::Sequence<beans::PropertyValue>& )
+{
+ uno::Any aRet;
+ ErrCode nErr = loadMacro( aURL.Complete, aRet, GetObjectShell_Impl() );
+
+ // aRet gets set to a different value only if nErr == ERRCODE_NONE
+ // Return it in such case to preserve the original behaviour
+
+ // In all other cases (nErr != ERRCODE_NONE), the calling code gets
+ // the actual error code back
+ if ( nErr != ERRCODE_NONE )
+ {
+ beans::PropertyValue aErrorCode;
+
+ aErrorCode.Name = "ErrorCode";
+ aErrorCode.Value <<= sal_uInt32(nErr);
+
+ aRet <<= aErrorCode;
+ }
+
+ return aRet;
+}
+
+void SAL_CALL SfxMacroLoader::dispatch(
+ const util::URL& aURL, const uno::Sequence<beans::PropertyValue>& /*lArgs*/ )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aAny;
+ loadMacro( aURL.Complete, aAny, GetObjectShell_Impl() );
+}
+
+void SAL_CALL SfxMacroLoader::addStatusListener(
+ const uno::Reference< frame::XStatusListener >& ,
+ const util::URL& )
+{
+ /* TODO
+ How we can handle different listener for further coming or currently running dispatch() jobs
+ without any inconsistency!
+ */
+}
+
+
+void SAL_CALL SfxMacroLoader::removeStatusListener(
+ const uno::Reference< frame::XStatusListener >&,
+ const util::URL& )
+{
+}
+
+ErrCode SfxMacroLoader::loadMacro( const OUString& rURL, css::uno::Any& rRetval, SfxObjectShell* pSh )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) rURL;
+ (void) rRetval;
+ (void) pSh;
+ return ERRCODE_BASIC_PROC_UNDEFINED;
+#else
+ SfxObjectShell* pCurrent = pSh;
+ if ( !pCurrent )
+ // all not full qualified names use the BASIC of the given or current document
+ pCurrent = SfxObjectShell::Current();
+
+ // 'macro:///lib.mod.proc(args)' => macro of App-BASIC
+ // 'macro://[docname|.]/lib.mod.proc(args)' => macro of current or qualified document
+ // 'macro://obj.method(args)' => direct API call, execute it via App-BASIC
+ const OUString& aMacro( rURL );
+ sal_Int32 nThirdSlashPos = aMacro.indexOf( '/', 8 );
+ sal_Int32 nArgsPos = aMacro.indexOf( '(' );
+ BasicManager *pAppMgr = SfxApplication::GetBasicManager();
+ BasicManager *pBasMgr = nullptr;
+ ErrCode nErr = ERRCODE_NONE;
+
+ // should a macro function be executed ( no direct API call)?
+ if ( -1 != nThirdSlashPos && ( -1 == nArgsPos || nThirdSlashPos < nArgsPos ) )
+ {
+ // find BasicManager
+ SfxObjectShell* pDoc = nullptr;
+ OUString aBasMgrName( INetURLObject::decode(aMacro.subView( 8, nThirdSlashPos-8 ), INetURLObject::DecodeMechanism::WithCharset) );
+ if ( aBasMgrName.isEmpty() )
+ pBasMgr = pAppMgr;
+ else if ( aBasMgrName == "." )
+ {
+ // current/actual document
+ pDoc = pCurrent;
+ if (pDoc)
+ pBasMgr = pDoc->GetBasicManager();
+ }
+ else
+ {
+ // full qualified name, find document by name
+ for ( SfxObjectShell *pObjSh = SfxObjectShell::GetFirst();
+ pObjSh && !pBasMgr;
+ pObjSh = SfxObjectShell::GetNext(*pObjSh) )
+ if ( aBasMgrName == pObjSh->GetTitle(SFX_TITLE_APINAME) )
+ {
+ pDoc = pObjSh;
+ pBasMgr = pDoc->GetBasicManager();
+ }
+ }
+
+ if ( pBasMgr )
+ {
+ const bool bIsAppBasic = ( pBasMgr == pAppMgr );
+ const bool bIsDocBasic = ( pBasMgr != pAppMgr );
+
+ if ( pDoc )
+ {
+ // security check for macros from document basic if an SFX doc is given
+ if ( !pDoc->AdjustMacroMode() )
+ // check forbids execution
+ return ERRCODE_IO_ACCESSDENIED;
+ }
+
+ // find BASIC method
+ OUString aQualifiedMethod( INetURLObject::decode(aMacro.subView( nThirdSlashPos+1 ), INetURLObject::DecodeMechanism::WithCharset) );
+ OUString aArgs;
+ if ( -1 != nArgsPos )
+ {
+ // remove arguments from macro name
+ aArgs = aQualifiedMethod.copy( nArgsPos - nThirdSlashPos - 1 );
+ aQualifiedMethod = aQualifiedMethod.copy( 0, nArgsPos - nThirdSlashPos - 1 );
+ }
+
+ if ( pBasMgr->HasMacro( aQualifiedMethod ) )
+ {
+ Any aOldThisComponent;
+ const bool bSetDocMacroMode = ( pDoc != nullptr ) && bIsDocBasic;
+ const bool bSetGlobalThisComponent = ( pDoc != nullptr ) && bIsAppBasic;
+ if ( bSetDocMacroMode )
+ {
+ // mark document: it executes an own macro, so it's in a modal mode
+ pDoc->SetMacroMode_Impl();
+ }
+
+ if ( bSetGlobalThisComponent )
+ {
+ // document is executed via AppBASIC, adjust ThisComponent variable
+ pAppMgr->SetGlobalUNOConstant( "ThisComponent", Any( pDoc->GetModel() ), &aOldThisComponent );
+ }
+
+ // just to let the shell be alive
+ SfxObjectShellRef xKeepDocAlive = pDoc;
+
+ {
+ // attempt to protect the document against the script tampering with its Undo Context
+ std::optional< ::framework::DocumentUndoGuard > pUndoGuard;
+ if ( bIsDocBasic )
+ pUndoGuard.emplace( pDoc->GetModel() );
+
+ // execute the method
+ SbxVariableRef retValRef = new SbxVariable;
+ nErr = pBasMgr->ExecuteMacro( aQualifiedMethod, aArgs, retValRef.get() );
+ if ( nErr == ERRCODE_NONE )
+ rRetval = sbxToUnoValue( retValRef.get() );
+ }
+
+ if ( bSetGlobalThisComponent )
+ {
+ pAppMgr->SetGlobalUNOConstant( "ThisComponent", aOldThisComponent );
+ }
+
+ if ( bSetDocMacroMode )
+ {
+ // remove flag for modal mode
+ pDoc->SetMacroMode_Impl( false );
+ }
+ }
+ else
+ nErr = ERRCODE_BASIC_PROC_UNDEFINED;
+ }
+ else
+ nErr = ERRCODE_IO_NOTEXISTS;
+ }
+ else
+ {
+ // direct API call on a specified object
+ OUString aCall =
+ "[" +
+ INetURLObject::decode(aMacro.subView(6),
+ INetURLObject::DecodeMechanism::WithCharset) +
+ "]";
+ pAppMgr->GetLib(0)->Execute(aCall);
+ nErr = SbxBase::GetError();
+ }
+
+ SbxBase::ResetError();
+ return nErr;
+#endif
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_sfx2_SfxMacroLoader_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &arguments)
+{
+ return cppu::acquire(new SfxMacroLoader(arguments));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/module.cxx b/sfx2/source/appl/module.cxx
new file mode 100644
index 0000000000..03f4fc2fa8
--- /dev/null
+++ b/sfx2/source/appl/module.cxx
@@ -0,0 +1,267 @@
+/* -*- 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 <sfx2/module.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/msgpool.hxx>
+#include <sfx2/tbxctrl.hxx>
+#include <sfx2/stbitem.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/docfac.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/tabdlg.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svl/intitem.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <unotools/resmgr.hxx>
+#include <sal/log.hxx>
+
+#define ShellClass_SfxModule
+#include <sfxslots.hxx>
+#include <optional>
+
+class SfxModule_Impl
+{
+public:
+
+ std::optional<SfxSlotPool> pSlotPool;
+ std::vector<SfxTbxCtrlFactory> maTbxCtrlFactories;
+ std::vector<SfxStbCtrlFactory> maStbCtrlFactories;
+ std::vector<SfxChildWinFactory> maFactories;
+ OString maResName;
+
+ SfxModule_Impl();
+ ~SfxModule_Impl();
+};
+
+SfxModule_Impl::SfxModule_Impl()
+{
+}
+
+SfxModule_Impl::~SfxModule_Impl()
+{
+ pSlotPool.reset();
+ maTbxCtrlFactories.clear();
+ maStbCtrlFactories.clear();
+}
+
+SFX_IMPL_SUPERCLASS_INTERFACE(SfxModule, SfxShell)
+
+SfxModule::SfxModule(const OString& rResName, std::initializer_list<SfxObjectFactory*> pFactoryList)
+ : pImpl(nullptr)
+{
+ Construct_Impl(rResName);
+ for (auto pFactory : pFactoryList)
+ {
+ if (pFactory)
+ pFactory->SetModule_Impl( this );
+ }
+}
+
+void SfxModule::Construct_Impl(const OString& rResName)
+{
+ SfxApplication *pApp = SfxApplication::GetOrCreate();
+ pImpl = new SfxModule_Impl;
+ pImpl->pSlotPool.emplace(&pApp->GetAppSlotPool_Impl());
+ pImpl->maResName = rResName;
+
+ SetPool( &pApp->GetPool() );
+}
+
+SfxModule::~SfxModule()
+{
+ //TODO how to silence useuniqueptr
+ if (true)
+ {
+ delete pImpl;
+ }
+}
+
+std::locale SfxModule::GetResLocale() const
+{
+ return Translate::Create(pImpl->maResName);
+}
+
+SfxSlotPool* SfxModule::GetSlotPool() const
+{
+ return &*pImpl->pSlotPool;
+}
+
+
+void SfxModule::RegisterChildWindow(const SfxChildWinFactory& rFact)
+{
+ DBG_ASSERT( pImpl, "No real Module!" );
+
+ for (size_t nFactory=0; nFactory<pImpl->maFactories.size(); ++nFactory)
+ {
+ if (rFact.nId == pImpl->maFactories[nFactory].nId)
+ {
+ pImpl->maFactories.erase( pImpl->maFactories.begin() + nFactory );
+ SAL_WARN("sfx.appl", "ChildWindow registered multiple times!");
+ return;
+ }
+ }
+
+ pImpl->maFactories.push_back( rFact );
+}
+
+
+void SfxModule::RegisterToolBoxControl( const SfxTbxCtrlFactory& rFact )
+{
+#ifdef DBG_UTIL
+ for ( size_t n=0; n<pImpl->maTbxCtrlFactories.size(); n++ )
+ {
+ SfxTbxCtrlFactory *pF = &pImpl->maTbxCtrlFactories[n];
+ if ( pF->nTypeId == rFact.nTypeId &&
+ (pF->nSlotId == rFact.nSlotId || pF->nSlotId == 0) )
+ {
+ SAL_INFO("sfx.appl", "TbxController-Registering is not clearly defined!");
+ }
+ }
+#endif
+
+ pImpl->maTbxCtrlFactories.push_back( rFact );
+}
+
+
+void SfxModule::RegisterStatusBarControl( const SfxStbCtrlFactory& rFact )
+{
+#ifdef DBG_UTIL
+ for ( size_t n=0; n<pImpl->maStbCtrlFactories.size(); n++ )
+ {
+ SfxStbCtrlFactory *pF = &pImpl->maStbCtrlFactories[n];
+ if ( pF->nTypeId == rFact.nTypeId &&
+ (pF->nSlotId == rFact.nSlotId || pF->nSlotId == 0) )
+ {
+ SAL_INFO("sfx.appl", "TbxController-Registering is not clearly defined!");
+ }
+ }
+#endif
+
+ pImpl->maStbCtrlFactories.push_back( rFact );
+}
+
+
+SfxTbxCtrlFactory* SfxModule::GetTbxCtrlFactory(const std::type_info& rSlotType, sal_uInt16 nSlotID) const
+{
+ // search for a factory with the given slot id
+ for (auto& rFactory : pImpl->maTbxCtrlFactories)
+ if( rFactory.nTypeId == rSlotType && rFactory.nSlotId == nSlotID )
+ return &rFactory;
+
+ // if no factory exists for the given slot id, see if we
+ // have a generic factory with the correct slot type and slot id == 0
+ for (auto& rFactory : pImpl->maTbxCtrlFactories)
+ if( rFactory.nTypeId == rSlotType && rFactory.nSlotId == 0 )
+ return &rFactory;
+
+ return nullptr;
+}
+
+
+SfxStbCtrlFactory* SfxModule::GetStbCtrlFactory(const std::type_info& rSlotType, sal_uInt16 nSlotID) const
+{
+ for (auto& rFactory : pImpl->maStbCtrlFactories)
+ if ( rFactory.nTypeId == rSlotType &&
+ ( rFactory.nSlotId == 0 || rFactory.nSlotId == nSlotID ) )
+ return &rFactory;
+ return nullptr;
+}
+
+SfxChildWinFactory* SfxModule::GetChildWinFactoryById(sal_uInt16 nId) const
+{
+ for (auto& rFactory : pImpl->maFactories)
+ if (rFactory.nId == nId)
+ return &rFactory;
+ return nullptr;
+}
+
+std::unique_ptr<SfxTabPage> SfxModule::CreateTabPage(sal_uInt16, weld::Container*, weld::DialogController*, const SfxItemSet&)
+{
+ return nullptr;
+}
+
+void SfxModule::Invalidate( sal_uInt16 nId )
+{
+ for( SfxViewFrame* pFrame = SfxViewFrame::GetFirst(); pFrame; pFrame = SfxViewFrame::GetNext( *pFrame ) )
+ if ( pFrame->GetObjectShell()->GetModule() == this )
+ Invalidate_Impl( pFrame->GetBindings(), nId );
+}
+
+SfxModule* SfxModule::GetActiveModule( SfxViewFrame* pFrame )
+{
+ if ( !pFrame )
+ pFrame = SfxViewFrame::Current();
+ SfxObjectShell* pSh = nullptr;
+ if( pFrame )
+ pSh = pFrame->GetObjectShell();
+ return pSh ? pSh->GetModule() : nullptr;
+}
+
+FieldUnit SfxModule::GetModuleFieldUnit( css::uno::Reference< css::frame::XFrame > const & i_frame )
+{
+ ENSURE_OR_RETURN( i_frame.is(), "SfxModule::GetModuleFieldUnit: invalid frame!", FieldUnit::MM_100TH );
+
+ // find SfxViewFrame for the given XFrame
+ SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst();
+ while ( pViewFrame != nullptr )
+ {
+ if ( pViewFrame->GetFrame().GetFrameInterface() == i_frame )
+ break;
+ pViewFrame = SfxViewFrame::GetNext( *pViewFrame );
+ }
+ ENSURE_OR_RETURN(
+ pViewFrame != nullptr,
+ "SfxModule::GetModuleFieldUnit: unable to find an SfxViewFrame for the given XFrame",
+ FieldUnit::MM_100TH);
+
+ // find the module
+ SfxModule const * pModule = GetActiveModule( pViewFrame );
+ ENSURE_OR_RETURN(pModule != nullptr,
+ "SfxModule::GetModuleFieldUnit: no SfxModule for the given frame!",
+ FieldUnit::MM_100TH);
+ return pModule->GetFieldUnit();
+}
+
+FieldUnit SfxModule::GetCurrentFieldUnit()
+{
+ FieldUnit eUnit = FieldUnit::INCH;
+ SfxModule* pModule = GetActiveModule();
+ if ( pModule )
+ {
+ const SfxPoolItem* pItem = pModule->GetItem( SID_ATTR_METRIC );
+ if ( pItem )
+ eUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(pItem)->GetValue());
+ }
+ else
+ SAL_WARN( "sfx.appl", "GetModuleFieldUnit(): no module found" );
+ return eUnit;
+}
+
+FieldUnit SfxModule::GetFieldUnit() const
+{
+ FieldUnit eUnit = FieldUnit::INCH;
+ const SfxPoolItem* pItem = GetItem( SID_ATTR_METRIC );
+ if ( pItem )
+ eUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(pItem)->GetValue());
+ return eUnit;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/newhelp.cxx b/sfx2/source/appl/newhelp.cxx
new file mode 100644
index 0000000000..7e51602371
--- /dev/null
+++ b/sfx2/source/appl/newhelp.cxx
@@ -0,0 +1,2666 @@
+/* -*- 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 "newhelp.hxx"
+#include <sfx2/sfxresid.hxx>
+#include "helpinterceptor.hxx"
+#include <helper.hxx>
+#include <srchdlg.hxx>
+#include <sfx2/sfxhelp.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <sfx2/strings.hrc>
+#include <helpids.h>
+#include <bitmaps.hlst>
+
+#include <rtl/ustrbuf.hxx>
+#include <comphelper/configurationhelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/frame/XComponentLoader.hpp>
+#include <com/sun/star/frame/XTitle.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/Frame.hpp>
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextCursor.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextViewCursor.hpp>
+#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
+#include <com/sun/star/ucb/CommandAbortedException.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <com/sun/star/util/XSearchable.hpp>
+#include <com/sun/star/util/XSearchDescriptor.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/view/XViewSettingsSupplier.hpp>
+#include <unotools/historyoptions.hxx>
+#include <unotools/viewoptions.hxx>
+#include <tools/urlobj.hxx>
+#include <svtools/imagemgr.hxx>
+#include <svtools/miscopt.hxx>
+#include <utility>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/i18nhelp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/unohelp.hxx>
+#include <vcl/weld.hxx>
+
+#include <ucbhelper/content.hxx>
+#include <unotools/ucbhelper.hxx>
+
+#include <string_view>
+#include <unordered_map>
+#include <vector>
+
+using namespace ::ucbhelper;
+using namespace ::com::sun::star::ucb;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::ui;
+
+using namespace ::comphelper;
+
+// defines ---------------------------------------------------------------
+
+constexpr OUString CONFIGNAME_HELPWIN = u"OfficeHelp"_ustr;
+constexpr OUString CONFIGNAME_INDEXWIN = u"OfficeHelpIndex"_ustr;
+constexpr OUString CONFIGNAME_SEARCHPAGE = u"OfficeHelpSearch"_ustr;
+constexpr OUString IMAGE_URL = u"private:factory/"_ustr;
+
+constexpr OUString PROPERTY_KEYWORDLIST = u"KeywordList"_ustr;
+constexpr OUString PROPERTY_KEYWORDREF = u"KeywordRef"_ustr;
+constexpr OUString PROPERTY_ANCHORREF = u"KeywordAnchorForRef"_ustr;
+constexpr OUString PROPERTY_TITLEREF = u"KeywordTitleForRef"_ustr;
+constexpr OUString PROPERTY_TITLE = u"Title"_ustr;
+constexpr OUString HELP_URL = u"vnd.sun.star.help://"_ustr;
+constexpr OUStringLiteral HELP_SEARCH_TAG = u"/?Query=";
+constexpr OUString USERITEM_NAME = u"UserItem"_ustr;
+
+constexpr OUStringLiteral PACKAGE_SETUP = u"/org.openoffice.Setup";
+constexpr OUString PATH_OFFICE_FACTORIES = u"Office/Factories/"_ustr;
+constexpr OUString KEY_HELP_ON_OPEN = u"ooSetupFactoryHelpOnOpen"_ustr;
+constexpr OUStringLiteral KEY_UI_NAME = u"ooSetupFactoryUIName";
+
+namespace sfx2
+{
+
+
+ /** Prepare a search string for searching or selecting.
+ For searching every search word needs the postfix '*' and the delimiter ' ' if necessary.
+ For selecting the delimiter '|' is required to search with regular expressions.
+ Samples:
+ search string | output for searching | output for selecting
+ -----------------------------------------------------------
+ "text" | "text*" | "text"
+ "text*" | "text*" | "text"
+ "text menu" | "text* menu*" | "text|menu"
+ */
+ static OUString PrepareSearchString( const OUString& rSearchString,
+ const Reference< XBreakIterator >& xBreak, bool bForSearch )
+ {
+ OUStringBuffer sSearchStr;
+ sal_Int32 nStartPos = 0;
+ const lang::Locale aLocale = Application::GetSettings().GetUILanguageTag().getLocale();
+ Boundary aBoundary = xBreak->getWordBoundary(
+ rSearchString, nStartPos, aLocale, WordType::ANYWORD_IGNOREWHITESPACES, true );
+
+ while ( aBoundary.startPos < aBoundary.endPos )
+ {
+ nStartPos = aBoundary.endPos;
+ OUString sSearchToken( rSearchString.copy(
+ static_cast<sal_uInt16>(aBoundary.startPos), static_cast<sal_uInt16>(aBoundary.endPos) - static_cast<sal_uInt16>(aBoundary.startPos) ) );
+ if ( !sSearchToken.isEmpty() && ( sSearchToken.getLength() > 1 || sSearchToken[0] != '.' ) )
+ {
+ if ( bForSearch && sSearchToken[ sSearchToken.getLength() - 1 ] != '*' )
+ sSearchToken += "*";
+
+ if ( sSearchToken.getLength() > 1 ||
+ ( sSearchToken.getLength() > 0 && sSearchToken[ 0 ] != '*' ) )
+ {
+ if ( !sSearchStr.isEmpty() )
+ {
+ if ( bForSearch )
+ sSearchStr.append(" ");
+ else
+ sSearchStr.append("|");
+ }
+ sSearchStr.append(sSearchToken);
+ }
+ }
+ aBoundary = xBreak->nextWord( rSearchString, nStartPos,
+ aLocale, WordType::ANYWORD_IGNOREWHITESPACES );
+ }
+
+ return sSearchStr.makeStringAndClear();
+ }
+
+// namespace sfx2
+}
+
+
+// struct IndexEntry_Impl ------------------------------------------------
+
+namespace {
+
+struct IndexEntry_Impl
+{
+ bool m_bSubEntry;
+ OUString m_aURL;
+
+ IndexEntry_Impl( OUString aURL, bool bSubEntry ) :
+ m_bSubEntry( bSubEntry ), m_aURL(std::move( aURL )) {}
+};
+
+// struct ContentEntry_Impl ----------------------------------------------
+
+struct ContentEntry_Impl
+{
+ OUString aURL;
+ bool bIsFolder;
+
+ ContentEntry_Impl( OUString _aURL, bool bFolder ) :
+ aURL(std::move( _aURL )), bIsFolder( bFolder ) {}
+};
+
+}
+
+void ContentTabPage_Impl::InitRoot()
+{
+ std::vector< OUString > aList =
+ SfxContentHelper::GetHelpTreeViewContents( "vnd.sun.star.hier://com.sun.star.help.TreeView/" );
+
+ for (const OUString & aRow : aList)
+ {
+ sal_Int32 nIdx = 0;
+ OUString aTitle = aRow.getToken( 0, '\t', nIdx );
+ OUString aURL = aRow.getToken( 0, '\t', nIdx );
+ sal_Unicode cFolder = o3tl::getToken(aRow, 0, '\t', nIdx )[0];
+ bool bIsFolder = ( '1' == cFolder );
+ OUString sId;
+ if (bIsFolder)
+ sId = weld::toId(new ContentEntry_Impl(aURL, true));
+ m_xContentBox->insert(nullptr, -1, &aTitle, &sId, nullptr, nullptr, true, m_xScratchIter.get());
+ m_xContentBox->set_image(*m_xScratchIter, aClosedBookImage);
+ }
+}
+
+void ContentTabPage_Impl::ClearChildren(const weld::TreeIter* pParent)
+{
+ std::unique_ptr<weld::TreeIter> xEntry = m_xContentBox->make_iterator(pParent);
+ bool bEntry = m_xContentBox->iter_children(*xEntry);
+ while (bEntry)
+ {
+ ClearChildren(xEntry.get());
+ delete weld::fromId<ContentEntry_Impl*>(m_xContentBox->get_id(*xEntry));
+ bEntry = m_xContentBox->iter_next_sibling(*xEntry);
+ }
+
+}
+
+IMPL_LINK(ContentTabPage_Impl, ExpandingHdl, const weld::TreeIter&, rIter, bool)
+{
+ ContentEntry_Impl* pContentEntry = weld::fromId<ContentEntry_Impl*>(m_xContentBox->get_id(rIter));
+ if (!m_xContentBox->iter_has_child(rIter))
+ {
+ try
+ {
+ if (pContentEntry)
+ {
+ std::vector<OUString > aList = SfxContentHelper::GetHelpTreeViewContents(pContentEntry->aURL);
+
+ for (const OUString & aRow : aList)
+ {
+ sal_Int32 nIdx = 0;
+ OUString aTitle = aRow.getToken( 0, '\t', nIdx );
+ OUString aURL = aRow.getToken( 0, '\t', nIdx );
+ sal_Unicode cFolder = o3tl::getToken(aRow, 0, '\t', nIdx )[0];
+ bool bIsFolder = ( '1' == cFolder );
+ if ( bIsFolder )
+ {
+ OUString sId = weld::toId(new ContentEntry_Impl(aURL, true));
+ m_xContentBox->insert(&rIter, -1, &aTitle, &sId, nullptr, nullptr, true, m_xScratchIter.get());
+ m_xContentBox->set_image(*m_xScratchIter, aClosedBookImage);
+ }
+ else
+ {
+ Any aAny( ::utl::UCBContentHelper::GetProperty( aURL, "TargetURL" ) );
+ OUString sId;
+ OUString aTargetURL;
+ if ( aAny >>= aTargetURL )
+ sId = weld::toId(new ContentEntry_Impl(aTargetURL, false));
+ m_xContentBox->insert(&rIter, -1, &aTitle, &sId, nullptr, nullptr, false, m_xScratchIter.get());
+ m_xContentBox->set_image(*m_xScratchIter, aDocumentImage);
+ }
+ }
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "ContentListBox_Impl::RequestingChildren(): unexpected exception" );
+ }
+ }
+
+ if (!pContentEntry || pContentEntry->bIsFolder)
+ m_xContentBox->set_image(rIter, aOpenBookImage);
+
+ return true;
+}
+
+IMPL_LINK(ContentTabPage_Impl, CollapsingHdl, const weld::TreeIter&, rIter, bool)
+{
+ ContentEntry_Impl* pContentEntry = weld::fromId<ContentEntry_Impl*>(m_xContentBox->get_id(rIter));
+ if (!pContentEntry || pContentEntry->bIsFolder)
+ m_xContentBox->set_image(rIter, aClosedBookImage);
+
+ return true;
+}
+
+OUString ContentTabPage_Impl::GetSelectedEntry() const
+{
+ OUString aRet;
+ ContentEntry_Impl* pEntry = weld::fromId<ContentEntry_Impl*>(m_xContentBox->get_selected_id());
+ if (pEntry && !pEntry->bIsFolder)
+ aRet = pEntry->aURL;
+ return aRet;
+}
+
+// class HelpTabPage_Impl ------------------------------------------------
+HelpTabPage_Impl::HelpTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin,
+ const OUString& rID, const OUString& rUIXMLDescription)
+ : BuilderPage(pParent, nullptr, rUIXMLDescription, rID)
+ , m_pIdxWin(pIdxWin)
+{
+}
+
+HelpTabPage_Impl::~HelpTabPage_Impl()
+{
+}
+
+// class ContentTabPage_Impl ---------------------------------------------
+ContentTabPage_Impl::ContentTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin)
+ : HelpTabPage_Impl(pParent, pIdxWin, "HelpContentPage",
+ "sfx/ui/helpcontentpage.ui")
+ , m_xContentBox(m_xBuilder->weld_tree_view("content"))
+ , m_xScratchIter(m_xContentBox->make_iterator())
+ , aOpenBookImage(BMP_HELP_CONTENT_BOOK_OPEN)
+ , aClosedBookImage(BMP_HELP_CONTENT_BOOK_CLOSED)
+ , aDocumentImage(BMP_HELP_CONTENT_DOC)
+{
+ m_xContentBox->set_size_request(m_xContentBox->get_approximate_digit_width() * 30,
+ m_xContentBox->get_height_rows(20));
+ m_xContentBox->connect_row_activated(LINK(this, ContentTabPage_Impl, DoubleClickHdl));
+ m_xContentBox->connect_expanding(LINK(this, ContentTabPage_Impl, ExpandingHdl));
+ m_xContentBox->connect_collapsing(LINK(this, ContentTabPage_Impl, CollapsingHdl));
+
+ InitRoot();
+}
+
+IMPL_LINK_NOARG(ContentTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
+{
+ aDoubleClickHdl.Call(nullptr);
+ return false;
+}
+
+void ContentTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
+{
+ aDoubleClickHdl = rLink;
+}
+
+ContentTabPage_Impl::~ContentTabPage_Impl()
+{
+ std::unique_ptr<weld::TreeIter> xEntry = m_xContentBox->make_iterator();
+ bool bEntry = m_xContentBox->get_iter_first(*xEntry);
+ while (bEntry)
+ {
+ ClearChildren(xEntry.get());
+ delete weld::fromId<ContentEntry_Impl*>(m_xContentBox->get_id(*xEntry));
+ bEntry = m_xContentBox->iter_next_sibling(*xEntry);
+ }
+}
+
+void IndexTabPage_Impl::SelectExecutableEntry()
+{
+ sal_Int32 nPos = m_xIndexList->find_text(m_xIndexEntry->get_text());
+ if (nPos == -1)
+ return;
+
+ sal_Int32 nOldPos = nPos;
+ OUString aEntryText;
+ IndexEntry_Impl* pEntry = weld::fromId<IndexEntry_Impl*>(m_xIndexList->get_id(nPos));
+ sal_Int32 nCount = m_xIndexList->n_children();
+ while ( nPos < nCount && ( !pEntry || pEntry->m_aURL.isEmpty() ) )
+ {
+ pEntry = weld::fromId<IndexEntry_Impl*>(m_xIndexList->get_id(++nPos));
+ aEntryText = m_xIndexList->get_text(nPos);
+ }
+
+ if ( nOldPos != nPos )
+ m_xIndexEntry->set_text(aEntryText);
+}
+
+// class IndexTabPage_Impl -----------------------------------------------
+IndexTabPage_Impl::IndexTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin)
+ : HelpTabPage_Impl(pParent, pIdxWin, "HelpIndexPage", "sfx/ui/helpindexpage.ui")
+ , m_xIndexEntry(m_xBuilder->weld_entry("termentry"))
+ , m_xIndexList(m_xBuilder->weld_tree_view("termlist"))
+ , m_xOpenBtn(m_xBuilder->weld_button("display"))
+ , aFactoryIdle("sfx2 appl IndexTabPage_Impl Factory")
+ , aAutoCompleteIdle("sfx2 appl IndexTabPage_Impl AutoComplete")
+ , aKeywordTimer("sfx2::IndexTabPage_Impl aKeywordTimer")
+ , bIsActivated(false)
+ , nRowHeight(m_xIndexList->get_height_rows(1))
+ , nAllHeight(0)
+ , nLastCharCode(0)
+{
+ m_xIndexList->set_size_request(m_xIndexList->get_approximate_digit_width() * 30, -1);
+
+ m_xOpenBtn->connect_clicked(LINK(this, IndexTabPage_Impl, OpenHdl));
+ aFactoryIdle.SetInvokeHandler( LINK(this, IndexTabPage_Impl, IdleHdl ));
+ aAutoCompleteIdle.SetInvokeHandler( LINK(this, IndexTabPage_Impl, AutoCompleteHdl ));
+ aKeywordTimer.SetInvokeHandler( LINK( this, IndexTabPage_Impl, TimeoutHdl ) );
+ m_xIndexList->connect_row_activated(LINK(this, IndexTabPage_Impl, DoubleClickHdl));
+ m_xIndexList->connect_changed(LINK(this, IndexTabPage_Impl, TreeChangeHdl));
+ m_xIndexList->connect_custom_get_size(LINK(this, IndexTabPage_Impl, CustomGetSizeHdl));
+ m_xIndexList->connect_custom_render(LINK(this, IndexTabPage_Impl, CustomRenderHdl));
+ m_xIndexList->set_column_custom_renderer(0, true);
+ m_xIndexList->connect_size_allocate(LINK(this, IndexTabPage_Impl, ResizeHdl));
+ m_xIndexEntry->connect_key_press(LINK(this, IndexTabPage_Impl, KeyInputHdl));
+ m_xIndexEntry->connect_changed(LINK(this, IndexTabPage_Impl, EntryChangeHdl));
+ m_xIndexEntry->connect_activate(LINK(this, IndexTabPage_Impl, ActivateHdl));
+}
+
+IMPL_LINK(IndexTabPage_Impl, ResizeHdl, const Size&, rSize, void)
+{
+ nAllHeight = rSize.Height();
+}
+
+IMPL_LINK_NOARG(IndexTabPage_Impl, CustomGetSizeHdl, weld::TreeView::get_size_args, Size)
+{
+ return Size(m_xIndexList->get_size_request().Width(), nRowHeight);
+}
+
+IMPL_LINK(IndexTabPage_Impl, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
+{
+ vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
+ const ::tools::Rectangle& rRect = std::get<1>(aPayload);
+ bool bSelected = std::get<2>(aPayload);
+ const OUString& rId = std::get<3>(aPayload);
+
+ rRenderContext.Push(vcl::PushFlags::TEXTCOLOR);
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ if (bSelected)
+ rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
+ else
+ rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
+
+ Point aPos(rRect.TopLeft());
+ aPos.AdjustY((rRect.GetHeight() - rRenderContext.GetTextHeight()) / 2);
+
+ int nIndex = m_xIndexList->find_id(rId);
+ OUString aEntry(m_xIndexList->get_text(nIndex));
+
+ IndexEntry_Impl* pEntry = weld::fromId<IndexEntry_Impl*>(rId);
+ if (pEntry && pEntry->m_bSubEntry)
+ {
+ // indent sub entries
+ aPos.AdjustX(8);
+ sal_Int32 nPos = aEntry.indexOf(';');
+ rRenderContext.DrawText(aPos, (nPos !=-1) ? aEntry.copy(nPos + 1) : aEntry);
+ }
+ else
+ rRenderContext.DrawText(aPos, aEntry);
+
+ rRenderContext.Pop();
+}
+
+IMPL_LINK_NOARG(IndexTabPage_Impl, TreeChangeHdl, weld::TreeView&, void)
+{
+ m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
+}
+
+IMPL_LINK_NOARG(IndexTabPage_Impl, EntryChangeHdl, weld::Entry&, void)
+{
+ switch (nLastCharCode)
+ {
+ case css::awt::Key::DELETE_WORD_BACKWARD:
+ case css::awt::Key::DELETE_WORD_FORWARD:
+ case css::awt::Key::DELETE_TO_BEGIN_OF_LINE:
+ case css::awt::Key::DELETE_TO_END_OF_LINE:
+ case KEY_BACKSPACE:
+ case KEY_DELETE:
+ aAutoCompleteIdle.Stop();
+ break;
+ default:
+ aAutoCompleteIdle.Start();
+ break;
+ }
+}
+
+IMPL_LINK(IndexTabPage_Impl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode& rKCode = rKEvt.GetKeyCode();
+ if (rKCode.GetModifier()) // only with no modifiers held
+ return false;
+
+ sal_uInt16 nCode = rKCode.GetCode();
+
+ if (nCode == KEY_UP || nCode == KEY_PAGEUP ||
+ nCode == KEY_DOWN || nCode == KEY_PAGEDOWN)
+ {
+// disable_notify_events();
+ sal_Int32 nIndex = m_xIndexList->get_selected_index();
+ sal_Int32 nOrigIndex = nIndex;
+ sal_Int32 nCount = m_xIndexList->n_children();
+ if (nIndex == -1)
+ {
+ m_xIndexList->set_cursor(0);
+ m_xIndexList->select(0);
+ m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
+ }
+ else
+ {
+ if (nCode == KEY_UP)
+ --nIndex;
+ else if (nCode == KEY_DOWN)
+ ++nIndex;
+ else if (nCode == KEY_PAGEUP)
+ {
+ int nVisRows = nAllHeight / nRowHeight;
+ nIndex -= nVisRows;
+ }
+ else if (nCode == KEY_PAGEDOWN)
+ {
+ int nVisRows = nAllHeight / nRowHeight;
+ nIndex += nVisRows;
+ }
+
+ if (nIndex < 0)
+ nIndex = 0;
+ if (nIndex >= nCount)
+ nIndex = nCount - 1;
+
+ if (nIndex != nOrigIndex)
+ {
+ m_xIndexList->set_cursor(nIndex);
+ m_xIndexList->select(nIndex);
+ m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
+ }
+
+// m_xIndexList->grab_focus();
+// g_signal_emit_by_name(pWidget, "key-press-event", pEvent, &ret);
+// m_xIndexEntry->set_text(m_xIndexList->get_selected_text());
+// m_xIndexEntry->grab_focus();
+ }
+ m_xIndexEntry->select_region(0, -1);
+// enable_notify_events();
+// m_bTreeChange = true;
+// m_pEntry->fire_signal_changed();
+// m_bTreeChange = false;
+ return true;
+ }
+
+ nLastCharCode = nCode;
+ return false;
+}
+
+IndexTabPage_Impl::~IndexTabPage_Impl()
+{
+ ClearIndex();
+}
+
+namespace sfx2 {
+
+ typedef std::unordered_map< OUString, int > KeywordInfo;
+}
+
+void IndexTabPage_Impl::InitializeIndex()
+{
+ weld::WaitObject aWaitCursor(m_pIdxWin->GetFrameWeld());
+
+ // By now more than 256 equal entries are not allowed
+ sal_Unicode append[256];
+ for(sal_Unicode & k : append)
+ k = ' ';
+
+ sfx2::KeywordInfo aInfo;
+ m_xIndexList->freeze();
+
+ try
+ {
+ OUStringBuffer aURL(HELP_URL + sFactory);
+ AppendConfigToken(aURL, true);
+
+ Content aCnt( aURL.makeStringAndClear(), Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ css::uno::Reference< css::beans::XPropertySetInfo > xInfo = aCnt.getProperties();
+ if ( xInfo->hasPropertyByName( PROPERTY_ANCHORREF ) )
+ {
+ css::uno::Sequence< OUString > aPropSeq{ PROPERTY_KEYWORDLIST, PROPERTY_KEYWORDREF,
+ PROPERTY_ANCHORREF, PROPERTY_TITLEREF };
+
+ // abi: use one possibly remote call only
+ css::uno::Sequence< css::uno::Any > aAnySeq =
+ aCnt.getPropertyValues( aPropSeq );
+
+ css::uno::Sequence< OUString > aKeywordList;
+ css::uno::Sequence< css::uno::Sequence< OUString > > aKeywordRefList;
+ css::uno::Sequence< css::uno::Sequence< OUString > > aAnchorRefList;
+ css::uno::Sequence< css::uno::Sequence< OUString > > aTitleRefList;
+
+ if ( ( aAnySeq[0] >>= aKeywordList ) && ( aAnySeq[1] >>= aKeywordRefList ) &&
+ ( aAnySeq[2] >>= aAnchorRefList ) && ( aAnySeq[3] >>= aTitleRefList ) )
+ {
+ int ndx,tmp;
+ OUString aIndex, aTempString;
+ sfx2::KeywordInfo::iterator it;
+
+ for ( int i = 0; i < aKeywordList.getLength(); ++i )
+ {
+ // abi: Do not copy, but use references
+ const OUString& aKeywordPair = aKeywordList[i];
+ DBG_ASSERT( !aKeywordPair.isEmpty(), "invalid help index" );
+ const css::uno::Sequence< OUString >& aRefList = aKeywordRefList[i];
+ const css::uno::Sequence< OUString >& aAnchorList = aAnchorRefList[i];
+ const css::uno::Sequence< OUString >& aTitleList = aTitleRefList[i];
+
+ DBG_ASSERT( aRefList.getLength() == aAnchorList.getLength(),"reference list and title list of different length" );
+
+ ndx = aKeywordPair.indexOf( ';' );
+ const bool insert = ndx != -1;
+
+ OUString sId;
+
+ if ( insert )
+ {
+ aTempString = aKeywordPair.copy( 0, ndx );
+ if ( aIndex != aTempString )
+ {
+ aIndex = aTempString;
+ it = aInfo.emplace(aTempString, 0).first;
+ sId = weld::toId(new IndexEntry_Impl(OUString(), false));
+ if ( (tmp = it->second++) != 0)
+ m_xIndexList->append(
+ sId, aTempString + std::u16string_view(append, tmp));
+ else
+ m_xIndexList->append(sId, aTempString);
+ }
+ }
+ else
+ aIndex.clear();
+
+ sal_uInt32 nRefListLen = aRefList.getLength();
+
+ DBG_ASSERT( aAnchorList.hasElements(), "*IndexTabPage_Impl::InitializeIndex(): AnchorList is empty!" );
+ DBG_ASSERT( nRefListLen, "*IndexTabPage_Impl::InitializeIndex(): RefList is empty!" );
+
+ if ( aAnchorList.hasElements() && nRefListLen )
+ {
+ if ( aAnchorList[0].getLength() > 0 )
+ {
+ sId = weld::toId(new IndexEntry_Impl(aRefList[0] + "#" + aAnchorList[0], insert));
+ }
+ else
+ sId = weld::toId(new IndexEntry_Impl(aRefList[0], insert));
+ }
+
+ // Assume the token is trimmed
+ it = aInfo.emplace(aKeywordPair, 0).first;
+ if ((tmp = it->second++) != 0)
+ m_xIndexList->append(sId, aKeywordPair + std::u16string_view(append, tmp));
+ else
+ m_xIndexList->append(sId, aKeywordPair);
+
+ for ( sal_uInt32 j = 1; j < nRefListLen ; ++j )
+ {
+ aTempString = aKeywordPair + " - " + aTitleList[j];
+
+ if ( aAnchorList[j].getLength() > 0 )
+ sId = weld::toId(new IndexEntry_Impl(aRefList[j] + "#" + aAnchorList[j], insert));
+ else
+ sId = weld::toId(new IndexEntry_Impl(aRefList[j], insert));
+
+ it = aInfo.emplace(aTempString, 0).first;
+ if ( (tmp = it->second++) != 0 )
+ m_xIndexList->append(
+ sId, aTempString + std::u16string_view(append, tmp));
+ else
+ m_xIndexList->append(sId, aTempString);
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "IndexTabPage_Impl::InitializeIndex(): unexpected exception" );
+ }
+
+ m_xIndexList->thaw();
+
+ if ( !sKeyword.isEmpty() )
+ aKeywordLink.Call( *this );
+}
+
+void IndexTabPage_Impl::ClearIndex()
+{
+ const sal_Int32 nCount = m_xIndexList->n_children();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ delete weld::fromId<IndexEntry_Impl*>(m_xIndexList->get_id(i));
+ m_xIndexList->clear();
+}
+
+IMPL_LINK_NOARG(IndexTabPage_Impl, OpenHdl, weld::Button&, void)
+{
+ aDoubleClickHdl.Call(nullptr);
+}
+
+IMPL_LINK_NOARG(IndexTabPage_Impl, ActivateHdl, weld::Entry&, bool)
+{
+ aDoubleClickHdl.Call(nullptr);
+ return true;
+}
+
+IMPL_LINK_NOARG(IndexTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
+{
+ aDoubleClickHdl.Call(nullptr);
+ return true;
+}
+
+IMPL_LINK_NOARG(IndexTabPage_Impl, IdleHdl, Timer*, void)
+{
+ InitializeIndex();
+}
+
+int IndexTabPage_Impl::starts_with(const OUString& rStr, int nStartRow, bool bCaseSensitive)
+{
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+
+ int nRet = nStartRow;
+ int nCount = m_xIndexList->n_children();
+ while (nRet < nCount)
+ {
+ OUString aStr(m_xIndexList->get_text(nRet));
+ const bool bMatch = !bCaseSensitive ? rI18nHelper.MatchString(rStr, aStr) : aStr.startsWith(rStr);
+ if (bMatch)
+ return nRet;
+ ++nRet;
+ }
+
+ return -1;
+}
+
+IMPL_LINK_NOARG(IndexTabPage_Impl, AutoCompleteHdl, Timer*, void)
+{
+ OUString aStartText = m_xIndexEntry->get_text();
+ int nStartPos, nEndPos;
+ m_xIndexEntry->get_selection_bounds(nStartPos, nEndPos);
+ int nMaxSelection = std::max(nStartPos, nEndPos);
+ if (nMaxSelection != aStartText.getLength())
+ return;
+
+ int nActive = m_xIndexList->get_selected_index();
+ int nStart = nActive;
+
+ if (nStart == -1)
+ nStart = 0;
+
+ // Try match case insensitive from current position
+ int nPos = starts_with(aStartText, nStart, false);
+ if (nPos == -1 && nStart != 0)
+ {
+ // Try match case insensitive, but from start
+ nPos = starts_with(aStartText, 0, false);
+ }
+
+ if (nPos == -1)
+ {
+ // Try match case sensitive from current position
+ nPos = starts_with(aStartText, nStart, true);
+ if (nPos == -1 && nStart != 0)
+ {
+ // Try match case sensitive, but from start
+ nPos = starts_with(aStartText, 0, true);
+ }
+ }
+
+ if (nPos != -1)
+ {
+ m_xIndexList->set_cursor(nPos);
+ m_xIndexList->select(nPos);
+ OUString aText = m_xIndexList->get_text(nPos);
+ if (aText != aStartText)
+ m_xIndexEntry->set_text(aText);
+ m_xIndexEntry->select_region(aText.getLength(), aStartText.getLength());
+ }
+}
+
+IMPL_LINK( IndexTabPage_Impl, TimeoutHdl, Timer*, pTimer, void)
+{
+ if(&aKeywordTimer == pTimer && !sKeyword.isEmpty())
+ aKeywordLink.Call(*this);
+}
+
+void IndexTabPage_Impl::Activate()
+{
+ if ( !bIsActivated )
+ {
+ bIsActivated = true;
+ aFactoryIdle.Start();
+ }
+}
+
+void IndexTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
+{
+ aDoubleClickHdl = rLink;
+}
+
+void IndexTabPage_Impl::SetFactory( const OUString& rFactory )
+{
+ OUString sNewFactory( rFactory );
+ DBG_ASSERT( !sNewFactory.isEmpty(), "empty factory" );
+ bool bValid = m_pIdxWin->IsValidFactory( rFactory );
+
+ if ( sFactory.isEmpty() && !bValid )
+ {
+ sNewFactory = SfxHelp::GetDefaultHelpModule();
+ bValid = true;
+ }
+
+ if ( sNewFactory != sFactory && bValid )
+ {
+ sFactory = sNewFactory;
+ ClearIndex();
+ if ( bIsActivated )
+ aFactoryIdle.Start();
+ }
+}
+
+OUString IndexTabPage_Impl::GetSelectedEntry() const
+{
+ OUString aRet;
+ IndexEntry_Impl* pEntry = weld::fromId<IndexEntry_Impl*>(m_xIndexList->get_id(m_xIndexList->find_text(m_xIndexEntry->get_text())));
+ if (pEntry)
+ aRet = pEntry->m_aURL;
+ return aRet;
+}
+
+void IndexTabPage_Impl::SetKeyword( const OUString& rKeyword )
+{
+ sKeyword = rKeyword;
+
+ if (m_xIndexList->n_children() > 0)
+ aKeywordTimer.Start();
+ else if ( !bIsActivated )
+ aFactoryIdle.Start();
+}
+
+
+bool IndexTabPage_Impl::HasKeyword() const
+{
+ bool bRet = false;
+ if ( !sKeyword.isEmpty() )
+ {
+ sal_Int32 nPos = m_xIndexList->find_text( sKeyword );
+ bRet = nPos != -1;
+ }
+
+ return bRet;
+}
+
+
+bool IndexTabPage_Impl::HasKeywordIgnoreCase()
+{
+ bool bRet = false;
+ if ( !sKeyword.isEmpty() )
+ {
+ sal_Int32 nEntries = m_xIndexList->n_children();
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetLocaleI18nHelper();
+ for ( sal_Int32 n = 0; n < nEntries; n++)
+ {
+ const OUString sIndexItem {m_xIndexList->get_text(n)};
+ if (rI18nHelper.MatchString( sIndexItem, sKeyword ))
+ {
+ sKeyword = sIndexItem;
+ bRet = true;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+void IndexTabPage_Impl::OpenKeyword()
+{
+ if ( !sKeyword.isEmpty() )
+ {
+ m_xIndexEntry->set_text(sKeyword);
+ aDoubleClickHdl.Call(nullptr);
+ sKeyword.clear();
+ }
+}
+
+IMPL_LINK_NOARG(SearchTabPage_Impl, ActivateHdl, weld::ComboBox&, bool)
+{
+ Search();
+ return true;
+}
+
+// class SearchTabPage_Impl ----------------------------------------------
+
+SearchTabPage_Impl::SearchTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin)
+ : HelpTabPage_Impl(pParent, pIdxWin, "HelpSearchPage",
+ "sfx/ui/helpsearchpage.ui")
+ , m_xSearchED(m_xBuilder->weld_combo_box("search"))
+ , m_xSearchBtn(m_xBuilder->weld_button("find"))
+ , m_xFullWordsCB(m_xBuilder->weld_check_button("completewords"))
+ , m_xScopeCB(m_xBuilder->weld_check_button("headings"))
+ , m_xResultsLB(m_xBuilder->weld_tree_view("results"))
+ , m_xOpenBtn(m_xBuilder->weld_button("display"))
+ , xBreakIterator(vcl::unohelper::CreateBreakIterator())
+{
+ m_xResultsLB->set_size_request(m_xResultsLB->get_approximate_digit_width() * 30,
+ m_xResultsLB->get_height_rows(15));
+
+ m_xSearchBtn->connect_clicked(LINK(this, SearchTabPage_Impl, ClickHdl));
+ m_xSearchED->connect_changed(LINK(this, SearchTabPage_Impl, ModifyHdl));
+ m_xSearchED->connect_entry_activate(LINK(this, SearchTabPage_Impl, ActivateHdl));
+ m_xOpenBtn->connect_clicked(LINK(this, SearchTabPage_Impl, OpenHdl));
+ m_xResultsLB->connect_row_activated(LINK(this, SearchTabPage_Impl, DoubleClickHdl));
+
+ SvtViewOptions aViewOpt( EViewType::TabPage, CONFIGNAME_SEARCHPAGE );
+ if ( aViewOpt.Exists() )
+ {
+ OUString aUserData;
+ Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
+ if ( aUserItem >>= aUserData )
+ {
+ sal_Int32 nIdx {0};
+ bool bChecked = o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx)) == 1;
+ m_xFullWordsCB->set_active(bChecked);
+ bChecked = o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx)) == 1;
+ m_xScopeCB->set_active(bChecked);
+
+ while ( nIdx > 0 )
+ {
+ m_xSearchED->append_text( INetURLObject::decode(
+ o3tl::getToken(aUserData, 0, ';', nIdx),
+ INetURLObject::DecodeMechanism::WithCharset ) );
+ }
+ }
+ }
+
+ ModifyHdl(*m_xSearchED);
+}
+
+SearchTabPage_Impl::~SearchTabPage_Impl()
+{
+ SvtViewOptions aViewOpt( EViewType::TabPage, CONFIGNAME_SEARCHPAGE );
+ OUStringBuffer aUserData =
+ OUString::number(m_xFullWordsCB->get_active() ? 1 : 0) +
+ ";" +
+ OUString::number(m_xScopeCB->get_active() ? 1 : 0);
+ sal_Int32 nCount = std::min(m_xSearchED->get_count(), 10); // save only 10 entries
+
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ aUserData.append(";" +
+ INetURLObject::encode(
+ m_xSearchED->get_text(i),
+ INetURLObject::PART_UNO_PARAM_VALUE,
+ INetURLObject::EncodeMechanism::All ));
+ }
+
+ Any aUserItem( aUserData.makeStringAndClear() );
+ aViewOpt.SetUserItem( USERITEM_NAME, aUserItem );
+
+ m_xSearchED.reset();
+ m_xSearchBtn.reset();
+ m_xFullWordsCB.reset();
+ m_xScopeCB.reset();
+ m_xResultsLB.reset();
+ m_xOpenBtn.reset();
+}
+
+void SearchTabPage_Impl::ClearSearchResults()
+{
+ m_xResultsLB->clear();
+}
+
+void SearchTabPage_Impl::RememberSearchText( const OUString& rSearchText )
+{
+ for (sal_Int32 i = 0, nEntryCount = m_xSearchED->get_count(); i < nEntryCount; ++i)
+ {
+ if (rSearchText == m_xSearchED->get_text(i))
+ {
+ m_xSearchED->remove(i);
+ break;
+ }
+ }
+
+ m_xSearchED->insert_text(0, rSearchText);
+}
+
+IMPL_LINK_NOARG(SearchTabPage_Impl, ClickHdl, weld::Button&, void)
+{
+ Search();
+}
+
+void SearchTabPage_Impl::Search()
+{
+ OUString aSearchText = comphelper::string::strip(m_xSearchED->get_active_text(), ' ');
+ if ( aSearchText.isEmpty() )
+ return;
+
+ std::unique_ptr<weld::WaitObject> xWaitCursor(new weld::WaitObject(m_pIdxWin->GetFrameWeld()));
+ ClearSearchResults();
+ RememberSearchText( aSearchText );
+ OUStringBuffer aSearchURL(HELP_URL + aFactory + HELP_SEARCH_TAG);
+ if (!m_xFullWordsCB->get_active())
+ aSearchText = sfx2::PrepareSearchString( aSearchText, xBreakIterator, true );
+ aSearchURL.append(aSearchText);
+ AppendConfigToken(aSearchURL, false);
+ if (m_xScopeCB->get_active())
+ aSearchURL.append("&Scope=Heading");
+ std::vector< OUString > aFactories = SfxContentHelper::GetResultSet(aSearchURL.makeStringAndClear());
+ for (const OUString & rRow : aFactories)
+ {
+ sal_Int32 nIdx = 0;
+ OUString aTitle = rRow.getToken(0, '\t', nIdx);
+ OUString sURL(rRow.getToken(1, '\t', nIdx));
+ m_xResultsLB->append(sURL, aTitle);
+ }
+ xWaitCursor.reset();
+
+ if ( aFactories.empty() )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xContainer.get(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SfxResId(STR_INFO_NOSEARCHRESULTS)));
+ xBox->run();
+ }
+}
+
+IMPL_LINK_NOARG(SearchTabPage_Impl, OpenHdl, weld::Button&, void)
+{
+ aDoubleClickHdl.Call(nullptr);
+}
+
+IMPL_LINK(SearchTabPage_Impl, ModifyHdl, weld::ComboBox&, rComboBox, void)
+{
+ OUString aSearchText = comphelper::string::strip(m_xSearchED->get_active_text(), ' ');
+ m_xSearchBtn->set_sensitive(!aSearchText.isEmpty());
+
+ if (rComboBox.changed_by_direct_pick())
+ Search();
+}
+
+IMPL_LINK_NOARG(SearchTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
+{
+ aDoubleClickHdl.Call(nullptr);
+ return true;
+}
+
+void SearchTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
+{
+ aDoubleClickHdl = rLink;
+}
+
+OUString SearchTabPage_Impl::GetSelectedEntry() const
+{
+ return m_xResultsLB->get_selected_id();
+}
+
+void SearchTabPage_Impl::ClearPage()
+{
+ ClearSearchResults();
+ m_xSearchED->set_entry_text(OUString());
+}
+
+bool SearchTabPage_Impl::OpenKeyword( const OUString& rKeyword )
+{
+ bool bRet = false;
+ m_xSearchED->set_entry_text(rKeyword);
+ Search();
+ if (m_xResultsLB->n_children() > 0)
+ {
+ // found keyword -> open it
+ m_xResultsLB->select(0);
+ OpenHdl(*m_xOpenBtn);
+ bRet = true;
+ }
+ return bRet;
+}
+
+// class BookmarksTabPage_Impl -------------------------------------------
+
+void BookmarksTabPage_Impl::DoAction(std::u16string_view rAction)
+{
+ if (rAction == u"display")
+ aDoubleClickHdl.Call(nullptr);
+ else if (rAction == u"rename")
+ {
+ sal_Int32 nPos = m_xBookmarksBox->get_selected_index();
+ if (nPos != -1)
+ {
+ SfxAddHelpBookmarkDialog_Impl aDlg(m_xBookmarksBox.get(), true);
+ aDlg.SetTitle(m_xBookmarksBox->get_text(nPos));
+ if (aDlg.run() == RET_OK)
+ {
+ OUString sURL = m_xBookmarksBox->get_id(nPos);
+ m_xBookmarksBox->remove(nPos);
+ m_xBookmarksBox->append(sURL, aDlg.GetTitle(),
+ SvFileInformationManager::GetImageId(INetURLObject(rtl::Concat2View(IMAGE_URL+INetURLObject(sURL).GetHost()))));
+ m_xBookmarksBox->select(m_xBookmarksBox->n_children() - 1);
+ }
+ }
+ }
+ else if (rAction == u"delete")
+ {
+ sal_Int32 nPos = m_xBookmarksBox->get_selected_index();
+ if (nPos != -1)
+ {
+ m_xBookmarksBox->remove(nPos);
+ const sal_Int32 nCount = m_xBookmarksBox->n_children();
+ if (nCount)
+ {
+ if (nPos >= nCount)
+ nPos = nCount - 1;
+ m_xBookmarksBox->select(nPos);
+ }
+ }
+ }
+}
+
+IMPL_LINK(BookmarksTabPage_Impl, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xBookmarksBox.get(), "sfx/ui/bookmarkmenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu = xBuilder->weld_menu("menu");
+
+ OUString sIdent = xMenu->popup_at_rect(m_xBookmarksBox.get(), ::tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
+ if (!sIdent.isEmpty())
+ DoAction(sIdent);
+ return true;
+}
+
+IMPL_LINK(BookmarksTabPage_Impl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = false;
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+ if (KEY_DELETE == nCode && m_xBookmarksBox->n_children() > 0)
+ {
+ DoAction(u"delete");
+ bHandled = true;
+ }
+ return bHandled;
+}
+
+// class BookmarksTabPage_Impl -------------------------------------------
+BookmarksTabPage_Impl::BookmarksTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* _pIdxWin)
+ : HelpTabPage_Impl(pParent, _pIdxWin, "HelpBookmarkPage",
+ "sfx/ui/helpbookmarkpage.ui")
+ , m_xBookmarksBox(m_xBuilder->weld_tree_view("bookmarks"))
+ , m_xBookmarksPB(m_xBuilder->weld_button("display"))
+{
+ m_xBookmarksBox->set_size_request(m_xBookmarksBox->get_approximate_digit_width() * 30,
+ m_xBookmarksBox->get_height_rows(20));
+
+ m_xBookmarksPB->connect_clicked( LINK(this, BookmarksTabPage_Impl, OpenHdl));
+ m_xBookmarksBox->connect_row_activated(LINK(this, BookmarksTabPage_Impl, DoubleClickHdl));
+ m_xBookmarksBox->connect_popup_menu(LINK(this, BookmarksTabPage_Impl, CommandHdl));
+ m_xBookmarksBox->connect_key_press(LINK(this, BookmarksTabPage_Impl, KeyInputHdl));
+
+ // load bookmarks from configuration
+ const std::vector< SvtHistoryOptions::HistoryItem > aBookmarkSeq = SvtHistoryOptions::GetList( EHistoryType::HelpBookmarks );
+ for ( const auto& rBookmark : aBookmarkSeq )
+ {
+ AddBookmarks( rBookmark.sTitle, rBookmark.sURL );
+ }
+}
+
+BookmarksTabPage_Impl::~BookmarksTabPage_Impl()
+{
+ // save bookmarks to configuration
+ SvtHistoryOptions::Clear( EHistoryType::HelpBookmarks );
+ const sal_Int32 nCount = m_xBookmarksBox->n_children();
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ SvtHistoryOptions::AppendItem(EHistoryType::HelpBookmarks, m_xBookmarksBox->get_id(i), "",
+ m_xBookmarksBox->get_text(i), std::nullopt, std::nullopt);
+ }
+
+ m_xBookmarksBox.reset();
+ m_xBookmarksPB.reset();
+}
+
+IMPL_LINK_NOARG(BookmarksTabPage_Impl, OpenHdl, weld::Button&, void)
+{
+ aDoubleClickHdl.Call(nullptr);
+}
+
+IMPL_LINK_NOARG(BookmarksTabPage_Impl, DoubleClickHdl, weld::TreeView&, bool)
+{
+ aDoubleClickHdl.Call(nullptr);
+ return true;
+}
+
+void BookmarksTabPage_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
+{
+ aDoubleClickHdl = rLink;
+}
+
+OUString BookmarksTabPage_Impl::GetSelectedEntry() const
+{
+ return m_xBookmarksBox->get_selected_id();
+}
+
+void BookmarksTabPage_Impl::AddBookmarks(const OUString& rTitle, const OUString& rURL)
+{
+ const OUString aImageURL {IMAGE_URL + INetURLObject(rURL).GetHost()};
+ m_xBookmarksBox->append(rURL, rTitle, SvFileInformationManager::GetImageId(INetURLObject(aImageURL)));
+}
+
+OUString SfxHelpWindow_Impl::buildHelpURL(std::u16string_view sFactory ,
+ std::u16string_view sContent ,
+ std::u16string_view sAnchor)
+{
+ OUStringBuffer sHelpURL(256);
+ sHelpURL.append(HELP_URL + sFactory + sContent);
+ AppendConfigToken(sHelpURL, true/*bUseQuestionMark*/);
+ if (!sAnchor.empty())
+ sHelpURL.append(sAnchor);
+ return sHelpURL.makeStringAndClear();
+}
+
+void SfxHelpWindow_Impl::loadHelpContent(const OUString& sHelpURL, bool bAddToHistory)
+{
+ Reference< XComponentLoader > xLoader(getTextFrame(), UNO_QUERY);
+ if (!xLoader.is())
+ return;
+
+ // If a print job runs do not open a new page
+ Reference< XFrame2 > xTextFrame = pTextWin->getFrame();
+ Reference< XController > xTextController ;
+ if (xTextFrame.is())
+ xTextController = xTextFrame->getController ();
+ if ( xTextController.is() && !xTextController->suspend( true ) )
+ {
+ xTextController->suspend( false );
+ return;
+ }
+
+ // save url to history
+ if (bAddToHistory)
+ pHelpInterceptor->addURL(sHelpURL);
+
+ if ( !IsWait() )
+ EnterWait();
+ bool bSuccess = false;
+// TODO implement locale fallback ... see below while(true)
+ {
+ try
+ {
+ Reference< XComponent > xContent = xLoader->loadComponentFromURL(sHelpURL, "_self", 0, Sequence< PropertyValue >());
+ if (xContent.is())
+ {
+ bSuccess = true;
+ }
+ }
+ catch(const RuntimeException&)
+ { throw; }
+ catch(const Exception&)
+ { /*break;*/ }
+
+ /* TODO try next locale ...
+ no further locale available? => break loop and show error page
+ */
+ }
+ openDone(sHelpURL, bSuccess);
+ if ( IsWait() )
+ LeaveWait();
+}
+
+IMPL_LINK(SfxHelpIndexWindow_Impl, ActivatePageHdl, const OUString&, rPage, void)
+{
+ GetPage(rPage)->Activate();
+}
+
+SfxHelpIndexWindow_Impl::SfxHelpIndexWindow_Impl(SfxHelpWindow_Impl* _pParent, weld::Container* pContainer)
+ : m_xBuilder(Application::CreateBuilder(pContainer, "sfx/ui/helpcontrol.ui"))
+ , m_xContainer(m_xBuilder->weld_container("HelpControl"))
+ , m_xActiveLB(m_xBuilder->weld_combo_box("active"))
+ , m_xTabCtrl(m_xBuilder->weld_notebook("tabcontrol"))
+ , aIdle("sfx2 appl SfxHelpIndexWindow_Impl")
+ , aIndexKeywordLink(LINK(this, SfxHelpIndexWindow_Impl, KeywordHdl))
+ , pParentWin(_pParent)
+ , bIsInitDone(false)
+{
+ // create the pages
+ GetContentPage();
+ GetIndexPage();
+ GetSearchPage();
+ GetBookmarksPage();
+
+ OUString sPageId("index");
+ SvtViewOptions aViewOpt( EViewType::TabDialog, CONFIGNAME_INDEXWIN );
+ if ( aViewOpt.Exists() )
+ {
+ OUString sSavedPageId = aViewOpt.GetPageID();
+ if (m_xTabCtrl->get_page_index(sSavedPageId) != -1)
+ sPageId = sSavedPageId;
+ }
+ m_xTabCtrl->set_current_page(sPageId);
+ ActivatePageHdl(sPageId);
+ m_xActiveLB->connect_changed(LINK(this, SfxHelpIndexWindow_Impl, SelectHdl));
+
+ m_xTabCtrl->connect_enter_page(LINK(this, SfxHelpIndexWindow_Impl, ActivatePageHdl));
+
+ aIdle.SetInvokeHandler( LINK( this, SfxHelpIndexWindow_Impl, InitHdl ) );
+ aIdle.Start();
+
+ m_xContainer->show();
+}
+
+SfxHelpIndexWindow_Impl::~SfxHelpIndexWindow_Impl()
+{
+ SvtViewOptions aViewOpt(EViewType::TabDialog, CONFIGNAME_INDEXWIN);
+ aViewOpt.SetPageID(m_xTabCtrl->get_current_page_ident());
+
+ xCPage.reset();
+ xIPage.reset();
+ xSPage.reset();
+ xBPage.reset();
+}
+
+void SfxHelpIndexWindow_Impl::Initialize()
+{
+ OUStringBuffer aHelpURL(HELP_URL);
+ AppendConfigToken(aHelpURL, true);
+ std::vector<OUString> aFactories = SfxContentHelper::GetResultSet(aHelpURL.makeStringAndClear());
+ for (const OUString & rRow : aFactories)
+ {
+ sal_Int32 nIdx = 0;
+ OUString aTitle = rRow.getToken( 0, '\t', nIdx ); // token 0
+ std::u16string_view aURL = o3tl::getToken(rRow, 1, '\t', nIdx ); // token 2
+ OUString aFactory(INetURLObject(aURL).GetHost());
+ m_xActiveLB->append(aFactory, aTitle);
+ }
+
+ if (m_xActiveLB->get_active() == -1)
+ SetActiveFactory();
+}
+
+void SfxHelpIndexWindow_Impl::SetActiveFactory()
+{
+ DBG_ASSERT( xIPage, "index page not initialized" );
+ if (!bIsInitDone && !m_xActiveLB->get_count())
+ {
+ aIdle.Stop();
+ InitHdl( nullptr );
+ }
+
+ for (sal_Int32 i = 0, nEntryCount = m_xActiveLB->get_count(); i < nEntryCount; ++i)
+ {
+ OUString aFactory = m_xActiveLB->get_id(i);
+ aFactory = aFactory.toAsciiLowerCase();
+ if (aFactory == xIPage->GetFactory())
+ {
+ if (m_xActiveLB->get_active() != i)
+ {
+ m_xActiveLB->set_active(i);
+ aSelectFactoryLink.Call(nullptr);
+ }
+ break;
+ }
+ }
+}
+
+HelpTabPage_Impl* SfxHelpIndexWindow_Impl::GetPage(std::u16string_view rName)
+{
+ HelpTabPage_Impl* pPage = nullptr;
+
+ if (rName == u"contents")
+ pPage = GetContentPage();
+ else if (rName == u"index")
+ pPage = GetIndexPage();
+ else if (rName == u"find")
+ pPage = GetSearchPage();
+ else if (rName == u"bookmarks")
+ pPage = GetBookmarksPage();
+
+ assert(pPage && "SfxHelpIndexWindow_Impl::GetCurrentPage(): no current page");
+
+ return pPage;
+}
+
+IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, SelectHdl, weld::ComboBox&, void)
+{
+ aIdle.Start();
+}
+
+IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, InitHdl, Timer *, void)
+{
+ bIsInitDone = true;
+ Initialize();
+
+ // now use the timer for selection
+ aIdle.SetInvokeHandler( LINK( this, SfxHelpIndexWindow_Impl, SelectFactoryHdl ) );
+ aIdle.SetPriority( TaskPriority::LOWEST );
+}
+
+IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, SelectFactoryHdl, Timer *, void)
+{
+ OUString aFactory = m_xActiveLB->get_active_id();
+ if (!aFactory.isEmpty())
+ {
+ SetFactory(aFactory.toAsciiLowerCase(), false);
+ aSelectFactoryLink.Call(this);
+ }
+}
+
+IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, KeywordHdl, IndexTabPage_Impl&, void)
+{
+ // keyword found on index?
+ bool bIndex = xIPage->HasKeyword();
+
+ if( !bIndex)
+ bIndex = xIPage->HasKeywordIgnoreCase();
+ // then set index or search page as current.
+ OUString sPageId = bIndex ? OUString("index") : OUString("find");
+ if (sPageId != m_xTabCtrl->get_current_page_ident())
+ m_xTabCtrl->set_current_page(sPageId);
+
+ // at last we open the keyword
+ if ( bIndex )
+ xIPage->OpenKeyword();
+ else if ( !xSPage->OpenKeyword( sKeyword ) )
+ pParentWin->ShowStartPage();
+}
+
+IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, IndexTabPageDoubleClickHdl, LinkParamNone*, void)
+{
+ aPageDoubleClickLink.Call(nullptr);
+}
+
+void SfxHelpIndexWindow_Impl::SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink)
+{
+ aPageDoubleClickLink = rLink;
+}
+
+IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, ContentTabPageDoubleClickHdl, LinkParamNone*, void)
+{
+ aPageDoubleClickLink.Call(nullptr);
+}
+
+IMPL_LINK_NOARG(SfxHelpIndexWindow_Impl, TabPageDoubleClickHdl, LinkParamNone*, void)
+{
+ aPageDoubleClickLink.Call(nullptr);
+}
+
+void SfxHelpIndexWindow_Impl::SetFactory( const OUString& rFactory, bool bActive )
+{
+ if ( !rFactory.isEmpty() )
+ {
+ GetIndexPage()->SetFactory( rFactory );
+ // the index page made a check if rFactory is valid,
+ // so the index page always returns a valid factory
+ GetSearchPage()->SetFactory( GetIndexPage()->GetFactory() );
+ if ( bActive )
+ SetActiveFactory();
+ }
+}
+
+OUString SfxHelpIndexWindow_Impl::GetSelectedEntry() const
+{
+ OUString sRet;
+
+ OUString sName(m_xTabCtrl->get_current_page_ident());
+
+ if (sName == "contents")
+ {
+ sRet = xCPage->GetSelectedEntry();
+ }
+ else if (sName == "index")
+ {
+ sRet = xIPage->GetSelectedEntry();
+ }
+ else if (sName == "find")
+ {
+ sRet = xSPage->GetSelectedEntry();
+ }
+ else if (sName == "bookmarks")
+ {
+ sRet = xBPage->GetSelectedEntry();
+ }
+
+ return sRet;
+}
+
+void SfxHelpIndexWindow_Impl::AddBookmarks( const OUString& rTitle, const OUString& rURL )
+{
+ GetBookmarksPage()->AddBookmarks( rTitle, rURL );
+}
+
+bool SfxHelpIndexWindow_Impl::IsValidFactory( std::u16string_view _rFactory )
+{
+ bool bValid = false;
+ for (sal_Int32 i = 0, nEntryCount = m_xActiveLB->get_count(); i < nEntryCount; ++i)
+ {
+ OUString aFactory = m_xActiveLB->get_id(i);
+ if (aFactory == _rFactory)
+ {
+ bValid = true;
+ break;
+ }
+ }
+ return bValid;
+}
+
+void SfxHelpIndexWindow_Impl::ClearSearchPage()
+{
+ if ( xSPage )
+ xSPage->ClearPage();
+}
+
+void SfxHelpIndexWindow_Impl::GrabFocusBack()
+{
+ OUString sName(m_xTabCtrl->get_current_page_ident());
+
+ if (sName == "contents" && xCPage)
+ xCPage->SetFocusOnBox();
+ else if (sName == "index" && xIPage)
+ xIPage->SetFocusOnBox();
+ else if (sName == "find" && xSPage)
+ xSPage->SetFocusOnBox();
+ else if (sName == "bookmarks" && xBPage)
+ xBPage->SetFocusOnBox();
+}
+
+bool SfxHelpIndexWindow_Impl::HasFocusOnEdit() const
+{
+ bool bRet = false;
+ OUString sName(m_xTabCtrl->get_current_page_ident());
+ if (sName == "index" && xIPage)
+ bRet = xIPage->HasFocusOnEdit();
+ else if (sName == "find" && xSPage)
+ bRet = xSPage->HasFocusOnEdit();
+ return bRet;
+}
+
+OUString SfxHelpIndexWindow_Impl::GetSearchText() const
+{
+ OUString sRet;
+ OUString sName(m_xTabCtrl->get_current_page_ident());
+ if (sName == "find" && xSPage)
+ sRet = xSPage->GetSearchText();
+ return sRet;
+}
+
+bool SfxHelpIndexWindow_Impl::IsFullWordSearch() const
+{
+ bool bRet = false;
+ OUString sName(m_xTabCtrl->get_current_page_ident());
+ if (sName == "find" && xSPage)
+ bRet = xSPage->IsFullWordSearch();
+ return bRet;
+}
+
+void SfxHelpIndexWindow_Impl::OpenKeyword( const OUString& rKeyword )
+{
+ sKeyword = rKeyword;
+ DBG_ASSERT( xIPage, "invalid index page" );
+ xIPage->SetKeyword( sKeyword );
+}
+
+void SfxHelpIndexWindow_Impl::SelectExecutableEntry()
+{
+ OUString sName(m_xTabCtrl->get_current_page_ident());
+ if (sName == "index" && xIPage )
+ xIPage->SelectExecutableEntry();
+}
+
+weld::Window* SfxHelpIndexWindow_Impl::GetFrameWeld() const
+{
+ return pParentWin->GetFrameWeld();
+}
+
+// class TextWin_Impl ----------------------------------------------------
+TextWin_Impl::TextWin_Impl( vcl::Window* p ) : DockingWindow( p, 0 )
+{
+}
+
+bool TextWin_Impl::EventNotify( NotifyEvent& rNEvt )
+{
+ if( ( rNEvt.GetType() == NotifyEventType::KEYINPUT ) && rNEvt.GetKeyEvent()->GetKeyCode().GetCode() == KEY_TAB )
+ return GetParent()->EventNotify( rNEvt );
+ else
+ return DockingWindow::EventNotify( rNEvt );
+}
+
+
+// remove docking area acceptor from layoutmanager, so it will not layout anything further .-)
+static void lcl_disableLayoutOfFrame(const Reference< XFrame2 >& xFrame)
+{
+ xFrame->setLayoutManager( Reference< XLayoutManager >() );
+}
+
+// class SfxHelpTextWindow_Impl ------------------------------------------
+
+SfxHelpTextWindow_Impl::SfxHelpTextWindow_Impl(SfxHelpWindow_Impl* pHelpWin, weld::Builder& rBuilder, vcl::Window* pParent) :
+
+ Window( pParent, WB_CLIPCHILDREN | WB_TABSTOP | WB_DIALOGCONTROL ),
+
+ xToolBox ( rBuilder.weld_toolbar("toolbar") ),
+ xOnStartupCB ( rBuilder.weld_check_button("checkbutton") ),
+ xMenu ( rBuilder.weld_menu("menu") ),
+ aSelectIdle ( "sfx2 appl SfxHelpTextWindow_Impl Select" ),
+ aIndexOnImage ( BMP_HELP_TOOLBOX_INDEX_ON ),
+ aIndexOffImage ( BMP_HELP_TOOLBOX_INDEX_OFF ),
+ aIndexOnText ( SfxResId( STR_HELP_BUTTON_INDEX_ON ) ),
+ aIndexOffText ( SfxResId( STR_HELP_BUTTON_INDEX_OFF ) ),
+ aOnStartupText ( SfxResId( RID_HELP_ONSTARTUP_TEXT ) ),
+ xHelpWin ( pHelpWin ),
+ pTextWin ( VclPtr<TextWin_Impl>::Create( this ) ),
+ bIsDebug ( false ),
+ bIsIndexOn ( false ),
+ bIsInClose ( false ),
+ bIsFullWordSearch ( false )
+{
+ xFrame = Frame::create( ::comphelper::getProcessComponentContext() );
+ xFrame->initialize( VCLUnoHelper::GetInterface ( pTextWin ) );
+ xFrame->setName( "OFFICE_HELP" );
+ lcl_disableLayoutOfFrame(xFrame);
+
+ xToolBox->set_help_id(HID_HELP_TOOLBOX);
+
+ xToolBox->set_item_tooltip_text("index", aIndexOffText );
+ xToolBox->set_item_help_id("index", HID_HELP_TOOLBOXITEM_INDEX);
+ xToolBox->set_item_help_id("backward", HID_HELP_TOOLBOXITEM_BACKWARD);
+ xToolBox->set_item_help_id("forward", HID_HELP_TOOLBOXITEM_FORWARD);
+ xToolBox->set_item_help_id("start", HID_HELP_TOOLBOXITEM_START);
+ xToolBox->set_item_help_id("print", HID_HELP_TOOLBOXITEM_PRINT);
+ xToolBox->set_item_help_id("bookmarks", HID_HELP_TOOLBOXITEM_BOOKMARKS );
+ xToolBox->set_item_help_id("searchdialog", HID_HELP_TOOLBOXITEM_SEARCHDIALOG);
+
+ InitToolBoxImages();
+ InitOnStartupBox();
+ xOnStartupCB->connect_toggled(LINK(this, SfxHelpTextWindow_Impl, CheckHdl));
+
+ aSelectIdle.SetInvokeHandler( LINK( this, SfxHelpTextWindow_Impl, SelectHdl ) );
+ aSelectIdle.SetPriority( TaskPriority::LOWEST );
+
+ char* pEnv = getenv( "help_debug" );
+ if ( pEnv )
+ bIsDebug = true;
+
+ SvtMiscOptions().AddListenerLink( LINK( this, SfxHelpTextWindow_Impl, NotifyHdl ) );
+}
+
+SfxHelpTextWindow_Impl::~SfxHelpTextWindow_Impl()
+{
+ disposeOnce();
+}
+
+void SfxHelpTextWindow_Impl::dispose()
+{
+ bIsInClose = true;
+ SvtMiscOptions().RemoveListenerLink( LINK( this, SfxHelpTextWindow_Impl, NotifyHdl ) );
+ m_xSrchDlg.reset();
+ xToolBox.reset();
+ xOnStartupCB.reset();
+ xHelpWin.clear();
+ pTextWin.disposeAndClear();
+ vcl::Window::dispose();
+}
+
+bool SfxHelpTextWindow_Impl::HasSelection() const
+{
+ // is there any selection in the text and not only a cursor?
+ bool bRet = false;
+ Reference < XTextRange > xRange = getCursor();
+ if ( xRange.is() )
+ {
+ Reference < XText > xText = xRange->getText();
+ Reference < XTextCursor > xCursor = xText->createTextCursorByRange( xRange );
+ bRet = !xCursor->isCollapsed();
+ }
+
+ return bRet;
+}
+
+void SfxHelpTextWindow_Impl::InitToolBoxImages()
+{
+ xToolBox->set_item_icon_name("index", bIsIndexOn ? aIndexOffImage : aIndexOnImage);
+}
+
+void SfxHelpTextWindow_Impl::InitOnStartupBox()
+{
+ sCurrentFactory = SfxHelp::GetCurrentModuleIdentifier();
+
+ Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ const OUString sPath { PATH_OFFICE_FACTORIES + sCurrentFactory };
+
+ // Attention: This check boy knows two states:
+ // 1) Reading of the config key fails with an exception or by getting an empty Any (!) => check box must be hidden
+ // 2) We read sal_True/sal_False => check box must be shown and enabled/disabled
+
+ bool bHideBox = true;
+ bool bHelpAtStartup = false;
+ try
+ {
+ xConfiguration = ConfigurationHelper::openConfig(
+ xContext, PACKAGE_SETUP, EConfigurationModes::Standard );
+ if ( xConfiguration.is() )
+ {
+ Any aAny = ConfigurationHelper::readRelativeKey( xConfiguration, sPath, KEY_HELP_ON_OPEN );
+ if (aAny >>= bHelpAtStartup)
+ bHideBox = false;
+ }
+ }
+ catch( Exception& )
+ {
+ bHideBox = true;
+ }
+
+ if ( bHideBox )
+ xOnStartupCB->hide();
+ else
+ {
+ // detect module name
+ OUString sModuleName;
+
+ if ( xConfiguration.is() )
+ {
+ OUString sTemp;
+ try
+ {
+ Any aAny = ConfigurationHelper::readRelativeKey( xConfiguration, sPath, KEY_UI_NAME );
+ aAny >>= sTemp;
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::InitOnStartupBox()" );
+ }
+ sModuleName = sTemp;
+ }
+
+ if ( !sModuleName.isEmpty() )
+ {
+ // set module name in checkbox text
+ xOnStartupCB->set_label(aOnStartupText.replaceFirst("%MODULENAME", sModuleName));
+ // and show it
+ xOnStartupCB->show();
+ // set check state
+ xOnStartupCB->set_active(bHelpAtStartup);
+ xOnStartupCB->save_state();
+ }
+ }
+}
+
+Reference< XBreakIterator > const & SfxHelpTextWindow_Impl::GetBreakIterator()
+{
+ if ( !xBreakIterator.is() )
+ xBreakIterator = vcl::unohelper::CreateBreakIterator();
+ DBG_ASSERT( xBreakIterator.is(), "Could not create BreakIterator" );
+ return xBreakIterator;
+}
+
+Reference< XTextRange > SfxHelpTextWindow_Impl::getCursor() const
+{
+ // return the current cursor
+ Reference< XTextRange > xCursor;
+
+ try
+ {
+ Reference < XSelectionSupplier > xSelSup( xFrame->getController(), UNO_QUERY );
+ if ( xSelSup.is() )
+ {
+ Any aAny = xSelSup->getSelection();
+ Reference < XIndexAccess > xSelection;
+ if ( aAny >>= xSelection )
+ {
+ if ( xSelection->getCount() == 1 )
+ {
+ aAny = xSelection->getByIndex(0);
+ aAny >>= xCursor;
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::getCursor(): unexpected exception" );
+ }
+
+ return xCursor;
+}
+
+
+bool SfxHelpTextWindow_Impl::isHandledKey( const vcl::KeyCode& _rKeyCode )
+{
+ bool bRet = false;
+ sal_uInt16 nCode = _rKeyCode.GetCode();
+
+ // the keys <CTRL><A> (select all), <CTRL><C> (copy),
+ // <CTRL><F> (find), <CTRL><P> (print) and <CTRL><W> (close window)
+ // were handled in help
+ if ( _rKeyCode.IsMod1() &&
+ ( KEY_A == nCode || KEY_C == nCode || KEY_F == nCode || KEY_P == nCode || KEY_W == nCode ) )
+ {
+ if ( KEY_F == nCode )
+ DoSearch();
+ else
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+
+IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, SelectHdl, Timer *, void)
+{
+ try
+ {
+ // select the words, which are equal to the search text of the search page
+ Reference < XController > xController = xFrame->getController();
+ if ( xController.is() )
+ {
+ // get document
+ Reference < XSearchable > xSearchable( xController->getModel(), UNO_QUERY );
+ if ( xSearchable.is() )
+ {
+ // create descriptor, set string and find all words
+ Reference < XSearchDescriptor > xSrchDesc = xSearchable->createSearchDescriptor();
+ xSrchDesc->setPropertyValue( "SearchRegularExpression", Any( true ) );
+ if ( bIsFullWordSearch )
+ xSrchDesc->setPropertyValue( "SearchWords", Any( true ) );
+
+ xSrchDesc->setSearchString( sfx2::PrepareSearchString( aSearchText, GetBreakIterator(), false ) );
+ Reference< XIndexAccess > xSelection = xSearchable->findAll( xSrchDesc );
+
+ // then select all found words
+ Reference < XSelectionSupplier > xSelectionSup( xController, UNO_QUERY );
+ if ( xSelectionSup.is() )
+ {
+ xSelectionSup->select( Any(xSelection) );
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SelectHdl(): unexpected exception" );
+ }
+}
+
+
+IMPL_LINK_NOARG( SfxHelpTextWindow_Impl, NotifyHdl, LinkParamNone*, void )
+{
+ InitToolBoxImages();
+ Resize();
+}
+
+IMPL_LINK( SfxHelpTextWindow_Impl, FindHdl, sfx2::SearchDialog&, rDlg, void )
+{
+ FindHdl(&rDlg);
+}
+void SfxHelpTextWindow_Impl::FindHdl(sfx2::SearchDialog* pDlg)
+{
+ bool bWrapAround = ( nullptr == pDlg );
+ if ( bWrapAround )
+ pDlg = m_xSrchDlg.get();
+ DBG_ASSERT( pDlg, "invalid search dialog" );
+ try
+ {
+ // select the words, which are equal to the search text of the search page
+ Reference < XController > xController = xFrame->getController();
+ if ( xController.is() )
+ {
+ // get document
+ Reference < XSearchable > xSearchable( xController->getModel(), UNO_QUERY );
+ if ( xSearchable.is() )
+ {
+ // create descriptor, set string and find all words
+ Reference < XSearchDescriptor > xSrchDesc = xSearchable->createSearchDescriptor();
+ xSrchDesc->setPropertyValue( "SearchWords", Any(pDlg->IsOnlyWholeWords()) );
+ xSrchDesc->setPropertyValue( "SearchCaseSensitive", Any(pDlg->IsMarchCase()) );
+ xSrchDesc->setPropertyValue( "SearchBackwards", Any(pDlg->IsSearchBackwards()) );
+ xSrchDesc->setSearchString( pDlg->GetSearchText() );
+ Reference< XInterface > xSelection;
+ Reference< XTextRange > xCursor = getCursor();
+
+ if ( xCursor.is() )
+ {
+ if ( pDlg->IsSearchBackwards() )
+ xCursor = xCursor->getStart();
+ xSelection = xSearchable->findNext( xCursor, xSrchDesc );
+ }
+ else
+ xSelection = xSearchable->findFirst( xSrchDesc );
+
+ // then select the found word
+ if ( xSelection.is() )
+ {
+ Reference < XSelectionSupplier > xSelectionSup( xController, UNO_QUERY );
+ if ( xSelectionSup.is() )
+ {
+ xSelectionSup->select( Any(xSelection) );
+ }
+ }
+ else if ( pDlg->IsWrapAround() && !bWrapAround )
+ {
+ Reference < text::XTextViewCursorSupplier > xCrsrSupp( xController, uno::UNO_QUERY );
+ Reference < text::XTextViewCursor > xTVCrsr = xCrsrSupp->getViewCursor();
+ if ( xTVCrsr.is() )
+ {
+ Reference < text::XTextDocument > xDoc( xController->getModel(), uno::UNO_QUERY );
+ Reference < text::XText > xText = xDoc->getText();
+ if ( xText.is() )
+ {
+ if ( pDlg->IsSearchBackwards() )
+ xTVCrsr->gotoRange( xText->getEnd(), false );
+ else
+ xTVCrsr->gotoRange( xText->getStart(), false );
+ FindHdl( nullptr );
+ }
+ }
+ }
+ else
+ {
+ assert(m_xSrchDlg && "no search dialog");
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xSrchDlg->getDialog(),
+ VclMessageType::Info, VclButtonsType::Ok, SfxResId(STR_INFO_NOSEARCHTEXTFOUND)));
+ xBox->run();
+ m_xSrchDlg->SetFocusOnEdit();
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SelectHdl(): unexpected exception" );
+ }
+}
+
+IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, CloseHdl, LinkParamNone*, void)
+{
+ m_xSrchDlg.reset();
+}
+
+IMPL_LINK_NOARG(SfxHelpTextWindow_Impl, CheckHdl, weld::Toggleable&, void)
+{
+ if ( !xConfiguration.is() )
+ return;
+
+ bool bChecked = xOnStartupCB->get_active();
+ try
+ {
+ ConfigurationHelper::writeRelativeKey(
+ xConfiguration, PATH_OFFICE_FACTORIES + sCurrentFactory, KEY_HELP_ON_OPEN, Any( bChecked ) );
+ ConfigurationHelper::flush( xConfiguration );
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::CheckHdl()" );
+ }
+}
+
+void SfxHelpTextWindow_Impl::Resize()
+{
+ Size aSize = GetOutputSizePixel();
+ pTextWin->SetPosSizePixel( Point(0, 0), aSize );
+}
+
+bool SfxHelpTextWindow_Impl::PreNotify( NotifyEvent& rNEvt )
+{
+ bool bDone = false;
+ NotifyEventType nType = rNEvt.GetType();
+ if ( NotifyEventType::COMMAND == nType && rNEvt.GetCommandEvent() )
+ {
+ const CommandEvent* pCmdEvt = rNEvt.GetCommandEvent();
+ vcl::Window* pCmdWin = rNEvt.GetWindow();
+
+ if ( pCmdEvt->GetCommand() == CommandEventId::ContextMenu && pCmdWin != this )
+ {
+ Point aPos;
+ if ( pCmdEvt->IsMouseEvent() )
+ aPos = pCmdEvt->GetMousePosPixel();
+ else
+ aPos = Point( pTextWin->GetPosPixel().X() + 20, 20 );
+
+ xMenu->clear();
+
+ if (bIsIndexOn)
+ xMenu->append("index", aIndexOffText, BMP_HELP_TOOLBOX_INDEX_OFF);
+ else
+ xMenu->append("index", aIndexOnText, BMP_HELP_TOOLBOX_INDEX_ON);
+
+ xMenu->append_separator("separator1");
+ xMenu->append("backward", SfxResId(STR_HELP_BUTTON_PREV), BMP_HELP_TOOLBOX_PREV);
+ xMenu->set_sensitive("backward", xHelpWin->HasHistoryPredecessor());
+ xMenu->append("forward", SfxResId(STR_HELP_BUTTON_NEXT), BMP_HELP_TOOLBOX_NEXT);
+ xMenu->set_sensitive("forward", xHelpWin->HasHistorySuccessor());
+ xMenu->append("start", SfxResId(STR_HELP_BUTTON_START), BMP_HELP_TOOLBOX_START);
+ xMenu->append_separator("separator2");
+ xMenu->append("print", SfxResId(STR_HELP_BUTTON_PRINT), BMP_HELP_TOOLBOX_PRINT);
+ xMenu->append("bookmarks", SfxResId(STR_HELP_BUTTON_ADDBOOKMARK), BMP_HELP_TOOLBOX_BOOKMARKS);
+ xMenu->append("searchdialog", SfxResId(STR_HELP_BUTTON_SEARCHDIALOG), BMP_HELP_TOOLBOX_SEARCHDIALOG);
+ xMenu->append_separator("separator3");
+ xMenu->append_check("selectionmode", SfxResId(STR_HELP_MENU_TEXT_SELECTION_MODE));
+ URL aURL;
+ aURL.Complete = ".uno:SelectTextMode";
+ Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
+ xTrans->parseStrict(aURL);
+ Reference < XDispatch > xDisp = xFrame->queryDispatch( aURL, OUString(), 0 );
+ if(xDisp.is())
+ {
+ rtl::Reference<HelpStatusListener_Impl> pStateListener =
+ new HelpStatusListener_Impl(xDisp, aURL );
+ FeatureStateEvent rEvent = pStateListener->GetStateEvent();
+ bool bCheck = false;
+ rEvent.State >>= bCheck;
+ xMenu->set_active("selectionmode", bCheck);
+ }
+ xMenu->append_separator("separator4");
+ xMenu->append("copy", SfxResId(STR_HELP_MENU_TEXT_COPY), BMP_HELP_TOOLBOX_COPY);
+ xMenu->set_sensitive("copy", HasSelection());
+
+ if ( bIsDebug )
+ {
+ xMenu->append_separator("separator5");
+ xMenu->append("sourceview", SfxResId(STR_HELP_BUTTON_SOURCEVIEW));
+ }
+
+ int x, y, width, height;
+ weld::Window* pTopLevel = GetFrameWeld();
+ xHelpWin->GetContainer()->get_extents_relative_to(*pTopLevel, x, y, width, height);
+ aPos.AdjustX(x);
+ aPos.AdjustY(y);
+
+ xHelpWin->DoAction(xMenu->popup_at_rect(pTopLevel, tools::Rectangle(aPos, Size(1,1))));
+ bDone = true;
+ }
+ }
+ else if ( NotifyEventType::KEYINPUT == nType && rNEvt.GetKeyEvent() )
+ {
+ const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
+ const vcl::KeyCode& rKeyCode = pKEvt->GetKeyCode();
+ sal_uInt16 nKeyGroup = rKeyCode.GetGroup();
+ sal_uInt16 nKey = rKeyCode.GetCode();
+ if ( KEYGROUP_ALPHA == nKeyGroup && !isHandledKey( rKeyCode ) )
+ {
+ // do nothing disables the writer accelerators
+ bDone = true;
+ }
+ else if ( rKeyCode.IsMod1() && ( KEY_F4 == nKey || KEY_W == nKey ) )
+ {
+ // <CTRL><F4> or <CTRL><W> -> close top frame
+ xHelpWin->CloseWindow();
+ bDone = true;
+ }
+ else if ( KEY_TAB == nKey && xOnStartupCB->has_focus() )
+ {
+ xToolBox->grab_focus();
+ bDone = true;
+ }
+ }
+
+ return bDone || Window::PreNotify( rNEvt );
+}
+
+
+void SfxHelpTextWindow_Impl::GetFocus()
+{
+ if ( bIsInClose )
+ return;
+
+ try
+ {
+ if( xFrame.is() )
+ {
+ Reference< css::awt::XWindow > xWindow = xFrame->getComponentWindow();
+ if( xWindow.is() )
+ xWindow->setFocus();
+ }
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::GetFocus()" );
+ }
+}
+
+
+void SfxHelpTextWindow_Impl::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ if ( ( ( rDCEvt.GetType() == DataChangedEventType::SETTINGS ) ||
+ ( rDCEvt.GetType() == DataChangedEventType::DISPLAY ) ) &&
+ ( rDCEvt.GetFlags() & AllSettingsFlags::STYLE ) )
+ {
+ SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFaceColor() ) );
+ InitToolBoxImages();
+ }
+}
+
+void SfxHelpTextWindow_Impl::ToggleIndex( bool bOn )
+{
+ bIsIndexOn = bOn;
+ if ( bIsIndexOn )
+ {
+ xToolBox->set_item_icon_name("index", aIndexOffImage);
+ xToolBox->set_item_tooltip_text("index", aIndexOffText);
+ }
+ else
+ {
+ xToolBox->set_item_icon_name("index", aIndexOnImage);
+ xToolBox->set_item_tooltip_text("index", aIndexOnText);
+ }
+}
+
+void SfxHelpTextWindow_Impl::SelectSearchText( const OUString& rSearchText, bool _bIsFullWordSearch )
+{
+ aSearchText = rSearchText;
+ bIsFullWordSearch = _bIsFullWordSearch;
+ aSelectIdle.Start();
+}
+
+
+void SfxHelpTextWindow_Impl::SetPageStyleHeaderOff() const
+{
+ bool bSetOff = false;
+ // set off the pagestyle header to prevent print output of the help URL
+ try
+ {
+ Reference < XController > xController = xFrame->getController();
+ Reference < XSelectionSupplier > xSelSup( xController, UNO_QUERY );
+ if ( xSelSup.is() )
+ {
+ Reference < XIndexAccess > xSelection;
+ if ( xSelSup->getSelection() >>= xSelection )
+ {
+ Reference < XTextRange > xRange;
+ if ( xSelection->getByIndex(0) >>= xRange )
+ {
+ Reference < XText > xText = xRange->getText();
+ Reference < XPropertySet > xProps( xText->createTextCursorByRange( xRange ), UNO_QUERY );
+ OUString sStyleName;
+ if ( xProps->getPropertyValue( "PageStyleName" ) >>= sStyleName )
+ {
+ Reference < XStyleFamiliesSupplier > xStyles( xController->getModel(), UNO_QUERY );
+ Reference < XNameContainer > xContainer;
+ if ( xStyles->getStyleFamilies()->getByName( "PageStyles" )
+ >>= xContainer )
+ {
+ Reference < XStyle > xStyle;
+ if ( xContainer->getByName( sStyleName ) >>= xStyle )
+ {
+ Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY );
+ xPropSet->setPropertyValue( "HeaderIsOn", Any( false ) );
+
+ Reference< XModifiable > xReset(xStyles, UNO_QUERY);
+ xReset->setModified(false);
+ bSetOff = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpTextWindow_Impl::SetPageStyleHeaderOff()" );
+ }
+
+ SAL_WARN_IF( !bSetOff, "sfx.appl", "SfxHelpTextWindow_Impl::SetPageStyleHeaderOff(): set off failed" );
+}
+
+
+void SfxHelpTextWindow_Impl::CloseFrame()
+{
+ bIsInClose = true;
+ try
+ {
+ css::uno::Reference< css::util::XCloseable > xCloseable ( xFrame, css::uno::UNO_QUERY );
+ if (xCloseable.is())
+ xCloseable->close(true);
+ }
+ catch( css::util::CloseVetoException& )
+ {
+ }
+}
+
+
+void SfxHelpTextWindow_Impl::DoSearch()
+{
+ if (m_xSrchDlg)
+ return;
+
+ // create the search dialog
+ m_xSrchDlg = std::make_shared<sfx2::SearchDialog>(pTextWin->GetFrameWeld(), "HelpSearchDialog");
+ // set handler
+ m_xSrchDlg->SetFindHdl( LINK( this, SfxHelpTextWindow_Impl, FindHdl ) );
+ m_xSrchDlg->SetCloseHdl( LINK( this, SfxHelpTextWindow_Impl, CloseHdl ) );
+ // get selected text of the help page to set it as the search text
+ Reference< XTextRange > xCursor = getCursor();
+ if ( xCursor.is() )
+ {
+ OUString sText = xCursor->getString();
+ if ( !sText.isEmpty() )
+ m_xSrchDlg->SetSearchText( sText );
+ }
+ sfx2::SearchDialog::runAsync(m_xSrchDlg);
+}
+
+void SfxHelpWindow_Impl::GetFocus()
+{
+ if (pTextWin)
+ pTextWin->GrabFocus();
+ else
+ ResizableDockingWindow::GetFocus();
+}
+
+void SfxHelpWindow_Impl::MakeLayout()
+{
+ Split();
+
+ m_xHelpPaneWindow->set_visible(bIndex);
+}
+
+IMPL_LINK(SfxHelpWindow_Impl, ResizeHdl, const Size&, rSize, void)
+{
+ int nNewWidth = rSize.Width();
+ if (!nNewWidth)
+ return;
+ if (bSplit)
+ nIndexSize = round(m_xContainer->get_position() * 100.0 / nNewWidth);
+ nWidth = nNewWidth;
+ Split();
+ nIndexSize = round(m_xContainer->get_position() * 100.0 / nWidth);
+}
+
+void SfxHelpWindow_Impl::Split()
+{
+ if (!nWidth)
+ return;
+ m_xContainer->set_position(nWidth * nIndexSize / 100);
+ bSplit = true;
+}
+
+void SfxHelpWindow_Impl::LoadConfig()
+{
+ SvtViewOptions aViewOpt( EViewType::Window, CONFIGNAME_HELPWIN );
+ if ( !aViewOpt.Exists() )
+ return;
+ bIndex = aViewOpt.IsVisible();
+
+ Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
+ OUString aUserData;
+ if ( aUserItem >>= aUserData )
+ {
+ DBG_ASSERT( comphelper::string::getTokenCount(aUserData, ';') == 6, "invalid user data" );
+ sal_Int32 nIdx = 0;
+ nIndexSize = o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx ));
+ o3tl::getToken(aUserData, 0, ';', nIdx); // ignore nTextSize
+ sal_Int32 nOldWidth = o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx ));
+ sal_Int32 nOldHeight = o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx ));
+ aWinSize = Size(nOldWidth, nOldHeight);
+ aWinPos.setX( o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx )) );
+ aWinPos.setY( o3tl::toInt32(o3tl::getToken(aUserData, 0, ';', nIdx )) );
+ }
+
+ pTextWin->ToggleIndex( bIndex );
+}
+
+void SfxHelpWindow_Impl::SaveConfig()
+{
+ SvtViewOptions aViewOpt( EViewType::Window, CONFIGNAME_HELPWIN );
+ sal_Int32 nW = 0, nH = 0;
+
+ if ( xWindow.is() )
+ {
+ css::awt::Rectangle aRect = xWindow->getPosSize();
+ nW = aRect.Width;
+ nH = aRect.Height;
+ }
+
+ aViewOpt.SetVisible( bIndex );
+ VclPtr<vcl::Window> pScreenWin = VCLUnoHelper::GetWindow( xWindow );
+ aWinPos = pScreenWin->GetWindowExtentsAbsolute().TopLeft();
+ if (bSplit)
+ nIndexSize = round(m_xContainer->get_position() * 100.0 / nWidth);
+ const OUString aUserData = OUString::number( nIndexSize )
+ + ";" + OUString::number( 100 - nIndexSize )
+ + ";" + OUString::number( nW )
+ + ";" + OUString::number( nH )
+ + ";" + OUString::number( aWinPos.X() )
+ + ";" + OUString::number( aWinPos.Y() );
+
+ aViewOpt.SetUserItem( USERITEM_NAME, Any( aUserData ) );
+}
+
+void SfxHelpWindow_Impl::ShowStartPage()
+{
+ loadHelpContent(SfxHelpWindow_Impl::buildHelpURL(xIndexWin->GetFactory(), u"/start", u""));
+}
+
+IMPL_LINK(SfxHelpWindow_Impl, SelectHdl, const OUString&, rCurItem, void)
+{
+ bGrabFocusToToolBox = pTextWin->GetToolBox().has_focus();
+ DoAction(rCurItem);
+}
+
+IMPL_LINK_NOARG(SfxHelpWindow_Impl, OpenHdl, LinkParamNone*, void)
+{
+ xIndexWin->SelectExecutableEntry();
+ OUString aEntry = xIndexWin->GetSelectedEntry();
+
+ if ( aEntry.isEmpty() )
+ return;
+
+ OUString sHelpURL;
+
+ bool bComplete = aEntry.toAsciiLowerCase().match("vnd.sun.star.help");
+
+ if (bComplete)
+ sHelpURL = aEntry;
+ else
+ {
+ std::u16string_view aId;
+ OUString aAnchor('#');
+ if ( comphelper::string::getTokenCount(aEntry, '#') == 2 )
+ {
+ sal_Int32 nIdx{ 0 };
+ aId = o3tl::getToken(aEntry, 0, '#', nIdx );
+ aAnchor += o3tl::getToken(aEntry, 0, '#', nIdx );
+ }
+ else
+ aId = aEntry;
+
+ sHelpURL = SfxHelpWindow_Impl::buildHelpURL(xIndexWin->GetFactory(), Concat2View(OUString::Concat("/") + aId), aAnchor);
+ }
+
+ loadHelpContent(sHelpURL);
+}
+
+IMPL_LINK( SfxHelpWindow_Impl, SelectFactoryHdl, SfxHelpIndexWindow_Impl* , pWin, void )
+{
+ if ( sTitle.isEmpty() )
+ sTitle = GetParent()->GetText();
+
+ Reference< XTitle > xTitle(xFrame, UNO_QUERY);
+ if (xTitle.is ())
+ xTitle->setTitle(sTitle + " - " + xIndexWin->GetActiveFactoryTitle());
+
+ if ( pWin )
+ ShowStartPage();
+ xIndexWin->ClearSearchPage();
+}
+
+
+IMPL_LINK( SfxHelpWindow_Impl, ChangeHdl, HelpListener_Impl&, rListener, void )
+{
+ SetFactory( rListener.GetFactory() );
+}
+
+
+void SfxHelpWindow_Impl::openDone(std::u16string_view sURL ,
+ bool bSuccess)
+{
+ INetURLObject aObj( sURL );
+ if ( aObj.GetProtocol() == INetProtocol::VndSunStarHelp )
+ SetFactory( aObj.GetHost() );
+ if ( IsWait() )
+ LeaveWait();
+ if ( bGrabFocusToToolBox )
+ {
+ pTextWin->GetToolBox().grab_focus();
+ bGrabFocusToToolBox = false;
+ }
+ else
+ xIndexWin->GrabFocusBack();
+ if ( !bSuccess )
+ return;
+
+ // set some view settings: "prevent help tips" and "helpid == 68245"
+ try
+ {
+ Reference < XController > xController = pTextWin->getFrame()->getController();
+ if ( xController.is() )
+ {
+ Reference < XViewSettingsSupplier > xSettings( xController, UNO_QUERY );
+ Reference < XPropertySet > xViewProps = xSettings->getViewSettings();
+ Reference< XPropertySetInfo > xInfo = xViewProps->getPropertySetInfo();
+ xViewProps->setPropertyValue( "ShowContentTips", Any( false ) );
+ xViewProps->setPropertyValue( "ShowGraphics", Any( true ) );
+ xViewProps->setPropertyValue( "ShowTables", Any( true ) );
+ xViewProps->setPropertyValue( "HelpURL", Any( OUString("HID:SFX2_HID_HELP_ONHELP") ) );
+ OUString sProperty( "IsExecuteHyperlinks" );
+ if ( xInfo->hasPropertyByName( sProperty ) )
+ xViewProps->setPropertyValue( sProperty, Any( true ) );
+ xController->restoreViewData(Any());
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::OpenDoneHdl(): unexpected exception" );
+ }
+
+ // When the SearchPage opens the help doc, then select all words, which are equal to its text
+ OUString sSearchText = comphelper::string::strip(xIndexWin->GetSearchText(), ' ');
+ if ( !sSearchText.isEmpty() )
+ pTextWin->SelectSearchText( sSearchText, xIndexWin->IsFullWordSearch() );
+
+ // no page style header -> this prevents a print output of the URL
+ pTextWin->SetPageStyleHeaderOff();
+}
+
+
+SfxHelpWindow_Impl::SfxHelpWindow_Impl(
+ const css::uno::Reference < css::frame::XFrame2 >& rFrame,
+ vcl::Window* pParent ) :
+
+ ResizableDockingWindow(pParent),
+
+ xFrame ( rFrame ),
+ pTextWin ( nullptr ),
+ pHelpInterceptor ( new HelpInterceptor_Impl() ),
+ pHelpListener ( new HelpListener_Impl( pHelpInterceptor ) ),
+ bIndex ( true ),
+ bGrabFocusToToolBox ( false ),
+ bSplit ( false ),
+ nWidth ( 0 ),
+ nIndexSize ( 40 ), // % of width
+ aWinPos ( 0, 0 ),
+ aWinSize ( 0, 0 ),
+ sTitle ( pParent->GetText() )
+{
+ SetStyle(GetStyle() & ~WB_DOCKABLE);
+
+ SetHelpId( HID_HELP_WINDOW );
+
+ m_xBuilder = Application::CreateInterimBuilder(m_xBox.get(), "sfx/ui/helpwindow.ui", false);
+ m_xContainer = m_xBuilder->weld_paned("HelpWindow");
+ m_xContainer->connect_size_allocate(LINK(this, SfxHelpWindow_Impl, ResizeHdl));
+ m_xHelpPaneWindow = m_xBuilder->weld_container("helppanewindow");
+ m_xHelpTextWindow = m_xBuilder->weld_container("helptextwindow");
+ m_xHelpTextXWindow = m_xHelpTextWindow->CreateChildFrame();
+
+ pHelpInterceptor->InitWaiter( this );
+ xIndexWin.reset(new SfxHelpIndexWindow_Impl(this, m_xHelpPaneWindow.get()));
+ xIndexWin->SetDoubleClickHdl( LINK( this, SfxHelpWindow_Impl, OpenHdl ) );
+ xIndexWin->SetSelectFactoryHdl( LINK( this, SfxHelpWindow_Impl, SelectFactoryHdl ) );
+
+ pTextWin = VclPtr<SfxHelpTextWindow_Impl>::Create(this, *m_xBuilder, VCLUnoHelper::GetWindow(m_xHelpTextXWindow));
+ Reference < XFrames > xFrames = rFrame->getFrames();
+ xFrames->append( Reference<XFrame>(pTextWin->getFrame(), UNO_QUERY_THROW) );
+ pTextWin->SetSelectHdl( LINK( this, SfxHelpWindow_Impl, SelectHdl ) );
+ pTextWin->Show();
+ pHelpInterceptor->setInterception( Reference<XFrame>(pTextWin->getFrame(), UNO_QUERY_THROW) );
+ pHelpListener->SetChangeHdl( LINK( this, SfxHelpWindow_Impl, ChangeHdl ) );
+ LoadConfig();
+}
+
+SfxHelpWindow_Impl::~SfxHelpWindow_Impl()
+{
+ disposeOnce();
+}
+
+void SfxHelpWindow_Impl::dispose()
+{
+ SaveConfig();
+ xIndexWin.reset();
+ pTextWin->CloseFrame();
+ pTextWin.disposeAndClear();
+
+ m_xHelpTextXWindow->dispose();
+ m_xHelpTextXWindow.clear();
+ m_xHelpTextWindow.reset();
+ m_xHelpPaneWindow.reset();
+ m_xContainer.reset();
+ m_xBuilder.reset();
+
+ ResizableDockingWindow::dispose();
+}
+
+bool SfxHelpWindow_Impl::PreNotify( NotifyEvent& rNEvt )
+{
+ bool bHandled = false;
+ if ( rNEvt.GetType() == NotifyEventType::KEYINPUT )
+ {
+ // Backward == <ALT><LEFT> or <BACKSPACE> Forward == <ALT><RIGHT>
+ const vcl::KeyCode& rKeyCode = rNEvt.GetKeyEvent()->GetKeyCode();
+ sal_uInt16 nKey = rKeyCode.GetCode();
+ if ( ( rKeyCode.IsMod2() && ( KEY_LEFT == nKey || KEY_RIGHT == nKey ) ) ||
+ ( !rKeyCode.GetModifier() && KEY_BACKSPACE == nKey && !xIndexWin->HasFocusOnEdit() ) )
+ {
+ DoAction( rKeyCode.GetCode() == KEY_RIGHT ? u"forward" : u"backward" );
+ bHandled = true;
+ }
+ else if ( rKeyCode.IsMod1() && ( KEY_F4 == nKey || KEY_W == nKey ) )
+ {
+ // <CTRL><F4> or <CTRL><W> -> close top frame
+ CloseWindow();
+ bHandled = true;
+ }
+ }
+ return bHandled || Window::PreNotify( rNEvt );
+}
+
+void SfxHelpWindow_Impl::setContainerWindow( const Reference < css::awt::XWindow >& xWin )
+{
+ xWindow = xWin;
+ MakeLayout();
+ if (xWindow.is())
+ {
+ VclPtr<vcl::Window> pScreenWin = VCLUnoHelper::GetWindow(xWindow);
+ if (aWinSize.Width() && aWinSize.Height())
+ pScreenWin->SetPosSizePixel(Point(aWinPos), aWinSize);
+ else
+ pScreenWin->SetPosPixel(Point(aWinPos));
+ }
+}
+
+void SfxHelpWindow_Impl::SetFactory( const OUString& rFactory )
+{
+ xIndexWin->SetFactory( rFactory, true );
+}
+
+void SfxHelpWindow_Impl::SetHelpURL( std::u16string_view rURL )
+{
+ INetURLObject aObj( rURL );
+ if ( aObj.GetProtocol() == INetProtocol::VndSunStarHelp )
+ SetFactory( aObj.GetHost() );
+}
+
+void SfxHelpWindow_Impl::DoAction(std::u16string_view rActionId)
+{
+ if (rActionId == u"index")
+ {
+ bIndex = !bIndex;
+ MakeLayout();
+ pTextWin->ToggleIndex( bIndex );
+ }
+ else if (rActionId == u"start")
+ {
+ ShowStartPage();
+ }
+ else if (rActionId == u"backward" || rActionId == u"forward")
+ {
+ URL aURL;
+ aURL.Complete = ".uno:Backward";
+ if (rActionId == u"forward")
+ aURL.Complete = ".uno:Forward";
+ Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
+ xTrans->parseStrict(aURL);
+ pHelpInterceptor->dispatch( aURL, Sequence < PropertyValue >() );
+ }
+ else if (rActionId == u"searchdialog")
+ {
+ pTextWin->DoSearch();
+ }
+ else if (rActionId == u"print" || rActionId == u"sourceview" || rActionId == u"copy" || rActionId == u"selectionmode")
+ {
+ Reference < XDispatchProvider > xProv = pTextWin->getFrame();
+ if ( xProv.is() )
+ {
+ URL aURL;
+ if (rActionId == u"print")
+ aURL.Complete = ".uno:Print";
+ else if (rActionId == u"sourceview")
+ aURL.Complete = ".uno:SourceView";
+ else if (rActionId == u"copy")
+ aURL.Complete = ".uno:Copy";
+ else // rActionId == "selectionmode"
+ aURL.Complete = ".uno:SelectTextMode";
+ Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
+ xTrans->parseStrict(aURL);
+ Reference < XDispatch > xDisp = xProv->queryDispatch( aURL, OUString(), 0 );
+ if ( xDisp.is() )
+ xDisp->dispatch( aURL, Sequence < PropertyValue >() );
+ }
+ }
+ else if (rActionId == u"bookmarks")
+ {
+ OUString aURL = pHelpInterceptor->GetCurrentURL();
+ if ( !aURL.isEmpty() )
+ {
+ try
+ {
+ Content aCnt( aURL, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ css::uno::Reference< css::beans::XPropertySetInfo > xInfo = aCnt.getProperties();
+ if ( xInfo->hasPropertyByName( PROPERTY_TITLE ) )
+ {
+ css::uno::Any aAny = aCnt.getPropertyValue( PROPERTY_TITLE );
+ OUString aValue;
+ if ( aAny >>= aValue )
+ {
+ SfxAddHelpBookmarkDialog_Impl aDlg(GetFrameWeld(), false);
+ aDlg.SetTitle(aValue);
+ if (aDlg.run() == RET_OK )
+ {
+ xIndexWin->AddBookmarks( aDlg.GetTitle(), aURL );
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::DoAction(): unexpected exception" );
+ }
+ }
+ }
+}
+
+void SfxHelpWindow_Impl::CloseWindow()
+{
+ try
+ {
+ // search for top frame
+ Reference< XFramesSupplier > xCreator = getTextFrame()->getCreator();
+ while ( xCreator.is() && !xCreator->isTop() )
+ {
+ xCreator = xCreator->getCreator();
+ }
+
+ // when found, close it
+ if ( xCreator.is() && xCreator->isTop() )
+ {
+ Reference < XCloseable > xCloser( xCreator, UNO_QUERY );
+ if ( xCloser.is() )
+ xCloser->close( false );
+ }
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelpWindow_Impl::CloseWindow()" );
+ }
+}
+
+
+void SfxHelpWindow_Impl::UpdateToolbox()
+{
+ pTextWin->GetToolBox().set_item_sensitive("backward", pHelpInterceptor->HasHistoryPred());
+ pTextWin->GetToolBox().set_item_sensitive("forward", pHelpInterceptor->HasHistorySucc());
+}
+
+
+bool SfxHelpWindow_Impl::HasHistoryPredecessor() const
+{
+ return pHelpInterceptor->HasHistoryPred();
+}
+
+
+bool SfxHelpWindow_Impl::HasHistorySuccessor() const
+{
+ return pHelpInterceptor->HasHistorySucc();
+}
+
+// class SfxAddHelpBookmarkDialog_Impl -----------------------------------
+
+SfxAddHelpBookmarkDialog_Impl::SfxAddHelpBookmarkDialog_Impl(weld::Widget* pParent, bool bRename)
+ : GenericDialogController(pParent, "sfx/ui/bookmarkdialog.ui", "BookmarkDialog")
+ , m_xTitleED(m_xBuilder->weld_entry("entry"))
+ , m_xAltTitle(m_xBuilder->weld_label("alttitle"))
+{
+ if (bRename)
+ m_xDialog->set_title(m_xAltTitle->get_label());
+}
+
+void SfxAddHelpBookmarkDialog_Impl::SetTitle(const OUString& rTitle)
+{
+ m_xTitleED->set_text(rTitle);
+ m_xTitleED->select_region(0, -1);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/newhelp.hxx b/sfx2/source/appl/newhelp.hxx
new file mode 100644
index 0000000000..8e828dad95
--- /dev/null
+++ b/sfx2/source/appl/newhelp.hxx
@@ -0,0 +1,511 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_SFX2_SOURCE_APPL_NEWHELP_HXX
+#define INCLUDED_SFX2_SOURCE_APPL_NEWHELP_HXX
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/frame/XFrame2.hpp>
+
+#include <rtl/ustrbuf.hxx>
+#include <vcl/builderpage.hxx>
+#include <vcl/dockwin.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/keycod.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/window.hxx>
+
+#include <srchdlg.hxx>
+
+// context menu ids
+#define MID_OPEN 1
+#define MID_RENAME 2
+#define MID_DELETE 3
+
+namespace com::sun::star::awt { class XWindow; }
+namespace com::sun::star::i18n { class XBreakIterator; }
+namespace com::sun::star::text { class XTextRange; }
+
+// class HelpTabPage_Impl ------------------------------------------------
+
+class SfxHelpIndexWindow_Impl;
+
+class HelpTabPage_Impl : public BuilderPage
+{
+protected:
+ SfxHelpIndexWindow_Impl* m_pIdxWin;
+
+public:
+ HelpTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* _pIdxWin,
+ const OUString& rID, const OUString& rUIXMLDescription);
+ virtual ~HelpTabPage_Impl() override;
+};
+
+// class ContentTabPage_Impl ---------------------------------------------
+
+class ContentTabPage_Impl : public HelpTabPage_Impl
+{
+private:
+ std::unique_ptr<weld::TreeView> m_xContentBox;
+ std::unique_ptr<weld::TreeIter> m_xScratchIter;
+ OUString aOpenBookImage;
+ OUString aClosedBookImage;
+ OUString aDocumentImage;
+
+ Link<LinkParamNone*, void> aDoubleClickHdl;
+
+ DECL_LINK(DoubleClickHdl, weld::TreeView&, bool);
+ DECL_LINK(ExpandingHdl, const weld::TreeIter&, bool);
+ DECL_LINK(CollapsingHdl, const weld::TreeIter&, bool);
+
+ void ClearChildren(const weld::TreeIter* pParent);
+ void InitRoot();
+public:
+ ContentTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* _pIdxWin);
+ virtual ~ContentTabPage_Impl() override;
+
+ void SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink);
+ OUString GetSelectedEntry() const;
+ void SetFocusOnBox() { m_xContentBox->grab_focus(); }
+};
+
+class IndexTabPage_Impl : public HelpTabPage_Impl
+{
+private:
+ std::unique_ptr<weld::Entry> m_xIndexEntry;
+ std::unique_ptr<weld::TreeView> m_xIndexList;
+ std::unique_ptr<weld::Button> m_xOpenBtn;
+
+ Idle aFactoryIdle;
+ Idle aAutoCompleteIdle;
+ Timer aKeywordTimer;
+ Link<IndexTabPage_Impl&,void> aKeywordLink;
+
+ OUString sFactory;
+ OUString sKeyword;
+
+ bool bIsActivated;
+ int nRowHeight;
+ int nAllHeight;
+ sal_uInt16 nLastCharCode;
+
+ void InitializeIndex();
+ void ClearIndex();
+
+ Link<LinkParamNone*, void> aDoubleClickHdl;
+
+ DECL_LINK(OpenHdl, weld::Button&, void);
+ DECL_LINK(IdleHdl, Timer*, void);
+ DECL_LINK(AutoCompleteHdl, Timer*, void);
+ DECL_LINK(TimeoutHdl, Timer*, void);
+ DECL_LINK(TreeChangeHdl, weld::TreeView&, void);
+ DECL_LINK(EntryChangeHdl, weld::Entry&, void);
+ DECL_LINK(ActivateHdl, weld::Entry&, bool);
+ DECL_LINK(DoubleClickHdl, weld::TreeView&, bool);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(CustomGetSizeHdl, weld::TreeView::get_size_args, Size);
+ DECL_LINK(CustomRenderHdl, weld::TreeView::render_args, void);
+ DECL_LINK(ResizeHdl, const Size&, void);
+
+ int starts_with(const OUString& rStr, int nStartRow, bool bCaseSensitive);
+
+public:
+ IndexTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin);
+ virtual ~IndexTabPage_Impl() override;
+
+ virtual void Activate() override;
+
+ void SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink);
+ void SetFactory( const OUString& rFactory );
+ const OUString& GetFactory() const { return sFactory; }
+ OUString GetSelectedEntry() const;
+ void SetFocusOnBox() { m_xIndexEntry->grab_focus(); }
+ bool HasFocusOnEdit() const { return m_xIndexEntry->has_focus(); }
+
+ void SetKeywordHdl( const Link<IndexTabPage_Impl&,void>& rLink ) { aKeywordLink = rLink; }
+ void SetKeyword( const OUString& rKeyword );
+ bool HasKeyword() const;
+ bool HasKeywordIgnoreCase();
+ void OpenKeyword();
+
+ void SelectExecutableEntry();
+};
+
+class SearchTabPage_Impl : public HelpTabPage_Impl
+{
+private:
+ std::unique_ptr<weld::ComboBox> m_xSearchED;
+ std::unique_ptr<weld::Button> m_xSearchBtn;
+ std::unique_ptr<weld::CheckButton> m_xFullWordsCB;
+ std::unique_ptr<weld::CheckButton> m_xScopeCB;
+ std::unique_ptr<weld::TreeView> m_xResultsLB;
+ std::unique_ptr<weld::Button> m_xOpenBtn;
+
+ Link<LinkParamNone*, void> aDoubleClickHdl;
+
+ OUString aFactory;
+
+ css::uno::Reference< css::i18n::XBreakIterator >
+ xBreakIterator;
+
+ void ClearSearchResults();
+ void RememberSearchText( const OUString& rSearchText );
+ void Search();
+
+ DECL_LINK(ClickHdl, weld::Button&, void);
+ DECL_LINK(OpenHdl, weld::Button&, void);
+ DECL_LINK(ModifyHdl, weld::ComboBox&, void);
+ DECL_LINK(DoubleClickHdl, weld::TreeView&, bool);
+ DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
+
+public:
+ SearchTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin);
+ virtual ~SearchTabPage_Impl() override;
+
+ void SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink);
+ void SetFactory( const OUString& rFactory ) { aFactory = rFactory; }
+ OUString GetSelectedEntry() const;
+ void ClearPage();
+ void SetFocusOnBox() { m_xResultsLB->grab_focus(); }
+ bool HasFocusOnEdit() const { return m_xSearchED->has_focus(); }
+ OUString GetSearchText() const { return m_xSearchED->get_active_text(); }
+ bool IsFullWordSearch() const { return m_xFullWordsCB->get_active(); }
+ bool OpenKeyword( const OUString& rKeyword );
+};
+
+class BookmarksTabPage_Impl : public HelpTabPage_Impl
+{
+private:
+ std::unique_ptr<weld::TreeView> m_xBookmarksBox;
+ std::unique_ptr<weld::Button> m_xBookmarksPB;
+
+ Link<LinkParamNone*, void> aDoubleClickHdl;
+
+ DECL_LINK(OpenHdl, weld::Button&, void);
+ DECL_LINK(DoubleClickHdl, weld::TreeView&, bool);
+ DECL_LINK(CommandHdl, const CommandEvent&, bool);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+
+ void DoAction(std::u16string_view rAction);
+
+public:
+ BookmarksTabPage_Impl(weld::Widget* pParent, SfxHelpIndexWindow_Impl* pIdxWin);
+ virtual ~BookmarksTabPage_Impl() override;
+
+ void SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink);
+ OUString GetSelectedEntry() const;
+ void AddBookmarks( const OUString& rTitle, const OUString& rURL );
+ void SetFocusOnBox() { m_xBookmarksBox->grab_focus(); }
+};
+
+// class SfxHelpIndexWindow_Impl -----------------------------------------
+
+class SfxHelpWindow_Impl;
+
+class SfxHelpIndexWindow_Impl
+{
+private:
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<weld::ComboBox> m_xActiveLB;
+ std::unique_ptr<weld::Notebook> m_xTabCtrl;
+
+ Idle aIdle;
+
+ Link<SfxHelpIndexWindow_Impl*,void> aSelectFactoryLink;
+ Link<LinkParamNone*,void> aPageDoubleClickLink;
+ Link<IndexTabPage_Impl&,void> aIndexKeywordLink;
+ OUString sKeyword;
+
+ VclPtr<SfxHelpWindow_Impl> pParentWin;
+
+ std::unique_ptr<ContentTabPage_Impl> xCPage;
+ std::unique_ptr<IndexTabPage_Impl> xIPage;
+ std::unique_ptr<SearchTabPage_Impl> xSPage;
+ std::unique_ptr<BookmarksTabPage_Impl> xBPage;
+
+ bool bIsInitDone;
+
+ void Initialize();
+ void SetActiveFactory();
+ HelpTabPage_Impl* GetPage(std::u16string_view );
+
+ inline ContentTabPage_Impl* GetContentPage();
+ inline IndexTabPage_Impl* GetIndexPage();
+ inline SearchTabPage_Impl* GetSearchPage();
+ inline BookmarksTabPage_Impl* GetBookmarksPage();
+
+ DECL_LINK(ActivatePageHdl, const OUString&, void);
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(InitHdl, Timer *, void);
+ DECL_LINK(SelectFactoryHdl, Timer *, void);
+ DECL_LINK(KeywordHdl, IndexTabPage_Impl&, void);
+ DECL_LINK(ContentTabPageDoubleClickHdl, LinkParamNone*, void);
+ DECL_LINK(TabPageDoubleClickHdl, LinkParamNone*, void);
+ DECL_LINK(IndexTabPageDoubleClickHdl, LinkParamNone*, void);
+
+public:
+ explicit SfxHelpIndexWindow_Impl(SfxHelpWindow_Impl* pParent, weld::Container* pContainer);
+ ~SfxHelpIndexWindow_Impl();
+
+ void SetDoubleClickHdl(const Link<LinkParamNone*, void>& rLink);
+ void SetSelectFactoryHdl( const Link<SfxHelpIndexWindow_Impl*,void>& rLink ) { aSelectFactoryLink = rLink; }
+ void SetFactory( const OUString& rFactory, bool bActive );
+ OUString const & GetFactory() const { return xIPage->GetFactory(); }
+ OUString GetSelectedEntry() const;
+ void AddBookmarks( const OUString& rTitle, const OUString& rURL );
+ bool IsValidFactory( std::u16string_view _rFactory );
+ OUString GetActiveFactoryTitle() const { return m_xActiveLB->get_active_text(); }
+ void ClearSearchPage();
+ void GrabFocusBack();
+ bool HasFocusOnEdit() const;
+ OUString GetSearchText() const;
+ bool IsFullWordSearch() const;
+ void OpenKeyword( const OUString& rKeyword );
+ void SelectExecutableEntry();
+
+ weld::Window* GetFrameWeld() const;
+};
+
+// inlines ---------------------------------------------------------------
+
+ContentTabPage_Impl* SfxHelpIndexWindow_Impl::GetContentPage()
+{
+ if (!xCPage)
+ {
+ xCPage.reset(new ContentTabPage_Impl(m_xTabCtrl->get_page("contents"), this));
+ xCPage->SetDoubleClickHdl(LINK(this, SfxHelpIndexWindow_Impl, ContentTabPageDoubleClickHdl));
+ }
+ return xCPage.get();
+}
+
+IndexTabPage_Impl* SfxHelpIndexWindow_Impl::GetIndexPage()
+{
+ if (!xIPage)
+ {
+ xIPage.reset(new IndexTabPage_Impl(m_xTabCtrl->get_page("index"), this));
+ xIPage->SetDoubleClickHdl( LINK(this, SfxHelpIndexWindow_Impl, IndexTabPageDoubleClickHdl) );
+ xIPage->SetKeywordHdl( aIndexKeywordLink );
+ }
+ return xIPage.get();
+}
+
+SearchTabPage_Impl* SfxHelpIndexWindow_Impl::GetSearchPage()
+{
+ if (!xSPage)
+ {
+ xSPage.reset(new SearchTabPage_Impl(m_xTabCtrl->get_page("find"), this));
+ xSPage->SetDoubleClickHdl( LINK(this, SfxHelpIndexWindow_Impl, TabPageDoubleClickHdl) );
+ }
+ return xSPage.get();
+}
+
+BookmarksTabPage_Impl* SfxHelpIndexWindow_Impl::GetBookmarksPage()
+{
+ if (!xBPage)
+ {
+ xBPage.reset(new BookmarksTabPage_Impl(m_xTabCtrl->get_page("bookmarks"), this));
+ xBPage->SetDoubleClickHdl( LINK(this, SfxHelpIndexWindow_Impl, TabPageDoubleClickHdl) );
+ }
+ return xBPage.get();
+}
+
+// class TextWin_Impl ----------------------------------------------------
+class TextWin_Impl : public DockingWindow
+{
+public:
+ explicit TextWin_Impl( vcl::Window* pParent );
+
+ virtual bool EventNotify( NotifyEvent& rNEvt ) override;
+};
+
+// class SfxHelpTextWindow_Impl ------------------------------------------
+
+class SvtMiscOptions;
+class SfxHelpWindow_Impl;
+
+class SfxHelpTextWindow_Impl : public vcl::Window
+{
+private:
+ std::unique_ptr<weld::Toolbar> xToolBox;
+ std::unique_ptr<weld::CheckButton> xOnStartupCB;
+ std::unique_ptr<weld::Menu> xMenu;
+ Idle aSelectIdle;
+ OUString aIndexOnImage;
+ OUString aIndexOffImage;
+ OUString aIndexOnText;
+ OUString aIndexOffText;
+ OUString aSearchText;
+ OUString aOnStartupText;
+ OUString sCurrentFactory;
+
+ VclPtr<SfxHelpWindow_Impl> xHelpWin;
+ VclPtr<vcl::Window> pTextWin;
+ std::shared_ptr<sfx2::SearchDialog> m_xSrchDlg;
+ css::uno::Reference < css::frame::XFrame2 >
+ xFrame;
+ css::uno::Reference< css::i18n::XBreakIterator >
+ xBreakIterator;
+ css::uno::Reference< css::uno::XInterface >
+ xConfiguration;
+ bool bIsDebug;
+ bool bIsIndexOn;
+ bool bIsInClose;
+ bool bIsFullWordSearch;
+
+ bool HasSelection() const;
+ void InitToolBoxImages();
+ void InitOnStartupBox();
+
+ css::uno::Reference< css::i18n::XBreakIterator > const &
+ GetBreakIterator();
+ css::uno::Reference< css::text::XTextRange >
+ getCursor() const;
+ bool isHandledKey( const vcl::KeyCode& _rKeyCode );
+
+ DECL_LINK( SelectHdl, Timer *, void);
+ DECL_LINK( NotifyHdl, LinkParamNone*, void );
+ DECL_LINK( FindHdl, sfx2::SearchDialog&, void );
+ DECL_LINK( CloseHdl, LinkParamNone*, void );
+ DECL_LINK( CheckHdl, weld::Toggleable&, void );
+ void FindHdl(sfx2::SearchDialog*);
+
+public:
+ explicit SfxHelpTextWindow_Impl(SfxHelpWindow_Impl* pHelpWin, weld::Builder& rBuilder, vcl::Window* pParent);
+ virtual ~SfxHelpTextWindow_Impl() override;
+ virtual void dispose() override;
+
+ virtual void Resize() override;
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+ virtual void GetFocus() override;
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+
+ const css::uno::Reference < css::frame::XFrame2 >&
+ getFrame() const { return xFrame; }
+
+ void SetSelectHdl(const Link<const OUString&, void>& rLink) { xToolBox->connect_clicked(rLink); }
+ void ToggleIndex( bool bOn );
+ void SelectSearchText( const OUString& rSearchText, bool _bIsFullWordSearch );
+ void SetPageStyleHeaderOff() const;
+ weld::Toolbar& GetToolBox() { return *xToolBox; }
+ void CloseFrame();
+ void DoSearch();
+};
+
+// class SfxHelpWindow_Impl ----------------------------------------------
+
+class HelpInterceptor_Impl;
+class HelpListener_Impl;
+class SfxHelpWindow_Impl : public ResizableDockingWindow
+{
+private:
+friend class SfxHelpIndexWindow_Impl;
+
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Paned> m_xContainer;
+ std::unique_ptr<weld::Container> m_xHelpPaneWindow;
+ std::unique_ptr<weld::Container> m_xHelpTextWindow;
+ css::uno::Reference<css::awt::XWindow> m_xHelpTextXWindow;
+
+ css::uno::Reference < css::awt::XWindow >
+ xWindow;
+ css::uno::Reference < css::frame::XFrame2 >
+ xFrame;
+
+ std::unique_ptr<SfxHelpIndexWindow_Impl> xIndexWin;
+ VclPtr<SfxHelpTextWindow_Impl> pTextWin;
+ HelpInterceptor_Impl* pHelpInterceptor;
+ rtl::Reference<HelpListener_Impl> pHelpListener;
+
+ bool bIndex;
+ bool bGrabFocusToToolBox;
+ bool bSplit;
+ int nWidth;
+ int nIndexSize;
+ AbsoluteScreenPixelPoint aWinPos;
+ Size aWinSize;
+ OUString sTitle;
+
+ virtual void GetFocus() override;
+
+ void MakeLayout();
+ void LoadConfig();
+ void SaveConfig();
+ void ShowStartPage();
+ void Split();
+
+ DECL_LINK(SelectHdl, const OUString&, void);
+ DECL_LINK(OpenHdl, LinkParamNone*, void);
+ DECL_LINK(SelectFactoryHdl, SfxHelpIndexWindow_Impl*, void);
+ DECL_LINK(ChangeHdl, HelpListener_Impl&, void);
+ DECL_LINK(ResizeHdl, const Size&, void);
+
+public:
+ SfxHelpWindow_Impl( const css::uno::Reference < css::frame::XFrame2 >& rFrame,
+ vcl::Window* pParent );
+ virtual ~SfxHelpWindow_Impl() override;
+ virtual void dispose() override;
+
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+
+ void setContainerWindow( const css::uno::Reference < css::awt::XWindow >& xWin );
+ css::uno::Reference < css::frame::XFrame2 > const &
+ getTextFrame() const { return pTextWin->getFrame(); }
+
+ void SetFactory( const OUString& rFactory );
+ void SetHelpURL( std::u16string_view rURL );
+ void DoAction(std::u16string_view rAction);
+ void CloseWindow();
+
+ weld::Container* GetContainer() { return m_xHelpTextWindow.get(); }
+
+ void UpdateToolbox();
+ void OpenKeyword( const OUString& rKeyword ) { xIndexWin->OpenKeyword( rKeyword ); }
+
+ bool HasHistoryPredecessor() const; // forward to interceptor
+ bool HasHistorySuccessor() const; // forward to interceptor
+
+ void openDone(std::u16string_view sURL ,
+ bool bSuccess);
+
+ static OUString buildHelpURL(std::u16string_view sFactory ,
+ std::u16string_view sContent ,
+ std::u16string_view sAnchor);
+
+ void loadHelpContent(const OUString& sHelpURL ,
+ bool bAddToHistory = true);
+};
+
+class SfxAddHelpBookmarkDialog_Impl : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::Entry> m_xTitleED;
+ std::unique_ptr<weld::Label> m_xAltTitle;
+public:
+ SfxAddHelpBookmarkDialog_Impl(weld::Widget* pParent, bool bRename);
+
+ void SetTitle( const OUString& rTitle );
+ OUString GetTitle() const { return m_xTitleED->get_text(); }
+};
+
+/// Appends ?Language=xy&System=abc to the help URL in rURL
+void AppendConfigToken(OUStringBuffer& rURL, bool bQuestionMark);
+
+#endif // INCLUDED_SFX2_SOURCE_APPL_NEWHELP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/opengrf.cxx b/sfx2/source/appl/opengrf.cxx
new file mode 100644
index 0000000000..3c94ca7ffb
--- /dev/null
+++ b/sfx2/source/appl/opengrf.cxx
@@ -0,0 +1,286 @@
+/* -*- 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 <tools/debug.hxx>
+#include <tools/urlobj.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
+#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <o3tl/any.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/opengrf.hxx>
+#include <sfx2/strings.hrc>
+#include <sfx2/sfxresid.hxx>
+#include <osl/diagnose.h>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::uno;
+using namespace ::cppu;
+
+static TranslateId SvxOpenGrfErr2ResId( ErrCode err )
+{
+ if (err == ERRCODE_GRFILTER_OPENERROR)
+ return RID_SVXSTR_GRFILTER_OPENERROR;
+ else if (err == ERRCODE_GRFILTER_IOERROR)
+ return RID_SVXSTR_GRFILTER_IOERROR;
+ else if (err == ERRCODE_GRFILTER_VERSIONERROR)
+ return RID_SVXSTR_GRFILTER_VERSIONERROR;
+ else if (err == ERRCODE_GRFILTER_FILTERERROR)
+ return RID_SVXSTR_GRFILTER_FILTERERROR;
+ else
+ return RID_SVXSTR_GRFILTER_FORMATERROR;
+}
+
+struct SvxOpenGrf_Impl
+{
+ SvxOpenGrf_Impl(weld::Window* pPreferredParent,
+ sal_Int16 nDialogType);
+
+ sfx2::FileDialogHelper aFileDlg;
+ OUString sDetectedFilter;
+ weld::Window* pDialogParent;
+ uno::Reference < XFilePickerControlAccess > xCtrlAcc;
+};
+
+
+SvxOpenGrf_Impl::SvxOpenGrf_Impl(weld::Window* pPreferredParent,
+ sal_Int16 nDialogType)
+ : aFileDlg(nDialogType, FileDialogFlags::Graphic, pPreferredParent)
+ , pDialogParent(pPreferredParent)
+{
+ uno::Reference < XFilePicker3 > xFP = aFileDlg.GetFilePicker();
+ xCtrlAcc.set(xFP, UNO_QUERY);
+}
+
+
+SvxOpenGraphicDialog::SvxOpenGraphicDialog(const OUString& rTitle, weld::Window* pPreferredParent)
+ : mpImpl(new SvxOpenGrf_Impl(pPreferredParent, ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW))
+{
+ mpImpl->aFileDlg.SetTitle(rTitle);
+ mpImpl->aFileDlg.SetContext(sfx2::FileDialogHelper::InsertImage);
+}
+
+SvxOpenGraphicDialog::SvxOpenGraphicDialog(const OUString& rTitle, weld::Window* pPreferredParent,
+ sal_Int16 nDialogType)
+ : mpImpl(new SvxOpenGrf_Impl(pPreferredParent, nDialogType))
+{
+ mpImpl->aFileDlg.SetTitle(rTitle);
+ mpImpl->aFileDlg.SetContext(sfx2::FileDialogHelper::InsertImage);
+}
+
+SvxOpenGraphicDialog::~SvxOpenGraphicDialog()
+{
+}
+
+ErrCode SvxOpenGraphicDialog::Execute()
+{
+ ErrCode nImpRet;
+ bool bQuitLoop(false);
+
+ while( !bQuitLoop &&
+ mpImpl->aFileDlg.Execute() == ERRCODE_NONE )
+ {
+ if( !GetPath().isEmpty() )
+ {
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ INetURLObject aObj( GetPath() );
+
+ // check whether we can load the graphic
+ OUString aCurFilter( GetCurrentFilter() );
+ sal_uInt16 nFormatNum = rFilter.GetImportFormatNumber( aCurFilter );
+ sal_uInt16 nRetFormat = 0;
+ sal_uInt16 nFound = USHRT_MAX;
+
+ // non-local?
+ if ( INetProtocol::File != aObj.GetProtocol() )
+ {
+ SfxMedium aMed( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ );
+ aMed.Download();
+ SvStream* pStream = aMed.GetInStream();
+
+ if( pStream )
+ nImpRet = rFilter.CanImportGraphic( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), *pStream, nFormatNum, &nRetFormat );
+ else
+ nImpRet = rFilter.CanImportGraphic( aObj, nFormatNum, &nRetFormat );
+
+ if ( ERRCODE_NONE != nImpRet )
+ {
+ if ( !pStream )
+ nImpRet = rFilter.CanImportGraphic( aObj, GRFILTER_FORMAT_DONTKNOW, &nRetFormat );
+ else
+ nImpRet = rFilter.CanImportGraphic( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), *pStream,
+ GRFILTER_FORMAT_DONTKNOW, &nRetFormat );
+ }
+ }
+ else
+ {
+ nImpRet = rFilter.CanImportGraphic( aObj, nFormatNum, &nRetFormat );
+ if( nImpRet != ERRCODE_NONE )
+ nImpRet = rFilter.CanImportGraphic( aObj, GRFILTER_FORMAT_DONTKNOW, &nRetFormat );
+ }
+
+ if ( ERRCODE_NONE == nImpRet )
+ nFound = nRetFormat;
+
+ // could not load?
+ if ( nFound == USHRT_MAX )
+ {
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(mpImpl->pDialogParent,
+ VclMessageType::Warning, VclButtonsType::NONE,
+ SfxResId(SvxOpenGrfErr2ResId(nImpRet))));
+ xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
+ xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ bQuitLoop = xWarn->run() != RET_RETRY;
+ }
+ else
+ {
+ if( rFilter.GetImportFormatCount() )
+ {
+ // store detected appropriate filter
+ OUString aFormatName(rFilter.GetImportFormatName(nFound));
+ SetDetectedFilter(aFormatName);
+ }
+ else
+ {
+ SetDetectedFilter(mpImpl->aFileDlg.GetCurrentFilter());
+ }
+
+ return nImpRet;
+ }
+ }
+ }
+
+ // cancel
+ return ErrCode(sal_uInt32(-1));
+}
+
+
+void SvxOpenGraphicDialog::SetPath( const OUString& rPath, bool bLinkState )
+{
+ mpImpl->aFileDlg.SetDisplayDirectory(rPath);
+ AsLink(bLinkState);
+}
+
+
+void SvxOpenGraphicDialog::EnableLink( bool state )
+{
+ if( !mpImpl->xCtrlAcc.is() )
+ return;
+
+ try
+ {
+ mpImpl->xCtrlAcc->enableControl( ExtendedFilePickerElementIds::CHECKBOX_LINK, state );
+ }
+ catch(const IllegalArgumentException&)
+ {
+#ifdef DBG_UTIL
+ OSL_FAIL( "Cannot enable \"link\" checkbox" );
+#endif
+ }
+}
+
+
+void SvxOpenGraphicDialog::AsLink(bool bState)
+{
+ if( !mpImpl->xCtrlAcc.is() )
+ return;
+
+ try
+ {
+ mpImpl->xCtrlAcc->setValue( ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, Any(bState) );
+ }
+ catch(const IllegalArgumentException&)
+ {
+#ifdef DBG_UTIL
+ OSL_FAIL( "Cannot check \"link\" checkbox" );
+#endif
+ }
+}
+
+
+bool SvxOpenGraphicDialog::IsAsLink() const
+{
+ try
+ {
+ if( mpImpl->xCtrlAcc.is() )
+ {
+ Any aVal = mpImpl->xCtrlAcc->getValue( ExtendedFilePickerElementIds::CHECKBOX_LINK, 0 );
+ DBG_ASSERT(aVal.hasValue(), "Value CBX_INSERT_AS_LINK not found");
+ return aVal.hasValue() && *o3tl::doAccess<bool>(aVal);
+ }
+ }
+ catch(const IllegalArgumentException&)
+ {
+#ifdef DBG_UTIL
+ OSL_FAIL( "Cannot access \"link\" checkbox" );
+#endif
+ }
+
+ return false;
+}
+
+ErrCode SvxOpenGraphicDialog::GetGraphic(Graphic& rGraphic) const
+{
+ return mpImpl->aFileDlg.GetGraphic(rGraphic);
+}
+
+OUString SvxOpenGraphicDialog::GetPath() const
+{
+ return mpImpl->aFileDlg.GetPath();
+}
+
+OUString SvxOpenGraphicDialog::GetCurrentFilter() const
+{
+ return mpImpl->aFileDlg.GetCurrentFilter();
+}
+
+OUString const & SvxOpenGraphicDialog::GetDetectedFilter() const
+{
+ return mpImpl->sDetectedFilter;
+}
+
+void SvxOpenGraphicDialog::SetCurrentFilter(const OUString& rStr)
+{
+ mpImpl->aFileDlg.SetCurrentFilter(rStr);
+}
+
+void SvxOpenGraphicDialog::SetDetectedFilter(const OUString& rStr)
+{
+ mpImpl->sDetectedFilter = rStr;
+}
+
+Reference<ui::dialogs::XFilePickerControlAccess> const & SvxOpenGraphicDialog::GetFilePickerControlAccess() const
+{
+ return mpImpl->xCtrlAcc;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/openuriexternally.cxx b/sfx2/source/appl/openuriexternally.cxx
new file mode 100644
index 0000000000..bdf8d72766
--- /dev/null
+++ b/sfx2/source/appl/openuriexternally.cxx
@@ -0,0 +1,141 @@
+/* -*- 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/.
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/security/AccessControlException.hpp>
+#include <com/sun/star/system/SystemShellExecute.hpp>
+#include <com/sun/star/system/SystemShellExecuteException.hpp>
+#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <comphelper/processfactory.hxx>
+#include <rtl/ustring.hxx>
+#include <sfx2/sfxresid.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <openuriexternally.hxx>
+#include <comphelper/lok.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+#include <sfx2/viewsh.hxx>
+#include <sfx2/strings.hrc>
+
+namespace {
+
+class URITools
+{
+private:
+ Timer aOpenURITimer { "sfx2::openUriExternallyTimer" };
+ OUString msURI;
+ weld::Widget* mpDialogParent;
+ bool mbHandleSystemShellExecuteException;
+ DECL_LINK(onOpenURI, Timer*, void);
+
+public:
+ URITools(weld::Widget* pDialogParent)
+ : mpDialogParent(pDialogParent)
+ , mbHandleSystemShellExecuteException(false)
+ {
+ }
+ void openURI(const OUString& sURI, bool bHandleSystemShellExecuteException);
+};
+
+}
+
+void URITools::openURI(const OUString& sURI, bool bHandleSystemShellExecuteException)
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (SfxViewShell* pViewShell = SfxViewShell::Current())
+ {
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED,
+ sURI.toUtf8());
+ }
+ delete this;
+ return;
+ }
+
+ mbHandleSystemShellExecuteException = bHandleSystemShellExecuteException;
+ msURI = sURI;
+
+ // tdf#116305 Workaround: Use timer to bring browsers to the front
+ aOpenURITimer.SetInvokeHandler(LINK(this, URITools, onOpenURI));
+#ifdef _WIN32
+ // 200ms seems to be the best compromise between responsiveness and success rate
+ aOpenURITimer.SetTimeout(200);
+#else
+ aOpenURITimer.SetTimeout(0);
+#endif
+ aOpenURITimer.Start();
+}
+
+IMPL_LINK_NOARG(URITools, onOpenURI, Timer*, void)
+{
+ std::unique_ptr<URITools> guard(this);
+ css::uno::Reference< css::system::XSystemShellExecute > exec(
+ css::system::SystemShellExecute::create(comphelper::getProcessComponentContext()));
+ for (sal_Int32 flags = css::system::SystemShellExecuteFlags::URIS_ONLY;;) {
+ try {
+ exec->execute(msURI, OUString(), flags);
+ } catch (css::security::AccessControlException & e) {
+ if (e.LackingPermission.hasValue() || flags == 0) {
+ throw css::uno::RuntimeException(
+ "unexpected AccessControlException: " + e.Message);
+ }
+ SolarMutexGuard g;
+ std::unique_ptr<weld::MessageDialog> eb(
+ Application::CreateMessageDialog(
+ mpDialogParent, VclMessageType::Warning, VclButtonsType::YesNo,
+ SfxResId(STR_DANGEROUS_TO_OPEN)));
+ eb->set_primary_text(eb->get_primary_text().replaceFirst("$(ARG1)", INetURLObject::decode(msURI, INetURLObject::DecodeMechanism::Unambiguous)));
+ eb->set_default_response(RET_NO);
+ if (eb->run() == RET_YES) {
+ flags = 0;
+ continue;
+ }
+ } catch (css::lang::IllegalArgumentException & e) {
+ if (e.ArgumentPosition != 0) {
+ throw css::uno::RuntimeException(
+ "unexpected IllegalArgumentException: " + e.Message);
+ }
+ SolarMutexGuard g;
+ std::unique_ptr<weld::MessageDialog> eb(Application::CreateMessageDialog(mpDialogParent,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SfxResId(STR_NO_ABS_URI_REF)));
+ eb->set_primary_text(eb->get_primary_text().replaceFirst("$(ARG1)", INetURLObject::decode(msURI, INetURLObject::DecodeMechanism::Unambiguous)));
+ eb->run();
+ } catch (css::system::SystemShellExecuteException & e) {
+ if (!mbHandleSystemShellExecuteException) {
+ throw;
+ }
+ SolarMutexGuard g;
+ std::unique_ptr<weld::MessageDialog> eb(Application::CreateMessageDialog(mpDialogParent,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SfxResId(STR_NO_WEBBROWSER_FOUND)));
+ eb->set_primary_text(
+ eb->get_primary_text().replaceFirst("$(ARG1)", msURI)
+ .replaceFirst("$(ARG2)", OUString::number(e.PosixError))
+ .replaceFirst("$(ARG3)", e.Message));
+ //TODO: avoid subsequent replaceFirst acting on previous replacement
+ eb->run();
+ }
+ break;
+ }
+}
+
+void sfx2::openUriExternally(const OUString& sURI, bool bHandleSystemShellExecuteException, weld::Widget* pDialogParent)
+{
+ URITools* uriTools = new URITools(pDialogParent);
+ uriTools->openURI(sURI, bHandleSystemShellExecuteException);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/preventduplicateinteraction.cxx b/sfx2/source/appl/preventduplicateinteraction.cxx
new file mode 100644
index 0000000000..c7d6341fa8
--- /dev/null
+++ b/sfx2/source/appl/preventduplicateinteraction.cxx
@@ -0,0 +1,220 @@
+/* -*- 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 <preventduplicateinteraction.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/task/XInteractionAbort.hpp>
+#include <utility>
+
+namespace sfx2 {
+
+PreventDuplicateInteraction::PreventDuplicateInteraction(css::uno::Reference< css::uno::XComponentContext > xContext)
+ : m_xContext(std::move(xContext))
+{
+}
+
+PreventDuplicateInteraction::~PreventDuplicateInteraction()
+{
+}
+
+void PreventDuplicateInteraction::setHandler(const css::uno::Reference< css::task::XInteractionHandler >& xHandler)
+{
+ // SAFE ->
+ std::unique_lock aLock(m_aLock);
+ m_xWarningDialogsParent.reset();
+ m_xHandler = xHandler;
+ // <- SAFE
+}
+
+void PreventDuplicateInteraction::useDefaultUUIHandler()
+{
+ //if we use the default handler, set the parent to a window belonging to this object so that the dialogs
+ //don't block unrelated windows.
+ m_xWarningDialogsParent.reset(new WarningDialogsParentScope(m_xContext));
+ css::uno::Reference<css::task::XInteractionHandler> xHandler(css::task::InteractionHandler::createWithParent(
+ m_xContext, m_xWarningDialogsParent->GetDialogParent()), css::uno::UNO_QUERY_THROW);
+
+ // SAFE ->
+ std::unique_lock aLock(m_aLock);
+ m_xHandler = xHandler;
+ // <- SAFE
+}
+
+css::uno::Any SAL_CALL PreventDuplicateInteraction::queryInterface( const css::uno::Type& aType )
+{
+ if ( aType.equals( cppu::UnoType<XInteractionHandler2>::get() ) )
+ {
+ std::unique_lock aLock(m_aLock);
+ css::uno::Reference< css::task::XInteractionHandler2 > xHandler( m_xHandler, css::uno::UNO_QUERY );
+ if ( !xHandler.is() )
+ return css::uno::Any();
+ }
+ return ::cppu::WeakImplHelper<css::lang::XInitialization, css::task::XInteractionHandler2>::queryInterface(aType);
+}
+
+void SAL_CALL PreventDuplicateInteraction::handle(const css::uno::Reference< css::task::XInteractionRequest >& xRequest)
+{
+ css::uno::Any aRequest = xRequest->getRequest();
+ bool bHandleIt = true;
+
+ // SAFE ->
+ std::unique_lock aLock(m_aLock);
+
+ auto pIt = std::find_if(m_lInteractionRules.begin(), m_lInteractionRules.end(),
+ [&aRequest](const InteractionInfo& rInfo) { return aRequest.isExtractableTo(rInfo.m_aInteraction); });
+ if (pIt != m_lInteractionRules.end())
+ {
+ InteractionInfo& rInfo = *pIt;
+
+ ++rInfo.m_nCallCount;
+ rInfo.m_xRequest = xRequest;
+ bHandleIt = (rInfo.m_nCallCount <= rInfo.m_nMaxCount);
+ }
+
+ css::uno::Reference< css::task::XInteractionHandler > xHandler = m_xHandler;
+
+ aLock.unlock();
+ // <- SAFE
+
+ if ( bHandleIt && xHandler.is() )
+ {
+ xHandler->handle(xRequest);
+ }
+ else
+ {
+ const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations = xRequest->getContinuations();
+ for (const auto& rContinuation : lContinuations)
+ {
+ css::uno::Reference< css::task::XInteractionAbort > xAbort(rContinuation, css::uno::UNO_QUERY);
+ if (xAbort.is())
+ {
+ xAbort->select();
+ break;
+ }
+ }
+ }
+}
+
+sal_Bool SAL_CALL PreventDuplicateInteraction::handleInteractionRequest( const css::uno::Reference< css::task::XInteractionRequest >& xRequest )
+{
+ css::uno::Any aRequest = xRequest->getRequest();
+ bool bHandleIt = true;
+
+ // SAFE ->
+ std::unique_lock aLock(m_aLock);
+
+ auto pIt = std::find_if(m_lInteractionRules.begin(), m_lInteractionRules.end(),
+ [&aRequest](const InteractionInfo& rInfo) { return aRequest.isExtractableTo(rInfo.m_aInteraction); });
+ if (pIt != m_lInteractionRules.end())
+ {
+ InteractionInfo& rInfo = *pIt;
+
+ ++rInfo.m_nCallCount;
+ rInfo.m_xRequest = xRequest;
+ bHandleIt = (rInfo.m_nCallCount <= rInfo.m_nMaxCount);
+ }
+
+ css::uno::Reference< css::task::XInteractionHandler2 > xHandler( m_xHandler, css::uno::UNO_QUERY );
+ OSL_ENSURE( xHandler.is() || !m_xHandler.is(),
+ "PreventDuplicateInteraction::handleInteractionRequest: inconsistency!" );
+
+ aLock.unlock();
+ // <- SAFE
+
+ if ( bHandleIt && xHandler.is() )
+ {
+ return xHandler->handleInteractionRequest(xRequest);
+ }
+ else
+ {
+ const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations = xRequest->getContinuations();
+ for (const auto& rContinuation : lContinuations)
+ {
+ css::uno::Reference< css::task::XInteractionAbort > xAbort(rContinuation, css::uno::UNO_QUERY);
+ if (xAbort.is())
+ {
+ xAbort->select();
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+void PreventDuplicateInteraction::addInteractionRule(const PreventDuplicateInteraction::InteractionInfo& aInteractionInfo)
+{
+ // SAFE ->
+ std::unique_lock aLock(m_aLock);
+
+ auto pIt = std::find_if(m_lInteractionRules.begin(), m_lInteractionRules.end(),
+ [&aInteractionInfo](const InteractionInfo& rInfo) { return rInfo.m_aInteraction == aInteractionInfo.m_aInteraction; });
+ if (pIt != m_lInteractionRules.end())
+ {
+ InteractionInfo& rInfo = *pIt;
+ rInfo.m_nMaxCount = aInteractionInfo.m_nMaxCount;
+ rInfo.m_nCallCount = aInteractionInfo.m_nCallCount;
+ return;
+ }
+
+ m_lInteractionRules.push_back(aInteractionInfo);
+ // <- SAFE
+}
+
+bool PreventDuplicateInteraction::getInteractionInfo(const css::uno::Type& aInteraction,
+ PreventDuplicateInteraction::InteractionInfo* pReturn ) const
+{
+ // SAFE ->
+ std::unique_lock aLock(m_aLock);
+
+ auto pIt = std::find_if(m_lInteractionRules.begin(), m_lInteractionRules.end(),
+ [&aInteraction](const InteractionInfo& rInfo) { return rInfo.m_aInteraction == aInteraction; });
+ if (pIt != m_lInteractionRules.end())
+ {
+ *pReturn = *pIt;
+ return true;
+ }
+ // <- SAFE
+
+ return false;
+}
+
+void SAL_CALL PreventDuplicateInteraction::initialize(const css::uno::Sequence<css::uno::Any>& rArguments)
+{
+ // If we're re-initialized to set a specific new window as a parent then drop our temporary
+ // dialog parent
+ css::uno::Reference<css::lang::XInitialization> xHandler(m_xHandler, css::uno::UNO_QUERY);
+ if (xHandler.is())
+ {
+ m_xWarningDialogsParent.reset();
+ xHandler->initialize(rArguments);
+ }
+}
+
+IMPL_STATIC_LINK_NOARG(WarningDialogsParent, TerminateDesktop, void*, void)
+{
+ css::frame::Desktop::create(comphelper::getProcessComponentContext())->terminate();
+}
+
+} // namespace sfx2
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/sfxhelp.cxx b/sfx2/source/appl/sfxhelp.cxx
new file mode 100644
index 0000000000..b596a4e33e
--- /dev/null
+++ b/sfx2/source/appl/sfxhelp.cxx
@@ -0,0 +1,1401 @@
+/* -*- 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 <config_folders.h>
+#include <sfx2/sfxhelp.hxx>
+
+#include <string_view>
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#ifdef MACOSX
+#include <premac.h>
+#include <Foundation/NSString.h>
+#include <CoreFoundation/CFURL.h>
+#include <CoreServices/CoreServices.h>
+#include <postmac.h>
+#endif
+
+#include <sal/log.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/UnknownModuleException.hpp>
+#include <com/sun/star/frame/XFrame2.hpp>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <unotools/configmgr.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <tools/urlobj.hxx>
+#include <ucbhelper/content.hxx>
+#include <unotools/pathoptions.hxx>
+#include <rtl/byteseq.hxx>
+#include <rtl/ustring.hxx>
+#include <o3tl/string_view.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <osl/process.h>
+#include <osl/file.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/securityoptions.hxx>
+#include <rtl/uri.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/keycod.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/locktoplevels.hxx>
+#include <vcl/weld.hxx>
+#include <openuriexternally.hxx>
+
+#include <comphelper/lok.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <sfx2/viewsh.hxx>
+
+#include "newhelp.hxx"
+#include <sfx2/flatpak.hxx>
+#include <sfx2/sfxresid.hxx>
+#include <helper.hxx>
+#include <sfx2/strings.hrc>
+#include <vcl/svapp.hxx>
+#include <rtl/string.hxx>
+#include <svtools/langtab.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+
+namespace {
+
+class NoHelpErrorBox
+{
+private:
+ std::unique_ptr<weld::MessageDialog> m_xErrBox;
+public:
+ DECL_STATIC_LINK(NoHelpErrorBox, HelpRequestHdl, weld::Widget&, bool);
+public:
+ explicit NoHelpErrorBox(weld::Widget* pParent)
+ : m_xErrBox(Application::CreateMessageDialog(pParent, VclMessageType::Error, VclButtonsType::Ok,
+ SfxResId(RID_STR_HLPFILENOTEXIST)))
+ {
+ // Error message: "No help available"
+ m_xErrBox->connect_help(LINK(nullptr, NoHelpErrorBox, HelpRequestHdl));
+ }
+ void run()
+ {
+ m_xErrBox->run();
+ }
+};
+
+}
+
+IMPL_STATIC_LINK_NOARG(NoHelpErrorBox, HelpRequestHdl, weld::Widget&, bool)
+{
+ // do nothing, because no help available
+ return false;
+}
+
+static OUString const & HelpLocaleString();
+
+namespace {
+
+/// Root path of the help.
+OUString const & getHelpRootURL()
+{
+ static OUString const s_instURL = []()
+ {
+ OUString tmp = officecfg::Office::Common::Path::Current::Help::get();
+ if (tmp.isEmpty())
+ {
+ // try to determine path from default
+ tmp = "$(instpath)/" LIBO_SHARE_HELP_FOLDER;
+ }
+
+ // replace anything like $(instpath);
+ SvtPathOptions aOptions;
+ tmp = aOptions.SubstituteVariable(tmp);
+
+ OUString url;
+ if (osl::FileBase::getFileURLFromSystemPath(tmp, url) == osl::FileBase::E_None)
+ tmp = url;
+ return tmp;
+ }();
+ return s_instURL;
+}
+
+bool impl_checkHelpLocalePath(OUString const & rpPath)
+{
+ osl::DirectoryItem directoryItem;
+ bool bOK = false;
+
+ osl::FileStatus fileStatus(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL | osl_FileStatus_Mask_FileName);
+ if (osl::DirectoryItem::get(rpPath, directoryItem) == osl::FileBase::E_None &&
+ directoryItem.getFileStatus(fileStatus) == osl::FileBase::E_None &&
+ fileStatus.isDirectory())
+ {
+ bOK = true;
+ }
+ return bOK;
+}
+
+/// Check for built-in help
+/// Check if help/<lang>/err.html file exist
+bool impl_hasHelpInstalled()
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ return false;
+
+ // detect installed locale
+ static OUString const aLocaleStr = HelpLocaleString();
+
+ OUString helpRootURL = getHelpRootURL() + "/" + aLocaleStr + "/err.html";
+ bool bOK = false;
+ osl::DirectoryItem directoryItem;
+ if(osl::DirectoryItem::get(helpRootURL, directoryItem) == osl::FileBase::E_None){
+ bOK=true;
+ }
+
+ SAL_INFO( "sfx.appl", "Checking old help installed " << bOK);
+ return bOK;
+}
+
+/// Check for html built-in help
+/// Check if help/lang/text folder exist. Only html has it.
+bool impl_hasHTMLHelpInstalled()
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ return false;
+
+ // detect installed locale
+ static OUString const aLocaleStr = HelpLocaleString();
+
+ OUString helpRootURL = getHelpRootURL() + "/" + aLocaleStr + "/text";
+ bool bOK = impl_checkHelpLocalePath( helpRootURL );
+ SAL_INFO( "sfx.appl", "Checking new help (html) installed " << bOK);
+ return bOK;
+}
+
+} // namespace
+
+/// Return the locale we prefer for displaying help
+static OUString const & HelpLocaleString()
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ return comphelper::LibreOfficeKit::getLanguageTag().getBcp47();
+
+ static OUString aLocaleStr;
+ if (!aLocaleStr.isEmpty())
+ return aLocaleStr;
+
+ static constexpr OUString aEnglish(u"en-US"_ustr);
+ // detect installed locale
+ aLocaleStr = utl::ConfigManager::getUILocale();
+
+ if ( aLocaleStr.isEmpty() )
+ {
+ aLocaleStr = aEnglish;
+ return aLocaleStr;
+ }
+
+ // get fall-back language (country)
+ OUString sLang = aLocaleStr;
+ sal_Int32 nSepPos = sLang.indexOf( '-' );
+ if (nSepPos != -1)
+ {
+ sLang = sLang.copy( 0, nSepPos );
+ }
+ OUString sHelpPath("");
+ sHelpPath = getHelpRootURL() + "/" + utl::ConfigManager::getProductVersion() + "/" + aLocaleStr;
+ if (impl_checkHelpLocalePath(sHelpPath))
+ {
+ return aLocaleStr;
+ }
+ sHelpPath = getHelpRootURL() + "/" + utl::ConfigManager::getProductVersion() + "/" + sLang;
+ if (impl_checkHelpLocalePath(sHelpPath))
+ {
+ aLocaleStr = sLang;
+ return aLocaleStr;
+ }
+ sHelpPath = getHelpRootURL() + "/" + aLocaleStr;
+ if (impl_checkHelpLocalePath(sHelpPath))
+ {
+ return aLocaleStr;
+ }
+ sHelpPath = getHelpRootURL() + "/" + sLang;
+ if (impl_checkHelpLocalePath(sHelpPath))
+ {
+ aLocaleStr = sLang;
+ return aLocaleStr;
+ }
+ sHelpPath = getHelpRootURL() + "/" + utl::ConfigManager::getProductVersion() + "/" + aEnglish;
+ if (impl_checkHelpLocalePath(sHelpPath))
+ {
+ aLocaleStr = aEnglish;
+ return aLocaleStr;
+ }
+ sHelpPath = getHelpRootURL() + "/" + aEnglish;
+ if (impl_checkHelpLocalePath(sHelpPath))
+ {
+ aLocaleStr = aEnglish;
+ return aLocaleStr;
+ }
+ return aLocaleStr;
+}
+
+
+
+void AppendConfigToken( OUStringBuffer& rURL, bool bQuestionMark )
+{
+ OUString aLocaleStr = HelpLocaleString();
+
+ // query part exists?
+ if ( bQuestionMark )
+ // no, so start with '?'
+ rURL.append('?');
+ else
+ // yes, so only append with '&'
+ rURL.append('&');
+
+ // set parameters
+ rURL.append("Language=");
+ rURL.append(aLocaleStr);
+ rURL.append("&System=");
+ rURL.append(officecfg::Office::Common::Help::System::get());
+ rURL.append("&Version=");
+ rURL.append(utl::ConfigManager::getProductVersion());
+}
+
+static bool GetHelpAnchor_Impl( std::u16string_view _rURL, OUString& _rAnchor )
+{
+ bool bRet = false;
+
+ try
+ {
+ ::ucbhelper::Content aCnt( INetURLObject( _rURL ).GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ Reference< css::ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext() );
+ OUString sAnchor;
+ if ( aCnt.getPropertyValue("AnchorName") >>= sAnchor )
+ {
+
+ if ( !sAnchor.isEmpty() )
+ {
+ _rAnchor = sAnchor;
+ bRet = true;
+ }
+ }
+ else
+ {
+ SAL_WARN( "sfx.appl", "Property 'AnchorName' is missing" );
+ }
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+
+ return bRet;
+}
+
+namespace {
+
+class SfxHelp_Impl
+{
+public:
+ static OUString GetHelpText( const OUString& aCommandURL, const OUString& rModule );
+};
+
+}
+
+OUString SfxHelp_Impl::GetHelpText( const OUString& aCommandURL, const OUString& rModule )
+{
+ // create help url
+ OUStringBuffer aHelpURL( SfxHelp::CreateHelpURL( aCommandURL, rModule ) );
+ // added 'active' parameter
+ sal_Int32 nIndex = aHelpURL.lastIndexOf( '#' );
+ if ( nIndex < 0 )
+ nIndex = aHelpURL.getLength();
+ aHelpURL.insert( nIndex, "&Active=true" );
+ // load help string
+ return SfxContentHelper::GetActiveHelpString( aHelpURL.makeStringAndClear() );
+}
+
+SfxHelp::SfxHelp()
+ : bIsDebug(false)
+ , bLaunchingHelp(false)
+{
+ // read the environment variable "HELP_DEBUG"
+ // if it's set, you will see debug output on active help
+ OUString sHelpDebug;
+ OUString sEnvVarName( "HELP_DEBUG" );
+ osl_getEnvironment( sEnvVarName.pData, &sHelpDebug.pData );
+ bIsDebug = !sHelpDebug.isEmpty();
+}
+
+SfxHelp::~SfxHelp()
+{
+}
+
+static OUString getDefaultModule_Impl()
+{
+ OUString sDefaultModule;
+ SvtModuleOptions aModOpt;
+ if ( aModOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) )
+ sDefaultModule = "swriter";
+ else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) )
+ sDefaultModule = "scalc";
+ else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) )
+ sDefaultModule = "simpress";
+ else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::EModule::DRAW ) )
+ sDefaultModule = "sdraw";
+ else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::EModule::MATH ) )
+ sDefaultModule = "smath";
+ else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::EModule::CHART ) )
+ sDefaultModule = "schart";
+ else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::EModule::BASIC ) )
+ sDefaultModule = "sbasic";
+ else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
+ sDefaultModule = "sdatabase";
+ else
+ {
+ SAL_WARN( "sfx.appl", "getDefaultModule_Impl(): no module installed" );
+ }
+ return sDefaultModule;
+}
+
+static OUString getCurrentModuleIdentifier_Impl()
+{
+ OUString sIdentifier;
+ Reference < XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ Reference < XModuleManager2 > xModuleManager = ModuleManager::create(xContext);
+ Reference < XDesktop2 > xDesktop = Desktop::create(xContext);
+ Reference < XFrame > xCurrentFrame = xDesktop->getCurrentFrame();
+
+ if ( xCurrentFrame.is() )
+ {
+ try
+ {
+ sIdentifier = xModuleManager->identify( xCurrentFrame );
+ }
+ catch (const css::frame::UnknownModuleException&)
+ {
+ SAL_INFO( "sfx.appl", "SfxHelp::getCurrentModuleIdentifier_Impl(): unknown module (help in help?)" );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelp::getCurrentModuleIdentifier_Impl(): exception of XModuleManager::identify()" );
+ }
+ }
+
+ return sIdentifier;
+}
+
+namespace
+{
+ OUString MapModuleIdentifier(const OUString &rFactoryShortName)
+ {
+ OUString aFactoryShortName(rFactoryShortName);
+
+ // Map some module identifiers to their "real" help module string.
+ if ( aFactoryShortName == "chart2" )
+ aFactoryShortName = "schart" ;
+ else if ( aFactoryShortName == "BasicIDE" )
+ aFactoryShortName = "sbasic";
+ else if ( aFactoryShortName == "sweb"
+ || aFactoryShortName == "sglobal"
+ || aFactoryShortName == "swxform" )
+ aFactoryShortName = "swriter" ;
+ else if ( aFactoryShortName == "dbquery"
+ || aFactoryShortName == "dbbrowser"
+ || aFactoryShortName == "dbrelation"
+ || aFactoryShortName == "dbtable"
+ || aFactoryShortName == "dbapp"
+ || aFactoryShortName == "dbreport"
+ || aFactoryShortName == "dbtdata"
+ || aFactoryShortName == "swreport"
+ || aFactoryShortName == "swform" )
+ aFactoryShortName = "sdatabase";
+ else if ( aFactoryShortName == "sbibliography"
+ || aFactoryShortName == "sabpilot"
+ || aFactoryShortName == "scanner"
+ || aFactoryShortName == "spropctrlr"
+ || aFactoryShortName == "StartModule" )
+ aFactoryShortName.clear();
+
+ return aFactoryShortName;
+ }
+}
+
+OUString SfxHelp::GetHelpModuleName_Impl(std::u16string_view rHelpID)
+{
+ OUString aFactoryShortName;
+
+ //rhbz#1438876 detect preferred module for this help id, e.g. csv dialog
+ //for calc import before any toplevel is created and so context is
+ //otherwise unknown. Cosmetic, same help is shown in any case because its
+ //in the shared section, but title bar would state "Writer" when context is
+ //expected to be "Calc"
+ std::u16string_view sRemainder;
+ if (o3tl::starts_with(rHelpID, u"modules/", &sRemainder))
+ {
+ std::size_t nEndModule = sRemainder.find(u'/');
+ aFactoryShortName = nEndModule != std::u16string_view::npos
+ ? sRemainder.substr(0, nEndModule) : sRemainder;
+ }
+
+ if (aFactoryShortName.isEmpty())
+ {
+ OUString aModuleIdentifier = getCurrentModuleIdentifier_Impl();
+ if (!aModuleIdentifier.isEmpty())
+ {
+ try
+ {
+ Reference < XModuleManager2 > xModuleManager(
+ ModuleManager::create(::comphelper::getProcessComponentContext()) );
+ Sequence< PropertyValue > lProps;
+ xModuleManager->getByName( aModuleIdentifier ) >>= lProps;
+ auto pProp = std::find_if(std::cbegin(lProps), std::cend(lProps),
+ [](const PropertyValue& rProp) { return rProp.Name == "ooSetupFactoryShortName"; });
+ if (pProp != std::cend(lProps))
+ pProp->Value >>= aFactoryShortName;
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sfx.appl", "SfxHelp::GetHelpModuleName_Impl()" );
+ }
+ }
+ }
+
+ if (!aFactoryShortName.isEmpty())
+ aFactoryShortName = MapModuleIdentifier(aFactoryShortName);
+ if (aFactoryShortName.isEmpty())
+ aFactoryShortName = getDefaultModule_Impl();
+
+ return aFactoryShortName;
+}
+
+OUString SfxHelp::CreateHelpURL_Impl( const OUString& aCommandURL, const OUString& rModuleName )
+{
+ // build up the help URL
+ OUStringBuffer aHelpURL("vnd.sun.star.help://");
+ bool bHasAnchor = false;
+ OUString aAnchor;
+
+ OUString aModuleName( rModuleName );
+ if (aModuleName.isEmpty())
+ aModuleName = getDefaultModule_Impl();
+
+ aHelpURL.append(aModuleName);
+
+ if ( aCommandURL.isEmpty() )
+ aHelpURL.append("/start");
+ else
+ {
+ aHelpURL.append("/" +
+ rtl::Uri::encode(aCommandURL,
+ rtl_UriCharClassRelSegment,
+ rtl_UriEncodeKeepEscapes,
+ RTL_TEXTENCODING_UTF8));
+
+ OUStringBuffer aTempURL = aHelpURL;
+ AppendConfigToken( aTempURL, true );
+ bHasAnchor = GetHelpAnchor_Impl(aTempURL, aAnchor);
+ }
+
+ AppendConfigToken( aHelpURL, true );
+
+ if ( bHasAnchor )
+ aHelpURL.append("#" + aAnchor);
+
+ return aHelpURL.makeStringAndClear();
+}
+
+static SfxHelpWindow_Impl* impl_createHelp(Reference< XFrame2 >& rHelpTask ,
+ Reference< XFrame >& rHelpContent)
+{
+ Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
+
+ // otherwise - create new help task
+ Reference< XFrame2 > xHelpTask(
+ xDesktop->findFrame( "OFFICE_HELP_TASK", FrameSearchFlag::TASKS | FrameSearchFlag::CREATE),
+ UNO_QUERY);
+ if (!xHelpTask.is())
+ return nullptr;
+
+ // create all internal windows and sub frames ...
+ Reference< css::awt::XWindow > xParentWindow = xHelpTask->getContainerWindow();
+ VclPtr<vcl::Window> pParentWindow = VCLUnoHelper::GetWindow( xParentWindow );
+ VclPtrInstance<SfxHelpWindow_Impl> pHelpWindow( xHelpTask, pParentWindow );
+ Reference< css::awt::XWindow > xHelpWindow = VCLUnoHelper::GetInterface( pHelpWindow );
+
+ Reference< XFrame > xHelpContent;
+ if (xHelpTask->setComponent( xHelpWindow, Reference< XController >() ))
+ {
+ // Customize UI ...
+ xHelpTask->setName("OFFICE_HELP_TASK");
+
+ Reference< XPropertySet > xProps(xHelpTask, UNO_QUERY);
+ if (xProps.is())
+ xProps->setPropertyValue(
+ "Title",
+ Any(SfxResId(STR_HELP_WINDOW_TITLE)));
+
+ pHelpWindow->setContainerWindow( xParentWindow );
+ xParentWindow->setVisible(true);
+ xHelpWindow->setVisible(true);
+
+ // This sub frame is created internally (if we called new SfxHelpWindow_Impl() ...)
+ // It should exist :-)
+ xHelpContent = xHelpTask->findFrame("OFFICE_HELP", FrameSearchFlag::CHILDREN);
+ }
+
+ if (!xHelpContent.is())
+ {
+ pHelpWindow.disposeAndClear();
+ return nullptr;
+ }
+
+ xHelpContent->setName("OFFICE_HELP");
+
+ rHelpTask = xHelpTask;
+ rHelpContent = xHelpContent;
+ return pHelpWindow;
+}
+
+OUString SfxHelp::GetHelpText( const OUString& aCommandURL, const vcl::Window* pWindow )
+{
+ OUString sModuleName = GetHelpModuleName_Impl(aCommandURL);
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommandURL, getCurrentModuleIdentifier_Impl());
+ OUString sRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties);
+ OUString sHelpText = SfxHelp_Impl::GetHelpText( sRealCommand.isEmpty() ? aCommandURL : sRealCommand, sModuleName );
+
+ OUString aNewHelpId;
+
+ if (pWindow && sHelpText.isEmpty())
+ {
+ // no help text found -> try with parent help id.
+ vcl::Window* pParent = pWindow->GetParent();
+ while ( pParent )
+ {
+ aNewHelpId = pParent->GetHelpId();
+ sHelpText = SfxHelp_Impl::GetHelpText( aNewHelpId, sModuleName );
+ if (!sHelpText.isEmpty())
+ pParent = nullptr;
+ else
+ pParent = pParent->GetParent();
+ }
+
+ if (bIsDebug && sHelpText.isEmpty())
+ aNewHelpId.clear();
+ }
+
+ // add some debug information?
+ if ( bIsDebug )
+ {
+ sHelpText += "\n-------------\n" +
+ sModuleName + ": " + aCommandURL;
+ if ( !aNewHelpId.isEmpty() )
+ {
+ sHelpText += " - " + aNewHelpId;
+ }
+ }
+
+ return sHelpText;
+}
+
+OUString SfxHelp::GetHelpText(const OUString& aCommandURL, const weld::Widget* pWidget)
+{
+ OUString sModuleName = GetHelpModuleName_Impl(aCommandURL);
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommandURL, getCurrentModuleIdentifier_Impl());
+ OUString sRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties);
+ OUString sHelpText = SfxHelp_Impl::GetHelpText( sRealCommand.isEmpty() ? aCommandURL : sRealCommand, sModuleName );
+
+ OUString aNewHelpId;
+
+ if (pWidget && sHelpText.isEmpty())
+ {
+ // no help text found -> try with parent help id.
+ std::unique_ptr<weld::Widget> xParent(pWidget->weld_parent());
+ while (xParent)
+ {
+ aNewHelpId = xParent->get_help_id();
+ sHelpText = SfxHelp_Impl::GetHelpText( aNewHelpId, sModuleName );
+ if (!sHelpText.isEmpty())
+ xParent.reset();
+ else
+ xParent = xParent->weld_parent();
+ }
+
+ if (bIsDebug && sHelpText.isEmpty())
+ aNewHelpId.clear();
+ }
+
+ // add some debug information?
+ if ( bIsDebug )
+ {
+ sHelpText += "\n-------------\n" +
+ sModuleName + ": " + aCommandURL;
+ if ( !aNewHelpId.isEmpty() )
+ {
+ sHelpText += " - " + aNewHelpId;
+ }
+ }
+
+ return sHelpText;
+}
+
+OUString SfxHelp::GetURLHelpText(std::u16string_view aURL)
+{
+ bool bCtrlClickHlink = SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink);
+
+ // "ctrl-click to follow link:" for not MacOS
+ // "⌘-click to follow link:" for MacOs
+ vcl::KeyCode aCode(KEY_SPACE);
+ vcl::KeyCode aModifiedCode(KEY_SPACE, KEY_MOD1);
+ OUString aModStr(aModifiedCode.GetName());
+ aModStr = aModStr.replaceFirst(aCode.GetName(), "");
+ aModStr = aModStr.replaceAll("+", "");
+ OUString aHelpStr
+ = bCtrlClickHlink ? SfxResId(STR_CTRLCLICKHYPERLINK) : SfxResId(STR_CLICKHYPERLINK);
+ aHelpStr = aHelpStr.replaceFirst("%{key}", aModStr);
+ aHelpStr = aHelpStr.replaceFirst("%{link}", aURL);
+ return aHelpStr;
+}
+
+void SfxHelp::SearchKeyword( const OUString& rKeyword )
+{
+ Start_Impl(OUString(), static_cast<weld::Widget*>(nullptr), rKeyword);
+}
+
+bool SfxHelp::Start( const OUString& rURL, const vcl::Window* pWindow )
+{
+ if (bLaunchingHelp)
+ return true;
+ bLaunchingHelp = true;
+ bool bRet = Start_Impl( rURL, pWindow );
+ bLaunchingHelp = false;
+ return bRet;
+}
+
+bool SfxHelp::Start(const OUString& rURL, weld::Widget* pWidget)
+{
+ if (bLaunchingHelp)
+ return true;
+ bLaunchingHelp = true;
+ bool bRet = Start_Impl(rURL, pWidget, OUString());
+ bLaunchingHelp = false;
+ return bRet;
+}
+
+/// Redirect the vnd.sun.star.help:// urls to http://help.libreoffice.org
+static bool impl_showOnlineHelp(const OUString& rURL, weld::Widget* pDialogParent)
+{
+ static constexpr OUString aInternal(u"vnd.sun.star.help://"_ustr);
+ if ( rURL.getLength() <= aInternal.getLength() || !rURL.startsWith(aInternal) )
+ return false;
+
+ OUString aHelpLink = officecfg::Office::Common::Help::HelpRootURL::get();
+ OUString aTarget = OUString::Concat("Target=") + rURL.subView(aInternal.getLength());
+ aTarget = aTarget.replaceAll("%2F", "/").replaceAll("?", "&");
+ aHelpLink += aTarget;
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if(SfxViewShell* pViewShell = SfxViewShell::Current())
+ {
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED,
+ aHelpLink.toUtf8());
+ return true;
+ }
+ else if (GetpApp())
+ {
+ GetpApp()->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED,
+ aHelpLink.toUtf8());
+ return true;
+ }
+
+ return false;
+ }
+
+ try
+ {
+#ifdef MACOSX
+ LSOpenCFURLRef(CFURLCreateWithString(kCFAllocatorDefault,
+ CFStringCreateWithCString(kCFAllocatorDefault,
+ aHelpLink.toUtf8().getStr(),
+ kCFStringEncodingUTF8),
+ nullptr),
+ nullptr);
+ (void)pDialogParent;
+#else
+ sfx2::openUriExternally(aHelpLink, false, pDialogParent);
+#endif
+ return true;
+ }
+ catch (const Exception&)
+ {
+ }
+ return false;
+}
+
+namespace {
+
+bool rewriteFlatpakHelpRootUrl(OUString * helpRootUrl) {
+ assert(helpRootUrl != nullptr);
+ //TODO: this function for now assumes that the passed-in *helpRootUrl references
+ // /app/libreoffice/help (which belongs to the org.libreoffice.LibreOffice.Help
+ // extension); it replaces it with the corresponding file URL as seen outside the flatpak
+ // sandbox:
+ struct Failure: public std::exception {};
+ try {
+ static auto const url = [] {
+ // From /.flatpak-info [Instance] section, read
+ // app-path=<path>
+ // app-extensions=...;org.libreoffice.LibreOffice.Help=<sha>;...
+ // lines:
+ osl::File ini("file:///.flatpak-info");
+ auto err = ini.open(osl_File_OpenFlag_Read);
+ if (err != osl::FileBase::E_None) {
+ SAL_WARN("sfx.appl", "LIBO_FLATPAK mode failure opening /.flatpak-info: " << err);
+ throw Failure();
+ }
+ OUString path;
+ OUString extensions;
+ bool havePath = false;
+ bool haveExtensions = false;
+ for (bool instance = false; !(havePath && haveExtensions);) {
+ rtl::ByteSequence bytes;
+ err = ini.readLine(bytes);
+ if (err != osl::FileBase::E_None) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode reading /.flatpak-info fails with " << err
+ << " before [Instance] app-path");
+ throw Failure();
+ }
+ std::string_view const line(
+ reinterpret_cast<char const *>(bytes.getConstArray()), bytes.getLength());
+ if (instance) {
+ static constexpr auto keyPath = std::string_view("app-path=");
+ static constexpr auto keyExtensions = std::string_view("app-extensions=");
+ if (!havePath && line.length() >= keyPath.size()
+ && line.substr(0, keyPath.size()) == keyPath.data())
+ {
+ auto const value = line.substr(keyPath.size());
+ if (!rtl_convertStringToUString(
+ &path.pData, value.data(), value.length(),
+ osl_getThreadTextEncoding(),
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
+ {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure converting app-path \"" << value
+ << "\" encoding");
+ throw Failure();
+ }
+ havePath = true;
+ } else if (!haveExtensions && line.length() >= keyExtensions.size()
+ && line.substr(0, keyExtensions.size()) == keyExtensions.data())
+ {
+ auto const value = line.substr(keyExtensions.size());
+ if (!rtl_convertStringToUString(
+ &extensions.pData, value.data(), value.length(),
+ osl_getThreadTextEncoding(),
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
+ {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure converting app-extensions \"" << value
+ << "\" encoding");
+ throw Failure();
+ }
+ haveExtensions = true;
+ } else if (line.length() > 0 && line[0] == '[') {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info lacks [Instance] app-path and"
+ " app-extensions");
+ throw Failure();
+ }
+ } else if (line == "[Instance]") {
+ instance = true;
+ }
+ }
+ ini.close();
+ // Extract <sha> from ...;org.libreoffice.LibreOffice.Help=<sha>;...:
+ OUString sha;
+ for (sal_Int32 i = 0;;) {
+ OUString elem = extensions.getToken(0, ';', i);
+ if (elem.startsWith("org.libreoffice.LibreOffice.Help=", &sha)) {
+ break;
+ }
+ if (i == -1) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info [Instance] app-extensions \""
+ << extensions << "\" org.libreoffice.LibreOffice.Help");
+ throw Failure();
+ }
+ }
+ // Assuming that <path> is of the form
+ // /.../app/org.libreoffice.LibreOffice/<arch>/<branch>/<sha'>/files
+ // rewrite it as
+ // /.../runtime/org.libreoffice.LibreOffice.Help/<arch>/<branch>/<sha>/files
+ // because the extension's files are stored at a different place than the app's files,
+ // so use this hack until flatpak itself provides a better solution:
+ static constexpr OUString segments = u"/app/org.libreoffice.LibreOffice/"_ustr;
+ auto const i1 = path.lastIndexOf(segments);
+ // use lastIndexOf instead of indexOf, in case the user-controlled prefix /.../
+ // happens to contain such segments
+ if (i1 == -1) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
+ << "\" doesn't contain /app/org.libreoffice.LibreOffice/");
+ throw Failure();
+ }
+ auto const i2 = i1 + segments.getLength();
+ auto i3 = path.indexOf('/', i2);
+ if (i3 == -1) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
+ << "\" doesn't contain branch segment");
+ throw Failure();
+ }
+ i3 = path.indexOf('/', i3 + 1);
+ if (i3 == -1) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
+ << "\" doesn't contain sha segment");
+ throw Failure();
+ }
+ ++i3;
+ auto const i4 = path.indexOf('/', i3);
+ if (i4 == -1) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
+ << "\" doesn't contain files segment");
+ throw Failure();
+ }
+ path = path.subView(0, i1) + OUString::Concat("/runtime/org.libreoffice.LibreOffice.Help/")
+ + path.subView(i2, i3 - i2) + sha + path.subView(i4);
+ // Turn <path> into a file URL:
+ OUString url_;
+ err = osl::FileBase::getFileURLFromSystemPath(path, url_);
+ if (err != osl::FileBase::E_None) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure converting app-path \"" << path << "\" to URL: "
+ << err);
+ throw Failure();
+ }
+ return url_;
+ }();
+ *helpRootUrl = url;
+ return true;
+ } catch (Failure &) {
+ return false;
+ }
+}
+
+}
+
+// add <noscript> meta for browsers without javascript
+
+constexpr OUStringLiteral SHTML1 = u"<!DOCTYPE HTML><html lang=\"en-US\"><head><meta charset=\"UTF-8\">";
+constexpr OUStringLiteral SHTML2 = u"<noscript><meta http-equiv=\"refresh\" content=\"0; url='";
+constexpr OUStringLiteral SHTML3 = u"/noscript.html'\"></noscript><meta http-equiv=\"refresh\" content=\"1; url='";
+constexpr OUStringLiteral SHTML4 = u"'\"><script type=\"text/javascript\"> window.location.href = \"";
+constexpr OUStringLiteral SHTML5 = u"\";</script><title>Help Page Redirection</title></head><body></body></html>";
+
+// use a tempfile since e.g. xdg-open doesn't support URL-parameters with file:// URLs
+static bool impl_showOfflineHelp(const OUString& rURL, weld::Widget* pDialogParent)
+{
+ OUString aBaseInstallPath = getHelpRootURL();
+ // For the flatpak case, find the pathname outside the flatpak sandbox that corresponds to
+ // aBaseInstallPath, because that is what needs to be stored in aTempFile below:
+ if (flatpak::isFlatpak() && !rewriteFlatpakHelpRootUrl(&aBaseInstallPath)) {
+ return false;
+ }
+
+ OUString aHelpLink( aBaseInstallPath + "/index.html?" );
+ OUString aTarget = OUString::Concat("Target=") + rURL.subView(RTL_CONSTASCII_LENGTH("vnd.sun.star.help://"));
+ aTarget = aTarget.replaceAll("%2F","/").replaceAll("?","&");
+ aHelpLink += aTarget;
+
+ // Get a html tempfile (for the flatpak case, create it in XDG_CACHE_HOME instead of /tmp for
+ // technical reasons, so that it can be accessed by the browser running outside the sandbox):
+ static constexpr OUStringLiteral aExtension(u".html");
+ OUString * parent = nullptr;
+ if (flatpak::isFlatpak() && !flatpak::createTemporaryHtmlDirectory(&parent)) {
+ return false;
+ }
+ ::utl::TempFileNamed aTempFile(u"NewHelp", true, aExtension, parent, false );
+
+ SvStream* pStream = aTempFile.GetStream(StreamMode::WRITE);
+ pStream->SetStreamCharSet(RTL_TEXTENCODING_UTF8);
+
+ OUString aTempStr = SHTML1 + SHTML2 +
+ aBaseInstallPath + "/" + HelpLocaleString() + SHTML3 +
+ aHelpLink + SHTML4 +
+ aHelpLink + SHTML5;
+
+ pStream->WriteUnicodeOrByteText(aTempStr);
+
+ aTempFile.CloseStream();
+ try
+ {
+#ifdef MACOSX
+ LSOpenCFURLRef(CFURLCreateWithString(kCFAllocatorDefault,
+ CFStringCreateWithCString(kCFAllocatorDefault,
+ aTempFile.GetURL().toUtf8().getStr(),
+ kCFStringEncodingUTF8),
+ nullptr),
+ nullptr);
+ (void)pDialogParent;
+#else
+ sfx2::openUriExternally(aTempFile.GetURL(), false, pDialogParent);
+#endif
+ return true;
+ }
+ catch (const Exception&)
+ {
+ }
+ aTempFile.EnableKillingFile();
+ return false;
+}
+
+namespace
+{
+ // tdf#119579 skip floating windows as potential parent for missing help dialog
+ const vcl::Window* GetBestParent(const vcl::Window* pWindow)
+ {
+ while (pWindow)
+ {
+ if (pWindow->IsSystemWindow() && pWindow->GetType() != WindowType::FLOATINGWINDOW)
+ break;
+ pWindow = pWindow->GetParent();
+ }
+ return pWindow;
+ }
+}
+
+namespace {
+
+class HelpManualMessage : public weld::MessageDialogController
+{
+private:
+ std::unique_ptr<weld::CheckButton> m_xHideOfflineHelpCB;
+
+public:
+ HelpManualMessage(weld::Widget* pParent)
+ : MessageDialogController(pParent, "sfx/ui/helpmanual.ui", "onlinehelpmanual", "hidedialog")
+ , m_xHideOfflineHelpCB(m_xBuilder->weld_check_button("hidedialog"))
+ {
+ LanguageType aLangType = Application::GetSettings().GetUILanguageTag().getLanguageType();
+ OUString sLocaleString = SvtLanguageTable::GetLanguageString(aLangType);
+ OUString sPrimText = get_primary_text();
+ set_primary_text(sPrimText.replaceAll("$UILOCALE", sLocaleString));
+ }
+
+ bool GetOfflineHelpPopUp() const { return !m_xHideOfflineHelpCB->get_active(); }
+};
+
+}
+
+bool SfxHelp::Start_Impl(const OUString& rURL, const vcl::Window* pWindow)
+{
+ OUStringBuffer aHelpRootURL("vnd.sun.star.help://");
+ AppendConfigToken(aHelpRootURL, true);
+ SfxContentHelper::GetResultSet(aHelpRootURL.makeStringAndClear());
+
+ /* rURL may be
+ * - a "real" URL
+ * - a HelpID (formerly a long, now a string)
+ * If rURL is a URL, CreateHelpURL should be called for this URL
+ * If rURL is an arbitrary string, the same should happen, but the URL should be tried out
+ * if it delivers real help content. In case only the Help Error Document is returned, the
+ * parent of the window for that help was called, is asked for its HelpID.
+ * For compatibility reasons this upward search is not implemented for "real" URLs.
+ * Help keyword search now is implemented as own method; in former versions it
+ * was done via Help::Start, but this implementation conflicted with the upward search.
+ */
+ OUString aHelpURL;
+ INetURLObject aParser( rURL );
+ INetProtocol nProtocol = aParser.GetProtocol();
+
+ switch ( nProtocol )
+ {
+ case INetProtocol::VndSunStarHelp:
+ // already a vnd.sun.star.help URL -> nothing to do
+ aHelpURL = rURL;
+ break;
+ default:
+ {
+ OUString aHelpModuleName(GetHelpModuleName_Impl(rURL));
+ OUString aRealCommand;
+
+ if ( nProtocol == INetProtocol::Uno )
+ {
+ // Command can be just an alias to another command.
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(rURL, getCurrentModuleIdentifier_Impl());
+ aRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties);
+ }
+
+ // no URL, just a HelpID (maybe empty in case of keyword search)
+ aHelpURL = CreateHelpURL_Impl( aRealCommand.isEmpty() ? rURL : aRealCommand, aHelpModuleName );
+
+ if ( impl_hasHelpInstalled() && pWindow && SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
+ {
+ // no help found -> try with parent help id.
+ vcl::Window* pParent = pWindow->GetParent();
+ while ( pParent )
+ {
+ OUString aHelpId = pParent->GetHelpId();
+ aHelpURL = CreateHelpURL( aHelpId, aHelpModuleName );
+
+ if ( !SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
+ {
+ break;
+ }
+ else
+ {
+ pParent = pParent->GetParent();
+ if (!pParent)
+ {
+ // create help url of start page ( helpid == 0 -> start page)
+ aHelpURL = CreateHelpURL( OUString(), aHelpModuleName );
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ pWindow = GetBestParent(pWindow);
+ weld::Window* pWeldWindow = pWindow ? pWindow->GetFrameWeld() : nullptr;
+
+ if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ impl_showOnlineHelp(aHelpURL, pWeldWindow);
+ return true;
+ }
+#ifdef MACOSX
+ if (@available(macOS 10.14, *)) {
+ // Workaround: Safari sandboxing prevents it from accessing files in the LibreOffice.app folder
+ // force online-help instead if Safari is default browser.
+ CFURLRef pBrowser = LSCopyDefaultApplicationURLForURL(
+ CFURLCreateWithString(
+ kCFAllocatorDefault,
+ static_cast<CFStringRef>(@"https://www.libreoffice.org"),
+ nullptr),
+ kLSRolesAll, nullptr);
+ if([static_cast<NSString*>(CFURLGetString(pBrowser)) hasSuffix:@"/Applications/Safari.app/"]) {
+ impl_showOnlineHelp(aHelpURL, pWeldWindow);
+ return true;
+ }
+ }
+#endif
+
+ // If the HTML or no help is installed, but aHelpURL nevertheless references valid help content,
+ // that implies that this help content belongs to an extension (and thus would not be available
+ // in neither the offline nor online HTML help); in that case, fall through to the "old-help to
+ // display" code below:
+ if (SfxContentHelper::IsHelpErrorDocument(aHelpURL))
+ {
+ if ( impl_hasHTMLHelpInstalled() && impl_showOfflineHelp(aHelpURL, pWeldWindow) )
+ {
+ return true;
+ }
+
+ if ( !impl_hasHelpInstalled() )
+ {
+ bool bShowOfflineHelpPopUp = officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::get();
+
+ TopLevelWindowLocker aBusy;
+
+ if(bShowOfflineHelpPopUp)
+ {
+ aBusy.incBusy(pWeldWindow);
+ HelpManualMessage aQueryBox(pWeldWindow);
+ short OnlineHelpBox = aQueryBox.run();
+ bShowOfflineHelpPopUp = OnlineHelpBox != RET_OK;
+ auto xChanges = comphelper::ConfigurationChanges::create();
+ officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::set(aQueryBox.GetOfflineHelpPopUp(), xChanges);
+ xChanges->commit();
+ aBusy.decBusy();
+ }
+ if(!bShowOfflineHelpPopUp)
+ {
+ if ( impl_showOnlineHelp(aHelpURL, pWeldWindow) )
+ return true;
+ else
+ {
+ aBusy.incBusy(pWeldWindow);
+ NoHelpErrorBox aErrBox(pWeldWindow);
+ aErrBox.run();
+ aBusy.decBusy();
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ // old-help to display
+ Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
+
+ // check if help window is still open
+ // If not, create a new one and return access directly to the internal sub frame showing the help content
+ // search must be done here; search one desktop level could return an arbitrary frame
+ Reference< XFrame2 > xHelp(
+ xDesktop->findFrame( "OFFICE_HELP_TASK", FrameSearchFlag::CHILDREN),
+ UNO_QUERY);
+ Reference< XFrame > xHelpContent = xDesktop->findFrame(
+ "OFFICE_HELP",
+ FrameSearchFlag::CHILDREN);
+
+ SfxHelpWindow_Impl* pHelpWindow = nullptr;
+ if (!xHelp.is())
+ pHelpWindow = impl_createHelp(xHelp, xHelpContent);
+ else
+ pHelpWindow = static_cast<SfxHelpWindow_Impl*>(VCLUnoHelper::GetWindow(xHelp->getComponentWindow()));
+ if (!xHelp.is() || !xHelpContent.is() || !pHelpWindow)
+ return false;
+
+ SAL_INFO("sfx.appl", "HelpId = " << aHelpURL);
+
+ pHelpWindow->SetHelpURL( aHelpURL );
+ pHelpWindow->loadHelpContent(aHelpURL);
+
+ Reference < css::awt::XTopWindow > xTopWindow( xHelp->getContainerWindow(), UNO_QUERY );
+ if ( xTopWindow.is() )
+ xTopWindow->toFront();
+
+ return true;
+}
+
+bool SfxHelp::Start_Impl(const OUString& rURL, weld::Widget* pWidget, const OUString& rKeyword)
+{
+ OUStringBuffer aHelpRootURL("vnd.sun.star.help://");
+ AppendConfigToken(aHelpRootURL, true);
+ SfxContentHelper::GetResultSet(aHelpRootURL.makeStringAndClear());
+
+ /* rURL may be
+ * - a "real" URL
+ * - a HelpID (formerly a long, now a string)
+ * If rURL is a URL, CreateHelpURL should be called for this URL
+ * If rURL is an arbitrary string, the same should happen, but the URL should be tried out
+ * if it delivers real help content. In case only the Help Error Document is returned, the
+ * parent of the window for that help was called, is asked for its HelpID.
+ * For compatibility reasons this upward search is not implemented for "real" URLs.
+ * Help keyword search now is implemented as own method; in former versions it
+ * was done via Help::Start, but this implementation conflicted with the upward search.
+ */
+ OUString aHelpURL;
+ INetURLObject aParser( rURL );
+ INetProtocol nProtocol = aParser.GetProtocol();
+
+ switch ( nProtocol )
+ {
+ case INetProtocol::VndSunStarHelp:
+ // already a vnd.sun.star.help URL -> nothing to do
+ aHelpURL = rURL;
+ break;
+ default:
+ {
+ OUString aHelpModuleName(GetHelpModuleName_Impl(rURL));
+ OUString aRealCommand;
+
+ if ( nProtocol == INetProtocol::Uno )
+ {
+ // Command can be just an alias to another command.
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(rURL, getCurrentModuleIdentifier_Impl());
+ aRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties);
+ }
+
+ // no URL, just a HelpID (maybe empty in case of keyword search)
+ aHelpURL = CreateHelpURL_Impl( aRealCommand.isEmpty() ? rURL : aRealCommand, aHelpModuleName );
+
+ if ( impl_hasHelpInstalled() && pWidget && SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
+ {
+ bool bUseFinalFallback = true;
+ // no help found -> try ids of parents.
+ pWidget->help_hierarchy_foreach([&aHelpModuleName, &aHelpURL, &bUseFinalFallback](const OUString& rHelpId){
+ if (rHelpId.isEmpty())
+ return false;
+ aHelpURL = CreateHelpURL(rHelpId, aHelpModuleName);
+ bool bFinished = !SfxContentHelper::IsHelpErrorDocument(aHelpURL);
+ if (bFinished)
+ bUseFinalFallback = false;
+ return bFinished;
+ });
+
+ if (bUseFinalFallback)
+ {
+ // create help url of start page ( helpid == 0 -> start page)
+ aHelpURL = CreateHelpURL( OUString(), aHelpModuleName );
+ }
+ }
+ break;
+ }
+ }
+
+ if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ impl_showOnlineHelp(aHelpURL, pWidget);
+ return true;
+ }
+#ifdef MACOSX
+ if (@available(macOS 10.14, *)) {
+ // Workaround: Safari sandboxing prevents it from accessing files in the LibreOffice.app folder
+ // force online-help instead if Safari is default browser.
+ CFURLRef pBrowser = LSCopyDefaultApplicationURLForURL(
+ CFURLCreateWithString(
+ kCFAllocatorDefault,
+ static_cast<CFStringRef>(@"https://www.libreoffice.org"),
+ nullptr),
+ kLSRolesAll, nullptr);
+ if([static_cast<NSString*>(CFURLGetString(pBrowser)) hasSuffix:@"/Applications/Safari.app/"]) {
+ impl_showOnlineHelp(aHelpURL, pWidget);
+ return true;
+ }
+ }
+#endif
+
+ // If the HTML or no help is installed, but aHelpURL nevertheless references valid help content,
+ // that implies that help content belongs to an extension (and thus would not be available
+ // in neither the offline nor online HTML help); in that case, fall through to the "old-help to
+ // display" code below:
+ if (SfxContentHelper::IsHelpErrorDocument(aHelpURL))
+ {
+ if ( impl_hasHTMLHelpInstalled() && impl_showOfflineHelp(aHelpURL, pWidget) )
+ {
+ return true;
+ }
+
+ if ( !impl_hasHelpInstalled() )
+ {
+ bool bShowOfflineHelpPopUp = officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::get();
+
+ TopLevelWindowLocker aBusy;
+
+ if(bShowOfflineHelpPopUp)
+ {
+ aBusy.incBusy(pWidget);
+ HelpManualMessage aQueryBox(pWidget);
+ short OnlineHelpBox = aQueryBox.run();
+ bShowOfflineHelpPopUp = OnlineHelpBox != RET_OK;
+ auto xChanges = comphelper::ConfigurationChanges::create();
+ officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::set(aQueryBox.GetOfflineHelpPopUp(), xChanges);
+ xChanges->commit();
+ aBusy.decBusy();
+ }
+ if(!bShowOfflineHelpPopUp)
+ {
+ if ( impl_showOnlineHelp(aHelpURL, pWidget) )
+ return true;
+ else
+ {
+ aBusy.incBusy(pWidget);
+ NoHelpErrorBox aErrBox(pWidget);
+ aErrBox.run();
+ aBusy.decBusy();
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+ }
+
+ // old-help to display
+ Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
+
+ // check if help window is still open
+ // If not, create a new one and return access directly to the internal sub frame showing the help content
+ // search must be done here; search one desktop level could return an arbitrary frame
+ Reference< XFrame2 > xHelp(
+ xDesktop->findFrame( "OFFICE_HELP_TASK", FrameSearchFlag::CHILDREN),
+ UNO_QUERY);
+ Reference< XFrame > xHelpContent = xDesktop->findFrame(
+ "OFFICE_HELP",
+ FrameSearchFlag::CHILDREN);
+
+ SfxHelpWindow_Impl* pHelpWindow = nullptr;
+ if (!xHelp.is())
+ pHelpWindow = impl_createHelp(xHelp, xHelpContent);
+ else
+ pHelpWindow = static_cast<SfxHelpWindow_Impl*>(VCLUnoHelper::GetWindow(xHelp->getComponentWindow()));
+ if (!xHelp.is() || !xHelpContent.is() || !pHelpWindow)
+ return false;
+
+ SAL_INFO("sfx.appl", "HelpId = " << aHelpURL);
+
+ pHelpWindow->SetHelpURL( aHelpURL );
+ pHelpWindow->loadHelpContent(aHelpURL);
+ if (!rKeyword.isEmpty())
+ pHelpWindow->OpenKeyword( rKeyword );
+
+ Reference < css::awt::XTopWindow > xTopWindow( xHelp->getContainerWindow(), UNO_QUERY );
+ if ( xTopWindow.is() )
+ xTopWindow->toFront();
+
+ return true;
+}
+
+OUString SfxHelp::CreateHelpURL(const OUString& aCommandURL, const OUString& rModuleName)
+{
+ SfxHelp* pHelp = static_cast< SfxHelp* >(Application::GetHelp());
+ return pHelp ? SfxHelp::CreateHelpURL_Impl( aCommandURL, rModuleName ) : OUString();
+}
+
+OUString SfxHelp::GetDefaultHelpModule()
+{
+ return getDefaultModule_Impl();
+}
+
+OUString SfxHelp::GetCurrentModuleIdentifier()
+{
+ return getCurrentModuleIdentifier_Impl();
+}
+
+bool SfxHelp::IsHelpInstalled()
+{
+ return impl_hasHelpInstalled();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/sfxpicklist.cxx b/sfx2/source/appl/sfxpicklist.cxx
new file mode 100644
index 0000000000..64ebcc1a34
--- /dev/null
+++ b/sfx2/source/appl/sfxpicklist.cxx
@@ -0,0 +1,227 @@
+/* -*- 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 <comphelper/lok.hxx>
+#include <comphelper/base64.hxx>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <unotools/historyoptions.hxx>
+#include <unotools/useroptions.hxx>
+#include <tools/datetime.hxx>
+#include <tools/urlobj.hxx>
+#include <svl/inethist.hxx>
+#include <vcl/filter/PngImageWriter.hxx>
+#include <vcl/svapp.hxx>
+#include <officecfg/Office/Common.hxx>
+
+
+#include <sfx2/app.hxx>
+#include <sfxpicklist.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/event.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <openurlhint.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/viewfrm.hxx>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+
+class SfxPickListImpl : public SfxListener
+{
+ /**
+ * Adds the given document to the pick list (recent documents) if it satisfies
+ certain requirements, e.g. being writable. Check implementation for requirement
+ details.
+ */
+ static void AddDocumentToPickList(const SfxObjectShell* pDocShell, bool bNoThumbnail = false);
+
+public:
+ SfxPickListImpl(SfxApplication& rApp);
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+};
+
+void SfxPickListImpl::AddDocumentToPickList(const SfxObjectShell* pDocSh, bool bNoThumbnail)
+{
+ if (pDocSh->IsAvoidRecentDocs() || comphelper::LibreOfficeKit::isActive())
+ return;
+
+ SfxMedium *pMed = pDocSh->GetMedium();
+ if( !pMed )
+ return;
+
+ // Unnamed Documents and embedded-Documents not in Picklist
+ if ( !pDocSh->HasName() ||
+ SfxObjectCreateMode::STANDARD != pDocSh->GetCreateMode() )
+ return;
+
+ // Help not in History
+ INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : pMed->GetOrigURL() );
+ if ( aURL.GetProtocol() == INetProtocol::VndSunStarHelp )
+ return;
+
+ // add no document that forbids this
+ if ( !pMed->IsUpdatePickList() )
+ return;
+
+ // ignore hidden documents
+ if ( !SfxViewFrame::GetFirst( pDocSh ) )
+ return;
+
+ OUString aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
+ OUString aFilter;
+ std::shared_ptr<const SfxFilter> pFilter = pMed->GetFilter();
+ if ( pFilter )
+ aFilter = pFilter->GetFilterName();
+
+ std::optional<OUString> aThumbnail;
+
+ // generate the thumbnail
+ //fdo#74834: only generate thumbnail for history if the corresponding option is not disabled in the configuration
+ if (!bNoThumbnail && !pDocSh->IsModified() && !Application::IsHeadlessModeEnabled() &&
+ officecfg::Office::Common::History::RecentDocsThumbnail::get())
+ {
+ // not modified => the document matches what is in the shell
+ const SfxUnoAnyItem* pEncryptionDataItem = pMed->GetItemSet().GetItem(SID_ENCRYPTIONDATA, false);
+ if ( pEncryptionDataItem )
+ {
+ // encrypted document, will show a generic document icon instead
+ aThumbnail = OUString();
+ }
+ else
+ {
+ BitmapEx aResultBitmap = pDocSh->GetPreviewBitmap();
+ if (!aResultBitmap.IsEmpty())
+ {
+ SvMemoryStream aStream(65535, 65535);
+ vcl::PngImageWriter aWriter(aStream);
+ if (aWriter.write(aResultBitmap))
+ {
+ Sequence<sal_Int8> aSequence(static_cast<const sal_Int8*>(aStream.GetData()), aStream.Tell());
+ OUStringBuffer aBuffer;
+ ::comphelper::Base64::encode(aBuffer, aSequence);
+ aThumbnail = aBuffer.makeStringAndClear();
+ }
+ }
+ }
+ }
+ ::std::optional<bool> const oIsReadOnly(pMed->IsOriginallyLoadedReadOnly());
+
+ // add to svtool history options
+ SvtHistoryOptions::AppendItem( EHistoryType::PickList,
+ aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ),
+ aFilter,
+ aTitle,
+ aThumbnail,
+ oIsReadOnly);
+
+ if ( aURL.GetProtocol() == INetProtocol::File )
+ Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ),
+ pFilter ? pFilter->GetMimeType() : OUString(),
+ pFilter ? pFilter->GetServiceName() : OUString() );
+}
+
+SfxPickList::SfxPickList(SfxApplication& rApp)
+ : mxImpl(new SfxPickListImpl(rApp))
+{
+}
+
+SfxPickList::~SfxPickList()
+{
+}
+
+SfxPickListImpl::SfxPickListImpl(SfxApplication& rApp)
+{
+ StartListening(rApp);
+}
+
+void SfxPickListImpl::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const SfxOpenUrlHint* pOpenUrlHint = dynamic_cast<const SfxOpenUrlHint*>(&rHint);
+ if ( pOpenUrlHint )
+ {
+ INetURLHistory::GetOrCreate()->PutUrl( INetURLObject( pOpenUrlHint->GetDocumentURL() ));
+ }
+
+ if (rHint.GetId() != SfxHintId::ThisIsAnSfxEventHint)
+ return;
+
+ const SfxEventHint& rEventHint = static_cast<const SfxEventHint&>(rHint);
+ // only ObjectShell-related events with media interest
+ SfxObjectShell* pDocSh = rEventHint.GetObjShell();
+ if( !pDocSh )
+ return;
+
+ switch (rEventHint.GetEventId())
+ {
+ case SfxEventHintId::CreateDoc:
+ {
+ bool bAllowModif = pDocSh->IsEnableSetModified();
+ if ( bAllowModif )
+ pDocSh->EnableSetModified( false );
+
+ using namespace ::com::sun::star;
+ uno::Reference<document::XDocumentProperties> xDocProps(
+ pDocSh->getDocProperties());
+ if (xDocProps.is()) {
+ xDocProps->setAuthor( SvtUserOptions().GetFullName() );
+ ::DateTime now( ::DateTime::SYSTEM );
+ xDocProps->setCreationDate( now.GetUNODateTime() );
+ }
+
+ if ( bAllowModif )
+ pDocSh->EnableSetModified( bAllowModif );
+ }
+ break;
+
+ case SfxEventHintId::OpenDoc:
+ case SfxEventHintId::SaveDocDone:
+ case SfxEventHintId::SaveAsDocDone:
+ case SfxEventHintId::SaveToDocDone:
+ case SfxEventHintId::CloseDoc:
+ {
+ const bool bNoThumbnail = rEventHint.GetEventId() == SfxEventHintId::CloseDoc;
+ AddDocumentToPickList(pDocSh, bNoThumbnail);
+ }
+ break;
+
+ case SfxEventHintId::SaveAsDoc:
+ {
+ SfxMedium *pMedium = pDocSh->GetMedium();
+ if (!pMedium)
+ return;
+
+ // We're starting a "Save As". Add the current document (if it's
+ // not a "new" document) to the "Recent Documents" list before we
+ // switch to the new path.
+ // If the current document is new, path will be empty.
+ OUString path = pMedium->GetOrigURL();
+ if (!path.isEmpty())
+ {
+ AddDocumentToPickList(pDocSh);
+ }
+ }
+ break;
+ default: break;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/shutdownicon.cxx b/sfx2/source/appl/shutdownicon.cxx
new file mode 100644
index 0000000000..fca7e56b3f
--- /dev/null
+++ b/sfx2/source/appl/shutdownicon.cxx
@@ -0,0 +1,684 @@
+/* -*- 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 <sal/config.h>
+#include <sal/log.hxx>
+
+#include "shutdownicon.hxx"
+#include <sfx2/strings.hrc>
+#include <sfx2/app.hxx>
+#include <svtools/imagemgr.hxx>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/TerminationVetoException.hpp>
+#include <com/sun/star/frame/XDispatchResultListener.hpp>
+#include <com/sun/star/frame/XNotifyingDispatch.hpp>
+#include <com/sun/star/frame/XFramesSupplier.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
+#include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
+#include <com/sun/star/ui/dialogs/ControlActions.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/document/UpdateDocMode.hpp>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/extract.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/debug.hxx>
+#include <osl/file.hxx>
+#include <osl/module.hxx>
+#include <rtl/ref.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+
+#include <sfx2/sfxresid.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::sfx2;
+
+class SfxNotificationListener_Impl : public cppu::WeakImplHelper< XDispatchResultListener >
+{
+public:
+ virtual void SAL_CALL dispatchFinished( const DispatchResultEvent& aEvent ) override;
+ virtual void SAL_CALL disposing( const EventObject& aEvent ) override;
+};
+
+void SAL_CALL SfxNotificationListener_Impl::dispatchFinished( const DispatchResultEvent& )
+{
+ ShutdownIcon::LeaveModalMode();
+}
+
+void SAL_CALL SfxNotificationListener_Impl::disposing( const EventObject& )
+{
+}
+
+OUString SAL_CALL ShutdownIcon::getImplementationName()
+{
+ return "com.sun.star.comp.desktop.QuickstartWrapper";
+}
+
+sal_Bool SAL_CALL ShutdownIcon::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> SAL_CALL ShutdownIcon::getSupportedServiceNames()
+{
+ return { "com.sun.star.office.Quickstart" };
+}
+
+bool ShutdownIcon::bModalMode = false;
+rtl::Reference<ShutdownIcon> ShutdownIcon::pShutdownIcon;
+
+void ShutdownIcon::initSystray()
+{
+ if (m_bInitialized)
+ return;
+ m_bInitialized = true;
+
+#ifdef ENABLE_QUICKSTART_APPLET
+# ifdef _WIN32
+ win32_init_sys_tray();
+# elif defined MACOSX
+ aqua_init_systray();
+# endif // MACOSX
+#endif // ENABLE_QUICKSTART_APPLET
+}
+
+void ShutdownIcon::deInitSystray()
+{
+ if (!m_bInitialized)
+ return;
+
+#ifdef ENABLE_QUICKSTART_APPLET
+# ifdef _WIN32
+ win32_shutdown_sys_tray();
+# elif defined MACOSX
+ aqua_shutdown_systray();
+# endif // MACOSX
+#endif // ENABLE_QUICKSTART_APPLET
+
+ m_bVeto = false;
+
+ m_pFileDlg.reset();
+ m_bInitialized = false;
+}
+
+static bool UseSystemFileDialog()
+{
+ return !Application::IsHeadlessModeEnabled() && officecfg::Office::Common::Misc::UseSystemFileDialog::get();
+}
+
+ShutdownIcon::ShutdownIcon( css::uno::Reference< XComponentContext > xContext ) :
+ m_bVeto ( false ),
+ m_bListenForTermination ( false ),
+ m_bSystemDialogs(UseSystemFileDialog()),
+ m_xContext(std::move( xContext )),
+ m_bInitialized( false )
+{
+}
+
+ShutdownIcon::~ShutdownIcon()
+{
+ deInitSystray();
+}
+
+
+void ShutdownIcon::OpenURL( const OUString& aURL, const OUString& rTarget, const Sequence< PropertyValue >& aArgs )
+{
+ if ( !getInstance() || !getInstance()->m_xDesktop.is() )
+ return;
+
+ css::uno::Reference < XDispatchProvider > xDispatchProvider = getInstance()->m_xDesktop;
+ if ( !xDispatchProvider.is() )
+ return;
+
+ css::util::URL aDispatchURL;
+ aDispatchURL.Complete = aURL;
+
+ css::uno::Reference< util::XURLTransformer > xURLTransformer( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
+ try
+ {
+ css::uno::Reference< css::frame::XDispatch > xDispatch;
+
+ xURLTransformer->parseStrict( aDispatchURL );
+ xDispatch = xDispatchProvider->queryDispatch( aDispatchURL, rTarget, 0 );
+ if ( xDispatch.is() )
+ xDispatch->dispatch( aDispatchURL, aArgs );
+ }
+ catch ( css::uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( css::uno::Exception& )
+ {
+ }
+}
+
+
+void ShutdownIcon::FileOpen()
+{
+ if ( getInstance() && getInstance()->m_xDesktop.is() )
+ {
+ ::SolarMutexGuard aGuard;
+ EnterModalMode();
+ getInstance()->StartFileDialog();
+ }
+}
+
+
+void ShutdownIcon::FromTemplate()
+{
+ if ( !getInstance() || !getInstance()->m_xDesktop.is() )
+ return;
+
+ css::uno::Reference < css::frame::XFramesSupplier > xDesktop = getInstance()->m_xDesktop;
+ css::uno::Reference < css::frame::XFrame > xFrame( xDesktop->getActiveFrame() );
+ if ( !xFrame.is() )
+ xFrame = xDesktop;
+
+ URL aTargetURL;
+ aTargetURL.Complete = ".uno:NewDoc";
+ css::uno::Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
+ xTrans->parseStrict( aTargetURL );
+
+ css::uno::Reference < css::frame::XDispatchProvider > xProv( xFrame, UNO_QUERY );
+ css::uno::Reference < css::frame::XDispatch > xDisp;
+ if ( xProv.is() )
+ {
+ xDisp = xProv->queryDispatch( aTargetURL, "_self", 0 );
+ }
+ if ( !xDisp.is() )
+ return;
+
+ Sequence<PropertyValue> aArgs { comphelper::makePropertyValue("Referer", OUString("private:user")) };
+ css::uno::Reference< css::frame::XNotifyingDispatch > xNotifier(xDisp, UNO_QUERY);
+ if (xNotifier.is())
+ {
+ EnterModalMode();
+ xNotifier->dispatchWithNotification(aTargetURL, aArgs, new SfxNotificationListener_Impl);
+ }
+ else
+ xDisp->dispatch( aTargetURL, aArgs );
+}
+
+OUString ShutdownIcon::GetUrlDescription( std::u16string_view aUrl )
+{
+ return SvFileInformationManager::GetDescription( INetURLObject( aUrl ) );
+}
+
+void ShutdownIcon::StartFileDialog()
+{
+ ::SolarMutexGuard aGuard;
+
+ bool bDirty = m_bSystemDialogs != UseSystemFileDialog();
+
+ if ( m_pFileDlg && bDirty )
+ {
+ // Destroy instance as changing the system file dialog setting
+ // forces us to create a new FileDialogHelper instance!
+ m_pFileDlg.reset();
+ }
+
+ if ( !m_pFileDlg )
+ m_pFileDlg.reset( new FileDialogHelper(
+ ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
+ FileDialogFlags::MultiSelection, OUString(), SfxFilterFlags::NONE, SfxFilterFlags::NONE, nullptr ) );
+ m_pFileDlg->StartExecuteModal( LINK( this, ShutdownIcon, DialogClosedHdl_Impl ) );
+}
+
+IMPL_LINK( ShutdownIcon, DialogClosedHdl_Impl, FileDialogHelper*, /*unused*/, void )
+{
+ DBG_ASSERT( m_pFileDlg, "ShutdownIcon, DialogClosedHdl_Impl(): no file dialog" );
+
+ // use constructor for filling up filters automatically!
+ if ( ERRCODE_NONE == m_pFileDlg->GetError() )
+ {
+ css::uno::Reference< XFilePicker3 > xPicker = m_pFileDlg->GetFilePicker();
+
+ try
+ {
+
+ if ( xPicker.is() )
+ {
+
+ css::uno::Reference < XFilePickerControlAccess > xPickerControls ( xPicker, UNO_QUERY );
+
+ Sequence< OUString > sFiles = xPicker->getSelectedFiles();
+ int nFiles = sFiles.getLength();
+
+ css::uno::Reference < css::task::XInteractionHandler2 > xInteraction(
+ task::InteractionHandler::createWithParent(::comphelper::getProcessComponentContext(), nullptr) );
+
+ int nArgs=3;
+ Sequence< PropertyValue > aArgs{
+ comphelper::makePropertyValue("InteractionHandler", xInteraction),
+ comphelper::makePropertyValue("MacroExecutionMode", sal_Int16(css::document::MacroExecMode::USE_CONFIG)),
+ comphelper::makePropertyValue("UpdateDocMode", sal_Int16(css::document::UpdateDocMode::ACCORDING_TO_CONFIG))
+ };
+
+ // use the filedlghelper to get the current filter name,
+ // because it removes the extensions before you get the filter name.
+ OUString aFilterName( m_pFileDlg->GetCurrentFilter() );
+
+ if ( xPickerControls.is() )
+ {
+
+ // Set readonly flag
+
+ bool bReadOnly = false;
+
+
+ xPickerControls->getValue( ExtendedFilePickerElementIds::CHECKBOX_READONLY, 0 ) >>= bReadOnly;
+
+ // Only set property if readonly is set to TRUE
+
+ if ( bReadOnly )
+ {
+ aArgs.realloc( ++nArgs );
+ auto pArgs = aArgs.getArray();
+ pArgs[nArgs-1].Name = "ReadOnly";
+ pArgs[nArgs-1].Value <<= bReadOnly;
+ }
+
+ // Get version string
+
+ sal_Int32 iVersion = -1;
+
+ xPickerControls->getValue( ExtendedFilePickerElementIds::LISTBOX_VERSION, ControlActions::GET_SELECTED_ITEM_INDEX ) >>= iVersion;
+
+ if ( iVersion >= 0 )
+ {
+ sal_Int16 uVersion = static_cast<sal_Int16>(iVersion);
+
+ aArgs.realloc( ++nArgs );
+ auto pArgs = aArgs.getArray();
+ pArgs[nArgs-1].Name = "Version";
+ pArgs[nArgs-1].Value <<= uVersion;
+ }
+
+ // Retrieve the current filter
+
+ if ( aFilterName.isEmpty() )
+ xPickerControls->getValue( CommonFilePickerElementIds::LISTBOX_FILTER, ControlActions::GET_SELECTED_ITEM ) >>= aFilterName;
+
+ }
+
+
+ // Convert UI filter name to internal filter name
+
+ if ( !aFilterName.isEmpty() )
+ {
+ std::shared_ptr<const SfxFilter> pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4UIName( aFilterName, SfxFilterFlags::NONE, SfxFilterFlags::NOTINFILEDLG );
+
+ if ( pFilter )
+ {
+ aFilterName = pFilter->GetFilterName();
+
+ if ( !aFilterName.isEmpty() )
+ {
+ aArgs.realloc( ++nArgs );
+ auto pArgs = aArgs.getArray();
+ pArgs[nArgs-1].Name = "FilterName";
+ pArgs[nArgs-1].Value <<= aFilterName;
+ }
+ }
+ }
+
+ if ( 1 == nFiles )
+ OpenURL( sFiles[0], "_default", aArgs );
+ else
+ {
+ OUString aBaseDirURL = sFiles[0];
+ if ( !aBaseDirURL.isEmpty() && !aBaseDirURL.endsWith("/") )
+ aBaseDirURL += "/";
+
+ int iFiles;
+ for ( iFiles = 1; iFiles < nFiles; iFiles++ )
+ {
+ OUString aURL = aBaseDirURL + sFiles[iFiles];
+ OpenURL( aURL, "_default", aArgs );
+ }
+ }
+ }
+ }
+ catch ( ... )
+ {
+ }
+ }
+
+#ifdef _WIN32
+ // Destroy dialog to prevent problems with custom controls
+ // This fix is dependent on the dialog settings. Destroying the dialog here will
+ // crash the non-native dialog implementation! Therefore make this dependent on
+ // the settings.
+ if (UseSystemFileDialog())
+ {
+ m_pFileDlg.reset();
+ }
+#endif
+
+ LeaveModalMode();
+}
+
+
+void ShutdownIcon::addTerminateListener()
+{
+ ShutdownIcon* pInst = getInstance();
+ if ( ! pInst)
+ return;
+
+ if (pInst->m_bListenForTermination)
+ return;
+
+ css::uno::Reference< XDesktop2 > xDesktop = pInst->m_xDesktop;
+ if ( ! xDesktop.is())
+ return;
+
+ xDesktop->addTerminateListener( pInst );
+ pInst->m_bListenForTermination = true;
+}
+
+
+void ShutdownIcon::terminateDesktop()
+{
+ ShutdownIcon* pInst = getInstance();
+ if ( ! pInst)
+ return;
+
+ css::uno::Reference< XDesktop2 > xDesktop = pInst->m_xDesktop;
+ if ( ! xDesktop.is())
+ return;
+
+ // always remove ourselves as listener
+ pInst->m_bListenForTermination = true;
+ xDesktop->removeTerminateListener( pInst );
+
+ // terminate desktop only if no tasks exist
+ css::uno::Reference< XIndexAccess > xTasks = xDesktop->getFrames();
+ if( xTasks.is() && xTasks->getCount() < 1 )
+ Application::Quit();
+
+ // remove the instance pointer
+ ShutdownIcon::pShutdownIcon = nullptr;
+}
+
+
+ShutdownIcon* ShutdownIcon::getInstance()
+{
+ OSL_ASSERT( pShutdownIcon );
+ return pShutdownIcon.get();
+}
+
+
+ShutdownIcon* ShutdownIcon::createInstance()
+{
+ if (pShutdownIcon)
+ return pShutdownIcon.get();
+
+ try {
+ rtl::Reference<ShutdownIcon> pIcon(new ShutdownIcon( comphelper::getProcessComponentContext() ));
+ pIcon->init ();
+ pShutdownIcon = pIcon;
+ } catch (...) {
+ }
+
+ return pShutdownIcon.get();
+}
+
+void ShutdownIcon::init()
+{
+ css::uno::Reference < XDesktop2 > xDesktop = Desktop::create( m_xContext );
+ std::unique_lock aGuard(m_aMutex);
+ m_xDesktop = xDesktop;
+}
+
+
+void ShutdownIcon::disposing(std::unique_lock<std::mutex>&)
+{
+ m_xContext.clear();
+ m_xDesktop.clear();
+
+ deInitSystray();
+}
+
+
+// XEventListener
+void SAL_CALL ShutdownIcon::disposing( const css::lang::EventObject& )
+{
+}
+
+
+// XTerminateListener
+void SAL_CALL ShutdownIcon::queryTermination( const css::lang::EventObject& )
+{
+ SAL_INFO("sfx.appl", "ShutdownIcon::queryTermination: veto is " << m_bVeto);
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_bVeto )
+ throw css::frame::TerminationVetoException();
+}
+
+
+void SAL_CALL ShutdownIcon::notifyTermination( const css::lang::EventObject& )
+{
+}
+
+
+void SAL_CALL ShutdownIcon::initialize( const css::uno::Sequence< css::uno::Any>& aArguments )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ // third argument only sets veto, everything else will be ignored!
+ if (aArguments.getLength() > 2)
+ {
+ bool bVeto = ::cppu::any2bool(aArguments[2]);
+ m_bVeto = bVeto;
+ return;
+ }
+
+ if ( aArguments.getLength() > 0 )
+ {
+ if ( !ShutdownIcon::pShutdownIcon )
+ {
+ try
+ {
+ bool bQuickstart = ::cppu::any2bool( aArguments[0] );
+ if( !bQuickstart && !GetAutostart() )
+ return;
+ aGuard.unlock();
+ init ();
+ aGuard.lock();
+ if ( !m_xDesktop.is() )
+ return;
+
+ /* Create a sub-classed instance - foo */
+ ShutdownIcon::pShutdownIcon = this;
+ initSystray();
+ }
+ catch(const css::lang::IllegalArgumentException&)
+ {
+ }
+ }
+ }
+ if ( aArguments.getLength() > 1 )
+ {
+ bool bAutostart = ::cppu::any2bool( aArguments[1] );
+ if (bAutostart && !GetAutostart())
+ SetAutostart( true );
+ if (!bAutostart && GetAutostart())
+ SetAutostart( false );
+ }
+
+}
+
+
+void ShutdownIcon::EnterModalMode()
+{
+ bModalMode = true;
+}
+
+
+void ShutdownIcon::LeaveModalMode()
+{
+ bModalMode = false;
+}
+
+#ifdef _WIN32
+// defined in shutdowniconw32.cxx
+#elif defined MACOSX
+// defined in shutdowniconaqua.cxx
+#else
+bool ShutdownIcon::IsQuickstarterInstalled()
+{
+ return false;
+}
+#endif
+
+
+#ifdef ENABLE_QUICKSTART_APPLET
+#ifdef _WIN32
+OUString ShutdownIcon::getShortcutName()
+{
+ return GetAutostartFolderNameW32() + "\\" + SfxResId(STR_QUICKSTART_LNKNAME) + ".lnk";
+}
+#endif // _WIN32
+#endif
+
+bool ShutdownIcon::GetAutostart( )
+{
+#if defined MACOSX
+ return true;
+#elif defined ENABLE_QUICKSTART_APPLET
+ bool bRet = false;
+ OUString aShortcut( getShortcutName() );
+ OUString aShortcutUrl;
+ osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
+ osl::File f( aShortcutUrl );
+ osl::File::RC error = f.open( osl_File_OpenFlag_Read );
+ if( error == osl::File::E_None )
+ {
+ f.close();
+ bRet = true;
+ }
+ return bRet;
+#else // ENABLE_QUICKSTART_APPLET
+ return false;
+#endif
+}
+
+void ShutdownIcon::SetAutostart( bool bActivate )
+{
+#ifdef ENABLE_QUICKSTART_APPLET
+#ifndef MACOSX
+ OUString aShortcut( getShortcutName() );
+#endif
+
+ if( bActivate && IsQuickstarterInstalled() )
+ {
+#ifdef _WIN32
+ EnableAutostartW32( aShortcut );
+#endif
+ }
+ else
+ {
+#ifndef MACOSX
+ OUString aShortcutUrl;
+ ::osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
+ ::osl::File::remove( aShortcutUrl );
+#endif
+ }
+#else
+ (void)bActivate; // unused variable
+#endif // ENABLE_QUICKSTART_APPLET
+}
+
+const ::sal_Int32 PROPHANDLE_TERMINATEVETOSTATE = 0;
+
+// XFastPropertySet
+void SAL_CALL ShutdownIcon::setFastPropertyValue( ::sal_Int32 nHandle,
+ const css::uno::Any& aValue )
+{
+ switch(nHandle)
+ {
+ case PROPHANDLE_TERMINATEVETOSTATE :
+ {
+ // use new value in case it's a valid information only
+ bool bState( false );
+ if (! (aValue >>= bState))
+ return;
+
+ m_bVeto = bState;
+ if (m_bVeto && ! m_bListenForTermination)
+ addTerminateListener();
+ }
+ break;
+
+ default :
+ throw css::beans::UnknownPropertyException(OUString::number(nHandle));
+ }
+}
+
+// XFastPropertySet
+css::uno::Any SAL_CALL ShutdownIcon::getFastPropertyValue( ::sal_Int32 nHandle )
+{
+ css::uno::Any aValue;
+ switch(nHandle)
+ {
+ case PROPHANDLE_TERMINATEVETOSTATE :
+ {
+ bool bState = (m_bListenForTermination && m_bVeto);
+ aValue <<= bState;
+ }
+ break;
+
+ default :
+ throw css::beans::UnknownPropertyException(OUString::number(nHandle));
+ }
+
+ return aValue;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_desktop_QuickstartWrapper_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ShutdownIcon(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/shutdownicon.hxx b/sfx2/source/appl/shutdownicon.hxx
new file mode 100644
index 0000000000..535a24b4df
--- /dev/null
+++ b/sfx2/source/appl/shutdownicon.hxx
@@ -0,0 +1,158 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_SFX2_SOURCE_APPL_SHUTDOWNICON_HXX
+#define INCLUDED_SFX2_SOURCE_APPL_SHUTDOWNICON_HXX
+
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/frame/XDesktop2.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <rtl/ustring.hxx>
+#include <rtl/ref.hxx>
+#include <comphelper/compbase.hxx>
+#include <tools/link.hxx>
+#include <memory>
+
+extern "C" {
+
+void SAL_DLLPUBLIC_EXPORT plugin_init_sys_tray();
+void SAL_DLLPUBLIC_EXPORT plugin_shutdown_sys_tray();
+
+}
+
+namespace sfx2
+{
+ class FileDialogHelper;
+}
+
+typedef comphelper::WeakComponentImplHelper<
+ css::lang::XInitialization,
+ css::frame::XTerminateListener,
+ css::lang::XServiceInfo,
+ css::beans::XFastPropertySet > ShutdownIconServiceBase;
+
+inline constexpr OUString WRITER_URL = u"private:factory/swriter"_ustr;
+inline constexpr OUString CALC_URL = u"private:factory/scalc"_ustr;
+inline constexpr OUString IMPRESS_URL = u"private:factory/simpress"_ustr;
+inline constexpr OUString IMPRESS_WIZARD_URL = u"private:factory/simpress?slot=6686"_ustr;
+inline constexpr OUString DRAW_URL = u"private:factory/sdraw"_ustr;
+inline constexpr OUString MATH_URL = u"private:factory/smath"_ustr;
+inline constexpr OUString BASE_URL = u"private:factory/sdatabase?Interactive"_ustr;
+inline constexpr OUString STARTMODULE_URL = u".uno:ShowStartModule"_ustr;
+
+class ShutdownIcon : public ShutdownIconServiceBase
+{
+ bool m_bVeto;
+ bool m_bListenForTermination;
+ bool m_bSystemDialogs;
+ std::unique_ptr<sfx2::FileDialogHelper> m_pFileDlg;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::frame::XDesktop2 > m_xDesktop;
+
+ static rtl::Reference<ShutdownIcon> pShutdownIcon; // one instance
+
+ bool m_bInitialized;
+ void initSystray();
+ void deInitSystray();
+
+ static void EnterModalMode();
+ static void LeaveModalMode();
+ static OUString getShortcutName();
+
+ friend class SfxNotificationListener_Impl;
+
+ public:
+ explicit ShutdownIcon( css::uno::Reference< css::uno::XComponentContext > xContext );
+
+ virtual ~ShutdownIcon() override;
+
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
+
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ static ShutdownIcon* getInstance();
+ static ShutdownIcon* createInstance();
+
+ static void terminateDesktop();
+ static void addTerminateListener();
+
+ static void FileOpen();
+ static void OpenURL( const OUString& aURL, const OUString& rTarget, const css::uno::Sequence< css::beans::PropertyValue >& =
+ css::uno::Sequence< css::beans::PropertyValue >( 0 ) );
+ static void FromTemplate();
+
+ static void SetAutostart( bool bActivate );
+ static bool GetAutostart();
+ static bool bModalMode;
+
+ /// @throws css::uno::Exception
+ void init();
+
+ static OUString GetUrlDescription( std::u16string_view aUrl );
+
+ void SetVeto( bool bVeto ) { m_bVeto = bVeto;}
+
+ void StartFileDialog();
+ DECL_LINK(DialogClosedHdl_Impl, sfx2::FileDialogHelper*, void);
+
+ static bool IsQuickstarterInstalled();
+
+ // Component Helper - force override
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL notifyTermination( const css::lang::EventObject& aEvent ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XFastPropertySet
+ virtual void SAL_CALL setFastPropertyValue( ::sal_Int32 nHandle,
+ const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getFastPropertyValue( ::sal_Int32 nHandle ) override;
+
+#ifdef _WIN32
+ static void EnableAutostartW32( const OUString &aShortcutName );
+ static OUString GetAutostartFolderNameW32();
+#endif
+};
+
+extern "C" {
+# ifdef _WIN32
+ // builtin win32 systray
+ void win32_init_sys_tray();
+ void win32_shutdown_sys_tray();
+# elif defined MACOSX
+ void aqua_init_systray();
+ void aqua_shutdown_systray();
+# endif
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/shutdowniconaqua.mm b/sfx2/source/appl/shutdowniconaqua.mm
new file mode 100644
index 0000000000..8cb9b6d806
--- /dev/null
+++ b/sfx2/source/appl/shutdowniconaqua.mm
@@ -0,0 +1,470 @@
+/* -*- 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 <unotools/moduleoptions.hxx>
+#include <unotools/dynamicmenuoptions.hxx>
+#include <unotools/historyoptions.hxx>
+#include <rtl/ustring.hxx>
+#include <tools/urlobj.hxx>
+#include <osl/file.h>
+#include <osl/diagnose.h>
+#include <comphelper/sequenceashashmap.hxx>
+#include <sfx2/app.hxx>
+#include <sal/macros.h>
+#include <sfx2/sfxresid.hxx>
+#include <sfx2/strings.hrc>
+#include <vcl/svapp.hxx>
+#include "shutdownicon.hxx"
+
+#include <com/sun/star/util/XStringWidth.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <set>
+#include <vector>
+
+#include <premac.h>
+#include <objc/objc-runtime.h>
+#include <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+#define MI_OPEN 1
+#define MI_WRITER 2
+#define MI_CALC 3
+#define MI_IMPRESS 4
+#define MI_DRAW 5
+#define MI_BASE 6
+#define MI_MATH 7
+#define MI_TEMPLATE 8
+#define MI_STARTMODULE 9
+
+@interface QSMenuExecute : NSObject
+{
+}
+-(void)executeMenuItem: (NSMenuItem*)pItem;
+-(void)dockIconClicked: (NSObject*)pSender;
+@end
+
+@implementation QSMenuExecute
+-(void)executeMenuItem: (NSMenuItem*)pItem
+{
+ switch( [pItem tag] )
+ {
+ case MI_OPEN:
+ ShutdownIcon::FileOpen();
+ break;
+ case MI_WRITER:
+ ShutdownIcon::OpenURL( WRITER_URL, "_default" );
+ break;
+ case MI_CALC:
+ ShutdownIcon::OpenURL( CALC_URL, "_default" );
+ break;
+ case MI_IMPRESS:
+ ShutdownIcon::OpenURL( IMPRESS_URL, "_default" );
+ break;
+ case MI_DRAW:
+ ShutdownIcon::OpenURL( DRAW_URL, "_default" );
+ break;
+ case MI_BASE:
+ ShutdownIcon::OpenURL( BASE_URL, "_default" );
+ break;
+ case MI_MATH:
+ ShutdownIcon::OpenURL( MATH_URL, "_default" );
+ break;
+ case MI_TEMPLATE:
+ ShutdownIcon::FromTemplate();
+ break;
+ case MI_STARTMODULE:
+ ShutdownIcon::OpenURL( STARTMODULE_URL, "_default" );
+ break;
+ default:
+ break;
+ }
+}
+
+-(void)dockIconClicked: (NSObject*)pSender
+{
+ (void)pSender;
+ // start module
+ ShutdownIcon::OpenURL( STARTMODULE_URL, "_default" );
+}
+
+@end
+
+bool ShutdownIcon::IsQuickstarterInstalled()
+{
+ return true;
+}
+
+static NSMenuItem* pDefMenu = nil, *pDockSubMenu = nil;
+static QSMenuExecute* pExecute = nil;
+
+static std::set< OUString > aShortcuts;
+
+static NSString* getAutoreleasedString( const OUString& rStr )
+{
+ return [[[NSString alloc] initWithCharacters: reinterpret_cast<unichar const *>(rStr.getStr()) length: rStr.getLength()] autorelease];
+}
+
+namespace {
+
+struct RecentMenuEntry
+{
+ OUString aURL;
+ OUString aFilter;
+ OUString aTitle;
+ OUString aPassword;
+};
+
+class RecentFilesStringLength : public ::cppu::WeakImplHelper< css::util::XStringWidth >
+{
+ public:
+ RecentFilesStringLength() {}
+
+ // XStringWidth
+ sal_Int32 SAL_CALL queryStringWidth( const OUString& aString ) override
+ {
+ return aString.getLength();
+ }
+};
+
+}
+
+@interface RecentMenuDelegate : NSObject <NSMenuDelegate>
+{
+ std::vector< RecentMenuEntry >* m_pRecentFilesItems;
+}
+-(id)init;
+-(void)dealloc;
+-(void)menuNeedsUpdate:(NSMenu *)menu;
+-(void)executeRecentEntry: (NSMenuItem*)item;
+@end
+
+@implementation RecentMenuDelegate
+-(id)init
+{
+ if( (self = [super init]) )
+ {
+ m_pRecentFilesItems = new std::vector< RecentMenuEntry >();
+ }
+ return self;
+}
+
+-(void)dealloc
+{
+ delete m_pRecentFilesItems;
+ [super dealloc];
+}
+
+-(void)menuNeedsUpdate:(NSMenu *)menu
+{
+ // clear menu
+ int nItems = [menu numberOfItems];
+ while( nItems -- )
+ [menu removeItemAtIndex: 0];
+
+ // update recent item list
+ std::vector< SvtHistoryOptions::HistoryItem > aHistoryList( SvtHistoryOptions::GetList( EHistoryType::PickList ) );
+
+ int nPickListMenuItems = ( aHistoryList.size() > 99 ) ? 99 : aHistoryList.size();
+
+ m_pRecentFilesItems->clear();
+ if( nPickListMenuItems > 0 )
+ {
+ for ( int i = 0; i < nPickListMenuItems; i++ )
+ {
+ const SvtHistoryOptions::HistoryItem & rPickListEntry = aHistoryList[i];
+ RecentMenuEntry aRecentFile;
+ aRecentFile.aURL = rPickListEntry.sURL;
+ aRecentFile.aFilter = rPickListEntry.sFilter;
+ aRecentFile.aTitle = rPickListEntry.sTitle;
+ aRecentFile.aPassword = rPickListEntry.sPassword;
+ m_pRecentFilesItems->push_back( aRecentFile );
+ }
+ }
+
+ // insert new recent items
+ for ( std::vector<RecentMenuEntry>::size_type i = 0; i < m_pRecentFilesItems->size(); i++ )
+ {
+ OUString aMenuTitle;
+ INetURLObject aURL( (*m_pRecentFilesItems)[i].aURL );
+
+ if ( aURL.GetProtocol() == INetProtocol::File )
+ {
+ // Do handle file URL differently => convert it to a system
+ // path and abbreviate it with a special function:
+ OUString aSystemPath( aURL.getFSysPath( FSysStyle::Detect ) );
+ OUString aCompactedSystemPath;
+
+ oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, nullptr );
+ if ( !nError )
+ aMenuTitle = aCompactedSystemPath;
+ else
+ aMenuTitle = aSystemPath;
+ }
+ else
+ {
+ // Use INetURLObject to abbreviate all other URLs
+ css::uno::Reference< css::util::XStringWidth > xStringLength( new RecentFilesStringLength() );
+ aMenuTitle = aURL.getAbbreviated( xStringLength, 46, INetURLObject::DecodeMechanism::Unambiguous );
+ }
+
+ NSMenuItem* pNewItem = [[NSMenuItem alloc] initWithTitle: getAutoreleasedString( aMenuTitle )
+ action: @selector(executeRecentEntry:)
+ keyEquivalent: @""];
+ [pNewItem setTag: i];
+ [pNewItem setTarget: self];
+ [pNewItem setEnabled: YES];
+ [menu addItem: pNewItem];
+ [pNewItem autorelease];
+ }
+}
+
+-(void)executeRecentEntry: (NSMenuItem*)item
+{
+ sal_Int32 nIndex = [item tag];
+ if( ( nIndex >= 0 ) && ( nIndex < static_cast<sal_Int32>( m_pRecentFilesItems->size() ) ) )
+ {
+ const RecentMenuEntry& rRecentFile = (*m_pRecentFilesItems)[ nIndex ];
+ int NUM_OF_PICKLIST_ARGS = 3;
+ css::uno::Sequence< css::beans::PropertyValue > aArgsList( NUM_OF_PICKLIST_ARGS );
+ css::beans::PropertyValue* pArgsList = aArgsList.getArray();
+
+ pArgsList[0].Name = "Referer";
+ pArgsList[0].Value <<= OUString( "private:user" );
+
+ // documents in the picklist will never be opened as templates
+ pArgsList[1].Name = "AsTemplate";
+ pArgsList[1].Value <<= false;
+
+ OUString aFilter( rRecentFile.aFilter );
+ sal_Int32 nPos = aFilter.indexOf( '|' );
+ if ( nPos >= 0 )
+ {
+ OUString aFilterOptions;
+
+ if ( nPos < ( aFilter.getLength() - 1 ) )
+ aFilterOptions = aFilter.copy( nPos+1 );
+
+ pArgsList[2].Name = "FilterOptions";
+ pArgsList[2].Value <<= aFilterOptions;
+
+ aFilter = aFilter.copy( 0, nPos-1 );
+ aArgsList.realloc( ++NUM_OF_PICKLIST_ARGS );
+ pArgsList = aArgsList.getArray();
+ }
+
+ pArgsList[NUM_OF_PICKLIST_ARGS-1].Name = "FilterName";
+ pArgsList[NUM_OF_PICKLIST_ARGS-1].Value <<= aFilter;
+
+ ShutdownIcon::OpenURL( rRecentFile.aURL, "_default", aArgsList );
+ }
+}
+@end
+
+static RecentMenuDelegate* pRecentDelegate = nil;
+
+static OUString getShortCut( const OUString& i_rTitle )
+{
+ // create shortcut
+ OUString aKeyEquiv;
+ for( sal_Int32 nIndex = 0; nIndex < i_rTitle.getLength(); nIndex++ )
+ {
+ OUString aShortcut( i_rTitle.copy( nIndex, 1 ).toAsciiLowerCase() );
+ if( aShortcuts.find( aShortcut ) == aShortcuts.end() )
+ {
+ aShortcuts.insert( aShortcut );
+ aKeyEquiv = aShortcut;
+ break;
+ }
+ }
+
+ return aKeyEquiv;
+}
+
+static void appendMenuItem( NSMenu* i_pMenu, NSMenu* i_pDockMenu, const OUString& i_rTitle, int i_nTag, const OUString& i_rKeyEquiv )
+{
+ if( ! i_rTitle.getLength() )
+ return;
+
+ NSMenuItem* pItem = [[NSMenuItem alloc] initWithTitle: getAutoreleasedString( i_rTitle )
+ action: @selector(executeMenuItem:)
+ keyEquivalent: (i_rKeyEquiv.getLength() ? getAutoreleasedString( i_rKeyEquiv ) : @"")
+ ];
+ [pItem setTag: i_nTag];
+ [pItem setTarget: pExecute];
+ [pItem setEnabled: YES];
+ [i_pMenu addItem: pItem];
+
+ if( i_pDockMenu )
+ {
+ // create a similar entry in the dock menu
+ pItem = [[NSMenuItem alloc] initWithTitle: getAutoreleasedString( i_rTitle )
+ action: @selector(executeMenuItem:)
+ keyEquivalent: @""
+ ];
+ [pItem setTag: i_nTag];
+ [pItem setTarget: pExecute];
+ [pItem setEnabled: YES];
+ [i_pDockMenu addItem: pItem];
+ }
+}
+
+static void appendRecentMenu( NSMenu* i_pMenu, const OUString& i_rTitle )
+{
+ if( ! pRecentDelegate )
+ pRecentDelegate = [[RecentMenuDelegate alloc] init];
+
+ NSMenuItem* pItem = [i_pMenu addItemWithTitle: getAutoreleasedString( i_rTitle )
+ action: @selector(executeMenuItem:)
+ keyEquivalent: @""
+ ];
+ [pItem setEnabled: YES];
+ NSMenu* pRecentMenu = [[NSMenu alloc] initWithTitle: getAutoreleasedString( i_rTitle ) ];
+
+ [pRecentMenu setDelegate: pRecentDelegate];
+
+ [pRecentMenu setAutoenablesItems: NO];
+ [pItem setSubmenu: pRecentMenu];
+}
+
+
+extern "C"
+{
+
+void aqua_init_systray()
+{
+ SolarMutexGuard aGuard;
+
+ ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
+ if( ! pShutdownIcon )
+ return;
+
+ // disable shutdown
+ pShutdownIcon->SetVeto( true );
+ ShutdownIcon::addTerminateListener();
+
+ if( ! pDefMenu )
+ {
+ if( [NSApp respondsToSelector: @selector(addFallbackMenuItem:)] )
+ {
+ aShortcuts.clear();
+
+ pExecute = [[QSMenuExecute alloc] init];
+ pDefMenu = [[NSMenuItem alloc] initWithTitle: getAutoreleasedString( SfxResId(STR_QUICKSTART_FILE) ) action: nullptr keyEquivalent: @""];
+ pDockSubMenu = [[NSMenuItem alloc] initWithTitle: getAutoreleasedString( SfxResId(STR_QUICKSTART_FILE) ) action: nullptr keyEquivalent: @""];
+ NSMenu* pMenu = [[NSMenu alloc] initWithTitle: getAutoreleasedString( SfxResId(STR_QUICKSTART_FILE) )];
+ [pMenu setAutoenablesItems: NO];
+ NSMenu* pDockMenu = [[NSMenu alloc] initWithTitle: getAutoreleasedString( SfxResId(STR_QUICKSTART_FILE) )];
+ [pDockMenu setAutoenablesItems: NO];
+
+ // collect the URLs of the entries in the File/New menu
+ SvtModuleOptions aModuleOptions;
+ std::set< OUString > aFileNewAppsAvailable;
+ std::vector < SvtDynMenuEntry > const aNewMenu = SvtDynamicMenuOptions::GetMenu( EDynamicMenuType::NewMenu );
+
+ for ( SvtDynMenuEntry const & newMenuProp : aNewMenu )
+ {
+ if ( !newMenuProp.sURL.isEmpty() )
+ aFileNewAppsAvailable.insert( newMenuProp.sURL );
+ }
+
+ // describe the menu entries for launching the applications
+ struct MenuEntryDescriptor
+ {
+ SvtModuleOptions::EModule eModuleIdentifier;
+ int nMenuTag;
+ OUString sURLDescription;
+ } static constexpr aMenuItems[] =
+ {
+ { SvtModuleOptions::EModule::WRITER, MI_WRITER, WRITER_URL },
+ { SvtModuleOptions::EModule::CALC, MI_CALC, CALC_URL },
+ { SvtModuleOptions::EModule::IMPRESS, MI_IMPRESS, IMPRESS_WIZARD_URL },
+ { SvtModuleOptions::EModule::DRAW, MI_DRAW, DRAW_URL },
+ { SvtModuleOptions::EModule::DATABASE, MI_BASE, BASE_URL },
+ { SvtModuleOptions::EModule::MATH, MI_MATH, MATH_URL }
+ };
+
+ // insert entry for startcenter
+ if( aModuleOptions.IsModuleInstalled( SvtModuleOptions::EModule::STARTMODULE ) )
+ {
+ appendMenuItem( pMenu, nil, SfxResId(STR_QUICKSTART_STARTCENTER), MI_STARTMODULE, "n" );
+ if( [NSApp respondsToSelector: @selector(setDockIconClickHandler:)] )
+ [NSApp performSelector:@selector(setDockIconClickHandler:) withObject: pExecute];
+ else
+ OSL_FAIL( "setDockIconClickHandler selector failed on NSApp" );
+
+ }
+
+ // insert the menu entries for launching the applications
+ for ( size_t i = 0; i < SAL_N_ELEMENTS( aMenuItems ); ++i )
+ {
+ if ( !aModuleOptions.IsModuleInstalled( aMenuItems[i].eModuleIdentifier ) )
+ // the complete application is not even installed
+ continue;
+
+ const OUString& sURL( aMenuItems[i].sURLDescription );
+
+ if ( aFileNewAppsAvailable.find( sURL ) == aFileNewAppsAvailable.end() )
+ // the application is installed, but the entry has been configured to *not* appear in the File/New
+ // menu => also let not appear it in the quickstarter
+ continue;
+
+ OUString aKeyEquiv( getShortCut( ShutdownIcon::GetUrlDescription( sURL ) ) );
+
+ appendMenuItem( pMenu, pDockMenu, ShutdownIcon::GetUrlDescription( sURL ), aMenuItems[i].nMenuTag, aKeyEquiv );
+ }
+
+ // insert the remaining menu entries
+
+ // add recent menu
+ appendRecentMenu( pMenu, SfxResId(STR_QUICKSTART_RECENTDOC) );
+
+ OUString aTitle( SfxResId(STR_QUICKSTART_FROMTEMPLATE) );
+ OUString aKeyEquiv( getShortCut( aTitle ) );
+ appendMenuItem( pMenu, pDockMenu, aTitle, MI_TEMPLATE, aKeyEquiv );
+ aTitle = SfxResId(STR_QUICKSTART_FILEOPEN);
+ aKeyEquiv = getShortCut( aTitle );
+ appendMenuItem( pMenu, pDockMenu, aTitle, MI_OPEN, aKeyEquiv );
+
+ [pDefMenu setSubmenu: pMenu];
+ [NSApp performSelector:@selector(addFallbackMenuItem:) withObject: pDefMenu];
+
+ if( [NSApp respondsToSelector: @selector(addDockMenuItem:)] )
+ {
+ [pDockSubMenu setSubmenu: pDockMenu];
+ // add the submenu
+ [NSApp performSelector:@selector(addDockMenuItem:) withObject: pDockSubMenu];
+ }
+ else
+ OSL_FAIL( "addDockMenuItem selector failed on NSApp" );
+ }
+ else
+ OSL_FAIL( "addFallbackMenuItem selector failed on NSApp" );
+ }
+}
+
+void SAL_DLLPUBLIC_EXPORT aqua_shutdown_systray()
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/shutdowniconw32.cxx b/sfx2/source/appl/shutdowniconw32.cxx
new file mode 100644
index 0000000000..2fb7cd2b78
--- /dev/null
+++ b/sfx2/source/appl/shutdowniconw32.cxx
@@ -0,0 +1,803 @@
+/*
+ * 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 <sal/macros.h>
+#include <sal/log.hxx>
+
+#include <unotools/moduleoptions.hxx>
+#include <unotools/dynamicmenuoptions.hxx>
+
+#undef WB_LEFT
+#undef WB_RIGHT
+
+#include "shutdownicon.hxx"
+#include <sfx2/sfxresid.hxx>
+#include <sfx2/strings.hrc>
+#include <shlobj.h>
+#include <objidl.h>
+#include <osl/diagnose.h>
+#include <osl/thread.h>
+#include <systools/win32/qswin32.h>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/windowserrorstring.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+
+#include <set>
+
+
+#define EXECUTER_WINDOWCLASS L"SO Executer Class"
+#define EXECUTER_WINDOWNAME L"SO Executer Window"
+
+
+#define ID_QUICKSTART 1
+#define IDM_EXIT 2
+#define IDM_OPEN 3
+#define IDM_WRITER 4
+#define IDM_CALC 5
+#define IDM_IMPRESS 6
+#define IDM_DRAW 7
+#define IDM_BASE 8
+#define IDM_TEMPLATE 9
+#define IDM_MATH 12
+#define IDM_INSTALL 10
+#define IDM_STARTCENTER 14
+
+
+#define ICON_LO_DEFAULT 1
+#define ICON_TEXT_DOCUMENT 2
+#define ICON_SPREADSHEET_DOCUMENT 4
+#define ICON_DRAWING_DOCUMENT 6
+#define ICON_PRESENTATION_DOCUMENT 8
+#define ICON_TEMPLATE 11
+#define ICON_DATABASE_DOCUMENT 12
+#define ICON_MATH_DOCUMENT 13
+#define ICON_OPEN 5 // See index of open folder icon in shell32.dll
+
+#define SFX_TASKBAR_NOTIFICATION WM_USER+1
+
+static HWND aListenerWindow = nullptr;
+static HWND aExecuterWindow = nullptr;
+static HMENU popupMenu = nullptr;
+
+static void OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis);
+static void OnDrawItem(HWND hwnd, LPDRAWITEMSTRUCT lpdis);
+
+namespace {
+
+struct MYITEM
+{
+ OUString text;
+ OUString module;
+ UINT iconId;
+};
+
+}
+
+static void addMenuItem( HMENU hMenu, UINT id, UINT iconId, const OUString& text, int& pos, bool bOwnerdraw, const OUString& module )
+{
+ MENUITEMINFOW mi = {};
+
+ mi.cbSize = sizeof( mi );
+ if( id == static_cast<UINT>( -1 ) )
+ {
+ mi.fMask=MIIM_FTYPE;
+ mi.fType=MFT_SEPARATOR;
+ }
+ else
+ {
+ if( bOwnerdraw )
+ {
+ mi.fMask=MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
+ mi.fType=MFT_OWNERDRAW;
+
+ MYITEM *pMyItem = new MYITEM;
+ pMyItem->text = text;
+ pMyItem->iconId = iconId;
+ pMyItem->module = module;
+ mi.dwItemData = reinterpret_cast<ULONG_PTR>(pMyItem);
+ }
+ else
+ {
+ mi.fMask=MIIM_STRING | MIIM_STATE | MIIM_ID;
+ mi.dwTypeData = o3tl::toW(
+ const_cast<sal_Unicode *>(text.getStr()));
+ mi.cch = text.getLength();
+ }
+
+ mi.fState = MFS_ENABLED;
+ mi.wID = id;
+ if ( IDM_TEMPLATE == id )
+ mi.fState |= MFS_DEFAULT;
+ }
+
+ InsertMenuItemW( hMenu, pos++, TRUE, &mi );
+}
+
+
+static HMENU createSystrayMenu( )
+{
+ SvtModuleOptions aModuleOptions;
+
+ HMENU hMenu = CreatePopupMenu();
+ int pos=0;
+
+ ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
+ OSL_ENSURE( pShutdownIcon, "ShutdownIcon instance empty!");
+
+ if( !pShutdownIcon )
+ return nullptr;
+
+ // collect the URLs of the entries in the File/New menu
+ ::std::set< OUString > aFileNewAppsAvailable;
+ std::vector< SvtDynMenuEntry > const aNewMenu = SvtDynamicMenuOptions::GetMenu( EDynamicMenuType::NewMenu );
+ for ( SvtDynMenuEntry const & newMenuProp : aNewMenu )
+ {
+ if ( !newMenuProp.sURL.isEmpty() )
+ aFileNewAppsAvailable.insert( newMenuProp.sURL );
+ }
+
+ // describe the menu entries for launching the applications
+ struct MenuEntryDescriptor
+ {
+ SvtModuleOptions::EModule eModuleIdentifier;
+ UINT nMenuItemID;
+ UINT nMenuIconID;
+ OUString sURLDescription;
+ } static constexpr aMenuItems[] =
+ {
+ { SvtModuleOptions::EModule::WRITER, IDM_WRITER, ICON_TEXT_DOCUMENT, WRITER_URL },
+ { SvtModuleOptions::EModule::CALC, IDM_CALC, ICON_SPREADSHEET_DOCUMENT, CALC_URL },
+ { SvtModuleOptions::EModule::IMPRESS, IDM_IMPRESS,ICON_PRESENTATION_DOCUMENT, IMPRESS_WIZARD_URL },
+ { SvtModuleOptions::EModule::DRAW, IDM_DRAW, ICON_DRAWING_DOCUMENT, DRAW_URL },
+ { SvtModuleOptions::EModule::DATABASE, IDM_BASE, ICON_DATABASE_DOCUMENT, BASE_URL },
+ { SvtModuleOptions::EModule::MATH, IDM_MATH, ICON_MATH_DOCUMENT, MATH_URL },
+ };
+
+ // insert the menu entries for launching the applications
+ for (const auto& [eModuleIdentifier, nMenuItemID, nMenuIconID, sURL] : aMenuItems)
+ {
+ if ( !aModuleOptions.IsModuleInstalled( eModuleIdentifier ) )
+ // the complete application is not even installed
+ continue;
+
+ if ( aFileNewAppsAvailable.find( sURL ) == aFileNewAppsAvailable.end() )
+ // the application is installed, but the entry has been configured to *not* appear in the File/New
+ // menu => also let not appear it in the quickstarter
+ continue;
+
+ addMenuItem( hMenu, nMenuItemID, nMenuIconID,
+ ShutdownIcon::GetUrlDescription( sURL ), pos, true, "" );
+ }
+
+
+ // insert the remaining menu entries
+ addMenuItem( hMenu, IDM_TEMPLATE, ICON_TEMPLATE,
+ SfxResId( STR_QUICKSTART_FROMTEMPLATE ), pos, true, "");
+ addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
+ addMenuItem( hMenu, IDM_OPEN, ICON_OPEN, SfxResId(STR_QUICKSTART_FILEOPEN), pos, true, "SHELL32");
+ addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
+ addMenuItem( hMenu, IDM_INSTALL,0, SfxResId(STR_QUICKSTART_PRELAUNCH), pos, false, "" );
+ addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
+ addMenuItem( hMenu, IDM_EXIT, 0, SfxResId(STR_QUICKSTART_EXIT), pos, false, "" );
+
+ // indicate status of autostart folder
+ CheckMenuItem( hMenu, IDM_INSTALL, MF_BYCOMMAND | (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
+
+ return hMenu;
+}
+
+
+static void deleteSystrayMenu( HMENU hMenu )
+{
+ if( !hMenu || !IsMenu( hMenu ))
+ return;
+
+ MENUITEMINFOW mi = {};
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_DATA;
+
+ for (UINT pos = 0; GetMenuItemInfoW(hMenu, pos, true, &mi); ++pos)
+ {
+ if (MYITEM* pMyItem = reinterpret_cast<MYITEM*>(mi.dwItemData))
+ delete pMyItem;
+ mi.fMask = MIIM_DATA;
+ }
+}
+
+
+static void addTaskbarIcon( HWND hWnd )
+{
+ OUString strTip = SfxResId(STR_QUICKSTART_TIP);
+
+ // add taskbar icon
+ NOTIFYICONDATAW nid;
+ nid.hIcon = static_cast<HICON>(LoadImageW( GetModuleHandleW( nullptr ), MAKEINTRESOURCEW( ICON_LO_DEFAULT ),
+ IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
+ LR_DEFAULTCOLOR | LR_SHARED ));
+
+ wcsncpy( nid.szTip, o3tl::toW(strTip.getStr()), 64 );
+
+ nid.cbSize = sizeof(nid);
+ nid.hWnd = hWnd;
+ nid.uID = ID_QUICKSTART;
+ nid.uCallbackMessage = SFX_TASKBAR_NOTIFICATION;
+ nid.uFlags = NIF_MESSAGE|NIF_TIP|NIF_ICON;
+
+ Shell_NotifyIconW(NIM_ADD, &nid);
+}
+
+
+static LRESULT CALLBACK listenerWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static UINT s_uTaskbarRestart = 0;
+ static UINT s_uMsgKillTray = 0;
+
+ switch (uMsg)
+ {
+ case WM_NCCREATE:
+ return TRUE;
+ case WM_CREATE:
+ {
+ // request notification when taskbar is recreated
+ // we then have to add our icon again
+ s_uTaskbarRestart = RegisterWindowMessageW(L"TaskbarCreated");
+ s_uMsgKillTray = RegisterWindowMessageW( SHUTDOWN_QUICKSTART_MESSAGE );
+
+ // create the menu
+ if( !popupMenu )
+ if( (popupMenu = createSystrayMenu( )) == nullptr )
+ return -1;
+
+ // and the icon
+ addTaskbarIcon( hWnd );
+
+ // disable shutdown
+ ShutdownIcon::getInstance()->SetVeto( true );
+ ShutdownIcon::addTerminateListener();
+ }
+ return 0;
+
+ case WM_MEASUREITEM:
+ OnMeasureItem(hWnd, reinterpret_cast<LPMEASUREITEMSTRUCT>(lParam));
+ return TRUE;
+
+ case WM_DRAWITEM:
+ OnDrawItem(hWnd, reinterpret_cast<LPDRAWITEMSTRUCT>(lParam));
+ return TRUE;
+
+ case SFX_TASKBAR_NOTIFICATION:
+ switch( lParam )
+ {
+ case WM_LBUTTONDOWN:
+ {
+ bool const ret = PostMessageW(aExecuterWindow, WM_COMMAND, IDM_STARTCENTER, reinterpret_cast<LPARAM>(hWnd));
+ SAL_WARN_IF(!ret, "sfx.appl", "ERROR: PostMessage() failed!");
+ break;
+ }
+
+ case WM_RBUTTONDOWN:
+ {
+ POINT pt;
+ GetCursorPos(&pt);
+ SetForegroundWindow( hWnd );
+
+ // update status before showing menu, could have been changed from option page
+ CheckMenuItem( popupMenu, IDM_INSTALL, MF_BYCOMMAND| (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
+
+ EnableMenuItem( popupMenu, IDM_EXIT, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
+ EnableMenuItem( popupMenu, IDM_OPEN, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
+ EnableMenuItem( popupMenu, IDM_TEMPLATE, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
+ int m = TrackPopupMenuEx( popupMenu, TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON,
+ pt.x, pt.y, hWnd, nullptr );
+ bool const ret = PostMessageW( hWnd, 0, 0, 0 );
+ SAL_WARN_IF(!ret, "sfx.appl", "ERROR: PostMessage() failed!");
+ switch( m )
+ {
+ case IDM_OPEN:
+ case IDM_WRITER:
+ case IDM_CALC:
+ case IDM_IMPRESS:
+ case IDM_DRAW:
+ case IDM_TEMPLATE:
+ case IDM_BASE:
+ case IDM_MATH:
+ break;
+ case IDM_INSTALL:
+ CheckMenuItem( popupMenu, IDM_INSTALL, MF_BYCOMMAND| (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
+ break;
+ case IDM_EXIT:
+ // delete taskbar icon
+ NOTIFYICONDATAW nid;
+ nid.cbSize=sizeof(nid);
+ nid.hWnd = hWnd;
+ nid.uID = ID_QUICKSTART;
+ Shell_NotifyIconW(NIM_DELETE, &nid);
+ break;
+ }
+
+ bool const ret2 = PostMessageW(aExecuterWindow, WM_COMMAND, m, reinterpret_cast<LPARAM>(hWnd));
+ SAL_WARN_IF(!ret2, "sfx.appl", "ERROR: PostMessage() failed!");
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ deleteSystrayMenu( popupMenu );
+ // We don't need the Systray Thread anymore
+ PostQuitMessage( 0 );
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+ default:
+ if( uMsg == s_uTaskbarRestart )
+ {
+ // re-create taskbar icon
+ addTaskbarIcon( hWnd );
+ }
+ else if ( uMsg == s_uMsgKillTray )
+ {
+ // delete taskbar icon
+ NOTIFYICONDATAW nid;
+ nid.cbSize=sizeof(nid);
+ nid.hWnd = hWnd;
+ nid.uID = ID_QUICKSTART;
+ Shell_NotifyIconW(NIM_DELETE, &nid);
+
+ bool const ret = PostMessageW(aExecuterWindow, WM_COMMAND, IDM_EXIT, reinterpret_cast<LPARAM>(hWnd));
+ SAL_WARN_IF(!ret, "sfx.appl", "ERROR: PostMessage() failed!");
+ }
+ else
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+ }
+ return 0;
+}
+
+
+static LRESULT CALLBACK executerWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_NCCREATE:
+ return TRUE;
+ case WM_CREATE:
+ return 0;
+
+ case WM_COMMAND:
+ switch( LOWORD(wParam) )
+ {
+ case IDM_OPEN:
+ if ( !ShutdownIcon::bModalMode )
+ ShutdownIcon::FileOpen();
+ break;
+ case IDM_WRITER:
+ ShutdownIcon::OpenURL( WRITER_URL, "_default" );
+ break;
+ case IDM_CALC:
+ ShutdownIcon::OpenURL( CALC_URL, "_default" );
+ break;
+ case IDM_IMPRESS:
+ ShutdownIcon::OpenURL( IMPRESS_WIZARD_URL, "_default" );
+ break;
+ case IDM_DRAW:
+ ShutdownIcon::OpenURL( DRAW_URL, "_default" );
+ break;
+ case IDM_BASE:
+ ShutdownIcon::OpenURL( BASE_URL, "_default" );
+ break;
+ case IDM_MATH:
+ ShutdownIcon::OpenURL( MATH_URL, "_default" );
+ break;
+ case IDM_STARTCENTER:
+ ShutdownIcon::OpenURL( STARTMODULE_URL, "_default" );
+ break;
+ case IDM_TEMPLATE:
+ if ( !ShutdownIcon::bModalMode )
+ ShutdownIcon::FromTemplate();
+ break;
+ case IDM_INSTALL:
+ ShutdownIcon::SetAutostart( !ShutdownIcon::GetAutostart() );
+ break;
+ case IDM_EXIT:
+ // remove listener and
+ // terminate office if running in background
+ if ( !ShutdownIcon::bModalMode )
+ ShutdownIcon::terminateDesktop();
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ default:
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+ }
+ return 0;
+}
+
+
+static unsigned __stdcall SystrayThread(void* /*lpParam*/)
+{
+ osl_setThreadName("SystrayThread");
+
+ aListenerWindow = CreateWindowExW(0,
+ QUICKSTART_CLASSNAME, // registered class name
+ QUICKSTART_WINDOWNAME, // window name
+ 0, // window style
+ CW_USEDEFAULT, // horizontal position of window
+ CW_USEDEFAULT, // vertical position of window
+ CW_USEDEFAULT, // window width
+ CW_USEDEFAULT, // window height
+ nullptr, // handle to parent or owner window
+ nullptr, // menu handle or child identifier
+ GetModuleHandleW( nullptr ), // handle to application instance
+ nullptr // window-creation data
+ );
+
+ MSG msg;
+
+ for (;;)
+ {
+ int const bRet = GetMessageW(&msg, nullptr, 0, 0);
+ if (bRet == 0)
+ {
+ break;
+ }
+ if (-1 == bRet)
+ {
+ SAL_WARN("sfx.appl", "GetMessageW failed: " << WindowsErrorString(GetLastError()));
+ return 1;
+ }
+ TranslateMessage( &msg );
+ DispatchMessageW( &msg );
+ }
+
+ return msg.wParam; // Exit code of WM_QUIT
+}
+
+
+void win32_init_sys_tray()
+{
+ if ( ShutdownIcon::IsQuickstarterInstalled() )
+ {
+ WNDCLASSEXW listenerClass;
+ listenerClass.cbSize = sizeof(listenerClass);
+ listenerClass.style = 0;
+ listenerClass.lpfnWndProc = listenerWndProc;
+ listenerClass.cbClsExtra = 0;
+ listenerClass.cbWndExtra = 0;
+ listenerClass.hInstance = GetModuleHandleW( nullptr );
+ listenerClass.hIcon = nullptr;
+ listenerClass.hCursor = nullptr;
+ listenerClass.hbrBackground = nullptr;
+ listenerClass.lpszMenuName = nullptr;
+ listenerClass.lpszClassName = QUICKSTART_CLASSNAME;
+ listenerClass.hIconSm = nullptr;
+
+ RegisterClassExW(&listenerClass);
+
+ WNDCLASSEXW executerClass;
+ executerClass.cbSize = sizeof(executerClass);
+ executerClass.style = 0;
+ executerClass.lpfnWndProc = executerWndProc;
+ executerClass.cbClsExtra = 0;
+ executerClass.cbWndExtra = 0;
+ executerClass.hInstance = GetModuleHandleW( nullptr );
+ executerClass.hIcon = nullptr;
+ executerClass.hCursor = nullptr;
+ executerClass.hbrBackground = nullptr;
+ executerClass.lpszMenuName = nullptr;
+ executerClass.lpszClassName = EXECUTER_WINDOWCLASS;
+ executerClass.hIconSm = nullptr;
+
+ RegisterClassExW( &executerClass );
+
+ aExecuterWindow = CreateWindowExW(0,
+ EXECUTER_WINDOWCLASS, // registered class name
+ EXECUTER_WINDOWNAME, // window name
+ 0, // window style
+ CW_USEDEFAULT, // horizontal position of window
+ CW_USEDEFAULT, // vertical position of window
+ CW_USEDEFAULT, // window width
+ CW_USEDEFAULT, // window height
+ nullptr, // handle to parent or owner window
+ nullptr, // menu handle or child identifier
+ GetModuleHandleW( nullptr ), // handle to application instance
+ nullptr // window-creation data
+ );
+
+ CloseHandle(reinterpret_cast<HANDLE>(
+ _beginthreadex(nullptr, 0, SystrayThread, nullptr, 0, nullptr)));
+ }
+}
+
+
+void win32_shutdown_sys_tray()
+{
+ if ( ShutdownIcon::IsQuickstarterInstalled() )
+ {
+ if( IsWindow( aListenerWindow ) )
+ {
+ DestroyWindow( aListenerWindow );
+ aListenerWindow = nullptr;
+ DestroyWindow( aExecuterWindow );
+ aExecuterWindow = nullptr;
+ }
+ UnregisterClassW( QUICKSTART_CLASSNAME, GetModuleHandleW( nullptr ) );
+ UnregisterClassW( EXECUTER_WINDOWCLASS, GetModuleHandleW( nullptr ) );
+ }
+}
+
+
+void OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis)
+{
+ MYITEM *pMyItem = reinterpret_cast<MYITEM *>(lpmis->itemData);
+ HDC hdc = GetDC(hwnd);
+ SIZE size;
+
+ NONCLIENTMETRICSW ncm = {};
+ ncm.cbSize = sizeof(ncm);
+
+ SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
+
+ // Assume every menu item can be default and printed bold
+ ncm.lfMenuFont.lfWeight = FW_BOLD;
+
+ HFONT hfntOld = static_cast<HFONT>(SelectObject(hdc, CreateFontIndirectW( &ncm.lfMenuFont )));
+
+ GetTextExtentPoint32W(hdc, o3tl::toW(pMyItem->text.getStr()),
+ pMyItem->text.getLength(), &size);
+
+ lpmis->itemWidth = size.cx + 4 + GetSystemMetrics( SM_CXSMICON );
+ lpmis->itemHeight = std::max<int>(size.cy, GetSystemMetrics( SM_CYSMICON ));
+ lpmis->itemHeight += 4;
+
+ DeleteObject( SelectObject(hdc, hfntOld) );
+ ReleaseDC(hwnd, hdc);
+}
+
+void OnDrawItem(HWND /*hwnd*/, LPDRAWITEMSTRUCT lpdis)
+{
+ MYITEM *pMyItem = reinterpret_cast<MYITEM *>(lpdis->itemData);
+ COLORREF clrPrevText, clrPrevBkgnd;
+ HFONT hfntOld;
+ HBRUSH hbrOld;
+ int x, y;
+ bool fSelected = lpdis->itemState & ODS_SELECTED;
+ bool fDisabled = lpdis->itemState & (ODS_DISABLED | ODS_GRAYED);
+
+ // Set the appropriate foreground and background colors.
+
+ RECT aRect = lpdis->rcItem;
+
+ clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_MENU) );
+
+ if ( fDisabled )
+ clrPrevText = SetTextColor( lpdis->hDC, GetSysColor( COLOR_GRAYTEXT ) );
+ else
+ clrPrevText = SetTextColor( lpdis->hDC, GetSysColor( fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT ) );
+
+ if ( fSelected )
+ clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT) );
+ else
+ clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_MENU) );
+
+ hbrOld = static_cast<HBRUSH>(SelectObject( lpdis->hDC, CreateSolidBrush( GetBkColor( lpdis->hDC ) ) ));
+
+ // Fill background
+ PatBlt(lpdis->hDC, aRect.left, aRect.top, aRect.right-aRect.left, aRect.bottom-aRect.top, PATCOPY);
+
+ int height = aRect.bottom-aRect.top;
+
+ x = aRect.left;
+ y = aRect.top;
+
+ int cx = GetSystemMetrics( SM_CXSMICON );
+ int cy = GetSystemMetrics( SM_CYSMICON );
+ HICON hIcon( nullptr );
+ HMODULE hModule( GetModuleHandleW( nullptr ) );
+
+ if ( pMyItem->module.getLength() > 0 )
+ {
+ LPCWSTR pModuleName = o3tl::toW( pMyItem->module.getStr() );
+ hModule = GetModuleHandleW( pModuleName );
+ if ( hModule == nullptr )
+ {
+ hModule = LoadLibraryW(pModuleName);
+ }
+ }
+
+ hIcon = static_cast<HICON>(LoadImageW( hModule, MAKEINTRESOURCEW( pMyItem->iconId ),
+ IMAGE_ICON, cx, cy,
+ LR_DEFAULTCOLOR | LR_SHARED ));
+
+
+ HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) );
+
+ DrawStateW( lpdis->hDC, hbrIcon, nullptr, reinterpret_cast<LPARAM>(hIcon), WPARAM(0), x, y+(height-cy)/2, 0, 0, DST_ICON | (fDisabled ? (fSelected ? DSS_MONO : DSS_DISABLED) : DSS_NORMAL) );
+
+ DeleteObject( hbrIcon );
+
+ x += cx + 4; // space for icon
+ aRect.left = x;
+
+ NONCLIENTMETRICSW ncm = {};
+ ncm.cbSize = sizeof(ncm);
+
+ SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
+
+ // Print default menu entry with bold font
+ if ( lpdis->itemState & ODS_DEFAULT )
+ ncm.lfMenuFont.lfWeight = FW_BOLD;
+
+ hfntOld = static_cast<HFONT>(SelectObject(lpdis->hDC, CreateFontIndirectW( &ncm.lfMenuFont )));
+
+
+ SIZE size;
+ GetTextExtentPointW( lpdis->hDC, o3tl::toW(pMyItem->text.getStr()), pMyItem->text.getLength(), &size );
+
+ DrawStateW( lpdis->hDC, nullptr, nullptr, reinterpret_cast<LPARAM>(pMyItem->text.getStr()), WPARAM(0), aRect.left, aRect.top + (height - size.cy)/2, 0, 0, DST_TEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) );
+
+ // Restore the original font and colors.
+ DeleteObject( SelectObject( lpdis->hDC, hbrOld ) );
+ DeleteObject( SelectObject( lpdis->hDC, hfntOld) );
+ SetTextColor(lpdis->hDC, clrPrevText);
+ SetBkColor(lpdis->hDC, clrPrevBkgnd);
+}
+
+
+// code from setup2 project
+
+
+static void SHFree_( void *pv )
+{
+ IMalloc *pMalloc;
+ if( NOERROR == SHGetMalloc(&pMalloc) )
+ {
+ pMalloc->Free( pv );
+ pMalloc->Release();
+ }
+}
+
+#define ALLOC(type, n) static_cast<type *>(HeapAlloc(GetProcessHeap(), 0, sizeof(type) * n ))
+#define FREE(p) HeapFree(GetProcessHeap(), 0, p)
+
+static OUString SHGetSpecialFolder( int nFolderID )
+{
+
+ LPITEMIDLIST pidl;
+ HRESULT hHdl = SHGetSpecialFolderLocation( nullptr, nFolderID, &pidl );
+ OUString aFolder;
+
+ if( hHdl == NOERROR )
+ {
+ WCHAR *lpFolderA;
+ lpFolderA = ALLOC( WCHAR, 16000 );
+
+ SHGetPathFromIDListW( pidl, lpFolderA );
+ aFolder = o3tl::toU( lpFolderA );
+
+ FREE( lpFolderA );
+ SHFree_( pidl );
+ }
+ return aFolder;
+}
+
+OUString ShutdownIcon::GetAutostartFolderNameW32()
+{
+ return SHGetSpecialFolder(CSIDL_STARTUP);
+}
+
+static HRESULT WINAPI SHCoCreateInstance( LPVOID lpszReserved, REFCLSID clsid, LPUNKNOWN pUnkUnknown, REFIID iid, LPVOID *ppv )
+{
+ HRESULT hResult = E_NOTIMPL;
+ HMODULE hModShell = GetModuleHandleW( L"SHELL32" );
+
+ if ( hModShell != nullptr )
+ {
+ typedef HRESULT (WINAPI *SHCoCreateInstance_PROC)( LPVOID lpszReserved, REFCLSID clsid, LPUNKNOWN pUnkUnknown, REFIID iid, LPVOID *ppv );
+
+ SHCoCreateInstance_PROC lpfnSHCoCreateInstance = reinterpret_cast<SHCoCreateInstance_PROC>(GetProcAddress( hModShell, MAKEINTRESOURCEA(102) ));
+
+ if ( lpfnSHCoCreateInstance )
+ hResult = lpfnSHCoCreateInstance( lpszReserved, clsid, pUnkUnknown, iid, ppv );
+ }
+ return hResult;
+}
+
+static bool CreateShortcut( const OUString& rAbsObject, const OUString& rAbsObjectPath,
+ const OUString& rAbsShortcut, const OUString& rDescription, const OUString& rParameter )
+{
+ HRESULT hres;
+ IShellLinkW* psl;
+ CLSID clsid_ShellLink = CLSID_ShellLink;
+ CLSID clsid_IShellLink = IID_IShellLinkW;
+
+ hres = CoCreateInstance( clsid_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
+ clsid_IShellLink, reinterpret_cast<void**>(&psl) );
+ if( FAILED(hres) )
+ hres = SHCoCreateInstance( nullptr, clsid_ShellLink, nullptr, clsid_IShellLink, reinterpret_cast<void**>(&psl) );
+
+ if( SUCCEEDED(hres) )
+ {
+ IPersistFile* ppf;
+ psl->SetPath( o3tl::toW(rAbsObject.getStr()) );
+ psl->SetWorkingDirectory( o3tl::toW(rAbsObjectPath.getStr()) );
+ psl->SetDescription( o3tl::toW(rDescription.getStr()) );
+ if( rParameter.getLength() )
+ psl->SetArguments( o3tl::toW(rParameter.getStr()) );
+
+ CLSID clsid_IPersistFile = IID_IPersistFile;
+ hres = psl->QueryInterface( clsid_IPersistFile, reinterpret_cast<void**>(&ppf) );
+
+ if( SUCCEEDED(hres) )
+ {
+ hres = ppf->Save( o3tl::toW(rAbsShortcut.getStr()), TRUE );
+ ppf->Release();
+ } else return false;
+ psl->Release();
+ } else return false;
+ return true;
+}
+
+
+// install/uninstall
+
+static bool FileExistsW( LPCWSTR lpPath )
+{
+ bool bExists = false;
+ WIN32_FIND_DATAW aFindData;
+
+ HANDLE hFind = FindFirstFileW( lpPath, &aFindData );
+
+ if ( INVALID_HANDLE_VALUE != hFind )
+ {
+ bExists = true;
+ FindClose( hFind );
+ }
+
+ return bExists;
+}
+
+bool ShutdownIcon::IsQuickstarterInstalled()
+{
+ wchar_t aPath[_MAX_PATH];
+ GetModuleFileNameW( nullptr, aPath, _MAX_PATH-1);
+
+ OUString aOfficepath( o3tl::toU(aPath) );
+ int i = aOfficepath.lastIndexOf('\\');
+ if( i != -1 )
+ aOfficepath = aOfficepath.copy(0, i);
+
+ OUString quickstartExe(aOfficepath + "\\quickstart.exe");
+
+ return FileExistsW( o3tl::toW(quickstartExe.getStr()) );
+}
+
+void ShutdownIcon::EnableAutostartW32( const OUString &aShortcut )
+{
+ wchar_t aPath[_MAX_PATH];
+ GetModuleFileNameW( nullptr, aPath, _MAX_PATH-1);
+
+ OUString aOfficepath( o3tl::toU(aPath) );
+ int i = aOfficepath.lastIndexOf('\\');
+ if( i != -1 )
+ aOfficepath = aOfficepath.copy(0, i);
+
+ OUString quickstartExe(aOfficepath + "\\quickstart.exe");
+
+ CreateShortcut( quickstartExe, aOfficepath, aShortcut, OUString(), OUString() );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/workwin.cxx b/sfx2/source/appl/workwin.cxx
new file mode 100644
index 0000000000..88b7cc016e
--- /dev/null
+++ b/sfx2/source/appl/workwin.cxx
@@ -0,0 +1,2356 @@
+/* -*- 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 <config_features.h>
+#include <config_feature_desktop.h>
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/app.hxx>
+#include <workwin.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/dockwin.hxx>
+#include <sfx2/viewsh.hxx>
+#include <splitwin.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/toolbarids.hxx>
+#include <vcl/taskpanelist.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/eitem.hxx>
+#include <tools/svborder.hxx>
+#include <tools/debug.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <com/sun/star/ui/XUIElement.hpp>
+#include <com/sun/star/frame/LayoutManagerEvents.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/frame/XLayoutManagerEventBroadcaster.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <type_traits>
+#include <unordered_map>
+#include <sfx2/notebookbar/SfxNotebookBar.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+struct ResIdToResName
+{
+ ToolbarId eId;
+ const char* pName;
+};
+
+}
+
+const ResIdToResName pToolBarResToName[] =
+{
+ { ToolbarId::FullScreenToolbox, "fullscreenbar" },
+ { ToolbarId::EnvToolbox, "standardbar", },
+ { ToolbarId::SvxTbx_Form_Navigation, "formsnavigationbar" },
+ { ToolbarId::SvxTbx_Form_Filter, "formsfilterbar" },
+ { ToolbarId::SvxTbx_Text_Control_Attributes, "formtextobjectbar" },
+ { ToolbarId::SvxTbx_Controls, "formcontrols" },
+ { ToolbarId::SvxTbx_FormDesign, "formdesign" },
+ { ToolbarId::Math_Toolbox, "toolbar" }, //math
+ { ToolbarId::Text_Toolbox_Sc, "textobjectbar" }, //calc
+ { ToolbarId::Draw_Objectbar, "drawobjectbar" },
+ { ToolbarId::Graphic_Objectbar, "graphicobjectbar" },
+ { ToolbarId::Objectbar_Format, "formatobjectbar" },
+ { ToolbarId::Objectbar_Preview, "previewbar" },
+ { ToolbarId::Objectbar_Tools, "toolbar" }, //calc
+ { ToolbarId::Bezier_Toolbox_Sd, "bezierobjectbar" }, //draw/impress
+ { ToolbarId::Gluepoints_Toolbox, "gluepointsobjectbar" },
+ { ToolbarId::Draw_Graf_Toolbox, "graphicobjectbar" },
+ { ToolbarId::Draw_Obj_Toolbox, "drawingobjectbar" }, //impress
+ { ToolbarId::Draw_Text_Toolbox_Sd, "textobjectbar" }, //impress
+ { ToolbarId::Draw_Toolbox_Sd, "toolbar" }, //impress
+ { ToolbarId::Draw_Options_Toolbox, "optionsbar" },
+ { ToolbarId::Draw_CommonTask_Toolbox, "commontaskbar" },
+ { ToolbarId::Graphic_Obj_Toolbox, "drawingobjectbar" }, //draw
+ { ToolbarId::Outline_Toolbox, "outlinetoolbar" }, //impress
+ { ToolbarId::Slide_Toolbox, "slideviewtoolbar" },
+ { ToolbarId::Slide_Obj_Toolbox, "slideviewobjectbar" },
+ { ToolbarId::Bezier_Toolbox_Sw, "bezierobjectbar" },
+ { ToolbarId::Draw_Toolbox_Sw, "drawingobjectbar" },
+ { ToolbarId::Draw_Text_Toolbox_Sw, "drawtextobjectbar" },
+ { ToolbarId::Frame_Toolbox, "frameobjectbar" },
+ { ToolbarId::Grafik_Toolbox, "graphicobjectbar" },
+ { ToolbarId::Num_Toolbox, "numobjectbar" },
+ { ToolbarId::Ole_Toolbox, "oleobjectbar" },
+ { ToolbarId::Table_Toolbox, "tableobjectbar" },
+ { ToolbarId::Text_Toolbox_Sw, "textobjectbar" },
+ { ToolbarId::PView_Toolbox, "previewobjectbar" }, //writer
+ { ToolbarId::Webtools_Toolbox, "toolbar" }, //web
+ { ToolbarId::Webtext_Toolbox, "textobjectbar" },
+ { ToolbarId::Tools_Toolbox, "toolbar" }, //writer
+ { ToolbarId::Webframe_Toolbox, "frameobjectbar" }, //web
+ { ToolbarId::Webgraphic_Toolbox, "graphicobjectbar" },
+ { ToolbarId::Webole_Toolbox, "oleobjectbar" },
+ { ToolbarId::Basicide_Objectbar, "macrobar" },
+ { ToolbarId::Svx_Fontwork_Bar, "fontworkobjectbar" }, //global
+ { ToolbarId::Svx_Extrusion_Bar, "extrusionobjectbar" },
+ { ToolbarId::FormLayer_Toolbox, "formsobjectbar" },
+ { ToolbarId::Module_Toolbox, "viewerbar" }, //writer (plugin)
+ { ToolbarId::Objectbar_App, "viewerbar" }, //calc (plugin)
+ { ToolbarId::Draw_Viewer_Toolbox, "viewerbar" }, //impress(plugin)
+ { ToolbarId::Draw_Media_Toolbox, "mediaobjectbar" }, //draw/impress
+ { ToolbarId::Media_Objectbar, "mediaobjectbar" }, //calc
+ { ToolbarId::Media_Toolbox, "mediaobjectbar" }, //writer
+ { ToolbarId::None, "" }
+};
+
+// Sort the Children according their alignment
+// The order corresponds to the enum SfxChildAlignment (->CHILDWIN.HXX).
+
+constexpr OUString g_aLayoutManagerPropName = u"LayoutManager"_ustr;
+
+// Help to make changes to the alignment compatible!
+LayoutManagerListener::LayoutManagerListener(
+ SfxWorkWindow* pWrkWin ) :
+ m_bHasFrame( false ),
+ m_pWrkWin( pWrkWin )
+{
+}
+
+LayoutManagerListener::~LayoutManagerListener()
+{
+}
+
+void LayoutManagerListener::setFrame( const css::uno::Reference< css::frame::XFrame >& xFrame )
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pWrkWin || m_bHasFrame )
+ return;
+
+ m_xFrame = xFrame;
+ m_bHasFrame = true;
+
+ if ( !xFrame.is() )
+ return;
+
+ css::uno::Reference< css::beans::XPropertySet > xPropSet( xFrame, UNO_QUERY );
+ css::uno::Reference< css::frame::XLayoutManagerEventBroadcaster > xLayoutManager;
+ if ( !xPropSet.is() )
+ return;
+
+ try
+ {
+ Any aValue = xPropSet->getPropertyValue( g_aLayoutManagerPropName );
+ aValue >>= xLayoutManager;
+
+ if ( xLayoutManager.is() )
+ xLayoutManager->addLayoutManagerEventListener(
+ css::uno::Reference< css::frame::XLayoutManagerListener >(this) );
+
+ xPropSet.set( xLayoutManager, UNO_QUERY );
+ if ( xPropSet.is() )
+ {
+ aValue = xPropSet->getPropertyValue( "LockCount" );
+ aValue >>= m_pWrkWin->m_nLock;
+ }
+ }
+ catch ( css::lang::DisposedException& )
+ {
+ }
+ catch ( const css::uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( css::uno::Exception& )
+ {
+ }
+}
+
+
+// XComponent
+
+void SAL_CALL LayoutManagerListener::addEventListener(
+ const css::uno::Reference< css::lang::XEventListener >& )
+{
+ // do nothing, only internal class
+}
+
+void SAL_CALL LayoutManagerListener::removeEventListener(
+ const css::uno::Reference< css::lang::XEventListener >& )
+{
+ // do nothing, only internal class
+}
+
+void SAL_CALL LayoutManagerListener::dispose()
+{
+ SolarMutexGuard aGuard;
+
+ // reset member
+ m_pWrkWin = nullptr;
+
+ css::uno::Reference< css::frame::XFrame > xFrame( m_xFrame.get(), css::uno::UNO_QUERY );
+ if ( !xFrame.is() )
+ return;
+
+ m_xFrame.clear();
+ m_bHasFrame = false;
+
+ css::uno::Reference< css::beans::XPropertySet > xPropSet( xFrame, css::uno::UNO_QUERY );
+ css::uno::Reference< css::frame::XLayoutManagerEventBroadcaster > xLayoutManager;
+ if ( !xPropSet.is() )
+ return;
+
+ try
+ {
+ css::uno::Any aValue = xPropSet->getPropertyValue( g_aLayoutManagerPropName );
+ aValue >>= xLayoutManager;
+
+ // remove as listener from layout manager
+ if ( xLayoutManager.is() )
+ xLayoutManager->removeLayoutManagerEventListener(
+ css::uno::Reference< css::frame::XLayoutManagerListener >(this) );
+ }
+ catch ( css::lang::DisposedException& )
+ {
+ }
+ catch ( const css::uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch ( css::uno::Exception& )
+ {
+ }
+}
+
+
+// XEventListener
+
+void SAL_CALL LayoutManagerListener::disposing(
+ const css::lang::EventObject& )
+{
+ SolarMutexGuard aGuard;
+ m_pWrkWin = nullptr;
+ m_bHasFrame = false;
+ m_xFrame.clear();
+}
+
+
+// XLayoutManagerEventListener
+
+void SAL_CALL LayoutManagerListener::layoutEvent(
+ const css::lang::EventObject&,
+ ::sal_Int16 eLayoutEvent,
+ const css::uno::Any& )
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pWrkWin )
+ return;
+
+ if ( eLayoutEvent == css::frame::LayoutManagerEvents::VISIBLE )
+ {
+ m_pWrkWin->MakeVisible_Impl( true );
+ m_pWrkWin->ShowChildren_Impl();
+ m_pWrkWin->ArrangeChildren_Impl();
+ }
+ else if ( eLayoutEvent == css::frame::LayoutManagerEvents::INVISIBLE )
+ {
+ m_pWrkWin->MakeVisible_Impl( false );
+ m_pWrkWin->HideChildren_Impl();
+ m_pWrkWin->ArrangeChildren_Impl();
+ }
+ else if ( eLayoutEvent == css::frame::LayoutManagerEvents::LOCK )
+ {
+ m_pWrkWin->Lock_Impl( true );
+ }
+ else if ( eLayoutEvent == css::frame::LayoutManagerEvents::UNLOCK )
+ {
+ m_pWrkWin->Lock_Impl( false );
+ }
+}
+
+namespace
+{
+ struct ToolbarIdHash
+ {
+ size_t operator()(ToolbarId t) const
+ {
+ typedef std::underlying_type<ToolbarId>::type underlying_type;
+ return std::hash<underlying_type>()(static_cast<underlying_type>(t));
+ }
+ };
+
+ class FilledToolBarResIdToResourceURLMap
+ {
+ private:
+ typedef std::unordered_map<ToolbarId, OUString, ToolbarIdHash> ToolBarResIdToResourceURLMap;
+ ToolBarResIdToResourceURLMap m_aResIdToResourceURLMap;
+ public:
+ FilledToolBarResIdToResourceURLMap()
+ {
+ sal_Int32 nIndex( 0 );
+ while (pToolBarResToName[nIndex].eId != ToolbarId::None)
+ {
+ OUString aResourceURL( OUString::createFromAscii( pToolBarResToName[nIndex].pName ));
+ m_aResIdToResourceURLMap.emplace(pToolBarResToName[nIndex].eId, aResourceURL);
+ ++nIndex;
+ }
+ }
+
+ OUString findURL(ToolbarId eId) const
+ {
+ ToolBarResIdToResourceURLMap::const_iterator aIter = m_aResIdToResourceURLMap.find(eId);
+ if ( aIter != m_aResIdToResourceURLMap.end() )
+ return aIter->second;
+ return OUString();
+ }
+ };
+}
+
+static OUString GetResourceURLFromToolbarId(ToolbarId eId)
+{
+ static FilledToolBarResIdToResourceURLMap theFilledToolBarResIdToResourceURLMap;
+ return theFilledToolBarResIdToResourceURLMap.findURL(eId);
+}
+
+static sal_uInt16 TbxMatch( sal_uInt16 nPos )
+{
+ switch ( nPos )
+ {
+ case SFX_OBJECTBAR_APPLICATION :
+ return 0;
+ case SFX_OBJECTBAR_OPTIONS:
+ return 1;
+ case SFX_OBJECTBAR_MACRO:
+ return 2;
+ case SFX_OBJECTBAR_OBJECT:
+ return 3;
+ case SFX_OBJECTBAR_TOOLS:
+ return 4;
+ case SFX_OBJECTBAR_FULLSCREEN:
+ case SFX_OBJECTBAR_COMMONTASK:
+ case SFX_OBJECTBAR_RECORDING:
+ return nPos+1;
+ default:
+ return nPos;
+ }
+}
+
+static sal_uInt16 ChildAlignValue(SfxChildAlignment eAlign)
+{
+ sal_uInt16 ret = 17;
+
+ switch (eAlign)
+ {
+ case SfxChildAlignment::HIGHESTTOP:
+ ret = 1;
+ break;
+ case SfxChildAlignment::LOWESTBOTTOM:
+ ret = 2;
+ break;
+ case SfxChildAlignment::FIRSTLEFT:
+ ret = 3;
+ break;
+ case SfxChildAlignment::LASTRIGHT:
+ ret = 4;
+ break;
+ case SfxChildAlignment::LEFT:
+ ret = 5;
+ break;
+ case SfxChildAlignment::RIGHT:
+ ret = 6;
+ break;
+ case SfxChildAlignment::FIRSTRIGHT:
+ ret = 7;
+ break;
+ case SfxChildAlignment::LASTLEFT:
+ ret = 8;
+ break;
+ case SfxChildAlignment::TOP:
+ ret = 9;
+ break;
+ case SfxChildAlignment::BOTTOM:
+ ret = 10;
+ break;
+ case SfxChildAlignment::TOOLBOXTOP:
+ ret = 11;
+ break;
+ case SfxChildAlignment::TOOLBOXBOTTOM:
+ ret = 12;
+ break;
+ case SfxChildAlignment::LOWESTTOP:
+ ret = 13;
+ break;
+ case SfxChildAlignment::HIGHESTBOTTOM:
+ ret = 14;
+ break;
+ case SfxChildAlignment::TOOLBOXLEFT:
+ ret = 15;
+ break;
+ case SfxChildAlignment::TOOLBOXRIGHT:
+ ret = 16;
+ break;
+ case SfxChildAlignment::NOALIGNMENT:
+ break; // -Wall not handled...
+ }
+
+ return ret;
+}
+
+void SfxWorkWindow::Sort_Impl()
+{
+ aSortedList.clear();
+ for (size_t i = 0; i < aChildren.size(); ++i)
+ {
+ SfxChild_Impl *pCli = aChildren[i].get();
+ if (pCli)
+ {
+ decltype(aSortedList)::size_type k;
+ for (k=0; k<aSortedList.size(); k++)
+ if (ChildAlignValue( aChildren[aSortedList[k]]->eAlign ) >
+ ChildAlignValue(pCli->eAlign))
+ break;
+ aSortedList.insert( aSortedList.begin() + k, i );
+ }
+ }
+
+ bSorted = true;
+}
+
+constexpr OUString g_aStatusBarResName( u"private:resource/statusbar/statusbar"_ustr );
+constexpr OUString g_aTbxTypeName( u"private:resource/toolbar/"_ustr );
+constexpr OUString g_aProgressBarResName( u"private:resource/progressbar/progressbar"_ustr );
+
+// constructor for workwin of a Frame
+
+SfxWorkWindow::SfxWorkWindow( vcl::Window *pWin, SfxFrame *pFrm, SfxFrame* pMaster ) :
+ pBindings(&pFrm->GetCurrentViewFrame()->GetBindings()),
+ pWorkWin (pWin),
+ pActiveChild( nullptr ),
+ nUpdateMode(SfxVisibilityFlags::Standard),
+ nChildren( 0 ),
+ nOrigMode( SfxVisibilityFlags::Invisible ),
+ bSorted( true ),
+ bDockingAllowed(true),
+ bInternalDockingAllowed(true),
+ bAllChildrenVisible(true),
+#if !defined(ANDROID) || HAVE_FEATURE_ANDROID_LOK
+ bIsFullScreen( false ),
+#else // Fennec-based Android Viewer
+ bIsFullScreen( true ),
+#endif
+#if HAVE_FEATURE_DESKTOP
+ bShowStatusBar( true ),
+#else
+ bShowStatusBar( sal_False ),
+#endif
+ m_nLock( 0 ),
+ pMasterFrame( pMaster ),
+ pFrame( pFrm )
+{
+ DBG_ASSERT (pBindings, "No Bindings!");
+
+ pBindings->SetWorkWindow_Impl( std::unique_ptr<SfxWorkWindow>(this) );
+
+ // For the ObjectBars an integral place in the Childlist is reserved,
+ // so that they always come in a defined order.
+ for (int i=0; i<SFX_OBJECTBAR_MAX; ++i)
+ aChildren.push_back( nullptr );
+
+ // create and initialize layout manager listener
+ Reference< css::frame::XFrame > xFrame = GetFrameInterface();
+ rtl::Reference<LayoutManagerListener> pLayoutManagerListener = new LayoutManagerListener( this );
+ m_xLayoutManagerListener = pLayoutManagerListener;
+ pLayoutManagerListener->setFrame( xFrame );
+
+ SfxShell* pConfigShell = pFrm->GetCurrentViewFrame();
+ if ( pConfigShell && pConfigShell->GetObjectShell() )
+ {
+ bShowStatusBar = ( !pConfigShell->GetObjectShell()->IsInPlaceActive() );
+ bDockingAllowed = true;
+ bInternalDockingAllowed = true;
+ }
+
+ // The required split windows (one for each side) can be created
+ for ( sal_uInt16 n=0; n<SFX_SPLITWINDOWS_MAX; n++ )
+ {
+ // The SplitWindows excludes direct ChildWindows of the WorkWindows
+ // and receives the docked window.
+
+ SfxChildAlignment eAlign =
+ ( n == SFX_SPLITWINDOWS_LEFT ? SfxChildAlignment::LEFT :
+ n == SFX_SPLITWINDOWS_RIGHT ? SfxChildAlignment::RIGHT :
+ n == SFX_SPLITWINDOWS_TOP ? SfxChildAlignment::TOP :
+ SfxChildAlignment::BOTTOM );
+ VclPtr<SfxSplitWindow> pSplitWin = VclPtr<SfxSplitWindow>::Create(pWorkWin, eAlign, this, true );
+ pSplit[n] = pSplitWin;
+ }
+
+ nOrigMode = SfxVisibilityFlags::Standard;
+ nUpdateMode = SfxVisibilityFlags::Standard;
+}
+
+
+// Destructor
+
+SfxWorkWindow::~SfxWorkWindow()
+{
+
+ // Delete SplitWindows
+ for (VclPtr<SfxSplitWindow> & p : pSplit)
+ {
+ if (p->GetWindowCount())
+ ReleaseChild_Impl(*p);
+ p.disposeAndClear();
+ }
+
+ // Delete help structure for Child-Windows
+ DBG_ASSERT( aChildren.empty(), "dangling children" );
+
+ if ( m_xLayoutManagerListener.is() )
+ m_xLayoutManagerListener->dispose();
+}
+
+void SfxWorkWindow::Lock_Impl( bool bLock )
+{
+ if ( bLock )
+ m_nLock++;
+ else
+ --m_nLock;
+ if ( m_nLock<0 )
+ {
+ OSL_FAIL("Lock count underflow!");
+ assert(m_nLock >= 0);
+ m_nLock = 0;
+ }
+
+ if ( !m_nLock )
+ ArrangeChildren_Impl();
+}
+
+
+// Helper method to release the child lists. Should the destructor not be
+// called after this, instead work continues, then space for the object bars
+// and split windows has to be reserved in the same way as in the constructor
+// of SfxWorkWindow.
+
+void SfxWorkWindow::DeleteControllers_Impl()
+{
+
+ // Lock SplitWindows (which means suppressing the Resize-Reaction of the
+ // DockingWindows)
+ for (size_t n=0; n<SFX_SPLITWINDOWS_MAX; n++ )
+ {
+ VclPtr<SfxSplitWindow> const &p = pSplit[n];
+ if (p->GetWindowCount())
+ p->Lock();
+ }
+
+ // Delete Child-Windows
+ while(!aChildWins.empty())
+ {
+ std::unique_ptr<SfxChildWin_Impl> pCW = std::move(*aChildWins.begin());
+ aChildWins.erase(aChildWins.begin());
+ SfxChildWindow *pChild = pCW->pWin;
+ if (pChild)
+ {
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ vcl::Window* pWindow = pChild->GetWindow();
+ if (pWindow)
+ {
+ pWindow->ReleaseLOKNotifier();
+ }
+ }
+ pChild->Hide();
+
+ // If the child window is a direct child window and not in a
+ // SplitWindow, cancel it at the workwindow.
+ // After TH a cancellation on the SplitWindow is not necessary
+ // since this window is also destroyed (see below).
+ if (pCW->pCli)
+ {
+ if (pChild->GetController())
+ ReleaseChild_Impl(*pChild->GetController());
+ else
+ ReleaseChild_Impl(*pChild->GetWindow());
+ }
+
+ pCW->pWin = nullptr;
+ pWorkWin->GetSystemWindow()->GetTaskPaneList()->RemoveWindow( pChild->GetWindow() );
+ pChild->Destroy();
+ }
+
+ // ATTENTION: The array itself is cleared after this loop!!
+ // Therefore we have to set every array entry to zero as it could be
+ // accessed by calling pChild->Destroy().
+ // Window::NotifyAllChildren() calls SfxWorkWindow::DataChanged_Impl for
+ // 8-bit displays (WM_QUERYPALETTECHANGED message due to focus change)!!
+ }
+
+ Reference< css::frame::XFrame > xFrame = GetFrameInterface();
+ Reference< css::beans::XPropertySet > xPropSet( xFrame, UNO_QUERY );
+ Reference< css::frame::XLayoutManager > xLayoutManager;
+ if ( xPropSet.is() )
+ {
+ try
+ {
+ Any aValue = xPropSet->getPropertyValue( g_aLayoutManagerPropName );
+ aValue >>= xLayoutManager;
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+
+ if ( xLayoutManager.is() )
+ {
+ xLayoutManager->reset();
+
+ // Delete StatusBar
+ ResetStatusBar_Impl();
+
+ // Delete ObjectBars (this is done last, so that aChildren does not
+ // receive dead Pointers)
+ for (SfxObjectBar_Impl & i : aObjBarList)
+ {
+ // Not every position must be occupied
+ ToolbarId eId = i.eId;
+ if (eId != ToolbarId::None)
+ i.eId = ToolbarId::None;
+ }
+ }
+
+ // ObjectBars are all released at once, since they occupy a
+ // fixed contiguous area in the array pChild
+ aChildren.clear();
+ bSorted = false;
+
+ nChildren = 0;
+}
+
+
+// for placing the child window.
+
+void SfxWorkWindow::ArrangeChildren_Impl( bool bForce )
+{
+ if ( pFrame->IsClosing_Impl() || ( m_nLock && !bForce ))
+ return;
+
+ SfxInPlaceClient *pClient = nullptr;
+ SfxViewFrame *pF = pFrame->GetCurrentViewFrame();
+ if ( pF && pF->GetViewShell() )
+ pClient = pF->GetViewShell()->GetIPClient();
+
+ if ( pClient )
+ return;
+
+ aClientArea = GetTopRect_Impl();
+ if ( aClientArea.IsEmpty() )
+ return;
+
+ SvBorder aBorder;
+ if ( nChildren && IsVisible_Impl() )
+ aBorder = Arrange_Impl();
+ // If the current application document contains an IPClient, then the
+ // object through SetTopToolFramePixel has to be assigned the available
+ // space. The object will then point to its UITools and sets the app border
+ // (-> SfxInPlaceEnv_Impl:: ArrangeChildren_Impl ()). Otherwise the
+ // app border is set here directly to possibly overwrite the Border that
+ // was set by an object from another document. The object does not set
+ // the SetAppBorder when it removes its UI tools so that no-dithering
+ // ObjectBar arises.
+ // (->SfxInPlaceEnv_Impl::ArrangeChildren_Impl())
+
+ pMasterFrame->SetToolSpaceBorderPixel_Impl( aBorder );
+
+ ArrangeAutoHideWindows( nullptr );
+}
+
+void SfxWorkWindow::FlushPendingChildSizes()
+{
+ // tdf#116865, if any windows are being resized, i.e. their
+ // resize timer is active, then calling GetSizePixel on
+ // them forces the timer to fire and sets the final
+ // size to which they are getting resized towards.
+ for (size_t i = 0; i < aChildren.size(); ++i)
+ {
+ SfxChild_Impl *pCli = aChildren[i].get();
+ if (!pCli || !pCli->pWin)
+ continue;
+ (void)pCli->pWin->GetSizePixel();
+ }
+}
+
+SvBorder SfxWorkWindow::Arrange_Impl()
+
+/* [Description]
+
+ This method organizes all visible child windows so that the docked window
+ sorted in order from the outside to the inside are placed after one
+ another. If a visible window does not fit anymore into the free
+ ClientArea, it is set to "not visible".
+*/
+{
+ //tdf#116865 trigger pending sizing timers now so we arrange
+ //with the final size of the client area.
+ //
+ //Otherwise calling GetSizePixel in the following loop will trigger the
+ //timers, causing reentry into Arrange_Impl again where the inner
+ //Arrange_Impl arranges with the final size, and then returns to this outer
+ //Arrange_Impl which would rearrange with the old client area size
+ FlushPendingChildSizes();
+ aClientArea = GetTopRect_Impl();
+ aUpperClientArea = aClientArea;
+
+ SvBorder aBorder;
+ if ( !nChildren )
+ return aBorder;
+
+ if (!bSorted)
+ Sort_Impl();
+
+ Point aPos;
+ Size aSize;
+ tools::Rectangle aTmp( aClientArea );
+
+ for (sal_uInt16 n : aSortedList)
+ {
+ SfxChild_Impl* pCli = aChildren[n].get();
+ if ( !pCli->pWin )
+ continue;
+
+ // First, we assume that there is room for the window.
+ pCli->nVisible |= SfxChildVisibility::FITS_IN;
+
+ // Skip invisible windows
+ if (pCli->nVisible != SfxChildVisibility::VISIBLE)
+ continue;
+
+ if ( pCli->bResize )
+ aSize = pCli->aSize;
+ else
+ aSize = pCli->pWin->GetSizePixel();
+
+ SvBorder aTemp = aBorder;
+ bool bAllowHiding = true;
+ switch ( pCli->eAlign )
+ {
+ case SfxChildAlignment::HIGHESTTOP:
+ case SfxChildAlignment::TOP:
+ case SfxChildAlignment::TOOLBOXTOP:
+ case SfxChildAlignment::LOWESTTOP:
+ aSize.setWidth( aTmp.GetWidth() );
+ if ( pCli->pWin->GetType() == WindowType::SPLITWINDOW )
+ aSize = static_cast<SplitWindow *>(pCli->pWin.get())->CalcLayoutSizePixel( aSize );
+ bAllowHiding = false;
+ aBorder.Top() += aSize.Height();
+ aPos = aTmp.TopLeft();
+ aTmp.AdjustTop(aSize.Height() );
+ if ( pCli->eAlign == SfxChildAlignment::HIGHESTTOP )
+ aUpperClientArea.AdjustTop(aSize.Height() );
+ break;
+
+ case SfxChildAlignment::LOWESTBOTTOM:
+ case SfxChildAlignment::BOTTOM:
+ case SfxChildAlignment::TOOLBOXBOTTOM:
+ case SfxChildAlignment::HIGHESTBOTTOM:
+ aSize.setWidth( aTmp.GetWidth() );
+ if ( pCli->pWin->GetType() == WindowType::SPLITWINDOW )
+ aSize = static_cast<SplitWindow *>(pCli->pWin.get())->CalcLayoutSizePixel( aSize );
+ aBorder.Bottom() += aSize.Height();
+ aPos = aTmp.BottomLeft();
+ aPos.AdjustY( -(aSize.Height()-1) );
+ aTmp.AdjustBottom( -(aSize.Height()) );
+ if ( pCli->eAlign == SfxChildAlignment::LOWESTBOTTOM )
+ aUpperClientArea.AdjustBottom( -(aSize.Height()) );
+ break;
+
+ case SfxChildAlignment::FIRSTLEFT:
+ case SfxChildAlignment::LEFT:
+ case SfxChildAlignment::LASTLEFT:
+ case SfxChildAlignment::TOOLBOXLEFT:
+ aSize.setHeight( aTmp.GetHeight() );
+ if ( pCli->pWin->GetType() == WindowType::SPLITWINDOW )
+ aSize = static_cast<SplitWindow *>(pCli->pWin.get())->CalcLayoutSizePixel( aSize );
+ bAllowHiding = false;
+ aBorder.Left() += aSize.Width();
+ aPos = aTmp.TopLeft();
+ aTmp.AdjustLeft(aSize.Width() );
+ if ( pCli->eAlign != SfxChildAlignment::TOOLBOXLEFT )
+ aUpperClientArea.AdjustLeft(aSize.Width() );
+ break;
+
+ case SfxChildAlignment::FIRSTRIGHT:
+ case SfxChildAlignment::RIGHT:
+ case SfxChildAlignment::LASTRIGHT:
+ case SfxChildAlignment::TOOLBOXRIGHT:
+ aSize.setHeight( aTmp.GetHeight() );
+ if ( pCli->pWin->GetType() == WindowType::SPLITWINDOW )
+ aSize = static_cast<SplitWindow *>(pCli->pWin.get())->CalcLayoutSizePixel( aSize );
+ aBorder.Right() += aSize.Width();
+ aPos = aTmp.TopRight();
+ aPos.AdjustX( -(aSize.Width()-1) );
+ aTmp.AdjustRight( -(aSize.Width()) );
+ if ( pCli->eAlign != SfxChildAlignment::TOOLBOXRIGHT )
+ aUpperClientArea.AdjustRight( -(aSize.Width()) );
+ break;
+
+ default:
+ pCli->aSize = pCli->pWin->GetSizePixel();
+ pCli->bResize = false;
+ continue;
+ }
+
+ pCli->pWin->SetPosSizePixel( aPos, aSize );
+ pCli->bResize = false;
+ pCli->aSize = aSize;
+ if( bAllowHiding && !RequestTopToolSpacePixel_Impl( aBorder ) )
+ {
+ pCli->nVisible ^= SfxChildVisibility::FITS_IN;
+ aBorder = aTemp;
+ }
+ }
+
+ if ( aClientArea.GetWidth() >= aBorder.Left() + aBorder.Right() )
+ {
+ aClientArea.AdjustLeft(aBorder.Left() );
+ aClientArea.AdjustRight( -(aBorder.Right()) );
+ }
+ else
+ {
+ aBorder.Left() = aClientArea.Left();
+ aBorder.Right() = aClientArea.Right();
+ aClientArea.SetRight( aTmp.Left() );
+ aClientArea.SetLeft( aTmp.Left() );
+ }
+
+ if ( aClientArea.GetHeight() >= aBorder.Top() + aBorder.Bottom() )
+ {
+ aClientArea.AdjustTop(aBorder.Top() );
+ aClientArea.AdjustBottom( -(aBorder.Bottom()) );
+ }
+ else
+ {
+ aBorder.Top() = aClientArea.Top();
+ aBorder.Bottom() = aClientArea.Bottom();
+ aClientArea.SetTop(aTmp.Top());
+ aClientArea.SetBottom(aTmp.Top());
+ }
+
+ return IsDockingAllowed() ? aBorder : SvBorder();
+}
+
+bool SfxWorkWindow::PrepareClose_Impl()
+{
+ for (const std::unique_ptr<SfxChildWin_Impl> &pCW : aChildWins)
+ {
+ SfxChildWindow *pChild = pCW->pWin;
+ if ( pChild && !pChild->QueryClose() )
+ return false;
+ }
+
+ return true;
+}
+
+SfxChild_Impl* SfxWorkWindow::RegisterChild_Impl( vcl::Window& rWindow,
+ SfxChildAlignment eAlign )
+{
+ DBG_ASSERT( aChildren.size() < 255, "too many children" );
+ DBG_ASSERT( SfxChildAlignValid(eAlign), "invalid align" );
+ DBG_ASSERT( !FindChild_Impl(&rWindow), "child registered more than once" );
+
+
+ if ( rWindow.GetParent() != pWorkWin )
+ rWindow.SetParent( pWorkWin );
+
+ auto pChild = std::make_unique<SfxChild_Impl>(rWindow, rWindow.GetSizePixel(),
+ eAlign, rWindow.IsVisible());
+
+ aChildren.push_back(std::move(pChild));
+ bSorted = false;
+ nChildren++;
+ return aChildren.back().get();
+}
+
+SfxChild_Impl* SfxWorkWindow::RegisterChild_Impl(std::shared_ptr<SfxDialogController>& rController,
+ SfxChildAlignment eAlign )
+{
+ DBG_ASSERT( aChildren.size() < 255, "too many children" );
+ DBG_ASSERT( SfxChildAlignValid(eAlign), "invalid align" );
+
+ auto pChild = std::make_unique<SfxChild_Impl>(rController, eAlign);
+
+ aChildren.push_back(std::move(pChild));
+ bSorted = false;
+ nChildren++;
+ return aChildren.back().get();
+}
+
+void SfxWorkWindow::ReleaseChild_Impl( vcl::Window& rWindow )
+{
+
+ SfxChild_Impl *pChild = nullptr;
+ decltype(aChildren)::size_type nPos;
+ for ( nPos = 0; nPos < aChildren.size(); ++nPos )
+ {
+ pChild = aChildren[nPos].get();
+ if ( pChild && pChild->pWin == &rWindow )
+ {
+ bSorted = false;
+ nChildren--;
+ aChildren.erase(aChildren.begin() + nPos);
+ return;
+ }
+ }
+ OSL_FAIL( "releasing unregistered child" );
+}
+
+void SfxWorkWindow::ReleaseChild_Impl(const SfxDialogController& rController)
+{
+
+ SfxChild_Impl *pChild = nullptr;
+ decltype(aChildren)::size_type nPos;
+ for ( nPos = 0; nPos < aChildren.size(); ++nPos )
+ {
+ pChild = aChildren[nPos].get();
+ if (pChild && pChild->xController.get() == &rController)
+ {
+ bSorted = false;
+ nChildren--;
+ aChildren.erase(aChildren.begin() + nPos);
+ return;
+ }
+ }
+ OSL_FAIL( "releasing unregistered child" );
+}
+
+SfxChild_Impl* SfxWorkWindow::FindChild_Impl( const vcl::Window* rWindow ) const
+{
+
+ sal_uInt16 nCount = aChildren.size();
+ for ( sal_uInt16 nPos = 0; nPos < nCount; ++nPos )
+ {
+ SfxChild_Impl *pChild = aChildren[nPos].get();
+ if ( pChild && pChild->pWin == rWindow )
+ return pChild;
+ }
+
+ return nullptr;
+}
+
+void SfxWorkWindow::ShowChildren_Impl()
+{
+ bool bInvisible = ( !IsVisible_Impl() || ( !pWorkWin->IsReallyVisible() && !pWorkWin->IsReallyShown() ));
+
+ for (std::unique_ptr<SfxChild_Impl>& pCli : aChildren)
+ {
+ if (!pCli)
+ continue;
+ SfxChildWin_Impl* pCW = nullptr;
+ if (pCli->pWin || pCli->xController)
+ {
+ // We have to find the SfxChildWin_Impl to retrieve the
+ // SFX_CHILDWIN flags that can influence visibility.
+ for (const std::unique_ptr<SfxChildWin_Impl>& pCWin : aChildWins)
+ {
+ SfxChild_Impl* pChild = pCWin->pCli;
+ if ( pChild == pCli.get() )
+ {
+ pCW = pCWin.get();
+ break;
+ }
+ }
+
+ bool bVisible( !bInvisible );
+ if ( pCW )
+ {
+ // Check flag SFX_CHILDWIN_NEVERHIDE that forces us to show
+ // the child window even in situations where no child window is
+ // visible.
+ SfxChildWindowFlags nFlags = pCW->aInfo.nFlags;
+ bVisible = !bInvisible || ( nFlags & SfxChildWindowFlags::NEVERHIDE );
+ }
+
+ if ( SfxChildVisibility::VISIBLE == (pCli->nVisible & SfxChildVisibility::VISIBLE) && bVisible )
+ {
+ if (pCli->xController)
+ {
+ if (!pCli->xController->getDialog()->get_visible())
+ {
+ auto xController = pCli->xController;
+ weld::DialogController::runAsync(xController,
+ [=](sal_Int32 nResult){
+ if (nResult == nCloseResponseToJustHide)
+ return;
+ xController->Close();
+ });
+ }
+ }
+ else
+ {
+ ShowFlags nFlags = pCli->bSetFocus ? ShowFlags::NONE : ShowFlags::NoFocusChange | ShowFlags::NoActivate;
+ pCli->pWin->Show(true, nFlags);
+ }
+ pCli->bSetFocus = false;
+ }
+ else
+ {
+ if (pCli->xController)
+ {
+ if (pCli->xController->getDialog()->get_visible())
+ pCli->xController->response(RET_CLOSE);
+ }
+ else
+ pCli->pWin->Hide();
+ }
+ }
+ }
+}
+
+
+void SfxWorkWindow::HideChildren_Impl()
+{
+ for ( sal_uInt16 nPos = aChildren.size(); nPos > 0; --nPos )
+ {
+ SfxChild_Impl *pChild = aChildren[nPos-1].get();
+ if (!pChild)
+ continue;
+ if (pChild->xController)
+ pChild->xController->response(RET_CLOSE);
+ else if (pChild->pWin)
+ pChild->pWin->Hide();
+ }
+}
+
+void SfxWorkWindow::ResetObjectBars_Impl()
+{
+ for ( auto & n: aObjBarList )
+ n.bDestroy = true;
+
+ for ( auto & n: aChildWins )
+ n->nId = 0;
+}
+
+void SfxWorkWindow::SetObjectBar_Impl(sal_uInt16 nPos, SfxVisibilityFlags nFlags, ToolbarId eId)
+{
+ DBG_ASSERT( nPos < SFX_OBJECTBAR_MAX, "object bar position overflow" );
+
+ SfxObjectBar_Impl aObjBar;
+ aObjBar.eId = eId;
+ aObjBar.nMode = nFlags;
+
+ for (SfxObjectBar_Impl & rBar : aObjBarList)
+ {
+ if ( rBar.eId == aObjBar.eId )
+ {
+ rBar = aObjBar;
+ return;
+ }
+ }
+
+ aObjBarList.push_back( aObjBar );
+}
+
+bool SfxWorkWindow::IsVisible_Impl( SfxVisibilityFlags nMode ) const
+{
+ switch( nUpdateMode )
+ {
+ case SfxVisibilityFlags::Standard:
+ return true;
+ case SfxVisibilityFlags::Invisible:
+ return false;
+ case SfxVisibilityFlags::Client:
+ case SfxVisibilityFlags::Server:
+ return bool(nMode & nUpdateMode);
+ default:
+ return (nMode & nOrigMode ) ||
+ nOrigMode == SfxVisibilityFlags::Standard;
+ }
+}
+
+void SfxWorkWindow::UpdateObjectBars_Impl()
+{
+ if ( pFrame->IsClosing_Impl() )
+ return;
+
+ UpdateObjectBars_Impl2();
+
+ {
+ ArrangeChildren_Impl( false );
+
+ ShowChildren_Impl();
+ }
+
+ ShowChildren_Impl();
+}
+
+Reference< css::task::XStatusIndicator > SfxWorkWindow::GetStatusIndicator()
+{
+ Reference< css::beans::XPropertySet > xPropSet( GetFrameInterface(), UNO_QUERY );
+ Reference< css::frame::XLayoutManager > xLayoutManager;
+ Reference< css::task::XStatusIndicator > xStatusIndicator;
+
+ if ( xPropSet.is() )
+ {
+ Any aValue = xPropSet->getPropertyValue( g_aLayoutManagerPropName );
+ aValue >>= xLayoutManager;
+ if ( xLayoutManager.is() )
+ {
+ xLayoutManager->createElement( g_aProgressBarResName );
+ xLayoutManager->showElement( g_aProgressBarResName );
+
+ Reference< css::ui::XUIElement > xProgressBar =
+ xLayoutManager->getElement( g_aProgressBarResName );
+ if ( xProgressBar.is() )
+ {
+ xStatusIndicator.set( xProgressBar->getRealInterface(), UNO_QUERY );
+ }
+ }
+ }
+
+ return xStatusIndicator;
+}
+
+
+bool SfxWorkWindow::IsPluginMode( SfxObjectShell const * pObjShell )
+{
+ if ( pObjShell && pObjShell->GetMedium() )
+ {
+ const SfxBoolItem* pViewOnlyItem = pObjShell->GetMedium()->GetItemSet().GetItem(SID_VIEWONLY, false);
+ if ( pViewOnlyItem && pViewOnlyItem->GetValue() )
+ return true;
+ }
+
+ return false;
+}
+
+
+css::uno::Reference< css::frame::XFrame > SfxWorkWindow::GetFrameInterface()
+{
+ css::uno::Reference< css::frame::XFrame > xFrame;
+
+ SfxDispatcher* pDispatcher( GetBindings().GetDispatcher() );
+ if ( pDispatcher )
+ {
+ SfxViewFrame* pViewFrame = pDispatcher->GetFrame();
+ if ( pViewFrame )
+ xFrame = pViewFrame->GetFrame().GetFrameInterface();
+ }
+
+ return xFrame;
+}
+
+
+void SfxWorkWindow::UpdateObjectBars_Impl2()
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return;
+
+ // Lock SplitWindows (which means suppressing the Resize-Reaction of the
+ // DockingWindows)
+ for ( sal_uInt16 n=0; n<SFX_SPLITWINDOWS_MAX; n++ )
+ {
+ VclPtr<SfxSplitWindow> const & p = pSplit[n];
+ if (p->GetWindowCount())
+ p->Lock();
+ }
+
+ Reference< css::beans::XPropertySet > xPropSet( GetFrameInterface(), UNO_QUERY );
+ Reference< css::frame::XLayoutManager > xLayoutManager;
+
+ if ( xPropSet.is() )
+ {
+ Any aValue = xPropSet->getPropertyValue( g_aLayoutManagerPropName );
+ aValue >>= xLayoutManager;
+ }
+
+ if ( !xLayoutManager.is() )
+ return;
+
+ bool bPluginMode( false );
+ SfxDispatcher* pDispatcher( GetBindings().GetDispatcher() );
+
+ if ( pDispatcher )
+ {
+ SfxViewFrame* pViewFrame = pDispatcher->GetFrame();
+ if ( pViewFrame )
+ bPluginMode = IsPluginMode( pViewFrame->GetObjectShell() );
+ }
+
+ // Iterate over all Toolboxes
+ xLayoutManager->lock();
+ const bool bForceDestroyToolbars =
+ comphelper::LibreOfficeKit::isActive() ? false : sfx2::SfxNotebookBar::IsActive(true);
+ for ( auto const & n: aObjBarList )
+ {
+ ToolbarId eId = n.eId;
+ bool bDestroy = n.bDestroy;
+
+ // Determine the valid mode for the ToolBox
+ SfxVisibilityFlags nTbxMode = n.nMode;
+ bool bFullScreenTbx( nTbxMode & SfxVisibilityFlags::FullScreen );
+ nTbxMode &= ~SfxVisibilityFlags::FullScreen;
+ nTbxMode &= ~SfxVisibilityFlags::Viewer;
+
+ // Is a ToolBox required in this context ?
+ bool bModesMatching = (nUpdateMode != SfxVisibilityFlags::Invisible) && ((nTbxMode & nUpdateMode) == nUpdateMode);
+ if ( bDestroy || bForceDestroyToolbars)
+ {
+ OUString aTbxId = g_aTbxTypeName + GetResourceURLFromToolbarId(eId);
+ xLayoutManager->destroyElement( aTbxId );
+ }
+ else if ( eId != ToolbarId::None && ( ( bModesMatching && !bIsFullScreen ) ||
+ ( bIsFullScreen && bFullScreenTbx ) ) )
+ {
+ OUString aTbxId = g_aTbxTypeName + GetResourceURLFromToolbarId(eId);
+ if ( !IsDockingAllowed() && !xLayoutManager->isElementFloating( aTbxId ))
+ xLayoutManager->destroyElement( aTbxId );
+ else
+ {
+ xLayoutManager->requestElement( aTbxId );
+ if ( bPluginMode )
+ xLayoutManager->lockWindow( aTbxId );
+ }
+ }
+ else if ( eId != ToolbarId::None )
+ {
+ // Delete the Toolbox at this Position if possible
+ OUString aTbxId = g_aTbxTypeName + GetResourceURLFromToolbarId(eId);
+ xLayoutManager->destroyElement( aTbxId );
+ }
+ }
+
+ UpdateStatusBar_Impl();
+
+ // unlocking automatically forces Layout
+ xLayoutManager->unlock();
+
+ UpdateChildWindows_Impl();
+
+ // Unlock the SplitWindows again
+ for ( sal_uInt16 n=0; n<SFX_SPLITWINDOWS_MAX; n++ )
+ {
+ VclPtr<SfxSplitWindow> const & p = pSplit[n];
+ if (p->GetWindowCount())
+ p->Lock(false);
+ }
+}
+
+void SfxWorkWindow::UpdateChildWindows_Impl()
+{
+ // tdf#100870, tdf#101320: don't use range-based for loop when
+ // container is modified
+ for ( size_t n=0; n<aChildWins.size(); n++ )
+ {
+ // any current or in the context available Childwindows
+ SfxChildWin_Impl *pCW = aChildWins[n].get();
+ SfxChildWindow *pChildWin = pCW->pWin;
+ bool bCreate = false;
+ if ( pCW->nId && (pCW->aInfo.nFlags & SfxChildWindowFlags::ALWAYSAVAILABLE || IsVisible_Impl( pCW->nVisibility ) ) )
+ {
+ // In the context is an appropriate ChildWindow allowed;
+ // it is also turned on?
+ if ( pChildWin == nullptr && pCW->bCreate )
+ {
+ // Internal docking is only used for embedding into another
+ // container. We force the floating state of all floatable
+ // child windows.
+ if ( !bInternalDockingAllowed )
+ {
+ // Special case for all non-floatable child windows. We have
+ // to prevent the creation here!
+ bCreate = !( pCW->aInfo.nFlags & SfxChildWindowFlags::FORCEDOCK );
+ }
+ else if ( !IsDockingAllowed() || bIsFullScreen ) // || !bInternalDocking )
+ {
+ // In Presentation mode or FullScreen only FloatingWindows
+ SfxChildAlignment eAlign;
+ if ( pCW->aInfo.GetExtraData_Impl( &eAlign ) )
+ bCreate = ( eAlign == SfxChildAlignment::NOALIGNMENT );
+ }
+ else
+ bCreate = true;
+
+ if (pCW->aInfo.nFlags & SfxChildWindowFlags::NEVERCLONE)
+ pCW->bCreate = bCreate = false; // Don't create and remember that we haven't created.
+
+ // Currently, no window here, but it is enabled; windows
+ // Create window and if possible theContext
+ if ( bCreate )
+ CreateChildWin_Impl( pCW, false );
+
+ if ( !bAllChildrenVisible && pCW->pCli )
+ pCW->pCli->nVisible &= ~SfxChildVisibility::ACTIVE;
+ }
+ else if ( pChildWin )
+ {
+ // Window already exists, it should also be visible?
+ if ( ( !bIsFullScreen || pChildWin->GetAlignment() == SfxChildAlignment::NOALIGNMENT ) && bAllChildrenVisible )
+ {
+ // Update Mode is compatible; definitely enable it
+ bCreate = true;
+ if ( pCW->pCli )
+ {
+ // The window is a direct Child
+ if ((IsDockingAllowed() && bInternalDockingAllowed)
+ || pCW->pCli->eAlign == SfxChildAlignment::NOALIGNMENT)
+ pCW->pCli->nVisible |= SfxChildVisibility::NOT_HIDDEN;
+ }
+ else
+ {
+ if ( pCW->bCreate && IsDockingAllowed() && bInternalDockingAllowed )
+ // The window ia within a SplitWindow
+ static_cast<SfxDockingWindow*>(pChildWin->GetWindow())->Reappear_Impl();
+ }
+ }
+ }
+ }
+
+ if ( pChildWin && !bCreate )
+ {
+ if ( !pChildWin->QueryClose() || pChildWin->IsHideNotDelete() || Application::IsUICaptured() )
+ {
+ if ( pCW->pCli )
+ {
+ if ( pCW->pCli->nVisible & SfxChildVisibility::NOT_HIDDEN )
+ pCW->pCli->nVisible ^= SfxChildVisibility::NOT_HIDDEN;
+ }
+ else
+ static_cast<SfxDockingWindow*>(pChildWin->GetWindow())->Disappear_Impl();
+ }
+ else
+ RemoveChildWin_Impl( pCW );
+ }
+ }
+}
+
+void SfxWorkWindow::CreateChildWin_Impl( SfxChildWin_Impl *pCW, bool bSetFocus )
+{
+ pCW->aInfo.bVisible = true;
+
+ SfxChildWindow *pChildWin = SfxChildWindow::CreateChildWindow( pCW->nId, pWorkWin, &GetBindings(), pCW->aInfo).release();
+ if (!pChildWin)
+ return;
+
+ if ( bSetFocus )
+ bSetFocus = pChildWin->WantsFocus();
+ pChildWin->SetWorkWindow_Impl( this );
+
+ // At least the extra string is changed during the evaluation,
+ // also get it anewed
+ SfxChildWinInfo aInfo = pChildWin->GetInfo();
+ pCW->aInfo.aExtraString = aInfo.aExtraString;
+ pCW->aInfo.bVisible = aInfo.bVisible;
+ pCW->aInfo.nFlags |= aInfo.nFlags;
+
+ // The creation was successful
+ GetBindings().Invalidate(pCW->nId);
+
+ sal_uInt16 nPos = pChildWin->GetPosition();
+ if (nPos != CHILDWIN_NOPOS)
+ {
+ DBG_ASSERT(nPos < SFX_OBJECTBAR_MAX, "Illegal objectbar position!");
+ if ( aChildren[TbxMatch(nPos)] )// &&
+ {
+ // ChildWindow replaces ObjectBar
+ aChildren[TbxMatch(nPos)]->nVisible ^= SfxChildVisibility::NOT_HIDDEN;
+ }
+ }
+
+ // make childwin keyboard accessible
+ pWorkWin->GetSystemWindow()->GetTaskPaneList()->AddWindow( pChildWin->GetWindow() );
+
+ pCW->pWin = pChildWin;
+
+ if ( pChildWin->GetAlignment() == SfxChildAlignment::NOALIGNMENT || pChildWin->GetWindow()->GetParent() == pWorkWin)
+ {
+ // The window is not docked or docked outside of one split windows
+ // and must therefore be registered explicitly as a Child
+ if (pChildWin->GetController())
+ pCW->pCli = RegisterChild_Impl(pChildWin->GetController(), pChildWin->GetAlignment());
+ else
+ pCW->pCli = RegisterChild_Impl(*(pChildWin->GetWindow()), pChildWin->GetAlignment());
+ pCW->pCli->nVisible = SfxChildVisibility::VISIBLE;
+ if ( pChildWin->GetAlignment() != SfxChildAlignment::NOALIGNMENT && bIsFullScreen )
+ pCW->pCli->nVisible ^= SfxChildVisibility::ACTIVE;
+ pCW->pCli->bSetFocus = bSetFocus;
+ }
+ else
+ {
+ // A docked window which parent is not a WorkingWindow, must lie
+ // in a SplitWindow and thus not be explicitly registered.
+ // This happens already in the initialization of SfxDockingWindows!
+ }
+
+ // Save the information in the INI file
+ SaveStatus_Impl(pChildWin, pCW->aInfo);
+}
+
+void SfxWorkWindow::RemoveChildWin_Impl( SfxChildWin_Impl *pCW )
+{
+ sal_uInt16 nId = pCW->nSaveId;
+ SfxChildWindow *pChildWin = pCW->pWin;
+
+ // Save the information in the INI file
+ SfxChildWindowFlags nFlags = pCW->aInfo.nFlags;
+ pCW->aInfo = pChildWin->GetInfo();
+ pCW->aInfo.nFlags |= nFlags;
+ SaveStatus_Impl(pChildWin, pCW->aInfo);
+
+ pChildWin->Hide();
+
+ if ( pCW->pCli )
+ {
+ // Child window is a direct child window and must therefore unregister
+ // itself from the WorkWindow
+ pCW->pCli = nullptr;
+ if (pChildWin->GetController())
+ ReleaseChild_Impl(*pChildWin->GetController());
+ else
+ ReleaseChild_Impl(*pChildWin->GetWindow());
+ }
+ else
+ {
+ // ChildWindow is within a SplitWindow and unregister itself in
+ // the destructor.
+ }
+
+ pWorkWin->GetSystemWindow()->GetTaskPaneList()->RemoveWindow( pChildWin->GetWindow() );
+ pCW->pWin = nullptr;
+ pChildWin->Destroy();
+
+ GetBindings().Invalidate( nId );
+}
+
+void SfxWorkWindow::ResetStatusBar_Impl()
+{
+ aStatBar.eId = StatusBarId::None;
+}
+
+void SfxWorkWindow::SetStatusBar_Impl(StatusBarId eId)
+{
+ if (eId != StatusBarId::None && bShowStatusBar && IsVisible_Impl())
+ aStatBar.eId = eId;
+}
+
+void SfxWorkWindow::UpdateStatusBar_Impl()
+{
+ Reference< css::beans::XPropertySet > xPropSet( GetFrameInterface(), UNO_QUERY );
+ Reference< css::frame::XLayoutManager > xLayoutManager;
+
+ Any aValue = xPropSet->getPropertyValue( g_aLayoutManagerPropName );
+ aValue >>= xLayoutManager;
+
+ // No status bar, if no ID is required or when in FullScreenView or
+ // if disabled
+ if (aStatBar.eId != StatusBarId::None && IsDockingAllowed() && bInternalDockingAllowed && bShowStatusBar &&
+ !bIsFullScreen)
+ {
+ // Id has changed, thus create a suitable Statusbarmanager, this takes
+ // over the current status bar;
+ if ( xLayoutManager.is() )
+ xLayoutManager->requestElement( g_aStatusBarResName );
+ }
+ else
+ {
+ // Destroy the current StatusBar
+ // The Manager only creates the Status bar, does not destroy it.
+ if ( xLayoutManager.is() )
+ xLayoutManager->destroyElement( g_aStatusBarResName );
+ }
+}
+
+void SfxWorkWindow::MakeVisible_Impl( bool bVis )
+{
+ if ( bVis )
+ nOrigMode = SfxVisibilityFlags::Standard;
+ else
+ nOrigMode = SfxVisibilityFlags::Invisible;
+
+ if ( nOrigMode != nUpdateMode)
+ nUpdateMode = nOrigMode;
+}
+
+bool SfxWorkWindow::IsVisible_Impl() const
+{
+ return nOrigMode != SfxVisibilityFlags::Invisible;
+}
+
+
+void SfxWorkWindow::HidePopups_Impl(bool bHide, sal_uInt16 nId )
+{
+ if (comphelper::LibreOfficeKit::isActive() && bHide)
+ return;
+
+ for (const std::unique_ptr<SfxChildWin_Impl>& i : aChildWins)
+ {
+ SfxChildWindow *pCW = i->pWin;
+ if (pCW && pCW->GetAlignment() == SfxChildAlignment::NOALIGNMENT && pCW->GetType() != nId)
+ {
+ vcl::Window *pWin = pCW->GetWindow();
+ SfxChild_Impl *pChild = FindChild_Impl(pWin);
+ if (!pChild)
+ {
+ SAL_WARN("sfx.appl", "missing SfxChild_Impl child!");
+ continue;
+ }
+ if (bHide)
+ {
+ pChild->nVisible &= ~SfxChildVisibility::ACTIVE;
+ pCW->Hide();
+ }
+ else if ( !comphelper::LibreOfficeKit::isActive() ||
+ SfxChildVisibility::ACTIVE != (pChild->nVisible & SfxChildVisibility::ACTIVE) )
+ {
+ pChild->nVisible |= SfxChildVisibility::ACTIVE;
+ if ( SfxChildVisibility::VISIBLE == (pChild->nVisible & SfxChildVisibility::VISIBLE) )
+ pCW->Show( ShowFlags::NoFocusChange | ShowFlags::NoActivate );
+ }
+ }
+ }
+}
+
+
+void SfxWorkWindow::ConfigChild_Impl(SfxChildIdentifier eChild,
+ SfxDockingConfig eConfig, sal_uInt16 nId)
+{
+ SfxDockingWindow* pDockWin=nullptr;
+ sal_uInt16 nPos = USHRT_MAX;
+ vcl::Window *pWin=nullptr;
+ SfxChildWin_Impl *pCW = nullptr;
+
+ // configure direct childwindow
+ for (const std::unique_ptr<SfxChildWin_Impl>& i : aChildWins)
+ {
+ pCW = i.get();
+ SfxChildWindow *pChild = pCW->pWin;
+ if ( pChild && (pChild->GetType() == nId ))
+ {
+ if (SfxDockingWindow* pSfxDockingWindow = dynamic_cast<SfxDockingWindow*>(pChild->GetWindow()))
+ {
+ // it's a DockingWindow
+ pDockWin = pSfxDockingWindow;
+ }
+ else
+ {
+ // FloatingWindow or ModelessDialog
+ pWin = pChild->GetWindow();
+ }
+ break;
+ }
+ }
+
+ if ( pDockWin )
+ {
+ if ( eChild == SfxChildIdentifier::DOCKINGWINDOW || pDockWin->GetAlignment() == SfxChildAlignment::NOALIGNMENT )
+ {
+ if ( eChild == SfxChildIdentifier::SPLITWINDOW && eConfig == SfxDockingConfig::TOGGLEFLOATMODE)
+ {
+ // DockingWindow was dragged out of a SplitWindow
+ pCW->pCli = RegisterChild_Impl(*pDockWin, pDockWin->GetAlignment());
+ pCW->pCli->nVisible = SfxChildVisibility::VISIBLE;
+ }
+
+ pWin = pDockWin;
+ }
+ else
+ {
+ SfxSplitWindow *pSplitWin = GetSplitWindow_Impl(pDockWin->GetAlignment());
+
+ // configure DockingWindow inside a SplitWindow
+ if ( eConfig == SfxDockingConfig::TOGGLEFLOATMODE)
+ {
+ // DockingWindow was dragged into a SplitWindow
+ pCW->pCli = nullptr;
+ ReleaseChild_Impl(*pDockWin);
+ }
+
+ pWin = pSplitWin->GetSplitWindow();
+ if ( pSplitWin->GetWindowCount() == 1 )
+ static_cast<SplitWindow*>(pWin)->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
+ }
+ }
+
+ DBG_ASSERT( pCW, "Unknown window!" );
+
+ if ( !bSorted )
+ // windows may have been registered and released without an update until now
+ Sort_Impl();
+
+ decltype(aSortedList)::size_type n;
+ for ( n=0; n<aSortedList.size(); ++n )
+ {
+ SfxChild_Impl *pChild = aChildren[aSortedList[n]].get();
+ if ( pChild && pChild->pWin == pWin )
+ break;
+ }
+
+ if ( n < aSortedList.size() )
+ // sometimes called while toggling float mode
+ nPos = aSortedList[n];
+
+ switch ( eConfig )
+ {
+ case SfxDockingConfig::SETDOCKINGRECTS :
+ {
+ if (nPos == USHRT_MAX || !pDockWin)
+ return;
+
+ tools::Rectangle aOuterRect( GetTopRect_Impl() );
+ aOuterRect.SetPos( pWorkWin->OutputToScreenPixel( aOuterRect.TopLeft() ));
+ tools::Rectangle aInnerRect( aOuterRect );
+
+ // The current affected window is included in the calculation of
+ // the inner rectangle!
+ for (sal_uInt16 i : aSortedList)
+ {
+ SfxChild_Impl* pCli = aChildren[i].get();
+
+ if ( pCli && pCli->nVisible == SfxChildVisibility::VISIBLE && pCli->pWin )
+ {
+ switch ( pCli->eAlign )
+ {
+ case SfxChildAlignment::TOP:
+ // Object-Toolboxes come always last
+ aInnerRect.AdjustTop(pCli->aSize.Height() );
+ break;
+
+ case SfxChildAlignment::HIGHESTTOP:
+ // Always performed first
+ aInnerRect.AdjustTop(pCli->aSize.Height() );
+ break;
+
+ case SfxChildAlignment::LOWESTTOP:
+ // Is only counted if it is the current window
+ if ( i == nPos )
+ aInnerRect.AdjustTop(pCli->aSize.Height() );
+ break;
+
+ case SfxChildAlignment::BOTTOM:
+ // Object-Toolboxes come always last
+ aInnerRect.AdjustBottom( -(pCli->aSize.Height()) );
+ break;
+
+ case SfxChildAlignment::LOWESTBOTTOM:
+ // Always performed first
+ aInnerRect.AdjustBottom( -(pCli->aSize.Height()) );
+ break;
+
+ case SfxChildAlignment::HIGHESTBOTTOM:
+ // Is only counted if it is the current window
+ if ( i == nPos )
+ aInnerRect.AdjustBottom( -(pCli->aSize.Height()) );
+ break;
+
+ case SfxChildAlignment::LEFT:
+ // Toolboxes come always last
+ aInnerRect.AdjustLeft(pCli->aSize.Width() );
+ break;
+
+ case SfxChildAlignment::FIRSTLEFT:
+ // Always performed first
+ aInnerRect.AdjustLeft(pCli->aSize.Width() );
+ break;
+
+ case SfxChildAlignment::LASTLEFT:
+ // Is only counted if it is the current window
+ if (i == nPos)
+ aInnerRect.AdjustLeft(pCli->aSize.Width() );
+ break;
+
+ case SfxChildAlignment::RIGHT:
+ // Toolboxes come always last
+ aInnerRect.AdjustRight( -(pCli->aSize.Width()) );
+ break;
+
+ case SfxChildAlignment::FIRSTRIGHT:
+ // Is only counted if it is the current window
+ if (i == nPos)
+ aInnerRect.AdjustRight( -(pCli->aSize.Width()) );
+ break;
+
+ case SfxChildAlignment::LASTRIGHT:
+ // Always performed first
+ aInnerRect.AdjustRight( -(pCli->aSize.Width()) );
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ pDockWin->SetDockingRects(aOuterRect, aInnerRect);
+ break;
+ }
+
+ case SfxDockingConfig::ALIGNDOCKINGWINDOW :
+ case SfxDockingConfig::TOGGLEFLOATMODE:
+ {
+ if ( nPos == USHRT_MAX && !pCW )
+ return;
+
+ SfxChildAlignment eAlign = SfxChildAlignment::NOALIGNMENT;
+ SfxChild_Impl *pCli = ( nPos != USHRT_MAX ) ? aChildren[nPos].get() : nullptr;
+ if ( pCli && pDockWin )
+ {
+ eAlign = pDockWin->GetAlignment();
+ if ( eChild == SfxChildIdentifier::DOCKINGWINDOW || eAlign == SfxChildAlignment::NOALIGNMENT)
+ {
+ // configuration inside the SplitWindow, no change for the SplitWindows' configuration
+ pCli->bResize = true;
+ pCli->aSize = pDockWin->GetSizePixel();
+ }
+ }
+
+ if ( pCli )
+ {
+ if( pCli->eAlign != eAlign )
+ {
+ bSorted = false;
+ pCli->eAlign = eAlign;
+ }
+
+ ArrangeChildren_Impl();
+ ShowChildren_Impl();
+ }
+
+ if ( pCW && pCW->pWin )
+ {
+ // store changed configuration
+ SfxChildWindowFlags nFlags = pCW->aInfo.nFlags;
+ pCW->aInfo = pCW->pWin->GetInfo();
+ pCW->aInfo.nFlags |= nFlags;
+ SaveStatus_Impl( pCW->pWin, pCW->aInfo);
+ }
+
+ break;
+ }
+ }
+}
+
+namespace
+{
+template <sal_uInt16 SfxChildWin_Impl::*Member>
+SfxChildWin_Impl* Get_Impl(const std::vector<std::unique_ptr<SfxChildWin_Impl>>& rChildWins,
+ sal_uInt16 nId)
+{
+ for (auto& pChildWin : rChildWins)
+ if (pChildWin.get()->*Member == nId)
+ return pChildWin.get();
+ return nullptr;
+}
+auto Get_ById = Get_Impl<&SfxChildWin_Impl::nId>;
+auto Get_BySaveId = Get_Impl<&SfxChildWin_Impl::nSaveId>;
+}
+
+void SfxWorkWindow::SetChildWindowVisible_Impl( sal_uInt32 lId, bool bEnabled, SfxVisibilityFlags nMode )
+{
+ sal_uInt16 nId = static_cast<sal_uInt16>( lId & 0xFFFF );
+
+ SfxChildWin_Impl* pCW = Get_BySaveId(aChildWins, nId);
+
+ if ( !pCW )
+ {
+ // If new, then initialize, add this here depending on the flag or
+ // the Parent
+ pCW = new SfxChildWin_Impl( lId );
+ pCW->nId = nId;
+ InitializeChild_Impl( pCW );
+ aChildWins.push_back( std::unique_ptr<SfxChildWin_Impl>(pCW) );
+ }
+
+ pCW->nId = nId;
+ pCW->nVisibility = nMode;
+ pCW->bEnable = bEnabled;
+}
+
+
+// The on/off status of a ChildWindow is switched
+
+void SfxWorkWindow::ToggleChildWindow_Impl(sal_uInt16 nId, bool bSetFocus)
+{
+ if (SfxChildWin_Impl* pCW = Get_ById(aChildWins, nId))
+ {
+ // The Window is already known
+ SfxChildWindow *pChild = pCW->pWin;
+
+ bool bCreationAllowed( true );
+ if ( !bInternalDockingAllowed )
+ {
+ // Special case for all non-floatable child windows. We have
+ // to prevent the creation here!
+ bCreationAllowed = !( pCW->aInfo.nFlags & SfxChildWindowFlags::FORCEDOCK );
+ }
+
+ if ( bCreationAllowed )
+ {
+ if ( pCW->bCreate )
+ {
+ if ( pChild )
+ {
+ if ( pChild->QueryClose() )
+ {
+ pCW->bCreate = false;
+ // The Window should be switched off
+ pChild->SetVisible_Impl( false );
+ RemoveChildWin_Impl( pCW );
+ }
+ }
+ else
+ {
+ // no actual Window exists, yet => just remember the "switched off" state
+ pCW->bCreate = false;
+ }
+ }
+ else
+ {
+ pCW->bCreate = true;
+ if ( pChild )
+ {
+ ShowChildWindow_Impl( nId, true, bSetFocus );
+ }
+ else
+ {
+ // create actual Window
+ CreateChildWin_Impl( pCW, bSetFocus );
+ if ( !pCW->pWin )
+ // no success
+ pCW->bCreate = false;
+ }
+ }
+ }
+
+ ArrangeChildren_Impl();
+ ShowChildren_Impl();
+
+ if ( pCW->bCreate && bCreationAllowed )
+ {
+ if ( !pCW->pCli )
+ {
+ SfxDockingWindow *pDock =
+ static_cast<SfxDockingWindow*>( pCW->pWin->GetWindow() );
+ if ( pDock->IsAutoHide_Impl() )
+ pDock->AutoShow_Impl();
+ }
+ }
+
+ return;
+ }
+
+#ifdef DBG_UTIL
+ if (Get_BySaveId(aChildWins, nId))
+ {
+ OSL_FAIL("The ChildWindow is not in context!");
+ }
+ else
+ {
+ OSL_FAIL("The ChildWindow is not registered!");
+ }
+#endif
+}
+
+
+bool SfxWorkWindow::HasChildWindow_Impl(sal_uInt16 nId)
+{
+ if (const SfxChildWin_Impl* pCW = Get_BySaveId(aChildWins, nId))
+ return ( pCW->pWin && pCW->bCreate );
+
+ return false;
+}
+
+bool SfxWorkWindow::IsFloating( sal_uInt16 nId )
+{
+ SfxChildWin_Impl* pCW = Get_BySaveId(aChildWins, nId);
+
+ if ( !pCW )
+ {
+ // If new, then initialize, add this here depending on the flag or
+ // the Parent
+ pCW = new SfxChildWin_Impl( nId );
+ pCW->bEnable = false;
+ pCW->nId = 0;
+ pCW->nVisibility = SfxVisibilityFlags::Invisible;
+ InitializeChild_Impl( pCW );
+ aChildWins.push_back( std::unique_ptr<SfxChildWin_Impl>(pCW) );
+ }
+
+ SfxChildAlignment eAlign;
+ if ( pCW->aInfo.GetExtraData_Impl( &eAlign ) )
+ return( eAlign == SfxChildAlignment::NOALIGNMENT );
+ else
+ return true;
+}
+
+
+bool SfxWorkWindow::KnowsChildWindow_Impl(sal_uInt16 nId)
+{
+ if (SfxChildWin_Impl* pCW = Get_BySaveId(aChildWins, nId))
+ {
+ if ( !(pCW->aInfo.nFlags & SfxChildWindowFlags::ALWAYSAVAILABLE) && !IsVisible_Impl( pCW->nVisibility ) )
+ return false;
+ return pCW->bEnable;
+ }
+ else
+ return false;
+}
+
+
+void SfxWorkWindow::SetChildWindow_Impl(sal_uInt16 nId, bool bOn, bool bSetFocus)
+{
+ SfxChildWin_Impl* pCW = Get_BySaveId(aChildWins, nId);
+
+ if ( !pCW )
+ {
+ // If new, then initialize, add this here depending on the flag or
+ // the Parent
+ pCW = new SfxChildWin_Impl( nId );
+ InitializeChild_Impl( pCW );
+ aChildWins.push_back( std::unique_ptr<SfxChildWin_Impl>(pCW) );
+ }
+
+ if ( pCW->bCreate != bOn )
+ ToggleChildWindow_Impl(nId,bSetFocus);
+}
+
+
+void SfxWorkWindow::ShowChildWindow_Impl(sal_uInt16 nId, bool bVisible, bool bSetFocus)
+{
+ if (SfxChildWin_Impl* pCW = Get_ById(aChildWins, nId))
+ {
+ SfxChildWindow *pChildWin = pCW->pWin;
+ if ( pChildWin )
+ {
+ if ( bVisible )
+ {
+ if ( pCW->pCli )
+ {
+ pCW->pCli->bSetFocus = bSetFocus;
+ pCW->pCli->nVisible = SfxChildVisibility::VISIBLE;
+ pChildWin->Show( bSetFocus && pChildWin->WantsFocus() ? ShowFlags::NONE : ShowFlags::NoFocusChange | ShowFlags::NoActivate );
+ }
+ else
+ static_cast<SfxDockingWindow*>(pChildWin->GetWindow())->Reappear_Impl();
+
+ }
+ else
+ {
+ if ( pCW->pCli )
+ {
+ pCW->pCli->nVisible = SfxChildVisibility::VISIBLE ^ SfxChildVisibility::NOT_HIDDEN;
+ pCW->pWin->Hide();
+ }
+ else
+ static_cast<SfxDockingWindow*>(pChildWin->GetWindow())->Disappear_Impl();
+
+ }
+
+ ArrangeChildren_Impl();
+ ShowChildren_Impl();
+ }
+ else if ( bVisible )
+ {
+ SetChildWindow_Impl( nId, true, bSetFocus );
+ pChildWin = pCW->pWin;
+ }
+
+ if ( pChildWin )
+ {
+ pChildWin->SetVisible_Impl( bVisible );
+ SfxChildWindowFlags nFlags = pCW->aInfo.nFlags;
+ pCW->aInfo = pChildWin->GetInfo();
+ pCW->aInfo.nFlags |= nFlags;
+ if ( !pCW->bCreate )
+ SaveStatus_Impl( pChildWin, pCW->aInfo );
+ }
+
+ return;
+ }
+
+#ifdef DBG_UTIL
+ if (Get_BySaveId(aChildWins, nId))
+ {
+ OSL_FAIL("The ChildWindow is not in context!");
+ }
+ else
+ {
+ OSL_FAIL("The ChildWindow is not registered");
+ }
+#endif
+}
+
+
+SfxChildWindow* SfxWorkWindow::GetChildWindow_Impl(sal_uInt16 nId)
+{
+ if (SfxChildWin_Impl* pCW = Get_BySaveId(aChildWins, nId))
+ return pCW->pWin;
+ return nullptr;
+}
+
+
+void SfxWorkWindow::ResetChildWindows_Impl()
+{
+ for (std::unique_ptr<SfxChildWin_Impl>& pChildWin : aChildWins)
+ {
+ pChildWin->nId = 0;
+ pChildWin->bEnable = false;
+ }
+}
+
+// returns the size of the area (client area) of the
+// parent windows, in which the ChildWindow can be fitted.
+
+tools::Rectangle SfxWorkWindow::GetTopRect_Impl() const
+{
+ return pMasterFrame->GetTopOuterRectPixel_Impl();
+}
+
+
+// Virtual method to find out if there is room for a ChildWindow in the
+// client area of the parent.
+
+bool SfxWorkWindow::RequestTopToolSpacePixel_Impl( SvBorder aBorder )
+{
+ return !(!IsDockingAllowed() ||
+ aClientArea.GetWidth() < aBorder.Left() + aBorder.Right() ||
+ aClientArea.GetHeight() < aBorder.Top() + aBorder.Bottom());
+}
+
+void SfxWorkWindow::SaveStatus_Impl(SfxChildWindow *pChild, const SfxChildWinInfo &rInfo)
+{
+ // The Status of the Presentation mode is not saved
+ if ( IsDockingAllowed() && bInternalDockingAllowed )
+ pChild->SaveStatus(rInfo);
+}
+
+void SfxWorkWindow::InitializeChild_Impl(SfxChildWin_Impl *pCW)
+{
+ SfxDispatcher *pDisp = pBindings->GetDispatcher_Impl();
+ SfxViewFrame *pViewFrame = pDisp ? pDisp->GetFrame() :nullptr;
+ SfxModule *pMod = pViewFrame ? SfxModule::GetActiveModule(pViewFrame) :nullptr;
+
+ OUString sModule;
+ if (pViewFrame)
+ {
+ try
+ {
+ uno::Reference< frame::XModuleManager2 > xModuleManager(
+ frame::ModuleManager::create(::comphelper::getProcessComponentContext()));
+ sModule = xModuleManager->identify(pViewFrame->GetFrame().GetFrameInterface());
+ SvtModuleOptions::EFactory eFac = SvtModuleOptions::ClassifyFactoryByServiceName(sModule);
+ sModule = SvtModuleOptions::GetFactoryShortName(eFac);
+ }
+ catch (...)
+ {
+ }
+ }
+
+ SfxChildWinFactory* pFact=nullptr;
+ SfxApplication *pApp = SfxGetpApp();
+ {
+ pFact = pApp->GetChildWinFactoryById(pCW->nSaveId);
+ if ( pFact )
+ {
+ pCW->aInfo = pFact->aInfo;
+ pCW->aInfo.aModule = sModule;
+ SfxChildWindow::InitializeChildWinFactory_Impl(
+ pCW->nSaveId, pCW->aInfo);
+ pCW->bCreate = pCW->aInfo.bVisible;
+ SfxChildWindowFlags nFlags = pFact->aInfo.nFlags;
+ if ( nFlags & SfxChildWindowFlags::TASK )
+ pCW->aInfo.nFlags |= SfxChildWindowFlags::TASK;
+ if ( nFlags & SfxChildWindowFlags::CANTGETFOCUS )
+ pCW->aInfo.nFlags |= SfxChildWindowFlags::CANTGETFOCUS;
+ if ( nFlags & SfxChildWindowFlags::FORCEDOCK )
+ pCW->aInfo.nFlags |= SfxChildWindowFlags::FORCEDOCK;
+ pFact->aInfo = pCW->aInfo;
+ return;
+ }
+ }
+
+ if ( !pMod )
+ return;
+
+ pFact = pMod->GetChildWinFactoryById(pCW->nSaveId);
+ if ( !pFact )
+ return;
+
+ pCW->aInfo = pFact->aInfo;
+ pCW->aInfo.aModule = sModule;
+ SfxChildWindow::InitializeChildWinFactory_Impl(
+ pCW->nSaveId, pCW->aInfo);
+ pCW->bCreate = pCW->aInfo.bVisible;
+ SfxChildWindowFlags nFlags = pFact->aInfo.nFlags;
+ if ( nFlags & SfxChildWindowFlags::TASK )
+ pCW->aInfo.nFlags |= SfxChildWindowFlags::TASK;
+ if ( nFlags & SfxChildWindowFlags::CANTGETFOCUS )
+ pCW->aInfo.nFlags |= SfxChildWindowFlags::CANTGETFOCUS;
+ if ( nFlags & SfxChildWindowFlags::FORCEDOCK )
+ pCW->aInfo.nFlags |= SfxChildWindowFlags::FORCEDOCK;
+ if ( nFlags & SfxChildWindowFlags::ALWAYSAVAILABLE )
+ pCW->aInfo.nFlags |= SfxChildWindowFlags::ALWAYSAVAILABLE;
+ pFact->aInfo = pCW->aInfo;
+}
+
+SfxSplitWindow* SfxWorkWindow::GetSplitWindow_Impl( SfxChildAlignment eAlign )
+{
+ switch ( eAlign )
+ {
+ case SfxChildAlignment::TOP:
+ return pSplit[2];
+
+ case SfxChildAlignment::BOTTOM:
+ return pSplit[3];
+
+ case SfxChildAlignment::LEFT:
+ return pSplit[0];
+
+ case SfxChildAlignment::RIGHT:
+ return pSplit[1];
+
+ default:
+ return nullptr;
+ }
+}
+
+void SfxWorkWindow::MakeChildrenVisible_Impl( bool bVis )
+{
+ bAllChildrenVisible = bVis;
+ if ( bVis )
+ {
+ if ( !bSorted )
+ Sort_Impl();
+ for (sal_uInt16 n : aSortedList)
+ {
+ SfxChild_Impl* pCli = aChildren[n].get();
+ if ( (pCli->eAlign == SfxChildAlignment::NOALIGNMENT) || (IsDockingAllowed() && bInternalDockingAllowed) )
+ pCli->nVisible |= SfxChildVisibility::ACTIVE;
+ }
+ }
+ else
+ {
+ if ( !bSorted )
+ Sort_Impl();
+ for (sal_uInt16 n : aSortedList)
+ {
+ SfxChild_Impl* pCli = aChildren[n].get();
+ pCli->nVisible &= ~SfxChildVisibility::ACTIVE;
+ }
+ }
+}
+
+bool SfxWorkWindow::IsAutoHideMode( const SfxSplitWindow *pSplitWin )
+{
+ for (const VclPtr<SfxSplitWindow> & pWin : pSplit)
+ {
+ if ( pWin.get() != pSplitWin && pWin->IsAutoHide( true ) )
+ return true;
+ }
+ return false;
+}
+
+
+void SfxWorkWindow::EndAutoShow_Impl( Point aPos )
+{
+ for (VclPtr<SfxSplitWindow> & p : pSplit)
+ {
+ if ( p && p->IsAutoHide(false) )
+ {
+ Point aLocalPos = p->ScreenToOutputPixel( aPos );
+ tools::Rectangle aRect( Point(), p->GetSizePixel() );
+ if ( !aRect.Contains( aLocalPos ) )
+ p->FadeOut();
+ }
+ }
+}
+
+void SfxWorkWindow::ArrangeAutoHideWindows( SfxSplitWindow *pActSplitWin )
+{
+ if ( m_nLock )
+ return;
+
+ tools::Rectangle aArea( aUpperClientArea );
+ for ( sal_uInt16 n=0; n<SFX_SPLITWINDOWS_MAX; n++ )
+ {
+ // Either dummy window or window in the auto-show-mode are processed
+ // (not pinned, FadeIn).
+ // Only the abandoned window may be invisible, because perhaps its
+ // size is just being calculated before it is displayed.
+ VclPtr<SfxSplitWindow> const & pSplitWin = pSplit[n];
+ bool bDummyWindow = !pSplitWin->IsFadeIn();
+ vcl::Window *pDummy = pSplitWin->GetSplitWindow();
+ vcl::Window *pWin = bDummyWindow ? pDummy : pSplitWin;
+ if ( (pSplitWin->IsPinned() && !bDummyWindow) || (!pWin->IsVisible() && pActSplitWin != pSplitWin) )
+ continue;
+
+ // Width and position of the dummy window as a starting point
+ Size aSize = pDummy->GetSizePixel();
+ Point aPos = pDummy->GetPosPixel();
+
+ switch ( n )
+ {
+ case 0 :
+ {
+ // Left SplitWindow
+ // Get the width of the Window yourself, if no DummyWindow
+ if ( !bDummyWindow )
+ aSize.setWidth( pSplitWin->GetSizePixel().Width() );
+
+ // If a Window is visible to the left, then the free region
+ // starts to the right from it, for example at the Client area
+ tools::Long nLeft = aPos.X() + aSize.Width();
+ if ( nLeft > aArea.Left() )
+ aArea.SetLeft( nLeft );
+ break;
+ }
+ case 1 :
+ {
+ // Right SplitWindow
+ // Position to correct the difference of the widths
+ aPos.AdjustX(aSize.Width() );
+
+ // Get the width of the Window yourself, if no DummyWindow
+ if ( !bDummyWindow )
+ aSize.setWidth( pSplitWin->GetSizePixel().Width() );
+
+ aPos.AdjustX( -(aSize.Width()) );
+
+ // If already a window is opened at the left side, then the
+ // right is not allowed to overlap this one.
+ if ( aPos.X() < aArea.Left() )
+ {
+ aPos.setX( aArea.Left() );
+ aSize.setWidth( aArea.GetWidth() );
+ }
+
+ // If a Window is visible to the right, then the free region
+ // starts to the left from it, for example at the Client area
+ tools::Long nRight = aPos.X();
+ if ( !aArea.IsWidthEmpty() && nRight < aArea.Right() )
+ aArea.SetRight( nRight );
+ break;
+ }
+ case 2 :
+ {
+ // Top SplitWindow
+ // Get the height of the Window yourself, if no DummyWindow
+ if ( !bDummyWindow )
+ aSize.setHeight( pSplitWin->GetSizePixel().Height() );
+
+
+ // Adjust width with regard to if a Window is already open
+ // to the left or right
+ aPos.setX( aArea.Left() );
+ aSize.setWidth( aArea.GetWidth() );
+
+ // If a Window is visible at the top, then the free region
+ // starts beneath it, for example at the Client area
+ tools::Long nTop = aPos.Y() + aSize.Height();
+ if ( nTop > aArea.Top() )
+ aArea.SetTop( nTop );
+ break;
+ }
+ case 3 :
+ {
+ // The bottom SplitWindow
+ // Position to correct the difference of the heights
+ aPos.AdjustY(aSize.Height() );
+
+ // Get the height of the Window yourself, if no DummyWindow
+ if ( !bDummyWindow )
+ aSize.setHeight( pSplitWin->GetSizePixel().Height() );
+
+ aPos.AdjustY( -(aSize.Height()) );
+
+ // Adjust width with regard to if a Window is already open
+ // to the left or right.
+ aPos.setX( aArea.Left() );
+ aSize.setWidth( aArea.GetWidth() );
+
+ // If already a window is opened at the top, then the
+ // bottom one is not allowed to overlap this one.
+ if ( aPos.Y() < aArea.Top() )
+ {
+ aPos.setY( aArea.Top() );
+ aSize.setHeight( aArea.GetHeight() );
+ }
+
+ break;
+ }
+ }
+
+ if ( !bDummyWindow )
+ // the FadeIn-Window is a Floating window, which coordinates are
+ // set in Screen coordinates.
+ pSplitWin->SetPosSizePixel( pWorkWin->OutputToScreenPixel(aPos), aSize );
+ else
+ // the docked DummyWindow
+ pDummy->SetPosSizePixel( aPos, aSize );
+ }
+}
+
+tools::Rectangle SfxWorkWindow::GetFreeArea( bool bAutoHide ) const
+{
+ if ( bAutoHide )
+ {
+ tools::Rectangle aArea( aClientArea );
+ for ( sal_uInt16 n=0; n<SFX_SPLITWINDOWS_MAX; n++ )
+ {
+ if ( pSplit[n]->IsPinned() || !pSplit[n]->IsVisible() )
+ continue;
+
+ Size aSize = pSplit[n]->GetSizePixel();
+ switch ( n )
+ {
+ case 0 :
+ aArea.AdjustLeft(aSize.Width() );
+ break;
+ case 1 :
+ aArea.AdjustRight( -(aSize.Width()) );
+ break;
+ case 2 :
+ aArea.AdjustTop(aSize.Height() );
+ break;
+ case 3 :
+ aArea.AdjustBottom( -(aSize.Height()) );
+ break;
+ }
+ }
+
+ return aArea;
+ }
+ else
+ return aClientArea;
+}
+
+void SfxWorkWindow::SetActiveChild_Impl( vcl::Window *pChild )
+{
+ pActiveChild = pChild;
+}
+
+void SfxWorkWindow::DataChanged_Impl()
+{
+ ArrangeChildren_Impl();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/xpackcreator.cxx b/sfx2/source/appl/xpackcreator.cxx
new file mode 100644
index 0000000000..29ebcc6155
--- /dev/null
+++ b/sfx2/source/appl/xpackcreator.cxx
@@ -0,0 +1,164 @@
+/* -*- 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 <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/embed/XPackageStructureCreator.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <sot/stg.hxx>
+#include <sot/storage.hxx>
+#include <tools/stream.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbhelper.hxx>
+#include <ucbhelper/content.hxx>
+
+using namespace css;
+
+namespace {
+
+class OPackageStructureCreator : public ::cppu::WeakImplHelper< embed::XPackageStructureCreator,
+ lang::XServiceInfo >
+{
+public:
+ OPackageStructureCreator() {}
+
+ // XPackageStructureCreator
+ virtual void SAL_CALL convertToPackage( const OUString& aFolderUrl, const uno::Reference< io::XOutputStream >& xTargetStream ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+
+void SAL_CALL OPackageStructureCreator::convertToPackage( const OUString& aFolderUrl,
+ const uno::Reference< io::XOutputStream >& xTargetStream )
+{
+ uno::Reference< ucb::XCommandEnvironment > xComEnv;
+
+ if ( !xTargetStream.is() )
+ throw io::IOException(); // TODO/LATER
+
+ bool bSuccess = false;
+ ::ucbhelper::Content aContent;
+ if( ::ucbhelper::Content::create( aFolderUrl, xComEnv, comphelper::getProcessComponentContext(), aContent ) )
+ {
+ OUString aTempURL = ::utl::CreateTempURL();
+ try {
+ if ( aContent.isFolder() )
+ {
+ UCBStorage* pUCBStorage = new UCBStorage( aContent,
+ aFolderUrl,
+ StreamMode::READ,
+ false,
+ true );
+ tools::SvRef<SotStorage> aStorage = new SotStorage( pUCBStorage );
+
+ if ( !aTempURL.isEmpty() )
+ {
+ SvFileStream aTempStream( aTempURL, StreamMode::STD_READWRITE );
+ tools::SvRef<SotStorage> aTargetStorage = new SotStorage( true, aTempStream );
+ aStorage->CopyTo( aTargetStorage.get() );
+ aTargetStorage->Commit();
+
+ if ( aStorage->GetError() || aTargetStorage->GetError() || aTempStream.GetError() )
+ throw io::IOException();
+
+ aTargetStorage = nullptr;
+ aStorage = nullptr;
+
+ aTempStream.Seek( 0 );
+
+ uno::Sequence< sal_Int8 > aSeq( 32000 );
+ sal_uInt32 nRead = 0;
+ do {
+ if ( aSeq.getLength() < 32000 )
+ aSeq.realloc( 32000 );
+
+ nRead = aTempStream.ReadBytes(aSeq.getArray(), 32000);
+ if ( nRead < 32000 )
+ aSeq.realloc( nRead );
+ xTargetStream->writeBytes( aSeq );
+ } while (aTempStream.good() && nRead);
+
+ if ( aTempStream.GetError() )
+ throw io::IOException();
+
+ bSuccess = true;
+ }
+ }
+ }
+ catch (const uno::RuntimeException&)
+ {
+ if ( !aTempURL.isEmpty() )
+ ::utl::UCBContentHelper::Kill( aTempURL );
+
+ throw;
+ }
+ catch (const io::IOException&)
+ {
+ if ( !aTempURL.isEmpty() )
+ ::utl::UCBContentHelper::Kill( aTempURL );
+
+ throw;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ if ( !aTempURL.isEmpty() )
+ ::utl::UCBContentHelper::Kill( aTempURL );
+ }
+
+ if ( !bSuccess )
+ throw io::IOException(); // TODO/LATER: can't proceed with creation
+}
+
+OUString SAL_CALL OPackageStructureCreator::getImplementationName()
+{
+ return "com.sun.star.comp.embed.PackageStructureCreator";
+}
+
+sal_Bool SAL_CALL OPackageStructureCreator::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL OPackageStructureCreator::getSupportedServiceNames()
+{
+ return { "com.sun.star.embed.PackageStructureCreator", "com.sun.star.comp.embed.PackageStructureCreator" };
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_embed_PackageStructureCreator_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new OPackageStructureCreator());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */