android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / uibase / dochdl / swdtflvr.cxx
bloba885f28cf6ed590e8e05316be594e72015b254db
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <com/sun/star/embed/XTransactedObject.hpp>
23 #include <com/sun/star/embed/Aspects.hpp>
24 #include <com/sun/star/embed/XEmbedObjectClipboardCreator.hpp>
25 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
26 #include <com/sun/star/embed/MSOLEObjectSystemCreator.hpp>
27 #include <com/sun/star/text/XPasteListener.hpp>
29 #include <svtools/embedtransfer.hxx>
30 #include <svtools/insdlg.hxx>
31 #include <unotools/tempfile.hxx>
32 #include <comphelper/fileformat.h>
33 #include <comphelper/processfactory.hxx>
34 #include <comphelper/propertyvalue.hxx>
35 #include <comphelper/servicehelper.hxx>
36 #include <comphelper/storagehelper.hxx>
37 #include <comphelper/string.hxx>
38 #include <o3tl/deleter.hxx>
39 #include <unotools/ucbstreamhelper.hxx>
40 #include <sot/filelist.hxx>
41 #include <svx/svxdlg.hxx>
42 #include <toolkit/helper/vclunohelper.hxx>
43 #include <osl/endian.h>
44 #include <sfx2/linkmgr.hxx>
45 #include <tools/urlobj.hxx>
46 #include <vcl/weld.hxx>
47 #include <sfx2/dispatch.hxx>
48 #include <sfx2/viewfrm.hxx>
49 #include <svl/stritem.hxx>
50 #include <vcl/imap.hxx>
51 #include <sot/storage.hxx>
52 #include <vcl/graph.hxx>
53 #include <svl/urihelper.hxx>
54 #include <svx/svdmodel.hxx>
55 #include <svx/xmlexchg.hxx>
56 #include <svx/dbaexchange.hxx>
57 #include <svx/clipfmtitem.hxx>
58 #include <sfx2/mieclip.hxx>
59 #include <svl/urlbmk.hxx>
60 #include <vcl/inetimg.hxx>
61 #include <svx/fmview.hxx>
62 #include <sfx2/docfilt.hxx>
63 #include <vcl/imapobj.hxx>
64 #include <sfx2/docfile.hxx>
65 #include <unotools/transliterationwrapper.hxx>
66 #include <unotools/streamwrap.hxx>
67 #include <vcl/graphicfilter.hxx>
69 #ifdef _WIN32
70 #include <prewin.h>
71 #include <postwin.h>
72 #include <o3tl/char16_t2wchar_t.hxx>
73 #include <osl/file.hxx>
74 #endif
76 #include <svx/unomodel.hxx>
77 #include <fmturl.hxx>
78 #include <fmtinfmt.hxx>
79 #include <swdtflvr.hxx>
80 #include <shellio.hxx>
81 #include <ddefld.hxx>
82 #include <doc.hxx>
83 #include <IDocumentUndoRedo.hxx>
84 #include <IDocumentDrawModelAccess.hxx>
85 #include <IDocumentFieldsAccess.hxx>
86 #include <IDocumentRedlineAccess.hxx>
87 #include <IDocumentState.hxx>
88 #include <IMark.hxx>
89 #include <section.hxx>
90 #include <ndtxt.hxx>
91 #include <edtdd.hxx>
92 #include <edtwin.hxx>
93 #include <navicont.hxx>
94 #include <swcont.hxx>
95 #include <wrtsh.hxx>
96 #include <swmodule.hxx>
97 #include <view.hxx>
98 #include <docsh.hxx>
99 #include <wdocsh.hxx>
100 #include <fldbas.hxx>
101 #include <swundo.hxx>
102 #include <pam.hxx>
103 #include <ndole.hxx>
104 #include <swwait.hxx>
105 #include <viewopt.hxx>
106 #include <SwCapObjType.hxx>
107 #include <cmdid.h>
108 #include <strings.hrc>
109 #include <svx/svditer.hxx>
110 #include <editeng/eeitem.hxx>
111 #include <editeng/fhgtitem.hxx>
112 #include <editeng/prntitem.hxx>
113 #include <svx/svdpage.hxx>
114 #include <avmedia/mediawindow.hxx>
115 #include <swcrsr.hxx>
116 #include <SwRewriter.hxx>
117 #include <vcl/svapp.hxx>
118 #include <swserv.hxx>
119 #include <fmtmeta.hxx>
120 #include <itabenum.hxx>
121 #include <iodetect.hxx>
122 #include <unotextrange.hxx>
123 #include <unoframe.hxx>
124 #include <txatbase.hxx>
125 #include <vcl/uitest/logger.hxx>
126 #include <vcl/uitest/eventdescription.hxx>
128 #include <vcl/GraphicNativeTransform.hxx>
129 #include <vcl/GraphicNativeMetadata.hxx>
130 #include <vcl/TypeSerializer.hxx>
131 #include <comphelper/lok.hxx>
132 #include <sfx2/classificationhelper.hxx>
133 #include <sfx2/sfxdlg.hxx>
134 #include <comphelper/classids.hxx>
135 #include <osl/diagnose.h>
137 #include <memory>
139 /* default (A4 format) width of 210mm - 2 * border size (border on both sides) */
140 constexpr tools::Long constOleWidthInMm = 210 - 2 * lMinBorderInMm;
142 constexpr Size constOleSize100mm(
143 constOleWidthInMm * 100, // convert from mm to 100mm
144 3000 // 3 cm
147 constexpr Size constOleSizeTwip = o3tl::convert(constOleSize100mm, o3tl::Length::mm100, o3tl::Length::twip);
149 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_DRAWMODEL = 0x00000001;
150 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_HTML = 0x00000002;
151 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_RTF = 0x00000004;
152 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_STRING = 0x00000008;
153 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_SWOLE = 0x00000010;
154 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_DDE = 0x00000020;
155 constexpr sal_uInt32 SWTRANSFER_OBJECTTYPE_RICHTEXT = 0x00000040;
157 using namespace ::svx;
158 using namespace ::com::sun::star;
159 using namespace ::com::sun::star::uno;
160 using namespace ::com::sun::star::datatransfer;
161 namespace {
163 void collectUIInformation(const OUString& rAction, const OUString& aParameters)
165 EventDescription aDescription;
166 aDescription.aAction = rAction;
167 aDescription.aParameters = {{"parameters", aParameters}};
168 aDescription.aID = "writer_edit";
169 aDescription.aKeyWord = "SwEditWinUIObject";
170 aDescription.aParent = "MainWindow";
171 UITestLogger::getInstance().logEvent(aDescription);
176 namespace {
178 class SwTransferDdeLink : public ::sfx2::SvBaseLink
180 OUString m_sName;
181 ::sfx2::SvLinkSourceRef m_xRefObj;
182 SwTransferable& m_rTransfer;
183 SwDocShell* m_pDocShell;
184 sal_uLong m_nOldTimeOut;
185 bool m_bDelBookmark : 1;
186 bool m_bInDisconnect : 1;
188 bool FindDocShell();
190 using sfx2::SvBaseLink::Disconnect;
192 protected:
193 virtual ~SwTransferDdeLink() override;
195 public:
196 SwTransferDdeLink( SwTransferable& rTrans, SwWrtShell& rSh );
198 virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(
199 const OUString& rMimeType, const css::uno::Any & rValue ) override;
200 virtual void Closed() override;
202 bool WriteData( SvStream& rStrm );
204 void Disconnect( bool bRemoveDataAdvise );
209 /// Tracks the boundaries of pasted content and notifies listeners.
210 class SwPasteContext
212 public:
213 SwPasteContext(SwWrtShell& rWrtShell);
214 ~SwPasteContext();
216 void remember();
217 void forget();
219 private:
220 SwWrtShell& m_rWrtShell;
221 std::optional<SwPaM> m_oPaM;
222 sal_Int32 m_nStartContent = 0;
225 namespace {
227 // helper class for Action and Undo enclosing
228 class SwTrnsfrActionAndUndo
230 SwWrtShell *pSh;
231 public:
232 SwTrnsfrActionAndUndo( SwWrtShell *pS, bool bDelSel = false, SwPasteContext* pContext = nullptr)
233 : pSh( pS )
235 pSh->StartUndo( SwUndoId::PASTE_CLIPBOARD );
236 if( bDelSel )
238 if (pContext)
239 pContext->forget();
240 pSh->DelRight();
241 if (pContext)
242 pContext->remember();
244 pSh->StartAllAction();
246 ~SwTrnsfrActionAndUndo() COVERITY_NOEXCEPT_FALSE
248 pSh->EndUndo();
249 pSh->EndAllAction();
255 SwTransferable::SwTransferable( SwWrtShell& rSh )
256 : m_pWrtShell( &rSh ),
257 m_pCreatorView( nullptr ),
258 m_pOrigGraphic( nullptr ),
259 m_eBufferType( TransferBufferType::NONE ),
260 m_bOldIdle(false),
261 m_bCleanUp(false)
263 rSh.GetView().AddTransferable(*this);
264 SwDocShell* pDShell = rSh.GetDoc()->GetDocShell();
265 if( !pDShell )
266 return;
268 pDShell->FillTransferableObjectDescriptor( m_aObjDesc );
269 if( pDShell->GetMedium() )
271 const INetURLObject& rURLObj = pDShell->GetMedium()->GetURLObject();
272 m_aObjDesc.maDisplayName = URIHelper::removePassword(
273 rURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
274 INetURLObject::EncodeMechanism::WasEncoded,
275 INetURLObject::DecodeMechanism::Unambiguous );
278 PrepareOLE( m_aObjDesc );
281 SwTransferable::~SwTransferable()
283 SolarMutexGuard aSolarGuard;
285 // the DDELink still needs the WrtShell!
286 if( m_xDdeLink.is() )
288 static_cast<SwTransferDdeLink*>( m_xDdeLink.get() )->Disconnect( true );
289 m_xDdeLink.clear();
292 m_pWrtShell = nullptr;
294 // release reference to the document so that aDocShellRef will delete
295 // it (if aDocShellRef is set). Otherwise, the OLE nodes keep references
296 // to their sub-storage when the storage is already dead.
297 m_pClpDocFac.reset();
299 // first close, then the Ref. can be cleared as well, so that
300 // the DocShell really gets deleted!
301 if( m_aDocShellRef.Is() )
303 SfxObjectShell * pObj = m_aDocShellRef;
304 SwDocShell* pDocSh = static_cast<SwDocShell*>(pObj);
305 pDocSh->DoClose();
307 m_aDocShellRef.Clear();
309 SwModule* pMod = SW_MOD();
310 if(pMod)
312 if ( pMod->m_pDragDrop == this )
313 pMod->m_pDragDrop = nullptr;
314 else if ( pMod->m_pXSelection == this )
315 pMod->m_pXSelection = nullptr;
318 m_eBufferType = TransferBufferType::NONE;
321 static SwDoc& lcl_GetDoc(SwDocFac & rDocFac)
323 SwDoc& rDoc = rDocFac.GetDoc();
324 rDoc.SetClipBoard( true );
325 return rDoc;
328 void SwTransferable::ObjectReleased()
330 SwModule *pMod = SW_MOD();
331 if (!pMod)
332 return;
333 if( this == pMod->m_pDragDrop )
334 pMod->m_pDragDrop = nullptr;
335 else if( this == pMod->m_pXSelection )
336 pMod->m_pXSelection = nullptr;
339 void SwTransferable::AddSupportedFormats()
341 // only need if we are the current XSelection Object
342 SwModule *pMod = SW_MOD();
343 if( this == pMod->m_pXSelection || comphelper::LibreOfficeKit::isActive())
345 SetDataForDragAndDrop( Point( 0,0) );
349 void SwTransferable::InitOle( SfxObjectShell* pDoc )
351 //set OleVisArea. Upper left corner of the page and size of
352 //RealSize in Twips.
353 const Size aSz(constOleSizeTwip);
354 SwRect aVis( Point( DOCUMENTBORDER, DOCUMENTBORDER ), aSz );
355 pDoc->SetVisArea( aVis.SVRect() );
358 uno::Reference < embed::XEmbeddedObject > SwTransferable::FindOLEObj( sal_Int64& nAspect ) const
360 uno::Reference < embed::XEmbeddedObject > xObj;
361 if( m_pClpDocFac )
363 SwIterator<SwContentNode,SwFormatColl> aIter( *m_pClpDocFac->GetDoc().GetDfltGrfFormatColl() );
364 for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
365 if( SwNodeType::Ole == pNd->GetNodeType() )
367 xObj = static_cast<SwOLENode*>(pNd)->GetOLEObj().GetOleRef();
368 nAspect = static_cast<SwOLENode*>(pNd)->GetAspect();
369 break;
372 return xObj;
375 const Graphic* SwTransferable::FindOLEReplacementGraphic() const
377 if( m_pClpDocFac )
379 SwIterator<SwContentNode,SwFormatColl> aIter( *m_pClpDocFac->GetDoc().GetDfltGrfFormatColl() );
380 for( SwContentNode* pNd = aIter.First(); pNd; pNd = aIter.Next() )
381 if( SwNodeType::Ole == pNd->GetNodeType() )
383 return static_cast<SwOLENode*>(pNd)->GetGraphic();
387 return nullptr;
390 void SwTransferable::RemoveDDELinkFormat(vcl::Window& rWin)
392 RemoveFormat( SotClipboardFormatId::LINK );
393 CopyToClipboard(&rWin);
396 namespace
398 //Resolves: fdo#40717 surely when we create a clipboard document we should
399 //overwrite the clipboard documents styles and settings with that of the
400 //source, so that we can WYSIWYG paste. If we want that the destinations
401 //styles are used over the source styles, that's a matter of the
402 //destination paste code to handle, not the source paste code.
403 void lclOverWriteDoc(SwWrtShell &rSrcWrtShell, SwDoc &rDest)
405 const SwDoc &rSrc = *rSrcWrtShell.GetDoc();
407 rDest.ReplaceCompatibilityOptions(rSrc);
408 rDest.ReplaceDefaults(rSrc);
410 //It would probably make most sense here to only insert the styles used
411 //by the selection, e.g. apply SwDoc::IsUsed on styles ?
412 rDest.ReplaceStyles(rSrc, false);
414 rSrcWrtShell.Copy(rDest);
416 rDest.GetMetaFieldManager().copyDocumentProperties(rSrc);
419 void lclCheckAndPerformRotation(Graphic& aGraphic)
421 GraphicNativeMetadata aMetadata;
422 if ( !aMetadata.read(aGraphic) )
423 return;
425 Degree10 aRotation = aMetadata.getRotation();
426 if (aRotation)
428 GraphicNativeTransform aTransform( aGraphic );
429 aTransform.rotate( aRotation );
434 sal_Bool SAL_CALL SwTransferable::isComplex()
436 sal_Int32 nTextLength = 0;
437 SwNodes& aNodes = m_pWrtShell->GetDoc()->GetNodes();
438 for (SwPaM& rPaM : m_pWrtShell->GetCursor()->GetRingContainer())
440 for (SwNodeOffset nIndex = rPaM.GetMark()->GetNodeIndex();
441 nIndex <= rPaM.GetPoint()->GetNodeIndex(); ++nIndex)
443 SwNode& rNd = *aNodes[nIndex];
445 SwTextNode* pTextNode = rNd.GetTextNode();
446 if (pTextNode)
448 if (pTextNode->HasHints())
450 for (size_t nHint = 0; nHint < pTextNode->GetSwpHints().Count(); ++nHint)
452 SwTextAttr* pHint = pTextNode->GetSwpHints().Get(nHint);
453 if (pHint->Which() == RES_TXTATR_FLYCNT)
455 return true; // Complex
460 nTextLength += pTextNode->GetText().getLength();
461 if (nTextLength >= 1024 * 512)
462 return true; // Complex
467 if (m_pWrtShell->GetSelectionType() == SelectionType::DrawObject)
468 return true; // Complex
470 // Simple
471 return false;
474 bool SwTransferable::GetData( const DataFlavor& rFlavor, const OUString& rDestDoc )
476 SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
478 // we can only fulfil the request if
479 // 1) we have data for this format
480 // 2) we have either a clipboard document (pClpDocFac), or
481 // we have a SwWrtShell (so we can generate a new clipboard document)
482 if( !HasFormat( nFormat ) || ( m_pClpDocFac == nullptr && m_pWrtShell == nullptr ) )
483 return false;
485 if( !m_pClpDocFac )
487 SelectionType nSelectionType = m_pWrtShell->GetSelectionType();
489 // when pending we will not get the correct type, but SelectionType::Text
490 // as fallback. This *happens* during D&D, so we need to check if we are in
491 // the fallback and just try to get a graphic
492 const bool bPending(m_pWrtShell->ActionPend());
494 // SEL_GRF is from ContentType of editsh
495 if(bPending || ((SelectionType::Graphic | SelectionType::DrawObject | SelectionType::DbForm) & nSelectionType))
497 m_oClpGraphic.emplace();
498 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
499 m_pOrigGraphic = &*m_oClpGraphic;
500 m_oClpBitmap.emplace();
501 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
502 m_pOrigGraphic = &*m_oClpBitmap;
504 // is it a URL-Button ?
505 OUString sURL;
506 OUString sDesc;
507 if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
509 m_oBookmark.emplace( sURL, sDesc );
510 m_eBufferType = TransferBufferType::InetField;
514 m_pClpDocFac.reset(new SwDocFac);
515 SwDoc& rTmpDoc = lcl_GetDoc(*m_pClpDocFac);
517 rTmpDoc.getIDocumentFieldsAccess().LockExpFields(); // never update fields - leave text as it is
518 lclOverWriteDoc(*m_pWrtShell, rTmpDoc);
520 // in CORE a new one was created (OLE-objects copied!)
521 m_aDocShellRef = rTmpDoc.GetTmpDocShell();
522 if( m_aDocShellRef.Is() )
523 SwTransferable::InitOle( m_aDocShellRef );
524 rTmpDoc.SetTmpDocShell( nullptr );
526 if( nSelectionType & SelectionType::Text && !m_pWrtShell->HasMark() )
528 SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
530 Point aPos( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY());
532 bool bSelect = g_bExecuteDrag &&
533 m_pWrtShell->GetView().GetDocShell() &&
534 !m_pWrtShell->GetView().GetDocShell()->IsReadOnly();
535 if( m_pWrtShell->GetContentAtPos( aPos, aContentAtPos, bSelect ) )
537 m_oBookmark.emplace(
538 static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr)->GetValue(),
539 aContentAtPos.sStr );
540 m_eBufferType = TransferBufferType::InetField;
541 if( bSelect )
542 m_pWrtShell->SelectTextAttr( RES_TXTATR_INETFMT );
545 if( m_pWrtShell->IsFrameSelected() )
547 SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
548 m_pWrtShell->GetFlyFrameAttr( aSet );
549 const SwFormatURL& rURL = aSet.Get( RES_URL );
550 if( rURL.GetMap() )
551 m_pImageMap.reset(new ImageMap( *rURL.GetMap() ));
552 else if( !rURL.GetURL().isEmpty() )
553 m_pTargetURL.reset(new INetImage(OUString(), rURL.GetURL(),
554 rURL.GetTargetFrameName() ));
558 bool bOK = false;
559 if( TransferBufferType::Ole == m_eBufferType )
561 //TODO/MBA: testing - is this the "single OLE object" case?!
562 // get OLE-Object from ClipDoc and get the data from that.
563 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT; // will be set in the next statement
564 uno::Reference < embed::XEmbeddedObject > xObj = FindOLEObj( nAspect );
565 const Graphic* pOLEGraph = FindOLEReplacementGraphic();
566 if( xObj.is() )
568 TransferableDataHelper aD( new SvEmbedTransferHelper( xObj, pOLEGraph, nAspect ) );
569 uno::Any aAny = aD.GetAny(rFlavor, rDestDoc);
570 if( aAny.hasValue() )
571 bOK = SetAny( aAny );
574 // the following solution will be used in the case when the object can not generate the image
575 // TODO/LATER: in future the transferhelper must probably be created based on object and the replacement stream
576 // TODO: Block not required now, SvEmbedTransferHelper should be able to handle GDIMetaFile format
577 if ( nFormat == SotClipboardFormatId::GDIMETAFILE )
579 pOLEGraph = FindOLEReplacementGraphic();
580 if ( pOLEGraph )
581 bOK = SetGDIMetaFile( pOLEGraph->GetGDIMetaFile() );
584 else
586 switch( nFormat )
588 case SotClipboardFormatId::LINK:
589 if( m_xDdeLink.is() )
590 bOK = SetObject( m_xDdeLink.get(), SWTRANSFER_OBJECTTYPE_DDE, rFlavor );
591 break;
593 case SotClipboardFormatId::OBJECTDESCRIPTOR:
594 case SotClipboardFormatId::LINKSRCDESCRIPTOR:
595 bOK = SetTransferableObjectDescriptor( m_aObjDesc );
596 break;
598 case SotClipboardFormatId::DRAWING:
600 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
601 bOK = SetObject( rDoc.getIDocumentDrawModelAccess().GetDrawModel(),
602 SWTRANSFER_OBJECTTYPE_DRAWMODEL, rFlavor );
604 break;
606 case SotClipboardFormatId::STRING:
608 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
609 bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_STRING, rFlavor );
611 break;
612 case SotClipboardFormatId::RTF:
614 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
615 bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_RTF, rFlavor );
617 break;
618 case SotClipboardFormatId::RICHTEXT:
620 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
621 bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_RICHTEXT, rFlavor );
623 break;
625 case SotClipboardFormatId::HTML:
627 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
628 bOK = SetObject( &rDoc, SWTRANSFER_OBJECTTYPE_HTML, rFlavor );
630 break;
632 case SotClipboardFormatId::SVXB:
633 if( m_eBufferType & TransferBufferType::Graphic && m_pOrigGraphic )
634 bOK = SetGraphic( *m_pOrigGraphic );
635 break;
637 case SotClipboardFormatId::GDIMETAFILE:
638 if( m_eBufferType & TransferBufferType::Graphic )
639 bOK = SetGDIMetaFile( m_oClpGraphic->GetGDIMetaFile() );
640 break;
641 case SotClipboardFormatId::BITMAP:
642 case SotClipboardFormatId::PNG:
643 // Neither pClpBitmap nor pClpGraphic are necessarily set
644 if( (m_eBufferType & TransferBufferType::Graphic) && (m_oClpBitmap || m_oClpGraphic))
645 bOK = SetBitmapEx( (m_oClpBitmap ? m_oClpBitmap : m_oClpGraphic)->GetBitmapEx(), rFlavor );
646 break;
648 case SotClipboardFormatId::SVIM:
649 if( m_pImageMap )
650 bOK = SetImageMap( *m_pImageMap );
651 break;
653 case SotClipboardFormatId::INET_IMAGE:
654 if( m_pTargetURL )
655 bOK = SetINetImage( *m_pTargetURL, rFlavor );
656 break;
658 case SotClipboardFormatId::SOLK:
659 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
660 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
661 case SotClipboardFormatId::FILECONTENT:
662 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
663 case SotClipboardFormatId::SIMPLE_FILE:
664 if( (TransferBufferType::InetField & m_eBufferType) && m_oBookmark )
665 bOK = SetINetBookmark( *m_oBookmark, rFlavor );
666 break;
668 case SotClipboardFormatId::EMBED_SOURCE:
669 if( !m_aDocShellRef.Is() )
671 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
672 SwDocShell* pNewDocSh = new SwDocShell( rDoc,
673 SfxObjectCreateMode::EMBEDDED );
674 m_aDocShellRef = pNewDocSh;
675 m_aDocShellRef->DoInitNew();
676 SwTransferable::InitOle( m_aDocShellRef );
678 bOK = SetObject( &m_aDocShellRef, SWTRANSFER_OBJECTTYPE_SWOLE,
679 rFlavor );
680 break;
681 default: break;
684 return bOK;
687 bool SwTransferable::WriteObject( tools::SvRef<SotTempStream>& xStream,
688 void* pObject, sal_uInt32 nObjectType,
689 const DataFlavor& /*rFlavor*/ )
691 bool bRet = false;
692 WriterRef xWrt;
694 switch( nObjectType )
696 case SWTRANSFER_OBJECTTYPE_DRAWMODEL:
698 // don't change the sequence of commands
699 SdrModel *pModel = static_cast<SdrModel*>(pObject);
700 xStream->SetBufferSize( 16348 );
702 // for the changed pool defaults from drawing layer pool set those
703 // attributes as hard attributes to preserve them for saving
704 const SfxItemPool& rItemPool = pModel->GetItemPool();
705 const SvxFontHeightItem& rDefaultFontHeight = rItemPool.GetDefaultItem(EE_CHAR_FONTHEIGHT);
707 // SW should have no MasterPages
708 OSL_ENSURE(0 == pModel->GetMasterPageCount(), "SW with MasterPages (!)");
710 for(sal_uInt16 a(0); a < pModel->GetPageCount(); a++)
712 const SdrPage* pPage = pModel->GetPage(a);
713 SdrObjListIter aIter(pPage, SdrIterMode::DeepNoGroups);
715 while(aIter.IsMore())
717 SdrObject* pObj = aIter.Next();
718 const SvxFontHeightItem& rItem = pObj->GetMergedItem(EE_CHAR_FONTHEIGHT);
720 if(rItem.GetHeight() == rDefaultFontHeight.GetHeight())
722 pObj->SetMergedItem(rDefaultFontHeight);
728 uno::Reference<io::XOutputStream> xDocOut( new utl::OOutputStreamWrapper( *xStream ) );
729 SvxDrawingLayerExport( pModel, xDocOut );
732 bRet = ERRCODE_NONE == xStream->GetError();
734 break;
736 case SWTRANSFER_OBJECTTYPE_SWOLE:
738 SfxObjectShell* pEmbObj = static_cast<SfxObjectShell*>(pObject);
741 ::utl::TempFileFast aTempFile;
742 SvStream* pTempStream = aTempFile.GetStream(StreamMode::READWRITE);
743 uno::Reference< embed::XStorage > xWorkStore =
744 ::comphelper::OStorageHelper::GetStorageFromStream( new utl::OStreamWrapper(*pTempStream), embed::ElementModes::READWRITE );
746 // write document storage
747 pEmbObj->SetupStorage( xWorkStore, SOFFICE_FILEFORMAT_CURRENT, false );
748 // mba: no BaseURL for clipboard
749 SfxMedium aMedium( xWorkStore, OUString() );
750 pEmbObj->DoSaveObjectAs( aMedium, false );
751 pEmbObj->DoSaveCompleted();
753 uno::Reference< embed::XTransactedObject > xTransact( xWorkStore, uno::UNO_QUERY );
754 if ( xTransact.is() )
755 xTransact->commit();
757 xStream->SetBufferSize( 0xff00 );
758 xStream->WriteStream( *pTempStream );
760 xWorkStore->dispose();
761 xWorkStore.clear();
763 catch (const uno::Exception&)
767 bRet = ( xStream->GetError() == ERRCODE_NONE );
769 break;
771 case SWTRANSFER_OBJECTTYPE_DDE:
773 xStream->SetBufferSize( 1024 );
774 SwTransferDdeLink* pDdeLnk = static_cast<SwTransferDdeLink*>(pObject);
775 if( pDdeLnk->WriteData( *xStream ) )
777 bRet = ERRCODE_NONE == xStream->GetError();
780 break;
782 case SWTRANSFER_OBJECTTYPE_HTML:
784 // LOK is interested in getting images embedded for copy/paste support.
785 GetHTMLWriter( comphelper::LibreOfficeKit::isActive() ? OUString("EmbedImages;NoPrettyPrint") : OUString(), OUString(), xWrt );
786 break;
789 case SWTRANSFER_OBJECTTYPE_RTF:
790 case SWTRANSFER_OBJECTTYPE_RICHTEXT:
791 GetRTFWriter(std::u16string_view(), OUString(), xWrt);
792 break;
794 case SWTRANSFER_OBJECTTYPE_STRING:
795 GetASCWriter(std::u16string_view(), OUString(), xWrt);
796 if( xWrt.is() )
798 SwAsciiOptions aAOpt;
799 aAOpt.SetCharSet( RTL_TEXTENCODING_UTF8 );
800 xWrt->SetAsciiOptions( aAOpt );
802 // no start char for clipboard
803 xWrt->m_bUCS2_WithStartChar = false;
805 break;
806 default: break;
809 if( xWrt.is() )
811 SwDoc* pDoc = static_cast<SwDoc*>(pObject);
812 xWrt->m_bWriteClipboardDoc = true;
813 xWrt->m_bWriteOnlyFirstTable = bool(TransferBufferType::Table & m_eBufferType);
814 xWrt->SetShowProgress(false);
816 #if defined(DEBUGPASTE)
817 SvFileStream aPasteDebug(OUString(
818 "PASTEBUFFER.debug"), StreamMode::WRITE|StreamMode::TRUNC);
819 SwWriter aDbgWrt( aPasteDebug, *pDoc );
820 aDbgWrt.Write( xWrt );
821 #endif
823 SwWriter aWrt( *xStream, *pDoc );
824 if( ! aWrt.Write( xWrt ).IsError() )
826 xStream->WriteChar( '\0' ); // terminate with a zero
827 bRet = true;
831 return bRet;
834 int SwTransferable::Cut()
836 int nRet = Copy( true );
837 if( nRet )
838 DeleteSelection();
839 collectUIInformation("CUT", "parameter");
840 return nRet;
843 void SwTransferable::DeleteSelection()
845 if(!m_pWrtShell)
846 return;
847 // ask for type of selection before action-bracketing
848 const SelectionType nSelection = m_pWrtShell->GetSelectionType();
849 // cut rows or columns selected by enhanced table selection and wholly selected tables
850 bool bCutMode = ( SelectionType::TableCell & nSelection ) && ( (SelectionType::TableRow | SelectionType::TableCol) & nSelection ||
851 m_pWrtShell->HasWholeTabSelection() );
853 m_pWrtShell->StartUndo( SwUndoId::START );
854 if( bCutMode )
856 if( !(SelectionType::TableCol & nSelection) )
857 m_pWrtShell->DeleteTable();
858 else
860 SfxDispatcher* pDispatch = m_pWrtShell->GetView().GetViewFrame().GetDispatcher();
861 pDispatch->Execute(FN_TABLE_DELETE_COL, SfxCallMode::SYNCHRON);
864 else
866 if( ( SelectionType::Text | SelectionType::Table ) & nSelection )
867 m_pWrtShell->IntelligentCut( nSelection );
868 m_pWrtShell->DelRight();
870 m_pWrtShell->EndUndo( SwUndoId::END );
873 static void DeleteDDEMarks(SwDoc & rDest)
875 IDocumentMarkAccess *const pMarkAccess = rDest.getIDocumentMarkAccess();
876 std::vector< ::sw::mark::IMark* > vDdeMarks;
877 // find all DDE-Bookmarks
878 for (IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin();
879 ppMark != pMarkAccess->getAllMarksEnd();
880 ++ppMark)
882 if (IDocumentMarkAccess::MarkType::DDE_BOOKMARK == IDocumentMarkAccess::GetType(**ppMark))
884 vDdeMarks.push_back(*ppMark);
887 // remove all DDE-Bookmarks, they are invalid inside the clipdoc!
888 for (const auto& rpMark : vDdeMarks)
890 pMarkAccess->deleteMark(rpMark);
894 void SwTransferable::PrepareForCopyTextRange(SwPaM & rPaM)
896 std::optional<SwWait> oWait;
897 if (m_pWrtShell->ShouldWait())
899 oWait.emplace( *m_pWrtShell->GetView().GetDocShell(), true );
902 m_pClpDocFac.reset(new SwDocFac);
904 SwDoc& rDest(lcl_GetDoc(*m_pClpDocFac));
905 rDest.getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is
907 SwDoc const& rSrc(*m_pWrtShell->GetDoc());
908 assert(&rSrc == &rPaM.GetDoc());
910 rDest.ReplaceCompatibilityOptions(rSrc);
911 rDest.ReplaceDefaults(rSrc);
913 //It would probably make most sense here to only insert the styles used
914 //by the selection, e.g. apply SwDoc::IsUsed on styles ?
915 rDest.ReplaceStyles(rSrc, false);
917 // relevant bits of rSrcWrtShell.Copy(rDest);
918 rDest.GetIDocumentUndoRedo().DoUndo(false); // always false!
919 rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::DeleteRedlines );
921 SwNodeIndex const aIdx(rDest.GetNodes().GetEndOfContent(), -1);
922 SwContentNode *const pContentNode(aIdx.GetNode().GetContentNode());
923 SwPosition aPos(aIdx, pContentNode, pContentNode ? pContentNode->Len() : 0);
925 rSrc.getIDocumentContentOperations().CopyRange(rPaM, aPos, SwCopyFlags::CheckPosInFly);
927 rDest.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE );
929 rDest.GetMetaFieldManager().copyDocumentProperties(rSrc);
932 DeleteDDEMarks(rDest);
934 // a new one was created in core (OLE objects copied!)
935 m_aDocShellRef = rDest.GetTmpDocShell();
936 if (m_aDocShellRef.Is())
937 SwTransferable::InitOle( m_aDocShellRef );
938 rDest.SetTmpDocShell( nullptr );
940 // let's add some formats
941 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
942 AddFormat( SotClipboardFormatId::RTF );
943 #if HAVE_FEATURE_DESKTOP
944 AddFormat( SotClipboardFormatId::RICHTEXT );
945 AddFormat( SotClipboardFormatId::HTML );
946 #endif
947 AddFormat( SotClipboardFormatId::STRING );
950 int SwTransferable::PrepareForCopy( bool bIsCut )
952 int nRet = 1;
953 if(!m_pWrtShell)
954 return 0;
956 if ( m_pWrtShell->GetTableInsertMode() != SwTable::SEARCH_NONE )
957 m_pWrtShell->SetTableInsertMode( SwTable::SEARCH_NONE );
959 if ( m_pWrtShell->GetTableCopied() )
960 m_pWrtShell->SetTableCopied( false );
962 OUString sGrfNm;
963 const SelectionType nSelection = m_pWrtShell->GetSelectionType();
964 if( nSelection == SelectionType::Graphic )
966 m_oClpGraphic.emplace();
967 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
968 m_pOrigGraphic = &*m_oClpGraphic;
969 m_oClpBitmap.emplace();
970 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
971 m_pOrigGraphic = &*m_oClpBitmap;
973 m_pClpDocFac.reset(new SwDocFac);
974 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
975 m_pWrtShell->Copy(rDoc);
977 #if HAVE_FEATURE_DESKTOP
978 if (m_pOrigGraphic && !m_pOrigGraphic->GetBitmapEx().IsEmpty())
979 AddFormat( SotClipboardFormatId::SVXB );
980 #endif
982 PrepareOLE( m_aObjDesc );
983 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
985 const Graphic* pGrf = m_pWrtShell->GetGraphic();
986 if( pGrf && pGrf->IsSupportedGraphic() )
988 AddFormat( SotClipboardFormatId::PNG );
989 #if HAVE_FEATURE_DESKTOP
990 AddFormat( SotClipboardFormatId::GDIMETAFILE );
991 AddFormat( SotClipboardFormatId::BITMAP );
992 #endif
994 m_eBufferType = TransferBufferType::Graphic;
995 m_pWrtShell->GetGrfNms( &sGrfNm, nullptr );
997 else if ( nSelection == SelectionType::Ole )
999 m_pClpDocFac.reset(new SwDocFac);
1000 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
1001 m_aDocShellRef = new SwDocShell(rDoc, SfxObjectCreateMode::EMBEDDED);
1002 m_aDocShellRef->DoInitNew();
1003 m_pWrtShell->Copy(rDoc);
1005 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
1007 // --> OD #i98753#
1008 // set size of embedded object at the object description structure
1009 m_aObjDesc.maSize = o3tl::convert(m_pWrtShell->GetObjSize(), o3tl::Length::twip, o3tl::Length::mm100);
1011 // <--
1012 PrepareOLE( m_aObjDesc );
1014 #if HAVE_FEATURE_DESKTOP
1015 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
1016 AddFormat( SotClipboardFormatId::GDIMETAFILE );
1018 // Fetch the formats supported via embedtransferhelper as well
1019 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
1020 uno::Reference < embed::XEmbeddedObject > xObj = FindOLEObj( nAspect );
1021 const Graphic* pOLEGraph = FindOLEReplacementGraphic();
1022 if( xObj.is() )
1024 TransferableDataHelper aD( new SvEmbedTransferHelper( xObj, pOLEGraph, nAspect ) );
1025 if ( aD.GetTransferable().is() )
1027 DataFlavorExVector aVector( aD.GetDataFlavorExVector() );
1029 for( const auto& rItem : aVector )
1030 AddFormat( rItem );
1033 #endif
1034 m_eBufferType = TransferBufferType::Ole;
1036 // Is there anything to provide anyway?
1037 else if ( m_pWrtShell->IsSelection() || m_pWrtShell->IsFrameSelected() ||
1038 m_pWrtShell->IsObjSelected() )
1040 std::optional<SwWait> oWait;
1041 if( m_pWrtShell->ShouldWait() )
1042 oWait.emplace( *m_pWrtShell->GetView().GetDocShell(), true );
1044 m_pClpDocFac.reset(new SwDocFac);
1046 // create additional cursor so that equal treatment of keyboard
1047 // and mouse selection is possible.
1048 // In AddMode with keyboard selection, the new cursor is not created
1049 // before the cursor is moved after end of selection.
1050 if( m_pWrtShell->IsAddMode() && m_pWrtShell->SwCursorShell::HasSelection() )
1051 m_pWrtShell->CreateCursor();
1053 SwDoc& rTmpDoc = lcl_GetDoc(*m_pClpDocFac);
1055 rTmpDoc.getIDocumentFieldsAccess().LockExpFields(); // Never update fields - leave text as is
1056 lclOverWriteDoc(*m_pWrtShell, rTmpDoc);
1058 DeleteDDEMarks(rTmpDoc);
1060 // a new one was created in CORE (OLE objects copied!)
1061 m_aDocShellRef = rTmpDoc.GetTmpDocShell();
1062 if( m_aDocShellRef.Is() )
1063 SwTransferable::InitOle( m_aDocShellRef );
1064 rTmpDoc.SetTmpDocShell( nullptr );
1066 if( m_pWrtShell->IsObjSelected() )
1067 m_eBufferType = TransferBufferType::Drawing;
1068 else
1070 m_eBufferType = TransferBufferType::Document;
1071 if (m_pWrtShell->IntelligentCut(nSelection, false) != SwWrtShell::NO_WORD)
1072 m_eBufferType = TransferBufferType::DocumentWord | m_eBufferType;
1075 bool bDDELink = m_pWrtShell->IsSelection();
1076 if( nSelection & SelectionType::TableCell )
1078 m_eBufferType = TransferBufferType::Table | m_eBufferType;
1079 bDDELink = m_pWrtShell->HasWholeTabSelection();
1081 m_pWrtShell->SetTableCopied(true);
1083 if ( bIsCut && (SelectionType::TableRow | SelectionType::TableCol) & nSelection )
1084 m_pWrtShell->SetTableInsertMode( (SelectionType::TableRow & nSelection) ? SwTable::SEARCH_ROW : SwTable::SEARCH_COL );
1087 #if HAVE_FEATURE_DESKTOP
1088 //When someone needs it, we 'OLE' him something
1089 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
1090 #endif
1092 //put RTF ahead of the OLE's Metafile to have less loss
1093 if( !m_pWrtShell->IsObjSelected() )
1095 AddFormat( SotClipboardFormatId::RTF );
1096 #if HAVE_FEATURE_DESKTOP
1097 AddFormat( SotClipboardFormatId::RICHTEXT );
1098 AddFormat( SotClipboardFormatId::HTML );
1099 #endif
1101 if( m_pWrtShell->IsSelection() )
1102 AddFormat( SotClipboardFormatId::STRING );
1104 if( nSelection & ( SelectionType::DrawObject | SelectionType::DbForm ))
1106 AddFormat( SotClipboardFormatId::DRAWING );
1107 if ( nSelection & SelectionType::DrawObject )
1109 #if HAVE_FEATURE_DESKTOP
1110 AddFormat( SotClipboardFormatId::GDIMETAFILE );
1111 AddFormat( SotClipboardFormatId::BITMAP );
1112 #endif
1113 AddFormat( SotClipboardFormatId::PNG );
1115 m_eBufferType = static_cast<TransferBufferType>( TransferBufferType::Graphic | m_eBufferType );
1117 m_oClpGraphic.emplace();
1118 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::GDIMETAFILE, *m_oClpGraphic ))
1119 m_pOrigGraphic = &*m_oClpGraphic;
1120 m_oClpBitmap.emplace();
1121 if( !m_pWrtShell->GetDrawObjGraphic( SotClipboardFormatId::BITMAP, *m_oClpBitmap ))
1122 m_pOrigGraphic = &*m_oClpBitmap;
1124 // is it a URL-Button ?
1125 OUString sURL;
1126 OUString sDesc;
1127 if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
1129 AddFormat( SotClipboardFormatId::STRING );
1130 #if HAVE_FEATURE_DESKTOP
1131 AddFormat( SotClipboardFormatId::SOLK );
1132 AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
1133 AddFormat( SotClipboardFormatId::FILECONTENT );
1134 AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
1135 #endif
1136 AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
1137 m_eBufferType = TransferBufferType::InetField | m_eBufferType;
1138 nRet = 1;
1142 // at Cut, DDE-Link doesn't make sense!!
1143 SwDocShell* pDShell;
1144 if( !bIsCut && bDDELink &&
1145 nullptr != ( pDShell = m_pWrtShell->GetDoc()->GetDocShell()) &&
1146 SfxObjectCreateMode::STANDARD == pDShell->GetCreateMode() )
1148 #if HAVE_FEATURE_DESKTOP
1149 AddFormat( SotClipboardFormatId::LINK );
1150 #endif
1151 m_xDdeLink = new SwTransferDdeLink( *this, *m_pWrtShell );
1154 //ObjectDescriptor was already filly from the old DocShell.
1155 //Now adjust it. Thus in GetData the first query can still
1156 //be answered with delayed rendering.
1157 m_aObjDesc.maSize = constOleSize100mm;
1159 PrepareOLE( m_aObjDesc );
1160 #if HAVE_FEATURE_DESKTOP
1161 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
1162 #endif
1164 else
1165 nRet = 0;
1167 if( m_pWrtShell->IsFrameSelected() )
1169 SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
1170 m_pWrtShell->GetFlyFrameAttr( aSet );
1171 const SwFormatURL& rURL = aSet.Get( RES_URL );
1172 if( rURL.GetMap() )
1174 m_pImageMap.reset( new ImageMap( *rURL.GetMap() ) );
1175 AddFormat( SotClipboardFormatId::SVIM );
1177 else if( !rURL.GetURL().isEmpty() )
1179 m_pTargetURL.reset(new INetImage( sGrfNm, rURL.GetURL(),
1180 rURL.GetTargetFrameName() ));
1181 AddFormat( SotClipboardFormatId::INET_IMAGE );
1185 return nRet;
1188 int SwTransferable::Copy( bool bIsCut )
1190 if (m_pWrtShell->GetView().GetObjectShell()->isContentExtractionLocked())
1191 return 0;
1193 int nRet = PrepareForCopy( bIsCut );
1194 if ( nRet )
1196 CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
1199 if( !bIsCut ){
1200 collectUIInformation("COPY", "parameter");
1203 return nRet;
1206 void SwTransferable::CalculateAndCopy()
1208 if(!m_pWrtShell)
1209 return;
1210 SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true );
1212 OUString aStr( m_pWrtShell->Calculate() );
1214 m_pClpDocFac.reset(new SwDocFac);
1215 SwDoc& rDoc = lcl_GetDoc(*m_pClpDocFac);
1216 m_pWrtShell->Copy(rDoc, &aStr);
1217 m_eBufferType = TransferBufferType::Document;
1218 AddFormat( SotClipboardFormatId::STRING );
1220 CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
1223 bool SwTransferable::CopyGlossary( SwTextBlocks& rGlossary, const OUString& rStr )
1225 if(!m_pWrtShell)
1226 return false;
1227 SwWait aWait( *m_pWrtShell->GetView().GetDocShell(), true );
1229 m_pClpDocFac.reset(new SwDocFac);
1230 SwDoc& rCDoc = lcl_GetDoc(*m_pClpDocFac);
1232 SwNodes& rNds = rCDoc.GetNodes();
1233 SwNodeIndex aNodeIdx( *rNds.GetEndOfContent().StartOfSectionNode() );
1234 SwContentNode* pCNd = rNds.GoNext( &aNodeIdx ); // go to 1st ContentNode
1235 SwPaM aPam( *pCNd );
1237 rCDoc.getIDocumentFieldsAccess().LockExpFields(); // never update fields - leave text as it is
1239 rCDoc.InsertGlossary( rGlossary, rStr, aPam );
1241 // a new one was created in CORE (OLE-Objects copied!)
1242 m_aDocShellRef = rCDoc.GetTmpDocShell();
1243 if( m_aDocShellRef.Is() )
1244 SwTransferable::InitOle( m_aDocShellRef );
1245 rCDoc.SetTmpDocShell( nullptr );
1247 m_eBufferType = TransferBufferType::Document;
1249 //When someone needs it, we 'OLE' her something.
1250 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
1251 AddFormat( SotClipboardFormatId::RTF );
1252 AddFormat( SotClipboardFormatId::RICHTEXT );
1253 AddFormat( SotClipboardFormatId::HTML );
1254 AddFormat( SotClipboardFormatId::STRING );
1256 //ObjectDescriptor was already filled from the old DocShell.
1257 //Now adjust it. Thus in GetData the first query can still
1258 //be answered with delayed rendering.
1259 m_aObjDesc.maSize = constOleSize100mm;
1261 PrepareOLE( m_aObjDesc );
1262 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
1264 CopyToClipboard( &m_pWrtShell->GetView().GetEditWin() );
1266 return true;
1269 static uno::Reference < XTransferable > * lcl_getTransferPointer ( uno::Reference < XTransferable > &xRef )
1271 return &xRef;
1274 SwPasteContext::SwPasteContext(SwWrtShell& rWrtShell)
1275 : m_rWrtShell(rWrtShell)
1277 remember();
1280 void SwPasteContext::remember()
1282 if (m_rWrtShell.GetPasteListeners().getLength() == 0)
1283 return;
1285 SwPaM* pCursor = m_rWrtShell.GetCursor();
1286 if (!pCursor)
1287 return;
1289 // Set point to the previous node, so it is not moved.
1290 const SwNode& rNode = pCursor->GetPoint()->GetNode();
1291 m_oPaM.emplace(rNode, rNode, SwNodeOffset(0), SwNodeOffset(-1));
1292 m_nStartContent = pCursor->GetPoint()->GetContentIndex();
1295 void SwPasteContext::forget() { m_oPaM.reset(); }
1297 SwPasteContext::~SwPasteContext()
1301 if (m_rWrtShell.GetPasteListeners().getLength() == 0)
1302 return;
1304 beans::PropertyValue aPropertyValue;
1306 switch (m_rWrtShell.GetView().GetShellMode())
1308 case ShellMode::Graphic:
1310 SwFrameFormat* pFormat = m_rWrtShell.GetFlyFrameFormat();
1311 if (!pFormat)
1312 return;
1314 aPropertyValue.Name = "TextGraphicObject";
1315 aPropertyValue.Value
1316 <<= uno::Reference<text::XTextContent>(SwXTextGraphicObject::CreateXTextGraphicObject(*pFormat->GetDoc(), pFormat));
1317 break;
1320 default:
1322 if (!m_oPaM)
1323 return;
1325 SwPaM* pCursor = m_rWrtShell.GetCursor();
1326 if (!pCursor)
1327 return;
1329 if (!pCursor->GetPoint()->GetNode().IsTextNode())
1330 // Non-text was pasted.
1331 return;
1333 // Update mark after paste.
1334 *m_oPaM->GetMark() = *pCursor->GetPoint();
1336 // Restore point.
1337 m_oPaM->GetPoint()->Adjust(SwNodeOffset(1));
1338 SwNode& rNode = m_oPaM->GetPointNode();
1339 if (!rNode.IsTextNode())
1340 // Starting point is no longer text.
1341 return;
1343 m_oPaM->GetPoint()->SetContent(m_nStartContent);
1345 aPropertyValue.Name = "TextRange";
1346 const rtl::Reference<SwXTextRange> xTextRange = SwXTextRange::CreateXTextRange(
1347 m_oPaM->GetDoc(), *m_oPaM->GetPoint(), m_oPaM->GetMark());
1348 aPropertyValue.Value <<= uno::Reference<text::XTextRange>(xTextRange);
1349 break;
1353 if (aPropertyValue.Name.isEmpty())
1354 return;
1356 // Invoke the listeners.
1357 uno::Sequence<beans::PropertyValue> aEvent{ aPropertyValue };
1358 m_rWrtShell.GetPasteListeners().notifyEach( &css::text::XPasteListener::notifyPasteEvent, aEvent );
1360 catch (const uno::Exception& rException)
1362 SAL_WARN("sw",
1363 "SwPasteContext::~SwPasteContext: uncaught exception: " << rException.Message);
1367 bool SwTransferable::IsPaste( const SwWrtShell& rSh,
1368 const TransferableDataHelper& rData )
1370 // Check the common case first: We can always paste our own data!
1371 // If _only_ the internal format can be pasted, this check will
1372 // yield 'true', while the one below would give a (wrong) result 'false'.
1374 bool bIsPaste = ( GetSwTransferable( rData ) != nullptr );
1376 // if it's not our own data, we need to have a closer look:
1377 if( ! bIsPaste )
1379 // determine the proper paste action, and return true if we find one
1380 uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
1382 SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
1383 sal_uInt16 nSourceOptions =
1384 (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
1385 SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
1386 SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
1387 SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
1388 ? EXCHG_IN_ACTION_COPY
1389 : EXCHG_IN_ACTION_MOVE);
1391 SotClipboardFormatId nFormat; // output param for GetExchangeAction
1392 sal_uInt8 nEventAction; // output param for GetExchangeAction
1393 sal_uInt8 nAction = SotExchange::GetExchangeAction(
1394 rData.GetDataFlavorExVector(),
1395 nDestination,
1396 nSourceOptions, /* ?? */
1397 EXCHG_IN_ACTION_DEFAULT, /* ?? */
1398 nFormat, nEventAction, SotClipboardFormatId::NONE,
1399 lcl_getTransferPointer ( xTransferable ) );
1401 // if we find a suitable action, we can paste!
1402 bIsPaste = (EXCHG_INOUT_ACTION_NONE != nAction);
1405 return bIsPaste;
1408 void SwTransferable::SelectPasteFormat(TransferableDataHelper& rData, sal_uInt8& nAction,
1409 SotClipboardFormatId& nFormat)
1411 if (nFormat != SotClipboardFormatId::RICHTEXT)
1413 return;
1416 if (!rData.HasFormat(SotClipboardFormatId::EMBED_SOURCE))
1418 return;
1421 if (!rData.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
1423 return;
1426 TransferableObjectDescriptor aObjDesc;
1427 if (!rData.GetTransferableObjectDescriptor(SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc))
1429 return;
1432 if (aObjDesc.maClassName != SvGlobalName(SO3_SW_CLASSID))
1434 return;
1437 // At this point we know that we paste from Writer to Writer and the clipboard has the content
1438 // in both RTF and ODF formats. Prefer ODF in this case.
1439 nAction = EXCHG_OUT_ACTION_INSERT_OLE;
1440 nFormat = SotClipboardFormatId::EMBED_SOURCE;
1443 // get HTML indentation level by counting tabulator characters before the index
1444 // (also index value -1 returns with 0)
1445 static sal_Int32 lcl_getLevel(OUString& sText, sal_Int32 nIdx)
1447 sal_Int32 nRet = 0;
1448 while ( nIdx-- > 0 && sText[nIdx] == '\t' )
1450 nRet++;
1452 return nRet;
1455 bool SwTransferable::Paste(SwWrtShell& rSh, TransferableDataHelper& rData, RndStdIds nAnchorType, bool bIgnoreComments, PasteTableType ePasteTable)
1457 SwPasteContext aPasteContext(rSh);
1459 sal_uInt8 nAction=0;
1460 SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
1461 SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
1462 SotExchangeActionFlags nActionFlags = SotExchangeActionFlags::NONE;
1463 bool bSingleCellTable = false;
1465 if( GetSwTransferable( rData ) )
1467 nAction = EXCHG_OUT_ACTION_INSERT_PRIVATE;
1469 else
1471 sal_uInt16 nSourceOptions =
1472 (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
1473 SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
1474 SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
1475 SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
1476 ? EXCHG_IN_ACTION_COPY
1477 : EXCHG_IN_ACTION_MOVE);
1478 uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
1479 sal_uInt8 nEventAction;
1480 nAction = SotExchange::GetExchangeAction(
1481 rData.GetDataFlavorExVector(),
1482 nDestination,
1483 nSourceOptions, /* ?? */
1484 EXCHG_IN_ACTION_DEFAULT, /* ?? */
1485 nFormat, nEventAction, SotClipboardFormatId::NONE,
1486 lcl_getTransferPointer ( xTransferable ),
1487 &nActionFlags );
1490 // when HTML is just an image don't generate new section
1491 if (rData.HasFormat(SotClipboardFormatId::HTML_SIMPLE) && rData.HasFormat(SotClipboardFormatId::HTML_NO_COMMENT)
1492 && rData.HasFormat(SotClipboardFormatId::BITMAP) && nFormat == SotClipboardFormatId::FILE_LIST)
1493 nFormat = SotClipboardFormatId::BITMAP;
1495 // tdf#37223 avoid non-native insertion of Calc worksheets in the following cases:
1496 // content of 1-cell worksheets are inserted as simple text using RTF format,
1497 // bigger worksheets within native (Writer) table cells are inserted as native tables,
1498 // ie. cell by cell instead of embedding the worksheet in a single cell of the Writer table
1499 if ( EXCHG_IN_ACTION_COPY == nAction && ( rData.HasFormat( SotClipboardFormatId::SYLK ) ||
1500 rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) )
1502 // is it a 1-cell worksheet?
1503 OUString aExpand;
1504 if( rData.GetString( SotClipboardFormatId::STRING, aExpand ))
1506 const sal_Int32 nNewlines{comphelper::string::getTokenCount(aExpand, '\n')};
1507 const sal_Int32 nRows = nNewlines ? nNewlines-1 : 0;
1508 if ( nRows == 1 )
1510 const sal_Int32 nCols = comphelper::string::getTokenCount(o3tl::getToken(aExpand, 0, '\n'), '\t');
1511 if (nCols == 1)
1512 bSingleCellTable = true;
1516 // convert the worksheet to a temporary native table using HTML format, and copy that into the original native table
1517 if (!bSingleCellTable && rData.HasFormat( SotClipboardFormatId::HTML ) &&
1518 SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr && rSh.DoesUndo())
1520 SfxDispatcher* pDispatch = rSh.GetView().GetViewFrame().GetDispatcher();
1521 sal_uInt32 nLevel = 0;
1523 // within Writer table cells, inserting worksheets using HTML format results only plain text, not a native table,
1524 // so remove all outer nested tables temporary to get a working insertion point
1525 // (RTF format has no such problem, but that inserts the hidden rows of the original Calc worksheet, too)
1527 // For this, switch off change tracking temporarily, if needed
1528 RedlineFlags eOld = rSh.GetDoc()->getIDocumentRedlineAccess().GetRedlineFlags();
1529 if ( eOld & RedlineFlags::On )
1530 rSh.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags( eOld & ~RedlineFlags::On );
1532 OUString sPreviousTableName;
1535 // tdf#152245 add a limit to the loop, if it's not possible to delete the table
1536 const SwTableNode* pNode = rSh.GetCursor()->GetPointNode().FindTableNode();
1537 const OUString sTableName = pNode->GetTable().GetFrameFormat()->GetName();
1538 if ( sTableName == sPreviousTableName )
1539 break;
1540 sPreviousTableName = sTableName;
1541 // insert a random character to redo the place of the insertion at the end
1542 pDispatch->Execute(FN_INSERT_NNBSP, SfxCallMode::SYNCHRON);
1543 pDispatch->Execute(FN_TABLE_DELETE_TABLE, SfxCallMode::SYNCHRON);
1544 nLevel++;
1545 } while (SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr);
1547 // restore change tracking settings
1548 if ( eOld & RedlineFlags::On )
1549 rSh.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags( eOld );
1551 if ( SwTransferable::PasteData( rData, rSh, EXCHG_OUT_ACTION_INSERT_STRING, nActionFlags, SotClipboardFormatId::HTML,
1552 nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, ePasteTable) )
1554 bool bFoundTemporaryTable = false;
1555 pDispatch->Execute(FN_LINE_UP, SfxCallMode::SYNCHRON);
1556 if (SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr)
1558 bFoundTemporaryTable = true;
1559 pDispatch->Execute(FN_TABLE_SELECT_ALL, SfxCallMode::SYNCHRON);
1560 pDispatch->Execute(SID_COPY, SfxCallMode::SYNCHRON);
1562 for(sal_uInt32 a = 0; a < 1 + (nLevel * 2); a++)
1563 pDispatch->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
1564 // clipboard content hasn't changed (limit potential infinite
1565 // recursion with the same non-native table, as was in tdf#138688)
1566 if (!bFoundTemporaryTable)
1567 return false;
1568 if (ePasteTable == PasteTableType::PASTE_TABLE)
1569 pDispatch->Execute(FN_PASTE_NESTED_TABLE, SfxCallMode::SYNCHRON);
1570 else if (ePasteTable == PasteTableType::PASTE_ROW)
1571 pDispatch->Execute(FN_TABLE_PASTE_ROW_BEFORE, SfxCallMode::SYNCHRON);
1572 else if (ePasteTable == PasteTableType::PASTE_COLUMN)
1573 pDispatch->Execute(FN_TABLE_PASTE_COL_BEFORE, SfxCallMode::SYNCHRON);
1574 else
1575 pDispatch->Execute(SID_PASTE, SfxCallMode::SYNCHRON);
1576 return true;
1577 } else {
1578 for(sal_uInt32 a = 0; a < (nLevel * 2); a++)
1579 pDispatch->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
1583 // insert clipboard content as new table rows/columns before the actual row/column instead of overwriting it
1584 else if ( (rSh.GetTableInsertMode() != SwTable::SEARCH_NONE || ePasteTable == PasteTableType::PASTE_ROW || ePasteTable == PasteTableType::PASTE_COLUMN) &&
1585 rData.HasFormat( SotClipboardFormatId::HTML ) &&
1586 SwDoc::IsInTable(rSh.GetCursor()->GetPointNode()) != nullptr )
1588 OUString aExpand;
1589 sal_Int32 nIdx;
1590 bool bRowMode = rSh.GetTableInsertMode() == SwTable::SEARCH_ROW || ePasteTable == PasteTableType::PASTE_ROW;
1591 if( rData.GetString( SotClipboardFormatId::HTML, aExpand ) && (nIdx = aExpand.indexOf("<table")) > -1 )
1593 // calculate table row/column count by analysing indentation of the HTML table extract
1595 // calculate indentation level of <table>, which is the base of the next calculations
1596 // (tdf#148791 table alignment can enlarge it using first level <center>, <div> or <dl>)
1597 sal_Int32 nTableLevel = lcl_getLevel(aExpand, nIdx);
1598 // table rows repeated heading use extra indentation, too:
1599 // <thead> is always used here, and the first table with <thead> is not nested,
1600 // if its indentation level is greater only by 1, than indentation level of the table
1601 bool bShifted = lcl_getLevel(aExpand, aExpand.indexOf("<thead")) == nTableLevel + 1;
1602 // calculate count of selected rows or columns
1603 sal_Int32 nSelectedRowsOrCols = 0;
1604 const OUString sSearchRowOrCol = bRowMode ? OUString("</tr>") : OUString("<col ");
1605 while((nIdx = aExpand.indexOf(sSearchRowOrCol, nIdx)) > -1)
1607 // skip rows/columns of nested tables, based on HTML indentation
1608 if ( lcl_getLevel(aExpand, nIdx) == nTableLevel + (bShifted ? 2 : 1) &&
1609 // skip also strange hidden empty rows <tr></tr>
1610 !aExpand.match("<tr></tr>", nIdx - 4) )
1612 ++nSelectedRowsOrCols;
1614 ++nIdx;
1616 // are we at the beginning of the cell?
1617 bool bStartTableBoxNode =
1618 // first paragraph of the cell?
1619 rSh.GetCursor()->GetPointNode().GetIndex() == rSh.GetCursor()->GetPointNode().FindTableBoxStartNode()->GetIndex()+1 &&
1620 // beginning of the paragraph?
1621 !rSh.GetCursor()->GetPoint()->GetContentIndex();
1622 SfxDispatcher* pDispatch = rSh.GetView().GetViewFrame().GetDispatcher();
1624 // go start of the cell
1625 if (!bStartTableBoxNode)
1626 pDispatch->Execute(FN_START_OF_DOCUMENT, SfxCallMode::SYNCHRON);
1628 // store cursor position in row mode
1629 ::sw::mark::IMark* pMark = (!bRowMode || nSelectedRowsOrCols == 0) ? nullptr : rSh.SetBookmark(
1630 vcl::KeyCode(),
1631 OUString(),
1632 IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
1634 // add a new empty row/column before the actual table row/column and go there
1635 const sal_uInt16 nDispatchSlot = bRowMode ? FN_TABLE_INSERT_ROW_BEFORE : FN_TABLE_INSERT_COL_BEFORE;
1636 pDispatch->Execute(nDispatchSlot, SfxCallMode::SYNCHRON);
1637 pDispatch->Execute(bRowMode ? FN_LINE_UP : FN_CHAR_LEFT, SfxCallMode::SYNCHRON);
1639 // add the other new empty rows/columns after the actual table row/column
1640 if ( nSelectedRowsOrCols > 1 )
1642 SfxInt16Item aCountItem( nDispatchSlot, nSelectedRowsOrCols-1 );
1643 SfxBoolItem aAfter( FN_PARAM_INSERT_AFTER, true );
1644 pDispatch->ExecuteList(nDispatchSlot,
1645 SfxCallMode::SYNCHRON|SfxCallMode::RECORD,
1646 { &aCountItem, &aAfter });
1649 // paste rows
1650 bool bResult = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
1651 nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext );
1653 // restore cursor position
1654 if (pMark != nullptr)
1656 rSh.GotoMark( pMark );
1657 rSh.getIDocumentMarkAccess()->deleteMark( pMark );
1660 return bResult;
1664 // special case for tables from draw application or 1-cell tables
1665 if( EXCHG_OUT_ACTION_INSERT_DRAWOBJ == nAction || bSingleCellTable )
1667 if( rData.HasFormat( SotClipboardFormatId::RTF ) )
1669 nAction = EXCHG_OUT_ACTION_INSERT_STRING;
1670 nFormat = SotClipboardFormatId::RTF;
1672 else if( rData.HasFormat( SotClipboardFormatId::RICHTEXT ) )
1674 nAction = EXCHG_OUT_ACTION_INSERT_STRING;
1675 nFormat = SotClipboardFormatId::RICHTEXT;
1679 // Tweak the format if necessary: the source application can be considered in this context,
1680 // while not in sot/ code.
1681 SwTransferable::SelectPasteFormat(rData, nAction, nFormat);
1683 collectUIInformation("PASTE", "parameter");
1685 return EXCHG_INOUT_ACTION_NONE != nAction &&
1686 SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
1687 nDestination, false, false, nullptr, 0, false, nAnchorType, bIgnoreComments, &aPasteContext, ePasteTable);
1690 bool SwTransferable::PasteData( TransferableDataHelper& rData,
1691 SwWrtShell& rSh, sal_uInt8 nAction, SotExchangeActionFlags nActionFlags,
1692 SotClipboardFormatId nFormat,
1693 SotExchangeDest nDestination, bool bIsPasteFormat,
1694 bool bIsDefault,
1695 const Point* pPt, sal_Int8 nDropAction,
1696 bool bPasteSelection, RndStdIds nAnchorType,
1697 bool bIgnoreComments,
1698 SwPasteContext* pContext,
1699 PasteTableType ePasteTable )
1701 SwWait aWait( *rSh.GetView().GetDocShell(), false );
1702 std::unique_ptr<SwTrnsfrActionAndUndo, o3tl::default_delete<SwTrnsfrActionAndUndo>> pAction;
1703 SwModule* pMod = SW_MOD();
1705 bool bRet = false;
1706 bool bCallAutoCaption = false;
1708 if( pPt )
1710 // external Drop
1711 if( bPasteSelection ? !pMod->m_pXSelection : !pMod->m_pDragDrop )
1713 switch( nDestination )
1715 case SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP:
1716 case SotExchangeDest::DOC_LNKD_GRAPHOBJ:
1717 case SotExchangeDest::DOC_GRAPH_W_IMAP:
1718 case SotExchangeDest::DOC_GRAPHOBJ:
1719 case SotExchangeDest::DOC_OLEOBJ:
1720 case SotExchangeDest::DOC_DRAWOBJ:
1721 case SotExchangeDest::DOC_URLBUTTON:
1722 case SotExchangeDest::DOC_GROUPOBJ:
1723 // select frames/objects
1724 SwTransferable::SetSelInShell( rSh, true, pPt );
1725 break;
1727 default:
1728 SwTransferable::SetSelInShell( rSh, false, pPt );
1729 break;
1733 else if( ( !GetSwTransferable( rData ) || bIsPasteFormat ) &&
1734 !rSh.IsTableMode() && rSh.HasSelection() )
1736 // then delete the selections
1738 //don't delete selected content
1739 // - at table-selection
1740 // - at ReRead of a graphic/DDEData
1741 // - at D&D, for the right selection was taken care of
1742 // in Drop-Handler
1743 bool bDelSel = false;
1744 switch( nDestination )
1746 case SotExchangeDest::DOC_TEXTFRAME:
1747 case SotExchangeDest::SWDOC_FREE_AREA:
1748 case SotExchangeDest::DOC_TEXTFRAME_WEB:
1749 case SotExchangeDest::SWDOC_FREE_AREA_WEB:
1750 bDelSel = true;
1751 break;
1752 default:
1753 break;
1756 if( bDelSel )
1757 // #i34830#
1758 pAction.reset(new SwTrnsfrActionAndUndo(&rSh, true, pContext));
1761 SwTransferable *pTrans=nullptr, *pTunneledTrans=GetSwTransferable( rData );
1763 // check for private drop
1764 bool bPrivateDrop(pPt);
1765 if (bPrivateDrop)
1767 if (bPasteSelection)
1768 pTrans = pMod->m_pXSelection;
1769 else
1770 pTrans = pMod->m_pDragDrop;
1771 bPrivateDrop = nullptr != pTrans;
1773 bool bNeedToSelectBeforePaste(false);
1775 if(bPrivateDrop && DND_ACTION_LINK == nDropAction)
1777 // internal drop on object, suppress bPrivateDrop to change internal fill
1778 bPrivateDrop = false;
1779 bNeedToSelectBeforePaste = true;
1782 if(bPrivateDrop && pPt && DND_ACTION_MOVE == nDropAction)
1784 // check if dragged over a useful target. If yes, use as content exchange
1785 // drop as if from external
1786 const SwFrameFormat* pSwFrameFormat = rSh.GetFormatFromObj(*pPt);
1788 if(dynamic_cast< const SwDrawFrameFormat* >(pSwFrameFormat))
1790 bPrivateDrop = false;
1791 bNeedToSelectBeforePaste = true;
1795 if(bPrivateDrop)
1797 // then internal Drag & Drop or XSelection
1798 bRet = pTrans->PrivateDrop( rSh, *pPt, DND_ACTION_MOVE == nDropAction,
1799 bPasteSelection );
1801 else if( !pPt && pTunneledTrans &&
1802 EXCHG_OUT_ACTION_INSERT_PRIVATE == nAction )
1804 // then internal paste
1805 bRet = pTunneledTrans->PrivatePaste(rSh, pContext, ePasteTable);
1807 else if( EXCHG_INOUT_ACTION_NONE != nAction )
1809 if( !pAction )
1811 pAction.reset(new SwTrnsfrActionAndUndo( &rSh ));
1814 // in Drag&Drop MessageBoxes must not be showed
1815 bool bMsg = nullptr == pPt;
1817 // delete selections
1819 switch( nAction )
1821 case EXCHG_OUT_ACTION_INSERT_PRIVATE:
1822 OSL_ENSURE( pPt, "EXCHG_OUT_ACTION_INSERT_PRIVATE: what should happen here?" );
1823 break;
1825 case EXCHG_OUT_ACTION_MOVE_PRIVATE:
1826 OSL_ENSURE( pPt, "EXCHG_OUT_ACTION_MOVE_PRIVATE: what should happen here?" );
1827 break;
1829 case EXCHG_IN_ACTION_MOVE:
1830 case EXCHG_IN_ACTION_COPY:
1831 case EXCHG_IN_ACTION_LINK:
1832 case EXCHG_OUT_ACTION_INSERT_HTML:
1833 case EXCHG_OUT_ACTION_INSERT_STRING:
1834 case EXCHG_OUT_ACTION_INSERT_IMAGEMAP:
1835 case EXCHG_OUT_ACTION_REPLACE_IMAGEMAP:
1837 // then we have to use the format
1838 switch( nFormat )
1840 case SotClipboardFormatId::DRAWING:
1841 bRet = SwTransferable::PasteSdrFormat( rData, rSh,
1842 SwPasteSdr::Insert, pPt,
1843 nActionFlags, bNeedToSelectBeforePaste);
1844 break;
1846 case SotClipboardFormatId::HTML:
1847 case SotClipboardFormatId::HTML_SIMPLE:
1848 case SotClipboardFormatId::HTML_NO_COMMENT:
1849 case SotClipboardFormatId::RTF:
1850 case SotClipboardFormatId::RICHTEXT:
1851 case SotClipboardFormatId::STRING:
1852 bRet = SwTransferable::PasteFileContent( rData, rSh,
1853 nFormat, bMsg, bIgnoreComments );
1854 break;
1856 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
1858 INetBookmark aBkmk;
1859 if( rData.GetINetBookmark( nFormat, aBkmk ) )
1861 SwFormatINetFormat aFormat( aBkmk.GetURL(), OUString() );
1862 rSh.InsertURL( aFormat, aBkmk.GetDescription() );
1863 bRet = true;
1866 break;
1868 case SotClipboardFormatId::SD_OLE:
1869 bRet = SwTransferable::PasteOLE( rData, rSh, nFormat,
1870 nActionFlags, bMsg );
1871 break;
1873 case SotClipboardFormatId::SVIM:
1874 bRet = SwTransferable::PasteImageMap( rData, rSh );
1875 break;
1877 case SotClipboardFormatId::SVXB:
1878 case SotClipboardFormatId::BITMAP:
1879 case SotClipboardFormatId::PNG:
1880 case SotClipboardFormatId::GDIMETAFILE:
1881 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
1882 SwPasteSdr::Insert,pPt,
1883 nActionFlags, nDropAction, bNeedToSelectBeforePaste);
1884 break;
1886 case SotClipboardFormatId::XFORMS:
1887 case SotClipboardFormatId::SBA_FIELDDATAEXCHANGE:
1888 case SotClipboardFormatId::SBA_DATAEXCHANGE:
1889 case SotClipboardFormatId::SBA_CTRLDATAEXCHANGE:
1890 bRet = SwTransferable::PasteDBData( rData, rSh, nFormat,
1891 EXCHG_IN_ACTION_LINK == nAction,
1892 pPt, bMsg );
1893 break;
1895 case SotClipboardFormatId::SIMPLE_FILE:
1896 bRet = SwTransferable::PasteFileName( rData, rSh, nFormat,
1897 ( EXCHG_IN_ACTION_MOVE == nAction
1898 ? SwPasteSdr::Replace
1899 : EXCHG_IN_ACTION_LINK == nAction
1900 ? SwPasteSdr::SetAttr
1901 : SwPasteSdr::Insert),
1902 pPt, nActionFlags, nullptr );
1903 break;
1905 case SotClipboardFormatId::FILE_LIST:
1906 // then insert as graphics only
1907 bRet = SwTransferable::PasteFileList( rData, rSh,
1908 EXCHG_IN_ACTION_LINK == nAction,
1909 pPt, bMsg );
1910 break;
1912 case SotClipboardFormatId::SONLK:
1913 if( pPt )
1915 NaviContentBookmark aBkmk;
1916 if( aBkmk.Paste( rData ) )
1918 if(bIsDefault)
1920 switch(aBkmk.GetDefaultDragType())
1922 case RegionMode::NONE: nAction = EXCHG_IN_ACTION_COPY; break;
1923 case RegionMode::EMBEDDED: nAction = EXCHG_IN_ACTION_MOVE; break;
1924 case RegionMode::LINK: nAction = EXCHG_IN_ACTION_LINK; break;
1927 rSh.NavigatorPaste( aBkmk, nAction );
1928 bRet = true;
1931 break;
1933 case SotClipboardFormatId::INET_IMAGE:
1934 case SotClipboardFormatId::NETSCAPE_IMAGE:
1935 bRet = SwTransferable::PasteTargetURL( rData, rSh,
1936 SwPasteSdr::Insert,
1937 pPt, true );
1938 break;
1940 default:
1941 OSL_ENSURE( pPt, "unknown format" );
1943 break;
1945 case EXCHG_OUT_ACTION_INSERT_FILE:
1947 bool graphicInserted;
1948 bRet = SwTransferable::PasteFileName( rData, rSh, nFormat,
1949 SwPasteSdr::Insert, pPt,
1950 nActionFlags,
1951 &graphicInserted );
1952 if( graphicInserted )
1953 bCallAutoCaption = true;
1955 break;
1957 case EXCHG_OUT_ACTION_INSERT_OLE:
1958 bRet = SwTransferable::PasteOLE( rData, rSh, nFormat,
1959 nActionFlags,bMsg );
1960 break;
1962 case EXCHG_OUT_ACTION_INSERT_DDE:
1964 bool bReRead = 0 != CNT_HasGrf( rSh.GetCntType() );
1965 bRet = SwTransferable::PasteDDE( rData, rSh, bReRead, bMsg );
1967 break;
1969 case EXCHG_OUT_ACTION_INSERT_HYPERLINK:
1971 OUString sURL, sDesc;
1972 if( SotClipboardFormatId::SIMPLE_FILE == nFormat )
1974 if( rData.GetString( nFormat, sURL ) && !sURL.isEmpty() )
1976 SwTransferable::CheckForURLOrLNKFile( rData, sURL, &sDesc );
1977 if( sDesc.isEmpty() )
1978 sDesc = sURL;
1979 bRet = true;
1982 else
1984 INetBookmark aBkmk;
1985 if( rData.GetINetBookmark( nFormat, aBkmk ) )
1987 sURL = aBkmk.GetURL();
1988 sDesc = aBkmk.GetDescription();
1989 bRet = true;
1993 if( bRet )
1995 SwFormatINetFormat aFormat( sURL, OUString() );
1996 rSh.InsertURL( aFormat, sDesc );
1999 break;
2001 case EXCHG_OUT_ACTION_GET_ATTRIBUTES:
2002 switch( nFormat )
2004 case SotClipboardFormatId::DRAWING:
2005 bRet = SwTransferable::PasteSdrFormat( rData, rSh,
2006 SwPasteSdr::SetAttr, pPt,
2007 nActionFlags, bNeedToSelectBeforePaste);
2008 break;
2009 case SotClipboardFormatId::SVXB:
2010 case SotClipboardFormatId::GDIMETAFILE:
2011 case SotClipboardFormatId::BITMAP:
2012 case SotClipboardFormatId::PNG:
2013 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
2014 case SotClipboardFormatId::SIMPLE_FILE:
2015 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
2016 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
2017 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
2018 SwPasteSdr::SetAttr, pPt,
2019 nActionFlags, nDropAction, bNeedToSelectBeforePaste);
2020 break;
2021 default:
2022 OSL_FAIL( "unknown format" );
2025 break;
2027 case EXCHG_OUT_ACTION_INSERT_DRAWOBJ:
2028 bRet = SwTransferable::PasteSdrFormat( rData, rSh,
2029 SwPasteSdr::Insert, pPt,
2030 nActionFlags, bNeedToSelectBeforePaste);
2031 break;
2032 case EXCHG_OUT_ACTION_INSERT_SVXB:
2033 case EXCHG_OUT_ACTION_INSERT_GDIMETAFILE:
2034 case EXCHG_OUT_ACTION_INSERT_BITMAP:
2035 case EXCHG_OUT_ACTION_INSERT_GRAPH:
2036 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
2037 SwPasteSdr::Insert, pPt,
2038 nActionFlags, nDropAction, bNeedToSelectBeforePaste, nAnchorType );
2039 break;
2041 case EXCHG_OUT_ACTION_REPLACE_DRAWOBJ:
2042 bRet = SwTransferable::PasteSdrFormat( rData, rSh,
2043 SwPasteSdr::Replace, pPt,
2044 nActionFlags, bNeedToSelectBeforePaste);
2045 break;
2047 case EXCHG_OUT_ACTION_REPLACE_SVXB:
2048 case EXCHG_OUT_ACTION_REPLACE_GDIMETAFILE:
2049 case EXCHG_OUT_ACTION_REPLACE_BITMAP:
2050 case EXCHG_OUT_ACTION_REPLACE_GRAPH:
2051 bRet = SwTransferable::PasteGrf( rData, rSh, nFormat,
2052 SwPasteSdr::Replace,pPt,
2053 nActionFlags, nDropAction, bNeedToSelectBeforePaste);
2054 break;
2056 case EXCHG_OUT_ACTION_INSERT_INTERACTIVE:
2057 bRet = SwTransferable::PasteAsHyperlink( rData, rSh, nFormat );
2058 break;
2060 default:
2061 OSL_FAIL("unknown action" );
2065 if( !bPasteSelection && rSh.IsFrameSelected() )
2067 rSh.EnterSelFrameMode();
2068 //force ::SelectShell
2069 rSh.GetView().StopShellTimer();
2072 pAction.reset();
2073 if( bCallAutoCaption )
2074 rSh.GetView().AutoCaption( GRAPHIC_CAP );
2076 return bRet;
2079 SotExchangeDest SwTransferable::GetSotDestination( const SwWrtShell& rSh )
2081 SotExchangeDest nRet = SotExchangeDest::NONE;
2083 ObjCntType eOType = rSh.GetObjCntTypeOfSelection();
2085 switch( eOType )
2087 case OBJCNT_GRF:
2089 bool bIMap, bLink;
2090 bIMap = nullptr != rSh.GetFlyFrameFormat()->GetURL().GetMap();
2091 OUString aDummy;
2092 rSh.GetGrfNms( &aDummy, nullptr );
2093 bLink = !aDummy.isEmpty();
2095 if( bLink && bIMap )
2096 nRet = SotExchangeDest::DOC_LNKD_GRAPH_W_IMAP;
2097 else if( bLink )
2098 nRet = SotExchangeDest::DOC_LNKD_GRAPHOBJ;
2099 else if( bIMap )
2100 nRet = SotExchangeDest::DOC_GRAPH_W_IMAP;
2101 else
2102 nRet = SotExchangeDest::DOC_GRAPHOBJ;
2104 break;
2106 case OBJCNT_FLY:
2107 if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr )
2108 nRet = SotExchangeDest::DOC_TEXTFRAME_WEB;
2109 else
2110 nRet = SotExchangeDest::DOC_TEXTFRAME;
2111 break;
2112 case OBJCNT_OLE: nRet = SotExchangeDest::DOC_OLEOBJ; break;
2114 case OBJCNT_CONTROL: /* no Action avail */
2115 case OBJCNT_SIMPLE: nRet = SotExchangeDest::DOC_DRAWOBJ; break;
2116 case OBJCNT_URLBUTTON: nRet = SotExchangeDest::DOC_URLBUTTON; break;
2117 case OBJCNT_GROUPOBJ: nRet = SotExchangeDest::DOC_GROUPOBJ; break;
2119 // what do we do at multiple selections???
2120 default:
2122 if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr )
2123 nRet = SotExchangeDest::SWDOC_FREE_AREA_WEB;
2124 else
2125 nRet = SotExchangeDest::SWDOC_FREE_AREA;
2129 return nRet;
2132 bool SwTransferable::PasteFileContent( const TransferableDataHelper& rData,
2133 SwWrtShell& rSh, SotClipboardFormatId nFormat, bool bMsg, bool bIgnoreComments )
2135 TranslateId pResId = STR_CLPBRD_FORMAT_ERROR;
2136 bool bRet = false;
2138 MSE40HTMLClipFormatObj aMSE40ClpObj;
2140 tools::SvRef<SotTempStream> xStrm;
2141 SvStream* pStream = nullptr;
2142 Reader* pRead = nullptr;
2143 OUString sData;
2144 switch( nFormat )
2146 case SotClipboardFormatId::STRING:
2148 pRead = ReadAscii;
2149 if( rData.GetString( nFormat, sData ) )
2151 pStream = new SvMemoryStream( const_cast<sal_Unicode *>(sData.getStr()),
2152 sData.getLength() * sizeof( sal_Unicode ),
2153 StreamMode::READ );
2154 #ifdef OSL_BIGENDIAN
2155 pStream->SetEndian( SvStreamEndian::BIG );
2156 #else
2157 pStream->SetEndian( SvStreamEndian::LITTLE );
2158 #endif
2160 SwAsciiOptions aAOpt;
2161 aAOpt.SetCharSet( RTL_TEXTENCODING_UCS2 );
2162 pRead->GetReaderOpt().SetASCIIOpts( aAOpt );
2163 break;
2166 [[fallthrough]]; // because then test if we get a stream
2168 default:
2169 if( rData.GetSotStorageStream( nFormat, xStrm ) )
2171 if( ( SotClipboardFormatId::HTML_SIMPLE == nFormat ) ||
2172 ( SotClipboardFormatId::HTML_NO_COMMENT == nFormat ) )
2174 pStream = aMSE40ClpObj.IsValid( *xStrm );
2175 pRead = ReadHTML;
2176 pRead->SetReadUTF8( true );
2178 bool bNoComments =
2179 ( nFormat == SotClipboardFormatId::HTML_NO_COMMENT );
2180 pRead->SetIgnoreHTMLComments( bNoComments );
2182 else
2184 pStream = xStrm.get();
2185 if( SotClipboardFormatId::RTF == nFormat || SotClipboardFormatId::RICHTEXT == nFormat)
2186 pRead = SwReaderWriter::GetRtfReader();
2187 else if( !pRead )
2189 pRead = ReadHTML;
2190 pRead->SetReadUTF8( true );
2194 break;
2197 if( pStream && pRead )
2199 Link<LinkParamNone*,void> aOldLink( rSh.GetChgLnk() );
2200 rSh.SetChgLnk( Link<LinkParamNone*,void>() );
2202 const SwPosition& rInsPos = *rSh.GetCursor()->Start();
2203 SwReader aReader(*pStream, OUString(), OUString(), *rSh.GetCursor());
2204 rSh.SaveTableBoxContent( &rInsPos );
2206 if (bIgnoreComments)
2207 pRead->SetIgnoreHTMLComments(true);
2209 if( aReader.Read( *pRead ).IsError() )
2210 pResId = STR_ERROR_CLPBRD_READ;
2211 else
2213 pResId = TranslateId();
2214 bRet = true;
2217 rSh.SetChgLnk( aOldLink );
2218 if( bRet )
2219 rSh.CallChgLnk();
2221 else
2222 pResId = STR_CLPBRD_FORMAT_ERROR;
2224 // Exist a SvMemoryStream? (data in the OUString and xStrm is empty)
2225 if( pStream && !xStrm.is() )
2226 delete pStream;
2228 if (bMsg && pResId)
2230 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2231 VclMessageType::Info, VclButtonsType::Ok,
2232 SwResId(pResId)));
2233 xBox->run();
2235 return bRet;
2238 bool SwTransferable::PasteOLE( TransferableDataHelper& rData, SwWrtShell& rSh,
2239 SotClipboardFormatId nFormat, SotExchangeActionFlags nActionFlags, bool bMsg )
2241 bool bRet = false;
2242 TransferableObjectDescriptor aObjDesc;
2243 uno::Reference < io::XInputStream > xStrm;
2244 uno::Reference < embed::XStorage > xStore;
2245 Reader* pRead = nullptr;
2247 // Get the preferred format
2248 SotClipboardFormatId nId;
2249 if( rData.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ ) )
2250 nId = SotClipboardFormatId::EMBEDDED_OBJ;
2251 else if( rData.HasFormat( SotClipboardFormatId::EMBED_SOURCE ) &&
2252 rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ))
2253 nId = SotClipboardFormatId::EMBED_SOURCE;
2254 else
2255 nId = SotClipboardFormatId::NONE;
2257 if (nId != SotClipboardFormatId::NONE)
2259 SwDocShell* pDocSh = rSh.GetDoc()->GetDocShell();
2260 xStrm = rData.GetInputStream(nId, SfxObjectShell::CreateShellID(pDocSh));
2263 if (xStrm.is())
2265 // if there is an embedded object, first try if it's a writer object
2266 // this will be inserted into the document by using a Reader
2269 xStore = comphelper::OStorageHelper::GetStorageFromInputStream( xStrm );
2270 switch( SotStorage::GetFormatID( xStore ) )
2272 case SotClipboardFormatId::STARWRITER_60:
2273 case SotClipboardFormatId::STARWRITERWEB_60:
2274 case SotClipboardFormatId::STARWRITERGLOB_60:
2275 case SotClipboardFormatId::STARWRITER_8:
2276 case SotClipboardFormatId::STARWRITERWEB_8:
2277 case SotClipboardFormatId::STARWRITERGLOB_8:
2278 pRead = ReadXML;
2279 break;
2280 default:
2283 xStore->dispose();
2284 xStore = nullptr;
2286 catch (const uno::Exception&)
2290 break;
2293 catch (const uno::Exception&)
2295 // it wasn't a storage, but maybe it's a useful stream
2299 if( pRead )
2301 SwPaM &rPAM = *rSh.GetCursor();
2302 SwReader aReader(xStore, OUString(), rPAM);
2303 if( ! aReader.Read( *pRead ).IsError() )
2304 bRet = true;
2305 else if( bMsg )
2307 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2308 VclMessageType::Info, VclButtonsType::Ok,
2309 SwResId(STR_ERROR_CLPBRD_READ)));
2310 xBox->run();
2313 else
2315 // temporary storage until the object is inserted
2316 uno::Reference< embed::XStorage > xTmpStor;
2317 uno::Reference < embed::XEmbeddedObject > xObj;
2318 OUString aName;
2319 comphelper::EmbeddedObjectContainer aCnt;
2321 if ( xStrm.is() )
2323 if ( !rData.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
2325 OSL_ENSURE( !xStrm.is(), "An object without descriptor in clipboard!");
2328 else
2330 if( rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR_OLE ) && rData.GetTransferableObjectDescriptor( nFormat, aObjDesc ) )
2332 xStrm = rData.GetInputStream(SotClipboardFormatId::EMBED_SOURCE_OLE, OUString());
2333 if (!xStrm.is())
2334 xStrm = rData.GetInputStream(SotClipboardFormatId::EMBEDDED_OBJ_OLE, OUString());
2336 if ( !xStrm.is() )
2338 // This is MSOLE object that should be created by direct using of system clipboard
2341 xTmpStor = ::comphelper::OStorageHelper::GetTemporaryStorage();
2342 uno::Reference < embed::XEmbedObjectClipboardCreator > xClipboardCreator =
2343 embed::MSOLEObjectSystemCreator::create( ::comphelper::getProcessComponentContext() );
2345 embed::InsertedObjectInfo aInfo = xClipboardCreator->createInstanceInitFromClipboard(
2346 xTmpStor,
2347 "DummyName",
2348 uno::Sequence< beans::PropertyValue >() );
2350 // TODO/LATER: in future InsertedObjectInfo will be used to get container related information
2351 // for example whether the object should be an iconified one
2352 xObj = aInfo.Object;
2354 catch (const uno::Exception&)
2359 else if (rData.HasFormat(SotClipboardFormatId::SIMPLE_FILE))
2361 OUString sFile;
2362 if (rData.GetString(nFormat, sFile) && !sFile.isEmpty())
2364 // Copied from sd::View::DropInsertFileHdl
2365 uno::Sequence< beans::PropertyValue > aMedium{ comphelper::makePropertyValue(
2366 "URL", sFile) };
2367 SwDocShell* pDocSh = rSh.GetDoc()->GetDocShell();
2368 xObj = pDocSh->GetEmbeddedObjectContainer().InsertEmbeddedObject(aMedium, aName);
2373 if ( xStrm.is() && !xObj.is() )
2374 xObj = aCnt.InsertEmbeddedObject( xStrm, aName );
2376 if( xObj.is() )
2378 svt::EmbeddedObjectRef xObjRef( xObj, aObjDesc.mnViewAspect );
2380 // try to get the replacement image from the clipboard
2381 Graphic aGraphic;
2382 SotClipboardFormatId nGrFormat = SotClipboardFormatId::NONE;
2384 // limit the size of the preview metafile to 100000 actions
2385 GDIMetaFile aMetafile;
2386 if (rData.GetGDIMetaFile(SotClipboardFormatId::GDIMETAFILE, aMetafile, 100000))
2388 nGrFormat = SotClipboardFormatId::GDIMETAFILE;
2389 aGraphic = aMetafile;
2392 // insert replacement image ( if there is one ) into the object helper
2393 if ( nGrFormat != SotClipboardFormatId::NONE )
2395 DataFlavor aDataFlavor;
2396 SotExchange::GetFormatDataFlavor( nGrFormat, aDataFlavor );
2397 xObjRef.SetGraphic( aGraphic, aDataFlavor.MimeType );
2399 else if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON )
2401 // it is important to have an icon, let an empty graphic be used
2402 // if no other graphic is provided
2403 // TODO/LATER: in future a default bitmap could be used
2404 MapMode aMapMode( MapUnit::Map100thMM );
2405 aGraphic.SetPrefSize( Size( 2500, 2500 ) );
2406 aGraphic.SetPrefMapMode( aMapMode );
2407 xObjRef.SetGraphic( aGraphic, OUString() );
2410 //set size. This is a hack because of handing over, size should be
2411 //passed to the InsertOle!!!!!!!!!!
2412 Size aSize;
2413 if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON )
2415 if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
2416 aSize = aObjDesc.maSize;
2417 else
2419 MapMode aMapMode( MapUnit::Map100thMM );
2420 aSize = xObjRef.GetSize( &aMapMode );
2423 else if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() )
2425 aSize = aObjDesc.maSize; //always 100TH_MM
2426 MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( aObjDesc.mnViewAspect ) );
2427 aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aUnit));
2428 awt::Size aSz;
2431 aSz = xObj->getVisualAreaSize( aObjDesc.mnViewAspect );
2433 catch (const embed::NoVisualAreaSizeException&)
2435 // in this case the provided size is used
2438 if ( aSz.Width != aSize.Width() || aSz.Height != aSize.Height() )
2440 aSz.Width = aSize.Width();
2441 aSz.Height = aSize.Height();
2442 xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz );
2445 else
2447 // the descriptor contains the wrong object size
2448 // the following call will let the MSOLE objects cache the size if it is possible
2449 // it should be done while the object is running
2452 xObj->getVisualAreaSize( aObjDesc.mnViewAspect );
2454 catch (const uno::Exception&)
2458 //End of Hack!
2460 rSh.InsertOleObject( xObjRef );
2461 bRet = true;
2463 if( bRet && ( nActionFlags & SotExchangeActionFlags::InsertTargetUrl) )
2464 SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
2466 // let the object be unloaded if possible
2467 SwOLEObj::UnloadObject( xObj, rSh.GetDoc(), embed::Aspects::MSOLE_CONTENT );
2470 return bRet;
2473 bool SwTransferable::PasteTargetURL( const TransferableDataHelper& rData,
2474 SwWrtShell& rSh, SwPasteSdr nAction,
2475 const Point* pPt, bool bInsertGRF )
2477 bool bRet = false;
2478 INetImage aINetImg;
2479 if( ( rData.HasFormat( SotClipboardFormatId::INET_IMAGE ) &&
2480 rData.GetINetImage( SotClipboardFormatId::INET_IMAGE, aINetImg )) ||
2481 ( rData.HasFormat( SotClipboardFormatId::NETSCAPE_IMAGE ) &&
2482 rData.GetINetImage( SotClipboardFormatId::NETSCAPE_IMAGE, aINetImg )) )
2484 if( !aINetImg.GetImageURL().isEmpty() && bInsertGRF )
2486 OUString sURL( aINetImg.GetImageURL() );
2487 SwTransferable::CheckForURLOrLNKFile( rData, sURL );
2489 //!!! check at FileSystem - only then it makes sense to test graphics !!!
2490 Graphic aGraphic;
2491 GraphicFilter &rFlt = GraphicFilter::GetGraphicFilter();
2492 bRet = ERRCODE_NONE == GraphicFilter::LoadGraphic(sURL, OUString(), aGraphic, &rFlt);
2494 if( bRet )
2496 //Check and Perform rotation if needed
2497 lclCheckAndPerformRotation(aGraphic);
2499 switch( nAction )
2501 case SwPasteSdr::Insert:
2502 SwTransferable::SetSelInShell( rSh, false, pPt );
2503 rSh.InsertGraphic(sURL, OUString(), aGraphic);
2504 break;
2506 case SwPasteSdr::Replace:
2507 if( rSh.IsObjSelected() )
2509 rSh.ReplaceSdrObj( sURL, &aGraphic );
2510 Point aPt( pPt ? *pPt : rSh.GetCursorDocPos() );
2511 SwTransferable::SetSelInShell( rSh, true, &aPt );
2513 else
2514 rSh.ReRead(sURL, OUString(), &aGraphic);
2515 break;
2517 case SwPasteSdr::SetAttr:
2518 if( rSh.IsObjSelected() )
2519 rSh.Paste( aGraphic, OUString() );
2520 else if( OBJCNT_GRF == rSh.GetObjCntTypeOfSelection() )
2521 rSh.ReRead(sURL, OUString(), &aGraphic);
2522 else
2524 SwTransferable::SetSelInShell( rSh, false, pPt );
2525 rSh.InsertGraphic(sURL, OUString(), aGraphic);
2527 break;
2528 default:
2529 bRet = false;
2533 else
2534 bRet = true;
2537 if( bRet )
2539 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
2540 rSh.GetFlyFrameAttr( aSet );
2541 SwFormatURL aURL( aSet.Get( RES_URL ) );
2543 if( aURL.GetURL() != aINetImg.GetTargetURL() ||
2544 aURL.GetTargetFrameName() != aINetImg.GetTargetFrame() )
2546 aURL.SetURL( aINetImg.GetTargetURL(), false );
2547 aURL.SetTargetFrameName( aINetImg.GetTargetFrame() );
2548 aSet.Put( aURL );
2549 rSh.SetFlyFrameAttr( aSet );
2552 return bRet;
2555 void SwTransferable::SetSelInShell( SwWrtShell& rSh, bool bSelectFrame,
2556 const Point* pPt )
2558 if( bSelectFrame )
2560 // select frames/objects
2561 if( pPt && !rSh.GetView().GetViewFrame().GetDispatcher()->IsLocked() )
2563 rSh.GetView().NoRotate();
2564 if( rSh.SelectObj( *pPt ))
2566 rSh.HideCursor();
2567 rSh.EnterSelFrameMode( pPt );
2568 g_bFrameDrag = true;
2572 else
2574 if( rSh.IsFrameSelected() || rSh.IsObjSelected() )
2576 rSh.UnSelectFrame();
2577 rSh.LeaveSelFrameMode();
2578 rSh.GetView().GetEditWin().StopInsFrame();
2579 g_bFrameDrag = false;
2581 else if( rSh.GetView().GetDrawFuncPtr() )
2582 rSh.GetView().GetEditWin().StopInsFrame();
2584 rSh.EnterStdMode();
2585 if( pPt )
2586 rSh.SwCursorShell::SetCursor( *pPt, true );
2590 bool SwTransferable::PasteDDE( const TransferableDataHelper& rData,
2591 SwWrtShell& rWrtShell, bool bReReadGrf,
2592 bool bMsg )
2594 // data from Clipboardformat
2595 OUString aApp, aTopic, aItem;
2598 tools::SvRef<SotTempStream> xStrm;
2599 if( !rData.GetSotStorageStream( SotClipboardFormatId::LINK, xStrm ))
2601 OSL_ENSURE( false, "DDE Data not found." );
2602 return false;
2603 } // report useful error!!
2605 rtl_TextEncoding eEncoding = osl_getThreadTextEncoding();
2606 aApp = read_zeroTerminated_uInt8s_ToOUString(*xStrm, eEncoding);
2607 aTopic = read_zeroTerminated_uInt8s_ToOUString(*xStrm, eEncoding);
2608 aItem = read_zeroTerminated_uInt8s_ToOUString(*xStrm, eEncoding);
2611 OUString aCmd;
2612 sfx2::MakeLnkName( aCmd, &aApp, aTopic, aItem );
2614 // do we want to read in a graphic now?
2615 SotClipboardFormatId nFormat;
2616 if( !rData.HasFormat( SotClipboardFormatId::RTF ) &&
2617 !rData.HasFormat( SotClipboardFormatId::RICHTEXT ) &&
2618 !rData.HasFormat( SotClipboardFormatId::HTML ) &&
2619 !rData.HasFormat( SotClipboardFormatId::STRING ) &&
2620 (rData.HasFormat( nFormat = SotClipboardFormatId::GDIMETAFILE ) ||
2621 rData.HasFormat( nFormat = SotClipboardFormatId::BITMAP )) )
2623 Graphic aGrf;
2624 bool bRet = rData.GetGraphic( nFormat, aGrf );
2625 if( bRet )
2627 OUString sLnkTyp("DDE");
2628 if ( bReReadGrf )
2629 rWrtShell.ReRead( aCmd, sLnkTyp, &aGrf );
2630 else
2631 rWrtShell.InsertGraphic( aCmd, sLnkTyp, aGrf );
2633 return bRet;
2636 SwFieldType* pTyp = nullptr;
2637 size_t i = 1;
2638 size_t j;
2639 OUString aName;
2640 bool bDoublePaste = false;
2641 const size_t nSize = rWrtShell.GetFieldTypeCount();
2642 const ::utl::TransliterationWrapper& rColl = ::GetAppCmpStrIgnore();
2644 do {
2645 aName = aApp + OUString::number( i );
2646 for( j = INIT_FLDTYPES; j < nSize; j++ )
2648 pTyp = rWrtShell.GetFieldType( j );
2649 if( SwFieldIds::Dde == pTyp->Which() )
2651 if( rColl.isEqual( static_cast<SwDDEFieldType*>(pTyp)->GetCmd(), aCmd ) &&
2652 SfxLinkUpdateMode::ALWAYS == static_cast<SwDDEFieldType*>(pTyp)->GetType() )
2654 aName = pTyp->GetName();
2655 bDoublePaste = true;
2656 break;
2658 else if( rColl.isEqual( aName, pTyp->GetName() ) )
2659 break;
2662 if( j == nSize )
2663 break;
2664 ++i;
2666 while( !bDoublePaste );
2668 if( !bDoublePaste )
2670 SwDDEFieldType aType( aName, aCmd, SfxLinkUpdateMode::ALWAYS );
2671 pTyp = rWrtShell.InsertFieldType( aType );
2674 SwDDEFieldType* pDDETyp = static_cast<SwDDEFieldType*>(pTyp);
2676 OUString aExpand;
2677 if( rData.GetString( SotClipboardFormatId::STRING, aExpand ))
2679 do { // middle checked loop
2681 const sal_Int32 nNewlines{comphelper::string::getTokenCount(aExpand, '\n')};
2682 // When data comes from a spreadsheet, we add a DDE-table
2683 if( !aExpand.isEmpty() &&
2684 ( rData.HasFormat( SotClipboardFormatId::SYLK ) ||
2685 rData.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ) ) )
2687 sal_Int32 nRows = nNewlines ? nNewlines-1 : 0;
2688 if (!aExpand.endsWith("\n"))
2689 ++nRows; // last row has no newline, e.g. one single cell
2690 const sal_Int32 nCols = comphelper::string::getTokenCount(o3tl::getToken(aExpand, 0, '\n'), '\t');
2692 // don't try to insert tables that are too large for writer
2693 if (nRows > SAL_MAX_UINT16 || nCols > SAL_MAX_UINT16)
2695 if( bMsg )
2697 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2698 VclMessageType::Info, VclButtonsType::Ok,
2699 SwResId(STR_TABLE_TOO_LARGE)));
2700 xBox->run();
2702 pDDETyp = nullptr;
2703 break;
2706 // at least one column & row must be there
2707 if( !nRows || !nCols )
2709 if( bMsg )
2711 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2712 VclMessageType::Info, VclButtonsType::Ok,
2713 SwResId(STR_NO_TABLE)));
2714 xBox->run();
2716 pDDETyp = nullptr;
2717 break;
2720 rWrtShell.InsertDDETable(
2721 SwInsertTableOptions( SwInsertTableFlags::SplitLayout, 1 ), // TODO MULTIHEADER
2722 pDDETyp, nRows, nCols );
2724 else if( nNewlines > 1 )
2726 // multiple paragraphs -> insert a protected section
2727 if( rWrtShell.HasSelection() )
2728 rWrtShell.DelRight();
2730 SwSectionData aSect( SectionType::DdeLink, aName );
2731 aSect.SetLinkFileName( aCmd );
2732 aSect.SetProtectFlag(true);
2733 rWrtShell.InsertSection( aSect );
2735 pDDETyp = nullptr; // remove FieldTypes again
2737 else
2739 // insert
2740 SwDDEField aSwDDEField( pDDETyp );
2741 rWrtShell.InsertField2( aSwDDEField );
2744 } while( false );
2746 else
2747 pDDETyp = nullptr; // remove FieldTypes again
2749 if( !pDDETyp && !bDoublePaste )
2751 // remove FieldType again - error occurred!
2752 for( j = nSize; j >= INIT_FLDTYPES; --j )
2753 if( pTyp == rWrtShell.GetFieldType( j ) )
2755 rWrtShell.RemoveFieldType( j );
2756 break;
2760 return true;
2763 bool SwTransferable::PasteSdrFormat( const TransferableDataHelper& rData,
2764 SwWrtShell& rSh, SwPasteSdr nAction,
2765 const Point* pPt, SotExchangeActionFlags nActionFlags, bool bNeedToSelectBeforePaste)
2767 bool bRet = false;
2768 tools::SvRef<SotTempStream> xStrm;
2769 if( rData.GetSotStorageStream( SotClipboardFormatId::DRAWING, xStrm ))
2771 xStrm->SetVersion( SOFFICE_FILEFORMAT_50 );
2773 if(bNeedToSelectBeforePaste && pPt)
2775 // if this is an internal drag, need to set the target right (select it), else
2776 // still the source will be selected
2777 SwTransferable::SetSelInShell( rSh, true, pPt );
2780 rSh.Paste( *xStrm, nAction, pPt );
2781 bRet = true;
2783 if( bRet && ( nActionFlags & SotExchangeActionFlags::InsertTargetUrl ))
2784 SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
2786 return bRet;
2789 bool SwTransferable::PasteGrf( const TransferableDataHelper& rData, SwWrtShell& rSh,
2790 SotClipboardFormatId nFormat, SwPasteSdr nAction, const Point* pPt,
2791 SotExchangeActionFlags nActionFlags, sal_Int8 nDropAction, bool bNeedToSelectBeforePaste, RndStdIds nAnchorType )
2793 bool bRet = false;
2795 Graphic aGraphic;
2796 INetBookmark aBkmk;
2797 bool bCheckForGrf = false, bCheckForImageMap = false;
2799 switch( nFormat )
2801 case SotClipboardFormatId::BITMAP:
2802 case SotClipboardFormatId::PNG:
2803 case SotClipboardFormatId::GDIMETAFILE:
2804 bRet = rData.GetGraphic( nFormat, aGraphic );
2805 break;
2807 case SotClipboardFormatId::SVXB:
2809 tools::SvRef<SotTempStream> xStm;
2811 if(rData.GetSotStorageStream(SotClipboardFormatId::SVXB, xStm))
2813 TypeSerializer aSerializer(*xStm);
2814 aSerializer.readGraphic(aGraphic);
2815 bRet = (GraphicType::NONE != aGraphic.GetType() && GraphicType::Default != aGraphic.GetType());
2818 break;
2821 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
2822 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
2823 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
2824 bRet = rData.GetINetBookmark( nFormat, aBkmk );
2825 if( bRet )
2827 if( SwPasteSdr::SetAttr == nAction )
2828 nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK;
2829 else
2830 bCheckForGrf = true;
2832 break;
2834 case SotClipboardFormatId::SIMPLE_FILE:
2836 OUString sText;
2837 bRet = rData.GetString( nFormat, sText );
2838 if( bRet )
2840 OUString sDesc;
2841 SwTransferable::CheckForURLOrLNKFile( rData, sText, &sDesc );
2843 sText = URIHelper::SmartRel2Abs(INetURLObject(), sText, Link<OUString*, bool>(),
2844 false);
2846 #ifdef _WIN32
2847 // Now that the path could be modified after SwTransferable::CheckForURLOrLNKFile,
2848 // where it could have been converted to URL, and made sure it's actually converted
2849 // to URL in URIHelper::SmartRel2Abs, we can finally convert file: URL back to
2850 // system path to make sure we don't use short path.
2851 // It looks not optimal, when we could apply GetLongPathNameW right to the original
2852 // pasted filename. But I don't know if (1) all arriving strings are system paths;
2853 // and (2) if SwTransferable::CheckForURLOrLNKFile could result in a different short
2854 // path, so taking a safe route.
2855 if (sText.startsWithIgnoreAsciiCase("file:"))
2857 // tdf#124500: Convert short path to long path which should be used in links
2858 OUString sSysPath;
2859 osl::FileBase::getSystemPathFromFileURL(sText, sSysPath);
2860 std::unique_ptr<sal_Unicode[]> aBuf(new sal_Unicode[32767]);
2861 DWORD nCopied = GetLongPathNameW(o3tl::toW(sSysPath.getStr()),
2862 o3tl::toW(aBuf.get()), 32767);
2863 if (nCopied && nCopied < 32767)
2864 sText = URIHelper::SmartRel2Abs(INetURLObject(), OUString(aBuf.get()),
2865 Link<OUString*, bool>(), false);
2867 #endif
2869 aBkmk = INetBookmark(sText, sDesc);
2870 bCheckForGrf = true;
2871 bCheckForImageMap = SwPasteSdr::Replace == nAction;
2874 break;
2876 default:
2877 bRet = rData.GetGraphic( nFormat, aGraphic );
2878 break;
2881 if( bCheckForGrf )
2883 //!!! check at FileSystem - only then it makes sense to test the graphics !!!
2884 GraphicFilter &rFlt = GraphicFilter::GetGraphicFilter();
2885 bRet = ERRCODE_NONE == GraphicFilter::LoadGraphic(aBkmk.GetURL(), OUString(),
2886 aGraphic, &rFlt );
2888 if( !bRet && SwPasteSdr::SetAttr == nAction &&
2889 SotClipboardFormatId::SIMPLE_FILE == nFormat &&
2890 // only at frame selection
2891 rSh.IsFrameSelected() )
2893 // then set as hyperlink after the graphic
2894 nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK;
2895 bRet = true;
2899 if(pPt && bNeedToSelectBeforePaste)
2901 // when using internal D&Ds, still the source object is selected and
2902 // this is necessary to get the correct source data which is also
2903 // dependent from selection. After receiving the drag data it is
2904 // now time to select the correct target object
2905 SwTransferable::SetSelInShell( rSh, true, pPt );
2908 if( bRet )
2910 //Check and Perform rotation if needed
2911 lclCheckAndPerformRotation(aGraphic);
2913 OUString sURL;
2914 if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr
2915 // #i123922# if link action is noted, also take URL
2916 || DND_ACTION_LINK == nDropAction)
2918 sURL = aBkmk.GetURL();
2921 switch( nAction )
2923 case SwPasteSdr::Insert:
2925 SwTransferable::SetSelInShell( rSh, false, pPt );
2926 rSh.InsertGraphic(sURL, OUString(), aGraphic, nullptr, nAnchorType);
2927 break;
2930 case SwPasteSdr::Replace:
2932 if( rSh.IsObjSelected() )
2934 // #i123922# for D&D on draw objects, do for now the same for
2935 // SwPasteSdr::Replace (D&D) as for SwPasteSdr::SetAttr (D&D and
2936 // CTRL+SHIFT). The code below replaces the draw object with
2937 // a writer graphic; maybe this is an option later again if wanted
2938 rSh.Paste( aGraphic, sURL );
2940 // rSh.ReplaceSdrObj(sURL, OUString(), &aGraphic);
2941 // Point aPt( pPt ? *pPt : rSh.GetCursorDocPos() );
2942 // SwTransferable::SetSelInShell( rSh, true, &aPt );
2944 else
2946 // set graphic at writer graphic without link
2947 rSh.ReRead(sURL, OUString(), &aGraphic);
2950 break;
2953 case SwPasteSdr::SetAttr:
2955 if( SotClipboardFormatId::NETSCAPE_BOOKMARK == nFormat )
2957 if( rSh.IsFrameSelected() )
2959 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
2960 rSh.GetFlyFrameAttr( aSet );
2961 SwFormatURL aURL( aSet.Get( RES_URL ) );
2962 aURL.SetURL( aBkmk.GetURL(), false );
2963 aSet.Put( aURL );
2964 rSh.SetFlyFrameAttr( aSet );
2967 else if( rSh.IsObjSelected() )
2969 // set as attribute at DrawObject
2970 rSh.Paste( aGraphic, sURL );
2972 else if( OBJCNT_GRF == rSh.GetObjCntTypeOfSelection() )
2974 // set as linked graphic at writer graphic frame
2975 rSh.ReRead(sURL, OUString(), &aGraphic);
2977 else
2979 SwTransferable::SetSelInShell( rSh, false, pPt );
2980 rSh.InsertGraphic(aBkmk.GetURL(), OUString(), aGraphic);
2982 break;
2984 default:
2986 bRet = false;
2987 break;
2992 if( bRet )
2995 if( nActionFlags &
2996 ( SotExchangeActionFlags::InsertImageMap | SotExchangeActionFlags::ReplaceImageMap ) )
2997 SwTransferable::PasteImageMap( rData, rSh );
2999 if( nActionFlags & SotExchangeActionFlags::InsertTargetUrl )
3000 SwTransferable::PasteTargetURL( rData, rSh, SwPasteSdr::NONE, nullptr, false );
3002 else if( bCheckForImageMap )
3004 // or should the file be an ImageMap-File?
3005 ImageMap aMap;
3006 SfxMedium aMed( INetURLObject(aBkmk.GetURL()).GetFull(),
3007 StreamMode::STD_READ );
3008 SvStream* pStream = aMed.GetInStream();
3009 if( pStream != nullptr &&
3010 !pStream->GetError() &&
3011 // mba: no BaseURL for clipboard functionality
3012 aMap.Read( *pStream, IMapFormat::Detect ) == IMAP_ERR_OK &&
3013 aMap.GetIMapObjectCount() )
3015 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3016 rSh.GetFlyFrameAttr( aSet );
3017 SwFormatURL aURL( aSet.Get( RES_URL ) );
3018 aURL.SetMap( &aMap );
3019 aSet.Put( aURL );
3020 rSh.SetFlyFrameAttr( aSet );
3021 bRet = true;
3025 return bRet;
3028 bool SwTransferable::PasteImageMap( const TransferableDataHelper& rData,
3029 SwWrtShell& rSh )
3031 bool bRet = false;
3032 if( rData.HasFormat( SotClipboardFormatId::SVIM ))
3034 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3035 rSh.GetFlyFrameAttr( aSet );
3036 SwFormatURL aURL( aSet.Get( RES_URL ) );
3037 const ImageMap* pOld = aURL.GetMap();
3039 // set or replace, that is the question
3040 ImageMap aImageMap;
3041 if( rData.GetImageMap( SotClipboardFormatId::SVIM, aImageMap ) &&
3042 ( !pOld || aImageMap != *pOld ))
3044 aURL.SetMap( &aImageMap );
3045 aSet.Put( aURL );
3046 rSh.SetFlyFrameAttr( aSet );
3048 bRet = true;
3050 return bRet;
3053 bool SwTransferable::PasteAsHyperlink( const TransferableDataHelper& rData,
3054 SwWrtShell& rSh, SotClipboardFormatId nFormat )
3056 bool bRet = false;
3057 OUString sFile;
3058 if( rData.GetString( nFormat, sFile ) && !sFile.isEmpty() )
3060 OUString sDesc;
3061 SwTransferable::CheckForURLOrLNKFile( rData, sFile, &sDesc );
3063 // first, make the URL absolute
3064 INetURLObject aURL;
3065 aURL.SetSmartProtocol( INetProtocol::File );
3066 aURL.SetSmartURL( sFile );
3067 sFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
3069 switch( rSh.GetObjCntTypeOfSelection() )
3071 case OBJCNT_FLY:
3072 case OBJCNT_GRF:
3073 case OBJCNT_OLE:
3075 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3076 rSh.GetFlyFrameAttr( aSet );
3077 SwFormatURL aURL2( aSet.Get( RES_URL ) );
3078 aURL2.SetURL( sFile, false );
3079 if( aURL2.GetName().isEmpty() )
3080 aURL2.SetName( sFile );
3081 aSet.Put( aURL2 );
3082 rSh.SetFlyFrameAttr( aSet );
3084 break;
3086 default:
3088 rSh.InsertURL( SwFormatINetFormat( sFile, OUString() ),
3089 sDesc.isEmpty() ? sFile : sDesc);
3092 bRet = true;
3094 return bRet;
3097 bool SwTransferable::PasteFileName( TransferableDataHelper& rData,
3098 SwWrtShell& rSh, SotClipboardFormatId nFormat,
3099 SwPasteSdr nAction, const Point* pPt,
3100 SotExchangeActionFlags nActionFlags,
3101 bool * graphicInserted)
3103 bool bRet = SwTransferable::PasteGrf( rData, rSh, nFormat, nAction,
3104 pPt, nActionFlags, 0, false);
3105 if (graphicInserted != nullptr) {
3106 *graphicInserted = bRet;
3108 if( !bRet )
3110 OUString sFile, sDesc;
3111 if( rData.GetString( nFormat, sFile ) && !sFile.isEmpty() )
3113 #if HAVE_FEATURE_AVMEDIA
3114 INetURLObject aMediaURL;
3116 aMediaURL.SetSmartURL( sFile );
3117 const OUString aMediaURLStr( aMediaURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
3119 if( ::avmedia::MediaWindow::isMediaURL( aMediaURLStr, ""/*TODO?*/ ) )
3121 const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, aMediaURLStr );
3122 rSh.GetView().GetViewFrame().GetDispatcher()->ExecuteList(
3123 SID_INSERT_AVMEDIA, SfxCallMode::SYNCHRON,
3124 { &aMediaURLItem });
3126 #else
3127 if (false)
3130 #endif
3131 else
3133 bool bIsURLFile = SwTransferable::CheckForURLOrLNKFile( rData, sFile, &sDesc );
3135 //Own FileFormat? --> insert, not for StarWriter/Web
3136 OUString sFileURL = URIHelper::SmartRel2Abs(INetURLObject(), sFile, Link<OUString *, bool>(), false );
3137 std::shared_ptr<const SfxFilter> pFlt = SwPasteSdr::SetAttr == nAction
3138 ? nullptr : SwIoSystem::GetFileFilter(sFileURL);
3139 if( pFlt && dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) == nullptr )
3141 // and then pull up the insert-region-dialog
3142 SwSectionData aSect(
3143 SectionType::FileLink,
3144 rSh.GetDoc()->GetUniqueSectionName() );
3145 aSect.SetLinkFileName( sFileURL );
3146 aSect.SetProtectFlag( true );
3148 rSh.StartInsertRegionDialog( aSect ); // starts dialog asynchronously
3149 bRet = true;
3151 else if (SwPasteSdr::Insert == nAction && rData.HasFormat(SotClipboardFormatId::SIMPLE_FILE))
3153 // insert file as OLE
3154 PasteOLE(rData, rSh, nFormat, nActionFlags, nullptr == pPt);
3156 else if( SwPasteSdr::SetAttr == nAction ||
3157 ( bIsURLFile && SwPasteSdr::Insert == nAction ))
3159 //we can insert foreign files as links after all
3161 // first, make the URL absolute
3162 INetURLObject aURL;
3163 aURL.SetSmartProtocol( INetProtocol::File );
3164 aURL.SetSmartURL( sFile );
3165 sFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
3167 switch( rSh.GetObjCntTypeOfSelection() )
3169 case OBJCNT_FLY:
3170 case OBJCNT_GRF:
3171 case OBJCNT_OLE:
3173 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3174 rSh.GetFlyFrameAttr( aSet );
3175 SwFormatURL aURL2( aSet.Get( RES_URL ) );
3176 aURL2.SetURL( sFile, false );
3177 if( aURL2.GetName().isEmpty() )
3178 aURL2.SetName( sFile );
3179 aSet.Put( aURL2 );
3180 rSh.SetFlyFrameAttr( aSet );
3182 break;
3184 default:
3186 rSh.InsertURL( SwFormatINetFormat( sFile, OUString() ),
3187 sDesc.isEmpty() ? sFile : sDesc );
3190 bRet = true;
3195 return bRet;
3198 bool SwTransferable::PasteDBData( const TransferableDataHelper& rData,
3199 SwWrtShell& rSh, SotClipboardFormatId nFormat, bool bLink,
3200 const Point* pDragPt, bool bMsg )
3202 bool bRet = false;
3203 OUString sText;
3204 if( rData.GetString( nFormat, sText ) && !sText.isEmpty() )
3206 sal_uInt16 nWh = SotClipboardFormatId::SBA_CTRLDATAEXCHANGE == nFormat
3208 : SotClipboardFormatId::SBA_DATAEXCHANGE == nFormat
3209 ? (bLink
3210 ? FN_QRY_MERGE_FIELD
3211 : FN_QRY_INSERT)
3212 : (bLink
3214 : FN_QRY_INSERT_FIELD );
3215 const DataFlavorExVector& rVector = rData.GetDataFlavorExVector();
3216 bool bHaveColumnDescriptor = OColumnTransferable::canExtractColumnDescriptor(rVector, ColumnTransferFormatFlags::COLUMN_DESCRIPTOR | ColumnTransferFormatFlags::CONTROL_EXCHANGE);
3217 if ( SotClipboardFormatId::XFORMS == nFormat )
3219 rSh.MakeDrawView();
3220 FmFormView* pFmView = dynamic_cast<FmFormView*>( rSh.GetDrawView() );
3221 if (pFmView && pDragPt)
3223 OXFormsDescriptor aDesc = OXFormsTransferable::extractDescriptor(rData);
3224 rtl::Reference<SdrObject> pObj = pFmView->CreateXFormsControl(aDesc);
3225 if(pObj)
3227 rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt );
3231 else if( nWh )
3233 std::unique_ptr<SfxUnoAnyItem> pConnectionItem;
3234 std::unique_ptr<SfxUnoAnyItem> pCursorItem;
3235 std::unique_ptr<SfxUnoAnyItem> pColumnItem;
3236 std::unique_ptr<SfxUnoAnyItem> pSourceItem;
3237 std::unique_ptr<SfxUnoAnyItem> pCommandItem;
3238 std::unique_ptr<SfxUnoAnyItem> pCommandTypeItem;
3239 std::unique_ptr<SfxUnoAnyItem> pColumnNameItem;
3240 std::unique_ptr<SfxUnoAnyItem> pSelectionItem;
3242 bool bDataAvailable = true;
3243 ODataAccessDescriptor aDesc;
3244 if(bHaveColumnDescriptor)
3245 aDesc = OColumnTransferable::extractColumnDescriptor(rData);
3246 else if(ODataAccessObjectTransferable::canExtractObjectDescriptor(rVector) )
3247 aDesc = ODataAccessObjectTransferable::extractObjectDescriptor(rData);
3248 else
3249 bDataAvailable = false;
3251 if ( bDataAvailable )
3253 pConnectionItem.reset(new SfxUnoAnyItem(FN_DB_CONNECTION_ANY, aDesc[DataAccessDescriptorProperty::Connection]));
3254 pColumnItem.reset(new SfxUnoAnyItem(FN_DB_COLUMN_ANY, aDesc[DataAccessDescriptorProperty::ColumnObject]));
3255 pSourceItem.reset(new SfxUnoAnyItem(FN_DB_DATA_SOURCE_ANY, Any(aDesc.getDataSource())));
3256 pCommandItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COMMAND_ANY, aDesc[DataAccessDescriptorProperty::Command]));
3257 pCommandTypeItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COMMAND_TYPE_ANY, aDesc[DataAccessDescriptorProperty::CommandType]));
3258 pColumnNameItem.reset(new SfxUnoAnyItem(FN_DB_DATA_COLUMN_NAME_ANY, aDesc[DataAccessDescriptorProperty::ColumnName]));
3259 pSelectionItem.reset(new SfxUnoAnyItem(FN_DB_DATA_SELECTION_ANY, aDesc[DataAccessDescriptorProperty::Selection]));
3260 pCursorItem.reset(new SfxUnoAnyItem(FN_DB_DATA_CURSOR_ANY, aDesc[DataAccessDescriptorProperty::Cursor]));
3263 SwView& rView = rSh.GetView();
3264 //force ::SelectShell
3265 rView.StopShellTimer();
3267 SfxStringItem aDataDesc( nWh, sText );
3268 rView.GetViewFrame().GetDispatcher()->ExecuteList(
3269 nWh, SfxCallMode::ASYNCHRON,
3270 { &aDataDesc, pConnectionItem.get(), pColumnItem.get(),
3271 pSourceItem.get(), pCommandItem.get(), pCommandTypeItem.get(),
3272 pColumnNameItem.get(), pSelectionItem.get(),
3273 pCursorItem.get() });
3275 else
3277 rSh.MakeDrawView();
3278 FmFormView* pFmView = dynamic_cast<FmFormView*>( rSh.GetDrawView() );
3279 if (pFmView && bHaveColumnDescriptor && pDragPt)
3281 rtl::Reference<SdrObject> pObj = pFmView->CreateFieldControl( OColumnTransferable::extractColumnDescriptor(rData) );
3282 if (pObj)
3283 rSh.SwFEShell::InsertDrawObj( *pObj, *pDragPt );
3286 bRet = true;
3288 else if( bMsg )
3290 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
3291 VclMessageType::Info, VclButtonsType::Ok,
3292 SwResId(STR_CLPBRD_FORMAT_ERROR)));
3293 xBox->run();
3295 return bRet;
3298 bool SwTransferable::PasteFileList( const TransferableDataHelper& rData,
3299 SwWrtShell& rSh, bool bLink,
3300 const Point* pPt, bool bMsg )
3302 bool bRet = false;
3303 FileList aFileList;
3304 if( rData.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList ) &&
3305 aFileList.Count() )
3307 SwPasteSdr nAct = bLink ? SwPasteSdr::SetAttr : SwPasteSdr::Insert;
3308 OUString sFlyNm;
3309 // iterate over the filelist
3310 for( sal_uLong n = 0, nEnd = aFileList.Count(); n < nEnd; ++n )
3312 rtl::Reference<TransferDataContainer> pHlp = new TransferDataContainer;
3313 pHlp->CopyString( SotClipboardFormatId::SIMPLE_FILE, aFileList.GetFile( n ));
3314 TransferableDataHelper aData( pHlp );
3316 if( SwTransferable::PasteFileName( aData, rSh, SotClipboardFormatId::SIMPLE_FILE, nAct,
3317 pPt, SotExchangeActionFlags::NONE, nullptr ))
3319 if( bLink )
3321 sFlyNm = rSh.GetFlyName();
3322 SwTransferable::SetSelInShell( rSh, false, pPt );
3324 bRet = true;
3327 if( !sFlyNm.isEmpty() )
3328 rSh.GotoFly( sFlyNm );
3330 else if( bMsg )
3332 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
3333 VclMessageType::Info, VclButtonsType::Ok,
3334 SwResId(STR_CLPBRD_FORMAT_ERROR)));
3335 xBox->run();
3337 return bRet;
3340 bool SwTransferable::CheckForURLOrLNKFile( const TransferableDataHelper& rData,
3341 OUString& rFileName, OUString* pTitle )
3343 bool bIsURLFile = false;
3344 INetBookmark aBkmk;
3345 if( rData.GetINetBookmark( SotClipboardFormatId::SOLK, aBkmk ) )
3347 rFileName = aBkmk.GetURL();
3348 if( pTitle )
3349 *pTitle = aBkmk.GetDescription();
3350 bIsURLFile = true;
3352 else
3354 if( rFileName.getLength()>4 && rFileName.endsWithIgnoreAsciiCase(".url") )
3356 OSL_ENSURE( false, "how do we read today .URL - Files?" );
3359 return bIsURLFile;
3362 bool SwTransferable::IsPasteSpecial( const SwWrtShell& rWrtShell,
3363 const TransferableDataHelper& rData )
3365 // we can paste-special if there's an entry in the paste-special-format list
3366 SvxClipboardFormatItem aClipboardFormatItem(TypedWhichId<SvxClipboardFormatItem>(0));
3367 FillClipFormatItem( rWrtShell, rData, aClipboardFormatItem);
3368 return aClipboardFormatItem.Count() > 0;
3371 bool SwTransferable::IsPasteOwnFormat( const TransferableDataHelper& rData )
3373 return ( GetSwTransferable( rData ) != nullptr );
3376 bool SwTransferable::PasteFormat( SwWrtShell& rSh,
3377 TransferableDataHelper& rData,
3378 SotClipboardFormatId nFormat )
3380 SwWait aWait( *rSh.GetView().GetDocShell(), false );
3381 bool bRet = false;
3383 SotClipboardFormatId nPrivateFormat = SotClipboardFormatId::PRIVATE;
3384 SwTransferable *pClipboard = GetSwTransferable( rData );
3385 if( pClipboard &&
3386 ((TransferBufferType::Document|TransferBufferType::Graphic|TransferBufferType::Ole) & pClipboard->m_eBufferType ))
3387 nPrivateFormat = SotClipboardFormatId::EMBED_SOURCE;
3389 if( pClipboard && nPrivateFormat == nFormat )
3390 bRet = pClipboard->PrivatePaste( rSh );
3391 else if( rData.HasFormat( nFormat ) )
3393 uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
3394 sal_uInt8 nEventAction;
3395 SotExchangeDest nDestination = SwTransferable::GetSotDestination( rSh );
3396 sal_uInt16 nSourceOptions =
3397 (( SotExchangeDest::DOC_TEXTFRAME == nDestination ||
3398 SotExchangeDest::SWDOC_FREE_AREA == nDestination ||
3399 SotExchangeDest::DOC_TEXTFRAME_WEB == nDestination ||
3400 SotExchangeDest::SWDOC_FREE_AREA_WEB == nDestination )
3401 ? EXCHG_IN_ACTION_COPY
3402 : EXCHG_IN_ACTION_MOVE);
3403 SotExchangeActionFlags nActionFlags;
3404 sal_uInt8 nAction = SotExchange::GetExchangeAction(
3405 rData.GetDataFlavorExVector(),
3406 nDestination,
3407 nSourceOptions, /* ?? */
3408 EXCHG_IN_ACTION_DEFAULT, /* ?? */
3409 nFormat, nEventAction, nFormat,
3410 lcl_getTransferPointer ( xTransferable ),
3411 &nActionFlags );
3413 if( EXCHG_INOUT_ACTION_NONE != nAction )
3414 bRet = SwTransferable::PasteData( rData, rSh, nAction, nActionFlags, nFormat,
3415 nDestination, true, false );
3417 return bRet;
3420 bool SwTransferable::TestAllowedFormat( const TransferableDataHelper& rData,
3421 SotClipboardFormatId nFormat, SotExchangeDest nDestination )
3423 sal_uInt8 nAction = EXCHG_INOUT_ACTION_NONE;
3424 if( rData.HasFormat( nFormat )) {
3425 uno::Reference<XTransferable> xTransferable( rData.GetXTransferable() );
3426 sal_uInt8 nEventAction;
3427 nAction = SotExchange::GetExchangeAction(
3428 rData.GetDataFlavorExVector(),
3429 nDestination, EXCHG_IN_ACTION_COPY,
3430 EXCHG_IN_ACTION_COPY, nFormat,
3431 nEventAction, nFormat,
3432 lcl_getTransferPointer ( xTransferable ) );
3434 return EXCHG_INOUT_ACTION_NONE != nAction;
3438 * the list of formats which will be offered to the user in the 'Paste
3439 * Special...' dialog and the paste button menu
3441 static SotClipboardFormatId aPasteSpecialIds[] =
3443 SotClipboardFormatId::HTML,
3444 SotClipboardFormatId::HTML_SIMPLE,
3445 SotClipboardFormatId::HTML_NO_COMMENT,
3446 SotClipboardFormatId::RTF,
3447 SotClipboardFormatId::RICHTEXT,
3448 SotClipboardFormatId::STRING,
3449 SotClipboardFormatId::SONLK,
3450 SotClipboardFormatId::NETSCAPE_BOOKMARK,
3451 SotClipboardFormatId::DRAWING,
3452 SotClipboardFormatId::SVXB,
3453 SotClipboardFormatId::GDIMETAFILE,
3454 SotClipboardFormatId::BITMAP,
3455 SotClipboardFormatId::SVIM,
3456 SotClipboardFormatId::FILEGRPDESCRIPTOR,
3457 SotClipboardFormatId::NONE
3460 bool SwTransferable::PasteUnformatted( SwWrtShell& rSh, TransferableDataHelper& rData )
3462 // Plain text == unformatted
3463 return SwTransferable::PasteFormat( rSh, rData, SotClipboardFormatId::STRING );
3466 void SwTransferable::PrePasteSpecial( const SwWrtShell& rSh, TransferableDataHelper& rData, const VclPtr<SfxAbstractPasteDialog>& pDlg )
3468 DataFlavorExVector aFormats( rData.GetDataFlavorExVector() );
3469 TransferableObjectDescriptor aDesc;
3471 SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh );
3473 SwTransferable *pClipboard = GetSwTransferable( rData );
3474 if( pClipboard )
3476 aDesc = pClipboard->m_aObjDesc;
3477 TranslateId pResId;
3478 if( pClipboard->m_eBufferType & TransferBufferType::Document )
3479 pResId = STR_PRIVATETEXT;
3480 else if( pClipboard->m_eBufferType & TransferBufferType::Graphic )
3481 pResId = STR_PRIVATEGRAPHIC;
3482 else if( pClipboard->m_eBufferType == TransferBufferType::Ole )
3483 pResId = STR_PRIVATEOLE;
3485 if (pResId)
3487 if (STR_PRIVATEOLE == pResId || STR_PRIVATEGRAPHIC == pResId)
3489 // add SotClipboardFormatId::EMBED_SOURCE to the formats. This
3490 // format display then the private format name.
3491 DataFlavorEx aFlavorEx;
3492 aFlavorEx.mnSotId = SotClipboardFormatId::EMBED_SOURCE;
3493 aFormats.insert( aFormats.begin(), aFlavorEx );
3495 pDlg->SetObjName( pClipboard->m_aObjDesc.maClassName,
3496 SwResId(pResId) );
3497 pDlg->Insert( SotClipboardFormatId::EMBED_SOURCE, OUString() );
3500 else
3502 if( rData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
3504 (void)rData.GetTransferableObjectDescriptor(
3505 SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc );
3508 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::EMBED_SOURCE, nDest ))
3509 pDlg->Insert( SotClipboardFormatId::EMBED_SOURCE, OUString() );
3510 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK_SOURCE, nDest ))
3511 pDlg->Insert( SotClipboardFormatId::LINK_SOURCE, OUString() );
3514 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK, nDest ))
3515 pDlg->Insert( SotClipboardFormatId::LINK, SwResId(STR_DDEFORMAT) );
3517 for( SotClipboardFormatId* pIds = aPasteSpecialIds; *pIds != SotClipboardFormatId::NONE; ++pIds )
3518 if( SwTransferable::TestAllowedFormat( rData, *pIds, nDest ))
3519 pDlg->Insert( *pIds, OUString() );
3522 void SwTransferable::FillClipFormatItem( const SwWrtShell& rSh,
3523 const TransferableDataHelper& rData,
3524 SvxClipboardFormatItem & rToFill )
3526 SotExchangeDest nDest = SwTransferable::GetSotDestination( rSh );
3528 SwTransferable *pClipboard = GetSwTransferable( rData );
3529 if( pClipboard )
3531 TranslateId pResId;
3532 if( pClipboard->m_eBufferType & TransferBufferType::Document )
3533 pResId = STR_PRIVATETEXT;
3534 else if( pClipboard->m_eBufferType & TransferBufferType::Graphic )
3535 pResId = STR_PRIVATEGRAPHIC;
3536 else if( pClipboard->m_eBufferType == TransferBufferType::Ole )
3537 pResId = STR_PRIVATEOLE;
3539 if (pResId)
3540 rToFill.AddClipbrdFormat(SotClipboardFormatId::EMBED_SOURCE,
3541 SwResId(pResId));
3543 else
3545 TransferableObjectDescriptor aDesc;
3546 if (rData.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
3548 (void)const_cast<TransferableDataHelper&>(rData).GetTransferableObjectDescriptor(
3549 SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc);
3552 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::EMBED_SOURCE, nDest ))
3553 rToFill.AddClipbrdFormat( SotClipboardFormatId::EMBED_SOURCE,
3554 aDesc.maTypeName );
3555 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK_SOURCE, nDest ))
3556 rToFill.AddClipbrdFormat( SotClipboardFormatId::LINK_SOURCE );
3558 SotClipboardFormatId nFormat;
3559 if ( rData.HasFormat(nFormat = SotClipboardFormatId::EMBED_SOURCE_OLE) || rData.HasFormat(nFormat = SotClipboardFormatId::EMBEDDED_OBJ_OLE) )
3561 OUString sName,sSource;
3562 if ( SvPasteObjectHelper::GetEmbeddedName(rData,sName,sSource,nFormat) )
3563 rToFill.AddClipbrdFormat( nFormat, sName );
3567 if( SwTransferable::TestAllowedFormat( rData, SotClipboardFormatId::LINK, nDest ))
3568 rToFill.AddClipbrdFormat( SotClipboardFormatId::LINK, SwResId(STR_DDEFORMAT) );
3570 for( SotClipboardFormatId* pIds = aPasteSpecialIds; *pIds != SotClipboardFormatId::NONE; ++pIds )
3571 if( SwTransferable::TestAllowedFormat( rData, *pIds, nDest ))
3572 rToFill.AddClipbrdFormat(*pIds, OUString());
3575 void SwTransferable::SetDataForDragAndDrop( const Point& rSttPos )
3577 if(!m_pWrtShell)
3578 return;
3579 OUString sGrfNm;
3580 const SelectionType nSelection = m_pWrtShell->GetSelectionType();
3581 if( SelectionType::Graphic == nSelection)
3583 AddFormat( SotClipboardFormatId::SVXB );
3584 const Graphic* pGrf = m_pWrtShell->GetGraphic();
3585 if ( pGrf && pGrf->IsSupportedGraphic() )
3587 AddFormat( SotClipboardFormatId::GDIMETAFILE );
3588 AddFormat( SotClipboardFormatId::PNG );
3589 AddFormat( SotClipboardFormatId::BITMAP );
3591 m_eBufferType = TransferBufferType::Graphic;
3592 m_pWrtShell->GetGrfNms( &sGrfNm, nullptr );
3594 else if( SelectionType::Ole == nSelection )
3596 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
3597 PrepareOLE( m_aObjDesc );
3598 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
3599 AddFormat( SotClipboardFormatId::GDIMETAFILE );
3600 m_eBufferType = TransferBufferType::Ole;
3602 //Is there anything to provide anyway?
3603 else if ( m_pWrtShell->IsSelection() || m_pWrtShell->IsFrameSelected() ||
3604 m_pWrtShell->IsObjSelected() )
3606 if( m_pWrtShell->IsObjSelected() )
3607 m_eBufferType = TransferBufferType::Drawing;
3608 else
3610 m_eBufferType = TransferBufferType::Document;
3611 if( SwWrtShell::NO_WORD !=
3612 m_pWrtShell->IntelligentCut( nSelection, false ))
3613 m_eBufferType = TransferBufferType::DocumentWord | m_eBufferType;
3616 if( nSelection & SelectionType::TableCell )
3617 m_eBufferType = TransferBufferType::Table | m_eBufferType;
3619 AddFormat( SotClipboardFormatId::EMBED_SOURCE );
3621 //put RTF ahead of the OLE's Metafile for less loss
3622 if( !m_pWrtShell->IsObjSelected() )
3624 AddFormat( SotClipboardFormatId::RTF );
3625 AddFormat( SotClipboardFormatId::RICHTEXT );
3626 AddFormat( SotClipboardFormatId::HTML );
3628 if( m_pWrtShell->IsSelection() )
3629 AddFormat( SotClipboardFormatId::STRING );
3631 if( nSelection & ( SelectionType::DrawObject | SelectionType::DbForm ))
3633 AddFormat( SotClipboardFormatId::DRAWING );
3634 if ( nSelection & SelectionType::DrawObject )
3636 AddFormat( SotClipboardFormatId::GDIMETAFILE );
3637 AddFormat( SotClipboardFormatId::PNG );
3638 AddFormat( SotClipboardFormatId::BITMAP );
3640 m_eBufferType = TransferBufferType::Graphic | m_eBufferType;
3642 // is it a URL-Button ?
3643 OUString sURL;
3644 OUString sDesc;
3645 if( m_pWrtShell->GetURLFromButton( sURL, sDesc ) )
3647 AddFormat( SotClipboardFormatId::STRING );
3648 AddFormat( SotClipboardFormatId::SOLK );
3649 AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
3650 AddFormat( SotClipboardFormatId::FILECONTENT );
3651 AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
3652 AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
3653 m_eBufferType = TransferBufferType::InetField | m_eBufferType;
3657 //ObjectDescriptor was already filled from the old DocShell.
3658 //Now adjust it. Thus in GetData the first query can still
3659 //be answered with delayed rendering.
3660 m_aObjDesc.maDragStartPos = rSttPos;
3661 m_aObjDesc.maSize = constOleSize100mm;
3663 PrepareOLE( m_aObjDesc );
3664 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
3666 else if( nSelection & SelectionType::Text && !m_pWrtShell->HasMark() )
3668 // is only one field - selected?
3669 SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
3670 Point aPos( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY());
3672 if( m_pWrtShell->GetContentAtPos( aPos, aContentAtPos ) )
3674 AddFormat( SotClipboardFormatId::STRING );
3675 AddFormat( SotClipboardFormatId::SOLK );
3676 AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
3677 AddFormat( SotClipboardFormatId::FILECONTENT );
3678 AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
3679 AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
3680 m_eBufferType = TransferBufferType::InetField;
3684 if( !m_pWrtShell->IsFrameSelected() )
3685 return;
3687 SfxItemSetFixed<RES_URL, RES_URL> aSet( m_pWrtShell->GetAttrPool() );
3688 m_pWrtShell->GetFlyFrameAttr( aSet );
3689 const SwFormatURL& rURL = aSet.Get( RES_URL );
3690 if( rURL.GetMap() )
3692 m_pImageMap.reset( new ImageMap( *rURL.GetMap() ) );
3693 AddFormat( SotClipboardFormatId::SVIM );
3695 else if( !rURL.GetURL().isEmpty() )
3697 m_pTargetURL.reset(new INetImage( sGrfNm, rURL.GetURL(),
3698 rURL.GetTargetFrameName() ));
3699 AddFormat( SotClipboardFormatId::INET_IMAGE );
3703 void SwTransferable::StartDrag( vcl::Window* pWin, const Point& rPos )
3705 if(!m_pWrtShell)
3706 return;
3707 m_bOldIdle = m_pWrtShell->GetViewOptions()->IsIdle();
3708 m_bCleanUp = true;
3710 m_pWrtShell->GetViewOptions()->SetIdle( false );
3712 if( m_pWrtShell->IsSelFrameMode() )
3713 m_pWrtShell->ShowCursor();
3715 SW_MOD()->m_pDragDrop = this;
3717 SetDataForDragAndDrop( rPos );
3719 sal_Int8 nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
3720 SwDocShell* pDShell = m_pWrtShell->GetView().GetDocShell();
3721 if( ( pDShell && pDShell->IsReadOnly() ) || m_pWrtShell->HasReadonlySel() )
3722 nDragOptions &= ~DND_ACTION_MOVE;
3724 TransferableHelper::StartDrag( pWin, nDragOptions );
3727 void SwTransferable::DragFinished( sal_Int8 nAction )
3729 //And the last finishing work so that all statuses are right
3730 if( DND_ACTION_MOVE == nAction )
3732 if( m_bCleanUp )
3734 //It was dropped outside of Writer. We still have to
3735 //delete.
3737 m_pWrtShell->StartAllAction();
3738 m_pWrtShell->StartUndo( SwUndoId::UI_DRAG_AND_MOVE );
3739 if ( m_pWrtShell->IsTableMode() )
3740 m_pWrtShell->DeleteTableSel();
3741 else
3743 if ( !(m_pWrtShell->IsSelFrameMode() || m_pWrtShell->IsObjSelected()) )
3744 //SmartCut, take one of the blanks along
3745 m_pWrtShell->IntelligentCut( m_pWrtShell->GetSelectionType() );
3746 m_pWrtShell->DelRight();
3748 m_pWrtShell->EndUndo( SwUndoId::UI_DRAG_AND_MOVE );
3749 m_pWrtShell->EndAllAction();
3751 else
3753 const SelectionType nSelection = m_pWrtShell->GetSelectionType();
3754 if( ( SelectionType::Frame | SelectionType::Graphic |
3755 SelectionType::Ole | SelectionType::DrawObject ) & nSelection )
3757 m_pWrtShell->EnterSelFrameMode();
3761 m_pWrtShell->GetView().GetEditWin().DragFinished();
3763 if( m_pWrtShell->IsSelFrameMode() )
3764 m_pWrtShell->HideCursor();
3765 else
3766 m_pWrtShell->ShowCursor();
3768 m_pWrtShell->GetViewOptions()->SetIdle( m_bOldIdle );
3771 namespace
3774 bool lcl_checkClassification(SwDoc* pSourceDoc, SwDoc* pDestinationDoc)
3776 if (!pSourceDoc || !pDestinationDoc)
3777 return true;
3779 SwDocShell* pSourceShell = pSourceDoc->GetDocShell();
3780 SwDocShell* pDestinationShell = pDestinationDoc->GetDocShell();
3781 if (!pSourceShell || !pDestinationShell)
3782 return true;
3784 SfxClassificationCheckPasteResult eResult = SfxClassificationHelper::CheckPaste(pSourceShell->getDocProperties(), pDestinationShell->getDocProperties());
3785 return SfxClassificationHelper::ShowPasteInfo(eResult);
3790 bool SwTransferable::PrivatePaste(SwWrtShell& rShell, SwPasteContext* pContext, PasteTableType ePasteTable)
3792 // first, ask for the SelectionType, then action-bracketing !!!!
3793 // (otherwise it's not pasted into a TableSelection!!!)
3794 OSL_ENSURE( !rShell.ActionPend(), "Paste must never have an ActionPend" );
3795 if ( !m_pClpDocFac )
3796 return false; // the return value of the SwFEShell::Paste also is bool!
3798 const SelectionType nSelection = rShell.GetSelectionType();
3800 SwTrnsfrActionAndUndo aAction( &rShell );
3802 bool bKillPaMs = false;
3804 //Delete selected content, not at table-selection and table in Clipboard, and don't delete hovering graphics.
3805 if( rShell.HasSelection() && !( nSelection & SelectionType::TableCell) && !( nSelection & SelectionType::DrawObject))
3807 if (!(nSelection & SelectionType::NumberList))
3809 bKillPaMs = true;
3810 rShell.SetRetainSelection( true );
3812 if (pContext)
3813 pContext->forget();
3814 rShell.DelRight();
3815 if (pContext)
3816 pContext->remember();
3817 // when a Fly was selected, a valid cursor position has to be found now
3818 // (parked Cursor!)
3819 if( ( SelectionType::Frame | SelectionType::Graphic |
3820 SelectionType::Ole | SelectionType::DrawObject |
3821 SelectionType::DbForm ) & nSelection )
3823 // position the cursor again
3824 Point aPt( rShell.GetCharRect().Pos() );
3825 rShell.SwCursorShell::SetCursor( aPt, true );
3827 if (!(nSelection & SelectionType::NumberList))
3829 rShell.SetRetainSelection( false );
3832 if ( nSelection & SelectionType::DrawObject) //unselect hovering graphics
3834 rShell.ResetSelect(nullptr,false);
3837 bool bInWrd = false, bEndWrd = false, bSttWrd = false,
3838 bSmart(TransferBufferType::DocumentWord & m_eBufferType);
3839 if( bSmart )
3841 // Why not for other Scripts? If TransferBufferType::DocumentWord is set, we have a word
3842 // in the buffer, word in this context means 'something with spaces at beginning
3843 // and end'. In this case we definitely want these spaces to be inserted here.
3844 bInWrd = rShell.IsInWord();
3845 bEndWrd = rShell.IsEndWrd();
3846 bSmart = bInWrd || bEndWrd;
3847 if( bSmart )
3849 bSttWrd = rShell.IsStartWord();
3850 if (!bSttWrd && (bInWrd || bEndWrd))
3851 rShell.SwEditShell::Insert(' ');
3855 bool bRet = true;
3856 // m_pWrtShell is nullptr when the source document is closed already.
3857 if (!m_pWrtShell || lcl_checkClassification(m_pWrtShell->GetDoc(), rShell.GetDoc()))
3858 bRet = rShell.Paste(m_pClpDocFac->GetDoc(), ePasteTable == PasteTableType::PASTE_TABLE);
3860 if( bKillPaMs )
3861 rShell.KillPams();
3863 // If Smart Paste then insert blank
3864 if( bRet && bSmart && ((bInWrd && !bEndWrd )|| bSttWrd) )
3865 rShell.SwEditShell::Insert(' ');
3867 return bRet;
3870 bool SwTransferable::PrivateDrop( SwWrtShell& rSh, const Point& rDragPt,
3871 bool bMove, bool bIsXSelection )
3873 int cWord = 0;
3874 bool bInWrd = false;
3875 bool bEndWrd = false;
3876 bool bSttWrd = false;
3877 bool bSttPara = false;
3878 bool bTableSel = false;
3879 bool bTableMove = false;
3880 bool bFrameSel = false;
3882 SwWrtShell& rSrcSh = *GetShell();
3884 rSh.UnSetVisibleCursor();
3886 if( TransferBufferType::InetField == m_eBufferType )
3888 if( rSh.GetFormatFromObj( rDragPt ) )
3890 INetBookmark aTmp;
3891 if( (TransferBufferType::InetField & m_eBufferType) && m_oBookmark )
3892 aTmp = *m_oBookmark;
3894 // select target graphic
3895 if( rSh.SelectObj( rDragPt ) )
3897 rSh.HideCursor();
3898 rSh.EnterSelFrameMode( &rDragPt );
3899 g_bFrameDrag = true;
3902 const SelectionType nSelection = rSh.GetSelectionType();
3904 // not yet consider Draw objects
3905 if( SelectionType::Graphic & nSelection )
3907 SfxItemSetFixed<RES_URL, RES_URL> aSet( rSh.GetAttrPool() );
3908 rSh.GetFlyFrameAttr( aSet );
3909 SwFormatURL aURL( aSet.Get( RES_URL ) );
3910 aURL.SetURL( aTmp.GetURL(), false );
3911 aSet.Put( aURL );
3912 rSh.SetFlyFrameAttr( aSet );
3913 return true;
3916 if( SelectionType::DrawObject & nSelection )
3918 rSh.LeaveSelFrameMode();
3919 rSh.UnSelectFrame();
3920 rSh.ShowCursor();
3921 g_bFrameDrag = false;
3926 if( &rSh != &rSrcSh && (SelectionType::Graphic & rSh.GetSelectionType()) &&
3927 TransferBufferType::Graphic == m_eBufferType )
3929 // ReRead the graphic
3930 OUString sGrfNm;
3931 OUString sFltNm;
3932 rSrcSh.GetGrfNms( &sGrfNm, &sFltNm );
3933 rSh.ReRead( sGrfNm, sFltNm, rSrcSh.GetGraphic() );
3934 return true;
3937 //not in selections or selected frames
3938 if( rSh.TestCurrPam( rDragPt ) ||
3939 ( rSh.IsSelFrameMode() && rSh.IsInsideSelectedObj( rDragPt )) )
3940 return false;
3942 if( rSrcSh.IsTableMode() )
3944 bTableSel = true;
3945 const SelectionType nSelection = rSrcSh.GetSelectionType();
3946 // at enhanced table row/column selection or wholly selected tables,
3947 // paste rows above or columns before, and in the case of moving, remove the selection
3948 // (limit only to the single document case temporarily)
3949 if( rSrcSh.GetDoc() == rSh.GetDoc() &&
3950 ( (( SelectionType::TableRow | SelectionType::TableCol) & nSelection ) || rSrcSh.HasWholeTabSelection() ) )
3952 bool bTableCol(SelectionType::TableCol & nSelection);
3954 ::sw::mark::IMark* pMarkMoveFrom = bMove
3955 ? rSh.SetBookmark(
3956 vcl::KeyCode(),
3957 OUString(),
3958 IDocumentMarkAccess::MarkType::UNO_BOOKMARK )
3959 : nullptr;
3961 // row count and direction of the table selection:
3962 // up to down, if the cursor is there in its last table row
3963 const SwSelBoxes& rBoxes = rSrcSh.GetTableCursor()->GetSelectedBoxes();
3964 const SwTableNode* pTableNd = rSh.IsCursorInTable();
3965 if (!pTableNd)
3967 SAL_WARN("sw", "presumably this case can't arise in practice");
3968 return false;
3970 const SwTableLines& rLines = pTableNd->GetTable().GetTabLines();
3971 const SwStartNode& rDelPos = rBoxes.back()
3972 ? *rBoxes.front()->GetSttNd()
3973 : *pTableNd->GetStartNode();
3975 // count selected rows or columns
3976 sal_Int32 nSelRowOrCols = 0;
3977 if ( rBoxes.back() )
3979 if ( bTableCol )
3981 // selected column count is the count of the cells
3982 // in the first row of the selection
3983 auto nLine = rLines.GetPos( rBoxes.front()->GetUpper() );
3984 for (auto pBox : rBoxes)
3986 // cell is in the next row
3987 if ( nLine != rLines.GetPos( pBox->GetUpper() ) )
3988 break;
3989 ++nSelRowOrCols;
3992 else
3994 // selected row count is the difference of the row number of the
3995 // first and the last cell of the selection
3996 nSelRowOrCols = rLines.GetPos( rBoxes.back()->GetUpper() ) -
3997 rLines.GetPos( rBoxes.front()->GetUpper() ) + 1;
4001 bool bSelUpToDown = rBoxes.back() && rBoxes.back()->GetUpper() ==
4002 rSh.GetCursor()->GetPointNode().GetTableBox()->GetUpper();
4004 SwUndoId eUndoId = bMove ? SwUndoId::UI_DRAG_AND_MOVE : SwUndoId::UI_DRAG_AND_COPY;
4006 SwRewriter aRewriter;
4008 aRewriter.AddRule(UndoArg1, rSrcSh.GetSelDescr());
4010 if(rSrcSh.GetDoc() != rSh.GetDoc())
4011 rSrcSh.StartUndo( eUndoId, &aRewriter );
4012 rSh.StartUndo( eUndoId, &aRewriter );
4014 rSh.StartAction();
4015 rSrcSh.StartAction();
4017 SfxDispatcher* pDispatch = rSrcSh.GetView().GetViewFrame().GetDispatcher();
4018 pDispatch->Execute(SID_COPY, SfxCallMode::SYNCHRON);
4020 rSrcSh.Push(); // save selection for later restoration
4021 rSh.EnterStdMode();
4022 rSh.SwCursorShell::SetCursor(rDragPt, false);
4024 bool bPasteIntoTable = rSh.GetCursor()->GetPointNode().GetTableBox() != nullptr;
4026 // store cursor
4027 ::sw::mark::IMark* pMark = rSh.SetBookmark(
4028 vcl::KeyCode(),
4029 OUString(),
4030 IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
4032 // paste rows above/columns before
4033 pDispatch->Execute(bTableCol ? FN_TABLE_PASTE_COL_BEFORE : FN_TABLE_PASTE_ROW_BEFORE, SfxCallMode::SYNCHRON);
4035 // go to the previously inserted table rows and set them to tracked insertion, if needed
4036 bool bNeedTrack = !bTableCol && rSh.getIDocumentRedlineAccess().IsRedlineOn();
4038 // restore cursor position
4039 if (bNeedTrack && pMark != nullptr)
4040 rSh.GotoMark( pMark );
4042 if ( !bNeedTrack && !bPasteIntoTable )
4044 rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // restore selection...
4046 // delete source rows/columns
4047 if (bMove)
4048 pDispatch->Execute(bTableCol
4049 ? FN_TABLE_DELETE_COL
4050 : FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
4052 else
4054 const SwTableBox* pBoxStt = rSh.GetCursor()->GetPointNode().GetTableBox();
4055 SwTableLine* pLine = pBoxStt ? const_cast<SwTableLine*>( pBoxStt->GetUpper()): nullptr;
4057 for (sal_Int32 nDeleted = 0; bNeedTrack && nDeleted < nSelRowOrCols;)
4059 // move up text cursor (note: "true" is important for the layout level)
4060 if ( !rSh.Up(false) )
4061 break;
4063 const SwTableBox* pBox = rSh.GetCursor()->GetPointNode().GetTableBox();
4065 if ( !pBox )
4066 break;
4068 // Up() reaches a new row
4069 if ( pBox->GetUpper() != pLine )
4071 //rSh.SelTableRow();
4072 SvxPrintItem aTracked(RES_PRINT, false);
4073 rSh.GetDoc()->SetRowNotTracked( *rSh.GetCursor(), aTracked );
4074 ++nDeleted;
4075 pLine = const_cast<SwTableLine*>(pBox->GetUpper());
4079 rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent); // restore selection...
4081 // delete source rows/columns
4082 if (bMove)
4084 // restore cursor position
4085 if (pMarkMoveFrom != nullptr)
4087 rSh.GotoMark( pMarkMoveFrom );
4088 rSh.getIDocumentMarkAccess()->deleteMark( pMarkMoveFrom );
4091 // tracked table row moving: set original rows as tracked deletion,
4092 // otherwise delete original rows/columns (tracking column deletion
4093 // and insertion is not supported yet)
4094 if ( !bTableCol && bNeedTrack )
4096 pLine = nullptr;
4098 for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols;)
4100 const SwTableBox* pBox = rSh.GetCursor()->GetPointNode().GetTableBox();
4102 if ( !pBox )
4103 break;
4105 if ( pBox->GetUpper() != pLine )
4107 pLine = const_cast<SwTableLine*>(pBox->GetUpper());
4108 pDispatch->Execute(FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
4109 ++nDeleted;
4112 bool bMoved = false;
4113 if (bSelUpToDown)
4114 bMoved = rSh.Up(false);
4115 else
4116 bMoved = rSh.Down(false);
4117 if (!bMoved)
4118 break;
4121 else
4123 // set cursor in the first cell of the original selection
4124 rSh.GetCursor()->DeleteMark();
4125 rSh.GetCursor()->GetPoint()->Assign( rDelPos.GetIndex() + 1);
4127 for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols; ++nDeleted)
4129 pDispatch->Execute(bTableCol
4130 ? FN_TABLE_DELETE_COL
4131 : FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON);
4137 // restore cursor position
4138 if (pMark != nullptr)
4140 rSh.GotoMark( pMark );
4141 rSh.getIDocumentMarkAccess()->deleteMark( pMark );
4144 rSh.DestroyCursor();
4145 rSh.EndUndo();
4146 rSh.EndAction();
4147 rSh.EndAction();
4148 return true;
4151 if ( bMove && rSrcSh.HasWholeTabSelection() )
4152 bTableMove = true;
4154 else if( rSrcSh.IsSelFrameMode() || rSrcSh.IsObjSelected() )
4156 // don't move position-protected objects!
4157 if( bMove && rSrcSh.IsSelObjProtected( FlyProtectFlags::Pos ) != FlyProtectFlags::NONE )
4158 return false;
4160 bFrameSel = true;
4163 const SelectionType nSel = rSrcSh.GetSelectionType();
4165 SwUndoId eUndoId = bMove ? SwUndoId::UI_DRAG_AND_MOVE : SwUndoId::UI_DRAG_AND_COPY;
4167 SwRewriter aRewriter;
4169 aRewriter.AddRule(UndoArg1, rSrcSh.GetSelDescr());
4171 if(rSrcSh.GetDoc() != rSh.GetDoc())
4172 rSrcSh.StartUndo( eUndoId, &aRewriter );
4173 rSh.StartUndo( eUndoId, &aRewriter );
4175 rSh.StartAction();
4176 rSrcSh.StartAction();
4178 if( &rSrcSh != &rSh )
4180 rSh.EnterStdMode();
4181 rSh.SwCursorShell::SetCursor( rDragPt, true );
4182 cWord = rSrcSh.IntelligentCut( nSel, false );
4184 else if( !bTableSel && !bFrameSel )
4186 if( !rSh.IsAddMode() )
4188 // #i87233#
4189 if ( rSh.IsBlockMode() )
4191 // preserve order of cursors for block mode
4192 rSh.GoPrevCursor();
4195 rSh.SwCursorShell::CreateCursor();
4197 rSh.SwCursorShell::SetCursor( rDragPt, true, false );
4198 rSh.GoPrevCursor();
4199 cWord = rSh.IntelligentCut( rSh.GetSelectionType(), false );
4200 rSh.GoNextCursor();
4203 bInWrd = rSh.IsInWord();
4204 bEndWrd = rSh.IsEndWrd();
4205 bSttWrd = !bEndWrd && rSh.IsStartWord();
4206 bSttPara= rSh.IsSttPara();
4208 Point aSttPt( SwEditWin::GetDDStartPosX(), SwEditWin::GetDDStartPosY() );
4210 // at first, select InetFields!
4211 if( TransferBufferType::InetField == m_eBufferType )
4213 if( &rSrcSh == &rSh )
4215 rSh.GoPrevCursor();
4216 rSh.SwCursorShell::SetCursor( aSttPt, true );
4217 rSh.SelectTextAttr( RES_TXTATR_INETFMT );
4218 if( rSh.TestCurrPam( rDragPt ) )
4220 // don't copy/move inside of yourself
4221 rSh.DestroyCursor();
4222 rSh.EndUndo();
4223 rSh.EndAction();
4224 rSh.EndAction();
4225 return false;
4227 rSh.GoNextCursor();
4229 else
4231 rSrcSh.SwCursorShell::SetCursor( aSttPt, true );
4232 rSrcSh.SelectTextAttr( RES_TXTATR_INETFMT );
4235 // is there a URL attribute at the insert point? Then replace that,
4236 // so simply put up a selection?
4237 rSh.DelINetAttrWithText();
4238 g_bDDINetAttr = true;
4241 if ( rSrcSh.IsSelFrameMode() )
4243 //Hack: fool the special treatment
4244 aSttPt = rSrcSh.GetObjRect().Pos();
4247 bool bRet = rSrcSh.SwFEShell::Copy(rSh, aSttPt, rDragPt, bMove,
4248 !bIsXSelection);
4250 if( !bIsXSelection )
4252 rSrcSh.Push();
4253 if ( bRet && bMove && !bFrameSel )
4255 if ( bTableSel )
4257 /* delete table contents not cells */
4258 rSrcSh.Delete(false);
4260 else
4262 //SmartCut, take one of the blanks along.
4263 rSh.SwCursorShell::DestroyCursor();
4264 if ( cWord == SwWrtShell::WORD_SPACE_BEFORE )
4265 rSh.ExtendSelection( false );
4266 else if ( cWord == SwWrtShell::WORD_SPACE_AFTER )
4267 rSh.ExtendSelection();
4268 rSrcSh.DelRight();
4271 rSrcSh.KillPams();
4272 rSrcSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
4274 /* after dragging a table selection inside one shell
4275 set cursor to the drop position. */
4276 if( &rSh == &rSrcSh && ( bTableSel || rSh.IsBlockMode() ) )
4278 rSrcSh.CalcLayout();
4279 rSrcSh.SwCursorShell::SetCursor(rDragPt);
4280 rSrcSh.GetCursor()->SetMark();
4284 if( bRet && !bTableSel && !bFrameSel )
4286 if( (bInWrd || bEndWrd) &&
4287 (cWord == SwWrtShell::WORD_SPACE_AFTER ||
4288 cWord == SwWrtShell::WORD_SPACE_BEFORE) )
4290 if ( bSttWrd || (bInWrd && !bEndWrd))
4291 rSh.SwEditShell::Insert(' ', bIsXSelection);
4292 if ( !bSttWrd || (bInWrd && !bSttPara) )
4294 rSh.SwapPam();
4295 if ( !bSttWrd )
4296 rSh.SwEditShell::Insert(' ', bIsXSelection);
4297 rSh.SwapPam();
4301 if( bIsXSelection )
4303 if( &rSrcSh == &rSh && !rSh.IsAddMode() )
4305 rSh.SwCursorShell::DestroyCursor();
4306 rSh.GoPrevCursor();
4308 else
4310 rSh.SwapPam();
4311 rSh.SwCursorShell::ClearMark();
4314 else
4316 if( rSh.IsAddMode() )
4317 rSh.SwCursorShell::CreateCursor();
4318 else
4320 // turn on selection mode
4321 rSh.SttSelect();
4322 rSh.EndSelect();
4326 else if ( bRet && bTableMove )
4328 SfxDispatcher* pDispatch = rSrcSh.GetView().GetViewFrame().GetDispatcher();
4329 pDispatch->Execute(FN_TABLE_DELETE_TABLE, SfxCallMode::SYNCHRON);
4332 if( bRet && bMove && bFrameSel )
4333 rSrcSh.LeaveSelFrameMode();
4335 if( rSrcSh.GetDoc() != rSh.GetDoc() )
4336 rSrcSh.EndUndo();
4337 rSh.EndUndo();
4339 // put the shell in the right state
4340 if( &rSrcSh != &rSh && ( rSh.IsFrameSelected() || rSh.IsObjSelected() ))
4341 rSh.EnterSelFrameMode();
4343 rSrcSh.EndAction();
4344 rSh.EndAction();
4345 return true;
4348 // Interfaces for Selection
4349 void SwTransferable::CreateSelection( SwWrtShell& rSh,
4350 const SwFrameShell * _pCreatorView )
4352 SwModule *pMod = SW_MOD();
4353 rtl::Reference<SwTransferable> pNew = new SwTransferable( rSh );
4355 pNew->m_pCreatorView = _pCreatorView;
4357 pMod->m_pXSelection = pNew.get();
4358 pNew->CopyToPrimarySelection();
4361 void SwTransferable::ClearSelection( const SwWrtShell& rSh,
4362 const SwFrameShell * _pCreatorView)
4364 SwModule *pMod = SW_MOD();
4365 if( pMod->m_pXSelection &&
4366 ((!pMod->m_pXSelection->m_pWrtShell) || (pMod->m_pXSelection->m_pWrtShell == &rSh)) &&
4367 (!_pCreatorView || (pMod->m_pXSelection->m_pCreatorView == _pCreatorView)) )
4369 TransferableHelper::ClearPrimarySelection();
4373 SwTransferable* SwTransferable::GetSwTransferable( const TransferableDataHelper& rData )
4375 return dynamic_cast<SwTransferable*>(rData.GetTransferable().get());
4378 SwTransferDdeLink::SwTransferDdeLink( SwTransferable& rTrans, SwWrtShell& rSh )
4379 : m_rTransfer(rTrans)
4380 , m_pDocShell(nullptr)
4381 , m_nOldTimeOut(0)
4382 , m_bDelBookmark(false)
4383 , m_bInDisconnect(false)
4385 // we only end up here with table- or text selection
4386 if( SelectionType::TableCell & rSh.GetSelectionType() )
4388 SwFrameFormat* pFormat = rSh.GetTableFormat();
4389 if( pFormat )
4390 m_sName = pFormat->GetName();
4392 else
4394 // creating a temp. bookmark without undo
4395 bool bUndo = rSh.DoesUndo();
4396 rSh.DoUndo( false );
4397 bool bIsModified = rSh.IsModified();
4399 ::sw::mark::IMark* pMark = rSh.SetBookmark(
4400 vcl::KeyCode(),
4401 OUString(),
4402 IDocumentMarkAccess::MarkType::DDE_BOOKMARK);
4403 if(pMark)
4405 m_sName = pMark->GetName();
4406 m_bDelBookmark = true;
4407 if( !bIsModified )
4408 rSh.ResetModified();
4410 else
4411 m_sName.clear();
4412 rSh.DoUndo( bUndo );
4415 if( m_sName.isEmpty() ||
4416 nullptr == ( m_pDocShell = rSh.GetDoc()->GetDocShell() ))
4417 return;
4419 // then we create our "server" and connect to it
4420 m_xRefObj = m_pDocShell->DdeCreateLinkSource( m_sName );
4421 if( m_xRefObj.is() )
4423 m_xRefObj->AddConnectAdvise( this );
4424 m_xRefObj->AddDataAdvise( this,
4425 OUString(),
4426 ADVISEMODE_NODATA | ADVISEMODE_ONLYONCE );
4427 m_nOldTimeOut = m_xRefObj->GetUpdateTimeout();
4428 m_xRefObj->SetUpdateTimeout( 0 );
4432 SwTransferDdeLink::~SwTransferDdeLink()
4434 if( m_xRefObj.is() )
4435 Disconnect( true );
4438 ::sfx2::SvBaseLink::UpdateResult SwTransferDdeLink::DataChanged( const OUString& ,
4439 const uno::Any& )
4441 // well, that's it with the link
4442 if( !m_bInDisconnect )
4444 if( FindDocShell() && m_pDocShell->GetView() )
4445 m_rTransfer.RemoveDDELinkFormat( m_pDocShell->GetView()->GetEditWin() );
4446 Disconnect( false );
4448 return SUCCESS;
4451 bool SwTransferDdeLink::WriteData( SvStream& rStrm )
4453 if( !m_xRefObj.is() || !FindDocShell() )
4454 return false;
4456 rtl_TextEncoding eEncoding = osl_getThreadTextEncoding();
4457 const OString aAppNm(OUStringToOString(
4458 Application::GetAppName(), eEncoding));
4459 const OString aTopic(OUStringToOString(
4460 m_pDocShell->GetTitle(SFX_TITLE_FULLNAME), eEncoding));
4461 const OString aName(OUStringToOString(m_sName, eEncoding));
4463 std::unique_ptr<char[]> pMem(new char[ aAppNm.getLength() + aTopic.getLength() + aName.getLength() + 4 ]);
4465 sal_Int32 nLen = aAppNm.getLength();
4466 memcpy( pMem.get(), aAppNm.getStr(), nLen );
4467 pMem[ nLen++ ] = 0;
4468 memcpy( pMem.get() + nLen, aTopic.getStr(), aTopic.getLength() );
4469 nLen = nLen + aTopic.getLength();
4470 pMem[ nLen++ ] = 0;
4471 memcpy( pMem.get() + nLen, aName.getStr(), aName.getLength() );
4472 nLen = nLen + aName.getLength();
4473 pMem[ nLen++ ] = 0;
4474 pMem[ nLen++ ] = 0;
4476 rStrm.WriteBytes( pMem.get(), nLen );
4477 pMem.reset();
4479 IDocumentMarkAccess* const pMarkAccess = m_pDocShell->GetDoc()->getIDocumentMarkAccess();
4480 IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->findMark(m_sName);
4481 if(ppMark != pMarkAccess->getAllMarksEnd()
4482 && IDocumentMarkAccess::GetType(**ppMark) != IDocumentMarkAccess::MarkType::BOOKMARK)
4484 // the mark is still a DdeBookmark
4485 // we replace it with a Bookmark, so it will get saved etc.
4486 ::sw::mark::IMark* const pMark = *ppMark;
4487 ::sfx2::SvLinkSource* p = m_xRefObj.get();
4488 SwServerObject& rServerObject = dynamic_cast<SwServerObject&>(*p);
4490 // collecting state of old mark
4491 SwPaM aPaM(pMark->GetMarkStart());
4492 *aPaM.GetPoint() = pMark->GetMarkStart();
4493 if(pMark->IsExpanded())
4495 aPaM.SetMark();
4496 *aPaM.GetMark() = pMark->GetMarkEnd();
4498 OUString sMarkName = pMark->GetName();
4500 // remove mark
4501 rServerObject.SetNoServer(); // this removes the connection between SwServerObject and mark
4502 // N.B. ppMark was not loaded from file and cannot have xml:id
4503 pMarkAccess->deleteMark(ppMark, false);
4505 // recreate as Bookmark
4506 ::sw::mark::IMark* const pNewMark = pMarkAccess->makeMark(
4507 aPaM,
4508 sMarkName,
4509 IDocumentMarkAccess::MarkType::BOOKMARK,
4510 ::sw::mark::InsertMode::New);
4511 rServerObject.SetDdeBookmark(*pNewMark);
4514 m_bDelBookmark = false;
4515 return true;
4518 void SwTransferDdeLink::Disconnect( bool bRemoveDataAdvise )
4520 // don't accept DataChanged anymore, when already in Disconnect!
4521 // (DTOR from Bookmark sends a DataChanged!)
4522 bool bOldDisconnect = m_bInDisconnect;
4523 m_bInDisconnect = true;
4525 // destroy the unused bookmark again (without Undo!)?
4526 if( m_bDelBookmark && m_xRefObj.is() && FindDocShell() )
4528 SwDoc* pDoc = m_pDocShell->GetDoc();
4529 ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
4531 // #i58448#
4532 Link<bool,void> aSavedOle2Link( pDoc->GetOle2Link() );
4533 pDoc->SetOle2Link( Link<bool,void>() );
4535 bool bIsModified = pDoc->getIDocumentState().IsModified();
4537 IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
4538 pMarkAccess->deleteMark(pMarkAccess->findMark(m_sName), false);
4540 if( !bIsModified )
4541 pDoc->getIDocumentState().ResetModified();
4542 // #i58448#
4543 pDoc->SetOle2Link( aSavedOle2Link );
4545 m_bDelBookmark = false;
4548 if( m_xRefObj.is() )
4550 m_xRefObj->SetUpdateTimeout( m_nOldTimeOut );
4551 m_xRefObj->RemoveConnectAdvise( this );
4552 if( bRemoveDataAdvise )
4553 // in a DataChanged the SelectionObject must NEVER be deleted
4554 // is already handled by the base class
4555 // (ADVISEMODE_ONLYONCE!!!!)
4556 // but always in normal Disconnect!
4557 m_xRefObj->RemoveAllDataAdvise( this );
4558 m_xRefObj.clear();
4560 m_bInDisconnect = bOldDisconnect;
4563 bool SwTransferDdeLink::FindDocShell()
4565 SfxObjectShell* pTmpSh = SfxObjectShell::GetFirst( checkSfxObjectShell<SwDocShell> );
4566 while( pTmpSh )
4568 if( pTmpSh == m_pDocShell ) // that's what we want to have
4570 if( m_pDocShell->GetDoc() )
4571 return true;
4572 break; // the Doc is not there anymore, so leave!
4574 pTmpSh = SfxObjectShell::GetNext( *pTmpSh, checkSfxObjectShell<SwDocShell> );
4577 m_pDocShell = nullptr;
4578 return false;
4581 void SwTransferDdeLink::Closed()
4583 if( !m_bInDisconnect && m_xRefObj.is() )
4585 m_xRefObj->RemoveAllDataAdvise( this );
4586 m_xRefObj->RemoveConnectAdvise( this );
4587 m_xRefObj.clear();
4591 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */