merge the formfield patch from ooo-build
[ooovba.git] / svx / source / svxlink / fileobj.cxx
bloba77c8852bb55f8f9dbff2a315e4855fb5bffe79d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: fileobj.cxx,v $
10 * $Revision: 1.24 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include <vcl/wrkwin.hxx>
34 #include <vcl/msgbox.hxx>
35 #include <tools/urlobj.hxx>
36 #include <tools/stream.hxx>
37 #include <sot/formats.hxx>
38 #include <svtools/filter.hxx>
39 #include <sfx2/lnkbase.hxx>
40 #include <sfx2/app.hxx>
41 #include <sfx2/progress.hxx>
42 #ifndef _SFX_INTERNO_HXX
43 //#include <sfx2/interno.hxx>
44 #endif
45 #include <sfx2/docfilt.hxx>
46 #include <sfx2/filedlghelper.hxx>
47 #include <sot/exchange.hxx>
48 #include <com/sun/star/uno/Any.hxx>
49 #include <com/sun/star/uno/Sequence.hxx>
50 #include <sfx2/docfac.hxx>
51 #include <com/sun/star/document/XTypeDetection.hpp>
52 #include <comphelper/mediadescriptor.hxx>
53 #include <comphelper/processfactory.hxx>
55 #include "fileobj.hxx"
56 #include "linkmgr.hxx"
57 #include <svx/dialmgr.hxx>
58 #include <svx/dialogs.hrc>
59 #include "xoutbmp.hxx"
60 #include "opengrf.hxx"
61 #include "impgrf.hxx"
63 namespace css = ::com::sun::star;
65 #define FILETYPE_TEXT 1
66 #define FILETYPE_GRF 2
67 #define FILETYPE_OBJECT 3
69 struct Impl_DownLoadData
71 Graphic aGrf;
72 Timer aTimer;
74 Impl_DownLoadData( const Link& rLink )
76 aTimer.SetTimeout( 100 );
77 aTimer.SetTimeoutHdl( rLink );
78 aGrf.SetDefaultType();
80 ~Impl_DownLoadData()
82 aTimer.Stop();
86 // --------------------------------------------------------------------------
89 SvFileObject::SvFileObject() :
90 pDownLoadData( NULL ), pOldParent( NULL ), nType( FILETYPE_TEXT )
92 bLoadAgain = TRUE;
93 bSynchron = bLoadError = bWaitForData = bDataReady = bNativFormat =
94 bClearMedium = bStateChangeCalled = bInCallDownLoad = FALSE;
98 SvFileObject::~SvFileObject()
100 if ( xMed.Is() )
102 xMed->SetDataAvailableLink( Link() );
103 xMed->SetDoneLink( Link() );
104 xMed.Clear();
106 delete pDownLoadData;
110 BOOL SvFileObject::GetData( ::com::sun::star::uno::Any & rData,
111 const String & rMimeType,
112 BOOL bGetSynchron )
114 ULONG nFmt = SotExchange::GetFormatStringId( rMimeType );
115 switch( nType )
117 case FILETYPE_TEXT:
118 if( FORMAT_FILE == nFmt )
120 // das Medium muss in der Applikation geoffnet werden, um die
121 // relativen Datei Links aufzuloesen!!!! Wird ueber den
122 // LinkManager und damit von dessen Storage erledigt.
123 rData <<= rtl::OUString( sFileNm );
125 break;
127 case FILETYPE_GRF:
128 if( !bLoadError )
130 SfxMediumRef xTmpMed;
132 if( FORMAT_GDIMETAFILE == nFmt || FORMAT_BITMAP == nFmt ||
133 SOT_FORMATSTR_ID_SVXB == nFmt )
135 Graphic aGrf;
137 //JP 15.07.98: Bug 52959
138 // falls das Nativformat doch erwuenscht ist, muss am
139 // Ende das Flag zurueckgesetzt werden.
140 // wird einzig und allein im sw/ndgrf.cxx benutzt, wenn der Link vom
141 // GraphicNode entfernt wird.
142 BOOL bOldNativFormat = bNativFormat;
143 //!!?? bNativFormat = 0 != (ASPECT_ICON & pSvData->GetAspect());
145 // falls gedruckt werden soll, warten wir bis die
146 // Daten vorhanden sind
147 if( bGetSynchron )
149 // testhalber mal ein LoadFile rufen um das nach-
150 // laden ueberahaupt anzustossen
151 if( !xMed.Is() )
152 LoadFile_Impl();
154 if( !bInCallDownLoad )
156 xTmpMed = xMed;
157 while( bWaitForData )
158 Application::Reschedule();
160 xMed = xTmpMed;
161 bClearMedium = TRUE;
165 if( pDownLoadData ||
166 ( !bWaitForData && ( xMed.Is() || // wurde als URL geladen
167 ( bSynchron && LoadFile_Impl() && xMed.Is() ) )) )
169 // falls
171 // falls es uebers Internet gesogen wurde, nicht
172 // wieder versuchen
173 if( !bGetSynchron )
174 bLoadAgain = !xMed->IsRemote();
175 bLoadError = !GetGraphic_Impl( aGrf, xMed->GetInStream() );
177 else if( !LoadFile_Impl() ||
178 !GetGraphic_Impl( aGrf, xMed.Is() ? xMed->GetInStream() : 0 ))
180 if( !xMed.Is() )
181 break;
182 aGrf.SetDefaultType();
185 if( SOT_FORMATSTR_ID_SVXB != nFmt )
186 nFmt = (bLoadError || GRAPHIC_BITMAP == aGrf.GetType())
187 ? FORMAT_BITMAP
188 : FORMAT_GDIMETAFILE;
190 SvMemoryStream aMemStm( 0, 65535 );
191 switch ( nFmt )
193 case SOT_FORMATSTR_ID_SVXB:
194 if( GRAPHIC_NONE != aGrf.GetType() )
196 aMemStm.SetVersion( SOFFICE_FILEFORMAT_50 );
197 aMemStm << aGrf;
199 break;
201 case FORMAT_BITMAP:
202 if( !aGrf.GetBitmap().IsEmpty())
203 aMemStm << aGrf.GetBitmap();
204 break;
206 default:
207 if( aGrf.GetGDIMetaFile().GetActionCount() )
209 GDIMetaFile aMeta( aGrf.GetGDIMetaFile() );
210 aMeta.Write( aMemStm );
213 rData <<= css::uno::Sequence< sal_Int8 >( (sal_Int8*) aMemStm.GetData(),
214 aMemStm.Seek( STREAM_SEEK_TO_END ) );
216 bNativFormat = bOldNativFormat;
218 // alles fertig?
219 if( xMed.Is() && !bSynchron && bClearMedium )
221 xMed.Clear();
222 bClearMedium = FALSE;
226 break;
227 case FILETYPE_OBJECT:
228 // TODO/LATER: possibility to insert a new object
229 rData <<= rtl::OUString( sFileNm );
230 break;
232 return sal_True/*0 != aTypeList.Count()*/;
238 BOOL SvFileObject::Connect( sfx2::SvBaseLink* pLink )
240 if( !pLink || !pLink->GetLinkManager() )
241 return FALSE;
243 // teste doch mal, ob nicht ein anderer Link mit der gleichen
244 // Verbindung schon existiert
245 pLink->GetLinkManager()->GetDisplayNames( pLink, 0, &sFileNm, 0, &sFilter );
247 if( OBJECT_CLIENT_GRF == pLink->GetObjType() )
249 SfxObjectShellRef pShell = pLink->GetLinkManager()->GetPersist();
250 if( pShell.Is() )
252 if( pShell->IsAbortingImport() )
253 return FALSE;
255 if( pShell->GetMedium() )
256 sReferer = pShell->GetMedium()->GetName();
260 switch( pLink->GetObjType() )
262 case OBJECT_CLIENT_GRF:
263 nType = FILETYPE_GRF;
264 bSynchron = pLink->IsSynchron();
265 break;
267 case OBJECT_CLIENT_FILE:
268 nType = FILETYPE_TEXT;
269 break;
271 case OBJECT_CLIENT_OLE:
272 nType = FILETYPE_OBJECT;
273 // TODO/LATER: introduce own type to be used for exchanging
274 break;
276 default:
277 return FALSE;
280 SetUpdateTimeout( 0 );
282 // und jetzt bei diesem oder gefundenem Pseudo-Object anmelden
283 AddDataAdvise( pLink, SotExchange::GetFormatMimeType( pLink->GetContentType()), 0 );
284 return TRUE;
288 BOOL SvFileObject::LoadFile_Impl()
290 // wir sind noch im Laden!!
291 if( bWaitForData || !bLoadAgain || xMed.Is() || pDownLoadData )
292 return FALSE;
294 // z.Z. nur auf die aktuelle DocShell
295 xMed = new SfxMedium( sFileNm, STREAM_STD_READ, TRUE );
296 SvLinkSource::StreamToLoadFrom aStreamToLoadFrom =
297 getStreamToLoadFrom();
298 xMed->setStreamToLoadFrom(
299 aStreamToLoadFrom.m_xInputStreamToLoadFrom,
300 aStreamToLoadFrom.m_bIsReadOnly);
301 // setStreamToLoadFrom(0,0);
302 // Keinen Eintrag im Roter Button Menu
303 xMed->SetDontCreateCancellable();
304 if( sReferer.Len() )
305 xMed->SetReferer( sReferer );
307 if( !bSynchron )
309 bLoadAgain = bDataReady = bInNewData = FALSE;
310 bWaitForData = TRUE;
312 SfxMediumRef xTmpMed = xMed;
313 xMed->SetDataAvailableLink( STATIC_LINK( this, SvFileObject, LoadGrfNewData_Impl ) );
314 bInCallDownLoad = TRUE;
315 xMed->DownLoad( STATIC_LINK( this, SvFileObject, LoadGrfReady_Impl ) );
316 bInCallDownLoad = FALSE;
318 bClearMedium = !xMed.Is();
319 if( bClearMedium )
320 xMed = xTmpMed; // falls gleich im DownLoad schon schluss ist
321 return bDataReady;
324 bWaitForData = TRUE;
325 bDataReady = bInNewData = FALSE;
326 xMed->DownLoad();
327 bLoadAgain = !xMed->IsRemote();
328 bWaitForData = FALSE;
330 // Grafik ist fertig, also DataChanged von der Statusaederung schicken:
331 SendStateChg_Impl( xMed->GetInStream() && xMed->GetInStream()->GetError()
332 ? STATE_LOAD_ERROR : STATE_LOAD_OK );
334 return TRUE;
338 BOOL SvFileObject::GetGraphic_Impl( Graphic& rGrf, SvStream* pStream )
340 GraphicFilter* pGF = GetGrfFilter();
342 const USHORT nFilter = sFilter.Len() && pGF->GetImportFormatCount()
343 ? pGF->GetImportFormatNumber( sFilter )
344 : GRFILTER_FORMAT_DONTKNOW;
346 String aEmptyStr;
347 int nRes;
349 // vermeiden, dass ein native Link angelegt wird
350 if( ( !pStream || !pDownLoadData ) && !rGrf.IsLink() &&
351 !rGrf.GetContext() && !bNativFormat )
352 rGrf.SetLink( GfxLink() );
354 if( !pStream )
355 nRes = xMed.Is() ? GRFILTER_OPENERROR
356 : pGF->ImportGraphic( rGrf, INetURLObject(sFileNm),
357 nFilter );
358 else if( !pDownLoadData )
360 pStream->Seek( STREAM_SEEK_TO_BEGIN );
361 nRes = pGF->ImportGraphic( rGrf, aEmptyStr, *pStream, nFilter );
363 else
365 nRes = pGF->ImportGraphic( pDownLoadData->aGrf, aEmptyStr,
366 *pStream, nFilter );
368 if( pDownLoadData )
370 rGrf = pDownLoadData->aGrf;
371 if( GRAPHIC_NONE == rGrf.GetType() )
372 rGrf.SetDefaultType();
375 if( !pDownLoadData->aGrf.GetContext() )
377 xMed->SetDataAvailableLink( Link() );
378 // xMed->SetDoneLink( Link() );
379 delete pDownLoadData, pDownLoadData = 0;
380 bDataReady = TRUE;
381 bWaitForData = FALSE;
383 else if( FALSE )
385 // Timer aufsetzen, um zurueck zukehren
386 pDownLoadData->aTimer.Start();
391 if( pStream && ERRCODE_IO_PENDING == pStream->GetError() )
392 pStream->ResetError();
394 #ifndef PRODUCT
395 if( nRes )
397 if( xMed.Is() && !pStream )
399 DBG_WARNING3( "GrafikFehler [%d] - [%s] URL[%s]",
400 nRes,
401 xMed->GetPhysicalName().GetBuffer(),
402 sFileNm.GetBuffer() );
404 else
406 DBG_WARNING2( "GrafikFehler [%d] - [%s]",
407 nRes, sFileNm.GetBuffer() );
410 #endif
412 return GRFILTER_OK == nRes;
415 /** detect the filter of the given file
417 @param _rURL
418 specifies the URL of the file which filter is to detected.<br/>
419 If the URL doesn't denote a valid (existent and accessible) file, the
420 request is silently dropped.
422 String impl_getFilter( const String& _rURL )
424 String sFilter;
425 if ( _rURL.Len() == 0 )
426 return sFilter;
430 css::uno::Reference< ::com::sun::star::document::XTypeDetection > xTypeDetection(
431 ::comphelper::getProcessServiceFactory()->createInstance(
432 ::rtl::OUString::createFromAscii("com.sun.star.document.TypeDetection") ),
433 css::uno::UNO_QUERY );
434 if ( xTypeDetection.is() )
436 ::comphelper::MediaDescriptor aDescr;
437 aDescr[ ::comphelper::MediaDescriptor::PROP_URL() ] <<= ::rtl::OUString( _rURL );
438 css::uno::Sequence< css::beans::PropertyValue > aDescrList =
439 aDescr.getAsConstPropertyValueList();
440 ::rtl::OUString sType = xTypeDetection->queryTypeByDescriptor( aDescrList, sal_True );
441 if ( sType.getLength() )
443 css::uno::Reference< css::container::XNameAccess > xTypeCont( xTypeDetection,
444 css::uno::UNO_QUERY );
445 if ( xTypeCont.is() )
447 ::comphelper::SequenceAsHashMap lTypeProps( xTypeCont->getByName( sType ) );
448 sFilter = lTypeProps.getUnpackedValueOrDefault(
449 ::rtl::OUString::createFromAscii("PreferredFilter"), ::rtl::OUString() );
454 catch( const css::uno::Exception& )
458 return sFilter;
461 void SvFileObject::Edit( Window* pParent, sfx2::SvBaseLink* pLink, const Link& rEndEditHdl )
463 aEndEditLink = rEndEditHdl;
464 String sFile, sRange, sTmpFilter;
465 if( pLink && pLink->GetLinkManager() )
467 pLink->GetLinkManager()->GetDisplayNames( pLink, 0, &sFile, &sRange, &sTmpFilter );
469 switch( pLink->GetObjType() )
471 case OBJECT_CLIENT_GRF:
473 nType = FILETYPE_GRF; // falls noch nicht gesetzt
475 SvxOpenGraphicDialog aDlg(ResId(RID_SVXSTR_EDITGRFLINK, DIALOG_MGR()));
476 aDlg.EnableLink(sal_False);
477 aDlg.SetPath( sFile, sal_True );
478 aDlg.SetCurrentFilter( sTmpFilter );
480 if( !aDlg.Execute() )
482 sFile = aDlg.GetPath();
483 sFile += ::sfx2::cTokenSeperator;
484 sFile += ::sfx2::cTokenSeperator;
485 sFile += aDlg.GetCurrentFilter();
487 if ( aEndEditLink.IsSet() )
488 aEndEditLink.Call( &sFile );
490 else
491 sFile.Erase();
493 break;
495 case OBJECT_CLIENT_OLE:
497 nType = FILETYPE_OBJECT; // if not set already
498 pOldParent = Application::GetDefDialogParent();
499 Application::SetDefDialogParent( pParent );
501 ::sfx2::FileDialogHelper* pFileDlg =
502 pLink->GetFileDialog( (SFXWB_INSERT | WB_3DLOOK), String() );
503 pFileDlg->StartExecuteModal( LINK( this, SvFileObject, DialogClosedHdl ) );
505 break;
507 case OBJECT_CLIENT_FILE:
509 nType = FILETYPE_TEXT; // if not set already
510 pOldParent = Application::GetDefDialogParent();
511 Application::SetDefDialogParent( pParent );
513 String sFactory;
514 SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
515 if ( pShell )
516 sFactory = pShell->GetFactory().GetFactoryName();
518 ::sfx2::FileDialogHelper* pFileDlg =
519 pLink->GetFileDialog( (SFXWB_INSERT | WB_3DLOOK), sFactory );
520 pFileDlg->StartExecuteModal( LINK( this, SvFileObject, DialogClosedHdl ) );
522 break;
524 default:
525 sFile.Erase();
530 IMPL_STATIC_LINK( SvFileObject, LoadGrfReady_Impl, void*, EMPTYARG )
532 // wenn wir von hier kommen, kann es kein Fehler mehr sein
533 pThis->bLoadError = FALSE;
534 pThis->bWaitForData = FALSE;
535 pThis->bInCallDownLoad = FALSE;
537 if( !pThis->bInNewData && !pThis->bDataReady )
539 // Grafik ist fertig, also DataChanged von der Status-
540 // aederung schicken:
541 pThis->bDataReady = TRUE;
542 pThis->SendStateChg_Impl( STATE_LOAD_OK );
544 // und dann nochmal die Daten senden
545 pThis->NotifyDataChanged();
548 if( pThis->bDataReady )
550 pThis->bLoadAgain = TRUE;
551 if( pThis->xMed.Is() )
553 pThis->xMed->SetDataAvailableLink( Link() );
554 pThis->xMed->SetDoneLink( Link() );
556 Application::PostUserEvent(
557 STATIC_LINK( pThis, SvFileObject, DelMedium_Impl ),
558 new SfxMediumRef( pThis->xMed ));
559 pThis->xMed.Clear();
561 if( pThis->pDownLoadData )
562 delete pThis->pDownLoadData, pThis->pDownLoadData = 0;
565 return 0;
568 IMPL_STATIC_LINK( SvFileObject, DelMedium_Impl, SfxMediumRef*, pDelMed )
570 (void)pThis;
571 delete pDelMed;
572 return 0;
575 IMPL_STATIC_LINK( SvFileObject, LoadGrfNewData_Impl, void*, EMPTYARG )
577 // wenn wir von hier kommen, kann es kein Fehler mehr sein
578 if( pThis->bInNewData )
579 return 0;
581 pThis->bInNewData = TRUE;
582 pThis->bLoadError = FALSE;
584 if( !pThis->pDownLoadData )
586 pThis->pDownLoadData = new Impl_DownLoadData(
587 STATIC_LINK( pThis, SvFileObject, LoadGrfNewData_Impl ) );
589 // Null-Link setzen, damit keine temporaeren Grafiken
590 // rausgeswapt werden; der Filter prueft, ob schon
591 // ein Link gesetzt ist => falls dies zutrifft, wird
592 // _kein_ neuer Link gesetzt; der Link muss hier gesetzt werden,
593 // (bevor das erste Mal gefiltert wird), um zu verhindern,
594 // dass der Kontext zurueckgesetzt wird (aynchrones Laden)
595 if( !pThis->bNativFormat )
597 static GfxLink aDummyLink;
598 pThis->pDownLoadData->aGrf.SetLink( aDummyLink );
602 pThis->NotifyDataChanged();
604 SvStream* pStrm = pThis->xMed.Is() ? pThis->xMed->GetInStream() : 0;
605 if( pStrm && pStrm->GetError() )
607 if( ERRCODE_IO_PENDING == pStrm->GetError() )
608 pStrm->ResetError();
610 // im DataChanged ein DataReady?
611 else if( pThis->bWaitForData && pThis->pDownLoadData )
613 pThis->bLoadError = TRUE;
617 if( pThis->bDataReady )
619 // Grafik ist fertig, also DataChanged von der Status-
620 // aederung schicken:
621 pThis->SendStateChg_Impl( pStrm->GetError() ? STATE_LOAD_ERROR
622 : STATE_LOAD_OK );
625 pThis->bInNewData = FALSE;
626 return 0;
629 IMPL_LINK( SvFileObject, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg )
631 String sFile;
632 Application::SetDefDialogParent( pOldParent );
634 if ( FILETYPE_TEXT == nType || FILETYPE_OBJECT == nType )
636 if ( _pFileDlg && _pFileDlg->GetError() == ERRCODE_NONE )
638 String sURL( _pFileDlg->GetPath() );
639 sFile = sURL;
640 sFile += ::sfx2::cTokenSeperator;
641 sFile += ::sfx2::cTokenSeperator;
642 sFile += impl_getFilter( sURL );
645 else
647 DBG_ERRORFILE( "SvFileObject::DialogClosedHdl(): wrong file type" );
650 if ( aEndEditLink.IsSet() )
651 aEndEditLink.Call( &sFile );
652 return 0;
655 /* [Beschreibung]
657 Die Methode stellt fest, ob aus einem DDE-Object die Daten gelesen
658 werden kann.
659 Zurueckgegeben wird:
660 ERRCODE_NONE wenn sie komplett gelesen wurde
661 ERRCODE_SO_PENDING wenn sie noch nicht komplett gelesen wurde
662 ERRCODE_SO_FALSE sonst
664 BOOL SvFileObject::IsPending() const
666 return FILETYPE_GRF == nType && !bLoadError &&
667 ( pDownLoadData || bWaitForData );
669 BOOL SvFileObject::IsDataComplete() const
671 BOOL bRet = FALSE;
672 if( FILETYPE_GRF != nType )
673 bRet = TRUE;
674 else if( !bLoadError && ( !bWaitForData && !pDownLoadData ))
676 SvFileObject* pThis = (SvFileObject*)this;
677 if( bDataReady ||
678 ( bSynchron && pThis->LoadFile_Impl() && xMed.Is() ) )
679 bRet = TRUE;
680 else
682 INetURLObject aUrl( sFileNm );
683 if( aUrl.HasError() ||
684 INET_PROT_NOT_VALID == aUrl.GetProtocol() )
685 bRet = TRUE;
688 return bRet;
693 void SvFileObject::CancelTransfers()
695 if( xMed.Is() )
696 xMed->CancelTransfers();
698 // und aus dem Cache austragen, wenn man mitten im Laden ist
699 if( !bDataReady )
701 // nicht noch mal aufsetzen
702 bLoadAgain = FALSE;
703 bDataReady = bLoadError = bWaitForData = TRUE;
704 SendStateChg_Impl( STATE_LOAD_ABORT );
709 void SvFileObject::SetTransferPriority( USHORT )
714 void SvFileObject::SendStateChg_Impl( LinkState nState )
716 if( !bStateChangeCalled && HasDataLinks() )
718 css::uno::Any aAny;
719 aAny <<= rtl::OUString::valueOf( (sal_Int32)nState );
720 DataChanged( SotExchange::GetFormatName(
721 SvxLinkManager::RegisterStatusInfoId()), aAny );
722 bStateChangeCalled = TRUE;