inieditor.pas 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. unit inieditor;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, FileUtil, Forms, Controls,
  6. Graphics, Dialogs, StdCtrls, EditBtn, ExtCtrls,
  7. IniFiles, lazutf8, SynEdit,SynMemo,{SynEditTypes,}SynHighlighterIni, SynEditTypes;
  8. type
  9. { TFormIniEditor }
  10. TFormIniEditor = class(TForm)
  11. GUITimer: TIdleTimer;
  12. Label1: TLabel;
  13. OKButton: TButton;
  14. CancelButton: TButton;
  15. ProfileSelect: TComboBox;
  16. FileNameEdit: TFileNameEdit;
  17. INIFileLabel: TLabel;
  18. ProfileLabel: TLabel;
  19. SynIniHighlighter: TSynIniSyn;
  20. SynMemo: TSynMemo;
  21. procedure CancelButtonClick(Sender: TObject);
  22. procedure FileNameEditAcceptFileName(Sender: TObject; var Value: String);
  23. procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
  24. procedure FormCreate(Sender: TObject);
  25. procedure FormDestroy(Sender: TObject);
  26. procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
  27. procedure FormShow(Sender: TObject);
  28. procedure GUITimerTimer(Sender: TObject);
  29. procedure ProfileSelectSelect(Sender: TObject);
  30. procedure SynMemoStatusChange(Sender: TObject; Changes: TSynStatusChanges);
  31. private
  32. FIniFilename: string;
  33. FIniStream: TMemoryStream;
  34. FMustReloadProfileSelect: boolean;
  35. FSaveChanges: boolean; //If off, don't save any changes (e.g. when canceling form)
  36. FProfileSelectKey: string;
  37. FProfileSelectSection: string;
  38. FProfileSelectValue: string;
  39. procedure LoadGUI(KeepCursorPosition: boolean; LoadSynmemo: boolean; LoadProfileselect: boolean); //Loads GUI elements from backing stream
  40. procedure SetIniFilename(AValue: string); //Loads file into stream
  41. procedure SetProfileSelectKey(AValue: string);
  42. procedure SetProfileSelectSection(AValue: string);
  43. // Saves synmemo contents to memory stream and optionally to file, too
  44. procedure SynMemoSave(AlsoToFile: boolean);
  45. { private declarations }
  46. public
  47. // File to be edited/viewed:
  48. property INIFile: string read FIniFilename write SetIniFilename;
  49. // Section name where profile selection is to be stored. If nothing, the root/top level will be used
  50. property ProfileSelectSection: string read FProfileSelectSection write SetProfileSelectSection;
  51. // Key to be used for storing selected profile
  52. // If empty, don't use the select profile combobox
  53. property ProfileSelectKey: string read FProfileSelectKey write SetProfileSelectKey;
  54. // The value the user selected
  55. property ProfileSelectValue: string read FProfileSelectValue;
  56. end;
  57. var
  58. Form1: TFormIniEditor;
  59. implementation
  60. {$R *.lfm}
  61. { TFormIniEditor }
  62. procedure TFormIniEditor.FormDropFiles(Sender: TObject;
  63. const FileNames: array of String);
  64. begin
  65. // Go through property for reload file+reload GUI code
  66. IniFile:=FileNames[0];
  67. end;
  68. procedure TFormIniEditor.FormShow(Sender: TObject);
  69. begin
  70. if FileNameEdit.FileName='' then
  71. FileNameEdit.FileName:=FIniFilename;
  72. end;
  73. procedure TFormIniEditor.GUITimerTimer(Sender: TObject);
  74. begin
  75. if FMustReloadProfileSelect then
  76. LoadGUI(true,false,true);
  77. end;
  78. procedure TFormIniEditor.ProfileSelectSelect(Sender: TObject);
  79. // Save selected profile
  80. var
  81. MyIniFile: TIniFile;
  82. begin
  83. FProfileSelectValue:=ProfileSelect.Text;
  84. if FProfileSelectValue<>'' then
  85. begin
  86. // Save any changes in synmemo
  87. SynMemoSave(false);
  88. FIniStream.Position:=0; //Load from beginning
  89. MyIniFile := TIniFile.Create(FIniStream, True);
  90. FIniStream.Position:=0; //Needed to save again
  91. try
  92. MyIniFile.WriteString(FProfileSelectSection,FProfileSelectKey,FProfileSelectValue);
  93. finally
  94. MyIniFile.Free;
  95. end;
  96. LoadGUI(true,true,true);
  97. end;
  98. end;
  99. procedure TFormIniEditor.SynMemoStatusChange(Sender: TObject;
  100. Changes: TSynStatusChanges);
  101. begin
  102. // If user edits the profile name directly or edits/deletes/adds
  103. // one of the section names, the combobox will need to be refreshed.
  104. // Pass this on to a timer so it gets done without disturbing the updates
  105. if (FMustReloadProfileSelect=false) and (scModified in Changes) then
  106. begin
  107. //todo: test for section line or key=value
  108. FMustReloadProfileSelect:=true;
  109. end;
  110. end;
  111. procedure TFormIniEditor.LoadGUI(KeepCursorPosition: boolean; LoadSynmemo: boolean; LoadProfileselect: boolean);
  112. var
  113. MyIniFile : TIniFile;
  114. OldPos: TPoint;
  115. ProfIndex: integer;
  116. Sections: TStringList;
  117. begin
  118. SynMemo.BeginUpdate(false);
  119. if LoadSynMemo then
  120. begin
  121. OldPos:=SynMemo.CaretXY;
  122. FIniStream.Position:=0; //Load from beginning
  123. SynMemo.Lines.LoadFromStream(FIniStream);
  124. end;
  125. FIniStream.Position:=0; //Load from beginning
  126. MyIniFile := TIniFile.Create(FIniStream, True);
  127. FIniStream.Position:=0; //In case we want to save
  128. Sections:=TStringList.Create;
  129. try
  130. if LoadProfileselect then
  131. begin
  132. Sections.Sorted:=true;
  133. MyIniFile.ReadSections(Sections);
  134. // Now take out the one where the profile is stored as it will confuse users
  135. if Sections.Find(FProfileSelectSection, ProfIndex) then
  136. Sections.Delete(ProfIndex);
  137. ProfileSelect.Clear;
  138. ProfileSelect.Items.AddStrings(Sections);
  139. FProfileSelectValue:=MyIniFile.ReadString(FProfileSelectSection,FProfileSelectKey,'');
  140. ProfileSelect.Text:=FProfileSelectValue;
  141. FMustReloadProfileSelect:=false;
  142. end;
  143. // restore cursor/caret position
  144. if LoadSynMemo and KeepCursorPosition then
  145. SynMemo.CaretXY:=OldPos;
  146. finally
  147. MyIniFile.Free;
  148. Sections.Free;
  149. SynMemo.EndUpdate;
  150. end;
  151. end;
  152. procedure TFormIniEditor.SetIniFilename(AValue: string);
  153. begin
  154. if FIniFilename=AValue then Exit;
  155. FIniFilename:=AValue;
  156. if FIniFileName<>'' then
  157. begin
  158. try
  159. FIniStream.Clear;
  160. FIniStream.LoadFromFile(FIniFilename);
  161. except
  162. on E: Exception do
  163. ShowMessage('Error loading file '+FIniFilename+': '+E.Message);
  164. end;
  165. LoadGUI(false,true,true);
  166. end;
  167. end;
  168. procedure TFormIniEditor.SetProfileSelectKey(AValue: string);
  169. begin
  170. if FProfileSelectKey=AValue then Exit;
  171. FProfileSelectKey:=AValue;
  172. if (FProfileSelectKey<>'') and (FProfileSelectSection<>'') then
  173. LoadGUI(false,true,true);
  174. end;
  175. procedure TFormIniEditor.SetProfileSelectSection(AValue: string);
  176. begin
  177. if FProfileSelectSection=AValue then Exit;
  178. FProfileSelectSection:=AValue;
  179. if (FProfileSelectKey<>'') and (FProfileSelectSection<>'') then
  180. LoadGUI(false,true,true);
  181. end;
  182. procedure TFormIniEditor.SynMemoSave(AlsoToFile: boolean);
  183. begin
  184. if FSaveChanges then
  185. begin
  186. FIniStream.Clear;
  187. FIniStream.Position:=0; //Save from beginning
  188. SynMemo.Lines.SaveToStream(FiniStream);
  189. FIniStream.Position:=0; //Save from beginning
  190. if AlsoToFile and (FIniFileName<>'') then
  191. FIniStream.SaveToFile(FIniFilename);
  192. end;
  193. end;
  194. procedure TFormIniEditor.CancelButtonClick(Sender: TObject);
  195. begin
  196. FSaveChanges:=false;
  197. end;
  198. procedure TFormIniEditor.FileNameEditAcceptFileName(Sender: TObject;
  199. var Value: String);
  200. begin
  201. // go through the property to load new file
  202. INIFile:=Value;
  203. end;
  204. procedure TFormIniEditor.FormCloseQuery(Sender: TObject; var CanClose: boolean);
  205. begin
  206. // Save any uncommitted changes
  207. //todo: only if dirty synmemo changestamp?; also check if this is best event
  208. SynMemoSave(true);
  209. end;
  210. procedure TFormIniEditor.FormCreate(Sender: TObject);
  211. begin
  212. FIniStream:=TMemoryStream.Create;
  213. FSaveChanges:=true; //allow editing
  214. end;
  215. procedure TFormIniEditor.FormDestroy(Sender: TObject);
  216. begin
  217. FIniStream.Free;
  218. end;
  219. end.