xref: /trunk/main/sw/source/core/docnode/swbaslnk.cxx (revision 2f121198)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include <hintids.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/outdev.hxx>
34 
35 #include <osl/thread.hxx>
36 #include <salhelper/condition.hxx>
37 #include <comphelper/mediadescriptor.hxx>
38 #include <sfx2/docfile.hxx>
39 #include <sfx2/lnkbase.hxx>
40 #include <sfx2/linkmgr.hxx>
41 #include <sfx2/objsh.hxx>
42 #include <editeng/boxitem.hxx>
43 #ifndef _SVX_SVXIDS_HRC
44 #include <svx/svxids.hrc>		// fuer die EventIds
45 #endif
46 #include <sfx2/linkmgr.hxx>
47 #include <svtools/soerr.hxx>
48 #include <fmtfsize.hxx>
49 #include <fmtanchr.hxx>
50 #include <frmatr.hxx>
51 #include <frmfmt.hxx>
52 #include <doc.hxx>
53 #include <pam.hxx>
54 #include <editsh.hxx>
55 #include <swtable.hxx>
56 #include <docary.hxx>
57 #include <swevent.hxx>
58 #include <swbaslnk.hxx>
59 #include <swserv.hxx>
60 #include <ndgrf.hxx>
61 #include <ndole.hxx>
62 #include <hints.hxx>
63 #include <tabfrm.hxx>
64 #include <cntfrm.hxx>
65 #include <htmltbl.hxx>
66 
67 using namespace com::sun::star;
68 
69 sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd );
70 
71 TYPEINIT1( SwBaseLink, ::sfx2::SvBaseLink );
72 
73 SV_IMPL_REF( SwServerObject )
74 
75 void lcl_CallModify( SwGrfNode& rGrfNd, SfxPoolItem& rItem )
76 {
77 	//JP 4.7.2001: call fist all not SwNoTxtFrames, then the SwNoTxtFrames.
78 	//				The reason is, that in the SwNoTxtFrames the Graphic
79 	//				after a Paint will be swapped out! So all other "behind"
80 	//				them havent't a loaded Graphic. - #86501#
81 	rGrfNd.LockModify();
82 
83 	SwClientIter aIter( rGrfNd );   // TODO
84 	for( int n = 0; n < 2; ++n )
85 	{
86 		SwClient * pLast = aIter.GoStart();
87 		if( pLast ) 	// konnte zum Anfang gesprungen werden ??
88 		{
89 			do {
90 				if( (0 == n) ^ ( 0 != pLast->ISA( SwCntntFrm )) )
91 					pLast->ModifyNotification( &rItem, &rItem );
92 			} while( 0 != ( pLast = ++aIter ));
93 		}
94 	}
95 	rGrfNd.UnlockModify();
96 }
97 
98 
99 void SwBaseLink::DataChanged( const String& rMimeType,
100                             const uno::Any & rValue )
101 {
102 	if( !pCntntNode )
103 	{
104 		ASSERT(!this, "DataChanged ohne ContentNode" );
105 		return ;
106 	}
107 
108 	SwDoc* pDoc = pCntntNode->GetDoc();
109 	if( pDoc->IsInDtor() || ChkNoDataFlag() || bIgnoreDataChanged )
110 	{
111 		bIgnoreDataChanged = sal_False;
112 		return ;
113 	}
114 
115 	sal_uLong nFmt = SotExchange::GetFormatIdFromMimeType( rMimeType );
116 
117 	if( pCntntNode->IsNoTxtNode() &&
118 		nFmt == sfx2::LinkManager::RegisterStatusInfoId() )
119 	{
120 		// nur eine Statusaenderung - Events bedienen ?
121 		::rtl::OUString sState;
122 		if( rValue.hasValue() && ( rValue >>= sState ))
123 		{
124 			sal_uInt16 nEvent = 0;
125 			switch( sState.toInt32() )
126 			{
127 			case sfx2::LinkManager::STATE_LOAD_OK:		nEvent = SVX_EVENT_IMAGE_LOAD;	break;
128 			case sfx2::LinkManager::STATE_LOAD_ERROR: 	nEvent = SVX_EVENT_IMAGE_ERROR;	break;
129 			case sfx2::LinkManager::STATE_LOAD_ABORT: 	nEvent = SVX_EVENT_IMAGE_ABORT;	break;
130 			}
131 
132 			SwFrmFmt* pFmt;
133 			if( nEvent && 0 != ( pFmt = pCntntNode->GetFlyFmt() ))
134 			{
135 				SwCallMouseEvent aCallEvent;
136 				aCallEvent.Set( EVENT_OBJECT_IMAGE, pFmt );
137 				pDoc->CallEvent( nEvent, aCallEvent );
138 			}
139 		}
140 		return;			// das wars!
141 	}
142 
143 	sal_Bool bUpdate = sal_False;
144 	sal_Bool bGraphicArrived = sal_False;
145 	sal_Bool bGraphicPieceArrived = sal_False;
146 	sal_Bool bDontNotify = sal_False;
147 	Size aGrfSz, aFrmFmtSz;
148 
149 	if( pCntntNode->IsGrfNode() )
150 	{
151 		GraphicObject& rGrfObj = ((SwGrfNode*)pCntntNode)->GetGrfObj();
152 
153 		bDontNotify = ((SwGrfNode*)pCntntNode)->IsFrameInPaint();
154 
155 		bGraphicArrived = GetObj()->IsDataComplete();
156 		bGraphicPieceArrived = GetObj()->IsPending();
157 		((SwGrfNode*)pCntntNode)->SetGrafikArrived( bGraphicArrived );
158 
159 		Graphic aGrf;
160 		if( sfx2::LinkManager::GetGraphicFromAny( rMimeType, rValue, aGrf ) &&
161 			( GRAPHIC_DEFAULT != aGrf.GetType() ||
162 			  GRAPHIC_DEFAULT != rGrfObj.GetType() ) )
163 		{
164 			aGrfSz = ::GetGraphicSizeTwip( aGrf, 0 );
165 			if( static_cast< const SwGrfNode * >( pCntntNode )->IsChgTwipSizeFromPixel() )
166 			{
167 				const MapMode aMapTwip( MAP_TWIP );
168 				aFrmFmtSz =
169 					Application::GetDefaultDevice()->PixelToLogic(
170 						aGrf.GetSizePixel(), aMapTwip );
171 
172 			}
173 			else
174 			{
175 				aFrmFmtSz = aGrfSz;
176 			}
177 			Size aSz( ((SwGrfNode*)pCntntNode)->GetTwipSize() );
178 
179 			if( bGraphicPieceArrived && GRAPHIC_DEFAULT != aGrf.GetType() &&
180 				( !aSz.Width() || !aSz.Height() ) )
181 			{
182 				// wenn nur ein Teil ankommt, aber die Groesse nicht
183 				// gesetzt ist, dann muss "unten" der Teil von
184 				// bGraphicArrived durchlaufen werden!
185 				// (ansonten wird die Grafik in deft. Size gepaintet)
186 				bGraphicArrived = sal_True;
187 				bGraphicPieceArrived = sal_False;
188 			}
189 
190 			rGrfObj.SetGraphic( aGrf, rGrfObj.GetLink() );
191 			bUpdate = sal_True;
192 
193 			// Bug 33999: damit der Node den Transparent-Status
194 			//		richtig gesetzt hat, ohne auf die Grafik
195 			//		zugreifen zu muessen (sonst erfolgt ein SwapIn!).
196 			if( bGraphicArrived )
197 			{
198 				// Bug #34735#: immer mit der korrekten Grafik-Size
199 				//				arbeiten
200 				if( aGrfSz.Height() && aGrfSz.Width() &&
201 					aSz.Height() && aSz.Width() &&
202 					aGrfSz != aSz )
203 					((SwGrfNode*)pCntntNode)->SetTwipSize( aGrfSz );
204 			}
205 		}
206 		if ( bUpdate && !bGraphicArrived && !bGraphicPieceArrived )
207 			((SwGrfNode*)pCntntNode)->SetTwipSize( Size(0,0) );
208 	}
209 	else if( pCntntNode->IsOLENode() )
210 		bUpdate = sal_True;
211 
212 	ViewShell *pSh = 0;
213 	SwEditShell* pESh = pDoc->GetEditShell( &pSh );
214 
215 	if ( bUpdate && bGraphicPieceArrived && !(bSwapIn || bDontNotify) )
216 	{
217 		//Hint ohne Actions verschicken, loest direktes Paint aus.
218 		if ( (!pSh || !pSh->ActionPend()) && (!pESh || !pESh->ActionPend()) )
219 		{
220 			SwMsgPoolItem aMsgHint( RES_GRAPHIC_PIECE_ARRIVED );
221 			pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint );
222 			bUpdate = sal_False;
223 		}
224 	}
225 
226 	static sal_Bool bInNotifyLinks = sal_False;
227 	if( bUpdate && !bDontNotify && (!bSwapIn || bGraphicArrived) &&
228 		!bInNotifyLinks)
229 	{
230 		sal_Bool bLockView = sal_False;
231 		if( pSh )
232 		{
233 			bLockView = pSh->IsViewLocked();
234 			pSh->LockView( sal_True );
235 		}
236 
237 		if( pESh )
238 			pESh->StartAllAction();
239 		else if( pSh )
240 			pSh->StartAction();
241 
242 		SwMsgPoolItem aMsgHint( static_cast<sal_uInt16>(
243             bGraphicArrived ? RES_GRAPHIC_ARRIVED : RES_UPDATE_ATTR ) );
244 
245 		if ( bGraphicArrived )
246 		{
247 			//Alle benachrichtigen, die am gleichen Link horchen.
248 			bInNotifyLinks = sal_True;
249 
250             const ::sfx2::SvBaseLinks& rLnks = pDoc->GetLinkManager().GetLinks();
251 			for( sal_uInt16 n = rLnks.Count(); n; )
252 			{
253                 ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]);
254 				if( pLnk && OBJECT_CLIENT_GRF == pLnk->GetObjType() &&
255 					pLnk->ISA( SwBaseLink ) && pLnk->GetObj() == GetObj() )
256 				{
257 					SwBaseLink* pBLink = (SwBaseLink*)pLnk;
258 					SwGrfNode* pGrfNd = (SwGrfNode*)pBLink->pCntntNode;
259 
260 					if( pBLink != this &&
261 						( !bSwapIn ||
262 							GRAPHIC_DEFAULT == pGrfNd->GetGrfObj().GetType()))
263 					{
264 						pBLink->bIgnoreDataChanged = sal_False;
265 						pBLink->DataChanged( rMimeType, rValue );
266 						pBLink->bIgnoreDataChanged = sal_True;
267 
268 						pGrfNd->SetGrafikArrived( ((SwGrfNode*)pCntntNode)->
269 													IsGrafikArrived() );
270 
271 						// Fly der Grafik anpassen !
272 						if( !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) )
273 							::lcl_CallModify( *pGrfNd, aMsgHint );
274 					}
275 					else if( pBLink == this &&
276 							!::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) )
277 						// Fly der Grafik anpassen !
278 						::lcl_CallModify( *pGrfNd, aMsgHint );
279 				}
280 			}
281 
282 			bInNotifyLinks = sal_False;
283 		}
284 		else
285 		{
286 			pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint );
287 		}
288 
289 
290 		if( pESh )
291 		{
292 			const sal_Bool bEndActionByVirDev = pESh->IsEndActionByVirDev();
293 			pESh->SetEndActionByVirDev( sal_True );
294 			pESh->EndAllAction();
295 			pESh->SetEndActionByVirDev( bEndActionByVirDev );
296 		}
297 		else if( pSh )
298 			pSh->EndAction();
299 
300 		if( pSh && !bLockView )
301 			pSh->LockView( sal_False );
302 	}
303 }
304 
305 sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd )
306 {
307 	sal_Bool bRet = sal_False;
308 	ViewShell *pSh;
309 	CurrShell *pCurr = 0;
310 	if ( pGrfNd->GetDoc()->GetEditShell( &pSh ) )
311 		pCurr = new CurrShell( pSh );
312 
313 	Size aSz = pGrfNd->GetTwipSize();
314 	if ( !(aSz.Width() && aSz.Height()) &&
315 			rGrfSz.Width() && rGrfSz.Height() )
316 	{
317 		SwFrmFmt* pFmt;
318 		if( pGrfNd->IsChgTwipSize() &&
319 			0 != (pFmt = pGrfNd->GetFlyFmt()) )
320 		{
321 			Size aCalcSz( aSz );
322 			if ( !aSz.Height() && aSz.Width() )
323 				//passende Hoehe ausrechnen.
324 				aCalcSz.Height() = rFrmSz.Height() *
325 						aSz.Width() / rFrmSz.Width();
326 			else if ( !aSz.Width() && aSz.Height() )
327 				//passende Breite ausrechnen
328 				aCalcSz.Width() = rFrmSz.Width() *
329 						aSz.Height() / rFrmSz.Height();
330 			else
331 				//Hoehe und Breite uebernehmen
332 				aCalcSz = rFrmSz;
333 
334 			const SvxBoxItem 	 &rBox = pFmt->GetBox();
335 			aCalcSz.Width() += rBox.CalcLineSpace(BOX_LINE_LEFT) +
336 							   rBox.CalcLineSpace(BOX_LINE_RIGHT);
337 			aCalcSz.Height()+= rBox.CalcLineSpace(BOX_LINE_TOP) +
338 							   rBox.CalcLineSpace(BOX_LINE_BOTTOM);
339 			const SwFmtFrmSize& rOldAttr = pFmt->GetFrmSize();
340 			if( rOldAttr.GetSize() != aCalcSz )
341 			{
342 				SwFmtFrmSize aAttr( rOldAttr  );
343 				aAttr.SetSize( aCalcSz );
344                 pFmt->SetFmtAttr( aAttr );
345 				bRet = sal_True;
346 			}
347 
348 			if( !aSz.Width() )
349 			{
350 				// Wenn die Grafik in einer Tabelle verankert ist, muess
351 				// die Tabellen-Spalten neu berechnet werden
352 				const SwDoc *pDoc = pGrfNd->GetDoc();
353 				const SwPosition* pAPos = pFmt->GetAnchor().GetCntntAnchor();
354 				SwNode *pANd;
355 				SwTableNode *pTblNd;
356 				if( pAPos &&
357                     0 != (pANd = & pAPos->nNode.GetNode()) &&
358 					0 != (pTblNd = pANd->FindTableNode()) )
359 				{
360                     const sal_Bool bLastGrf = !pTblNd->GetTable().DecGrfsThatResize();
361 					SwHTMLTableLayout *pLayout =
362 						pTblNd->GetTable().GetHTMLTableLayout();
363 					if(	pLayout )
364 					{
365                         const sal_uInt16 nBrowseWidth =
366                                     pLayout->GetBrowseWidthByTable( *pDoc );
367                         if ( nBrowseWidth )
368                         {
369 							pLayout->Resize( nBrowseWidth, sal_True, sal_True,
370 											 bLastGrf ? HTMLTABLE_RESIZE_NOW
371 													  : 500 );
372                         }
373 					}
374 				}
375 			}
376 		}
377 
378 		// SetTwipSize skaliert ggf. eine ImageMap neu und
379 		// braucht dazu das Frame-Format
380 		pGrfNd->SetTwipSize( rGrfSz );
381 	}
382 
383 	delete pCurr;
384 
385 	return bRet;
386 }
387 
388 
389 sal_Bool SwBaseLink::SwapIn( sal_Bool bWaitForData, sal_Bool bNativFormat )
390 {
391 	bSwapIn = sal_True;
392 
393 	sal_Bool bRes;
394 
395 	if( !GetObj() && ( bNativFormat || ( !IsSynchron() && bWaitForData ) ))
396 	{
397 		AddNextRef();
398 		_GetRealObject();
399 		ReleaseRef();
400 	}
401 
402 #if OSL_DEBUG_LEVEL > 1
403 	{
404 		String sGrfNm;
405 		if(GetLinkManager())
406 			GetLinkManager()->GetDisplayNames( this, 0, &sGrfNm, 0, 0 );
407 		int x = 0;
408         ++x;
409 	}
410 #endif
411 
412     if( GetObj() )
413 	{
414         String aMimeType( SotExchange::GetFormatMimeType( GetContentType() ));
415         uno::Any aValue;
416 		GetObj()->GetData( aValue, aMimeType, !IsSynchron() && bWaitForData );
417 
418 		if( bWaitForData && !GetObj() )
419 		{
420 			ASSERT( !this, "das SvxFileObject wurde in einem GetData geloescht!" );
421 			bRes = sal_False;
422 		}
423 		else if( 0 != ( bRes = aValue.hasValue() ) )
424 		{
425 			//JP 14.04.99: Bug 64820 - das Flag muss beim SwapIn natuerlich
426 			//				zurueckgesetzt werden. Die Daten sollen ja neu
427 			//				uebernommen werden
428 			bIgnoreDataChanged = sal_False;
429 			DataChanged( aMimeType, aValue );
430 		}
431 	}
432 	else if( !IsSynchron() && bWaitForData )
433 	{
434 		SetSynchron( sal_True );
435 		bRes = Update();
436 		SetSynchron( sal_False );
437 	}
438 	else
439 		bRes = Update();
440 
441 	bSwapIn = sal_False;
442     return bRes;
443 }
444 
445 void SwBaseLink::Closed()
446 {
447 	if( pCntntNode && !pCntntNode->GetDoc()->IsInDtor() )
448 	{
449 		// wir heben die Verbindung auf
450 		if( pCntntNode->IsGrfNode() )
451 			((SwGrfNode*)pCntntNode)->ReleaseLink();
452 	}
453 	SvBaseLink::Closed();
454 }
455 
456 const SwNode* SwBaseLink::GetAnchor() const
457 {
458     if (pCntntNode)
459     {
460         SwFrmFmt *const pFmt = pCntntNode->GetFlyFmt();
461         if (pFmt)
462         {
463             const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
464             SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
465             if (pAPos &&
466                 ((FLY_AS_CHAR == rAnchor.GetAnchorId()) ||
467                  (FLY_AT_CHAR == rAnchor.GetAnchorId()) ||
468                  (FLY_AT_FLY  == rAnchor.GetAnchorId()) ||
469                  (FLY_AT_PARA == rAnchor.GetAnchorId())))
470             {
471                     return &pAPos->nNode.GetNode();
472             }
473             return 0;
474         }
475     }
476 
477 	ASSERT( !this, "GetAnchor nicht ueberlagert" );
478 	return 0;
479 }
480 
481 sal_Bool SwBaseLink::IsRecursion( const SwBaseLink* pChkLnk ) const
482 {
483 	SwServerObjectRef aRef( (SwServerObject*)GetObj() );
484 	if( aRef.Is() )
485 	{
486 		// es ist ein ServerObject, also frage nach allen darin
487 		// befindlichen Links, ob wir darin enthalten sind. Ansonsten
488 		// handelt es sich um eine Rekursion.
489 		return aRef->IsLinkInServer( pChkLnk );
490 	}
491 	return sal_False;
492 }
493 
494 sal_Bool SwBaseLink::IsInRange( sal_uLong, sal_uLong, xub_StrLen, xub_StrLen ) const
495 {
496 	// Grafik oder OLE-Links nicht,
497 	// Felder oder Sections haben eigene Ableitung!
498 	return sal_False;
499 }
500 
501 SwBaseLink::~SwBaseLink()
502 {
503 }
504