LibreOffice Module sfx2 (master) 1
fileobj.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <tools/urlobj.hxx>
21#include <tools/stream.hxx>
22#include <sot/formats.hxx>
23#include <sal/log.hxx>
24#include <sfx2/lnkbase.hxx>
26#include <sot/exchange.hxx>
27#include <com/sun/star/uno/Any.hxx>
28#include <com/sun/star/uno/Sequence.hxx>
29#include <sfx2/docfac.hxx>
30#include <com/sun/star/document/XTypeDetection.hpp>
31#include <com/sun/star/container/XNameAccess.hpp>
32#include <com/sun/star/lang/XMultiServiceFactory.hpp>
35#include <sfx2/linkmgr.hxx>
36#include <sfx2/opengrf.hxx>
37#include <sfx2/sfxresid.hxx>
38#include <sfx2/objsh.hxx>
39#include "fileobj.hxx"
40#include <sfx2/strings.hrc>
41#include <vcl/svapp.hxx>
42
44{
45 Text = 1, Graphic = 2, Object = 3
46};
47
49 : nPostUserEventId(nullptr)
51 , bLoadAgain(true)
52 , bSynchron(false)
53 , bLoadError(false)
54 , bWaitForData(false)
55 , bDataReady(false)
56 , bClearMedium(false)
57 , bStateChangeCalled(false)
58{
59}
60
62{
63 if (xMed.is())
64 {
65 xMed->SetDoneLink( Link<void*,void>() );
66 xMed.clear();
67 }
70}
71
72bool SvFileObject::GetData( css::uno::Any & rData,
73 const OUString & rMimeType,
74 bool /*bGetSynchron*/ )
75{
77 switch( nType )
78 {
80 if( SotClipboardFormatId::SIMPLE_FILE == nFmt )
81 {
82 // The media in the application must be opened to lookup the
83 // relative file links!! This is done through the link manager
84 // of the Storage.
85 rData <<= sFileNm;
86 }
87 break;
88
90 if (SotClipboardFormatId::GDIMETAFILE == nFmt
91 || SotClipboardFormatId::BITMAP == nFmt
92 || SotClipboardFormatId::SVXB == nFmt)
93 {
94 rData <<= sFileNm;
95 }
96 break;
98 // TODO/LATER: possibility to insert a new object
99 rData <<= sFileNm;
100 break;
101 }
102 return true/*0 != aTypeList.Count()*/;
103}
104
106{
107 if( !pLink || !pLink->GetLinkManager() )
108 return false;
109
110 // Test if not another link of the same connection already exists
112
114 {
115 SfxObjectShellRef pShell = pLink->GetLinkManager()->GetPersist();
116 if( pShell.is() )
117 {
118 if( pShell->IsAbortingImport() )
119 return false;
120
121 if( pShell->GetMedium() )
122 sReferer = pShell->GetMedium()->GetName();
123 }
124 }
125
126 switch( pLink->GetObjType() )
127 {
130 bSynchron = pLink->IsSynchron();
131 break;
132
135 break;
136
139 // TODO/LATER: introduce own type to be used for exchanging
140 break;
141
142 default:
143 return false;
144 }
145
146 SetUpdateTimeout( 0 );
147
148 // and now register by this or other found Pseudo-Object
149 AddDataAdvise( pLink, SotExchange::GetFormatMimeType( pLink->GetContentType()), 0 );
150 return true;
151}
152
154{
155 // We are still at Loading!!
156 if( bWaitForData || !bLoadAgain || xMed.is() )
157 return false;
158
159 // at the moment on the current DocShell
160 xMed = new SfxMedium( sFileNm, sReferer, StreamMode::STD_READ );
161 SvLinkSource::StreamToLoadFrom aStreamToLoadFrom =
163 xMed->setStreamToLoadFrom(
164 aStreamToLoadFrom.m_xInputStreamToLoadFrom,
165 aStreamToLoadFrom.m_bIsReadOnly);
166
167 if( !bSynchron )
168 {
169 bLoadAgain = bDataReady = false;
170 bWaitForData = true;
171
173 xMed->Download( LINK( this, SvFileObject, LoadGrfReady_Impl ) );
174
175 bClearMedium = !xMed.is();
176 if( bClearMedium )
177 xMed = xTmpMed; // If already finished in Download
178 return bDataReady;
179 }
180
181 bWaitForData = true;
182 bDataReady = false;
183 xMed->Download();
184 bLoadAgain = !xMed->IsRemote();
185 bWaitForData = false;
186
187 // Graphic is finished, also send DataChanged of the Status change:
188 SendStateChg_Impl( xMed->GetInStream() && xMed->GetInStream()->GetError()
190 return true;
191}
192
193
201static OUString impl_getFilter( const OUString& _rURL )
202{
203 OUString sFilter;
204 if ( _rURL.isEmpty() )
205 return sFilter;
206
207 try
208 {
209 css::uno::Reference< css::document::XTypeDetection > xTypeDetection(
210 ::comphelper::getProcessServiceFactory()->createInstance( "com.sun.star.document.TypeDetection" ),
211 css::uno::UNO_QUERY );
212 if ( xTypeDetection.is() )
213 {
215 aDescr[ utl::MediaDescriptor::PROP_URL ] <<= _rURL;
216 css::uno::Sequence< css::beans::PropertyValue > aDescrList =
217 aDescr.getAsConstPropertyValueList();
218 OUString sType = xTypeDetection->queryTypeByDescriptor( aDescrList, true );
219 if ( !sType.isEmpty() )
220 {
221 // Honor a selected/detected filter.
222 for (const auto& rDescr : std::as_const(aDescrList))
223 {
224 if (rDescr.Name == "FilterName")
225 {
226 if (rDescr.Value >>= sFilter)
227 break;
228 }
229 }
230 if (sFilter.isEmpty())
231 {
232 css::uno::Reference< css::container::XNameAccess > xTypeCont( xTypeDetection,
233 css::uno::UNO_QUERY );
234 if ( xTypeCont.is() )
235 {
236 /* XXX: for fdo#69948 scenario the sequence returned by
237 * getByName() contains an empty PreferredFilter
238 * property value (since? expected?) */
239 ::comphelper::SequenceAsHashMap lTypeProps( xTypeCont->getByName( sType ) );
240 sFilter = lTypeProps.getUnpackedValueOrDefault(
241 "PreferredFilter", OUString() );
242 }
243 }
244 }
245 }
246 }
247 catch( const css::uno::Exception& )
248 {
249 }
250
251 return sFilter;
252}
253
255{
256 aEndEditLink = rEndEditHdl;
257 OUString sFile, sRange, sTmpFilter;
258 if( !pLink || !pLink->GetLinkManager() )
259 return;
260
261 sfx2::LinkManager::GetDisplayNames( pLink, nullptr, &sFile, &sRange, &sTmpFilter );
262
263 switch( pLink->GetObjType() )
264 {
266 {
267 nType = SvFileObjectType::Graphic; // If not set already
268
269 SvxOpenGraphicDialog aDlg(SfxResId(RID_SVXSTR_EDITGRFLINK), pParent);
270 aDlg.EnableLink(false);
271 aDlg.SetPath( sFile, true );
272 aDlg.SetCurrentFilter( sTmpFilter );
273
274 if( !aDlg.Execute() )
275 {
276 sFile = aDlg.GetPath()
277 + OUStringChar(sfx2::cTokenSeparator)
278 + OUStringChar(sfx2::cTokenSeparator)
279 + aDlg.GetDetectedFilter();
280
281 aEndEditLink.Call( sFile );
282 }
283 else
284 sFile.clear();
285 }
286 break;
287
289 {
290 nType = SvFileObjectType::Object; // if not set already
291
292 ::sfx2::FileDialogHelper & rFileDlg =
293 pLink->GetInsertFileDialog( OUString() );
295 rFileDlg.StartExecuteModal(
296 LINK( this, SvFileObject, DialogClosedHdl ) );
297 }
298 break;
299
301 {
302 nType = SvFileObjectType::Text; // if not set already
303
304 OUString sFactory;
305 SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
306 if ( pShell )
307 sFactory = pShell->GetFactory().GetFactoryName();
308
309 ::sfx2::FileDialogHelper & rFileDlg =
310 pLink->GetInsertFileDialog(sFactory);
312 rFileDlg.StartExecuteModal(
313 LINK( this, SvFileObject, DialogClosedHdl ) );
314 }
315 break;
316
317 default:
318 sFile.clear();
319 }
320}
321
322IMPL_LINK_NOARG( SvFileObject, LoadGrfReady_Impl, void*, void )
323{
324 // When we come from here there it can not be an error no more.
325 bLoadError = false;
326 bWaitForData = false;
327
328 if( !bDataReady )
329 {
330 // Graphic is finished, also send DataChanged from Status change
331 bDataReady = true;
332 SendStateChg_Impl( sfx2::LinkManager::STATE_LOAD_OK );
333
334 // and then send the data again
335 NotifyDataChanged();
336 }
337
338 if( bDataReady )
339 {
340 bLoadAgain = true;
341 if( xMed.is() )
342 {
343 xMed->SetDoneLink( Link<void*,void>() );
344 mxDelMed = xMed;
345 nPostUserEventId = Application::PostUserEvent(
346 LINK( this, SvFileObject, DelMedium_Impl ));
347 xMed.clear();
348 }
349 }
350}
351
352IMPL_LINK_NOARG( SvFileObject, DelMedium_Impl, void*, void )
353{
354 nPostUserEventId = nullptr;
355 mxDelMed.clear();
356}
357
358IMPL_LINK( SvFileObject, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void )
359{
360 OUString sFile;
361
363 {
364 if ( _pFileDlg && _pFileDlg->GetError() == ERRCODE_NONE )
365 {
366 OUString sURL( _pFileDlg->GetPath() );
367 sFile = sURL + OUStringChar(sfx2::cTokenSeparator)
368 + OUStringChar(sfx2::cTokenSeparator)
369 + impl_getFilter( sURL );
370 }
371 }
372 else
373 {
374 SAL_WARN( "sfx.appl", "SvFileObject::DialogClosedHdl(): wrong file type" );
375 }
376
377 aEndEditLink.Call( sFile );
378}
379
380/*
381 The method determines whether the data-object can be read from a DDE.
382*/
384{
386}
387
389{
390 bool bRet = false;
392 bRet = true;
393 else if( !bLoadError && !bWaitForData )
394 {
395 SvFileObject* pThis = const_cast<SvFileObject*>(this);
396 if( bDataReady ||
397 ( bSynchron && pThis->LoadFile_Impl() && xMed.is() ) )
398 bRet = true;
399 else
400 {
401 INetURLObject aUrl( sFileNm );
402 if( aUrl.HasError() ||
403 INetProtocol::NotValid == aUrl.GetProtocol() )
404 bRet = true;
405 }
406 }
407 return bRet;
408}
409
410
412{
413 // unsubscribe from the cache if in the middle of loading
414 if( !bDataReady )
415 {
416 // Do not set-up again
417 bLoadAgain = false;
420 }
421}
422
423
425{
427 {
429 sfx2::LinkManager::RegisterStatusInfoId()), css::uno::Any(OUString::number( nState )) );
430 bStateChangeCalled = true;
431 }
432}
433
434
435/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sType
HRESULT createInstance(REFIID iid, Ifc **ppIfc)
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
static void RemoveUserEvent(ImplSVEvent *nUserEvent)
bool HasError() const
INetProtocol GetProtocol() const
const OUString & GetFactoryName() const
Definition: docfac.hxx:52
virtual SfxObjectFactory & GetFactory() const =0
static OUString GetFormatMimeType(SotClipboardFormatId nFormat)
static OUString GetFormatName(SotClipboardFormatId nFormat)
static SotClipboardFormatId RegisterFormatMimeType(const OUString &rMimeType)
bool bClearMedium
Definition: fileobj.hxx:49
bool bSynchron
Definition: fileobj.hxx:45
Link< const OUString &, void > aEndEditLink
Definition: fileobj.hxx:37
virtual ~SvFileObject() override
Definition: fileobj.cxx:61
OUString sFileNm
Definition: fileobj.hxx:34
bool bLoadError
Definition: fileobj.hxx:46
virtual void Edit(weld::Window *, sfx2::SvBaseLink *, const Link< const OUString &, void > &rEndEditHdl) override
Definition: fileobj.cxx:254
SvFileObjectType nType
Definition: fileobj.hxx:42
virtual bool IsDataComplete() const override
Definition: fileobj.cxx:388
void SendStateChg_Impl(sfx2::LinkManager::LinkState nState)
Definition: fileobj.cxx:424
ImplSVEvent * nPostUserEventId
Definition: fileobj.hxx:39
OUString sFilter
Definition: fileobj.hxx:35
bool bLoadAgain
Definition: fileobj.hxx:44
bool bWaitForData
Definition: fileobj.hxx:47
tools::SvRef< SfxMedium > xMed
Definition: fileobj.hxx:38
virtual bool GetData(css::uno::Any &rData, const OUString &rMimeType, bool bSynchron=false) override
Definition: fileobj.cxx:72
bool bDataReady
Definition: fileobj.hxx:48
bool bStateChangeCalled
Definition: fileobj.hxx:50
virtual bool IsPending() const override
Definition: fileobj.cxx:383
bool LoadFile_Impl()
Definition: fileobj.cxx:153
OUString sReferer
Definition: fileobj.hxx:36
virtual bool Connect(sfx2::SvBaseLink *) override
Definition: fileobj.cxx:105
void CancelTransfers()
Definition: fileobj.cxx:411
void EnableLink(bool)
Definition: opengrf.cxx:194
void SetCurrentFilter(const OUString &)
Definition: opengrf.cxx:271
void SetPath(const OUString &rPath, bool bLinkState)
Definition: opengrf.cxx:187
OUString GetPath() const
Definition: opengrf.cxx:256
OUString const & GetDetectedFilter() const
Definition: opengrf.cxx:266
TValueType getUnpackedValueOrDefault(const OUString &sKey, const TValueType &aDefault) const
void StartExecuteModal(const Link< FileDialogHelper *, void > &rEndDialogHdl)
void SetContext(Context _eNewContext)
sets the context of the dialog and trigger necessary actions e.g.
static bool GetDisplayNames(const SvBaseLink *, OUString *pType, OUString *pFile=nullptr, OUString *pLink=nullptr, OUString *pFilter=nullptr)
Definition: linkmgr2.cxx:218
static SotClipboardFormatId RegisterStatusInfoId()
Definition: linkmgr2.cxx:497
void DataChanged(const OUString &rMimeType, const css::uno::Any &rVal)
Definition: linksrc.cxx:308
void AddDataAdvise(SvBaseLink *, const OUString &rMimeType, sal_uInt16 nAdviceMode)
Definition: linksrc.cxx:342
StreamToLoadFrom getStreamToLoadFrom()
Definition: linksrc.cxx:205
void SetUpdateTimeout(sal_uInt64 nTimeMs)
Definition: linksrc.cxx:237
bool HasDataLinks() const
Definition: linksrc.cxx:377
bool is() const
static constexpr OUStringLiteral PROP_URL
sal_Int32 nState
#define ERRCODE_NONE
IMPL_LINK(SvFileObject, DialogClosedHdl, sfx2::FileDialogHelper *, _pFileDlg, void)
Definition: fileobj.cxx:358
IMPL_LINK_NOARG(SvFileObject, LoadGrfReady_Impl, void *, void)
Definition: fileobj.cxx:322
static OUString impl_getFilter(const OUString &_rURL)
detect the filter of the given file
Definition: fileobj.cxx:201
SvFileObjectType
Definition: fileobj.cxx:44
SotClipboardFormatId
SvBaseLink * pLink
Definition: lnkbase2.cxx:81
#define SAL_WARN(area, stream)
const sal_Unicode cTokenSeparator
Definition: linkmgr.hxx:172
QPRO_FUNC_TYPE nType
OUString SfxResId(TranslateId aId)
Definition: sfxresid.cxx:22