LibreOffice Module chart2 (master) 1
InternalData.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 <InternalData.hxx>
21#include <ResId.hxx>
22#include <strings.hrc>
23
25#include <o3tl/safeint.hxx>
26#include <osl/diagnose.h>
27
28#ifdef DEBUG_CHART2_TOOLS
29#define DEBUG_INTERNAL_DATA 1
30#endif
31
32#ifdef DEBUG_INTERNAL_DATA
33#include <svl/gridprinter.hxx>
34#endif
35
36#include <algorithm>
37#include <iterator>
38#include <limits>
39
40using ::com::sun::star::uno::Sequence;
41
42using namespace ::com::sun::star;
43
44namespace chart
45{
46
47namespace
48{
49struct lcl_NumberedStringGenerator
50{
51 lcl_NumberedStringGenerator( const OUString & rStub, std::u16string_view rWildcard ) :
52 m_aStub( rStub ),
53 m_nCounter( 0 ),
54 m_nStubStartIndex( rStub.indexOf( rWildcard )),
55 m_nWildcardLength( rWildcard.size())
56 {
57 }
58 std::vector< uno::Any > operator()()
59 {
60 return { uno::Any(m_aStub.replaceAt( m_nStubStartIndex, m_nWildcardLength, OUString::number( ++m_nCounter ))) };
61 }
62private:
63 OUString m_aStub;
64 sal_Int32 m_nCounter;
65 const sal_Int32 m_nStubStartIndex;
66 const sal_Int32 m_nWildcardLength;
67};
68
69template< typename T >
70 Sequence< T > lcl_ValarrayToSequence( const std::valarray< T > & rValarray )
71{
72#if defined __GLIBCXX__ && (!defined _GLIBCXX_RELEASE || _GLIBCXX_RELEASE < 12)
73 // workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103022
74 if (!size(rValarray))
75 return Sequence<T>();
76#endif
77
78 return comphelper::containerToSequence(rValarray);
79}
80
81} // anonymous namespace
82
84 : m_nColumnCount( 0 )
85 , m_nRowCount( 0 )
86 , m_aRowLabels( 0 )
87 , m_aColumnLabels( 0 )
88{}
89
90const double fDefaultData[] = {
91 9.10, 3.20, 4.54,
92 2.40, 8.80, 9.65,
93 3.10, 1.50, 3.70,
94 4.30, 9.02, 6.20
95};
96
98{
99 const sal_Int32 nRowCount = 4;
100 const sal_Int32 nColumnCount = 3;
101
102 m_nRowCount = nRowCount;
103 m_nColumnCount = nColumnCount;
104 const sal_Int32 nSize = nColumnCount * nRowCount;
105 // @todo: localize this!
106 const OUString aRowName(SchResId(STR_ROW_LABEL));
107 const OUString aColName(SchResId(STR_COLUMN_LABEL));
108
109 m_aData.resize( nSize );
110 for( sal_Int32 i=0; i<nSize; ++i )
112
113 m_aRowLabels.clear();
114 m_aRowLabels.reserve( m_nRowCount );
115 generate_n( back_inserter( m_aRowLabels ), m_nRowCount,
116 lcl_NumberedStringGenerator( aRowName, u"%ROWNUMBER" ));
117
118 m_aColumnLabels.clear();
120 generate_n( back_inserter( m_aColumnLabels ), m_nColumnCount,
121 lcl_NumberedStringGenerator( aColName, u"%COLUMNNUMBER" ));
122}
123
125{
126 m_nRowCount = rDataInRows.getLength();
127 m_nColumnCount = (m_nRowCount ? rDataInRows[0].getLength() : 0);
128
129 if( m_aRowLabels.size() != static_cast< sal_uInt32 >( m_nRowCount ))
130 m_aRowLabels.resize( m_nRowCount );
131 if( m_aColumnLabels.size() != static_cast< sal_uInt32 >( m_nColumnCount ))
133
135 // set all values to Nan
136 m_aData = std::numeric_limits<double>::quiet_NaN();
137
138 for( sal_Int32 nRow=0; nRow<m_nRowCount; ++nRow )
139 {
140 int nDataIdx = nRow*m_nColumnCount;
141 const sal_Int32 nMax = std::min( rDataInRows[nRow].getLength(), m_nColumnCount );
142 for( sal_Int32 nCol=0; nCol < nMax; ++nCol )
143 {
144 m_aData[nDataIdx] = rDataInRows[nRow][nCol];
145 nDataIdx += 1;
146 }
147 }
148}
149
151{
153 auto aResultRange = asNonConstRange(aResult);
154
155 for( sal_Int32 i=0; i<m_nRowCount; ++i )
156 aResultRange[i] = lcl_ValarrayToSequence< tDataType::value_type >(
157 m_aData[ std::slice( i*m_nColumnCount, m_nColumnCount, 1 ) ] );
158
159 return aResult;
160}
161
163{
164 if( nColumnIndex >= 0 && nColumnIndex < m_nColumnCount )
165 return lcl_ValarrayToSequence< tDataType::value_type >(
166 m_aData[ std::slice( nColumnIndex, m_nRowCount, m_nColumnCount ) ] );
167 return Sequence< double >();
168}
170{
171 if( nRowIndex >= 0 && nRowIndex < m_nRowCount )
172 return lcl_ValarrayToSequence< tDataType::value_type >(
173 m_aData[ std::slice( nRowIndex*m_nColumnCount, m_nColumnCount, 1 ) ] );
174 return Sequence< double >();
175}
176
177void InternalData::setColumnValues( sal_Int32 nColumnIndex, const std::vector< double > & rNewData )
178{
179 if( nColumnIndex < 0 )
180 return;
181 enlargeData( nColumnIndex + 1, rNewData.size() );
182
183 tDataType aSlice = m_aData[ std::slice( nColumnIndex, m_nRowCount, m_nColumnCount ) ];
184 for( std::vector< double >::size_type i = 0; i < rNewData.size(); ++i )
185 aSlice[i] = rNewData[i];
186 m_aData[ std::slice( nColumnIndex, m_nRowCount, m_nColumnCount ) ] = aSlice;
187}
188
189void InternalData::setRowValues( sal_Int32 nRowIndex, const std::vector< double > & rNewData )
190{
191 if( nRowIndex < 0 )
192 return;
193 enlargeData( rNewData.size(), nRowIndex+1 );
194
195 tDataType aSlice = m_aData[ std::slice( nRowIndex*m_nColumnCount, m_nColumnCount, 1 ) ];
196 for( std::vector< double >::size_type i = 0; i < rNewData.size(); ++i )
197 aSlice[i] = rNewData[i];
198 m_aData[ std::slice( nRowIndex*m_nColumnCount, m_nColumnCount, 1 ) ]= aSlice;
199}
200
201void InternalData::setComplexColumnLabel( sal_Int32 nColumnIndex, std::vector< uno::Any >&& rComplexLabel )
202{
203 if( nColumnIndex < 0 )
204 return;
205 if( o3tl::make_unsigned(nColumnIndex) >= m_aColumnLabels.size() )
206 {
207 m_aColumnLabels.resize(nColumnIndex+1);
208 enlargeData( nColumnIndex+1, 0 );
209 }
210 m_aColumnLabels[nColumnIndex] = std::move(rComplexLabel);
211
212 dump();
213}
214
215void InternalData::setComplexRowLabel( sal_Int32 nRowIndex, std::vector< uno::Any >&& rComplexLabel )
216{
217 if( nRowIndex < 0 )
218 return;
219 if( o3tl::make_unsigned(nRowIndex) >= m_aRowLabels.size() )
220 {
221 m_aRowLabels.resize(nRowIndex+1);
222 enlargeData( 0, nRowIndex+1 );
223 }
224 sal_Int32 nSize = static_cast<sal_Int32>( m_aRowLabels[nRowIndex].size() );
225 if( nSize >= 1 && !rComplexLabel.empty() )
226 {
227 m_aRowLabels[nRowIndex].resize(nSize+1);
228 m_aRowLabels[nRowIndex][nSize] = rComplexLabel[0];
229 }
230 else
231 {
232 m_aRowLabels[nRowIndex] = std::move(rComplexLabel);
233 }
234}
235
236std::vector< uno::Any > InternalData::getComplexColumnLabel( sal_Int32 nColumnIndex ) const
237{
238 if( nColumnIndex < static_cast< sal_Int32 >( m_aColumnLabels.size() ) )
239 return m_aColumnLabels[nColumnIndex];
240 else
241 return std::vector< uno::Any >();
242}
243std::vector< uno::Any > InternalData::getComplexRowLabel( sal_Int32 nRowIndex ) const
244{
245 if( nRowIndex < static_cast< sal_Int32 >( m_aRowLabels.size() ) )
246 return m_aRowLabels[nRowIndex];
247 else
248 return std::vector< uno::Any >();
249}
250
251void InternalData::swapRowWithNext( sal_Int32 nRowIndex )
252{
253 if( nRowIndex >= m_nRowCount - 1 )
254 return;
255
256 const sal_Int32 nMax = m_nColumnCount;
257 for( sal_Int32 nColIdx=0; nColIdx<nMax; ++nColIdx )
258 {
259 size_t nIndex1 = nColIdx + nRowIndex*m_nColumnCount;
260 size_t nIndex2 = nIndex1 + m_nColumnCount;
261 std::swap(m_aData[nIndex1], m_aData[nIndex2]);
262 }
263
264 std::vector< uno::Any > aTemp( m_aRowLabels[nRowIndex] );
265 m_aRowLabels[nRowIndex] = m_aRowLabels[nRowIndex + 1];
266 m_aRowLabels[nRowIndex + 1] = aTemp;
267}
268
269void InternalData::swapColumnWithNext( sal_Int32 nColumnIndex )
270{
271 if( nColumnIndex >= m_nColumnCount - 1 )
272 return;
273
274 const sal_Int32 nMax = m_nRowCount;
275 for( sal_Int32 nRowIdx=0; nRowIdx<nMax; ++nRowIdx )
276 {
277 size_t nIndex1 = nColumnIndex + nRowIdx*m_nColumnCount;
278 size_t nIndex2 = nIndex1 + 1;
279 std::swap(m_aData[nIndex1], m_aData[nIndex2]);
280 }
281
282 std::vector< uno::Any > aTemp( m_aColumnLabels[nColumnIndex] );
283 m_aColumnLabels[nColumnIndex] = m_aColumnLabels[nColumnIndex + 1];
284 m_aColumnLabels[nColumnIndex + 1] = aTemp;
285}
286
287bool InternalData::enlargeData( sal_Int32 nColumnCount, sal_Int32 nRowCount )
288{
289 sal_Int32 nNewColumnCount( std::max<sal_Int32>( m_nColumnCount, nColumnCount ) );
290 sal_Int32 nNewRowCount( std::max<sal_Int32>( m_nRowCount, nRowCount ) );
291 sal_Int32 nNewSize( nNewColumnCount*nNewRowCount );
292
293 bool bGrow = (nNewSize > m_nColumnCount*m_nRowCount);
294
295 if( bGrow )
296 {
297 tDataType aNewData( std::numeric_limits<double>::quiet_NaN(), nNewSize );
298 // copy old data
299 for( int nCol=0; nCol<m_nColumnCount; ++nCol )
300 static_cast< tDataType >(
301 aNewData[ std::slice( nCol, m_nRowCount, nNewColumnCount ) ] ) =
302 m_aData[ std::slice( nCol, m_nRowCount, m_nColumnCount ) ];
303
304 m_aData.resize( nNewSize );
305 m_aData = aNewData;
306 }
307 m_nColumnCount = nNewColumnCount;
308 m_nRowCount = nNewRowCount;
309 return bGrow;
310}
311
312void InternalData::insertColumn( sal_Int32 nAfterIndex )
313{
314 // note: -1 is allowed, as we insert after the given index
315 OSL_ASSERT( nAfterIndex < m_nColumnCount && nAfterIndex >= -1 );
316 if( nAfterIndex >= m_nColumnCount || nAfterIndex < -1 )
317 return;
318 sal_Int32 nNewColumnCount = m_nColumnCount + 1;
319 sal_Int32 nNewSize( nNewColumnCount * m_nRowCount );
320
321 tDataType aNewData( std::numeric_limits<double>::quiet_NaN(), nNewSize );
322
323 // copy old data
324 int nCol=0;
325 for( ; nCol<=nAfterIndex; ++nCol )
326 aNewData[ std::slice( nCol, m_nRowCount, nNewColumnCount ) ] =
327 static_cast< tDataType >(
328 m_aData[ std::slice( nCol, m_nRowCount, m_nColumnCount ) ] );
329 for( ++nCol; nCol<nNewColumnCount; ++nCol )
330 aNewData[ std::slice( nCol, m_nRowCount, nNewColumnCount ) ] =
331 static_cast< tDataType >(
332 m_aData[ std::slice( nCol - 1, m_nRowCount, m_nColumnCount ) ] );
333
334 m_nColumnCount = nNewColumnCount;
335 m_aData.resize( nNewSize );
336 m_aData = aNewData;
337
338 // labels
339 if( nAfterIndex < static_cast< sal_Int32 >( m_aColumnLabels.size()))
340 m_aColumnLabels.insert( m_aColumnLabels.begin() + (nAfterIndex + 1), std::vector< uno::Any >(1) );
341
342 dump();
343}
344
346{
348 return getColumnCount() - 1;
349}
350
352{
353 insertRow( getRowCount() - 1 );
354 return getRowCount() - 1;
355}
356
358{
359 return m_nRowCount;
360}
361
363{
364 return m_nColumnCount;
365}
366
367void InternalData::insertRow( sal_Int32 nAfterIndex )
368{
369 // note: -1 is allowed, as we insert after the given index
370 OSL_ASSERT( nAfterIndex < m_nRowCount && nAfterIndex >= -1 );
371 if( nAfterIndex >= m_nRowCount || nAfterIndex < -1 )
372 return;
373 sal_Int32 nNewRowCount = m_nRowCount + 1;
374 sal_Int32 nNewSize( m_nColumnCount * nNewRowCount );
375
376 tDataType aNewData( std::numeric_limits<double>::quiet_NaN(), nNewSize );
377
378 // copy old data
379 sal_Int32 nIndex = nAfterIndex + 1;
380 aNewData[ std::slice( 0, nIndex * m_nColumnCount, 1 ) ] =
381 static_cast< tDataType >(
382 m_aData[ std::slice( 0, nIndex * m_nColumnCount, 1 ) ] );
383
384 if( nIndex < m_nRowCount )
385 {
386 sal_Int32 nRemainingCount = m_nColumnCount * (m_nRowCount - nIndex);
387 aNewData[ std::slice( (nIndex + 1) * m_nColumnCount, nRemainingCount, 1 ) ] =
388 static_cast< tDataType >(
389 m_aData[ std::slice( nIndex * m_nColumnCount, nRemainingCount, 1 ) ] );
390 }
391
392 m_nRowCount = nNewRowCount;
393 m_aData.resize( nNewSize );
394 m_aData = aNewData;
395
396 // labels
397 if( nAfterIndex < static_cast< sal_Int32 >( m_aRowLabels.size()))
398 m_aRowLabels.insert( m_aRowLabels.begin() + nIndex, std::vector< uno::Any > (1));
399
400 dump();
401}
402
403void InternalData::deleteColumn( sal_Int32 nAtIndex )
404{
405 OSL_ASSERT( nAtIndex < m_nColumnCount && nAtIndex >= 0 );
406 if( nAtIndex >= m_nColumnCount || m_nColumnCount < 1 || nAtIndex < 0 )
407 return;
408 sal_Int32 nNewColumnCount = m_nColumnCount - 1;
409 sal_Int32 nNewSize( nNewColumnCount * m_nRowCount );
410
411 tDataType aNewData( std::numeric_limits<double>::quiet_NaN(), nNewSize );
412
413 // copy old data
414 int nCol=0;
415 for( ; nCol<nAtIndex; ++nCol )
416 aNewData[ std::slice( nCol, m_nRowCount, nNewColumnCount ) ] =
417 static_cast< tDataType >(
418 m_aData[ std::slice( nCol, m_nRowCount, m_nColumnCount ) ] );
419 for( ; nCol<nNewColumnCount; ++nCol )
420 aNewData[ std::slice( nCol, m_nRowCount, nNewColumnCount ) ] =
421 static_cast< tDataType >(
422 m_aData[ std::slice( nCol + 1, m_nRowCount, m_nColumnCount ) ] );
423
424 m_nColumnCount = nNewColumnCount;
425 m_aData.resize( nNewSize );
426 m_aData = aNewData;
427
428 // labels
429 if( nAtIndex < static_cast< sal_Int32 >( m_aColumnLabels.size()))
430 m_aColumnLabels.erase( m_aColumnLabels.begin() + nAtIndex );
431
432 dump();
433}
434
435void InternalData::deleteRow( sal_Int32 nAtIndex )
436{
437 OSL_ASSERT( nAtIndex < m_nRowCount && nAtIndex >= 0 );
438 if( nAtIndex >= m_nRowCount || m_nRowCount < 1 || nAtIndex < 0 )
439 return;
440 sal_Int32 nNewRowCount = m_nRowCount - 1;
441 sal_Int32 nNewSize( m_nColumnCount * nNewRowCount );
442
443 tDataType aNewData( std::numeric_limits<double>::quiet_NaN(), nNewSize );
444
445 // copy old data
446 sal_Int32 nIndex = nAtIndex;
447 if( nIndex )
448 aNewData[ std::slice( 0, nIndex * m_nColumnCount, 1 ) ] =
449 static_cast< tDataType >(
450 m_aData[ std::slice( 0, nIndex * m_nColumnCount, 1 ) ] );
451
452 if( nIndex < nNewRowCount )
453 {
454 sal_Int32 nRemainingCount = m_nColumnCount * (nNewRowCount - nIndex);
455 aNewData[ std::slice( nIndex * m_nColumnCount, nRemainingCount, 1 ) ] =
456 static_cast< tDataType >(
457 m_aData[ std::slice( (nIndex + 1) * m_nColumnCount, nRemainingCount, 1 ) ] );
458 }
459
460 m_nRowCount = nNewRowCount;
461 m_aData.resize( nNewSize );
462 m_aData = aNewData;
463
464 // labels
465 if( nAtIndex < static_cast< sal_Int32 >( m_aRowLabels.size()))
466 m_aRowLabels.erase( m_aRowLabels.begin() + nAtIndex );
467
468 dump();
469}
470
472{
473 m_aRowLabels = std::move(rNewRowLabels);
474 sal_Int32 nNewRowCount = static_cast< sal_Int32 >( m_aRowLabels.size() );
475 if( nNewRowCount < m_nRowCount )
476 m_aRowLabels.resize( m_nRowCount );
477 else
478 enlargeData( 0, nNewRowCount );
479}
480
482{
483 return m_aRowLabels;
484}
485
487{
488 m_aColumnLabels = std::move(rNewColumnLabels);
489 sal_Int32 nNewColumnCount = static_cast< sal_Int32 >( m_aColumnLabels.size() );
490 if( nNewColumnCount < m_nColumnCount )
492 else
493 enlargeData( nNewColumnCount, 0 );
494}
495
497{
498 return m_aColumnLabels;
499}
500
501#ifdef DEBUG_INTERNAL_DATA
502void InternalData::dump() const
503{
504 // Header
505 if (!m_aColumnLabels.empty())
506 {
507 svl::GridPrinter aPrinter(m_aColumnLabels[0].size(), m_aColumnLabels.size(), true);
508 for (size_t nCol = 0; nCol < m_aColumnLabels.size(); ++nCol)
509 {
510 for (size_t nRow = 0; nRow < m_aColumnLabels[nCol].size(); ++nRow)
511 {
512 OUString aStr;
513 if (m_aColumnLabels[nCol].at(nRow) >>= aStr)
514 aPrinter.set(nRow, nCol, aStr);
515 }
516 }
517 aPrinter.print("Header");
518 }
519
520 if (!m_aRowLabels.empty())
521 {
522 svl::GridPrinter aPrinter(m_aRowLabels.size(), m_aRowLabels[0].size(), true);
523 for (size_t nRow = 0; nRow < m_aRowLabels.size(); ++nRow)
524 {
525 for (size_t nCol = 0; nCol < m_aRowLabels[nRow].size(); ++nCol)
526 {
527 OUString aStr;
528 if (m_aRowLabels[nRow].at(nCol) >>= aStr)
529 aPrinter.set(nRow, nCol, aStr);
530 }
531 }
532 aPrinter.print("Row labels");
533 }
534
536
537 for (sal_Int32 nRow = 0; nRow < m_nRowCount; ++nRow)
538 {
539 tDataType aSlice( m_aData[ std::slice( nRow*m_nColumnCount, m_nColumnCount, 1 ) ] );
540 for (sal_Int32 nCol = 0; nCol < m_nColumnCount; ++nCol)
541 aPrinter.set(nRow, nCol, OUString::number(aSlice[nCol]));
542 }
543
544 aPrinter.print("Column data");
545}
546#else
547void InternalData::dump() const {}
548#endif
549
550} // namespace chart
551
552/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 m_nCounter
OUString m_aStub
const sal_Int32 m_nStubStartIndex
const sal_Int32 m_nWildcardLength
sal_Int32 getColumnCount() const
std::valarray< double > tDataType
const tVecVecAny & getComplexColumnLabels() const
sal_Int32 getRowCount() const
void deleteColumn(sal_Int32 nAtIndex)
void setComplexRowLabel(sal_Int32 nRowIndex, std::vector< css::uno::Any > &&rComplexLabel)
css::uno::Sequence< double > getRowValues(sal_Int32 nRowIndex) const
void setComplexColumnLabel(sal_Int32 nColumnIndex, std::vector< css::uno::Any > &&rComplexLabel)
void insertColumn(sal_Int32 nAfterIndex)
css::uno::Sequence< css::uno::Sequence< double > > getData() const
sal_Int32 appendColumn()
const tVecVecAny & getComplexRowLabels() const
void setColumnValues(sal_Int32 nColumnIndex, const std::vector< double > &rNewData)
void insertRow(sal_Int32 nAfterIndex)
std::vector< std::vector< css::uno::Any > > tVecVecAny
tVecVecAny m_aRowLabels
void deleteRow(sal_Int32 nAtIndex)
void setComplexColumnLabels(tVecVecAny &&rNewColumnLabels)
tVecVecAny m_aColumnLabels
void swapColumnWithNext(sal_Int32 nColumnIndex)
sal_Int32 m_nColumnCount
bool enlargeData(sal_Int32 nColumnCount, sal_Int32 nRowCount)
resizes the data if at least one of the given dimensions is larger than before.
void setRowValues(sal_Int32 nRowIndex, const std::vector< double > &rNewData)
void swapRowWithNext(sal_Int32 nRowIndex)
std::vector< css::uno::Any > getComplexColumnLabel(sal_Int32 nColumnIndex) const
css::uno::Sequence< double > getColumnValues(sal_Int32 nColumnIndex) const
std::vector< css::uno::Any > getComplexRowLabel(sal_Int32 nRowIndex) const
void setData(const css::uno::Sequence< css::uno::Sequence< double > > &rDataInRows)
void setComplexRowLabels(tVecVecAny &&rNewRowLabels)
float u
sal_Int32 nIndex
aStr
double getLength(const B2DPolygon &rCandidate)
size
const double fDefaultData[]
OUString OOO_DLLPUBLIC_CHARTTOOLS SchResId(TranslateId aId)
Definition: ResId.cxx:24
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)