Day 4: Making Progress

At this point I have a lot more working. Here’s what happened to get to this point.

Recap

Once I was able to receive the XML from Flickr containing the list of photos, I had to give it to the TileList. Then the TileList’s listItemRenderer would take the data and build the URL to display the actual thumbnail image. This turned out to be pretty easy:

  1. The Gallery component has a setter for dataProvider which expects an Array. This will be the Array of photo information from Flickr.
  2. The Gallery dataProvider setter takes this Array and creates a new ArrayCollection.
    [Bindable]
    public var ac:ArrayCollection;
    ...
    // inside of dataProvider setter:
    ac = new ArrayCollection( ar );
    
  3. When the TileList has its dataProvider changed, it causes all of the renderers to receive new dataObjects (the elements of the ArrayCollection).
  4. The Thumbnail renderer has an override to the setter for dataObject which causes the Thumbnail to switch to its base state that displays the “Loading” message and hides the image.
  5. The dataObject setter also forms the URL for the thumbnail and assigns it to the Image.
  6. When the Image complete event triggers, the Thumbnail switches to the image state, displaying the image and hiding the label.

That seems complicated, but the code is pretty clean right now. I know things need to become more complex in the next few days, but for right now, I’m getting to see thumbnails when I enter a tag into the Search Panel.

Not Much Progress

My next task was to get the Progress Bar to work. This is located in the ControlBar area of the Gallery panel and shows how the thumbnails are loading. In the Flex 1.5 version, I made the Gallery itself a source for the Progress Bar. This means that the Gallery dispatches progress and complete as well as implementing byteLoaded and bytesTotal methods. That was easy with the Gallery being a Tile container. But in my Flex 2 Alpha 1 version, the Gallery is a TileList and I need someway to know when each image has loaded.

I could not find out how a listItemRenderer knows what control it is a renderer for. In Flex 1.5, each cell renderer was given an object, listOwner. I do not see anywhere in the documentation what this is.

My idea was to tell the listOwner when an image was complete so it could bump up its byte count and be a good source to the Progress Bar.

Since I don’t know how to do that know, I’m leaving out the Progress Bar.

Decisions

Up to this point the path has been straightforward. Now there are some choices: do I get the Image Viewer (the TitleWindow that displays the larger size image when you click) working? Do I get drag-and-drop working? Do I finish out the Search Panel and add the advanced options? Do I get saving the search history working?

I decided to do a little bit of everything.

Drag and Drop

The Flex 2 docs on how to do drag and drop are pretty good. I dragEnabled my TileList and it merrily allowed me to drag images all around. However, as soon as I pressed down the mouse, the TileList emitted a change event. Oops. After a quick read through the documentation, I found that I needed to use itemClick instead. You see, I want the ImageViewer to pop up when the mouse is clicked; I don’t want it to pop up when I drag an image to the Favorites panel.

In the Favorites panel I also have TileList and on that I placed event handlers for dragEnter, dragOver and dragDrop.

The dragEnter event handler is where you determine if your component is a valid drop target. You get the dragSource from the DragEvent (in Flex 2 there are many more classes and this one is specific to drag and drop) and look at the dragFormats supported. If the items being dragged are what your component can handle, then you:

  • Invoke DragManager.acceptDragDrop(event.target) which is different from Flex 1.5.
  • Invoke DragManager.showFeedback(DragManager.LINK). The default is a MOVE which, as it turns out, really removes the item. When I first implemented this in Flex 2, I dragged a thumbnail from the Gallery and dropped it onto the Favorites panel and the item was removed from the Gallery! So I changed this to a LINK operation. I could also have used COPY, but LINK seemed more appropriate.

The dragOver event handler is optional. I just set the focus to the Favorites’ TileList.

The dragDrop event hanlder is where you add the data to the drop target. Since the data is what goes into the Gallery’s ArrayCollection, it is perfectly suitable for the Favorites TileList since that also uses the Thumbnail for its listItemRenderer. All I did was add the data from the dragSource to the Favorites TileList dataProvider (also an ArrayCollection) and voila – thumbnail appears.

Search History

Once a search is successful, I want to remember it in the DataGrid, aka SearchHistory. I already had code to do this from the Flex 1.5 version, so I inserted that into the SearchHistory component and, with an adjustment for the ArrayCollection, things worked.

When using an ArrayCollection, you do use the addItem method just as you would have with an Array in Flex 1.5. Except, merely using addItem does not trigger an event to update the TileList. You also have to call notifyItemUpdate like this:

if( ac == null ) ac = new ArrayCollection();
ac.addItem( searchCriteria );
ac.notifyItemUpdate( searchCriteria );

When the SearchHistory DataGrid is bound to the ArrayCollection ac the notifyItemUpdate causes the new criteria to be placed into the DataGrid.

ImageViewer

This last task was much more complex than I would have liked. In hindsight, there wasn’t much to do, but with 2 bugs in the Flex 2 Alpha 1, I had to find work-arounds.

First, I’ve only made the ImageViewer show the larger size image of the one clicked in either the Gallery or Favorites. None of the controls (information, print, etc.) work yet. Nor does the image information (tags, description, etc.). That will be later.

First issue: TitleWindows are very transparent. Panels are now given an alpha of about .6 I think. TitleWindows seem to be about .2 – nearly invisible. I wound up changing their style to have headerColors and an alpha of 1.

Second issue: The click event means ‘click anywhere in the window’, not just the close box. This means that if you have the ImageViewer open and click one of the control buttons (eg, Print), it triggers the click event for the TitleWindow. I had a listener for this event in the PhotoSearch component which dismisses the window and sets its instance variable to null. So no matter where I clicked, the ImageViewer disappeared.

To circumvent this, I removed the close button and added a specific “Close” button on the ImageViewer’s ControlBar which dispatches a “close” event. Now the only way to dismiss the ImageViewer is to click that button.

Third Issue: Images, on the complete event have their width and height properties set to zero. This means that I could not resize the ImageViewer to see the entire larger image the way I did in Flex 1.5.

As I reported in the last journal, I found a response to that from likn who suggested that I use img.content.width and img.content.height. That worked. So now the ImageViewer reshapes itself properly.

Finally, in keeping with the flow from the Thumbnail, the ImageViewer now builds the URL to the full-size image itself, rather than it being part of the information in the TileList dataProvider ArrayCollection.

Conclusion

This ‘day’ was more intense as I uncovered some problems with the Flex 2 Alpha 1, but found reasonable work-arounds for them. The Flickr PhotoSearch application is about 50% of the way to running as a Flex 2 application. I need to save the search history and favorites list, get the image information/details to display, allow searchs from the image details tags, get searching by Flickr user to work, and more.

Getting drag and drop from the Gallery to the Favorites went really well. Getting the ImageViewer to work was harder due to the click event issue and then the image sizing issue. And I was disappointed by the Progress Bar, which I would probably have had issues with in Flex 1.5 if I had used a TileList there, too.

Stay turned…