| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- {
- MiConfigXml
- ===========
- Por Tito Hinostroza 29/07/2016
- Descripción
- ===========
- Unidad con rutinas de lectura/escritura de propiedades en archivos XML. Permite crear
- fácilmente, una ventana de configuración, con las opciones: ACEPTAR y CANCELAR.
- Es similar a MiConfigINI, pero trabaja con archivos XML.
- Para alamacenar las propiedades, se debe crear un objeto TMiConfigXML. Sin embargo,
- la unidad crea por defecto, una instancia de TMiConfigXML, llamada "cfgFile", que toma
- como nombre <nombre del proyecto>.xml
- Tiene como dependencia a la librería MisUtils.
- Por Tito Hinostroza 29/07/2016
- }
- unit MiConfigXML;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils, Graphics, Forms, LCLType, Laz2_XMLCfg, MiConfigBasic;
- type
- { TMiConfigXML }
- {Clase base que es usada para manejar los campos de configuración.}
- TMiConfigXML = class(TMiConfigBasic)
- protected
- fileName : string; //archivo XML
- function DefaultFileName: string;
- procedure FileProperty(xmlCfg: TXMLConfig; const r: TParElem; FileToProp: boolean);
- function LoadXMLFile(filName: string; out xmlCfg: TXMLConfig): boolean;
- public
- secINI: string; //sección donde se guardarán los datos en un archivo INI
- procedure VerifyFile;
- function FileToProperties: boolean; virtual;
- function FileToPropertiesCat(xmlFil: string; cat: integer): boolean;
- function PropertiesToWindowCat(cat: integer): boolean;
- function PropertiesToFile: boolean; virtual;
- function GetFileName: string;
- procedure SetFileName(AValue: string);
- public //Constructor y Destructor
- constructor Create(XMLfile0: string);
- destructor Destroy; override;
- end;
- var
- cfgFile: TMiConfigXML; //Default XML Config file
- implementation
- { TMiConfigXML }
- function TMiConfigXML.LoadXMLFile(filName: string; out xmlCfg: TXMLConfig): boolean;
- {Carga el archivo "filName" en xmlCfg. Si hay error, actualiza "MsjError" y
- devuelve FALSE. Función creada para uso interno de la clase.}
- begin
- msjErr := '';
- Result := true;
- if not FileExists(filName) then begin
- ctlErr := nil;
- MsjErr := 'XML file does not exist.'; //errro
- exit(false); //para que no intente leer
- end;
- try
- xmlCfg := TXMLConfig.Create(nil);
- xmlCfg.Filename := filName; //lee archivo XML, al asignar propiedad
- except
- ctlErr := nil;
- MsjErr := Format('Error reading XML file: %s', [filName]);
- xmlCfg.Free;
- exit(false);
- end;
- end;
- function TMiConfigXML.DefaultFileName: string;
- {Devuelve el nombre por defecto del archvio de configuración}
- begin
- Result := ChangeFileExt(Application.ExeName,'.xml');
- end;
- procedure TMiConfigXML.VerifyFile;
- //Verifica si el archivo XML "FileName" existe. Si no, muestra un mensaje y lo crea.
- var
- F: textfile;
- begin
- if not FileExists(fileName) then begin
- Application.MessageBox(
- Pchar(Format('No XML file found: %s', [fileName])),
- '', MB_ICONERROR);
- //Crea uno vacío para leer las opciones por defecto
- AssignFile(F, fileName);
- Rewrite(F);
- writeln(F, '<?xml version="1.0" encoding="utf-8"?>');
- writeln(F, '<CONFIG>');
- writeln(F, '</CONFIG>');
- CloseFile(F);
- end;
- end;
- procedure TMiConfigXML.FileProperty(xmlCfg: TXMLConfig; const r: TParElem; FileToProp: boolean);
- {Permite leer o escribir una propiedad en el archivo XML}
- var
- s, defStr: String;
- c: TColor;
- list: TStringList;
- begin
- if r.varRef = nil then exit; //se inició con NIL
- case r.asType of
- tp_Int, tp_Int_TEdit, tp_Int_TSpinEdit, tp_Int_TRadioGroup:
- if FileToProp then begin //lee entero
- r.AsInteger := xmlCfg.GetValue(r.asLabel + '/Val', r.defInt)
- end else begin
- xmlCfg.SetValue(r.asLabel + '/Val', r.AsInteger) ;
- end;
- //---------------------------------------------------------------------
- tp_Dbl, tp_Dbl_TEdit, tp_Dbl_TFloatSpinEdit:
- //No hay métodos para leer/escribir números flotantes. Se usarán cadena
- if FileToProp then begin
- defStr := FloatToStr(r.defDbl);
- s := xmlCfg.GetValue(r.asLabel + '/Val', defStr); //lee como cadena
- r.AsDouble := StrToFloat(s);
- end else begin
- s := FloatToStr(r.AsDouble);
- xmlCfg.SetValue(r.asLabel + '/Val', s) ;
- end;
- //---------------------------------------------------------------------
- tp_Str, tp_Str_TEdit, tp_Str_TEditButton, tp_Str_TCmbBox:
- if FileToProp then begin //lee cadena
- r.AsString := xmlCfg.GetValue(r.asLabel + '/Val', r.defStr);
- end else begin
- xmlCfg.SetValue(r.asLabel + '/Val', r.AsString) ;
- end;
- //---------------------------------------------------------------------
- tp_Bol, tp_Bol_TCheckBox, tp_Bol_TRadBut:
- if FileToProp then begin //lee booleano
- r.AsBoolean := xmlCfg.GetValue(r.asLabel + '/Val', r.defBol);
- end else begin
- xmlCfg.SetValue(r.asLabel + '/Val', r.AsBoolean);
- end;
- //---------------------------------------------------------------------
- tp_Enum, tp_Enum_TRadBut, tp_Enum_TRadGroup:
- if FileToProp then begin //lee enumerado como entero
- if r.varSiz = 4 then begin //tamaño común de las variable enumeradas
- r.AsInt32 := xmlCfg.GetValue(r.asLabel + '/Val', r.defInt);
- end else begin //tamaño no implementado
- msjErr := 'Enumerated type no handled.';
- exit;
- end;
- end else begin
- if r.varSiz = 4 then begin
- xmlCfg.SetValue(r.asLabel + '/Val', r.AsInt32) ;
- end else begin //tamaño no implementado
- msjErr := 'Enumerated type no handled.';
- exit;
- end;
- end;
- //---------------------------------------------------------------------
- tp_TCol_TColBut, tp_TCol_TColBox:
- if FileToProp then begin //lee TColor
- r.AsTColor := xmlCfg.GetValue(r.asLabel + '/Val', r.defCol); //lee como entero
- end else begin
- c := r.AsTColor;
- xmlCfg.SetValue(r.asLabel + '/Val', c) ; //escribe como entero
- end;
- tp_StrList, tp_StrList_TListBox:
- if FileToProp then begin //lee TStringList
- list := TStringList(r.varRef^);
- list.Text := xmlCfg.GetValue(r.asLabel + '/Val', ''); //lee como texto
- end else begin
- list := TStringList(r.varRef^);
- xmlCfg.SetValue(r.asLabel + '/Val', list.Text); //escribe como texto
- end;
- else //no se ha implementado bien
- msjErr := 'Design error.';
- exit;
- end;
- end;
- function TMiConfigXML.FileToProperties: boolean;
- {Lee de disco las propiedades registradas
- Si encuentra error devuelve FALSE, y el mensaje de error en "MsjErr", y el elemento
- con error en "ctlErr".}
- var
- r: TParElem;
- xmlCfg: TXMLConfig;
- begin
- if not LoadXMLFile(fileName, xmlCfg) then exit(false);
- for r in listParElem do begin
- FileProperty(xmlCfg, r, true);
- if msjErr<>'' then begin
- ctlErr := r; //elemento que produjo el error
- xmlCfg.Free; //libera
- exit(false); //sale con error
- end;
- if r.OnFileToProperty<>nil then r.OnFileToProperty;
- end;
- //Terminó con éxito. Actualiza los cambios
- if OnPropertiesChanges<>nil then OnPropertiesChanges;
- ctlErr := nil;
- xmlCfg.Free; //libera
- exit(true); //sale sin error
- end;
- function TMiConfigXML.FileToPropertiesCat(xmlFil: string; cat: integer): boolean;
- {Lee de disco las propiedades registradas con una categoría específica.
- Si encuentra error devuelve FALSE, y el mensaje de error en "MsjErr", y el elemento
- con error en "ctlErr".
- Es similar a FileToProperties(), pero no genera eventos. Se creó pensando usarse
- en casos como una rutina independiente para cargar solo ciertas propiedades de un
- archivo de configuración, como cuando se manejan configuraciones de colores (temas)}
- var
- r: TParElem;
- xmlCfg: TXMLConfig;
- begin
- if not LoadXMLFile(xmlFil, xmlCfg) then exit(false);
- for r in listParElem do begin
- if r.categ<>cat then continue; //ignora los de otra categoría
- FileProperty(xmlCfg, r, true);
- if msjErr<>'' then begin
- ctlErr := r; //elemento que produjo el error
- xmlCfg.Free; //libera
- exit(false); //sale con error
- end;
- end;
- //Terminó con éxito. Actualiza los cambios
- ctlErr := nil;
- xmlCfg.Free; //libera
- exit(true); //sale sin error
- end;
- function TMiConfigXML.PropertiesToWindowCat(cat: integer): boolean;
- {Versión de PropertiesToWindow, que solo trabaja con una categoría, y no genera
- eventos.}
- var
- r: TParElem;
- begin
- msjErr := '';
- for r in listParElem do begin
- if r.categ<>cat then continue; //ignora los de otra categoría
- PropertyWindow(r, true);
- if msjErr<>'' then begin
- ctlErr := r; //guarda la referencia al elemento, en caso de que haya error
- end;
- end;
- Result := (msjErr='');
- end;
- function TMiConfigXML.PropertiesToFile: boolean;
- {Guarda en disco las propiedades registradas
- Si encuentra error devuelve FALSE, y el mensaje de error en "MsjErr", y el elemento
- con error en "ctlErr".}
- var
- r: TParElem;
- xmlCfg: TXMLConfig;
- begin
- if FileExists(fileName) then begin //ve si existe
- if FileIsReadOnly(fileName) then begin
- ctlErr := nil;
- MsjErr := 'XML file is only read.';
- exit(false);
- end;
- end;
- try
- xmlCfg := TXMLConfig.Create(nil);
- xmlCfg.Filename := fileName; //lee archivo XML
- xmlCfg.Clear;
- except
- ctlErr := nil;
- MsjErr := Format('Error writing XML file: %s', [fileName]);
- xmlCfg.Free;
- exit(false);
- end;
- msjErr := '';
- for r in listParElem do begin
- if r.OnPropertyToFile<>nil then r.OnPropertyToFile; //se ejecuta antes
- FileProperty(xmlCfg, r, false);
- if msjErr<>'' then begin
- ctlErr := r; //elemento que produjo el error
- xmlCfg.Free; //libera
- exit(false); //sale con error
- end;
- end;
- xmlCfg.Flush;
- ctlErr := nil;
- xmlCfg.Free;
- exit(true); //sin error
- end;
- function TMiConfigXML.GetFileName: string;
- begin
- Result := fileName;
- end;
- procedure TMiConfigXML.SetFileName(AValue: string);
- begin
- fileName := AValue;
- end;
- //Constructor y Destructor
- constructor TMiConfigXML.Create(XMLfile0: string);
- begin
- inherited Create;
- fileName := XMLfile0;
- end;
- destructor TMiConfigXML.Destroy;
- begin
- inherited Destroy;
- end;
- initialization
- cfgFile := TMiConfigXML.Create(cfgFile.DefaultFileName);
- finalization
- cfgFile.Destroy;
- end.
|