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