788 lines
26 KiB
C++
788 lines
26 KiB
C++
/* -*- 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 <vector>
|
|
#include <unordered_set>
|
|
#include <editeng/editdata.hxx>
|
|
#include <rtl/strbuf.hxx>
|
|
#include <svx/xfillit0.hxx>
|
|
#include <svx/xlineit0.hxx>
|
|
#include <svx/svdxcgv.hxx>
|
|
#include <svx/svdoutl.hxx>
|
|
#include <svx/svdundo.hxx>
|
|
#include <svx/svdograf.hxx>
|
|
#include <svx/svdomedia.hxx>
|
|
#include <svx/svdoole2.hxx>
|
|
#include <svx/svdorect.hxx>
|
|
#include <svx/svdopage.hxx>
|
|
#include <svx/svdpage.hxx>
|
|
#include <svx/svdpagv.hxx>
|
|
#include <svx/svdtrans.hxx>
|
|
#include <svx/strings.hrc>
|
|
#include <svx/dialmgr.hxx>
|
|
#include <tools/bigint.hxx>
|
|
#include <clonelist.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <svl/style.hxx>
|
|
#include <fmobj.hxx>
|
|
#include <vcl/vectorgraphicdata.hxx>
|
|
#include <drawinglayer/primitive2d/groupprimitive2d.hxx>
|
|
#include <drawinglayer/geometry/viewinformation2d.hxx>
|
|
#include <drawinglayer/converters.hxx>
|
|
#include <svx/sdr/contact/viewcontact.hxx>
|
|
#include <sdr/contact/objectcontactofobjlistpainter.hxx>
|
|
#include <svx/sdr/contact/displayinfo.hxx>
|
|
#include <svx/svdotable.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <comphelper/lok.hxx>
|
|
|
|
using namespace com::sun::star;
|
|
|
|
SdrExchangeView::SdrExchangeView(
|
|
SdrModel& rSdrModel,
|
|
OutputDevice* pOut)
|
|
: SdrObjEditView(rSdrModel, pOut)
|
|
{
|
|
}
|
|
|
|
bool SdrExchangeView::ImpLimitToWorkArea(Point& rPt) const
|
|
{
|
|
bool bRet(false);
|
|
|
|
if(!maMaxWorkArea.IsEmpty())
|
|
{
|
|
if(rPt.X()<maMaxWorkArea.Left())
|
|
{
|
|
rPt.setX( maMaxWorkArea.Left() );
|
|
bRet = true;
|
|
}
|
|
|
|
if(rPt.X()>maMaxWorkArea.Right())
|
|
{
|
|
rPt.setX( maMaxWorkArea.Right() );
|
|
bRet = true;
|
|
}
|
|
|
|
if(rPt.Y()<maMaxWorkArea.Top())
|
|
{
|
|
rPt.setY( maMaxWorkArea.Top() );
|
|
bRet = true;
|
|
}
|
|
|
|
if(rPt.Y()>maMaxWorkArea.Bottom())
|
|
{
|
|
rPt.setY( maMaxWorkArea.Bottom() );
|
|
bRet = true;
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
void SdrExchangeView::ImpGetPasteObjList(Point& /*rPos*/, SdrObjList*& rpLst)
|
|
{
|
|
if (rpLst==nullptr)
|
|
{
|
|
SdrPageView* pPV = GetSdrPageView();
|
|
|
|
if (pPV!=nullptr) {
|
|
rpLst=pPV->GetObjList();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SdrExchangeView::ImpGetPasteLayer(const SdrObjList* pObjList, SdrLayerID& rLayer) const
|
|
{
|
|
bool bRet=false;
|
|
rLayer=SdrLayerID(0);
|
|
if (pObjList!=nullptr) {
|
|
const SdrPage* pPg=pObjList->getSdrPageFromSdrObjList();
|
|
if (pPg!=nullptr) {
|
|
rLayer=pPg->GetLayerAdmin().GetLayerID(maActualLayer);
|
|
if (rLayer==SDRLAYER_NOTFOUND) rLayer=SdrLayerID(0);
|
|
SdrPageView* pPV = GetSdrPageView();
|
|
if (pPV!=nullptr) {
|
|
bRet=!pPV->GetLockedLayers().IsSet(rLayer) && pPV->GetVisibleLayers().IsSet(rLayer);
|
|
}
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
bool SdrExchangeView::Paste(const OUString& rStr, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions)
|
|
{
|
|
if (rStr.isEmpty())
|
|
return false;
|
|
|
|
Point aPos(rPos);
|
|
ImpGetPasteObjList(aPos,pLst);
|
|
ImpLimitToWorkArea( aPos );
|
|
if (pLst==nullptr) return false;
|
|
SdrLayerID nLayer;
|
|
if (!ImpGetPasteLayer(pLst,nLayer)) return false;
|
|
bool bUnmark = (nOptions & (SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit();
|
|
if (bUnmark) UnmarkAllObj();
|
|
tools::Rectangle aTextRect(0,0,500,500);
|
|
SdrPage* pPage=pLst->getSdrPageFromSdrObjList();
|
|
if (pPage!=nullptr) {
|
|
aTextRect.SetSize(pPage->GetSize());
|
|
}
|
|
rtl::Reference<SdrRectObj> pObj = new SdrRectObj(
|
|
getSdrModelFromSdrView(),
|
|
SdrObjKind::Text,
|
|
aTextRect);
|
|
|
|
pObj->SetLayer(nLayer);
|
|
pObj->NbcSetText(rStr); // SetText before SetAttr, else SetAttr doesn't work!
|
|
if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false);
|
|
|
|
pObj->SetMergedItemSet(maDefaultAttr);
|
|
|
|
SfxItemSet aTempAttr(GetModel().GetItemPool()); // no fill, no line
|
|
aTempAttr.Put(XLineStyleItem(drawing::LineStyle_NONE));
|
|
aTempAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
|
|
|
|
pObj->SetMergedItemSet(aTempAttr);
|
|
|
|
pObj->FitFrameToTextSize();
|
|
Size aSiz(pObj->GetLogicRect().GetSize());
|
|
MapUnit eMap = GetModel().GetScaleUnit();
|
|
ImpPasteObject(pObj.get(), *pLst, aPos, aSiz, MapMode(eMap), nOptions);
|
|
return true;
|
|
}
|
|
|
|
bool SdrExchangeView::Paste(SvStream& rInput, EETextFormat eFormat, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions)
|
|
{
|
|
Point aPos(rPos);
|
|
ImpGetPasteObjList(aPos,pLst);
|
|
ImpLimitToWorkArea( aPos );
|
|
if (pLst==nullptr) return false;
|
|
SdrLayerID nLayer;
|
|
if (!ImpGetPasteLayer(pLst,nLayer)) return false;
|
|
bool bUnmark=(nOptions&(SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit();
|
|
if (bUnmark) UnmarkAllObj();
|
|
tools::Rectangle aTextRect(0,0,500,500);
|
|
SdrPage* pPage=pLst->getSdrPageFromSdrObjList();
|
|
if (pPage!=nullptr) {
|
|
aTextRect.SetSize(pPage->GetSize());
|
|
}
|
|
rtl::Reference<SdrRectObj> pObj = new SdrRectObj(
|
|
getSdrModelFromSdrView(),
|
|
SdrObjKind::Text,
|
|
aTextRect);
|
|
|
|
pObj->SetLayer(nLayer);
|
|
if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false);
|
|
|
|
pObj->SetMergedItemSet(maDefaultAttr);
|
|
|
|
SfxItemSet aTempAttr(GetModel().GetItemPool()); // no fill, no line
|
|
aTempAttr.Put(XLineStyleItem(drawing::LineStyle_NONE));
|
|
aTempAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
|
|
|
|
pObj->SetMergedItemSet(aTempAttr);
|
|
|
|
pObj->NbcSetText(rInput,OUString(),eFormat);
|
|
pObj->FitFrameToTextSize();
|
|
Size aSiz(pObj->GetLogicRect().GetSize());
|
|
MapUnit eMap = GetModel().GetScaleUnit();
|
|
ImpPasteObject(pObj.get(), *pLst, aPos, aSiz, MapMode(eMap), nOptions);
|
|
|
|
// b4967543
|
|
if(pObj->GetOutlinerParaObject())
|
|
{
|
|
SdrOutliner& rOutliner = pObj->getSdrModelFromSdrObject().GetHitTestOutliner();
|
|
rOutliner.SetText(*pObj->GetOutlinerParaObject());
|
|
|
|
if(1 == rOutliner.GetParagraphCount())
|
|
{
|
|
SfxStyleSheet* pCandidate = rOutliner.GetStyleSheet(0);
|
|
|
|
if(pCandidate)
|
|
{
|
|
if(pObj->getSdrModelFromSdrObject().GetStyleSheetPool() == pCandidate->GetPool())
|
|
{
|
|
pObj->NbcSetStyleSheet(pCandidate, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SdrExchangeView::Paste(
|
|
const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions)
|
|
{
|
|
const SdrModel* pSrcMod=&rMod;
|
|
if (pSrcMod == &GetModel())
|
|
return false; // this can't work, right?
|
|
|
|
const bool bUndo = IsUndoEnabled();
|
|
|
|
if( bUndo )
|
|
BegUndo(SvxResId(STR_ExchangePaste));
|
|
|
|
if( mxSelectionController.is() && mxSelectionController->PasteObjModel( rMod ) )
|
|
{
|
|
if( bUndo )
|
|
EndUndo();
|
|
return true;
|
|
}
|
|
|
|
Point aPos(rPos);
|
|
ImpGetPasteObjList(aPos,pLst);
|
|
SdrPageView* pMarkPV=nullptr;
|
|
SdrPageView* pPV = GetSdrPageView();
|
|
|
|
if(pPV && pPV->GetObjList() == pLst )
|
|
pMarkPV=pPV;
|
|
|
|
ImpLimitToWorkArea( aPos );
|
|
if (pLst==nullptr)
|
|
return false;
|
|
|
|
bool bUnmark=(nOptions&(SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit();
|
|
if (bUnmark)
|
|
UnmarkAllObj();
|
|
|
|
// Rescale, if the Model uses a different MapUnit.
|
|
// Calculate the necessary factors first.
|
|
MapUnit eSrcUnit = pSrcMod->GetScaleUnit();
|
|
MapUnit eDstUnit = GetModel().GetScaleUnit();
|
|
bool bResize=eSrcUnit!=eDstUnit;
|
|
Fraction aXResize,aYResize;
|
|
Point aPt0;
|
|
if (bResize)
|
|
{
|
|
FrPair aResize(GetMapFactor(eSrcUnit,eDstUnit));
|
|
aXResize=aResize.X();
|
|
aYResize=aResize.Y();
|
|
}
|
|
SdrObjList* pDstLst=pLst;
|
|
sal_uInt16 nPg,nPgCount=pSrcMod->GetPageCount();
|
|
for (nPg=0; nPg<nPgCount; nPg++)
|
|
{
|
|
const SdrPage* pSrcPg=pSrcMod->GetPage(nPg);
|
|
|
|
// Use SnapRect, not BoundRect here
|
|
tools::Rectangle aR=pSrcPg->GetAllObjSnapRect();
|
|
|
|
if (bResize)
|
|
ResizeRect(aR,aPt0,aXResize,aYResize);
|
|
Point aDist(aPos-aR.Center());
|
|
Size aSiz(aDist.X(),aDist.Y());
|
|
size_t nCloneErrCnt = 0;
|
|
const size_t nObjCount = pSrcPg->GetObjCount();
|
|
bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE;
|
|
|
|
// #i13033#
|
|
// New mechanism to re-create the connections of cloned connectors
|
|
CloneList aCloneList;
|
|
std::unordered_set<rtl::OUString> aNameSet;
|
|
for (size_t nOb=0; nOb<nObjCount; ++nOb)
|
|
{
|
|
const SdrObject* pSrcOb=pSrcPg->GetObj(nOb);
|
|
|
|
rtl::Reference<SdrObject> pNewObj(pSrcOb->CloneSdrObject(GetModel()));
|
|
|
|
if (pNewObj!=nullptr)
|
|
{
|
|
if(bResize)
|
|
{
|
|
pNewObj->getSdrModelFromSdrObject().SetPasteResize(true);
|
|
pNewObj->NbcResize(aPt0,aXResize,aYResize);
|
|
pNewObj->getSdrModelFromSdrObject().SetPasteResize(false);
|
|
}
|
|
|
|
// #i39861#
|
|
pNewObj->NbcMove(aSiz);
|
|
|
|
const SdrPage* pPg = pDstLst->getSdrPageFromSdrObjList();
|
|
|
|
if(pPg)
|
|
{
|
|
// #i72535#
|
|
const SdrLayerAdmin& rAd = pPg->GetLayerAdmin();
|
|
SdrLayerID nLayer(0);
|
|
|
|
if(dynamic_cast<const FmFormObj*>( pNewObj.get()) != nullptr)
|
|
{
|
|
// for FormControls, force to form layer
|
|
nLayer = rAd.GetLayerID(rAd.GetControlLayerName());
|
|
}
|
|
else
|
|
{
|
|
nLayer = rAd.GetLayerID(maActualLayer);
|
|
}
|
|
|
|
if(SDRLAYER_NOTFOUND == nLayer)
|
|
{
|
|
nLayer = SdrLayerID(0);
|
|
}
|
|
|
|
pNewObj->SetLayer(nLayer);
|
|
}
|
|
|
|
pDstLst->InsertObjectThenMakeNameUnique(pNewObj.get(), aNameSet);
|
|
|
|
if( bUndo )
|
|
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pNewObj));
|
|
|
|
if (bMark) {
|
|
// Don't already set Markhandles!
|
|
// That is instead being done by ModelHasChanged in MarkView.
|
|
MarkObj(pNewObj.get(),pMarkPV,false,true);
|
|
}
|
|
|
|
// #i13033#
|
|
aCloneList.AddPair(pSrcOb, pNewObj.get());
|
|
}
|
|
else
|
|
{
|
|
nCloneErrCnt++;
|
|
}
|
|
}
|
|
|
|
// #i13033#
|
|
// New mechanism to re-create the connections of cloned connectors
|
|
aCloneList.CopyConnections();
|
|
|
|
if(0 != nCloneErrCnt)
|
|
{
|
|
#ifdef DBG_UTIL
|
|
OStringBuffer aStr("SdrExchangeView::Paste(): Error when cloning ");
|
|
|
|
if(nCloneErrCnt == 1)
|
|
{
|
|
aStr.append("a drawing object.");
|
|
}
|
|
else
|
|
{
|
|
aStr.append(OString::number(static_cast<sal_Int32>(nCloneErrCnt))
|
|
+ " drawing objects.");
|
|
}
|
|
|
|
aStr.append(" Not copying object connectors.");
|
|
|
|
OSL_FAIL(aStr.getStr());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if( bUndo )
|
|
EndUndo();
|
|
|
|
return true;
|
|
}
|
|
|
|
void SdrExchangeView::ImpPasteObject(SdrObject* pObj, SdrObjList& rLst, const Point& rCenter, const Size& rSiz, const MapMode& rMap, SdrInsertFlags nOptions)
|
|
{
|
|
BigInt nSizX(rSiz.Width());
|
|
BigInt nSizY(rSiz.Height());
|
|
MapUnit eSrcMU=rMap.GetMapUnit();
|
|
MapUnit eDstMU = GetModel().GetScaleUnit();
|
|
FrPair aMapFact(GetMapFactor(eSrcMU,eDstMU));
|
|
nSizX *= double(aMapFact.X() * rMap.GetScaleX());
|
|
nSizY *= double(aMapFact.Y() * rMap.GetScaleY());
|
|
tools::Long xs=nSizX;
|
|
tools::Long ys=nSizY;
|
|
// set the pos to 0, 0 for online case
|
|
bool isLOK = comphelper::LibreOfficeKit::isActive();
|
|
Point aPos(isLOK ? 0 : rCenter.X()-xs/2, isLOK ? 0 : rCenter.Y()-ys/2);
|
|
tools::Rectangle aR(aPos.X(),aPos.Y(),aPos.X()+xs,aPos.Y()+ys);
|
|
pObj->SetLogicRect(aR);
|
|
rLst.InsertObject(pObj, SAL_MAX_SIZE);
|
|
|
|
if( IsUndoEnabled() )
|
|
AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pObj));
|
|
|
|
SdrPageView* pMarkPV=nullptr;
|
|
SdrPageView* pPV = GetSdrPageView();
|
|
|
|
if(pPV && pPV->GetObjList()==&rLst)
|
|
pMarkPV=pPV;
|
|
|
|
bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE;
|
|
if (bMark)
|
|
{ // select object the first PageView we found
|
|
MarkObj(pObj,pMarkPV);
|
|
}
|
|
}
|
|
|
|
BitmapEx SdrExchangeView::GetMarkedObjBitmapEx(bool bNoVDevIfOneBmpMarked, const sal_uInt32 nMaximumQuadraticPixels, const std::optional<Size>& rTargetDPI) const
|
|
{
|
|
BitmapEx aBmp;
|
|
|
|
const SdrMarkList& rMarkList = GetMarkedObjectList();
|
|
if(1 == rMarkList.GetMarkCount())
|
|
{
|
|
if (auto pGrafObj
|
|
= dynamic_cast<const SdrGrafObj*>(rMarkList.GetMark(0)->GetMarkedSdrObj()))
|
|
{
|
|
if(bNoVDevIfOneBmpMarked)
|
|
{
|
|
if (pGrafObj->GetGraphicType() == GraphicType::Bitmap)
|
|
aBmp = pGrafObj->GetTransformedGraphic().GetBitmapEx();
|
|
}
|
|
else
|
|
{
|
|
if (pGrafObj->isEmbeddedVectorGraphicData())
|
|
aBmp = pGrafObj->GetGraphic().getVectorGraphicData()->getReplacement();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (aBmp.IsEmpty() && rMarkList.GetMarkCount() != 0)
|
|
{
|
|
// choose conversion directly using primitives to bitmap to avoid
|
|
// rendering errors with tiled bitmap fills (these will be tiled in a
|
|
// in-between metafile, but tend to show 'gaps' since the target is *no*
|
|
// bitmap rendering)
|
|
::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
|
|
const size_t nCount(aSdrObjects.size());
|
|
|
|
// collect sub-primitives as group objects, thus no expensive append
|
|
// to existing sequence is needed
|
|
drawinglayer::primitive2d::Primitive2DContainer xPrimitives(nCount);
|
|
|
|
for (size_t a(0); a < nCount; a++)
|
|
{
|
|
const SdrObject* pCandidate = aSdrObjects[a];
|
|
|
|
if (auto pSdrGrafObj = dynamic_cast<const SdrGrafObj*>(pCandidate))
|
|
{
|
|
// #122753# To ensure existence of graphic content, force swap in
|
|
pSdrGrafObj->ForceSwapIn();
|
|
}
|
|
|
|
drawinglayer::primitive2d::Primitive2DContainer xRetval;
|
|
pCandidate->GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
|
|
xPrimitives[a] = new drawinglayer::primitive2d::GroupPrimitive2D(
|
|
std::move(xRetval));
|
|
}
|
|
|
|
// get logic range
|
|
const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
|
|
const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D));
|
|
|
|
if(!aRange.isEmpty())
|
|
{
|
|
o3tl::Length eRangeUnit = o3tl::Length::mm100;
|
|
|
|
if (GetModel().IsWriter())
|
|
{
|
|
eRangeUnit = o3tl::Length::twip;
|
|
}
|
|
|
|
// if we have geometry and it has a range, convert to BitmapEx using
|
|
// common tooling
|
|
aBmp = drawinglayer::convertPrimitive2DContainerToBitmapEx(
|
|
std::move(xPrimitives),
|
|
aRange,
|
|
nMaximumQuadraticPixels,
|
|
eRangeUnit,
|
|
rTargetDPI);
|
|
}
|
|
}
|
|
|
|
return aBmp;
|
|
}
|
|
|
|
|
|
GDIMetaFile SdrExchangeView::GetMarkedObjMetaFile(bool bNoVDevIfOneMtfMarked) const
|
|
{
|
|
GDIMetaFile aMtf;
|
|
|
|
const SdrMarkList& rMarkList = GetMarkedObjectList();
|
|
if( rMarkList.GetMarkCount() != 0 )
|
|
{
|
|
tools::Rectangle aBound( GetMarkedObjBoundRect() );
|
|
Size aBoundSize( aBound.GetWidth(), aBound.GetHeight() );
|
|
MapMode aMap(GetModel().GetScaleUnit());
|
|
|
|
if (bNoVDevIfOneMtfMarked && rMarkList.GetMarkCount() == 1)
|
|
{
|
|
if (auto pGrafObj
|
|
= dynamic_cast<const SdrGrafObj*>(rMarkList.GetMark(0)->GetMarkedSdrObj()))
|
|
{
|
|
Graphic aGraphic( pGrafObj->GetTransformedGraphic() );
|
|
|
|
// #119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
|
|
aMtf = aGraphic.GetGDIMetaFile();
|
|
}
|
|
}
|
|
|
|
if( !aMtf.GetActionSize() )
|
|
{
|
|
ScopedVclPtrInstance< VirtualDevice > pOut;
|
|
const Size aDummySize(2, 2);
|
|
|
|
pOut->SetOutputSizePixel(aDummySize);
|
|
pOut->EnableOutput(false);
|
|
pOut->SetMapMode(aMap);
|
|
aMtf.Clear();
|
|
aMtf.Record(pOut);
|
|
|
|
DrawMarkedObj(*pOut);
|
|
|
|
aMtf.Stop();
|
|
aMtf.WindStart();
|
|
|
|
// moving the result is more reliable then setting a relative MapMode at the VDev (used
|
|
// before), also see #i99268# in GetObjGraphic() below. Some draw actions at
|
|
// the OutDev are simply not handled correctly when a MapMode is set at the
|
|
// target device, e.g. MetaFloatTransparentAction. Even the Move for this action
|
|
// was missing the manipulation of the embedded Metafile
|
|
aMtf.Move(-aBound.Left(), -aBound.Top());
|
|
|
|
aMtf.SetPrefMapMode( aMap );
|
|
|
|
// removed PrefSize extension. It is principally wrong to set a reduced size at
|
|
// the created MetaFile. The mentioned errors occur at output time since the integer
|
|
// MapModes from VCL lead to errors. It is now corrected in the VCLRenderer for
|
|
// primitives (and may later be done in breaking up a MetaFile to primitives)
|
|
aMtf.SetPrefSize(aBoundSize);
|
|
}
|
|
}
|
|
|
|
return aMtf;
|
|
}
|
|
|
|
|
|
Graphic SdrExchangeView::GetAllMarkedGraphic() const
|
|
{
|
|
Graphic aRet;
|
|
|
|
const SdrMarkList& rMarkList = GetMarkedObjectList();
|
|
if( rMarkList.GetMarkCount() != 0 )
|
|
{
|
|
if( ( 1 == rMarkList.GetMarkCount() ) && rMarkList.GetMark( 0 ) )
|
|
aRet = SdrExchangeView::GetObjGraphic(*rMarkList.GetMark(0)->GetMarkedSdrObj());
|
|
else
|
|
aRet = GetMarkedObjMetaFile();
|
|
}
|
|
|
|
return aRet;
|
|
}
|
|
|
|
|
|
// tdf#155479 bSVG: need to know it's SVG export, default is false
|
|
Graphic SdrExchangeView::GetObjGraphic(const SdrObject& rSdrObject, bool bSVG)
|
|
{
|
|
Graphic aRet;
|
|
|
|
if (!rSdrObject.HasText())
|
|
{
|
|
// try to get a graphic from the object first
|
|
const SdrGrafObj* pSdrGrafObj(dynamic_cast<const SdrGrafObj*>(&rSdrObject));
|
|
const SdrOle2Obj* pSdrOle2Obj(dynamic_cast<const SdrOle2Obj*>(&rSdrObject));
|
|
|
|
if (pSdrGrafObj)
|
|
{
|
|
if (pSdrGrafObj->isEmbeddedVectorGraphicData())
|
|
{
|
|
// get Metafile for Svg content
|
|
aRet = pSdrGrafObj->getMetafileFromEmbeddedVectorGraphicData();
|
|
}
|
|
else
|
|
{
|
|
// Make behaviour coherent with metafile
|
|
// recording below (which of course also takes
|
|
// view-transformed objects)
|
|
aRet = pSdrGrafObj->GetTransformedGraphic();
|
|
}
|
|
}
|
|
else if (pSdrOle2Obj)
|
|
{
|
|
if (const Graphic* pGraphic = pSdrOle2Obj->GetGraphic())
|
|
{
|
|
aRet = *pGraphic;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Support extracting a snapshot from video media, if possible.
|
|
const SdrMediaObj* pSdrMediaObj = dynamic_cast<const SdrMediaObj*>(&rSdrObject);
|
|
if (pSdrMediaObj)
|
|
{
|
|
const css::uno::Reference<css::graphic::XGraphic>& xGraphic
|
|
= pSdrMediaObj->getSnapshot();
|
|
if (xGraphic.is())
|
|
aRet = Graphic(xGraphic);
|
|
}
|
|
}
|
|
}
|
|
|
|
// if graphic could not be retrieved => go the hard way and create a MetaFile
|
|
if((GraphicType::NONE == aRet.GetType()) || (GraphicType::Default == aRet.GetType()))
|
|
{
|
|
ScopedVclPtrInstance< VirtualDevice > pOut;
|
|
GDIMetaFile aMtf;
|
|
const tools::Rectangle aBoundRect(rSdrObject.GetCurrentBoundRect());
|
|
const MapMode aMap(rSdrObject.getSdrModelFromSdrObject().GetScaleUnit());
|
|
|
|
pOut->EnableOutput(false);
|
|
pOut->SetMapMode(aMap);
|
|
aMtf.Record(pOut);
|
|
aMtf.setSVG(bSVG);
|
|
rSdrObject.SingleObjectPainter(*pOut);
|
|
aMtf.Stop();
|
|
aMtf.WindStart();
|
|
|
|
// #i99268# replace the original offset from using XOutDev's SetOffset
|
|
// NOT (as tried with #i92760#) with another MapMode which gets recorded
|
|
// by the Metafile itself (what always leads to problems), but by
|
|
// moving the result directly
|
|
aMtf.Move(-aBoundRect.Left(), -aBoundRect.Top());
|
|
aMtf.SetPrefMapMode(aMap);
|
|
aMtf.SetPrefSize(aBoundRect.GetSize());
|
|
|
|
if(aMtf.GetActionSize())
|
|
{
|
|
aRet = aMtf;
|
|
}
|
|
}
|
|
|
|
return aRet;
|
|
}
|
|
|
|
|
|
::std::vector< SdrObject* > SdrExchangeView::GetMarkedObjects() const
|
|
{
|
|
const SdrMarkList& rMarkList = GetMarkedObjectList();
|
|
rMarkList.ForceSort();
|
|
::std::vector< SdrObject* > aRetval;
|
|
|
|
::std::vector< ::std::vector< SdrMark* > > aObjVectors( 2 );
|
|
::std::vector< SdrMark* >& rObjVector1 = aObjVectors[ 0 ];
|
|
::std::vector< SdrMark* >& rObjVector2 = aObjVectors[ 1 ];
|
|
const SdrLayerAdmin& rLayerAdmin = GetModel().GetLayerAdmin();
|
|
const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID( rLayerAdmin.GetControlLayerName() );
|
|
|
|
for( size_t n = 0, nCount = rMarkList.GetMarkCount(); n < nCount; ++n )
|
|
{
|
|
SdrMark* pMark = rMarkList.GetMark( n );
|
|
|
|
// paint objects on control layer on top of all other objects
|
|
if( nControlLayerId == pMark->GetMarkedSdrObj()->GetLayer() )
|
|
rObjVector2.push_back( pMark );
|
|
else
|
|
rObjVector1.push_back( pMark );
|
|
}
|
|
|
|
for(const std::vector<SdrMark*> & rObjVector : aObjVectors)
|
|
{
|
|
for(SdrMark* pMark : rObjVector)
|
|
{
|
|
aRetval.push_back(pMark->GetMarkedSdrObj());
|
|
}
|
|
}
|
|
|
|
return aRetval;
|
|
}
|
|
|
|
|
|
void SdrExchangeView::DrawMarkedObj(OutputDevice& rOut) const
|
|
{
|
|
::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
|
|
|
|
if(!aSdrObjects.empty())
|
|
{
|
|
SdrPage* pPage = aSdrObjects[0]->getSdrPageFromSdrObject();
|
|
sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, std::move(aSdrObjects), pPage);
|
|
sdr::contact::DisplayInfo aDisplayInfo;
|
|
|
|
// do processing
|
|
aPainter.ProcessDisplay(aDisplayInfo);
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<SdrModel> SdrExchangeView::CreateMarkedObjModel() const
|
|
{
|
|
// Sorting the MarkList here might be problematic in the future, so
|
|
// use a copy.
|
|
const SdrMarkList& rMarkList = GetMarkedObjectList();
|
|
rMarkList.ForceSort();
|
|
std::unique_ptr<SdrModel> pNewModel(GetModel().AllocModel());
|
|
rtl::Reference<SdrPage> pNewPage = pNewModel->AllocPage(false);
|
|
pNewModel->InsertPage(pNewPage.get());
|
|
::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
|
|
|
|
// #i13033#
|
|
// New mechanism to re-create the connections of cloned connectors
|
|
CloneList aCloneList;
|
|
|
|
for(SdrObject* pObj : aSdrObjects)
|
|
{
|
|
assert(pObj);
|
|
|
|
rtl::Reference<SdrObject> pNewObj;
|
|
|
|
if(nullptr != dynamic_cast< const SdrPageObj* >(pObj))
|
|
{
|
|
// convert SdrPageObj's to a graphic representation, because
|
|
// virtual connection to referenced page gets lost in new model
|
|
pNewObj = new SdrGrafObj(
|
|
*pNewModel,
|
|
GetObjGraphic(*pObj),
|
|
pObj->GetLogicRect());
|
|
}
|
|
else if(nullptr != dynamic_cast< const sdr::table::SdrTableObj* >(pObj))
|
|
{
|
|
// check if we have a valid selection *different* from whole table
|
|
// being selected
|
|
if(mxSelectionController.is())
|
|
{
|
|
pNewObj = mxSelectionController->GetMarkedSdrObjClone(*pNewModel);
|
|
}
|
|
}
|
|
|
|
if(!pNewObj)
|
|
{
|
|
// not cloned yet
|
|
if(pObj->GetObjIdentifier() == SdrObjKind::OLE2 && nullptr == GetModel().GetPersist())
|
|
{
|
|
// tdf#125520 - former fix was wrong, the SdrModel
|
|
// has to have a GetPersist() already, see task.
|
|
// We can still warn here when this is not the case
|
|
SAL_WARN( "svx", "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" );
|
|
}
|
|
|
|
// use default way
|
|
pNewObj = pObj->CloneSdrObject(*pNewModel);
|
|
}
|
|
|
|
if(pNewObj)
|
|
{
|
|
pNewPage->InsertObject(pNewObj.get(), SAL_MAX_SIZE);
|
|
|
|
// #i13033#
|
|
aCloneList.AddPair(pObj, pNewObj.get());
|
|
}
|
|
}
|
|
|
|
// #i13033#
|
|
// New mechanism to re-create the connections of cloned connectors
|
|
aCloneList.CopyConnections();
|
|
|
|
return pNewModel;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|