xref: /AOO41X/main/sw/source/core/docnode/swbaslnk.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
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 
27 #include <hintids.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/outdev.hxx>
30 
31 #include <osl/thread.hxx>
32 #include <salhelper/condition.hxx>
33 #include <comphelper/mediadescriptor.hxx>
34 #include <sfx2/docfile.hxx>
35 #include <sfx2/lnkbase.hxx>
36 #include <sfx2/linkmgr.hxx>
37 #include <sfx2/objsh.hxx>
38 #include <editeng/boxitem.hxx>
39 #ifndef _SVX_SVXIDS_HRC
40 #include <svx/svxids.hrc>       // fuer die EventIds
41 #endif
42 #include <sfx2/linkmgr.hxx>
43 #include <svtools/soerr.hxx>
44 #include <fmtfsize.hxx>
45 #include <fmtanchr.hxx>
46 #include <frmatr.hxx>
47 #include <frmfmt.hxx>
48 #include <doc.hxx>
49 #include <pam.hxx>
50 #include <editsh.hxx>
51 #include <swtable.hxx>
52 #include <docary.hxx>
53 #include <swevent.hxx>
54 #include <swbaslnk.hxx>
55 #include <swserv.hxx>
56 #include <ndgrf.hxx>
57 #include <ndole.hxx>
58 #include <hints.hxx>
59 #include <tabfrm.hxx>
60 #include <cntfrm.hxx>
61 #include <htmltbl.hxx>
62 
63 using namespace com::sun::star;
64 
65 sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd );
66 
67 TYPEINIT1( SwBaseLink, ::sfx2::SvBaseLink );
68 
69 SV_IMPL_REF( SwServerObject )
70 
71 void lcl_CallModify( SwGrfNode& rGrfNd, SfxPoolItem& rItem )
72 {
73     //JP 4.7.2001: call fist all not SwNoTxtFrames, then the SwNoTxtFrames.
74     //              The reason is, that in the SwNoTxtFrames the Graphic
75     //              after a Paint will be swapped out! So all other "behind"
76     //              them havent't a loaded Graphic. - #86501#
77     rGrfNd.LockModify();
78 
79     SwClientIter aIter( rGrfNd );   // TODO
80     for( int n = 0; n < 2; ++n )
81     {
82         SwClient * pLast = aIter.GoStart();
83         if( pLast )     // konnte zum Anfang gesprungen werden ??
84         {
85             do {
86                 if( (0 == n) ^ ( 0 != pLast->ISA( SwCntntFrm )) )
87                     pLast->ModifyNotification( &rItem, &rItem );
88             } while( 0 != ( pLast = ++aIter ));
89         }
90     }
91     rGrfNd.UnlockModify();
92 }
93 
94 
95 void SwBaseLink::DataChanged( const String& rMimeType,
96                             const uno::Any & rValue )
97 {
98     if( !pCntntNode )
99     {
100         ASSERT(!this, "DataChanged ohne ContentNode" );
101         return ;
102     }
103 
104     SwDoc* pDoc = pCntntNode->GetDoc();
105     if( pDoc->IsInDtor() || ChkNoDataFlag() || bIgnoreDataChanged )
106     {
107         bIgnoreDataChanged = sal_False;
108         return ;
109     }
110 
111     sal_uLong nFmt = SotExchange::GetFormatIdFromMimeType( rMimeType );
112 
113     if( pCntntNode->IsNoTxtNode() &&
114         nFmt == sfx2::LinkManager::RegisterStatusInfoId() )
115     {
116         // nur eine Statusaenderung - Events bedienen ?
117         ::rtl::OUString sState;
118         if( rValue.hasValue() && ( rValue >>= sState ))
119         {
120             sal_uInt16 nEvent = 0;
121             switch( sState.toInt32() )
122             {
123             case sfx2::LinkManager::STATE_LOAD_OK:      nEvent = SVX_EVENT_IMAGE_LOAD;  break;
124             case sfx2::LinkManager::STATE_LOAD_ERROR:   nEvent = SVX_EVENT_IMAGE_ERROR; break;
125             case sfx2::LinkManager::STATE_LOAD_ABORT:   nEvent = SVX_EVENT_IMAGE_ABORT; break;
126             }
127 
128             SwFrmFmt* pFmt;
129             if( nEvent && 0 != ( pFmt = pCntntNode->GetFlyFmt() ))
130             {
131                 SwCallMouseEvent aCallEvent;
132                 aCallEvent.Set( EVENT_OBJECT_IMAGE, pFmt );
133                 pDoc->CallEvent( nEvent, aCallEvent );
134             }
135         }
136         return;         // das wars!
137     }
138 
139     sal_Bool bUpdate = sal_False;
140     sal_Bool bGraphicArrived = sal_False;
141     sal_Bool bGraphicPieceArrived = sal_False;
142     sal_Bool bDontNotify = sal_False;
143     Size aGrfSz, aFrmFmtSz;
144 
145     if( pCntntNode->IsGrfNode() )
146     {
147         GraphicObject& rGrfObj = ((SwGrfNode*)pCntntNode)->GetGrfObj();
148 
149         bDontNotify = ((SwGrfNode*)pCntntNode)->IsFrameInPaint();
150 
151         bGraphicArrived = GetObj()->IsDataComplete();
152         bGraphicPieceArrived = GetObj()->IsPending();
153         ((SwGrfNode*)pCntntNode)->SetGrafikArrived( bGraphicArrived );
154 
155         Graphic aGrf;
156         if( sfx2::LinkManager::GetGraphicFromAny( rMimeType, rValue, aGrf ) &&
157             ( GRAPHIC_DEFAULT != aGrf.GetType() ||
158               GRAPHIC_DEFAULT != rGrfObj.GetType() ) )
159         {
160             aGrfSz = ::GetGraphicSizeTwip( aGrf, 0 );
161             if( static_cast< const SwGrfNode * >( pCntntNode )->IsChgTwipSizeFromPixel() )
162             {
163                 const MapMode aMapTwip( MAP_TWIP );
164                 aFrmFmtSz =
165                     Application::GetDefaultDevice()->PixelToLogic(
166                         aGrf.GetSizePixel(), aMapTwip );
167 
168             }
169             else
170             {
171                 aFrmFmtSz = aGrfSz;
172             }
173             Size aSz( ((SwGrfNode*)pCntntNode)->GetTwipSize() );
174 
175             if( bGraphicPieceArrived && GRAPHIC_DEFAULT != aGrf.GetType() &&
176                 ( !aSz.Width() || !aSz.Height() ) )
177             {
178                 // wenn nur ein Teil ankommt, aber die Groesse nicht
179                 // gesetzt ist, dann muss "unten" der Teil von
180                 // bGraphicArrived durchlaufen werden!
181                 // (ansonten wird die Grafik in deft. Size gepaintet)
182                 bGraphicArrived = sal_True;
183                 bGraphicPieceArrived = sal_False;
184             }
185 
186             rGrfObj.SetGraphic( aGrf, rGrfObj.GetLink() );
187             bUpdate = sal_True;
188 
189             // Bug 33999: damit der Node den Transparent-Status
190             //      richtig gesetzt hat, ohne auf die Grafik
191             //      zugreifen zu muessen (sonst erfolgt ein SwapIn!).
192             if( bGraphicArrived )
193             {
194                 // Bug #34735#: immer mit der korrekten Grafik-Size
195                 //              arbeiten
196                 if( aGrfSz.Height() && aGrfSz.Width() &&
197                     aSz.Height() && aSz.Width() &&
198                     aGrfSz != aSz )
199                     ((SwGrfNode*)pCntntNode)->SetTwipSize( aGrfSz );
200             }
201         }
202         if ( bUpdate && !bGraphicArrived && !bGraphicPieceArrived )
203             ((SwGrfNode*)pCntntNode)->SetTwipSize( Size(0,0) );
204     }
205     else if( pCntntNode->IsOLENode() )
206         bUpdate = sal_True;
207 
208     ViewShell *pSh = 0;
209     SwEditShell* pESh = pDoc->GetEditShell( &pSh );
210 
211     if ( bUpdate && bGraphicPieceArrived && !(bSwapIn || bDontNotify) )
212     {
213         //Hint ohne Actions verschicken, loest direktes Paint aus.
214         if ( (!pSh || !pSh->ActionPend()) && (!pESh || !pESh->ActionPend()) )
215         {
216             SwMsgPoolItem aMsgHint( RES_GRAPHIC_PIECE_ARRIVED );
217             pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint );
218             bUpdate = sal_False;
219         }
220     }
221 
222     static sal_Bool bInNotifyLinks = sal_False;
223     if( bUpdate && !bDontNotify && (!bSwapIn || bGraphicArrived) &&
224         !bInNotifyLinks)
225     {
226         sal_Bool bLockView = sal_False;
227         if( pSh )
228         {
229             bLockView = pSh->IsViewLocked();
230             pSh->LockView( sal_True );
231         }
232 
233         if( pESh )
234             pESh->StartAllAction();
235         else if( pSh )
236             pSh->StartAction();
237 
238         SwMsgPoolItem aMsgHint( static_cast<sal_uInt16>(
239             bGraphicArrived ? RES_GRAPHIC_ARRIVED : RES_UPDATE_ATTR ) );
240 
241         if ( bGraphicArrived )
242         {
243             //Alle benachrichtigen, die am gleichen Link horchen.
244             bInNotifyLinks = sal_True;
245 
246             const ::sfx2::SvBaseLinks& rLnks = pDoc->GetLinkManager().GetLinks();
247             for( sal_uInt16 n = rLnks.Count(); n; )
248             {
249                 ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]);
250                 if( pLnk && OBJECT_CLIENT_GRF == pLnk->GetObjType() &&
251                     pLnk->ISA( SwBaseLink ) && pLnk->GetObj() == GetObj() )
252                 {
253                     SwBaseLink* pBLink = (SwBaseLink*)pLnk;
254                     SwGrfNode* pGrfNd = (SwGrfNode*)pBLink->pCntntNode;
255 
256                     if( pBLink != this &&
257                         ( !bSwapIn ||
258                             GRAPHIC_DEFAULT == pGrfNd->GetGrfObj().GetType()))
259                     {
260                         pBLink->bIgnoreDataChanged = sal_False;
261                         pBLink->DataChanged( rMimeType, rValue );
262                         pBLink->bIgnoreDataChanged = sal_True;
263 
264                         pGrfNd->SetGrafikArrived( ((SwGrfNode*)pCntntNode)->
265                                                     IsGrafikArrived() );
266 
267                         // Fly der Grafik anpassen !
268                         if( !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) )
269                             ::lcl_CallModify( *pGrfNd, aMsgHint );
270                     }
271                     else if( pBLink == this &&
272                             !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) )
273                         // Fly der Grafik anpassen !
274                         ::lcl_CallModify( *pGrfNd, aMsgHint );
275                 }
276             }
277 
278             bInNotifyLinks = sal_False;
279         }
280         else
281         {
282             pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint );
283         }
284 
285 
286         if( pESh )
287         {
288             const sal_Bool bEndActionByVirDev = pESh->IsEndActionByVirDev();
289             pESh->SetEndActionByVirDev( sal_True );
290             pESh->EndAllAction();
291             pESh->SetEndActionByVirDev( bEndActionByVirDev );
292         }
293         else if( pSh )
294             pSh->EndAction();
295 
296         if( pSh && !bLockView )
297             pSh->LockView( sal_False );
298     }
299 }
300 
301 sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd )
302 {
303     sal_Bool bRet = sal_False;
304     ViewShell *pSh;
305     CurrShell *pCurr = 0;
306     if ( pGrfNd->GetDoc()->GetEditShell( &pSh ) )
307         pCurr = new CurrShell( pSh );
308 
309     Size aSz = pGrfNd->GetTwipSize();
310     if ( !(aSz.Width() && aSz.Height()) &&
311             rGrfSz.Width() && rGrfSz.Height() )
312     {
313         SwFrmFmt* pFmt;
314         if( pGrfNd->IsChgTwipSize() &&
315             0 != (pFmt = pGrfNd->GetFlyFmt()) )
316         {
317             Size aCalcSz( aSz );
318             if ( !aSz.Height() && aSz.Width() )
319                 //passende Hoehe ausrechnen.
320                 aCalcSz.Height() = rFrmSz.Height() *
321                         aSz.Width() / rFrmSz.Width();
322             else if ( !aSz.Width() && aSz.Height() )
323                 //passende Breite ausrechnen
324                 aCalcSz.Width() = rFrmSz.Width() *
325                         aSz.Height() / rFrmSz.Height();
326             else
327                 //Hoehe und Breite uebernehmen
328                 aCalcSz = rFrmSz;
329 
330             const SvxBoxItem     &rBox = pFmt->GetBox();
331             aCalcSz.Width() += rBox.CalcLineSpace(BOX_LINE_LEFT) +
332                                rBox.CalcLineSpace(BOX_LINE_RIGHT);
333             aCalcSz.Height()+= rBox.CalcLineSpace(BOX_LINE_TOP) +
334                                rBox.CalcLineSpace(BOX_LINE_BOTTOM);
335             const SwFmtFrmSize& rOldAttr = pFmt->GetFrmSize();
336             if( rOldAttr.GetSize() != aCalcSz )
337             {
338                 SwFmtFrmSize aAttr( rOldAttr  );
339                 aAttr.SetSize( aCalcSz );
340                 pFmt->SetFmtAttr( aAttr );
341                 bRet = sal_True;
342             }
343 
344             if( !aSz.Width() )
345             {
346                 // Wenn die Grafik in einer Tabelle verankert ist, muess
347                 // die Tabellen-Spalten neu berechnet werden
348                 const SwDoc *pDoc = pGrfNd->GetDoc();
349                 const SwPosition* pAPos = pFmt->GetAnchor().GetCntntAnchor();
350                 SwNode *pANd;
351                 SwTableNode *pTblNd;
352                 if( pAPos &&
353                     0 != (pANd = & pAPos->nNode.GetNode()) &&
354                     0 != (pTblNd = pANd->FindTableNode()) )
355                 {
356                     const sal_Bool bLastGrf = !pTblNd->GetTable().DecGrfsThatResize();
357                     SwHTMLTableLayout *pLayout =
358                         pTblNd->GetTable().GetHTMLTableLayout();
359                     if( pLayout )
360                     {
361                         const sal_uInt16 nBrowseWidth =
362                                     pLayout->GetBrowseWidthByTable( *pDoc );
363                         if ( nBrowseWidth )
364                         {
365                             pLayout->Resize( nBrowseWidth, sal_True, sal_True,
366                                              bLastGrf ? HTMLTABLE_RESIZE_NOW
367                                                       : 500 );
368                         }
369                     }
370                 }
371             }
372         }
373 
374         // SetTwipSize skaliert ggf. eine ImageMap neu und
375         // braucht dazu das Frame-Format
376         pGrfNd->SetTwipSize( rGrfSz );
377     }
378 
379     delete pCurr;
380 
381     return bRet;
382 }
383 
384 
385 sal_Bool SwBaseLink::SwapIn( sal_Bool bWaitForData, sal_Bool bNativFormat )
386 {
387     bSwapIn = sal_True;
388 
389     sal_Bool bRes;
390 
391     if( !GetObj() && ( bNativFormat || ( !IsSynchron() && bWaitForData ) ))
392     {
393         AddNextRef();
394         _GetRealObject();
395         ReleaseRef();
396     }
397 
398 #if OSL_DEBUG_LEVEL > 1
399     {
400         String sGrfNm;
401         if(GetLinkManager())
402             GetLinkManager()->GetDisplayNames( this, 0, &sGrfNm, 0, 0 );
403         int x = 0;
404         ++x;
405     }
406 #endif
407 
408     if( GetObj() )
409     {
410         String aMimeType( SotExchange::GetFormatMimeType( GetContentType() ));
411         uno::Any aValue;
412         GetObj()->GetData( aValue, aMimeType, !IsSynchron() && bWaitForData );
413 
414         if( bWaitForData && !GetObj() )
415         {
416             ASSERT( !this, "das SvxFileObject wurde in einem GetData geloescht!" );
417             bRes = sal_False;
418         }
419         else if( 0 != ( bRes = aValue.hasValue() ) )
420         {
421             //JP 14.04.99: Bug 64820 - das Flag muss beim SwapIn natuerlich
422             //              zurueckgesetzt werden. Die Daten sollen ja neu
423             //              uebernommen werden
424             bIgnoreDataChanged = sal_False;
425             DataChanged( aMimeType, aValue );
426         }
427     }
428     else if( !IsSynchron() && bWaitForData )
429     {
430         SetSynchron( sal_True );
431         bRes = Update();
432         SetSynchron( sal_False );
433     }
434     else
435         bRes = Update();
436 
437     bSwapIn = sal_False;
438     return bRes;
439 }
440 
441 void SwBaseLink::Closed()
442 {
443     if( pCntntNode && !pCntntNode->GetDoc()->IsInDtor() )
444     {
445         // wir heben die Verbindung auf
446         if( pCntntNode->IsGrfNode() )
447             ((SwGrfNode*)pCntntNode)->ReleaseLink();
448     }
449     SvBaseLink::Closed();
450 }
451 
452 const SwNode* SwBaseLink::GetAnchor() const
453 {
454     if (pCntntNode)
455     {
456         SwFrmFmt *const pFmt = pCntntNode->GetFlyFmt();
457         if (pFmt)
458         {
459             const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
460             SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
461             if (pAPos &&
462                 ((FLY_AS_CHAR == rAnchor.GetAnchorId()) ||
463                  (FLY_AT_CHAR == rAnchor.GetAnchorId()) ||
464                  (FLY_AT_FLY  == rAnchor.GetAnchorId()) ||
465                  (FLY_AT_PARA == rAnchor.GetAnchorId())))
466             {
467                     return &pAPos->nNode.GetNode();
468             }
469             return 0;
470         }
471     }
472 
473     ASSERT( !this, "GetAnchor nicht ueberlagert" );
474     return 0;
475 }
476 
477 sal_Bool SwBaseLink::IsRecursion( const SwBaseLink* pChkLnk ) const
478 {
479     SwServerObjectRef aRef( (SwServerObject*)GetObj() );
480     if( aRef.Is() )
481     {
482         // es ist ein ServerObject, also frage nach allen darin
483         // befindlichen Links, ob wir darin enthalten sind. Ansonsten
484         // handelt es sich um eine Rekursion.
485         return aRef->IsLinkInServer( pChkLnk );
486     }
487     return sal_False;
488 }
489 
490 sal_Bool SwBaseLink::IsInRange( sal_uLong, sal_uLong, xub_StrLen, xub_StrLen ) const
491 {
492     // Grafik oder OLE-Links nicht,
493     // Felder oder Sections haben eigene Ableitung!
494     return sal_False;
495 }
496 
497 SwBaseLink::~SwBaseLink()
498 {
499 }
500