]> git.tdb.fi Git - libs/datafile.git/commitdiff
Add a mechanism for collections to be notified when an item is added
authorMikko Rasa <tdb@tdb.fi>
Sun, 25 Apr 2021 11:07:56 +0000 (14:07 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 25 Apr 2021 11:07:56 +0000 (14:07 +0300)
source/collection.cpp
source/collection.h

index 6d7306357712c2b737f9ff5d8232a6888b5daffb..f86adf65c71ace3370e7a57537eaa4fe6cd8243a 100644 (file)
@@ -16,6 +16,13 @@ Collection::~Collection()
                delete *i;
 }
 
+void Collection::add_var(const string &name, const CollectionItemTypeBase *type, const Variant &var)
+{
+       insert_unique(items, name, var);
+       if(type)
+               type->notify_item(*this, name, var);
+}
+
 const Variant &Collection::get_var(const string &name, const CollectionItemTypeBase *type)
 {
        const Variant *var = find_var(name, type);
index 0cd799abf060e399a20c55027371917e14f563c5..aa3c18a0fcc1a5e27f5d4ddc1278b58e65904877 100644 (file)
@@ -104,10 +104,11 @@ public:
                if(!item)
                        throw std::invalid_argument("Collection::add(item)");
 
-               RefPtr<typename RemoveConst<T>::Type> ptr(item);
+               typedef typename RemoveConst<T>::Type NCT;
+               RefPtr<NCT> ptr(item);
                try
                {
-                       insert_unique(items, name, ptr);
+                       add_var(name, get_type<NCT>(name), ptr);
                }
                catch(...)
                {
@@ -153,6 +154,7 @@ public:
        }
 
 private:
+       void add_var(const std::string &, const CollectionItemTypeBase *, const Variant &);
        const Variant &get_var(const std::string &, const CollectionItemTypeBase *);
        const Variant *find_var(const std::string &, const CollectionItemTypeBase *);
 
@@ -363,6 +365,7 @@ public:
        virtual bool can_create() const = 0;
        virtual void create_item(Collection &, const std::string &) const = 0;
        virtual void load_item(Collection &, Parser &, const std::string &) const = 0;
+       virtual void notify_item(Collection &, const std::string &, const Variant &) const = 0;
 
        template<typename T>
        bool can_extract() const
@@ -412,6 +415,26 @@ private:
                { return (dynamic_cast<C &>(coll).*func)(name); }
        };
 
+       struct NotifyeeBase
+       {
+               virtual ~NotifyeeBase() { }
+
+               virtual void notify(Collection &, const std::string &, T &) const = 0;
+       };
+
+       template<typename C>
+       struct Notifyee: NotifyeeBase
+       {
+               typedef void (C::*FuncPtr)(const std::string &, T &);
+
+               FuncPtr func;
+
+               Notifyee(FuncPtr f): func(f) { }
+
+               virtual void notify(Collection &coll, const std::string &name, T &item) const
+               { (dynamic_cast<C &>(coll).*func)(name, item); }
+       };
+
        template<typename B>
        struct Extractor: CollectionItemTypeBase::Extractor<B>
        {
@@ -420,6 +443,7 @@ private:
        };
 
        CreatorBase *creat;
+       std::vector<NotifyeeBase *> notif;
 
 public:
        CollectionItemType():
@@ -429,6 +453,8 @@ public:
        ~CollectionItemType()
        {
                delete creat;
+               for(typename std::vector<NotifyeeBase *>::const_iterator i=notif.begin(); i!=notif.end(); ++i)
+                       delete *i;
        }
 
        /** Sets a datafile keyword for this item type.  The Collection's loader
@@ -472,6 +498,13 @@ public:
                return *this;
        }
 
+       template<typename C>
+       CollectionItemType &notify(void (C::*func)(const std::string &, T &))
+       {
+               notif.push_back(new Notifyee<C>(func));
+               return *this;
+       }
+
        virtual bool is_same_type(const CollectionItemTypeBase &other) const
        { return dynamic_cast<const CollectionItemType<T> *>(&other); }
 
@@ -497,6 +530,13 @@ public:
        {
                throw std::runtime_error("this type cannot be loaded");
        }
+
+       virtual void notify_item(Collection &coll, const std::string &name, const Variant &var) const
+       {
+               RefPtr<T> obj = var.value<RefPtr<T> >();
+               for(typename std::vector<NotifyeeBase *>::const_iterator i=notif.begin(); i!=notif.end(); ++i)
+                       (*i)->notify(coll, name, *obj);
+       }
 };