fpspreadsheet: Fix grid's Col/RowCount not being reduced if a sheet with less cols/rows than the current sheet is selected (http://forum.lazarus.freepascal.org/index.php/topic,35182.msg232477.html#msg232477). Introduce top/left cell indexes in worksheet to make sure that active cell remains at the row/col stored in the worksheet when changing worksheets.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5560 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2016-12-23 17:05:14 +00:00
parent d6e3ba3a4f
commit e22ceab9c9
3 changed files with 126 additions and 36 deletions

View File

@ -84,6 +84,8 @@ type
FRows, FCols: TIndexedAVLTree; // This lists contain only rows or cols with styles different from default
FActiveCellRow: Cardinal;
FActiveCellCol: Cardinal;
FTopRow: Cardinal;
FLeftCol: Cardinal;
FSelection: TsCellRangeArray;
FLeftPaneWidth: Integer;
FTopPaneHeight: Integer;
@ -477,6 +479,8 @@ type
function GetSelectionRangeIndexOfActiveCell: Integer;
procedure SetSelection(const ASelection: TsCellRangeArray);
procedure ScrollTo(ANewTopRow, ANewLeftCol: Cardinal);
// Comments
function FindComment(ACell: PCell): PsComment;
function HasComment(ACell: PCell): Boolean;
@ -582,6 +586,10 @@ type
property ActiveCellCol: Cardinal read FActiveCellCol;
{@@ Row index of the selected cell of this worksheet }
property ActiveCellRow: Cardinal read FActiveCellRow;
{@@ Index of the left-most visible column in the grid - used by WorksheetGrid}
property LeftCol: Cardinal read FLeftCol;
{@@ Index of the top-most visible row in the grid - used by WorksheetGrid }
property TopRow: Cardinal read FTopRow;
{@@ Number of frozen columns which do not scroll }
property LeftPaneWidth: Integer read FLeftPaneWidth write FLeftPaneWidth;
{@@ Number of frozen rows which do not scroll }
@ -4225,6 +4233,17 @@ begin
FSelection[i] := ASelection[i];
end;
{@@ ----------------------------------------------------------------------------
Uses the passed parameters a TopRow and LeftCol. These are used by the
TsWorksheetGrid to scroll the visible grid such that the corresponding cell
is at the top/left.
-------------------------------------------------------------------------------}
procedure TsWorksheet.ScrollTo(ANewTopRow, ANewLeftCol: Cardinal);
begin
FTopRow := ANewTopRow;
FLeftCol := ANewLeftCol;
end;
{@@ ----------------------------------------------------------------------------
Helper method to update internal caching variables
-------------------------------------------------------------------------------}

View File

@ -1071,7 +1071,8 @@ begin
AWorkbook.DisableNotifications;
if AWorkbook <> FWorkbook then
InternalCreateNewWorkbook(AWorkbook);
InternalCreateNewWorkbook(AWorkbook) else
SetOptions(FOptions);
WorkbookOpenedHandler(self);
if AWorksheetIndex = -1 then
@ -1672,10 +1673,10 @@ begin
FWorksheet.OnZoom := @WorksheetZoomHandler;
NotifyListeners([lniWorksheet]);
FWorksheet := AWorksheet; // !!!!!
if FWorksheet.ActiveCellRow = Cardinal(-1) then
if FWorksheet.ActiveCellRow = UNASSIGNED_ROW_COL_INDEX then
r := FWorksheet.TopPaneHeight else
r := FWorksheet.ActiveCellRow;
if FWorksheet.ActiveCellCol = Cardinal(-1) then
if FWorksheet.ActiveCellCol = UNASSIGNED_ROW_COL_INDEX then
c := FWorksheet.LeftPaneWidth else
c := FWorksheet.ActiveCellCol;
SelectCell(r, c);

View File

@ -15,6 +15,8 @@ unit fpspreadsheetgrid;
{$mode objfpc}{$H+}
{$I ..\fps.inc}
{.$DEFINE GRID_DEBUG}
{ To do:
- When Lazarus 1.4 comes out remove the workaround for the RGB2HLS bug in
FindNearestPaletteIndex.
@ -247,6 +249,7 @@ type
procedure SetEditText(ACol, ARow: Longint; const AValue: string); override;
procedure Setup;
procedure Sort(AColSorting: Boolean; AIndex, AIndxFrom, AIndxTo:Integer); override;
procedure TopLeftChanged; override;
function TrimToCell(ACell: PCell): String;
{@@ Automatically recalculate formulas whenever a cell value changes. }
@ -4081,45 +4084,100 @@ end;
procedure TsCustomWorksheetGrid.ListenerNotification(AChangedItems: TsNotificationItems;
AData: Pointer = nil);
var
actgrow, actgcol: Integer;
grow, gcol: Integer;
srow, scol: Cardinal;
cell: PCell;
lRow: PRow;
{$IFDEF GRID_DEBUG}
procedure DebugNotification(ACaption: String);
var
s: String;
begin
WriteLn(ACaption);
s := '';
if (lniWorksheet in AChangedItems) then s := s + 'lniWorksheet, ';
if (lniCell in AChangedItems) then s := s + 'lniCell, ';
if (lniSelection in AChangedItems) then s := s + 'lniSelection, ';
if (lniAbortSelection in AChangedItems) then s := s + 'lniAbortSelection, ';
if (lniRow in AChangedItems) then s := s + 'lniRow, ';
if (lniCol in AChangedItems) then s := s + 'lniCol, ';
if (lniWorksheetZoom in AChangedItems) then s := s + 'lniWorksheetZoom, ';
if s <> '' then SetLength(s, Length(s) - 2);
WriteLn(' AChangedItems = [', s, ']');
WriteLn(' ActiveCellRow: ', Worksheet.ActiveCellRow, ' ActiveCellCol: ', Worksheet.ActiveCellCol);
WriteLn(' TopRow: ', Worksheet.TopRow, ' LeftCol: ', Worksheet.LeftCol);
WriteLn;
end;
{$ENDIF}
begin
Unused(AData);
{$IFDEF GRID_DEBUG}
if Worksheet <> nil then
DebugNotification('BEFORE ListenerNotification WorksheetGrid "' + Worksheet.Name + '":');
{$ENDIF}
// Nothing to do for "workbook changed" because this is always combined with
// "worksheet changed".
// Worksheet changed
if (lniWorksheet in AChangedItems) then
begin
if (Worksheet <> nil) then
begin
inc(FLockSetup);
ShowHeaders := (soShowHeaders in Worksheet.Options);
ShowGridLines := (soShowGridLines in Worksheet.Options);
if (soHasFrozenPanes in Worksheet.Options) then begin
FrozenCols := Worksheet.LeftPaneWidth;
FrozenRows := Worksheet.TopPaneHeight;
end else begin
FrozenCols := 0;
FrozenRows := 0;
BeginUpdate; // avoid flicker...
try
if (Worksheet <> nil) then
begin
// remember indexes of top/left and active cell
grow := GetGridRow(Worksheet.TopRow);
gcol := GetGridCol(Worksheet.LeftCol);
actgrow := GetGridRow(Worksheet.ActiveCellRow);
actgcol := GetGridCol(Worksheet.ActiveCellCol);
AutoExpandToRow(grow, aeNavigation);
AutoExpandToCol(gcol, aeNavigation);
if (grow <> Row) or (gcol <> Col) then
MoveExtend(false, gcol, grow);
inc(FLockSetup);
// Setup grid headers and col/row count
ShowHeaders := (soShowHeaders in Worksheet.Options);
ShowGridLines := (soShowGridLines in Worksheet.Options);
if (soHasFrozenPanes in Worksheet.Options) then begin
FrozenCols := Worksheet.LeftPaneWidth;
FrozenRows := Worksheet.TopPaneHeight;
end else begin
FrozenCols := 0;
FrozenRows := 0;
end;
case Worksheet.BiDiMode of
bdDefault: ParentBiDiMode := true;
bdLTR : begin
ParentBiDiMode := false;
BiDiMode := bdLeftToRight;
end;
bdRTL : begin
ParentBiDiMode := false;
BiDiMode := bdRightToLeft;
end;
end;
dec(FLockSetup);
end;
case Worksheet.BiDiMode of
bdDefault: ParentBiDiMode := true;
bdLTR : begin
ParentBiDiMode := false;
BiDiMode := bdLeftToRight;
end;
bdRTL : begin
ParentBiDiMode := false;
BiDiMode := bdRightToLeft;
end;
Setup;
// scroll the grid for top/left to be as stored in the sheet
if (grow <> TopRow) or (gcol <> LeftCol) then
begin
TopRow := gRow;
LeftCol := gCol;
end;
dec(FLockSetup);
// Select active cell
AutoExpandToRow(actgrow, aeNavigation);
AutoExpandToCol(actgcol, aeNavigation);
if (actgrow <> Row) or (actgcol <> Col) then
MoveExtend(false, actgcol, actgrow);
finally
EndUpdate;
end;
Setup;
end;
// Cell value or format changed
@ -4179,6 +4237,12 @@ begin
// Worksheet zoom
if (lniWorksheetZoom in AChangedItems) and (Worksheet <> nil) then
AdaptToZoomFactor; // Reads value directly from Worksheet
{$IFDEF GRID_DEBUG}
if Worksheet <> nil then
DebugNotification('AFTER ListenerNotification WorksheetGrid "' + Worksheet.Name + '":');
{$ENDIF}
end;
{@@ ----------------------------------------------------------------------------
@ -4498,6 +4562,8 @@ end;
initial column widths and row heights.
-------------------------------------------------------------------------------}
procedure TsCustomWorksheetGrid.Setup;
var
defColCount, defRowCount: Integer;
begin
if csLoading in ComponentState then
exit;
@ -4520,15 +4586,10 @@ begin
end;
end else
if Worksheet <> nil then begin
if FHeaderCount = 0 then
begin
ColCount := Max(GetGridCol(Worksheet.GetLastColIndex), ColCount-1);
RowCount := Max(GetGridRow(Worksheet.GetLastRowIndex), RowCount-1);
end else
begin
ColCount := Max(GetGridCol(Worksheet.GetLastColIndex) + 1, ColCount);
RowCount := Max(GetGridRow(Worksheet.GetLastRowIndex) + 1, RowCount);
end;
defColCount := DEFAULT_COL_COUNT;
defRowCount := DEFAULT_ROW_COUNT;
ColCount := Max(GetGridCol(Worksheet.GetLastColIndex)+1, defColCount) + FHeaderCount;
RowCount := max(GetGridRow(Worksheet.GetLastRowIndex)+1, defRowCount) + FHeaderCount;
FixedCols := FFrozenCols + FHeaderCount;
FixedRows := FFrozenRows + FHeaderCount;
if ShowHeaders then begin
@ -4539,7 +4600,7 @@ begin
end;
UpdateColWidths;
UpdateRowHeights;
Invalidate;
//Invalidate; // wp: really needed? Might cause flicker
end;
{@@ ----------------------------------------------------------------------------
@ -4681,6 +4742,15 @@ begin
);
end;
{@@ ----------------------------------------------------------------------------
Store the value of the TopLeft cell in the worksheet
-------------------------------------------------------------------------------}
procedure TsCustomWorksheetGrid.TopLeftChanged;
begin
inherited;
Worksheet.ScrollTo(GetWorkSheetRow(TopRow), GetWorksheetCol(LeftCol));
end;
{@@ ----------------------------------------------------------------------------
Modifies the text that is show for cells which are too narrow to hold the
entire text. The method follows the behavior of Excel and Open/LibreOffice: