Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <hintids.hxx>
22 : #include <vcl/svapp.hxx>
23 : #include <vcl/outdev.hxx>
24 :
25 : #include <osl/thread.hxx>
26 : #include <salhelper/condition.hxx>
27 : #include <comphelper/mediadescriptor.hxx>
28 : #include <sfx2/docfile.hxx>
29 : #include <sfx2/lnkbase.hxx>
30 : #include <sfx2/objsh.hxx>
31 : #include <editeng/boxitem.hxx>
32 : #include <svx/svxids.hrc> // For the EventIds
33 : #include <sfx2/linkmgr.hxx>
34 : #include <svtools/soerr.hxx>
35 : #include <fmtfsize.hxx>
36 : #include <fmtanchr.hxx>
37 : #include <frmatr.hxx>
38 : #include <frmfmt.hxx>
39 : #include <doc.hxx>
40 : #include <pam.hxx>
41 : #include <editsh.hxx>
42 : #include <swtable.hxx>
43 : #include <docary.hxx>
44 : #include <swevent.hxx>
45 : #include <swbaslnk.hxx>
46 : #include <swserv.hxx>
47 : #include <ndgrf.hxx>
48 : #include <ndole.hxx>
49 : #include <hints.hxx>
50 : #include <tabfrm.hxx>
51 : #include <cntfrm.hxx>
52 : #include <htmltbl.hxx>
53 :
54 : using namespace com::sun::star;
55 :
56 : sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd );
57 :
58 0 : TYPEINIT1( SwBaseLink, ::sfx2::SvBaseLink );
59 :
60 0 : SV_IMPL_REF( SwServerObject )
61 :
62 0 : static void lcl_CallModify( SwGrfNode& rGrfNd, SfxPoolItem& rItem )
63 : {
64 : //call fist all not SwNoTxtFrames, then the SwNoTxtFrames.
65 : // The reason is, that in the SwNoTxtFrames the Graphic
66 : // after a Paint will be swapped out! So all other "behind"
67 : // them havent't a loaded Graphic.
68 0 : rGrfNd.LockModify();
69 :
70 0 : SwClientIter aIter( rGrfNd ); // TODO
71 0 : for( int n = 0; n < 2; ++n )
72 : {
73 0 : SwClient * pLast = aIter.GoStart();
74 0 : if( pLast ) // Were we able to jump to the beginning?
75 : {
76 0 : do {
77 0 : if( (0 == n) ^ ( 0 != pLast->ISA( SwCntntFrm )) )
78 0 : pLast->ModifyNotification( &rItem, &rItem );
79 : } while( 0 != ( pLast = ++aIter ));
80 : }
81 : }
82 0 : rGrfNd.UnlockModify();
83 0 : }
84 :
85 :
86 0 : ::sfx2::SvBaseLink::UpdateResult SwBaseLink::DataChanged(
87 : const String& rMimeType, const uno::Any & rValue )
88 : {
89 0 : if( !pCntntNode )
90 : {
91 : OSL_ENSURE(!this, "DataChanged without ContentNode" );
92 0 : return ERROR_GENERAL;
93 : }
94 :
95 0 : SwDoc* pDoc = pCntntNode->GetDoc();
96 0 : if( pDoc->IsInDtor() || ChkNoDataFlag() || bIgnoreDataChanged )
97 : {
98 0 : bIgnoreDataChanged = sal_False;
99 0 : return SUCCESS;
100 : }
101 :
102 0 : sal_uLong nFmt = SotExchange::GetFormatIdFromMimeType( rMimeType );
103 :
104 0 : if( pCntntNode->IsNoTxtNode() &&
105 0 : nFmt == sfx2::LinkManager::RegisterStatusInfoId() )
106 : {
107 : // Only a status change - serve Events?
108 0 : ::rtl::OUString sState;
109 0 : if( rValue.hasValue() && ( rValue >>= sState ))
110 : {
111 0 : sal_uInt16 nEvent = 0;
112 0 : switch( sState.toInt32() )
113 : {
114 0 : case sfx2::LinkManager::STATE_LOAD_OK: nEvent = SVX_EVENT_IMAGE_LOAD; break;
115 0 : case sfx2::LinkManager::STATE_LOAD_ERROR: nEvent = SVX_EVENT_IMAGE_ERROR; break;
116 0 : case sfx2::LinkManager::STATE_LOAD_ABORT: nEvent = SVX_EVENT_IMAGE_ABORT; break;
117 : }
118 :
119 : SwFrmFmt* pFmt;
120 0 : if( nEvent && 0 != ( pFmt = pCntntNode->GetFlyFmt() ))
121 : {
122 0 : SwCallMouseEvent aCallEvent;
123 0 : aCallEvent.Set( EVENT_OBJECT_IMAGE, pFmt );
124 0 : pDoc->CallEvent( nEvent, aCallEvent );
125 : }
126 : }
127 0 : return SUCCESS; // That's it!
128 : }
129 :
130 0 : bool bUpdate = false;
131 0 : sal_Bool bGraphicArrived = sal_False;
132 0 : sal_Bool bGraphicPieceArrived = sal_False;
133 0 : sal_Bool bDontNotify = sal_False;
134 0 : Size aGrfSz, aFrmFmtSz;
135 :
136 0 : if( pCntntNode->IsGrfNode() )
137 : {
138 0 : GraphicObject& rGrfObj = ((SwGrfNode*)pCntntNode)->GetGrfObj();
139 :
140 0 : bDontNotify = ((SwGrfNode*)pCntntNode)->IsFrameInPaint();
141 :
142 0 : bGraphicArrived = GetObj()->IsDataComplete();
143 0 : bGraphicPieceArrived = GetObj()->IsPending();
144 0 : ((SwGrfNode*)pCntntNode)->SetGrafikArrived( bGraphicArrived );
145 :
146 0 : Graphic aGrf;
147 0 : if( sfx2::LinkManager::GetGraphicFromAny( rMimeType, rValue, aGrf ) &&
148 0 : ( GRAPHIC_DEFAULT != aGrf.GetType() ||
149 0 : GRAPHIC_DEFAULT != rGrfObj.GetType() ) )
150 : {
151 0 : aGrfSz = ::GetGraphicSizeTwip( aGrf, 0 );
152 0 : if( static_cast< const SwGrfNode * >( pCntntNode )->IsChgTwipSizeFromPixel() )
153 : {
154 0 : const MapMode aMapTwip( MAP_TWIP );
155 : aFrmFmtSz =
156 : Application::GetDefaultDevice()->PixelToLogic(
157 0 : aGrf.GetSizePixel(), aMapTwip );
158 :
159 : }
160 : else
161 : {
162 0 : aFrmFmtSz = aGrfSz;
163 : }
164 0 : Size aSz( ((SwGrfNode*)pCntntNode)->GetTwipSize() );
165 :
166 0 : if( bGraphicPieceArrived && GRAPHIC_DEFAULT != aGrf.GetType() &&
167 0 : ( !aSz.Width() || !aSz.Height() ) )
168 : {
169 : // If only a part arrives, but the size is not set
170 : // we need to go through bGraphicArrived down there.
171 : // Or else the graphic is painted at its definitive size
172 0 : bGraphicArrived = sal_True;
173 0 : bGraphicPieceArrived = sal_False;
174 : }
175 :
176 0 : rGrfObj.SetGraphic( aGrf, rGrfObj.GetLink() );
177 0 : bUpdate = true;
178 :
179 : // In order for the Node to have the right transparency status
180 : // without having to access the graphic.
181 : // Or else we cause a SwapIn.
182 0 : if( bGraphicArrived )
183 : {
184 : // Always use the correct graphic size
185 0 : if( aGrfSz.Height() && aGrfSz.Width() &&
186 0 : aSz.Height() && aSz.Width() &&
187 0 : aGrfSz != aSz )
188 0 : ((SwGrfNode*)pCntntNode)->SetTwipSize( aGrfSz );
189 : }
190 : }
191 0 : if ( bUpdate && !bGraphicArrived && !bGraphicPieceArrived )
192 0 : ((SwGrfNode*)pCntntNode)->SetTwipSize( Size(0,0) );
193 : }
194 0 : else if( pCntntNode->IsOLENode() )
195 0 : bUpdate = true;
196 :
197 0 : ViewShell *pSh = 0;
198 0 : SwEditShell* pESh = pDoc->GetEditShell( &pSh );
199 :
200 0 : if ( bUpdate && bGraphicPieceArrived && !(bSwapIn || bDontNotify) )
201 : {
202 : // Send hint without Actions; triggers direct paint
203 0 : if ( (!pSh || !pSh->ActionPend()) && (!pESh || !pESh->ActionPend()) )
204 : {
205 0 : SwMsgPoolItem aMsgHint( RES_GRAPHIC_PIECE_ARRIVED );
206 0 : pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint );
207 0 : bUpdate = false;
208 : }
209 : }
210 :
211 : static bool bInNotifyLinks = false;
212 0 : if( bUpdate && !bDontNotify && (!bSwapIn || bGraphicArrived) &&
213 0 : !bInNotifyLinks)
214 : {
215 0 : sal_Bool bLockView = sal_False;
216 0 : if( pSh )
217 : {
218 0 : bLockView = pSh->IsViewLocked();
219 0 : pSh->LockView( sal_True );
220 : }
221 :
222 0 : if( pESh )
223 0 : pESh->StartAllAction();
224 0 : else if( pSh )
225 0 : pSh->StartAction();
226 :
227 : SwMsgPoolItem aMsgHint( static_cast<sal_uInt16>(
228 0 : bGraphicArrived ? RES_GRAPHIC_ARRIVED : RES_UPDATE_ATTR ) );
229 :
230 0 : if ( bGraphicArrived )
231 : {
232 : // Notify all who are listening at the same link
233 0 : bInNotifyLinks = true;
234 :
235 0 : const ::sfx2::SvBaseLinks& rLnks = pDoc->GetLinkManager().GetLinks();
236 0 : for( sal_uInt16 n = rLnks.size(); n; )
237 : {
238 0 : ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]);
239 0 : if( pLnk && OBJECT_CLIENT_GRF == pLnk->GetObjType() &&
240 0 : pLnk->ISA( SwBaseLink ) && pLnk->GetObj() == GetObj() )
241 : {
242 0 : SwBaseLink* pBLink = (SwBaseLink*)pLnk;
243 0 : SwGrfNode* pGrfNd = (SwGrfNode*)pBLink->pCntntNode;
244 :
245 0 : if( pBLink != this &&
246 0 : ( !bSwapIn ||
247 0 : GRAPHIC_DEFAULT == pGrfNd->GetGrfObj().GetType()))
248 : {
249 0 : pBLink->bIgnoreDataChanged = sal_False;
250 0 : pBLink->DataChanged( rMimeType, rValue );
251 0 : pBLink->bIgnoreDataChanged = sal_True;
252 :
253 : pGrfNd->SetGrafikArrived( ((SwGrfNode*)pCntntNode)->
254 0 : IsGrafikArrived() );
255 :
256 : // Adjust the Fly's graphic
257 0 : if( !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) )
258 0 : ::lcl_CallModify( *pGrfNd, aMsgHint );
259 : }
260 0 : else if( pBLink == this &&
261 0 : !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) )
262 : // Adjust the Fly's graphic
263 0 : ::lcl_CallModify( *pGrfNd, aMsgHint );
264 : }
265 : }
266 :
267 0 : bInNotifyLinks = false;
268 : }
269 : else
270 : {
271 0 : pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint );
272 : }
273 :
274 :
275 0 : if( pESh )
276 : {
277 0 : const sal_Bool bEndActionByVirDev = pESh->IsEndActionByVirDev();
278 0 : pESh->SetEndActionByVirDev( sal_True );
279 0 : pESh->EndAllAction();
280 0 : pESh->SetEndActionByVirDev( bEndActionByVirDev );
281 : }
282 0 : else if( pSh )
283 0 : pSh->EndAction();
284 :
285 0 : if( pSh && !bLockView )
286 0 : pSh->LockView( sal_False );
287 : }
288 :
289 0 : return SUCCESS;
290 : }
291 :
292 0 : sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd )
293 : {
294 0 : sal_Bool bRet = sal_False;
295 : ViewShell *pSh;
296 0 : CurrShell *pCurr = 0;
297 0 : if ( pGrfNd->GetDoc()->GetEditShell( &pSh ) )
298 0 : pCurr = new CurrShell( pSh );
299 :
300 0 : Size aSz = pGrfNd->GetTwipSize();
301 0 : if ( !(aSz.Width() && aSz.Height()) &&
302 0 : rGrfSz.Width() && rGrfSz.Height() )
303 : {
304 : SwFrmFmt* pFmt;
305 0 : if( pGrfNd->IsChgTwipSize() &&
306 0 : 0 != (pFmt = pGrfNd->GetFlyFmt()) )
307 : {
308 0 : Size aCalcSz( aSz );
309 0 : if ( !aSz.Height() && aSz.Width() )
310 : // Calculate the right height
311 0 : aCalcSz.Height() = rFrmSz.Height() *
312 0 : aSz.Width() / rFrmSz.Width();
313 0 : else if ( !aSz.Width() && aSz.Height() )
314 : // Calculate the right width
315 0 : aCalcSz.Width() = rFrmSz.Width() *
316 0 : aSz.Height() / rFrmSz.Height();
317 : else
318 : // Take over height and width
319 0 : aCalcSz = rFrmSz;
320 :
321 0 : const SvxBoxItem &rBox = pFmt->GetBox();
322 0 : aCalcSz.Width() += rBox.CalcLineSpace(BOX_LINE_LEFT) +
323 0 : rBox.CalcLineSpace(BOX_LINE_RIGHT);
324 0 : aCalcSz.Height()+= rBox.CalcLineSpace(BOX_LINE_TOP) +
325 0 : rBox.CalcLineSpace(BOX_LINE_BOTTOM);
326 0 : const SwFmtFrmSize& rOldAttr = pFmt->GetFrmSize();
327 0 : if( rOldAttr.GetSize() != aCalcSz )
328 : {
329 0 : SwFmtFrmSize aAttr( rOldAttr );
330 0 : aAttr.SetSize( aCalcSz );
331 0 : pFmt->SetFmtAttr( aAttr );
332 0 : bRet = sal_True;
333 : }
334 :
335 0 : if( !aSz.Width() )
336 : {
337 : // If the graphic is anchored in a table, we need to recalculate
338 : // the table rows
339 0 : const SwDoc *pDoc = pGrfNd->GetDoc();
340 0 : const SwPosition* pAPos = pFmt->GetAnchor().GetCntntAnchor();
341 : SwNode *pANd;
342 : SwTableNode *pTblNd;
343 0 : if( pAPos &&
344 0 : 0 != (pANd = & pAPos->nNode.GetNode()) &&
345 : 0 != (pTblNd = pANd->FindTableNode()) )
346 : {
347 0 : const sal_Bool bLastGrf = !pTblNd->GetTable().DecGrfsThatResize();
348 : SwHTMLTableLayout *pLayout =
349 0 : pTblNd->GetTable().GetHTMLTableLayout();
350 0 : if( pLayout )
351 : {
352 : const sal_uInt16 nBrowseWidth =
353 0 : pLayout->GetBrowseWidthByTable( *pDoc );
354 0 : if ( nBrowseWidth )
355 : {
356 : pLayout->Resize( nBrowseWidth, sal_True, sal_True,
357 : bLastGrf ? HTMLTABLE_RESIZE_NOW
358 0 : : 500 );
359 : }
360 : }
361 : }
362 : }
363 : }
364 :
365 : // SetTwipSize rescales an ImageMap if needed for which
366 : // it requires the Frame Format
367 0 : pGrfNd->SetTwipSize( rGrfSz );
368 : }
369 :
370 0 : delete pCurr;
371 :
372 0 : return bRet;
373 : }
374 :
375 :
376 0 : sal_Bool SwBaseLink::SwapIn( sal_Bool bWaitForData, sal_Bool bNativFormat )
377 : {
378 0 : bSwapIn = sal_True;
379 :
380 : sal_Bool bRes;
381 :
382 0 : if( !GetObj() && ( bNativFormat || ( !IsSynchron() && bWaitForData ) ))
383 : {
384 0 : AddNextRef();
385 0 : _GetRealObject();
386 0 : ReleaseRef();
387 : }
388 :
389 : #if OSL_DEBUG_LEVEL > 1
390 : {
391 : String sGrfNm;
392 : if(GetLinkManager())
393 : GetLinkManager()->GetDisplayNames( this, 0, &sGrfNm, 0, 0 );
394 : int x = 0;
395 : ++x;
396 : }
397 : #endif
398 :
399 0 : if( GetObj() )
400 : {
401 0 : String aMimeType( SotExchange::GetFormatMimeType( GetContentType() ));
402 0 : uno::Any aValue;
403 0 : GetObj()->GetData( aValue, aMimeType, !IsSynchron() && bWaitForData );
404 :
405 0 : if( bWaitForData && !GetObj() )
406 : {
407 : OSL_ENSURE( !this, "The SvxFileObject was deleted in a GetData!" );
408 0 : bRes = sal_False;
409 : }
410 0 : else if( 0 != ( bRes = aValue.hasValue() ) )
411 : {
412 : // The Flag needs to be reset on a SwapIn, because
413 : // we want to reapply the data.
414 0 : bIgnoreDataChanged = sal_False;
415 0 : DataChanged( aMimeType, aValue );
416 0 : }
417 : }
418 0 : else if( !IsSynchron() && bWaitForData )
419 : {
420 0 : SetSynchron( sal_True );
421 0 : bRes = Update();
422 0 : SetSynchron( sal_False );
423 : }
424 : else
425 0 : bRes = Update();
426 :
427 0 : bSwapIn = sal_False;
428 0 : return bRes;
429 : }
430 :
431 0 : void SwBaseLink::Closed()
432 : {
433 0 : if( pCntntNode && !pCntntNode->GetDoc()->IsInDtor() )
434 : {
435 : // Delete the connection
436 0 : if( pCntntNode->IsGrfNode() )
437 0 : ((SwGrfNode*)pCntntNode)->ReleaseLink();
438 : }
439 0 : SvBaseLink::Closed();
440 0 : }
441 :
442 0 : const SwNode* SwBaseLink::GetAnchor() const
443 : {
444 0 : if (pCntntNode)
445 : {
446 0 : SwFrmFmt *const pFmt = pCntntNode->GetFlyFmt();
447 0 : if (pFmt)
448 : {
449 0 : const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
450 0 : SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
451 0 : if (pAPos &&
452 0 : ((FLY_AS_CHAR == rAnchor.GetAnchorId()) ||
453 0 : (FLY_AT_CHAR == rAnchor.GetAnchorId()) ||
454 0 : (FLY_AT_FLY == rAnchor.GetAnchorId()) ||
455 0 : (FLY_AT_PARA == rAnchor.GetAnchorId())))
456 : {
457 0 : return &pAPos->nNode.GetNode();
458 : }
459 0 : return 0;
460 : }
461 : }
462 :
463 : OSL_ENSURE( !this, "GetAnchor is not shadowed" );
464 0 : return 0;
465 : }
466 :
467 0 : sal_Bool SwBaseLink::IsRecursion( const SwBaseLink* pChkLnk ) const
468 : {
469 0 : SwServerObjectRef aRef( (SwServerObject*)GetObj() );
470 0 : if( aRef.Is() )
471 : {
472 : // As it's a ServerObject, we query all contained Links
473 : // if we are contained in them. Else we have a recursion.
474 0 : return aRef->IsLinkInServer( pChkLnk );
475 : }
476 0 : return sal_False;
477 : }
478 :
479 0 : sal_Bool SwBaseLink::IsInRange( sal_uLong, sal_uLong, xub_StrLen, xub_StrLen ) const
480 : {
481 : // Not Graphic or OLE Links
482 : // Fields or Sections have their own derivation!
483 0 : return sal_False;
484 : }
485 :
486 2 : SwBaseLink::~SwBaseLink()
487 : {
488 2 : }
489 :
490 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|