IEEditableObject


Derives from: -
Header: IEEditableObject.h
Library: ObjectHandlerLib.so



Overview

IEEditableObject is the base class for an Interface Elements add-on. An IEEditableObject is very generic and should provide these functions and information about the object it represents (method names in parenthesis):

Instantiating the object from a byte stream

The derived class must implement the Unflatten method which returns an object instance. (Unflatten differs from the BFlattenable usage of unflattening that it does not modify the object which it was called on, but returns a new instance.)

In addition it must implement and export a static version of Unflatten called UnflattenObject. This is necessary because sometimes only an object pointer is known and not the static UnflattenObject function, while sometimes only the UnflattenObject address is known and not a valid object.

Unflatten and UnflattenObject does the same, it is OK if you implement Unflatten as

IEEditableObject    *MyEditableThing::Unflatten(const void *buf, ssize_t size)
{
    return MyEditableThing::UnflattenObject(buf, size);    // call the static function
}
Unflatten has many functions depending on if buf is NULL, or size is 0L, or both, which is discussed in the method description. The only thing I can tell you so early that Unflatten should return a default object instance if buf == NULL.


Which symbols to export and how?

For an editable object you need to export the UnflattenObject method as extern "C" function this way:
extern "C" __declspec(dllexport) IEEditableObject *UnflattenObject__EditableWindow(const void *buf, ssize_t size);


IEEditableObject *UnflattenObject__EditableWindow(const void *buf, ssize_t size)
{
	return EditableWindow::UnflattenObject(buf, size);
};
That is you don't export it from the class declaration. Don't forget to append the class name after the two underscores, this makes having more objects in one add-on file possible.

Optionally you can export another symbol, an AddOnLoaded method, which is called with the add-on file entry_ref on load time. This is useful for loading resources from the add-on file:

extern "C" __declspec(dllexport) void AddOnLoaded__EditableWindow(entry_ref *addonref);


void AddOnLoaded__EditableWindow(entry_ref *addonref)
{
	BFile addonfile;
	BResources resources;
	void *resource;
	size_t resource_size;
		
	if(addonfile.SetTo(addonref, B_READ_ONLY)==B_OK){
		if(resources.SetTo(&addonfile)==B_OK){
			resource=resources.FindResource(B_ARCHIVED_OBJECT, "YourResource", &resource_size);
			if(resource){	// got it!
				// do something with the resource...
			}else{
				(new BAlert("", "Window Editor cannot find its resources. \n\nMake sure the resources are linked to the add-on.", "OK"))->Go();
			}
		}
	}
}

Accepting a dropped object

Your add-on can accept dropped objects which were dragged from the 'Object Editors' window of Interface Elements. The message that you will receive has IE_DATATYPE ('Idat') as the what member.

Data name Type code Description
"Name" B_STRING_TYPE Data type name, e.g. "long", "Small Icon", "BCheckBox"
"FlattenedObject" B_RAW_TYPE The flattened object. Unflatten it by using the right add-on whose type is in "Name".

E.g. if msg contains the above info:

AddOnInfo *ai=ie_object_roster->FindClass(msg->FindString("Name"));
if(ai){
	const void *data;
	ssize_t datasize;
	if(msg->FindData("FlattenedObject", B_RAW_TYPE, &data, &datasize)==B_OK){
		IEEditableObject *the_object=ai->unflatten(data, datasize);
		if(the_object){	// success by instantiating
		}else{	// instantiating not successful
		}
	}else{	// data not found in message, this should not happen
	}
}else{	// class add-on not found
}


Hook Functions

FlattenedSize() Must be implemented if the editable object is not BArchivable. By default it returns the archive size if the object is a BArchivable, null otherwise.
Flatten() Must be implemented if the editable object is not BArchivable. By default it returns the flattened archive if the object is a BArchivable, NULL otherwise.
Unflatten() Must be implemented to instantiate the object from a byte stream.
GetEditor() Can be implemented to build an object editor view (IEObjectEditor). By default it returns NULL, which means the object has no editor.
GetDragRepresentation() Can be implemented to show a bitmap or view when the user drags the object. By default the class name over a blue background is dragged if the object is not a BView, or the default BView if the object is a kind of BView.
Generate() Can be implemented to create source files from the object. By default it does nothing.


Constructor and Destructor


IEEditableObject()

    IEEditableObject(void);
The constructor initializes internal data and registers the editable object in the object roster.

When you override the IEEditableObject class, you need to specify base classes and add-on information in the constructor. The base classes are stored in a BMessage named base_classes and the add-on info is also stored in a BMessage named info.

As an example here is the constructor of EditableBButton (IEEditableView derives from IEEditableObject) :

EditableBButton::EditableBButton(BMessage *data)
	: BButton(data), IEEditableView()
{
	base_classes.MakeEmpty();
	base_classes.AddString("class", "BButton");
	base_classes.AddString("class", "BControl");
	base_classes.AddString("class", "BView");
	
	info.MakeEmpty();
	info.AddString("Name", "BButton");
	info.AddString("Author", "Attila Mezei");
	info.AddString("Copyright", B_UTF8_COPYRIGHT " 1997 Attila Mezei");
	info.AddString("Message", "This is a button for initiating an action. A message can be posted when it is pressed.");
	info.AddInt32("TypeCode", B_ARCHIVED_OBJECT);
}

You should add the base classes in a top to bottom level order, beginning with the actual class which you turn to editable. The message format for base_classes:

Data name Type code Description
"class" B_STRING_TYPE Class name, e.g. "BControl"

You can add all kinds of information to the class by adding data to the info message. These are shown in the about box of the add-on:

Data name Type code Description
"Name" B_STRING_TYPE The name of the class or datatype which this add-on represents, e.g. "long", "BControl"
"Author" B_STRING_TYPE The author's name.
"Copyright" B_STRING_TYPE Copyright message.
"Message" B_STRING_TYPE Help text for the user.
"TypeCode" B_INT32_TYPE 32-bit type code for the object. Should be B_ARCHIVED_OBJECT if the object is a BArchivable.



~IEEditableObject()

    virtual ~IEEditableObject(void);
Notifies the object roster that the object is deleted.


Static Functions


AddOnLoaded()

      static void AddOnLoaded(entry_ref *ref);

This function is optional to implement and export. AddOnLoaded is called when the add-on image is loaded in memory and can be used to read the resources if necessary.


UnflattenObject()

      static IEEditableObject *UnflattenObject(const void *buf, ssize_t size);

This function is mandatory to implement and export. UnflattenObject returns an instance of the class or datatype from a flattened binary data.


Member Functions


Flatten()

      virtual	status_t	Flatten(void *buffer, ssize_t size);

Flatten is implemented by derived classes to write the object into the buffer. There are size bytes of memory available at the buffer address. If this isn't at least as much memory as the FlattenedSize function says is necessary, Flatten should return an error. If successful, it should return B_OK.

By default it flattens the object if it is a kind of BArchivable. This means when your class does not derive from BArchivable, you have to implement Flatten.


FlattenedSize()

      virtual	ssize_t		FlattenedSize();

Implemented by derived classes to return the amount of memory needed to hold the flattened object. This is the minimal amount that must be allocated and passed to Flatten.

By default it returns the size of the flattened archive if the object is a kind of BArchivable. This means when your class does not derive from BArchivable, you have to implement FlattenedSize.


Generate()

      virtual BMessage *Generate(BMessage *info);

Implemented by derived classes to create C++ source from the object. You can call Generate yourself if you provide the info data.

The info message contains this:

Data name Type code Description
"directory" B_REF_TYPE The directory where files should be put in.
"name" B_STRING_TYPE The name of the object. The resource editor puts the resource name here.
"windowname" B_STRING_TYPE The window name.
(Only if the object is a view in a window!)
"windowclass" B_STRING_TYPE The window class. This is the same as 'windowname' but converted to a valid C identifier.
(Only if the object is a view in a window!)
"viewnameid" B_STRING_TYPE The view name converted to a valid C identifier.
(Only if the object is a view in a window!)
"iewindowview" B_STRING_TYPE The string "IE_<windowname>_<viewname>" which can be used as an identifier for message constants, for example. The last four information are passed to the view to ease the job of creating C++ source fragments.
(Only if the object is a view in a window!)

The what data of the return message is either B_OK or B_ERROR depending on if the generation was successful or not. The return message also contains these data:

Data name Type code Description
"file" B_STRING_TYPE A filename if file was generated. View objects do not generate file, they include the following information in the message:
"Header" B_STRING_TYPE The text will be inserted in the window header file (WindowName.h). If the window includes more than one views of this type, the text will be inserted in the header for each view.
(Only if the object is a view in a window!)
"HeaderOnce" B_STRING_TYPE The text will be inserted in the window header file (WindowName.h). If the window includes more than one views of this type, the text will be inserted in the header only once, not for each view.
(Only if the object is a view in a window!)
"WindowDefs" B_STRING_TYPE The text will be inserted in the window definitions header file (WindowNameDefs.h). If the window includes more than one views of this type, the text will be inserted in the header for each view.
(Only if the object is a view in a window!)
"WindowDefsOnce" B_STRING_TYPE The text will be inserted in the window definitions header file (WindowNameDefs.h). If the window includes more than one views of this type, the text will be inserted in the header only once, not for each view.
(Only if the object is a view in a window!)
"MessageConstant" B_STRING_TYPE A message constant looks like this:
<CONSTANTNAME> = 0x<some constant>,
The comma and the carriage return is important at the end of line, as this will be a line in an enum block.
(Only if the object is a view in a window!)
"MessageReceived" B_STRING_TYPE This text will be inserted in WindowName::MessageReceived(). It should be a case block.
(Only if the object is a view in a window!)
"Constructor" B_STRING_TYPE This text will be inserted in WindowName::WindowName().
(Only if the object is a view in a window!)
"SetVariable" B_STRING_TYPE This text will be inserted in the constructor (WindowName::WindowName()). It is almost the same as "Constructor" but the text is inserted in a part where variables should be initialized.
(Only if the object is a view in a window!)
"MenusBeginning" B_STRING_TYPE This text will be inserted in WindowName::MenusBeginning().
(Only if the object is a view in a window!)


GetBaseClasses()

      BMessage *GetBaseClasses(void);

Returns the base_classes member which is filled in the constructor. You can request the class or datatype what the editable object represents by GetBaseClasses()->FindString("class").


GetDragRepresentation()

      virtual void GetDragRepresentation(BView **a_view, BBitmap **a_bitmap);

Can be implemented to show a bitmap or view when the user drags the object. By default the class name over a blue background is dragged if the object is not a BView, or the default BView if the object is a kind of BView.

If you have a view to drag, initialize the a_view pointer to point to the view. Load NULL to the a_bitmap pointer. If you want to show a bitmap, initialize a_bitmap and clear a_view.


GetEditor()

      virtual IEObjectEditor *GetEditor(IEEditableObject *object_to_edit);

This method creates an object editor view which is a kind of IEObjectEditor. In order to make an object editor you need to derive from IEObjectEditor. The IEObjectEditor has a target editable object, which is object_to_edit in this case (not the object on which GetEditor is invoked).

You must check whether the object_to_edit pointer fits you. You can be sure that it is an IEEditableObject. Use dynamic cast if necessary. This can be tricky because for example if you have an EditableBControl class which derives from IEEditableView and BControl, you shouldn't try to cast object_to_edit to EditableBControl, because it may be an EditableBCheckBox, and cannot cast to EditableBControl. You should try to cast it to BControl instead.

By default it returns NULL, which means the object has no editor.


GetInfo()

      BMessage *GetInfo(void);

Returns the info member which is filled in the constructor. You can request add-on information with this method, e.g. GetInfo()->FindString("Author").


Target()

      void *Target();

Every IEEditableObject has a target which is an object (or data) pointer which the IEEditableObject represents. The target is usually itself if you derive your class with multiple inheritence, but external objects can also be edited

In these cases you can set the target data member to the real target, and handle the target object appropriately. E.g. the editor also should work with the target pointer. Since the Target method returns a void pointer, you cannot dynamic cast it. The safest way is to examine in the object editor (which has also a target BTW, but that is an IEEditableObject...) if the target is the same as the editable object, and do according to that.


Unflatten()

      virtual IEEditableObject	*Unflatten(const void *buf, ssize_t size)=0;

This method is mandatory to implement. Its purpose is the same as of UnflattenObject, please see the description of UnflattenObject

You can implement Unflatten as

IEEditableObject    *MyEditableThing::Unflatten(const void *buf, ssize_t size)
{
    return MyEditableThing::UnflattenObject(buf, size);    // call the static function
}