diff --git a/tools/jsonviewer/README.txt b/tools/jsonviewer/README.txt index 228957b11f..68904cb923 100644 --- a/tools/jsonviewer/README.txt +++ b/tools/jsonviewer/README.txt @@ -24,5 +24,3 @@ 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. \ No newline at end of file diff --git a/tools/jsonviewer/frmmain.lfm b/tools/jsonviewer/frmmain.lfm index 68af73c3f0..1cad195d30 100644 --- a/tools/jsonviewer/frmmain.lfm +++ b/tools/jsonviewer/frmmain.lfm @@ -134,10 +134,12 @@ object MainForm: TMainForm Width = 695 Align = alClient DefaultItemHeight = 16 + HideSelection = False Images = ILJSON TabOrder = 1 OnEdited = TVJSONEdited OnEditing = TVJSONEditing + Options = [tvoAutoItemHeight, tvoKeepCollapsedNodes, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] end object ActionList1: TActionList Images = ILJSON @@ -288,6 +290,21 @@ object MainForm: TMainForm OnUpdate = AExpandCurrentContainerUpdate ShortCut = 16453 end + object AFind: TAction + Category = 'Edit' + Caption = '&Find' + ImageIndex = 15 + OnExecute = AFindExecute + OnUpdate = HaveData + ShortCut = 16454 + end + object AFindNext: TAction + Category = 'Edit' + Caption = 'Find &next occurrence' + OnExecute = AFindNextExecute + OnUpdate = AFindNextUpdate + ShortCut = 114 + end end object MMJSON: TMainMenu Images = ILJSON @@ -617,6 +634,12 @@ object MainForm: TMainForm object MIPasteAsDocument: TMenuItem Action = APasteAsDocument end + object MenuItem3: TMenuItem + Caption = '-' + end + object MIFInd: TMenuItem + Action = AFind + end object MenuItem2: TMenuItem Caption = '-' end @@ -929,7 +952,7 @@ object MainForm: TMainForm left = 112 top = 61 Bitmap = { - 4C690F0000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + 4C69100000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF006D9CD4896A9AD2FB6697CFEEFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00709ED6DB6D9C @@ -1409,7 +1432,39 @@ object MainForm: TMainForm A1FFC0C0C0FF909090FF909090FF868686FF6E6E6EFF7A7A7AFF49392DFF5C4F 3EFF8F8780FF40311AFF000000FF0000000000000083000000FF000000D30000 00DC000000FF000000FF000000FF000000FF000000FF000000FF000000E00000 - 00E1000000FF000000FF00000047 + 00E1000000FF000000FF00000047FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009C8F + 83E2BCB0A4FF9D9185FFFFFFFF00AEA093FF9D9185FF655D55DAFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008E83 + 78E2C3B8AEFF655D55FFFFFFFF007C7268FFA89B8EFF9C8F83E4FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00746B62FFA4978AFF9589 + 7DFF9F9286FF3E3934FFFFFFFF004C4640FF7E746AFF857A70FF3E3934FF453F + 3AA72522200C15131102FFFFFF00B9ACA008877D72489B8E82FF9D9185FF867B + 71FF564F48FF504A44FF80766CFF6E665DFF826C58FFA6917DFF948474FF564F + 48FF0C0B0B7A07070601FFFFFF00AB9D9004AFA194E1BAAEA2FF82776DFF8277 + 6DFFAA917BFFBAA794FFB7A48EFAB09781FF9F8D7DFF836D5BFF716357FF9589 + 7DFF040403E000000003FFFFFF009F9286059D9185FFB1A396FF7F756BFF7C72 + 68FF776D64FF6C635BFF2E2A26FF564F48FF80766CFF7C7268FF776D64FF7067 + 5EFF000000FE00000005FFFFFF00797066055C554EF9423D38FF58514AFF3D38 + 33FF332F2BFF23201DE5171614301E1C19B51A1816FF252220FF191715FF0F0E + 0DFF010101EE00000002FFFFFF00FFFFFF005A524CC39F9286FFCCC3BAFFC0B4 + AAFFA6988BFF3E3934A8FFFFFF002C2925A8908479FFC2B8ADFFC0B4AAFFA89B + 8EFF110F0EC3FFFFFF00FFFFFF00FFFFFF00534C46FC83786FFFCCC3BAFF7970 + 66FF71685FFF37332ED5FFFFFF00252220D5857A70FFC2B8ADFF786F65FF7B71 + 67FF0A0908FCFFFFFF00FFFFFF00FFFFFF004D4741FF83786FFFCCC3BAFF786F + 65FF7B7167FF2F2B28F9272421011D1B18EE95897DFFC2B8ADFF786F65FF7C72 + 68FF060505FFFFFFFF00FFFFFF00FFFFFF0046413BFF857A70FFC3B8AEFF7C72 + 68FF7F756BFF36322DFF1E1C190F282522D495897DFFBAAEA2FF7C7268FF7F75 + 6BFF010101FFFFFFFF00FFFFFF00FFFFFF003E3934FF393430FF332F2BFF2C29 + 25FF272421FF201D1BFF1716141A110F0EDB0B0A09FF070706FF040403FF0000 + 00FF000000FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00 } end object ODJSON: TOpenDialog @@ -1450,4 +1505,10 @@ object MainForm: TMainForm left = 196 top = 96 end + object FDJSON: TFindDialog + Options = [frDown, frHideUpDown, frDisableUpDown] + OnFind = FDJSONFind + left = 264 + top = 109 + end end diff --git a/tools/jsonviewer/frmmain.pp b/tools/jsonviewer/frmmain.pp index 2200e8b497..92645ddb3a 100644 --- a/tools/jsonviewer/frmmain.pp +++ b/tools/jsonviewer/frmmain.pp @@ -38,6 +38,8 @@ type TMainForm = class(TForm) ACopy: TAction; + AFindNext: TAction; + AFind: TAction; AExpandCurrentContainer: TAction; AExpandAll: TAction; APasteAsDocument: TAction; @@ -56,9 +58,12 @@ type AOpen: TAction; ANew: TAction; ActionList1: TActionList; + FDJSON: TFindDialog; ILJSON: TImageList; MEDit: TMenuItem; MenuItem2: TMenuItem; + MenuItem3: TMenuItem; + MIFInd: TMenuItem; MIExpandCurrent: TMenuItem; MIExpandAll: TMenuItem; MIPasteAsDocument: TMenuItem; @@ -113,6 +118,9 @@ type procedure AExpandAllUpdate(Sender: TObject); procedure AExpandCurrentContainerExecute(Sender: TObject); procedure AExpandCurrentContainerUpdate(Sender: TObject); + procedure AFindExecute(Sender: TObject); + procedure AFindNextExecute(Sender: TObject); + procedure AFindNextUpdate(Sender: TObject); procedure ANewArrayExecute(Sender: TObject); procedure ANewBooleanValueExecute(Sender: TObject); procedure ANewNullValueExecute(Sender: TObject); @@ -127,6 +135,7 @@ type procedure ContainerAvailable(Sender: TObject); procedure ANewExecute(Sender: TObject); procedure AOpenExecute(Sender: TObject); + procedure FDJSONFind(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); procedure FormCreate(Sender: TObject); procedure FormShow(Sender: TObject); @@ -153,9 +162,13 @@ type FStrict, FNewObject, FModified : Boolean; + FCurrentFind : TTreeNode; procedure AddDataToContainer(const AMemberName: String; D: TJSONData); procedure CopyCurrentData; procedure DeleteCurrentValue; + function FindNode(Start: TTreeNode; const AText: String; + CaseInsensitive: Boolean; WholeWord: Boolean): TTreeNode; + function GetNextSearchNode(Anode: TTreeNode): TTreeNode; procedure Modify; procedure AddNewValue(AType: TJSONType); function CurrentNode: TTreeNode; @@ -387,6 +400,22 @@ begin (Sender as TACtion).Enabled:=(CurrentContainerType<>jtUnknown) end; +procedure TMainForm.AFindExecute(Sender: TObject); +begin + With FDJSON do + Execute; +end; + +procedure TMainForm.AFindNextExecute(Sender: TObject); +begin + FDJSONFind(Sender); +end; + +procedure TMainForm.AFindNextUpdate(Sender: TObject); +begin + (Sender as TAction).ENabled:=(FCurrentFind<>Nil) +end; + procedure TMainForm.ADeleteValueExecute(Sender: TObject); begin @@ -794,6 +823,82 @@ begin end; end; +procedure TMainForm.FDJSONFind(Sender: TObject); + +Var + N : TTreeNode; + +begin + If (FCurrentFind=Nil) then + begin + If (frEntireScope in FDJSON.Options) and (TVJSON.Items.Count>0) then + FCurrentFind:=TVJSON.Items[0] + else + FCurrentFind:=TVJSON.Selected; + end + else + FCurrentFind:=GetNextSearchNode(FCurrentFind); + If (FCurrentFind=Nil) then + Exit; + With FDJSON do + N:=FindNode(FCurrentFind,FindText,Not (frMatchCase in Options), frWholeWord in Options); + If Assigned(N) then + begin + N.MakeVisible; + TVJSON.Selected:=N; + end + else + ShowMessage(SNoMoreMatches); + FCurrentFind:=N; +end; + +Function TMainForm.GetNextSearchNode(Anode : TTreeNode) : TTreeNode; + +begin + Result:=Nil; + If (ANode=Nil) then Exit; + If (ANode.Count>0) then + Result:=ANode.GetFirstChild + else + Result:=ANode.GetNextSibling; + While (Result=Nil) and (ANode<>Nil) do + begin + ANode:=ANode.Parent; + Result:=ANode.GetNextSibling; + end; +end; + +Function TMainForm.FindNode(Start : TTreeNode; Const AText: String; CaseInsensitive : Boolean; WholeWord : Boolean) : TTreeNode; + + Function Match(Const ST : String; ANode : TTreeNode) : boolean; + + Var + NT : String; + + begin + If CaseInsensitive then + NT:=Uppercase(ANode.Text) + else + NT:=ANode.Text; + If WholeWord then + Result:=(NT=ST) + else + Result:=(Pos(ST,NT)>0); + end; + +Var + ST : String; + +begin + If CaseInsensitive then + ST:=UpperCase(AText) + else + ST:=AText; + Result:=Start; + While (Result<>Nil) and not Match(ST,Result) do + Result:=GetNextSearchNode(Result); +end; + procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: boolean); begin CanClose:=Not FModified; diff --git a/tools/jsonviewer/languages/jsonviewer.po b/tools/jsonviewer/languages/jsonviewer.po index f39020bab6..21178bbb24 100644 --- a/tools/jsonviewer/languages/jsonviewer.po +++ b/tools/jsonviewer/languages/jsonviewer.po @@ -14,6 +14,7 @@ msgid "Do not paste the new data" msgstr "" #: msgjsonviewer.scaption +msgctxt "msgjsonviewer.scaption" msgid "JSON Viewer" msgstr "" @@ -63,6 +64,10 @@ msgstr "" msgid "Enter a name for the new member (type: %s)" msgstr "" +#: msgjsonviewer.snomorematches +msgid "No nodes match the criterium" +msgstr "" + #: msgjsonviewer.snull msgid "null" msgstr "" @@ -75,3 +80,220 @@ msgstr "" msgid "Save the changes" msgstr "" +#: TMAINFORM.ACOPY.CAPTION +msgid "&Copy" +msgstr "" + +#: TMAINFORM.ACOPY.HINT +msgid "Copy selected node to clipboard as JSON" +msgstr "" + +#: TMAINFORM.ACUT.CAPTION +msgid "C&ut" +msgstr "" + +#: TMAINFORM.ACUT.HINT +msgid "Cut selected node to clipboard as JSON" +msgstr "" + +#: TMAINFORM.ADELETEVALUE.CAPTION +msgid "&Delete value" +msgstr "" + +#: TMAINFORM.ADELETEVALUE.HINT +msgid "Delete the selected value" +msgstr "" + +#: TMAINFORM.AEXPANDALL.CAPTION +msgid "E&xpand all nodes" +msgstr "" + +#: TMAINFORM.AEXPANDALL.HINT +msgid "Expand all nodes in the document" +msgstr "" + +#: TMAINFORM.AEXPANDCURRENTCONTAINER.CAPTION +msgid "Expand ¤t object/array" +msgstr "" + +#: TMAINFORM.AEXPANDCURRENTCONTAINER.HINT +msgid "Expand all nodes in the current object/array" +msgstr "" + +#: TMAINFORM.AFIND.CAPTION +msgid "&Find" +msgstr "" + +#: TMAINFORM.AFINDNEXT.CAPTION +msgid "Find &next occurrence" +msgstr "" + +#: TMAINFORM.ANEW.CAPTION +msgid "&New" +msgstr "" + +#: TMAINFORM.ANEW.HINT +msgid "Create new JSON document" +msgstr "" + +#: TMAINFORM.ANEWARRAY.CAPTION +msgid "New &Array" +msgstr "" + +#: TMAINFORM.ANEWARRAY.HINT +msgid "Add a new JSON array" +msgstr "" + +#: TMAINFORM.ANEWBOOLEANVALUE.CAPTION +msgid "New &boolean value" +msgstr "" + +#: TMAINFORM.ANEWBOOLEANVALUE.HINT +msgid "Add a new boolean value" +msgstr "" + +#: TMAINFORM.ANEWNULLVALUE.CAPTION +msgid "New N&ull value" +msgstr "" + +#: TMAINFORM.ANEWNULLVALUE.HINT +msgid "Add a new null value" +msgstr "" + +#: TMAINFORM.ANEWNUMBERVALUE.CAPTION +msgid "&New numerical Value" +msgstr "" + +#: TMAINFORM.ANEWNUMBERVALUE.HINT +msgid "Add a new number value" +msgstr "" + +#: TMAINFORM.ANEWOBJECT.CAPTION +msgid "New &Object" +msgstr "" + +#: TMAINFORM.ANEWOBJECT.HINT +msgid "Add a new JSON object" +msgstr "" + +#: TMAINFORM.ANEWSTRINGVALUE.CAPTION +msgid "New &string value" +msgstr "" + +#: TMAINFORM.ANEWSTRINGVALUE.HINT +msgid "Add a new string value" +msgstr "" + +#: TMAINFORM.AOPEN.CAPTION +msgid "&Open" +msgstr "" + +#: TMAINFORM.AOPEN.HINT +msgid "Open JSON document from file" +msgstr "" + +#: TMAINFORM.APASTE.CAPTION +msgid "&Paste" +msgstr "" + +#: TMAINFORM.APASTE.HINT +msgid "Paste JSON data in clipboard as new member" +msgstr "" + +#: TMAINFORM.APASTEASDOCUMENT.CAPTION +msgid "Paste as new document" +msgstr "" + +#: TMAINFORM.APASTEASDOCUMENT.HINT +msgid "Paste JSON data in clipboard as new document" +msgstr "" + +#: TMAINFORM.AQUIT.CAPTION +msgid "&Quit" +msgstr "" + +#: TMAINFORM.AQUIT.HINT +msgid "Exit the program" +msgstr "" + +#: TMAINFORM.ASAVE.CAPTION +msgid "&Save" +msgstr "" + +#: TMAINFORM.ASAVE.HINT +msgid "Save the JSON document to file" +msgstr "" + +#: TMAINFORM.ASAVEAS.CAPTION +msgid "Save &as" +msgstr "" + +#: TMAINFORM.ASAVEAS.HINT +msgid "Save JSON document with a new name" +msgstr "" + +#: TMAINFORM.MAINFORM.CAPTION +msgctxt "TMAINFORM.MAINFORM.CAPTION" +msgid "JSON Viewer" +msgstr "" + +#: TMAINFORM.MEDIT.CAPTION +msgid "&Edit" +msgstr "" + +#: TMAINFORM.MENUITEM1.CAPTION +msgctxt "TMAINFORM.MENUITEM1.CAPTION" +msgid "-" +msgstr "" + +#: TMAINFORM.MENUITEM2.CAPTION +msgctxt "TMAINFORM.MENUITEM2.CAPTION" +msgid "-" +msgstr "" + +#: TMAINFORM.MENUITEM3.CAPTION +msgctxt "TMAINFORM.MENUITEM3.CAPTION" +msgid "-" +msgstr "" + +#: TMAINFORM.MENUITEM8.CAPTION +msgctxt "TMAINFORM.MENUITEM8.CAPTION" +msgid "-" +msgstr "" + +#: TMAINFORM.MFILE.CAPTION +msgid "&File" +msgstr "" + +#: TMAINFORM.MIDOCUMENT.CAPTION +msgid "&New document with object" +msgstr "" + +#: TMAINFORM.MIINSERT.CAPTION +msgid "&Values" +msgstr "" + +#: TMAINFORM.MISORTMEMBERS.CAPTION +msgid "Sort object members" +msgstr "" + +#: TMAINFORM.MISTRICT.CAPTION +msgid "&Strict JSON" +msgstr "" + +#: TMAINFORM.MOPTIONS.CAPTION +msgid "&Options" +msgstr "" + +#: TMAINFORM.TBJSON.CAPTION +msgid "TBJSON" +msgstr "" + +#: TMAINFORM.TOOLBUTTON1.CAPTION +msgid "ToolButton1" +msgstr "" + +#: TMAINFORM.TOOLBUTTON4.CAPTION +msgid "ToolButton4" +msgstr "" + diff --git a/tools/jsonviewer/msgjsonviewer.pp b/tools/jsonviewer/msgjsonviewer.pp index 94daf7800b..1b592e00f6 100644 --- a/tools/jsonviewer/msgjsonviewer.pp +++ b/tools/jsonviewer/msgjsonviewer.pp @@ -25,6 +25,7 @@ Resourcestring 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"'; + SNoMoreMatches = 'No nodes match the criterium'; SDiscard = 'Discard changes'; SSaveData = 'Save the changes';