; ------------------------------------------------------------------------------------------------

FUNCTION db_search_field::selevent, event

; The user selected a new search type with the droplist widget.

; Configure the search widget for the type of search indicated by
; new value of the droplist widget.

CASE event.index OF

   0: self->onesearch, 0  ; Single Parameter Search, "="
   1: self->onesearch, 1  ; Single Parameter Search, ">"
   2: self->onesearch, 2  ; Single Parameter Search, "<"

   3: self->twosearch     ; Double Parameter Search, " < < "

ENDCASE

RETURN, 0

END

; ------------------------------------------------------------------------------------------------

FUNCTION db_search_field::textevent, event

RETURN, 0

END

; ------------------------------------------------------------------------------------------------

PRO db_search_field::calc_search_str

; Querry the different fields in the widget and generate a search string
; Note: This procedure currently does no error checking.

; Get the the value from the text field

WIDGET_CONTROL, self.txt_id, GET_VALUE = val

; Figure out which of the relationship operaters in the drop list
; was selected

relid = WIDGET_INFO (self.sel_id, /DROPLIST_SELECT)

; Create the search string from the information entered in the widget.

IF relid EQ 0 THEN BEGIN

   str = STRTRIM (self.label, 2) + "=" + val
   GOTO, SELECT_END

ENDIF

IF relid EQ 1 THEN BEGIN

   str = STRTRIM (self.label, 2) + ">" + val
   GOTO, SELECT_END

ENDIF

IF relid EQ 2 THEN BEGIN

   str = STRTRIM (self.label, 2) + "<" + val
   GOTO, SELECT_END

ENDIF

IF relid EQ 3 THEN BEGIN

; Get the the value from the secondary text field

   WIDGET_CONTROL, self.tx2_id, GET_VALUE = val2

   str = val + "<" + STRTRIM (self.label, 2) + "<" + val2
   GOTO, SELECT_END

ENDIF

SELECT_END:

; Check if a value is currently defined for this widget.
; If one is, then free the pointer.

IF self.value NE PTR_NEW () THEN PTR_FREE, self.value

; Set self.value to point to the new search string for this field

self.value = PTR_NEW (str)

RETURN

END

; ------------------------------------------------------------------------------------------------

PRO db_search_field::onesearch, rel

; Check if the current format is a two field search.  If it is then we are going to
; have to redraw most of the widget.

IF self.format EQ 2 THEN BEGIN

; Start by destroying previously existing widgets needed for two field search.

   IF self.lbl_id NE 0 THEN WIDGET_CONTROL, self.lbl_id, /DESTROY
   IF self.rel_id NE 0 THEN WIDGET_CONTROL, self.rel_id, /DESTROY
   IF self.re2_id NE 0 THEN WIDGET_CONTROL, self.re2_id, /DESTROY
   IF self.txt_id NE 0 THEN WIDGET_CONTROL, self.txt_id, /DESTROY
   IF self.tx2_id NE 0 THEN WIDGET_CONTROL, self.tx2_id, /DESTROY

; Now set the id's of the widgets destroyed to 0.

   self.lbl_id = 0L
   self.rel_id = 0L
   self.re2_id = 0L
   self.txt_id = 0L
   self.tx2_id = 0L

ENDIF

; If we need to go and recreate any widgets, go ahead and do that now.

IF self.lbl_id EQ 0L THEN BEGIN

   self.lbl_id = WIDGET_LABEL (          $
         self.src_id,             $
         VALUE =  self.label,           $
         FONT =  self.buttonfnt          $
         )

ENDIF

IF self.rel_id EQ 0L THEN BEGIN

   self.rel_id = WIDGET_LABEL (          $
         self.src_id,             $
         VALUE =  "   ",           $
         FONT =  self.buttonfnt          $
         )

ENDIF

IF self.txt_id EQ 0L THEN BEGIN

   self.txt_id = WIDGET_TEXT (           $
         self.src_id,             $
         FONT  = self.fieldfont,         $
         VALUE = '0',             $
         /FRAME ,             $
         /EDITABLE,           $
         EVENT_FUNC = 'db_search_field_event_handler',  $
         UVALUE = {method: "textevent", object:self}    $
         )

ENDIF

; Reset the format value to indicate a single field search.

self.format = 1

; Set rel widgit to display the correct relationship operator.

CASE rel OF

   0: WIDGET_CONTROL, self.rel_id, SET_VALUE = " = "
   1: WIDGET_CONTROL, self.rel_id, SET_VALUE = " > "
   2: WIDGET_CONTROL, self.rel_id, SET_VALUE = " < "

ENDCASE

RETURN

END

; ------------------------------------------------------------------------------------------------


PRO db_search_field::twosearch

; Check if the current format is a one field search.  If it is then we are going to
; have to redraw most of the widget.

IF self.format EQ 1 THEN BEGIN

; Start by destroying previously existing widgets needed for a one field search.

   IF self.lbl_id NE 0 THEN WIDGET_CONTROL, self.lbl_id, /DESTROY
   IF self.rel_id NE 0 THEN WIDGET_CONTROL, self.rel_id, /DESTROY
   IF self.txt_id NE 0 THEN WIDGET_CONTROL, self.txt_id, /DESTROY

; Now set the id's of the widgets destroyed to 0.

   self.lbl_id = 0L
   self.rel_id = 0L
   self.txt_id = 0L

ENDIF

; If we need to go and recreate any widgets (which we probably do),
; go ahead and do that now.

IF self.txt_id EQ 0L THEN BEGIN

   self.txt_id = WIDGET_TEXT (           $
         self.src_id,             $
         FONT  = self.fieldfont,         $
         VALUE = '0',             $
         /EDITABLE,           $
         EVENT_FUNC = 'db_search_field_event_handler',  $
         UVALUE = {method: "textevent", object:self}    $
         )

ENDIF

IF self.rel_id EQ 0L THEN BEGIN

   self.rel_id = WIDGET_LABEL (          $
         self.src_id,             $
         VALUE =  "   ",           $
         FONT =  self.buttonfnt          $
         )

ENDIF

IF self.lbl_id EQ 0L THEN BEGIN

   self.lbl_id = WIDGET_LABEL (          $
         self.src_id,             $
         VALUE =  self.label,           $
         FONT =  self.buttonfnt          $
         )

ENDIF

IF self.re2_id EQ 0L THEN BEGIN

   self.re2_id = WIDGET_LABEL (          $
         self.src_id,             $
         VALUE =  "   ",           $
         FONT =  self.buttonfnt          $
         )

ENDIF

IF self.tx2_id EQ 0L THEN BEGIN

   self.tx2_id = WIDGET_TEXT (           $
         self.src_id,             $
         FONT  = self.fieldfont,         $
         VALUE = '0',             $
         /EDITABLE,           $
         EVENT_FUNC = 'db_search_field_event_handler',  $
         UVALUE = {method: "textevent", object:self}    $
         )

ENDIF

; Reset the format value to indicate a double field search.

self.format = 2

; Setthe rel and re2 widgit to display the correct relationship operators.

WIDGET_CONTROL, self.rel_id, SET_VALUE = " < "
WIDGET_CONTROL, self.re2_id, SET_VALUE = " < "

RETURN

END

; ------------------------------------------------------------------------------------------------

FUNCTION db_search_field::get_value

; This method returns the actual value of the compound widget.
; If the widget doesn't have a value for some reason, then the
; undefined value is returned.

; Call the method calc_search_str to generate the search string
; from the values that the user has chosen.

self->calc_search_str

; If a value is defined for the widget, return it.  Otherwise return the undefined marker.

IF self.value NE PTR_NEW () THEN BEGIN

   RETURN, *self.value

ENDIF ELSE BEGIN

   RETURN, *self.undefined

ENDELSE

END

; ------------------------------------------------------------------------------------------------

PRO db_search_field::getproperty, $
;
; This method allows you to obtain various properties of
; the compound widget via output keywords.
;

   LST_XSIZE = lst_xsize,       $ ; Maximum number of characters displayed in the list widget.
   DATABASE = database,         $ ; Name of the database to interogate.
   DESCRIPTION = description,   $ ; Set to TRUE (1) if descriptions are to be displayed.
   RESIZE = resize,             $ ; Set to enable resizing the list widget to accomadate long text.
   VALUE = value,               $ ; The "value" of the compound widget.
   _EXTRA = extra                 ; Passes along extra keywords to this method.

; Call the default widget version of this method to get those properties which are common
; to all widgets.

self->def_widget_obj::getproperty, _EXTRA = extra

; Get the properties.

value = self.value
lst_xsize = self.lst_xsize
database = self.database
description = self.description
resize = self.resize

RETURN

END

; ------------------------------------------------------------------------------------------------

PRO db_search_field::setproperty, $
;
; This method allows you to set various properties of the compound widget.
;
   RESIZE = resize,             $ ; Set to enable resizing the list widget to accomadate long text.
   _EXTRA = extra                 ; Passes along extra keywords to this method.


; Call the default widget version of this method to set those properties which are common
; to all widgets.

self->def_widget_obj::setproperty, _EXTRA = extra

; Set the update flag to 0 (FALSE).  If the widget needs to be updated, then
; it will be set to 1 (TRUE)

update = 0

; Set the properties, if needed.

IF N_ELEMENTS (resize) NE 0 THEN self.resize = KEYWORD_SET (resize)

END

; ------------------------------------------------------------------------------------------------


FUNCTION db_search_field::init, $ ; The compound widget DB_SEARCH_FIELD INIT method..
   parent,                      $ ; The parent widget. Required for all compound widgets.
   COLUMN = column,             $ ; Align the widget in columns.
   ROW = row,                   $ ; Align the widget in rows.
   LABEL = label,               $ ; The text label of the seach field.
   DB = db,                     $ ; The database the search field is derived from.
   DESCRIPTION = description,   $ ; Set to TRUE (1) if descriptions are to be displayed.
   _EXTRA = extra,              $ ; Passes along extra keywords to the text widget.

; Preprocess the row and column keywords.

row    = KEYWORD_SET (row)
column = KEYWORD_SET (column)

; Make sure that either row x/or column is enabled (row is default).

IF row EQ 1 AND column EQ 1 THEN column = 0
IF row EQ 0 AND column EQ 0 THEN row = 1

; Call the default widget intitialization routine

res = self->def_widget_obj::init (parent, _EXTRA = extra, COLUMN = column, ROW = row)

; Check keyword values.

IF N_ELEMENTS (label)       EQ 0 THEN label = ""
IF N_ELEMENTS (db)          EQ 0 THEN db = ""
IF N_ELEMENTS (description) EQ 0 THEN description = 0

; Make sure that label is string value.

label = STRING (label [0])

   ; Make sure that title and label are defined.

IF title EQ "" THEN title = "Search Field"

IF label EQ "" THEN BEGIN

   IF name NE "" THEN label = name ELSE label = title

ENDIF

   ; Make sure the label is at least 10 characters long.  We will insert some extra
   ; spaces on the end to fill it out if is not.

label = STRING (label, FORMAT = '(A, T10 )')

   ; Check if db is defined.  If it is. make sure that it is also 10 characters long.
   ; Again, we will insert some extra spaces if it is not.

IF KEYWORD_SET (db) THEN db = STRING (db, FORMAT = '(A, T10 )')

   ; Initialize the base node object.

IF (self->base_node_obj::init ( name )) EQ 0 THEN RETURN, 0

   ; Print a warning message if DEBUG has been defined.

IF debug THEN PRINT, 'WARNING:  DEBUG is enabled for ' + name + ' ' + title + ' widget.'

   ; Populate the object.

IF NOT orphan THEN self.parent = parent ELSE self.parent = -1

self.event_pro = event_pro
self.event_func = event_func
self.undefined = PTR_NEW (undefined)
self.nonsensitive = nonsensitive
self.debug = debug
self.name = name
self.label = label
self.db = db
self.labelfont = labelfont
self.fieldfont = fieldfont
self.buttonfnt = buttonfnt
self.destroy_on_exit = doe

   ; Create the widgets.

IF orphan THEN BEGIN

   self.tlb = WIDGET_BASE (           $
                FRAME = frame,            $
                BASE_ALIGN_CENTER = 1,           $
                TITLE = title,            $
                UNAME = name,             $
                UVALUE = uvalue,           $
                FUNC_GET_VALUE = 'db_search_field_get_value',   $
                EVENT_PRO = event_pro,           $
                EVENT_FUNC = event_func          $
                )

ENDIF ELSE BEGIN

   self.tlb = WIDGET_BASE (parent,          $
                FRAME = frame,            $
                BASE_ALIGN_CENTER = 1,           $
                TITLE = title,            $
                UNAME = name,             $
                UVALUE = uvalue,           $
                FUNC_GET_VALUE = 'db_search_field_get_value',   $
                EVENT_PRO = event_pro,           $
                EVENT_FUNC = event_func          $
                )

ENDELSE

align = WIDGET_BASE (self.tlb, ROW = row, COLUMN = column)

tmp = WIDGET_LABEL (              $
         align,               $
         VALUE =  self.db,           $
         FONT =  self.labelfont,         $
         /FRAME               $
         )

self.src_id  = WIDGET_BASE (align, /ROW)

self.sel_id = WIDGET_DROPLIST (          $
         self.src_id,             $
         FONT = buttonfnt,          $
         VALUE = ["=  ",          $
                  ">  ",          $
                  "<  ",          $
                  "< <"],          $
         EVENT_FUNC = 'db_search_field_event_handler',  $
         UVALUE = {method: "selevent", object:self}     $
         )

; Call the procedure onesearch to finish creating the child widgets.  The initial
; search type will be a single parameter search using the "=" relationship.

self->onesearch, 0

; Find the widget ID of the first widget child.

childid = WIDGET_INFO ( self.tlb, /CHILD )

; Store a pointer to the object as the uvalue of the child widget.

WIDGET_CONTROL, childid, SET_UVALUE = self

; Set up procedure to kill off the object if the widget dies

WIDGET_CONTROL, childid, KILL_NOTIFY = 'db_search_field_kill_notify'

RETURN, 1

END

; ------------------------------------------------------------------------------------------------

PRO db_search_field::cleanup

; This method makes sure there are not any pointers left on the heap.

; First check to see if the debug flag is set.  If it is, then create message
; describing the object that is about to be destroyed.

IF self->getdebug () THEN BEGIN

   msg = 'CLEANUP method called for '

   IF   self.name EQ ""               $
   THEN msg = msg + 'unnamed widget'           $
   ELSE msg = msg + 'widget: ' + self.name

   msg = msg + ' with ID: ' + STRING (self.tld, FORMAT = '(I0)')

   PRINT, msg

ENDIF

PTR_FREE, self.value
PTR_FREE, self.undefined

; Kill off the widget if it is still around.

IF WIDGET_INFO (self.tlb, /VALID_ID) THEN BEGIN

   WIDGET_CONTROL, self.tlb, /DESTROY

ENDIF

END

; ------------------------------------------------------------------------------------------------

FUNCTION db_search_field_event_handler, event

; The main event handler for the compound widget. It reacts
; to "messages" in the UValue of the text widget.
; The message indicates which object method to call. A message
; consists of an object method and the self object reference.

WIDGET_CONTROL, event.id, GET_UVALUE = message

; Check if need to print debugging info.

IF message.object->getdebug () THEN BEGIN

   message.object->getproperty, NAME = name

   msg = 'Calling method: ' + message.method + ' from '

   IF   name EQ ""                $
   THEN msg = msg + 'unnamed widget'           $
   ELSE msg = msg + 'widget: ' + name

   msg = msg + ' with ID: ' + STRING (event.id, FORMAT = '(I0)')

   PRINT, msg

ENDIF

event = CALL_METHOD (message.method, message.object, event)

RETURN, event

END

; ------------------------------------------------------------------------------------------------

PRO db_search_field_event__define

; The DB_SEARCH_FIELD Event Structure. Sent only if EVENT_PRO or EVENT_FUNC keywords
; have defined an event handler for the top-level base of the compound widget.

event = { DB_SEARCH_FIELD_EVENT,$ ; The name of the event structure.
          ID:      0L,      $ ; The ID of the compound widget's top-level base.
          TOP:     0L,      $ ; The widget ID of the top-level base of the hierarchy.
          HANDLER: 0L,      $ ; The event handler ID. Filled out by IDL.
          KEYWORD: "",      $ ; Returns the keyword  (name) of the selected field.
          REL:     "",   $ ; Defines the relationships between the keyword and values
          VAL1:    "",          $ ; Returns the first value of the search criterion
          VAL2:    ""    $ ; Returns the second value of the search criterion.
        }

END

; ------------------------------------------------------------------------------------------------

FUNCTION db_search_field_get_value, tlb

; This utilty routine is invoked when the user tries to get
; the value of the compound widget using the base widget
; identifier of the top-level base of the compound widget.
; The self object is located, and the Get_Value method is called
; on the object.

childid = WIDGET_INFO (tlb, /CHILD)

WIDGET_CONTROL, childid, GET_UVALUE = self

RETURN, self->get_value ()

END

; ------------------------------------------------------------------------------------------------

PRO db_search_field_kill_notify, widget_id

; This widget call-back procedure makes sure the self object is
; destroyed when the widget is destroyed.

WIDGET_CONTROL, widget_id, GET_UVALUE = obj

; Kill off the object associated with the widget, but only if it is an orphan

; IF obj->destroy_on_exit () THEN OBJ_DESTROY, obj

OBJ_DESTROY, obj

END

; ------------------------------------------------------------------------------------------------

PRO db_search_field__define

obj = { DB_SEARCH_FIELD,      $ ; The object class name.
        parent: 0L,        $ ; The parent widget ID.
        tlb: 0L,      $ ; The top-level base of the compound widget.
        lbl_id: 0L,        $ ; The main title label widget ID
    rel_id: 0L,       $ ; The relationship label widget ID
    re2_id: 0L,       $ ; The secondary relationship label widget ID (may not exist).
    label:"",   $ ; The text label of the search field.
    db: "",      $ ; The database the search field is derived from.
        txt_id: 0L,        $ ; The primary search target text widget ID.
    tx2_id: 0L,      $ ; The sedondary search target text widget ID (may not exist).
    sel_id: 0L,       $ ; The droplist widget ID that selects the relationship
        src_id: 0L,     $ ; The base widget id of the search parameters
        event_func: "",     $ ; The name of the specified event handler function.
        format: 0,   $ ; The format of search request (currently 1 or 2).
        event_pro: "",      $ ; The name of the specified event handler procedrue.
        fieldfont: "",   $ ; The font name for the text in the Text Widget.
        labelfont: "",   $ ; The font name for the text in the Label Widget.
        buttonfnt: "",   $ ; The font name for the text in the Button Widgets.
        nonsensitive: 0,    $ ; Setting this keywords makes the text widget non-sensitive.
        undefined: PTR_NEW (),  $ ; The "undefined" value. Used in Get_Value methods, etc.
        value: PTR_NEW (),  $ ; A pointer to the value of the objecte
        destroy_on_exit: 0, $ ; Set to enable resizing the list widget to accomadate long text.
    description:0,     $ ; Set to TRUE (1) if descriptions are to be displayed.
        debug: 0,     $ ; Debug flag.  If TRUE (1) then print debug info.
        INHERITS BASE_NODE_OBJ  $ ; Inherit BASE NODE OBJ so it can be used in an olist.
      }

END









