source upload

This commit is contained in:
Razor12911
2022-01-17 22:16:47 +02:00
parent 12936d065b
commit 098e8c48de
1778 changed files with 1206749 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
TSynJSONTreeView
================
By *EMartin* (Esteban Martin).
# Presentation
`TSynJSONTreeView` is a treeview supporting mORMot's JSON document, the allowed tasks are:
- edit a node
- delete a node
- add a node
- save to file
- load from file
- generate JSON to string variable
- implement a custom input for edit/insert node
# Forum Thread
See http://synopse.info/forum/viewtopic.php?id=3451
# TODO
- FPC support (I just use Windows)
- Developed with Delphi 7, not tested with any other Delphi version.
# License
Feel free to use and/or append to Lib and extend if needed.

View File

@@ -0,0 +1 @@
{"HandleUserAuthentication":true,"HTTPServer":{"HttpQueueLength":1000,"MaxBandWidth":0,"MaxConnections":0,"BindPort":"8888","Authentication":"adDefault","EnableCORS":false,"ThreadCount":32,"Https":false,"HttpSysQueueName":"ARISQueue","WebSocketPassword":""},"HTTPServerWS":{"HttpQueueLength":0,"MaxBandWidth":0,"MaxConnections":0,"BindPort":"8889","Authentication":"adDefault","EnableCORS":false,"ThreadCount":0,"Https":false,"HttpSysQueueName":"ARISWSQueue","WebSocketPassword":"Bsyv1NapccWDNwPVgcQ+fU+pKhed5PGUVUT4h0Im+E07aA=="},"Log":{"Ident":0,"Level":["sllNone","sllInfo","sllDebug","sllTrace","sllWarning","sllError","sllEnter","sllLeave","sllLastError","sllException","sllExceptionOS","sllMemory","sllStackTrace","sllFail","sllSQL","sllCache","sllResult","sllDB","sllHTTP","sllClient","sllServer","sllServiceCall","sllServiceReturn","sllUserAuth","sllCustom1","sllCustom2","sllCustom3","sllCustom4","sllNewRun","sllDDDError","sllDDDInfo","sllMonitoring"],"LevelStackTrace":["sllError","sllLastError","sllException","sllExceptionOS","sllStackTrace","sllFail","sllDDDError"],"DestinationPath":"D:\\TecnoVoz\\Log\\","DefaultExtension":".synlog","IncludeComputerNameInFileName":false,"CustomFileName":"ARIS","ArchivePath":"D:\\TecnoVoz\\Log\\Archive","ArchiveAfterDays":1,"BufferSize":4096,"PerThreadLog":"ptIdentifiedInOnFile","HighResolutionTimeStamp":false,"LocalTimeStamp":true,"WithUnitName":true,"AutoFlushTimeOut":0,"NoEnvironmentVariable":false,"NoFile":false,"RotateFileCount":10,"RotateFileSizeKB":262144,"RotateFileDailyAtHour":-1,"StackTraceLevel":30,"StackTraceUse":"stOnlyAPI","FileExistsAction":"acAppend","EndOfLineCRLF":false},"SMTP":{"Authentication":"","Port":"25","Server":"tvzserver","SSLVersion":"sslvNone","UserName":"emartin","Password":"GaZZ0opaJqvttSQ="},"SQLDBConnections":{"ConnectionTimeoutMinutes":10,"Count":9,"ConnectionDefinitions":[{"DatabaseName":"DRIVER={ODBC Driver 11 for SQL Server};UID=USER;PWD=D3rNfXg2ug==;Server=DBEngines;DataBase=TEST;","DBMS":"dMSSQL","Kind":"TODBCConnectionProperties","Name":"TEST_MSSQL","ServerName":"","AllowGetObjects":false,"Description":"Conexi<78>n a la m<>quina virtual de bases de datos.","Properties":"","UserName":"TEST_USER","Password":""},{"DatabaseName":"FirebirdTest1","DBMS":"dFirebird","Kind":"TSQLDBZEOSConnectionProperties","Name":"APPROACH","ServerName":"firebird-2.5://DBEngines","AllowGetObjects":false,"Description":"","Properties":"hard_commit=true","UserName":"SYSDBA","Password":"D3rNfXg2ug=="},{"DatabaseName":"FirebirdTest2","DBMS":"dFirebird","Kind":"TSQLDBZEOSConnectionProperties","Name":"SCHEDULER","ServerName":"firebird-2.5://DBEngines","AllowGetObjects":false,"Description":"Any description with accented characters <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>","Properties":"hard_commit=true","UserName":"SYSDBA","Password":"D3rNfXg2ug=="}]},"LastElement":true}

View File

@@ -0,0 +1,15 @@
program SynJSONTVEditor;
uses
Forms,
fMain in 'fMain.pas' {frmJSONEditor},
SynJSONTreeView in 'SynJSONTreeView.pas',
fLevel in 'fLevel.pas' {frmLevel};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TfrmJSONEditor, frmJSONEditor);
Application.Run;
end.

View File

@@ -0,0 +1,903 @@
/// JSON tree view bases on Synopse JSON parser
// - based on JSON TreeView VCL Component from pawel.glowacki@embarcadero.com
// - this unit is a part of the freeware Synopse mORMot framework,
// licensed under a MPL/GPL/LGPL tri-license; version 1.18
unit SynJSONTreeView;
{
This file is part of Synopse framework.
Synopse framework. Copyright (C) 2020 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.
The Original Code is Synopse mORMot framework.
The Initial Developer of the Original Code is Arnaud Bouchez.
Portions created by the Initial Developer are Copyright (C) 2020
the Initial Developer. All Rights Reserved.
Contributor(s):
- Esteban Martin (EMartin)
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****
Version 1.18
- first public release, corresponding to Synopse mORMot Framework 1.18
TODO:
- FPC support (I just use Windows)
- Developed with Delphi 7, not tested with other Delphi versions
}
{$I Synopse.inc} // define HASINLINE CPU32 CPU64 OWNNORMTOUPPER
interface
uses
SysUtils,
Classes,
ComCtrls,
Controls,
SynCommons,
SynTable;
type
ESynJSONTreeView = class(ESynException);
TSynJSONTreeNode = class;
/// Tree node types
// - jtnObject: JSON object, i.e: {"fieldNumber":123,"fieldText":"text","fieldNull":null}
// - jtnObjectContent: conten of jtnObject, i.e: "fieldNumber":123
// - jtnArray: JSON array, i.e: [123,"text",{"fieldNumber":123,"fieldText":"text","fieldNull":null},null]
// - jtnArrayContent: content of jtnArray, i.e: 123 or {"fieldNumber":123,"fieldText":"text","fieldNull":null}
TSynJSONTreeNodeType = (jtnObject, jtnObjectContent, jtnArray, jtnArrayContent);
/// Event type for fire event when editing
TSynJSONTreeViewCustomInputEvent = procedure(Sender: TObject; Node: TSynJSONTreeNode;
var Prompt: RawUTF8; var Value: Variant;
var Handled: Boolean) of object;
/// Node extension for handling JSON value in the treeview
TSynJSONTreeNode = class(TTreeNode)
protected
fName: RawUTF8;
fJSONType: TSynJSONTreeNodeType;
fValue: Variant;
public
/// Clone the node
function Clone: TSynJSONTreeNode;
/// JSON type in the node
property JSONType: TSynJSONTreeNodeType read fJSONType write fJSONType;
/// Name of the JSON value
property Name: RawUTF8 read FName write fName;
/// JSON value
property Value: Variant read fValue write fValue;
end;
/// Allowed edition states of treeview
// - estEdit: allow edit a node
// - estDelete: allow delete a node
// - estInsert: allow insert a node
TSynJSONTreeViewEditionStateType = (estEdit , estDelete, estInsert);
TSynJSONTreeViewEditionStateSet = set of TSynJSONTreeViewEditionStateType;
/// TSynJSONTreeView is a treeview supporting mORMOn JSON document (TDocVariantData), the allowed tasks are:
// - edit a node
// - delete a node
// - add a node
// - save to file
// - load from file
// - generate JSON to string variable
// - implement a custom input for edit/insert node
TSynJSONTreeView = class(TTreeView)
private
fAllowedEditionStates: TSynJSONTreeViewEditionStateSet;
protected
fFirsttime: Boolean;
fJSONDocument: Variant;
fJSONText: RawUTF8;
fKey: Integer;
fOnDblClickBak: TNotifyEvent;
fOnEditingBak: TTVEditingEvent;
fOnKeyDownBak: TKeyEvent;
fOnCustomInput: TSynJSONTreeViewCustomInputEvent;
fVisibleChildrenCounts: boolean;
fVisibleByteSizes: boolean;
/// Add child node from JSON value
// - aNode: node from which add the child
// - aJSON: JSON value single or object/array
// - aNameOrIndex: if it is numeric, then is the index into the object/array, otherwise the name of the container node
function AddChildFromJSON(const aNode: TSynJSONTreeNode; const aJSON: Variant; const aNameOrIndex: Variant): TSynJSONTreeNode;
procedure BackupEvents;
procedure DeleteNode(Node: TSynJSONTreeNode; const aAsk: Boolean = True);
procedure DoOnCreateNodeClass(Sender: TCustomTreeView; var NodeClass: TTreeNodeClass);
procedure DoOnDblClick(Sender: TObject);
procedure DoOnEditing(Sender: TObject; Node: TTreeNode; var AllowEdit: Boolean);
procedure DoOnKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure EditNode(Node: TSynJSONTreeNode);
procedure InsertNode(Node: TSynJSONTreeNode; const aJSON: Variant);
function IsActive: Boolean;
function IsSimpleJsonValue(v: Variant): boolean;{$ifdef HASINLINE}inline;{$endif}
procedure ProcessArray(const aCurrNode: TSynJSONTreeNode; const aValue: Variant; const aNameOrIndex: Variant);
procedure ProcessElement(currNode: TSynJSONTreeNode; arr: Variant; aIndex: integer);
function ProcessJSONText: boolean;
procedure ProcessObject(const aCurrNode: TSynJSONTreeNode; const aValue: Variant; const aNameOrIndex: Variant);
function ProcessPair(currNode: TSynJSONTreeNode; obj: Variant; aIndex: integer): TSynJSONTreeNode;
/// Assign and process the JSON text
// - if Value is null then clear the JSON text and the treeview content
procedure SetJSONText(const Value: RawUTF8);
/// Assign mORMot JSON Document
// - if Value is not equal to the previous value then load the JSON into the treeview
procedure SetSynJSONDocument(const Value: Variant);
/// Show how many children has a container node
procedure SetVisibleChildrenCounts(const Value: boolean);
/// Show byte size of a container node
procedure SetVisibleByteSizes(const Value: boolean);
/// Update info of a container node
procedure UpdateNodeInfo(aNode: TSynJSONTreeNode);
/// Get the original value from variant value
function VariantToRaw(const aVarData: Variant): Variant;
/// Assign source variant to dest variant but considering the dest data type
procedure VariantToVariant(aSource: Variant; var aDest: Variant);
/// Convert variant to UTF8 but checking the boolean type and convert it to true/false string
function VarToUTF8(const aVarData: Variant): RawUTF8;
public
constructor Create(AOwner: TComponent); override;
/// Remove items and JSON text
procedure ClearAll;
/// Load from file
procedure LoadFromFile(const aFileName: TFileName);
/// Load the JSONText in the treeview, clear if empty
procedure LoadJSON;
/// Save to file
procedure SaveToFile(const aFileName: TFileName);
/// Generate JSON from the treeview
function ToJSON: RawUTF8;
/// JSON DocVariantData
property JSONDocument: Variant read FJSONDocument write SeTSynJSONDocument;
published
/// Allowed state editions
property AllowedEditionStates: TSynJSONTreeViewEditionStateSet read fAllowedEditionStates write fAllowedEditionStates;
/// Content the JSON text, when assigned parse the the JSON and load in the treeview
property JSONText: RawUTF8 read fJSONText write SetJSONText;
/// Display info over how many children has each node
property VisibleChildrenCounts: boolean read FVisibleChildrenCounts write SetVisibleChildrenCounts;
/// Display info over the size of node
property VisibleByteSizes: boolean read FVisibleByteSizes write SetVisibleByteSizes;
/// Event fired when editing for custom input
property OnCustomInput: TSynJSONTreeViewCustomInputEvent read fOnCustomInput write fOnCustomInput;
end;
implementation
uses
Windows,
Variants,
mORMotUILogin;
resourcestring
SInvalidJSONValue = 'Invalid JSON value';
SInvalidJSON = 'Invalid JSON: %';
SEnterValue = 'Enter Value';
SInsertNewItem = 'Insert new item';
SInsertNewItemPrompt = 'Enter JSON:\n\n object: <name>:<value>\n array: [<index>]:<value>\n\n ' +
'In array the brackets are required.';
SRemoveChildren = 'This node has children, are you sure to remove them';
SDeleteNode = 'Delete node\n\n% ?';
{ TSynJSONTreeView }
procedure TSynJSONTreeView.ClearAll;
begin
SetJSONText('');
Items.Clear;
end;
constructor TSynJSONTreeView.Create(AOwner: TComponent);
begin
inherited;
OnCreateNodeClass := DoOnCreateNodeClass;
fAllowedEditionStates := [estEdit, estDelete, estInsert];
fFirstTime := True;
FVisibleChildrenCounts := true;
FVisibleByteSizes := false;
end;
procedure TSynJSONTreeView.LoadJson;
var
v: Variant;
begin
BackupEvents;
Items.Clear;
if IsActive then
begin
v := fJSONDocument;
Items.Clear;
if (v._Kind = dvObject) then
ProcessObject(nil, v, Unassigned)
else if (v._Kind = dvArray) then
ProcessArray(nil, v, Unassigned)
else
raise ESynJSONTreeView.Create(SInvalidJSONValue);
FullExpand;
end;
end;
function TSynJSONTreeView.ProcessPair(currNode: TSynJSONTreeNode; obj: Variant; aIndex: integer): TSynJSONTreeNode;
var
p: Variant;
begin
Result := nil;
p := obj._(aIndex);
if IsSimpleJsonValue(p) then
begin
AddChildFromJSON(currNode, obj, aIndex);
Exit;
end;
if (p._Kind = dvObject) then
ProcessObject(currNode, _CopyFast(p), obj.Name(aIndex))
else if (p._Kind = dvArray) then
ProcessArray(currNode, _CopyFast(p), obj.Name(aIndex))
else
raise ESynJSONTreeView.Create(SInvalidJSONValue);
end;
procedure TSynJSONTreeView.ProcessElement(currNode: TSynJSONTreeNode; arr: Variant; aIndex: integer);
var
v: Variant;
begin
v := arr._(aIndex);
if IsSimpleJsonValue(v) then
begin
AddChildFromJSON(currNode, arr, aIndex);
Exit;
end;
if (v._Kind = dvObject) then
ProcessObject(currNode, _CopyFast(v), IntToStr(aIndex))
else if (v._Kind = dvArray) then
ProcessArray(currNode, _CopyFast(v), aIndex)
else
raise ESynJSONTreeView.Create(SInvalidJSONValue);
end;
procedure TSynJSONTreeView.SetSynJSONDocument(const Value: Variant);
begin
if fJSONDocument <> Value then
begin
fJSONDocument := Value;
ClearAll;
if IsActive then
LoadJson;
end;
end;
procedure TSynJSONTreeView.SetVisibleByteSizes(const Value: boolean);
begin
if FVisibleByteSizes <> Value then
begin
FVisibleByteSizes := Value;
LoadJson;
end;
end;
procedure TSynJSONTreeView.SetVisibleChildrenCounts(const Value: boolean);
begin
if FVisibleChildrenCounts <> Value then
begin
FVisibleChildrenCounts := Value;
LoadJson;
end;
end;
function TSynJSONTreeView.VarToUTF8(const aVarData: Variant): RawUTF8;
begin
if (TVarData(aVarData).VType = varBoolean) then
begin
if TVarData(aVarData).VBoolean then
Result := 'true'
else
Result := 'false';
end else
Result := VariantToUTF8(aVarData);
end;
function TSynJSONTreeView.ToJSON: RawUTF8;
var
lW: TTextWriter;
procedure ProcessNode(aNode: TSynJSONTreeNode);
procedure CheckLastComma(aW: TTextWriter);
begin
if (aW.TextLength > 0) and (not (aW.LastChar in [',','[','{'])) then
aW.Add(',');
end;
var
lNode: TSynJSONTreeNode;
begin
lNode := aNode;
repeat
if Assigned(lNode) then begin
case lNode.JSONType of
jtnObject:
begin
CheckLastComma(lW);
// numeric name is excluded
if (lNode.Name <> '') and (StrToIntDef(lNode.Name, MaxInt) = MaxInt) then
lW.AddFieldName(lNode.Name);
lW.Add('{');
end;
jtnArray:
begin
CheckLastComma(lW);
if (lNode.Name <> '') then
lW.AddFieldName(lNode.Name);
lW.Add('[');
end;
jtnObjectContent:
begin
CheckLastComma(lW);
lW.AddFieldName(lNode.Name);
lW.AddVariant(lNode.Value);
lW.Add(',');
end;
jtnArrayContent:
begin
CheckLastComma(lW);
lW.AddVariant(lNode.Value);
lW.Add(',');
end;
end;
end;
if lNode.HasChildren then begin
ProcessNode(TSynJSONTreeNode(lNode.GetFirstChild));
lW.CancelLastComma;
case lNode.JSONType of
jtnObject: lW.Add('}');
jtnArray: lW.Add(']');
end;
end;
lNode := TSynJSONTreeNode(lNode.GetNextSibling);
until not Assigned(lNode);
end;
begin
lW := TTextWriter.CreateOwnedStream;
try
ProcessNode(TSynJSONTreeNode(Items.GetFirstNode));
lW.CancelLastComma;
lW.SetText(Result);
finally
lW.Free;
end;
end;
procedure TSynJSONTreeView.DoOnCreateNodeClass(Sender: TCustomTreeView; var NodeClass: TTreeNodeClass);
begin
NodeClass := TSynJSONTreeNode;
end;
function TSynJSONTreeView.VariantToRaw(const aVarData: Variant): Variant;
var
lVar: TSQLVar;
lTmp: RawByteString;
begin
if VarIs(aVarData, [varBoolean]) then
begin
Result := aVarData;
Exit;
end;
VariantToSQLVar(aVarData, lTmp, lVar);
with lVar do
case VType of
ftNull: Result := null;
ftCurrency: Result := VInt64;
ftUTF8:
if Assigned(VText) then
Result := RawUTF8(PUTF8Char(VText))
else
Result := '';
ftInt64: Result := VInt64;
ftDouble: Result := VDouble;
end;
end;
procedure TSynJSONTreeView.DoOnDblClick(Sender: TObject);
begin
if ReadOnly or (Selected.Count > 0) or (not (estEdit in fAllowedEditionStates)) then
Exit;
EditNode(TSynJSONTreeNode(Selected));
if Assigned(fOnDblClickBak) then
fOnDblClickBak(Sender);
end;
function TSynJSONTreeView.IsActive: Boolean;
begin
Result := (fJSONDocument <> Unassigned) and (not VarIsEmptyOrNull(fJSONDocument)) and (fJSONDocument._Kind <> dvUndefined);
end;
function TSynJSONTreeView.IsSimpleJsonValue(v: Variant): boolean;
begin
Result := VarIsEmptyOrNull(v) or VarIsNumeric(v) or VarIsStr(v) or VarIsStr(v);
end;
procedure TSynJSONTreeView.SetJSONText(const Value: RawUTF8);
begin
if fJSONText <> Value then
begin
fJSONText := Value;
if fJSONText <> '' then
ProcessJSONText
else
begin
TDocVariantData(fJSONDocument).Clear;
fJSONDocument := Unassigned;
end;
end;
end;
function TSynJSONTreeView.ProcessJSONText: boolean;
begin
if IsActive then
fJSONDocument.Clear;
TDocVariantData(fJSONDocument).InitJSON(fJSONText);
if (TDocVariantData(fJSONDocument).Kind = dvUndefined) then
raise ESynJSONTreeView.CreateUTF8(SInvalidJSON, [fJSONText]);
Result := IsActive;
end;
procedure TSynJSONTreeView.BackupEvents;
begin
if not fFirstTime then
Exit;
if not Assigned(fOnDblClickBak) and Assigned(OnDblClick) then
fOnDblClickBak := OnDblClick;
OnDblClick := DoOnDblClick;
if not Assigned(fOnEditingBak) and Assigned(OnEditing) then
fOnEditingBak := OnEditing;
OnEditing := DoOnEditing;
if not Assigned(fOnKeyDownBak) and Assigned(OnKeyDown) then
fOnKeyDownBak := OnKeyDown;
OnKeyDown := DoOnKeyDown;
fFirstTime := False;
end;
procedure TSynJSONTreeView.DoOnKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if ReadOnly or (not (Key in [VK_DELETE, VK_INSERT, VK_RETURN])) or
((Key = VK_DELETE) and (not (estDelete in fAllowedEditionStates))) or
((Key = VK_RETURN) and (not (estEdit in fAllowedEditionStates))) or
((Key = VK_INSERT) and (not (estInsert in fAllowedEditionStates))) then
Exit;
case Key of
VK_DELETE: DeleteNode(TSynJSONTreeNode(Selected));
VK_INSERT: InsertNode(TSynJSONTreeNode(Selected), Unassigned);
VK_RETURN: EditNode(TSynJSONTreeNode(Selected));
end;
if Assigned(fOnKeyDownBak) then
fOnKeyDownBak(Sender, Key, Shift);
end;
procedure TSynJSONTreeView.UpdateNodeInfo(aNode: TSynJSONTreeNode);
procedure UpdateNodeText(aNode: TSynJSONTreeNode; const aText: RawUTF8);
begin
if not VarIsNull(aNode.Value) then
aNode.Text := aText
else
aNode.Text := aNode.Name + ': null';
end;
begin
case aNode.JSONType of
jtnObject: begin
if (not Assigned(aNode.Parent)) or (TSynJSONTreeNode(aNode.Parent).JSONType <> jtnArray) then
UpdateNodeText(aNode, aNode.Name + ' {}')
else
UpdateNodeText(aNode, FormatUTF8('[%] {}', [aNode.Name]));
end;
jtnArray:
if not VarIsNull(aNode.Value) then
UpdateNodeText(aNode, aNode.Name + ' []');
end;
case aNode.JSONType of
jtnObject, jtnArray: begin
if VisibleChildrenCounts then
if not VarIsNull(aNode.Value) then
UpdateNodeText(aNode, aNode.Text + ' (' + IntToStr(aNode.Value._Count) + ')')
else
UpdateNodeText(aNode, '');
if VisibleByteSizes then
if not VarIsNull(aNode.Value) then
UpdateNodeText(aNode, aNode.Text + ' (size: ' + IntToStr(Length(aNode.Value._JSON)) + ' bytes)')
else
UpdateNodeText(aNode, '');
end;
jtnObjectContent, jtnArrayContent: begin
UpdateNodeText(aNode, '');
end;
end;
end;
procedure TSynJSONTreeView.DeleteNode(Node: TSynJSONTreeNode; const aAsk: Boolean);
procedure RecalculateChildNames(aNode: TSynJSONTreeNode);
var
lNode: TSynJSONTreeNode;
I: Integer;
begin
lNode := TSynJSONTreeNode(aNode.GetFirstChild);
if not Assigned(lNode) then
Exit;
I := 0;
case lNode.JSONType of
jtnObject: begin
repeat
if Assigned(lNode) then begin
if (StrToIntDef(lNode.Name, MaxInt) <> MaxInt) then
lNode.Name := IntToStr(I);
UpdateNodeInfo(lNode);
Inc(I);
end;
lNode := TSynJSONTreeNode(lNode.getNextSibling);
until not Assigned(lNode);
end;
jtnArrayContent: begin
repeat
if Assigned(lNode) then begin
lNode.Name := IntToStr(I);
lNode.Text := UTF8ToString(FormatUTF8('[%]: %', [lNode.Name, lNode.Value]));
Inc(I);
end;
lNode := TSynJSONTreeNode(lNode.getNextSibling);
until not Assigned(lNode);
end;
end;
end;
procedure UpdateEmptyParent(aParent: TSynJSONTreeNode);
begin
if (aParent.Count = 0) then begin
aParent.Value := NULL;
case TSynJSONTreeNode(aParent.Parent).JSONType of
jtnObject: aParent.JSONType := jtnObjectContent;
jtnArray: aParent.JSONType := jtnArrayContent;
end;
end;
end;
var
lParent, lDeletedNode: TSynJSONTreeNode;
begin
if aAsk then
if (YesNo(UTF8ToString(FormatUTF8(SDeleteNode, [Node.Text])), '', False) <> mrYes) then
Exit;
lDeletedNode := Node.Clone;
lParent := TSynJSONTreeNode(Node.Parent);
Items.BeginUpdate;
try
Node.Delete;
Node := lDeletedNode;
// if node name is empty it means that the JSON object is empty
if (Node.Name = '') then begin
ClearAll;
Exit;
end;
case Node.JSONType of
jtnArray, jtnObject: begin
if (StrToIntDef(Node.Name, MaxInt) <> MaxInt) then
TDocVariantData(lParent.Value).Delete(StrToInt(Node.Name))
else
TDocVariantData(lParent.Value).Delete(Node.Name);
if (lParent.Count = 0) then
UpdateEmptyParent(lParent)
else
RecalculateChildNames(lParent);
UpdateNodeInfo(lParent);
end;
jtnArrayContent: begin
TDocVariantData(lParent.Value).Delete(StrToInt(Node.Name));
if (lParent.Count = 0) then
UpdateEmptyParent(lParent)
else
RecalculateChildNames(lParent);
UpdateNodeInfo(lParent);
end;
jtnObjectContent: begin
TDocVariantData(lParent.Value).Delete(Node.Name);
if (lParent.Count = 0) then
UpdateEmptyParent(lParent);
UpdateNodeInfo(lParent);
end;
end;
finally
Items.EndUpdate;
end;
end;
procedure TSynJSONTreeView.InsertNode(Node: TSynJSONTreeNode; const aJSON: Variant);
var
lJSON: Variant;
lPrompt: RawUTF8;
lValue: Variant;
I: Integer;
lCount: Integer;
lHandled: Boolean;
begin
if (aJSON = Unassigned) then begin
lPrompt := SInsertNewItemPrompt;
if Assigned(fOnCustomInput) then
fOnCustomInput(Self, Node, lPrompt, lValue, lHandled);
if not lHandled then
lValue := InputBox(SInsertNewItem, lPrompt, '');
if (lValue = '') then
Exit;
if (lValue[1] <> '[') then
if (lValue[1] <> '{') then
lValue := '{' + lValue + '}';
TDocVariantData(lJSON).InitJSON(lValue);
if (TDocVariantData(lJSON).Kind = dvUndefined) then
raise ESynJSONTreeView.CreateUTF8(SInvalidJSON, [lValue]);
end else
lJSON := aJSON;
// always will be an object the inserted node
lCount := lJSON._Count;
TDocVariantData(TSynJSONTreeNode(Node).Value).AddOrUpdateObject(lJSON);
for I := 0 to lCount-1 do begin
lValue := lJSON._(I);
if IsSimpleJsonValue(lValue) then begin
AddChildFromJSON(Node, lJSON, I);
end else
ProcessObject(Node, _CopyFast(lValue), lJSON.Name(I));
end;
UpdateNodeInfo(Node);
end;
function TSynJSONTreeView.AddChildFromJSON(const aNode: TSynJSONTreeNode; const aJSON: Variant; const aNameOrIndex: Variant): TSynJSONTreeNode;
var
lValue: Variant;
begin
Result := TSynJSONTreeNode(Items.AddChild(aNode, ''));
if not VarIsEmpty(aNameOrIndex) and (VariantToIntegerDef(aNameOrIndex, -1) <> -1) then
lValue := VariantToRaw(aJSON._(aNameOrIndex))
else
lValue := aJSON;
if (TDocVariantData(lValue).Kind <> dvUndefined) then
Result.Value := _CopyFast(lValue)
else
Result.Value := lValue;
case TDocVariantData(aJSON).Kind of
dvObject:
if not VarIsEmpty(aNameOrIndex) then begin
// is name or index is numeric, the text property is assigned showing the name and value, otherwise is a
// container node
if (VariantToIntegerDef(aNameOrIndex, -1) <> -1) then begin
Result.Name := aJSON.Name(aNameOrIndex);
Result.JSONType := jtnObjectContent;
Result.Text := Result.Name + ': ' + VarToUTF8(lValue);
end else begin
Result.Name := aNameOrIndex;
Result.JSONType := jtnObject;
end;
end;
dvArray:
if not VarIsEmpty(aNameOrIndex) then begin
// is name or index is numeric, the text property is assigned showing the name and value, otherwise is a
// container node
if (VariantToIntegerDef(aNameOrIndex, -1) <> -1) then begin
Result.Name := aNameOrIndex;
Result.JSONType := jtnArrayContent;
Result.Text := IntToStr(aNameOrIndex) + ': ' + VarToUTF8(lValue);
end else begin
Result.Name := aNameOrIndex;
Result.JSONType := jtnArray;
end;
end;
end;
end;
procedure TSynJSONTreeView.ProcessObject(const aCurrNode: TSynJSONTreeNode; const aValue: Variant; const aNameOrIndex: Variant);
var
lCount: Integer;
I: Integer;
lCurrNode: TSynJSONTreeNode;
begin
lCurrNode := AddChildFromJSON(aCurrNode, aValue, aNameOrIndex);
UpdateNodeInfo(lCurrNode);
lCount := aValue._Count;
for I := 0 to lCount - 1 do
ProcessPair(lCurrNode, _CopyFast(aValue), I);
end;
procedure TSynJSONTreeView.ProcessArray(const aCurrNode: TSynJSONTreeNode; const aValue: Variant; const aNameOrIndex: Variant);
var
lCount: Integer;
I: Integer;
lCurrNode: TSynJSONTreeNode;
begin
lCurrNode := AddChildFromJSON(aCurrNode, aValue, aNameOrIndex);
UpdateNodeInfo(lCurrNode);
lCount := aValue._Count;
for I := 0 to lCount - 1 do
ProcessElement(lCurrNode, aValue, I);
end;
procedure TSynJSONTreeView.EditNode(Node: TSynJSONTreeNode);
var
lPrompt: RawUTF8;
lJSON, lValue, lDestValue: Variant;
lHandled: Boolean;
begin
lPrompt := UTF8ToString(TSynJSONTreeNode(Selected).Name);
if (Selected.Text[1] = '[') then
lPrompt := FormatUTF8('[%]', [lPrompt]);
lValue := '';
if not VarIsNull(TSynJSONTreeNode(Selected).Value) then
lValue := TSynJSONTreeNode(Selected).Value;
if Assigned(fOnCustomInput) then
fOnCustomInput(Self, Node, lPrompt, lValue, lHandled);
if not lHandled then
lValue := InputBox(SEnterValue, lPrompt, lValue);
// if not modification, exit
if (lValue = TSynJSONTreeNode(Selected).Value) then
Exit;
// remove children if input data was null
if (TDocVariantData(lValue).Kind = dvUndefined) and
((lValue = '') or IdemPChar(pointer(VariantToUTF8(lValue)), 'NULL')) and
Selected.HasChildren then begin
if (YesNo(SRemoveChildren, '', False) = mrYes) then begin
Selected.DeleteChildren;
TSynJSONTreeNode(Selected).Value := NULL;
UpdateNodeInfo(TSynJSONTreeNode(Selected));
Exit;
end;
end;
TDocVariantData(lJSON).InitJSON(lValue);
case TDocVariantData(lJSON).Kind of
dvUndefined: begin
Selected.Text := FormatUTF8('%: %', [lPrompt, lValue]);
lDestValue := TSynJSONTreeNode(Selected).Value;
VariantToVariant(lValue, lDestValue);
TSynJSONTreeNode(Selected).Value := lDestValue;
if Assigned(Selected.Parent) then begin
case TSynJSONTreeNode(Selected.Parent).JSONType of
jtnObject: TSynJSONTreeNode(Selected).JSONType := jtnObjectContent;
jtnArray: begin
TSynJSONTreeNode(Selected).JSONType := jtnArrayContent;
TDocVariantData(TSynJSONTreeNode(Selected.Parent).Value).Values[StrToInt(TSynJSONTreeNode(Selected).Name)] :=
TSynJSONTreeNode(Selected).Value;
end;
end;
end;
end;
else
case TDocVariantData(lJSON).Kind of
dvObject: TSynJSONTreeNode(Selected).JSONType := jtnObject;
dvArray: TSynJSONTreeNode(Selected).JSONType := jtnArray;
end;
Node.Value := _CopyFast(lJSON);
if Node.HasChildren then
Node.DeleteChildren;
InsertNode(Node, lJSON);
UpdateNodeInfo(Node);
end;
end;
procedure TSynJSONTreeView.LoadFromFile(const aFileName: TFileName);
begin
if (aFileName = '') then
Exit;
SetJSONText(StringFromFile(aFileName));
LoadJSON;
end;
procedure TSynJSONTreeView.SaveToFile(const aFileName: TFileName);
var
lJSON: RawUTF8;
begin
if (aFileName = '') then
Exit;
lJSON := ToJSON;
FileFromString(lJSON, aFileName);
end;
procedure TSynJSONTreeView.DoOnEditing(Sender: TObject; Node: TTreeNode; var AllowEdit: Boolean);
begin
AllowEdit := (estEdit in fAllowedEditionStates);
if AllowEdit and Assigned(fOnEditingBak) then
fOnEditingBak(Sender, Node, AllowEdit);
end;
procedure TSynJSONTreeView.VariantToVariant(aSource: Variant; var aDest: Variant);
var
lVar: TSQLVar;
lTmp: RawByteString;
begin
VariantToSQLVar(aDest, lTmp, lVar);
with lVar do
case VType of
ftNull: aDest := aSource;
ftCurrency: aDest := aSource.VInt64;
ftUTF8: aDest := VariantToUTF8(aSource);
ftInt64: begin
if (aSource <> '') then
if (UpperCaseU(aSource) <> 'TRUE') and (UpperCaseU(aSource) <> 'FALSE') then begin
aDest := StrToInt64Def(aSource, MaxInt);
if (aDest = MaxInt) then
raise ESynJSONTreeView.CreateUTF8('Invalid input data type: %', [aSource]);
end else
if (UpperCaseU(aSource) = 'TRUE') then
aDest := True
else
aDest := False;
end;
ftDouble: aDest := aSource.VDouble;
end;
end;
{ TSynJSONTreeNode }
function TSynJSONTreeNode.Clone: TSynJSONTreeNode;
begin
Result := TSynJSONTreeNode.Create(nil);
Result.Name := fName;
Result.JSONType := fJSONType;
Result.Value := fValue;
end;
end.

View File

@@ -0,0 +1,48 @@
object frmLevel: TfrmLevel
Left = 746
Top = 164
Width = 346
Height = 490
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object chklstLevel: TCheckListBox
Left = 0
Top = 0
Width = 338
Height = 423
Align = alClient
ItemHeight = 13
TabOrder = 0
end
object pnlBottom: TPanel
Left = 0
Top = 423
Width = 338
Height = 36
Align = alBottom
TabOrder = 1
object btnOK: TBitBtn
Left = 84
Top = 6
Width = 75
Height = 25
TabOrder = 0
Kind = bkOK
end
object btnCancel: TBitBtn
Left = 180
Top = 6
Width = 75
Height = 25
TabOrder = 1
Kind = bkCancel
end
end
end

View File

@@ -0,0 +1,73 @@
unit fLevel;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, ExtCtrls, CheckLst,
SynCommons;
type
TfrmLevel = class(TForm)
chklstLevel: TCheckListBox;
pnlBottom: TPanel;
btnOK: TBitBtn;
btnCancel: TBitBtn;
private
{ Private declarations }
public
{ Public declarations }
procedure FillListBox(const aJSON: Variant);
function ToJSON: RawUTF8;
end;
var
frmLevel: TfrmLevel;
implementation
{$R *.dfm}
{ TfrmLevel }
procedure TfrmLevel.FillListBox(const aJSON: Variant);
var
I, J, lCount: Integer;
begin
lCount := TDocVariantData(aJSON).Count;
chklstLevel.Items.BeginUpdate;
try
for I := 0 to lCount-1 do
begin
J := chklstLevel.Items.Add(TDocVariantData(aJSON).Values[I]);
chklstLevel.Checked[J] := True;
end;
finally
chklstLevel.Items.EndUpdate;
end;
end;
function TfrmLevel.ToJSON: RawUTF8;
var
lW: TTextWriter;
I: Integer;
begin
lW := TTextWriter.CreateOwnedStream;
try
lW.Add('[');
for I := 0 to chklstLevel.Items.Count-1 do
if chklstLevel.Checked[I] then
begin
lW.Add('"');
lW.AddString(chklstLevel.Items[I]);
lW.Add('"', ',');
end;
lW.CancelLastComma;
lW.Add(']');
lW.SetText(Result);
finally
lW.Free;
end;
end;
end.

View File

@@ -0,0 +1,430 @@
object frmJSONEditor: TfrmJSONEditor
Left = 600
Top = 213
Width = 466
Height = 643
Caption = 'Delphi JSON Editor'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Panel1: TPanel
Left = 0
Top = 0
Width = 458
Height = 33
Align = alTop
TabOrder = 0
object BitBtn1: TBitBtn
Left = 5
Top = 4
Width = 75
Height = 25
Action = EditPaste1
Caption = '&Paste'
TabOrder = 0
Glyph.Data = {
36040000424D3604000000000000360000002800000010000000100000000100
2000000000000004000000000000000000000000000000000000FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF008000000080000000800000008000
0000800000008000000080000000800000008000000080000000FF00FF000000
00000000000000000000000000000000000080000000FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0080000000000000008686
86000080800086868600008080008686860080000000FFFFFF00000000000000
000000000000000000000000000000000000FFFFFF0080000000000000000080
80008686860000808000868686000080800080000000FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0080000000000000008686
86000080800086868600008080008686860080000000FFFFFF00000000000000
000000000000FFFFFF0080000000800000008000000080000000000000000080
80008686860000808000868686000080800080000000FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF0080000000FFFFFF0080000000FF00FF00000000008686
86000080800086868600008080008686860080000000FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF008000000080000000FF00FF00FF00FF00000000000080
8000868686000080800086868600008080008000000080000000800000008000
000080000000800000008000000000000000FF00FF00FF00FF00000000008686
8600008080008686860000808000868686000080800086868600008080008686
860000808000868686000080800000000000FF00FF00FF00FF00000000000080
8000868686000000000000000000000000000000000000000000000000000000
000000000000868686008686860000000000FF00FF00FF00FF00000000008686
86008686860000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF0000000000868686000080800000000000FF00FF00FF00FF00000000000080
800086868600008080000000000000FFFF00000000000000000000FFFF000000
000086868600008080008686860000000000FF00FF00FF00FF00FF00FF000000
00000000000000000000000000000000000000FFFF0000FFFF00000000000000
0000000000000000000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF0000000000000000000000000000000000FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00}
end
object btnClear: TBitBtn
Left = 91
Top = 4
Width = 75
Height = 25
Action = EditClear1
Caption = '&Clear'
TabOrder = 1
Glyph.Data = {
36040000424D3604000000000000360000002800000010000000100000000100
2000000000000004000000000000000000000000000000000000FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF0000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF0000000000FF00FF00FF00FF00FF00
FF00000000000000000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF0000000000000000000000000000000000FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF0000000000FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00000000000000000000000000FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF0000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00000000000000000000000000FF00FF00FF00FF00FF00
FF00FF00FF000000000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00000000000000000000000000FF00FF00FF00
FF000000000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF000000000000000000000000000000
000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF0000000000000000000000
0000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF000000000000000000000000000000
000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00000000000000000000000000FF00FF00FF00
FF000000000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF0000000000000000000000000000000000FF00FF00FF00FF00FF00
FF00FF00FF000000000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF0000000000000000000000000000000000FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF000000000000000000FF00FF00FF00FF00FF00FF00FF00
FF00000000000000000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF0000000000FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00}
end
object btnSaveJSON: TBitBtn
Left = 178
Top = 4
Width = 75
Height = 25
Action = EditSave1
Caption = '&Save'
TabOrder = 2
Glyph.Data = {
36040000424D3604000000000000360000002800000010000000100000000100
2000000000000004000000000000000000000000000000000000C8C8C8008F8D
8D008B8787008784840087848400878484008784840087848400878484008784
8400878484008784840087848400908E8E008F8D8D00DADADA008E8E8E008181
80006E6C6C00A6A2A200A6A2A200A6A2A200A6A2A200A6A2A200A6A2A200A6A2
A200A6A2A200A6A2A200A6A2A200272424007C7B7B009C9A9A008E8C8C001F1C
1B008E8A8900EAE5E400E8E4E300E8E4E300E8E4E300E8E4E300E8E4E300E8E4
E300E8E4E300E8E4E300EBE7E600353130001F1C1B009C9B9B008F8D8D00211E
1E008D8A8900EFEAE900EFEAE900EFEAE900EFEAE900EFEAE900EFEAE900EFEA
E900EFEAE900EFEAE900EFEAE90036333300211E1E009C9C9C00908F8F002421
21008C898900E7E2E100E5E0DF00E5E0DF00E5E0DF00E5E0DF00E5E0DF00E5E0
DF00E5E0DF00E5E0DF00E8E2E10039363600242121009F9C9C00929090002724
23008C878700E4DEDE00E3DDDD00E3DDDD00E3DDDD00E3DDDD00E3DDDD00E3DD
DD00E3DDDD00E3DDDD00E6E0E0003B383800272423009F9C9C00939191002926
26008A878700E3DCDC00E1DBDA00E1DBDA00E1DBDA00E1DBDA00E1DBDA00E1DB
DA00E1DBDA00E1DBDA00E4DEDD003D3A3A00292626009F9C9C00949392002C29
280075727000CDC7C600CEC7C700CEC7C700CEC7C700CEC7C700CEC7C700CEC7
C700CEC7C700CEC7C700CAC4C400383433002C2928009F9F9F00969494002F2C
2B002F2C2B002F2C2B002F2C2B002F2C2B002F2C2B002F2C2B002F2C2B002F2C
2B002F2C2B002F2C2B002F2C2B002F2C2B002F2C2B009F9F9F0097959500312E
2D00312E2D0043403F00423F3F00434040004340400043404000434040004340
4000434040003F3C3C003C3B3A0038343300312E2D00A09F9F009A9898003734
330037343300807E7E00B5B3B30095939300B5B3B300B7B5B500B7B5B500B7B5
B500B7B5B50098969600201C1C00423F3E0037343300A2A0A0009E9C9B003F3B
3A003F3B3A0089868600ABAAAA0027232300B1B1B100B5B4B400B5B4B400B5B4
B400B5B4B4009E9A9A0027232300484545003F3B3A00A5A3A300A2A09F004743
4100474341008C898900ABAAAA002F2A2A00B1B1B100B5B4B400B5B4B400B5B4
B400B5B4B400A09C9C002F2A2A00504C4B0047434100A6A5A500A6A4A2004F4B
48004F4B48009A989800BFBEBE0037313100C8C7C700D1D0D000D1D0D000D1D0
D000D1D0D000AFABAB0037313100585352004F4B4800A8A6A600D6D6D5005E5B
5A0057535000A9A7A600E5E4E400C5C2C200EAE9E900EEEDED00EEEDED00EEED
ED00EEEDED00BDBBBB003F3838005F5B590057535000ABA9A800FF00FF00D9D8
D800AFADAC00A9A9A9009A9797009A9797009A9797009A9797009A9997009A99
97009A999700A6A5A500B7B7B700B5B5B300B0AFAE00D4D4D400}
end
object btnLoad: TBitBtn
Left = 264
Top = 4
Width = 75
Height = 25
Action = actEditLoad1
Caption = 'Load'
TabOrder = 3
Glyph.Data = {
36040000424D3604000000000000360000002800000010000000100000000100
2000000000000004000000000000000000000000000000000000FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00D2CE
CD00C4B09F00A4917E00A4917E00A4917E00A4917E00A4917E00A4917E00A491
7E00A4917E00A18C7B00C5B29F00CFC8BF00FF00FF00FF00FF00FF00FF008D89
8500A87B5500C7905D00C7905D00C7905D00C7905D00C78F5D00C78F5C00C78F
5C00C78F5C00C78F5C00C78F5C00BA895C00E4DCD600FF00FF00FF00FF00A2A2
A20087756500CA986A00CE9B6C00CE9B6C00CE9B6C00CE9B6C00CD9B6B00CD9B
6B00CD9A6B00CD9A6B00CD9A6B00CA976700DDC2AC00FF00FF00FF00FF009393
93009A928C00C59B7500D2A57B00D1A37800D0A17500D0A07400CFA07300CFA0
7300CF9F7200CF9F7200CF9F7200D0A17400CDA48500FF00FF00FF00FF009393
9300BAB8B600C6A28300D5A98200D3A87F00D3A77E00D3A77E00D3A77D00D3A6
7D00D2A57B00D1A37800CFA07300CF9F7200CAA07900FF00FF00E9E9E9009292
9200B8B8B800C1A08500D6AD8600D4AA8100D4A98100D4A98000D4A88000D4A8
7F00D3A87F00D3A77E00D3A67D00D0A17500CFA27900E2CEBC00E3E3E3009797
9700B0B0B000BCA48D00D5AD8800D5AD8600D5AC8500D5AC8400D5AB8400D4AB
8300D4AB8200D4AA8200D4AA8100D4A98000D4A87F00D4B29600DADADA00ABAB
AB00A4A4A400B2A29400CAA58300CDA98900CDA98900CDA98900CDA98900CDA9
8900CDA98900CDA98900C6A18400CEAA8800D3AD8C00D0AB8D00CFCFCF00B5B5
B50099999900B8B7B700A8A5A100A7A4A100A7A4A100A8A5A100A8A5A100A9A5
A200ADA8A400AEA9A400B0ABA600A8A29C00FF00FF00FF00FF00C7C7C700B4B4
B400A1A1A100BBBBBB00BDBDBD00B5B5B500B6B6B600B6B6B600B6B6B600B6B6
B600B7B7B700B8B8B800BEBEBE00B5B5B500E4E4E400FF00FF00C1C1C100B1B1
B100A8A8A800ADADAD00D2D2D200BEBEBE00BCBCBC00BDBDBD00BDBDBD00BDBD
BD00BEBEBE00C0C0C000C4C4C400CCCCCC00D7D7D700FF00FF00BEBEBE00B6B6
B600B1B1B100A2A2A200E3E3E300D0D0D000CDCDCD00CECECE00CFCFCF00CFCF
CF00CFCFCF00D3D3D300DDDDDD00E5E5E500D5D5D500FF00FF00FF00FF00D1D1
D100D4D4D400B4B4B400E8E8E800E5E5E500E4E4E400E3E3E300E3E3E300E3E3
E300E3E3E300E4E4E400E4E4E400E7E7E700CFCFCF00FF00FF00FF00FF00FF00
FF00FF00FF00FF00FF00D5D5D500D7D7D700D7D7D700D8D8D800D9D9D900DADA
DA00DCDCDC00DDDDDD00DDDDDD00DFDFDF00EAEAEA00FF00FF00}
end
end
object pnlJSONTreeView: TPanel
Left = 0
Top = 33
Width = 458
Height = 579
Align = alClient
Caption = 'JSON TreeView'
TabOrder = 1
end
object ActionList1: TActionList
Images = ImageList1
Left = 327
Top = 150
object EditPaste1: TEditPaste
Category = 'Edit'
Caption = '&Paste'
Hint = 'Paste|Inserts Clipboard contents'
ImageIndex = 0
ShortCut = 16470
OnExecute = EditPaste1Execute
end
object EditClear1: TEditDelete
Category = 'Edit'
Caption = '&Clear'
Enabled = False
Hint = 'Clear|Clears the selection'
ImageIndex = 1
ShortCut = 16430
OnExecute = EditClear1Execute
end
object ActionToggleVisibleChildrenCounts: TAction
AutoCheck = True
Caption = 'Visible Children Counts'
OnExecute = ActionToggleVisibleChildrenCountsExecute
end
object ActionToggleVisibleByteSizes: TAction
AutoCheck = True
Caption = 'Visible Byte Sizes'
OnExecute = ActionToggleVisibleByteSizesExecute
end
object EditSave1: TAction
Category = 'Edit'
Caption = '&Save'
Enabled = False
Hint = 'Save|Save to JSON file'
ImageIndex = 2
ShortCut = 16467
OnExecute = EditSave1Execute
end
object actEditLoad1: TAction
Category = 'Edit'
Caption = 'Load'
Hint = 'Load|Load JSON from file'
ImageIndex = 3
ShortCut = 16463
OnExecute = actEditLoad1Execute
end
end
object ImageList1: TImageList
Left = 335
Top = 238
Bitmap = {
494C0101040008000C0010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
0000000000003600000028000000400000001000000001002000000000000010
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000C8C8C8008F8D8D008B8787008784
8400878484008784840087848400878484008784840087848400878484008784
840087848400908E8E008F8D8D00DADADA000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000080000000800000008000000080000000800000008000
0000800000008000000080000000800000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000008E8E8E00818180006E6C6C00A6A2
A200A6A2A200A6A2A200A6A2A200A6A2A200A6A2A200A6A2A200A6A2A200A6A2
A200A6A2A200272424007C7B7B009C9A9A000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000080000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00800000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000008E8C8C001F1C1B008E8A8900EAE5
E400E8E4E300E8E4E300E8E4E300E8E4E300E8E4E300E8E4E300E8E4E300E8E4
E300EBE7E600353130001F1C1B009C9B9B0000000000D2CECD00C4B09F00A491
7E00A4917E00A4917E00A4917E00A4917E00A4917E00A4917E00A4917E00A18C
7B00C5B29F00CFC8BF0000000000000000000000000086868600008080008686
8600008080008686860080000000FFFFFF000000000000000000000000000000
00000000000000000000FFFFFF00800000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000008F8D8D00211E1E008D8A8900EFEA
E900EFEAE900EFEAE900EFEAE900EFEAE900EFEAE900EFEAE900EFEAE900EFEA
E900EFEAE90036333300211E1E009C9C9C00000000008D898500A87B5500C790
5D00C7905D00C7905D00C7905D00C78F5D00C78F5C00C78F5C00C78F5C00C78F
5C00C78F5C00BA895C00E4DCD600000000000000000000808000868686000080
8000868686000080800080000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00800000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000908F8F00242121008C898900E7E2
E100E5E0DF00E5E0DF00E5E0DF00E5E0DF00E5E0DF00E5E0DF00E5E0DF00E5E0
DF00E8E2E10039363600242121009F9C9C0000000000A2A2A20087756500CA98
6A00CE9B6C00CE9B6C00CE9B6C00CE9B6C00CD9B6B00CD9B6B00CD9A6B00CD9A
6B00CD9A6B00CA976700DDC2AC00000000000000000086868600008080008686
8600008080008686860080000000FFFFFF00000000000000000000000000FFFF
FF00800000008000000080000000800000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000092909000272423008C878700E4DE
DE00E3DDDD00E3DDDD00E3DDDD00E3DDDD00E3DDDD00E3DDDD00E3DDDD00E3DD
DD00E6E0E0003B383800272423009F9C9C0000000000939393009A928C00C59B
7500D2A57B00D1A37800D0A17500D0A07400CFA07300CFA07300CF9F7200CF9F
7200CF9F7200D0A17400CDA48500000000000000000000808000868686000080
8000868686000080800080000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF0080000000FFFFFF0080000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000093919100292626008A878700E3DC
DC00E1DBDA00E1DBDA00E1DBDA00E1DBDA00E1DBDA00E1DBDA00E1DBDA00E1DB
DA00E4DEDD003D3A3A00292626009F9C9C000000000093939300BAB8B600C6A2
8300D5A98200D3A87F00D3A77E00D3A77E00D3A77D00D3A67D00D2A57B00D1A3
7800CFA07300CF9F7200CAA07900000000000000000086868600008080008686
8600008080008686860080000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00800000008000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000949392002C29280075727000CDC7
C600CEC7C700CEC7C700CEC7C700CEC7C700CEC7C700CEC7C700CEC7C700CEC7
C700CAC4C400383433002C2928009F9F9F00E9E9E90092929200B8B8B800C1A0
8500D6AD8600D4AA8100D4A98100D4A98000D4A88000D4A87F00D3A87F00D3A7
7E00D3A67D00D0A17500CFA27900E2CEBC000000000000808000868686000080
8000868686000080800080000000800000008000000080000000800000008000
0000800000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000969494002F2C2B002F2C2B002F2C
2B002F2C2B002F2C2B002F2C2B002F2C2B002F2C2B002F2C2B002F2C2B002F2C
2B002F2C2B002F2C2B002F2C2B009F9F9F00E3E3E30097979700B0B0B000BCA4
8D00D5AD8800D5AD8600D5AC8500D5AC8400D5AB8400D4AB8300D4AB8200D4AA
8200D4AA8100D4A98000D4A87F00D4B296000000000086868600008080008686
8600008080008686860000808000868686000080800086868600008080008686
8600008080000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000097959500312E2D00312E2D004340
3F00423F3F004340400043404000434040004340400043404000434040003F3C
3C003C3B3A0038343300312E2D00A09F9F00DADADA00ABABAB00A4A4A400B2A2
9400CAA58300CDA98900CDA98900CDA98900CDA98900CDA98900CDA98900CDA9
8900C6A18400CEAA8800D3AD8C00D0AB8D000000000000808000868686000000
0000000000000000000000000000000000000000000000000000000000008686
8600868686000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000009A9898003734330037343300807E
7E00B5B3B30095939300B5B3B300B7B5B500B7B5B500B7B5B500B7B5B5009896
9600201C1C00423F3E0037343300A2A0A000CFCFCF00B5B5B50099999900B8B7
B700A8A5A100A7A4A100A7A4A100A8A5A100A8A5A100A9A5A200ADA8A400AEA9
A400B0ABA600A8A29C0000000000000000000000000086868600868686000000
0000000000000000000000000000000000000000000000000000000000008686
8600008080000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000009E9C9B003F3B3A003F3B3A008986
8600ABAAAA0027232300B1B1B100B5B4B400B5B4B400B5B4B400B5B4B4009E9A
9A0027232300484545003F3B3A00A5A3A300C7C7C700B4B4B400A1A1A100BBBB
BB00BDBDBD00B5B5B500B6B6B600B6B6B600B6B6B600B6B6B600B7B7B700B8B8
B800BEBEBE00B5B5B500E4E4E400000000000000000000808000868686000080
80000000000000FFFF00000000000000000000FFFF0000000000868686000080
8000868686000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000A2A09F0047434100474341008C89
8900ABAAAA002F2A2A00B1B1B100B5B4B400B5B4B400B5B4B400B5B4B400A09C
9C002F2A2A00504C4B0047434100A6A5A500C1C1C100B1B1B100A8A8A800ADAD
AD00D2D2D200BEBEBE00BCBCBC00BDBDBD00BDBDBD00BDBDBD00BEBEBE00C0C0
C000C4C4C400CCCCCC00D7D7D700000000000000000000000000000000000000
0000000000000000000000FFFF0000FFFF000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000A6A4A2004F4B48004F4B48009A98
9800BFBEBE0037313100C8C7C700D1D0D000D1D0D000D1D0D000D1D0D000AFAB
AB0037313100585352004F4B4800A8A6A600BEBEBE00B6B6B600B1B1B100A2A2
A200E3E3E300D0D0D000CDCDCD00CECECE00CFCFCF00CFCFCF00CFCFCF00D3D3
D300DDDDDD00E5E5E500D5D5D500000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000D6D6D5005E5B5A0057535000A9A7
A600E5E4E400C5C2C200EAE9E900EEEDED00EEEDED00EEEDED00EEEDED00BDBB
BB003F3838005F5B590057535000ABA9A80000000000D1D1D100D4D4D400B4B4
B400E8E8E800E5E5E500E4E4E400E3E3E300E3E3E300E3E3E300E3E3E300E4E4
E400E4E4E400E7E7E700CFCFCF00000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000D9D8D800AFADAC00A9A9
A9009A9797009A9797009A9797009A9797009A9997009A9997009A999700A6A5
A500B7B7B700B5B5B300B0AFAE00D4D4D4000000000000000000000000000000
0000D5D5D500D7D7D700D7D7D700D8D8D800D9D9D900DADADA00DCDCDC00DDDD
DD00DDDDDD00DFDFDF00EAEAEA0000000000424D3E000000000000003E000000
2800000040000000100000000100010000000000800000000000000000000000
000000000000000000000000FFFFFF00FFFFFFFF0000FFFFFC00FFFF0000FFFF
8000EFFD000080030000C7FF000080010000C3FB000080010000E3F700008001
0001F1E7000080010003F8CF000000000003FC1F000000000003FE3F00000000
0003FC1F000000030FC3F8CF000000010003E1E7000000018007C3F300000001
F87FC7FD00008001FFFFFFFF8000F00100000000000000000000000000000000
000000000000}
end
object PopupMenu1: TPopupMenu
Left = 323
Top = 92
object VisibleChildrenCounts1: TMenuItem
Action = ActionToggleVisibleChildrenCounts
AutoCheck = True
end
object VisibleByteSizes1: TMenuItem
Action = ActionToggleVisibleByteSizes
AutoCheck = True
end
end
object dlgSave: TSaveDialog
DefaultExt = 'json'
Filter = 'JSON file|*.json'
Options = [ofOverwritePrompt, ofHideReadOnly, ofEnableSizing]
Title = 'Save JSON file'
Left = 184
Top = 41
end
object dlgOpenJSONFile: TOpenDialog
DefaultExt = 'json'
Filter = 'JSON File|*.json'
Options = [ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing]
Title = 'Select a JSON file'
Left = 272
Top = 97
end
end

View File

@@ -0,0 +1,155 @@
unit fMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, Buttons, ActnList, StdActns, ImgList, Menus,
ComCtrls,
SynJSONTreeView,
SynCommons;
type
TfrmJSONEditor = class(TForm)
Panel1: TPanel;
ActionList1: TActionList;
ImageList1: TImageList;
EditPaste1: TEditPaste;
EditClear1: TEditDelete;
BitBtn1: TBitBtn;
btnClear: TBitBtn;
ActionToggleVisibleChildrenCounts: TAction;
ActionToggleVisibleByteSizes: TAction;
PopupMenu1: TPopupMenu;
VisibleChildrenCounts1: TMenuItem;
VisibleByteSizes1: TMenuItem;
pnlJSONTreeView: TPanel;
btnSaveJSON: TBitBtn;
EditSave1: TAction;
dlgSave: TSaveDialog;
actEditLoad1: TAction;
btnLoad: TBitBtn;
dlgOpenJSONFile: TOpenDialog;
procedure ActionToggleVisibleChildrenCountsExecute(Sender: TObject);
procedure ActionToggleVisibleByteSizesExecute(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure EditPaste1Execute(Sender: TObject);
procedure EditClear1Execute(Sender: TObject);
procedure EditSave1Execute(Sender: TObject);
procedure actEditLoad1Execute(Sender: TObject);
private
{ Private declarations }
JSONTreeView1: TSynJSONTreeView;
procedure DoOnCustomInput(Sender: TObject; Node: TSynJSONTreeNode;
var Prompt: RawUTF8; var Value: Variant; var Handled: Boolean);
procedure SetJSON(const aJSON: RawUTF8);
procedure ToogleButtons;
public
{ Public declarations }
end;
var
frmJSONEditor: TfrmJSONEditor;
implementation
uses
Clipbrd,
fLevel;
{$R *.dfm}
procedure TfrmJSONEditor.FormCreate(Sender: TObject);
begin
JSONTreeView1 := TSynJSONTreeView.Create(pnlJSONTreeView);
JSONTreeView1.PopupMenu := PopupMenu1;
JSONTreeView1.Align := alClient;
JSONTreeView1.Parent := pnlJSONTreeView;
JSONTreeView1.OnCustomInput := DoOnCustomInput;
ActionToggleVisibleByteSizes.Checked := JSONTreeView1.VisibleByteSizes;
ActionToggleVisibleChildrenCounts.Checked := JSONTreeView1.VisibleChildrenCounts;
end;
procedure TfrmJSONEditor.ActionToggleVisibleByteSizesExecute(Sender: TObject);
begin
JSONTreeView1.VisibleByteSizes := not JSONTreeView1.VisibleByteSizes;
end;
procedure TfrmJSONEditor.ActionToggleVisibleChildrenCountsExecute(Sender: TObject);
begin
JSONTreeView1.VisibleChildrenCounts := not JSONTreeView1.VisibleChildrenCounts;
end;
procedure TfrmJSONEditor.EditClear1Execute(Sender: TObject);
begin
JSONTreeView1.ClearAll;
ToogleButtons;
end;
procedure TfrmJSONEditor.EditPaste1Execute(Sender: TObject);
begin
SetJSON(Clipboard.AsText);
ToogleButtons;
end;
procedure TfrmJSONEditor.EditSave1Execute(Sender: TObject);
begin
if dlgSave.Execute then
JSONTreeView1.SaveToFile(dlgSave.FileName);
end;
procedure TfrmJSONEditor.actEditLoad1Execute(Sender: TObject);
begin
if dlgOpenJSONFile.Execute then
begin
SetJSON(StringFromFile(dlgOpenJSONFile.FileName));
ToogleButtons;
end;
end;
procedure TfrmJSONEditor.SetJSON(const aJSON: RawUTF8);
begin
JSONTreeView1.JsonText := aJSON;
JSONTreeView1.Items.BeginUpdate;
JSONTreeView1.LoadJSON;
JSONTreeView1.Items.EndUpdate;
end;
procedure TfrmJSONEditor.ToogleButtons;
begin
EditSave1.Enabled := (JSONTreeView1.Items.Count > 0);
EditClear1.Enabled := (JSONTreeView1.Items.Count > 0);
end;
procedure TfrmJSONEditor.DoOnCustomInput(Sender: TObject;
Node: TSynJSONTreeNode; var Prompt: RawUTF8; var Value: Variant; var Handled: Boolean);
procedure ProcessLevel;
begin
if (TDocVariantData(Value).Kind <> dvArray) then
begin
MessageDlg('Level node is not an array', mtError, [mbOK], 0);
Exit;
end;
with TFrmLevel.Create(nil) do
begin
Caption := Prompt;
FillListBox(Value);
ShowModal;
if (ModalResult = mrOK) then
begin
TDocVariantData(Value).Clear;
TDocVariantData(Value).InitJSON(ToJSON);
end;
Handled := True;
end;
end;
begin
if IdemPChar(pointer(Prompt), 'LEVEL') then
ProcessLevel;
end;
end.