Eris 1.3.18
UIFactory.h
00001 #ifndef ERIS_UI_FACTORY_H
00002 #define ERIS_UI_FACTORY_H
00003 
00004 #include <Atlas/Message/Element.h>
00005 
00006 #include <sigc++/object.h>
00007 #include <sigc++/signal.h>
00008 
00009 #include <list>
00010 
00011 namespace Atlas {
00012   namespace Objects {
00013     namespace Operation {
00014       class Create;
00015     }
00016     namespace Entity {
00017       class UIEntity;
00018       class Frame;
00019       class Slot;
00020     }
00021   }
00022 }
00023 
00024 namespace Eris { namespace UI {
00025 
00026 // Element is a virtual class because we expect to
00027 // get an inheritance hierarchy like:
00028 //
00029 //              Element
00030 //              |     |
00031 //    FrameElement    MyElement
00032 //              |     |
00033 //           MyFrameElement
00034 //
00035 // where MyElement and MyFrameElement are classes
00036 // in client-side bindings. There should only be
00037 // one Element instance in MyFrameElement, so
00038 // we want children of Element to inherit
00039 // virtually.
00040 
00042 class Element
00043 {
00044  public:
00045   virtual ~Element() {}
00046 
00047   // implementations of this function should emit PropertiesChanged for
00048   // valid properties
00049   virtual void setProperties(const Atlas::Message::Element::MapType&) = 0;
00050 
00051   void setProperty(const std::string& name, const Atlas::Message::Element& arg)
00052   {
00053     Atlas::Message::Element::MapType map;
00054     map[name] = arg;
00055     setProperties(map);
00056   }
00057 
00058   SigC::Signal1<void,const Atlas::Message::Element::MapType&> PropertiesChanged;
00059 };
00060 
00061 class SlotElement : public Element, virtual public SigC::Object
00062 {
00063  public:
00064   virtual void action(const Atlas::Message::Element::MapType&) = 0;
00065 };
00066 
00067 class FrameElement : virtual public Element
00068 {
00069  public:
00070   ~FrameElement()
00071   {
00072     for(SlotList::iterator I = _list.begin(); I!= _list.end(); ++I)
00073      delete *I;
00074   }
00075 
00076   virtual void pack(Element*) = 0;
00077   void packSlot(SlotElement* slot) {_list.push_back(slot);}
00078 
00079  private:
00080   typedef std::list<SlotElement*> SlotList;
00081   SlotList _list;
00082 };
00083 
00084 class Bindings;
00085 
00086 class Factory
00087 {
00088  public:
00089   class BaseGen
00090   {
00091    public:
00092     virtual ~BaseGen() {}
00093     virtual Element* create(const Atlas::Message::Element::MapType&) = 0;
00094   };
00095 
00096   template<class E>
00097   class Gen : public BaseGen
00098   {
00099    public:
00100     virtual Element* create(const Atlas::Message::Element::MapType& attrs)
00101                 {return E(attrs);}
00102   };
00103 
00104   Factory(const std::string& id, BaseGen* gen)
00105         : _id(id), _gen(gen), _persistent(true), _refcount(1)
00106         {_id_list.push_back(id);}
00107   virtual ~Factory() {if(_persistent && _gen) delete _gen;}
00108 
00109   typedef std::map<std::string,Element*> IDMap;
00110 
00111   // create a dialog element
00112   virtual Element* create(IDMap&) const;
00113   // create a new factory
00114   virtual Factory* parse(const Atlas::Message::Element::MapType&, const Bindings&) const;
00115 
00116   void ref() {++_refcount;}
00117   void unref() {if(--_refcount == 0) delete this;}
00118   bool unique() const {return _refcount == 1;}
00119   bool persistent() const {return _persistent;}
00120   const std::string& id() const {return _id;}
00121 
00122  protected:
00123   typedef std::list<std::string> IDList;
00124 
00125   Factory(const Atlas::Objects::Entity::UIEntity&, const std::string&,
00126           const IDList&, const Atlas::Message::Element::MapType&, BaseGen*);
00127 
00128   const Atlas::Message::Element::MapType& attrs() const {return _attrs;}
00129   const IDList& idlist() const {return _id_list;}
00130   BaseGen* gen() const {return _gen;}
00131 
00132  private:
00133   Factory(const Factory&);
00134   Factory& operator=(const Factory&);
00135 
00136   std::string _id;
00137   IDList _id_list; // _id plus all parent ids, for use in connecting slots
00138   BaseGen* _gen;
00139   bool _persistent; // factories not created by the server
00140   unsigned long _refcount;
00141   Atlas::Message::Element::MapType _attrs;
00142 };
00143 
00144 // factory for children of Atlas::Objects::Entity::Frame
00145 class FrameFactory : public Factory
00146 {
00147  public:
00148   class BaseGen
00149   {
00150    public:
00151     virtual ~BaseGen() {}
00152     virtual FrameElement* create(const std::string& valign,
00153         const std::string& halign, const std::string& rel_pos,
00154         const Atlas::Message::Element::MapType&) = 0;
00155   };
00156   template<class FE>
00157   class Gen : public BaseGen
00158   {
00159    public:
00160     virtual FrameElement* create(const std::string& valign,
00161         const std::string& halign, const std::string& rel_pos,
00162         const Atlas::Message::Element::MapType& attrs)
00163                 {return new FE(valign, halign, rel_pos, attrs);}
00164   };
00165 
00166 
00167   FrameFactory(BaseGen* gen) : Factory("frame", 0), _valign("center"),
00168         _halign("center"), _rel_pos("right"), _gen(gen) {}
00169   virtual ~FrameFactory();
00170 
00171   virtual Element* create(IDMap&) const;
00172   virtual Factory* parse(const Atlas::Message::Element::MapType&, const Bindings&) const;
00173 
00174  private:
00175   FrameFactory(const Atlas::Objects::Entity::Frame&, const IDList&,
00176                const Bindings&, const Atlas::Message::Element::MapType&, BaseGen*);
00177 
00178   std::string _valign, _halign, _rel_pos;
00179   typedef std::list<Factory*> ChildList;
00180   ChildList _children;
00181   BaseGen* _gen;
00182 };
00183 
00184 class SlotFactory : public Factory
00185 {
00186  public:
00187   // for the base slot classes
00188   SlotFactory(const std::string& id, BaseGen* gen) : Factory(id, gen) {}
00189 
00190   virtual Element* create(IDMap&) const;
00191   virtual Factory* parse(const Atlas::Message::Element::MapType&, const Bindings&) const;
00192 
00193   const Atlas::Message::Element::ListType& target() const {return _target;}
00194 
00195  private:
00196   SlotFactory(const Atlas::Objects::Entity::Slot&, const IDList&,
00197               const Atlas::Message::Element::MapType&, BaseGen*);
00198 
00199   Atlas::Message::Element::ListType _target;
00200 };
00201 
00203 class Bindings
00204 {
00205  public:
00206   Bindings();
00207   virtual ~Bindings();
00208 
00209   void parse(const Atlas::Message::Element&);
00210 
00212   void clear();
00213 
00214   Factory* findFactory(const Atlas::Message::Element& id) const
00215   {
00216     return id.isString() ? findFactory(id.asString()) : 0;
00217   }
00218 
00219   Factory* findFactory(const std::string& id) const
00220   {
00221     FactoryMap::const_iterator I = _factory_map.find(id);
00222     return (I != _factory_map.end()) ? I->second : 0;
00223   }
00224 
00225   bool bind(Factory* f) {return _factory_map.insert(
00226         FactoryMap::value_type(f->id(), f)).second;}
00227 
00228   // a trick to get reasonable syntax for the interface,
00229   // e.g. Bind<Foo>(bindings).slot("foo");
00230   template<class C>
00231   friend struct Bind
00232   {
00233    public:
00234     Bind(Bindings& b) : _b(b) {}
00235 
00236     bool slot(const std::string& id)
00237         {return _b.bind(new SlotFactory(id, new SlotFactory::Gen<C>()));}
00238     bool element(const std::string& id)
00239         {return _b.bind(new Factory(id, new Factory::Gen<C>()));}
00240     bool frame()
00241         {return _b.bind(new FrameFactory(new FrameFactory::Gen<C>()));}
00242    private:
00243     Bindings& _b;
00244   };
00245 
00246   // put an Element on the screen as a dialog
00247   virtual void display(Element*, const std::string& id) = 0;
00248 
00249   virtual void createConsoleElement(const Atlas::Objects::Entity::UIEntity&) = 0;
00250 
00251  private:
00252 
00253  typedef std::map<std::string,Factory*> FactoryMap;
00254  FactoryMap _factory_map;
00255 };
00256 
00257 }} // namespace Eris::UI
00258 
00259 #endif