# The Interface Kit: BShelf

Derived from: public BHandler

Declared in: be/interface/Shelf.h

Library: libbe.so

## Overview

A BShelf is an object that you "attach" to a view in order to make the view accept dropped BDragger objects (and the views that they serve). In user-talk, a shelf receives and displays replicants. Attaching a BShelf to a view (called the "container" view) is remarkably simple:

       BShelf *shelf = new BShelf(some_view);

That's all there is to it: With this single line of code, `some_view` is primed to accept and (automatically) display dropped replicants. A dropped replicant becomes a child of the container view. The container view itself can be any BView object--you don't alter the view in any way, or even tell it that it's going to be a container.

A rule you should remember:

|  | Attaching a shelf to a view is performed by the BShelf constructor only. You can't create a BShelf and then decide which view you want it to serve.

### Dropping into the View Hierarchy

When the user drops a replicant on a container view, the view receives a `B_ARCHIVED_OBJECT` message that contains a BDragger and the dragger's target (a BView). These two objects (the BDragger and its target) are directly related as parent-child, child-parent, or as siblings (as explained in the BDragger class). The "more elderly" of the two objects is added as a child of the container view; if they're siblings, the two objects are both added as children.

You can also send or post `B_ARCHIVED_OBJECT` messages to a BShelf to simulate a drag and drop.

### Other BShelf Features

- Settings. A BShelf can configure itself from a "settings" file, and can write its contents to that file. Your only chance to associate a BShelf with a settings file is during construction. You can save the contents at any time through the `Save()` function.

- Replicant rejection. A BShelf can reject replicants, and can adjust the position of the replicants that it accepts. These features are provided through the hook functions `CanAcceptReplicantMessage(), CanAcceptReplicantView(),` and `AdjustReplicantBy()`. A named shelf can also reject replicants, as explained next.

- BShelf names. When a replicant message is dropped on the shelf, the shelf's name (set in the constructor) is compared to the dropped message's "shelf_type" field (if it has one). If the two don't match, the replicant rejects the shelf. In this way, individual replicants can be picky about the shelves that they want to be displayed on. Additionally, if a BShelf is set to "enforce type" (set through `SetTypeEnforced()`), then it will only accept replicants that name the shelf (in their "shelf_type" fields). Type enforcement is `false` by default.

- A BShelf assigns each replicant a unique id that's valid for as long as the replicant is attached to the shelf. Replicant ids don't change, even if the shelf is `Save()`'d and then later restored (through the constructor).

## Hook Functions

`CanAcceptReplicantMessage()
` Invoked when a replicant BMessage is received by the BShelf. A return value of `false` rejects the replicant.

`CanAcceptReplicantView()
` Invoked after the message has been accepted (by the above); this is the shelf's chance to reject on the basis of the view that the message contains. A return value of `false` rejects the replicant.

`AdjustReplicantBy()
` Invoked after the replicant has been accepted, but before it's displayed. The function can return a BPoint that offsets the replicant's frame.

## Constructor and Destructor

### BShelf()

          BShelf(BView *view, bool allowsDragging = true, const char *name = NULL)

          BShelf(const entry_ref *ref, BView *view, bool allowsDragging = true,
             const char *name = NULL)

          BShelf(BDataIO *stream, BView *view, bool allowsDragging = true,
             const char *name = NULL)

Initializes the BShelf object so that it serves a container view. The versions that accept an `entry_ref` or BDataIO argument prime the shelf so that it (initially) contains the replicants that are archived in the referred to file or stream using `Save()`. The ref/stream argument is also used as the archival repository when you tell your BShelf to `Save()` itself.

If the allowsDragging flag is `true`, the user will be able to drag replicant view within the container's bounds. If the flag is `false`, dropped views stay where they're first put.

name is the BShelf's handler name. The name can be important: It's compared to the replicant's "shelf_type" field, as explained in `AddReplicant()`.

|  | There's an archive-accepting version of the BShelf constructor declared in Shelf.h. Don't use it.

### ~BShelf()

          virtual ~BShelf()

The destructor calls `Save()`, and then frees the object.

## Static Functions

### Instantiate()

|  | `Instantiate()` is currently a no-op that returns `NULL`. You can't archive a BShelf. If you want to archive something, archive the shelf's contents by calling `Save()`.

## Member Functions

### AddReplicant()

          status_t AddReplicant(BMessage *archive, BPoint point)

This function is invoked automatically when a replicant is dropped on the BShelf. The archive message contains the BDragger archive that's being dropped; point is where, within the container view's bounds, the message was dropped. The function goes through these steps to reject and adjust the replicant:

- First, it invokes the `CanAcceptReplicantMessage()` hook function. If the hook returns `false`, then `AddReplicant()` doesn't add the replicant.

- Next, it looks for a "shelf_type" string field in the BMessage. If it finds one and the value of the field doesn't match the BShelf's name, the replicant is rejected.

  If type enforcement is `true` (see `SetTypeEnforced()`) and the shelf has a name, then the BMessage must have a "shelf_type" string and this string must match the shelf name. Otherwise, the replicant is rejected.

  There's no specific API for adding the "shelf_type" field to a view. If you want to configure your views to accept only certain BShelf objects, you have to add the field directly as part of the view's `Archive()` implementation.

- The archive message is then unarchived (the replicant is instantiated). If the archive doesn't contain a BView, the message is passed on to another handler (`B_DISPATCH_MESSAGE` is returned).

- `CanAcceptReplicantView()` hook function is called next (with a return of `false` meaning rejection).

- Finally, `AdjustReplicantBy()` is called, and the replicant is drawn in the container view.

Except in the case of a no-view archive, `AddReplicant()` returns `B_SKIP_MESSAGE`.

It's possible to archive a BDragger and call this function yourself, although that's not its expected use.

### AdjustReplicantBy()

          virtual BPoint AdjustReplicantBy(BRect destRect, BMessage *archive) const

This hook function is invoked automatically when a replicant is dropped on the BShelf. It gives the shelf a chance to fine-tune the placement of the BDragger and its target view.

destRect is the rectangle (in the container view's coordinates) in which the dropped replicant is about to be drawn. Exactly what the rectangle means depends on the relationship between the dragger and its target:

- If the dragger is the target's parent, then destRect encloses the BDragger's frame.

- Otherwise (if the target is the parent, or if the two views are siblings), destRect encloses the target's frame. Note that in the case of siblings, the BDragger's frame isn't included in the rectangle.

archive is the archive message that was dropped on the shelf.

The BPoint that this function returns offsets (is added into) the location of the replicant. If you don't want to move the replicant, return BPoint(0, 0). Note that the BDragger and the view are both moved by this offset, even in the case where destRect doesn't include the dragger's frame.

This function ignores the "allows dragging" flag given in the BShelf constructor. In other words, you can adjust a replicant's placement through this function even if the BShelf doesn't otherwise allow dragging.

### AllowsDragging() see SetAllowsDragging()

### AllowsZombies() see SetAllowsZombies()

### Archive()

|  | `Archive()` is currently a no-op that returns `B_ERROR`. You can't archive a BShelf. If you want to archive something, archive the shelf's contents by calling `Save()`.

### CanAcceptReplicantMessage(), CanAcceptReplicantView()

          virtual bool CanAcceptReplicantMessage(BMessage *archive) const
          virtual bool CanAcceptReplicantView(BRect destRect,
             BView *view,
             BMessage *archive) const

These hook function are invoked from within `AddReplicant()` whenever a replicant is dropped on the BShelf. You can implement these functions to reject unwanted replicants.

`CanAcceptReplicantMessage()` is called first; the argument is the archive that (should) contain the replicated view. If you don't like the look of the archive, return `false` and the message will be thrown away. Note that you shouldn't return `false` if the archive doesn't seem to be in the correct form (specifically, if it doesn't contain any views). Rejection of such messages is handled more elegantly (and after this function is invoked) by the `AddReplicant()` function.

`CanAcceptReplicantView()` is invoked after the message has been unarchived. destRect is the rectangle that the replicant will occupy in the BShelf's container view's coordinates. view is the replicated view itself. archive is theoriginal message.

If either function returns `false`, the replicant is rejected and the message is thrown away (it isn't passed on to another handler). A return of `true` does the obvious thing.

### CountReplicants()

          int32 CountReplicants(void) const

Returns the number of replicants attached to the shelf.

### DeleteReplicant()

          status_t DeleteReplicant(BView *replicant_view)
          status_t DeleteReplicant(const BMessage *archive)
          status_t DeleteReplicant(uint32 uid)

Removes the specified replicant from the shelf. It identifies replicants by either a view, a replicant message, or a unique id.

### DisplaysZombies() see SetAllowsZombies()

### IndexOf(), ReplicantAt()

          int32 IndexOf(const BView *replicant_view) const
          int32 IndexOf(const BMessage *archive) const
          int32 IndexOf(uint32 uid) const

          BMessage *ReplicantAt(int32 index, BView **view = NULL, uint32 *uid = NULL,
             status_t *err = NULL) const

`IndexOf()` returns the index of a specified replicant in the shelf, or -1 if no such replicant exists. It accepts either a view, a replicant message, or a unique id as identifiers.

`ReplicantAt()` returns information about a replicant in a shelf given its index (as returned by `IndexOf()`). It returns the BMessage archive of the replicant or `NULL` if the index is invalid. It returns the view of the replicant as well as its uid, if these parameters are non-`NULL`. It returns an error message in err if there was an error in initializing the given replicant.

### IsDirty() see Save()

### IsTypeEnforced() see SetTypeEnforced()

### ReplicantAt() see IndexOf()

### ReplicantDeleted()

          virtual void ReplicantDeleted(int32 index, const BMessage *archive,
             const BView *view)

This hook function is invoked from within `DeleteReplicant()` to indicate a replicant has been deleted from the BShelf. It is called after the view has been removed from the shelf with the index of the replicant in the shelf, its archive message, and the detached view.

### Save(), SaveLocation(), SetSaveLocation(), SetDirty(), IsDirty()

          status_t Save(void)
          BDataIO *SaveLocation(entry_ref *ref) const
          status_t SetSaveLocation(BDataIO *data_io)
          status_t SetSaveLocation(const entry_ref *ref)

          virtual void SetDirty(bool flag)
          bool IsDirty(void)

Writes the shelf's contents (the replicants that it contains) as an archive to the `entry_ref` or BDataIO object that was specified in the constructor. You can also set the location where the shelf is saved with `SetSaveLocation()` and fetch it with `SaveLocation()`. The entry_ref is stored in ref (if ref is non-`NULL`) and the BDataIO the shelf will be written to is returned. If the shelf will be written to an entry_ref that is not a BDataIO, `SaveLocation()` returns `NULL`.

By default, the save is only performed if the object's "dirty" flag is set--in other words, if it has changed since it was last written. You can force set the dirty flag by calling `SetDirty()`.

`IsDirty()` returns the current state of the "dirty" flag.

### SetAllowsDragging(), AllowsDragging()

          void SetAllowsDragging(bool state)

          bool AllowsDragging(void) const

`SetAllowsDragging()` determines whether the BShelf accepts replicants dragged into the view by the user. `AllowsDragging()` returns whether the BShelf accepts replicants dragged by the user into the container view's frame?

### SetAllowsZombies(), AllowsZombies(), SetDisplayZombies(), AllowsZombies()

          void SetAllowsZombies(bool state)
          bool AllowsZombies(void) const

          void SetDisplaysZombies(bool state)
          bool DisplaysZombies(void) const

`SetAllowsZombies()` determines whether the BShelf accepts zombie views. `AllowsZombies()` returns whether the BShelf accepts zombie views.

Similarly,`SetDisplaysZombies()` determines whether the BShelf displays zombie views and `DisplaysZombies()` returns whether the BShelf displays zombie views.

### SetDisplaysZombies() see SetAllowsZombies()

### SetTypeEnforced(), IsTypeEnforced()

          void SetTypeEnforced(bool state)

          bool IsTypeEnforced(void) const

`SetTypeEnforced()` determines whether the BShelf checks accepts replicants

These two methods set and return the type enforcement flag. When it is `true`, the shelf compares its name to the "shelf_type" field of any dropped messages. The replicant is accepted only if the two match. If the dropped message does not have a "shelf_type" field, then it is rejected. Type enforcement is `false` by default.

## Scripting Support

The BShelf class implements the suite called "suite/vnd.Be-shelf" consisting of the following message:

### The Replicant Property

Message | Specifiers | Meaning
`B_COUNT_PROPERTIES` | `B_DIRECT_SPECIFIER` | Returns number of replicants in the shelf.
`B_CREATE_PROPERTIES` | `B_DIRECT_SPECIFIER` | Adds the archived replicant in the BMessage "data" to the view at the BPoint in "location."
`B_DELETE_PROPERTY` | `B_INDEX_SPECIFIER`, `B_REVERSE_INDEX_SPECIFIER`, `B_NAME_SPECIFIER`, `B_ID_SPECIFIER` | Removes the specified replicant from the shelf.
`B_GET_PROPERTY` | B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, B_NAME_SPECIFIER, B_ID_SPECIFIER | Archives the specified replicant into a BMessage in "result."
anything else | `B_INDEX_SPECIFIER`, `B_REVERSE_INDEX_SPECIFIER`, `B_NAME_SPECIFIER`, `B_ID_SPECIFIER` | Directs the scripting message to the replicant interface "suite/vnd.Be-replicant" (described below), first popping the current specifier off the stack.

The "Replicant" property provides access to the replicants contained in a BShelf. It also allows you to manipulate the replicants themselves by forwarding certain messages to a "suite/vnd.Be-replicant" interface. This interface consists of the following messages:

### The ID Property

Message | Specifiers | Meaning
`B_GET_PROPERTY` | `B_DIRECT_SPECIFIER` | Returns the replicant ID.

### The Name Property

Message | Specifiers | Meaning
`B_GET_PROPERTY` | `B_DIRECT_SPECIFIER` | Returns the name of the replicant view.

### The Signature Property

Message | Specifiers | Meaning
`B_GET_PROPERTY` | `B_DIRECT_SPECIFIER` | Returns the signature of the add-on containing the code for the replicant.

### The Suites Property

Message | Specifiers | Meaning
`B_GET_PROPERTY` | `B_DIRECT_SPECIFIER` | Returns "suite/vnd.Be-replicant" in "suites" and a flattened BPropertyInfo describing the scripting suite in "messages."

### The View Property

Message | Specifiers | Meaning
any | `B_DIRECT_SPECIFIER` | Directs the scripting message to the replicant view, first popping the current specifier off the specifier stack.

The Be Book, in lovely HTML, for BeOS Release 3.

Copyright © 1998 Be, Inc. All rights reserved.

Last modified March 26, 1998.