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 <drawingml/chart/datasourcecontext.hxx>
21
22 #include <oox/drawingml/chart/datasourcemodel.hxx>
23
24 #include <oox/core/xmlfilterbase.hxx>
25 #include <oox/helper/attributelist.hxx>
26 #include <oox/token/namespaces.hxx>
27 #include <oox/token/tokens.hxx>
28 #include <svl/zforlist.hxx>
29 #include <osl/diagnose.h>
30
31 namespace oox::drawingml::chart {
32
33 using ::oox::core::ContextHandler2Helper;
34 using ::oox::core::ContextHandlerRef;
35
36 using namespace ::com::sun::star;
37
DoubleSequenceContext(ContextHandler2Helper & rParent,DataSequenceModel & rModel)38 DoubleSequenceContext::DoubleSequenceContext( ContextHandler2Helper& rParent, DataSequenceModel& rModel ) :
39 DataSequenceContextBase( rParent, rModel ),
40 mnPtIndex( -1 )
41 {
42 }
43
~DoubleSequenceContext()44 DoubleSequenceContext::~DoubleSequenceContext()
45 {
46 }
47
onCreateContext(sal_Int32 nElement,const AttributeList & rAttribs)48 ContextHandlerRef DoubleSequenceContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
49 {
50 switch( getCurrentElement() )
51 {
52 case C_TOKEN( numRef ):
53 switch( nElement )
54 {
55 case C_TOKEN( f ):
56 case C_TOKEN( numCache ):
57 return this;
58 }
59 break;
60
61 case C_TOKEN( numCache ):
62 case C_TOKEN( numLit ):
63 switch( nElement )
64 {
65 case C_TOKEN( formatCode ):
66 return this;
67 case C_TOKEN( ptCount ):
68 mrModel.mnPointCount = rAttribs.getInteger( XML_val, -1 );
69 return nullptr;
70 case C_TOKEN( pt ):
71 mnPtIndex = rAttribs.getInteger( XML_idx, -1 );
72 return this;
73 }
74 break;
75
76 case C_TOKEN( pt ):
77 switch( nElement )
78 {
79 case C_TOKEN( v ):
80 return this;
81 }
82 break;
83 }
84 return nullptr;
85 }
86
onCharacters(const OUString & rChars)87 void DoubleSequenceContext::onCharacters( const OUString& rChars )
88 {
89 switch( getCurrentElement() )
90 {
91 case C_TOKEN( f ):
92 mrModel.maFormula = rChars;
93 break;
94 case C_TOKEN( formatCode ):
95 mrModel.maFormatCode = rChars;
96 break;
97 case C_TOKEN( v ):
98 if( mnPtIndex >= 0 )
99 {
100 /* Import categories as String even though it could
101 * be values.
102 * n#810508: xVal needs to be imported as double
103 * TODO: NumberFormat conversion, remove the check then.
104 */
105 if( isParentElement( C_TOKEN( cat ), 4 ) )
106 {
107 // workaround for bug n#889755
108 SvNumberFormatter* pNumFrmt = getNumberFormatter();
109 if( pNumFrmt )
110 {
111 sal_uInt32 nKey = pNumFrmt->GetEntryKey( mrModel.maFormatCode );
112 bool bNoKey = ( nKey == NUMBERFORMAT_ENTRY_NOT_FOUND );
113 if( bNoKey )
114 {
115 OUString aFormatCode = mrModel.maFormatCode;
116 sal_Int32 nCheckPos = 0;
117 SvNumFormatType nType;
118 pNumFrmt->PutEntry( aFormatCode, nCheckPos, nType, nKey );
119 bNoKey = (nCheckPos != 0);
120 }
121 if( bNoKey )
122 {
123 mrModel.maData[ mnPtIndex ] <<= rChars;
124 }
125 else
126 {
127 double fValue = rChars.toDouble();
128 const ::Color* pColor = nullptr;
129 OUString aFormattedValue;
130 // tdf#91250: use UNLIMITED_PRECISION in case of GENERAL Number Format of category axis labels
131 if( pNumFrmt->GetStandardPrec() != SvNumberFormatter::UNLIMITED_PRECISION )
132 pNumFrmt->ChangeStandardPrec(SvNumberFormatter::UNLIMITED_PRECISION);
133 pNumFrmt->GetOutputString( fValue, nKey, aFormattedValue, &pColor );
134 mrModel.maData[ mnPtIndex ] <<= aFormattedValue;
135 }
136 }
137 else
138 {
139 mrModel.maData[ mnPtIndex ] <<= rChars;
140 }
141 }
142 else
143 {
144 mrModel.maData[ mnPtIndex ] <<= rChars.toDouble();
145 }
146 }
147 break;
148 }
149 }
150
151
getNumberFormatter()152 SvNumberFormatter* DoubleSequenceContext::getNumberFormatter()
153 {
154 if( mpNumberFormatter == nullptr )
155 {
156 uno::Reference<uno::XComponentContext> rContext =
157 getFilter().getComponentContext();
158 mpNumberFormatter.reset(
159 new SvNumberFormatter(rContext, LANGUAGE_SYSTEM) );
160 }
161 return mpNumberFormatter.get();
162 }
163
164
StringSequenceContext(ContextHandler2Helper & rParent,DataSequenceModel & rModel)165 StringSequenceContext::StringSequenceContext( ContextHandler2Helper& rParent, DataSequenceModel& rModel )
166 : DataSequenceContextBase( rParent, rModel )
167 , mnPtIndex(-1)
168 {
169 }
170
~StringSequenceContext()171 StringSequenceContext::~StringSequenceContext()
172 {
173 }
174
onCreateContext(sal_Int32 nElement,const AttributeList & rAttribs)175 ContextHandlerRef StringSequenceContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
176 {
177 switch( getCurrentElement() )
178 {
179 case C_TOKEN( multiLvlStrRef ):
180 switch( nElement )
181 {
182 case C_TOKEN( f ):
183 case C_TOKEN( multiLvlStrCache ):
184 return this;
185 }
186 break;
187
188 case C_TOKEN( strRef ):
189 switch( nElement )
190 {
191 case C_TOKEN( f ):
192 case C_TOKEN( strCache ):
193 return this;
194 }
195 break;
196
197 case C_TOKEN( strCache ):
198 case C_TOKEN( strLit ):
199 switch( nElement )
200 {
201 case C_TOKEN( ptCount ):
202 mrModel.mnPointCount = rAttribs.getInteger( XML_val, -1 );
203 return nullptr;
204 case C_TOKEN( pt ):
205 mnPtIndex = rAttribs.getInteger( XML_idx, -1 );
206 return this;
207 }
208 break;
209
210 case C_TOKEN( multiLvlStrCache ):
211 switch (nElement)
212 {
213 case C_TOKEN( ptCount ):
214 mrModel.mnPointCount = rAttribs.getInteger(XML_val, -1);
215 mrModel.mnLevelCount--; // normalize level count
216 return nullptr;
217 case C_TOKEN( lvl ):
218 mrModel.mnLevelCount++;
219 return this;
220 }
221 break;
222
223 case C_TOKEN( lvl ):
224 switch (nElement)
225 {
226 case C_TOKEN(pt):
227 mnPtIndex = rAttribs.getInteger(XML_idx, -1);
228 return this;
229 }
230 break;
231
232 case C_TOKEN( pt ):
233 switch( nElement )
234 {
235 case C_TOKEN( v ):
236 return this;
237 }
238 break;
239 }
240 return nullptr;
241 }
242
onCharacters(const OUString & rChars)243 void StringSequenceContext::onCharacters( const OUString& rChars )
244 {
245 switch( getCurrentElement() )
246 {
247 case C_TOKEN( f ):
248 mrModel.maFormula = rChars;
249 break;
250 case C_TOKEN( v ):
251 if( mnPtIndex >= 0 )
252 mrModel.maData[ (mrModel.mnLevelCount-1) * mrModel.mnPointCount + mnPtIndex ] <<= rChars;
253 break;
254 }
255 }
256
DataSourceContext(ContextHandler2Helper & rParent,DataSourceModel & rModel)257 DataSourceContext::DataSourceContext( ContextHandler2Helper& rParent, DataSourceModel& rModel ) :
258 ContextBase< DataSourceModel >( rParent, rModel )
259 {
260 }
261
~DataSourceContext()262 DataSourceContext::~DataSourceContext()
263 {
264 }
265
onCreateContext(sal_Int32 nElement,const AttributeList &)266 ContextHandlerRef DataSourceContext::onCreateContext( sal_Int32 nElement, const AttributeList& )
267 {
268 switch( getCurrentElement() )
269 {
270 case C_TOKEN( cat ):
271 case C_TOKEN( xVal ):
272 switch( nElement )
273 {
274 case C_TOKEN( multiLvlStrRef ):
275 case C_TOKEN( strLit ):
276 case C_TOKEN( strRef ):
277 OSL_ENSURE( !mrModel.mxDataSeq, "DataSourceContext::onCreateContext - multiple data sequences" );
278 return new StringSequenceContext( *this, mrModel.mxDataSeq.create() );
279
280 case C_TOKEN( numLit ):
281 case C_TOKEN( numRef ):
282 OSL_ENSURE( !mrModel.mxDataSeq, "DataSourceContext::onCreateContext - multiple data sequences" );
283 return new DoubleSequenceContext( *this, mrModel.mxDataSeq.create() );
284 }
285 break;
286
287 case C_TOKEN( plus ):
288 case C_TOKEN( minus ):
289 case C_TOKEN( val ):
290 case C_TOKEN( yVal ):
291 case C_TOKEN( bubbleSize ):
292 switch( nElement )
293 {
294 case C_TOKEN( numLit ):
295 case C_TOKEN( numRef ):
296 OSL_ENSURE( !mrModel.mxDataSeq, "DataSourceContext::onCreateContext - multiple data sequences" );
297 return new DoubleSequenceContext( *this, mrModel.mxDataSeq.create() );
298 }
299 break;
300 }
301 return nullptr;
302 }
303
304 } // namespace oox::drawingml::chart
305
306 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
307