tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sfx2 / source / appl / appopen.cxx
blob0eb93a09571f7973d8b7d1714f72abb72d33d5d5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/uno/Reference.h>
21 #include <com/sun/star/beans/PropertyValue.hpp>
22 #include <com/sun/star/beans/NamedValue.hpp>
23 #include <com/sun/star/frame/FrameSearchFlag.hpp>
24 #include <com/sun/star/frame/XDispatchProvider.hpp>
25 #include <com/sun/star/frame/XFrame.hpp>
26 #include <com/sun/star/frame/Desktop.hpp>
27 #include <com/sun/star/util/URL.hpp>
28 #include <com/sun/star/util/URLTransformer.hpp>
29 #include <com/sun/star/util/XURLTransformer.hpp>
30 #include <com/sun/star/system/SystemShellExecuteException.hpp>
31 #include <com/sun/star/document/XTypeDetection.hpp>
32 #include <com/sun/star/document/MacroExecMode.hpp>
33 #include <com/sun/star/document/UpdateDocMode.hpp>
34 #include <com/sun/star/task/ErrorCodeRequest.hpp>
35 #include <com/sun/star/task/InteractionHandler.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/embed/ElementModes.hpp>
38 #include <com/sun/star/embed/XStorage.hpp>
39 #include <com/sun/star/container/XNameAccess.hpp>
40 #include <com/sun/star/packages/WrongPasswordException.hpp>
41 #include <com/sun/star/uno/Sequence.h>
42 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
43 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
44 #include <rtl/ustring.hxx>
46 #include <comphelper/processfactory.hxx>
47 #include <comphelper/sequence.hxx>
48 #include <comphelper/storagehelper.hxx>
49 #include <comphelper/string.hxx>
50 #include <comphelper/synchronousdispatch.hxx>
52 #include <svl/intitem.hxx>
53 #include <svl/stritem.hxx>
54 #include <svl/eitem.hxx>
55 #include <sfx2/doctempl.hxx>
56 #include <svtools/sfxecode.hxx>
57 #include <preventduplicateinteraction.hxx>
58 #include <svtools/ehdl.hxx>
59 #include <unotools/pathoptions.hxx>
60 #include <unotools/securityoptions.hxx>
61 #include <unotools/moduleoptions.hxx>
62 #include <unotools/extendedsecurityoptions.hxx>
63 #include <comphelper/docpasswordhelper.hxx>
64 #include <vcl/svapp.hxx>
65 #include <vcl/weld.hxx>
67 #include <sfx2/app.hxx>
68 #include <sfx2/bindings.hxx>
69 #include <sfx2/dispatch.hxx>
70 #include <sfx2/docfile.hxx>
71 #include <sfx2/docfilt.hxx>
72 #include <sfx2/fcontnr.hxx>
73 #include <sfx2/objitem.hxx>
74 #include <sfx2/objsh.hxx>
75 #include <svl/slstitm.hxx>
76 #include <appopen.hxx>
77 #include <sfx2/request.hxx>
78 #include <sfx2/sfxresid.hxx>
79 #include <sfx2/viewsh.hxx>
80 #include <sfx2/strings.hrc>
81 #include <sfx2/viewfrm.hxx>
82 #include <sfx2/sfxuno.hxx>
83 #include <sfx2/objface.hxx>
84 #include <sfx2/filedlghelper.hxx>
85 #include <sfx2/templatedlg.hxx>
86 #include <sfx2/sfxsids.hrc>
87 #include <o3tl/string_view.hxx>
88 #include <openuriexternally.hxx>
90 #include <officecfg/Office/ProtocolHandler.hxx>
91 #include <officecfg/Office/Security.hxx>
93 using namespace ::com::sun::star;
94 using namespace ::com::sun::star::beans;
95 using namespace ::com::sun::star::frame;
96 using namespace ::com::sun::star::lang;
97 using namespace ::com::sun::star::uno;
98 using namespace ::com::sun::star::util;
99 using namespace ::com::sun::star::task;
100 using namespace ::com::sun::star::container;
101 using namespace ::cppu;
102 using namespace ::sfx2;
104 void SetTemplate_Impl( std::u16string_view rFileName,
105 const OUString &rLongName,
106 SfxObjectShell *pDoc)
108 // write TemplateName to DocumentProperties of document
109 // TemplateDate stays as default (=current date)
110 pDoc->ResetFromTemplate( rLongName, rFileName );
113 namespace {
115 class SfxDocPasswordVerifier : public ::comphelper::IDocPasswordVerifier
117 public:
118 explicit SfxDocPasswordVerifier(SfxMedium& rMedium)
119 : m_rMedium(rMedium)
120 , mxStorage(rMedium.GetStorage())
124 virtual ::comphelper::DocPasswordVerifierResult
125 verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData ) override;
126 virtual ::comphelper::DocPasswordVerifierResult
127 verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData ) override;
129 private:
130 SfxMedium & m_rMedium;
131 Reference< embed::XStorage > mxStorage;
136 ::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
138 o_rEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( rPassword );
139 return verifyEncryptionData( o_rEncryptionData );
143 ::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
145 ::comphelper::DocPasswordVerifierResult eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword;
148 // check the encryption data
149 // if the data correct is the stream will be opened successfully
150 // and immediately closed
151 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( mxStorage, rEncryptionData );
153 // for new ODF encryption, try to extract the encrypted inner package
154 // (it will become the SfxObjectShell storage)
155 if (!m_rMedium.TryEncryptedInnerPackage(mxStorage))
156 { // ... old ODF encryption:
157 mxStorage->openStreamElement(
158 u"content.xml"_ustr,
159 embed::ElementModes::READ | embed::ElementModes::NOCREATE );
162 // no exception -> success
163 eResult = ::comphelper::DocPasswordVerifierResult::OK;
165 catch( const packages::WrongPasswordException& )
167 eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword;
169 catch( const uno::Exception& )
171 // unknown error, report it as wrong password
172 // TODO/LATER: we need an additional way to report unknown problems in this case
173 eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword;
175 return eResult;
179 ErrCode CheckPasswd_Impl
181 SfxObjectShell* pDoc,
182 SfxMedium* pFile // the Medium and its Password should be obtained
185 /* [Description]
187 Ask for the password for a medium, only works if it concerns storage.
188 If the password flag is set in the Document Info, then the password is
189 requested through a user dialogue and the set at the Set of the medium.
190 If the set does not exist the it is created.
193 ErrCode nRet = ERRCODE_NONE;
195 if( !pFile->GetFilter() || pFile->IsStorage() )
197 uno::Reference< embed::XStorage > xStorage = pFile->GetStorage();
198 if( xStorage.is() )
200 uno::Reference< beans::XPropertySet > xStorageProps( xStorage, uno::UNO_QUERY );
201 if ( xStorageProps.is() )
203 bool bIsEncrypted = false;
204 uno::Sequence< uno::Sequence< beans::NamedValue > > aGpgProperties;
205 try {
206 xStorageProps->getPropertyValue(u"HasEncryptedEntries"_ustr)
207 >>= bIsEncrypted;
208 xStorageProps->getPropertyValue(u"EncryptionGpGProperties"_ustr)
209 >>= aGpgProperties;
210 } catch( uno::Exception& )
212 // TODO/LATER:
213 // the storage either has no encrypted elements or it's just
214 // does not allow to detect it, probably it should be implemented later
217 if ( bIsEncrypted )
219 css::uno::Reference<css::awt::XWindow> xWin(pDoc ? pDoc->GetDialogParent(pFile) : nullptr);
220 if (xWin)
221 xWin->setVisible(true);
223 nRet = ERRCODE_SFX_CANTGETPASSWD;
225 SfxItemSet& rSet = pFile->GetItemSet();
226 Reference< css::task::XInteractionHandler > xInteractionHandler = pFile->GetInteractionHandler();
227 if( xInteractionHandler.is() )
229 // use the comphelper password helper to request a password
230 OUString aPassword;
231 const SfxStringItem* pPasswordItem = rSet.GetItem(SID_PASSWORD, false);
232 if ( pPasswordItem )
233 aPassword = pPasswordItem->GetValue();
235 uno::Sequence< beans::NamedValue > aEncryptionData;
236 const SfxUnoAnyItem* pEncryptionDataItem = rSet.GetItem(SID_ENCRYPTIONDATA, false);
237 if ( pEncryptionDataItem )
238 pEncryptionDataItem->GetValue() >>= aEncryptionData;
240 // try if one of the public key entries is
241 // decryptable, then extract session key
242 // from it
243 if ( !aEncryptionData.hasElements() && aGpgProperties.hasElements() )
244 aEncryptionData = ::comphelper::DocPasswordHelper::decryptGpgSession(aGpgProperties);
246 // tdf#93389: if recovering a document, encryption data should contain
247 // entries for the real filter, not only for recovery ODF, to keep it
248 // encrypted. Pass this in encryption data.
249 // TODO: pass here the real filter (from AutoRecovery::implts_openDocs)
250 // to marshal this to requestAndVerifyDocPassword
251 if (rSet.GetItemState(SID_DOC_SALVAGE, false) == SfxItemState::SET)
253 aEncryptionData = comphelper::concatSequences(
254 aEncryptionData, std::initializer_list<beans::NamedValue>{
255 { u"ForSalvage"_ustr, css::uno::Any(true) } });
258 SfxDocPasswordVerifier aVerifier(*pFile);
259 aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
260 aVerifier, aEncryptionData, aPassword, xInteractionHandler, pFile->GetOrigURL(), comphelper::DocPasswordRequestType::Standard );
262 rSet.ClearItem( SID_PASSWORD );
263 rSet.ClearItem( SID_ENCRYPTIONDATA );
265 if ( aEncryptionData.hasElements() )
267 rSet.Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::Any( aEncryptionData ) ) );
271 // update the version list of the medium using the new password
272 pFile->GetVersionList();
274 catch( uno::Exception& )
276 // TODO/LATER: set the error code
279 nRet = ERRCODE_NONE;
281 else
282 nRet = ERRCODE_IO_ABORT;
286 else
288 OSL_FAIL( "A storage must implement XPropertySet interface!" );
289 nRet = ERRCODE_SFX_CANTGETPASSWD;
294 return nRet;
298 ErrCodeMsg SfxApplication::LoadTemplate( SfxObjectShellLock& xDoc, const OUString &rFileName, std::unique_ptr<SfxItemSet> pSet )
300 std::shared_ptr<const SfxFilter> pFilter;
301 SfxMedium aMedium( rFileName, ( StreamMode::READ | StreamMode::SHARE_DENYNONE ) );
303 if ( !aMedium.GetStorage( false ).is() )
304 aMedium.GetInStream();
306 if ( aMedium.GetErrorIgnoreWarning() )
308 return aMedium.GetErrorCode();
311 aMedium.UseInteractionHandler( true );
312 ErrCode nErr = GetFilterMatcher().GuessFilter( aMedium, pFilter, SfxFilterFlags::TEMPLATE, SfxFilterFlags::NONE );
313 if ( ERRCODE_NONE != nErr)
315 return ERRCODE_SFX_NOTATEMPLATE;
318 if( !pFilter || !pFilter->IsAllowedAsTemplate() )
320 return ERRCODE_SFX_NOTATEMPLATE;
323 if ( pFilter->GetFilterFlags() & SfxFilterFlags::STARONEFILTER )
325 DBG_ASSERT( !xDoc.Is(), "Sorry, not implemented!" );
326 SfxStringItem aName( SID_FILE_NAME, rFileName );
327 SfxStringItem aReferer( SID_REFERER, u"private:user"_ustr );
328 SfxStringItem aFlags( SID_OPTIONS, u"T"_ustr );
329 SfxBoolItem aHidden( SID_HIDDEN, true );
330 const SfxPoolItemHolder aRet(GetDispatcher_Impl()->ExecuteList(
331 SID_OPENDOC, SfxCallMode::SYNCHRON,
332 { &aName, &aHidden, &aReferer, &aFlags } ));
333 const SfxObjectItem* pObj(dynamic_cast<const SfxObjectItem*>(aRet.getItem()));
334 if ( pObj )
335 xDoc = dynamic_cast<SfxObjectShell*>( pObj->GetShell() );
336 else
338 const SfxViewFrameItem* pView(dynamic_cast<const SfxViewFrameItem*>(aRet.getItem()));
339 if ( pView )
341 SfxViewFrame *pFrame = pView->GetFrame();
342 if ( pFrame )
343 xDoc = pFrame->GetObjectShell();
347 if ( !xDoc.Is() )
348 return ERRCODE_SFX_DOLOADFAILED;
350 else
352 if ( !xDoc.Is() )
353 xDoc = SfxObjectShell::CreateObject( pFilter->GetServiceName() );
355 //pMedium takes ownership of pSet
356 SfxMedium *pMedium = new SfxMedium(rFileName, StreamMode::STD_READ, std::move(pFilter), std::move(pSet));
357 if(!xDoc->DoLoad(pMedium))
359 ErrCodeMsg nErrCode = xDoc->GetErrorCode();
360 xDoc->DoClose();
361 xDoc.Clear();
362 return nErrCode;
368 // TODO: introduce error handling
370 uno::Reference< embed::XStorage > xTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
371 if( !xTempStorage.is() )
372 throw uno::RuntimeException();
374 xDoc->GetStorage()->copyToStorage( xTempStorage );
376 if ( !xDoc->DoSaveCompleted( new SfxMedium( xTempStorage, OUString() ) ) )
377 throw uno::RuntimeException();
379 catch( uno::Exception& )
381 xDoc->DoClose();
382 xDoc.Clear();
384 // TODO: transfer correct error outside
385 return ERRCODE_SFX_GENERAL;
388 SetTemplate_Impl( rFileName, OUString(), xDoc );
390 xDoc->SetNoName();
391 xDoc->InvalidateName();
392 xDoc->SetModified(false);
393 xDoc->ResetError();
395 css::uno::Reference< css::frame::XModel > xModel = xDoc->GetModel();
396 if ( xModel.is() )
398 std::unique_ptr<SfxItemSet> pNew = xDoc->GetMedium()->GetItemSet().Clone();
399 pNew->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
400 pNew->ClearItem( SID_FILTER_NAME );
401 css::uno::Sequence< css::beans::PropertyValue > aArgs;
402 TransformItems( SID_OPENDOC, *pNew, aArgs );
403 sal_Int32 nLength = aArgs.getLength();
404 aArgs.realloc( nLength + 1 );
405 auto pArgs = aArgs.getArray();
406 pArgs[nLength].Name = "Title";
407 pArgs[nLength].Value <<= xDoc->GetTitle( SFX_TITLE_DETECT );
408 xModel->attachResource( OUString(), aArgs );
411 return xDoc->GetErrorCode();
415 void SfxApplication::NewDocDirectExec_Impl( SfxRequest& rReq )
417 const SfxStringItem* pFactoryItem = rReq.GetArg<SfxStringItem>(SID_NEWDOCDIRECT);
418 OUString aFactName;
419 if ( pFactoryItem )
420 aFactName = pFactoryItem->GetValue();
421 else
422 aFactName = SvtModuleOptions().GetDefaultModuleName();
424 SfxRequest aReq( SID_OPENDOC, SfxCallMode::SYNCHRON, GetPool() );
425 aReq.AppendItem( SfxStringItem( SID_FILE_NAME, "private:factory/" + aFactName ) );
426 aReq.AppendItem( SfxFrameItem( SID_DOCFRAME, GetFrame() ) );
427 aReq.AppendItem( SfxStringItem( SID_TARGETNAME, u"_default"_ustr ) );
429 // TODO/LATER: Should the other arguments be transferred as well?
430 const SfxStringItem* pDefaultPathItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILEPATH);
431 if ( pDefaultPathItem )
432 aReq.AppendItem( *pDefaultPathItem );
433 const SfxStringItem* pDefaultNameItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILENAME);
434 if ( pDefaultNameItem )
435 aReq.AppendItem( *pDefaultNameItem );
437 SfxGetpApp()->ExecuteSlot( aReq );
438 const SfxViewFrameItem* pItem(dynamic_cast<const SfxViewFrameItem*>(aReq.GetReturnValue().getItem()));
439 if (nullptr != pItem)
440 rReq.SetReturnValue(SfxFrameItem(0, pItem->GetFrame()));
443 void SfxApplication::NewDocDirectState_Impl( SfxItemSet &rSet )
445 rSet.Put(SfxStringItem(SID_NEWDOCDIRECT, "private:factory/" + SvtModuleOptions().GetDefaultModuleName()));
448 void SfxApplication::NewDocExec_Impl( SfxRequest& rReq )
450 // No Parameter from BASIC only Factory given?
451 const SfxStringItem* pTemplNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_NAME);
452 const SfxStringItem* pTemplFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
453 const SfxStringItem* pTemplRegionNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_REGIONNAME);
455 SfxObjectShellLock xDoc;
457 OUString aTemplateRegion, aTemplateName, aTemplateFileName;
458 bool bDirect = false; // through FileName instead of Region/Template
459 SfxErrorContext aEc(ERRCTX_SFX_NEWDOC);
460 if ( !pTemplNameItem && !pTemplFileNameItem )
462 bool bNewWin = false;
463 weld::Window* pTopWin = GetTopWindow();
465 SfxObjectShell* pCurrentShell = SfxObjectShell::Current();
466 Reference<XModel> xModel;
467 if(pCurrentShell)
468 xModel = pCurrentShell->GetModel();
470 SfxTemplateManagerDlg aTemplDlg(rReq.GetFrameWeld());
472 if (xModel.is())
473 aTemplDlg.setDocumentModel(xModel);
475 int nRet = aTemplDlg.run();
476 if ( nRet == RET_OK )
478 rReq.Done();
479 if ( pTopWin != GetTopWindow() )
481 // the dialogue opens a document -> a new TopWindow appears
482 pTopWin = GetTopWindow();
483 bNewWin = true;
487 if (bNewWin && pTopWin)
489 // after the destruction of the dialogue its parent comes to top,
490 // but we want that the new document is on top
491 pTopWin->present();
494 return;
496 else
498 // Template-Name
499 if ( pTemplNameItem )
500 aTemplateName = pTemplNameItem->GetValue();
502 // Template-Region
503 if ( pTemplRegionNameItem )
504 aTemplateRegion = pTemplRegionNameItem->GetValue();
506 // Template-File-Name
507 if ( pTemplFileNameItem )
509 aTemplateFileName = pTemplFileNameItem->GetValue();
510 bDirect = true;
514 ErrCode lErr = ERRCODE_NONE;
515 if ( !bDirect )
517 SfxDocumentTemplates aTmpFac;
518 if( aTemplateFileName.isEmpty() )
519 aTmpFac.GetFull( aTemplateRegion, aTemplateName, aTemplateFileName );
521 if( aTemplateFileName.isEmpty() )
522 lErr = ERRCODE_SFX_TEMPLATENOTFOUND;
525 INetURLObject aObj( aTemplateFileName );
526 SfxErrorContext aEC( ERRCTX_SFX_LOADTEMPLATE, aObj.PathToFileName() );
528 if ( lErr != ERRCODE_NONE )
530 ErrCode lFatalErr = lErr.IgnoreWarning();
531 if ( lFatalErr )
532 ErrorHandler::HandleError(lErr);
534 else
536 SfxCallMode eMode = SfxCallMode::SYNCHRON;
537 SfxPoolItemHolder aResult;
538 SfxStringItem aReferer( SID_REFERER, u"private:user"_ustr );
539 SfxStringItem aTarget( SID_TARGETNAME, u"_default"_ustr );
540 if ( !aTemplateFileName.isEmpty() )
542 DBG_ASSERT( aObj.GetProtocol() != INetProtocol::NotValid, "Illegal URL!" );
544 SfxStringItem aName( SID_FILE_NAME, aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
545 SfxStringItem aTemplName( SID_TEMPLATE_NAME, aTemplateName );
546 SfxStringItem aTemplRegionName( SID_TEMPLATE_REGIONNAME, aTemplateRegion );
547 aResult = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode,
548 {&aName, &aTarget, &aReferer, &aTemplName, &aTemplRegionName});
550 else
552 SfxStringItem aName( SID_FILE_NAME, u"private:factory"_ustr );
553 aResult = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode,
554 { &aName, &aTarget, &aReferer } );
557 if (aResult)
558 rReq.SetReturnValue( *aResult.getItem() );
563 namespace {
566 * Check if a given filter type should open the hyperlinked document
567 * natively.
569 * @param rFilter filter object
571 bool lcl_isFilterNativelySupported(const SfxFilter& rFilter)
573 if (rFilter.IsOwnFormat())
574 return true;
576 const OUString& aName = rFilter.GetFilterName();
577 // We can handle all Excel variants natively.
578 return aName.startsWith("MS Excel");
583 void SfxApplication::OpenDocExec_Impl( SfxRequest& rReq )
585 OUString aDocService;
586 const SfxStringItem* pDocSrvItem = rReq.GetArg<SfxStringItem>(SID_DOC_SERVICE);
587 if (pDocSrvItem)
588 aDocService = pDocSrvItem->GetValue();
590 sal_uInt16 nSID = rReq.GetSlot();
591 const SfxStringItem* pFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
592 if ( pFileNameItem )
594 OUString aCommand( pFileNameItem->GetValue() );
595 const SfxSlot* pSlot = GetInterface()->GetSlot( aCommand );
596 if ( pSlot )
598 pFileNameItem = nullptr;
600 else
602 if ( aCommand.startsWith("slot:") )
604 sal_uInt16 nSlotId = static_cast<sal_uInt16>(o3tl::toInt32(aCommand.subView(5)));
605 if ( nSlotId == SID_OPENDOC )
606 pFileNameItem = nullptr;
611 if ( !pFileNameItem )
613 // get FileName from dialog
614 std::vector<OUString> aURLList;
615 OUString aFilter;
616 std::optional<SfxAllItemSet> pSet;
617 OUString aPath;
618 const SfxStringItem* pFolderNameItem = rReq.GetArg<SfxStringItem>(SID_PATH);
619 if ( pFolderNameItem )
620 aPath = pFolderNameItem->GetValue();
621 else if ( nSID == SID_OPENTEMPLATE )
623 aPath = SvtPathOptions().GetTemplatePath();
624 if (!aPath.isEmpty()) // if not empty then get last token
625 aPath = aPath.copy(aPath.lastIndexOf(';')+1); // lastIndexOf+copy works whether separator (';') is there or not
628 sal_Int16 nDialog = SFX2_IMPL_DIALOG_CONFIG;
629 const SfxBoolItem* pSystemDialogItem = rReq.GetArg<SfxBoolItem>(SID_FILE_DIALOG);
630 if ( pSystemDialogItem )
631 nDialog = pSystemDialogItem->GetValue() ? SFX2_IMPL_DIALOG_SYSTEM : SFX2_IMPL_DIALOG_OOO;
633 const SfxBoolItem* pRemoteDialogItem = rReq.GetArg<SfxBoolItem>(SID_REMOTE_DIALOG);
634 if ( pRemoteDialogItem && pRemoteDialogItem->GetValue())
635 nDialog = SFX2_IMPL_DIALOG_REMOTE;
637 sal_Int16 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION;
638 FileDialogFlags eDialogFlags = FileDialogFlags::MultiSelection;
639 const SfxBoolItem* pSignPDFItem = rReq.GetArg<SfxBoolItem>(SID_SIGNPDF);
640 if (pSignPDFItem && pSignPDFItem->GetValue())
642 eDialogFlags |= FileDialogFlags::SignPDF;
643 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE;
646 OUString sStandardDir;
648 const SfxStringItem* pStandardDirItem = rReq.GetArg<SfxStringItem>(SID_STANDARD_DIR);
649 if ( pStandardDirItem )
650 sStandardDir = pStandardDirItem->GetValue();
652 css::uno::Sequence< OUString > aDenyList;
654 const SfxStringListItem* pDenyListItem = rReq.GetArg<SfxStringListItem>(SID_DENY_LIST);
655 if ( pDenyListItem )
656 pDenyListItem->GetStringList( aDenyList );
658 weld::Window* pTopWindow = GetTopWindow();
659 ErrCode nErr = sfx2::FileOpenDialog_Impl(pTopWindow,
660 nDialogType,
661 eDialogFlags, aURLList,
662 aFilter, pSet, &aPath, nDialog, sStandardDir, aDenyList);
664 if ( nErr == ERRCODE_ABORT )
666 aURLList.clear();
667 return;
670 rReq.SetArgs( *pSet );
671 if ( !aFilter.isEmpty() )
672 rReq.AppendItem( SfxStringItem( SID_FILTER_NAME, aFilter ) );
673 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, u"_default"_ustr ) );
674 rReq.AppendItem( SfxStringItem( SID_REFERER, u"private:user"_ustr ) );
675 pSet.reset();
677 if(!aURLList.empty())
679 if ( nSID == SID_OPENTEMPLATE )
680 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) );
682 // This helper wraps an existing (or may new created InteractionHandler)
683 // intercept all incoming interactions and provide useful information
684 // later if the following transaction was finished.
686 rtl::Reference<sfx2::PreventDuplicateInteraction> pHandler = new sfx2::PreventDuplicateInteraction(comphelper::getProcessComponentContext());
687 uno::Reference<task::XInteractionHandler> xHandler(pHandler);
688 uno::Reference<task::XInteractionHandler> xWrappedHandler;
690 // wrap existing handler or create new UUI handler
691 const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER);
692 if (pInteractionItem)
694 pInteractionItem->GetValue() >>= xWrappedHandler;
695 rReq.RemoveItem( SID_INTERACTIONHANDLER );
697 if (xWrappedHandler.is())
698 pHandler->setHandler(xWrappedHandler);
699 else
700 pHandler->useDefaultUUIHandler();
701 rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::Any(xHandler)) );
703 // define rules for this handler
704 css::uno::Type aInteraction = ::cppu::UnoType<css::task::ErrorCodeRequest>::get();
705 ::sfx2::PreventDuplicateInteraction::InteractionInfo aRule(aInteraction);
706 pHandler->addInteractionRule(aRule);
708 if (!aDocService.isEmpty())
710 rReq.RemoveItem(SID_DOC_SERVICE);
711 rReq.AppendItem(SfxStringItem(SID_DOC_SERVICE, aDocService));
714 for (auto const& url : aURLList)
716 rReq.RemoveItem( SID_FILE_NAME );
717 rReq.AppendItem( SfxStringItem( SID_FILE_NAME, url ) );
719 // Run synchronous, so that not the next document is loaded
720 // when rescheduling
721 // TODO/LATER: use URLList argument and always remove one document after another, each step in asynchronous execution, until finished
722 // but only if reschedule is a problem
723 GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() );
725 // check for special interaction "NO MORE DOCUMENTS ALLOWED" and
726 // break loop then. Otherwise we risk showing the same interaction more than once.
727 if ( pHandler->getInteractionInfo(aInteraction, &aRule) )
729 if (aRule.m_nCallCount > 0)
731 if (aRule.m_xRequest.is())
733 css::task::ErrorCodeRequest aRequest;
734 if (aRule.m_xRequest->getRequest() >>= aRequest)
736 if (aRequest.ErrCode == sal_Int32(sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED)))
737 break;
744 aURLList.clear();
745 return;
747 aURLList.clear();
750 bool bHyperlinkUsed = false;
752 if ( SID_OPENURL == nSID )
754 // SID_OPENURL does the same as SID_OPENDOC!
755 rReq.SetSlot( SID_OPENDOC );
757 else if ( nSID == SID_OPENTEMPLATE )
759 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) );
761 // pass URL to OS by using ShellExecuter or open it internal
762 // if it seems to be an own format.
763 /* Attention!
764 There exist two possibilities to open hyperlinks:
765 a) using SID_OPENHYPERLINK (new)
766 b) using SID_BROWSE (old)
768 else if ( nSID == SID_OPENHYPERLINK )
770 rReq.SetSlot( SID_OPENDOC );
771 bHyperlinkUsed = true;
774 // no else here! It's optional ...
775 if (!bHyperlinkUsed)
777 const SfxBoolItem* pHyperLinkUsedItem = rReq.GetArg<SfxBoolItem>(SID_BROWSE);
778 if ( pHyperLinkUsedItem )
779 bHyperlinkUsed = pHyperLinkUsedItem->GetValue();
780 // no "official" item, so remove it from ItemSet before using UNO-API
781 rReq.RemoveItem( SID_BROWSE );
784 const SfxStringItem* pFileName = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
785 assert(pFileName && "SID_FILE_NAME is required");
786 OUString aFileName = pFileName->GetValue();
788 OUString aReferer;
789 const SfxStringItem* pRefererItem = rReq.GetArg<SfxStringItem>(SID_REFERER);
790 if ( pRefererItem )
791 aReferer = pRefererItem->GetValue();
793 const SfxStringItem* pFileFlagsItem = rReq.GetArg<SfxStringItem>(SID_OPTIONS);
794 if ( pFileFlagsItem )
796 const OUString aFileFlags = pFileFlagsItem->GetValue().toAsciiUpperCase();
797 if ( aFileFlags.indexOf('T') >= 0 )
799 rReq.RemoveItem( SID_TEMPLATE );
800 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, true ) );
803 if ( aFileFlags.indexOf('H') >= 0 )
805 rReq.RemoveItem( SID_HIDDEN );
806 rReq.AppendItem( SfxBoolItem( SID_HIDDEN, true ) );
809 if ( aFileFlags.indexOf('R') >= 0 )
811 rReq.RemoveItem( SID_DOC_READONLY );
812 rReq.AppendItem( SfxBoolItem( SID_DOC_READONLY, true ) );
815 if ( aFileFlags.indexOf('B') >= 0 )
817 rReq.RemoveItem( SID_PREVIEW );
818 rReq.AppendItem( SfxBoolItem( SID_PREVIEW, true ) );
821 rReq.RemoveItem( SID_OPTIONS );
824 // Mark without URL cannot be handled by hyperlink code
825 if ( bHyperlinkUsed && !aFileName.isEmpty() && aFileName[0] != '#' )
827 uno::Reference<document::XTypeDetection> xTypeDetection(
828 comphelper::getProcessServiceFactory()->createInstance(u"com.sun.star.document.TypeDetection"_ustr), UNO_QUERY);
830 if ( xTypeDetection.is() )
832 URL aURL;
834 aURL.Complete = aFileName;
835 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
836 xTrans->parseStrict( aURL );
838 INetProtocol aINetProtocol = INetURLObject( aURL.Complete ).GetProtocol();
839 auto eMode = officecfg::Office::Security::Hyperlinks::Open::get();
841 if ( eMode == SvtExtendedSecurityOptions::OPEN_NEVER && aINetProtocol != INetProtocol::VndSunStarHelp )
843 SolarMutexGuard aGuard;
844 weld::Window *pWindow = SfxGetpApp()->GetTopWindow();
846 std::unique_ptr<weld::MessageDialog> xSecurityWarningBox(Application::CreateMessageDialog(pWindow,
847 VclMessageType::Warning, VclButtonsType::Ok, SfxResId(STR_SECURITY_WARNING_NO_HYPERLINKS)));
848 xSecurityWarningBox->set_title(SfxResId(RID_SECURITY_WARNING_TITLE));
849 xSecurityWarningBox->run();
850 return;
853 std::shared_ptr<const SfxFilter> pFilter{};
855 // attempt loading native documents only if they are from a known protocol
856 // it might be sensible to limit the set of protocols even further, but that
857 // may cause regressions, needs further testing
858 // see tdf#136427 for details
859 if (aINetProtocol != INetProtocol::NotValid) {
860 const OUString aTypeName { xTypeDetection->queryTypeByURL( aURL.Main ) };
861 SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
862 pFilter = rMatcher.GetFilter4EA( aTypeName );
865 bool bStartPresentation = false;
866 if (pFilter)
868 const SfxUInt16Item* pSlide = rReq.GetArg<SfxUInt16Item>(SID_DOC_STARTPRESENTATION);
869 if (pSlide
870 && (pFilter->GetWildcard().Matches(u".pptx")
871 || pFilter->GetWildcard().Matches(u".ppt")
872 || pFilter->GetWildcard().Matches(u".ppsx")
873 || pFilter->GetWildcard().Matches(u".pps")))
875 bStartPresentation = true;
879 if (!pFilter || (!lcl_isFilterNativelySupported(*pFilter) && !bStartPresentation))
881 // hyperlink does not link to own type => special handling (http, ftp) browser and (other external protocols) OS
882 if ( aINetProtocol == INetProtocol::Mailto )
884 // don't dispatch mailto hyperlink to desktop dispatcher
885 rReq.RemoveItem( SID_TARGETNAME );
886 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, u"_self"_ustr ) );
888 else if ( aINetProtocol == INetProtocol::Ftp ||
889 aINetProtocol == INetProtocol::Http ||
890 aINetProtocol == INetProtocol::Https )
892 sfx2::openUriExternally(aURL.Complete, true, rReq.GetFrameWeld());
893 return;
895 else
897 // check for "internal" protocols that should not be forwarded to the system
898 // add special protocols that always should be treated as internal
899 std::vector < OUString > aProtocols { u"private:*"_ustr, u"vnd.sun.star.*"_ustr };
901 // get registered protocol handlers from configuration
902 Reference < XNameAccess > xAccess(officecfg::Office::ProtocolHandler::HandlerSet::get());
903 const Sequence < OUString > aNames = xAccess->getElementNames();
904 for ( const auto& rName : aNames )
906 Reference < XPropertySet > xSet;
907 Any aRet = xAccess->getByName( rName );
908 aRet >>= xSet;
909 if ( xSet.is() )
911 // copy protocols
912 aRet = xSet->getPropertyValue(u"Protocols"_ustr);
913 Sequence < OUString > aTmp;
914 aRet >>= aTmp;
916 aProtocols.insert(aProtocols.end(),std::cbegin(aTmp),std::cend(aTmp));
920 bool bFound = false;
921 for (const OUString & rProtocol : aProtocols)
923 WildCard aPattern(rProtocol);
924 if ( aPattern.Matches( aURL.Complete ) )
926 bFound = true;
927 break;
931 if ( !bFound )
933 bool bLoadInternal = false;
936 sfx2::openUriExternally(
937 aURL.Complete, pFilter == nullptr, rReq.GetFrameWeld());
939 catch ( css::system::SystemShellExecuteException& )
941 rReq.RemoveItem( SID_TARGETNAME );
942 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, u"_default"_ustr ) );
943 bLoadInternal = true;
945 if ( !bLoadInternal )
946 return;
950 else
952 // hyperlink document must be loaded into a new frame
953 rReq.RemoveItem( SID_TARGETNAME );
954 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, u"_default"_ustr ) );
959 if (!SvtSecurityOptions::isSecureMacroUri(aFileName, aReferer))
961 SfxErrorContext aCtx( ERRCTX_SFX_OPENDOC, aFileName );
962 ErrorHandler::HandleError( ERRCODE_IO_ACCESSDENIED );
963 return;
966 SfxFrame* pTargetFrame = nullptr;
967 Reference< XFrame > xTargetFrame;
969 const SfxFrameItem* pFrameItem = rReq.GetArg<SfxFrameItem>(SID_DOCFRAME);
970 if ( pFrameItem )
971 pTargetFrame = pFrameItem->GetFrame();
973 if ( !pTargetFrame )
975 const SfxUnoFrameItem* pUnoFrameItem = rReq.GetArg<SfxUnoFrameItem>(SID_FILLFRAME);
976 if ( pUnoFrameItem )
977 xTargetFrame = pUnoFrameItem->GetFrame();
980 if (!pTargetFrame && !xTargetFrame.is())
982 if (const SfxViewFrame* pViewFrame = SfxViewFrame::Current())
983 pTargetFrame = &pViewFrame->GetFrame();
986 // check if caller has set a callback
987 std::unique_ptr<SfxLinkItem> pLinkItem;
989 // remove from Itemset, because it confuses the parameter transformation
990 if (auto pParamLinkItem = rReq.GetArg<SfxLinkItem>(SID_DONELINK))
991 pLinkItem.reset(pParamLinkItem->Clone());
993 rReq.RemoveItem( SID_DONELINK );
995 // check if the view must be hidden
996 bool bHidden = false;
997 const SfxBoolItem* pHidItem = rReq.GetArg<SfxBoolItem>(SID_HIDDEN);
998 if ( pHidItem )
999 bHidden = pHidItem->GetValue();
1001 // This request is a UI call. We have to set the right values inside the MediaDescriptor
1002 // for: InteractionHandler, StatusIndicator, MacroExecutionMode and DocTemplate.
1003 // But we have to look for already existing values or for real hidden requests.
1004 const SfxBoolItem* pPreviewItem = rReq.GetArg<SfxBoolItem>(SID_PREVIEW);
1005 if (!bHidden && ( !pPreviewItem || !pPreviewItem->GetValue() ) )
1007 const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER);
1008 const SfxUInt16Item* pMacroExecItem = rReq.GetArg<SfxUInt16Item>(SID_MACROEXECMODE);
1009 const SfxUInt16Item* pDocTemplateItem = rReq.GetArg<SfxUInt16Item>(SID_UPDATEDOCMODE);
1011 if (!pInteractionItem)
1013 Reference < task::XInteractionHandler2 > xHdl = task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr );
1014 rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::Any(xHdl)) );
1016 if (!pMacroExecItem)
1017 rReq.AppendItem( SfxUInt16Item(SID_MACROEXECMODE,css::document::MacroExecMode::USE_CONFIG) );
1018 if (!pDocTemplateItem)
1019 rReq.AppendItem( SfxUInt16Item(SID_UPDATEDOCMODE,css::document::UpdateDocMode::ACCORDING_TO_CONFIG) );
1022 // extract target name
1023 OUString aTarget;
1024 const SfxStringItem* pTargetItem = rReq.GetArg<SfxStringItem>(SID_TARGETNAME);
1025 if ( pTargetItem )
1026 aTarget = pTargetItem->GetValue();
1027 else
1029 const SfxBoolItem* pNewViewItem = rReq.GetArg<SfxBoolItem>(SID_OPEN_NEW_VIEW);
1030 if ( pNewViewItem && pNewViewItem->GetValue() )
1031 aTarget = "_blank" ;
1034 if ( bHidden )
1036 aTarget = "_blank";
1037 DBG_ASSERT( rReq.IsSynchronCall() || pLinkItem, "Hidden load process must be done synchronously!" );
1040 Reference < XController > xController;
1041 // if a frame is given, it must be used for the starting point of the targeting mechanism
1042 // this code is also used if asynchronous loading is possible, because loadComponent always is synchron
1043 if ( !xTargetFrame.is() )
1045 if ( pTargetFrame )
1047 xTargetFrame = pTargetFrame->GetFrameInterface();
1049 else
1051 xTargetFrame = Desktop::create(::comphelper::getProcessComponentContext());
1055 // make URL ready
1056 const SfxStringItem* pURLItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
1057 aFileName = pURLItem->GetValue();
1058 if( aFileName.startsWith("#") ) // Mark without URL
1060 SfxViewFrame *pView = pTargetFrame ? pTargetFrame->GetCurrentViewFrame() : nullptr;
1061 if (!pView)
1062 pView = SfxViewFrame::Current();
1063 if (pView)
1064 pView->GetViewShell()->JumpToMark( aFileName.copy(1) );
1065 rReq.SetReturnValue( SfxViewFrameItem( pView ) );
1066 return;
1069 // convert items to properties for framework API calls
1070 Sequence < PropertyValue > aArgs;
1071 TransformItems( SID_OPENDOC, *rReq.GetArgs(), aArgs );
1072 // Any Referer (that was relevant in the above call to
1073 // SvtSecurityOptions::isSecureMacroUri) is no longer relevant, assuming
1074 // this "open" request is initiated directly by the user:
1075 auto pArg = std::find_if(std::cbegin(aArgs), std::cend(aArgs),
1076 [](const PropertyValue& rArg) { return rArg.Name == "Referer"; });
1077 if (pArg != std::cend(aArgs))
1079 auto nIndex = static_cast<sal_Int32>(std::distance(std::cbegin(aArgs), pArg));
1080 comphelper::removeElementAt(aArgs, nIndex);
1083 // TODO/LATER: either remove LinkItem or create an asynchronous process for it
1084 if( bHidden || pLinkItem || rReq.IsSynchronCall() )
1086 // if loading must be done synchron, we must wait for completion to get a return value
1087 // find frame by myself; I must know the exact frame to get the controller for the return value from it
1088 Reference < XComponent > xComp;
1092 xComp = ::comphelper::SynchronousDispatch::dispatch( xTargetFrame, aFileName, aTarget, aArgs );
1094 catch(const RuntimeException&)
1096 throw;
1098 catch(const css::uno::Exception&)
1102 Reference < XModel > xModel( xComp, UNO_QUERY );
1103 if ( xModel.is() )
1104 xController = xModel->getCurrentController();
1105 else
1106 xController.set( xComp, UNO_QUERY );
1109 else
1111 URL aURL;
1112 aURL.Complete = aFileName;
1113 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
1114 xTrans->parseStrict( aURL );
1116 Reference < XDispatchProvider > xProv( xTargetFrame, UNO_QUERY );
1117 Reference < XDispatch > xDisp = xProv.is() ? xProv->queryDispatch( aURL, aTarget, FrameSearchFlag::ALL ) : Reference < XDispatch >();
1118 if ( xDisp.is() )
1119 xDisp->dispatch( aURL, aArgs );
1122 if ( xController.is() )
1124 // try to find the SfxFrame for the controller
1125 SfxFrame* pCntrFrame = nullptr;
1126 for ( SfxViewShell* pShell = SfxViewShell::GetFirst( false ); pShell; pShell = SfxViewShell::GetNext( *pShell, false ) )
1128 if ( pShell->GetController() == xController )
1130 pCntrFrame = &pShell->GetViewFrame().GetFrame();
1131 break;
1135 if ( pCntrFrame )
1137 SfxObjectShell* pSh = pCntrFrame->GetCurrentDocument();
1138 DBG_ASSERT( pSh, "Controller without ObjectShell ?!" );
1140 rReq.SetReturnValue( SfxViewFrameItem( pCntrFrame->GetCurrentViewFrame() ) );
1144 if (pLinkItem)
1146 const SfxPoolItem* pRetValue(rReq.GetReturnValue().getItem());
1147 if (pRetValue)
1149 pLinkItem->GetValue().Call(pRetValue);
1154 void SfxApplication::OpenRemoteExec_Impl( SfxRequest& rReq )
1156 rReq.AppendItem( SfxBoolItem( SID_REMOTE_DIALOG, true ) );
1157 GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() );
1160 void SfxApplication::SignPDFExec_Impl(SfxRequest& rReq)
1162 rReq.AppendItem(SfxBoolItem(SID_SIGNPDF, true));
1163 GetDispatcher_Impl()->Execute(SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs());
1166 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */