1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
21 #include <com/sun/star/embed/XEmbeddedObject.hpp>
23 #include <svx/svditer.hxx>
24 #include <svx/svdograf.hxx>
25 #include <svx/svdoole2.hxx>
26 #include <svx/svdouno.hxx>
27 #include <svx/svdpage.hxx>
28 #include <svx/svdpagv.hxx>
29 #include <svx/svdundo.hxx>
30 #include <svtools/embedhlp.hxx>
31 #include <sfx2/objsh.hxx>
32 #include <sfx2/ipclient.hxx>
33 #include <toolkit/helper/vclunohelper.hxx>
34 #include <com/sun/star/embed/Aspects.hpp>
35 #include <osl/diagnose.h>
37 #include <document.hxx>
38 #include <viewfunc.hxx>
39 #include <tabvwsh.hxx>
40 #include <drawview.hxx>
42 #include <drwlayer.hxx>
43 #include <drwtrans.hxx>
44 #include <globstr.hrc>
45 #include <scresid.hxx>
48 #include <dragdata.hxx>
49 #include <gridwin.hxx>
50 #include <stlpool.hxx>
52 bool bPasteIsMove
= false;
54 using namespace com::sun::star
;
56 static void lcl_AdjustInsertPos( ScViewData
& rData
, Point
& rPos
, const Size
& rSize
)
58 SdrPage
* pPage
= rData
.GetScDrawView()->GetModel().GetPage( static_cast<sal_uInt16
>(rData
.GetTabNo()) );
59 assert(pPage
&& "pPage ???");
60 Size
aPgSize( pPage
->GetSize() );
61 if (aPgSize
.Width() < 0)
62 aPgSize
.setWidth( -aPgSize
.Width() );
63 tools::Long x
= aPgSize
.Width() - rPos
.X() - rSize
.Width();
64 tools::Long y
= aPgSize
.Height() - rPos
.Y() - rSize
.Height();
65 // if necessary: adjustments (80/200) for pixel approx. errors
67 rPos
.AdjustX(x
+ 80 );
69 rPos
.AdjustY(y
+ 200 );
70 rPos
.AdjustX(rSize
.Width() / 2 ); // position at paste is center
71 rPos
.AdjustY(rSize
.Height() / 2 );
74 void ScViewFunc::PasteDraw( const Point
& rLogicPos
, SdrModel
* pModel
,
75 bool bGroup
, std::u16string_view rSrcShellID
, std::u16string_view rDestShellID
)
77 bool bSameDocClipboard
= rSrcShellID
== rDestShellID
;
80 Point
aPos( rLogicPos
);
82 // MapMode at Outliner-RefDevice has to be right (as in FuText::MakeOutliner)
83 //! merge with FuText::MakeOutliner?
85 OutputDevice
* pRef
= GetViewData().GetDocument().GetDrawLayer()->GetRefDevice();
88 aOldMapMode
= pRef
->GetMapMode();
89 pRef
->SetMapMode( MapMode(MapUnit::Map100thMM
) );
92 bool bNegativePage
= GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() );
94 SdrView
* pDragEditView
= nullptr;
95 const ScDragData
& rData
= ScModule::get()->GetDragData();
96 ScDrawTransferObj
* pDrawTrans
= rData
.pDrawTransfer
;
99 pDragEditView
= pDrawTrans
->GetDragSourceView();
101 aPos
-= aDragStartDiff
;
104 if (aPos
.X() > 0) aPos
.setX( 0 );
108 if (aPos
.X() < 0) aPos
.setX( 0 );
110 if (aPos
.Y() < 0) aPos
.setY( 0 );
113 ScDrawView
* pScDrawView
= GetScDrawView();
115 pScDrawView
->BegUndo( ScResId( STR_UNDO_PASTE
) );
117 bool bSameDoc
= ( pDragEditView
&& &pDragEditView
->GetModel() == &pScDrawView
->GetModel() );
120 // copy locally - incl. charts
122 Point aSourceStart
= pDragEditView
->GetAllMarkedRect().TopLeft();
123 tools::Long nDiffX
= aPos
.X() - aSourceStart
.X();
124 tools::Long nDiffY
= aPos
.Y() - aSourceStart
.Y();
126 // move within a page?
129 pScDrawView
->GetSdrPageView()->GetPage() ==
130 pDragEditView
->GetSdrPageView()->GetPage() )
132 if ( nDiffX
!= 0 || nDiffY
!= 0 )
133 pDragEditView
->MoveAllMarked(Size(nDiffX
,nDiffY
));
137 SdrModel
& rDrawModel
= pDragEditView
->GetModel();
138 SCTAB nTab
= GetViewData().GetTabNo();
139 SdrPage
* pDestPage
= rDrawModel
.GetPage( static_cast< sal_uInt16
>( nTab
) );
140 OSL_ENSURE(pDestPage
,"who is this, Page?");
142 ::std::vector
< OUString
> aExcludedChartNames
;
145 ScChartHelper::GetChartNames( aExcludedChartNames
, pDestPage
);
148 const SdrMarkList
& rMarkList
= pDragEditView
->GetMarkedObjectList();
149 rMarkList
.ForceSort();
150 const size_t nMarkCnt
=rMarkList
.GetMarkCount();
151 for (size_t nm
=0; nm
<nMarkCnt
; ++nm
) {
152 const SdrMark
* pM
=rMarkList
.GetMark(nm
);
153 const SdrObject
* pObj
=pM
->GetMarkedSdrObj();
155 // Directly Clone to target SdrModel
156 rtl::Reference
<SdrObject
> pNewObj(pObj
->CloneSdrObject(rDrawModel
));
158 if (pNewObj
!=nullptr)
160 // copy graphics within the same model - always needs new name
161 if ( dynamic_cast<const SdrGrafObj
*>( pNewObj
.get()) != nullptr && !bPasteIsMove
)
162 pNewObj
->SetName(static_cast<ScDrawLayer
*>(&rDrawModel
)->GetNewGraphicName());
164 if (nDiffX
!=0 || nDiffY
!=0)
165 pNewObj
->NbcMove(Size(nDiffX
,nDiffY
));
167 pDestPage
->InsertObject( pNewObj
.get() );
168 pScDrawView
->AddUndo(std::make_unique
<SdrUndoInsertObj
>( *pNewObj
));
170 if (ScDrawLayer::IsCellAnchored(*pNewObj
))
171 ScDrawLayer::SetCellAnchoredFromPosition(*pNewObj
, GetViewData().GetDocument(), nTab
,
172 ScDrawLayer::IsResizeWithCell(*pNewObj
));
177 pDragEditView
->DeleteMarked();
179 ScDocument
& rDocument
= GetViewData().GetDocument();
180 ScDocShell
* pDocShell
= GetViewData().GetDocShell();
181 ScModelObj
* pModelObj
= ( pDocShell
? pDocShell
->GetModel() : nullptr );
182 if ( pDestPage
&& pModelObj
&& pDrawTrans
)
184 const ScRangeListVector
& rProtectedChartRangesVector( pDrawTrans
->GetProtectedChartRangesVector() );
185 ScChartHelper::CreateProtectedChartListenersAndNotify( rDocument
, pDestPage
, pModelObj
, nTab
,
186 rProtectedChartRangesVector
, aExcludedChartNames
, bSameDoc
);
192 bPasteIsMove
= false; // no internal move happened
193 SdrView
aView(*pModel
); // #i71529# never create a base class of SdrView directly!
194 SdrPageView
* pPv
= aView
.ShowSdrPage(aView
.GetModel().GetPage(0));
195 aView
.MarkAllObj(pPv
);
196 Size aSize
= aView
.GetAllMarkedRect().GetSize();
197 lcl_AdjustInsertPos( GetViewData(), aPos
, aSize
);
199 // don't change marking if OLE object is active
200 // (at Drop from OLE object it would be deactivated in the middle of ExecuteDrag!)
202 SdrInsertFlags nOptions
= SdrInsertFlags::NONE
;
203 SfxInPlaceClient
* pClient
= GetViewData().GetViewShell()->GetIPClient();
204 if ( pClient
&& pClient
->IsObjectInPlaceActive() )
205 nOptions
|= SdrInsertFlags::DONTMARK
;
207 ::std::vector
< OUString
> aExcludedChartNames
;
208 SCTAB nTab
= GetViewData().GetTabNo();
209 SdrPage
* pPage
= pScDrawView
->GetModel().GetPage( static_cast< sal_uInt16
>( nTab
) );
210 OSL_ENSURE( pPage
, "Page?" );
213 ScChartHelper::GetChartNames( aExcludedChartNames
, pPage
);
216 if ( !bSameDocClipboard
)
218 auto pPool
= static_cast<ScStyleSheetPool
*>(pScDrawView
->GetModel().GetStyleSheetPool());
219 pPool
->CopyUsedGraphicStylesFrom(pModel
->GetStyleSheetPool());
221 // #89247# Set flag for ScDocument::UpdateChartListeners() which is
222 // called during paste.
223 GetViewData().GetDocument().SetPastingDrawFromOtherDoc( true );
226 pScDrawView
->Paste(*pModel
, aPos
, nullptr, nOptions
);
228 if ( !bSameDocClipboard
)
229 GetViewData().GetDocument().SetPastingDrawFromOtherDoc( false );
231 // Paste puts all objects on the active (front) layer
232 // controls must be on SC_LAYER_CONTROLS
235 SdrObjListIter
aIter( pPage
, SdrIterMode::DeepNoGroups
);
236 SdrObject
* pObject
= aIter
.Next();
239 if ( dynamic_cast<const SdrUnoObj
*>( pObject
) != nullptr && pObject
->GetLayer() != SC_LAYER_CONTROLS
)
240 pObject
->NbcSetLayer(SC_LAYER_CONTROLS
);
242 if (ScDrawLayer::IsCellAnchored(*pObject
))
243 ScDrawLayer::SetCellAnchoredFromPosition(*pObject
, GetViewData().GetDocument(), nTab
,
244 ScDrawLayer::IsResizeWithCell(*pObject
));
246 pObject
= aIter
.Next();
250 // all graphics objects must have names
251 GetViewData().GetDocument().EnsureGraphicNames();
253 ScDocument
& rDocument
= GetViewData().GetDocument();
254 ScDocShell
* pDocShell
= GetViewData().GetDocShell();
255 ScModelObj
* pModelObj
= ( pDocShell
? pDocShell
->GetModel() : nullptr );
256 const ScDrawTransferObj
* pTransferObj
= ScDrawTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(GetViewData().GetActiveWin()));
257 if ( pPage
&& pModelObj
&& ( pTransferObj
|| pDrawTrans
) )
259 const ScRangeListVector
& rProtectedChartRangesVector(
260 pTransferObj
? pTransferObj
->GetProtectedChartRangesVector() : pDrawTrans
->GetProtectedChartRangesVector() );
261 ScChartHelper::CreateProtectedChartListenersAndNotify( rDocument
, pPage
, pModelObj
, nTab
,
262 rProtectedChartRangesVector
, aExcludedChartNames
, bSameDocClipboard
);
268 pScDrawView
->GroupMarked();
269 pScDrawView
->EndUndo();
273 pRef
->SetMapMode( aOldMapMode
);
275 // GetViewData().GetViewShell()->SetDrawShell( true );
276 // It is not sufficient to just set the DrawShell if we pasted, for
277 // example, a chart. SetDrawShellOrSub() would only work for D&D in the
278 // same document but not if inserting from the clipboard, therefore
279 // MarkListHasChanged() is what we need.
280 pScDrawView
->MarkListHasChanged();
284 bool ScViewFunc::PasteObject( const Point
& rPos
, const uno::Reference
< embed::XEmbeddedObject
>& xObj
,
285 const Size
* pDescSize
, const Graphic
* pReplGraph
, const OUString
& aMediaType
, sal_Int64 nAspect
)
291 //TODO/MBA: is that OK?
292 comphelper::EmbeddedObjectContainer
& aCnt
= GetViewData().GetViewShell()->GetObjectShell()->GetEmbeddedObjectContainer();
293 if ( !aCnt
.HasEmbeddedObject( xObj
) )
294 aCnt
.InsertEmbeddedObject( xObj
, aName
);
296 aName
= aCnt
.GetEmbeddedObjectName( xObj
);
298 svt::EmbeddedObjectRef
aObjRef( xObj
, nAspect
);
300 aObjRef
.SetGraphic( *pReplGraph
, aMediaType
);
303 if ( nAspect
== embed::Aspects::MSOLE_ICON
)
305 MapMode
aMapMode( MapUnit::Map100thMM
);
306 aSize
= aObjRef
.GetSize( &aMapMode
);
310 // working with visual area can switch object to running state
311 MapUnit aMapObj
= VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj
->getMapUnit( nAspect
) );
312 MapUnit aMap100
= MapUnit::Map100thMM
;
314 if ( pDescSize
&& pDescSize
->Width() && pDescSize
->Height() )
316 // use size from object descriptor if given
317 aSize
= OutputDevice::LogicToLogic(*pDescSize
, MapMode(aMap100
), MapMode(aMapObj
));
319 aSz
.Width
= aSize
.Width();
320 aSz
.Height
= aSize
.Height();
321 xObj
->setVisualAreaSize( nAspect
, aSz
);
327 aSz
= xObj
->getVisualAreaSize( nAspect
);
329 catch ( embed::NoVisualAreaSizeException
& )
331 // the default size will be set later
334 aSize
= Size( aSz
.Width
, aSz
.Height
);
335 aSize
= OutputDevice::LogicToLogic(aSize
, MapMode(aMapObj
), MapMode(aMap100
)); // for SdrOle2Obj
337 if( aSize
.IsEmpty() )
339 OSL_FAIL("SvObjectDescriptor::GetSize == 0");
340 aSize
.setWidth( 5000 );
341 aSize
.setHeight( 5000 );
342 aSize
= OutputDevice::LogicToLogic(aSize
, MapMode(aMap100
), MapMode(aMapObj
));
343 aSz
.Width
= aSize
.Width();
344 aSz
.Height
= aSize
.Height();
345 xObj
->setVisualAreaSize( nAspect
, aSz
);
349 // don't call AdjustInsertPos
350 Point aInsPos
= rPos
;
351 if ( GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() ) )
352 aInsPos
.AdjustX( -(aSize
.Width()) );
353 tools::Rectangle
aRect( aInsPos
, aSize
);
355 ScDrawView
* pDrView
= GetScDrawView();
356 rtl::Reference
<SdrOle2Obj
> pSdrObj
= new SdrOle2Obj(
357 pDrView
->getSdrModelFromSdrView(),
362 SdrPageView
* pPV
= pDrView
->GetSdrPageView();
363 pDrView
->InsertObjectSafe( pSdrObj
.get(), *pPV
); // don't mark if OLE
364 GetViewData().GetViewShell()->SetDrawShell( true );
371 bool ScViewFunc::PasteBitmapEx( const Point
& rPos
, const BitmapEx
& rBmpEx
)
373 Graphic
aGraphic(rBmpEx
);
374 return PasteGraphic( rPos
, aGraphic
, u
""_ustr
);
377 bool ScViewFunc::PasteMetaFile( const Point
& rPos
, const GDIMetaFile
& rMtf
)
379 Graphic
aGraphic(rMtf
);
380 return PasteGraphic( rPos
, aGraphic
, u
""_ustr
);
383 bool ScViewFunc::PasteGraphic( const Point
& rPos
, const Graphic
& rGraphic
,
384 const OUString
& rFile
)
387 ScDrawView
* pScDrawView
= GetScDrawView();
392 // #i123922# check if the drop was over an existing object; if yes, evtl. replace
393 // the graphic for a SdrGraphObj (including link state updates) or adapt the fill
394 // style for other objects
395 SdrPageView
* pPageView
= pScDrawView
->GetSdrPageView();
398 SdrObject
* pPickObj
= pScDrawView
->PickObj(rPos
, pScDrawView
->getHitTolLog(), pPageView
);
401 const OUString
aBeginUndo(ScResId(STR_UNDO_DRAGDROP
));
402 SdrObject
* pResult
= pScDrawView
->ApplyGraphicToObject(
410 // we are done; mark the modified/new object
411 pScDrawView
->MarkObj(pResult
, pScDrawView
->GetSdrPageView());
418 vcl::Window
* pWin
= GetActiveWin();
419 MapMode aSourceMap
= rGraphic
.GetPrefMapMode();
420 MapMode
aDestMap( MapUnit::Map100thMM
);
422 if (aSourceMap
.GetMapUnit() == MapUnit::MapPixel
)
424 // consider pixel correction, so bitmap fits to screen
425 Fraction aScaleX
, aScaleY
;
426 pScDrawView
->CalcNormScale( aScaleX
, aScaleY
);
427 aDestMap
.SetScaleX(aScaleX
);
428 aDestMap
.SetScaleY(aScaleY
);
431 Size aSize
= pWin
->LogicToLogic( rGraphic
.GetPrefSize(), &aSourceMap
, &aDestMap
);
433 if ( GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() ) )
434 aPos
.AdjustX( -(aSize
.Width()) );
436 GetViewData().GetViewShell()->SetDrawShell( true );
437 tools::Rectangle
aRect(aPos
, aSize
);
438 rtl::Reference
<SdrGrafObj
> pGrafObj
= new SdrGrafObj(
439 pScDrawView
->getSdrModelFromSdrView(),
443 // path was the name of the graphic in history
445 ScDrawLayer
* pLayer
= static_cast<ScDrawLayer
*>(&pScDrawView
->GetModel());
446 OUString aName
= pLayer
->GetNewGraphicName(); // "Graphics"
447 pGrafObj
->SetName(aName
);
450 bool bSuccess
= pScDrawView
->InsertObjectSafe(pGrafObj
.get(), *pScDrawView
->GetSdrPageView());
452 // SetGraphicLink has to be used after inserting the object,
453 // otherwise an empty graphic is swapped in and the contact stuff crashes.
455 if (bSuccess
&& !rFile
.isEmpty())
456 pGrafObj
->SetGraphicLink( rFile
);
461 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */