#ifndef ERIS_UI_FACTORY_H #define ERIS_UI_FACTORY_H #include #include #include #include namespace Atlas { namespace Objects { namespace Operation { class Create; } namespace Entity { class UIEntity; class Frame; class Slot; } } } namespace Eris { namespace UI { // Element is a virtual class because we expect to // get an inheritance hierarchy like: // // Element // | | // FrameElement MyElement // | | // MyFrameElement // // where MyElement and MyFrameElement are classes // in client-side bindings. There should only be // one Element instance in MyFrameElement, so // we want children of Element to inherit // virtually. /// an instantiated dialog element class Element { public: virtual ~Element() {} // implementations of this function should emit PropertiesChanged for // valid properties virtual void setProperties(const Atlas::Message::Element::MapType&) = 0; void setProperty(const std::string& name, const Atlas::Message::Element& arg) { Atlas::Message::Element::MapType map; map[name] = arg; setProperties(map); } SigC::Signal1 PropertiesChanged; }; class SlotElement : public Element, virtual public SigC::Object { public: virtual void action(const Atlas::Message::Element::MapType&) = 0; }; class FrameElement : virtual public Element { public: ~FrameElement() { for(SlotList::iterator I = _list.begin(); I!= _list.end(); ++I) delete *I; } virtual void pack(Element*) = 0; void packSlot(SlotElement* slot) {_list.push_back(slot);} private: typedef std::list SlotList; SlotList _list; }; class Bindings; class Factory { public: class BaseGen { public: virtual ~BaseGen() {} virtual Element* create(const Atlas::Message::Element::MapType&) = 0; }; template class Gen : public BaseGen { public: virtual Element* create(const Atlas::Message::Element::MapType& attrs) {return E(attrs);} }; Factory(const std::string& id, BaseGen* gen) : _id(id), _gen(gen), _persistent(true), _refcount(1) {_id_list.push_back(id);} virtual ~Factory() {if(_persistent && _gen) delete _gen;} typedef std::map IDMap; // create a dialog element virtual Element* create(IDMap&) const; // create a new factory virtual Factory* parse(const Atlas::Message::Element::MapType&, const Bindings&) const; void ref() {++_refcount;} void unref() {if(--_refcount == 0) delete this;} bool unique() const {return _refcount == 1;} bool persistent() const {return _persistent;} const std::string& id() const {return _id;} protected: typedef std::list IDList; Factory(const Atlas::Objects::Entity::UIEntity&, const std::string&, const IDList&, const Atlas::Message::Element::MapType&, BaseGen*); const Atlas::Message::Element::MapType& attrs() const {return _attrs;} const IDList& idlist() const {return _id_list;} BaseGen* gen() const {return _gen;} private: Factory(const Factory&); Factory& operator=(const Factory&); std::string _id; IDList _id_list; // _id plus all parent ids, for use in connecting slots BaseGen* _gen; bool _persistent; // factories not created by the server unsigned long _refcount; Atlas::Message::Element::MapType _attrs; }; // factory for children of Atlas::Objects::Entity::Frame class FrameFactory : public Factory { public: class BaseGen { public: virtual ~BaseGen() {} virtual FrameElement* create(const std::string& valign, const std::string& halign, const std::string& rel_pos, const Atlas::Message::Element::MapType&) = 0; }; template class Gen : public BaseGen { public: virtual FrameElement* create(const std::string& valign, const std::string& halign, const std::string& rel_pos, const Atlas::Message::Element::MapType& attrs) {return new FE(valign, halign, rel_pos, attrs);} }; FrameFactory(BaseGen* gen) : Factory("frame", 0), _valign("center"), _halign("center"), _rel_pos("right"), _gen(gen) {} virtual ~FrameFactory(); virtual Element* create(IDMap&) const; virtual Factory* parse(const Atlas::Message::Element::MapType&, const Bindings&) const; private: FrameFactory(const Atlas::Objects::Entity::Frame&, const IDList&, const Bindings&, const Atlas::Message::Element::MapType&, BaseGen*); std::string _valign, _halign, _rel_pos; typedef std::list ChildList; ChildList _children; BaseGen* _gen; }; class SlotFactory : public Factory { public: // for the base slot classes SlotFactory(const std::string& id, BaseGen* gen) : Factory(id, gen) {} virtual Element* create(IDMap&) const; virtual Factory* parse(const Atlas::Message::Element::MapType&, const Bindings&) const; const Atlas::Message::Element::ListType& target() const {return _target;} private: SlotFactory(const Atlas::Objects::Entity::Slot&, const IDList&, const Atlas::Message::Element::MapType&, BaseGen*); Atlas::Message::Element::ListType _target; }; /// the dialog generator/handler class Bindings { public: Bindings(); virtual ~Bindings(); void parse(const Atlas::Message::Element&); /// purge all server-generated classes void clear(); Factory* findFactory(const Atlas::Message::Element& id) const { return id.isString() ? findFactory(id.asString()) : 0; } Factory* findFactory(const std::string& id) const { FactoryMap::const_iterator I = _factory_map.find(id); return (I != _factory_map.end()) ? I->second : 0; } bool bind(Factory* f) {return _factory_map.insert( FactoryMap::value_type(f->id(), f)).second;} // a trick to get reasonable syntax for the interface, // e.g. Bind(bindings).slot("foo"); template friend struct Bind { public: Bind(Bindings& b) : _b(b) {} bool slot(const std::string& id) {return _b.bind(new SlotFactory(id, new SlotFactory::Gen()));} bool element(const std::string& id) {return _b.bind(new Factory(id, new Factory::Gen()));} bool frame() {return _b.bind(new FrameFactory(new FrameFactory::Gen()));} private: Bindings& _b; }; // put an Element on the screen as a dialog virtual void display(Element*, const std::string& id) = 0; virtual void createConsoleElement(const Atlas::Objects::Entity::UIEntity&) = 0; private: typedef std::map FactoryMap; FactoryMap _factory_map; }; }} // namespace Eris::UI #endif