Hints for a generic Juce Factory


#1

I’d like to create juce objects, especially components, by classname and want to delegate this to a central factory class.
For my own classes I’m happy using a CloneFactory which registers a prototype together with a name and then clones that prototype.

Panel* Panel::clone() { return new Panel; }

I can’t do this with arbitrary juce objects, because they don’t have a common base class with a clone method.

So I think the best approach would be to build a CreatorFactory which uses
external creation functions instead of prototypes:

TextEditor* createTextEditor() { return new TextEditor; }

I think the jucer must do something in this direction, any hints where to look for those things inside the juce source code are welcome.


#2

Toolbars work with a factory Frank, check that out.

The online juce docs have a search function, btw.

http://www.rawmaterialsoftware.com/juce/api/search.php?query=factory

Regards,

Bruce


#3

Thank you Bruce for this hint.
I also looked into the jucer sources to find out if there is a kind of factory.
What I found was a handler for each component:

Component* createNewComponent (JucerDocument*) { return new TextButton (T("new button"), String::empty); }

I have to dig a bit deeper to find out if and how the jucer finds a handler by name.

For those, who are interested, what I have so far (WIP), it’s a functor based factory template:

This defines a factory for juce components:

This are the typedefs for creator functors:

typedef CreatorTemplate< TextEditor > TextEditorCreator; typedef CreatorTemplate< WebBrowserComponent > WebBrowserComponentCreator; typedef CreatorTemplate< ValueTreeView > ValueTreeViewCreator;

With this call you can register a functor:

component_factory.registerCreator( new TextEditorCreator,T("TextEditor") ); component_factory.registerCreator( new WebBrowserComponentCreator, T("WebBrowserComponent") ); component_factory.registerCreator( new ValueTreeViewCreator, T("ValueTreeView") );

and later use this call to create a component based on info from a ValueTree
(thanks Jules for the ValueTree class) :slight_smile:

[code]Component* GuiSystem::createComponent( const ValueTree& node )
{
Component* comp = NULL;
if( node.hasType(“Panel”) ) // a gui node item
{
String type = node.getProperty ( String(T(“Type”) ));
String name = node.getProperty ( String(T(“Name”) ));

    comp = component_factory.createObject(type);
    initializeComponent(  comp, node );
 }

return comp;

}

[/code]

Here comes the code for the factory:

[code]class Functor
{
public:

    virtual void* create(void) const
    {
     return 0;
    }
    
    virtual void* operator()(void)
    {
        return 0;
        //cout << typeid(T).name() <<endl;
    }
};

template
class CreatorTemplate : public Functor
{
public:

virtual T* create(void)const
{
    return new T;
}

 virtual T* operator()(void) // covariant return type
{
     return new T;
    //cout << typeid(T).name() <<endl;
}

};

//typedef CreatorTemplate< Functor > FunctorCreator;

typedef std::vector<const Functor*> FunctorArray;

/**
This factory creates objects by calling a create functor
For each class you have to provide an external functor which can create an instance of that class
typename T is the type of object you want to create, eg a juce::Component
*/

template
class CreatorFactory
{
public:
/*
CreatorFactory()
{
void* result = test_functor();
}
*/

    size_t registerCreator(   Functor* functor,  String type)
    {
        size_t idx = functors.size();

        const Functor* existing_functor = getFunctor(type);
        if( existing_functor == NULL) // not yet registered
        {
            typenames.add(type);
            functors.push_back(functor);
        }
        return idx;
        
    }
    
    const Functor* getFunctor( const String& name) const
    {
        const Functor* functor = NULL;
        for( size_t i=0;i<typenames.size();i++)
        {
            if( typenames[i] == name )
            {
                functor = functors[i];
                break;
            }    
        } 
        return functor;
    }
    
    size_t getTypeID( const String& name) const
    {
        size_t type_id = (size_t)-1;
        for( size_t i=0;i<typenames.size();i++)
        {
            if( typenames[i] == name )
            {
                type_id = i;
                break;
            }    
        } 
        return type_id;
    }
    
    
    T* createObject( const String& name)
    {
        T* object = NULL;
        const Functor* functor = getFunctor(name);
        if( functor ) 
        {
            object = (T*)functor->create();
        } 
        else
        {
            std::cout << "Factory Couldn't create a " << name.toUTF8() << std::endl;
        }
        
        return object;
    } 
    
    /**
     Builds a list with the names of all available functors
     */
    size_t getTypeNames( StringArray& names ) const
    {
        for( size_t i=0;i<typenames.size();i++)
        {
            const String& name = typenames[i]; 
            names.add(name);
        } 
        return names.size();
    }
    
    
    Functor       test_functor;
    StringArray   typenames; 
    FunctorArray  functors; 
};

[/code]