/* -*- 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 #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 #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 #include #include #include #include #include #include #include #define OLESIZE 11905 - 2 * lMinBorder, 6 * MM50 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_DRAWMODEL = 0x00000001; constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_HTML = 0x00000002; constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_RTF = 0x00000004; constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_STRING = 0x00000008; constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_SWOLE = 0x00000010; constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_DDE = 0x00000020; constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_RICHTEXT = 0x00000040; using namespace ::svx; using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::datatransfer; #define DDE_TXT_ENCODING osl_getThreadTextEncoding() class SwTrnsfrDdeLink : public ::sfx2::SvBaseLink { OUString sName; ::sfx2::SvLinkSourceRef refObj; SwTransferable& rTrnsfr; SwDocShell* pDocShell; sal_uLong nOldTimeOut; bool bDelBookmrk : 1; bool bInDisconnect : 1; bool FindDocShell(); using sfx2::SvBaseLink::Disconnect; protected: virtual ~SwTrnsfrDdeLink() override; public: SwTrnsfrDdeLink( SwTransferable& rTrans, SwWrtShell& rSh ); virtual ::sfx2::SvBaseLink::UpdateResult DataChanged( const OUString& rMimeType, const css::uno::Any & rValue ) override; virtual void Closed() override; bool WriteData( SvStream& rStrm ); void Disconnect( bool bRemoveDataAdvise ); }; // helper class for Action and Undo enclosing class SwTrnsfrActionAndUndo { SwWrtShell *pSh; public: SwTrnsfrActionAndUndo( SwWrtShell *pS, bool bDelSel = false) : pSh( pS ) { pSh->StartUndo( SwUndoId::PASTE_CLIPBOARD ); if( bDelSel ) pSh->DelRight(); pSh->StartAllAction(); } ~SwTrnsfrActionAndUndo() COVERITY_NOEXCEPT_FALSE { pSh->EndUndo(); pSh->EndAllAction(); } }; SwTransferable::SwTransferable( SwWrtShell& rSh ) : m_pWrtShell( &rSh ), m_pCreatorView( nullptr ), m_pClpDocFac( nullptr ), m_pClpGraphic( nullptr ), m_pClpBitmap( nullptr ), m_pOrigGraphic( nullptr ), m_pBookmark( nullptr ), m_pImageMap( nullptr ), m_pTargetURL( nullptr ), m_eBufferType( TransferBufferType::NONE ) { rSh.GetView().AddTransferable(*this); SwDocShell* pDShell = rSh.GetDoc()->GetDocShell(); if( pDShell ) { pDShell->FillTransferableObjectDescriptor( m_aObjDesc ); if( pDShell->GetMedium() ) { const INetURLObject& rURLObj = pDShell->GetMedium()->GetURLObject(); m_aObjDesc.maDisplayName = URIHelper::removePassword( rURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), INetURLObject::EncodeMechanism::WasEncoded, INetURLObject::DecodeMechanism::Unambiguous ); } PrepareOLE( m_aObjDesc ); } } SwTransferable::~SwTransferable() { SolarMutexGuard aSolarGuard; // the DDELink still needs the WrtShell! if( m_xDdeLink.is() ) { static_cast( m_xDdeLink.get() )->Disconnect( true ); m_xDdeLink.clear(); } m_pWrtShell = nullptr; // release reference to the document so that aDocShellRef will delete // it (if aDocShellRef is set). Otherwise, the OLE nodes keep references // to their sub-storage when the storage is already dead. delete m_pClpDocFac; // first close, then the Ref. can be cleared as well, so that // the DocShell really gets deleted! if( m_aDocShellRef.Is() ) { SfxObjectShell * pObj = m_aDocShellRef; SwDocShell* pDocSh = static_cast(pObj); pDocSh->DoClose(); } m_aDocShellRef.Clear(); SwModule* pMod = SW_MOD(); if(pMod) { if ( pMod->m_pDragDrop == this ) pMod->m_pDragDrop = nullptr; else if ( pMod->m_pXSelection == this ) pMod->m_pXSelection = nullptr; } m_eBufferType = TransferBufferType::NONE; } static SwDoc * lcl_GetDoc(SwDocFac & rDocFac) { SwDoc *const pDoc = rDocFac.GetDoc(); OSL_ENSURE( pDoc, "Document not found" ); if (pDoc) { pDoc->SetClipBoard( true ); } return pDoc; } void SwTransferable::ObjectReleased() { SwModule *pMod = SW_MOD(); if( this == pMod->m_pDragDrop ) pMod->m_pDragDrop = nullptr; else if( this == pMod->m_pXSelection ) pMod->m_pXSelection = nullptr; } void SwTransferable::AddSupportedFormats() { // only need if we are the current XSelection Object SwModule *pMod = SW_MOD(); if( this == pMod->m_pXSelection || comphelper::LibreOfficeKit::isActive()) { SetDataForDragAndDrop( Point( 0,0) ); } } void SwTransferable::InitOle( SfxObjectShell* pDoc ) { //set OleVisArea. Upper left corner of the page and size of //RealSize in Twips. const Size aSz( OLESIZE ); SwRect aVis( Point( DOCUMENTBORDER, DOCUMENTBORDER ), aSz ); pDoc->SetVisArea( aVis.SVRect() ); } uno::Reference < embed::XEmbeddedObject > SwTransferable::FindOLEObj( sal_Int64& nAspect ) const { uno::Reference < embed::XEmbeddedObject > xObj; if( m_pClpDocFac ) { SwIterator aIter( *m_pClpDocFac->GetDoc()->GetDfltGrfFormatColl() ); for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() ) if( SwNodeType::Ole == pNd->GetNodeType() ) { xObj = static_cast(pNd)->GetOLEObj().GetOleRef(); nAspect = static_cast(pNd)->GetAspect(); break; } } return xObj; } const Graphic* SwTransferable::FindOLEReplacementGraphic() const { if( m_pClpDocFac ) { SwIterator aIter( *m_pClpDocFac->GetDoc()->GetDfltGrfFormatColl() ); for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() ) if( SwNodeType::Ole == pNd->GetNodeType() ) { return static_cast(pNd)->GetGraphic(); } } return nullptr; } void SwTransferable::RemoveDDELinkFormat( const vcl::Window& rWin ) { RemoveFormat( SotClipboardFormatId::LINK ); CopyToClipboard( const_cast(&rWin) ); } namespace { //Resolves: fdo#40717 surely when we create a clipboard document we should //overwrite the clipboard documents styles and settings with that of the //source, so that we can WYSIWYG paste. If we want that the destinations //styles are used over the source styles, that's a matter of the //destination paste code to handle, not the source paste code. void lclOverWriteDoc(SwWrtShell &rSrcWrtShell, SwDoc &rDest) { const SwDoc &rSrc = *rSrcWrtShell.GetDoc(); rDest.ReplaceCompatibilityOptions(rSrc); rDest.ReplaceDefaults(rSrc); //It would probably make most sense here to only insert the styles used //by the selection, e.g. apply SwDoc::IsUsed on styles ? rDest.ReplaceStyles(rSrc, false); rSrcWrtShell.Copy(&rDest); rDest.GetMetaFieldManager().copyDocumentProperties(rSrc); } void lclCheckAndPerformRotation(Graphic& aGraphic) { GraphicNativeMetadata aMetadata; if ( aMetadata.read(aGraphic) ) { sal_uInt16 aRotation = aMetadata.getRotation(); if (aRotation != 0) { ScopedVclPtrInstance< MessageDialog > aQueryBox( nullptr, "QueryRotateIntoStandardOrientationDialog", "modules/swriter/ui/queryrotateintostandarddialog.ui"); if (aQueryBox->Execute() == RET_YES) { GraphicNativeTransform aTransform( aGraphic ); aTransform.rotate( aRotation ); } } } } } bool SwTransferable::GetData( const DataFlavor& rFlavor, const OUString& rDestDoc ) { SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor ); // we can only fulfil the request if // 1) we have data for this format // 2) we have either a clipboard document (pClpDocFac), or // we have a SwWrtShell (so we can generate a new clipboard document) if( !HasFormat( nFormat ) || ( m_pClpDocFac == nullptr && m_pWrtShell == nullptr ) ) return false; if( !m_pClpDocFac ) { SelectionType nSelectionType = m_pWrtShell->GetSelectionType(); // when pending we will not get the correct type, but SelectionType::Text // as fallback. This *happens* during D&D, so we need to check if we are in // the fallback and just try to get a graphic const bool bPending(m_pWrtShell->ActionPend()); // SEL_GRF is from ContentType of editsh if(bPending || ((SelectionType::Graphic | SelectionType::DbForm) & nSelectionType)) { m_pClpGraphic.reset(new Graphic); if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_pClpGraphic )) m_pOrigGraphic = m_pClpGraphic.get(); m_pClpBitmap.reset(new Graphic); if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_pClpBitmap )) m_pOrigGraphic = m_pClpBitmap.get(); // is it an URL-Button ? OUString sURL; OUString sDesc; if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) ) { m_pBookmark.reset(new INetBookmark( sURL, sDesc )); m_eBufferType = TransferBufferType::InetField; } } m_pClpDocFac = new SwDocFac; SwDoc *const pTmpDoc = lcl_GetDoc(*m_pClpDocFac); pTmpDoc->getIDocumentFieldsAccess().LockExpFields(); // never update fields - leave text as it is lclOverWriteDoc(*m_pWrtShell, *pTmpDoc); // in CORE a new one was created (OLE-objects copied!) m_aDocShellRef = pTmpDoc->GetTmpDocShell(); if( m_aDocShellRef.Is() ) SwTransferable::InitOle( m_aDocShellRef ); pTmpDoc->SetTmpDocShell( nullptr ); if( nSelectionType & SelectionType::Text && !m_pWrtShell->HasMark() ) { SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr ); Point aPos( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY()); bool bSelect = g_bExecuteDrag && m_pWrtShell->GetView().GetDocShell() && !m_pWrtShell->GetView().GetDocShell()->IsReadOnly(); if( m_pWrtShell->GetContentAtPos( aPos, aContentAtPos, bSelect ) ) { m_pBookmark.reset(new INetBookmark( static_cast(aContentAtPos.aFnd.pAttr)->GetValue(), aContentAtPos.sStr )); m_eBufferType = TransferBufferType::InetField; if( bSelect ) m_pWrtShell->SelectTextAttr( RES_TXTATR_INETFMT ); } } if( m_pWrtShell->IsFrameSelected() ) { SfxItemSet aSet( m_pWrtShell->GetAttrPool(), svl::Items{} ); m_pWrtShell->GetFlyFrameAttr( aSet ); const SwFormatURL& rURL = static_cast(aSet.Get( RES_URL )); if( rURL.GetMap() ) m_pImageMap.reset(new ImageMap( *rURL.GetMap() )); else if( !rURL.GetURL().isEmpty() ) m_pTargetURL.reset(new INetImage( aEmptyOUStr, rURL.GetURL(), rURL.GetTargetFrameName() )); } } bool bOK = false; if( TransferBufferType::Ole == m_eBufferType ) { //TODO/MBA: testing - is this the "single OLE object" case?! // get OLE-Object from ClipDoc and get the data from that. sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT; // will be set in the next statement uno::Reference < embed::XEmbeddedObject > xObj = FindOLEObj( nAspect ); const Graphic* pOLEGraph = FindOLEReplacementGraphic(); if( xObj.is() ) { TransferableDataHelper aD( new SvEmbedTransferHelper( xObj, pOLEGraph, nAspect ) ); uno::Any aAny = aD.GetAny(rFlavor, rDestDoc); if( aAny.hasValue() ) bOK = SetAny( aAny ); } // the following solution will be used in the case when the object can not generate the image // TODO/LATER: in future the transferhelper must probably be created based on object and the replacement stream // TODO: Block not required now, SvEmbedTransferHelper should be able to handle GDIMetaFile format if ( nFormat == SotClipboardFormatId::GDIMETAFILE ) { pOLEGraph = FindOLEReplacementGraphic(); if ( pOLEGraph ) bOK = SetGDIMetaFile( pOLEGraph->GetGDIMetaFile() ); } } else { switch( nFormat ) { case SotClipboardFormatId::LINK: if( m_xDdeLink.is() ) bOK = SetObject( m_xDdeLink.get(), SWTRANSFER_OBJECTTYPE_DDE, rFlavor ); break; case SotClipboardFormatId::OBJECTDESCRIPTOR: case SotClipboardFormatId::LINKSRCDESCRIPTOR: bOK = SetTransferableObjectDescriptor( m_aObjDesc ); break; case SotClipboardFormatId::DRAWING: { SwDoc *const pDoc = lcl_GetDoc(*m_pClpDocFac); bOK = SetObject( pDoc->getIDocumentDrawModelAccess().GetDrawModel(), SWTRANSFER_OBJECTTYPE_DRAWMODEL, rFlavor ); } break; case SotClipboardFormatId::STRING: { SwDoc *const pDoc = lcl_GetDoc(*m_pClpDocFac); bOK = SetObject( pDoc, SWTRANSFER_OBJECTTYPE_STRING, rFlavor ); } break; case SotClipboardFormatId::RTF: { SwDoc *const pDoc = lcl_GetDoc(*m_pClpDocFac); bOK = SetObject( pDoc, SWTRANSFER_OBJECTTYPE_RTF, rFlavor ); } break; case SotClipboardFormatId::RICHTEXT: { SwDoc *const pDoc = lcl_GetDoc(*m_pClpDocFac); bOK = SetObject( pDoc, SWTRANSFER_OBJECTTYPE_RICHTEXT, rFlavor ); } break; case SotClipboardFormatId::HTML: { SwDoc *const pDoc = lcl_GetDoc(*m_pClpDocFac); bOK = SetObject( pDoc, SWTRANSFER_OBJECTTYPE_HTML, rFlavor ); } break; case SotClipboardFormatId::SVXB: if( m_eBufferType & TransferBufferType::Graphic && m_pOrigGraphic ) bOK = SetGraphic( *m_pOrigGraphic ); break; case SotClipboardFormatId::GDIMETAFILE: if( m_eBufferType & TransferBufferType::Graphic ) bOK = SetGDIMetaFile( m_pClpGraphic->GetGDIMetaFile() ); break; case SotClipboardFormatId::BITMAP: case SotClipboardFormatId::PNG: // Neither pClpBitmap nor pClpGraphic are necessarily set if( (m_eBufferType & TransferBufferType::Graphic) && (m_pClpBitmap != nullptr || m_pClpGraphic != nullptr)) bOK = SetBitmapEx( (m_pClpBitmap ? m_pClpBitmap : m_pClpGraphic)->GetBitmapEx(), rFlavor ); break; case SotClipboardFormatId::SVIM: if( m_pImageMap ) bOK = SetImageMap( *m_pImageMap ); break; case SotClipboardFormatId::INET_IMAGE: if( m_pTargetURL ) bOK = SetINetImage( *m_pTargetURL, rFlavor ); break; case SotClipboardFormatId::SOLK: case SotClipboardFormatId::NETSCAPE_BOOKMARK: case SotClipboardFormatId::FILEGRPDESCRIPTOR: case SotClipboardFormatId::FILECONTENT: case SotClipboardFormatId::UNIFORMRESOURCELOCATOR: case SotClipboardFormatId::SIMPLE_FILE: if( (TransferBufferType::InetField & m_eBufferType) && m_pBookmark ) bOK = SetINetBookmark( *m_pBookmark, rFlavor ); break; case SotClipboardFormatId::EMBED_SOURCE: if( !m_aDocShellRef.Is() ) { SwDoc *const pDoc = lcl_GetDoc(*m_pClpDocFac); SwDocShell* pNewDocSh = new SwDocShell( pDoc, SfxObjectCreateMode::EMBEDDED ); m_aDocShellRef = pNewDocSh; m_aDocShellRef->DoInitNew(); SwTransferable::InitOle( m_aDocShellRef ); } bOK = SetObject( &m_aDocShellRef, SWTRANSFER_OBJECTTYPE_SWOLE, rFlavor ); break; default: break; } } return bOK; } bool SwTransferable::WriteObject( tools::SvRef& xStream, void* pObject, sal_uInt32 nObjectType, const DataFlavor& /*rFlavor*/ ) { bool bRet = false; WriterRef xWrt; switch( nObjectType ) { case SWTRANSFER_OBJECTTYPE_DRAWMODEL: { // don't change the sequence of commands SdrModel *pModel = static_cast(pObject); xStream->SetBufferSize( 16348 ); // for the changed pool defaults from drawing layer pool set those // attributes as hard attributes to preserve them for saving const SfxItemPool& rItemPool = pModel->GetItemPool(); const SvxFontHeightItem& rDefaultFontHeight = rItemPool.GetDefaultItem(EE_CHAR_FONTHEIGHT); // SW should have no MasterPages OSL_ENSURE(0 == pModel->GetMasterPageCount(), "SW with MasterPages (!)"); for(sal_uInt16 a(0); a < pModel->GetPageCount(); a++) { const SdrPage* pPage = pModel->GetPage(a); SdrObjListIter aIter(*pPage, SdrIterMode::DeepNoGroups); while(aIter.IsMore()) { SdrObject* pObj = aIter.Next(); const SvxFontHeightItem& rItem = pObj->GetMergedItem(EE_CHAR_FONTHEIGHT); if(rItem.GetHeight() == rDefaultFontHeight.GetHeight()) { pObj->SetMergedItem(rDefaultFontHeight); } } } { uno::Reference xDocOut( new utl::OOutputStreamWrapper( *xStream ) ); if( SvxDrawingLayerExport( pModel, xDocOut ) ) xStream->Commit(); } bRet = ERRCODE_NONE == xStream->GetError(); } break; case SWTRANSFER_OBJECTTYPE_SWOLE: { SfxObjectShell* pEmbObj = static_cast(pObject); try { ::utl::TempFile aTempFile; aTempFile.EnableKillingFile(); uno::Reference< embed::XStorage > xWorkStore = ::comphelper::OStorageHelper::GetStorageFromURL( aTempFile.GetURL(), embed::ElementModes::READWRITE ); // write document storage pEmbObj->SetupStorage( xWorkStore, SOFFICE_FILEFORMAT_CURRENT, false ); // mba: no BaseURL for clipboard SfxMedium aMedium( xWorkStore, OUString() ); pEmbObj->DoSaveObjectAs( aMedium, false ); pEmbObj->DoSaveCompleted(); uno::Reference< embed::XTransactedObject > xTransact( xWorkStore, uno::UNO_QUERY ); if ( xTransact.is() ) xTransact->commit(); std::unique_ptr pSrcStm(::utl::UcbStreamHelper::CreateStream( aTempFile.GetURL(), StreamMode::READ )); if( pSrcStm ) { xStream->SetBufferSize( 0xff00 ); xStream->WriteStream( *pSrcStm ); pSrcStm.reset(); } xWorkStore->dispose(); xWorkStore.clear(); xStream->Commit(); } catch (const uno::Exception&) { } bRet = ( xStream->GetError() == ERRCODE_NONE ); } break; case SWTRANSFER_OBJECTTYPE_DDE: { xStream->SetBufferSize( 1024 ); SwTrnsfrDdeLink* pDdeLnk = static_cast(pObject); if( pDdeLnk->WriteData( *xStream ) ) { xStream->Commit(); bRet = ERRCODE_NONE == xStream->GetError(); } } break; case SWTRANSFER_OBJECTTYPE_HTML: GetHTMLWriter( aEmptyOUStr, OUString(), xWrt ); break; case SWTRANSFER_OBJECTTYPE_RTF: case SWTRANSFER_OBJECTTYPE_RICHTEXT: GetRTFWriter( aEmptyOUStr, OUString(), xWrt ); break; case SWTRANSFER_OBJECTTYPE_STRING: GetASCWriter( aEmptyOUStr, OUString(), xWrt ); if( xWrt.is() ) { SwAsciiOptions aAOpt; aAOpt.SetCharSet( RTL_TEXTENCODING_UTF8 ); xWrt->SetAsciiOptions( aAOpt ); // no start char for clipboard xWrt->bUCS2_WithStartChar = false; } break; default: break; } if( xWrt.is() ) { SwDoc* pDoc = static_cast(pObject); xWrt->bWriteClipboardDoc = true; xWrt->bWriteOnlyFirstTable = bool(TransferBufferType::Table & m_eBufferType); xWrt->SetShowProgress(false); #if defined(DEBUGPASTE) SvFileStream aPasteDebug(OUString( "PASTEBUFFER.debug"), StreamMode::WRITE|StreamMode::TRUNC); SwWriter aDbgWrt( aPasteDebug, *pDoc ); aDbgWrt.Write( xWrt ); #endif SwWriter aWrt( *xStream, *pDoc ); if( ! aWrt.Write( xWrt ).IsError() ) { xStream->WriteChar( '\0' ); // terminate with a zero xStream->Commit(); bRet = true; } } return bRet; } int SwTransferable::Cut() { int nRet = Copy( true ); if( nRet ) DeleteSelection(); return nRet; } void SwTransferable::DeleteSelection() { if(!m_pWrtShell) return; // ask for type of selection before action-bracketing const SelectionType nSelection = m_pWrtShell->GetSelectionType(); m_pWrtShell->StartUndo( SwUndoId::START ); if( ( SelectionType::Text | SelectionType::Table ) & nSelection ) m_pWrtShell->IntelligentCut( nSelection ); m_pWrtShell->DelRight(); m_pWrtShell->EndUndo( SwUndoId::END ); } int SwTransferable::PrepareForCopy( bool bIsCut ) { int nRet = 1; if(!m_pWrtShell) return 0; OUString sGrfNm; const SelectionType nSelection = m_pWrtShell->GetSelectionType(); if( nSelection == SelectionType::Graphic ) { m_pClpGraphic.reset(new Graphic); if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_pClpGraphic )) m_pOrigGraphic = m_pClpGraphic.get(); m_pClpBitmap.reset(new Graphic); if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_pClpBitmap )) m_pOrigGraphic = m_pClpBitmap.get(); m_pClpDocFac = new SwDocFac; SwDoc *const pDoc = lcl_GetDoc(*m_pClpDocFac); m_pWrtShell->Copy( pDoc ); if (m_pOrigGraphic && !m_pOrigGraphic->GetBitmap().IsEmpty()) AddFormat( SotClipboardFormatId::SVXB ); PrepareOLE( m_aObjDesc ); AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ); const Graphic* pGrf = m_pWrtShell->GetGraphic(); if( pGrf && pGrf->IsSupportedGraphic() ) { AddFormat( SotClipboardFormatId::GDIMETAFILE ); AddFormat( SotClipboardFormatId::PNG ); AddFormat( SotClipboardFormatId::BITMAP ); } m_eBufferType = TransferBufferType::Graphic; m_pWrtShell->GetGrfNms( &sGrfNm, nullptr ); } else if ( nSelection == SelectionType::Ole ) { m_pClpDocFac = new SwDocFac; SwDoc *const pDoc = lcl_GetDoc(*m_pClpDocFac); m_aDocShellRef = new SwDocShell( pDoc, SfxObjectCreateMode::EMBEDDED); m_aDocShellRef->DoInitNew(); m_pWrtShell->Copy( pDoc ); AddFormat( SotClipboardFormatId::EMBED_SOURCE ); // --> OD #i98753# // set size of embedded object at the object description structure m_aObjDesc.maSize = OutputDevice::LogicToLogic(m_pWrtShell->GetObjSize(), MapMode(MapUnit::MapTwip), MapMode(MapUnit::Map100thMM)); // <-- PrepareOLE( m_aObjDesc ); AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ); AddFormat( SotClipboardFormatId::GDIMETAFILE ); // Fetch the formats supported via embedtransferhelper as well sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT; uno::Reference < embed::XEmbeddedObject > xObj = FindOLEObj( nAspect ); const Graphic* pOLEGraph = FindOLEReplacementGraphic(); if( xObj.is() ) { TransferableDataHelper aD( new SvEmbedTransferHelper( xObj, pOLEGraph, nAspect ) ); if ( aD.GetTransferable().is() ) { DataFlavorExVector aVector( aD.GetDataFlavorExVector() ); DataFlavorExVector::iterator aIter( aVector.begin() ), aEnd( aVector.end() ); while( aIter != aEnd ) AddFormat( *aIter++ ); } } m_eBufferType = TransferBufferType::Ole; } // Is there anything to provide anyway? else if ( m_pWrtShell->IsSelection() || m_pWrtShell->IsFrameSelected() || m_pWrtShell->IsObjSelected() ) { std::unique_ptr pWait; if( m_pWrtShell->ShouldWait() ) pWait.reset(new SwWait( *m_pWrtShell->GetView().GetDocShell(), true )); m_pClpDocFac = new SwDocFac; // create additional cursor so that equal treatment of keyboard // and mouse selection is possible. // In AddMode with keyboard selection, the new cursor is not created // before the cursor is moved after end of selection. if( m_pWrtShell->IsAddMode() && m_pWrtShell->SwCursorShell::HasSelection() ) m_pWrtShell->CreateCursor(); SwDoc *const pTmpDoc = lcl_GetDoc(*m_pClpDocFac); pTmpDoc->getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is lclOverWriteDoc(*m_pWrtShell, *pTmpDoc); { IDocumentMarkAccess* const pMarkAccess = pTmpDoc->getIDocumentMarkAccess(); std::vector< ::sw::mark::IMark* > vDdeMarks; // find all DDE-Bookmarks for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin(); ppMark != pMarkAccess->getAllMarksEnd(); ++ppMark) { if(IDocumentMarkAccess::MarkType::DDE_BOOKMARK == IDocumentMarkAccess::GetType(**ppMark)) vDdeMarks.push_back(ppMark->get()); } // remove all DDE-Bookmarks, they are invalid inside the clipdoc! for(std::vector< ::sw::mark::IMark* >::iterator ppMark = vDdeMarks.begin(); ppMark != vDdeMarks.end(); ++ppMark) pMarkAccess->deleteMark(*ppMark); } // a new one was created in CORE (OLE objects copied!) m_aDocShellRef = pTmpDoc->GetTmpDocShell(); if( m_aDocShellRef.Is() ) SwTransferable::InitOle( m_aDocShellRef ); pTmpDoc->SetTmpDocShell( nullptr ); if( m_pWrtShell->IsObjSelected() ) m_eBufferType = TransferBufferType::Drawing; else { m_eBufferType = TransferBufferType::Document; if (m_pWrtShell->IntelligentCut(nSelection, false) != SwWrtShell::NO_WORD) m_eBufferType = TransferBufferType::DocumentWord | m_eBufferType; } bool bDDELink = m_pWrtShell->IsSelection(); if( nSelection & SelectionType::TableCell ) { m_eBufferType = TransferBufferType::Table | m_eBufferType; bDDELink = m_pWrtShell->HasWholeTabSelection(); } //When someone needs it, we 'OLE' him something AddFormat( SotClipboardFormatId::EMBED_SOURCE ); //put RTF ahead of the OLE's Metafile to have less loss if( !m_pWrtShell->IsObjSelected() ) { AddFormat( SotClipboardFormatId::RTF ); AddFormat( SotClipboardFormatId::RICHTEXT ); AddFormat( SotClipboardFormatId::HTML ); } if( m_pWrtShell->IsSelection() ) AddFormat( SotClipboardFormatId::STRING ); if( nSelection & ( SelectionType::DrawObject | SelectionType::DbForm )) { AddFormat( SotClipboardFormatId::DRAWING ); if ( nSelection & SelectionType::DrawObject ) { AddFormat( SotClipboardFormatId::GDIMETAFILE ); AddFormat( SotClipboardFormatId::PNG ); AddFormat( SotClipboardFormatId::BITMAP ); } m_eBufferType = (TransferBufferType)( TransferBufferType::Graphic | m_eBufferType ); m_pClpGraphic.reset(new Graphic); if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_pClpGraphic )) m_pOrigGraphic = m_pClpGraphic.get(); m_pClpBitmap.reset(new Graphic); if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_pClpBitmap )) m_pOrigGraphic = m_pClpBitmap.get(); // is it an URL-Button ? OUString sURL; OUString sDesc; if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) ) { AddFormat( SotClipboardFormatId::STRING ); AddFormat( SotClipboardFormatId::SOLK ); AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ); AddFormat( SotClipboardFormatId::FILECONTENT ); AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ); AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ); m_eBufferType = TransferBufferType::InetField | m_eBufferType; nRet = 1; } } // at Cut, DDE-Link doesn't make sense!! SwDocShell* pDShell; if( !bIsCut && bDDELink && nullptr != ( pDShell = m_pWrtShell->GetDoc()->GetDocShell()) && SfxObjectCreateMode::STANDARD == pDShell->GetCreateMode() ) { AddFormat( SotClipboardFormatId::LINK ); m_xDdeLink = new SwTrnsfrDdeLink( *this, *m_pWrtShell ); } //ObjectDescriptor was already filly from the old DocShell. //Now adjust it. Thus in GetData the first query can still //be answered with delayed rendering. Size aSz( OLESIZE ); m_aObjDesc.maSize = OutputDevice::LogicToLogic(aSz, MapMode(MapUnit::MapTwip), MapMode(MapUnit::Map100thMM)); PrepareOLE( m_aObjDesc ); AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ); } else nRet = 0; if( m_pWrtShell->IsFrameSelected() ) { SfxItemSet aSet( m_pWrtShell->GetAttrPool(), svl::Items{} ); m_pWrtShell->GetFlyFrameAttr( aSet ); const SwFormatURL& rURL = static_cast(aSet.Get( RES_URL )); if( rURL.GetMap() ) { m_pImageMap.reset( new ImageMap( *rURL.GetMap() ) ); AddFormat( SotClipboardFormatId::SVIM ); } else if( !rURL.GetURL().isEmpty() ) { m_pTargetURL.reset(new INetImage( sGrfNm, rURL.GetURL(), rURL.GetTargetFrameName() )); AddFormat( SotClipboardFormatId::INET_IMAGE ); } } return nRet; } int SwTransferable::Copy( bool bIsCut ) { int nRet = PrepareForCopy( bIsCut ); if ( nRet ) { CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() ); } return nRet; } void SwTransferable::CalculateAndCopy() { if(!m_pWrtShell) return; SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true ); OUString aStr( m_pWrtShell->Calculate() ); m_pClpDocFac = new SwDocFac; SwDoc *const pDoc = lcl_GetDoc(*m_pClpDocFac); m_pWrtShell->Copy(pDoc, & aStr); m_eBufferType = TransferBufferType::Document; AddFormat( SotClipboardFormatId::STRING ); CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() ); } int SwTransferable::CopyGlossary( SwTextBlocks& rGlossary, const OUString& rStr ) { if(!m_pWrtShell) return 0; SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true ); m_pClpDocFac = new SwDocFac; SwDoc *const pCDoc = lcl_GetDoc(*m_pClpDocFac); SwNodes& rNds = pCDoc->GetNodes(); SwNodeIndex aNodeIdx( *rNds.GetEndOfContent().StartOfSectionNode() ); SwContentNode* pCNd = rNds.GoNext( &aNodeIdx ); // go to 1st ContentNode SwPaM aPam( *pCNd ); pCDoc->getIDocumentFieldsAccess().LockExpFields(); // never update fields - leave text as it is pCDoc->InsertGlossary( rGlossary, rStr, aPam ); // a new one was created in CORE (OLE-Objects copied!) m_aDocShellRef = pCDoc->GetTmpDocShell(); if( m_aDocShellRef.Is() ) SwTransferable::InitOle( m_aDocShellRef ); pCDoc->SetTmpDocShell( nullptr ); m_eBufferType = TransferBufferType::Document; //When someone needs it, we 'OLE' her something. AddFormat( SotClipboardFormatId::EMBED_SOURCE ); AddFormat( SotClipboardFormatId::RTF ); AddFormat( SotClipboardFormatId::RICHTEXT ); AddFormat( SotClipboardFormatId::HTML ); AddFormat( SotClipboardFormatId::STRING ); //ObjectDescriptor was already filled from the old DocShell. //Now adjust it. Thus in GetData the first query can still //be answered with delayed rendering. Size aSz( OLESIZE ); m_aObjDesc.maSize = OutputDevice::LogicToLogic(aSz, MapMode(MapUnit::MapTwip), MapMode(MapUnit::Map100thMM)); PrepareOLE( m_aObjDesc ); AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ); CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() ); return 1; } static inline uno::Reference < XTransferable > * lcl_getTransferPointer ( uno::Reference < XTransferable > &xRef ) { return &xRef; } bool SwTransferable::IsPaste( const SwWrtShell& rSh, const TransferableDataHelper& rData ) { // Check the common case first: We can always paste our own data! // If _only_ the internal format can be pasted, this check will // yield 'true', while the one below would give a (wrong) result 'false'. bool bIsPaste = ( GetSwTransferable( rData ) != nullptr ); // if it's not our own data, we need to have a closer look: if( ! bIsPaste ) { // determine the proper paste action, and return true if we find one uno::Reference xTransferable( rData.GetXTransferable() ); SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh ); sal_uInt16 nSourceOptions = (( SotExchangeDest::DOC_TEXTFRAME == nDestination || SotExchangeDest::SWDOC_FREE_AREA == nDestination || SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination || SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination ) ? EXCHG_IN_ACTION_COPY : EXCHG_IN_ACTION_MOVE); SotClipboardFormatId nFormat; // output param for GetExchangeAction sal_uInt8 nEventAction; // output param for GetExchangeAction sal_uInt8 nAction = SotExchange::GetExchangeAction( rData.GetDataFlavorExVector(), nDestination, nSourceOptions, /* ?? */ EXCHG_IN_ACTION_DEFAULT, /* ?? */ nFormat, nEventAction, SotClipboardFormatId::NONE, lcl_getTransferPointer ( xTransferable ) ); // if we find a suitable action, we can paste! bIsPaste = (EXCHG_INOUT_ACTION_NONE != nAction); } return bIsPaste; } bool SwTransferable::Paste(SwWrtShell& rSh, TransferableDataHelper& rData, RndStdIds nAnchorType) { sal_uInt8 nEventAction, nAction=0; SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh ); SotClipboardFormatId nFormat = SotClipboardFormatId::NONE; SotExchangeActionFlags nActionFlags = SotExchangeActionFlags::NONE; bool bSingleCellTable = false; if( GetSwTransferable( rData ) ) { nAction = EXCHG_OUT_ACTION_INSERT_PRIVATE; } else { sal_uInt16 nSourceOptions = (( SotExchangeDest::DOC_TEXTFRAME == nDestination || SotExchangeDest::SWDOC_FREE_AREA == nDestination || SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination || SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination ) ? EXCHG_IN_ACTION_COPY : EXCHG_IN_ACTION_MOVE); uno::Reference xTransferable( rData.GetXTransferable() ); nAction = SotExchange::GetExchangeAction( rData.GetDataFlavorExVector(), nDestination, nSourceOptions, /* ?? */ EXCHG_IN_ACTION_DEFAULT, /* ?? */ nFormat, nEventAction, SotClipboardFormatId::NONE, lcl_getTransferPointer ( xTransferable ), &nActionFlags ); } bool bInsertOleTable = ( EXCHG_OUT_ACTION_INSERT_OLE == nAction && ( rData.HasFormat( SotClipboardFormatId::SYLK ) || rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) ); // content of 1-cell tables is inserted as simple text if (bInsertOleTable) { OUString aExpand; if( rData.GetString( SotClipboardFormatId::STRING, aExpand )) { const sal_Int32 nNewlines{comphelper::string::getTokenCount(aExpand, '\n')}; const sal_Int32 nRows = nNewlines ? nNewlines-1 : 0; if ( nRows == 1 ) { const sal_Int32 nCols = comphelper::string::getTokenCount(aExpand.getToken(0, '\n'), '\t'); if (nCols == 1) bSingleCellTable = true; } } } bool bInsertOleTableInTable = (bInsertOleTable && !bSingleCellTable && (rSh.GetDoc()->IsIdxInTable(rSh.GetCursor()->GetNode()) != nullptr)); // special case for tables from draw application or 1-cell tables if( EXCHG_OUT_ACTION_INSERT_DRAWOBJ == nAction || bSingleCellTable || bInsertOleTableInTable ) { if( rData.HasFormat( SotClipboardFormatId::RTF ) ) { nAction = EXCHG_OUT_ACTION_INSERT_STRING; nFormat = SotClipboardFormatId::RTF; } else if( rData.HasFormat( SotClipboardFormatId::RICHTEXT ) ) { nAction = EXCHG_OUT_ACTION_INSERT_STRING; nFormat = SotClipboardFormatId::RICHTEXT; } } // tdf#37223 insert OLE table in text tables as a native text table // (first as an RTF nested table, and cut and paste that to get a // native table insertion, removing also the temporary nested table) // TODO set a working view lock to avoid of showing the temporary nested table for a moment if (bInsertOleTableInTable && EXCHG_OUT_ACTION_INSERT_STRING == nAction) { bool bPasted = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat, nDestination, false, false, nullptr, 0, false, nAnchorType ); if (bPasted && rSh.DoesUndo()) { SfxDispatcher* pDispatch = rSh.GetView().GetViewFrame()->GetDispatcher(); pDispatch->Execute(FN_PREV_TABLE, SfxCallMode::SYNCHRON); pDispatch->Execute(FN_TABLE_SELECT_ALL, SfxCallMode::SYNCHRON); pDispatch->Execute(SID_COPY, SfxCallMode::SYNCHRON); pDispatch->Execute(SID_UNDO, SfxCallMode::SYNCHRON); pDispatch->Execute(SID_PASTE, SfxCallMode::SYNCHRON); } return bPasted; } return EXCHG_INOUT_ACTION_NONE != nAction && SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat, nDestination, false, false, nullptr, 0, false, nAnchorType ); } bool SwTransferable::PasteData( TransferableDataHelper& rData, SwWrtShell& rSh, sal_uInt8 nAction, SotExchangeActionFlags nActionFlags, SotClipboardFormatId nFormat, SotExchangeDest nDestination, bool bIsPasteFormat, bool bIsDefault, const Point* pPt, sal_Int8 nDropAction, bool bPasteSelection, RndStdIds nAnchorType ) { SwWait aWait( *rSh.GetView().GetDocShell(), false ); std::unique_ptr> pAction; SwModule* pMod = SW_MOD(); bool bRet = false; bool bCallAutoCaption = false; if( pPt ) { // external Drop if( bPasteSelection ? !pMod->m_pXSelection : !pMod->m_pDragDrop ) { switch( nDestination ) { case SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP: case SotExchangeDest::DOC_LNKD_GRAPHOBJ: case SotExchangeDest::DOC_GRAPH_W_IMAP: case SotExchangeDest::DOC_GRAPHOBJ: case SotExchangeDest::DOC_OLEOBJ: case SotExchangeDest::DOC_DRAWOBJ: case SotExchangeDest::DOC_URLBUTTON: case SotExchangeDest::DOC_GROUPOBJ: // select frames/objects SwTransferable::SetSelInShell( rSh, true, pPt ); break; default: SwTransferable::SetSelInShell( rSh, false, pPt ); break; } } } else if( ( !GetSwTransferable( rData ) || bIsPasteFormat ) && !rSh.IsTableMode() && rSh.HasSelection() ) { // then delete the selections //don't delete selected content // - at table-selection // - at ReRead of a graphic/DDEData // - at D&D, for the right selection was taken care of // in Drop-Handler bool bDelSel = false; switch( nDestination ) { case SotExchangeDest::DOC_TEXTFRAME: case SotExchangeDest::SWDOC_FREE_AREA: case SotExchangeDest::DOC_TEXTFRAME_WEB: case SotExchangeDest::SWDOC_FREE_AREA_WEB: bDelSel = true; break; default: break; } if( bDelSel ) // #i34830# pAction.reset(new SwTrnsfrActionAndUndo( &rSh, true )); } SwTransferable *pTrans=nullptr, *pTunneledTrans=GetSwTransferable( rData ); // check for private drop bool bPrivateDrop(pPt && (bPasteSelection ? nullptr != (pTrans = pMod->m_pXSelection) : nullptr != (pTrans = pMod->m_pDragDrop))); bool bNeedToSelectBeforePaste(false); if(bPrivateDrop && DND_ACTION_LINK == nDropAction) { // internal drop on object, suppress bPrivateDrop to change internal fill bPrivateDrop = false; bNeedToSelectBeforePaste = true; } if(bPrivateDrop && pPt && DND_ACTION_MOVE == nDropAction) { // check if dragged over a useful target. If yes, use as content exchange // drop as if from external const SwFrameFormat* pSwFrameFormat = rSh.GetFormatFromObj(*pPt); if(pSwFrameFormat && dynamic_cast< const SwDrawFrameFormat* >(pSwFrameFormat) != nullptr) { bPrivateDrop = false; bNeedToSelectBeforePaste = true; } } if(bPrivateDrop) { // then internal Drag & Drop or XSelection bRet = pTrans->PrivateDrop( rSh, *pPt, DND_ACTION_MOVE == nDropAction, bPasteSelection ); } else if( !pPt && pTunneledTrans && EXCHG_OUT_ACTION_INSERT_PRIVATE == nAction ) { // then internal paste bRet = pTunneledTrans->PrivatePaste( rSh ); } else if( EXCHG_INOUT_ACTION_NONE != nAction ) { if( !pAction ) { pAction.reset(new SwTrnsfrActionAndUndo( &rSh )); } // in Drag&Drop MessageBoxes must not be showed bool bMsg = nullptr == pPt; // delete selections switch( nAction ) { case EXCHG_OUT_ACTION_INSERT_PRIVATE: OSL_ENSURE( pPt, "EXCHG_OUT_ACTION_INSERT_PRIVATE: what should happen here?" ); break; case EXCHG_OUT_ACTION_MOVE_PRIVATE: OSL_ENSURE( pPt, "EXCHG_OUT_ACTION_MOVE_PRIVATE: what should happen here?" ); break; case EXCHG_IN_ACTION_MOVE: case EXCHG_IN_ACTION_COPY: case EXCHG_IN_ACTION_LINK: case EXCHG_OUT_ACTION_INSERT_HTML: case EXCHG_OUT_ACTION_INSERT_STRING: case EXCHG_OUT_ACTION_INSERT_IMAGEMAP: case EXCHG_OUT_ACTION_REPLACE_IMAGEMAP: // then we have to use the format switch( nFormat ) { case SotClipboardFormatId::DRAWING: bRet = SwTransferable::PasteSdrFormat( rData, rSh, SwPasteSdr::Insert, pPt, nActionFlags, bNeedToSelectBeforePaste); break; case SotClipboardFormatId::HTML: case SotClipboardFormatId::HTML_SIMPLE: case SotClipboardFormatId::HTML_NO_COMMENT: case SotClipboardFormatId::RTF: case SotClipboardFormatId::RICHTEXT: case SotClipboardFormatId::STRING: bRet = SwTransferable::PasteFileContent( rData, rSh, nFormat, bMsg ); break; case SotClipboardFormatId::NETSCAPE_BOOKMARK: { INetBookmark aBkmk; if( rData.GetINetBookmark( nFormat, aBkmk ) ) { SwFormatINetFormat aFormat( aBkmk.GetURL(), OUString() ); rSh.InsertURL( aFormat, aBkmk.GetDescription() ); bRet = true; } } break; case SotClipboardFormatId::SD_OLE: bRet = SwTransferable::PasteOLE( rData, rSh, nFormat, nActionFlags, bMsg ); break; case SotClipboardFormatId::SVIM: bRet = SwTransferable::PasteImageMap( rData, rSh ); break; case SotClipboardFormatId::SVXB: case SotClipboardFormatId::BITMAP: case SotClipboardFormatId::PNG: case SotClipboardFormatId::GDIMETAFILE: bRet = SwTransferable::PasteGrf( rData, rSh, nFormat, SwPasteSdr::Insert,pPt, nActionFlags, nDropAction, bNeedToSelectBeforePaste); break; case SotClipboardFormatId::XFORMS: case SotClipboardFormatId::SBA_FIELDDATAEXCHANGE: case SotClipboardFormatId::SBA_DATAEXCHANGE: case SotClipboardFormatId::SBA_CTRLDATAEXCHANGE: bRet = SwTransferable::PasteDBData( rData, rSh, nFormat, EXCHG_IN_ACTION_LINK == nAction, pPt, bMsg ); break; case SotClipboardFormatId::SIMPLE_FILE: bRet = SwTransferable::PasteFileName( rData, rSh, nFormat, ( EXCHG_IN_ACTION_MOVE == nAction ? SwPasteSdr::Replace : EXCHG_IN_ACTION_LINK == nAction ? SwPasteSdr::SetAttr : SwPasteSdr::Insert), pPt, nActionFlags, nullptr ); break; case SotClipboardFormatId::FILE_LIST: // then insert as graphics only bRet = SwTransferable::PasteFileList( rData, rSh, EXCHG_IN_ACTION_LINK == nAction, pPt, bMsg ); break; case SotClipboardFormatId::SONLK: if( pPt ) { NaviContentBookmark aBkmk; if( aBkmk.Paste( rData ) ) { if(bIsDefault) { switch(aBkmk.GetDefaultDragType()) { case RegionMode::NONE: nAction = EXCHG_IN_ACTION_COPY; break; case RegionMode::EMBEDDED: nAction = EXCHG_IN_ACTION_MOVE; break; case RegionMode::LINK: nAction = EXCHG_IN_ACTION_LINK; break; } } rSh.NavigatorPaste( aBkmk, nAction ); bRet = true; } } break; case SotClipboardFormatId::INET_IMAGE: case SotClipboardFormatId::NETSCAPE_IMAGE: bRet = SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::Insert, pPt, true ); break; default: OSL_ENSURE( pPt, "unknown format" ); } break; case EXCHG_OUT_ACTION_INSERT_FILE: { bool graphicInserted; bRet = SwTransferable::PasteFileName( rData, rSh, nFormat, SwPasteSdr::Insert, pPt, nActionFlags, &graphicInserted ); if( graphicInserted ) bCallAutoCaption = true; } break; case EXCHG_OUT_ACTION_INSERT_OLE: bRet = SwTransferable::PasteOLE( rData, rSh, nFormat, nActionFlags,bMsg ); break; case EXCHG_OUT_ACTION_INSERT_DDE: { bool bReRead = 0 != CNT_HasGrf( rSh.GetCntType() ); bRet = SwTransferable::PasteDDE( rData, rSh, bReRead, bMsg ); } break; case EXCHG_OUT_ACTION_INSERT_HYPERLINK: { OUString sURL, sDesc; if( SotClipboardFormatId::SIMPLE_FILE == nFormat ) { if( rData.GetString( nFormat, sURL ) && !sURL.isEmpty() ) { SwTransferable::CheckForURLOrLNKFile( rData, sURL, &sDesc ); if( sDesc.isEmpty() ) sDesc = sURL; bRet = true; } } else { INetBookmark aBkmk; if( rData.GetINetBookmark( nFormat, aBkmk ) ) { sURL = aBkmk.GetURL(); sDesc = aBkmk.GetDescription(); bRet = true; } } if( bRet ) { SwFormatINetFormat aFormat( sURL, OUString() ); rSh.InsertURL( aFormat, sDesc ); } } break; case EXCHG_OUT_ACTION_GET_ATTRIBUTES: switch( nFormat ) { case SotClipboardFormatId::DRAWING: bRet = SwTransferable::PasteSdrFormat( rData, rSh, SwPasteSdr::SetAttr, pPt, nActionFlags, bNeedToSelectBeforePaste); break; case SotClipboardFormatId::SVXB: case SotClipboardFormatId::GDIMETAFILE: case SotClipboardFormatId::BITMAP: case SotClipboardFormatId::PNG: case SotClipboardFormatId::NETSCAPE_BOOKMARK: case SotClipboardFormatId::SIMPLE_FILE: case SotClipboardFormatId::FILEGRPDESCRIPTOR: case SotClipboardFormatId::UNIFORMRESOURCELOCATOR: bRet = SwTransferable::PasteGrf( rData, rSh, nFormat, SwPasteSdr::SetAttr, pPt, nActionFlags, nDropAction, bNeedToSelectBeforePaste); break; default: OSL_FAIL( "unknown format" ); } break; case EXCHG_OUT_ACTION_INSERT_DRAWOBJ: bRet = SwTransferable::PasteSdrFormat( rData, rSh, SwPasteSdr::Insert, pPt, nActionFlags, bNeedToSelectBeforePaste); break; case EXCHG_OUT_ACTION_INSERT_SVXB: case EXCHG_OUT_ACTION_INSERT_GDIMETAFILE: case EXCHG_OUT_ACTION_INSERT_BITMAP: case EXCHG_OUT_ACTION_INSERT_GRAPH: bRet = SwTransferable::PasteGrf( rData, rSh, nFormat, SwPasteSdr::Insert, pPt, nActionFlags, nDropAction, bNeedToSelectBeforePaste, nAnchorType ); break; case EXCHG_OUT_ACTION_REPLACE_DRAWOBJ: bRet = SwTransferable::PasteSdrFormat( rData, rSh, SwPasteSdr::Replace, pPt, nActionFlags, bNeedToSelectBeforePaste); break; case EXCHG_OUT_ACTION_REPLACE_SVXB: case EXCHG_OUT_ACTION_REPLACE_GDIMETAFILE: case EXCHG_OUT_ACTION_REPLACE_BITMAP: case EXCHG_OUT_ACTION_REPLACE_GRAPH: bRet = SwTransferable::PasteGrf( rData, rSh, nFormat, SwPasteSdr::Replace,pPt, nActionFlags, nDropAction, bNeedToSelectBeforePaste); break; case EXCHG_OUT_ACTION_INSERT_INTERACTIVE: bRet = SwTransferable::PasteAsHyperlink( rData, rSh, nFormat ); break; default: OSL_FAIL("unknown action" ); } } if( !bPasteSelection && rSh.IsFrameSelected() ) { rSh.EnterSelFrameMode(); //force ::SelectShell rSh.GetView().StopShellTimer(); } pAction.reset(); if( bCallAutoCaption ) rSh.GetView().AutoCaption( GRAPHIC_CAP ); return bRet; } SotExchangeDest SwTransferable::GetSotDestination( const SwWrtShell& rSh ) { SotExchangeDest nRet = SotExchangeDest::NONE; ObjCntType eOType = rSh.GetObjCntTypeOfSelection(); switch( eOType ) { case OBJCNT_GRF: { bool bIMap, bLink; bIMap = nullptr != rSh.GetFlyFrameFormat()->GetURL().GetMap(); OUString aDummy; rSh.GetGrfNms( &aDummy, nullptr ); bLink = !aDummy.isEmpty(); if( bLink && bIMap ) nRet = SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP; else if( bLink ) nRet = SotExchangeDest::DOC_LNKD_GRAPHOBJ; else if( bIMap ) nRet = SotExchangeDest::DOC_GRAPH_W_IMAP; else nRet = SotExchangeDest::DOC_GRAPHOBJ; } break; case OBJCNT_FLY: if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr ) nRet = SotExchangeDest::DOC_TEXTFRAME_WEB; else nRet = SotExchangeDest::DOC_TEXTFRAME; break; case OBJCNT_OLE: nRet = SotExchangeDest::DOC_OLEOBJ; break; case OBJCNT_CONTROL: /* no Action avail */ case OBJCNT_SIMPLE: nRet = SotExchangeDest::DOC_DRAWOBJ; break; case OBJCNT_URLBUTTON: nRet = SotExchangeDest::DOC_URLBUTTON; break; case OBJCNT_GROUPOBJ: nRet = SotExchangeDest::DOC_GROUPOBJ; break; // what do we do at multiple selections??? default: { if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr ) nRet = SotExchangeDest::SWDOC_FREE_AREA_WEB; else nRet = SotExchangeDest::SWDOC_FREE_AREA; } } return nRet; } bool SwTransferable::PasteFileContent( TransferableDataHelper& rData, SwWrtShell& rSh, SotClipboardFormatId nFormat, bool bMsg ) { const char* pResId = STR_CLPBRD_FORMAT_ERROR; bool bRet = false; MSE40HTMLClipFormatObj aMSE40ClpObj; tools::SvRef xStrm; SvStream* pStream = nullptr; SwRead pRead = nullptr; OUString sData; switch( nFormat ) { case SotClipboardFormatId::STRING: { pRead = ReadAscii; if( rData.GetString( nFormat, sData ) ) { pStream = new SvMemoryStream( const_cast(sData.getStr()), sData.getLength() * sizeof( sal_Unicode ), StreamMode::READ ); #ifdef OSL_BIGENDIAN pStream->SetEndian( SvStreamEndian::BIG ); #else pStream->SetEndian( SvStreamEndian::LITTLE ); #endif SwAsciiOptions aAOpt; aAOpt.SetCharSet( RTL_TEXTENCODING_UCS2 ); pRead->GetReaderOpt().SetASCIIOpts( aAOpt ); break; } } SAL_FALLTHROUGH; // because then test if we get a stream default: if( rData.GetSotStorageStream( nFormat, xStrm ) ) { if( ( SotClipboardFormatId::HTML_SIMPLE == nFormat ) || ( SotClipboardFormatId::HTML_NO_COMMENT == nFormat ) ) { pStream = aMSE40ClpObj.IsValid( *xStrm ); pRead = ReadHTML; pRead->SetReadUTF8( true ); bool bNoComments = ( nFormat == SotClipboardFormatId::HTML_NO_COMMENT ); pRead->SetIgnoreHTMLComments( bNoComments ); } else { pStream = xStrm.get(); if( SotClipboardFormatId::RTF == nFormat || SotClipboardFormatId::RICHTEXT == nFormat) pRead = SwReaderWriter::GetRtfReader(); else if( !pRead ) { pRead = ReadHTML; pRead->SetReadUTF8( true ); } } } break; } if( pStream && pRead ) { Link aOldLink( rSh.GetChgLnk() ); rSh.SetChgLnk( Link() ); const SwPosition& rInsPos = *rSh.GetCursor()->Start(); SwReader aReader( *pStream, aEmptyOUStr, OUString(), *rSh.GetCursor() ); rSh.SaveTableBoxContent( &rInsPos ); if( aReader.Read( *pRead ).IsError() ) pResId = STR_ERROR_CLPBRD_READ; else { pResId = nullptr; bRet = true; } rSh.SetChgLnk( aOldLink ); if( bRet ) rSh.CallChgLnk(); } else pResId = STR_CLPBRD_FORMAT_ERROR; // Exist a SvMemoryStream? (data in the OUString and xStrm is empty) if( pStream && !xStrm.is() ) delete pStream; if (bMsg && pResId) { ScopedVclPtrInstance(nullptr, SwResId(pResId), VclMessageType::Info)->Execute(); } return bRet; } bool SwTransferable::PasteOLE( TransferableDataHelper& rData, SwWrtShell& rSh, SotClipboardFormatId nFormat, SotExchangeActionFlags nActionFlags, bool bMsg ) { bool bRet = false; TransferableObjectDescriptor aObjDesc; uno::Reference < io::XInputStream > xStrm; uno::Reference < embed::XStorage > xStore; Reader* pRead = nullptr; // Get the preferred format SotClipboardFormatId nId; if( rData.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ ) ) nId = SotClipboardFormatId::EMBEDDED_OBJ; else if( rData.HasFormat( SotClipboardFormatId::EMBED_SOURCE ) && rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR )) nId = SotClipboardFormatId::EMBED_SOURCE; else nId = SotClipboardFormatId::NONE; if (nId != SotClipboardFormatId::NONE) { SwDocShell* pDocSh = rSh.GetDoc()->GetDocShell(); xStrm = rData.GetInputStream(nId, SfxObjectShell::CreateShellID(pDocSh)); } if (xStrm.is()) { // if there is an embedded object, first try if it's a writer object // this will be inserted into the document by using a Reader try { xStore = comphelper::OStorageHelper::GetStorageFromInputStream( xStrm ); switch( SotStorage::GetFormatID( xStore ) ) { case SotClipboardFormatId::STARWRITER_60: case SotClipboardFormatId::STARWRITERWEB_60: case SotClipboardFormatId::STARWRITERGLOB_60: case SotClipboardFormatId::STARWRITER_8: case SotClipboardFormatId::STARWRITERWEB_8: case SotClipboardFormatId::STARWRITERGLOB_8: pRead = ReadXML; break; default: try { uno::Reference < lang::XComponent > xComp( xStore, uno::UNO_QUERY ); xComp->dispose(); xStore = nullptr; } catch (const uno::Exception&) { } break; } } catch (const uno::Exception&) { // it wasn't a storage, but maybe it's a useful stream } } if( pRead ) { SwPaM &rPAM = *rSh.GetCursor(); SwReader aReader( xStore, aEmptyOUStr, rPAM ); if( ! aReader.Read( *pRead ).IsError() ) bRet = true; else if( bMsg ) ScopedVclPtrInstance(nullptr, SwResId(STR_ERROR_CLPBRD_READ), VclMessageType::Info)->Execute(); } else { // temporary storage until the object is inserted uno::Reference< embed::XStorage > xTmpStor; uno::Reference < embed::XEmbeddedObject > xObj; OUString aName; comphelper::EmbeddedObjectContainer aCnt; if ( xStrm.is() ) { if ( !rData.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) ) { OSL_ENSURE( !xStrm.is(), "An object without descriptor in clipboard!"); } } else { if( rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR_OLE ) && rData.GetTransferableObjectDescriptor( nFormat, aObjDesc ) ) { xStrm = rData.GetInputStream(SotClipboardFormatId::EMBED_SOURCE_OLE, OUString()); if (!xStrm.is()) xStrm = rData.GetInputStream(SotClipboardFormatId::EMBEDDED_OBJ_OLE, OUString()); if ( !xStrm.is() ) { // This is MSOLE object that should be created by direct using of system clipboard try { xTmpStor = ::comphelper::OStorageHelper::GetTemporaryStorage(); uno::Reference < embed::XEmbedObjectClipboardCreator > xClipboardCreator = embed::MSOLEObjectSystemCreator::create( ::comphelper::getProcessComponentContext() ); embed::InsertedObjectInfo aInfo = xClipboardCreator->createInstanceInitFromClipboard( xTmpStor, "DummyName", uno::Sequence< beans::PropertyValue >() ); // TODO/LATER: in future InsertedObjectInfo will be used to get container related information // for example whether the object should be an iconified one xObj = aInfo.Object; } catch (const uno::Exception&) { } } } } if ( xStrm.is() && !xObj.is() ) xObj = aCnt.InsertEmbeddedObject( xStrm, aName ); if( xObj.is() ) { svt::EmbeddedObjectRef xObjRef( xObj, aObjDesc.mnViewAspect ); // try to get the replacement image from the clipboard Graphic aGraphic; SotClipboardFormatId nGrFormat = SotClipboardFormatId::NONE; // limit the size of the preview metafile to 100000 actions GDIMetaFile aMetafile; if (rData.GetGDIMetaFile(SotClipboardFormatId::GDIMETAFILE, aMetafile, 100000)) { nGrFormat = SotClipboardFormatId::GDIMETAFILE; aGraphic = aMetafile; } // insert replacement image ( if there is one ) into the object helper if ( nGrFormat != SotClipboardFormatId::NONE ) { DataFlavor aDataFlavor; SotExchange::GetFormatDataFlavor( nGrFormat, aDataFlavor ); xObjRef.SetGraphic( aGraphic, aDataFlavor.MimeType ); } else if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON ) { // it is important to have an icon, let an empty graphic be used // if no other graphic is provided // TODO/LATER: in future a default bitmap could be used MapMode aMapMode( MapUnit::Map100thMM ); aGraphic.SetPrefSize( Size( 2500, 2500 ) ); aGraphic.SetPrefMapMode( aMapMode ); xObjRef.SetGraphic( aGraphic, OUString() ); } //set size. This is a hack because of handing over, size should be //passed to the InsertOle!!!!!!!!!! Size aSize; if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON ) { if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() ) aSize = aObjDesc.maSize; else { MapMode aMapMode( MapUnit::Map100thMM ); aSize = xObjRef.GetSize( &aMapMode ); } } else if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() ) { aSize = aObjDesc.maSize; //always 100TH_MM MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( aObjDesc.mnViewAspect ) ); aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aUnit)); awt::Size aSz; try { aSz = xObj->getVisualAreaSize( aObjDesc.mnViewAspect ); } catch (const embed::NoVisualAreaSizeException&) { // in this case the provided size is used } if ( aSz.Width != aSize.Width() || aSz.Height != aSize.Height() ) { aSz.Width = aSize.Width(); aSz.Height = aSize.Height(); xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz ); } } else { // the descriptor contains the wrong object size // the following call will let the MSOLE objects cache the size if it is possible // it should be done while the object is running try { xObj->getVisualAreaSize( aObjDesc.mnViewAspect ); } catch (const uno::Exception&) { } } //End of Hack! rSh.InsertOleObject( xObjRef ); bRet = true; if( bRet && ( nActionFlags & SotExchangeActionFlags::InsertTargetUrl) ) SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false ); // let the object be unloaded if possible SwOLEObj::UnloadObject( xObj, rSh.GetDoc(), embed::Aspects::MSOLE_CONTENT ); } } return bRet; } bool SwTransferable::PasteTargetURL( TransferableDataHelper& rData, SwWrtShell& rSh, SwPasteSdr nAction, const Point* pPt, bool bInsertGRF ) { bool bRet = false; INetImage aINetImg; if( ( rData.HasFormat( SotClipboardFormatId::INET_IMAGE ) && rData.GetINetImage( SotClipboardFormatId::INET_IMAGE, aINetImg )) || ( rData.HasFormat( SotClipboardFormatId::NETSCAPE_IMAGE ) && rData.GetINetImage( SotClipboardFormatId::NETSCAPE_IMAGE, aINetImg )) ) { if( !aINetImg.GetImageURL().isEmpty() && bInsertGRF ) { OUString sURL( aINetImg.GetImageURL() ); SwTransferable::CheckForURLOrLNKFile( rData, sURL ); //!!! check at FileSystem - only then it make sense to test graphics !!! Graphic aGraphic; GraphicFilter &rFlt = GraphicFilter::GetGraphicFilter(); bRet = ERRCODE_NONE == GraphicFilter::LoadGraphic( sURL, aEmptyOUStr, aGraphic, &rFlt ); if( bRet ) { //Check and Perform rotation if needed lclCheckAndPerformRotation(aGraphic); switch( nAction ) { case SwPasteSdr::Insert: SwTransferable::SetSelInShell( rSh, false, pPt ); rSh.Insert( sURL, aEmptyOUStr, aGraphic ); break; case SwPasteSdr::Replace: if( rSh.IsObjSelected() ) { rSh.ReplaceSdrObj( sURL, &aGraphic ); Point aPt( pPt ? *pPt : rSh.GetCursorDocPos() ); SwTransferable::SetSelInShell( rSh, true, &aPt ); } else rSh.ReRead( sURL, aEmptyOUStr, &aGraphic ); break; case SwPasteSdr::SetAttr: if( rSh.IsObjSelected() ) rSh.Paste( aGraphic, OUString() ); else if( OBJCNT_GRF == rSh.GetObjCntTypeOfSelection() ) rSh.ReRead( sURL, aEmptyOUStr, &aGraphic ); else { SwTransferable::SetSelInShell( rSh, false, pPt ); rSh.Insert( sURL, aEmptyOUStr, aGraphic ); } break; default: bRet = false; } } } else bRet = true; } if( bRet ) { SfxItemSet aSet( rSh.GetAttrPool(), svl::Items{} ); rSh.GetFlyFrameAttr( aSet ); SwFormatURL aURL( static_cast(aSet.Get( RES_URL )) ); if( aURL.GetURL() != aINetImg.GetTargetURL() || aURL.GetTargetFrameName() != aINetImg.GetTargetFrame() ) { aURL.SetURL( aINetImg.GetTargetURL(), false ); aURL.SetTargetFrameName( aINetImg.GetTargetFrame() ); aSet.Put( aURL ); rSh.SetFlyFrameAttr( aSet ); } } return bRet; } void SwTransferable::SetSelInShell( SwWrtShell& rSh, bool bSelectFrame, const Point* pPt ) { if( bSelectFrame ) { // select frames/objects if( pPt && !rSh.GetView().GetViewFrame()->GetDispatcher()->IsLocked() ) { rSh.GetView().NoRotate(); if( rSh.SelectObj( *pPt )) { rSh.HideCursor(); rSh.EnterSelFrameMode( pPt ); g_bFrameDrag = true; } } } else { if( rSh.IsFrameSelected() || rSh.IsObjSelected() ) { rSh.UnSelectFrame(); rSh.LeaveSelFrameMode(); rSh.GetView().GetEditWin().StopInsFrame(); g_bFrameDrag = false; } else if( rSh.GetView().GetDrawFuncPtr() ) rSh.GetView().GetEditWin().StopInsFrame(); rSh.EnterStdMode(); if( pPt ) rSh.SwCursorShell::SetCursor( *pPt, true ); } } bool SwTransferable::PasteDDE( TransferableDataHelper& rData, SwWrtShell& rWrtShell, bool bReReadGrf, bool bMsg ) { // data from Clipboardformat OUString aApp, aTopic, aItem; { tools::SvRef xStrm; if( !rData.GetSotStorageStream( SotClipboardFormatId::LINK, xStrm )) { OSL_ENSURE( false, "DDE Data not found." ); return false; } // report useful error!! rtl_TextEncoding eEncoding = DDE_TXT_ENCODING; aApp = read_zeroTerminated_uInt8s_ToOUString(*xStrm, eEncoding); aTopic = read_zeroTerminated_uInt8s_ToOUString(*xStrm, eEncoding); aItem = read_zeroTerminated_uInt8s_ToOUString(*xStrm, eEncoding); } OUString aCmd; sfx2::MakeLnkName( aCmd, &aApp, aTopic, aItem ); // do we want to read in a graphic now? SotClipboardFormatId nFormat; if( !rData.HasFormat( SotClipboardFormatId::RTF ) && !rData.HasFormat( SotClipboardFormatId::RICHTEXT ) && !rData.HasFormat( SotClipboardFormatId::HTML ) && !rData.HasFormat( SotClipboardFormatId::STRING ) && (rData.HasFormat( nFormat = SotClipboardFormatId::GDIMETAFILE ) || rData.HasFormat( nFormat = SotClipboardFormatId::BITMAP )) ) { Graphic aGrf; bool bRet = rData.GetGraphic( nFormat, aGrf ); if( bRet ) { OUString sLnkTyp("DDE"); if ( bReReadGrf ) rWrtShell.ReRead( aCmd, sLnkTyp, &aGrf ); else rWrtShell.Insert( aCmd, sLnkTyp, aGrf ); } return bRet; } SwFieldType* pTyp = nullptr; size_t i = 1; size_t j; OUString aName; bool bDoublePaste = false; const size_t nSize = rWrtShell.GetFieldTypeCount(); const ::utl::TransliterationWrapper& rColl = ::GetAppCmpStrIgnore(); do { aName = aApp; aName += OUString::number( i ); for( j = INIT_FLDTYPES; j < nSize; j++ ) { pTyp = rWrtShell.GetFieldType( j ); if( SwFieldIds::Dde == pTyp->Which() ) { OUString sTmp( static_cast(pTyp)->GetCmd() ); if( rColl.isEqual( sTmp, aCmd ) && SfxLinkUpdateMode::ALWAYS == static_cast(pTyp)->GetType() ) { aName = pTyp->GetName(); bDoublePaste = true; break; } else if( rColl.isEqual( aName, pTyp->GetName() ) ) break; } } if( j == nSize ) break; ++i; } while( !bDoublePaste ); if( !bDoublePaste ) { SwDDEFieldType aType( aName, aCmd, SfxLinkUpdateMode::ALWAYS ); pTyp = rWrtShell.InsertFieldType( aType ); } SwDDEFieldType* pDDETyp = static_cast(pTyp); OUString aExpand; if( rData.GetString( SotClipboardFormatId::STRING, aExpand )) { do { // middle checked loop // When data comes from a spreadsheet, we add a DDE-table if( ( rData.HasFormat( SotClipboardFormatId::SYLK ) || rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) && !aExpand.isEmpty() && ( 1 < comphelper::string::getTokenCount(aExpand, '\n') || comphelper::string::getTokenCount(aExpand, '\t') ) ) { OUString sTmp( aExpand ); sal_Int32 nRows = comphelper::string::getTokenCount(sTmp, '\n'); if( nRows ) --nRows; sTmp = sTmp.getToken( 0, '\n' ); sal_Int32 nCols = comphelper::string::getTokenCount(sTmp, '\t'); // don't try to insert tables that are too large for writer if (nRows > USHRT_MAX || nCols > USHRT_MAX) { if( bMsg ) ScopedVclPtrInstance(nullptr, SwResId(STR_TABLE_TOO_LARGE), VclMessageType::Info)->Execute(); pDDETyp = nullptr; break; } // at least one column & row must be there if( !nRows || !nCols ) { if( bMsg ) ScopedVclPtrInstance(nullptr, SwResId(STR_NO_TABLE), VclMessageType::Info)->Execute(); pDDETyp = nullptr; break; } rWrtShell.InsertDDETable( SwInsertTableOptions( tabopts::SPLIT_LAYOUT, 1 ), // TODO MULTIHEADER pDDETyp, nRows, nCols ); } else if( 1 < comphelper::string::getTokenCount(aExpand, '\n') ) { // multiple paragraphs -> insert a protected section if( rWrtShell.HasSelection() ) rWrtShell.DelRight(); SwSectionData aSect( DDE_LINK_SECTION, aName ); aSect.SetLinkFileName( aCmd ); aSect.SetProtectFlag(true); rWrtShell.InsertSection( aSect ); pDDETyp = nullptr; // remove FieldTypes again } else { // insert SwDDEField aSwDDEField( pDDETyp ); rWrtShell.Insert( aSwDDEField ); } } while( false ); } else pDDETyp = nullptr; // remove FieldTypes again if( !pDDETyp && !bDoublePaste ) { // remove FieldType again - error occurred! for( j = nSize; j >= INIT_FLDTYPES; --j ) if( pTyp == rWrtShell.GetFieldType( j ) ) { rWrtShell.RemoveFieldType( j ); break; } } return true; } bool SwTransferable::PasteSdrFormat( TransferableDataHelper& rData, SwWrtShell& rSh, SwPasteSdr nAction, const Point* pPt, SotExchangeActionFlags nActionFlags, bool bNeedToSelectBeforePaste) { bool bRet = false; tools::SvRef xStrm; if( rData.GetSotStorageStream( SotClipboardFormatId::DRAWING, xStrm )) { xStrm->SetVersion( SOFFICE_FILEFORMAT_50 ); if(bNeedToSelectBeforePaste && pPt) { // if this is an internal drag, need to set the target right (select it), else // still the source will be selected SwTransferable::SetSelInShell( rSh, true, pPt ); } rSh.Paste( *xStrm, nAction, pPt ); bRet = true; if( bRet && ( nActionFlags & SotExchangeActionFlags::InsertTargetUrl )) SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false ); } return bRet; } bool SwTransferable::PasteGrf( TransferableDataHelper& rData, SwWrtShell& rSh, SotClipboardFormatId nFormat, SwPasteSdr nAction, const Point* pPt, SotExchangeActionFlags nActionFlags, sal_Int8 nDropAction, bool bNeedToSelectBeforePaste, RndStdIds nAnchorType ) { bool bRet = false; Graphic aGraphic; INetBookmark aBkmk; bool bCheckForGrf = false, bCheckForImageMap = false; switch( nFormat ) { case SotClipboardFormatId::BITMAP: case SotClipboardFormatId::PNG: case SotClipboardFormatId::GDIMETAFILE: bRet = rData.GetGraphic( nFormat, aGraphic ); break; case SotClipboardFormatId::SVXB: { tools::SvRef xStm; if(rData.GetSotStorageStream(SotClipboardFormatId::SVXB, xStm)) { ReadGraphic( *xStm, aGraphic ); bRet = (GraphicType::NONE != aGraphic.GetType() && GraphicType::Default != aGraphic.GetType()); } break; } case SotClipboardFormatId::NETSCAPE_BOOKMARK: case SotClipboardFormatId::FILEGRPDESCRIPTOR: case SotClipboardFormatId::UNIFORMRESOURCELOCATOR: bRet = rData.GetINetBookmark( nFormat, aBkmk ); if( bRet ) { if( SwPasteSdr::SetAttr == nAction ) nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK; else bCheckForGrf = true; } break; case SotClipboardFormatId::SIMPLE_FILE: { OUString sText; bRet = rData.GetString( nFormat, sText ); if( bRet ) { OUString sDesc; SwTransferable::CheckForURLOrLNKFile( rData, sText, &sDesc ); aBkmk = INetBookmark( URIHelper::SmartRel2Abs(INetURLObject(), sText, Link(), false ), sDesc ); bCheckForGrf = true; bCheckForImageMap = SwPasteSdr::Replace == nAction; } } break; default: bRet = rData.GetGraphic( nFormat, aGraphic ); break; } if( bCheckForGrf ) { //!!! check at FileSystem - only then it makes sense to test the graphics !!! GraphicFilter &rFlt = GraphicFilter::GetGraphicFilter(); bRet = ERRCODE_NONE == GraphicFilter::LoadGraphic( aBkmk.GetURL(), aEmptyOUStr, aGraphic, &rFlt ); if( !bRet && SwPasteSdr::SetAttr == nAction && SotClipboardFormatId::SIMPLE_FILE == nFormat && // only at frame selection rSh.IsFrameSelected() ) { // then set as hyperlink after the graphic nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK; bRet = true; } } if(pPt && bNeedToSelectBeforePaste) { // when using internal D&Ds, still the source object is selected and // this is necessary to get the correct source data which is also // dependent from selection. After receiving the drag data it is // now time to select the correct target object SwTransferable::SetSelInShell( rSh, true, pPt ); } if( bRet ) { //Check and Perform rotation if needed lclCheckAndPerformRotation(aGraphic); OUString sURL; if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr // #i123922# if link action is noted, also take URL || DND_ACTION_LINK == nDropAction) { sURL = aBkmk.GetURL(); } switch( nAction ) { case SwPasteSdr::Insert: { SwTransferable::SetSelInShell( rSh, false, pPt ); rSh.Insert( sURL, aEmptyOUStr, aGraphic, nullptr, nAnchorType ); break; } case SwPasteSdr::Replace: { if( rSh.IsObjSelected() ) { // #i123922# for D&D on draw objects, do for now the same for // SwPasteSdr::Replace (D&D) as for SwPasteSdr::SetAttr (D&D and // CTRL+SHIFT). The code below replaces the draw object with // a writer graphic; maybe this is an option later again if wanted rSh.Paste( aGraphic, sURL ); // rSh.ReplaceSdrObj( sURL, aEmptyOUStr, &aGraphic ); // Point aPt( pPt ? *pPt : rSh.GetCursorDocPos() ); // SwTransferable::SetSelInShell( rSh, true, &aPt ); } else { // set graphic at writer graphic without link rSh.ReRead( sURL, aEmptyOUStr, &aGraphic ); } break; } case SwPasteSdr::SetAttr: { if( SotClipboardFormatId::NETSCAPE_BOOKMARK == nFormat ) { if( rSh.IsFrameSelected() ) { SfxItemSet aSet( rSh.GetAttrPool(), svl::Items{} ); rSh.GetFlyFrameAttr( aSet ); SwFormatURL aURL( static_cast(aSet.Get( RES_URL )) ); aURL.SetURL( aBkmk.GetURL(), false ); aSet.Put( aURL ); rSh.SetFlyFrameAttr( aSet ); } } else if( rSh.IsObjSelected() ) { // set as attribute at DrawObject rSh.Paste( aGraphic, sURL ); } else if( OBJCNT_GRF == rSh.GetObjCntTypeOfSelection() ) { // set as linked graphic at writer graphic frame rSh.ReRead( sURL, aEmptyOUStr, &aGraphic ); } else { SwTransferable::SetSelInShell( rSh, false, pPt ); rSh.Insert( aBkmk.GetURL(), aEmptyOUStr, aGraphic ); } break; } default: { bRet = false; break; } } } if( bRet ) { if( nActionFlags & ( SotExchangeActionFlags::InsertImageMap | SotExchangeActionFlags::ReplaceImageMap ) ) SwTransferable::PasteImageMap( rData, rSh ); if( nActionFlags & SotExchangeActionFlags::InsertTargetUrl ) SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false ); } else if( bCheckForImageMap ) { // or should the file be an ImageMap-File? ImageMap aMap; SfxMedium aMed( INetURLObject(aBkmk.GetURL()).GetFull(), StreamMode::STD_READ ); SvStream* pStream = aMed.GetInStream(); if( pStream != nullptr && !pStream->GetError() && // mba: no BaseURL for clipboard functionality aMap.Read( *pStream, IMAP_FORMAT_DETECT ) == IMAP_ERR_OK && aMap.GetIMapObjectCount() ) { SfxItemSet aSet( rSh.GetAttrPool(), svl::Items{} ); rSh.GetFlyFrameAttr( aSet ); SwFormatURL aURL( static_cast(aSet.Get( RES_URL )) ); aURL.SetMap( &aMap ); aSet.Put( aURL ); rSh.SetFlyFrameAttr( aSet ); bRet = true; } } return bRet; } bool SwTransferable::PasteImageMap( TransferableDataHelper& rData, SwWrtShell& rSh ) { bool bRet = false; if( rData.HasFormat( SotClipboardFormatId::SVIM )) { SfxItemSet aSet( rSh.GetAttrPool(), svl::Items{} ); rSh.GetFlyFrameAttr( aSet ); SwFormatURL aURL( static_cast(aSet.Get( RES_URL )) ); const ImageMap* pOld = aURL.GetMap(); // set or replace, that is the question ImageMap aImageMap; if( rData.GetImageMap( SotClipboardFormatId::SVIM, aImageMap ) && ( !pOld || aImageMap != *pOld )) { aURL.SetMap( &aImageMap ); aSet.Put( aURL ); rSh.SetFlyFrameAttr( aSet ); } bRet = true; } return bRet; } bool SwTransferable::PasteAsHyperlink( TransferableDataHelper& rData, SwWrtShell& rSh, SotClipboardFormatId nFormat ) { bool bRet = false; OUString sFile; if( rData.GetString( nFormat, sFile ) && !sFile.isEmpty() ) { OUString sDesc; SwTransferable::CheckForURLOrLNKFile( rData, sFile, &sDesc ); // first, make the URL absolute INetURLObject aURL; aURL.SetSmartProtocol( INetProtocol::File ); aURL.SetSmartURL( sFile ); sFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); switch( rSh.GetObjCntTypeOfSelection() ) { case OBJCNT_FLY: case OBJCNT_GRF: case OBJCNT_OLE: { SfxItemSet aSet( rSh.GetAttrPool(), svl::Items{} ); rSh.GetFlyFrameAttr( aSet ); SwFormatURL aURL2( static_cast(aSet.Get( RES_URL )) ); aURL2.SetURL( sFile, false ); if( aURL2.GetName().isEmpty() ) aURL2.SetName( sFile ); aSet.Put( aURL2 ); rSh.SetFlyFrameAttr( aSet ); } break; default: { rSh.InsertURL( SwFormatINetFormat( sFile, OUString() ), sDesc.isEmpty() ? sFile : sDesc); } } bRet = true; } return bRet; } bool SwTransferable::PasteFileName( TransferableDataHelper& rData, SwWrtShell& rSh, SotClipboardFormatId nFormat, SwPasteSdr nAction, const Point* pPt, SotExchangeActionFlags nActionFlags, bool * graphicInserted) { bool bRet = SwTransferable::PasteGrf( rData, rSh, nFormat, nAction, pPt, nActionFlags, 0, false); if (graphicInserted != nullptr) { *graphicInserted = bRet; } if( !bRet ) { OUString sFile, sDesc; if( rData.GetString( nFormat, sFile ) && !sFile.isEmpty() ) { #if HAVE_FEATURE_AVMEDIA INetURLObject aMediaURL; aMediaURL.SetSmartURL( sFile ); const OUString aMediaURLStr( aMediaURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); if( ::avmedia::MediaWindow::isMediaURL( aMediaURLStr, ""/*TODO?*/ ) ) { const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, aMediaURLStr ); rSh.GetView().GetViewFrame()->GetDispatcher()->ExecuteList( SID_INSERT_AVMEDIA, SfxCallMode::SYNCHRON, { &aMediaURLItem }); } #else if (false) { } #endif else { bool bIsURLFile = SwTransferable::CheckForURLOrLNKFile( rData, sFile, &sDesc ); //Own FileFormat? --> insert, not for StarWriter/Web OUString sFileURL = URIHelper::SmartRel2Abs(INetURLObject(), sFile, Link(), false ); std::shared_ptr pFlt = SwPasteSdr::SetAttr == nAction ? nullptr : SwIoSystem::GetFileFilter(sFileURL); if( pFlt && dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) == nullptr ) { // and then pull up the insert-region-dialog by PostUser event SwSectionData * pSect = new SwSectionData( FILE_LINK_SECTION, rSh.GetDoc()->GetUniqueSectionName() ); pSect->SetLinkFileName( sFileURL ); pSect->SetProtectFlag( true ); Application::PostUserEvent( LINK( &rSh, SwWrtShell, InsertRegionDialog ), pSect ); bRet = true; } else if( SwPasteSdr::SetAttr == nAction || ( bIsURLFile && SwPasteSdr::Insert == nAction )) { //we can insert foreign files as links after all // first, make the URL absolute INetURLObject aURL; aURL.SetSmartProtocol( INetProtocol::File ); aURL.SetSmartURL( sFile ); sFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); switch( rSh.GetObjCntTypeOfSelection() ) { case OBJCNT_FLY: case OBJCNT_GRF: case OBJCNT_OLE: { SfxItemSet aSet( rSh.GetAttrPool(), svl::Items{} ); rSh.GetFlyFrameAttr( aSet ); SwFormatURL aURL2( static_cast(aSet.Get( RES_URL )) ); aURL2.SetURL( sFile, false ); if( aURL2.GetName().isEmpty() ) aURL2.SetName( sFile ); aSet.Put( aURL2 ); rSh.SetFlyFrameAttr( aSet ); } break; default: { rSh.InsertURL( SwFormatINetFormat( sFile, OUString() ), sDesc.isEmpty() ? sFile : sDesc ); } } bRet = true; } } } } return bRet; } bool SwTransferable::PasteDBData( TransferableDataHelper& rData, SwWrtShell& rSh, SotClipboardFormatId nFormat, bool bLink, const Point* pDragPt, bool bMsg ) { bool bRet = false; OUString sText; if( rData.GetString( nFormat, sText ) && !sText.isEmpty() ) { sal_uInt16 nWh = SotClipboardFormatId::SBA_CTRLDATAEXCHANGE == nFormat ? 0 : SotClipboardFormatId::SBA_DATAEXCHANGE == nFormat ? (bLink ? FN_QRY_MERGE_FIELD : FN_QRY_INSERT) : (bLink ? 0 : FN_QRY_INSERT_FIELD ); const DataFlavorExVector& rVector = rData.GetDataFlavorExVector(); bool bHaveColumnDescriptor = OColumnTransferable::canExtractColumnDescriptor(rVector, ColumnTransferFormatFlags::COLUMN_DESCRIPTOR | ColumnTransferFormatFlags::CONTROL_EXCHANGE); if ( SotClipboardFormatId::XFORMS == nFormat ) { rSh.MakeDrawView(); FmFormView* pFmView = dynamic_cast( rSh.GetDrawView() ); if (pFmView && pDragPt) { const OXFormsDescriptor &rDesc = OXFormsTransferable::extractDescriptor(rData); SdrObject* pObj = pFmView->CreateXFormsControl(rDesc); if(nullptr != pObj) { rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt ); } } } else if( nWh ) { std::unique_ptr pConnectionItem; std::unique_ptr pCursorItem; std::unique_ptr pColumnItem; std::unique_ptr pSourceItem; std::unique_ptr pCommandItem; std::unique_ptr pCommandTypeItem; std::unique_ptr pColumnNameItem; std::unique_ptr pSelectionItem; bool bDataAvailable = true; ODataAccessDescriptor aDesc; if(bHaveColumnDescriptor) aDesc = OColumnTransferable::extractColumnDescriptor(rData); else if(ODataAccessObjectTransferable::canExtractObjectDescriptor(rVector) ) aDesc = ODataAccessObjectTransferable::extractObjectDescriptor(rData); else bDataAvailable = false; if ( bDataAvailable ) { pConnectionItem.reset(new SfxUsrAnyItem(FN_DB_CONNECTION_ANY, aDesc[DataAccessDescriptorProperty::Connection])); pColumnItem.reset(new SfxUsrAnyItem(FN_DB_COLUMN_ANY, aDesc[DataAccessDescriptorProperty::ColumnObject])); pSourceItem.reset(new SfxUsrAnyItem(FN_DB_DATA_SOURCE_ANY, makeAny(aDesc.getDataSource()))); pCommandItem.reset(new SfxUsrAnyItem(FN_DB_DATA_COMMAND_ANY, aDesc[DataAccessDescriptorProperty::Command])); pCommandTypeItem.reset(new SfxUsrAnyItem(FN_DB_DATA_COMMAND_TYPE_ANY, aDesc[DataAccessDescriptorProperty::CommandType])); pColumnNameItem.reset(new SfxUsrAnyItem(FN_DB_DATA_COLUMN_NAME_ANY, aDesc[DataAccessDescriptorProperty::ColumnName])); pSelectionItem.reset(new SfxUsrAnyItem(FN_DB_DATA_SELECTION_ANY, aDesc[DataAccessDescriptorProperty::Selection])); pCursorItem.reset(new SfxUsrAnyItem(FN_DB_DATA_CURSOR_ANY, aDesc[DataAccessDescriptorProperty::Cursor])); } SwView& rView = rSh.GetView(); //force ::SelectShell rView.StopShellTimer(); SfxStringItem aDataDesc( nWh, sText ); rView.GetViewFrame()->GetDispatcher()->ExecuteList( nWh, SfxCallMode::ASYNCHRON, { &aDataDesc, pConnectionItem.get(), pColumnItem.get(), pSourceItem.get(), pCommandItem.get(), pCommandTypeItem.get(), pColumnNameItem.get(), pSelectionItem.get(), pCursorItem.get() }); } else { rSh.MakeDrawView(); FmFormView* pFmView = dynamic_cast( rSh.GetDrawView() ); if (pFmView && bHaveColumnDescriptor && pDragPt) { SdrObject* pObj = pFmView->CreateFieldControl( OColumnTransferable::extractColumnDescriptor(rData) ); if ( nullptr != pObj) rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt ); } } bRet = true; } else if( bMsg ) { ScopedVclPtrInstance(nullptr, SwResId(STR_CLPBRD_FORMAT_ERROR), VclMessageType::Info)->Execute(); } return bRet; } bool SwTransferable::PasteFileList( TransferableDataHelper& rData, SwWrtShell& rSh, bool bLink, const Point* pPt, bool bMsg ) { bool bRet = false; FileList aFileList; if( rData.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList ) && aFileList.Count() ) { SwPasteSdr nAct = bLink ? SwPasteSdr::SetAttr : SwPasteSdr::Insert; OUString sFlyNm; // iterate over the filelist for( sal_uLong n = 0, nEnd = aFileList.Count(); n < nEnd; ++n ) { TransferDataContainer* pHlp = new TransferDataContainer; pHlp->CopyString( SotClipboardFormatId::SIMPLE_FILE, aFileList.GetFile( n )); TransferableDataHelper aData( pHlp ); if( SwTransferable::PasteFileName( aData, rSh, SotClipboardFormatId::SIMPLE_FILE, nAct, pPt, SotExchangeActionFlags::NONE, nullptr )) { if( bLink ) { sFlyNm = rSh.GetFlyName(); SwTransferable::SetSelInShell( rSh, false, pPt ); } bRet = true; } } if( !sFlyNm.isEmpty() ) rSh.GotoFly( sFlyNm ); } else if( bMsg ) { ScopedVclPtrInstance(nullptr, SwResId(STR_CLPBRD_FORMAT_ERROR), VclMessageType::Info)->Execute(); } return bRet; } bool SwTransferable::CheckForURLOrLNKFile( TransferableDataHelper& rData, OUString& rFileName, OUString* pTitle ) { bool bIsURLFile = false; INetBookmark aBkmk; if( rData.GetINetBookmark( SotClipboardFormatId::SOLK, aBkmk ) ) { rFileName = aBkmk.GetURL(); if( pTitle ) *pTitle = aBkmk.GetDescription(); bIsURLFile = true; } else { sal_Int32 nLen = rFileName.getLength(); if( 4 < nLen && '.' == rFileName[ nLen - 4 ]) { OUString sExt( rFileName.copy( nLen - 3 )); if( sExt.equalsIgnoreAsciiCase( "url" )) { OSL_ENSURE( false, "how do we read today .URL - Files?" ); } } } return bIsURLFile; } bool SwTransferable::IsPasteSpecial( const SwWrtShell& rWrtShell, const TransferableDataHelper& rData ) { // we can paste-special if there's an entry in the paste-special-format list SvxClipboardFormatItem aClipboardFormatItem(0); FillClipFormatItem( rWrtShell, rData, aClipboardFormatItem); return aClipboardFormatItem.Count() > 0; } bool SwTransferable::PasteFormat( SwWrtShell& rSh, TransferableDataHelper& rData, SotClipboardFormatId nFormat ) { SwWait aWait( *rSh.GetView().GetDocShell(), false ); bool bRet = false; SotClipboardFormatId nPrivateFormat = SotClipboardFormatId::PRIVATE; SwTransferable *pClipboard = GetSwTransferable( rData ); if( pClipboard && ((TransferBufferType::Document|TransferBufferType::Graphic|TransferBufferType::Ole) & pClipboard->m_eBufferType )) nPrivateFormat = SotClipboardFormatId::EMBED_SOURCE; if( pClipboard && nPrivateFormat == nFormat ) bRet = pClipboard->PrivatePaste( rSh ); else if( rData.HasFormat( nFormat ) ) { uno::Reference xTransferable( rData.GetXTransferable() ); sal_uInt8 nEventAction; SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh ); sal_uInt16 nSourceOptions = (( SotExchangeDest::DOC_TEXTFRAME == nDestination || SotExchangeDest::SWDOC_FREE_AREA == nDestination || SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination || SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination ) ? EXCHG_IN_ACTION_COPY : EXCHG_IN_ACTION_MOVE); SotExchangeActionFlags nActionFlags; sal_uInt8 nAction = SotExchange::GetExchangeAction( rData.GetDataFlavorExVector(), nDestination, nSourceOptions, /* ?? */ EXCHG_IN_ACTION_DEFAULT, /* ?? */ nFormat, nEventAction, nFormat, lcl_getTransferPointer ( xTransferable ), &nActionFlags ); if( EXCHG_INOUT_ACTION_NONE != nAction ) bRet = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat, nDestination, true, false ); } return bRet; } bool SwTransferable::TestAllowedFormat( const TransferableDataHelper& rData, SotClipboardFormatId nFormat, SotExchangeDest nDestination ) { sal_uInt8 nAction = EXCHG_INOUT_ACTION_NONE, nEventAction; if( rData.HasFormat( nFormat )) { uno::Reference xTransferable( rData.GetXTransferable() ); nAction = SotExchange::GetExchangeAction( rData.GetDataFlavorExVector(), nDestination, EXCHG_IN_ACTION_COPY, EXCHG_IN_ACTION_COPY, nFormat, nEventAction, nFormat, lcl_getTransferPointer ( xTransferable ) ); } return EXCHG_INOUT_ACTION_NONE != nAction; } /** * the list of formats which will be offered to the user in the 'Paste * Special...' dialog and the paste button menu */ static SotClipboardFormatId aPasteSpecialIds[] = { SotClipboardFormatId::HTML, SotClipboardFormatId::HTML_SIMPLE, SotClipboardFormatId::HTML_NO_COMMENT, SotClipboardFormatId::RTF, SotClipboardFormatId::RICHTEXT, SotClipboardFormatId::STRING, SotClipboardFormatId::SONLK, SotClipboardFormatId::NETSCAPE_BOOKMARK, SotClipboardFormatId::DRAWING, SotClipboardFormatId::SVXB, SotClipboardFormatId::GDIMETAFILE, SotClipboardFormatId::BITMAP, SotClipboardFormatId::SVIM, SotClipboardFormatId::FILEGRPDESCRIPTOR, SotClipboardFormatId::NONE }; bool SwTransferable::PasteUnformatted( SwWrtShell& rSh, TransferableDataHelper& rData ) { // Plain text == unformatted return SwTransferable::PasteFormat( rSh, rData, SotClipboardFormatId::STRING ); } bool SwTransferable::PasteSpecial( SwWrtShell& rSh, TransferableDataHelper& rData, SotClipboardFormatId& rFormatUsed ) { bool bRet = false; SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); ScopedVclPtr pDlg(pFact->CreatePasteDialog( &rSh.GetView().GetEditWin() )); DataFlavorExVector aFormats( rData.GetDataFlavorExVector() ); TransferableObjectDescriptor aDesc; SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh ); SwTransferable *pClipboard = GetSwTransferable( rData ); if( pClipboard ) { aDesc = pClipboard->m_aObjDesc; const char* pResId; if( pClipboard->m_eBufferType & TransferBufferType::Document ) pResId = STR_PRIVATETEXT; else if( pClipboard->m_eBufferType & TransferBufferType::Graphic ) pResId = STR_PRIVATEGRAPHIC; else if( pClipboard->m_eBufferType == TransferBufferType::Ole ) pResId = STR_PRIVATEOLE; else pResId = nullptr; if (pResId) { if (strcmp(STR_PRIVATEOLE, pResId) == 0 || strcmp(STR_PRIVATEGRAPHIC, pResId) == 0) { // add SotClipboardFormatId::EMBED_SOURCE to the formats. This // format display then the private format name. DataFlavorEx aFlavorEx; aFlavorEx.mnSotId = SotClipboardFormatId::EMBED_SOURCE; aFormats.insert( aFormats.begin(), aFlavorEx ); } pDlg->SetObjName( pClipboard->m_aObjDesc.maClassName, SwResId(pResId) ); pDlg->Insert( SotClipboardFormatId::EMBED_SOURCE, aEmptyOUStr ); } } else { if( rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) ) { (void)rData.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc ); } if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::EMBED_SOURCE, nDest )) pDlg->Insert( SotClipboardFormatId::EMBED_SOURCE, aEmptyOUStr ); if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK_SOURCE, nDest )) pDlg->Insert( SotClipboardFormatId::LINK_SOURCE, aEmptyOUStr ); } if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK, nDest )) pDlg->Insert( SotClipboardFormatId::LINK, SwResId(STR_DDEFORMAT) ); for( SotClipboardFormatId* pIds = aPasteSpecialIds; *pIds != SotClipboardFormatId::NONE; ++pIds ) if( SwTransferable::TestAllowedFormat( rData, *pIds, nDest )) pDlg->Insert( *pIds, aEmptyOUStr ); SotClipboardFormatId nFormat = pDlg->GetFormat( rData.GetTransferable() ); if( nFormat != SotClipboardFormatId::NONE ) bRet = SwTransferable::PasteFormat( rSh, rData, nFormat ); if ( bRet ) rFormatUsed = nFormat; return bRet; } void SwTransferable::FillClipFormatItem( const SwWrtShell& rSh, const TransferableDataHelper& rData, SvxClipboardFormatItem & rToFill ) { SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh ); SwTransferable *pClipboard = GetSwTransferable( rData ); if( pClipboard ) { const char* pResId; if( pClipboard->m_eBufferType & TransferBufferType::Document ) pResId = STR_PRIVATETEXT; else if( pClipboard->m_eBufferType & TransferBufferType::Graphic ) pResId = STR_PRIVATEGRAPHIC; else if( pClipboard->m_eBufferType == TransferBufferType::Ole ) pResId = STR_PRIVATEOLE; else pResId = nullptr; if (pResId) rToFill.AddClipbrdFormat(SotClipboardFormatId::EMBED_SOURCE, SwResId(pResId)); } else { TransferableObjectDescriptor aDesc; if (rData.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR)) { (void)const_cast(rData).GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc); } if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::EMBED_SOURCE, nDest )) rToFill.AddClipbrdFormat( SotClipboardFormatId::EMBED_SOURCE, aDesc.maTypeName ); if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK_SOURCE, nDest )) rToFill.AddClipbrdFormat( SotClipboardFormatId::LINK_SOURCE ); SotClipboardFormatId nFormat; if ( rData.HasFormat(nFormat = SotClipboardFormatId::EMBED_SOURCE_OLE) || rData.HasFormat(nFormat = SotClipboardFormatId::EMBEDDED_OBJ_OLE) ) { OUString sName,sSource; if ( SvPasteObjectHelper::GetEmbeddedName(rData,sName,sSource,nFormat) ) rToFill.AddClipbrdFormat( nFormat, sName ); } } if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK, nDest )) rToFill.AddClipbrdFormat( SotClipboardFormatId::LINK, SwResId(STR_DDEFORMAT) ); for( SotClipboardFormatId* pIds = aPasteSpecialIds; *pIds != SotClipboardFormatId::NONE; ++pIds ) if( SwTransferable::TestAllowedFormat( rData, *pIds, nDest )) rToFill.AddClipbrdFormat( *pIds, aEmptyOUStr ); } void SwTransferable::SetDataForDragAndDrop( const Point& rSttPos ) { if(!m_pWrtShell) return; OUString sGrfNm; const SelectionType nSelection = m_pWrtShell->GetSelectionType(); if( SelectionType::Graphic == nSelection) { AddFormat( SotClipboardFormatId::SVXB ); const Graphic* pGrf = m_pWrtShell->GetGraphic(); if ( pGrf && pGrf->IsSupportedGraphic() ) { AddFormat( SotClipboardFormatId::GDIMETAFILE ); AddFormat( SotClipboardFormatId::PNG ); AddFormat( SotClipboardFormatId::BITMAP ); } m_eBufferType = TransferBufferType::Graphic; m_pWrtShell->GetGrfNms( &sGrfNm, nullptr ); } else if( SelectionType::Ole == nSelection ) { AddFormat( SotClipboardFormatId::EMBED_SOURCE ); PrepareOLE( m_aObjDesc ); AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ); AddFormat( SotClipboardFormatId::GDIMETAFILE ); m_eBufferType = TransferBufferType::Ole; } //Is there anything to provide anyway? else if ( m_pWrtShell->IsSelection() || m_pWrtShell->IsFrameSelected() || m_pWrtShell->IsObjSelected() ) { if( m_pWrtShell->IsObjSelected() ) m_eBufferType = TransferBufferType::Drawing; else { m_eBufferType = TransferBufferType::Document; if( SwWrtShell::NO_WORD != m_pWrtShell->IntelligentCut( nSelection, false )) m_eBufferType = TransferBufferType::DocumentWord | m_eBufferType; } if( nSelection & SelectionType::TableCell ) m_eBufferType = TransferBufferType::Table | m_eBufferType; AddFormat( SotClipboardFormatId::EMBED_SOURCE ); //put RTF ahead of the OLE's Metafile for less loss if( !m_pWrtShell->IsObjSelected() ) { AddFormat( SotClipboardFormatId::RTF ); AddFormat( SotClipboardFormatId::RICHTEXT ); AddFormat( SotClipboardFormatId::HTML ); } if( m_pWrtShell->IsSelection() ) AddFormat( SotClipboardFormatId::STRING ); if( nSelection & ( SelectionType::DrawObject | SelectionType::DbForm )) { AddFormat( SotClipboardFormatId::DRAWING ); if ( nSelection & SelectionType::DrawObject ) { AddFormat( SotClipboardFormatId::GDIMETAFILE ); AddFormat( SotClipboardFormatId::PNG ); AddFormat( SotClipboardFormatId::BITMAP ); } m_eBufferType = TransferBufferType::Graphic | m_eBufferType; m_pClpGraphic.reset(new Graphic); if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_pClpGraphic )) m_pOrigGraphic = m_pClpGraphic.get(); m_pClpBitmap.reset(new Graphic); if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_pClpBitmap )) m_pOrigGraphic = m_pClpBitmap.get(); // is it an URL-Button ? OUString sURL; OUString sDesc; if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) ) { AddFormat( SotClipboardFormatId::STRING ); AddFormat( SotClipboardFormatId::SOLK ); AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ); AddFormat( SotClipboardFormatId::FILECONTENT ); AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ); AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ); m_eBufferType = TransferBufferType::InetField | m_eBufferType; } } //ObjectDescriptor was already filled from the old DocShell. //Now adjust it. Thus in GetData the first query can still //be answered with delayed rendering. m_aObjDesc.maDragStartPos = rSttPos; m_aObjDesc.maSize = OutputDevice::LogicToLogic( Size( OLESIZE ), MapMode(MapUnit::MapTwip), MapMode(MapUnit::Map100thMM)); PrepareOLE( m_aObjDesc ); AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ); } else if( nSelection & SelectionType::Text && !m_pWrtShell->HasMark() ) { // is only one field - selected? SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr ); Point aPos( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY()); if( m_pWrtShell->GetContentAtPos( aPos, aContentAtPos ) ) { AddFormat( SotClipboardFormatId::STRING ); AddFormat( SotClipboardFormatId::SOLK ); AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ); AddFormat( SotClipboardFormatId::FILECONTENT ); AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ); AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ); m_eBufferType = TransferBufferType::InetField; } } if( m_pWrtShell->IsFrameSelected() ) { SfxItemSet aSet( m_pWrtShell->GetAttrPool(), svl::Items{} ); m_pWrtShell->GetFlyFrameAttr( aSet ); const SwFormatURL& rURL = static_cast(aSet.Get( RES_URL )); if( rURL.GetMap() ) { m_pImageMap.reset( new ImageMap( *rURL.GetMap() ) ); AddFormat( SotClipboardFormatId::SVIM ); } else if( !rURL.GetURL().isEmpty() ) { m_pTargetURL.reset(new INetImage( sGrfNm, rURL.GetURL(), rURL.GetTargetFrameName() )); AddFormat( SotClipboardFormatId::INET_IMAGE ); } } } void SwTransferable::StartDrag( vcl::Window* pWin, const Point& rPos ) { if(!m_pWrtShell) return; m_bOldIdle = m_pWrtShell->GetViewOptions()->IsIdle(); m_bCleanUp = true; m_pWrtShell->GetViewOptions()->SetIdle( false ); if( m_pWrtShell->IsSelFrameMode() ) m_pWrtShell->ShowCursor(); SW_MOD()->m_pDragDrop = this; SetDataForDragAndDrop( rPos ); sal_Int8 nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK; SwDocShell* pDShell = m_pWrtShell->GetView().GetDocShell(); if( ( pDShell && pDShell->IsReadOnly() ) || m_pWrtShell->HasReadonlySel() ) nDragOptions &= ~DND_ACTION_MOVE; TransferableHelper::StartDrag( pWin, nDragOptions ); } void SwTransferable::DragFinished( sal_Int8 nAction ) { //And the last finishing work so that all statuses are right if( DND_ACTION_MOVE == nAction ) { if( m_bCleanUp ) { //It was dropped outside of Writer. We still have to //delete. m_pWrtShell->StartAllAction(); m_pWrtShell->StartUndo( SwUndoId::UI_DRAG_AND_MOVE ); if ( m_pWrtShell->IsTableMode() ) m_pWrtShell->DeleteTableSel(); else { if ( !(m_pWrtShell->IsSelFrameMode() || m_pWrtShell->IsObjSelected()) ) //SmartCut, take one of the blanks along m_pWrtShell->IntelligentCut( m_pWrtShell->GetSelectionType() ); m_pWrtShell->DelRight(); } m_pWrtShell->EndUndo( SwUndoId::UI_DRAG_AND_MOVE ); m_pWrtShell->EndAllAction(); } else { const SelectionType nSelection = m_pWrtShell->GetSelectionType(); if( ( SelectionType::Frame | SelectionType::Graphic | SelectionType::Ole | SelectionType::DrawObject ) & nSelection ) { m_pWrtShell->EnterSelFrameMode(); } } } m_pWrtShell->GetView().GetEditWin().DragFinished(); if( m_pWrtShell->IsSelFrameMode() ) m_pWrtShell->HideCursor(); else m_pWrtShell->ShowCursor(); m_pWrtShell->GetViewOptions()->SetIdle( m_bOldIdle ); } namespace { bool lcl_checkClassification(SwDoc* pSourceDoc, SwDoc* pDestinationDoc) { if (!pSourceDoc || !pDestinationDoc) return true; SwDocShell* pSourceShell = pSourceDoc->GetDocShell(); SwDocShell* pDestinationShell = pDestinationDoc->GetDocShell(); if (!pSourceShell || !pDestinationShell) return true; SfxClassificationCheckPasteResult eResult = SfxClassificationHelper::CheckPaste(pSourceShell->getDocProperties(), pDestinationShell->getDocProperties()); return SfxClassificationHelper::ShowPasteInfo(eResult); } } bool SwTransferable::PrivatePaste( SwWrtShell& rShell ) { // first, ask for the SelectionType, then action-bracketing !!!! // (otherwise it's not pasted into a TableSelection!!!) OSL_ENSURE( !rShell.ActionPend(), "Paste must never have an ActionPend" ); if ( !m_pClpDocFac ) return false; // the return value of the SwFEShell::Paste also is bool! const SelectionType nSelection = rShell.GetSelectionType(); SwTrnsfrActionAndUndo aAction( &rShell ); bool bKillPaMs = false; //Delete selected content, not at table-selection and table in Clipboard, and don't delete hovering graphics. if( rShell.HasSelection() && !( nSelection & SelectionType::TableCell) && !( nSelection & SelectionType::DrawObject)) { bKillPaMs = true; rShell.SetRetainSelection( true ); rShell.DelRight(); // when a Fly was selected, a valid cursor position has to be found now // (parked Cursor!) if( ( SelectionType::Frame | SelectionType::Graphic | SelectionType::Ole | SelectionType::DrawObject | SelectionType::DbForm ) & nSelection ) { // position the cursor again Point aPt( rShell.GetCharRect().Pos() ); rShell.SwCursorShell::SetCursor( aPt, true ); } rShell.SetRetainSelection( false ); } if ( nSelection & SelectionType::DrawObject) //unselect hovering graphics { rShell.ResetSelect(nullptr,false); } bool bInWrd = false, bEndWrd = false, bSttWrd = false, bSmart(TransferBufferType::DocumentWord & m_eBufferType); if( bSmart ) { // Why not for other Scripts? If TransferBufferType::DocumentWord is set, we have a word // in the buffer, word in this context means 'something with spaces at beginning // and end'. In this case we definitely want these spaces to be inserted here. bInWrd = rShell.IsInWord(); bEndWrd = rShell.IsEndWrd(); bSmart = bInWrd || bEndWrd; if( bSmart ) { bSttWrd = rShell.IsStartWord(); if( bSmart && !bSttWrd && (bInWrd || bEndWrd) ) rShell.SwEditShell::Insert(' '); } } bool bRet = true; // m_pWrtShell is nullptr when the source document is closed already. if (!m_pWrtShell || lcl_checkClassification(m_pWrtShell->GetDoc(), rShell.GetDoc())) bRet = rShell.Paste(m_pClpDocFac->GetDoc()); if( bKillPaMs ) rShell.KillPams(); // If Smart Paste then insert blank if( bRet && bSmart && ((bInWrd && !bEndWrd )|| bSttWrd) ) rShell.SwEditShell::Insert(' '); return bRet; } bool SwTransferable::PrivateDrop( SwWrtShell& rSh, const Point& rDragPt, bool bMove, bool bIsXSelection ) { int cWord = 0; bool bInWrd = false; bool bEndWrd = false; bool bSttWrd = false; bool bSttPara = false; bool bTableSel = false; bool bFrameSel = false; SwWrtShell& rSrcSh = *GetShell(); rSh.UnSetVisibleCursor(); if( TransferBufferType::InetField == m_eBufferType ) { if( rSh.GetFormatFromObj( rDragPt ) ) { INetBookmark aTmp; if( (TransferBufferType::InetField & m_eBufferType) && m_pBookmark ) aTmp = *m_pBookmark; // select target graphic if( rSh.SelectObj( rDragPt ) ) { rSh.HideCursor(); rSh.EnterSelFrameMode( &rDragPt ); g_bFrameDrag = true; } const SelectionType nSelection = rSh.GetSelectionType(); // not yet consider Draw objects if( SelectionType::Graphic & nSelection ) { SfxItemSet aSet( rSh.GetAttrPool(), svl::Items{} ); rSh.GetFlyFrameAttr( aSet ); SwFormatURL aURL( static_cast(aSet.Get( RES_URL )) ); aURL.SetURL( aTmp.GetURL(), false ); aSet.Put( aURL ); rSh.SetFlyFrameAttr( aSet ); return true; } if( SelectionType::DrawObject & nSelection ) { rSh.LeaveSelFrameMode(); rSh.UnSelectFrame(); rSh.ShowCursor(); g_bFrameDrag = false; } } } if( &rSh != &rSrcSh && (SelectionType::Graphic & rSh.GetSelectionType()) && TransferBufferType::Graphic == m_eBufferType ) { // ReRead the graphic OUString sGrfNm; OUString sFltNm; rSrcSh.GetGrfNms( &sGrfNm, &sFltNm ); rSh.ReRead( sGrfNm, sFltNm, rSrcSh.GetGraphic() ); return true; } //not in selections or selected frames if( rSh.TestCurrPam( rDragPt ) || ( rSh.IsSelFrameMode() && rSh.IsInsideSelectedObj( rDragPt )) ) return false; if( rSrcSh.IsTableMode() ) bTableSel = true; else if( rSrcSh.IsSelFrameMode() || rSrcSh.IsObjSelected() ) { // don't move position-protected objects! if( bMove && rSrcSh.IsSelObjProtected( FlyProtectFlags::Pos ) != FlyProtectFlags::NONE ) return false; bFrameSel = true; } const SelectionType nSel = rSrcSh.GetSelectionType(); SwUndoId eUndoId = bMove ? SwUndoId::UI_DRAG_AND_MOVE : SwUndoId::UI_DRAG_AND_COPY; SwRewriter aRewriter; aRewriter.AddRule(UndoArg1, rSrcSh.GetSelDescr()); if(rSrcSh.GetDoc() != rSh.GetDoc()) rSrcSh.StartUndo( eUndoId, &aRewriter ); rSh.StartUndo( eUndoId, &aRewriter ); rSh.StartAction(); rSrcSh.StartAction(); if( &rSrcSh != &rSh ) { rSh.EnterStdMode(); rSh.SwCursorShell::SetCursor( rDragPt, true ); cWord = rSrcSh.IntelligentCut( nSel, false ); } else if( !bTableSel && !bFrameSel ) { if( !rSh.IsAddMode() ) { // #i87233# if ( rSh.IsBlockMode() ) { // preserve order of cursors for block mode rSh.GoPrevCursor(); } rSh.SwCursorShell::CreateCursor(); } rSh.SwCursorShell::SetCursor( rDragPt, true, false ); rSh.GoPrevCursor(); cWord = rSh.IntelligentCut( rSh.GetSelectionType(), false ); rSh.GoNextCursor(); } bInWrd = rSh.IsInWord(); bEndWrd = rSh.IsEndWrd(); bSttWrd = !bEndWrd && rSh.IsStartWord(); bSttPara= rSh.IsSttPara(); Point aSttPt( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY() ); // at first, select INetFelder! if( TransferBufferType::InetField == m_eBufferType ) { if( &rSrcSh == &rSh ) { rSh.GoPrevCursor(); rSh.SwCursorShell::SetCursor( aSttPt, true ); rSh.SelectTextAttr( RES_TXTATR_INETFMT ); if( rSh.TestCurrPam( rDragPt ) ) { // don't copy/move inside of yourself rSh.DestroyCursor(); rSh.EndUndo(); rSh.EndAction(); rSh.EndAction(); return false; } rSh.GoNextCursor(); } else { rSrcSh.SwCursorShell::SetCursor( aSttPt, true ); rSrcSh.SelectTextAttr( RES_TXTATR_INETFMT ); } // is there an URL attribute at the insert point? Then replace that, // so simply put up a selection? rSh.DelINetAttrWithText(); g_bDDINetAttr = true; } if ( rSrcSh.IsSelFrameMode() ) { //Hack: fool the special treatment aSttPt -= aSttPt - rSrcSh.GetObjRect().Pos(); } bool bRet = rSrcSh.SwFEShell::Copy( &rSh, aSttPt, rDragPt, bMove, !bIsXSelection ); if( !bIsXSelection ) { rSrcSh.Push(); if ( bRet && bMove && !bFrameSel ) { if ( bTableSel ) { /* delete table contents not cells */ rSrcSh.Delete(); } else { //SmartCut, take one of the blanks along. rSh.SwCursorShell::DestroyCursor(); if ( cWord == SwWrtShell::WORD_SPACE_BEFORE ) rSh.ExtendSelection( false ); else if ( cWord == SwWrtShell::WORD_SPACE_AFTER ) rSh.ExtendSelection(); rSrcSh.DelRight(); } } rSrcSh.KillPams(); rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent); /* after dragging a table selection inside one shell set cursor to the drop position. */ if( &rSh == &rSrcSh && ( bTableSel || rSh.IsBlockMode() ) ) { rSrcSh.CalcLayout(); rSrcSh.SwCursorShell::SetCursor(rDragPt); rSrcSh.GetSwCursor()->SetMark(); } } if( bRet && !bTableSel && !bFrameSel ) { if( (bInWrd || bEndWrd) && (cWord == SwWrtShell::WORD_SPACE_AFTER || cWord == SwWrtShell::WORD_SPACE_BEFORE) ) { if ( bSttWrd || (bInWrd && !bEndWrd)) rSh.SwEditShell::Insert(' ', bIsXSelection); if ( !bSttWrd || (bInWrd && !bSttPara) ) { rSh.SwapPam(); if ( !bSttWrd ) rSh.SwEditShell::Insert(' ', bIsXSelection); rSh.SwapPam(); } } if( bIsXSelection ) { if( &rSrcSh == &rSh && !rSh.IsAddMode() ) { rSh.SwCursorShell::DestroyCursor(); rSh.GoPrevCursor(); } else { rSh.SwapPam(); rSh.SwCursorShell::ClearMark(); } } else { if( rSh.IsAddMode() ) rSh.SwCursorShell::CreateCursor(); else { // turn on selection mode rSh.SttSelect(); rSh.EndSelect(); } } } if( bRet && bMove && bFrameSel ) rSrcSh.LeaveSelFrameMode(); if( rSrcSh.GetDoc() != rSh.GetDoc() ) rSrcSh.EndUndo(); rSh.EndUndo(); // put the shell in the right state if( &rSrcSh != &rSh && ( rSh.IsFrameSelected() || rSh.IsObjSelected() )) rSh.EnterSelFrameMode(); rSrcSh.EndAction(); rSh.EndAction(); return true; } // Interfaces for Selection void SwTransferable::CreateSelection( SwWrtShell& rSh, const SwFrameShell * _pCreatorView ) { SwModule *pMod = SW_MOD(); rtl::Reference pNew = new SwTransferable( rSh ); pNew->m_pCreatorView = _pCreatorView; pMod->m_pXSelection = pNew.get(); pNew->CopyToSelection( rSh.GetWin() ); } void SwTransferable::ClearSelection( SwWrtShell& rSh, const SwFrameShell * _pCreatorView) { SwModule *pMod = SW_MOD(); if( pMod->m_pXSelection && ((!pMod->m_pXSelection->m_pWrtShell) || (pMod->m_pXSelection->m_pWrtShell == &rSh)) && (!_pCreatorView || (pMod->m_pXSelection->m_pCreatorView == _pCreatorView)) ) { TransferableHelper::ClearSelection( rSh.GetWin() ); } } namespace { class theSwTransferableUnoTunnelId : public rtl::Static< UnoTunnelIdInit, SwTransferable > {}; } const Sequence< sal_Int8 >& SwTransferable::getUnoTunnelId() { return theSwTransferableUnoTunnelId::get().getSeq(); } sal_Int64 SwTransferable::getSomething( const Sequence< sal_Int8 >& rId ) { sal_Int64 nRet; if( ( rId.getLength() == 16 ) && ( 0 == memcmp( getUnoTunnelId().getConstArray(), rId.getConstArray(), 16 ) ) ) { nRet = sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >( this ) ); } else nRet = TransferableHelper::getSomething(rId); return nRet; } SwTransferable* SwTransferable::GetSwTransferable( const TransferableDataHelper& rData ) { SwTransferable* pSwTransferable = nullptr; uno::Reference xTunnel( rData.GetTransferable(), UNO_QUERY ); if ( xTunnel.is() ) { sal_Int64 nHandle = xTunnel->getSomething( getUnoTunnelId() ); if ( nHandle ) pSwTransferable = reinterpret_cast( (sal_IntPtr) nHandle ); } return pSwTransferable; } SwTrnsfrDdeLink::SwTrnsfrDdeLink( SwTransferable& rTrans, SwWrtShell& rSh ) : rTrnsfr(rTrans) , pDocShell(nullptr) , nOldTimeOut(0) , bDelBookmrk(false) , bInDisconnect(false) { // we only end up here with table- or text selection if( SelectionType::TableCell & rSh.GetSelectionType() ) { SwFrameFormat* pFormat = rSh.GetTableFormat(); if( pFormat ) sName = pFormat->GetName(); } else { // creating a temp. bookmark without undo bool bUndo = rSh.DoesUndo(); rSh.DoUndo( false ); bool bIsModified = rSh.IsModified(); ::sw::mark::IMark* pMark = rSh.SetBookmark( vcl::KeyCode(), OUString(), IDocumentMarkAccess::MarkType::DDE_BOOKMARK); if(pMark) { sName = pMark->GetName(); bDelBookmrk = true; if( !bIsModified ) rSh.ResetModified(); } else sName.clear(); rSh.DoUndo( bUndo ); } if( !sName.isEmpty() && nullptr != ( pDocShell = rSh.GetDoc()->GetDocShell() ) ) { // then we create our "server" and connect to it refObj = pDocShell->DdeCreateLinkSource( sName ); if( refObj.is() ) { refObj->AddConnectAdvise( this ); refObj->AddDataAdvise( this, aEmptyOUStr, ADVISEMODE_NODATA | ADVISEMODE_ONLYONCE ); nOldTimeOut = refObj->GetUpdateTimeout(); refObj->SetUpdateTimeout( 0 ); } } } SwTrnsfrDdeLink::~SwTrnsfrDdeLink() { if( refObj.is() ) Disconnect( true ); } ::sfx2::SvBaseLink::UpdateResult SwTrnsfrDdeLink::DataChanged( const OUString& , const uno::Any& ) { // well, that's it with the link if( !bInDisconnect ) { if( FindDocShell() && pDocShell->GetView() ) rTrnsfr.RemoveDDELinkFormat( pDocShell->GetView()->GetEditWin() ); Disconnect( false ); } return SUCCESS; } bool SwTrnsfrDdeLink::WriteData( SvStream& rStrm ) { if( !refObj.is() || !FindDocShell() ) return false; rtl_TextEncoding eEncoding = DDE_TXT_ENCODING; const OString aAppNm(OUStringToOString( Application::GetAppName(), eEncoding)); const OString aTopic(OUStringToOString( pDocShell->GetTitle(SFX_TITLE_FULLNAME), eEncoding)); const OString aName(OUStringToOString(sName, eEncoding)); std::unique_ptr pMem(new sal_Char[ aAppNm.getLength() + aTopic.getLength() + aName.getLength() + 4 ]); sal_Int32 nLen = aAppNm.getLength(); memcpy( pMem.get(), aAppNm.getStr(), nLen ); pMem[ nLen++ ] = 0; memcpy( pMem.get() + nLen, aTopic.getStr(), aTopic.getLength() ); nLen = nLen + aTopic.getLength(); pMem[ nLen++ ] = 0; memcpy( pMem.get() + nLen, aName.getStr(), aName.getLength() ); nLen = nLen + aName.getLength(); pMem[ nLen++ ] = 0; pMem[ nLen++ ] = 0; rStrm.WriteBytes( pMem.get(), nLen ); pMem.reset(); IDocumentMarkAccess* const pMarkAccess = pDocShell->GetDoc()->getIDocumentMarkAccess(); IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->findMark(sName); if(ppMark != pMarkAccess->getAllMarksEnd() && IDocumentMarkAccess::GetType(**ppMark) != IDocumentMarkAccess::MarkType::BOOKMARK) { // the mark is still a DdeBookmark // we replace it with a Bookmark, so it will get saved etc. ::sw::mark::IMark* const pMark = ppMark->get(); ::sfx2::SvLinkSource* p = refObj.get(); SwServerObject& rServerObject = dynamic_cast(*p); // collecting state of old mark SwPaM aPaM(pMark->GetMarkStart()); *aPaM.GetPoint() = pMark->GetMarkStart(); if(pMark->IsExpanded()) { aPaM.SetMark(); *aPaM.GetMark() = pMark->GetMarkEnd(); } OUString sMarkName = pMark->GetName(); // remove mark rServerObject.SetNoServer(); // this removes the connection between SwServerObject and mark // N.B. ppMark was not loaded from file and cannot have xml:id pMarkAccess->deleteMark(ppMark); // recreate as Bookmark ::sw::mark::IMark* const pNewMark = pMarkAccess->makeMark( aPaM, sMarkName, IDocumentMarkAccess::MarkType::BOOKMARK, ::sw::mark::InsertMode::New); rServerObject.SetDdeBookmark(*pNewMark); } bDelBookmrk = false; return true; } void SwTrnsfrDdeLink::Disconnect( bool bRemoveDataAdvise ) { // don't accept DataChanged anymore, when already in Disconnect! // (DTOR from Bookmark sends a DataChanged!) bool bOldDisconnect = bInDisconnect; bInDisconnect = true; // destroy the unused bookmark again (without Undo!)? if( bDelBookmrk && refObj.is() && FindDocShell() ) { SwDoc* pDoc = pDocShell->GetDoc(); ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); // #i58448# Link aSavedOle2Link( pDoc->GetOle2Link() ); pDoc->SetOle2Link( Link() ); bool bIsModified = pDoc->getIDocumentState().IsModified(); IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); pMarkAccess->deleteMark(pMarkAccess->findMark(sName)); if( !bIsModified ) pDoc->getIDocumentState().ResetModified(); // #i58448# pDoc->SetOle2Link( aSavedOle2Link ); bDelBookmrk = false; } if( refObj.is() ) { refObj->SetUpdateTimeout( nOldTimeOut ); refObj->RemoveConnectAdvise( this ); if( bRemoveDataAdvise ) // in a DataChanged the SelectionObject must NEVER be deleted // is already handled by the base class // (ADVISEMODE_ONLYONCE!!!!) // but always in normal Disconnect! refObj->RemoveAllDataAdvise( this ); refObj.clear(); } bInDisconnect = bOldDisconnect; } bool SwTrnsfrDdeLink::FindDocShell() { SfxObjectShell* pTmpSh = SfxObjectShell::GetFirst( checkSfxObjectShell ); while( pTmpSh ) { if( pTmpSh == pDocShell ) // that's what we want to have { if( pDocShell->GetDoc() ) return true; break; // the Doc is not there anymore, so leave! } pTmpSh = SfxObjectShell::GetNext( *pTmpSh, checkSfxObjectShell ); } pDocShell = nullptr; return false; } void SwTrnsfrDdeLink::Closed() { if( !bInDisconnect && refObj.is() ) { refObj->RemoveAllDataAdvise( this ); refObj->RemoveConnectAdvise( this ); refObj.clear(); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */