Difference between revisions of "Calc/Implementation/Calc styles export"

From Apache OpenOffice Wiki
Jump to: navigation, search
 
(23 intermediate revisions by the same user not shown)
Line 2: Line 2:
 
[[Category:Implementation]]
 
[[Category:Implementation]]
  
==Basic concept of Styles==
+
This document mainly introduces the current design of styles export mechanism for spreadsheet. Before introduction of design, some basic knowledge of styles is required.
 +
 
 +
 
 +
== Basic concept of Styles ==
 
In the OpenDocument format, formatting properties, which influences  
 
In the OpenDocument format, formatting properties, which influences  
 
the visual representation of objects, are stored in styles. Using styles to store formatting properties has advantages such as, format information is separated from document content, and styles enable consistent formatting and changing of formatting for objects subject to styles.
 
the visual representation of objects, are stored in styles. Using styles to store formatting properties has advantages such as, format information is separated from document content, and styles enable consistent formatting and changing of formatting for objects subject to styles.
Following picture is a sample of OpenDocument styles.xml file. This file is the main file for  styles storage.
 
  
 +
Styles.xml inside zipped OpenDocument is the main file for  styles storage, as following sample picture of styles.xml shows, both <style:default-style> and <style:style> in <office:styles> have a “style:name” attribute. In fact, styles and font face declarations are referenced by their style:name attribute[1]. A referenced style or font face declaration should be defined in the same file as the reference, or in styles.xml. Styles built in  the stylist (can be used by click menu "Format"--"Styles and formatting") or ones that you create there, will have names like “Heading 1” or Custom Citation. Automatic styles <office:automatic-styles> will have names consisting of  style-family abbreviation followed by a number; a style name such as T1 is the first automatic style for style:family="text"; P3 would be the third style for paragraphs, ta2 would be the second style for a table, ro4 would be the fourth style for a table row, etc(please refer content.xml for OpenDocument).  The other attribute of interest is the optional parent-style-name, which you will find in styles that have been derived from other styles.
 
  [[File:styles.xml .jpg]]
 
  [[File:styles.xml .jpg]]
  
As styles.xml shows, both <style:default-style> and <style:style> in <office:styles> have a “style:name” attribute. In fact, styles and font face declarations are referenced by their style:name attribute[1]. A referenced style or font face declaration should be defined in the same file as the reference, or in styles.xml. Styles built in  the stylist (can be used by click menu "Format"--"Styles and formatting") or ones that you create there, will have names like “Heading 1” or Custom Citation. Automatic styles <office:automatic-styles> will have names consisting of  style-family abbreviation followed by a number; a style name such as T1 is the first automatic style for style:family="text"; P3 would be the third style for paragraphs, ta2 would be the second style for a table, ro4 would be the fourth style for a table row, etc(please refer content.xml for OpenDocument).  The other attribute of interest is the optional parent-style-name, which you will find in styles that have been derived from other styles.
 
 
<style:font-face> element represents a font face declaration which documents the properties of a font used in a document. OpenDocument font face declarations may have an unique name. This name can be used inside styles (as an attribute of <style:text-properties> element) as value of the style:font-name attribute to select a font face declaration. <style:style> element represents styles,and <style:default-style> element represents default styles. A default style specifies default formatting properties for a style family. These defaults are used if a formatting property is neither specified by an automatic nor a common style. Default styles exist for all style families that are represented by the <style:style> element specified by the style:family attribute. An OpenDocument document should contain the default styles of the style families for which are used in common or automatic styles in the document.<office:master-styles> <style:master-page> defines page styles which is in stylist.
 
<style:font-face> element represents a font face declaration which documents the properties of a font used in a document. OpenDocument font face declarations may have an unique name. This name can be used inside styles (as an attribute of <style:text-properties> element) as value of the style:font-name attribute to select a font face declaration. <style:style> element represents styles,and <style:default-style> element represents default styles. A default style specifies default formatting properties for a style family. These defaults are used if a formatting property is neither specified by an automatic nor a common style. Default styles exist for all style families that are represented by the <style:style> element specified by the style:family attribute. An OpenDocument document should contain the default styles of the style families for which are used in common or automatic styles in the document.<office:master-styles> <style:master-page> defines page styles which is in stylist.
  
[[File:styles_font_face.xml .jpg]]
+
Attributes for elements defined by OpenDocument are divided between those used by structural elements[2] versus those used by <style:*-properties> elements. Attributes defined by reference[2] standard have default values , and when any element appears in a document instance without such an attribute, consumers should behave as if the attribute is present with the defined default value. <style:*-properties> elements is commonly used to aggregate attributes of one type for specific style. Formatting definitions are expressed as attributes on the <style:*-properties> elements or as child elements of these elements.
  
Attributes for elements defined by OpenDocument are divided between those used by structural elements[2] versus those used by <style:*-properties> elements. Attributes have default values defined by reference[2] standard, and when any element appears in a document instance without such an attribute, consumers should behave as if the attribute is present with the defined default value. <style:*-properties> elements is commonly used to aggregate attributes of one type for specific style.  Formatting definitions are expressed as attributes on the <style:*-properties> elements or as child elements of these elements.
 
 
From code perspective, these <office:styles> , <office:automatic-styles> etc elements in styles.xml is written by  
 
From code perspective, these <office:styles> , <office:automatic-styles> etc elements in styles.xml is written by  
SvXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass ),  when export ods, eClass is XML_SPREADSHEET. For example, ImplExportStyles() inside SvXMLExport::exportDoc() is for writing <office:styles> elements, _ExportFontDecls(); is for <office:font-face-decls>, and ImplExportAutoStyles() is for <office:automatic-styles>. Inside  ImplExportStyles() , ScXMLExport::_ExportStyles will call exportDefaultStyle(), exportDataStyles(), exportStyleFamily() etc, in turn to export
+
SvXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass ),  when export ods, eClass is XML_SPREADSHEET. For example, ImplExportStyles() inside SvXMLExport::exportDoc() is for writing <office:styles> elements, _ExportFontDecls(); is for <office:font-face-decls>, and ImplExportAutoStyles() is for <office:automatic-styles>. Inside  ImplExportStyles() , ScXMLExport::_ExportStyles will call exportDefaultStyle(), exportDataStyles(), exportStyleFamily() etc, in turn to export <style:default-style> <number:number-style>,  <style:style> etc. ScXMLImportWrapper::ExportToComponent() is called with different parameters to export each file inside ods, such as styles.xml, content.xml.
<style:default-style> <number:number-style>,  <style:style> etc.  
+
ScXMLImportWrapper::ExportToComponent() is called with different parameters to export each file inside ods, such as styles.xml, content.xml.
+
  
 
==Styles export  sequence diagrams overview==
 
==Styles export  sequence diagrams overview==
Line 31: Line 30:
 
==Main class for export, SvXMLExport and ScXMLExport==
 
==Main class for export, SvXMLExport and ScXMLExport==
 
 
SvXMLExport is the main class for XML file export. It implements several UNO interfaces such as ::com::sun::star::document::Xfilter,  which is used by service ImportFilter or    ExportFilter to support loading/saving of documents in  different formats,  and ::com::sun::star::xml::sax::XDocumentHandler plus ::com::sun::star::xml::sax::XEntendedDocumentHandler, which is interfaces for  calling SAX(an event-based sequential access parser API ). It also holds ::com::sun::star::frame::XModel to access  document data model. And it use XMLFontAutoStylePool, SvXMLAutoStylePoolP  to manage font declarations and automatic styles store plus export. Member UniReference< XMLPageExport > mxPageExport is used as child exporter, which export page styles; and UniReference< XMLShapeExport > mxShapeExport for exporting shape styles. It has function ImplExportStyles( ) for <office:styles> export, _ImplExportMasterStyles() for <style:master-styles> export, etc.
+
SvXMLExport is the main class for XML file export. It implements several UNO interfaces such as ::com::sun::star::document::Xfilter,  which is used by service ImportFilter or    ExportFilter to support loading/saving of documents in  different formats,  and ::com::sun::star::xml::sax::XDocumentHandler plus ::com::sun::star::xml::sax::XEntendedDocumentHandler, which is interfaces for  calling SAX(an event-based sequential access parser API ). It also holds ::com::sun::star::frame::XModel to access  document data model. And it use XMLFontAutoStylePool, SvXMLAutoStylePoolP  to manage font declarations and automatic styles store plus export. Member UniReference< XMLPageExport > mxPageExport is used as child exporter, which export page styles; and UniReference< XMLShapeExport > mxShapeExport for exporting shape styles. It has function ImplExportStyles() for <office:styles> export, _ImplExportMasterStyles() for <style:master-styles> export, etc.
 +
 
 
ScXMLExport is derived from SvXMLExport and it holds specific SvXMLExportPropertyMapper for SC module, such as xCellStylesExportPropertySetMapper, xRowStylesExportPropertySetMapper. And  ScColumnStyles, ScRowStyles etc for corresponding automatic styles export. It implements _ExportFontDecls(),  _ExportStyles(), _ExportAutoStyles() etc to actually export styles. ScXMLExport will be constructed once writing a XML file such as styles.xml, content.xml.
 
ScXMLExport is derived from SvXMLExport and it holds specific SvXMLExportPropertyMapper for SC module, such as xCellStylesExportPropertySetMapper, xRowStylesExportPropertySetMapper. And  ScColumnStyles, ScRowStyles etc for corresponding automatic styles export. It implements _ExportFontDecls(),  _ExportStyles(), _ExportAutoStyles() etc to actually export styles. ScXMLExport will be constructed once writing a XML file such as styles.xml, content.xml.
 +
 
  class XMLOFF_DLLPUBLIC SvXMLExport  
 
  class XMLOFF_DLLPUBLIC SvXMLExport  
 
  {
 
  {
 
  …
 
  …
SvXMLNamespaceMap *mpNamespaceMap; // the namepspace map
+
  SvXMLNamespaceMap *mpNamespaceMap; // the namepspace map
SvXMLUnitConverter *mpUnitConv; // the unit converter
+
  SvXMLUnitConverter *mpUnitConv; // the unit converter
+
 
UniReference< SvXMLAutoStylePoolP > mxAutoStylePool;
+
  UniReference< SvXMLAutoStylePoolP > mxAutoStylePool;
+
    UniReference< XMLFontAutoStylePool > mxFontAutoStylePool;
UniReference< XMLFontAutoStylePool > mxFontAutoStylePool;
+
 
+
  SAL_DLLPRIVATE void ImplExportMeta(); // <office:meta>
SAL_DLLPRIVATE void ImplExportMeta(); // <office:meta>
+
  SAL_DLLPRIVATE void ImplExportSettings(); // <office:settings>
SAL_DLLPRIVATE void ImplExportSettings(); // <office:settings>
+
  SAL_DLLPRIVATE void ImplExportStyles( sal_Bool bUsed ); // <office:styles>
SAL_DLLPRIVATE void ImplExportStyles( sal_Bool bUsed ); // <office:styles>
+
  SAL_DLLPRIVATE void ImplExportAutoStyles( sal_Bool bUsed );// <office:automatic-styles>
SAL_DLLPRIVATE void ImplExportAutoStyles( sal_Bool bUsed );// <office:automatic-styles>
+
  SAL_DLLPRIVATE void ImplExportMasterStyles( sal_Bool bUsed ); // <office:master-styles>
SAL_DLLPRIVATE void ImplExportMasterStyles( sal_Bool bUsed ); // <office:master-styles>
+
  SAL_DLLPRIVATE void ImplExportContent(); // <office:body>
SAL_DLLPRIVATE void ImplExportContent(); // <office:body>
+
 
+
  // This method should be overloaded to export the content of <style:styles>.
// This method can be overloaded to export the font declarations
+
  virtual void _ExportStyles( sal_Bool bUsed ) ;
// The default implementation will export the contents of the
+
 
// XMLFontAutoStylePool if it has been created.
+
      // methods for accessing the document handler and handling SAX errors
virtual void _ExportFontDecls();
+
  void StartElement(sal_uInt16 nPrefix,
+
                          enum ::xmloff::token::XMLTokenEnum eName,
// This method should be overloaded to export the content of <style:styles>.
+
      sal_Bool bIgnWSOutside );
// If bUsed is set, used styles should be exported only.
+
 
// Overloaded Methods must call this method !
+
  }  
virtual void _ExportStyles( sal_Bool bUsed ) ;
+
+
    // methods for accessing the document handler and handling SAX errors
+
void StartElement(sal_uInt16 nPrefix,
+
                        enum ::xmloff::token::XMLTokenEnum eName,
+
    sal_Bool bIgnWSOutside );
+
+
  }
+
 
SvXMLElementExport is helper class to export an element, its constructors prints a start tag with the common attributes. For example, SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, XML_FONT_FACE,  sal_True, sal_True )  could print tag <style:font-face style:name="Arial" svg:font-family="Arial" style:font-pitch="variable" /> .  Constructor of SvXMLElementExport will indirectly call SvXMLExport::StartElement() to write XML. And the destructor ~SvXMLElementExport() prints an end tag.
 
SvXMLElementExport is helper class to export an element, its constructors prints a start tag with the common attributes. For example, SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, XML_FONT_FACE,  sal_True, sal_True )  could print tag <style:font-face style:name="Arial" svg:font-family="Arial" style:font-pitch="variable" /> .  Constructor of SvXMLElementExport will indirectly call SvXMLExport::StartElement() to write XML. And the destructor ~SvXMLElementExport() prints an end tag.
 
For different properties, process of writing XML is quite differently. Handling color will use XMLColorPropHdl for writing XML and string using XMLStringProHdl; meanwhile XMLPropertyHandler is abstract base-class for different XML-types. Derivations of XMLPropertyHandler  knows how to compare, im/export a special XML-type.  
 
For different properties, process of writing XML is quite differently. Handling color will use XMLColorPropHdl for writing XML and string using XMLStringProHdl; meanwhile XMLPropertyHandler is abstract base-class for different XML-types. Derivations of XMLPropertyHandler  knows how to compare, im/export a special XML-type.  
 +
 
Some property types need SvXMLUnitConverter converts values  from their internal represantation to the textual form used in xml and back.Most of the methods are static but the SvXMLUnitConverter can also store default units for both numerical and textual measures.  For example, when XMLFontPitchPropHdl writing FontPitch property to XML, it use SvXMLUnitConverter::convertEnum() to convert enum FontPitch to textual form, by searching SvXMLEnumMapEntry aFontPitchMapping[] it will get mapped XMLTokenEnum and finally get corresponding text in xmltoken.cxx. Sample code is as below.
 
Some property types need SvXMLUnitConverter converts values  from their internal represantation to the textual form used in xml and back.Most of the methods are static but the SvXMLUnitConverter can also store default units for both numerical and textual measures.  For example, when XMLFontPitchPropHdl writing FontPitch property to XML, it use SvXMLUnitConverter::convertEnum() to convert enum FontPitch to textual form, by searching SvXMLEnumMapEntry aFontPitchMapping[] it will get mapped XMLTokenEnum and finally get corresponding text in xmltoken.cxx. Sample code is as below.
  
 
  static SvXMLEnumMapEntry __READONLY_DATA aFontPitchMapping[] =
 
  static SvXMLEnumMapEntry __READONLY_DATA aFontPitchMapping[] =
 
  {  
 
  {  
{ XML_FIXED,     PITCH_FIXED },
+
  { XML_FIXED,     PITCH_FIXED },
{ XML_VARIABLE,         PITCH_VARIABLE },
+
  { XML_VARIABLE,         PITCH_VARIABLE },
{ XML_TOKEN_INVALID,    0 }
+
  { XML_TOKEN_INVALID,    0 }
 
  };
 
  };
 
  sal_Bool XMLFontPitchPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
 
  sal_Bool XMLFontPitchPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
 
  {  
 
  {  
sal_Bool bRet = sal_False;
+
  sal_Bool bRet = sal_False;
sal_Int16 nPitch = sal_Int16();
+
  sal_Int16 nPitch = sal_Int16();
OUStringBuffer aOut;
+
  OUStringBuffer aOut;
 +
  FontPitch ePitch = PITCH_DONTKNOW;
 +
  if( rValue >>= nPitch )
 +
  ePitch =  (FontPitch)nPitch;
 +
  if( PITCH_DONTKNOW != ePitch )
 +
  {
 +
  bRet = SvXMLUnitConverter::convertEnum( aOut, ePitch, aFontPitchMapping, XML_FIXED );
 +
  rStrExpValue = aOut.makeStringAndClear();
 +
  }
 +
  return bRet;
 +
}
 +
 
 +
==XMLPropertySetMapper, SvXMLExportPropertyMapper, XMLPropertySetMapperEntry_Impl==
 +
 
 +
XMLPropertySetMapper is helper class for XML im/export, it holds a pointer to a given array of  XMLPropertySetMapperEntry_Impl, which is added by XMLPropertySetMapper::XMLPropertySetMapper(const XMLPropertyMapEntry* pEntries, const UniReference< XMLPropertyHandlerFactory >& rFactory ). XMLPropertyMapEntry* pEntries is usually passed from static array, such as XMLPropertyMapEntry aXMLScCellStylesProperties[], defined in xmlstyle.cxx, txtprmap.cxx etc. XMLPropertySetMapperEntry_Impl is basic element for export XML, it transforms XMLTokenEnum meXMLName inside XMLPropertyMapEntry  to sXMLAttributeName, which will be written in XML, so it holds a Sequence of XML-names (for properties) for  writing XML. XMLPropertySetMapperEntry_Impl also holds  nContextId for context filter, for example, in text properties context,  nContextId will only count id for text properties, it is defined intuitive in txtprmap.cxx, such as #define CTF_CHARHEIGHT  (XML_TEXT_CTF_START + 1).  sAPIPropertyName in XMLPropertySetMapperEntry_Impl is for UNO property-name.  XMLPropertySetMapper provides several methods to access data from XMLPropertySetMapperEntry_Impl array, such as GetEntryXMLName( sal_Int32 nIndex ), GetEntryNameSpace( sal_Int32 nIndex ).  Sample code is as below.
 +
 
 +
// xmloff\source\text\txtprmap.cxx
 +
XMLPropertyMapEntry aXMLParaPropMap[]//hundreds of entries
 +
XMLPropertyMapEntry aXMLSectionPropMap
 +
XMLPropertyMapEntry aXMLTextPropMap[]
 
   
 
   
FontPitch ePitch = PITCH_DONTKNOW;
+
XMLPropertyMapEntry aXMLParaPropMap[] =
  if( rValue >>= nPitch )
+
{
ePitch =  (FontPitch)nPitch;
+
  MP_E( "ParaUserDefinedAttributes", TEXT, XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), // RES_UNKNOWNATR_CONTAINER
 +
MP_E( "ParaLeftMargin", FO, MARGIN, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPE RTY, CTF_PARAMARGINALL ), // RES_LR_SPACE
 +
...
 +
  }
 +
class XMLPropertySetMapper
 +
{
 +
  ...
 +
      sal_uInt32 GetEntryFlags( sal_Int32 nIndex ) const    //Returns the flags of an entry
 +
      sal_uInt32 GetEntryType( sal_Int32 nIndex,  sal_Bool bWithFlags = sal_True ) const    //Returns the type of an entry
 +
    sal_uInt16 GetEntryNameSpace( sal_Int32 nIndex ) const  //Returns the namespace-key of an entry
 +
  /** import/export, this methods calls the respective im/export-method of the respective PropertyHandler. */
 +
virtual sal_Bool exportXML( ::rtl::OUString& rStrExpValue, const XMLPropertyState& rProperty, const SvXMLUnitConverter& rUnitConverter )  const;
 +
  ...
 +
  }
 
   
 
   
  if( PITCH_DONTKNOW != ePitch )
+
//ScXMLExport:: ScXMLExport()
 +
  xCellStylesPropertySetMapper = new XMLPropertySetMapper((XMLPropertyMapEntry*)aXMLScCellStylesProperties,    xScPropHdlFactory);
 +
  xColumnStylesPropertySetMapper = new XMLPropertySetMapper((XMLPropertyMapEntry*)aXMLScColumnStylesProperties,  xScPropHdlFactory);
 +
  xCellStylesExportPropertySetMapper = new ScXMLCellExportPropertyMapper(xCellStylesPropertySetMapper);
 +
 
 +
For nType in property map entry (XMLPropertySetMapperEntry_Impl), 15th to 18th bits from right of it are for type index, mnIndex in XMLPropertyState correspond to this index, which will be mapped for query information when exportXML(). And 32nd to 14th bits from right of nType are used as flags, such as following definition in Xmltypes.hxx (lib\xmloff\inc\xmloff).
 +
 +
SvXMLExportPropertyMapper is the base class of ScXMLCellExportPropertyMapper, ScXMLColumnExportPropertyMapper  etc. They hold XMLPropertySetMapper and knows how to compare with parameter XPropertySet  and filter unwanted properties. SvXMLExportPropertyMapper has method Filter( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet>), which filter properties and only take all properties of the XPropertySet which are also found in the XMLPropertyMapEntry-array and which are not  default or inherited.  SvXMLExportPropertyMapper also has method FilterDefaults( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rPropSet ) , which has quite similar process as Filter() except that it  only takes  properties that have the map flag MID_FLAG_DEFAULT_ITEM_EXPORT, and instead of the property's value, its defualt value is set for export. It holds mxNextMapper for stacked contextfilter(), which will be described afterwards. For writing XML, it has method exportXML(), which  fills the SvXMLAttributeList& rAttrList  with the items in std::vector< XMLPropertyState >& rProperties , and has handleSpecialItem()  for every item that has the MID_FLAG_SPECIAL_ITEM_EXPORT flag.
 +
 +
For Filter() or FilterDefaults(), it will first exclude mapperEntries which has flag MID_FLAG_NO_PROPERTY_EXPORT out of properties intended export. Entries that is included in properties intended to export should furthmore meet followings,
 +
first, it has flags MID_FLAG_MUST_EXIST or input XPropertySet  contains property type of this entry;
 +
second, ODFVersion is meeted; third, pass FillPropertyStateArray(aPropStateArray, xPropSet, maPropMapper, bDefault) and remain;(for FilterDefaults() , bDefault == true, and false for Filter()); fourth, pass ContextFilter() and remain.
 +
 
 +
In FillPropertyStateArray(aPropStateArray, xPropSet, maPropMapper,bDefault), code will judge bDefault to export properties with defualt value or new value. Output parameter aPropStateArray will then filtered by stacked mxNextMapper->ContextFilter( ).
 +
 +
ContextFilter() is  application-specific filter, just as XMLPageExportPropertyMapper, ScXMLCellExportPropertyMapper, XMLTextExportPropertySetMapper has different implementation, and by default it do nothing. Take  XMLTextExportPropertySetMapper for exmaple, ContextFilter() will finally call ContextFontFilter(), as follows,
 +
 
 +
void XMLTextExportPropertySetMapper::ContextFontFilter(XMLPropertyState *pFontNameState, XMLPropertyState *pFontFamilyNameState,
 +
  XMLPropertyState *pFontStyleNameState, XMLPropertyState *pFontFamilyState, XMLPropertyState *pFontPitchState,
 +
  XMLPropertyState *pFontCharsetState ) const
 +
  { ...
 +
OUString sName( ((SvXMLExport&)GetExport()).GetFontAutoStylePool()->Find( sFamilyName, sStyleName, nFamily, nPitch, eEnc ) );
 +
  if( sName.getLength() )
 
  {
 
  {
  bRet = SvXMLUnitConverter::convertEnum( aOut, ePitch, aFontPitchMapping, XML_FIXED );
+
  pFontNameState->maValue <<= sName;
  rStrExpValue = aOut.makeStringAndClear();
+
if( pFontFamilyNameState )
 +
pFontFamilyNameState->mnIndex = -1;
 +
  if( pFontStyleNameState )
 +
pFontStyleNameState->mnIndex = -1;
 +
if( pFontFamilyState )
 +
pFontFamilyState->mnIndex = -1;
 +
if( pFontPitchState )
 +
pFontPitchState->mnIndex = -1;
 +
if( pFontCharsetState )
 +
pFontCharsetState->mnIndex = -1;
 
  }
 
  }
 +
...
 +
}
 +
 +
When Find( sFamilyName, sStyleName, nFamily, nPitch, eEnc )  got valid sName,  then text specific properties pFontFamilyNameState, pFontStyleNameState will be filtered and not exported, meanwhile pFontNameState is enough to determine needed element attributes.
 +
 +
After above filter process,  SvXMLExportPropertyMapper::exportXML() will use the filter result std::vector< XMLPropertyState >& rProperties to write XML. In outer iteration of exportXML(), code will iterate each type of 14 property types ( PAGE, SECTION, TEXT, GRAPHIC,CHART, COLUMN etc.) to export each type in turn ( write all of  one type's property value string in XML files and then the next type, in order to show different type of properties in different lines inside XML tags, just like below picture).
 +
 +
[[File: cell_style.jpg]]
 +
 +
The XML parts in this picture is written by ScXMLExport::_ExportStyles(), aStylesExp.exportDefaultStyle(xProperties, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME)), xCellStylesExportPropertySetMapper).
 +
For the first type of properties, _exportXML() will iterate each element of  std::vector< XMLPropertyState >& rProperties, and set rPropTypeFlags which marks property-map entries containing which property types. For the second type and so on, if judge rPropTypeFlags don't contain the type, it will not call _exportXML() so as to reduce time cost. For each type,  code will iterate every  property in  rProperties, if property index is among nPropMapStartIdx and nPropMapEndIdx of XMLPropertySetMapper and property type matchs, it will be exported. In _exportXML(), if rPropTypeFlags match MID_FLAG_ELEMENT_ITEM_EXPORT, it will be stored in SvUShorts* pIndexArray, and finally call SvXMLExportPropertyMapper::exportElementItems() to export.
 +
 +
In above exportXML(), each property in rProperties is queried probably by several times, so the performance improvemence could be considered.
 +
There are also some styles which don't call SvXMLExportPropertyMapper::exportXML(). When XMLPageExport export automatic-styles, code will call ScXMLAutoStylePoolP::exportStyleAttributes() to export attributes of each style type,  for example, style:name="ta1" style:family="table",  and style:master-page-name, which is  in XMLPropertyMapEntry aXMLScTableStylesProperties[]. style:master-page-name is not like two other entries in aXMLScTableStylesProperties[], which is exported by SvXMLExportPropertyMapper::exportXML() and put into child elements.
 +
 +
==SvXMLAutoStylePoolP, ScXMLAutoStylePoolP,  XMLFamilyDataList_Impl, SvXMLAutoStylePoolParentP_Impl==
 +
 +
SvXMLAutoStylePoolP is the main class for automatic styles export.  ScXMLAutoStylePoolP is derived from SvXMLAutoStylePoolP and could export SC  specific style attributes.
 +
 +
SvXMLAutoStylePoolP holds pointer of SvXMLAutoStylePoolP_Impl, which is implemention class for function such as Add( ),  AddFamily() and exportXML(). SvXMLAutoStylePoolP_Impl also holds XMLFamilyDataList_Impl aFamilyList. When class ScXMLExport is constructed, AddFamily( ) is called to add various type of XMLFamilyData_Impl, such as table-cell, table-column etc., to  XMLFamilyDataList_Impl.  XMLFamilyData_Impl is  data structure for each  type of style family, and it stores  mnFamily as family ID,  maStrPrefix as family prefix (such as ce, co, ta),  and mnCount as count of SvXMLAutoStylePoolPropertiesP_Impl. mnCount is copied to mnPos of SvXMLAutoStylePoolPropertiesP_Impl when add properties. SvXMLAutoStylePoolP_Impl:: Add( ) is used to add a array of XMLPropertyState to  maPropertiesList of corresponding SvXMLAutoStylePoolParentP_Impl if not added yet.
 +
 +
SvXMLAutoStylePoolParentP_Impl is  parents of AutoStylePool,  and XMLFamilyData use several SvXMLAutoStylePoolParentP_Impl  for storing styles in its maPropertiesList.  SvXMLAutoStylePoolParentP_Impl holds  msParent as parent name, such as "Default" in xml tag style:parent-style-name="Default". Sample code is as below.
 +
 +
class XMLFamilyData_Impl
 +
{
 +
public:
 +
SvXMLAutoStylePoolCache_Impl *pCache;
 +
sal_uInt32 mnFamily;
 +
::rtl::OUString maStrFamilyName;//such as table-column
 +
UniReference < SvXMLExportPropertyMapper > mxMapper;
 
   
 
   
  return bRet;
+
  SvXMLAutoStylePoolParentsP_Impl* mpParentList;// sorted list of SvXMLAutoStylePoolParentP_Impl
 +
SvXMLAutoStylePoolNamesP_Impl*     mpNameList;
 +
sal_uInt32 mnCount;//count of SvXMLAutoStylePoolPropertiesP_Impl
 +
sal_uInt32 mnName;
 +
::rtl::OUString maStrPrefix;
 +
sal_Bool bAsFamily;
 +
...
 +
 +
For properties filter process of ScXMLExport :: _ExportAutoStyles( ),  code will call xTableStylesExportPropertySetMapper to filter xTableProperties and add output xPropStates to ScXMLAutoStylePoolP, the same is using xColumnStylesExportPropertySetMapper to filter xColumnProperties. In xTableProperties filter process,  it will seek whether XMLFamilyDataList_Impl of this ScXMLAutoStylePoolP has family data of table type, if exist, it will furthermore seek SvXMLAutoStylePoolParentsP_Impl of this family data. If searched pool parent is not in  SvXMLAutoStylePoolParentsP_Impl, it will create a new pool parent, and insert into  SvXMLAutoStylePoolParentsP_Impl. Using the new pool parent, it add filtered properties, and update corresponding XMLFamilyData_Impl. The properties  is finally put in SvXMLAutoStylePoolPropertiesP_Impl, and msName, such as ce1, co1 etc., is created from pFamilyData->maStrPrefix and pFamilyData->mnName. 
 +
 
 +
When SvXMLAutoStylePoolP::exportXML( sal_Int32 nFamily,  const uno::Reference< ::com::sun::star::xml::sax::XDocumentHandler > &, const SvXMLUnitConverter&, const SvXMLNamespaceMap&), it will seek input type of family data  in maFamilyList, and if exist, it will iterate all SvXMLAutoStylePoolParentP_Impl in  found family data and all properties in SvXMLAutoStylePoolPropertiesPList_Impl of each SvXMLAutoStylePoolParentP_Impl, and then save these properties in array of SvXMLAutoStylePoolPExport_Impl, which will be exported to XML by pFamily->mxMapper->exportXML(). Sample code is as below.
 +
 
 +
struct SvXMLAutoStylePoolPExport_Impl
 +
{
 +
const ::rtl::OUString *mpParent;
 +
const SvXMLAutoStylePoolPropertiesP_Impl  *mpProperties;
 +
};
 +
 +
class SvXMLAutoStylePoolPropertiesP_Impl
 +
{
 +
::rtl::OUString   msName;//such asco1, stylename
 +
::std::vector< XMLPropertyState >  maProperties;
 +
sal_uInt32  mnPos;// pFamilyData->mnCount
 +
...
 
  }
 
  }
 +
 +
==How is XML tag constructed by XMLToken==
 +
 +
In styles.xml, we usually see attributes like style:font-name="Arial",  this  attribute is constructed by SvXMLExport::AddAttribute() and then added to SvXMLAttributeList mpAttrList and  construct SvXMLTagAttribute_Impl, which is finally written into styles.xml by SAXWriter. Sample code is as below.
 +
 +
void SvXMLExport::AddAttribute( sal_uInt16 nPrefixKey, enum XMLTokenEnum eName, const OUString& rValue )
 +
{
 +
mpAttrList->AddAttribute(
 +
        mpNamespaceMap->GetQNameByKey( nPrefixKey, GetXMLToken(eName) ),
 +
        rValue );
 +
}
 +
 +
void SvXMLAttributeList::AddAttribute( const OUString &sName , const OUString &sValue )
 +
{
 +
m_pImpl->vecAttribute.push_back( SvXMLTagAttribute_Impl( sName , sValue ) );
 +
}
 +
For style:font-name="Arial",  input parameters of SvXMLExport::AddAttribute() is, nPrefixKey:1, eName: XML_FONT_NAME, rValue:Arial. GetXMLToken(eName) get XML string for eName inside struct XMLTokenEntry aTokenList in xmltoken.cxx(lib\xmloff\source\core).When export style family, code get string for family name token in Families.hxx (xmloff\inc\xmloff).
 +
For GetQNameByKey(), we have to know how SvXMLNamespaceMap add entries before. In xmlnmspe.hxx, XML_NAMESPACE( STYLE, 1U ) defines XML_NAMESPACE_STYLE. When call xServiceFactory->createInstanceWithArguments( sComponentName , aArgs ), it will construct SvXMLExport, and _initCtor() inside xmlexp.cxx, mpNamespaceMap->Add( GetXMLToken(XML_NP_STYLE), GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE ) add  NameSpaceEntry holding full namespace name and prefix for key XML_NAMESPACE_STYLE. 
 +
 +
Fnd NameSpaceEntry entry in  aNameMap of SvXMLNamespaceMap by nKey, then get prefix "style" from the entry and append input parameter rLocalName, which get "style:font-name". After that, QNameCache will cache these infomation,and when next time call GetQNameByKey() with same parameters, code could find entry in QNameCache by key QNamePair ( nKey, &rLocalName ), the second element of the found entry is "style:font-name".
 +
 +
class NameSpaceEntry : public cppu::OWeakObject
 +
{
 +
public:
 +
::rtl::OUString  sName;    //sName refers to the full namespace name
 +
::rtl::OUString  sPrefix;  // sPrefix is the prefix used to declare a given item to be from a given namespace
 +
sal_uInt16  nKey;          //nKey is the unique identifier of a namespace
 +
 +
};
 +
 +
==UNO interfaces, transfer properties across modules==
 +
 +
As styles properties are transfered between several modules, such as SC, xmloff and SAX, so interfaces XpropertySet, XPropertySetInfo etc are used to support UNO transfer.  When export  style “Result”,”Result2” inside stylist, XMLStyleExport::exportStyleFamily() will query Reference< XStyleFamiliesSupplier > xFamiliesSupp from document model, and finally get each Reference< XStyle > xStyle and call exportStyle() to export. In exportStyle(), Reference< XPropertySet > xPropSet is queried from xStyle. XpropertySet, which is implemented by ScStyleObj here,  could get property value uno::Any by method getPropertyValue([in] string PropertyName). Meanwhile get Reference< XPropertySetInfo > xInfo, which has  properties information by APIName, from xPropSet. By methods of xInfo,which is implemented by SfxItemPropertySetInfo here, xPropSet is processed for the first stage and transformed into FilterPropertiesInfo_Impl *pFilterInfo.
 +
 +
XpropertyState is queried from XpropertySet when FillPropertyStateArray(), and is used to get each property's state[3], which refers enum PropertyState. By FilterPropertiesInfo_Impl::FillPropertyStateArray, properties in XpropertyState are filtered by judging PropertyState is default, set-direct etc., std::vector< XMLPropertyState > xPropStates is finally got and passed to exportXML() for writing properties string into XML. mnIndex of XMLPropertyState correspond to entry index of XMLPropertySetMapper,  therefore could used to get property-name. Sample code is as below.
 +
 +
enum PropertyState
 +
{
 +
    PropertyState_DIRECT_VALUE = 0,
 +
    PropertyState_DEFAULT_VALUE = 1,
 +
    PropertyState_AMBIGUOUS_VALUE = 2,
 +
    PropertyState_MAKE_FIXED_SIZE = SAL_MAX_ENUM
 +
};
 +
class SAL_NO_VTABLE XPropertyState : public ::com::sun::star::uno::XInterface
 +
{
 +
public:
 +
    virtual ::com::sun::star::beans::PropertyState SAL_CALL getPropertyState( const ::rtl::OUString& PropertyName ) throw (...) = 0;
 +
    virtual void SAL_CALL setPropertyToDefault( const ::rtl::OUString& PropertyName ) throw (...) = 0;
 +
    virtual ::com::sun::star::uno::Any SAL_CALL getPropertyDefault( const ::rtl::OUString& aPropertyName ) throw (...) = 0;
 +
...
 +
};
 +
published interface XPropertySet: com::sun::star::uno::XInterface
 +
{
 +
com::sun::star::beans::XPropertySetInfo getPropertySetInfo();
 +
void setPropertyValue( [in] string aPropertyName, [in] any aValue ) raises(...);
 +
any getPropertyValue( [in] string PropertyName ) raises(...);
 +
...
 +
}
 +
 +
 +
==References==
 +
 +
[1] OASIS OpenDocument Essentials, http://books.evc-cit.info/
 +
 +
[2] Open Document Format for Office Applications (OpenDocument) Version 1.2, Part 1
 +
 +
[3] http://wiki.openoffice.org/wiki/ZH/Documentation/BASIC_Guide/Structure_of_Text_Documents

Latest revision as of 09:37, 31 August 2012


This document mainly introduces the current design of styles export mechanism for spreadsheet. Before introduction of design, some basic knowledge of styles is required.


Basic concept of Styles

In the OpenDocument format, formatting properties, which influences the visual representation of objects, are stored in styles. Using styles to store formatting properties has advantages such as, format information is separated from document content, and styles enable consistent formatting and changing of formatting for objects subject to styles.

Styles.xml inside zipped OpenDocument is the main file for styles storage, as following sample picture of styles.xml shows, both <style:default-style> and <style:style> in <office:styles> have a “style:name” attribute. In fact, styles and font face declarations are referenced by their style:name attribute[1]. A referenced style or font face declaration should be defined in the same file as the reference, or in styles.xml. Styles built in the stylist (can be used by click menu "Format"--"Styles and formatting") or ones that you create there, will have names like “Heading 1” or Custom Citation. Automatic styles <office:automatic-styles> will have names consisting of style-family abbreviation followed by a number; a style name such as T1 is the first automatic style for style:family="text"; P3 would be the third style for paragraphs, ta2 would be the second style for a table, ro4 would be the fourth style for a table row, etc(please refer content.xml for OpenDocument). The other attribute of interest is the optional parent-style-name, which you will find in styles that have been derived from other styles.

Styles.xml .jpg

<style:font-face> element represents a font face declaration which documents the properties of a font used in a document. OpenDocument font face declarations may have an unique name. This name can be used inside styles (as an attribute of <style:text-properties> element) as value of the style:font-name attribute to select a font face declaration. <style:style> element represents styles,and <style:default-style> element represents default styles. A default style specifies default formatting properties for a style family. These defaults are used if a formatting property is neither specified by an automatic nor a common style. Default styles exist for all style families that are represented by the <style:style> element specified by the style:family attribute. An OpenDocument document should contain the default styles of the style families for which are used in common or automatic styles in the document.<office:master-styles> <style:master-page> defines page styles which is in stylist.

Attributes for elements defined by OpenDocument are divided between those used by structural elements[2] versus those used by <style:*-properties> elements. Attributes defined by reference[2] standard have default values , and when any element appears in a document instance without such an attribute, consumers should behave as if the attribute is present with the defined default value. <style:*-properties> elements is commonly used to aggregate attributes of one type for specific style. Formatting definitions are expressed as attributes on the <style:*-properties> elements or as child elements of these elements.

From code perspective, these <office:styles> , <office:automatic-styles> etc elements in styles.xml is written by SvXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass ), when export ods, eClass is XML_SPREADSHEET. For example, ImplExportStyles() inside SvXMLExport::exportDoc() is for writing <office:styles> elements, _ExportFontDecls(); is for <office:font-face-decls>, and ImplExportAutoStyles() is for <office:automatic-styles>. Inside ImplExportStyles() , ScXMLExport::_ExportStyles will call exportDefaultStyle(), exportDataStyles(), exportStyleFamily() etc, in turn to export <style:default-style> <number:number-style>, <style:style> etc. ScXMLImportWrapper::ExportToComponent() is called with different parameters to export each file inside ods, such as styles.xml, content.xml.

Styles export sequence diagrams overview

<style:font-face> elements export is mainly in following sequence, Styles font face export.jpg <style: default style> elements is exported generally as following sequece,

 Defaultstyle.jpg

Automatic styles export is mainly as below,

 Autostyle.jpg

Main class for export, SvXMLExport and ScXMLExport

SvXMLExport is the main class for XML file export. It implements several UNO interfaces such as ::com::sun::star::document::Xfilter, which is used by service ImportFilter or ExportFilter to support loading/saving of documents in different formats, and ::com::sun::star::xml::sax::XDocumentHandler plus ::com::sun::star::xml::sax::XEntendedDocumentHandler, which is interfaces for calling SAX(an event-based sequential access parser API ). It also holds ::com::sun::star::frame::XModel to access document data model. And it use XMLFontAutoStylePool, SvXMLAutoStylePoolP to manage font declarations and automatic styles store plus export. Member UniReference< XMLPageExport > mxPageExport is used as child exporter, which export page styles; and UniReference< XMLShapeExport > mxShapeExport for exporting shape styles. It has function ImplExportStyles() for <office:styles> export, _ImplExportMasterStyles() for <style:master-styles> export, etc.

ScXMLExport is derived from SvXMLExport and it holds specific SvXMLExportPropertyMapper for SC module, such as xCellStylesExportPropertySetMapper, xRowStylesExportPropertySetMapper. And ScColumnStyles, ScRowStyles etc for corresponding automatic styles export. It implements _ExportFontDecls(), _ExportStyles(), _ExportAutoStyles() etc to actually export styles. ScXMLExport will be constructed once writing a XML file such as styles.xml, content.xml.

class XMLOFF_DLLPUBLIC SvXMLExport 
{
		…
 	SvXMLNamespaceMap			*mpNamespaceMap;	// the namepspace map
 	SvXMLUnitConverter			*mpUnitConv;		// the unit converter
 
 	UniReference< SvXMLAutoStylePoolP > mxAutoStylePool;
   	UniReference< XMLFontAutoStylePool > mxFontAutoStylePool;
 
 	SAL_DLLPRIVATE void ImplExportMeta(); // <office:meta>
 	SAL_DLLPRIVATE void ImplExportSettings(); // <office:settings>
 	SAL_DLLPRIVATE void ImplExportStyles( sal_Bool bUsed ); // <office:styles>
 	SAL_DLLPRIVATE void ImplExportAutoStyles( sal_Bool bUsed );// <office:automatic-styles>
 	SAL_DLLPRIVATE void ImplExportMasterStyles( sal_Bool bUsed ); // <office:master-styles>
 	SAL_DLLPRIVATE void ImplExportContent(); // <office:body>
 
 	// This method should be overloaded to export the content of <style:styles>.
  	virtual void _ExportStyles( sal_Bool bUsed ) ;
 
     // methods for accessing the document handler and handling SAX errors
 	void StartElement(sal_uInt16 nPrefix,
                         enum ::xmloff::token::XMLTokenEnum eName,
 					    sal_Bool bIgnWSOutside );
 		…
} 

SvXMLElementExport is helper class to export an element, its constructors prints a start tag with the common attributes. For example, SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, XML_FONT_FACE, sal_True, sal_True ) could print tag <style:font-face style:name="Arial" svg:font-family="Arial" style:font-pitch="variable" /> . Constructor of SvXMLElementExport will indirectly call SvXMLExport::StartElement() to write XML. And the destructor ~SvXMLElementExport() prints an end tag. For different properties, process of writing XML is quite differently. Handling color will use XMLColorPropHdl for writing XML and string using XMLStringProHdl; meanwhile XMLPropertyHandler is abstract base-class for different XML-types. Derivations of XMLPropertyHandler knows how to compare, im/export a special XML-type.

Some property types need SvXMLUnitConverter converts values from their internal represantation to the textual form used in xml and back.Most of the methods are static but the SvXMLUnitConverter can also store default units for both numerical and textual measures. For example, when XMLFontPitchPropHdl writing FontPitch property to XML, it use SvXMLUnitConverter::convertEnum() to convert enum FontPitch to textual form, by searching SvXMLEnumMapEntry aFontPitchMapping[] it will get mapped XMLTokenEnum and finally get corresponding text in xmltoken.cxx. Sample code is as below.

static SvXMLEnumMapEntry __READONLY_DATA aFontPitchMapping[] =
{ 
 	{ XML_FIXED,		    PITCH_FIXED		},
 	{ XML_VARIABLE,	        PITCH_VARIABLE	},
 	{ XML_TOKEN_INVALID,    0 				}
};
sal_Bool XMLFontPitchPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
{ 
 	sal_Bool bRet = sal_False;
 	sal_Int16 nPitch = sal_Int16();
 	OUStringBuffer aOut;
 	FontPitch ePitch = PITCH_DONTKNOW;
 	if( rValue >>= nPitch )
 		ePitch =  (FontPitch)nPitch;
 	if( PITCH_DONTKNOW != ePitch )
 	{
 		bRet = SvXMLUnitConverter::convertEnum( aOut, ePitch, aFontPitchMapping, XML_FIXED );
 		rStrExpValue = aOut.makeStringAndClear();
 	} 
 	return bRet;
} 

XMLPropertySetMapper, SvXMLExportPropertyMapper, XMLPropertySetMapperEntry_Impl

XMLPropertySetMapper is helper class for XML im/export, it holds a pointer to a given array of XMLPropertySetMapperEntry_Impl, which is added by XMLPropertySetMapper::XMLPropertySetMapper(const XMLPropertyMapEntry* pEntries, const UniReference< XMLPropertyHandlerFactory >& rFactory ). XMLPropertyMapEntry* pEntries is usually passed from static array, such as XMLPropertyMapEntry aXMLScCellStylesProperties[], defined in xmlstyle.cxx, txtprmap.cxx etc. XMLPropertySetMapperEntry_Impl is basic element for export XML, it transforms XMLTokenEnum meXMLName inside XMLPropertyMapEntry to sXMLAttributeName, which will be written in XML, so it holds a Sequence of XML-names (for properties) for writing XML. XMLPropertySetMapperEntry_Impl also holds nContextId for context filter, for example, in text properties context, nContextId will only count id for text properties, it is defined intuitive in txtprmap.cxx, such as #define CTF_CHARHEIGHT (XML_TEXT_CTF_START + 1). sAPIPropertyName in XMLPropertySetMapperEntry_Impl is for UNO property-name. XMLPropertySetMapper provides several methods to access data from XMLPropertySetMapperEntry_Impl array, such as GetEntryXMLName( sal_Int32 nIndex ), GetEntryNameSpace( sal_Int32 nIndex ). Sample code is as below.

// xmloff\source\text\txtprmap.cxx
XMLPropertyMapEntry aXMLParaPropMap[]//hundreds of entries
XMLPropertyMapEntry aXMLSectionPropMap
XMLPropertyMapEntry aXMLTextPropMap[]

XMLPropertyMapEntry aXMLParaPropMap[] =
{
	MP_E( "ParaUserDefinedAttributes", TEXT, XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), 	// RES_UNKNOWNATR_CONTAINER
	MP_E( "ParaLeftMargin",	FO, MARGIN, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPE RTY, CTF_PARAMARGINALL ), 	// RES_LR_SPACE
	...
 } 
class XMLPropertySetMapper
{ 
  	...
 	    	sal_uInt32 GetEntryFlags( sal_Int32 nIndex ) const    //Returns the flags of an entry
  	    	sal_uInt32 GetEntryType( sal_Int32 nIndex,  sal_Bool bWithFlags = sal_True )  const    //Returns the type of an entry
 	   	sal_uInt16 GetEntryNameSpace( sal_Int32 nIndex ) const   //Returns the namespace-key of an entry
  /** import/export, this methods calls the respective im/export-method of the respective PropertyHandler. */
virtual sal_Bool exportXML( ::rtl::OUString& rStrExpValue, const XMLPropertyState& rProperty, const SvXMLUnitConverter& rUnitConverter )   const;
 	...
 }

//ScXMLExport:: ScXMLExport()
 xCellStylesPropertySetMapper = new XMLPropertySetMapper((XMLPropertyMapEntry*)aXMLScCellStylesProperties,    xScPropHdlFactory);
 xColumnStylesPropertySetMapper = new XMLPropertySetMapper((XMLPropertyMapEntry*)aXMLScColumnStylesProperties,   xScPropHdlFactory);
 xCellStylesExportPropertySetMapper = new ScXMLCellExportPropertyMapper(xCellStylesPropertySetMapper);

For nType in property map entry (XMLPropertySetMapperEntry_Impl), 15th to 18th bits from right of it are for type index, mnIndex in XMLPropertyState correspond to this index, which will be mapped for query information when exportXML(). And 32nd to 14th bits from right of nType are used as flags, such as following definition in Xmltypes.hxx (lib\xmloff\inc\xmloff).

SvXMLExportPropertyMapper is the base class of ScXMLCellExportPropertyMapper, ScXMLColumnExportPropertyMapper etc. They hold XMLPropertySetMapper and knows how to compare with parameter XPropertySet and filter unwanted properties. SvXMLExportPropertyMapper has method Filter( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet>), which filter properties and only take all properties of the XPropertySet which are also found in the XMLPropertyMapEntry-array and which are not default or inherited. SvXMLExportPropertyMapper also has method FilterDefaults( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rPropSet ) , which has quite similar process as Filter() except that it only takes properties that have the map flag MID_FLAG_DEFAULT_ITEM_EXPORT, and instead of the property's value, its defualt value is set for export. It holds mxNextMapper for stacked contextfilter(), which will be described afterwards. For writing XML, it has method exportXML(), which fills the SvXMLAttributeList& rAttrList with the items in std::vector< XMLPropertyState >& rProperties , and has handleSpecialItem() for every item that has the MID_FLAG_SPECIAL_ITEM_EXPORT flag.

For Filter() or FilterDefaults(), it will first exclude mapperEntries which has flag MID_FLAG_NO_PROPERTY_EXPORT out of properties intended export. Entries that is included in properties intended to export should furthmore meet followings, first, it has flags MID_FLAG_MUST_EXIST or input XPropertySet contains property type of this entry; second, ODFVersion is meeted; third, pass FillPropertyStateArray(aPropStateArray, xPropSet, maPropMapper, bDefault) and remain;(for FilterDefaults() , bDefault == true, and false for Filter()); fourth, pass ContextFilter() and remain.

In FillPropertyStateArray(aPropStateArray, xPropSet, maPropMapper,bDefault), code will judge bDefault to export properties with defualt value or new value. Output parameter aPropStateArray will then filtered by stacked mxNextMapper->ContextFilter( ).

ContextFilter() is application-specific filter, just as XMLPageExportPropertyMapper, ScXMLCellExportPropertyMapper, XMLTextExportPropertySetMapper has different implementation, and by default it do nothing. Take XMLTextExportPropertySetMapper for exmaple, ContextFilter() will finally call ContextFontFilter(), as follows,

void XMLTextExportPropertySetMapper::ContextFontFilter(XMLPropertyState *pFontNameState, XMLPropertyState *pFontFamilyNameState,
  XMLPropertyState *pFontStyleNameState, XMLPropertyState *pFontFamilyState, XMLPropertyState *pFontPitchState,
  XMLPropertyState *pFontCharsetState ) const
 {	...
	OUString sName( ((SvXMLExport&)GetExport()).GetFontAutoStylePool()->Find( sFamilyName, sStyleName, nFamily, nPitch, eEnc ) );
	if( sName.getLength() )
	{
		pFontNameState->maValue <<= sName;
		if( pFontFamilyNameState )
			pFontFamilyNameState->mnIndex = -1;
		if( pFontStyleNameState )
			pFontStyleNameState->mnIndex = -1;
		if( pFontFamilyState )
			pFontFamilyState->mnIndex = -1;
		if( pFontPitchState )
			pFontPitchState->mnIndex = -1;
		if( pFontCharsetState )
			pFontCharsetState->mnIndex = -1;
	}
	...
}

When Find( sFamilyName, sStyleName, nFamily, nPitch, eEnc ) got valid sName, then text specific properties pFontFamilyNameState, pFontStyleNameState will be filtered and not exported, meanwhile pFontNameState is enough to determine needed element attributes.

After above filter process, SvXMLExportPropertyMapper::exportXML() will use the filter result std::vector< XMLPropertyState >& rProperties to write XML. In outer iteration of exportXML(), code will iterate each type of 14 property types ( PAGE, SECTION, TEXT, GRAPHIC,CHART, COLUMN etc.) to export each type in turn ( write all of one type's property value string in XML files and then the next type, in order to show different type of properties in different lines inside XML tags, just like below picture).

Cell style.jpg

The XML parts in this picture is written by ScXMLExport::_ExportStyles(), aStylesExp.exportDefaultStyle(xProperties, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME)), xCellStylesExportPropertySetMapper). For the first type of properties, _exportXML() will iterate each element of std::vector< XMLPropertyState >& rProperties, and set rPropTypeFlags which marks property-map entries containing which property types. For the second type and so on, if judge rPropTypeFlags don't contain the type, it will not call _exportXML() so as to reduce time cost. For each type, code will iterate every property in rProperties, if property index is among nPropMapStartIdx and nPropMapEndIdx of XMLPropertySetMapper and property type matchs, it will be exported. In _exportXML(), if rPropTypeFlags match MID_FLAG_ELEMENT_ITEM_EXPORT, it will be stored in SvUShorts* pIndexArray, and finally call SvXMLExportPropertyMapper::exportElementItems() to export.

In above exportXML(), each property in rProperties is queried probably by several times, so the performance improvemence could be considered. There are also some styles which don't call SvXMLExportPropertyMapper::exportXML(). When XMLPageExport export automatic-styles, code will call ScXMLAutoStylePoolP::exportStyleAttributes() to export attributes of each style type, for example, style:name="ta1" style:family="table", and style:master-page-name, which is in XMLPropertyMapEntry aXMLScTableStylesProperties[]. style:master-page-name is not like two other entries in aXMLScTableStylesProperties[], which is exported by SvXMLExportPropertyMapper::exportXML() and put into child elements.

SvXMLAutoStylePoolP, ScXMLAutoStylePoolP, XMLFamilyDataList_Impl, SvXMLAutoStylePoolParentP_Impl

SvXMLAutoStylePoolP is the main class for automatic styles export. ScXMLAutoStylePoolP is derived from SvXMLAutoStylePoolP and could export SC specific style attributes.

SvXMLAutoStylePoolP holds pointer of SvXMLAutoStylePoolP_Impl, which is implemention class for function such as Add( ), AddFamily() and exportXML(). SvXMLAutoStylePoolP_Impl also holds XMLFamilyDataList_Impl aFamilyList. When class ScXMLExport is constructed, AddFamily( ) is called to add various type of XMLFamilyData_Impl, such as table-cell, table-column etc., to XMLFamilyDataList_Impl. XMLFamilyData_Impl is data structure for each type of style family, and it stores mnFamily as family ID, maStrPrefix as family prefix (such as ce, co, ta), and mnCount as count of SvXMLAutoStylePoolPropertiesP_Impl. mnCount is copied to mnPos of SvXMLAutoStylePoolPropertiesP_Impl when add properties. SvXMLAutoStylePoolP_Impl:: Add( ) is used to add a array of XMLPropertyState to maPropertiesList of corresponding SvXMLAutoStylePoolParentP_Impl if not added yet.

SvXMLAutoStylePoolParentP_Impl is parents of AutoStylePool, and XMLFamilyData use several SvXMLAutoStylePoolParentP_Impl for storing styles in its maPropertiesList. SvXMLAutoStylePoolParentP_Impl holds msParent as parent name, such as "Default" in xml tag style:parent-style-name="Default". Sample code is as below.

class XMLFamilyData_Impl
{
public:
	SvXMLAutoStylePoolCache_Impl		*pCache;
	sal_uInt32							mnFamily;
	::rtl::OUString						maStrFamilyName;//such as table-column
	UniReference < SvXMLExportPropertyMapper >	mxMapper;

	SvXMLAutoStylePoolParentsP_Impl*	mpParentList;// sorted list of SvXMLAutoStylePoolParentP_Impl
	SvXMLAutoStylePoolNamesP_Impl*	    mpNameList;
	sal_uInt32							mnCount;//count of SvXMLAutoStylePoolPropertiesP_Impl
	sal_uInt32							mnName;
	::rtl::OUString						maStrPrefix;
	sal_Bool							bAsFamily;
		...
}  

For properties filter process of ScXMLExport :: _ExportAutoStyles( ), code will call xTableStylesExportPropertySetMapper to filter xTableProperties and add output xPropStates to ScXMLAutoStylePoolP, the same is using xColumnStylesExportPropertySetMapper to filter xColumnProperties. In xTableProperties filter process, it will seek whether XMLFamilyDataList_Impl of this ScXMLAutoStylePoolP has family data of table type, if exist, it will furthermore seek SvXMLAutoStylePoolParentsP_Impl of this family data. If searched pool parent is not in SvXMLAutoStylePoolParentsP_Impl, it will create a new pool parent, and insert into SvXMLAutoStylePoolParentsP_Impl. Using the new pool parent, it add filtered properties, and update corresponding XMLFamilyData_Impl. The properties is finally put in SvXMLAutoStylePoolPropertiesP_Impl, and msName, such as ce1, co1 etc., is created from pFamilyData->maStrPrefix and pFamilyData->mnName.

When SvXMLAutoStylePoolP::exportXML( sal_Int32 nFamily, const uno::Reference< ::com::sun::star::xml::sax::XDocumentHandler > &, const SvXMLUnitConverter&, const SvXMLNamespaceMap&), it will seek input type of family data in maFamilyList, and if exist, it will iterate all SvXMLAutoStylePoolParentP_Impl in found family data and all properties in SvXMLAutoStylePoolPropertiesPList_Impl of each SvXMLAutoStylePoolParentP_Impl, and then save these properties in array of SvXMLAutoStylePoolPExport_Impl, which will be exported to XML by pFamily->mxMapper->exportXML(). Sample code is as below.

struct SvXMLAutoStylePoolPExport_Impl
{
	const ::rtl::OUString	*mpParent;
	const SvXMLAutoStylePoolPropertiesP_Impl  *mpProperties;
}; 

class SvXMLAutoStylePoolPropertiesP_Impl
{
	::rtl::OUString	  msName;//such asco1, stylename
	::std::vector< XMLPropertyState >  maProperties;
	sal_uInt32  mnPos;// pFamilyData->mnCount 
	...
}

How is XML tag constructed by XMLToken

In styles.xml, we usually see attributes like style:font-name="Arial", this attribute is constructed by SvXMLExport::AddAttribute() and then added to SvXMLAttributeList mpAttrList and construct SvXMLTagAttribute_Impl, which is finally written into styles.xml by SAXWriter. Sample code is as below.

void SvXMLExport::AddAttribute( sal_uInt16 nPrefixKey, enum XMLTokenEnum eName, const OUString& rValue )
{
	mpAttrList->AddAttribute(
       mpNamespaceMap->GetQNameByKey( nPrefixKey, GetXMLToken(eName) ),
       rValue );
} 

void SvXMLAttributeList::AddAttribute( const OUString &sName , const OUString &sValue )
{
	m_pImpl->vecAttribute.push_back( SvXMLTagAttribute_Impl( sName , sValue ) );
}

For style:font-name="Arial", input parameters of SvXMLExport::AddAttribute() is, nPrefixKey:1, eName: XML_FONT_NAME, rValue:Arial. GetXMLToken(eName) get XML string for eName inside struct XMLTokenEntry aTokenList in xmltoken.cxx(lib\xmloff\source\core).When export style family, code get string for family name token in Families.hxx (xmloff\inc\xmloff). For GetQNameByKey(), we have to know how SvXMLNamespaceMap add entries before. In xmlnmspe.hxx, XML_NAMESPACE( STYLE, 1U ) defines XML_NAMESPACE_STYLE. When call xServiceFactory->createInstanceWithArguments( sComponentName , aArgs ), it will construct SvXMLExport, and _initCtor() inside xmlexp.cxx, mpNamespaceMap->Add( GetXMLToken(XML_NP_STYLE), GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE ) add NameSpaceEntry holding full namespace name and prefix for key XML_NAMESPACE_STYLE.

Fnd NameSpaceEntry entry in aNameMap of SvXMLNamespaceMap by nKey, then get prefix "style" from the entry and append input parameter rLocalName, which get "style:font-name". After that, QNameCache will cache these infomation,and when next time call GetQNameByKey() with same parameters, code could find entry in QNameCache by key QNamePair ( nKey, &rLocalName ), the second element of the found entry is "style:font-name".

class NameSpaceEntry : public cppu::OWeakObject
{
public:
	 	::rtl::OUString  sName;    //sName refers to the full namespace name
	 	::rtl::OUString  sPrefix;  // sPrefix is the prefix used to declare a given item to be from a given namespace
	 	sal_uInt16  nKey;          //nKey is the unique identifier of a namespace

};

UNO interfaces, transfer properties across modules

As styles properties are transfered between several modules, such as SC, xmloff and SAX, so interfaces XpropertySet, XPropertySetInfo etc are used to support UNO transfer. When export style “Result”,”Result2” inside stylist, XMLStyleExport::exportStyleFamily() will query Reference< XStyleFamiliesSupplier > xFamiliesSupp from document model, and finally get each Reference< XStyle > xStyle and call exportStyle() to export. In exportStyle(), Reference< XPropertySet > xPropSet is queried from xStyle. XpropertySet, which is implemented by ScStyleObj here, could get property value uno::Any by method getPropertyValue([in] string PropertyName). Meanwhile get Reference< XPropertySetInfo > xInfo, which has properties information by APIName, from xPropSet. By methods of xInfo,which is implemented by SfxItemPropertySetInfo here, xPropSet is processed for the first stage and transformed into FilterPropertiesInfo_Impl *pFilterInfo.

XpropertyState is queried from XpropertySet when FillPropertyStateArray(), and is used to get each property's state[3], which refers enum PropertyState. By FilterPropertiesInfo_Impl::FillPropertyStateArray, properties in XpropertyState are filtered by judging PropertyState is default, set-direct etc., std::vector< XMLPropertyState > xPropStates is finally got and passed to exportXML() for writing properties string into XML. mnIndex of XMLPropertyState correspond to entry index of XMLPropertySetMapper, therefore could used to get property-name. Sample code is as below.

enum PropertyState
{
    PropertyState_DIRECT_VALUE = 0,
    PropertyState_DEFAULT_VALUE = 1,
    PropertyState_AMBIGUOUS_VALUE = 2,
    PropertyState_MAKE_FIXED_SIZE = SAL_MAX_ENUM
};
class SAL_NO_VTABLE XPropertyState : public ::com::sun::star::uno::XInterface
{
public:
    virtual ::com::sun::star::beans::PropertyState SAL_CALL getPropertyState( const ::rtl::OUString& PropertyName ) throw (...) = 0;
    virtual void SAL_CALL setPropertyToDefault( const ::rtl::OUString& PropertyName ) throw (...) = 0;
    virtual ::com::sun::star::uno::Any SAL_CALL getPropertyDefault( const ::rtl::OUString& aPropertyName ) throw (...) = 0;
	...
};
published interface XPropertySet: com::sun::star::uno::XInterface
{ 
	com::sun::star::beans::XPropertySetInfo getPropertySetInfo(); 
	void setPropertyValue( [in] string aPropertyName, [in] any aValue ) raises(...); 
	any getPropertyValue( [in] string PropertyName ) raises(...); 
				...
}


References

[1] OASIS OpenDocument Essentials, http://books.evc-cit.info/

[2] Open Document Format for Office Applications (OpenDocument) Version 1.2, Part 1

[3] http://wiki.openoffice.org/wiki/ZH/Documentation/BASIC_Guide/Structure_of_Text_Documents

Personal tools