Yo manejo una modificada, y con buenos resultados.
Acá le dejo una clase adicional que graba los valores en una tabla DBF.
La idea es que las variables puedan ser compartidas, sobre todo si son de configuración.
Code: Select all
#Include "FiveWin.ch"
#ifdef __CDXAX__
#include "ads.ch"
#endif
#ifdef __HARBOUR__
# xtranslate BYNAME <V> [, <VN> ] => ::<V> := <V> [; ::<VN> := <VN> ]
# xtranslate BYNAME <V> DEFAULT <Val> => ::<V> := BYDEFAULT <V>, <Val>
# xtranslate BYNAME <V> IFNONIL => if <V> != NIL ; ::<V> := <V> ; endif
# xtranslate BYDEFAULT <V>, <Val> => if( <V> == NIL, <Val>, <V> )
#endif
#ifdef __CDXAX__
#define DRIVER "ADS"
#else
#define DRIVER "DBFCDX"
#endif
#define VARNAME 1
#define VARVALUE 2
FIELD Name
//----------------------------------------------------------------------------//
CLASS TDBPublic FROM TPublic
DATA cPath, cFile, oDBVariables
#ifdef __CDXAX__
DATA cFileDD, nServerType, nConnection
#endif
#ifdef __CDXAX__
METHOD New( cPath, lQuick, lRebuild, nLenVarName, lAutomatic, cFile, cFileDD, nServerType, nConnection ) CONSTRUCTOR
#else
METHOD New( cPath, lQuick, lRebuild, nLenVarName, lAutomatic, cFile ) CONSTRUCTOR
#endif
METHOD Reindex( ) VIRTUAL //esto ya no va porque se realiza un mantenimiento automatico
METHOD Read( cName, uDefault ) //Recupera una Variable, si no esta en ::aVars la busca en oDBVariables = "Tabla Variable"
METHOD Save( cName, uValue ) //Establece una Variable en ::aVars y en oDBVariables = "Tabla Variable"
ENDCLASS
//----------------------------------------------------------------------------//
#ifdef __CDXAX__
METHOD New( cPath, lQuick, lRebuild, nLenVarName, lAutomatic, cFile, cFileDD, nServerType, nConnection ) CLASS TDBPublic
LOCAL nConnect
#else
METHOD New( cPath, lQuick, lRebuild, nLenVarName, lAutomatic, cFile ) CLASS TDBPublic
#endif
local cFileName,;
nAreaAnterior := Select()
Super:New( nLenVarName, lAutomatic )
DEFAULT lQuick := .T.,;
lRebuild := .F.,;
cFile := "Variable",;
cPath := SET( _SET_DEFAULT )
cPath := TRUENAME( cPath )
::cFile := cFile
::cPath := cPath
#ifdef __CDXAX__
DEFAULT cFileDD := "",;
nServerType := 0,;
nConnection := 0
::cFileDD := cFileDD
::nServerType := nServerType
::nConnection := nConnection
if nConnection > 0
AdsConnection( nConnection ) //Cambiamos la conexion a nConnection
endif
#endif
//Verificamos si se hara el Rebuild
IF lRebuild .AND.;
!MsgNoYes("Se reconstruira la tabla de VARIABLES. Usted es el unico usuario activo?","TDBVariable:New(..)")
lRebuild := .F. //si se responde que no a la pregunta, no se hace el Rebuild
ENDIF
#ifdef __CDXAX__
cFileName := cFile
#else
cFileName := cPath + "\" + cFile
#endif
#ifdef __CDXAX__
IF ( !lQuick .OR. lRebuild ) .AND. nServerType < ADS_AIS_SERVER
#else
IF ( !lQuick .OR. lRebuild )
#endif
#ifdef __CDXAX__
IF !_AdsIsTablePresent( cFile ) .OR. lRebuild
if nServerType>0
_AdsDDDecriptTable( cFile )
endif
#else
IF ! File( cFileName + ".dbf" ) .OR. lRebuild
#endif
Rebuild( cFile, cPath,;
{ { "NAME", "C", nLenVarName, 0 },;
{ "TYPE", "C", 1, 0 },;
{ "VALUE", "C", 256, 0 } }, DRIVER )
USE ( cFileName ) NEW EXCLUSIVE
INDEX ON UPPER(FIELD->NAME) TAG "NAME" TO ( cFileName ) FOR ! Deleted() UNIQUE
USE
ENDIF
ENDIF //End lQuick
#ifdef __CDXAX__
//Mantenimiento de la tabla
//OJO!!!! Falta: Elim. duplicados y reindexar
//REOJO!!!!!: al tener el valor UNIQUE el indice de la tabla, y reindexarla, no es necesario borrar lo registros duplicados
if nServerType < ADS_AIS_SERVER .AND. SELECT( cFile ) = 0
TRY
USE ( cFileName ) NEW EXCLUSIVE
PACK //tb se reindexa, y al tener el valor UNIQUE en el indice de la tabla, y ahora reindexarla, no es necesario borrar lo registros duplicados
//REINDEX //al tener el valor UNIQUE en el indice de la tabla, y ahora reindexarla, no es necesario borrar lo registros duplicados
//Verificamos si la Longitud de los nombres de Variable es la correcta...
//si no es asi, colocamos la señal para que mas tarde se haga el ReBuild()
lRebuild := .F.
IF .NOT. (LEN(FIELD->NAME) = ::nLenVarName)
lRebuild := .T.
ENDIF
USE
//para hacer el Rebuild(), primero hemos cerrado el area de trabajo
IF lRebuild
if nServerType>0
_AdsDDDecriptTable( cFile )
endif
Rebuild( cFile, cPath,;
{ { "NAME", "C", ::nLenVarName, 0 },;
{ "TYPE", "C", 1, 0 },;
{ "VALUE", "C", 256, 0 } }, DRIVER )
USE ( cFileName ) NEW EXCLUSIVE
INDEX ON UPPER(FIELD->NAME) TAG "NAME" TO ( cFileName ) FOR ! Deleted() UNIQUE
USE
ENDIF
CATCH
END TRY
endif
TRY
USE ( cFileName ) NEW SHARED
CATCH
if nServerType < ADS_AIS_SERVER .AND.;
!EMPTY(cFileDD) .AND.;
nConnection > 0 .AND.;
AdsDDAddTable( cFile, cPath + "\" + cFile + ".dbf", cPath + "\" + cFile + OrdBagExt(), nConnection ) //Enlazamos a un AdsDD si se puede
USE ( cFileName ) NEW SHARED
else
MsgStop("No se pudo abrir la tabla: " + cPath +"\"+ cFile + ".Dbf", "TDBVariable(..)")
DBSELECTAREA( nAreaAnterior )
return nil
endif
END TRY
#else
//Mantenimiento de la tabla
//OJO!!!! Falta: Elim. duplicados y reindexar
//REOJO!!!!!: al tener el valor UNIQUE el indice de la tabla, y reindexarla, no es necesario borrar lo registros duplicados
if SELECT( cFile ) = 0
TRY
USE ( cFileName ) NEW EXCLUSIVE
PACK
//REINDEX //al tener el valor UNIQUE en el indice de la tabla, y ahora reindexarla, no es necesario borrar lo registros duplicados
//Verificamos si la Longitud de los nombres de Variable es la correcta...
//si no es asi, colocamos la señal para que mas tarde se haga el ReBuild()
IF .NOT. LEN(FIELD->NAME) = ::nLenVarName
lRebuild := .T.
ENDIF
USE
IF lRebuild
Rebuild( cFile, cPath,;
{ { "NAME", "C", ::nLenVarName, 0 },;
{ "TYPE", "C", 1, 0 },;
{ "VALUE", "C", 256, 0 } }, DRIVER )
USE ( cFileName ) NEW EXCLUSIVE
INDEX ON UPPER(FIELD->NAME) TAG "NAME" TO ( cFileName ) FOR ! Deleted() UNIQUE
USE
ENDIF
CATCH
END TRY
endif
USE ( cFileName ) NEW SHARED
#endif
SET ORDER TO 1
DATABASE ::oDBVariables
::oDBVariables:bEoF = nil
DBSELECTAREA( nAreaAnterior )
return Self
//------------------------------------//
//Read(cVar, uDefault) Read Variable, retorna el valor de la variable establecida en la tabla VARIABLES
METHOD Read( cName, uDefault ) CLASS TDBPublic
LOCAL uValue
cName := AllTrim(Upper(cName))
IF ::Get( cName ) = NIL
//Recuperar del archivos de variables
::oDBVariables:SetOrder( "NAME" )
IF ::oDBVariables:Seek( cName, .F. )
IF uDefault <> NIL .AND. ValType(uDefault) <> ::oDBVariables:Type
::oDBVariables:Type := ValType(uDefault)
::oDBVariables:Save()
ENDIF
DO CASE
CASE ::oDBVariables:Type $ "CM"
uValue := RTRIM(::oDBVariables:Value) //en el caso de las variables caracter/memo se les quita los blancos de la derecha
CASE ::oDBVariables:Type = "N"
uValue := VAL(RTRIM(::oDBVariables:Value))
CASE ::oDBVariables:Type = "D"
uValue := CTOD(::oDBVariables:Value)
CASE ::oDBVariables:Type = "L"
uValue := UPPER(RTRIM(::oDBVariables:Value))=".T."
CASE ::oDBVariables:Type = "A"
uValue:=ARRAY(VAL( SubStr(::oDBVariables:Value,AT("[",::oDBVariables:Value)+1,AT("]",::oDBVariables:Value)-AT("[",::oDBVariables:Value)-1) ))
AEVAL(uValue, {|x,i| uValue[i] := ::Read("{"+cValToChar(i)+"}"+cName) } )
CASE ::oDBVariables:Type $ "UO"
uValue := NIL
CASE ::oDBVariables:Type = "B" //Los CodeBlock solo se los puede restaurar. !No se los puede salvar!.
//La edicion de estas variables es direcctamente en la tabla
//uValue := GenBlock( ::oDBVariables:Value )
END CASE
if AT("{",cName)>0 .AND. AT("}",cName)>0
RETURN uValue
else
::nPos := ASCAN( ::aVars, {|aVal| aVal[ VARNAME ] == cName } )
::aVars[::nPos, VARVALUE] := uValue
endif
ELSE
Return ::Save( cName, uDefault )
ENDIF
endif
RETURN ::aVars[::nPos, VARVALUE]
//----------------------------------------------------------------//
//Save(cName, uValue ) Salva el valor de Variable en el arreglo ::aVars y la graba a la tabla Variables
METHOD Save( cName, uValue ) CLASS TDBPublic
cName := AllTrim(Upper(cName))
DEFAULT uValue := ::Get(cName)
::Set( cName, uValue )
IF !( cName == ::oDBVariables:NAME)
::oDBVariables:SetOrder( "NAME" )
IF ! ::oDBVariables:Seek( cName, .F. )
::oDBVariables:APPEND()
::oDBVariables:NAME := cName
ENDIF
ENDIF
::oDBVariables:TYPE := ValType(uValue)
IF ::oDBVariables:TYPE="A" //para grabar arreglos
::oDBVariables:VALUE := cValToChar(uValue)+"["+cValToChar(LEN(uValue))+"]"
::oDBVariables:Save()
AEVAL(uValue, {|uValue,i| ::Save("{"+cValToChar(i)+"}"+cName, uValue) } )
else
::oDBVariables:VALUE := cValToChar(uValue)
::oDBVariables:Save()
ENDIF
return uValue
Desde Cochabamba, Bolivia.