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