<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.6  2000/02/10 20:19:24  abagchi
 * Added docs for equality operators
 *
 * Revision 1.5  2000/02/06 07:47:30  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.4  2000/02/04 01:49:28  aruna1
 * TreeWalker and NodeIterator changes
 *
 * Revision 1.3  2000/01/22 01:38:29  andyh
 * Remove compiler warnings in DOM impl classes
 *
 * Revision 1.2  2000/01/05 01:16:07  andyh
 * DOM Level 2 core, namespace support added.
 *
 * Revision 1.1.1.1  1999/11/09 01:08:59  twl
 * Initial checkin
 *
 * Revision 1.3  1999/11/08 20:44:18  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

#ifndef DOM_NamedNodeMap_HEADER_GUARD_
#define DOM_NamedNodeMap_HEADER_GUARD_

#include <util/XML4CDefs.hpp>

#include <dom/DOM_Node.hpp>
class NamedNodeMapImpl;

/**
*  NamedNodeMaps  are used to
* represent collections of nodes that can be accessed by name.
*
* Note that NamedNodeMap does not inherit from NodeList;
* NamedNodeMaps are not maintained in any particular order.
* Nodes contained in a NamedNodeMap may
* also be accessed by an ordinal index, but this is simply to allow
* convenient enumeration of the contents, and
* does not imply that the DOM specifies an order to these Nodes.
*/
class CDOM_EXPORT DOM_NamedNodeMap {
private:
    NamedNodeMapImpl        *fImpl;

public:
    /** @name Constructors and assignment operator */
    //@{
    /**
      * Default constructor for DOM_NamedNodeMap.  The resulting object does not
      * refer to an actual DOM_NamedNodeMap node; it will compare == to 0, and is similar
      * to a null object reference variable in Java. NamedNopes are instantiated
      * by these methods:  DOM_Node::getAttributes, DOM_DocumentType::getEntities
      * andDOM_DocumentType::getNotations
      *
      */
    DOM_NamedNodeMap();

    /**
      * Copy constructor.  Creates a new DOM_NamedNodeMap reference object
      * that refers to the same underlying NamedNodeMap as the original.
      *
      * @param other The object to be copied.
      */
    DOM_NamedNodeMap(const DOM_NamedNodeMap &other);

    /**
      * Assignment operator.
      *
      * @param other The object to be copied.
      */
    DOM_NamedNodeMap & operator = (const DOM_NamedNodeMap &other);
    DOM_NamedNodeMap & operator = (const DOM_NullPtr *other);

    //@}
    /** @name Destructor. */
    //@{
    /**
      * Destructor for DOM_NamedNodeMap.  The object being destroyed is the reference
      * object, not the underlying NamedNodeMap itself.
      *
      *
Like most other DOM types in this implementation, memory management
      * of named node maps is automatic.  Instances of DOM_NamedNodeMap function
      * as references to an underlying heap based implementation object,
      * and should never be explicitly new-ed or deleted in application code, but
      * should appear only as local variables or function parameters.
	  *
	  */
    ~DOM_NamedNodeMap();

    //@}

    /** @Comparisons. */
    //@{
    /**
     *  Test whether this NamedNodeMap reference refers to the same underlying
     *  named node map as the other reference object.  This does not
     *  compare the contents of two different objects.
     *
     *  @param arg p The value to be compared
     *  @return Returns true if the underlying named node map is same
     */
    bool operator == (const DOM_NamedNodeMap &other) const;

    /**
     *  Test whether this NamedNodeMap reference refers to a different underlying
     *  named node map as the other reference object.  This does not
     *  compare the contents of two different objects.
     *
     *  @param arg p The value to be compared
     *  @return Returns true if the underlying named node map is different
     */
    bool operator != (const DOM_NamedNodeMap &other) const;

    /**
     *  Use this comparison operator to test whether a Named Node Map reference
     *  is null.
     *
     *  @param arg p The value to be compared, which must be 0 or null.
     *  @return Returns true if the named node map is null
     */
    bool operator == (const DOM_NullPtr *p) const;

    /**
     *  Use this comparison operator to test whether a Named Node Map reference
     *  is not null.
     *
     *  @param arg p The value to be compared, which must not be 0 or null.
     *  @return Returns true if the named node map is not null
     */
    bool operator != (const DOM_NullPtr *p) const;

    //@}

    /** @name Set functions. */
    //@{

    /**
    * Adds a node using its nodeName attribute.
    *
    *
As the nodeName attribute is used to derive the name
    * which the node must be stored under, multiple nodes of certain types
    * (those that have a "special" string value) cannot be stored as the names
    * would clash. This is seen as preferable to allowing nodes to be aliased.
    * @param arg A node to store in a named node map. The node will later be
    *   accessible using the value of the nodeName attribute of
    *   the node. If a node with that name is already present in the map, it
    *   is replaced by the new one.
    * @return If the new Node replaces an existing node the
    *   replaced Node is returned,
    *   otherwise null is returned.
    * @exception DOMException
    *   WRONG_DOCUMENT_ERR: Raised if arg was created from a
    *   different document than the one that created the
    *   NamedNodeMap.
    *
NO_MODIFICATION_ALLOWED_ERR: Raised if this
    *   NamedNodeMap is readonly.
    *
INUSE_ATTRIBUTE_ERR: Raised if arg is an
    *   Attr that is already an attribute of another
    *   Element object. The DOM user must explicitly clone
    *   Attr nodes to re-use them in other elements.
    */
    DOM_Node               setNamedItem(DOM_Node arg);

    /**
    * Returns the indexth item in the map.
    *
    * If index
    * is greater than or equal to the number of nodes in the map, this returns
    * null.
    * @param index Index into the map.
    * @return The node at the indexth position in the
    *   NamedNodeMap, or null if that is not a valid
    *   index.
    */
    DOM_Node               item(unsigned int index);

    //@}
    /** @name Get functions. */
    //@{

    /**
    * Retrieves a node specified by name.
    *
    * @param name The nodeName of a node to retrieve.
    * @return A DOM_Node (of any type) with the specified nodeName, or
    *   null if it does not identify any node in
    *   the map.
    */
    DOM_Node               getNamedItem(const DOMString &name);

    /**
    * The number of nodes in the map.
    *
    * The range of valid child node indices is
    * 0 to length-1 inclusive.
    */
    unsigned int           getLength() const;

    //@}
    /** @name Functions to change the node collection. */
    //@{

    /**
    * Removes a node specified by name.
    *
    * If the removed node is an
    * Attr with a default value it is immediately replaced.
    * @param name The nodeName of a node to remove.
    * @return The node removed from the map or null if no node
    *   with such a name exists.
    * @exception DOMException
    *   NOT_FOUND_ERR: Raised if there is no node named name in
    *   the map.
    *

    *   NO_MODIFICATION_ALLOWED_ERR: Raised if this NamedNodeMap
    *   is readonly.
    */
    DOM_Node               removeNamedItem(const DOMString &name);

    //@}
    /** @name Functions introduced in DOM Level 2. */
    //@{

    /**
     * Retrieves a node specified by local name and namespace URI.
     *
     * @param namespaceURI The namespace URI of
     *    the node to retrieve.
     * @param localName The local name of the node to retrieve.
     * @return A DOM_Node (of any type) with the specified
     *    local name and namespace URI, or null if they do not
     *    identify any node in the map.
     */
    DOM_Node               getNamedItemNS(const DOMString &namespaceURI,
	const DOMString &localName);

    /**
     * Adds a node using its namespaceURI and localName.
     * @param arg A node to store in a named node map. The node will later be
     *       accessible using the value of the namespaceURI and
     *       localName attribute of the node. If a node with those
     *       namespace URI and local name is already present in the map, it is
     *       replaced by the new one.
     * @return If the new Node replaces an existing node the
     *   replaced Node is returned,
     *   otherwise null is returned.
     * @exception DOMException
     *   WRONG_DOCUMENT_ERR: Raised if arg was created from a
     *   different document than the one that created the
     *   NamedNodeMap.
     *
NO_MODIFICATION_ALLOWED_ERR: Raised if this
     *   NamedNodeMap is readonly.
     *
INUSE_ATTRIBUTE_ERR: Raised if arg is an
     *   Attr that is already an attribute of another
     *   Element object. The DOM user must explicitly clone
     *   Attr nodes to re-use them in other elements.
     */
    DOM_Node               setNamedItemNS(DOM_Node arg);

    /**
     * Removes a node specified by local name and namespace URI.
     *
     * @param namespaceURI The namespace URI of
     *    the node to remove.
     * @param localName The local name of the
     *    node to remove. When this DOM_NamedNodeMap contains the
     *    attributes attached to an element, as returned by the attributes
     *    attribute of the DOM_Node interface, if the removed
     *    attribute is known to have a default value, an attribute
     *    immediately appears containing the default value
     *    as well as the corresponding namespace URI, local name, and prefix.
     * @return The node removed from the map if a node with such a local name
     *    and namespace URI exists.
     * @exception DOMException
     *   NOT_FOUND_ERR: Raised if there is no node named name in
     *   the map.
     *

     *   NO_MODIFICATION_ALLOWED_ERR: Raised if this NamedNodeMap
     *   is readonly.
     */
    DOM_Node               removeNamedItemNS(const DOMString &namespaceURI,
	const DOMString &localName);

    //@}

 protected:

    DOM_NamedNodeMap(NamedNodeMapImpl *impl);

    friend class DOM_DocumentType;
    friend class DOM_Node;

};

#endif

<commit_msg>Added docs for assignment operators<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.7  2000/02/10 20:20:42  abagchi
 * Added docs for assignment operators
 *
 * Revision 1.6  2000/02/10 20:19:24  abagchi
 * Added docs for equality operators
 *
 * Revision 1.5  2000/02/06 07:47:30  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.4  2000/02/04 01:49:28  aruna1
 * TreeWalker and NodeIterator changes
 *
 * Revision 1.3  2000/01/22 01:38:29  andyh
 * Remove compiler warnings in DOM impl classes
 *
 * Revision 1.2  2000/01/05 01:16:07  andyh
 * DOM Level 2 core, namespace support added.
 *
 * Revision 1.1.1.1  1999/11/09 01:08:59  twl
 * Initial checkin
 *
 * Revision 1.3  1999/11/08 20:44:18  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

#ifndef DOM_NamedNodeMap_HEADER_GUARD_
#define DOM_NamedNodeMap_HEADER_GUARD_

#include <util/XML4CDefs.hpp>

#include <dom/DOM_Node.hpp>
class NamedNodeMapImpl;

/**
*  NamedNodeMaps  are used to
* represent collections of nodes that can be accessed by name.
*
* Note that NamedNodeMap does not inherit from NodeList;
* NamedNodeMaps are not maintained in any particular order.
* Nodes contained in a NamedNodeMap may
* also be accessed by an ordinal index, but this is simply to allow
* convenient enumeration of the contents, and
* does not imply that the DOM specifies an order to these Nodes.
*/
class CDOM_EXPORT DOM_NamedNodeMap {
private:
    NamedNodeMapImpl        *fImpl;

public:
    /** @name Constructors and assignment operator */
    //@{
    /**
      * Default constructor for DOM_NamedNodeMap.  The resulting object does not
      * refer to an actual DOM_NamedNodeMap node; it will compare == to 0, and is similar
      * to a null object reference variable in Java. NamedNopes are instantiated
      * by these methods:  DOM_Node::getAttributes, DOM_DocumentType::getEntities
      * andDOM_DocumentType::getNotations
      *
      */
    DOM_NamedNodeMap();

    /**
      * Copy constructor.  Creates a new DOM_NamedNodeMap reference object
      * that refers to the same underlying NamedNodeMap as the original.
      *
      * @param other The object to be copied.
      */
    DOM_NamedNodeMap(const DOM_NamedNodeMap &other);

    /**
      * Assignment operator.
      *
      * @param other The object to be copied.
      */
    DOM_NamedNodeMap & operator = (const DOM_NamedNodeMap &other);

    /**
      * Assignment operator.
      *
      * @param other The object to be copied.
      */
    DOM_NamedNodeMap & operator = (const DOM_NullPtr *other);

    //@}
    /** @name Destructor. */
    //@{
    /**
      * Destructor for DOM_NamedNodeMap.  The object being destroyed is the reference
      * object, not the underlying NamedNodeMap itself.
      *
      *
Like most other DOM types in this implementation, memory management
      * of named node maps is automatic.  Instances of DOM_NamedNodeMap function
      * as references to an underlying heap based implementation object,
      * and should never be explicitly new-ed or deleted in application code, but
      * should appear only as local variables or function parameters.
	  *
	  */
    ~DOM_NamedNodeMap();

    //@}

    /** @Comparisons. */
    //@{
    /**
     *  Test whether this NamedNodeMap reference refers to the same underlying
     *  named node map as the other reference object.  This does not
     *  compare the contents of two different objects.
     *
     *  @param arg p The value to be compared
     *  @return Returns true if the underlying named node map is same
     */
    bool operator == (const DOM_NamedNodeMap &other) const;

    /**
     *  Test whether this NamedNodeMap reference refers to a different underlying
     *  named node map as the other reference object.  This does not
     *  compare the contents of two different objects.
     *
     *  @param arg p The value to be compared
     *  @return Returns true if the underlying named node map is different
     */
    bool operator != (const DOM_NamedNodeMap &other) const;

    /**
     *  Use this comparison operator to test whether a Named Node Map reference
     *  is null.
     *
     *  @param arg p The value to be compared, which must be 0 or null.
     *  @return Returns true if the named node map is null
     */
    bool operator == (const DOM_NullPtr *p) const;

    /**
     *  Use this comparison operator to test whether a Named Node Map reference
     *  is not null.
     *
     *  @param arg p The value to be compared, which must not be 0 or null.
     *  @return Returns true if the named node map is not null
     */
    bool operator != (const DOM_NullPtr *p) const;

    //@}

    /** @name Set functions. */
    //@{

    /**
    * Adds a node using its nodeName attribute.
    *
    *
As the nodeName attribute is used to derive the name
    * which the node must be stored under, multiple nodes of certain types
    * (those that have a "special" string value) cannot be stored as the names
    * would clash. This is seen as preferable to allowing nodes to be aliased.
    * @param arg A node to store in a named node map. The node will later be
    *   accessible using the value of the nodeName attribute of
    *   the node. If a node with that name is already present in the map, it
    *   is replaced by the new one.
    * @return If the new Node replaces an existing node the
    *   replaced Node is returned,
    *   otherwise null is returned.
    * @exception DOMException
    *   WRONG_DOCUMENT_ERR: Raised if arg was created from a
    *   different document than the one that created the
    *   NamedNodeMap.
    *
NO_MODIFICATION_ALLOWED_ERR: Raised if this
    *   NamedNodeMap is readonly.
    *
INUSE_ATTRIBUTE_ERR: Raised if arg is an
    *   Attr that is already an attribute of another
    *   Element object. The DOM user must explicitly clone
    *   Attr nodes to re-use them in other elements.
    */
    DOM_Node               setNamedItem(DOM_Node arg);

    /**
    * Returns the indexth item in the map.
    *
    * If index
    * is greater than or equal to the number of nodes in the map, this returns
    * null.
    * @param index Index into the map.
    * @return The node at the indexth position in the
    *   NamedNodeMap, or null if that is not a valid
    *   index.
    */
    DOM_Node               item(unsigned int index);

    //@}
    /** @name Get functions. */
    //@{

    /**
    * Retrieves a node specified by name.
    *
    * @param name The nodeName of a node to retrieve.
    * @return A DOM_Node (of any type) with the specified nodeName, or
    *   null if it does not identify any node in
    *   the map.
    */
    DOM_Node               getNamedItem(const DOMString &name);

    /**
    * The number of nodes in the map.
    *
    * The range of valid child node indices is
    * 0 to length-1 inclusive.
    */
    unsigned int           getLength() const;

    //@}
    /** @name Functions to change the node collection. */
    //@{

    /**
    * Removes a node specified by name.
    *
    * If the removed node is an
    * Attr with a default value it is immediately replaced.
    * @param name The nodeName of a node to remove.
    * @return The node removed from the map or null if no node
    *   with such a name exists.
    * @exception DOMException
    *   NOT_FOUND_ERR: Raised if there is no node named name in
    *   the map.
    *

    *   NO_MODIFICATION_ALLOWED_ERR: Raised if this NamedNodeMap
    *   is readonly.
    */
    DOM_Node               removeNamedItem(const DOMString &name);

    //@}
    /** @name Functions introduced in DOM Level 2. */
    //@{

    /**
     * Retrieves a node specified by local name and namespace URI.
     *
     * @param namespaceURI The namespace URI of
     *    the node to retrieve.
     * @param localName The local name of the node to retrieve.
     * @return A DOM_Node (of any type) with the specified
     *    local name and namespace URI, or null if they do not
     *    identify any node in the map.
     */
    DOM_Node               getNamedItemNS(const DOMString &namespaceURI,
	const DOMString &localName);

    /**
     * Adds a node using its namespaceURI and localName.
     * @param arg A node to store in a named node map. The node will later be
     *       accessible using the value of the namespaceURI and
     *       localName attribute of the node. If a node with those
     *       namespace URI and local name is already present in the map, it is
     *       replaced by the new one.
     * @return If the new Node replaces an existing node the
     *   replaced Node is returned,
     *   otherwise null is returned.
     * @exception DOMException
     *   WRONG_DOCUMENT_ERR: Raised if arg was created from a
     *   different document than the one that created the
     *   NamedNodeMap.
     *
NO_MODIFICATION_ALLOWED_ERR: Raised if this
     *   NamedNodeMap is readonly.
     *
INUSE_ATTRIBUTE_ERR: Raised if arg is an
     *   Attr that is already an attribute of another
     *   Element object. The DOM user must explicitly clone
     *   Attr nodes to re-use them in other elements.
     */
    DOM_Node               setNamedItemNS(DOM_Node arg);

    /**
     * Removes a node specified by local name and namespace URI.
     *
     * @param namespaceURI The namespace URI of
     *    the node to remove.
     * @param localName The local name of the
     *    node to remove. When this DOM_NamedNodeMap contains the
     *    attributes attached to an element, as returned by the attributes
     *    attribute of the DOM_Node interface, if the removed
     *    attribute is known to have a default value, an attribute
     *    immediately appears containing the default value
     *    as well as the corresponding namespace URI, local name, and prefix.
     * @return The node removed from the map if a node with such a local name
     *    and namespace URI exists.
     * @exception DOMException
     *   NOT_FOUND_ERR: Raised if there is no node named name in
     *   the map.
     *

     *   NO_MODIFICATION_ALLOWED_ERR: Raised if this NamedNodeMap
     *   is readonly.
     */
    DOM_Node               removeNamedItemNS(const DOMString &namespaceURI,
	const DOMString &localName);

    //@}

 protected:

    DOM_NamedNodeMap(NamedNodeMapImpl *impl);

    friend class DOM_DocumentType;
    friend class DOM_Node;

};

#endif

<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include <math.h>
#include "common.h"
#include "global.h"
#include "PyramidBuilding.h"
#include "Intersect.h"
#include "TriWallSceneNode.h"
#include "QuadWallSceneNode.h"
#include "BZDBCache.h"

std::string		PyramidBuilding::typeName("PyramidBuilding");

PyramidBuilding::PyramidBuilding(const float* p, float a,
				float w, float b, float h, bool drive, bool shoot) :
				Obstacle(p, a, w, b, h,drive,shoot)
{
  // do nothing
}

PyramidBuilding::~PyramidBuilding()
{
  // do nothing
}

std::string		PyramidBuilding::getType() const
{
  return typeName;
}

std::string		PyramidBuilding::getClassName() // const
{
  return typeName;
}

float			PyramidBuilding::intersect(const Ray& r) const
{
  return timeRayHitsPyramids(r, getPosition(), getRotation(),
			     getWidth(), getBreadth(), getHeight(),
			     getZFlip());
}

void			PyramidBuilding::getNormal(const float* p,
							float* n) const
{
  // get normal in z = const plane
  const float s = shrinkFactor(p[2]);
  getNormalRect(p, getPosition(), getRotation(),
			s * getWidth(), s * getBreadth(), n);

  // make sure we are not way above or way below it
  // above is good so we can drive on it when it's fliped
  float top =  getPosition()[2]+getHeight();
  float bottom = getPosition()[2];

  if (s ==0){
	  if (this->getZFlip()){
		  if (p[2] >= top){
			  n[0] = n[1] = 0;
			  n[2] = 1;
			  return;
		  }
	  }else{
		  if (p[2] <= bottom){
			  n[0] = n[1] = 0;
			  n[2] = -1;
			  return;
		  }
	  }
  }

  // now angle it due to slope of wall
  // FIXME -- this assumes the pyramid has a square base!
  const float h = 1.0f / hypotf(getHeight(), getWidth());
  n[0] *= h * getHeight();
  n[1] *= h * getHeight();
  n[2] = h * getWidth();

  if (this->getZFlip())
	  n[2] *= -1;
}

void			PyramidBuilding::get3DNormal(const float* p,
						     float* n) const
{
  const float epsilon = 1.0e-5f;

  // get normal in z = const plane
  const float s = shrinkFactor(p[2]);
  getNormalRect(p, getPosition(), getRotation(),
		s * getWidth(), s * getBreadth(), n);

  // make sure we are not way above or way below it
  // above is good so we can drive on it when it's fliped
  float top =  getPosition()[2]+getHeight();
  float bottom = getPosition()[2];

  if (s == 0) {
    if (getZFlip()) {
      if (p[2] >= top) {
	n[0] = n[1] = 0;
	n[2] = 1;
	return;
      }
    } else {
      if (p[2] <= bottom) {
	n[0] = n[1] = 0;
	n[2] = -1;
	return;
      }
    }
  }

  if (s >= 1.0f - epsilon) {
    n[0] = n[1] = 0;
    if (getZFlip()) {
      n[2] = 1;
    } else {
      n[2] = -1;
    }
    return;
  }

  // now angle it due to slope of wall
  // FIXME -- this assumes the pyramid has a square base!
  const float h = 1.0f / hypotf(getHeight(), getWidth());
  n[0] *= h * getHeight();
  n[1] *= h * getHeight();
  n[2]  = h * getWidth();

  if (this->getZFlip())
    n[2] *= -1;
}

bool			PyramidBuilding::isInside(const float* p,
						float radius) const
{
  // really rough -- doesn't decrease size with height
  return (p[2] <= getHeight())
  &&     ((p[2]+BZDBCache::tankHeight) >= getPosition()[2])
  &&     testRectCircle(getPosition(), getRotation(), getWidth(), getBreadth(), p, radius);
}

bool			PyramidBuilding::isInside(const float* p, float a,
						float dx, float dy) const
{
  // Tank is below pyramid ?
  if (p[2] + BZDBCache::tankHeight < getPosition()[2])
    return false;
  // Tank is above pyramid ?
  if (p[2] > getPosition()[2] + getHeight())
    return false;
  // Could be inside. Then check collision with the rectangle at object height
  // This is a rectangle reduced by shrinking but pass the height that we are
  // not so sure where collision can be
  const float s = shrinkFactor(p[2], BZDBCache::tankHeight);
  return testRectRect(getPosition(), getRotation(),
		      s * getWidth(), s * getBreadth(), p, a, dx, dy);
}

bool			PyramidBuilding::isCrossing(const float* p, float a,
					float dx, float dy, float* plane) const
{
  // if not inside or contained then not crossing
  if (!isInside(p, a, dx, dy) ||
	testRectInRect(getPosition(), getRotation(),
			getWidth(), getBreadth(), p, a, dx, dy))
    return false;
  if (!plane) return true;

  // it's crossing -- choose which wall is being crossed (this
  // is a guestimate, should really do a careful test).  just
  // see which wall the point is closest to.
  const float* p2 = getPosition();
  const float a2 = getRotation();
  const float c = cosf(-a2), s = sinf(-a2);
  const float x = c * (p[0] - p2[0]) - s * (p[1] - p2[1]);
  const float y = c * (p[1] - p2[1]) + s * (p[0] - p2[0]);
  float pw[2];
  if (fabsf(fabsf(x) - getWidth()) < fabsf(fabsf(y) - getBreadth())) {
    plane[0] = ((x < 0.0) ? -cosf(a2) : cosf(a2));
    plane[1] = ((x < 0.0) ? -sinf(a2) : sinf(a2));
    pw[0] = p2[0] + getWidth() * plane[0];
    pw[1] = p2[1] + getWidth() * plane[1];
  }
  else {
    plane[0] = ((y < 0.0) ? sinf(a2) : -sinf(a2));
    plane[1] = ((y < 0.0) ? -cosf(a2) : cosf(a2));
    pw[0] = p2[0] + getBreadth() * plane[0];
    pw[1] = p2[1] + getBreadth() * plane[1];
  }

  // now finish off plane equation (FIXME -- assumes a square base)
  const float h = 1.0f / hypotf(getHeight(), getWidth());
  plane[0] *= h * getHeight();
  plane[1] *= h * getHeight();
  plane[2] = h * getWidth();
  plane[3] = -(plane[0] * pw[0] + plane[1] * pw[1]);
  return true;
}

bool			PyramidBuilding::getHitNormal(
				const float* pos1, float,
				const float* pos2, float,
				float, float, float height,
				float* normal) const
{
  // pyramids height, top, bottom and flipping
  float oHeight = getHeight();
  float oBottom = getPosition()[2];
  float oTop    = oBottom;
  bool  flip    = getZFlip();
  if (flip)
    oHeight = -oHeight;
  if (oHeight < 0) {
    flip    = !flip;
    oHeight = -oHeight;
  }
  if (flip)
    oBottom += oHeight;
  else
    oTop    += oHeight;

  float objHigh = pos1[2];
  float objLow  = pos2[2];
  if (objHigh < objLow) {
    float temp = objHigh;
    objHigh    = objLow;
    objLow     = temp;
  }

  normal[0] = normal[1] = 0;
  if (objHigh > oTop) {
      normal[2] = 1;
      return true;
  } else if (objLow + height < oBottom) {
    normal[2] = -1;
    return true;
  }

  // get normal in z = const plane
  const float s = shrinkFactor(pos1[2], height);

  getNormalRect(pos1, getPosition(), getRotation(),
		s * getWidth(), s * getBreadth(), normal);

  // now angle it due to slope of wall
  // FIXME -- this assumes the pyramid has a square base!
  const float h = 1.0f / hypotf(oHeight, getWidth());
  normal[0] *= h * oHeight;
  normal[1] *= h * oHeight;
  normal[2]  = h * getWidth();

  if (flip)
    normal[2] = -normal[2];
  return true;
}

ObstacleSceneNodeGenerator*	PyramidBuilding::newSceneNodeGenerator() const
{
  return new PyramidSceneNodeGenerator(this);
}

void			PyramidBuilding::getCorner(int index,
						float* pos) const
{
  const float* base = getPosition();
  const float c = cosf(getRotation());
  const float s = sinf(getRotation());
  const float w = getWidth();
  const float h = getBreadth();
  const float top  = getHeight() + base[2];
  switch (index) {
    case 0:
      pos[0] = base[0] + c * w - s * h;
      pos[1] = base[1] + s * w + c * h;
	  if (getZFlip())
		 pos[2] = top;
	  else
		 pos[2] = base[2];
      break;
    case 1:
      pos[0] = base[0] - c * w - s * h;
      pos[1] = base[1] - s * w + c * h;
	  if (getZFlip())
		 pos[2] = top;
	  else
		 pos[2] = base[2];
      break;
    case 2:
      pos[0] = base[0] - c * w + s * h;
      pos[1] = base[1] - s * w - c * h;
	  if (getZFlip())
		 pos[2] = top;
	  else
		 pos[2] = base[2];
      break;
    case 3:
      pos[0] = base[0] + c * w + s * h;
      pos[1] = base[1] + s * w - c * h;
	  if (getZFlip())
		 pos[2] = top;
	  else
		 pos[2] = base[2];
      break;
    case 4:
      pos[0] = base[0];
      pos[1] = base[1];
	  if (getZFlip())
		 pos[2] = base[2];
	  else
		 pos[2] = top;
      break;
  }
}

float			PyramidBuilding::shrinkFactor(float z,
						      float height) const
{
  float shrink;

 // Remove heights bias
  const float *pos = getPosition();
  z -= pos[2];
  // Normalize heights
  z /= getHeight();

  // if flipped the bigger intersection is at top of obiect
  if (getZFlip()) {
    // Normalize the object height, we have not done yet
    height /= getHeight();
    z += height;
  }

  // shrink is that
  if (getZFlip()) {
    shrink = z;
  } else {
    shrink = 1.0f - z;
  }

  // clamp in 0 .. 1
  if (shrink < 0.0)
    shrink = 0.0;
  else if (shrink > 1.0)
    shrink = 1.0;

  return shrink;
}

//
// PyramidSceneNodeGenerator
//

PyramidSceneNodeGenerator::PyramidSceneNodeGenerator(
				const PyramidBuilding* _pyramid) :
				pyramid(_pyramid)
{
  // do nothing
}

PyramidSceneNodeGenerator::~PyramidSceneNodeGenerator()
{
  // do nothing
}

WallSceneNode*		PyramidSceneNodeGenerator::getNextNode(
				float uRepeats, float vRepeats, bool lod)
{

	bool isSquare = false;

	if (getNodeNumber() == 5) return NULL;

  GLfloat base[3], sCorner[3], tCorner[3];
  if (pyramid->getZFlip()){
  switch (incNodeNumber()) {
    case 1:
      pyramid->getCorner(4, base);
      pyramid->getCorner(1, sCorner);
      pyramid->getCorner(0, tCorner);
	  isSquare = false;
      break;
    case 2:
      pyramid->getCorner(4, base);
      pyramid->getCorner(2, sCorner);
      pyramid->getCorner(1, tCorner);
	  isSquare = false;
      break;
    case 3:
      pyramid->getCorner(4, base);
      pyramid->getCorner(3, sCorner);
      pyramid->getCorner(2, tCorner);
	  isSquare = false;
      break;
    case 4:
      pyramid->getCorner(4, base);
      pyramid->getCorner(0, sCorner);
      pyramid->getCorner(3, tCorner);
	  isSquare = false;
      break;
    case 5:
      pyramid->getCorner(0, base);
      pyramid->getCorner(1, sCorner);
      pyramid->getCorner(3, tCorner);
	  isSquare = true;
      break;
  }
  }else{
	  switch (incNodeNumber()) {
    case 1:
      pyramid->getCorner(0, base);
      pyramid->getCorner(1, sCorner);
      pyramid->getCorner(4, tCorner);
	  isSquare = false;
      break;
    case 2:
      pyramid->getCorner(1, base);
      pyramid->getCorner(2, sCorner);
      pyramid->getCorner(4, tCorner);
	  isSquare = false;
      break;
    case 3:
      pyramid->getCorner(2, base);
      pyramid->getCorner(3, sCorner);
      pyramid->getCorner(4, tCorner);
	  isSquare = false;
      break;
    case 4:
      pyramid->getCorner(3, base);
      pyramid->getCorner(0, sCorner);
      pyramid->getCorner(4, tCorner);
	  isSquare = false;
      break;
    case 5:
      pyramid->getCorner(0, base);
      pyramid->getCorner(3, sCorner);
      pyramid->getCorner(1, tCorner);
	  isSquare = true;
      break;
  }
  }

  GLfloat sEdge[3];
  GLfloat tEdge[3];
  sEdge[0] = sCorner[0] - base[0];
  sEdge[1] = sCorner[1] - base[1];
  sEdge[2] = sCorner[2] - base[2];
  tEdge[0] = tCorner[0] - base[0];
  tEdge[1] = tCorner[1] - base[1];
  tEdge[2] = tCorner[2] - base[2];

  if(isSquare != true)
	return new TriWallSceneNode(base, sEdge, tEdge, uRepeats, vRepeats, lod);
  else
	return new QuadWallSceneNode(base, sEdge, tEdge, uRepeats, vRepeats, lod);

}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>Taking flip into account better<commit_after>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include <math.h>
#include "common.h"
#include "global.h"
#include "PyramidBuilding.h"
#include "Intersect.h"
#include "TriWallSceneNode.h"
#include "QuadWallSceneNode.h"
#include "BZDBCache.h"

std::string		PyramidBuilding::typeName("PyramidBuilding");

PyramidBuilding::PyramidBuilding(const float* p, float a,
				float w, float b, float h, bool drive, bool shoot) :
				Obstacle(p, a, w, b, h,drive,shoot)
{
  // do nothing
}

PyramidBuilding::~PyramidBuilding()
{
  // do nothing
}

std::string		PyramidBuilding::getType() const
{
  return typeName;
}

std::string		PyramidBuilding::getClassName() // const
{
  return typeName;
}

float			PyramidBuilding::intersect(const Ray& r) const
{
  return timeRayHitsPyramids(r, getPosition(), getRotation(),
			     getWidth(), getBreadth(), getHeight(),
			     getZFlip());
}

void			PyramidBuilding::getNormal(const float* p,
							float* n) const
{
  // get normal in z = const plane
  const float s = shrinkFactor(p[2]);
  getNormalRect(p, getPosition(), getRotation(),
			s * getWidth(), s * getBreadth(), n);

  // make sure we are not way above or way below it
  // above is good so we can drive on it when it's fliped
  float top =  getPosition()[2]+getHeight();
  float bottom = getPosition()[2];

  if (s ==0){
	  if (this->getZFlip()){
		  if (p[2] >= top){
			  n[0] = n[1] = 0;
			  n[2] = 1;
			  return;
		  }
	  }else{
		  if (p[2] <= bottom){
			  n[0] = n[1] = 0;
			  n[2] = -1;
			  return;
		  }
	  }
  }

  // now angle it due to slope of wall
  // FIXME -- this assumes the pyramid has a square base!
  const float h = 1.0f / hypotf(getHeight(), getWidth());
  n[0] *= h * getHeight();
  n[1] *= h * getHeight();
  n[2] = h * getWidth();

  if (this->getZFlip())
	  n[2] *= -1;
}

void			PyramidBuilding::get3DNormal(const float* p,
						     float* n) const
{
  const float epsilon = 1.0e-5f;

  // get normal in z = const plane
  const float s = shrinkFactor(p[2]);
  getNormalRect(p, getPosition(), getRotation(),
		s * getWidth(), s * getBreadth(), n);

  // make sure we are not way above or way below it
  // above is good so we can drive on it when it's fliped
  float top =  getPosition()[2]+getHeight();
  float bottom = getPosition()[2];

  if (s == 0) {
    if (getZFlip()) {
      if (p[2] >= top) {
	n[0] = n[1] = 0;
	n[2] = 1;
	return;
      }
    } else {
      if (p[2] <= bottom) {
	n[0] = n[1] = 0;
	n[2] = -1;
	return;
      }
    }
  }

  if (s >= 1.0f - epsilon) {
    n[0] = n[1] = 0;
    if (getZFlip()) {
      n[2] = 1;
    } else {
      n[2] = -1;
    }
    return;
  }

  // now angle it due to slope of wall
  // FIXME -- this assumes the pyramid has a square base!
  const float h = 1.0f / hypotf(getHeight(), getWidth());
  n[0] *= h * getHeight();
  n[1] *= h * getHeight();
  n[2]  = h * getWidth();

  if (this->getZFlip())
    n[2] *= -1;
}

bool			PyramidBuilding::isInside(const float* p,
						float radius) const
{
  // really rough -- doesn't decrease size with height
  return (p[2] <= getHeight())
  &&     ((p[2]+BZDBCache::tankHeight) >= getPosition()[2])
  &&     testRectCircle(getPosition(), getRotation(), getWidth(), getBreadth(), p, radius);
}

bool			PyramidBuilding::isInside(const float* p, float a,
						float dx, float dy) const
{
  // Tank is below pyramid ?
  if (p[2] + BZDBCache::tankHeight < getPosition()[2])
    return false;
  // Tank is above pyramid ?
  if (p[2] > getPosition()[2] + getHeight())
    return false;
  // Could be inside. Then check collision with the rectangle at object height
  // This is a rectangle reduced by shrinking but pass the height that we are
  // not so sure where collision can be
  const float s = shrinkFactor(p[2], BZDBCache::tankHeight);
  return testRectRect(getPosition(), getRotation(),
		      s * getWidth(), s * getBreadth(), p, a, dx, dy);
}

bool			PyramidBuilding::isCrossing(const float* p, float a,
					float dx, float dy, float* plane) const
{
  // if not inside or contained then not crossing
  if (!isInside(p, a, dx, dy) ||
	testRectInRect(getPosition(), getRotation(),
			getWidth(), getBreadth(), p, a, dx, dy))
    return false;
  if (!plane) return true;

  // it's crossing -- choose which wall is being crossed (this
  // is a guestimate, should really do a careful test).  just
  // see which wall the point is closest to.
  const float* p2 = getPosition();
  const float a2 = getRotation();
  const float c = cosf(-a2), s = sinf(-a2);
  const float x = c * (p[0] - p2[0]) - s * (p[1] - p2[1]);
  const float y = c * (p[1] - p2[1]) + s * (p[0] - p2[0]);
  float pw[2];
  if (fabsf(fabsf(x) - getWidth()) < fabsf(fabsf(y) - getBreadth())) {
    plane[0] = ((x < 0.0) ? -cosf(a2) : cosf(a2));
    plane[1] = ((x < 0.0) ? -sinf(a2) : sinf(a2));
    pw[0] = p2[0] + getWidth() * plane[0];
    pw[1] = p2[1] + getWidth() * plane[1];
  }
  else {
    plane[0] = ((y < 0.0) ? sinf(a2) : -sinf(a2));
    plane[1] = ((y < 0.0) ? -cosf(a2) : cosf(a2));
    pw[0] = p2[0] + getBreadth() * plane[0];
    pw[1] = p2[1] + getBreadth() * plane[1];
  }

  // now finish off plane equation (FIXME -- assumes a square base)
  const float h = 1.0f / hypotf(getHeight(), getWidth());
  plane[0] *= h * getHeight();
  plane[1] *= h * getHeight();
  plane[2] = h * getWidth();
  plane[3] = -(plane[0] * pw[0] + plane[1] * pw[1]);
  return true;
}

bool			PyramidBuilding::getHitNormal(
				const float* pos1, float,
				const float* pos2, float,
				float, float, float height,
				float* normal) const
{
  // pyramids height and flipping
  // normalize height sign and report that in flip
  float oHeight = getHeight();
  bool  flip    = getZFlip();
  if (oHeight < 0) {
    flip    = !flip;
    oHeight = -oHeight;
  }

  // get Bottom and Top of building
  float oBottom = getPosition()[2];
  float oTop    = oBottom + oHeight;

  // get higher and lower point of base of colliding object
  float objHigh = pos1[2];
  float objLow  = pos2[2];
  if (objHigh < objLow) {
    float temp = objHigh;
    objHigh    = objLow;
    objLow     = temp;
  }

  normal[0] = normal[1] = 0;
  if (flip && objHigh > oTop) {
    // base of higher object is over the plateau
    normal[2] = 1;
    return true;
  } else if (!flip && objLow + height < oBottom) {
    // top of lower object is below the base
    normal[2] = -1;
    return true;
  }

  // get normal in z = const plane
  const float s = shrinkFactor(pos1[2], height);

  getNormalRect(pos1, getPosition(), getRotation(),
		s * getWidth(), s * getBreadth(), normal);

  // now angle it due to slope of wall
  // FIXME -- this assumes the pyramid has a square base!
  const float h = 1.0f / hypotf(oHeight, getWidth());
  normal[0] *= h * oHeight;
  normal[1] *= h * oHeight;
  normal[2]  = h * getWidth();

  if (flip)
    normal[2] = -normal[2];
  return true;
}

ObstacleSceneNodeGenerator*	PyramidBuilding::newSceneNodeGenerator() const
{
  return new PyramidSceneNodeGenerator(this);
}

void			PyramidBuilding::getCorner(int index,
						float* pos) const
{
  const float* base = getPosition();
  const float c = cosf(getRotation());
  const float s = sinf(getRotation());
  const float w = getWidth();
  const float h = getBreadth();
  const float top  = getHeight() + base[2];
  switch (index) {
    case 0:
      pos[0] = base[0] + c * w - s * h;
      pos[1] = base[1] + s * w + c * h;
	  if (getZFlip())
		 pos[2] = top;
	  else
		 pos[2] = base[2];
      break;
    case 1:
      pos[0] = base[0] - c * w - s * h;
      pos[1] = base[1] - s * w + c * h;
	  if (getZFlip())
		 pos[2] = top;
	  else
		 pos[2] = base[2];
      break;
    case 2:
      pos[0] = base[0] - c * w + s * h;
      pos[1] = base[1] - s * w - c * h;
	  if (getZFlip())
		 pos[2] = top;
	  else
		 pos[2] = base[2];
      break;
    case 3:
      pos[0] = base[0] + c * w + s * h;
      pos[1] = base[1] + s * w - c * h;
	  if (getZFlip())
		 pos[2] = top;
	  else
		 pos[2] = base[2];
      break;
    case 4:
      pos[0] = base[0];
      pos[1] = base[1];
	  if (getZFlip())
		 pos[2] = base[2];
	  else
		 pos[2] = top;
      break;
  }
}

float			PyramidBuilding::shrinkFactor(float z,
						      float height) const
{
  float shrink;

  // Normalize Height and flip to have height > 0
  float oHeight = getHeight();
  bool  flip    = getZFlip();
  if (oHeight < 0) {
    flip    = !flip;
    oHeight = - oHeight;
  }

 // Remove heights bias
  const float *pos = getPosition();
  z -= pos[2];
  // Normalize heights
  z /= oHeight;

  // if flipped the bigger intersection is at top of obiect
  if (flip) {
    // Normalize the object height, we have not done yet
    z += height / oHeight;
  }

  // shrink is that
  if (flip) {
    shrink = z;
  } else {
    shrink = 1.0f - z;
  }

  // clamp in 0 .. 1
  if (shrink < 0.0)
    shrink = 0.0;
  else if (shrink > 1.0)
    shrink = 1.0;

  return shrink;
}

//
// PyramidSceneNodeGenerator
//

PyramidSceneNodeGenerator::PyramidSceneNodeGenerator(
				const PyramidBuilding* _pyramid) :
				pyramid(_pyramid)
{
  // do nothing
}

PyramidSceneNodeGenerator::~PyramidSceneNodeGenerator()
{
  // do nothing
}

WallSceneNode*		PyramidSceneNodeGenerator::getNextNode(
				float uRepeats, float vRepeats, bool lod)
{

	bool isSquare = false;

	if (getNodeNumber() == 5) return NULL;

  GLfloat base[3], sCorner[3], tCorner[3];
  if (pyramid->getZFlip()){
  switch (incNodeNumber()) {
    case 1:
      pyramid->getCorner(4, base);
      pyramid->getCorner(1, sCorner);
      pyramid->getCorner(0, tCorner);
	  isSquare = false;
      break;
    case 2:
      pyramid->getCorner(4, base);
      pyramid->getCorner(2, sCorner);
      pyramid->getCorner(1, tCorner);
	  isSquare = false;
      break;
    case 3:
      pyramid->getCorner(4, base);
      pyramid->getCorner(3, sCorner);
      pyramid->getCorner(2, tCorner);
	  isSquare = false;
      break;
    case 4:
      pyramid->getCorner(4, base);
      pyramid->getCorner(0, sCorner);
      pyramid->getCorner(3, tCorner);
	  isSquare = false;
      break;
    case 5:
      pyramid->getCorner(0, base);
      pyramid->getCorner(1, sCorner);
      pyramid->getCorner(3, tCorner);
	  isSquare = true;
      break;
  }
  }else{
	  switch (incNodeNumber()) {
    case 1:
      pyramid->getCorner(0, base);
      pyramid->getCorner(1, sCorner);
      pyramid->getCorner(4, tCorner);
	  isSquare = false;
      break;
    case 2:
      pyramid->getCorner(1, base);
      pyramid->getCorner(2, sCorner);
      pyramid->getCorner(4, tCorner);
	  isSquare = false;
      break;
    case 3:
      pyramid->getCorner(2, base);
      pyramid->getCorner(3, sCorner);
      pyramid->getCorner(4, tCorner);
	  isSquare = false;
      break;
    case 4:
      pyramid->getCorner(3, base);
      pyramid->getCorner(0, sCorner);
      pyramid->getCorner(4, tCorner);
	  isSquare = false;
      break;
    case 5:
      pyramid->getCorner(0, base);
      pyramid->getCorner(3, sCorner);
      pyramid->getCorner(1, tCorner);
	  isSquare = true;
      break;
  }
  }

  GLfloat sEdge[3];
  GLfloat tEdge[3];
  sEdge[0] = sCorner[0] - base[0];
  sEdge[1] = sCorner[1] - base[1];
  sEdge[2] = sCorner[2] - base[2];
  tEdge[0] = tCorner[0] - base[0];
  tEdge[1] = tCorner[1] - base[1];
  tEdge[2] = tCorner[2] - base[2];

  if(isSquare != true)
	return new TriWallSceneNode(base, sEdge, tEdge, uRepeats, vRepeats, lod);
  else
	return new QuadWallSceneNode(base, sEdge, tEdge, uRepeats, vRepeats, lod);

}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<|endoftext|>


<commit_before><commit_msg>[booking] Quality check tools<commit_after><|endoftext|>


<commit_before>#include "bot.h"

#include <boost/regex/pattern_except.hpp>
#include <boost/regex.hpp>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>

#include "connection.h"
#include "logger.h"
#include "curl_easy.h"

namespace geecxx
{

Bot::Bot()
{
}

Bot::~Bot()
{
    if (_connection) {
        quit();
        _connection->close();
    }
}

bool Bot::init(const ConfigurationProvider& configuration)
{
    _connection.reset(new Connection(configuration.getServer(), std::to_string(configuration.getPortNumber())));
    if (!_connection) {
        return false;
    }
    _connection->setExternalReadHandler([this](const std::string& m){
        this->_readHandler(m);
    });
    _connection->setExternalWriteHandler([this]() { _writeHandler(); });
    if(!_connection->open()) {
        return false;
    }
    nick(configuration.getNickname());
    join(configuration.getChannelName(), configuration.getChannelKey());

    return true;
}

void Bot::run()
{
    _connection->run();
}

void Bot::nick(const std::string& nickname)
{
    LOG_INFO("nick: " + nickname);
    _connection->writeMessage(std::string("NICK ") + nickname);
    _connection->writeMessage(std::string("USER ") + nickname + " * * :" + nickname);
    _nickname = nickname;
}

void Bot::join(const std::string& channel, const std::string& key)
{
    LOG_INFO(std::string("JOIN ") + channel + " " + key);
    _connection->writeMessage(std::string("JOIN ") + channel + " " + key);
    _currentChannel = channel;
}

void Bot::say(const std::string& message)
{
   msg(_currentChannel, message);
}

void Bot::msg(const std::string& receiver, const std::string& message)
{
    _connection->writeMessage(std::string("PRIVMSG ") + receiver + " :" + message);
}

void Bot::pong(const std::string& serverName)
{
    _connection->writeMessage(std::string("PONG ") + serverName);
}

void Bot::quit()
{
    _connection->writeMessage(std::string("QUIT : Shutting down."));
}

std::istringstream& Bot::_skipToContent(std::istringstream& iss)
{
    char c = 0;
    while(!iss.eof() && c != ':') {
        iss >> c;
    }
    return iss;
}

void Bot::_readHandler(const std::string& message)
{
    LOG_DEBUG("Reading: " + message);

    std::istringstream iss(message);
    std::string command;
    std::string sender = "";
    iss >> command;

    if (command.size() > 1 && command[0] == ':') {
    //this is probably a privmsg
        size_t pos = command.find('!');
        if (pos != std::string::npos) {
            sender = command.substr(1, pos - 1);
            iss >> command;
        }
    }

    if (command == "PRIVMSG") {
        std::string recipient;
        iss >> recipient;
        LOG_DEBUG("PRIVMSG FROM " + sender + " TO " + recipient);

        if(recipient == _nickname) {
            return;
        }

        std::string result;
        if (_parseURL(message, result)) {
            LOG_DEBUG("Found URL: " + result);
            const std::string title = _getTitleFromUrl(result);
            if (sender == _currentChannel) {
                say(title);
            } else {
                msg(sender, title);
            }
        }
    } else if (command == "PING") {
        _skipToContent(iss);
        std::string host;
        iss >> host;
        pong(host);
    }

}

std::string Bot::_getTitleFromUrl(const std::string& url)
{
    std::ostringstream oss;
    curl_writer writer(oss);
    curl::curl_easy easy(writer);
    easy.add(curl_pair<CURLoption,string>(CURLOPT_URL, url) );
    easy.add(curl_pair<CURLoption,long>(CURLOPT_FOLLOWLOCATION, 1L));
    try {
        easy.perform();
    } catch (curl::curl_easy_exception e) {
        std::vector<pair<std::string, std::string>> w = e.what();
        return "Exception: " + w.at(0).first;
    }

    size_t pos = oss.str().find("<title>") + 7;
    size_t pos2 = oss.str().find("</title>");
    return oss.str().substr(pos, pos2 - pos);
}

void Bot::_writeHandler()
{
    std::string line, comm;
    while (_connection->isAlive()) {
        std::getline(std::cin, line);
        std::istringstream iss(line);

        iss >> comm;
        if (comm == "/n") {
            iss >> comm;
            nick(comm);
        } else if (comm == "/j") {
            iss >> comm;
            join(comm);
        } else if (comm == "/m") {
            iss >> comm;
            msg(comm, iss.str());
        } else if (comm == "/s") {
            say(iss.str());
        } else if (comm == "/q") {
            iss >> comm;
            quit();
        }
    }
}

bool Bot::_parseURL(const std::string& message, std::string& result)
{
    boost::regex urlRegex;
    try {
        // Source of the regular expression:
        // http://daringfireball.net/2010/07/improved_regex_for_matching_urls
        urlRegex.assign(R"((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))",
                         boost::regex::ECMAScript);
    } catch(boost::regex_error& error) {
        std::cerr << "Invalid regular expression: " << error.what() << std::endl;
        return false;
    }

    boost::smatch matchedElements;
    bool containsURL = boost::regex_search(message, matchedElements, urlRegex);
    result = matchedElements[0];

    return containsURL;
}

}

<commit_msg>url title retrieval return the url itself when no title is found<commit_after>#include "bot.h"

#include <boost/regex/pattern_except.hpp>
#include <boost/regex.hpp>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>

#include "connection.h"
#include "logger.h"
#include "curl_easy.h"

namespace geecxx
{

Bot::Bot()
{
}

Bot::~Bot()
{
    if (_connection) {
        quit();
        _connection->close();
    }
}

bool Bot::init(const ConfigurationProvider& configuration)
{
    _connection.reset(new Connection(configuration.getServer(), std::to_string(configuration.getPortNumber())));
    if (!_connection) {
        return false;
    }
    _connection->setExternalReadHandler([this](const std::string& m){
        this->_readHandler(m);
    });
    _connection->setExternalWriteHandler([this]() { _writeHandler(); });
    if(!_connection->open()) {
        return false;
    }
    nick(configuration.getNickname());
    join(configuration.getChannelName(), configuration.getChannelKey());

    return true;
}

void Bot::run()
{
    _connection->run();
}

void Bot::nick(const std::string& nickname)
{
    LOG_INFO("nick: " + nickname);
    _connection->writeMessage(std::string("NICK ") + nickname);
    _connection->writeMessage(std::string("USER ") + nickname + " * * :" + nickname);
    _nickname = nickname;
}

void Bot::join(const std::string& channel, const std::string& key)
{
    LOG_INFO(std::string("JOIN ") + channel + " " + key);
    _connection->writeMessage(std::string("JOIN ") + channel + " " + key);
    _currentChannel = channel;
}

void Bot::say(const std::string& message)
{
   msg(_currentChannel, message);
}

void Bot::msg(const std::string& receiver, const std::string& message)
{
    _connection->writeMessage(std::string("PRIVMSG ") + receiver + " :" + message);
}

void Bot::pong(const std::string& serverName)
{
    _connection->writeMessage(std::string("PONG ") + serverName);
}

void Bot::quit()
{
    _connection->writeMessage(std::string("QUIT : Shutting down."));
}

std::istringstream& Bot::_skipToContent(std::istringstream& iss)
{
    char c = 0;
    while(!iss.eof() && c != ':') {
        iss >> c;
    }
    return iss;
}

void Bot::_readHandler(const std::string& message)
{
    LOG_DEBUG("Reading: " + message);

    std::istringstream iss(message);
    std::string command;
    std::string sender = "";
    iss >> command;

    if (command.size() > 1 && command[0] == ':') {
    //this is probably a privmsg
        size_t pos = command.find('!');
        if (pos != std::string::npos) {
            sender = command.substr(1, pos - 1);
            iss >> command;
        }
    }

    if (command == "PRIVMSG") {
        std::string recipient;
        iss >> recipient;
        LOG_DEBUG("PRIVMSG FROM " + sender + " TO " + recipient);

        if(recipient == _nickname) {
            return;
        }

        std::string result;
        if (_parseURL(message, result)) {
            LOG_DEBUG("Found URL: " + result);
            const std::string title = _getTitleFromUrl(result);
            if (sender == _currentChannel) {
                say(title);
            } else {
                msg(sender, title);
            }
        }
    } else if (command == "PING") {
        _skipToContent(iss);
        std::string host;
        iss >> host;
        pong(host);
    }

}

std::string Bot::_getTitleFromUrl(const std::string& url)
{
    std::ostringstream oss;
    curl_writer writer(oss);
    curl::curl_easy easy(writer);
    easy.add(curl_pair<CURLoption,string>(CURLOPT_URL, url) );
    easy.add(curl_pair<CURLoption,long>(CURLOPT_FOLLOWLOCATION, 1L));
    try {
        easy.perform();
    } catch (curl::curl_easy_exception e) {
        std::vector<pair<std::string, std::string>> w = e.what();
        return "Exception: " + w.at(0).first;
    }

    size_t pos = oss.str().find("<title>") + 7;
    size_t pos2 = oss.str().find("</title>");

    if (pos == std::string::npos || pos2 == std::string::npos) {
        return url;
    }

    return oss.str().substr(pos, pos2 - pos);
}

void Bot::_writeHandler()
{
    std::string line, comm;
    while (_connection->isAlive()) {
        std::getline(std::cin, line);
        std::istringstream iss(line);

        iss >> comm;
        if (comm == "/n") {
            iss >> comm;
            nick(comm);
        } else if (comm == "/j") {
            iss >> comm;
            join(comm);
        } else if (comm == "/m") {
            iss >> comm;
            msg(comm, iss.str());
        } else if (comm == "/s") {
            say(iss.str());
        } else if (comm == "/q") {
            iss >> comm;
            quit();
        }
    }
}

bool Bot::_parseURL(const std::string& message, std::string& result)
{
    boost::regex urlRegex;
    try {
        // Source of the regular expression:
        // http://daringfireball.net/2010/07/improved_regex_for_matching_urls
        urlRegex.assign(R"((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))",
                         boost::regex::ECMAScript);
    } catch(boost::regex_error& error) {
        std::cerr << "Invalid regular expression: " << error.what() << std::endl;
        return false;
    }

    boost::smatch matchedElements;
    bool containsURL = boost::regex_search(message, matchedElements, urlRegex);
    result = matchedElements[0];

    return containsURL;
}

}

<|endoftext|>


<commit_before>#include "ButtonPress.h"
#include <assert.h>

ButtonPress::ButtonPress(int pinNum, void(*callback)(void))
	: m_pinNum(pinNum), m_callback(callback)
{
	assert(m_callback != NULL);

	pinMode(m_pinNum, INPUT_PULLUP);

	// Assume pin state at init is the "unpressed" state
	m_unpressedPinState = digitalRead(m_pinNum);
	m_lastPinState = m_unpressedPinState;
}

void ButtonPress::Update()
{
	bool currentPinState = digitalRead(m_pinNum);
	if (currentPinState != m_lastPinState)
	{
		if (currentPinState != m_unpressedPinState)
		{
			m_callback();
		}
	}
}
<commit_msg>Fix state not getting set for button.<commit_after>#include "ButtonPress.h"
#include <assert.h>

ButtonPress::ButtonPress(int pinNum, void(*callback)(void))
	: m_pinNum(pinNum), m_callback(callback)
{
	assert(m_callback != NULL);

	pinMode(m_pinNum, INPUT_PULLUP);

	// Assume pin state at init is the "unpressed" state
	m_unpressedPinState = digitalRead(m_pinNum);
	m_lastPinState = m_unpressedPinState;
}

void ButtonPress::Update()
{
	bool currentPinState = digitalRead(m_pinNum);
	if (currentPinState != m_lastPinState)
	{
		m_lastPinState = currentPinState;
		if (currentPinState != m_unpressedPinState)
		{
			m_callback();
		}
	}
}
<|endoftext|>


<commit_before>/**
 * Template C++ file.
 * Function with references to pointers: func(int *&ptr);
 */
/********************* Header Files ***********************/
/* C++ Headers */
#include <iostream> /* Input/output objects. */
//#include <fstream> /* File operations. */
//#include <sstream> /* String stream. */
#include <string> /* C++ String class. */
//#include <new> /* Defines bad_malloc exception, new functions. */
//#include <typeinfo> /* Casting header. */
//#include <exception> /* Top level exception header. */
//#include <stdexcept> /* Derived exception classes. */

/* STL Headers */
#include <vector>
//#include <list>
//#include <deque>
//#include <stack>
//#include <queue>
//#include <priority_queue>
//#include <bitset>
//#include <set> // multiset for multiple keys allowed.
//#include <map> // multimap for multiple keys allowed.
//#include <utility> // Has pair for map.
//#include <algorithm>
//#include <numeric>
//#include <functional> // Functional objects.
//#include <iterator> // Contains back_inserter function and like.

/* C Headers */
//#include <cstdlib>
//#include <cstddef>
//#include <cctype>
//#include <cstring>
//#include <cstdio>
//#include <climits>
//#include <cassert>

/* Project Headers */
#include "gtest/gtest.h"

/******************* Constants/Macros *********************/

/**************** Namespace Declarations ******************/
using std::cin;
using std::cout;
using std::endl;
using std::string;

/******************* Type Definitions *********************/
/* For enums: Try to namesapce the common elements.
 * typedef enum {
 *	VAL_,
 * } name_e;
 */

/* For structs:
 * typedef struct name_s {
 *	int index;
 * } name_t;
 */

/****************** Class Definitions *********************/

/****************** Global Functions **********************/
int fib(int n) {
	if (n < 0)
		return 0;
	if (n < 2)
		return n;

	int f_n2 = 0, f_n1 = 1, f_n = 0, t = 1;
	while(t++ != n) {
		f_n = f_n2 + f_n1;
		f_n2 = f_n1;
		f_n1 = f_n;
	}

	return f_n;
}

int factorial(int n) {
	if (n < 0)
		return 1;

	return factorial(n-1) * n;
}

void testAssert() {
	std::vector<int> v, v2;
	v.push_back(1);
	v2.push_back(1);

	ASSERT_EQ(v.size(), v2.size());

	for (std::vector<int>::size_type i = 0; i < v.size(); ++i) {
		EXPECT_EQ(v[i], v2[i]) << "Vectors v & v2 differ at index " << i;
	}
}

TEST(FibTest, HandlesZeroInput) {
	EXPECT_EQ(0, fib(0));
}

TEST(FibTest, HandlesPositiveInput) {
	EXPECT_EQ(1, fib(1));
	EXPECT_EQ(1, fib(2));
	EXPECT_EQ(2, fib(3));
	EXPECT_EQ(21, fib(8));
}

/**
 * Main loop of the function.
 */
int main(int argc, char **argv) {
	::testing::InitGoogleTest(&argc, argv);
	testAssert();
	return RUN_ALL_TESTS();
}

/* Notes:
 * Force call to use another version of virtual function: baseP->Item_base::net_price(42);
 *
 */
<commit_msg>More examples with factorial.<commit_after>/**
 * Template C++ file.
 * Function with references to pointers: func(int *&ptr);
 */
/********************* Header Files ***********************/
/* C++ Headers */
#include <iostream> /* Input/output objects. */
//#include <fstream> /* File operations. */
//#include <sstream> /* String stream. */
#include <string> /* C++ String class. */
//#include <new> /* Defines bad_malloc exception, new functions. */
//#include <typeinfo> /* Casting header. */
//#include <exception> /* Top level exception header. */
//#include <stdexcept> /* Derived exception classes. */

/* STL Headers */
#include <vector>
//#include <list>
//#include <deque>
//#include <stack>
//#include <queue>
//#include <priority_queue>
//#include <bitset>
//#include <set> // multiset for multiple keys allowed.
//#include <map> // multimap for multiple keys allowed.
//#include <utility> // Has pair for map.
//#include <algorithm>
//#include <numeric>
//#include <functional> // Functional objects.
//#include <iterator> // Contains back_inserter function and like.

/* C Headers */
//#include <cstdlib>
//#include <cstddef>
//#include <cctype>
//#include <cstring>
//#include <cstdio>
//#include <climits>
//#include <cassert>

/* Project Headers */
#include "gtest/gtest.h"

/******************* Constants/Macros *********************/

/**************** Namespace Declarations ******************/
using std::cin;
using std::cout;
using std::endl;
using std::string;

/******************* Type Definitions *********************/
/* For enums: Try to namesapce the common elements.
 * typedef enum {
 *	VAL_,
 * } name_e;
 */

/* For structs:
 * typedef struct name_s {
 *	int index;
 * } name_t;
 */

/****************** Class Definitions *********************/

/****************** Global Functions **********************/
int fib(int n) {
	if (n < 0)
		return 0;
	if (n < 2)
		return n;

	int f_n2 = 0, f_n1 = 1, f_n = 0, t = 1;
	while(t++ != n) {
		f_n = f_n2 + f_n1;
		f_n2 = f_n1;
		f_n1 = f_n;
	}

	return f_n;
}

int factorial(int n) {
	if (n <= 1)
		return 1;

	int fact = 1;
	do {
		fact *= n;
		cout << n << '-' << fact << std::endl;
	} while (n-- != 1);

	return fact;
}

void testAssert() {
	std::vector<int> v, v2;
	v.push_back(1);
	v2.push_back(1);

	ASSERT_EQ(v.size(), v2.size());

	for (std::vector<int>::size_type i = 0; i < v.size(); ++i) {
		EXPECT_EQ(v[i], v2[i]) << "Vectors v & v2 differ at index " << i;
	}
}

TEST(FibTest, HandlesZeroInput) {
	EXPECT_EQ(0, fib(0));
}

TEST(FibTest, HandlesPositiveInput) {
	EXPECT_EQ(1, fib(1));
	EXPECT_EQ(1, fib(2));
	EXPECT_EQ(2, fib(3));
	EXPECT_EQ(21, fib(8));
}

TEST(FactTest, HandlesPositiveInput) {
	EXPECT_EQ(1, factorial(1));
	EXPECT_EQ(6, factorial(3));
	EXPECT_EQ(720, factorial(6));
	EXPECT_EQ(5040, factorial(7));
}

/**
 * Main loop of the function.
 */
int main(int argc, char **argv) {
	::testing::InitGoogleTest(&argc, argv);
	testAssert();
	return RUN_ALL_TESTS();
}

/* Notes:
 * Force call to use another version of virtual function: baseP->Item_base::net_price(42);
 *
 */
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Matthew Harvey
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "gui/account_list_ctrl.hpp"
#include "app.hpp"
#include "account.hpp"
#include "account_table_iterator.hpp"
#include "account_type.hpp"
#include "finformat.hpp"
#include "dcm_database_connection.hpp"
#include "string_flags.hpp"
#include "gui/account_dialog.hpp"
#include "gui/locale.hpp"
#include "gui/persistent_object_event.hpp"
#include "gui/top_panel.hpp"
#include <jewel/assert.hpp>
#include <sqloxx/handle.hpp>
#include <wx/event.h>
#include <wx/listctrl.h>
#include <wx/notebook.h>
#include <wx/string.h>
#include <algorithm>
#include <set>

using sqloxx::Handle;
using std::is_signed;
using std::max;
using std::set;

namespace dcm
{
namespace gui
{

BEGIN_EVENT_TABLE(AccountListCtrl, wxListCtrl)
    EVT_LIST_ITEM_ACTIVATED
    (   wxID_ANY,
        AccountListCtrl::on_item_activated
    )
END_EVENT_TABLE()

AccountListCtrl::AccountListCtrl
(   wxWindow* p_parent,
    DcmDatabaseConnection& p_database_connection,
    AccountSuperType p_account_super_type
):
    wxListCtrl
    (   p_parent,
        wxID_ANY,
        wxDefaultPosition,
        wxSize
        (   p_parent->GetClientSize().GetX() / 4,
            p_parent->GetClientSize().GetY()
        ),
        wxLC_REPORT | wxLC_SINGLE_SEL | wxFULL_REPAINT_ON_RESIZE
    ),
    m_show_hidden(false),
    m_account_super_type(p_account_super_type),
    m_database_connection(p_database_connection)
{
    update();
}

AccountListCtrl::~AccountListCtrl()
{
}

set<sqloxx::Id>
AccountListCtrl::selected_accounts() const
{
    set<sqloxx::Id> ret;
    size_t i = 0;
    size_t const lim = GetItemCount();
    for ( ; i != lim; ++i)
    {
        if (GetItemState(i, wxLIST_STATE_SELECTED))
        {
            Handle<Account> const account
            (   m_database_connection,
                GetItemData(i)
            );
            JEWEL_ASSERT (account->has_id());
            ret.insert(account->id());
        }
    }
    return ret;
}

void
AccountListCtrl::on_item_activated(wxListEvent& event)
{
    JEWEL_LOG_TRACE();
    sqloxx::Id const account_id = GetItemData(event.GetIndex());

    // Fire an Account editing request. This will be handled higher up
    // the window hierarchy.
    PersistentObjectEvent::fire
    (   this,
        DCM_ACCOUNT_EDITING_EVENT,
        account_id
    );
    JEWEL_LOG_TRACE();
    return;
 }

void
AccountListCtrl::update()
{
    // Remember which rows are selected currently
    set<sqloxx::Id> const selected = selected_accounts();

    // Now (re)draw
    ClearAll();
    InsertColumn
    (   s_name_col,
        account_concept_name
        (   m_account_super_type,
            AccountPhraseFlags().set(string_flags::capitalize)
        ),
        wxLIST_FORMAT_LEFT
    );
    InsertColumn
    (   s_balance_col,
        wxString("Balance"),
        wxLIST_FORMAT_RIGHT
    );
    if (showing_daily_budget())
    {
        InsertColumn(s_budget_col, "Daily top-up", wxLIST_FORMAT_RIGHT);
    }

    long i = 0;  // because wxWidgets uses long
    AccountTableIterator it = make_type_name_ordered_account_table_iterator
    (   m_database_connection
    );
    AccountTableIterator const end;
    for ( ; it != end; ++it)
    {
        Handle<Account> const& account = *it;
        if
        (   (account->account_super_type() == m_account_super_type) &&
            (m_show_hidden || (account->visibility() == Visibility::visible))
        )
        {
            // Insert item, with string for Column 0
            InsertItem(i, account->name());

            JEWEL_ASSERT (account->has_id());
            auto const id = account->id();
            static_assert
            (   (sizeof(id) <= sizeof(long)) &&
                is_signed<decltype(id)>::value &&
                is_signed<long>::value,
                "Object Id is too wide to be safely passed to "
                "SetItemData."
            );
            SetItemData(i, id);

            // Insert the balance string
            SetItem
            (   i,
                s_balance_col,
                finformat_wx(account->friendly_balance(), locale())
            );

            if (showing_daily_budget())
            {
                // Insert budget string
                SetItem
                (   i,
                    s_budget_col,
                    finformat_wx(account->budget(), locale())
                );
            }

            ++i;
        }
    }

    // Reinstate the selections we remembered
    for (size_t j = 0, lim = GetItemCount(); j != lim; ++j)
    {
        Handle<Account> const account
        (   m_database_connection,
            GetItemData(j)
        );
        JEWEL_ASSERT (account->has_id());
        if (selected.find(account->id()) != selected.end())
        {
            SetItemState
            (   j,
                wxLIST_STATE_SELECTED,
                wxLIST_STATE_SELECTED
            );
        }
    }

    // Configure column widths
    SetColumnWidth(s_name_col, wxLIST_AUTOSIZE_USEHEADER);
    SetColumnWidth(s_name_col, max(GetColumnWidth(s_name_col), 200));
    SetColumnWidth(s_balance_col, wxLIST_AUTOSIZE);
    SetColumnWidth(s_balance_col, max(GetColumnWidth(s_balance_col), 90));
    if (showing_daily_budget())
    {
        SetColumnWidth(s_budget_col, wxLIST_AUTOSIZE);
        SetColumnWidth(s_budget_col, max(GetColumnWidth(s_budget_col), 90));
    }

    Layout();

    return;
}

bool
AccountListCtrl::showing_daily_budget() const
{
    return m_account_super_type == AccountSuperType::pl;
}

Handle<Account>
AccountListCtrl::default_account() const
{
    Handle<Account> ret;
    if (GetItemCount() != 0)
    {
        // Return the first Account that is actually showing in the
        // control.
        JEWEL_ASSERT (GetItemCount() > 0);
        ret = Handle<Account>(m_database_connection, GetItemData(GetTopItem()));
    }
    else
    {
        // Return the an Account of the AccountSuperType of this control,
        // even though not showing in the control (because hidden).
        AccountTableIterator it = make_type_name_ordered_account_table_iterator
        (   m_database_connection
        );
        AccountTableIterator const end;
        for ( ; it != end; ++it)
        {
            Handle<Account> const account = *it;
            if (account->account_super_type() == m_account_super_type)
            {
                ret = account;
                break;
            }
        }
    }
    return ret;
}

void
AccountListCtrl::select_only(Handle<Account> const& p_account)
{
    JEWEL_ASSERT (p_account->has_id());  // precondition

    size_t const sz = GetItemCount();
    for (size_t i = 0; i != sz; ++i)
    {
        Handle<Account> const account(m_database_connection, GetItemData(i));
        long const filter = (wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
        long const flags = ((account == p_account)? filter: 0);
        SetItemState(i, flags, filter);
    }
    return;
}

bool
AccountListCtrl::toggle_showing_hidden()
{
    m_show_hidden = !m_show_hidden;
    update();
    return m_show_hidden;
}

}  // namespace gui
}  // namespace dcm
<commit_msg>Make AccountListCtrl retain its scrolled position after update.<commit_after>/*
 * Copyright 2013 Matthew Harvey
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "gui/account_list_ctrl.hpp"
#include "app.hpp"
#include "account.hpp"
#include "account_table_iterator.hpp"
#include "account_type.hpp"
#include "finformat.hpp"
#include "dcm_database_connection.hpp"
#include "string_flags.hpp"
#include "gui/account_dialog.hpp"
#include "gui/locale.hpp"
#include "gui/persistent_object_event.hpp"
#include "gui/top_panel.hpp"
#include <jewel/assert.hpp>
#include <sqloxx/handle.hpp>
#include <wx/event.h>
#include <wx/listctrl.h>
#include <wx/notebook.h>
#include <wx/string.h>
#include <algorithm>
#include <set>

using sqloxx::Handle;
using std::is_signed;
using std::max;
using std::set;

namespace dcm
{
namespace gui
{

BEGIN_EVENT_TABLE(AccountListCtrl, wxListCtrl)
    EVT_LIST_ITEM_ACTIVATED
    (   wxID_ANY,
        AccountListCtrl::on_item_activated
    )
END_EVENT_TABLE()

AccountListCtrl::AccountListCtrl
(   wxWindow* p_parent,
    DcmDatabaseConnection& p_database_connection,
    AccountSuperType p_account_super_type
):
    wxListCtrl
    (   p_parent,
        wxID_ANY,
        wxDefaultPosition,
        wxSize
        (   p_parent->GetClientSize().GetX() / 4,
            p_parent->GetClientSize().GetY()
        ),
        wxLC_REPORT | wxLC_SINGLE_SEL | wxFULL_REPAINT_ON_RESIZE
    ),
    m_show_hidden(false),
    m_account_super_type(p_account_super_type),
    m_database_connection(p_database_connection)
{
    update();
}

AccountListCtrl::~AccountListCtrl()
{
}

set<sqloxx::Id>
AccountListCtrl::selected_accounts() const
{
    set<sqloxx::Id> ret;
    size_t i = 0;
    size_t const lim = GetItemCount();
    for ( ; i != lim; ++i)
    {
        if (GetItemState(i, wxLIST_STATE_SELECTED))
        {
            Handle<Account> const account
            (   m_database_connection,
                GetItemData(i)
            );
            JEWEL_ASSERT (account->has_id());
            ret.insert(account->id());
        }
    }
    return ret;
}

void
AccountListCtrl::on_item_activated(wxListEvent& event)
{
    JEWEL_LOG_TRACE();
    sqloxx::Id const account_id = GetItemData(event.GetIndex());

    // Fire an Account editing request. This will be handled higher up
    // the window hierarchy.
    PersistentObjectEvent::fire
    (   this,
        DCM_ACCOUNT_EDITING_EVENT,
        account_id
    );
    JEWEL_LOG_TRACE();
    return;
 }

void
AccountListCtrl::update()
{
    // Remember which rows are selected currently
    auto const selected = selected_accounts();

    // Remember scrolled position
    auto const item_count = GetItemCount();
    auto const top_item = GetTopItem();
    auto const last_item = item_count - 1;
    auto const last_position = top_item + GetCountPerPage();
    auto const bottom_item = ((last_position < last_item) ? last_position : last_item);

    // Now (re)draw
    ClearAll();
    InsertColumn
    (   s_name_col,
        account_concept_name
        (   m_account_super_type,
            AccountPhraseFlags().set(string_flags::capitalize)
        ),
        wxLIST_FORMAT_LEFT
    );
    InsertColumn
    (   s_balance_col,
        wxString("Balance"),
        wxLIST_FORMAT_RIGHT
    );
    if (showing_daily_budget())
    {
        InsertColumn(s_budget_col, "Daily top-up", wxLIST_FORMAT_RIGHT);
    }

    long i = 0;  // because wxWidgets uses long
    AccountTableIterator it = make_type_name_ordered_account_table_iterator
    (   m_database_connection
    );
    AccountTableIterator const end;
    for ( ; it != end; ++it)
    {
        Handle<Account> const& account = *it;
        if
        (   (account->account_super_type() == m_account_super_type) &&
            (m_show_hidden || (account->visibility() == Visibility::visible))
        )
        {
            // Insert item, with string for Column 0
            InsertItem(i, account->name());

            JEWEL_ASSERT (account->has_id());
            auto const id = account->id();
            static_assert
            (   (sizeof(id) <= sizeof(long)) &&
                is_signed<decltype(id)>::value &&
                is_signed<long>::value,
                "Object Id is too wide to be safely passed to "
                "SetItemData."
            );
            SetItemData(i, id);

            // Insert the balance string
            SetItem
            (   i,
                s_balance_col,
                finformat_wx(account->friendly_balance(), locale())
            );

            if (showing_daily_budget())
            {
                // Insert budget string
                SetItem
                (   i,
                    s_budget_col,
                    finformat_wx(account->budget(), locale())
                );
            }

            ++i;
        }
    }

    // Reinstate the selections we remembered
    for (size_t j = 0, lim = GetItemCount(); j != lim; ++j)
    {
        Handle<Account> const account
        (   m_database_connection,
            GetItemData(j)
        );
        JEWEL_ASSERT (account->has_id());
        if (selected.find(account->id()) != selected.end())
        {
            SetItemState
            (   j,
                wxLIST_STATE_SELECTED,
                wxLIST_STATE_SELECTED
            );
        }
    }

    // Configure column widths
    SetColumnWidth(s_name_col, wxLIST_AUTOSIZE_USEHEADER);
    SetColumnWidth(s_name_col, max(GetColumnWidth(s_name_col), 200));
    SetColumnWidth(s_balance_col, wxLIST_AUTOSIZE);
    SetColumnWidth(s_balance_col, max(GetColumnWidth(s_balance_col), 90));
    if (showing_daily_budget())
    {
        SetColumnWidth(s_budget_col, wxLIST_AUTOSIZE);
        SetColumnWidth(s_budget_col, max(GetColumnWidth(s_budget_col), 90));
    }

    // Reinstate scrolled position
    if (bottom_item > 0) EnsureVisible(bottom_item - 1);

    Layout();

    return;
}

bool
AccountListCtrl::showing_daily_budget() const
{
    return m_account_super_type == AccountSuperType::pl;
}

Handle<Account>
AccountListCtrl::default_account() const
{
    Handle<Account> ret;
    if (GetItemCount() != 0)
    {
        // Return the first Account that is actually showing in the
        // control.
        JEWEL_ASSERT (GetItemCount() > 0);
        ret = Handle<Account>(m_database_connection, GetItemData(GetTopItem()));
    }
    else
    {
        // Return the an Account of the AccountSuperType of this control,
        // even though not showing in the control (because hidden).
        AccountTableIterator it = make_type_name_ordered_account_table_iterator
        (   m_database_connection
        );
        AccountTableIterator const end;
        for ( ; it != end; ++it)
        {
            Handle<Account> const account = *it;
            if (account->account_super_type() == m_account_super_type)
            {
                ret = account;
                break;
            }
        }
    }
    return ret;
}

void
AccountListCtrl::select_only(Handle<Account> const& p_account)
{
    JEWEL_ASSERT (p_account->has_id());  // precondition

    size_t const sz = GetItemCount();
    for (size_t i = 0; i != sz; ++i)
    {
        Handle<Account> const account(m_database_connection, GetItemData(i));
        long const filter = (wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
        long const flags = ((account == p_account)? filter: 0);
        SetItemState(i, flags, filter);
    }
    return;
}

bool
AccountListCtrl::toggle_showing_hidden()
{
    m_show_hidden = !m_show_hidden;
    update();
    return m_show_hidden;
}

}  // namespace gui
}  // namespace dcm
<|endoftext|>


<commit_before>#include "rosplan_planning_system/PlannerInterface/FFPlannerInterface.h"

namespace KCL_rosplan {

	/*-------------*/
	/* constructor */
	/*-------------*/

	FFPlannerInterface::FFPlannerInterface(ros::NodeHandle& nh)
	{
		node_handle = &nh;

		plan_server = new actionlib::SimpleActionServer<rosplan_dispatch_msgs::PlanAction>((*node_handle), "start_planning", boost::bind(&PlannerInterface::runPlanningServerAction, this, _1), false);

		// publishing raw planner output
		std::string plannerTopic = "planner_output";
		node_handle->getParam("planner_topic", plannerTopic);
		plan_publisher = node_handle->advertise<std_msgs::String>(plannerTopic, 1, true);

		// start planning action server
		plan_server->start();
	}

	FFPlannerInterface::~FFPlannerInterface()
	{
		delete plan_server;
	}

	/**
	 * Runs external commands
	 */
	std::string FFPlannerInterface::runCommand(std::string cmd) {
		std::string data;
		FILE *stream;
		char buffer[1000];
		stream = popen(cmd.c_str(), "r");
		while ( fgets(buffer, 1000, stream) != NULL )
			data.append(buffer);
		pclose(stream);
		return data;
	}

	/*------------------*/
	/* Plan and process */
	/*------------------*/

	/**
	 * passes the problem to the Planner; the plan to post-processing.
	 */
	bool FFPlannerInterface::runPlanner() {
		planner_output.clear(); // Clear previous plan
		// save problem to file for planner
		if(use_problem_topic && problem_instance_received) {
			ROS_INFO("KCL: (%s) (%s) Writing problem to file.", ros::this_node::getName().c_str(), problem_name.c_str());
			std::ofstream dest;
			dest.open((problem_path).c_str());
			dest << problem_instance;
			dest.close();
		}

		// prepare the planner command line
		std::string str = planner_command;
		std::size_t dit = str.find("DOMAIN");
		if(dit!=std::string::npos) str.replace(dit,6,domain_path);
		std::size_t pit = str.find("PROBLEM");
		if(pit!=std::string::npos) str.replace(pit,7,problem_path);
		std::string commandString = str + " > " + data_path + "plan.pddl";

		// call the planer
		ROS_INFO("KCL: (%s) (%s) Running: %s", ros::this_node::getName().c_str(), problem_name.c_str(),  commandString.c_str());
		std::string plan = runCommand(commandString.c_str());
		ROS_INFO("KCL: (%s) (%s) Planning complete", ros::this_node::getName().c_str(), problem_name.c_str());

		// check the planner solved the problem
		std::ifstream planfile;
		planfile.open((data_path + "plan.pddl").c_str());
		std::string line;

		bool solved = false;
		while (not solved and std::getline(planfile, line)) {
			// skip lines until there is a plan
			if (line.find("ff: found legal plan") != line.npos) {
				solved = true;
			}
		}

		// Parse the solved plan
		if (solved) {
			std::getline(planfile, line); //go to first action line
			// First iteration line will be like   0: got_place C1
			while (line.find("cost of plan") == line.npos and line.find("time spend") == line.npos and line.size() > 0) {
				ROS_INFO(line.c_str());
				std::stringstream ss(line); // To trim whitespaces
				std::string aux;
				// Read the action number X:
				ss >> aux;
				planner_output += aux + " "; // Add parenthesis before the action
				while (ss >> aux) { // Read the rest
					planner_output += aux;
					if (ss.good()) planner_output += " "; // Add a whitespace unless we have processed all the line
				}
				planner_output += "  [0.001]\n"; // Close parenthesis and add duration
				std::getline(planfile, line);
			}
			// Convert to lowercase as FF prints all the actions and parameters in uppercase
			std::transform(planner_output.begin(), planner_output.end(), planner_output.begin(), ::tolower);
		}
		planfile.close();

		if(!solved) ROS_INFO("KCL: (%s) (%s) Plan was unsolvable.", ros::this_node::getName().c_str(), problem_name.c_str());
		else ROS_INFO("KCL: (%s) (%s) Plan was solved.", ros::this_node::getName().c_str(), problem_name.c_str());

		return solved;
	}

} // close namespace

	/*-------------*/
	/* Main method */
	/*-------------*/

	int main(int argc, char **argv) {

		srand (static_cast <unsigned> (time(0)));

		ros::init(argc,argv,"rosplan_planner_interface");
		ros::NodeHandle nh("~");

		KCL_rosplan::FFPlannerInterface pi(nh);

		// subscribe to problem instance
		std::string problemTopic = "problem_instance";
		nh.getParam("problem_topic", problemTopic);
		ros::Subscriber problem_sub = nh.subscribe(problemTopic, 1, &KCL_rosplan::PlannerInterface::problemCallback, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));

		// start the planning services
		ros::ServiceServer service1 = nh.advertiseService("planning_server", &KCL_rosplan::PlannerInterface::runPlanningServerDefault, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));
		ros::ServiceServer service2 = nh.advertiseService("planning_server_params", &KCL_rosplan::PlannerInterface::runPlanningServerParams, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));

		ROS_INFO("KCL: (%s) Ready to receive", ros::this_node::getName().c_str());
		ros::spin();

		return 0;
	}
<commit_msg>Remove a ROS_INFO<commit_after>#include "rosplan_planning_system/PlannerInterface/FFPlannerInterface.h"

namespace KCL_rosplan {

	/*-------------*/
	/* constructor */
	/*-------------*/

	FFPlannerInterface::FFPlannerInterface(ros::NodeHandle& nh)
	{
		node_handle = &nh;

		plan_server = new actionlib::SimpleActionServer<rosplan_dispatch_msgs::PlanAction>((*node_handle), "start_planning", boost::bind(&PlannerInterface::runPlanningServerAction, this, _1), false);

		// publishing raw planner output
		std::string plannerTopic = "planner_output";
		node_handle->getParam("planner_topic", plannerTopic);
		plan_publisher = node_handle->advertise<std_msgs::String>(plannerTopic, 1, true);

		// start planning action server
		plan_server->start();
	}

	FFPlannerInterface::~FFPlannerInterface()
	{
		delete plan_server;
	}

	/**
	 * Runs external commands
	 */
	std::string FFPlannerInterface::runCommand(std::string cmd) {
		std::string data;
		FILE *stream;
		char buffer[1000];
		stream = popen(cmd.c_str(), "r");
		while ( fgets(buffer, 1000, stream) != NULL )
			data.append(buffer);
		pclose(stream);
		return data;
	}

	/*------------------*/
	/* Plan and process */
	/*------------------*/

	/**
	 * passes the problem to the Planner; the plan to post-processing.
	 */
	bool FFPlannerInterface::runPlanner() {
		planner_output.clear(); // Clear previous plan
		// save problem to file for planner
		if(use_problem_topic && problem_instance_received) {
			ROS_INFO("KCL: (%s) (%s) Writing problem to file.", ros::this_node::getName().c_str(), problem_name.c_str());
			std::ofstream dest;
			dest.open((problem_path).c_str());
			dest << problem_instance;
			dest.close();
		}

		// prepare the planner command line
		std::string str = planner_command;
		std::size_t dit = str.find("DOMAIN");
		if(dit!=std::string::npos) str.replace(dit,6,domain_path);
		std::size_t pit = str.find("PROBLEM");
		if(pit!=std::string::npos) str.replace(pit,7,problem_path);
		std::string commandString = str + " > " + data_path + "plan.pddl";

		// call the planer
		ROS_INFO("KCL: (%s) (%s) Running: %s", ros::this_node::getName().c_str(), problem_name.c_str(),  commandString.c_str());
		std::string plan = runCommand(commandString.c_str());
		ROS_INFO("KCL: (%s) (%s) Planning complete", ros::this_node::getName().c_str(), problem_name.c_str());

		// check the planner solved the problem
		std::ifstream planfile;
		planfile.open((data_path + "plan.pddl").c_str());
		std::string line;

		bool solved = false;
		while (not solved and std::getline(planfile, line)) {
			// skip lines until there is a plan
			if (line.find("ff: found legal plan") != line.npos) {
				solved = true;
			}
		}

		// Parse the solved plan
		if (solved) {
			std::getline(planfile, line); //go to first action line
			// First iteration line will be like   0: got_place C1
			while (line.find("cost of plan") == line.npos and line.find("time spend") == line.npos and line.size() > 0) {
				std::stringstream ss(line); // To trim whitespaces
				std::string aux;
				// Read the action number X:
				ss >> aux;
				planner_output += aux + " "; // Add parenthesis before the action
				while (ss >> aux) { // Read the rest
					planner_output += aux;
					if (ss.good()) planner_output += " "; // Add a whitespace unless we have processed all the line
				}
				planner_output += "  [0.001]\n"; // Close parenthesis and add duration
				std::getline(planfile, line);
			}
			// Convert to lowercase as FF prints all the actions and parameters in uppercase
			std::transform(planner_output.begin(), planner_output.end(), planner_output.begin(), ::tolower);
		}
		planfile.close();

		if(!solved) ROS_INFO("KCL: (%s) (%s) Plan was unsolvable.", ros::this_node::getName().c_str(), problem_name.c_str());
		else ROS_INFO("KCL: (%s) (%s) Plan was solved.", ros::this_node::getName().c_str(), problem_name.c_str());

		return solved;
	}

} // close namespace

	/*-------------*/
	/* Main method */
	/*-------------*/

	int main(int argc, char **argv) {

		srand (static_cast <unsigned> (time(0)));

		ros::init(argc,argv,"rosplan_planner_interface");
		ros::NodeHandle nh("~");

		KCL_rosplan::FFPlannerInterface pi(nh);

		// subscribe to problem instance
		std::string problemTopic = "problem_instance";
		nh.getParam("problem_topic", problemTopic);
		ros::Subscriber problem_sub = nh.subscribe(problemTopic, 1, &KCL_rosplan::PlannerInterface::problemCallback, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));

		// start the planning services
		ros::ServiceServer service1 = nh.advertiseService("planning_server", &KCL_rosplan::PlannerInterface::runPlanningServerDefault, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));
		ros::ServiceServer service2 = nh.advertiseService("planning_server_params", &KCL_rosplan::PlannerInterface::runPlanningServerParams, dynamic_cast<KCL_rosplan::PlannerInterface*>(&pi));

		ROS_INFO("KCL: (%s) Ready to receive", ros::this_node::getName().c_str());
		ros::spin();

		return 0;
	}
<|endoftext|>