* Initial implementation of JSON viewer

git-svn-id: trunk@27406 -
This commit is contained in:
michael 2010-09-18 09:56:29 +00:00
parent 4249723a19
commit 90df5d83ac
17 changed files with 3262 additions and 0 deletions

16
.gitattributes vendored
View File

@ -5542,6 +5542,22 @@ tools/install/win/lazarus-cross.iss svneol=native#text/plain
tools/install/win/lazarus_install_cheetah.bmp -text svneol=unset#image/bmp
tools/install/win/lazarus_install_cheetah_small.bmp -text svneol=unset#image/bmp
tools/install/win/readme.txt svneol=native#text/plain
tools/jsonviewer/README.txt svneol=native#text/plain
tools/jsonviewer/frmmain.lfm svneol=native#text/plain
tools/jsonviewer/frmmain.pp svneol=native#text/plain
tools/jsonviewer/frmnewboolean.lfm svneol=native#text/plain
tools/jsonviewer/frmnewboolean.pp svneol=native#text/plain
tools/jsonviewer/frmnewinteger.lfm svneol=native#text/plain
tools/jsonviewer/frmnewinteger.pp svneol=native#text/plain
tools/jsonviewer/frmnewstring.lfm svneol=native#text/plain
tools/jsonviewer/frmnewstring.pp svneol=native#text/plain
tools/jsonviewer/jsonviewer.ico -text
tools/jsonviewer/jsonviewer.lpi svneol=native#text/plain
tools/jsonviewer/jsonviewer.lpr svneol=native#text/plain
tools/jsonviewer/jsonviewer.res -text
tools/jsonviewer/languages/jsonviewer.po svneol=native#text/plain
tools/jsonviewer/mainform.ico -text
tools/jsonviewer/msgjsonviewer.pp svneol=native#text/plain
tools/lazdatadesktop/README.txt svneol=native#text/plain
tools/lazdatadesktop/bitmaps/btndown.bmp -text
tools/lazdatadesktop/bitmaps/btndown.xpm -text

View File

@ -0,0 +1,28 @@
This little application allows to view JSON data in a graphical tree.
Each array and object is represented in the tree with the members (or
elements) below them.
It should be compilable with FPC version 2.4.0 and up.
The data can be loaded from a file, or can be pasted from the clipboard.
(Edit|Paste as new document)
It is possible to edit the JSON (change member names, values), add items,
and save the data. It is also possible to copy&paste parts of the structure.
Options menu:
When compiled with FPC 2.5.1 or higher, the 'Strict JSON' option appears
under the 'Options' menu. This option will be off by default (matching
TJSONParser's behaviour). See fpc/packages/fcl-json/src/README.txt
for an explanation of the Strict JSON property.
The 'Start new document with Object' option will cause the application to
create an object as root object when File-New is chosen.
The 'Sort member names' will sort the member names in an object
alphabetically.
TODO:
Implement a search feature.

1453
tools/jsonviewer/frmmain.lfm Normal file

File diff suppressed because it is too large Load Diff

960
tools/jsonviewer/frmmain.pp Normal file
View File

@ -0,0 +1,960 @@
{ JSON data viewer main form
Copyright (C) 2010 Michael Van Canneyt michael@freepascal.org
This source is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
A copy of the GNU General Public License is available on the World Wide Web
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
{$IFNDEF VER2_4}
{$DEFINE HAVESTRICT}
{$ENDIF}
unit frmmain;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ActnList,
Menus, ComCtrls, IniPropStorage, fpJSON, JSONParser, PropertyStorage;
type
{ TMainForm }
TMainForm = class(TForm)
ACopy: TAction;
AExpandCurrentContainer: TAction;
AExpandAll: TAction;
APasteAsDocument: TAction;
APaste: TAction;
ACut: TAction;
ADeleteValue: TAction;
ANewBooleanValue: TAction;
ANewNullValue: TAction;
ANewNumberValue: TAction;
ANewStringValue: TAction;
ANewObject: TAction;
ANewArray: TAction;
AQuit: TAction;
ASaveAs: TAction;
ASave: TAction;
AOpen: TAction;
ANew: TAction;
ActionList1: TActionList;
ILJSON: TImageList;
MEDit: TMenuItem;
MenuItem2: TMenuItem;
MIExpandCurrent: TMenuItem;
MIExpandAll: TMenuItem;
MIPasteAsDocument: TMenuItem;
MIpaste: TMenuItem;
MICut: TMenuItem;
MICopy: TMenuItem;
MISortMembers: TMenuItem;
MenuItem8: TMenuItem;
MIDelete: TMenuItem;
PSMain: TIniPropStorage;
MenuItem1: TMenuItem;
MINewNull: TMenuItem;
MINewNumber: TMenuItem;
MINewBoolean: TMenuItem;
MINewString: TMenuItem;
MINewArray: TMenuItem;
MINewObject: TMenuItem;
MIdocument: TMenuItem;
MIStrict: TMenuItem;
MOptions: TMenuItem;
MIInsert: TMenuItem;
MIQuit: TMenuItem;
MISaveAs: TMenuItem;
MISave: TMenuItem;
MIOpen: TMenuItem;
MINew: TMenuItem;
MFile: TMenuItem;
MMJSON: TMainMenu;
ODJSON: TOpenDialog;
SDJSON: TSaveDialog;
TBJSON: TToolBar;
TBNew: TToolButton;
TBNewButton: TToolButton;
TBOpen: TToolButton;
TBSave: TToolButton;
ToolButton1: TToolButton;
ToolButton2: TToolButton;
ToolButton4: TToolButton;
TBNEwNull: TToolButton;
TBNewBoolean: TToolButton;
TBNewNumber: TToolButton;
TBNewString: TToolButton;
TBNewArray: TToolButton;
TVJSON: TTreeView;
procedure ACopyExecute(Sender: TObject);
procedure ACopyUpdate(Sender: TObject);
procedure ACutExecute(Sender: TObject);
procedure ACutUpdate(Sender: TObject);
procedure ADeleteValueExecute(Sender: TObject);
procedure ADeleteValueUpdate(Sender: TObject);
procedure AExpandAllExecute(Sender: TObject);
procedure AExpandAllUpdate(Sender: TObject);
procedure AExpandCurrentContainerExecute(Sender: TObject);
procedure AExpandCurrentContainerUpdate(Sender: TObject);
procedure ANewArrayExecute(Sender: TObject);
procedure ANewBooleanValueExecute(Sender: TObject);
procedure ANewNullValueExecute(Sender: TObject);
procedure ANewNumberValueExecute(Sender: TObject);
procedure ANewObjectExecute(Sender: TObject);
procedure ANewStringValueExecute(Sender: TObject);
procedure APasteAsDocumentExecute(Sender: TObject);
procedure APasteExecute(Sender: TObject);
procedure APasteUpdate(Sender: TObject);
procedure AQuitExecute(Sender: TObject);
procedure ASaveExecute(Sender: TObject);
procedure ContainerAvailable(Sender: TObject);
procedure ANewExecute(Sender: TObject);
procedure AOpenExecute(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure HaveData(Sender: TObject);
procedure MIdocumentClick(Sender: TObject);
procedure MISortMembersClick(Sender: TObject);
procedure MIStrictClick(Sender: TObject);
procedure PSMainRestoreProperties(Sender: TObject);
procedure PSMainStoredValues0Restore(Sender: TStoredValue;
var Value: TStoredType);
procedure PSMainStoredValues1Restore(Sender: TStoredValue;
var Value: TStoredType);
procedure PSMainStoredValues2Restore(Sender: TStoredValue;
var Value: TStoredType);
procedure TVJSONChanging(Sender: TObject; Node: TTreeNode;
var AllowChange: Boolean);
procedure TVJSONEdited(Sender: TObject; Node: TTreeNode; var S: string);
procedure TVJSONEditing(Sender: TObject; Node: TTreeNode;
var AllowEdit: Boolean);
private
FRoot : TJSONData;
FFileName : String;
FSortObjectMembers,
FStrict,
FNewObject,
FModified : Boolean;
procedure AddDataToContainer(const AMemberName: String; D: TJSONData);
procedure CopyCurrentData;
procedure DeleteCurrentValue;
procedure Modify;
procedure AddNewValue(AType: TJSONType);
function CurrentNode: TTreeNode;
function CurrentNodeType : TJSONType;
function CurrentData: TJSONData;
function CurrentContainerNode: TTreeNode;
function CurrentContainertype: TJSONtype;
Function CurrentContainer: TJSONData;
function FindContainerNode(AStart: TTreeNode): TTreeNode;
function GetSaveFileName(Force: Boolean): String;
function IsContainerNode(ANode: TTreeNode): Boolean;
procedure NewDocument;
procedure OpenFile(const AFileName: String);
procedure PasteJSON(DoClear: Boolean);
procedure SaveToFile(const AFileName: string);
procedure SetCaption;
procedure ShowJSONData(AParent: TTreeNode; Data: TJSONData);
procedure ShowJSONDocument;
{ private declarations }
public
{ public declarations }
end;
var
MainForm: TMainForm;
implementation
uses msgjsonviewer, frmNewBoolean, frmNewINteger, frmNewString, clipbrd;
{$R *.lfm}
Const
ImageTypeMap : Array[TJSONtype] of Integer =
// jtUnknown, jtNumber, jtString, jtBoolean, jtNull, jtArray, jtObject
(-1,8,9,7,6,5,4);
JSONTypeNames : Array[TJSONtype] of string =
('Unknown','Number','String','Boolean','Null','Array','Object');
{ TMainForm }
procedure TMainForm.MIStrictClick(Sender: TObject);
begin
FStrict:=(Sender as TMenuItem).Checked;
PSMain.StoredValue['strict']:=IntToStr(Ord(Fstrict));
end;
procedure TMainForm.PSMainRestoreProperties(Sender: TObject);
begin
end;
procedure TMainForm.PSMainStoredValues0Restore(Sender: TStoredValue;
var Value: TStoredType);
begin
FStrict:=StrToIntDef(Value,0)=1
end;
procedure TMainForm.PSMainStoredValues1Restore(Sender: TStoredValue;
var Value: TStoredType);
begin
FNewObject:=StrToIntDef(Value,0)=1
end;
procedure TMainForm.PSMainStoredValues2Restore(Sender: TStoredValue;
var Value: TStoredType);
begin
FSortObjectMembers:=StrToIntDef(Value,0)=1;
end;
procedure TMainForm.TVJSONChanging(Sender: TObject; Node: TTreeNode;
var AllowChange: Boolean);
begin
end;
procedure TMainForm.TVJSONEdited(Sender: TObject; Node: TTreeNode; var S: string
);
Var
D : TJSONData;
O : TJSONObject;
I : Integer;
begin
D:=CurrentData;
If (Node.Data=Nil) then
begin
// Member name change
O:=CurrentContainer as TJSONObject;
I:=O.IndexOfName(S);
If (I=-1) then
begin
I:=O.IndexOf(D);
O.Extract(I);
O.Add(S,D);
end
else
begin
if (O.Items[i]<>D) then
begin
ShowMessage(Format(SDuplicateMemberName,[S]));
S:=O.Names[I];
end
end;
end
else
begin
// value change
try
D.AsString:=S;
except
ShowMessage(Format(SErrInvalidValue,[S]));
S:=D.AsString;
end
end;
Modify;
end;
procedure TMainForm.TVJSONEditing(Sender: TObject; Node: TTreeNode;
var AllowEdit: Boolean);
begin
if (Node.Data=Nil) then
// Label node. Allow member name change for objects
AllowEdit:=(CurrentContainerType=jtObject)
else
// value node. Allow change for simple not null values
AllowEdit:=Not (CurrentNodeType in [jtNull,jtArray,jtObject]);
end;
procedure TMainForm.Modify;
begin
FModified:=True;
SetCaption;
end;
procedure TMainForm.SetCaption;
Var
FN : String;
begin
If (FFileName='') then
FN:=SEmpty
else
FN:=FFileName;
If FModified then
FN:=FN+' *';
Caption:=SCaption+' ['+FN+']';
end;
procedure TMainForm.ANewExecute(Sender: TObject);
begin
NewDocument;
end;
procedure TMainForm.NewDocument;
begin
FreeAndNil(FRoot);
If FNewObject then
FRoot:=TJSONObject.Create;
ShowJSONDocument;
FFileName:='';
SetCaption;
end;
procedure TMainForm.ContainerAvailable(Sender: TObject);
begin
(Sender as Taction).Enabled:=(TVJSON.Items.Count=0) or (Nil<>CurrentContainer) ;
end;
procedure TMainForm.ASaveExecute(Sender: TObject);
Var
S : String;
begin
S:=GetSaveFileName(Sender=ASaveAs);
If (S<>'') then
SaveToFile(S);
end;
procedure TMainForm.AQuitExecute(Sender: TObject);
begin
Close;
end;
procedure TMainForm.ANewNullValueExecute(Sender: TObject);
begin
AddNewValue(jtNull);
end;
procedure TMainForm.ANewArrayExecute(Sender: TObject);
begin
AddNewValue(jtArray);
end;
procedure TMainForm.ADeleteValueUpdate(Sender: TObject);
begin
(Sender as TAction).Enabled:=(CurrentNodeType<>jtUnknown)
end;
procedure TMainForm.AExpandAllExecute(Sender: TObject);
begin
With TVJSON do
if (Items.Count>0) then
Items[0].Expand(True);
end;
procedure TMainForm.AExpandAllUpdate(Sender: TObject);
begin
(Sender as TAction).Enabled:=Assigned(FRoot);
end;
procedure TMainForm.AExpandCurrentContainerExecute(Sender: TObject);
Var
N : TTreeNode;
begin
N:=CurrentContainerNode;
If Assigned(N) then
N.Expand(True);
end;
procedure TMainForm.AExpandCurrentContainerUpdate(Sender: TObject);
begin
(Sender as TACtion).Enabled:=(CurrentContainerType<>jtUnknown)
end;
procedure TMainForm.ADeleteValueExecute(Sender: TObject);
begin
DeleteCurrentValue;
end;
procedure TMainForm.DeleteCurrentValue;
Var
PN : TTreeNode;
P,D : TJSONData;
begin
D:=CurrentData;
If (CurrentContainerNode=CurrentNode) then
PN:=FindContainerNode(CurrentNode.Parent)
else
PN:=CurrentContainerNode;
If (PN=Nil) then
begin
FreeAndNil(FRoot);
ShowJSONDocument;
end
else
begin
P:=TJSONData(PN.Data);
If P.JSONType=jtArray then
begin
TJSONArray(P).Remove(D);
PN:=PN.Parent;
If PN<>Nil then
PN.DeleteChildren
else
TVJSON.Items.Clear;
ShowJSONData(PN,P);
end
else If P.JSONType=jtObject then
begin
TJSONObject(P).Remove(D);
PN:=PN.Parent;
If PN<>Nil then
PN.DeleteChildren;
ShowJSONData(PN,P);
end;
end;
Modify;
end;
procedure TMainForm.ACopyUpdate(Sender: TObject);
begin
(Sender as Taction).Enabled:=Assigned(CurrentData);
end;
procedure TMainForm.ACutExecute(Sender: TObject);
begin
CopyCurrentData;
DeleteCurrentValue;
end;
procedure TMainForm.ACopyExecute(Sender: TObject);
begin
CopyCurrentData;
end;
procedure TMainForm.CopyCurrentData;
Var
D : TJSONData;
begin
D:=CurrentData;
If Not Assigned(D) then
exit;
ShowMessage(D.AsJSON);
Clipboard.Clear;
ClipBoard.AsText:=D.AsJSON;
end;
procedure TMainForm.ACutUpdate(Sender: TObject);
begin
(Sender as Taction).Enabled:=Assigned(CurrentData);
end;
procedure TMainForm.ANewBooleanValueExecute(Sender: TObject);
begin
AddNewValue(jtBoolean);
end;
procedure TMainForm.ANewNumberValueExecute(Sender: TObject);
begin
AddNewValue(jtNumber);
end;
procedure TMainForm.ANewObjectExecute(Sender: TObject);
begin
AddNewValue(jtObject);
end;
procedure TMainForm.ANewStringValueExecute(Sender: TObject);
begin
AddNewValue(jtString);
end;
procedure TMainForm.APasteAsDocumentExecute(Sender: TObject);
begin
PasteJSON(True);
end;
procedure TMainForm.APasteExecute(Sender: TObject);
begin
PasteJSON(False);
end;
procedure TMainForm.PasteJSON(DoClear : Boolean);
Var
P : TJSONParser;
D : TJSONData;
N : String;
begin
D:=Nil;
try
P:=TJSONParser.Create(Clipboard.AsText);
try
D:=P.Parse;
finally
P.Free;
end;
except
On E : Exception do
ShowMessage(SErrNoValidJSONClipBoard)
end;
N:=SNewMember;
If DoClear then
begin
If FModified then
case QuestionDlg(SDocumentModified,SDocumentModifiedAction,mtWarning,[
mrNo,SDiscard,
mrYes,SSaveData,
mrCancel,SCancelPaste],0) of
mrYes : SaveToFile(GetSaveFileName(FFileName=''));
mrNo : ;
mrCancel : Exit;
end;
FreeAndNil(FRoot);
TVJSON.Items.Clear;
FFileName:='';
N:='';
end
else If CurrentContainerType=jtObject then
if not InputQuery(SNewMember,Format(SNewMemberName,[JSONTypeNames[D.JSONType]]),N) then
begin
D.Free;
Exit;
end;
AddDataToCOntainer(N,D);
end;
procedure TMainForm.APasteUpdate(Sender: TObject);
begin
(Sender as TAction).Enabled:=ClipBoard.HasFormat(Clipboard.FindFormatID('text/plain'));
end;
procedure TMainForm.AddNewValue(AType : TJSONType);
Function NewMemberName : string;
begin
Case CurrentContainerType of
jtUnknown : Result:= '';
jtObject : Result:=SNewMember;
jtArray : Result:=Format(SElement,[TJSONArray(CurrentContainer).Count]);
end;
end;
Var
D : TJSONData;
N : String;
I : Integer;
begin
Case AType of
jtNull,
jtObject,
jtArray :
begin
N:=SNewMember;
If (CurrentContainerType=jtObject) then
if not InputQuery(SNewMember,Format(SNewMemberName,[JSONTypeNames[AType]]),N) then
Exit;
Case AType of
jtNull : D:=TJSONNull.Create;
jtObject : D:=TJSONObject.Create;
jtArray : D:=TJSONArray.Create;
end;
end;
jtBoolean:
begin
With TNewBooleanForm.Create(Self) do
try
MemberName:=NewMemberName;
AllowName:=CurrentContainerType=jtObject;
If (ShowModal<>mrOK) then
Exit;
N:=MemberName;
D:=TJSONBoolean.Create(Value);
finally
Free;
end;
end;
jtString:
begin
With TNewStringForm.Create(Self) do
try
MemberName:=NewMemberName;
AllowName:=CurrentContainerType=jtObject;
If (ShowModal<>mrOK) then
Exit;
N:=MemberName;
D:=TJSONString.Create(Value);
finally
Free;
end;
end;
jtNumber:
begin
With TNewNumberForm.Create(Self) do
try
MemberName:=NewMemberName;
AllowName:=CurrentContainerType=jtObject;
NumberType:=ntInteger;
If (ShowModal<>mrOK) then
Exit;
N:=MemberName;
Case NumberType of
ntInteger : D:=TJSONIntegerNumber.Create(AsInteger);
ntFloat : D:=TJSONFloatNumber.Create(AsFloat);
ntInt64 : D:=TJSONInt64Number.Create(AsInt64);
end;
finally
Free;
end;
end;
end;
AddDataToContainer(N,D);
end;
procedure TMainForm.AddDataToContainer(Const AMemberName : String; D : TJSONData);
Var
P : TTreeNode;
I : Integer;
begin
Case CurrentContainerType of
jtUnknown :
begin
FRoot:=D;
P:=Nil;
end;
jtObject :
begin
TJSONObject(CurrentContainer).Add(AmemberName,D);
P:=TVJSON.Items.AddChild(CurrentContainerNode,AmemberName)
end;
jtArray:
begin
I:=TJSONArray(CurrentContainer).Add(D);
P:=TVJSON.Items.AddChild(CurrentContainerNode,IntToStr(I))
end;
end;
Modify;
If Assigned(P) then
begin
P.ImageIndex:=ImageTypeMap[D.JSONType];
P.SelectedIndex:=ImageTypeMap[D.JSONType];
end;
ShowJSONData(P,D);
end;
function TMainForm.CurrentNode: TTreeNode;
begin
Result:=TVJSON.Selected;
end;
function TMainForm.CurrentNodeType: TJSONType;
Var
D : TJSONData;
begin
D:=CurrentData;
If (D=Nil) then
Result:=jtUnknown
else
Result:=D.JSONType;
end;
Procedure TMainForm.SaveToFile(Const AFileName : string);
Var
S : String;
F : TFileStream;
begin
F:=TFileStream.Create(AFileName,fmCreate);
try
If Assigned(FRoot) then
S:=FRoot.AsJSON;
If length(S)>0 then
F.WriteBuffer(S[1],Length(S));
FModified:=False;
finally
F.Free;
end;
FFileName:=AFileName;
SetCaption;
end;
Function TMainForm.GetSaveFileName(Force : Boolean) : String;
begin
Result:=FFileName;
If Force or (Result='') then
with SDJSON do
begin
FileName:=Result;
If Execute then
Result:=FileName
else
Result:=''
end;
end;
Function TMainForm.CurrentData : TJSONData;
begin
If (CurrentNode=Nil) then
Result:=Nil
else
begin
Result:=TJSONData(CurrentNode.Data);
If (Result=Nil) and (CurrentNode.Count=1) then
Result:=TJSONData(CurrentNode.Items[0].Data);
end;
end;
Function TMainForm.CurrentContainerType : TJSONtype;
Var
D : TJSONData;
begin
D:=CurrentContainer;
If (D=Nil) then
Result:=jtUnknown
else
Result:=D.JSONType;
end;
Function TMainForm.IsContainerNode(ANode : TTreeNode) : Boolean;
begin
Result:=Assigned(ANode)
and Assigned(ANode.Data)
and (TJSONData(ANode.Data).JSONType in [jtArray,jtObject]);
end;
Function TMainForm.FindContainerNode(AStart : TTreeNode) : TTreeNode;
begin
Result:=Astart;
While (Result<>Nil) and Not IsContainerNode(Result) do
Result:=Result.Parent;
end;
Function TMainForm.CurrentContainerNode : TTreeNode;
begin
Result:=FindContainerNode(CurrentNode);
end;
Function TMainForm.CurrentContainer : TJSONData;
Var
N : TTreeNode;
begin
N:=CurrentContainerNode;
If (N<>Nil) then
Result:=TJSONData(N.Data)
else
Result:=Nil
end;
procedure TMainForm.AOpenExecute(Sender: TObject);
begin
With ODJSON do
begin
FileName:=FFileName;
If Execute then
OpenFile(FileName)
end;
end;
procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: boolean);
begin
CanClose:=Not FModified;
If Not CanClose then
case QuestionDlg(SDocumentModified,SDocumentModifiedAction,mtWarning,[
mrNo,SDiscard,
mrYes,SSaveData,
mrCancel,SCancelClose],0) of
mrNo : CanClose:=True;
mrYes :
begin
SaveToFile(GetSaveFileName(FFileName=''));
CanClose:=True;
end;
end;
end;
procedure TMainForm.FormCreate(Sender: TObject);
Var
S : String;
begin
{$IFNDEF HAVESTRICT}
MIStrict.Visible:=False;
{$ENDIF}
S:=GetAppConfigFile(false,true);
PSMain.IniFileName:=S;
S:=ExtractFilePath(S);
If not ForceDirectories(S) then
ShowMessage(Format(SErrCreatingConfigDir,[S]));
PSMain.Active:=True;
end;
procedure TMainForm.FormShow(Sender: TObject);
begin
NewDocument;
end;
procedure TMainForm.HaveData(Sender: TObject);
begin
(Sender as TAction).Enabled:=(FRoot<>Nil);
end;
procedure TMainForm.MIdocumentClick(Sender: TObject);
begin
FNewObject:=(Sender as TMenuItem).Checked;
PSMain.StoredValue['object']:=IntToStr(Ord(FNewObject));
end;
procedure TMainForm.MISortMembersClick(Sender: TObject);
begin
FSortObjectMembers:=(Sender as TMenuItem).Checked;
ShowJSONDocument;
end;
procedure TMainForm.OpenFile(Const AFileName : String);
Var
S : TFileStream;
P : TJSONParser;
D : TJSONData;
begin
S:=TFileStream.Create(AFileName,fmOpenRead);
try
P:=TJSONParser.Create(S);
try
{$IFDEF HAVESTRICT}
P.Strict:=FStrict;
{$ENDIF}
D:=P.Parse;
finally
P.Free;
end;
finally
S.Free;
end;
FFileName:=AFileName;
SetCaption;
FreeAndNil(FRoot);
FRoot:=D;
ShowJSONDocument;
end;
procedure TMainForm.ShowJSONDocument;
begin
With TVJSON.Items do
begin
BeginUpdate;
try
TVJSON.Items.Clear;
SHowJSONData(Nil,FRoot);
With TVJSON do
If (Items.Count>0) and Assigned(Items[0]) then
begin
Items[0].Expand(False);
Selected:=Items[0];
end;
finally
EndUpdate;
end;
end;
end;
procedure TMainForm.ShowJSONData(AParent : TTreeNode; Data : TJSONData);
Var
N,N2 : TTreeNode;
I : Integer;
D : TJSONData;
C : String;
S : TStringList;
begin
N:=Nil;
if Assigned(Data) then
begin
Case Data.JSONType of
jtArray,
jtObject:
begin
If (Data.JSONType=jtArray) then
C:=SArray
else
C:=SObject;
N:=TVJSON.Items.AddChild(AParent,Format(C,[Data.Count]));
S:=TstringList.Create;
try
For I:=0 to Data.Count-1 do
If Data.JSONtype=jtArray then
S.AddObject(IntToStr(I),Data.items[i])
else
S.AddObject(TJSONObject(Data).Names[i],Data.items[i]);
If FSortObjectMembers and (Data.JSONType=jtObject) then
S.Sort;
For I:=0 to S.Count-1 do
begin
N2:=TVJSON.Items.AddChild(N,S[i]);
D:=TJSONData(S.Objects[i]);
N2.ImageIndex:=ImageTypeMap[D.JSONType];
N2.SelectedIndex:=ImageTypeMap[D.JSONType];
ShowJSONData(N2,D);
end
finally
S.Free;
end;
end;
jtNull:
N:=TVJSON.Items.AddChild(AParent,SNull);
else
N:=TVJSON.Items.AddChild(AParent,Data.AsString);
end;
If Assigned(N) then
begin
N.ImageIndex:=ImageTypeMap[Data.JSONType];
N.SelectedIndex:=ImageTypeMap[Data.JSONType];
N.Data:=Data;
end;
end;
end;
end.

View File

@ -0,0 +1,57 @@
object NewBooleanForm: TNewBooleanForm
Left = 423
Height = 124
Top = 305
Width = 375
ActiveControl = Ename
BorderIcons = [biSystemMenu]
BorderStyle = bsDialog
Caption = 'New boolean value'
ClientHeight = 124
ClientWidth = 375
OnCloseQuery = FormCloseQuery
Position = poMainFormCenter
LCLVersion = '0.9.29'
object BPNewBoolean: TButtonPanel
Left = 6
Height = 34
Top = 84
Width = 363
OKButton.Name = 'OKButton'
OKButton.Caption = '&OK'
HelpButton.Name = 'HelpButton'
HelpButton.Caption = '&Help'
HelpButton.Enabled = False
CloseButton.Name = 'CloseButton'
CloseButton.Caption = '&Close'
CloseButton.Enabled = False
CancelButton.Name = 'CancelButton'
CancelButton.Caption = 'Cancel'
TabOrder = 0
ShowButtons = [pbOK, pbCancel]
end
object Label1: TLabel
Left = 17
Height = 15
Top = 12
Width = 83
Caption = '&Member name'
FocusControl = Ename
ParentColor = False
end
object CBValue: TCheckBox
Left = 113
Height = 21
Top = 44
Width = 84
Caption = 'Set to true'
TabOrder = 1
end
object Ename: TEdit
Left = 113
Height = 22
Top = 8
Width = 247
TabOrder = 2
end
end

View File

@ -0,0 +1,100 @@
{ JSON data viewer : collect data for new boolean
Copyright (C) 2010 Michael Van Canneyt michael@freepascal.org
This source is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
A copy of the GNU General Public License is available on the World Wide Web
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
unit frmNewBoolean;
{$mode objfpc}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ButtonPanel,
StdCtrls;
type
{ TNewBooleanForm }
TNewBooleanForm = class(TForm)
BPNewBoolean: TButtonPanel;
CBValue: TCheckBox;
Ename: TEdit;
Label1: TLabel;
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
private
function GetAllowName: Boolean;
function GetMemberName: String;
function GetValue: Boolean;
procedure SetAllowName(const AValue: Boolean);
procedure SetMemberName(const AValue: String);
procedure SetValue(const AValue: Boolean);
{ private declarations }
public
{ public declarations }
Property AllowName: Boolean Read GetAllowName Write SetAllowName;
Property MemberName : String Read GetMemberName Write SetMemberName;
Property Value : Boolean Read GetValue Write SetValue;
end;
var
NewBooleanForm: TNewBooleanForm;
implementation
{$R *.lfm}
{ TNewBooleanForm }
procedure TNewBooleanForm.FormCloseQuery(Sender: TObject; var CanClose: boolean);
begin
CanClose:=(Not AllowName) or (EName.Text<>'');
end;
function TNewBooleanForm.GetAllowName: Boolean;
begin
Result:=EName.ENabled;
end;
function TNewBooleanForm.GetMemberName: String;
begin
Result:=EName.Text;
end;
function TNewBooleanForm.GetValue: Boolean;
begin
Result:=CBValue.Checked;
end;
procedure TNewBooleanForm.SetAllowName(const AValue: Boolean);
begin
Ename.Enabled:=AValue;
end;
procedure TNewBooleanForm.SetMemberName(const AValue: String);
begin
EName.Text:=AValue;
end;
procedure TNewBooleanForm.SetValue(const AValue: Boolean);
begin
CBValue.Checked:=AValue;
end;
end.

View File

@ -0,0 +1,88 @@
object NewNumberForm: TNewNumberForm
Left = 436
Height = 240
Top = 247
Width = 320
ActiveControl = EName
BorderIcons = [biSystemMenu]
BorderStyle = bsDialog
Caption = 'New number value'
ClientHeight = 240
ClientWidth = 320
OnCloseQuery = FormCloseQuery
Position = poMainFormCenter
LCLVersion = '0.9.29'
object BPNewNumber: TButtonPanel
Left = 6
Height = 34
Top = 200
Width = 308
OKButton.Name = 'OKButton'
OKButton.Caption = '&OK'
HelpButton.Name = 'HelpButton'
HelpButton.Caption = '&Help'
HelpButton.Enabled = False
CloseButton.Name = 'CloseButton'
CloseButton.Caption = '&Close'
CloseButton.Enabled = False
CancelButton.Name = 'CancelButton'
CancelButton.Caption = 'Cancel'
TabOrder = 0
ShowButtons = [pbOK, pbCancel]
end
object EName: TEdit
Left = 87
Height = 22
Top = 10
Width = 185
TabOrder = 1
end
object RGType: TRadioGroup
Left = 83
Height = 105
Top = 44
Width = 185
AutoFill = True
Caption = 'Number Type'
ChildSizing.LeftRightSpacing = 6
ChildSizing.TopBottomSpacing = 6
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 89
ClientWidth = 181
Items.Strings = (
'Float'
'Integer'
'Int64'
)
TabOrder = 2
end
object EValue: TEdit
Left = 84
Height = 22
Top = 161
Width = 164
TabOrder = 3
end
object Label1: TLabel
Left = 22
Height = 15
Top = 14
Width = 34
Caption = '&Name'
FocusControl = EName
ParentColor = False
end
object Label2: TLabel
Left = 12
Height = 15
Top = 159
Width = 31
Caption = 'Value'
ParentColor = False
end
end

View File

@ -0,0 +1,135 @@
{ JSON data viewer : collect data for new integer
Copyright (C) 2010 Michael Van Canneyt michael@freepascal.org
This source is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
A copy of the GNU General Public License is available on the World Wide Web
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
unit frmnewinteger;
{$mode objfpc}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ButtonPanel,
StdCtrls, ExtCtrls, fpjson;
type
{ TNewNumberForm }
TNewNumberForm = class(TForm)
BPNewNumber: TButtonPanel;
EName: TEdit;
EValue: TEdit;
Label1: TLabel;
Label2: TLabel;
RGType: TRadioGroup;
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
private
function GetAllowName: Boolean;
function GetAsFloat: Double;
function GetAsInt64: Integer;
function GetAsInteger: Integer;
function GetMemberName: String;
function GetNumberType: TJSONNumberType;
procedure SetAllowName(const AValue: Boolean);
procedure SetMemberName(const AValue: String);
procedure SetNumberType(const AValue: TJSONNumberType);
{ private declarations }
public
{ public declarations }
Property AllowName: Boolean Read GetAllowName Write SetAllowName;
Property MemberName : String Read GetMemberName Write SetMemberName;
Property NumberType : TJSONNumberType Read GetNumberType Write SetNumberType;
Property AsInteger : Integer Read GetAsInteger;
Property AsInt64 : Integer Read GetAsInt64;
Property AsFLoat : Double Read GetAsFloat;
end;
var
NewNumberForm: TNewNumberForm;
implementation
{$R *.lfm}
{ TNewNumberForm }
procedure TNewNumberForm.FormCloseQuery(Sender: TObject; var CanClose: boolean);
begin
CanClose:=(ModalResult<>mrOK);
If not CanClose then
try
Case NumberType of
ntFloat : GetAsFloat;
ntInteger : GetAsInteger;
ntInt64 : GetAsInt64;
end;
CanClose:=(Not AllowName) or (EName.Text<>'');
except
on E : Exception do
ShowMessage(E.Message)
end;
end;
function TNewNumberForm.GetAllowName: Boolean;
begin
Result:=EName.Enabled;
end;
function TNewNumberForm.GetAsFloat: Double;
begin
Result:=StrToFloat(EValue.Text);
end;
function TNewNumberForm.GetAsInt64: Integer;
begin
Result:=StrToInt64(EValue.Text);
end;
function TNewNumberForm.GetAsInteger: Integer;
begin
Result:=StrToInt(EValue.Text);
end;
function TNewNumberForm.GetMemberName: String;
begin
Result:=EName.Text;
end;
function TNewNumberForm.GetNumberType: TJSONNumberType;
begin
Result:=TJSONNumberType(RGType.ItemIndex);
end;
procedure TNewNumberForm.SetAllowName(const AValue: Boolean);
begin
EName.Enabled:=AValue;
end;
procedure TNewNumberForm.SetMemberName(const AValue: String);
begin
EName.Text:=AValue;
end;
procedure TNewNumberForm.SetNumberType(const AValue: TJSONNumberType);
begin
RGType.ItemIndex:=Ord(Avalue);
end;
end.

View File

@ -0,0 +1,71 @@
object NewStringForm: TNewStringForm
Left = 509
Height = 144
Top = 290
Width = 320
ActiveControl = EName
BorderIcons = [biSystemMenu]
BorderStyle = bsDialog
Caption = 'New String value'
ClientHeight = 144
ClientWidth = 320
OnCloseQuery = FormCloseQuery
Position = poMainFormCenter
LCLVersion = '0.9.29'
object EName: TEdit
Left = 80
Height = 22
Top = 18
Width = 216
TabOrder = 0
end
object EValue: TEdit
Left = 80
Height = 22
Top = 49
Width = 216
TabOrder = 1
end
object Label1: TLabel
Left = 34
Height = 22
Top = 18
Width = 34
Alignment = taRightJustify
AutoSize = False
Caption = '&Name'
FocusControl = EName
Layout = tlCenter
ParentColor = False
end
object Label2: TLabel
Left = 37
Height = 22
Top = 49
Width = 31
Alignment = taRightJustify
AutoSize = False
Caption = '&Value'
FocusControl = EValue
Layout = tlCenter
ParentColor = False
end
object BPNewString: TButtonPanel
Left = 6
Height = 34
Top = 104
Width = 308
OKButton.Name = 'OKButton'
OKButton.Caption = '&OK'
HelpButton.Name = 'HelpButton'
HelpButton.Caption = '&Help'
HelpButton.Enabled = False
CloseButton.Name = 'CloseButton'
CloseButton.Caption = '&Close'
CloseButton.Enabled = False
CancelButton.Name = 'CancelButton'
CancelButton.Caption = 'Cancel'
TabOrder = 2
ShowButtons = [pbOK, pbCancel]
end
end

View File

@ -0,0 +1,101 @@
{ JSON data viewer : collect data for new string
Copyright (C) 2010 Michael Van Canneyt michael@freepascal.org
This source is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
A copy of the GNU General Public License is available on the World Wide Web
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
unit frmnewstring;
{$mode objfpc}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
ButtonPanel;
type
{ TNewStringForm }
TNewStringForm = class(TForm)
BPNewString: TButtonPanel;
EName: TEdit;
EValue: TEdit;
Label1: TLabel;
Label2: TLabel;
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
private
function GetAllowName: Boolean;
function GetMemberName: String;
function GetValue: String;
procedure SetAllowName(const AValue: Boolean);
procedure SetMemberName(const AValue: String);
procedure SetValue(const AValue: String);
{ private declarations }
public
{ public declarations }
Property AllowName: Boolean Read GetAllowName Write SetAllowName;
Property MemberName : String Read GetMemberName Write SetMemberName;
Property Value : String Read GetValue Write SetValue;
end;
var
NewStringForm: TNewStringForm;
implementation
{$R *.lfm}
{ TNewStringForm }
procedure TNewStringForm.FormCloseQuery(Sender: TObject; var CanClose: boolean);
begin
CanClose:=(Not AllowName) or (EName.Text<>'');
end;
function TNewStringForm.GetAllowName: Boolean;
begin
Result:=EName.Enabled;
end;
function TNewStringForm.GetMemberName: String;
begin
Result:=EName.Text;
end;
function TNewStringForm.GetValue: String;
begin
Result:=EValue.Text;
end;
procedure TNewStringForm.SetAllowName(const AValue: Boolean);
begin
EName.Enabled:=AValue;
end;
procedure TNewStringForm.SetMemberName(const AValue: String);
begin
EName.Text:=Avalue;
end;
procedure TNewStringForm.SetValue(const AValue: String);
begin
EValue.Text:=Avalue;
end;
end.

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

View File

@ -0,0 +1,115 @@
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
<Version Value="8"/>
<General>
<Flags>
<SaveOnlyProjectUnits Value="True"/>
<UseDefaultCompilerOptions Value="True"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<TargetFileExt Value=""/>
<Title Value="JSON Data viewer"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
<Icon Value="0"/>
</General>
<i18n>
<EnableI18N Value="True"/>
<OutDir Value="languages"/>
</i18n>
<VersionInfo>
<Language Value=""/>
<CharSet Value=""/>
<StringTable Comments="" CompanyName="" FileDescription="" FileVersion="" InternalName="" LegalCopyright="" LegalTrademarks="" OriginalFilename="" ProductName="" ProductVersion=""/>
</VersionInfo>
<PublishOptions>
<Version Value="2"/>
<IgnoreBinaries Value="False"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
<LaunchingApplication PathPlusParams="/usr/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
</local>
</RunParams>
<RequiredPackages Count="1">
<Item1>
<PackageName Value="LCL"/>
</Item1>
</RequiredPackages>
<Units Count="6">
<Unit0>
<Filename Value="jsonviewer.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="jsonviewer"/>
</Unit0>
<Unit1>
<Filename Value="frmmain.pp"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="MainForm"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="frmmain"/>
</Unit1>
<Unit2>
<Filename Value="frmnewboolean.pp"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="NewBooleanForm"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="frmNewBoolean"/>
</Unit2>
<Unit3>
<Filename Value="frmnewinteger.pp"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="NewNumberForm"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="frmnewinteger"/>
</Unit3>
<Unit4>
<Filename Value="frmnewstring.pp"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="NewStringForm"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="frmnewstring"/>
</Unit4>
<Unit5>
<Filename Value="msgjsonviewer.pp"/>
<IsPartOfProject Value="True"/>
<UnitName Value="msgjsonviewer"/>
</Unit5>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="9"/>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)/"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<UseAnsiStrings Value="False"/>
</SyntaxOptions>
</Parsing>
<Other>
<CompilerMessages>
<UseMsgFile Value="True"/>
</CompilerMessages>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,24 @@
program jsonviewer;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, frmmain, frmNewBoolean, frmnewinteger, frmnewstring, msgjsonviewer
{ you can add units after this };
{$R *.res}
begin
Application.Title:='JSON Data viewer';
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TNewBooleanForm, NewBooleanForm);
Application.CreateForm(TNewNumberForm, NewNumberForm);
Application.CreateForm(TNewStringForm, NewStringForm);
Application.Run;
end.

Binary file not shown.

View File

@ -0,0 +1,77 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
#: msgjsonviewer.sarray
msgid "Array (%d elements)"
msgstr ""
#: msgjsonviewer.scancelclose
msgid "Do not close the window"
msgstr ""
#: msgjsonviewer.scancelpaste
msgid "Do not paste the new data"
msgstr ""
#: msgjsonviewer.scaption
msgid "JSON Viewer"
msgstr ""
#: msgjsonviewer.sdiscard
msgid "Discard changes"
msgstr ""
#: msgjsonviewer.sdocumentmodified
msgid "JSON document modified"
msgstr ""
#: msgjsonviewer.sdocumentmodifiedaction
msgid ""
"The JSON data was changed but not saved.\n"
"What do want to do ?\n"
msgstr ""
#: msgjsonviewer.sduplicatemembername
msgid "Duplicate member name \"%s\"."
msgstr ""
#: msgjsonviewer.selement
msgid "Element nr. %d"
msgstr ""
#: msgjsonviewer.sempty
msgid "Empty document"
msgstr ""
#: msgjsonviewer.serrcreatingconfigdir
msgid "Could not create the configuration files directory \"s\""
msgstr ""
#: msgjsonviewer.serrinvalidvalue
msgid "Invalid value or wrong type: \"%s\""
msgstr ""
#: msgjsonviewer.serrnovalidjsonclipboard
msgid "The clipboard does not contain valid JSON data"
msgstr ""
#: msgjsonviewer.snewmember
msgid "New object member"
msgstr ""
#: msgjsonviewer.snewmembername
msgid "Enter a name for the new member (type: %s)"
msgstr ""
#: msgjsonviewer.snull
msgid "null"
msgstr ""
#: msgjsonviewer.sobject
msgid "Object (%d members)"
msgstr ""
#: msgjsonviewer.ssavedata
msgid "Save the changes"
msgstr ""

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,37 @@
unit msgjsonviewer;
{$mode objfpc}
interface
uses
Classes, SysUtils;
Resourcestring
SCaption = 'JSON Viewer';
SEmpty = 'Empty document';
SArray = 'Array (%d elements)';
SObject = 'Object (%d members)';
SNull = 'null';
SNewMember = 'New object member';
SNewMemberName = 'Enter a name for the new member (type: %s)';
SElement = 'Element nr. %d';
SDocumentModified = 'JSON document modified';
SDocumentModifiedAction = 'The JSON data was changed but not saved.'+slinebreak+
'What do want to do ?';
SDuplicateMemberName = 'Duplicate member name "%s".';
SErrinvalidValue = 'Invalid value or wrong type: "%s"';
SErrNoValidJSONClipBoard = 'The clipboard does not contain valid JSON data';
SErrCreatingConfigDir = 'Could not create the configuration files directory "s"';
SDiscard = 'Discard changes';
SSaveData = 'Save the changes';
SCancelClose = 'Do not close the window';
SCancelPaste = 'Do not paste the new data';
implementation
end.