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