On Fri, 25 Apr 2008, Szakáts Viktor wrote: Hi Viktor, sorry for the delay.
> Could you pls reattach the modified br.prg? It looks > this one was the original file. Ups, my fault. I'm attaching modified version. > Do you think there is any reasonable way to avoid > to infamous "roll up" problem in any ways? > This might have something to do with your point 2. > See below the conversation about the "roll up" > problem. It basically means that in "certain" situations > the user will experience the browse to start going > up one by one until it reaches the beginning of the > table. It will happen when some filtered records will disappear due to concurent access. TBrowse does not know anything about data source. It means it's possible to desynchronize the data in the cache with real data. Each tbrowse implementation will have such problem until it will not be extended with additional data attribute which will have unique record ID (RecNo() is good enough) to detect it. Additionaly it should have an mechanism for scope checking and automatic refreshing when it will detect out of scope positioning. In summary it's not sth what can be easy added though it should be possible to add some smaller modifications to TBrowse and it will be possible for user to implement such functionality in child class. I'll think about it. best regards, Przemek
STATIC s_nCount := 0 STATIC s_cCurrBlock := "" STATIC s_cResult1 STATIC s_cResult2 #translate TEST_CALL( <x> ) => TEST_C_CALL( o, #<x>, {|| <x> } ) FUNCTION Main() LOCAL o LOCAL nOldRecNo LOCAL tmp // AltD() dbCreate( "_test", {{ "ID", "C", 10, 0 }} ) USE _test NEW EXCLUSIVE ALIAS w_TEST dbAppend() ; w_TEST->ID := "01" dbAppend() ; w_TEST->ID := "02" dbAppend() ; w_TEST->ID := "03" dbAppend() ; w_TEST->ID := "04" o := TBrowseNew( 0, 0, 6, 8 ) o:GoTopBlock := { || nOldRecNo := RecNo(), dbGoTop(), my_QOut( o, { "TOP", RecNo(), nOldRecNo } ) } o:GoBottomBlock := { || nOldRecNo := RecNo(), dbGoBottom(), my_QOut( o, { "BOT", RecNo(), nOldRecNo } ) } o:SkipBlock := { | nRecs | nOldRecNo := RecNo(), tmp := Skipped( nRecs ), my_QOut( o, { "SKP", RecNo(), nOldRecNo, nRecs, tmp } ), tmp } o:AddColumn( TBColumnNew( "#", {|| my_QOut( NIL, { "BLK", RecNo() } ), StrZero( RecNo(), 3 ) } ) ) #define Inkey(x) CLS TEST_CALL( o:leftVisible ) TEST_CALL( o:goTop() ) TEST_CALL( ForceStable( o ) ) TEST_CALL( o:goTop() ) TEST_CALL( o:pageUp() ) TEST_CALL( ForceStable( o ) ) TEST_CALL( o:goTop() ) TEST_CALL( o:pageDown() ) TEST_CALL( ForceStable( o ) ) TEST_CALL( o:goBottom() ) TEST_CALL( ForceStable( o ) ) TEST_CALL( o:goBottom() ) TEST_CALL( o:pageUp() ) TEST_CALL( ForceStable( o ) ) TEST_CALL( o:goBottom() ) TEST_CALL( o:pageDown() ) TEST_CALL( ForceStable( o ) ) TEST_CALL( o:leftVisible ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:rowPos ) TEST_CALL( o:rowPos ) TEST_CALL( dbGoTop() ) TEST_CALL( ForceStable( o ) ) TEST_CALL( o:goTop() ) TEST_CALL( o:goBottom() ) TEST_CALL( ForceStable( o ) ) TEST_CALL( o:up() ) TEST_CALL( o:up() ) TEST_CALL( o:down() ) // dbGoTop() TEST_CALL( ForceStable( o ) ) TEST_CALL( o:PageUp() ) TEST_CALL( ForceStable( o ) ) o:goTop() o:forceStable() TEST_CALL( o:down() ) TEST_CALL( o:down() ) TEST_CALL( o:PageDown() ) TEST_CALL( o:PageDown() ) TEST_CALL( o:PageUp() ) TEST_CALL( ForceStable( o ) ) Inkey(0) TEST_CALL( o:goTop() ) TEST_CALL( o:PageDown() ) TEST_CALL( ForceStable( o ) ) Inkey(0) TEST_CALL( o:goTop() ) TEST_CALL( o:down() ) TEST_CALL( ForceStable( o ) ) Inkey(0) TEST_CALL( o:goTop() ) TEST_CALL( o:down() ) TEST_CALL( o:down() ) TEST_CALL( o:down() ) TEST_CALL( o:down() ) TEST_CALL( o:down() ) TEST_CALL( o:down() ) TEST_CALL( ForceStable( o ) ) Inkey(0) TEST_CALL( o:goBottom() ) TEST_CALL( ForceStable( o ) ) Inkey(0) TEST_CALL( o:goBottom() ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) Inkey(0) TEST_CALL( o:goBottom() ) TEST_CALL( o:pageDown() ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) Inkey(0) TEST_CALL( o:goTop() ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) Inkey(0) TEST_CALL( o:goTop() ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:down() ) TEST_CALL( o:stabilize ) Inkey(0) TEST_CALL( o:goTop() ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:down() ) TEST_CALL( o:down() ) TEST_CALL( o:down() ) TEST_CALL( o:down() ) TEST_CALL( o:down() ) TEST_CALL( o:down() ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) TEST_CALL( o:stabilize ) Inkey(0) /* o:Stabilize() o:Up() o:Down() o:PageUp() o:PageDown() o:GoTop() o:GoBottom() */ RETURN NIL STATIC FUNCTION Skipped( nRecs ) LOCAL nSkipped := 0 IF LastRec() != 0 IF nRecs == 0 dbSkip( 0 ) ELSEIF nRecs > 0 .AND. RecNo() != LastRec() + 1 DO WHILE nSkipped < nRecs dbSkip() IF Eof() dbSkip( -1 ) EXIT ENDIF nSkipped++ ENDDO ELSEIF nRecs < 0 DO WHILE nSkipped > nRecs dbSkip( -1 ) IF Bof() EXIT ENDIF nSkipped-- ENDDO ENDIF ENDIF RETURN nSkipped FUNCTION XToStrE( xValue ) LOCAL cType := ValType( xValue ) DO CASE CASE cType == "C" xValue := StrTran( xValue, Chr(0), '"+Chr(0)+"' ) xValue := StrTran( xValue, Chr(9), '"+Chr(9)+"' ) xValue := StrTran( xValue, Chr(10), '"+Chr(10)+"' ) xValue := StrTran( xValue, Chr(13), '"+Chr(13)+"' ) xValue := StrTran( xValue, Chr(26), '"+Chr(26)+"' ) RETURN xValue CASE cType == "N" ; RETURN LTrim( Str( xValue ) ) CASE cType == "D" ; RETURN DToS( xValue ) CASE cType == "L" ; RETURN iif( xValue, ".T.", ".F." ) CASE cType == "O" ; RETURN xValue:className() + " Object" CASE cType == "U" ; RETURN "NIL" CASE cType == "B" ; RETURN '{||...} -> ' + XToStrE( Eval( xValue ) ) CASE cType == "A" ; RETURN '{ ' + ArrayToEList( xValue ) + ' }' CASE cType == "M" ; RETURN 'M:' + xValue ENDCASE RETURN "" FUNCTION ArrayToEList( a ) LOCAL tmp LOCAL cString := "" FOR tmp := 1 TO Len( a ) cString += XToStrE( a[ tmp ] ) IF tmp < Len( a ) cString += ", " ENDIF NEXT RETURN cString FUNCTION ForceStable( o ) DO WHILE !TEST_CALL( o:stabilize ) ENDDO RETURN NIL FUNCTION TEST_C_CALL( o, cBlock, bBlock ) LOCAL xRetVal LOCAL cOldBlock := s_cCurrBlock s_cCurrBlock := cBlock LOGSTUFF( o, .T., "BEGIN" ) xRetVal := Eval( bBlock ) LOGSTUFF( o, .T., "END" ) s_cCurrBlock := cOldBlock RETURN xRetVal FUNCTION LOGSTUFF( o, l, cText ) STATIC s_nRow := 0 LOCAL nLevel := 16 IF s_nRow == MaxRow() Scroll( 0, 16, MaxRow(), MaxCol(), 1, 0 ) DispOutAt( MaxRow(), 0, Space( MaxCol() + 1 ) ) ELSE s_nRow++ ENDIF #define DispOut( x ) OutStd( x ) WHILE procline(--nLevel)==0 ENDDO //nLevel:=2 SetPos( s_nRow, 16 + iif( l, 0, 3 ) ) ++s_nCount DispOut( padr(procname(nLevel),10)+":"+strzero(procline(nLevel),3) ) //DispOut( s_nCount ) DispOut( " " ) DispOut( PadR( iif( l, s_cCurrBlock, "" ), 11 ) ) ; DispOut( " " ) DispOut( iif( o != NIL, o:rowPos, PadL( "", 10 ) ) ) ; DispOut( " " ) DispOut( cText ) ; DispOut( " " ) DispOut( /* Chr( 13 ) + */ Chr( 10 ) ) RETURN NIL FUNCTION my_QOut( o, a ) LOGSTUFF( o, .F., ArrayToEList( a ) ) RETURN NIL
_______________________________________________ Harbour mailing list Harbour@harbour-project.org http://lists.harbour-project.org/mailman/listinfo/harbour