Skip to main content.
Find on this site:

Me as a baby.Mark A. Taff
Location: Home Code Viewer
  1.  /** @file
  2.   * This file contains the KGameSvgDocument class, used for manipulating
  3.   * an SVG file using DOM.
  4.   */
  5.  
  6.  /***************************************************************************
  7.   * Copyright (C) 2007 Mark A. Taff <kde@marktaff.com> *
  8.   * *
  9.   * This program is free software; you can redistribute it and/or modify *
  10.   * it under the terms of the GNU Library General Public License *
  11.   * version 2 as published by the Free Software Foundation *
  12.   * *
  13.   * This program is distributed in the hope that it will be useful, *
  14.   * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  15.   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  16.   * GNU Library General Public License for more details. *
  17.   * *
  18.   * You should have received a copy of the GNU Library General Public *
  19.   * License along with this program; if not, write to the *
  20.   * Free Software Foundation, Inc., *
  21.   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
  22.   ***************************************************************************/
  23.  
  24.  #ifndef _KGAMESVGDOCUMENT_H_
  25.  #define _KGAMESVGDOCUMENT_H_
  26.  
  27.  #include <QtCore/QHash>
  28.  #include <QtCore/QStringList>
  29.  #include <QtGui/QMatrix>
  30.  #include <QtXml/QDomDocument>
  31.  #include <libkdegames_export.h>
  32.  
  33.  
  34.  class KGameSvgDocumentPrivate;
  35.  
  36.  /**
  37.   * @brief A class for manipulating an SVG file using DOM
  38.   *
  39.   * This class is a wrapper around QDomDocument for SVG files.
  40.   * It:
  41.   * @li implements elementById();
  42.   * @li manipulates a node's style properties; and,
  43.   * @li manipulates a node's transform properties.
  44.   *
  45.   * @note The DOM standard requires all changes to be "live", so we cannot cache any values
  46.   * from the file; instead, we always have to query the DOM for the current value. This also
  47.   * means that style & matrix changes we make happen to the DOM immediately.
  48.   *
  49.   * A typical use is to read in an SVG file, edit the style or transform attributes
  50.   * in DOM as desired, and then output a QByteArray suitable for being loaded with
  51.   * KSvgRenderer::load().
  52.   *
  53.   * To read an SVG file into DOM:
  54.   * @code
  55.   * KGameSvgDocument svgDom;
  56.   * svgDom.load("/path/to/svgFile.svg");
  57.   * @endcode
  58.   *
  59.   * To find a node with a specific value in its id attribute, for example where id="playerOneGamepiece":
  60.   * @code
  61.   * QDomNode playerOneGamepiece = svgDom.elementById("playerOneGamepiece");
  62.   *
  63.   * // This works too
  64.   * QDomNode playerOneGamepiece = svgDom.elementByUniqueAttributeValue("id", "playerOneGamepiece");
  65.   * @endcode
  66.   *
  67.   * Most methods operate on the last node found by @c elementById() or @c elementByUniqueAttributeValue().
  68.   * If the methods are working on the wrong node, then you are mistaken about which node was
  69.   * the last node (or you found a bug). Try calling @c setCurrentNode() with the node you are
  70.   * wanting to modify to see if this is the issue. Consider the following code for example:
  71.   * @code
  72.   * QDomNode playerOneGamepiece = svgDom.elementById("playerOneGamepiece");
  73.   * QDomNode playerTwoGamepiece = svgDom.elementById("playerTwoGamepiece");
  74.   *
  75.   * // Set player one's game piece to have a white fill
  76.   * svgDom.setStyleProperty("fill", "#ffffff"); // INCORRECT: playerTwoGamepiece is the last node, not playerOneGamepiece
  77.   *
  78.   * svgDom.setCurrentNode(playerOneGamepiece); // CORRECT: Set current node to the node we want,
  79.   * svgDom.setStyleProperty("fill", "#ffffff"); // then we modify the node
  80.   * @endcode
  81.   *
  82.   * To skew the @c currentNode():
  83.   * @code
  84.   * // Skew the horizontal axis 7.5 degrees
  85.   * svgDom.skew(-7.5, 0, KGameSvgDocument::ReplaceCurrentMatrix);
  86.   * @endcode
  87.   *
  88.   * @warning Be careful when using the KGameSvgDocument::ApplyToCurrentMatrix flag. It multiplies the matrices,
  89.   * so if you repeatedly apply the same matrix to a node, you have a polynomial series @c x^2, and you will
  90.   * very quickly run into overflow issues.
  91.   *
  92.   * To output @c currentNode() to be rendered:
  93.   * @code
  94.   * KSvgRenderer svgRenderer;
  95.   * QByteArray svg = svgDom.nodeToByteArray();
  96.   * svgRenderer.load(svg);
  97.   * @endcode
  98.   *
  99.   * To output the whole document to be rendered (See QDomDocument::toByteArray()):
  100.   * @code
  101.   * KSvgRenderer svgRenderer;
  102.   * QByteArray svg = svgDom.toByteArray();
  103.   * svgRenderer.load(svg);
  104.   * @endcode
  105.   *
  106.   * @see QDomDocument, KSvgRenderer
  107.   * @author Mark A. Taff \<kde@marktaff.com\>
  108.   * @version 0.1
  109.   *
  110.   * @todo Add convenience functions for getting/setting individual style properties.
  111.   * I haven't completely convinced myself of the utility of this, so don't hold your breathe. ;-)
  112.   */
  113.  class KDEGAMES_EXPORT KGameSvgDocument : public QDomDocument
  114.  {
  115.  public:
  116.   /**
  117.   * @brief Constructor
  118.   */
  119.   explicit KGameSvgDocument();
  120.  
  121.   /**
  122.   * @brief Copy Constructor
  123.   */
  124.   KGameSvgDocument(const KGameSvgDocument &doc);
  125.  
  126.   /**
  127.   * @brief Destructor
  128.   */
  129.   virtual ~KGameSvgDocument();
  130.  
  131.   /**
  132.   * @brief Assignment Operator
  133.   */
  134.   KGameSvgDocument& operator=(const KGameSvgDocument &doc);
  135.  
  136.   /**
  137.   * @brief Options for applying (multiplying) or replacing the current matrix
  138.   */
  139.   enum MatrixOption {
  140.   /**
  141.   * Apply to current matrix
  142.   */
  143.   ApplyToCurrentMatrix = 0x01,
  144.   /**
  145.   * Replace the current matrix
  146.   */
  147.   ReplaceCurrentMatrix = 0x02
  148.   };
  149.   /** @brief Q_DECLARE_FLAGS macro confuses doxygen, so create typedef's manually */
  150.   typedef QFlags<MatrixOption> MatrixOptions;
  151.  
  152.   /**
  153.   * Options for sorting style properties when building a style attribute
  154.   */
  155.   enum StylePropertySortOption {
  156.   /**
  157.   * When building a style attribute, do not sort
  158.   */
  159.   Unsorted = 0x01,
  160.   /**
  161.   * When building a style attribute, sort properties the same way Inkscape does
  162.   */
  163.   UseInkscapeOrder = 0x02
  164.   };
  165.   /** @brief Q_DECLARE_FLAGS macro confuses doxygen, so create typedef's manually */
  166.   typedef QFlags<StylePropertySortOption> StylePropertySortOptions;
  167.  
  168.   /**
  169.   * @brief Returns the node with the given value for the given attribute.
  170.   *
  171.   * Returns the element whose attribute given in @p attributeName is equal to the value
  172.   * given in @p attributeValue.
  173.   *
  174.   * QDomDocument::elementById() always returns a null node because TT says they can't know
  175.   * which attribute is the id attribute. Here, we allow the id attribute to be specified.
  176.   *
  177.   * This function also sets @p m_currentNode to this node.
  178.   *
  179.   * @param attributeName The name of the identifing attribute, such as "id" to find.
  180.   * @param attributeValue The value to look for in the attribute @p attributeName
  181.   * The values held in this attribute must be unique in the document, or the consequences
  182.   * may be unpredictably incorrect. You've been warned. ;-)
  183.   * @returns the matching node, or a null node if no matching node found
  184.   */
  185.   QDomNode elementByUniqueAttributeValue(const QString& attributeName, const QString& attributeValue);
  186.  
  187.   /**
  188.   * @brief Returns a node with the given id.
  189.   *
  190.   * This is a convenience function. We call elementByUniqueAttributeValue(), but we assume
  191.   * that the name of the attribute is "id". This assumption will be correct for valid SVG files.
  192.   *
  193.   * Returns the element whose ID is equal to elementId. If no element with the ID was found,
  194.   * this function returns a null element.
  195.   *
  196.   * @param attributeValue The value of the id attribute to find
  197.   * @returns the matching node, or a null node if no matching node found
  198.   * @see elementByUniqueAttributeValue()
  199.   */
  200.   QDomNode elementById(const QString& attributeValue);
  201.  
  202.   /**
  203.   * @brief Reads the SVG file svgFilename() into DOM.
  204.   * @returns nothing
  205.   */
  206.   void load();
  207.  
  208.   /**
  209.   * @overload
  210.   * @brief This function permits specifying the svg file and loading it at once.
  211.   *
  212.   * @param svgFilename The filename of the SVG file to open.
  213.   * @returns nothing
  214.   */
  215.   void load(const QString& svgFilename);
  216.  
  217.   /**
  218.   * @brief Rotates the origin of the current node counterclockwise.
  219.   *
  220.   * @param degrees The amount in degrees to rotate by.
  221.   * @param options Apply to current matrix or replace current matrix.
  222.   * @returns nothing
  223.   * @see QMatrix#rotate()
  224.   */
  225.   void rotate(double degrees, const MatrixOptions& options = ApplyToCurrentMatrix);
  226.  
  227.   /**
  228.   * @brief Moves the origin of the current node
  229.   *
  230.   * @param xPixels The number of pixels to move the x-axis by.
  231.   * @param yPixels The number of pixels to move the y-axis by.
  232.   * @param options Apply to current matrix or replace current matrix.
  233.   * @returns nothing
  234.   * @see QMatrix::translate()
  235.   */
  236.   void translate(int xPixels, int yPixels, const MatrixOptions& options = ApplyToCurrentMatrix);
  237.  
  238.   /**
  239.   * @brief Shears the origin of the current node.
  240.   *
  241.   * @param xRadians The amount in radians to shear (skew) the x-axis by.
  242.   * @param yRadians The amount in radians to shear (skew) the y-axis by.
  243.   * @param options Apply to current matrix or replace current matrix.
  244.   * @returns nothing
  245.   * @see QMatrix::shear()
  246.   */
  247.   void shear(double xRadians, double yRadians, const MatrixOptions& options = ApplyToCurrentMatrix);
  248.  
  249.   /**
  250.   * @brief Skews the origin of the current node.
  251.   *
  252.   * This is a convenience function. It simply coverts it's arguments to
  253.   * radians, then calls shear().
  254.   *
  255.   * @param xDegrees The amount in degrees to shear (skew) the x-axis by.
  256.   * @param yDegrees The amount in degrees to shear (skew) the y-axis by.
  257.   * @param options Apply to current matrix or replace current matrix.
  258.   * @returns nothing
  259.   * @see shear()
  260.   */
  261.   void skew(double xDegrees, double yDegrees, const MatrixOptions& options = ApplyToCurrentMatrix);
  262.  
  263.   /**
  264.   * @brief Scales the origin of the current node.
  265.   *
  266.   * @note Neither @c xFactor nor @c yFactor may be zero, otherwise you scale
  267.   * the element into nonexistence.
  268.   *
  269.   * @param xFactor The factor to scale the x-axis by.
  270.   * @param yFactor The factor to scale the y-axis by.
  271.   * @param options Apply to current matrix or replace current matrix.
  272.   * @returns nothing
  273.   * @see QMatrix::scale()
  274.   */
  275.   void scale(double xFactor, double yFactor, const MatrixOptions& options = ApplyToCurrentMatrix);
  276.  
  277.   /**
  278.   * @brief Returns the last node found by elementById, or null if node not found
  279.   *
  280.   * @returns The current node
  281.   * @see setCurrentNode()
  282.   */
  283.   QDomNode currentNode() const;
  284.  
  285.   /**
  286.   * @brief Sets the current node.
  287.   *
  288.   * @param node The node to set currentNode to.
  289.   * @returns nothing
  290.   * @see currentNode()
  291.   */
  292.   void setCurrentNode(const QDomNode& node);
  293.  
  294.   /**
  295.   * @brief Returns the name of the SVG file this DOM represents.
  296.   *
  297.   * @returns The current filename.
  298.   * @see setSvgFilename()
  299.   */
  300.   QString svgFilename() const;
  301.  
  302.   /**
  303.   * @brief Sets the current SVG filename.
  304.   *
  305.   * @param svgFilename The filename of the SVG file to open.
  306.   * @returns nothing
  307.   * @see svgFilename()
  308.   */
  309.   void setSvgFilename(const QString& svgFilename);
  310.  
  311.   /**
  312.   * @brief Returns the value of the style property given for the current node.
  313.   *
  314.   * @note Internally, we create a hash with @c styleProperties, then return the value
  315.   * of the @c propertyName property. As such, if you need the values of multiple
  316.   * properties, it will be more efficient to call @c styleProperties()
  317.   * and then use the hash directly.
  318.   *
  319.   * See KGameSvgDocumentPrivate::m_inkscapeOrder for a list of common SVG style properties
  320.   *
  321.   * @param propertyName the name of the property to return
  322.   * @returns The value style property given, or null if no such property for this node.
  323.   * @see setStyleProperty(), styleProperties(), setStyleProperties()
  324.   */
  325.   QString styleProperty(const QString& propertyName) const;
  326.  
  327.   /**
  328.   * @brief Sets the value of the style property given for the current node.
  329.   *
  330.   * @note Internally, we create a hash with @c styleProperties, then update the
  331.   * @p propertyName to @p propertyValue, before finally applying the hash to
  332.   * DOM via @c setStyleProperties(). Because of this, if you need to set multiple
  333.   * properties per node, it will be more efficient to call @c styleProperties(),
  334.   * modify the hash it returns, and then apply the hash with @c setStyleProperties().
  335.   *
  336.   * @param propertyName The name of the property to set.
  337.   * @param propertyValue The value of the property to set.
  338.   * @returns nothing
  339.   * @see styleProperty(), styleProperties(), setStyleProperties()
  340.   */
  341.   void setStyleProperty(const QString& propertyName, const QString& propertyValue);
  342.  
  343.   /**
  344.   * @brief Returns the current node and it's children as a new xml svg document.
  345.   *
  346.   * @returns The xml for the new svg document
  347.   */
  348.   QString nodeToSvg() const;
  349.  
  350.   /**
  351.   * @brief Builds a new svg document and returns a QByteArray suitable for passing to KSvgRenderer::load().
  352.   *
  353.   * Internally, we call @c nodeToSvg() and then convert to a QByteArray, so this method
  354.   * should be called @b instead of @c nodeToSvg().
  355.   *
  356.   * @returns the QByteArray
  357.   */
  358.   QByteArray nodeToByteArray() const;
  359.  
  360.   /**
  361.   * @brief Returns the style attribute of the current node.
  362.   *
  363.   * Unless you are parsing your own style attribute for some reason, you probably
  364.   * want to use styleProperty() or styleProperties().
  365.   *
  366.   * @returns The style atttibute.
  367.   * @see styleProperty() styleProperties()
  368.   */
  369.   QString style() const;
  370.  
  371.   /**
  372.   * @brief Sets the style attribute of the current node.
  373.   *
  374.   * Unless you are parsing your own style attribute for some reason, you probably
  375.   * want to use setStyleProperty() or setStyleProperties().
  376.   *
  377.   * @param styleAttribute The style attribute to apply.
  378.   * @returns nothing
  379.   *
  380.   * @see setStyleProperty() setStyleProperties()
  381.   */
  382.   void setStyle(const QString& styleAttribute);
  383.  
  384.   /**
  385.   * @brief Returns the patterns in the document
  386.   *
  387.   * @returns The patterns in the document
  388.   */
  389.   QDomNodeList patterns() const;
  390.  
  391.   /**
  392.   * @brief Returns the linearGradients in the document
  393.   *
  394.   * @returns The linearGradients in the document
  395.   */
  396.   QDomNodeList linearGradients() const;
  397.  
  398.   /**
  399.   * @brief Returns the radialGradients in the document
  400.   *
  401.   * @returns The radialGradients in the document
  402.   */
  403.   QDomNodeList radialGradients() const;
  404.  
  405.   /**
  406.   * @brief Returns the defs in the document
  407.   *
  408.   * @returns The defs in the document
  409.   */
  410.   QDomNodeList defs() const;
  411.  
  412.   /**
  413.   * @brief Returns the first def in the document
  414.   *
  415.   * @returns The first def in the document
  416.   */
  417.   QDomNode def() const;
  418.  
  419.   /**
  420.   * @brief Returns the transform attribute of the current node.
  421.   * @returns The transform atttibute.
  422.   * @see setTransform(), transformMatrix(), setTransformMatrix()
  423.   */
  424.   QString transform() const;
  425.  
  426.   /**
  427.   * @brief Sets the transform attribute of the current node.
  428.   *
  429.   * As this function works on QStrings, it <b>replaces</b> the existing
  430.   * transform attribute. If you need to multiply, use setTransformMatrix() instead.
  431.   *
  432.   * @param transformAttribute The transform attribute to apply.
  433.   * @returns nothing
  434.   * @see transform(), transformMatrix(), setTransformMatrix()
  435.   */
  436.   void setTransform(const QString& transformAttribute);
  437.  
  438.   /**
  439.   * @brief Returns a hash of the style properties of the current node.
  440.   * @returns The style properties.
  441.   * @see setStyleProperties()
  442.   */
  443.   QHash<QString, QString> styleProperties() const;
  444.  
  445.   /**
  446.   * @brief Sets the style properties of the current node.
  447.   *
  448.   * The only(?) reason to set useInkscapeOrder to true is if you are saving the svg xml to a file
  449.   * that may be human-edited later, for consistency. There is a performance hit, since hashes store
  450.   * their data unsorted.
  451.   *
  452.   * @param _styleProperties The hash of style properties to apply.
  453.   * @param options Apply the hash so the properties are in the same order as Inkscape writes them.
  454.   * @returns nothing
  455.   * @see styleProperties()
  456.   */
  457.   void setStyleProperties(const QHash<QString, QString>& _styleProperties, const StylePropertySortOptions& options = Unsorted);
  458.  
  459.   /**
  460.   * @brief Returns the transform attribute of the current node as a matrix.
  461.   *
  462.   * @returns The matrix for the transform atttibute.
  463.   * @see setTransformMatrix()
  464.   */
  465.   QMatrix transformMatrix() const;
  466.  
  467.   /**
  468.   * @brief Sets the transform attribute of the current node.
  469.   *
  470.   * @param matrix The matrix to apply.
  471.   * @param options Should we apply matrix to the current matrix?
  472.   * We modify matrix internally if @p options includes ApplyToCurrentMatrix, so it can't
  473.   * be passed as const.
  474.   * Normally we want to apply the existing matrix. If we apply the matrix,
  475.   * we potentially end up squaring with each call, e.g. x^2.
  476.   * @returns nothing
  477.   * @see transformMatrix()
  478.   */
  479.   void setTransformMatrix(QMatrix& matrix, const MatrixOptions& options = ApplyToCurrentMatrix);
  480.  
  481.  private:
  482.  
  483.  
  484.   /**
  485.   * @brief d-pointer
  486.   */
  487.   KGameSvgDocumentPrivate * const d;
  488.  
  489.  };
  490.  Q_DECLARE_OPERATORS_FOR_FLAGS(KGameSvgDocument::MatrixOptions)
  491.  Q_DECLARE_OPERATORS_FOR_FLAGS(KGameSvgDocument::StylePropertySortOptions)
  492.  
  493.  #endif // _KGAMESVGDOCUMENT_H_
CC-GNU GPL
Photos & software licensed under the CC-GNU GPL
unless otherwise noted in the JPEG comments field or source code.