]> git.mxchange.org Git - simgear.git/commitdiff
PropertyBasedElement: extend HTML5 (Canvas) data props interface
authorThomas Geymayer <tomgey@gmail.com>
Wed, 28 May 2014 22:29:12 +0000 (00:29 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Wed, 28 May 2014 23:22:35 +0000 (01:22 +0200)
Allow check if property exists and removing properties.

simgear/canvas/elements/CanvasElement.cxx
simgear/canvas/elements/CanvasElement.hxx
simgear/canvas/elements/canvas_element_test.cpp
simgear/props/PropertyBasedElement.cxx
simgear/props/PropertyBasedElement.hxx
simgear/props/props.cxx
simgear/props/props.hxx

index 1c506fbc6d002e68d812860e75fab6482363efe7..61239d4dffba726907c6a7132b29c37a84febd9c 100644 (file)
@@ -635,74 +635,6 @@ namespace canvas
     return m;
   }
 
-  //----------------------------------------------------------------------------
-  static const std::string DATA_PREFIX("data-");
-
-  //----------------------------------------------------------------------------
-  std::string Element::dataPropToAttrName(const std::string& name)
-  {
-    // http://www.w3.org/TR/html5/dom.html#attr-data-*
-    //
-    // 3. Insert the string data- at the front of name.
-
-    std::string attr_name;
-    for( std::string::const_iterator cur = name.begin();
-                                     cur != name.end();
-                                   ++cur )
-    {
-      // If name contains a "-" (U+002D) character followed by a lowercase ASCII
-      // letter, throw a SyntaxError exception and abort these steps.
-      if( *cur == '-' )
-      {
-        std::string::const_iterator next = cur + 1;
-        if( next != name.end() && islower(*next) )
-          return std::string();
-      }
-
-      // For each uppercase ASCII letter in name, insert a "-" (U+002D)
-      // character before the character and replace the character with the same
-      // character converted to ASCII lowercase.
-      if( isupper(*cur) )
-      {
-        attr_name.push_back('-');
-        attr_name.push_back( tolower(*cur) );
-      }
-      else
-        attr_name.push_back( *cur );
-    }
-    return DATA_PREFIX + attr_name;
-  }
-
-  //----------------------------------------------------------------------------
-  std::string Element::attrToDataPropName(const std::string& name)
-  {
-    // http://www.w3.org/TR/html5/dom.html#attr-data-*
-    //
-    // For each "-" (U+002D) character in the name that is followed by a
-    // lowercase ASCII letter, remove the "-" (U+002D) character and replace the
-    // character that followed it by the same character converted to ASCII
-    // uppercase.
-
-    if( !boost::starts_with(name, DATA_PREFIX) )
-      return std::string();
-
-    std::string data_name;
-    for( std::string::const_iterator cur = name.begin() + DATA_PREFIX.length();
-                                     cur != name.end();
-                                   ++cur )
-    {
-      std::string::const_iterator next = cur + 1;
-      if( *cur == '-' && next != name.end() && islower(*next) )
-      {
-        data_name.push_back( toupper(*next) );
-        cur = next;
-      }
-      else
-        data_name.push_back(*cur);
-    }
-    return data_name;
-  }
-
   //----------------------------------------------------------------------------
   Element::StyleSetters Element::_style_setters;
 
index 73a184726e2150f53af533f013baf6a4aae6a869..87548c68d4108edf25ce713e189603abcdc76409 100644 (file)
@@ -107,30 +107,6 @@ namespace canvas
       bool addEventListener(const std::string& type, const EventListener& cb);
       virtual void clearEventListener();
 
-      template<class T>
-      void setDataProp( const std::string& name,
-                        const T& val )
-      {
-        const std::string& attr = dataPropToAttrName(name);
-        if( !attr.empty() )
-          set<T>(attr, val);
-        else
-          SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name);
-      }
-
-      template<class T>
-      T getDataProp( const std::string& name,
-                     const T& def = T() )
-      {
-        const std::string& attr = dataPropToAttrName(name);
-        if( !attr.empty() )
-          return get<T>(attr, def);
-        else
-          SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name);
-
-        return def;
-      }
-
       virtual bool accept(EventVisitor& visitor);
       virtual bool ascend(EventVisitor& visitor);
       virtual bool traverse(EventVisitor& visitor);
@@ -228,9 +204,6 @@ namespace canvas
         return ElementPtr( new Derived(canvas, node, style, parent) );
       }
 
-      static std::string dataPropToAttrName(const std::string& name);
-      static std::string attrToDataPropName(const std::string& name);
-
     protected:
 
       enum Attributes
index fe3c2ee75b7722a7fc7f21997bef20fa010018c3..444af4c17520847538a476ed8d3da13fc3c79254 100644 (file)
@@ -51,4 +51,16 @@ BOOST_AUTO_TEST_CASE( attr_data )
   el->setDataProp("myData", 3);
   BOOST_CHECK_EQUAL( el->getDataProp<int>("myData"), 3 );
   BOOST_CHECK_EQUAL( node->getIntValue("data-my-data"), 3 );
+
+  SGPropertyNode* prop = el->getDataProp<SGPropertyNode*>("notExistingProp");
+  BOOST_CHECK( !prop );
+  prop = el->getDataProp<SGPropertyNode*>("myData");
+  BOOST_CHECK(  prop );
+  BOOST_CHECK_EQUAL( prop->getParent(), node );
+  BOOST_CHECK_EQUAL( prop->getIntValue(), 3 );
+
+  BOOST_CHECK( el->hasDataProp("myData") );
+  el->removeDataProp("myData");
+  BOOST_CHECK( !el->hasDataProp("myData") );
+  BOOST_CHECK_EQUAL( el->getDataProp("myData", 5), 5 );
 }
index 855829c7769d8ff01e8fadae64b5c1fba51d63d9..348842b9142342eb979286eb03ab1d4755cb33b9 100644 (file)
@@ -17,6 +17,7 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
 
 #include "PropertyBasedElement.hxx"
+#include <boost/algorithm/string/predicate.hpp>
 
 namespace simgear
 {
@@ -65,4 +66,86 @@ namespace simgear
     return _node;
   }
 
+  //----------------------------------------------------------------------------
+  bool PropertyBasedElement::hasDataProp(const std::string& name) const
+  {
+    return getDataProp<SGPropertyNode*>(name) != NULL;
+  }
+
+  //----------------------------------------------------------------------------
+  void PropertyBasedElement::removeDataProp(const std::string& name)
+  {
+    SGPropertyNode* node = getDataProp<SGPropertyNode*>(name);
+    if( node )
+      _node->removeChild(node);
+  }
+
+  //----------------------------------------------------------------------------
+  static const std::string DATA_PREFIX("data-");
+
+  //----------------------------------------------------------------------------
+  std::string PropertyBasedElement::dataPropToAttrName(const std::string& name)
+  {
+    // http://www.w3.org/TR/html5/dom.html#attr-data-*
+    //
+    // 3. Insert the string data- at the front of name.
+
+    std::string attr_name;
+    for( std::string::const_iterator cur = name.begin();
+                                     cur != name.end();
+                                   ++cur )
+    {
+      // If name contains a "-" (U+002D) character followed by a lowercase ASCII
+      // letter, throw a SyntaxError exception and abort these steps.
+      if( *cur == '-' )
+      {
+        std::string::const_iterator next = cur + 1;
+        if( next != name.end() && islower(*next) )
+          return std::string();
+      }
+
+      // For each uppercase ASCII letter in name, insert a "-" (U+002D)
+      // character before the character and replace the character with the same
+      // character converted to ASCII lowercase.
+      if( isupper(*cur) )
+      {
+        attr_name.push_back('-');
+        attr_name.push_back( tolower(*cur) );
+      }
+      else
+        attr_name.push_back( *cur );
+    }
+    return DATA_PREFIX + attr_name;
+  }
+
+  //----------------------------------------------------------------------------
+  std::string PropertyBasedElement::attrToDataPropName(const std::string& name)
+  {
+    // http://www.w3.org/TR/html5/dom.html#attr-data-*
+    //
+    // For each "-" (U+002D) character in the name that is followed by a
+    // lowercase ASCII letter, remove the "-" (U+002D) character and replace the
+    // character that followed it by the same character converted to ASCII
+    // uppercase.
+
+    if( !boost::starts_with(name, DATA_PREFIX) )
+      return std::string();
+
+    std::string data_name;
+    for( std::string::const_iterator cur = name.begin() + DATA_PREFIX.length();
+                                     cur != name.end();
+                                   ++cur )
+    {
+      std::string::const_iterator next = cur + 1;
+      if( *cur == '-' && next != name.end() && islower(*next) )
+      {
+        data_name.push_back( toupper(*next) );
+        cur = next;
+      }
+      else
+        data_name.push_back(*cur);
+    }
+    return data_name;
+  }
+
 } // namespace simgear
index dcaceaf028724b92e93973f19aed4552bb4826d4..52af9b30bb79fcd3cc033edf3823be011d1af6fe 100644 (file)
@@ -76,8 +76,102 @@ namespace simgear
       // Unshadow what we have just hidden...
       using SGWeakReferenced::get;
 
+
+      /** @brief Set a HTML5 like data property on this element.
+       *
+       * Set data-* properties on this element. A camel-case @a name will be
+       * converted to a hyphenated name with 'data-' prefixed. Setting a value
+       * with this method does not trigger an update of the canvas and is meant
+       * to store data related to this element (used eg. inside scripts).
+       *
+       * @code{cpp}
+       * // Set value
+       * my_element->setDataProp("mySpecialInt", 3);
+       *
+       * // Get value (with default value)
+       * int val = my_element->getDataProp<int>("mySpecialInt");   // val == 3
+       *     val = my_element->getDataProp<int>("notExisting", 5); // val == 5
+       *
+       * // Check if value exists
+       * SGPropertyNode* node =
+       *   my_element->getDataProp<SGPropertyNode*>("mySpecialInt");
+       * if( node )
+       *   val = node->getIntValue(); // node != NULL, val == 3
+       *
+       * node = my_element->getDataProp<SGPropertyNode*>("notExisting");
+       * // node == NULL
+       * @endcode
+       */
+      template<class T>
+      void setDataProp( const std::string& name,
+                        const T& val )
+      {
+        const std::string& attr = dataPropToAttrName(name);
+        if( !attr.empty() )
+          set<T>(attr, val);
+        else
+          SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name);
+      }
+
+      /** @brief Get a HTML5 like data property on this element.
+       *
+       * Get value or default value.
+       *
+       * @see setDataProp
+       */
+      template<class T>
+      typename boost::disable_if<
+        boost::is_same<T, SGPropertyNode*>,
+        T
+      >::type getDataProp( const std::string& name,
+                           const T& def = T() ) const
+      {
+        SGPropertyNode* node = getDataProp<SGPropertyNode*>(name);
+        if( node )
+          return getValue<T>(node);
+
+        return def;
+      }
+
+      /** @brief Get a HTML5 like data property on this element.
+       *
+       * Use this variant to check if a property exists.
+       *
+       * @see setDataProp
+       */
+      template<class T>
+      typename boost::enable_if<
+        boost::is_same<T, SGPropertyNode*>,
+        T
+      >::type getDataProp( const std::string& name,
+                           SGPropertyNode* = NULL ) const
+      {
+        const std::string& attr = dataPropToAttrName(name);
+        if( attr.empty() )
+        {
+          SG_LOG(SG_GENERAL, SG_WARN, "Invalid data-prop name: " << name);
+          return NULL;
+        }
+
+        return _node->getNode(attr);
+      }
+
+      /** @brief Check whether a HTML5 like data property exists on this
+       *         element.
+       *
+       */
+      bool hasDataProp(const std::string& name) const;
+
+      /** @brief Remove a HTML5 like data property (if it exists).
+       *
+       */
+      void removeDataProp(const std::string& name);
+
       virtual void onDestroy() {};
 
+      static std::string dataPropToAttrName(const std::string& name);
+      static std::string attrToDataPropName(const std::string& name);
+
     protected:
 
       SGPropertyNode_ptr _node;
index d9c90a33c814a09815703588b42ed6ae5d2033f4..6d7047223ed58d49f14dc3a0162eb08d44b8842f 100644 (file)
@@ -1002,26 +1002,28 @@ SGPropertyNode::getChildren (const char * name) const
   return children;
 }
 
+//------------------------------------------------------------------------------
+bool SGPropertyNode::removeChild(SGPropertyNode* node)
+{
+  if( node->_parent != this )
+    return false;
 
-/**
- * Remove child by position.
- */
-SGPropertyNode_ptr
-SGPropertyNode::removeChild(int pos)
+  PropertyList::iterator it =
+    std::find(_children.begin(), _children.end(), node);
+  if( it == _children.end() )
+    return false;
+
+  eraseChild(it);
+  return true;
+}
+
+//------------------------------------------------------------------------------
+SGPropertyNode_ptr SGPropertyNode::removeChild(int pos)
 {
-  SGPropertyNode_ptr node;
   if (pos < 0 || pos >= (int)_children.size())
-    return node;
-
-  PropertyList::iterator it = _children.begin();
-  it += pos;
-  node = _children[pos];
-  _children.erase(it);
+    return SGPropertyNode_ptr();
 
-  node->setAttribute(REMOVED, true);
-  node->clearValue();
-  fireChildRemoved(node);
-  return node;
+  return eraseChild(_children.begin() + pos);
 }
 
 
@@ -2250,6 +2252,19 @@ SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
     _parent->fireChildRemoved(parent, child);
 }
 
+//------------------------------------------------------------------------------
+SGPropertyNode_ptr
+SGPropertyNode::eraseChild(simgear::PropertyList::iterator child)
+{
+  SGPropertyNode_ptr node = *child;
+  node->setAttribute(REMOVED, true);
+  node->clearValue();
+  fireChildRemoved(node);
+
+  _children.erase(child);
+  return node;
+}
+
 ////////////////////////////////////////////////////////////////////////
 // Implementation of SGPropertyChangeListener.
 ////////////////////////////////////////////////////////////////////////
index c9e7c05d2fa48eb0d89a6c3ccffbd4566065e43f..59a8a43f1b17829c5f27a54446a6b49930f8996e 100644 (file)
@@ -911,6 +911,13 @@ public:
   simgear::PropertyList getChildren (const std::string& name) const
   { return getChildren(name.c_str()); }
 
+  /**
+   * Remove child by pointer (if it is a child of this node).
+   *
+   * @return true, if the node was deleted.
+   */
+  bool removeChild(SGPropertyNode* node);
+
   // TODO do we need the removeXXX methods to return the deleted nodes?
   /**
    * Remove child by position.
@@ -1701,6 +1708,8 @@ protected:
   void fireChildAdded (SGPropertyNode * parent, SGPropertyNode * child);
   void fireChildRemoved (SGPropertyNode * parent, SGPropertyNode * child);
 
+  SGPropertyNode_ptr eraseChild(simgear::PropertyList::iterator child);
+
   /**
    * Protected constructor for making new nodes on demand.
    */