fpspreadsheet: Add redundant information on selected worksheet to xls files (like Excel does). Add code to read/write selected cell in xls, xlsx and ods.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4243 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2015-08-04 09:42:39 +00:00
parent 31090f663a
commit 71fa9ae693
6 changed files with 139 additions and 48 deletions

View File

@ -2961,6 +2961,7 @@ var
sheet: TsWorksheet;
vsm, hsm, hsp, vsp: Integer;
showGrid, showHeaders: Boolean;
actCol, actRow: Cardinal;
i: Integer;
begin
showGrid := true;
@ -3027,14 +3028,14 @@ begin
begin
cfgName := GetAttrValue(node, 'config:name');
cfgValue := GetNodeValue(node);
if cfgName = 'VerticalSplitMode' then
vsm := StrToInt(cfgValue)
else if cfgName = 'HorizontalSplitMode' then
hsm := StrToInt(cfgValue)
else if cfgName = 'VerticalSplitPosition' then
vsp := StrToInt(cfgValue)
else if cfgName = 'HorizontalSplitPosition' then
hsp := StrToInt(cfgValue);
case cfgName of
'CursorPositionX': actCol := StrToInt(cfgValue);
'CursorPositionY': actRow := StrToInt(cfgValue);
'VerticalSplitMode': vsm := StrToInt(cfgValue);
'HorizontalSplitMode': hsm := StrToInt(cfgValue);
'VerticalSplitPosition': vsp := StrToInt(cfgValue);
'HorizontalSplitPosition': hsp := StrToInt(cfgValue);
end;
end;
node := node.NextSibling;
end;
@ -3046,6 +3047,8 @@ begin
end else
sheet.Options := sheet.Options - [soHasFrozenPanes];
end;
// Active cell
sheet.SelectCell(actRow, actCol);
end;
end;
cfgTableItemNode := cfgTableItemNode.NextSibling;
@ -5023,9 +5026,10 @@ procedure TsSpreadOpenDocWriter.WriteTableSettings(AStream: TStream);
var
i: Integer;
sheet: TsWorkSheet;
hsm: Integer; // HorizontalSplitMode
vsm: Integer; // VerticalSplitMode
asr: Integer; // ActiveSplitRange
hsm: Integer; // HorizontalSplitMode
vsm: Integer; // VerticalSplitMode
asr: Integer; // ActiveSplitRange
actX, actY: Integer; // Active cell col/row index
begin
for i:=0 to Workbook.GetWorksheetCount-1 do
begin
@ -5051,10 +5055,20 @@ begin
end;
{showGrid := (soShowGridLines in sheet.Options);}
if (sheet.ActiveCellRow <> cardinal(-1)) and (sheet.ActiveCellCol <> cardinal(-1)) then
begin
actX := sheet.ActiveCellCol;
actY := sheet.ActiveCellRow;
end else
begin
actX := sheet.LeftPaneWidth;
actY := sheet.TopPaneHeight;
end;
AppendToStream(AStream,
'<config:config-item config:name="CursorPositionX" config:type="int">'+IntToStr(sheet.LeftPaneWidth)+'</config:config-item>');
'<config:config-item config:name="CursorPositionX" config:type="int">'+IntToStr(actX)+'</config:config-item>');
AppendToStream(AStream,
'<config:config-item config:name="CursorPositionY" config:type="int">'+IntToStr(sheet.TopPaneHeight)+'</config:config-item>');
'<config:config-item config:name="CursorPositionY" config:type="int">'+IntToStr(actY)+'</config:config-item>');
AppendToStream(AStream,
'<config:config-item config:name="HorizontalSplitMode" config:type="short">'+IntToStr(hsm)+'</config:config-item>');
AppendToStream(AStream,

View File

@ -504,6 +504,7 @@ begin
INT_EXCEL_ID_PRINTHEADERS: ReadPrintHeaders(AStream);
INT_EXCEL_ID_RIGHTMARGIN : ReadMargin(AStream, 1);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_SELECTION : ReadSELECTION(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
INT_EXCEL_ID_TOPMARGIN : ReadMargin(AStream, 2);
INT_EXCEL_ID_DEFROWHEIGHT: ReadDefRowHeight(AStream);

View File

@ -431,6 +431,7 @@ begin
INT_EXCEL_ID_RK : ReadRKValue(AStream); //(RK) This record represents a cell that contains an RK value (encoded integer or floating-point value). If a floating-point value cannot be encoded to an RK value, a NUMBER record will be written. This record replaces the record INTEGER written in BIFF2.
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_RSTRING : ReadRString(AStream); //(RSTRING) This record stores a formatted text cell (Rich-Text). In BIFF8 it is usually replaced by the LABELSST record. Excel still uses this record, if it copies formatted text cells to the clipboard.
INT_EXCEL_ID_SELECTION : ReadSELECTION(AStream);
INT_EXCEL_ID_SHAREDFMLA : ReadSharedFormula(AStream);
INT_EXCEL_ID_SHEETPR : ReadSHEETPR(AStream);
INT_EXCEL_ID_STANDARDWIDTH : ReadStandardWidth(AStream, FWorksheet);

View File

@ -819,6 +819,7 @@ begin
// This record replaces the record INTEGER written in BIFF2.
INT_EXCEL_ID_RK : ReadRKValue(AStream);
INT_EXCEL_ID_SELECTION : ReadSELECTION(AStream);
INT_EXCEL_ID_SHAREDFMLA : ReadSharedFormula(AStream);
INT_EXCEL_ID_SHEETPR : ReadSHEETPR(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);

View File

@ -431,6 +431,7 @@ type
function ReadRPNTokenArray(AStream: TStream; ACell: PCell;
ASharedFormulaBase: PCell = nil): Boolean;
function ReadRPNTokenArraySize(AStream: TStream): word; virtual;
procedure ReadSELECTION(AStream: TStream);
procedure ReadSharedFormula(AStream: TStream);
procedure ReadSHEETPR(AStream: TStream);
@ -543,7 +544,7 @@ type
procedure WriteRPNTokenArraySize(AStream: TStream; ASize: Word); virtual;
// Writes out a SELECTION record
procedure WriteSelection(AStream: TStream; ASheet: TsWorksheet; APane: Byte);
procedure WriteSELECTION(AStream: TStream; ASheet: TsWorksheet; APane: Byte);
procedure WriteSelections(AStream: TStream; ASheet: TsWorksheet);
(*
// Writes out a shared formula
@ -2163,6 +2164,35 @@ begin
Result := WordLEToN(AStream.ReadWord);
end;
{@@ ----------------------------------------------------------------------------
Reads a SELECTION record containing the currently selected cell
Valid for BIFF2-BIFF8.
-------------------------------------------------------------------------------}
procedure TsSpreadBIFFReader.ReadSELECTION(AStream: TStream);
var
actPane: byte;
actRow, actCol: Word;
rngIndex: Word;
i, numRanges: Word;
begin
// Active pane
actPane := AStream.ReadByte;
// Row index of the active cell
actRow := WordLEToN(AStream.ReadWord);
// Column index of the active cell
actCol := WordLEToN(AStream.ReadWord);
// Index into the following range list which contains the active cell
rngIndex := WordLEToN(AStream.ReadWord);
// Count of selected ranges
// Selected ranges --> ignore
FWorksheet.SelectCell(actRow, actCol);
end;
{@@ ----------------------------------------------------------------------------
Reads a SHAREDFMLA record, i.e. reads cell range coordinates and a rpn
formula. The formula is applied to all cells in the range. The formula is
@ -3695,29 +3725,34 @@ end;
APane is 0..3 (see below)
Valid for BIFF2-BIFF8
-------------------------------------------------------------------------------}
procedure TsSpreadBIFFWriter.WriteSelection(AStream: TStream;
procedure TsSpreadBIFFWriter.WriteSELECTION(AStream: TStream;
ASheet: TsWorksheet; APane: Byte);
var
activeCellRow, activeCellCol: Word;
begin
case APane of
0: begin // right-bottom
activeCellRow := ASheet.TopPaneHeight;
activeCellCol := ASheet.LeftPaneWidth;
end;
1: begin // right-top
activeCellRow := 0;
activeCellCol := ASheet.LeftPaneWidth;
end;
2: begin // left-bottom
activeCellRow := ASheet.TopPaneHeight;
activeCellCol := 0;
end;
3: begin // left-top
activeCellRow := 0;
activeCellCol := 0;
end;
end;
if FWorkbook.ActiveWorksheet <> nil then
begin
activeCellRow := FWorksheet.ActiveCellRow;
activeCellCol := FWorksheet.ActiveCellCol;
end else
case APane of
0: begin // right-bottom
activeCellRow := ASheet.TopPaneHeight;
activeCellCol := ASheet.LeftPaneWidth;
end;
1: begin // right-top
activeCellRow := 0;
activeCellCol := ASheet.LeftPaneWidth;
end;
2: begin // left-bottom
activeCellRow := ASheet.TopPaneHeight;
activeCellCol := 0;
end;
3: begin // left-top
activeCellRow := 0;
activeCellCol := 0;
end;
end;
{ BIFF record header }
WriteBIFFHeader(AStream, INT_EXCEL_ID_SELECTION, 15);
@ -3963,6 +3998,8 @@ end;
Valid for BIFF5-BIFF8.
-------------------------------------------------------------------------------}
procedure TsSpreadBIFFWriter.WriteWindow1(AStream: TStream);
var
actSheet: Integer;
begin
{ BIFF Record header }
WriteBIFFHeader(AStream, INT_EXCEL_ID_WINDOW1, 18);
@ -3986,7 +4023,10 @@ begin
MASK_WINDOW1_OPTION_WORKSHEET_TAB_VISIBLE));
{ Index to active (displayed) worksheet }
AStream.WriteWord(WordToLE($00));
if FWorkbook.ActiveWorksheet = nil then
actSheet := 0 else
actSheet := FWorkbook.GetWorksheetIndex(FWorkbook.ActiveWorksheet);
AStream.WriteWord(WordToLE(actSheet));
{ Index of first visible tab in the worksheet tab bar }
AStream.WriteWord(WordToLE($00));

View File

@ -1751,6 +1751,7 @@ var
childNode: TDOMNode;
nodeName: String;
s: String;
actRow, actCol: Cardinal;
begin
if ANode = nil then
exit;
@ -1778,6 +1779,14 @@ begin
s := GetAttrValue(childNode, 'ySplit');
if s <> '' then AWorksheet.TopPaneHeight := StrToInt(s);
end;
end else
if nodeName = 'selection' then begin
s := GetAttrValue(childnode, 'activeCell');
if s <> '' then
begin
ParseCellString(s, actRow, actCol);
AWorksheet.SelectCell(actRow, actCol);
end;
end;
childNode := childNode.NextSibling;
end;
@ -3025,6 +3034,8 @@ var
topRightCell: String;
bottomLeftCell: String;
bottomRightCell: String;
actCell: String;
tabSel: String;
begin
// Show gridlines ?
showGridLines := StrUtils.IfThen(soShowGridLines in AWorksheet.Options, ' ', 'showGridLines="0" ');
@ -3032,63 +3043,86 @@ begin
// Show headers?
showHeaders := StrUtils.IfThen(soShowHeaders in AWorksheet.Options, ' ', 'showRowColHeaders="0" ');
// Active cell
if (AWorksheet.ActiveCellRow <> cardinal(-1)) and (AWorksheet.ActiveCellCol <> cardinal(-1)) then
actCell := GetCellString(AWorksheet.ActiveCellRow, AWorksheet.ActiveCellCol) else
actCell := '';
// Selected tab?
tabSel := StrUtils.IfThen(AWorksheet = FWorkbook.ActiveWorksheet, 'tabSelected="1" ', '');
// No frozen panes
if not (soHasFrozenPanes in AWorksheet.Options) or
((AWorksheet.LeftPaneWidth = 0) and (AWorksheet.TopPaneHeight = 0))
then
begin
if actCell = '' then actCell := 'A1';
AppendToStream(AStream, Format(
'<sheetViews>' +
'<sheetView workbookViewId="0" %s%s/>' +
'<sheetView workbookViewId="0" %s%s%s>' +
'<selection activeCell="%s" sqref="%s" />' +
'</sheetView>' +
'</sheetViews>', [
showGridLines, showHeaders
showGridLines, showHeaders, tabSel,
actCell, actCell
]))
else
end else
begin // Frozen panes
topRightCell := GetCellString(0, AWorksheet.LeftPaneWidth, [rfRelRow, rfRelCol]);
bottomLeftCell := GetCellString(AWorksheet.TopPaneHeight, 0, [rfRelRow, rfRelCol]);
bottomRightCell := GetCellString(AWorksheet.TopPaneHeight, AWorksheet.LeftPaneWidth, [rfRelRow, rfRelCol]);
if (AWorksheet.LeftPaneWidth > 0) and (AWorksheet.TopPaneHeight > 0) then
begin
if actCell = '' then
actCell := bottomRightcell;
AppendToStream(AStream, Format(
'<sheetViews>' +
'<sheetView workbookViewId="0" %s%s>'+
'<sheetView workbookViewId="0" %s%s%s>'+
'<pane xSplit="%d" ySplit="%d" topLeftCell="%s" activePane="bottomRight" state="frozen" />' +
'<selection pane="topRight" activeCell="%s" sqref="%s" />' +
'<selection pane="bottomLeft" activeCell="%s" sqref="%s" />' +
'<selection pane="bottomRight" activeCell="%s" sqref="%s" />' +
'</sheetView>' +
'</sheetViews>', [
showGridLines, showHeaders,
showGridLines, showHeaders, tabSel,
AWorksheet.LeftPaneWidth, AWorksheet.TopPaneHeight, bottomRightCell,
topRightCell, topRightCell,
bottomLeftCell, bottomLeftCell,
bottomRightCell, bottomrightCell
actCell, actCell
]))
else
end else
if (AWorksheet.LeftPaneWidth > 0) then
begin
if actCell = '' then
actCell := topRightCell;
AppendToStream(AStream, Format(
'<sheetViews>' +
'<sheetView workbookViewId="0" %s%s>'+
'<sheetView workbookViewId="0" %s%s%s>'+
'<pane xSplit="%d" topLeftCell="%s" activePane="topRight" state="frozen" />' +
'<selection pane="topRight" activeCell="%s" sqref="%s" />' +
'</sheetView>' +
'</sheetViews>', [
showGridLines, showHeaders,
showGridLines, showHeaders, tabSel,
AWorksheet.LeftPaneWidth, topRightCell,
topRightCell, topRightCell
actCell, actCell
]))
else
end else
if (AWorksheet.TopPaneHeight > 0) then
begin
if actCell = '' then
actCell := bottomLeftCell;
AppendToStream(AStream, Format(
'<sheetViews>'+
'<sheetView workbookViewId="0" %s%s>'+
'<sheetView workbookViewId="0" %s%s%s>'+
'<pane ySplit="%d" topLeftCell="%s" activePane="bottomLeft" state="frozen" />'+
'<selection pane="bottomLeft" activeCell="%s" sqref="%s" />' +
'</sheetView>'+
'</sheetViews>', [
showGridLines, showHeaders,
showGridLines, showHeaders, tabSel,
AWorksheet.TopPaneHeight, bottomLeftCell,
bottomLeftCell, bottomLeftCell
actCell, actCell
]));
end;
end;
end;