Virtual Grid bug?

HMG en Español

Moderator: Rathinagiri

Post Reply
User avatar
danielmaximiliano
Posts: 2611
Joined: Fri Apr 09, 2010 4:53 pm
Location: Argentina
Contact:

Virtual Grid bug?

Post by danielmaximiliano »

HI :
there is an error when compiling an application with Virtual Grid.

HMG reference say:
DEFINE GRID <ControlName>
.....................
VIRTUAL <lValue>
.......................
END GRID

Compile OK:

Code: Select all

/*
* HMG Virtual Grid Demo
* (c) 2003 Roberto Lopez
*/

#include "hmg.ch"

Function Main
	public aElem := {}
		
	for i:= 1 to 1000
		aadd( aElem, {  i, .T., 1 })
	next
	
	DEFINE WINDOW Form_1 AT 0,0 ;
		WIDTH 650 HEIGHT 400; 
		TITLE 'Hello World!' MAIN 
    
		DEfine  GRID Grid_1 
		Parent Form_1
		Row 10
		Col 10
		WIDTH 400
		HEIGHT 330 
		HEADERS         {'Number'               ,'Boolean'              ,'Number'} 
		WIDTHS          {100                    ,100                    , 100}
		Items aElem
		COLUMNCONTROLS {{'TEXTBOX','NUMERIC'  } ,{'CHECKBOX','Si','No' },{'COMBOBOX',{'Uno','Dos','Tres'}} }
		Value 1
		Virtual .F.
		Itemcount 1000
		End Grid
			 
	END WINDOW
	
	CENTER WINDOW Form_1
	ACTIVATE WINDOW Form_1

Return
ok virtual_2011-10-25_19-37-47.png
ok virtual_2011-10-25_19-37-47.png (56.33 KiB) Viewed 5959 times

Fail :

Code: Select all

/*
* HMG Virtual Grid Demo
* (c) 2003 Roberto Lopez
*/

#include "hmg.ch"

Function Main
	public aElem := {}
		
	for i:= 1 to 1000
		aadd( aElem, {  i, .T., 1 })
	next
	
	DEFINE WINDOW Form_1 AT 0,0 ;
		WIDTH 650 HEIGHT 400; 
		TITLE 'Hello World!' MAIN 
    
		DEfine  GRID Grid_1 
		Parent Form_1
		Row 10
		Col 10
		WIDTH 400
		HEIGHT 330 
		HEADERS         {'Number'               ,'Boolean'              ,'Number'} 
		WIDTHS          {100                    ,100                    , 100}
		Items aElem
		COLUMNCONTROLS {{'TEXTBOX','NUMERIC'  } ,{'CHECKBOX','Si','No' },{'COMBOBOX',{'Uno','Dos','Tres'}} }
		Value 1
		Virtual .T.
		Itemcount 1000
		End Grid
			 
	END WINDOW
	
	CENTER WINDOW Form_1
	ACTIVATE WINDOW Form_1

Return
Fail virtual_2011-10-25_19-37-47.png
Fail virtual_2011-10-25_19-37-47.png (61.66 KiB) Viewed 5959 times
happens in HMG4?
*´¨)
¸.·´¸.·*´¨) ¸.·*¨)
(¸.·´. (¸.·` *
.·`. Harbour/HMG : It's magic !
(¸.·``··*

Saludos / Regards
DaNiElMaXiMiLiAnO

Whatsapp. := +54901169026142
Telegram Name := DaNiElMaXiMiLiAnO
JosK
Posts: 46
Joined: Tue Nov 08, 2011 11:38 pm

Re: Virtual Grid bug?

Post by JosK »

i have made some changes to virtualgrid (first copyéd virtualgrid.prg to jkGrid.prg).
Notes:
with filecompare you can find the change.


*
* $Id: virtualgrid.prg 806 2011-11-22 12:14:57Z fperillo $
*/

/*
* HMG Source Code
*
* Copyright 2010 Carlos Bacco <carlosbacco at gmail.com>
* www - http://harbour-project.org
*
* Copyright 2002-2010 Roberto Lopez <mail.box.hmg@gmail.com>
* http://sites.google.com/site/hmgweb/
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or( at your option ) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License FOR more details.
*
* You should have received a copy of the GNU General Public License along with
* this software; see the file COPYING. IF not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA( or
* visit the web site http://www.gnu.org/ ).
*
* As a special exception, you have permission FOR additional uses of the text
* contained in this release of HMG.
*
* The exception is that, IF you link the HMG library with other
* files to produce an executable, this does not by itself cause the resulting
* executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of linking the
* HMG library code into it.
*/

#include "hbclass.ch"
#include "common.ch"
#include "hbqtgui.ch"
#include "hmg.ch"


/*----------------------------------------------------------------------*/

CLASS JKGRID FROM ABSTRACTGRID

* Internal Data

DATA cClass INIT "VIRTUALGRID"
DATA QAbstractItemModel INIT NIL
DATA nCellRowIndex INIT 0
DATA nCellColIndex INIT 0
DATA aStruct INIT {}
DATA QHeaderView INIT NIL
DATA oSize INIT NIL
DATA nCX INIT 0
DATA nCY INIT 0
DATA QAbstractItemDelegate INIT NIL
DATA QItemSelectionModel INIT NIL
DATA nCurrent INIT NIL
DATA nNew INIT NIL
DATA nDiff INIT NIL
DATA nMasterItemNo INIT NIL
DATA nMasterRecNo INIT NIL
DATA nItemCount INIT 0
DATA nRecordCount INIT 0
DATA oQHeaderView INIT NIL
DATA nValue INIT NIL
DATA xValue INIT NIL

DATA lCellNavigation INIT NIL
DATA nLockColumns INIT NIL

* Data Variables FOR in-place edit

DATA oCurrentWidget INIT NIL
DATA xOldValue INIT NIL
DATA lCellActive INIT .F.
DATA lCellChangeActive INIT .F.
DATA oCellQTObject INIT NIL
DATA nOldRow INIT 0
DATA lReturnValueOnEnter INIT .F.
DATA bOnInitCellEditor INIT NIL

* Properties

METHOD Value SETGET
METHOD CellNavigation SETGET
METHOD LockColumns SETGET
METHOD MultiSelect SETGET
METHOD ItemCount SETGET
METHOD ColumnControls SETGET
METHOD Cell SETGET
METHOD Item SETGET
METHOD Items SETGET

* Events
METHOD OnChange SETGET

* Methods
METHOD New
METHOD Create
METHOD OnSave
METHOD OnSelect
METHOD setItemPos
METHOD setRecordPos

METHOD AddColumn
METHOD DeleteColumn
METHOD DeleteItem
METHOD DeleteAllItems
METHOD AddItem
METHOD Refresh

* FOR inplace edit
METHOD DoKeyBoardEvents SETGET
METHOD DefineCellcontrol SETGET
METHOD DoCellKeyBoardEvents SETGET
METHOD CellDoubleClicked SETGET
METHOD CloseCell

ENDCLASS

/*----------------------------------------------------------------------*/
* Properties
/*----------------------------------------------------------------------*/

METHOD Value( xValue ) CLASS JKGRID
LOCAL aValue := {}
LOCAL oModelIndex, i, j, nCurrentArea

IF ! ::lCreated
::xValue := xValue
RETURN Self
ENDIF

DO CASE
CASE ::nMODE == ARRAY_MODE
IF Pcount() == 0
IF LEN( ::aItems ) == 0
IF ::lCellNavigation .OR. ::lMultiSelect
RETURN {}
ELSE
RETURN 0
ENDIF
ENDIF
IF ::lCellNavigation
IF !::lMultiSelect // cellnavigation ON MultiSelect OFF
oModelIndex := ::QItemSelectionModel:currentIndex()
RETURN { oModelIndex:row() + 1, oModelIndex:column() + 1 }
ELSE // cellnavigation ON MultiSelect ON
* Not Implemeted QModelIndexList Therefore dirtyway
* * oModelIndexList := QModelIndexList( ::oQTObject:selectedIndexes() )
* * FOR i := 0 to oModelIndexList:Size() - 1
* * oModelIndex := QModelIndex( oModelIndexList:At( i ) )
* * nRow := oModelIndex:Row() + 1
* * nCol := oModelIndex:Column() + 1
* * aAdd( aValue,{nRow,nCol} )
* * NEXT i
FOR i := 1 TO LEN( ::aItems )
FOR j := 1 TO LEN ( ::aItems[ i ] )
oModelIndex := ::QAbstractItemModel:index( i - 1, j - 1, QModelIndex() )
IF ::QItemSelectionModel:isSelected( oModelIndex )
aadd( aValue, {i,j} )
ENDIF
NEXT j
NEXT i
RETURN aValue
ENDIF
ELSE
IF !::lMultiSelect // cellnavigation OFF MultiSelect OFF
::setItemPos( ::nCy )
RETURN ::nMasterItemNo
ELSE // cellnavigation OFF MultiSelect ON
* QModelIndexList not yet implemented Hence dirty way
* * oModelIndexList := QModelIndexList( ::oQTObject:selectedIndexes() )
* * FOR i := 0 to oModelIndexList:Size() - 1
* * oModelIndex := QModelIndex( oModelIndexList:At( i ) )
* * nRow := oModelIndex:Row() + 1
* * IF aScan( aValue,nRow ) == 0
* * aAdd( aValue,nRow )
* * ENDIF
* * NEXT i
FOR i := 1 TO LEN( ::aItems )
FOR j := 1 TO LEN ( ::aItems[ i ] )
oModelIndex := ::QAbstractItemModel:index( i - 1, j - 1, QModelIndex() )
IF ::QItemSelectionModel:isSelected( oModelIndex )
IF aScan( aValue,i ) == 0
aAdd( aValue,i )
ENDIF
ENDIF
NEXT j
NEXT i
RETURN aValue
ENDIF
ENDIF
ELSEIF Pcount() == 1
IF ::lCellNavigation
IF !::lMultiSelect // CellNavigation ON MultiSelect OFF
oModelIndex := ::QAbstractItemModel:index( xValue[1] - 1, xValue[2] - 1, QModelIndex() )
::oQTObject:setCurrentIndex( oModelIndex )
ELSE // CellNavigation ON MultiSelect ON
::oQTObject:ClearSelection()
FOR i := 1 to len( xValue )
oModelIndex := ::QAbstractItemModel:index( xValue[i,1] - 1, xValue[i,2] - 1, QModelIndex() )
::QItemSelectionModel:select( oModelIndex, 0x0002 )
NEXT i
::oQTObject:setSelectionModel( ::QItemSelectionModel )
ENDIF
ELSE
IF !::lMultiSelect // CellNavigation OFF MultiSelect OFF
::oQTObject:selectRow( xValue - 1 )
ELSE // CellNavigation OFF MultiSelect ON
::oQTObject:ClearSelection()
FOR i := 1 TO len( xValue )
FOR j := 1 TO LEN( ::aItems[ xValue[ i ] ] )
oModelIndex := ::QAbstractItemModel:index( xValue - 1, j - 1, QModelIndex() )
::QItemSelectionModel:select( oModelIndex, 0x0002 )
NEXT j
NEXT i
::oQTObject:setSelectionModel( ::QItemSelectionModel )
ENDIF
ENDIF
ENDIF
CASE ::nMode == DATA_MODE

/* PLEASE BE CAREFUL: NEVER USE A MSGINFO HERE ! */
/* when msginfo exists, Qt redraws the screen and recno()/ordkeyno()/etc ARE WRONG */

IF Pcount() == 0
::setRecordPos( ::nCy )
RETURN ::nMasterRecNo
ELSEIF Pcount() == 1
IF empty( &( ::cWorkArea )->( dbFilter() ) )
&( ::cWorkArea )->( dbGoTo( xValue ) )
::oQTObject:setCurrentIndex( ::QAbstractItemModel:index( &( ::cWorkArea )->( OrdKeyNo() ) - 1 , ::nCX , QModelIndex() ) )
ELSE
nCurrentArea := Select()
dbselectarea( ::cWorkArea )
dbGoTop()
DO WHILE .not. eof()
IF recno() == xValue
::oQTObject:setCurrentIndex( ::QAbstractItemModel:index( i - 1 , ::nCX , QModelIndex() ) )
EXIT
ENDIF
i++
skip
ENDDO
dbselectarea( nCurrentArea )
ENDIF
ENDIF
ENDCASE
::xValue := xValue
RETURN Self

/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
* Events
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
* Methods
/*----------------------------------------------------------------------*/

/*..............................................................................
New
..............................................................................*/
METHOD New( cName, oParent ) CLASS JKGRID

::aItems := {}
::aColumnHeaders := {}

Super:New( cName, oParent )

IF hb_IsObject( ::oParent )
::oQtObject := QTableView( ::oParent:QtParent ) //QTableView( ::oParent:QtObject )
ELSE
::oQtObject := QTableView()
ENDIF

::oQtFont := ::oQtObject:font()
::oQtObject:setFocusPolicy( Qt_StrongFocus )
// ::oQtObject:setAutoFillBackground( .T. )

// default cell navigation and multiselect .F.
::CellNavigation := .F.
::MultiSelect := .F.
::showHeaders := .F.
::showColHeader( .T. )

RETURN Self

/*----------------------------------------------------------------------*/

METHOD Create() CLASS JKGRID
LOCAL i

::oSize := QSize( 24,24 )

::lCreated := .T.
DO CASE
CASE ::nMode == DATA_MODE
IF empty( ::aColumnFields ) .and. ;
empty( ::aColumnHeaders ) .and. ;
empty( ::aColumnWidths ) .and. ;
hb_IsChar( ::cWorkArea )

::aStruct := &( ::cWorkArea )->( DBStruct() )
::aColumnFields := {}
::aColumnHeaders := {}
FOR i := 1 to len( ::aStruct )
aadd( ::aColumnFields , ::aStruct[i,1] )
aadd( ::aColumnHeaders, ::aStruct[i,1] )
NEXT i
ELSE

::aStruct := {}
FOR i := 1 to len( ::aColumnFields )
aadd( ::aStruct , { ::aColumnFields , Type( ::aColumnFields ) , fieldlen( FieldPos( ::aColumnFields ) ), FieldDec( FieldPos( ::aColumnFields ) ) } )

NEXT i
ENDIF
CASE ::nMode == ARRAY_MODE
::aStruct := {}
FOR i := 1 to len( ::aColumnHeaders )
IF hb_IsArray( ::aColumnControls )
DO CASE
CASE upper( ::aColumnControls [i, 1] ) == 'TEXTBOX'
DO CASE
CASE upper( ::aColumnControls [i, 2] ) == 'CHARACTER'
aadd( ::aStruct , { ::aColumnHeaders , 'C' , 0 , 0 } )
CASE upper( ::aColumnControls [i, 2] ) == 'NUMERIC'
aadd( ::aStruct , { ::aColumnHeaders , 'N' , 0 , 0 } )
CASE upper( ::aColumnControls [i, 2] ) == 'DATE'
aadd( ::aStruct , { ::aColumnHeaders , 'D' , 0 , 0 } )
ENDCASE
CASE upper( ::aColumnControls [i, 1] ) == 'COMBOBOX'
aadd( ::aStruct , { ::aColumnHeaders , 'C' , 0 , 0 } )
CASE upper( ::aColumnControls [i, 1] ) == 'DATEPICKER'
aadd( ::aStruct , { ::aColumnHeaders , 'D' , 0 , 0 } )
CASE upper( ::aColumnControls [i, 1] ) == 'SPINNER'
aadd( ::aStruct , { ::aColumnHeaders [i] , 'N' , 0 , 0 } )
CASE upper( ::aColumnControls [i, 1] ) == 'CHECKBOX'
aadd( ::aStruct , { ::aColumnHeaders [i] , 'L' , 0 , 0 } )
ENDCASE
ELSE
IF LEN( ::aItems ) > 0
aadd( ::aStruct , { ::aColumnHeaders [i] , VALTYPE(::aItems[1,i]) , 0 , 0 } )
ELSE
aadd( ::aStruct , { ::aColumnHeaders [i] , 'C' , 0 , 0 } )
ENDIF
ENDIF
NEXT i
ENDCASE


::QAbstractItemModel := HBQAbstractItemModel( {| t, r, x, y| ::OnQueryData( ::aStruct , t, r, x, y ) } )
::oQTObject:setModel( ::QAbstractItemModel )

::QItemSelectionModel := ::oQTObject:selectionModel()
::QItemSelectionModel:connect( "currentChanged(QModelIndex,QModelIndex)", {| n | ::OnSelect( n ) } )

::oQTObject:verticalHeader():setDefaultSectionSize( 24 )

::QAbstractItemDelegate := ::oQTObject:itemDelegate()
::QAbstractItemDelegate:connect( "commitData(QWidget*)", {| w | ::OnSave( w ) } )

::oQTObject:connect( "doubleClicked(QModelIndex)", {| n | ::CellDoubleClicked( n )} )
::oQTObject:connect( QEvent_KeyPress , {|e|::DoKeyBoardEvents( e )} )

::oQHeaderView := QHeaderView( ::oQTObject:horizontalHeader() )
IF hb_IsArray( ::bOnHeadClick )
::oQHeaderView:disconnect( "sectionClicked(int)" )
::oQHeaderView:connect( "sectionClicked(int)",{|i| if( hb_IsBlock( ::bOnHeadClick[i+1] ), Eval( ::bOnHeadClick[i+1] ),nil ) } )
ENDIF

::QAbstractItemModel := HBQAbstractItemModel( {| t, r, x, y| ::OnQueryData( ::aStruct , t, r, x, y ) } )
::oQTObject:setModel( ::QAbstractItemModel )

::QItemSelectionModel := ::oQTObject:selectionModel()
::QItemSelectionModel:connect( "currentChanged(QModelIndex,QModelIndex)", {| n | ::OnSelect( n ) } )
::Refresh()

FOR i := 1 To Len( ::aStruct )
IF valtype( ::aColumnWidths ) = 'U'
::oQtObject:setColumnWidth( i - 1, ::aStruct[ i, 3 ] * 6 + 60 )
ELSE
::oQtObject:setColumnWidth( i - 1, ::aColumnWidths [i] )
ENDIF
NEXT

IF ::nMode == DATA_MODE
::nCurrent := 1
&( ::cWorkArea )->( dbGoTop() )
::nMasterRecNo := &( ::cWorkArea )->( recno() )
ELSE
IF VALTYPE( ::xValue ) != 'U'
::Value := ::xValue
ENDIF
ENDIF

IF hb_IsArray( ::aColumnControls )
IF LEN( ::aColumnControls ) > 0
::oQTObject:setEditTriggers( 0 )
ENDIF
ELSE
IF ::lAllowEdit
msgQuit( "Can't edit cells without setting their type.<br><br>Editing disabled", "Unsupported" )
::oQTObject:setEditTriggers( 0 )
ENDIF
ENDIF

IF ::Visible()
::oQtObject:show()
ENDIF

RETURN Self

/*----------------------------------------------------------------------*/

METHOD OnSave( pWidget ) CLASS JKGRID
LOCAL cData
LOCAL nCurrentArea, mVar
LOCAL aStru := ::aStruct
LOCAL nCX := ::nCX
LOCAL nCY := ::nCY


cData := pWidget:text()

DO CASE
CASE ::nMode == DATA_MODE
::setRecordPos( nCY )
IF hb_IsArray( ::aColumnValid )
IF hb_IsBlock( ::aColumnValid [nCX + 1] )
mVar := 'MemVar' + ::cWorkArea + aStru [ nCX+1 ] [ 1 ]
DO CASE
CASE type( aStru [ nCX+1 ] [ 1 ] ) == 'C'
&mVar := cData
CASE type( aStru [ nCX+1 ] [ 1 ] ) == 'N'
&mVar := val( cData )
CASE type( aStru [ nCX+1 ] [ 1 ] ) == 'L'
&mVar := if( upper( alltrim( cData ) ) == 'Y' , .T. , .F. )
CASE type( aStru [ nCX+1 ] [ 1 ] ) == 'D'
&mVar := ctod( cData )
ENDCASE
ENDIF
IF ! eval( ::aColumnValid [nCX + 1] )
IF hb_IsArray( ::aValidMessages )
IF hb_IsChar( ::aValidMessages [ nCX + 1 ] )
MsgStop( ::aValidMessages [ nCX + 1 ] )
ELSE
MsgStop( 'Invalid Input!' )
ENDIF
ELSE
MsgStop( 'Invalid Input!' )
ENDIF
RETURN NIL
ENDIF
ENDIF
SWITCH aStru[ nCX + 1, 2 ]
CASE "C"
nCurrentArea := Select()
dbselectarea( ::cWorkArea )
replace &( aStru [ nCX+1 ] [ 1 ] ) with AllTrim( cData )
dbselectarea( nCurrentArea )
EXIT
CASE "N"
nCurrentArea := Select()
dbselectarea( ::cWorkArea )
replace &( aStru [ nCX+1 ] [ 1 ] ) with Val( cData )
dbselectarea( nCurrentArea )
EXIT
CASE "L"
nCurrentArea := Select()
dbselectarea( ::cWorkArea )
replace &( aStru [ nCX+1 ] [ 1 ] ) with Left( cData, 1 ) $ "YyTt"
dbselectarea( nCurrentArea )
EXIT
CASE "D"
nCurrentArea := Select()
dbselectarea( ::cWorkArea )
replace &( aStru [ nCX+1 ] [ 1 ] ) with CToD( cData )
dbselectarea( nCurrentArea )
EXIT
ENDSWITCH
CASE ::nMode == ARRAY_MODE
::setItemPos( nCY )
IF hb_IsArray( ::aColumnValid )
IF hb_IsBlock( ::aColumnValid [nCX + 1] )
IF ! eval( ::aColumnValid [nCX + 1] )
IF hb_IsArray( ::aValidMessages )
IF hb_IsChar( ::aValidMessages [ nCX + 1 ] )
MsgStop( ::aValidMessages [ nCX + 1 ] )
ELSE
MsgStop( 'Invalid Input!' )
ENDIF
ELSE
MsgStop( 'Invalid Input!' )
ENDIF
RETURN NIL
ENDIF
ENDIF
ELSE
DO CASE
CASE aStru [ nCX+1 ] [ 2 ] == 'C'
::aItems [ nCY+1 ] [ nCX + 1 ] := cData
CASE aStru [ nCX+1 ] [ 2 ] == 'N'
::aItems [ nCY+1 ] [ nCX + 1 ] := val( cData )
CASE aStru [ nCX+1 ] [ 2 ] == 'L'
::aItems [ nCY+1 ] [ nCX + 1 ] := if( upper( alltrim( cData ) ) == 'Y' .OR. upper( alltrim( cData ) ) == 'T' , .T. , .F. )
CASE aStru [ nCX+1 ] [ 2 ] == 'D'
::aItems [ nCY+1 ] [ nCX + 1 ] := ctod( cData )
ENDCASE
ENDIF
ENDCASE

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD onSelect( qModelIndex ) CLASS JKGRID
LOCAL xValue, oModelIndex, nNewRow, nNewCol

::nCX := qModelIndex:column()
::nCY := qModelIndex:row()
IF ::lCellActive .and. .not. ::lCellChangeActive
nNewRow := ::nCY + 1
nNewCol := ::nCX + 1
IF nNewRow == ::nCellRow .and. nNewCol == ::nCellCol
* Nothing Doing
RETURN NIL
ENDIF
xValue := ::oCurrentWidget:Value
IF hb_IsArray( ::aColumnValid )
IF hb_IsBlock( ::aColumnValid[ ::nCellCol ] )
* Restore the cell cursor to old place until columnvalid is ok
::lCellChangeActive := .T.
oModelIndex := ::QAbstractItemModel:index( ::nCellRow - 1, ::nCellCol - 1, QModelIndex() )
::oQTObject:setCurrentIndex( oModelIndex )
IF !Eval( ::aColumnValid[ ::nCellCol ] )
::oCellQTObject:setFocus()
::lCellChangeActive := .F.
RETURN NIL
ENDIF
ENDIF
ENDIF
::CloseCell( xValue )
::oQTObject:reset()
* ::QAbstractItemModel:reset()
oModelIndex := ::QAbstractItemModel:index( nNewRow - 1, nNewCol - 1, QModelIndex() )
::oQTObject:setCurrentIndex( oModelIndex )
::oQTObject:setFocus()
::lCellChangeActive := .F.
ENDIF
IF ValType( ::bOnChange ) != 'U' .AND. .NOT. ::lCellChangeActive .AND. ::lCreated
nNewRow := ::nCY
IF !::lCellNavigation // QT gives signal FOR change in columns even in a full row selection mode
IF nNewRow != ::nOldRow
Eval( ::bOnChange )
::nOldRow := nNewRow
ENDIF
ELSE
Eval( ::bOnChange )
ENDIF
ENDIF

RETURN Self

/*----------------------------------------------------------------------*/

METHOD setItemPos( nValue ) CLASS JKGRID

IF PCOUNT() == 1 .AND. hb_IsNumeric( nValue )
::nCurrent := nValue + 1

::nMasterItemNo := nValue + 1
ENDIF

RETURN Self

/*----------------------------------------------------------------------*/

METHOD setRecordPos( nValue ) CLASS JKGRID

IF PCOUNT() == 1 .AND. hb_IsNumeric( nValue )
&( ::cWorkArea )->( dbGoTo( ::nMasterRecNo ) )

if( nValue + 1 ) == 1
&( ::cWorkArea )->( dbGoTop() )
::nCurrent := nValue + 1

ELSEIF( nValue + 1 ) > ::nRecordCount - 100 // Why 100 ??? Ricci
&( ::cWorkArea )->( dbGoBottom() )
&( ::cWorkArea )->( dbskip( ( nValue + 1 ) - ::nRecordCount ) )
::nCurrent := nValue + 1
ELSE
::nNew := nValue + 1
::nDiff := ::nNew - ::nCurrent
IF ::ndiff <> 0
&( ::cWorkArea )->( dbSkip( ::nDiff ) )
::nCurrent := ::nNew
ENDIF
ENDIF
::nMasterRecNo := &( ::cWorkArea )->( recno() )
ENDIF

RETURN Self

/*----------------------------------------------------------------------*/
METHOD CellNavigation( lValue ) CLASS JKGRID

IF Pcount() == 0
RETURN ::lCellNavigation
ELSEIF PCOUNT() == 1 .AND. hb_IsLogical( lValue )
::lCellNavigation := lValue
IF !::lCellNavigation
::oQTObject:setSelectionBehavior( QAbstractItemView_SelectRows )
ELSE
::oQTObject:setSelectionBehavior( QAbstractItemView_SelectItems )
ENDIF
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD LockColumns( nValue ) CLASS JKGRID

IF Pcount() == 0
RETURN ::nLockColumns
ELSEIF PCOUNT() == 1 .AND. hb_IsNumeric( nValue )
::nLockColumns := nValue
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD MultiSelect( lValue ) CLASS JKGRID

IF Pcount() == 0
IF ::oQTObject:selectionmode() == 3
RETURN .t.
ELSE
RETURN .f.
ENDIF
ELSEIF PCOUNT() == 1 .AND. hb_IsLogical( lValue )
IF lValue
* Multiselect is not allowed in DATA_MODE
IF ::nMode == ARRAY_MODE
::oQTObject:setselectionmode( 3 )
* Not to allow edit while in multiselect mode
::lAllowEdit := .f.
ENDIF
ELSE
::oQTObject:setSelectionMode( 1 )
ENDIF
::lMultiSelect := lValue
IF ::lCreated
::Refresh()
ENDIF
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD ItemCount() CLASS JKGRID

IF ::nMode == ARRAY_MODE
RETURN len( ::aItems )
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD ColumnControls( aValue ) CLASS JKGRID

IF Pcount() == 0
RETURN ::aColumnControls
ELSEIF PCOUNT() == 1 .AND. hb_IsArray( aValue )
::aColumnControls := aValue
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD Cell( nRow , nCol , xValue ) CLASS JKGRID

IF PCOUNT() == 2 .AND. hb_IsNumeric( nRow ) .AND. hb_IsNumeric( nCol )
IF ::nMode == ARRAY_MODE
RETURN ::aItems[ nRow, nCol ]
ENDIF
ELSEIF PCOUNT() == 3 .AND. hb_IsNumeric( nRow ) .AND. hb_IsNumeric( nCol )
IF ::nMode == ARRAY_MODE
::aItems[ nRow,nCol ] := xValue
IF ! ::lCellActive
::Refresh()
ENDIF
ENDIF
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD Item( nRow , xValue ) CLASS JKGRID

LOCAL i
* Item method is allowed only in array mode
IF .NOT. ::nMode == ARRAY_MODE
RETURN NIL
ENDIF

IF PCOUNT() == 1 .AND. hb_IsNumeric( nRow )
RETURN ::aItems[ nRow ]
ELSEIF PCOUNT() == 2 .AND. hb_IsNumeric( nRow )
FOR i := 1 TO LEN( ::aItems[ nRow ] )
IF LEN( xValue ) >= i
::aItems[ nRow,i ] := xValue[i]
ENDIF
NEXT
::Refresh()
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD AddColumn( nColIndex , cCaption , nWidth , nJustify, cHeaderImage ) CLASS JKGRID
LOCAL i

* AddColumn method is allowed only in array mode
IF .NOT. ::nMode == ARRAY_MODE
RETURN NIL
ENDIF

IF PCOUNT() >= 3 .AND. hb_IsNumeric( nColIndex ) .AND. hb_IsChar( cCaption ) .AND. hb_IsNumeric( nWidth )

aSize( ::aStruct, LEN( ::aStruct ) + 1 )
aIns( ::aStruct,nColIndex )
::aStruct[nColIndex] := { cCaption, 'C', 20, 0 }

aSize( ::aColumnHeaders,len( ::aColumnHeaders )+1 )
aIns( ::aColumnHeaders,nColIndex )
::aColumnHeaders[nColIndex] := cCaption

aSize( ::aColumnWidths,len( ::aColumnWidths )+1 )
aIns( ::aColumnWidths,nColIndex )
::aColumnWidths[nColIndex] := nWidth

aSize( ::aColumnJustify,len( ::aColumnJustify )+1 )
aIns( ::aColumnJustify,nColIndex )
::aColumnJustify[nColIndex] := nJustify

IF ValType( ::aHeaderImages ) != 'U'
aSize( ::aHeaderImages,len( ::aHeaderImages )+1 )
aIns( ::aHeaderImages,nColIndex )
aSize( ::aHeaderPixmaps,len( ::aHeaderPixmaps )+1 )
aIns( ::aHeaderPixmaps,nColIndex )
::aHeaderImages[nColIndex] := cHeaderImage
::aHeaderPixmaps[nColIndex] := QPixmap( ::aHeaderImages[nColIndex] )
ENDIF

FOR i := 1 To Len( ::aStruct )
IF valtype( ::aColumnHeaders ) = 'U' ;
.and. ;
valtype( ::aColumnWidths ) = 'U'
::oQtObject:setColumnWidth( i - 1, ::aStruct[ i, 3 ] * 6 + 60 )
ELSE
::oQtObject:setColumnWidth( i - 1, ::aColumnWidths [i] )
ENDIF
NEXT

aSize( ::aItems, 0)

::Refresh()

ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD DeleteColumn( nCol ) CLASS JKGRID
LOCAL i

* DeleteColumn method is allowed only in array mode
IF .NOT. ::nMode == ARRAY_MODE
RETURN NIL
ENDIF


IF PCOUNT() == 1 .and. hb_IsNumeric( nCol ) .and. nCol < len( ::aStruct )

aSize( ::aItems, 0)

::Refresh()

aDel( ::aStruct,nCol )
aSize( ::aStruct,len( ::aStruct )-1 )

aDel( ::aColumnHeaders,nCol )
aSize( ::aColumnHeaders,len( ::aColumnHeaders )-1 )

aDel( ::aColumnJustify,nCol )
aSize( ::aColumnJustify,len( ::aColumnJustify )-1 )

aDel( ::aColumnWidths,nCol )
aSize( ::aColumnWidths,len( ::aColumnWidths )-1 )

IF ValType( ::aHeaderImages ) != 'U'
aDel( ::aHeaderImages,nCol )
aSize( ::aHeaderImages,len( ::aHeaderImages )-1 )
aDel( ::aHeaderPixmaps,nCol )
aSize( ::aHeaderPixmaps,len( ::aHeaderPixmaps )-1 )
ENDIF

FOR i := 1 To Len( ::aStruct )
IF valtype( ::aColumnHeaders ) = 'U' ;
.and. ;
valtype( ::aColumnWidths ) = 'U'
::oQtObject:setColumnWidth( i - 1, ::aStruct[ i, 3 ] * 6 + 60 )
ELSE
::oQtObject:setColumnWidth( i - 1, ::aColumnWidths [i] )
ENDIF
NEXT

::Refresh()

ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD DeleteItem( nRow ) CLASS JKGRID

IF PCOUNT() == 1 .AND. hb_IsNumeric( nRow )
* DeleteItem method is allowed only in array mode
IF .NOT. ::nMode == ARRAY_MODE
RETURN NIL
ENDIF

aDel( ::aItems, nRow)
aSize( ::aItems, LEN( ::aItems ) - 1 )
::Refresh()
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD DeleteAllItems() CLASS JKGRID

* DeleteAllItems method is allowed only in array mode
IF .NOT. ::nMode == ARRAY_MODE
RETURN NIL
ENDIF

aSize( ::aItems, 0 )
::Refresh()

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD AddItem( aValue ) CLASS JKGRID

IF PCOUNT() == 1 .AND. hb_IsArray( aValue )
* AddItem method is allowed only in array mode
IF .NOT. ::nMode == ARRAY_MODE
RETURN NIL
ENDIF

aadd( ::aItems, aValue )
::Refresh()
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD ITEMS( aValue ) CLASS JKGRID

* Items method is allowed only in array mode
IF .NOT. ::nMode == ARRAY_MODE
msgquit( "virtualgrid:items() not in ARRAY_MODE" )
RETURN NIL
ENDIF

IF Pcount() == 0
RETURN ::aItems
ELSEIF PCOUNT() == 1 .AND. hb_IsArray( aValue )
::aItems := aClone( aValue )
::Refresh()
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD OnChange( bValue ) CLASS JKGRID

IF Pcount() == 0
RETURN ::bOnChange
ELSEIF PCOUNT() == 1 .AND. hb_IsBlock( bValue )
::bOnChange := bValue
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD CellDoubleClicked( qModelIndex ) CLASS JKGRID

LOCAL nNewRow,nNewCol

nNewRow := qModelIndex:row() + 1
nNewCol := qModelIndex:column() + 1
* If already cell edit is in process, don't process anything here
IF ::lCellActive
RETURN NIL
ENDIF
* process on dblclick event IF any
IF ValType( ::bOnDblClick ) != 'U'
Eval( ::bOnDblClick )
ENDIF
* FOR inplace edit
IF !::lAllowEdit .or. ::lMultiSelect
* Nothing doing
RETURN NIL
ELSE
IF ValType( ::aColumnControls ) == 'U' // no inplace edit required.
RETURN NIL
ENDIF
ENDIF
::nCellRow := nNewRow
::nCellCol := nNewCol
IF hb_IsArray( ::aColumnWhen )
IF hb_IsBlock( ::aColumnWhen[ ::nCellCol ] )
IF !Eval( ::aColumnWhen[ ::nCellCol ] )
RETURN .T.
ENDIF
ENDIF
ENDIF
* Inplace edit area
::DefineCellControl()

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD DoKeyBoardEvents( e ) CLASS JKGRID

LOCAL oKeyEvent := e
LOCAL nKey := oKeyEvent:key()
LOCAL nModifiers := oKeyEvent:modifiers()
IF ::lCellActive //Already cell edit is in process, so don't process any key here
//functie-toetsen zou moeten mogen ?
RETURN .T.
ENDIF
IF !::lAllowEdit .or. ::lMultiSelect
* Nothing doing
RETURN .F.
ELSE
IF ValType( ::aColumnControls ) == 'U' // no inplace edit required.
RETURN .T.
ENDIF
ENDIF
::nCellRow := ::nCY + 1
::nCellCol := ::nCX + 1
IF hb_IsArray( ::aColumnWhen )
IF hb_isBlock(::aColumnWhen[::nCellCol])
IF !Eval( ::aColumnWhen[::nCellCol] )
IF ::nCellCol == len( ::aColumnWhen )
RETURN .F.
ELSE
::nCellCol++ // to navigate to NEXT cell IF columnwhen is not allowed
ENDIF
ENDIF
ENDIF
ENDIF
* Inplace edit area
If( nKey == Qt_Key_Return .and. nModifiers == Qt_NoModifier ) .or.( nKey == Qt_Key_Enter .and. nModifiers == Qt_KeypadModifier ) .or.( nKey == Qt_Key_F2 .and. nModifiers == Qt_NoModifier )
::DefineCellControl()
ENDIF

RETURN .F.

/*----------------------------------------------------------------------*/

METHOD DefineCellControl CLASS JKGRID

LOCAL oModelIndex, nCurrentArea

* Preserve old value to restore IF escape key is pressed or editing cancelled.
DO CASE
CASE ::nMode == DATA_MODE
::setRecordPos( ::nCellRow - 1 )
nCurrentArea := Select()
dbselectarea( ::cWorkArea )
::xOldValue := &( ::cWorkArea )->( &( ::aStruct [ ::nCellCol ] [ 1 ] ) )
dbselectarea( nCurrentArea )
CASE ::nMode == ARRAY_MODE
::xOldValue := ::Cell( ::nCellRow, ::nCellCol )
ENDCASE //er stond ENDCASEw

::s_lGridCellFlag := .t.
DO CASE
CASE upper( alltrim( ::aColumnControls[::nCellCol][1] ) ) == 'TEXTBOX'
::oCurrentWidget := TextBox():New()
* Finding the datatype and textbox type
DO CASE
CASE upper( alltrim( ::aColumnControls[::nCellCol][2] ) ) == 'NUMERIC'
::oCurrentWidget:DataType := TXT_NUMERIC
CASE upper( alltrim( ::aColumnControls[::nCellCol][2] ) ) == 'DATE'
::oCurrentWidget:DataType := TXT_DATE
OTHERWISE
::oCurrentWidget:DataType := TXT_CHARACTER
ENDCASE
IF !::oCurrentWidget:DataType == TXT_DATE
IF len( ::aColumnControls[::nCellCol] ) > 2
IF ValType( ::aColumnControls[::nCellCol] [3] ) != 'U'
IF Len( alltrim( ::aColumnControls[::nCellCol][3] ) ) > 0 // inputmask
::oCurrentWidget:InputMask := ::aColumnControls[::nCellCol][3]
ENDIF
ENDIF
IF ::oCurrentWidget:DataType == TXT_NUMERIC
IF len( ::aColumnControls[::nCellCol] ) > 3
IF ValType( ::aColumnControls[::nCellCol][4] ) != 'U'
IF Len( alltrim( ::aColumnControls[::nCellCol][4] ) ) > 0 // format
::oCurrentWidget:Format := ::aColumnControls[::nCellCol][4]
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
* Right align the cell if column justification is right
IF valtype( ::aColumnJustify ) <> 'U'
IF ::aColumnJustify[::nCellCol] == GRID_JTFY_RIGHT
::oCurrentWidget:Alignment := TXT_RIGHT
ENDIF
ENDIF
CASE upper( alltrim( ::aColumnControls[::nCellCol][1] ) ) == 'CHECKBOX'
::oCurrentWidget := CheckBox():New()
* set the initial value to edit ie., old value
::oCurrentWidget:Caption := if( ::xOldValue,::aColumnControls[::nCellCol][2],::aColumnControls[::nCellCol][3] )
::oCurrentWidget:OnChange := {|| If( ::oCurrentWidget:Value,::oCurrentWidget:Caption := ::aColumnControls[::nCellCol][2],::oCurrentWidget:Caption := ::aColumnControls[::nCellCol][3] )}
CASE upper( alltrim( ::aColumnControls[::nCellCol][1] ) ) == 'DATEPICKER'
::oCurrentWidget := DatePicker():New()
* set the initial value to edit ie., old value
IF upper( alltrim( ::aColumnControls[::nCellCol][2] ) ) == 'UPDOWN'
::oCurrentWidget:UpDown := .t.
ELSE
::oCurrentWidget:UpDown := .f.
ENDIF
CASE upper( alltrim( ::aColumnControls[::nCellCol][1] ) ) == 'SPINNER'
::oCurrentWidget := Spinner():New()
* set the initial value to edit ie., old value
::oCurrentWidget:RangeMin := ::aColumnControls[::nCellCol][2]
::oCurrentWidget:RangeMax := ::aColumnControls[::nCellCol][3]
CASE upper( alltrim( ::aColumnControls[::nCellCol][1] ) ) == 'COMBOBOX'
* ComboBox creation & initialization started
::oCurrentWidget := ComboBox():New()
* set the initial value to edit ie., old value
::oCurrentWidget:Items := ::aColumnControls[::nCellCol][2]
ENDCASE
* set the initial value to edit ie., old value
::oCurrentWidget:Value := ::xOldValue

IF upper( alltrim( ::aColumnControls[::nCellCol][1] ) ) == 'TEXTBOX'
* To set the inputmask & format
::oCurrentWidget:Create()
// ::oCellQTObject:selectAll()
ENDIF

* store qt object and set the same to the cell of the grid
::s_lGridCellFlag := .f.
::oCellQTObject := ::oCurrentWidget:QTObject
::oCellQTObject:setAutoFillBackground( .t. )
* connect keypress event of the datepicker FOR processing enter and escape key
::oCellQTObject:connect( QEvent_KeyPress , {|e|::DoCellKeyBoardEvents( e )} )

oModelIndex := ::QAbstractItemModel:index( ::nCellRow - 1, ::nCellCol - 1, QModelIndex() )
::oQTObject:setIndexWidget( oModelIndex, ::oCellQTObject )
* cell is activated
::lCellActive := .T.
::oCellQTObject:setFocus()

if ::bOnInitCellEditor != NIL
eval( ::bOnInitCellEditor, Self, ::oCurrentWidget, ::aColumnControls[::nCellCol][1] )
endif

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD DoCellKeyBoardEvents( e ) Class JKGRID
//flags en enum QT::KeyboardModifiers : QT_NoModifier = geen shift, ctrl, alt, keypad en geen meta (meta is bijvb start mail)


LOCAL oKeyEvent := e
LOCAL nKey := oKeyEvent:key()
LOCAL nModifiers := oKeyEvent:modifiers()
LOCAL xValue
LOCAL oModelIndex, nRecNo , nArea


/*
* dit was voor de help/f10 !?
* ook insert bInsToggle
if(jkBlock:=setkey(nkey) !=NIL)
eval(jkBlock, procname(1), procline(1),'')
//was loop maar hier return .f.
// de eval is uitgevoerd en we willen nieuwe nKey
return .f.
endif
*/

DO CASE
CASE nKey == Qt_Key_Escape //.and. nModifiers == Qt_NoModifier
::lCellActive := .F.
::oCellQTObject:close()
::oQTObject:reset()
oModelIndex := ::QAbstractItemModel:index( ::nCellRow - 1, ::nCellCol - 1, QModelIndex() )
::oQTObject:setCurrentIndex( oModelIndex )
::oQTObject:setFocus()
CASE(nKey == Qt_Key_Up).or.;
(nKey == Qt_Key_Down).or.;
(nKey == Qt_Key_Right).or.;
(nKey == Qt_Key_Left).or.;
(nKey == Qt_Key_Home).or.;
(nKey == Qt_Key_PageDown).or.;
(nKey == Qt_Key_PageUp).or.;
(nKey == Qt_Key_PageUp)
return .f.
CASE (nKey == Qt_Key_Return .and. nModifiers == Qt_NoModifier ) .or. ( nKey == Qt_Key_Enter .and. nModifiers == Qt_KeypadModifier )
* na enter op veld krijg je de edit mode
xValue := ::oCurrentWidget:Value
IF hb_IsArray( ::aColumnValid )
IF hb_IsBlock( ::aColumnValid[ ::nCellCol ] )
IF !Eval( ::aColumnValid[ ::nCellCol ] )
RETURN .T.
ENDIF
ENDIF
ENDIF
::CloseCell( xValue )
* Move on to the next cell
IF ::nCellCol < LEN( ::aColumnControls )
::nCellCol++
ELSE
DO CASE
CASE ::nMode == ARRAY_MODE
IF ::nCellRow < LEN( ::aItems )
::nCellRow++
::nCellCol := 1
ENDIF
CASE ::nMode == DATA_MODE
IF ( empty( &( ::cWorkArea )->( dbFilter() ) ) ) .and.( .Not. Set( _SET_DELETED ) )
::nRecordCount := &( ::cWorkArea )->( OrdKeyCount() )
ELSE
nArea := Select()
nRecNo := recno()
dbSelectArea( ::cWorkArea )
COUNT TO ::nRecordCount
dbSelectArea( nArea )
dbgoto( nRecNo )
ENDIF
//jk IF ::nCellRow < LEN( ::nRecordCount )
IF ::nCellRow < ::nRecordCount
::nCellRow++
::nCellCol := 1
ELSE
//msg add line ?
ENDIF
ENDCASE
ENDIF
::oQTObject:reset()
oModelIndex := ::QAbstractItemModel:index( ::nCellRow - 1, ::nCellCol - 1, QModelIndex() )
::oQTObject:setCurrentIndex( oModelIndex ) //jk: kreeg ERROR na RETURN input laatste veld; RETURN en NoModifiers (numlock stond aan maar valt niet onder NoModi
::oQTObject:setFocus()
RETURN ::lReturnValueOnEnter
CASE nModifiers == Qt_NoModifier .or. nModifiers == Qt_KeypadModifier
* geen alt/shift/meta dit gaan we nog wel wijzigen
ENDCASE

RETURN .F.

/*----------------------------------------------------------------------*/

METHOD Refresh() CLASS JKGRID

IF ::lCreated .and. ! ::lCellActive
::QAbstractItemModel:reset()
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/
METHOD CloseCell( xValue ) CLASS JKGRID

LOCAL nCurrentArea
DO CASE
CASE ::nMode == ARRAY_MODE
::Cell( ::nCellRow,::nCellCol,xValue )
CASE ::nMode == DATA_MODE
::setRecordPos( ::nCellRow - 1 )
nCurrentArea := Select()
dbselectarea( ::cWorkArea )
replace &( ::aStruct [ ::nCellCol ] [ 1 ] ) with xValue
dbselectarea( nCurrentArea )
ENDCASE
::lCellActive := .F.
::oCellQTObject:close()
* To remove the widget from QTableView

RETURN NIL

/*----------------------------------------------------------------------*/
JosK
Posts: 46
Joined: Tue Nov 08, 2011 11:38 pm

Re: Virtual Grid bug?

Post by JosK »

also some changes to abstractgrid ..
Most imported reasen: when was evalued everty time. Also when the table was not yet stable.

This is my version:
/*
* $Id$
*/

/*
* HMG Source Code
*
* Copyright 2010 Carlos Bacco <carlosbacco at gmail.com>
* www - http://harbour-project.org
*
* Copyright 2002-2010 Roberto Lopez <mail.box.hmg@gmail.com>
* http://sites.google.com/site/hmgweb/
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or( at your option ) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License FOR more details.
*
* You should have received a copy of the GNU General Public License along with
* this software; see the file COPYING. IF not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA( or
* visit the web site http://www.gnu.org/ ).
*
* As a special exception, you have permission FOR additional uses of the text
* contained in this release of HMG.
*
* The exception is that, IF you link the HMG library with other
* files to produce an executable, this does not by itself cause the resulting
* executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of linking the
* HMG library code into it.
*/

#include "hbclass.ch"
#include "common.ch"
#include "hbqtgui.ch"
#include "hmg.ch"

/*----------------------------------------------------------------------*/

CLASS ABSTRACTGRID FROM CONTROL

* Internal Data

DATA cClass INIT "ABSTRACTGRID"
DATA nMode INIT ARRAY_MODE
DATA cWorkArea INIT NIL
DATA aColumnFields INIT NIL
DATA aItems INIT NIL
DATA aColumnHeaders INIT NIL
DATA aColumnWidths INIT NIL
DATA aColumnJustify INIT NIL
DATA aDynamicBackColor INIT NIL
DATA aDynamicForeColor INIT NIL
DATA aDynamicDisplay INIT NIL
DATA bOnHeadClick INIT NIL
DATA bOnDblClick INIT NIL
DATA aHeaderImages INIT NIL
DATA aHeaderPixMaps INIT NIL
DATA lAllowEdit INIT .F.
DATA lLines INIT .T.
DATA lVScrollBar INIT .T.
DATA aColumnWhen INIT NIL
DATA aColumnValid INIT NIL
DATA aValidMessages INIT NIL
DATA lShowColHeader INIT NIL
DATA lShowHeaders INIT NIL
DATA lShowRowHeader INIT NIL

DATA aColumnControls INIT NIL

* Data Variables FOR in-place edit

DATA nCellRow INIT 0
DATA nCellCol INIT 0

* Properties
METHOD WorkArea SETGET
METHOD ColumnFields SETGET
METHOD ColumnHeaders SETGET
METHOD ColumnWidths SETGET
METHOD ColumnJustify SETGET
METHOD DynamicBackColor SETGET
METHOD DynamicForeColor SETGET
METHOD DynamicDisplay SETGET
METHOD Header SETGET
METHOD HeaderImages SETGET
METHOD AllowEdit SETGET
METHOD Lines SETGET
METHOD VSCrollBar SETGET
METHOD ColumnWhen SETGET
METHOD ColumnValid SETGET
METHOD ValidMessages SETGET
METHOD CellRowIndex SETGET
METHOD CellColIndex SETGET
METHOD ShowColHeader SETGET
METHOD ShowHeaders SETGET
METHOD ShowRowHeader SETGET

* Events
METHOD OnDblClick SETGET
METHOD OnHeadClick SETGET

* Methods
METHOD CreateLocal
METHOD OnQueryData
METHOD StandardItemDisplay
METHOD StandardFieldDisplay

ENDCLASS

/*----------------------------------------------------------------------*/
* Properties
/*----------------------------------------------------------------------*/

METHOD ColumnWhen( aValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::aColumnWhen
ELSEIF Pcount() == 1 .AND. hb_Isarray( aValue )
::aColumnWhen := aValue
ENDIF

RETURN Self
/*----------------------------------------------------------------------*/

METHOD ValidMessages( aValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::aValidMessages
ELSEIF Pcount() == 1 .AND. hb_Isarray( aValue )
::aValidMessages := aValue
ENDIF

RETURN Self
/*----------------------------------------------------------------------*/

METHOD ColumnValid( aValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::aColumnValid
ELSEIF Pcount() == 1 .AND. hb_Isarray( aValue )
::aColumnValid := aValue
ENDIF

RETURN Self
/*----------------------------------------------------------------------*/

METHOD ColumnJustify( aValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::aColumnJustify
ELSEIF Pcount() == 1 .AND. hb_Isarray( aValue )
::aColumnJustify := aValue
ENDIF

RETURN Self
/*----------------------------------------------------------------------*/

METHOD AllowEdit( lValue ) CLASS ABSTRACTGRID
//FP nella Browse non e' implementato
IF Pcount() == 0
RETURN ::lAllowEdit
ELSEIF Pcount() == 1 .AND. hb_IsLogical( lValue )
::lAllowEdit := lValue
ENDIF

RETURN Self
/*----------------------------------------------------------------------*/
// FP e' per il This.
METHOD CellRowIndex( nValue ) CLASS ABSTRACTGRID
IF Pcount() == 1 .AND. hb_IsNumeric( nValue )
::nCellRowIndex := nValue
ENDIF

RETURN ::nCellRowIndex
/*----------------------------------------------------------------------*/
// FP e' per il This.

METHOD CellColIndex( nValue ) CLASS ABSTRACTGRID
IF Pcount() == 1 .AND. hb_IsNumeric( nValue )
::nCellColIndex := nValue
ENDIF

RETURN ::nCellColIndex
/*----------------------------------------------------------------------*/

METHOD WorkArea( cValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::cWorkArea
ELSEIF Pcount() == 1 .AND. hb_IsChar( cValue )
::cWorkArea := cValue
::nMode := DATA_MODE
ENDIF

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

METHOD ColumnFields( aValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::aColumnFields
ELSEIF Pcount() == 1 .AND. hb_Isarray( aValue )
::aColumnFields := aValue
ENDIF

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

METHOD Lines( lValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::lLines
ELSEIF Pcount() == 1 .AND. hb_IsLogical( lValue )
::lLines := lValue
::oQTObject:setShowGrid( ::lLines )
ENDIF

RETURN Self
/*----------------------------------------------------------------------*/

METHOD VSCrollBar( lValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::lVScrollBar
ELSEIF Pcount() == 1 .AND. hb_IsLogical( lValue )
::lVScrollBar := lValue
IF ::lVScrollBar
::oQTObject:setVerticalScrollBarPolicy( 2 )
ELSE
::oQTObject:setVerticalScrollBarPolicy( 1 )
ENDIF
ENDIF

RETURN Self

/*----------------------------------------------------------------------*/

METHOD Header( nCol , cValue ) CLASS ABSTRACTGRID

IF Pcount() == 1 .AND. hb_IsNumeric( nCol )
RETURN ::aColumnHeaders[nCol]
ELSEIF Pcount() == 2 .AND. hb_IsChar( cValue )
::aColumnHeaders[nCol] := cValue
::Refresh() // FP: only if lCreated = T ?
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD HeaderImages( aValue ) CLASS ABSTRACTGRID
LOCAL i

IF Pcount() == 0
RETURN ::aHeaderImages
ELSEIF Pcount() == 1 .AND. hb_Isarray( aValue )
::aHeaderImages := aValue
::aHeaderPixmaps := array( len( ::aHeaderImages ) )
FOR i := 1 to len( ::aHeaderImages )
::aHeaderPixmaps := QPixmap( ::aHeaderImages )
NEXT i
ENDIF

RETURN Self

/*----------------------------------------------------------------------*/

METHOD DynamicBackColor( aValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::aDynamicBackColor
ELSEIF Pcount() == 1 .AND. hb_Isarray( aValue )
::aDynamicBackColor := aValue
ENDIF

RETURN Self

/*----------------------------------------------------------------------*/

METHOD DynamicForeColor( aValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::aDynamicForeColor
ELSEIF Pcount() == 1 .AND. hb_Isarray( aValue )
::aDynamicForeColor := aValue
ENDIF

RETURN Self

/*----------------------------------------------------------------------*/

METHOD DynamicDisplay( aValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::aDynamicDisplay
ELSEIF Pcount() == 1 .AND. hb_Isarray( aValue )
::aDynamicDisplay := aValue
ENDIF

RETURN Self

/*----------------------------------------------------------------------*/

METHOD ColumnWidths( aValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::aColumnWidths
ELSEIF Pcount() == 1 .AND. hb_Isarray( aValue )
::aColumnWidths := aValue
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/
METHOD ColumnHeaders( aValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::aColumnHeaders
ELSEIF Pcount() == 1 .AND. hb_Isarray( aValue )
::aColumnHeaders := aValue
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD ShowColHeader( lValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::lShowColHeader
ELSEIF Pcount() == 1 .AND. hb_IsLogical( lValue )
IF lValue
::oQTObject:horizontalHeader():Show()
ELSE
::oQTObject:horizontalHeader():Hide()
ENDIF
::lShowColHeader := lValue
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD ShowHeaders( lValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::lShowHeaders
ELSEIF Pcount() == 1 .AND. hb_IsLogical( lValue )
IF lValue
::oQTObject:verticalHeader():Show()
::oQTObject:horizontalHeader():Show()
ELSE
::oQTObject:verticalHeader():hide()
::oQTObject:horizontalHeader():hide()
ENDIF
::lShowHeaders := lValue
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD ShowRowHeader( lValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::lShowRowHeader
ELSEIF Pcount() == 1 .AND. hb_IsLogical( lValue )
IF lValue
::oQTObject:verticalHeader():Show()
ELSE
::oQTObject:verticalHeader():Hide()
ENDIF
::lShowRowHeader := lValue
ENDIF

RETURN NIL


/*----------------------------------------------------------------------*/
* Events
/*----------------------------------------------------------------------*/

METHOD OnDblClick( bValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::bOnDblClick
ELSEIF Pcount() == 1 .AND. hb_IsBlock( bValue )
::bOnDblClick := bValue
ENDIF

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD OnHeadClick( bValue ) CLASS ABSTRACTGRID

IF Pcount() == 0
RETURN ::bOnHeadClick
ELSEIF Pcount() == 1 .AND. hb_IsBlock( bValue )
::bOnHeadClick := bValue
ENDIF

RETURN Self

/*----------------------------------------------------------------------*/
* Methods
/*----------------------------------------------------------------------*/

METHOD CreateLocal() CLASS ABSTRACTGRID
LOCAL i

::oSize := QSize( 24,24 )

::lCreated := .T.
DO CASE
CASE ::nMode == DATA_MODE
IF valtype( ::aColumnFields ) == 'U' ;
.and. ;
valtype( ::aColumnHeaders ) == 'U' ;
.and. ;
valtype( ::aColumnWidths ) == 'U' ;
.and. ;
hb_IsChar( ::cWorkArea )

::aStruct := &( ::cWorkArea )->( DBStruct() )
ELSE
::aStruct := {}
FOR i := 1 to len( ::aColumnFields )
aadd( ::aStruct , { ::aColumnFields , Type( ::aColumnFields ) , 0 , 0 } )
NEXT i
ENDIF
CASE ::nMode == ARRAY_MODE
::aStruct := {}
FOR i := 1 to len( ::aColumnHeaders )
IF hb_IsArray( ::aColumnControls )
DO CASE
CASE upper( ::aColumnControls [i, 1] ) == 'TEXTBOX'
DO CASE
CASE upper( ::aColumnControls [i, 2] ) == 'CHARACTER'
aadd( ::aStruct , { ::aColumnHeaders , 'C' , 0 , 0 } )
CASE upper( ::aColumnControls [i, 2] ) == 'NUMERIC'
aadd( ::aStruct , { ::aColumnHeaders , 'N' , 0 , 0 } )
CASE upper( ::aColumnControls [i, 2] ) == 'DATE'
aadd( ::aStruct , { ::aColumnHeaders , 'D' , 0 , 0 } )
ENDCASE
CASE upper( ::aColumnControls [i, 1] ) == 'COMBOBOX'
aadd( ::aStruct , { ::aColumnHeaders , 'C' , 0 , 0 } )
CASE upper( ::aColumnControls [i, 1] ) == 'DATEPICKER'
aadd( ::aStruct , { ::aColumnHeaders , 'D' , 0 , 0 } )
CASE upper( ::aColumnControls [i, 1] ) == 'SPINNER'
aadd( ::aStruct , { ::aColumnHeaders , 'N' , 0 , 0 } )
CASE upper( ::aColumnControls [i, 1] ) == 'CHECKBOX'
aadd( ::aStruct , { ::aColumnHeaders [i] , 'L' , 0 , 0 } )
ENDCASE
ELSE
IF LEN( ::aItems ) > 0
aadd( ::aStruct , { ::aColumnHeaders [i] , VALTYPE(::aItems[1,i]) , 0 , 0 } )
ELSE
aadd( ::aStruct , { ::aColumnHeaders [i] , 'C' , 0 , 0 } )
ENDIF
ENDIF
NEXT i
ENDCASE


::Refresh()

::oQTObject:verticalHeader():setDefaultSectionSize( 24 )

::QAbstractItemDelegate := ::oQTObject:itemDelegate()
::QAbstractItemDelegate:connect( "commitData(QWidget*)", {| w | ::OnSave( w ) } )

::oQTObject:connect( "doubleClicked(QModelIndex)", {| n | ::CellDoubleClicked( n )} )
::oQTObject:connect( QEvent_KeyPress , {|e|Self:DoKeyBoardEvents( e )} ) //deze staatin grid, virtualgrid en virtualwindow=dochter

::oQHeaderView := QHeaderView( ::oQTObject:horizontalHeader() )
IF hb_IsArray( ::bOnHeadClick )
::oQHeaderView:disconnect( "sectionClicked(int)" )
::oQHeaderView:connect( "sectionClicked(int)",{|i| if( hb_IsBlock( ::bOnHeadClick[i+1] ), Eval( ::bOnHeadClick[i+1] ),nil ) } )
ENDIF

::Refresh()

FOR i := 1 To Len( ::aStruct )
IF valtype( ::aColumnWidths ) = 'U'
::oQtObject:setColumnWidth( i - 1, ::aStruct[ i, 3 ] * 6 + 60 )
ELSE
::oQtObject:setColumnWidth( i - 1, ::aColumnWidths [i] )
ENDIF
NEXT


// ::oParent:ChildAdd( ::cName , Self )

IF ValType( ::lVisible ) != 'U'; Self:Visible := ::lVisible ; ELSE ; ::oQTObject:show() ; ENDIF

IF ::nMode == DATA_MODE
::nCurrent := 1
&( ::cWorkArea )->( dbGoTop() )
::nMasterRecNo := &( ::cWorkArea )->( recno() )
ELSE
IF VALTYPE( ::xValue ) != 'U'
::Value := ::xValue
ENDIF
ENDIF

IF hb_IsArray( ::aColumnControls )
IF LEN( ::aColumnControls ) > 0
::oQTObject:setEditTriggers( 0 )
ENDIF
ENDIF

RETURN Self

/*----------------------------------------------------------------------*/

METHOD OnQueryData( aStru, t, role, x, y ) CLASS ABSTRACTGRID
LOCAL aRetVal , aColor, nRetVal, nRecNo , nArea
// msginfo("onquerydata")

SWITCH t
CASE HBQT_QAIM_flags
IF ::lAllowEdit
nRetVal := Qt_ItemIsEnabled + Qt_ItemIsSelectable

IF hb_IsArray( ::aColumnWhen )
IF hb_IsBlock( ::aColumnWhen [x+1] )
DO CASE
CASE ::nMode == DATA_MODE
::setRecordPos( y )
CASE ::nMode == ARRAY_MODE
::setItemPos( y )
ENDCASE
//DEZE EVAL DOEN WE ALLEEN BIJ INVOEREN EN NIET BIJ OPBOUWEN SCHERM
//IF eval( ::aColumnWhen [x+1] )
nRetVal += Qt_ItemIsEditable
//ENDIF
ELSE
nRetVal += Qt_ItemIsEditable
ENDIF
ELSE
nRetVal += Qt_ItemIsEditable
ENDIF

RETURN nRetVal
ELSE
RETURN Qt_ItemIsEnabled + Qt_ItemIsSelectable
ENDIF

CASE HBQT_QAIM_data
// msginfo( "QAIM_DATA" )
SWITCH role
CASE Qt_DisplayRole
DO CASE
CASE ::nMode == DATA_MODE
::setRecordPos( y )
CASE ::nMode == ARRAY_MODE
::setItemPos( y )
ENDCASE
IF valtype( ::aDynamicDisplay ) = 'U'
DO CASE
CASE ::nMode == DATA_MODE
RETURN ::StandardFieldDisplay( aStru, x )
CASE ::nMode == ARRAY_MODE
RETURN ::StandardItemDisplay( aStru, x, y )
ENDCASE
ELSE
IF hb_IsBlock( ::aDynamicDisplay [ x+1 ] )

RETURN Eval( ::aDynamicDisplay [ x+1 ] )
ELSE
DO CASE
CASE ::nMode == DATA_MODE

RETURN ::StandardFieldDisplay( aStru, x )
CASE ::nMode == ARRAY_MODE

RETURN ::StandardItemDisplay( aStru, x, y )
ENDCASE
ENDIF
ENDIF

CASE Qt_EditRole /* Here we can specify different formats FOR editing*/
DO CASE
CASE ::nMode == DATA_MODE
::setRecordPos( y )
SWITCH aStru[ x + 1, 2 ]
CASE "C"
RETURN AllTrim( &( ::cWorkArea )->( &( aStru [ x+1 ] [ 1 ] ) ) )
CASE "N"
RETURN hb_NToS( &( ::cWorkArea )->( &( aStru [ x+1 ] [ 1 ] ) ) )
CASE "L"
RETURN IIf( &( ::cWorkArea )->( &( aStru [ x+1 ] [ 1 ] ) ), "Y", "N" )
CASE "D"
RETURN DToC( &( ::cWorkArea )->( &( aStru [ x+1 ] [ 1 ] ) ) )
ENDSWITCH
RETURN "?"
CASE ::nMode == ARRAY_MODE
::setItemPos( y )
SWITCH aStru[ x + 1, 2 ]
CASE "C"
RETURN AllTrim( ::aItems [ y+1 ] [ x+1 ] )
CASE "N"
RETURN hb_NToS( ::aItems [ y+1 ] [ x+1 ] )
CASE "L"
RETURN IIf( ::aItems [ y+1 ] [ x+1 ] , "Y", "N" )
CASE "D"
RETURN DToC( ::aItems [ y+1 ] [ x+1 ] )
ENDSWITCH
RETURN "?"
ENDCASE

CASE Qt_ForegroundRole
IF hb_IsArray( ::aDynamicForeColor )
DO CASE
CASE ::nMode == DATA_MODE
::setRecordPos( y )
CASE ::nMode == ARRAY_MODE
::setItemPos( y )
ENDCASE
::nCellRowIndex := y + 1
::nCellColIndex := x + 1
aColor := eval( ::aDynamicForeColor [ x + 1 ], y + 1 )
aRetVal := qColor( aColor [1] , aColor [2] , aColor [3] )
ELSE
aRetVal := NIL
ENDIF
RETURN aRetVal

CASE Qt_BackgroundRole
IF hb_IsArray( ::aDynamicBackColor )
DO CASE
CASE ::nMode == DATA_MODE
::setRecordPos( y )
CASE ::nMode == ARRAY_MODE
::setItemPos( y )
ENDCASE
::nCellRowIndex := y + 1
::nCellColIndex := x + 1
aColor := eval( ::aDynamicBackColor [ x + 1 ], y + 1 )
aRetVal := qColor( aColor [1] , aColor [2] , aColor [3] )
ELSE
aRetVal := NIL
ENDIF
RETURN aRetVal

CASE Qt_TextAlignmentRole
IF valtype( ::aColumnJustify ) = 'U'
SWITCH aStru[ x + 1, 2 ]
CASE "C"
RETURN Qt_AlignVCenter + Qt_AlignLeft
CASE "N"
RETURN Qt_AlignVCenter + Qt_AlignRight
ENDSWITCH
RETURN Qt_AlignCenter
ELSE
RETURN Qt_AlignVCenter + ::aColumnJustify [ x+1 ]
ENDIF

ENDSWITCH
RETURN NIL

CASE HBQT_QAIM_headerData
SWITCH role
CASE Qt_DisplayRole
IF x == Qt_Horizontal
IF hb_IsArray( ::aColumnHeaders )
RETURN ::aColumnHeaders[ y + 1 ]
ELSE
RETURN aStru[ y + 1, 1 ]
ENDIF
ELSE
IF ::nCy == y
RETURN '>'
ELSE
RETURN ''
ENDIF
ENDIF

CASE Qt_TextAlignmentRole
IF x == Qt_Horizontal
RETURN Qt_AlignCenter
ELSE
RETURN Qt_AlignVCenter + Qt_AlignRight
ENDIF

CASE Qt_SizeHintRole

RETURN ::oSize

CASE Qt_DecorationRole
IF x == Qt_Horizontal
IF ValType( ::aHeaderPixmaps ) != 'U'
RETURN ::aHeaderPixmaps[y+1]
ENDIF
ENDIF

ENDSWITCH
RETURN NIL

CASE HBQT_QAIM_rowCount
DO CASE
CASE ::nMode == DATA_MODE
IF ( empty( &( ::cWorkArea )->( dbFilter() ) ) ) .and.( .Not. Set( _SET_DELETED ) )
::nRecordCount := &( ::cWorkArea )->( OrdKeyCount() )
ELSE
nArea := Select()
nRecNo := recno()
dbSelectArea( ::cWorkArea )
COUNT TO ::nRecordCount
dbSelectArea( nArea )
dbgoto( nRecNo )
ENDIF
RETURN ::nRecordCount
CASE ::nMode == ARRAY_MODE
IF hb_IsArray( ::aItems )
::nItemCount := LEN( ::aItems )
ELSE
::nItemCount := 0
ENDIF
RETURN ::nItemCount
ENDCASE

CASE HBQT_QAIM_columnCount
DO CASE
CASE ::nMode == DATA_MODE
RETURN &( ::cWorkArea )->( Len( aStru ) )
CASE ::nMode == ARRAY_MODE
RETURN Len( aStru )
ENDCASE

ENDSWITCH

RETURN NIL

/*----------------------------------------------------------------------*/

METHOD StandardItemDisplay( aStru , x, y ) CLASS ABSTRACTGRID

LOCAL cText, nCol, xValue

nCol := x + 1
xValue := ::aItems[ y + 1, x + 1 ]
// msginfo("stabd: " +str(y)+" "+str(x) )

IF valtype( ::aColumnControls ) != 'U'
DO CASE
CASE upper( alltrim( ::aColumnControls[nCol][1] ) ) == 'TEXTBOX'
DO CASE
CASE upper( alltrim( ::aColumnControls[nCol][2] ) ) == 'NUMERIC'
IF len( ::aColumnControls[nCol] ) > 2 // with inputmask|format
IF ValType( ::aColumnControls[nCol] [3] ) != 'U'
IF len( ::aColumnControls[nCol] [3] ) > 0
cText := Transform( xValue ,( ::aColumnControls[nCol] [3] ) )
ENDIF
ENDIF
ELSE
cText := Alltrim( Str( Int( xValue ) ) )
ENDIF
CASE upper( alltrim( ::aColumnControls[nCol][2] ) ) == 'DATE'
cText := rtrim( dtoc( xValue ) )
OTHERWISE
cText := xValue
ENDCASE
CASE upper( alltrim( ::aColumnControls[nCol][1] ) ) == 'CHECKBOX'
IF xValue
cText := ::aColumnControls[nCol][2]
ELSE
cText := ::aColumnControls[nCol][3]
ENDIF
CASE upper( alltrim( ::aColumnControls[nCol][1] ) ) == 'DATEPICKER'
cText := DtoC( xValue )
CASE upper( alltrim( ::aColumnControls[nCol][1] ) ) == 'SPINNER'
cText := alltrim( Str( int( xValue ) ) )
CASE upper( alltrim( ::aColumnControls[nCol][1] ) ) == 'COMBOBOX'
cText := ::aColumnControls[nCol][2][xValue]
ENDCASE
RETURN cText
ELSE
SWITCH aStru[ x + 1, 2 ]
CASE "C"
RETURN AllTrim( ::aItems [ y+1 ] [ x+1 ] )
CASE "N"
RETURN hb_NToS( ::aItems [ y+1 ] [ x+1 ] )
CASE "L"
RETURN IIf( ::aItems [ y+1 ] [ x+1 ] , "Yes", "No" )
CASE "D"
RETURN DToC( ::aItems [ y+1 ] [ x+1 ] )
CASE "M"
RETURN '<memo>'
ENDSWITCH
ENDIF
RETURN "?"
/*----------------------------------------------------------------------*/

METHOD StandardFieldDisplay( aStru , x ) CLASS ABSTRACTGRID

SWITCH aStru[ x + 1, 2 ]
CASE "C"
RETURN AllTrim( &( ::cWorkArea )->( &( aStru [ x+1 ] [ 1 ] ) ) )
CASE "N"
RETURN hb_NToS( &( ::cWorkArea )->( &( aStru [ x+1 ] [ 1 ] ) ) )
CASE "L"
RETURN IIf( &( ::cWorkArea )->( &( aStru [ x+1 ] [ 1 ] ) ), "Yes", "No" )
CASE "D"
RETURN DToC( &( ::cWorkArea )->( &( aStru [ x+1 ] [ 1 ] ) ) )
CASE "M"
RETURN '<memo>'
ENDSWITCH

RETURN "?"

/*----------------------------------------------------------------------*/
JosK
Posts: 46
Joined: Tue Nov 08, 2011 11:38 pm

Re: Virtual Grid bug?

Post by JosK »

My example of jkgrid.prg with tab pages en also set key en the use of layoutbox:

/*
*/

#include "hmg.ch"
#include "hbqtgui.ch"
#include "hbgtinfo.ch"
#include "std.ch"

SET DATE TO ANSI
SET EPOCH TO 1950 //KAN OOK CENTURY DOEN MAAR DAN 4 POSITIES..
SET CENTURY OFF
SET WRAP ON && ref 'menu to ...'
SET TALK OFF &&
SET BELL OFF &&
SET DELETED ON &&
SET SAFETY OFF &&
SET HEADING OFF &&
SET DELIMITERS OFF &&
SET SCOREBOARD OFF && geen Num, Ins, enz op lijn 0.
SET INTENSITY ON
SET DELIMITERS OFF
SET EXACT OFF
SET CURSOR OFF //KENT HMG NIET daar std.ch
SET DELETED ON && alleen btw bestand word direct gepackt ivm reccount()
SET EXCLUSIVE ON
setcancel(.f.)


FUNCTION Main()

Public oTLB //oTabpageLayoutBox

HbQt_ErrorSys()

wMain :=MaakMain("wMain")
oCW :=Widget():New("oCW",wMain)
oCW :CentralWidgetOF(wMain)
oLB :=LayoutBox():New("oLB",oCW,LAYOUT_TOPTOBOTTOM)
with object oTab:=Tab():New("oTab")
MaakTP1("oTP1",oTab)
MaakTP2("oTP2",oTab)

end
oLB:add(oTab)
oLB:SetLayout()
ON KEY F10 OF WMAIN ACTION {|| MSGSTOP("f10 binnen wmain")}
ON KEY F8 OF WMAIN ACTION {|| MSGSTOP(str(OTLB:direction()))}
//0=l->r, 1=r-l, 2=t-b, 3=b-t, 4=form, 5=grid
ON KEY F9 OF WMAIN ACTION {|| if( (x:=oTLB:Direction())==3,oTLB:Directon(0),oTLB:Direction(x+1))}
wMain:Activate()
Return NIL
***************************
STATIC FUNCTION MaakMain(c)
***************************
static o
if o==nil
o:= MAINWINDOW():New(c)
o:Title := "Maak Main Demo"
endif
return o
***************************************
STATIC FUNCTION MaakTab(c,oParent,nRow)
***************************************
local o
o:=Tab():New(c,oParent)
return o
***************************
FUNCTION MaakTP1(c,oParent)
***************************
static o
if o=Nil
o:=TabPage():New(c,oParent)
o:caption:="&Tabpage1"
oTLB:=LayoutBox():New("oTLB",o)
oTLB:direction(0)
oB1:=Button():New()
oB1:caption("Button1")
oT1:=TextBox():New()
oB2:=Button():New()
oB3:=MaakBtn("oB3")
oTLB:add(oB1)
oTLB:insertstretch(1,10)
oTLB:add(oT1)
oTLB:insertstretch(2,10)
oTLB:add(oB2)
oTLB:insertstretch(3,10)
oTLB:add(oB3)
oTLB:setLayout()
endif
return o

************
STATIC FUNCTION MaakBtn(c,oParent)
************
static o
o:=Button():New(c,oParent)
o:MaxWidth :=300
o:Caption := "Current Language"
o:OnClick := { || Bt1_OnClick() }
RETURN o
************
STATIC FUNCTION Bt1_OnClick()
************
MsgInfo( "Current Language is " + hb_ValToExp( HMGAPP():Language() ), "Language" )
RETURN NIL

***************************
FUNCTION MaakTP2(c,oParent)
static o

use c:\hmg.4\svn\samples\t\demo alias demo
go top

if o=Nil
o:=TabPage():New(c,oParent)
o:caption:="&RekSchema"
oTLB:=LayoutBox():New("oTLB",o,LAYOUT_TOPTOBOTTOM)

oBrowse:=MaakBrowse("oBrowse")
oTLB:add(oBrowse)
oTLB:setlayout()
endif
return o
*******************
function MaakBrowse(c)
*******************
static o
static bColor := { || IF ( ordkeyno()/2 == INT(ordkeyno()/2) , { 222,222,222 } , { 255,255,255 } ) }
static fColor := { || IF ( ordkeyno()/2 == INT(ordkeyno()/2) , { 255,0,0 } , { 0,0,255 } ) }
o:=jkGrid():New(c)
o:Row := 10
o:Col := 10
o:Width := 690
o:Height := 615
o:WorkArea := 'demo'
//o:OnChange :={||MsgInfo( "Andere cell/regel geselecteerd!" )}
//o:ONDBLClick :={||MsgInfo( "We gaan cell editten!" )}

* 'First','Last','Street','City','State','Zip','Hire Date','Married' ,'Age', Salary' , 'Notes'}
* '1,2,3,4,5,6Zip,7H,8'Married',9Age',10Salary' , 11Notes'}
//kreeg een error er daarom columnHeader toegevoegd
o:ColumnHeaders := { 'First' , 'Last' , 'Street' , 'City' , 'State' , 'Zip' , 'HireDate' , 'Married' , 'Age' , 'Salary' , 'Notes' }
o:ColumnFields := { 'First' , 'Last' , 'Street' , 'City' , 'State' , 'Zip' , 'HireDate' , 'Married' , 'Age' , 'Salary' , 'Notes' }
o:ColumnWidths := { 150 , 150 , 150 , 150 , 150 , 150 , 150 , 150 , 150 , 150 , 150 }
// ColumnJustify {GRID_JTFY_LEFT,GRID_JTFY_RIGHT,GRID_JTFY_LEFT,GRID_JTFY_LEFT,GRID_JTFY_LEFT,GRID_JTFY_RIGHT,GRID_JTFY_LEFT}
// brw_left etc is idem als grid_jtfy_left
o:ColumnJustify := { BRW_LEFT , BRW_RIGHT , BRW_CENTER , BRW_LEFT , BRW_RIGHT , BRW_CENTER , BRW_LEFT , BRW_RIGHT , BRW_CENTER , BRW_LEFT , BRW_RIGHT }
o:DynamicBackColor := { bColor , bColor , bColor , bColor , bColor , bColor , bColor , bColor , bColor , bColor , bColor }
o:DynamicForeColor := { fColor , fColor , fColor , fColor , fColor , fColor , fColor , fColor , fColor , fColor , fColor }
o:DynamicDisplay := { { || UPPER(First) } , NIL , NIL , NIL , NIL , NIL , NIL , { || IF(married,'Married','Not Married' ) } , NIL , NIL , NIL }
o:OnHeadClick := { { || MsgInfo( 'Click 1' ) } , , { || MsgInfo( 'Click 3' ) } , { || MsgInfo( 'Click 4' ) } , { || MsgInfo( 'Click 5' ) } , { || MsgInfo( 'Click 6' ) } , { || MsgInfo( 'Click 7' ) } , { || MsgInfo( '8' ) } , ,}
o:HeaderImages := { 'new.png' , 'open.png' , 'paste.png' , 'save.png' , 'new.png' , 'open.png' , 'paste.png' , 'save.png' , 'new.png' , 'open.png' , 'paste.png' }
//1.1= textbox,checkbox
//1.2=nummeric,date,character
//1.3=imputmask
//1.4=format alleen bij nummeric
// justify via andere array
//1="checkbox", caption=2of3,onchange=2of3 hij checkt op wel/niet block!?
//1="datepicker",2="UPDOWN" else updown=f
//1="spinner",2=RangeMin, 3=RangeMax
//1="combobox",2=items=array

o:ColumnControls :={{'TEXTBOX','CHARACTER'},;
{'TEXTBOX','CHARACTER'},;
{'TEXTBOX','CHARACTER','@K'},;
{"SPINNER",1,1000},;
{"COMBOBOX",{"January","February","March","April","May","June","July","August","September","October","November","December"}},;
{'TEXTBOX','CHARACTER',"@K"},;
{"DATEPICKER","UpDown"},;
{'CHECKBOX','Yes','No'},;
{'TEXTBOX','NUMERIC','99'},;
{'TEXTBOX','NUMERIC','999.99'},;
{'TEXTBOX','CHARACTER'};
}
o:MultiSelect := .F. //bij true = geen edit , alleen display
o:AllowEdit := .T. //alleen indien columnControls is ingevuld
o:Lines := .F.
o:VScrollBar := .F.
o:ColumnWhen := { { || UPPER(LEFT(first,1) ) == 'A' } ,;
, , , , , , , , , , , }
//msgstop wordt bij opbouwen scherm bij iedere regel getoond
//bij when en browse problem want werd bij iedere regel werd when uitgevoerd; ook bij opbouwen scherm
//er moet een block in staan want anders error na intoetsen key
//o:ColumnWhen := { { || UPPER(LEFT(first,1) ) == 'A' } , , , , , , , , , , }
//o:ColumnValid := { { || !EMPTY(memvar.demo.first) } , , , , , , , , , { || demo->salary > 100 } , }
o:ColumnValid := { { || !EMPTY(demo.first) } , , , , , , , , , { || demo->salary > 100 } , }
o:ValidMessages := { "First name can't be EMPTY" , , , , , , , , , "Salary mus be greater than 100" , }
x1:=len(o:ColumnControls())
x2:=len(o:ColumnValid())
x3:=len(o:ValidMessages())
if x1#x2.or.x1#x3
msgstop("x1="+str(x1) + " x2="+str(x2)+ " x3="+str(x3))
endif
return o
JosK
Posts: 46
Joined: Tue Nov 08, 2011 11:38 pm

Re: Virtual Grid bug?

Post by JosK »

F9 does'nt work grrrr ;-)

so change line 41
maakTP2(...
//maakTP2(..

After this change F9 works ... a little bit ;-)
There is still a bug ... Direction(0) is not stored!?
JosK
Posts: 46
Joined: Tue Nov 08, 2011 11:38 pm

Re: Virtual Grid bug?

Post by JosK »

For the record ;-)
i'm working with hmg 4 2011.11.23
Post Reply