4615 lines
168 KiB
C++
4615 lines
168 KiB
C++
/* -*- 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 <config_features.h>
|
|
|
|
#include <com/sun/star/embed/XTransactedObject.hpp>
|
|
#include <com/sun/star/embed/Aspects.hpp>
|
|
#include <com/sun/star/embed/XEmbedObjectClipboardCreator.hpp>
|
|
#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
|
|
#include <com/sun/star/embed/MSOLEObjectSystemCreator.hpp>
|
|
#include <com/sun/star/text/XPasteListener.hpp>
|
|
|
|
#include <svtools/embedtransfer.hxx>
|
|
#include <svtools/insdlg.hxx>
|
|
#include <unotools/tempfile.hxx>
|
|
#include <comphelper/fileformat.h>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <comphelper/propertyvalue.hxx>
|
|
#include <comphelper/servicehelper.hxx>
|
|
#include <comphelper/storagehelper.hxx>
|
|
#include <comphelper/string.hxx>
|
|
#include <o3tl/deleter.hxx>
|
|
#include <o3tl/temporary.hxx>
|
|
#include <unotools/ucbstreamhelper.hxx>
|
|
#include <sot/filelist.hxx>
|
|
#include <svx/svxdlg.hxx>
|
|
#include <toolkit/helper/vclunohelper.hxx>
|
|
#include <osl/endian.h>
|
|
#include <sfx2/linkmgr.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
#include <vcl/weld.hxx>
|
|
#include <sfx2/dispatch.hxx>
|
|
#include <sfx2/viewfrm.hxx>
|
|
#include <svl/stritem.hxx>
|
|
#include <vcl/imap.hxx>
|
|
#include <sot/storage.hxx>
|
|
#include <vcl/graph.hxx>
|
|
#include <svl/urihelper.hxx>
|
|
#include <svx/svdmodel.hxx>
|
|
#include <svx/xmlexchg.hxx>
|
|
#include <svx/dbaexchange.hxx>
|
|
#include <svx/clipfmtitem.hxx>
|
|
#include <sfx2/mieclip.hxx>
|
|
#include <svl/urlbmk.hxx>
|
|
#include <vcl/inetimg.hxx>
|
|
#include <svx/fmview.hxx>
|
|
#include <sfx2/docfilt.hxx>
|
|
#include <vcl/imapobj.hxx>
|
|
#include <sfx2/docfile.hxx>
|
|
#include <unotools/transliterationwrapper.hxx>
|
|
#include <unotools/streamwrap.hxx>
|
|
#include <vcl/graphicfilter.hxx>
|
|
|
|
#ifdef _WIN32
|
|
#include <prewin.h>
|
|
#include <postwin.h>
|
|
#include <o3tl/char16_t2wchar_t.hxx>
|
|
#include <osl/file.hxx>
|
|
#endif
|
|
|
|
#include <svx/unomodel.hxx>
|
|
#include <fmturl.hxx>
|
|
#include <fmtinfmt.hxx>
|
|
#include <swdtflvr.hxx>
|
|
#include <shellio.hxx>
|
|
#include <ddefld.hxx>
|
|
#include <doc.hxx>
|
|
#include <IDocumentUndoRedo.hxx>
|
|
#include <IDocumentDrawModelAccess.hxx>
|
|
#include <IDocumentFieldsAccess.hxx>
|
|
#include <IDocumentRedlineAccess.hxx>
|
|
#include <IDocumentState.hxx>
|
|
#include <IMark.hxx>
|
|
#include <section.hxx>
|
|
#include <ndtxt.hxx>
|
|
#include <edtdd.hxx>
|
|
#include <edtwin.hxx>
|
|
#include <navicont.hxx>
|
|
#include <swcont.hxx>
|
|
#include <wrtsh.hxx>
|
|
#include <swmodule.hxx>
|
|
#include <view.hxx>
|
|
#include <docsh.hxx>
|
|
#include <wdocsh.hxx>
|
|
#include <fldbas.hxx>
|
|
#include <swundo.hxx>
|
|
#include <pam.hxx>
|
|
#include <ndole.hxx>
|
|
#include <swwait.hxx>
|
|
#include <viewopt.hxx>
|
|
#include <SwCapObjType.hxx>
|
|
#include <cmdid.h>
|
|
#include <strings.hrc>
|
|
#include <svx/svditer.hxx>
|
|
#include <editeng/eeitem.hxx>
|
|
#include <editeng/fhgtitem.hxx>
|
|
#include <editeng/prntitem.hxx>
|
|
#include <svx/svdpage.hxx>
|
|
#include <avmedia/mediawindow.hxx>
|
|
#include <swcrsr.hxx>
|
|
#include <SwRewriter.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <swserv.hxx>
|
|
#include <fmtmeta.hxx>
|
|
#include <itabenum.hxx>
|
|
#include <iodetect.hxx>
|
|
#include <unotextrange.hxx>
|
|
#include <unoframe.hxx>
|
|
#include <txatbase.hxx>
|
|
#include <unoparaframeenum.hxx>
|
|
#include <vcl/uitest/logger.hxx>
|
|
#include <vcl/uitest/eventdescription.hxx>
|
|
|
|
#include <vcl/GraphicNativeTransform.hxx>
|
|
#include <vcl/GraphicNativeMetadata.hxx>
|
|
#include <vcl/TypeSerializer.hxx>
|
|
#include <comphelper/lok.hxx>
|
|
#include <sfx2/classificationhelper.hxx>
|
|
#include <sfx2/sfxdlg.hxx>
|
|
#include <comphelper/classids.hxx>
|
|
#include <osl/diagnose.h>
|
|
|
|
#include <memory>
|
|
|
|
/* default (A4 format) width of 210mm - 2 * border size (border on both sides) */
|
|
constexpr tools::Long constOleWidthInMm = 210 - 2 * lMinBorderInMm;
|
|
|
|
constexpr Size constOleSize100mm(
|
|
constOleWidthInMm * 100, // convert from mm to 100mm
|
|
3000 // 3 cm
|
|
);
|
|
|
|
constexpr Size constOleSizeTwip = o3tl::convert(constOleSize100mm, o3tl::Length::mm100, o3tl::Length::twip);
|
|
|
|
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;
|
|
namespace {
|
|
|
|
void collectUIInformation(const OUString& rAction, const OUString& aParameters)
|
|
{
|
|
EventDescription aDescription;
|
|
aDescription.aAction = rAction;
|
|
aDescription.aParameters = {{"parameters", aParameters}};
|
|
aDescription.aID = "writer_edit";
|
|
aDescription.aKeyWord = "SwEditWinUIObject";
|
|
aDescription.aParent = "MainWindow";
|
|
UITestLogger::getInstance().logEvent(aDescription);
|
|
}
|
|
|
|
}
|
|
|
|
class SwTransferDdeLink : public ::sfx2::SvBaseLink
|
|
{
|
|
OUString m_sName;
|
|
::sfx2::SvLinkSourceRef m_xRefObj;
|
|
SwTransferable& m_rTransfer;
|
|
SwDocShell* m_pDocShell;
|
|
sal_uLong m_nOldTimeOut;
|
|
bool m_bDelBookmark : 1;
|
|
bool m_bInDisconnect : 1;
|
|
|
|
bool FindDocShell();
|
|
|
|
using sfx2::SvBaseLink::Disconnect;
|
|
|
|
protected:
|
|
virtual ~SwTransferDdeLink() override;
|
|
|
|
public:
|
|
SwTransferDdeLink( 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 );
|
|
};
|
|
|
|
/// Tracks the boundaries of pasted content and notifies listeners.
|
|
class SwPasteContext
|
|
{
|
|
public:
|
|
SwPasteContext(SwWrtShell& rWrtShell);
|
|
~SwPasteContext();
|
|
|
|
void remember();
|
|
void forget();
|
|
|
|
private:
|
|
SwWrtShell& m_rWrtShell;
|
|
std::optional<SwPaM> m_oPaM;
|
|
sal_Int32 m_nStartContent = 0;
|
|
};
|
|
|
|
namespace {
|
|
|
|
// helper class for Action and Undo enclosing
|
|
class SwTrnsfrActionAndUndo
|
|
{
|
|
SwWrtShell *pSh;
|
|
public:
|
|
SwTrnsfrActionAndUndo( SwWrtShell *pS, bool bDelSel = false, SwPasteContext* pContext = nullptr)
|
|
: pSh( pS )
|
|
{
|
|
pSh->StartUndo( SwUndoId::PASTE_CLIPBOARD );
|
|
if( bDelSel )
|
|
{
|
|
if (pContext)
|
|
pContext->forget();
|
|
pSh->DelRight();
|
|
if (pContext)
|
|
pContext->remember();
|
|
}
|
|
pSh->StartAllAction();
|
|
}
|
|
~SwTrnsfrActionAndUndo() COVERITY_NOEXCEPT_FALSE
|
|
{
|
|
pSh->EndUndo();
|
|
pSh->EndAllAction();
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
SwTransferable::SwTransferable( SwWrtShell& rSh )
|
|
: m_pWrtShell( &rSh ),
|
|
m_pCreatorView( nullptr ),
|
|
m_pOrigGraphic( nullptr ),
|
|
m_eBufferType( TransferBufferType::NONE ),
|
|
m_bOldIdle(false),
|
|
m_bCleanUp(false)
|
|
{
|
|
rSh.GetView().AddTransferable(*this);
|
|
SwDocShell* pDShell = rSh.GetDoc()->GetDocShell();
|
|
if( !pDShell )
|
|
return;
|
|
|
|
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!
|
|
DisconnectDDE();
|
|
|
|
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.
|
|
m_pClpDocFac.reset();
|
|
|
|
// 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<SwDocShell*>(pObj);
|
|
pDocSh->DoClose();
|
|
}
|
|
m_aDocShellRef.Clear();
|
|
|
|
if (SwModule* pMod = SwModule::get())
|
|
{
|
|
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& rDoc = rDocFac.GetDoc();
|
|
rDoc.SetClipBoard( true );
|
|
return rDoc;
|
|
}
|
|
|
|
void SwTransferable::ObjectReleased()
|
|
{
|
|
SwModule* pMod = SwModule::get();
|
|
if (!pMod)
|
|
return;
|
|
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
|
|
if (this == SwModule::get()->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(constOleSizeTwip);
|
|
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<SwContentNode,SwFormatColl> aIter( *m_pClpDocFac->GetDoc().GetDfltGrfFormatColl() );
|
|
for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
|
|
if( SwNodeType::Ole == pNd->GetNodeType() )
|
|
{
|
|
xObj = static_cast<SwOLENode*>(pNd)->GetOLEObj().GetOleRef();
|
|
nAspect = static_cast<SwOLENode*>(pNd)->GetAspect();
|
|
break;
|
|
}
|
|
}
|
|
return xObj;
|
|
}
|
|
|
|
const Graphic* SwTransferable::FindOLEReplacementGraphic() const
|
|
{
|
|
if( m_pClpDocFac )
|
|
{
|
|
SwIterator<SwContentNode,SwFormatColl> aIter( *m_pClpDocFac->GetDoc().GetDfltGrfFormatColl() );
|
|
for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
|
|
if( SwNodeType::Ole == pNd->GetNodeType() )
|
|
{
|
|
return static_cast<SwOLENode*>(pNd)->GetGraphic();
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void SwTransferable::RemoveDDELinkFormat(vcl::Window& rWin)
|
|
{
|
|
RemoveFormat( SotClipboardFormatId::LINK );
|
|
if (rWin.GetClipboard()->getContents().get() == this)
|
|
CopyToClipboard(&rWin);
|
|
}
|
|
|
|
void SwTransferable::DisconnectDDE()
|
|
{
|
|
if( m_xDdeLink.is() )
|
|
{
|
|
m_xDdeLink->Disconnect( true );
|
|
m_xDdeLink.clear();
|
|
}
|
|
}
|
|
|
|
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) )
|
|
return;
|
|
|
|
Degree10 aRotation = aMetadata.getRotation();
|
|
if (aRotation)
|
|
{
|
|
GraphicNativeTransform aTransform( aGraphic );
|
|
aTransform.rotate( aRotation );
|
|
}
|
|
}
|
|
}
|
|
|
|
sal_Bool SAL_CALL SwTransferable::isComplex()
|
|
{
|
|
sal_Int32 nTextLength = 0;
|
|
SwNodes& aNodes = m_pWrtShell->GetDoc()->GetNodes();
|
|
for (SwPaM& rPaM : m_pWrtShell->GetCursor()->GetRingContainer())
|
|
{
|
|
for (SwNodeOffset nIndex = rPaM.GetMark()->GetNodeIndex();
|
|
nIndex <= rPaM.GetPoint()->GetNodeIndex(); ++nIndex)
|
|
{
|
|
SwNode& rNd = *aNodes[nIndex];
|
|
|
|
SwTextNode* pTextNode = rNd.GetTextNode();
|
|
if (pTextNode)
|
|
{
|
|
if (pTextNode->HasHints())
|
|
{
|
|
for (size_t nHint = 0; nHint < pTextNode->GetSwpHints().Count(); ++nHint)
|
|
{
|
|
SwTextAttr* pHint = pTextNode->GetSwpHints().Get(nHint);
|
|
if (pHint->Which() == RES_TXTATR_FLYCNT)
|
|
{
|
|
return true; // Complex
|
|
}
|
|
}
|
|
}
|
|
|
|
FrameClientSortList_t vFrames;
|
|
::CollectFrameAtNode(rNd, vFrames, true);
|
|
if (!vFrames.empty())
|
|
{
|
|
// There is an at-char anchored object to this node, that's complex.
|
|
return true;
|
|
}
|
|
|
|
nTextLength += pTextNode->GetText().getLength();
|
|
if (nTextLength >= 1024 * 512)
|
|
return true; // Complex
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_pWrtShell->GetSelectionType() == SelectionType::DrawObject)
|
|
return true; // Complex
|
|
|
|
// Simple
|
|
return false;
|
|
}
|
|
|
|
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::DrawObject | SelectionType::DbForm) & nSelectionType))
|
|
{
|
|
m_oClpGraphic.emplace();
|
|
if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
|
|
m_pOrigGraphic = &*m_oClpGraphic;
|
|
m_oClpBitmap.emplace();
|
|
if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
|
|
m_pOrigGraphic = &*m_oClpBitmap;
|
|
|
|
// is it a URL-Button ?
|
|
OUString sURL;
|
|
OUString sDesc;
|
|
if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
|
|
{
|
|
m_oBookmark.emplace( sURL, sDesc );
|
|
m_eBufferType = TransferBufferType::InetField;
|
|
}
|
|
}
|
|
|
|
m_pClpDocFac.reset(new SwDocFac);
|
|
SwDoc& rTmpDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
|
|
rTmpDoc.getIDocumentFieldsAccess().LockExpFields(); // never update fields - leave text as it is
|
|
lclOverWriteDoc(*m_pWrtShell, rTmpDoc);
|
|
|
|
// in CORE a new one was created (OLE-objects copied!)
|
|
m_aDocShellRef = rTmpDoc.GetTmpDocShell();
|
|
if( m_aDocShellRef.Is() )
|
|
SwTransferable::InitOle( m_aDocShellRef );
|
|
rTmpDoc.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_oBookmark.emplace(
|
|
static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr)->GetValue(),
|
|
aContentAtPos.sStr );
|
|
m_eBufferType = TransferBufferType::InetField;
|
|
if( bSelect )
|
|
m_pWrtShell->SelectTextAttr( RES_TXTATR_INETFMT );
|
|
}
|
|
}
|
|
if( m_pWrtShell->IsFrameSelected() )
|
|
{
|
|
SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
|
|
m_pWrtShell->GetFlyFrameAttr( aSet );
|
|
const SwFormatURL& rURL = aSet.Get( RES_URL );
|
|
if( rURL.GetMap() )
|
|
m_pImageMap.reset(new ImageMap( *rURL.GetMap() ));
|
|
else if( !rURL.GetURL().isEmpty() )
|
|
m_pTargetURL.reset(new INetImage(OUString(), 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& rDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
bOK = SetObject( rDoc.getIDocumentDrawModelAccess().GetDrawModel(),
|
|
SWTRANSFER_OBJECTTYPE_DRAWMODEL, rFlavor );
|
|
}
|
|
break;
|
|
|
|
case SotClipboardFormatId::STRING:
|
|
{
|
|
SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_STRING, rFlavor );
|
|
}
|
|
break;
|
|
case SotClipboardFormatId::RTF:
|
|
{
|
|
SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_RTF, rFlavor );
|
|
}
|
|
break;
|
|
case SotClipboardFormatId::RICHTEXT:
|
|
{
|
|
SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_RICHTEXT, rFlavor );
|
|
}
|
|
break;
|
|
|
|
case SotClipboardFormatId::HTML:
|
|
{
|
|
SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
bOK = SetObject( &rDoc, 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_oClpGraphic->GetGDIMetaFile() );
|
|
break;
|
|
case SotClipboardFormatId::BITMAP:
|
|
case SotClipboardFormatId::PNG:
|
|
// Neither pClpBitmap nor pClpGraphic are necessarily set
|
|
if( (m_eBufferType & TransferBufferType::Graphic) && (m_oClpBitmap || m_oClpGraphic))
|
|
bOK = SetBitmapEx( (m_oClpBitmap ? m_oClpBitmap : m_oClpGraphic)->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_oBookmark )
|
|
bOK = SetINetBookmark( *m_oBookmark, rFlavor );
|
|
break;
|
|
|
|
case SotClipboardFormatId::EMBED_SOURCE:
|
|
if( !m_aDocShellRef.Is() )
|
|
{
|
|
SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
m_aDocShellRef = new SwDocShell(rDoc, SfxObjectCreateMode::EMBEDDED);
|
|
m_aDocShellRef->DoInitNew();
|
|
SwTransferable::InitOle( m_aDocShellRef );
|
|
}
|
|
bOK = SetObject( &m_aDocShellRef, SWTRANSFER_OBJECTTYPE_SWOLE,
|
|
rFlavor );
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
return bOK;
|
|
}
|
|
|
|
bool SwTransferable::WriteObject( SvStream& rOStream,
|
|
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<SdrModel*>(pObject);
|
|
rOStream.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.GetUserOrPoolDefaultItem(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<io::XOutputStream> xDocOut( new utl::OOutputStreamWrapper( rOStream ) );
|
|
SvxDrawingLayerExport( pModel, xDocOut );
|
|
}
|
|
|
|
bRet = ERRCODE_NONE == rOStream.GetError();
|
|
}
|
|
break;
|
|
|
|
case SWTRANSFER_OBJECTTYPE_SWOLE:
|
|
{
|
|
SfxObjectShell* pEmbObj = static_cast<SfxObjectShell*>(pObject);
|
|
try
|
|
{
|
|
::utl::TempFileFast aTempFile;
|
|
SvStream* pTempStream = aTempFile.GetStream(StreamMode::READWRITE);
|
|
uno::Reference< embed::XStorage > xWorkStore =
|
|
::comphelper::OStorageHelper::GetStorageFromStream( new utl::OStreamWrapper(*pTempStream), 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();
|
|
|
|
rOStream.SetBufferSize( 0xff00 );
|
|
rOStream.WriteStream( *pTempStream );
|
|
|
|
xWorkStore->dispose();
|
|
xWorkStore.clear();
|
|
}
|
|
catch (const uno::Exception&)
|
|
{
|
|
}
|
|
|
|
bRet = ( rOStream.GetError() == ERRCODE_NONE );
|
|
}
|
|
break;
|
|
|
|
case SWTRANSFER_OBJECTTYPE_DDE:
|
|
{
|
|
rOStream.SetBufferSize( 1024 );
|
|
SwTransferDdeLink* pDdeLnk = static_cast<SwTransferDdeLink*>(pObject);
|
|
if( pDdeLnk->WriteData( rOStream ) )
|
|
{
|
|
bRet = ERRCODE_NONE == rOStream.GetError();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SWTRANSFER_OBJECTTYPE_HTML:
|
|
{
|
|
// LOK is interested in getting images embedded for copy/paste support.
|
|
GetHTMLWriter( comphelper::LibreOfficeKit::isActive() ? u"EmbedImages;NoPrettyPrint"_ustr : OUString(), OUString(), xWrt );
|
|
break;
|
|
}
|
|
|
|
case SWTRANSFER_OBJECTTYPE_RTF:
|
|
case SWTRANSFER_OBJECTTYPE_RICHTEXT:
|
|
GetRTFWriter(std::u16string_view(), OUString(), xWrt);
|
|
break;
|
|
|
|
case SWTRANSFER_OBJECTTYPE_STRING:
|
|
GetASCWriter(std::u16string_view(), OUString(), xWrt);
|
|
if( xWrt.is() )
|
|
{
|
|
SwAsciiOptions aAOpt;
|
|
aAOpt.SetCharSet( RTL_TEXTENCODING_UTF8 );
|
|
xWrt->SetAsciiOptions( aAOpt );
|
|
|
|
// no start char for clipboard
|
|
xWrt->m_bUCS2_WithStartChar = false;
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
if( xWrt.is() )
|
|
{
|
|
SwDoc* pDoc = static_cast<SwDoc*>(pObject);
|
|
xWrt->m_bWriteClipboardDoc = true;
|
|
xWrt->m_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( rOStream, *pDoc );
|
|
if( ! aWrt.Write( xWrt ).IsError() )
|
|
{
|
|
rOStream.WriteChar( '\0' ); // terminate with a zero
|
|
bRet = true;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
int SwTransferable::Cut()
|
|
{
|
|
int nRet = Copy( true );
|
|
if( nRet )
|
|
DeleteSelection();
|
|
collectUIInformation(u"CUT"_ustr, u"parameter"_ustr);
|
|
return nRet;
|
|
}
|
|
|
|
void SwTransferable::DeleteSelection()
|
|
{
|
|
if(!m_pWrtShell)
|
|
return;
|
|
// ask for type of selection before action-bracketing
|
|
const SelectionType nSelection = m_pWrtShell->GetSelectionType();
|
|
// cut rows or columns selected by enhanced table selection and wholly selected tables
|
|
bool bCutMode = ( SelectionType::TableCell & nSelection ) && ( (SelectionType::TableRow | SelectionType::TableCol) & nSelection ||
|
|
m_pWrtShell->HasWholeTabSelection() );
|
|
|
|
m_pWrtShell->StartUndo( SwUndoId::START );
|
|
if( bCutMode )
|
|
{
|
|
if( !(SelectionType::TableCol & nSelection) )
|
|
m_pWrtShell->DeleteTable();
|
|
else
|
|
{
|
|
SfxDispatcher* pDispatch = m_pWrtShell->GetView().GetViewFrame().GetDispatcher();
|
|
pDispatch->Execute(FN_TABLE_DELETE_COL, SfxCallMode::SYNCHRON);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( ( SelectionType::Text | SelectionType::Table ) & nSelection )
|
|
m_pWrtShell->IntelligentCut( nSelection );
|
|
m_pWrtShell->DelRight();
|
|
}
|
|
m_pWrtShell->EndUndo( SwUndoId::END );
|
|
}
|
|
|
|
static void DeleteDDEMarks(SwDoc & rDest)
|
|
{
|
|
IDocumentMarkAccess *const pMarkAccess = rDest.getIDocumentMarkAccess();
|
|
std::vector< ::sw::mark::MarkBase* > vDdeMarks;
|
|
// find all DDE-Bookmarks
|
|
for (auto ppMark = pMarkAccess->getAllMarksBegin();
|
|
ppMark != pMarkAccess->getAllMarksEnd();
|
|
++ppMark)
|
|
{
|
|
if (IDocumentMarkAccess::MarkType::DDE_BOOKMARK == IDocumentMarkAccess::GetType(**ppMark))
|
|
{
|
|
vDdeMarks.push_back(*ppMark);
|
|
}
|
|
}
|
|
// remove all DDE-Bookmarks, they are invalid inside the clipdoc!
|
|
for (const auto& rpMark : vDdeMarks)
|
|
{
|
|
pMarkAccess->deleteMark(rpMark);
|
|
}
|
|
}
|
|
|
|
void SwTransferable::PrepareForCopyTextRange(SwPaM & rPaM)
|
|
{
|
|
std::optional<SwWait> oWait;
|
|
if (m_pWrtShell->ShouldWait())
|
|
{
|
|
oWait.emplace( *m_pWrtShell->GetView().GetDocShell(), true );
|
|
}
|
|
|
|
m_pClpDocFac.reset(new SwDocFac);
|
|
|
|
SwDoc& rDest(lcl_GetDoc(*m_pClpDocFac));
|
|
rDest.getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is
|
|
{
|
|
SwDoc const& rSrc(*m_pWrtShell->GetDoc());
|
|
assert(&rSrc == &rPaM.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);
|
|
|
|
// relevant bits of rSrcWrtShell.Copy(rDest);
|
|
rDest.GetIDocumentUndoRedo().DoUndo(false); // always false!
|
|
rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::DeleteRedlines );
|
|
|
|
SwNodeIndex const aIdx(rDest.GetNodes().GetEndOfContent(), -1);
|
|
SwContentNode *const pContentNode(aIdx.GetNode().GetContentNode());
|
|
SwPosition aPos(aIdx, pContentNode, pContentNode ? pContentNode->Len() : 0);
|
|
|
|
rSrc.getIDocumentContentOperations().CopyRange(rPaM, aPos, SwCopyFlags::CheckPosInFly);
|
|
|
|
rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE );
|
|
|
|
rDest.GetMetaFieldManager().copyDocumentProperties(rSrc);
|
|
}
|
|
|
|
DeleteDDEMarks(rDest);
|
|
|
|
// a new one was created in core (OLE objects copied!)
|
|
m_aDocShellRef = rDest.GetTmpDocShell();
|
|
if (m_aDocShellRef.Is())
|
|
SwTransferable::InitOle( m_aDocShellRef );
|
|
rDest.SetTmpDocShell( nullptr );
|
|
|
|
// let's add some formats
|
|
AddFormat( SotClipboardFormatId::EMBED_SOURCE );
|
|
AddFormat( SotClipboardFormatId::RTF );
|
|
#if HAVE_FEATURE_DESKTOP
|
|
AddFormat( SotClipboardFormatId::RICHTEXT );
|
|
AddFormat( SotClipboardFormatId::HTML );
|
|
#endif
|
|
AddFormat( SotClipboardFormatId::STRING );
|
|
}
|
|
|
|
int SwTransferable::PrepareForCopy( bool bIsCut )
|
|
{
|
|
int nRet = 1;
|
|
if(!m_pWrtShell)
|
|
return 0;
|
|
|
|
if ( m_pWrtShell->GetTableInsertMode() != SwTable::SEARCH_NONE )
|
|
m_pWrtShell->SetTableInsertMode( SwTable::SEARCH_NONE );
|
|
|
|
if ( m_pWrtShell->GetTableCopied() )
|
|
m_pWrtShell->SetTableCopied( false );
|
|
|
|
OUString sGrfNm;
|
|
const SelectionType nSelection = m_pWrtShell->GetSelectionType();
|
|
if( nSelection == SelectionType::Graphic )
|
|
{
|
|
m_oClpGraphic.emplace();
|
|
if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
|
|
m_pOrigGraphic = &*m_oClpGraphic;
|
|
m_oClpBitmap.emplace();
|
|
if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
|
|
m_pOrigGraphic = &*m_oClpBitmap;
|
|
|
|
m_pClpDocFac.reset(new SwDocFac);
|
|
SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
m_pWrtShell->Copy(rDoc);
|
|
|
|
#if HAVE_FEATURE_DESKTOP
|
|
if (m_pOrigGraphic && !m_pOrigGraphic->GetBitmapEx().IsEmpty())
|
|
AddFormat( SotClipboardFormatId::SVXB );
|
|
#endif
|
|
|
|
PrepareOLE( m_aObjDesc );
|
|
AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
|
|
|
|
const Graphic* pGrf = m_pWrtShell->GetGraphic();
|
|
if( pGrf && pGrf->IsSupportedGraphic() )
|
|
{
|
|
AddFormat( SotClipboardFormatId::PNG );
|
|
#if HAVE_FEATURE_DESKTOP
|
|
AddFormat( SotClipboardFormatId::GDIMETAFILE );
|
|
AddFormat( SotClipboardFormatId::BITMAP );
|
|
#endif
|
|
}
|
|
m_eBufferType = TransferBufferType::Graphic;
|
|
m_pWrtShell->GetGrfNms( &sGrfNm, nullptr );
|
|
}
|
|
else if ( nSelection == SelectionType::Ole )
|
|
{
|
|
m_pClpDocFac.reset(new SwDocFac);
|
|
SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
m_aDocShellRef = new SwDocShell(rDoc, SfxObjectCreateMode::EMBEDDED);
|
|
m_aDocShellRef->DoInitNew();
|
|
m_pWrtShell->Copy(rDoc);
|
|
|
|
AddFormat( SotClipboardFormatId::EMBED_SOURCE );
|
|
|
|
// --> OD #i98753#
|
|
// set size of embedded object at the object description structure
|
|
m_aObjDesc.maSize = o3tl::convert(m_pWrtShell->GetObjSize(), o3tl::Length::twip, o3tl::Length::mm100);
|
|
|
|
// <--
|
|
PrepareOLE( m_aObjDesc );
|
|
|
|
#if HAVE_FEATURE_DESKTOP
|
|
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() );
|
|
|
|
for( const auto& rItem : aVector )
|
|
AddFormat( rItem );
|
|
}
|
|
}
|
|
#endif
|
|
m_eBufferType = TransferBufferType::Ole;
|
|
}
|
|
// Is there anything to provide anyway?
|
|
else if ( m_pWrtShell->IsSelection() || m_pWrtShell->IsFrameSelected() ||
|
|
m_pWrtShell->IsObjSelected() )
|
|
{
|
|
std::optional<SwWait> oWait;
|
|
if( m_pWrtShell->ShouldWait() )
|
|
oWait.emplace( *m_pWrtShell->GetView().GetDocShell(), true );
|
|
|
|
m_pClpDocFac.reset(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& rTmpDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
|
|
rTmpDoc.getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is
|
|
lclOverWriteDoc(*m_pWrtShell, rTmpDoc);
|
|
|
|
DeleteDDEMarks(rTmpDoc);
|
|
|
|
// a new one was created in CORE (OLE objects copied!)
|
|
m_aDocShellRef = rTmpDoc.GetTmpDocShell();
|
|
if( m_aDocShellRef.Is() )
|
|
SwTransferable::InitOle( m_aDocShellRef );
|
|
rTmpDoc.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();
|
|
|
|
m_pWrtShell->SetTableCopied(true);
|
|
|
|
if ( bIsCut && (SelectionType::TableRow | SelectionType::TableCol) & nSelection )
|
|
m_pWrtShell->SetTableInsertMode( (SelectionType::TableRow & nSelection) ? SwTable::SEARCH_ROW : SwTable::SEARCH_COL );
|
|
}
|
|
|
|
#if HAVE_FEATURE_DESKTOP
|
|
//When someone needs it, we 'OLE' him something
|
|
AddFormat( SotClipboardFormatId::EMBED_SOURCE );
|
|
#endif
|
|
|
|
//put RTF ahead of the OLE's Metafile to have less loss
|
|
if( !m_pWrtShell->IsObjSelected() )
|
|
{
|
|
AddFormat( SotClipboardFormatId::RTF );
|
|
#if HAVE_FEATURE_DESKTOP
|
|
AddFormat( SotClipboardFormatId::RICHTEXT );
|
|
AddFormat( SotClipboardFormatId::HTML );
|
|
#endif
|
|
}
|
|
if( m_pWrtShell->IsSelection() )
|
|
AddFormat( SotClipboardFormatId::STRING );
|
|
|
|
if( nSelection & ( SelectionType::DrawObject | SelectionType::DbForm ))
|
|
{
|
|
AddFormat( SotClipboardFormatId::DRAWING );
|
|
if ( nSelection & SelectionType::DrawObject )
|
|
{
|
|
#if HAVE_FEATURE_DESKTOP
|
|
AddFormat( SotClipboardFormatId::GDIMETAFILE );
|
|
AddFormat( SotClipboardFormatId::BITMAP );
|
|
#endif
|
|
AddFormat( SotClipboardFormatId::PNG );
|
|
}
|
|
m_eBufferType = static_cast<TransferBufferType>( TransferBufferType::Graphic | m_eBufferType );
|
|
|
|
m_oClpGraphic.emplace();
|
|
if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
|
|
m_pOrigGraphic = &*m_oClpGraphic;
|
|
m_oClpBitmap.emplace();
|
|
if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
|
|
m_pOrigGraphic = &*m_oClpBitmap;
|
|
|
|
// is it a URL-Button ?
|
|
OUString sURL;
|
|
OUString sDesc;
|
|
if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
|
|
{
|
|
AddFormat( SotClipboardFormatId::STRING );
|
|
#if HAVE_FEATURE_DESKTOP
|
|
AddFormat( SotClipboardFormatId::SOLK );
|
|
AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
|
|
AddFormat( SotClipboardFormatId::FILECONTENT );
|
|
AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
|
|
#endif
|
|
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() )
|
|
{
|
|
#if HAVE_FEATURE_DESKTOP
|
|
AddFormat( SotClipboardFormatId::LINK );
|
|
#endif
|
|
m_xDdeLink = new SwTransferDdeLink( *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.
|
|
m_aObjDesc.maSize = constOleSize100mm;
|
|
|
|
PrepareOLE( m_aObjDesc );
|
|
#if HAVE_FEATURE_DESKTOP
|
|
AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
|
|
#endif
|
|
}
|
|
else
|
|
nRet = 0;
|
|
|
|
if( m_pWrtShell->IsFrameSelected() )
|
|
{
|
|
SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
|
|
m_pWrtShell->GetFlyFrameAttr( aSet );
|
|
const SwFormatURL& rURL = 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 )
|
|
{
|
|
if (m_pWrtShell->GetView().GetObjectShell()->isContentExtractionLocked())
|
|
return 0;
|
|
|
|
int nRet = PrepareForCopy( bIsCut );
|
|
if ( nRet )
|
|
{
|
|
CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
|
|
}
|
|
|
|
if( !bIsCut ){
|
|
collectUIInformation(u"COPY"_ustr, u"parameter"_ustr);
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
void SwTransferable::CalculateAndCopy()
|
|
{
|
|
if(!m_pWrtShell)
|
|
return;
|
|
SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true );
|
|
|
|
OUString aStr( m_pWrtShell->Calculate() );
|
|
|
|
m_pClpDocFac.reset(new SwDocFac);
|
|
SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
m_pWrtShell->Copy(rDoc, &aStr);
|
|
m_eBufferType = TransferBufferType::Document;
|
|
AddFormat( SotClipboardFormatId::STRING );
|
|
|
|
CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
|
|
}
|
|
|
|
bool SwTransferable::CopyGlossary( SwTextBlocks& rGlossary, const OUString& rStr )
|
|
{
|
|
if(!m_pWrtShell)
|
|
return false;
|
|
SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true );
|
|
|
|
m_pClpDocFac.reset(new SwDocFac);
|
|
SwDoc& rCDoc = lcl_GetDoc(*m_pClpDocFac);
|
|
|
|
SwNodes& rNds = rCDoc.GetNodes();
|
|
SwNodeIndex aNodeIdx( *rNds.GetEndOfContent().StartOfSectionNode() );
|
|
SwContentNode* pCNd = SwNodes::GoNext(&aNodeIdx); // go to 1st ContentNode
|
|
SwPaM aPam( *pCNd );
|
|
|
|
rCDoc.getIDocumentFieldsAccess().LockExpFields(); // never update fields - leave text as it is
|
|
|
|
rCDoc.InsertGlossary( rGlossary, rStr, aPam );
|
|
|
|
// a new one was created in CORE (OLE-Objects copied!)
|
|
m_aDocShellRef = rCDoc.GetTmpDocShell();
|
|
if( m_aDocShellRef.Is() )
|
|
SwTransferable::InitOle( m_aDocShellRef );
|
|
rCDoc.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.
|
|
m_aObjDesc.maSize = constOleSize100mm;
|
|
|
|
PrepareOLE( m_aObjDesc );
|
|
AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
|
|
|
|
CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
|
|
|
|
return true;
|
|
}
|
|
|
|
static uno::Reference < XTransferable > * lcl_getTransferPointer ( uno::Reference < XTransferable > &xRef )
|
|
{
|
|
return &xRef;
|
|
}
|
|
|
|
SwPasteContext::SwPasteContext(SwWrtShell& rWrtShell)
|
|
: m_rWrtShell(rWrtShell)
|
|
{
|
|
remember();
|
|
}
|
|
|
|
void SwPasteContext::remember()
|
|
{
|
|
if (m_rWrtShell.GetPasteListeners().getLength() == 0)
|
|
return;
|
|
|
|
SwPaM* pCursor = m_rWrtShell.GetCursor();
|
|
if (!pCursor)
|
|
return;
|
|
|
|
// Set point to the previous node, so it is not moved.
|
|
const SwNode& rNode = pCursor->GetPoint()->GetNode();
|
|
m_oPaM.emplace(rNode, rNode, SwNodeOffset(0), SwNodeOffset(-1));
|
|
m_nStartContent = pCursor->GetPoint()->GetContentIndex();
|
|
}
|
|
|
|
void SwPasteContext::forget() { m_oPaM.reset(); }
|
|
|
|
SwPasteContext::~SwPasteContext()
|
|
{
|
|
try
|
|
{
|
|
if (m_rWrtShell.GetPasteListeners().getLength() == 0)
|
|
return;
|
|
|
|
beans::PropertyValue aPropertyValue;
|
|
|
|
switch (m_rWrtShell.GetView().GetShellMode())
|
|
{
|
|
case ShellMode::Graphic:
|
|
{
|
|
SwFrameFormat* pFormat = m_rWrtShell.GetFlyFrameFormat();
|
|
if (!pFormat)
|
|
return;
|
|
|
|
aPropertyValue.Name = "TextGraphicObject";
|
|
aPropertyValue.Value
|
|
<<= uno::Reference<text::XTextContent>(SwXTextGraphicObject::CreateXTextGraphicObject(*pFormat->GetDoc(), pFormat));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
if (!m_oPaM)
|
|
return;
|
|
|
|
SwPaM* pCursor = m_rWrtShell.GetCursor();
|
|
if (!pCursor)
|
|
return;
|
|
|
|
if (!pCursor->GetPoint()->GetNode().IsTextNode())
|
|
// Non-text was pasted.
|
|
return;
|
|
|
|
// Update mark after paste.
|
|
*m_oPaM->GetMark() = *pCursor->GetPoint();
|
|
|
|
// Restore point.
|
|
m_oPaM->GetPoint()->Adjust(SwNodeOffset(1));
|
|
SwNode& rNode = m_oPaM->GetPointNode();
|
|
if (!rNode.IsTextNode())
|
|
// Starting point is no longer text.
|
|
return;
|
|
|
|
m_oPaM->GetPoint()->SetContent(m_nStartContent);
|
|
|
|
aPropertyValue.Name = "TextRange";
|
|
const rtl::Reference<SwXTextRange> xTextRange = SwXTextRange::CreateXTextRange(
|
|
m_oPaM->GetDoc(), *m_oPaM->GetPoint(), m_oPaM->GetMark());
|
|
aPropertyValue.Value <<= uno::Reference<text::XTextRange>(xTextRange);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (aPropertyValue.Name.isEmpty())
|
|
return;
|
|
|
|
// Invoke the listeners.
|
|
uno::Sequence<beans::PropertyValue> aEvent{ std::move(aPropertyValue) };
|
|
m_rWrtShell.GetPasteListeners().notifyEach( &css::text::XPasteListener::notifyPasteEvent, aEvent );
|
|
}
|
|
catch (const uno::Exception& rException)
|
|
{
|
|
SAL_WARN("sw",
|
|
"SwPasteContext::~SwPasteContext: uncaught exception: " << rException.Message);
|
|
}
|
|
}
|
|
|
|
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> 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;
|
|
}
|
|
|
|
void SwTransferable::SelectPasteFormat(TransferableDataHelper& rData, sal_uInt8& nAction,
|
|
SotClipboardFormatId& nFormat)
|
|
{
|
|
if (nFormat != SotClipboardFormatId::RICHTEXT)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!rData.HasFormat(SotClipboardFormatId::EMBED_SOURCE))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!rData.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
|
|
{
|
|
return;
|
|
}
|
|
|
|
TransferableObjectDescriptor aObjDesc;
|
|
if (!rData.GetTransferableObjectDescriptor(SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (aObjDesc.maClassName != SvGlobalName(SO3_SW_CLASSID))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// At this point we know that we paste from Writer to Writer and the clipboard has the content
|
|
// in both RTF and ODF formats. Prefer ODF in this case.
|
|
nAction = EXCHG_OUT_ACTION_INSERT_OLE;
|
|
nFormat = SotClipboardFormatId::EMBED_SOURCE;
|
|
}
|
|
|
|
// get HTML indentation level by counting tabulator characters before the index
|
|
// (also index value -1 returns with 0)
|
|
static sal_Int32 lcl_getLevel(OUString& sText, sal_Int32 nIdx)
|
|
{
|
|
sal_Int32 nRet = 0;
|
|
while ( nIdx-- > 0 && sText[nIdx] == '\t' )
|
|
{
|
|
nRet++;
|
|
}
|
|
return nRet;
|
|
}
|
|
|
|
bool SwTransferable::Paste(SwWrtShell& rSh, TransferableDataHelper& rData, RndStdIds nAnchorType, bool bIgnoreComments, PasteTableType ePasteTable)
|
|
{
|
|
SwPasteContext aPasteContext(rSh);
|
|
|
|
sal_uInt8 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> xTransferable( rData.GetXTransferable() );
|
|
sal_uInt8 nEventAction;
|
|
nAction = SotExchange::GetExchangeAction(
|
|
rData.GetDataFlavorExVector(),
|
|
nDestination,
|
|
nSourceOptions, /* ?? */
|
|
EXCHG_IN_ACTION_DEFAULT, /* ?? */
|
|
nFormat, nEventAction, SotClipboardFormatId::NONE,
|
|
lcl_getTransferPointer ( xTransferable ),
|
|
&nActionFlags );
|
|
}
|
|
|
|
// when HTML is just an image don't generate new section
|
|
if (rData.HasFormat(SotClipboardFormatId::HTML_SIMPLE) && rData.HasFormat(SotClipboardFormatId::HTML_NO_COMMENT)
|
|
&& rData.HasFormat(SotClipboardFormatId::BITMAP) && nFormat == SotClipboardFormatId::FILE_LIST)
|
|
nFormat = SotClipboardFormatId::BITMAP;
|
|
|
|
// tdf#37223 avoid non-native insertion of Calc worksheets in the following cases:
|
|
// content of 1-cell worksheets are inserted as simple text using RTF format,
|
|
// bigger worksheets within native (Writer) table cells are inserted as native tables,
|
|
// ie. cell by cell instead of embedding the worksheet in a single cell of the Writer table
|
|
if ( EXCHG_IN_ACTION_COPY == nAction && ( rData.HasFormat( SotClipboardFormatId::SYLK ) ||
|
|
rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) )
|
|
{
|
|
// is it a 1-cell worksheet?
|
|
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(o3tl::getToken(aExpand, 0, '\n'), '\t');
|
|
if (nCols == 1)
|
|
bSingleCellTable = true;
|
|
}
|
|
}
|
|
|
|
// convert the worksheet to a temporary native table using HTML format, and copy that into the original native table
|
|
if (!bSingleCellTable && rData.HasFormat( SotClipboardFormatId::HTML ) &&
|
|
SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr && rSh.DoesUndo())
|
|
{
|
|
SfxDispatcher* pDispatch = rSh.GetView().GetViewFrame().GetDispatcher();
|
|
sal_uInt32 nLevel = 0;
|
|
|
|
// within Writer table cells, inserting worksheets using HTML format results only plain text, not a native table,
|
|
// so remove all outer nested tables temporary to get a working insertion point
|
|
// (RTF format has no such problem, but that inserts the hidden rows of the original Calc worksheet, too)
|
|
|
|
// For this, switch off change tracking temporarily, if needed
|
|
RedlineFlags eOld = rSh.GetDoc()->getIDocumentRedlineAccess().GetRedlineFlags();
|
|
if ( eOld & RedlineFlags::On )
|
|
rSh.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags( eOld & ~RedlineFlags::On );
|
|
|
|
OUString sPreviousTableName;
|
|
do
|
|
{
|
|
// tdf#152245 add a limit to the loop, if it's not possible to delete the table
|
|
const SwTableNode* pNode = rSh.GetCursor()->GetPointNode().FindTableNode();
|
|
const OUString sTableName = pNode->GetTable().GetFrameFormat()->GetName();
|
|
if ( sTableName == sPreviousTableName )
|
|
break;
|
|
sPreviousTableName = sTableName;
|
|
// insert a random character to redo the place of the insertion at the end
|
|
pDispatch->Execute(FN_INSERT_NNBSP, SfxCallMode::SYNCHRON);
|
|
pDispatch->Execute(FN_TABLE_DELETE_TABLE, SfxCallMode::SYNCHRON);
|
|
nLevel++;
|
|
} while (SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr);
|
|
|
|
// restore change tracking settings
|
|
if ( eOld & RedlineFlags::On )
|
|
rSh.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags( eOld );
|
|
|
|
if ( SwTransferable::PasteData( rData, rSh, EXCHG_OUT_ACTION_INSERT_STRING, nActionFlags, SotClipboardFormatId::HTML,
|
|
nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, ePasteTable) )
|
|
{
|
|
bool bFoundTemporaryTable = false;
|
|
pDispatch->Execute(FN_LINE_UP, SfxCallMode::SYNCHRON);
|
|
if (SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr)
|
|
{
|
|
bFoundTemporaryTable = true;
|
|
pDispatch->Execute(FN_TABLE_SELECT_ALL, SfxCallMode::SYNCHRON);
|
|
pDispatch->Execute(SID_COPY, SfxCallMode::SYNCHRON);
|
|
}
|
|
for(sal_uInt32 a = 0; a < 1 + (nLevel * 2); a++)
|
|
pDispatch->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
|
|
// clipboard content hasn't changed (limit potential infinite
|
|
// recursion with the same non-native table, as was in tdf#138688)
|
|
if (!bFoundTemporaryTable)
|
|
return false;
|
|
if (ePasteTable == PasteTableType::PASTE_TABLE)
|
|
pDispatch->Execute(FN_PASTE_NESTED_TABLE, SfxCallMode::SYNCHRON);
|
|
else if (ePasteTable == PasteTableType::PASTE_ROW)
|
|
pDispatch->Execute(FN_TABLE_PASTE_ROW_BEFORE, SfxCallMode::SYNCHRON);
|
|
else if (ePasteTable == PasteTableType::PASTE_COLUMN)
|
|
pDispatch->Execute(FN_TABLE_PASTE_COL_BEFORE, SfxCallMode::SYNCHRON);
|
|
else
|
|
pDispatch->Execute(SID_PASTE, SfxCallMode::SYNCHRON);
|
|
return true;
|
|
} else {
|
|
for(sal_uInt32 a = 0; a < (nLevel * 2); a++)
|
|
pDispatch->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
|
|
}
|
|
}
|
|
}
|
|
// insert clipboard content as new table rows/columns before the actual row/column instead of overwriting it
|
|
else if ( (rSh.GetTableInsertMode() != SwTable::SEARCH_NONE || ePasteTable == PasteTableType::PASTE_ROW || ePasteTable == PasteTableType::PASTE_COLUMN) &&
|
|
rData.HasFormat( SotClipboardFormatId::HTML ) &&
|
|
SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr )
|
|
{
|
|
OUString aExpand;
|
|
sal_Int32 nIdx;
|
|
bool bRowMode = rSh.GetTableInsertMode() == SwTable::SEARCH_ROW || ePasteTable == PasteTableType::PASTE_ROW;
|
|
if( rData.GetString( SotClipboardFormatId::HTML, aExpand ) && (nIdx = aExpand.indexOf("<table")) > -1 )
|
|
{
|
|
// calculate table row/column count by analysing indentation of the HTML table extract
|
|
|
|
// calculate indentation level of <table>, which is the base of the next calculations
|
|
// (tdf#148791 table alignment can enlarge it using first level <center>, <div> or <dl>)
|
|
sal_Int32 nTableLevel = lcl_getLevel(aExpand, nIdx);
|
|
// table rows repeated heading use extra indentation, too:
|
|
// <thead> is always used here, and the first table with <thead> is not nested,
|
|
// if its indentation level is greater only by 1, than indentation level of the table
|
|
bool bShifted = lcl_getLevel(aExpand, aExpand.indexOf("<thead")) == nTableLevel + 1;
|
|
// calculate count of selected rows or columns
|
|
sal_Int32 nSelectedRowsOrCols = 0;
|
|
const OUString sSearchRowOrCol = bRowMode ? u"</tr>"_ustr : u"<col "_ustr;
|
|
while((nIdx = aExpand.indexOf(sSearchRowOrCol, nIdx)) > -1)
|
|
{
|
|
// skip rows/columns of nested tables, based on HTML indentation
|
|
if ( lcl_getLevel(aExpand, nIdx) == nTableLevel + (bShifted ? 2 : 1) &&
|
|
// skip also strange hidden empty rows <tr></tr>
|
|
!aExpand.match("<tr></tr>", nIdx - 4) )
|
|
{
|
|
++nSelectedRowsOrCols;
|
|
}
|
|
++nIdx;
|
|
}
|
|
// are we at the beginning of the cell?
|
|
bool bStartTableBoxNode =
|
|
// first paragraph of the cell?
|
|
rSh.GetCursor()->GetPointNode().GetIndex() == rSh.GetCursor()->GetPointNode().FindTableBoxStartNode()->GetIndex()+1 &&
|
|
// beginning of the paragraph?
|
|
!rSh.GetCursor()->GetPoint()->GetContentIndex();
|
|
SfxDispatcher* pDispatch = rSh.GetView().GetViewFrame().GetDispatcher();
|
|
|
|
// go start of the cell
|
|
if (!bStartTableBoxNode)
|
|
pDispatch->Execute(FN_START_OF_DOCUMENT, SfxCallMode::SYNCHRON);
|
|
|
|
// store cursor position in row mode
|
|
::sw::mark::MarkBase* pMark = (!bRowMode || nSelectedRowsOrCols == 0) ? nullptr : rSh.SetBookmark(
|
|
vcl::KeyCode(),
|
|
OUString(),
|
|
IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
|
|
|
|
// add a new empty row/column before the actual table row/column and go there
|
|
const sal_uInt16 nDispatchSlot = bRowMode ? FN_TABLE_INSERT_ROW_BEFORE : FN_TABLE_INSERT_COL_BEFORE;
|
|
pDispatch->Execute(nDispatchSlot, SfxCallMode::SYNCHRON);
|
|
pDispatch->Execute(bRowMode ? FN_LINE_UP : FN_CHAR_LEFT, SfxCallMode::SYNCHRON);
|
|
|
|
// add the other new empty rows/columns after the actual table row/column
|
|
if ( nSelectedRowsOrCols > 1 )
|
|
{
|
|
SfxInt16Item aCountItem( nDispatchSlot, nSelectedRowsOrCols-1 );
|
|
SfxBoolItem aAfter( FN_PARAM_INSERT_AFTER, true );
|
|
pDispatch->ExecuteList(nDispatchSlot,
|
|
SfxCallMode::SYNCHRON|SfxCallMode::RECORD,
|
|
{ &aCountItem, &aAfter });
|
|
}
|
|
|
|
// paste rows
|
|
bool bResult = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
|
|
nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext );
|
|
|
|
// restore cursor position
|
|
if (pMark != nullptr)
|
|
{
|
|
rSh.GotoMark( pMark );
|
|
rSh.getIDocumentMarkAccess()->deleteMark( pMark );
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
}
|
|
|
|
// special case for tables from draw application or 1-cell tables
|
|
if( EXCHG_OUT_ACTION_INSERT_DRAWOBJ == nAction || bSingleCellTable )
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
// Tweak the format if necessary: the source application can be considered in this context,
|
|
// while not in sot/ code.
|
|
SwTransferable::SelectPasteFormat(rData, nAction, nFormat);
|
|
|
|
collectUIInformation(u"PASTE"_ustr, u"parameter"_ustr);
|
|
|
|
return EXCHG_INOUT_ACTION_NONE != nAction &&
|
|
SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
|
|
nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, ePasteTable);
|
|
}
|
|
|
|
bool SwTransferable::PasteData( const TransferableDataHelper& rData,
|
|
SwWrtShell& rSh, sal_uInt8 nAction, SotExchangeActionFlags nActionFlags,
|
|
SotClipboardFormatId nFormat,
|
|
SotExchangeDest nDestination, bool bIsPasteFormat,
|
|
[[maybe_unused]] bool bIsDefault,
|
|
const Point* pPt, sal_Int8 nDropAction,
|
|
bool bPasteSelection, RndStdIds nAnchorType,
|
|
bool bIgnoreComments,
|
|
SwPasteContext* pContext,
|
|
PasteTableType ePasteTable )
|
|
{
|
|
SwWait aWait( *rSh.GetView().GetDocShell(), false );
|
|
std::unique_ptr<SwTrnsfrActionAndUndo, o3tl::default_delete<SwTrnsfrActionAndUndo>> pAction;
|
|
SwModule* pMod = SwModule::get();
|
|
|
|
bool bRet = false;
|
|
bool bCallAutoCaption = false;
|
|
|
|
if( pPt )
|
|
{
|
|
// external Drop
|
|
if ((bPasteSelection ? !pMod->m_pXSelection : !pMod->m_pDragDrop) &&
|
|
// The following condition is used for tdf#156111 to prevent a selection from being
|
|
// cleared by the default case of the nDestination switch.
|
|
!(rSh.GetCursorCnt() == 1 && rSh.TestCurrPam(*pPt) &&
|
|
nDestination == SotExchangeDest::SWDOC_FREE_AREA &&
|
|
nFormat == SotClipboardFormatId::SONLK))
|
|
{
|
|
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:
|
|
bool bLockView = rSh.IsViewLocked();
|
|
if (nFormat == SotClipboardFormatId::SONLK)
|
|
rSh.LockView(true); // prevent view jump
|
|
SwTransferable::SetSelInShell( rSh, false, pPt );
|
|
rSh.LockView(bLockView);
|
|
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, pContext));
|
|
}
|
|
|
|
SwTransferable *pTrans=nullptr, *pTunneledTrans=GetSwTransferable( rData );
|
|
|
|
// check for private drop
|
|
bool bPrivateDrop(pPt);
|
|
if (bPrivateDrop)
|
|
{
|
|
if (bPasteSelection)
|
|
pTrans = pMod->m_pXSelection;
|
|
else
|
|
pTrans = pMod->m_pDragDrop;
|
|
bPrivateDrop = nullptr != pTrans;
|
|
}
|
|
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(dynamic_cast< const SwDrawFrameFormat* >(pSwFrameFormat))
|
|
{
|
|
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, pContext, ePasteTable);
|
|
}
|
|
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, bIgnoreComments );
|
|
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, rSh.GetSelText()))
|
|
{
|
|
aWait.~SwWait(); // end the wait pointer, X11 only annoyance
|
|
rSh.NavigatorPaste(aBkmk);
|
|
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;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
bool CanSkipInvalidateNumRules(const SwPosition& rInsertPosition)
|
|
{
|
|
SwTextNode* pTextNode = rInsertPosition.GetNode().GetTextNode();
|
|
if (!pTextNode)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const SwNodeNum* pNum = pTextNode->GetNum();
|
|
if (pNum)
|
|
{
|
|
SwNumRule* pNumRule = pNum->GetNumRule();
|
|
if (pNumRule)
|
|
{
|
|
const SvxNumberType rType = pNumRule->Get(pTextNode->GetActualListLevel());
|
|
if (rType.GetNumberingType() == SVX_NUM_CHAR_SPECIAL)
|
|
{
|
|
// Bullet list, skip invalidation.
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Numbered list, invalidate.
|
|
return false;
|
|
}
|
|
|
|
// Not a list, skip invalidation.
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool SwTransferable::PasteFileContent( const TransferableDataHelper& rData,
|
|
SwWrtShell& rSh, SotClipboardFormatId nFormat, bool bMsg, bool bIgnoreComments )
|
|
{
|
|
TranslateId pResId = STR_CLPBRD_FORMAT_ERROR;
|
|
bool bRet = false;
|
|
|
|
MSE40HTMLClipFormatObj aMSE40ClpObj;
|
|
|
|
std::unique_ptr<SvStream> xStrm;
|
|
SvStream* pStream = nullptr;
|
|
Reader* pRead = nullptr;
|
|
OUString sData;
|
|
bool bSkipInvalidateNumRules = false;
|
|
switch( nFormat )
|
|
{
|
|
case SotClipboardFormatId::STRING:
|
|
{
|
|
pRead = ReadAscii;
|
|
|
|
const SwPosition& rInsertPosition = *rSh.GetCursor()->Start();
|
|
if (CanSkipInvalidateNumRules(rInsertPosition))
|
|
{
|
|
// Insertion point is not a numbering and we paste plain text: then no need to
|
|
// invalidate all numberings.
|
|
bSkipInvalidateNumRules = true;
|
|
}
|
|
|
|
if( rData.GetString( nFormat, sData ) )
|
|
{
|
|
pStream = new SvMemoryStream( const_cast<sal_Unicode *>(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;
|
|
}
|
|
}
|
|
[[fallthrough]]; // because then test if we get a stream
|
|
|
|
default:
|
|
if( (xStrm = rData.GetSotStorageStream( nFormat )) )
|
|
{
|
|
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<LinkParamNone*,void> aOldLink( rSh.GetChgLnk() );
|
|
rSh.SetChgLnk( Link<LinkParamNone*,void>() );
|
|
|
|
const SwPosition& rInsPos = *rSh.GetCursor()->Start();
|
|
SwReader aReader(*pStream, OUString(), OUString(), *rSh.GetCursor());
|
|
rSh.SaveTableBoxContent( &rInsPos );
|
|
|
|
if (bIgnoreComments)
|
|
pRead->SetIgnoreHTMLComments(true);
|
|
if (bSkipInvalidateNumRules)
|
|
{
|
|
aReader.SetSkipInvalidateNumRules(bSkipInvalidateNumRules);
|
|
}
|
|
|
|
if( aReader.Read( *pRead ).IsError() )
|
|
pResId = STR_ERROR_CLPBRD_READ;
|
|
else
|
|
{
|
|
pResId = TranslateId();
|
|
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 )
|
|
delete pStream;
|
|
|
|
if (bMsg && pResId)
|
|
{
|
|
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
|
|
VclMessageType::Info, VclButtonsType::Ok,
|
|
SwResId(pResId)));
|
|
xBox->run();
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
bool SwTransferable::PasteOLE( const 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
|
|
{
|
|
xStore->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, OUString(), rPAM);
|
|
aReader.SetInPaste(true);
|
|
if( ! aReader.Read( *pRead ).IsError() )
|
|
bRet = true;
|
|
else if( bMsg )
|
|
{
|
|
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
|
|
VclMessageType::Info, VclButtonsType::Ok,
|
|
SwResId(STR_ERROR_CLPBRD_READ)));
|
|
xBox->run();
|
|
}
|
|
}
|
|
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,
|
|
u"DummyName"_ustr,
|
|
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&)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
else if (rData.HasFormat(SotClipboardFormatId::SIMPLE_FILE))
|
|
{
|
|
OUString sFile;
|
|
if (rData.GetString(nFormat, sFile) && !sFile.isEmpty())
|
|
{
|
|
// Copied from sd::View::DropInsertFileHdl
|
|
uno::Sequence< beans::PropertyValue > aMedium{ comphelper::makePropertyValue(
|
|
u"URL"_ustr, sFile) };
|
|
SwDocShell* pDocSh = rSh.GetDoc()->GetDocShell();
|
|
xObj = pDocSh->GetEmbeddedObjectContainer().InsertEmbeddedObject(aMedium, aName);
|
|
}
|
|
}
|
|
}
|
|
|
|
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( const 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 makes sense to test graphics !!!
|
|
Graphic aGraphic;
|
|
GraphicFilter &rFlt = GraphicFilter::GetGraphicFilter();
|
|
bRet = ERRCODE_NONE == GraphicFilter::LoadGraphic(sURL, OUString(), aGraphic, &rFlt);
|
|
|
|
if( bRet )
|
|
{
|
|
//Check and Perform rotation if needed
|
|
lclCheckAndPerformRotation(aGraphic);
|
|
|
|
switch( nAction )
|
|
{
|
|
case SwPasteSdr::Insert:
|
|
SwTransferable::SetSelInShell( rSh, false, pPt );
|
|
rSh.InsertGraphic(sURL, OUString(), 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, OUString(), &aGraphic);
|
|
break;
|
|
|
|
case SwPasteSdr::SetAttr:
|
|
if( rSh.IsObjSelected() )
|
|
rSh.Paste( aGraphic, OUString() );
|
|
else if( OBJCNT_GRF == rSh.GetObjCntTypeOfSelection() )
|
|
rSh.ReRead(sURL, OUString(), &aGraphic);
|
|
else
|
|
{
|
|
SwTransferable::SetSelInShell( rSh, false, pPt );
|
|
rSh.InsertGraphic(sURL, OUString(), aGraphic);
|
|
}
|
|
break;
|
|
default:
|
|
bRet = false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
bRet = true;
|
|
}
|
|
|
|
if( bRet )
|
|
{
|
|
SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
|
|
rSh.GetFlyFrameAttr( aSet );
|
|
SwFormatURL aURL( 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( const TransferableDataHelper& rData,
|
|
SwWrtShell& rWrtShell, bool bReReadGrf,
|
|
bool bMsg )
|
|
{
|
|
// data from Clipboardformat
|
|
OUString aApp, aTopic, aItem;
|
|
|
|
if (!rData.ReadDDELink(aApp, aTopic, aItem, o3tl::temporary(OUString())))
|
|
{
|
|
return false;
|
|
} // report useful error!!
|
|
|
|
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(u"DDE"_ustr);
|
|
if ( bReReadGrf )
|
|
rWrtShell.ReRead( aCmd, sLnkTyp, &aGrf );
|
|
else
|
|
rWrtShell.InsertGraphic( 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 + OUString::number( i );
|
|
for( j = INIT_FLDTYPES; j < nSize; j++ )
|
|
{
|
|
pTyp = rWrtShell.GetFieldType( j );
|
|
if( SwFieldIds::Dde == pTyp->Which() )
|
|
{
|
|
if( rColl.isEqual( static_cast<SwDDEFieldType*>(pTyp)->GetCmd(), aCmd ) &&
|
|
SfxLinkUpdateMode::ALWAYS == static_cast<SwDDEFieldType*>(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<SwDDEFieldType*>(pTyp);
|
|
|
|
OUString aExpand;
|
|
if( rData.GetString( SotClipboardFormatId::STRING, aExpand ))
|
|
{
|
|
do { // middle checked loop
|
|
|
|
const sal_Int32 nNewlines{comphelper::string::getTokenCount(aExpand, '\n')};
|
|
// When data comes from a spreadsheet, we add a DDE-table
|
|
if( !aExpand.isEmpty() &&
|
|
( rData.HasFormat( SotClipboardFormatId::SYLK ) ||
|
|
rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) )
|
|
{
|
|
sal_Int32 nRows = nNewlines ? nNewlines-1 : 0;
|
|
if (!aExpand.endsWith("\n"))
|
|
++nRows; // last row has no newline, e.g. one single cell
|
|
const sal_Int32 nCols = comphelper::string::getTokenCount(o3tl::getToken(aExpand, 0, '\n'), '\t');
|
|
|
|
// don't try to insert tables that are too large for writer
|
|
if (nRows > SAL_MAX_UINT16 || nCols > SAL_MAX_UINT16)
|
|
{
|
|
if( bMsg )
|
|
{
|
|
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
|
|
VclMessageType::Info, VclButtonsType::Ok,
|
|
SwResId(STR_TABLE_TOO_LARGE)));
|
|
xBox->run();
|
|
}
|
|
pDDETyp = nullptr;
|
|
break;
|
|
}
|
|
|
|
// at least one column & row must be there
|
|
if( !nRows || !nCols )
|
|
{
|
|
if( bMsg )
|
|
{
|
|
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
|
|
VclMessageType::Info, VclButtonsType::Ok,
|
|
SwResId(STR_NO_TABLE)));
|
|
xBox->run();
|
|
}
|
|
pDDETyp = nullptr;
|
|
break;
|
|
}
|
|
|
|
rWrtShell.InsertDDETable(
|
|
SwInsertTableOptions( SwInsertTableFlags::SplitLayout, 1 ), // TODO MULTIHEADER
|
|
pDDETyp, nRows, nCols );
|
|
}
|
|
else if( nNewlines > 1 )
|
|
{
|
|
// multiple paragraphs -> insert a protected section
|
|
if( rWrtShell.HasSelection() )
|
|
rWrtShell.DelRight();
|
|
|
|
SwSectionData aSect( SectionType::DdeLink, aName );
|
|
aSect.SetLinkFileName( aCmd );
|
|
aSect.SetProtectFlag(true);
|
|
rWrtShell.InsertSection( aSect );
|
|
|
|
pDDETyp = nullptr; // remove FieldTypes again
|
|
}
|
|
else
|
|
{
|
|
// insert
|
|
SwDDEField aSwDDEField( pDDETyp );
|
|
rWrtShell.InsertField2( 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( const TransferableDataHelper& rData,
|
|
SwWrtShell& rSh, SwPasteSdr nAction,
|
|
const Point* pPt, SotExchangeActionFlags nActionFlags, bool bNeedToSelectBeforePaste)
|
|
{
|
|
bool bRet = false;
|
|
if( std::unique_ptr<SvStream> xStrm = rData.GetSotStorageStream( SotClipboardFormatId::DRAWING ))
|
|
{
|
|
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( const 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:
|
|
{
|
|
if (std::unique_ptr<SvStream> xStm = rData.GetSotStorageStream(SotClipboardFormatId::SVXB))
|
|
{
|
|
TypeSerializer aSerializer(*xStm);
|
|
aSerializer.readGraphic(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 );
|
|
|
|
sText = URIHelper::SmartRel2Abs(INetURLObject(), sText, Link<OUString*, bool>(),
|
|
false);
|
|
|
|
#ifdef _WIN32
|
|
// Now that the path could be modified after SwTransferable::CheckForURLOrLNKFile,
|
|
// where it could have been converted to URL, and made sure it's actually converted
|
|
// to URL in URIHelper::SmartRel2Abs, we can finally convert file: URL back to
|
|
// system path to make sure we don't use short path.
|
|
// It looks not optimal, when we could apply GetLongPathNameW right to the original
|
|
// pasted filename. But I don't know if (1) all arriving strings are system paths;
|
|
// and (2) if SwTransferable::CheckForURLOrLNKFile could result in a different short
|
|
// path, so taking a safe route.
|
|
if (sText.startsWithIgnoreAsciiCase("file:"))
|
|
{
|
|
// tdf#124500: Convert short path to long path which should be used in links
|
|
OUString sSysPath;
|
|
osl::FileBase::getSystemPathFromFileURL(sText, sSysPath);
|
|
std::unique_ptr<sal_Unicode[]> aBuf(new sal_Unicode[32767]);
|
|
DWORD nCopied = GetLongPathNameW(o3tl::toW(sSysPath.getStr()),
|
|
o3tl::toW(aBuf.get()), 32767);
|
|
if (nCopied && nCopied < 32767)
|
|
sText = URIHelper::SmartRel2Abs(INetURLObject(), OUString(aBuf.get()),
|
|
Link<OUString*, bool>(), false);
|
|
}
|
|
#endif
|
|
|
|
aBkmk = INetBookmark(sText, 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(), OUString(),
|
|
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.InsertGraphic(sURL, OUString(), 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, OUString(), &aGraphic);
|
|
// Point aPt( pPt ? *pPt : rSh.GetCursorDocPos() );
|
|
// SwTransferable::SetSelInShell( rSh, true, &aPt );
|
|
}
|
|
else
|
|
{
|
|
// set graphic at writer graphic without link
|
|
rSh.ReRead(sURL, OUString(), &aGraphic);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SwPasteSdr::SetAttr:
|
|
{
|
|
if( SotClipboardFormatId::NETSCAPE_BOOKMARK == nFormat )
|
|
{
|
|
if( rSh.IsFrameSelected() )
|
|
{
|
|
SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
|
|
rSh.GetFlyFrameAttr( aSet );
|
|
SwFormatURL aURL( 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, OUString(), &aGraphic);
|
|
}
|
|
else
|
|
{
|
|
SwTransferable::SetSelInShell( rSh, false, pPt );
|
|
rSh.InsertGraphic(aBkmk.GetURL(), OUString(), 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, IMapFormat::Detect ) == IMAP_ERR_OK &&
|
|
aMap.GetIMapObjectCount() )
|
|
{
|
|
SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
|
|
rSh.GetFlyFrameAttr( aSet );
|
|
SwFormatURL aURL( aSet.Get( RES_URL ) );
|
|
aURL.SetMap( &aMap );
|
|
aSet.Put( aURL );
|
|
rSh.SetFlyFrameAttr( aSet );
|
|
bRet = true;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
bool SwTransferable::PasteImageMap( const TransferableDataHelper& rData,
|
|
SwWrtShell& rSh )
|
|
{
|
|
bool bRet = false;
|
|
if( rData.HasFormat( SotClipboardFormatId::SVIM ))
|
|
{
|
|
SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
|
|
rSh.GetFlyFrameAttr( aSet );
|
|
SwFormatURL aURL( 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( const 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:
|
|
{
|
|
SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
|
|
rSh.GetFlyFrameAttr( aSet );
|
|
SwFormatURL aURL2( 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( const 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, u""_ustr/*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<OUString *, bool>(), false );
|
|
std::shared_ptr<const SfxFilter> 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
|
|
SwSectionData aSect(
|
|
SectionType::FileLink,
|
|
rSh.GetDoc()->GetUniqueSectionName() );
|
|
aSect.SetLinkFileName( sFileURL );
|
|
aSect.SetProtectFlag( true );
|
|
|
|
rSh.StartInsertRegionDialog( aSect ); // starts dialog asynchronously
|
|
bRet = true;
|
|
}
|
|
else if (SwPasteSdr::Insert == nAction && rData.HasFormat(SotClipboardFormatId::SIMPLE_FILE))
|
|
{
|
|
// insert file as OLE
|
|
PasteOLE(rData, rSh, nFormat, nActionFlags, nullptr == pPt);
|
|
}
|
|
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:
|
|
{
|
|
SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
|
|
rSh.GetFlyFrameAttr( aSet );
|
|
SwFormatURL aURL2( 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( const 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<FmFormView*>( rSh.GetDrawView() );
|
|
if (pFmView && pDragPt)
|
|
{
|
|
OXFormsDescriptor aDesc = OXFormsTransferable::extractDescriptor(rData);
|
|
rtl::Reference<SdrObject> pObj = pFmView->CreateXFormsControl(aDesc);
|
|
if(pObj)
|
|
{
|
|
rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt );
|
|
}
|
|
}
|
|
}
|
|
else if( nWh )
|
|
{
|
|
std::unique_ptr<SfxUnoAnyItem> pConnectionItem;
|
|
std::unique_ptr<SfxUnoAnyItem> pCursorItem;
|
|
std::unique_ptr<SfxUnoAnyItem> pColumnItem;
|
|
std::unique_ptr<SfxUnoAnyItem> pSourceItem;
|
|
std::unique_ptr<SfxUnoAnyItem> pCommandItem;
|
|
std::unique_ptr<SfxUnoAnyItem> pCommandTypeItem;
|
|
std::unique_ptr<SfxUnoAnyItem> pColumnNameItem;
|
|
std::unique_ptr<SfxUnoAnyItem> 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 SfxUnoAnyItem(FN_DB_CONNECTION_ANY, aDesc[DataAccessDescriptorProperty::Connection]));
|
|
pColumnItem.reset(new SfxUnoAnyItem(FN_DB_COLUMN_ANY, aDesc[DataAccessDescriptorProperty::ColumnObject]));
|
|
pSourceItem.reset(new SfxUnoAnyItem(FN_DB_DATA_SOURCE_ANY, Any(aDesc.getDataSource())));
|
|
pCommandItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COMMAND_ANY, aDesc[DataAccessDescriptorProperty::Command]));
|
|
pCommandTypeItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COMMAND_TYPE_ANY, aDesc[DataAccessDescriptorProperty::CommandType]));
|
|
pColumnNameItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COLUMN_NAME_ANY, aDesc[DataAccessDescriptorProperty::ColumnName]));
|
|
pSelectionItem.reset(new SfxUnoAnyItem(FN_DB_DATA_SELECTION_ANY, aDesc[DataAccessDescriptorProperty::Selection]));
|
|
pCursorItem.reset(new SfxUnoAnyItem(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<FmFormView*>( rSh.GetDrawView() );
|
|
if (pFmView && bHaveColumnDescriptor && pDragPt)
|
|
{
|
|
rtl::Reference<SdrObject> pObj = pFmView->CreateFieldControl( OColumnTransferable::extractColumnDescriptor(rData) );
|
|
if (pObj)
|
|
rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt );
|
|
}
|
|
}
|
|
bRet = true;
|
|
}
|
|
else if( bMsg )
|
|
{
|
|
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
|
|
VclMessageType::Info, VclButtonsType::Ok,
|
|
SwResId(STR_CLPBRD_FORMAT_ERROR)));
|
|
xBox->run();
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
bool SwTransferable::PasteFileList( const 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 )
|
|
{
|
|
rtl::Reference<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 )
|
|
{
|
|
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
|
|
VclMessageType::Info, VclButtonsType::Ok,
|
|
SwResId(STR_CLPBRD_FORMAT_ERROR)));
|
|
xBox->run();
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
bool SwTransferable::CheckForURLOrLNKFile( const 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
|
|
{
|
|
if( rFileName.getLength()>4 && rFileName.endsWithIgnoreAsciiCase(".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(TypedWhichId<SvxClipboardFormatItem>(0));
|
|
FillClipFormatItem( rWrtShell, rData, aClipboardFormatItem);
|
|
return aClipboardFormatItem.Count() > 0;
|
|
}
|
|
|
|
bool SwTransferable::IsPasteOwnFormat( const TransferableDataHelper& rData )
|
|
{
|
|
return ( GetSwTransferable( rData ) != nullptr );
|
|
}
|
|
|
|
bool SwTransferable::PasteFormat( SwWrtShell& rSh,
|
|
const 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> 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;
|
|
if( rData.HasFormat( nFormat )) {
|
|
uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
|
|
sal_uInt8 nEventAction;
|
|
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 );
|
|
}
|
|
|
|
void SwTransferable::PrePasteSpecial( const SwWrtShell& rSh, const TransferableDataHelper& rData, const VclPtr<SfxAbstractPasteDialog>& pDlg )
|
|
{
|
|
DataFlavorExVector aFormats( rData.GetDataFlavorExVector() );
|
|
TransferableObjectDescriptor aDesc;
|
|
|
|
SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh );
|
|
|
|
SwTransferable *pClipboard = GetSwTransferable( rData );
|
|
if( pClipboard )
|
|
{
|
|
aDesc = pClipboard->m_aObjDesc;
|
|
TranslateId 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;
|
|
|
|
if (pResId)
|
|
{
|
|
if (STR_PRIVATEOLE == pResId || STR_PRIVATEGRAPHIC == pResId)
|
|
{
|
|
// 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, OUString() );
|
|
}
|
|
}
|
|
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, OUString() );
|
|
if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK_SOURCE, nDest ))
|
|
pDlg->Insert( SotClipboardFormatId::LINK_SOURCE, OUString() );
|
|
}
|
|
|
|
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, OUString() );
|
|
}
|
|
|
|
void SwTransferable::FillClipFormatItem( const SwWrtShell& rSh,
|
|
const TransferableDataHelper& rData,
|
|
SvxClipboardFormatItem & rToFill )
|
|
{
|
|
SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh );
|
|
|
|
SwTransferable *pClipboard = GetSwTransferable( rData );
|
|
if( pClipboard )
|
|
{
|
|
TranslateId 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;
|
|
|
|
if (pResId)
|
|
rToFill.AddClipbrdFormat(SotClipboardFormatId::EMBED_SOURCE,
|
|
SwResId(pResId));
|
|
}
|
|
else
|
|
{
|
|
TransferableObjectDescriptor aDesc;
|
|
if (rData.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
|
|
{
|
|
(void)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, OUString());
|
|
}
|
|
|
|
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;
|
|
|
|
// is it a 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 = constOleSize100mm;
|
|
|
|
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() )
|
|
return;
|
|
|
|
SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
|
|
m_pWrtShell->GetFlyFrameAttr( aSet );
|
|
const SwFormatURL& rURL = 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();
|
|
|
|
SwModule::get()->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, SwPasteContext* pContext, PasteTableType ePasteTable)
|
|
{
|
|
// 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))
|
|
{
|
|
if (!(nSelection & SelectionType::NumberList))
|
|
{
|
|
bKillPaMs = true;
|
|
rShell.SetRetainSelection( true );
|
|
}
|
|
if (pContext)
|
|
pContext->forget();
|
|
rShell.DelRight();
|
|
if (pContext)
|
|
pContext->remember();
|
|
// 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 );
|
|
}
|
|
if (!(nSelection & SelectionType::NumberList))
|
|
{
|
|
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 (!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(), ePasteTable == PasteTableType::PASTE_TABLE);
|
|
|
|
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 bTableMove = 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_oBookmark )
|
|
aTmp = *m_oBookmark;
|
|
|
|
// 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 )
|
|
{
|
|
SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
|
|
rSh.GetFlyFrameAttr( aSet );
|
|
SwFormatURL aURL( 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;
|
|
const SelectionType nSelection = rSrcSh.GetSelectionType();
|
|
// at enhanced table row/column selection or wholly selected tables,
|
|
// paste rows above or columns before, and in the case of moving, remove the selection
|
|
// (limit only to the single document case temporarily)
|
|
if( rSrcSh.GetDoc() == rSh.GetDoc() &&
|
|
( (( SelectionType::TableRow | SelectionType::TableCol) & nSelection ) || rSrcSh.HasWholeTabSelection() ) )
|
|
{
|
|
bool bTableCol(SelectionType::TableCol & nSelection);
|
|
|
|
::sw::mark::MarkBase* pMarkMoveFrom = bMove
|
|
? rSh.SetBookmark(
|
|
vcl::KeyCode(),
|
|
OUString(),
|
|
IDocumentMarkAccess::MarkType::UNO_BOOKMARK )
|
|
: nullptr;
|
|
|
|
// row count and direction of the table selection:
|
|
// up to down, if the cursor is there in its last table row
|
|
const SwSelBoxes& rBoxes = rSrcSh.GetTableCursor()->GetSelectedBoxes();
|
|
const SwTableNode* pTableNd = rSh.IsCursorInTable();
|
|
if (!pTableNd)
|
|
{
|
|
SAL_WARN("sw", "presumably this case can't arise in practice");
|
|
return false;
|
|
}
|
|
const SwTableLines& rLines = pTableNd->GetTable().GetTabLines();
|
|
const SwStartNode& rDelPos = rBoxes.back()
|
|
? *rBoxes.front()->GetSttNd()
|
|
: *pTableNd->GetStartNode();
|
|
|
|
// count selected rows or columns
|
|
sal_Int32 nSelRowOrCols = 0;
|
|
if ( rBoxes.back() )
|
|
{
|
|
if ( bTableCol )
|
|
{
|
|
// selected column count is the count of the cells
|
|
// in the first row of the selection
|
|
auto nLine = rLines.GetPos( rBoxes.front()->GetUpper() );
|
|
for (auto pBox : rBoxes)
|
|
{
|
|
// cell is in the next row
|
|
if ( nLine != rLines.GetPos( pBox->GetUpper() ) )
|
|
break;
|
|
++nSelRowOrCols;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// selected row count is the difference of the row number of the
|
|
// first and the last cell of the selection
|
|
nSelRowOrCols = rLines.GetPos( rBoxes.back()->GetUpper() ) -
|
|
rLines.GetPos( rBoxes.front()->GetUpper() ) + 1;
|
|
}
|
|
}
|
|
|
|
bool bSelUpToDown = rBoxes.back() && rBoxes.back()->GetUpper() ==
|
|
rSh.GetCursor()->GetPointNode().GetTableBox()->GetUpper();
|
|
|
|
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();
|
|
|
|
SfxDispatcher* pDispatch = rSrcSh.GetView().GetViewFrame().GetDispatcher();
|
|
pDispatch->Execute(SID_COPY, SfxCallMode::SYNCHRON);
|
|
|
|
rSrcSh.Push(); // save selection for later restoration
|
|
rSh.EnterStdMode();
|
|
rSh.SwCursorShell::SetCursor(rDragPt, false);
|
|
|
|
bool bPasteIntoTable = rSh.GetCursor()->GetPointNode().GetTableBox() != nullptr;
|
|
|
|
// store cursor
|
|
::sw::mark::MarkBase* pMark = rSh.SetBookmark(
|
|
vcl::KeyCode(),
|
|
OUString(),
|
|
IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
|
|
|
|
// paste rows above/columns before
|
|
pDispatch->Execute(bTableCol ? FN_TABLE_PASTE_COL_BEFORE : FN_TABLE_PASTE_ROW_BEFORE, SfxCallMode::SYNCHRON);
|
|
|
|
// go to the previously inserted table rows and set them to tracked insertion, if needed
|
|
bool bNeedTrack = !bTableCol && rSh.getIDocumentRedlineAccess().IsRedlineOn();
|
|
|
|
// restore cursor position
|
|
if (bNeedTrack && pMark != nullptr)
|
|
rSh.GotoMark( pMark );
|
|
|
|
if ( !bNeedTrack && !bPasteIntoTable )
|
|
{
|
|
rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // restore selection...
|
|
|
|
// delete source rows/columns
|
|
if (bMove)
|
|
pDispatch->Execute(bTableCol
|
|
? FN_TABLE_DELETE_COL
|
|
: FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
|
|
}
|
|
else
|
|
{
|
|
const SwTableBox* pBoxStt = rSh.GetCursor()->GetPointNode().GetTableBox();
|
|
SwTableLine* pLine = pBoxStt ? const_cast<SwTableLine*>( pBoxStt->GetUpper()): nullptr;
|
|
|
|
for (sal_Int32 nDeleted = 0; bNeedTrack && nDeleted < nSelRowOrCols;)
|
|
{
|
|
// move up text cursor (note: "true" is important for the layout level)
|
|
if ( !rSh.Up(false) )
|
|
break;
|
|
|
|
const SwTableBox* pBox = rSh.GetCursor()->GetPointNode().GetTableBox();
|
|
|
|
if ( !pBox )
|
|
break;
|
|
|
|
// Up() reaches a new row
|
|
if ( pBox->GetUpper() != pLine )
|
|
{
|
|
//rSh.SelTableRow();
|
|
SvxPrintItem aTracked(RES_PRINT, false);
|
|
rSh.GetDoc()->SetRowNotTracked( *rSh.GetCursor(), aTracked );
|
|
++nDeleted;
|
|
pLine = const_cast<SwTableLine*>(pBox->GetUpper());
|
|
}
|
|
}
|
|
|
|
rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // restore selection...
|
|
|
|
// delete source rows/columns
|
|
if (bMove)
|
|
{
|
|
// restore cursor position
|
|
if (pMarkMoveFrom != nullptr)
|
|
{
|
|
rSh.GotoMark( pMarkMoveFrom );
|
|
rSh.getIDocumentMarkAccess()->deleteMark( pMarkMoveFrom );
|
|
}
|
|
|
|
// tracked table row moving: set original rows as tracked deletion,
|
|
// otherwise delete original rows/columns (tracking column deletion
|
|
// and insertion is not supported yet)
|
|
if ( !bTableCol && bNeedTrack )
|
|
{
|
|
pLine = nullptr;
|
|
|
|
for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols;)
|
|
{
|
|
const SwTableBox* pBox = rSh.GetCursor()->GetPointNode().GetTableBox();
|
|
|
|
if ( !pBox )
|
|
break;
|
|
|
|
if ( pBox->GetUpper() != pLine )
|
|
{
|
|
pLine = const_cast<SwTableLine*>(pBox->GetUpper());
|
|
pDispatch->Execute(FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
|
|
++nDeleted;
|
|
}
|
|
|
|
bool bMoved = false;
|
|
if (bSelUpToDown)
|
|
bMoved = rSh.Up(false);
|
|
else
|
|
bMoved = rSh.Down(false);
|
|
if (!bMoved)
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// set cursor in the first cell of the original selection
|
|
rSh.GetCursor()->DeleteMark();
|
|
rSh.GetCursor()->GetPoint()->Assign( rDelPos.GetIndex() + 1);
|
|
|
|
for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols; ++nDeleted)
|
|
{
|
|
pDispatch->Execute(bTableCol
|
|
? FN_TABLE_DELETE_COL
|
|
: FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// restore cursor position
|
|
if (pMark != nullptr)
|
|
{
|
|
rSh.GotoMark( pMark );
|
|
rSh.getIDocumentMarkAccess()->deleteMark( pMark );
|
|
}
|
|
|
|
rSh.DestroyCursor();
|
|
rSh.EndUndo();
|
|
rSh.EndAction();
|
|
rSh.EndAction();
|
|
return true;
|
|
}
|
|
|
|
if ( bMove && rSrcSh.HasWholeTabSelection() )
|
|
bTableMove = 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 InetFields!
|
|
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 a 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 = 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(false);
|
|
}
|
|
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.GetCursor()->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();
|
|
}
|
|
}
|
|
}
|
|
else if ( bRet && bTableMove )
|
|
{
|
|
SfxDispatcher* pDispatch = rSrcSh.GetView().GetViewFrame().GetDispatcher();
|
|
pDispatch->Execute(FN_TABLE_DELETE_TABLE, SfxCallMode::SYNCHRON);
|
|
}
|
|
|
|
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 )
|
|
{
|
|
rtl::Reference<SwTransferable> pNew = new SwTransferable( rSh );
|
|
|
|
pNew->m_pCreatorView = _pCreatorView;
|
|
|
|
SwModule::get()->m_pXSelection = pNew.get();
|
|
pNew->CopyToPrimarySelection();
|
|
}
|
|
|
|
void SwTransferable::ClearSelection( const SwWrtShell& rSh,
|
|
const SwFrameShell * _pCreatorView)
|
|
{
|
|
SwModule* pMod = SwModule::get();
|
|
if( pMod->m_pXSelection &&
|
|
((!pMod->m_pXSelection->m_pWrtShell) || (pMod->m_pXSelection->m_pWrtShell == &rSh)) &&
|
|
(!_pCreatorView || (pMod->m_pXSelection->m_pCreatorView == _pCreatorView)) )
|
|
{
|
|
TransferableHelper::ClearPrimarySelection();
|
|
}
|
|
}
|
|
|
|
SwTransferable* SwTransferable::GetSwTransferable( const TransferableDataHelper& rData )
|
|
{
|
|
return dynamic_cast<SwTransferable*>(rData.GetTransferable().get());
|
|
}
|
|
|
|
SwTransferDdeLink::SwTransferDdeLink( SwTransferable& rTrans, SwWrtShell& rSh )
|
|
: m_rTransfer(rTrans)
|
|
, m_pDocShell(nullptr)
|
|
, m_nOldTimeOut(0)
|
|
, m_bDelBookmark(false)
|
|
, m_bInDisconnect(false)
|
|
{
|
|
// we only end up here with table- or text selection
|
|
if( SelectionType::TableCell & rSh.GetSelectionType() )
|
|
{
|
|
SwFrameFormat* pFormat = rSh.GetTableFormat();
|
|
if( pFormat )
|
|
m_sName = pFormat->GetName();
|
|
}
|
|
else
|
|
{
|
|
// creating a temp. bookmark without undo
|
|
bool bUndo = rSh.DoesUndo();
|
|
rSh.DoUndo( false );
|
|
bool bIsModified = rSh.IsModified();
|
|
|
|
::sw::mark::MarkBase* pMark = rSh.SetBookmark(
|
|
vcl::KeyCode(),
|
|
OUString(),
|
|
IDocumentMarkAccess::MarkType::DDE_BOOKMARK);
|
|
if(pMark)
|
|
{
|
|
m_sName = pMark->GetName();
|
|
m_bDelBookmark = true;
|
|
if( !bIsModified )
|
|
rSh.ResetModified();
|
|
}
|
|
else
|
|
m_sName.clear();
|
|
rSh.DoUndo( bUndo );
|
|
}
|
|
|
|
if( m_sName.isEmpty() ||
|
|
nullptr == ( m_pDocShell = rSh.GetDoc()->GetDocShell() ))
|
|
return;
|
|
|
|
// then we create our "server" and connect to it
|
|
m_xRefObj = m_pDocShell->DdeCreateLinkSource( m_sName );
|
|
if( m_xRefObj.is() )
|
|
{
|
|
m_xRefObj->AddConnectAdvise( this );
|
|
m_xRefObj->AddDataAdvise( this,
|
|
OUString(),
|
|
ADVISEMODE_NODATA | ADVISEMODE_ONLYONCE );
|
|
m_nOldTimeOut = m_xRefObj->GetUpdateTimeout();
|
|
m_xRefObj->SetUpdateTimeout( 0 );
|
|
}
|
|
}
|
|
|
|
SwTransferDdeLink::~SwTransferDdeLink()
|
|
{
|
|
if( m_xRefObj.is() )
|
|
Disconnect( true );
|
|
}
|
|
|
|
::sfx2::SvBaseLink::UpdateResult SwTransferDdeLink::DataChanged( const OUString& ,
|
|
const uno::Any& )
|
|
{
|
|
// well, that's it with the link
|
|
if( !m_bInDisconnect )
|
|
{
|
|
if( FindDocShell() && m_pDocShell->GetView() )
|
|
m_rTransfer.RemoveDDELinkFormat( m_pDocShell->GetView()->GetEditWin() );
|
|
Disconnect( false );
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
bool SwTransferDdeLink::WriteData( SvStream& rStrm )
|
|
{
|
|
if( !m_xRefObj.is() || !FindDocShell() )
|
|
return false;
|
|
|
|
TransferableDataHelper::WriteDDELink(rStrm, Application::GetAppName(),
|
|
m_pDocShell->GetTitle(SFX_TITLE_FULLNAME), m_sName);
|
|
|
|
IDocumentMarkAccess* const pMarkAccess = m_pDocShell->GetDoc()->getIDocumentMarkAccess();
|
|
auto ppMark = pMarkAccess->findMark(m_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::MarkBase* const pMark = *ppMark;
|
|
::sfx2::SvLinkSource* p = m_xRefObj.get();
|
|
SwServerObject& rServerObject = dynamic_cast<SwServerObject&>(*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, false);
|
|
|
|
// recreate as Bookmark
|
|
::sw::mark::MarkBase* const pNewMark = pMarkAccess->makeMark(
|
|
aPaM,
|
|
sMarkName,
|
|
IDocumentMarkAccess::MarkType::BOOKMARK,
|
|
::sw::mark::InsertMode::New);
|
|
rServerObject.SetDdeBookmark(*pNewMark);
|
|
}
|
|
|
|
m_bDelBookmark = false;
|
|
return true;
|
|
}
|
|
|
|
void SwTransferDdeLink::Disconnect( bool bRemoveDataAdvise )
|
|
{
|
|
// don't accept DataChanged anymore, when already in Disconnect!
|
|
// (DTOR from Bookmark sends a DataChanged!)
|
|
bool bOldDisconnect = m_bInDisconnect;
|
|
m_bInDisconnect = true;
|
|
|
|
// destroy the unused bookmark again (without Undo!)?
|
|
if( m_bDelBookmark && m_xRefObj.is() && FindDocShell() )
|
|
{
|
|
SwDoc* pDoc = m_pDocShell->GetDoc();
|
|
::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
|
|
|
|
// #i58448#
|
|
Link<bool,void> aSavedOle2Link( pDoc->GetOle2Link() );
|
|
pDoc->SetOle2Link( Link<bool,void>() );
|
|
|
|
bool bIsModified = pDoc->getIDocumentState().IsModified();
|
|
|
|
IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
|
|
pMarkAccess->deleteMark(pMarkAccess->findMark(m_sName), false);
|
|
|
|
if( !bIsModified )
|
|
pDoc->getIDocumentState().ResetModified();
|
|
// #i58448#
|
|
pDoc->SetOle2Link( aSavedOle2Link );
|
|
|
|
m_bDelBookmark = false;
|
|
}
|
|
|
|
if( m_xRefObj.is() )
|
|
{
|
|
m_xRefObj->SetUpdateTimeout( m_nOldTimeOut );
|
|
m_xRefObj->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!
|
|
m_xRefObj->RemoveAllDataAdvise( this );
|
|
m_xRefObj.clear();
|
|
}
|
|
m_bInDisconnect = bOldDisconnect;
|
|
}
|
|
|
|
bool SwTransferDdeLink::FindDocShell()
|
|
{
|
|
SfxObjectShell* pTmpSh = SfxObjectShell::GetFirst( checkSfxObjectShell<SwDocShell> );
|
|
while( pTmpSh )
|
|
{
|
|
if( pTmpSh == m_pDocShell ) // that's what we want to have
|
|
{
|
|
if( m_pDocShell->GetDoc() )
|
|
return true;
|
|
break; // the Doc is not there anymore, so leave!
|
|
}
|
|
pTmpSh = SfxObjectShell::GetNext( *pTmpSh, checkSfxObjectShell<SwDocShell> );
|
|
}
|
|
|
|
m_pDocShell = nullptr;
|
|
return false;
|
|
}
|
|
|
|
void SwTransferDdeLink::Closed()
|
|
{
|
|
if( !m_bInDisconnect && m_xRefObj.is() )
|
|
{
|
|
m_xRefObj->RemoveAllDataAdvise( this );
|
|
m_xRefObj->RemoveConnectAdvise( this );
|
|
m_xRefObj.clear();
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|