diff options
Diffstat (limited to 'svx/source')
-rw-r--r-- | svx/source/dialog/framelink.cxx | 12 | ||||
-rw-r--r-- | svx/source/dialog/framelinkarray.cxx | 472 | ||||
-rw-r--r-- | svx/source/dialog/frmsel.cxx | 4 | ||||
-rw-r--r-- | svx/source/table/viewcontactoftableobj.cxx | 197 |
4 files changed, 341 insertions, 344 deletions
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx index e86e6f1b3e34..8c087157d287 100644 --- a/svx/source/dialog/framelink.cxx +++ b/svx/source/dialog/framelink.cxx @@ -51,14 +51,12 @@ void Style::implEnsureImplStyle() } Style::Style() : - maImplStyle(), - mpUsingCell(nullptr) + maImplStyle() { } Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) : - maImplStyle(new implStyle()), - mpUsingCell(nullptr) + maImplStyle(new implStyle()) { maImplStyle->mnType = nType; maImplStyle->mfPatternScale = fScale; @@ -66,8 +64,7 @@ Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double } Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) : - maImplStyle(new implStyle()), - mpUsingCell(nullptr) + maImplStyle(new implStyle()) { maImplStyle->mnType = nType; maImplStyle->mfPatternScale = fScale; @@ -75,8 +72,7 @@ Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rCo } Style::Style( const editeng::SvxBorderLine* pBorder, double fScale ) : - maImplStyle(), - mpUsingCell(nullptr) + maImplStyle() { if(nullptr != pBorder) { diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index c9273c41344f..7cd4b26027dc 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -21,6 +21,7 @@ #include <math.h> #include <vector> +#include <set> #include <algorithm> #include <vcl/outdev.hxx> #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx> @@ -45,10 +46,8 @@ public: long mnAddTop; long mnAddBottom; - SvxRotateMode meRotMode; - double mfOrientation; - basegfx::B2DHomMatrix maCoordinateSystem; - size_t maCellIndex; + SvxRotateMode meRotMode; + double mfOrientation; bool mbMergeOrig; bool mbOverlapX; @@ -57,12 +56,12 @@ public: public: explicit Cell(); - void SetStyleLeft(const Style& rStyle) { maLeft = rStyle; maLeft.SetUsingCell(this); } - void SetStyleRight(const Style& rStyle) { maRight = rStyle; maRight.SetUsingCell(this); } - void SetStyleTop(const Style& rStyle) { maTop = rStyle; maTop.SetUsingCell(this); } - void SetStyleBottom(const Style& rStyle) { maBottom = rStyle; maBottom.SetUsingCell(this); } - void SetStyleTLBR(const Style& rStyle) { maTLBR = rStyle; maTLBR.SetUsingCell(this); } - void SetStyleBLTR(const Style& rStyle) { maBLTR = rStyle; maBLTR.SetUsingCell(this); } + void SetStyleLeft(const Style& rStyle) { maLeft = rStyle; } + void SetStyleRight(const Style& rStyle) { maRight = rStyle; } + void SetStyleTop(const Style& rStyle) { maTop = rStyle; } + void SetStyleBottom(const Style& rStyle) { maBottom = rStyle; } + void SetStyleTLBR(const Style& rStyle) { maTLBR = rStyle; } + void SetStyleBLTR(const Style& rStyle) { maBLTR = rStyle; } const Style& GetStyleLeft() const { return maLeft; } const Style& GetStyleRight() const { return maRight; } @@ -76,74 +75,54 @@ public: void MirrorSelfX(); - basegfx::B2DHomMatrix CreateCoordinateSystem(const Array& rArray) const; - size_t GetCellIndex(const Array& rArray) const; + basegfx::B2DHomMatrix CreateCoordinateSystem(const Array& rArray, size_t nCol, size_t nRow, bool bExpandMerged) const; }; typedef std::vector< long > LongVec; typedef std::vector< Cell > CellVec; -size_t Cell::GetCellIndex(const Array& rArray) const +basegfx::B2DHomMatrix Cell::CreateCoordinateSystem(const Array& rArray, size_t nCol, size_t nRow, bool bExpandMerged) const { - if(static_cast<size_t>(-1) == maCellIndex) - { - rArray.AddCellIndices(); - } - - return maCellIndex; -} + basegfx::B2DHomMatrix aRetval; + const basegfx::B2DRange aRange(rArray.GetCellRange(nCol, nRow, bExpandMerged)); -basegfx::B2DHomMatrix Cell::CreateCoordinateSystem(const Array& rArray) const -{ - if(!maCoordinateSystem.isIdentity()) + if(!aRange.isEmpty()) { - return maCoordinateSystem; - } + basegfx::B2DPoint aOrigin(aRange.getMinimum()); + basegfx::B2DVector aX(aRange.getWidth(), 0.0); + basegfx::B2DVector aY(0.0, aRange.getHeight()); - const size_t nCellIndex(GetCellIndex(rArray)); - - if(static_cast<size_t>(-1) != nCellIndex) - { - const basegfx::B2DRange aRange(rArray.GetCellRange(nCellIndex)); - - if(!aRange.isEmpty()) + if (IsRotated() && SvxRotateMode::SVX_ROTATE_MODE_STANDARD != meRotMode) { - basegfx::B2DPoint aOrigin(aRange.getMinimum()); - basegfx::B2DVector aX(aRange.getWidth(), 0.0); - basegfx::B2DVector aY(0.0, aRange.getHeight()); + // when rotated, adapt values. Get Skew (cos/sin == 1/tan) + const double fSkew(aY.getY() * (cos(mfOrientation) / sin(mfOrientation))); - if (IsRotated() && SvxRotateMode::SVX_ROTATE_MODE_STANDARD != meRotMode) + switch (meRotMode) { - // when rotated, adapt values. Get Skew (cos/sin == 1/tan) - const double fSkew(aY.getY() * (cos(mfOrientation) / sin(mfOrientation))); - - switch (meRotMode) - { - case SvxRotateMode::SVX_ROTATE_MODE_TOP: - // shear Y-Axis - aY.setX(-fSkew); - break; - case SvxRotateMode::SVX_ROTATE_MODE_CENTER: - // shear origin half, Y full - aOrigin.setX(aOrigin.getX() + (fSkew * 0.5)); - aY.setX(-fSkew); - break; - case SvxRotateMode::SVX_ROTATE_MODE_BOTTOM: - // shear origin full, Y full - aOrigin.setX(aOrigin.getX() + fSkew); - aY.setX(-fSkew); - break; - default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, already excluded above - break; - } + case SvxRotateMode::SVX_ROTATE_MODE_TOP: + // shear Y-Axis + aY.setX(-fSkew); + break; + case SvxRotateMode::SVX_ROTATE_MODE_CENTER: + // shear origin half, Y full + aOrigin.setX(aOrigin.getX() + (fSkew * 0.5)); + aY.setX(-fSkew); + break; + case SvxRotateMode::SVX_ROTATE_MODE_BOTTOM: + // shear origin full, Y full + aOrigin.setX(aOrigin.getX() + fSkew); + aY.setX(-fSkew); + break; + default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, already excluded above + break; } - - // use column vectors as coordinate axes, homogen column for translation - const_cast<Cell*>(this)->maCoordinateSystem = basegfx::utils::createCoordinateSystemTransform(aOrigin, aX, aY); } + + // use column vectors as coordinate axes, homogen column for translation + aRetval = basegfx::utils::createCoordinateSystemTransform(aOrigin, aX, aY); } - return maCoordinateSystem; + return aRetval; } Cell::Cell() : @@ -153,8 +132,6 @@ Cell::Cell() : mnAddBottom( 0 ), meRotMode(SvxRotateMode::SVX_ROTATE_MODE_STANDARD ), mfOrientation( 0.0 ), - maCoordinateSystem(), - maCellIndex(static_cast<size_t>(-1)), mbMergeOrig( false ), mbOverlapX( false ), mbOverlapY( false ) @@ -168,8 +145,6 @@ void Cell::MirrorSelfX() maLeft.MirrorSelf(); maRight.MirrorSelf(); mfOrientation = -mfOrientation; - maCoordinateSystem.identity(); - maCellIndex = static_cast<size_t>(-1); } @@ -864,31 +839,46 @@ long Array::GetHeight() const return GetRowPosition( mxImpl->mnHeight ) - GetRowPosition( 0 ); } -basegfx::B2DRange Array::GetCellRange( size_t nCellIndex ) const +basegfx::B2DRange Array::GetCellRange( size_t nCol, size_t nRow, bool bExpandMerged ) const { - return GetCellRange(nCellIndex % GetColCount(), nCellIndex / GetColCount()); -} - -basegfx::B2DRange Array::GetCellRange( size_t nCol, size_t nRow ) const -{ - size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); - size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); - size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); - size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); - const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) ); - const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 ); - tools::Rectangle aRect(aPoint, aSize); + if(bExpandMerged) + { + // get the Range of the fully expanded cell (if merged) + const size_t nFirstCol(mxImpl->GetMergedFirstCol( nCol, nRow )); + const size_t nFirstRow(mxImpl->GetMergedFirstRow( nCol, nRow )); + const size_t nLastCol(mxImpl->GetMergedLastCol( nCol, nRow )); + const size_t nLastRow(mxImpl->GetMergedLastRow( nCol, nRow )); + const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) ); + const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 ); + tools::Rectangle aRect(aPoint, aSize); + + // adjust rectangle for partly visible merged cells + const Cell& rCell = CELL( nCol, nRow ); + + if( rCell.IsMerged() ) + { + // not *sure* what exactly this is good for, + // it is just a hard set extension at merged cells, + // probably *should* be included in the above extended + // GetColPosition/GetColWidth already. This might be + // added due to GetColPosition/GetColWidth not working + // correcly over PageChanges (if used), but not sure. + aRect.Left() -= rCell.mnAddLeft; + aRect.Right() += rCell.mnAddRight; + aRect.Top() -= rCell.mnAddTop; + aRect.Bottom() += rCell.mnAddBottom; + } - // adjust rectangle for partly visible merged cells - const Cell& rCell = CELL( nCol, nRow ); - if( rCell.IsMerged() ) + return basegfx::B2DRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom()); + } + else { - aRect.Left() -= rCell.mnAddLeft; - aRect.Right() += rCell.mnAddRight; - aRect.Top() -= rCell.mnAddTop; - aRect.Bottom() += rCell.mnAddBottom; + const Point aPoint( GetColPosition( nCol ), GetRowPosition( nRow ) ); + const Size aSize( GetColWidth( nCol, nCol ) + 1, GetRowHeight( nRow, nRow ) + 1 ); + const tools::Rectangle aRect(aPoint, aSize); + + return basegfx::B2DRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom()); } - return basegfx::B2DRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom()); } // mirroring @@ -1023,45 +1013,6 @@ void HelperCreateVerticalEntry( ); } -void HelperCreateEntry(const Array& rArray, const Style& rStyle, drawinglayer::primitive2d::Primitive2DContainer& rSequence, const Color* pForceColor) -{ - const Cell* pCell = rStyle.GetUsingCell(); - - if(nullptr != pCell) - { - const size_t nCellIndex(pCell->GetCellIndex(rArray)); - - if(static_cast<size_t>(-1) != nCellIndex) - { - size_t col(nCellIndex % rArray.GetColCount()); - size_t row(nCellIndex / rArray.GetColCount()); - const bool bL(&rStyle == &pCell->GetStyleLeft()); - const bool bR(&rStyle == &pCell->GetStyleRight()); - const bool bT(&rStyle == &pCell->GetStyleTop()); - const bool bB(&rStyle == &pCell->GetStyleBottom()); - - if(bL || bR || bT || bB) - { - const basegfx::B2DHomMatrix aCoordinateSystem(pCell->CreateCoordinateSystem(rArray)); - const basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0)); - const basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1)); - const basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2)); - - if(bL || bR) - { - // left/right - HelperCreateVerticalEntry(rArray, rStyle, bL ? col : col + 1, row, aOrigin, aX, aY, rSequence, bL, pForceColor); - } - else if(bT || bB) - { - // top/bottom - HelperCreateHorizontalEntry(rArray, rStyle, col, bT ? row : row + 1, aOrigin, aX, aY, rSequence, bT, pForceColor); - } - } - } - } -} - void HelperMergeInB2DPrimitiveArray( const drawinglayer::primitive2d::Primitive2DContainer& rSource, drawinglayer::primitive2d::Primitive2DContainer& rTarget) @@ -1111,28 +1062,51 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "CreateB2DPrimitiveRange" ); DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "CreateB2DPrimitiveRange" ); + // It may be necessary to extend the loop ranges by one cell to the outside, + // when possible. This is needed e.g. when there is in Calc a Cell with an + // upper CellBorder using DoubleLine and that is right/left connected upwards + // to also DoubleLine. These upper DoubleLines will be extended to meet the + // lower of the upper CellBorder and thus have graphical parts that are + // displayed one cell below and right/left of the target cell - analog to + // other examples in all other directions. + // It would be possible to explicitely test this (if possible by indices at all) + // looping and testing the styles in the outer cells to detect this, but since + // for other usages (e.g. UI) usually nFirstRow==0 and nLastRow==GetRowCount()-1 + // (and analog for Col) it is okay to just expand the range when available. + // Do *not* change nFirstRow/nLastRow due to these needed to the boolean tests + // below (!) + // Checked usages, this method is used in Calc EditView/Print/Export stuff and + // in UI (Dialog), not for Writer Tables and Draw/Impress tables. All usages + // seem okay with this change, so I will add it. + const size_t nStartRow(nFirstRow > 0 ? nFirstRow - 1 : nFirstRow); + const size_t nEndRow(nLastRow < GetRowCount() - 1 ? nLastRow + 1 : nLastRow); + const size_t nStartCol(nFirstCol > 0 ? nFirstCol - 1 : nFirstCol); + const size_t nEndCol(nLastCol < GetColCount() - 1 ? nLastCol + 1 : nLastCol); + // various primitive sequences to collect the different border types drawinglayer::primitive2d::Primitive2DContainer aHorizontalSequence; - std::vector< drawinglayer::primitive2d::Primitive2DContainer > aVerticalSequences(nLastCol - nFirstCol + 1); + std::vector< drawinglayer::primitive2d::Primitive2DContainer > aVerticalSequences(nEndCol - nStartCol + 1); drawinglayer::primitive2d::Primitive2DContainer aCrossSequence; - for (size_t nRow = nFirstRow; nRow <= nLastRow; ++nRow) + // remember for which merged cells crossed lines were already created. To + // do so, hold the size_t cell index in a set for fast check + std::set< size_t > aMergedCells; + + for (size_t nRow(nStartRow); nRow <= nEndRow; ++nRow) { - for (size_t nCol = nFirstCol; nCol <= nLastCol; ++nCol) + for (size_t nCol(nStartCol); nCol <= nEndCol; ++nCol) { - const Cell& rCell = CELL(nCol, nRow); - const basegfx::B2DHomMatrix aCoordinateSystem(rCell.CreateCoordinateSystem(*this)); - const basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0)); - const basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1)); + // get Cell and CoordinateSystem (*only* for this Cell, do *not* expand for + // merged cells (!)), check if used (non-empty vectors) + const Cell& rCell(CELL(nCol, nRow)); + basegfx::B2DHomMatrix aCoordinateSystem(rCell.CreateCoordinateSystem(*this, nCol, nRow, false)); + basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0)); + basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1)); if(!aX.equalZero() && !aY.equalZero()) { - size_t _nFirstCol = mxImpl->GetMergedFirstCol(nCol, nRow); - size_t _nFirstRow = mxImpl->GetMergedFirstRow(nCol, nRow); - size_t _nLastCol = mxImpl->GetMergedLastCol(nCol, nRow); - size_t _nLastRow = mxImpl->GetMergedLastRow(nCol, nRow); - const basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2)); - + // get needed local values + basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2)); const bool bOverlapX(rCell.mbOverlapX); const bool bOverlapY(rCell.mbOverlapY); const bool bFirstCol(nCol == nFirstCol); @@ -1140,116 +1114,170 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( const bool bFirstRow(nRow == nFirstRow); const bool bLastRow(nRow == nLastRow); - if (!bOverlapX || bFirstRow) + // handle rotation: If cell is rotated, handle lower/right edge inside + // this local geometry due to the created CoordinateSystem already representing + // the needed transformations. + const bool bRotated(rCell.IsRotated()); + + // Additionally avoid double-handling by supressing handling when self not roated, + // but above/left is rotated and thus already handled. Two directly connected + // rotated will paint/create both edges, they might be rotated differently. + const bool bSuppressAbove(!bRotated && nRow > nFirstRow && CELL(nCol, nRow - 1).IsRotated()); + const bool bSupressLeft(!bRotated && nCol > nFirstCol && CELL(nCol - 1, nRow).IsRotated()); + + // create upper line for this Cell + if ((!bOverlapY // true for first line in merged cells or cells + || bFirstRow) // true for non_Calc usages of this tooling + && !bSuppressAbove) // true when above is not rotated, so edge is already handled (see bRotated) { - const Style& rTop = GetCellStyleTop(_nFirstCol, _nFirstRow); + // get CellStyle - method will take care to get the correct one, e.g. + // for merged cells (it uses ORIGCELL that works with topLeft's of these) + const Style& rTop(GetCellStyleTop(nCol, nRow)); if(rTop.IsUsed()) { - HelperCreateEntry(*this, rTop, aHorizontalSequence, pForceColor); + HelperCreateHorizontalEntry(*this, rTop, nCol, nRow, aOrigin, aX, aY, aHorizontalSequence, true, pForceColor); } } - if (bLastRow) + // create lower line for this Cell + if (bLastRow // true for non_Calc usages of this tooling + || bRotated) // true if cell is rotated, handle lower edge in local geometry { - const Style& rBottom = GetCellStyleBottom(_nFirstCol, _nFirstRow); + const Style& rBottom(GetCellStyleBottom(nCol, nRow)); if(rBottom.IsUsed()) { - HelperCreateEntry(*this, rBottom, aHorizontalSequence, pForceColor); + HelperCreateHorizontalEntry(*this, rBottom, nCol, nRow + 1, aOrigin, aX, aY, aHorizontalSequence, false, pForceColor); } } - if (!bOverlapY || bFirstCol) + // create left line for this Cell + if ((!bOverlapX // true for first column in merged cells or cells + || bFirstCol) // true for non_Calc usages of this tooling + && !bSupressLeft) // true when left is not rotated, so edge is already handled (see bRotated) { - const Style& rLeft(GetCellStyleLeft(_nFirstCol, _nFirstRow)); + const Style& rLeft(GetCellStyleLeft(nCol, nRow)); if(rLeft.IsUsed()) { - HelperCreateEntry(*this, rLeft, aVerticalSequences[nCol - nFirstCol], pForceColor); + HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, aVerticalSequences[nCol - nStartCol], true, pForceColor); } } - if (bLastCol) + // create right line for this Cell + if (bLastCol // true for non_Calc usages of this tooling + || bRotated) // true if cell is rotated, handle right edge in local geometry { - const Style& rRight(GetCellStyleRight(_nFirstCol, _nFirstRow)); + const Style& rRight(GetCellStyleRight(nCol, nRow)); if(rRight.IsUsed()) { - HelperCreateEntry(*this, rRight, aVerticalSequences[nCol - nFirstCol], pForceColor); + HelperCreateVerticalEntry(*this, rRight, nCol + 1, nRow, aOrigin, aX, aY, aVerticalSequences[nCol - nStartCol], false, pForceColor); } } - if ((!bOverlapX && !bOverlapY) || (bFirstCol && bFirstRow) || (!bOverlapY && bFirstCol) || (!bOverlapX && bFirstRow)) + // check for crossed lines, these need special treatment, especially + // for merged cells, see below + const Style& rTLBR(GetCellStyleTLBR(nCol, nRow)); + const Style& rBLTR(GetCellStyleBLTR(nCol, nRow)); + + if(rTLBR.IsUsed() || rBLTR.IsUsed()) { - const Style& rTLBR = GetCellStyleTLBR(_nFirstCol, _nFirstRow); - if(rTLBR.IsUsed()) + bool bContinue(true); + + if(rCell.IsMerged()) { - /// top-left and bottom-right Style Tables - /// Fill top-left Style Table - const Style& rTLFromRight(GetCellStyleTop(_nFirstCol, _nFirstRow)); - const Style& rTLFromBottom(GetCellStyleLeft(_nFirstCol, _nFirstRow)); - StyleVectorTable aStart; - const basegfx::B2DVector aAxisA(aX + aY); - - aStart.add(rTLFromRight, aAxisA, aX, false); - aStart.add(rTLFromBottom, aAxisA, aY, false); - aStart.sort(); - - /// Fill bottom-right Style Table - const Style& rBRFromBottom(GetCellStyleRight(_nLastCol, _nLastRow)); - const Style& rBRFromLeft(GetCellStyleBottom(_nLastCol, _nLastRow)); - StyleVectorTable aEnd; - const basegfx::B2DVector aAxisB(-aX -aY); - - aEnd.add(rBRFromBottom, aAxisB, -aY, true); - aEnd.add(rBRFromLeft, aAxisB, -aX, true); - aEnd.sort(); - - CreateBorderPrimitives( - aCrossSequence, - aOrigin, - aX + aY, - rTLBR, - aStart, - aEnd, - pForceColor - ); + // first check if this merged cell was already handled. To do so, + // calculate and use the index of the TopLeft cell + const size_t _nMergedFirstCol(mxImpl->GetMergedFirstCol(nCol, nRow)); + const size_t _nMergedFirstRow(mxImpl->GetMergedFirstRow(nCol, nRow)); + const size_t nIndexOfMergedCell(mxImpl->GetIndex(_nMergedFirstCol, _nMergedFirstRow)); + bContinue = (aMergedCells.end() == aMergedCells.find(nIndexOfMergedCell)); + + if(bContinue) + { + // not found, add now to mark as handled + aMergedCells.insert(nIndexOfMergedCell); + + // when merged, get extended coordinate system and derived values + // for the full range of this merged cell + aCoordinateSystem = rCell.CreateCoordinateSystem(*this, nCol, nRow, true); + aX = basegfx::utils::getColumn(aCoordinateSystem, 0); + aY = basegfx::utils::getColumn(aCoordinateSystem, 1); + aOrigin = basegfx::utils::getColumn(aCoordinateSystem, 2); + } } - const Style& rBLTR = GetCellStyleBLTR(_nFirstCol, _nFirstRow); - if(rBLTR.IsUsed()) + if(bContinue) { - /// bottom-left and top-right Style Tables - /// Fill bottom-left Style Table - const Style& rBLFromTop(GetCellStyleLeft(_nFirstCol, _nLastRow)); - const Style& rBLFromBottom(GetCellStyleBottom(_nFirstCol, _nLastRow)); - StyleVectorTable aStart; - const basegfx::B2DVector aAxisA(aX - aY); - - aStart.add(rBLFromTop, aAxisA, -aY, true); - aStart.add(rBLFromBottom, aAxisA, aX, false); - aStart.sort(); - - /// Fill top-right Style Table - const Style& rTRFromLeft(GetCellStyleTop(_nLastCol, _nFirstRow)); - const Style& rTRFromBottom(GetCellStyleRight(_nLastCol, _nFirstRow)); - StyleVectorTable aEnd; - const basegfx::B2DVector aAxisB(aY - aX); - - aEnd.add(rTRFromLeft, aAxisB, -aX, true); - aEnd.add(rTRFromBottom, aAxisB, aY, false); - aEnd.sort(); - - CreateBorderPrimitives( - aCrossSequence, - aOrigin + aY, - aX - aY, - rBLTR, - aStart, - aEnd, - pForceColor - ); + if(rTLBR.IsUsed()) + { + /// top-left and bottom-right Style Tables + /// Fill top-left Style Table + const Style& rTLFromRight(GetCellStyleTop(nCol, nRow)); + const Style& rTLFromBottom(GetCellStyleLeft(nCol, nRow)); + StyleVectorTable aStart; + const basegfx::B2DVector aAxisA(aX + aY); + + aStart.add(rTLFromRight, aAxisA, aX, false); + aStart.add(rTLFromBottom, aAxisA, aY, false); + aStart.sort(); + + /// Fill bottom-right Style Table + const Style& rBRFromBottom(GetCellStyleRight(nCol, nRow)); + const Style& rBRFromLeft(GetCellStyleBottom(nCol, nRow)); + StyleVectorTable aEnd; + const basegfx::B2DVector aAxisB(-aX -aY); + + aEnd.add(rBRFromBottom, aAxisB, -aY, true); + aEnd.add(rBRFromLeft, aAxisB, -aX, true); + aEnd.sort(); + + CreateBorderPrimitives( + aCrossSequence, + aOrigin, + aX + aY, + rTLBR, + aStart, + aEnd, + pForceColor + ); + } + + if(rBLTR.IsUsed()) + { + /// bottom-left and top-right Style Tables + /// Fill bottom-left Style Table + const Style& rBLFromTop(GetCellStyleLeft(nCol, nRow)); + const Style& rBLFromBottom(GetCellStyleBottom(nCol, nRow)); + StyleVectorTable aStart; + const basegfx::B2DVector aAxisA(aX - aY); + + aStart.add(rBLFromTop, aAxisA, -aY, true); + aStart.add(rBLFromBottom, aAxisA, aX, false); + aStart.sort(); + + /// Fill top-right Style Table + const Style& rTRFromLeft(GetCellStyleTop(nCol, nRow)); + const Style& rTRFromBottom(GetCellStyleRight(nCol, nRow)); + StyleVectorTable aEnd; + const basegfx::B2DVector aAxisB(aY - aX); + + aEnd.add(rTRFromLeft, aAxisB, -aX, true); + aEnd.add(rTRFromBottom, aAxisB, aY, false); + aEnd.sort(); + + CreateBorderPrimitives( + aCrossSequence, + aOrigin + aY, + aX - aY, + rBLTR, + aStart, + aEnd, + pForceColor + ); + } } } } @@ -1259,6 +1287,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( // to stay compatible, create order as it was formally. Also try to // merge primitives as far as possible HelperMergeInB2DPrimitiveArray(aHorizontalSequence, aCrossSequence); + for(const auto& aVert : aVerticalSequences) { HelperMergeInB2DPrimitiveArray(aVert, aCrossSequence); @@ -1279,19 +1308,9 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveArray() return aPrimitives; } -void Array::AddCellIndices() const -{ - for (size_t a(0); a < mxImpl->maCells.size(); a++) - { - const_cast<Array*>(this)->mxImpl->maCells[a].maCellIndex = a; - } -} - #undef ORIGCELL #undef CELLACC #undef CELL - - #undef DBG_FRAME_CHECK_ROW_1 #undef DBG_FRAME_CHECK_COL_1 #undef DBG_FRAME_CHECK_COLROW @@ -1299,7 +1318,6 @@ void Array::AddCellIndices() const #undef DBG_FRAME_CHECK_COL #undef DBG_FRAME_CHECK - } } diff --git a/svx/source/dialog/frmsel.cxx b/svx/source/dialog/frmsel.cxx index e3a6b6a9f8ba..fd858605e32c 100644 --- a/svx/source/dialog/frmsel.cxx +++ b/svx/source/dialog/frmsel.cxx @@ -410,7 +410,7 @@ void FrameSelectorImpl::InitBorderGeometry() { for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow ) { - const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow )); + const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow, true )); const tools::Rectangle aRect( basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()), basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY())); @@ -469,7 +469,7 @@ void FrameSelectorImpl::InitBorderGeometry() for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow ) { // the usable area between horizonal/vertical frame borders of current quadrant - const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow )); + const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow, true )); const tools::Rectangle aRect( basegfx::fround(aCellRange.getMinX()) + nClV + 1, basegfx::fround(aCellRange.getMinY()) + nClH + 1, basegfx::fround(aCellRange.getMaxX()) - nClV + 1, basegfx::fround(aCellRange.getMaxY()) - nClH + 1); diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx index 2f818e5ee7f2..b37950323fe3 100644 --- a/svx/source/table/viewcontactoftableobj.cxx +++ b/svx/source/table/viewcontactoftableobj.cxx @@ -36,8 +36,10 @@ #include <drawinglayer/attribute/sdrlineattribute.hxx> #include <drawinglayer/attribute/sdrshadowattribute.hxx> #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <svx/framelink.hxx> +#include <svx/framelinkarray.hxx> #include <cell.hxx> #include "tablelayouter.hxx" @@ -196,42 +198,6 @@ namespace sdr return svx::frame::Style(); } - void createForVector(bool bHor, drawinglayer::primitive2d::Primitive2DContainer& rContainer, const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX, - const svx::frame::Style& rLine, - const svx::frame::Style& rLeftA, const svx::frame::Style& rLeftB, const svx::frame::Style& rLeftC, - const svx::frame::Style& rRightA, const svx::frame::Style& rRightB, const svx::frame::Style& rRightC) - { - /// top-left and bottom-right Style Tables - const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(rX)); - - /// Fill top-left Style Table - svx::frame::StyleVectorTable aStart; - - aStart.add(rLeftA, rX, -aY, bHor); // bHor ? true : false)); - aStart.add(rLeftB, rX, -rX, true); // bHor ? true : true)); - aStart.add(rLeftC, rX, aY, !bHor); // bHor ? false : true)); - aStart.sort(); - - /// Fill bottom-right Style Table - svx::frame::StyleVectorTable aEnd; - const basegfx::B2DVector aAxis(-rX); - - aEnd.add(rRightA, aAxis, -aY, bHor); // bHor ? true : false)); - aEnd.add(rRightB, aAxis, rX, false); // bHor ? false : false)); - aEnd.add(rRightC, aAxis, aY, !bHor); // bHor ? false : true)); - aEnd.sort(); - - CreateBorderPrimitives( - rContainer, - rOrigin, - rX, - rLine, - aStart, - aEnd, - nullptr - ); - } - drawinglayer::primitive2d::Primitive2DContainer ViewContactOfTableObj::createViewIndependentPrimitive2DSequence() const { const sdr::table::SdrTableObj& rTableObj = static_cast<const sdr::table::SdrTableObj&>(GetSdrObject()); @@ -249,7 +215,7 @@ namespace sdr if(nAllCount) { - const sdr::table::TableLayouter& rTableLayouter = rTableObj.getTableLayouter(); + const sdr::table::TableLayouter& rTableLayouter(rTableObj.getTableLayouter()); const bool bIsRTL(css::text::WritingMode_RL_TB == rTableObj.GetWritingMode()); sdr::table::CellPos aCellPos; sdr::table::CellRef xCurrentCell; @@ -258,19 +224,59 @@ namespace sdr // create range using the model data directly. This is in SdrTextObj::aRect which i will access using // GetGeoRect() to not trigger any calculations. It's the unrotated geometry. const tools::Rectangle& rObjectRectangle(rTableObj.GetGeoRect()); - const basegfx::B2DRange aObjectRange(rObjectRectangle.Left(), rObjectRectangle.Top(), rObjectRectangle.Right(), rObjectRectangle.Bottom()); + const basegfx::B2DRange aObjectRange( + rObjectRectangle.Left(), rObjectRectangle.Top(), + rObjectRectangle.Right(), rObjectRectangle.Bottom()); + + // To create the CellBorderPrimitives, use the tolling from svx::frame::Array + // which is capable of creating the needed visualization. Fill it during the + // anyways needed run over the table. + svx::frame::Array aArray; - // for each cell we need potentially a cell primitive and a border primitive - // (e.g. single cell). Prepare sequences and input counters - drawinglayer::primitive2d::Primitive2DContainer aBorderSequence; + // initialize CellBorderArray for primitive creation + aArray.Initialize(nColCount, nRowCount); // create single primitives per cell for(aCellPos.mnRow = 0; aCellPos.mnRow < nRowCount; aCellPos.mnRow++) { + // add RowHeight to CellBorderArray for primitive creation + aArray.SetRowHeight(aCellPos.mnRow, rTableLayouter.getRowHeight(aCellPos.mnRow)); + for(aCellPos.mnCol = 0; aCellPos.mnCol < nColCount; aCellPos.mnCol++) { + // add ColWidth to CellBorderArray for primitive creation, only + // needs to be done in the 1st run + if(0 == aCellPos.mnRow) + { + aArray.SetColWidth(aCellPos.mnCol, rTableLayouter.getColumnWidth(aCellPos.mnCol)); + } + + // access the cell xCurrentCell.set(dynamic_cast< sdr::table::Cell* >(xTable->getCellByPosition(aCellPos.mnCol, aCellPos.mnRow).get())); + if(xCurrentCell.is()) + { + // copy styles for current cell to CellBorderArray for primitive creation + aArray.SetCellStyleLeft(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow, false, nColCount, nRowCount, bIsRTL)); + aArray.SetCellStyleRight(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol + 1, aCellPos.mnRow, false, nColCount, nRowCount, bIsRTL)); + aArray.SetCellStyleTop(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow, true, nColCount, nRowCount, bIsRTL)); + aArray.SetCellStyleBottom(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow + 1, true, nColCount, nRowCount, bIsRTL)); + + // ignore merged cells (all except the top-left of a merged cell) + if(!xCurrentCell->isMerged()) + { + // check if we are the top-left of a merged cell + const sal_Int32 nXSpan(xCurrentCell->getColumnSpan()); + const sal_Int32 nYSpan(xCurrentCell->getRowSpan()); + + if(nXSpan > 1 || nYSpan > 1) + { + // if merged, set so at CellBorderArray for primitive creation + aArray.SetMergedRange(aCellPos.mnCol, aCellPos.mnRow, aCellPos.mnCol + nXSpan - 1, aCellPos.mnRow + nYSpan - 1); + } + } + } + if(xCurrentCell.is() && !xCurrentCell->isMerged()) { if(rTableLayouter.getCellArea(xCurrentCell, aCellPos, aCellArea)) @@ -318,77 +324,54 @@ namespace sdr aCellMatrix, aAttribute)); aRetval.append(xCellReference); } - - // handle cell borders - const sal_Int32 nX(bIsRTL ? nColCount - aCellPos.mnCol : aCellPos.mnCol); - const sal_Int32 nY(aCellPos.mnRow); - - // get access values for X,Y at the cell's end - const sal_Int32 nXSpan(xCurrentCell->getColumnSpan()); - const sal_Int32 nYSpan(xCurrentCell->getRowSpan()); - const sal_Int32 nXRight(bIsRTL ? nX - nXSpan : nX + nXSpan); - const sal_Int32 nYBottom(nY + nYSpan); - - // get basic lines - const svx::frame::Style aLeftLine(impGetLineStyle(rTableLayouter, nX, nY, false, nColCount, nRowCount, bIsRTL)); - //To resolve the bug fdo#59117 - //In RTL table as BottomLine & TopLine are drawn from Left Side to Right, nX should be nX-1 - const svx::frame::Style aBottomLine(impGetLineStyle(rTableLayouter, bIsRTL?nX-1:nX, nYBottom, true, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aRightLine(impGetLineStyle(rTableLayouter, nXRight, nY, false, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aTopLine(impGetLineStyle(rTableLayouter, bIsRTL?nX-1:nX, nY, true, nColCount, nRowCount, bIsRTL)); - - if(aLeftLine.IsUsed() || aBottomLine.IsUsed() || aRightLine.IsUsed() || aTopLine.IsUsed()) - { - // get the neighbor cells' borders - const svx::frame::Style aLeftFromTLine(impGetLineStyle(rTableLayouter, nX, nY - 1, false, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aLeftFromBLine(impGetLineStyle(rTableLayouter, nX, nYBottom + 1, false, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aRightFromTLine(impGetLineStyle(rTableLayouter, nXRight, nY - 1, false, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aRightFromBLine(impGetLineStyle(rTableLayouter, nXRight, nYBottom + 1, false, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aTopFromLLine(impGetLineStyle(rTableLayouter, nX - 1, nY, true, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aTopFromRLine(impGetLineStyle(rTableLayouter, nXRight + 1, nY, true, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aBottomFromLLine(impGetLineStyle(rTableLayouter, nX - 1, nYBottom, true, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aBottomFromRLine(impGetLineStyle(rTableLayouter, nXRight + 1, nYBottom, true, nColCount, nRowCount, bIsRTL)); - - // get cell coordinate system - const basegfx::B2DPoint aOrigin(aCellMatrix * basegfx::B2DPoint(0.0, 0.0)); - const basegfx::B2DVector aX(aCellMatrix * basegfx::B2DVector(1.0, 0.0)); - const basegfx::B2DVector aY(aCellMatrix * basegfx::B2DVector(0.0, 1.0)); - - if(aLeftLine.IsUsed()) - { - createForVector(false, aBorderSequence, aOrigin, aY, aLeftLine, - aTopLine, aLeftFromTLine, aTopFromLLine, - aBottomLine, aLeftFromBLine, aBottomFromLLine); - } - - if(aBottomLine.IsUsed()) - { - createForVector(true, aBorderSequence, aOrigin + aY, aX, aBottomLine, - aLeftLine, aBottomFromLLine, aLeftFromBLine, - aRightLine, aBottomFromRLine, aRightFromBLine); - } - - if(aRightLine.IsUsed()) - { - createForVector(false, aBorderSequence, aOrigin + aX, aY, aRightLine, - aTopFromRLine, aRightFromTLine, aTopLine, - aBottomFromRLine, aRightFromBLine, aBottomLine); - } - - if(aTopLine.IsUsed()) - { - createForVector(true, aBorderSequence, aOrigin, aX, aTopLine, - aLeftFromTLine, aTopFromLLine, aLeftLine, - aRightFromTLine, aTopFromRLine, aRightLine); - } - } } } } } - // append Border info to target. We want fillings and text first - aRetval.append(aBorderSequence); + // now create all CellBorderPrimitives + const drawinglayer::primitive2d::Primitive2DContainer aCellBorderPrimitives(aArray.CreateB2DPrimitiveArray()); + + if(!aCellBorderPrimitives.empty()) + { + // this is already scaled (due to Table in non-uniform coordinates), so + // first transform removing scale + basegfx::B2DHomMatrix aTransform( + basegfx::utils::createScaleB2DHomMatrix( + 1.0 / aObjectRange.getWidth(), + 1.0 / aObjectRange.getHeight())); + + // If RTL, mirror the whole unified table in X and move right. + // This is much easier than taking this into account for the whole + // index calcualtions + if(bIsRTL) + { + aTransform.scale(-1.0, 1.0); + aTransform.translate(1.0, 0.0); + } + + // create object matrix + const GeoStat& rGeoStat(rTableObj.GetGeoStat()); + const double fShearX(rGeoStat.nShearAngle ? tan((36000 - rGeoStat.nShearAngle) * F_PI18000) : 0.0); + const double fRotate(rGeoStat.nRotationAngle ? (36000 - rGeoStat.nRotationAngle) * F_PI18000 : 0.0); + const basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( + aObjectRange.getWidth(), aObjectRange.getHeight(), fShearX, fRotate, + aObjectRange.getMinX(), aObjectRange.getMinY())); + + // add object matrix to transform. By doing so theoretically + // CellBorders could be also rotated/sheared for the first time ever. + // To completely make that work, the primitives already created in + // aRetval would also have to be based on ObjectMatrix, not only on + // ObjectRange as it currently is. + aTransform *= aObjectMatrix; + + // create a transform primitive with this and embed CellBorders + // and append to retval + aRetval.append( + new drawinglayer::primitive2d::TransformPrimitive2D( + aTransform, + aCellBorderPrimitives)); + } } if(!aRetval.empty()) |