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