diff options
Diffstat (limited to 'sc/source/ui/view/viewfun7.cxx')
-rw-r--r-- | sc/source/ui/view/viewfun7.cxx | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/sc/source/ui/view/viewfun7.cxx b/sc/source/ui/view/viewfun7.cxx new file mode 100644 index 0000000000..f704256756 --- /dev/null +++ b/sc/source/ui/view/viewfun7.cxx @@ -0,0 +1,462 @@ +/* -*- 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 <com/sun/star/embed/NoVisualAreaSizeException.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> + +#include <svx/svditer.hxx> +#include <svx/svdograf.hxx> +#include <svx/svdoole2.hxx> +#include <svx/svdouno.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdundo.hxx> +#include <svtools/embedhlp.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/ipclient.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <com/sun/star/embed/Aspects.hpp> +#include <osl/diagnose.h> + +#include <document.hxx> +#include <viewfunc.hxx> +#include <tabvwsh.hxx> +#include <drawview.hxx> +#include <scmod.hxx> +#include <drwlayer.hxx> +#include <drwtrans.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <docuno.hxx> +#include <docsh.hxx> +#include <dragdata.hxx> +#include <gridwin.hxx> +#include <stlpool.hxx> + +bool bPasteIsMove = false; + +using namespace com::sun::star; + +static void lcl_AdjustInsertPos( ScViewData& rData, Point& rPos, const Size& rSize ) +{ + SdrPage* pPage = rData.GetScDrawView()->GetModel().GetPage( static_cast<sal_uInt16>(rData.GetTabNo()) ); + OSL_ENSURE(pPage,"pPage ???"); + Size aPgSize( pPage->GetSize() ); + if (aPgSize.Width() < 0) + aPgSize.setWidth( -aPgSize.Width() ); + tools::Long x = aPgSize.Width() - rPos.X() - rSize.Width(); + tools::Long y = aPgSize.Height() - rPos.Y() - rSize.Height(); + // if necessary: adjustments (80/200) for pixel approx. errors + if( x < 0 ) + rPos.AdjustX(x + 80 ); + if( y < 0 ) + rPos.AdjustY(y + 200 ); + rPos.AdjustX(rSize.Width() / 2 ); // position at paste is center + rPos.AdjustY(rSize.Height() / 2 ); +} + +void ScViewFunc::PasteDraw( const Point& rLogicPos, SdrModel* pModel, + bool bGroup, std::u16string_view rSrcShellID, std::u16string_view rDestShellID ) +{ + bool bSameDocClipboard = rSrcShellID == rDestShellID; + + MakeDrawLayer(); + Point aPos( rLogicPos ); + + // MapMode at Outliner-RefDevice has to be right (as in FuText::MakeOutliner) + //! merge with FuText::MakeOutliner? + MapMode aOldMapMode; + OutputDevice* pRef = GetViewData().GetDocument().GetDrawLayer()->GetRefDevice(); + if (pRef) + { + aOldMapMode = pRef->GetMapMode(); + pRef->SetMapMode( MapMode(MapUnit::Map100thMM) ); + } + + bool bNegativePage = GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() ); + + SdrView* pDragEditView = nullptr; + ScModule* pScMod = SC_MOD(); + const ScDragData& rData = pScMod->GetDragData(); + ScDrawTransferObj* pDrawTrans = rData.pDrawTransfer; + if (pDrawTrans) + { + pDragEditView = pDrawTrans->GetDragSourceView(); + + aPos -= aDragStartDiff; + if ( bNegativePage ) + { + if (aPos.X() > 0) aPos.setX( 0 ); + } + else + { + if (aPos.X() < 0) aPos.setX( 0 ); + } + if (aPos.Y() < 0) aPos.setY( 0 ); + } + + ScDrawView* pScDrawView = GetScDrawView(); + if (bGroup) + pScDrawView->BegUndo( ScResId( STR_UNDO_PASTE ) ); + + bool bSameDoc = ( pDragEditView && &pDragEditView->GetModel() == &pScDrawView->GetModel() ); + if (bSameDoc) + { + // copy locally - incl. charts + + Point aSourceStart = pDragEditView->GetAllMarkedRect().TopLeft(); + tools::Long nDiffX = aPos.X() - aSourceStart.X(); + tools::Long nDiffY = aPos.Y() - aSourceStart.Y(); + + // move within a page? + + if ( bPasteIsMove && + pScDrawView->GetSdrPageView()->GetPage() == + pDragEditView->GetSdrPageView()->GetPage() ) + { + if ( nDiffX != 0 || nDiffY != 0 ) + pDragEditView->MoveAllMarked(Size(nDiffX,nDiffY)); + } + else + { + SdrModel& rDrawModel = pDragEditView->GetModel(); + SCTAB nTab = GetViewData().GetTabNo(); + SdrPage* pDestPage = rDrawModel.GetPage( static_cast< sal_uInt16 >( nTab ) ); + OSL_ENSURE(pDestPage,"who is this, Page?"); + + ::std::vector< OUString > aExcludedChartNames; + if ( pDestPage ) + { + ScChartHelper::GetChartNames( aExcludedChartNames, pDestPage ); + } + + SdrMarkList aMark = pDragEditView->GetMarkedObjectList(); + aMark.ForceSort(); + const size_t nMarkCnt=aMark.GetMarkCount(); + for (size_t nm=0; nm<nMarkCnt; ++nm) { + const SdrMark* pM=aMark.GetMark(nm); + const SdrObject* pObj=pM->GetMarkedSdrObj(); + + // Directly Clone to target SdrModel + rtl::Reference<SdrObject> pNewObj(pObj->CloneSdrObject(rDrawModel)); + + if (pNewObj!=nullptr) + { + // copy graphics within the same model - always needs new name + if ( dynamic_cast<const SdrGrafObj*>( pNewObj.get()) != nullptr && !bPasteIsMove ) + pNewObj->SetName(static_cast<ScDrawLayer*>(&rDrawModel)->GetNewGraphicName()); + + if (nDiffX!=0 || nDiffY!=0) + pNewObj->NbcMove(Size(nDiffX,nDiffY)); + if (pDestPage) + pDestPage->InsertObject( pNewObj.get() ); + pScDrawView->AddUndo(std::make_unique<SdrUndoInsertObj>( *pNewObj )); + + if (ScDrawLayer::IsCellAnchored(*pNewObj)) + ScDrawLayer::SetCellAnchoredFromPosition(*pNewObj, GetViewData().GetDocument(), nTab, + ScDrawLayer::IsResizeWithCell(*pNewObj)); + } + } + + if (bPasteIsMove) + pDragEditView->DeleteMarked(); + + ScDocument& rDocument = GetViewData().GetDocument(); + ScDocShell* pDocShell = GetViewData().GetDocShell(); + ScModelObj* pModelObj = ( pDocShell ? pDocShell->GetModel() : nullptr ); + if ( pDestPage && pModelObj && pDrawTrans ) + { + const ScRangeListVector& rProtectedChartRangesVector( pDrawTrans->GetProtectedChartRangesVector() ); + ScChartHelper::CreateProtectedChartListenersAndNotify( rDocument, pDestPage, pModelObj, nTab, + rProtectedChartRangesVector, aExcludedChartNames, bSameDoc ); + } + } + } + else + { + bPasteIsMove = false; // no internal move happened + SdrView aView(*pModel); // #i71529# never create a base class of SdrView directly! + SdrPageView* pPv = aView.ShowSdrPage(aView.GetModel().GetPage(0)); + aView.MarkAllObj(pPv); + Size aSize = aView.GetAllMarkedRect().GetSize(); + lcl_AdjustInsertPos( GetViewData(), aPos, aSize ); + + // don't change marking if OLE object is active + // (at Drop from OLE object it would be deactivated in the middle of ExecuteDrag!) + + SdrInsertFlags nOptions = SdrInsertFlags::NONE; + SfxInPlaceClient* pClient = GetViewData().GetViewShell()->GetIPClient(); + if ( pClient && pClient->IsObjectInPlaceActive() ) + nOptions |= SdrInsertFlags::DONTMARK; + + ::std::vector< OUString > aExcludedChartNames; + SCTAB nTab = GetViewData().GetTabNo(); + SdrPage* pPage = pScDrawView->GetModel().GetPage( static_cast< sal_uInt16 >( nTab ) ); + OSL_ENSURE( pPage, "Page?" ); + if ( pPage ) + { + ScChartHelper::GetChartNames( aExcludedChartNames, pPage ); + } + + if ( !bSameDocClipboard ) + { + auto pPool = static_cast<ScStyleSheetPool*>(pScDrawView->GetModel().GetStyleSheetPool()); + pPool->CopyUsedGraphicStylesFrom(pModel->GetStyleSheetPool()); + + // #89247# Set flag for ScDocument::UpdateChartListeners() which is + // called during paste. + GetViewData().GetDocument().SetPastingDrawFromOtherDoc( true ); + } + + pScDrawView->Paste(*pModel, aPos, nullptr, nOptions); + + if ( !bSameDocClipboard ) + GetViewData().GetDocument().SetPastingDrawFromOtherDoc( false ); + + // Paste puts all objects on the active (front) layer + // controls must be on SC_LAYER_CONTROLS + if (pPage) + { + SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); + SdrObject* pObject = aIter.Next(); + while (pObject) + { + if ( dynamic_cast<const SdrUnoObj*>( pObject) != nullptr && pObject->GetLayer() != SC_LAYER_CONTROLS ) + pObject->NbcSetLayer(SC_LAYER_CONTROLS); + + if (ScDrawLayer::IsCellAnchored(*pObject)) + ScDrawLayer::SetCellAnchoredFromPosition(*pObject, GetViewData().GetDocument(), nTab, + ScDrawLayer::IsResizeWithCell(*pObject)); + + pObject = aIter.Next(); + } + } + + // all graphics objects must have names + GetViewData().GetDocument().EnsureGraphicNames(); + + ScDocument& rDocument = GetViewData().GetDocument(); + ScDocShell* pDocShell = GetViewData().GetDocShell(); + ScModelObj* pModelObj = ( pDocShell ? pDocShell->GetModel() : nullptr ); + const ScDrawTransferObj* pTransferObj = ScDrawTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(GetViewData().GetActiveWin())); + if ( pPage && pModelObj && ( pTransferObj || pDrawTrans ) ) + { + const ScRangeListVector& rProtectedChartRangesVector( + pTransferObj ? pTransferObj->GetProtectedChartRangesVector() : pDrawTrans->GetProtectedChartRangesVector() ); + ScChartHelper::CreateProtectedChartListenersAndNotify( rDocument, pPage, pModelObj, nTab, + rProtectedChartRangesVector, aExcludedChartNames, bSameDocClipboard ); + } + } + + if (bGroup) + { + pScDrawView->GroupMarked(); + pScDrawView->EndUndo(); + } + + if (pRef) + pRef->SetMapMode( aOldMapMode ); + + // GetViewData().GetViewShell()->SetDrawShell( true ); + // It is not sufficient to just set the DrawShell if we pasted, for + // example, a chart. SetDrawShellOrSub() would only work for D&D in the + // same document but not if inserting from the clipboard, therefore + // MarkListHasChanged() is what we need. + pScDrawView->MarkListHasChanged(); + +} + +bool ScViewFunc::PasteObject( const Point& rPos, const uno::Reference < embed::XEmbeddedObject >& xObj, + const Size* pDescSize, const Graphic* pReplGraph, const OUString& aMediaType, sal_Int64 nAspect ) +{ + MakeDrawLayer(); + if ( xObj.is() ) + { + OUString aName; + //TODO/MBA: is that OK? + comphelper::EmbeddedObjectContainer& aCnt = GetViewData().GetViewShell()->GetObjectShell()->GetEmbeddedObjectContainer(); + if ( !aCnt.HasEmbeddedObject( xObj ) ) + aCnt.InsertEmbeddedObject( xObj, aName ); + else + aName = aCnt.GetEmbeddedObjectName( xObj ); + + svt::EmbeddedObjectRef aObjRef( xObj, nAspect ); + if ( pReplGraph ) + aObjRef.SetGraphic( *pReplGraph, aMediaType ); + + Size aSize; + if ( nAspect == embed::Aspects::MSOLE_ICON ) + { + MapMode aMapMode( MapUnit::Map100thMM ); + aSize = aObjRef.GetSize( &aMapMode ); + } + else + { + // working with visual area can switch object to running state + MapUnit aMapObj = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) ); + MapUnit aMap100 = MapUnit::Map100thMM; + + if ( pDescSize && pDescSize->Width() && pDescSize->Height() ) + { + // use size from object descriptor if given + aSize = OutputDevice::LogicToLogic(*pDescSize, MapMode(aMap100), MapMode(aMapObj)); + awt::Size aSz; + aSz.Width = aSize.Width(); + aSz.Height = aSize.Height(); + xObj->setVisualAreaSize( nAspect, aSz ); + } + + awt::Size aSz; + try + { + aSz = xObj->getVisualAreaSize( nAspect ); + } + catch ( embed::NoVisualAreaSizeException& ) + { + // the default size will be set later + } + + aSize = Size( aSz.Width, aSz.Height ); + aSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapObj), MapMode(aMap100)); // for SdrOle2Obj + + if( aSize.IsEmpty() ) + { + OSL_FAIL("SvObjectDescriptor::GetSize == 0"); + aSize.setWidth( 5000 ); + aSize.setHeight( 5000 ); + aSize = OutputDevice::LogicToLogic(aSize, MapMode(aMap100), MapMode(aMapObj)); + aSz.Width = aSize.Width(); + aSz.Height = aSize.Height(); + xObj->setVisualAreaSize( nAspect, aSz ); + } + } + + // don't call AdjustInsertPos + Point aInsPos = rPos; + if ( GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() ) ) + aInsPos.AdjustX( -(aSize.Width()) ); + tools::Rectangle aRect( aInsPos, aSize ); + + ScDrawView* pDrView = GetScDrawView(); + rtl::Reference<SdrOle2Obj> pSdrObj = new SdrOle2Obj( + pDrView->getSdrModelFromSdrView(), + aObjRef, + aName, + aRect); + + SdrPageView* pPV = pDrView->GetSdrPageView(); + pDrView->InsertObjectSafe( pSdrObj.get(), *pPV ); // don't mark if OLE + GetViewData().GetViewShell()->SetDrawShell( true ); + return true; + } + else + return false; +} + +bool ScViewFunc::PasteBitmapEx( const Point& rPos, const BitmapEx& rBmpEx ) +{ + Graphic aGraphic(rBmpEx); + return PasteGraphic( rPos, aGraphic, "" ); +} + +bool ScViewFunc::PasteMetaFile( const Point& rPos, const GDIMetaFile& rMtf ) +{ + Graphic aGraphic(rMtf); + return PasteGraphic( rPos, aGraphic, "" ); +} + +bool ScViewFunc::PasteGraphic( const Point& rPos, const Graphic& rGraphic, + const OUString& rFile ) +{ + MakeDrawLayer(); + ScDrawView* pScDrawView = GetScDrawView(); + + if (!pScDrawView) + return false; + + // #i123922# check if the drop was over an existing object; if yes, evtl. replace + // the graphic for a SdrGraphObj (including link state updates) or adapt the fill + // style for other objects + SdrPageView* pPageView = pScDrawView->GetSdrPageView(); + if (pPageView) + { + SdrObject* pPickObj = pScDrawView->PickObj(rPos, pScDrawView->getHitTolLog(), pPageView); + if (pPickObj) + { + const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP)); + SdrObject* pResult = pScDrawView->ApplyGraphicToObject( + *pPickObj, + rGraphic, + aBeginUndo, + rFile); + + if (pResult) + { + // we are done; mark the modified/new object + pScDrawView->MarkObj(pResult, pScDrawView->GetSdrPageView()); + return true; + } + } + } + + Point aPos( rPos ); + vcl::Window* pWin = GetActiveWin(); + MapMode aSourceMap = rGraphic.GetPrefMapMode(); + MapMode aDestMap( MapUnit::Map100thMM ); + + if (aSourceMap.GetMapUnit() == MapUnit::MapPixel) + { + // consider pixel correction, so bitmap fits to screen + Fraction aScaleX, aScaleY; + pScDrawView->CalcNormScale( aScaleX, aScaleY ); + aDestMap.SetScaleX(aScaleX); + aDestMap.SetScaleY(aScaleY); + } + + Size aSize = pWin->LogicToLogic( rGraphic.GetPrefSize(), &aSourceMap, &aDestMap ); + + if ( GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() ) ) + aPos.AdjustX( -(aSize.Width()) ); + + GetViewData().GetViewShell()->SetDrawShell( true ); + tools::Rectangle aRect(aPos, aSize); + rtl::Reference<SdrGrafObj> pGrafObj = new SdrGrafObj( + pScDrawView->getSdrModelFromSdrView(), + rGraphic, + aRect); + + // path was the name of the graphic in history + + ScDrawLayer* pLayer = static_cast<ScDrawLayer*>(&pScDrawView->GetModel()); + OUString aName = pLayer->GetNewGraphicName(); // "Graphics" + pGrafObj->SetName(aName); + + // don't mark if OLE + bool bSuccess = pScDrawView->InsertObjectSafe(pGrafObj.get(), *pScDrawView->GetSdrPageView()); + + // SetGraphicLink has to be used after inserting the object, + // otherwise an empty graphic is swapped in and the contact stuff crashes. + // See #i37444#. + if (bSuccess && !rFile.isEmpty()) + pGrafObj->SetGraphicLink( rFile ); + + return bSuccess; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |