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>
51 bool bPasteIsMove
= false;
53 using namespace com::sun::star
;
55 static void lcl_AdjustInsertPos( ScViewData
& rData
, Point
& rPos
, const Size
& rSize
)
57 SdrPage
* pPage
= rData
.GetScDrawView()->GetModel()->GetPage( static_cast<sal_uInt16
>(rData
.GetTabNo()) );
58 OSL_ENSURE(pPage
,"pPage ???");
59 Size
aPgSize( pPage
->GetSize() );
60 if (aPgSize
.Width() < 0)
61 aPgSize
.setWidth( -aPgSize
.Width() );
62 tools::Long x
= aPgSize
.Width() - rPos
.X() - rSize
.Width();
63 tools::Long y
= aPgSize
.Height() - rPos
.Y() - rSize
.Height();
64 // if necessary: adjustments (80/200) for pixel approx. errors
66 rPos
.AdjustX(x
+ 80 );
68 rPos
.AdjustY(y
+ 200 );
69 rPos
.AdjustX(rSize
.Width() / 2 ); // position at paste is center
70 rPos
.AdjustY(rSize
.Height() / 2 );
73 void ScViewFunc::PasteDraw( const Point
& rLogicPos
, SdrModel
* pModel
,
74 bool bGroup
, std::u16string_view rSrcShellID
, std::u16string_view rDestShellID
)
76 bool bSameDocClipboard
= rSrcShellID
== rDestShellID
;
79 Point
aPos( rLogicPos
);
81 // MapMode at Outliner-RefDevice has to be right (as in FuText::MakeOutliner)
82 //! merge with FuText::MakeOutliner?
84 OutputDevice
* pRef
= GetViewData().GetDocument().GetDrawLayer()->GetRefDevice();
87 aOldMapMode
= pRef
->GetMapMode();
88 pRef
->SetMapMode( MapMode(MapUnit::Map100thMM
) );
91 bool bNegativePage
= GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() );
93 SdrView
* pDragEditView
= nullptr;
94 ScModule
* pScMod
= SC_MOD();
95 const ScDragData
& rData
= pScMod
->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
* pDrawModel
= pDragEditView
->GetModel();
138 SCTAB nTab
= GetViewData().GetTabNo();
139 SdrPage
* pDestPage
= pDrawModel
->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 SdrMarkList aMark
= pDragEditView
->GetMarkedObjectList();
150 const size_t nMarkCnt
=aMark
.GetMarkCount();
151 for (size_t nm
=0; nm
<nMarkCnt
; ++nm
) {
152 const SdrMark
* pM
=aMark
.GetMark(nm
);
153 const SdrObject
* pObj
=pM
->GetMarkedSdrObj();
155 // Directly Clone to target SdrModel
156 SdrObject
* pNewObj(pObj
->CloneSdrObject(*pDrawModel
));
158 if (pNewObj
!=nullptr)
160 // copy graphics within the same model - always needs new name
161 if ( dynamic_cast<const SdrGrafObj
*>( pNewObj
) != nullptr && !bPasteIsMove
)
162 pNewObj
->SetName(static_cast<ScDrawLayer
*>(pDrawModel
)->GetNewGraphicName());
164 if (nDiffX
!=0 || nDiffY
!=0)
165 pNewObj
->NbcMove(Size(nDiffX
,nDiffY
));
167 pDestPage
->InsertObject( pNewObj
);
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
? comphelper::getFromUnoTunnel
<ScModelObj
>( 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 // #89247# Set flag for ScDocument::UpdateChartListeners() which is
217 // called during paste.
218 if ( !bSameDocClipboard
)
219 GetViewData().GetDocument().SetPastingDrawFromOtherDoc( true );
221 pScDrawView
->Paste(*pModel
, aPos
, nullptr, nOptions
);
223 if ( !bSameDocClipboard
)
224 GetViewData().GetDocument().SetPastingDrawFromOtherDoc( false );
226 // Paste puts all objects on the active (front) layer
227 // controls must be on SC_LAYER_CONTROLS
230 SdrObjListIter
aIter( pPage
, SdrIterMode::DeepNoGroups
);
231 SdrObject
* pObject
= aIter
.Next();
234 if ( dynamic_cast<const SdrUnoObj
*>( pObject
) != nullptr && pObject
->GetLayer() != SC_LAYER_CONTROLS
)
235 pObject
->NbcSetLayer(SC_LAYER_CONTROLS
);
237 if (ScDrawLayer::IsCellAnchored(*pObject
))
238 ScDrawLayer::SetCellAnchoredFromPosition(*pObject
, GetViewData().GetDocument(), nTab
,
239 ScDrawLayer::IsResizeWithCell(*pObject
));
241 pObject
= aIter
.Next();
245 // all graphics objects must have names
246 GetViewData().GetDocument().EnsureGraphicNames();
248 ScDocument
& rDocument
= GetViewData().GetDocument();
249 ScDocShell
* pDocShell
= GetViewData().GetDocShell();
250 ScModelObj
* pModelObj
= ( pDocShell
? comphelper::getFromUnoTunnel
<ScModelObj
>( pDocShell
->GetModel() ) : nullptr );
251 const ScDrawTransferObj
* pTransferObj
= ScDrawTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(GetViewData().GetActiveWin()));
252 if ( pPage
&& pModelObj
&& ( pTransferObj
|| pDrawTrans
) )
254 const ScRangeListVector
& rProtectedChartRangesVector(
255 pTransferObj
? pTransferObj
->GetProtectedChartRangesVector() : pDrawTrans
->GetProtectedChartRangesVector() );
256 ScChartHelper::CreateProtectedChartListenersAndNotify( rDocument
, pPage
, pModelObj
, nTab
,
257 rProtectedChartRangesVector
, aExcludedChartNames
, bSameDocClipboard
);
263 pScDrawView
->GroupMarked();
264 pScDrawView
->EndUndo();
268 pRef
->SetMapMode( aOldMapMode
);
270 // GetViewData().GetViewShell()->SetDrawShell( true );
271 // It is not sufficient to just set the DrawShell if we pasted, for
272 // example, a chart. SetDrawShellOrSub() would only work for D&D in the
273 // same document but not if inserting from the clipboard, therefore
274 // MarkListHasChanged() is what we need.
275 pScDrawView
->MarkListHasChanged();
279 bool ScViewFunc::PasteObject( const Point
& rPos
, const uno::Reference
< embed::XEmbeddedObject
>& xObj
,
280 const Size
* pDescSize
, const Graphic
* pReplGraph
, const OUString
& aMediaType
, sal_Int64 nAspect
)
286 //TODO/MBA: is that OK?
287 comphelper::EmbeddedObjectContainer
& aCnt
= GetViewData().GetViewShell()->GetObjectShell()->GetEmbeddedObjectContainer();
288 if ( !aCnt
.HasEmbeddedObject( xObj
) )
289 aCnt
.InsertEmbeddedObject( xObj
, aName
);
291 aName
= aCnt
.GetEmbeddedObjectName( xObj
);
293 svt::EmbeddedObjectRef
aObjRef( xObj
, nAspect
);
295 aObjRef
.SetGraphic( *pReplGraph
, aMediaType
);
298 if ( nAspect
== embed::Aspects::MSOLE_ICON
)
300 MapMode
aMapMode( MapUnit::Map100thMM
);
301 aSize
= aObjRef
.GetSize( &aMapMode
);
305 // working with visual area can switch object to running state
306 MapUnit aMapObj
= VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj
->getMapUnit( nAspect
) );
307 MapUnit aMap100
= MapUnit::Map100thMM
;
309 if ( pDescSize
&& pDescSize
->Width() && pDescSize
->Height() )
311 // use size from object descriptor if given
312 aSize
= OutputDevice::LogicToLogic(*pDescSize
, MapMode(aMap100
), MapMode(aMapObj
));
314 aSz
.Width
= aSize
.Width();
315 aSz
.Height
= aSize
.Height();
316 xObj
->setVisualAreaSize( nAspect
, aSz
);
322 aSz
= xObj
->getVisualAreaSize( nAspect
);
324 catch ( embed::NoVisualAreaSizeException
& )
326 // the default size will be set later
329 aSize
= Size( aSz
.Width
, aSz
.Height
);
330 aSize
= OutputDevice::LogicToLogic(aSize
, MapMode(aMapObj
), MapMode(aMap100
)); // for SdrOle2Obj
332 if( aSize
.IsEmpty() )
334 OSL_FAIL("SvObjectDescriptor::GetSize == 0");
335 aSize
.setWidth( 5000 );
336 aSize
.setHeight( 5000 );
337 aSize
= OutputDevice::LogicToLogic(aSize
, MapMode(aMap100
), MapMode(aMapObj
));
338 aSz
.Width
= aSize
.Width();
339 aSz
.Height
= aSize
.Height();
340 xObj
->setVisualAreaSize( nAspect
, aSz
);
344 // don't call AdjustInsertPos
345 Point aInsPos
= rPos
;
346 if ( GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() ) )
347 aInsPos
.AdjustX( -(aSize
.Width()) );
348 tools::Rectangle
aRect( aInsPos
, aSize
);
350 ScDrawView
* pDrView
= GetScDrawView();
351 SdrOle2Obj
* pSdrObj
= new SdrOle2Obj(
352 pDrView
->getSdrModelFromSdrView(),
357 SdrPageView
* pPV
= pDrView
->GetSdrPageView();
358 pDrView
->InsertObjectSafe( pSdrObj
, *pPV
); // don't mark if OLE
359 GetViewData().GetViewShell()->SetDrawShell( true );
366 bool ScViewFunc::PasteBitmapEx( const Point
& rPos
, const BitmapEx
& rBmpEx
)
368 Graphic
aGraphic(rBmpEx
);
369 return PasteGraphic( rPos
, aGraphic
, "" );
372 bool ScViewFunc::PasteMetaFile( const Point
& rPos
, const GDIMetaFile
& rMtf
)
374 Graphic
aGraphic(rMtf
);
375 return PasteGraphic( rPos
, aGraphic
, "" );
378 bool ScViewFunc::PasteGraphic( const Point
& rPos
, const Graphic
& rGraphic
,
379 const OUString
& rFile
)
382 ScDrawView
* pScDrawView
= GetScDrawView();
387 // #i123922# check if the drop was over an existing object; if yes, evtl. replace
388 // the graphic for a SdrGraphObj (including link state updates) or adapt the fill
389 // style for other objects
390 SdrPageView
* pPageView
= pScDrawView
->GetSdrPageView();
393 SdrObject
* pPickObj
= pScDrawView
->PickObj(rPos
, pScDrawView
->getHitTolLog(), pPageView
);
396 const OUString
aBeginUndo(ScResId(STR_UNDO_DRAGDROP
));
397 SdrObject
* pResult
= pScDrawView
->ApplyGraphicToObject(
405 // we are done; mark the modified/new object
406 pScDrawView
->MarkObj(pResult
, pScDrawView
->GetSdrPageView());
413 vcl::Window
* pWin
= GetActiveWin();
414 MapMode aSourceMap
= rGraphic
.GetPrefMapMode();
415 MapMode
aDestMap( MapUnit::Map100thMM
);
417 if (aSourceMap
.GetMapUnit() == MapUnit::MapPixel
)
419 // consider pixel correction, so bitmap fits to screen
420 Fraction aScaleX
, aScaleY
;
421 pScDrawView
->CalcNormScale( aScaleX
, aScaleY
);
422 aDestMap
.SetScaleX(aScaleX
);
423 aDestMap
.SetScaleY(aScaleY
);
426 Size aSize
= pWin
->LogicToLogic( rGraphic
.GetPrefSize(), &aSourceMap
, &aDestMap
);
428 if ( GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() ) )
429 aPos
.AdjustX( -(aSize
.Width()) );
431 GetViewData().GetViewShell()->SetDrawShell( true );
432 tools::Rectangle
aRect(aPos
, aSize
);
433 SdrGrafObj
* pGrafObj
= new SdrGrafObj(
434 pScDrawView
->getSdrModelFromSdrView(),
438 // path was the name of the graphic in history
440 ScDrawLayer
* pLayer
= static_cast<ScDrawLayer
*>( pScDrawView
->GetModel() );
441 OUString aName
= pLayer
->GetNewGraphicName(); // "Graphics"
442 pGrafObj
->SetName(aName
);
445 bool bSuccess
= pScDrawView
->InsertObjectSafe(pGrafObj
, *pScDrawView
->GetSdrPageView());
447 // SetGraphicLink has to be used after inserting the object,
448 // otherwise an empty graphic is swapped in and the contact stuff crashes.
450 if (bSuccess
&& !rFile
.isEmpty())
451 pGrafObj
->SetGraphicLink( rFile
);
456 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */