diff options
author | David Tardon <dtardon@redhat.com> | 2013-06-01 09:43:50 +0200 |
---|---|---|
committer | Noel Power <noel.power@suse.com> | 2013-06-19 17:21:11 +0000 |
commit | 2839735633dedfcbf2de77180a140eb4bf9a9c2d (patch) | |
tree | d647961c63164f07d48d57fdba462e183d058426 | |
parent | 5a246765fced0099ae9071c8df98636638ee0b18 (diff) |
fdo#62224 reconstruct border state for table dialog
Change-Id: I68a4cd1974579119a2d6dccba008441a9bec78df
(cherry picked from commit 67e87f8b88a5a6a741717cc4a8e64f65f9c9cd52)
Conflicts:
include/svx/sdr/table/tablecontroller.hxx
Change-Id: Id9d72360d234dd1f9dbb9fd252fc0abefff9ad63
Reviewed-on: https://gerrit.libreoffice.org/4144
Reviewed-by: Noel Power <noel.power@suse.com>
Tested-by: Noel Power <noel.power@suse.com>
-rw-r--r-- | editeng/inc/editeng/borderline.hxx | 2 | ||||
-rw-r--r-- | editeng/source/items/borderline.cxx | 5 | ||||
-rw-r--r-- | svx/source/table/tablecontroller.cxx | 219 | ||||
-rw-r--r-- | svx/source/table/tablecontroller.hxx | 8 |
4 files changed, 232 insertions, 2 deletions
diff --git a/editeng/inc/editeng/borderline.hxx b/editeng/inc/editeng/borderline.hxx index 067e216aaa9a..a7713b7edffb 100644 --- a/editeng/inc/editeng/borderline.hxx +++ b/editeng/inc/editeng/borderline.hxx @@ -160,7 +160,7 @@ namespace editeng { static BorderWidthImpl getWidthImpl( SvxBorderStyle nStyle ); }; -// ============================================================================ +EDITENG_DLLPUBLIC bool operator!=( const SvxBorderLine& rLeft, const SvxBorderLine& rRight ); } // namespace editeng diff --git a/editeng/source/items/borderline.cxx b/editeng/source/items/borderline.cxx index 646a3480724c..fe451c333881 100644 --- a/editeng/source/items/borderline.cxx +++ b/editeng/source/items/borderline.cxx @@ -723,6 +723,11 @@ bool SvxBorderLine::HasPriority( const SvxBorderLine& rOtherLine ) const return false; } +bool operator!=( const SvxBorderLine& rLeft, const SvxBorderLine& rRight ) +{ + return !(rLeft == rRight); +} + } // namespace editeng /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/table/tablecontroller.cxx b/svx/source/table/tablecontroller.cxx index 16a2c2cceb8d..b25e5f19b77b 100644 --- a/svx/source/table/tablecontroller.cxx +++ b/svx/source/table/tablecontroller.cxx @@ -17,6 +17,7 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <algorithm> #include "tablecontroller.hxx" @@ -712,7 +713,6 @@ void SvxTableController::onFormatTable( SfxRequest& rReq ) if( !pArgs && pTableObj->GetModel() ) { SfxItemSet aNewAttr( pTableObj->GetModel()->GetItemPool() ); - MergeAttrFromSelectedCells(aNewAttr, sal_False); // merge drawing layer text distance items into SvxBoxItem used by the dialog SvxBoxItem aBoxItem( static_cast< const SvxBoxItem& >( aNewAttr.Get( SDRATTR_TABLE_BORDER ) ) ); @@ -720,7 +720,13 @@ void SvxTableController::onFormatTable( SfxRequest& rReq ) aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( ((SdrTextRightDistItem&)(aNewAttr.Get(SDRATTR_TEXT_RIGHTDIST))).GetValue()), BOX_LINE_RIGHT ); aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( ((SdrTextUpperDistItem&)(aNewAttr.Get(SDRATTR_TEXT_UPPERDIST))).GetValue()), BOX_LINE_TOP ); aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( ((SdrTextLowerDistItem&)(aNewAttr.Get(SDRATTR_TEXT_LOWERDIST))).GetValue()), BOX_LINE_BOTTOM ); + + SvxBoxInfoItem aBoxInfoItem( static_cast< const SvxBoxInfoItem& >( aNewAttr.Get( SDRATTR_TABLE_BORDER_INNER ) ) ); + + MergeAttrFromSelectedCells(aNewAttr, sal_False); + FillCommonBorderAttrFromSelectedCells( aBoxItem, aBoxInfoItem ); aNewAttr.Put( aBoxItem ); + aNewAttr.Put( aBoxInfoItem ); SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); std::auto_ptr< SfxAbstractTabDialog > pDlg( pFact ? pFact->CreateSvxFormatCellsDialog( NULL, &aNewAttr, pTableObj->GetModel(), pTableObj) : 0 ); @@ -2574,6 +2580,217 @@ IMPL_LINK_NOARG(SvxTableController, UpdateHdl) return 0; } +namespace +{ + +struct LinesState +{ + LinesState(SvxBoxItem& rBoxItem_, SvxBoxInfoItem& rBoxInfoItem_) + : rBoxItem(rBoxItem_) + , rBoxInfoItem(rBoxInfoItem_) + { + std::fill_n(aBorderSet, 4, false); + std::fill_n(aInnerLineSet, 2, false); + std::fill_n(aBorderIndeterminate, 4, false); + std::fill_n(aInnerLineIndeterminate, 2, false); + } + + SvxBoxItem& rBoxItem; + SvxBoxInfoItem& rBoxInfoItem; + bool aBorderSet[4]; + bool aInnerLineSet[2]; + bool aBorderIndeterminate[4]; + bool aInnerLineIndeterminate[2]; +}; + +class BoxItemWrapper +{ +public: + BoxItemWrapper(SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem, sal_uInt16 nBorderLine, sal_uInt16 nInnerLine, bool bBorder); + + const SvxBorderLine* getLine() const; + void setLine(const SvxBorderLine* pLine); + +private: + SvxBoxItem& m_rBoxItem; + SvxBoxInfoItem& m_rBoxInfoItem; + const sal_uInt16 m_nLine; + const bool m_bBorder; +}; + +BoxItemWrapper::BoxItemWrapper( + SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem, + const sal_uInt16 nBorderLine, const sal_uInt16 nInnerLine, const bool bBorder) + : m_rBoxItem(rBoxItem) + , m_rBoxInfoItem(rBoxInfoItem) + , m_nLine(bBorder ? nBorderLine : nInnerLine) + , m_bBorder(bBorder) +{ + assert(bBorder ? (m_nLine <= BOX_LINE_RIGHT) : (m_nLine <= BOXINFO_LINE_VERT)); +} + +const SvxBorderLine* BoxItemWrapper::getLine() const +{ + if (m_bBorder) + return m_rBoxItem.GetLine(m_nLine); + else + return (m_nLine == BOXINFO_LINE_HORI) ? m_rBoxInfoItem.GetHori() : m_rBoxInfoItem.GetVert(); +} + +void BoxItemWrapper::setLine(const SvxBorderLine* pLine) +{ + if (m_bBorder) + m_rBoxItem.SetLine(pLine, m_nLine); + else + m_rBoxInfoItem.SetLine(pLine, m_nLine); +} + +void lcl_MergeBorderLine( + LinesState& rLinesState, const SvxBorderLine* const pLine, const sal_uInt16 nLine, + const sal_uInt8 nValidFlag, const bool bBorder = true) +{ + const sal_uInt16 nInnerLine(bBorder ? 0 : ((nValidFlag & VALID_HORI) ? BOXINFO_LINE_HORI : BOXINFO_LINE_VERT)); + BoxItemWrapper aBoxItem(rLinesState.rBoxItem, rLinesState.rBoxInfoItem, nLine, nInnerLine, bBorder); + bool& rbSet(bBorder ? rLinesState.aBorderSet[nLine] : rLinesState.aInnerLineSet[nInnerLine]); + bool& rbIndeterminate(bBorder ? rLinesState.aBorderIndeterminate[nLine] : rLinesState.aInnerLineIndeterminate[nInnerLine]); + + if (rbSet) + { + if (!rbIndeterminate) + { + const SvxBorderLine* const pMergedLine(aBoxItem.getLine()); + if ((pLine && !pMergedLine) || (!pLine && pMergedLine) || (pLine && (*pLine != *pMergedLine))) + { + aBoxItem.setLine(0); + rbIndeterminate = true; + } + } + } + else + { + aBoxItem.setLine(pLine); + rbSet = true; + } +} + +void lcl_MergeBorderOrInnerLine( + LinesState& rLinesState, const SvxBorderLine* const pLine, const sal_uInt16 nLine, + const sal_uInt8 nValidFlag, const bool bBorder) +{ + if (bBorder) + lcl_MergeBorderLine(rLinesState, pLine, nLine, nValidFlag); + else + { + const bool bVertical = (nLine == BOX_LINE_LEFT) || (nLine == BOX_LINE_RIGHT); + lcl_MergeBorderLine(rLinesState, pLine, nLine, bVertical ? VALID_VERT : VALID_HORI, false); + } +} + +void lcl_MergeCommonBorderAttr(LinesState& rLinesState, const SvxBoxItem& rCellBoxItem, const sal_Int32 nCellFlags) +{ + if( (nCellFlags & (CELL_BEFORE|CELL_AFTER|CELL_UPPER|CELL_LOWER)) != 0 ) + { + // current cell is outside the selection + + if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER)) == 0 ) // check if its not nw or ne corner + { + if( nCellFlags & CELL_UPPER ) + lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetBottom(), BOX_LINE_TOP, VALID_TOP); + else if( nCellFlags & CELL_LOWER ) + lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetTop(), BOX_LINE_BOTTOM, VALID_BOTTOM); + } + else if( (nCellFlags & ( CELL_UPPER|CELL_LOWER)) == 0 ) // check if its not sw or se corner + { + if( nCellFlags & CELL_BEFORE ) + lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetRight(), BOX_LINE_LEFT, VALID_LEFT); + else if( nCellFlags & CELL_AFTER ) + lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetLeft(), BOX_LINE_RIGHT, VALID_RIGHT); + } + } + else + { + // current cell is inside the selection + + lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetTop(), BOX_LINE_TOP, VALID_TOP, nCellFlags & CELL_TOP); + lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetBottom(), BOX_LINE_BOTTOM, VALID_BOTTOM, nCellFlags & CELL_BOTTOM); + lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetLeft(), BOX_LINE_LEFT, VALID_LEFT, nCellFlags & CELL_LEFT); + lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetRight(), BOX_LINE_RIGHT, VALID_RIGHT, nCellFlags & CELL_RIGHT); + } +} + +} + +void SvxTableController::FillCommonBorderAttrFromSelectedCells( SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem ) const +{ + if( mxTable.is() ) + { + const sal_Int32 nRowCount = mxTable->getRowCount(); + const sal_Int32 nColCount = mxTable->getColumnCount(); + if( nRowCount && nColCount ) + { + CellPos aStart, aEnd; + const_cast< SvxTableController* >( this )->getSelectedCells( aStart, aEnd ); + + // We are adding one more row/column around the block of selected cells. + // We will be checking the adjoining border of these too. + const sal_Int32 nLastRow = std::min( aEnd.mnRow + 2, nRowCount ); + const sal_Int32 nLastCol = std::min( aEnd.mnCol + 2, nColCount ); + + rBoxInfoItem.SetValid( sal_uInt8( ~0 ), sal_False ); + LinesState aLinesState( rBoxItem, rBoxInfoItem ); + + /* Here we go through all the selected cells (enhanced by + * the adjoining row/column on each side) and determine the + * lines for presentation. The algorithm is simple: + * 1. if a border or inner line is set in all cells to the + * same value, it will be used. + * 2. if a border or inner line is set only in some cells, + * or it has different values, it will be set to + * indeterminate state (SetValid() on rBoxInfoItem). + * 3. otherwise it will be unset. + */ + for( sal_Int32 nRow = std::max( aStart.mnRow - 1, (sal_Int32)0 ); nRow < nLastRow; nRow++ ) + { + sal_uInt16 nRowFlags = 0; + nRowFlags |= (nRow == aStart.mnRow) ? CELL_TOP : 0; + nRowFlags |= (nRow == aEnd.mnRow) ? CELL_BOTTOM : 0; + nRowFlags |= (nRow < aStart.mnRow) ? CELL_UPPER : 0; + nRowFlags |= (nRow > aEnd.mnRow) ? CELL_LOWER : 0; + + for( sal_Int32 nCol = std::max( aStart.mnCol - 1, (sal_Int32)0 ); nCol < nLastCol; nCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( !xCell.is() ) + continue; + + sal_uInt16 nCellFlags = nRowFlags; + nCellFlags |= (nCol == aStart.mnCol) ? CELL_LEFT : 0; + nCellFlags |= (nCol == aEnd.mnCol) ? CELL_RIGHT : 0; + nCellFlags |= (nCol < aStart.mnCol) ? CELL_BEFORE : 0; + nCellFlags |= (nCol > aEnd.mnCol) ? CELL_AFTER : 0; + + const SfxItemSet& rSet = xCell->GetItemSet(); + const SvxBoxItem& rCellBoxItem = static_cast< const SvxBoxItem& >( rSet.Get(SDRATTR_TABLE_BORDER ) ); + lcl_MergeCommonBorderAttr( aLinesState, rCellBoxItem, nCellFlags ); + } + } + + if (!aLinesState.aBorderIndeterminate[BOX_LINE_TOP]) + aLinesState.rBoxInfoItem.SetValid(VALID_TOP); + if (!aLinesState.aBorderIndeterminate[BOX_LINE_BOTTOM]) + aLinesState.rBoxInfoItem.SetValid(VALID_BOTTOM); + if (!aLinesState.aBorderIndeterminate[BOX_LINE_LEFT]) + aLinesState.rBoxInfoItem.SetValid(VALID_LEFT); + if (!aLinesState.aBorderIndeterminate[BOX_LINE_RIGHT]) + aLinesState.rBoxInfoItem.SetValid(VALID_RIGHT); + if (!aLinesState.aInnerLineIndeterminate[BOXINFO_LINE_HORI]) + aLinesState.rBoxInfoItem.SetValid(VALID_HORI); + if (!aLinesState.aInnerLineIndeterminate[BOXINFO_LINE_VERT]) + aLinesState.rBoxInfoItem.SetValid(VALID_VERT); + } + } +} + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/table/tablecontroller.hxx b/svx/source/table/tablecontroller.hxx index c25b2f1b093b..7a9d4075dda5 100644 --- a/svx/source/table/tablecontroller.hxx +++ b/svx/source/table/tablecontroller.hxx @@ -33,6 +33,8 @@ class SdrObjEditView; class SdrObject; class SfxItemSet; +class SvxBoxItem; +class SvxBoxInfoItem; namespace sdr { namespace table { @@ -76,6 +78,12 @@ public: SVX_DLLPRIVATE void MergeAttrFromSelectedCells(SfxItemSet& rAttr, bool bOnlyHardAttr) const; SVX_DLLPRIVATE void SetAttrToSelectedCells(const SfxItemSet& rAttr, bool bReplaceAll); + /** Fill the values that are common for all selected cells. + * + * This lets the Borders dialog to display the line arrangement + * properly. + */ + SVX_DLLPRIVATE void FillCommonBorderAttrFromSelectedCells(SvxBoxItem& rBox, SvxBoxInfoItem& rBoxInfo) const; SVX_DLLPRIVATE virtual bool GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const; SVX_DLLPRIVATE virtual bool SetAttributes(const SfxItemSet& rSet, bool bReplaceAll); |