
/*!
        @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>
                                &lt;?xml version="1.0" ?&gt;
                                &lt;!DOCTYPE toolbar SYSTEM "atoolbar.dtd"&gt;
                                &lt;toolbar&gt;
                                &nbsp;&nbsp;&lt;item&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;com.uncommonplace.accela.sample&lt;/id&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;text&gt;Sample&lt;/text&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;command&gt;Samp&lt;/command&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;iconcreator&gt;ACEL&lt;/iconcreator&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;icontype&gt;Samp&lt;/icontype&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;attributes&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;allowduplicates /&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;/attributes&gt;
                                &nbsp;&nbsp;&lt;/item&gt;
                                &nbsp;&nbsp;&lt;default&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;com.uncommonplace.accela.sample&lt;/id&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;com.apple.hitoolbox.toolbar.flexiblespace&lt;/id&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;com.apple.hitoolbox.toolbar.customize&lt;/id&gt;
                                &nbsp;&nbsp;&lt;/default&gt;
                                &nbsp;&nbsp;&lt;allowed&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;com.uncommonplace.accela.sample&lt;/id&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;com.apple.hitoolbox.toolbar.separator&lt;/id&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;com.apple.hitoolbox.toolbar.space&lt;/id&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;com.apple.hitoolbox.toolbar.flexiblespace&lt;/id&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;com.apple.hitoolbox.toolbar.customize&lt;/id&gt;
                                &nbsp;&nbsp;&nbsp;&nbsp;&lt;id&gt;com.apple.hitoolbox.toolbar.print&lt;/id&gt;
                                &nbsp;&nbsp;&lt;/allowed&gt;
                                &lt;/toolbar&gt;
                                </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>

*/

