Today we add behavior so that when one selects a date in the grid, it closes the drop down, assigns the date to the calendar's model, and displays it in the input field portion of our Calendar.
Simple Changes
We don't need to do too much to accomplish today's goals. First, we need to subscribe to the #cellSelected: event of the grid:
This event, when triggered sends the cell location as a point, to our method of choice, here named #selectDateAt:. Here's that method:
CalendarAgent>>selectDateAt: aPoint
| newDate |
newDate := (dropDown paneAt: #(#Form1 #Grid1)) list at: aPoint.
pane model value: newDate.
The ObservedTwoDList knows how to handle either points or integers sent to it's #at: method. If we send an integer, it gives us the array of values for the row associated with that integer. If we send it a point, it gives us just the value of that element.
Next we want to close the drop down when the selection is complete. This we want to happen when the mouse is released on the selection. The #cellSelected: action takes place before the mouse is released, in other words, on mouse down. Fortunately, there is an event that occurs on mouse up for any selection type; #selectionChangeFinished. So we'll hook to that event as follows:
CalendarAgent>>closeDropDown
pane topPane sensor addMetaInput: (CloseEvent new window: dropDown)
Now, this might seem fairly obtuse. Here's the deal. Our goal is to make the drop down window close after all processing is done to the grid and anything else on the drop down. If we simply send #close to the drop down (you can try it), you'll be interrupting a flow of code that does things like highlight the selected item and other things. So, sending #close isn't good. Thus, by adding a system close event targeted to the drop down, to the event queue of the main window (not the dropDown), we know that it won't get processed until all other events are done.
In the future, Pollock will likely support a more direct API for queuing these kind of things. For now, it does the trick, and will work even in the face of future API additions.
So, if we open our Calendar tester (CalendarTest new openWindowWithCalendar), open the drop down, select a date (with or without navigating) everything looks nice. If we don't pick "Today" as our selection, in the grid, the next time we open the drop down, it is now focused on the month and date we selected the last time we opened the drop down.
Displaying The Selected Date
Now all we have to do is make it so whenever we select a new target date, that date shows up in the input field portion of our Calendar. We'll start by adding a method to Calendar to subscribe to the #changed event on our model:
Calendar>>setModelEvent
model when: #changed send: #updateDateDisplay to: self
Then we add this to our #getDefaultModel method:
Calendar>>setDefaultModel
model := Date today asObservedValue.
self setModelEvent
Finally, we create an #updateDateDisplay method:
Calendar>>updateDateDisplay
self displayPart model value: self model value shortPrintString
With all that, now when we select the date in the grid, we get the new date displayed in the input field part of our Calendar. The shortPrintString is already an internationalized value, so we're all set to go.
Details
One thing we're missing is that when we open our Calendar, it doesn't display the current model value. We just need to call updateDateDisplay during initialization for this to happen:
Lastly, to be complete, we need to add our own #model: method. This is a subclass responsibility method, and we haven't made one yet. We do this in case we want to have some special model object instead of an ObservedValue on a Date. Here that method:
Calendar>>model: aValue
model ifNotNil: [model removeAllActionsWithReceiver: self].
model := aValue.
self setModelEvent
Note that we make sure that we remove only the events on the old model if they are targeted to the Calendar itself. This makes sure we don't release events on that model object that might, for instance, be domain objects of some kind, with other receivers. We don't want to mess with those, only our events.
The above is published as version 1.15 in the Package named "Pollock-Calendar" on the Cincom public repository.
Next time we'll make it so if a user enters some date in the input field, it updates all the right values in our Calendar.