/* -*- 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 .
*/
/// Tracks the boundaries of pasted content and notifies listeners. class SwPasteContext
{ public:
SwPasteContext(SwWrtShell& rWrtShell);
~SwPasteContext();
// 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; elseif ( pMod->m_pXSelection == this )
pMod->m_pXSelection = nullptr;
}
void SwTransferable::ObjectReleased()
{
SwModule* pMod = SwModule::get(); if (!pMod) return; if( this == pMod->m_pDragDrop )
pMod->m_pDragDrop = nullptr; elseif( 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() );
}
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, bool bDeleteRedlines = true)
{ const SwDoc &rSrc = *rSrcWrtShell.GetDoc();
//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);
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)
{ returntrue; // Complex
}
}
}
FrameClientSortList_t vFrames;
::CollectFrameAtNode(rNd, vFrames, true); if (!vFrames.empty())
{ // There is an at-char anchored object to this node, that's complex. returntrue;
}
// 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 ) ) returnfalse;
// 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 constbool bPending(m_pWrtShell->ActionPend());
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 );
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;
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 (!)");
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;
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());
//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);
// 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 );
// --> 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);
// 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, bDeleteRedlines);
DeleteDDEAndReminderMarks(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 );
//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;
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 );
//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;
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;
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;
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'.
// 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() );
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(std::u16string_view sText, sal_Int32 nIdx)
{
sal_Int32 nRet = 0; while ( nIdx-- > 0 && sText[nIdx] == '\t' )
{
nRet++;
} return nRet;
}
// 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 );
UIName 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 UIName 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);
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) returnfalse; if (ePasteTable == PasteTableType::PASTE_TABLE)
pDispatch->Execute(FN_PASTE_NESTED_TABLE, SfxCallMode::SYNCHRON); elseif (ePasteTable == PasteTableType::PASTE_ROW)
pDispatch->Execute(FN_TABLE_PASTE_ROW_BEFORE, SfxCallMode::SYNCHRON); elseif (ePasteTable == PasteTableType::PASTE_COLUMN)
pDispatch->Execute(FN_TABLE_PASTE_COL_BEFORE, SfxCallMode::SYNCHRON); else
pDispatch->Execute(SID_PASTE, SfxCallMode::SYNCHRON); returntrue;
} 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 elseif ( (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("
)) > -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(")) == nTableLevel + 1; // calculate count of selected rows or columns
sal_Int32 nSelectedRowsOrCols = 0; const OUString sSearchRowOrCol = bRowMode ? u""_ustr : u"
_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("
", 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(),
SwMarkName(),
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 });
}
// 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;
} elseif( 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);
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;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.