1 { $Id$ }
2 {
3 *****************************************************************************
4 This file is part of the Lazarus Component Library (LCL)
5
6 See the file COPYING.modifiedLGPL.txt, included in this distribution,
7 for details about the license.
8 *****************************************************************************
9 }
10 unit XMLPropStorage;
11
12 {$mode objfpc}{$H+}
13
14 interface
15
16
17 uses
18 // RTL, FCL
19 Classes, SysUtils, XMLConf, DOM, XMLRead, XMLWrite,
20 // LCL
21 LCLProc, Forms,
22 // LazUtils
23 LazConfigStorage, LazUTF8;
24
25 type
26 { TPropStorageXMLConfig }
27
28 TPropStorageXMLConfig = class(TXMLConfig)
29 Public
30 procedure DeleteSubNodes(const ARootNode: String);
31 procedure LoadFromStream(s: TStream); virtual;
32 procedure SaveToStream(s: TStream); virtual;
33 property XMLDoc: TXMLDocument read Doc;
34 end;
35
36 { TCustomXMLPropStorage }
37
38 TCustomXMLPropStorage = class(TFormPropertyStorage)
39 private
40 FCount: Integer;
41 FFileName: String;
42 FXML: TPropStorageXMLConfig;
43 FRootNodePath: String;
44 protected
GetXMLFileNamenull45 function GetXMLFileName: string; virtual;
RootSectionnull46 function RootSection: String; Override;
FixPathnull47 function FixPath(const APath: String): String; virtual;
48 Property XMLConfig: TPropStorageXMLConfig Read FXML;
49 public
50 procedure StorageNeeded(ReadOnly: Boolean);override;
51 procedure FreeStorage; override;
DoReadStringnull52 function DoReadString(const Section, Ident, TheDefault: string): string; override;
53 procedure DoWriteString(const Section, Ident, Value: string); override;
54 procedure DoEraseSections(const ARootSection: String);override;
55 public
56 property FileName: String Read FFileName Write FFileName;
57 property RootNodePath: String Read FRootNodePath Write FRootNodePath;
58 end;
59
60 { TXMLPropStorage }
61
62 TXMLPropStorage = class(TCustomXMLPropStorage)
63 Published
64 property StoredValues;
65 property FileName;
66 property RootNodePath;
67 property Active;
68 property OnSavingProperties;
69 property OnSaveProperties;
70 property OnRestoringProperties;
71 property OnRestoreProperties;
72 end;
73
74 { TXMLConfigStorage }
75
76 TXMLConfigStorage = class(TConfigStorage)
77 private
78 FFilename: string;
79 FFreeXMLConfig: boolean;
80 FXMLConfig: TXMLConfig;
81 protected
GetFullPathValuenull82 function GetFullPathValue(const APath, ADefault: String): String; override;
GetFullPathValuenull83 function GetFullPathValue(const APath: String; ADefault: Integer): Integer; override;
GetFullPathValuenull84 function GetFullPathValue(const APath: String; ADefault: Boolean): Boolean; override;
85 procedure SetFullPathValue(const APath, AValue: String); override;
86 procedure SetDeleteFullPathValue(const APath, AValue, DefValue: String); override;
87 procedure SetFullPathValue(const APath: String; AValue: Integer); override;
88 procedure SetDeleteFullPathValue(const APath: String; AValue, DefValue: Integer); override;
89 procedure SetFullPathValue(const APath: String; AValue: Boolean); override;
90 procedure SetDeleteFullPathValue(const APath: String; AValue, DefValue: Boolean); override;
91 procedure DeleteFullPath(const APath: string); override;
92 procedure DeleteFullPathValue(const APath: string); override;
93 public
94 procedure Clear; override;
95 constructor Create(const Filename: string; LoadFromDisk: Boolean); override;
96 constructor Create(TheXMLConfig: TXMLConfig);
97 constructor Create(TheXMLConfig: TXMLConfig; const StartPath: string);
98 constructor Create(s: TStream; const StartPath: string = '');
99 destructor Destroy; override;
100 property XMLConfig: TXMLConfig read FXMLConfig;
101 property FreeXMLConfig: boolean read FFreeXMLConfig write FFreeXMLConfig;
102 procedure WriteToDisk; override;
GetFilenamenull103 function GetFilename: string; override;
104 procedure SaveToStream(s: TStream); virtual;
105 end;
106
107 procedure Register;
108
109
110 implementation
111
112 {$IFDEF FPC_HAS_CPSTRING}
113 {$WARN IMPLICIT_STRING_CAST OFF}
114 {$WARN IMPLICIT_STRING_CAST_LOSS OFF}
115 {$ENDIF}
116
117 procedure Register;
118 begin
119 RegisterComponents('Misc',[TXMLPropStorage]);
120 end;
121
122 { TCustomXMLPropStorage }
123
124 procedure TCustomXMLPropStorage.StorageNeeded(ReadOnly: Boolean);
125 begin
126 If (FXML=Nil) and not (csDesigning in ComponentState) then
127 begin
128 FXML:=TPropStorageXMLConfig.Create(nil);
129 FXML.FileName := GetXMLFileName;
130 end;
131 Inc(FCount);
132 //debugln('TCustomXMLPropStorage.StorageNeeded ',dbgsname(FXML),' ',dbgs(FXML),' FCount=',dbgs(FCount));
133 end;
134
135 procedure TCustomXMLPropStorage.FreeStorage;
136 begin
137 Dec(FCount);
138 //debugln('TCustomXMLPropStorage.FreeStorage ',dbgsname(FXML),' ',dbgs(FXML),' FCount=',dbgs(FCount));
139 If (FCount<=0) then
140 begin
141 FCount:=0;
142 FreeAndNil(FXML);
143 end;
144 end;
145
GetXMLFileNamenull146 function TCustomXMLPropStorage.GetXMLFileName: string;
147 begin
148 if (FFileName<>'') then
149 Result:=FFileName
150 else if csDesigning in ComponentState then
151 raise Exception.Create('TCustomXMLPropStorage.GetXMLFileName: missing Filename')
152 else
153 {$ifdef unix}
154 Result:=IncludeTrailingPathDelimiter(GetEnvironmentVariableUTF8('HOME'))
155 +'.'+ExtractFileName(Application.ExeName);
156
157 {$else}
158 Result:=ChangeFileExt(Application.ExeName,'.xml');
159 {$endif}
160 //debugln('TCustomXMLPropStorage.GetXMLFileName "',Result,'"');
161 end;
162
TCustomXMLPropStorage.FixPathnull163 function TCustomXMLPropStorage.FixPath(const APath: String): String;
164 begin
165 Result:=StringReplace(APath,'.','/',[rfReplaceAll]);
166 end;
167
TCustomXMLPropStorage.RootSectionnull168 function TCustomXMLPropStorage.RootSection: String;
169 begin
170 If (FRootNodePath<>'') then
171 Result:=FRootNodePath
172 else
173 Result:=inherited RootSection;
174 Result:=FixPath(Result);
175 end;
176
DoReadStringnull177 function TCustomXMLPropStorage.DoReadString(const Section, Ident,
178 TheDefault: string): string;
179 var
180 Res: UnicodeString;
181 begin
182 Res:=FXML.GetValue(Utf8Decode(FixPath(Section)+'/'+Ident), Utf8Decode(TheDefault));
183 Result := Utf8Encode(Res);
184 //debugln('TCustomXMLPropStorage.DoReadString Section="',Section,'" Ident="',Ident,'" Result=',Result);
185 end;
186
187 procedure TCustomXMLPropStorage.DoWriteString(const Section, Ident,
188 Value: string);
189 begin
190 //debugln('TCustomXMLPropStorage.DoWriteString Section="',Section,'" Ident="',Ident,'" Value="',Value,'"');
191 FXML.SetValue(Utf8Decode(FixPath(Section)+'/'+Ident), Utf8Decode(Value));
192 end;
193
194 procedure TCustomXMLPropStorage.DoEraseSections(const ARootSection: String);
195 begin
196 //debugln('TCustomXMLPropStorage.DoEraseSections ARootSection="',ARootSection,'"');
197 FXML.DeleteSubNodes(FixPath(ARootSection));
198 end;
199
200 { TPropStorageXMLConfig }
201
202 procedure TPropStorageXMLConfig.DeleteSubNodes(const ARootNode: String);
203 var
204 Node, Child: TDOMNode;
205 i: Integer;
206 NodePath: String;
207 begin
208 Node := doc.DocumentElement;
209 NodePath := ARootNode;
210 while (Length(NodePath)>0) and (Node<>Nil) do
211 begin
212 i := Pos('/', NodePath);
213 if i = 0 then
214 I:=Length(NodePath)+1;
215 Child := Node.FindNode(UTF8Decode(Copy(NodePath,1,i - 1)));
216 System.Delete(NodePath,1,I);
217 Node := Child;
218 end;
219 If Assigned(Node) then begin
220 //debugln('TPropStorageXMLConfig.DeleteSubNodes ',ARootNode);
221 Node.Free;
222 end;
223 end;
224
225 procedure TPropStorageXMLConfig.LoadFromStream(s: TStream);
226 begin
227 FreeAndNil(Doc);
228 ReadXMLFile(Doc,s);
229 end;
230
231 procedure TPropStorageXMLConfig.SaveToStream(s: TStream);
232 begin
233 WriteXMLFile(Doc,s);
234 end;
235
236 { TXMLConfigStorage }
237
TXMLConfigStorage.GetFullPathValuenull238 function TXMLConfigStorage.GetFullPathValue(const APath, ADefault: String
239 ): String;
240 begin
241 Result:=XMLConfig.GetValue(APath, ADefault);
242 end;
243
TXMLConfigStorage.GetFullPathValuenull244 function TXMLConfigStorage.GetFullPathValue(const APath: String;
245 ADefault: Integer): Integer;
246 begin
247 Result:=XMLConfig.GetValue(APath, ADefault);
248 end;
249
TXMLConfigStorage.GetFullPathValuenull250 function TXMLConfigStorage.GetFullPathValue(const APath: String;
251 ADefault: Boolean): Boolean;
252 begin
253 Result:=XMLConfig.GetValue(APath, ADefault);
254 end;
255
256 procedure TXMLConfigStorage.SetFullPathValue(const APath, AValue: String);
257 begin
258 XMLConfig.SetValue(APath, AValue);
259 end;
260
261 procedure TXMLConfigStorage.SetDeleteFullPathValue(const APath, AValue,
262 DefValue: String);
263 begin
264 XMLConfig.SetDeleteValue(APath, AValue, DefValue);
265 end;
266
267 procedure TXMLConfigStorage.SetFullPathValue(const APath: String;
268 AValue: Integer);
269 begin
270 XMLConfig.SetValue(APath, AValue);
271 end;
272
273 procedure TXMLConfigStorage.SetDeleteFullPathValue(const APath: String;
274 AValue, DefValue: Integer);
275 begin
276 XMLConfig.SetDeleteValue(APath, AValue, DefValue);
277 end;
278
279 procedure TXMLConfigStorage.SetFullPathValue(const APath: String;
280 AValue: Boolean);
281 begin
282 XMLConfig.SetValue(APath, AValue);
283 end;
284
285 procedure TXMLConfigStorage.SetDeleteFullPathValue(const APath: String;
286 AValue, DefValue: Boolean);
287 begin
288 XMLConfig.SetDeleteValue(APath, AValue, DefValue);
289 end;
290
291 procedure TXMLConfigStorage.DeleteFullPath(const APath: string);
292 begin
293 XMLConfig.DeletePath(APath);
294 end;
295
296 procedure TXMLConfigStorage.DeleteFullPathValue(const APath: string);
297 begin
298 XMLConfig.DeleteValue(APath);
299 end;
300
301 procedure TXMLConfigStorage.Clear;
302 begin
303 FXMLConfig.Clear;
304 end;
305
306 constructor TXMLConfigStorage.Create(const Filename: string;
307 LoadFromDisk: Boolean);
308 var
309 ms: TMemoryStream;
310 fs: TFileStream;
311 begin
312 FXMLConfig:=TPropStorageXMLConfig.Create(nil);
313 FFilename:=Filename;
314 FFreeXMLConfig:=true;
315 if LoadFromDisk then
316 begin
317 fs:=TFileStream.Create(Filename,fmOpenRead+fmShareDenyWrite);
318 try
319 ms:=TMemoryStream.Create;
320 try
321 ms.CopyFrom(fs,fs.Size);
322 ms.Position:=0;
323 TPropStorageXMLConfig(FXMLConfig).LoadFromStream(ms);
324 finally
325 ms.Free;
326 end;
327 finally
328 fs.Free;
329 end;
330 end;
331 end;
332
333 constructor TXMLConfigStorage.Create(TheXMLConfig: TXMLConfig);
334 begin
335 FXMLConfig:=TheXMLConfig;
336 FFilename:=FXMLConfig.Filename;
337 if FXMLConfig=nil then
338 raise Exception.Create('');
339 end;
340
341 constructor TXMLConfigStorage.Create(TheXMLConfig: TXMLConfig;
342 const StartPath: string);
343 begin
344 Create(TheXMLConfig);
345 AppendBasePath(StartPath);
346 end;
347
348 constructor TXMLConfigStorage.Create(s: TStream; const StartPath: string);
349 begin
350 FXMLConfig:=TPropStorageXMLConfig.Create(nil);
351 FFreeXMLConfig:=true;
352 TPropStorageXMLConfig(FXMLConfig).LoadFromStream(s);
353 if StartPath<>'' then
354 AppendBasePath(StartPath);
355 end;
356
357 destructor TXMLConfigStorage.Destroy;
358 begin
359 if FreeXMLConfig then FreeAndNil(FXMLConfig);
360 inherited Destroy;
361 end;
362
363 procedure TXMLConfigStorage.WriteToDisk;
364 var
365 ms: TMemoryStream;
366 fs: TFileStream;
367 begin
368 if FXMLConfig is TPropStorageXMLConfig then
369 begin
370 ms:=TMemoryStream.Create;
371 try
372 TPropStorageXMLConfig(FXMLConfig).SaveToStream(ms);
373 ms.Position:=0;
374 fs:=TFileStream.Create(GetFilename,fmCreate);
375 try
376 fs.CopyFrom(ms,ms.Size);
377 finally
378 fs.Free;
379 end;
380 finally
381 ms.Free;
382 end;
383 end else
384 FXMLConfig.Flush;
385 end;
386
TXMLConfigStorage.GetFilenamenull387 function TXMLConfigStorage.GetFilename: string;
388 begin
389 Result:=FFilename;
390 end;
391
392 procedure TXMLConfigStorage.SaveToStream(s: TStream);
393 begin
394 if FXMLConfig is TPropStorageXMLConfig then begin
395 TPropStorageXMLConfig(FXMLConfig).SaveToStream(s);
396 end else
397 raise Exception.Create('TXMLConfigStorage.SaveToStream not supported for '+DbgSName(FXMLConfig));
398 end;
399
400 end.
401