Thursday, February 19, 2009

The Base Index Thing

Having already converted to MYSQL as a backend database while still using VFP – I have come up against an old xbase peculiarity with the base number for array indexing. In most other languages that I’ve come across (including Actionscript) – array indexing starts at zero – in xbase it starts at 1. Kind of cool for “FOR loops” in xbase, and has workable logic to it, but that’s about it!

A common practice for a finite number of options for a given field value is to tie an integer field to a combobox. Let me give an example: in an application that I’ve been working on there is a pricing option that is stored in a rate table. This defines how a price is calculated – “per person”, “group” or “group + additional”. The application only works with those price calculations, the list is not something that’s customizable by the user, so we don’t need a related table for that list – we just need a 1, 2 or 3 (or in Actionscript 0, 1 or 2) to tell us which pricing option has been assigned.

NB: You could argue that the best practice would be a related table with formulaic data that the application uses to calculate and the user could customise – that’s on the to-do list!

So to return to the problem – values in the database were stored originally in Foxpro but now need to be integrated into Flex. This means we now have an issue with just tying the value to the selectedIndex for a combobox – 1 now = 0, 2 now = 1 etc. The straightforward answer is to “just convert the data for Flex”. I actually adopted that policy previously on a different project and for reasons I won’t bother to explain right now it slowed down development and kept biting me in the nether region. Additionally – I want to use Flex and Foxpro concurrently - replacing sections of the front end in stages - and eventually ending up with an AIR application. In some areas of the application the user is working in Flex, in others it is still the Foxpro GUI.

The answer I came up with was relatively simple – override the getter and setter for selectedIndex, and use a separate private variable for binding the value from the data field. A little bit of plus and minus 1 and it all works. The code is below in the subclass of the combobox.

But then a second issue arose making things just a little more complicated. As soon as I put this extension of the Combobox on a canvas in a TabNavigator that wasn’t the first to be displayed (ie: the second or subsequent tab) strange things happened. Whatever I had the data field set to, I ended up with a blank comboBox when I clicked the tab the very first time. Move to another record and everything starts working and the values start displaying…

I am guessing this is related to some code inside Flex that is doing some delayed jiggery-pokery to enhance performance. Without delving into the code though – that will have to remain just a guess. In the meantime – I tweaked a way round it. The test in the override for selectedIndex checks to see if the combobox is on a tabNavigator – and make sure that if it is - when Flex sets the selectedIndex it doesn’t set it to minus one after it has already been set via the cbSelected variable.

Admittedly this is obscure stuff – but if I’ve helped out just one other person – I’ll be a happier individual for it!

Here’s the extension of the combobox.


package
{
import mx.containers.TabNavigator;
import mx.controls.ComboBox;
import mx.containers.Canvas;


/**
* ...
* @author ...
*/
public class ComboBoxSelectedIndex extends ComboBox
{
private var _cbSelected:int;
private var _selectedIndex:int;

public function ComboBoxSelectedIndex()
{
super();

}
public function get cbSelected():int
{
return _cbSelected;
}
public function set cbSelected(value:int):void
{
_cbSelected = value;

if (value > 0)
{
super.selectedIndex = value -1;
}
}
public override function get selectedIndex():int
{
return _selectedIndex;
}
public override function set selectedIndex(value:int):void
{
var setSelected:Boolean = true;
if (owner is Canvas)
{
if ((owner as Canvas).parent is TabNavigator)
{
if (cbSelected is int)
{
if (selectedIndex < 0 && cbSelected >= 0)
{
setSelected = false;
}
}
}
}
if (setSelected)
{
_cbSelected = value + 1;
super.selectedIndex = value;
_selectedIndex = value;
}
}
}
}

No comments: