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