diff --git a/components/fpspreadsheet/examples/fpsvisual/fpsvisual.ico b/components/fpspreadsheet/examples/fpsvisual/fpsvisual.ico
new file mode 100644
index 000000000..0341321b5
Binary files /dev/null and b/components/fpspreadsheet/examples/fpsvisual/fpsvisual.ico differ
diff --git a/components/fpspreadsheet/examples/fpsvisual/fpsvisual.lpi b/components/fpspreadsheet/examples/fpsvisual/fpsvisual.lpi
new file mode 100644
index 000000000..913da8eff
--- /dev/null
+++ b/components/fpspreadsheet/examples/fpsvisual/fpsvisual.lpi
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/fpspreadsheet/examples/fpsvisual/fpsvisual.lpr b/components/fpspreadsheet/examples/fpsvisual/fpsvisual.lpr
new file mode 100644
index 000000000..2f5bd0480
--- /dev/null
+++ b/components/fpspreadsheet/examples/fpsvisual/fpsvisual.lpr
@@ -0,0 +1,21 @@
+program fpsvisual;
+
+{$mode objfpc}{$H+}
+
+uses
+ {$IFDEF UNIX}{$IFDEF UseCThreads}
+ cthreads,
+ {$ENDIF}{$ENDIF}
+ Interfaces, // this includes the LCL widgetset
+ Forms, mainform, LResources, laz_fpspreadsheet_visual
+ { you can add units after this };
+
+{$IFDEF WINDOWS}{$R fpsvisual.rc}{$ENDIF}
+
+begin
+ {$I fpsvisual.lrs}
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
+
diff --git a/components/fpspreadsheet/examples/fpsvisual/fpsvisual.manifest b/components/fpspreadsheet/examples/fpsvisual/fpsvisual.manifest
new file mode 100644
index 000000000..515fedeef
--- /dev/null
+++ b/components/fpspreadsheet/examples/fpsvisual/fpsvisual.manifest
@@ -0,0 +1,17 @@
+
+
+
+ Your application description here.
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/fpspreadsheet/examples/fpsvisual/fpsvisual.rc b/components/fpspreadsheet/examples/fpsvisual/fpsvisual.rc
new file mode 100644
index 000000000..38c4c6053
--- /dev/null
+++ b/components/fpspreadsheet/examples/fpsvisual/fpsvisual.rc
@@ -0,0 +1,7 @@
+#define RT_MANIFEST 24
+#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
+#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2
+#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3
+
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "fpsvisual.manifest"
+MAINICON ICON "fpsvisual.ico"
diff --git a/components/fpspreadsheet/examples/fpsvisual/mainform.lfm b/components/fpspreadsheet/examples/fpsvisual/mainform.lfm
new file mode 100644
index 000000000..3d0c301d5
--- /dev/null
+++ b/components/fpspreadsheet/examples/fpsvisual/mainform.lfm
@@ -0,0 +1,26 @@
+object Form1: TForm1
+ Left = 288
+ Height = 300
+ Top = 204
+ Width = 400
+ Caption = 'FPSVisual'
+ ClientHeight = 300
+ ClientWidth = 400
+ LCLVersion = '0.9.29'
+ object sWorksheetGrid1: TsWorksheetGrid
+ Left = 8
+ Height = 232
+ Top = 8
+ Width = 384
+ TabOrder = 0
+ end
+ object buttonPopulateGrid: TButton
+ Left = 144
+ Height = 25
+ Top = 256
+ Width = 112
+ Caption = 'Populate Grid'
+ OnClick = buttonPopulateGridClick
+ TabOrder = 1
+ end
+end
diff --git a/components/fpspreadsheet/examples/fpsvisual/mainform.lrs b/components/fpspreadsheet/examples/fpsvisual/mainform.lrs
new file mode 100644
index 000000000..5c87f3ceb
--- /dev/null
+++ b/components/fpspreadsheet/examples/fpsvisual/mainform.lrs
@@ -0,0 +1,11 @@
+{ This is an automatically generated lazarus resource file }
+
+LazarusResources.Add('TForm1','FORMDATA',[
+ 'TPF0'#6'TForm1'#5'Form1'#4'Left'#3' '#1#6'Height'#3','#1#3'Top'#3#204#0#5'Wi'
+ +'dth'#3#144#1#7'Caption'#6#9'FPSVisual'#12'ClientHeight'#3','#1#11'ClientWid'
+ +'th'#3#144#1#10'LCLVersion'#6#6'0.9.29'#0#15'TsWorksheetGrid'#15'sWorksheetG'
+ +'rid1'#4'Left'#2#8#6'Height'#3#232#0#3'Top'#2#8#5'Width'#3#128#1#8'TabOrder'
+ +#2#0#0#0#7'TButton'#18'buttonPopulateGrid'#4'Left'#3#144#0#6'Height'#2#25#3
+ +'Top'#3#0#1#5'Width'#2'p'#7'Caption'#6#13'Populate Grid'#7'OnClick'#7#23'but'
+ +'tonPopulateGridClick'#8'TabOrder'#2#1#0#0#0
+]);
diff --git a/components/fpspreadsheet/examples/fpsvisual/mainform.pas b/components/fpspreadsheet/examples/fpsvisual/mainform.pas
new file mode 100644
index 000000000..5c76f68ed
--- /dev/null
+++ b/components/fpspreadsheet/examples/fpsvisual/mainform.pas
@@ -0,0 +1,49 @@
+unit mainform;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
+ StdCtrls, fpspreadsheetgrid, fpspreadsheet;
+
+type
+
+ { TForm1 }
+
+ TForm1 = class(TForm)
+ buttonPopulateGrid: TButton;
+ sWorksheetGrid1: TsWorksheetGrid;
+ procedure buttonPopulateGridClick(Sender: TObject);
+ private
+ { private declarations }
+ public
+ { public declarations }
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{ TForm1 }
+
+procedure TForm1.buttonPopulateGridClick(Sender: TObject);
+var
+ lWorksheet: TsWorksheet;
+begin
+ lWorksheet := TsWorksheet.Create;
+ try
+ lWorksheet.GetCell(2, 2)^.UTF8StringValue := 'Algo';
+ sWorksheetGrid1.LoadFromWorksheet(lWorksheet);
+ finally
+ lWorksheet.Free;
+ end;
+end;
+
+initialization
+ {$I mainform.lrs}
+
+end.
+
diff --git a/components/fpspreadsheet/examples/opendocdemo/opendocwrite.lpi b/components/fpspreadsheet/examples/opendocdemo/opendocwrite.lpi
index f8cfb5074..df4b78fd0 100644
--- a/components/fpspreadsheet/examples/opendocdemo/opendocwrite.lpi
+++ b/components/fpspreadsheet/examples/opendocdemo/opendocwrite.lpi
@@ -11,7 +11,7 @@
-
+
@@ -33,13 +33,13 @@
-
+
-
+
@@ -70,7 +70,7 @@
-
+
@@ -79,7 +79,7 @@
-
+
@@ -88,7 +88,7 @@
-
+
@@ -97,7 +97,7 @@
-
+
@@ -116,9 +116,9 @@
-
-
-
+
+
+
@@ -133,7 +133,7 @@
-
+
@@ -142,12 +142,12 @@
-
+
-
+
@@ -157,25 +157,25 @@
-
+
-
+
-
+
-
+
@@ -185,131 +185,165 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index abd0cbb61..239c83fa4 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -99,6 +99,7 @@ type
TsWorksheet = class
private
FCells: TAvlTree;
+ FCurrentNode: TAVLTreeNode; // For GetFirstCell and GetNextCell
procedure RemoveCallback(data, arg: pointer);
public
Name: string;
@@ -109,6 +110,8 @@ type
function FindCell(ARow, ACol: Cardinal): PCell;
function GetCell(ARow, ACol: Cardinal): PCell;
function GetCellCount: Cardinal;
+ function GetFirstCell(): PCell;
+ function GetNextCell(): PCell;
function GetLastColNumber: Cardinal;
function GetLastRowNumber: Cardinal;
function ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
@@ -294,7 +297,7 @@ begin
LCell.Row := ARow;
LCell.Col := ACol;
- AVLNode := Cells.Find(@LCell);
+ AVLNode := FCells.Find(@LCell);
if Assigned(AVLNode) then
result := PCell(AVLNode.Data);
end;
@@ -335,21 +338,65 @@ end;
{@@
Returns the number of cells in the worksheet with contents.
- This routine is used together with GetCellByIndex to
- iterate througth all cells in a worksheet efficiently.
+ This routine is used together with GetFirstCell and GetNextCell
+ to iterate througth all cells in a worksheet efficiently.
@return The number of cells with contents in the worksheet
@see TCell
- @see GetCellByIndex
+ @see GetFirstCell
+ @see GetNextCell
}
function TsWorksheet.GetCellCount: Cardinal;
begin
- Result := Cells.Count;
+ Result := FCells.Count;
end;
{@@
- Returns the number of the last column with a cell with contents.
+ Returns the first Cell.
+
+ Use together with GetCellCount and GetNextCell
+ to iterate througth all cells in a worksheet efficiently.
+
+ @return The first cell if any exists, nil otherwise
+
+ @see TCell
+ @see GetCellCount
+ @see GetNextCell
+}
+function TsWorksheet.GetFirstCell(): PCell;
+begin
+ FCurrentNode := FCells.FindLowest();
+ if FCurrentNode <> nil then
+ Result := PCell(FCurrentNode.Data)
+ else Result := nil;
+end;
+
+{@@
+ Returns the next Cell.
+
+ Should always be used either after GetFirstCell or
+ after GetNextCell.
+
+ Use together with GetCellCount and GetFirstCell
+ to iterate througth all cells in a worksheet efficiently.
+
+ @return The first cell if any exists, nil otherwise
+
+ @see TCell
+ @see GetCellCount
+ @see GetFirstCell
+}
+function TsWorksheet.GetNextCell(): PCell;
+begin
+ FCurrentNode := FCells.FindSuccessor(FCurrentNode);
+ if FCurrentNode <> nil then
+ Result := PCell(FCurrentNode.Data)
+ else Result := nil;
+end;
+
+{@@
+ Returns the 0-based number of the last column with a cell with contents.
If no cells have contents, zero will be returned, which is also a valid value.
@@ -367,16 +414,16 @@ begin
// Traverse the tree from lowest to highest.
// Since tree primary sort order is on Row
// highest Col could exist anywhere.
- AVLNode := Cells.FindLowest;
+ AVLNode := FCells.FindLowest;
While Assigned(AVLNode) do
begin
Result := Math.Max(Result, PCell(AVLNode.Data)^.Col);
- AVLNode := Cells.FindSuccessor(AVLNode);
+ AVLNode := FCells.FindSuccessor(AVLNode);
end;
end;
{@@
- Returns the number of the last row with a cell with contents.
+ Returns the 0-based number of the last row with a cell with contents.
If no cells have contents, zero will be returned, which is also a valid value.
diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas
new file mode 100644
index 000000000..73c1fd602
--- /dev/null
+++ b/components/fpspreadsheet/fpspreadsheetgrid.pas
@@ -0,0 +1,212 @@
+unit fpspreadsheetgrid;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Grids,
+ fpspreadsheet;
+
+type
+
+ { TsWorksheetGrid }
+
+ { TsCustomWorksheetGrid }
+
+ TsCustomWorksheetGrid = class(TCustomStringGrid)
+ private
+ FDisplayFixedColRow: Boolean;
+ FWorksheet: TsWorksheet;
+ procedure SetDisplayFixedColRow(const AValue: Boolean);
+ { Private declarations }
+ protected
+ { Protected declarations }
+ public
+ { methods }
+ constructor Create(AOwner: TComponent); override;
+ procedure LoadFromWorksheet(AWorksheet: TsWorksheet);
+ property DisplayFixedColRow: Boolean read FDisplayFixedColRow write SetDisplayFixedColRow;
+ end;
+
+ TsWorksheetGrid = class(TsCustomWorksheetGrid)
+ published
+ property Align;
+ property AlternateColor;
+ property Anchors;
+ property AutoAdvance;
+ property AutoEdit;
+ property AutoFillColumns;
+ //property BiDiMode;
+ property BorderSpacing;
+ property BorderStyle;
+ property Color;
+ property ColCount;
+ property Columns;
+ property Constraints;
+ property DefaultColWidth;
+ property DefaultDrawing;
+ property DefaultRowHeight;
+ property DragCursor;
+ property DragKind;
+ property DragMode;
+ property Enabled;
+ property ExtendedSelect;
+ property FixedColor;
+ property Flat;
+ property Font;
+ property GridLineWidth;
+ property HeaderHotZones;
+ property HeaderPushZones;
+ property MouseWheelOption;
+ property Options;
+ //property ParentBiDiMode;
+ property ParentColor default false;
+ property ParentFont;
+ property ParentShowHint;
+ property PopupMenu;
+ property RowCount;
+ property ScrollBars;
+ property ShowHint;
+ property TabOrder;
+ property TabStop;
+ property TitleFont;
+ property TitleImageList;
+ property TitleStyle;
+ property UseXORFeatures;
+ property Visible;
+ property VisibleColCount;
+ property VisibleRowCount;
+
+
+ property OnBeforeSelection;
+ property OnChangeBounds;
+ property OnClick;
+ property OnColRowDeleted;
+ property OnColRowExchanged;
+ property OnColRowInserted;
+ property OnColRowMoved;
+ property OnCompareCells;
+ property OnDragDrop;
+ property OnDragOver;
+ property OnDblClick;
+ property OnDrawCell;
+ property OnEditButtonClick;
+ property OnEditingDone;
+ property OnEndDock;
+ property OnEndDrag;
+ property OnEnter;
+ property OnExit;
+ property OnGetEditMask;
+ property OnGetEditText;
+ property OnHeaderClick;
+ property OnHeaderSized;
+ property OnKeyDown;
+ property OnKeyPress;
+ property OnKeyUp;
+ property OnMouseDown;
+ property OnMouseMove;
+ property OnMouseUp;
+ property OnMouseWheel;
+ property OnMouseWheelDown;
+ property OnMouseWheelUp;
+ property OnPickListSelect;
+ property OnPrepareCanvas;
+ property OnResize;
+ property OnSelectEditor;
+ property OnSelection;
+ property OnSelectCell;
+ property OnSetEditText;
+ property OnShowHint;
+ property OnStartDock;
+ property OnStartDrag;
+ property OnTopLeftChanged;
+ property OnUTF8KeyPress;
+ property OnValidateEntry;
+ property OnContextPopup;
+ end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+ RegisterComponents('Additional',[TsWorksheetGrid]);
+end;
+
+{ TsCustomWorksheetGrid }
+
+procedure TsCustomWorksheetGrid.SetDisplayFixedColRow(const AValue: Boolean);
+var
+ x: Integer;
+begin
+ if AValue = FDisplayFixedColRow then Exit;
+
+ FDisplayFixedColRow := AValue;
+
+ if AValue then
+ begin
+ for x := 1 to ColCount - 1 do
+ SetCells(x, 0, 'A');
+ for x := 1 to RowCount - 1 do
+ SetCells(0, x, IntToStr(x));
+ end;
+end;
+
+constructor TsCustomWorksheetGrid.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+
+ FDisplayFixedColRow := False;
+ FixedCols := 0;
+ FixedRows := 0;
+end;
+
+procedure TsCustomWorksheetGrid.LoadFromWorksheet(AWorksheet: TsWorksheet);
+var
+ x, lRow, lCol: Integer;
+ lStr: string;
+ lCell: PCell;
+begin
+ FWorksheet := AWorksheet;
+
+ { First get the size of the table }
+ if FWorksheet.GetCellCount = 0 then
+ begin
+ ColCount := 0;
+ RowCount := 0;
+ end
+ else
+ begin
+ if DisplayFixedColRow then
+ begin
+ ColCount := FWorksheet.GetLastColNumber() + 2;
+ RowCount := FWorksheet.GetLastRowNumber() + 2;
+ end
+ else
+ begin
+ ColCount := FWorksheet.GetLastColNumber() + 1;
+ RowCount := FWorksheet.GetLastRowNumber() + 1;
+ end;
+ end;
+
+ { Now copy the contents }
+
+ lCell := FWorksheet.GetFirstCell();
+ for x := 0 to FWorksheet.GetCellCount() - 1 do
+ begin
+ lCol := lCell^.Col;
+ lRow := lCell^.Row;
+ lStr := lCell^.UTF8StringValue;
+
+ if DisplayFixedColRow then
+ SetCells(lCol + 1, lRow + 1, lStr)
+ else
+ SetCells(lCol, lRow, lStr);
+
+ lCell := FWorksheet.GetNextCell();
+ end;
+end;
+
+end.
diff --git a/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk b/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk
new file mode 100644
index 000000000..d6031afa5
--- /dev/null
+++ b/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/fpspreadsheet/laz_fpspreadsheet_visual.pas b/components/fpspreadsheet/laz_fpspreadsheet_visual.pas
new file mode 100644
index 000000000..10a9c2828
--- /dev/null
+++ b/components/fpspreadsheet/laz_fpspreadsheet_visual.pas
@@ -0,0 +1,21 @@
+{ This file was automatically created by Lazarus. do not edit!
+ This source is only used to compile and install the package.
+ }
+
+unit laz_fpspreadsheet_visual;
+
+interface
+
+uses
+ fpspreadsheetgrid, LazarusPackageIntf;
+
+implementation
+
+procedure Register;
+begin
+ RegisterUnit('fpspreadsheetgrid', @fpspreadsheetgrid.Register);
+end;
+
+initialization
+ RegisterPackage('laz_fpspreadsheet_visual', @Register);
+end.