xref: /core/sw/source/uibase/dochdl/swdtflvr.cxx (revision 18ef3915)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <config_features.h>
21 
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>
28 
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>
69 
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
76 
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>
129 
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>
138 
139 #include <memory>
140 
141 /* default (A4 format) width of 210mm - 2 * border size (border on both sides) */
142 constexpr tools::Long constOleWidthInMm = 210 - 2 * lMinBorderInMm;
143 
144 constexpr Size constOleSize100mm(
145     constOleWidthInMm * 100, // convert from mm to 100mm
146     3000 // 3 cm
147 );
148 
149 constexpr Size constOleSizeTwip = o3tl::convert(constOleSize100mm, o3tl::Length::mm100, o3tl::Length::twip);
150 
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;
158 
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 {
164 
collectUIInformation(const OUString & rAction,const OUString & aParameters)165 void collectUIInformation(const OUString& rAction, const OUString& aParameters)
166 {
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);
174 }
175 
176 }
177 
178 class SwTransferDdeLink : public ::sfx2::SvBaseLink
179 {
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;
187 
188     bool FindDocShell();
189 
190     using sfx2::SvBaseLink::Disconnect;
191 
192 protected:
193     virtual ~SwTransferDdeLink() override;
194 
195 public:
196     SwTransferDdeLink( SwTransferable& rTrans, SwWrtShell& rSh );
197 
198     virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(
199         const OUString& rMimeType, const css::uno::Any & rValue ) override;
200     virtual void Closed() override;
201 
202     bool WriteData( SvStream& rStrm );
203 
204     void Disconnect( bool bRemoveDataAdvise );
205 };
206 
207 /// Tracks the boundaries of pasted content and notifies listeners.
208 class SwPasteContext
209 {
210 public:
211     SwPasteContext(SwWrtShell& rWrtShell);
212     ~SwPasteContext();
213 
214     void remember();
215     void forget();
216 
217 private:
218     SwWrtShell& m_rWrtShell;
219     std::optional<SwPaM> m_oPaM;
220     sal_Int32 m_nStartContent = 0;
221 };
222 
223 namespace {
224 
225 // helper class for Action and Undo enclosing
226 class SwTrnsfrActionAndUndo
227 {
228     SwWrtShell *pSh;
229 public:
SwTrnsfrActionAndUndo(SwWrtShell * pS,bool bDelSel=false,SwPasteContext * pContext=nullptr)230     SwTrnsfrActionAndUndo( SwWrtShell *pS, bool bDelSel = false, SwPasteContext* pContext = nullptr)
231         : pSh( pS )
232     {
233         pSh->StartUndo( SwUndoId::PASTE_CLIPBOARD );
234         if( bDelSel )
235         {
236             if (pContext)
237                 pContext->forget();
238             pSh->DelRight();
239             if (pContext)
240                 pContext->remember();
241         }
242         pSh->StartAllAction();
243     }
~SwTrnsfrActionAndUndo()244     ~SwTrnsfrActionAndUndo() COVERITY_NOEXCEPT_FALSE
245     {
246         pSh->EndUndo();
247         pSh->EndAllAction();
248     }
249 };
250 
251 }
252 
SwTransferable(SwWrtShell & rSh)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)
260 {
261     rSh.GetView().AddTransferable(*this);
262     SwDocShell* pDShell = rSh.GetDoc()->GetDocShell();
263     if( !pDShell )
264         return;
265 
266     pDShell->FillTransferableObjectDescriptor( m_aObjDesc );
267     if( pDShell->GetMedium() )
268     {
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 );
274     }
275 
276     PrepareOLE( m_aObjDesc );
277 }
278 
~SwTransferable()279 SwTransferable::~SwTransferable()
280 {
281     SolarMutexGuard aSolarGuard;
282 
283     // the DDELink still needs the WrtShell!
284     DisconnectDDE();
285 
286     m_pWrtShell = nullptr;
287 
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();
292 
293     // first close, then the Ref. can be cleared as well, so that
294     // the DocShell really gets deleted!
295     if( m_aDocShellRef.Is() )
296     {
297         SfxObjectShell * pObj = m_aDocShellRef;
298         SwDocShell* pDocSh = static_cast<SwDocShell*>(pObj);
299         pDocSh->DoClose();
300     }
301     m_aDocShellRef.Clear();
302 
303     SwModule* pMod = SW_MOD();
304     if(pMod)
305     {
306         if ( pMod->m_pDragDrop == this )
307             pMod->m_pDragDrop = nullptr;
308         else if ( pMod->m_pXSelection == this )
309             pMod->m_pXSelection = nullptr;
310     }
311 
312     m_eBufferType = TransferBufferType::NONE;
313 }
314 
lcl_GetDoc(SwDocFac & rDocFac)315 static SwDoc& lcl_GetDoc(SwDocFac & rDocFac)
316 {
317     SwDoc& rDoc = rDocFac.GetDoc();
318     rDoc.SetClipBoard( true );
319     return rDoc;
320 }
321 
ObjectReleased()322 void SwTransferable::ObjectReleased()
323 {
324     SwModule *pMod = SW_MOD();
325     if (!pMod)
326         return;
327     if( this == pMod->m_pDragDrop )
328         pMod->m_pDragDrop = nullptr;
329     else if( this == pMod->m_pXSelection )
330         pMod->m_pXSelection = nullptr;
331 }
332 
AddSupportedFormats()333 void SwTransferable::AddSupportedFormats()
334 {
335     // only need if we are the current XSelection Object
336     SwModule *pMod = SW_MOD();
337     if( this == pMod->m_pXSelection || comphelper::LibreOfficeKit::isActive())
338     {
339         SetDataForDragAndDrop( Point( 0,0) );
340     }
341 }
342 
InitOle(SfxObjectShell * pDoc)343 void SwTransferable::InitOle( SfxObjectShell* pDoc )
344 {
345     //set OleVisArea. Upper left corner of the page and size of
346     //RealSize in Twips.
347     const Size aSz(constOleSizeTwip);
348     SwRect aVis( Point( DOCUMENTBORDER, DOCUMENTBORDER ), aSz );
349     pDoc->SetVisArea( aVis.SVRect() );
350 }
351 
FindOLEObj(sal_Int64 & nAspect) const352 uno::Reference < embed::XEmbeddedObject > SwTransferable::FindOLEObj( sal_Int64& nAspect ) const
353 {
354     uno::Reference < embed::XEmbeddedObject > xObj;
355     if( m_pClpDocFac )
356     {
357         SwIterator<SwContentNode,SwFormatColl> aIter( *m_pClpDocFac->GetDoc().GetDfltGrfFormatColl() );
358         for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
359             if( SwNodeType::Ole == pNd->GetNodeType() )
360             {
361                 xObj = static_cast<SwOLENode*>(pNd)->GetOLEObj().GetOleRef();
362                 nAspect = static_cast<SwOLENode*>(pNd)->GetAspect();
363                 break;
364             }
365     }
366     return xObj;
367 }
368 
FindOLEReplacementGraphic() const369 const Graphic* SwTransferable::FindOLEReplacementGraphic() const
370 {
371     if( m_pClpDocFac )
372     {
373         SwIterator<SwContentNode,SwFormatColl> aIter( *m_pClpDocFac->GetDoc().GetDfltGrfFormatColl() );
374         for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
375             if( SwNodeType::Ole == pNd->GetNodeType() )
376             {
377                 return static_cast<SwOLENode*>(pNd)->GetGraphic();
378             }
379     }
380 
381     return nullptr;
382 }
383 
RemoveDDELinkFormat(vcl::Window & rWin)384 void SwTransferable::RemoveDDELinkFormat(vcl::Window& rWin)
385 {
386     RemoveFormat( SotClipboardFormatId::LINK );
387     if (rWin.GetClipboard()->getContents().get() == this)
388         CopyToClipboard(&rWin);
389 }
390 
DisconnectDDE()391 void SwTransferable::DisconnectDDE()
392 {
393     if( m_xDdeLink.is() )
394     {
395         m_xDdeLink->Disconnect( true );
396         m_xDdeLink.clear();
397     }
398 }
399 
400 namespace
401 {
402     //Resolves: fdo#40717 surely when we create a clipboard document we should
403     //overwrite the clipboard documents styles and settings with that of the
404     //source, so that we can WYSIWYG paste. If we want that the destinations
405     //styles are used over the source styles, that's a matter of the
406     //destination paste code to handle, not the source paste code.
lclOverWriteDoc(SwWrtShell & rSrcWrtShell,SwDoc & rDest)407     void lclOverWriteDoc(SwWrtShell &rSrcWrtShell, SwDoc &rDest)
408     {
409         const SwDoc &rSrc = *rSrcWrtShell.GetDoc();
410 
411         rDest.ReplaceCompatibilityOptions(rSrc);
412         rDest.ReplaceDefaults(rSrc);
413 
414         //It would probably make most sense here to only insert the styles used
415         //by the selection, e.g. apply SwDoc::IsUsed on styles ?
416         rDest.ReplaceStyles(rSrc, false);
417 
418         rSrcWrtShell.Copy(rDest);
419 
420         rDest.GetMetaFieldManager().copyDocumentProperties(rSrc);
421     }
422 
lclCheckAndPerformRotation(Graphic & aGraphic)423     void lclCheckAndPerformRotation(Graphic& aGraphic)
424     {
425         GraphicNativeMetadata aMetadata;
426         if ( !aMetadata.read(aGraphic) )
427             return;
428 
429         Degree10 aRotation = aMetadata.getRotation();
430         if (aRotation)
431         {
432             GraphicNativeTransform aTransform( aGraphic );
433             aTransform.rotate( aRotation );
434         }
435     }
436 }
437 
isComplex()438 sal_Bool SAL_CALL SwTransferable::isComplex()
439 {
440     sal_Int32 nTextLength = 0;
441     SwNodes& aNodes = m_pWrtShell->GetDoc()->GetNodes();
442     for (SwPaM& rPaM : m_pWrtShell->GetCursor()->GetRingContainer())
443     {
444         for (SwNodeOffset nIndex = rPaM.GetMark()->GetNodeIndex();
445              nIndex <= rPaM.GetPoint()->GetNodeIndex(); ++nIndex)
446         {
447             SwNode& rNd = *aNodes[nIndex];
448 
449             SwTextNode* pTextNode = rNd.GetTextNode();
450             if (pTextNode)
451             {
452                 if (pTextNode->HasHints())
453                 {
454                     for (size_t nHint = 0; nHint < pTextNode->GetSwpHints().Count(); ++nHint)
455                     {
456                         SwTextAttr* pHint = pTextNode->GetSwpHints().Get(nHint);
457                         if (pHint->Which() == RES_TXTATR_FLYCNT)
458                         {
459                             return true; // Complex
460                         }
461                     }
462                 }
463 
464                 FrameClientSortList_t vFrames;
465                 ::CollectFrameAtNode(rNd, vFrames, true);
466                 if (!vFrames.empty())
467                 {
468                     // There is an at-char anchored object to this node, that's complex.
469                     return true;
470                 }
471 
472                 nTextLength += pTextNode->GetText().getLength();
473                 if (nTextLength >= 1024 * 512)
474                     return true; // Complex
475             }
476         }
477     }
478 
479     if (m_pWrtShell->GetSelectionType() == SelectionType::DrawObject)
480         return true; // Complex
481 
482     // Simple
483     return false;
484 }
485 
GetData(const DataFlavor & rFlavor,const OUString & rDestDoc)486 bool SwTransferable::GetData( const DataFlavor& rFlavor, const OUString& rDestDoc )
487 {
488     SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
489 
490     // we can only fulfil the request if
491     // 1) we have data for this format
492     // 2) we have either a clipboard document (pClpDocFac), or
493     //    we have a SwWrtShell (so we can generate a new clipboard document)
494     if( !HasFormat( nFormat ) || ( m_pClpDocFac == nullptr && m_pWrtShell == nullptr ) )
495         return false;
496 
497     if( !m_pClpDocFac )
498     {
499         SelectionType nSelectionType = m_pWrtShell->GetSelectionType();
500 
501         // when pending we will not get the correct type, but SelectionType::Text
502         // as fallback. This *happens* during D&D, so we need to check if we are in
503         // the fallback and just try to get a graphic
504         const bool bPending(m_pWrtShell->ActionPend());
505 
506         // SEL_GRF is from ContentType of editsh
507         if(bPending || ((SelectionType::Graphic | SelectionType::DrawObject | SelectionType::DbForm) & nSelectionType))
508         {
509             m_oClpGraphic.emplace();
510             if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
511                 m_pOrigGraphic = &*m_oClpGraphic;
512             m_oClpBitmap.emplace();
513             if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
514                 m_pOrigGraphic = &*m_oClpBitmap;
515 
516             // is it a URL-Button ?
517             OUString sURL;
518             OUString sDesc;
519             if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
520             {
521                 m_oBookmark.emplace( sURL, sDesc );
522                 m_eBufferType = TransferBufferType::InetField;
523             }
524         }
525 
526         m_pClpDocFac.reset(new SwDocFac);
527         SwDoc& rTmpDoc = lcl_GetDoc(*m_pClpDocFac);
528 
529         rTmpDoc.getIDocumentFieldsAccess().LockExpFields();     // never update fields - leave text as it is
530         lclOverWriteDoc(*m_pWrtShell, rTmpDoc);
531 
532         // in CORE a new one was created (OLE-objects copied!)
533         m_aDocShellRef = rTmpDoc.GetTmpDocShell();
534         if( m_aDocShellRef.Is() )
535             SwTransferable::InitOle( m_aDocShellRef );
536         rTmpDoc.SetTmpDocShell( nullptr );
537 
538         if( nSelectionType & SelectionType::Text && !m_pWrtShell->HasMark() )
539         {
540             SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
541 
542             Point aPos( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY());
543 
544             bool bSelect = g_bExecuteDrag &&
545                             m_pWrtShell->GetView().GetDocShell() &&
546                             !m_pWrtShell->GetView().GetDocShell()->IsReadOnly();
547             if( m_pWrtShell->GetContentAtPos( aPos, aContentAtPos, bSelect ) )
548             {
549                 m_oBookmark.emplace(
550                         static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr)->GetValue(),
551                         aContentAtPos.sStr );
552                 m_eBufferType = TransferBufferType::InetField;
553                 if( bSelect )
554                     m_pWrtShell->SelectTextAttr( RES_TXTATR_INETFMT );
555             }
556         }
557         if( m_pWrtShell->IsFrameSelected() )
558         {
559             SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
560             m_pWrtShell->GetFlyFrameAttr( aSet );
561             const SwFormatURL& rURL = aSet.Get( RES_URL );
562             if( rURL.GetMap() )
563                 m_pImageMap.reset(new ImageMap( *rURL.GetMap() ));
564             else if( !rURL.GetURL().isEmpty() )
565                 m_pTargetURL.reset(new INetImage(OUString(), rURL.GetURL(),
566                                             rURL.GetTargetFrameName() ));
567         }
568     }
569 
570     bool bOK = false;
571     if( TransferBufferType::Ole == m_eBufferType )
572     {
573         //TODO/MBA: testing - is this the "single OLE object" case?!
574         // get OLE-Object from ClipDoc and get the data from that.
575         sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT; // will be set in the next statement
576         uno::Reference < embed::XEmbeddedObject > xObj = FindOLEObj( nAspect );
577         const Graphic* pOLEGraph = FindOLEReplacementGraphic();
578         if( xObj.is() )
579         {
580             TransferableDataHelper aD( new SvEmbedTransferHelper( xObj, pOLEGraph, nAspect ) );
581             uno::Any aAny = aD.GetAny(rFlavor, rDestDoc);
582             if( aAny.hasValue() )
583                 bOK = SetAny( aAny );
584         }
585 
586         // the following solution will be used in the case when the object can not generate the image
587         // TODO/LATER: in future the transferhelper must probably be created based on object and the replacement stream
588         // TODO: Block not required now, SvEmbedTransferHelper should be able to handle GDIMetaFile format
589         if ( nFormat == SotClipboardFormatId::GDIMETAFILE )
590         {
591             pOLEGraph = FindOLEReplacementGraphic();
592             if ( pOLEGraph )
593                 bOK = SetGDIMetaFile( pOLEGraph->GetGDIMetaFile() );
594         }
595     }
596     else
597     {
598         switch( nFormat )
599         {
600         case SotClipboardFormatId::LINK:
601             if( m_xDdeLink.is() )
602                 bOK = SetObject( m_xDdeLink.get(), SWTRANSFER_OBJECTTYPE_DDE, rFlavor );
603             break;
604 
605         case SotClipboardFormatId::OBJECTDESCRIPTOR:
606         case SotClipboardFormatId::LINKSRCDESCRIPTOR:
607             bOK = SetTransferableObjectDescriptor( m_aObjDesc );
608             break;
609 
610         case SotClipboardFormatId::DRAWING:
611             {
612                 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
613                 bOK = SetObject( rDoc.getIDocumentDrawModelAccess().GetDrawModel(),
614                                 SWTRANSFER_OBJECTTYPE_DRAWMODEL, rFlavor );
615             }
616             break;
617 
618         case SotClipboardFormatId::STRING:
619         {
620             SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
621             bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_STRING, rFlavor );
622         }
623         break;
624         case SotClipboardFormatId::RTF:
625         {
626             SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
627             bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_RTF, rFlavor );
628         }
629         break;
630         case SotClipboardFormatId::RICHTEXT:
631         {
632             SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
633             bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_RICHTEXT, rFlavor );
634         }
635         break;
636 
637         case SotClipboardFormatId::HTML:
638         {
639             SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
640             bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_HTML, rFlavor );
641         }
642             break;
643 
644         case SotClipboardFormatId::SVXB:
645             if( m_eBufferType & TransferBufferType::Graphic && m_pOrigGraphic )
646                 bOK = SetGraphic( *m_pOrigGraphic );
647             break;
648 
649         case SotClipboardFormatId::GDIMETAFILE:
650             if( m_eBufferType & TransferBufferType::Graphic )
651                 bOK = SetGDIMetaFile( m_oClpGraphic->GetGDIMetaFile() );
652             break;
653         case SotClipboardFormatId::BITMAP:
654         case SotClipboardFormatId::PNG:
655             // Neither pClpBitmap nor pClpGraphic are necessarily set
656             if( (m_eBufferType & TransferBufferType::Graphic) && (m_oClpBitmap || m_oClpGraphic))
657                 bOK = SetBitmapEx( (m_oClpBitmap ? m_oClpBitmap : m_oClpGraphic)->GetBitmapEx(), rFlavor );
658             break;
659 
660         case SotClipboardFormatId::SVIM:
661             if( m_pImageMap )
662                 bOK = SetImageMap( *m_pImageMap );
663             break;
664 
665         case SotClipboardFormatId::INET_IMAGE:
666             if( m_pTargetURL )
667                 bOK = SetINetImage( *m_pTargetURL, rFlavor );
668             break;
669 
670         case SotClipboardFormatId::SOLK:
671         case SotClipboardFormatId::NETSCAPE_BOOKMARK:
672         case SotClipboardFormatId::FILEGRPDESCRIPTOR:
673         case SotClipboardFormatId::FILECONTENT:
674         case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
675         case SotClipboardFormatId::SIMPLE_FILE:
676             if( (TransferBufferType::InetField & m_eBufferType) && m_oBookmark )
677                 bOK = SetINetBookmark( *m_oBookmark, rFlavor );
678             break;
679 
680         case SotClipboardFormatId::EMBED_SOURCE:
681             if( !m_aDocShellRef.Is() )
682             {
683                 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
684                 m_aDocShellRef = new SwDocShell(rDoc, SfxObjectCreateMode::EMBEDDED);
685                 m_aDocShellRef->DoInitNew();
686                 SwTransferable::InitOle( m_aDocShellRef );
687             }
688             bOK = SetObject( &m_aDocShellRef, SWTRANSFER_OBJECTTYPE_SWOLE,
689                             rFlavor );
690             break;
691         default: break;
692         }
693     }
694     return bOK;
695 }
696 
WriteObject(SvStream & rOStream,void * pObject,sal_uInt32 nObjectType,const DataFlavor &)697 bool SwTransferable::WriteObject( SvStream& rOStream,
698                                     void* pObject, sal_uInt32 nObjectType,
699                                     const DataFlavor& /*rFlavor*/ )
700 {
701     bool bRet = false;
702     WriterRef xWrt;
703 
704     switch( nObjectType )
705     {
706     case SWTRANSFER_OBJECTTYPE_DRAWMODEL:
707         {
708             // don't change the sequence of commands
709             SdrModel *pModel = static_cast<SdrModel*>(pObject);
710             rOStream.SetBufferSize( 16348 );
711 
712             // for the changed pool defaults from drawing layer pool set those
713             // attributes as hard attributes to preserve them for saving
714             const SfxItemPool& rItemPool = pModel->GetItemPool();
715             const SvxFontHeightItem& rDefaultFontHeight = rItemPool.GetUserOrPoolDefaultItem(EE_CHAR_FONTHEIGHT);
716 
717             // SW should have no MasterPages
718             OSL_ENSURE(0 == pModel->GetMasterPageCount(), "SW with MasterPages (!)");
719 
720             for(sal_uInt16 a(0); a < pModel->GetPageCount(); a++)
721             {
722                 const SdrPage* pPage = pModel->GetPage(a);
723                 SdrObjListIter aIter(pPage, SdrIterMode::DeepNoGroups);
724 
725                 while(aIter.IsMore())
726                 {
727                     SdrObject* pObj = aIter.Next();
728                     const SvxFontHeightItem& rItem = pObj->GetMergedItem(EE_CHAR_FONTHEIGHT);
729 
730                     if(rItem.GetHeight() == rDefaultFontHeight.GetHeight())
731                     {
732                         pObj->SetMergedItem(rDefaultFontHeight);
733                     }
734                 }
735             }
736 
737             {
738                 uno::Reference<io::XOutputStream> xDocOut( new utl::OOutputStreamWrapper( rOStream ) );
739                 SvxDrawingLayerExport( pModel, xDocOut );
740             }
741 
742             bRet = ERRCODE_NONE == rOStream.GetError();
743         }
744         break;
745 
746     case SWTRANSFER_OBJECTTYPE_SWOLE:
747         {
748             SfxObjectShell*   pEmbObj = static_cast<SfxObjectShell*>(pObject);
749             try
750             {
751                 ::utl::TempFileFast aTempFile;
752                 SvStream* pTempStream = aTempFile.GetStream(StreamMode::READWRITE);
753                 uno::Reference< embed::XStorage > xWorkStore =
754                     ::comphelper::OStorageHelper::GetStorageFromStream( new utl::OStreamWrapper(*pTempStream), embed::ElementModes::READWRITE );
755 
756                 // write document storage
757                 pEmbObj->SetupStorage( xWorkStore, SOFFICE_FILEFORMAT_CURRENT, false );
758                 // mba: no BaseURL for clipboard
759                 SfxMedium aMedium( xWorkStore, OUString() );
760                 pEmbObj->DoSaveObjectAs( aMedium, false );
761                 pEmbObj->DoSaveCompleted();
762 
763                 uno::Reference< embed::XTransactedObject > xTransact( xWorkStore, uno::UNO_QUERY );
764                 if ( xTransact.is() )
765                     xTransact->commit();
766 
767                 rOStream.SetBufferSize( 0xff00 );
768                 rOStream.WriteStream( *pTempStream );
769 
770                 xWorkStore->dispose();
771                 xWorkStore.clear();
772             }
773             catch (const uno::Exception&)
774             {
775             }
776 
777             bRet = ( rOStream.GetError() == ERRCODE_NONE );
778         }
779         break;
780 
781     case SWTRANSFER_OBJECTTYPE_DDE:
782         {
783             rOStream.SetBufferSize( 1024 );
784             SwTransferDdeLink* pDdeLnk = static_cast<SwTransferDdeLink*>(pObject);
785             if( pDdeLnk->WriteData( rOStream ) )
786             {
787                 bRet = ERRCODE_NONE == rOStream.GetError();
788             }
789         }
790         break;
791 
792     case SWTRANSFER_OBJECTTYPE_HTML:
793     {
794         // LOK is interested in getting images embedded for copy/paste support.
795         GetHTMLWriter( comphelper::LibreOfficeKit::isActive() ? u"EmbedImages;NoPrettyPrint"_ustr : OUString(), OUString(), xWrt );
796         break;
797     }
798 
799     case SWTRANSFER_OBJECTTYPE_RTF:
800     case SWTRANSFER_OBJECTTYPE_RICHTEXT:
801         GetRTFWriter(std::u16string_view(), OUString(), xWrt);
802         break;
803 
804     case SWTRANSFER_OBJECTTYPE_STRING:
805         GetASCWriter(std::u16string_view(), OUString(), xWrt);
806         if( xWrt.is() )
807         {
808             SwAsciiOptions aAOpt;
809             aAOpt.SetCharSet( RTL_TEXTENCODING_UTF8 );
810             xWrt->SetAsciiOptions( aAOpt );
811 
812             // no start char for clipboard
813             xWrt->m_bUCS2_WithStartChar = false;
814         }
815         break;
816     default: break;
817     }
818 
819     if( xWrt.is() )
820     {
821         SwDoc* pDoc = static_cast<SwDoc*>(pObject);
822         xWrt->m_bWriteClipboardDoc = true;
823         xWrt->m_bWriteOnlyFirstTable = bool(TransferBufferType::Table & m_eBufferType);
824         xWrt->SetShowProgress(false);
825 
826 #if defined(DEBUGPASTE)
827         SvFileStream aPasteDebug(OUString(
828             "PASTEBUFFER.debug"), StreamMode::WRITE|StreamMode::TRUNC);
829         SwWriter aDbgWrt( aPasteDebug, *pDoc );
830         aDbgWrt.Write( xWrt );
831 #endif
832 
833         SwWriter aWrt( rOStream, *pDoc );
834         if( ! aWrt.Write( xWrt ).IsError() )
835         {
836             rOStream.WriteChar( '\0' );               // terminate with a zero
837             bRet = true;
838         }
839     }
840 
841     return bRet;
842 }
843 
Cut()844 int SwTransferable::Cut()
845 {
846     int nRet = Copy( true );
847     if( nRet )
848         DeleteSelection();
849     collectUIInformation(u"CUT"_ustr, u"parameter"_ustr);
850     return nRet;
851 }
852 
DeleteSelection()853 void SwTransferable::DeleteSelection()
854 {
855     if(!m_pWrtShell)
856         return;
857     // ask for type of selection before action-bracketing
858     const SelectionType nSelection = m_pWrtShell->GetSelectionType();
859     // cut rows or columns selected by enhanced table selection and wholly selected tables
860     bool bCutMode = ( SelectionType::TableCell & nSelection ) && ( (SelectionType::TableRow | SelectionType::TableCol) & nSelection ||
861         m_pWrtShell->HasWholeTabSelection() );
862 
863     m_pWrtShell->StartUndo( SwUndoId::START );
864     if( bCutMode )
865     {
866         if( !(SelectionType::TableCol & nSelection) )
867             m_pWrtShell->DeleteTable();
868         else
869         {
870             SfxDispatcher* pDispatch = m_pWrtShell->GetView().GetViewFrame().GetDispatcher();
871             pDispatch->Execute(FN_TABLE_DELETE_COL, SfxCallMode::SYNCHRON);
872         }
873     }
874     else
875     {
876         if( ( SelectionType::Text | SelectionType::Table ) & nSelection )
877             m_pWrtShell->IntelligentCut( nSelection );
878         m_pWrtShell->DelRight();
879     }
880     m_pWrtShell->EndUndo( SwUndoId::END );
881 }
882 
DeleteDDEMarks(SwDoc & rDest)883 static void DeleteDDEMarks(SwDoc & rDest)
884 {
885     IDocumentMarkAccess *const pMarkAccess = rDest.getIDocumentMarkAccess();
886     std::vector< ::sw::mark::IMark* > vDdeMarks;
887     // find all DDE-Bookmarks
888     for (IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin();
889         ppMark != pMarkAccess->getAllMarksEnd();
890         ++ppMark)
891     {
892         if (IDocumentMarkAccess::MarkType::DDE_BOOKMARK == IDocumentMarkAccess::GetType(**ppMark))
893         {
894             vDdeMarks.push_back(*ppMark);
895         }
896     }
897     // remove all DDE-Bookmarks, they are invalid inside the clipdoc!
898     for (const auto& rpMark : vDdeMarks)
899     {
900         pMarkAccess->deleteMark(rpMark);
901     }
902 }
903 
PrepareForCopyTextRange(SwPaM & rPaM)904 void SwTransferable::PrepareForCopyTextRange(SwPaM & rPaM)
905 {
906     std::optional<SwWait> oWait;
907     if (m_pWrtShell->ShouldWait())
908     {
909         oWait.emplace( *m_pWrtShell->GetView().GetDocShell(), true );
910     }
911 
912     m_pClpDocFac.reset(new SwDocFac);
913 
914     SwDoc& rDest(lcl_GetDoc(*m_pClpDocFac));
915     rDest.getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is
916     {
917         SwDoc const& rSrc(*m_pWrtShell->GetDoc());
918         assert(&rSrc == &rPaM.GetDoc());
919 
920         rDest.ReplaceCompatibilityOptions(rSrc);
921         rDest.ReplaceDefaults(rSrc);
922 
923         //It would probably make most sense here to only insert the styles used
924         //by the selection, e.g. apply SwDoc::IsUsed on styles ?
925         rDest.ReplaceStyles(rSrc, false);
926 
927         // relevant bits of rSrcWrtShell.Copy(rDest);
928         rDest.GetIDocumentUndoRedo().DoUndo(false); // always false!
929         rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::DeleteRedlines );
930 
931         SwNodeIndex const aIdx(rDest.GetNodes().GetEndOfContent(), -1);
932         SwContentNode *const pContentNode(aIdx.GetNode().GetContentNode());
933         SwPosition aPos(aIdx, pContentNode, pContentNode ? pContentNode->Len() : 0);
934 
935         rSrc.getIDocumentContentOperations().CopyRange(rPaM, aPos, SwCopyFlags::CheckPosInFly);
936 
937         rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE );
938 
939         rDest.GetMetaFieldManager().copyDocumentProperties(rSrc);
940     }
941 
942     DeleteDDEMarks(rDest);
943 
944     // a new one was created in core (OLE objects copied!)
945     m_aDocShellRef = rDest.GetTmpDocShell();
946     if (m_aDocShellRef.Is())
947         SwTransferable::InitOle( m_aDocShellRef );
948     rDest.SetTmpDocShell( nullptr );
949 
950     // let's add some formats
951     AddFormat( SotClipboardFormatId::EMBED_SOURCE );
952     AddFormat( SotClipboardFormatId::RTF );
953 #if HAVE_FEATURE_DESKTOP
954     AddFormat( SotClipboardFormatId::RICHTEXT );
955     AddFormat( SotClipboardFormatId::HTML );
956 #endif
957     AddFormat( SotClipboardFormatId::STRING );
958 }
959 
PrepareForCopy(bool bIsCut)960 int SwTransferable::PrepareForCopy( bool bIsCut )
961 {
962     int nRet = 1;
963     if(!m_pWrtShell)
964         return 0;
965 
966     if ( m_pWrtShell->GetTableInsertMode() != SwTable::SEARCH_NONE )
967         m_pWrtShell->SetTableInsertMode( SwTable::SEARCH_NONE );
968 
969     if ( m_pWrtShell->GetTableCopied() )
970         m_pWrtShell->SetTableCopied( false );
971 
972     OUString sGrfNm;
973     const SelectionType nSelection = m_pWrtShell->GetSelectionType();
974     if( nSelection == SelectionType::Graphic )
975     {
976         m_oClpGraphic.emplace();
977         if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
978             m_pOrigGraphic = &*m_oClpGraphic;
979         m_oClpBitmap.emplace();
980         if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
981             m_pOrigGraphic = &*m_oClpBitmap;
982 
983         m_pClpDocFac.reset(new SwDocFac);
984         SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
985         m_pWrtShell->Copy(rDoc);
986 
987 #if HAVE_FEATURE_DESKTOP
988         if (m_pOrigGraphic && !m_pOrigGraphic->GetBitmapEx().IsEmpty())
989           AddFormat( SotClipboardFormatId::SVXB );
990 #endif
991 
992         PrepareOLE( m_aObjDesc );
993         AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
994 
995         const Graphic* pGrf = m_pWrtShell->GetGraphic();
996         if( pGrf && pGrf->IsSupportedGraphic() )
997         {
998             AddFormat( SotClipboardFormatId::PNG );
999 #if HAVE_FEATURE_DESKTOP
1000             AddFormat( SotClipboardFormatId::GDIMETAFILE );
1001             AddFormat( SotClipboardFormatId::BITMAP );
1002 #endif
1003         }
1004         m_eBufferType = TransferBufferType::Graphic;
1005         m_pWrtShell->GetGrfNms( &sGrfNm, nullptr );
1006     }
1007     else if ( nSelection == SelectionType::Ole )
1008     {
1009         m_pClpDocFac.reset(new SwDocFac);
1010         SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
1011         m_aDocShellRef = new SwDocShell(rDoc, SfxObjectCreateMode::EMBEDDED);
1012         m_aDocShellRef->DoInitNew();
1013         m_pWrtShell->Copy(rDoc);
1014 
1015         AddFormat( SotClipboardFormatId::EMBED_SOURCE );
1016 
1017         // --> OD #i98753#
1018         // set size of embedded object at the object description structure
1019         m_aObjDesc.maSize = o3tl::convert(m_pWrtShell->GetObjSize(), o3tl::Length::twip, o3tl::Length::mm100);
1020 
1021         // <--
1022         PrepareOLE( m_aObjDesc );
1023 
1024 #if HAVE_FEATURE_DESKTOP
1025         AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
1026         AddFormat( SotClipboardFormatId::GDIMETAFILE );
1027 
1028         // Fetch the formats supported via embedtransferhelper as well
1029         sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
1030         uno::Reference < embed::XEmbeddedObject > xObj = FindOLEObj( nAspect );
1031         const Graphic* pOLEGraph = FindOLEReplacementGraphic();
1032         if( xObj.is() )
1033         {
1034             TransferableDataHelper aD( new SvEmbedTransferHelper( xObj, pOLEGraph, nAspect ) );
1035             if ( aD.GetTransferable().is() )
1036             {
1037                 DataFlavorExVector              aVector( aD.GetDataFlavorExVector() );
1038 
1039                 for( const auto& rItem : aVector )
1040                     AddFormat( rItem );
1041             }
1042         }
1043 #endif
1044         m_eBufferType = TransferBufferType::Ole;
1045     }
1046     // Is there anything to provide anyway?
1047     else if ( m_pWrtShell->IsSelection() || m_pWrtShell->IsFrameSelected() ||
1048               m_pWrtShell->IsObjSelected() )
1049     {
1050         std::optional<SwWait> oWait;
1051         if( m_pWrtShell->ShouldWait() )
1052             oWait.emplace( *m_pWrtShell->GetView().GetDocShell(), true );
1053 
1054         m_pClpDocFac.reset(new SwDocFac);
1055 
1056         // create additional cursor so that equal treatment of keyboard
1057         // and mouse selection is possible.
1058         // In AddMode with keyboard selection, the new cursor is not created
1059         // before the cursor is moved after end of selection.
1060         if( m_pWrtShell->IsAddMode() && m_pWrtShell->SwCursorShell::HasSelection() )
1061             m_pWrtShell->CreateCursor();
1062 
1063         SwDoc& rTmpDoc = lcl_GetDoc(*m_pClpDocFac);
1064 
1065         rTmpDoc.getIDocumentFieldsAccess().LockExpFields();     // Never update fields - leave text as is
1066         lclOverWriteDoc(*m_pWrtShell, rTmpDoc);
1067 
1068         DeleteDDEMarks(rTmpDoc);
1069 
1070         // a new one was created in CORE (OLE objects copied!)
1071         m_aDocShellRef = rTmpDoc.GetTmpDocShell();
1072         if( m_aDocShellRef.Is() )
1073             SwTransferable::InitOle( m_aDocShellRef );
1074         rTmpDoc.SetTmpDocShell( nullptr );
1075 
1076         if( m_pWrtShell->IsObjSelected() )
1077             m_eBufferType = TransferBufferType::Drawing;
1078         else
1079         {
1080             m_eBufferType = TransferBufferType::Document;
1081             if (m_pWrtShell->IntelligentCut(nSelection, false) != SwWrtShell::NO_WORD)
1082                 m_eBufferType = TransferBufferType::DocumentWord | m_eBufferType;
1083         }
1084 
1085         bool bDDELink = m_pWrtShell->IsSelection();
1086         if( nSelection & SelectionType::TableCell )
1087         {
1088             m_eBufferType = TransferBufferType::Table | m_eBufferType;
1089             bDDELink = m_pWrtShell->HasWholeTabSelection();
1090 
1091             m_pWrtShell->SetTableCopied(true);
1092 
1093             if ( bIsCut && (SelectionType::TableRow | SelectionType::TableCol) & nSelection )
1094                 m_pWrtShell->SetTableInsertMode( (SelectionType::TableRow & nSelection) ? SwTable::SEARCH_ROW : SwTable::SEARCH_COL );
1095         }
1096 
1097 #if HAVE_FEATURE_DESKTOP
1098         //When someone needs it, we 'OLE' him something
1099         AddFormat( SotClipboardFormatId::EMBED_SOURCE );
1100 #endif
1101 
1102         //put RTF ahead of  the OLE's Metafile to have less loss
1103         if( !m_pWrtShell->IsObjSelected() )
1104         {
1105             AddFormat( SotClipboardFormatId::RTF );
1106 #if HAVE_FEATURE_DESKTOP
1107             AddFormat( SotClipboardFormatId::RICHTEXT );
1108             AddFormat( SotClipboardFormatId::HTML );
1109 #endif
1110         }
1111         if( m_pWrtShell->IsSelection() )
1112             AddFormat( SotClipboardFormatId::STRING );
1113 
1114         if( nSelection & ( SelectionType::DrawObject | SelectionType::DbForm ))
1115         {
1116             AddFormat( SotClipboardFormatId::DRAWING );
1117             if ( nSelection & SelectionType::DrawObject )
1118             {
1119 #if HAVE_FEATURE_DESKTOP
1120                 AddFormat( SotClipboardFormatId::GDIMETAFILE );
1121                 AddFormat( SotClipboardFormatId::BITMAP );
1122 #endif
1123                 AddFormat( SotClipboardFormatId::PNG );
1124             }
1125             m_eBufferType = static_cast<TransferBufferType>( TransferBufferType::Graphic | m_eBufferType );
1126 
1127             m_oClpGraphic.emplace();
1128             if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
1129                 m_pOrigGraphic = &*m_oClpGraphic;
1130             m_oClpBitmap.emplace();
1131             if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
1132                 m_pOrigGraphic = &*m_oClpBitmap;
1133 
1134             // is it a URL-Button ?
1135             OUString sURL;
1136             OUString sDesc;
1137             if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
1138             {
1139                 AddFormat( SotClipboardFormatId::STRING );
1140 #if HAVE_FEATURE_DESKTOP
1141                 AddFormat( SotClipboardFormatId::SOLK );
1142                 AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
1143                 AddFormat( SotClipboardFormatId::FILECONTENT );
1144                 AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
1145 #endif
1146                 AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
1147                 m_eBufferType = TransferBufferType::InetField | m_eBufferType;
1148                 nRet = 1;
1149             }
1150         }
1151 
1152         // at Cut, DDE-Link doesn't make sense!!
1153         SwDocShell* pDShell;
1154         if( !bIsCut && bDDELink &&
1155             nullptr != ( pDShell = m_pWrtShell->GetDoc()->GetDocShell()) &&
1156             SfxObjectCreateMode::STANDARD == pDShell->GetCreateMode() )
1157         {
1158 #if HAVE_FEATURE_DESKTOP
1159             AddFormat( SotClipboardFormatId::LINK );
1160 #endif
1161             m_xDdeLink = new SwTransferDdeLink( *this, *m_pWrtShell );
1162         }
1163 
1164         //ObjectDescriptor was already filly from the old DocShell.
1165         //Now adjust it. Thus in GetData the first query can still
1166         //be answered with delayed rendering.
1167         m_aObjDesc.maSize = constOleSize100mm;
1168 
1169         PrepareOLE( m_aObjDesc );
1170 #if HAVE_FEATURE_DESKTOP
1171         AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
1172 #endif
1173     }
1174     else
1175         nRet = 0;
1176 
1177     if( m_pWrtShell->IsFrameSelected() )
1178     {
1179         SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
1180         m_pWrtShell->GetFlyFrameAttr( aSet );
1181         const SwFormatURL& rURL = aSet.Get( RES_URL );
1182         if( rURL.GetMap() )
1183         {
1184             m_pImageMap.reset( new ImageMap( *rURL.GetMap() ) );
1185             AddFormat( SotClipboardFormatId::SVIM );
1186         }
1187         else if( !rURL.GetURL().isEmpty() )
1188         {
1189             m_pTargetURL.reset(new INetImage( sGrfNm, rURL.GetURL(),
1190                                         rURL.GetTargetFrameName() ));
1191             AddFormat( SotClipboardFormatId::INET_IMAGE );
1192         }
1193     }
1194 
1195     return nRet;
1196 }
1197 
Copy(bool bIsCut)1198 int SwTransferable::Copy( bool bIsCut )
1199 {
1200     if (m_pWrtShell->GetView().GetObjectShell()->isContentExtractionLocked())
1201         return 0;
1202 
1203     int nRet = PrepareForCopy( bIsCut );
1204     if ( nRet )
1205     {
1206         CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
1207     }
1208 
1209     if( !bIsCut ){
1210         collectUIInformation(u"COPY"_ustr, u"parameter"_ustr);
1211     }
1212 
1213     return nRet;
1214 }
1215 
CalculateAndCopy()1216 void SwTransferable::CalculateAndCopy()
1217 {
1218     if(!m_pWrtShell)
1219         return;
1220     SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true );
1221 
1222     OUString aStr( m_pWrtShell->Calculate() );
1223 
1224     m_pClpDocFac.reset(new SwDocFac);
1225     SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
1226     m_pWrtShell->Copy(rDoc, &aStr);
1227     m_eBufferType = TransferBufferType::Document;
1228     AddFormat( SotClipboardFormatId::STRING );
1229 
1230     CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
1231 }
1232 
CopyGlossary(SwTextBlocks & rGlossary,const OUString & rStr)1233 bool SwTransferable::CopyGlossary( SwTextBlocks& rGlossary, const OUString& rStr )
1234 {
1235     if(!m_pWrtShell)
1236         return false;
1237     SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true );
1238 
1239     m_pClpDocFac.reset(new SwDocFac);
1240     SwDoc& rCDoc = lcl_GetDoc(*m_pClpDocFac);
1241 
1242     SwNodes& rNds = rCDoc.GetNodes();
1243     SwNodeIndex aNodeIdx( *rNds.GetEndOfContent().StartOfSectionNode() );
1244     SwContentNode* pCNd = SwNodes::GoNext(&aNodeIdx); // go to 1st ContentNode
1245     SwPaM aPam( *pCNd );
1246 
1247     rCDoc.getIDocumentFieldsAccess().LockExpFields();   // never update fields - leave text as it is
1248 
1249     rCDoc.InsertGlossary( rGlossary, rStr, aPam );
1250 
1251     // a new one was created in CORE (OLE-Objects copied!)
1252     m_aDocShellRef = rCDoc.GetTmpDocShell();
1253     if( m_aDocShellRef.Is() )
1254         SwTransferable::InitOle( m_aDocShellRef );
1255     rCDoc.SetTmpDocShell( nullptr );
1256 
1257     m_eBufferType = TransferBufferType::Document;
1258 
1259     //When someone needs it, we 'OLE' her something.
1260     AddFormat( SotClipboardFormatId::EMBED_SOURCE );
1261     AddFormat( SotClipboardFormatId::RTF );
1262     AddFormat( SotClipboardFormatId::RICHTEXT );
1263     AddFormat( SotClipboardFormatId::HTML );
1264     AddFormat( SotClipboardFormatId::STRING );
1265 
1266     //ObjectDescriptor was already filled from the old DocShell.
1267     //Now adjust it. Thus in GetData the first query can still
1268     //be answered with delayed rendering.
1269     m_aObjDesc.maSize = constOleSize100mm;
1270 
1271     PrepareOLE( m_aObjDesc );
1272     AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
1273 
1274     CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
1275 
1276     return true;
1277 }
1278 
lcl_getTransferPointer(uno::Reference<XTransferable> & xRef)1279 static uno::Reference < XTransferable > * lcl_getTransferPointer ( uno::Reference < XTransferable > &xRef )
1280 {
1281     return &xRef;
1282 }
1283 
SwPasteContext(SwWrtShell & rWrtShell)1284 SwPasteContext::SwPasteContext(SwWrtShell& rWrtShell)
1285     : m_rWrtShell(rWrtShell)
1286 {
1287     remember();
1288 }
1289 
remember()1290 void SwPasteContext::remember()
1291 {
1292     if (m_rWrtShell.GetPasteListeners().getLength() == 0)
1293         return;
1294 
1295     SwPaM* pCursor = m_rWrtShell.GetCursor();
1296     if (!pCursor)
1297         return;
1298 
1299     // Set point to the previous node, so it is not moved.
1300     const SwNode& rNode = pCursor->GetPoint()->GetNode();
1301     m_oPaM.emplace(rNode, rNode, SwNodeOffset(0), SwNodeOffset(-1));
1302     m_nStartContent = pCursor->GetPoint()->GetContentIndex();
1303 }
1304 
forget()1305 void SwPasteContext::forget() { m_oPaM.reset(); }
1306 
~SwPasteContext()1307 SwPasteContext::~SwPasteContext()
1308 {
1309     try
1310     {
1311         if (m_rWrtShell.GetPasteListeners().getLength() == 0)
1312             return;
1313 
1314         beans::PropertyValue aPropertyValue;
1315 
1316         switch (m_rWrtShell.GetView().GetShellMode())
1317         {
1318             case ShellMode::Graphic:
1319             {
1320                 SwFrameFormat* pFormat = m_rWrtShell.GetFlyFrameFormat();
1321                 if (!pFormat)
1322                     return;
1323 
1324                 aPropertyValue.Name = "TextGraphicObject";
1325                 aPropertyValue.Value
1326                     <<= uno::Reference<text::XTextContent>(SwXTextGraphicObject::CreateXTextGraphicObject(*pFormat->GetDoc(), pFormat));
1327                 break;
1328             }
1329 
1330             default:
1331             {
1332                 if (!m_oPaM)
1333                     return;
1334 
1335                 SwPaM* pCursor = m_rWrtShell.GetCursor();
1336                 if (!pCursor)
1337                     return;
1338 
1339                 if (!pCursor->GetPoint()->GetNode().IsTextNode())
1340                     // Non-text was pasted.
1341                     return;
1342 
1343                 // Update mark after paste.
1344                 *m_oPaM->GetMark() = *pCursor->GetPoint();
1345 
1346                 // Restore point.
1347                 m_oPaM->GetPoint()->Adjust(SwNodeOffset(1));
1348                 SwNode& rNode = m_oPaM->GetPointNode();
1349                 if (!rNode.IsTextNode())
1350                     // Starting point is no longer text.
1351                     return;
1352 
1353                 m_oPaM->GetPoint()->SetContent(m_nStartContent);
1354 
1355                 aPropertyValue.Name = "TextRange";
1356                 const rtl::Reference<SwXTextRange> xTextRange = SwXTextRange::CreateXTextRange(
1357                     m_oPaM->GetDoc(), *m_oPaM->GetPoint(), m_oPaM->GetMark());
1358                 aPropertyValue.Value <<= uno::Reference<text::XTextRange>(xTextRange);
1359                 break;
1360             }
1361         }
1362 
1363         if (aPropertyValue.Name.isEmpty())
1364             return;
1365 
1366         // Invoke the listeners.
1367         uno::Sequence<beans::PropertyValue> aEvent{ aPropertyValue };
1368         m_rWrtShell.GetPasteListeners().notifyEach( &css::text::XPasteListener::notifyPasteEvent, aEvent );
1369     }
1370     catch (const uno::Exception& rException)
1371     {
1372         SAL_WARN("sw",
1373                  "SwPasteContext::~SwPasteContext: uncaught exception: " << rException.Message);
1374     }
1375 }
1376 
IsPaste(const SwWrtShell & rSh,const TransferableDataHelper & rData)1377 bool SwTransferable::IsPaste( const SwWrtShell& rSh,
1378                               const TransferableDataHelper& rData )
1379 {
1380     // Check the common case first: We can always paste our own data!
1381     // If _only_ the internal format can be pasted, this check will
1382     // yield 'true', while the one below would give a (wrong) result 'false'.
1383 
1384     bool bIsPaste = ( GetSwTransferable( rData ) != nullptr );
1385 
1386     // if it's not our own data, we need to have a closer look:
1387     if( ! bIsPaste )
1388     {
1389         // determine the proper paste action, and return true if we find one
1390         uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
1391 
1392         SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
1393         sal_uInt16 nSourceOptions =
1394                     (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
1395                        SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
1396                        SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
1397                        SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
1398                                     ? EXCHG_IN_ACTION_COPY
1399                      : EXCHG_IN_ACTION_MOVE);
1400 
1401         SotClipboardFormatId nFormat;          // output param for GetExchangeAction
1402         sal_uInt8 nEventAction;    // output param for GetExchangeAction
1403         sal_uInt8 nAction = SotExchange::GetExchangeAction(
1404                                 rData.GetDataFlavorExVector(),
1405                                 nDestination,
1406                                 nSourceOptions,             /* ?? */
1407                                 EXCHG_IN_ACTION_DEFAULT,    /* ?? */
1408                                 nFormat, nEventAction, SotClipboardFormatId::NONE,
1409                                 lcl_getTransferPointer ( xTransferable ) );
1410 
1411         // if we find a suitable action, we can paste!
1412         bIsPaste = (EXCHG_INOUT_ACTION_NONE != nAction);
1413     }
1414 
1415     return bIsPaste;
1416 }
1417 
SelectPasteFormat(TransferableDataHelper & rData,sal_uInt8 & nAction,SotClipboardFormatId & nFormat)1418 void SwTransferable::SelectPasteFormat(TransferableDataHelper& rData, sal_uInt8& nAction,
1419                                        SotClipboardFormatId& nFormat)
1420 {
1421     if (nFormat != SotClipboardFormatId::RICHTEXT)
1422     {
1423         return;
1424     }
1425 
1426     if (!rData.HasFormat(SotClipboardFormatId::EMBED_SOURCE))
1427     {
1428         return;
1429     }
1430 
1431     if (!rData.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
1432     {
1433         return;
1434     }
1435 
1436     TransferableObjectDescriptor aObjDesc;
1437     if (!rData.GetTransferableObjectDescriptor(SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc))
1438     {
1439         return;
1440     }
1441 
1442     if (aObjDesc.maClassName != SvGlobalName(SO3_SW_CLASSID))
1443     {
1444         return;
1445     }
1446 
1447     // At this point we know that we paste from Writer to Writer and the clipboard has the content
1448     // in both RTF and ODF formats. Prefer ODF in this case.
1449     nAction = EXCHG_OUT_ACTION_INSERT_OLE;
1450     nFormat = SotClipboardFormatId::EMBED_SOURCE;
1451 }
1452 
1453 // get HTML indentation level by counting tabulator characters before the index
1454 // (also index value -1 returns with 0)
lcl_getLevel(OUString & sText,sal_Int32 nIdx)1455 static sal_Int32 lcl_getLevel(OUString& sText, sal_Int32 nIdx)
1456 {
1457     sal_Int32 nRet = 0;
1458     while ( nIdx-- > 0 && sText[nIdx] == '\t' )
1459     {
1460         nRet++;
1461     }
1462     return nRet;
1463 }
1464 
Paste(SwWrtShell & rSh,TransferableDataHelper & rData,RndStdIds nAnchorType,bool bIgnoreComments,PasteTableType ePasteTable)1465 bool SwTransferable::Paste(SwWrtShell& rSh, TransferableDataHelper& rData, RndStdIds nAnchorType, bool bIgnoreComments, PasteTableType ePasteTable)
1466 {
1467     SwPasteContext aPasteContext(rSh);
1468 
1469     sal_uInt8 nAction=0;
1470     SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
1471     SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
1472     SotExchangeActionFlags nActionFlags = SotExchangeActionFlags::NONE;
1473     bool bSingleCellTable = false;
1474 
1475     if( GetSwTransferable( rData ) )
1476     {
1477         nAction = EXCHG_OUT_ACTION_INSERT_PRIVATE;
1478     }
1479     else
1480     {
1481         sal_uInt16 nSourceOptions =
1482                     (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
1483                     SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
1484                     SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
1485                     SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
1486                                     ? EXCHG_IN_ACTION_COPY
1487                                     : EXCHG_IN_ACTION_MOVE);
1488         uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
1489         sal_uInt8 nEventAction;
1490         nAction = SotExchange::GetExchangeAction(
1491                                     rData.GetDataFlavorExVector(),
1492                                     nDestination,
1493                                     nSourceOptions,             /* ?? */
1494                                     EXCHG_IN_ACTION_DEFAULT,    /* ?? */
1495                                     nFormat, nEventAction, SotClipboardFormatId::NONE,
1496                                     lcl_getTransferPointer ( xTransferable ),
1497                                     &nActionFlags );
1498     }
1499 
1500     // when HTML is just an image don't generate new section
1501     if (rData.HasFormat(SotClipboardFormatId::HTML_SIMPLE) && rData.HasFormat(SotClipboardFormatId::HTML_NO_COMMENT)
1502         && rData.HasFormat(SotClipboardFormatId::BITMAP) && nFormat == SotClipboardFormatId::FILE_LIST)
1503         nFormat = SotClipboardFormatId::BITMAP;
1504 
1505     // tdf#37223 avoid non-native insertion of Calc worksheets in the following cases:
1506     // content of 1-cell worksheets are inserted as simple text using RTF format,
1507     // bigger worksheets within native (Writer) table cells are inserted as native tables,
1508     // ie. cell by cell instead of embedding the worksheet in a single cell of the Writer table
1509     if ( EXCHG_IN_ACTION_COPY == nAction && ( rData.HasFormat( SotClipboardFormatId::SYLK ) ||
1510                   rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) )
1511     {
1512         // is it a 1-cell worksheet?
1513         OUString aExpand;
1514         if( rData.GetString( SotClipboardFormatId::STRING, aExpand ))
1515         {
1516             const sal_Int32 nNewlines{comphelper::string::getTokenCount(aExpand, '\n')};
1517             const sal_Int32 nRows = nNewlines ? nNewlines-1 : 0;
1518             if ( nRows == 1 )
1519             {
1520                 const sal_Int32 nCols = comphelper::string::getTokenCount(o3tl::getToken(aExpand, 0, '\n'), '\t');
1521                 if (nCols == 1)
1522                     bSingleCellTable = true;
1523             }
1524         }
1525 
1526         // convert the worksheet to a temporary native table using HTML format, and copy that into the original native table
1527         if (!bSingleCellTable && rData.HasFormat( SotClipboardFormatId::HTML ) &&
1528                         SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr && rSh.DoesUndo())
1529         {
1530             SfxDispatcher* pDispatch = rSh.GetView().GetViewFrame().GetDispatcher();
1531             sal_uInt32 nLevel = 0;
1532 
1533             // within Writer table cells, inserting worksheets using HTML format results only plain text, not a native table,
1534             // so remove all outer nested tables temporary to get a working insertion point
1535             // (RTF format has no such problem, but that inserts the hidden rows of the original Calc worksheet, too)
1536 
1537             // For this, switch off change tracking temporarily, if needed
1538             RedlineFlags eOld = rSh.GetDoc()->getIDocumentRedlineAccess().GetRedlineFlags();
1539             if ( eOld & RedlineFlags::On )
1540                 rSh.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags( eOld & ~RedlineFlags::On );
1541 
1542             OUString sPreviousTableName;
1543             do
1544             {
1545                 // tdf#152245 add a limit to the loop, if it's not possible to delete the table
1546                 const SwTableNode* pNode = rSh.GetCursor()->GetPointNode().FindTableNode();
1547                 const OUString sTableName = pNode->GetTable().GetFrameFormat()->GetName();
1548                 if ( sTableName == sPreviousTableName )
1549                     break;
1550                 sPreviousTableName = sTableName;
1551                 // insert a random character to redo the place of the insertion at the end
1552                 pDispatch->Execute(FN_INSERT_NNBSP, SfxCallMode::SYNCHRON);
1553                 pDispatch->Execute(FN_TABLE_DELETE_TABLE, SfxCallMode::SYNCHRON);
1554                 nLevel++;
1555             } while (SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr);
1556 
1557             // restore change tracking settings
1558             if ( eOld & RedlineFlags::On )
1559                 rSh.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags( eOld );
1560 
1561             if ( SwTransferable::PasteData( rData, rSh, EXCHG_OUT_ACTION_INSERT_STRING, nActionFlags, SotClipboardFormatId::HTML,
1562                                         nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, ePasteTable) )
1563             {
1564                 bool bFoundTemporaryTable = false;
1565                 pDispatch->Execute(FN_LINE_UP, SfxCallMode::SYNCHRON);
1566                 if (SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr)
1567                 {
1568                     bFoundTemporaryTable = true;
1569                     pDispatch->Execute(FN_TABLE_SELECT_ALL, SfxCallMode::SYNCHRON);
1570                     pDispatch->Execute(SID_COPY, SfxCallMode::SYNCHRON);
1571                 }
1572                 for(sal_uInt32 a = 0; a < 1 + (nLevel * 2); a++)
1573                     pDispatch->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
1574                 // clipboard content hasn't changed (limit potential infinite
1575                 // recursion with the same non-native table, as was in tdf#138688)
1576                 if (!bFoundTemporaryTable)
1577                     return false;
1578                 if (ePasteTable == PasteTableType::PASTE_TABLE)
1579                     pDispatch->Execute(FN_PASTE_NESTED_TABLE, SfxCallMode::SYNCHRON);
1580                 else if (ePasteTable == PasteTableType::PASTE_ROW)
1581                     pDispatch->Execute(FN_TABLE_PASTE_ROW_BEFORE, SfxCallMode::SYNCHRON);
1582                 else if (ePasteTable == PasteTableType::PASTE_COLUMN)
1583                     pDispatch->Execute(FN_TABLE_PASTE_COL_BEFORE, SfxCallMode::SYNCHRON);
1584                 else
1585                     pDispatch->Execute(SID_PASTE, SfxCallMode::SYNCHRON);
1586                 return true;
1587             } else {
1588                 for(sal_uInt32 a = 0; a < (nLevel * 2); a++)
1589                     pDispatch->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
1590             }
1591         }
1592     }
1593     // insert clipboard content as new table rows/columns before the actual row/column instead of overwriting it
1594     else if ( (rSh.GetTableInsertMode() != SwTable::SEARCH_NONE || ePasteTable == PasteTableType::PASTE_ROW || ePasteTable == PasteTableType::PASTE_COLUMN) &&
1595         rData.HasFormat( SotClipboardFormatId::HTML ) &&
1596         SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr )
1597     {
1598         OUString aExpand;
1599         sal_Int32 nIdx;
1600         bool bRowMode = rSh.GetTableInsertMode() == SwTable::SEARCH_ROW || ePasteTable == PasteTableType::PASTE_ROW;
1601         if( rData.GetString( SotClipboardFormatId::HTML, aExpand ) && (nIdx = aExpand.indexOf("<table")) > -1 )
1602         {
1603             // calculate table row/column count by analysing indentation of the HTML table extract
1604 
1605             // calculate indentation level of <table>, which is the base of the next calculations
1606             // (tdf#148791 table alignment can enlarge it using first level <center>, <div> or <dl>)
1607             sal_Int32 nTableLevel = lcl_getLevel(aExpand, nIdx);
1608             // table rows repeated heading use extra indentation, too:
1609             // <thead> is always used here, and the first table with <thead> is not nested,
1610             // if its indentation level is greater only by 1, than indentation level of the table
1611             bool bShifted = lcl_getLevel(aExpand, aExpand.indexOf("<thead")) == nTableLevel + 1;
1612             // calculate count of selected rows or columns
1613             sal_Int32 nSelectedRowsOrCols = 0;
1614             const OUString sSearchRowOrCol = bRowMode ? u"</tr>"_ustr : u"<col "_ustr;
1615             while((nIdx = aExpand.indexOf(sSearchRowOrCol, nIdx)) > -1)
1616             {
1617                 // skip rows/columns of nested tables, based on HTML indentation
1618                 if ( lcl_getLevel(aExpand, nIdx) == nTableLevel + (bShifted ? 2 : 1) &&
1619                     // skip also strange hidden empty rows <tr></tr>
1620                     !aExpand.match("<tr></tr>", nIdx - 4) )
1621                 {
1622                     ++nSelectedRowsOrCols;
1623                 }
1624                 ++nIdx;
1625             }
1626             // are we at the beginning of the cell?
1627             bool bStartTableBoxNode =
1628                 // first paragraph of the cell?
1629                 rSh.GetCursor()->GetPointNode().GetIndex() == rSh.GetCursor()->GetPointNode().FindTableBoxStartNode()->GetIndex()+1 &&
1630                 // beginning of the paragraph?
1631                 !rSh.GetCursor()->GetPoint()->GetContentIndex();
1632             SfxDispatcher* pDispatch = rSh.GetView().GetViewFrame().GetDispatcher();
1633 
1634             // go start of the cell
1635             if (!bStartTableBoxNode)
1636                 pDispatch->Execute(FN_START_OF_DOCUMENT, SfxCallMode::SYNCHRON);
1637 
1638             // store cursor position in row mode
1639             ::sw::mark::IMark* pMark = (!bRowMode || nSelectedRowsOrCols == 0) ? nullptr : rSh.SetBookmark(
1640                                     vcl::KeyCode(),
1641                                     OUString(),
1642                                     IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
1643 
1644             // add a new empty row/column before the actual table row/column and go there
1645             const sal_uInt16 nDispatchSlot = bRowMode ? FN_TABLE_INSERT_ROW_BEFORE : FN_TABLE_INSERT_COL_BEFORE;
1646             pDispatch->Execute(nDispatchSlot, SfxCallMode::SYNCHRON);
1647             pDispatch->Execute(bRowMode ? FN_LINE_UP : FN_CHAR_LEFT, SfxCallMode::SYNCHRON);
1648 
1649             // add the other new empty rows/columns after the actual table row/column
1650             if ( nSelectedRowsOrCols > 1 )
1651             {
1652                 SfxInt16Item aCountItem( nDispatchSlot, nSelectedRowsOrCols-1 );
1653                 SfxBoolItem aAfter( FN_PARAM_INSERT_AFTER, true );
1654                 pDispatch->ExecuteList(nDispatchSlot,
1655                     SfxCallMode::SYNCHRON|SfxCallMode::RECORD,
1656                     { &aCountItem, &aAfter });
1657             }
1658 
1659             // paste rows
1660             bool bResult = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
1661                                         nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext );
1662 
1663             // restore cursor position
1664             if (pMark != nullptr)
1665             {
1666                 rSh.GotoMark( pMark );
1667                 rSh.getIDocumentMarkAccess()->deleteMark( pMark );
1668             }
1669 
1670             return bResult;
1671         }
1672     }
1673 
1674     // special case for tables from draw application or 1-cell tables
1675     if( EXCHG_OUT_ACTION_INSERT_DRAWOBJ == nAction || bSingleCellTable )
1676     {
1677         if( rData.HasFormat( SotClipboardFormatId::RTF ) )
1678         {
1679             nAction = EXCHG_OUT_ACTION_INSERT_STRING;
1680             nFormat = SotClipboardFormatId::RTF;
1681         }
1682         else if( rData.HasFormat( SotClipboardFormatId::RICHTEXT ) )
1683         {
1684             nAction = EXCHG_OUT_ACTION_INSERT_STRING;
1685             nFormat = SotClipboardFormatId::RICHTEXT;
1686         }
1687     }
1688 
1689     // Tweak the format if necessary: the source application can be considered in this context,
1690     // while not in sot/ code.
1691     SwTransferable::SelectPasteFormat(rData, nAction, nFormat);
1692 
1693     collectUIInformation(u"PASTE"_ustr, u"parameter"_ustr);
1694 
1695     return EXCHG_INOUT_ACTION_NONE != nAction &&
1696             SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
1697                                         nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, ePasteTable);
1698 }
1699 
PasteData(const TransferableDataHelper & rData,SwWrtShell & rSh,sal_uInt8 nAction,SotExchangeActionFlags nActionFlags,SotClipboardFormatId nFormat,SotExchangeDest nDestination,bool bIsPasteFormat,bool bIsDefault,const Point * pPt,sal_Int8 nDropAction,bool bPasteSelection,RndStdIds nAnchorType,bool bIgnoreComments,SwPasteContext * pContext,PasteTableType ePasteTable)1700 bool SwTransferable::PasteData( const TransferableDataHelper& rData,
1701                             SwWrtShell& rSh, sal_uInt8 nAction, SotExchangeActionFlags nActionFlags,
1702                             SotClipboardFormatId nFormat,
1703                             SotExchangeDest nDestination, bool bIsPasteFormat,
1704                             [[maybe_unused]] bool bIsDefault,
1705                             const Point* pPt, sal_Int8 nDropAction,
1706                             bool bPasteSelection, RndStdIds nAnchorType,
1707                             bool bIgnoreComments,
1708                             SwPasteContext* pContext,
1709                             PasteTableType ePasteTable )
1710 {
1711     SwWait aWait( *rSh.GetView().GetDocShell(), false );
1712     std::unique_ptr<SwTrnsfrActionAndUndo, o3tl::default_delete<SwTrnsfrActionAndUndo>> pAction;
1713     SwModule* pMod = SW_MOD();
1714 
1715     bool bRet = false;
1716     bool bCallAutoCaption = false;
1717 
1718     if( pPt )
1719     {
1720         // external Drop
1721         if ((bPasteSelection ? !pMod->m_pXSelection : !pMod->m_pDragDrop) &&
1722                 // The following condition is used for tdf#156111 to prevent a selection from being
1723                 // cleared by the default case of the nDestination switch.
1724                 !(rSh.GetCursorCnt() == 1 && rSh.TestCurrPam(*pPt) &&
1725                 nDestination == SotExchangeDest::SWDOC_FREE_AREA &&
1726                 nFormat == SotClipboardFormatId::SONLK))
1727         {
1728             switch( nDestination )
1729             {
1730             case SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP:
1731             case SotExchangeDest::DOC_LNKD_GRAPHOBJ:
1732             case SotExchangeDest::DOC_GRAPH_W_IMAP:
1733             case SotExchangeDest::DOC_GRAPHOBJ:
1734             case SotExchangeDest::DOC_OLEOBJ:
1735             case SotExchangeDest::DOC_DRAWOBJ:
1736             case SotExchangeDest::DOC_URLBUTTON:
1737             case SotExchangeDest::DOC_GROUPOBJ:
1738                 // select frames/objects
1739                 SwTransferable::SetSelInShell( rSh, true, pPt );
1740                 break;
1741 
1742             default:
1743                 bool bLockView = rSh.IsViewLocked();
1744                 if (nFormat == SotClipboardFormatId::SONLK)
1745                     rSh.LockView(true); // prevent view jump
1746                 SwTransferable::SetSelInShell( rSh, false, pPt );
1747                 rSh.LockView(bLockView);
1748                 break;
1749             }
1750         }
1751     }
1752     else if( ( !GetSwTransferable( rData ) || bIsPasteFormat ) &&
1753             !rSh.IsTableMode() && rSh.HasSelection() )
1754     {
1755         // then delete the selections
1756 
1757         //don't delete selected content
1758         // - at table-selection
1759         // - at ReRead of a graphic/DDEData
1760         // - at D&D, for the right selection was taken care of
1761         //      in Drop-Handler
1762         bool bDelSel = false;
1763         switch( nDestination )
1764         {
1765         case SotExchangeDest::DOC_TEXTFRAME:
1766         case SotExchangeDest::SWDOC_FREE_AREA:
1767         case SotExchangeDest::DOC_TEXTFRAME_WEB:
1768         case SotExchangeDest::SWDOC_FREE_AREA_WEB:
1769             bDelSel = true;
1770             break;
1771         default:
1772             break;
1773         }
1774 
1775         if( bDelSel )
1776             // #i34830#
1777             pAction.reset(new SwTrnsfrActionAndUndo(&rSh, true, pContext));
1778     }
1779 
1780     SwTransferable *pTrans=nullptr, *pTunneledTrans=GetSwTransferable( rData );
1781 
1782     // check for private drop
1783     bool bPrivateDrop(pPt);
1784     if (bPrivateDrop)
1785     {
1786         if (bPasteSelection)
1787             pTrans = pMod->m_pXSelection;
1788         else
1789             pTrans = pMod->m_pDragDrop;
1790         bPrivateDrop = nullptr != pTrans;
1791     }
1792     bool bNeedToSelectBeforePaste(false);
1793 
1794     if(bPrivateDrop && DND_ACTION_LINK == nDropAction)
1795     {
1796         // internal drop on object, suppress bPrivateDrop to change internal fill
1797         bPrivateDrop = false;
1798         bNeedToSelectBeforePaste = true;
1799     }
1800 
1801     if(bPrivateDrop && pPt && DND_ACTION_MOVE == nDropAction)
1802     {
1803         // check if dragged over a useful target. If yes, use as content exchange
1804         // drop as if from external
1805         const SwFrameFormat* pSwFrameFormat = rSh.GetFormatFromObj(*pPt);
1806 
1807         if(dynamic_cast< const SwDrawFrameFormat* >(pSwFrameFormat))
1808         {
1809             bPrivateDrop = false;
1810             bNeedToSelectBeforePaste = true;
1811         }
1812     }
1813 
1814     if(bPrivateDrop)
1815     {
1816         // then internal Drag & Drop or XSelection
1817         bRet = pTrans->PrivateDrop( rSh, *pPt, DND_ACTION_MOVE == nDropAction,
1818                                     bPasteSelection );
1819     }
1820     else if( !pPt && pTunneledTrans &&
1821             EXCHG_OUT_ACTION_INSERT_PRIVATE == nAction )
1822     {
1823         // then internal paste
1824         bRet = pTunneledTrans->PrivatePaste(rSh, pContext, ePasteTable);
1825     }
1826     else if( EXCHG_INOUT_ACTION_NONE != nAction )
1827     {
1828         if( !pAction )
1829         {
1830             pAction.reset(new SwTrnsfrActionAndUndo( &rSh ));
1831         }
1832 
1833         // in Drag&Drop MessageBoxes must not be showed
1834         bool bMsg = nullptr == pPt;
1835 
1836         // delete selections
1837 
1838         switch( nAction )
1839         {
1840         case EXCHG_OUT_ACTION_INSERT_PRIVATE:
1841             OSL_ENSURE( pPt, "EXCHG_OUT_ACTION_INSERT_PRIVATE: what should happen here?" );
1842             break;
1843 
1844         case EXCHG_OUT_ACTION_MOVE_PRIVATE:
1845             OSL_ENSURE( pPt, "EXCHG_OUT_ACTION_MOVE_PRIVATE: what should happen here?" );
1846             break;
1847 
1848         case EXCHG_IN_ACTION_MOVE:
1849         case EXCHG_IN_ACTION_COPY:
1850         case EXCHG_IN_ACTION_LINK:
1851         case EXCHG_OUT_ACTION_INSERT_HTML:
1852         case EXCHG_OUT_ACTION_INSERT_STRING:
1853         case EXCHG_OUT_ACTION_INSERT_IMAGEMAP:
1854         case EXCHG_OUT_ACTION_REPLACE_IMAGEMAP:
1855 
1856             // then we have to use the format
1857             switch( nFormat )
1858             {
1859             case SotClipboardFormatId::DRAWING:
1860                 bRet = SwTransferable::PasteSdrFormat( rData, rSh,
1861                                                 SwPasteSdr::Insert, pPt,
1862                                                 nActionFlags, bNeedToSelectBeforePaste);
1863                 break;
1864 
1865             case SotClipboardFormatId::HTML:
1866             case SotClipboardFormatId::HTML_SIMPLE:
1867             case SotClipboardFormatId::HTML_NO_COMMENT:
1868             case SotClipboardFormatId::RTF:
1869             case SotClipboardFormatId::RICHTEXT:
1870             case SotClipboardFormatId::STRING:
1871                 bRet = SwTransferable::PasteFileContent( rData, rSh,
1872                                                             nFormat, bMsg, bIgnoreComments );
1873                 break;
1874 
1875             case SotClipboardFormatId::NETSCAPE_BOOKMARK:
1876                 {
1877                     INetBookmark aBkmk;
1878                     if( rData.GetINetBookmark( nFormat, aBkmk ) )
1879                     {
1880                         SwFormatINetFormat aFormat( aBkmk.GetURL(), OUString() );
1881                         rSh.InsertURL( aFormat, aBkmk.GetDescription() );
1882                         bRet = true;
1883                     }
1884                 }
1885                 break;
1886 
1887             case SotClipboardFormatId::SD_OLE:
1888                 bRet = SwTransferable::PasteOLE( rData, rSh, nFormat,
1889                                                     nActionFlags, bMsg );
1890                 break;
1891 
1892             case SotClipboardFormatId::SVIM:
1893                 bRet = SwTransferable::PasteImageMap( rData, rSh );
1894                 break;
1895 
1896             case SotClipboardFormatId::SVXB:
1897             case SotClipboardFormatId::BITMAP:
1898             case SotClipboardFormatId::PNG:
1899             case SotClipboardFormatId::GDIMETAFILE:
1900                 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
1901                                                 SwPasteSdr::Insert,pPt,
1902                                                 nActionFlags, nDropAction, bNeedToSelectBeforePaste);
1903                 break;
1904 
1905             case SotClipboardFormatId::XFORMS:
1906             case SotClipboardFormatId::SBA_FIELDDATAEXCHANGE:
1907             case SotClipboardFormatId::SBA_DATAEXCHANGE:
1908             case SotClipboardFormatId::SBA_CTRLDATAEXCHANGE:
1909                 bRet = SwTransferable::PasteDBData( rData, rSh, nFormat,
1910                                             EXCHG_IN_ACTION_LINK == nAction,
1911                                             pPt, bMsg );
1912                 break;
1913 
1914             case SotClipboardFormatId::SIMPLE_FILE:
1915                 bRet = SwTransferable::PasteFileName( rData, rSh, nFormat,
1916                                 ( EXCHG_IN_ACTION_MOVE == nAction
1917                                     ? SwPasteSdr::Replace
1918                                     : EXCHG_IN_ACTION_LINK == nAction
1919                                         ? SwPasteSdr::SetAttr
1920                                         : SwPasteSdr::Insert),
1921                                 pPt, nActionFlags, nullptr );
1922                 break;
1923 
1924             case SotClipboardFormatId::FILE_LIST:
1925                 // then insert as graphics only
1926                 bRet = SwTransferable::PasteFileList( rData, rSh,
1927                                     EXCHG_IN_ACTION_LINK == nAction,
1928                                     pPt, bMsg );
1929                 break;
1930 
1931             case SotClipboardFormatId::SONLK:
1932                 if( pPt )
1933                 {
1934                     NaviContentBookmark aBkmk;
1935                     if (aBkmk.Paste(rData, rSh.GetSelText()))
1936                     {
1937                         aWait.~SwWait(); // end the wait pointer, X11 only annoyance
1938                         rSh.NavigatorPaste(aBkmk);
1939                         bRet = true;
1940                     }
1941                 }
1942                 break;
1943 
1944             case SotClipboardFormatId::INET_IMAGE:
1945             case SotClipboardFormatId::NETSCAPE_IMAGE:
1946                 bRet = SwTransferable::PasteTargetURL( rData, rSh,
1947                                                         SwPasteSdr::Insert,
1948                                                         pPt, true );
1949                 break;
1950 
1951             default:
1952                 OSL_ENSURE( pPt, "unknown format" );
1953             }
1954             break;
1955 
1956         case EXCHG_OUT_ACTION_INSERT_FILE:
1957             {
1958                 bool graphicInserted;
1959                 bRet = SwTransferable::PasteFileName( rData, rSh, nFormat,
1960                                             SwPasteSdr::Insert, pPt,
1961                                             nActionFlags,
1962                                             &graphicInserted );
1963                 if( graphicInserted )
1964                     bCallAutoCaption = true;
1965             }
1966             break;
1967 
1968         case EXCHG_OUT_ACTION_INSERT_OLE:
1969             bRet = SwTransferable::PasteOLE( rData, rSh, nFormat,
1970                                                 nActionFlags,bMsg );
1971             break;
1972 
1973         case EXCHG_OUT_ACTION_INSERT_DDE:
1974             {
1975                 bool bReRead = 0 != CNT_HasGrf( rSh.GetCntType() );
1976                 bRet = SwTransferable::PasteDDE( rData, rSh, bReRead, bMsg );
1977             }
1978             break;
1979 
1980         case EXCHG_OUT_ACTION_INSERT_HYPERLINK:
1981             {
1982                 OUString sURL, sDesc;
1983                 if( SotClipboardFormatId::SIMPLE_FILE == nFormat )
1984                 {
1985                     if( rData.GetString( nFormat, sURL ) && !sURL.isEmpty() )
1986                     {
1987                         SwTransferable::CheckForURLOrLNKFile( rData, sURL, &sDesc );
1988                         if( sDesc.isEmpty() )
1989                             sDesc = sURL;
1990                         bRet = true;
1991                     }
1992                 }
1993                 else
1994                 {
1995                     INetBookmark aBkmk;
1996                     if( rData.GetINetBookmark( nFormat, aBkmk ) )
1997                     {
1998                         sURL = aBkmk.GetURL();
1999                         sDesc = aBkmk.GetDescription();
2000                         bRet = true;
2001                     }
2002                 }
2003 
2004                 if( bRet )
2005                 {
2006                     SwFormatINetFormat aFormat( sURL, OUString() );
2007                     rSh.InsertURL( aFormat, sDesc );
2008                 }
2009             }
2010             break;
2011 
2012         case EXCHG_OUT_ACTION_GET_ATTRIBUTES:
2013             switch( nFormat )
2014             {
2015             case SotClipboardFormatId::DRAWING:
2016                 bRet = SwTransferable::PasteSdrFormat( rData, rSh,
2017                                                 SwPasteSdr::SetAttr, pPt,
2018                                                 nActionFlags, bNeedToSelectBeforePaste);
2019                 break;
2020             case SotClipboardFormatId::SVXB:
2021             case SotClipboardFormatId::GDIMETAFILE:
2022             case SotClipboardFormatId::BITMAP:
2023             case SotClipboardFormatId::PNG:
2024             case SotClipboardFormatId::NETSCAPE_BOOKMARK:
2025             case SotClipboardFormatId::SIMPLE_FILE:
2026             case SotClipboardFormatId::FILEGRPDESCRIPTOR:
2027             case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
2028                 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
2029                                                 SwPasteSdr::SetAttr, pPt,
2030                                                 nActionFlags, nDropAction, bNeedToSelectBeforePaste);
2031                 break;
2032             default:
2033                 OSL_FAIL( "unknown format" );
2034             }
2035 
2036             break;
2037 
2038         case EXCHG_OUT_ACTION_INSERT_DRAWOBJ:
2039             bRet = SwTransferable::PasteSdrFormat( rData, rSh,
2040                                                 SwPasteSdr::Insert, pPt,
2041                                                 nActionFlags, bNeedToSelectBeforePaste);
2042             break;
2043         case EXCHG_OUT_ACTION_INSERT_SVXB:
2044         case EXCHG_OUT_ACTION_INSERT_GDIMETAFILE:
2045         case EXCHG_OUT_ACTION_INSERT_BITMAP:
2046         case EXCHG_OUT_ACTION_INSERT_GRAPH:
2047             bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
2048                                                 SwPasteSdr::Insert, pPt,
2049                                                 nActionFlags, nDropAction, bNeedToSelectBeforePaste, nAnchorType );
2050             break;
2051 
2052         case EXCHG_OUT_ACTION_REPLACE_DRAWOBJ:
2053             bRet = SwTransferable::PasteSdrFormat( rData, rSh,
2054                                                 SwPasteSdr::Replace, pPt,
2055                                                 nActionFlags, bNeedToSelectBeforePaste);
2056             break;
2057 
2058         case EXCHG_OUT_ACTION_REPLACE_SVXB:
2059         case EXCHG_OUT_ACTION_REPLACE_GDIMETAFILE:
2060         case EXCHG_OUT_ACTION_REPLACE_BITMAP:
2061         case EXCHG_OUT_ACTION_REPLACE_GRAPH:
2062             bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
2063                                                 SwPasteSdr::Replace,pPt,
2064                                                 nActionFlags, nDropAction, bNeedToSelectBeforePaste);
2065             break;
2066 
2067         case EXCHG_OUT_ACTION_INSERT_INTERACTIVE:
2068             bRet = SwTransferable::PasteAsHyperlink( rData, rSh, nFormat );
2069             break;
2070 
2071         default:
2072             OSL_FAIL("unknown action" );
2073         }
2074     }
2075 
2076     if( !bPasteSelection && rSh.IsFrameSelected() )
2077     {
2078         rSh.EnterSelFrameMode();
2079         //force ::SelectShell
2080         rSh.GetView().StopShellTimer();
2081     }
2082 
2083     pAction.reset();
2084     if( bCallAutoCaption )
2085         rSh.GetView().AutoCaption( GRAPHIC_CAP );
2086 
2087     return bRet;
2088 }
2089 
GetSotDestination(const SwWrtShell & rSh)2090 SotExchangeDest SwTransferable::GetSotDestination( const SwWrtShell& rSh )
2091 {
2092     SotExchangeDest nRet = SotExchangeDest::NONE;
2093 
2094     ObjCntType eOType = rSh.GetObjCntTypeOfSelection();
2095 
2096     switch( eOType )
2097     {
2098     case OBJCNT_GRF:
2099         {
2100             bool bIMap, bLink;
2101             bIMap = nullptr != rSh.GetFlyFrameFormat()->GetURL().GetMap();
2102             OUString aDummy;
2103             rSh.GetGrfNms( &aDummy, nullptr );
2104             bLink = !aDummy.isEmpty();
2105 
2106             if( bLink && bIMap )
2107                 nRet = SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP;
2108             else if( bLink )
2109                 nRet = SotExchangeDest::DOC_LNKD_GRAPHOBJ;
2110             else if( bIMap )
2111                 nRet = SotExchangeDest::DOC_GRAPH_W_IMAP;
2112             else
2113                 nRet = SotExchangeDest::DOC_GRAPHOBJ;
2114         }
2115         break;
2116 
2117     case OBJCNT_FLY:
2118         if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr  )
2119             nRet = SotExchangeDest::DOC_TEXTFRAME_WEB;
2120         else
2121             nRet = SotExchangeDest::DOC_TEXTFRAME;
2122         break;
2123     case OBJCNT_OLE:        nRet = SotExchangeDest::DOC_OLEOBJ;       break;
2124 
2125     case OBJCNT_CONTROL:    /* no Action avail */
2126     case OBJCNT_SIMPLE:     nRet = SotExchangeDest::DOC_DRAWOBJ;      break;
2127     case OBJCNT_URLBUTTON:  nRet = SotExchangeDest::DOC_URLBUTTON;    break;
2128     case OBJCNT_GROUPOBJ:   nRet = SotExchangeDest::DOC_GROUPOBJ;     break;
2129 
2130     // what do we do at multiple selections???
2131     default:
2132         {
2133             if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr  )
2134                 nRet = SotExchangeDest::SWDOC_FREE_AREA_WEB;
2135             else
2136                 nRet = SotExchangeDest::SWDOC_FREE_AREA;
2137         }
2138     }
2139 
2140     return nRet;
2141 }
2142 
PasteFileContent(const TransferableDataHelper & rData,SwWrtShell & rSh,SotClipboardFormatId nFormat,bool bMsg,bool bIgnoreComments)2143 bool SwTransferable::PasteFileContent( const TransferableDataHelper& rData,
2144                                     SwWrtShell& rSh, SotClipboardFormatId nFormat, bool bMsg, bool bIgnoreComments )
2145 {
2146     TranslateId pResId = STR_CLPBRD_FORMAT_ERROR;
2147     bool bRet = false;
2148 
2149     MSE40HTMLClipFormatObj aMSE40ClpObj;
2150 
2151     std::unique_ptr<SvStream> xStrm;
2152     SvStream* pStream = nullptr;
2153     Reader* pRead = nullptr;
2154     OUString sData;
2155     switch( nFormat )
2156     {
2157     case SotClipboardFormatId::STRING:
2158         {
2159             pRead = ReadAscii;
2160             if( rData.GetString( nFormat, sData ) )
2161             {
2162                 pStream = new SvMemoryStream( const_cast<sal_Unicode *>(sData.getStr()),
2163                             sData.getLength() * sizeof( sal_Unicode ),
2164                             StreamMode::READ );
2165 #ifdef OSL_BIGENDIAN
2166                 pStream->SetEndian( SvStreamEndian::BIG );
2167 #else
2168                 pStream->SetEndian( SvStreamEndian::LITTLE );
2169 #endif
2170 
2171                 SwAsciiOptions aAOpt;
2172                 aAOpt.SetCharSet( RTL_TEXTENCODING_UCS2 );
2173                 pRead->GetReaderOpt().SetASCIIOpts( aAOpt );
2174                 break;
2175             }
2176         }
2177         [[fallthrough]]; // because then test if we get a stream
2178 
2179     default:
2180         if( (xStrm = rData.GetSotStorageStream( nFormat )) )
2181         {
2182             if( ( SotClipboardFormatId::HTML_SIMPLE == nFormat ) ||
2183                 ( SotClipboardFormatId::HTML_NO_COMMENT == nFormat ) )
2184             {
2185                 pStream = aMSE40ClpObj.IsValid( *xStrm );
2186                 pRead = ReadHTML;
2187                 pRead->SetReadUTF8( true );
2188 
2189                 bool bNoComments =
2190                     ( nFormat == SotClipboardFormatId::HTML_NO_COMMENT );
2191                 pRead->SetIgnoreHTMLComments( bNoComments );
2192             }
2193             else
2194             {
2195                 pStream = xStrm.get();
2196                 if( SotClipboardFormatId::RTF == nFormat || SotClipboardFormatId::RICHTEXT == nFormat)
2197                     pRead = SwReaderWriter::GetRtfReader();
2198                 else if( !pRead )
2199                 {
2200                     pRead = ReadHTML;
2201                     pRead->SetReadUTF8( true );
2202                 }
2203             }
2204         }
2205         break;
2206     }
2207 
2208     if( pStream && pRead )
2209     {
2210         Link<LinkParamNone*,void> aOldLink( rSh.GetChgLnk() );
2211         rSh.SetChgLnk( Link<LinkParamNone*,void>() );
2212 
2213         const SwPosition& rInsPos = *rSh.GetCursor()->Start();
2214         SwReader aReader(*pStream, OUString(), OUString(), *rSh.GetCursor());
2215         rSh.SaveTableBoxContent( &rInsPos );
2216 
2217         if (bIgnoreComments)
2218             pRead->SetIgnoreHTMLComments(true);
2219 
2220         if( aReader.Read( *pRead ).IsError() )
2221             pResId = STR_ERROR_CLPBRD_READ;
2222         else
2223         {
2224             pResId = TranslateId();
2225             bRet = true;
2226         }
2227 
2228         rSh.SetChgLnk( aOldLink );
2229         if( bRet )
2230             rSh.CallChgLnk();
2231     }
2232     else
2233         pResId = STR_CLPBRD_FORMAT_ERROR;
2234 
2235     // Exist a SvMemoryStream? (data in the OUString and xStrm is empty)
2236     if( pStream && !xStrm )
2237         delete pStream;
2238 
2239     if (bMsg && pResId)
2240     {
2241         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2242                                                   VclMessageType::Info, VclButtonsType::Ok,
2243                                                   SwResId(pResId)));
2244         xBox->run();
2245     }
2246     return bRet;
2247 }
2248 
PasteOLE(const TransferableDataHelper & rData,SwWrtShell & rSh,SotClipboardFormatId nFormat,SotExchangeActionFlags nActionFlags,bool bMsg)2249 bool SwTransferable::PasteOLE( const TransferableDataHelper& rData, SwWrtShell& rSh,
2250                                 SotClipboardFormatId nFormat, SotExchangeActionFlags nActionFlags, bool bMsg )
2251 {
2252     bool bRet = false;
2253     TransferableObjectDescriptor aObjDesc;
2254     uno::Reference < io::XInputStream > xStrm;
2255     uno::Reference < embed::XStorage > xStore;
2256     Reader* pRead = nullptr;
2257 
2258     // Get the preferred format
2259     SotClipboardFormatId nId;
2260     if( rData.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ ) )
2261         nId = SotClipboardFormatId::EMBEDDED_OBJ;
2262     else if( rData.HasFormat( SotClipboardFormatId::EMBED_SOURCE ) &&
2263              rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ))
2264         nId = SotClipboardFormatId::EMBED_SOURCE;
2265     else
2266         nId = SotClipboardFormatId::NONE;
2267 
2268     if (nId != SotClipboardFormatId::NONE)
2269     {
2270         SwDocShell* pDocSh = rSh.GetDoc()->GetDocShell();
2271         xStrm = rData.GetInputStream(nId, SfxObjectShell::CreateShellID(pDocSh));
2272     }
2273 
2274     if (xStrm.is())
2275     {
2276         // if there is an embedded object, first try if it's a writer object
2277         // this will be inserted into the document by using a Reader
2278         try
2279         {
2280             xStore = comphelper::OStorageHelper::GetStorageFromInputStream( xStrm );
2281             switch( SotStorage::GetFormatID( xStore ) )
2282             {
2283                 case SotClipboardFormatId::STARWRITER_60:
2284                 case SotClipboardFormatId::STARWRITERWEB_60:
2285                 case SotClipboardFormatId::STARWRITERGLOB_60:
2286                 case SotClipboardFormatId::STARWRITER_8:
2287                 case SotClipboardFormatId::STARWRITERWEB_8:
2288                 case SotClipboardFormatId::STARWRITERGLOB_8:
2289                     pRead = ReadXML;
2290                     break;
2291                 default:
2292                     try
2293                     {
2294                         xStore->dispose();
2295                         xStore = nullptr;
2296                     }
2297                     catch (const uno::Exception&)
2298                     {
2299                     }
2300 
2301                     break;
2302             }
2303         }
2304         catch (const uno::Exception&)
2305         {
2306             // it wasn't a storage, but maybe it's a useful stream
2307         }
2308     }
2309 
2310     if( pRead )
2311     {
2312         SwPaM &rPAM = *rSh.GetCursor();
2313         SwReader aReader(xStore, OUString(), rPAM);
2314         if( ! aReader.Read( *pRead ).IsError() )
2315             bRet = true;
2316         else if( bMsg )
2317         {
2318             std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2319                                                       VclMessageType::Info, VclButtonsType::Ok,
2320                                                       SwResId(STR_ERROR_CLPBRD_READ)));
2321             xBox->run();
2322         }
2323     }
2324     else
2325     {
2326         // temporary storage until the object is inserted
2327         uno::Reference< embed::XStorage > xTmpStor;
2328         uno::Reference < embed::XEmbeddedObject > xObj;
2329         OUString aName;
2330         comphelper::EmbeddedObjectContainer aCnt;
2331 
2332         if ( xStrm.is() )
2333         {
2334             if ( !rData.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
2335             {
2336                 OSL_ENSURE( !xStrm.is(), "An object without descriptor in clipboard!");
2337             }
2338         }
2339         else
2340         {
2341             if( rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR_OLE ) && rData.GetTransferableObjectDescriptor( nFormat, aObjDesc ) )
2342             {
2343                 xStrm = rData.GetInputStream(SotClipboardFormatId::EMBED_SOURCE_OLE, OUString());
2344                 if (!xStrm.is())
2345                     xStrm = rData.GetInputStream(SotClipboardFormatId::EMBEDDED_OBJ_OLE, OUString());
2346 
2347                 if ( !xStrm.is() )
2348                 {
2349                     // This is MSOLE object that should be created by direct using of system clipboard
2350                     try
2351                     {
2352                         xTmpStor = ::comphelper::OStorageHelper::GetTemporaryStorage();
2353                         uno::Reference < embed::XEmbedObjectClipboardCreator > xClipboardCreator =
2354                             embed::MSOLEObjectSystemCreator::create( ::comphelper::getProcessComponentContext() );
2355 
2356                         embed::InsertedObjectInfo aInfo = xClipboardCreator->createInstanceInitFromClipboard(
2357                                                             xTmpStor,
2358                                                             u"DummyName"_ustr,
2359                                                             uno::Sequence< beans::PropertyValue >() );
2360 
2361                         // TODO/LATER: in future InsertedObjectInfo will be used to get container related information
2362                         // for example whether the object should be an iconified one
2363                         xObj = aInfo.Object;
2364                     }
2365                     catch (const uno::Exception&)
2366                     {
2367                     }
2368                 }
2369             }
2370             else if (rData.HasFormat(SotClipboardFormatId::SIMPLE_FILE))
2371             {
2372                 OUString sFile;
2373                 if (rData.GetString(nFormat, sFile) && !sFile.isEmpty())
2374                 {
2375                     // Copied from sd::View::DropInsertFileHdl
2376                     uno::Sequence< beans::PropertyValue > aMedium{ comphelper::makePropertyValue(
2377                         u"URL"_ustr, sFile) };
2378                     SwDocShell* pDocSh = rSh.GetDoc()->GetDocShell();
2379                     xObj = pDocSh->GetEmbeddedObjectContainer().InsertEmbeddedObject(aMedium, aName);
2380                 }
2381             }
2382         }
2383 
2384         if ( xStrm.is() && !xObj.is() )
2385             xObj = aCnt.InsertEmbeddedObject( xStrm, aName );
2386 
2387         if( xObj.is() )
2388         {
2389             svt::EmbeddedObjectRef xObjRef( xObj, aObjDesc.mnViewAspect );
2390 
2391             // try to get the replacement image from the clipboard
2392             Graphic aGraphic;
2393             SotClipboardFormatId nGrFormat = SotClipboardFormatId::NONE;
2394 
2395             // limit the size of the preview metafile to 100000 actions
2396             GDIMetaFile aMetafile;
2397             if (rData.GetGDIMetaFile(SotClipboardFormatId::GDIMETAFILE, aMetafile, 100000))
2398             {
2399                 nGrFormat = SotClipboardFormatId::GDIMETAFILE;
2400                 aGraphic = aMetafile;
2401             }
2402 
2403             // insert replacement image ( if there is one ) into the object helper
2404             if ( nGrFormat != SotClipboardFormatId::NONE )
2405             {
2406                 DataFlavor aDataFlavor;
2407                 SotExchange::GetFormatDataFlavor( nGrFormat, aDataFlavor );
2408                 xObjRef.SetGraphic( aGraphic, aDataFlavor.MimeType );
2409             }
2410             else if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON )
2411             {
2412                 // it is important to have an icon, let an empty graphic be used
2413                 // if no other graphic is provided
2414                 // TODO/LATER: in future a default bitmap could be used
2415                 MapMode aMapMode( MapUnit::Map100thMM );
2416                 aGraphic.SetPrefSize( Size( 2500, 2500 ) );
2417                 aGraphic.SetPrefMapMode( aMapMode );
2418                 xObjRef.SetGraphic( aGraphic, OUString() );
2419             }
2420 
2421             //set size. This is a hack because of handing over, size should be
2422             //passed to the InsertOle!!!!!!!!!!
2423             Size aSize;
2424             if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON )
2425             {
2426                 if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
2427                     aSize = aObjDesc.maSize;
2428                 else
2429                 {
2430                     MapMode aMapMode( MapUnit::Map100thMM );
2431                     aSize = xObjRef.GetSize( &aMapMode );
2432                 }
2433             }
2434             else if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
2435             {
2436                 aSize = aObjDesc.maSize;    //always 100TH_MM
2437                 MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( aObjDesc.mnViewAspect ) );
2438                 aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aUnit));
2439                 awt::Size aSz;
2440                 try
2441                 {
2442                     aSz = xObj->getVisualAreaSize( aObjDesc.mnViewAspect );
2443                 }
2444                 catch (const embed::NoVisualAreaSizeException&)
2445                 {
2446                     // in this case the provided size is used
2447                 }
2448 
2449                 if ( aSz.Width != aSize.Width() || aSz.Height != aSize.Height() )
2450                 {
2451                     aSz.Width = aSize.Width();
2452                     aSz.Height = aSize.Height();
2453                     xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz );
2454                 }
2455             }
2456             else
2457             {
2458                 // the descriptor contains the wrong object size
2459                 // the following call will let the MSOLE objects cache the size if it is possible
2460                 // it should be done while the object is running
2461                 try
2462                 {
2463                     xObj->getVisualAreaSize( aObjDesc.mnViewAspect );
2464                 }
2465                 catch (const uno::Exception&)
2466                 {
2467                 }
2468             }
2469             //End of Hack!
2470 
2471             rSh.InsertOleObject( xObjRef );
2472             bRet = true;
2473 
2474             if( bRet && ( nActionFlags & SotExchangeActionFlags::InsertTargetUrl) )
2475                 SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
2476 
2477             // let the object be unloaded if possible
2478             SwOLEObj::UnloadObject( xObj, rSh.GetDoc(), embed::Aspects::MSOLE_CONTENT );
2479         }
2480     }
2481     return bRet;
2482 }
2483 
PasteTargetURL(const TransferableDataHelper & rData,SwWrtShell & rSh,SwPasteSdr nAction,const Point * pPt,bool bInsertGRF)2484 bool SwTransferable::PasteTargetURL( const TransferableDataHelper& rData,
2485                                     SwWrtShell& rSh, SwPasteSdr nAction,
2486                                     const Point* pPt, bool bInsertGRF )
2487 {
2488     bool bRet = false;
2489     INetImage aINetImg;
2490     if( ( rData.HasFormat( SotClipboardFormatId::INET_IMAGE ) &&
2491           rData.GetINetImage( SotClipboardFormatId::INET_IMAGE, aINetImg )) ||
2492         ( rData.HasFormat( SotClipboardFormatId::NETSCAPE_IMAGE ) &&
2493           rData.GetINetImage( SotClipboardFormatId::NETSCAPE_IMAGE, aINetImg )) )
2494     {
2495         if( !aINetImg.GetImageURL().isEmpty() && bInsertGRF )
2496         {
2497             OUString sURL( aINetImg.GetImageURL() );
2498             SwTransferable::CheckForURLOrLNKFile( rData, sURL );
2499 
2500             //!!! check at FileSystem - only then it makes sense to test graphics !!!
2501             Graphic aGraphic;
2502             GraphicFilter &rFlt = GraphicFilter::GetGraphicFilter();
2503             bRet = ERRCODE_NONE == GraphicFilter::LoadGraphic(sURL, OUString(), aGraphic, &rFlt);
2504 
2505             if( bRet )
2506             {
2507                 //Check and Perform rotation if needed
2508                 lclCheckAndPerformRotation(aGraphic);
2509 
2510                 switch( nAction )
2511                 {
2512                 case SwPasteSdr::Insert:
2513                     SwTransferable::SetSelInShell( rSh, false, pPt );
2514                     rSh.InsertGraphic(sURL, OUString(), aGraphic);
2515                     break;
2516 
2517                 case SwPasteSdr::Replace:
2518                     if( rSh.IsObjSelected() )
2519                     {
2520                         rSh.ReplaceSdrObj( sURL, &aGraphic );
2521                         Point aPt( pPt ? *pPt : rSh.GetCursorDocPos() );
2522                         SwTransferable::SetSelInShell( rSh, true, &aPt );
2523                     }
2524                     else
2525                         rSh.ReRead(sURL, OUString(), &aGraphic);
2526                     break;
2527 
2528                 case SwPasteSdr::SetAttr:
2529                     if( rSh.IsObjSelected() )
2530                         rSh.Paste( aGraphic, OUString() );
2531                     else if( OBJCNT_GRF == rSh.GetObjCntTypeOfSelection() )
2532                         rSh.ReRead(sURL, OUString(), &aGraphic);
2533                     else
2534                     {
2535                         SwTransferable::SetSelInShell( rSh, false, pPt );
2536                         rSh.InsertGraphic(sURL, OUString(), aGraphic);
2537                     }
2538                     break;
2539                 default:
2540                     bRet = false;
2541                 }
2542             }
2543         }
2544         else
2545             bRet = true;
2546     }
2547 
2548     if( bRet )
2549     {
2550         SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
2551         rSh.GetFlyFrameAttr( aSet );
2552         SwFormatURL aURL( aSet.Get( RES_URL ) );
2553 
2554         if( aURL.GetURL() != aINetImg.GetTargetURL() ||
2555             aURL.GetTargetFrameName() != aINetImg.GetTargetFrame() )
2556         {
2557             aURL.SetURL( aINetImg.GetTargetURL(), false );
2558             aURL.SetTargetFrameName( aINetImg.GetTargetFrame() );
2559             aSet.Put( aURL );
2560             rSh.SetFlyFrameAttr( aSet );
2561         }
2562     }
2563     return bRet;
2564 }
2565 
SetSelInShell(SwWrtShell & rSh,bool bSelectFrame,const Point * pPt)2566 void SwTransferable::SetSelInShell( SwWrtShell& rSh, bool bSelectFrame,
2567                                         const Point* pPt )
2568 {
2569     if( bSelectFrame )
2570     {
2571         // select frames/objects
2572         if( pPt && !rSh.GetView().GetViewFrame().GetDispatcher()->IsLocked() )
2573         {
2574             rSh.GetView().NoRotate();
2575             if( rSh.SelectObj( *pPt ))
2576             {
2577                 rSh.HideCursor();
2578                 rSh.EnterSelFrameMode( pPt );
2579                 g_bFrameDrag = true;
2580             }
2581         }
2582     }
2583     else
2584     {
2585         if( rSh.IsFrameSelected() || rSh.IsObjSelected() )
2586         {
2587             rSh.UnSelectFrame();
2588             rSh.LeaveSelFrameMode();
2589             rSh.GetView().GetEditWin().StopInsFrame();
2590             g_bFrameDrag = false;
2591         }
2592         else if( rSh.GetView().GetDrawFuncPtr() )
2593             rSh.GetView().GetEditWin().StopInsFrame();
2594 
2595         rSh.EnterStdMode();
2596         if( pPt )
2597             rSh.SwCursorShell::SetCursor( *pPt, true );
2598     }
2599 }
2600 
PasteDDE(const TransferableDataHelper & rData,SwWrtShell & rWrtShell,bool bReReadGrf,bool bMsg)2601 bool SwTransferable::PasteDDE( const TransferableDataHelper& rData,
2602                                 SwWrtShell& rWrtShell, bool bReReadGrf,
2603                                 bool bMsg )
2604 {
2605     // data from Clipboardformat
2606     OUString aApp, aTopic, aItem;
2607 
2608     if (!rData.ReadDDELink(aApp, aTopic, aItem, o3tl::temporary(OUString())))
2609     {
2610         return false;
2611     }   // report useful error!!
2612 
2613     OUString aCmd;
2614     sfx2::MakeLnkName( aCmd, &aApp, aTopic, aItem );
2615 
2616     // do we want to read in a graphic now?
2617     SotClipboardFormatId nFormat;
2618     if( !rData.HasFormat( SotClipboardFormatId::RTF ) &&
2619         !rData.HasFormat( SotClipboardFormatId::RICHTEXT ) &&
2620         !rData.HasFormat( SotClipboardFormatId::HTML ) &&
2621         !rData.HasFormat( SotClipboardFormatId::STRING ) &&
2622         (rData.HasFormat( nFormat = SotClipboardFormatId::GDIMETAFILE ) ||
2623          rData.HasFormat( nFormat = SotClipboardFormatId::BITMAP )) )
2624     {
2625         Graphic aGrf;
2626         bool bRet = rData.GetGraphic( nFormat, aGrf );
2627         if( bRet )
2628         {
2629             OUString sLnkTyp(u"DDE"_ustr);
2630             if ( bReReadGrf )
2631                 rWrtShell.ReRead( aCmd, sLnkTyp, &aGrf );
2632             else
2633                 rWrtShell.InsertGraphic( aCmd, sLnkTyp, aGrf );
2634         }
2635         return bRet;
2636     }
2637 
2638     SwFieldType* pTyp = nullptr;
2639     size_t i = 1;
2640     size_t j;
2641     OUString aName;
2642     bool bDoublePaste = false;
2643     const size_t nSize = rWrtShell.GetFieldTypeCount();
2644     const ::utl::TransliterationWrapper& rColl = ::GetAppCmpStrIgnore();
2645 
2646     do {
2647         aName = aApp + OUString::number( i );
2648         for( j = INIT_FLDTYPES; j < nSize; j++ )
2649         {
2650             pTyp = rWrtShell.GetFieldType( j );
2651             if( SwFieldIds::Dde == pTyp->Which() )
2652             {
2653                 if( rColl.isEqual( static_cast<SwDDEFieldType*>(pTyp)->GetCmd(), aCmd ) &&
2654                     SfxLinkUpdateMode::ALWAYS == static_cast<SwDDEFieldType*>(pTyp)->GetType() )
2655                 {
2656                     aName = pTyp->GetName();
2657                     bDoublePaste = true;
2658                     break;
2659                 }
2660                 else if( rColl.isEqual( aName, pTyp->GetName() ) )
2661                     break;
2662             }
2663         }
2664         if( j == nSize )
2665             break;
2666         ++i;
2667     }
2668     while( !bDoublePaste );
2669 
2670     if( !bDoublePaste )
2671     {
2672         SwDDEFieldType aType( aName, aCmd, SfxLinkUpdateMode::ALWAYS );
2673         pTyp = rWrtShell.InsertFieldType( aType );
2674     }
2675 
2676     SwDDEFieldType* pDDETyp = static_cast<SwDDEFieldType*>(pTyp);
2677 
2678     OUString aExpand;
2679     if( rData.GetString( SotClipboardFormatId::STRING, aExpand ))
2680     {
2681         do {            // middle checked loop
2682 
2683             const sal_Int32 nNewlines{comphelper::string::getTokenCount(aExpand, '\n')};
2684             // When data comes from a spreadsheet, we add a DDE-table
2685             if( !aExpand.isEmpty() &&
2686                 ( rData.HasFormat( SotClipboardFormatId::SYLK ) ||
2687                   rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) )
2688             {
2689                 sal_Int32 nRows = nNewlines ? nNewlines-1 : 0;
2690                 if (!aExpand.endsWith("\n"))
2691                     ++nRows;    // last row has no newline, e.g. one single cell
2692                 const sal_Int32 nCols = comphelper::string::getTokenCount(o3tl::getToken(aExpand, 0, '\n'), '\t');
2693 
2694                 // don't try to insert tables that are too large for writer
2695                 if (nRows > SAL_MAX_UINT16 || nCols > SAL_MAX_UINT16)
2696                 {
2697                     if( bMsg )
2698                     {
2699                         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2700                                                                   VclMessageType::Info, VclButtonsType::Ok,
2701                                                                   SwResId(STR_TABLE_TOO_LARGE)));
2702                         xBox->run();
2703                     }
2704                     pDDETyp = nullptr;
2705                     break;
2706                 }
2707 
2708                 // at least one column & row must be there
2709                 if( !nRows || !nCols )
2710                 {
2711                     if( bMsg )
2712                     {
2713                         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2714                                                                   VclMessageType::Info, VclButtonsType::Ok,
2715                                                                   SwResId(STR_NO_TABLE)));
2716                         xBox->run();
2717                     }
2718                     pDDETyp = nullptr;
2719                     break;
2720                 }
2721 
2722                 rWrtShell.InsertDDETable(
2723                     SwInsertTableOptions( SwInsertTableFlags::SplitLayout, 1 ), // TODO MULTIHEADER
2724                     pDDETyp, nRows, nCols );
2725             }
2726             else if( nNewlines > 1 )
2727             {
2728                 // multiple paragraphs -> insert a protected section
2729                 if( rWrtShell.HasSelection() )
2730                     rWrtShell.DelRight();
2731 
2732                 SwSectionData aSect( SectionType::DdeLink, aName );
2733                 aSect.SetLinkFileName( aCmd );
2734                 aSect.SetProtectFlag(true);
2735                 rWrtShell.InsertSection( aSect );
2736 
2737                 pDDETyp = nullptr;                // remove FieldTypes again
2738             }
2739             else
2740             {
2741                 // insert
2742                 SwDDEField aSwDDEField( pDDETyp );
2743                 rWrtShell.InsertField2( aSwDDEField );
2744             }
2745 
2746         } while( false );
2747     }
2748     else
2749         pDDETyp = nullptr;                        // remove FieldTypes again
2750 
2751     if( !pDDETyp && !bDoublePaste )
2752     {
2753         // remove FieldType again - error occurred!
2754         for( j = nSize; j >= INIT_FLDTYPES; --j )
2755             if( pTyp == rWrtShell.GetFieldType( j ) )
2756             {
2757                 rWrtShell.RemoveFieldType( j );
2758                 break;
2759             }
2760     }
2761 
2762     return true;
2763 }
2764 
PasteSdrFormat(const TransferableDataHelper & rData,SwWrtShell & rSh,SwPasteSdr nAction,const Point * pPt,SotExchangeActionFlags nActionFlags,bool bNeedToSelectBeforePaste)2765 bool SwTransferable::PasteSdrFormat(  const TransferableDataHelper& rData,
2766                                     SwWrtShell& rSh, SwPasteSdr nAction,
2767                                     const Point* pPt, SotExchangeActionFlags nActionFlags, bool bNeedToSelectBeforePaste)
2768 {
2769     bool bRet = false;
2770     if( std::unique_ptr<SvStream> xStrm = rData.GetSotStorageStream( SotClipboardFormatId::DRAWING ))
2771     {
2772         xStrm->SetVersion( SOFFICE_FILEFORMAT_50 );
2773 
2774         if(bNeedToSelectBeforePaste && pPt)
2775         {
2776             // if this is an internal drag, need to set the target right (select it), else
2777             // still the source will be selected
2778             SwTransferable::SetSelInShell( rSh, true, pPt );
2779         }
2780 
2781         rSh.Paste( *xStrm, nAction, pPt );
2782         bRet = true;
2783 
2784         if( bRet && ( nActionFlags & SotExchangeActionFlags::InsertTargetUrl ))
2785             SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
2786     }
2787     return bRet;
2788 }
2789 
PasteGrf(const TransferableDataHelper & rData,SwWrtShell & rSh,SotClipboardFormatId nFormat,SwPasteSdr nAction,const Point * pPt,SotExchangeActionFlags nActionFlags,sal_Int8 nDropAction,bool bNeedToSelectBeforePaste,RndStdIds nAnchorType)2790 bool SwTransferable::PasteGrf( const TransferableDataHelper& rData, SwWrtShell& rSh,
2791                                 SotClipboardFormatId nFormat, SwPasteSdr nAction, const Point* pPt,
2792                                 SotExchangeActionFlags nActionFlags, sal_Int8 nDropAction, bool bNeedToSelectBeforePaste, RndStdIds nAnchorType )
2793 {
2794     bool bRet = false;
2795 
2796     Graphic aGraphic;
2797     INetBookmark aBkmk;
2798     bool bCheckForGrf = false, bCheckForImageMap = false;
2799 
2800     switch( nFormat )
2801     {
2802     case SotClipboardFormatId::BITMAP:
2803     case SotClipboardFormatId::PNG:
2804     case SotClipboardFormatId::GDIMETAFILE:
2805         bRet = rData.GetGraphic( nFormat, aGraphic );
2806         break;
2807 
2808     case SotClipboardFormatId::SVXB:
2809     {
2810         if (std::unique_ptr<SvStream> xStm = rData.GetSotStorageStream(SotClipboardFormatId::SVXB))
2811         {
2812             TypeSerializer aSerializer(*xStm);
2813             aSerializer.readGraphic(aGraphic);
2814             bRet = (GraphicType::NONE != aGraphic.GetType() && GraphicType::Default != aGraphic.GetType());
2815         }
2816 
2817         break;
2818     }
2819 
2820     case SotClipboardFormatId::NETSCAPE_BOOKMARK:
2821     case SotClipboardFormatId::FILEGRPDESCRIPTOR:
2822     case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
2823         bRet = rData.GetINetBookmark( nFormat, aBkmk );
2824         if( bRet )
2825         {
2826             if( SwPasteSdr::SetAttr == nAction )
2827                 nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK;
2828             else
2829                 bCheckForGrf = true;
2830         }
2831         break;
2832 
2833     case SotClipboardFormatId::SIMPLE_FILE:
2834         {
2835             OUString sText;
2836             bRet = rData.GetString( nFormat, sText );
2837             if( bRet )
2838             {
2839                 OUString sDesc;
2840                 SwTransferable::CheckForURLOrLNKFile( rData, sText, &sDesc );
2841 
2842                 sText = URIHelper::SmartRel2Abs(INetURLObject(), sText, Link<OUString*, bool>(),
2843                     false);
2844 
2845 #ifdef _WIN32
2846                 // Now that the path could be modified after SwTransferable::CheckForURLOrLNKFile,
2847                 // where it could have been converted to URL, and made sure it's actually converted
2848                 // to URL in URIHelper::SmartRel2Abs, we can finally convert file: URL back to
2849                 // system path to make sure we don't use short path.
2850                 // It looks not optimal, when we could apply GetLongPathNameW right to the original
2851                 // pasted filename. But I don't know if (1) all arriving strings are system paths;
2852                 // and (2) if SwTransferable::CheckForURLOrLNKFile could result in a different short
2853                 // path, so taking a safe route.
2854                 if (sText.startsWithIgnoreAsciiCase("file:"))
2855                 {
2856                     // tdf#124500: Convert short path to long path which should be used in links
2857                     OUString sSysPath;
2858                     osl::FileBase::getSystemPathFromFileURL(sText, sSysPath);
2859                     std::unique_ptr<sal_Unicode[]> aBuf(new sal_Unicode[32767]);
2860                     DWORD nCopied = GetLongPathNameW(o3tl::toW(sSysPath.getStr()),
2861                                                      o3tl::toW(aBuf.get()), 32767);
2862                     if (nCopied && nCopied < 32767)
2863                         sText = URIHelper::SmartRel2Abs(INetURLObject(), OUString(aBuf.get()),
2864                                                         Link<OUString*, bool>(), false);
2865                 }
2866 #endif
2867 
2868                 aBkmk = INetBookmark(sText, sDesc);
2869                 bCheckForGrf = true;
2870                 bCheckForImageMap = SwPasteSdr::Replace == nAction;
2871             }
2872         }
2873         break;
2874 
2875     default:
2876         bRet = rData.GetGraphic( nFormat, aGraphic );
2877         break;
2878     }
2879 
2880     if( bCheckForGrf )
2881     {
2882         //!!! check at FileSystem - only then it makes sense to test the graphics !!!
2883         GraphicFilter &rFlt = GraphicFilter::GetGraphicFilter();
2884         bRet = ERRCODE_NONE == GraphicFilter::LoadGraphic(aBkmk.GetURL(), OUString(),
2885                                             aGraphic, &rFlt );
2886 
2887         if( !bRet && SwPasteSdr::SetAttr == nAction &&
2888             SotClipboardFormatId::SIMPLE_FILE == nFormat &&
2889             // only at frame selection
2890             rSh.IsFrameSelected() )
2891         {
2892             // then set as hyperlink after the graphic
2893             nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK;
2894             bRet = true;
2895         }
2896     }
2897 
2898     if(pPt && bNeedToSelectBeforePaste)
2899     {
2900         // when using internal D&Ds, still the source object is selected and
2901         // this is necessary to get the correct source data which is also
2902         // dependent from selection. After receiving the drag data it is
2903         // now time to select the correct target object
2904         SwTransferable::SetSelInShell( rSh, true, pPt );
2905     }
2906 
2907     if( bRet )
2908     {
2909         //Check and Perform rotation if needed
2910         lclCheckAndPerformRotation(aGraphic);
2911 
2912         OUString sURL;
2913         if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr
2914             // #i123922# if link action is noted, also take URL
2915             || DND_ACTION_LINK == nDropAction)
2916         {
2917             sURL = aBkmk.GetURL();
2918         }
2919 
2920         switch( nAction )
2921         {
2922             case SwPasteSdr::Insert:
2923             {
2924                 SwTransferable::SetSelInShell( rSh, false, pPt );
2925                 rSh.InsertGraphic(sURL, OUString(), aGraphic, nullptr, nAnchorType);
2926                 break;
2927             }
2928 
2929             case SwPasteSdr::Replace:
2930             {
2931                 if( rSh.IsObjSelected() )
2932                 {
2933                     // #i123922# for D&D on draw objects, do for now the same for
2934                     // SwPasteSdr::Replace (D&D) as for SwPasteSdr::SetAttr (D&D and
2935                     // CTRL+SHIFT). The code below replaces the draw object with
2936                     // a writer graphic; maybe this is an option later again if wanted
2937                     rSh.Paste( aGraphic, sURL );
2938 
2939                     // rSh.ReplaceSdrObj(sURL, OUString(), &aGraphic);
2940                     // Point aPt( pPt ? *pPt : rSh.GetCursorDocPos() );
2941                     // SwTransferable::SetSelInShell( rSh, true, &aPt );
2942                 }
2943                 else
2944                 {
2945                     // set graphic at writer graphic without link
2946                     rSh.ReRead(sURL, OUString(), &aGraphic);
2947                 }
2948 
2949                 break;
2950             }
2951 
2952             case SwPasteSdr::SetAttr:
2953             {
2954                 if( SotClipboardFormatId::NETSCAPE_BOOKMARK == nFormat )
2955                 {
2956                     if( rSh.IsFrameSelected() )
2957                     {
2958                         SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
2959                         rSh.GetFlyFrameAttr( aSet );
2960                         SwFormatURL aURL( aSet.Get( RES_URL ) );
2961                         aURL.SetURL( aBkmk.GetURL(), false );
2962                         aSet.Put( aURL );
2963                         rSh.SetFlyFrameAttr( aSet );
2964                     }
2965                 }
2966                 else if( rSh.IsObjSelected() )
2967                 {
2968                     // set as attribute at DrawObject
2969                     rSh.Paste( aGraphic, sURL );
2970                 }
2971                 else if( OBJCNT_GRF == rSh.GetObjCntTypeOfSelection() )
2972                 {
2973                     // set as linked graphic at writer graphic frame
2974                     rSh.ReRead(sURL, OUString(), &aGraphic);
2975                 }
2976                 else
2977                 {
2978                     SwTransferable::SetSelInShell( rSh, false, pPt );
2979                     rSh.InsertGraphic(aBkmk.GetURL(), OUString(), aGraphic);
2980                 }
2981                 break;
2982             }
2983             default:
2984             {
2985                 bRet = false;
2986                 break;
2987             }
2988         }
2989     }
2990 
2991     if( bRet )
2992     {
2993 
2994         if( nActionFlags &
2995             ( SotExchangeActionFlags::InsertImageMap | SotExchangeActionFlags::ReplaceImageMap ) )
2996             SwTransferable::PasteImageMap( rData, rSh );
2997 
2998         if( nActionFlags & SotExchangeActionFlags::InsertTargetUrl )
2999             SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
3000     }
3001     else if( bCheckForImageMap )
3002     {
3003         // or should the file be an ImageMap-File?
3004         ImageMap aMap;
3005         SfxMedium aMed( INetURLObject(aBkmk.GetURL()).GetFull(),
3006                             StreamMode::STD_READ );
3007         SvStream* pStream = aMed.GetInStream();
3008         if( pStream != nullptr  &&
3009             !pStream->GetError()  &&
3010             // mba: no BaseURL for clipboard functionality
3011             aMap.Read( *pStream, IMapFormat::Detect ) == IMAP_ERR_OK &&
3012             aMap.GetIMapObjectCount() )
3013         {
3014             SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3015             rSh.GetFlyFrameAttr( aSet );
3016             SwFormatURL aURL( aSet.Get( RES_URL ) );
3017             aURL.SetMap( &aMap );
3018             aSet.Put( aURL );
3019             rSh.SetFlyFrameAttr( aSet );
3020             bRet = true;
3021         }
3022     }
3023 
3024     return bRet;
3025 }
3026 
PasteImageMap(const TransferableDataHelper & rData,SwWrtShell & rSh)3027 bool SwTransferable::PasteImageMap( const TransferableDataHelper& rData,
3028                                     SwWrtShell& rSh )
3029 {
3030     bool bRet = false;
3031     if( rData.HasFormat( SotClipboardFormatId::SVIM ))
3032     {
3033         SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3034         rSh.GetFlyFrameAttr( aSet );
3035         SwFormatURL aURL( aSet.Get( RES_URL ) );
3036         const ImageMap* pOld = aURL.GetMap();
3037 
3038         // set or replace, that is the question
3039         ImageMap aImageMap;
3040         if( rData.GetImageMap( SotClipboardFormatId::SVIM, aImageMap ) &&
3041             ( !pOld || aImageMap != *pOld ))
3042         {
3043             aURL.SetMap( &aImageMap );
3044             aSet.Put( aURL );
3045             rSh.SetFlyFrameAttr( aSet );
3046         }
3047         bRet = true;
3048     }
3049     return bRet;
3050 }
3051 
PasteAsHyperlink(const TransferableDataHelper & rData,SwWrtShell & rSh,SotClipboardFormatId nFormat)3052 bool SwTransferable::PasteAsHyperlink( const TransferableDataHelper& rData,
3053                                         SwWrtShell& rSh, SotClipboardFormatId nFormat )
3054 {
3055     bool bRet = false;
3056     OUString sFile;
3057     if( rData.GetString( nFormat, sFile ) && !sFile.isEmpty() )
3058     {
3059         OUString sDesc;
3060         SwTransferable::CheckForURLOrLNKFile( rData, sFile, &sDesc );
3061 
3062         // first, make the URL absolute
3063         INetURLObject aURL;
3064         aURL.SetSmartProtocol( INetProtocol::File );
3065         aURL.SetSmartURL( sFile );
3066         sFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
3067 
3068         switch( rSh.GetObjCntTypeOfSelection() )
3069         {
3070         case OBJCNT_FLY:
3071         case OBJCNT_GRF:
3072         case OBJCNT_OLE:
3073             {
3074                 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3075                 rSh.GetFlyFrameAttr( aSet );
3076                 SwFormatURL aURL2( aSet.Get( RES_URL ) );
3077                 aURL2.SetURL( sFile, false );
3078                 if( aURL2.GetName().isEmpty() )
3079                     aURL2.SetName( sFile );
3080                 aSet.Put( aURL2 );
3081                 rSh.SetFlyFrameAttr( aSet );
3082             }
3083             break;
3084 
3085         default:
3086             {
3087                 rSh.InsertURL( SwFormatINetFormat( sFile, OUString() ),
3088                                 sDesc.isEmpty() ? sFile : sDesc);
3089             }
3090         }
3091         bRet = true;
3092     }
3093     return bRet;
3094 }
3095 
PasteFileName(const TransferableDataHelper & rData,SwWrtShell & rSh,SotClipboardFormatId nFormat,SwPasteSdr nAction,const Point * pPt,SotExchangeActionFlags nActionFlags,bool * graphicInserted)3096 bool SwTransferable::PasteFileName( const TransferableDataHelper& rData,
3097                                     SwWrtShell& rSh, SotClipboardFormatId nFormat,
3098                                     SwPasteSdr nAction, const Point* pPt,
3099                                     SotExchangeActionFlags nActionFlags,
3100                                     bool * graphicInserted)
3101 {
3102     bool bRet = SwTransferable::PasteGrf( rData, rSh, nFormat, nAction,
3103                                             pPt, nActionFlags, 0, false);
3104     if (graphicInserted != nullptr) {
3105         *graphicInserted = bRet;
3106     }
3107     if( !bRet )
3108     {
3109         OUString sFile, sDesc;
3110         if( rData.GetString( nFormat, sFile ) && !sFile.isEmpty() )
3111         {
3112 #if HAVE_FEATURE_AVMEDIA
3113             INetURLObject aMediaURL;
3114 
3115             aMediaURL.SetSmartURL( sFile );
3116             const OUString aMediaURLStr( aMediaURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
3117 
3118             if( ::avmedia::MediaWindow::isMediaURL( aMediaURLStr, u""_ustr/*TODO?*/ ) )
3119             {
3120                 const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, aMediaURLStr );
3121                 rSh.GetView().GetViewFrame().GetDispatcher()->ExecuteList(
3122                                 SID_INSERT_AVMEDIA, SfxCallMode::SYNCHRON,
3123                                 { &aMediaURLItem });
3124             }
3125 #else
3126             if (false)
3127             {
3128             }
3129 #endif
3130             else
3131             {
3132                 bool bIsURLFile = SwTransferable::CheckForURLOrLNKFile( rData, sFile, &sDesc );
3133 
3134                 //Own FileFormat? --> insert, not for StarWriter/Web
3135                 OUString sFileURL = URIHelper::SmartRel2Abs(INetURLObject(), sFile, Link<OUString *, bool>(), false );
3136                 std::shared_ptr<const SfxFilter> pFlt = SwPasteSdr::SetAttr == nAction
3137                         ? nullptr : SwIoSystem::GetFileFilter(sFileURL);
3138                 if( pFlt && dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) == nullptr )
3139                 {
3140                     // and then pull up the insert-region-dialog
3141                     SwSectionData aSect(
3142                                     SectionType::FileLink,
3143                                     rSh.GetDoc()->GetUniqueSectionName() );
3144                     aSect.SetLinkFileName( sFileURL );
3145                     aSect.SetProtectFlag( true );
3146 
3147                     rSh.StartInsertRegionDialog( aSect ); // starts dialog asynchronously
3148                     bRet = true;
3149                 }
3150                 else if (SwPasteSdr::Insert == nAction && rData.HasFormat(SotClipboardFormatId::SIMPLE_FILE))
3151                 {
3152                     // insert file as OLE
3153                     PasteOLE(rData, rSh, nFormat, nActionFlags, nullptr == pPt);
3154                 }
3155                 else if( SwPasteSdr::SetAttr == nAction ||
3156                         ( bIsURLFile && SwPasteSdr::Insert == nAction ))
3157                 {
3158                     //we can insert foreign files as links after all
3159 
3160                     // first, make the URL absolute
3161                     INetURLObject aURL;
3162                     aURL.SetSmartProtocol( INetProtocol::File );
3163                     aURL.SetSmartURL( sFile );
3164                     sFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
3165 
3166                     switch( rSh.GetObjCntTypeOfSelection() )
3167                     {
3168                     case OBJCNT_FLY:
3169                     case OBJCNT_GRF:
3170                     case OBJCNT_OLE:
3171                         {
3172                             SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3173                             rSh.GetFlyFrameAttr( aSet );
3174                             SwFormatURL aURL2( aSet.Get( RES_URL ) );
3175                             aURL2.SetURL( sFile, false );
3176                             if( aURL2.GetName().isEmpty() )
3177                                 aURL2.SetName( sFile );
3178                             aSet.Put( aURL2 );
3179                             rSh.SetFlyFrameAttr( aSet );
3180                         }
3181                         break;
3182 
3183                     default:
3184                         {
3185                             rSh.InsertURL( SwFormatINetFormat( sFile, OUString() ),
3186                                             sDesc.isEmpty() ? sFile : sDesc );
3187                         }
3188                     }
3189                     bRet = true;
3190                 }
3191             }
3192         }
3193     }
3194     return bRet;
3195 }
3196 
PasteDBData(const TransferableDataHelper & rData,SwWrtShell & rSh,SotClipboardFormatId nFormat,bool bLink,const Point * pDragPt,bool bMsg)3197 bool SwTransferable::PasteDBData( const TransferableDataHelper& rData,
3198                                     SwWrtShell& rSh, SotClipboardFormatId nFormat, bool bLink,
3199                                     const Point* pDragPt, bool bMsg )
3200 {
3201     bool bRet = false;
3202     OUString sText;
3203     if( rData.GetString( nFormat, sText ) && !sText.isEmpty() )
3204     {
3205         sal_uInt16 nWh = SotClipboardFormatId::SBA_CTRLDATAEXCHANGE == nFormat
3206                     ? 0
3207                     : SotClipboardFormatId::SBA_DATAEXCHANGE == nFormat
3208                                 ? (bLink
3209                                     ? FN_QRY_MERGE_FIELD
3210                                     : FN_QRY_INSERT)
3211                                 : (bLink
3212                                     ? 0
3213                                     : FN_QRY_INSERT_FIELD );
3214         const DataFlavorExVector& rVector = rData.GetDataFlavorExVector();
3215         bool bHaveColumnDescriptor = OColumnTransferable::canExtractColumnDescriptor(rVector, ColumnTransferFormatFlags::COLUMN_DESCRIPTOR | ColumnTransferFormatFlags::CONTROL_EXCHANGE);
3216         if ( SotClipboardFormatId::XFORMS == nFormat )
3217         {
3218             rSh.MakeDrawView();
3219             FmFormView* pFmView = dynamic_cast<FmFormView*>( rSh.GetDrawView()  );
3220             if (pFmView && pDragPt)
3221             {
3222                 OXFormsDescriptor aDesc = OXFormsTransferable::extractDescriptor(rData);
3223                 rtl::Reference<SdrObject> pObj = pFmView->CreateXFormsControl(aDesc);
3224                 if(pObj)
3225                 {
3226                     rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt );
3227                 }
3228             }
3229         }
3230         else if( nWh )
3231         {
3232             std::unique_ptr<SfxUnoAnyItem> pConnectionItem;
3233             std::unique_ptr<SfxUnoAnyItem> pCursorItem;
3234             std::unique_ptr<SfxUnoAnyItem> pColumnItem;
3235             std::unique_ptr<SfxUnoAnyItem> pSourceItem;
3236             std::unique_ptr<SfxUnoAnyItem> pCommandItem;
3237             std::unique_ptr<SfxUnoAnyItem> pCommandTypeItem;
3238             std::unique_ptr<SfxUnoAnyItem> pColumnNameItem;
3239             std::unique_ptr<SfxUnoAnyItem> pSelectionItem;
3240 
3241             bool bDataAvailable = true;
3242             ODataAccessDescriptor aDesc;
3243             if(bHaveColumnDescriptor)
3244                 aDesc = OColumnTransferable::extractColumnDescriptor(rData);
3245             else if(ODataAccessObjectTransferable::canExtractObjectDescriptor(rVector) )
3246                 aDesc = ODataAccessObjectTransferable::extractObjectDescriptor(rData);
3247             else
3248                 bDataAvailable = false;
3249 
3250             if ( bDataAvailable )
3251             {
3252                 pConnectionItem.reset(new SfxUnoAnyItem(FN_DB_CONNECTION_ANY, aDesc[DataAccessDescriptorProperty::Connection]));
3253                 pColumnItem.reset(new SfxUnoAnyItem(FN_DB_COLUMN_ANY, aDesc[DataAccessDescriptorProperty::ColumnObject]));
3254                 pSourceItem.reset(new SfxUnoAnyItem(FN_DB_DATA_SOURCE_ANY, Any(aDesc.getDataSource())));
3255                 pCommandItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COMMAND_ANY, aDesc[DataAccessDescriptorProperty::Command]));
3256                 pCommandTypeItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COMMAND_TYPE_ANY, aDesc[DataAccessDescriptorProperty::CommandType]));
3257                 pColumnNameItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COLUMN_NAME_ANY, aDesc[DataAccessDescriptorProperty::ColumnName]));
3258                 pSelectionItem.reset(new SfxUnoAnyItem(FN_DB_DATA_SELECTION_ANY, aDesc[DataAccessDescriptorProperty::Selection]));
3259                 pCursorItem.reset(new SfxUnoAnyItem(FN_DB_DATA_CURSOR_ANY, aDesc[DataAccessDescriptorProperty::Cursor]));
3260             }
3261 
3262             SwView& rView = rSh.GetView();
3263             //force ::SelectShell
3264             rView.StopShellTimer();
3265 
3266             SfxStringItem aDataDesc( nWh, sText );
3267             rView.GetViewFrame().GetDispatcher()->ExecuteList(
3268                 nWh, SfxCallMode::ASYNCHRON,
3269                 { &aDataDesc, pConnectionItem.get(), pColumnItem.get(),
3270                   pSourceItem.get(), pCommandItem.get(), pCommandTypeItem.get(),
3271                   pColumnNameItem.get(), pSelectionItem.get(),
3272                   pCursorItem.get() });
3273         }
3274         else
3275         {
3276             rSh.MakeDrawView();
3277             FmFormView* pFmView = dynamic_cast<FmFormView*>( rSh.GetDrawView()  );
3278             if (pFmView && bHaveColumnDescriptor && pDragPt)
3279             {
3280                 rtl::Reference<SdrObject> pObj = pFmView->CreateFieldControl( OColumnTransferable::extractColumnDescriptor(rData) );
3281                 if (pObj)
3282                     rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt );
3283             }
3284         }
3285         bRet = true;
3286     }
3287     else if( bMsg )
3288     {
3289         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
3290                                                   VclMessageType::Info, VclButtonsType::Ok,
3291                                                   SwResId(STR_CLPBRD_FORMAT_ERROR)));
3292         xBox->run();
3293     }
3294     return bRet;
3295 }
3296 
PasteFileList(const TransferableDataHelper & rData,SwWrtShell & rSh,bool bLink,const Point * pPt,bool bMsg)3297 bool SwTransferable::PasteFileList( const TransferableDataHelper& rData,
3298                                     SwWrtShell& rSh, bool bLink,
3299                                     const Point* pPt, bool bMsg )
3300 {
3301     bool bRet = false;
3302     FileList aFileList;
3303     if( rData.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList ) &&
3304         aFileList.Count() )
3305     {
3306         SwPasteSdr nAct = bLink ? SwPasteSdr::SetAttr : SwPasteSdr::Insert;
3307         OUString sFlyNm;
3308         // iterate over the filelist
3309         for( sal_uLong n = 0, nEnd = aFileList.Count(); n < nEnd; ++n )
3310         {
3311             rtl::Reference<TransferDataContainer> pHlp = new TransferDataContainer;
3312             pHlp->CopyString( SotClipboardFormatId::SIMPLE_FILE, aFileList.GetFile( n ));
3313             TransferableDataHelper aData( pHlp );
3314 
3315             if( SwTransferable::PasteFileName( aData, rSh, SotClipboardFormatId::SIMPLE_FILE, nAct,
3316                                             pPt, SotExchangeActionFlags::NONE, nullptr ))
3317             {
3318                 if( bLink )
3319                 {
3320                     sFlyNm = rSh.GetFlyName();
3321                     SwTransferable::SetSelInShell( rSh, false, pPt );
3322                 }
3323                 bRet = true;
3324             }
3325         }
3326         if( !sFlyNm.isEmpty() )
3327             rSh.GotoFly( sFlyNm );
3328     }
3329     else if( bMsg )
3330     {
3331         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
3332                                                   VclMessageType::Info, VclButtonsType::Ok,
3333                                                   SwResId(STR_CLPBRD_FORMAT_ERROR)));
3334         xBox->run();
3335     }
3336     return bRet;
3337 }
3338 
CheckForURLOrLNKFile(const TransferableDataHelper & rData,OUString & rFileName,OUString * pTitle)3339 bool SwTransferable::CheckForURLOrLNKFile( const TransferableDataHelper& rData,
3340                                         OUString& rFileName, OUString* pTitle )
3341 {
3342     bool bIsURLFile = false;
3343     INetBookmark aBkmk;
3344     if( rData.GetINetBookmark( SotClipboardFormatId::SOLK, aBkmk ) )
3345     {
3346         rFileName = aBkmk.GetURL();
3347         if( pTitle )
3348             *pTitle = aBkmk.GetDescription();
3349         bIsURLFile = true;
3350     }
3351     else
3352     {
3353         if( rFileName.getLength()>4 && rFileName.endsWithIgnoreAsciiCase(".url") )
3354         {
3355             OSL_ENSURE( false, "how do we read today .URL - Files?" );
3356         }
3357     }
3358     return bIsURLFile;
3359 }
3360 
IsPasteSpecial(const SwWrtShell & rWrtShell,const TransferableDataHelper & rData)3361 bool SwTransferable::IsPasteSpecial( const SwWrtShell& rWrtShell,
3362                                      const TransferableDataHelper& rData )
3363 {
3364     // we can paste-special if there's an entry in the paste-special-format list
3365     SvxClipboardFormatItem aClipboardFormatItem(TypedWhichId<SvxClipboardFormatItem>(0));
3366     FillClipFormatItem( rWrtShell, rData, aClipboardFormatItem);
3367     return aClipboardFormatItem.Count() > 0;
3368 }
3369 
IsPasteOwnFormat(const TransferableDataHelper & rData)3370 bool SwTransferable::IsPasteOwnFormat( const TransferableDataHelper& rData )
3371 {
3372     return ( GetSwTransferable( rData ) != nullptr );
3373 }
3374 
PasteFormat(SwWrtShell & rSh,const TransferableDataHelper & rData,SotClipboardFormatId nFormat)3375 bool SwTransferable::PasteFormat( SwWrtShell& rSh,
3376                                     const TransferableDataHelper& rData,
3377                                     SotClipboardFormatId nFormat )
3378 {
3379     SwWait aWait( *rSh.GetView().GetDocShell(), false );
3380     bool bRet = false;
3381 
3382     SotClipboardFormatId nPrivateFormat = SotClipboardFormatId::PRIVATE;
3383     SwTransferable *pClipboard = GetSwTransferable( rData );
3384     if( pClipboard &&
3385         ((TransferBufferType::Document|TransferBufferType::Graphic|TransferBufferType::Ole) & pClipboard->m_eBufferType ))
3386         nPrivateFormat = SotClipboardFormatId::EMBED_SOURCE;
3387 
3388     if( pClipboard && nPrivateFormat == nFormat )
3389         bRet = pClipboard->PrivatePaste( rSh );
3390     else if( rData.HasFormat( nFormat ) )
3391     {
3392         uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
3393         sal_uInt8       nEventAction;
3394         SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
3395         sal_uInt16      nSourceOptions =
3396                     (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
3397                        SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
3398                        SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
3399                        SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
3400                                         ? EXCHG_IN_ACTION_COPY
3401                                         : EXCHG_IN_ACTION_MOVE);
3402         SotExchangeActionFlags nActionFlags;
3403         sal_uInt8      nAction = SotExchange::GetExchangeAction(
3404                                     rData.GetDataFlavorExVector(),
3405                                     nDestination,
3406                                     nSourceOptions,             /* ?? */
3407                                     EXCHG_IN_ACTION_DEFAULT,    /* ?? */
3408                                     nFormat, nEventAction, nFormat,
3409                                     lcl_getTransferPointer ( xTransferable ),
3410                                     &nActionFlags );
3411 
3412         if( EXCHG_INOUT_ACTION_NONE != nAction )
3413             bRet = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
3414                                                 nDestination, true, false );
3415     }
3416     return bRet;
3417 }
3418 
TestAllowedFormat(const TransferableDataHelper & rData,SotClipboardFormatId nFormat,SotExchangeDest nDestination)3419 bool SwTransferable::TestAllowedFormat( const TransferableDataHelper& rData,
3420                                         SotClipboardFormatId nFormat, SotExchangeDest nDestination )
3421 {
3422     sal_uInt8 nAction = EXCHG_INOUT_ACTION_NONE;
3423     if( rData.HasFormat( nFormat )) {
3424         uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
3425         sal_uInt8 nEventAction;
3426         nAction = SotExchange::GetExchangeAction(
3427                         rData.GetDataFlavorExVector(),
3428                         nDestination, EXCHG_IN_ACTION_COPY,
3429                         EXCHG_IN_ACTION_COPY, nFormat,
3430                         nEventAction, nFormat,
3431                         lcl_getTransferPointer ( xTransferable ) );
3432     }
3433     return EXCHG_INOUT_ACTION_NONE != nAction;
3434 }
3435 
3436 /**
3437  * the list of formats which will be offered to the user in the 'Paste
3438  * Special...' dialog and the paste button menu
3439  */
3440 static SotClipboardFormatId aPasteSpecialIds[] =
3441 {
3442     SotClipboardFormatId::HTML,
3443     SotClipboardFormatId::HTML_SIMPLE,
3444     SotClipboardFormatId::HTML_NO_COMMENT,
3445     SotClipboardFormatId::RTF,
3446     SotClipboardFormatId::RICHTEXT,
3447     SotClipboardFormatId::STRING,
3448     SotClipboardFormatId::SONLK,
3449     SotClipboardFormatId::NETSCAPE_BOOKMARK,
3450     SotClipboardFormatId::DRAWING,
3451     SotClipboardFormatId::SVXB,
3452     SotClipboardFormatId::GDIMETAFILE,
3453     SotClipboardFormatId::BITMAP,
3454     SotClipboardFormatId::SVIM,
3455     SotClipboardFormatId::FILEGRPDESCRIPTOR,
3456     SotClipboardFormatId::NONE
3457 };
3458 
PasteUnformatted(SwWrtShell & rSh,TransferableDataHelper & rData)3459 bool SwTransferable::PasteUnformatted( SwWrtShell& rSh, TransferableDataHelper& rData )
3460 {
3461     // Plain text == unformatted
3462     return SwTransferable::PasteFormat( rSh, rData, SotClipboardFormatId::STRING );
3463 }
3464 
PrePasteSpecial(const SwWrtShell & rSh,const TransferableDataHelper & rData,const VclPtr<SfxAbstractPasteDialog> & pDlg)3465 void SwTransferable::PrePasteSpecial( const SwWrtShell& rSh, const TransferableDataHelper& rData, const VclPtr<SfxAbstractPasteDialog>& pDlg )
3466 {
3467     DataFlavorExVector aFormats( rData.GetDataFlavorExVector() );
3468     TransferableObjectDescriptor aDesc;
3469 
3470     SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh );
3471 
3472     SwTransferable *pClipboard = GetSwTransferable( rData );
3473     if( pClipboard )
3474     {
3475         aDesc = pClipboard->m_aObjDesc;
3476         TranslateId pResId;
3477         if( pClipboard->m_eBufferType & TransferBufferType::Document )
3478             pResId = STR_PRIVATETEXT;
3479         else if( pClipboard->m_eBufferType & TransferBufferType::Graphic )
3480             pResId = STR_PRIVATEGRAPHIC;
3481         else if( pClipboard->m_eBufferType == TransferBufferType::Ole )
3482             pResId = STR_PRIVATEOLE;
3483 
3484         if (pResId)
3485         {
3486             if (STR_PRIVATEOLE == pResId || STR_PRIVATEGRAPHIC == pResId)
3487             {
3488                 // add SotClipboardFormatId::EMBED_SOURCE to the formats. This
3489                 // format display then the private format name.
3490                 DataFlavorEx aFlavorEx;
3491                 aFlavorEx.mnSotId = SotClipboardFormatId::EMBED_SOURCE;
3492                 aFormats.insert( aFormats.begin(), aFlavorEx );
3493             }
3494             pDlg->SetObjName( pClipboard->m_aObjDesc.maClassName,
3495                                 SwResId(pResId) );
3496             pDlg->Insert( SotClipboardFormatId::EMBED_SOURCE, OUString() );
3497         }
3498     }
3499     else
3500     {
3501         if( rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
3502         {
3503             (void)rData.GetTransferableObjectDescriptor(
3504                                 SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc );
3505         }
3506 
3507         if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::EMBED_SOURCE, nDest ))
3508             pDlg->Insert( SotClipboardFormatId::EMBED_SOURCE, OUString() );
3509         if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK_SOURCE, nDest ))
3510             pDlg->Insert( SotClipboardFormatId::LINK_SOURCE, OUString() );
3511     }
3512 
3513     if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK, nDest ))
3514         pDlg->Insert( SotClipboardFormatId::LINK, SwResId(STR_DDEFORMAT) );
3515 
3516     for( SotClipboardFormatId* pIds = aPasteSpecialIds; *pIds != SotClipboardFormatId::NONE; ++pIds )
3517         if( SwTransferable::TestAllowedFormat( rData, *pIds, nDest ))
3518             pDlg->Insert( *pIds, OUString() );
3519 }
3520 
FillClipFormatItem(const SwWrtShell & rSh,const TransferableDataHelper & rData,SvxClipboardFormatItem & rToFill)3521 void SwTransferable::FillClipFormatItem( const SwWrtShell& rSh,
3522                                 const TransferableDataHelper& rData,
3523                                 SvxClipboardFormatItem & rToFill )
3524 {
3525     SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh );
3526 
3527     SwTransferable *pClipboard = GetSwTransferable( rData );
3528     if( pClipboard )
3529     {
3530         TranslateId pResId;
3531         if( pClipboard->m_eBufferType & TransferBufferType::Document )
3532             pResId = STR_PRIVATETEXT;
3533         else if( pClipboard->m_eBufferType & TransferBufferType::Graphic )
3534             pResId = STR_PRIVATEGRAPHIC;
3535         else if( pClipboard->m_eBufferType == TransferBufferType::Ole )
3536             pResId = STR_PRIVATEOLE;
3537 
3538         if (pResId)
3539             rToFill.AddClipbrdFormat(SotClipboardFormatId::EMBED_SOURCE,
3540                                        SwResId(pResId));
3541     }
3542     else
3543     {
3544         TransferableObjectDescriptor aDesc;
3545         if (rData.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
3546         {
3547             (void)rData.GetTransferableObjectDescriptor(
3548                                 SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc);
3549         }
3550 
3551         if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::EMBED_SOURCE, nDest ))
3552             rToFill.AddClipbrdFormat( SotClipboardFormatId::EMBED_SOURCE,
3553                                             aDesc.maTypeName );
3554         if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK_SOURCE, nDest ))
3555             rToFill.AddClipbrdFormat( SotClipboardFormatId::LINK_SOURCE );
3556 
3557         SotClipboardFormatId nFormat;
3558         if ( rData.HasFormat(nFormat = SotClipboardFormatId::EMBED_SOURCE_OLE) || rData.HasFormat(nFormat = SotClipboardFormatId::EMBEDDED_OBJ_OLE) )
3559         {
3560             OUString sName,sSource;
3561             if ( SvPasteObjectHelper::GetEmbeddedName(rData,sName,sSource,nFormat) )
3562                 rToFill.AddClipbrdFormat( nFormat, sName );
3563         }
3564     }
3565 
3566     if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK, nDest ))
3567         rToFill.AddClipbrdFormat( SotClipboardFormatId::LINK, SwResId(STR_DDEFORMAT) );
3568 
3569     for( SotClipboardFormatId* pIds = aPasteSpecialIds; *pIds != SotClipboardFormatId::NONE; ++pIds )
3570         if( SwTransferable::TestAllowedFormat( rData, *pIds, nDest ))
3571             rToFill.AddClipbrdFormat(*pIds, OUString());
3572 }
3573 
SetDataForDragAndDrop(const Point & rSttPos)3574 void SwTransferable::SetDataForDragAndDrop( const Point& rSttPos )
3575 {
3576     if(!m_pWrtShell)
3577         return;
3578     OUString sGrfNm;
3579     const SelectionType nSelection = m_pWrtShell->GetSelectionType();
3580     if( SelectionType::Graphic == nSelection)
3581     {
3582         AddFormat( SotClipboardFormatId::SVXB );
3583         const Graphic* pGrf = m_pWrtShell->GetGraphic();
3584         if ( pGrf && pGrf->IsSupportedGraphic() )
3585         {
3586             AddFormat( SotClipboardFormatId::GDIMETAFILE );
3587             AddFormat( SotClipboardFormatId::PNG );
3588             AddFormat( SotClipboardFormatId::BITMAP );
3589         }
3590         m_eBufferType = TransferBufferType::Graphic;
3591         m_pWrtShell->GetGrfNms( &sGrfNm, nullptr );
3592     }
3593     else if( SelectionType::Ole == nSelection )
3594     {
3595         AddFormat( SotClipboardFormatId::EMBED_SOURCE );
3596         PrepareOLE( m_aObjDesc );
3597         AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
3598         AddFormat( SotClipboardFormatId::GDIMETAFILE );
3599         m_eBufferType = TransferBufferType::Ole;
3600     }
3601     //Is there anything to provide anyway?
3602     else if ( m_pWrtShell->IsSelection() || m_pWrtShell->IsFrameSelected() ||
3603               m_pWrtShell->IsObjSelected() )
3604     {
3605         if( m_pWrtShell->IsObjSelected() )
3606             m_eBufferType = TransferBufferType::Drawing;
3607         else
3608         {
3609             m_eBufferType = TransferBufferType::Document;
3610             if( SwWrtShell::NO_WORD !=
3611                 m_pWrtShell->IntelligentCut( nSelection, false ))
3612                 m_eBufferType = TransferBufferType::DocumentWord | m_eBufferType;
3613         }
3614 
3615         if( nSelection & SelectionType::TableCell )
3616             m_eBufferType = TransferBufferType::Table | m_eBufferType;
3617 
3618         AddFormat( SotClipboardFormatId::EMBED_SOURCE );
3619 
3620         //put RTF ahead of the OLE's Metafile for less loss
3621         if( !m_pWrtShell->IsObjSelected() )
3622         {
3623             AddFormat( SotClipboardFormatId::RTF );
3624             AddFormat( SotClipboardFormatId::RICHTEXT );
3625             AddFormat( SotClipboardFormatId::HTML );
3626         }
3627         if( m_pWrtShell->IsSelection() )
3628             AddFormat( SotClipboardFormatId::STRING );
3629 
3630         if( nSelection & ( SelectionType::DrawObject | SelectionType::DbForm ))
3631         {
3632             AddFormat( SotClipboardFormatId::DRAWING );
3633             if ( nSelection & SelectionType::DrawObject )
3634             {
3635                 AddFormat( SotClipboardFormatId::GDIMETAFILE );
3636                 AddFormat( SotClipboardFormatId::PNG );
3637                 AddFormat( SotClipboardFormatId::BITMAP );
3638             }
3639             m_eBufferType = TransferBufferType::Graphic | m_eBufferType;
3640 
3641             // is it a URL-Button ?
3642             OUString sURL;
3643             OUString sDesc;
3644             if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
3645             {
3646                 AddFormat( SotClipboardFormatId::STRING );
3647                 AddFormat( SotClipboardFormatId::SOLK );
3648                 AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
3649                 AddFormat( SotClipboardFormatId::FILECONTENT );
3650                 AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
3651                 AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
3652                 m_eBufferType = TransferBufferType::InetField | m_eBufferType;
3653             }
3654         }
3655 
3656         //ObjectDescriptor was already filled from the old DocShell.
3657         //Now adjust it. Thus in GetData the first query can still
3658         //be answered with delayed rendering.
3659         m_aObjDesc.maDragStartPos = rSttPos;
3660         m_aObjDesc.maSize = constOleSize100mm;
3661 
3662         PrepareOLE( m_aObjDesc );
3663         AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
3664     }
3665     else if( nSelection & SelectionType::Text && !m_pWrtShell->HasMark() )
3666     {
3667         // is only one field - selected?
3668         SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
3669         Point aPos( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY());
3670 
3671         if( m_pWrtShell->GetContentAtPos( aPos, aContentAtPos ) )
3672         {
3673             AddFormat( SotClipboardFormatId::STRING );
3674             AddFormat( SotClipboardFormatId::SOLK );
3675             AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
3676             AddFormat( SotClipboardFormatId::FILECONTENT );
3677             AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
3678             AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
3679             m_eBufferType = TransferBufferType::InetField;
3680         }
3681     }
3682 
3683     if( !m_pWrtShell->IsFrameSelected() )
3684         return;
3685 
3686     SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
3687     m_pWrtShell->GetFlyFrameAttr( aSet );
3688     const SwFormatURL& rURL = aSet.Get( RES_URL );
3689     if( rURL.GetMap() )
3690     {
3691         m_pImageMap.reset( new ImageMap( *rURL.GetMap() ) );
3692         AddFormat( SotClipboardFormatId::SVIM );
3693     }
3694     else if( !rURL.GetURL().isEmpty() )
3695     {
3696         m_pTargetURL.reset(new INetImage( sGrfNm, rURL.GetURL(),
3697                                     rURL.GetTargetFrameName() ));
3698         AddFormat( SotClipboardFormatId::INET_IMAGE );
3699     }
3700 }
3701 
StartDrag(vcl::Window * pWin,const Point & rPos)3702 void SwTransferable::StartDrag( vcl::Window* pWin, const Point& rPos )
3703 {
3704     if(!m_pWrtShell)
3705         return;
3706     m_bOldIdle = m_pWrtShell->GetViewOptions()->IsIdle();
3707     m_bCleanUp = true;
3708 
3709     m_pWrtShell->GetViewOptions()->SetIdle( false );
3710 
3711     if( m_pWrtShell->IsSelFrameMode() )
3712         m_pWrtShell->ShowCursor();
3713 
3714     SW_MOD()->m_pDragDrop = this;
3715 
3716     SetDataForDragAndDrop( rPos );
3717 
3718     sal_Int8 nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
3719     SwDocShell* pDShell = m_pWrtShell->GetView().GetDocShell();
3720     if( ( pDShell && pDShell->IsReadOnly() ) || m_pWrtShell->HasReadonlySel() )
3721         nDragOptions &= ~DND_ACTION_MOVE;
3722 
3723     TransferableHelper::StartDrag( pWin, nDragOptions );
3724 }
3725 
DragFinished(sal_Int8 nAction)3726 void SwTransferable::DragFinished( sal_Int8 nAction )
3727 {
3728     //And the last finishing work so that all statuses are right
3729     if( DND_ACTION_MOVE == nAction  )
3730     {
3731         if( m_bCleanUp )
3732         {
3733             //It was dropped outside of Writer. We still have to
3734             //delete.
3735 
3736             m_pWrtShell->StartAllAction();
3737             m_pWrtShell->StartUndo( SwUndoId::UI_DRAG_AND_MOVE );
3738             if ( m_pWrtShell->IsTableMode() )
3739                 m_pWrtShell->DeleteTableSel();
3740             else
3741             {
3742                 if ( !(m_pWrtShell->IsSelFrameMode() || m_pWrtShell->IsObjSelected()) )
3743                     //SmartCut, take one of the blanks along
3744                     m_pWrtShell->IntelligentCut( m_pWrtShell->GetSelectionType() );
3745                 m_pWrtShell->DelRight();
3746             }
3747             m_pWrtShell->EndUndo( SwUndoId::UI_DRAG_AND_MOVE );
3748             m_pWrtShell->EndAllAction();
3749         }
3750         else
3751         {
3752             const SelectionType nSelection = m_pWrtShell->GetSelectionType();
3753             if( ( SelectionType::Frame | SelectionType::Graphic |
3754                  SelectionType::Ole | SelectionType::DrawObject ) & nSelection )
3755             {
3756                 m_pWrtShell->EnterSelFrameMode();
3757             }
3758         }
3759     }
3760     m_pWrtShell->GetView().GetEditWin().DragFinished();
3761 
3762     if( m_pWrtShell->IsSelFrameMode() )
3763         m_pWrtShell->HideCursor();
3764     else
3765         m_pWrtShell->ShowCursor();
3766 
3767     m_pWrtShell->GetViewOptions()->SetIdle( m_bOldIdle );
3768 }
3769 
3770 namespace
3771 {
3772 
lcl_checkClassification(SwDoc * pSourceDoc,SwDoc * pDestinationDoc)3773 bool lcl_checkClassification(SwDoc* pSourceDoc, SwDoc* pDestinationDoc)
3774 {
3775     if (!pSourceDoc || !pDestinationDoc)
3776         return true;
3777 
3778     SwDocShell* pSourceShell = pSourceDoc->GetDocShell();
3779     SwDocShell* pDestinationShell = pDestinationDoc->GetDocShell();
3780     if (!pSourceShell || !pDestinationShell)
3781         return true;
3782 
3783     SfxClassificationCheckPasteResult eResult = SfxClassificationHelper::CheckPaste(pSourceShell->getDocProperties(), pDestinationShell->getDocProperties());
3784     return SfxClassificationHelper::ShowPasteInfo(eResult);
3785 }
3786 
3787 }
3788 
PrivatePaste(SwWrtShell & rShell,SwPasteContext * pContext,PasteTableType ePasteTable)3789 bool SwTransferable::PrivatePaste(SwWrtShell& rShell, SwPasteContext* pContext, PasteTableType ePasteTable)
3790 {
3791     // first, ask for the SelectionType, then action-bracketing !!!!
3792     // (otherwise it's not pasted into a TableSelection!!!)
3793     OSL_ENSURE( !rShell.ActionPend(), "Paste must never have an ActionPend" );
3794     if ( !m_pClpDocFac )
3795         return false; // the return value of the SwFEShell::Paste also is bool!
3796 
3797     const SelectionType nSelection = rShell.GetSelectionType();
3798 
3799     SwTrnsfrActionAndUndo aAction( &rShell );
3800 
3801     bool bKillPaMs = false;
3802 
3803     //Delete selected content, not at table-selection and table in Clipboard, and don't delete hovering graphics.
3804     if( rShell.HasSelection() && !( nSelection & SelectionType::TableCell) && !( nSelection & SelectionType::DrawObject))
3805     {
3806         if (!(nSelection & SelectionType::NumberList))
3807         {
3808             bKillPaMs = true;
3809             rShell.SetRetainSelection( true );
3810         }
3811         if (pContext)
3812             pContext->forget();
3813         rShell.DelRight();
3814         if (pContext)
3815             pContext->remember();
3816         // when a Fly was selected, a valid cursor position has to be found now
3817         // (parked Cursor!)
3818         if( ( SelectionType::Frame | SelectionType::Graphic |
3819             SelectionType::Ole | SelectionType::DrawObject |
3820             SelectionType::DbForm ) & nSelection )
3821         {
3822             // position the cursor again
3823             Point aPt( rShell.GetCharRect().Pos() );
3824             rShell.SwCursorShell::SetCursor( aPt, true );
3825         }
3826         if (!(nSelection & SelectionType::NumberList))
3827         {
3828             rShell.SetRetainSelection( false );
3829         }
3830     }
3831     if ( nSelection & SelectionType::DrawObject) //unselect hovering graphics
3832     {
3833         rShell.ResetSelect(nullptr,false);
3834     }
3835 
3836     bool bInWrd = false, bEndWrd = false, bSttWrd = false,
3837          bSmart(TransferBufferType::DocumentWord & m_eBufferType);
3838     if( bSmart )
3839     {
3840             // Why not for other Scripts? If TransferBufferType::DocumentWord is set, we have a word
3841             // in the buffer, word in this context means 'something with spaces at beginning
3842             // and end'. In this case we definitely want these spaces to be inserted here.
3843             bInWrd = rShell.IsInWord();
3844             bEndWrd = rShell.IsEndWrd();
3845             bSmart = bInWrd || bEndWrd;
3846             if( bSmart )
3847             {
3848                 bSttWrd = rShell.IsStartWord();
3849                 if (!bSttWrd && (bInWrd || bEndWrd))
3850                     rShell.SwEditShell::Insert(' ');
3851             }
3852     }
3853 
3854     bool bRet = true;
3855     // m_pWrtShell is nullptr when the source document is closed already.
3856     if (!m_pWrtShell || lcl_checkClassification(m_pWrtShell->GetDoc(), rShell.GetDoc()))
3857         bRet = rShell.Paste(m_pClpDocFac->GetDoc(), ePasteTable == PasteTableType::PASTE_TABLE);
3858 
3859     if( bKillPaMs )
3860         rShell.KillPams();
3861 
3862     // If Smart Paste then insert blank
3863     if( bRet && bSmart && ((bInWrd && !bEndWrd )|| bSttWrd) )
3864         rShell.SwEditShell::Insert(' ');
3865 
3866     return bRet;
3867 }
3868 
PrivateDrop(SwWrtShell & rSh,const Point & rDragPt,bool bMove,bool bIsXSelection)3869 bool SwTransferable::PrivateDrop( SwWrtShell& rSh, const Point& rDragPt,
3870                                 bool bMove, bool bIsXSelection )
3871 {
3872     int cWord    = 0;
3873     bool bInWrd  = false;
3874     bool bEndWrd = false;
3875     bool bSttWrd = false;
3876     bool bSttPara = false;
3877     bool bTableSel = false;
3878     bool bTableMove = false;
3879     bool bFrameSel = false;
3880 
3881     SwWrtShell& rSrcSh = *GetShell();
3882 
3883     rSh.UnSetVisibleCursor();
3884 
3885     if( TransferBufferType::InetField == m_eBufferType )
3886     {
3887         if( rSh.GetFormatFromObj( rDragPt ) )
3888         {
3889             INetBookmark aTmp;
3890             if( (TransferBufferType::InetField & m_eBufferType) && m_oBookmark )
3891                 aTmp = *m_oBookmark;
3892 
3893             // select target graphic
3894             if( rSh.SelectObj( rDragPt ) )
3895             {
3896                 rSh.HideCursor();
3897                 rSh.EnterSelFrameMode( &rDragPt );
3898                 g_bFrameDrag = true;
3899             }
3900 
3901             const SelectionType nSelection = rSh.GetSelectionType();
3902 
3903             // not yet consider Draw objects
3904             if( SelectionType::Graphic & nSelection )
3905             {
3906                 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3907                 rSh.GetFlyFrameAttr( aSet );
3908                 SwFormatURL aURL( aSet.Get( RES_URL ) );
3909                 aURL.SetURL( aTmp.GetURL(), false );
3910                 aSet.Put( aURL );
3911                 rSh.SetFlyFrameAttr( aSet );
3912                 return true;
3913             }
3914 
3915             if( SelectionType::DrawObject & nSelection )
3916             {
3917                 rSh.LeaveSelFrameMode();
3918                 rSh.UnSelectFrame();
3919                 rSh.ShowCursor();
3920                 g_bFrameDrag = false;
3921             }
3922         }
3923     }
3924 
3925     if( &rSh != &rSrcSh && (SelectionType::Graphic & rSh.GetSelectionType()) &&
3926         TransferBufferType::Graphic == m_eBufferType )
3927     {
3928         // ReRead the graphic
3929         OUString sGrfNm;
3930         OUString sFltNm;
3931         rSrcSh.GetGrfNms( &sGrfNm, &sFltNm );
3932         rSh.ReRead( sGrfNm, sFltNm, rSrcSh.GetGraphic() );
3933         return true;
3934     }
3935 
3936     //not in selections or selected frames
3937     if( rSh.TestCurrPam( rDragPt ) ||
3938         ( rSh.IsSelFrameMode() && rSh.IsInsideSelectedObj( rDragPt )) )
3939         return false;
3940 
3941     if( rSrcSh.IsTableMode() )
3942     {
3943         bTableSel = true;
3944         const SelectionType nSelection = rSrcSh.GetSelectionType();
3945         // at enhanced table row/column selection or wholly selected tables,
3946         // paste rows above or columns before, and in the case of moving, remove the selection
3947         // (limit only to the single document case temporarily)
3948         if( rSrcSh.GetDoc() == rSh.GetDoc() &&
3949                 ( (( SelectionType::TableRow | SelectionType::TableCol) & nSelection ) || rSrcSh.HasWholeTabSelection() ) )
3950         {
3951             bool bTableCol(SelectionType::TableCol & nSelection);
3952 
3953             ::sw::mark::IMark* pMarkMoveFrom = bMove
3954                     ? rSh.SetBookmark(
3955                                     vcl::KeyCode(),
3956                                     OUString(),
3957                                     IDocumentMarkAccess::MarkType::UNO_BOOKMARK )
3958                     : nullptr;
3959 
3960             // row count and direction of the table selection:
3961             // up to down, if the cursor is there in its last table row
3962             const SwSelBoxes& rBoxes = rSrcSh.GetTableCursor()->GetSelectedBoxes();
3963             const SwTableNode* pTableNd = rSh.IsCursorInTable();
3964             if (!pTableNd)
3965             {
3966                 SAL_WARN("sw", "presumably this case can't arise in practice");
3967                 return false;
3968             }
3969             const SwTableLines& rLines = pTableNd->GetTable().GetTabLines();
3970             const SwStartNode& rDelPos = rBoxes.back()
3971                     ? *rBoxes.front()->GetSttNd()
3972                     : *pTableNd->GetStartNode();
3973 
3974             // count selected rows or columns
3975             sal_Int32 nSelRowOrCols = 0;
3976             if ( rBoxes.back() )
3977             {
3978                 if ( bTableCol )
3979                 {
3980                     // selected column count is the count of the cells
3981                     // in the first row of the selection
3982                     auto nLine = rLines.GetPos( rBoxes.front()->GetUpper() );
3983                     for (auto pBox : rBoxes)
3984                     {
3985                         // cell is in the next row
3986                         if ( nLine != rLines.GetPos( pBox->GetUpper() ) )
3987                             break;
3988                         ++nSelRowOrCols;
3989                     }
3990                 }
3991                 else
3992                 {
3993                    // selected row count is the difference of the row number of the
3994                    // first and the last cell of the selection
3995                    nSelRowOrCols = rLines.GetPos( rBoxes.back()->GetUpper() ) -
3996                                    rLines.GetPos( rBoxes.front()->GetUpper() ) + 1;
3997                 }
3998             }
3999 
4000             bool bSelUpToDown = rBoxes.back() && rBoxes.back()->GetUpper() ==
4001                            rSh.GetCursor()->GetPointNode().GetTableBox()->GetUpper();
4002 
4003             SwUndoId eUndoId = bMove ? SwUndoId::UI_DRAG_AND_MOVE : SwUndoId::UI_DRAG_AND_COPY;
4004 
4005             SwRewriter aRewriter;
4006 
4007             aRewriter.AddRule(UndoArg1, rSrcSh.GetSelDescr());
4008 
4009             if(rSrcSh.GetDoc() != rSh.GetDoc())
4010                 rSrcSh.StartUndo( eUndoId, &aRewriter );
4011             rSh.StartUndo( eUndoId, &aRewriter );
4012 
4013             rSh.StartAction();
4014             rSrcSh.StartAction();
4015 
4016             SfxDispatcher* pDispatch = rSrcSh.GetView().GetViewFrame().GetDispatcher();
4017             pDispatch->Execute(SID_COPY, SfxCallMode::SYNCHRON);
4018 
4019             rSrcSh.Push(); // save selection for later restoration
4020             rSh.EnterStdMode();
4021             rSh.SwCursorShell::SetCursor(rDragPt, false);
4022 
4023             bool bPasteIntoTable = rSh.GetCursor()->GetPointNode().GetTableBox() != nullptr;
4024 
4025             // store cursor
4026             ::sw::mark::IMark* pMark = rSh.SetBookmark(
4027                                     vcl::KeyCode(),
4028                                     OUString(),
4029                                     IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
4030 
4031             // paste rows above/columns before
4032             pDispatch->Execute(bTableCol ? FN_TABLE_PASTE_COL_BEFORE : FN_TABLE_PASTE_ROW_BEFORE, SfxCallMode::SYNCHRON);
4033 
4034             // go to the previously inserted table rows and set them to tracked insertion, if needed
4035             bool bNeedTrack = !bTableCol && rSh.getIDocumentRedlineAccess().IsRedlineOn();
4036 
4037             // restore cursor position
4038             if (bNeedTrack && pMark != nullptr)
4039                 rSh.GotoMark( pMark );
4040 
4041             if ( !bNeedTrack && !bPasteIntoTable )
4042             {
4043                 rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // restore selection...
4044 
4045                 // delete source rows/columns
4046                 if (bMove)
4047                     pDispatch->Execute(bTableCol
4048                         ? FN_TABLE_DELETE_COL
4049                         : FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
4050             }
4051             else
4052             {
4053                 const SwTableBox* pBoxStt = rSh.GetCursor()->GetPointNode().GetTableBox();
4054                 SwTableLine* pLine = pBoxStt ? const_cast<SwTableLine*>( pBoxStt->GetUpper()): nullptr;
4055 
4056                 for (sal_Int32 nDeleted = 0; bNeedTrack && nDeleted < nSelRowOrCols;)
4057                 {
4058                     // move up text cursor (note: "true" is important for the layout level)
4059                     if ( !rSh.Up(false) )
4060                         break;
4061 
4062                     const SwTableBox* pBox = rSh.GetCursor()->GetPointNode().GetTableBox();
4063 
4064                     if ( !pBox )
4065                         break;
4066 
4067                     // Up() reaches a new row
4068                     if ( pBox->GetUpper() != pLine )
4069                     {
4070                         //rSh.SelTableRow();
4071                         SvxPrintItem aTracked(RES_PRINT, false);
4072                         rSh.GetDoc()->SetRowNotTracked( *rSh.GetCursor(), aTracked );
4073                         ++nDeleted;
4074                         pLine = const_cast<SwTableLine*>(pBox->GetUpper());
4075                     }
4076                 }
4077 
4078                 rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // restore selection...
4079 
4080                 // delete source rows/columns
4081                 if (bMove)
4082                 {
4083                     // restore cursor position
4084                     if (pMarkMoveFrom != nullptr)
4085                     {
4086                         rSh.GotoMark( pMarkMoveFrom );
4087                         rSh.getIDocumentMarkAccess()->deleteMark( pMarkMoveFrom );
4088                     }
4089 
4090                     // tracked table row moving: set original rows as tracked deletion,
4091                     // otherwise delete original rows/columns (tracking column deletion
4092                     // and insertion is not supported yet)
4093                     if ( !bTableCol && bNeedTrack )
4094                     {
4095                         pLine = nullptr;
4096 
4097                         for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols;)
4098                         {
4099                             const SwTableBox* pBox = rSh.GetCursor()->GetPointNode().GetTableBox();
4100 
4101                             if ( !pBox )
4102                                 break;
4103 
4104                             if ( pBox->GetUpper() != pLine )
4105                             {
4106                                 pLine = const_cast<SwTableLine*>(pBox->GetUpper());
4107                                 pDispatch->Execute(FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
4108                                 ++nDeleted;
4109                             }
4110 
4111                             bool bMoved = false;
4112                             if (bSelUpToDown)
4113                                 bMoved = rSh.Up(false);
4114                             else
4115                                 bMoved = rSh.Down(false);
4116                             if (!bMoved)
4117                                 break;
4118                         }
4119                     }
4120                     else
4121                     {
4122                         // set cursor in the first cell of the original selection
4123                         rSh.GetCursor()->DeleteMark();
4124                         rSh.GetCursor()->GetPoint()->Assign( rDelPos.GetIndex() + 1);
4125 
4126                         for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols; ++nDeleted)
4127                         {
4128                             pDispatch->Execute(bTableCol
4129                                 ? FN_TABLE_DELETE_COL
4130                                 : FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
4131                         }
4132                     }
4133                 }
4134             }
4135 
4136             // restore cursor position
4137             if (pMark != nullptr)
4138             {
4139                 rSh.GotoMark( pMark );
4140                 rSh.getIDocumentMarkAccess()->deleteMark( pMark );
4141             }
4142 
4143             rSh.DestroyCursor();
4144             rSh.EndUndo();
4145             rSh.EndAction();
4146             rSh.EndAction();
4147             return true;
4148         }
4149 
4150         if ( bMove && rSrcSh.HasWholeTabSelection() )
4151             bTableMove = true;
4152     }
4153     else if( rSrcSh.IsSelFrameMode() || rSrcSh.IsObjSelected() )
4154     {
4155         // don't move position-protected objects!
4156         if( bMove && rSrcSh.IsSelObjProtected( FlyProtectFlags::Pos ) != FlyProtectFlags::NONE )
4157             return false;
4158 
4159         bFrameSel = true;
4160     }
4161 
4162     const SelectionType nSel = rSrcSh.GetSelectionType();
4163 
4164     SwUndoId eUndoId = bMove ? SwUndoId::UI_DRAG_AND_MOVE : SwUndoId::UI_DRAG_AND_COPY;
4165 
4166     SwRewriter aRewriter;
4167 
4168     aRewriter.AddRule(UndoArg1, rSrcSh.GetSelDescr());
4169 
4170     if(rSrcSh.GetDoc() != rSh.GetDoc())
4171         rSrcSh.StartUndo( eUndoId, &aRewriter );
4172     rSh.StartUndo( eUndoId, &aRewriter );
4173 
4174     rSh.StartAction();
4175     rSrcSh.StartAction();
4176 
4177     if( &rSrcSh != &rSh )
4178     {
4179         rSh.EnterStdMode();
4180         rSh.SwCursorShell::SetCursor( rDragPt, true );
4181         cWord = rSrcSh.IntelligentCut( nSel, false );
4182     }
4183     else if( !bTableSel && !bFrameSel )
4184     {
4185         if( !rSh.IsAddMode() )
4186         {
4187             // #i87233#
4188             if ( rSh.IsBlockMode() )
4189             {
4190                 // preserve order of cursors for block mode
4191                 rSh.GoPrevCursor();
4192             }
4193 
4194             rSh.SwCursorShell::CreateCursor();
4195         }
4196         rSh.SwCursorShell::SetCursor( rDragPt, true, false );
4197         rSh.GoPrevCursor();
4198         cWord = rSh.IntelligentCut( rSh.GetSelectionType(), false );
4199         rSh.GoNextCursor();
4200     }
4201 
4202     bInWrd  = rSh.IsInWord();
4203     bEndWrd = rSh.IsEndWrd();
4204     bSttWrd = !bEndWrd && rSh.IsStartWord();
4205     bSttPara= rSh.IsSttPara();
4206 
4207     Point aSttPt( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY() );
4208 
4209     // at first, select InetFields!
4210     if( TransferBufferType::InetField == m_eBufferType )
4211     {
4212         if( &rSrcSh == &rSh )
4213         {
4214             rSh.GoPrevCursor();
4215             rSh.SwCursorShell::SetCursor( aSttPt, true );
4216             rSh.SelectTextAttr( RES_TXTATR_INETFMT );
4217             if( rSh.TestCurrPam( rDragPt ) )
4218             {
4219                 // don't copy/move inside of yourself
4220                 rSh.DestroyCursor();
4221                 rSh.EndUndo();
4222                 rSh.EndAction();
4223                 rSh.EndAction();
4224                 return false;
4225             }
4226             rSh.GoNextCursor();
4227         }
4228         else
4229         {
4230             rSrcSh.SwCursorShell::SetCursor( aSttPt, true );
4231             rSrcSh.SelectTextAttr( RES_TXTATR_INETFMT );
4232         }
4233 
4234         // is there a URL attribute at the insert point? Then replace that,
4235         // so simply put up a selection?
4236         rSh.DelINetAttrWithText();
4237         g_bDDINetAttr = true;
4238     }
4239 
4240     if ( rSrcSh.IsSelFrameMode() )
4241     {
4242         //Hack: fool the special treatment
4243         aSttPt = rSrcSh.GetObjRect().Pos();
4244     }
4245 
4246     bool bRet = rSrcSh.SwFEShell::Copy(rSh, aSttPt, rDragPt, bMove,
4247                                        !bIsXSelection);
4248 
4249     if( !bIsXSelection )
4250     {
4251         rSrcSh.Push();
4252         if ( bRet && bMove && !bFrameSel )
4253         {
4254             if ( bTableSel )
4255             {
4256                 /* delete table contents not cells */
4257                 rSrcSh.Delete(false);
4258             }
4259             else
4260             {
4261                 //SmartCut, take one of the blanks along.
4262                 rSh.SwCursorShell::DestroyCursor();
4263                 if ( cWord == SwWrtShell::WORD_SPACE_BEFORE )
4264                     rSh.ExtendSelection( false );
4265                 else if ( cWord == SwWrtShell::WORD_SPACE_AFTER )
4266                     rSh.ExtendSelection();
4267                 rSrcSh.DelRight();
4268             }
4269         }
4270         rSrcSh.KillPams();
4271         rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
4272 
4273         /* after dragging a table selection inside one shell
4274             set cursor to the drop position. */
4275         if( &rSh == &rSrcSh && ( bTableSel || rSh.IsBlockMode() ) )
4276         {
4277             rSrcSh.CalcLayout();
4278             rSrcSh.SwCursorShell::SetCursor(rDragPt);
4279             rSrcSh.GetCursor()->SetMark();
4280         }
4281     }
4282 
4283     if( bRet && !bTableSel && !bFrameSel )
4284     {
4285         if( (bInWrd || bEndWrd) &&
4286             (cWord == SwWrtShell::WORD_SPACE_AFTER ||
4287                 cWord == SwWrtShell::WORD_SPACE_BEFORE) )
4288         {
4289             if ( bSttWrd || (bInWrd && !bEndWrd))
4290                 rSh.SwEditShell::Insert(' ', bIsXSelection);
4291             if ( !bSttWrd || (bInWrd && !bSttPara) )
4292             {
4293                 rSh.SwapPam();
4294                 if ( !bSttWrd )
4295                     rSh.SwEditShell::Insert(' ', bIsXSelection);
4296                 rSh.SwapPam();
4297             }
4298         }
4299 
4300         if( bIsXSelection )
4301         {
4302             if( &rSrcSh == &rSh && !rSh.IsAddMode() )
4303             {
4304                 rSh.SwCursorShell::DestroyCursor();
4305                 rSh.GoPrevCursor();
4306             }
4307             else
4308             {
4309                 rSh.SwapPam();
4310                 rSh.SwCursorShell::ClearMark();
4311             }
4312         }
4313         else
4314         {
4315             if( rSh.IsAddMode() )
4316                 rSh.SwCursorShell::CreateCursor();
4317             else
4318             {
4319                 // turn on selection mode
4320                 rSh.SttSelect();
4321                 rSh.EndSelect();
4322             }
4323         }
4324     }
4325     else if ( bRet && bTableMove )
4326     {
4327         SfxDispatcher* pDispatch = rSrcSh.GetView().GetViewFrame().GetDispatcher();
4328         pDispatch->Execute(FN_TABLE_DELETE_TABLE, SfxCallMode::SYNCHRON);
4329     }
4330 
4331     if( bRet && bMove && bFrameSel )
4332         rSrcSh.LeaveSelFrameMode();
4333 
4334     if( rSrcSh.GetDoc() != rSh.GetDoc() )
4335         rSrcSh.EndUndo();
4336     rSh.EndUndo();
4337 
4338         // put the shell in the right state
4339     if( &rSrcSh != &rSh && ( rSh.IsFrameSelected() || rSh.IsObjSelected() ))
4340         rSh.EnterSelFrameMode();
4341 
4342     rSrcSh.EndAction();
4343     rSh.EndAction();
4344     return true;
4345 }
4346 
4347 // Interfaces for Selection
CreateSelection(SwWrtShell & rSh,const SwFrameShell * _pCreatorView)4348 void SwTransferable::CreateSelection( SwWrtShell& rSh,
4349                                       const SwFrameShell * _pCreatorView )
4350 {
4351     SwModule *pMod = SW_MOD();
4352     rtl::Reference<SwTransferable> pNew = new SwTransferable( rSh );
4353 
4354     pNew->m_pCreatorView = _pCreatorView;
4355 
4356     pMod->m_pXSelection = pNew.get();
4357     pNew->CopyToPrimarySelection();
4358 }
4359 
ClearSelection(const SwWrtShell & rSh,const SwFrameShell * _pCreatorView)4360 void SwTransferable::ClearSelection( const SwWrtShell& rSh,
4361                                      const SwFrameShell * _pCreatorView)
4362 {
4363     SwModule *pMod = SW_MOD();
4364     if( pMod->m_pXSelection &&
4365         ((!pMod->m_pXSelection->m_pWrtShell) || (pMod->m_pXSelection->m_pWrtShell == &rSh)) &&
4366         (!_pCreatorView || (pMod->m_pXSelection->m_pCreatorView == _pCreatorView)) )
4367     {
4368         TransferableHelper::ClearPrimarySelection();
4369     }
4370 }
4371 
GetSwTransferable(const TransferableDataHelper & rData)4372 SwTransferable* SwTransferable::GetSwTransferable( const TransferableDataHelper& rData )
4373 {
4374     return dynamic_cast<SwTransferable*>(rData.GetTransferable().get());
4375 }
4376 
SwTransferDdeLink(SwTransferable & rTrans,SwWrtShell & rSh)4377 SwTransferDdeLink::SwTransferDdeLink( SwTransferable& rTrans, SwWrtShell& rSh )
4378     : m_rTransfer(rTrans)
4379     , m_pDocShell(nullptr)
4380     , m_nOldTimeOut(0)
4381     , m_bDelBookmark(false)
4382     , m_bInDisconnect(false)
4383 {
4384     // we only end up here with table- or text selection
4385     if( SelectionType::TableCell & rSh.GetSelectionType() )
4386     {
4387         SwFrameFormat* pFormat = rSh.GetTableFormat();
4388         if( pFormat )
4389             m_sName = pFormat->GetName();
4390     }
4391     else
4392     {
4393         // creating a temp. bookmark without undo
4394         bool bUndo = rSh.DoesUndo();
4395         rSh.DoUndo( false );
4396         bool bIsModified = rSh.IsModified();
4397 
4398         ::sw::mark::IMark* pMark = rSh.SetBookmark(
4399             vcl::KeyCode(),
4400             OUString(),
4401             IDocumentMarkAccess::MarkType::DDE_BOOKMARK);
4402         if(pMark)
4403         {
4404             m_sName = pMark->GetName();
4405             m_bDelBookmark = true;
4406             if( !bIsModified )
4407                 rSh.ResetModified();
4408         }
4409         else
4410             m_sName.clear();
4411         rSh.DoUndo( bUndo );
4412     }
4413 
4414     if( m_sName.isEmpty() ||
4415         nullptr == ( m_pDocShell = rSh.GetDoc()->GetDocShell() ))
4416         return;
4417 
4418     // then we create our "server" and connect to it
4419     m_xRefObj = m_pDocShell->DdeCreateLinkSource( m_sName );
4420     if( m_xRefObj.is() )
4421     {
4422         m_xRefObj->AddConnectAdvise( this );
4423         m_xRefObj->AddDataAdvise( this,
4424                         OUString(),
4425                         ADVISEMODE_NODATA | ADVISEMODE_ONLYONCE );
4426         m_nOldTimeOut = m_xRefObj->GetUpdateTimeout();
4427         m_xRefObj->SetUpdateTimeout( 0 );
4428     }
4429 }
4430 
~SwTransferDdeLink()4431 SwTransferDdeLink::~SwTransferDdeLink()
4432 {
4433     if( m_xRefObj.is() )
4434         Disconnect( true );
4435 }
4436 
DataChanged(const OUString &,const uno::Any &)4437 ::sfx2::SvBaseLink::UpdateResult SwTransferDdeLink::DataChanged( const OUString& ,
4438                                     const uno::Any& )
4439 {
4440     // well, that's it with the link
4441     if( !m_bInDisconnect )
4442     {
4443         if( FindDocShell() && m_pDocShell->GetView() )
4444             m_rTransfer.RemoveDDELinkFormat( m_pDocShell->GetView()->GetEditWin() );
4445         Disconnect( false );
4446     }
4447     return SUCCESS;
4448 }
4449 
WriteData(SvStream & rStrm)4450 bool SwTransferDdeLink::WriteData( SvStream& rStrm )
4451 {
4452     if( !m_xRefObj.is() || !FindDocShell() )
4453         return false;
4454 
4455     TransferableDataHelper::WriteDDELink(rStrm, Application::GetAppName(),
4456                                          m_pDocShell->GetTitle(SFX_TITLE_FULLNAME), m_sName);
4457 
4458     IDocumentMarkAccess* const pMarkAccess = m_pDocShell->GetDoc()->getIDocumentMarkAccess();
4459     IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->findMark(m_sName);
4460     if(ppMark != pMarkAccess->getAllMarksEnd()
4461         && IDocumentMarkAccess::GetType(**ppMark) != IDocumentMarkAccess::MarkType::BOOKMARK)
4462     {
4463         // the mark is still a DdeBookmark
4464         // we replace it with a Bookmark, so it will get saved etc.
4465         ::sw::mark::IMark* const pMark = *ppMark;
4466         ::sfx2::SvLinkSource* p = m_xRefObj.get();
4467         SwServerObject& rServerObject = dynamic_cast<SwServerObject&>(*p);
4468 
4469         // collecting state of old mark
4470         SwPaM aPaM(pMark->GetMarkStart());
4471         *aPaM.GetPoint() = pMark->GetMarkStart();
4472         if(pMark->IsExpanded())
4473         {
4474             aPaM.SetMark();
4475             *aPaM.GetMark() = pMark->GetMarkEnd();
4476         }
4477         OUString sMarkName = pMark->GetName();
4478 
4479         // remove mark
4480         rServerObject.SetNoServer(); // this removes the connection between SwServerObject and mark
4481         // N.B. ppMark was not loaded from file and cannot have xml:id
4482         pMarkAccess->deleteMark(ppMark, false);
4483 
4484         // recreate as Bookmark
4485         ::sw::mark::IMark* const pNewMark = pMarkAccess->makeMark(
4486             aPaM,
4487             sMarkName,
4488             IDocumentMarkAccess::MarkType::BOOKMARK,
4489             ::sw::mark::InsertMode::New);
4490         rServerObject.SetDdeBookmark(*pNewMark);
4491     }
4492 
4493     m_bDelBookmark = false;
4494     return true;
4495 }
4496 
Disconnect(bool bRemoveDataAdvise)4497 void SwTransferDdeLink::Disconnect( bool bRemoveDataAdvise )
4498 {
4499     //  don't accept DataChanged anymore, when already in Disconnect!
4500     //  (DTOR from Bookmark sends a DataChanged!)
4501     bool bOldDisconnect = m_bInDisconnect;
4502     m_bInDisconnect = true;
4503 
4504     // destroy the unused bookmark again (without Undo!)?
4505     if( m_bDelBookmark && m_xRefObj.is() && FindDocShell() )
4506     {
4507         SwDoc* pDoc = m_pDocShell->GetDoc();
4508         ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
4509 
4510         // #i58448#
4511         Link<bool,void> aSavedOle2Link( pDoc->GetOle2Link() );
4512         pDoc->SetOle2Link( Link<bool,void>() );
4513 
4514         bool bIsModified = pDoc->getIDocumentState().IsModified();
4515 
4516         IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
4517         pMarkAccess->deleteMark(pMarkAccess->findMark(m_sName), false);
4518 
4519         if( !bIsModified )
4520             pDoc->getIDocumentState().ResetModified();
4521         // #i58448#
4522         pDoc->SetOle2Link( aSavedOle2Link );
4523 
4524         m_bDelBookmark = false;
4525     }
4526 
4527     if( m_xRefObj.is() )
4528     {
4529         m_xRefObj->SetUpdateTimeout( m_nOldTimeOut );
4530         m_xRefObj->RemoveConnectAdvise( this );
4531         if( bRemoveDataAdvise )
4532             // in a DataChanged the SelectionObject must NEVER be deleted
4533             // is already handled by the base class
4534             // (ADVISEMODE_ONLYONCE!!!!)
4535             // but always in normal Disconnect!
4536             m_xRefObj->RemoveAllDataAdvise( this );
4537         m_xRefObj.clear();
4538     }
4539     m_bInDisconnect = bOldDisconnect;
4540 }
4541 
FindDocShell()4542 bool SwTransferDdeLink::FindDocShell()
4543 {
4544     SfxObjectShell* pTmpSh = SfxObjectShell::GetFirst( checkSfxObjectShell<SwDocShell> );
4545     while( pTmpSh )
4546     {
4547         if( pTmpSh == m_pDocShell )       // that's what we want to have
4548         {
4549             if( m_pDocShell->GetDoc() )
4550                 return true;
4551             break;      // the Doc is not there anymore, so leave!
4552         }
4553         pTmpSh = SfxObjectShell::GetNext( *pTmpSh, checkSfxObjectShell<SwDocShell> );
4554     }
4555 
4556     m_pDocShell = nullptr;
4557     return false;
4558 }
4559 
Closed()4560 void SwTransferDdeLink::Closed()
4561 {
4562     if( !m_bInDisconnect && m_xRefObj.is() )
4563     {
4564         m_xRefObj->RemoveAllDataAdvise( this );
4565         m_xRefObj->RemoveConnectAdvise( this );
4566         m_xRefObj.clear();
4567     }
4568 }
4569 
4570 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4571