LibreOffice Module xmloff (master)  1
XMLTextListBlockContext.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <com/sun/star/container/XIndexReplace.hpp>
21 #include <com/sun/star/style/XStyle.hpp>
22 #include <com/sun/star/beans/XPropertySet.hpp>
23 #include <xmloff/xmlimp.hxx>
24 #include <xmloff/namespacemap.hxx>
25 #include <xmloff/xmlnamespace.hxx>
26 #include <xmloff/xmltoken.hxx>
29 #include <txtlists.hxx>
30 #include <sal/log.hxx>
31 
32 
33 using namespace ::com::sun::star;
34 using namespace ::com::sun::star::uno;
35 using namespace ::com::sun::star::container;
36 using namespace ::com::sun::star::style;
37 using namespace ::com::sun::star::beans;
38 using namespace ::xmloff::token;
39 
40 
41 // OD 2008-05-07 #refactorlists#
42 // add optional parameter <bRestartNumberingAtSubList> and its handling
44  SvXMLImport& rImport,
45  XMLTextImportHelper& rTxtImp,
46  const Reference< xml::sax::XFastAttributeList > & xAttrList,
47  const bool bRestartNumberingAtSubList )
48 : SvXMLImportContext( rImport )
49 , mrTxtImport( rTxtImp )
50 , msListStyleName()
51 , mxParentListBlock( )
52 , mnLevel( 0 )
53 , mbRestartNumbering( false )
54 , mbSetDefaults( false )
55 , msListId()
56 , msContinueListId()
57 {
58  static const char s_PropNameDefaultListId[] = "DefaultListId";
59  {
60  // get the parent list block context (if any); this is a bit ugly...
61  XMLTextListBlockContext * pLB(nullptr);
62  XMLTextListItemContext * pLI(nullptr);
63  XMLNumberedParaContext * pNP(nullptr);
64  rTxtImp.GetTextListHelper().ListContextTop(pLB, pLI, pNP);
65  mxParentListBlock = pLB;
66  }
67  // Inherit style name from parent list, as well as the flags whether
68  // numbering must be restarted and formats have to be created.
69  OUString sParentListStyleName;
70  if( mxParentListBlock.is() )
71  {
72  XMLTextListBlockContext *pParent = mxParentListBlock.get();
73  msListStyleName = pParent->msListStyleName;
74  sParentListStyleName = msListStyleName;
75  mxNumRules = pParent->GetNumRules();
76  mnLevel = pParent->GetLevel() + 1;
77  mbRestartNumbering = pParent->IsRestartNumbering() ||
78  bRestartNumberingAtSubList;
79  mbSetDefaults = pParent->mbSetDefaults;
80  msListId = pParent->GetListId();
81  msContinueListId = pParent->GetContinueListId();
82  }
83 
84  bool bIsContinueNumberingAttributePresent( false );
85  for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
86  {
87  OUString sValue = aIter.toString();
88  switch( aIter.getToken() )
89  {
90  case XML_ELEMENT(XML, XML_ID):
91 //FIXME: there is no UNO API for lists
92  // xml:id is also the list ID (#i92221#)
93  if ( mnLevel == 0 ) // root <list> element
94  {
95  msListId = sValue;
96  }
97  break;
99  mbRestartNumbering = !IsXMLToken(sValue, XML_TRUE);
100  bIsContinueNumberingAttributePresent = true;
101  break;
102  case XML_ELEMENT(TEXT, XML_STYLE_NAME):
103  msListStyleName = sValue;
104  break;
105  case XML_ELEMENT(TEXT, XML_CONTINUE_LIST):
106  if ( mnLevel == 0 ) // root <list> element
107  {
108  msContinueListId = sValue;
109  }
110  break;
111  default:
112  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
113  }
114  }
115 
116  // Remember this list block.
117  mrTxtImport.GetTextListHelper().PushListContext( this );
118 
119  mxNumRules = XMLTextListsHelper::MakeNumRule(GetImport(), mxNumRules,
120  sParentListStyleName, msListStyleName,
121  mnLevel, &mbRestartNumbering, &mbSetDefaults );
122  if( !mxNumRules.is() )
123  return;
124 
125  if ( mnLevel != 0 ) // root <list> element
126  return;
127 
128  XMLTextListsHelper& rTextListsHelper( mrTxtImport.GetTextListHelper() );
129  // Inconsistent behavior regarding lists (#i92811#)
130  OUString sListStyleDefaultListId;
131  {
132  uno::Reference< beans::XPropertySet > xNumRuleProps( mxNumRules, UNO_QUERY );
133  if ( xNumRuleProps.is() )
134  {
135  uno::Reference< beans::XPropertySetInfo > xNumRulePropSetInfo(
136  xNumRuleProps->getPropertySetInfo());
137  if (xNumRulePropSetInfo.is() &&
138  xNumRulePropSetInfo->hasPropertyByName(
139  s_PropNameDefaultListId))
140  {
141  xNumRuleProps->getPropertyValue(s_PropNameDefaultListId)
142  >>= sListStyleDefaultListId;
143  SAL_WARN_IF( sListStyleDefaultListId.isEmpty(), "xmloff",
144  "no default list id found at numbering rules instance. Serious defect." );
145  }
146  }
147  }
148  if ( msListId.isEmpty() ) // no text:id property found
149  {
150  sal_Int32 nUPD( 0 );
151  sal_Int32 nBuild( 0 );
152  const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild );
153  if ( rImport.IsTextDocInOOoFileFormat() ||
154  ( bBuildIdFound && nUPD == 680 ) )
155  {
156  /* handling former documents written by OpenOffice.org:
157  use default list id of numbering rules instance, if existing
158  (#i92811#)
159  */
160  if ( !sListStyleDefaultListId.isEmpty() )
161  {
162  msListId = sListStyleDefaultListId;
163  if ( !bIsContinueNumberingAttributePresent &&
164  !mbRestartNumbering &&
165  rTextListsHelper.IsListProcessed( msListId ) )
166  {
167  mbRestartNumbering = true;
168  }
169  }
170  }
171  if ( msListId.isEmpty() )
172  {
173  // generate a new list id for the list
174  msListId = rTextListsHelper.GenerateNewListId();
175  }
176  }
177 
178  if ( bIsContinueNumberingAttributePresent && !mbRestartNumbering &&
179  msContinueListId.isEmpty() )
180  {
181  const OUString& Last( rTextListsHelper.GetLastProcessedListId() );
182  if ( rTextListsHelper.GetListStyleOfLastProcessedList() == msListStyleName
183  && Last != msListId )
184  {
185  msContinueListId = Last;
186  }
187  }
188 
189  if ( !msContinueListId.isEmpty() )
190  {
191  if ( !rTextListsHelper.IsListProcessed( msContinueListId ) )
192  {
193  msContinueListId.clear();
194  }
195  else
196  {
197  // search continue list chain for master list and
198  // continue the master list.
199  OUString sTmpStr =
200  rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId );
201  while ( !sTmpStr.isEmpty() )
202  {
203  msContinueListId = sTmpStr;
204 
205  sTmpStr =
206  rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId );
207  }
208  }
209  }
210 
211  if ( !rTextListsHelper.IsListProcessed( msListId ) )
212  {
213  // Inconsistent behavior regarding lists (#i92811#)
214  rTextListsHelper.KeepListAsProcessed(
215  msListId, msListStyleName, msContinueListId,
216  sListStyleDefaultListId );
217  }
218 }
219 
220 // OD 2008-05-07 #refactorlists#
221 // add optional parameter <bRestartNumberingAtSubList> and its handling
223  SvXMLImport& rImport,
224  XMLTextImportHelper& rTxtImp,
225  sal_uInt16 nPrfx,
226  const OUString& rLName,
227  const Reference< xml::sax::XAttributeList > & xAttrList,
228  const bool bRestartNumberingAtSubList )
229 : SvXMLImportContext( rImport, nPrfx, rLName )
230 , mrTxtImport( rTxtImp )
231 , msListStyleName()
232 , mxParentListBlock( )
233 , mnLevel( 0 )
234 , mbRestartNumbering( false )
235 , mbSetDefaults( false )
236 , msListId()
237 , msContinueListId()
238 {
239  static const char s_PropNameDefaultListId[] = "DefaultListId";
240  {
241  // get the parent list block context (if any); this is a bit ugly...
242  XMLTextListBlockContext * pLB(nullptr);
243  XMLTextListItemContext * pLI(nullptr);
244  XMLNumberedParaContext * pNP(nullptr);
245  rTxtImp.GetTextListHelper().ListContextTop(pLB, pLI, pNP);
246  mxParentListBlock = pLB;
247  }
248  // Inherit style name from parent list, as well as the flags whether
249  // numbering must be restarted and formats have to be created.
250  OUString sParentListStyleName;
251  if( mxParentListBlock.is() )
252  {
253  XMLTextListBlockContext *pParent = mxParentListBlock.get();
254  msListStyleName = pParent->msListStyleName;
255  sParentListStyleName = msListStyleName;
256  mxNumRules = pParent->GetNumRules();
257  mnLevel = pParent->GetLevel() + 1;
258  mbRestartNumbering = pParent->IsRestartNumbering() ||
259  bRestartNumberingAtSubList;
260  mbSetDefaults = pParent->mbSetDefaults;
261  msListId = pParent->GetListId();
262  msContinueListId = pParent->GetContinueListId();
263  }
264 
265  const SvXMLTokenMap& rTokenMap = mrTxtImport.GetTextListBlockAttrTokenMap();
266 
267  bool bIsContinueNumberingAttributePresent( false );
268  sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
269  for( sal_Int16 i=0; i < nAttrCount; i++ )
270  {
271  const OUString& rAttrName = xAttrList->getNameByIndex( i );
272  const OUString& rValue = xAttrList->getValueByIndex( i );
273 
274  OUString aLocalName;
275  sal_uInt16 nPrefix =
276  GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
277  &aLocalName );
278  switch( rTokenMap.Get( nPrefix, aLocalName ) )
279  {
281 //FIXME: there is no UNO API for lists
282  // xml:id is also the list ID (#i92221#)
283  if ( mnLevel == 0 ) // root <list> element
284  {
285  msListId = rValue;
286  }
287  break;
289  mbRestartNumbering = !IsXMLToken(rValue, XML_TRUE);
290  bIsContinueNumberingAttributePresent = true;
291  break;
293  msListStyleName = rValue;
294  break;
296  if ( mnLevel == 0 ) // root <list> element
297  {
298  msContinueListId = rValue;
299  }
300  break;
301  }
302  }
303 
304  // Remember this list block.
305  mrTxtImport.GetTextListHelper().PushListContext( this );
306 
307  mxNumRules = XMLTextListsHelper::MakeNumRule(GetImport(), mxNumRules,
308  sParentListStyleName, msListStyleName,
309  mnLevel, &mbRestartNumbering, &mbSetDefaults );
310  if( !mxNumRules.is() )
311  return;
312 
313  if ( mnLevel != 0 ) // root <list> element
314  return;
315 
316  XMLTextListsHelper& rTextListsHelper( mrTxtImport.GetTextListHelper() );
317  // Inconsistent behavior regarding lists (#i92811#)
318  OUString sListStyleDefaultListId;
319  {
320  uno::Reference< beans::XPropertySet > xNumRuleProps( mxNumRules, UNO_QUERY );
321  if ( xNumRuleProps.is() )
322  {
323  uno::Reference< beans::XPropertySetInfo > xNumRulePropSetInfo(
324  xNumRuleProps->getPropertySetInfo());
325  if (xNumRulePropSetInfo.is() &&
326  xNumRulePropSetInfo->hasPropertyByName(
327  s_PropNameDefaultListId))
328  {
329  xNumRuleProps->getPropertyValue(s_PropNameDefaultListId)
330  >>= sListStyleDefaultListId;
331  SAL_WARN_IF( sListStyleDefaultListId.isEmpty(), "xmloff",
332  "no default list id found at numbering rules instance. Serious defect." );
333  }
334  }
335  }
336  if ( msListId.isEmpty() ) // no text:id property found
337  {
338  sal_Int32 nUPD( 0 );
339  sal_Int32 nBuild( 0 );
340  const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild );
341  if ( rImport.IsTextDocInOOoFileFormat() ||
342  ( bBuildIdFound && nUPD == 680 ) )
343  {
344  /* handling former documents written by OpenOffice.org:
345  use default list id of numbering rules instance, if existing
346  (#i92811#)
347  */
348  if ( !sListStyleDefaultListId.isEmpty() )
349  {
350  msListId = sListStyleDefaultListId;
351  if ( !bIsContinueNumberingAttributePresent &&
352  !mbRestartNumbering &&
353  rTextListsHelper.IsListProcessed( msListId ) )
354  {
355  mbRestartNumbering = true;
356  }
357  }
358  }
359  if ( msListId.isEmpty() )
360  {
361  // generate a new list id for the list
362  msListId = rTextListsHelper.GenerateNewListId();
363  }
364  }
365 
366  if ( bIsContinueNumberingAttributePresent && !mbRestartNumbering &&
367  msContinueListId.isEmpty() )
368  {
369  const OUString& Last( rTextListsHelper.GetLastProcessedListId() );
370  if ( rTextListsHelper.GetListStyleOfLastProcessedList() == msListStyleName
371  && Last != msListId )
372  {
373  msContinueListId = Last;
374  }
375  }
376 
377  if ( !msContinueListId.isEmpty() )
378  {
379  if ( !rTextListsHelper.IsListProcessed( msContinueListId ) )
380  {
381  msContinueListId.clear();
382  }
383  else
384  {
385  // search continue list chain for master list and
386  // continue the master list.
387  OUString sTmpStr =
388  rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId );
389  while ( !sTmpStr.isEmpty() )
390  {
391  msContinueListId = sTmpStr;
392 
393  sTmpStr =
394  rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId );
395  }
396  }
397  }
398 
399  if ( !rTextListsHelper.IsListProcessed( msListId ) )
400  {
401  // Inconsistent behavior regarding lists (#i92811#)
402  rTextListsHelper.KeepListAsProcessed(
403  msListId, msListStyleName, msContinueListId,
404  sListStyleDefaultListId );
405  }
406 }
407 
409 {
410 }
411 
413 {
414  // Numbering has not to be restarted if it has been restarted within
415  // a child list.
417  if( pParent )
418  {
420  }
421 
422  // Restore current list block.
424 
425  // Any paragraph following the list within the same list item must not
426  // be numbered.
428 }
429 
430 css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextListBlockContext::createFastChildContext(
431  sal_Int32 nElement,
432  const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
433 {
434  SvXMLImportContext *pContext = nullptr;
435 
436  bool bHeader = false;
437  switch( nElement )
438  {
440  bHeader = true;
441  [[fallthrough]];
443  pContext = new XMLTextListItemContext( GetImport(), mrTxtImport,
444  xAttrList, bHeader );
445  break;
446  default:
447  XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
448  }
449 
450 
451  return pContext;
452 }
453 
454 
455 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsXMLToken(const OUString &rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3461
const OUString & GetContinueListId() const
sal_Int16 mnLevel
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:59
XMLTextImportHelper & mrTxtImport
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
const OUString & GetListId() const
css::uno::Any const & rValue
Definition: ImageStyle.hxx:38
#define XMLOFF_WARN_UNKNOWN(area, rIter)
Definition: xmlictxt.hxx:131
void ListContextTop(XMLTextListBlockContext *&o_pListBlockContext, XMLTextListItemContext *&o_pListItemContext, XMLNumberedParaContext *&o_pNumberedParagraphContext)
peek at the top of the list context stack
Definition: txtlists.cxx:74
static css::uno::Reference< css::container::XIndexReplace > MakeNumRule(SvXMLImport &i_rImport, const css::uno::Reference< css::container::XIndexReplace > &i_xNumRule, const OUString &i_ParentStyleName, const OUString &i_StyleName, sal_Int16 &io_rLevel, bool *o_pRestartNumbering=nullptr, bool *io_pSetDefaults=nullptr)
Creates a NumRule from given style-name.
Definition: txtlists.cxx:402
virtual ~XMLTextListBlockContext() override
int i
bool IsTextDocInOOoFileFormat() const
Definition: xmlimp.cxx:1878
virtual void SAL_CALL endFastElement(sal_Int32 nElement) override
endFastElement is called before a context will be destructed, but after an elements context has been ...
sal_uInt16 Get(sal_uInt16 nPrefix, const OUString &rLName) const
Definition: xmltkmap.cxx:99
XMLTextListBlockContext(SvXMLImport &rImport, XMLTextImportHelper &rTxtImp, sal_uInt16 nPrfx, const OUString &rLName, const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList, const bool bRestartNumberingAtSubList=false)
rtl::Reference< XMLTextListBlockContext > mxParentListBlock
XMLTextListsHelper & GetTextListHelper()
Definition: txtimp.cxx:664
This class deliberately does not support XWeak, to improve performance when loading large documents...
Definition: xmlictxt.hxx:45
#define SAL_WARN_IF(condition, area, stream)
void SetListItem(XMLTextListItemContext *pListItem)
set list item on top of the list context stack
Definition: txtlists.cxx:89
Handling of tokens in XML:
void PopListContext()
pop the list context stack
Definition: txtlists.cxx:67
#define XML_ELEMENT(prefix, name)
Definition: xmlimp.hxx:94
const css::uno::Reference< css::container::XIndexReplace > & GetNumRules() const
#define XMLOFF_WARN_UNKNOWN_ELEMENT(area, token)
Definition: xmlictxt.hxx:137
if(!pCandidateA->getEnd().equal(pCandidateB->getStart()))
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
TEXT