diff options
Diffstat (limited to 'sw/source/filter/html/htmlnumwriter.cxx')
-rw-r--r-- | sw/source/filter/html/htmlnumwriter.cxx | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/sw/source/filter/html/htmlnumwriter.cxx b/sw/source/filter/html/htmlnumwriter.cxx new file mode 100644 index 0000000000..046747754a --- /dev/null +++ b/sw/source/filter/html/htmlnumwriter.cxx @@ -0,0 +1,336 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <svtools/htmlout.hxx> +#include <numrule.hxx> +#include <doc.hxx> +#include <ndtxt.hxx> +#include <pam.hxx> + +#include "htmlnum.hxx" +#include "wrthtml.hxx" + +#include <osl/diagnose.h> + +using namespace css; + + +void SwHTMLWriter::FillNextNumInfo() +{ + m_pNextNumRuleInfo = nullptr; + + SwNodeOffset nPos = m_pCurrentPam->GetPoint()->GetNodeIndex() + 1; + + bool bTable = false; + do + { + const SwNode* pNd = m_pDoc->GetNodes()[nPos]; + if( pNd->IsTextNode() ) + { + m_pNextNumRuleInfo.reset( new SwHTMLNumRuleInfo( *pNd->GetTextNode() ) ); + + // Before a table we keep the old level if the same numbering is + // continued after the table and no new numbering is started. + // The table will get the indentation that corresponds to its + // numbering level during import. + if( bTable && + m_pNextNumRuleInfo->GetNumRule()==GetNumInfo().GetNumRule() && + !m_pNextNumRuleInfo->IsRestart(GetNumInfo()) ) + { + m_pNextNumRuleInfo->SetDepth( GetNumInfo().GetDepth() ); + } + } + else if( pNd->IsTableNode() ) + { + // A table is skipped so the node after table is viewed. + nPos = pNd->EndOfSectionIndex() + 1; + bTable = true; + } + else + { + // In all other case the numbering is over. + m_pNextNumRuleInfo.reset(new SwHTMLNumRuleInfo); + } + } + while( !m_pNextNumRuleInfo ); +} + +void SwHTMLWriter::ClearNextNumInfo() +{ + m_pNextNumRuleInfo.reset(); +} + +void SwHTMLWriter::SetNextNumInfo( std::unique_ptr<SwHTMLNumRuleInfo> pNxt ) +{ + m_pNextNumRuleInfo = std::move(pNxt); +} + +SwHTMLWriter& OutHTML_NumberBulletListStart( SwHTMLWriter& rWrt, + const SwHTMLNumRuleInfo& rInfo ) +{ + SwHTMLNumRuleInfo& rPrevInfo = rWrt.GetNumInfo(); + bool bSameRule = rPrevInfo.GetNumRule() == rInfo.GetNumRule(); + if( bSameRule && rPrevInfo.GetDepth() >= rInfo.GetDepth() && + !rInfo.IsRestart(rPrevInfo) ) + { + return rWrt; + } + + bool bStartValue = false; + if( !bSameRule && rInfo.GetDepth() ) + { + OUString aName( rInfo.GetNumRule()->GetName() ); + if( 0 != rWrt.m_aNumRuleNames.count( aName ) ) + { + // The rule has been applied before + sal_Int16 eType = rInfo.GetNumRule() + ->Get( rInfo.GetDepth()-1 ).GetNumberingType(); + if( SVX_NUM_CHAR_SPECIAL != eType && SVX_NUM_BITMAP != eType ) + { + // If it's a numbering rule, the current number should be + // exported as start value, but only if there are no nodes + // within the numbering that have a lower level + bStartValue = true; + if( rInfo.GetDepth() > 1 ) + { + SwNodeOffset nPos = + rWrt.m_pCurrentPam->GetPoint()->GetNodeIndex() + 1; + do + { + const SwNode* pNd = rWrt.m_pDoc->GetNodes()[nPos]; + if( pNd->IsTextNode() ) + { + const SwTextNode *pTextNd = pNd->GetTextNode(); + if( !pTextNd->GetNumRule() ) + { + // node isn't numbered => check completed + break; + } + + OSL_ENSURE(! pTextNd->IsOutline(), + "outline not expected"); + + if( pTextNd->GetActualListLevel() + 1 < + rInfo.GetDepth() ) + { + if (rPrevInfo.GetDepth() == 0) + // previous node had no numbering => write start value + bStartValue = true; + else + // node is numbered, but level is lower + bStartValue = false; + // => check completed + break; + } + nPos++; + } + else if( pNd->IsTableNode() ) + { + // skip table + nPos = pNd->EndOfSectionIndex() + 1; + } + else + { + // end node or sections start node -> check + // completed + break; + } + } + while( true ); + } + } + } + else + { + rWrt.m_aNumRuleNames.insert( aName ); + } + } + + OSL_ENSURE( rWrt.m_nLastParaToken == HtmlTokenId::NONE, + "<PRE> was not closed before <OL>." ); + sal_uInt16 nPrevDepth = + (bSameRule && !rInfo.IsRestart(rPrevInfo)) ? rPrevInfo.GetDepth() : 0; + + for( sal_uInt16 i=nPrevDepth; i<rInfo.GetDepth(); i++ ) + { + rWrt.OutNewLine(); // <OL>/<UL> in a new row + + rWrt.m_aBulletGrfs[i].clear(); + OString sOut = "<" + rWrt.GetNamespace(); + if (rWrt.mbXHTML && i != nPrevDepth) + { + // for all skipped sublevels, add a li + sOut += OOO_STRING_SVTOOLS_HTML_li "><" + rWrt.GetNamespace(); + } + const SwNumFormat& rNumFormat = rInfo.GetNumRule()->Get( i ); + sal_Int16 eType = rNumFormat.GetNumberingType(); + if( SVX_NUM_CHAR_SPECIAL == eType ) + { + // unordered list: <UL> + sOut += OOO_STRING_SVTOOLS_HTML_unorderlist; + + // determine the type by the bullet character + const char *pStr = nullptr; + switch( rNumFormat.GetBulletChar() ) + { + case HTML_BULLETCHAR_DISC: + pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_disc; + break; + case HTML_BULLETCHAR_CIRCLE: + pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_circle; + break; + case HTML_BULLETCHAR_SQUARE: + pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_square; + break; + } + + if( pStr ) + { + sOut += OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_type "=\"") + pStr + "\""; + } + } + else if( SVX_NUM_BITMAP == eType ) + { + // Unordered list: <UL> + sOut += OOO_STRING_SVTOOLS_HTML_unorderlist; + } + else + { + // Ordered list: <OL> + sOut += OOO_STRING_SVTOOLS_HTML_orderlist; + + if (!rWrt.mbReqIF) // No 'type' nor 'start' attribute in ReqIF + { + // determine the type by the format + char cType = 0; + switch (eType) + { + case SVX_NUM_CHARS_UPPER_LETTER: + case SVX_NUM_CHARS_UPPER_LETTER_N: + cType = 'A'; + break; + case SVX_NUM_CHARS_LOWER_LETTER: + case SVX_NUM_CHARS_LOWER_LETTER_N: + cType = 'a'; + break; + case SVX_NUM_ROMAN_UPPER: + cType = 'I'; + break; + case SVX_NUM_ROMAN_LOWER: + cType = 'i'; + break; + } + if( cType ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_type "=\"" + OStringChar(cType) + "\""; + } + + sal_uInt16 nStartVal = rNumFormat.GetStart(); + if( bStartValue && 1 == nStartVal && i == rInfo.GetDepth()-1 ) + { + if ( rWrt.m_pCurrentPam->GetPointNode().GetTextNode()->GetNum() ) + { + nStartVal = static_cast< sal_uInt16 >( rWrt.m_pCurrentPam->GetPointNode() + .GetTextNode()->GetNumberVector()[i] ); + } + else + { + OSL_FAIL( "<OutHTML_NumberBulletListStart(..) - text node has no number." ); + } + } + if( nStartVal != 1 ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_start "=\"" + OString::number(static_cast<sal_Int32>(nStartVal)) + "\""; + } + } + } + + rWrt.Strm().WriteOString(sOut); + + if (eType == SVX_NUM_BITMAP) + OutHTML_BulletImage(rWrt, nullptr, rNumFormat.GetBrush(), rWrt.m_aBulletGrfs[i]); + + if( rWrt.m_bCfgOutStyles ) + OutCSS1_NumberBulletListStyleOpt( rWrt, *rInfo.GetNumRule(), static_cast<sal_uInt8>(i) ); + + rWrt.Strm().WriteChar( '>' ); + + rWrt.IncIndentLevel(); // indent content of <OL> + } + + return rWrt; +} + +SwHTMLWriter& OutHTML_NumberBulletListEnd( SwHTMLWriter& rWrt, + const SwHTMLNumRuleInfo& rNextInfo ) +{ + SwHTMLNumRuleInfo& rInfo = rWrt.GetNumInfo(); + bool bSameRule = rNextInfo.GetNumRule() == rInfo.GetNumRule(); + bool bListEnd = !bSameRule || rNextInfo.GetDepth() < rInfo.GetDepth() || rNextInfo.IsRestart(rInfo); + bool bNextIsSubitem = !bListEnd && rNextInfo.GetDepth() > rInfo.GetDepth(); + + // XHTML </li> for the list item content, if there is an open <li>. + if (bListEnd || (!bNextIsSubitem && rNextInfo.IsNumbered())) + { + HTMLOutFuncs::Out_AsciiTag( + rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_li), + false); + } + + if (!bListEnd) + { + return rWrt; + } + + OSL_ENSURE( rWrt.m_nLastParaToken == HtmlTokenId::NONE, + "<PRE> was not closed before </OL>." ); + sal_uInt16 nNextDepth = + (bSameRule && !rNextInfo.IsRestart(rInfo)) ? rNextInfo.GetDepth() : 0; + + // MIB 23.7.97: We must loop backwards, to get the right order of </OL>/</UL> + for( sal_uInt16 i=rInfo.GetDepth(); i>nNextDepth; i-- ) + { + rWrt.DecIndentLevel(); // indent content of <OL> + if (rWrt.IsLFPossible()) + rWrt.OutNewLine(); // </OL>/</UL> in a new line + + // a list is started or ended: + sal_Int16 eType = rInfo.GetNumRule()->Get( i-1 ).GetNumberingType(); + OString aTag; + if( SVX_NUM_CHAR_SPECIAL == eType || SVX_NUM_BITMAP == eType) + aTag = OOO_STRING_SVTOOLS_HTML_unorderlist ""_ostr; + else + aTag = OOO_STRING_SVTOOLS_HTML_orderlist ""_ostr; + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + aTag), false ); + if (rWrt.mbXHTML && (i != nNextDepth + 1 || (i != 1 && rNextInfo.IsNumbered()))) + { + // for all skipped sublevels, close a li + HTMLOutFuncs::Out_AsciiTag( + rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_li), + /*bOn=*/false); + } + rWrt.SetLFPossible(true); + } + + return rWrt; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |