From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- sc/source/ui/view/drawvie4.cxx | 581 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 581 insertions(+) create mode 100644 sc/source/ui/view/drawvie4.cxx (limited to 'sc/source/ui/view/drawvie4.cxx') diff --git a/sc/source/ui/view/drawvie4.cxx b/sc/source/ui/view/drawvie4.cxx new file mode 100644 index 000000000..178f43c45 --- /dev/null +++ b/sc/source/ui/view/drawvie4.cxx @@ -0,0 +1,581 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; + +Point aDragStartDiff; + +void ScDrawView::BeginDrag( vcl::Window* pWindow, const Point& rStartPos ) +{ + if ( AreObjectsMarked() ) + { + BrkAction(); + + tools::Rectangle aMarkedRect = GetAllMarkedRect(); + + aDragStartDiff = rStartPos - aMarkedRect.TopLeft(); + + bool bAnyOle, bOneOle; + const SdrMarkList& rMarkList = GetMarkedObjectList(); + CheckOle( rMarkList, bAnyOle, bOneOle ); + + ScDocShellRef aDragShellRef; + if (bAnyOle) + { + aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately + aDragShellRef->DoInitNew(); + } + ScDrawLayer::SetGlobalDrawPersist( aDragShellRef.get() ); + std::unique_ptr pModel(CreateMarkedObjModel()); + ScDrawLayer::SetGlobalDrawPersist(nullptr); + + // Charts now always copy their data in addition to the source reference, so + // there's no need to call SchDLL::Update for the charts in the clipboard doc. + // Update with the data (including NumberFormatter) from the live document would + // also store the NumberFormatter in the clipboard chart (#88749#) + + ScDocShell* pDocSh = pViewData->GetDocShell(); + + TransferableObjectDescriptor aObjDesc; + pDocSh->FillTransferableObjectDescriptor( aObjDesc ); + aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass(); + // maSize is set in ScDrawTransferObj ctor + + rtl::Reference pTransferObj = new ScDrawTransferObj( std::move(pModel), pDocSh, aObjDesc ); + + pTransferObj->SetDrawPersist( aDragShellRef.get() ); // keep persist for ole objects alive + pTransferObj->SetDragSource( this ); // copies selection + + SC_MOD()->SetDragObject( nullptr, pTransferObj.get() ); // for internal D&D + pTransferObj->StartDrag( pWindow, DND_ACTION_COPYMOVE | DND_ACTION_LINK ); + } +} + +namespace { + +void getRangeFromDataSource( uno::Reference< chart2::data::XDataSource > const & xDataSource, std::vector& rRangeRep) +{ + const uno::Sequence > xSeqs = xDataSource->getDataSequences(); + for (const uno::Reference& xLS : xSeqs) + { + uno::Reference xSeq = xLS->getValues(); + if (xSeq.is()) + { + OUString aRep = xSeq->getSourceRangeRepresentation(); + rRangeRep.push_back(aRep); + } + xSeq = xLS->getLabel(); + if (xSeq.is()) + { + OUString aRep = xSeq->getSourceRangeRepresentation(); + rRangeRep.push_back(aRep); + } + } +} + +void getRangeFromErrorBar(const uno::Reference< chart2::XChartDocument >& rChartDoc, std::vector& rRangeRep) +{ + uno::Reference xDiagram = rChartDoc->getFirstDiagram(); + if(!xDiagram.is()) + return; + + uno::Reference< chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY); + if(!xCooSysContainer.is()) + return; + + const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > xCooSysSequence( xCooSysContainer->getCoordinateSystems()); + for(const auto& rCooSys : xCooSysSequence) + { + uno::Reference< chart2::XChartTypeContainer > xChartTypeContainer( rCooSys, uno::UNO_QUERY); + if(!xChartTypeContainer.is()) + continue; + + const uno::Sequence< uno::Reference< chart2::XChartType > > xChartTypeSequence( xChartTypeContainer->getChartTypes() ); + for(const auto& rChartType : xChartTypeSequence) + { + uno::Reference< chart2::XDataSeriesContainer > xDataSequenceContainer( rChartType, uno::UNO_QUERY); + if(!xDataSequenceContainer.is()) + continue; + + const uno::Sequence< uno::Reference< chart2::XDataSeries > > xSeriesSequence( xDataSequenceContainer->getDataSeries() ); + for(const uno::Reference& xSeries : xSeriesSequence) + { + uno::Reference< beans::XPropertySet > xPropSet( xSeries, uno::UNO_QUERY); + uno::Reference< chart2::data::XDataSource > xErrorBarY; + xPropSet->getPropertyValue("ErrorBarY") >>= xErrorBarY; + if(xErrorBarY.is()) + getRangeFromDataSource(xErrorBarY, rRangeRep); + uno::Reference< chart2::data::XDataSource > xErrorBarX; + xPropSet->getPropertyValue("ErrorBarX") >>= xErrorBarX; + if(xErrorBarX.is()) + getRangeFromDataSource(xErrorBarX, rRangeRep); + } + } + } +} + +void getRangeFromOle2Object(const SdrOle2Obj& rObj, std::vector& rRangeRep) +{ + if (!rObj.IsChart()) + // not a chart object. + return; + + const uno::Reference& xObj = rObj.GetObjRef(); + if (!xObj.is()) + return; + + uno::Reference xChartDoc(xObj->getComponent(), uno::UNO_QUERY); + if (!xChartDoc.is()) + return; + + if(xChartDoc->hasInternalDataProvider()) + return; + + getRangeFromErrorBar(xChartDoc, rRangeRep); + + uno::Reference xDataSource(xChartDoc, uno::UNO_QUERY); + if (!xDataSource.is()) + return; + + // Get all data sources used in this chart. + getRangeFromDataSource(xDataSource, rRangeRep); + + return; +} + +// Get all cell ranges that are referenced by the selected chart objects. +void getOleSourceRanges(const SdrMarkList& rMarkList, bool& rAnyOle, bool& rOneOle, std::vector* pRanges = nullptr, const ScDocument* pDoc = nullptr ) +{ + bool bCalcSourceRanges = pRanges && pDoc; + std::vector aRangeReps; + rAnyOle = rOneOle = false; + const size_t nCount = rMarkList.GetMarkCount(); + for (size_t i=0; iGetMarkedSdrObj(); + if ( !pObj ) + continue; + + sal_uInt16 nSdrObjKind = pObj->GetObjIdentifier(); + if (nSdrObjKind == OBJ_OLE2) + { + rAnyOle = true; + rOneOle = (nCount == 1); + if ( bCalcSourceRanges ) + getRangeFromOle2Object( static_cast( *pObj ), aRangeReps ); + else + break; + } + else if ( dynamic_cast( pObj) != nullptr ) + { + SdrObjListIter aIter( *pObj, SdrIterMode::DeepNoGroups ); + SdrObject* pSubObj = aIter.Next(); + while (pSubObj) + { + if ( pSubObj->GetObjIdentifier() == OBJ_OLE2 ) + { + rAnyOle = true; + // rOneOle remains false - a group isn't treated like a single OLE object + if ( !bCalcSourceRanges ) + return; + + getRangeFromOle2Object( static_cast( *pSubObj ), aRangeReps ); + } + pSubObj = aIter.Next(); + } + } + } + + if (!bCalcSourceRanges) + return; + + // Compile all range representation strings into ranges. + for (const auto& rRangeRep : aRangeReps) + { + ScRangeList aRange; + ScAddress aAddr; + if (aRange.Parse(rRangeRep, pDoc, pDoc->GetAddressConvention()) & ScRefFlags::VALID) + { + for(size_t i = 0; i < aRange.size(); ++i) + pRanges->push_back(aRange[i]); + } + else if (aAddr.Parse(rRangeRep, pDoc, pDoc->GetAddressConvention()) & ScRefFlags::VALID) + pRanges->push_back(aAddr); + } + + return; +} + +class InsertTabIndex +{ + std::vector& mrTabs; +public: + explicit InsertTabIndex(std::vector& rTabs) : mrTabs(rTabs) {} + void operator() (const ScRange& rRange) + { + mrTabs.push_back(rRange.aStart.Tab()); + } +}; + +class CopyRangeData +{ + ScDocument* mpSrc; + ScDocument* mpDest; +public: + CopyRangeData(ScDocument* pSrc, ScDocument* pDest) : mpSrc(pSrc), mpDest(pDest) {} + + void operator() (const ScRange& rRange) + { + OUString aTabName; + mpSrc->GetName(rRange.aStart.Tab(), aTabName); + + SCTAB nTab; + if (!mpDest->GetTable(aTabName, nTab)) + // Sheet by this name doesn't exist. + return; + + mpSrc->CopyStaticToDocument(rRange, nTab, mpDest); + } +}; + +void copyChartRefDataToClipDoc(ScDocument* pSrcDoc, ScDocument* pClipDoc, const std::vector& rRanges) +{ + // Get a list of referenced table indices. + std::vector aTabs; + std::for_each(rRanges.begin(), rRanges.end(), InsertTabIndex(aTabs)); + std::sort(aTabs.begin(), aTabs.end()); + aTabs.erase(std::unique(aTabs.begin(), aTabs.end()), aTabs.end()); + + // Get table names. + if (aTabs.empty()) + return; + + // Create sheets only for referenced source sheets. + OUString aName; + std::vector::const_iterator it = aTabs.begin(), itEnd = aTabs.end(); + if (!pSrcDoc->GetName(*it, aName)) + return; + + pClipDoc->SetTabNameOnLoad(0, aName); // document initially has one sheet. + + for (++it; it != itEnd; ++it) + { + if (!pSrcDoc->GetName(*it, aName)) + return; + + pClipDoc->AppendTabOnLoad(aName); + } + + std::for_each(rRanges.begin(), rRanges.end(), CopyRangeData(pSrcDoc, pClipDoc)); +} + +} + +void ScDrawView::CheckOle( const SdrMarkList& rMarkList, bool& rAnyOle, bool& rOneOle ) +{ + getOleSourceRanges( rMarkList, rAnyOle, rOneOle ); +} + +void ScDrawView::DoCopy() +{ + const SdrMarkList& rMarkList = GetMarkedObjectList(); + std::vector aRanges; + bool bAnyOle = false, bOneOle = false; + getOleSourceRanges( rMarkList, bAnyOle, bOneOle, &aRanges, pDoc ); + + // update ScGlobal::xDrawClipDocShellRef + ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) ); + if (ScGlobal::xDrawClipDocShellRef.is() && !aRanges.empty()) + { + // Copy data referenced by the chart objects to the draw clip + // document. We need to do this before CreateMarkedObjModel() below. + ScDocShellRef xDocSh = ScGlobal::xDrawClipDocShellRef; + ScDocument& rClipDoc = xDocSh->GetDocument(); + copyChartRefDataToClipDoc(pDoc, &rClipDoc, aRanges); + } + std::unique_ptr pModel(CreateMarkedObjModel()); + ScDrawLayer::SetGlobalDrawPersist(nullptr); + + // Charts now always copy their data in addition to the source reference, so + // there's no need to call SchDLL::Update for the charts in the clipboard doc. + // Update with the data (including NumberFormatter) from the live document would + // also store the NumberFormatter in the clipboard chart (#88749#) + + ScDocShell* pDocSh = pViewData->GetDocShell(); + + TransferableObjectDescriptor aObjDesc; + pDocSh->FillTransferableObjectDescriptor( aObjDesc ); + aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass(); + // maSize is set in ScDrawTransferObj ctor + + rtl::Reference pTransferObj(new ScDrawTransferObj( std::move(pModel), pDocSh, aObjDesc )); + + if ( ScGlobal::xDrawClipDocShellRef.is() ) + { + pTransferObj->SetDrawPersist( ScGlobal::xDrawClipDocShellRef.get() ); // keep persist for ole objects alive + } + + pTransferObj->CopyToClipboard( pViewData->GetActiveWin() ); // system clipboard +} + +uno::Reference ScDrawView::CopyToTransferable() +{ + bool bAnyOle, bOneOle; + const SdrMarkList& rMarkList = GetMarkedObjectList(); + CheckOle( rMarkList, bAnyOle, bOneOle ); + + // update ScGlobal::xDrawClipDocShellRef + ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) ); + std::unique_ptr pModel( CreateMarkedObjModel() ); + ScDrawLayer::SetGlobalDrawPersist(nullptr); + + // Charts now always copy their data in addition to the source reference, so + // there's no need to call SchDLL::Update for the charts in the clipboard doc. + // Update with the data (including NumberFormatter) from the live document would + // also store the NumberFormatter in the clipboard chart (#88749#) + // lcl_RefreshChartData( pModel, pViewData->GetDocument() ); + + ScDocShell* pDocSh = pViewData->GetDocShell(); + + TransferableObjectDescriptor aObjDesc; + pDocSh->FillTransferableObjectDescriptor( aObjDesc ); + aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass(); + // maSize is set in ScDrawTransferObj ctor + + ScDrawTransferObj* pTransferObj = new ScDrawTransferObj( std::move(pModel), pDocSh, aObjDesc ); + uno::Reference xTransferable( pTransferObj ); + + if ( ScGlobal::xDrawClipDocShellRef.is() ) + { + pTransferObj->SetDrawPersist( ScGlobal::xDrawClipDocShellRef.get() ); // keep persist for ole objects alive + } + + return xTransferable; +} + +// Calculate correction for 100%, regardless of current settings + +void ScDrawView::CalcNormScale( Fraction& rFractX, Fraction& rFractY ) const +{ + double nPPTX = ScGlobal::nScreenPPTX; + double nPPTY = ScGlobal::nScreenPPTY; + + if (pViewData) + nPPTX /= pViewData->GetDocShell()->GetOutputFactor(); + + SCCOL nEndCol = 0; + SCROW nEndRow = 0; + pDoc->GetTableArea( nTab, nEndCol, nEndRow ); + if (nEndCol<20) + nEndCol = 20; + if (nEndRow<20) + nEndRow = 1000; + + Fraction aZoom(1,1); + ScDrawUtil::CalcScale( pDoc, nTab, 0,0, nEndCol,nEndRow, pDev, aZoom,aZoom, + nPPTX, nPPTY, rFractX,rFractY ); +} + +void ScDrawView::SetMarkedOriginalSize() +{ + std::unique_ptr pUndoGroup(new SdrUndoGroup(*GetModel())); + + const SdrMarkList& rMarkList = GetMarkedObjectList(); + long nDone = 0; + const size_t nCount = rMarkList.GetMarkCount(); + for (size_t i=0; iGetMarkedSdrObj(); + sal_uInt16 nIdent = pObj->GetObjIdentifier(); + bool bDo = false; + Size aOriginalSize; + if (nIdent == OBJ_OLE2) + { + // TODO/LEAN: working with visual area can switch object to running state + uno::Reference < embed::XEmbeddedObject > xObj = static_cast(pObj)->GetObjRef(); + if ( xObj.is() ) // NULL for an invalid object that couldn't be loaded + { + sal_Int64 nAspect = static_cast(pObj)->GetAspect(); + + if ( nAspect == embed::Aspects::MSOLE_ICON ) + { + MapMode aMapMode( MapUnit::Map100thMM ); + aOriginalSize = static_cast(pObj)->GetOrigObjSize( &aMapMode ); + bDo = true; + } + else + { + MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( static_cast(pObj)->GetAspect() ) ); + awt::Size aSz; + try + { + aSz = xObj->getVisualAreaSize( static_cast(pObj)->GetAspect() ); + aOriginalSize = OutputDevice::LogicToLogic( + Size( aSz.Width, aSz.Height ), + MapMode(aUnit), + MapMode(MapUnit::Map100thMM)); + bDo = true; + } catch( embed::NoVisualAreaSizeException& ) + { + OSL_ENSURE( false, "Can't get the original size of the object!" ); + } + } + } + } + else if (nIdent == OBJ_GRAF) + { + const Graphic& rGraphic = static_cast(pObj)->GetGraphic(); + + MapMode aSourceMap = rGraphic.GetPrefMapMode(); + MapMode aDestMap( MapUnit::Map100thMM ); + if (aSourceMap.GetMapUnit() == MapUnit::MapPixel) + { + // consider pixel correction, so that the bitmap is correct on the screen + Fraction aNormScaleX, aNormScaleY; + CalcNormScale( aNormScaleX, aNormScaleY ); + aDestMap.SetScaleX(aNormScaleX); + aDestMap.SetScaleY(aNormScaleY); + } + if (pViewData) + { + vcl::Window* pActWin = pViewData->GetActiveWin(); + if (pActWin) + { + aOriginalSize = pActWin->LogicToLogic( + rGraphic.GetPrefSize(), &aSourceMap, &aDestMap ); + bDo = true; + } + } + } + + if ( bDo ) + { + tools::Rectangle aDrawRect = pObj->GetLogicRect(); + + pUndoGroup->AddAction( std::make_unique( *pObj ) ); + pObj->Resize( aDrawRect.TopLeft(), Fraction( aOriginalSize.Width(), aDrawRect.GetWidth() ), + Fraction( aOriginalSize.Height(), aDrawRect.GetHeight() ) ); + ++nDone; + } + } + + if (nDone && pViewData) + { + pUndoGroup->SetComment(ScResId( STR_UNDO_ORIGINALSIZE )); + ScDocShell* pDocSh = pViewData->GetDocShell(); + pDocSh->GetUndoManager()->AddUndoAction(std::move(pUndoGroup)); + pDocSh->SetDrawModified(); + } +} + +void ScDrawView::FitToCellSize() +{ + const SdrMarkList& rMarkList = GetMarkedObjectList(); + + if (rMarkList.GetMarkCount() != 1) + { + SAL_WARN("sc.ui", "Fit to cell only works with one graphic!"); + return; + } + + SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); + + ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObj); + if (aAnchorType != SCA_CELL && aAnchorType != SCA_CELL_RESIZE) + { + SAL_WARN("sc.ui", "Fit to cell only works with cell anchored graphics!"); + return; + } + + ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pObj); + if (!pObjData) + { + SAL_WARN("sc.ui", "Missing ScDrawObjData!"); + return; + } + + std::unique_ptr pUndoGroup(new SdrUndoGroup(*GetModel())); + tools::Rectangle aGraphicRect = pObj->GetSnapRect(); + tools::Rectangle aCellRect = ScDrawLayer::GetCellRect( *pDoc, pObjData->maStart, true); + + // For graphic objects, we want to keep the aspect ratio + if (pObj->shouldKeepAspectRatio()) + { + long nWidth = aGraphicRect.GetWidth(); + assert(nWidth && "div-by-zero"); + double fScaleX = static_cast(aCellRect.GetWidth()) / static_cast(nWidth); + long nHeight = aGraphicRect.GetHeight(); + assert(nHeight && "div-by-zero"); + double fScaleY = static_cast(aCellRect.GetHeight()) / static_cast(nHeight); + double fScaleMin = std::min(fScaleX, fScaleY); + + aCellRect.setWidth(static_cast(aGraphicRect.GetWidth()) * fScaleMin); + aCellRect.setHeight(static_cast(aGraphicRect.GetHeight()) * fScaleMin); + } + + pUndoGroup->AddAction( std::make_unique( *pObj ) ); + if (pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE) + pObj->AdjustToMaxRect(aCellRect); + else + pObj->SetSnapRect(aCellRect); + + pUndoGroup->SetComment(ScResId( STR_UNDO_FITCELLSIZE )); + ScDocShell* pDocSh = pViewData->GetDocShell(); + pDocSh->GetUndoManager()->AddUndoAction(std::move(pUndoGroup)); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3