/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd ); TYPEINIT1( SwBaseLink, ::sfx2::SvBaseLink ); SV_IMPL_REF( SwServerObject ) static void lcl_CallModify( SwGrfNode& rGrfNd, SfxPoolItem& rItem ) { //call fist all not SwNoTxtFrames, then the SwNoTxtFrames. // The reason is, that in the SwNoTxtFrames the Graphic // after a Paint will be swapped out! So all other "behind" // them havent't a loaded Graphic. rGrfNd.LockModify(); SwClientIter aIter( rGrfNd ); // TODO for( int n = 0; n < 2; ++n ) { SwClient * pLast = aIter.GoStart(); if( pLast ) // Were we able to jump to the beginning? { do { if( (0 == n) ^ ( 0 != pLast->ISA( SwCntntFrm )) ) pLast->ModifyNotification( &rItem, &rItem ); } while( 0 != ( pLast = ++aIter )); } } rGrfNd.UnlockModify(); } ::sfx2::SvBaseLink::UpdateResult SwBaseLink::DataChanged( const OUString& rMimeType, const uno::Any & rValue ) { if( !pCntntNode ) { OSL_ENSURE(!this, "DataChanged without ContentNode" ); return ERROR_GENERAL; } SwDoc* pDoc = pCntntNode->GetDoc(); if( pDoc->IsInDtor() || ChkNoDataFlag() || bIgnoreDataChanged ) { bIgnoreDataChanged = sal_False; return SUCCESS; } sal_uLong nFmt = SotExchange::GetFormatIdFromMimeType( rMimeType ); if( pCntntNode->IsNoTxtNode() && nFmt == sfx2::LinkManager::RegisterStatusInfoId() ) { // Only a status change - serve Events? OUString sState; if( rValue.hasValue() && ( rValue >>= sState )) { sal_uInt16 nEvent = 0; switch( sState.toInt32() ) { case sfx2::LinkManager::STATE_LOAD_OK: nEvent = SVX_EVENT_IMAGE_LOAD; break; case sfx2::LinkManager::STATE_LOAD_ERROR: nEvent = SVX_EVENT_IMAGE_ERROR; break; case sfx2::LinkManager::STATE_LOAD_ABORT: nEvent = SVX_EVENT_IMAGE_ABORT; break; } SwFrmFmt* pFmt; if( nEvent && 0 != ( pFmt = pCntntNode->GetFlyFmt() )) { SwCallMouseEvent aCallEvent; aCallEvent.Set( EVENT_OBJECT_IMAGE, pFmt ); pDoc->CallEvent( nEvent, aCallEvent ); } } return SUCCESS; // That's it! } bool bUpdate = false; sal_Bool bGraphicArrived = sal_False; sal_Bool bGraphicPieceArrived = sal_False; sal_Bool bDontNotify = sal_False; Size aGrfSz, aFrmFmtSz; if( pCntntNode->IsGrfNode() ) { SwGrfNode* pSwGrfNode = dynamic_cast< SwGrfNode* >(pCntntNode); OSL_ENSURE(pSwGrfNode, "Error, pSwGrfNode expected when node answers IsGrfNode() with true (!)"); const GraphicObject& rGrfObj = pSwGrfNode->GetGrfObj(); bDontNotify = pSwGrfNode->IsFrameInPaint(); bGraphicArrived = GetObj()->IsDataComplete(); bGraphicPieceArrived = GetObj()->IsPending(); pSwGrfNode->SetGrafikArrived( bGraphicArrived ); Graphic aGrf; if( sfx2::LinkManager::GetGraphicFromAny( rMimeType, rValue, aGrf ) && ( GRAPHIC_DEFAULT != aGrf.GetType() || GRAPHIC_DEFAULT != rGrfObj.GetType() ) ) { aGrfSz = ::GetGraphicSizeTwip( aGrf, 0 ); if( pSwGrfNode->IsChgTwipSizeFromPixel() ) { const MapMode aMapTwip( MAP_TWIP ); aFrmFmtSz = Application::GetDefaultDevice()->PixelToLogic( aGrf.GetSizePixel(), aMapTwip ); } else { aFrmFmtSz = aGrfSz; } Size aSz( pSwGrfNode->GetTwipSize() ); if( bGraphicPieceArrived && GRAPHIC_DEFAULT != aGrf.GetType() && ( !aSz.Width() || !aSz.Height() ) ) { // If only a part arrives, but the size is not set // we need to go through bGraphicArrived down there. // Or else the graphic is painted at its definitive size bGraphicArrived = sal_True; bGraphicPieceArrived = sal_False; } pSwGrfNode->SetGraphic(aGrf, rGrfObj.GetLink()); bUpdate = true; // In order for the Node to have the right transparency status // without having to access the graphic. // Or else we cause a SwapIn. if( bGraphicArrived ) { // Always use the correct graphic size if( aGrfSz.Height() && aGrfSz.Width() && aSz.Height() && aSz.Width() && aGrfSz != aSz ) pSwGrfNode->SetTwipSize( aGrfSz ); } } if ( bUpdate && !bGraphicArrived && !bGraphicPieceArrived ) pSwGrfNode->SetTwipSize( Size(0,0) ); } else if( pCntntNode->IsOLENode() ) bUpdate = true; SwViewShell *pSh = 0; SwEditShell* pESh = pDoc->GetEditShell( &pSh ); if ( bUpdate && bGraphicPieceArrived && !(bSwapIn || bDontNotify) ) { // Send hint without Actions; triggers direct paint if ( (!pSh || !pSh->ActionPend()) && (!pESh || !pESh->ActionPend()) ) { SwMsgPoolItem aMsgHint( RES_GRAPHIC_PIECE_ARRIVED ); pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint ); bUpdate = false; } } static bool bInNotifyLinks = false; if( bUpdate && !bDontNotify && (!bSwapIn || bGraphicArrived) && !bInNotifyLinks) { sal_Bool bLockView = sal_False; if( pSh ) { bLockView = pSh->IsViewLocked(); pSh->LockView( sal_True ); } if( pESh ) pESh->StartAllAction(); else if( pSh ) pSh->StartAction(); SwMsgPoolItem aMsgHint( static_cast( bGraphicArrived ? RES_GRAPHIC_ARRIVED : RES_UPDATE_ATTR ) ); if ( bGraphicArrived ) { // Notify all who are listening at the same link bInNotifyLinks = true; const ::sfx2::SvBaseLinks& rLnks = pDoc->GetLinkManager().GetLinks(); for( sal_uInt16 n = rLnks.size(); n; ) { ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]); if( pLnk && OBJECT_CLIENT_GRF == pLnk->GetObjType() && pLnk->ISA( SwBaseLink ) && pLnk->GetObj() == GetObj() ) { SwBaseLink* pBLink = (SwBaseLink*)pLnk; SwGrfNode* pGrfNd = (SwGrfNode*)pBLink->pCntntNode; if( pBLink != this && ( !bSwapIn || GRAPHIC_DEFAULT == pGrfNd->GetGrfObj().GetType())) { pBLink->bIgnoreDataChanged = sal_False; pBLink->DataChanged( rMimeType, rValue ); pBLink->bIgnoreDataChanged = sal_True; pGrfNd->SetGrafikArrived( ((SwGrfNode*)pCntntNode)-> IsGrafikArrived() ); // Adjust the Fly's graphic if( !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) ) ::lcl_CallModify( *pGrfNd, aMsgHint ); } else if( pBLink == this && !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) ) // Adjust the Fly's graphic ::lcl_CallModify( *pGrfNd, aMsgHint ); } } bInNotifyLinks = false; } else { pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint ); } if( pESh ) { const sal_Bool bEndActionByVirDev = pESh->IsEndActionByVirDev(); pESh->SetEndActionByVirDev( sal_True ); pESh->EndAllAction(); pESh->SetEndActionByVirDev( bEndActionByVirDev ); } else if( pSh ) pSh->EndAction(); if( pSh && !bLockView ) pSh->LockView( sal_False ); } return SUCCESS; } sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd ) { sal_Bool bRet = sal_False; SwViewShell *pSh; CurrShell *pCurr = 0; if ( pGrfNd->GetDoc()->GetEditShell( &pSh ) ) pCurr = new CurrShell( pSh ); Size aSz = pGrfNd->GetTwipSize(); if ( !(aSz.Width() && aSz.Height()) && rGrfSz.Width() && rGrfSz.Height() ) { SwFrmFmt* pFmt; if( pGrfNd->IsChgTwipSize() && 0 != (pFmt = pGrfNd->GetFlyFmt()) ) { Size aCalcSz( aSz ); if ( !aSz.Height() && aSz.Width() ) // Calculate the right height aCalcSz.Height() = rFrmSz.Height() * aSz.Width() / rFrmSz.Width(); else if ( !aSz.Width() && aSz.Height() ) // Calculate the right width aCalcSz.Width() = rFrmSz.Width() * aSz.Height() / rFrmSz.Height(); else // Take over height and width aCalcSz = rFrmSz; const SvxBoxItem &rBox = pFmt->GetBox(); aCalcSz.Width() += rBox.CalcLineSpace(BOX_LINE_LEFT) + rBox.CalcLineSpace(BOX_LINE_RIGHT); aCalcSz.Height()+= rBox.CalcLineSpace(BOX_LINE_TOP) + rBox.CalcLineSpace(BOX_LINE_BOTTOM); const SwFmtFrmSize& rOldAttr = pFmt->GetFrmSize(); if( rOldAttr.GetSize() != aCalcSz ) { SwFmtFrmSize aAttr( rOldAttr ); aAttr.SetSize( aCalcSz ); pFmt->SetFmtAttr( aAttr ); bRet = sal_True; } if( !aSz.Width() ) { // If the graphic is anchored in a table, we need to recalculate // the table rows const SwDoc *pDoc = pGrfNd->GetDoc(); const SwPosition* pAPos = pFmt->GetAnchor().GetCntntAnchor(); SwNode *pANd; SwTableNode *pTblNd; if( pAPos && 0 != (pANd = & pAPos->nNode.GetNode()) && 0 != (pTblNd = pANd->FindTableNode()) ) { const sal_Bool bLastGrf = !pTblNd->GetTable().DecGrfsThatResize(); SwHTMLTableLayout *pLayout = pTblNd->GetTable().GetHTMLTableLayout(); if( pLayout ) { const sal_uInt16 nBrowseWidth = pLayout->GetBrowseWidthByTable( *pDoc ); if ( nBrowseWidth ) { pLayout->Resize( nBrowseWidth, sal_True, sal_True, bLastGrf ? HTMLTABLE_RESIZE_NOW : 500 ); } } } } } // SetTwipSize rescales an ImageMap if needed for which // it requires the Frame Format pGrfNd->SetTwipSize( rGrfSz ); } delete pCurr; return bRet; } sal_Bool SwBaseLink::SwapIn( sal_Bool bWaitForData, sal_Bool bNativFormat ) { bSwapIn = sal_True; sal_Bool bRes; if( !GetObj() && ( bNativFormat || ( !IsSynchron() && bWaitForData ) )) { AddNextRef(); _GetRealObject(); ReleaseRef(); } #if OSL_DEBUG_LEVEL > 1 { OUString sGrfNm; if(GetLinkManager()) GetLinkManager()->GetDisplayNames( this, 0, &sGrfNm, 0, 0 ); int x = 0; ++x; } #endif if( GetObj() ) { OUString aMimeType( SotExchange::GetFormatMimeType( GetContentType() )); uno::Any aValue; GetObj()->GetData( aValue, aMimeType, !IsSynchron() && bWaitForData ); if( bWaitForData && !GetObj() ) { OSL_ENSURE( !this, "The SvxFileObject was deleted in a GetData!" ); bRes = sal_False; } else if( 0 != ( bRes = aValue.hasValue() ) ) { // The Flag needs to be reset on a SwapIn, because // we want to reapply the data. bIgnoreDataChanged = sal_False; DataChanged( aMimeType, aValue ); } } else if( !IsSynchron() && bWaitForData ) { SetSynchron( sal_True ); bRes = Update(); SetSynchron( sal_False ); } else bRes = Update(); bSwapIn = sal_False; return bRes; } void SwBaseLink::Closed() { if( pCntntNode && !pCntntNode->GetDoc()->IsInDtor() ) { // Delete the connection if( pCntntNode->IsGrfNode() ) ((SwGrfNode*)pCntntNode)->ReleaseLink(); } SvBaseLink::Closed(); } const SwNode* SwBaseLink::GetAnchor() const { if (pCntntNode) { SwFrmFmt *const pFmt = pCntntNode->GetFlyFmt(); if (pFmt) { const SwFmtAnchor& rAnchor = pFmt->GetAnchor(); SwPosition const*const pAPos = rAnchor.GetCntntAnchor(); if (pAPos && ((FLY_AS_CHAR == rAnchor.GetAnchorId()) || (FLY_AT_CHAR == rAnchor.GetAnchorId()) || (FLY_AT_FLY == rAnchor.GetAnchorId()) || (FLY_AT_PARA == rAnchor.GetAnchorId()))) { return &pAPos->nNode.GetNode(); } return 0; } } OSL_ENSURE( !this, "GetAnchor is not shadowed" ); return 0; } sal_Bool SwBaseLink::IsRecursion( const SwBaseLink* pChkLnk ) const { SwServerObjectRef aRef( (SwServerObject*)GetObj() ); if( aRef.Is() ) { // As it's a ServerObject, we query all contained Links // if we are contained in them. Else we have a recursion. return aRef->IsLinkInServer( pChkLnk ); } return sal_False; } sal_Bool SwBaseLink::IsInRange( sal_uLong, sal_uLong, sal_Int32, sal_Int32 ) const { // Not Graphic or OLE Links // Fields or Sections have their own derivation! return sal_False; } SwBaseLink::~SwBaseLink() { } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */