[Libreoffice-commits] core.git: cui/source cui/uiconfig editeng/source include/editeng sc/inc sc/source

Dennis Francis dennisfrancis.in at gmail.com
Mon Dec 7 05:50:16 PST 2015


 cui/source/inc/border.hxx         |    5 
 cui/source/tabpages/border.cxx    |   86 +++++++++++-
 cui/uiconfig/ui/borderpage.ui     |   14 +
 editeng/source/items/frmitems.cxx |    9 -
 include/editeng/boxitem.hxx       |    5 
 sc/inc/markdata.hxx               |   15 ++
 sc/source/core/data/document.cxx  |   80 +++++++++++
 sc/source/core/data/markdata.cxx  |  267 +++++++++++++++++++++++++++++++++++++-
 sc/source/ui/inc/undoblk.hxx      |    4 
 sc/source/ui/undo/undoblk3.cxx    |    8 -
 sc/source/ui/view/viewfunc.cxx    |   22 ++-
 11 files changed, 499 insertions(+), 16 deletions(-)

New commits:
commit 2e512174f2116d86682037459fd5ab5164e9f510
Author: Dennis Francis <dennisfrancis.in at gmail.com>
Date:   Sun Nov 1 03:49:38 2015 +0530

    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 at redhat.com>
    Tested-by: Eike Rathke <erack at 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 f7e0e28..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 );


More information about the Libreoffice-commits mailing list