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>
diff --git a/cui/source/inc/border.hxx b/cui/source/inc/border.hxx
index 81fee64..ba780e1 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 180fd28..a4853ba 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 4e1943e..d25dbed 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 10211e4..69c18f3 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 7b1efd8..563a1b5 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 20777a6..6e3eafc 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 5225443..129695a 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 137a2e4..b8eaac7 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 2bafcdd..3187163 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 f7e0e2846..aa04576 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 ebcee5d..cb140c8 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 );