diff options
author | Dennis Francis <dennisfrancis.in@gmail.com> | 2015-11-01 03:49:38 +0530 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2015-12-07 13:49:53 +0000 |
commit | 2e512174f2116d86682037459fd5ab5164e9f510 (patch) | |
tree | f28b135f29c1246a7a1f6a766de1214ab49f3bf6 | |
parent | 1a032dcfebc2702f0612c470d6b9c3e3cf4fb637 (diff) |
tdf#34449 : ability of deleting borders of a cell from adjacent cell
Change-Id: Ieb13a9ea88faa220d1ee352b0e47268a7fda5f38
Reviewed-on: https://gerrit.libreoffice.org/19715
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Eike Rathke <erack@redhat.com>
-rw-r--r-- | cui/source/inc/border.hxx | 5 | ||||
-rw-r--r-- | cui/source/tabpages/border.cxx | 86 | ||||
-rw-r--r-- | cui/uiconfig/ui/borderpage.ui | 14 | ||||
-rw-r--r-- | editeng/source/items/frmitems.cxx | 9 | ||||
-rw-r--r-- | include/editeng/boxitem.hxx | 5 | ||||
-rw-r--r-- | sc/inc/markdata.hxx | 15 | ||||
-rw-r--r-- | sc/source/core/data/document.cxx | 80 | ||||
-rw-r--r-- | sc/source/core/data/markdata.cxx | 267 | ||||
-rw-r--r-- | sc/source/ui/inc/undoblk.hxx | 4 | ||||
-rw-r--r-- | sc/source/ui/undo/undoblk3.cxx | 8 | ||||
-rw-r--r-- | sc/source/ui/view/viewfunc.cxx | 22 |
11 files changed, 499 insertions, 16 deletions
diff --git a/cui/source/inc/border.hxx b/cui/source/inc/border.hxx index 81fee6486a53..ba780e1aa41a 100644 --- a/cui/source/inc/border.hxx +++ b/cui/source/inc/border.hxx @@ -98,6 +98,7 @@ private: VclPtr<CheckBox> m_pMergeWithNextCB; // #i29550# VclPtr<CheckBox> m_pMergeAdjacentBordersCB; + VclPtr<CheckBox> m_pRemoveAdjcentCellBordersCB; ImageList aShadowImgLstH; ImageList aShadowImgLst; @@ -113,6 +114,8 @@ private: bool mbBLTREnabled; ///< true = Bottom-left to top-right border enabled. bool mbUseMarginItem; bool mbSync; + bool mbRemoveAdjacentCellBorders; + bool bIsCalcDoc; std::set<sal_Int16> maUsedBorderStyles; @@ -125,6 +128,7 @@ private: DECL_LINK_TYPED( ModifyDistanceHdl_Impl, Edit&, void); DECL_LINK_TYPED( ModifyWidthHdl_Impl, Edit&, void); DECL_LINK_TYPED( SyncHdl_Impl, Button*, void); + DECL_LINK_TYPED( RemoveAdjacentCellBorderHdl_Impl, Button*, void); sal_uInt16 GetPresetImageId( sal_uInt16 nValueSetIdx ) const; sal_uInt16 GetPresetStringId( sal_uInt16 nValueSetIdx ) const; @@ -142,6 +146,7 @@ private: bool bValid ); bool IsBorderLineStyleAllowed( sal_Int16 nStyle ) const; + void UpdateRemoveAdjCellBorderCB( sal_uInt16 nPreset ); }; diff --git a/cui/source/tabpages/border.cxx b/cui/source/tabpages/border.cxx index 180fd28238b2..a4853ba56fa8 100644 --- a/cui/source/tabpages/border.cxx +++ b/cui/source/tabpages/border.cxx @@ -44,10 +44,13 @@ #include <svl/int64item.hxx> #include <sfx2/itemconnect.hxx> #include <sal/macros.h> +#include <com/sun/star/lang/XServiceInfo.hpp> #include "borderconn.hxx" using namespace ::editeng; - +using ::com::sun::star::uno::Reference; +using ::com::sun::star::lang::XServiceInfo; +using ::com::sun::star::uno::UNO_QUERY; /* @@ -99,7 +102,9 @@ SvxBorderTabPage::SvxBorderTabPage(vcl::Window* pParent, const SfxItemSet& rCore mbTLBREnabled( false ), mbBLTREnabled( false ), mbUseMarginItem( false ), - mbSync(true) + mbSync(true), + mbRemoveAdjacentCellBorders( false ), + bIsCalcDoc( false ) { get(m_pWndPresets, "presets"); @@ -130,6 +135,7 @@ SvxBorderTabPage::SvxBorderTabPage(vcl::Window* pParent, const SfxItemSet& rCore get(m_pPropertiesFrame, "properties"); get(m_pMergeWithNextCB, "mergewithnext"); get(m_pMergeAdjacentBordersCB, "mergeadjacent"); + get(m_pRemoveAdjcentCellBordersCB, "rmadjcellborders"); if ( GetDPIScaleFactor() > 1 ) { @@ -331,6 +337,21 @@ SvxBorderTabPage::SvxBorderTabPage(vcl::Window* pParent, const SfxItemSet& rCore // checkbox "Merge adjacent line styles" only visible for Writer dialog format.table AddItemConnection( new sfx::CheckBoxConnection( SID_SW_COLLAPSING_BORDERS, *m_pMergeAdjacentBordersCB, sfx::ITEMCONN_DEFAULT ) ); m_pMergeAdjacentBordersCB->Hide(); + + if( pDocSh ) + { + Reference< XServiceInfo > xSI( pDocSh->GetModel(), UNO_QUERY ); + if ( xSI.is() ) + bIsCalcDoc = xSI->supportsService("com.sun.star.sheet.SpreadsheetDocument"); + } + if( bIsCalcDoc ) + { + m_pRemoveAdjcentCellBordersCB->SetClickHdl(LINK(this, SvxBorderTabPage, RemoveAdjacentCellBorderHdl_Impl)); + m_pRemoveAdjcentCellBordersCB->Show(); + m_pRemoveAdjcentCellBordersCB->Enable( false ); + } + else + m_pRemoveAdjcentCellBordersCB->Hide(); } SvxBorderTabPage::~SvxBorderTabPage() @@ -365,6 +386,7 @@ void SvxBorderTabPage::dispose() m_pPropertiesFrame.clear(); m_pMergeWithNextCB.clear(); m_pMergeAdjacentBordersCB.clear(); + m_pRemoveAdjcentCellBordersCB.clear(); SfxTabPage::dispose(); } @@ -596,6 +618,10 @@ void SvxBorderTabPage::Reset( const SfxItemSet* rSet ) else mbSync = false; m_pSynchronizeCB->Check(mbSync); + + mbRemoveAdjacentCellBorders = false; + m_pRemoveAdjcentCellBordersCB->Check( false ); + m_pRemoveAdjcentCellBordersCB->Enable( false ); } void SvxBorderTabPage::ChangesApplied() @@ -645,6 +671,7 @@ bool SvxBorderTabPage::FillItemSet( SfxItemSet* rCoreAttrs ) aBoxItem.SetLine( m_pFrameSel->GetFrameBorderStyle( eTypes1[i].first ), eTypes1[i].second ); + aBoxItem.SetRemoveAdjacentCellBorder( mbRemoveAdjacentCellBorders ); // border hor/ver and TableFlag ::std::pair<svx::FrameBorderType,SvxBoxInfoItemLine> eTypes2[] = { @@ -843,6 +870,7 @@ IMPL_LINK_NOARG_TYPED(SvxBorderTabPage, SelPreHdl_Impl, ValueSet*, void) m_pWndPresets->SetNoSelection(); LinesChanged_Impl( nullptr ); + UpdateRemoveAdjCellBorderCB( nLine + 1 ); } @@ -1172,6 +1200,7 @@ IMPL_LINK_NOARG_TYPED(SvxBorderTabPage, LinesChanged_Impl, LinkParamNone*, void) m_pSynchronizeCB->Enable( m_pRightMF->IsEnabled() || m_pTopMF->IsEnabled() || m_pBottomMF->IsEnabled() || m_pLeftMF->IsEnabled() ); } + UpdateRemoveAdjCellBorderCB( -1 ); } @@ -1197,6 +1226,59 @@ IMPL_LINK_TYPED( SvxBorderTabPage, SyncHdl_Impl, Button*, pBox, void) mbSync = static_cast<CheckBox*>(pBox)->IsChecked(); } +IMPL_LINK_TYPED( SvxBorderTabPage, RemoveAdjacentCellBorderHdl_Impl, Button*, pBox, void) +{ + mbRemoveAdjacentCellBorders = static_cast<CheckBox*>(pBox)->IsChecked(); +} + +void SvxBorderTabPage::UpdateRemoveAdjCellBorderCB( sal_uInt16 nPreset ) +{ + if( !bIsCalcDoc ) + return; + const SfxItemSet& rOldSet = GetItemSet(); + const SvxBoxInfoItem* pOldBoxInfoItem = static_cast<const SvxBoxInfoItem*>(GetOldItem( rOldSet, SID_ATTR_BORDER_INNER )); + const SvxBoxItem* pOldBoxItem = static_cast<const SvxBoxItem*>(GetOldItem( rOldSet, SID_ATTR_BORDER_OUTER )); + if( !pOldBoxInfoItem || !pOldBoxItem ) + return; + ::std::pair<svx::FrameBorderType, SvxBoxInfoItemValidFlags> eTypes1[] = { + { svx::FRAMEBORDER_TOP,SvxBoxInfoItemValidFlags::TOP }, + { svx::FRAMEBORDER_BOTTOM,SvxBoxInfoItemValidFlags::BOTTOM }, + { svx::FRAMEBORDER_LEFT,SvxBoxInfoItemValidFlags::LEFT }, + { svx::FRAMEBORDER_RIGHT,SvxBoxInfoItemValidFlags::RIGHT }, + }; + SvxBoxItemLine eTypes2[] = { + SvxBoxItemLine::TOP, + SvxBoxItemLine::BOTTOM, + SvxBoxItemLine::LEFT, + SvxBoxItemLine::RIGHT, + }; + + // Check if current selection involves deletion of at least one border + bool bBorderDeletionReq = false; + for ( sal_uInt32 i=0; i < SAL_N_ELEMENTS( eTypes1 ); ++i ) + { + if( pOldBoxItem->GetLine( eTypes2[i] ) || !( pOldBoxInfoItem->IsValid( eTypes1[i].second ) ) ) + { + if( m_pFrameSel->GetFrameBorderState( eTypes1[i].first ) == svx::FRAMESTATE_HIDE ) + { + bBorderDeletionReq = true; + break; + } + } + } + + if( !bBorderDeletionReq && ( nPreset == IID_PRE_CELL_NONE || nPreset == IID_PRE_TABLE_NONE ) ) + bBorderDeletionReq = true; + + m_pRemoveAdjcentCellBordersCB->Enable( bBorderDeletionReq ); + + if( !bBorderDeletionReq ) + { + mbRemoveAdjacentCellBorders = false; + m_pRemoveAdjcentCellBordersCB->Check( false ); + } +} + void SvxBorderTabPage::DataChanged( const DataChangedEvent& rDCEvt ) { if( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) diff --git a/cui/uiconfig/ui/borderpage.ui b/cui/uiconfig/ui/borderpage.ui index 4e1943ea24c8..d25dbedfd65b 100644 --- a/cui/uiconfig/ui/borderpage.ui +++ b/cui/uiconfig/ui/borderpage.ui @@ -102,6 +102,20 @@ <property name="top_attach">1</property> </packing> </child> + <child> + <object class="GtkCheckButton" id="rmadjcellborders"> + <property name="label" translatable="yes">Remove border from adjacent cells as well</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">4</property> + </packing> + </child> </object> </child> </object> diff --git a/editeng/source/items/frmitems.cxx b/editeng/source/items/frmitems.cxx index 10211e45db97..69c18f3ea4db 100644 --- a/editeng/source/items/frmitems.cxx +++ b/editeng/source/items/frmitems.cxx @@ -1611,7 +1611,8 @@ SvxBoxItem::SvxBoxItem( const SvxBoxItem& rCpy ) : nTopDist ( rCpy.nTopDist ), nBottomDist ( rCpy.nBottomDist ), nLeftDist ( rCpy.nLeftDist ), - nRightDist ( rCpy.nRightDist ) + nRightDist ( rCpy.nRightDist ), + bRemoveAdjCellBorder ( rCpy.bRemoveAdjCellBorder ) { pTop = rCpy.GetTop() ? new SvxBorderLine( *rCpy.GetTop() ) : nullptr; @@ -1632,8 +1633,8 @@ SvxBoxItem::SvxBoxItem( const sal_uInt16 nId ) : nTopDist ( 0 ), nBottomDist ( 0 ), nLeftDist ( 0 ), - nRightDist ( 0 ) - + nRightDist ( 0 ), + bRemoveAdjCellBorder ( false ) { } @@ -1655,6 +1656,7 @@ SvxBoxItem& SvxBoxItem::operator=( const SvxBoxItem& rBox ) nBottomDist = rBox.nBottomDist; nLeftDist = rBox.nLeftDist; nRightDist = rBox.nRightDist; + bRemoveAdjCellBorder = rBox.bRemoveAdjCellBorder; SetLine( rBox.GetTop(), SvxBoxItemLine::TOP ); SetLine( rBox.GetBottom(), SvxBoxItemLine::BOTTOM ); SetLine( rBox.GetLeft(), SvxBoxItemLine::LEFT ); @@ -1685,6 +1687,7 @@ bool SvxBoxItem::operator==( const SfxPoolItem& rAttr ) const ( nBottomDist == rBoxItem.nBottomDist ) && ( nLeftDist == rBoxItem.nLeftDist ) && ( nRightDist == rBoxItem.nRightDist ) && + ( bRemoveAdjCellBorder == rBoxItem.bRemoveAdjCellBorder ) && CmpBrdLn( pTop, rBoxItem.GetTop() ) && CmpBrdLn( pBottom, rBoxItem.GetBottom() ) && CmpBrdLn( pLeft, rBoxItem.GetLeft() ) && diff --git a/include/editeng/boxitem.hxx b/include/editeng/boxitem.hxx index 7b1efd8de332..563a1b5711bb 100644 --- a/include/editeng/boxitem.hxx +++ b/include/editeng/boxitem.hxx @@ -60,6 +60,7 @@ class EDITENG_DLLPUBLIC SvxBoxItem : public SfxPoolItem nBottomDist, nLeftDist, nRightDist; + bool bRemoveAdjCellBorder; public: static SfxPoolItem* CreateDefault(); @@ -100,9 +101,13 @@ public: sal_uInt16 GetDistance( SvxBoxItemLine nLine ) const; sal_uInt16 GetDistance() const; + bool IsRemoveAdjacentCellBorder() const { return bRemoveAdjCellBorder; } + void SetDistance( sal_uInt16 nNew, SvxBoxItemLine nLine ); inline void SetDistance( sal_uInt16 nNew ); + void SetRemoveAdjacentCellBorder( bool bSet = true ) { bRemoveAdjCellBorder = bSet; } + // Line width plus Space plus inward distance // bIgnoreLine = TRUE -> Also return distance, when no Line is set sal_uInt16 CalcLineSpace( SvxBoxItemLine nLine, bool bIgnoreLine = false ) const; diff --git a/sc/inc/markdata.hxx b/sc/inc/markdata.hxx index 20777a69367f..6e3eafc3aee8 100644 --- a/sc/inc/markdata.hxx +++ b/sc/inc/markdata.hxx @@ -21,6 +21,7 @@ #define INCLUDED_SC_INC_MARKDATA_HXX #include "address.hxx" +#include "rangelst.hxx" #include "scdllapi.h" #include <set> @@ -55,6 +56,11 @@ private: bool bMarking:1; // area is being marked -> no MarkToMulti bool bMarkIsNeg:1; // cancel if multi selection + ScRangeList aTopEnvelope; // list of ranges in the top envelope of the multi selection + ScRangeList aBottomEnvelope; // list of ranges in the bottom envelope of the multi selection + ScRangeList aLeftEnvelope; // list of ranges in the left envelope of the multi selection + ScRangeList aRightEnvelope; // list of ranges in the right envelope of the multi selection + public: ScMarkData(); @@ -122,6 +128,15 @@ public: void InsertTab( SCTAB nTab ); void DeleteTab( SCTAB nTab ); + // Generate envelopes if mutimarked and fills the passed ScRange object with + // the smallest range that includes the marked area plus its envelopes. + void GetSelectionCover( ScRange& rRange ); + // Get top, bottom, left and right envelopes + const ScRangeList& GetTopEnvelope() const { return aTopEnvelope; } + const ScRangeList& GetBottomEnvelope() const { return aBottomEnvelope; } + const ScRangeList& GetLeftEnvelope() const { return aLeftEnvelope; } + const ScRangeList& GetRightEnvelope() const { return aRightEnvelope; } + // iterators for table access typedef std::set<SCTAB>::iterator iterator; typedef std::set<SCTAB>::const_iterator const_iterator; diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 5225443475b2..129695ab12bb 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -5591,6 +5591,86 @@ void ScDocument::ApplySelectionFrame( const ScMarkData& rMark, } } } + if( pLineOuter && pLineOuter->IsRemoveAdjacentCellBorder() ) + { + SvxBoxItem aTmp0( *pLineOuter ); + aTmp0.SetLine( NULL, SvxBoxItemLine::TOP ); + aTmp0.SetLine( NULL, SvxBoxItemLine::BOTTOM ); + aTmp0.SetLine( NULL, SvxBoxItemLine::LEFT ); + aTmp0.SetLine( NULL, SvxBoxItemLine::RIGHT ); + SvxBoxItem aLeft( aTmp0 ); + SvxBoxItem aRight( aTmp0 ); + SvxBoxItem aTop( aTmp0 ); + SvxBoxItem aBottom( aTmp0 ); + + SvxBoxInfoItem aTmp1( *pLineInner ); + aTmp1.SetTable( false ); + aTmp1.SetLine( NULL, SvxBoxInfoItemLine::HORI ); + aTmp1.SetLine( NULL, SvxBoxInfoItemLine::VERT ); + aTmp1.SetValid( SvxBoxInfoItemValidFlags::ALL, false ); + aTmp1.SetValid( SvxBoxInfoItemValidFlags::DISTANCE, true ); + SvxBoxInfoItem aLeftInfo( aTmp1 ); + SvxBoxInfoItem aRightInfo( aTmp1 ); + SvxBoxInfoItem aTopInfo( aTmp1 ); + SvxBoxInfoItem aBottomInfo( aTmp1 ); + + if( pLineInner->IsValid( SvxBoxInfoItemValidFlags::TOP ) && !pLineOuter->GetTop() ) + aTopInfo.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, true ); + + if( pLineInner->IsValid( SvxBoxInfoItemValidFlags::BOTTOM ) && !pLineOuter->GetBottom() ) + aBottomInfo.SetValid( SvxBoxInfoItemValidFlags::TOP, true ); + + if( pLineInner->IsValid( SvxBoxInfoItemValidFlags::LEFT ) && !pLineOuter->GetLeft() ) + aLeftInfo.SetValid( SvxBoxInfoItemValidFlags::RIGHT, true ); + + if( pLineInner->IsValid( SvxBoxInfoItemValidFlags::RIGHT ) && !pLineOuter->GetRight() ) + aRightInfo.SetValid( SvxBoxInfoItemValidFlags::LEFT, true ); + + const ScRangeList& rRangeListTopEnvelope = rMark.GetTopEnvelope(); + const ScRangeList& rRangeListBottomEnvelope = rMark.GetBottomEnvelope(); + const ScRangeList& rRangeListLeftEnvelope = rMark.GetLeftEnvelope(); + const ScRangeList& rRangeListRightEnvelope = rMark.GetRightEnvelope(); + + ScMarkData::const_iterator itr1 = rMark.begin(), itrEnd1 = rMark.end(); + for ( ; itr1 != itrEnd1 && *itr1 < nMax; ++itr1 ) + { + if ( maTabs[*itr1] ) + { + size_t nEnvelopeRangeCount = rRangeListTopEnvelope.size(); + for ( size_t j=0; j < nEnvelopeRangeCount; j++ ) + { + const ScRange* pRange = rRangeListTopEnvelope[ j ]; + maTabs[*itr1]->ApplyBlockFrame( &aTop, &aTopInfo, + pRange->aStart.Col(), pRange->aStart.Row(), + pRange->aEnd.Col(), pRange->aEnd.Row() ); + } + nEnvelopeRangeCount = rRangeListBottomEnvelope.size(); + for ( size_t j=0; j < nEnvelopeRangeCount; j++ ) + { + const ScRange* pRange = rRangeListBottomEnvelope[ j ]; + maTabs[*itr1]->ApplyBlockFrame( &aBottom, &aBottomInfo, + pRange->aStart.Col(), pRange->aStart.Row(), + pRange->aEnd.Col(), pRange->aEnd.Row() ); + } + nEnvelopeRangeCount = rRangeListLeftEnvelope.size(); + for ( size_t j=0; j < nEnvelopeRangeCount; j++ ) + { + const ScRange* pRange = rRangeListLeftEnvelope[ j ]; + maTabs[*itr1]->ApplyBlockFrame( &aLeft, &aLeftInfo, + pRange->aStart.Col(), pRange->aStart.Row(), + pRange->aEnd.Col(), pRange->aEnd.Row() ); + } + nEnvelopeRangeCount = rRangeListRightEnvelope.size(); + for ( size_t j=0; j < nEnvelopeRangeCount; j++ ) + { + const ScRange* pRange = rRangeListRightEnvelope[ j ]; + maTabs[*itr1]->ApplyBlockFrame( &aRight, &aRightInfo, + pRange->aStart.Col(), pRange->aStart.Row(), + pRange->aEnd.Col(), pRange->aEnd.Row() ); + } + } + } + } } void ScDocument::ApplyFrameAreaTab( const ScRange& rRange, diff --git a/sc/source/core/data/markdata.cxx b/sc/source/core/data/markdata.cxx index 137a2e442ee7..b8eaac78d4c0 100644 --- a/sc/source/core/data/markdata.cxx +++ b/sc/source/core/data/markdata.cxx @@ -20,8 +20,10 @@ #include "markdata.hxx" #include "markarr.hxx" #include "rangelst.hxx" +#include "segmenttree.hxx" #include <columnspanset.hxx> #include <fstalgorithm.hxx> +#include <unordered_map> #include <osl/diagnose.h> @@ -40,7 +42,11 @@ ScMarkData::ScMarkData(const ScMarkData& rData) : maTabMarked( rData.maTabMarked ), aMarkRange( rData.aMarkRange ), aMultiRange( rData.aMultiRange ), - pMultiSel( nullptr ) + pMultiSel( nullptr ), + aTopEnvelope( rData.aTopEnvelope ), + aBottomEnvelope( rData.aBottomEnvelope ), + aLeftEnvelope( rData.aLeftEnvelope ), + aRightEnvelope( rData.aRightEnvelope ) { bMarked = rData.bMarked; bMultiMarked = rData.bMultiMarked; @@ -69,6 +75,10 @@ ScMarkData& ScMarkData::operator=(const ScMarkData& rData) bMultiMarked = rData.bMultiMarked; bMarking = rData.bMarking; bMarkIsNeg = rData.bMarkIsNeg; + aTopEnvelope = rData.aTopEnvelope; + aBottomEnvelope = rData.aBottomEnvelope; + aLeftEnvelope = rData.aLeftEnvelope; + aRightEnvelope = rData.aRightEnvelope; maTabMarked = rData.maTabMarked; @@ -94,6 +104,10 @@ void ScMarkData::ResetMark() bMarked = bMultiMarked = false; bMarking = bMarkIsNeg = false; + aTopEnvelope.RemoveAll(); + aBottomEnvelope.RemoveAll(); + aLeftEnvelope.RemoveAll(); + aRightEnvelope.RemoveAll(); } void ScMarkData::SetMarkArea( const ScRange& rRange ) @@ -553,6 +567,257 @@ void ScMarkData::DeleteTab( SCTAB nTab ) maTabMarked.swap(tabMarked); } +static void lcl_AddRanges(ScRange& rRangeDest, const ScRange& rNewRange ) +{ + SCCOL nStartCol = rNewRange.aStart.Col(); + SCROW nStartRow = rNewRange.aStart.Row(); + SCCOL nEndCol = rNewRange.aEnd.Col(); + SCROW nEndRow = rNewRange.aEnd.Row(); + PutInOrder( nStartRow, nEndRow ); + PutInOrder( nStartCol, nEndCol ); + if ( nStartCol < rRangeDest.aStart.Col() ) + rRangeDest.aStart.SetCol( nStartCol ); + if ( nStartRow < rRangeDest.aStart.Row() ) + rRangeDest.aStart.SetRow( nStartRow ); + if ( nEndCol > rRangeDest.aEnd.Col() ) + rRangeDest.aEnd.SetCol( nEndCol ); + if ( nEndRow > rRangeDest.aEnd.Row() ) + rRangeDest.aEnd.SetRow( nEndRow ); +} + +void ScMarkData::GetSelectionCover( ScRange& rRange ) +{ + if( bMultiMarked ) + { + rRange = aMultiRange; + SCCOL nStartCol = aMultiRange.aStart.Col(), nEndCol = aMultiRange.aEnd.Col(); + PutInOrder( nStartCol, nEndCol ); + nStartCol = ( nStartCol == 0 ) ? nStartCol : nStartCol - 1; + nEndCol = ( nEndCol == MAXCOL ) ? nEndCol : nEndCol + 1; + std::unique_ptr<ScFlatBoolRowSegments> pPrevColMarkedRows; + std::unique_ptr<ScFlatBoolRowSegments> pCurColMarkedRows; + std::unordered_map<SCROW,ScFlatBoolColSegments> aRowToColSegmentsInTopEnvelope; + std::unordered_map<SCROW,ScFlatBoolColSegments> aRowToColSegmentsInBottomEnvelope; + ScFlatBoolRowSegments aNoRowsMarked; + aNoRowsMarked.setFalse( 0, MAXROW ); + + const ScMarkArray* pArray = pMultiSel; + bool bPrevColUnMarked = false; + + for ( SCCOL nCol=nStartCol; nCol <= nEndCol; nCol++ ) + { + SCROW nTop, nBottom; + bool bCurColUnMarked = !pArray[nCol].HasMarks(); + if ( !bCurColUnMarked ) + { + pCurColMarkedRows.reset( new ScFlatBoolRowSegments() ); + pCurColMarkedRows->setFalse( 0, MAXROW ); + ScMarkArrayIter aMarkIter( pArray + nCol ); + ScFlatBoolRowSegments::ForwardIterator aPrevItr ( pPrevColMarkedRows.get() ? *pPrevColMarkedRows : aNoRowsMarked ); // For finding left envelope + ScFlatBoolRowSegments::ForwardIterator aPrevItr1( pPrevColMarkedRows.get() ? *pPrevColMarkedRows : aNoRowsMarked ); // For finding right envelope + SCROW nTopPrev = 0, nBottomPrev = 0; // For right envelope + while ( aMarkIter.Next( nTop, nBottom ) ) + { + pCurColMarkedRows->setTrue( nTop, nBottom ); + if( bPrevColUnMarked && ( nCol > nStartCol )) + { + ScRange aAddRange(nCol - 1, nTop, aMultiRange.aStart.Tab(), + nCol - 1, nBottom, aMultiRange.aStart.Tab()); + lcl_AddRanges( rRange, aAddRange ); // Left envelope + aLeftEnvelope.Append( aAddRange ); + } + else if( nCol > nStartCol ) + { + SCROW nTop1 = nTop, nBottom1 = nTop; + while( nTop1 <= nBottom && nBottom1 <= nBottom ) + { + bool bRangeMarked = false; + aPrevItr.getValue( nTop1, bRangeMarked ); + if( bRangeMarked ) + { + nTop1 = aPrevItr.getLastPos() + 1; + nBottom1 = nTop1; + } + else + { + nBottom1 = aPrevItr.getLastPos(); + if( nBottom1 > nBottom ) + nBottom1 = nBottom; + ScRange aAddRange( nCol - 1, nTop1, aMultiRange.aStart.Tab(), + nCol - 1, nBottom1, aMultiRange.aStart.Tab() ); + lcl_AddRanges( rRange, aAddRange ); // Left envelope + aLeftEnvelope.Append( aAddRange ); + nTop1 = ++nBottom1; + } + } + while( nTopPrev <= nBottom && nBottomPrev <= nBottom ) + { + bool bRangeMarked; + aPrevItr1.getValue( nTopPrev, bRangeMarked ); + if( bRangeMarked ) + { + nBottomPrev = aPrevItr1.getLastPos(); + if( nTopPrev < nTop ) + { + if( nBottomPrev >= nTop ) + { + nBottomPrev = nTop - 1; + ScRange aAddRange( nCol, nTopPrev, aMultiRange.aStart.Tab(), + nCol, nBottomPrev, aMultiRange.aStart.Tab()); + lcl_AddRanges( rRange, aAddRange ); // Right envelope + aRightEnvelope.Append( aAddRange ); + nTopPrev = nBottomPrev = (nBottom + 1); + } + else + { + ScRange aAddRange( nCol, nTopPrev, aMultiRange.aStart.Tab(), + nCol, nBottomPrev, aMultiRange.aStart.Tab()); + lcl_AddRanges( rRange, aAddRange ); // Right envelope + aRightEnvelope.Append( aAddRange ); + nTopPrev = ++nBottomPrev; + } + } + else + nTopPrev = nBottomPrev = ( nBottom + 1 ); + } + else + { + nBottomPrev = aPrevItr1.getLastPos(); + nTopPrev = ++nBottomPrev; + } + } + } + if( nTop ) + { + ScRange aAddRange( nCol, nTop - 1, aMultiRange.aStart.Tab(), + nCol, nTop - 1, aMultiRange.aStart.Tab()); + lcl_AddRanges( rRange, aAddRange ); // Top envelope + aRowToColSegmentsInTopEnvelope[nTop - 1].setTrue( nCol, nCol ); + } + if( nBottom < MAXROW ) + { + ScRange aAddRange(nCol, nBottom + 1, aMultiRange.aStart.Tab(), + nCol, nBottom + 1, aMultiRange.aStart.Tab()); + lcl_AddRanges( rRange, aAddRange ); // Bottom envelope + aRowToColSegmentsInBottomEnvelope[nBottom + 1].setTrue( nCol, nCol ); + } + } + + while( nTopPrev <= MAXROW && nBottomPrev <= MAXROW && ( nCol > nStartCol ) ) + { + bool bRangeMarked; + aPrevItr1.getValue( nTopPrev, bRangeMarked ); + if( bRangeMarked ) + { + nBottomPrev = aPrevItr1.getLastPos(); + ScRange aAddRange(nCol, nTopPrev, aMultiRange.aStart.Tab(), + nCol, nBottomPrev, aMultiRange.aStart.Tab()); + lcl_AddRanges( rRange, aAddRange ); // Right envelope + aRightEnvelope.Append( aAddRange ); + nTopPrev = ++nBottomPrev; + } + else + { + nBottomPrev = aPrevItr1.getLastPos(); + nTopPrev = ++nBottomPrev; + } + } + } + else if( nCol > nStartCol ) + { + bPrevColUnMarked = true; + SCROW nTopPrev = 0, nBottomPrev = 0; + bool bRangeMarked = false; + ScFlatBoolRowSegments::ForwardIterator aPrevItr( pPrevColMarkedRows.get() ? *pPrevColMarkedRows : aNoRowsMarked ); + while( nTopPrev <= MAXROW && nBottomPrev <= MAXROW ) + { + aPrevItr.getValue(nTopPrev, bRangeMarked); + if( bRangeMarked ) + { + nBottomPrev = aPrevItr.getLastPos(); + ScRange aAddRange(nCol, nTopPrev, aMultiRange.aStart.Tab(), + nCol, nBottomPrev, aMultiRange.aStart.Tab()); + lcl_AddRanges( rRange, aAddRange ); // Right envelope + aRightEnvelope.Append( aAddRange ); + nTopPrev = ++nBottomPrev; + } + else + { + nBottomPrev = aPrevItr.getLastPos(); + nTopPrev = ++nBottomPrev; + } + } + } + if ( bCurColUnMarked ) + pPrevColMarkedRows.reset( nullptr ); + else + pPrevColMarkedRows.reset( pCurColMarkedRows.release() ); + } + for( auto& rKV : aRowToColSegmentsInTopEnvelope ) + { + SCCOL nStart = nStartCol; + ScFlatBoolColSegments::RangeData aRange; + while( nStart <= nEndCol ) + { + if( !rKV.second.getRangeData( nStart, aRange ) ) + break; + if( aRange.mbValue ) // is marked + aTopEnvelope.Append( ScRange( aRange.mnCol1, rKV.first, aMultiRange.aStart.Tab(), + aRange.mnCol2, rKV.first, aMultiRange.aStart.Tab() ) ); + nStart = aRange.mnCol2 + 1; + } + } + for( auto& rKV : aRowToColSegmentsInBottomEnvelope ) + { + SCCOL nStart = nStartCol; + ScFlatBoolColSegments::RangeData aRange; + while( nStart <= nEndCol ) + { + if( !rKV.second.getRangeData( nStart, aRange ) ) + break; + if( aRange.mbValue ) // is marked + aBottomEnvelope.Append( ScRange( aRange.mnCol1, rKV.first, aMultiRange.aStart.Tab(), + aRange.mnCol2, rKV.first, aMultiRange.aStart.Tab() ) ); + nStart = aRange.mnCol2 + 1; + } + } + } + else if( bMarked ) + { + aMarkRange.PutInOrder(); + SCROW nRow1, nRow2, nRow1New, nRow2New; + SCCOL nCol1, nCol2, nCol1New, nCol2New; + SCTAB nTab1, nTab2; + aMarkRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); + nCol1New = nCol1; + nCol2New = nCol2; + nRow1New = nRow1; + nRow2New = nRow2; + // Each envelope will have zero or more ranges for single rectangle selection. + if( nCol1 > 0 ) + { + aLeftEnvelope.Append( ScRange( nCol1 - 1, nRow1, nTab1, nCol1 - 1, nRow2, nTab2 ) ); + --nCol1New; + } + if( nRow1 > 0 ) + { + aTopEnvelope.Append( ScRange( nCol1, nRow1 - 1, nTab1, nCol2, nRow1 - 1, nTab2 ) ); + --nRow1New; + } + if( nCol2 < MAXCOL ) + { + aRightEnvelope.Append( ScRange( nCol2 + 1, nRow1, nTab1, nCol2 + 1, nRow2, nTab2 ) ); + ++nCol2New; + } + if( nRow2 < MAXROW ) + { + aBottomEnvelope.Append( ScRange( nCol1, nRow2 + 1, nTab1, nCol2, nRow2 + 1, nTab2 ) ); + ++nRow2New; + } + rRange = ScRange( nCol1New, nRow1New, nTab1, nCol2New, nRow2New, nTab2 ); + } +} + //iterators ScMarkData::iterator ScMarkData::begin() { diff --git a/sc/source/ui/inc/undoblk.hxx b/sc/source/ui/inc/undoblk.hxx index 2bafcdddfffb..3187163aefd3 100644 --- a/sc/source/ui/inc/undoblk.hxx +++ b/sc/source/ui/inc/undoblk.hxx @@ -322,7 +322,8 @@ public: ScDocument* pNewUndoDoc, bool bNewMulti, const ScPatternAttr* pNewApply, const SvxBoxItem* pNewOuter = nullptr, - const SvxBoxInfoItem* pNewInner = nullptr ); + const SvxBoxInfoItem* pNewInner = nullptr, + const ScRange* pRangeCover = nullptr ); virtual ~ScUndoSelectionAttr(); virtual void Undo() override; @@ -336,6 +337,7 @@ public: private: ScMarkData aMarkData; ScRange aRange; + ScRange aRangeCover; std::unique_ptr<ScEditDataArray> mpDataArray; ScDocument* pUndoDoc; bool bMulti; diff --git a/sc/source/ui/undo/undoblk3.cxx b/sc/source/ui/undo/undoblk3.cxx index f7e0e2846869..aa04576f6b90 100644 --- a/sc/source/ui/undo/undoblk3.cxx +++ b/sc/source/ui/undo/undoblk3.cxx @@ -349,7 +349,8 @@ ScUndoSelectionAttr::ScUndoSelectionAttr( ScDocShell* pNewDocShell, SCCOL nEndX, SCROW nEndY, SCTAB nEndZ, ScDocument* pNewUndoDoc, bool bNewMulti, const ScPatternAttr* pNewApply, - const SvxBoxItem* pNewOuter, const SvxBoxInfoItem* pNewInner ) + const SvxBoxItem* pNewOuter, const SvxBoxInfoItem* pNewInner, + const ScRange* pRangeCover ) : ScSimpleUndo( pNewDocShell ), aMarkData ( rMark ), aRange ( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ ), @@ -361,6 +362,7 @@ ScUndoSelectionAttr::ScUndoSelectionAttr( ScDocShell* pNewDocShell, pApplyPattern = const_cast<ScPatternAttr*>(static_cast<const ScPatternAttr*>( &pPool->Put( *pNewApply ) )); pLineOuter = pNewOuter ? const_cast<SvxBoxItem*>(static_cast<const SvxBoxItem*>( &pPool->Put( *pNewOuter ) )) : nullptr; pLineInner = pNewInner ? const_cast<SvxBoxInfoItem*>(static_cast<const SvxBoxInfoItem*>( &pPool->Put( *pNewInner ) )) : nullptr; + aRangeCover = pRangeCover ? *pRangeCover : aRange; } ScUndoSelectionAttr::~ScUndoSelectionAttr() @@ -392,7 +394,7 @@ void ScUndoSelectionAttr::DoChange( const bool bUndo ) SetViewMarkData( aMarkData ); - ScRange aEffRange( aRange ); + ScRange aEffRange( aRangeCover ); if ( rDoc.HasAttrib( aEffRange, HASATTR_MERGED ) ) // merged cells? rDoc.ExtendMerge( aEffRange ); @@ -403,7 +405,7 @@ void ScUndoSelectionAttr::DoChange( const bool bUndo ) if (bUndo) // only for Undo { - ScRange aCopyRange = aRange; + ScRange aCopyRange = aRangeCover; SCTAB nTabCount = rDoc.GetTableCount(); aCopyRange.aStart.SetTab(0); aCopyRange.aEnd.SetTab(nTabCount-1); diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx index ebcee5d1941c..cb140c8fca6c 100644 --- a/sc/source/ui/view/viewfunc.cxx +++ b/sc/source/ui/view/viewfunc.cxx @@ -1019,7 +1019,10 @@ void ScViewFunc::ApplyPatternLines( const ScPatternAttr& rAttr, const SvxBoxItem if (bRecord && !pDoc->IsUndoEnabled()) bRecord = false; - ScRange aMarkRange; + bool bRemoveAdjCellBorder = false; + if( pNewOuter ) + bRemoveAdjCellBorder = pNewOuter->IsRemoveAdjacentCellBorder(); + ScRange aMarkRange, aMarkRangeWithEnvelope; aFuncMark.MarkToSimple(); bool bMulti = aFuncMark.IsMultiMarked(); if (bMulti) @@ -1035,6 +1038,10 @@ void ScViewFunc::ApplyPatternLines( const ScPatternAttr& rAttr, const SvxBoxItem aFuncMark.SetMarkArea(aMarkRange); MarkDataChanged(); } + if( bRemoveAdjCellBorder ) + aFuncMark.GetSelectionCover( aMarkRangeWithEnvelope ); + else + aMarkRangeWithEnvelope = aMarkRange; ScDocShell* pDocSh = GetViewData().GetDocShell(); @@ -1045,31 +1052,34 @@ void ScViewFunc::ApplyPatternLines( const ScPatternAttr& rAttr, const SvxBoxItem ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); SCTAB nStartTab = aMarkRange.aStart.Tab(); SCTAB nTabCount = pDoc->GetTableCount(); + bool bCopyOnlyMarked = false; + if( !bRemoveAdjCellBorder ) + bCopyOnlyMarked = bMulti; pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab ); ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end(); for (; itr != itrEnd; ++itr) if (*itr != nStartTab) pUndoDoc->AddUndoTab( *itr, *itr ); - ScRange aCopyRange = aMarkRange; + ScRange aCopyRange = aMarkRangeWithEnvelope; aCopyRange.aStart.SetTab(0); aCopyRange.aEnd.SetTab(nTabCount-1); - pDoc->CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, bMulti, pUndoDoc, &aFuncMark ); + pDoc->CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, bCopyOnlyMarked, pUndoDoc, &aFuncMark ); pDocSh->GetUndoManager()->AddUndoAction( new ScUndoSelectionAttr( pDocSh, aFuncMark, aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), aMarkRange.aStart.Tab(), aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), aMarkRange.aEnd.Tab(), - pUndoDoc, bMulti, &rAttr, pNewOuter, pNewInner ) ); + pUndoDoc, bCopyOnlyMarked, &rAttr, pNewOuter, pNewInner, &aMarkRangeWithEnvelope ) ); } sal_uInt16 nExt = SC_PF_TESTMERGE; - pDocSh->UpdatePaintExt( nExt, aMarkRange ); // content before the change + pDocSh->UpdatePaintExt( nExt, aMarkRangeWithEnvelope ); // content before the change pDoc->ApplySelectionFrame( aFuncMark, pNewOuter, pNewInner ); - pDocSh->UpdatePaintExt( nExt, aMarkRange ); // content after the change + pDocSh->UpdatePaintExt( nExt, aMarkRangeWithEnvelope ); // content after the change aFuncMark.MarkToMulti(); pDoc->ApplySelectionPattern( rAttr, aFuncMark ); |