diff --git a/components/fpspreadsheet/examples/spready/mainform.lfm b/components/fpspreadsheet/examples/spready/mainform.lfm index f7ca69e26..69c3569f5 100644 --- a/components/fpspreadsheet/examples/spready/mainform.lfm +++ b/components/fpspreadsheet/examples/spready/mainform.lfm @@ -188,7 +188,7 @@ object Form1: TForm1 Action = AcSaveAs end object ToolButton3: TToolButton - Left = 103 + Left = 149 Top = 0 Action = AcQuit end @@ -205,7 +205,7 @@ object Form1: TForm1 Action = AcEdit end object ToolButton6: TToolButton - Left = 98 + Left = 144 Top = 0 Width = 5 Caption = 'ToolButton6' @@ -216,6 +216,16 @@ object Form1: TForm1 Top = 0 Action = AcNew end + object ToolButton23: TToolButton + Left = 98 + Top = 0 + Action = AcAddColumn + end + object ToolButton27: TToolButton + Left = 121 + Top = 0 + Action = AcAddRow + end end object FormatToolBar: TToolBar Left = 0 @@ -647,6 +657,15 @@ object Form1: TForm1 FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } end + object MenuItem64: TMenuItem + Caption = '-' + end + object MenuItem65: TMenuItem + Action = AcAddColumn + end + object MenuItem66: TMenuItem + Action = AcAddRow + end end object mnuFormat: TMenuItem Caption = 'Format' @@ -1067,7 +1086,7 @@ object Form1: TForm1 left = 272 top = 264 Bitmap = { - 4C69230000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + 4C69250000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00EAC39DFFE6BF96FFE4BB92FFE4BB92FFD1A06CF5D09E6DF6CC96 5FDAC479427EB2673C09FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00E5BE96FFFFFFFEFFFDF3E9FFFDF3EAFFFCF2E8FFFAEFE3FFFAF2 @@ -2187,7 +2206,71 @@ object Form1: TForm1 FCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFC FCFDF9F9F9F300000033FFFFFF00FFFFFF000000001D00000034000000360000 0036000000360000003600000036000000360000003600000036000000360000 - 0036000000330000001DFFFFFF00 + 0036000000330000001DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00A2AE8EFF5F9771FF4F8E + 66FF49895FFFA2AE8EFFFFFFFF00FFFFFF00EFC2A37EEFC1A2E3EDC09FFFEBBE + 9DFFEBBC9AFFE9BA96FFE7B793FFE6B590FF9DAF91FF61AB81FF95D4B4FFBAE6 + D0FF6ABB8FFF2D8F57FF196B378CFFFFFF00EEC1A1EBFBF7F4FFFBF7F4FFFBF7 + F4FFFBF7F4FFFBF7F4FFFBF7F4FFFBF7F4FF498960FF90D3B1FF92D6B1FFFFFF + FFFF65BC8CFF67BC8FFF196B37F7FFFFFF00ECBF9EFFFBF7F4FF9CD5A5FF98D3 + A1FF94D09DFF90CE98FF8BCB93FF87C98EFF317B4CFF9CD4B6FFFFFFFFFFFFFF + FFFFFFFFFFFF95D2B2FF196B37FFFFFFFF00EBBD9BFFFBF7F4FFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22703EFF62BA8BFF60BA87FFFFFF + FFFF60B987FF67BC8FFF196B37F7FFFFFF00E9BA98FFFBF7F4FFE9C3A6FFE9C3 + A6FFE9C3A6FFE9C3A6FFE9C3A6FFE9C3A6FFA2AE8EFF288C53FF64BA8DFF95D2 + B2FF64BA8DFF288C53FF196B378CFFFFFF00E7B794FFFBF7F4FFE9C3A6FFFFFF + FFFFE8C4A9FFFFFFFFFFFFFFFFFFFFFFFFFFE8C7ACFF84B094FF257341FF196B + 37FF247240FF6C7C4AFFFFFFFF00FFFFFF00E5B48FFFFAF6F2FFE9C6AAFFE9C6 + ACFFEAC7ACFFE9C7ADFFE9C9AEFFE9C9B0FFE8C7ACFFE9C9B0FFE8C8B0FFE8CC + B5FFF2E7DEFFC88A59FFFFFFFF00FFFFFF00E3B18CFFFAF6F1FFEAC9AEFFFFFF + FFFFEAC9B0FFFFFFFFFFFFFFFFFFFFFFFFFFE8C7ACFFFFFFFFFFFFFFFFFFFFFF + FFFFF1E5DBFFC68655FFFFFFFF00FFFFFF00E1AE87FFFAF4F0FF59B163FF54AB + 5EFF4FA358FF4FA358FF489B51FF42924AFF3B8842FF347E3AFF2E7533FF276D + 2CFFF0E2D8FFC48654FFFFFFFF00FFFFFF00DFAA82FFF9F3EFFF58B162FFB9DF + BDFFB6DDBAFFB6DDBAFFACD8B0FFA0D3A4FF92CC97FF84C68AFF79C17EFF2265 + 26FFF0E2D8FFC88D5FFFFFFFFF00FFFFFF00DDA87EFFF9F3EFFF4FA358FF489B + 51FF42924AFF42924AFF3B8842FF347E3AFF2E7533FF276D2CFF226526FF1D5F + 21FFF0E2D8FFC68A5CFFFFFFFF00FFFFFF00D9A47AFFF9F3EEFFEBD2BEFFFFFF + FFFFEBD3BFFFFFFFFFFFFFFFFFFFFFFFFFFFEAC7ADFFFFFFFFFFFFFFFFFFFFFF + FFFFF0E2D8FFC68C5FFFFFFFFF00FFFFFF00D7A175FFF8F2EDFFF7F0EAFFF6ED + E6FFF4EAE2FFF3E7DEFFF1E4DBFFF0E2D8FFF0E2D8FFF0E2D8FFF0E2D8FFF0E2 + D8FFF0E2D8FFC58A5DFDFFFFFF00FFFFFF00D69E72C4D3996EF4D19668FFCE92 + 63FFCB8E5EFFC98A5BFFC78756FFC38452FFC38452FFC38452FFC38452FFC384 + 52FFC38452FFBB7742B0FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00A2AE8EFF5F9771FF4F8E + 66FF49895FFFA2AE8EFFFFFFFF00FFFFFF00EFC2A37EEFC1A2E3EDC09FFFEBBE + 9DFFEBBC9AFFE9BA96FFE7B793FFE6B590FF9DAF91FF61AB81FF95D4B4FFBAE6 + D0FF6ABB8FFF2D8F57FF196B378CFFFFFF00EEC1A1EBFBF7F4FFFBF7F4FFFBF7 + F4FFFBF7F4FFFBF7F4FFFBF7F4FFFBF7F4FF498960FF90D3B1FF92D6B1FFFFFF + FFFF65BC8CFF67BC8FFF196B37F7FFFFFF00ECBF9EFFFBF7F4FF9CD5A5FF98D3 + A1FF94D09DFF90CE98FF8BCB93FF87C98EFF317B4CFF9CD4B6FFFFFFFFFFFFFF + FFFFFFFFFFFF95D2B2FF196B37FFFFFFFF00EBBD9BFFFBF7F4FFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22703EFF62BA8BFF60BA87FFFFFF + FFFF60B987FF67BC8FFF196B37F7FFFFFF00E9BA98FFFBF7F4FF4FA358FF4FA3 + 58FF59B163FFE9C3A6FFE9C3A6FFE9C3A6FFA2AE8EFF288C53FF64BA8DFF95D2 + B2FF64BA8DFF288C53FF196B378CFFFFFF00E7B794FFFBF7F4FF489B51FFB9DF + BDFF54AB5EFFFFFFFFFFFFFFFFFFFFFFFFFFE8C7ACFF84B094FF257341FF196B + 37FF247240FF6C7C4AFFFFFFFF00FFFFFF00E5B48FFFFAF6F2FF42924AFFB6DD + BAFF4FA358FFE9C7ADFFE9C9AEFFE9C9B0FFE8C7ACFFE9C9B0FFE8C8B0FFE8CC + B5FFF2E7DEFFC88A59FFFFFFFF00FFFFFF00E3B18CFFFAF6F1FF3B8842FFACD8 + B0FF489B51FFFFFFFFFFFFFFFFFFFFFFFFFFE8C7ACFFFFFFFFFFFFFFFFFFFFFF + FFFFF1E5DBFFC68655FFFFFFFF00FFFFFF00E1AE87FFFAF4F0FF347E3AFFA0D3 + A4FF42924AFFEACCB3FFEACCB3FFEACEB7FFE8C7ACFFE8C7ACFFE8C8B0FFE8C8 + AEFFF0E2D8FFC48654FFFFFFFF00FFFFFF00DFAA82FFF9F3EFFF2E7533FF92CC + 97FF3B8842FFFFFFFFFFFFFFFFFFFFFFFFFFEACFBAFFFBF6F2FFFFFFFFFFFFFF + FFFFF0E2D8FFC88D5FFFFFFFFF00FFFFFF00DDA87EFFF9F3EFFF276D2CFF84C6 + 8AFF347E3AFFEBD0BBFFEBD0BBFFEBD1BDFFEACDB5FFEACDB5FFEACDB5FFEACD + B5FFF0E2D8FFC68A5CFFFFFFFF00FFFFFF00D9A47AFFF9F3EEFF1D5F21FF2265 + 26FF276D2CFFFFFFFFFFFFFFFFFFFFFFFFFFEAC7ADFFFFFFFFFFFFFFFFFFFFFF + FFFFF0E2D8FFC68C5FFFFFFFFF00FFFFFF00D7A175FFF8F2EDFFF7F0EAFFF6ED + E6FFF4EAE2FFF3E7DEFFF1E4DBFFF0E2D8FFF0E2D8FFF0E2D8FFF0E2D8FFF0E2 + D8FFF0E2D8FFC58A5DFDFFFFFF00FFFFFF00D69E72C4D3996EF4D19668FFCE92 + 63FFCB8E5EFFC98A5BFFC78756FFC38452FFC38452FFC38452FFC38452FFC384 + 52FFC38452FFBB7742B0FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00 } end object ActionList: TActionList @@ -2619,6 +2702,20 @@ object Form1: TForm1 ImageIndex = 3 OnExecute = AcEditExecute end + object AcAddColumn: TAction + Category = 'Edit' + Caption = 'Add column' + Hint = 'Add column' + ImageIndex = 36 + OnExecute = AcAddColumnExecute + end + object AcAddRow: TAction + Category = 'Edit' + Caption = 'Add row' + Hint = 'Add row' + ImageIndex = 35 + OnExecute = AcAddRowExecute + end end object FontDialog: TFontDialog MinFontSize = 0 diff --git a/components/fpspreadsheet/examples/spready/mainform.pas b/components/fpspreadsheet/examples/spready/mainform.pas index ad887cdd2..e3df2bb03 100644 --- a/components/fpspreadsheet/examples/spready/mainform.pas +++ b/components/fpspreadsheet/examples/spready/mainform.pas @@ -69,6 +69,8 @@ type AcNFCusstomMS: TAction; AcNFCustomMSZ: TAction; AcNew: TAction; + AcAddColumn: TAction; + AcAddRow: TAction; AcWordwrap: TAction; AcVAlignDefault: TAction; AcVAlignTop: TAction; @@ -146,6 +148,9 @@ type MenuItem61: TMenuItem; MenuItem62: TMenuItem; MenuItem63: TMenuItem; + MenuItem64: TMenuItem; + MenuItem65: TMenuItem; + MenuItem66: TMenuItem; MnuFmtDateTimeMSZ: TMenuItem; MnuTimeInterval: TMenuItem; MnuShortTimeAM: TMenuItem; @@ -198,6 +203,8 @@ type FormulaToolBar: TToolBar; FormulaToolbarSplitter: TSplitter; ToolButton22: TToolButton; + ToolButton23: TToolButton; + ToolButton27: TToolButton; WorksheetGrid: TsWorksheetGrid; TabSheet1: TTabSheet; ToolBar1: TToolBar; @@ -228,6 +235,8 @@ type ToolButton7: TToolButton; ToolButton8: TToolButton; ToolButton9: TToolButton; + procedure AcAddColumnExecute(Sender: TObject); + procedure AcAddRowExecute(Sender: TObject); procedure AcBorderExecute(Sender: TObject); procedure AcCopyFormatExecute(Sender: TObject); procedure AcEditExecute(Sender: TObject); @@ -407,6 +416,18 @@ begin end; end; +procedure TForm1.AcAddColumnExecute(Sender: TObject); +begin + WorksheetGrid.InsertCol(WorksheetGrid.Col); + WorksheetGrid.Col := WorksheetGrid.Col + 1; +end; + +procedure TForm1.AcAddRowExecute(Sender: TObject); +begin + WorksheetGrid.InsertRow(WorksheetGrid.Row); + WorksheetGrid.Row := WorksheetGrid.Row + 1; +end; + procedure TForm1.AcCopyFormatExecute(Sender: TObject); var cell: PCell; diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index cdd63f3f8..ebd8b122e 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -502,6 +502,8 @@ type { Callback procedures called when iterating through all cells } procedure CalcFormulaCallback(data, arg: Pointer); procedure CalcStateCallback(data, arg: Pointer); + procedure InsertColCallback(data, arg: Pointer); + procedure InsertRowCallback(data, arg: Pointer); procedure RemoveCallback(data, arg: pointer); protected @@ -667,6 +669,8 @@ type function GetRowHeight(ARow: Cardinal): Single; function GetCol(ACol: Cardinal): PCol; function GetColWidth(ACol: Cardinal): Single; + procedure InsertCol(ACol: Cardinal); + procedure InsertRow(ARow: Cardinal); procedure RemoveAllRows; procedure RemoveAllCols; procedure WriteRowInfo(ARow: Cardinal; AData: TRow); @@ -3829,8 +3833,10 @@ begin FillChar(Result^, SizeOf(TRow), #0); Result^.Row := ARow; FRows.Add(Result); - if FLastRowIndex = 0 then FLastRowIndex := GetLastRowIndex(true) - else FLastRowIndex := Max(FLastRowIndex, ARow); + if FLastRowIndex = 0 then + FLastRowIndex := GetLastRowIndex(true) + else + FLastRowIndex := Max(FLastRowIndex, ARow); end; end; @@ -3849,8 +3855,10 @@ begin FillChar(Result^, SizeOf(TCol), #0); Result^.Col := ACol; FCols.Add(Result); - if FLastColIndex = 0 then FLastColIndex := GetLastColIndex(true) - else FLastColIndex := Max(FLastColIndex, ACol); + if FLastColIndex = 0 then + FLastColIndex := GetLastColIndex(true) + else + FLastColIndex := Max(FLastColIndex, ACol); end; end; @@ -3940,6 +3948,130 @@ begin Result := FWorkbook.DefaultRowHeight; end; +procedure TsWorksheet.InsertColCallback(data, arg: Pointer); +var + cell: PCell; + col: PtrInt; + fe: TsFormulaElement; + i: Integer; +begin + col := PtrInt(arg); + cell := PCell(data); + + // Update column index of moved cells + if cell^.Col >= col then + inc(cell^.Col); + + // Update rpn formulas + for i:=0 to Length(cell^.RPNFormulaValue)-1 do begin + fe := cell^.RPNFormulaValue[i]; // "fe" means "formula element" + case fe.ElementKind of + fekCell, fekCellRef: if fe.Col >= col then inc(fe.Col); + fekCellRange: + begin + if fe.Col >= col then inc(fe.Col); + if fe.Col2 >= col then inc(fe.Col2); + end; + end; + end; +end; + +{@@ + Inserts a column BEFORE the index specified. Cells with greater column indexes are + moved one column up. Cell references in rpn formulas are considered as well. + However, lacking a parser for string formulas, references in string formulas + are not changed which may lead to incorrect operation! + + @param ACol Index of the column before which a new column is inserted. +} +procedure TsWorksheet.InsertCol(ACol: Cardinal); +var + cellnode: TAVLTreeNode; + cell: PCell; + col: PCol; + i: Integer; +begin + // Update column index of cell records + cellnode := FCells.FindLowest; + while Assigned(cellnode) do begin + InsertColCallback(cellnode.Data, pointer(PtrInt(ACol))); + cellnode := FCells.FindSuccessor(cellnode); + end; + + // Update column index of column records + for i:=0 to FCols.Count-1 do begin + col := PCol(FCols.Items[i]); + if col^.Col >= ACol then inc(col^.Col); + end; + + // Update last column index + inc(FLastColIndex); + + ChangedCell(0, ACol); +end; + +procedure TsWorksheet.InsertRowCallback(data, arg: Pointer); +var + cell: PCell; + row: PtrInt; + i: Integer; + fe: TsFormulaElement; +begin + row := PtrInt(arg); + cell := PCell(data); + + // Update row index of moved cells + if cell^.Row >= row then + inc(cell^.Row); + + // Update rpn formulas + for i:=0 to Length(cell^.RPNFormulaValue)-1 do begin + fe := cell^.RPNFormulaValue[i]; // "fe" means "formula element" + case fe.ElementKind of + fekCell, fekCellRef: if fe.Row >= row then inc(fe.Row); + fekCellRange: + begin + if fe.Row >= row then inc(fe.Row); + if fe.Row2 >= row then inc(fe.Row2); + end; + end; + end; +end; + +{@@ + Inserts a row BEFORE the row specified. Cells with greater row indexes are + moved one row up. Cell references in rpn formulas are considered as well. + However, lacking a parser for string formulas, references in string formulas + are not changed which may lead to incorrect operation! + + @param ARow Index of the row before which a new row is inserted. +} +procedure TsWorksheet.InsertRow(ARow: Cardinal); +var + cell: PCell; + row: PRow; + cellnode: TAVLTreeNode; + i: Integer; +begin + // Update row index of cell records + cellnode := FCells.FindLowest; + while Assigned(cellnode) do begin + InsertRowCallback(cellnode.Data, pointer(PtrInt(ARow))); + cellnode := FCells.FindSuccessor(cellnode); + end; + + // Update row index of row records + for i:=0 to FRows.Count-1 do begin + row := PRow(FRows.Items[i]); + if row^.Row >= ARow then inc(row^.Row); + end; + + // Update last row index + inc(FLastRowIndex); + + ChangedCell(ARow, 0); +end; + {@@ Removes all row records from the worksheet and frees the occupied memory. Note: Cells are retained. diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas index f8db58b27..829acdfed 100644 --- a/components/fpspreadsheet/fpspreadsheetgrid.pas +++ b/components/fpspreadsheet/fpspreadsheetgrid.pas @@ -138,6 +138,8 @@ type procedure SelectEditor; override; procedure SetEditText(ACol, ARow: Longint; const AValue: string); override; procedure Setup; + procedure UpdateColWidths(AStartIndex: Integer = 0); + procedure UpdateRowHeights(AStartIndex: Integer = 0); {@@ Displays column and row headers in the fixed col/row style of the grid. Deprecated. Use ShowHeaders instead. } property DisplayFixedColRow: Boolean read GetShowHeaders write SetShowHeaders default true; @@ -168,6 +170,8 @@ type function GetGridRow(ASheetRow: Cardinal): Integer; function GetWorksheetCol(AGridCol: Integer): Cardinal; function GetWorksheetRow(AGridRow: Integer): Cardinal; + procedure InsertCol(AGridCol: Integer); + procedure InsertRow(AGridRow: Integer); procedure LoadFromSpreadsheetFile(AFileName: string; AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = 0); overload; procedure LoadFromSpreadsheetFile(AFileName: string; @@ -2235,6 +2239,41 @@ begin end; end; +{@@ + Inserts an empty column before the column specified +} +procedure TsCustomWorksheetGrid.InsertCol(AGridCol: Integer); +var + c: Cardinal; +begin + if AGridCol < FHeaderCount then + exit; + + if FWorksheet.GetLastColIndex+1 + FHeaderCount >= FInitColCount then + ColCount := ColCount + 1; + c := AGridCol - FHeaderCount; + FWorksheet.InsertCol(c); + + UpdateColWidths(AGridCol); +end; + +{@@ + Inserts an empty row before the row specified +} +procedure TsCustomWorksheetGrid.InsertRow(AGridRow: Integer); +var + r: Cardinal; +begin + if AGridRow < FHeaderCount then + exit; + + if FWorksheet.GetlastRowIndex+1 + FHeaderCount >= FInitRowCount then + RowCount := RowCount + 1; + r := AGridRow - FHeaderCount; + FWorksheet.InsertRow(r); + + UpdateRowHeights(AGridRow); +end; {@@ Internal general text drawing method. @@ -2855,20 +2894,8 @@ begin ColWidths[0] := Canvas.TextWidth(' 999999 '); RowHeights[0] := DefaultRowHeight; end; - for i := FHeaderCount to ColCount-1 do begin - lCol := FWorksheet.FindCol(i - FHeaderCount); - if (lCol <> nil) then - ColWidths[i] := CalcColWidth(lCol^.Width) - else - ColWidths[i] := DefaultColWidth; - end; - for i := FHeaderCount to RowCount-1 do begin - lRow := FWorksheet.FindRow(i - FHeaderCount); - if (lRow = nil) then - RowHeights[i] := CalcAutoRowHeight(i) - else - RowHeights[i] := CalcRowHeight(lRow^.Height); - end; + UpdateColWidths; + UpdateRowHeights; end; Invalidate; end; @@ -2917,6 +2944,36 @@ begin end; end; +procedure TsCustomWorksheetGrid.UpdateColWidths(AStartIndex: Integer = 0); +var + i: Integer; + lCol: PCol; +begin + if AStartIndex = 0 then AStartIndex := FHeaderCount; + for i := AStartIndex to ColCount-1 do begin + lCol := FWorksheet.FindCol(i - FHeaderCount); + if lCol <> nil then + ColWidths[i] := CalcColWidth(lCol^.Width) + else + ColWidths[i] := DefaultColWidth; + end; +end; + +procedure TsCustomWorksheetGrid.UpdateRowHeights(AStartIndex: Integer = 0); +var + i: Integer; + lRow: PRow; +begin + if AStartIndex <= 0 then AStartIndex := FHeaderCount; + for i := AStartIndex to RowCount-1 do begin + lRow := FWorksheet.FindRow(i - FHeaderCount); + if (lRow = nil) then + RowHeights[i] := CalcAutoRowHeight(i) + else + RowHeights[i] := CalcRowHeight(lRow^.Height); + end; +end; + {@@ Loads the worksheet into the grid and displays its contents.