home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / SLAX 6.0.8 / slax-6.0.8.iso / slax / base / 006-devel.lzm / usr / include / KoGenStyles.h < prev    next >
Encoding:
C/C++ Source or Header  |  2007-05-30  |  18.4 KB  |  464 lines

  1. /* This file is part of the KDE project
  2.    Copyright (C) 2004-2006 David Faure <faure@kde.org>
  3.  
  4.    This library is free software; you can redistribute it and/or
  5.    modify it under the terms of the GNU Library General Public
  6.    License version 2 as published by the Free Software Foundation.
  7.  
  8.    This library is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.    Library General Public License for more details.
  12.  
  13.    You should have received a copy of the GNU Library General Public License
  14.    along with this library; see the file COPYING.LIB.  If not, write to
  15.    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  16.  * Boston, MA 02110-1301, USA.
  17. */
  18.  
  19. #ifndef KOGENSTYLES_H
  20. #define KOGENSTYLES_H
  21.  
  22. #include <qdict.h>
  23. #include <qmap.h>
  24. #include <qvaluevector.h>
  25.  
  26. #include <koffice_export.h>
  27.  
  28. class KoXmlWriter;
  29. class KoGenStyle;
  30.  
  31. /**
  32.  * @brief Repository of styles used during saving of OASIS/OOo file.
  33.  *
  34.  * Each instance of KoGenStyles is a collection of styles whose names
  35.  * are in the same "namespace".
  36.  * This means there should be one instance for all styles in <office:styles>,
  37.  * and automatic-styles, another instance for number formats, another
  38.  * one for draw styles, and another one for list styles.
  39.  *
  40.  * "Style" in this context only means "a collection of properties".
  41.  * The "Gen" means both "Generic" and "Generated" :)
  42.  *
  43.  * The basic design principle is the flyweight pattern: if you need
  44.  * a style with the same properties from two different places, you
  45.  * get the same object. Here it means rather you get the same name for the style,
  46.  * and it will get saved only once to the file.
  47.  *
  48.  * KoGenStyles features sharing, creation on demand, and name generation.
  49.  * Since this is used for saving only, it doesn't feature refcounting, nor
  50.  * removal of individual styles.
  51.  *
  52.  * NOTE: the use of KoGenStyles isn't mandatory, of course. If the application
  53.  * is already designed with user and automatic styles in mind for a given
  54.  * set of properties, it can go ahead and save all styles directly (after
  55.  * ensuring they have unique names).
  56.  *
  57.  * @author David Faure <faure@kde.org>
  58.  */
  59. class KOFFICECORE_EXPORT KoGenStyles
  60. {
  61. public:
  62.     KoGenStyles();
  63.     ~KoGenStyles();
  64.  
  65.     /**
  66.      * Those are flags for the lookup() call.
  67.      *
  68.      * By default, the generated style names will look like "name1", "name2".
  69.      * If DontForceNumbering is set, the first name that will be tried is "name", and only if
  70.      * that one exists, then "name1" is tried. Set DontForceNumbering if the name given as
  71.      * argument is supposed to be the full style name.
  72.      *
  73.      */
  74.     enum Flags { // bitfield
  75.         NoFlag = 0,
  76.         ForceNumbering = 0, // it's the default anyway
  77.         DontForceNumbering = 1
  78.     };
  79.     // KDE4 TODO: use QFlags and change the arg type in lookup
  80.  
  81.     /**
  82.      * Look up a style in the collection, inserting it if necessary.
  83.      * This assigns a name to the style and returns it.
  84.      *
  85.      * @param style the style to look up.
  86.      * @param name proposed (base) name for the style. Note that with the OASIS format,
  87.      * the style name is never shown to the user (there's a separate display-name
  88.      * attribute for that). So there are little reasons to use named styles anyway.
  89.      * But this attribute can be used for clarity of the files.
  90.      * If this name is already in use (for another style), then a number is appended
  91.      * to it until unique.
  92.      * @param flags see Flags
  93.      *
  94.      * @return the name for this style
  95.      * @todo ### rename lookup to insert
  96.      */
  97.     QString lookup( const KoGenStyle& style, const QString& name = QString::null, int flags = NoFlag );
  98.  
  99.     typedef QMap<KoGenStyle, QString> StyleMap;
  100.     /**
  101.      * Return the entire collection of styles
  102.      * Use this for saving the styles
  103.      */
  104.     const StyleMap& styles() const { return m_styleMap; }
  105.  
  106.     struct NamedStyle {
  107.         const KoGenStyle* style; ///< @note owned by the collection
  108.         QString name;
  109.     };
  110.     /**
  111.      * Return all styles of a given type
  112.      * Use this for saving the styles
  113.      *
  114.      * @param type the style type, see the KoGenStyle constructor
  115.      * @param markedForStylesXml if true, return only style marked for styles.xml,
  116.      * otherwise only those NOT marked for styles.xml.
  117.      * @see lookup
  118.      */
  119.     QValueList<NamedStyle> styles( int type, bool markedForStylesXml = false ) const;
  120.  
  121.     /**
  122.      * @return an existing style by name
  123.      */
  124.     const KoGenStyle* style( const QString& name ) const;
  125.  
  126.     /**
  127.      * @return an existing style by name, which can be modified.
  128.      * @warning This is DANGEROUS.
  129.      * It basically defeats the purpose of lookup()!
  130.      * Only do this if you know for sure no other 'user' of that style will
  131.      * be affected.
  132.      */
  133.     KoGenStyle* styleForModification( const QString& name );
  134.  
  135.     /**
  136.      * Mark a given automatic style as being needed in styles.xml.
  137.      * For instance styles used by headers and footers need to go there, since
  138.      * they are saved in styles.xml, and styles.xml must be independent from content.xml.
  139.      *
  140.      * Equivalent to using KoGenStyle::setAutoStyleInStylesDotXml() but this can be done after lookup.
  141.      *
  142.      * This operation can't be undone; once styles are promoted they can't go back
  143.      * to being content.xml-only.
  144.      *
  145.      * @see styles, KoGenStyle::setAutoStyleInStylesDotXml
  146.      */
  147.     void markStyleForStylesXml( const QString& name );
  148.  
  149.     /**
  150.      * Outputs debug information
  151.      */
  152.     void dump();
  153.  
  154. private:
  155.     QString makeUniqueName( const QString& base, int flags ) const;
  156.  
  157.     /// style definition -> name
  158.     StyleMap m_styleMap;
  159.  
  160.     /// Map with the style name as key.
  161.     /// This map is mainly used to check for name uniqueness
  162.     /// The value of the bool doesn't matter.
  163.     typedef QMap<QString, bool> NameMap; // KDE4: QSet
  164.     NameMap m_styleNames;
  165.     NameMap m_autoStylesInStylesDotXml;
  166.  
  167.     /// List of styles (used to preserve ordering)
  168.     typedef QValueVector<NamedStyle> StyleArray;
  169.     StyleArray m_styleArray;
  170.  
  171.     class Private;
  172.     Private *d;
  173. };
  174.  
  175. /**
  176.  * A generic style, i.e. basically a collection of properties and a name.
  177.  * Instances of KoGenStyle can either be held in the KoGenStyles collection,
  178.  * or created (e.g. on the stack) and given to KoGenStyles::lookup.
  179.  *
  180.  * @author David Faure <faure@kde.org>
  181.  */
  182. class KOFFICECORE_EXPORT KoGenStyle
  183. {
  184. public:
  185.     /**
  186.      * Possible values for the "type" argument of the KoGenStyle constructor.
  187.      * Those values can be extended by applications (starting at number 20),
  188.      * it's for their own consumption anyway.
  189.      * (The reason for having the very common ones here, is to make it possible to
  190.      * use them from libkotext).
  191.      */
  192.     enum { STYLE_PAGELAYOUT = 0,
  193.            STYLE_USER = 1,
  194.            STYLE_AUTO = 2,
  195.            STYLE_MASTER = 3,
  196.            STYLE_LIST = 4,
  197.            STYLE_AUTO_LIST = 5,
  198.            STYLE_NUMERIC_NUMBER = 6,
  199.            STYLE_NUMERIC_DATE = 7,
  200.            STYLE_NUMERIC_TIME = 8,
  201.            STYLE_NUMERIC_FRACTION = 9,
  202.            STYLE_NUMERIC_PERCENTAGE = 10,
  203.            STYLE_NUMERIC_SCIENTIFIC = 11,
  204.            STYLE_NUMERIC_CURRENCY = 12,
  205.            STYLE_NUMERIC_TEXT = 13,
  206.            STYLE_HATCH = 14,
  207.            STYLE_GRAPHICAUTO = 15};
  208.  
  209.     /**
  210.      * Start the definition of a new style. Its name will be set later by KoGenStyles::lookup(),
  211.      * but first you must define its properties and attributes.
  212.      *
  213.      * @param type this is a hook for the application to categorize styles
  214.      * See the STYLE_* enum. Ignored when writing out the style.
  215.      *
  216.      * @param familyName The value for style:family, e.g. text, paragraph, graphic etc.
  217.      * The family is for style:style elements only; number styles and list styles don't have one.
  218.      *
  219.      * @param parentName If set, name of the parent style from which this one inherits.
  220.      */
  221.     explicit KoGenStyle( int type = 0, const char* familyName = 0,
  222.                          const QString& parentName = QString::null );
  223.     ~KoGenStyle();
  224.  
  225.     /*
  226.      * setAutoStyleInStylesDotXml(true) marks a given automatic style as being needed in styles.xml.
  227.      * For instance styles used by headers and footers need to go there, since
  228.      * they are saved in styles.xml, and styles.xml must be independent from content.xml.
  229.      *
  230.      * The application should use KoGenStyles::styles( type, true ) in order to retrieve
  231.      * those styles and save them separately.
  232.      */
  233.     void setAutoStyleInStylesDotXml( bool b ) { m_autoStyleInStylesDotXml = b; }
  234.     /// @return the value passed to setAutoStyleInStylesDotXml; false by default
  235.     bool autoStyleInStylesDotXml() const { return m_autoStyleInStylesDotXml; }
  236.  
  237.     /*
  238.      * setDefaultStyle(true) marks a given style as being the default style.
  239.      * This means we expect that you will call writeStyle( ...,"style:default-style"),
  240.      * and its name will be ommitted in the output.
  241.      */
  242.     void setDefaultStyle( bool b ) { m_defaultStyle = b; }
  243.     /// @return the value passed to setDefaultStyle; false by default
  244.     bool isDefaultStyle() const { return m_defaultStyle; }
  245.  
  246.     /// Return the type of this style, as set in the constructor
  247.     int type() const { return m_type; }
  248.  
  249.     /// Return the family name
  250.     const char* familyName() const { return m_familyName.data(); }
  251.  
  252.     /// Return the name of style's parent, if set
  253.     QString parentName() const { return m_parentName; }
  254.  
  255.     /**
  256.      *  @brief The types of properties
  257.      *
  258.      *  Simple styles only write one foo-properties tag, in which case they can just use DefaultType.
  259.      *  However a given style might want to write several kinds of properties, in which case it would
  260.      *  need to use other property types than the default one.
  261.      *
  262.      *  For instance this style:
  263.      *  @code
  264.      *  <style:style style:family="chart">
  265.      *    <style:chart-properties .../>
  266.      *    <style:graphic-properties .../>
  267.      *    <style:text-properties .../>
  268.      *  </style:style>
  269.      *  @endcode
  270.      *  would use DefaultType for chart-properties (and would pass "style:chart-properties" to writeStyle(),
  271.      *  and would use GraphicType and TextType.
  272.      */
  273.     enum PropertyType
  274.     {
  275.         /**
  276.          *  DefaultType depends on family: e.g. paragraph-properties if family=paragraph
  277.          *  or on the type of style (e.g. page-layout -> page-layout-properties).
  278.          *  (In fact that tag name is the one passed to writeStyle)
  279.          */
  280.         DefaultType = 0,
  281.         /// TextType is always text-properties.
  282.         TextType,
  283.         /// ParagraphType is always paragraph-properties.
  284.         ParagraphType,
  285.         /// GraphicType is always graphic-properties.
  286.         GraphicType,
  287.         Reserved1, ///< @internal for binary compatible extensions
  288.         Reserved2, ///< @internal for binary compatible extensions
  289.         ChildElement, ///< @internal
  290.         N_NumTypes ///< @internal - warning, adding items here affects binary compatibility (size of KoGenStyle)
  291.     };
  292.  
  293.     /// Add a property to the style
  294.     void addProperty( const QString& propName, const QString& propValue, PropertyType type = DefaultType ) {
  295.         m_properties[type].insert( propName, propValue );
  296.     }
  297.     /// Overloaded version of addProperty that takes a char*, usually for "..."
  298.     void addProperty( const QString& propName, const char* propValue, PropertyType type = DefaultType ) {
  299.         m_properties[type].insert( propName, QString::fromUtf8( propValue ) );
  300.     }
  301.     /// Overloaded version of addProperty that converts an int to a string
  302.     void addProperty( const QString& propName, int propValue, PropertyType type = DefaultType ) {
  303.         m_properties[type].insert( propName, QString::number( propValue ) );
  304.     }
  305.     /// Overloaded version of addProperty that converts a bool to a string (false/true)
  306.     void addProperty( const QString& propName, bool propValue, PropertyType type = DefaultType ) {
  307.         m_properties[type].insert( propName, propValue ? "true" : "false" );
  308.     }
  309.  
  310.     /**
  311.      *  Add a property which represents a distance, measured in pt
  312.      *  The number is written out with the highest possible precision
  313.      *  (unlike QString::number and setNum, which default to 6 digits),
  314.      *  and the unit name ("pt") is appended to it.
  315.      */
  316.     void addPropertyPt( const QString& propName, double propValue, PropertyType type = DefaultType );
  317.  
  318.     /**
  319.      *  Add an attribute to the style
  320.      *  The difference between property and attributes is a bit oasis-format-specific:
  321.      *  attributes are for the style element itself, and properties are in the style:properties child element
  322.      */
  323.     void addAttribute( const QString& attrName, const QString& attrValue ) {
  324.         m_attributes.insert( attrName, attrValue );
  325.     }
  326.     /// Overloaded version of addAttribute that takes a char*, usually for "..."
  327.     void addAttribute( const QString& attrName, const char* attrValue ) {
  328.         m_attributes.insert( attrName, QString::fromUtf8( attrValue ) );
  329.     }
  330.     /// Overloaded version of addAttribute that converts an int to a string
  331.     void addAttribute( const QString& attrName, int attrValue ) {
  332.         m_attributes.insert( attrName, QString::number( attrValue ) );
  333.     }
  334.  
  335.     /// Overloaded version of addAttribute that converts a bool to a string
  336.     void addAttribute( const QString& attrName, bool attrValue ) {
  337.         m_attributes.insert( attrName, attrValue ? "true" : "false" );
  338.     }
  339.  
  340.     /**
  341.      *  Add an attribute which represents a distance, measured in pt
  342.      *  The number is written out with the highest possible precision
  343.      *  (unlike QString::number and setNum, which default to 6 digits),
  344.      *  and the unit name ("pt") is appended to it.
  345.      */
  346.     void addAttributePt( const QString& attrName, double attrValue );
  347.  
  348.     /**
  349.      * @brief Add a child element to the style properties.
  350.      *
  351.      * What is meant here is that the contents of the QString
  352.      * will be written out literally. This means you should use
  353.      * KoXmlWriter to generate it:
  354.      * @code
  355.      * QBuffer buffer;
  356.      * buffer.open( IO_WriteOnly );
  357.      * KoXmlWriter elementWriter( &buffer );  // TODO pass indentation level
  358.      * elementWriter.startElement( "..." );
  359.      * ...
  360.      * elementWriter.endElement();
  361.      * QString elementContents = QString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
  362.      * gs.addChildElement( "...", elementContents );
  363.      * @endcode
  364.      *
  365.      * The value of @p elementName isn't used, except that it must be unique.
  366.      */
  367.     void addChildElement( const QString& elementName, const QString& elementContents ) {
  368.         m_properties[ChildElement].insert( elementName, elementContents );
  369.     }
  370.  
  371.     /**
  372.      * @brief Add a style:map to the style.
  373.      * @param styleMap the attributes for the map, associated as (name,value).
  374.      */
  375.     void addStyleMap( const QMap<QString, QString>& styleMap ) {
  376.         m_maps.append( styleMap );
  377.     }
  378.  
  379.     /**
  380.      * @return true if the style has no attributes, no properties, no style map etc.
  381.      * This can be used by applications which do not save all attributes unconditionally,
  382.      * but only those that differ from the parent. But note that lookup() can't find this out...
  383.      */
  384.     bool isEmpty() const {
  385.         if ( !m_attributes.isEmpty() || ! m_maps.isEmpty() )
  386.             return false;
  387.         for ( uint i = 0 ; i < N_NumTypes ; ++i )
  388.             if ( ! m_properties[i].isEmpty() )
  389.                 return false;
  390.         return true;
  391.     }
  392.  
  393.     /**
  394.      *  Write the definition of this style to @p writer, using the OASIS format.
  395.      *  @param writer the KoXmlWriter in which @p elementName will be created and filled in
  396.      *  @param styles the styles collection, used to look up the parent style
  397.      *  @param elementName the name of the XML element, e.g. "style:style". Don't forget to
  398.      *  pass style:default-style if isDefaultStyle().
  399.      *  @param name must come from the collection. It will be ignored if isDefaultStyle() is true.
  400.      *  @param propertiesElementName the name of the XML element with the style properties,
  401.      *  e.g. "style:text-properties". Can be 0 in special cases where there should be no such item,
  402.      *  in which case the attributes and elements are added under the style itself.
  403.      *  @param closeElement set it to false to be able to add more child elements to the style element
  404.      *  @param drawElement set it to true to add "draw:name" (used for gradient/hatch style) otherwise add "style:name"
  405.      */
  406.     void writeStyle( KoXmlWriter* writer, KoGenStyles& styles, const char* elementName, const QString& name,
  407.                      const char* propertiesElementName, bool closeElement = true, bool drawElement = false ) const;
  408.  
  409.     /**
  410.      *  QMap requires a complete sorting order.
  411.      *  Another solution would have been a qdict and a key() here, a la KoTextFormat,
  412.      *  but the key was difficult to generate.
  413.      *  Solutions with only a hash value (not representative of the whole data)
  414.      *  require us to write a hashtable by hand....
  415.      */
  416.     bool operator<( const KoGenStyle &other ) const;
  417.  
  418.     /// Not needed for QMap, but can still be useful
  419.     bool operator==( const KoGenStyle &other ) const;
  420.  
  421. private:
  422.     QString property( const QString& propName, PropertyType type ) const {
  423.         QMap<QString, QString>::const_iterator it = m_properties[type].find( propName );
  424.         if ( it != m_properties[type].end() )
  425.             return it.data();
  426.         return QString::null;
  427.     }
  428.  
  429.     QString attribute( const QString& propName ) const {
  430.         QMap<QString, QString>::const_iterator it = m_attributes.find( propName );
  431.         if ( it != m_attributes.end() )
  432.             return it.data();
  433.         return QString::null;
  434.     }
  435.  
  436.     void writeStyleProperties( KoXmlWriter* writer, PropertyType i,
  437.                                const char* elementName, const KoGenStyle* parentStyle ) const;
  438.  
  439. #ifndef NDEBUG
  440.     void printDebug() const;
  441. #endif
  442.  
  443. private:
  444.     // Note that the copy constructor and assignment operator are allowed.
  445.     // Better not use pointers below!
  446.     int m_type;
  447.     QCString m_familyName;
  448.     QString m_parentName;
  449.     /// We use QMaps since they provide automatic sorting on the key (important for unicity!)
  450.     QMap<QString, QString> m_properties[N_NumTypes];
  451.     QMap<QString, QString> m_attributes;
  452.     typedef QMap<QString, QString> StyleMap;
  453.     QValueVector<StyleMap> m_maps; // we can't really sort the maps between themselves...
  454.  
  455.     bool m_autoStyleInStylesDotXml;
  456.     bool m_defaultStyle;
  457.     short m_unused2;
  458.  
  459.     // For lookup
  460.     friend class KoGenStyles;
  461. };
  462.  
  463. #endif /* KOGENSTYLES_H */
  464.