| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sw.hxx" |
| |
| #include <hintids.hxx> |
| #include <vcl/svapp.hxx> |
| #include <vcl/outdev.hxx> |
| |
| #include <osl/thread.hxx> |
| #include <salhelper/condition.hxx> |
| #include <comphelper/mediadescriptor.hxx> |
| #include <sfx2/docfile.hxx> |
| #include <sfx2/lnkbase.hxx> |
| #include <sfx2/linkmgr.hxx> |
| #include <sfx2/objsh.hxx> |
| #include <editeng/boxitem.hxx> |
| #ifndef _SVX_SVXIDS_HRC |
| #include <svx/svxids.hrc> // fuer die EventIds |
| #endif |
| #include <sfx2/linkmgr.hxx> |
| #include <svtools/soerr.hxx> |
| #include <fmtfsize.hxx> |
| #include <fmtanchr.hxx> |
| #include <frmatr.hxx> |
| #include <frmfmt.hxx> |
| #include <doc.hxx> |
| #include <pam.hxx> |
| #include <editsh.hxx> |
| #include <swtable.hxx> |
| #include <docary.hxx> |
| #include <swevent.hxx> |
| #include <swbaslnk.hxx> |
| #include <swserv.hxx> |
| #include <ndgrf.hxx> |
| #include <ndole.hxx> |
| #include <hints.hxx> |
| #include <tabfrm.hxx> |
| #include <cntfrm.hxx> |
| #include <htmltbl.hxx> |
| |
| using namespace com::sun::star; |
| |
| sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd ); |
| |
| TYPEINIT1( SwBaseLink, ::sfx2::SvBaseLink ); |
| |
| SV_IMPL_REF( SwServerObject ) |
| |
| void lcl_CallModify( SwGrfNode& rGrfNd, SfxPoolItem& rItem ) |
| { |
| //JP 4.7.2001: 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. - #86501# |
| rGrfNd.LockModify(); |
| |
| SwClientIter aIter( rGrfNd ); // TODO |
| for( int n = 0; n < 2; ++n ) |
| { |
| SwClient * pLast = aIter.GoStart(); |
| if( pLast ) // konnte zum Anfang gesprungen werden ?? |
| { |
| do { |
| if( (0 == n) ^ ( 0 != pLast->ISA( SwCntntFrm )) ) |
| pLast->ModifyNotification( &rItem, &rItem ); |
| } while( 0 != ( pLast = ++aIter )); |
| } |
| } |
| rGrfNd.UnlockModify(); |
| } |
| |
| |
| void SwBaseLink::DataChanged( const String& rMimeType, |
| const uno::Any & rValue ) |
| { |
| if( !pCntntNode ) |
| { |
| ASSERT(!this, "DataChanged ohne ContentNode" ); |
| return ; |
| } |
| |
| SwDoc* pDoc = pCntntNode->GetDoc(); |
| if( pDoc->IsInDtor() || ChkNoDataFlag() || bIgnoreDataChanged ) |
| { |
| bIgnoreDataChanged = sal_False; |
| return ; |
| } |
| |
| sal_uLong nFmt = SotExchange::GetFormatIdFromMimeType( rMimeType ); |
| |
| if( pCntntNode->IsNoTxtNode() && |
| nFmt == sfx2::LinkManager::RegisterStatusInfoId() ) |
| { |
| // nur eine Statusaenderung - Events bedienen ? |
| ::rtl::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; // das wars! |
| } |
| |
| sal_Bool bUpdate = sal_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() ) ) |
| { |
| // wenn nur ein Teil ankommt, aber die Groesse nicht |
| // gesetzt ist, dann muss "unten" der Teil von |
| // bGraphicArrived durchlaufen werden! |
| // (ansonten wird die Grafik in deft. Size gepaintet) |
| bGraphicArrived = sal_True; |
| bGraphicPieceArrived = sal_False; |
| } |
| |
| pSwGrfNode->SetGraphic(aGrf, rGrfObj.GetLink()); |
| bUpdate = sal_True; |
| |
| // Bug 33999: damit der Node den Transparent-Status |
| // richtig gesetzt hat, ohne auf die Grafik |
| // zugreifen zu muessen (sonst erfolgt ein SwapIn!). |
| if( bGraphicArrived ) |
| { |
| // Bug #34735#: immer mit der korrekten Grafik-Size |
| // arbeiten |
| 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 = sal_True; |
| |
| ViewShell *pSh = 0; |
| SwEditShell* pESh = pDoc->GetEditShell( &pSh ); |
| |
| if ( bUpdate && bGraphicPieceArrived && !(bSwapIn || bDontNotify) ) |
| { |
| //Hint ohne Actions verschicken, loest direktes Paint aus. |
| if ( (!pSh || !pSh->ActionPend()) && (!pESh || !pESh->ActionPend()) ) |
| { |
| SwMsgPoolItem aMsgHint( RES_GRAPHIC_PIECE_ARRIVED ); |
| pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint ); |
| bUpdate = sal_False; |
| } |
| } |
| |
| static sal_Bool bInNotifyLinks = sal_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<sal_uInt16>( |
| bGraphicArrived ? RES_GRAPHIC_ARRIVED : RES_UPDATE_ATTR ) ); |
| |
| if ( bGraphicArrived ) |
| { |
| //Alle benachrichtigen, die am gleichen Link horchen. |
| bInNotifyLinks = sal_True; |
| |
| const ::sfx2::SvBaseLinks& rLnks = pDoc->GetLinkManager().GetLinks(); |
| for( sal_uInt16 n = rLnks.Count(); 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() ); |
| |
| // Fly der Grafik anpassen ! |
| if( !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) ) |
| ::lcl_CallModify( *pGrfNd, aMsgHint ); |
| } |
| else if( pBLink == this && |
| !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) ) |
| // Fly der Grafik anpassen ! |
| ::lcl_CallModify( *pGrfNd, aMsgHint ); |
| } |
| } |
| |
| bInNotifyLinks = sal_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 ); |
| } |
| } |
| |
| sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd ) |
| { |
| sal_Bool bRet = sal_False; |
| ViewShell *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() ) |
| //passende Hoehe ausrechnen. |
| aCalcSz.Height() = rFrmSz.Height() * |
| aSz.Width() / rFrmSz.Width(); |
| else if ( !aSz.Width() && aSz.Height() ) |
| //passende Breite ausrechnen |
| aCalcSz.Width() = rFrmSz.Width() * |
| aSz.Height() / rFrmSz.Height(); |
| else |
| //Hoehe und Breite uebernehmen |
| 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() ) |
| { |
| // Wenn die Grafik in einer Tabelle verankert ist, muess |
| // die Tabellen-Spalten neu berechnet werden |
| 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 skaliert ggf. eine ImageMap neu und |
| // braucht dazu das 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 |
| { |
| String sGrfNm; |
| if(GetLinkManager()) |
| GetLinkManager()->GetDisplayNames( this, 0, &sGrfNm, 0, 0 ); |
| int x = 0; |
| ++x; |
| } |
| #endif |
| |
| if( GetObj() ) |
| { |
| String aMimeType( SotExchange::GetFormatMimeType( GetContentType() )); |
| uno::Any aValue; |
| GetObj()->GetData( aValue, aMimeType, !IsSynchron() && bWaitForData ); |
| |
| if( bWaitForData && !GetObj() ) |
| { |
| ASSERT( !this, "das SvxFileObject wurde in einem GetData geloescht!" ); |
| bRes = sal_False; |
| } |
| else if( 0 != ( bRes = aValue.hasValue() ) ) |
| { |
| //JP 14.04.99: Bug 64820 - das Flag muss beim SwapIn natuerlich |
| // zurueckgesetzt werden. Die Daten sollen ja neu |
| // uebernommen werden |
| 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() ) |
| { |
| // wir heben die Verbindung auf |
| 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; |
| } |
| } |
| |
| ASSERT( !this, "GetAnchor nicht ueberlagert" ); |
| return 0; |
| } |
| |
| sal_Bool SwBaseLink::IsRecursion( const SwBaseLink* pChkLnk ) const |
| { |
| SwServerObjectRef aRef( (SwServerObject*)GetObj() ); |
| if( aRef.Is() ) |
| { |
| // es ist ein ServerObject, also frage nach allen darin |
| // befindlichen Links, ob wir darin enthalten sind. Ansonsten |
| // handelt es sich um eine Rekursion. |
| return aRef->IsLinkInServer( pChkLnk ); |
| } |
| return sal_False; |
| } |
| |
| sal_Bool SwBaseLink::IsInRange( sal_uLong, sal_uLong, xub_StrLen, xub_StrLen ) const |
| { |
| // Grafik oder OLE-Links nicht, |
| // Felder oder Sections haben eigene Ableitung! |
| return sal_False; |
| } |
| |
| SwBaseLink::~SwBaseLink() |
| { |
| } |