Blog

Latest entries from the YAY! blog...

October 29, 2009

Wowza IDE – enabling CVS Repository Exploring

The Wowza IDE is a great way to start coding Wowza projects. It’s based on Eclipse 3.3 but unfortunately it’s also missing a few core components that most people would be used to or require, an important one being the CVS Repository Exploring perspective that allows you to connect and synchronise projects with a CVS repository. However it’s fairly simple to get it back (once you know how). Here’s a quick guide to getting the CVS Explorer back into your Wowza IDE. These instructions are for OSX but it’s pretty much the same process on Windows:

  1. Download the CVS client package from the eclipse.org site and unzip it somewhere
  2. Start the Wowza IDE and select Help > Software updates > Find and install
  3. Select the option that says ‘Search for new features to install’ and click ‘Next’
  4. On the next screen select ‘New local site’ from the right hand side
  5. Navigate to the folder you just unzipped above and select it

Eclipse will then proceed to install the CVS Repository client. Restart Eclipse after the installation and once restarted, go to the Add Perspective button and the CVS option should be there in the list. And that’s it!

November 4, 2008

AIR FileReference and scope

I ran into a small problem recently in my AIR application when using FileReference to initiate and monitor a download operation; no events from a FileReference object created within a method were being fired. After a quick check of the Livedoc entry I found the issue:

if the FileReference object goes out of scope, any upload or download that is not yet completed on that object is canceled upon leaving the scope. Be sure that your FileReference object remains in scope for as long as the upload or download is expected to continue.

So basically a FileReference object needs to be created in such a way that it stays in scope for the duration of your operation; if you instantiate it within a method it there’s a good chance it will go out of scope and any events you were waiting for from it will never fire. The easiest solution is to declare it outside of the method, so instead of:


private function download(event:MouseEvent):void
{
var fileRef:FileReference = new FileReference();
fileRef.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
fileRef.addEventListener(Event.COMPLETE, onComplete);
//etc.
}

you need to do something like this:


private var fileRef:FileReference();
private function download(event:MouseEvent):void
{
fileRef = new FileReference();
fileRef.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
fileRef.addEventListener(Event.COMPLETE, onComplete);
//etc.
}

Sorted. Afterwards I also found more info about this via a couple of useful blog articles here and here.

September 26, 2008

AIR: Rendering native system icons, Pt.1

I was asked how I got AIR to display native file icons in a component – it’s pretty easy to do, although my method is a little convoluted to explain without posting reams of code, partly because it’s buried in a sequence of Cairngorm events/commands but also because there a couple of important issues to watch for and handle (see bottom of this entry for those). Here’s an overview:

AIR has support for retrieving the native system icons in whatever supported sizes exist. The icons are stored as a property of each File object as BitmapData, in an array, File.icon.bitmaps. Each element in the array is the same icon at different sizes, e.g. 32×32, 16×16 etc.

In order to get at an icon at a given size, you can’t rely on what sizes are available at a given element position, so you need to create a new (empty) BitmapData object at your target dimension, then iterate through File.icon.bitmaps until you hit the matching-sized BitmapData object. Once you have a match, you can put the matching data into your own BitmapData object. Here’s a brief example:

public function get32Icon():BitmapData {
var myFile:File = new File("C:/foo.txt");
var bmpData:BitmapData = new BitmapData(32, 32);
for (var i:uint = 0; i < myFile.icon.bitmaps.length; i++) {
if (myFile.icon.bitmaps[i].height == bmpData.height) {
bmpData = myFile.icon.bitmaps[i];
}
}
return bmpData;
}

Obviously you need more than the code above to handle situations where the 32×32 icon isn’t available, but that’s a basic way to grab the icon as BitmapData. At this point you could create a new Bitmap object and give it the captured data, but for my application I set the icon data back onto an Object that represents the File object (I actually used an ObjectProxy because I wanted to bind this data to an ItemRenderer later) – again this becomes important later on.

Okay, so now I have my icon data, in an object that also contains other information about the file, like its name etc. To display it in a TileList, or other component, I just use a custom ItemRenderer. I set up an image tag for the icon within the renderer:

<mx:Image width="32" height="32" source="{getIcon(data)}" />

…and then create a method in the renderer to return the icon data to the image component:

private function getIcon(data:Object):Bitmap {
var bmpData:BitmapData = new BitmapData(32, 32);
bmpData = data.icon;
var iconBmp:Bitmap = new Bitmap(bmpData);
return iconBmp;
}

Now each time the ItemRenderer has to render an item, it gets the relevant icon, the filename etc. and displays them within the TileList – easy! Here’s the result, showing the app running in XP and OSX:
Files part screen grab

But there are caveats; AIR does not behave consistently on all platforms with icon data. Here are couple of the problems I encountered:

  • Performance. There seem to be some differences in execution time for file system queries in AIR. Originally I had an ArrayCollection of File objects as the DataProvider for the TileList, retrieving icon data for each one in the ItemRenderer as required. On Windows this seemed fine, but on Mac OSX it proved to be very slow, to the point where my app was unusable. I overcame this by using the Flex Profiler to see what was causing the problem, finding that the underlying get icon() execution time was very long on OSX. By grabbing the icon data once, then caching it and other key File properties into an ObjectProxy, I was able to get OSX performance almost on a par with Windows, and this also sped things up elsewhere because I was calling get icon() once, rather than per-item in the renderer. It also improves scrolling performance of the TileList because that component renders items dynamically as they are displayed. In fact you could go one step further than I did and extend UIComponent to improve render performance even more.
  • Missing icons. AIR on Windows won’t retrieve some icons, in particular for .EXE, .TMP and .INI files. These are stored in shell32.dll on XP, but for some reason AIR can’t get to them. I also found one or two similar issues in OSX. AIR on Linux using the most recent AIR beta just returns a null value for File.icon.bitmaps, so rendering native icons is currently impossible. You need to add some way of checking for a missing icon in these cases, and swop it out for an embedded one if you can; I created a temporary workaround where I parse the BitmapData for null pixel values.

The next part of this article will deal with how I got native icons to render for remote files, but I bet you can already guess how that’s done…

September 25, 2008

AIR: Creating a custom status bar

It’s easy to create your own customised status bar for AIR applications. For my example, I wanted to be able to display a network status icon that indicates whether the application is connected – this is bound to a state set by AIR’s network service monitor, via Cairngorm.

First of all, in your application MXML file, make sure showStatusBar is set to true, add the statusBarFactory parameter and point it to your custom component:

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
showStatusBar="true"
statusBarFactory="{new ClassFactory(CustomStatusBar)}">

Then just make a new MXML component called CustomStatusBar and add any elements you want to display in your new status bar. There are a couple of things AIR will be expecting from a StatusBar, most importantly the status setter and getter methods required to display status text:

<?xml version="1.0" encoding="utf-8"?>
<mx:HBox width="100%"
xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundColor="#E3E1E1"
>
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
import uk.ac.warwick.filesclient.model.AppModel;
[Bindable] private var modelLocator:AppModel = AppModel.getInstance();
[Bindable] public function get status():String
{
return this.statusText.text;
}
public function set status(value:String):void
{
this.statusText.text = value;
}
private function showNetworkStatusIcon():void
{
var path:String = "";
if(modelLocator.isNetworked)
{
statusIcon.source = "greenlight.png";
} else {
statusIcon.source = "greylight.png";
}
}
]]>
</mx:Script>
<mx:Label id="statusText" paddingLeft="7" fontAntiAliasType="advanced"/>
<mx:Image id="statusIcon"
toolTip="Network status"
horizontalAlign="right"
width="100%"
height="10"
verticalAlign="middle"
render="showNetworkStatusIcon()"/>
</mx:HBox>

You can add almost anything you like in there with this technique; animations, custom text etc. Here’s a quick screen grab of my basic custom status bar with its status light on green after a bit more tweaking of the layout and styling – nothing amazing, but its useful to be able to add your own elements when required (click to enlarge);

Status bar