inieditor.pas 7.3 KB

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