/*! @header AAutoToolbar.h @abstract Header for AAutoToolbar and AAutoToolbarDelegate . @discussion <code>AAutoToolbar</code> and <code>AAutoToolbarDelegate</code> together make it easy to add toolbars to an application. Little programming is required if you're only using simple icon items. The items that the toolbar can have are specified in an XML file, containing the following elements: <ul> <li><code>toolbar</code>: The root element, containing a <code>default</code> element, an <code>allowed</code> element, and any number of <code>item</code> elements. <li><code>item</code>: Contains <code>id</code>, <code>text</code>, <code>command</code>, <code>iconcreator</code>, <code>icontype</code>, and <code>attributes</code> elements. <li><code>default</code>: A list of <code>id</code> elements defining the initial item set for the toolbar. <li><code>allowed</code>: A list of <code>id</code> elements defining all allowable items, which determines the appearance of the Configure sheet. <li><code>id</code>: A unique ID for an item type. The reverse domain name format is recommended. <li><code>text</code>: The item's title text. <li><code>command</code>: A four-character code for the command ID. <li><code>noautoenable</code>: Don't try to synchronize the item's enabled state with a menu item (using <code>AToolbar::ItemEnabler</code>). This will also not be done if the command ID is absent (or zero). This element should be empty. <li><code>iconcreator</code>: A four-character code for the icon creator code. <li><code>icontype</code>: A four-character code for the icon creator type. <li><code>attribute</code>: Contains any of the following elements defining an item's attributes: <ul> <li><code>allowduplicates</code>: The toolbar may contain more than one of this item. <li><code>cantberemoved</code>: The item may be rearranged, but not removed. <li><code>anchoredleft</code>: The item cannot be moved and is anchored to the left side. <li><code>isseparator</code>: The item functions as a separator. <li><code>userfocus</code>: Commands generated by the item should be sent to the current user focus instead of to the window.</ul></ul> Sample XML data: <pre> <?xml version="1.0" ?> <!DOCTYPE toolbar SYSTEM "atoolbar.dtd"> <toolbar> <item> <id>com.uncommonplace.accela.sample</id> <text>Sample</text> <command>Samp</command> <iconcreator>ACEL</iconcreator> <icontype>Samp</icontype> <attributes> <allowduplicates /> </attributes> </item> <default> <id>com.uncommonplace.accela.sample</id> <id>com.apple.hitoolbox.toolbar.flexiblespace</id> <id>com.apple.hitoolbox.toolbar.customize</id> </default> <allowed> <id>com.uncommonplace.accela.sample</id> <id>com.apple.hitoolbox.toolbar.separator</id> <id>com.apple.hitoolbox.toolbar.space</id> <id>com.apple.hitoolbox.toolbar.flexiblespace</id> <id>com.apple.hitoolbox.toolbar.customize</id> <id>com.apple.hitoolbox.toolbar.print</id> </allowed> </toolbar> </pre> */ // See the bottom of this file for the plain text version of the XML sample. #pragma once #include "ACFBundle.h" #include "ACFString.h" #include "ACFXMLParser.h" #include "AToolbar.h" class AAutoToolbarDelegate; class ACFURL; // --------------------------------------------------------------------------- /*! @class AAutoToolbar @abstract A toolbar that reads its configuration from an XML file. @discussion The delegate class actually does all the work. If you need to use custom items (like a popup button), you can subclass <code>AAutoToolbarDelegate</code> and specify your subclass as a template parameter for <code>AAutoToolbar</code>. @templatefield Source A class containing the toolbar ID and the file name. @templatefield DelegateClass A subclass of <code>AToolbar::Delegate</code>. Defaults to <code>AAutoToolbarDelegate</code>. Use a subclass of that if you need custom items. */ template <class Source,class DelegateClass = AAutoToolbarDelegate> class AAutoToolbar : public AToolbar { public: /*! @function AAutoToolbar @abstract Create a toolbar for the given window. @discussion Unlike the <code>AToolbar</code> constructor, the toolbar ID is not specified here; it's in the XML file. Also, this constructor immediately associates the new toolbar with a window. The toolbar ID will also become the class ID of the delegate class. @param inWindow The window. @param inAttributes Valid options so far are <code>kHIToolbarAutoSavesConfig</code> and <code>kHIToolbarIsConfigurable</code>. */ AAutoToolbar( WindowRef inWindow, OptionBits inAttributes) : AToolbar(Source::identifier,inAttributes) { // note that the toolbar id is also the delegate class id if (sDelegateClass == NULL) sDelegateClass = new AHIObjectClassT<DelegateClass>(Source::identifier); if (sDelegate == NULL) sDelegate = sDelegateClass->MakeObject( (void*)ACFMainBundle().CopyResourceURL(Source::filename,CFSTR("xml"))); SetDelegate(*sDelegate); ::SetWindowToolbar(inWindow,*this); } /*! Destructor function */ virtual ~AAutoToolbar() { std::vector<ItemEnabler*>::iterator iter; for (iter = mEnablers.begin(); iter != mEnablers.end(); iter++) delete *iter; } protected: /*! @var mEnablers List of item enablers so they can be properly deleted. */ std::vector<ItemEnabler*> mEnablers; /*! @var sDelegateClass The HIObject class for the delegate. */ static AHIObjectClassT<DelegateClass> *sDelegateClass; /*! @var sDelegate The global delegate object. */ static DelegateClass *sDelegate; }; // --------------------------------------------------------------------------- /*! @defined DeclareAutoToolbar_ @abstract Creates the declaration of a class for use as the template parameter for <code>AAutoToolbar</code>. @discussion The class created by this macro holds the toolbar identifier and the name of the XML settings file. */ #define DeclareAutoToolbar_(_name_) \ class _name_ \ { \ public: \ static const CFStringRef identifier,filename; \ }; /*! @defined DefineAutoToolbar_ @abstract Creates the definitions for the static data members of the class created by <code>DeclareAutoToolbar_</code> and the instantiation of <code>AAutoToolbar</code>. @discussion The <code>_name_</code> parameter should be the same one used with <code>DeclareAutoToolbar_</code>. The <code>_id_</code> parameter is the ID string for your toolbar, and <code>_file_</code> is the name of the XML settings file. */ #define DefineAutoToolbar_(_name_,_id_,_file_) \ const CFStringRef _name_::identifier = CFSTR(_id_),_name_::filename = CFSTR(_file_); \ AHIObjectClassT<AAutoToolbarDelegate> *AAutoToolbar<_name_>::sDelegateClass = NULL; \ AAutoToolbarDelegate *AAutoToolbar<_name_>::sDelegate = NULL; /*! @defined DefineCustomAutoToolbar_ @abstract As with <code>DefineAutoToolbar_</code>, but with a custom delegate class for when you need to implement custom items. @discussion The <code>_delegate_</code> parameter is your subclass of <code>AAutoToolbarDelegate</code>. */ #define DefineCustomAutoToolbar_(_name_,_delegate_,_id_,_file_) \ const CFStringRef _name_::identifier = CFSTR(_id_),_name_::filename = CFSTR(_file_); \ AHIObjectClassT<AAutoToolbarDelegate> *AAutoToolbar<_name_>::sDelegateClass = NULL; \ _delegate_ *AAutoToolbar<_name_,_delegate_>::sDelegate = NULL; // --------------------------------------------------------------------------- /*! @class AAutoToolbarDelegate @abstract Toolbar delegate whose behavior depends on the contents of an XML settings file. @discussion If you need to implement custom toolbar items, then you should subclass <code>AAutoToolbarDelegate</code> and override <code>CreateItemWithIdentifier</code>. */ class AAutoToolbarDelegate : public AToolbar::Delegate, public AHICustomObject { public: /*! @class AAutoToolbarDelegate::ItemSettings @abstract Holds the settings for a toolbar item. */ class ItemSettings { public: /*! @function ItemSettings @abstract Initialize from a portion of the XML data. @param inTree The XML data subtree defining this item. */ ItemSettings( const ACFXMLTree &inTree); /*! @function ID @abstract Get the item ID @result A reference to the item ID. */ const ACFString& ID() const { return mID; } /*! @function Text @abstract Get the item's title text. @result A reference to the title text. */ const ACFString& Text() const { return mText; } /*! @function Command ID @abstract Get the item's command ID. @result The command ID. */ UInt32 CommandID() const { return mCommandID; } /*! @function IconCreator @abstract Get the item's icon creator. @result The icon creator. A value of 0 means no value was specified. */ UInt32 IconCreator() const { return mIconCreator; } /*! @function IconType @abstract Get the item's icon type. @result The icon type. A value of 0 means no value was specified. */ UInt32 IconType() const { return mIconCreator; } /*! @function Icon @abstract Get the item's icon @result The item's icon. */ IconRef Icon() const; /*! @function Options @abstract Get the item's option flags. @result The item's option flags. */ OptionBits Options() const { return mOptions; } bool CanUseEnabler() const { return mUseEnabler && (mCommandID != 0); } protected: /*! @var mID The item ID. */ ACFString mID; /*! @var mText The item's title text. */ ACFString mText; /*! @var mCommandID The command ID generated when the item is clicked. */ UInt32 mCommandID; /*! @var mIconCreator The creator code for the icon. */ UInt32 mIconCreator; /*! @var mIconCreator The type code for the icon. */ UInt32 mIconType; /*! @var mOptions The option bits. */ OptionBits mOptions; bool mUseEnabler; /*! @function GetFourByteValue @abstract A utility function for turning a four-character string into a four-byte value. @param inString A four-character string. @param outValue The resulting four-byte value. */ static void GetFourByteValue( const ACFString &inString, UInt32 &outValue); }; protected: friend class AHIObjectClassT<AAutoToolbarDelegate>; typedef std::vector<ItemSettings> ItemVector; typedef std::vector<ACFString> StringVector; /*! @var mItems The list of item definitions. */ ItemVector mItems; /*! @var mDefaults The list of item IDs in the default configuration. */ StringVector mDefaults; /*! @var mAllowed The list of all item IDs to be shown in the "configure" sheet. */ StringVector mAllowed; AAutoToolbarDelegate( HIObjectRef inObject) : Delegate(::HIObjectGetEventTarget(inObject)), AHICustomObject(inObject) {} /*! @functiongroup Delegate events */ /*! @function GetDefaultIdentifiers @abstract Handle the <code>kEventToolbarGetDefaultIdentifiers</code> event. @discussion This function determines the default item configuration of the toolbar. It is handled automatically by remembering what was in the <code>default</code> tag in the XML file. @result Whether the event was handled. @param ioArray An array to be filled with the default item IDs. */ virtual bool GetDefaultIdentifiers( ACFMutableArray &ioArray); /*! @function GetDefaultIdentifiers @abstract Handle the <code>kEventToolbarGetAllowedIdentifiers</code> event. @discussion This function determines which items will show up in the Configure sheet. It is handled automatically by remembering what was in the <code>allowed</code> tag in the XML file. @result Whether the event was handled. @param ioArray An array to be filled with the default item IDs. */ virtual bool GetAllowedIdentifiers( ACFMutableArray &ioArray); /*! @function CreateItemWithIdentifier @abstract Creat a new toolbar item of a specified type. @param inIdentifier The item ID. @param inConfigData Configuration data that a custom item may need. @param outItem On return, the <code>HIToolbarItemRef</code> of the created item. @result Whether the event was handled. */ virtual bool CreateItemWithIdentifier( const ACFString &inIdentifier, const AEventParameter<CFTypeRef> &inConfigData, AEventParameter<HIToolbarItemRef,AWriteOnly> &outItem); /*! @functiongroup <code>AHICustomObject</code> overrides */ /*! @function Initialize @abstract Handle the <code>kHIObjectInitialize</code> event. @discussion This is the function that reads the XML file and stores the information for future use. The name of the file is a parameter of the event. @result An OSStatus code. @param inEvent The initialization event. */ OSStatus Initialize( const ACarbonEvent &inEvent); /*! @functiongroup <code>AAutoDelegate</code> utility functions */ /*! @function AddIDs @abstract Add all item IDs in the given XML tree to a vector. @discussion This function is used to process both the <code>default</code> and <code>allowed</code> tags, since they are both lists of item IDs and differ only in their eventual purpose. @param inTree An XML tree containing a list of <code>id</code> elements. @param ioArray An array which will be filled with the item IDs. */ void AddIDs( const ACFXMLTree &inTree, StringVector &inVector); /*! @function GetIdentifiers @abstract Populate an array with the contents of a string vector. @discussion This method is used to respond to both <code>kEventToolbarGetAllowedIdentifiers</code> and <code>kEventToolbarGetDefaultIdentifiers</code>. @param inSource Either <code>mDefaults</code> or <code>mAllowed</code>. @param ioArray The array from the event. */ static void GetIdentifiers( const StringVector &inSource, ACFMutableArray &ioArray); }; // --------------------------------------------------------------------------- /* XML example <?xml version="1.0" ?> <!DOCTYPE toolbar SYSTEM "atoolbar.dtd"> <toolbar> <item> <id>com.uncommonplace.accela.sample</id> <text>Sample</text> <command>Samp</command> <iconcreator>ACEL</iconcreator> <icontype>Samp</icontype> <attributes> <allowduplicates /> </attributes> </item> <default> <id>com.uncommonplace.accela.sample</id> <id>com.apple.hitoolbox.toolbar.flexiblespace</id> <id>com.apple.hitoolbox.toolbar.customize</id> </default> <allowed> <id>com.uncommonplace.accela.sample</id> <id>com.apple.hitoolbox.toolbar.separator</id> <id>com.apple.hitoolbox.toolbar.space</id> <id>com.apple.hitoolbox.toolbar.flexiblespace</id> <id>com.apple.hitoolbox.toolbar.customize</id> <id>com.apple.hitoolbox.toolbar.print</id> </allowed> </toolbar> */