How to exclude some enum values from a combobox?

Imagine a combobox based on an enum. By default it contains a list of items that correspond to the values of the enum.

Quite often people wonder whether there is a simple way to limit this list to a set of allowed values. Maybe there is a solution posted somewhere in the net - please let me know if you met one. As I has not found anything like that, I propose the following.

1. Create a class, named, say, SysCustomizedEnumComboBox. In the class declaration, write:

class SysCustomizedEnumComboBox

{

    FormRun formRun;

    int comboBoxControlId;

  EnumId enumId;

    Set allowedEnumValuesSet;

 

    Map enumValue2ComboBoxItemMap;

    SysDictEnum sysDictEnum;

}

2. Create parm-methods for each of the first 4 variables, and a constructor method without input parameters.

3. Now, create init() method (thanks to Palle Agermark who proposed a way to build comboboxes at run-time):

protected void init()

{

    #define.List(1)

    FormComboBoxControl formComboBoxControl;

    SetEnumerator allowedEnumValueEnumerator;

    int comboBoxItemNumber;

    int allowedEnumValue;

    ;

    sysDictEnum = new SysDictEnum(enumId);

    formComboBoxControl = formRun.form().design().control(comboBoxControlId);

    formComboBoxControl.enumType(0); // don't assign any enum type

    formComboBoxControl.label(sysDictEnum.label());

    formComboBoxControl.helpText(sysDictEnum.help());

    formComboBoxControl.comboType(#List);

    formComboBoxControl.items(allowedEnumValuesSet.elements());

    enumValue2ComboBoxItemMap = new Map(Types::Integer, Types::Integer);

    comboBoxItemNumber = 1;

    allowedEnumValueEnumerator = allowedEnumValuesSet.getEnumerator();

    while (allowedEnumValueEnumerator.moveNext())

    {

        allowedEnumValue = allowedEnumValueEnumerator.current();

        formComboBoxControl.item(comboBoxItemNumber);

        formComboBoxControl.text(sysDictEnum.value2Name(allowedEnumValue));

        enumValue2ComboBoxItemMap.insert(allowedEnumValue, comboBoxItemNumber);

        comboBoxItemNumber++;

    }

}

4. Create a method that will construct the class and initialize it:

public static SysCustomizedEnumComboBox newParameters(

    FormRun _formRun,

    int _comboBoxControlId,

    EnumId _enumId,

    Set _allowedEnumValuesSet)

{

    SysCustomizedEnumComboBox sysCustomizedEnumComboBox =

        SysCustomizedEnumComboBox::construct();

    ;

    sysCustomizedEnumComboBox.parmFormRun(_formRun);

    sysCustomizedEnumComboBox.parmComboBoxControlId(_comboBoxControlId);

    sysCustomizedEnumComboBox.parmEnumId(_enumId);

    sysCustomizedEnumComboBox.parmAllowedEnumValuesSet(_allowedEnumValuesSet);

    sysCustomizedEnumComboBox.init();

    return sysCustomizedEnumComboBox;

}

5. And finally, add a couple of methods that will manipulate the combobox:

public void select(int _enumValue)

{

    FormComboBoxControl formComboBoxControl;

    ;

    if (!enumValue2ComboBoxItemMap.exists(_enumValue))

        throw error(Error::wrongUseOfFunction(funcName()));

    formComboBoxControl = formRun.control(comboBoxControlId);

    formComboBoxControl.selection(enumValue2ComboBoxItemMap.lookup(_enumValue) - 1);

}

public int selection()

{

    FormComboBoxControl formComboBoxControl;

    int ret;

    ;

    formComboBoxControl = formRun.control(comboBoxControlId);

    ret = sysDictEnum.name2Value(

        formComboBoxControl.getText(formComboBoxControl.selection()));

    return ret;

}

6. That's it.

Now, you may use the class in a form. For example, you have a form named ReserveTickets. It is used for booking airplain tickets for employees. There are 2 classes that represent employees and managers, and Manager class extends Employee. The booking form may be called by either of the classes. Depending on what class is the caller, the types of the tickets are different, so that employees may book only economy seats, while managers - economy and business seats. Let's say we have an enum SeatType representing both seat types.

So, first of all we have to add a method to Employee class, and override it in the sub-class:

// Employee class method 

public Set allowedSeatTypeValuesSet()

{

    Set allowedSeatTypeValuesSet;   

    ;

    allowedSeatTypeValuesSet = new Set(Types::Enum);

    allowedSeatTypeValuesSet.add(SeatType::Economy);

    return allowedSeatTypeValuesSet;

}

// Manager class method

public Set allowedSeatTypeValuesSet()

{

Set allowedSeatTypeValuesSet;

;

allowedSeatTypeValuesSet = super();

allowedSeatTypeValuesSet.add(SeatType::Business);

return allowedSeatTypeValuesSet;

}

And finally, let's correct the form ReserveTickets (assuming that it has a combobox named SeatTypeComboBox). Declare sysCustomizedEnumComboBox member-variable in the form class declaration. Then override init() method of the form as follows:

public void init()

{

Employee caller = this.args().caller();

;

sysCustomizedEnumComboBox = SysCustomizedEnumComboBox::newParameters(

element,

control::SeatTypeComboBox,

enumNum(SeatType),

caller.allowedSeatTypeValuesSet());

super();

}

Done. From now on, whenever this form is called by Employee class - only economy tickets will be selectable, and when called by Manager - then both economy and business tickets will.

We don't actually use select() and selection() methods of SysCustomizedEnumComboBox in this form example. These methods would become handy if there was another class behind the form, and the form was used as a user interface for this class member-variable SeatType. I don't provide the example here, but I know - you understand the concept.