xbrowse, dbf and codeblock

Post Reply
JoséQuintas
Posts: 55
Joined: Tue Feb 09, 2021 4:20 pm

xbrowse, dbf and codeblock

Post by JoséQuintas »

Image

Using DBF.
When define a codeblock for skip, xbrowse update fail.

Code: Select all | Expand

   @ 70, 10 XBROWSE xControl ;
      DATASOURCE Alias() ;
      SIZE nDlgWidth - 24, nDlgHeight - 100 PIXEL ;
      OF xDlg ;
      ON DBLCLICK ( (nRow), (nCol), (nFlags), FWBrowseENTER( xDlg, xControl ) )

   WITH OBJECT xControl
      :SetRdd()
      :bGoTop    := { || ( nSelect )->( FazBrowseTop() ) }
      :bGoBottom := { || ( nSelect )->( FazBrowseBottom() ) }
      :bSkip     := { | n | ( nSelect )->( FazBrowseSkip( n ) ) }
      //:bBof      := { || Bof() }
      //:bEof      := { || Eof() }
      //:bBookMark := { | n | iif( n == nil, RecNo(), DbGoto( n ) ) }
   ENDWITH
   ...
   STATIC FUNCTION FazBrowseSkip( nSkip )

   LOCAL nSkipped := 0

   IF Empty( nSkip  )
      RETURN 0
   ENDIF
   IF nSkip > 0
      DO WHILE nSkipped < nSkip
         SKIP
         IF Eof()
            SKIP -1
            EXIT
         ENDIF
         nSkipped++
      ENDDO
   ELSE
      DO WHILE nSkipped > nSkip
         SKIP -1
         IF Bof()
            SKIP
            EXIT
         ENDIF
         nSkipped--
      ENDDO
   ENDIF

   RETURN nSkipped
   
User avatar
nageswaragunupudi
Posts: 10701
Joined: Sun Nov 19, 2006 5:22 am
Location: India
Been thanked: 3 times
Contact:

Re: xbrowse, dbf and codeblock

Post by nageswaragunupudi »

To create xBrowse, this is enough

Code: Select all | Expand

   @ 70, 10 XBROWSE xControl ;
      DATASOURCE Alias() ;
      SIZE nDlgWidth - 24, nDlgHeight - 100 PIXEL ;
      OF xDlg ;
      ON DBLCLICK ( (nRow), (nCol), (nFlags), FWBrowseENTER( xDlg, xControl ) )
XBrowse automatically generates all navigation codeblocks internally and correctly for all known datasources like arrays, hashes, dbf, ado-recordsets and all other known classes.

Please do not write our own navigation codeblocks.

Also, another small note:

Code: Select all | Expand

      SIZE nDlgWidth - 24, nDlgHeight - 100 PIXEL ;
You can simply write

Code: Select all | Expand

 SIZE -24,-100 PIXEL
This works even when the dialog is resized

Finally, end with

Code: Select all | Expand

xControl:CreateFromCode()
Regards

G. N. Rao.
Hyderabad, India
JoséQuintas
Posts: 55
Joined: Tue Feb 09, 2021 4:20 pm

Re: xbrowse, dbf and codeblock

Post by JoséQuintas »

nageswaragunupudi wrote: Thu Jan 23, 2025 5:32 am XBrowse automatically generates all navigation codeblocks internally and correctly for all known datasources like arrays, hashes, dbf, ado-recordsets and all other known classes.
Please do not write our own navigation codeblocks.
Yes, for a standard navigation.
What to do when I need a not default navigation for dbf?
I think codeblocks are available on xbrowse to do things like this, in same way as harbour tbrowse.
Am I wrong ?
User avatar
nageswaragunupudi
Posts: 10701
Joined: Sun Nov 19, 2006 5:22 am
Location: India
Been thanked: 3 times
Contact:

Re: xbrowse, dbf and codeblock

Post by nageswaragunupudi »

These are the default codeblocks for a normal DBF.

Code: Select all | Expand

::bGoTop    := {|| ( ::cAlias )->( DbGoTop() ) }
::bGoBottom := {|| ( ::cAlias )->( DbGoBottom() ) }
::bSkip     := {| n | ( ::cAlias )->( DbSkipper( IfNil( n, 1 ) ) ) }
::bBof      := {|| ( ::cAlias )->( Bof() ) }
::bEof      := {|| ( ::cAlias )->( Eof() ) }
::bBookMark := {| n | iif( n == nil
                          ( ::cAlias )->( RecNo() )
                          ( ::cAlias )->( DbGoto( n );
                         ) ) }

::bKeyNo    := {| n | iif( n == nil
                         ( ::cAlias )->( OrdKeyNo() )
                         ( ::cAlias )->( OrdKeyGoto( n );
                         ) ) }
::bKeyCount := {|| ( ::cAlias )->( If( eof() .and. bof(), 0, OrdKeyCount() ) ) }
Note: There are minor variations for SQLRDD, ADS, Large DBFCDX

If we need a different navigational behavior, we need to change these codeblocks consistent with each other.
Regards

G. N. Rao.
Hyderabad, India
JoséQuintas
Posts: 55
Joined: Tue Feb 09, 2021 4:20 pm

Re: xbrowse, dbf and codeblock

Post by JoséQuintas »

On a first momment anything is wrong.

Code: Select all | Expand

   WITH OBJECT xControl
      :SetRdd()
      :bGoTop    := {|| ( :cAlias )->( DbGoTop() ) }
      :bGoBottom := {|| ( :cAlias )->( DbGoBottom() ) }
      :bSkip     := {| n | ( :cAlias )->( DbSkipper( IfNil( n, 1 ) ) ) }
      :bBof      := {|| ( :cAlias )->( Bof() ) }
      :bEof      := {|| ( :cAlias )->( Eof() ) }
      :bBookMark := {| n | iif( n == nil,;
         ( :cAlias )->( RecNo() ),;
         ( :cAlias )->( DbGoto( n );
         ) ) }

      //:bGoTop    := { || ( nSelect )->( FazBrowseTop() ) }
      //:bGoBottom := { || ( nSelect )->( FazBrowseBottom() ) }
      //:bSkip     := { | n | ( nSelect )->( FazBrowseSkip( n ) ) }
      //:bBof      := { || Bof() }
      //:bEof      := { || Eof() }
      //:bBookMark := { | n | iif( n == nil, RecNo(), DbGoto( n ) ) }
   ENDWITH
   
With same codeblocks, it is expected same result.

Will test again, may be harbour behaviour about WITH OBJECT construction/execution
I discover about this some months ago, after began to use fivewin.
User avatar
nageswaragunupudi
Posts: 10701
Joined: Sun Nov 19, 2006 5:22 am
Location: India
Been thanked: 3 times
Contact:

Re: xbrowse, dbf and codeblock

Post by nageswaragunupudi »

Note:
The codeblock bSkip uses the function:
nSkipped := DbSkipper( nRecs ) // xHarbour
nSkipped := __DbSkipper( nRecs ) // Harbour

The functionality is similar to this function

Code: Select all | Expand

function MyDbfSkipper( nRecs )

   local nKeyFrom := OrdKeyNo()
   
   DBSKIP( nRecs )
   if Eof()
      DbGoBottom()
   elseif Bof(
      DbGoTop()
   endif
   
return OrdKeyNo() - nKeyFrom
Regards

G. N. Rao.
Hyderabad, India
JoséQuintas
Posts: 55
Joined: Tue Feb 09, 2021 4:20 pm

Re: xbrowse, dbf and codeblock

Post by JoséQuintas »

Yes
It is it !
Harbour behaviour using WITH OBJECT !
Check this code:

Code: Select all | Expand

#include "hbclass.ch"

PROCEDURE Main()

   LOCAL a, b, x

   SetMode(30,100)
   CLS

   a := AnyClass():New()
   b := AnyClass():New()

   WITH OBJECT a
      :Value := 10
      x := { || :Value } // created here, seems a:Value
   ENDWITH
   WITH OBJECT b
      ? a:Value
      ? b:Value
      ? eval( x ) // executed here, results b:Value
   ENDWITH
   Inkey(0)

   RETURN

CREATE CLASS AnyClass

   VAR Value INIT 0

   ENDCLASS
seems that result will be 10, 10, 0
but result is 10, 0, 0

x is created inside WITH a, but do not have defined object, it is not a:value
when used inside WITH b, x return b:value not a:value
The same occurs when define codeblocks for xbrowse.

Solution is to use full name.
WITH OBJECT need caution when creating codeblock.
I forgot about this.

This works ok, with full name.

Code: Select all | Expand


   WITH OBJECT xControl
      xControl:SetRdd()
      xControl:bGoTop    := {|| ( xControl:cAlias )->( DbGoTop() ) }
      xControl:bGoBottom := {|| ( xControl:cAlias )->( DbGoBottom() ) }
      xControl:bSkip     := {| n | ( xControl:cAlias )->( DbSkipper( IfNil( n, 1 ) ) ) }
      xControl:bBof      := {|| ( xControl:cAlias )->( Bof() ) }
      xControl:bEof      := {|| ( xControl:cAlias )->( Eof() ) }
      xControl:bBookMark := {| n | iif( n == nil,;
         ( xControl:cAlias )->( RecNo() ),;
         ( xControl:cAlias )->( DbGoto( n );
         ) ) }
JoséQuintas
Posts: 55
Joined: Tue Feb 09, 2021 4:20 pm

Re: xbrowse, dbf and codeblock

Post by JoséQuintas »

Extra comment:

May be this expains why a external database works, and internal may not.
As example using mysql.

Internal

Code: Select all | Expand

WITH OBJECT xbrowse
   :bGoTop := { || :Rs:MoveFirst() } // may use wrong object, anything:Rs:MoveFirst()
ENDWITH   
External

Code: Select all | Expand

WITH OBJECT xBrowse
   :bGoTop := RS:MoveNext() // use right object, RS
ENDWITH
I had same problem using ADO, but I forgot about this.
Not easy to remember issues on not common situations.
May be interesting to include about this on documentation of xbrowse, and on source code too.

Code: Select all | Expand

   // Code-blocks for navitation
   // Caution: Use allways full name for codeblocks, WITH OBJECT may fail

   DATA bGoTop,;     // codeblock for going to first row
        bGoBottom,;  // codeblock for going to last row
        bSkip,;      // codeblock for skiping rows, it receives the number of rows
JoséQuintas
Posts: 55
Joined: Tue Feb 09, 2021 4:20 pm

Re: xbrowse, dbf and codeblock

Post by JoséQuintas »

Another thing is a visible bug on xbrowse.

Code: Select all | Expand

      xControl:bSkip     := {| n | ( xControl:cAlias )->( DbSkipper( IfNil( n, 1 ) ) ) }
Xbrowse requires to skip NIL records.
When xbrowse requires NIL records, it is needed to change to 1.

Code: Select all | Expand

METHOD Skip( n ) CLASS TXBrowse

   local nStart
   local nSkipped := 0

   if !::lClosed
      TRY
         if Empty( ::aFilter )
            nSkipped := Eval( ::bSkip, n, Self )
         else
            nStart      := ::nFltRow
            ::GoFltRow( ::nFltRow + IfNil( n, 1 ) )
            nSkipped    := ::nFltRow - nStart
         endif
      CATCH
         ::nLen      := 0
         ::lClosed   := .t.
      END
   endif

return nSkipped
Looking to method skip, one more test about Nil

Could be changed to

Code: Select all | Expand

hb_Default( @n, 1 )
If needed for xharbour:

Code: Select all | Expand

FUNCTION hb_Default( a, b )
   IF valType( a ) != ValType( b )
       a := b
     ENDIF
     RETURN Nil
New source

Code: Select all | Expand

METHOD Skip( n ) CLASS TXBrowse

   local nStart
   local nSkipped := 0

   if !::lClosed
      TRY
         hb_Default( @n, 1 )
         if Empty( ::aFilter )
            nSkipped := Eval( ::bSkip, n, Self )
         else
            nStart      := ::nFltRow
            ::GoFltRow( ::nFltRow + n )
            nSkipped    := ::nFltRow - nStart
         endif
      CATCH
         ::nLen      := 0
         ::lClosed   := .t.
      END
   endif

return nSkipped
Not sure if it is needed the TRY/CATCH.
This is the reason why we see xbrowse fail, but do not know that anything is wrong on bSkip codeblock. (as example the Nil)
User avatar
nageswaragunupudi
Posts: 10701
Joined: Sun Nov 19, 2006 5:22 am
Location: India
Been thanked: 3 times
Contact:

Re: xbrowse, dbf and codeblock

Post by nageswaragunupudi »

Thanks for your concern and efforts.

1)
seems that result will be 10, 10, 0
but result is 10, 0, 0
Looking at the code, any programmer should expect the result to be 10,0,0 and in fact the result is 10,0,0.

2)
WITH OBJECT xbrowse
:bGoTop := { || :Rs:MoveFirst() } // may use wrong object, anything:Rs:MoveFirst()
ENDWITH
Please check again. XBrowse program does not have any such defective code.

In contrast,

Code: Select all | Expand

::bGoTop := { || ::oRs:MoveFirst() }
This works perfectly.

Not only XBrowse, there is no module in FWH using such defective code.

3)
May be interesting to include about this on documentation of xbrowse, and on source code too.
// Code-blocks for navitation
// Caution: Use allways full name for codeblocks, WITH OBJECT may fail[/quote]

This is nothing specific to xBrowse or Fivewin. This is what every (x)Harbour programmer is expected to know.

4)
This is the reason why we see xbrowse fail, but do not know that anything is wrong on bSkip codeblock. (as example the Nil)
XBrowse never fails on Skip().
We do not expect any programmer to use non numeric values.

5)
We appreciate that a function like hb_default is safer than IfNil.

6)
we see xbrowse fail
To the best of our knowledge and experience, xbrowse never fails on such issues.
If you find that XBrowse is failing at times, you may like to help FWH and our community by providing a sample program to demonstrate such a failure.

Thanks again for your interest and time to help improve xbrowse.
Regards

G. N. Rao.
Hyderabad, India
Post Reply