office-gobmx/xmloff/source/style/xmlnumfi.cxx
2011-11-27 13:27:50 -06:00

2235 lines
84 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org 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 Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
#include <unotools/syslocale.hxx>
#define _ZFORLIST_DECLARE_TABLE
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
#include <svl/numuno.hxx>
#include <rtl/math.hxx>
#include <i18npool/mslangid.hxx>
#include <tools/debug.hxx>
#include <rtl/ustrbuf.hxx>
#include <sax/tools/converter.hxx>
#include <xmloff/xmlnumfi.hxx>
#include <xmloff/xmltkmap.hxx>
#include "xmloff/xmlnmspe.hxx"
#include <xmloff/xmlictxt.hxx>
#include <xmloff/xmlimp.hxx>
#include <xmloff/xmluconv.hxx>
#include <xmloff/nmspmap.hxx>
#include <xmloff/families.hxx>
#include <xmloff/xmltoken.hxx>
using ::rtl::OUString;
using ::rtl::OUStringBuffer;
using namespace ::com::sun::star;
using namespace ::xmloff::token;
//-------------------------------------------------------------------------
struct SvXMLNumFmtEntry
{
rtl::OUString aName;
sal_uInt32 nKey;
sal_Bool bRemoveAfterUse;
SvXMLNumFmtEntry( const rtl::OUString& rN, sal_uInt32 nK, sal_Bool bR ) :
aName(rN), nKey(nK), bRemoveAfterUse(bR) {}
};
typedef SvXMLNumFmtEntry* SvXMLNumFmtEntryPtr;
SV_DECL_PTRARR_DEL( SvXMLNumFmtEntryArr, SvXMLNumFmtEntryPtr, 4, 4 )
struct SvXMLEmbeddedElement
{
sal_Int32 nFormatPos;
rtl::OUString aText;
SvXMLEmbeddedElement( sal_Int32 nFP, const rtl::OUString& rT ) :
nFormatPos(nFP), aText(rT) {}
// comparison operators for PTRARR sorting - sorted by position
sal_Bool operator ==( const SvXMLEmbeddedElement& r ) const { return nFormatPos == r.nFormatPos; }
sal_Bool operator < ( const SvXMLEmbeddedElement& r ) const { return nFormatPos < r.nFormatPos; }
};
typedef SvXMLEmbeddedElement* SvXMLEmbeddedElementPtr;
SV_DECL_PTRARR_SORT_DEL( SvXMLEmbeddedElementArr, SvXMLEmbeddedElementPtr, 0, 4 )
//-------------------------------------------------------------------------
class SvXMLNumImpData
{
SvNumberFormatter* pFormatter;
SvXMLTokenMap* pStylesElemTokenMap;
SvXMLTokenMap* pStyleElemTokenMap;
SvXMLTokenMap* pStyleAttrTokenMap;
SvXMLTokenMap* pStyleElemAttrTokenMap;
LocaleDataWrapper* pLocaleData;
SvXMLNumFmtEntryArr aNameEntries;
::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > mxServiceFactory;
public:
SvXMLNumImpData(
SvNumberFormatter* pFmt,
const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory );
~SvXMLNumImpData();
SvNumberFormatter* GetNumberFormatter() const { return pFormatter; }
const SvXMLTokenMap& GetStylesElemTokenMap();
const SvXMLTokenMap& GetStyleElemTokenMap();
const SvXMLTokenMap& GetStyleAttrTokenMap();
const SvXMLTokenMap& GetStyleElemAttrTokenMap();
const LocaleDataWrapper& GetLocaleData( LanguageType nLang );
sal_uInt32 GetKeyForName( const rtl::OUString& rName );
void AddKey( sal_uInt32 nKey, const rtl::OUString& rName, sal_Bool bRemoveAfterUse );
void SetUsed( sal_uInt32 nKey );
void RemoveVolatileFormats();
};
struct SvXMLNumberInfo
{
sal_Int32 nDecimals;
sal_Int32 nInteger;
sal_Int32 nExpDigits;
sal_Int32 nNumerDigits;
sal_Int32 nDenomDigits;
sal_Bool bGrouping;
sal_Bool bDecReplace;
sal_Bool bVarDecimals;
double fDisplayFactor;
SvXMLEmbeddedElementArr aEmbeddedElements;
SvXMLNumberInfo()
{
nDecimals = nInteger = nExpDigits = nNumerDigits = nDenomDigits = -1;
bGrouping = bDecReplace = bVarDecimals = sal_False;
fDisplayFactor = 1.0;
}
};
class SvXMLNumFmtElementContext : public SvXMLImportContext
{
SvXMLNumFormatContext& rParent;
sal_uInt16 nType;
rtl::OUStringBuffer aContent;
SvXMLNumberInfo aNumInfo;
LanguageType nElementLang;
sal_Bool bLong;
sal_Bool bTextual;
rtl::OUString sCalendar;
public:
SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
const rtl::OUString& rLName,
SvXMLNumFormatContext& rParentContext, sal_uInt16 nNewType,
const ::com::sun::star::uno::Reference<
::com::sun::star::xml::sax::XAttributeList>& xAttrList );
virtual ~SvXMLNumFmtElementContext();
virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
const rtl::OUString& rLocalName,
const ::com::sun::star::uno::Reference<
::com::sun::star::xml::sax::XAttributeList>& xAttrList );
virtual void Characters( const rtl::OUString& rChars );
virtual void EndElement();
void AddEmbeddedElement( sal_Int32 nFormatPos, const rtl::OUString& rContent );
};
class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext
{
SvXMLNumFmtElementContext& rParent;
rtl::OUStringBuffer aContent;
sal_Int32 nTextPosition;
public:
SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
const rtl::OUString& rLName,
SvXMLNumFmtElementContext& rParentContext,
const ::com::sun::star::uno::Reference<
::com::sun::star::xml::sax::XAttributeList>& xAttrList );
virtual ~SvXMLNumFmtEmbeddedTextContext();
virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
const rtl::OUString& rLocalName,
const ::com::sun::star::uno::Reference<
::com::sun::star::xml::sax::XAttributeList>& xAttrList );
virtual void Characters( const rtl::OUString& rChars );
virtual void EndElement();
};
class SvXMLNumFmtMapContext : public SvXMLImportContext
{
SvXMLNumFormatContext& rParent;
rtl::OUString sCondition;
rtl::OUString sName;
public:
SvXMLNumFmtMapContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
const rtl::OUString& rLName,
SvXMLNumFormatContext& rParentContext,
const ::com::sun::star::uno::Reference<
::com::sun::star::xml::sax::XAttributeList>& xAttrList );
virtual ~SvXMLNumFmtMapContext();
virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
const rtl::OUString& rLocalName,
const ::com::sun::star::uno::Reference<
::com::sun::star::xml::sax::XAttributeList>& xAttrList );
virtual void Characters( const rtl::OUString& rChars );
virtual void EndElement();
};
class SvXMLNumFmtPropContext : public SvXMLImportContext
{
SvXMLNumFormatContext& rParent;
sal_Int32 m_nColor;
sal_Bool bColSet;
public:
SvXMLNumFmtPropContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
const rtl::OUString& rLName,
SvXMLNumFormatContext& rParentContext,
const ::com::sun::star::uno::Reference<
::com::sun::star::xml::sax::XAttributeList>& xAttrList );
virtual ~SvXMLNumFmtPropContext();
virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
const rtl::OUString& rLocalName,
const ::com::sun::star::uno::Reference<
::com::sun::star::xml::sax::XAttributeList>& xAttrList );
virtual void Characters( const rtl::OUString& rChars );
virtual void EndElement();
};
//-------------------------------------------------------------------------
enum SvXMLStyleTokens
{
XML_TOK_STYLE_TEXT,
XML_TOK_STYLE_NUMBER,
XML_TOK_STYLE_SCIENTIFIC_NUMBER,
XML_TOK_STYLE_FRACTION,
XML_TOK_STYLE_CURRENCY_SYMBOL,
XML_TOK_STYLE_DAY,
XML_TOK_STYLE_MONTH,
XML_TOK_STYLE_YEAR,
XML_TOK_STYLE_ERA,
XML_TOK_STYLE_DAY_OF_WEEK,
XML_TOK_STYLE_WEEK_OF_YEAR,
XML_TOK_STYLE_QUARTER,
XML_TOK_STYLE_HOURS,
XML_TOK_STYLE_AM_PM,
XML_TOK_STYLE_MINUTES,
XML_TOK_STYLE_SECONDS,
XML_TOK_STYLE_BOOLEAN,
XML_TOK_STYLE_TEXT_CONTENT,
XML_TOK_STYLE_PROPERTIES,
XML_TOK_STYLE_MAP
};
enum SvXMLStyleAttrTokens
{
XML_TOK_STYLE_ATTR_NAME,
XML_TOK_STYLE_ATTR_LANGUAGE,
XML_TOK_STYLE_ATTR_COUNTRY,
XML_TOK_STYLE_ATTR_TITLE,
XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER,
XML_TOK_STYLE_ATTR_FORMAT_SOURCE,
XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW,
XML_TOK_STYLE_ATTR_VOLATILE,
XML_TOK_STYLE_ATTR_TRANSL_FORMAT,
XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE,
XML_TOK_STYLE_ATTR_TRANSL_COUNTRY,
XML_TOK_STYLE_ATTR_TRANSL_STYLE
};
enum SvXMLStyleElemAttrTokens
{
XML_TOK_ELEM_ATTR_DECIMAL_PLACES,
XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS,
XML_TOK_ELEM_ATTR_GROUPING,
XML_TOK_ELEM_ATTR_DISPLAY_FACTOR,
XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT,
XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS,
XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS,
XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS,
XML_TOK_ELEM_ATTR_LANGUAGE,
XML_TOK_ELEM_ATTR_COUNTRY,
XML_TOK_ELEM_ATTR_STYLE,
XML_TOK_ELEM_ATTR_TEXTUAL,
XML_TOK_ELEM_ATTR_CALENDAR
};
//-------------------------------------------------------------------------
//
// standard colors
//
#define XML_NUMF_COLORCOUNT 10
static ColorData aNumFmtStdColors[XML_NUMF_COLORCOUNT] =
{
COL_BLACK,
COL_LIGHTBLUE,
COL_LIGHTGREEN,
COL_LIGHTCYAN,
COL_LIGHTRED,
COL_LIGHTMAGENTA,
COL_BROWN,
COL_GRAY,
COL_YELLOW,
COL_WHITE
};
//
// token maps
//
// maps for SvXMLUnitConverter::convertEnum
static SvXMLEnumMapEntry aStyleValueMap[] =
{
{ XML_SHORT, sal_False },
{ XML_LONG, sal_True },
{ XML_TOKEN_INVALID, 0 }
};
static SvXMLEnumMapEntry aFormatSourceMap[] =
{
{ XML_FIXED, sal_False },
{ XML_LANGUAGE, sal_True },
{ XML_TOKEN_INVALID, 0 }
};
//-------------------------------------------------------------------------
struct SvXMLDefaultDateFormat
{
NfIndexTableOffset eFormat;
SvXMLDateElementAttributes eDOW;
SvXMLDateElementAttributes eDay;
SvXMLDateElementAttributes eMonth;
SvXMLDateElementAttributes eYear;
SvXMLDateElementAttributes eHours;
SvXMLDateElementAttributes eMins;
SvXMLDateElementAttributes eSecs;
sal_Bool bSystem;
};
static SvXMLDefaultDateFormat aDefaultDateFormats[] =
{
// format day-of-week day month year hours minutes seconds format-source
{ NF_DATE_SYSTEM_SHORT, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_True },
{ NF_DATE_SYSTEM_LONG, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_True },
{ NF_DATE_SYS_MMYY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False },
{ NF_DATE_SYS_DDMMM, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_TEXTSHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False },
{ NF_DATE_SYS_DDMMYYYY, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False },
{ NF_DATE_SYS_DDMMYY, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False },
{ NF_DATE_SYS_DMMMYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False },
{ NF_DATE_SYS_DMMMYYYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False },
{ NF_DATE_SYS_DMMMMYYYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False },
{ NF_DATE_SYS_NNDMMMYY, XML_DEA_SHORT, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False },
{ NF_DATE_SYS_NNDMMMMYYYY, XML_DEA_SHORT, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False },
{ NF_DATE_SYS_NNNNDMMMMYYYY, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False },
{ NF_DATETIME_SYSTEM_SHORT_HHMM, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, sal_True },
{ NF_DATETIME_SYS_DDMMYYYY_HHMMSS, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, sal_False }
};
//-------------------------------------------------------------------------
SV_IMPL_PTRARR( SvXMLNumFmtEntryArr, SvXMLNumFmtEntryPtr );
SV_IMPL_OP_PTRARR_SORT( SvXMLEmbeddedElementArr, SvXMLEmbeddedElementPtr );
//-------------------------------------------------------------------------
//
// SvXMLNumImpData
//
SvXMLNumImpData::SvXMLNumImpData(
SvNumberFormatter* pFmt,
const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory )
: pFormatter(pFmt),
pStylesElemTokenMap(NULL),
pStyleElemTokenMap(NULL),
pStyleAttrTokenMap(NULL),
pStyleElemAttrTokenMap(NULL),
pLocaleData(NULL),
mxServiceFactory(xServiceFactory)
{
DBG_ASSERT( mxServiceFactory.is(), "got no service manager" );
}
SvXMLNumImpData::~SvXMLNumImpData()
{
delete pStylesElemTokenMap;
delete pStyleElemTokenMap;
delete pStyleAttrTokenMap;
delete pStyleElemAttrTokenMap;
delete pLocaleData;
}
sal_uInt32 SvXMLNumImpData::GetKeyForName( const rtl::OUString& rName )
{
sal_uInt16 nCount = aNameEntries.Count();
for (sal_uInt16 i=0; i<nCount; i++)
{
const SvXMLNumFmtEntry* pObj = aNameEntries[i];
if ( pObj->aName == rName )
return pObj->nKey; // found
}
return NUMBERFORMAT_ENTRY_NOT_FOUND;
}
void SvXMLNumImpData::AddKey( sal_uInt32 nKey, const rtl::OUString& rName, sal_Bool bRemoveAfterUse )
{
if ( bRemoveAfterUse )
{
// if there is already an entry for this key without the bRemoveAfterUse flag,
// clear the flag for this entry, too
sal_uInt16 nCount = aNameEntries.Count();
for (sal_uInt16 i=0; i<nCount; i++)
{
SvXMLNumFmtEntry* pObj = aNameEntries[i];
if ( pObj->nKey == nKey && !pObj->bRemoveAfterUse )
{
bRemoveAfterUse = sal_False; // clear flag for new entry
break;
}
}
}
else
{
// call SetUsed to clear the bRemoveAfterUse flag for other entries for this key
SetUsed( nKey );
}
SvXMLNumFmtEntry* pObj = new SvXMLNumFmtEntry( rName, nKey, bRemoveAfterUse );
aNameEntries.Insert( pObj, aNameEntries.Count() );
}
void SvXMLNumImpData::SetUsed( sal_uInt32 nKey )
{
sal_uInt16 nCount = aNameEntries.Count();
for (sal_uInt16 i=0; i<nCount; i++)
{
SvXMLNumFmtEntry* pObj = aNameEntries[i];
if ( pObj->nKey == nKey )
{
pObj->bRemoveAfterUse = sal_False; // used -> don't remove
// continue searching - there may be several entries for the same key
// (with different names), the format must not be deleted if any one of
// them is used
}
}
}
void SvXMLNumImpData::RemoveVolatileFormats()
{
// remove temporary (volatile) formats from NumberFormatter
// called at the end of each import (styles and content), so volatile formats
// from styles can't be used in content
if ( !pFormatter )
return;
sal_uInt16 nCount = aNameEntries.Count();
for (sal_uInt16 i=0; i<nCount; i++)
{
const SvXMLNumFmtEntry* pObj = aNameEntries[i];
if ( pObj->bRemoveAfterUse )
{
const SvNumberformat* pFormat = pFormatter->GetEntry(pObj->nKey);
if (pFormat && (pFormat->GetType() & NUMBERFORMAT_DEFINED))
pFormatter->DeleteEntry( pObj->nKey );
}
}
}
const SvXMLTokenMap& SvXMLNumImpData::GetStylesElemTokenMap()
{
if( !pStylesElemTokenMap )
{
static SvXMLTokenMapEntry aStylesElemMap[] =
{
// style elements
{ XML_NAMESPACE_NUMBER, XML_NUMBER_STYLE, XML_TOK_STYLES_NUMBER_STYLE },
{ XML_NAMESPACE_NUMBER, XML_CURRENCY_STYLE, XML_TOK_STYLES_CURRENCY_STYLE },
{ XML_NAMESPACE_NUMBER, XML_PERCENTAGE_STYLE, XML_TOK_STYLES_PERCENTAGE_STYLE },
{ XML_NAMESPACE_NUMBER, XML_DATE_STYLE, XML_TOK_STYLES_DATE_STYLE },
{ XML_NAMESPACE_NUMBER, XML_TIME_STYLE, XML_TOK_STYLES_TIME_STYLE },
{ XML_NAMESPACE_NUMBER, XML_BOOLEAN_STYLE, XML_TOK_STYLES_BOOLEAN_STYLE },
{ XML_NAMESPACE_NUMBER, XML_TEXT_STYLE, XML_TOK_STYLES_TEXT_STYLE },
XML_TOKEN_MAP_END
};
pStylesElemTokenMap = new SvXMLTokenMap( aStylesElemMap );
}
return *pStylesElemTokenMap;
}
const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemTokenMap()
{
if( !pStyleElemTokenMap )
{
static SvXMLTokenMapEntry aStyleElemMap[] =
{
// elements in a style
{ XML_NAMESPACE_NUMBER, XML_TEXT, XML_TOK_STYLE_TEXT },
{ XML_NAMESPACE_NUMBER, XML_NUMBER, XML_TOK_STYLE_NUMBER },
{ XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER, XML_TOK_STYLE_SCIENTIFIC_NUMBER },
{ XML_NAMESPACE_NUMBER, XML_FRACTION, XML_TOK_STYLE_FRACTION },
{ XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL, XML_TOK_STYLE_CURRENCY_SYMBOL },
{ XML_NAMESPACE_NUMBER, XML_DAY, XML_TOK_STYLE_DAY },
{ XML_NAMESPACE_NUMBER, XML_MONTH, XML_TOK_STYLE_MONTH },
{ XML_NAMESPACE_NUMBER, XML_YEAR, XML_TOK_STYLE_YEAR },
{ XML_NAMESPACE_NUMBER, XML_ERA, XML_TOK_STYLE_ERA },
{ XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK, XML_TOK_STYLE_DAY_OF_WEEK },
{ XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR, XML_TOK_STYLE_WEEK_OF_YEAR },
{ XML_NAMESPACE_NUMBER, XML_QUARTER, XML_TOK_STYLE_QUARTER },
{ XML_NAMESPACE_NUMBER, XML_HOURS, XML_TOK_STYLE_HOURS },
{ XML_NAMESPACE_NUMBER, XML_AM_PM, XML_TOK_STYLE_AM_PM },
{ XML_NAMESPACE_NUMBER, XML_MINUTES, XML_TOK_STYLE_MINUTES },
{ XML_NAMESPACE_NUMBER, XML_SECONDS, XML_TOK_STYLE_SECONDS },
{ XML_NAMESPACE_NUMBER, XML_BOOLEAN, XML_TOK_STYLE_BOOLEAN },
{ XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT, XML_TOK_STYLE_TEXT_CONTENT },
{ XML_NAMESPACE_STYLE, XML_TEXT_PROPERTIES, XML_TOK_STYLE_PROPERTIES },
{ XML_NAMESPACE_STYLE, XML_MAP, XML_TOK_STYLE_MAP },
XML_TOKEN_MAP_END
};
pStyleElemTokenMap = new SvXMLTokenMap( aStyleElemMap );
}
return *pStyleElemTokenMap;
}
const SvXMLTokenMap& SvXMLNumImpData::GetStyleAttrTokenMap()
{
if( !pStyleAttrTokenMap )
{
static SvXMLTokenMapEntry aStyleAttrMap[] =
{
// attributes for a style
{ XML_NAMESPACE_STYLE, XML_NAME, XML_TOK_STYLE_ATTR_NAME },
{ XML_NAMESPACE_NUMBER, XML_LANGUAGE, XML_TOK_STYLE_ATTR_LANGUAGE },
{ XML_NAMESPACE_NUMBER, XML_COUNTRY, XML_TOK_STYLE_ATTR_COUNTRY },
{ XML_NAMESPACE_NUMBER, XML_TITLE, XML_TOK_STYLE_ATTR_TITLE },
{ XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER, XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER },
{ XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE, XML_TOK_STYLE_ATTR_FORMAT_SOURCE },
{ XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW, XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW },
{ XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TOK_STYLE_ATTR_VOLATILE },
{ XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT, XML_TOK_STYLE_ATTR_TRANSL_FORMAT },
{ XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE, XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE },
{ XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY, XML_TOK_STYLE_ATTR_TRANSL_COUNTRY },
{ XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE, XML_TOK_STYLE_ATTR_TRANSL_STYLE },
XML_TOKEN_MAP_END
};
pStyleAttrTokenMap = new SvXMLTokenMap( aStyleAttrMap );
}
return *pStyleAttrTokenMap;
}
const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemAttrTokenMap()
{
if( !pStyleElemAttrTokenMap )
{
static SvXMLTokenMapEntry aStyleElemAttrMap[] =
{
// attributes for an element within a style
{ XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, XML_TOK_ELEM_ATTR_DECIMAL_PLACES },
{ XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS },
{ XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TOK_ELEM_ATTR_GROUPING },
{ XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, XML_TOK_ELEM_ATTR_DISPLAY_FACTOR },
{ XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT, XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT },
{ XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS, XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS },
{ XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS },
{ XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS },
{ XML_NAMESPACE_NUMBER, XML_LANGUAGE, XML_TOK_ELEM_ATTR_LANGUAGE },
{ XML_NAMESPACE_NUMBER, XML_COUNTRY, XML_TOK_ELEM_ATTR_COUNTRY },
{ XML_NAMESPACE_NUMBER, XML_STYLE, XML_TOK_ELEM_ATTR_STYLE },
{ XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TOK_ELEM_ATTR_TEXTUAL },
{ XML_NAMESPACE_NUMBER, XML_CALENDAR, XML_TOK_ELEM_ATTR_CALENDAR },
XML_TOKEN_MAP_END
};
pStyleElemAttrTokenMap = new SvXMLTokenMap( aStyleElemAttrMap );
}
return *pStyleElemAttrTokenMap;
}
const LocaleDataWrapper& SvXMLNumImpData::GetLocaleData( LanguageType nLang )
{
if ( !pLocaleData )
pLocaleData = new LocaleDataWrapper(
(pFormatter ? pFormatter->GetServiceManager() :
mxServiceFactory),
MsLangId::convertLanguageToLocale( nLang ) );
else
pLocaleData->setLocale( MsLangId::convertLanguageToLocale( nLang ) );
return *pLocaleData;
}
//-------------------------------------------------------------------------
//
// SvXMLNumFmtMapContext
//
SvXMLNumFmtMapContext::SvXMLNumFmtMapContext( SvXMLImport& rImport,
sal_uInt16 nPrfx, const rtl::OUString& rLName,
SvXMLNumFormatContext& rParentContext,
const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
SvXMLImportContext( rImport, nPrfx, rLName ),
rParent( rParentContext )
{
sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
for( sal_Int16 i=0; i < nAttrCount; i++ )
{
OUString sAttrName = xAttrList->getNameByIndex( i );
OUString sValue = xAttrList->getValueByIndex( i );
OUString aLocalName;
sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
if ( nPrefix == XML_NAMESPACE_STYLE )
{
if ( IsXMLToken( aLocalName, XML_CONDITION) )
sCondition = sValue;
else if ( IsXMLToken( aLocalName, XML_APPLY_STYLE_NAME) )
sName = sValue;
}
}
}
SvXMLNumFmtMapContext::~SvXMLNumFmtMapContext()
{
}
SvXMLImportContext* SvXMLNumFmtMapContext::CreateChildContext(
sal_uInt16 nPrfx, const rtl::OUString& rLName,
const uno::Reference<xml::sax::XAttributeList>& )
{
// no elements supported - use default context
return new SvXMLImportContext( GetImport(), nPrfx, rLName );
}
void SvXMLNumFmtMapContext::Characters( const rtl::OUString& )
{
}
void SvXMLNumFmtMapContext::EndElement()
{
rParent.AddCondition( sCondition, sName );
}
//-------------------------------------------------------------------------
//
// SvXMLNumFmtPropContext
//
SvXMLNumFmtPropContext::SvXMLNumFmtPropContext( SvXMLImport& rImport,
sal_uInt16 nPrfx, const rtl::OUString& rLName,
SvXMLNumFormatContext& rParentContext,
const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
SvXMLImportContext( rImport, nPrfx, rLName ),
rParent( rParentContext ),
bColSet( sal_False )
{
sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
for( sal_Int16 i=0; i < nAttrCount; i++ )
{
OUString sAttrName = xAttrList->getNameByIndex( i );
OUString sValue = xAttrList->getValueByIndex( i );
OUString aLocalName;
sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
if ( nPrefix == XML_NAMESPACE_FO && IsXMLToken( aLocalName, XML_COLOR ) )
{
bColSet = ::sax::Converter::convertColor( m_nColor, sValue );
}
}
}
SvXMLNumFmtPropContext::~SvXMLNumFmtPropContext()
{
}
SvXMLImportContext* SvXMLNumFmtPropContext::CreateChildContext(
sal_uInt16 nPrfx, const rtl::OUString& rLName,
const uno::Reference<xml::sax::XAttributeList>& )
{
// no elements supported - use default context
return new SvXMLImportContext( GetImport(), nPrfx, rLName );
}
void SvXMLNumFmtPropContext::Characters( const rtl::OUString& )
{
}
void SvXMLNumFmtPropContext::EndElement()
{
if (bColSet)
rParent.AddColor( m_nColor );
}
//-------------------------------------------------------------------------
//
// SvXMLNumFmtEmbeddedTextContext
//
SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport,
sal_uInt16 nPrfx, const rtl::OUString& rLName,
SvXMLNumFmtElementContext& rParentContext,
const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
SvXMLImportContext( rImport, nPrfx, rLName ),
rParent( rParentContext ),
nTextPosition( 0 )
{
sal_Int32 nAttrVal;
sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
for( sal_Int16 i=0; i < nAttrCount; i++ )
{
OUString sAttrName = xAttrList->getNameByIndex( i );
OUString sValue = xAttrList->getValueByIndex( i );
OUString aLocalName;
sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
if ( nPrefix == XML_NAMESPACE_NUMBER && IsXMLToken( aLocalName, XML_POSITION ) )
{
if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
nTextPosition = nAttrVal;
}
}
}
SvXMLNumFmtEmbeddedTextContext::~SvXMLNumFmtEmbeddedTextContext()
{
}
SvXMLImportContext* SvXMLNumFmtEmbeddedTextContext::CreateChildContext(
sal_uInt16 nPrfx, const rtl::OUString& rLName,
const uno::Reference<xml::sax::XAttributeList>& )
{
// no elements supported - use default context
return new SvXMLImportContext( GetImport(), nPrfx, rLName );
}
void SvXMLNumFmtEmbeddedTextContext::Characters( const rtl::OUString& rChars )
{
aContent.append( rChars );
}
void SvXMLNumFmtEmbeddedTextContext::EndElement()
{
rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear() );
}
//-------------------------------------------------------------------------
sal_Bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rParent )
{
sal_uInt16 nFormatType = rParent.GetType();
// Treat space equal to non-breaking space separator.
const sal_Unicode cNBSP = 0x00A0;
sal_Unicode cTS;
if ( ( nFormatType == XML_TOK_STYLES_NUMBER_STYLE ||
nFormatType == XML_TOK_STYLES_CURRENCY_STYLE ||
nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE ) &&
(cChar == (cTS = rParent.GetLocaleData().getNumThousandSep().GetChar(0)) ||
(cChar == ' ' && cTS == cNBSP)) )
{
// #i22394# Extra occurrences of thousands separator must be quoted, so they
// aren't mis-interpreted as display-factor.
// This must be limited to the format types that can contain a number element,
// because the same character can be a date separator that should not be quoted
// in date formats.
return sal_False; // force quotes
}
// see ImpSvNumberformatScan::Next_Symbol
if ( cChar == ' ' ||
cChar == '-' ||
cChar == '/' ||
cChar == '.' ||
cChar == ',' ||
cChar == ':' ||
cChar == '\'' )
return sal_True; // for all format types
// percent sign must be used without quotes for percentage styles only
if ( nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE && cChar == '%' )
return sal_True;
// don't put quotes around single parentheses (often used for negative numbers)
if ( ( nFormatType == XML_TOK_STYLES_NUMBER_STYLE ||
nFormatType == XML_TOK_STYLES_CURRENCY_STYLE ||
nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE ) &&
( cChar == '(' || cChar == ')' ) )
return sal_True;
return sal_False;
}
void lcl_EnquoteIfNecessary( rtl::OUStringBuffer& rContent, const SvXMLNumFormatContext& rParent )
{
sal_Bool bQuote = sal_True;
sal_Int32 nLength = rContent.getLength();
if ( ( nLength == 1 &&
lcl_ValidChar( rContent.charAt(0), rParent ) ) ||
( nLength == 2 &&
lcl_ValidChar( rContent.charAt(0), rParent ) &&
rContent.charAt(1) == ' ' ) )
{
// don't quote single separator characters like space or percent,
// or separator characters followed by space (used in date formats)
bQuote = sal_False;
}
else if ( rParent.GetType() == XML_TOK_STYLES_PERCENTAGE_STYLE && nLength > 1 )
{
// the percent character in percentage styles must be left out of quoting
// (one occurrence is enough even if there are several percent characters in the string)
rtl::OUString aString( rContent.getStr() );
sal_Int32 nPos = aString.indexOf( (sal_Unicode) '%' );
if ( nPos >= 0 )
{
if ( nPos + 1 < nLength )
{
if ( nPos + 2 == nLength && lcl_ValidChar( rContent.charAt(nPos + 1), rParent ) )
{
// single character that doesn't need quoting
}
else
{
// quote text behind percent character
rContent.insert( nPos + 1, (sal_Unicode) '"' );
rContent.append( (sal_Unicode) '"' );
}
}
if ( nPos > 0 )
{
if ( nPos == 1 && lcl_ValidChar( rContent.charAt(0), rParent ) )
{
// single character that doesn't need quoting
}
else
{
// quote text before percent character
rContent.insert( nPos, (sal_Unicode) '"' );
rContent.insert( 0, (sal_Unicode) '"' );
}
}
bQuote = sal_False;
}
// else: normal quoting (below)
}
if ( bQuote )
{
// #i55469# quotes in the string itself have to be escaped
rtl::OUString aString( rContent.getStr() );
bool bEscape = ( aString.indexOf( (sal_Unicode) '"' ) >= 0 );
if ( bEscape )
{
// A quote is turned into "\"" - a quote to end quoted text, an escaped quote,
// and a quote to resume quoting.
rtl::OUString aInsert( RTL_CONSTASCII_USTRINGPARAM( "\"\\\"" ) );
sal_Int32 nPos = 0;
while ( nPos < rContent.getLength() )
{
if ( rContent.charAt( nPos ) == (sal_Unicode) '"' )
{
rContent.insert( nPos, aInsert );
nPos += aInsert.getLength();
}
++nPos;
}
}
// quote string literals
rContent.insert( 0, (sal_Unicode) '"' );
rContent.append( (sal_Unicode) '"' );
// remove redundant double quotes at start or end
if ( bEscape )
{
if ( rContent.getLength() > 2 &&
rContent.charAt(0) == (sal_Unicode) '"' &&
rContent.charAt(1) == (sal_Unicode) '"' )
{
String aTrimmed( rContent.makeStringAndClear().copy(2) );
rContent = rtl::OUStringBuffer( aTrimmed );
}
sal_Int32 nLen = rContent.getLength();
if ( nLen > 2 &&
rContent.charAt(nLen-1) == (sal_Unicode) '"' &&
rContent.charAt(nLen-2) == (sal_Unicode) '"' )
{
String aTrimmed( rContent.makeStringAndClear().copy( 0, nLen - 2 ) );
rContent = rtl::OUStringBuffer( aTrimmed );
}
}
}
}
//
// SvXMLNumFmtElementContext
//
SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport,
sal_uInt16 nPrfx, const rtl::OUString& rLName,
SvXMLNumFormatContext& rParentContext, sal_uInt16 nNewType,
const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
SvXMLImportContext( rImport, nPrfx, rLName ),
rParent( rParentContext ),
nType( nNewType ),
nElementLang( LANGUAGE_SYSTEM ),
bLong( sal_False ),
bTextual( sal_False )
{
OUString sLanguage, sCountry;
sal_Int32 nAttrVal;
bool bAttrBool(false);
sal_uInt16 nAttrEnum;
double fAttrDouble;
sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
for( sal_Int16 i=0; i < nAttrCount; i++ )
{
OUString sAttrName = xAttrList->getNameByIndex( i );
OUString sValue = xAttrList->getValueByIndex( i );
OUString aLocalName;
sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
const SvXMLTokenMap& rTokenMap = rParent.GetData()->GetStyleElemAttrTokenMap();
sal_uInt16 nToken = rTokenMap.Get( nPrefix, aLocalName );
switch (nToken)
{
case XML_TOK_ELEM_ATTR_DECIMAL_PLACES:
if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
aNumInfo.nDecimals = nAttrVal;
break;
case XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS:
if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
aNumInfo.nInteger = nAttrVal;
break;
case XML_TOK_ELEM_ATTR_GROUPING:
if (::sax::Converter::convertBool( bAttrBool, sValue ))
aNumInfo.bGrouping = bAttrBool;
break;
case XML_TOK_ELEM_ATTR_DISPLAY_FACTOR:
if (::sax::Converter::convertDouble( fAttrDouble, sValue ))
aNumInfo.fDisplayFactor = fAttrDouble;
break;
case XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT:
if ( sValue.getLength() > 0 )
aNumInfo.bDecReplace = sal_True; // only a default string is supported
else
aNumInfo.bVarDecimals = sal_True; // empty replacement string: variable decimals
break;
case XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS:
if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
aNumInfo.nExpDigits = nAttrVal;
break;
case XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS:
if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
aNumInfo.nNumerDigits = nAttrVal;
break;
case XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS:
if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
aNumInfo.nDenomDigits = nAttrVal;
break;
case XML_TOK_ELEM_ATTR_LANGUAGE:
sLanguage = sValue;
break;
case XML_TOK_ELEM_ATTR_COUNTRY:
sCountry = sValue;
break;
case XML_TOK_ELEM_ATTR_STYLE:
if ( SvXMLUnitConverter::convertEnum( nAttrEnum, sValue, aStyleValueMap ) )
bLong = (sal_Bool) nAttrEnum;
break;
case XML_TOK_ELEM_ATTR_TEXTUAL:
if (::sax::Converter::convertBool( bAttrBool, sValue ))
bTextual = bAttrBool;
break;
case XML_TOK_ELEM_ATTR_CALENDAR:
sCalendar = sValue;
break;
}
}
if ( sLanguage.getLength() || sCountry.getLength() )
{
nElementLang = MsLangId::convertIsoNamesToLanguage( sLanguage, sCountry );
if ( nElementLang == LANGUAGE_DONTKNOW )
nElementLang = LANGUAGE_SYSTEM; //! error handling for invalid locales?
}
}
SvXMLNumFmtElementContext::~SvXMLNumFmtElementContext()
{
}
SvXMLImportContext* SvXMLNumFmtElementContext::CreateChildContext(
sal_uInt16 nPrfx, const rtl::OUString& rLName,
const uno::Reference<xml::sax::XAttributeList>& xAttrList )
{
// only number:number supports number:embedded-text child element
if ( nType == XML_TOK_STYLE_NUMBER &&
nPrfx == XML_NAMESPACE_NUMBER && IsXMLToken( rLName, XML_EMBEDDED_TEXT ) )
{
return new SvXMLNumFmtEmbeddedTextContext( GetImport(), nPrfx, rLName, *this, xAttrList );
}
else
return new SvXMLImportContext( GetImport(), nPrfx, rLName );
}
void SvXMLNumFmtElementContext::Characters( const rtl::OUString& rChars )
{
aContent.append( rChars );
}
void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, const rtl::OUString& rContent )
{
if ( rContent.getLength() )
{
SvXMLEmbeddedElement* pObj = new SvXMLEmbeddedElement( nFormatPos, rContent );
if ( !aNumInfo.aEmbeddedElements.Insert( pObj ) )
{
// there's already an element at this position - append text to existing element
delete pObj;
sal_uInt16 nElementCount = aNumInfo.aEmbeddedElements.Count();
for (sal_uInt16 i=0; i<nElementCount; i++)
{
pObj = aNumInfo.aEmbeddedElements[i];
if ( pObj->nFormatPos == nFormatPos )
{
pObj->aText += rContent;
break;
}
}
}
}
}
void SvXMLNumFmtElementContext::EndElement()
{
sal_Bool bEffLong = bLong;
switch (nType)
{
case XML_TOK_STYLE_TEXT:
if ( rParent.HasLongDoW() &&
rParent.GetLocaleData().getLongDateDayOfWeekSep() ==
String( aContent.getStr() ) )
{
// skip separator constant after long day of week
// (NF_KEY_NNNN contains the separator)
if ( rParent.ReplaceNfKeyword( NF_KEY_NNN, NF_KEY_NNNN ) )
{
aContent = OUStringBuffer();
}
rParent.SetHasLongDoW( sal_False ); // only once
}
if ( aContent.getLength() )
{
lcl_EnquoteIfNecessary( aContent, rParent );
rParent.AddToCode( aContent.makeStringAndClear() );
}
break;
case XML_TOK_STYLE_NUMBER:
rParent.AddNumber( aNumInfo );
break;
case XML_TOK_STYLE_CURRENCY_SYMBOL:
rParent.AddCurrency( aContent.makeStringAndClear(), nElementLang );
break;
case XML_TOK_STYLE_TEXT_CONTENT:
rParent.AddToCode( OUString::valueOf((sal_Unicode)'@') );
break;
case XML_TOK_STYLE_BOOLEAN:
// ignored - only default boolean format is supported
break;
case XML_TOK_STYLE_DAY:
rParent.UpdateCalendar( sCalendar );
//! I18N doesn't provide SYSTEM or extended date information yet
rParent.AddNfKeyword(
sal::static_int_cast< sal_uInt16 >(
bEffLong ? NF_KEY_DD : NF_KEY_D ) );
break;
case XML_TOK_STYLE_MONTH:
rParent.UpdateCalendar( sCalendar );
//! I18N doesn't provide SYSTEM or extended date information yet
rParent.AddNfKeyword(
sal::static_int_cast< sal_uInt16 >(
bTextual
? ( bEffLong ? NF_KEY_MMMM : NF_KEY_MMM )
: ( bEffLong ? NF_KEY_MM : NF_KEY_M ) ) );
break;
case XML_TOK_STYLE_YEAR:
rParent.UpdateCalendar( sCalendar );
//! I18N doesn't provide SYSTEM or extended date information yet
// Y after G (era) is replaced by E
if ( rParent.HasEra() )
rParent.AddNfKeyword(
sal::static_int_cast< sal_uInt16 >(
bEffLong ? NF_KEY_EEC : NF_KEY_EC ) );
else
rParent.AddNfKeyword(
sal::static_int_cast< sal_uInt16 >(
bEffLong ? NF_KEY_YYYY : NF_KEY_YY ) );
break;
case XML_TOK_STYLE_ERA:
rParent.UpdateCalendar( sCalendar );
//! I18N doesn't provide SYSTEM or extended date information yet
rParent.AddNfKeyword(
sal::static_int_cast< sal_uInt16 >(
bEffLong ? NF_KEY_GGG : NF_KEY_G ) );
// HasEra flag is set
break;
case XML_TOK_STYLE_DAY_OF_WEEK:
rParent.UpdateCalendar( sCalendar );
//! I18N doesn't provide SYSTEM or extended date information yet
rParent.AddNfKeyword(
sal::static_int_cast< sal_uInt16 >(
bEffLong ? NF_KEY_NNNN : NF_KEY_NN ) );
break;
case XML_TOK_STYLE_WEEK_OF_YEAR:
rParent.UpdateCalendar( sCalendar );
rParent.AddNfKeyword( NF_KEY_WW );
break;
case XML_TOK_STYLE_QUARTER:
rParent.UpdateCalendar( sCalendar );
rParent.AddNfKeyword(
sal::static_int_cast< sal_uInt16 >(
bEffLong ? NF_KEY_QQ : NF_KEY_Q ) );
break;
case XML_TOK_STYLE_HOURS:
rParent.AddNfKeyword(
sal::static_int_cast< sal_uInt16 >(
bEffLong ? NF_KEY_HH : NF_KEY_H ) );
break;
case XML_TOK_STYLE_AM_PM:
//! short/long?
rParent.AddNfKeyword( NF_KEY_AMPM );
break;
case XML_TOK_STYLE_MINUTES:
rParent.AddNfKeyword(
sal::static_int_cast< sal_uInt16 >(
bEffLong ? NF_KEY_MMI : NF_KEY_MI ) );
break;
case XML_TOK_STYLE_SECONDS:
rParent.AddNfKeyword(
sal::static_int_cast< sal_uInt16 >(
bEffLong ? NF_KEY_SS : NF_KEY_S ) );
if ( aNumInfo.nDecimals > 0 )
{
// manually add the decimal places
const String& rSep = rParent.GetLocaleData().getNumDecimalSep();
for ( xub_StrLen j=0; j<rSep.Len(); j++ )
{
rParent.AddToCode( OUString::valueOf( rSep.GetChar(j) ) );
}
for (sal_Int32 i=0; i<aNumInfo.nDecimals; i++)
rParent.AddToCode( OUString::valueOf((sal_Unicode)'0') );
}
break;
case XML_TOK_STYLE_FRACTION:
{
if ( aNumInfo.nInteger >= 0 )
{
// add integer part only if min-integer-digits attribute is there
aNumInfo.nDecimals = 0;
rParent.AddNumber( aNumInfo ); // number without decimals
rParent.AddToCode( OUString::valueOf((sal_Unicode)' ') );
}
//! build string and add at once
sal_Int32 i;
for (i=0; i<aNumInfo.nNumerDigits; i++)
rParent.AddToCode( OUString::valueOf((sal_Unicode)'?') );
rParent.AddToCode( OUString::valueOf((sal_Unicode)'/') );
for (i=0; i<aNumInfo.nDenomDigits; i++)
rParent.AddToCode( OUString::valueOf((sal_Unicode)'?') );
}
break;
case XML_TOK_STYLE_SCIENTIFIC_NUMBER:
{
rParent.AddNumber( aNumInfo ); // simple number
rParent.AddToCode( OUString(RTL_CONSTASCII_USTRINGPARAM("E+")) );
for (sal_Int32 i=0; i<aNumInfo.nExpDigits; i++)
rParent.AddToCode( OUString::valueOf((sal_Unicode)'0') );
}
break;
default:
OSL_FAIL("invalid element ID");
}
}
//-------------------------------------------------------------------------
sal_uInt16 SvXMLNumFmtDefaults::GetDefaultDateFormat( SvXMLDateElementAttributes eDOW,
SvXMLDateElementAttributes eDay, SvXMLDateElementAttributes eMonth,
SvXMLDateElementAttributes eYear, SvXMLDateElementAttributes eHours,
SvXMLDateElementAttributes eMins, SvXMLDateElementAttributes eSecs,
sal_Bool bSystem )
{
const sal_uInt16 nCount = sizeof(aDefaultDateFormats) / sizeof(SvXMLDefaultDateFormat);
for (sal_uInt16 nPos=0; nPos<nCount; nPos++)
{
const SvXMLDefaultDateFormat& rEntry = aDefaultDateFormats[nPos];
if ( bSystem == rEntry.bSystem &&
( eDOW == rEntry.eDOW || ( rEntry.eDOW == XML_DEA_ANY && eDOW != XML_DEA_NONE ) ) &&
( eDay == rEntry.eDay || ( rEntry.eDay == XML_DEA_ANY && eDay != XML_DEA_NONE ) ) &&
( eMonth == rEntry.eMonth || ( rEntry.eMonth == XML_DEA_ANY && eMonth != XML_DEA_NONE ) ) &&
( eYear == rEntry.eYear || ( rEntry.eYear == XML_DEA_ANY && eYear != XML_DEA_NONE ) ) &&
( eHours == rEntry.eHours || ( rEntry.eHours == XML_DEA_ANY && eHours != XML_DEA_NONE ) ) &&
( eMins == rEntry.eMins || ( rEntry.eMins == XML_DEA_ANY && eMins != XML_DEA_NONE ) ) &&
( eSecs == rEntry.eSecs || ( rEntry.eSecs == XML_DEA_ANY && eSecs != XML_DEA_NONE ) ) )
{
return sal::static_int_cast< sal_uInt16 >(rEntry.eFormat);
}
}
return NF_INDEX_TABLE_ENTRIES; // invalid
}
//-------------------------------------------------------------------------
//
// SvXMLNumFormatContext
//
SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport,
sal_uInt16 nPrfx, const rtl::OUString& rLName,
SvXMLNumImpData* pNewData, sal_uInt16 nNewType,
const uno::Reference<xml::sax::XAttributeList>& xAttrList,
SvXMLStylesContext& rStyles ) :
SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList ),
pData( pNewData ),
pStyles( &rStyles ),
aMyConditions(),
nType( nNewType ),
nKey(-1),
nFormatLang( LANGUAGE_SYSTEM ),
bAutoOrder( sal_False ),
bFromSystem( sal_False ),
bTruncate( sal_True ),
bAutoDec( sal_False ),
bAutoInt( sal_False ),
bHasExtraText( sal_False ),
bHasLongDoW( sal_False ),
bHasEra( sal_False ),
bHasDateTime( sal_False ),
bRemoveAfterUse( sal_False ),
eDateDOW( XML_DEA_NONE ),
eDateDay( XML_DEA_NONE ),
eDateMonth( XML_DEA_NONE ),
eDateYear( XML_DEA_NONE ),
eDateHours( XML_DEA_NONE ),
eDateMins( XML_DEA_NONE ),
eDateSecs( XML_DEA_NONE ),
bDateNoDefault( sal_False )
{
OUString sLanguage, sCountry;
::com::sun::star::i18n::NativeNumberXmlAttributes aNatNumAttr;
bool bAttrBool(false);
sal_uInt16 nAttrEnum;
sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
for( sal_Int16 i=0; i < nAttrCount; i++ )
{
OUString sAttrName = xAttrList->getNameByIndex( i );
OUString sValue = xAttrList->getValueByIndex( i );
OUString aLocalName;
sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
const SvXMLTokenMap& rTokenMap = pData->GetStyleAttrTokenMap();
sal_uInt16 nToken = rTokenMap.Get( nPrefix, aLocalName );
switch (nToken)
{
case XML_TOK_STYLE_ATTR_NAME:
break;
case XML_TOK_STYLE_ATTR_LANGUAGE:
sLanguage = sValue;
break;
case XML_TOK_STYLE_ATTR_COUNTRY:
sCountry = sValue;
break;
case XML_TOK_STYLE_ATTR_TITLE:
sFormatTitle = sValue;
break;
case XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER:
if (::sax::Converter::convertBool( bAttrBool, sValue ))
bAutoOrder = bAttrBool;
break;
case XML_TOK_STYLE_ATTR_FORMAT_SOURCE:
if ( SvXMLUnitConverter::convertEnum( nAttrEnum, sValue, aFormatSourceMap ) )
bFromSystem = (sal_Bool) nAttrEnum;
break;
case XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW:
if (::sax::Converter::convertBool( bAttrBool, sValue ))
bTruncate = bAttrBool;
break;
case XML_TOK_STYLE_ATTR_VOLATILE:
// volatile formats can be removed after importing
// if not used in other styles
if (::sax::Converter::convertBool( bAttrBool, sValue ))
bRemoveAfterUse = bAttrBool;
break;
case XML_TOK_STYLE_ATTR_TRANSL_FORMAT:
aNatNumAttr.Format = sValue;
break;
case XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE:
aNatNumAttr.Locale.Language = sValue;
break;
case XML_TOK_STYLE_ATTR_TRANSL_COUNTRY:
aNatNumAttr.Locale.Country = sValue;
break;
case XML_TOK_STYLE_ATTR_TRANSL_STYLE:
aNatNumAttr.Style = sValue;
break;
}
}
if ( sLanguage.getLength() || sCountry.getLength() )
{
nFormatLang = MsLangId::convertIsoNamesToLanguage( sLanguage, sCountry );
if ( nFormatLang == LANGUAGE_DONTKNOW )
nFormatLang = LANGUAGE_SYSTEM; //! error handling for invalid locales?
}
if ( aNatNumAttr.Format.getLength() )
{
SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
if ( pFormatter )
{
sal_Int32 nNatNum = pFormatter->GetNatNum()->convertFromXmlAttributes( aNatNumAttr );
aFormatCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "[NatNum" ) );
aFormatCode.append( nNatNum, 10 );
LanguageType eLang = MsLangId::convertLocaleToLanguage( aNatNumAttr.Locale );
if ( eLang == LANGUAGE_DONTKNOW )
eLang = LANGUAGE_SYSTEM; //! error handling for invalid locales?
if ( eLang != nFormatLang && eLang != LANGUAGE_SYSTEM )
{
aFormatCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "][$-" ) );
// language code in upper hex:
aFormatCode.append( String::CreateFromInt32( sal_Int32( eLang ), 16 ).ToUpperAscii() );
}
aFormatCode.append( sal_Unicode(']') );
}
}
}
SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport,
sal_uInt16 nPrfx, const rtl::OUString& rLName,
const uno::Reference<xml::sax::XAttributeList>& xAttrList,
const sal_Int32 nTempKey,
SvXMLStylesContext& rStyles ) :
SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList, XML_STYLE_FAMILY_DATA_STYLE ),
pData( NULL ),
pStyles( &rStyles ),
aMyConditions(),
nType( 0 ),
nKey(nTempKey),
nFormatLang( LANGUAGE_SYSTEM ),
bAutoOrder( sal_False ),
bFromSystem( sal_False ),
bTruncate( sal_True ),
bAutoDec( sal_False ),
bAutoInt( sal_False ),
bHasExtraText( sal_False ),
bHasLongDoW( sal_False ),
bHasEra( sal_False ),
bHasDateTime( sal_False ),
bRemoveAfterUse( sal_False ),
eDateDOW( XML_DEA_NONE ),
eDateDay( XML_DEA_NONE ),
eDateMonth( XML_DEA_NONE ),
eDateYear( XML_DEA_NONE ),
eDateHours( XML_DEA_NONE ),
eDateMins( XML_DEA_NONE ),
eDateSecs( XML_DEA_NONE ),
bDateNoDefault( sal_False )
{
SetAttribute(XML_NAMESPACE_STYLE, GetXMLToken(XML_NAME), rLName);
}
SvXMLNumFormatContext::~SvXMLNumFormatContext()
{
}
SvXMLImportContext* SvXMLNumFormatContext::CreateChildContext(
sal_uInt16 nPrfx, const rtl::OUString& rLName,
const uno::Reference<xml::sax::XAttributeList>& xAttrList )
{
SvXMLImportContext* pContext = NULL;
const SvXMLTokenMap& rTokenMap = pData->GetStyleElemTokenMap();
sal_uInt16 nToken = rTokenMap.Get( nPrfx, rLName );
switch (nToken)
{
case XML_TOK_STYLE_TEXT:
case XML_TOK_STYLE_NUMBER:
case XML_TOK_STYLE_SCIENTIFIC_NUMBER:
case XML_TOK_STYLE_FRACTION:
case XML_TOK_STYLE_CURRENCY_SYMBOL:
case XML_TOK_STYLE_DAY:
case XML_TOK_STYLE_MONTH:
case XML_TOK_STYLE_YEAR:
case XML_TOK_STYLE_ERA:
case XML_TOK_STYLE_DAY_OF_WEEK:
case XML_TOK_STYLE_WEEK_OF_YEAR:
case XML_TOK_STYLE_QUARTER:
case XML_TOK_STYLE_HOURS:
case XML_TOK_STYLE_AM_PM:
case XML_TOK_STYLE_MINUTES:
case XML_TOK_STYLE_SECONDS:
case XML_TOK_STYLE_BOOLEAN:
case XML_TOK_STYLE_TEXT_CONTENT:
pContext = new SvXMLNumFmtElementContext( GetImport(), nPrfx, rLName,
*this, nToken, xAttrList );
break;
case XML_TOK_STYLE_PROPERTIES:
pContext = new SvXMLNumFmtPropContext( GetImport(), nPrfx, rLName,
*this, xAttrList );
break;
case XML_TOK_STYLE_MAP:
{
// SvXMLNumFmtMapContext::EndElement adds to aMyConditions,
// so there's no need for an extra flag
pContext = new SvXMLNumFmtMapContext( GetImport(), nPrfx, rLName,
*this, xAttrList );
}
break;
}
if( !pContext )
pContext = new SvXMLImportContext( GetImport(), nPrfx, rLName );
return pContext;
}
sal_Int32 SvXMLNumFormatContext::GetKey()
{
if (nKey > -1)
{
if (bRemoveAfterUse)
{
// format is used -> don't remove
bRemoveAfterUse = sal_False;
if (pData)
pData->SetUsed(nKey);
// Add to import's list of keys now - CreateAndInsert didn't add
// the style if bRemoveAfterUse was set.
GetImport().AddNumberStyle( nKey, GetName() );
}
return nKey;
}
else
{
// reset bRemoveAfterUse before CreateAndInsert, so AddKey is called without bRemoveAfterUse set
bRemoveAfterUse = sal_False;
CreateAndInsert(sal_True);
return nKey;
}
}
sal_Int32 SvXMLNumFormatContext::PrivateGetKey()
{
// used for map elements in CreateAndInsert - don't reset bRemoveAfterUse flag
if (nKey > -1)
return nKey;
else
{
CreateAndInsert(sal_True);
return nKey;
}
}
sal_Int32 SvXMLNumFormatContext::CreateAndInsert( com::sun::star::uno::Reference< com::sun::star::util::XNumberFormatsSupplier >& xFormatsSupplier )
{
if (nKey <= -1)
{
SvNumberFormatter* pFormatter = NULL;
SvNumberFormatsSupplierObj* pObj =
SvNumberFormatsSupplierObj::getImplementation( xFormatsSupplier );
if (pObj)
pFormatter = pObj->GetNumberFormatter();
if ( pFormatter )
return CreateAndInsert( pFormatter );
else
return -1;
}
else
return nKey;
}
void SvXMLNumFormatContext::CreateAndInsert(sal_Bool /*bOverwrite*/)
{
if (!(nKey > -1))
CreateAndInsert(pData->GetNumberFormatter());
}
sal_Int32 SvXMLNumFormatContext::CreateAndInsert(SvNumberFormatter* pFormatter)
{
if (!pFormatter)
{
OSL_FAIL("no number formatter");
return -1;
}
sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
for (sal_uInt32 i = 0; i < aMyConditions.size(); i++)
{
SvXMLNumFormatContext* pStyle = (SvXMLNumFormatContext *)pStyles->FindStyleChildContext(
XML_STYLE_FAMILY_DATA_STYLE, aMyConditions[i].sMapName, sal_False);
if (pStyle)
{
if ((pStyle->PrivateGetKey() > -1)) // don't reset pStyle's bRemoveAfterUse flag
AddCondition(i);
}
}
if ( !aFormatCode.getLength() )
{
// insert empty format as empty string (with quotes)
// #93901# this check has to be done before inserting the conditions
aFormatCode.appendAscii("\"\""); // ""
}
aFormatCode.insert( 0, aConditions.makeStringAndClear() );
OUString sFormat = aFormatCode.makeStringAndClear();
// test special cases
if ( bAutoDec ) // automatic decimal places
{
// #99391# adjust only if the format contains no text elements, no conditions
// and no color definition (detected by the '[' at the start)
if ( nType == XML_TOK_STYLES_NUMBER_STYLE && !bHasExtraText &&
aMyConditions.size() == 0 && sFormat.toChar() != (sal_Unicode)'[' )
nIndex = pFormatter->GetStandardIndex( nFormatLang );
}
if ( bAutoInt ) // automatic integer digits
{
//! only if two decimal places was set?
if ( nType == XML_TOK_STYLES_NUMBER_STYLE && !bHasExtraText &&
aMyConditions.size() == 0 && sFormat.toChar() != (sal_Unicode)'[' )
nIndex = pFormatter->GetFormatIndex( NF_NUMBER_SYSTEM, nFormatLang );
}
// boolean is always the builtin boolean format
// (no other boolean formats are implemented)
if ( nType == XML_TOK_STYLES_BOOLEAN_STYLE )
nIndex = pFormatter->GetFormatIndex( NF_BOOLEAN, nFormatLang );
// check for default date formats
if ( nType == XML_TOK_STYLES_DATE_STYLE && bAutoOrder && !bDateNoDefault )
{
NfIndexTableOffset eFormat = (NfIndexTableOffset) SvXMLNumFmtDefaults::GetDefaultDateFormat(
eDateDOW, eDateDay, eDateMonth, eDateYear,
eDateHours, eDateMins, eDateSecs, bFromSystem );
if ( eFormat < NF_INDEX_TABLE_ENTRIES )
{
// #109651# if a date format has the automatic-order attribute and
// contains exactly the elements of one of the default date formats,
// use that default format, with the element order and separators
// from the current locale settings
nIndex = pFormatter->GetFormatIndex( eFormat, nFormatLang );
}
}
if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND && sFormat.getLength() )
{
// insert by format string
String aFormatStr( sFormat );
nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND )
{
xub_StrLen nErrPos = 0;
short l_nType = 0;
sal_Bool bOk = pFormatter->PutEntry( aFormatStr, nErrPos, l_nType, nIndex, nFormatLang );
if ( !bOk && nErrPos == 0 && aFormatStr != String(sFormat) )
{
// if the string was modified by PutEntry, look for an existing format
// with the modified string
nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND )
bOk = sal_True;
}
if (!bOk)
nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
}
}
//! I18N doesn't provide SYSTEM or extended date information yet
if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND && !bAutoOrder )
{
// use fixed-order formats instead of SYS... if bAutoOrder is false
// (only if the format strings are equal for the locale)
NfIndexTableOffset eOffset = pFormatter->GetIndexTableOffset( nIndex );
if ( eOffset == NF_DATE_SYS_DMMMYYYY )
{
sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMYYYY, nFormatLang );
const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
nIndex = nNewIndex;
}
else if ( eOffset == NF_DATE_SYS_DMMMMYYYY )
{
sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMMYYYY, nFormatLang );
const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
nIndex = nNewIndex;
}
}
if ((nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND) && sFormatTitle.getLength())
{
SvNumberformat* pFormat = const_cast<SvNumberformat*>(pFormatter->GetEntry( nIndex ));
if (pFormat)
{
String sTitle (sFormatTitle);
pFormat->SetComment(sTitle);
}
}
if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND )
{
OSL_FAIL("invalid number format");
nIndex = pFormatter->GetStandardIndex( nFormatLang );
}
pData->AddKey( nIndex, GetName(), bRemoveAfterUse );
nKey = nIndex;
// Add to import's list of keys (shared between styles and content import)
// only if not volatile - formats are removed from NumberFormatter at the
// end of each import (in SvXMLNumFmtHelper dtor).
// If bRemoveAfterUse is reset later in GetKey, AddNumberStyle is called there.
if (!bRemoveAfterUse)
GetImport().AddNumberStyle( nKey, GetName() );
return nKey;
}
void SvXMLNumFormatContext::Finish( sal_Bool bOverwrite )
{
SvXMLStyleContext::Finish( bOverwrite );
}
const LocaleDataWrapper& SvXMLNumFormatContext::GetLocaleData() const
{
return pData->GetLocaleData( nFormatLang );
}
void SvXMLNumFormatContext::AddToCode( const rtl::OUString& rString )
{
aFormatCode.append( rString );
bHasExtraText = sal_True;
}
void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo )
{
SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
if (!pFormatter)
return;
// store special conditions
bAutoDec = ( rInfo.nDecimals < 0 );
bAutoInt = ( rInfo.nInteger < 0 );
sal_uInt16 nPrec = 0;
sal_uInt16 nLeading = 0;
if ( rInfo.nDecimals >= 0 ) // < 0 : Default
nPrec = (sal_uInt16) rInfo.nDecimals;
if ( rInfo.nInteger >= 0 ) // < 0 : Default
nLeading = (sal_uInt16) rInfo.nInteger;
if ( bAutoDec )
{
if ( nType == XML_TOK_STYLES_CURRENCY_STYLE )
{
// for currency formats, "automatic decimals" is used for the automatic
// currency format with (fixed) decimals from the locale settings
const LocaleDataWrapper& rLoc = pData->GetLocaleData( nFormatLang );
nPrec = rLoc.getCurrDigits();
}
else
{
// for other types, "automatic decimals" means dynamic determination of
// decimals, as achieved with the "general" keyword
aFormatCode.append( pFormatter->GetStandardName( nFormatLang ) );
return;
}
}
if ( bAutoInt )
{
//!...
}
sal_uInt16 nGenPrec = nPrec;
if ( rInfo.bDecReplace || rInfo.bVarDecimals )
nGenPrec = 0; // generate format without decimals...
sal_Bool bGrouping = rInfo.bGrouping;
sal_uInt16 nEmbeddedCount = rInfo.aEmbeddedElements.Count();
if ( nEmbeddedCount )
bGrouping = sal_False; // grouping and embedded characters can't be used together
String aNumStr;
sal_uInt32 nStdIndex = pFormatter->GetStandardIndex( nFormatLang );
pFormatter->GenerateFormat( aNumStr, nStdIndex, nFormatLang,
bGrouping, sal_False, nGenPrec, nLeading );
if ( rInfo.nExpDigits >= 0 && nLeading == 0 && !bGrouping && nEmbeddedCount == 0 )
{
// #i43959# For scientific numbers, "#" in the integer part forces a digit,
// so it has to be removed if nLeading is 0 (".00E+0", not "#.00E+0").
aNumStr.EraseLeadingChars( (sal_Unicode)'#' );
}
if ( nEmbeddedCount )
{
// insert embedded strings into number string
// only the integer part is supported
// nZeroPos is the string position where format position 0 is inserted
xub_StrLen nZeroPos = aNumStr.Search( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() );
if ( nZeroPos == STRING_NOTFOUND )
nZeroPos = aNumStr.Len();
// aEmbeddedElements is sorted - last entry has the largest position (leftmost)
const SvXMLEmbeddedElement* pLastObj = rInfo.aEmbeddedElements[nEmbeddedCount - 1];
sal_Int32 nLastFormatPos = pLastObj->nFormatPos;
if ( nLastFormatPos >= nZeroPos )
{
// add '#' characters so all embedded texts are really embedded in digits
// (there always has to be a digit before the leftmost embedded text)
xub_StrLen nAddCount = (xub_StrLen)nLastFormatPos + 1 - nZeroPos;
String aDigitStr;
aDigitStr.Fill( nAddCount, (sal_Unicode)'#' );
aNumStr.Insert( aDigitStr, 0 );
nZeroPos = nZeroPos + nAddCount;
}
// aEmbeddedElements is sorted with ascending positions - loop is from right to left
for (sal_uInt16 nElement = 0; nElement < nEmbeddedCount; nElement++)
{
const SvXMLEmbeddedElement* pObj = rInfo.aEmbeddedElements[nElement];
sal_Int32 nFormatPos = pObj->nFormatPos;
sal_Int32 nInsertPos = nZeroPos - nFormatPos;
if ( nFormatPos >= 0 && nInsertPos >= 0 )
{
rtl::OUStringBuffer aContent( pObj->aText );
// #107805# always quote embedded strings - even space would otherwise
// be recognized as thousands separator in French.
aContent.insert( 0, (sal_Unicode) '"' );
aContent.append( (sal_Unicode) '"' );
aNumStr.Insert( String( aContent.makeStringAndClear() ), (xub_StrLen)nInsertPos );
}
}
}
aFormatCode.append( aNumStr );
if ( ( rInfo.bDecReplace || rInfo.bVarDecimals ) && nPrec ) // add decimal replacement (dashes)
{
// add dashes for explicit decimal replacement, # for variable decimals
sal_Unicode cAdd = rInfo.bDecReplace ? '-' : '#';
aFormatCode.append( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() );
for ( sal_uInt16 i=0; i<nPrec; i++)
aFormatCode.append( cAdd );
}
// add extra thousands separators for display factor
if ( rInfo.fDisplayFactor != 1.0 && rInfo.fDisplayFactor > 0.0 )
{
// test for 1.0 is just for optimization - nSepCount would be 0
// one separator for each factor of 1000
sal_Int32 nSepCount = (sal_Int32) ::rtl::math::round( log10(rInfo.fDisplayFactor) / 3.0 );
if ( nSepCount > 0 )
{
OUString aSep = pData->GetLocaleData( nFormatLang ).getNumThousandSep();
for ( sal_Int32 i=0; i<nSepCount; i++ )
aFormatCode.append( aSep );
}
}
}
void SvXMLNumFormatContext::AddCurrency( const rtl::OUString& rContent, LanguageType nLang )
{
sal_Bool bAutomatic = sal_False;
OUString aSymbol = rContent;
if ( aSymbol.getLength() == 0 )
{
SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
if ( pFormatter )
{
pFormatter->ChangeIntl( nFormatLang );
String sCurString, sDummy;
pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
aSymbol = sCurString;
bAutomatic = sal_True;
}
}
else if ( nLang == LANGUAGE_SYSTEM && aSymbol.compareToAscii("CCC") == 0 )
{
// "CCC" is used for automatic long symbol
bAutomatic = sal_True;
}
if ( bAutomatic )
{
// remove unnecessary quotes before automatic symbol (formats like "-(0DM)")
// otherwise the currency symbol isn't recognized (#94048#)
sal_Int32 nLength = aFormatCode.getLength();
if ( nLength > 1 && aFormatCode.charAt( nLength-1 ) == '"' )
{
// find start of quoted string
// When SvXMLNumFmtElementContext::EndElement creates escaped quotes,
// they must be handled here, too.
sal_Int32 nFirst = nLength - 2;
while ( nFirst >= 0 && aFormatCode.charAt( nFirst ) != '"' )
--nFirst;
if ( nFirst >= 0 )
{
// remove both quotes from aFormatCode
rtl::OUString aOld = aFormatCode.makeStringAndClear();
if ( nFirst > 0 )
aFormatCode.append( aOld.copy( 0, nFirst ) );
if ( nLength > nFirst + 2 )
aFormatCode.append( aOld.copy( nFirst + 1, nLength - nFirst - 2 ) );
}
}
}
if (!bAutomatic)
aFormatCode.appendAscii( "[$" ); // intro for "new" currency symbols
aFormatCode.append( aSymbol );
if (!bAutomatic)
{
if ( nLang != LANGUAGE_SYSTEM )
{
// '-' sign and language code in hex:
aFormatCode.append( (sal_Unicode) '-' );
aFormatCode.append( String::CreateFromInt32( sal_Int32( nLang ), 16 ).ToUpperAscii() );
}
aFormatCode.append( (sal_Unicode) ']' ); // end of "new" currency symbol
}
}
void SvXMLNumFormatContext::AddNfKeyword( sal_uInt16 nIndex )
{
SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
if (!pFormatter)
return;
if ( nIndex == NF_KEY_G || nIndex == NF_KEY_GG || nIndex == NF_KEY_GGG )
bHasEra = sal_True;
if ( nIndex == NF_KEY_NNNN )
{
nIndex = NF_KEY_NNN;
bHasLongDoW = sal_True; // to remove string constant with separator
}
String sKeyword = pFormatter->GetKeyword( nFormatLang, nIndex );
if ( nIndex == NF_KEY_H || nIndex == NF_KEY_HH ||
nIndex == NF_KEY_MI || nIndex == NF_KEY_MMI ||
nIndex == NF_KEY_S || nIndex == NF_KEY_SS )
{
if ( !bTruncate && !bHasDateTime )
{
// with truncate-on-overflow = false, add "[]" to first time part
sKeyword.Insert( (sal_Unicode) '[', 0 );
sKeyword.Append( (sal_Unicode) ']' );
}
bHasDateTime = sal_True;
}
aFormatCode.append( sKeyword );
// collect the date elements that the format contains, to recognize default date formats
switch ( nIndex )
{
case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break;
case NF_KEY_NNN:
case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break;
case NF_KEY_D: eDateDay = XML_DEA_SHORT; break;
case NF_KEY_DD: eDateDay = XML_DEA_LONG; break;
case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break;
case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break;
case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break;
case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break;
case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break;
case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break;
case NF_KEY_H: eDateHours = XML_DEA_SHORT; break;
case NF_KEY_HH: eDateHours = XML_DEA_LONG; break;
case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break;
case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break;
case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break;
case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break;
case NF_KEY_AP:
case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself
default:
bDateNoDefault = sal_True; // any other element -> no default format
}
}
sal_Bool lcl_IsAtEnd( rtl::OUStringBuffer& rBuffer, const String& rToken )
{
sal_Int32 nBufLen = rBuffer.getLength();
xub_StrLen nTokLen = rToken.Len();
if ( nTokLen > nBufLen )
return sal_False;
sal_Int32 nStartPos = nBufLen - nTokLen;
for ( xub_StrLen nTokPos = 0; nTokPos < nTokLen; nTokPos++ )
if ( rToken.GetChar( nTokPos ) != rBuffer.charAt( nStartPos + nTokPos ) )
return sal_False;
return sal_True;
}
sal_Bool SvXMLNumFormatContext::ReplaceNfKeyword( sal_uInt16 nOld, sal_uInt16 nNew )
{
// replaces one keyword with another if it is found at the end of the code
SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
if (!pFormatter)
return sal_False;
String sOldStr = pFormatter->GetKeyword( nFormatLang, nOld );
if ( lcl_IsAtEnd( aFormatCode, sOldStr ) )
{
// remove old keyword
aFormatCode.setLength( aFormatCode.getLength() - sOldStr.Len() );
// add new keyword
String sNewStr = pFormatter->GetKeyword( nFormatLang, nNew );
aFormatCode.append( sNewStr );
return sal_True; // changed
}
return sal_False; // not found
}
void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex )
{
rtl::OUString rApplyName = aMyConditions[nIndex].sMapName;
rtl::OUString rCondition = aMyConditions[nIndex].sCondition;
SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
sal_uInt32 l_nKey = pData->GetKeyForName( rApplyName );
OUString sValue(RTL_CONSTASCII_USTRINGPARAM("value()")); //! define constant
sal_Int32 nValLen = sValue.getLength();
if ( pFormatter && l_nKey != NUMBERFORMAT_ENTRY_NOT_FOUND &&
rCondition.copy( 0, nValLen ) == sValue )
{
//! test for valid conditions
//! test for default conditions
OUString sRealCond = rCondition.copy( nValLen, rCondition.getLength() - nValLen );
sal_Bool bDefaultCond = sal_False;
//! collect all conditions first and adjust default to >=0, >0 or <0 depending on count
//! allow blanks in conditions
sal_Bool bFirstCond = ( aConditions.getLength() == 0 );
if ( bFirstCond && aMyConditions.size() == 1 && sRealCond.compareToAscii( ">=0" ) == 0 )
bDefaultCond = sal_True;
if ( nType == XML_TOK_STYLES_TEXT_STYLE && nIndex == 2 )
{
// The third condition in a number format with a text part can only be
// "all other numbers", the condition string must be empty.
bDefaultCond = sal_True;
}
if (!bDefaultCond)
{
sal_Int32 nPos = sRealCond.indexOf( '.' );
if ( nPos >= 0 )
{ // #i8026# #103991# localize decimal separator
const String& rDecSep = GetLocaleData().getNumDecimalSep();
if ( rDecSep.Len() > 1 || rDecSep.GetChar(0) != '.' )
sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep );
}
aConditions.append( (sal_Unicode) '[' );
aConditions.append( sRealCond );
aConditions.append( (sal_Unicode) ']' );
}
const SvNumberformat* pFormat = pFormatter->GetEntry(l_nKey);
if ( pFormat )
aConditions.append( OUString( pFormat->GetFormatstring() ) );
aConditions.append( (sal_Unicode) ';' );
}
}
void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex, const rtl::OUString& rFormat, const LocaleDataWrapper& rData )
{
rtl::OUString rCondition = aMyConditions[nIndex].sCondition;
OUString sValue(RTL_CONSTASCII_USTRINGPARAM("value()")); //! define constant
sal_Int32 nValLen = sValue.getLength();
if ( rCondition.copy( 0, nValLen ) == sValue )
{
//! test for valid conditions
//! test for default conditions
OUString sRealCond = rCondition.copy( nValLen, rCondition.getLength() - nValLen );
sal_Bool bDefaultCond = sal_False;
//! collect all conditions first and adjust default to >=0, >0 or <0 depending on count
//! allow blanks in conditions
sal_Bool bFirstCond = ( aConditions.getLength() == 0 );
if ( bFirstCond && aMyConditions.size() == 1 && sRealCond.compareToAscii( ">=0" ) == 0 )
bDefaultCond = sal_True;
if ( nType == XML_TOK_STYLES_TEXT_STYLE && nIndex == 2 )
{
// The third condition in a number format with a text part can only be
// "all other numbers", the condition string must be empty.
bDefaultCond = sal_True;
}
if (!bDefaultCond)
{
sal_Int32 nPos = sRealCond.indexOf( '.' );
if ( nPos >= 0 )
{ // #i8026# #103991# localize decimal separator
const String& rDecSep = rData.getNumDecimalSep();
if ( rDecSep.Len() > 1 || rDecSep.GetChar(0) != '.' )
sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep );
}
aConditions.append( (sal_Unicode) '[' );
aConditions.append( sRealCond );
aConditions.append( (sal_Unicode) ']' );
}
aConditions.append( rFormat );
aConditions.append( (sal_Unicode) ';' );
}
}
void SvXMLNumFormatContext::AddCondition( const rtl::OUString& rCondition, const rtl::OUString& rApplyName )
{
MyCondition aCondition;
aCondition.sCondition = rCondition;
aCondition.sMapName = rApplyName;
aMyConditions.push_back(aCondition);
}
void SvXMLNumFormatContext::AddColor( sal_uInt32 const nColor )
{
SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
if (!pFormatter)
return;
OUStringBuffer aColName;
for ( sal_uInt16 i=0; i<XML_NUMF_COLORCOUNT; i++ )
if (nColor == aNumFmtStdColors[i])
{
aColName = OUString( pFormatter->GetKeyword( nFormatLang, sal::static_int_cast< sal_uInt16 >(NF_KEY_FIRSTCOLOR + i) ) );
break;
}
if ( aColName.getLength() )
{
aColName.insert( 0, (sal_Unicode) '[' );
aColName.append( (sal_Unicode) ']' );
aFormatCode.insert( 0, aColName.makeStringAndClear() );
}
}
void SvXMLNumFormatContext::UpdateCalendar( const rtl::OUString& rNewCalendar )
{
if ( rNewCalendar != sCalendar )
{
sCalendar = rNewCalendar;
if ( sCalendar.getLength() )
{
aFormatCode.appendAscii( "[~" ); // intro for calendar code
aFormatCode.append( sCalendar );
aFormatCode.append( (sal_Unicode) ']' ); // end of "new" currency symbolcalendar code
}
}
}
sal_Bool SvXMLNumFormatContext::IsSystemLanguage()
{
return nFormatLang == LANGUAGE_SYSTEM;
}
//-------------------------------------------------------------------------
//
// SvXMLNumFmtHelper
//
SvXMLNumFmtHelper::SvXMLNumFmtHelper(
const uno::Reference<util::XNumberFormatsSupplier>& rSupp,
const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory )
: mxServiceFactory(xServiceFactory)
{
DBG_ASSERT( mxServiceFactory.is(), "got no service manager" );
SvNumberFormatter* pFormatter = NULL;
SvNumberFormatsSupplierObj* pObj =
SvNumberFormatsSupplierObj::getImplementation( rSupp );
if (pObj)
pFormatter = pObj->GetNumberFormatter();
pData = new SvXMLNumImpData( pFormatter, mxServiceFactory );
}
SvXMLNumFmtHelper::SvXMLNumFmtHelper(
SvNumberFormatter* pNumberFormatter,
const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory )
: mxServiceFactory(xServiceFactory)
{
DBG_ASSERT( mxServiceFactory.is(), "got no service manager" );
pData = new SvXMLNumImpData( pNumberFormatter, mxServiceFactory );
}
SvXMLNumFmtHelper::~SvXMLNumFmtHelper()
{
// remove temporary (volatile) formats from NumberFormatter
pData->RemoveVolatileFormats();
delete pData;
}
SvXMLStyleContext* SvXMLNumFmtHelper::CreateChildContext( SvXMLImport& rImport,
sal_uInt16 nPrefix, const OUString& rLocalName,
const uno::Reference<xml::sax::XAttributeList>& xAttrList,
SvXMLStylesContext& rStyles )
{
SvXMLStyleContext* pContext = NULL;
const SvXMLTokenMap& rTokenMap = pData->GetStylesElemTokenMap();
sal_uInt16 nToken = rTokenMap.Get( nPrefix, rLocalName );
switch (nToken)
{
case XML_TOK_STYLES_NUMBER_STYLE:
case XML_TOK_STYLES_CURRENCY_STYLE:
case XML_TOK_STYLES_PERCENTAGE_STYLE:
case XML_TOK_STYLES_DATE_STYLE:
case XML_TOK_STYLES_TIME_STYLE:
case XML_TOK_STYLES_BOOLEAN_STYLE:
case XML_TOK_STYLES_TEXT_STYLE:
pContext = new SvXMLNumFormatContext( rImport, nPrefix, rLocalName,
pData, nToken, xAttrList, rStyles );
break;
}
// return NULL if not a data style, caller must handle other elements
return pContext;
}
const SvXMLTokenMap& SvXMLNumFmtHelper::GetStylesElemTokenMap()
{
return pData->GetStylesElemTokenMap();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */