From: Mikko Rasa Date: Sun, 25 Apr 2021 11:07:56 +0000 (+0300) Subject: Add a mechanism for collections to be notified when an item is added X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=fbf76ed98dbd2cca6785efe2dd489d717fa5dce6;p=libs%2Fdatafile.git Add a mechanism for collections to be notified when an item is added --- diff --git a/source/collection.cpp b/source/collection.cpp index 6d73063..f86adf6 100644 --- a/source/collection.cpp +++ b/source/collection.cpp @@ -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); diff --git a/source/collection.h b/source/collection.h index 0cd799a..aa3c18a 100644 --- a/source/collection.h +++ b/source/collection.h @@ -104,10 +104,11 @@ public: if(!item) throw std::invalid_argument("Collection::add(item)"); - RefPtr::Type> ptr(item); + typedef typename RemoveConst::Type NCT; + RefPtr ptr(item); try { - insert_unique(items, name, ptr); + add_var(name, get_type(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 bool can_extract() const @@ -412,6 +415,26 @@ private: { return (dynamic_cast(coll).*func)(name); } }; + struct NotifyeeBase + { + virtual ~NotifyeeBase() { } + + virtual void notify(Collection &, const std::string &, T &) const = 0; + }; + + template + 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(coll).*func)(name, item); } + }; + template struct Extractor: CollectionItemTypeBase::Extractor { @@ -420,6 +443,7 @@ private: }; CreatorBase *creat; + std::vector notif; public: CollectionItemType(): @@ -429,6 +453,8 @@ public: ~CollectionItemType() { delete creat; + for(typename std::vector::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 + CollectionItemType ¬ify(void (C::*func)(const std::string &, T &)) + { + notif.push_back(new Notifyee(func)); + return *this; + } + virtual bool is_same_type(const CollectionItemTypeBase &other) const { return dynamic_cast *>(&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 obj = var.value >(); + for(typename std::vector::const_iterator i=notif.begin(); i!=notif.end(); ++i) + (*i)->notify(coll, name, *obj); + } };