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
SV_IMPL_REF(SwServerObject)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
DataChanged(const String & rMimeType,const uno::Any & rValue)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 SwGrfNode* pSwGrfNode = dynamic_cast< SwGrfNode* >(pCntntNode);
148 OSL_ENSURE(pSwGrfNode, "Error, pSwGrfNode expected when node answers IsGrfNode() with true (!)");
149 const GraphicObject& rGrfObj = pSwGrfNode->GetGrfObj();
150
151 bDontNotify = pSwGrfNode->IsFrameInPaint();
152
153 bGraphicArrived = GetObj()->IsDataComplete();
154 bGraphicPieceArrived = GetObj()->IsPending();
155 pSwGrfNode->SetGrafikArrived( bGraphicArrived );
156
157 Graphic aGrf;
158 if( sfx2::LinkManager::GetGraphicFromAny( rMimeType, rValue, aGrf ) &&
159 ( GRAPHIC_DEFAULT != aGrf.GetType() ||
160 GRAPHIC_DEFAULT != rGrfObj.GetType() ) )
161 {
162 aGrfSz = ::GetGraphicSizeTwip( aGrf, 0 );
163 if( pSwGrfNode->IsChgTwipSizeFromPixel() )
164 {
165 const MapMode aMapTwip( MAP_TWIP );
166 aFrmFmtSz =
167 Application::GetDefaultDevice()->PixelToLogic(
168 aGrf.GetSizePixel(), aMapTwip );
169
170 }
171 else
172 {
173 aFrmFmtSz = aGrfSz;
174 }
175 Size aSz( pSwGrfNode->GetTwipSize() );
176
177 if( bGraphicPieceArrived && GRAPHIC_DEFAULT != aGrf.GetType() &&
178 ( !aSz.Width() || !aSz.Height() ) )
179 {
180 // wenn nur ein Teil ankommt, aber die Groesse nicht
181 // gesetzt ist, dann muss "unten" der Teil von
182 // bGraphicArrived durchlaufen werden!
183 // (ansonten wird die Grafik in deft. Size gepaintet)
184 bGraphicArrived = sal_True;
185 bGraphicPieceArrived = sal_False;
186 }
187
188 pSwGrfNode->SetGraphic(aGrf, rGrfObj.GetLink());
189 bUpdate = sal_True;
190
191 // Bug 33999: damit der Node den Transparent-Status
192 // richtig gesetzt hat, ohne auf die Grafik
193 // zugreifen zu muessen (sonst erfolgt ein SwapIn!).
194 if( bGraphicArrived )
195 {
196 // Bug #34735#: immer mit der korrekten Grafik-Size
197 // arbeiten
198 if( aGrfSz.Height() && aGrfSz.Width() &&
199 aSz.Height() && aSz.Width() &&
200 aGrfSz != aSz )
201 pSwGrfNode->SetTwipSize( aGrfSz );
202 }
203 }
204 if ( bUpdate && !bGraphicArrived && !bGraphicPieceArrived )
205 pSwGrfNode->SetTwipSize( Size(0,0) );
206 }
207 else if( pCntntNode->IsOLENode() )
208 bUpdate = sal_True;
209
210 ViewShell *pSh = 0;
211 SwEditShell* pESh = pDoc->GetEditShell( &pSh );
212
213 if ( bUpdate && bGraphicPieceArrived && !(bSwapIn || bDontNotify) )
214 {
215 //Hint ohne Actions verschicken, loest direktes Paint aus.
216 if ( (!pSh || !pSh->ActionPend()) && (!pESh || !pESh->ActionPend()) )
217 {
218 SwMsgPoolItem aMsgHint( RES_GRAPHIC_PIECE_ARRIVED );
219 pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint );
220 bUpdate = sal_False;
221 }
222 }
223
224 static sal_Bool bInNotifyLinks = sal_False;
225 if( bUpdate && !bDontNotify && (!bSwapIn || bGraphicArrived) &&
226 !bInNotifyLinks)
227 {
228 sal_Bool bLockView = sal_False;
229 if( pSh )
230 {
231 bLockView = pSh->IsViewLocked();
232 pSh->LockView( sal_True );
233 }
234
235 if( pESh )
236 pESh->StartAllAction();
237 else if( pSh )
238 pSh->StartAction();
239
240 SwMsgPoolItem aMsgHint( static_cast<sal_uInt16>(
241 bGraphicArrived ? RES_GRAPHIC_ARRIVED : RES_UPDATE_ATTR ) );
242
243 if ( bGraphicArrived )
244 {
245 //Alle benachrichtigen, die am gleichen Link horchen.
246 bInNotifyLinks = sal_True;
247
248 const ::sfx2::SvBaseLinks& rLnks = pDoc->GetLinkManager().GetLinks();
249 for( sal_uInt16 n = rLnks.Count(); n; )
250 {
251 ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]);
252 if( pLnk && OBJECT_CLIENT_GRF == pLnk->GetObjType() &&
253 pLnk->ISA( SwBaseLink ) && pLnk->GetObj() == GetObj() )
254 {
255 SwBaseLink* pBLink = (SwBaseLink*)pLnk;
256 SwGrfNode* pGrfNd = (SwGrfNode*)pBLink->pCntntNode;
257
258 if( pBLink != this &&
259 ( !bSwapIn ||
260 GRAPHIC_DEFAULT == pGrfNd->GetGrfObj().GetType()))
261 {
262 pBLink->bIgnoreDataChanged = sal_False;
263 pBLink->DataChanged( rMimeType, rValue );
264 pBLink->bIgnoreDataChanged = sal_True;
265
266 pGrfNd->SetGrafikArrived( ((SwGrfNode*)pCntntNode)->
267 IsGrafikArrived() );
268
269 // Fly der Grafik anpassen !
270 if( !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) )
271 ::lcl_CallModify( *pGrfNd, aMsgHint );
272 }
273 else if( pBLink == this &&
274 !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) )
275 // Fly der Grafik anpassen !
276 ::lcl_CallModify( *pGrfNd, aMsgHint );
277 }
278 }
279
280 bInNotifyLinks = sal_False;
281 }
282 else
283 {
284 pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint );
285 }
286
287
288 if( pESh )
289 {
290 const sal_Bool bEndActionByVirDev = pESh->IsEndActionByVirDev();
291 pESh->SetEndActionByVirDev( sal_True );
292 pESh->EndAllAction();
293 pESh->SetEndActionByVirDev( bEndActionByVirDev );
294 }
295 else if( pSh )
296 pSh->EndAction();
297
298 if( pSh && !bLockView )
299 pSh->LockView( sal_False );
300 }
301 }
302
SetGrfFlySize(const Size & rGrfSz,const Size & rFrmSz,SwGrfNode * pGrfNd)303 sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd )
304 {
305 sal_Bool bRet = sal_False;
306 ViewShell *pSh;
307 CurrShell *pCurr = 0;
308 if ( pGrfNd->GetDoc()->GetEditShell( &pSh ) )
309 pCurr = new CurrShell( pSh );
310
311 Size aSz = pGrfNd->GetTwipSize();
312 if ( !(aSz.Width() && aSz.Height()) &&
313 rGrfSz.Width() && rGrfSz.Height() )
314 {
315 SwFrmFmt* pFmt;
316 if( pGrfNd->IsChgTwipSize() &&
317 0 != (pFmt = pGrfNd->GetFlyFmt()) )
318 {
319 Size aCalcSz( aSz );
320 if ( !aSz.Height() && aSz.Width() )
321 //passende Hoehe ausrechnen.
322 aCalcSz.Height() = rFrmSz.Height() *
323 aSz.Width() / rFrmSz.Width();
324 else if ( !aSz.Width() && aSz.Height() )
325 //passende Breite ausrechnen
326 aCalcSz.Width() = rFrmSz.Width() *
327 aSz.Height() / rFrmSz.Height();
328 else
329 //Hoehe und Breite uebernehmen
330 aCalcSz = rFrmSz;
331
332 const SvxBoxItem &rBox = pFmt->GetBox();
333 aCalcSz.Width() += rBox.CalcLineSpace(BOX_LINE_LEFT) +
334 rBox.CalcLineSpace(BOX_LINE_RIGHT);
335 aCalcSz.Height()+= rBox.CalcLineSpace(BOX_LINE_TOP) +
336 rBox.CalcLineSpace(BOX_LINE_BOTTOM);
337 const SwFmtFrmSize& rOldAttr = pFmt->GetFrmSize();
338 if( rOldAttr.GetSize() != aCalcSz )
339 {
340 SwFmtFrmSize aAttr( rOldAttr );
341 aAttr.SetSize( aCalcSz );
342 pFmt->SetFmtAttr( aAttr );
343 bRet = sal_True;
344 }
345
346 if( !aSz.Width() )
347 {
348 // Wenn die Grafik in einer Tabelle verankert ist, muess
349 // die Tabellen-Spalten neu berechnet werden
350 const SwDoc *pDoc = pGrfNd->GetDoc();
351 const SwPosition* pAPos = pFmt->GetAnchor().GetCntntAnchor();
352 SwNode *pANd;
353 SwTableNode *pTblNd;
354 if( pAPos &&
355 0 != (pANd = & pAPos->nNode.GetNode()) &&
356 0 != (pTblNd = pANd->FindTableNode()) )
357 {
358 const sal_Bool bLastGrf = !pTblNd->GetTable().DecGrfsThatResize();
359 SwHTMLTableLayout *pLayout =
360 pTblNd->GetTable().GetHTMLTableLayout();
361 if( pLayout )
362 {
363 const sal_uInt16 nBrowseWidth =
364 pLayout->GetBrowseWidthByTable( *pDoc );
365 if ( nBrowseWidth )
366 {
367 pLayout->Resize( nBrowseWidth, sal_True, sal_True,
368 bLastGrf ? HTMLTABLE_RESIZE_NOW
369 : 500 );
370 }
371 }
372 }
373 }
374 }
375
376 // SetTwipSize skaliert ggf. eine ImageMap neu und
377 // braucht dazu das Frame-Format
378 pGrfNd->SetTwipSize( rGrfSz );
379 }
380
381 delete pCurr;
382
383 return bRet;
384 }
385
386
SwapIn(sal_Bool bWaitForData,sal_Bool bNativFormat)387 sal_Bool SwBaseLink::SwapIn( sal_Bool bWaitForData, sal_Bool bNativFormat )
388 {
389 bSwapIn = sal_True;
390
391 sal_Bool bRes;
392
393 if( !GetObj() && ( bNativFormat || ( !IsSynchron() && bWaitForData ) ))
394 {
395 AddNextRef();
396 _GetRealObject();
397 ReleaseRef();
398 }
399
400 #if OSL_DEBUG_LEVEL > 1
401 {
402 String sGrfNm;
403 if(GetLinkManager())
404 GetLinkManager()->GetDisplayNames( this, 0, &sGrfNm, 0, 0 );
405 int x = 0;
406 ++x;
407 }
408 #endif
409
410 if( GetObj() )
411 {
412 String aMimeType( SotExchange::GetFormatMimeType( GetContentType() ));
413 uno::Any aValue;
414 GetObj()->GetData( aValue, aMimeType, !IsSynchron() && bWaitForData );
415
416 if( bWaitForData && !GetObj() )
417 {
418 ASSERT( !this, "das SvxFileObject wurde in einem GetData geloescht!" );
419 bRes = sal_False;
420 }
421 else if( 0 != ( bRes = aValue.hasValue() ) )
422 {
423 //JP 14.04.99: Bug 64820 - das Flag muss beim SwapIn natuerlich
424 // zurueckgesetzt werden. Die Daten sollen ja neu
425 // uebernommen werden
426 bIgnoreDataChanged = sal_False;
427 DataChanged( aMimeType, aValue );
428 }
429 }
430 else if( !IsSynchron() && bWaitForData )
431 {
432 SetSynchron( sal_True );
433 bRes = Update();
434 SetSynchron( sal_False );
435 }
436 else
437 bRes = Update();
438
439 bSwapIn = sal_False;
440 return bRes;
441 }
442
Closed()443 void SwBaseLink::Closed()
444 {
445 if( pCntntNode && !pCntntNode->GetDoc()->IsInDtor() )
446 {
447 // wir heben die Verbindung auf
448 if( pCntntNode->IsGrfNode() )
449 ((SwGrfNode*)pCntntNode)->ReleaseLink();
450 }
451 SvBaseLink::Closed();
452 }
453
GetAnchor() const454 const SwNode* SwBaseLink::GetAnchor() const
455 {
456 if (pCntntNode)
457 {
458 SwFrmFmt *const pFmt = pCntntNode->GetFlyFmt();
459 if (pFmt)
460 {
461 const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
462 SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
463 if (pAPos &&
464 ((FLY_AS_CHAR == rAnchor.GetAnchorId()) ||
465 (FLY_AT_CHAR == rAnchor.GetAnchorId()) ||
466 (FLY_AT_FLY == rAnchor.GetAnchorId()) ||
467 (FLY_AT_PARA == rAnchor.GetAnchorId())))
468 {
469 return &pAPos->nNode.GetNode();
470 }
471 return 0;
472 }
473 }
474
475 ASSERT( !this, "GetAnchor nicht ueberlagert" );
476 return 0;
477 }
478
IsRecursion(const SwBaseLink * pChkLnk) const479 sal_Bool SwBaseLink::IsRecursion( const SwBaseLink* pChkLnk ) const
480 {
481 SwServerObjectRef aRef( (SwServerObject*)GetObj() );
482 if( aRef.Is() )
483 {
484 // es ist ein ServerObject, also frage nach allen darin
485 // befindlichen Links, ob wir darin enthalten sind. Ansonsten
486 // handelt es sich um eine Rekursion.
487 return aRef->IsLinkInServer( pChkLnk );
488 }
489 return sal_False;
490 }
491
IsInRange(sal_uLong,sal_uLong,xub_StrLen,xub_StrLen) const492 sal_Bool SwBaseLink::IsInRange( sal_uLong, sal_uLong, xub_StrLen, xub_StrLen ) const
493 {
494 // Grafik oder OLE-Links nicht,
495 // Felder oder Sections haben eigene Ableitung!
496 return sal_False;
497 }
498
~SwBaseLink()499 SwBaseLink::~SwBaseLink()
500 {
501 }
502