//////////////////////////////////////////////////////////////////////
//
//  COMBOCOL.PRG
//
//  Copyright:
//      Alaska Software, (c) 1999-2002. Alle Rechte vorbehalten.         
//  
//  Inhalt:
//      Das Beispiel implementiert die XbpComboboxColumn Klasse, die
//      eine Combobox zum Editieren einzelner Zellen in einem
//      XbpBrowse Objekt verwendet.
//   
//      Die Combobox wird durch die Klasse XbpGetCombobox 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 eine Combobox Klasse mit einem eindeutigen :dataLink 
//         versieht.
//   
//////////////////////////////////////////////////////////////////////

#include "Appevent.ch"
#include "Common.ch"
#include "Xbp.ch"


CLASS XbpComboboxColumn FROM XbpGetColumn
                                     ** Ueberladene XbpGetColumn Methoden
   PROTECTED:                        // umbenannt zur besseren Lesbarkeit
   VAR    comboBox IS xbpGet IN XbpGetColumn
   METHOD setPosAndSize              // Setze Pos und Groeáe entsprechend der Zeile

                                     ** Neu in dieser Klasse
   VAR    aItems                     // Array fuer die Werte der Combobox

   EXPORTED:                         // Ueberladene XbpGetColumn Methoden
   METHOD init                       // Initialisiet das Objekt
   METHOD destroy                    // Gibt Speicher frei
   METHOD createXbp                  // Erzeugt das XbpGetCombobox Objekt

                                     ** Neu in dieser Klasse
   VAR    comboType                  // wird an ::combobox:type zugweisen
   VAR    comboHeight                // Hoehe der Combobox
   METHOD setItems                   // Kopiert Arrayelemente in die Combobox
ENDCLASS


/*
 * Objekt initialisieren
 */
METHOD XbpComboboxColumn:init( p1, p2, p3, p4, p5, p6 )
   ::xbpGetColumn:init( p1, p2, p3, p4, p5, p6 )
   ::aItems           := {}
   ::comboType        := XBPCOMBO_DROPDOWN
   ::comboHeight      := 150
RETURN self


/*
 * Resourcen freigeben und Arrayreferenz der gueltigen Werte loeschen.
 */
METHOD XbpComboboxColumn:destroy
   ::aItems := {}
   ::xbpGetColumn:destroy()
RETURN self


 /*
 * Erzeuge anstelle von XbpGet ein XbpComboBox Objekt und weise den
 * :dataLink Codeblock zu.
 *
 * Hinweis: die Instanzvariable :comboBox ist eigentlich in der Superklasse
 *          als :xbpGet deklariert, aber in dieser Klasse umbenannt worden.
 *          Dadurch wird der Code besser lesbar.
 */
METHOD XbpComboboxColumn:createXbp
   ::comboBox              := XbpGetComboBox():new( ::dataArea, ::dataArea, NIL, NIL, NIL, .F. )
   ::combobox:controller   := self
   ::comboBox:type         := ::comboType
   ::comboBox:dataLink     := ::dataLink

   IF ::bufferLength <> NIL
      ::comboBox:bufferLength := ::bufferLength
   ENDIF

   ::comboBox:create()
   ::comboBox:setItems( ::aItems )
RETURN self

 
/*
 * X/Y Koordinaten fuer die Anzeige der Combobox bestimmen.
 */
METHOD XbpComboboxColumn:setPosAndSize( nRowPos )
   LOCAL aRect, aPos, aSize

   aRect    := ::dataArea:cellRect( nRowPos )
   aPos     := { aRect[1], aRect[2] }
   aSize    := { aRect[3]-aRect[1], aRect[4]-aRect[2] }
   aPos[2]  -= ::comboHeight
   aSize[2] += ::comboHeight

   ::comboBox:setPos ( aPos  )
   ::comboBox:setSize( aSize )
RETURN self


/*
 * Array clonen, das die Zeichenketten der gueltigen Werte enthaelt
 */
METHOD XbpComboboxColumn:setItems( aStrings )
   ::aItems := AClone( aStrings )
   IF ::comboBox <> NIL
      ::comboBox:setItems( ::aItems )
   ENDIF
RETURN self


******************************************************************************
/*
 * Combobox Klasse mit eindeutigem :dataLink und ueberladener
 * :keyboard() Methode.
 *
 *    - :dataLink, :setData(), :getData() gilt immer fuer die XbpSLE
 *      Komponente der Combobox
 *
 *    - Die Tasten xbeK_UP, xbeK_DOWN werden zur Browser-Navigation
 *      verwendet, solange die Combobox nicht aufgeklappt ist
 */

CLASS XbpGetCombobox FROM XbpCombobox
   EXPORTED:
   VAR    dataLink
   VAR    controller
   VAR    bufferLength

   ACCESS ASSIGN METHOD dataLink
   ACCESS ASSIGN METHOD bufferLength
   METHOD clear
   METHOD undo
   METHOD setData
   METHOD editBuffer
   METHOD getData
   METHOD setItems
   METHOD getItems
   METHOD keyboard
ENDCLASS


METHOD XbpGetCombobox:dataLink( bData )
   IF PCount() == 1
      ::XbpSLE:datalink := bData
   ENDIF
RETURN ::XbpSLE:datalink


METHOD XbpGetCombobox:bufferLength( nLen )
   IF Valtype( nLen ) == "N"
      ::XbpSLE:bufferLength := nLen
   ENDIF
RETURN ::XbpSLE:bufferLength


METHOD XbpGetCombobox:clear
RETURN ::xbpSLE:clear()


METHOD XbpGetCombobox:undo
RETURN ::xbpSLE:undo()


METHOD XbpGetCombobox:editBuffer
RETURN ::xbpSLE:editBuffer()


METHOD XbpGetCombobox:setData( xValue )
   IF xValue == NIL
      xValue := ::xbpSLE:setData()
   ELSE
      xValue := ::xbpSLE:setData( xValue )
   ENDIF
   ::changed := .F.
RETURN xValue


METHOD XbpGetCombobox:getData
   LOCAL cValue := Trim( ::xbpSLE:getData() )
   LOCAL aItems := ::getItems()
   LOCAL nPos

   /*
    * Falls ein eingegebener Wert nicht in der Listbox enthalten ist,
    * wird er an der richtigen Position eingefuegt. Die Combobox "lernt".
    */
   IF Ascan( aItems, {|c| Upper(c) == Upper(cValue) } ) == 0
      nPos := AScan( aItems, {|c| Upper(c) > Upper(cValue) } )
      IF nPos == 0
         ::addItem( cValue )
      ELSE
         ::insItem( nPos, cValue )
      ENDIF
   ENDIF
RETURN cValue


METHOD XbpGetCombobox:setItems( aArray )
   ::xbpComboBox:clear()
RETURN AEval( aArray, {|c| ::addItem( c ) } )


METHOD XbpGetCombobox:getItems
RETURN AEval( Array( ::numItems() ), ;
              {|x,i| x := ::getItem(i) },,, .T. )


METHOD XbpGetCombobox:keyboard( nKey )
   DO CASE
   CASE nKey == xbeK_ALT_DOWN .OR. nKey == xbeK_CTRL_RETURN
      /*
       * Listbox aufklappen.
       */
      ::listboxFocus( .T. )

   CASE .NOT. ::listboxFocus()
      /*
       * Wenn die Combobox nicht in eine Browserspalte eingebettet ist
       * oder wenn das :contoller Objekt (XbpComboboxColumn) die Taste
       * nicht verarbeitet, wird das Default Key-Handling von
       * XbpCombobox ausgefuehrt.
       */
      IF ::controller == NIL .OR. .NOT. ::controller:keyboard( nKey )
         DO CASE
         CASE ::controller <> NIL .AND. ::type == XBPCOMBO_DROPDOWNLIST
            IF nKey == xbeK_LEFT
               ::controller:keyboard( xbeK_SH_TAB )
            ELSEIF nKey == xbeK_RIGHT
               ::controller:keyboard( xbeK_TAB )
            ELSE
               ::xbpCombobox:keyboard( nKey )
            ENDIF

         CASE nKey == xbeK_RETURN
            PostAppEvent( xbeLB_ItemSelected,,, self )
         OTHERWISE
            ::xbpCombobox:keyboard( nKey )
         ENDCASE
      ENDIF

   OTHERWISE
      /*
       * Alle anderen Situationen werden von XbpCombobox behandelt.
       */
      ::xbpCombobox:keyboard( nKey )

   ENDCASE
RETURN self
