1 {
2 MiConfigIni 0.1b
3 =============
4 Por Tito Hinostroza 29/07/2016
5
6 Descripción
7 ===========
8 Unidad con rutinas de lectura/escritura de propiedades en archivos INI. Permite crear
9 fácilmente, una ventana de configuración, con las opciones: ACEPTAR y CANCELAR.
10 Está basado en la librería ConfigFrame, pero a diferencia de esta, aquí las propiedades
11 no se separan en "frames", sino que todas las propiedades se manejan en un mismo objeto.
12 Para alamacenar las propiedades, se debe crear un objeto TMiConfigINI. Sin embargo,
13 la unidad crea por defecto, una isntancia de TMiConfigINI, llamada "cfgFile", que toma
14 como nombre <nombre del proyecto>.ini
15 Tiene como dependencia a la librería MisUtils.
16
17 Por Tito Hinostroza 29/07/2016
18 }
19 unit MiConfigINI;
20 {$mode objfpc}{$H+}
21 interface
22 uses
23 Classes, SysUtils, Graphics, Forms, IniFiles, MisUtils, MiConfigBasic;
24 type
25 { TMiConfigINI }
26 {Clase base que es usada para manejar los campos de configuración.}
27 TMiConfigINI = class(TMiConfigBasic)
28 private
29 fileName : string; //archivo XML
DefaultFileNamenull30 function DefaultFileName: string;
31 procedure FileProperty(iniCfg: TIniFile; const r: TParElem; FileToProp: boolean);
32 public
33 secINI: string; //sección donde se guardarán los datos en un archivo INI
34 procedure VerifyFile;
FileToPropertiesnull35 function FileToProperties: boolean; virtual;
PropertiesToFilenull36 function PropertiesToFile: boolean; virtual;
37 public //Constructor y Destructor
38 constructor Create(INIfile0: string);
39 destructor Destroy; override;
40 end;
41
42 var
43 cfgFile : TMiConfigINI; //Default INI Config file
44
45 implementation
46 //Funciones de uso interno
CodeStrnull47 function CodeStr(s:string): string;
48 {Protege a una cadena para que no pierda los espacios laterales si es que los tiene,
49 porque el el archivo INI se pierden. Además codifica el caracter "=", porque es
50 reservado en el archvio INI}
51 begin
52 Result := '.'+s+'.';
53 Result := StringReplace(Result, '=', #25, [rfReplaceAll]); //protege caracter
54 Result := StringReplace(Result, LineEnding, #26, [rfReplaceAll]); //protege caracter
55 end;
DecodeStrnull56 function DecodeStr(s:string): string;
57 {Quita la protección a una cadena que ha sido guardada en un archivo INI}
58 begin
59 Result:=copy(s,2,length(s)-2);
60 Result := StringReplace(Result, #25, '=', [rfReplaceAll]); //protege caracter
61 Result := StringReplace(Result, #26, LineEnding, [rfReplaceAll]); //protege caracter
62 end;
63 { TMiConfigINI }
TMiConfigINI.DefaultFileNamenull64 function TMiConfigINI.DefaultFileName: string;
65 {Devuelve el nombre pro defecto del archvio de configuración}
66 begin
67 Result := ChangeFileExt(Application.ExeName,'.ini');
68 end;
69 procedure TMiConfigINI.VerifyFile;
70 //Verifica si el archivo INI "FileName" existe. Si no, muestra un mensaje y lo crea.
71 var
72 F: textfile;
73 begin
74 if not FileExists(fileName) then begin
75 MsgErr('No INI file found: %s', [fileName]);
76 //crea uno vacío para leer las opciones por defecto
77 AssignFile(F, fileName);
78 Rewrite(F);
79 CloseFile(F);
80 end;
81 end;
82 procedure TMiConfigINI.FileProperty(iniCfg: TIniFile; const r: TParElem; FileToProp: boolean);
83 {Permite leer o escribir una propiedad en el archivo XML}
84 var
85 n, j: Integer;
86 list: TStringList;
87 strlst: TStringList;
88 c: TColor;
89 begin
90 if r.pVar = nil then exit; //se inició con NIL
91 case r.tipPar of
92 tp_Int, tp_Int_TEdit, tp_Int_TSpinEdit, tp_Int_TRadioGroup:
93 if FileToProp then begin //lee entero
94 r.AsInteger := iniCfg.ReadInteger(secINI, r.etiqVar, r.defInt);
95 end else begin
96 iniCfg.WriteInteger(secINI, r.etiqVar, r.AsInteger);
97 end;
98 //---------------------------------------------------------------------
99 tp_Dbl, tp_Dbl_TEdit, tp_Dbl_TFloatSpinEdit:
100 if FileToProp then begin
101 r.AsDouble := iniCfg.ReadFloat(secINI, r.etiqVar, r.defDbl);
102 end else begin
103 iniCfg.WriteFloat(secINI, r.etiqVar, r.AsDouble);
104 end;
105 //---------------------------------------------------------------------
106 tp_Str, tp_Str_TEdit, tp_Str_TEditButton, tp_Str_TCmbBox:
107 if FileToProp then begin //lee cadena
108 r.AsString := DecodeStr(iniCfg.ReadString(secINI, r.etiqVar, '.'+r.defStr+'.'));
109 end else begin
110 iniCfg.WriteString(secINI, r.etiqVar, CodeStr(r.AsString));
111 end;
112 //---------------------------------------------------------------------
113 tp_Bol, tp_Bol_TCheckBox, tp_Bol_TRadBut:
114 if FileToProp then begin //lee booleano
115 r.AsBoolean := iniCfg.ReadBool(secINI, r.etiqVar, r.defBol);
116 end else begin
117 iniCfg.WriteBool(secINI, r.etiqVar, r.AsBoolean);
118 end;
119 //---------------------------------------------------------------------
120 tp_Enum, tp_Enum_TRadBut, tp_Enum_TRadGroup:
121 if FileToProp then begin //lee enumerado como entero
122 if r.lVar = 4 then begin //tamaño común de las variable enumeradas
123 r.AsInt32 := iniCfg.ReadInteger(secINI, r.etiqVar, r.defInt);
124 end else begin //tamaño no implementado
125 msjErr := dic('Enumerated type no handled.');
126 exit;
127 end;
128 end else begin
129 if r.lVar = 4 then begin
130 iniCfg.WriteInteger(secINI, r.etiqVar, r.AsInt32); //como entero de 4 bytes
131 end else begin //tamaño no implementado
132 msjErr := dic('Enumerated type no handled.');
133 exit;
134 end;
135 end;
136 //---------------------------------------------------------------------
137 tp_TCol_TColBut, tp_TCol_TColBox:
138 if FileToProp then begin //lee TColor
139 r.AsTColor := iniCfg.ReadInteger(secINI, r.etiqVar, r.defCol);
140 end else begin
141 c := r.AsTColor;
142 iniCfg.WriteInteger(secINI, r.etiqVar, c);
143 end;
144 tp_StrList, tp_StrList_TListBox:
145 if FileToProp then begin //lee TStringList
146 list := TStringList(r.Pvar^);
147 iniCfg.ReadSection(secINI+'_'+r.etiqVar, list);
148 //decodifica cadena
149 for n:=0 to list.Count-1 do list[n] := DecodeStr(list[n]);
150 end else begin
151 strlst := TStringList(r.Pvar^);
152 iniCfg.EraseSection(secINI+'_'+r.etiqVar);
153 for j:= 0 to strlst.Count-1 do begin
154 iniCfg.WriteString(secINI+'_'+r.etiqVar,
155 CodeStr(strlst[j]),'');
156 end;
157 end;
158 else //no se ha implementado bien
159 msjErr := dic('Design error.');
160 exit;
161 end;
162 end;
TMiConfigINI.FileToPropertiesnull163 function TMiConfigINI.FileToProperties: boolean;
164 {Lee de disco las propiedades registradas
165 Si encuentra error devuelve FALSE, y el mensaje de error en "MsjErr", y el elemento
166 con error en "ctlErr".}
167 var
168 r: TParElem;
169 iniCfg: TIniFile;
170 begin
171 if not FileExists(fileName) then begin
172 ctlErr := nil;
173 MsjErr := dic('INI file does not exist.'); //errro
174 exit(false); //para que no intente leer
175 end;
176 try
177 iniCfg := TIniFile.Create(fileName);
178 except
179 ctlErr := nil;
180 MsjErr := dic('Error reading INI file: %s', [fileName]);
181 iniCfg.Free;
182 exit(false);
183 end;
184 msjErr := '';
185 for r in listParElem do begin
186 FileProperty(iniCfg, r, true);
187 if msjErr<>'' then begin
188 ctlErr := r; //elemento que produjo el error
189 iniCfg.Free; //libera
190 exit(false); //sale con error
191 end;
192 if r.OnFileToProperty<>nil then r.OnFileToProperty;
193 end;
194 //Terminó con éxito. Actualiza los cambios
195 if OnPropertiesChanges<>nil then OnPropertiesChanges;
196 ctlErr := nil;
197 iniCfg.Free; //libera
198 exit(true); //sale sin error
199 end;
TMiConfigINI.PropertiesToFilenull200 function TMiConfigINI.PropertiesToFile: boolean;
201 {Guarda en disco las propiedades registradas
202 Si encuentra error devuelve FALSE, y el mensaje de error en "MsjErr", y el elemento
203 con error en "ctlErr".}
204 var
205 r: TParElem;
206 iniCfg: TIniFile; //
207 begin
208 if FileExists(fileName) then begin //ve si existe
209 if FileIsReadOnly(fileName) then begin
210 ctlErr := nil;
211 MsjErr := dic('INI file is only read.');
212 exit(false);
213 end;
214 end;
215 try
216 iniCfg := TIniFile.Create(fileName);
217 except
218 ctlErr := nil;
219 MsjErr := dic('Error writing INI file: %s', [fileName]);
220 exit(false);
221 end;
222 msjErr := '';
223 for r in listParElem do begin
224 if r.OnPropertyToFile<>nil then r.OnPropertyToFile; //se ejecuta antes
225 FileProperty(iniCfg, r, false);
226 if msjErr<>'' then begin
227 ctlErr := r; //elemento que produjo el error
228 iniCfg.Free; //libera
229 exit(false); //sale con error
230 end;
231 end;
232 ctlErr := nil;
233 iniCfg.Free; //libera
234 exit(true); //sin error
235 end;
236 //Constructor y Destructor
237 constructor TMiConfigINI.Create(INIfile0: string);
238 begin
239 inherited Create;
240 fileName := INIfile0;
241 secINI := 'config'; //sección por defecto en archivo INI
242 end;
243 destructor TMiConfigINI.Destroy;
244 begin
245 inherited Destroy;
246 end;
247
248 initialization
249 cfgFile := TMiConfigINI.Create(cfgFile.DefaultFileName);
250
251 finalization
252 cfgFile.Destroy;
253 end.
254
255