/src/libreoffice/xmloff/source/text/XMLTextListBlockContext.cxx
Line | Count | Source |
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/beans/XPropertySet.hpp> |
21 | | #include <xmloff/xmlimp.hxx> |
22 | | #include <xmloff/xmlnamespace.hxx> |
23 | | #include <xmloff/xmltoken.hxx> |
24 | | #include "XMLTextListItemContext.hxx" |
25 | | #include "XMLTextListBlockContext.hxx" |
26 | | #include <txtlists.hxx> |
27 | | #include <sal/log.hxx> |
28 | | |
29 | | |
30 | | using namespace ::com::sun::star; |
31 | | using namespace ::com::sun::star::uno; |
32 | | using namespace ::com::sun::star::beans; |
33 | | using namespace ::xmloff::token; |
34 | | |
35 | | |
36 | | // OD 2008-05-07 #refactorlists# |
37 | | // add optional parameter <bRestartNumberingAtSubList> and its handling |
38 | | XMLTextListBlockContext::XMLTextListBlockContext( |
39 | | SvXMLImport& rImport, |
40 | | XMLTextImportHelper& rTxtImp, |
41 | | const Reference< xml::sax::XFastAttributeList > & xAttrList, |
42 | | const bool bRestartNumberingAtSubList ) |
43 | 93.7k | : SvXMLImportContext( rImport ) |
44 | 93.7k | , mrTxtImport( rTxtImp ) |
45 | 93.7k | , mnLevel( 0 ) |
46 | 93.7k | , mbRestartNumbering( false ) |
47 | 93.7k | , mbSetDefaults( false ) |
48 | 93.7k | { |
49 | 93.7k | static constexpr OUString s_PropNameDefaultListId = u"DefaultListId"_ustr; |
50 | 93.7k | { |
51 | | // get the parent list block context (if any); this is a bit ugly... |
52 | 93.7k | XMLTextListBlockContext * pLB(nullptr); |
53 | 93.7k | XMLTextListItemContext * pLI(nullptr); |
54 | 93.7k | XMLNumberedParaContext * pNP(nullptr); |
55 | 93.7k | rTxtImp.GetTextListHelper().ListContextTop(pLB, pLI, pNP); |
56 | 93.7k | mxParentListBlock = pLB; |
57 | 93.7k | } |
58 | | // Inherit style name from parent list, as well as the flags whether |
59 | | // numbering must be restarted and formats have to be created. |
60 | 93.7k | OUString sParentListStyleName; |
61 | 93.7k | if( mxParentListBlock.is() ) |
62 | 0 | { |
63 | 0 | XMLTextListBlockContext *pParent = mxParentListBlock.get(); |
64 | 0 | msListStyleName = pParent->msListStyleName; |
65 | 0 | sParentListStyleName = msListStyleName; |
66 | 0 | mxNumRules = pParent->GetNumRules(); |
67 | 0 | mnLevel = pParent->GetLevel() + 1; |
68 | 0 | mbRestartNumbering = pParent->IsRestartNumbering() || |
69 | 0 | bRestartNumberingAtSubList; |
70 | 0 | mbSetDefaults = pParent->mbSetDefaults; |
71 | 0 | msListId = pParent->GetListId(); |
72 | 0 | msContinueListId = pParent->GetContinueListId(); |
73 | 0 | } |
74 | | |
75 | 93.7k | bool bIsContinueNumberingAttributePresent( false ); |
76 | 93.7k | for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) |
77 | 1 | { |
78 | 1 | switch( aIter.getToken() ) |
79 | 1 | { |
80 | 0 | case XML_ELEMENT(XML, XML_ID): |
81 | | //FIXME: there is no UNO API for lists |
82 | | // xml:id is also the list ID (#i92221#) |
83 | 0 | if ( mnLevel == 0 ) // root <list> element |
84 | 0 | { |
85 | 0 | msListId = aIter.toString(); |
86 | 0 | } |
87 | 0 | break; |
88 | 0 | case XML_ELEMENT(TEXT, XML_CONTINUE_NUMBERING): |
89 | 0 | mbRestartNumbering = !IsXMLToken(aIter, XML_TRUE); |
90 | 0 | bIsContinueNumberingAttributePresent = true; |
91 | 0 | break; |
92 | 0 | case XML_ELEMENT(TEXT, XML_STYLE_NAME): |
93 | 0 | msListStyleName = aIter.toString(); |
94 | 0 | break; |
95 | 0 | case XML_ELEMENT(TEXT, XML_CONTINUE_LIST): |
96 | 0 | if ( mnLevel == 0 ) // root <list> element |
97 | 0 | { |
98 | 0 | msContinueListId = aIter.toString(); |
99 | 0 | } |
100 | 0 | break; |
101 | 1 | default: |
102 | 1 | XMLOFF_WARN_UNKNOWN("xmloff", aIter); |
103 | 1 | } |
104 | 1 | } |
105 | | |
106 | | // Remember this list block. |
107 | 93.7k | mrTxtImport.GetTextListHelper().PushListContext( this ); |
108 | 93.7k | try |
109 | 93.7k | { |
110 | 93.7k | mxNumRules = XMLTextListsHelper::MakeNumRule(GetImport(), mxNumRules, |
111 | 93.7k | sParentListStyleName, msListStyleName, |
112 | 93.7k | mnLevel, &mbRestartNumbering, &mbSetDefaults ); |
113 | 93.7k | if( !mxNumRules.is() ) |
114 | 0 | return; |
115 | | |
116 | 93.7k | if ( mnLevel != 0 ) // root <list> element |
117 | 0 | return; |
118 | | |
119 | 93.7k | XMLTextListsHelper& rTextListsHelper( mrTxtImport.GetTextListHelper() ); |
120 | | // Inconsistent behavior regarding lists (#i92811#) |
121 | 93.7k | OUString sListStyleDefaultListId; |
122 | 93.7k | { |
123 | 93.7k | uno::Reference< beans::XPropertySet > xNumRuleProps( mxNumRules, UNO_QUERY ); |
124 | 93.7k | if ( xNumRuleProps.is() ) |
125 | 90.8k | { |
126 | 90.8k | uno::Reference< beans::XPropertySetInfo > xNumRulePropSetInfo( |
127 | 90.8k | xNumRuleProps->getPropertySetInfo()); |
128 | 90.8k | if (xNumRulePropSetInfo.is() && |
129 | 90.8k | xNumRulePropSetInfo->hasPropertyByName( |
130 | 90.8k | s_PropNameDefaultListId)) |
131 | 90.8k | { |
132 | 90.8k | xNumRuleProps->getPropertyValue(s_PropNameDefaultListId) |
133 | 90.8k | >>= sListStyleDefaultListId; |
134 | 90.8k | SAL_WARN_IF( sListStyleDefaultListId.isEmpty(), "xmloff", |
135 | 90.8k | "no default list id found at numbering rules instance. Serious defect." ); |
136 | 90.8k | } |
137 | 90.8k | } |
138 | 93.7k | } |
139 | 93.7k | if ( msListId.isEmpty() ) // no text:id property found |
140 | 93.7k | { |
141 | 93.7k | sal_Int32 nUPD( 0 ); |
142 | 93.7k | sal_Int32 nBuild( 0 ); |
143 | 93.7k | const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild ); |
144 | 93.7k | if ( rImport.IsTextDocInOOoFileFormat() || |
145 | 93.7k | ( bBuildIdFound && nUPD == 680 ) ) |
146 | 0 | { |
147 | | /* handling former documents written by OpenOffice.org: |
148 | | use default list id of numbering rules instance, if existing |
149 | | (#i92811#) |
150 | | */ |
151 | 0 | if ( !sListStyleDefaultListId.isEmpty() ) |
152 | 0 | { |
153 | 0 | msListId = sListStyleDefaultListId; |
154 | 0 | if ( !bIsContinueNumberingAttributePresent && |
155 | 0 | !mbRestartNumbering && |
156 | 0 | rTextListsHelper.IsListProcessed( msListId ) ) |
157 | 0 | { |
158 | 0 | mbRestartNumbering = true; |
159 | 0 | } |
160 | 0 | } |
161 | 0 | } |
162 | 93.7k | if ( msListId.isEmpty() ) |
163 | 93.7k | { |
164 | | // generate a new list id for the list |
165 | 93.7k | msListId = rTextListsHelper.GenerateNewListId(); |
166 | 93.7k | } |
167 | 93.7k | } |
168 | | |
169 | 93.7k | if ( bIsContinueNumberingAttributePresent && !mbRestartNumbering && |
170 | 0 | msContinueListId.isEmpty() ) |
171 | 0 | { |
172 | 0 | const OUString& Last( rTextListsHelper.GetLastProcessedListId() ); |
173 | 0 | if ( rTextListsHelper.GetListStyleOfLastProcessedList() == msListStyleName |
174 | 0 | && Last != msListId ) |
175 | 0 | { |
176 | 0 | msContinueListId = Last; |
177 | 0 | } |
178 | 0 | } |
179 | | |
180 | 93.7k | bool bContinueNumbering = bIsContinueNumberingAttributePresent && !mbRestartNumbering; |
181 | 93.7k | if (msContinueListId.isEmpty() && bContinueNumbering && GetImport().IsMSO()) |
182 | 0 | { |
183 | | // No "continue list" id, but continue numbering was requested. Connect to the last list of |
184 | | // the same list style in the Word case, even if there was a different list in the meantime. |
185 | 0 | msContinueListId = rTextListsHelper.GetLastIdOfStyleName(msListStyleName); |
186 | 0 | } |
187 | | |
188 | 93.7k | if ( !msContinueListId.isEmpty() ) |
189 | 0 | { |
190 | 0 | if ( !rTextListsHelper.IsListProcessed( msContinueListId ) ) |
191 | 0 | { |
192 | 0 | msContinueListId.clear(); |
193 | 0 | } |
194 | 0 | else |
195 | 0 | { |
196 | | // search continue list chain for master list and |
197 | | // continue the master list. |
198 | 0 | OUString sTmpStr = |
199 | 0 | rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId ); |
200 | 0 | while ( !sTmpStr.isEmpty() ) |
201 | 0 | { |
202 | 0 | msContinueListId = sTmpStr; |
203 | |
|
204 | 0 | sTmpStr = |
205 | 0 | rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId ); |
206 | 0 | } |
207 | 0 | } |
208 | 0 | } |
209 | | |
210 | 93.7k | if ( !rTextListsHelper.IsListProcessed( msListId ) ) |
211 | 93.7k | { |
212 | | // Inconsistent behavior regarding lists (#i92811#) |
213 | 93.7k | rTextListsHelper.KeepListAsProcessed( |
214 | 93.7k | msListId, msListStyleName, msContinueListId, |
215 | 93.7k | sListStyleDefaultListId ); |
216 | 93.7k | } |
217 | 93.7k | } |
218 | 93.7k | catch (uno::Exception&) |
219 | 93.7k | { |
220 | | // pop ourselves if anything goes wrong to avoid use-after-free |
221 | 0 | rTxtImp.GetTextListHelper().PopListContext(); |
222 | 0 | throw; |
223 | 0 | } |
224 | 93.7k | } |
225 | | |
226 | | XMLTextListBlockContext::~XMLTextListBlockContext() |
227 | 93.7k | { |
228 | 93.7k | } |
229 | | |
230 | | void XMLTextListBlockContext::endFastElement(sal_Int32 ) |
231 | 93.6k | { |
232 | | // Numbering has not to be restarted if it has been restarted within |
233 | | // a child list. |
234 | 93.6k | XMLTextListBlockContext *pParent = mxParentListBlock.get(); |
235 | 93.6k | if( pParent ) |
236 | 0 | { |
237 | 0 | pParent->mbRestartNumbering = mbRestartNumbering; |
238 | 0 | } |
239 | | |
240 | | // Restore current list block. |
241 | 93.6k | mrTxtImport.GetTextListHelper().PopListContext(); |
242 | | |
243 | | // Any paragraph following the list within the same list item must not |
244 | | // be numbered. |
245 | 93.6k | mrTxtImport.GetTextListHelper().SetListItem( nullptr ); |
246 | 93.6k | } |
247 | | |
248 | | css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextListBlockContext::createFastChildContext( |
249 | | sal_Int32 nElement, |
250 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) |
251 | 462 | { |
252 | 462 | SvXMLImportContext *pContext = nullptr; |
253 | | |
254 | 462 | bool bHeader = false; |
255 | 462 | switch( nElement ) |
256 | 462 | { |
257 | 0 | case XML_ELEMENT(TEXT, XML_LIST_HEADER): |
258 | 0 | bHeader = true; |
259 | 0 | [[fallthrough]]; |
260 | 0 | case XML_ELEMENT(TEXT, XML_LIST_ITEM): |
261 | 0 | pContext = new XMLTextListItemContext( GetImport(), mrTxtImport, |
262 | 0 | xAttrList, bHeader ); |
263 | 0 | break; |
264 | 462 | default: |
265 | 462 | XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); |
266 | 462 | } |
267 | | |
268 | 462 | return pContext; |
269 | 462 | } |
270 | | |
271 | | |
272 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |