Commits

Eike Rathke [er]  committed 0ba1da2

calcdatatables: DataTable expansion and insertion/deletion of cells
* Expand DataTable range when inserting cells below/right of data rows/columns.
* Prevent DataTable corruption when attempting to insert/delete cells and
fragments of rows/columns of the table are chosen.

  • Participants
  • Parent commits b83ce4e

Comments (0)

Files changed (15)

File sc/inc/attarray.hxx

 
 	BOOL	TestInsertCol( SCROW nStartRow, SCROW nEndRow) const;
 	BOOL	TestInsertRow( SCSIZE nSize ) const;
-	void	InsertRow( SCROW nStartRow, SCSIZE nSize );
+	void	InsertRow( SCROW nStartRow, SCSIZE nSize, const ::std::vector<sal_uInt32> * pDataTables );
 	void	DeleteRow( SCROW nStartRow, SCSIZE nSize );
 	void	DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex );
 

File sc/inc/column.hxx

 
 	BOOL		TestInsertCol( SCROW nStartRow, SCROW nEndRow) const;
 	BOOL		TestInsertRow( SCSIZE nSize ) const;
-	void		InsertRow( SCROW nStartRow, SCSIZE nSize );
+	void		InsertRow( SCROW nStartRow, SCSIZE nSize, const ::std::vector<sal_uInt32> * pDataTables );
 	void		DeleteRow( SCROW nStartRow, SCSIZE nSize );
     void        DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex, USHORT nDelFlag );
     void        DeleteArea( SCROW nStartRow, SCROW nEndRow, USHORT nDelFlag,

File sc/inc/datatablestyle.hxx

         bool                        GetLastColFlag() const    { return mbLastCol; }
         bool                        GetBandedColsFlag() const { return mbBandedCols; }
 
+        SCROW                       GetFirstDataRow() const
+                                        { return mbHeaderRow ? maRange.aStart.Row() + 1 : maRange.aStart.Row(); }
+        SCROW                       GetLastDataRow() const
+                                        { return mbTotalRow ? maRange.aEnd.Row() - 1 : maRange.aEnd.Row(); }
+        bool                        IsExpandBottomRight( const ScRange& rRange, SCsCOL nDx, SCsROW nDy ) const;
+
         void                        InvalidateStyleSheetPointers();
         bool                        IsStyleSheetUsed( const ScStyleSheet& rStyle, bool bGatherAllStyles ) const;
         void                        InvalidateStyleSheet( const SfxStyleSheetBase* pStyleSheet, const String& rName );
         bool                        Equals( const ScDataTableFormat& rOther ) const;
         void                        UpdateReference( UpdateRefMode eUpdateRefMode,
-                                            const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
+                                                     const ScRange& rRange,
+                                                     SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
         void                        UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos );
         void                        RenameCellStyle( const String& rOld, const String& rNew );
                                     /// Is maRange completely covered by rRange?
         const ScDataTableFormat*    GetFormat( sal_uInt32 nKey ) const;
 
         void                        UpdateReference( UpdateRefMode eUpdateRefMode,
-                                        const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
+                                                     const ScRange& rRange,
+                                                     SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
         void                        UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos );
         void                        RenameCellStyle( const String& rOld, const String& rNew );
         bool                        IsStyleSheetUsed( const ScStyleSheet& rStyle, bool bGatherAllStyles ) const;
                                     /// Find all that are entirely covered by rRange.
         void                        FindInRange( ScDataTableMap & o_rDataTables, const ScRange& rRange ) const;
 
+        /** Find all that contain nRow entirely within nStartCol and nEndCol, 
+            or where inserting cells at nRow would result in an expanded 
+            DataTable. Additionally test whether cells can be inserted 
+            (shifting down) without destroying the table.
+
+            @param bTestOnly
+                   Only perform test for insertion of cells, do not gather 
+                   tables in o_rDataTables.
+
+            @returns TRUE if no DataTable contains only a fragment of nRow, 
+                     FALSE if at least one does.
+         */
+        bool                        FindInsertWithRow( ::std::vector<sal_uInt32> & o_rDataTables,
+                                                       SCCOL nStartCol, SCCOL nEndCol, SCROW nRow,
+                                                       const ::std::vector<SCTAB> & rTabs,
+                                                       bool bTestOnly ) const;
+
+        /** Find all that contain nCol entirely within nStartRow and nEndRow, 
+            or where inserting cells at nCol would result in an expanded 
+            DataTable. Additionally test whether cells can be inserted 
+            (shifting down) without destroying the table.
+
+            @param bTestOnly
+                   Only perform test for insertion of cells, do not gather 
+                   tables in o_rDataTables.
+
+            @returns TRUE if no DataTable contains only a fragment of nCol, 
+                     FALSE if at least one does.
+         */
+        bool                        FindInsertWithCol( ::std::vector<sal_uInt32> & o_rDataTables,
+                                                       SCROW nStartRow, SCROW nEndRow, SCCOL nCol,
+                                                       const ::std::vector<SCTAB> & rTabs,
+                                                       bool bTestOnly ) const;
+
+        /** Tests if no DataTable would result in fragmentation if nRow+nSize 
+            would be deleted within nStartCol and nEndCol.
+         */
+        bool                        TestDeleteRow( SCCOL nStartCol, SCCOL nEndCol,
+                                                   SCROW nRow, SCSIZE nSize,
+                                                   const ::std::vector<SCTAB> & rTabs) const;
+
+        /** Tests if no DataTable would result in fragmentation if nCol+nSize 
+            would be deleted within nStartRow and nEndRow.
+         */
+        bool                        TestDeleteCol( SCROW nStartRow, SCROW nEndRow,
+                                                   SCCOL nCol, SCSIZE nSize,
+                                                   const ::std::vector<SCTAB> & rTabs) const;
+
                                     /// For Ref-Undo
         bool                        operator==( const ScDataTableFormatList& rList ) const;
 };

File sc/inc/document.hxx

     ScDataTableFormatList*          GetDataTableFormatList() const { return pDataTableFormatList; }
     void                            SetDataTableFormatList( const ScDataTableFormatList& rList );
     sal_uInt32                      AddDataTableFormat( const ScDataTableFormat& rNew );
+	const ScDataTableFormat*        GetDataTableFormat( sal_uInt32 nKey ) const;
     SC_DLLPUBLIC const SfxItemSet*  GetDataTableItemSet( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt32 nKey = 0 ) const;
 
 	SC_DLLPUBLIC void			ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab,
     void            FindDataTablesInMarked( ScDataTableMap & o_rDataTables,
                                             const ScMarkData& rMark, SCTAB nTab = -1 ) const;
 
+                    /** Obtain DataTables containing nRowCol entirely with
+                        nStartColRow <= DataTableStartCol and
+                        DataTableEndCol <= nEndCol if bCol=false,
+                        or nRowCol entirely with
+                        nStartColRow <= DataTableStartRow and
+                        DataTableEndRow <= nEndColRow if bCol=true.
+
+                        @param pTabMark
+                               If not NULL, selected sheets, in which case 
+                               nStartTab and nEndTab are ignored.
+                               IF NULL, all nStartTab <= sheets <= nEndTab are 
+                               considered.
+
+                        @param bTestOnly
+                               Test only for insertion of cells without 
+                               gathering tables in o_rDataTables.
+
+                        @returns TRUE if cells can be inserted, FALSE if 
+                                 fragmentation was found.
+
+                        @see ScDataTableFormatList::FindInsertWithRow() and 
+                             ScDataTableFormatList::FindInsertWithCol()
+                     */
+    bool            FindDataTablesInsert( ::std::vector<sal_uInt32> & o_rDataTables,
+                                          SCCOLROW nStartColRow, SCCOLROW nEndColRow, SCCOLROW nRowCol,
+                                          SCTAB nStartTab, SCTAB nEndTab,
+                                          const ScMarkData* pTabMark, bool bCol, bool bTestOnly ) const;
+
+                    /** Tests for DataTable fragments affected by deletion.
+
+                        @returns TRUE if cells can be deleted, FALSE if 
+                                 fragmentation was found.
+                     */
+    bool            TestDataTablesDelete( SCCOLROW nStartColRow, SCCOLROW nEndColRow, SCCOLROW nRowCol,
+                                          SCSIZE nSize, SCTAB nStartTab, SCTAB nEndTab,
+                                          const ScMarkData* pTabMark, bool bCol ) const;
+
     SC_DLLPUBLIC void           SetColWidth( SCCOL nCol, SCTAB nTab, USHORT nNewWidth );
     SC_DLLPUBLIC void           SetRowHeight( SCROW nRow, SCTAB nTab, USHORT nNewHeight );
     SC_DLLPUBLIC void           SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab,

File sc/inc/table.hxx

     void        InitializeNoteCaptions( bool bForced = false );
 
 	BOOL		TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCSIZE nSize );
-	void		InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize );
+	void		InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize,
+                           const ::std::vector<sal_uInt32> * pDataTables );
 	void		DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize,
 							BOOL* pUndoOutline = NULL );
 

File sc/source/core/data/attarray.cxx

 }
 
 
-void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
+void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize, const ::std::vector<sal_uInt32> * pDataTables )
 {
 	if (!pData)
 		return;
 
-	SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0;		// Vorgaenger erweitern
+	SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0;		// expand predecessor
 	SCSIZE nIndex;
 	Search( nSearch, nIndex );
 
-	//	ein gesetztes ScMergeAttr darf nicht ausgedehnt werden
-	//	(darum hinterher wieder loeschen)
+    // If ScMergeAttr is set it must not be expanded, therefor remove 
+    // afterwards.
+	BOOL bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
 
-	BOOL bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
+    // DataTables are expanded only if listed and may have to be removed 
+    // afterwards.
+    sal_uInt32 nDataTable = static_cast<const SfxUInt32Item&>( 
+            pData[nIndex].pPattern->GetItem( ATTR_DATATABLE)).GetValue();
 
 	SCSIZE nRemove = 0;
 	SCSIZE i;
 	for (i = nIndex; i < nCount-1; i++)
 	{
 		SCROW nNew = pData[i].nRow + nSize;
-		if ( nNew >= MAXROW )					// Ende erreicht ?
+		if ( nNew >= MAXROW )					// end reached?
 		{
 			nNew = MAXROW;
 			if (!nRemove)
-				nRemove = i+1;					// folgende loeschen
+				nRemove = i+1;					// remove following
 		}
 		pData[i].nRow = nNew;
 	}
 
-	//	muessen Eintraege am Ende geloescht werden?
+    // Are entries to be deleted at the end?
 
 	if (nRemove && nRemove < nCount)
 		DeleteRange( nRemove, nCount-1 );
 
-	if (bDoMerge)			// ausgedehntes ScMergeAttr wieder reparieren
-	{
-			//!	ApplyAttr fuer Bereiche !!!
+    // If DataTable and not in list, remove all attributes and set default 
+    // pattern. Else proceed as usual.
+    if (nDataTable && (!pDataTables || find( pDataTables->begin(), 
+                    pDataTables->end(), nDataTable) == pDataTables->end()))
+        SetPatternArea( nStartRow, nStartRow+nSize-1, pDocument->GetDefPattern());
+    else
+    {
+        if (bDoMerge)			// repair expanded ScMergeAttr
+        {
+            /* TODO: ApplyAttr for ranges */
 
-		const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
-        for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
-            pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
+            const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
+            for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
+                pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
 
-		//	im eingefuegten Bereich ist nichts zusammengefasst
-	}
+            // Nothing merged in the range inserted.
+        }
 
-    // Don't duplicate the merge flags in the inserted row.
-    // #i108488# SC_MF_SCENARIO has to be allowed.
-    RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON );
+        // Don't duplicate the merge flags in the inserted row.
+        // #i108488# SC_MF_SCENARIO has to be allowed.
+        RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON );
+    }
 }
 
 

File sc/source/core/data/column.cxx

 }
 
 
-void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
+void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize, const ::std::vector<sal_uInt32> * pDataTables )
 {
-	pAttrArray->InsertRow( nStartRow, nSize );
+	pAttrArray->InsertRow( nStartRow, nSize, pDataTables );
 
 	//!	Search
 

File sc/source/core/data/datatablestyle.cxx

 }
 
 
+bool ScDataTableFormat::IsExpandBottomRight( const ScRange& rRange, SCsCOL nDx, SCsROW nDy ) const
+{
+    return ((nDx > 0 && rRange.aStart.Col() == maRange.aEnd.Col() + 1 && 
+                rRange.aStart.Row() <= maRange.aStart.Row() && 
+                maRange.aEnd.Row() <= rRange.aEnd.Row()) ||
+            (nDy > 0 && rRange.aStart.Row() == GetLastDataRow() + 1 && 
+                rRange.aStart.Col() <= maRange.aStart.Col() && 
+                maRange.aEnd.Col() <= rRange.aEnd.Col()));
+}
+
+
 void ScDataTableFormat::UpdateReference( UpdateRefMode eUpdateRefMode,
         const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
 {
     SCROW nRow1, nRow2;
     SCTAB nTab1, nTab2;
     maRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+    bool bExpandBottomRight = IsExpandBottomRight( rRange, nDx, nDy);
     ScRefUpdateRes eRes = ScRefUpdate::Update( mpDoc, eUpdateRefMode,
             rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
             rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
-            nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+            nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, bExpandBottomRight );
     if (eRes != UR_NOTHING)
         SetTableRange( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
 }
         }
     }
 }
+
+
+bool ScDataTableFormatList::FindInsertWithRow( ::std::vector<sal_uInt32> & o_rDataTables,
+        SCCOL nStartCol, SCCOL nEndCol, SCROW nRow, const ::std::vector<SCTAB> & rTabs,
+        bool bTestOnly ) const
+{
+    bool bNoFragment = true;
+    size_t nCount = Count();
+    for (size_t i=0; i < nCount && (!bTestOnly || bNoFragment); i++)
+    {
+        const ScDataTableFormat* pFormat = (*this)[i];
+        const ScRange& rRange = pFormat->GetTableRange();
+        if (!bTestOnly &&
+                rRange.aStart.Row() <= nRow && nRow <= pFormat->GetLastDataRow() + 1 &&
+                nStartCol <= rRange.aStart.Col() && rRange.aEnd.Col() <= nEndCol)
+        {
+            for (::std::vector<SCTAB>::const_iterator it( rTabs.begin());
+                    it != rTabs.end(); ++it)
+            {
+                if (rRange.aStart.Tab() == *it)
+                {
+                    sal_uInt32 nKey = pFormat->GetKey();
+                    o_rDataTables.push_back( nKey);
+                    break;  // for
+                }
+            }
+        }
+        else if (bNoFragment && nRow <= rRange.aEnd.Row() &&
+                ((rRange.aStart.Col() < nStartCol && nStartCol <= rRange.aEnd.Col()) ||
+                 (rRange.aStart.Col() <= nEndCol && nEndCol < rRange.aEnd.Col())))
+        {
+            for (::std::vector<SCTAB>::const_iterator it( rTabs.begin());
+                    it != rTabs.end(); ++it)
+            {
+                if (rRange.aStart.Tab() == *it)
+                {
+                    bNoFragment = false;
+                    break;  // for
+                }
+            }
+        }
+    }
+    return bNoFragment;
+}
+
+
+bool ScDataTableFormatList::FindInsertWithCol( ::std::vector<sal_uInt32> & o_rDataTables,
+        SCROW nStartRow, SCROW nEndRow, SCCOL nCol, const ::std::vector<SCTAB> & rTabs,
+        bool bTestOnly ) const
+{
+    bool bNoFragment = true;
+    size_t nCount = Count();
+    for (size_t i=0; i < nCount && (!bTestOnly || bNoFragment); i++)
+    {
+        const ScDataTableFormat* pFormat = (*this)[i];
+        const ScRange& rRange = pFormat->GetTableRange();
+        if (!bTestOnly &&
+                rRange.aStart.Col() <= nCol && nCol <= rRange.aEnd.Col() + 1 &&
+                nStartRow <= rRange.aStart.Row() && rRange.aEnd.Row() <= nEndRow)
+        {
+            for (::std::vector<SCTAB>::const_iterator it( rTabs.begin());
+                    it != rTabs.end(); ++it)
+            {
+                if (rRange.aStart.Tab() == *it)
+                {
+                    sal_uInt32 nKey = pFormat->GetKey();
+                    o_rDataTables.push_back( nKey);
+                    break;  // for
+                }
+            }
+        }
+        else if (bNoFragment && nCol <= rRange.aEnd.Col() &&
+                ((rRange.aStart.Row() < nStartRow && nStartRow <= rRange.aEnd.Row()) ||
+                 (rRange.aStart.Row() <= nEndRow && nEndRow < rRange.aEnd.Row())))
+        {
+            for (::std::vector<SCTAB>::const_iterator it( rTabs.begin());
+                    it != rTabs.end(); ++it)
+            {
+                if (rRange.aStart.Tab() == *it)
+                {
+                    bNoFragment = false;
+                    break;  // for
+                }
+            }
+        }
+    }
+    return bNoFragment;
+}
+
+
+bool ScDataTableFormatList::TestDeleteRow( SCCOL nStartCol, SCCOL nEndCol, 
+        SCROW nRow, SCSIZE nSize, const ::std::vector<SCTAB> & rTabs) const
+{
+    bool bNoFragment = true;
+    SCROW nEndRow = nRow + nSize - 1;
+    size_t nCount = Count();
+    for (size_t i=0; i < nCount && bNoFragment; i++)
+    {
+        const ScDataTableFormat* pFormat = (*this)[i];
+        const ScRange& rRange = pFormat->GetTableRange();
+        if (nRow <= rRange.aEnd.Row())
+        {
+            bool bShred =
+                ((rRange.aStart.Col() < nStartCol && nStartCol <= rRange.aEnd.Col()) ||
+                 (rRange.aStart.Col() <= nEndCol && nEndCol < rRange.aEnd.Col()));
+            if (!bShred)
+            {
+                // Deletion of header row or total row is not allowed if not 
+                // the entire table is to be deleted. Data rows only are fine.
+                if (pFormat->GetHeaderRowFlag())
+                    bShred = (nRow <= rRange.aStart.Row() && 
+                            rRange.aStart.Row() <= nEndRow && nEndRow < rRange.aEnd.Row());
+                if (!bShred && pFormat->GetTotalRowFlag())
+                    bShred = (rRange.aStart.Row() < nRow && rRange.aEnd.Row() <= nEndRow);
+            }
+            if (bShred)
+            {
+                for (::std::vector<SCTAB>::const_iterator it( rTabs.begin());
+                        it != rTabs.end(); ++it)
+                {
+                    if (rRange.aStart.Tab() == *it)
+                    {
+                        bNoFragment = false;
+                        break;  // for
+                    }
+                }
+            }
+        }
+    }
+    return bNoFragment;
+}
+
+
+bool ScDataTableFormatList::TestDeleteCol( SCROW nStartRow, SCROW nEndRow, 
+        SCCOL nCol, SCSIZE /* nSize */, const ::std::vector<SCTAB> & rTabs) const
+{
+    bool bNoFragment = true;
+    size_t nCount = Count();
+    for (size_t i=0; i < nCount && bNoFragment; i++)
+    {
+        const ScDataTableFormat* pFormat = (*this)[i];
+        const ScRange& rRange = pFormat->GetTableRange();
+        if (nCol <= rRange.aEnd.Col() &&
+                ((rRange.aStart.Row() < nStartRow && nStartRow <= rRange.aEnd.Row()) ||
+                 (rRange.aStart.Row() <= nEndRow && nEndRow < rRange.aEnd.Row())))
+        {
+            for (::std::vector<SCTAB>::const_iterator it( rTabs.begin());
+                    it != rTabs.end(); ++it)
+            {
+                if (rRange.aStart.Tab() == *it)
+                {
+                    bNoFragment = false;
+                    break;  // for
+                }
+            }
+        }
+    }
+    return bNoFragment;
+}

File sc/source/core/data/documen3.cxx

 				pCondFormList->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
 			if ( pValidationList )
 				pValidationList->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
+            // DataTables MUST be updated _after_ DBCollection because of IsExpandBottomRight()
 			if ( pDataTableFormatList )
 				pDataTableFormatList->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
 			if ( pDetOpList )

File sc/source/core/data/documen4.cxx

 	return nNewKey;
 }
 
+
+const ScDataTableFormat* ScDocument::GetDataTableFormat( sal_uInt32 nKey ) const
+{
+	if (nKey)
+	{
+		if (pDataTableFormatList)
+			return pDataTableFormatList->GetFormat( nKey );
+		else
+		{
+			DBG_ERROR("pDataTableFormatList is 0");
+		}
+	}
+	return NULL;
+}
+
+
 void ScDocument::SetDataTableFormatList( const ScDataTableFormatList& rList )
 {
 	if (!pDataTableFormatList)

File sc/source/core/data/document.cxx

 
 #include <map>
 #include <limits>
+#include <numeric>
 
 namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
 using ::com::sun::star::uno::Sequence;
 		if (pTab[i])
 			bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
 
+    if (bTest)
+    {
+        ::std::vector<sal_uInt32> aDataTables;
+        bTest = FindDataTablesInsert( aDataTables, nStartCol, nEndCol, 
+                nStartRow, nStartTab, nEndTab, NULL, false /*row*/, true /*testonly*/);
+    }
+
 	return bTest;
 }
 
 	for ( i = nStartTab; i <= nEndTab && bTest; i++)
         if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
 			bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
+
+    // Before references are updated, obtain DataTables before possibly being 
+    // expanded, and test for fragments.
+    ::std::vector<sal_uInt32> aDataTables;
+    if (bTest)
+        bTest = FindDataTablesInsert( aDataTables, nStartCol, nEndCol, 
+                nStartRow, nStartTab, nEndTab, pTabMark, false /*row*/, false /*nottestonly*/);
+
 	if (bTest)
 	{
-		// UpdateBroadcastAreas muss vor UpdateReference gerufen werden, damit nicht
-		// Eintraege verschoben werden, die erst bei UpdateReference neu erzeugt werden
+        const ::std::vector<sal_uInt32> * pDataTables = (aDataTables.size() ? &aDataTables : NULL);
+
+        // UpdateBroadcastAreas has to be called before UpdateReference in 
+        // order to not update entries that are created during UpdateReference.
 
         // handle chunks of consecutive selected sheets together
         SCTAB nTabRangeStart = nStartTab;
 
 		for (i=nStartTab; i<=nEndTab; i++)
             if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
-				pTab[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
+				pTab[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize, pDataTables );
 
 		//	#82991# UpdateRef for drawing layer must be after inserting,
 		//	when the new row heights are known.
 							0, static_cast<SCsROW>(nSize), 0 );
 
 		if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
+		{
+            // Because of references to deleted ranges being restored, a new 
+            // listening is due. Existing listeners were removed during 
+            // ScFormulaCell::UpdateReference().
+			StartAllListeners();
+		}
+		else
+        {   // Listeners have been removed in UpdateReference
+			for (i=0; i<=MAXTAB; i++)
+				if (pTab[i])
+                    pTab[i]->StartNeededListeners();
+            // #69592# at least all cells using range names pointing relative
+            // to the moved range must recalculate
+			for (i=0; i<=MAXTAB; i++)
+				if (pTab[i])
+					pTab[i]->SetRelNameDirty();
+		}
+		bRet = TRUE;
+	}
+	SetAutoCalc( bOldAutoCalc );
+	if ( bRet )
+		pChartListenerCollection->UpdateDirtyCharts();
+	return bRet;
+}
+
+
+BOOL ScDocument::InsertRow( const ScRange& rRange, ScDocument* pRefUndoDoc )
+{
+	return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
+					  rRange.aEnd.Col(),   rRange.aEnd.Tab(),
+					  rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
+					  pRefUndoDoc );
+}
+
+
+void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
+							SCCOL nEndCol,   SCTAB nEndTab,
+							SCROW nStartRow, SCSIZE nSize,
+                            ScDocument* pRefUndoDoc, BOOL* pUndoOutline,
+                            const ScMarkData* pTabMark )
+{
+	SCTAB i;
+
+	PutInOrder( nStartCol, nEndCol );
+	PutInOrder( nStartTab, nEndTab );
+	if ( pTabMark )
+	{
+	    nStartTab = 0;
+	    nEndTab = MAXTAB;
+	}
+
+    bool bTest = TestDataTablesDelete( nStartCol, nEndCol, nStartRow, nSize, 
+            nStartTab, nEndTab, pTabMark, false /*row*/);
+    if (!bTest)
+        /* FIXME: return value and UI needed */
+        return;
+
+	BOOL bOldAutoCalc = GetAutoCalc();
+	SetAutoCalc( FALSE );	// Mehrfachberechnungen vermeiden
+
+    // handle chunks of consecutive selected sheets together
+    SCTAB nTabRangeStart = nStartTab;
+    SCTAB nTabRangeEnd = nEndTab;
+    lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+    do
+    {
+        if ( ValidRow(nStartRow+nSize) )
+        {
+            DelBroadcastAreasInRange( ScRange(
+                ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+                ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
+            UpdateBroadcastAreas( URM_INSDEL, ScRange(
+                ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
+                ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, -(static_cast<SCsROW>(nSize)), 0 );
+        }
+        else
+            DelBroadcastAreasInRange( ScRange(
+                ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+                ScAddress( nEndCol, MAXROW, nTabRangeEnd ) ) );
+    }
+    while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+	if ( ValidRow(nStartRow+nSize) )
+	{
+        lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+        do
+        {
+            UpdateReference( URM_INSDEL, nStartCol, nStartRow+nSize, nTabRangeStart,
+                             nEndCol, MAXROW, nTabRangeEnd,
+                             0, -(static_cast<SCsROW>(nSize)), 0, pRefUndoDoc, TRUE, false );
+        }
+        while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+	}
+
+	if (pUndoOutline)
+		*pUndoOutline = FALSE;
+
+	for ( i = nStartTab; i <= nEndTab; i++)
+        if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+			pTab[i]->DeleteRow( nStartCol, nEndCol, nStartRow, nSize, pUndoOutline );
+
+	if ( ValidRow(nStartRow+nSize) )
+    {   // Listeners have been removed in UpdateReference
+		for (i=0; i<=MAXTAB; i++)
+			if (pTab[i])
+                pTab[i]->StartNeededListeners();
+        // #69592# at least all cells using range names pointing relative to
+        // the moved range must recalculate
+		for (i=0; i<=MAXTAB; i++)
+			if (pTab[i])
+				pTab[i]->SetRelNameDirty();
+	}
+
+	SetAutoCalc( bOldAutoCalc );
+	pChartListenerCollection->UpdateDirtyCharts();
+}
+
+
+void ScDocument::DeleteRow( const ScRange& rRange, ScDocument* pRefUndoDoc, BOOL* pUndoOutline )
+{
+	DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
+			   rRange.aEnd.Col(),   rRange.aEnd.Tab(),
+			   rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
+			   pRefUndoDoc, pUndoOutline );
+}
+
+
+BOOL ScDocument::CanInsertCol( const ScRange& rRange ) const
+{
+	SCCOL nStartCol = rRange.aStart.Col();
+	SCROW nStartRow = rRange.aStart.Row();
+	SCTAB nStartTab = rRange.aStart.Tab();
+	SCCOL nEndCol = rRange.aEnd.Col();
+	SCROW nEndRow = rRange.aEnd.Row();
+	SCTAB nEndTab = rRange.aEnd.Tab();
+	PutInOrder( nStartCol, nEndCol );
+	PutInOrder( nStartRow, nEndRow );
+	PutInOrder( nStartTab, nEndTab );
+	SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
+
+	BOOL bTest = TRUE;
+	for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
+		if (pTab[i])
+			bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
+
+    if (bTest)
+    {
+        ::std::vector<sal_uInt32> aDataTables;
+        bTest = FindDataTablesInsert( aDataTables, nStartRow, nEndRow, 
+                nStartCol, nStartTab, nEndTab, NULL, true /*col*/, true /*testonly*/);
+    }
+
+	return bTest;
+}
+
+
+BOOL ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
+							SCROW nEndRow,   SCTAB nEndTab,
+                            SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
+                            const ScMarkData* pTabMark )
+{
+	SCTAB i;
+
+	PutInOrder( nStartRow, nEndRow );
+	PutInOrder( nStartTab, nEndTab );
+	if ( pTabMark )
+	{
+	    nStartTab = 0;
+	    nEndTab = MAXTAB;
+	}
+
+	BOOL bTest = TRUE;
+	BOOL bRet = FALSE;
+	BOOL bOldAutoCalc = GetAutoCalc();
+	SetAutoCalc( FALSE );	// Mehrfachberechnungen vermeiden
+	for ( i = nStartTab; i <= nEndTab && bTest; i++)
+        if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+			bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
+
+    // Before references are updated, obtain DataTables before possibly being 
+    // expanded, and test for fragments.
+    ::std::vector<sal_uInt32> aDataTables;
+    if (bTest)
+        bTest = FindDataTablesInsert( aDataTables, nStartRow, nEndRow, 
+                nStartCol, nStartTab, nEndTab, pTabMark, true /*col*/, true /*testonly*/);
+
+	if (bTest)
+	{
+        // handle chunks of consecutive selected sheets together
+        SCTAB nTabRangeStart = nStartTab;
+        SCTAB nTabRangeEnd = nEndTab;
+        lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+        do
+        {
+            UpdateBroadcastAreas( URM_INSDEL, ScRange(
+                ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+                ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), static_cast<SCsCOL>(nSize), 0, 0 );
+        }
+        while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+        lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+        do
+        {
+            UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
+                             MAXCOL, nEndRow, nTabRangeEnd,
+                             static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc, TRUE, false );
+        }
+        while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+		for (i=nStartTab; i<=nEndTab; i++)
+            if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+				pTab[i]->InsertCol( nStartCol, nStartRow, nEndRow, nSize );
+
+		if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
 		{	// durch Restaurierung von Referenzen auf geloeschte Bereiche ist
 			// ein neues Listening faellig, bisherige Listener wurden in
 			// FormulaCell UpdateReference abgehaengt
 }
 
 
-BOOL ScDocument::InsertRow( const ScRange& rRange, ScDocument* pRefUndoDoc )
-{
-	return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
-					  rRange.aEnd.Col(),   rRange.aEnd.Tab(),
-					  rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
+BOOL ScDocument::InsertCol( const ScRange& rRange, ScDocument* pRefUndoDoc )
+{
+	return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
+					  rRange.aEnd.Row(),   rRange.aEnd.Tab(),
+					  rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
 					  pRefUndoDoc );
 }
 
 
-void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
-							SCCOL nEndCol,   SCTAB nEndTab,
-							SCROW nStartRow, SCSIZE nSize,
-                            ScDocument* pRefUndoDoc, BOOL* pUndoOutline,
-                            const ScMarkData* pTabMark )
-{
-	SCTAB i;
-
-	PutInOrder( nStartCol, nEndCol );
-	PutInOrder( nStartTab, nEndTab );
-	if ( pTabMark )
-	{
-	    nStartTab = 0;
-	    nEndTab = MAXTAB;
-	}
-
-	BOOL bOldAutoCalc = GetAutoCalc();
-	SetAutoCalc( FALSE );	// Mehrfachberechnungen vermeiden
-
-    // handle chunks of consecutive selected sheets together
-    SCTAB nTabRangeStart = nStartTab;
-    SCTAB nTabRangeEnd = nEndTab;
-    lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
-    do
-    {
-        if ( ValidRow(nStartRow+nSize) )
-        {
-            DelBroadcastAreasInRange( ScRange(
-                ScAddress( nStartCol, nStartRow, nTabRangeStart ),
-                ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
-            UpdateBroadcastAreas( URM_INSDEL, ScRange(
-                ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
-                ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, -(static_cast<SCsROW>(nSize)), 0 );
-        }
-        else
-            DelBroadcastAreasInRange( ScRange(
-                ScAddress( nStartCol, nStartRow, nTabRangeStart ),
-                ScAddress( nEndCol, MAXROW, nTabRangeEnd ) ) );
-    }
-    while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
-
-	if ( ValidRow(nStartRow+nSize) )
-	{
-        lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
-        do
-        {
-            UpdateReference( URM_INSDEL, nStartCol, nStartRow+nSize, nTabRangeStart,
-                             nEndCol, MAXROW, nTabRangeEnd,
-                             0, -(static_cast<SCsROW>(nSize)), 0, pRefUndoDoc, TRUE, false );
-        }
-        while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
-	}
-
-	if (pUndoOutline)
-		*pUndoOutline = FALSE;
-
-	for ( i = nStartTab; i <= nEndTab; i++)
-        if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
-			pTab[i]->DeleteRow( nStartCol, nEndCol, nStartRow, nSize, pUndoOutline );
-
-	if ( ValidRow(nStartRow+nSize) )
-    {   // Listeners have been removed in UpdateReference
-		for (i=0; i<=MAXTAB; i++)
-			if (pTab[i])
-                pTab[i]->StartNeededListeners();
-        // #69592# at least all cells using range names pointing relative to
-        // the moved range must recalculate
-		for (i=0; i<=MAXTAB; i++)
-			if (pTab[i])
-				pTab[i]->SetRelNameDirty();
-	}
-
-	SetAutoCalc( bOldAutoCalc );
-	pChartListenerCollection->UpdateDirtyCharts();
-}
-
-
-void ScDocument::DeleteRow( const ScRange& rRange, ScDocument* pRefUndoDoc, BOOL* pUndoOutline )
-{
-	DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
-			   rRange.aEnd.Col(),   rRange.aEnd.Tab(),
-			   rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
-			   pRefUndoDoc, pUndoOutline );
-}
-
-
-BOOL ScDocument::CanInsertCol( const ScRange& rRange ) const
-{
-	SCCOL nStartCol = rRange.aStart.Col();
-	SCROW nStartRow = rRange.aStart.Row();
-	SCTAB nStartTab = rRange.aStart.Tab();
-	SCCOL nEndCol = rRange.aEnd.Col();
-	SCROW nEndRow = rRange.aEnd.Row();
-	SCTAB nEndTab = rRange.aEnd.Tab();
-	PutInOrder( nStartCol, nEndCol );
-	PutInOrder( nStartRow, nEndRow );
-	PutInOrder( nStartTab, nEndTab );
-	SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
-
-	BOOL bTest = TRUE;
-	for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
-		if (pTab[i])
-			bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
-
-	return bTest;
-}
-
-
-BOOL ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
-							SCROW nEndRow,   SCTAB nEndTab,
-                            SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
-                            const ScMarkData* pTabMark )
+void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
+								SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
+                                BOOL* pUndoOutline, const ScMarkData* pTabMark )
 {
 	SCTAB i;
 
 	    nEndTab = MAXTAB;
 	}
 
-	BOOL bTest = TRUE;
-	BOOL bRet = FALSE;
-	BOOL bOldAutoCalc = GetAutoCalc();
-	SetAutoCalc( FALSE );	// Mehrfachberechnungen vermeiden
-	for ( i = nStartTab; i <= nEndTab && bTest; i++)
-        if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
-			bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
-	if (bTest)
-	{
-        // handle chunks of consecutive selected sheets together
-        SCTAB nTabRangeStart = nStartTab;
-        SCTAB nTabRangeEnd = nEndTab;
-        lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
-        do
-        {
-            UpdateBroadcastAreas( URM_INSDEL, ScRange(
-                ScAddress( nStartCol, nStartRow, nTabRangeStart ),
-                ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), static_cast<SCsCOL>(nSize), 0, 0 );
-        }
-        while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
-
-        lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
-        do
-        {
-            UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
-                             MAXCOL, nEndRow, nTabRangeEnd,
-                             static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc, TRUE, false );
-        }
-        while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
-
-		for (i=nStartTab; i<=nEndTab; i++)
-            if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
-				pTab[i]->InsertCol( nStartCol, nStartRow, nEndRow, nSize );
-
-		if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
-		{	// durch Restaurierung von Referenzen auf geloeschte Bereiche ist
-			// ein neues Listening faellig, bisherige Listener wurden in
-			// FormulaCell UpdateReference abgehaengt
-			StartAllListeners();
-		}
-		else
-        {   // Listeners have been removed in UpdateReference
-			for (i=0; i<=MAXTAB; i++)
-				if (pTab[i])
-                    pTab[i]->StartNeededListeners();
-            // #69592# at least all cells using range names pointing relative
-            // to the moved range must recalculate
-			for (i=0; i<=MAXTAB; i++)
-				if (pTab[i])
-					pTab[i]->SetRelNameDirty();
-		}
-		bRet = TRUE;
-	}
-	SetAutoCalc( bOldAutoCalc );
-	if ( bRet )
-		pChartListenerCollection->UpdateDirtyCharts();
-	return bRet;
-}
-
-
-BOOL ScDocument::InsertCol( const ScRange& rRange, ScDocument* pRefUndoDoc )
-{
-	return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
-					  rRange.aEnd.Row(),   rRange.aEnd.Tab(),
-					  rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
-					  pRefUndoDoc );
-}
-
-
-void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
-								SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
-                                BOOL* pUndoOutline, const ScMarkData* pTabMark )
-{
-	SCTAB i;
-
-	PutInOrder( nStartRow, nEndRow );
-	PutInOrder( nStartTab, nEndTab );
-	if ( pTabMark )
-	{
-	    nStartTab = 0;
-	    nEndTab = MAXTAB;
-	}
+    bool bTest = TestDataTablesDelete( nStartRow, nEndRow, nStartCol, nSize, 
+            nStartTab, nEndTab, pTabMark, true /*col*/);
+    if (!bTest)
+        /* FIXME: return value and UI needed */
+        return;
 
 	BOOL bOldAutoCalc = GetAutoCalc();
 	SetAutoCalc( FALSE );	// Mehrfachberechnungen vermeiden
 }
 
 
+bool ScDocument::FindDataTablesInsert( ::std::vector<sal_uInt32> & o_rDataTables,
+        SCCOLROW nStartColRow, SCCOLROW nEndColRow, SCCOLROW nRowCol,
+        SCTAB nStartTab, SCTAB nEndTab,
+        const ScMarkData* pTabMark, bool bCol, bool bTestOnly ) const
+{
+    if (pDataTableFormatList)
+    {
+        ::std::vector<SCTAB> aTabs;
+        if (pTabMark)
+        {
+            for (SCTAB nTab=0; nTab <= MAXTAB; ++nTab)
+                if (pTabMark->GetTableSelect( nTab))
+                    aTabs.push_back( nTab);
+        }
+        else
+        {
+            aTabs.reserve( nEndTab - nStartTab + 1);
+            iota( aTabs.begin(), aTabs.end(), nStartTab);
+        }
+        if (bCol)
+            return pDataTableFormatList->FindInsertWithCol( o_rDataTables, 
+                    static_cast<SCROW>(nStartColRow), 
+                    static_cast<SCROW>(nEndColRow), 
+                    static_cast<SCCOL>(nRowCol), aTabs, bTestOnly);
+        else
+            return pDataTableFormatList->FindInsertWithRow( o_rDataTables, 
+                    static_cast<SCCOL>(nStartColRow), 
+                    static_cast<SCCOL>(nEndColRow), 
+                    static_cast<SCROW>(nRowCol), aTabs, bTestOnly);
+    }
+    return true;
+}
+
+
+bool ScDocument::TestDataTablesDelete( SCCOLROW nStartColRow, SCCOLROW nEndColRow, SCCOLROW nRowCol,
+        SCSIZE nSize, SCTAB nStartTab, SCTAB nEndTab, const ScMarkData* pTabMark, bool bCol ) const
+{
+    if (pDataTableFormatList)
+    {
+        ::std::vector<SCTAB> aTabs;
+        if (pTabMark)
+        {
+            for (SCTAB nTab=0; nTab <= MAXTAB; ++nTab)
+                if (pTabMark->GetTableSelect( nTab))
+                    aTabs.push_back( nTab);
+        }
+        else
+        {
+            aTabs.reserve( nEndTab - nStartTab + 1);
+            iota( aTabs.begin(), aTabs.end(), nStartTab);
+        }
+        if (bCol)
+            return pDataTableFormatList->TestDeleteCol( 
+                    static_cast<SCROW>(nStartColRow), 
+                    static_cast<SCROW>(nEndColRow), 
+                    static_cast<SCCOL>(nRowCol), nSize, aTabs);
+        else
+            return pDataTableFormatList->TestDeleteRow(
+                    static_cast<SCCOL>(nStartColRow), 
+                    static_cast<SCCOL>(nEndColRow), 
+                    static_cast<SCROW>(nRowCol), nSize, aTabs);
+    }
+    return true;
+}
+
+
 ScPatternAttr* ScDocument::GetDefPattern() const
 {
 	return (ScPatternAttr*) &xPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN);

File sc/source/core/data/table2.cxx

 }
 
 
-void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize )
+void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize,
+        const ::std::vector<sal_uInt32> * pDataTables )
 {
 	IncRecalcLevel();
     InitializeNoteCaptions();
 	}
 
 	for (SCCOL j=nStartCol; j<=nEndCol; j++)
-		aCol[j].InsertRow( nStartRow, nSize );
+		aCol[j].InsertRow( nStartRow, nSize, pDataTables );
 	DecRecalcLevel( false );
 
     InvalidatePageBreaks();

File sc/source/core/inc/refupdat.hxx

 							SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
 							SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
 							SCCOL& theCol1, SCROW& theRow1, SCTAB& theTab1,
-							SCCOL& theCol2, SCROW& theRow2, SCTAB& theTab2 );
+							SCCOL& theCol2, SCROW& theRow2, SCTAB& theTab2,
+                            bool bExpandBottomRight = false );
 
 	static ScRefUpdateRes Update( UpdateRefMode eUpdateRefMode,
 								const ScBigRange& rWhere,
 								  UpdateRefMode eUpdateRefMode,
 								  const ScAddress& rPos, const ScRange& rRange,
 								  SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
-								  ScComplexRefData& rRef, WhatType eWhat = ALL );
+								  ScComplexRefData& rRef, WhatType eWhat = ALL,
+                                  bool bExpandBottomRight = false );
 
     /// Before calling, the absolute references must be up-to-date!
 	static ScRefUpdateRes Move( const ScDocument* pDoc, const ScAddress& rPos,

File sc/source/core/tool/dbcolect.cxx

 #include "rechead.hxx"
 #include "document.hxx"
 #include "queryparam.hxx"
+#include "datatablestyle.hxx"
 #include "globstr.hrc"
 
 
 		SCCOL theCol2;
 		SCROW theRow2;
 		SCTAB theTab2;
-		((ScDBData*)pItems[i])->GetArea( theTab1, theCol1, theRow1, theCol2, theRow2 );
+        ScDBData* pData = static_cast<ScDBData*>(pItems[i]);
+		pData->GetArea( theTab1, theCol1, theRow1, theCol2, theRow2 );
 		theTab2 = theTab1;
 
+        bool bExpandBottomRight = false;
+        if (nDx > 0 || nDy > 0)
+        {
+            sal_uInt32 nDataTable = pData->GetDataTable();
+            if (nDataTable)
+            {
+                const ScDataTableFormat* pDTab = pDoc->GetDataTableFormat( nDataTable);
+                if (pDTab)
+                    bExpandBottomRight = pDTab->IsExpandBottomRight(
+                            ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2), nDx, nDy);
+            }
+        }
+
 		BOOL bDoUpdate = ScRefUpdate::Update( pDoc, eUpdateRefMode,
 												nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
-                                                theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) != UR_NOTHING;
+                                                theCol1,theRow1,theTab1, theCol2,theRow2,theTab2,
+                                                bExpandBottomRight ) != UR_NOTHING;
 		if (bDoUpdate)
-			((ScDBData*)pItems[i])->MoveTo( theTab1, theCol1, theRow1, theCol2, theRow2 );
+			pData->MoveTo( theTab1, theCol1, theRow1, theCol2, theRow2 );
 
 		ScRange aAdvSource;
-		if ( ((ScDBData*)pItems[i])->GetAdvancedQuerySource(aAdvSource) )
+		if ( pData->GetAdvancedQuerySource(aAdvSource) )
 		{
 			aAdvSource.GetVars( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
 			if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
 			{
 				aAdvSource.aStart.Set( theCol1,theRow1,theTab1 );
 				aAdvSource.aEnd.Set( theCol2,theRow2,theTab2 );
-				((ScDBData*)pItems[i])->SetAdvancedQuerySource( &aAdvSource );
+				pData->SetAdvancedQuerySource( &aAdvSource );
 
 				bDoUpdate = TRUE;		// DBData is modified
 			}
 		}
 
-		((ScDBData*)pItems[i])->SetModified(bDoUpdate);
+		pData->SetModified(bDoUpdate);
 
 		//!		Testen, ob mitten aus dem Bereich geloescht/eingefuegt wurde !!!
 	}

File sc/source/core/tool/refupdat.cxx

 }
 
 template< typename R, typename S, typename U >
-BOOL IsExpand( R n1, R n2, U nStart, S nD )
-{	//! vor normalem Move...
-	return
-		nD > 0 			// Insert
-	 && n1 < n2			// mindestens zwei Cols/Rows/Tabs in Ref
-	 && (
-		(nStart <= n1 && n1 < nStart + nD)		// n1 innerhalb des Insert
-		|| (n2 + 1 == nStart)					// n2 direkt vor Insert
-		);		// n1 < nStart <= n2 wird sowieso expanded!
+BOOL IsExpand( R n1, R n2, U nStart, S nD, bool bBottomRightOnly )
+{   //! prior to normal Move...
+    return
+        nD > 0          // Insert
+     && n1 < n2         // at least two Cols/Rows/Tabs in Ref
+     && (
+        (!bBottomRightOnly && nStart <= n1 && n1 < nStart + nD)     // n1 within Insert
+        || (n2 + 1 == nStart)                                       // n2 immediately before Insert
+        );      // n1 < nStart <= n2 will be expanded anyway!
 }
 
 
 template< typename R, typename S, typename U >
-void Expand( R& n1, R& n2, U nStart, S nD )
-{	//! nach normalem Move..., nur wenn IsExpand vorher TRUE war!
-	//! erst das Ende
-	if ( n2 + 1 == nStart )
-	{	// am Ende
+void Expand( R& n1, R& n2, U nStart, S nD, bool bBottomRightOnly )
+{   //! after normal Move... only if IsExpand was TRUE before!
+    //! first the end
+    if ( n2 + 1 == nStart )
+    {   // at end
         n2 = sal::static_int_cast<R>( n2 + nD );
-		return;
-	}
-	// am Anfang
-    n1 = sal::static_int_cast<R>( n1 - nD );
+        return;
+    }
+    if (!bBottomRightOnly)
+        // at start
+        n1 = sal::static_int_cast<R>( n1 - nD );
 }
 
 
 										SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
 										SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
 										SCCOL& theCol1, SCROW& theRow1, SCTAB& theTab1,
-										SCCOL& theCol2, SCROW& theRow2, SCTAB& theTab2 )
+										SCCOL& theCol2, SCROW& theRow2, SCTAB& theTab2,
+                                        bool bExpandBottomRight )
 {
 	ScRefUpdateRes eRet = UR_NOTHING;
 
 
 	if (eUpdateRefMode == URM_INSDEL)
 	{
-		BOOL bExpand = pDoc->IsExpandRefs();
+		BOOL bExpand = (bExpandBottomRight || pDoc->IsExpandRefs());
 		if ( nDx && (theRow1 >= nRow1) && (theRow2 <= nRow2) &&
 					(theTab1 >= nTab1) && (theTab2 <= nTab2) )
 		{
-			BOOL bExp = (bExpand && IsExpand( theCol1, theCol2, nCol1, nDx ));
+			BOOL bExp = (bExpand && IsExpand( theCol1, theCol2, nCol1, nDx, bExpandBottomRight ));
 			bCut1 = lcl_MoveStart( theCol1, nCol1, nDx, MAXCOL );
 			bCut2 = lcl_MoveEnd( theCol2, nCol1, nDx, MAXCOL );
 			if ( theCol2 < theCol1 )
 				eRet = UR_UPDATED;
 			if ( bExp )
 			{
-				Expand( theCol1, theCol2, nCol1, nDx );
+				Expand( theCol1, theCol2, nCol1, nDx, bExpandBottomRight );
 				eRet = UR_UPDATED;
 			}
 		}
 		if ( nDy && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
 					(theTab1 >= nTab1) && (theTab2 <= nTab2) )
 		{
-			BOOL bExp = (bExpand && IsExpand( theRow1, theRow2, nRow1, nDy ));
+			BOOL bExp = (bExpand && IsExpand( theRow1, theRow2, nRow1, nDy, bExpandBottomRight ));
 			bCut1 = lcl_MoveStart( theRow1, nRow1, nDy, MAXROW );
 			bCut2 = lcl_MoveEnd( theRow2, nRow1, nDy, MAXROW );
 			if ( theRow2 < theRow1 )
 				eRet = UR_UPDATED;
 			if ( bExp )
 			{
-				Expand( theRow1, theRow2, nRow1, nDy );
+				Expand( theRow1, theRow2, nRow1, nDy, bExpandBottomRight );
 				eRet = UR_UPDATED;
 			}
 		}
 		{
 			SCsTAB nMaxTab = pDoc->GetTableCount() - 1;
             nMaxTab = sal::static_int_cast<SCsTAB>(nMaxTab + nDz);      // adjust to new count
-			BOOL bExp = (bExpand && IsExpand( theTab1, theTab2, nTab1, nDz ));
+			BOOL bExp = (bExpand && IsExpand( theTab1, theTab2, nTab1, nDz, bExpandBottomRight ));
 			bCut1 = lcl_MoveStart( theTab1, nTab1, nDz, static_cast<SCTAB>(nMaxTab) );
 			bCut2 = lcl_MoveEnd( theTab2, nTab1, nDz, static_cast<SCTAB>(nMaxTab) );
 			if ( theTab2 < theTab1 )
 				eRet = UR_UPDATED;
 			if ( bExp )
 			{
-				Expand( theTab1, theTab2, nTab1, nDz );
+				Expand( theTab1, theTab2, nTab1, nDz, bExpandBottomRight );
 				eRet = UR_UPDATED;
 			}
 		}
 ScRefUpdateRes ScRefUpdate::Update( const ScDocument* pDoc, UpdateRefMode eMode,
 									const ScAddress& rPos, const ScRange& r,
 									SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
-									ScComplexRefData& rRef, WhatType eWhat )
+									ScComplexRefData& rRef, WhatType eWhat,
+                                    bool bExpandBottomRight )
 {
 	ScRefUpdateRes eRet = UR_NOTHING;
 
 
 	if( eMode == URM_INSDEL )
 	{
-		BOOL bExpand = pDoc->IsExpandRefs();
+		BOOL bExpand = (bExpandBottomRight || pDoc->IsExpandRefs());
 
 		const ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
 		BOOL bInDeleteUndo =
 		   )
 		{
 			BOOL bExp = (bExpand && !bInDeleteUndo && IsExpand( rRef.Ref1.nCol,
-				rRef.Ref2.nCol, nCol1, nDx ));
+				rRef.Ref2.nCol, nCol1, nDx, bExpandBottomRight ));
             BOOL bDo1 = (eWhat == ScRefUpdate::ALL || (eWhat ==
                         ScRefUpdate::ABSOLUTE && !rRef.Ref1.IsColRel()));
             BOOL bDo2 = (eWhat == ScRefUpdate::ALL || (eWhat ==
 			}
 			if ( bExp )
 			{
-				Expand( rRef.Ref1.nCol, rRef.Ref2.nCol, nCol1, nDx );
+				Expand( rRef.Ref1.nCol, rRef.Ref2.nCol, nCol1, nDx, bExpandBottomRight );
 				eRet = UR_UPDATED;
 			}
 		}
 		   )
 		{
 			BOOL bExp = (bExpand && !bInDeleteUndo && IsExpand( rRef.Ref1.nRow,
-				rRef.Ref2.nRow, nRow1, nDy ));
+				rRef.Ref2.nRow, nRow1, nDy, bExpandBottomRight ));
             BOOL bDo1 = (eWhat == ScRefUpdate::ALL || (eWhat ==
                         ScRefUpdate::ABSOLUTE && !rRef.Ref1.IsRowRel()));
             BOOL bDo2 = (eWhat == ScRefUpdate::ALL || (eWhat ==
 			}
 			if ( bExp )
 			{
-				Expand( rRef.Ref1.nRow, rRef.Ref2.nRow, nRow1, nDy );
+				Expand( rRef.Ref1.nRow, rRef.Ref2.nRow, nRow1, nDy, bExpandBottomRight );
 				eRet = UR_UPDATED;
 			}
 		}
 		   )
 		{
 			BOOL bExp = (bExpand && !bInDeleteUndo && IsExpand( rRef.Ref1.nTab,
-				rRef.Ref2.nTab, nTab1, nDz ));
+				rRef.Ref2.nTab, nTab1, nDz, bExpandBottomRight ));
 			SCTAB nMaxTab = pDoc->GetTableCount() - 1;
             BOOL bDo1 = (eWhat == ScRefUpdate::ALL || (eWhat ==
                         ScRefUpdate::ABSOLUTE && !rRef.Ref1.IsTabRel()));
 			}
 			if ( bExp )
 			{
-				Expand( rRef.Ref1.nTab, rRef.Ref2.nTab, nTab1, nDz );
+				Expand( rRef.Ref1.nTab, rRef.Ref2.nTab, nTab1, nDz, bExpandBottomRight );
 				eRet = UR_UPDATED;
 			}
 		}