XBrowse & Edit Dialogs: Writing Portable code (Recommended)

XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby nageswaragunupudi » Sat Mar 16, 2019 5:22 pm

XBrowse and TDataRow (used by Xbrowse for adding/editing records) are designed to help writing code portable across different datasources like DBF, TDatabase, ADO, FWMariaDB, Dolphin, TMySql, PostGreSQL, etc.
Same code written for one datasource can be used without any changes (or with very minimal changes in some complex cases) for the same table from another datasource/database. Writing the code in this manner makes it easy to switch database for the same software.

This is a simple sample, which browses "states" table with add and edit dialogs and delete record features.
This program may be copied to fwh\samples folder and built with buildh.bat or buildx.bat

Program Code:

Part-1 :
function Main(): Select the datasource (database)
function OpenData() --> uTable: Open the table depending on the database selected
function CloseData( uTable ): Close the table and database

Obviously, these functions are different for different databases.

Code: Select all  Expand view

#include "fivewin.ch"

REQUEST DBFCDX

static oCn, nDataType

//----------------------------------------------------------------------------//

function Main()

   local uTable

   SET DELETED ON
   SetGetColorFocus()

   nDataType   := Alert( "Choose Data Source", { "DBF", "TDataBase", "FWMariaDB", "ADO", "Dolphin" } )
   if nDataType == 0
      return nil
   endif

   if !Empty( uTable := OpenTable() )
      BrowseTable( uTable )
      CloseData( uTable )
   endif

return nil

//----------------------------------------------------------------------------//

static function OpenTable()

   local uTable

   SWITCH nDataType

   CASE 1 // DBF
      USE STATES NEW SHARED VIA "DBFCDX"
      uTable   := ALIAS()
      EXIT

   case 2 // TDatabase
      uTable   := TDatabase():Open( nil, "STATES", "DBFCDX", .T. )
      if !uTable:Used()
         uTable   := nil
      endif
      EXIT

   case 3 // FWMariaDB
      oCn      := FW_DemoDB()
      uTable   := oCn:RowSet( "states" )
      EXIT

   case 4 // ADO
      oCn      := FW_DemoDB( "ADO" )
      uTable   := FW_OpenRecordSet( oCn, "states" )
      EXIT

   case 5 // DOLPHIN
#ifdef __XHARBOUR__
      ? "Dolphin Library not linked."
#else
      oCn      := FW_DemoDB( "DLP" )
      uTable   := oCn:Query( "SELECT * FROM states" )
#endif
      EXIT
   END

return uTable

//----------------------------------------------------------------------------//

static function CloseData( uTable )

   SWITCH nDataType

   CASE 1 // DBF
      CLOSE STATES
      EXIT

   case 2 // TDatabase
      uTable:Close()
      EXIT

   case 3 // FWMariaDB
      uTable:Close()
      EXIT

   case 4 // ADO
      uTable:Close()
      oCn:Close()
      EXIT

   case 5 // DOLPHIN
#ifndef __XHARBOUR__
      uTable:End()
      oCn:End()
#endif
      EXIT

   END

   oCn   := nil

return nil

//----------------------------------------------------------------------------//

#ifndef __XHARBOUR__
EXTERNAL TDOLPHINSRV
#endif
 



Part-2:

function BrowseTable( uTable )
function EditRecord( oRecord )

These two functions are identical for all kinds of databases. The same code works for all.
We recommend this approach for any database.
These functions can be treated as a template.

Code: Select all  Expand view

static function BrowseTable( uTable )

   local oDlg, oBar, oFont, oBrw

   DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-14
   DEFINE DIALOG oDlg SIZE 360,600 PIXEL TRUEPIXEL FONT oFont

   DEFINE BUTTONBAR oBar OF oDlg SIZE 56,32 2010
   DEFINE BUTTON OF oBar PROMPT "Add"     ACTION oBrw:EditSource( .t. )
   DEFINE BUTTON OF oBar PROMPT "Edit"    ACTION oBrw:EditSource()
   DEFINE BUTTON OF oBar PROMPT "Delete"  ACTION ;
      If( MsgNoYes( "Delete " + Trim( oBrw:Name:Value ) + " ?" ), ;
      oBrw:Delete(), nil )
   DEFINE BUTTON OF oBar PROMPT "Close"   ACTION oDlg:End() BTNRIGHT

   @ 60,20 XBROWSE oBrw SIZE -20,-20 PIXEL OF oDlg ;
      DATASOURCE uTable ;
      COLUMNS "CODE","NAME" ;
      PICTURES "!!" ;
      FASTEDIT CELL LINES NOBORDER

   WITH OBJECT oBrw

      :nStretchCol   := 2
      :nEditTypes    := EDIT_GET

      :Code:bEditValid  := { |oGet| Len( Trim( oGet:VarGet() ) ) == 2 }
      :Name:bEditValid  := { |oGet| If( Empty( oGet:VarGet() ), oBrw:ShowMessage( "Can not be empty" ), .t. ) }

      // To use custom dialog. If ommitted, FWH uses default dialog
      :bEdit      := { |oRec| EditRecord( oRec ) }
      //

      :CreateFromCode()
   END

   ACTIVATE DIALOG oDlg CENTERED
   RELEASE FONT oFont

return nil

//----------------------------------------------------------------------------//

function EditRecord( oRec )

   local lNew     := ( oRec:RecNo == 0 )
   local oDlg, oFont, oBtn

   DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-14
   DEFINE DIALOG oDlg SIZE 400,240 PIXEL TRUEPIXEL FONT oFont ;
      TITLE "STATES"

   @ 20, 20 SAY If( oRec:RecNo == 0, "ADD NEW STATE", "EDIT STATE" ) ;
      SIZE 360,22 PIXEL OF oDlg CENTER VCENTER

   oDlg:bInit := <||
   @  80, 40 SAY "StateCode :" GET oRec:Code PICTURE "!!" SIZE 130,24 PIXEL OF oDlg ;
      VALID If( Len( Trim( oRec:Code ) ) < 2, ( MsgAlert( "Enter 2 chars" ), .f. ), .t. )

   @ 110, 40 SAY "StateName :" GET oRec:Name SIZE 300,24 PIXEL OF oDlg ;
      VALID If( Empty( oRec:Name ), ( MsgAlert( "Can not be empty" ), .f. ), .t. )
   return nil
   >

   oRec:bValid := { || Len( Trim( oRec:Code ) ) == 2 .and. !Empty( oRec:Name ) }

   @ 180, 20 BTNBMP oBtn PROMPT "SAVE"   SIZE 100,30 PIXEL OF oDlg FLAT ;
      WHEN oRec:lValid() .and. oRec:Modified() ;
      ACTION ( oRec:Save(), oDlg:End() )

   @ 180,280 BTNBMP oBtn PROMPT "CANCEL" SIZE 100,30 PIXEL OF oDlg FLAT ACTION oDlg:End()
   oBtn:lCancel   := .t.

   ACTIVATE DIALOG oDlg CENTERED ;
      ON PAINT oDlg:Box( 60, 20, 155, 380 )
   RELEASE FONT oFont

return nil
 
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10641
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby Silvio.Falconi » Sun Mar 17, 2019 6:26 pm

I tried to compile it
I have these errors
Perhaps I need some libs

Code: Select all  Expand view

Progetto: test, Ambiente: bcc7Harbor:
[1]:Harbour.Exe test.prg  /m /n0 /gc1 /es2 /a /iC:\Work\fwh\include /iC:\work\HARBOUR\Include /jC:\Work\Errori\NAGES_~4\I18n\Main.hil /iinclude;c:\work\fwh\include;C:\work\HARBOUR\include /oObj\test.c
Harbour 3.2.0dev (r1703231115)
Copyright (c) 1999-2016, http://harbour-project.org/
Compiling 'test.prg'...
Lines 5005, Functions/Procedures 5
Generating C source output to 'Obj\test.c'... Done.
[1]:Bcc32.Exe -M -c -DHB_OS_WIN_32 -DHB_FM_STATISTICS_OFF -DHB_NO_DEFAULT_API_MACROS -DHB_NO_DEFAULT_STACK_MACROS -IC:\Work\fwh\include -IC:\work\bcc7\Include\windows\sdk\;C:\work\HARBOUR\Include  -nC:\Work\Errori\NAGES_~4\Obj test.c
Embarcadero C++ 7.00 for Win32 Copyright (c) 1993-2015 Embarcadero Technologies, Inc.
test.c:
[1]:iLink32.Exe -Gn -aa -Tpe -s -v @test.bcl
Turbo Incremental Link 6.70 Copyright (c) 1997-2014 Embarcadero Technologies, Inc.
Error: Unresolved external 'mysql_set_character_set' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_server_init' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_init' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_options' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_real_connect' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_list_tables' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_list_dbs' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_field_count' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_affected_rows' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_list_fields' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_fetch_field' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_hex_string' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_real_query' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_use_result' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_fetch_fields' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_real_escape_string' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_escape_string' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_store_result' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_data_seek' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_num_fields' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_fetch_row' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_fetch_lengths' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_stmt_bind_param' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_set_server_option' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_autocommit' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_insert_id' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_get_client_info' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_character_set_name' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_get_server_info' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_ping' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_commit' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_rollback' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_select_db' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_errno' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_error' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_info' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_next_result' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_free_result' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_close' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_server_end' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_num_rows' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_stmt_init' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_stmt_prepare' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_stmt_execute' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external 'mysql_stmt_close' referenced from C:\WORK\FWH\LIB\FIVEH.LIB|FWMARIA
Error: Unresolved external '_HB_FUN_TDOLPHINSRV' referenced from C:\WORK\ERRORI\NAGES_SAMPLE\OBJ\TEST.OBJ
Error: Unable to perform link
 
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 7061
Joined: Thu Oct 18, 2012 7:17 pm

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby Silvio.Falconi » Sun Mar 17, 2019 6:32 pm

I would prefer an example how to edit an archive having an incremental field eg record number +1
In the past month to convert old procedures created in fwh / clipper I had difficulties (even with James) because I have some archives that use the code recno + 1 and the client wants to see this code in the record entry procedure: it seems with database there are difficulty .
Now I have many problems because in other procedures they are related to this code and I don't know how to go on or I have to change the program by changing it all.
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 7061
Joined: Thu Oct 18, 2012 7:17 pm

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby nageswaragunupudi » Mon Mar 18, 2019 1:58 am

I tried to compile it
I have these errors
Perhaps I need some libs

Copy this program to \fwh\samples folder.
Run buildh <program>
Buildh.bat links all the libraries required.
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10641
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby Silvio.Falconi » Mon Mar 18, 2019 8:41 am

thanks resolved
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 7061
Joined: Thu Oct 18, 2012 7:17 pm

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby Compuin » Mon Mar 18, 2019 11:56 am

Thanks Mr Rao

Is it possible to do the same with Eagle 1 ?
FWH 20.12
Hbmk2 32/64 Bits (Build 19.29.30133)
Microsoft Visual C 32 Bits
MySql 8.0.24 32/64 Bits
VS Code
Compuin
 
Posts: 1214
Joined: Tue Dec 28, 2010 1:29 pm
Location: Quebec, Canada

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby nageswaragunupudi » Mon Mar 18, 2019 12:00 pm

No.
I have never tried Eagle.
How can I try?
Can you also explain how do you use Eagle with FWH?
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10641
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby Silvio.Falconi » Wed Mar 27, 2019 12:55 am

Nages,
I made all as you wrote
I open my dbf with

Code: Select all  Expand view
oClienti := TDatabase():Open( , cPath+ "CLIENTI", "DBFCDX", .T. )
oClienti:SetOrder( 1 )
 oClienti:GoTop()




Image



and I show the archive with a xbrowse as you can see I insert a tab to select the index

on edit I have 3 option Mode
nMode = 1 -> add New
nMome = 2 -> modify record
nMode = 3 --> duplicate record

at the beginning of the edit function
I call tdatarow with
Code: Select all  Expand view
oRec     := oClienti:record()


then I wrote

Code: Select all  Expand view
     IF nMode == 1 //add new
         oRec:Load(.t.)
          nRecAdd := oRec:RecNo()
         Endif


cNumcli     := Iif(nMode==1 .or.nMode==3 .AND.cCli!=nil,cCli,oRec:numcli)
         cCognome    := oRec:cognome
         cNome       := oRec:nome
         cIndirizzo  := oRec:indirizzo
         cCitta      := oRec:citta
         cProvincia  := oRec:provincia
         cCap        := oRec:cap
         cStato      := oRec:stato
         cEmail      := oRec:email
         cCodfiscale := oRec:Codfiscale
         cPartiva    := oRec:Partiva
         cAppunti    := oRec:appunti
         cTelefono1  := oRec:Telefono1
         cTelefono2  := oRec:Telefono2
         cTelefono3  := oRec:Telefono3
         cTelefono4  := oRec:Telefono4
         cTeleTipo1  := oRec:TeleTipo1
         cTeletipo2  := oRec:TeleTipo2
         cTeletipo3  := oRec:TeleTipo3
         cTeletipo4  := oRec:TeleTipo4
         cTipoCli    := oRec:TipoCli
         lIslock     := Iif(nMode==1 .or.nMode==3 ,.f.,oRec:Islock)

IF nMode == 3  //duplicate
                     oRec:Load(.t.)
          nRecAdd := oRec:RecNo()
       Endif




 


I made the dialog of gets

then at the end

Code: Select all  Expand view
IF oDlg:nresult == IDOK
    lReturn := .t.

        if nMode == 2  //modify
         oClienti:GoTo(nRecPtr)
      else
         oClienti:GoTo(nRecAdd)
      endif

 IF nMode == 1 .or. nMode == 3    // add or modify
                 oClienti:gobottom()
                  cCli:= strzero(oClienti:RecNo+1,4)
                  oClienti:GoTo(nRecAdd)
                elseif nMode == 2
                     oClienti:GoTo(nRecPtr)
                  ENDIF

oRec:NumCli     := cCli
        oRec:Cognome    := cCognome
        oRec:Nome       := cNome
        oRec:Indirizzo  := cIndirizzo
        oRec:Citta      := cCitta
        oRec:Provincia  := cProvincia
        oRec:Cap        := cCap
        oRec:Stato      := cStato
        oRec:Email      := cEmail
        oRec:Codfiscale := cCodfiscale
        oRec:Partiva    := cPartiva
        oRec:Appunti    := cAppunti
        oRec:Telefono1  := cTelefono1
        oRec:Telefono2  := cTelefono2
        oRec:Telefono3  := cTelefono3
        oRec:Telefono4  := cTelefono4
        oRec:TeleTipo1  := cTeleTipo1
        oRec:Teletipo2  := cTeletipo2
        oRec:Teletipo3  := cTeletipo3
        oRec:Teletipo4  := cTeletipo4
        oRec:TipoCli    := cTipoCli
        oRec:Islock     := lIslock
        oRec:save()
 




it run but sometimes when I change the index of archive selecting the tab it save bad ( with numcli bad)... why ?

this is the tab and command action
Code: Select all  Expand view
@ oBrwClienti:nBottom+4,oBrwClienti:nLeft  TABS oTabCli  ;
    OPTION nOrder SIZE oBrwClienti:nWidth-20, 22 PIXEL OF oDlgClienti ;
      ITEMS ' Codice ','Denominazione','Tipo Cliente','Città';
       ACTION ( nOrder := oTabCli:nOption  ,;
               oClienti:SetOrder(nOrder),;
               oClienti:GoTop()        ,;
               oBrwClienti:Refresh(.t.)      ,;
               RefreshCont(oCont, oClienti) )
 


why it save bad ?
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 7061
Joined: Thu Oct 18, 2012 7:17 pm

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby nageswaragunupudi » Wed Mar 27, 2019 1:37 am

Silvio
You still have not understood.

If you write so many lines of code, you have not understood the power of FWH.
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10641
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby Silvio.Falconi » Wed Mar 27, 2019 8:13 am

nageswaragunupudi wrote:Silvio
You still have not understood.

If you write so many lines of code, you have not understood the power of FWH.



Yes..Of Course
You sad me it because you see I set the variables sample


cCognome := oRec:cognome
cNome := oRec:nome


but if you use on get directly the field sample :

@10,10 GET oRec:cognome Size 100,12 of Odlg

you can only add a new record or modify the record

and it run ok

I need also the duplication of a record

I explain you :

Imagine... you must insert records having the same surname, telephones and other data info

you need have the same record and change only one get and save it with ID ( account number of customer) different

I tried and tried many times I can only add new and modify record if make as you sad

if you use

@ 26, 5 SAY "Cognome:" OF oDlg SIZE 36, 8 PIXEL FONT oFont
@ 24, 36 GET oRec:Cognome OF oDlg SIZE 90, 10 PIXEL FONT oFont UPDATE

it's right but then you cannot manage a duplicate record !!!



If you not understand the sequence I write you not undestood my problem!!!


to use "tdatabase" I have to give up not showing the user code ( account number of customer) and do only inserting and editing and I can't use record duplication I prefer not to use it
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 7061
Joined: Thu Oct 18, 2012 7:17 pm

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby nageswaragunupudi » Wed Mar 27, 2019 10:15 am

This example uses the data of an existing record and with modifications, saves it as a new record.
Code: Select all  Expand view
#include "fivewin.ch"

REQUEST DBFCDX

function Main()

   local oCustomers, oCustomer100, oCustomerNew

   oCustomers  := TDataBase():Open( nil, "CUSTOMER", "DBFCDX", .t. )
   // if you want to use your dialog
   // oCustomers:bEdit := { |oRec| MyCustomerDialog( oRec ) }
   
   XBROWSER oCustomers

   oCustomers:GoTo( 100 )
   oCustomer100   := oCustomers:Record()
   oCustomer100:Copy()  // copy contents to memory

   oCustomerNew   := oCustomers:Record( , .t. )
   oCustomerNew:Paste() // paste contents from memory
   oCustomerNew:Edit()

   XBROWSER oCustomers

   oCustomers:Close()

return nil
 
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10641
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby Silvio.Falconi » Wed Mar 27, 2019 11:46 am

thanks Maestro
finally I solved my problems, at least for the add, the modification and now for the duplication of a record

and for the other problem How I can resolve?
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 7061
Joined: Thu Oct 18, 2012 7:17 pm

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby Silvio.Falconi » Wed Mar 27, 2019 6:22 pm

Nages run ok
How I must make to calc oRec:NumCli

I made

at init

Open table
oClienti := TDatabase():Open( , cPath+ "CLIENTI", "DBFCDX", .T. )
oClienti:SetOrder( 1 )
oClienti:GoTop()

on xbrowse

:bEdit := { |oRec| EditRecord( oRec ) }

then I associated on buttons oBrwClienti:EditSource( .t. ) for add or oBrwClienti:EditSource( .f. ) for modify

function EditRecord( oRec )
Local nMode:= If( oRec:RecNo == 0, 1, 2)

IF nMode == 1
oClienti:gobottom()
cCodeCliente:=StrZero(val(oClienti:numcli)+1,4)
Endif

on Dialog

@ 12, 5 SAY "Codice:" OF oDlg SIZE 19, 8 PIXEL FONT oBold
@ 10, 36 GET aGet[1] VAR cCodeCliente OF oDlg SIZE 25, 10 PIXEL READONLY

@ 26, 5 SAY "Cognome:" OF oDlg SIZE 36, 8 PIXEL FONT oBold
@ 24, 36 Get aGet[4] VAR oRec:Cognome OF oDlg SIZE 90, 10 PIXEL PICTURE "@!" FONT oFont UPDATE

....

When I save

IF nMode == 1
oClienti:SetOrder( 1 )
oClienti:gobottom()
cCodeCliente:=StrZero(val(oClienti:numcli)+1,4)
oRec:numcli:=cCodeCliente
else // modify
oClienti:numcli := cCodeCliente
Endif

oRec:Save()


here seems run ok
is it wrong ?
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 7061
Joined: Thu Oct 18, 2012 7:17 pm

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby nageswaragunupudi » Thu Mar 28, 2019 12:27 am

on xbrowse

:bEdit := { |oRec| EditRecord( oRec ) }

In case of TDatabase or Mariadb RowSet, you better assign this to the table object like this:
Code: Select all  Expand view

oClienti:bEdit := { |oRec| EditRecord( oRec ) }
 

Then you need not again assign anything to oBrw:bEdit.
This works even without browse
Code: Select all  Expand view

oClienti:Edit()
// OR
oClienti:Edit( .t. )
 


These are the problems I notice:

Saving an existing record after modification:
Code: Select all  Expand view

else // modify
oClienti:numcli := cCodeCliente
 

Here cCodeCliente does not have any value. This is wrong. In any case, when you modify, you should not change the value of oClienti:numcli.
So, remove this code.

Adding new records:

Assume that the DBF already has 100 records. Two users (User-A and User-B) are running your program and trying to add a new record at the same time.

Problem-1:
Then both User-A and User-B will see the new number as "101" in their edit dialog. Is this acceptable to you and your users?

Even if this is accepted, still you have problems.

Problem-2:
Assume User-B saves the new record first. Then this record will be saved with "101" as the "numcli"
Still, User-A is thinking that his new record will be saved as "101". But when he actually saves, the record will be saved as "102". So what User-A sees on the screen is "101" but saves as "102". Is this acceptable to you and your users?

Problem-3:
Again let us take the case of User-A and User-B trying to edit and save a new record. Both see the new number as "101" in their dialogs.

Assume both hit the "Save" button more or less at the same time.
If one user saves the new record just after other user's program executed
Code: Select all  Expand view

oClienti:SetOrder( 1 )
oClienti:gobottom()
cCodeCliente:=StrZero(val(oClienti:numcli)+1,4)
oRec:numcli:=cCodeCliente
 

and just before executing
Code: Select all  Expand view

oRec:Save()
 

both users end up saving two records with the same "numcli" as "101", resulting in duplication of the numbers.

Now it is upto you.
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10641
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: XBrowse & Edit Dialogs: Writing Portable code (Recommended)

Postby Silvio.Falconi » Thu Mar 28, 2019 9:49 am

Add new
let's say that two users User-a and User-B insert a customer from two different offices, both of them will see the user code "101" but only one will save with this code, the other can save with the code "102" this must be normal and the procedure should show the user-B that the customer code is not 101 but 102.

Modify
Regarding the modification, the user code must not be modified; the other fields can be modified instead

Duplication
For the duplication it works as for the insertion only that the user will have all the fields inserted equal to the selected record, only when he goes to save the user code is a new one that is a new record
obviously if the A-user and the B-user duplicate the same record, the saving occurs as the insertion ie the procedure must inform the user -B that the code number is another.

how to do this in fwh and with tdatabase?


I tested also this morning this test and now it seems run ok

Code: Select all  Expand view

 
#include "fivewin.ch"
#include "constant.ch"
#include "dtpicker.ch"

REQUEST DBFCDX

static oClienti

static cPath,cPathDb

static cIniFile,cIniReport,cIniUser


FUNCTION Main()

 
   SET _3DLOOK ON
   SET CENTURY ON
   SET DATE ITALIAN

   RDDSetDefault( 'DBFCDX' )

     cIniFile    := TakeOffExt( GetModuleFileName( GetInstance() ) ) + ".ini"
     cIniReport  := TakeOffExt( GetModuleFileName( GetInstance() ) ) + ".rpt"
     cIniUser    := TakeOffExt( GetModuleFileName( GetInstance() ) ) + ".usr"

   
    cPath:="data\"

   Clienti()

   RETURN NIL
//----------------------------------------------------------------------------------//

Function Clienti()
BuildDBF()
OpenTable()
BrowseTable()
return nil
//----------------------------------------------------------------------------------//

static function OpenTable()
// Customers

       oClienti := TDatabase():Open( , cPath+ "
CLIENTI", "DBFCDX", .T. )
       oClienti:SetOrder( 1 )
       oClienti:GoTop()

return nil
//----------------------------------------------------------------------------------//

Function BuildDbf()

   FIELD NUMCLI,NOMEINTERO,CITTA,TIPO


local oDbf

local cDir:= cPath

   local aCols       := {{'Numcli' ,'C',4  ,0 }  ,;
                         {'Cognome','C',30 ,0 }  ,;
                         {'Nome','C',30 ,0 }  ,;
                         {'Indirizzo' ,'C',50 ,0 }  ,;
                         {'Citta'     ,'C',30 ,0 }  ,;
                         {'Provincia' ,'C',2  ,0 }  ,;
                         {'Cap'       ,'C',5  ,0 }  ,;
                         {'Stato'     ,'C',30 ,0 }  ,;
                         {'Email'     ,'C',50 ,0 }  ,;
                         {'Codfiscale','C',16 ,0 }  ,;
                         {'Partiva'   ,'C',11 ,0 }  ,;
                         {'Appunti'   ,'C',200,0 }  ,;
                         {'Telefono1' ,'C',20 ,0 }  ,;
                         {'Telefono2' ,'C',20 ,0 }  ,;
                         {'Telefono3' ,'C',20 ,0 }  ,;
                         {'Telefono4' ,'C',20 ,0 }  ,;
                         {'TeleTipo1' ,'C',10 ,0 }  ,;
                         {'Teletipo2' ,'C',10 ,0 }  ,;
                         {'Teletipo3' ,'C',10 ,0 }  ,;
                         {'Teletipo4' ,'C',10 ,0 }  ,;
                         {'TipoCli'   ,'C',25 ,0 }  ,;
                         {'Islock'    ,'L', 1 ,0 }   }


 IF !file(cDir+"
CLIENTI.DBF")
          oDbf  := TDatabase():Create( cDir+"
CLIENTI.DBF", aCols, "DBFCDX"  ) //"*"
            oDbf:Append()
            oDbf:numcli:= "
0001"
            oDbf:Cognome:= "
<< Cliente Generico >>"
            oDbf:TipoCli:="
darkgray"
            oDbf:Islock:= .t.
            oDbf:save()



            INDEX ON NUMCLI TAG CL001 FOR !Deleted()
            INDEX ON upper(COGNOME)+UPPER(NOME) TAG CL002 FOR !Deleted()
            INDEX ON upper(TIPOCLI) TAG CL003 FOR !Deleted()
            INDEX ON upper(CITTA) TAG CL004 FOR !Deleted()

            oDbf:Close()

       ENDIF

return nil
//----------------------------------------------------------------------------------//


static function BrowseTable()
Local oDlgClienti,oFont,oBold
Local cCursor:= TCursor():New(,'HAND')
Local oBrwClienti
Local oBtnNew,oBtnMod,oBtnDup
Local oCont,oSay
Local oTabcli

Local nOrder      := VAL(GetPvProfString("
Browse", "CLOrder","1", cIniUser))
Local nRecno      := VAL(GetPvProfString("
Browse", "CLRecno","1", cIniUser))
local cState      := GetPvProfString("
Browse", "ClState","", cIniUser)


   DEFINE FONT oFont NAME "
TAHOMA" SIZE 0,-14
   DEFINE FONT oBold NAME "
TAHOMA" SIZE 0,-14 BOLD

   DEFINE DIALOG oDlgClienti SIZE 880,600 PIXEL TRUEPIXEL RESIZABLE FONT oFont ;
   TITLE "
Bikini - Clienti" ;
   COLOR CLR_BLACK,CLR_WHITE TRANSPARENT


   @ 05,oDlgClienti:nleft+10 SAY oSay PROMPT "
Gestione dei Clienti:"  SIZE 120,12 PIXEL OF oDlgClienti

   @ 05,oDlgClienti:nleft+160 SAY oCont PROMPT tran(oClienti:KeyNo(),'@E 999,999')+"
/ "+tran(oClienti:KeyCount(),'@E 999,999')  SIZE 100,12 PIXEL OF oDlgClienti

   @ 45,oDlgClienti:nleft+10 XBROWSE oBrwClienti SIZE -5,-80 PIXEL OF oDlgClienti ;
      COLUMNS "
NUMCLI","COGNOME","NOME","","CITTA","TELEFONO1","TELEFONO2","ISLOCK";
      HEADERS "
Codice","Cognome","Nome","Tipo","Città", "Telefono","Cellulare","";
      COLSIZES 40,150,120,40,120,120,120,30 ;
      CELL LINES NOBORDER ;
      DATASOURCE oClienti


                WITH OBJECT oBrwClienti
                     :nRowHeight    := 30
                      :lHscroll            := .F.
                      :l2007               := .F.
                      :l2015               := .T.
                      :lRecordSelector     := .f.
                      :nStretchCol         := STRETCHCOL_WIDEST
                      :lAllowRowSizing     := .F.
                      :lAllowColSwapping   := .F.
                      :lAllowColHiding     := .F.
                      :nMarqueeStyle       := MARQSTYLE_HIGHLROW
                      :bEdit      := { |oRec| EditRecord( oRec ) }
                      :CreateFromCode()
                   END



   oClienti:bEdit := { |oRec| EditRecord( oRec,oCont,oBrwClienti ) }

   oBrwClienti:bClrStd   := { || { CLR_BLACK, If( oBrwClienti:KeyNo % 2 == 0, RGB(193,221,255), RGB(221,245,255) ) } }

   oBrwClienti:setStyle(2018)



    oClienti:SetOrder(nOrder)


 if nRecNo < oClienti:LastRec() .AND. nRecno != 0
      oClienti:GoTo(nRecno)
   else
      oClienti:GoTop()
   endif


@ oDlgClienti:nBottom - 40,oDlgClienti:nleft+10 BUTTONBMP oBtnNew;
    RESOURCE "
bitmaps\Clinuevo.png" ;
    PROMPT "
     New" SIZE 90,30 PIXEL OF oDlgClienti;
    TEXTRIGHT FONT oBold ;
    ACTION oBrwClienti:EditSource( .t. )

  @ oDlgClienti:nBottom - 40,oDlgClienti:nleft+110 BUTTONBMP oBtnMod;
    RESOURCE "
bitmaps\Climod.png" ;
    PROMPT "
     Modify" SIZE 90,30 PIXEL OF oDlgClienti;
    TEXTRIGHT FONT oBold ;
    ACTION  oBrwClienti:EditSource( .f. )

   @ oDlgClienti:nBottom - 40,oDlgClienti:nleft+110 BUTTONBMP oBtnDup;
    RESOURCE "
bitmaps\Climod.png" ;
    PROMPT "
     Duplicate" SIZE 90,30 PIXEL OF oDlgClienti;
    TEXTRIGHT FONT oBold ;
    ACTION Duplicate_Record()


 oBtnNew:oCursor:=cCursor
 oBtnMod:oCursor:=cCursor
 oBtnDup:oCursor:=cCursor


oDlgClienti:aMinMaxInfo := { nil, nil, nil, nil, 878, 570, nil, nil } //878, 570
   oDlgClienti:bResized  := <||
      local oRect    := oDlgClienti:GetCliRect()
      local x        := Int( oRect:nWidth / 2 )

      oBtnNew:nLeft   := oRect:nLeft +10
      oBtnNew:nTop    := oRect:nBottom - 40

      oBtnMod:nLeft   := oRect:nLeft +110
      oBtnMod:nTop    := oRect:nBottom - 40

      oBtnDup:nLeft   := oRect:nLeft +310
      oBtnDup:nTop    := oRect:nBottom - 40


        oBrwClienti:refresh()
      return nil

  >

  ACTIVATE DIALOG  oDlgClienti CENTERED;
          ON INIT (eval( oDlgClienti:bResized ))

   RELEASE FONT oFont, oBold

return nil

//--------------------------------------------------------------------------------------//
FUNCTION TakeOffExt(cFile)
   local nAt := At("
.", cFile)
   if nAt > 0
      cFile := Left(cFile, nAt-1)
   endif
   RETURN cFile
//------------------------------------------------------------//

   static function EditRecord( oRec,oCont,oGrid )
   local oDlg, oFld, oBmp , oFont, cBmp,oBold
   local aTitle := { i18n( "
Aggiungere un cliente" ),;
                     i18n( "
Modificare un cliente") ,;
                     i18n( "
Duplicare un cliente") }
   Local cCursor:= TCursor():New(,'HAND')
   Local nBottom   := 28.4
   Local nRight    := 63.3
   Local nWidth    := Max( nRight * DLG_CHARPIX_W, 180 )
   Local nHeight   := nBottom * DLG_CHARPIX_H
   Local lReturn := .f.
   Local aGet[21]

   Local nPos,oGroup1,oGroup2
   Local nColor,oTipoSay
   local aTelefono:={"
","Telefono","Cellulare","Palmare","Fax"}
   local aSesso:={"
Uomo","Donna"}
   local aBmpTel:= {"
MINIEMP","MINITEL", "MINICEL","MINIPAL","MINIFAX" }

   Local  nMode:= If( oRec:RecNo == 0, 1, 2)

   local nRecPtr  := oClienti:RecNo()
   local nOrden   := oClienti:OrdNumber()

   Local cCodeCliente,cCli

         //calc new Account Number
        IF nMode == 1
          oClienti:SetOrder( 1 )
          oClienti:gobottom()
          cCodeCliente:=StrZero(val(oClienti:numcli)+1,4)
         Endif

    //  Assign to cCli the new account number  if is new record
         cCli:=If(nMode==1,cCodeCliente,oRec:Numcli)

     DEFINE FONT oBold NAME "
MS Sans Serif" SIZE 0, 8 bold
   DEFINE FONT oFont NAME "
MS Sans Serif" SIZE 0, 8

   DEFINE DIALOG oDlg SIZE nwidth,nHeight PIXEL ;
          TITLE aTitle[nMode] FONT oFont ;
          COLOR CLR_BLACK,CLR_WHITE TRANSPARENT

      oDlg:lHelpIcon := .F.
      oDlg:nStyle    := nOR( DS_MODALFRAME, WS_POPUP, WS_CAPTION,  4 )


    @ 12, 5 SAY "
Codice:" OF oDlg SIZE 19, 8 PIXEL  FONT oBold
    @ 10, 36 GET aGet[1] VAR  cCli   OF oDlg SIZE 25, 10 PIXEL READONLY

    @ 26, 5 SAY "
Cognome:" OF oDlg SIZE 36, 8 PIXEL FONT oBold
    @ 24, 36 Get aGet[4] VAR oRec:Cognome    OF oDlg SIZE 90, 10 PIXEL PICTURE "
@!" FONT oFont UPDATE

     @ 26, 130 SAY "
Nome:" OF oDlg SIZE 36, 8 PIXEL FONT oBold
     @ 24, 156 GET aGet[5] var oRec:Nome    OF oDlg SIZE 90, 10 PIXEL PICTURE "
@!" FONT oFont UPDATE
      //VALID CliClave(oRec:Cognome, oRec:Nome, aGet, nMode )



      @ 198, 150 BUTTONBMP oBtnConferma         ;
              RESOURCE "
bitmaps\save.png"   ;
              PROMPT "
    Conferma"  SIZE 42, 14 PIXEL OF oDlg;
              TOOLTIP "
Salva Cliente" ;
              TEXTRIGHT FONT oBold    ;
              DEFAULT ;
              ACTION ( oDlg:end( IDOK ) )

 @ 198, 197 BUTTONBMP oBtnAnnulla         ;
              RESOURCE "
bitmaps\no.png"   ;
              PROMPT "
    Annulla"  SIZE 42, 14 PIXEL OF oDlg;
              TOOLTIP "
Annulla" ;
              TEXTRIGHT FONT oBold    ;
              CANCEL ;
              ACTION ( oDlg:end( IDCANCEL ) )


        oBtnConferma:oCursor:=cCursor
              oBtnAnnulla:oCursor:=cCursor



     ACTIVATE DIALOG oDlg CENTERED
      RELEASE FONT oFont, oBold

IF oDlg:nresult == IDOK
    lReturn := .t.

       IF nMode == 1
          oClienti:SetOrder( 1 )
          oClienti:gobottom()
          cCodeCliente:=StrZero(val(oClienti:numcli)+1,4)

          If cCodeCliente==cCli
          Else
             Msginfo("
The customer was saved with the account number "+ltrim(cCodeCliente)+"instead of "+ltrim(cCli),"Attention!!!" )
          endif

          oRec:numcli:=cCodeCliente
          else // modify
         // oClienti:numcli :=  cCodeCliente
         Endif

         oRec:Save()

      Endif

  IF oCont != NIL
             RefreshCont(oCont,oClienti)
          ENDIF

          //Select( oClienti )
          oClienti:SetOrder( nOrden ) // return to old index

        IF oGrid != NIL
           oGrid:Refresh()
           oGrid:SetFocus( .t. )
          ENDIF

          RETURN lReturn

//------------------------------------------------------------//
  static function Duplicate_Record()
   Local oClienteTemp   := oClienti:Record()
   Local oClienteNew

       oClienteTemp:Copy()
       oClienteNew   := oClienti:Record( , .t. )
       oClienteNew:Paste() // paste contents from memory
       oClienteNew:Edit()

       return nil
//-----------------------------------------------------------------//
       static function RefreshCont( oCont, oDbf )

    oCont:settext(  tran( oDbf:KeyNo(),'@E 999,999')+"
/ "+tran(oDbf:KeyCount(),'@E 999,999'))
    oCont:refresh()

    RETURN nil

Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 7061
Joined: Thu Oct 18, 2012 7:17 pm

Next

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 79 guests