/* -*- 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 .
*/
// #i33700# // Set shadow distance defaults as PoolDefaultItems. Details see bug.
rPool.SetUserDefaultItem(makeSdrShadowXDistItem(300));
rPool.SetUserDefaultItem(makeSdrShadowYDistItem(300));
// default for script spacing depends on locale, see SdDrawDocument ctor in sd
LanguageType eOfficeLanguage = Application::GetSettings().GetLanguageTag().getLanguageType(); if (MsLangId::isKorean(eOfficeLanguage) || eOfficeLanguage == LANGUAGE_JAPANESE)
{ // secondary is edit engine pool
rPool.GetSecondaryPool()->SetUserDefaultItem( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
}
SetStyleSheetPool(pDocument ? pDocument->GetStyleSheetPool() : new ScStyleSheetPool(rPool, pDocument));
SdrLayerAdmin& rAdmin = GetLayerAdmin();
rAdmin.NewLayer(u"vorne"_ustr, SC_LAYER_FRONT.get());
rAdmin.NewLayer(u"hinten"_ustr, SC_LAYER_BACK.get());
rAdmin.NewLayer(u"intern"_ustr, SC_LAYER_INTERN.get()); // tdf#140252 use same name as in ctor of SdrLayerAdmin
rAdmin.NewLayer(rAdmin.GetControlLayerName(), SC_LAYER_CONTROLS.get());
rAdmin.NewLayer(u"hidden"_ustr, SC_LAYER_HIDDEN.get());
// Set link for URL-Fields
ScModule* pScMod = ScModule::get();
Outliner& rOutliner = GetDrawOutliner();
rOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
rOutliner.SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
sal_uInt16 nCount = GetPageCount(); for (sal_uInt16 i=0; i<nCount && !bFound; i++) if (GetPage(i)->GetObjCount())
bFound = true;
return bFound;
}
SdrModel* ScDrawLayer::AllocModel() const
{ // Allocated model (for clipboard etc) must not have a pointer // to the original model's document, pass NULL as document: auto pNewModel = std::make_unique<ScDrawLayer>(nullptr, aName); auto pNewPool = static_cast<ScStyleSheetPool*>(pNewModel->GetStyleSheetPool());
pNewPool->CopyUsedGraphicStylesFrom(GetStyleSheetPool());
return pNewModel.release();
}
bool ScDrawLayer::ScAddPage( SCTAB nTab )
{ if (bDrawIsInUndo) returnfalse; // not inserted
void ScDrawLayer::ScRemovePage( SCTAB nTab )
{ if (bDrawIsInUndo) return;
Broadcast( ScTabDeletedHint( nTab ) ); if (bRecording)
{
SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
AddCalcUndo(std::make_unique<SdrUndoDelPage>(*pPage)); // Undo-Action becomes the page owner
RemovePage( static_cast<sal_uInt16>(nTab) ); // just deliver, not deleting
} else
DeletePage( static_cast<sal_uInt16>(nTab) ); // just get rid of it
if ( rSize != pPage->GetSize() )
{
pPage->SetSize( rSize );
Broadcast( ScTabSizeChangedHint( static_cast<SCTAB>(nPageNo) ) ); // SetWorkArea() on the views
}
// Do not call RecalcPos while loading, because row height is not finished, when SetPageSize // is called first time. Instead the objects are initialized from ScXMLImport::endDocument() and // RecalcPos is called from there. if (!pDoc || pDoc->IsImportingXML()) return;
// Implement Detective lines (adjust to new heights / widths) // even if size is still the same // (individual rows/columns can have been changed))
tools::Rectangle lcl_UpdateCalcPoly(basegfx::B2DPolygon &rCalcPoly, int nWhichPoint, const Point &rPos)
{
rCalcPoly.setB2DPoint(nWhichPoint, basegfx::B2DPoint(rPos.X(), rPos.Y()));
basegfx::B2DRange aRange(basegfx::utils::getRange(rCalcPoly)); return tools::Rectangle(static_cast<tools::Long>(aRange.getMinX()), static_cast<tools::Long>(aRange.getMinY()), static_cast<tools::Long>(aRange.getMaxX()), static_cast<tools::Long>(aRange.getMaxY()));
}
bool lcl_AreRectanglesApproxEqual(const tools::Rectangle& rRectA, const tools::Rectangle& rRectB)
{ // Twips <-> Hmm conversions introduce +-1 differences although there are no real changes in the object. // Therefore test with == is not appropriate in some cases. if (std::abs(rRectA.Left() - rRectB.Left()) > 1) returnfalse; if (std::abs(rRectA.Top() - rRectB.Top()) > 1) returnfalse; if (std::abs(rRectA.Right() - rRectB.Right()) > 1) returnfalse; if (std::abs(rRectA.Bottom() - rRectB.Bottom()) > 1) returnfalse; returntrue;
}
void lcl_SetLogicRectFromAnchor(SdrObject* pObj, const ScDrawObjData& rAnchor, const ScDocument* pDoc)
{ // This is only used during initialization. At that time, shape handling is always LTR. No need // to consider negative page. if (!pObj || !pDoc || !rAnchor.maEnd.IsValid() || !rAnchor.maStart.IsValid()) return;
// In case of a vertical mirrored custom shape, LibreOffice uses internally an additional 180deg // in aGeo.nRotationAngle and in turn has a different logic rectangle position. We remove flip, // set the logic rectangle, and apply flip again. You cannot simple use a 180deg-rotated // rectangle, because custom shape mirroring is internally applied after the other // transformations. constbool bNeedsMirrorYCorrection = lcl_NeedsMirrorYCorrection(pObj); // remember state if (bNeedsMirrorYCorrection)
{ const tools::Rectangle aRect(pObj->GetSnapRect()); const Point aLeft(aRect.Left(), (aRect.Top() + aRect.Bottom()) >> 1); const Point aRight(aLeft.X() + 1000, aLeft.Y());
pObj->NbcMirror(aLeft, aRight);
}
// Build full sized logic rectangle from start and end given in anchor. const tools::Rectangle aStartCellRect(
pDoc->GetMMRect(rAnchor.maStart.Col(), rAnchor.maStart.Row(), rAnchor.maStart.Col(),
rAnchor.maStart.Row(), rAnchor.maStart.Tab(), false/*bHiddenAsZero*/));
Point aStartPoint(aStartCellRect.Left(), aStartCellRect.Top());
aStartPoint.AdjustX(rAnchor.maStartOffset.getX());
aStartPoint.AdjustY(rAnchor.maStartOffset.getY());
Point aEndPoint(aEndCellRect.Left(), aEndCellRect.Top());
aEndPoint.AdjustX(rAnchor.maEndOffset.getX());
aEndPoint.AdjustY(rAnchor.maEndOffset.getY());
// Set this as new, full sized logical rectangle
tools::Rectangle aNewRectangle(aStartPoint, aEndPoint);
aNewRectangle.Normalize(); if (!lcl_AreRectanglesApproxEqual(pObj->GetLogicRect(), aNewRectangle))
pObj->NbcSetLogicRect(lcl_makeSafeRectangle(aNewRectangle));
// The shape has the correct logical rectangle now. Reapply the above removed mirroring. if (bNeedsMirrorYCorrection)
{ const tools::Rectangle aRect(pObj->GetSnapRect()); const Point aLeft(aRect.Left(), (aRect.Top() + aRect.Bottom()) >> 1); const Point aRight(aLeft.X() + 1000, aLeft.Y());
pObj->NbcMirror(aLeft, aRight);
}
}
// this sets the needed changed position (translation)
aRect.SetPos(aPos);
if (bCanResize)
{ // all this stuff is additional stuff to evtl. not only translate the // range (Rectangle), but also check for and evtl. do corrections for it's size const tools::Rectangle aLastCellRect(rData.getLastCellRect());
// If the row was hidden before, or we don't have a valid cell rect, calculate the // new rect based on the end point. // Also when the end point is set, we need to consider it. if (rData.mbWasInHiddenRow || aLastCellRect.IsEmpty() || nRow1 != nRow2 || nCol1 != nCol2)
{
Point aEnd(pDoc->GetColOffset(nCol2, nTab2, /*bHiddenAsZero*/true),
pDoc->GetRowOffset(nRow2, nTab2, /*bHiddenAsZero*/true));
aEnd.setX(convertTwipToMm100(aEnd.X()));
aEnd.setY(convertTwipToMm100(aEnd.Y()));
aEnd += lcl_calcAvailableDiff(*pDoc, nCol2, nRow2, nTab2, rData.maEndOffset);
aRect = tools::Rectangle(aPos, aEnd);
} elseif (!aLastCellRect.IsEmpty())
{ // We calculate based on the last cell rect to be able to scale the image // as much as the cell was scaled. // Still, we keep the image in its current cell (to keep start anchor == end anchor) const tools::Rectangle aCurrentCellRect(GetCellRect(*GetDocument(), rData.maStart, true));
tools::Long nCurrentWidth(aCurrentCellRect.GetWidth());
tools::Long nCurrentHeight(aCurrentCellRect.GetHeight()); const tools::Long nLastWidth(aLastCellRect.GetWidth()); const tools::Long nLastHeight(aLastCellRect.GetHeight());
// tdf#116931 Avoid and correct nifty numerical problems with the integer // based and converted values (GetCellRect uses multiplies with HMM_PER_TWIPS) if(nCurrentWidth + 1 == nLastWidth || nCurrentWidth == nLastWidth + 1)
{
nCurrentWidth = nLastWidth;
}
if(bIsGrowing) // cell is growing larger
{ // To actually grow the image, we need to take the max
fWidthFactor = std::max(fWidthFactor, fHeightFactor);
} elseif(bIsShrinking) // cell is growing smaller, take the min
{
fWidthFactor = std::min(fWidthFactor, fHeightFactor);
}
// We don't want the image to become larger than the current cell
fWidthFactor = fHeightFactor = std::min(fWidthFactor, fMaxFactor);
}
if(bIsSizeChanged)
{ // tdf#116931 re-organized scaling (if needed) // Check if we need to scale at all. Always scale on growing. bool bNeedToScale(bIsGrowing);
if(!bNeedToScale && bIsShrinking)
{ // Check if original still fits into space. Do *not* forget to // compare with evtl. numerically corrected aCurrentCellRect constbool bFitsInX(aRect.Right() <= aCurrentCellRect.Left() + nCurrentWidth); constbool bFitsInY(aRect.Bottom() <= aCurrentCellRect.Top() + nCurrentHeight);
// If the image still fits in the smaller cell, don't resize it at all
bNeedToScale = (!bFitsInX || !bFitsInY);
}
if(bNeedToScale)
{ // tdf#116931 use transformations now. Translation is already applied // (see aRect.SetPos above), so only scale needs to be applied - relative // to *new* CellRect (which is aCurrentCellRect). // Prepare scale relative to top-left of aCurrentCellRect
basegfx::B2DHomMatrix aChange;
void ScDrawLayer::InitializeCellAnchoredObj(SdrObject* pObj, ScDrawObjData& rData)
{ // This is called from ScXMLImport::endDocument() if (!pDoc || !pObj) return; if (!rData.getShapeRect().IsEmpty()) return; // already initialized, should not happen if (rData.meType == ScDrawObjData::CellNote || rData.meType == ScDrawObjData::ValidationCircle
|| rData.meType == ScDrawObjData::DetectiveArrow) return; // handled in RecalcPos
// Prevent multiple broadcasts during the series of changes. bool bWasLocked = pObj->getSdrModelFromSdrObject().isLocked();
pObj->getSdrModelFromSdrObject().setLock(true);
// rNoRotatedAnchor refers in its start and end addresses and its start and end offsets to // the logic rectangle of the object. The values are so, as if no hidden columns and rows // exists and if it is a LTR sheet. These values are directly used for XML in ODF file.
ScDrawObjData& rNoRotatedAnchor = *GetNonRotatedObjData(pObj, true/*bCreate*/);
// From XML import, rData contains temporarily the anchor information as they are given in // XML. Copy it to rNoRotatedAnchor, where it belongs. rData will later contain the anchor // of the transformed object as visible on screen.
rNoRotatedAnchor.maStart = rData.maStart;
rNoRotatedAnchor.maEnd = rData.maEnd;
rNoRotatedAnchor.maStartOffset = rData.maStartOffset;
rNoRotatedAnchor.maEndOffset = rData.maEndOffset;
SCCOL nCol1 = rNoRotatedAnchor.maStart.Col();
SCROW nRow1 = rNoRotatedAnchor.maStart.Row();
SCTAB nTab1 = rNoRotatedAnchor.maStart.Tab(); // Used as parameter several times
// Object has coordinates relative to left/top of containing cell in XML. Change object to // absolute coordinates as internally used. const tools::Rectangle aRect(
pDoc->GetMMRect(nCol1, nRow1, nCol1, nRow1, nTab1, false/*bHiddenAsZero*/)); const Size aShift(aRect.Left(), aRect.Top());
pObj->NbcMove(aShift);
const ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObj); if (aAnchorType == SCA_CELL_RESIZE)
{ if (pObj->GetObjIdentifier() == SdrObjKind::Line)
{ // Horizontal lines might have wrong start and end anchor because of erroneously applied // 180deg rotation (tdf#137446). Other lines have wrong end anchor. Coordinates in // object are correct. Use them for recreating the anchor. const basegfx::B2DPolygon aPoly( static_cast<SdrPathObj*>(pObj)->GetPathPoly().getB2DPolygon(0)); const basegfx::B2DPoint aB2DPoint0(aPoly.getB2DPoint(0)); const basegfx::B2DPoint aB2DPoint1(aPoly.getB2DPoint(1)); const Point aPointLT(basegfx::fround<tools::Long>(std::min(aB2DPoint0.getX(), aB2DPoint1.getX())),
basegfx::fround<tools::Long>(std::min(aB2DPoint0.getY(), aB2DPoint1.getY()))); const Point aPointRB(basegfx::fround<tools::Long>(std::max(aB2DPoint0.getX(), aB2DPoint1.getX())),
basegfx::fround<tools::Long>(std::max(aB2DPoint0.getY(), aB2DPoint1.getY()))); const tools::Rectangle aObjRect(aPointLT, aPointRB);
GetCellAnchorFromPosition(aObjRect, rNoRotatedAnchor, *pDoc, nTab1, false/*bHiddenAsZero*/);
} elseif (pObj->GetObjIdentifier() == SdrObjKind::Measure)
{ // Measure lines might have got wrong start and end anchor from XML import. Recreate // anchor from start and end point.
SdrMeasureObj* pMeasureObj = static_cast<SdrMeasureObj*>(pObj); // tdf#137576. The logic rectangle has likely no current values here, but only the // 1cm x 1cm default size. The call of TakeUnrotatedSnapRect is currently (LO 7.2) // the only way to force a recalc of the logic rectangle.
tools::Rectangle aObjRect;
pMeasureObj->TakeUnrotatedSnapRect(aObjRect);
GetCellAnchorFromPosition(aObjRect, rNoRotatedAnchor, *pDoc, rData.maStart.Tab(), false/*bHiddenAsZero*/);
} elseif (pObj->IsResizeProtect())
{ // tdf#154005: This is a workaround for documents created with LO 6 and older.
rNoRotatedAnchor.mbResizeWithCell = false;
rData.mbResizeWithCell = false;
UpdateCellAnchorFromPositionEnd(*pObj, rNoRotatedAnchor, *pDoc, nTab1, true/*bUseLogicRect*/);
} elseif (pObj->GetObjIdentifier() == SdrObjKind::Group)
{ // nothing to do.
} else
{ // In case there are hidden rows or cols, versions 7.0 and earlier have written width and // height in file so that hidden row or col are count as zero. XML import bases the // logical rectangle of the object on it. Shapes have at least wrong size, when row or col // are shown. We try to regenerate the logic rectangle as far as possible from the anchor. // ODF specifies anyway, that the size has to be ignored, if end cell attributes exist.
lcl_SetLogicRectFromAnchor(pObj, rNoRotatedAnchor, pDoc);
}
} else// aAnchorType == SCA_CELL
{ // XML has no end cell address in this case. We generate it from position.
UpdateCellAnchorFromPositionEnd(*pObj, rNoRotatedAnchor, *pDoc, nTab1, true/*bUseLogicRect*/);
}
// Make sure maShapeRect of rNoRotatedAnchor is not empty. Method ScDrawView::Notify() // needs it to detect a change in object geometry. For example a 180deg rotation effects only // logic rect.
rNoRotatedAnchor.setShapeRect(GetDocument(), pObj->GetLogicRect(), true);
// Start and end addresses and offsets in rData refer to the actual snap rectangle of the // shape. We initialize them here based on the "full" sized object. Adaptation to reduced size // (by hidden row/col) is done later in RecalcPos.
GetCellAnchorFromPosition(pObj->GetSnapRect(), rData, *pDoc, nTab1, false/*bHiddenAsZero*/);
// As of ODF 1.3 strict there is no attribute to store whether an object is hidden. So a "visible" // object might actually be hidden by being in hidden row or column. We detect it here. // Note, that visibility by hidden row or column refers to the snap rectangle. if (pObj->IsVisible()
&& (pDoc->RowHidden(rData.maStart.Row(), rData.maStart.Tab())
|| pDoc->ColHidden(rData.maStart.Col(), rData.maStart.Tab())))
pObj->SetVisible(false);
// Set visibility. ToDo: Really used?
rNoRotatedAnchor.setShapeRect(GetDocument(), pObj->GetLogicRect(), pObj->IsVisible());
// And set maShapeRect in rData. It stores not only the current rectangles, but currently, // existence of maShapeRect is the flag for initialization is done.
rData.setShapeRect(GetDocument(), pObj->GetSnapRect(), pObj->IsVisible());
if (rData.meType == ScDrawObjData::CellNote)
{
OSL_ENSURE( rData.maStart.IsValid(), "ScDrawLayer::RecalcPos - invalid position for cell note" ); /* #i109372# On insert/remove rows/columns/cells: Updating the caption position must not be done, if the cell containing the note has not been moved yet in the document. The calling code now passes an
additional boolean stating if the cells are already moved. */ /* tdf #152081 Do not change hidden objects. That would produce zero height
or width and loss of caption.*/ if (bUpdateNoteCaptionPos && pObj->IsVisible())
{ /* When inside an undo action, there may be pending note captions where cell note is already deleted (thus document cannot find the note object anymore). The caption will be deleted later
with drawing undo. */ if( ScPostIt* pNote = pDoc->GetNote( rData.maStart ) )
pNote->UpdateCaptionPos( rData.maStart );
} return;
}
if (rData.meType == ScDrawObjData::ValidationCircle)
{ // Validation circle for detective.
rData.setShapeRect(GetDocument(), pObj->GetLogicRect());
// rData.maStart should contain the address of the be validated cell.
tools::Rectangle aRect = GetCellRect(*GetDocument(), rData.maStart, true);
aRect.AdjustLeft( -250 );
aRect.AdjustRight(250 );
aRect.AdjustTop( -70 );
aRect.AdjustBottom(70 ); if ( bNegativePage )
MirrorRectRTL( aRect );
if ( pObj->GetLogicRect() != aRect )
{ if (bRecording)
AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
rData.setShapeRect(GetDocument(), lcl_makeSafeRectangle(aRect)); // maStart has the meaning of "to be validated cell" in a validation circle. For usual // drawing objects it has the meaning "left/top of logic/snap rect". Because the rectangle // is expanded above, SetLogicRect() will set maStart to one cell left and one cell above // of the to be validated cell. We need to backup the old value and restore it.
ScAddress aBackup(rData.maStart);
pObj->SetLogicRect(rData.getShapeRect());
rData.maStart = aBackup;
}
} elseif (rData.meType == ScDrawObjData::DetectiveArrow)
{
rData.setShapeRect(GetDocument(), pObj->GetLogicRect());
basegfx::B2DPolygon aCalcPoly;
Point aOrigStartPos(pObj->GetPoint(0));
Point aOrigEndPos(pObj->GetPoint(1));
aCalcPoly.append(basegfx::B2DPoint(aOrigStartPos.X(), aOrigStartPos.Y()));
aCalcPoly.append(basegfx::B2DPoint(aOrigEndPos.X(), aOrigEndPos.Y())); //TODO: do not create multiple Undos for one object (last one can be omitted then)
SCCOL nLastCol;
SCROW nLastRow; if( bValid1 )
{
Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) ); if (!pDoc->ColHidden(nCol1, nTab1, nullptr, &nLastCol))
aPos.AdjustX(pDoc->GetColWidth( nCol1, nTab1 ) / 4 ); if (!pDoc->RowHidden(nRow1, nTab1, nullptr, &nLastRow))
aPos.AdjustY(pDoc->GetRowHeight( nRow1, nTab1 ) / 2 );
aPos.setX(convertTwipToMm100(aPos.X()));
aPos.setY(convertTwipToMm100(aPos.Y()));
Point aStartPos = aPos; if ( bNegativePage )
aStartPos.setX( -aStartPos.X() ); // don't modify aPos - used below if ( pObj->GetPoint( 0 ) != aStartPos )
{ if (bRecording)
AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
if( !bValid1 )
{
Point aStartPos( aPos.X() - DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET ); if (aStartPos.X() < 0)
aStartPos.AdjustX(2 * DET_ARROW_OFFSET); if (aStartPos.Y() < 0)
aStartPos.AdjustY(2 * DET_ARROW_OFFSET); if ( bNegativePage )
aStartPos.setX( -aStartPos.X() ); if ( pObj->GetPoint( 0 ) != aStartPos )
{ if (bRecording)
AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
rData.setShapeRect(GetDocument(), lcl_UpdateCalcPoly(aCalcPoly, 0, aStartPos));
pObj->SetPoint( aStartPos, 0 );
}
}
}
} // end ScDrawObjData::DetectiveArrow else// start ScDrawObjData::DrawingObject
{ // Do not change hidden objects. That would produce zero height or width and loss of offsets. if (!pObj->IsVisible()) return;
// Prevent multiple broadcasts during the series of changes. bool bWasLocked = pObj->getSdrModelFromSdrObject().isLocked();
pObj->getSdrModelFromSdrObject().setLock(true);
// ToDo: Implement NbcSetSnapRect of SdrMeasureObj. Then this can be removed.
tools::Long nOldWidth = aOld.GetWidth();
tools::Long nOldHeight = aOld.GetHeight(); if (pObj->IsPolyObj() && nOldWidth && nOldHeight)
{ // Polyline objects need special treatment.
Size aSizeMove(aNew.Left()-aOld.Left(), aNew.Top()-aOld.Top());
pObj->NbcMove(aSizeMove);
rData.setShapeRect(GetDocument(), lcl_makeSafeRectangle(rData.getShapeRect()), pObj->IsVisible()); if (pObj->GetObjIdentifier() == SdrObjKind::CustomShape)
pObj->AdjustToMaxRect(rData.getShapeRect()); else
pObj->SetSnapRect(rData.getShapeRect());
// The shape rectangle in the 'unrotated' anchor needs to be updated to the changed // object geometry. It is used in adjustAnchoredPosition() in ScDrawView::Notify().
rNoRotatedAnchor.setShapeRect(pDoc, pObj->GetLogicRect(), pObj->IsVisible());
}
} else
{ const Point aPos(rData.getShapeRect().TopLeft()); if ( pObj->GetRelativePos() != aPos )
{ if (bRecording)
AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
pObj->SetRelativePos( aPos );
rNoRotatedAnchor.setShapeRect(pDoc, pObj->GetLogicRect(), pObj->IsVisible());
}
} /* * If we were not allowed resize the object, then the end cell anchor * is possibly incorrect now, and if the object has no end-cell (e.g. * missing in original .xml) we are also forced to generate one
*/ bool bEndAnchorIsBad = !bValid2 || pObj->IsResizeProtect(); if (bEndAnchorIsBad)
{ // update 'rotated' anchor
ScDrawLayer::UpdateCellAnchorFromPositionEnd(*pObj, rData, *pDoc, nTab1, false); // update 'unrotated' anchor
ScDrawLayer::UpdateCellAnchorFromPositionEnd(*pObj, rNoRotatedAnchor, *pDoc, nTab1 );
}
// End prevent multiple broadcasts during the series of changes.
pObj->getSdrModelFromSdrObject().setLock(bWasLocked); if (!bWasLocked)
pObj->BroadcastObjectChange();
} // end ScDrawObjData::DrawingObject
}
if ( bNegativePage )
{
nStartX = -nStartX; // positions are negative, swap start/end so the same comparisons work
nEndX = -nEndX;
::std::swap( nStartX, nEndX );
}
const SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
OSL_ENSURE(pPage,"Page not found"); if (pPage)
{
SdrObjListIter aIter( pPage, SdrIterMode::Flat ); while (SdrObject* pObject = aIter.Next())
{ //TODO: test Flags (hidden?)
tools::Rectangle aObjRect = pObject->GetCurrentBoundRect(); bool bFit = true; if ( !bSetHor && ( aObjRect.Right() < nStartX || aObjRect.Left() > nEndX ) )
bFit = false; if ( !bSetVer && ( aObjRect.Bottom() < nStartY || aObjRect.Top() > nEndY ) )
bFit = false; // #i104716# don't include hidden note objects if ( bFit && pObject->GetLayer() != SC_LAYER_HIDDEN )
{ if (bSetHor)
{ if (aObjRect.Left() < nStartX) nStartX = aObjRect.Left(); if (aObjRect.Right() > nEndX) nEndX = aObjRect.Right();
} if (bSetVer)
{ if (aObjRect.Top() < nStartY) nStartY = aObjRect.Top(); if (aObjRect.Bottom() > nEndY) nEndY = aObjRect.Bottom();
}
bAny = true;
}
}
}
if ( bNegativePage )
{
nStartX = -nStartX; // reverse transformation, so the same cell address calculation works
nEndX = -nEndX;
::std::swap( nStartX, nEndX );
}
if (bAny)
{
OSL_ENSURE( nStartX<=nEndX && nStartY<=nEndY, "Start/End wrong in ScDrawLayer::GetPrintArea" );
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.