//////////////////////////////////////////////////////////////////////
//
//  MLECOL.PRG
//
//  Copyright:
//      Alaska Software, (c) 1999-2002. Alle Rechte vorbehalten.         
//  
//  Inhalt:
//      Das Beispiel implementiert die XbpMleColumn Klasse, mit
//      der Memofelder in einem XbpBrowse Objekt angezeigt und editiert
//      werden knnen.
//   
//      Das XbpMle wird durch die Klasse MemoEditDialog bereitgestellt,
//      welche ebenfalls in dieser Datei implementiert ist.
//   
//  Bemerkungen:
//   
//      Die folgenden Programmiertechniken werden demonstriert:
//     
//      1. Wie man eine Klasse von der XbpGetColumn Klasse ableitet um
//         anstelle von XbpGet einen anderen Xbase Part zum Editieren
//         im Browser zu verwenden.
//     
//      2. Wie man einen :dataLink Codeblock "heimlich" ersetzt, so dass
//         der eine :dataLink Codeblock zur Anzeige in XbpColumn und ein
//         zweiter zum Editieren in XbpMle verwendet wird.
//   
//////////////////////////////////////////////////////////////////////

#include "Appevent.ch"
#include "Common.ch"
#include "Xbp.ch"


CLASS XbpMleColumn FROM XbpGetColumn
   PROTECTED:
   VAR    MemoDlg IS xbpGet IN XbpGetColumn
   VAR    _dataLink
   METHOD setPosAndSize

   EXPORTED:   
   METHOD create
   METHOD createXbp
   METHOD firstMemoLine
   METHOD hiliteRow
ENDCLASS


/*
 * Wechsele den :dataLink Codeblock aus, bevor das Objekt erzeugt wird.
 * Der originale :dataLink Codeblock verweist direkt auf ein Memofeld.
 * Der neue Codeblock gibt die erste Textzeile aus dem Memofeld zurck.
 * Diese wird in der Browserspalte angezeigt.
 */
METHOD XbpMleColumn:create( p1, p2, p3, p4, p5, p6 )
   ::bufferLength := 40
   ::_dataLink    := ::dataLink
   ::dataLink     := {|| ::firstMemoLine() }
   ::xbpGetColumn:create( p1, p2, p3, p4, p5, p6 )
RETURN self


METHOD XbpMleColumn:firstMemoLine
RETURN MemoLine( Eval( ::_dataLink ), ::bufferLength, 1 )


/*
 * Erzeuge anstelle von XbpGet ein MemoEditDialog Objekt und weise den
 * originalen :dataLink Codeblock zu, der auf das Memofeld zugreift.
 *
 * Hinweis 1: die Instanzvariable :MemoDlg ist eigentlich in der Superklasse
 *            als :xbpGet deklariert, aber in dieser Klasse umbenannt worden.
 *            Dadurch wird der Code besser lesbar.
 *
 * Hinweis 2: Der Owner vom MemoEditDialog ist das Fenster, das den Browser
 *            enthlt. Der Parent ist fr MemoEditDialog und Browser-Fenster
 *            identisch. Wenn das Browser-Fenster verschoben wird, wird
 *            das MemoEditDialog Fenster automatisch mitverschoben.
 */
METHOD XbpMleColumn:createXbp
   LOCAL oOwner := ::setParent()
   LOCAL oParent, aSize := { 220, 180 }

   DO WHILE .NOT. ( oOwner:IsDerivedFrom( "XbpDialog" ) .OR. oOwner:IsDerivedFrom( "XbpCrt" ) )
      oOwner := oOwner:setParent()
   ENDDO

   IF oOwner:isDerivedFrom( "XbpCrt" )
      oParent := AppDesktop()
   ELSE
      oParent := oOwner:setParent()
   ENDIF

   aSize[1]                := ::currentSize()[1]
   ::MemoDlg               := MemoEditDialog():new( oParent, oOwner,, aSize,, .F. )
   ::MemoDlg:controller    := self
   ::MemoDlg:dataLink      := ::_dataLink
   ::MemoDlg:moveWithOwner := .T.
   ::MemoDlg:title         := ::heading:getCell(1)
   ::MemoDlg:create()
RETURN self


/*
 * Ueberladen von XbpGetColumn: Nur die Position des MemoEditDialog Fensters
 * aendert sich mit dem Browse-Cursor, nicht die Groesse.
 *
 * Hinweis: Die Position des Browse Cursors kann nicht direkt zur
 *          Positionierung des MemoEditDialog Fensters verwendet werden.
 *          Die Koordinaten mssen auf den Ursprung des Koordinatensystems
 *          umgerechnet werden, das fr das Browser Fenster gilt.
 */
METHOD XbpMleColumn:setPosAndSize( nRowPos )
   LOCAL aRect  := ::dataArea:cellRect( nRowPos )
   LOCAL aPos   := { aRect[1], aRect[2] + ( aRect[4]-aRect[2] ) }
   LOCAL aSize  := ::MemoDlg:currentSize()
   LOCAL oOwner := ::MemoDlg:setOwner()

   aPos[1] += ::currentPos()[1] + ::setParent():currentPos()[1]
   aPos[2] += ::footing:currentSize()[2]

   aPos[1] += ::browser:currentPos()[1]
   aPos[2] += ::browser:currentPos()[2]

   aPos[1] += oOwner:currentPos()[1]
   aPos[2] += oOwner:currentPos()[2]

   aPos[1] := Max( 0, Min( aPos[1], oOwner:setParent():currentSize()[1]-aSize[1] ) )
   aPos[2] := Max( 0, aPos[2]-aSize[2] )

   ::MemoDlg:setPos( aPos )
RETURN self


/*
 * Ueberladen von XbpGetColumn: Das MemoEditDialog Fenster bleibt sichtbar
 */
METHOD XbpMleColumn:hiliteRow( nRowPos, lHilite, lFrame, lRepaint )
   DEFAULT nRowPos TO ::browser:rowPos

   IF ::active
      IF lHilite
         ::read( nRowPos )
      ELSE
         IF ::MemoDlg:changed
            ::MemoDlg:getData()
            ::xbpColumn:refreshRows( nRowPos, nRowPos )
         ENDIF
      ENDIF
   ENDIF

   ::xbpColumn:hiliteRow( nRowPos, lHilite, lFrame, lRepaint )
RETURN self


******************************************************************************
/*
 * MemoEditDialog Klasse mit eingebettetem XbpMle und :dataLink Codeblock
 */

CLASS MemoEditDialog FROM XbpDialog
   PROTECTED:
   VAR btnOk    
   VAR bntUndo

   EXPORTED:
   VAR    controller
   VAR    MLE        
   VAR    dataLink
   VAR    changed
   VAR    bufferLength
   ACCESS ASSIGN METHOD dataLink   
   ACCESS ASSIGN METHOD changed

   METHOD dings   /* TEST */
   METHOD init
   METHOD create
   METHOD setData
   METHOD getData
   METHOD editBuffer
   METHOD clear
   METHOD undo
   METHOD setMarked
   METHOD keyboard
ENDCLASS


METHOD MemoEditDialog:init( oParent, oOwner, aPos, aSize, aPP, lVisible )
   LOCAL aMinSize := {218,160}

   DEFAULT oParent  TO AppDesktop(), ;
           aPos     TO {0,0}, ;
           aSize    TO {218,160}, ;
           lVisible TO .F.

   aSize[1] := Max( aSize[1], aMinSize[1] )
   aSize[2] := Max( aSize[2], aMinSize[2] )

   ::XbpDialog:init( oParent, oOwner, aPos, aSize, aPP, lVisible )
   ::XbpDialog:taskList := .F.
   ::XbpDialog:title    := "Memo"
   ::XbpDialog:minSize  := aMinSize
   ::XbpDialog:close    := {|| ::controller:killRead() }
   ::XbpDialog:setInputFocus := {|x,y,obj| SetAppFocus( IIf(obj:isVisible(),obj:MLE, obj:controller) ) }

   ::MLE                := XbpMle():new( ::drawingArea )
   ::MLE:ignoreTab      := .T.
   ::MLE:wordWrap       := .T.
   ::MLE:horizScroll    := .F.

   ::btnOk              := XbpPushButton():new( ::drawingArea, , {8,8}, {88,24} )
   ::btnOk:caption      := "~Ok"
//   ::btnOk:activate     := {|| ::getData(), ::controller:killRead() }
   ::btnOk:activate     := {|| dings() }

   ::bntUndo            := XbpPushButton():new( ::drawingArea, , {112,8}, {88,24} )
   ::bntUndo:caption    := "~Undo"
   ::bntUndo:activate   := {|| ::undo()   , ::controller:killRead() }

   ::bufferLength       := 66
RETURN self

METHOD MemoEditDialog:dings()
LOCAL a := "b"
//   ::btnOk:activate     := {|| ::getData(), ::controller:killRead() }
      a := "c"
RETURN self

METHOD MemoEditDialog:create( oParent, oOwner, aPos, aSize, aPP, lVisible )
   ::XbpDialog:create( oParent, oOwner, aPos, aSize, aPP, lVisible )

   aPos     := {8,48}
   aSize    := ::drawingArea:currentSize()
   aSize[1] -= 16
   aSize[2] -= 56

   ::MLE:create(,, aPos, aSize )
   ::btnOk:create()
   ::bntUndo:create()

   ::drawingArea:resize := {|aOld, aNew| aNew[1] -= 16, ;
                                         aNew[2] -= 56, ;
                                         ::Mle:setSize( aNew ) }
RETURN self


/*
 * Methoden zum Editieren
 */
METHOD MemoEditDialog:setData( xValue )
   IF .NOT. ::isVisible()
      ::show()
   ENDIF

   IF PCount() == 0
      xValue := ::MLE:setData()
   ELSE
      xValue := ::MLE:setData( xValue )
   ENDIF
RETURN xValue


METHOD MemoEditDialog:getData
   LOCAL xRet := ::MLE:getData()

   ::changed := .F.
   ::controller:browser:refreshCurrent()
RETURN xRet


METHOD MemoEditDialog:editBuffer
RETURN ::MLE:editBuffer()


METHOD MemoEditDialog:clear
RETURN ::MLE:clear()


METHOD MemoEditDialog:undo
RETURN ::MLE:undo()


METHOD MemoEditDialog:setMarked( aMarked )
RETURN ::MLE:setMarked( aMarked )


METHOD MemoEditDialog:dataLink( bBlock )
   IF PCount() == 1
      ::MLE:dataLink := bBlock
   ENDIF
RETURN ::MLE:dataLink


METHOD MemoEditDialog:changed( lChanged )
   IF Valtype( lChanged ) == "L"
      ::MLE:changed( lChanged )
   ENDIF
RETURN ::MLE:changed


/*
 * xbeK_ALT_UP und xbeK_ALT_DOWN werden zur Navigation im Browser
 * verwendet.
 */
METHOD MemoEditDialog:keyboard( nKey )
   DO CASE
   CASE nKey == xbeK_ALT_F4
      ::controller:killRead()

   CASE nKey == xbeK_ALT_UP
      ::controller:keyboard( xbeK_UP )
      SetAppFocus( self )

   CASE nKey == xbeK_ALT_DOWN
      ::controller:keyboard( xbeK_DOWN )
      SetAppFocus( self )

   CASE nKey == xbeK_ALT_O
      ::getData()
      ::controller:killRead()

   CASE nKey == xbeK_ALT_U
      ::setData()
      ::controller:killRead()

   CASE .NOT. ::controller:keyboard( nKey )
      ::xbpDialog:keyboard( nKey )

   ENDCASE
RETURN self
