Components of an Inspector Panel

Inspecting an object boils down to examining its properties. In general, to inspect a property, an inspector panel uses the following pair of components: an accessor and an editor.

The accessor interfaces with the inspected property while the editor interfaces with a gadget that represents it graphically in the inspector panel (an IlvTextField, for example). In the context where an accessor is paired with an editor, the accessor is responsible for fetching the property value and displaying it via the editor. The editor for its part notifies the accessor whenever its content changes. In other words, inspecting a property means initializing the accessor when the inspector is initialized, and requesting the accessor to apply modifications made to the editor’s content. In this context, only a list of accessors is required to inspect an object.

Certain editors, however, do not need to be linked with accessors to work. For example, a combo box used to show or hide a set of gadgets does not need to access data to be initialized. Similarly, changing the selected item in the combo box does not affect the data. Because these stand-alone editors are not initialized by accessors, they must be initialized explicitly.

To handle both the pairs accessors/editors and stand-alone editors, an inspector panel makes use of a main editor defined by the class IlvStIMainEditor. Actually, inspection operations, including managing the Apply button present in each inspector panel, which are carried out by the inspector panel, are processed by the main editor.

The following figures illustrate respectively:

  • The various components of an inspector panel and how they relate to one another.

  • The initialization steps of an inspector panel.

  • What happens when a property is modified in a inspector panel.

  • The steps involved in applying changes to properties made via an inspector panel.

Components of an Inspector Panel

Initialization Steps of an Inspector Panel

What Happens When Modifications are Made in the Inspector Panel

Applying Modifications Made in an Inspector Panel

Accessors

An inspector panel handles accessors of the class IlvStIAccessor, which is the base class of all the accessor classes. It performs two actions on accessors by calling the methods initialize and apply. Calling the first method initializes the calling accessors, while apply brings into effect the modifications made to the inspected object.

Property Accessors

Most of the time, accessors are used to inspect object properties. In fact, if you take a look at the accessor class hierarchy illustrated below, you’ll see that IlvStIPropertyAccessor, a subclass of IlvStIAccessor, is the base class for all types of accessors in the library.

Accessor Hierarchy

Property accessors manipulate properties via the class IlvStIProperty in which they are encapsulated. For example, to manipulate a property of the type IlvValue, an accessor uses an object of the type IlvStIValueProperty deriving from the class IlvStIProperty, in which the IlvValue object is encapsulated.

Accessors inspect properties using two different modes:

  • An update mode, which specifies whether the property accessor should apply modifications immediately or when the user clicks the Apply button.

  • A building mode, which specifies whether a property should be created, if not found, and/or copied.

Since the initialize and apply methods of the property accessor utilize these parameters, you must not redefine them when subclassing IlvStIPropertyAccessor. Instead redefine the methods getOriginalValue and applyValue, which are invoked by initialize and apply, respectively.

The following example shows how to subclass IlvStIPropertyAccessor to access the label of a gadget item:

class IlvLabelAccessor

: public IlvStIPropertyAccessor

{

public:

IlvLabelAccessor(IlvGadgetItem* gadgetItem,

const char* name = 0,

UpdateMode updateMode = NoUpdate,

BuildMode buildMode = None):

IlvStIPropertyAccessor(name, updateMode, buildMode),

_gadgetItem(gadgetItem)

{}

protected:

IlvGadgetItem* _gadgetItem;

IlvGadgetItem* getGadgetItem()const;

virtual IlvStProperty* getOriginalValue() const;

virtual void applyValue(IlvStProperty* property);

};

 

IlvGadgetItem*

IlvLabelAccessor::getGadgetItem() const

{

return _gadgetItem;

}

 

IlvStIProperty*

IlvLabelAccessor::getOriginalValue()

{

IlvGadgetItem* gadgetItem = getGadgetItem();

return new IlvStIValueProperty(gadgetItem->getLabel(), “label”);

}

void

IlvLabelAccessor::applyValue(IlvStIProperty* property)

{

IlvGadgetItem* gadgetItem = getGadgetItem();

IlvValue value;

property->getValue(value);

const char* label = (const char*)value;

gadgetItem->setLabel(label);

}

Dependent Accessors

Certain inspected properties directly depend on other inspected properties. For example, the user should not be able to inspect the intermediate state of a toggle button if the intermediate mode was not set for it. In other words, the accessor to the “intermediate state” property should always be aware of the value set for the accessor to the “intermediate mode” property, and its associated editor should appear gray or not depending on that value. This means that if the accessor to the “intermediate mode” property is initialized or is modified, the accessor to the “intermediate state” must be reinitialized accordingly. For this initialization precedence order to be achieved, the accessor to the “intermediate state” property should be made dependent on the accessor to the “intermediate mode” property using the method addDependentAccessor.

This dependency mechanism is also used by combined accessors, which are described in the next section.

Combined Accessors

A combined accessor is an instance of the class IlvStICombinedAccessor, a subclass of IlvStIPropertyAccessor, which is used to inspect the property of an object that is returned by another accessor. For example, let us consider a name accessor used to inspect the name of a gadget item. By combining this accessor with a gadget item accessor, you can use it to inspect both an element selected in a gadget item list or a gadget item in a message label. Combined accessors are usually implemented as dependent accessors since they must be reinitialized whenever the property they access through another accessor is itself reinitialized. In our example, changing the current selection in a gadget item list would cause the name accessor to be reinitialized.

The example given in the section Accessors has been rewritten below to illustrate combined accessors. It shows how to subclass IlvStICombinedAccessor to access the label of a gadget item:

class IlvLabelAccessor

: public IlvStICombinedAccessor

{

public:

protected:

IlvGadgetItem* getGadgetItem() const;

virtual IlvStProperty* getOriginalValue();

virtual void applyValue(IlvStProperty* property);

};

 

IlvGadgetItem*

IlvLabelAccessor::getGadgetItem()

{

if (!getObjectAccessor())

return 0;

IlvStIProperty* property = getObjectAccessor()->get();

return (property? (IlvGadgetItem*)property->getPointer() : 0);

}

 

// The implementation of the getOriginalValue and applyValue methods

// are the same as in previous the sample.

...

List Accessors

A list accessor is an instance of the class IlvStIPropertyListAccessor, which derives from IlvStICombinedAccessor. A list accessor is used to inspect a list of properties. It allows you to add, remove, or modify a property in a list. This type of accessor works in conjunction with instances of the class IlvStIPropertyListEditor. Editors of this kind handle gadgets that are used to edit lists, that is, list gadgets, and the following four buttons: Add After, Add Before, Remove, and Clean.

The following code sample shows how to access a list of gadget items that are contained in a gadget item holder:

class IlvStIGadgetItemListAccessor

: public IlvStIPropertyListAccessor {

public:

// ----------------------------------------------------------------------

// Constructor / destructor

IlvStIGadgetItemListAccessor(IlvStIPropertyAccessor* accessor = 0,

IlvStIAccessor::UpdateMode updateMode=

IlvStIAccessor::Inherited,

const char* name = 0);

~IlvStIListGadgetItemAccessor();

 

IlvListGadgetItemHolder* getListGadgetItemHolder() const;

 

protected:

IlvGadgetItem* getGadgetItem(const IlvStIProperty*) const;

virtual IlvStIProperty** getInitialProperties(IlUInt& count);

virtual IlvStIProperty* createDefaultProperty() const;

virtual IlvGadgetItem* createGadgetItem(

const IlvStIProperty* prop) const;

 

virtual void addProperty(IlvStIProperty* property, IlUInt index);

virtual void replaceProperty(IlvStIProperty* origProperty,

IlvStIProperty* newProperty,

IlUInt index);

virtual void deleteNewProperty(IlvStIProperty* property);

virtual void deleteProperty(IlvStIProperty* property, IlUInt index);

virtual void moveProperty(IlvStIProperty* property,

IlUInt previousIndex,

IlUInt newIndex);

};

 

IlvStIGadgetItemListAccessor::

IlvStIGadgetItemListAccessor(IlvStIPropertyAccessor* accessor,

IlvStIAccessor::UpdateMode updateMode,

const char* name):

IlvStICombinedAccessor(accessor, update, name)

{

}

 

IlvStIGadgetItemListAccessor::~IlvStIGadgetItemListAccessor()

{

}

IlvListGadgetItemHolder*

IlvStIGadgetItemListAccessor::getListGadgetItemHolder() const

{

if (!getObjectAccessor())

return 0;

IlvStIProperty* property = getObjectAccessor()->get();

return (property? (IlvListGadgetItemHolder*)property->get() : 0);

}

 

IlvStIProperty**

IlvStIListGadgetItemAccessor::getInitialProperties(IlUInt& count)

{

IlvListGadgetItemHolder* listHolder = getListGadgetItemHolder();

if (!listHolder)

return 0;

count = (IlUInt)listHolder->getCardinal();

if (!count)

return 0;

IlvStIProperty** properties = new IlvStIProperty*[count];

for(IlUInt i = 0; i < count; i++)

properties[i] = new IlvStIValueProperty(

(IlvAny)listHolder->getItem((IlvUShort)i));

return properties;

}

 

IlvGadgetItem*

IlvStIListGadgetItemAccessor::getGadgetItem(

const IlvStIProperty* property)const

{

return (property? (IlvGadgetItem*)property->getPointer() : 0);

}

 

IlvStIProperty*

IlvStIListGadgetItemAccessor::createDefaultProperty()const

{

return new IlvStIValueProperty(

(IlvAny)new IlvGadgetItem("&Item", (IlvBitmap*)0));

}

 

IlvGadgetItem*

IlvStIListGadgetItemAccessor::createGadgetItem(

const IlvStIProperty* prop) const

{

const IlvStIGadgetItemValue* value =

ILVI_CONSTDOWNCAST(IlvStIGadgetItemValue, prop);

if (!value)

return 0;

IlvGadgetItem* newGadgetItem =

(value->getGadgetItem()? value->getGadgetItem()->copy() : 0);

if (!newGadgetItem)

return 0;

newGadgetItem->setSensitive(IlTrue);

newGadgetItem->showLabel(IlTrue);

newGadgetItem->showPicture(IlTrue);

newGadgetItem->setEditable(IlFalse);

return newGadgetItem;

}

 

void

IlvStIListGadgetItemAccessor::addProperty(IlvStIProperty* property,

IlUInt index)

{

IlvListGadgetItemHolder* listHolder = getListGadgetItemHolder();

if (listHolder) {

listHolder->insertItem(getGadgetItem(property), (IlvShort)index);

}

}

 

void

IlvStIListGadgetItemAccessor::replaceProperty(IlvStIProperty* origProperty,

IlvStIProperty* newProperty,

IlUInt position)

{

IlvListGadgetItemHolder* listHolder = getListGadgetItemHolder();

if (!listHolder)

return;

listHolder->removeItem((IlvUShort)position);

listHolder->insertItem(getGadgetItem(newProperty), (IlvUShort)position);

}

 

void

IlvStIListGadgetItemAccessor::deleteNewProperty(IlvStIProperty* property)

{

delete getGadgetItem(property);

}

 

void

IlvStIListGadgetItemAccessor::deleteProperty(IlvStIProperty* property,

IlUInt index)

{

IlvListGadgetItemHolder* listHolder = getListGadgetItemHolder();

if (!listHolder

return;

listHolder->removeItem((IlvShort)(IlvUShort)index);

}

 

void

IlvStIListGadgetItemAccessor::moveProperty(IlvStIProperty* property,

IlUInt previousIndex,

IlUInt newIndex)

{

IlvListGadgetItemHolder* listHolder = getListGadgetItemHolder();

if (!listHolder)

return;

listHolder->removeItem((IlvUShort)previousIndex, IlFalse);

listHolder->insertItem(getGadgetItem(property),

(IlvShort)(IlvUShort)(newIndex -

(newIndex > previousIndex? 1 : 0)));

}

Tree Accessors

A tree accessor is an instance of the class IlvStIPropertyTreeAccessor, which derives from IlvStICombinedAccessor. A tree accessor is used to inspect a tree of properties. It allows you to add, remove, or modify a property in a tree. This type of accessors works in conjunction with instances of the class IlvStIPropertyTreeEditor. Editors of this kind handle gadgets that are used to edit trees, that is, tree gadgets, and the following five buttons: Add After, Add Before, Add Child, Remove, and Clean.

The following code sample shows how to access a tree of gadget items that are contained in a tree gadget:

class IlvStIGadgetItemTreeAccessor

: public IlvStIPropertyTreeAccessor {

public:

IlvStIGadgetItemTreeAccessor(IlvStIPropertyAccessor* accessor = 0,

IlvStIAccessor::UpdateMode updateMode =

IlvStIAccessor::Inherited,

const char* name = 0,

IlvStIAccessor::BuildMode buildMode =

IlvStIAccessor::Copy);

~IlvStIGadgetItemTreeAccessor();

 

// ----------------------------------------------------------------------

IlvTreeGadgetItemHolder* getTreeGadgetItemHolder() const;

 

protected:

 

IlvTreeGadgetItem* getGadgetItem(const IlvStIProperty*) const;

IlvTreeGadgetItem* getParentGadgetItem(const IlvStIProperty*) const;

 

// Applying.

 

virtual IlUInt getChildPosition(const IlvStIProperty* parentProperty,

const IlvStIProperty* property) const;

virtual void addProperty(IlvStIProperty* property,

const IlvStIProperty* parent,

IlUInt childPosition);

virtual void replaceProperty(IlvStIProperty* origProperty,

IlvStIProperty* newProperty,

const IlvStIProperty* parent,

IlUInt childPosition);

// Array of properties.

virtual IlvStIProperty** getInitialChildrenProperties(

IlUInt& count,

const IlvStIProperty* parent = 0) const;

// Insertion of properties.

virtual IlvStIProperty* createProperty(const IlvStIProperty* parent,

IlUInt childPosition,

IlvAny param = 0) const;

 

// Destruction of properties.

virtual void deleteNewProperty(IlvStIProperty* property);

virtual void deleteProperty(IlvStIProperty* property);

};

 

IlvStIGadgetItemTreeAccessor::IlvStIGadgetItemTreeAccessor(

IlvStIPropertyAccessor* accessor,

IlvStIAccessor::UpdateMode updateMode,

const char* name,

IlvStIAccessor::BuildMode buildMode):

IlvStIPropertyTreeAccessor(accessor,

updateMode,

buildMode,

(name? name : "GadgetItemTreeAccessor"))

{

}

 

IlvStIGadgetItemTreeAccessor::~IlvStIGadgetItemTreeAccessor()

{

}

 

IlvTreeGadgetItemHolder*

IlvStIGadgetItemTreeAccessor::getTreeGadgetItemHolder()const

{

IlvStIProperty* property = (_accessor? _accessor->get() : 0);

return (property? (IlvTreeGadget*)property->getPointer() : 0);

}

 

// --------------------------------------------------------------------------

IlvTreeGadgetItem*

IlvStIGadgetItemTreeAccessor::getGadgetItem(

const IlvStIProperty* property) const

{

return (property? (IlvTreeGadgetItem*)property->getPointer() : 0);

}

 

IlvTreeGadgetItem*

IlvStIGadgetItemTreeAccessor::getParentGadgetItem(

const IlvStIProperty* property) const

{

if (!property) {

// Returns root.

IlvTreeGadgetItemHolder* holder = getTreeGadgetItemHolder();

if(!holder)

return 0;

return holder->getRoot();

}

return (property? (IlvTreeGadgetItem*)property->getPointer() : 0);

}

 

IlUInt

IlvStIGadgetItemTreeAccessor::getChildPosition(

const IlvStIProperty* parentProperty,

const IlvStIProperty* property)const

{

// Get parentItem.

IlvTreeGadgetItem* parentItem = getParentGadgetItem(parentProperty);

if (!parentItem)

return (IlUInt)-1;

 

IlvTreeGadgetItem* findItem = getGadgetItem(property);

IlUInt position = 0;

for(IlvTreeGadgetItem* item = parentItem->getFirstChild();

item;

item = item->getNextSibling(), position++) {

if (item == findItem)

return position;

}

return (IlUInt)-1;

}

 

void

IlvStIGadgetItemTreeAccessor::addProperty(IlvStIProperty* property,

const IlvStIProperty* parent,

IlUInt index)

{

IlvTreeGadgetItemHolder* holder = getTreeGadgetItemHolder();

if (!holder)

return;

holder->addItem(getParentGadgetItem(parent),

getGadgetItem(property), (IlvInt)index);

}

 

void

IlvStIGadgetItemTreeAccessor::replaceProperty(IlvStIProperty* origProperty,

IlvStIProperty* newProperty,

const IlvStIProperty* property,

IlUInt index)

{

IlvTreeGadgetItemHolder* holder = getTreeGadgetItemHolder();

if (!holder)

return;

// Instead of removing the old gadget item and adding the new one, the

// following line copies the attributes of the new created gadget item

// to the old one.

*(getGadgetItem(origProperty)) = *getGadgetItem(newProperty);

// After this method is called, newProperty becomes the new

// original property and should therefore be updated.

// As we have copied attributes from the new created gadget item

// to the initial one, the inspected gadget item

// keeps being the one contained in origProperty.

newProperty->setPointer(origProperty->getPointer());

}

 

// Array of properties.

IlvStIProperty**

IlvStIGadgetItemTreeAccessor::getInitialChildrenProperties(

IlUInt& count,

const IlvStIProperty* parent) const

{

IlvTreeGadgetItem* parentItem = getParentGadgetItem(parent);

if (!parentItem)

return 0;

IlvArray properties;

for(IlvTreeGadgetItem* item = parentItem->getFirstChild();

item;

item = item->getNextSibling()) {

properties.add(new IlvStIValueProperty((IlvAny)item));

}

count = properties.getLength();

if (!count)

return 0;

IlvStIProperty** props = new IlvStIProperty*[count];

::memcpy(props,

properties.getArray(),

(size_t)(sizeof(IlvStIProperty*) * (IlvInt)count));

return props;

}

 

// Inserting properties.

IlvStIProperty*

IlvStIGadgetItemTreeAccessor::createProperty(const IlvStIProperty*,

IlUInt,

IlvAny) const

{

return new IlvStIValueProperty((IlvAny)new IlvTreeGadgetItem("&Item"));

}

 

// Destruction of properties.

void

IlvStIGadgetItemTreeAccessor::deleteNewProperty(IlvStIProperty* property)

{

IlvGadgetItem* gadgetItem = (IlvGadgetItem*)property->getPointer();

if (gadgetItem)

delete gadgetItem;

}

 

void

IlvStIGadgetItemTreeAccessor::deleteProperty(IlvStIProperty* property)

{

IlvTreeGadgetItemHolder* holder = getTreeGadgetItemHolder();

if (!holder)

return;

holder->removeItem(getGadgetItem(property));

}