+ /// Gets a descriptor with the same type as another descriptor.
+ CollectionItemTypeBase *get_type(const CollectionItemTypeBase &) const;
+
+ /// Returns the descriptor for an item, or null if it's of an unknown type.
+ CollectionItemTypeBase *get_type_for_item(const Variant &) const;
+
+protected:
+ /** Adds a source for automatically loading items. Sources are consulted
+ in the order they are added. */
+ void add_source(const CollectionSource &);
+
+public:
+ /** Opens a raw resource, without interpreting it as object data. Null is
+ returned if no such file is found. The caller must dispose of the returned
+ object when done with it. */
+ IO::Seekable *open_raw(const std::string &) const;
+
+protected:
+ IO::Seekable *open_from_sources(const std::string &n) { return open_raw(n); }
+
+private:
+ void gather_names_from_sources(std::list<std::string> &, const CollectionItemTypeBase &) const;
+
+ void load_items_from_sources(const CollectionItemTypeBase &);
+
+protected:
+ /** Sets a fallback collection, which will be consulted if an item is not
+ found. */
+ void set_fallback(Collection *);
+
+ Collection *get_fallback() const { return fallback; }
+};
+
+template<typename T>
+class Collection::ItemLoader<T, false>: public T::Loader
+{
+public:
+ ItemLoader(T &o, Collection &):
+ T::Loader(o)
+ { }
+};
+
+template<typename T>
+class Collection::ItemLoader<T, true>: public T::Loader
+{
+public:
+ ItemLoader(T &o, Collection &c):
+ T::Loader(o, dynamic_cast<typename T::Loader::Collection &>(c))
+ { }
+};
+
+
+class CollectionItemTypeBase
+{
+protected:
+ struct ExtractorBase
+ {
+ virtual ~ExtractorBase() { }
+ };
+
+ template<typename T>
+ struct Extractor: ExtractorBase
+ {
+ virtual T &extract(const Variant &) const = 0;
+ };
+
+ std::string kwd;
+ std::vector<std::string> suffixes;
+ std::vector<ExtractorBase *> extractors;
+
+ CollectionItemTypeBase() { }
+public:
+ virtual ~CollectionItemTypeBase();
+
+ void set_keyword(const std::string &);
+ const std::string &get_keyword() const { return kwd; }
+ void add_suffix(const std::string &);
+ bool match_name(const std::string &) const;
+ virtual bool is_same_type(const CollectionItemTypeBase &) const = 0;
+ virtual bool check_item_type(const Variant &) const = 0;
+ virtual void add_to_loader(Collection::Loader &) const = 0;
+ 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;
+
+ template<typename T>
+ bool can_extract() const
+ {
+ for(std::vector<ExtractorBase *>::const_iterator i=extractors.begin(); i!=extractors.end(); ++i)
+ if(dynamic_cast<Extractor<T> *>(*i))
+ return true;
+ return false;
+ }
+
+ template<typename T>
+ T *extract(const Variant &var) const
+ {
+ for(std::vector<ExtractorBase *>::const_iterator i=extractors.begin(); i!=extractors.end(); ++i)
+ if(Extractor<T> *ex = dynamic_cast<Extractor<T> *>(*i))
+ return &ex->extract(var);
+ return 0;
+ }
+};
+
+
+/**
+Describes a type of item that can be loaded by a Collection. These are created
+by Collection::add_type.
+*/
+template<typename T>
+class CollectionItemType: public CollectionItemTypeBase
+{
+private:
+ struct CreatorBase
+ {
+ virtual ~CreatorBase() { }
+
+ virtual T *create(Collection &, const std::string &) const = 0;
+ };
+
+ template<typename C>
+ struct Creator: CreatorBase
+ {
+ typedef T *(C::*FuncPtr)(const std::string &);
+
+ FuncPtr func;
+
+ Creator(FuncPtr f): func(f) { }
+
+ virtual T *create(Collection &coll, const std::string &name) const
+ { return (dynamic_cast<C &>(coll).*func)(name); }
+ };
+
+ template<typename B>
+ struct Extractor: CollectionItemTypeBase::Extractor<B>
+ {
+ virtual B &extract(const Variant &var) const
+ { return *var.value<RefPtr<T> >(); }
+ };
+
+ CreatorBase *creat;
+
+public:
+ CollectionItemType():
+ creat(0)
+ { }
+
+ ~CollectionItemType()
+ {
+ delete creat;
+ }
+
+ /** Sets a datafile keyword for this item type. The Collection's loader
+ will accept a statement with this keyword and a single string argument - the
+ item's name. */
+ CollectionItemType &keyword(const std::string &k)
+ {
+ set_keyword(k);
+ return *this;
+ }