/* -*- 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 #include #include #include #include using namespace com::sun::star; SwGrfNode::SwGrfNode( const SwNodeIndex & rWhere, const String& rGrfName, const String& rFltName, const Graphic* pGraphic, SwGrfFmtColl *pGrfColl, SwAttrSet* pAutoAttr ) : SwNoTxtNode( rWhere, ND_GRFNODE, pGrfColl, pAutoAttr ), m_rGrfObj(GraphicObject::Create()), m_rReplacementGraphic(), // #i73788# mbLinkedInputStreamReady( false ), mbIsStreamReadOnly( sal_False ) { m_rGrfObj->SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ) ); bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel = bLoadLowResGrf = bFrameInPaint = bScaleImageMap = sal_False; bGrafikArrived = sal_True; ReRead(rGrfName, rFltName, pGraphic, 0, sal_False); } SwGrfNode::SwGrfNode( const SwNodeIndex & rWhere, const rtl::Reference& rGrfObj, SwGrfFmtColl *pGrfColl, SwAttrSet* pAutoAttr ) : SwNoTxtNode( rWhere, ND_GRFNODE, pGrfColl, pAutoAttr ), m_rGrfObj(rGrfObj), m_rReplacementGraphic(), // #i73788# mbLinkedInputStreamReady( false ), mbIsStreamReadOnly( sal_False ) { m_rGrfObj->SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ) ); if( rGrfObj->HasUserData() && rGrfObj->IsSwappedOut() ) { m_rGrfObj->SetSwapState(); } bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel= bLoadLowResGrf = bFrameInPaint = bScaleImageMap = sal_False; bGrafikArrived = sal_True; } /** Create new SW/G reader. * * Use this ctor if you want to read a linked graphic. * * @note Does not read/open the image itself! */ SwGrfNode::SwGrfNode( const SwNodeIndex & rWhere, const String& rGrfName, const String& rFltName, SwGrfFmtColl *pGrfColl, SwAttrSet* pAutoAttr ) : SwNoTxtNode( rWhere, ND_GRFNODE, pGrfColl, pAutoAttr ), m_rGrfObj(GraphicObject::Create()), m_rReplacementGraphic(), // #i73788# mbLinkedInputStreamReady( false ), mbIsStreamReadOnly( sal_False ) { m_rGrfObj->SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ) ); Graphic aGrf; aGrf.SetDefaultType(); m_rGrfObj->SetLink(rGrfName); m_rGrfObj = GraphicObject::Create(m_rGrfObj, aGrf); bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel = bLoadLowResGrf = bFrameInPaint = bScaleImageMap = sal_False; bGrafikArrived = sal_True; InsertLink( rGrfName, rFltName ); if( IsLinkedFile() ) { INetURLObject aUrl( rGrfName ); if( INET_PROT_FILE == aUrl.GetProtocol() && FStatHelper::IsDocument( aUrl.GetMainURL( INetURLObject::NO_DECODE ) )) { // file exists, so create connection without an update ((SwBaseLink*)&refLink)->Connect(); } } } sal_Bool SwGrfNode::ReRead( const String& rGrfName, const String& rFltName, const Graphic* pGraphic, const rtl::Reference* prGrfObj, sal_Bool bNewGrf ) { sal_Bool bReadGrf = sal_False, bSetTwipSize = sal_True; m_rReplacementGraphic = rtl::Reference(); OSL_ENSURE( pGraphic || prGrfObj || rGrfName.Len(), "GraphicNode without a name, Graphic or GraphicObject" ); // with name if( refLink.Is() ) { OSL_ENSURE( !bInSwapIn, "ReRead: I am still in SwapIn" ); if( rGrfName.Len() ) { // Note: If there is DDE in the FltName, than it is a DDE-linked graphic String sCmd( rGrfName ); if( rFltName.Len() ) { sal_uInt16 nNewType; if( rFltName.EqualsAscii( "DDE" )) nNewType = OBJECT_CLIENT_DDE; else { sfx2::MakeLnkName( sCmd, 0, rGrfName, aEmptyStr, &rFltName ); nNewType = OBJECT_CLIENT_GRF; } if( nNewType != refLink->GetObjType() ) { refLink->Disconnect(); ((SwBaseLink*)&refLink)->SetObjType( nNewType ); } } refLink->SetLinkSourceName( sCmd ); } else // no name anymore, so remove link { GetDoc()->GetLinkManager().Remove( refLink ); refLink.Clear(); } if( pGraphic ) { m_rGrfObj = GraphicObject::Create(m_rGrfObj, *pGraphic); m_rGrfObj->SetLink(rGrfName); onGraphicChanged(); bReadGrf = sal_True; } else if( prGrfObj && prGrfObj->is() ) { m_rGrfObj = *prGrfObj; if( (*prGrfObj)->HasUserData() && (*prGrfObj)->IsSwappedOut() ) { m_rGrfObj->SetSwapState(); } m_rGrfObj->SetLink( rGrfName ); onGraphicChanged(); bReadGrf = sal_True; } else { // reset data of the old graphic so that the correct placeholder is // shown in case the new link could not be loaded Graphic aGrf; aGrf.SetDefaultType(); m_rGrfObj = GraphicObject::Create(m_rGrfObj, aGrf); m_rGrfObj->SetLink(rGrfName); if( refLink.Is() ) { if( getLayoutFrm( GetDoc()->GetCurrentLayout() ) ) { SwMsgPoolItem aMsgHint( RES_GRF_REREAD_AND_INCACHE ); ModifyNotification( &aMsgHint, &aMsgHint ); } // #i59688# - do not load linked graphic, if it isn't a new linked graphic. else if ( bNewGrf ) { //TODO refLink->setInputStream(getInputStream()); ((SwBaseLink*)&refLink)->SwapIn(); } } onGraphicChanged(); bSetTwipSize = sal_False; } } else if( pGraphic && !rGrfName.Len() ) { // Old stream must be deleted before the new one is set. if( HasStreamName() ) DelStreamName(); m_rGrfObj = GraphicObject::Create( *pGraphic ); onGraphicChanged(); bReadGrf = sal_True; } else if( prGrfObj && prGrfObj->is() && !rGrfName.Len() ) { // Old stream must be deleted before the new one is set. if( HasStreamName() ) DelStreamName(); m_rGrfObj = *prGrfObj; onGraphicChanged(); if( (*prGrfObj)->HasUserData() && (*prGrfObj)->IsSwappedOut() ) { m_rGrfObj->SetSwapState(); } bReadGrf = sal_True; } // Was the graphic already loaded? else if( !bNewGrf && GRAPHIC_NONE != m_rGrfObj->GetType() ) { return sal_True; } else { if( HasStreamName() ) DelStreamName(); // create new link for the graphic object InsertLink( rGrfName, rFltName ); if( GetNodes().IsDocNodes() ) { if( pGraphic ) { m_rGrfObj = GraphicObject::Create( m_rGrfObj, *pGraphic); m_rGrfObj->SetLink( rGrfName ); onGraphicChanged(); bReadGrf = sal_True; // create connection without update, as we have the graphic ((SwBaseLink*)&refLink)->Connect(); } else if( prGrfObj && prGrfObj->is() ) { m_rGrfObj = *prGrfObj; m_rGrfObj->SetLink( rGrfName ); onGraphicChanged(); bReadGrf = sal_True; // create connection without update, as we have the graphic ((SwBaseLink*)&refLink)->Connect(); } else { // reset data of the old graphic so that the correct placeholder is // shown in case the new link could not be loaded Graphic aGrf; aGrf.SetDefaultType(); m_rGrfObj = GraphicObject::Create(m_rGrfObj, aGrf); m_rGrfObj->SetLink( rGrfName ); onGraphicChanged(); // #i59688# - do not load linked graphic, if it isn't a new linked graphic. if ( bNewGrf ) { ((SwBaseLink*)&refLink)->SwapIn(); } } } } // Bug 39281: Do not delete Size immediately - Events on ImageMaps should have // something to work with when swapping if( bSetTwipSize ) { SetTwipSize( ::GetGraphicSizeTwip( m_rGrfObj->GetGraphic(), 0 ) ); } // create an updates for the frames if( bReadGrf && bNewGrf ) { SwMsgPoolItem aMsgHint( RES_UPDATE_ATTR ); ModifyNotification( &aMsgHint, &aMsgHint ); } return bReadGrf; } SwGrfNode::~SwGrfNode() { m_rReplacementGraphic = rtl::Reference(); // #i73788# mpThreadConsumer.reset(); SwDoc* pDoc = GetDoc(); if( refLink.Is() ) { OSL_ENSURE( !bInSwapIn, "DTOR: I am still in SwapIn" ); pDoc->GetLinkManager().Remove( refLink ); refLink->Disconnect(); } else { // #i40014# - A graphic node, which is in a linked // section, whose link is another section in the document, doesn't // have to remove the stream from the storage. // Because it's hard to detect this case here and it would only fix // one problem with shared graphic files - there are also problems, // a certain graphic file is referenced by two independent graphic nodes, // brush item or drawing objects, the stream isn't no longer removed here. // To do this stuff correctly, a reference counting on shared streams // inside one document has to be implemented. } //#39289# delete frames already here since the Frms' dtor needs the graphic for its StopAnimation if( GetDepends() ) DelFrms(); } /// allow reaction on change of content of GraphicObject void SwGrfNode::onGraphicChanged() { // try to access SwFlyFrmFmt; since title/desc/name are set there, there is no // use to continue if it is not yet set. If not yet set, call onGraphicChanged() // when it is set. SwFlyFrmFmt* pFlyFmt = dynamic_cast< SwFlyFrmFmt* >(GetFlyFmt()); if(pFlyFmt) { String aName; String aTitle; String aDesc; const SvgDataPtr& rSvgDataPtr = GetGrf().getSvgData(); if(rSvgDataPtr.get()) { const drawinglayer::primitive2d::Primitive2DSequence aSequence(rSvgDataPtr->getPrimitive2DSequence()); if(aSequence.hasElements()) { drawinglayer::geometry::ViewInformation2D aViewInformation2D; drawinglayer::processor2d::ObjectInfoPrimitiveExtractor2D aProcessor(aViewInformation2D); aProcessor.process(aSequence); const drawinglayer::primitive2d::ObjectInfoPrimitive2D* pResult = aProcessor.getResult(); if(pResult) { aName = pResult->getName(); aTitle = pResult->getTitle(); aDesc = pResult->getDesc(); } } } if(aTitle.Len()) { SetTitle(aTitle); } if(aDesc.Len()) { SetDescription(aDesc); } } } void SwGrfNode::SetGraphic(const Graphic& rGraphic, const String& rLink) { m_rGrfObj = GraphicObject::Create(m_rGrfObj,rGraphic); m_rGrfObj->SetLink( rLink ); onGraphicChanged(); } const rtl::Reference SwGrfNode::GetReplacementGrfObj() const { if(!m_rReplacementGraphic.is()) { const SvgDataPtr& rSvgDataPtr = GetGrfObj()->GetGraphic().getSvgData(); if(rSvgDataPtr.get()) { const_cast< SwGrfNode* >(this)->m_rReplacementGraphic = GraphicObject::Create(rSvgDataPtr->getReplacement()); } } return m_rReplacementGraphic; } SwCntntNode *SwGrfNode::SplitCntntNode( const SwPosition & ) { return this; } SwGrfNode * SwNodes::MakeGrfNode( const SwNodeIndex & rWhere, const String& rGrfName, const String& rFltName, const Graphic* pGraphic, SwGrfFmtColl* pGrfColl, SwAttrSet* pAutoAttr, sal_Bool bDelayed ) { OSL_ENSURE( pGrfColl, "MakeGrfNode: Formatpointer ist 0." ); SwGrfNode *pNode; // create object delayed, only from a SW/G-reader if( bDelayed ) { pNode = new SwGrfNode( rWhere, rGrfName, rFltName, pGrfColl, pAutoAttr ); } else { pNode = new SwGrfNode( rWhere, rGrfName, rFltName, pGraphic, pGrfColl, pAutoAttr ); } return pNode; } SwGrfNode * SwNodes::MakeGrfNode( const SwNodeIndex & rWhere, const rtl::Reference& rGrfObj, SwGrfFmtColl* pGrfColl, SwAttrSet* pAutoAttr ) { OSL_ENSURE( pGrfColl, "MakeGrfNode: Formatpointer ist 0." ); return new SwGrfNode( rWhere, rGrfObj, pGrfColl, pAutoAttr ); } Size SwGrfNode::GetTwipSize() const { return nGrfSize; } sal_Bool SwGrfNode::ImportGraphic( SvStream& rStrm ) { Graphic aGraphic; const OUString aURL(m_rGrfObj->GetUserData()); if(!GraphicFilter::GetGraphicFilter().ImportGraphic(aGraphic, aURL, rStrm)) { m_rReplacementGraphic = rtl::Reference(); m_rGrfObj = GraphicObject::Create(m_rGrfObj, aGraphic ); m_rGrfObj->SetUserData( aURL ); onGraphicChanged(); return sal_True; } return sal_False; } /** * @return -1 if ReRead successful, * 1 if reading successful, * 0 if not loaded */ short SwGrfNode::SwapIn( sal_Bool bWaitForData ) { if( bInSwapIn ) // not recursively! return !m_rGrfObj->IsSwappedOut(); short nRet = 0; bInSwapIn = sal_True; SwBaseLink* pLink = (SwBaseLink*)(::sfx2::SvBaseLink*) refLink; if( pLink ) { if( GRAPHIC_NONE == m_rGrfObj->GetType() || GRAPHIC_DEFAULT == m_rGrfObj->GetType() ) { // link was not loaded yet if( pLink->SwapIn( bWaitForData ) ) nRet = -1; else if( GRAPHIC_DEFAULT == m_rGrfObj->GetType() ) { // no default bitmap anymore, thus re-paint m_rReplacementGraphic = rtl::Reference(); m_rGrfObj = GraphicObject::Create(m_rGrfObj, Graphic() ); onGraphicChanged(); SwMsgPoolItem aMsgHint( RES_GRAPHIC_PIECE_ARRIVED ); ModifyNotification( &aMsgHint, &aMsgHint ); } } else if( m_rGrfObj->IsSwappedOut() ) { // link to download nRet = pLink->SwapIn( bWaitForData ) ? 1 : 0; } else { nRet = 1; } } else if( m_rGrfObj->IsSwappedOut() ) { // graphic is in storage or in a temp file if( !HasStreamName() ) { nRet = (short)m_rGrfObj->SwapIn(); } else { try { String aStrmName, aPicStgName; _GetStreamStorageNames( aStrmName, aPicStgName ); uno::Reference < embed::XStorage > refPics = _GetDocSubstorageOrRoot( aPicStgName ); SvStream* pStrm = _GetStreamForEmbedGrf( refPics, aStrmName ); if ( pStrm ) { if ( ImportGraphic( *pStrm ) ) nRet = 1; delete pStrm; } } catch (const uno::Exception&) { // #i48434# OSL_FAIL( " - unhandled exception!" ); } } if( 1 == nRet ) { SwMsgPoolItem aMsg( RES_GRAPHIC_SWAPIN ); ModifyNotification( &aMsg, &aMsg ); } } else nRet = 1; OSL_ENSURE( nRet, "Cannot swap in graphic" ); if( nRet ) { if( !nGrfSize.Width() && !nGrfSize.Height() ) SetTwipSize( ::GetGraphicSizeTwip( m_rGrfObj->GetGraphic(), 0 ) ); } bInSwapIn = sal_False; return nRet; } short SwGrfNode::SwapOut() { if( m_rGrfObj->GetType() != GRAPHIC_DEFAULT && m_rGrfObj->GetType() != GRAPHIC_NONE && !m_rGrfObj->IsSwappedOut() && !bInSwapIn ) { if( !refLink.Is() ) { // Swapping is only needed for embedded pictures. // The graphic will be written into a temp file if it is new, i.e. // if there is no stream name in the storage yet if( !HasStreamName() ) if( !m_rGrfObj->SwapOut() ) return 0; } // written graphics and links are removed here return (short) m_rGrfObj->SwapOut( NULL ); } return 1; } bool SwGrfNode::GetFileFilterNms( String* pFileNm, String* pFilterNm ) const { bool bRet = false; if( refLink.Is() && refLink->GetLinkManager() ) { sal_uInt16 nType = refLink->GetObjType(); if( OBJECT_CLIENT_GRF == nType ) bRet = refLink->GetLinkManager()->GetDisplayNames( refLink, 0, pFileNm, 0, pFilterNm ); else if( OBJECT_CLIENT_DDE == nType && pFileNm && pFilterNm ) { String sApp, sTopic, sItem; if( refLink->GetLinkManager()->GetDisplayNames( refLink, &sApp, &sTopic, &sItem ) ) { ( *pFileNm = sApp ) += sfx2::cTokenSeparator; ( *pFileNm += sTopic ) += sfx2::cTokenSeparator; *pFileNm += sItem; pFilterNm->AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDE" )); bRet = true; } } } return bRet; } /** Make a graphic object ready for UNDO. * * If it is already in storage, it needs to be loaded. */ sal_Bool SwGrfNode::SavePersistentData() { if( refLink.Is() ) { OSL_ENSURE( !bInSwapIn, "SavePersistentData: I am still in SwapIn" ); GetDoc()->GetLinkManager().Remove( refLink ); return sal_True; } // swap in first if already in storage if( HasStreamName() && !SwapIn() ) return sal_False; // #i44367# // Do not delete graphic file in storage, because the graphic file could // be referenced by other graphic nodes. // Because it's hard to detect this case here and it would only fix // one problem with shared graphic files - there are also problems, if // a certain graphic file is referenced by two independent graphic nodes, // brush item or drawing objects, the stream isn't no longer removed here. // To do this stuff correct, a reference counting on shared streams // inside one document has to be implemented. // Important note: see also fix for #i40014# // swap out into temp file return (sal_Bool) SwapOut(); } sal_Bool SwGrfNode::RestorePersistentData() { if( refLink.Is() ) { IDocumentLinksAdministration* pIDLA = getIDocumentLinksAdministration(); refLink->SetVisible( pIDLA->IsVisibleLinks() ); pIDLA->GetLinkManager().InsertDDELink( refLink ); if( getIDocumentLayoutAccess()->GetCurrentLayout() ) //swmod 080218 refLink->Update(); } return sal_True; } void SwGrfNode::InsertLink( const String& rGrfName, const String& rFltName ) { refLink = new SwBaseLink( sfx2::LINKUPDATE_ONCALL, FORMAT_GDIMETAFILE, this ); IDocumentLinksAdministration* pIDLA = getIDocumentLinksAdministration(); if( GetNodes().IsDocNodes() ) { refLink->SetVisible( pIDLA->IsVisibleLinks() ); if( rFltName.EqualsAscii( "DDE" )) { sal_Int32 nTmp = 0; String sApp, sTopic, sItem; sApp = rGrfName.GetToken( 0, sfx2::cTokenSeparator, nTmp ); sTopic = rGrfName.GetToken( 0, sfx2::cTokenSeparator, nTmp ); sItem = rGrfName.Copy( nTmp ); pIDLA->GetLinkManager().InsertDDELink( refLink, sApp, sTopic, sItem ); } else { sal_Bool bSync = rFltName.EqualsAscii( "SYNCHRON" ); refLink->SetSynchron( bSync ); refLink->SetContentType( SOT_FORMATSTR_ID_SVXB ); pIDLA->GetLinkManager().InsertFileLink( *refLink, OBJECT_CLIENT_GRF, rGrfName, (!bSync && rFltName.Len() ? &rFltName : 0) ); } } m_rGrfObj->SetLink( rGrfName ); } void SwGrfNode::ReleaseLink() { if( refLink.Is() ) { { bInSwapIn = sal_True; SwBaseLink* pLink = (SwBaseLink*)(::sfx2::SvBaseLink*) refLink; pLink->SwapIn( sal_True, sal_True ); bInSwapIn = sal_False; } getIDocumentLinksAdministration()->GetLinkManager().Remove( refLink ); refLink.Clear(); m_rGrfObj->SetLink(); } } void SwGrfNode::SetTwipSize( const Size& rSz ) { nGrfSize = rSz; if( IsScaleImageMap() && nGrfSize.Width() && nGrfSize.Height() ) { // resize Image-Map to size of the graphic ScaleImageMap(); // do not re-scale Image-Map SetScaleImageMap( sal_False ); } } void SwGrfNode::ScaleImageMap() { if( !nGrfSize.Width() || !nGrfSize.Height() ) return; // re-scale Image-Map SwFrmFmt* pFmt = GetFlyFmt(); if( !pFmt ) return; SwFmtURL aURL( pFmt->GetURL() ); if ( !aURL.GetMap() ) return; bool bScale = false; Fraction aScaleX( 1, 1 ); Fraction aScaleY( 1, 1 ); const SwFmtFrmSize& rFrmSize = pFmt->GetFrmSize(); const SvxBoxItem& rBox = pFmt->GetBox(); if( !rFrmSize.GetWidthPercent() ) { SwTwips nWidth = rFrmSize.GetWidth(); nWidth -= rBox.CalcLineSpace(BOX_LINE_LEFT) + rBox.CalcLineSpace(BOX_LINE_RIGHT); OSL_ENSURE( nWidth>0, "Do any 0 twip wide graphics exist!?" ); if( nGrfSize.Width() != nWidth ) { aScaleX = Fraction( nGrfSize.Width(), nWidth ); bScale = true; } } if( !rFrmSize.GetHeightPercent() ) { SwTwips nHeight = rFrmSize.GetHeight(); nHeight -= rBox.CalcLineSpace(BOX_LINE_TOP) + rBox.CalcLineSpace(BOX_LINE_BOTTOM); OSL_ENSURE( nHeight>0, "Do any 0 twip high graphics exist!?" ); if( nGrfSize.Height() != nHeight ) { aScaleY = Fraction( nGrfSize.Height(), nHeight ); bScale = true; } } if( bScale ) { aURL.GetMap()->Scale( aScaleX, aScaleY ); pFmt->SetFmtAttr( aURL ); } } void SwGrfNode::DelStreamName() { if( HasStreamName() ) { // then remove graphic from storage uno::Reference < embed::XStorage > xDocStg = GetDoc()->GetDocStorage(); if( xDocStg.is() ) { try { String aPicStgName, aStrmName; _GetStreamStorageNames( aStrmName, aPicStgName ); uno::Reference < embed::XStorage > refPics = xDocStg; if ( aPicStgName.Len() ) refPics = xDocStg->openStorageElement( aPicStgName, embed::ElementModes::READWRITE ); refPics->removeElement( aStrmName ); uno::Reference < embed::XTransactedObject > xTrans( refPics, uno::UNO_QUERY ); if ( xTrans.is() ) xTrans->commit(); } catch (const uno::Exception&) { // #i48434# OSL_FAIL( " - unhandled exception!" ); } } m_rGrfObj->SetUserData(); } } /** helper method to get a substorage of the document storage for readonly access. OD, MAV 2005-08-17 #i53025# A substorage with the specified name will be opened readonly. If the provided name is empty the root storage will be returned. */ uno::Reference< embed::XStorage > SwGrfNode::_GetDocSubstorageOrRoot( const String& aStgName ) const { uno::Reference < embed::XStorage > refStor = const_cast(this)->GetDoc()->GetDocStorage(); OSL_ENSURE( refStor.is(), "Kein Storage am Doc" ); if ( aStgName.Len() ) { if( refStor.is() ) return refStor->openStorageElement( aStgName, embed::ElementModes::READ ); } return refStor; } /** helper method to determine stream for the embedded graphic. OD 2005-05-04 #i48434# Important note: caller of this method has to handle the thrown exceptions OD, MAV 2005-08-17 #i53025# Storage, which should contain the stream of the embedded graphic, is provided via parameter. Otherwise the returned stream will be closed after the method returns, because its parent stream is closed and deleted. Proposed name of embedded graphic stream is also provided by parameter. */ SvStream* SwGrfNode::_GetStreamForEmbedGrf( const uno::Reference< embed::XStorage >& _refPics, String& _aStrmName ) const { SvStream* pStrm( 0L ); if( _refPics.is() && _aStrmName.Len() ) { // If stream doesn't exist in the storage, try access the graphic file by // re-generating its name. // A save action can have changed the filename of the embedded graphic, // because a changed unique ID of the graphic is calculated. // --> recursive calls of have to be avoided. // Thus, use local static boolean to assure this. if ( !_refPics->hasByName( _aStrmName ) || !_refPics->isStreamElement( _aStrmName ) ) { xub_StrLen nExtPos = _aStrmName.Search( '.' ); String aExtStr = _aStrmName.Copy( nExtPos ); if ( GetGrfObj()->GetType() != GRAPHIC_NONE ) { _aStrmName = OStringToOUString(GetGrfObj()->GetUniqueID(), RTL_TEXTENCODING_ASCII_US); _aStrmName += aExtStr; } } // assure that graphic file exist in the storage. if ( _refPics->hasByName( _aStrmName ) && _refPics->isStreamElement( _aStrmName ) ) { uno::Reference < io::XStream > refStrm = _refPics->openStreamElement( _aStrmName, embed::ElementModes::READ ); pStrm = utl::UcbStreamHelper::CreateStream( refStrm ); } else { OSL_FAIL( " - embedded graphic file not found!" ); } } return pStrm; } void SwGrfNode::_GetStreamStorageNames( String& rStrmName, String& rStorName ) const { rStorName.Erase(); rStrmName.Erase(); String aUserData( m_rGrfObj->GetUserData() ); if( !aUserData.Len() ) return; if (aNewStrmName.Len()>0) { aUserData=aNewStrmName; } String aProt( "vnd.sun.star.Package:" ); if( 0 == aUserData.CompareTo( aProt, aProt.Len() ) ) { // 6.0 (XML) Package xub_StrLen nPos = aUserData.Search( '/' ); if( STRING_NOTFOUND == nPos ) { rStrmName = aUserData.Copy( aProt.Len() ); } else { xub_StrLen nPathStart = aProt.Len(); if( 0 == aUserData.CompareToAscii( "./", 2 ) ) nPathStart += 2; rStorName = aUserData.Copy( nPathStart, nPos-nPathStart ); rStrmName = aUserData.Copy( nPos+1 ); } } else { OSL_FAIL( " - unknown graphic URL type. Code for handling 3.1 - 5.2 storages has been deleted by issue i53025." ); } OSL_ENSURE( STRING_NOTFOUND == rStrmName.Search( '/' ), "invalid graphic stream name" ); } SwCntntNode* SwGrfNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const { // copy formats into the other document SwGrfFmtColl* pColl = pDoc->CopyGrfColl( *GetGrfColl() ); Graphic aTmpGrf; SwBaseLink* pLink = (SwBaseLink*)(::sfx2::SvBaseLink*) refLink; if( !pLink && HasStreamName() ) { try { String aStrmName, aPicStgName; _GetStreamStorageNames( aStrmName, aPicStgName ); uno::Reference < embed::XStorage > refPics = _GetDocSubstorageOrRoot( aPicStgName ); SvStream* pStrm = _GetStreamForEmbedGrf( refPics, aStrmName ); if ( pStrm ) { const OUString aURL(m_rGrfObj->GetUserData()); GraphicFilter::GetGraphicFilter().ImportGraphic(aTmpGrf, aURL, *pStrm); delete pStrm; } } catch (const uno::Exception& e) { // #i48434# SAL_WARN("sw.core", " - unhandled exception!" << e.Message); } } else { if( m_rGrfObj->IsSwappedOut() ) const_cast(this)->SwapIn(); aTmpGrf = m_rGrfObj->GetGraphic(); } const sfx2::LinkManager& rMgr = getIDocumentLinksAdministration()->GetLinkManager(); String sFile, sFilter; if( IsLinkedFile() ) rMgr.GetDisplayNames( refLink, 0, &sFile, 0, &sFilter ); else if( IsLinkedDDE() ) { String sTmp1, sTmp2; rMgr.GetDisplayNames( refLink, &sTmp1, &sTmp2, &sFilter ); sfx2::MakeLnkName( sFile, &sTmp1, sTmp2, sFilter ); sFilter.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDE" )); } SwGrfNode* pGrfNd = pDoc->GetNodes().MakeGrfNode( rIdx, sFile, sFilter, &aTmpGrf, pColl, (SwAttrSet*)GetpSwAttrSet() ); pGrfNd->SetTitle( GetTitle() ); pGrfNd->SetDescription( GetDescription() ); pGrfNd->SetContour( HasContour(), HasAutomaticContour() ); return pGrfNd; } IMPL_LINK( SwGrfNode, SwapGraphic, rtl::Reference*, prGrfObj ) { SvStream* pRet; // Keep graphic while in swap in. That's at least important // when breaking links, because in this situation a reschedule call and // a DataChanged call lead to a paint of the graphic. if( (*prGrfObj)->IsInSwapOut() && (IsSelected() || bInSwapIn) ) { pRet = GRFMGR_AUTOSWAPSTREAM_NONE; } else if( refLink.Is() ) { if( (*prGrfObj)->IsInSwapIn() ) { // then make it by your self if( !bInSwapIn ) { bool bIsModifyLocked = IsModifyLocked(); LockModify(); SwapIn( sal_False ); if( !bIsModifyLocked ) UnlockModify(); } pRet = GRFMGR_AUTOSWAPSTREAM_NONE; } else pRet = GRFMGR_AUTOSWAPSTREAM_LINK; } else { pRet = GRFMGR_AUTOSWAPSTREAM_TEMP; if( HasStreamName() ) { try { String aStrmName, aPicStgName; _GetStreamStorageNames( aStrmName, aPicStgName ); uno::Reference < embed::XStorage > refPics = _GetDocSubstorageOrRoot( aPicStgName ); SvStream* pStrm = _GetStreamForEmbedGrf( refPics, aStrmName ); if ( pStrm ) { if( (*prGrfObj)->IsInSwapOut() ) { pRet = GRFMGR_AUTOSWAPSTREAM_LINK; } else { ImportGraphic( *pStrm ); pRet = GRFMGR_AUTOSWAPSTREAM_LOADED; } delete pStrm; } } catch (const uno::Exception&) { // #i48434# OSL_FAIL( " - unhandled exception!" ); } } } return (sal_IntPtr)pRet; } /// delete all QuickDraw-Bitmaps in the specified document void DelAllGrfCacheEntries( SwDoc* /*pDoc*/ ) { } /// returns the Graphic-Attr-Structure filled with our graphic attributes GraphicAttr& SwGrfNode::GetGraphicAttr( GraphicAttr& rGA, const SwFrm* pFrm ) const { const SwAttrSet& rSet = GetSwAttrSet(); rGA.SetDrawMode( (GraphicDrawMode)rSet.GetDrawModeGrf().GetValue() ); const SwMirrorGrf & rMirror = rSet.GetMirrorGrf(); sal_uLong nMirror = BMP_MIRROR_NONE; if( rMirror.IsGrfToggle() && pFrm && !pFrm->FindPageFrm()->OnRightPage() ) { switch( rMirror.GetValue() ) { case RES_MIRROR_GRAPH_DONT: nMirror = BMP_MIRROR_HORZ; break; case RES_MIRROR_GRAPH_VERT: nMirror = BMP_MIRROR_NONE; break; case RES_MIRROR_GRAPH_HOR: nMirror = BMP_MIRROR_HORZ|BMP_MIRROR_VERT; break; default: nMirror = BMP_MIRROR_VERT; break; } } else switch( rMirror.GetValue() ) { case RES_MIRROR_GRAPH_BOTH: nMirror = BMP_MIRROR_HORZ|BMP_MIRROR_VERT; break; case RES_MIRROR_GRAPH_VERT: nMirror = BMP_MIRROR_HORZ; break; case RES_MIRROR_GRAPH_HOR: nMirror = BMP_MIRROR_VERT; break; } rGA.SetMirrorFlags( nMirror ); const SwCropGrf& rCrop = rSet.GetCropGrf(); rGA.SetCrop( TWIP_TO_MM100( rCrop.GetLeft() ), TWIP_TO_MM100( rCrop.GetTop() ), TWIP_TO_MM100( rCrop.GetRight() ), TWIP_TO_MM100( rCrop.GetBottom() )); const SwRotationGrf& rRotation = rSet.GetRotationGrf(); rGA.SetRotation( rRotation.GetValue() ); rGA.SetLuminance( rSet.GetLuminanceGrf().GetValue() ); rGA.SetContrast( rSet.GetContrastGrf().GetValue() ); rGA.SetChannelR( rSet.GetChannelRGrf().GetValue() ); rGA.SetChannelG( rSet.GetChannelGGrf().GetValue() ); rGA.SetChannelB( rSet.GetChannelBGrf().GetValue() ); rGA.SetGamma( rSet.GetGammaGrf().GetValue() ); rGA.SetInvert( rSet.GetInvertGrf().GetValue() ); const sal_uInt16 nTrans = rSet.GetTransparencyGrf().GetValue(); rGA.SetTransparency( (sal_uInt8) FRound( std::min( nTrans, (sal_uInt16) 100 ) * 2.55 ) ); return rGA; } sal_Bool SwGrfNode::IsTransparent() const { sal_Bool bRet = m_rGrfObj->IsTransparent(); if( !bRet ) // ask the attribut { bRet = 0 != GetSwAttrSet().GetTransparencyGrf().GetValue(); } return bRet; } sal_Bool SwGrfNode::IsSelected() const { sal_Bool bRet = sal_False; const SwEditShell* pESh = GetDoc()->GetEditShell(); if( pESh ) { const SwNode* pN = this; const ViewShell* pV = pESh; do { if( pV->ISA( SwEditShell ) && pN == &((SwCrsrShell*)pV) ->GetCrsr()->GetPoint()->nNode.GetNode() ) { bRet = sal_True; break; } } while( pESh != ( pV = (ViewShell*)pV->GetNext() )); } return bRet; } // #i73788# boost::weak_ptr< SwAsyncRetrieveInputStreamThreadConsumer > SwGrfNode::GetThreadConsumer() { return mpThreadConsumer; } void SwGrfNode::TriggerAsyncRetrieveInputStream() { if ( !IsLinkedFile() ) { OSL_FAIL( " - Method is misused. Method call is only valid for graphic nodes, which refer a linked graphic file" ); return; } if ( mpThreadConsumer.get() == 0 ) { mpThreadConsumer.reset( new SwAsyncRetrieveInputStreamThreadConsumer( *this ) ); String sGrfNm; refLink->GetLinkManager()->GetDisplayNames( refLink, 0, &sGrfNm, 0, 0 ); mpThreadConsumer->CreateThread( sGrfNm ); } } bool SwGrfNode::IsLinkedInputStreamReady() const { return mbLinkedInputStreamReady; } void SwGrfNode::ApplyInputStream( com::sun::star::uno::Reference xInputStream, const sal_Bool bIsStreamReadOnly ) { if ( IsLinkedFile() ) { if ( xInputStream.is() ) { mxInputStream = xInputStream; mbIsStreamReadOnly = bIsStreamReadOnly; mbLinkedInputStreamReady = true; SwMsgPoolItem aMsgHint( RES_LINKED_GRAPHIC_STREAM_ARRIVED ); ModifyNotification( &aMsgHint, &aMsgHint ); } } } void SwGrfNode::UpdateLinkWithInputStream() { // do not work on link, if a has been triggered. if ( !bInSwapIn && IsLinkedFile() ) { GetLink()->setStreamToLoadFrom( mxInputStream, mbIsStreamReadOnly ); GetLink()->Update(); SwMsgPoolItem aMsgHint( RES_GRAPHIC_ARRIVED ); ModifyNotification( &aMsgHint, &aMsgHint ); // #i88291# mxInputStream.clear(); GetLink()->clearStreamToLoadFrom(); mbLinkedInputStreamReady = false; mpThreadConsumer.reset(); } } // #i90395# bool SwGrfNode::IsAsyncRetrieveInputStreamPossible() const { bool bRet = false; if ( IsLinkedFile() ) { String sGrfNm; refLink->GetLinkManager()->GetDisplayNames( refLink, 0, &sGrfNm, 0, 0 ); String sProtocol( "vnd.sun.star.pkg:" ); if ( sGrfNm.CompareTo( sProtocol, sProtocol.Len() ) != 0 ) { bRet = true; } } return bRet; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */