xref: /trunk/main/sw/source/core/graphic/ndgrf.cxx (revision e1d5bd03a6ea7ac2b26b792c9e2a94e9f347a43b)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 #include <hintids.hxx>
27 #include <vcl/salbtype.hxx>             // FRound
28 #include <tools/urlobj.hxx>
29 #include <svl/undo.hxx>
30 #ifndef SVTOOLS_FSTATHELPER_HXX
31 #include <svl/fstathelper.hxx>
32 #endif
33 #include <svtools/imap.hxx>
34 #include <svtools/filter.hxx>
35 #include <sot/storage.hxx>
36 #include <sfx2/linkmgr.hxx>
37 #include <editeng/boxitem.hxx>
38 #include <sot/formats.hxx>
39 #include <fmtfsize.hxx>
40 #include <fmturl.hxx>
41 #include <frmfmt.hxx>
42 #include <doc.hxx>
43 #include <frmatr.hxx>
44 #include <grfatr.hxx>
45 #include <swtypes.hxx>
46 #include <ndgrf.hxx>
47 #include <fmtcol.hxx>
48 #include <hints.hxx>
49 #include <swbaslnk.hxx>
50 #include <pagefrm.hxx>
51 #include <editsh.hxx>
52 #include <pam.hxx>
53 
54 #include <unotools/ucbstreamhelper.hxx>
55 #include <com/sun/star/embed/ElementModes.hpp>
56 #include <com/sun/star/embed/XTransactedObject.hpp>
57 #include <tools/link.hxx>
58 #include <vcl/svapp.hxx>
59 #include <com/sun/star/io/XSeekable.hpp>
60 // --> OD 2007-03-28 #i73788#
61 #include <retrieveinputstreamconsumer.hxx>
62 // <--
63 
64 using namespace com::sun::star;
65 
66 // --------------------
67 // SwGrfNode
68 // --------------------
69 SwGrfNode::SwGrfNode(
70         const SwNodeIndex & rWhere,
71         const String& rGrfName, const String& rFltName,
72         const Graphic* pGraphic,
73         SwGrfFmtColl *pGrfColl,
74         SwAttrSet* pAutoAttr ) :
75     SwNoTxtNode( rWhere, ND_GRFNODE, pGrfColl, pAutoAttr ),
76     // --> OD 2007-01-23 #i73788#
77     mbLinkedInputStreamReady( false ),
78     mbIsStreamReadOnly( sal_False )
79     // <--
80 {
81     aGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ) );
82     bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel = bLoadLowResGrf =
83         bFrameInPaint = bScaleImageMap = sal_False;
84 
85     bGrafikArrived = sal_True;
86     ReRead(rGrfName,rFltName, pGraphic, 0, sal_False);
87 }
88 
89 SwGrfNode::SwGrfNode( const SwNodeIndex & rWhere,
90                         const GraphicObject& rGrfObj,
91                       SwGrfFmtColl *pGrfColl, SwAttrSet* pAutoAttr ) :
92     SwNoTxtNode( rWhere, ND_GRFNODE, pGrfColl, pAutoAttr ),
93     // --> OD 2007-01-23 #i73788#
94     mbLinkedInputStreamReady( false ),
95     mbIsStreamReadOnly( sal_False )
96     // <--
97 {
98     aGrfObj = rGrfObj;
99     aGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ) );
100     if( rGrfObj.HasUserData() && rGrfObj.IsSwappedOut() )
101         aGrfObj.SetSwapState();
102     bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel= bLoadLowResGrf =
103         bFrameInPaint = bScaleImageMap = sal_False;
104     bGrafikArrived = sal_True;
105 }
106 
107 // Konstruktor fuer den SW/G-Reader. Dieser ctor wird verwendet,
108 // wenn eine gelinkte Grafik gelesen wird. Sie liest diese NICHT ein.
109 
110 
111 SwGrfNode::SwGrfNode( const SwNodeIndex & rWhere,
112                       const String& rGrfName, const String& rFltName,
113                       SwGrfFmtColl *pGrfColl,
114                       SwAttrSet* pAutoAttr ) :
115     SwNoTxtNode( rWhere, ND_GRFNODE, pGrfColl, pAutoAttr ),
116     // --> OD 2007-01-23 #i73788#
117     mbLinkedInputStreamReady( false ),
118     mbIsStreamReadOnly( sal_False )
119     // <--
120 {
121     aGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ) );
122 
123     Graphic aGrf; aGrf.SetDefaultType();
124     aGrfObj.SetGraphic( aGrf, rGrfName );
125 
126     bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel = bLoadLowResGrf =
127         bFrameInPaint = bScaleImageMap = sal_False;
128     bGrafikArrived = sal_True;
129 
130     InsertLink( rGrfName, rFltName );
131     if( IsLinkedFile() )
132     {
133         INetURLObject aUrl( rGrfName );
134         if( INET_PROT_FILE == aUrl.GetProtocol() &&
135             FStatHelper::IsDocument( aUrl.GetMainURL( INetURLObject::NO_DECODE ) ))
136         {
137             // File vorhanden, Verbindung herstellen ohne ein Update
138             ((SwBaseLink*)&refLink)->Connect();
139         }
140     }
141 }
142 
143 sal_Bool SwGrfNode::ReRead(
144     const String& rGrfName, const String& rFltName,
145     const Graphic* pGraphic, const GraphicObject* pGrfObj,
146     sal_Bool bNewGrf )
147 {
148     sal_Bool bReadGrf = sal_False, bSetTwipSize = sal_True;
149 
150     ASSERT( pGraphic || pGrfObj || rGrfName.Len(),
151             "GraphicNode without a name, Graphic or GraphicObject" );
152 
153     // ReadRead mit Namen
154     if( refLink.Is() )
155     {
156         ASSERT( !bInSwapIn, "ReRead: stehe noch im SwapIn" );
157 
158         if( rGrfName.Len() )
159         {
160             // Besonderheit: steht im FltNamen DDE, handelt es sich um eine
161             //                  DDE-gelinkte Grafik
162             String sCmd( rGrfName );
163             if( rFltName.Len() )
164             {
165                 sal_uInt16 nNewType;
166                 if( rFltName.EqualsAscii( "DDE" ))
167                     nNewType = OBJECT_CLIENT_DDE;
168                 else
169                 {
170                     sfx2::MakeLnkName( sCmd, 0, rGrfName, aEmptyStr, &rFltName );
171                     nNewType = OBJECT_CLIENT_GRF;
172                 }
173 
174                 if( nNewType != refLink->GetObjType() )
175                 {
176                     refLink->Disconnect();
177                     ((SwBaseLink*)&refLink)->SetObjType( nNewType );
178                 }
179             }
180 
181             refLink->SetLinkSourceName( sCmd );
182         }
183         else        // kein Name mehr, Link aufheben
184         {
185             GetDoc()->GetLinkManager().Remove( refLink );
186             refLink.Clear();
187         }
188 
189         if( pGraphic )
190         {
191             aGrfObj.SetGraphic( *pGraphic, rGrfName );
192             bReadGrf = sal_True;
193         }
194         else if( pGrfObj )
195         {
196             aGrfObj = *pGrfObj;
197             if( pGrfObj->HasUserData() && pGrfObj->IsSwappedOut() )
198                 aGrfObj.SetSwapState();
199             aGrfObj.SetLink( rGrfName );
200             bReadGrf = sal_True;
201         }
202         else
203         {
204             // MIB 25.02.97: Daten der alten Grafik zuruecksetzen, damit
205             // die korrekte Ersatz-Darstellung erscheint, wenn die
206             // der neue Link nicht geladen werden konnte.
207             Graphic aGrf; aGrf.SetDefaultType();
208             aGrfObj.SetGraphic( aGrf, rGrfName );
209 
210             if( refLink.Is() )
211             {
212                 if( getLayoutFrm( GetDoc()->GetCurrentLayout() ) )
213                 {
214                     SwMsgPoolItem aMsgHint( RES_GRF_REREAD_AND_INCACHE );
215                     ModifyNotification( &aMsgHint, &aMsgHint );
216                 }
217                 // --> OD 2006-11-03 #i59688#
218                 // do not load linked graphic, if it isn't a new linked graphic.
219 //                else {
220                 else if ( bNewGrf )
221                 // <--
222                 {
223                     //TODO refLink->setInputStream(getInputStream());
224                     ((SwBaseLink*)&refLink)->SwapIn();
225                 }
226             }
227             bSetTwipSize = sal_False;
228         }
229     }
230     else if( pGraphic && !rGrfName.Len() )
231     {
232         // MIB 27.02.2001: Old stream must be deleted before the new one is set.
233         if( HasStreamName() )
234             DelStreamName();
235 
236         aGrfObj.SetGraphic( *pGraphic );
237         bReadGrf = sal_True;
238     }
239     else if( pGrfObj && !rGrfName.Len() )
240     {
241         // MIB 27.02.2001: Old stream must be deleted before the new one is set.
242         if( HasStreamName() )
243             DelStreamName();
244 
245         aGrfObj = *pGrfObj;
246         if( pGrfObj->HasUserData() && pGrfObj->IsSwappedOut() )
247             aGrfObj.SetSwapState();
248         bReadGrf = sal_True;
249     }
250         // Import einer Grafik:
251         // Ist die Grafik bereits geladen?
252     else if( !bNewGrf && GRAPHIC_NONE != aGrfObj.GetType() )
253         return sal_True;
254 
255     else
256     {
257         if( HasStreamName() )
258             DelStreamName();
259 
260         // einen neuen Grafik-Link anlegen
261         InsertLink( rGrfName, rFltName );
262 
263         if( GetNodes().IsDocNodes() )
264         {
265             if( pGraphic )
266             {
267                 aGrfObj.SetGraphic( *pGraphic, rGrfName );
268                 bReadGrf = sal_True;
269                 // Verbindung herstellen ohne ein Update; Grafik haben wir!
270                 ((SwBaseLink*)&refLink)->Connect();
271             }
272             else if( pGrfObj )
273             {
274                 aGrfObj = *pGrfObj;
275                 aGrfObj.SetLink( rGrfName );
276                 bReadGrf = sal_True;
277                 // Verbindung herstellen ohne ein Update; Grafik haben wir!
278                 ((SwBaseLink*)&refLink)->Connect();
279             }
280             else
281             {
282                 // MIB 25.02.97: Daten der alten Grafik zuruecksetzen, damit
283                 // die korrekte Ersatz-Darstellung erscheint, wenn die
284                 // der neue Kink nicht geladen werden konnte.
285                 Graphic aGrf; aGrf.SetDefaultType();
286                 aGrfObj.SetGraphic( aGrf, rGrfName );
287                 // --> OD 2006-11-03 #i59688#
288                 // do not load linked graphic, if it isn't a new linked graphic.
289 //                //TODO refLink->setInputStream(getInputStream());
290 //                ((SwBaseLink*)&refLink)->SwapIn();
291                 if ( bNewGrf )
292                 {
293                     ((SwBaseLink*)&refLink)->SwapIn();
294                 }
295                 // <--
296             }
297         }
298     }
299 
300     // Bug 39281: Size nicht sofort loeschen - Events auf ImageMaps
301     //            sollten nicht beim Austauschen nicht ins "leere greifen"
302     if( bSetTwipSize )
303         SetTwipSize( ::GetGraphicSizeTwip( aGrfObj.GetGraphic(), 0 ) );
304 
305     // erzeuge noch einen Update auf die Frames
306     if( bReadGrf && bNewGrf )
307     {
308         SwMsgPoolItem aMsgHint( RES_UPDATE_ATTR );
309         ModifyNotification( &aMsgHint, &aMsgHint );
310     }
311 
312     return bReadGrf;
313 }
314 
315 
316 SwGrfNode::~SwGrfNode()
317 {
318     // --> OD 2007-03-30 #i73788#
319     mpThreadConsumer.reset();
320     // <--
321 
322     SwDoc* pDoc = GetDoc();
323     if( refLink.Is() )
324     {
325         ASSERT( !bInSwapIn, "DTOR: stehe noch im SwapIn" );
326         pDoc->GetLinkManager().Remove( refLink );
327         refLink->Disconnect();
328     }
329     else
330     {
331         // --> OD 2005-01-19 #i40014# - A graphic node, which are in linked
332         // section, whose link is another section is the document, doesn't
333         // have to remove the stream from the storage.
334         // Because it's hard to detect this case here and it would only fix
335         // one problem with shared graphic files - there are also problems,
336         // a certain graphic file is referenced by two independent graphic nodes,
337         // brush item or drawing objects, the stream isn't no longer removed here.
338         // To do this stuff correct, a reference counting on shared streams
339         // inside one document have to be implemented.
340 //        if( !pDoc->IsInDtor() && HasStreamName() )
341 //          DelStreamName();
342         // <--
343     }
344     //#39289# Die Frames muessen hier bereits geloescht weil der DTor der
345     //Frms die Grafik noch fuer StopAnimation braucht.
346     if( GetDepends() )
347         DelFrms();
348 }
349 
350 
351 SwCntntNode *SwGrfNode::SplitCntntNode( const SwPosition & )
352 {
353     return this;
354 }
355 
356 
357 SwGrfNode * SwNodes::MakeGrfNode( const SwNodeIndex & rWhere,
358                                 const String& rGrfName,
359                                 const String& rFltName,
360                                 const Graphic* pGraphic,
361                                 SwGrfFmtColl* pGrfColl,
362                                 SwAttrSet* pAutoAttr,
363                                 sal_Bool bDelayed )
364 {
365     ASSERT( pGrfColl, "MakeGrfNode: Formatpointer ist 0." );
366     SwGrfNode *pNode;
367     // Delayed erzeugen nur aus dem SW/G-Reader
368     if( bDelayed )
369         pNode = new SwGrfNode( rWhere, rGrfName,
370                                 rFltName, pGrfColl, pAutoAttr );
371     else
372         pNode = new SwGrfNode( rWhere, rGrfName,
373                                 rFltName, pGraphic, pGrfColl, pAutoAttr );
374     return pNode;
375 }
376 
377 SwGrfNode * SwNodes::MakeGrfNode( const SwNodeIndex & rWhere,
378                                 const GraphicObject& rGrfObj,
379                                 SwGrfFmtColl* pGrfColl,
380                                 SwAttrSet* pAutoAttr )
381 {
382     ASSERT( pGrfColl, "MakeGrfNode: Formatpointer ist 0." );
383     return new SwGrfNode( rWhere, rGrfObj, pGrfColl, pAutoAttr );
384 }
385 
386 
387 Size SwGrfNode::GetTwipSize() const
388 {
389     return nGrfSize;
390 }
391 
392 
393 
394 sal_Bool SwGrfNode::ImportGraphic( SvStream& rStrm )
395 {
396     Graphic aGraphic;
397     if( !GraphicFilter::GetGraphicFilter()->ImportGraphic( aGraphic, String(), rStrm ) )
398     {
399         const String aUserData( aGrfObj.GetUserData() );
400 
401         aGrfObj.SetGraphic( aGraphic );
402         aGrfObj.SetUserData( aUserData );
403         return sal_True;
404     }
405 
406     return sal_False;
407 }
408 
409 // Returnwert:
410 // -1 : ReRead erfolgreich
411 //  0 : nicht geladen
412 //  1 : Einlesen erfolgreich
413 
414 short SwGrfNode::SwapIn( sal_Bool bWaitForData )
415 {
416     if( bInSwapIn )                 // nicht rekuriv!!
417         return !aGrfObj.IsSwappedOut();
418 
419     short nRet = 0;
420     bInSwapIn = sal_True;
421     SwBaseLink* pLink = (SwBaseLink*)(::sfx2::SvBaseLink*) refLink;
422 
423     if( pLink )
424     {
425         if( GRAPHIC_NONE == aGrfObj.GetType() ||
426             GRAPHIC_DEFAULT == aGrfObj.GetType() )
427         {
428             // noch nicht geladener Link
429             //TODO pLink->setInputStream(getInputStream());
430             if( pLink->SwapIn( bWaitForData ) )
431                 nRet = -1;
432             else if( GRAPHIC_DEFAULT == aGrfObj.GetType() )
433             {
434                 // keine default Bitmap mehr, also neu Painten!
435                 aGrfObj.SetGraphic( Graphic() );
436                 SwMsgPoolItem aMsgHint( RES_GRAPHIC_PIECE_ARRIVED );
437                 ModifyNotification( &aMsgHint, &aMsgHint );
438             }
439         }
440         else if( aGrfObj.IsSwappedOut() ) {
441             // nachzuladender Link
442             //TODO pLink->setInputStream(getInputStream());
443             nRet = pLink->SwapIn( bWaitForData ) ? 1 : 0;
444         }
445         else
446             nRet = 1;
447     }
448     else if( aGrfObj.IsSwappedOut() )
449     {
450         // Die Grafik ist im Storage oder im TempFile drin
451         if( !HasStreamName() )
452             nRet = (short)aGrfObj.SwapIn();
453         else
454         {
455 
456             // --> OD 2005-05-04 #i48434# - usage of new method <_GetStreamForEmbedGrf(..)>
457             try
458             {
459                 // --> OD, MAV 2005-08-17 #i53025# - needed correction of new
460                 // method <_GetStreamForEmbedGrf(..)>
461 //                bool bGraphic(false);
462 //                SvStream* pStrm = _GetStreamForEmbedGrf( bGraphic );
463                 String aStrmName, aPicStgName;
464                 _GetStreamStorageNames( aStrmName, aPicStgName );
465                 uno::Reference < embed::XStorage > refPics = _GetDocSubstorageOrRoot( aPicStgName );
466                 SvStream* pStrm = _GetStreamForEmbedGrf( refPics, aStrmName );
467                 if ( pStrm )
468                 {
469                     if ( ImportGraphic( *pStrm ) )
470                         nRet = 1;
471                     delete pStrm;
472                 }
473                 // <--
474             }
475             catch ( uno::Exception& )
476             {
477                 // --> OD 2005-04-25 #i48434#
478                 ASSERT( false, "<SwGrfNode::SwapIn(..)> - unhandled exception!" );
479                 // <--
480             }
481             // <--
482         }
483 
484         if( 1 == nRet )
485         {
486             SwMsgPoolItem aMsg( RES_GRAPHIC_SWAPIN );
487             ModifyNotification( &aMsg, &aMsg );
488         }
489     }
490     else
491         nRet = 1;
492     DBG_ASSERTWARNING( nRet, "Grafik kann nicht eingeswapt werden" );
493 
494     if( nRet )
495     {
496         if( !nGrfSize.Width() && !nGrfSize.Height() )
497             SetTwipSize( ::GetGraphicSizeTwip( aGrfObj.GetGraphic(), 0 ) );
498     }
499     bInSwapIn = sal_False;
500     return nRet;
501 }
502 
503 
504 short SwGrfNode::SwapOut()
505 {
506     if( aGrfObj.GetType() != GRAPHIC_DEFAULT &&
507         aGrfObj.GetType() != GRAPHIC_NONE &&
508         !aGrfObj.IsSwappedOut() && !bInSwapIn )
509     {
510         if( !refLink.Is() )
511         {
512             // Das Swapping brauchen wir nur fuer Embedded Pictures
513             // Die Grafik wird in eine TempFile geschrieben, wenn
514             // sie frisch eingefuegt war, d.h. wenn es noch keinen
515             // Streamnamen im Storage gibt.
516             if( !HasStreamName() )
517                 if( !aGrfObj.SwapOut() )
518                     return 0;
519         }
520         // Geschriebene Grafiken oder Links werden jetzt weggeschmissen
521         return (short) aGrfObj.SwapOut( NULL );
522     }
523     return 1;
524 }
525 
526 
527 sal_Bool SwGrfNode::GetFileFilterNms( String* pFileNm, String* pFilterNm ) const
528 {
529     sal_Bool bRet = sal_False;
530     if( refLink.Is() && refLink->GetLinkManager() )
531     {
532         sal_uInt16 nType = refLink->GetObjType();
533         if( OBJECT_CLIENT_GRF == nType )
534             bRet = refLink->GetLinkManager()->GetDisplayNames(
535                     refLink, 0, pFileNm, 0, pFilterNm );
536         else if( OBJECT_CLIENT_DDE == nType && pFileNm && pFilterNm )
537         {
538             String sApp, sTopic, sItem;
539             if( refLink->GetLinkManager()->GetDisplayNames(
540                     refLink, &sApp, &sTopic, &sItem ) )
541             {
542                 ( *pFileNm = sApp ) += sfx2::cTokenSeperator;
543                 ( *pFileNm += sTopic ) += sfx2::cTokenSeperator;
544                 *pFileNm += sItem;
545                 pFilterNm->AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDE" ));
546                 bRet = sal_True;
547             }
548         }
549     }
550     return bRet;
551 }
552 
553 
554 // Eine Grafik Undo-faehig machen. Falls sie sich bereits in
555 // einem Storage befindet, muss sie geladen werden.
556 
557 sal_Bool SwGrfNode::SavePersistentData()
558 {
559     if( refLink.Is() )
560     {
561         ASSERT( !bInSwapIn, "SavePersistentData: stehe noch im SwapIn" );
562         GetDoc()->GetLinkManager().Remove( refLink );
563         return sal_True;
564     }
565 
566     // Erst mal reinswappen, falls sie im Storage ist
567     if( HasStreamName() && !SwapIn() )
568         return sal_False;
569 
570     // --> OD 2005-04-19 #i44367#
571     // Do not delete graphic file in storage, because the graphic file could
572     // be referenced by other graphic nodes.
573     // Because it's hard to detect this case here and it would only fix
574     // one problem with shared graphic files - there are also problems,
575     // a certain graphic file is referenced by two independent graphic nodes,
576     // brush item or drawing objects, the stream isn't no longer removed here.
577     // To do this stuff correct, a reference counting on shared streams
578     // inside one document have to be implemented.
579     // Important note: see also fix for #i40014#
580 //    if( HasStreamName() )
581 //        DelStreamName();
582     // <--
583 
584     // Und in TempFile rausswappen
585     return (sal_Bool) SwapOut();
586 }
587 
588 
589 sal_Bool SwGrfNode::RestorePersistentData()
590 {
591     if( refLink.Is() )
592     {
593         IDocumentLinksAdministration* pIDLA = getIDocumentLinksAdministration();
594         refLink->SetVisible( pIDLA->IsVisibleLinks() );
595         pIDLA->GetLinkManager().InsertDDELink( refLink );
596         if( getIDocumentLayoutAccess()->GetCurrentLayout() )    //swmod 080218
597             refLink->Update();
598     }
599     return sal_True;
600 }
601 
602 
603 void SwGrfNode::InsertLink( const String& rGrfName, const String& rFltName )
604 {
605     refLink = new SwBaseLink( sfx2::LINKUPDATE_ONCALL, FORMAT_GDIMETAFILE, this );
606 
607     IDocumentLinksAdministration* pIDLA = getIDocumentLinksAdministration();
608     if( GetNodes().IsDocNodes() )
609     {
610         refLink->SetVisible( pIDLA->IsVisibleLinks() );
611         if( rFltName.EqualsAscii( "DDE" ))
612         {
613             sal_uInt16 nTmp = 0;
614             String sApp, sTopic, sItem;
615             sApp = rGrfName.GetToken( 0, sfx2::cTokenSeperator, nTmp );
616             sTopic = rGrfName.GetToken( 0, sfx2::cTokenSeperator, nTmp );
617             sItem = rGrfName.Copy( nTmp );
618             pIDLA->GetLinkManager().InsertDDELink( refLink,
619                                             sApp, sTopic, sItem );
620         }
621         else
622         {
623             sal_Bool bSync = rFltName.EqualsAscii( "SYNCHRON" );
624             refLink->SetSynchron( bSync );
625             refLink->SetContentType( SOT_FORMATSTR_ID_SVXB );
626 
627             pIDLA->GetLinkManager().InsertFileLink( *refLink,
628                                             OBJECT_CLIENT_GRF, rGrfName,
629                                 (!bSync && rFltName.Len() ? &rFltName : 0) );
630         }
631     }
632     aGrfObj.SetLink( rGrfName );
633 }
634 
635 
636 void SwGrfNode::ReleaseLink()
637 {
638     if( refLink.Is() )
639     {
640         // erst die Grafik reinswappen!
641 //      if( aGraphic.IsSwapOut() || !refLink->IsSynchron() )
642         {
643             bInSwapIn = sal_True;
644             SwBaseLink* pLink = (SwBaseLink*)(::sfx2::SvBaseLink*) refLink;
645             //TODO pLink->setInputStream(getInputStream());
646             pLink->SwapIn( sal_True, sal_True );
647             bInSwapIn = sal_False;
648         }
649         getIDocumentLinksAdministration()->GetLinkManager().Remove( refLink );
650         refLink.Clear();
651         aGrfObj.SetLink();
652     }
653 }
654 
655 
656 void SwGrfNode::SetTwipSize( const Size& rSz )
657 {
658     nGrfSize = rSz;
659     if( IsScaleImageMap() && nGrfSize.Width() && nGrfSize.Height() )
660     {
661         // Image-Map an Grafik-Groesse anpassen
662         ScaleImageMap();
663 
664         // Image-Map nicht noch einmal skalieren
665         SetScaleImageMap( sal_False );
666     }
667 }
668 
669 void SwGrfNode::ScaleImageMap()
670 {
671     if( !nGrfSize.Width() || !nGrfSize.Height() )
672         return;
673 
674     // dann die Image-Map skalieren
675     SwFrmFmt* pFmt = GetFlyFmt();
676 
677     if( !pFmt )
678         return;
679 
680     SwFmtURL aURL( pFmt->GetURL() );
681     if ( !aURL.GetMap() )
682         return;
683 
684     sal_Bool bScale = sal_False;
685     Fraction aScaleX( 1, 1 );
686     Fraction aScaleY( 1, 1 );
687 
688     const SwFmtFrmSize& rFrmSize = pFmt->GetFrmSize();
689     const SvxBoxItem& rBox = pFmt->GetBox();
690 
691     if( !rFrmSize.GetWidthPercent() )
692     {
693         SwTwips nWidth = rFrmSize.GetWidth();
694 
695         nWidth -= rBox.CalcLineSpace(BOX_LINE_LEFT) +
696                   rBox.CalcLineSpace(BOX_LINE_RIGHT);
697 
698         ASSERT( nWidth>0, "Gibt es 0 twip breite Grafiken!?" );
699 
700         if( nGrfSize.Width() != nWidth )
701         {
702             aScaleX = Fraction( nGrfSize.Width(), nWidth );
703             bScale = sal_True;
704         }
705     }
706     if( !rFrmSize.GetHeightPercent() )
707     {
708         SwTwips nHeight = rFrmSize.GetHeight();
709 
710         nHeight -= rBox.CalcLineSpace(BOX_LINE_TOP) +
711                    rBox.CalcLineSpace(BOX_LINE_BOTTOM);
712 
713         ASSERT( nHeight>0, "Gibt es 0 twip hohe Grafiken!?" );
714 
715         if( nGrfSize.Height() != nHeight )
716         {
717             aScaleY = Fraction( nGrfSize.Height(), nHeight );
718             bScale = sal_True;
719         }
720     }
721 
722     if( bScale )
723     {
724         aURL.GetMap()->Scale( aScaleX, aScaleY );
725         pFmt->SetFmtAttr( aURL );
726     }
727 }
728 
729 
730 void SwGrfNode::DelStreamName()
731 {
732     if( HasStreamName() )
733     {
734         // Dann die Grafik im Storage loeschen
735         uno::Reference < embed::XStorage > xDocStg = GetDoc()->GetDocStorage();
736         if( xDocStg.is() )
737         {
738             try
739             {
740                 String aPicStgName, aStrmName;
741                 _GetStreamStorageNames( aStrmName, aPicStgName );
742                 uno::Reference < embed::XStorage > refPics = xDocStg;
743                 if ( aPicStgName.Len() )
744                     refPics = xDocStg->openStorageElement( aPicStgName, embed::ElementModes::READWRITE );
745                 refPics->removeElement( aStrmName );
746                 uno::Reference < embed::XTransactedObject > xTrans( refPics, uno::UNO_QUERY );
747                 if ( xTrans.is() )
748                     xTrans->commit();
749             }
750             catch ( uno::Exception& )
751             {
752                 // --> OD 2005-04-25 #i48434#
753                 ASSERT( false, "<SwGrfNode::DelStreamName()> - unhandled exception!" );
754                 // <--
755             }
756         }
757 
758         aGrfObj.SetUserData();
759     }
760 }
761 
762 /** helper method to get a substorage of the document storage for readonly access.
763 
764     OD, MAV 2005-08-17 #i53025#
765     A substorage with the specified name will be opened readonly. If the provided
766     name is empty the root storage will be returned.
767 */
768 uno::Reference< embed::XStorage > SwGrfNode::_GetDocSubstorageOrRoot( const String& aStgName ) const
769 {
770     uno::Reference < embed::XStorage > refStor =
771         const_cast<SwGrfNode*>(this)->GetDoc()->GetDocStorage();
772     ASSERT( refStor.is(), "Kein Storage am Doc" );
773 
774     if ( aStgName.Len() )
775     {
776         if( refStor.is() )
777             return refStor->openStorageElement( aStgName, embed::ElementModes::READ );
778     }
779 
780     return refStor;
781 }
782 
783 /** helper method to determine stream for the embedded graphic.
784 
785     OD 2005-05-04 #i48434#
786     Important note: caller of this method has to handle the thrown exceptions
787     OD, MAV 2005-08-17 #i53025#
788     Storage, which should contain the stream of the embedded graphic, is
789     provided via parameter. Otherwise the returned stream will be closed
790     after the the method returns, because its parent stream is closed and deleted.
791     Proposed name of embedded graphic stream is also provided by parameter.
792 
793     @author OD
794 */
795 SvStream* SwGrfNode::_GetStreamForEmbedGrf(
796             const uno::Reference< embed::XStorage >& _refPics,
797             String& _aStrmName ) const
798 {
799     SvStream* pStrm( 0L );
800 
801     if( _refPics.is() && _aStrmName.Len() )
802     {
803         // If stream doesn't exist in the storage, try access the graphic file by
804         // re-generating its name.
805         // A save action can have changed the filename of the embedded graphic,
806         // because a changed unique ID of the graphic is calculated.
807         // --> OD 2006-01-30 #b6364738#
808         // recursive calls of <GetUniqueID()> have to be avoided.
809         // Thus, use local static boolean to assure this.
810         static bool bInRegenerateStrmName( false );
811         if ( !bInRegenerateStrmName &&
812              ( !_refPics->hasByName( _aStrmName ) ||
813                !_refPics->isStreamElement( _aStrmName ) ) )
814         {
815             bInRegenerateStrmName = true;
816             xub_StrLen nExtPos = _aStrmName.Search( '.' );
817             String aExtStr = _aStrmName.Copy( nExtPos );
818             Graphic aGraphic( GetGrfObj().GetGraphic() );
819             if ( aGraphic.GetType() != GRAPHIC_NONE )
820             {
821                 _aStrmName = String( GetGrfObj().GetUniqueID(), RTL_TEXTENCODING_ASCII_US );
822                 _aStrmName += aExtStr;
823             }
824             bInRegenerateStrmName = false;
825         }
826         // <--
827 
828         // assure that graphic file exist in the storage.
829         if ( _refPics->hasByName( _aStrmName ) &&
830              _refPics->isStreamElement( _aStrmName ) )
831         {
832             uno::Reference < io::XStream > refStrm = _refPics->openStreamElement( _aStrmName, embed::ElementModes::READ );
833             pStrm = utl::UcbStreamHelper::CreateStream( refStrm );
834         }
835         else
836         {
837             ASSERT( false, "<SwGrfNode::_GetStreamForEmbedGrf(..)> - embedded graphic file not found!" );
838         }
839     }
840 
841     return pStrm;
842 }
843 
844 
845 // --> OD 2005-08-17 #i53025# - stream couldn't be in a 3.1 - 5.2 storage any more.
846 // Thus, removing corresponding code.
847 void SwGrfNode::_GetStreamStorageNames( String& rStrmName,
848                                         String& rStorName ) const
849 {
850     rStorName.Erase();
851     rStrmName.Erase();
852 
853     String aUserData( aGrfObj.GetUserData() );
854     if( !aUserData.Len() )
855         return;
856 
857     String aProt( RTL_CONSTASCII_STRINGPARAM( "vnd.sun.star.Package:" ) );
858     if( 0 == aUserData.CompareTo( aProt, aProt.Len() ) )
859     {
860         // 6.0 (XML) Package
861         xub_StrLen nPos = aUserData.Search( '/' );
862         if( STRING_NOTFOUND == nPos )
863         {
864             rStrmName = aUserData.Copy( aProt.Len() );
865         }
866         else
867         {
868             xub_StrLen nPathStart = aProt.Len();
869             if( 0 == aUserData.CompareToAscii( "./", 2 ) )
870                 nPathStart += 2;
871             rStorName = aUserData.Copy( nPathStart, nPos-nPathStart );
872             rStrmName = aUserData.Copy( nPos+1 );
873         }
874     }
875     else
876     {
877         ASSERT( false,
878                 "<SwGrfNode::_GetStreamStorageNames(..)> - unknown graphic URL type. Code for handling 3.1 - 5.2 storages has been deleted by issue i53025." );
879     }
880     ASSERT( STRING_NOTFOUND == rStrmName.Search( '/' ),
881             "invalid graphic stream name" );
882 }
883 // <--
884 
885 SwCntntNode* SwGrfNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
886 {
887     // kopiere die Formate in das andere Dokument:
888     SwGrfFmtColl* pColl = pDoc->CopyGrfColl( *GetGrfColl() );
889 
890     Graphic aTmpGrf;
891     SwBaseLink* pLink = (SwBaseLink*)(::sfx2::SvBaseLink*) refLink;
892     if( !pLink && HasStreamName() )
893     {
894         // --> OD 2005-05-04 #i48434# - usage of new method <_GetStreamForEmbedGrf(..)>
895         try
896         {
897             // --> OD, MAV 2005-08-17 #i53025# - needed correction of new
898             // method <_GetStreamForEmbedGrf(..)>
899 //            bool bGraphic(false);
900 //            SvStream* pStrm = _GetStreamForEmbedGrf( bGraphic );
901             String aStrmName, aPicStgName;
902             _GetStreamStorageNames( aStrmName, aPicStgName );
903             uno::Reference < embed::XStorage > refPics = _GetDocSubstorageOrRoot( aPicStgName );
904             SvStream* pStrm = _GetStreamForEmbedGrf( refPics, aStrmName );
905             if ( pStrm )
906             {
907                 GraphicFilter::GetGraphicFilter()->ImportGraphic( aTmpGrf, String(), *pStrm );
908                 delete pStrm;
909             }
910             // <--
911         }
912         catch ( uno::Exception& )
913         {
914             // --> OD 2005-04-25 #i48434#
915             ASSERT( false, "<SwGrfNode::MakeCopy(..)> - unhandled exception!" );
916             // <--
917         }
918         // <--
919     }
920     else
921     {
922         if( aGrfObj.IsSwappedOut() )
923             const_cast<SwGrfNode*>(this)->SwapIn();
924         aTmpGrf = aGrfObj.GetGraphic();
925     }
926 
927     const sfx2::LinkManager& rMgr = getIDocumentLinksAdministration()->GetLinkManager();
928     String sFile, sFilter;
929     if( IsLinkedFile() )
930         rMgr.GetDisplayNames( refLink, 0, &sFile, 0, &sFilter );
931     else if( IsLinkedDDE() )
932     {
933         String sTmp1, sTmp2;
934         rMgr.GetDisplayNames( refLink, &sTmp1, &sTmp2, &sFilter );
935         sfx2::MakeLnkName( sFile, &sTmp1, sTmp2, sFilter );
936         sFilter.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDE" ));
937     }
938 
939     SwGrfNode* pGrfNd = pDoc->GetNodes().MakeGrfNode( rIdx, sFile, sFilter,
940                                                     &aTmpGrf, pColl,
941                                             (SwAttrSet*)GetpSwAttrSet() );
942     pGrfNd->SetTitle( GetTitle() );
943     pGrfNd->SetDescription( GetDescription() );
944     pGrfNd->SetContour( HasContour(), HasAutomaticContour() );
945     return pGrfNd;
946 }
947 
948 IMPL_LINK( SwGrfNode, SwapGraphic, GraphicObject*, pGrfObj )
949 {
950     SvStream* pRet;
951 
952     // #101174#: Keep graphic while in swap in. That's at least important
953     // when breaking links, because in this situation a reschedule call and
954     // a DataChanged call lead to a paint of the graphic.
955     if( pGrfObj->IsInSwapOut() && (IsSelected() || bInSwapIn) )
956         pRet = GRFMGR_AUTOSWAPSTREAM_NONE;
957     else if( refLink.Is() )
958     {
959         if( pGrfObj->IsInSwapIn() )
960         {
961             // then make it by your self
962             if( !bInSwapIn )
963             {
964                 sal_Bool bIsModifyLocked = IsModifyLocked();
965                 LockModify();
966                 SwapIn( sal_False );
967                 if( !bIsModifyLocked )
968                     UnlockModify();
969             }
970             pRet = GRFMGR_AUTOSWAPSTREAM_NONE;
971         }
972         else
973             pRet = GRFMGR_AUTOSWAPSTREAM_LINK;
974     }
975     else
976     {
977         pRet = GRFMGR_AUTOSWAPSTREAM_TEMP;
978 
979         if( HasStreamName() )
980         {
981             // --> OD 2005-05-04 #i48434# - usage of new method <_GetStreamForEmbedGrf(..)>
982             try
983             {
984                 // --> OD, MAV 2005-08-17 #i53025# - needed correction of new
985                 // method <_GetStreamForEmbedGrf(..)>
986 //                bool bGraphic(false);
987 //                SvStream* pStrm = _GetStreamForEmbedGrf( bGraphic );
988                 String aStrmName, aPicStgName;
989                 _GetStreamStorageNames( aStrmName, aPicStgName );
990                 uno::Reference < embed::XStorage > refPics = _GetDocSubstorageOrRoot( aPicStgName );
991                 SvStream* pStrm = _GetStreamForEmbedGrf( refPics, aStrmName );
992                 if ( pStrm )
993                 {
994                     if( pGrfObj->IsInSwapOut() )
995                     {
996                         pRet = GRFMGR_AUTOSWAPSTREAM_LINK;
997                     }
998                     else
999                     {
1000                         ImportGraphic( *pStrm );
1001                         pRet = GRFMGR_AUTOSWAPSTREAM_LOADED;
1002                     }
1003                     delete pStrm;
1004                 }
1005                 // <--
1006             }
1007             catch ( uno::Exception& )
1008             {
1009                 // --> OD 2005-04-25 #i48434#
1010                 ASSERT( false, "<SwapGraphic> - unhandled exception!" );
1011                 // <--
1012             }
1013             // <--
1014         }
1015     }
1016 
1017     return (long)pRet;
1018 }
1019 
1020 
1021 // alle QuickDraw-Bitmaps eines speziellen Docs loeschen
1022 void DelAllGrfCacheEntries( SwDoc* pDoc )
1023 {
1024     if( pDoc )
1025     {
1026         // alle Graphic-Links mit dem Namen aus dem Cache loeschen
1027         const sfx2::LinkManager& rLnkMgr = pDoc->GetLinkManager();
1028         const ::sfx2::SvBaseLinks& rLnks = rLnkMgr.GetLinks();
1029         SwGrfNode* pGrfNd;
1030         String sFileNm;
1031         for( sal_uInt16 n = rLnks.Count(); n; )
1032         {
1033             ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]);
1034             if( pLnk && OBJECT_CLIENT_GRF == pLnk->GetObjType() &&
1035                 rLnkMgr.GetDisplayNames( pLnk, 0, &sFileNm ) &&
1036                 pLnk->ISA( SwBaseLink ) && 0 != ( pGrfNd =
1037                 ((SwBaseLink*)pLnk)->GetCntntNode()->GetGrfNode()) )
1038             {
1039                 pGrfNd->GetGrfObj().ReleaseFromCache();
1040             }
1041         }
1042     }
1043 }
1044 
1045 // returns the with our graphic attributes filled Graphic-Attr-Structure
1046 GraphicAttr& SwGrfNode::GetGraphicAttr( GraphicAttr& rGA,
1047                                         const SwFrm* pFrm ) const
1048 {
1049     const SwAttrSet& rSet = GetSwAttrSet();
1050 
1051     rGA.SetDrawMode( (GraphicDrawMode)rSet.GetDrawModeGrf().GetValue() );
1052 
1053     const SwMirrorGrf & rMirror = rSet.GetMirrorGrf();
1054     sal_uLong nMirror = BMP_MIRROR_NONE;
1055     if( rMirror.IsGrfToggle() && pFrm && !pFrm->FindPageFrm()->OnRightPage() )
1056     {
1057         switch( rMirror.GetValue() )
1058         {
1059         case RES_MIRROR_GRAPH_DONT:     nMirror = BMP_MIRROR_HORZ; break;
1060         case RES_MIRROR_GRAPH_VERT:     nMirror = BMP_MIRROR_NONE; break;
1061         case RES_MIRROR_GRAPH_HOR:  nMirror = BMP_MIRROR_HORZ|BMP_MIRROR_VERT;
1062                                     break;
1063         default:                    nMirror = BMP_MIRROR_VERT; break;
1064         }
1065     }
1066     else
1067         switch( rMirror.GetValue() )
1068         {
1069         case RES_MIRROR_GRAPH_BOTH:     nMirror = BMP_MIRROR_HORZ|BMP_MIRROR_VERT;
1070                                     break;
1071         case RES_MIRROR_GRAPH_VERT: nMirror = BMP_MIRROR_HORZ; break;
1072         case RES_MIRROR_GRAPH_HOR:  nMirror = BMP_MIRROR_VERT; break;
1073         }
1074 
1075     rGA.SetMirrorFlags( nMirror );
1076 
1077     const SwCropGrf& rCrop = rSet.GetCropGrf();
1078     rGA.SetCrop( TWIP_TO_MM100( rCrop.GetLeft() ),
1079                  TWIP_TO_MM100( rCrop.GetTop() ),
1080                  TWIP_TO_MM100( rCrop.GetRight() ),
1081                  TWIP_TO_MM100( rCrop.GetBottom() ));
1082 
1083     const SwRotationGrf& rRotation = rSet.GetRotationGrf();
1084     rGA.SetRotation( rRotation.GetValue() );
1085 
1086     rGA.SetLuminance( rSet.GetLuminanceGrf().GetValue() );
1087     rGA.SetContrast( rSet.GetContrastGrf().GetValue() );
1088     rGA.SetChannelR( rSet.GetChannelRGrf().GetValue() );
1089     rGA.SetChannelG( rSet.GetChannelGGrf().GetValue() );
1090     rGA.SetChannelB( rSet.GetChannelBGrf().GetValue() );
1091     rGA.SetGamma( rSet.GetGammaGrf().GetValue() );
1092     rGA.SetInvert( rSet.GetInvertGrf().GetValue() );
1093 
1094     const sal_uInt16 nTrans = rSet.GetTransparencyGrf().GetValue();
1095     rGA.SetTransparency( (sal_uInt8) FRound(
1096                                 Min( nTrans, (sal_uInt16) 100 )  * 2.55 ) );
1097 
1098     return rGA;
1099 }
1100 
1101 sal_Bool SwGrfNode::IsTransparent() const
1102 {
1103     sal_Bool bRet = aGrfObj.IsTransparent();
1104     if( !bRet ) // ask the attribut
1105         bRet = 0 != GetSwAttrSet().GetTransparencyGrf().GetValue();
1106 
1107     return bRet;
1108 }
1109 
1110 
1111 sal_Bool SwGrfNode::IsSelected() const
1112 {
1113     sal_Bool bRet = sal_False;
1114     const SwEditShell* pESh = GetDoc()->GetEditShell();
1115     if( pESh )
1116     {
1117         const SwNode* pN = this;
1118         const ViewShell* pV = pESh;
1119         do {
1120             if( pV->ISA( SwEditShell ) && pN == &((SwCrsrShell*)pV)
1121                                 ->GetCrsr()->GetPoint()->nNode.GetNode() )
1122             {
1123                 bRet = sal_True;
1124                 break;
1125             }
1126         }
1127         while( pESh != ( pV = (ViewShell*)pV->GetNext() ));
1128     }
1129     return bRet;
1130 }
1131 
1132 // --> OD 2006-12-22 #i73788#
1133 boost::weak_ptr< SwAsyncRetrieveInputStreamThreadConsumer > SwGrfNode::GetThreadConsumer()
1134 {
1135     return mpThreadConsumer;
1136 }
1137 
1138 void SwGrfNode::TriggerAsyncRetrieveInputStream()
1139 {
1140     if ( !IsLinkedFile() )
1141     {
1142         ASSERT( false,
1143                 "<SwGrfNode::TriggerAsyncLoad()> - Method is misused. Method call is only valid for graphic nodes, which refer a linked graphic file" );
1144         return;
1145     }
1146 
1147     if ( mpThreadConsumer.get() == 0 )
1148     {
1149         mpThreadConsumer.reset( new SwAsyncRetrieveInputStreamThreadConsumer( *this ) );
1150 
1151         String sGrfNm;
1152         refLink->GetLinkManager()->GetDisplayNames( refLink, 0, &sGrfNm, 0, 0 );
1153 
1154         mpThreadConsumer->CreateThread( sGrfNm );
1155     }
1156 }
1157 
1158 bool SwGrfNode::IsLinkedInputStreamReady() const
1159 {
1160     return mbLinkedInputStreamReady;
1161 }
1162 
1163 void SwGrfNode::ApplyInputStream(
1164     com::sun::star::uno::Reference<com::sun::star::io::XInputStream> xInputStream,
1165     const sal_Bool bIsStreamReadOnly )
1166 {
1167     if ( IsLinkedFile() )
1168     {
1169         if ( xInputStream.is() )
1170         {
1171             mxInputStream = xInputStream;
1172             mbIsStreamReadOnly = bIsStreamReadOnly;
1173             mbLinkedInputStreamReady = true;
1174             SwMsgPoolItem aMsgHint( RES_LINKED_GRAPHIC_STREAM_ARRIVED );
1175             ModifyNotification( &aMsgHint, &aMsgHint );
1176         }
1177     }
1178 }
1179 
1180 void SwGrfNode::UpdateLinkWithInputStream()
1181 {
1182     // --> OD #i85105#
1183     // do not work on link, if a <SwapIn> has been triggered.
1184     if ( !bInSwapIn && IsLinkedFile() )
1185     // <--
1186     {
1187         GetLink()->setStreamToLoadFrom( mxInputStream, mbIsStreamReadOnly );
1188         GetLink()->Update();
1189         SwMsgPoolItem aMsgHint( RES_GRAPHIC_ARRIVED );
1190         ModifyNotification( &aMsgHint, &aMsgHint );
1191 
1192         // --> OD 2008-06-18 #i88291#
1193         mxInputStream.clear();
1194         GetLink()->clearStreamToLoadFrom();
1195         // <--
1196         mbLinkedInputStreamReady = false;
1197         mpThreadConsumer.reset();
1198     }
1199 }
1200 // <--
1201 
1202 // --> OD 2008-07-21 #i90395#
1203 bool SwGrfNode::IsAsyncRetrieveInputStreamPossible() const
1204 {
1205     bool bRet = false;
1206 
1207     if ( IsLinkedFile() )
1208     {
1209         String sGrfNm;
1210         refLink->GetLinkManager()->GetDisplayNames( refLink, 0, &sGrfNm, 0, 0 );
1211         String sProtocol( RTL_CONSTASCII_STRINGPARAM( "vnd.sun.star.pkg:" ) );
1212         if ( sGrfNm.CompareTo( sProtocol, sProtocol.Len() ) != 0 )
1213         {
1214             bRet = true;
1215         }
1216     }
1217 
1218     return bRet;
1219 }
1220 // <--
1221