MarkTaff.com

  • Increase font size
  • Default font size
  • Decrease font size
Home Portfolio Source Code KGameSvgDocument.h

KGameSvgDocument.h

E-mail Print PDF

  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_
  494.  

Last Updated ( Saturday, 06 December 2008 19:16 )  

Quotes, Aphorisms & Epigrams

flash•light (flăsh līt′)  n. A highly specialized container, typically used to store dead batteries.