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 <svx/svditer.hxx>
21 #include <svx/svdograf.hxx>
22 #include <svx/svdogrp.hxx>
23 #include <svx/svdoole2.hxx>
24 #include <svx/svdundo.hxx>
25 #include <sfx2/docfile.hxx>
26 #include <tools/urlobj.hxx>
27 #include <toolkit/helper/vclunohelper.hxx>
28 #include <sal/log.hxx>
30 #include <drawview.hxx>
32 #include <drwlayer.hxx>
33 #include <viewdata.hxx>
34 #include <document.hxx>
36 #include <drwtrans.hxx>
37 #include <transobj.hxx>
38 #include <drawutil.hxx>
40 #include <globstr.hrc>
41 #include <scresid.hxx>
42 #include <gridwin.hxx>
43 #include <userdat.hxx>
45 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
46 #include <com/sun/star/embed/Aspects.hpp>
47 #include <com/sun/star/embed/XEmbeddedObject.hpp>
48 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
49 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
50 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
51 #include <com/sun/star/chart2/XChartDocument.hpp>
52 #include <comphelper/diagnose_ex.hxx>
54 using namespace com::sun::star
;
58 void ScDrawView::BeginDrag( vcl::Window
* pWindow
, const Point
& rStartPos
)
60 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
61 if ( rMarkList
.GetMarkCount() == 0 )
66 tools::Rectangle aMarkedRect
= GetAllMarkedRect();
68 aDragStartDiff
= rStartPos
- aMarkedRect
.TopLeft();
70 bool bAnyOle
, bOneOle
;
71 CheckOle( rMarkList
, bAnyOle
, bOneOle
);
73 ScDocShellRef aDragShellRef
;
76 aDragShellRef
= new ScDocShell
; // DocShell needs a Ref immediately
77 aDragShellRef
->DoInitNew();
79 ScDrawLayer::SetGlobalDrawPersist( aDragShellRef
.get() );
80 std::unique_ptr
<SdrModel
> pModel(CreateMarkedObjModel());
81 ScDrawLayer::SetGlobalDrawPersist(nullptr);
83 // Charts now always copy their data in addition to the source reference, so
84 // there's no need to call SchDLL::Update for the charts in the clipboard doc.
85 // Update with the data (including NumberFormatter) from the live document would
86 // also store the NumberFormatter in the clipboard chart (#88749#)
88 ScDocShell
* pDocSh
= pViewData
->GetDocShell();
90 TransferableObjectDescriptor aObjDesc
;
91 pDocSh
->FillTransferableObjectDescriptor( aObjDesc
);
92 aObjDesc
.maDisplayName
= pDocSh
->GetMedium()->GetURLObject().GetURLNoPass();
93 // maSize is set in ScDrawTransferObj ctor
95 rtl::Reference
<ScDrawTransferObj
> pTransferObj
= new ScDrawTransferObj( std::move(pModel
), pDocSh
, std::move(aObjDesc
) );
97 pTransferObj
->SetDrawPersist(aDragShellRef
); // keep persist for ole objects alive
98 pTransferObj
->SetDragSource( this ); // copies selection
100 ScModule::get()->SetDragObject(nullptr, pTransferObj
.get()); // for internal D&D
101 pTransferObj
->StartDrag( pWindow
, DND_ACTION_COPYMOVE
| DND_ACTION_LINK
);
106 void getRangeFromDataSource( uno::Reference
< chart2::data::XDataSource
> const & xDataSource
, std::vector
<OUString
>& rRangeRep
)
108 const uno::Sequence
<uno::Reference
<chart2::data::XLabeledDataSequence
> > xSeqs
= xDataSource
->getDataSequences();
109 for (const uno::Reference
<chart2::data::XLabeledDataSequence
>& xLS
: xSeqs
)
111 uno::Reference
<chart2::data::XDataSequence
> xSeq
= xLS
->getValues();
114 OUString aRep
= xSeq
->getSourceRangeRepresentation();
115 rRangeRep
.push_back(aRep
);
117 xSeq
= xLS
->getLabel();
120 OUString aRep
= xSeq
->getSourceRangeRepresentation();
121 rRangeRep
.push_back(aRep
);
126 void getRangeFromErrorBar(const uno::Reference
< chart2::XChartDocument
>& rChartDoc
, std::vector
<OUString
>& rRangeRep
)
128 uno::Reference
<chart2::XDiagram
> xDiagram
= rChartDoc
->getFirstDiagram();
132 uno::Reference
< chart2::XCoordinateSystemContainer
> xCooSysContainer( xDiagram
, uno::UNO_QUERY
);
133 if(!xCooSysContainer
.is())
136 const uno::Sequence
< uno::Reference
< chart2::XCoordinateSystem
> > xCooSysSequence( xCooSysContainer
->getCoordinateSystems());
137 for(const auto& rCooSys
: xCooSysSequence
)
139 uno::Reference
< chart2::XChartTypeContainer
> xChartTypeContainer( rCooSys
, uno::UNO_QUERY
);
140 if(!xChartTypeContainer
.is())
143 const uno::Sequence
< uno::Reference
< chart2::XChartType
> > xChartTypeSequence( xChartTypeContainer
->getChartTypes() );
144 for(const auto& rChartType
: xChartTypeSequence
)
146 uno::Reference
< chart2::XDataSeriesContainer
> xDataSequenceContainer( rChartType
, uno::UNO_QUERY
);
147 if(!xDataSequenceContainer
.is())
150 const uno::Sequence
< uno::Reference
< chart2::XDataSeries
> > xSeriesSequence( xDataSequenceContainer
->getDataSeries() );
151 for(const uno::Reference
<chart2::XDataSeries
>& xSeries
: xSeriesSequence
)
153 uno::Reference
< beans::XPropertySet
> xPropSet( xSeries
, uno::UNO_QUERY
);
154 uno::Reference
< chart2::data::XDataSource
> xErrorBarY
;
155 xPropSet
->getPropertyValue(u
"ErrorBarY"_ustr
) >>= xErrorBarY
;
157 getRangeFromDataSource(xErrorBarY
, rRangeRep
);
158 uno::Reference
< chart2::data::XDataSource
> xErrorBarX
;
159 xPropSet
->getPropertyValue(u
"ErrorBarX"_ustr
) >>= xErrorBarX
;
161 getRangeFromDataSource(xErrorBarX
, rRangeRep
);
167 void getRangeFromOle2Object(const SdrOle2Obj
& rObj
, std::vector
<OUString
>& rRangeRep
)
170 // not a chart object.
173 const uno::Reference
<embed::XEmbeddedObject
>& xObj
= rObj
.GetObjRef();
177 uno::Reference
<chart2::XChartDocument
> xChartDoc(xObj
->getComponent(), uno::UNO_QUERY
);
181 if(xChartDoc
->hasInternalDataProvider())
184 getRangeFromErrorBar(xChartDoc
, rRangeRep
);
186 uno::Reference
<chart2::data::XDataSource
> xDataSource(xChartDoc
, uno::UNO_QUERY
);
187 if (!xDataSource
.is())
190 // Get all data sources used in this chart.
191 getRangeFromDataSource(xDataSource
, rRangeRep
);
196 // Get all cell ranges that are referenced by the selected chart objects.
197 void getOleSourceRanges(const SdrMarkList
& rMarkList
, bool& rAnyOle
, bool& rOneOle
, std::vector
<ScRange
>* pRanges
= nullptr, const ScDocument
* pDoc
= nullptr )
199 bool bCalcSourceRanges
= pRanges
&& pDoc
;
200 std::vector
<OUString
> aRangeReps
;
201 rAnyOle
= rOneOle
= false;
202 const size_t nCount
= rMarkList
.GetMarkCount();
203 for (size_t i
=0; i
<nCount
; ++i
)
205 SdrMark
* pMark
= rMarkList
.GetMark(i
);
209 SdrObject
* pObj
= pMark
->GetMarkedSdrObj();
213 SdrObjKind nSdrObjKind
= pObj
->GetObjIdentifier();
214 if (nSdrObjKind
== SdrObjKind::OLE2
)
217 rOneOle
= (nCount
== 1);
218 if ( bCalcSourceRanges
)
219 getRangeFromOle2Object( static_cast<const SdrOle2Obj
&>( *pObj
), aRangeReps
);
223 else if ( dynamic_cast<const SdrObjGroup
*>( pObj
) != nullptr )
225 SdrObjListIter
aIter( *pObj
, SdrIterMode::DeepNoGroups
);
226 SdrObject
* pSubObj
= aIter
.Next();
229 if ( pSubObj
->GetObjIdentifier() == SdrObjKind::OLE2
)
232 // rOneOle remains false - a group isn't treated like a single OLE object
233 if ( !bCalcSourceRanges
)
236 getRangeFromOle2Object( static_cast<const SdrOle2Obj
&>( *pSubObj
), aRangeReps
);
238 pSubObj
= aIter
.Next();
243 if (!bCalcSourceRanges
)
246 // Compile all range representation strings into ranges.
247 for (const auto& rRangeRep
: aRangeReps
)
251 if (aRange
.Parse(rRangeRep
, *pDoc
, pDoc
->GetAddressConvention()) & ScRefFlags::VALID
)
253 pRanges
->insert(pRanges
->end(), aRange
.begin(), aRange
.end());
255 else if (aAddr
.Parse(rRangeRep
, *pDoc
, pDoc
->GetAddressConvention()) & ScRefFlags::VALID
)
256 pRanges
->push_back(ScRange(aAddr
));
264 std::vector
<SCTAB
>& mrTabs
;
266 explicit InsertTabIndex(std::vector
<SCTAB
>& rTabs
) : mrTabs(rTabs
) {}
267 void operator() (const ScRange
& rRange
)
269 mrTabs
.push_back(rRange
.aStart
.Tab());
278 CopyRangeData(ScDocument
& rSrc
, ScDocument
& rDest
) : mrSrc(rSrc
), mrDest(rDest
) {}
280 void operator() (const ScRange
& rRange
)
283 mrSrc
.GetName(rRange
.aStart
.Tab(), aTabName
);
286 if (!mrDest
.GetTable(aTabName
, nTab
))
287 // Sheet by this name doesn't exist.
290 mrSrc
.CopyStaticToDocument(rRange
, nTab
, mrDest
);
294 void copyChartRefDataToClipDoc(ScDocument
& rSrcDoc
, ScDocument
& rClipDoc
, const std::vector
<ScRange
>& rRanges
)
296 // Get a list of referenced table indices.
297 std::vector
<SCTAB
> aTabs
;
298 std::for_each(rRanges
.begin(), rRanges
.end(), InsertTabIndex(aTabs
));
299 std::sort(aTabs
.begin(), aTabs
.end());
300 aTabs
.erase(std::unique(aTabs
.begin(), aTabs
.end()), aTabs
.end());
306 // Create sheets only for referenced source sheets.
308 std::vector
<SCTAB
>::const_iterator it
= aTabs
.begin(), itEnd
= aTabs
.end();
309 if (!rSrcDoc
.GetName(*it
, aName
))
312 rClipDoc
.SetTabNameOnLoad(0, aName
); // document initially has one sheet.
314 for (++it
; it
!= itEnd
; ++it
)
316 if (!rSrcDoc
.GetName(*it
, aName
))
319 rClipDoc
.AppendTabOnLoad(aName
);
322 std::for_each(rRanges
.begin(), rRanges
.end(), CopyRangeData(rSrcDoc
, rClipDoc
));
327 void ScDrawView::CheckOle( const SdrMarkList
& rMarkList
, bool& rAnyOle
, bool& rOneOle
)
329 getOleSourceRanges( rMarkList
, rAnyOle
, rOneOle
);
332 void ScDrawView::DoCopy()
334 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
335 std::vector
<ScRange
> aRanges
;
336 bool bAnyOle
= false, bOneOle
= false;
337 getOleSourceRanges( rMarkList
, bAnyOle
, bOneOle
, &aRanges
, &rDoc
);
339 // update ScGlobal::xDrawClipDocShellRef
340 ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle
) );
341 if (ScGlobal::xDrawClipDocShellRef
.is() && !aRanges
.empty())
343 // Copy data referenced by the chart objects to the draw clip
344 // document. We need to do this before CreateMarkedObjModel() below.
345 ScDocShellRef xDocSh
= ScGlobal::xDrawClipDocShellRef
;
346 ScDocument
& rClipDoc
= xDocSh
->GetDocument();
347 copyChartRefDataToClipDoc(rDoc
, rClipDoc
, aRanges
);
349 std::unique_ptr
<SdrModel
> pModel(CreateMarkedObjModel());
350 ScDrawLayer::SetGlobalDrawPersist(nullptr);
352 // Charts now always copy their data in addition to the source reference, so
353 // there's no need to call SchDLL::Update for the charts in the clipboard doc.
354 // Update with the data (including NumberFormatter) from the live document would
355 // also store the NumberFormatter in the clipboard chart (#88749#)
357 ScDocShell
* pDocSh
= pViewData
->GetDocShell();
359 TransferableObjectDescriptor aObjDesc
;
360 pDocSh
->FillTransferableObjectDescriptor( aObjDesc
);
361 aObjDesc
.maDisplayName
= pDocSh
->GetMedium()->GetURLObject().GetURLNoPass();
362 // maSize is set in ScDrawTransferObj ctor
364 rtl::Reference
<ScDrawTransferObj
> pTransferObj(new ScDrawTransferObj( std::move(pModel
), pDocSh
, std::move(aObjDesc
) ));
366 if ( ScGlobal::xDrawClipDocShellRef
.is() )
368 pTransferObj
->SetDrawPersist( ScGlobal::xDrawClipDocShellRef
); // keep persist for ole objects alive
371 pTransferObj
->CopyToClipboard( pViewData
->GetActiveWin() ); // system clipboard
374 uno::Reference
<datatransfer::XTransferable
> ScDrawView::CopyToTransferable()
376 bool bAnyOle
, bOneOle
;
377 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
378 CheckOle( rMarkList
, bAnyOle
, bOneOle
);
380 // update ScGlobal::xDrawClipDocShellRef
381 ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle
) );
382 std::unique_ptr
<SdrModel
> pModel( CreateMarkedObjModel() );
383 ScDrawLayer::SetGlobalDrawPersist(nullptr);
385 // Charts now always copy their data in addition to the source reference, so
386 // there's no need to call SchDLL::Update for the charts in the clipboard doc.
387 // Update with the data (including NumberFormatter) from the live document would
388 // also store the NumberFormatter in the clipboard chart (#88749#)
389 // lcl_RefreshChartData( pModel, pViewData->GetDocument() );
391 ScDocShell
* pDocSh
= pViewData
->GetDocShell();
393 TransferableObjectDescriptor aObjDesc
;
394 pDocSh
->FillTransferableObjectDescriptor( aObjDesc
);
395 aObjDesc
.maDisplayName
= pDocSh
->GetMedium()->GetURLObject().GetURLNoPass();
396 // maSize is set in ScDrawTransferObj ctor
398 rtl::Reference
<ScDrawTransferObj
> pTransferObj
= new ScDrawTransferObj( std::move(pModel
), pDocSh
, std::move(aObjDesc
) );
400 if ( ScGlobal::xDrawClipDocShellRef
.is() )
402 pTransferObj
->SetDrawPersist( ScGlobal::xDrawClipDocShellRef
); // keep persist for ole objects alive
408 // Calculate correction for 100%, regardless of current settings
410 void ScDrawView::CalcNormScale( Fraction
& rFractX
, Fraction
& rFractY
) const
412 double nPPTX
= ScGlobal::nScreenPPTX
;
413 double nPPTY
= ScGlobal::nScreenPPTY
;
416 nPPTX
/= pViewData
->GetDocShell()->GetOutputFactor();
420 rDoc
.GetTableArea( nTab
, nEndCol
, nEndRow
);
427 ScDrawUtil::CalcScale( rDoc
, nTab
, 0,0, nEndCol
,nEndRow
, pDev
, aZoom
,aZoom
,
428 nPPTX
, nPPTY
, rFractX
,rFractY
);
431 void ScDrawView::SetMarkedOriginalSize()
433 std::unique_ptr
<SdrUndoGroup
> pUndoGroup(new SdrUndoGroup(GetModel()));
435 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
436 tools::Long nDone
= 0;
437 const size_t nCount
= rMarkList
.GetMarkCount();
438 for (size_t i
=0; i
<nCount
; ++i
)
440 SdrObject
* pObj
= rMarkList
.GetMark(i
)->GetMarkedSdrObj();
441 SdrObjKind nIdent
= pObj
->GetObjIdentifier();
444 if (nIdent
== SdrObjKind::OLE2
)
446 // TODO/LEAN: working with visual area can switch object to running state
447 uno::Reference
< embed::XEmbeddedObject
> xObj
= static_cast<SdrOle2Obj
*>(pObj
)->GetObjRef();
448 if ( xObj
.is() ) // NULL for an invalid object that couldn't be loaded
450 sal_Int64 nAspect
= static_cast<SdrOle2Obj
*>(pObj
)->GetAspect();
452 if ( nAspect
== embed::Aspects::MSOLE_ICON
)
454 MapMode
aMapMode( MapUnit::Map100thMM
);
455 aOriginalSize
= static_cast<SdrOle2Obj
*>(pObj
)->GetOrigObjSize( &aMapMode
);
460 MapUnit aUnit
= VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj
->getMapUnit( static_cast<SdrOle2Obj
*>(pObj
)->GetAspect() ) );
463 awt::Size aSz
= xObj
->getVisualAreaSize( static_cast<SdrOle2Obj
*>(pObj
)->GetAspect() );
464 aOriginalSize
= OutputDevice::LogicToLogic(
465 Size( aSz
.Width
, aSz
.Height
),
467 MapMode(MapUnit::Map100thMM
));
469 } catch( embed::NoVisualAreaSizeException
& )
471 TOOLS_WARN_EXCEPTION("sc.ui", "Can't get the original size of the object!" );
476 else if (nIdent
== SdrObjKind::Graphic
)
478 const SdrGrafObj
* pSdrGrafObj
= static_cast<const SdrGrafObj
*>(pObj
);
480 MapMode aSourceMap
= pSdrGrafObj
->GetGraphic().GetPrefMapMode();
481 MapMode
aDestMap( MapUnit::Map100thMM
);
482 if (aSourceMap
.GetMapUnit() == MapUnit::MapPixel
)
484 // consider pixel correction, so that the bitmap is correct on the screen
485 Fraction aNormScaleX
, aNormScaleY
;
486 CalcNormScale( aNormScaleX
, aNormScaleY
);
487 aDestMap
.SetScaleX(aNormScaleX
);
488 aDestMap
.SetScaleY(aNormScaleY
);
490 aOriginalSize
= pSdrGrafObj
->getOriginalSize();
496 tools::Rectangle aDrawRect
= pObj
->GetLogicRect();
498 pUndoGroup
->AddAction( std::make_unique
<SdrUndoGeoObj
>( *pObj
) );
499 pObj
->Resize( aDrawRect
.TopLeft(), Fraction( aOriginalSize
.Width(), aDrawRect
.GetWidth() ),
500 Fraction( aOriginalSize
.Height(), aDrawRect
.GetHeight() ) );
505 if (nDone
&& pViewData
)
507 pUndoGroup
->SetComment(ScResId( STR_UNDO_ORIGINALSIZE
));
508 ScDocShell
* pDocSh
= pViewData
->GetDocShell();
509 pDocSh
->GetUndoManager()->AddUndoAction(std::move(pUndoGroup
));
510 pDocSh
->SetDrawModified();
514 void ScDrawView::FitToCellSize()
516 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
518 if (rMarkList
.GetMarkCount() != 1)
520 SAL_WARN("sc.ui", "Fit to cell only works with one graphic!");
524 SdrObject
* pObj
= rMarkList
.GetMark(0)->GetMarkedSdrObj();
526 ScAnchorType aAnchorType
= ScDrawLayer::GetAnchorType(*pObj
);
527 if (aAnchorType
!= SCA_CELL
&& aAnchorType
!= SCA_CELL_RESIZE
)
529 SAL_WARN("sc.ui", "Fit to cell only works with cell anchored graphics!");
533 ScDrawObjData
* pObjData
= ScDrawLayer::GetObjData(pObj
);
536 SAL_WARN("sc.ui", "Missing ScDrawObjData!");
540 std::unique_ptr
<SdrUndoGroup
> pUndoGroup(new SdrUndoGroup(GetModel()));
541 tools::Rectangle aGraphicRect
= pObj
->GetSnapRect();
542 tools::Rectangle aCellRect
= ScDrawLayer::GetCellRect( rDoc
, pObjData
->maStart
, true);
544 // For graphic objects, we want to keep the aspect ratio
545 if (pObj
->shouldKeepAspectRatio())
547 tools::Long nWidth
= aGraphicRect
.GetWidth();
548 assert(nWidth
&& "div-by-zero");
549 double fScaleX
= static_cast<double>(aCellRect
.GetWidth()) / static_cast<double>(nWidth
);
550 tools::Long nHeight
= aGraphicRect
.GetHeight();
551 assert(nHeight
&& "div-by-zero");
552 double fScaleY
= static_cast<double>(aCellRect
.GetHeight()) / static_cast<double>(nHeight
);
553 double fScaleMin
= std::min(fScaleX
, fScaleY
);
555 aCellRect
.setWidth(static_cast<double>(aGraphicRect
.GetWidth()) * fScaleMin
);
556 aCellRect
.setHeight(static_cast<double>(aGraphicRect
.GetHeight()) * fScaleMin
);
559 pUndoGroup
->AddAction( std::make_unique
<SdrUndoGeoObj
>( *pObj
) );
560 if (pObj
->GetObjIdentifier() == SdrObjKind::CustomShape
)
561 pObj
->AdjustToMaxRect(aCellRect
);
563 pObj
->SetSnapRect(aCellRect
);
565 pUndoGroup
->SetComment(ScResId( STR_UNDO_FITCELLSIZE
));
566 ScDocShell
* pDocSh
= pViewData
->GetDocShell();
567 pDocSh
->GetUndoManager()->AddUndoAction(std::move(pUndoGroup
));
571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */