You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/lib/kofficecore/KoGenStyles.h

464 lines
18 KiB

/* This file is part of the KDE project
Copyright (C) 2004-2006 David Faure <faure@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KOGENSTYLES_H
#define KOGENSTYLES_H
#include <tqdict.h>
#include <tqmap.h>
#include <tqvaluevector.h>
#include <koffice_export.h>
class KoXmlWriter;
class KoGenStyle;
/**
* @brief Repository of styles used during saving of OASIS/OOo file.
*
* Each instance of KoGenStyles is a collection of styles whose names
* are in the same "namespace".
* This means there should be one instance for all styles in <office:styles>,
* and automatic-styles, another instance for number formats, another
* one for draw styles, and another one for list styles.
*
* "Style" in this context only means "a collection of properties".
* The "Gen" means both "Generic" and "Generated" :)
*
* The basic design principle is the flyweight pattern: if you need
* a style with the same properties from two different places, you
* get the same object. Here it means rather you get the same name for the style,
* and it will get saved only once to the file.
*
* KoGenStyles features sharing, creation on demand, and name generation.
* Since this is used for saving only, it doesn't feature refcounting, nor
* removal of individual styles.
*
* NOTE: the use of KoGenStyles isn't mandatory, of course. If the application
* is already designed with user and automatic styles in mind for a given
* set of properties, it can go ahead and save all styles directly (after
* ensuring they have unique names).
*
* @author David Faure <faure@kde.org>
*/
class KOFFICECORE_EXPORT KoGenStyles
{
public:
KoGenStyles();
~KoGenStyles();
/**
* Those are flags for the lookup() call.
*
* By default, the generated style names will look like "name1", "name2".
* If DontForceNumbering is set, the first name that will be tried is "name", and only if
* that one exists, then "name1" is tried. Set DontForceNumbering if the name given as
* argument is supposed to be the full style name.
*
*/
enum Flags { // bitfield
NoFlag = 0,
ForceNumbering = 0, // it's the default anyway
DontForceNumbering = 1
};
// KDE4 TODO: use TQFlags and change the arg type in lookup
/**
* Look up a style in the collection, inserting it if necessary.
* This assigns a name to the style and returns it.
*
* @param style the style to look up.
* @param name proposed (base) name for the style. Note that with the OASIS format,
* the style name is never shown to the user (there's a separate display-name
* attribute for that). So there are little reasons to use named styles anyway.
* But this attribute can be used for clarity of the files.
* If this name is already in use (for another style), then a number is appended
* to it until unique.
* @param flags see Flags
*
* @return the name for this style
* @todo ### rename lookup to insert
*/
TQString lookup( const KoGenStyle& style, const TQString& name = TQString(), int flags = NoFlag );
typedef TQMap<KoGenStyle, TQString> StyleMap;
/**
* Return the entire collection of styles
* Use this for saving the styles
*/
const StyleMap& styles() const { return m_styleMap; }
struct NamedStyle {
const KoGenStyle* style; ///< @note owned by the collection
TQString name;
};
/**
* Return all styles of a given type
* Use this for saving the styles
*
* @param type the style type, see the KoGenStyle constructor
* @param markedForStylesXml if true, return only style marked for styles.xml,
* otherwise only those NOT marked for styles.xml.
* @see lookup
*/
TQValueList<NamedStyle> styles( int type, bool markedForStylesXml = false ) const;
/**
* @return an existing style by name
*/
const KoGenStyle* style( const TQString& name ) const;
/**
* @return an existing style by name, which can be modified.
* @warning This is DANGEROUS.
* It basically defeats the purpose of lookup()!
* Only do this if you know for sure no other 'user' of that style will
* be affected.
*/
KoGenStyle* styleForModification( const TQString& name );
/**
* Mark a given automatic style as being needed in styles.xml.
* For instance styles used by headers and footers need to go there, since
* they are saved in styles.xml, and styles.xml must be independent from content.xml.
*
* Equivalent to using KoGenStyle::setAutoStyleInStylesDotXml() but this can be done after lookup.
*
* This operation can't be undone; once styles are promoted they can't go back
* to being content.xml-only.
*
* @see styles, KoGenStyle::setAutoStyleInStylesDotXml
*/
void markStyleForStylesXml( const TQString& name );
/**
* Outputs debug information
*/
void dump();
private:
TQString makeUniqueName( const TQString& base, int flags ) const;
/// style definition -> name
StyleMap m_styleMap;
/// Map with the style name as key.
/// This map is mainly used to check for name uniqueness
/// The value of the bool doesn't matter.
typedef TQMap<TQString, bool> NameMap; // KDE4: TQSet
NameMap m_styleNames;
NameMap m_autoStylesInStylesDotXml;
/// List of styles (used to preserve ordering)
typedef TQValueVector<NamedStyle> StyleArray;
StyleArray m_styleArray;
class Private;
Private *d;
};
/**
* A generic style, i.e. basically a collection of properties and a name.
* Instances of KoGenStyle can either be held in the KoGenStyles collection,
* or created (e.g. on the stack) and given to KoGenStyles::lookup.
*
* @author David Faure <faure@kde.org>
*/
class KOFFICECORE_EXPORT KoGenStyle
{
public:
/**
* Possible values for the "type" argument of the KoGenStyle constructor.
* Those values can be extended by applications (starting at number 20),
* it's for their own consumption anyway.
* (The reason for having the very common ones here, is to make it possible to
* use them from libkotext).
*/
enum { STYLE_PAGELAYOUT = 0,
STYLE_USER = 1,
STYLE_AUTO = 2,
STYLE_MASTER = 3,
STYLE_LIST = 4,
STYLE_AUTO_LIST = 5,
STYLE_NUMERIC_NUMBER = 6,
STYLE_NUMERIC_DATE = 7,
STYLE_NUMERIC_TIME = 8,
STYLE_NUMERIC_FRACTION = 9,
STYLE_NUMERIC_PERCENTAGE = 10,
STYLE_NUMERIC_SCIENTIFIC = 11,
STYLE_NUMERIC_CURRENCY = 12,
STYLE_NUMERIC_TEXT = 13,
STYLE_HATCH = 14,
STYLE_GRAPHICAUTO = 15};
/**
* Start the definition of a new style. Its name will be set later by KoGenStyles::lookup(),
* but first you must define its properties and attributes.
*
* @param type this is a hook for the application to categorize styles
* See the STYLE_* enum. Ignored when writing out the style.
*
* @param familyName The value for style:family, e.g. text, paragraph, graphic etc.
* The family is for style:style elements only; number styles and list styles don't have one.
*
* @param parentName If set, name of the parent style from which this one inherits.
*/
explicit KoGenStyle( int type = 0, const char* familyName = 0,
const TQString& parentName = TQString() );
~KoGenStyle();
/*
* setAutoStyleInStylesDotXml(true) marks a given automatic style as being needed in styles.xml.
* For instance styles used by headers and footers need to go there, since
* they are saved in styles.xml, and styles.xml must be independent from content.xml.
*
* The application should use KoGenStyles::styles( type, true ) in order to retrieve
* those styles and save them separately.
*/
void setAutoStyleInStylesDotXml( bool b ) { m_autoStyleInStylesDotXml = b; }
/// @return the value passed to setAutoStyleInStylesDotXml; false by default
bool autoStyleInStylesDotXml() const { return m_autoStyleInStylesDotXml; }
/*
* setDefaultStyle(true) marks a given style as being the default style.
* This means we expect that you will call writeStyle( ...,"style:default-style"),
* and its name will be ommitted in the output.
*/
void setDefaultStyle( bool b ) { m_defaultStyle = b; }
/// @return the value passed to setDefaultStyle; false by default
bool isDefaultStyle() const { return m_defaultStyle; }
/// Return the type of this style, as set in the constructor
int type() const { return m_type; }
/// Return the family name
const char* familyName() const { return m_familyName.data(); }
/// Return the name of style's parent, if set
TQString parentName() const { return m_parentName; }
/**
* @brief The types of properties
*
* Simple styles only write one foo-properties tag, in which case they can just use DefaultType.
* However a given style might want to write several kinds of properties, in which case it would
* need to use other property types than the default one.
*
* For instance this style:
* @code
* <style:style style:family="chart">
* <style:chart-properties .../>
* <style:graphic-properties .../>
* <style:text-properties .../>
* </style:style>
* @endcode
* would use DefaultType for chart-properties (and would pass "style:chart-properties" to writeStyle(),
* and would use GraphicType and TextType.
*/
enum PropertyType
{
/**
* DefaultType depends on family: e.g. paragraph-properties if family=paragraph
* or on the type of style (e.g. page-layout -> page-layout-properties).
* (In fact that tag name is the one passed to writeStyle)
*/
DefaultType = 0,
/// TextType is always text-properties.
TextType,
/// ParagraphType is always paragraph-properties.
ParagraphType,
/// GraphicType is always graphic-properties.
GraphicType,
Reserved1, ///< @internal for binary compatible extensions
Reserved2, ///< @internal for binary compatible extensions
ChildElement, ///< @internal
N_NumTypes ///< @internal - warning, adding items here affects binary compatibility (size of KoGenStyle)
};
/// Add a property to the style
void addProperty( const TQString& propName, const TQString& propValue, PropertyType type = DefaultType ) {
m_properties[type].insert( propName, propValue );
}
/// Overloaded version of addProperty that takes a char*, usually for "..."
void addProperty( const TQString& propName, const char* propValue, PropertyType type = DefaultType ) {
m_properties[type].insert( propName, TQString::fromUtf8( propValue ) );
}
/// Overloaded version of addProperty that converts an int to a string
void addProperty( const TQString& propName, int propValue, PropertyType type = DefaultType ) {
m_properties[type].insert( propName, TQString::number( propValue ) );
}
/// Overloaded version of addProperty that converts a bool to a string (false/true)
void addProperty( const TQString& propName, bool propValue, PropertyType type = DefaultType ) {
m_properties[type].insert( propName, propValue ? "true" : "false" );
}
/**
* Add a property which represents a distance, measured in pt
* The number is written out with the highest possible precision
* (unlike TQString::number and setNum, which default to 6 digits),
* and the unit name ("pt") is appended to it.
*/
void addPropertyPt( const TQString& propName, double propValue, PropertyType type = DefaultType );
/**
* Add an attribute to the style
* The difference between property and attributes is a bit oasis-format-specific:
* attributes are for the style element itself, and properties are in the style:properties child element
*/
void addAttribute( const TQString& attrName, const TQString& attrValue ) {
m_attributes.insert( attrName, attrValue );
}
/// Overloaded version of addAttribute that takes a char*, usually for "..."
void addAttribute( const TQString& attrName, const char* attrValue ) {
m_attributes.insert( attrName, TQString::fromUtf8( attrValue ) );
}
/// Overloaded version of addAttribute that converts an int to a string
void addAttribute( const TQString& attrName, int attrValue ) {
m_attributes.insert( attrName, TQString::number( attrValue ) );
}
/// Overloaded version of addAttribute that converts a bool to a string
void addAttribute( const TQString& attrName, bool attrValue ) {
m_attributes.insert( attrName, attrValue ? "true" : "false" );
}
/**
* Add an attribute which represents a distance, measured in pt
* The number is written out with the highest possible precision
* (unlike TQString::number and setNum, which default to 6 digits),
* and the unit name ("pt") is appended to it.
*/
void addAttributePt( const TQString& attrName, double attrValue );
/**
* @brief Add a child element to the style properties.
*
* What is meant here is that the contents of the TQString
* will be written out literally. This means you should use
* KoXmlWriter to generate it:
* @code
* TQBuffer buffer;
* buffer.open( IO_WriteOnly );
* KoXmlWriter elementWriter( &buffer ); // TODO pass indentation level
* elementWriter.startElement( "..." );
* ...
* elementWriter.endElement();
* TQString elementContents = TQString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
* gs.addChildElement( "...", elementContents );
* @endcode
*
* The value of @p elementName isn't used, except that it must be unique.
*/
void addChildElement( const TQString& elementName, const TQString& elementContents ) {
m_properties[ChildElement].insert( elementName, elementContents );
}
/**
* @brief Add a style:map to the style.
* @param styleMap the attributes for the map, associated as (name,value).
*/
void addStyleMap( const TQMap<TQString, TQString>& styleMap ) {
m_maps.append( styleMap );
}
/**
* @return true if the style has no attributes, no properties, no style map etc.
* This can be used by applications which do not save all attributes unconditionally,
* but only those that differ from the parent. But note that lookup() can't find this out...
*/
bool isEmpty() const {
if ( !m_attributes.isEmpty() || ! m_maps.isEmpty() )
return false;
for ( uint i = 0 ; i < N_NumTypes ; ++i )
if ( ! m_properties[i].isEmpty() )
return false;
return true;
}
/**
* Write the definition of this style to @p writer, using the OASIS format.
* @param writer the KoXmlWriter in which @p elementName will be created and filled in
* @param styles the styles collection, used to look up the parent style
* @param elementName the name of the XML element, e.g. "style:style". Don't forget to
* pass style:default-style if isDefaultStyle().
* @param name must come from the collection. It will be ignored if isDefaultStyle() is true.
* @param propertiesElementName the name of the XML element with the style properties,
* e.g. "style:text-properties". Can be 0 in special cases where there should be no such item,
* in which case the attributes and elements are added under the style itself.
* @param closeElement set it to false to be able to add more child elements to the style element
* @param drawElement set it to true to add "draw:name" (used for gradient/hatch style) otherwise add "style:name"
*/
void writeStyle( KoXmlWriter* writer, KoGenStyles& styles, const char* elementName, const TQString& name,
const char* propertiesElementName, bool closeElement = true, bool drawElement = false ) const;
/**
* TQMap requires a complete sorting order.
* Another solution would have been a qdict and a key() here, a la KoTextFormat,
* but the key was difficult to generate.
* Solutions with only a hash value (not representative of the whole data)
* require us to write a hashtable by hand....
*/
bool operator<( const KoGenStyle &other ) const;
/// Not needed for TQMap, but can still be useful
bool operator==( const KoGenStyle &other ) const;
private:
TQString property( const TQString& propName, PropertyType type ) const {
TQMap<TQString, TQString>::const_iterator it = m_properties[type].find( propName );
if ( it != m_properties[type].end() )
return it.data();
return TQString();
}
TQString attribute( const TQString& propName ) const {
TQMap<TQString, TQString>::const_iterator it = m_attributes.find( propName );
if ( it != m_attributes.end() )
return it.data();
return TQString();
}
void writeStyleProperties( KoXmlWriter* writer, PropertyType i,
const char* elementName, const KoGenStyle* parentStyle ) const;
#ifndef NDEBUG
void printDebug() const;
#endif
private:
// Note that the copy constructor and assignment operator are allowed.
// Better not use pointers below!
int m_type;
TQCString m_familyName;
TQString m_parentName;
/// We use TQMaps since they provide automatic sorting on the key (important for unicity!)
TQMap<TQString, TQString> m_properties[N_NumTypes];
TQMap<TQString, TQString> m_attributes;
typedef TQMap<TQString, TQString> StyleMap;
TQValueVector<StyleMap> m_maps; // we can't really sort the maps between themselves...
bool m_autoStyleInStylesDotXml;
bool m_defaultStyle;
short m_unused2;
// For lookup
friend class KoGenStyles;
};
#endif /* KOGENSTYLES_H */