BBjInpuDSpinner Example

USE java.util.HashMap
USE java.util.TreeSet

REM Obtain the instance of the BBjAPI object
LET myAPI!=BBjAPI()

REM Open the SysGui device
SYSGUI=UNT
OPEN (SYSGUI)"X0"

REM Obtain the instance of the BBjSysGui object
LET mySysGui!=myAPI!.getSysGui()

REM Set addWindow param values
X=200
Y=200
WIDTH=350
HEIGHT=250
TITLE$="Birthday Finder"

REM Set the current context
mySysGui!.setContext(0)

REM Create a window
myWindow! = mySysGui!.addWindow(X,Y,WIDTH,HEIGHT,TITLE$,$00010083$)

REM All our dates are in 2006
startDate = JUL(2006, 1, 1)
endDate = JUL(2006, 12, 31)

REM Mask in numeric precedence order
myDateMask$ = "%Y-%Mz-%Dz"

REM Create date range for data.
myLowDate! = myWindow!.addInputDSpinner(101, 10, 10, 100, 25, $$, myDateMask$)
IF (myLowDate!.getMinimumDate() <> startDate)
    myLowDate!.setMinimumDate(startDate)
ENDIF
IF (myLowDate!.getMaximumDate() <> endDate)
    myLowDate!.setMaximumDate(endDate)
ENDIF
myLowDate!.setValue(startDate)
IF (myLowDate!.getSpinField() <> myLowDate!.MONTH)
    myLowDate!.setSpinField(myLowDate!.MONTH)
ENDIF

myHighDate! = myWindow!.addInputDSpinner(102, 120, 10, 100, 25, $$, myDateMask$)
IF (myLowDate!.getMinimumDate() <> startDate)
    myLowDate!.setMinimumDate(startDate)
ENDIF
IF (myLowDate!.getMaximumDate() <> endDate)
    myLowDate!.setMaximumDate(endDate)
ENDIF
myHighDate!.setValue(endDate)

IF (myHighDate!.getSpinField() <> myHighDate!.MONTH)
    myHighDate!.setSpinField(myHighDate!.MONTH)
ENDIF

REM Create date of event
myEventDate! = myWindow!.addInputD(103, 10, 45, 100, 25, $$, myDateMask$)
myEventDate!.setText(" ")

REM Create edit box for event name
myEditBox! = myWindow!.addEditBox(104, 120, 45, 120, 25, $$)

REM Create list box for the list of valid events
myList! = myWindow!.addListBox(105, 10, 80, 140, 100, $$)

REM Create buttons for date range
mySqueeze! = myWindow!.addButton(106, 250, 10, 90, 25, "Squeeze")
myExpand! = myWindow!.addButton(107, 250, 45, 90, 25, "Expand")

REM Set callbacks
myWindow!.setCallback(myWindow!.ON_CLOSE,"APP_CLOSE")
myLowDate!.setCallback(myLowDate!.ON_SPIN, "LOW_SPIN")
myHighDate!.setCallback(myHighDate!.ON_SPIN, "HIGH_SPIN")
myList!.setCallback(myList!.ON_LIST_DOUBLE_CLICK, "SELECT_EVENT")
mySqueeze!.setCallback(mySqueeze!.ON_BUTTON_PUSH, "SQUEEZE_RANGE")
myExpand!.setCallback(myExpand!.ON_BUTTON_PUSH, "EXPAND_RANGE")

REM Set callbacks for fast spin response
myAPI!.setCustomEventCallback("low_spin_started", "LOW_SPIN_STARTED")
myAPI!.setCustomEventCallback("high_spin_started", "HIGH_SPIN_STARTED")

REM Setup data structures for events
myEvents! = new TreeSet()
myEventDates! = new HashMap()

REM Populate data structures and myList!
GOSUB ADD_EVENTS
GOSUB DO_FILTER

lowSpin = 0
highSpin = 0

PROCESS_EVENTS

REM Callback for myLowDate! ON_SPIN
LOW_SPIN:
    REM Get BBjSpinEvent
    ev! = myAPI!.getLastEvent()

    REM Get text and convert to date
    date$ = ev!.getText()
    lowDate = NUM(date$)

    REM Set a new minimum for myHighDate! to be our current date.
    myHighDate!.setMinimumDate(lowDate)

    REM While receiving spin events, keep adding to the counter
    lowSpin = lowSpin + 1

    REM Post custom event, which will decrement the counter until 0
    REM Then it will update myList!
    myAPI!.postCustomEvent("low_spin_started", NULL())
    RETURN

REM Callback for "low_spin_started"
LOW_SPIN_STARTED:
    REM Decrement counter
    lowSpin = lowSpin - 1

    REM When it reaches zero, filter the list and reset the displayed values
    IF (lowSpin = 0)
        GOSUB DO_FILTER
    ENDIF

    RETURN

REM Callback for myHighDate! ON_SPIN
HIGH_SPIN:
    REM Get BBjSpinEvent
    ev! = myAPI!.getLastEvent()

    REM Get text and convert to date
    date$ = ev!.getText()
    highDate = NUM(date$)

    REM Set a new maximum for myLowDate! to be our current date.
    myLowDate!.setMaximumDate(highDate)

    REM While receiving spin events, keep adding to the counter
    highSpin = highSpin + 1

    REM Post custom event, which will decrement the counter until 0
    REM Then it will update myList!
    myAPI!.postCustomEvent("high_spin_started", NULL())

    RETURN

HIGH_SPIN_STARTED:
    REM Decrement counter
    highSpin = highSpin - 1

    REM When it reaches zero, filter the list and reset the displayed values
    IF (highSpin = 0)
        GOSUB DO_FILTER
    ENDIF

    RETURN

SELECT_EVENT:
    REM Get the currently selected index
    index = myList!.getSelectedIndex()

    REM Get the event
    eventName$ = myList!.getItemAt(index)
    
    REM Get the time
    myDate = myEventDates!.get(eventName$)

    REM Show them in the "detail" fields
    myEditBox!.setText(eventName$)
    myEventDate!.setValue(myDate)

    RETURN

REM Callback for Squeeze button
SQUEEZE_RANGE:
    REM Get the next and previous, and spin if there's room to spin.
    nextLow = myLowDate!.getNextDate()
    prevHigh = myHighDate!.getPreviousDate()

    IF (nextLow <> -1 AND prevHigh <> -1)
        REM Prefer squeezing higher dates, if we can only move one.
        IF (nextLow < prevHigh)
            myLowDate!.spin(1)
        ENDIF
        myHighDate!.spin(0)
    ENDIF

    REM spin doesn't cause event, so we have to manually filter
    GOSUB DO_FILTER

    RETURN

REM Callback for Expand button
EXPAND_RANGE:
    prevLow = myLowDate!.getPreviousDate()
    nextHigh = myHighDate!.getNextDate()
    IF (prevLow <> -1)
        myLowDate!.spin(0)
    ENDIF
    IF (nextHigh <> -1)
        myHighDate!.spin(1)
    ENDIF

    REM spin doesn't cause event, so we have to manually filter
    GOSUB DO_FILTER

    RETURN

REM Callback for window close box
APP_CLOSE:
    RELEASE

REM Subroutine to filter the contents of myList!
DO_FILTER:
        REM Get the ends of the sequence.
        lowDate = myLowDate!.getValue()
        highDate = myHighDate!.getValue()

        REM Use the TreeSet to filter the sequence by date.
        eventsFiltered! = myEvents!.subSet(STR(lowDate:myNumMask$), STR(highDate + 1:myNumMask$))

        REM Make a vector to set as the data for myList!
        vec! = myAPI!.makeVector()

        REM Iterate through and only add the events in the filtered list
        iter! = eventsFiltered!.iterator()
        maskLen = LEN(myNumMask$)
        WHILE (iter!.hasNext())
            key$ = iter!.next()

            REM Strip off the date part
            key$ = key$(maskLen + 1)
            vec!.add(key$)
        WEND

        REM Remove all the existing events and set the new ones.
        myList!.removeAllItems()
        myList!.insertItems(0, vec!)

        REM Don't forget to let go of the references
        vec! = NULL()
    RETURN

REM Subroutine to set the initial events
ADD_EVENTS:
    REM This mask will allow the julian to sort lexigraphically
    myNumMask$ = "0000000000"

    REM Add all the dates
    dummy = fnAddEvent("Jim", JUL(2006, 1, 25))
    dummy = fnAddEvent("Laura", JUL(2006, 2, 5))
    dummy = fnAddEvent("Catherine", JUL(2006, 2, 28))
    dummy = fnAddEvent("John", JUL(2006, 3, 10))
    dummy = fnAddEvent("Ian", JUL(2006, 4, 13))
    dummy = fnAddEvent("Bob", JUL(2006, 5, 7))
    dummy = fnAddEvent("Stephen", JUL(2006, 6, 28))
    dummy = fnAddEvent("Jason", JUL(2006, 7, 6))
    dummy = fnAddEvent("Edna", JUL(2006, 8, 9))
    dummy = fnAddEvent("Stephanie", JUL(2006, 9, 17))
    dummy = fnAddEvent("Tara", JUL(2006, 10, 12))
    dummy = fnAddEvent("Joe", JUL(2006, 12, 12))
    RETURN

REM Add a single event
DEF fnAddEvent(event$, date)
    REM Add the events so they'll sort by date in the TreeSet
    myEvents!.add(STR(date:myNumMask$) + event$)

    REM To provide lookup by name, put the events in the eventDates! map
    myEventDates!.put(event$, date)
    RETURN 0
FNEND