Files
harbour-core/harbour/contrib/mysql/tsqlbrw.prg
David Arturo Macias Corona 2f1ddb94d5 2004-10-05 05:39 UTC-0500 David Arturo Macias Corona <dmacias@mail.udg.mx>
* harbour/contrib/mysql/tmysql.prg
  * harbour/contrib/mysql/tsqlbrw.prg
    * Changes to approach Clipper behaviour
      NOTE: My changes are marked in source code with label "DAVID:", to
            help in quick review of changes, and these changes are
            described widely in files difer.txt, diffeng.txt
            These labels will be removed in a reasonable time

  + harbour/contrib/mysql/difer.txt
    Describe modifications to programs of harbour\contrib\mysql, in Spanish
  + harbour/contrib/mysql/diffeng.txt
    Describe modifications to programs of harbour\contrib\mysql, in English
2004-10-05 10:55:08 +00:00

417 lines
11 KiB
Plaintext

/*
* $Id$
*/
/*
* Harbour Project source code:
* MySQL TBrowse
* A TBrowse on a MySQL Table / query
*
* Copyright 2000 Maurilio Longo <maurilio.longo@libero.it>
* www - http://www.harbour-project.org
*
* 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, 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, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries 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 Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
#include "hbclass.ch"
#include "common.ch"
#include "inkey.ch"
#include "dbstruct.ch"
#include "mysql.ch"
/* NOTE:
In fact no, the 'regular syntax is the same as the VO one,
ACCESS Block Method Block()
or
ACCESS Block Inline ::MyVal
and
ASSIGN Block(x) Method Block(x)
or
ASSIGN Block(x) INLINE ::MyVal := x
*/
CLASS TBColumnSQL from TBColumn
DATA oBrw // pointer to Browser containing this column, needed to be able to
// retreive field values from Browse instance variable oCurRow
//DATA Picture // From clipper 5.3
DATA nFieldNum // This column maps field num from query
MESSAGE Block METHOD Block() // When evaluating code block to get data from source this method
// gets called. I need this since inside TBColumn Block I cannot
// reference Column or Browser instance variables
METHOD New(cHeading, bBlock, oBrw) // Saves inside column a copy of container browser
ENDCLASS
METHOD New(cHeading, bBlock, oBrw) CLASS TBColumnSQL
super:New(cHeading, bBlock)
::oBrw := oBrw
return Self
METHOD Block() CLASS TBColumnSQL
local xValue := ::oBrw:oCurRow:FieldGet(::nFieldNum)
local xType := ::oBrw:oCurRow:FieldType(::nFieldNum)
do case
case xType == "N"
xValue := Str(xValue, ::oBrw:oCurRow:FieldLen(::nFieldNum), ::oBrw:oCurRow:FieldDec(::nFieldNum))
case xType == "D"
xValue := "'" + DToC(xValue) + "'"
case xType == "L"
xValue := iif(xValue, ".T.", ".F.")
case xType == "C"
// Chr(34) is a double quote
// That is: if there is a double quote inside text substitute it with a string
// which gets converted back to a double quote by macro operator. If not it would
// give an error because of unbalanced double quotes.
xValue := Chr(34) + StrTran(xValue, Chr(34), Chr(34) + "+Chr(34)+" + Chr(34)) + Chr(34)
case xType == "M"
xValue := "' <MEMO> '"
otherwise
endcase
return &("{||" + xValue + "}")
/*--------------------------------------------------------------------------------------------------*/
/*
This class is more or less like a TBrowseDB() object in that it receives an oQuery/oTable
object and gives back a browseable view of it
*/
CLASS TBrowseSQL from TBrowse
DATA oCurRow // Active row inside table / sql query
DATA oQuery // Query / table object which we are browsing
METHOD New(nTop, nLeft, nBottom, nRight, oServer, oQuery, cTable)
METHOD EditField() // Editing of hilighted field, after editing does an update of
// corresponding row inside table
METHOD BrowseTable(lCanEdit, aExitKeys) // Handles standard moving inside table and if lCanEdit == .T.
// allows editing of field. It is the stock ApplyKey() moved inside a table
// if lCanEdit K_DEL deletes current row
// When a key is pressed which is present inside aExitKeys it leaves editing loop
METHOD KeyboardHook(nKey) // Where do all unknown keys go?
ENDCLASS
METHOD New(nTop, nLeft, nBottom, nRight, oServer, oQuery, cTable) CLASS TBrowseSQL
local i, oCol
super:New(nTop, nLeft, nBottom, nRight)
::oQuery := oQuery
// Let's get a row to build needed columns
::oCurRow := ::oQuery:GetRow(1)
// positioning blocks
::SkipBlock := {|n| ::oCurRow := Skipper(@n, ::oQuery), n }
::GoBottomBlock := {|| ::oCurRow := ::oQuery:GetRow(::oQuery:LastRec()), 1 }
::GoTopBlock := {|| ::oCurRow := ::oQuery:GetRow(1), 1 }
// Add a column for each field
for i := 1 to ::oQuery:FCount()
// No bBlock now since New() would use it to find column length, but column is not ready yet at this point
oCol := TBColumnSQL():New(::oCurRow:FieldName(i),, Self)
if ::oCurRow:FieldType(i) <> "M"
oCol:Width := Max(::oCurRow:FieldLen(i), Len(oCol:Heading))
else
oCol:Width := 10
endif
// which field does this column display
oCol:nFieldNum := i
// Add a picture
do case
case ::oCurRow:FieldType(i) == "N"
oCol:picture := replicate("9", oCol:Width)
case ::oCurRow:FieldType(i) $ "CM"
oCol:picture := replicate("!", oCol:Width)
endcase
::AddColumn(oCol)
next
return Self
static function Skipper(nSkip, oQuery)
local i := 0
do case
case (nSkip == 0 .OR. oQuery:LastRec() == 0)
oQuery:Skip(0)
case (nSkip > 0)
while ( i < nSkip ) // Skip Foward
//DAVID: change in TMySQLquery:eof() definition if oQuery:eof()
if oQuery:recno() == oQuery:lastrec()
exit
endif
oQuery:Skip(1)
i++
enddo
case ( nSkip < 0 )
while ( i > nSkip ) // Skip backward
//DAVID: change in TMySQLquery:bof() definition if oQuery:bof()
if oQuery:recno() == 1
exit
endif
oQuery:Skip(-1)
i--
enddo
endcase
nSkip := i
return oQuery:GetRow(oQuery:RecNo())
METHOD EditField() CLASS TBrowseSQL
local oCol
local aGetList
local nKey
local xGetValue
local cMemoBuff, cMemo
// Get the current column object from the browse
oCol := ::getColumn(::colPos)
// Editing of a memo field requires a MemoEdit() window
if ::oCurRow:FieldType(oCol:nFieldNum) == "M"
/* save, clear, and frame window for memoedit */
cMemoBuff := SaveScreen(10, 10, 22, 69)
Scroll(10, 10, 22, 69, 0)
DispBox(10, 10, 22, 69)
/* use fieldspec for title */
//@ 10,((76 - Len(::oCurRow:FieldName(oCol:nFieldNum)) / 2) SAY " " + (::oCurRow:FieldName(oCol:nFieldNum)) + " "
/* edit the memo field */
cMemo := MemoEdit(::oCurRow:FieldGet(oCol:nFieldNum), 11, 11, 21, 68, .T.)
if Lastkey() == K_CTRL_END
::oCurRow:FieldPut(oCol:nFieldNum, cMemo)
/* NOTE: To do in a better way */
if !::oQuery:Update(::oCurRow)
Alert(Left(::oQuery:Error(), 60))
endif
endif
RestScreen(10, 10, 22, 69, cMemoBuff)
else
// Create a corresponding GET
// NOTE: I need to use ::oCurRow:FieldPut(...) when changing values since message redirection doesn't work at present
// time for write access to instance variables but only for reading them
aGetList := { getnew( row(), col(), ;
{|xValue| iif(xValue == nil, Eval(oCol:Block), ::oCurRow:FieldPut(oCol:nFieldNum, xValue))} ,;
oCol:heading, ;
oCol:picture, ;
::colorSpec ) }
// Set initial cursor shape
//setcursor( iif( ReadInsert(), SC_INSERT, SC_NORMAL ) )
ReadModal(aGetList)
//setcursor( SC_NONE )
/* NOTE: To do in a better way */
if !::oQuery:Update(::oCurRow)
Alert(Left(::oQuery:Error(), 60))
endif
endif
if !::oQuery:Refresh()
Alert(::oQuery:Error())
endif
::RefreshAll()
// Check exit key from get
nKey := LastKey()
if nKey == K_UP .or. nKey == K_DOWN .or. ;
nKey == K_PGUP .or. nKey == K_PGDN
// Ugh
keyboard( chr( nKey ) )
endif
RETURN Self
METHOD BrowseTable(lCanEdit, aExitKeys) CLASS TBrowseSQL
local nKey
local lKeepGoing := .T.
default nKey to nil
default lCanEdit to .F.
default aExitKeys to {K_ESC}
while lKeepGoing
while !::Stabilize() .and. NextKey() == 0
enddo
nKey := Inkey(0)
if AScan(aExitKeys, nKey) > 0
lKeepGoing := .F.
LOOP
endif
do case
case nKey == K_DOWN
::down()
case nKey == K_PGDN
::pageDown()
case nKey == K_CTRL_PGDN
::goBottom()
case nKey == K_UP
::up()
case nKey == K_PGUP
::pageUp()
case nKey == K_CTRL_PGUP
::goTop()
case nKey == K_RIGHT
::right()
case nKey == K_LEFT
::left()
case nKey == K_HOME
::home()
case nKey == K_END
::end()
case nKey == K_CTRL_LEFT
::panLeft()
case nKey == K_CTRL_RIGHT
::panRight()
case nKey == K_CTRL_HOME
::panHome()
case nKey == K_CTRL_END
::panEnd()
case nKey == K_RETURN .AND. lCanEdit
::EditField()
/*case nKey == K_DEL
if lCanEdit
if ! ::oQuery:Delete(::oCurRow)
Alert("not deleted " + ::oQuery:Error())
endif
if !::oQuery:Refresh()
Alert(::oQuery:Error())
endif
::inValidate()
::refreshAll():forceStable()
endif*/
otherwise
::KeyboardHook(nKey)
endcase
enddo
return Self
// Empty method to be subclassed
METHOD KeyboardHook(nKey) CLASS TBrowseSQL
return Self