Most of the wrapper classes in ACCELA are based on the XWrapper or XRefCountObject templates. They are both based on the XValueWrapper template, which simply wraps a value type T and has an operator T() method as well as explicit accesors. The two subclasses add the needed logic in their constructors, destructors, and operator=() methods to properly manage the wrapped value.
Each of those templates has another class template (XOwnedRef and XRetainedRef) used to wrap values that have just been created or retained. Using this instead of a plain value triggers the use of a different constructor, which handles this special case appropriately. All methods that return a created or retained value will use one of these special wrappers.
For example, ANib::CreateWindow() returns an XRetainedRef<WindowRef> instead of just a WindowRef, so that the return value can be passed to the constructor of AWindow, signaling that the value should not be retained. This value can also be transparently treated as a WindowRef since the superclass XValueWrapper<WindowRef> has an operator WindowRef() method.
XWrapper handles references that are simply created and destroyed. For every specialized subclass, there must also be a specialization of XWrapper<T>::DisposeSelf() which handles disposing of the reference. For example:
template<>
inline void
XWrapper<IBNibRef>::DisposeSelf()
{ ::DisposeNibReference(mValue); }
If XWrapper's constructor is given an XOwnedRef object, then it sets a flag indicating that the destructor should dispose of the reference.
XRefCountObject handles references that have a retain count. This template has a second template parameter, which is a class that contains the Retain(), Release(), and RetainCount() methods for the value type. The DefineRefCounter_ macro makes it easy to define the necessary class.
Unless XRefCountObject's constructor is given an XRetainedRef, the given value will be retained. The destructor always releases the value.
Thus, the behavior for both XWrapper and XRefCountObject is to leave the wrapped value in its original state if the constructor was given a plain value.
ACarbonEvent inherits from XRefCountObject<EventRef>, wraps all event related functions, and also provides some method templates for convenience in dealing with parameters. For example, calling event.SetParameter(kEventParamDirectObject,someWindowRef) will automatically use the correct data size and type constant for a WindowRef.
AEventParameter is a class template that simplifies getting and setting event parameters, especially from within an event handler. There are many subclass templates and specializations for dealing with many of the standard parameters and data types. The AEventObject subclasses such as AWindowHandler contain extensive examples of how to use these.
Unfortunately this cannot be described without a potential confusion between C++ template parameters and Carbon Event parameters, so watch closely.
The first template parameter is the value type of the event parameter, and the second is a policy class which determines the read/write behavior. AReadOnly, AReadWrite, and AWriteOnly are provided for use in this template parameter, with AReadOnly being the default.
ASpecificParameter is a template where the event parameter name and type code are included as template parameters.
ANamedParam is a subclass of ASpecificParameter which takes only the event parameter name and uses the XParamTraits template specializations to determine the type code, since most event parameters are always the same type. For example, the specialization of XParamTraits<kEventParamWindowRef> includes enum { typeCode = typeWindowRef }.
AParams is a class template, but could be thought of as a "namespace template" since it consists only of typedefs: specializations of ASpecificParameter and ANamedParam for many common and important event parameters. Its only template parameter specifies the read/write policy.
For example, look at AParams<>::Window:
AGenericParameter and ATypeParams are similar to ASpecificParameter and AParams, but they still take a parameter name in the constructor. This is for working with general-purpose parameters such as kEventParamDirectObject which is used with many different types.
AEventObject essentially wraps an EventHandlerRef and contains the event handler callback. The primary method to override is HandleEvent(). There is also a mechanism to make it safe to delete a handler object from inside the callback.
The form that the standard event handler classes follow is that there is an AEventObject subclass for every Carbon Event class, and a method for every event. These methods return a boolean value which is true if the event was handled, so the standard default behavior is to do nothing and return false. Read-only parameters are passed by value, and read/write and write-only parameters are passed as AEventParameter objects.
It is possible to multiply inherit from several event handler classes, but you must be careful to explicitly reference the correct superclass for operations such as adding event types to the handler. See AToolbar::ItemEnabler for an example.
The Framework folder contains code that can be used for building a document-based application, complete with AppleScript support. The document classes have basic file handling features, and implement the standard UI guidelines for using the Navigation Services dialogs for opening and saving.
ADocumentManager is patterned after Cocoa's NSDocumentManager. It manages the list of documents and implements the application-level document commands such as New and Open. It also uses ARecentItemsMenu to maintain a list of recent documents.
The list of file types that will appear in the Open dialog is determined by the application's Info.plist file, in the same way as with a Cocoa document-based application.
ADocument is actually a class template, where the template parameters are policy classes that determine the handling of files and windows. Single-file and single-window behaviors are implemented in ASingleFileRep and ASingleWindowRep, and the AStandardDocument subclass puts those two together.
As with ADocumentManager, ADocument uses the Info.plist file to build the list of file types that the user can choose in the Save As dialog.
Cocoa's scripting system is used as the base for ACCELA's AppleScript support because it conveniently implements many tedious features, such as working with lists. For example, when a script tries to access a window by name or by index, ACCELA only needs to provide the list of windows. Cocoa automatically handles searching the list for the referenced item.
For every type of object that a script can access, there is an Objective-C proxy class which implements the commands and property accessors, usually forwarding the command to a C++ object. At this level, everything works just as in scripting a Cocoa application, so you can refer to the Cocoa documentation on this subject. See also the Documents sample project for a starter .sdef file.
If you need to add more functionality to your document or window script interface, then you can subclass ADocumentScriptProxy or AWindowScriptProxy, and update your .sdef file to refer to your new subclasses. If you need to add application-level commands, then you can subclass AAppScriptDelegate and override ADocumentManager::SetUpScripting() to instantiate your subclass instead.