objtree.h

Go to the documentation of this file.
00001 /*
00002  * objtree.h
00003  * 
00004  * Copyright (C) 2006,2008  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 #ifndef WAVEPACKET_OBJTREE_H__
00032 #define WAVEPACKET_OBJTREE_H__
00033 
00034 
00035 // includes --------------------------------------------------------------------
00036 #include "common/common.h"
00037 #include "datahash/datahash.h"
00038 
00039 /// \ingroup general
00040 /*@{*/
00041 
00042 ////////////////////////////////////////////////////////////////////////////////
00043 ///
00044 /// \defgroup objtree Object Tree API
00045 ///
00046 /// API for manipulating hierarchical trees of objects + properties.
00047 ///
00048 /// This is typically used by UI applications when the user has selected a
00049 /// number of different object, and then wants to see/edit properties.  This
00050 /// low-level API abstracts the general (hierarchical) set of objects.
00051 ///
00052 ////////////////////////////////////////////////////////////////////////////////
00053 
00054 /*@{*/
00055 
00056 
00057 namespace objtree {
00058 
00059 
00060 /// returns true if the given name is an acceptable property name
00061 ///
00062 /// property names are very restricted!  alphanumerics and hyphens only
00063 ///  goal is names that do not need to be URL encoded etc
00064 bool isValidPropertyName(IN const char * candidate_name) throw();
00065 
00066 
00067 /// abstraction of a general property of an object
00068 ///
00069 /// This attempts to capture the metadata around a property.  For instance,
00070 /// the user may have selected a rectangle, and they want the properties of
00071 /// the rectangle.  A single property of the rectangle (for instance the
00072 /// line color) will be generally represented by this.  The "value" of the
00073 /// property is the line color (red, black, whatever).  But there could be
00074 /// other metadata fields such as the property type (it is a color, not a
00075 /// weight or length etc.).  It could have units (lengths could be measured
00076 /// in meters or miles, etc.).  And so on.
00077 ///
00078 /// There are multiple
00079 ///     possible metadata fields (up to the client), such as the type (string?
00080 ///     float?  int?  color?), units (centimeters?  miles?  liters?) etc.
00081 ///
00082 /// There is one "special" property, the value.  All property_t objects are
00083 ///     required to have a value entry, albeit empty.  All other fields may
00084 ///     not exist (and getFieldValue() can return null for those).  But
00085 ///     clients can rely on getValue() returning non-null at least.
00086 struct property_t : public Dictionary {
00087         // constructor, manipulators
00088         property_t(IN const char * in_value) {
00089                         ASSERT(in_value, "null input value");
00090                         this->setValue(in_value);
00091                 }
00092         property_t(void) throw() { this->clear(); }
00093 
00094         void clear(void) throw() {
00095                         Dictionary::clear();
00096                         this->setValue(NULL);
00097                 }
00098 
00099         void setFieldValue(IN const char * field, IN const char * value) {
00100                         ASSERT(field, "null field");
00101                         ASSERT(value, "null value");
00102                         ASSERT(strcmp(field, "name"),
00103                             "'name' is a reserved property field value");
00104                         this->operator[](field) = value;
00105                 }
00106 
00107         const char * getFieldValue(IN const char * field) const throw() {
00108                         ASSERT(field, "null field");
00109                         Dictionary::const_iterator i = this->find(field);
00110                         if (this->end() == i)
00111                                 return NULL;            // field not found
00112                         return i->second.c_str();
00113                 }
00114 
00115         const char * getOptionalFieldValue(IN const char * field,
00116                                 IN const char * default_value) const throw() {
00117                         const char * val = this->getFieldValue(field);
00118                         return (val) ? val : default_value;
00119                 }
00120 
00121         void setValue(IN const char * value) throw() {
00122                         if (!value)
00123                                 value = "";
00124                         this->setFieldValue("value", value);
00125                 }
00126 
00127         const char * getValue(void) const throw() {
00128                         return this->getFieldValue("value");
00129                 }
00130 
00131         void dump(IN const char * title) const throw();
00132 };
00133 
00134 
00135 
00136 /// a set of properties.
00137 ///
00138 /// For instance, a rectangle object could have a propert set which contained
00139 /// a property "line_color", "line_style", "fill_color", etc.
00140 struct property_set_t : public std::map<std::string, property_t> {
00141         // manipulators
00142         void addProperty(IN const char * name,
00143                                 IN const char * value) {
00144                         ASSERT(isValidPropertyName(name),
00145                             "Bad property name: '%s'", name);
00146                         (*this)[name] = property_t(value);
00147                 }
00148 
00149         property_t * getProperty(IN const char * name) throw() {
00150                         ASSERT(isValidPropertyName(name),
00151                             "Bad property name: '%s'", name);
00152                         property_set_t::iterator i = this->find(name);
00153                         if (this->end() == i)
00154                                 return NULL;    // property not found
00155                         return &i->second;
00156                 }
00157 
00158         const property_t * getProperty(IN const char * name) const throw() {
00159                         ASSERT(isValidPropertyName(name),
00160                             "Bad property name: '%s'", name);
00161                         property_set_t::const_iterator i = this->find(name);
00162                         if (this->end() == i)
00163                                 return NULL;    // property not found
00164                         return &i->second;
00165                 }
00166 
00167         const char * getValue(IN const char * name) const throw() {
00168                         ASSERT(isValidPropertyName(name),
00169                             "Bad property name: '%s'", name);
00170                         const property_t * p = this->getProperty(name);
00171                         if (!p)
00172                                 return NULL;    // not found
00173                         return p->getValue();
00174                 }
00175 
00176         const char * getOptionalValue(IN const char * name,
00177                                 IN const char * default_value) const throw() {
00178                         const char * value = this->getValue(name);
00179                         return value ? value : default_value;
00180                 }
00181 
00182         void dump(IN const char * title) const throw();
00183 };
00184 
00185 
00186 
00187 ////////////////////////////////////////////////////////////////////////////////
00188 ///
00189 ///     How you interact with this object is the key to the objtree library.
00190 ///
00191 ///     You can add and remove objects by their (client-specified) ID.
00192 ///
00193 ///     You can then iteract with multiple objects at once by specifying the
00194 ///     targets as an id_query rather than a single ID.  For instance, you could
00195 ///     call
00196 /// \code
00197 ///     list->setProperties("*", my_property_set);
00198 /// \endcode
00199 ///     which would update that property for all objects in the list, provided
00200 ///     they already had a property of that name.
00201 ///
00202 ///     NOTE: query support is a bit limited.  At the moment you can only use
00203 ///     a specific ID, or the query "*" which specifies all IDs in the list.
00204 ///     Better query support could obviously be added but I haven't needed it.
00205 ///
00206 ////////////////////////////////////////////////////////////////////////////////
00207 class List {
00208 public:
00209         // virtual destructor --------------------------------------------------
00210         virtual ~List(void) throw();
00211 
00212         // objtree::List class interface methods -------------------------------
00213         virtual bool addObject(IN const char * id) = 0;
00214         virtual bool removeObject(IN const char * id) = 0;
00215         virtual void getObjects(IN const char * id_query,
00216                                 OUT VecString& ids) = 0;
00217 
00218         /// getProperties -- retrieves properties common to all objects
00219         virtual void getProperties(IN const char * id_query,
00220                                 OUT property_set_t& pset) = 0;
00221 
00222         /// addProperties -- adds if necessary, sets all properties on all objs
00223         virtual void addProperties(IN const char * id_query,
00224                                 IN const property_set_t& pset) = 0;
00225 
00226         /// setProperties -- sets properties only if exists + matches on object
00227         virtual void setProperties(IN const char * id_query,
00228                                 IN const property_set_t& pset) = 0;
00229 
00230         // public static methods (factories) -----------------------------------
00231         static smart_ptr<List> create(void);
00232 };
00233 
00234 
00235 
00236 /// the root object for discovering objects
00237 ///
00238 /// Why isn't this recursive?  Because the lists already contain recursive
00239 /// structure (you can use nested object IDs and treat them as paths).
00240 ///
00241 /// So the List could properly be described as a Tree, and this is really a
00242 /// Forest.
00243 class Tree {
00244 public:
00245         // virtual destructor --------------------------------------------------
00246         virtual ~Tree(void) throw();
00247 
00248         // objtree::Tree class interface methods -------------------------------
00249         /// return the list (and create if no list exists yet by that name)
00250         virtual List * getList(IN const char * name) = 0;
00251 
00252         /// return names of all lists
00253         virtual void getListNames(OUT VecString& names) = 0;
00254 
00255         // public static methods (factories) -----------------------------------
00256         static smart_ptr<Tree> create(void);
00257 };
00258 
00259 
00260 
00261 ////////////////////////////////////////////////////////////////////////////////
00262 //
00263 //      helper methods
00264 //
00265 ////////////////////////////////////////////////////////////////////////////////
00266 
00267 bool isTrue(IN const char * text) throw();
00268 
00269 /// given a property set, serialize into a datahash object
00270 smart_ptr<Datahash> getDatahash(IN const property_set_t& pset);
00271 
00272 /// given a datahash, deserialize into a property set
00273 void getPropertySet(IN const Datahash * hash,
00274                                 OUT property_set_t& pset);
00275 
00276 
00277 };      // objtree namespace
00278 
00279 #endif  // WAVEPACKET_OBJTREE_H__
00280