tdf#35361 Add a Quick Look plugins for .od* files on macOS
[LibreOffice.git] / sw / source / uibase / dochdl / swdtflvr.cxx
blob6d4c5df1b84d158458fb9fac3da7b136d75734c6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <com/sun/star/embed/XTransactedObject.hpp>
23 #include <com/sun/star/embed/Aspects.hpp>
24 #include <com/sun/star/embed/XEmbedObjectClipboardCreator.hpp>
25 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
26 #include <com/sun/star/embed/MSOLEObjectSystemCreator.hpp>
27 #include <com/sun/star/text/XPasteListener.hpp>
29 #include <svtools/embedtransfer.hxx>
30 #include <svtools/insdlg.hxx>
31 #include <unotools/tempfile.hxx>
32 #include <comphelper/fileformat.h>
33 #include <comphelper/processfactory.hxx>
34 #include <comphelper/propertyvalue.hxx>
35 #include <comphelper/servicehelper.hxx>
36 #include <comphelper/storagehelper.hxx>
37 #include <comphelper/string.hxx>
38 #include <o3tl/deleter.hxx>
39 #include <o3tl/temporary.hxx>
40 #include <unotools/ucbstreamhelper.hxx>
41 #include <sot/filelist.hxx>
42 #include <svx/svxdlg.hxx>
43 #include <toolkit/helper/vclunohelper.hxx>
44 #include <osl/endian.h>
45 #include <sfx2/linkmgr.hxx>
46 #include <tools/urlobj.hxx>
47 #include <vcl/weld.hxx>
48 #include <sfx2/dispatch.hxx>
49 #include <sfx2/viewfrm.hxx>
50 #include <svl/stritem.hxx>
51 #include <vcl/imap.hxx>
52 #include <sot/storage.hxx>
53 #include <vcl/graph.hxx>
54 #include <svl/urihelper.hxx>
55 #include <svx/svdmodel.hxx>
56 #include <svx/xmlexchg.hxx>
57 #include <svx/dbaexchange.hxx>
58 #include <svx/clipfmtitem.hxx>
59 #include <sfx2/mieclip.hxx>
60 #include <svl/urlbmk.hxx>
61 #include <vcl/inetimg.hxx>
62 #include <svx/fmview.hxx>
63 #include <sfx2/docfilt.hxx>
64 #include <vcl/imapobj.hxx>
65 #include <sfx2/docfile.hxx>
66 #include <unotools/transliterationwrapper.hxx>
67 #include <unotools/streamwrap.hxx>
68 #include <vcl/graphicfilter.hxx>
70 #ifdef _WIN32
71 #include <prewin.h>
72 #include <postwin.h>
73 #include <o3tl/char16_t2wchar_t.hxx>
74 #include <osl/file.hxx>
75 #endif
77 #include <svx/unomodel.hxx>
78 #include <fmturl.hxx>
79 #include <fmtinfmt.hxx>
80 #include <swdtflvr.hxx>
81 #include <shellio.hxx>
82 #include <ddefld.hxx>
83 #include <doc.hxx>
84 #include <IDocumentUndoRedo.hxx>
85 #include <IDocumentDrawModelAccess.hxx>
86 #include <IDocumentFieldsAccess.hxx>
87 #include <IDocumentRedlineAccess.hxx>
88 #include <IDocumentState.hxx>
89 #include <IMark.hxx>
90 #include <section.hxx>
91 #include <ndtxt.hxx>
92 #include <edtdd.hxx>
93 #include <edtwin.hxx>
94 #include <navicont.hxx>
95 #include <swcont.hxx>
96 #include <wrtsh.hxx>
97 #include <swmodule.hxx>
98 #include <view.hxx>
99 #include <docsh.hxx>
100 #include <wdocsh.hxx>
101 #include <fldbas.hxx>
102 #include <swundo.hxx>
103 #include <pam.hxx>
104 #include <ndole.hxx>
105 #include <swwait.hxx>
106 #include <viewopt.hxx>
107 #include <SwCapObjType.hxx>
108 #include <cmdid.h>
109 #include <strings.hrc>
110 #include <svx/svditer.hxx>
111 #include <editeng/eeitem.hxx>
112 #include <editeng/fhgtitem.hxx>
113 #include <editeng/prntitem.hxx>
114 #include <svx/svdpage.hxx>
115 #include <avmedia/mediawindow.hxx>
116 #include <swcrsr.hxx>
117 #include <SwRewriter.hxx>
118 #include <vcl/svapp.hxx>
119 #include <swserv.hxx>
120 #include <fmtmeta.hxx>
121 #include <itabenum.hxx>
122 #include <iodetect.hxx>
123 #include <unotextrange.hxx>
124 #include <unoframe.hxx>
125 #include <txatbase.hxx>
126 #include <unoparaframeenum.hxx>
127 #include <vcl/uitest/logger.hxx>
128 #include <vcl/uitest/eventdescription.hxx>
130 #include <vcl/GraphicNativeTransform.hxx>
131 #include <vcl/GraphicNativeMetadata.hxx>
132 #include <vcl/TypeSerializer.hxx>
133 #include <comphelper/lok.hxx>
134 #include <sfx2/classificationhelper.hxx>
135 #include <sfx2/sfxdlg.hxx>
136 #include <comphelper/classids.hxx>
137 #include <osl/diagnose.h>
139 #include <memory>
141 /* default (A4 format) width of 210mm - 2 * border size (border on both sides) */
142 constexpr tools::Long constOleWidthInMm = 210 - 2 * lMinBorderInMm;
144 constexpr Size constOleSize100mm(
145 constOleWidthInMm * 100, // convert from mm to 100mm
146 3000 // 3 cm
149 constexpr Size constOleSizeTwip = o3tl::convert(constOleSize100mm, o3tl::Length::mm100, o3tl::Length::twip);
151 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_DRAWMODEL = 0x00000001;
152 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_HTML = 0x00000002;
153 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_RTF = 0x00000004;
154 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_STRING = 0x00000008;
155 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_SWOLE = 0x00000010;
156 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_DDE = 0x00000020;
157 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_RICHTEXT = 0x00000040;
159 using namespace ::svx;
160 using namespace ::com::sun::star;
161 using namespace ::com::sun::star::uno;
162 using namespace ::com::sun::star::datatransfer;
163 namespace {
165 void collectUIInformation(const OUString& rAction, const OUString& aParameters)
167 EventDescription aDescription;
168 aDescription.aAction = rAction;
169 aDescription.aParameters = {{"parameters", aParameters}};
170 aDescription.aID = "writer_edit";
171 aDescription.aKeyWord = "SwEditWinUIObject";
172 aDescription.aParent = "MainWindow";
173 UITestLogger::getInstance().logEvent(aDescription);
178 class SwTransferDdeLink : public ::sfx2::SvBaseLink
180 OUString m_sName;
181 ::sfx2::SvLinkSourceRef m_xRefObj;
182 SwTransferable& m_rTransfer;
183 SwDocShell* m_pDocShell;
184 sal_uLong m_nOldTimeOut;
185 bool m_bDelBookmark : 1;
186 bool m_bInDisconnect : 1;
188 bool FindDocShell();
190 using sfx2::SvBaseLink::Disconnect;
192 protected:
193 virtual ~SwTransferDdeLink() override;
195 public:
196 SwTransferDdeLink( SwTransferable& rTrans, SwWrtShell& rSh );
198 virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(
199 const OUString& rMimeType, const css::uno::Any & rValue ) override;
200 virtual void Closed() override;
202 bool WriteData( SvStream& rStrm );
204 void Disconnect( bool bRemoveDataAdvise );
207 /// Tracks the boundaries of pasted content and notifies listeners.
208 class SwPasteContext
210 public:
211 SwPasteContext(SwWrtShell& rWrtShell);
212 ~SwPasteContext();
214 void remember();
215 void forget();
217 private:
218 SwWrtShell& m_rWrtShell;
219 std::optional<SwPaM> m_oPaM;
220 sal_Int32 m_nStartContent = 0;
223 namespace {
225 // helper class for Action and Undo enclosing
226 class SwTrnsfrActionAndUndo
228 SwWrtShell *pSh;
229 public:
230 SwTrnsfrActionAndUndo( SwWrtShell *pS, bool bDelSel = false, SwPasteContext* pContext = nullptr)
231 : pSh( pS )
233 pSh->StartUndo( SwUndoId::PASTE_CLIPBOARD );
234 if( bDelSel )
236 if (pContext)
237 pContext->forget();
238 pSh->DelRight();
239 if (pContext)
240 pContext->remember();
242 pSh->StartAllAction();
244 ~SwTrnsfrActionAndUndo() COVERITY_NOEXCEPT_FALSE
246 pSh->EndUndo();
247 pSh->EndAllAction();
253 SwTransferable::SwTransferable( SwWrtShell& rSh )
254 : m_pWrtShell( &rSh ),
255 m_pCreatorView( nullptr ),
256 m_pOrigGraphic( nullptr ),
257 m_eBufferType( TransferBufferType::NONE ),
258 m_bOldIdle(false),
259 m_bCleanUp(false)
261 rSh.GetView().AddTransferable(*this);
262 SwDocShell* pDShell = rSh.GetDoc()->GetDocShell();
263 if( !pDShell )
264 return;
266 pDShell->FillTransferableObjectDescriptor( m_aObjDesc );
267 if( pDShell->GetMedium() )
269 const INetURLObject& rURLObj = pDShell->GetMedium()->GetURLObject();
270 m_aObjDesc.maDisplayName = URIHelper::removePassword(
271 rURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
272 INetURLObject::EncodeMechanism::WasEncoded,
273 INetURLObject::DecodeMechanism::Unambiguous );
276 PrepareOLE( m_aObjDesc );
279 SwTransferable::~SwTransferable()
281 SolarMutexGuard aSolarGuard;
283 // the DDELink still needs the WrtShell!
284 DisconnectDDE();
286 m_pWrtShell = nullptr;
288 // release reference to the document so that aDocShellRef will delete
289 // it (if aDocShellRef is set). Otherwise, the OLE nodes keep references
290 // to their sub-storage when the storage is already dead.
291 m_pClpDocFac.reset();
293 // first close, then the Ref. can be cleared as well, so that
294 // the DocShell really gets deleted!
295 if( m_aDocShellRef.Is() )
297 SfxObjectShell * pObj = m_aDocShellRef;
298 SwDocShell* pDocSh = static_cast<SwDocShell*>(pObj);
299 pDocSh->DoClose();
301 m_aDocShellRef.Clear();
303 if (SwModule* pMod = SwModule::get())
305 if ( pMod->m_pDragDrop == this )
306 pMod->m_pDragDrop = nullptr;
307 else if ( pMod->m_pXSelection == this )
308 pMod->m_pXSelection = nullptr;
311 m_eBufferType = TransferBufferType::NONE;
314 static SwDoc& lcl_GetDoc(SwDocFac & rDocFac)
316 SwDoc& rDoc = rDocFac.GetDoc();
317 rDoc.SetClipBoard( true );
318 return rDoc;
321 void SwTransferable::ObjectReleased()
323 SwModule* pMod = SwModule::get();
324 if (!pMod)
325 return;
326 if( this == pMod->m_pDragDrop )
327 pMod->m_pDragDrop = nullptr;
328 else if( this == pMod->m_pXSelection )
329 pMod->m_pXSelection = nullptr;
332 void SwTransferable::AddSupportedFormats()
334 // only need if we are the current XSelection Object
335 if (this == SwModule::get()->m_pXSelection || comphelper::LibreOfficeKit::isActive())
337 SetDataForDragAndDrop( Point( 0,0) );
341 void SwTransferable::InitOle( SfxObjectShell* pDoc )
343 //set OleVisArea. Upper left corner of the page and size of
344 //RealSize in Twips.
345 const Size aSz(constOleSizeTwip);
346 SwRect aVis( Point( DOCUMENTBORDER, DOCUMENTBORDER ), aSz );
347 pDoc->SetVisArea( aVis.SVRect() );
350 uno::Reference < embed::XEmbeddedObject > SwTransferable::FindOLEObj( sal_Int64& nAspect ) const
352 uno::Reference < embed::XEmbeddedObject > xObj;
353 if( m_pClpDocFac )
355 SwIterator<SwContentNode,SwFormatColl> aIter( *m_pClpDocFac->GetDoc().GetDfltGrfFormatColl() );
356 for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
357 if( SwNodeType::Ole == pNd->GetNodeType() )
359 xObj = static_cast<SwOLENode*>(pNd)->GetOLEObj().GetOleRef();
360 nAspect = static_cast<SwOLENode*>(pNd)->GetAspect();
361 break;
364 return xObj;
367 const Graphic* SwTransferable::FindOLEReplacementGraphic() const
369 if( m_pClpDocFac )
371 SwIterator<SwContentNode,SwFormatColl> aIter( *m_pClpDocFac->GetDoc().GetDfltGrfFormatColl() );
372 for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
373 if( SwNodeType::Ole == pNd->GetNodeType() )
375 return static_cast<SwOLENode*>(pNd)->GetGraphic();
379 return nullptr;
382 void SwTransferable::RemoveDDELinkFormat(vcl::Window& rWin)
384 RemoveFormat( SotClipboardFormatId::LINK );
385 if (rWin.GetClipboard()->getContents().get() == this)
386 CopyToClipboard(&rWin);
389 void SwTransferable::DisconnectDDE()
391 if( m_xDdeLink.is() )
393 m_xDdeLink->Disconnect( true );
394 m_xDdeLink.clear();
398 namespace
400 //Resolves: fdo#40717 surely when we create a clipboard document we should
401 //overwrite the clipboard documents styles and settings with that of the
402 //source, so that we can WYSIWYG paste. If we want that the destinations
403 //styles are used over the source styles, that's a matter of the
404 //destination paste code to handle, not the source paste code.
405 void lclOverWriteDoc(SwWrtShell &rSrcWrtShell, SwDoc &rDest)
407 const SwDoc &rSrc = *rSrcWrtShell.GetDoc();
409 rDest.ReplaceCompatibilityOptions(rSrc);
410 rDest.ReplaceDefaults(rSrc);
412 //It would probably make most sense here to only insert the styles used
413 //by the selection, e.g. apply SwDoc::IsUsed on styles ?
414 rDest.ReplaceStyles(rSrc, false);
416 rSrcWrtShell.Copy(rDest);
418 rDest.GetMetaFieldManager().copyDocumentProperties(rSrc);
421 void lclCheckAndPerformRotation(Graphic& aGraphic)
423 GraphicNativeMetadata aMetadata;
424 if ( !aMetadata.read(aGraphic) )
425 return;
427 Degree10 aRotation = aMetadata.getRotation();
428 if (aRotation)
430 GraphicNativeTransform aTransform( aGraphic );
431 aTransform.rotate( aRotation );
436 sal_Bool SAL_CALL SwTransferable::isComplex()
438 sal_Int32 nTextLength = 0;
439 SwNodes& aNodes = m_pWrtShell->GetDoc()->GetNodes();
440 for (SwPaM& rPaM : m_pWrtShell->GetCursor()->GetRingContainer())
442 for (SwNodeOffset nIndex = rPaM.GetMark()->GetNodeIndex();
443 nIndex <= rPaM.GetPoint()->GetNodeIndex(); ++nIndex)
445 SwNode& rNd = *aNodes[nIndex];
447 SwTextNode* pTextNode = rNd.GetTextNode();
448 if (pTextNode)
450 if (pTextNode->HasHints())
452 for (size_t nHint = 0; nHint < pTextNode->GetSwpHints().Count(); ++nHint)
454 SwTextAttr* pHint = pTextNode->GetSwpHints().Get(nHint);
455 if (pHint->Which() == RES_TXTATR_FLYCNT)
457 return true; // Complex
462 FrameClientSortList_t vFrames;
463 ::CollectFrameAtNode(rNd, vFrames, true);
464 if (!vFrames.empty())
466 // There is an at-char anchored object to this node, that's complex.
467 return true;
470 nTextLength += pTextNode->GetText().getLength();
471 if (nTextLength >= 1024 * 512)
472 return true; // Complex
477 if (m_pWrtShell->GetSelectionType() == SelectionType::DrawObject)
478 return true; // Complex
480 // Simple
481 return false;
484 bool SwTransferable::GetData( const DataFlavor& rFlavor, const OUString& rDestDoc )
486 SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
488 // we can only fulfil the request if
489 // 1) we have data for this format
490 // 2) we have either a clipboard document (pClpDocFac), or
491 // we have a SwWrtShell (so we can generate a new clipboard document)
492 if( !HasFormat( nFormat ) || ( m_pClpDocFac == nullptr && m_pWrtShell == nullptr ) )
493 return false;
495 if( !m_pClpDocFac )
497 SelectionType nSelectionType = m_pWrtShell->GetSelectionType();
499 // when pending we will not get the correct type, but SelectionType::Text
500 // as fallback. This *happens* during D&D, so we need to check if we are in
501 // the fallback and just try to get a graphic
502 const bool bPending(m_pWrtShell->ActionPend());
504 // SEL_GRF is from ContentType of editsh
505 if(bPending || ((SelectionType::Graphic | SelectionType::DrawObject | SelectionType::DbForm) & nSelectionType))
507 m_oClpGraphic.emplace();
508 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
509 m_pOrigGraphic = &*m_oClpGraphic;
510 m_oClpBitmap.emplace();
511 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
512 m_pOrigGraphic = &*m_oClpBitmap;
514 // is it a URL-Button ?
515 OUString sURL;
516 OUString sDesc;
517 if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
519 m_oBookmark.emplace( sURL, sDesc );
520 m_eBufferType = TransferBufferType::InetField;
524 m_pClpDocFac.reset(new SwDocFac);
525 SwDoc& rTmpDoc = lcl_GetDoc(*m_pClpDocFac);
527 rTmpDoc.getIDocumentFieldsAccess().LockExpFields(); // never update fields - leave text as it is
528 lclOverWriteDoc(*m_pWrtShell, rTmpDoc);
530 // in CORE a new one was created (OLE-objects copied!)
531 m_aDocShellRef = rTmpDoc.GetTmpDocShell();
532 if( m_aDocShellRef.Is() )
533 SwTransferable::InitOle( m_aDocShellRef );
534 rTmpDoc.SetTmpDocShell( nullptr );
536 if( nSelectionType & SelectionType::Text && !m_pWrtShell->HasMark() )
538 SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
540 Point aPos( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY());
542 bool bSelect = g_bExecuteDrag &&
543 m_pWrtShell->GetView().GetDocShell() &&
544 !m_pWrtShell->GetView().GetDocShell()->IsReadOnly();
545 if( m_pWrtShell->GetContentAtPos( aPos, aContentAtPos, bSelect ) )
547 m_oBookmark.emplace(
548 static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr)->GetValue(),
549 aContentAtPos.sStr );
550 m_eBufferType = TransferBufferType::InetField;
551 if( bSelect )
552 m_pWrtShell->SelectTextAttr( RES_TXTATR_INETFMT );
555 if( m_pWrtShell->IsFrameSelected() )
557 SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
558 m_pWrtShell->GetFlyFrameAttr( aSet );
559 const SwFormatURL& rURL = aSet.Get( RES_URL );
560 if( rURL.GetMap() )
561 m_pImageMap.reset(new ImageMap( *rURL.GetMap() ));
562 else if( !rURL.GetURL().isEmpty() )
563 m_pTargetURL.reset(new INetImage(OUString(), rURL.GetURL(),
564 rURL.GetTargetFrameName() ));
568 bool bOK = false;
569 if( TransferBufferType::Ole == m_eBufferType )
571 //TODO/MBA: testing - is this the "single OLE object" case?!
572 // get OLE-Object from ClipDoc and get the data from that.
573 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT; // will be set in the next statement
574 uno::Reference < embed::XEmbeddedObject > xObj = FindOLEObj( nAspect );
575 const Graphic* pOLEGraph = FindOLEReplacementGraphic();
576 if( xObj.is() )
578 TransferableDataHelper aD( new SvEmbedTransferHelper( xObj, pOLEGraph, nAspect ) );
579 uno::Any aAny = aD.GetAny(rFlavor, rDestDoc);
580 if( aAny.hasValue() )
581 bOK = SetAny( aAny );
584 // the following solution will be used in the case when the object can not generate the image
585 // TODO/LATER: in future the transferhelper must probably be created based on object and the replacement stream
586 // TODO: Block not required now, SvEmbedTransferHelper should be able to handle GDIMetaFile format
587 if ( nFormat == SotClipboardFormatId::GDIMETAFILE )
589 pOLEGraph = FindOLEReplacementGraphic();
590 if ( pOLEGraph )
591 bOK = SetGDIMetaFile( pOLEGraph->GetGDIMetaFile() );
594 else
596 switch( nFormat )
598 case SotClipboardFormatId::LINK:
599 if( m_xDdeLink.is() )
600 bOK = SetObject( m_xDdeLink.get(), SWTRANSFER_OBJECTTYPE_DDE, rFlavor );
601 break;
603 case SotClipboardFormatId::OBJECTDESCRIPTOR:
604 case SotClipboardFormatId::LINKSRCDESCRIPTOR:
605 bOK = SetTransferableObjectDescriptor( m_aObjDesc );
606 break;
608 case SotClipboardFormatId::DRAWING:
610 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
611 bOK = SetObject( rDoc.getIDocumentDrawModelAccess().GetDrawModel(),
612 SWTRANSFER_OBJECTTYPE_DRAWMODEL, rFlavor );
614 break;
616 case SotClipboardFormatId::STRING:
618 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
619 bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_STRING, rFlavor );
621 break;
622 case SotClipboardFormatId::RTF:
624 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
625 bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_RTF, rFlavor );
627 break;
628 case SotClipboardFormatId::RICHTEXT:
630 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
631 bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_RICHTEXT, rFlavor );
633 break;
635 case SotClipboardFormatId::HTML:
637 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
638 bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_HTML, rFlavor );
640 break;
642 case SotClipboardFormatId::SVXB:
643 if( m_eBufferType & TransferBufferType::Graphic && m_pOrigGraphic )
644 bOK = SetGraphic( *m_pOrigGraphic );
645 break;
647 case SotClipboardFormatId::GDIMETAFILE:
648 if( m_eBufferType & TransferBufferType::Graphic )
649 bOK = SetGDIMetaFile( m_oClpGraphic->GetGDIMetaFile() );
650 break;
651 case SotClipboardFormatId::BITMAP:
652 case SotClipboardFormatId::PNG:
653 // Neither pClpBitmap nor pClpGraphic are necessarily set
654 if( (m_eBufferType & TransferBufferType::Graphic) && (m_oClpBitmap || m_oClpGraphic))
655 bOK = SetBitmapEx( (m_oClpBitmap ? m_oClpBitmap : m_oClpGraphic)->GetBitmapEx(), rFlavor );
656 break;
658 case SotClipboardFormatId::SVIM:
659 if( m_pImageMap )
660 bOK = SetImageMap( *m_pImageMap );
661 break;
663 case SotClipboardFormatId::INET_IMAGE:
664 if( m_pTargetURL )
665 bOK = SetINetImage( *m_pTargetURL, rFlavor );
666 break;
668 case SotClipboardFormatId::SOLK:
669 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
670 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
671 case SotClipboardFormatId::FILECONTENT:
672 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
673 case SotClipboardFormatId::SIMPLE_FILE:
674 if( (TransferBufferType::InetField & m_eBufferType) && m_oBookmark )
675 bOK = SetINetBookmark( *m_oBookmark, rFlavor );
676 break;
678 case SotClipboardFormatId::EMBED_SOURCE:
679 if( !m_aDocShellRef.Is() )
681 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
682 m_aDocShellRef = new SwDocShell(rDoc, SfxObjectCreateMode::EMBEDDED);
683 m_aDocShellRef->DoInitNew();
684 SwTransferable::InitOle( m_aDocShellRef );
686 bOK = SetObject( &m_aDocShellRef, SWTRANSFER_OBJECTTYPE_SWOLE,
687 rFlavor );
688 break;
689 default: break;
692 return bOK;
695 bool SwTransferable::WriteObject( SvStream& rOStream,
696 void* pObject, sal_uInt32 nObjectType,
697 const DataFlavor& /*rFlavor*/ )
699 bool bRet = false;
700 WriterRef xWrt;
702 switch( nObjectType )
704 case SWTRANSFER_OBJECTTYPE_DRAWMODEL:
706 // don't change the sequence of commands
707 SdrModel *pModel = static_cast<SdrModel*>(pObject);
708 rOStream.SetBufferSize( 16348 );
710 // for the changed pool defaults from drawing layer pool set those
711 // attributes as hard attributes to preserve them for saving
712 const SfxItemPool& rItemPool = pModel->GetItemPool();
713 const SvxFontHeightItem& rDefaultFontHeight = rItemPool.GetUserOrPoolDefaultItem(EE_CHAR_FONTHEIGHT);
715 // SW should have no MasterPages
716 OSL_ENSURE(0 == pModel->GetMasterPageCount(), "SW with MasterPages (!)");
718 for(sal_uInt16 a(0); a < pModel->GetPageCount(); a++)
720 const SdrPage* pPage = pModel->GetPage(a);
721 SdrObjListIter aIter(pPage, SdrIterMode::DeepNoGroups);
723 while(aIter.IsMore())
725 SdrObject* pObj = aIter.Next();
726 const SvxFontHeightItem& rItem = pObj->GetMergedItem(EE_CHAR_FONTHEIGHT);
728 if(rItem.GetHeight() == rDefaultFontHeight.GetHeight())
730 pObj->SetMergedItem(rDefaultFontHeight);
736 uno::Reference<io::XOutputStream> xDocOut( new utl::OOutputStreamWrapper( rOStream ) );
737 SvxDrawingLayerExport( pModel, xDocOut );
740 bRet = ERRCODE_NONE == rOStream.GetError();
742 break;
744 case SWTRANSFER_OBJECTTYPE_SWOLE:
746 SfxObjectShell* pEmbObj = static_cast<SfxObjectShell*>(pObject);
749 ::utl::TempFileFast aTempFile;
750 SvStream* pTempStream = aTempFile.GetStream(StreamMode::READWRITE);
751 uno::Reference< embed::XStorage > xWorkStore =
752 ::comphelper::OStorageHelper::GetStorageFromStream( new utl::OStreamWrapper(*pTempStream), embed::ElementModes::READWRITE );
754 // write document storage
755 pEmbObj->SetupStorage( xWorkStore, SOFFICE_FILEFORMAT_CURRENT, false );
756 // mba: no BaseURL for clipboard
757 SfxMedium aMedium( xWorkStore, OUString() );
758 pEmbObj->DoSaveObjectAs( aMedium, false );
759 pEmbObj->DoSaveCompleted();
761 uno::Reference< embed::XTransactedObject > xTransact( xWorkStore, uno::UNO_QUERY );
762 if ( xTransact.is() )
763 xTransact->commit();
765 rOStream.SetBufferSize( 0xff00 );
766 rOStream.WriteStream( *pTempStream );
768 xWorkStore->dispose();
769 xWorkStore.clear();
771 catch (const uno::Exception&)
775 bRet = ( rOStream.GetError() == ERRCODE_NONE );
777 break;
779 case SWTRANSFER_OBJECTTYPE_DDE:
781 rOStream.SetBufferSize( 1024 );
782 SwTransferDdeLink* pDdeLnk = static_cast<SwTransferDdeLink*>(pObject);
783 if( pDdeLnk->WriteData( rOStream ) )
785 bRet = ERRCODE_NONE == rOStream.GetError();
788 break;
790 case SWTRANSFER_OBJECTTYPE_HTML:
792 // LOK is interested in getting images embedded for copy/paste support.
793 GetHTMLWriter( comphelper::LibreOfficeKit::isActive() ? u"EmbedImages;NoPrettyPrint"_ustr : OUString(), OUString(), xWrt );
794 break;
797 case SWTRANSFER_OBJECTTYPE_RTF:
798 case SWTRANSFER_OBJECTTYPE_RICHTEXT:
799 GetRTFWriter(std::u16string_view(), OUString(), xWrt);
800 break;
802 case SWTRANSFER_OBJECTTYPE_STRING:
803 GetASCWriter(std::u16string_view(), OUString(), xWrt);
804 if( xWrt.is() )
806 SwAsciiOptions aAOpt;
807 aAOpt.SetCharSet( RTL_TEXTENCODING_UTF8 );
808 xWrt->SetAsciiOptions( aAOpt );
810 // no start char for clipboard
811 xWrt->m_bUCS2_WithStartChar = false;
813 break;
814 default: break;
817 if( xWrt.is() )
819 SwDoc* pDoc = static_cast<SwDoc*>(pObject);
820 xWrt->m_bWriteClipboardDoc = true;
821 xWrt->m_bWriteOnlyFirstTable = bool(TransferBufferType::Table & m_eBufferType);
822 xWrt->SetShowProgress(false);
824 #if defined(DEBUGPASTE)
825 SvFileStream aPasteDebug(
826 u"PASTEBUFFER.debug"_ustr, StreamMode::WRITE|StreamMode::TRUNC);
827 SwWriter aDbgWrt( aPasteDebug, *pDoc );
828 aDbgWrt.Write( xWrt );
829 #endif
831 SwWriter aWrt( rOStream, *pDoc );
832 if( ! aWrt.Write( xWrt ).IsError() )
834 rOStream.WriteChar( '\0' ); // terminate with a zero
835 bRet = true;
839 return bRet;
842 int SwTransferable::Cut()
844 int nRet = Copy( true );
845 if( nRet )
846 DeleteSelection();
847 collectUIInformation(u"CUT"_ustr, u"parameter"_ustr);
848 return nRet;
851 void SwTransferable::DeleteSelection()
853 if(!m_pWrtShell)
854 return;
855 // ask for type of selection before action-bracketing
856 const SelectionType nSelection = m_pWrtShell->GetSelectionType();
857 // cut rows or columns selected by enhanced table selection and wholly selected tables
858 bool bCutMode = ( SelectionType::TableCell & nSelection ) && ( (SelectionType::TableRow | SelectionType::TableCol) & nSelection ||
859 m_pWrtShell->HasWholeTabSelection() );
861 m_pWrtShell->StartUndo( SwUndoId::START );
862 if( bCutMode )
864 if( !(SelectionType::TableCol & nSelection) )
865 m_pWrtShell->DeleteTable();
866 else
868 SfxDispatcher* pDispatch = m_pWrtShell->GetView().GetViewFrame().GetDispatcher();
869 pDispatch->Execute(FN_TABLE_DELETE_COL, SfxCallMode::SYNCHRON);
872 else
874 if( ( SelectionType::Text | SelectionType::Table ) & nSelection )
875 m_pWrtShell->IntelligentCut( nSelection );
876 m_pWrtShell->DelRight();
878 m_pWrtShell->EndUndo( SwUndoId::END );
881 static void DeleteDDEMarks(SwDoc & rDest)
883 IDocumentMarkAccess *const pMarkAccess = rDest.getIDocumentMarkAccess();
884 std::vector< ::sw::mark::MarkBase* > vDdeMarks;
885 // find all DDE-Bookmarks
886 for (auto ppMark = pMarkAccess->getAllMarksBegin();
887 ppMark != pMarkAccess->getAllMarksEnd();
888 ++ppMark)
890 if (IDocumentMarkAccess::MarkType::DDE_BOOKMARK == IDocumentMarkAccess::GetType(**ppMark))
892 vDdeMarks.push_back(*ppMark);
895 // remove all DDE-Bookmarks, they are invalid inside the clipdoc!
896 for (const auto& rpMark : vDdeMarks)
898 pMarkAccess->deleteMark(rpMark);
902 void SwTransferable::PrepareForCopyTextRange(SwPaM & rPaM)
904 std::optional<SwWait> oWait;
905 if (m_pWrtShell->ShouldWait())
907 oWait.emplace( *m_pWrtShell->GetView().GetDocShell(), true );
910 m_pClpDocFac.reset(new SwDocFac);
912 SwDoc& rDest(lcl_GetDoc(*m_pClpDocFac));
913 rDest.getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is
915 SwDoc const& rSrc(*m_pWrtShell->GetDoc());
916 assert(&rSrc == &rPaM.GetDoc());
918 rDest.ReplaceCompatibilityOptions(rSrc);
919 rDest.ReplaceDefaults(rSrc);
921 //It would probably make most sense here to only insert the styles used
922 //by the selection, e.g. apply SwDoc::IsUsed on styles ?
923 rDest.ReplaceStyles(rSrc, false);
925 // relevant bits of rSrcWrtShell.Copy(rDest);
926 rDest.GetIDocumentUndoRedo().DoUndo(false); // always false!
927 rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::DeleteRedlines );
929 SwNodeIndex const aIdx(rDest.GetNodes().GetEndOfContent(), -1);
930 SwContentNode *const pContentNode(aIdx.GetNode().GetContentNode());
931 SwPosition aPos(aIdx, pContentNode, pContentNode ? pContentNode->Len() : 0);
933 rSrc.getIDocumentContentOperations().CopyRange(rPaM, aPos, SwCopyFlags::CheckPosInFly);
935 rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE );
937 rDest.GetMetaFieldManager().copyDocumentProperties(rSrc);
940 DeleteDDEMarks(rDest);
942 // a new one was created in core (OLE objects copied!)
943 m_aDocShellRef = rDest.GetTmpDocShell();
944 if (m_aDocShellRef.Is())
945 SwTransferable::InitOle( m_aDocShellRef );
946 rDest.SetTmpDocShell( nullptr );
948 // let's add some formats
949 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
950 AddFormat( SotClipboardFormatId::RTF );
951 #if HAVE_FEATURE_DESKTOP
952 AddFormat( SotClipboardFormatId::RICHTEXT );
953 AddFormat( SotClipboardFormatId::HTML );
954 #endif
955 AddFormat( SotClipboardFormatId::STRING );
958 int SwTransferable::PrepareForCopy( bool bIsCut )
960 int nRet = 1;
961 if(!m_pWrtShell)
962 return 0;
964 if ( m_pWrtShell->GetTableInsertMode() != SwTable::SEARCH_NONE )
965 m_pWrtShell->SetTableInsertMode( SwTable::SEARCH_NONE );
967 if ( m_pWrtShell->GetTableCopied() )
968 m_pWrtShell->SetTableCopied( false );
970 OUString sGrfNm;
971 const SelectionType nSelection = m_pWrtShell->GetSelectionType();
972 if( nSelection == SelectionType::Graphic )
974 m_oClpGraphic.emplace();
975 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
976 m_pOrigGraphic = &*m_oClpGraphic;
977 m_oClpBitmap.emplace();
978 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
979 m_pOrigGraphic = &*m_oClpBitmap;
981 m_pClpDocFac.reset(new SwDocFac);
982 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
983 m_pWrtShell->Copy(rDoc);
985 #if HAVE_FEATURE_DESKTOP
986 if (m_pOrigGraphic && !m_pOrigGraphic->GetBitmapEx().IsEmpty())
987 AddFormat( SotClipboardFormatId::SVXB );
988 #endif
990 PrepareOLE( m_aObjDesc );
991 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
993 const Graphic* pGrf = m_pWrtShell->GetGraphic();
994 if( pGrf && pGrf->IsSupportedGraphic() )
996 AddFormat( SotClipboardFormatId::PNG );
997 #if HAVE_FEATURE_DESKTOP
998 AddFormat( SotClipboardFormatId::GDIMETAFILE );
999 AddFormat( SotClipboardFormatId::BITMAP );
1000 #endif
1002 m_eBufferType = TransferBufferType::Graphic;
1003 m_pWrtShell->GetGrfNms( &sGrfNm, nullptr );
1005 else if ( nSelection == SelectionType::Ole )
1007 m_pClpDocFac.reset(new SwDocFac);
1008 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
1009 m_aDocShellRef = new SwDocShell(rDoc, SfxObjectCreateMode::EMBEDDED);
1010 m_aDocShellRef->DoInitNew();
1011 m_pWrtShell->Copy(rDoc);
1013 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
1015 // --> OD #i98753#
1016 // set size of embedded object at the object description structure
1017 m_aObjDesc.maSize = o3tl::convert(m_pWrtShell->GetObjSize(), o3tl::Length::twip, o3tl::Length::mm100);
1019 // <--
1020 PrepareOLE( m_aObjDesc );
1022 #if HAVE_FEATURE_DESKTOP
1023 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
1024 AddFormat( SotClipboardFormatId::GDIMETAFILE );
1026 // Fetch the formats supported via embedtransferhelper as well
1027 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
1028 uno::Reference < embed::XEmbeddedObject > xObj = FindOLEObj( nAspect );
1029 const Graphic* pOLEGraph = FindOLEReplacementGraphic();
1030 if( xObj.is() )
1032 TransferableDataHelper aD( new SvEmbedTransferHelper( xObj, pOLEGraph, nAspect ) );
1033 if ( aD.GetTransferable().is() )
1035 DataFlavorExVector aVector( aD.GetDataFlavorExVector() );
1037 for( const auto& rItem : aVector )
1038 AddFormat( rItem );
1041 #endif
1042 m_eBufferType = TransferBufferType::Ole;
1044 // Is there anything to provide anyway?
1045 else if ( m_pWrtShell->IsSelection() || m_pWrtShell->IsFrameSelected() ||
1046 m_pWrtShell->IsObjSelected() )
1048 std::optional<SwWait> oWait;
1049 if( m_pWrtShell->ShouldWait() )
1050 oWait.emplace( *m_pWrtShell->GetView().GetDocShell(), true );
1052 m_pClpDocFac.reset(new SwDocFac);
1054 // create additional cursor so that equal treatment of keyboard
1055 // and mouse selection is possible.
1056 // In AddMode with keyboard selection, the new cursor is not created
1057 // before the cursor is moved after end of selection.
1058 if( m_pWrtShell->IsAddMode() && m_pWrtShell->SwCursorShell::HasSelection() )
1059 m_pWrtShell->CreateCursor();
1061 SwDoc& rTmpDoc = lcl_GetDoc(*m_pClpDocFac);
1063 rTmpDoc.getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is
1064 lclOverWriteDoc(*m_pWrtShell, rTmpDoc);
1066 DeleteDDEMarks(rTmpDoc);
1068 // a new one was created in CORE (OLE objects copied!)
1069 m_aDocShellRef = rTmpDoc.GetTmpDocShell();
1070 if( m_aDocShellRef.Is() )
1071 SwTransferable::InitOle( m_aDocShellRef );
1072 rTmpDoc.SetTmpDocShell( nullptr );
1074 if( m_pWrtShell->IsObjSelected() )
1075 m_eBufferType = TransferBufferType::Drawing;
1076 else
1078 m_eBufferType = TransferBufferType::Document;
1079 if (m_pWrtShell->IntelligentCut(nSelection, false) != SwWrtShell::NO_WORD)
1080 m_eBufferType = TransferBufferType::DocumentWord | m_eBufferType;
1083 bool bDDELink = m_pWrtShell->IsSelection();
1084 if( nSelection & SelectionType::TableCell )
1086 m_eBufferType = TransferBufferType::Table | m_eBufferType;
1087 bDDELink = m_pWrtShell->HasWholeTabSelection();
1089 m_pWrtShell->SetTableCopied(true);
1091 if ( bIsCut && (SelectionType::TableRow | SelectionType::TableCol) & nSelection )
1092 m_pWrtShell->SetTableInsertMode( (SelectionType::TableRow & nSelection) ? SwTable::SEARCH_ROW : SwTable::SEARCH_COL );
1095 #if HAVE_FEATURE_DESKTOP
1096 //When someone needs it, we 'OLE' him something
1097 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
1098 #endif
1100 //put RTF ahead of the OLE's Metafile to have less loss
1101 if( !m_pWrtShell->IsObjSelected() )
1103 AddFormat( SotClipboardFormatId::RTF );
1104 #if HAVE_FEATURE_DESKTOP
1105 AddFormat( SotClipboardFormatId::RICHTEXT );
1106 AddFormat( SotClipboardFormatId::HTML );
1107 #endif
1109 if( m_pWrtShell->IsSelection() )
1110 AddFormat( SotClipboardFormatId::STRING );
1112 if( nSelection & ( SelectionType::DrawObject | SelectionType::DbForm ))
1114 AddFormat( SotClipboardFormatId::DRAWING );
1115 if ( nSelection & SelectionType::DrawObject )
1117 #if HAVE_FEATURE_DESKTOP
1118 AddFormat( SotClipboardFormatId::GDIMETAFILE );
1119 AddFormat( SotClipboardFormatId::BITMAP );
1120 #endif
1121 AddFormat( SotClipboardFormatId::PNG );
1123 m_eBufferType = static_cast<TransferBufferType>( TransferBufferType::Graphic | m_eBufferType );
1125 m_oClpGraphic.emplace();
1126 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
1127 m_pOrigGraphic = &*m_oClpGraphic;
1128 m_oClpBitmap.emplace();
1129 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
1130 m_pOrigGraphic = &*m_oClpBitmap;
1132 // is it a URL-Button ?
1133 OUString sURL;
1134 OUString sDesc;
1135 if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
1137 AddFormat( SotClipboardFormatId::STRING );
1138 #if HAVE_FEATURE_DESKTOP
1139 AddFormat( SotClipboardFormatId::SOLK );
1140 AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
1141 AddFormat( SotClipboardFormatId::FILECONTENT );
1142 AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
1143 #endif
1144 AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
1145 m_eBufferType = TransferBufferType::InetField | m_eBufferType;
1146 nRet = 1;
1150 // at Cut, DDE-Link doesn't make sense!!
1151 SwDocShell* pDShell;
1152 if( !bIsCut && bDDELink &&
1153 nullptr != ( pDShell = m_pWrtShell->GetDoc()->GetDocShell()) &&
1154 SfxObjectCreateMode::STANDARD == pDShell->GetCreateMode() )
1156 #if HAVE_FEATURE_DESKTOP
1157 AddFormat( SotClipboardFormatId::LINK );
1158 #endif
1159 m_xDdeLink = new SwTransferDdeLink( *this, *m_pWrtShell );
1162 //ObjectDescriptor was already filly from the old DocShell.
1163 //Now adjust it. Thus in GetData the first query can still
1164 //be answered with delayed rendering.
1165 m_aObjDesc.maSize = constOleSize100mm;
1167 PrepareOLE( m_aObjDesc );
1168 #if HAVE_FEATURE_DESKTOP
1169 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
1170 #endif
1172 else
1173 nRet = 0;
1175 if( m_pWrtShell->IsFrameSelected() )
1177 SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
1178 m_pWrtShell->GetFlyFrameAttr( aSet );
1179 const SwFormatURL& rURL = aSet.Get( RES_URL );
1180 if( rURL.GetMap() )
1182 m_pImageMap.reset( new ImageMap( *rURL.GetMap() ) );
1183 AddFormat( SotClipboardFormatId::SVIM );
1185 else if( !rURL.GetURL().isEmpty() )
1187 m_pTargetURL.reset(new INetImage( sGrfNm, rURL.GetURL(),
1188 rURL.GetTargetFrameName() ));
1189 AddFormat( SotClipboardFormatId::INET_IMAGE );
1193 return nRet;
1196 int SwTransferable::Copy( bool bIsCut )
1198 if (m_pWrtShell->GetView().GetObjectShell()->isContentExtractionLocked())
1199 return 0;
1201 int nRet = PrepareForCopy( bIsCut );
1202 if ( nRet )
1204 CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
1207 if( !bIsCut ){
1208 collectUIInformation(u"COPY"_ustr, u"parameter"_ustr);
1211 return nRet;
1214 void SwTransferable::CalculateAndCopy()
1216 if(!m_pWrtShell)
1217 return;
1218 SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true );
1220 OUString aStr( m_pWrtShell->Calculate() );
1222 m_pClpDocFac.reset(new SwDocFac);
1223 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
1224 m_pWrtShell->Copy(rDoc, &aStr);
1225 m_eBufferType = TransferBufferType::Document;
1226 AddFormat( SotClipboardFormatId::STRING );
1228 CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
1231 bool SwTransferable::CopyGlossary( SwTextBlocks& rGlossary, const OUString& rStr )
1233 if(!m_pWrtShell)
1234 return false;
1235 SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true );
1237 m_pClpDocFac.reset(new SwDocFac);
1238 SwDoc& rCDoc = lcl_GetDoc(*m_pClpDocFac);
1240 SwNodes& rNds = rCDoc.GetNodes();
1241 SwNodeIndex aNodeIdx( *rNds.GetEndOfContent().StartOfSectionNode() );
1242 SwContentNode* pCNd = SwNodes::GoNext(&aNodeIdx); // go to 1st ContentNode
1243 SwPaM aPam( *pCNd );
1245 rCDoc.getIDocumentFieldsAccess().LockExpFields(); // never update fields - leave text as it is
1247 rCDoc.InsertGlossary( rGlossary, rStr, aPam );
1249 // a new one was created in CORE (OLE-Objects copied!)
1250 m_aDocShellRef = rCDoc.GetTmpDocShell();
1251 if( m_aDocShellRef.Is() )
1252 SwTransferable::InitOle( m_aDocShellRef );
1253 rCDoc.SetTmpDocShell( nullptr );
1255 m_eBufferType = TransferBufferType::Document;
1257 //When someone needs it, we 'OLE' her something.
1258 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
1259 AddFormat( SotClipboardFormatId::RTF );
1260 AddFormat( SotClipboardFormatId::RICHTEXT );
1261 AddFormat( SotClipboardFormatId::HTML );
1262 AddFormat( SotClipboardFormatId::STRING );
1264 //ObjectDescriptor was already filled from the old DocShell.
1265 //Now adjust it. Thus in GetData the first query can still
1266 //be answered with delayed rendering.
1267 m_aObjDesc.maSize = constOleSize100mm;
1269 PrepareOLE( m_aObjDesc );
1270 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
1272 CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
1274 return true;
1277 static uno::Reference < XTransferable > * lcl_getTransferPointer ( uno::Reference < XTransferable > &xRef )
1279 return &xRef;
1282 SwPasteContext::SwPasteContext(SwWrtShell& rWrtShell)
1283 : m_rWrtShell(rWrtShell)
1285 remember();
1288 void SwPasteContext::remember()
1290 if (m_rWrtShell.GetPasteListeners().getLength() == 0)
1291 return;
1293 SwPaM* pCursor = m_rWrtShell.GetCursor();
1294 if (!pCursor)
1295 return;
1297 // Set point to the previous node, so it is not moved.
1298 const SwNode& rNode = pCursor->GetPoint()->GetNode();
1299 m_oPaM.emplace(rNode, rNode, SwNodeOffset(0), SwNodeOffset(-1));
1300 m_nStartContent = pCursor->GetPoint()->GetContentIndex();
1303 void SwPasteContext::forget() { m_oPaM.reset(); }
1305 SwPasteContext::~SwPasteContext()
1309 if (m_rWrtShell.GetPasteListeners().getLength() == 0)
1310 return;
1312 beans::PropertyValue aPropertyValue;
1314 switch (m_rWrtShell.GetView().GetShellMode())
1316 case ShellMode::Graphic:
1318 SwFrameFormat* pFormat = m_rWrtShell.GetFlyFrameFormat();
1319 if (!pFormat)
1320 return;
1322 aPropertyValue.Name = "TextGraphicObject";
1323 aPropertyValue.Value
1324 <<= uno::Reference<text::XTextContent>(SwXTextGraphicObject::CreateXTextGraphicObject(*pFormat->GetDoc(), pFormat));
1325 break;
1328 default:
1330 if (!m_oPaM)
1331 return;
1333 SwPaM* pCursor = m_rWrtShell.GetCursor();
1334 if (!pCursor)
1335 return;
1337 if (!pCursor->GetPoint()->GetNode().IsTextNode())
1338 // Non-text was pasted.
1339 return;
1341 // Update mark after paste.
1342 *m_oPaM->GetMark() = *pCursor->GetPoint();
1344 // Restore point.
1345 m_oPaM->GetPoint()->Adjust(SwNodeOffset(1));
1346 SwNode& rNode = m_oPaM->GetPointNode();
1347 if (!rNode.IsTextNode())
1348 // Starting point is no longer text.
1349 return;
1351 m_oPaM->GetPoint()->SetContent(m_nStartContent);
1353 aPropertyValue.Name = "TextRange";
1354 const rtl::Reference<SwXTextRange> xTextRange = SwXTextRange::CreateXTextRange(
1355 m_oPaM->GetDoc(), *m_oPaM->GetPoint(), m_oPaM->GetMark());
1356 aPropertyValue.Value <<= uno::Reference<text::XTextRange>(xTextRange);
1357 break;
1361 if (aPropertyValue.Name.isEmpty())
1362 return;
1364 // Invoke the listeners.
1365 uno::Sequence<beans::PropertyValue> aEvent{ std::move(aPropertyValue) };
1366 m_rWrtShell.GetPasteListeners().notifyEach( &css::text::XPasteListener::notifyPasteEvent, aEvent );
1368 catch (const uno::Exception& rException)
1370 SAL_WARN("sw",
1371 "SwPasteContext::~SwPasteContext: uncaught exception: " << rException.Message);
1375 bool SwTransferable::IsPaste( const SwWrtShell& rSh,
1376 const TransferableDataHelper& rData )
1378 // Check the common case first: We can always paste our own data!
1379 // If _only_ the internal format can be pasted, this check will
1380 // yield 'true', while the one below would give a (wrong) result 'false'.
1382 bool bIsPaste = ( GetSwTransferable( rData ) != nullptr );
1384 // if it's not our own data, we need to have a closer look:
1385 if( ! bIsPaste )
1387 // determine the proper paste action, and return true if we find one
1388 uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
1390 SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
1391 sal_uInt16 nSourceOptions =
1392 (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
1393 SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
1394 SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
1395 SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
1396 ? EXCHG_IN_ACTION_COPY
1397 : EXCHG_IN_ACTION_MOVE);
1399 SotClipboardFormatId nFormat; // output param for GetExchangeAction
1400 sal_uInt8 nEventAction; // output param for GetExchangeAction
1401 sal_uInt8 nAction = SotExchange::GetExchangeAction(
1402 rData.GetDataFlavorExVector(),
1403 nDestination,
1404 nSourceOptions, /* ?? */
1405 EXCHG_IN_ACTION_DEFAULT, /* ?? */
1406 nFormat, nEventAction, SotClipboardFormatId::NONE,
1407 lcl_getTransferPointer ( xTransferable ) );
1409 // if we find a suitable action, we can paste!
1410 bIsPaste = (EXCHG_INOUT_ACTION_NONE != nAction);
1413 return bIsPaste;
1416 void SwTransferable::SelectPasteFormat(TransferableDataHelper& rData, sal_uInt8& nAction,
1417 SotClipboardFormatId& nFormat)
1419 if (nFormat != SotClipboardFormatId::RICHTEXT)
1421 return;
1424 if (!rData.HasFormat(SotClipboardFormatId::EMBED_SOURCE))
1426 return;
1429 if (!rData.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
1431 return;
1434 TransferableObjectDescriptor aObjDesc;
1435 if (!rData.GetTransferableObjectDescriptor(SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc))
1437 return;
1440 if (aObjDesc.maClassName != SvGlobalName(SO3_SW_CLASSID))
1442 return;
1445 // At this point we know that we paste from Writer to Writer and the clipboard has the content
1446 // in both RTF and ODF formats. Prefer ODF in this case.
1447 nAction = EXCHG_OUT_ACTION_INSERT_OLE;
1448 nFormat = SotClipboardFormatId::EMBED_SOURCE;
1451 // get HTML indentation level by counting tabulator characters before the index
1452 // (also index value -1 returns with 0)
1453 static sal_Int32 lcl_getLevel(OUString& sText, sal_Int32 nIdx)
1455 sal_Int32 nRet = 0;
1456 while ( nIdx-- > 0 && sText[nIdx] == '\t' )
1458 nRet++;
1460 return nRet;
1463 bool SwTransferable::Paste(SwWrtShell& rSh, TransferableDataHelper& rData, RndStdIds nAnchorType, bool bIgnoreComments, PasteTableType ePasteTable)
1465 SwPasteContext aPasteContext(rSh);
1467 sal_uInt8 nAction=0;
1468 SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
1469 SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
1470 SotExchangeActionFlags nActionFlags = SotExchangeActionFlags::NONE;
1471 bool bSingleCellTable = false;
1473 if( GetSwTransferable( rData ) )
1475 nAction = EXCHG_OUT_ACTION_INSERT_PRIVATE;
1477 else
1479 sal_uInt16 nSourceOptions =
1480 (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
1481 SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
1482 SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
1483 SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
1484 ? EXCHG_IN_ACTION_COPY
1485 : EXCHG_IN_ACTION_MOVE);
1486 uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
1487 sal_uInt8 nEventAction;
1488 nAction = SotExchange::GetExchangeAction(
1489 rData.GetDataFlavorExVector(),
1490 nDestination,
1491 nSourceOptions, /* ?? */
1492 EXCHG_IN_ACTION_DEFAULT, /* ?? */
1493 nFormat, nEventAction, SotClipboardFormatId::NONE,
1494 lcl_getTransferPointer ( xTransferable ),
1495 &nActionFlags );
1498 // when HTML is just an image don't generate new section
1499 if (rData.HasFormat(SotClipboardFormatId::HTML_SIMPLE) && rData.HasFormat(SotClipboardFormatId::HTML_NO_COMMENT)
1500 && rData.HasFormat(SotClipboardFormatId::BITMAP) && nFormat == SotClipboardFormatId::FILE_LIST)
1501 nFormat = SotClipboardFormatId::BITMAP;
1503 // tdf#37223 avoid non-native insertion of Calc worksheets in the following cases:
1504 // content of 1-cell worksheets are inserted as simple text using RTF format,
1505 // bigger worksheets within native (Writer) table cells are inserted as native tables,
1506 // ie. cell by cell instead of embedding the worksheet in a single cell of the Writer table
1507 if ( EXCHG_IN_ACTION_COPY == nAction && ( rData.HasFormat( SotClipboardFormatId::SYLK ) ||
1508 rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) )
1510 // is it a 1-cell worksheet?
1511 OUString aExpand;
1512 if( rData.GetString( SotClipboardFormatId::STRING, aExpand ))
1514 const sal_Int32 nNewlines{comphelper::string::getTokenCount(aExpand, '\n')};
1515 const sal_Int32 nRows = nNewlines ? nNewlines-1 : 0;
1516 if ( nRows == 1 )
1518 const sal_Int32 nCols = comphelper::string::getTokenCount(o3tl::getToken(aExpand, 0, '\n'), '\t');
1519 if (nCols == 1)
1520 bSingleCellTable = true;
1524 // convert the worksheet to a temporary native table using HTML format, and copy that into the original native table
1525 if (!bSingleCellTable && rData.HasFormat( SotClipboardFormatId::HTML ) &&
1526 SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr && rSh.DoesUndo())
1528 SfxDispatcher* pDispatch = rSh.GetView().GetViewFrame().GetDispatcher();
1529 sal_uInt32 nLevel = 0;
1531 // within Writer table cells, inserting worksheets using HTML format results only plain text, not a native table,
1532 // so remove all outer nested tables temporary to get a working insertion point
1533 // (RTF format has no such problem, but that inserts the hidden rows of the original Calc worksheet, too)
1535 // For this, switch off change tracking temporarily, if needed
1536 RedlineFlags eOld = rSh.GetDoc()->getIDocumentRedlineAccess().GetRedlineFlags();
1537 if ( eOld & RedlineFlags::On )
1538 rSh.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags( eOld & ~RedlineFlags::On );
1540 OUString sPreviousTableName;
1543 // tdf#152245 add a limit to the loop, if it's not possible to delete the table
1544 const SwTableNode* pNode = rSh.GetCursor()->GetPointNode().FindTableNode();
1545 const OUString sTableName = pNode->GetTable().GetFrameFormat()->GetName();
1546 if ( sTableName == sPreviousTableName )
1547 break;
1548 sPreviousTableName = sTableName;
1549 // insert a random character to redo the place of the insertion at the end
1550 pDispatch->Execute(FN_INSERT_NNBSP, SfxCallMode::SYNCHRON);
1551 pDispatch->Execute(FN_TABLE_DELETE_TABLE, SfxCallMode::SYNCHRON);
1552 nLevel++;
1553 } while (SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr);
1555 // restore change tracking settings
1556 if ( eOld & RedlineFlags::On )
1557 rSh.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags( eOld );
1559 if ( SwTransferable::PasteData( rData, rSh, EXCHG_OUT_ACTION_INSERT_STRING, nActionFlags, SotClipboardFormatId::HTML,
1560 nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, ePasteTable) )
1562 bool bFoundTemporaryTable = false;
1563 pDispatch->Execute(FN_LINE_UP, SfxCallMode::SYNCHRON);
1564 if (SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr)
1566 bFoundTemporaryTable = true;
1567 pDispatch->Execute(FN_TABLE_SELECT_ALL, SfxCallMode::SYNCHRON);
1568 pDispatch->Execute(SID_COPY, SfxCallMode::SYNCHRON);
1570 for(sal_uInt32 a = 0; a < 1 + (nLevel * 2); a++)
1571 pDispatch->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
1572 // clipboard content hasn't changed (limit potential infinite
1573 // recursion with the same non-native table, as was in tdf#138688)
1574 if (!bFoundTemporaryTable)
1575 return false;
1576 if (ePasteTable == PasteTableType::PASTE_TABLE)
1577 pDispatch->Execute(FN_PASTE_NESTED_TABLE, SfxCallMode::SYNCHRON);
1578 else if (ePasteTable == PasteTableType::PASTE_ROW)
1579 pDispatch->Execute(FN_TABLE_PASTE_ROW_BEFORE, SfxCallMode::SYNCHRON);
1580 else if (ePasteTable == PasteTableType::PASTE_COLUMN)
1581 pDispatch->Execute(FN_TABLE_PASTE_COL_BEFORE, SfxCallMode::SYNCHRON);
1582 else
1583 pDispatch->Execute(SID_PASTE, SfxCallMode::SYNCHRON);
1584 return true;
1585 } else {
1586 for(sal_uInt32 a = 0; a < (nLevel * 2); a++)
1587 pDispatch->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
1591 // insert clipboard content as new table rows/columns before the actual row/column instead of overwriting it
1592 else if ( (rSh.GetTableInsertMode() != SwTable::SEARCH_NONE || ePasteTable == PasteTableType::PASTE_ROW || ePasteTable == PasteTableType::PASTE_COLUMN) &&
1593 rData.HasFormat( SotClipboardFormatId::HTML ) &&
1594 SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr )
1596 OUString aExpand;
1597 sal_Int32 nIdx;
1598 bool bRowMode = rSh.GetTableInsertMode() == SwTable::SEARCH_ROW || ePasteTable == PasteTableType::PASTE_ROW;
1599 if( rData.GetString( SotClipboardFormatId::HTML, aExpand ) && (nIdx = aExpand.indexOf("<table")) > -1 )
1601 // calculate table row/column count by analysing indentation of the HTML table extract
1603 // calculate indentation level of <table>, which is the base of the next calculations
1604 // (tdf#148791 table alignment can enlarge it using first level <center>, <div> or <dl>)
1605 sal_Int32 nTableLevel = lcl_getLevel(aExpand, nIdx);
1606 // table rows repeated heading use extra indentation, too:
1607 // <thead> is always used here, and the first table with <thead> is not nested,
1608 // if its indentation level is greater only by 1, than indentation level of the table
1609 bool bShifted = lcl_getLevel(aExpand, aExpand.indexOf("<thead")) == nTableLevel + 1;
1610 // calculate count of selected rows or columns
1611 sal_Int32 nSelectedRowsOrCols = 0;
1612 const OUString sSearchRowOrCol = bRowMode ? u"</tr>"_ustr : u"<col "_ustr;
1613 while((nIdx = aExpand.indexOf(sSearchRowOrCol, nIdx)) > -1)
1615 // skip rows/columns of nested tables, based on HTML indentation
1616 if ( lcl_getLevel(aExpand, nIdx) == nTableLevel + (bShifted ? 2 : 1) &&
1617 // skip also strange hidden empty rows <tr></tr>
1618 !aExpand.match("<tr></tr>", nIdx - 4) )
1620 ++nSelectedRowsOrCols;
1622 ++nIdx;
1624 // are we at the beginning of the cell?
1625 bool bStartTableBoxNode =
1626 // first paragraph of the cell?
1627 rSh.GetCursor()->GetPointNode().GetIndex() == rSh.GetCursor()->GetPointNode().FindTableBoxStartNode()->GetIndex()+1 &&
1628 // beginning of the paragraph?
1629 !rSh.GetCursor()->GetPoint()->GetContentIndex();
1630 SfxDispatcher* pDispatch = rSh.GetView().GetViewFrame().GetDispatcher();
1632 // go start of the cell
1633 if (!bStartTableBoxNode)
1634 pDispatch->Execute(FN_START_OF_DOCUMENT, SfxCallMode::SYNCHRON);
1636 // store cursor position in row mode
1637 ::sw::mark::MarkBase* pMark = (!bRowMode || nSelectedRowsOrCols == 0) ? nullptr : rSh.SetBookmark(
1638 vcl::KeyCode(),
1639 OUString(),
1640 IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
1642 // add a new empty row/column before the actual table row/column and go there
1643 const sal_uInt16 nDispatchSlot = bRowMode ? FN_TABLE_INSERT_ROW_BEFORE : FN_TABLE_INSERT_COL_BEFORE;
1644 pDispatch->Execute(nDispatchSlot, SfxCallMode::SYNCHRON);
1645 pDispatch->Execute(bRowMode ? FN_LINE_UP : FN_CHAR_LEFT, SfxCallMode::SYNCHRON);
1647 // add the other new empty rows/columns after the actual table row/column
1648 if ( nSelectedRowsOrCols > 1 )
1650 SfxInt16Item aCountItem( nDispatchSlot, nSelectedRowsOrCols-1 );
1651 SfxBoolItem aAfter( FN_PARAM_INSERT_AFTER, true );
1652 pDispatch->ExecuteList(nDispatchSlot,
1653 SfxCallMode::SYNCHRON|SfxCallMode::RECORD,
1654 { &aCountItem, &aAfter });
1657 // paste rows
1658 bool bResult = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
1659 nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext );
1661 // restore cursor position
1662 if (pMark != nullptr)
1664 rSh.GotoMark( pMark );
1665 rSh.getIDocumentMarkAccess()->deleteMark( pMark );
1668 return bResult;
1672 // special case for tables from draw application or 1-cell tables
1673 if( EXCHG_OUT_ACTION_INSERT_DRAWOBJ == nAction || bSingleCellTable )
1675 if( rData.HasFormat( SotClipboardFormatId::RTF ) )
1677 nAction = EXCHG_OUT_ACTION_INSERT_STRING;
1678 nFormat = SotClipboardFormatId::RTF;
1680 else if( rData.HasFormat( SotClipboardFormatId::RICHTEXT ) )
1682 nAction = EXCHG_OUT_ACTION_INSERT_STRING;
1683 nFormat = SotClipboardFormatId::RICHTEXT;
1687 // Tweak the format if necessary: the source application can be considered in this context,
1688 // while not in sot/ code.
1689 SwTransferable::SelectPasteFormat(rData, nAction, nFormat);
1691 collectUIInformation(u"PASTE"_ustr, u"parameter"_ustr);
1693 return EXCHG_INOUT_ACTION_NONE != nAction &&
1694 SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
1695 nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, ePasteTable);
1698 bool SwTransferable::PasteData( const TransferableDataHelper& rData,
1699 SwWrtShell& rSh, sal_uInt8 nAction, SotExchangeActionFlags nActionFlags,
1700 SotClipboardFormatId nFormat,
1701 SotExchangeDest nDestination, bool bIsPasteFormat,
1702 [[maybe_unused]] bool bIsDefault,
1703 const Point* pPt, sal_Int8 nDropAction,
1704 bool bPasteSelection, RndStdIds nAnchorType,
1705 bool bIgnoreComments,
1706 SwPasteContext* pContext,
1707 PasteTableType ePasteTable )
1709 SwWait aWait( *rSh.GetView().GetDocShell(), false );
1710 std::unique_ptr<SwTrnsfrActionAndUndo, o3tl::default_delete<SwTrnsfrActionAndUndo>> pAction;
1711 SwModule* pMod = SwModule::get();
1713 bool bRet = false;
1714 bool bCallAutoCaption = false;
1716 if( pPt )
1718 // external Drop
1719 if ((bPasteSelection ? !pMod->m_pXSelection : !pMod->m_pDragDrop) &&
1720 // The following condition is used for tdf#156111 to prevent a selection from being
1721 // cleared by the default case of the nDestination switch.
1722 !(rSh.GetCursorCnt() == 1 && rSh.TestCurrPam(*pPt) &&
1723 nDestination == SotExchangeDest::SWDOC_FREE_AREA &&
1724 nFormat == SotClipboardFormatId::SONLK))
1726 switch( nDestination )
1728 case SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP:
1729 case SotExchangeDest::DOC_LNKD_GRAPHOBJ:
1730 case SotExchangeDest::DOC_GRAPH_W_IMAP:
1731 case SotExchangeDest::DOC_GRAPHOBJ:
1732 case SotExchangeDest::DOC_OLEOBJ:
1733 case SotExchangeDest::DOC_DRAWOBJ:
1734 case SotExchangeDest::DOC_URLBUTTON:
1735 case SotExchangeDest::DOC_GROUPOBJ:
1736 // select frames/objects
1737 SwTransferable::SetSelInShell( rSh, true, pPt );
1738 break;
1740 default:
1741 bool bLockView = rSh.IsViewLocked();
1742 if (nFormat == SotClipboardFormatId::SONLK)
1743 rSh.LockView(true); // prevent view jump
1744 SwTransferable::SetSelInShell( rSh, false, pPt );
1745 rSh.LockView(bLockView);
1746 break;
1750 else if( ( !GetSwTransferable( rData ) || bIsPasteFormat ) &&
1751 !rSh.IsTableMode() && rSh.HasSelection() )
1753 // then delete the selections
1755 //don't delete selected content
1756 // - at table-selection
1757 // - at ReRead of a graphic/DDEData
1758 // - at D&D, for the right selection was taken care of
1759 // in Drop-Handler
1760 bool bDelSel = false;
1761 switch( nDestination )
1763 case SotExchangeDest::DOC_TEXTFRAME:
1764 case SotExchangeDest::SWDOC_FREE_AREA:
1765 case SotExchangeDest::DOC_TEXTFRAME_WEB:
1766 case SotExchangeDest::SWDOC_FREE_AREA_WEB:
1767 bDelSel = true;
1768 break;
1769 default:
1770 break;
1773 if( bDelSel )
1774 // #i34830#
1775 pAction.reset(new SwTrnsfrActionAndUndo(&rSh, true, pContext));
1778 SwTransferable *pTrans=nullptr, *pTunneledTrans=GetSwTransferable( rData );
1780 // check for private drop
1781 bool bPrivateDrop(pPt);
1782 if (bPrivateDrop)
1784 if (bPasteSelection)
1785 pTrans = pMod->m_pXSelection;
1786 else
1787 pTrans = pMod->m_pDragDrop;
1788 bPrivateDrop = nullptr != pTrans;
1790 bool bNeedToSelectBeforePaste(false);
1792 if(bPrivateDrop && DND_ACTION_LINK == nDropAction)
1794 // internal drop on object, suppress bPrivateDrop to change internal fill
1795 bPrivateDrop = false;
1796 bNeedToSelectBeforePaste = true;
1799 if(bPrivateDrop && pPt && DND_ACTION_MOVE == nDropAction)
1801 // check if dragged over a useful target. If yes, use as content exchange
1802 // drop as if from external
1803 const SwFrameFormat* pSwFrameFormat = rSh.GetFormatFromObj(*pPt);
1805 if(dynamic_cast< const SwDrawFrameFormat* >(pSwFrameFormat))
1807 bPrivateDrop = false;
1808 bNeedToSelectBeforePaste = true;
1812 if(bPrivateDrop)
1814 // then internal Drag & Drop or XSelection
1815 bRet = pTrans->PrivateDrop( rSh, *pPt, DND_ACTION_MOVE == nDropAction,
1816 bPasteSelection );
1818 else if( !pPt && pTunneledTrans &&
1819 EXCHG_OUT_ACTION_INSERT_PRIVATE == nAction )
1821 // then internal paste
1822 bRet = pTunneledTrans->PrivatePaste(rSh, pContext, ePasteTable);
1824 else if( EXCHG_INOUT_ACTION_NONE != nAction )
1826 if( !pAction )
1828 pAction.reset(new SwTrnsfrActionAndUndo( &rSh ));
1831 // in Drag&Drop MessageBoxes must not be showed
1832 bool bMsg = nullptr == pPt;
1834 // delete selections
1836 switch( nAction )
1838 case EXCHG_OUT_ACTION_INSERT_PRIVATE:
1839 OSL_ENSURE( pPt, "EXCHG_OUT_ACTION_INSERT_PRIVATE: what should happen here?" );
1840 break;
1842 case EXCHG_OUT_ACTION_MOVE_PRIVATE:
1843 OSL_ENSURE( pPt, "EXCHG_OUT_ACTION_MOVE_PRIVATE: what should happen here?" );
1844 break;
1846 case EXCHG_IN_ACTION_MOVE:
1847 case EXCHG_IN_ACTION_COPY:
1848 case EXCHG_IN_ACTION_LINK:
1849 case EXCHG_OUT_ACTION_INSERT_HTML:
1850 case EXCHG_OUT_ACTION_INSERT_STRING:
1851 case EXCHG_OUT_ACTION_INSERT_IMAGEMAP:
1852 case EXCHG_OUT_ACTION_REPLACE_IMAGEMAP:
1854 // then we have to use the format
1855 switch( nFormat )
1857 case SotClipboardFormatId::DRAWING:
1858 bRet = SwTransferable::PasteSdrFormat( rData, rSh,
1859 SwPasteSdr::Insert, pPt,
1860 nActionFlags, bNeedToSelectBeforePaste);
1861 break;
1863 case SotClipboardFormatId::HTML:
1864 case SotClipboardFormatId::HTML_SIMPLE:
1865 case SotClipboardFormatId::HTML_NO_COMMENT:
1866 case SotClipboardFormatId::RTF:
1867 case SotClipboardFormatId::RICHTEXT:
1868 case SotClipboardFormatId::STRING:
1869 bRet = SwTransferable::PasteFileContent( rData, rSh,
1870 nFormat, bMsg, bIgnoreComments );
1871 break;
1873 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
1875 INetBookmark aBkmk;
1876 if( rData.GetINetBookmark( nFormat, aBkmk ) )
1878 SwFormatINetFormat aFormat( aBkmk.GetURL(), OUString() );
1879 rSh.InsertURL( aFormat, aBkmk.GetDescription() );
1880 bRet = true;
1883 break;
1885 case SotClipboardFormatId::SD_OLE:
1886 bRet = SwTransferable::PasteOLE( rData, rSh, nFormat,
1887 nActionFlags, bMsg );
1888 break;
1890 case SotClipboardFormatId::SVIM:
1891 bRet = SwTransferable::PasteImageMap( rData, rSh );
1892 break;
1894 case SotClipboardFormatId::SVXB:
1895 case SotClipboardFormatId::BITMAP:
1896 case SotClipboardFormatId::PNG:
1897 case SotClipboardFormatId::GDIMETAFILE:
1898 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
1899 SwPasteSdr::Insert,pPt,
1900 nActionFlags, nDropAction, bNeedToSelectBeforePaste);
1901 break;
1903 case SotClipboardFormatId::XFORMS:
1904 case SotClipboardFormatId::SBA_FIELDDATAEXCHANGE:
1905 case SotClipboardFormatId::SBA_DATAEXCHANGE:
1906 case SotClipboardFormatId::SBA_CTRLDATAEXCHANGE:
1907 bRet = SwTransferable::PasteDBData( rData, rSh, nFormat,
1908 EXCHG_IN_ACTION_LINK == nAction,
1909 pPt, bMsg );
1910 break;
1912 case SotClipboardFormatId::SIMPLE_FILE:
1913 bRet = SwTransferable::PasteFileName( rData, rSh, nFormat,
1914 ( EXCHG_IN_ACTION_MOVE == nAction
1915 ? SwPasteSdr::Replace
1916 : EXCHG_IN_ACTION_LINK == nAction
1917 ? SwPasteSdr::SetAttr
1918 : SwPasteSdr::Insert),
1919 pPt, nActionFlags, nullptr );
1920 break;
1922 case SotClipboardFormatId::FILE_LIST:
1923 // then insert as graphics only
1924 bRet = SwTransferable::PasteFileList( rData, rSh,
1925 EXCHG_IN_ACTION_LINK == nAction,
1926 pPt, bMsg );
1927 break;
1929 case SotClipboardFormatId::SONLK:
1930 if( pPt )
1932 NaviContentBookmark aBkmk;
1933 if (aBkmk.Paste(rData, rSh.GetSelText()))
1935 aWait.~SwWait(); // end the wait pointer, X11 only annoyance
1936 rSh.NavigatorPaste(aBkmk);
1937 bRet = true;
1940 break;
1942 case SotClipboardFormatId::INET_IMAGE:
1943 case SotClipboardFormatId::NETSCAPE_IMAGE:
1944 bRet = SwTransferable::PasteTargetURL( rData, rSh,
1945 SwPasteSdr::Insert,
1946 pPt, true );
1947 break;
1949 default:
1950 OSL_ENSURE( pPt, "unknown format" );
1952 break;
1954 case EXCHG_OUT_ACTION_INSERT_FILE:
1956 bool graphicInserted;
1957 bRet = SwTransferable::PasteFileName( rData, rSh, nFormat,
1958 SwPasteSdr::Insert, pPt,
1959 nActionFlags,
1960 &graphicInserted );
1961 if( graphicInserted )
1962 bCallAutoCaption = true;
1964 break;
1966 case EXCHG_OUT_ACTION_INSERT_OLE:
1967 bRet = SwTransferable::PasteOLE( rData, rSh, nFormat,
1968 nActionFlags,bMsg );
1969 break;
1971 case EXCHG_OUT_ACTION_INSERT_DDE:
1973 bool bReRead = 0 != CNT_HasGrf( rSh.GetCntType() );
1974 bRet = SwTransferable::PasteDDE( rData, rSh, bReRead, bMsg );
1976 break;
1978 case EXCHG_OUT_ACTION_INSERT_HYPERLINK:
1980 OUString sURL, sDesc;
1981 if( SotClipboardFormatId::SIMPLE_FILE == nFormat )
1983 if( rData.GetString( nFormat, sURL ) && !sURL.isEmpty() )
1985 SwTransferable::CheckForURLOrLNKFile( rData, sURL, &sDesc );
1986 if( sDesc.isEmpty() )
1987 sDesc = sURL;
1988 bRet = true;
1991 else
1993 INetBookmark aBkmk;
1994 if( rData.GetINetBookmark( nFormat, aBkmk ) )
1996 sURL = aBkmk.GetURL();
1997 sDesc = aBkmk.GetDescription();
1998 bRet = true;
2002 if( bRet )
2004 SwFormatINetFormat aFormat( sURL, OUString() );
2005 rSh.InsertURL( aFormat, sDesc );
2008 break;
2010 case EXCHG_OUT_ACTION_GET_ATTRIBUTES:
2011 switch( nFormat )
2013 case SotClipboardFormatId::DRAWING:
2014 bRet = SwTransferable::PasteSdrFormat( rData, rSh,
2015 SwPasteSdr::SetAttr, pPt,
2016 nActionFlags, bNeedToSelectBeforePaste);
2017 break;
2018 case SotClipboardFormatId::SVXB:
2019 case SotClipboardFormatId::GDIMETAFILE:
2020 case SotClipboardFormatId::BITMAP:
2021 case SotClipboardFormatId::PNG:
2022 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
2023 case SotClipboardFormatId::SIMPLE_FILE:
2024 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
2025 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
2026 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
2027 SwPasteSdr::SetAttr, pPt,
2028 nActionFlags, nDropAction, bNeedToSelectBeforePaste);
2029 break;
2030 default:
2031 OSL_FAIL( "unknown format" );
2034 break;
2036 case EXCHG_OUT_ACTION_INSERT_DRAWOBJ:
2037 bRet = SwTransferable::PasteSdrFormat( rData, rSh,
2038 SwPasteSdr::Insert, pPt,
2039 nActionFlags, bNeedToSelectBeforePaste);
2040 break;
2041 case EXCHG_OUT_ACTION_INSERT_SVXB:
2042 case EXCHG_OUT_ACTION_INSERT_GDIMETAFILE:
2043 case EXCHG_OUT_ACTION_INSERT_BITMAP:
2044 case EXCHG_OUT_ACTION_INSERT_GRAPH:
2045 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
2046 SwPasteSdr::Insert, pPt,
2047 nActionFlags, nDropAction, bNeedToSelectBeforePaste, nAnchorType );
2048 break;
2050 case EXCHG_OUT_ACTION_REPLACE_DRAWOBJ:
2051 bRet = SwTransferable::PasteSdrFormat( rData, rSh,
2052 SwPasteSdr::Replace, pPt,
2053 nActionFlags, bNeedToSelectBeforePaste);
2054 break;
2056 case EXCHG_OUT_ACTION_REPLACE_SVXB:
2057 case EXCHG_OUT_ACTION_REPLACE_GDIMETAFILE:
2058 case EXCHG_OUT_ACTION_REPLACE_BITMAP:
2059 case EXCHG_OUT_ACTION_REPLACE_GRAPH:
2060 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
2061 SwPasteSdr::Replace,pPt,
2062 nActionFlags, nDropAction, bNeedToSelectBeforePaste);
2063 break;
2065 case EXCHG_OUT_ACTION_INSERT_INTERACTIVE:
2066 bRet = SwTransferable::PasteAsHyperlink( rData, rSh, nFormat );
2067 break;
2069 default:
2070 OSL_FAIL("unknown action" );
2074 if( !bPasteSelection && rSh.IsFrameSelected() )
2076 rSh.EnterSelFrameMode();
2077 //force ::SelectShell
2078 rSh.GetView().StopShellTimer();
2081 pAction.reset();
2082 if( bCallAutoCaption )
2083 rSh.GetView().AutoCaption( GRAPHIC_CAP );
2085 return bRet;
2088 SotExchangeDest SwTransferable::GetSotDestination( const SwWrtShell& rSh )
2090 SotExchangeDest nRet = SotExchangeDest::NONE;
2092 ObjCntType eOType = rSh.GetObjCntTypeOfSelection();
2094 switch( eOType )
2096 case OBJCNT_GRF:
2098 bool bIMap, bLink;
2099 bIMap = nullptr != rSh.GetFlyFrameFormat()->GetURL().GetMap();
2100 OUString aDummy;
2101 rSh.GetGrfNms( &aDummy, nullptr );
2102 bLink = !aDummy.isEmpty();
2104 if( bLink && bIMap )
2105 nRet = SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP;
2106 else if( bLink )
2107 nRet = SotExchangeDest::DOC_LNKD_GRAPHOBJ;
2108 else if( bIMap )
2109 nRet = SotExchangeDest::DOC_GRAPH_W_IMAP;
2110 else
2111 nRet = SotExchangeDest::DOC_GRAPHOBJ;
2113 break;
2115 case OBJCNT_FLY:
2116 if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr )
2117 nRet = SotExchangeDest::DOC_TEXTFRAME_WEB;
2118 else
2119 nRet = SotExchangeDest::DOC_TEXTFRAME;
2120 break;
2121 case OBJCNT_OLE: nRet = SotExchangeDest::DOC_OLEOBJ; break;
2123 case OBJCNT_CONTROL: /* no Action avail */
2124 case OBJCNT_SIMPLE: nRet = SotExchangeDest::DOC_DRAWOBJ; break;
2125 case OBJCNT_URLBUTTON: nRet = SotExchangeDest::DOC_URLBUTTON; break;
2126 case OBJCNT_GROUPOBJ: nRet = SotExchangeDest::DOC_GROUPOBJ; break;
2128 // what do we do at multiple selections???
2129 default:
2131 if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr )
2132 nRet = SotExchangeDest::SWDOC_FREE_AREA_WEB;
2133 else
2134 nRet = SotExchangeDest::SWDOC_FREE_AREA;
2138 return nRet;
2141 namespace
2143 bool CanSkipInvalidateNumRules(const SwPosition& rInsertPosition)
2145 SwTextNode* pTextNode = rInsertPosition.GetNode().GetTextNode();
2146 if (!pTextNode)
2148 return false;
2151 const SwNodeNum* pNum = pTextNode->GetNum();
2152 if (pNum)
2154 SwNumRule* pNumRule = pNum->GetNumRule();
2155 if (pNumRule)
2157 const SvxNumberType rType = pNumRule->Get(pTextNode->GetActualListLevel());
2158 if (rType.GetNumberingType() == SVX_NUM_CHAR_SPECIAL)
2160 // Bullet list, skip invalidation.
2161 return true;
2165 // Numbered list, invalidate.
2166 return false;
2169 // Not a list, skip invalidation.
2170 return true;
2174 bool SwTransferable::PasteFileContent( const TransferableDataHelper& rData,
2175 SwWrtShell& rSh, SotClipboardFormatId nFormat, bool bMsg, bool bIgnoreComments )
2177 bool bRet = false;
2179 MSE40HTMLClipFormatObj aMSE40ClpObj;
2181 std::unique_ptr<SvStream> xStrm;
2182 SvStream* pStream = nullptr;
2183 Reader* pRead = nullptr;
2184 OUString sData;
2185 bool bSkipInvalidateNumRules = false;
2186 switch( nFormat )
2188 case SotClipboardFormatId::STRING:
2190 pRead = ReadAscii;
2192 const SwPosition& rInsertPosition = *rSh.GetCursor()->Start();
2193 if (CanSkipInvalidateNumRules(rInsertPosition))
2195 // Insertion point is not a numbering and we paste plain text: then no need to
2196 // invalidate all numberings.
2197 bSkipInvalidateNumRules = true;
2200 if( rData.GetString( nFormat, sData ) )
2202 pStream = new SvMemoryStream( const_cast<sal_Unicode *>(sData.getStr()),
2203 sData.getLength() * sizeof( sal_Unicode ),
2204 StreamMode::READ );
2205 #ifdef OSL_BIGENDIAN
2206 pStream->SetEndian( SvStreamEndian::BIG );
2207 #else
2208 pStream->SetEndian( SvStreamEndian::LITTLE );
2209 #endif
2211 SwAsciiOptions aAOpt;
2212 aAOpt.SetCharSet( RTL_TEXTENCODING_UCS2 );
2213 pRead->GetReaderOpt().SetASCIIOpts( aAOpt );
2214 break;
2217 [[fallthrough]]; // because then test if we get a stream
2219 default:
2220 if( (xStrm = rData.GetSotStorageStream( nFormat )) )
2222 if( ( SotClipboardFormatId::HTML_SIMPLE == nFormat ) ||
2223 ( SotClipboardFormatId::HTML_NO_COMMENT == nFormat ) )
2225 pStream = aMSE40ClpObj.IsValid( *xStrm );
2226 pRead = ReadHTML;
2227 pRead->SetReadUTF8( true );
2229 bool bNoComments =
2230 ( nFormat == SotClipboardFormatId::HTML_NO_COMMENT );
2231 pRead->SetIgnoreHTMLComments( bNoComments );
2233 else
2235 pStream = xStrm.get();
2236 if( SotClipboardFormatId::RTF == nFormat || SotClipboardFormatId::RICHTEXT == nFormat)
2237 pRead = SwReaderWriter::GetRtfReader();
2238 else if( !pRead )
2240 pRead = ReadHTML;
2241 pRead->SetReadUTF8( true );
2245 break;
2248 TranslateId pResId;
2249 if( pStream && pRead )
2251 Link<LinkParamNone*,void> aOldLink( rSh.GetChgLnk() );
2252 rSh.SetChgLnk( Link<LinkParamNone*,void>() );
2254 const SwPosition& rInsPos = *rSh.GetCursor()->Start();
2255 SwReader aReader(*pStream, OUString(), OUString(), *rSh.GetCursor());
2256 rSh.SaveTableBoxContent( &rInsPos );
2258 if (bIgnoreComments)
2259 pRead->SetIgnoreHTMLComments(true);
2260 if (bSkipInvalidateNumRules)
2262 aReader.SetSkipInvalidateNumRules(bSkipInvalidateNumRules);
2265 if( aReader.Read( *pRead ).IsError() )
2266 pResId = STR_ERROR_CLPBRD_READ;
2267 else
2269 pResId = TranslateId();
2270 bRet = true;
2273 rSh.SetChgLnk( aOldLink );
2274 if( bRet )
2275 rSh.CallChgLnk();
2277 else
2278 pResId = STR_CLPBRD_FORMAT_ERROR;
2280 // Exist a SvMemoryStream? (data in the OUString and xStrm is empty)
2281 if( pStream && !xStrm )
2282 delete pStream;
2284 if (bMsg && pResId)
2286 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2287 VclMessageType::Info, VclButtonsType::Ok,
2288 SwResId(pResId)));
2289 xBox->run();
2291 return bRet;
2294 bool SwTransferable::PasteOLE( const TransferableDataHelper& rData, SwWrtShell& rSh,
2295 SotClipboardFormatId nFormat, SotExchangeActionFlags nActionFlags, bool bMsg )
2297 bool bRet = false;
2298 TransferableObjectDescriptor aObjDesc;
2299 uno::Reference < io::XInputStream > xStrm;
2300 uno::Reference < embed::XStorage > xStore;
2301 Reader* pRead = nullptr;
2303 // Get the preferred format
2304 SotClipboardFormatId nId;
2305 if( rData.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ ) )
2306 nId = SotClipboardFormatId::EMBEDDED_OBJ;
2307 else if( rData.HasFormat( SotClipboardFormatId::EMBED_SOURCE ) &&
2308 rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ))
2309 nId = SotClipboardFormatId::EMBED_SOURCE;
2310 else
2311 nId = SotClipboardFormatId::NONE;
2313 if (nId != SotClipboardFormatId::NONE)
2315 SwDocShell* pDocSh = rSh.GetDoc()->GetDocShell();
2316 xStrm = rData.GetInputStream(nId, SfxObjectShell::CreateShellID(pDocSh));
2319 if (xStrm.is())
2321 // if there is an embedded object, first try if it's a writer object
2322 // this will be inserted into the document by using a Reader
2325 xStore = comphelper::OStorageHelper::GetStorageFromInputStream( xStrm );
2326 switch( SotStorage::GetFormatID( xStore ) )
2328 case SotClipboardFormatId::STARWRITER_60:
2329 case SotClipboardFormatId::STARWRITERWEB_60:
2330 case SotClipboardFormatId::STARWRITERGLOB_60:
2331 case SotClipboardFormatId::STARWRITER_8:
2332 case SotClipboardFormatId::STARWRITERWEB_8:
2333 case SotClipboardFormatId::STARWRITERGLOB_8:
2334 pRead = ReadXML;
2335 break;
2336 default:
2339 xStore->dispose();
2340 xStore = nullptr;
2342 catch (const uno::Exception&)
2346 break;
2349 catch (const uno::Exception&)
2351 // it wasn't a storage, but maybe it's a useful stream
2355 if( pRead )
2357 SwPaM &rPAM = *rSh.GetCursor();
2358 SwReader aReader(xStore, OUString(), rPAM);
2359 aReader.SetInPaste(true);
2360 if( ! aReader.Read( *pRead ).IsError() )
2361 bRet = true;
2362 else if( bMsg )
2364 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2365 VclMessageType::Info, VclButtonsType::Ok,
2366 SwResId(STR_ERROR_CLPBRD_READ)));
2367 xBox->run();
2370 else
2372 // temporary storage until the object is inserted
2373 uno::Reference< embed::XStorage > xTmpStor;
2374 uno::Reference < embed::XEmbeddedObject > xObj;
2375 OUString aName;
2376 comphelper::EmbeddedObjectContainer aCnt;
2378 if ( xStrm.is() )
2380 if ( !rData.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
2382 OSL_ENSURE( !xStrm.is(), "An object without descriptor in clipboard!");
2385 else
2387 if( rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR_OLE ) && rData.GetTransferableObjectDescriptor( nFormat, aObjDesc ) )
2389 xStrm = rData.GetInputStream(SotClipboardFormatId::EMBED_SOURCE_OLE, OUString());
2390 if (!xStrm.is())
2391 xStrm = rData.GetInputStream(SotClipboardFormatId::EMBEDDED_OBJ_OLE, OUString());
2393 if ( !xStrm.is() )
2395 // This is MSOLE object that should be created by direct using of system clipboard
2398 xTmpStor = ::comphelper::OStorageHelper::GetTemporaryStorage();
2399 uno::Reference < embed::XEmbedObjectClipboardCreator > xClipboardCreator =
2400 embed::MSOLEObjectSystemCreator::create( ::comphelper::getProcessComponentContext() );
2402 embed::InsertedObjectInfo aInfo = xClipboardCreator->createInstanceInitFromClipboard(
2403 xTmpStor,
2404 u"DummyName"_ustr,
2405 uno::Sequence< beans::PropertyValue >() );
2407 // TODO/LATER: in future InsertedObjectInfo will be used to get container related information
2408 // for example whether the object should be an iconified one
2409 xObj = aInfo.Object;
2411 catch (const uno::Exception&)
2416 else if (rData.HasFormat(SotClipboardFormatId::SIMPLE_FILE))
2418 OUString sFile;
2419 if (rData.GetString(nFormat, sFile) && !sFile.isEmpty())
2421 // Copied from sd::View::DropInsertFileHdl
2422 uno::Sequence< beans::PropertyValue > aMedium{ comphelper::makePropertyValue(
2423 u"URL"_ustr, sFile) };
2424 SwDocShell* pDocSh = rSh.GetDoc()->GetDocShell();
2425 xObj = pDocSh->GetEmbeddedObjectContainer().InsertEmbeddedObject(aMedium, aName);
2430 if ( xStrm.is() && !xObj.is() )
2431 xObj = aCnt.InsertEmbeddedObject( xStrm, aName );
2433 if( xObj.is() )
2435 svt::EmbeddedObjectRef xObjRef( xObj, aObjDesc.mnViewAspect );
2437 // try to get the replacement image from the clipboard
2438 Graphic aGraphic;
2439 SotClipboardFormatId nGrFormat = SotClipboardFormatId::NONE;
2441 // limit the size of the preview metafile to 100000 actions
2442 GDIMetaFile aMetafile;
2443 if (rData.GetGDIMetaFile(SotClipboardFormatId::GDIMETAFILE, aMetafile, 100000))
2445 nGrFormat = SotClipboardFormatId::GDIMETAFILE;
2446 aGraphic = aMetafile;
2449 // insert replacement image ( if there is one ) into the object helper
2450 if ( nGrFormat != SotClipboardFormatId::NONE )
2452 DataFlavor aDataFlavor;
2453 SotExchange::GetFormatDataFlavor( nGrFormat, aDataFlavor );
2454 xObjRef.SetGraphic( aGraphic, aDataFlavor.MimeType );
2456 else if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON )
2458 // it is important to have an icon, let an empty graphic be used
2459 // if no other graphic is provided
2460 // TODO/LATER: in future a default bitmap could be used
2461 MapMode aMapMode( MapUnit::Map100thMM );
2462 aGraphic.SetPrefSize( Size( 2500, 2500 ) );
2463 aGraphic.SetPrefMapMode( aMapMode );
2464 xObjRef.SetGraphic( aGraphic, OUString() );
2467 //set size. This is a hack because of handing over, size should be
2468 //passed to the InsertOle!!!!!!!!!!
2469 Size aSize;
2470 if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON )
2472 if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
2473 aSize = aObjDesc.maSize;
2474 else
2476 MapMode aMapMode( MapUnit::Map100thMM );
2477 aSize = xObjRef.GetSize( &aMapMode );
2480 else if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
2482 aSize = aObjDesc.maSize; //always 100TH_MM
2483 MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( aObjDesc.mnViewAspect ) );
2484 aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aUnit));
2485 awt::Size aSz;
2488 aSz = xObj->getVisualAreaSize( aObjDesc.mnViewAspect );
2490 catch (const embed::NoVisualAreaSizeException&)
2492 // in this case the provided size is used
2495 if ( aSz.Width != aSize.Width() || aSz.Height != aSize.Height() )
2497 aSz.Width = aSize.Width();
2498 aSz.Height = aSize.Height();
2499 xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz );
2502 else
2504 // the descriptor contains the wrong object size
2505 // the following call will let the MSOLE objects cache the size if it is possible
2506 // it should be done while the object is running
2509 xObj->getVisualAreaSize( aObjDesc.mnViewAspect );
2511 catch (const uno::Exception&)
2515 //End of Hack!
2517 rSh.InsertOleObject( xObjRef );
2518 bRet = true;
2520 if( bRet && ( nActionFlags & SotExchangeActionFlags::InsertTargetUrl) )
2521 SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
2523 // let the object be unloaded if possible
2524 SwOLEObj::UnloadObject( xObj, rSh.GetDoc(), embed::Aspects::MSOLE_CONTENT );
2527 return bRet;
2530 bool SwTransferable::PasteTargetURL( const TransferableDataHelper& rData,
2531 SwWrtShell& rSh, SwPasteSdr nAction,
2532 const Point* pPt, bool bInsertGRF )
2534 bool bRet = false;
2535 INetImage aINetImg;
2536 if( ( rData.HasFormat( SotClipboardFormatId::INET_IMAGE ) &&
2537 rData.GetINetImage( SotClipboardFormatId::INET_IMAGE, aINetImg )) ||
2538 ( rData.HasFormat( SotClipboardFormatId::NETSCAPE_IMAGE ) &&
2539 rData.GetINetImage( SotClipboardFormatId::NETSCAPE_IMAGE, aINetImg )) )
2541 if( !aINetImg.GetImageURL().isEmpty() && bInsertGRF )
2543 OUString sURL( aINetImg.GetImageURL() );
2544 SwTransferable::CheckForURLOrLNKFile( rData, sURL );
2546 //!!! check at FileSystem - only then it makes sense to test graphics !!!
2547 Graphic aGraphic;
2548 GraphicFilter &rFlt = GraphicFilter::GetGraphicFilter();
2549 bRet = ERRCODE_NONE == GraphicFilter::LoadGraphic(sURL, OUString(), aGraphic, &rFlt);
2551 if( bRet )
2553 //Check and Perform rotation if needed
2554 lclCheckAndPerformRotation(aGraphic);
2556 switch( nAction )
2558 case SwPasteSdr::Insert:
2559 SwTransferable::SetSelInShell( rSh, false, pPt );
2560 rSh.InsertGraphic(sURL, OUString(), aGraphic);
2561 break;
2563 case SwPasteSdr::Replace:
2564 if( rSh.IsObjSelected() )
2566 rSh.ReplaceSdrObj( sURL, &aGraphic );
2567 Point aPt( pPt ? *pPt : rSh.GetCursorDocPos() );
2568 SwTransferable::SetSelInShell( rSh, true, &aPt );
2570 else
2571 rSh.ReRead(sURL, OUString(), &aGraphic);
2572 break;
2574 case SwPasteSdr::SetAttr:
2575 if( rSh.IsObjSelected() )
2576 rSh.Paste( aGraphic, OUString() );
2577 else if( OBJCNT_GRF == rSh.GetObjCntTypeOfSelection() )
2578 rSh.ReRead(sURL, OUString(), &aGraphic);
2579 else
2581 SwTransferable::SetSelInShell( rSh, false, pPt );
2582 rSh.InsertGraphic(sURL, OUString(), aGraphic);
2584 break;
2585 default:
2586 bRet = false;
2590 else
2591 bRet = true;
2594 if( bRet )
2596 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
2597 rSh.GetFlyFrameAttr( aSet );
2598 SwFormatURL aURL( aSet.Get( RES_URL ) );
2600 if( aURL.GetURL() != aINetImg.GetTargetURL() ||
2601 aURL.GetTargetFrameName() != aINetImg.GetTargetFrame() )
2603 aURL.SetURL( aINetImg.GetTargetURL(), false );
2604 aURL.SetTargetFrameName( aINetImg.GetTargetFrame() );
2605 aSet.Put( aURL );
2606 rSh.SetFlyFrameAttr( aSet );
2609 return bRet;
2612 void SwTransferable::SetSelInShell( SwWrtShell& rSh, bool bSelectFrame,
2613 const Point* pPt )
2615 if( bSelectFrame )
2617 // select frames/objects
2618 if( pPt && !rSh.GetView().GetViewFrame().GetDispatcher()->IsLocked() )
2620 rSh.GetView().NoRotate();
2621 if( rSh.SelectObj( *pPt ))
2623 rSh.HideCursor();
2624 rSh.EnterSelFrameMode( pPt );
2625 g_bFrameDrag = true;
2629 else
2631 if( rSh.IsFrameSelected() || rSh.IsObjSelected() )
2633 rSh.UnSelectFrame();
2634 rSh.LeaveSelFrameMode();
2635 rSh.GetView().GetEditWin().StopInsFrame();
2636 g_bFrameDrag = false;
2638 else if( rSh.GetView().GetDrawFuncPtr() )
2639 rSh.GetView().GetEditWin().StopInsFrame();
2641 rSh.EnterStdMode();
2642 if( pPt )
2643 rSh.SwCursorShell::SetCursor( *pPt, true );
2647 bool SwTransferable::PasteDDE( const TransferableDataHelper& rData,
2648 SwWrtShell& rWrtShell, bool bReReadGrf,
2649 bool bMsg )
2651 // data from Clipboardformat
2652 OUString aApp, aTopic, aItem;
2654 if (!rData.ReadDDELink(aApp, aTopic, aItem, o3tl::temporary(OUString())))
2656 return false;
2657 } // report useful error!!
2659 OUString aCmd;
2660 sfx2::MakeLnkName( aCmd, &aApp, aTopic, aItem );
2662 // do we want to read in a graphic now?
2663 SotClipboardFormatId nFormat;
2664 if( !rData.HasFormat( SotClipboardFormatId::RTF ) &&
2665 !rData.HasFormat( SotClipboardFormatId::RICHTEXT ) &&
2666 !rData.HasFormat( SotClipboardFormatId::HTML ) &&
2667 !rData.HasFormat( SotClipboardFormatId::STRING ) &&
2668 (rData.HasFormat( nFormat = SotClipboardFormatId::GDIMETAFILE ) ||
2669 rData.HasFormat( nFormat = SotClipboardFormatId::BITMAP )) )
2671 Graphic aGrf;
2672 bool bRet = rData.GetGraphic( nFormat, aGrf );
2673 if( bRet )
2675 OUString sLnkTyp(u"DDE"_ustr);
2676 if ( bReReadGrf )
2677 rWrtShell.ReRead( aCmd, sLnkTyp, &aGrf );
2678 else
2679 rWrtShell.InsertGraphic( aCmd, sLnkTyp, aGrf );
2681 return bRet;
2684 SwFieldType* pTyp = nullptr;
2685 size_t i = 1;
2686 size_t j;
2687 OUString aName;
2688 bool bDoublePaste = false;
2689 const size_t nSize = rWrtShell.GetFieldTypeCount();
2690 const ::utl::TransliterationWrapper& rColl = ::GetAppCmpStrIgnore();
2692 do {
2693 aName = aApp + OUString::number( i );
2694 for( j = INIT_FLDTYPES; j < nSize; j++ )
2696 pTyp = rWrtShell.GetFieldType( j );
2697 if( SwFieldIds::Dde == pTyp->Which() )
2699 if( rColl.isEqual( static_cast<SwDDEFieldType*>(pTyp)->GetCmd(), aCmd ) &&
2700 SfxLinkUpdateMode::ALWAYS == static_cast<SwDDEFieldType*>(pTyp)->GetType() )
2702 aName = pTyp->GetName();
2703 bDoublePaste = true;
2704 break;
2706 else if( rColl.isEqual( aName, pTyp->GetName() ) )
2707 break;
2710 if( j == nSize )
2711 break;
2712 ++i;
2714 while( !bDoublePaste );
2716 if( !bDoublePaste )
2718 SwDDEFieldType aType( aName, aCmd, SfxLinkUpdateMode::ALWAYS );
2719 pTyp = rWrtShell.InsertFieldType( aType );
2722 SwDDEFieldType* pDDETyp = static_cast<SwDDEFieldType*>(pTyp);
2724 OUString aExpand;
2725 if( rData.GetString( SotClipboardFormatId::STRING, aExpand ))
2727 do { // middle checked loop
2729 const sal_Int32 nNewlines{comphelper::string::getTokenCount(aExpand, '\n')};
2730 // When data comes from a spreadsheet, we add a DDE-table
2731 if( !aExpand.isEmpty() &&
2732 ( rData.HasFormat( SotClipboardFormatId::SYLK ) ||
2733 rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) )
2735 sal_Int32 nRows = nNewlines ? nNewlines-1 : 0;
2736 if (!aExpand.endsWith("\n"))
2737 ++nRows; // last row has no newline, e.g. one single cell
2738 const sal_Int32 nCols = comphelper::string::getTokenCount(o3tl::getToken(aExpand, 0, '\n'), '\t');
2740 // don't try to insert tables that are too large for writer
2741 if (nRows > SAL_MAX_UINT16 || nCols > SAL_MAX_UINT16)
2743 if( bMsg )
2745 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2746 VclMessageType::Info, VclButtonsType::Ok,
2747 SwResId(STR_TABLE_TOO_LARGE)));
2748 xBox->run();
2750 pDDETyp = nullptr;
2751 break;
2754 // at least one column & row must be there
2755 if( !nRows || !nCols )
2757 if( bMsg )
2759 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2760 VclMessageType::Info, VclButtonsType::Ok,
2761 SwResId(STR_NO_TABLE)));
2762 xBox->run();
2764 pDDETyp = nullptr;
2765 break;
2768 rWrtShell.InsertDDETable(
2769 SwInsertTableOptions( SwInsertTableFlags::SplitLayout, 1 ), // TODO MULTIHEADER
2770 pDDETyp, nRows, nCols );
2772 else if( nNewlines > 1 )
2774 // multiple paragraphs -> insert a protected section
2775 if( rWrtShell.HasSelection() )
2776 rWrtShell.DelRight();
2778 SwSectionData aSect( SectionType::DdeLink, aName );
2779 aSect.SetLinkFileName( aCmd );
2780 aSect.SetProtectFlag(true);
2781 rWrtShell.InsertSection( aSect );
2783 pDDETyp = nullptr; // remove FieldTypes again
2785 else
2787 // insert
2788 SwDDEField aSwDDEField( pDDETyp );
2789 rWrtShell.InsertField2( aSwDDEField );
2792 } while( false );
2794 else
2795 pDDETyp = nullptr; // remove FieldTypes again
2797 if( !pDDETyp && !bDoublePaste )
2799 // remove FieldType again - error occurred!
2800 for( j = nSize; j >= INIT_FLDTYPES; --j )
2801 if( pTyp == rWrtShell.GetFieldType( j ) )
2803 rWrtShell.RemoveFieldType( j );
2804 break;
2808 return true;
2811 bool SwTransferable::PasteSdrFormat( const TransferableDataHelper& rData,
2812 SwWrtShell& rSh, SwPasteSdr nAction,
2813 const Point* pPt, SotExchangeActionFlags nActionFlags, bool bNeedToSelectBeforePaste)
2815 bool bRet = false;
2816 if( std::unique_ptr<SvStream> xStrm = rData.GetSotStorageStream( SotClipboardFormatId::DRAWING ))
2818 xStrm->SetVersion( SOFFICE_FILEFORMAT_50 );
2820 if(bNeedToSelectBeforePaste && pPt)
2822 // if this is an internal drag, need to set the target right (select it), else
2823 // still the source will be selected
2824 SwTransferable::SetSelInShell( rSh, true, pPt );
2827 rSh.Paste( *xStrm, nAction, pPt );
2828 bRet = true;
2830 if( bRet && ( nActionFlags & SotExchangeActionFlags::InsertTargetUrl ))
2831 SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
2833 return bRet;
2836 bool SwTransferable::PasteGrf( const TransferableDataHelper& rData, SwWrtShell& rSh,
2837 SotClipboardFormatId nFormat, SwPasteSdr nAction, const Point* pPt,
2838 SotExchangeActionFlags nActionFlags, sal_Int8 nDropAction, bool bNeedToSelectBeforePaste, RndStdIds nAnchorType )
2840 bool bRet = false;
2842 Graphic aGraphic;
2843 INetBookmark aBkmk;
2844 bool bCheckForGrf = false, bCheckForImageMap = false;
2846 switch( nFormat )
2848 case SotClipboardFormatId::BITMAP:
2849 case SotClipboardFormatId::PNG:
2850 case SotClipboardFormatId::GDIMETAFILE:
2851 bRet = rData.GetGraphic( nFormat, aGraphic );
2852 break;
2854 case SotClipboardFormatId::SVXB:
2856 if (std::unique_ptr<SvStream> xStm = rData.GetSotStorageStream(SotClipboardFormatId::SVXB))
2858 TypeSerializer aSerializer(*xStm);
2859 aSerializer.readGraphic(aGraphic);
2860 bRet = (GraphicType::NONE != aGraphic.GetType() && GraphicType::Default != aGraphic.GetType());
2863 break;
2866 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
2867 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
2868 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
2869 bRet = rData.GetINetBookmark( nFormat, aBkmk );
2870 if( bRet )
2872 if( SwPasteSdr::SetAttr == nAction )
2873 nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK;
2874 else
2875 bCheckForGrf = true;
2877 break;
2879 case SotClipboardFormatId::SIMPLE_FILE:
2881 OUString sText;
2882 bRet = rData.GetString( nFormat, sText );
2883 if( bRet )
2885 OUString sDesc;
2886 SwTransferable::CheckForURLOrLNKFile( rData, sText, &sDesc );
2888 sText = URIHelper::SmartRel2Abs(INetURLObject(), sText, Link<OUString*, bool>(),
2889 false);
2891 #ifdef _WIN32
2892 // Now that the path could be modified after SwTransferable::CheckForURLOrLNKFile,
2893 // where it could have been converted to URL, and made sure it's actually converted
2894 // to URL in URIHelper::SmartRel2Abs, we can finally convert file: URL back to
2895 // system path to make sure we don't use short path.
2896 // It looks not optimal, when we could apply GetLongPathNameW right to the original
2897 // pasted filename. But I don't know if (1) all arriving strings are system paths;
2898 // and (2) if SwTransferable::CheckForURLOrLNKFile could result in a different short
2899 // path, so taking a safe route.
2900 if (sText.startsWithIgnoreAsciiCase("file:"))
2902 // tdf#124500: Convert short path to long path which should be used in links
2903 OUString sSysPath;
2904 osl::FileBase::getSystemPathFromFileURL(sText, sSysPath);
2905 std::unique_ptr<sal_Unicode[]> aBuf(new sal_Unicode[32767]);
2906 DWORD nCopied = GetLongPathNameW(o3tl::toW(sSysPath.getStr()),
2907 o3tl::toW(aBuf.get()), 32767);
2908 if (nCopied && nCopied < 32767)
2909 sText = URIHelper::SmartRel2Abs(INetURLObject(), OUString(aBuf.get()),
2910 Link<OUString*, bool>(), false);
2912 #endif
2914 aBkmk = INetBookmark(sText, sDesc);
2915 bCheckForGrf = true;
2916 bCheckForImageMap = SwPasteSdr::Replace == nAction;
2919 break;
2921 default:
2922 bRet = rData.GetGraphic( nFormat, aGraphic );
2923 break;
2926 if( bCheckForGrf )
2928 //!!! check at FileSystem - only then it makes sense to test the graphics !!!
2929 GraphicFilter &rFlt = GraphicFilter::GetGraphicFilter();
2930 bRet = ERRCODE_NONE == GraphicFilter::LoadGraphic(aBkmk.GetURL(), OUString(),
2931 aGraphic, &rFlt );
2933 if( !bRet && SwPasteSdr::SetAttr == nAction &&
2934 SotClipboardFormatId::SIMPLE_FILE == nFormat &&
2935 // only at frame selection
2936 rSh.IsFrameSelected() )
2938 // then set as hyperlink after the graphic
2939 nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK;
2940 bRet = true;
2944 if(pPt && bNeedToSelectBeforePaste)
2946 // when using internal D&Ds, still the source object is selected and
2947 // this is necessary to get the correct source data which is also
2948 // dependent from selection. After receiving the drag data it is
2949 // now time to select the correct target object
2950 SwTransferable::SetSelInShell( rSh, true, pPt );
2953 if( bRet )
2955 //Check and Perform rotation if needed
2956 lclCheckAndPerformRotation(aGraphic);
2958 OUString sURL;
2959 if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr
2960 // #i123922# if link action is noted, also take URL
2961 || DND_ACTION_LINK == nDropAction)
2963 sURL = aBkmk.GetURL();
2966 switch( nAction )
2968 case SwPasteSdr::Insert:
2970 SwTransferable::SetSelInShell( rSh, false, pPt );
2971 rSh.InsertGraphic(sURL, OUString(), aGraphic, nullptr, nAnchorType);
2972 break;
2975 case SwPasteSdr::Replace:
2977 if( rSh.IsObjSelected() )
2979 // #i123922# for D&D on draw objects, do for now the same for
2980 // SwPasteSdr::Replace (D&D) as for SwPasteSdr::SetAttr (D&D and
2981 // CTRL+SHIFT). The code below replaces the draw object with
2982 // a writer graphic; maybe this is an option later again if wanted
2983 rSh.Paste( aGraphic, sURL );
2985 // rSh.ReplaceSdrObj(sURL, OUString(), &aGraphic);
2986 // Point aPt( pPt ? *pPt : rSh.GetCursorDocPos() );
2987 // SwTransferable::SetSelInShell( rSh, true, &aPt );
2989 else
2991 // set graphic at writer graphic without link
2992 rSh.ReRead(sURL, OUString(), &aGraphic);
2995 break;
2998 case SwPasteSdr::SetAttr:
3000 if( SotClipboardFormatId::NETSCAPE_BOOKMARK == nFormat )
3002 if( rSh.IsFrameSelected() )
3004 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3005 rSh.GetFlyFrameAttr( aSet );
3006 SwFormatURL aURL( aSet.Get( RES_URL ) );
3007 aURL.SetURL( aBkmk.GetURL(), false );
3008 aSet.Put( aURL );
3009 rSh.SetFlyFrameAttr( aSet );
3012 else if( rSh.IsObjSelected() )
3014 // set as attribute at DrawObject
3015 rSh.Paste( aGraphic, sURL );
3017 else if( OBJCNT_GRF == rSh.GetObjCntTypeOfSelection() )
3019 // set as linked graphic at writer graphic frame
3020 rSh.ReRead(sURL, OUString(), &aGraphic);
3022 else
3024 SwTransferable::SetSelInShell( rSh, false, pPt );
3025 rSh.InsertGraphic(aBkmk.GetURL(), OUString(), aGraphic);
3027 break;
3029 default:
3031 bRet = false;
3032 break;
3037 if( bRet )
3040 if( nActionFlags &
3041 ( SotExchangeActionFlags::InsertImageMap | SotExchangeActionFlags::ReplaceImageMap ) )
3042 SwTransferable::PasteImageMap( rData, rSh );
3044 if( nActionFlags & SotExchangeActionFlags::InsertTargetUrl )
3045 SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
3047 else if( bCheckForImageMap )
3049 // or should the file be an ImageMap-File?
3050 ImageMap aMap;
3051 SfxMedium aMed( INetURLObject(aBkmk.GetURL()).GetFull(),
3052 StreamMode::STD_READ );
3053 SvStream* pStream = aMed.GetInStream();
3054 if( pStream != nullptr &&
3055 !pStream->GetError() &&
3056 // mba: no BaseURL for clipboard functionality
3057 aMap.Read( *pStream, IMapFormat::Detect ) == IMAP_ERR_OK &&
3058 aMap.GetIMapObjectCount() )
3060 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3061 rSh.GetFlyFrameAttr( aSet );
3062 SwFormatURL aURL( aSet.Get( RES_URL ) );
3063 aURL.SetMap( &aMap );
3064 aSet.Put( aURL );
3065 rSh.SetFlyFrameAttr( aSet );
3066 bRet = true;
3070 return bRet;
3073 bool SwTransferable::PasteImageMap( const TransferableDataHelper& rData,
3074 SwWrtShell& rSh )
3076 bool bRet = false;
3077 if( rData.HasFormat( SotClipboardFormatId::SVIM ))
3079 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3080 rSh.GetFlyFrameAttr( aSet );
3081 SwFormatURL aURL( aSet.Get( RES_URL ) );
3082 const ImageMap* pOld = aURL.GetMap();
3084 // set or replace, that is the question
3085 ImageMap aImageMap;
3086 if( rData.GetImageMap( SotClipboardFormatId::SVIM, aImageMap ) &&
3087 ( !pOld || aImageMap != *pOld ))
3089 aURL.SetMap( &aImageMap );
3090 aSet.Put( aURL );
3091 rSh.SetFlyFrameAttr( aSet );
3093 bRet = true;
3095 return bRet;
3098 bool SwTransferable::PasteAsHyperlink( const TransferableDataHelper& rData,
3099 SwWrtShell& rSh, SotClipboardFormatId nFormat )
3101 bool bRet = false;
3102 OUString sFile;
3103 if( rData.GetString( nFormat, sFile ) && !sFile.isEmpty() )
3105 OUString sDesc;
3106 SwTransferable::CheckForURLOrLNKFile( rData, sFile, &sDesc );
3108 // first, make the URL absolute
3109 INetURLObject aURL;
3110 aURL.SetSmartProtocol( INetProtocol::File );
3111 aURL.SetSmartURL( sFile );
3112 sFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
3114 switch( rSh.GetObjCntTypeOfSelection() )
3116 case OBJCNT_FLY:
3117 case OBJCNT_GRF:
3118 case OBJCNT_OLE:
3120 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3121 rSh.GetFlyFrameAttr( aSet );
3122 SwFormatURL aURL2( aSet.Get( RES_URL ) );
3123 aURL2.SetURL( sFile, false );
3124 if( aURL2.GetName().isEmpty() )
3125 aURL2.SetName( sFile );
3126 aSet.Put( aURL2 );
3127 rSh.SetFlyFrameAttr( aSet );
3129 break;
3131 default:
3133 rSh.InsertURL( SwFormatINetFormat( sFile, OUString() ),
3134 sDesc.isEmpty() ? sFile : sDesc);
3137 bRet = true;
3139 return bRet;
3142 bool SwTransferable::PasteFileName( const TransferableDataHelper& rData,
3143 SwWrtShell& rSh, SotClipboardFormatId nFormat,
3144 SwPasteSdr nAction, const Point* pPt,
3145 SotExchangeActionFlags nActionFlags,
3146 bool * graphicInserted)
3148 bool bRet = SwTransferable::PasteGrf( rData, rSh, nFormat, nAction,
3149 pPt, nActionFlags, 0, false);
3150 if (graphicInserted != nullptr) {
3151 *graphicInserted = bRet;
3153 if( !bRet )
3155 OUString sFile, sDesc;
3156 if( rData.GetString( nFormat, sFile ) && !sFile.isEmpty() )
3158 #if HAVE_FEATURE_AVMEDIA
3159 INetURLObject aMediaURL;
3161 aMediaURL.SetSmartURL( sFile );
3162 const OUString aMediaURLStr( aMediaURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
3164 if( ::avmedia::MediaWindow::isMediaURL( aMediaURLStr, u""_ustr/*TODO?*/ ) )
3166 const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, aMediaURLStr );
3167 rSh.GetView().GetViewFrame().GetDispatcher()->ExecuteList(
3168 SID_INSERT_AVMEDIA, SfxCallMode::SYNCHRON,
3169 { &aMediaURLItem });
3171 #else
3172 if (false)
3175 #endif
3176 else
3178 bool bIsURLFile = SwTransferable::CheckForURLOrLNKFile( rData, sFile, &sDesc );
3180 //Own FileFormat? --> insert, not for StarWriter/Web
3181 OUString sFileURL = URIHelper::SmartRel2Abs(INetURLObject(), sFile, Link<OUString *, bool>(), false );
3182 std::shared_ptr<const SfxFilter> pFlt = SwPasteSdr::SetAttr == nAction
3183 ? nullptr : SwIoSystem::GetFileFilter(sFileURL);
3184 if( pFlt && dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) == nullptr )
3186 // and then pull up the insert-region-dialog
3187 SwSectionData aSect(
3188 SectionType::FileLink,
3189 rSh.GetDoc()->GetUniqueSectionName() );
3190 aSect.SetLinkFileName( sFileURL );
3191 aSect.SetProtectFlag( true );
3193 rSh.StartInsertRegionDialog( aSect ); // starts dialog asynchronously
3194 bRet = true;
3196 else if (SwPasteSdr::Insert == nAction && rData.HasFormat(SotClipboardFormatId::SIMPLE_FILE))
3198 // insert file as OLE
3199 PasteOLE(rData, rSh, nFormat, nActionFlags, nullptr == pPt);
3201 else if( SwPasteSdr::SetAttr == nAction ||
3202 ( bIsURLFile && SwPasteSdr::Insert == nAction ))
3204 //we can insert foreign files as links after all
3206 // first, make the URL absolute
3207 INetURLObject aURL;
3208 aURL.SetSmartProtocol( INetProtocol::File );
3209 aURL.SetSmartURL( sFile );
3210 sFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
3212 switch( rSh.GetObjCntTypeOfSelection() )
3214 case OBJCNT_FLY:
3215 case OBJCNT_GRF:
3216 case OBJCNT_OLE:
3218 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3219 rSh.GetFlyFrameAttr( aSet );
3220 SwFormatURL aURL2( aSet.Get( RES_URL ) );
3221 aURL2.SetURL( sFile, false );
3222 if( aURL2.GetName().isEmpty() )
3223 aURL2.SetName( sFile );
3224 aSet.Put( aURL2 );
3225 rSh.SetFlyFrameAttr( aSet );
3227 break;
3229 default:
3231 rSh.InsertURL( SwFormatINetFormat( sFile, OUString() ),
3232 sDesc.isEmpty() ? sFile : sDesc );
3235 bRet = true;
3240 return bRet;
3243 bool SwTransferable::PasteDBData( const TransferableDataHelper& rData,
3244 SwWrtShell& rSh, SotClipboardFormatId nFormat, bool bLink,
3245 const Point* pDragPt, bool bMsg )
3247 bool bRet = false;
3248 OUString sText;
3249 if( rData.GetString( nFormat, sText ) && !sText.isEmpty() )
3251 sal_uInt16 nWh = SotClipboardFormatId::SBA_CTRLDATAEXCHANGE == nFormat
3253 : SotClipboardFormatId::SBA_DATAEXCHANGE == nFormat
3254 ? (bLink
3255 ? FN_QRY_MERGE_FIELD
3256 : FN_QRY_INSERT)
3257 : (bLink
3259 : FN_QRY_INSERT_FIELD );
3260 const DataFlavorExVector& rVector = rData.GetDataFlavorExVector();
3261 bool bHaveColumnDescriptor = OColumnTransferable::canExtractColumnDescriptor(rVector, ColumnTransferFormatFlags::COLUMN_DESCRIPTOR | ColumnTransferFormatFlags::CONTROL_EXCHANGE);
3262 if ( SotClipboardFormatId::XFORMS == nFormat )
3264 rSh.MakeDrawView();
3265 FmFormView* pFmView = dynamic_cast<FmFormView*>( rSh.GetDrawView() );
3266 if (pFmView && pDragPt)
3268 OXFormsDescriptor aDesc = OXFormsTransferable::extractDescriptor(rData);
3269 rtl::Reference<SdrObject> pObj = pFmView->CreateXFormsControl(aDesc);
3270 if(pObj)
3272 rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt );
3276 else if( nWh )
3278 std::unique_ptr<SfxUnoAnyItem> pConnectionItem;
3279 std::unique_ptr<SfxUnoAnyItem> pCursorItem;
3280 std::unique_ptr<SfxUnoAnyItem> pColumnItem;
3281 std::unique_ptr<SfxUnoAnyItem> pSourceItem;
3282 std::unique_ptr<SfxUnoAnyItem> pCommandItem;
3283 std::unique_ptr<SfxUnoAnyItem> pCommandTypeItem;
3284 std::unique_ptr<SfxUnoAnyItem> pColumnNameItem;
3285 std::unique_ptr<SfxUnoAnyItem> pSelectionItem;
3287 bool bDataAvailable = true;
3288 ODataAccessDescriptor aDesc;
3289 if(bHaveColumnDescriptor)
3290 aDesc = OColumnTransferable::extractColumnDescriptor(rData);
3291 else if(ODataAccessObjectTransferable::canExtractObjectDescriptor(rVector) )
3292 aDesc = ODataAccessObjectTransferable::extractObjectDescriptor(rData);
3293 else
3294 bDataAvailable = false;
3296 if ( bDataAvailable )
3298 pConnectionItem.reset(new SfxUnoAnyItem(FN_DB_CONNECTION_ANY, aDesc[DataAccessDescriptorProperty::Connection]));
3299 pColumnItem.reset(new SfxUnoAnyItem(FN_DB_COLUMN_ANY, aDesc[DataAccessDescriptorProperty::ColumnObject]));
3300 pSourceItem.reset(new SfxUnoAnyItem(FN_DB_DATA_SOURCE_ANY, Any(aDesc.getDataSource())));
3301 pCommandItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COMMAND_ANY, aDesc[DataAccessDescriptorProperty::Command]));
3302 pCommandTypeItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COMMAND_TYPE_ANY, aDesc[DataAccessDescriptorProperty::CommandType]));
3303 pColumnNameItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COLUMN_NAME_ANY, aDesc[DataAccessDescriptorProperty::ColumnName]));
3304 pSelectionItem.reset(new SfxUnoAnyItem(FN_DB_DATA_SELECTION_ANY, aDesc[DataAccessDescriptorProperty::Selection]));
3305 pCursorItem.reset(new SfxUnoAnyItem(FN_DB_DATA_CURSOR_ANY, aDesc[DataAccessDescriptorProperty::Cursor]));
3308 SwView& rView = rSh.GetView();
3309 //force ::SelectShell
3310 rView.StopShellTimer();
3312 SfxStringItem aDataDesc( nWh, sText );
3313 rView.GetViewFrame().GetDispatcher()->ExecuteList(
3314 nWh, SfxCallMode::ASYNCHRON,
3315 { &aDataDesc, pConnectionItem.get(), pColumnItem.get(),
3316 pSourceItem.get(), pCommandItem.get(), pCommandTypeItem.get(),
3317 pColumnNameItem.get(), pSelectionItem.get(),
3318 pCursorItem.get() });
3320 else
3322 rSh.MakeDrawView();
3323 FmFormView* pFmView = dynamic_cast<FmFormView*>( rSh.GetDrawView() );
3324 if (pFmView && bHaveColumnDescriptor && pDragPt)
3326 rtl::Reference<SdrObject> pObj = pFmView->CreateFieldControl( OColumnTransferable::extractColumnDescriptor(rData) );
3327 if (pObj)
3328 rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt );
3331 bRet = true;
3333 else if( bMsg )
3335 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
3336 VclMessageType::Info, VclButtonsType::Ok,
3337 SwResId(STR_CLPBRD_FORMAT_ERROR)));
3338 xBox->run();
3340 return bRet;
3343 bool SwTransferable::PasteFileList( const TransferableDataHelper& rData,
3344 SwWrtShell& rSh, bool bLink,
3345 const Point* pPt, bool bMsg )
3347 bool bRet = false;
3348 FileList aFileList;
3349 if( rData.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList ) &&
3350 aFileList.Count() )
3352 SwPasteSdr nAct = bLink ? SwPasteSdr::SetAttr : SwPasteSdr::Insert;
3353 OUString sFlyNm;
3354 // iterate over the filelist
3355 for( sal_uLong n = 0, nEnd = aFileList.Count(); n < nEnd; ++n )
3357 rtl::Reference<TransferDataContainer> pHlp = new TransferDataContainer;
3358 pHlp->CopyString( SotClipboardFormatId::SIMPLE_FILE, aFileList.GetFile( n ));
3359 TransferableDataHelper aData( pHlp );
3361 if( SwTransferable::PasteFileName( aData, rSh, SotClipboardFormatId::SIMPLE_FILE, nAct,
3362 pPt, SotExchangeActionFlags::NONE, nullptr ))
3364 if( bLink )
3366 sFlyNm = rSh.GetFlyName();
3367 SwTransferable::SetSelInShell( rSh, false, pPt );
3369 bRet = true;
3372 if( !sFlyNm.isEmpty() )
3373 rSh.GotoFly( sFlyNm );
3375 else if( bMsg )
3377 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
3378 VclMessageType::Info, VclButtonsType::Ok,
3379 SwResId(STR_CLPBRD_FORMAT_ERROR)));
3380 xBox->run();
3382 return bRet;
3385 bool SwTransferable::CheckForURLOrLNKFile( const TransferableDataHelper& rData,
3386 OUString& rFileName, OUString* pTitle )
3388 bool bIsURLFile = false;
3389 INetBookmark aBkmk;
3390 if( rData.GetINetBookmark( SotClipboardFormatId::SOLK, aBkmk ) )
3392 rFileName = aBkmk.GetURL();
3393 if( pTitle )
3394 *pTitle = aBkmk.GetDescription();
3395 bIsURLFile = true;
3397 else
3399 if( rFileName.getLength()>4 && rFileName.endsWithIgnoreAsciiCase(".url") )
3401 OSL_ENSURE( false, "how do we read today .URL - Files?" );
3404 return bIsURLFile;
3407 bool SwTransferable::IsPasteSpecial( const SwWrtShell& rWrtShell,
3408 const TransferableDataHelper& rData )
3410 // we can paste-special if there's an entry in the paste-special-format list
3411 SvxClipboardFormatItem aClipboardFormatItem(TypedWhichId<SvxClipboardFormatItem>(0));
3412 FillClipFormatItem( rWrtShell, rData, aClipboardFormatItem);
3413 return aClipboardFormatItem.Count() > 0;
3416 bool SwTransferable::IsPasteOwnFormat( const TransferableDataHelper& rData )
3418 return ( GetSwTransferable( rData ) != nullptr );
3421 bool SwTransferable::PasteFormat( SwWrtShell& rSh,
3422 const TransferableDataHelper& rData,
3423 SotClipboardFormatId nFormat )
3425 SwWait aWait( *rSh.GetView().GetDocShell(), false );
3426 bool bRet = false;
3428 SotClipboardFormatId nPrivateFormat = SotClipboardFormatId::PRIVATE;
3429 SwTransferable *pClipboard = GetSwTransferable( rData );
3430 if( pClipboard &&
3431 ((TransferBufferType::Document|TransferBufferType::Graphic|TransferBufferType::Ole) & pClipboard->m_eBufferType ))
3432 nPrivateFormat = SotClipboardFormatId::EMBED_SOURCE;
3434 if( pClipboard && nPrivateFormat == nFormat )
3435 bRet = pClipboard->PrivatePaste( rSh );
3436 else if( rData.HasFormat( nFormat ) )
3438 uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
3439 sal_uInt8 nEventAction;
3440 SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
3441 sal_uInt16 nSourceOptions =
3442 (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
3443 SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
3444 SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
3445 SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
3446 ? EXCHG_IN_ACTION_COPY
3447 : EXCHG_IN_ACTION_MOVE);
3448 SotExchangeActionFlags nActionFlags;
3449 sal_uInt8 nAction = SotExchange::GetExchangeAction(
3450 rData.GetDataFlavorExVector(),
3451 nDestination,
3452 nSourceOptions, /* ?? */
3453 EXCHG_IN_ACTION_DEFAULT, /* ?? */
3454 nFormat, nEventAction, nFormat,
3455 lcl_getTransferPointer ( xTransferable ),
3456 &nActionFlags );
3458 if( EXCHG_INOUT_ACTION_NONE != nAction )
3459 bRet = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
3460 nDestination, true, false );
3462 return bRet;
3465 bool SwTransferable::TestAllowedFormat( const TransferableDataHelper& rData,
3466 SotClipboardFormatId nFormat, SotExchangeDest nDestination )
3468 sal_uInt8 nAction = EXCHG_INOUT_ACTION_NONE;
3469 if( rData.HasFormat( nFormat )) {
3470 uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
3471 sal_uInt8 nEventAction;
3472 nAction = SotExchange::GetExchangeAction(
3473 rData.GetDataFlavorExVector(),
3474 nDestination, EXCHG_IN_ACTION_COPY,
3475 EXCHG_IN_ACTION_COPY, nFormat,
3476 nEventAction, nFormat,
3477 lcl_getTransferPointer ( xTransferable ) );
3479 return EXCHG_INOUT_ACTION_NONE != nAction;
3483 * the list of formats which will be offered to the user in the 'Paste
3484 * Special...' dialog and the paste button menu
3486 static SotClipboardFormatId aPasteSpecialIds[] =
3488 SotClipboardFormatId::HTML,
3489 SotClipboardFormatId::HTML_SIMPLE,
3490 SotClipboardFormatId::HTML_NO_COMMENT,
3491 SotClipboardFormatId::RTF,
3492 SotClipboardFormatId::RICHTEXT,
3493 SotClipboardFormatId::STRING,
3494 SotClipboardFormatId::SONLK,
3495 SotClipboardFormatId::NETSCAPE_BOOKMARK,
3496 SotClipboardFormatId::DRAWING,
3497 SotClipboardFormatId::SVXB,
3498 SotClipboardFormatId::GDIMETAFILE,
3499 SotClipboardFormatId::BITMAP,
3500 SotClipboardFormatId::SVIM,
3501 SotClipboardFormatId::FILEGRPDESCRIPTOR,
3502 SotClipboardFormatId::NONE
3505 bool SwTransferable::PasteUnformatted( SwWrtShell& rSh, TransferableDataHelper& rData )
3507 // Plain text == unformatted
3508 return SwTransferable::PasteFormat( rSh, rData, SotClipboardFormatId::STRING );
3511 void SwTransferable::PrePasteSpecial( const SwWrtShell& rSh, const TransferableDataHelper& rData, const VclPtr<SfxAbstractPasteDialog>& pDlg )
3513 DataFlavorExVector aFormats( rData.GetDataFlavorExVector() );
3514 TransferableObjectDescriptor aDesc;
3516 SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh );
3518 SwTransferable *pClipboard = GetSwTransferable( rData );
3519 if( pClipboard )
3521 aDesc = pClipboard->m_aObjDesc;
3522 TranslateId pResId;
3523 if( pClipboard->m_eBufferType & TransferBufferType::Document )
3524 pResId = STR_PRIVATETEXT;
3525 else if( pClipboard->m_eBufferType & TransferBufferType::Graphic )
3526 pResId = STR_PRIVATEGRAPHIC;
3527 else if( pClipboard->m_eBufferType == TransferBufferType::Ole )
3528 pResId = STR_PRIVATEOLE;
3530 if (pResId)
3532 if (STR_PRIVATEOLE == pResId || STR_PRIVATEGRAPHIC == pResId)
3534 // add SotClipboardFormatId::EMBED_SOURCE to the formats. This
3535 // format display then the private format name.
3536 DataFlavorEx aFlavorEx;
3537 aFlavorEx.mnSotId = SotClipboardFormatId::EMBED_SOURCE;
3538 aFormats.insert( aFormats.begin(), aFlavorEx );
3540 pDlg->SetObjName( pClipboard->m_aObjDesc.maClassName,
3541 SwResId(pResId) );
3542 pDlg->Insert( SotClipboardFormatId::EMBED_SOURCE, OUString() );
3545 else
3547 if( rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
3549 (void)rData.GetTransferableObjectDescriptor(
3550 SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc );
3553 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::EMBED_SOURCE, nDest ))
3554 pDlg->Insert( SotClipboardFormatId::EMBED_SOURCE, OUString() );
3555 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK_SOURCE, nDest ))
3556 pDlg->Insert( SotClipboardFormatId::LINK_SOURCE, OUString() );
3559 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK, nDest ))
3560 pDlg->Insert( SotClipboardFormatId::LINK, SwResId(STR_DDEFORMAT) );
3562 for( SotClipboardFormatId* pIds = aPasteSpecialIds; *pIds != SotClipboardFormatId::NONE; ++pIds )
3563 if( SwTransferable::TestAllowedFormat( rData, *pIds, nDest ))
3564 pDlg->Insert( *pIds, OUString() );
3567 void SwTransferable::FillClipFormatItem( const SwWrtShell& rSh,
3568 const TransferableDataHelper& rData,
3569 SvxClipboardFormatItem & rToFill )
3571 SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh );
3573 SwTransferable *pClipboard = GetSwTransferable( rData );
3574 if( pClipboard )
3576 TranslateId pResId;
3577 if( pClipboard->m_eBufferType & TransferBufferType::Document )
3578 pResId = STR_PRIVATETEXT;
3579 else if( pClipboard->m_eBufferType & TransferBufferType::Graphic )
3580 pResId = STR_PRIVATEGRAPHIC;
3581 else if( pClipboard->m_eBufferType == TransferBufferType::Ole )
3582 pResId = STR_PRIVATEOLE;
3584 if (pResId)
3585 rToFill.AddClipbrdFormat(SotClipboardFormatId::EMBED_SOURCE,
3586 SwResId(pResId));
3588 else
3590 TransferableObjectDescriptor aDesc;
3591 if (rData.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
3593 (void)rData.GetTransferableObjectDescriptor(
3594 SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc);
3597 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::EMBED_SOURCE, nDest ))
3598 rToFill.AddClipbrdFormat( SotClipboardFormatId::EMBED_SOURCE,
3599 aDesc.maTypeName );
3600 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK_SOURCE, nDest ))
3601 rToFill.AddClipbrdFormat( SotClipboardFormatId::LINK_SOURCE );
3603 SotClipboardFormatId nFormat;
3604 if ( rData.HasFormat(nFormat = SotClipboardFormatId::EMBED_SOURCE_OLE) || rData.HasFormat(nFormat = SotClipboardFormatId::EMBEDDED_OBJ_OLE) )
3606 OUString sName,sSource;
3607 if ( SvPasteObjectHelper::GetEmbeddedName(rData,sName,sSource,nFormat) )
3608 rToFill.AddClipbrdFormat( nFormat, sName );
3612 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK, nDest ))
3613 rToFill.AddClipbrdFormat( SotClipboardFormatId::LINK, SwResId(STR_DDEFORMAT) );
3615 for( SotClipboardFormatId* pIds = aPasteSpecialIds; *pIds != SotClipboardFormatId::NONE; ++pIds )
3616 if( SwTransferable::TestAllowedFormat( rData, *pIds, nDest ))
3617 rToFill.AddClipbrdFormat(*pIds, OUString());
3620 void SwTransferable::SetDataForDragAndDrop( const Point& rSttPos )
3622 if(!m_pWrtShell)
3623 return;
3624 OUString sGrfNm;
3625 const SelectionType nSelection = m_pWrtShell->GetSelectionType();
3626 if( SelectionType::Graphic == nSelection)
3628 AddFormat( SotClipboardFormatId::SVXB );
3629 const Graphic* pGrf = m_pWrtShell->GetGraphic();
3630 if ( pGrf && pGrf->IsSupportedGraphic() )
3632 AddFormat( SotClipboardFormatId::GDIMETAFILE );
3633 AddFormat( SotClipboardFormatId::PNG );
3634 AddFormat( SotClipboardFormatId::BITMAP );
3636 m_eBufferType = TransferBufferType::Graphic;
3637 m_pWrtShell->GetGrfNms( &sGrfNm, nullptr );
3639 else if( SelectionType::Ole == nSelection )
3641 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
3642 PrepareOLE( m_aObjDesc );
3643 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
3644 AddFormat( SotClipboardFormatId::GDIMETAFILE );
3645 m_eBufferType = TransferBufferType::Ole;
3647 //Is there anything to provide anyway?
3648 else if ( m_pWrtShell->IsSelection() || m_pWrtShell->IsFrameSelected() ||
3649 m_pWrtShell->IsObjSelected() )
3651 if( m_pWrtShell->IsObjSelected() )
3652 m_eBufferType = TransferBufferType::Drawing;
3653 else
3655 m_eBufferType = TransferBufferType::Document;
3656 if( SwWrtShell::NO_WORD !=
3657 m_pWrtShell->IntelligentCut( nSelection, false ))
3658 m_eBufferType = TransferBufferType::DocumentWord | m_eBufferType;
3661 if( nSelection & SelectionType::TableCell )
3662 m_eBufferType = TransferBufferType::Table | m_eBufferType;
3664 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
3666 //put RTF ahead of the OLE's Metafile for less loss
3667 if( !m_pWrtShell->IsObjSelected() )
3669 AddFormat( SotClipboardFormatId::RTF );
3670 AddFormat( SotClipboardFormatId::RICHTEXT );
3671 AddFormat( SotClipboardFormatId::HTML );
3673 if( m_pWrtShell->IsSelection() )
3674 AddFormat( SotClipboardFormatId::STRING );
3676 if( nSelection & ( SelectionType::DrawObject | SelectionType::DbForm ))
3678 AddFormat( SotClipboardFormatId::DRAWING );
3679 if ( nSelection & SelectionType::DrawObject )
3681 AddFormat( SotClipboardFormatId::GDIMETAFILE );
3682 AddFormat( SotClipboardFormatId::PNG );
3683 AddFormat( SotClipboardFormatId::BITMAP );
3685 m_eBufferType = TransferBufferType::Graphic | m_eBufferType;
3687 // is it a URL-Button ?
3688 OUString sURL;
3689 OUString sDesc;
3690 if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
3692 AddFormat( SotClipboardFormatId::STRING );
3693 AddFormat( SotClipboardFormatId::SOLK );
3694 AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
3695 AddFormat( SotClipboardFormatId::FILECONTENT );
3696 AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
3697 AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
3698 m_eBufferType = TransferBufferType::InetField | m_eBufferType;
3702 //ObjectDescriptor was already filled from the old DocShell.
3703 //Now adjust it. Thus in GetData the first query can still
3704 //be answered with delayed rendering.
3705 m_aObjDesc.maDragStartPos = rSttPos;
3706 m_aObjDesc.maSize = constOleSize100mm;
3708 PrepareOLE( m_aObjDesc );
3709 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
3711 else if( nSelection & SelectionType::Text && !m_pWrtShell->HasMark() )
3713 // is only one field - selected?
3714 SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
3715 Point aPos( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY());
3717 if( m_pWrtShell->GetContentAtPos( aPos, aContentAtPos ) )
3719 AddFormat( SotClipboardFormatId::STRING );
3720 AddFormat( SotClipboardFormatId::SOLK );
3721 AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
3722 AddFormat( SotClipboardFormatId::FILECONTENT );
3723 AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
3724 AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
3725 m_eBufferType = TransferBufferType::InetField;
3729 if( !m_pWrtShell->IsFrameSelected() )
3730 return;
3732 SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
3733 m_pWrtShell->GetFlyFrameAttr( aSet );
3734 const SwFormatURL& rURL = aSet.Get( RES_URL );
3735 if( rURL.GetMap() )
3737 m_pImageMap.reset( new ImageMap( *rURL.GetMap() ) );
3738 AddFormat( SotClipboardFormatId::SVIM );
3740 else if( !rURL.GetURL().isEmpty() )
3742 m_pTargetURL.reset(new INetImage( sGrfNm, rURL.GetURL(),
3743 rURL.GetTargetFrameName() ));
3744 AddFormat( SotClipboardFormatId::INET_IMAGE );
3748 void SwTransferable::StartDrag( vcl::Window* pWin, const Point& rPos )
3750 if(!m_pWrtShell)
3751 return;
3752 m_bOldIdle = m_pWrtShell->GetViewOptions()->IsIdle();
3753 m_bCleanUp = true;
3755 m_pWrtShell->GetViewOptions()->SetIdle( false );
3757 if( m_pWrtShell->IsSelFrameMode() )
3758 m_pWrtShell->ShowCursor();
3760 SwModule::get()->m_pDragDrop = this;
3762 SetDataForDragAndDrop( rPos );
3764 sal_Int8 nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
3765 SwDocShell* pDShell = m_pWrtShell->GetView().GetDocShell();
3766 if( ( pDShell && pDShell->IsReadOnly() ) || m_pWrtShell->HasReadonlySel() )
3767 nDragOptions &= ~DND_ACTION_MOVE;
3769 TransferableHelper::StartDrag( pWin, nDragOptions );
3772 void SwTransferable::DragFinished( sal_Int8 nAction )
3774 //And the last finishing work so that all statuses are right
3775 if( DND_ACTION_MOVE == nAction )
3777 if( m_bCleanUp )
3779 //It was dropped outside of Writer. We still have to
3780 //delete.
3782 m_pWrtShell->StartAllAction();
3783 m_pWrtShell->StartUndo( SwUndoId::UI_DRAG_AND_MOVE );
3784 if ( m_pWrtShell->IsTableMode() )
3785 m_pWrtShell->DeleteTableSel();
3786 else
3788 if ( !(m_pWrtShell->IsSelFrameMode() || m_pWrtShell->IsObjSelected()) )
3789 //SmartCut, take one of the blanks along
3790 m_pWrtShell->IntelligentCut( m_pWrtShell->GetSelectionType() );
3791 m_pWrtShell->DelRight();
3793 m_pWrtShell->EndUndo( SwUndoId::UI_DRAG_AND_MOVE );
3794 m_pWrtShell->EndAllAction();
3796 else
3798 const SelectionType nSelection = m_pWrtShell->GetSelectionType();
3799 if( ( SelectionType::Frame | SelectionType::Graphic |
3800 SelectionType::Ole | SelectionType::DrawObject ) & nSelection )
3802 m_pWrtShell->EnterSelFrameMode();
3806 m_pWrtShell->GetView().GetEditWin().DragFinished();
3808 if( m_pWrtShell->IsSelFrameMode() )
3809 m_pWrtShell->HideCursor();
3810 else
3811 m_pWrtShell->ShowCursor();
3813 m_pWrtShell->GetViewOptions()->SetIdle( m_bOldIdle );
3816 namespace
3819 bool lcl_checkClassification(SwDoc* pSourceDoc, SwDoc* pDestinationDoc)
3821 if (!pSourceDoc || !pDestinationDoc)
3822 return true;
3824 SwDocShell* pSourceShell = pSourceDoc->GetDocShell();
3825 SwDocShell* pDestinationShell = pDestinationDoc->GetDocShell();
3826 if (!pSourceShell || !pDestinationShell)
3827 return true;
3829 SfxClassificationCheckPasteResult eResult = SfxClassificationHelper::CheckPaste(pSourceShell->getDocProperties(), pDestinationShell->getDocProperties());
3830 return SfxClassificationHelper::ShowPasteInfo(eResult);
3835 bool SwTransferable::PrivatePaste(SwWrtShell& rShell, SwPasteContext* pContext, PasteTableType ePasteTable)
3837 // first, ask for the SelectionType, then action-bracketing !!!!
3838 // (otherwise it's not pasted into a TableSelection!!!)
3839 OSL_ENSURE( !rShell.ActionPend(), "Paste must never have an ActionPend" );
3840 if ( !m_pClpDocFac )
3841 return false; // the return value of the SwFEShell::Paste also is bool!
3843 const SelectionType nSelection = rShell.GetSelectionType();
3845 SwTrnsfrActionAndUndo aAction( &rShell );
3847 bool bKillPaMs = false;
3849 //Delete selected content, not at table-selection and table in Clipboard, and don't delete hovering graphics.
3850 if( rShell.HasSelection() && !( nSelection & SelectionType::TableCell) && !( nSelection & SelectionType::DrawObject))
3852 if (!(nSelection & SelectionType::NumberList))
3854 bKillPaMs = true;
3855 rShell.SetRetainSelection( true );
3857 if (pContext)
3858 pContext->forget();
3859 rShell.DelRight();
3860 if (pContext)
3861 pContext->remember();
3862 // when a Fly was selected, a valid cursor position has to be found now
3863 // (parked Cursor!)
3864 if( ( SelectionType::Frame | SelectionType::Graphic |
3865 SelectionType::Ole | SelectionType::DrawObject |
3866 SelectionType::DbForm ) & nSelection )
3868 // position the cursor again
3869 Point aPt( rShell.GetCharRect().Pos() );
3870 rShell.SwCursorShell::SetCursor( aPt, true );
3872 if (!(nSelection & SelectionType::NumberList))
3874 rShell.SetRetainSelection( false );
3877 if ( nSelection & SelectionType::DrawObject) //unselect hovering graphics
3879 rShell.ResetSelect(nullptr,false);
3882 bool bInWrd = false, bEndWrd = false, bSttWrd = false,
3883 bSmart(TransferBufferType::DocumentWord & m_eBufferType);
3884 if( bSmart )
3886 // Why not for other Scripts? If TransferBufferType::DocumentWord is set, we have a word
3887 // in the buffer, word in this context means 'something with spaces at beginning
3888 // and end'. In this case we definitely want these spaces to be inserted here.
3889 bInWrd = rShell.IsInWord();
3890 bEndWrd = rShell.IsEndWrd();
3891 bSmart = bInWrd || bEndWrd;
3892 if( bSmart )
3894 bSttWrd = rShell.IsStartWord();
3895 if (!bSttWrd && (bInWrd || bEndWrd))
3896 rShell.SwEditShell::Insert(' ');
3900 bool bRet = true;
3901 // m_pWrtShell is nullptr when the source document is closed already.
3902 if (!m_pWrtShell || lcl_checkClassification(m_pWrtShell->GetDoc(), rShell.GetDoc()))
3903 bRet = rShell.Paste(m_pClpDocFac->GetDoc(), ePasteTable == PasteTableType::PASTE_TABLE);
3905 if( bKillPaMs )
3906 rShell.KillPams();
3908 // If Smart Paste then insert blank
3909 if( bRet && bSmart && ((bInWrd && !bEndWrd )|| bSttWrd) )
3910 rShell.SwEditShell::Insert(' ');
3912 return bRet;
3915 bool SwTransferable::PrivateDrop( SwWrtShell& rSh, const Point& rDragPt,
3916 bool bMove, bool bIsXSelection )
3918 int cWord = 0;
3919 bool bInWrd = false;
3920 bool bEndWrd = false;
3921 bool bSttWrd = false;
3922 bool bSttPara = false;
3923 bool bTableSel = false;
3924 bool bTableMove = false;
3925 bool bFrameSel = false;
3927 SwWrtShell& rSrcSh = *GetShell();
3929 rSh.UnSetVisibleCursor();
3931 if( TransferBufferType::InetField == m_eBufferType )
3933 if( rSh.GetFormatFromObj( rDragPt ) )
3935 INetBookmark aTmp;
3936 if( (TransferBufferType::InetField & m_eBufferType) && m_oBookmark )
3937 aTmp = *m_oBookmark;
3939 // select target graphic
3940 if( rSh.SelectObj( rDragPt ) )
3942 rSh.HideCursor();
3943 rSh.EnterSelFrameMode( &rDragPt );
3944 g_bFrameDrag = true;
3947 const SelectionType nSelection = rSh.GetSelectionType();
3949 // not yet consider Draw objects
3950 if( SelectionType::Graphic & nSelection )
3952 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3953 rSh.GetFlyFrameAttr( aSet );
3954 SwFormatURL aURL( aSet.Get( RES_URL ) );
3955 aURL.SetURL( aTmp.GetURL(), false );
3956 aSet.Put( aURL );
3957 rSh.SetFlyFrameAttr( aSet );
3958 return true;
3961 if( SelectionType::DrawObject & nSelection )
3963 rSh.LeaveSelFrameMode();
3964 rSh.UnSelectFrame();
3965 rSh.ShowCursor();
3966 g_bFrameDrag = false;
3971 if( &rSh != &rSrcSh && (SelectionType::Graphic & rSh.GetSelectionType()) &&
3972 TransferBufferType::Graphic == m_eBufferType )
3974 // ReRead the graphic
3975 OUString sGrfNm;
3976 OUString sFltNm;
3977 rSrcSh.GetGrfNms( &sGrfNm, &sFltNm );
3978 rSh.ReRead( sGrfNm, sFltNm, rSrcSh.GetGraphic() );
3979 return true;
3982 //not in selections or selected frames
3983 if( rSh.TestCurrPam( rDragPt ) ||
3984 ( rSh.IsSelFrameMode() && rSh.IsInsideSelectedObj( rDragPt )) )
3985 return false;
3987 if( rSrcSh.IsTableMode() )
3989 bTableSel = true;
3990 const SelectionType nSelection = rSrcSh.GetSelectionType();
3991 // at enhanced table row/column selection or wholly selected tables,
3992 // paste rows above or columns before, and in the case of moving, remove the selection
3993 // (limit only to the single document case temporarily)
3994 if( rSrcSh.GetDoc() == rSh.GetDoc() &&
3995 ( (( SelectionType::TableRow | SelectionType::TableCol) & nSelection ) || rSrcSh.HasWholeTabSelection() ) )
3997 bool bTableCol(SelectionType::TableCol & nSelection);
3999 ::sw::mark::MarkBase* pMarkMoveFrom = bMove
4000 ? rSh.SetBookmark(
4001 vcl::KeyCode(),
4002 OUString(),
4003 IDocumentMarkAccess::MarkType::UNO_BOOKMARK )
4004 : nullptr;
4006 // row count and direction of the table selection:
4007 // up to down, if the cursor is there in its last table row
4008 const SwSelBoxes& rBoxes = rSrcSh.GetTableCursor()->GetSelectedBoxes();
4009 const SwTableNode* pTableNd = rSh.IsCursorInTable();
4010 if (!pTableNd)
4012 SAL_WARN("sw", "presumably this case can't arise in practice");
4013 return false;
4015 const SwTableLines& rLines = pTableNd->GetTable().GetTabLines();
4016 const SwStartNode& rDelPos = rBoxes.back()
4017 ? *rBoxes.front()->GetSttNd()
4018 : *pTableNd->GetStartNode();
4020 // count selected rows or columns
4021 sal_Int32 nSelRowOrCols = 0;
4022 if ( rBoxes.back() )
4024 if ( bTableCol )
4026 // selected column count is the count of the cells
4027 // in the first row of the selection
4028 auto nLine = rLines.GetPos( rBoxes.front()->GetUpper() );
4029 for (auto pBox : rBoxes)
4031 // cell is in the next row
4032 if ( nLine != rLines.GetPos( pBox->GetUpper() ) )
4033 break;
4034 ++nSelRowOrCols;
4037 else
4039 // selected row count is the difference of the row number of the
4040 // first and the last cell of the selection
4041 nSelRowOrCols = rLines.GetPos( rBoxes.back()->GetUpper() ) -
4042 rLines.GetPos( rBoxes.front()->GetUpper() ) + 1;
4046 bool bSelUpToDown = rBoxes.back() && rBoxes.back()->GetUpper() ==
4047 rSh.GetCursor()->GetPointNode().GetTableBox()->GetUpper();
4049 SwUndoId eUndoId = bMove ? SwUndoId::UI_DRAG_AND_MOVE : SwUndoId::UI_DRAG_AND_COPY;
4051 SwRewriter aRewriter;
4053 aRewriter.AddRule(UndoArg1, rSrcSh.GetSelDescr());
4055 if(rSrcSh.GetDoc() != rSh.GetDoc())
4056 rSrcSh.StartUndo( eUndoId, &aRewriter );
4057 rSh.StartUndo( eUndoId, &aRewriter );
4059 rSh.StartAction();
4060 rSrcSh.StartAction();
4062 SfxDispatcher* pDispatch = rSrcSh.GetView().GetViewFrame().GetDispatcher();
4063 pDispatch->Execute(SID_COPY, SfxCallMode::SYNCHRON);
4065 rSrcSh.Push(); // save selection for later restoration
4066 rSh.EnterStdMode();
4067 rSh.SwCursorShell::SetCursor(rDragPt, false);
4069 bool bPasteIntoTable = rSh.GetCursor()->GetPointNode().GetTableBox() != nullptr;
4071 // store cursor
4072 ::sw::mark::MarkBase* pMark = rSh.SetBookmark(
4073 vcl::KeyCode(),
4074 OUString(),
4075 IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
4077 // paste rows above/columns before
4078 pDispatch->Execute(bTableCol ? FN_TABLE_PASTE_COL_BEFORE : FN_TABLE_PASTE_ROW_BEFORE, SfxCallMode::SYNCHRON);
4080 // go to the previously inserted table rows and set them to tracked insertion, if needed
4081 bool bNeedTrack = !bTableCol && rSh.getIDocumentRedlineAccess().IsRedlineOn();
4083 // restore cursor position
4084 if (bNeedTrack && pMark != nullptr)
4085 rSh.GotoMark( pMark );
4087 if ( !bNeedTrack && !bPasteIntoTable )
4089 rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // restore selection...
4091 // delete source rows/columns
4092 if (bMove)
4093 pDispatch->Execute(bTableCol
4094 ? FN_TABLE_DELETE_COL
4095 : FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
4097 else
4099 const SwTableBox* pBoxStt = rSh.GetCursor()->GetPointNode().GetTableBox();
4100 SwTableLine* pLine = pBoxStt ? const_cast<SwTableLine*>( pBoxStt->GetUpper()): nullptr;
4102 for (sal_Int32 nDeleted = 0; bNeedTrack && nDeleted < nSelRowOrCols;)
4104 // move up text cursor (note: "true" is important for the layout level)
4105 if ( !rSh.Up(false) )
4106 break;
4108 const SwTableBox* pBox = rSh.GetCursor()->GetPointNode().GetTableBox();
4110 if ( !pBox )
4111 break;
4113 // Up() reaches a new row
4114 if ( pBox->GetUpper() != pLine )
4116 //rSh.SelTableRow();
4117 SvxPrintItem aTracked(RES_PRINT, false);
4118 rSh.GetDoc()->SetRowNotTracked( *rSh.GetCursor(), aTracked );
4119 ++nDeleted;
4120 pLine = const_cast<SwTableLine*>(pBox->GetUpper());
4124 rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // restore selection...
4126 // delete source rows/columns
4127 if (bMove)
4129 // restore cursor position
4130 if (pMarkMoveFrom != nullptr)
4132 rSh.GotoMark( pMarkMoveFrom );
4133 rSh.getIDocumentMarkAccess()->deleteMark( pMarkMoveFrom );
4136 // tracked table row moving: set original rows as tracked deletion,
4137 // otherwise delete original rows/columns (tracking column deletion
4138 // and insertion is not supported yet)
4139 if ( !bTableCol && bNeedTrack )
4141 pLine = nullptr;
4143 for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols;)
4145 const SwTableBox* pBox = rSh.GetCursor()->GetPointNode().GetTableBox();
4147 if ( !pBox )
4148 break;
4150 if ( pBox->GetUpper() != pLine )
4152 pLine = const_cast<SwTableLine*>(pBox->GetUpper());
4153 pDispatch->Execute(FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
4154 ++nDeleted;
4157 bool bMoved = false;
4158 if (bSelUpToDown)
4159 bMoved = rSh.Up(false);
4160 else
4161 bMoved = rSh.Down(false);
4162 if (!bMoved)
4163 break;
4166 else
4168 // set cursor in the first cell of the original selection
4169 rSh.GetCursor()->DeleteMark();
4170 rSh.GetCursor()->GetPoint()->Assign( rDelPos.GetIndex() + 1);
4172 for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols; ++nDeleted)
4174 pDispatch->Execute(bTableCol
4175 ? FN_TABLE_DELETE_COL
4176 : FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
4182 // restore cursor position
4183 if (pMark != nullptr)
4185 rSh.GotoMark( pMark );
4186 rSh.getIDocumentMarkAccess()->deleteMark( pMark );
4189 rSh.DestroyCursor();
4190 rSh.EndUndo();
4191 rSh.EndAction();
4192 rSh.EndAction();
4193 return true;
4196 if ( bMove && rSrcSh.HasWholeTabSelection() )
4197 bTableMove = true;
4199 else if( rSrcSh.IsSelFrameMode() || rSrcSh.IsObjSelected() )
4201 // don't move position-protected objects!
4202 if( bMove && rSrcSh.IsSelObjProtected( FlyProtectFlags::Pos ) != FlyProtectFlags::NONE )
4203 return false;
4205 bFrameSel = true;
4208 const SelectionType nSel = rSrcSh.GetSelectionType();
4210 SwUndoId eUndoId = bMove ? SwUndoId::UI_DRAG_AND_MOVE : SwUndoId::UI_DRAG_AND_COPY;
4212 SwRewriter aRewriter;
4214 aRewriter.AddRule(UndoArg1, rSrcSh.GetSelDescr());
4216 if(rSrcSh.GetDoc() != rSh.GetDoc())
4217 rSrcSh.StartUndo( eUndoId, &aRewriter );
4218 rSh.StartUndo( eUndoId, &aRewriter );
4220 rSh.StartAction();
4221 rSrcSh.StartAction();
4223 if( &rSrcSh != &rSh )
4225 rSh.EnterStdMode();
4226 rSh.SwCursorShell::SetCursor( rDragPt, true );
4227 cWord = rSrcSh.IntelligentCut( nSel, false );
4229 else if( !bTableSel && !bFrameSel )
4231 if( !rSh.IsAddMode() )
4233 // #i87233#
4234 if ( rSh.IsBlockMode() )
4236 // preserve order of cursors for block mode
4237 rSh.GoPrevCursor();
4240 rSh.SwCursorShell::CreateCursor();
4242 rSh.SwCursorShell::SetCursor( rDragPt, true, false );
4243 rSh.GoPrevCursor();
4244 cWord = rSh.IntelligentCut( rSh.GetSelectionType(), false );
4245 rSh.GoNextCursor();
4248 bInWrd = rSh.IsInWord();
4249 bEndWrd = rSh.IsEndWrd();
4250 bSttWrd = !bEndWrd && rSh.IsStartWord();
4251 bSttPara= rSh.IsSttPara();
4253 Point aSttPt( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY() );
4255 // at first, select InetFields!
4256 if( TransferBufferType::InetField == m_eBufferType )
4258 if( &rSrcSh == &rSh )
4260 rSh.GoPrevCursor();
4261 rSh.SwCursorShell::SetCursor( aSttPt, true );
4262 rSh.SelectTextAttr( RES_TXTATR_INETFMT );
4263 if( rSh.TestCurrPam( rDragPt ) )
4265 // don't copy/move inside of yourself
4266 rSh.DestroyCursor();
4267 rSh.EndUndo();
4268 rSh.EndAction();
4269 rSh.EndAction();
4270 return false;
4272 rSh.GoNextCursor();
4274 else
4276 rSrcSh.SwCursorShell::SetCursor( aSttPt, true );
4277 rSrcSh.SelectTextAttr( RES_TXTATR_INETFMT );
4280 // is there a URL attribute at the insert point? Then replace that,
4281 // so simply put up a selection?
4282 rSh.DelINetAttrWithText();
4283 g_bDDINetAttr = true;
4286 if ( rSrcSh.IsSelFrameMode() )
4288 //Hack: fool the special treatment
4289 aSttPt = rSrcSh.GetObjRect().Pos();
4292 bool bRet = rSrcSh.SwFEShell::Copy(rSh, aSttPt, rDragPt, bMove,
4293 !bIsXSelection);
4295 if( !bIsXSelection )
4297 rSrcSh.Push();
4298 if ( bRet && bMove && !bFrameSel )
4300 if ( bTableSel )
4302 /* delete table contents not cells */
4303 rSrcSh.Delete(false);
4305 else
4307 //SmartCut, take one of the blanks along.
4308 rSh.SwCursorShell::DestroyCursor();
4309 if ( cWord == SwWrtShell::WORD_SPACE_BEFORE )
4310 rSh.ExtendSelection( false );
4311 else if ( cWord == SwWrtShell::WORD_SPACE_AFTER )
4312 rSh.ExtendSelection();
4313 rSrcSh.DelRight();
4316 rSrcSh.KillPams();
4317 rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
4319 /* after dragging a table selection inside one shell
4320 set cursor to the drop position. */
4321 if( &rSh == &rSrcSh && ( bTableSel || rSh.IsBlockMode() ) )
4323 rSrcSh.CalcLayout();
4324 rSrcSh.SwCursorShell::SetCursor(rDragPt);
4325 rSrcSh.GetCursor()->SetMark();
4329 if( bRet && !bTableSel && !bFrameSel )
4331 if( (bInWrd || bEndWrd) &&
4332 (cWord == SwWrtShell::WORD_SPACE_AFTER ||
4333 cWord == SwWrtShell::WORD_SPACE_BEFORE) )
4335 if ( bSttWrd || (bInWrd && !bEndWrd))
4336 rSh.SwEditShell::Insert(' ', bIsXSelection);
4337 if ( !bSttWrd || (bInWrd && !bSttPara) )
4339 rSh.SwapPam();
4340 if ( !bSttWrd )
4341 rSh.SwEditShell::Insert(' ', bIsXSelection);
4342 rSh.SwapPam();
4346 if( bIsXSelection )
4348 if( &rSrcSh == &rSh && !rSh.IsAddMode() )
4350 rSh.SwCursorShell::DestroyCursor();
4351 rSh.GoPrevCursor();
4353 else
4355 rSh.SwapPam();
4356 rSh.SwCursorShell::ClearMark();
4359 else
4361 if( rSh.IsAddMode() )
4362 rSh.SwCursorShell::CreateCursor();
4363 else
4365 // turn on selection mode
4366 rSh.SttSelect();
4367 rSh.EndSelect();
4371 else if ( bRet && bTableMove )
4373 SfxDispatcher* pDispatch = rSrcSh.GetView().GetViewFrame().GetDispatcher();
4374 pDispatch->Execute(FN_TABLE_DELETE_TABLE, SfxCallMode::SYNCHRON);
4377 if( bRet && bMove && bFrameSel )
4378 rSrcSh.LeaveSelFrameMode();
4380 if( rSrcSh.GetDoc() != rSh.GetDoc() )
4381 rSrcSh.EndUndo();
4382 rSh.EndUndo();
4384 // put the shell in the right state
4385 if( &rSrcSh != &rSh && ( rSh.IsFrameSelected() || rSh.IsObjSelected() ))
4386 rSh.EnterSelFrameMode();
4388 rSrcSh.EndAction();
4389 rSh.EndAction();
4390 return true;
4393 // Interfaces for Selection
4394 void SwTransferable::CreateSelection( SwWrtShell& rSh,
4395 const SwFrameShell * _pCreatorView )
4397 rtl::Reference<SwTransferable> pNew = new SwTransferable( rSh );
4399 pNew->m_pCreatorView = _pCreatorView;
4401 SwModule::get()->m_pXSelection = pNew.get();
4402 pNew->CopyToPrimarySelection();
4405 void SwTransferable::ClearSelection( const SwWrtShell& rSh,
4406 const SwFrameShell * _pCreatorView)
4408 SwModule* pMod = SwModule::get();
4409 if( pMod->m_pXSelection &&
4410 ((!pMod->m_pXSelection->m_pWrtShell) || (pMod->m_pXSelection->m_pWrtShell == &rSh)) &&
4411 (!_pCreatorView || (pMod->m_pXSelection->m_pCreatorView == _pCreatorView)) )
4413 TransferableHelper::ClearPrimarySelection();
4417 SwTransferable* SwTransferable::GetSwTransferable( const TransferableDataHelper& rData )
4419 return dynamic_cast<SwTransferable*>(rData.GetTransferable().get());
4422 SwTransferDdeLink::SwTransferDdeLink( SwTransferable& rTrans, SwWrtShell& rSh )
4423 : m_rTransfer(rTrans)
4424 , m_pDocShell(nullptr)
4425 , m_nOldTimeOut(0)
4426 , m_bDelBookmark(false)
4427 , m_bInDisconnect(false)
4429 // we only end up here with table- or text selection
4430 if( SelectionType::TableCell & rSh.GetSelectionType() )
4432 SwFrameFormat* pFormat = rSh.GetTableFormat();
4433 if( pFormat )
4434 m_sName = pFormat->GetName();
4436 else
4438 // creating a temp. bookmark without undo
4439 bool bUndo = rSh.DoesUndo();
4440 rSh.DoUndo( false );
4441 bool bIsModified = rSh.IsModified();
4443 ::sw::mark::MarkBase* pMark = rSh.SetBookmark(
4444 vcl::KeyCode(),
4445 OUString(),
4446 IDocumentMarkAccess::MarkType::DDE_BOOKMARK);
4447 if(pMark)
4449 m_sName = pMark->GetName();
4450 m_bDelBookmark = true;
4451 if( !bIsModified )
4452 rSh.ResetModified();
4454 else
4455 m_sName.clear();
4456 rSh.DoUndo( bUndo );
4459 if( m_sName.isEmpty() ||
4460 nullptr == ( m_pDocShell = rSh.GetDoc()->GetDocShell() ))
4461 return;
4463 // then we create our "server" and connect to it
4464 m_xRefObj = m_pDocShell->DdeCreateLinkSource( m_sName );
4465 if( m_xRefObj.is() )
4467 m_xRefObj->AddConnectAdvise( this );
4468 m_xRefObj->AddDataAdvise( this,
4469 OUString(),
4470 ADVISEMODE_NODATA | ADVISEMODE_ONLYONCE );
4471 m_nOldTimeOut = m_xRefObj->GetUpdateTimeout();
4472 m_xRefObj->SetUpdateTimeout( 0 );
4476 SwTransferDdeLink::~SwTransferDdeLink()
4478 if( m_xRefObj.is() )
4479 Disconnect( true );
4482 ::sfx2::SvBaseLink::UpdateResult SwTransferDdeLink::DataChanged( const OUString& ,
4483 const uno::Any& )
4485 // well, that's it with the link
4486 if( !m_bInDisconnect )
4488 if( FindDocShell() && m_pDocShell->GetView() )
4489 m_rTransfer.RemoveDDELinkFormat( m_pDocShell->GetView()->GetEditWin() );
4490 Disconnect( false );
4492 return SUCCESS;
4495 bool SwTransferDdeLink::WriteData( SvStream& rStrm )
4497 if( !m_xRefObj.is() || !FindDocShell() )
4498 return false;
4500 TransferableDataHelper::WriteDDELink(rStrm, Application::GetAppName(),
4501 m_pDocShell->GetTitle(SFX_TITLE_FULLNAME), m_sName);
4503 IDocumentMarkAccess* const pMarkAccess = m_pDocShell->GetDoc()->getIDocumentMarkAccess();
4504 auto ppMark = pMarkAccess->findMark(m_sName);
4505 if(ppMark != pMarkAccess->getAllMarksEnd()
4506 && IDocumentMarkAccess::GetType(**ppMark) != IDocumentMarkAccess::MarkType::BOOKMARK)
4508 // the mark is still a DdeBookmark
4509 // we replace it with a Bookmark, so it will get saved etc.
4510 ::sw::mark::MarkBase* const pMark = *ppMark;
4511 ::sfx2::SvLinkSource* p = m_xRefObj.get();
4512 SwServerObject& rServerObject = dynamic_cast<SwServerObject&>(*p);
4514 // collecting state of old mark
4515 SwPaM aPaM(pMark->GetMarkStart());
4516 *aPaM.GetPoint() = pMark->GetMarkStart();
4517 if(pMark->IsExpanded())
4519 aPaM.SetMark();
4520 *aPaM.GetMark() = pMark->GetMarkEnd();
4522 OUString sMarkName = pMark->GetName();
4524 // remove mark
4525 rServerObject.SetNoServer(); // this removes the connection between SwServerObject and mark
4526 // N.B. ppMark was not loaded from file and cannot have xml:id
4527 pMarkAccess->deleteMark(ppMark, false);
4529 // recreate as Bookmark
4530 ::sw::mark::MarkBase* const pNewMark = pMarkAccess->makeMark(
4531 aPaM,
4532 sMarkName,
4533 IDocumentMarkAccess::MarkType::BOOKMARK,
4534 ::sw::mark::InsertMode::New);
4535 rServerObject.SetDdeBookmark(*pNewMark);
4538 m_bDelBookmark = false;
4539 return true;
4542 void SwTransferDdeLink::Disconnect( bool bRemoveDataAdvise )
4544 // don't accept DataChanged anymore, when already in Disconnect!
4545 // (DTOR from Bookmark sends a DataChanged!)
4546 bool bOldDisconnect = m_bInDisconnect;
4547 m_bInDisconnect = true;
4549 // destroy the unused bookmark again (without Undo!)?
4550 if( m_bDelBookmark && m_xRefObj.is() && FindDocShell() )
4552 SwDoc* pDoc = m_pDocShell->GetDoc();
4553 ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
4555 // #i58448#
4556 Link<bool,void> aSavedOle2Link( pDoc->GetOle2Link() );
4557 pDoc->SetOle2Link( Link<bool,void>() );
4559 bool bIsModified = pDoc->getIDocumentState().IsModified();
4561 IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
4562 pMarkAccess->deleteMark(pMarkAccess->findMark(m_sName), false);
4564 if( !bIsModified )
4565 pDoc->getIDocumentState().ResetModified();
4566 // #i58448#
4567 pDoc->SetOle2Link( aSavedOle2Link );
4569 m_bDelBookmark = false;
4572 if( m_xRefObj.is() )
4574 m_xRefObj->SetUpdateTimeout( m_nOldTimeOut );
4575 m_xRefObj->RemoveConnectAdvise( this );
4576 if( bRemoveDataAdvise )
4577 // in a DataChanged the SelectionObject must NEVER be deleted
4578 // is already handled by the base class
4579 // (ADVISEMODE_ONLYONCE!!!!)
4580 // but always in normal Disconnect!
4581 m_xRefObj->RemoveAllDataAdvise( this );
4582 m_xRefObj.clear();
4584 m_bInDisconnect = bOldDisconnect;
4587 bool SwTransferDdeLink::FindDocShell()
4589 SfxObjectShell* pTmpSh = SfxObjectShell::GetFirst( checkSfxObjectShell<SwDocShell> );
4590 while( pTmpSh )
4592 if( pTmpSh == m_pDocShell ) // that's what we want to have
4594 if( m_pDocShell->GetDoc() )
4595 return true;
4596 break; // the Doc is not there anymore, so leave!
4598 pTmpSh = SfxObjectShell::GetNext( *pTmpSh, checkSfxObjectShell<SwDocShell> );
4601 m_pDocShell = nullptr;
4602 return false;
4605 void SwTransferDdeLink::Closed()
4607 if( !m_bInDisconnect && m_xRefObj.is() )
4609 m_xRefObj->RemoveAllDataAdvise( this );
4610 m_xRefObj->RemoveConnectAdvise( this );
4611 m_xRefObj.clear();
4615 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */