Commits

Anonymous committed 7ba13f4

calcfilterrange: #i109553# #160403# for filters (AutoFilter, StandardFilter, AdvancedFilter) shrink selected area to used data area and expand single selected row down to end of data

Comments (0)

Files changed (19)

sc/inc/document.hxx

 
 	USHORT			GetErrCode( const ScAddress& ) const;
 
-    bool            ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const;
+                    /** Shrink a range to only include data area.
+                        This is not the actually used area within the 
+                        selection, but the bounds of the sheet's data area 
+                        instead. */
+    bool            ShrinkToDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow ) const;
+
+                    /** Shrink a range to only include used data area. */
+    bool            ShrinkToUsedDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const;
 
 	void			GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
-									SCCOL& rEndCol, SCROW& rEndRow, BOOL bIncludeOld );
+									SCCOL& rEndCol, SCROW& rEndRow, BOOL bIncludeOld, bool bOnlyDown );
 	SC_DLLPUBLIC BOOL			GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const;
 	SC_DLLPUBLIC BOOL			GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const;
 	SC_DLLPUBLIC BOOL			GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow,

sc/inc/global.hxx

 	SC_DB_OLD		// nicht neu anlegen
 };
 
+/// For ScDBFunc::GetDBData()
+enum ScGetDBSelection
+{
+    /** Keep selection as is, expand to used data area if no selection. */
+    SC_DBSEL_KEEP,
+
+    /** Shrink selection to sheet's data area. */
+    SC_DBSEL_SHRINK_TO_SHEET_DATA,
+
+    /** Shrink selection to actually used data area within the selection. */
+    SC_DBSEL_SHRINK_TO_USED_DATA,
+
+    /** If only one row or portion thereof is selected, shrink row to used data 
+        columns and select further rows down until end of data. If an area is 
+        selected, shrink rows to actually used columns. Else, no selection, 
+        expand to used data area. */
+    SC_DBSEL_ROW_DOWN,
+
+    /** Behave as if the range corresponding to a ScDBData area was selected, 
+        for API use. */
+    SC_DBSEL_FORCE_MARK
+};
+
 enum ScLkUpdMode
 {					//Verknuepfungen
 	LM_ALWAYS,		//immer aktualisieren
 						SCCOL nStartCol, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow );
 
 	void		GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow,
-								BOOL bIncludeOld );
+								BOOL bIncludeOld, bool bOnlyDown ) const;
+
+	bool		ShrinkToUsedDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const;
 
 	SCSIZE	    GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
 										SCCOL nEndCol, SCROW nEndRow, ScDirection eDir );

sc/source/core/data/document.cxx

     return true;  // success!
 }
 
+bool ScDocument::ShrinkToUsedDataArea( SCTAB nTab, SCCOL& rStartCol,
+        SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
+{
+    if (!ValidTab(nTab) || !pTab[nTab])
+        return false;
+    return pTab[nTab]->ShrinkToUsedDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly);
+}
+
 //	zusammenhaengender Bereich
 
 void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
-								SCCOL& rEndCol, SCROW& rEndRow, BOOL bIncludeOld )
+								SCCOL& rEndCol, SCROW& rEndRow, BOOL bIncludeOld, bool bOnlyDown )
 {
 	if (VALIDTAB(nTab))
 		if (pTab[nTab])
-			pTab[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld );
+			pTab[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
 }
 
 

sc/source/core/data/table1.cxx

 }
 
 void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow,
-							BOOL bIncludeOld )
+							BOOL bIncludeOld, bool bOnlyDown ) const
 {
 	BOOL bLeft       = FALSE;
 	BOOL bRight  = FALSE;
 	{
 		bChanged = FALSE;
 
-		SCROW nStart = rStartRow;
-		SCROW nEnd = rEndRow;
-		if (nStart>0) --nStart;
-		if (nEnd<MAXROW) ++nEnd;
+        if (!bOnlyDown)
+        {
+            SCROW nStart = rStartRow;
+            SCROW nEnd = rEndRow;
+            if (nStart>0) --nStart;
+            if (nEnd<MAXROW) ++nEnd;
 
-		if (rEndCol < MAXCOL)
-			if (!aCol[rEndCol+1].IsEmptyBlock(nStart,nEnd))
-			{
-				++rEndCol;
-				bChanged = TRUE;
-				bRight = TRUE;
-			}
+            if (rEndCol < MAXCOL)
+                if (!aCol[rEndCol+1].IsEmptyBlock(nStart,nEnd))
+                {
+                    ++rEndCol;
+                    bChanged = TRUE;
+                    bRight = TRUE;
+                }
 
-		if (rStartCol > 0)
-			if (!aCol[rStartCol-1].IsEmptyBlock(nStart,nEnd))
-			{
-				--rStartCol;
-				bChanged = TRUE;
-				bLeft = TRUE;
-			}
+            if (rStartCol > 0)
+                if (!aCol[rStartCol-1].IsEmptyBlock(nStart,nEnd))
+                {
+                    --rStartCol;
+                    bChanged = TRUE;
+                    bLeft = TRUE;
+                }
+
+            if (rStartRow > 0)
+            {
+                nTest = rStartRow-1;
+                bFound = FALSE;
+                for (i=rStartCol; i<=rEndCol && !bFound; i++)
+                    if (aCol[i].HasDataAt(nTest))
+                        bFound = TRUE;
+                if (bFound)
+                {
+                    --rStartRow;
+                    bChanged = TRUE;
+                    bTop = TRUE;
+                }
+            }
+        }
 
 		if (rEndRow < MAXROW)
 		{
 				bBottom = TRUE;
 			}
 		}
-
-		if (rStartRow > 0)
-		{
-			nTest = rStartRow-1;
-			bFound = FALSE;
-			for (i=rStartCol; i<=rEndCol && !bFound; i++)
-				if (aCol[i].HasDataAt(nTest))
-					bFound = TRUE;
-			if (bFound)
-			{
-				--rStartRow;
-				bChanged = TRUE;
-				bTop = TRUE;
-			}
-		}
 	}
 	while( bChanged );
 
 	}
 }
 
+
+bool ScTable::ShrinkToUsedDataArea( SCCOL& rStartCol, SCROW& rStartRow,
+        SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
+{
+    bool bRet = false;
+    bool bChanged;
+
+    do
+    {
+        bChanged = false;
+
+        bool bCont = true;
+        while (rEndCol > 0 && bCont && rStartCol < rEndCol)
+        {
+            if (aCol[rEndCol].IsEmptyBlock( rStartRow, rEndRow))
+            {
+                --rEndCol;
+                bChanged = true;
+            }
+            else
+                bCont = false;
+        }
+
+        bCont = true;
+        while (rStartCol < MAXCOL && bCont && rStartCol < rEndCol)
+        {
+            if (aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow))
+            {
+                ++rStartCol;
+                bChanged = true;
+            }
+            else
+                bCont = false;
+        }
+
+        if (!bColumnsOnly)
+        {
+            if (rStartRow < MAXROW && rStartRow < rEndRow)
+            {
+                bool bFound = false;
+                for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
+                    if (aCol[i].HasDataAt( rStartRow))
+                        bFound = true;
+                if (!bFound)
+                {
+                    ++rStartRow;
+                    bChanged = true;
+                }
+            }
+
+            if (rEndRow > 0 && rStartRow < rEndRow)
+            {
+                bool bFound = false;
+                for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
+                    if (aCol[i].HasDataAt( rEndRow))
+                        bFound = true;
+                if (!bFound)
+                {
+                    --rEndRow;
+                    bChanged = true;
+                }
+            }
+        }
+
+        if (bChanged)
+            bRet = true;
+    } while( bChanged );
+    return bRet;
+}
+
+
 SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
 										SCCOL nEndCol, SCROW nEndRow, ScDirection eDir )
 {

sc/source/core/tool/interpr4.cxx

                             (SCROW&) aRefData.Ref1.nRow,
                             (SCCOL&) aRefData.Ref2.nCol,
                             (SCROW&) aRefData.Ref2.nRow,
-                            TRUE );
+                            TRUE, false );
         // DataArea im Ursprung begrenzen
         aRefData.Ref1.nCol = nStartCol;
         aRefData.Ref1.nRow = nStartRow;

sc/source/ui/docshell/dbdocfun.cxx

 		if (pDestData)
 			pNewData = pDestData;				// Bereich vorhanden -> anpassen
 		else									// Bereich ab Cursor/Markierung wird angelegt
-			pNewData = rDocShell.GetDBData(aDestPos, SC_DB_MAKE, TRUE );
+			pNewData = rDocShell.GetDBData(aDestPos, SC_DB_MAKE, SC_DBSEL_FORCE_MARK );
 		if (pNewData)
 		{
 			pNewData->SetArea( nTab,
 			pNewData = rDocShell.GetDBData(
 							ScRange( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
 									 aLocalParam.nCol2, aLocalParam.nRow2, nDestTab ),
-							SC_DB_MAKE, TRUE );
+							SC_DB_MAKE, SC_DBSEL_FORCE_MARK );
 
 		if (pNewData)
 		{

sc/source/ui/docshell/dbdocimp.cxx

 		//	create database range
 		//!	merge this with SID_SBA_IMPORT execute in docsh4.cxx
 
-		ScDBData* pDBData = rDocShell.GetDBData( ScRange(rPos), SC_DB_IMPORT, FALSE );
+		ScDBData* pDBData = rDocShell.GetDBData( ScRange(rPos), SC_DB_IMPORT, SC_DBSEL_KEEP );
 		DBG_ASSERT(pDBData, "can't create DB data");
 		String sTarget = pDBData->GetName();
 

sc/source/ui/docshell/docsh4.cxx

 								GetUndoManager()->EnterListAction( aStrImport, aStrImport );
 							}
 
-							ScDBData* pDBData = GetDBData( ScRange(aPos), SC_DB_IMPORT, FALSE );
+							ScDBData* pDBData = GetDBData( ScRange(aPos), SC_DB_IMPORT, SC_DBSEL_KEEP );
 							DBG_ASSERT(pDBData, "kann DB-Daten nicht anlegen");
 							sTarget = pDBData->GetName();
 						}

sc/source/ui/docshell/docsh5.cxx

 	return pNoNameData;					// "unbenannt" nur zurueck, wenn sonst nichts gefunden
 }
 
-ScDBData* ScDocShell::GetDBData( const ScRange& rMarked, ScGetDBMode eMode, BOOL bForceMark )
+ScDBData* ScDocShell::GetDBData( const ScRange& rMarked, ScGetDBMode eMode, ScGetDBSelection eSel )
 {
 	SCCOL nCol = rMarked.aStart.Col();
 	SCROW nRow = rMarked.aStart.Row();
 	if (!pData)
 		pData = lcl_GetDBNearCursor( aDocument.GetDBCollection(), nCol, nRow, nTab );
 
-	BOOL bSelected = ( bForceMark || rMarked.aStart != rMarked.aEnd );
+	BOOL bSelected = ( eSel == SC_DBSEL_FORCE_MARK ||
+            (rMarked.aStart != rMarked.aEnd && eSel != SC_DBSEL_ROW_DOWN) );
+    bool bOnlyDown = (!bSelected && eSel == SC_DBSEL_ROW_DOWN && rMarked.aStart.Row() == rMarked.aEnd.Row());
 
 	BOOL bUseThis = FALSE;
 	if (pData)
 			bUseThis = TRUE;
 			if ( bIsNoName && eMode == SC_DB_MAKE )
 			{
-				//	wenn nichts markiert, "unbenannt" auf zusammenhaengenden Bereich anpassen
-				nStartCol = nCol;
-				nStartRow = nRow;
-				nEndCol = nStartCol;
-				nEndRow = nStartRow;
-				aDocument.GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, FALSE );
+                // If nothing marked or only one row marked, adapt 
+                // "unbenannt"/"unnamed" to contiguous area.
+                nStartCol = nCol;
+                nStartRow = nRow;
+                if (bOnlyDown)
+                {
+                    nEndCol = rMarked.aEnd.Col();
+                    nEndRow = rMarked.aEnd.Row();
+                }
+                else
+                {
+                    nEndCol = nStartCol;
+                    nEndRow = nStartRow;
+                }
+				aDocument.GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, FALSE, bOnlyDown );
 				if ( nOldCol1 != nStartCol || nOldCol2 != nEndCol || nOldRow1 != nStartRow )
 					bUseThis = FALSE;				// passt gar nicht
 				else if ( nOldRow2 != nEndRow )
 		{										// zusammenhaengender Bereich
 			nStartCol = nCol;
 			nStartRow = nRow;
-			nEndCol = nStartCol;
-			nEndRow = nStartRow;
-			aDocument.GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, FALSE );
+            if (bOnlyDown)
+            {
+                nEndCol = rMarked.aEnd.Col();
+                nEndRow = rMarked.aEnd.Row();
+            }
+            else
+            {
+                nEndCol = nStartCol;
+                nEndRow = nStartRow;
+            }
+			aDocument.GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, FALSE, bOnlyDown );
 		}
 
 		BOOL bHasHeader = aDocument.HasColHeader( nStartCol,nStartRow, nEndCol,nEndRow, nTab );

sc/source/ui/inc/dbfunc.hxx

 	void			GotoDBArea( const String& rDBName );
 
 					// DB-Bereich vom Cursor
-	ScDBData* 		GetDBData( BOOL bMarkArea = TRUE, ScGetDBMode eMode = SC_DB_MAKE, bool bShrinkToData = false );
+	ScDBData* 		GetDBData( BOOL bMarkArea = TRUE, ScGetDBMode eMode = SC_DB_MAKE, ScGetDBSelection eSel = SC_DBSEL_KEEP );
 
 	void			NotifyCloseDbNameDlg( const ScDBCollection& rNewColl, const List& rDelAreaList );
 

sc/source/ui/inc/docsh.hxx

 	BOOL			IsOle();
 
 	void			DBAreaDeleted( SCTAB nTab, SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2 );
-	ScDBData*		GetDBData( const ScRange& rMarked, ScGetDBMode eMode, BOOL bForceMark );
+	ScDBData*		GetDBData( const ScRange& rMarked, ScGetDBMode eMode, ScGetDBSelection eSel );
     ScDBData*       GetOldAutoDBRange();    // has to be deleted by caller!
     void            CancelAutoDBRange();    // called when dialog is cancelled
 

sc/source/ui/unoobj/cellsuno.cxx

 	if ( pDocSh )
 	{
 		// DB-Bereich anlegen erst beim Ausfuehren, per API immer genau den Bereich
-		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, TRUE );
+		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, SC_DBSEL_FORCE_MARK );
 		if (pData)
 		{
 			pData->GetSortParam(aParam);
 	{
 		USHORT i;
 		ScSortParam aParam;
-		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_MAKE, TRUE );	// ggf. Bereich anlegen
+		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_MAKE, SC_DBSEL_FORCE_MARK );	// ggf. Bereich anlegen
 		if (pData)
 		{
 			//	alten Einstellungen holen, falls nicht alles neu gesetzt wird
 		aParam.nCol2 = aRange.aEnd.Col();
 		aParam.nRow2 = aRange.aEnd.Row();
 
-		pDocSh->GetDBData( aRange, SC_DB_MAKE, TRUE );		// ggf. Bereich anlegen
+		pDocSh->GetDBData( aRange, SC_DB_MAKE, SC_DBSEL_FORCE_MARK );		// ggf. Bereich anlegen
 
 		ScDBDocFunc aFunc(*pDocSh);							// Bereich muss angelegt sein
 		aFunc.Sort( nTab, aParam, TRUE, TRUE, TRUE );
 	if ( !bEmpty && pDocSh )
 	{
 		// DB-Bereich anlegen erst beim Ausfuehren, per API immer genau den Bereich
-		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, TRUE );
+		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, SC_DBSEL_FORCE_MARK );
 		if (pData)
 		{
 			ScQueryParam aParam;
 		aParam.nCol2 = aRange.aEnd.Col();
 		aParam.nRow2 = aRange.aEnd.Row();
 
-		pDocSh->GetDBData( aRange, SC_DB_MAKE, TRUE );	// ggf. Bereich anlegen
+		pDocSh->GetDBData( aRange, SC_DB_MAKE, SC_DBSEL_FORCE_MARK );	// ggf. Bereich anlegen
 
 		//!	keep source range in filter descriptor
 		//!	if created by createFilterDescriptorByObject ???
 	if ( !bEmpty && pDocSh )
 	{
 		// DB-Bereich anlegen erst beim Ausfuehren, per API immer genau den Bereich
-		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, TRUE );
+		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, SC_DBSEL_FORCE_MARK );
 		if (pData)
 		{
 			ScSubTotalParam aParam;
 		aParam.nCol2 = aRange.aEnd.Col();
 		aParam.nRow2 = aRange.aEnd.Row();
 
-		pDocSh->GetDBData( aRange, SC_DB_MAKE, TRUE );	// ggf. Bereich anlegen
+		pDocSh->GetDBData( aRange, SC_DB_MAKE, SC_DBSEL_FORCE_MARK );	// ggf. Bereich anlegen
 
 		ScDBDocFunc aFunc(*pDocSh);
 		aFunc.DoSubTotals( nTab, aParam, NULL, TRUE, TRUE );	// Bereich muss angelegt sein
 	if (pDocSh)
 	{
 		ScSubTotalParam aParam;
-		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, TRUE );
+		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, SC_DBSEL_FORCE_MARK );
 		if (pData)
 			pData->GetSubTotalParam(aParam);	// auch bei Remove die Feld-Eintraege behalten
 
 		aParam.nCol2 = aRange.aEnd.Col();
 		aParam.nRow2 = aRange.aEnd.Row();
 
-		pDocSh->GetDBData( aRange, SC_DB_MAKE, TRUE );	// ggf. Bereich anlegen
+		pDocSh->GetDBData( aRange, SC_DB_MAKE, SC_DBSEL_FORCE_MARK );	// ggf. Bereich anlegen
 
 		ScDBDocFunc aFunc(*pDocSh);
 		aFunc.DoSubTotals( nTab, aParam, NULL, TRUE, TRUE );	// Bereich muss angelegt sein
 	if ( !bEmpty && pDocSh )
 	{
 		// DB-Bereich anlegen erst beim Ausfuehren, per API immer genau den Bereich
-		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, TRUE );
+		ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, SC_DBSEL_FORCE_MARK );
 		if (pData)
 			pData->GetImportParam(aParam);
 	}
         //! TODO: could we get passed a valid result set by any means?
         uno::Reference< sdbc::XResultSet > xResultSet;
 
-		pDocSh->GetDBData( aRange, SC_DB_MAKE, TRUE );		// ggf. Bereich anlegen
+		pDocSh->GetDBData( aRange, SC_DB_MAKE, SC_DBSEL_FORCE_MARK );		// ggf. Bereich anlegen
 
 		ScDBDocFunc aFunc(*pDocSh);							// Bereich muss angelegt sein
 		aFunc.DoImport( nTab, aParam, xResultSet, NULL, TRUE, FALSE );	//! Api-Flag als Parameter

sc/source/ui/unoobj/cursuno.cxx

 		SCTAB nTab = aOneRange.aStart.Tab();
 
 		pDocSh->GetDocument()->GetDataArea(
-						nTab, nStartCol, nStartRow, nEndCol, nEndRow, TRUE );
+						nTab, nStartCol, nStartRow, nEndCol, nEndRow, TRUE, false );
 
 		ScRange aNew( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
 		SetNewRange( aNew );
 		SCTAB nTab = aOneRange.aStart.Tab();
 
 		pDocSh->GetDocument()->GetDataArea(
-						nTab, nStartCol, nStartRow, nEndCol, nEndRow, FALSE );
+						nTab, nStartCol, nStartRow, nEndCol, nEndRow, FALSE, false );
 
 		ScRange aNew( nStartCol, nStartRow, nTab );
 		SetNewRange( aNew );
 		SCTAB nTab = aOneRange.aStart.Tab();
 
 		pDocSh->GetDocument()->GetDataArea(
-						nTab, nStartCol, nStartRow, nEndCol, nEndRow, FALSE );
+						nTab, nStartCol, nStartRow, nEndCol, nEndRow, FALSE, false );
 
 		ScRange aNew( nEndCol, nEndRow, nTab );
 		SetNewRange( aNew );

sc/source/ui/view/cellsh2.cxx

     SCCOL nStartCol = aExternalRange.aStart.Col();
     SCROW nEndRow   = aExternalRange.aEnd.Row();
     SCCOL nEndCol   = aExternalRange.aEnd.Col();
-    pDoc->GetDataArea( aExternalRange.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow, FALSE );
+    pDoc->GetDataArea( aExternalRange.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow, FALSE, false );
     aExternalRange.aStart.SetRow( nStartRow );
     aExternalRange.aStart.SetCol( nStartCol );
     aExternalRange.aEnd.SetRow( nEndRow );

sc/source/ui/view/dbfunc.cxx

 
 //	aktuellen Datenbereich fuer Sortieren / Filtern suchen
 
-ScDBData* ScDBFunc::GetDBData( BOOL bMark, ScGetDBMode eMode, bool bShrinkToData )
+ScDBData* ScDBFunc::GetDBData( BOOL bMark, ScGetDBMode eMode, ScGetDBSelection eSel )
 {
 	ScDocShell* pDocSh = GetViewData()->GetDocShell();
 	ScDBData* pData = NULL;
 	ScMarkType eMarkType = GetViewData()->GetSimpleArea(aRange);
 	if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
     {
-        if (bShrinkToData)
+        bool bShrinkColumnsOnly = false;
+        if (eSel == SC_DBSEL_ROW_DOWN)
         {
-            // Shrink the range to only include data area.
-            ScDocument* pDoc = pDocSh->GetDocument();
-            SCCOL nCol1 = aRange.aStart.Col(), nCol2 = aRange.aEnd.Col();
-            SCROW nRow1 = aRange.aStart.Row(), nRow2 = aRange.aEnd.Row();
-            if (pDoc->ShrinkToDataArea(aRange.aStart.Tab(), nCol1, nRow1, nCol2, nRow2))
+            // Don't alter row range, additional rows may have been selected on 
+            // purpose to append data, or to have a fake header row.
+            bShrinkColumnsOnly = true;
+            // Select further rows only if only one row or a portion thereof is 
+            // selected.
+            if (aRange.aStart.Row() != aRange.aEnd.Row())
             {
-                aRange.aStart.SetCol(nCol1);
-                aRange.aEnd.SetCol(nCol2);
-                aRange.aStart.SetRow(nRow1);
-                aRange.aEnd.SetRow(nRow2);
+                // If an area is selected shrink that to the actual used 
+                // columns, don't draw filter buttons for empty columns.
+                eSel = SC_DBSEL_SHRINK_TO_USED_DATA;
+            }
+            else if (aRange.aStart.Col() == aRange.aEnd.Col())
+            {
+                // One cell only, if it is not marked obtain entire used data 
+                // area.
+                const ScMarkData& rMarkData = GetViewData()->GetMarkData();
+                if (!(rMarkData.IsMarked() || rMarkData.IsMultiMarked()))
+                    eSel = SC_DBSEL_KEEP;
             }
         }
-		pData = pDocSh->GetDBData( aRange, eMode, FALSE );
+        switch (eSel)
+        {
+            case SC_DBSEL_SHRINK_TO_SHEET_DATA:
+                {
+                    // Shrink the selection to sheet data area.
+                    ScDocument* pDoc = pDocSh->GetDocument();
+                    SCCOL nCol1 = aRange.aStart.Col(), nCol2 = aRange.aEnd.Col();
+                    SCROW nRow1 = aRange.aStart.Row(), nRow2 = aRange.aEnd.Row();
+                    if (pDoc->ShrinkToDataArea( aRange.aStart.Tab(), nCol1, nRow1, nCol2, nRow2))
+                    {
+                        aRange.aStart.SetCol(nCol1);
+                        aRange.aEnd.SetCol(nCol2);
+                        aRange.aStart.SetRow(nRow1);
+                        aRange.aEnd.SetRow(nRow2);
+                    }
+                }
+                break;
+            case SC_DBSEL_SHRINK_TO_USED_DATA:
+            case SC_DBSEL_ROW_DOWN:
+                {
+                    // Shrink the selection to actual used area.
+                    ScDocument* pDoc = pDocSh->GetDocument();
+                    SCCOL nCol1 = aRange.aStart.Col(), nCol2 = aRange.aEnd.Col();
+                    SCROW nRow1 = aRange.aStart.Row(), nRow2 = aRange.aEnd.Row();
+                    if (pDoc->ShrinkToUsedDataArea( aRange.aStart.Tab(), nCol1, nRow1, nCol2, nRow2, bShrinkColumnsOnly))
+                    {
+                        aRange.aStart.SetCol(nCol1);
+                        aRange.aEnd.SetCol(nCol2);
+                        aRange.aStart.SetRow(nRow1);
+                        aRange.aEnd.SetRow(nRow2);
+                    }
+                }
+                break;
+            default:
+                ;   // nothing
+        }
+        pData = pDocSh->GetDBData( aRange, eMode, eSel );
     }
 	else if ( eMode != SC_DB_OLD )
 		pData = pDocSh->GetDBData(
 					ScRange( GetViewData()->GetCurX(), GetViewData()->GetCurY(),
 							 GetViewData()->GetTabNo() ),
-					eMode, FALSE );
+					eMode, SC_DBSEL_KEEP );
 
 	if ( pData && bMark )
 	{
 
 	ScQueryParam	aParam;
 	ScDocument*		pDoc	= GetViewData()->GetDocument();
-	ScDBData*		pDBData = GetDBData( FALSE );
+	ScDBData*		pDBData = GetDBData( FALSE, SC_DB_MAKE, SC_DBSEL_ROW_DOWN );
 
 	pDBData->SetByRow( TRUE );				//! Undo, vorher abfragen ??
 	pDBData->GetQueryParam( aParam );

sc/source/ui/view/tabview3.cxx

 	SCCOL nEndCol = nStartCol;
 	SCROW nEndRow = nStartRow;
 
-	pDoc->GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, bIncludeCursor );
+	pDoc->GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, bIncludeCursor, false );
 
 	HideAllCursors();
 	DoneBlockMode();

sc/source/ui/view/tabvwshc.cxx

 									 SCITEM_QUERYDATA,
 									 SCITEM_QUERYDATA );
 
-			ScDBData* pDBData = GetDBData();
+			ScDBData* pDBData = GetDBData( TRUE, SC_DB_MAKE, SC_DBSEL_ROW_DOWN);
 			pDBData->GetQueryParam( aQueryParam );
 
 			ScQueryItem aItem( SCITEM_QUERYDATA, GetViewData(), &aQueryParam );
 									 SCITEM_QUERYDATA,
 									 SCITEM_QUERYDATA );
 
-			ScDBData* pDBData = GetDBData();
+			ScDBData* pDBData = GetDBData( TRUE, SC_DB_MAKE, SC_DBSEL_ROW_DOWN);
 			pDBData->GetQueryParam( aQueryParam );
 
 			aArgSet.Put( ScQueryItem( SCITEM_QUERYDATA,

sc/source/ui/view/viewfun5.cxx

 			//	Creation of database area "Import1" isn't here, but in the DocShell
 			//	slot execute, so it can be added to the undo action
 
-			ScDBData* pDBData = pDocSh->GetDBData( ScRange(nPosX,nPosY,nTab), SC_DB_OLD, FALSE );
+			ScDBData* pDBData = pDocSh->GetDBData( ScRange(nPosX,nPosY,nTab), SC_DB_OLD, SC_DBSEL_KEEP );
 			String sTarget;
 			if (pDBData)
 				sTarget = pDBData->GetName();