* PAGEDGRID.SCX.SRC
* Form "pagedgrid.scx"
* C:\PROGRAM FILES (X86)\ABAQUE\FICSAMPLES\FICTUTO\PROGS\FORMS\PAGEDGRID.SCX.SRC (included in c:\program files (x86)\abaque\ficsamples\fictuto\fictutobs.exe)
* (366 lines before localization)
* ========================================================================================================================

PUBLIC opagedgrid

SET CLASSLIB TO ab\aw\samples\fic\classe\ficsample.vcx ADDITIVE

opagedgrid=NEWOBJECT("pagedgrid")
opagedgrid.Show
RETURN

  **************************************************
*-- Form: pagedgrid (ab\aw\samples\fic\fictuto\progs\forms\pagedgrid.scx)
*-- ParentClass: ficfrm (ab\aw\samples\fic\classe\ficsample.vcx)
*-- BaseClass: form
*-- Time Stamp: 12/05/20 10:02:08 PM

#INCLUDE "ab\ab.h"
DEFINE CLASS pagedgrid AS ficfrm

  Height = 432
  DoCreate = .T.
  Caption = "Paged Grid"
  _memberdata = ""
  Name = "PagedGrid"
  cntOK.opgStyle.optClassic.Value = 1
  cntOK.opgStyle.optClassic.Left = 0
  cntOK.opgStyle.optClassic.Top = 0
  cntOK.opgStyle.optClassic.Name = "optClassic"
  cntOK.opgStyle.optBS.Left = 0
  cntOK.opgStyle.optBS.Top = 30
  cntOK.opgStyle.optBS.Name = "optBS"
  cntOK.opgStyle.Name = "opgStyle"
  cntOK.cmdOK.Name = "cmdOK"
  cntOK.imgSrce.Name = "imgSrce"
  cntOK.imgHelp.Name = "imgHelp"
  cntOK.Top = 11
  cntOK.Height = 254
  cntOK.Name = "cntOK"
  waitpic.Top = 0
  waitpic.Name = "waitpic"
  lblFiC.TabIndex = 4
  lblFiC.Name = "lblFiC"
  lblTime.Height = 15
  lblTime.Left = 387
  lblTime.Top = 416
  lblTime.TabIndex = 5
  lblTime.Name = "lblTime"

  ADD OBJECT cntgrdpage AS ficcntgrdpage WITH ;
    Anchor = 15, ;
    Top = 12, ;
    Left = 12, ;
    Width = 678, ;
    Height = 257, ;
    TabIndex = 1, ;
    Name = "cntgrdpage", ;
    lbl1.TabIndex = 3, ;
    lbl1.Name = "lbl1", ;
    LBL4.Name = "LBL4", ;
    LBL3.Name = "LBL3", ;
    lbl2.TabIndex = 4, ;
    lbl2.Name = "lbl2", ;
    cntSearch.txtSearch.Name = "txtSearch", ;
    cntSearch.lbl.Name = "lbl", ;
    cntSearch.Top = 180, ;
    cntSearch.Left = 588, ;
    cntSearch.TabIndex = 5, ;
    cntSearch.Name = "cntSearch", ;
    cntNav.IMGREFRESH.Name = "IMGREFRESH", ;
    cntNav.cboLines.Name = "cboLines", ;
    cntNav.imgTop.Name = "imgTop", ;
    cntNav.imgPrev.Height = 11, ;
    cntNav.imgPrev.Width = 6, ;
    cntNav.imgPrev.Name = "imgPrev", ;
    cntNav.spnPage.Name = "spnPage", ;
    cntNav.imgNext.Name = "imgNext", ;
    cntNav.imgBot.Name = "imgBot", ;
    cntNav.Top = 226, ;
    cntNav.Left = 336, ;
    cntNav.TabIndex = 2, ;
    cntNav.Name = "cntNav"

  ADD OBJECT pagedgrid.cntgrdpage.grid AS ficgrd WITH ;
    Height = 204, ;
    Left = 360, ;
    ReadOnly = .T., ;
    RecordSource = "orders_", ;
    TabIndex = 1, ;
    Top = 12, ;
    Width = 320, ;
    AllowCellSelection = .F., ;
    Name = "grid"

  ADD OBJECT cmgnav AS ficcmg WITH ;
    ButtonCount = 4, ;
    Anchor = 6, ;
    BackStyle = 0, ;
    BorderStyle = 0, ;
    Height = 36, ;
    Left = 152, ;
    Top = 231, ;
    Width = 176, ;
    TabIndex = 3, ;
    Name = "cmgNav", ;
    Ficcmd1.Top = 2, ;
    Ficcmd1.Left = 3, ;
    Ficcmd1.Height = 31, ;
    Ficcmd1.Width = 36, ;
    Ficcmd1.Caption = "|<", ;
    Ficcmd1.ToolTipText = "First record", ;
    Ficcmd1.Name = "cmdTop", ;
    Ficcmd2.Top = 2, ;
    Ficcmd2.Left = 46, ;
    Ficcmd2.Height = 31, ;
    Ficcmd2.Width = 36, ;
    Ficcmd2.Caption = "<", ;
    Ficcmd2.ToolTipText = "Previous record", ;
    Ficcmd2.Name = "cmdUp", ;
    Ficcmd3.Top = 2, ;
    Ficcmd3.Left = 89, ;
    Ficcmd3.Height = 31, ;
    Ficcmd3.Width = 36, ;
    Ficcmd3.Caption = ">", ;
    Ficcmd3.ToolTipText = "Next record", ;
    Ficcmd3.Name = "cmdDown", ;
    Ficcmd4.Top = 2, ;
    Ficcmd4.Left = 132, ;
    Ficcmd4.Height = 31, ;
    Ficcmd4.Width = 37, ;
    Ficcmd4.Caption = ">|", ;
    Ficcmd4.ToolTipText = "Last record", ;
    Ficcmd4.Name = "cmdBottom"

  ADD OBJECT tutoinfoboxfic AS ficebxsrcecode WITH ;
    Anchor = 14, ;
    Height = 140, ;
    Left = 12, ;
    TabIndex = 6, ;
    Top = 274, ;
    Width = 774, ;
    ZOrderSet = 21, ;
    Name = "tutoInfoBoxFic"

  ADD OBJECT ficlbl1 AS ficlbl WITH ;
    Anchor = 6, ;
    Alignment = 1, ;
    Caption = "Navigate records", ;
    Height = 17, ;
    Left = 24, ;
    Top = 241, ;
    Width = 125, ;
    Name = "Ficlbl1"

  PROCEDURE wreadme
    lparameters cLangUser
    cLangUser = Evl(Evl(m.cLangUser, m.this.wcLangUser), cLangUser())

    local result as String

    * remove '.F. && ' whenever a translation is available

    do case
    case .F. && m.cLangUser = 'fr' && copy-paste this block to support another language
      text to result noshow flags 1 && pretext 3
      endtext

    case .F. && m.cLangUser = 'de' && copy-paste this block to support another language
      text to result noshow flags 1 && pretext 3
      endtext

    case .F. && m.cLangUser = 'es' && copy-paste this block to support another language
      text to result noshow flags 1 && pretext 3
      endtext

    case .F. && m.cLangUser = 'it' && copy-paste this block to support another language
      text to result noshow flags 1 && pretext 3
      endtext

    case .F. && m.cLangUser = 'pt' && copy-paste this block to support another language
      text to result noshow flags 1 && pretext 3
      endtext

    otherwise && default: English
      text to result noshow flags 1 && pretext 3
      Desktop applications can manage long lists ('000 of records) very easily
      Conversely, because of the time it takes to:
      - serialize the list on server side,
      - transfer the list through the network,
      - eventually convert the list into HTML and display it in the browser,
      Web Applications need be able to reduce the number of lines loaded in the browser and, very easily load another set of lines.

      This list management process is generally called '
paging': the entire list is divided into 'pages' that user can display on demand. Ideally, moving between pages should be pretty fast so that paging provides a similar comfort of use as in the desktop experience.

      Obviously, if user can sort the list on a column, generally by clicking the corresponding header, sorting should happen on the whole list and not just on the bunch of lines displayed as a page. Similarly, a search feature should address the full list range.

      FoxInCloud addresses this problem in a very simple and handy manner: if you have a grid with a Reccount(.RecordSource) that can be greater than 1,000, and this grid.RecordSource has a primary or candidate key (or you can create one):
      - drop your subclass of awCntGrdPage (eg. xxxCntGrdPage) next to your grid
      - size and move your container based on awCntGrdPage like the grid, send to the background
      - select your grid and CUT it
      - enter into the container (right-click, edit) and PASTE the grid inside
      - resize the grid to leave some space in the bottom for the page navigation bar
      - give the container the SAME NAME as the grid

      At run time the container will automatically:
      - create a paged cursor derived from current grid.recordSource and set it as the new grid.recordSource
      - towards the outside world, appear like the grid; in fact the container fakes to be the grid: when code running in some other member of the form addresses the grid, the container handles the call and defers to the contained grid when appropriate.

      As mentioned earlier, this can work only if your grid.recordSource has or can have a primary or candidate key.

      If grid.recordSource is a cursor, you can simply index it after generation:
      this...grid.recordSource = '
'
      SELECT ... into cursor grdRecordSource
      index on xxx candidate tag xxx && you can also use a composite index expression, eg. xxx+yyy
      this...grid.recordSource = '
grdRecordSource'

      If grid.recordSource is a view, you can index it after first use, in Form.Load() or, if you prefer open the view in the form'
s dataEnvironement, in the dataEnvironment cursor object's .Init():
      use myView nodata in 0 && you may also opened the view in the dataEnvironnement
      select myView
      index on xxx candidate tag xxx && you can also use a composite index expression, eg. xxx+yyy

      If grid.recordSource is a table, you need to figure what column or expression can be unique across all records; you should do this at design time:
      select myTable
      index on xxx candidate tag xxx && you can also use a composite index expression, eg. xxx+yyy

      endtext

    endcase

    return m.result
  ENDPROC

  PROCEDURE Load
    lParameters void_reminder_to_call_DoDefault_in_your_subclass_when_all_views_and_cursorAdapters_are_open

    && this code could also be located in dataEnvironment'
s cursor.Init()

    select orders_ && view opened nodata in dataEnvironment
    index on customer_id+order_id tag cust_ord candidate collate 'machine' && Using the paged grid requires a candidate unique index
    set order to
    go top

    return DoDefault() && important in form.Load() -- see void parameter above
  ENDPROC

  PROCEDURE grid.RightClick
    if m.thisForm.wlHTMLgen && FoxInCloud Automated Adaptation
      return .T. && Execute this VFP event code on FoxInCloud server
    endif

    thisForm.wMessageBox('aw.vcx!awGrd.this_Access() ' + Textmerge(ICase(;
       thisform.wcLangUser = 'fr',  [redirige this.Parent vers le parent original (formulaire) :],; && copy-paste this line to add another language support
                                    [redirects this.Parent to the original parent (form):]; && default: English
         ) + CRLF;
       + [this.Parent: '<<Sys(1272, m.this.Parent)>>', class: '<<m.this.Parent.Class>>', BaseClass: '<<m.this.Parent.BaseClass>>'];
       );
      , 64;
      , 'this.Parent?';
      )
  ENDPROC

  PROCEDURE grid.Init
    thisForm.Init_SrceCode(m.this, 'RightClick', .T.)
    this.AutoFit('20%')

    return DoDefault()
  ENDPROC

  PROCEDURE cmgnav.Init
    local cmd as ficCmd of ficSample

    for each cmd in this.Objects foxobject
      thisForm.Init_SrceCode(m.cmd, 'click', .T.)
      wcPropSaveEdit(m.cmd, 'Enabled')
    endfor

    return DoDefault()
  ENDPROC

  PROCEDURE cmgnav.cmdTop.refresh_
    this.Enabled = !lBOF(thisForm.grid.RecordSource) && modify command abData
  ENDPROC

  PROCEDURE cmgnav.cmdTop.Click
    if m.thisForm.wlHTMLgen && FoxInCloud Automated Adaptation
      return .T. && Execute this VFP event code on FoxInCloud server
    endif

    && code unchanged though grid was moved from thisForm into thisForm.cntGrdPage
    &&

    go top in (thisForm.grid.RecordSource)
    thisForm.refresh
  ENDPROC

  PROCEDURE cmgnav.cmdUp.refresh_
    this.Enabled = !lBOF(thisForm.grid.RecordSource) && modify command abData
  ENDPROC

  PROCEDURE cmgnav.cmdUp.Click
    if m.thisForm.wlHTMLgen && FoxInCloud Automated Adaptation
      return .T. && Execute this VFP event code on FoxInCloud server
    endif

    && code unchanged though grid was moved from thisForm into thisForm.cntGrdPage
    &&

    skip -1 in (thisForm.grid.RecordSource)
    thisForm.refresh
  ENDPROC

  PROCEDURE cmgnav.cmdDown.refresh_
    this.Enabled = !lEOF(thisForm.grid.RecordSource) && modify command abData
  ENDPROC

  PROCEDURE cmgnav.cmdDown.Click
    if m.thisForm.wlHTMLgen && FoxInCloud Automated Adaptation
      return .T. && Execute this VFP event code on FoxInCloud server
    endif

    && code unchanged though grid was moved from thisForm into thisForm.cntGrdPage
    &&

    skip in (thisForm.grid.RecordSource)
    thisForm.refresh
  ENDPROC

  PROCEDURE cmgnav.cmdBottom.refresh_
    this.Enabled = !lEOF(thisForm.grid.RecordSource) && modify command abData
  ENDPROC

  PROCEDURE cmgnav.cmdBottom.Click
    if m.thisForm.wlHTMLgen && FoxInCloud Automated Adaptation
      return .T. && Execute this VFP event code on FoxInCloud server
    endif

    && code unchanged though grid was moved from thisForm into thisForm.cntGrdPage
    &&

    go bottom in (thisForm.grid.RecordSource)
    thisForm.refresh
  ENDPROC

ENDDEFINE
*-- EndDefine: pagedgrid
**************************************************