Archive for January, 2008

DataCalendar

The DataCalendar is a combination of DateChooser and DataGrid. Like the DateChooser, the DataCalendar displays a standard calendar with controls to navigate to another month and year. And like the DataGrid, the cells of the DataCalendar display data.

Also similar to the DataGrid, the DataCalendar uses itemRenderers – either the default ones I’ve included with the package, or ones you create. The image below shows an example using custom itemRenderers and skins.

A long time ago I helped a friend of mine who owns a nightclub write an application which lets her booking manager create an online calendar of the bands performing at her nightclub. The central part of this application is the calendar which displays the bands playing each night, along with any notes and ticket information. I wrote all of that using PHP and I’ve been meaning to, over the years, write it again in Flex. The only thing holding me back was the calendar.

The DateChooser is fine to pick dates, but you cannot display anything other than the date in the calendar. The DataGrid is also fine but I needed something a bit more flexible. So I finally sat down, planned it out, and came up with the DataCalendar.

See a demo of DataCalendar here

The demonstration is of the nightclub booking tool. The information is stored in XML files and is available for the months of Dec 2007 through Feb 2008; I haven’t modified the program to create new months, but feel free to experiment with the code on your own.

Screen shot of the BookingTool

View Documentation

In hindsight, you can probably do this with the DataGrid. Once I had it planned I wanted to see it through, but if you wanted to do something similar with the DataGrid, I believe you could.

Source Code

These ZIP files are Flex 3 Beta 3 project archives.

DataCalendar Flex Library. This is the source to the DataCalendar control and supporting classes.
Test Application. This is the source to the test applications, including the BookingTool (above).

DataProvider

To use the DataCalendar you need a special data provider. I had toyed around with using the conventional ArrayCollection and XMLListCollection classes, but the more I thought about how someone would use this control, the more I thought I needed something specialized. When you look at a calendar, what do you see? Dates, right? And wouldn’t it make sense to orient the data to the dates of the calendar?

My first thought was to include the day of the month as one of the fields: {day:18, value:"Tim’s Birthday"}, {day:4, value:"Big Meeting"}, and so forth. The problem with this is that you have to repeatedly search through the collection for the information on a particular day. In this example, the information for the 4th comes after the information for the 18th. I could do a one-time pass and create a mapping, but that seemed like too much work and could have issues with data binding events.

Instead, I created the DataCalendarDataProvider class. The class implements ICollectionView, but it allows data to be assigned by day. For instance:

var januaryData:DataCalendarDataProvider = new DataCalendarDataProvider();
januaryData.addItemAt( 18, {value:"Tim's Birthday});
januaryData.addItemAt( 4, {value:"Big Meeting"});

The DataCalendarDataProvider class allocates 32 slots – slot 0 is not used – so each slot corresponds to a day of the month.

Certain properties such as sort and functions such addItem() do not make sense for a calendar, so those will throw exceptions if used.

Layout

The calendar is a grid of 7 columns and 6 rows (to accomodate those months which require 6 weeks, eg. March 2008). Regardless of the width, the DataCalendar makes all of the week day columns the same size. If you specify an explicit height the DataCalendar also makes all of the week rows the same height. However, if you do not specify a height, then the DataCalendar will allow each week row’s height to be different from the others, using the content of the day cells to determine a week row’s maximum height.

Renderers

I wanted this control to be as flexible as possible, so I gave it the ability to use itemRenderers. There are several renderers you can change:

itemRenderer: This is the renderer for the contents of a day cell. The default (DataCalendarItemRenderer) renderer takes the contents and displays it in a Text field. The BookingTool demonstration uses a complex itemRenderer. You can also add video and audio. Imagine showing the most popular YouTube™ video for each day of the month.
todayRenderer: This renderer displays the indicator for the day cell representing the current date. The default renderer simply displays the DataCalendarTodaySkin.
dayNumberRenderer: This renderer displays the date in the day cell. The default (DataCalendarDayNumberRenderer) displays the numerals for the date in the upper right corner of each day cell.
dayNameRenderer: This renderer displays the name of the day of the week across the top of each week day column. The default is DataCalendarDayNameRenderer.

Skins

I also wanted the control to have a great deal of flexability when it came to its look, so there are also a number of skins you can change:

DataCalendarDayNameSkin: the skin used for the background of the week day names.
DataCalendarDayNumberSkin: the skin used for the background of the dates for each day of the month (day cell).
DataCalendarSkin: the skin used for the background and border of the DataCalendar control.
DataCalendarTodaySkin: the skin used to show the indicator for the current day.

Version 2.0

Of course, once you finish a project you think about things you’d like to add or change. I may never get to this, but I can think of some "enhancement requests":

  • Scrolling like the DataGrid. That is, keep the DataCalendar’s title area and day names fixed in place and just scroll the day cells.
  • Selecting by day of the week. This would allow you to select all of the Mondays, for instance.
  • Adding itemEditor capability. This might make the BookingTool even easier to use.
  • Starting the week on some day other than Sunday. A typical business week begins Monday, for example.
  • Items which span rows or columns. For example, a vacation over a long weekend.

Comcast Uses Flash Video

Comcast has a new beta site, FANCAST, where you can watch streaming episodes of many of your favorite shows. You can watch something as recent as a latest 30 Rock or something as old as the first Lost in Space from the 1960’s (in black-and-white no less). Oh, an it’s FREE! At least for now.

I suppose Comcast could have choosen to use any number of web technologies to do this, but to me, chosing Flash Video was the right choice. OK, I am a bit biased, but come on, this is really cool technology. Look at all the different ways video is being presented on the web when used with Flash Video.

I’ve watched a couple of episodes on both fast and slow connections including WiFi. Never a hiccup. That may change as more people find out about FANCAST, but that only means Comcast needs to upgrade its equipment, not the software.

For more information about Flash Video, check out the new Flash Media Server.

Using SQL with Adobe AIR

I’ve not been happy about the performance of my Atmospheres Music Player. I installed it on my home computer where I have a network disk that holds all my CDs – about 240 of them. When I pointed Atmospheres at the network drive, it took a long time for it to read all of the music information from the disk. I had taken steps to make the program responsive while the files were being read, but still, it took a long time. I told my teammate, Kyle Quevillon, about this and he suggested that I cache the information much like other music players do.

What he meant was that Atmospheres shouldn’t read the file system, especially one on a remote disk, as its primary source of information in the music library. A light went off in my head when I realized I could use the SQL Lite database built into Adobe AIR. This was a perfect application of the database: I could have Atmospheres read the file system and store information into a local database, reading that information whenever it started. I’d only read the file system when new CDs were ripped.

If you didn’t know it already, AIR comes with a genuine, lightweight, database – an implementation of SQL Lite. You can create tables, views, insert data, delete data, and run queries. The API to do this is the flash.data package. If you are interested in using the SQL capabilities of AIR, then read on.

Here’s what I did:

I created a class to read the file system and build the Album objects. The Album class already existed and in fact, the code to read the file system already existed, too, in the MusicLibraryViewer class. I created a new class (FileReader) which creates the Album objects and notifies another class once an album has been read.

The other class is the Cache. One function of the Cache class is to take the information from the FileReader (ie, Albums) and store them into a database. Another function is to read the database and build a list of Albums from that information.

Atmospheres starts by getting the Cache to read the database and build the Album list. This is presented in the Atmosphere’s user interface. At any time, especially the first time you run Atmospheres, you can refresh the music library. Doing this causes the FileReader to create an Album which the Cache compares to what it has read from the database. Anything new is put into the database as well as in memory.

Scanning the file system isn’t lightning fast, but when you are expecting it to be slow, it moves along quickly enough and builds the local database. Reading the database is, in my opinion, astonishingly fast. I’ve got about 2,800 tracks from those CDs stored in the local database. It reads that data very quickly and builds the Album list in an eye-blink.

Download
You can download the code here. This is a Flex 3 Beta 3 project archive. If you do not hav Flex 3 Beta 3, find it here.

Now when Atmospheres starts on my home computer, it comes up right away, showing all 240 albums and is ready to play any of them.