Fixes #449

Fixes #449

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING XSharp
USING XSharp.RDD
USING XSharp.RDD.Enums
USING System.Collections.Generic
USING System.IO
USING System.Reflection
USING System.Linq
USING System.Text

#command DOINAREA <uArea> <func>  => ;
  	LOCAL nOld := RuntimeState.CurrentWorkarea AS DWORD ; ;
    IF _Select(<uArea>) != 0 ; ;
         TRY ;  ;
            RETURN <FUNC> ;;
         FINALLY;  ;
            RuntimeState.CurrentWorkarea := nOld ; ;
        END TRY; ;
    ENDIF ; ;
    THROW _NoAlias( <uArea> )

FUNCTION _NoAlias(uArea AS USUAL) AS Error
    VAR oErr := Error{EG_NOTABLE, "uArea", "Alias '"+uArea:ToString()+"' is not found"}
    oErr:FuncSym := ProcName(1):Replace("FUNCTIONS:","")
    RETURN oErr

/// <exclude />
FUNCTION _DbThrowErrorOnFailure(funcName AS STRING, resultToCheck AS LOGIC) AS LOGIC
    IF !resultToCheck
        resultToCheck := (LOGIC) DoError(funcName)
    ENDIF
    RETURN resultToCheck

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/alias0/*" />
FUNCTION Alias0() AS STRING
   LOCAL oRDD := VoDb.CWA("Alias0", FALSE) AS IRdd
    IF oRDD != NULL
        RETURN oRDD:Alias
    ENDIF
    RETURN String.Empty

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bof/*" />
FUNCTION Bof() AS LOGIC
   RETURN VoDb.Bof()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bof/*" />
FUNCTION Bof(uArea AS USUAL) AS LOGIC
    DOINAREA uArea Bof()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbf/*" />
FUNCTION DBF() AS STRING
    RETURN VoDb.Dbf()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbf/*" />
FUNCTION DBF(uArea AS USUAL) AS STRING
    DOINAREA uArea DBF()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbpack/*" />
FUNCTION DbPack() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Pack())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbpack/*" />
FUNCTION DbPack(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbPack()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbrecall/*" />
FUNCTION DbRecall() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Recall())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbrecall/*" />
FUNCTION DbRecall(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbRecall()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbunlock/*" />
FUNCTION DbUnLock() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Unlock(NULL_OBJECT))

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbunlock/*" />
FUNCTION DbUnLock(nRecord AS LONG) AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Unlock(nRecord))

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbzap/*" />
FUNCTION DbZap() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Zap())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbzap/*" />
FUNCTION DbZap(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbZap()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbunlockall/*" />
FUNCTION DbUnLockAll() AS LOGIC STRICT
	RETURN VoDb.UnlockAll()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/deleted/*" />
FUNCTION Deleted() AS LOGIC STRICT
	RETURN VoDb.Deleted()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/deleted/*" />
FUNCTION Deleted(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea Deleted()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/eof/*" />
FUNCTION Eof() AS LOGIC
   RETURN VoDb.Eof()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/eof/*" />
FUNCTION Eof(uArea AS USUAL) AS LOGIC
    DOINAREA uArea Eof()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/flock/*" />
FUNCTION Flock() AS LOGIC STRICT
	RETURN VoDb.Flock()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/flock/*" />
FUNCTION Flock(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea Flock()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fcount/*" />
FUNCTION FCount() AS DWORD
    RETURN VoDb.FCount()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fcount/*" />
FUNCTION FCount(uArea AS USUAL) AS DWORD
    DOINAREA uArea FCount()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldname/*" />
FUNCTION FieldName(dwFieldPos AS DWORD) AS STRING
    IF dwFieldPos > 0 .AND. dwFieldPos <= VoDb.FCount()
        RETURN VoDb.FieldName(dwFieldPos)
    ENDIF
    RETURN String.Empty

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldname/*" />
FUNCTION FieldName(dwFieldPos AS DWORD, uArea AS USUAL) AS STRING
    DOINAREA uArea FieldName(dwFieldPos)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldsym/*" />
FUNCTION FieldSym(dwFieldPos AS DWORD) AS SYMBOL
    IF dwFieldPos > 0 .AND. dwFieldPos <= VoDb.FCount()
        RETURN (SYMBOL) VoDb.FieldName(dwFieldPos)
    ENDIF
    RETURN NULL_SYMBOL

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldsym/*" />
FUNCTION FieldSym(dwFieldPos AS DWORD, uArea AS USUAL) AS SYMBOL
    DOINAREA uArea FieldSym(dwFieldPos)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldpos/*" />
FUNCTION FieldPos(cFieldName AS STRING) AS DWORD
    RETURN VoDb.FieldPos(cFieldName)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldpos/*" />
FUNCTION FieldPos(cFieldName AS STRING, nArea AS DWORD) AS DWORD
    LOCAL oRDD := RuntimeState.Workareas:GetRDD(nArea) AS IRdd
    IF oRDD != NULL_OBJECT
        RETURN (DWORD) oRDD:FieldIndex(cFieldName)
    ENDIF
    RETURN 0

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/found/*" />
FUNCTION Found() AS LOGIC
	RETURN VoDb.Found()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/found/*" />
FUNCTION Found(uArea AS USUAL) AS LOGIC
    DOINAREA uArea Found()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/header/*" />
FUNCTION Header() AS LONG
    LOCAL oValue := NULL AS OBJECT
    IF VoDb.Info(DBI_GETHEADERSIZE, REF oValue)
        RETURN Convert.ToInt32(oValue)
    ENDIF
    RETURN 0

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/header/*" />
FUNCTION Header(uArea AS USUAL) AS LONG
    DOINAREA uArea Header()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/lastrec/*" />
FUNCTION LastRec() AS DWORD
    RETURN (DWORD) VoDb.LastRec()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/lastrec/*" />
FUNCTION LastRec(uArea AS USUAL) AS DWORD
    DOINAREA uArea LastRec()

/// <summary>Refresh the buffer for the current workarea, discarding any changes that were made.</summary>
/// <returns>
/// </returns>
FUNCTION DbBuffRefresh() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.BuffRefresh())

FUNCTION DbBuffRefresh(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbBuffRefresh()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclearfilter/*" />
FUNCTION DbClearFilter() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.ClearFilter())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclearfilter/*" />
FUNCTION DbClearFilter(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbClearFilter()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclearrelation/*" />
FUNCTION DbClearRelation() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.ClearRelation())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclearrelation/*" />
FUNCTION DbClearRelation(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbClearRelation()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcloseall/*" />
FUNCTION DbCloseAll() AS LOGIC STRICT
	RETURN VoDb.CloseAll()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclosearea/*" />
FUNCTION DbCloseArea () AS LOGIC STRICT
	RETURN VoDb.CloseArea()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclosearea/*" />
FUNCTION DbCloseArea (uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbCloseArea()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcommit/*" />
FUNCTION DbCommit() AS LOGIC STRICT
	RETURN VoDb.Commit()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcommit/*" />
FUNCTION DbCommit(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbCommit()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcommitall/*" />
FUNCTION DbCommitAll() AS LOGIC STRICT
	RETURN VoDb.CommitAll()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcontinue/*" />
FUNCTION DbContinue(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbContinue()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcontinue/*" />
FUNCTION DbContinue() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Continue())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbdriver/*" />
FUNCTION DbDriver() AS STRING STRICT
	RETURN RddName()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbfilter/*" />
FUNCTION DbFilter() AS STRING STRICT
	RETURN VoDb.Filter()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbfilter/*" />
FUNCTION DbFilter(uArea AS USUAL) AS STRING STRICT
    DOINAREA uArea DbFilter()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbgetselect/*" />
FUNCTION DbGetSelect() AS DWORD STRICT
	RETURN VoDb.GetSelect()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbgobottom/*" />
FUNCTION DbGoBottom() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.GoBottom())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbgobottom/*" />
FUNCTION DbGoBottom(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbGoBottom()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbgotop/*" />
FUNCTION DbGoTop() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.GoTop())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbgotop/*" />
FUNCTION DbGoTop(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbGoTop()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rddname/*" />
FUNCTION RddName        () AS STRING STRICT
	LOCAL cRet      AS STRING
	IF Used()
		cRet := VoDb.RddName()
	ELSE
		cRet := RddSetDefault()
	ENDIF
	RETURN cRet

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rddsetdefault/*" />
FUNCTION RddSetDefault  () AS STRING STRICT
    RETURN VoDb.RddSetDefault(NULL_STRING)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rddsetdefault/*" />
FUNCTION RddSetDefault  (cNewSetting AS STRING) AS STRING
    RETURN VoDb.RddSetDefault(cNewSetting)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/reccount/*" />
FUNCTION RecCount() AS LONG
    RETURN VoDb.LastRec()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/reccount/*" />
FUNCTION RecCount(uArea AS USUAL) AS LONG
    DOINAREA uArea RecCount()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/recno/*" />
FUNCTION RecNo() AS DWORD
    RETURN VoDb.Recno()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/recno/*" />
FUNCTION RecNo(uArea AS USUAL) AS DWORD
    DOINAREA uArea RecNo()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/recsize/*" />
FUNCTION RecSize AS LONG
    RETURN VoDb.RecSize()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/recsize/*" />
FUNCTION RecSize(uArea AS USUAL) AS LONG
    DOINAREA uArea RecSize()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rlock/*" />
FUNCTION RLock() AS LOGIC STRICT
	RETURN VoDb.RLock(NULL)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rlock/*" />
FUNCTION RLock(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea RLock()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rlock/*" />
FUNCTION RLock(cRecordNumberList AS STRING, uArea AS USUAL) AS LOGIC STRICT
	LOCAL aRecords  AS STRING[]
    LOCAL nSelect   AS DWORD
    LOCAL lOk       AS LOGIC
    IF String.IsNullOrWhiteSpace(cRecordNumberList)
        RETURN FALSE
    ENDIF
    aRecords := cRecordNumberList:Split(<CHAR>{','},StringSplitOptions.RemoveEmptyEntries)
    nSelect := DbGetSelect()
    DbSelectArea(uArea)
    lOk := TRUE
    FOREACH VAR s IN aRecords
        IF Int32.TryParse(s, OUT VAR iRecno)
            IF ! VoDb.RLock(iRecno)
                lOk := FALSE
                EXIT
            ENDIF
        ELSE
            lOk := FALSE
            EXIT
        ENDIF
    NEXT
    DbSelectArea(nSelect)
    RETURN lOk

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/used/*" />
FUNCTION Used() AS LOGIC
    RETURN RuntimeState.Workareas:CurrentWorkarea != NULL

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/used/*" />
FUNCTION Used(uArea AS USUAL) AS LOGIC
    IF IsString(uArea) .OR. IsSymbol(uArea)
        RETURN VoDbGetSelect(uArea) != 0
    ENDIF
    RETURN Alias(uArea) != NULL_STRING

FUNCTION DoError (cSymFunc AS STRING, nTries:= 0 AS INT) AS OBJECT
	LOCAL oError    AS Error
    LOCAL bBlock    AS ICodeblock
    IF RuntimeState.LastRddError IS Error
	    oError         := (Error) RuntimeState.LastRddError
    ELSEIF RuntimeState.LastRddError != NULL_OBJECT
        oError         := Error{RuntimeState.LastRddError}
    ELSE
        oError  := Error{"Unknown Error occurred" }
    ENDIF
	oError:FuncSym := cSymFunc
    oError:Tries   := nTries
    bBlock := XSharp.RuntimeState.GetValue<ICodeblock>(Set.ErrorBlock)
    IF bBlock != NULL
	    RETURN bBlock:EvalBlock(oError)
    ENDIF
    THROW oError

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING XSharp
USING XSharp.RDD
USING XSharp.RDD.Enums
USING System.Collections.Generic
USING System.IO
USING System.Reflection
USING System.Linq
USING System.Text

#command DOINAREA <uArea> <func>  => ;
    LOCAL nArea := _Select(<uArea>)  AS DWORD ; ;
    IF nArea != 0; ;
        VAR nOld := RuntimeState.CurrentWorkarea; ;
        TRY ;  ;
            RuntimeState.CurrentWorkarea := nArea; ;
            RETURN <FUNC> ; ;
        FINALLY;  ;
            RuntimeState.CurrentWorkarea := nOld ; ;
        END TRY; ;
    ENDIF; ;
    THROW _NoAlias( <uArea> )

FUNCTION _NoAlias(uArea AS USUAL) AS Error
    VAR oErr := Error{EG_NOTABLE, "uArea", "Alias '"+uArea:ToString()+"' is not found"}
    oErr:FuncSym := ProcName(1):Replace("FUNCTIONS:","")
    RETURN oErr

/// <exclude />
FUNCTION _DbThrowErrorOnFailure(funcName AS STRING, resultToCheck AS LOGIC) AS LOGIC
    IF !resultToCheck
        resultToCheck := (LOGIC) DoError(funcName)
    ENDIF
    RETURN resultToCheck

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/alias0/*" />
FUNCTION Alias0() AS STRING
   LOCAL oRDD := VoDb.CWA("Alias0", FALSE) AS IRdd
    IF oRDD != NULL
        RETURN oRDD:Alias
    ENDIF
    RETURN String.Empty

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bof/*" />
FUNCTION Bof() AS LOGIC
   RETURN VoDb.Bof()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bof/*" />
FUNCTION Bof(uArea AS USUAL) AS LOGIC
    DOINAREA uArea Bof()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbf/*" />
FUNCTION DBF() AS STRING
    RETURN VoDb.Dbf()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbf/*" />
FUNCTION DBF(uArea AS USUAL) AS STRING
    DOINAREA uArea DBF()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbpack/*" />
FUNCTION DbPack() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Pack())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbpack/*" />
FUNCTION DbPack(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbPack()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbrecall/*" />
FUNCTION DbRecall() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Recall())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbrecall/*" />
FUNCTION DbRecall(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbRecall()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbunlock/*" />
FUNCTION DbUnLock() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Unlock(NULL_OBJECT))

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbunlock/*" />
FUNCTION DbUnLock(nRecord AS LONG) AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Unlock(nRecord))

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbzap/*" />
FUNCTION DbZap() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Zap())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbzap/*" />
FUNCTION DbZap(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbZap()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbunlockall/*" />
FUNCTION DbUnLockAll() AS LOGIC STRICT
	RETURN VoDb.UnlockAll()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/deleted/*" />
FUNCTION Deleted() AS LOGIC STRICT
	RETURN VoDb.Deleted()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/deleted/*" />
FUNCTION Deleted(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea Deleted()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/eof/*" />
FUNCTION Eof() AS LOGIC
   RETURN VoDb.Eof()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/eof/*" />
FUNCTION Eof(uArea AS USUAL) AS LOGIC
    DOINAREA uArea Eof()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/flock/*" />
FUNCTION Flock() AS LOGIC STRICT
	RETURN VoDb.Flock()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/flock/*" />
FUNCTION Flock(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea Flock()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fcount/*" />
FUNCTION FCount() AS DWORD
    RETURN VoDb.FCount()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fcount/*" />
FUNCTION FCount(uArea AS USUAL) AS DWORD
    DOINAREA uArea FCount()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldname/*" />
FUNCTION FieldName(dwFieldPos AS DWORD) AS STRING
    IF dwFieldPos > 0 .AND. dwFieldPos <= VoDb.FCount()
        RETURN VoDb.FieldName(dwFieldPos)
    ENDIF
    RETURN String.Empty

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldname/*" />
FUNCTION FieldName(dwFieldPos AS DWORD, uArea AS USUAL) AS STRING
    DOINAREA uArea FieldName(dwFieldPos)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldsym/*" />
FUNCTION FieldSym(dwFieldPos AS DWORD) AS SYMBOL
    IF dwFieldPos > 0 .AND. dwFieldPos <= VoDb.FCount()
        RETURN (SYMBOL) VoDb.FieldName(dwFieldPos)
    ENDIF
    RETURN NULL_SYMBOL

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldsym/*" />
FUNCTION FieldSym(dwFieldPos AS DWORD, uArea AS USUAL) AS SYMBOL
    DOINAREA uArea FieldSym(dwFieldPos)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldpos/*" />
FUNCTION FieldPos(cFieldName AS STRING) AS DWORD
    RETURN VoDb.FieldPos(cFieldName)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/fieldpos/*" />
FUNCTION FieldPos(cFieldName AS STRING, nArea AS DWORD) AS DWORD
    LOCAL oRDD := RuntimeState.Workareas:GetRDD(nArea) AS IRdd
    IF oRDD != NULL_OBJECT
        RETURN (DWORD) oRDD:FieldIndex(cFieldName)
    ENDIF
    RETURN 0

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/found/*" />
FUNCTION Found() AS LOGIC
	RETURN VoDb.Found()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/found/*" />
FUNCTION Found(uArea AS USUAL) AS LOGIC
    DOINAREA uArea Found()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/header/*" />
FUNCTION Header() AS LONG
    LOCAL oValue := NULL AS OBJECT
    IF VoDb.Info(DBI_GETHEADERSIZE, REF oValue)
        RETURN Convert.ToInt32(oValue)
    ENDIF
    RETURN 0

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/header/*" />
FUNCTION Header(uArea AS USUAL) AS LONG
    DOINAREA uArea Header()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/lastrec/*" />
FUNCTION LastRec() AS DWORD
    RETURN (DWORD) VoDb.LastRec()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/lastrec/*" />
FUNCTION LastRec(uArea AS USUAL) AS DWORD
    DOINAREA uArea LastRec()

/// <summary>Refresh the buffer for the current workarea, discarding any changes that were made.</summary>
/// <returns>
/// </returns>
FUNCTION DbBuffRefresh() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.BuffRefresh())

FUNCTION DbBuffRefresh(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbBuffRefresh()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclearfilter/*" />
FUNCTION DbClearFilter() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.ClearFilter())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclearfilter/*" />
FUNCTION DbClearFilter(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbClearFilter()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclearrelation/*" />
FUNCTION DbClearRelation() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.ClearRelation())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclearrelation/*" />
FUNCTION DbClearRelation(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbClearRelation()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcloseall/*" />
FUNCTION DbCloseAll() AS LOGIC STRICT
	RETURN VoDb.CloseAll()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclosearea/*" />
FUNCTION DbCloseArea () AS LOGIC STRICT
	RETURN VoDb.CloseArea()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbclosearea/*" />
FUNCTION DbCloseArea (uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbCloseArea()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcommit/*" />
FUNCTION DbCommit() AS LOGIC STRICT
	RETURN VoDb.Commit()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcommit/*" />
FUNCTION DbCommit(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbCommit()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcommitall/*" />
FUNCTION DbCommitAll() AS LOGIC STRICT
	RETURN VoDb.CommitAll()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcontinue/*" />
FUNCTION DbContinue(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbContinue()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbcontinue/*" />
FUNCTION DbContinue() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.Continue())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbdriver/*" />
FUNCTION DbDriver() AS STRING STRICT
	RETURN RddName()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbfilter/*" />
FUNCTION DbFilter() AS STRING STRICT
	RETURN VoDb.Filter()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbfilter/*" />
FUNCTION DbFilter(uArea AS USUAL) AS STRING STRICT
    DOINAREA uArea DbFilter()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbgetselect/*" />
FUNCTION DbGetSelect() AS DWORD STRICT
	RETURN VoDb.GetSelect()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbgobottom/*" />
FUNCTION DbGoBottom() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.GoBottom())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbgobottom/*" />
FUNCTION DbGoBottom(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbGoBottom()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbgotop/*" />
FUNCTION DbGoTop() AS LOGIC STRICT
	RETURN _DbThrowErrorOnFailure(__FUNCTION__, VoDb.GoTop())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dbgotop/*" />
FUNCTION DbGoTop(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea DbGoTop()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rddname/*" />
FUNCTION RddName        () AS STRING STRICT
	LOCAL cRet      AS STRING
	IF Used()
		cRet := VoDb.RddName()
	ELSE
		cRet := RddSetDefault()
	ENDIF
	RETURN cRet

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rddsetdefault/*" />
FUNCTION RddSetDefault  () AS STRING STRICT
    RETURN VoDb.RddSetDefault(NULL_STRING)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rddsetdefault/*" />
FUNCTION RddSetDefault  (cNewSetting AS STRING) AS STRING
    RETURN VoDb.RddSetDefault(cNewSetting)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/reccount/*" />
FUNCTION RecCount() AS LONG
    RETURN VoDb.LastRec()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/reccount/*" />
FUNCTION RecCount(uArea AS USUAL) AS LONG
    DOINAREA uArea RecCount()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/recno/*" />
FUNCTION RecNo() AS DWORD
    RETURN VoDb.Recno()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/recno/*" />
FUNCTION RecNo(uArea AS USUAL) AS DWORD
    DOINAREA uArea RecNo()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/recsize/*" />
FUNCTION RecSize AS LONG
    RETURN VoDb.RecSize()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/recsize/*" />
FUNCTION RecSize(uArea AS USUAL) AS LONG
    DOINAREA uArea RecSize()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rlock/*" />
FUNCTION RLock() AS LOGIC STRICT
	RETURN VoDb.RLock(NULL)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rlock/*" />
FUNCTION RLock(uArea AS USUAL) AS LOGIC STRICT
    DOINAREA uArea RLock()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rlock/*" />
FUNCTION RLock(cRecordNumberList AS STRING, uArea AS USUAL) AS LOGIC STRICT
	LOCAL aRecords  AS STRING[]
    LOCAL nSelect   AS DWORD
    LOCAL lOk       AS LOGIC
    IF String.IsNullOrWhiteSpace(cRecordNumberList)
        RETURN FALSE
    ENDIF
    aRecords := cRecordNumberList:Split(<CHAR>{','},StringSplitOptions.RemoveEmptyEntries)
    nSelect := DbGetSelect()
    DbSelectArea(uArea)
    lOk := TRUE
    FOREACH VAR s IN aRecords
        IF Int32.TryParse(s, OUT VAR iRecno)
            IF ! VoDb.RLock(iRecno)
                lOk := FALSE
                EXIT
            ENDIF
        ELSE
            lOk := FALSE
            EXIT
        ENDIF
    NEXT
    DbSelectArea(nSelect)
    RETURN lOk

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/used/*" />
FUNCTION Used() AS LOGIC
    RETURN RuntimeState.Workareas:CurrentWorkarea != NULL

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/used/*" />
FUNCTION Used(uArea AS USUAL) AS LOGIC
    IF IsString(uArea) .OR. IsSymbol(uArea)
        RETURN VoDbGetSelect(uArea) != 0
    ENDIF
    RETURN Alias(uArea) != NULL_STRING

FUNCTION DoError (cSymFunc AS STRING, nTries:= 0 AS INT) AS OBJECT
	LOCAL oError    AS Error
    LOCAL bBlock    AS ICodeblock
    IF RuntimeState.LastRddError IS Error
	    oError         := (Error) RuntimeState.LastRddError
    ELSEIF RuntimeState.LastRddError != NULL_OBJECT
        oError         := Error{RuntimeState.LastRddError}
    ELSE
        oError  := Error{"Unknown Error occurred" }
    ENDIF
	oError:FuncSym := cSymFunc
    oError:Tries   := nTries
    bBlock := XSharp.RuntimeState.GetValue<ICodeblock>(Set.ErrorBlock)
    IF bBlock != NULL
	    RETURN bBlock:EvalBlock(oError)
    ENDIF
    THROW oError


WED now writes static defines

WED now writes static defines

USING System.Collections.Generic
USING System.Windows.Forms
USING System.IO
USING Xide

BEGIN NAMESPACE XSharp.VOEditors
CLASS XSharp_VOWindowEditor INHERIT VOWindowEditor
	PROTECT oXProject as XSharpModel.XProject
	PROTECT aStylesUsed as List<String>		// List of styles used in this window
	CONSTRUCTOR(_oSurface AS Control , _oOptions AS WindowDesignerOptions , _oGrid AS DesignerGrid , _oToolBox AS ToolBox)
		SUPER(_oSurface , _oOptions , _oGrid , _oToolBox)
		aStylesUsed := List<String>{}
	RETURN

	METHOD AddStyles(aStyles as STRING[]) AS VOID
		FOREACH cStyle as STRING IN aStyles
			IF !aStylesUsed:Contains(cStyle)
				aStylesUsed:Add(cStyle)
			ENDIF
		NEXT
		RETURN

	PROTECTED VIRTUAL METHOD CreateControl(cControl AS STRING, oParent AS Control , cGuid AS STRING) AS DesignWindowItem
		LOCAL oItem AS XSharpDesignWindowItem
		// Use our own DesignWindowItem so we can collect the list of styles used
		oItem := XSharpDesignWindowItem{SELF , VOWindowEditorTemplate.Get(cControl)}
		IF String.IsNullOrEmpty(cGuid)
			cGuid := Guid.NewGuid():ToString()
		ENDIF
		oItem:cGuid := cGuid
		oParent:Controls:Add(oItem:Control)

		IF oItem:IsForm
			SELF:oWindowDesign	:= oItem
			SELF:oWindow		:= oItem:Control
		ENDIF

		IF oItem:Column != NULL
			oParent:Controls:Add(oItem:Column)
		END IF
		IF SELF:ViewMode == ViewMode.Browse
			oItem:lBrowseView := TRUE
			oItem:Control:Hide()
		ELSE
			IF oItem:Column != NULL_OBJECT
				oItem:Column:Hide()
			END IF
		ENDIF
	RETURN oItem

	METHOD Open(cFileName as STRING) as LOGIC
		VAR oFile := XSharpModel.XSolution.FindFile(cFileName)
		if (oFile != NULL_OBJECT)
			oXProject := oFile:Project
		endif
		if oXProject == NULL
			XFuncs.ErrorBox("Cannot find project for file "+cFileName)
			RETURN FALSE
		ENDIF
		RETURN SUPER:Open(cFileName)

	PROTECTED METHOD GetSaveFileStreams(cVNFrmFileName AS STRING , oVNFrmStream REF FileStream , ;
								oRCStream AS EditorStream , oPrgStream AS EditorStream , oVhStream AS EditorStream , ;
								cVhName REF STRING , lVnfrmOnly AS LOGIC , lRcInSameFolder REF LOGIC) AS LOGIC
		LOCAL cRCFileName AS STRING
		LOCAL cPrgFileName AS STRING
		LOCAL cHeaderFile AS STRING
		LOCAL cFileName AS STRING
		LOCAL cBaseName AS STRING
		LOCAL oFileInfo AS FileInfo
		LOCAL oBaseDir AS DirectoryInfo
		LOCAL cBaseDir AS STRING
		LOCAL cAlternative AS STRING
		LOCAL lSuccess AS LOGIC
		LOCAL lError AS LOGIC
		LOCAL nAt AS INT

		TRY

			oFileInfo	:= FileInfo{cVNFrmFileName}
			oBaseDir	:= oFileInfo:Directory
			cBaseDir	:= oBaseDir:FullName
			cBaseName	:= oFileInfo:Name

			IF cBaseName:ToLower():Endswith(".vnfrm") .or. cBaseName:ToLower():Endswith(".xsfrm")
				cBaseName	:= System.IO.Path.GetFileNameWithoutExtension(cBaseName)
			ENDIF
			cRCFileName		:= cBaseDir + "\Resources\" + cBaseName + ".rc"
			cAlternative	:= cBaseDir + "\" + cBaseName + ".rc"
			IF !File.Exists(cRCFileName) .and. File.Exists(cAlternative)
				cRCFileName := cAlternative
				lRcInSameFolder := TRUE
			ENDIF

			cFileName	:= cBaseName
			nAt			:= cFileName:LastIndexOf('.')
			IF nAt != -1 // strip out window name
				cFileName := cFileName:Substring(0 , nAt)
			ENDIF
			cPrgFileName := cBaseDir + "\" + cFileName + ".prg"
			cHeaderFile  := System.IO.Path.ChangeExtension(cPrgFileName, ".vh")
			IF !File.Exists(cHeaderFile)
				cHeaderFile  := System.IO.Path.ChangeExtension(cHeaderFile, ".xh")
			ENDIF
			cAlternative := oBaseDir:Parent:FullName + "\" + cFileName + ".prg"
			IF !File.Exists(cPrgFileName)
				cPrgFileName := cAlternative
				cHeaderFile  := System.IO.Path.ChangeExtension(cPrgFileName, ".vh")
				IF !File.Exists(cHeaderFile)
					cHeaderFile  := System.IO.Path.ChangeExtension(cHeaderFile, ".xh")
				ENDIF
			ENDIF
			cVhName := System.IO.Path.GetFileName(cHeaderFile)

			lError := FALSE
			IF !lVnfrmOnly
				if ! File.Exists(cRCFileName)
					cRCFileName := System.IO.Path.ChangeExtension(cVNFrmFileName, ".rc")
				endif
				XFuncs.EnsureFileNodeExists(oXProject, cRCFileName)
				IF !File.Exists(cPrgFileName)
					XFuncs.ErrorBox("File was not found : " + cPrgFileName)
					lError := TRUE
				END IF
			END IF

			lSuccess := FALSE
			IF !lError
				IF !lVnfrmOnly
					oRCStream:Load(cRCFileName)
					oPrgStream:Load(cPrgFileName)
					IF File.Exists(cHeaderFile) // else old transporter version
						oVhStream:Load(cHeaderFile)
					ENDIF
					lSuccess := oRCStream:IsValid .and. oPrgStream:IsValid
				ELSE
					lSuccess := TRUE
				END IF
			END IF
			IF lSuccess .and. !lError
				lSuccess := FALSE
				oVNFrmStream := File.Open(cVNFrmFileName , FileMode.Create , FileAccess.Write , FileShare.None)
				lSuccess := TRUE
			ENDIF

		CATCH e AS Exception

			XFuncs.WarningBox(e:Message )
			lSuccess := FALSE

		END TRY

		IF !lSuccess
			IF oVNFrmStream != NULL
				oVNFrmStream:Close()
			ENDIF
			IF oRCStream:IsValid
				oRCStream:Close()
			ENDIF
			IF oPrgStream:IsValid
				oPrgStream:Close()
			ENDIF
			IF oVhStream:IsValid
				oVhStream:Close()
			ENDIF
		END IF

	RETURN lSuccess

	VIRTUAL METHOD Save() AS VOID
		SELF:Save(SELF:cDefaultFileName , FALSE)

	VIRTUAL METHOD Save(cVNFrmFileName AS STRING , lBinaryOnly AS LOGIC) AS LOGIC
		LOCAL oPrg , oVh  , oRC AS XSharp_EditorStream
		LOCAL lRcInSameFolder AS LOGIC
		LOCAL lOldTransporter AS LOGIC
		LOCAL oVNFrm AS FileStream
		LOCAL cVhName AS STRING

		IF cVNFrmFileName:ToUpper():Contains("~AUTORECOVER")
			lBinaryOnly := TRUE
		END IF

		SELF:ArrangeColumnsOrder(TRUE)
		SELF:ArrangeControlOrder()

		oPrg := XSharp_EditorStream{}
		oVh := XSharp_EditorStream{}
		oRc := XSharp_EditorStream{}

		oVNFrm := NULL; cVhName := NULL; lRcInSameFolder := FALSE // Grrr
		IF .not. SELF:GetSaveFileStreams(cVNFrmFileName , oVNFrm , oRC , oPrg , oVh , REF cVhName , lBinaryOnly , REF lRcInSameFolder)
			RETURN FALSE
		ENDIF

		lOldTransporter := .not. oVh:IsValid

		SELF:SaveToXml(oVNFrm)

		IF .not. lBinaryOnly
			LOCAL oCode AS CodeContents
			oCode := SELF:GetCodeContents()

			SELF:SaveRC(oRC , oCode , cVhName , lOldTransporter , lRcInSameFolder)

			IF oVh:IsValid
				SELF:SaveVh(oVh , oCode)
			END IF

			SELF:SavePrg(oPrg , oCode , lOldTransporter , cVhName)

			SELF:nActionSaved := SELF:nAction
		END IF

	RETURN TRUE

	METHOD SaveRC(oStream AS XSharp_EditorStream , oCode AS CodeContents , cVhName AS STRING , lOldTransporter AS LOGIC , lRcInSameFolder AS LOGIC) AS LOGIC
		LOCAL oGenerator AS CodeGenerator
		oGenerator := CodeGenerator{oStream:Editor}
		oGenerator:BeginCode(TRUE)

		oGenerator:Clear()
		XFuncs.WriteHeader(oGenerator, "XSharp.FormEditor")
		// in x#, always add the #defines in the .rc header, no need to put them in a .vh anymore
		FOR LOCAL n := 0 UPTO oCode:aDefines:Count - 1
			oGenerator:AddDefine(oCode:aDefines[n] , oCode:aDefineValues[n])
		NEXT
		// Write the styles that are used in Alphabetical order
		aStylesUsed:Sort()
		FOREACH cStyle as STRING in SELF:aStylesUsed
			oGenerator:AddDefine(cStyle, "0x"+VODefines.GetDefineValue(cStyle):ToString("X8"))
		NEXT
		oGenerator:AddLine("")
		FOREACH cResource as STRING IN oCode:aResource
			oGenerator:AddLine(cResource)
		NEXT
		oStream:Save()
	RETURN TRUE

	METHOD SavePrg(oDest AS XSharp_EditorStream , oCode AS CodeContents , lOldTransporter AS LOGIC , cVhName AS STRING) AS LOGIC
		LOCAL aEntity AS List<STRING>
		LOCAL cFormName AS STRING
		LOCAL cPrevName AS STRING

		LOCAL oGenerator AS CodeGenerator
		oGenerator := CodeGenerator{oDest:Editor}
		oGenerator:BeginCode(TRUE)

		LOCAL ceTab AS STRING
		ceTab := ""

		cFormName := SELF:oWindowDesign:Name
		// needed for renaming a window:
		cPrevName := SELF:oWindowDesign:Name

		// don't delete the header file for now, maybe the .vh file contains defines for other windows in the same prg
		oGenerator:DeleteDefines(oCode:aDefines)
		oGenerator:AddXSharpDefines(oCode:aDefines , oCode:aDefineValues,TRUE)

		oGenerator:WriteEntity(EntityType._Class , cPrevName , cPrevName , EntityOptions.AddUser , oCode:aClass)
		oGenerator:WriteEntity(EntityType._Constructor , cFormName , cFormName , EntityOptions.None , oCode:aConstructor)

		LOCAL lAccessAssign AS LOGIC
		LOCAL oProp AS DesignProperty

		aEntity := List<STRING>{}

		oProp := SELF:oWindowDesign:GetPropertyByMember("NoAcc")
		lAccessAssign := oProp != NULL .and. oProp:TextValue:Trim() == "" .and. oProp:cPage != "_Hidden"
		FOREACH cName as STRING in oCode:aAccessAssign

			IF lAccessAssign
				aEntity:Clear()
				aEntity:Add(ceTab + "ACCESS " + cName)
				aEntity:Add(ceTab + "RETURN SELF:FieldGet( #" + cName + " )")
				oGenerator:WriteEntity(EntityType._Access , cName , cFormName , EntityOptions.None , aEntity)

				aEntity:Clear()
				aEntity:Add(ceTab + "ASSIGN " + cName + "( uValue )")
				aEntity:Add(ceTab + "SELF:FieldPut( #" + cName + " , uValue )")
				oGenerator:WriteEntity(EntityType._Assign , cName , cFormName , EntityOptions.None , aEntity)

			ELSE
				oGenerator:DeleteEntity(EntityType._Access , cName , cFormName)
				oGenerator:DeleteEntity(EntityType._Assign , cName , cFormName)
			END IF
		NEXT

		oGenerator:WriteEndClass(cFormName)
		oGenerator:EndCode()
	RETURN oDest:Save()

	METHOD SaveVh(oStream AS XSharp_EditorStream , oCode AS CodeContents) AS LOGIC
		LOCAL oGenerator AS CodeGenerator
		oGenerator := CodeGenerator{oStream:Editor}
		oGenerator:BeginCode(TRUE)

		oGenerator:DeleteDefines(oCode:aDefines)

		oStream:Save()
	RETURN TRUE

	// The following is the original vulcan code which generates callbacks in the code
	// Always generates the code directly in a VS editor file
	// Of course needs adjustment to work with x#'s project system

	ACCESS XFile AS XSharpModel.XFile
		LOCAL cPrgFileName AS STRING
		cPrgFileName := Funcs.GetModuleFilenameFromBinary(SELF:cDefaultFileName) + ".prg"
	RETURN XSharpModel.XSolution.FindFile(cPrgFileName)

	PROTECTED VIRTUAL METHOD WriteCallback(oDesign AS DesignWindowItem , cName AS STRING) AS VOID
		LOCAL oProject AS XSharpModel.XProject
		LOCAL oFile AS XSharpModel.XFile
		LOCAL oType AS XSharpModel.XType
		//LOCAL oEditor AS VulcanEditor
		LOCAL aLines AS List<STRING>
		LOCAL cClass AS STRING
		LOCAL lOpen AS LOGIC

		cClass := SELF:oWindowDesign:Name

		oFile := SELF:XFile
		IF oFile == NULL
			RETURN
		END IF
		oProject := oFile:Project

		IF cName == "Click"
			cName := oDesign:Name
			aLines := List<STRING>{}
			aLines:Add("METHOD " + cName + "( )")
			aLines:Add("")
			aLines:Add("RETURN NIL")
		ELSE
			aLines := GetTemplate(cName)
		END IF
		IF aLines == NULL
			XFuncs.WarningBox("Could not find code template for event: " + cName)
			RETURN
		END IF
		// Find Method for this class
	    var rootNs := oFile:Project:ProjectNode:RootNameSpace
		oType := oProject:Lookup(cClass,true)
		if oType == NULL_OBJECT
			oType := oProject:Lookup(rootNs+"."+cClass,true)
		ENDIF
		IF cName:ToUpper() == "CLASSDECLARATION"
	        IF (oType != NULL_OBJECT)
				oType:OpenEditor()
	            RETURN
	        ENDIF

        ELSEIF oType != NULL_OBJECT
			FOREACH VAR oMember in oType:Members
				if string.Compare(oMember:Name, cName, TRUE) == 0
					oMember:OpenEditor()
					RETURN
				endif
			NEXT
        ENDIF
		lOpen := FALSE
		var source := oProject:ProjectNode:DocumentGetText(oFile:FullPath, ref lOpen)

		IF .not. lOpen
			oProject:ProjectNode:OpenElement(oFile:FullPath, 1,1)
		END IF
		source := oProject:ProjectNode:DocumentGetText(oFile:FullPath, ref lOpen)
		IF .not. lOpen
			RETURN
		END IF

		VAR oEditor := XSharp_EditorStream{}
		oEditor:Load(oFile:FullPath)
		VAR nLine := oType:Range:EndLine -1
		aLines:Reverse()
		FOREACH VAR cLine in aLines
			VAR cNew := VOWindowEditor.SubStituteTpl(cLine, cClass, oWindowDesign:cInitMethod)
			oFile:Project:ProjectNode:DocumentInsertLine(oFile:FullPath, nLine, cNew)
		NEXT
		oFile:Project:ProjectNode:OpenElement(oFile:FullPath, nLine,1)
		XSharpModel.XSolution.WalkFile(oFile:FullPath)
	RETURN

END CLASS

END NAMESPACE

USING System.Collections.Generic
USING System.Windows.Forms
USING System.IO
USING Xide

BEGIN NAMESPACE XSharp.VOEditors
CLASS XSharp_VOWindowEditor INHERIT VOWindowEditor
	PROTECT oXProject as XSharpModel.XProject
	PROTECT aStylesUsed as List<String>		// List of styles used in this window
	CONSTRUCTOR(_oSurface AS Control , _oOptions AS WindowDesignerOptions , _oGrid AS DesignerGrid , _oToolBox AS ToolBox)
		SUPER(_oSurface , _oOptions , _oGrid , _oToolBox)
		aStylesUsed := List<String>{}
	RETURN

	METHOD AddStyles(aStyles as STRING[]) AS VOID
		FOREACH cStyle as STRING IN aStyles
			IF !aStylesUsed:Contains(cStyle)
				aStylesUsed:Add(cStyle)
			ENDIF
		NEXT
		RETURN

	PROTECTED VIRTUAL METHOD CreateControl(cControl AS STRING, oParent AS Control , cGuid AS STRING) AS DesignWindowItem
		LOCAL oItem AS XSharpDesignWindowItem
		// Use our own DesignWindowItem so we can collect the list of styles used
		oItem := XSharpDesignWindowItem{SELF , VOWindowEditorTemplate.Get(cControl)}
		IF String.IsNullOrEmpty(cGuid)
			cGuid := Guid.NewGuid():ToString()
		ENDIF
		oItem:cGuid := cGuid
		oParent:Controls:Add(oItem:Control)

		IF oItem:IsForm
			SELF:oWindowDesign	:= oItem
			SELF:oWindow		:= oItem:Control
		ENDIF

		IF oItem:Column != NULL
			oParent:Controls:Add(oItem:Column)
		END IF
		IF SELF:ViewMode == ViewMode.Browse
			oItem:lBrowseView := TRUE
			oItem:Control:Hide()
		ELSE
			IF oItem:Column != NULL_OBJECT
				oItem:Column:Hide()
			END IF
		ENDIF
	RETURN oItem

	METHOD Open(cFileName as STRING) as LOGIC
		VAR oFile := XSharpModel.XSolution.FindFile(cFileName)
		if (oFile != NULL_OBJECT)
			oXProject := oFile:Project
		endif
		if oXProject == NULL
			XFuncs.ErrorBox("Cannot find project for file "+cFileName)
			RETURN FALSE
		ENDIF
		RETURN SUPER:Open(cFileName)

	PROTECTED METHOD GetSaveFileStreams(cVNFrmFileName AS STRING , oVNFrmStream REF FileStream , ;
								oRCStream AS EditorStream , oPrgStream AS EditorStream , oVhStream AS EditorStream , ;
								cVhName REF STRING , lVnfrmOnly AS LOGIC , lRcInSameFolder REF LOGIC) AS LOGIC
		LOCAL cRCFileName AS STRING
		LOCAL cPrgFileName AS STRING
		LOCAL cHeaderFile AS STRING
		LOCAL cFileName AS STRING
		LOCAL cBaseName AS STRING
		LOCAL oFileInfo AS FileInfo
		LOCAL oBaseDir AS DirectoryInfo
		LOCAL cBaseDir AS STRING
		LOCAL cAlternative AS STRING
		LOCAL lSuccess AS LOGIC
		LOCAL lError AS LOGIC
		LOCAL nAt AS INT

		TRY

			oFileInfo	:= FileInfo{cVNFrmFileName}
			oBaseDir	:= oFileInfo:Directory
			cBaseDir	:= oBaseDir:FullName
			cBaseName	:= oFileInfo:Name

			IF cBaseName:ToLower():Endswith(".vnfrm") .or. cBaseName:ToLower():Endswith(".xsfrm")
				cBaseName	:= System.IO.Path.GetFileNameWithoutExtension(cBaseName)
			ENDIF
			cRCFileName		:= cBaseDir + "\Resources\" + cBaseName + ".rc"
			cAlternative	:= cBaseDir + "\" + cBaseName + ".rc"
			IF !File.Exists(cRCFileName) .and. File.Exists(cAlternative)
				cRCFileName := cAlternative
				lRcInSameFolder := TRUE
			ENDIF

			cFileName	:= cBaseName
			nAt			:= cFileName:LastIndexOf('.')
			IF nAt != -1 // strip out window name
				cFileName := cFileName:Substring(0 , nAt)
			ENDIF
			cPrgFileName := cBaseDir + "\" + cFileName + ".prg"
			cHeaderFile  := System.IO.Path.ChangeExtension(cPrgFileName, ".vh")
			IF !File.Exists(cHeaderFile)
				cHeaderFile  := System.IO.Path.ChangeExtension(cHeaderFile, ".xh")
			ENDIF
			cAlternative := oBaseDir:Parent:FullName + "\" + cFileName + ".prg"
			IF !File.Exists(cPrgFileName)
				cPrgFileName := cAlternative
				cHeaderFile  := System.IO.Path.ChangeExtension(cPrgFileName, ".vh")
				IF !File.Exists(cHeaderFile)
					cHeaderFile  := System.IO.Path.ChangeExtension(cHeaderFile, ".xh")
				ENDIF
			ENDIF
			cVhName := System.IO.Path.GetFileName(cHeaderFile)

			lError := FALSE
			IF !lVnfrmOnly
				if ! File.Exists(cRCFileName)
					cRCFileName := System.IO.Path.ChangeExtension(cVNFrmFileName, ".rc")
				endif
				XFuncs.EnsureFileNodeExists(oXProject, cRCFileName)
				IF !File.Exists(cPrgFileName)
					XFuncs.ErrorBox("File was not found : " + cPrgFileName)
					lError := TRUE
				END IF
			END IF

			lSuccess := FALSE
			IF !lError
				IF !lVnfrmOnly
					oRCStream:Load(cRCFileName)
					oPrgStream:Load(cPrgFileName)
					IF File.Exists(cHeaderFile) // else old transporter version
						oVhStream:Load(cHeaderFile)
					ENDIF
					lSuccess := oRCStream:IsValid .and. oPrgStream:IsValid
				ELSE
					lSuccess := TRUE
				END IF
			END IF
			IF lSuccess .and. !lError
				lSuccess := FALSE
				oVNFrmStream := File.Open(cVNFrmFileName , FileMode.Create , FileAccess.Write , FileShare.None)
				lSuccess := TRUE
			ENDIF

		CATCH e AS Exception

			XFuncs.WarningBox(e:Message )
			lSuccess := FALSE

		END TRY

		IF !lSuccess
			IF oVNFrmStream != NULL
				oVNFrmStream:Close()
			ENDIF
			IF oRCStream:IsValid
				oRCStream:Close()
			ENDIF
			IF oPrgStream:IsValid
				oPrgStream:Close()
			ENDIF
			IF oVhStream:IsValid
				oVhStream:Close()
			ENDIF
		END IF

	RETURN lSuccess

	VIRTUAL METHOD Save() AS VOID
		SELF:Save(SELF:cDefaultFileName , FALSE)

	VIRTUAL METHOD Save(cVNFrmFileName AS STRING , lBinaryOnly AS LOGIC) AS LOGIC
		LOCAL oPrg , oVh  , oRC AS XSharp_EditorStream
		LOCAL lRcInSameFolder AS LOGIC
		LOCAL lOldTransporter AS LOGIC
		LOCAL oVNFrm AS FileStream
		LOCAL cVhName AS STRING

		IF cVNFrmFileName:ToUpper():Contains("~AUTORECOVER")
			lBinaryOnly := TRUE
		END IF

		SELF:ArrangeColumnsOrder(TRUE)
		SELF:ArrangeControlOrder()

		oPrg := XSharp_EditorStream{}
		oVh := XSharp_EditorStream{}
		oRc := XSharp_EditorStream{}

		oVNFrm := NULL; cVhName := NULL; lRcInSameFolder := FALSE // Grrr
		IF .not. SELF:GetSaveFileStreams(cVNFrmFileName , oVNFrm , oRC , oPrg , oVh , REF cVhName , lBinaryOnly , REF lRcInSameFolder)
			RETURN FALSE
		ENDIF

		lOldTransporter := .not. oVh:IsValid

		SELF:SaveToXml(oVNFrm)

		IF .not. lBinaryOnly
			LOCAL oCode AS CodeContents
			oCode := SELF:GetCodeContents()

			SELF:SaveRC(oRC , oCode , cVhName , lOldTransporter , lRcInSameFolder)

			IF oVh:IsValid
				SELF:SaveVh(oVh , oCode)
			END IF

			SELF:SavePrg(oPrg , oCode , lOldTransporter , cVhName)

			SELF:nActionSaved := SELF:nAction
		END IF

	RETURN TRUE

	METHOD SaveRC(oStream AS XSharp_EditorStream , oCode AS CodeContents , cVhName AS STRING , lOldTransporter AS LOGIC , lRcInSameFolder AS LOGIC) AS LOGIC
		LOCAL oGenerator AS CodeGenerator
		oGenerator := CodeGenerator{oStream:Editor}
		oGenerator:BeginCode(TRUE)

		oGenerator:Clear()
		XFuncs.WriteHeader(oGenerator, "XSharp.FormEditor")
		// in x#, always add the #defines in the .rc header, no need to put them in a .vh anymore
		FOR LOCAL n := 0 UPTO oCode:aDefines:Count - 1
			oGenerator:AddDefine(oCode:aDefines[n] , oCode:aDefineValues[n])
		NEXT
		// Write the styles that are used in Alphabetical order
		aStylesUsed:Sort()
		FOREACH cStyle as STRING in SELF:aStylesUsed
			oGenerator:AddDefine(cStyle, "0x"+VODefines.GetDefineValue(cStyle):ToString("X8"))
		NEXT
		oGenerator:AddLine("")
		FOREACH cResource as STRING IN oCode:aResource
			oGenerator:AddLine(cResource)
		NEXT
		oStream:Save()
	RETURN TRUE

	METHOD SavePrg(oDest AS XSharp_EditorStream , oCode AS CodeContents , lOldTransporter AS LOGIC , cVhName AS STRING) AS LOGIC
		LOCAL aEntity AS List<STRING>
		LOCAL cFormName AS STRING
		LOCAL cPrevName AS STRING

		LOCAL oGenerator AS CodeGenerator
		oGenerator := CodeGenerator{oDest:Editor}
		oGenerator:BeginCode(TRUE)

		LOCAL ceTab AS STRING
		ceTab := ""

		cFormName := SELF:oWindowDesign:Name
		// needed for renaming a window:
		cPrevName := SELF:oWindowDesign:Name

		// don't delete the header file for now, maybe the .vh file contains defines for other windows in the same prg
		oGenerator:DeleteDefines(oCode:aDefines)
		oGenerator:AddXSharpDefines(oCode:aDefines , oCode:aDefineValues)

		oGenerator:WriteEntity(EntityType._Class , cPrevName , cPrevName , EntityOptions.AddUser , oCode:aClass)
		oGenerator:WriteEntity(EntityType._Constructor , cFormName , cFormName , EntityOptions.None , oCode:aConstructor)

		LOCAL lAccessAssign AS LOGIC
		LOCAL oProp AS DesignProperty

		aEntity := List<STRING>{}

		oProp := SELF:oWindowDesign:GetPropertyByMember("NoAcc")
		lAccessAssign := oProp != NULL .and. oProp:TextValue:Trim() == "" .and. oProp:cPage != "_Hidden"
		FOREACH cName as STRING in oCode:aAccessAssign

			IF lAccessAssign
				aEntity:Clear()
				aEntity:Add(ceTab + "ACCESS " + cName)
				aEntity:Add(ceTab + "RETURN SELF:FieldGet( #" + cName + " )")
				oGenerator:WriteEntity(EntityType._Access , cName , cFormName , EntityOptions.None , aEntity)

				aEntity:Clear()
				aEntity:Add(ceTab + "ASSIGN " + cName + "( uValue )")
				aEntity:Add(ceTab + "SELF:FieldPut( #" + cName + " , uValue )")
				oGenerator:WriteEntity(EntityType._Assign , cName , cFormName , EntityOptions.None , aEntity)

			ELSE
				oGenerator:DeleteEntity(EntityType._Access , cName , cFormName)
				oGenerator:DeleteEntity(EntityType._Assign , cName , cFormName)
			END IF
		NEXT

		oGenerator:WriteEndClass(cFormName)
		oGenerator:EndCode()
	RETURN oDest:Save()

	METHOD SaveVh(oStream AS XSharp_EditorStream , oCode AS CodeContents) AS LOGIC
		LOCAL oGenerator AS CodeGenerator
		oGenerator := CodeGenerator{oStream:Editor}
		oGenerator:BeginCode(TRUE)

		oGenerator:DeleteDefines(oCode:aDefines)

		oStream:Save()
	RETURN TRUE

	// The following is the original vulcan code which generates callbacks in the code
	// Always generates the code directly in a VS editor file
	// Of course needs adjustment to work with x#'s project system

	ACCESS XFile AS XSharpModel.XFile
		LOCAL cPrgFileName AS STRING
		cPrgFileName := Funcs.GetModuleFilenameFromBinary(SELF:cDefaultFileName) + ".prg"
	RETURN XSharpModel.XSolution.FindFile(cPrgFileName)

	PROTECTED VIRTUAL METHOD WriteCallback(oDesign AS DesignWindowItem , cName AS STRING) AS VOID
		LOCAL oProject AS XSharpModel.XProject
		LOCAL oFile AS XSharpModel.XFile
		LOCAL oType AS XSharpModel.XType
		//LOCAL oEditor AS VulcanEditor
		LOCAL aLines AS List<STRING>
		LOCAL cClass AS STRING
		LOCAL lOpen AS LOGIC

		cClass := SELF:oWindowDesign:Name

		oFile := SELF:XFile
		IF oFile == NULL
			RETURN
		END IF
		oProject := oFile:Project

		IF cName == "Click"
			cName := oDesign:Name
			aLines := List<STRING>{}
			aLines:Add("METHOD " + cName + "( )")
			aLines:Add("")
			aLines:Add("RETURN NIL")
		ELSE
			aLines := GetTemplate(cName)
		END IF
		IF aLines == NULL
			XFuncs.WarningBox("Could not find code template for event: " + cName)
			RETURN
		END IF
		// Find Method for this class
	    var rootNs := oFile:Project:ProjectNode:RootNameSpace
		oType := oProject:Lookup(cClass,true)
		if oType == NULL_OBJECT
			oType := oProject:Lookup(rootNs+"."+cClass,true)
		ENDIF
		IF cName:ToUpper() == "CLASSDECLARATION"
	        IF (oType != NULL_OBJECT)
				oType:OpenEditor()
	            RETURN
	        ENDIF

        ELSEIF oType != NULL_OBJECT
			FOREACH VAR oMember in oType:Members
				if string.Compare(oMember:Name, cName, TRUE) == 0
					oMember:OpenEditor()
					RETURN
				endif
			NEXT
        ENDIF
		lOpen := FALSE
		var source := oProject:ProjectNode:DocumentGetText(oFile:FullPath, ref lOpen)

		IF .not. lOpen
			oProject:ProjectNode:OpenElement(oFile:FullPath, 1,1)
		END IF
		source := oProject:ProjectNode:DocumentGetText(oFile:FullPath, ref lOpen)
		IF .not. lOpen
			RETURN
		END IF

		VAR oEditor := XSharp_EditorStream{}
		oEditor:Load(oFile:FullPath)
		VAR nLine := oType:Range:EndLine -1
		aLines:Reverse()
		FOREACH VAR cLine in aLines
			VAR cNew := VOWindowEditor.SubStituteTpl(cLine, cClass, oWindowDesign:cInitMethod)
			oFile:Project:ProjectNode:DocumentInsertLine(oFile:FullPath, nLine, cNew)
		NEXT
		oFile:Project:ProjectNode:OpenElement(oFile:FullPath, nLine,1)
		XSharpModel.XSolution.WalkFile(oFile:FullPath)
	RETURN

END CLASS

END NAMESPACE