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.
464 lines
18 KiB
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 */
|