diff options
Diffstat (limited to 'sw/source/filter/ww8/writerwordglue.cxx')
-rw-r--r-- | sw/source/filter/ww8/writerwordglue.cxx | 1026 |
1 files changed, 1026 insertions, 0 deletions
diff --git a/sw/source/filter/ww8/writerwordglue.cxx b/sw/source/filter/ww8/writerwordglue.cxx new file mode 100644 index 000000000000..878286ccbb23 --- /dev/null +++ b/sw/source/filter/ww8/writerwordglue.cxx @@ -0,0 +1,1026 @@ +/* -*- 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <msfilter.hxx> +#include "writerwordglue.hxx" +#include <doc.hxx> +#include "writerhelper.hxx" + +#include <algorithm> //std::find_if +#include <functional> //std::unary_function + +#include <unicode/ubidi.h> //ubidi_getLogicalRun +#include <tools/tenccvt.hxx> //GetExtendedTextEncoding +#include <com/sun/star/i18n/ScriptType.hdl> //ScriptType + +#include <unotools/fontcvt.hxx> //GetSubsFontName +#include <editeng/paperinf.hxx> //lA0Width... +#include <editeng/lrspitem.hxx> //SvxLRSpaceItem +#include <editeng/ulspitem.hxx> //SvxULSpaceItem +#include <editeng/boxitem.hxx> //SvxBoxItem +#include <editeng/fontitem.hxx> //SvxFontItem +#include <frmfmt.hxx> //SwFrmFmt +#include <fmtclds.hxx> //SwFmtCol +#include <hfspacingitem.hxx> //SwHeaderAndFooterEatSpacingItem +#include <fmtfsize.hxx> //SwFmtFrmSize +#include <swrect.hxx> //SwRect +#include <fmthdft.hxx> //SwFmtHeader/SwFmtFooter +#include <frmatr.hxx> //GetLRSpace... +#include <ndtxt.hxx> //SwTxtNode +#include <breakit.hxx> //pBreakIt +#include <i18npool/mslangid.hxx> + +#define ASSIGN_CONST_ASC(s) AssignAscii(RTL_CONSTASCII_STRINGPARAM(s)) + +namespace myImplHelpers +{ + SwTwips CalcHdFtDist(const SwFrmFmt& rFmt, sal_uInt16 nSpacing) + { + /* + The normal case for reexporting word docs is to have dynamic spacing, + as this is word's only setting, and the reason for the existance of the + dynamic spacing features. If we have dynamic spacing active then we can + add its spacing to the value height of the h/f and get the wanted total + size for word. + + Otherwise we have to get the real layout rendered + height, which is totally nonoptimum, but the best we can do. + */ + long nDist=0; + const SwFmtFrmSize& rSz = rFmt.GetFrmSize(); + + const SwHeaderAndFooterEatSpacingItem &rSpacingCtrl = + sw::util::ItemGet<SwHeaderAndFooterEatSpacingItem> + (rFmt, RES_HEADER_FOOTER_EAT_SPACING); + if (rSpacingCtrl.GetValue()) + nDist += rSz.GetHeight(); + else + { + SwRect aRect(rFmt.FindLayoutRect(false)); + if (aRect.Height()) + nDist += aRect.Height(); + else + { + const SwFmtFrmSize& rSize = rFmt.GetFrmSize(); + if (ATT_VAR_SIZE != rSize.GetHeightSizeType()) + nDist += rSize.GetHeight(); + else + { + nDist += 274; // default for 12pt text + nDist += nSpacing; + } + } + } + return nDist; + } + + SwTwips CalcHdDist(const SwFrmFmt& rFmt) + { + return CalcHdFtDist(rFmt, rFmt.GetULSpace().GetUpper()); + } + + SwTwips CalcFtDist(const SwFrmFmt& rFmt) + { + return CalcHdFtDist(rFmt, rFmt.GetULSpace().GetLower()); + } + + /* + SwTxtFmtColl and SwCharFmt are quite distinct types and how they are + gotten is also distinct, but the algorithm to match word's eqivalents into + them is the same, so we put the different stuff into two seperate helper + implementations and a core template that uses the helpers that uses the + same algorithm to do the work. We'll make the helpers specializations of a + non existing template so I can let the compiler figure out the right one + to use from a simple argument to the algorithm class + */ + template <class C> class MapperImpl; + template<> class MapperImpl<SwTxtFmtColl> + { + private: + SwDoc &mrDoc; + public: + MapperImpl(SwDoc &rDoc) : mrDoc(rDoc) {} + SwTxtFmtColl* GetBuiltInStyle(ww::sti eSti); + SwTxtFmtColl* GetStyle(const String &rName); + SwTxtFmtColl* MakeStyle(const String &rName); + }; + + SwTxtFmtColl* MapperImpl<SwTxtFmtColl>::GetBuiltInStyle(ww::sti eSti) + { + const RES_POOL_COLLFMT_TYPE RES_NONE = RES_POOLCOLL_DOC_END; + static const RES_POOL_COLLFMT_TYPE aArr[]= + { + RES_POOLCOLL_STANDARD, RES_POOLCOLL_HEADLINE1, + RES_POOLCOLL_HEADLINE2, RES_POOLCOLL_HEADLINE3, + RES_POOLCOLL_HEADLINE4, RES_POOLCOLL_HEADLINE5, + RES_POOLCOLL_HEADLINE6, RES_POOLCOLL_HEADLINE7, + RES_POOLCOLL_HEADLINE8, RES_POOLCOLL_HEADLINE9, + RES_POOLCOLL_TOX_IDX1, RES_POOLCOLL_TOX_IDX2, + RES_POOLCOLL_TOX_IDX3, RES_NONE, RES_NONE, RES_NONE, RES_NONE, + RES_NONE, RES_NONE, RES_POOLCOLL_TOX_CNTNT1, + RES_POOLCOLL_TOX_CNTNT2, RES_POOLCOLL_TOX_CNTNT3, + RES_POOLCOLL_TOX_CNTNT4, RES_POOLCOLL_TOX_CNTNT5, + RES_POOLCOLL_TOX_CNTNT6, RES_POOLCOLL_TOX_CNTNT7, + RES_POOLCOLL_TOX_CNTNT8, RES_POOLCOLL_TOX_CNTNT9, RES_NONE, + RES_POOLCOLL_FOOTNOTE, RES_NONE, RES_POOLCOLL_HEADER, + RES_POOLCOLL_FOOTER, RES_POOLCOLL_TOX_IDXH, RES_NONE, RES_NONE, + RES_POOLCOLL_JAKETADRESS, RES_POOLCOLL_SENDADRESS, RES_NONE, + RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_POOLCOLL_ENDNOTE, + RES_NONE, RES_NONE, RES_NONE, RES_POOLCOLL_LISTS_BEGIN, + RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE, + RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE, + RES_NONE, RES_NONE, RES_POOLCOLL_HEADLINE_BASE, RES_NONE, + RES_POOLCOLL_SIGNATURE, RES_NONE, RES_POOLCOLL_TEXT, + RES_POOLCOLL_TEXT_MOVE, RES_NONE, RES_NONE, RES_NONE, RES_NONE, + RES_NONE, RES_NONE, RES_POOLCOLL_DOC_SUBTITEL + }; + + const size_t nArrSize = (SAL_N_ELEMENTS(aArr)); + OSL_ENSURE(nArrSize == 75, "Style Array has false size"); + + SwTxtFmtColl* pRet = 0; + //If this is a built-in word style that has a built-in writer + //equivalent, then map it to one of our built in styles regardless + //of its name + if (sal::static_int_cast< size_t >(eSti) < nArrSize && aArr[eSti] != RES_NONE) + pRet = mrDoc.GetTxtCollFromPool( static_cast< sal_uInt16 >(aArr[eSti]), false); + return pRet; + } + + SwTxtFmtColl* MapperImpl<SwTxtFmtColl>::GetStyle(const String &rName) + { + return sw::util::GetParaStyle(mrDoc, rName); + } + + SwTxtFmtColl* MapperImpl<SwTxtFmtColl>::MakeStyle(const String &rName) + { + return mrDoc.MakeTxtFmtColl(rName, + const_cast<SwTxtFmtColl *>(mrDoc.GetDfltTxtFmtColl())); + } + + template<> class MapperImpl<SwCharFmt> + { + private: + SwDoc &mrDoc; + public: + MapperImpl(SwDoc &rDoc) : mrDoc(rDoc) {} + SwCharFmt* GetBuiltInStyle(ww::sti eSti); + SwCharFmt* GetStyle(const String &rName); + SwCharFmt* MakeStyle(const String &rName); + }; + + SwCharFmt* MapperImpl<SwCharFmt>::GetBuiltInStyle(ww::sti eSti) + { + RES_POOL_CHRFMT_TYPE eLookup = RES_POOLCHR_NORMAL_END; + switch (eSti) + { + case ww::stiFtnRef: + eLookup = RES_POOLCHR_FOOTNOTE; + break; + case ww::stiLnn: + eLookup = RES_POOLCHR_LINENUM; + break; + case ww::stiPgn: + eLookup = RES_POOLCHR_PAGENO; + break; + case ww::stiEdnRef: + eLookup = RES_POOLCHR_ENDNOTE; + break; + case ww::stiHyperlink: + eLookup = RES_POOLCHR_INET_NORMAL; + break; + case ww::stiHyperlinkFollowed: + eLookup = RES_POOLCHR_INET_VISIT; + break; + case ww::stiStrong: + eLookup = RES_POOLCHR_HTML_STRONG; + break; + case ww::stiEmphasis: + eLookup = RES_POOLCHR_HTML_EMPHASIS; + break; + default: + eLookup = RES_POOLCHR_NORMAL_END; + break; + } + SwCharFmt *pRet = 0; + if (eLookup != RES_POOLCHR_NORMAL_END) + pRet = mrDoc.GetCharFmtFromPool( static_cast< sal_uInt16 >(eLookup) ); + return pRet; + } + + SwCharFmt* MapperImpl<SwCharFmt>::GetStyle(const String &rName) + { + return sw::util::GetCharStyle(mrDoc, rName); + } + + SwCharFmt* MapperImpl<SwCharFmt>::MakeStyle(const String &rName) + { + return mrDoc.MakeCharFmt(rName, mrDoc.GetDfltCharFmt()); + } + + template<class C> class StyleMapperImpl + { + private: + MapperImpl<C> maHelper; + std::set<const C*> maUsedStyles; + C* MakeNonCollidingStyle(const String& rName); + public: + typedef std::pair<C*, bool> StyleResult; + StyleMapperImpl(SwDoc &rDoc) : maHelper(rDoc) {} + StyleResult GetStyle(const String& rName, ww::sti eSti); + }; + + template<class C> + typename StyleMapperImpl<C>::StyleResult + StyleMapperImpl<C>::GetStyle(const String& rName, ww::sti eSti) + { + C *pRet = maHelper.GetBuiltInStyle(eSti); + + //If we've used it once, don't reuse it + if (pRet && (maUsedStyles.end() != maUsedStyles.find(pRet))) + pRet = 0; + + if (!pRet) + { + pRet = maHelper.GetStyle(rName); + //If we've used it once, don't reuse it + if (pRet && (maUsedStyles.end() != maUsedStyles.find(pRet))) + pRet = 0; + } + + bool bStyExist = pRet ? true : false; + + if (!pRet) + { + String aName(rName); + xub_StrLen nPos = aName.Search(','); + // No commas allow in SW style names + if (STRING_NOTFOUND != nPos) + aName.Erase(nPos); + pRet = MakeNonCollidingStyle(aName); + } + + if (pRet) + maUsedStyles.insert(pRet); + + return StyleResult(pRet, bStyExist); + } + + template<class C> + C* StyleMapperImpl<C>::MakeNonCollidingStyle(const String& rName) + { + String aName(rName); + C* pColl = 0; + + if (0 != (pColl = maHelper.GetStyle(aName))) + { + //If the style collides first stick WW- in front of it, unless + //it already has it and then successively add a larger and + //larger number after it, its got to work at some stage! + if (!aName.EqualsIgnoreCaseAscii("WW-", 0, 3)) + aName.InsertAscii("WW-" , 0); + + sal_Int32 nI = 1; + while ( + 0 != (pColl = maHelper.GetStyle(aName)) && + (nI < SAL_MAX_INT32) + ) + { + aName += String::CreateFromInt32(nI++); + } + } + + return pColl ? 0 : maHelper.MakeStyle(aName); + } + + String FindBestMSSubstituteFont(const String &rFont) + { + String sRet; + if (sw::util::IsStarSymbol(rFont)) + sRet.ASSIGN_CONST_ASC("Arial Unicode MS"); + else + sRet = GetSubsFontName(rFont, SUBSFONT_ONLYONE | SUBSFONT_MS); + return sRet; + } + + //Utility to remove entries before a given starting position + class IfBeforeStart + : public std::unary_function<const sw::util::CharRunEntry&, bool> + { + private: + xub_StrLen mnStart; + public: + IfBeforeStart(xub_StrLen nStart) : mnStart(nStart) {} + bool operator()(const sw::util::CharRunEntry &rEntry) const + { + return rEntry.mnEndPos < mnStart; + } + }; +} + +namespace sw +{ + namespace util + { + + bool IsPlausableSingleWordSection(const SwFrmFmt &rTitleFmt, + const SwFrmFmt &rFollowFmt) + { + bool bPlausableTitlePage = true; + + const SwFmtCol& rFirstCols = rTitleFmt.GetCol(); + const SwFmtCol& rFollowCols = rFollowFmt.GetCol(); + const SwColumns& rFirstColumns = rFirstCols.GetColumns(); + const SwColumns& rFollowColumns = rFollowCols.GetColumns(); + const SvxLRSpaceItem &rOneLR = rTitleFmt.GetLRSpace(); + const SvxLRSpaceItem &rTwoLR= rFollowFmt.GetLRSpace(); + + if (rFirstColumns.Count() != rFollowColumns.Count()) + { + //e.g. #i4320# + bPlausableTitlePage = false; + } + else if (rOneLR != rTwoLR) + bPlausableTitlePage = false; + else + { + HdFtDistanceGlue aOne(rTitleFmt.GetAttrSet()); + HdFtDistanceGlue aTwo(rFollowFmt.GetAttrSet()); + //e.g. #i14509# + if (!aOne.EqualTopBottom(aTwo)) + bPlausableTitlePage = false; + } + return bPlausableTitlePage; + } + + HdFtDistanceGlue::HdFtDistanceGlue(const SfxItemSet &rPage) + { + if (const SvxBoxItem *pBox = HasItem<SvxBoxItem>(rPage, RES_BOX)) + { + dyaHdrTop = pBox->CalcLineSpace(BOX_LINE_TOP); + dyaHdrBottom = pBox->CalcLineSpace(BOX_LINE_BOTTOM); + } + else + { + dyaHdrTop = dyaHdrBottom = 0; + dyaHdrBottom = 0; + } + const SvxULSpaceItem &rUL = + ItemGet<SvxULSpaceItem>(rPage, RES_UL_SPACE); + dyaHdrTop = dyaHdrTop + rUL.GetUpper(); + dyaHdrBottom = dyaHdrBottom + rUL.GetLower(); + + dyaTop = dyaHdrTop; + dyaBottom = dyaHdrBottom; + + using sw::types::msword_cast; + + const SwFmtHeader *pHd = HasItem<SwFmtHeader>(rPage, RES_HEADER); + if (pHd && pHd->IsActive() && pHd->GetHeaderFmt()) + { + mbHasHeader = true; + dyaTop = dyaTop + static_cast< sal_uInt16 >( (myImplHelpers::CalcHdDist(*(pHd->GetHeaderFmt()))) ); + } + else + mbHasHeader = false; + + const SwFmtFooter *pFt = HasItem<SwFmtFooter>(rPage, RES_FOOTER); + if (pFt && pFt->IsActive() && pFt->GetFooterFmt()) + { + mbHasFooter = true; + dyaBottom = dyaBottom + static_cast< sal_uInt16 >( (myImplHelpers::CalcFtDist(*(pFt->GetFooterFmt()))) ); + } + else + mbHasFooter = false; + } + + bool HdFtDistanceGlue::EqualTopBottom(const HdFtDistanceGlue &rOther) + const + { + return (dyaTop == rOther.dyaTop && dyaBottom == rOther.dyaBottom); + } + + ParaStyleMapper::ParaStyleMapper(SwDoc &rDoc) + : mpImpl(new myImplHelpers::StyleMapperImpl<SwTxtFmtColl>(rDoc)) + { + } + + ParaStyleMapper::~ParaStyleMapper() + { + delete mpImpl; + } + + ParaStyleMapper::StyleResult ParaStyleMapper::GetStyle( + const String& rName, ww::sti eSti) + { + return mpImpl->GetStyle(rName, eSti); + } + + CharStyleMapper::CharStyleMapper(SwDoc &rDoc) + : mpImpl(new myImplHelpers::StyleMapperImpl<SwCharFmt>(rDoc)) + { + } + + CharStyleMapper::~CharStyleMapper() + { + delete mpImpl; + } + + CharStyleMapper::StyleResult CharStyleMapper::GetStyle( + const String& rName, ww::sti eSti) + { + return mpImpl->GetStyle(rName, eSti); + } + + FontMapExport::FontMapExport(const String &rFamilyName) + { + msPrimary = GetFontToken(rFamilyName, 0); + msSecondary = myImplHelpers::FindBestMSSubstituteFont(msPrimary); + if (!msSecondary.Len()) + msSecondary = GetFontToken(rFamilyName, 1); + } + + bool FontMapExport::HasDistinctSecondary() const + { + if (msSecondary.Len() && msSecondary != msPrimary) + return true; + return false; + } + + bool ItemSort::operator()(sal_uInt16 nA, sal_uInt16 nB) const + { + /* + #i24291# + All we want to do is ensure for now is that if a charfmt exist + in the character properties that it rises to the top and is + exported first. In the future we might find more ordering + depandancies for export, in which case this is the place to do + it + */ + if (nA == nB) + return false; + if (nA == RES_TXTATR_CHARFMT) + return true; + if (nB == RES_TXTATR_CHARFMT) + return false; + return nA < nB; + } + + CharRuns GetPseudoCharRuns(const SwTxtNode& rTxtNd, + xub_StrLen nTxtStart, bool bSplitOnCharSet) + { + const String &rTxt = rTxtNd.GetTxt(); + + bool bParaIsRTL = false; + OSL_ENSURE(rTxtNd.GetDoc(), "No document for node?, suspicious"); + if (rTxtNd.GetDoc()) + { + if (FRMDIR_HORI_RIGHT_TOP == + rTxtNd.GetDoc()->GetTextDirection(SwPosition(rTxtNd))) + { + bParaIsRTL = true; + } + } + + using namespace ::com::sun::star::i18n; + + sal_uInt16 nScript = i18n::ScriptType::LATIN; + if (rTxt.Len() && pBreakIt && pBreakIt->GetBreakIter().is()) + nScript = pBreakIt->GetBreakIter()->getScriptType(rTxt, 0); + + rtl_TextEncoding eChrSet = ItemGet<SvxFontItem>(rTxtNd, + GetWhichOfScript(RES_CHRATR_FONT, nScript)).GetCharSet(); + eChrSet = GetExtendedTextEncoding(eChrSet); + + CharRuns aRunChanges; + + if (!rTxt.Len()) + { + aRunChanges.push_back(CharRunEntry(0, nScript, eChrSet, + bParaIsRTL)); + return aRunChanges; + } + + typedef std::pair<int32_t, bool> DirEntry; + typedef std::vector<DirEntry> DirChanges; + typedef DirChanges::const_iterator cDirIter; + + typedef std::pair<xub_StrLen, sal_Int16> CharSetEntry; + typedef std::vector<CharSetEntry> CharSetChanges; + typedef CharSetChanges::const_iterator cCharSetIter; + + typedef std::pair<xub_StrLen, sal_uInt16> ScriptEntry; + typedef std::vector<ScriptEntry> ScriptChanges; + typedef ScriptChanges::const_iterator cScriptIter; + + DirChanges aDirChanges; + CharSetChanges aCharSets; + ScriptChanges aScripts; + + UBiDiDirection eDefaultDir = bParaIsRTL ? UBIDI_RTL : UBIDI_LTR; + UErrorCode nError = U_ZERO_ERROR; + UBiDi* pBidi = ubidi_openSized(rTxt.Len(), 0, &nError); + ubidi_setPara(pBidi, reinterpret_cast<const UChar *>(rTxt.GetBuffer()), rTxt.Len(), + static_cast< UBiDiLevel >(eDefaultDir), 0, &nError); + + sal_Int32 nCount = ubidi_countRuns(pBidi, &nError); + aDirChanges.reserve(nCount); + + int32_t nStart = 0; + int32_t nEnd; + UBiDiLevel nCurrDir; + + for (sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx) + { + ubidi_getLogicalRun(pBidi, nStart, &nEnd, &nCurrDir); + /* + UBiDiLevel is the type of the level values in this BiDi + implementation. + + It holds an embedding level and indicates the visual direction + by its bit 0 (even/odd value). + + The value for UBIDI_DEFAULT_LTR is even and the one for + UBIDI_DEFAULT_RTL is odd + */ + aDirChanges.push_back(DirEntry(nEnd, nCurrDir & 0x1)); + nStart = nEnd; + } + ubidi_close(pBidi); + + if (bSplitOnCharSet) + { + //Split unicode text into plausable 8bit ranges for export to + //older non unicode aware format + xub_StrLen nLen = rTxt.Len(); + xub_StrLen nPos = 0; + while (nPos != nLen) + { + rtl_TextEncoding ScriptType = + getBestMSEncodingByChar(rTxt.GetChar(nPos++)); + while ( + (nPos != nLen) && + (ScriptType == getBestMSEncodingByChar(rTxt.GetChar(nPos))) + ) + { + ++nPos; + } + + aCharSets.push_back(CharSetEntry(nPos, ScriptType)); + } + } + + using sw::types::writer_cast; + + if (pBreakIt && pBreakIt->GetBreakIter().is()) + { + xub_StrLen nLen = rTxt.Len(); + xub_StrLen nPos = 0; + while (nPos < nLen) + { + sal_Int32 nEnd2 = pBreakIt->GetBreakIter()->endOfScript(rTxt, nPos, + nScript); + if (nEnd2 < 0) + break; + nPos = static_cast< xub_StrLen >(nEnd2); + aScripts.push_back(ScriptEntry(nPos, nScript)); + nScript = pBreakIt->GetBreakIter()->getScriptType(rTxt, nPos); + } + } + + cDirIter aBiDiEnd = aDirChanges.end(); + cCharSetIter aCharSetEnd = aCharSets.end(); + cScriptIter aScriptEnd = aScripts.end(); + + cDirIter aBiDiIter = aDirChanges.begin(); + cCharSetIter aCharSetIter = aCharSets.begin(); + cScriptIter aScriptIter = aScripts.begin(); + + bool bCharIsRTL = bParaIsRTL; + + while ( + aBiDiIter != aBiDiEnd || + aCharSetIter != aCharSetEnd || + aScriptIter != aScriptEnd + ) + { + xub_StrLen nMinPos = rTxt.Len(); + + if (aBiDiIter != aBiDiEnd) + { + if (aBiDiIter->first < nMinPos) + nMinPos = static_cast< xub_StrLen >(aBiDiIter->first); + bCharIsRTL = aBiDiIter->second; + } + + if (aCharSetIter != aCharSetEnd) + { + if (aCharSetIter->first < nMinPos) + nMinPos = aCharSetIter->first; + eChrSet = aCharSetIter->second; + } + + if (aScriptIter != aScriptEnd) + { + if (aScriptIter->first < nMinPos) + nMinPos = aScriptIter->first; + nScript = aScriptIter->second; + } + + aRunChanges.push_back( + CharRunEntry(nMinPos, nScript, eChrSet, bCharIsRTL)); + + if (aBiDiIter != aBiDiEnd) + { + if (aBiDiIter->first == nMinPos) + ++aBiDiIter; + } + + if (aCharSetIter != aCharSetEnd) + { + if (aCharSetIter->first == nMinPos) + ++aCharSetIter; + } + + if (aScriptIter != aScriptEnd) + { + if (aScriptIter->first == nMinPos) + ++aScriptIter; + } + } + + aRunChanges.erase(std::remove_if(aRunChanges.begin(), + aRunChanges.end(), myImplHelpers::IfBeforeStart(nTxtStart)), aRunChanges.end()); + + return aRunChanges; + } + } + + namespace ms + { + sal_uInt8 rtl_TextEncodingToWinCharset(rtl_TextEncoding eTextEncoding) + { + sal_uInt8 nRet = + rtl_getBestWindowsCharsetFromTextEncoding(eTextEncoding); + switch (eTextEncoding) + { + case RTL_TEXTENCODING_DONTKNOW: + case RTL_TEXTENCODING_UCS2: + case RTL_TEXTENCODING_UTF7: + case RTL_TEXTENCODING_UTF8: + case RTL_TEXTENCODING_JAVA_UTF8: + OSL_ENSURE(nRet != 0x80, "This method may be redundant"); + nRet = 0x80; + break; + default: + break; + } + return nRet; + } + + long DateTime2DTTM( const DateTime& rDT ) + { + /* + mint short :6 0000003F minutes (0-59) + hr short :5 000007C0 hours (0-23) + dom short :5 0000F800 days of month (1-31) + mon short :4 000F0000 months (1-12) + yr short :9 1FF00000 years (1900-2411)-1900 + wdy short :3 E0000000 weekday(Sunday=0 + Monday=1 + ( wdy can be ignored ) Tuesday=2 + Wednesday=3 + Thursday=4 + Friday=5 + Saturday=6) + */ + + if ( rDT.GetDate() == 0L ) + return 0L; + long nDT = ( rDT.GetDayOfWeek() + 1 ) % 7; + nDT <<= 9; + nDT += ( rDT.GetYear() - 1900 ) & 0x1ff; + nDT <<= 4; + nDT += rDT.GetMonth() & 0xf; + nDT <<= 5; + nDT += rDT.GetDay() & 0x1f; + nDT <<= 5; + nDT += rDT.GetHour() & 0x1f; + nDT <<= 6; + nDT += rDT.GetMin() & 0x3f; + return nDT; + } + + DateTime DTTM2DateTime( long lDTTM ) + { + /* + mint short :6 0000003F minutes (0-59) + hr short :5 000007C0 hours (0-23) + dom short :5 0000F800 days of month (1-31) + mon short :4 000F0000 months (1-12) + yr short :9 1FF00000 years (1900-2411)-1900 + wdy short :3 E0000000 weekday(Sunday=0 + Monday=1 + ( wdy can be ignored ) Tuesday=2 + Wednesday=3 + Thursday=4 + Friday=5 + Saturday=6) + */ + DateTime aDateTime(Date( 0 ), Time( 0 )); + if( lDTTM ) + { + sal_uInt16 lMin = (sal_uInt16)(lDTTM & 0x0000003F); + lDTTM >>= 6; + sal_uInt16 lHour= (sal_uInt16)(lDTTM & 0x0000001F); + lDTTM >>= 5; + sal_uInt16 lDay = (sal_uInt16)(lDTTM & 0x0000001F); + lDTTM >>= 5; + sal_uInt16 lMon = (sal_uInt16)(lDTTM & 0x0000000F); + lDTTM >>= 4; + sal_uInt16 lYear= (sal_uInt16)(lDTTM & 0x000001FF) + 1900; + aDateTime = DateTime(Date(lDay, lMon, lYear), Time(lHour, lMin)); + } + return aDateTime; + } + + sal_uLong MSDateTimeFormatToSwFormat(String& rParams, + SvNumberFormatter *pFormatter, sal_uInt16 &rLang, bool bHijri, + sal_uInt16 nDocLang) + { + // tell the Formatter about the new entry + sal_uInt16 nCheckPos = 0; + short nType = NUMBERFORMAT_DEFINED; + sal_uInt32 nKey = 0; + + SwapQuotesInField(rParams); + + // Force to Japanese when finding one of 'geaE' + rtl::OUString sJChars(RTL_CONSTASCII_USTRINGPARAM("geE")); + bool bForceJapanese = ( STRING_NOTFOUND != rParams.SearchChar( sJChars.getStr() ) ); + if ( bForceJapanese ) + { + rParams.SearchAndReplaceAll( String::CreateFromAscii( "ee" ), + String::CreateFromAscii( "yyyy" ) ); + rParams.SearchAndReplaceAll( String::CreateFromAscii( "EE" ), + String::CreateFromAscii( "YYYY" ) ); + } + if (LANGUAGE_FRENCH != nDocLang) + { + // Handle the 'a' case here + xub_StrLen nLastPos = 0; + do + { + xub_StrLen nPos = rParams.Search( 'a', nLastPos + 1 ); + bForceJapanese |= ( nPos != STRING_NOTFOUND && IsNotAM( rParams, nPos ) ); + nLastPos = nPos; + } while ( STRING_NOTFOUND != nLastPos ); + } + + // Force to NatNum when finding one of 'oOA' + String sOldParams( rParams ); + rParams.SearchAndReplaceAll( String::CreateFromAscii( "o" ), + String::CreateFromAscii( "m" ) ); + rParams.SearchAndReplaceAll( String::CreateFromAscii( "O" ), + String::CreateFromAscii( "M" ) ); + bool bForceNatNum = !sOldParams.Equals( rParams ); + if (LANGUAGE_FRENCH != nDocLang) + { + // Handle the 'A' case here + xub_StrLen nLastPos = 0; + do + { + xub_StrLen nPos = rParams.Search( 'A', nLastPos + 1 ); + bool bIsCharA = ( nPos != STRING_NOTFOUND && IsNotAM( rParams, nPos ) ); + bForceNatNum |= bIsCharA; + if ( bIsCharA ) + rParams.SetChar( nPos, 'D' ); + nLastPos = nPos; + } while ( STRING_NOTFOUND != nLastPos ); + } + + xub_StrLen nLen = rParams.Len(); + xub_StrLen nI = 0; + while (nI < nLen) + { + if (rParams.GetChar(nI) == '\\') + nI++; + else if (rParams.GetChar(nI) == '\"') + { + ++nI; + //While not at the end and not at an unescaped end quote + while ((nI < nLen) && (!(rParams.GetChar(nI) == '\"') && (rParams.GetChar(nI-1) != '\\'))) + ++nI; + } + else //normal unquoted section + { + sal_Unicode nChar = rParams.GetChar(nI); + + // Change the localized word string to english + switch ( nDocLang ) + { + case LANGUAGE_FRENCH: + if ( ( nChar == 'a' || nChar == 'A' ) && IsNotAM(rParams, nI) ) + rParams.SetChar(nI, 'Y'); + break; + default: + ; + } + if (nChar == '/') + { + // MM We have to escape '/' in case it's used as a char + rParams.Replace(nI, 1, CREATE_CONST_ASC("\\/")); + nI++; + nLen++; + } + + // Deal with language differences in date format expression. + // Should be made with i18n framework. + // The list of the mappings and of those "special" locales is to be found at: + // http://l10n.openoffice.org/i18n_framework/LocaleData.html + if ( !bForceJapanese && !bForceNatNum ) + { + // Convert to the localized equivalent for OOo + switch ( rLang ) + { + case LANGUAGE_FINNISH: + { + if (nChar == 'y' || nChar == 'Y') + rParams.SetChar (nI, 'V'); + else if (nChar == 'm' || nChar == 'M') + rParams.SetChar (nI, 'K'); + else if (nChar == 'd' || nChar == 'D') + rParams.SetChar (nI, 'P'); + else if (nChar == 'h' || nChar == 'H') + rParams.SetChar (nI, 'T'); + } + break; + case LANGUAGE_DANISH: + case LANGUAGE_NORWEGIAN: + case LANGUAGE_NORWEGIAN_BOKMAL: + case LANGUAGE_NORWEGIAN_NYNORSK: + case LANGUAGE_SWEDISH: + case LANGUAGE_SWEDISH_FINLAND: + { + if (nChar == 'h' || nChar == 'H') + rParams.SetChar (nI, 'T'); + } + break; + case LANGUAGE_PORTUGUESE: + case LANGUAGE_PORTUGUESE_BRAZILIAN: + case LANGUAGE_SPANISH_MODERN: + case LANGUAGE_SPANISH_DATED: + case LANGUAGE_SPANISH_MEXICAN: + case LANGUAGE_SPANISH_GUATEMALA: + case LANGUAGE_SPANISH_COSTARICA: + case LANGUAGE_SPANISH_PANAMA: + case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC: + case LANGUAGE_SPANISH_VENEZUELA: + case LANGUAGE_SPANISH_COLOMBIA: + case LANGUAGE_SPANISH_PERU: + case LANGUAGE_SPANISH_ARGENTINA: + case LANGUAGE_SPANISH_ECUADOR: + case LANGUAGE_SPANISH_CHILE: + case LANGUAGE_SPANISH_URUGUAY: + case LANGUAGE_SPANISH_PARAGUAY: + case LANGUAGE_SPANISH_BOLIVIA: + case LANGUAGE_SPANISH_EL_SALVADOR: + case LANGUAGE_SPANISH_HONDURAS: + case LANGUAGE_SPANISH_NICARAGUA: + case LANGUAGE_SPANISH_PUERTO_RICO: + { + if (nChar == 'a' || nChar == 'A') + rParams.SetChar (nI, 'O'); + else if (nChar == 'y' || nChar == 'Y') + rParams.SetChar (nI, 'A'); + } + break; + case LANGUAGE_DUTCH: + case LANGUAGE_DUTCH_BELGIAN: + { + if (nChar == 'y' || nChar == 'Y') + rParams.SetChar (nI, 'J'); + else if (nChar == 'u' || nChar == 'U') + rParams.SetChar (nI, 'H'); + } + break; + case LANGUAGE_ITALIAN: + case LANGUAGE_ITALIAN_SWISS: + { + if (nChar == 'a' || nChar == 'A') + rParams.SetChar (nI, 'O'); + else if (nChar == 'g' || nChar == 'G') + rParams.SetChar (nI, 'X'); + else if (nChar == 'y' || nChar == 'Y') + rParams.SetChar(nI, 'A'); + else if (nChar == 'd' || nChar == 'D') + rParams.SetChar (nI, 'G'); + } + break; + case LANGUAGE_GERMAN: + case LANGUAGE_GERMAN_SWISS: + case LANGUAGE_GERMAN_AUSTRIAN: + case LANGUAGE_GERMAN_LUXEMBOURG: + case LANGUAGE_GERMAN_LIECHTENSTEIN: + { + if (nChar == 'y' || nChar == 'Y') + rParams.SetChar (nI, 'J'); + else if (nChar == 'd' || nChar == 'D') + rParams.SetChar (nI, 'T'); + } + break; + case LANGUAGE_FRENCH: + case LANGUAGE_FRENCH_BELGIAN: + case LANGUAGE_FRENCH_CANADIAN: + case LANGUAGE_FRENCH_SWISS: + case LANGUAGE_FRENCH_LUXEMBOURG: + case LANGUAGE_FRENCH_MONACO: + { + if (nChar == 'y' || nChar == 'Y' || nChar == 'a') + rParams.SetChar (nI, 'A'); + else if (nChar == 'd' || nChar == 'D' || nChar == 'j') + rParams.SetChar (nI, 'J'); + } + break; + default: + { + ; // Nothing + } + } + } + } + ++nI; + } + + if (bForceNatNum) + bForceJapanese = true; + + if (bForceJapanese) + rLang = LANGUAGE_JAPANESE; + + if (bForceNatNum) + rParams.Insert(CREATE_CONST_ASC("[NatNum1][$-411]"),0); + + if (bHijri) + rParams.Insert(CREATE_CONST_ASC("[~hijri]"), 0); + + pFormatter->PutEntry(rParams, nCheckPos, nType, nKey, rLang); + + return nKey; + } + + bool IsNotAM(String& rParams, xub_StrLen nPos) + { + return ( + (nPos == rParams.Len() - 1) || + ( + (rParams.GetChar(nPos+1) != 'M') && + (rParams.GetChar(nPos+1) != 'm') + ) + ); + } + + void SwapQuotesInField(String &rFmt) + { + //Swap unescaped " and ' with ' and " + xub_StrLen nLen = rFmt.Len(); + for (xub_StrLen nI = 0; nI < nLen; ++nI) + { + if ((rFmt.GetChar(nI) == '\"') && (!nI || rFmt.GetChar(nI-1) != '\\')) + rFmt.SetChar(nI, '\''); + else if ((rFmt.GetChar(nI) == '\'') && (!nI || rFmt.GetChar(nI-1) != '\\')) + rFmt.SetChar(nI, '\"'); + } + } + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |