fpspreadsheet: Adjust defined name ranges when rows/cols are inserted/deleted. Handle #REF! error in defined names.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9409 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
6a319f55b8
commit
12ee2c0b1b
@ -116,7 +116,7 @@ begin
|
|||||||
sh.WriteText(row, 1, 'background gray');
|
sh.WriteText(row, 1, 'background gray');
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcLessEqual, 5, fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcLessEqual, 5, fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: between
|
// conditional format #7: between
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'between 2 and 7');
|
sh.WriteText(row, 0, 'between 2 and 7');
|
||||||
sh.WriteText(row, 1, 'background light gray');
|
sh.WriteText(row, 1, 'background light gray');
|
||||||
@ -124,13 +124,13 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcBetween, 2, 7, fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcBetween, 2, 7, fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: not between
|
// conditional format #8: not between
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'not between 2 and 7');
|
sh.WriteText(row, 0, 'not between 2 and 7');
|
||||||
sh.WriteText(row, 1, 'background light gray');
|
sh.WriteText(row, 1, 'background light gray');
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcNotBetween, 2, 7, fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcNotBetween, 2, 7, fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: above average
|
// conditional format #9: above average
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, '> average');
|
sh.WriteText(row, 0, '> average');
|
||||||
sh.WriteText(row, 1, 'hatched background yellow on red');
|
sh.WriteText(row, 1, 'hatched background yellow on red');
|
||||||
@ -139,7 +139,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcAboveAverage, fmtIdx); // only 1..9 -> ave = 5
|
sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcAboveAverage, fmtIdx); // only 1..9 -> ave = 5
|
||||||
|
|
||||||
// conditional format #6: below average
|
// conditional format #10: below average
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, '< average');
|
sh.WriteText(row, 0, '< average');
|
||||||
sh.WriteText(row, 1, 'dotted background yellow on red');
|
sh.WriteText(row, 1, 'dotted background yellow on red');
|
||||||
@ -148,7 +148,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcBelowAverage, fmtIdx); // only 1..9 -> ave = 5
|
sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcBelowAverage, fmtIdx); // only 1..9 -> ave = 5
|
||||||
|
|
||||||
// conditional format #6: above or equal to average
|
// conditional format #11: above or equal to average
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, '>= average');
|
sh.WriteText(row, 0, '>= average');
|
||||||
sh.WriteText(row, 1, 'hor striped background yellow on red');
|
sh.WriteText(row, 1, 'hor striped background yellow on red');
|
||||||
@ -157,7 +157,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcAboveEqualAverage, fmtIdx); // only 1..9 -> ave = 5
|
sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcAboveEqualAverage, fmtIdx); // only 1..9 -> ave = 5
|
||||||
|
|
||||||
// conditional format #6: below or equal to average
|
// conditional format #12: below or equal to average
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, '<= average');
|
sh.WriteText(row, 0, '<= average');
|
||||||
sh.WriteText(row, 1, 'vert striped background yellow on red');
|
sh.WriteText(row, 1, 'vert striped background yellow on red');
|
||||||
@ -166,7 +166,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcBelowEqualAverage, fmtIdx); // only 1..9 -> ave = 5
|
sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcBelowEqualAverage, fmtIdx); // only 1..9 -> ave = 5
|
||||||
|
|
||||||
// conditional format #6: top 3 values
|
// conditional format #13: top 3 values
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'top 3 values');
|
sh.WriteText(row, 0, 'top 3 values');
|
||||||
sh.WriteText(row, 1, 'background green');
|
sh.WriteText(row, 1, 'background green');
|
||||||
@ -174,7 +174,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcTop, 3, fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcTop, 3, fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: smallest 3 values
|
// conditional format #14: smallest 3 values
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'smallest 3 values');
|
sh.WriteText(row, 0, 'smallest 3 values');
|
||||||
sh.WriteText(row, 1, 'background bright blue');
|
sh.WriteText(row, 1, 'background bright blue');
|
||||||
@ -182,7 +182,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcBottom, 3, fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcBottom, 3, fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: top 30 percent
|
// conditional format #15: top 10 percent
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'top 10 percent');
|
sh.WriteText(row, 0, 'top 10 percent');
|
||||||
sh.WriteText(row, 1, 'background green');
|
sh.WriteText(row, 1, 'background green');
|
||||||
@ -190,7 +190,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcTopPercent, 10, fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcTopPercent, 10, fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: smallest 3 values
|
// conditional format #16: smallest 10 percent
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'smallest 10 percent');
|
sh.WriteText(row, 0, 'smallest 10 percent');
|
||||||
sh.WriteText(row, 1, 'background bright blue');
|
sh.WriteText(row, 1, 'background bright blue');
|
||||||
@ -198,7 +198,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcBottomPercent, 10, fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcBottomPercent, 10, fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: duplicates
|
// conditional format #17: duplicates
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'duplicate values');
|
sh.WriteText(row, 0, 'duplicate values');
|
||||||
sh.WriteText(row, 1, 'background bright red');
|
sh.WriteText(row, 1, 'background bright red');
|
||||||
@ -206,7 +206,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcDuplicate, fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcDuplicate, fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: unique
|
// conditional format #18: unique
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'unique values');
|
sh.WriteText(row, 0, 'unique values');
|
||||||
sh.WriteText(row, 1, 'borders all sides');
|
sh.WriteText(row, 1, 'borders all sides');
|
||||||
@ -215,7 +215,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcUnique, fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcUnique, fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: contains any text
|
// conditional format #19: contains any text
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'contains any text');
|
sh.WriteText(row, 0, 'contains any text');
|
||||||
sh.WriteText(row, 1, 'background red');
|
sh.WriteText(row, 1, 'background red');
|
||||||
@ -224,7 +224,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcContainsText, '', fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcContainsText, '', fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: empty
|
// conditional format #20: empty
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'empty');
|
sh.WriteText(row, 0, 'empty');
|
||||||
sh.WriteText(row, 1, 'background red');
|
sh.WriteText(row, 1, 'background red');
|
||||||
@ -232,7 +232,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcNotContainsText, '', fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcNotContainsText, '', fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: text begins with 'ab'
|
// conditional format #21: text begins with 'ab'
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'text begins with "ab"');
|
sh.WriteText(row, 0, 'text begins with "ab"');
|
||||||
sh.WriteText(row, 1, 'background red');
|
sh.WriteText(row, 1, 'background red');
|
||||||
@ -240,7 +240,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcBeginsWith, 'ab', fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcBeginsWith, 'ab', fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: text ends with 'g'
|
// conditional format #22: text ends with 'g'
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'text ends with "g"');
|
sh.WriteText(row, 0, 'text ends with "g"');
|
||||||
sh.WriteText(row, 1, 'background red');
|
sh.WriteText(row, 1, 'background red');
|
||||||
@ -248,7 +248,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcEndsWith, 'g', fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcEndsWith, 'g', fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: text contains 'ef'
|
// conditional format #23: text contains 'ef'
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'text contains "ef"');
|
sh.WriteText(row, 0, 'text contains "ef"');
|
||||||
sh.WriteText(row, 1, 'background red');
|
sh.WriteText(row, 1, 'background red');
|
||||||
@ -256,7 +256,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcContainsText, 'ef', fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcContainsText, 'ef', fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: text does NOT contain 'ef'
|
// conditional format #24: text does NOT contain 'ef'
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'text does not contain "ef"');
|
sh.WriteText(row, 0, 'text does not contain "ef"');
|
||||||
sh.WriteText(row, 1, 'background red');
|
sh.WriteText(row, 1, 'background red');
|
||||||
@ -264,7 +264,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcNotContainsText, 'ef', fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcNotContainsText, 'ef', fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: contains error
|
// conditional format #25: contains error
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'contains error');
|
sh.WriteText(row, 0, 'contains error');
|
||||||
sh.WriteText(row, 1, 'background red');
|
sh.WriteText(row, 1, 'background red');
|
||||||
@ -272,7 +272,7 @@ begin
|
|||||||
fmtIdx := wb.AddCellFormat(fmt);
|
fmtIdx := wb.AddCellFormat(fmt);
|
||||||
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcContainsErrors, fmtIdx);
|
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcContainsErrors, fmtIdx);
|
||||||
|
|
||||||
// conditional format #6: no errors
|
// conditional format #26: no errors
|
||||||
inc(row);
|
inc(row);
|
||||||
sh.WriteText(row, 0, 'no errors');
|
sh.WriteText(row, 0, 'no errors');
|
||||||
sh.WriteText(row, 1, 'background yellow, font "Courier New"/red/bold/14');
|
sh.WriteText(row, 1, 'background yellow, font "Courier New"/red/bold/14');
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
program demo_read_definednames;
|
program demo_read_definednames;
|
||||||
{$DEFINE ODS}
|
{$DEFINE ODS}
|
||||||
uses
|
uses
|
||||||
fpspreadsheet, fpsTypes, fpsClasses, fpsUtils, fpsAllFormats;
|
SysUtils, fpspreadsheet, fpsTypes, fpsClasses, fpsUtils, fpsAllFormats;
|
||||||
var
|
var
|
||||||
wb: TsWorkbook;
|
wb: TsWorkbook;
|
||||||
ws: TsWorksheet;
|
ws: TsWorksheet;
|
||||||
@ -15,7 +15,7 @@ begin
|
|||||||
fn := 'test_defnames.xlsx';
|
fn := 'test_defnames.xlsx';
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
//fn := 'test3D.xlsx';
|
fn := 'Mappe2.ods';
|
||||||
|
|
||||||
wb := TsWorkbook.Create;
|
wb := TsWorkbook.Create;
|
||||||
try
|
try
|
||||||
@ -26,7 +26,13 @@ begin
|
|||||||
|
|
||||||
WriteLn('DEFINED NAMES (GLOBAL)');
|
WriteLn('DEFINED NAMES (GLOBAL)');
|
||||||
for i := 0 to wb.DefinedNames.Count-1 do
|
for i := 0 to wb.DefinedNames.Count-1 do
|
||||||
WriteLn(' "', wb.DefinedNames[i].Name, '" --> ', wb.DefinedNames[i].RangeAsString(wb));
|
begin
|
||||||
|
Write(' "', wb.DefinedNames[i].Name, '" --> ');
|
||||||
|
case ExtractFileExt(fn) of
|
||||||
|
'.xlsx': WriteLn(wb.DefinedNames[i].RangeAsString(wb));
|
||||||
|
'.ods': WriteLn(wb.DefinedNames[i].RangeAsString_ODS(wb));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
WriteLn('--------------------------------------------------------');
|
WriteLn('--------------------------------------------------------');
|
||||||
|
|
||||||
@ -40,7 +46,13 @@ begin
|
|||||||
WriteLn(' (none)')
|
WriteLn(' (none)')
|
||||||
else
|
else
|
||||||
for j := 0 to ws.DefinedNames.Count-1 do
|
for j := 0 to ws.DefinedNames.Count-1 do
|
||||||
WriteLn(' "', ws.DefinedNames[i].Name, '" --> ', ws.DefinedNames[i].RangeAsString(wb));
|
begin
|
||||||
|
Write(' "', ws.DefinedNames[i].Name, '" --> ');
|
||||||
|
case ExtractFileExt(fn) of
|
||||||
|
'.xlsx': WriteLn(ws.DefinedNames[i].RangeAsString(wb));
|
||||||
|
'.ods': WriteLn(ws.DefinedNames[i].RangeAsString_ODS(wb));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
WriteLn(' CELLS');
|
WriteLn(' CELLS');
|
||||||
for cell in ws.Cells do
|
for cell in ws.Cells do
|
||||||
|
|||||||
@ -229,8 +229,10 @@ type
|
|||||||
FRange: TsCellRange3D;
|
FRange: TsCellRange3D;
|
||||||
public
|
public
|
||||||
procedure CopyFrom(AItem: TsDefinedName);
|
procedure CopyFrom(AItem: TsDefinedName);
|
||||||
|
function IllegalRef: Boolean;
|
||||||
function RangeAsString(AWorkbook: TsBasicWorkbook): String;
|
function RangeAsString(AWorkbook: TsBasicWorkbook): String;
|
||||||
function RangeAsString_ODS(AWorkbook: TsBasicWorkbook): String;
|
function RangeAsString_ODS(AWorkbook: TsBasicWorkbook): String;
|
||||||
|
procedure SetIllegalRef;
|
||||||
class function ValidName(AName: String): Boolean;
|
class function ValidName(AName: String): Boolean;
|
||||||
property Name: String read FName;
|
property Name: String read FName;
|
||||||
property Range: TsCellRange3D read FRange write FRange;
|
property Range: TsCellRange3D read FRange write FRange;
|
||||||
@ -244,8 +246,10 @@ type
|
|||||||
public
|
public
|
||||||
function Add(AName: String; ASheetIndex: Integer; ARow, ACol: Cardinal): Integer; overload;
|
function Add(AName: String; ASheetIndex: Integer; ARow, ACol: Cardinal): Integer; overload;
|
||||||
function Add(AName: String; ASheetIndex1, ASheetIndex2: Integer; ARow1, ACol1, ARow2, ACol2: Cardinal): Integer; overload;
|
function Add(AName: String; ASheetIndex1, ASheetIndex2: Integer; ARow1, ACol1, ARow2, ACol2: Cardinal): Integer; overload;
|
||||||
|
procedure DeleteRowOrCol(AWorksheetIndex, AColRowIndex: Integer; IsRow: Boolean);
|
||||||
function DuplicateName(AName: String): Boolean;
|
function DuplicateName(AName: String): Boolean;
|
||||||
function FindIndexOfName(AName: String): Integer;
|
function FindIndexOfName(AName: String): Integer;
|
||||||
|
procedure InsertRowOrCol(AWorksheetIndex, AColRowIndex: Integer; IsRow: Boolean);
|
||||||
property Items[AIndex: Integer]: TsDefinedName read GetItem write SetItem; default;
|
property Items[AIndex: Integer]: TsDefinedName read GetItem write SetItem; default;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1847,6 +1851,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TsDefinedName.IllegalRef: Boolean;
|
||||||
|
begin
|
||||||
|
Result := (FRange.Row1 = UNASSIGNED_ROW_COL_INDEX);
|
||||||
|
end;
|
||||||
|
|
||||||
// Test!$C$3
|
// Test!$C$3
|
||||||
function TsDefinedName.RangeAsString(AWorkbook: TsBasicWorkbook): String;
|
function TsDefinedName.RangeAsString(AWorkbook: TsBasicWorkbook): String;
|
||||||
var
|
var
|
||||||
@ -1858,7 +1867,10 @@ begin
|
|||||||
begin
|
begin
|
||||||
sh1 := book.GetWorksheetByIndex(Sheet1);
|
sh1 := book.GetWorksheetByIndex(Sheet1);
|
||||||
sh2 := book.GetWorksheetByIndex(Sheet2);
|
sh2 := book.GetWorksheetByIndex(Sheet2);
|
||||||
Result := GetCellRangeString(sh1.Name, sh2.Name, Row1, Col1, Row2, Col2, [], true);
|
if IllegalRef then
|
||||||
|
Result := Format('%s!%s', [sh1.Name, STR_ERR_ILLEGAL_REF])
|
||||||
|
else
|
||||||
|
Result := GetCellRangeString(sh1.Name, sh2.Name, Row1, Col1, Row2, Col2, [], true);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1872,6 +1884,11 @@ begin
|
|||||||
with FRange do
|
with FRange do
|
||||||
begin
|
begin
|
||||||
sh1 := book.GetWorksheetByIndex(Sheet1);
|
sh1 := book.GetWorksheetByIndex(Sheet1);
|
||||||
|
if IllegalRef then
|
||||||
|
begin
|
||||||
|
Result := Format('$%s!%s', [sh1.Name, STR_ERR_ILLEGAL_REF]); // Is '!' correct?
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
Result := Format('$%s.%s', [sh1.Name, GetCellString(Row1, Col1, [])]);
|
Result := Format('$%s.%s', [sh1.Name, GetCellString(Row1, Col1, [])]);
|
||||||
if (Sheet1 <> Sheet2) or (Row1 <> Row2) or (Col1 <> Col2) then
|
if (Sheet1 <> Sheet2) or (Row1 <> Row2) or (Col1 <> Col2) then
|
||||||
begin
|
begin
|
||||||
@ -1881,6 +1898,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsDefinedName.SetIllegalRef;
|
||||||
|
begin
|
||||||
|
FRange.Row1 := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
end;
|
||||||
|
|
||||||
// https://www.ablebits.com/office-addins-blog/excel-named-range/
|
// https://www.ablebits.com/office-addins-blog/excel-named-range/
|
||||||
class function TsDefinedName.ValidName(AName: string): Boolean;
|
class function TsDefinedName.ValidName(AName: string): Boolean;
|
||||||
const
|
const
|
||||||
@ -1953,6 +1975,51 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Adjusts the range extent when a row or column is deleted from the worksheet
|
||||||
|
with the given index. Note: Switches the defines names to #REF! when the
|
||||||
|
range is not valid after the deletion. }
|
||||||
|
procedure TsDefinedNames.DeleteRowOrCol(AWorksheetIndex, AColRowIndex: Integer;
|
||||||
|
IsRow: Boolean);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
item: TsDefinedName;
|
||||||
|
begin
|
||||||
|
for i := 0 to Count-1 do
|
||||||
|
begin
|
||||||
|
item := Items[i];
|
||||||
|
if (item.Range.Sheet1 <= AWorksheetIndex) and (AWorksheetIndex <= item.Range.Sheet2) then
|
||||||
|
begin
|
||||||
|
if IsRow then
|
||||||
|
begin
|
||||||
|
if (item.Range.Row1 = AColRowIndex) and (item.Range.Row2 = AColRowIndex) then
|
||||||
|
// Deleting the only row of the defined name's range --> #REF!
|
||||||
|
item.SetIllegalRef
|
||||||
|
else
|
||||||
|
if item.Range.Row1 <= AColRowIndex then
|
||||||
|
begin
|
||||||
|
dec(item.FRange.Row1);
|
||||||
|
dec(item.FRange.Row2);
|
||||||
|
end else
|
||||||
|
if AColRowIndex <= item.Range.Row2 then
|
||||||
|
dec(item.FRange.Row2);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if (item.Range.Col1 = AColRowIndex) and (item.Range.Col2 = AColRowIndex) then
|
||||||
|
// Deleting the only column of the defined name's range --> #REF!
|
||||||
|
item.SetIllegalRef
|
||||||
|
else
|
||||||
|
if item.Range.Col1 <= AColRowIndex then
|
||||||
|
begin
|
||||||
|
dec(item.FRange.Col1);
|
||||||
|
dec(item.FRange.Col2);
|
||||||
|
end else
|
||||||
|
if AColRowIndex <= item.Range.Col2 then
|
||||||
|
dec(item.FRange.Col2);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TsDefinedNames.DuplicateName(AName: String): Boolean;
|
function TsDefinedNames.DuplicateName(AName: String): Boolean;
|
||||||
begin
|
begin
|
||||||
Result := FindIndexOfName(AName) <> -1;
|
Result := FindIndexOfName(AName) <> -1;
|
||||||
@ -1971,6 +2038,43 @@ begin
|
|||||||
Result := TsDefinedName(inherited Items[AIndex]);
|
Result := TsDefinedName(inherited Items[AIndex]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ AWorksheetIndex: Index of the worksheet in which a row/column is inserted
|
||||||
|
AColRowIndex: Index of the row or column to be inserted
|
||||||
|
IsRow: Indicator whether AColRow refers to a row or column }
|
||||||
|
procedure TsDefinedNames.InsertRowOrCol(AWorksheetIndex, AColRowIndex: Integer;
|
||||||
|
IsRow: Boolean);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
item: TsDefinedName;
|
||||||
|
begin
|
||||||
|
for i := 0 to Count-1 do
|
||||||
|
begin
|
||||||
|
item := Items[i];
|
||||||
|
if (item.Range.Sheet1 <= AWorksheetIndex) and (AWorksheetIndex <= item.Range.Sheet2) then
|
||||||
|
begin
|
||||||
|
if IsRow then
|
||||||
|
begin
|
||||||
|
if item.Range.Row1 <= AColRowIndex then
|
||||||
|
begin
|
||||||
|
inc(item.FRange.Row1);
|
||||||
|
inc(item.FRange.Row2);
|
||||||
|
end else
|
||||||
|
if AColRowIndex <= item.Range.Row2 then
|
||||||
|
inc(item.FRange.Row2);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if item.Range.Col1 <= AColRowIndex then
|
||||||
|
begin
|
||||||
|
inc(item.FRange.Col1);
|
||||||
|
inc(item.FRange.Col2);
|
||||||
|
end else
|
||||||
|
if AColRowIndex <= item.Range.Col2 then
|
||||||
|
inc(item.FRange.Col2);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TsDefinedNames.SetItem(AIndex: Integer; AValue: TsDefinedName);
|
procedure TsDefinedNames.SetItem(AIndex: Integer; AValue: TsDefinedName);
|
||||||
begin
|
begin
|
||||||
TsDefinedName(inherited Items[AIndex]).CopyFrom(AValue);
|
TsDefinedName(inherited Items[AIndex]).CopyFrom(AValue);
|
||||||
|
|||||||
@ -2428,8 +2428,6 @@ var
|
|||||||
begin
|
begin
|
||||||
sheet := TsWorksheet(FWorksheet);
|
sheet := TsWorksheet(FWorksheet);
|
||||||
|
|
||||||
// FIXME: This code does not distinguish between local and global scope!
|
|
||||||
|
|
||||||
for i := 0 to sheet.Definednames.Count-1 do
|
for i := 0 to sheet.Definednames.Count-1 do
|
||||||
begin
|
begin
|
||||||
defName := sheet.DefinedNames[i];
|
defName := sheet.DefinedNames[i];
|
||||||
@ -4031,6 +4029,12 @@ begin
|
|||||||
c2 := Col2;
|
c2 := Col2;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if r1 = UNASSIGNED_ROW_COL_INDEX then
|
||||||
|
begin
|
||||||
|
AResult := ErrorResult(errIllegalRef);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
sheet := book.GetWorksheetByIndex(sheetIdx1);
|
sheet := book.GetWorksheetByIndex(sheetIdx1);
|
||||||
if (sheetIdx1 = sheetIdx2) and IsSingleCell(sheet, r1, c1, r2, c2) then
|
if (sheetIdx1 = sheetIdx2) and IsSingleCell(sheet, r1, c1, r2, c2) then
|
||||||
begin
|
begin
|
||||||
|
|||||||
@ -2642,10 +2642,13 @@ var
|
|||||||
nodeName: String;
|
nodeName: String;
|
||||||
defName: String;
|
defName: String;
|
||||||
defAddr: String;
|
defAddr: String;
|
||||||
|
defExpr: String;
|
||||||
r1, c1, r2, c2: Cardinal;
|
r1, c1, r2, c2: Cardinal;
|
||||||
sheetName1, sheetName2: String;
|
sheetName1, sheetName2: String;
|
||||||
sheetIdx1, sheetIdx2: Integer;
|
sheetIdx1, sheetIdx2: Integer;
|
||||||
flags: TsRelFlags;
|
flags: TsRelFlags;
|
||||||
|
err: TsErrorValue;
|
||||||
|
isDefName: Boolean;
|
||||||
begin
|
begin
|
||||||
if ANode = nil then
|
if ANode = nil then
|
||||||
exit;
|
exit;
|
||||||
@ -2660,11 +2663,25 @@ begin
|
|||||||
while ANode <> nil do
|
while ANode <> nil do
|
||||||
begin
|
begin
|
||||||
nodeName := ANode.NodeName;
|
nodeName := ANode.NodeName;
|
||||||
if nodeName = 'table:named-range' then
|
if nodeName = 'table:named-expression' then
|
||||||
begin
|
begin
|
||||||
defName := GetAttrValue(ANode, 'table:name');
|
defName := GetAttrValue(ANode, 'table:name');
|
||||||
defAddr := GetAttrValue(ANode, 'table:cell-range-address');
|
defAddr := GetAttrValue(ANode, 'table:cell-range-address');
|
||||||
|
defExpr := GetAttrValue(ANode, 'table:expression');
|
||||||
|
if TryStrToErrorValue(defExpr, '!', sheetName1, err) then // not clear whether '!' is correct; test file was created from Excel
|
||||||
|
begin
|
||||||
|
r1 := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
c1 := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
r2 := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
c2 := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
sheetName2 := sheetName1;
|
||||||
|
isDefName := true;
|
||||||
|
end else
|
||||||
if TryStrToCellRange_ODS(defAddr, sheetName1, sheetName2, r1, c1, r2, c2, flags) then
|
if TryStrToCellRange_ODS(defAddr, sheetName1, sheetName2, r1, c1, r2, c2, flags) then
|
||||||
|
isDefName := true
|
||||||
|
else
|
||||||
|
isDefName := false;
|
||||||
|
if isDefName then
|
||||||
begin
|
begin
|
||||||
if (sheetName1 <> '') and (sheetName1[1] = '$') then Delete(sheetName1, 1,1);
|
if (sheetName1 <> '') and (sheetName1[1] = '$') then Delete(sheetName1, 1,1);
|
||||||
if (sheetName2 <> '') and (sheetName2[1] = '$') then Delete(sheetName2, 1,1);
|
if (sheetName2 <> '') and (sheetName2[1] = '$') then Delete(sheetName2, 1,1);
|
||||||
|
|||||||
@ -2208,7 +2208,7 @@ begin
|
|||||||
if HasFormula(ACell) then
|
if HasFormula(ACell) then
|
||||||
WriteFormula(ACell, '');
|
WriteFormula(ACell, '');
|
||||||
|
|
||||||
// To do: Check if the cell is referencec by a formula. In this case we have
|
// To do: Check if the cell is referenced by a formula. In this case we have
|
||||||
// a #REF! error.
|
// a #REF! error.
|
||||||
|
|
||||||
// Cell is part of a merged block? --> Erase content, formatting etc.
|
// Cell is part of a merged block? --> Erase content, formatting etc.
|
||||||
@ -5821,6 +5821,15 @@ begin
|
|||||||
// Fix conditional formats
|
// Fix conditional formats
|
||||||
FWorkbook.FConditionalFormatList.DeleteRowOrCol(Self, AIndex, IsRow);
|
FWorkbook.FConditionalFormatList.DeleteRowOrCol(Self, AIndex, IsRow);
|
||||||
|
|
||||||
|
// Fix defined names
|
||||||
|
i := FWorkbook.GetWorksheetIndex(Self);
|
||||||
|
FWorkbook.DefinedNames.DeleteRowOrCol(i, AIndex, IsRow);
|
||||||
|
for i := 0 to FWorkbook.GetWorksheetCount-1 do
|
||||||
|
begin
|
||||||
|
sheet := FWorkbook.GetWorksheetByIndex(i);
|
||||||
|
sheet.DefinedNames.DeleteRowOrCol(i, AIndex, IsRow);
|
||||||
|
end;
|
||||||
|
|
||||||
// Fix formulas:
|
// Fix formulas:
|
||||||
// 1) Fix Row/Col index of in-sheet formulas
|
// 1) Fix Row/Col index of in-sheet formulas
|
||||||
FFormulas.DeleteRowOrCol(AIndex, IsRow);
|
FFormulas.DeleteRowOrCol(AIndex, IsRow);
|
||||||
@ -5923,6 +5932,15 @@ begin
|
|||||||
// Update range of conditional formats
|
// Update range of conditional formats
|
||||||
FWorkbook.FConditionalFormatList.InsertRowOrCol(Self, AIndex, IsRow);
|
FWorkbook.FConditionalFormatList.InsertRowOrCol(Self, AIndex, IsRow);
|
||||||
|
|
||||||
|
// Fix defined names
|
||||||
|
i := FWorkbook.GetWorksheetIndex(self);
|
||||||
|
FWorkbook.DefinedNames.InsertRowOrCol(i, AIndex, IsRow);
|
||||||
|
for i := 0 to FWorkbook.GetWorksheetCount-1 do
|
||||||
|
begin
|
||||||
|
sheet := FWorkbook.GetWorksheetByIndex(i);
|
||||||
|
sheet.DefinedNames.InsertRowOrCol(i, AIndex, IsRow);
|
||||||
|
end;
|
||||||
|
|
||||||
// Fix formulas:
|
// Fix formulas:
|
||||||
// 1) Update Row/Col index of in-sheet formulas
|
// 1) Update Row/Col index of in-sheet formulas
|
||||||
FFormulas.InsertRowOrCol(AIndex, IsRow);
|
FFormulas.InsertRowOrCol(AIndex, IsRow);
|
||||||
|
|||||||
@ -145,6 +145,8 @@ function GetSheetCellRangeString_ODS(ASheet1, ASheet2: String;
|
|||||||
|
|
||||||
function GetErrorValueStr(AErrorValue: TsErrorValue): String;
|
function GetErrorValueStr(AErrorValue: TsErrorValue): String;
|
||||||
function TryStrToErrorValue(AErrorStr: String; out AErr: TsErrorValue): boolean;
|
function TryStrToErrorValue(AErrorStr: String; out AErr: TsErrorValue): boolean;
|
||||||
|
function TryStrToErrorValue(AErrorStr: String; SheetSep: Char;
|
||||||
|
out ASheetName: String; out AErr: TsErrorValue): Boolean;
|
||||||
|
|
||||||
function GetFileFormatName(AFormat: TsSpreadsheetFormat): string; deprecated;
|
function GetFileFormatName(AFormat: TsSpreadsheetFormat): string; deprecated;
|
||||||
//function GetFileFormatExt(AFormat: TsSpreadsheetFormat): String;
|
//function GetFileFormatExt(AFormat: TsSpreadsheetFormat): String;
|
||||||
@ -1506,7 +1508,7 @@ end;
|
|||||||
function TryStrToErrorValue(AErrorStr: String; out AErr: TsErrorValue): boolean;
|
function TryStrToErrorValue(AErrorStr: String; out AErr: TsErrorValue): boolean;
|
||||||
begin
|
begin
|
||||||
Result := true;
|
Result := true;
|
||||||
case AErrorStr of
|
case Uppercase(AErrorStr) of
|
||||||
STR_ERR_EMPTY_INTERSECTION : AErr := errEmptyIntersection; // #NULL!
|
STR_ERR_EMPTY_INTERSECTION : AErr := errEmptyIntersection; // #NULL!
|
||||||
STR_ERR_DIVIDE_BY_ZERO : AErr := errDivideByZero; // #DIV/0!
|
STR_ERR_DIVIDE_BY_ZERO : AErr := errDivideByZero; // #DIV/0!
|
||||||
STR_ERR_WRONG_TYPE : AErr := errWrongType; // #VALUE!
|
STR_ERR_WRONG_TYPE : AErr := errWrongType; // #VALUE!
|
||||||
@ -1520,6 +1522,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TryStrToErrorValue(AErrorStr: String; SheetSep: Char;
|
||||||
|
out ASheetName: String; out AErr: TsErrorValue): Boolean;
|
||||||
|
var
|
||||||
|
p: Integer;
|
||||||
|
begin
|
||||||
|
p := pos(SheetSep, AErrorStr);
|
||||||
|
if p > 0 then
|
||||||
|
begin
|
||||||
|
ASheetName := Copy(AErrorStr, 1, p-1);
|
||||||
|
AErrorStr := Copy(AErrorStr, p+1, Length(AErrorStr));
|
||||||
|
end else
|
||||||
|
ASheetName := '';
|
||||||
|
Result := TryStrToErrorValue(AErrorStr, AErr);
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Returns the message text assigned to an error value
|
Returns the message text assigned to an error value
|
||||||
|
|
||||||
|
|||||||
@ -2377,6 +2377,8 @@ var
|
|||||||
namestr: String;
|
namestr: String;
|
||||||
s, sheetname1, sheetName2: String;
|
s, sheetname1, sheetName2: String;
|
||||||
sheetIdx1, sheetIdx2: Integer;
|
sheetIdx1, sheetIdx2: Integer;
|
||||||
|
isDefinedName: Boolean;
|
||||||
|
err: TsErrorValue;
|
||||||
L: TStringList;
|
L: TStringList;
|
||||||
begin
|
begin
|
||||||
if ANode = nil then
|
if ANode = nil then
|
||||||
@ -2468,12 +2470,26 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
// "Normal" defined names
|
// "Normal" defined names
|
||||||
|
isDefinedName := false;
|
||||||
s := GetNodeValue(node);
|
s := GetNodeValue(node);
|
||||||
|
if TryStrToErrorValue(s, '!', sheetName1, err) then
|
||||||
|
begin
|
||||||
|
r1 := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
r2 := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
c1 := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
c2 := UNASSIGNED_ROW_COL_INDEX;
|
||||||
|
sheetName2 := sheetName1;
|
||||||
|
isDefinedName := true;
|
||||||
|
end else
|
||||||
if ParseCellRangeString(s, sheetName1, sheetName2, r1, c1, r2, c2, flags) then
|
if ParseCellRangeString(s, sheetName1, sheetName2, r1, c1, r2, c2, flags) then
|
||||||
begin
|
begin
|
||||||
if (r2 = UNASSIGNED_ROW_COL_INDEX) then r2 := r1;
|
if (r2 = UNASSIGNED_ROW_COL_INDEX) then r2 := r1;
|
||||||
if (c2 = UNASSIGNED_ROW_COL_INDEX) then c2 := c1;
|
if (c2 = UNASSIGNED_ROW_COL_INDEX) then c2 := c1;
|
||||||
if sheetName2 = '' then sheetName2 := sheetName1;
|
if sheetName2 = '' then sheetName2 := sheetName1;
|
||||||
|
isDefinedName := true;
|
||||||
|
end;
|
||||||
|
if isDefinedName then
|
||||||
|
begin
|
||||||
sheetIdx1 := book.GetWorksheetIndex(sheetName1);
|
sheetIdx1 := book.GetWorksheetIndex(sheetName1);
|
||||||
sheetIdx2 := book.GetWorksheetIndex(sheetName2);
|
sheetIdx2 := book.GetWorksheetIndex(sheetName2);
|
||||||
s := GetAttrValue(node, 'localSheetId');
|
s := GetAttrValue(node, 'localSheetId');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user