Checking changes in folder

Post Reply
User avatar
Marco Turco
Posts: 858
Joined: Fri Oct 07, 2005 12:00 pm
Location: London
Contact:

Checking changes in folder

Post by Marco Turco »

Hi,
I need to check if the value of some controls (get, combobox..) in a folder has changed in order to request a confirm to the customer before exit.

Due the outlook interface I am using the customer can loose the data simply selecting another record so a confirm exit is needed.

See image at www.softwarexp.co.uk/beta/sample.jpg

I made the following routine to check it that providing the oFld as parameter will scan all GET controls inside and check the ::oGet:Changed() value.

Function CheckChanged(oFld)
local aArray,i,n,nPrompts,lChanged

lChanged:=.f.
nPrompts:=len(oFld:aPrompts)

for n:=1 to nPrompts
aArray:=oFld:aDialogs[n]:aControls
for i:=1 to len(aArray)
if oFld:aDialogs[n]:aControls:Classname="TGET"
if oFld:aDialogs[n]:aControls:oGet:Changed()
lChanged:=.t. && has changed
exit
endif
endif
next
next
return(lChanged)

The problem is that I only can check changes in GET controls but I need to check the combobox and tcbrowse also.
Any ideas to make this ? As I know the ::Changed() data is only applied on GET controls.

Thanks iin advance.
Best Regards,

Marco Turco
SOFTWARE XP LLP
User avatar
driessen
Posts: 1239
Joined: Mon Oct 10, 2005 11:26 am
Location: Genk, Belgium

Post by driessen »

Marco,

This is the way I do this check :

Code: Select all

LOCAL cFIELD1, oFIELD1
LOCAL cFIELD2, oFIELD2
....
cFIELD1 := oFIELD1 := FILE->FIELD1
cFIELD2 := oFIELD2 := FILE->FIELD2
....
DEFINE DIALOG ....
....
REDEFINE GET cFIELD1 ID 101 OF ....
REDEFINE CHECKBOX cFIELD2 ID 102 OF ....
....
ACTIVATE DIALOG ....

IF cFIELD1 = oFIELD1 .AND. cFIELD2 = oFIELD2
    .... data has not been changed ....
ELSE
    .... data has been changed ....
ENDIF
It doesn't matter what the kind of cFIELD1 or cFIELD2 is : a GET, a CHECKBOX, a RADIO BUTTON, ...

It always works.

Good luck
Regards,

Michel D.
Genk (Belgium)
_____________________________________________________________________________________________
I use : FiveWin for (x)Harbour v. 21.01 - Harbour 3.2.0 (October 2020) - xHarbour Builder (January 2020) - Bcc7
User avatar
Marco Turco
Posts: 858
Joined: Fri Oct 07, 2005 12:00 pm
Location: London
Contact:

Post by Marco Turco »

Hi Driessen,
you are right but I have a lot of variables to check so I would like find an automatic check without manage each control.
Best Regards,

Marco Turco
SOFTWARE XP LLP
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Marco,

Do you use a Class TDataBase for fields editing ?

If yes, then you can simply check oDataBase:Modified() :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Marco Turco
Posts: 858
Joined: Fri Oct 07, 2005 12:00 pm
Location: London
Contact:

Post by Marco Turco »

Antonio Linares wrote:Marco,

Do you use a Class TDataBase for fields editing ?

If yes, then you can simply check oDataBase:Modified() :-)
Unfortunately that data file is not in a dbf format.
Best Regards,

Marco Turco
SOFTWARE XP LLP
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Marco,

If you use locals, then I am thinking that we could implement an easy and very powerfull solution :-)

if you keep the locals together, then we could step through them and build an array from them, and later on, compare the original values with the array. Thats what Class TDataBase does basically.

There are some functions in [x]Harbour to step through the local variables by their position (order) and no by its name. So it can be done :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Marco,

Here you have a working sample. It can be very much simplified, as I have included some code so testers can understand the virtual machine stack structure. Also the "locals" checker code could be placed into an external function:

Code: Select all

#include "FiveWin.ch"

function Main()

   Test( "one", "two", "three" )

return nil

function Test( x, y, z )

   local local1 := "first", local2 := "second", aBegin := HB_DBG_VMSTKLLIST(), aEnd, n
   
   MsgInfo( "Name of the function: " + aBegin[ 1 ] )
   MsgInfo( "Is this a function or a method ? " + If( aBegin[ 2 ] != nil, "Method", "function" ) )

   for n = 1 to PCount()
      MsgInfo( "parameter " + AllTrim( Str( n ) ) + ": " + cValToChar( aBegin[ 2 + n ] ) )
   next   
   
   n++
   while n < Len( aBegin ) - 1
      MsgInfo( "local " + AllTrim( Str( n - PCount() - 1 ) ) + ": " + cValToChar( aBegin[ n + 1 ] ) )
      n++
   end   

   local2 := "changed!" // we change a local value

   aEnd = HB_DBG_VMSTKLLIST()
   for n = PCount() + 1 to Len( aEnd ) - 1
      if aBegin[ n ] != aEnd[ n ]
         MsgInfo( "local " + AllTrim( Str( n - PCount() - 2 ) ) + " has changed!" )
      endif
   next
         
return nil
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

A simplified version:

Code: Select all

#include "FiveWin.ch"

function Main()

   Test( "one", "two", "three" )

return nil

function Test( x, y, z )

   local local1 := "first", local2 := "second", aBegin := HB_DBG_VMSTKLLIST(), aEnd, n

   // your code...
   
   local2 := "changed!" // we change a local value
   
   // Now we check for changes in locals variables

   aEnd = HB_DBG_VMSTKLLIST()
   for n = PCount() + 1 to Len( aEnd ) - 1
      if aBegin[ n ] != aEnd[ n ]
         MsgInfo( "local " + AllTrim( Str( n - PCount() - 2 ) ) + " has changed!" )
      endif
   next
         
return nil
regards, saludos

Antonio Linares
www.fivetechsoft.com
demont frank
Posts: 167
Joined: Thu Mar 22, 2007 11:24 am

Post by demont frank »

Maybe this will work , also when folders are nested

Frank

Code: Select all


#include "FiveWin.ch"
#include "common.ch"

function Main()

   local oDlg, oFld
 LOCAL Num := 100
 LOCAL MemInpVal[0]
 LOCAL n := 1 , oRadMenu , oGet
   DEFINE DIALOG oDlg RESOURCE "test"

   REDEFINE FOLDER oFld ID 110 OF oDlg ;
      DIALOGS "dlg1", "dlg2" PROMPTS "One", "Two"
   REDEFINE GET oGet VAR Num OF oFld:aDialogs[1] ID 100
   REDEFINE RADIO oRadMenu VAR n ID 110 , 120 OF oFld:aDialogs[2]
   
    REDEFINE BUTTON ID 120 OF oDlg ACTION CompInputValue(oDlg , @MemInpVal )

   ACTIVATE DIALOG oDlg CENTERED ;
      ON INIT (SaveInputValue(oDlg , @MemInpVal))

return nil

PROC SaveInputValue(oDlg , Arr)
*************************
LOCAL el , elem , oRadMenu[0]
FOR EACH el IN oDlg:aControls
  IF el:ClassName == "TFOLDER"
    FOR EACH elem IN el:aDialogs                                
      SaveInputValue(elem , @Arr)
    NEXT
  ELSE
    IF el:ClassName = "TRADIO"
      IF ASCAN(oRadMenu , {|j|j==el:oRadMenu}) == 0
        AADD(oRadMenu , el:oRadMenu)
        AADD(Arr,el:oRadMenu:nOption())
      END
    ELSEIF __ObjHasMethod(el,"VarGet")
    // Maybe better : IF el:ClassName IN {"TGET","TCHECK", ......}
       AADD(Arr,el:VarGet()   )
     END 
  END
NEXT
RETURN
**********************************************************************************************
FUNC CompInputValue(oDlg , MemInpVal )
***************************************
LOCAL Arr[0] , i
LOCAL lOk := .T.
SaveInputValue(oDlg,@Arr)
FOR i := 1 TO Len(MemInpVal)
  IF Arr[i] <> MemInpVal[i]
    lOk := .F.
    EXIT	 
  END
NEXT
RETURN lOk
************************************************************
Test DIALOG 19, 47, 233, 124
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "FiveWin Folders"
{
 CONTROL "", 110, "SysTabControl32", 0 | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 4, 5, 225, 99
 PUSHBUTTON "&OK", 120, 98, 108, 37, 14
}

dlg1 DIALOG 18, 18, 205, 80
STYLE WS_CHILD | 4
{
LTEXT    "Number : ", 90, 10 , 2 , 40 , 10 //, WS_BORDER | WS_TABSTOP
EDITTEXT 100, 37 , 2, 20 , 10, WS_BORDER | WS_TABSTOP
CONTROL "First", 110, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 37, 30, 28, 12
}

dlg2 DIALOG 18, 18, 205, 80
STYLE WS_CHILD | 4
{
 CONTROL "Second", 110, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 37, 30, 28, 12
 CONTROL "Third", 120, "BUTTON", BS_AUTORADIOBUTTON | WS_TABSTOP, 37, 43, 28, 12
}

demont frank
Posts: 167
Joined: Thu Mar 22, 2007 11:24 am

Post by demont frank »

Antonio

In many cases we are using arrays , or why not , nested arrays , or arrays are mixted with others.

In this case i suppose that this code is much more complicated and has to
be changed .

Frank
Antonio Linares wrote:A simplified version:

Code: Select all

#include "FiveWin.ch"

function Main()

   Test( "one", "two", "three" )

return nil

function Test( x, y, z )

   local local1 := "first", local2 := "second", aBegin := HB_DBG_VMSTKLLIST(), aEnd, n

   // your code...
   
   local2 := "changed!" // we change a local value
   
   // Now we check for changes in locals variables

   aEnd = HB_DBG_VMSTKLLIST()
   for n = PCount() + 1 to Len( aEnd ) - 1
      if aBegin[ n ] != aEnd[ n ]
         MsgInfo( "local " + AllTrim( Str( n - PCount() - 2 ) ) + " has changed!" )
      endif
   next
         
return nil
User avatar
Marco Turco
Posts: 858
Joined: Fri Oct 07, 2005 12:00 pm
Location: London
Contact:

Post by Marco Turco »

Hi Frank,
your code is the easyest solution for my case.

Thanks to all for the tips.
Best Regards,

Marco Turco
SOFTWARE XP LLP
Post Reply