program TreeAndEditors; // Atlas VCL controls exercised on a hidden form: TAtlasTree hierarchy, lazy // loading and JSON; TAtlasSheetGrid over a TAtlasWorkbook; TAtlasInspector // editing published properties; TAtlasRichEdit formatting, RTF, find and // replace; TAtlasValueEdit validation. Every result is verified and the // program exits with 0 on success. Nothing is shown on screen. {$APPTYPE CONSOLE} uses System.SysUtils, System.Classes, Vcl.Forms, Vcl.Controls, Vcl.ComCtrls, Vcl.Graphics, Atlas.Data, Atlas.Editors, Atlas.Tree, Atlas.Spreadsheet, Atlas.SheetGrid, Atlas.Inspector, Atlas.RichEdit; type TLazyLoader = class Calls: Integer; procedure LoadChildren(Sender: TObject; Node: TTreeNode); end; TPriority = (prLow, prNormal, prHigh); TTaskSettings = class(TComponent) private FTitle: string; FRetries: Integer; FRatio: Double; FPriority: TPriority; FEnabled: Boolean; published property Title: string read FTitle write FTitle; property Retries: Integer read FRetries write FRetries; property Ratio: Double read FRatio write FRatio; property Priority: TPriority read FPriority write FPriority; property Enabled: Boolean read FEnabled write FEnabled; property Version: Integer read FRetries; end; procedure TLazyLoader.LoadChildren(Sender: TObject; Node: TTreeNode); begin Inc(Calls); TAtlasTree(Sender).AddNode(Node, 'Loaded on expand'); end; procedure Expect(Condition: Boolean; const What: string); begin if not Condition then raise Exception.Create('Check failed: ' + What); Writeln(' ok: ', What); end; procedure ExpectText(const Expected, Actual, What: string); begin if Expected <> Actual then raise Exception.CreateFmt('%s: expected [%s], got [%s]', [What, Expected, Actual]); Writeln(' ok: ', What, ' = ', Actual); end; procedure TreeSection(Form: TForm); var Tree, Copy: TAtlasTree; Loader: TLazyLoader; Root, Lazy, Node: TTreeNode; Failed: Boolean; begin Writeln('TAtlasTree'); Loader := TLazyLoader.Create; try Tree := TAtlasTree.Create(Form); Tree.Parent := Form; // nodes need a window handle Copy := TAtlasTree.Create(Form); Copy.Parent := Form; Root := Tree.AddNode(nil, 'Engineering'); Tree.AddNode(Root, 'Quality'); Tree.AddNode(Root, 'Desktop'); Node := Tree.AddNode(Root, 'Data platform'); Tree.SortChildren(Root); ExpectText('Data platform', Root.Item[0].Text, 'children sorted by caption'); Expect(Tree.FindCaption('desktop') = Root.Item[1], 'case-insensitive caption search'); Tree.MoveNode(Node, nil); Expect((Node.Parent = nil) and (Root.Count = 2), 'node moved to the root level'); Failed := False; try Tree.MoveNode(Root, Root.Item[0]); except on E: EAtlasTreeError do Failed := True; end; Expect(Failed, 'moving a node under its own child is rejected'); Tree.OnLoadChildren := Loader.LoadChildren; Lazy := Tree.AddNode(nil, 'Archive', True); Expect(Lazy.HasChildren and (Lazy.Count = 0), 'a lazy node shows an expand button before loading'); Lazy.Expand(False); Expect((Loader.Calls = 1) and (Lazy.Count = 1), 'OnLoadChildren ran once on first expand'); Lazy.Collapse(False); Lazy.Expand(False); Expect(Loader.Calls = 1, 'children are not loaded twice'); Tree.AddNode(nil, 'Later', True); Copy.LoadJSON(Tree.ToJSON); ExpectText(Tree.ToJSON, Copy.ToJSON, 'JSON round trip keeps captions, expansion and lazy flags'); Failed := False; try Copy.LoadJSON('[{"caption":"no other fields"}]'); except on E: EAtlasTreeError do Failed := True; end; Expect(Failed and (Copy.ToJSON = Tree.ToJSON), 'a rejected import leaves the tree unchanged'); finally Loader.Free; end; end; procedure SheetSection(Form: TForm); var Workbook: TAtlasWorkbook; Sheet: TAtlasSheetGrid; Format: TAtlasCellFormat; begin Writeln('TAtlasSheetGrid'); Workbook := TAtlasWorkbook.Create(Form); Workbook.SetCell('A1', '12'); Workbook.SetCell('A2', '30'); Workbook.SetCell('B1', '=SUM(A1:A2)'); Sheet := TAtlasSheetGrid.Create(Form); Sheet.Parent := Form; Sheet.Workbook := Workbook; ExpectText('A', Sheet.Cells[1, 0], 'column headers use letters'); ExpectText('42', Sheet.Cells[2, 1], 'B1 shows the calculated value'); Workbook.SetCell('A2', '8'); ExpectText('20', Sheet.Cells[2, 1], 'the grid follows workbook changes'); Format := TAtlasCellFormat.Default; Format.NumberFormat := anfFixed; Format.Decimals := 1; Workbook.SetCellFormat('B1', Format); ExpectText('20.0', Sheet.Cells[2, 1], 'cell formats apply to the displayed text'); Workbook.Free; Expect(Sheet.Workbook = nil, 'the grid detaches when its workbook is freed'); end; procedure InspectorSection(Form: TForm); var Settings: TTaskSettings; Inspector: TAtlasInspector; Failed: Boolean; begin Writeln('TAtlasInspector'); Settings := TTaskSettings.Create(nil); try Settings.Title := 'Nightly build'; Settings.Retries := 3; Inspector := TAtlasInspector.Create(Form); Inspector.Parent := Form; Inspector.Instance := Settings; ExpectText('3', Inspector.Strings.Values['Retries'], 'published properties are listed with their values'); Inspector.SetProperty('Retries', '5'); Inspector.SetProperty('Ratio', '0.75'); Inspector.SetProperty('Priority', 'prHigh'); Inspector.SetProperty('Enabled', 'True'); Expect((Settings.Retries = 5) and (Settings.Ratio = 0.75) and (Settings.Priority = prHigh) and Settings.Enabled, 'SetProperty converts and assigns typed values'); Failed := False; try Inspector.SetProperty('Retries', 'five'); except on E: EAtlasPropertyError do Failed := True; end; Expect(Failed and (Settings.Retries = 5), 'an invalid value is rejected before assignment'); Failed := False; try Inspector.SetProperty('Version', '9'); except on E: EAtlasPropertyError do Failed := True; end; Expect(Failed, 'a read-only property is rejected'); Settings.Free; Settings := nil; Expect(Inspector.Instance = nil, 'destroying the component detaches the inspector'); finally Settings.Free; end; end; procedure RichEditSection(Form: TForm); var Editor, Copy: TAtlasRichEdit; Rtf: TBytes; begin Writeln('TAtlasRichEdit'); Editor := TAtlasRichEdit.Create(Form); Editor.Parent := Form; // the control needs a window before streaming RTF Copy := TAtlasRichEdit.Create(Form); Copy.Parent := Form; Editor.Text := 'Atlas notes: draft one, draft two.'; Editor.SelStart := 0; Editor.SelLength := 11; Editor.FormatSelection('Segoe UI', 14, [fsBold], clNavy); Expect(fsBold in Editor.SelAttributes.Style, 'selection formatting applied'); Rtf := Editor.SaveRTF; Expect(TEncoding.ASCII.GetString(Rtf, 0, 5) = '{\rtf', 'SaveRTF returns RTF bytes'); Copy.LoadRTF(Rtf); ExpectText(Editor.Text, Copy.Text, 'LoadRTF restores the text'); Copy.SelStart := 0; Copy.SelLength := 11; Expect(fsBold in Copy.SelAttributes.Style, 'LoadRTF restores the formatting'); Editor.SelStart := 0; Editor.SelLength := 0; Expect(Editor.FindNext('draft') and (Editor.SelStart = 13), 'FindNext selects the first match after the caret'); Expect(Editor.FindNext('draft') and (Editor.SelStart = 24), 'FindNext continues from the selection'); Expect(Editor.ReplaceAll('draft', 'revision') = 2, 'ReplaceAll reports two replacements'); ExpectText('Atlas notes: revision one, revision two.', Editor.Text, 'text after ReplaceAll'); end; procedure ValueEditSection; var Edit: TAtlasValueEdit; begin Writeln('TAtlasValueEdit'); Edit := TAtlasValueEdit.Create(nil); try Edit.ValueKind := ackNumber; Edit.Text := '12.50'; Expect(Edit.Validate, 'a number is accepted'); ExpectText('12.5', Edit.NormalizedValue, 'NormalizedValue is the stored form'); Edit.Text := '1,5'; Expect(not Edit.Validate and (Edit.ValidationMessage <> ''), 'a locale decimal comma is rejected with a message'); Edit.Text := ''; Expect(Edit.Validate, 'blank is valid when not required'); Edit.Required := True; Expect(not Edit.Validate, 'blank is invalid when required'); Edit.ValueKind := ackDate; Edit.Text := '2026-02-29'; Expect(not Edit.Validate, '2026-02-29 is not a real date'); Edit.Text := '2028-02-29'; Expect(Edit.Validate, '2028-02-29 is a leap day'); finally Edit.Free; end; end; var Form: TForm; begin try Application.Initialize; Form := TForm.CreateNew(nil); try TreeSection(Form); SheetSection(Form); InspectorSection(Form); RichEditSection(Form); ValueEditSection; finally Form.Free; end; Writeln('PASS: TreeAndEditors'); except on E: Exception do begin Writeln('FAIL: ', E.ClassName, ': ', E.Message); Halt(1); end; end; end.