LibreOffice Module sc (master) 1
chart2uno.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 <memory>
21#include <sal/config.h>
22#include <sal/log.hxx>
23
24#include <algorithm>
25#include <utility>
26
27#include <chart2uno.hxx>
28#include <miscuno.hxx>
29#include <document.hxx>
30#include <formulacell.hxx>
31#include <unonames.hxx>
32#include <globstr.hrc>
33#include <scresid.hxx>
34#include <rangeutl.hxx>
35#include <hints.hxx>
36#include <unoreflist.hxx>
37#include <compiler.hxx>
38#include <reftokenhelper.hxx>
39#include <chartlis.hxx>
40#include <tokenuno.hxx>
41#include <cellvalue.hxx>
42#include <tokenarray.hxx>
43#include <scmatrix.hxx>
44#include <brdcst.hxx>
45#include <mtvelements.hxx>
46
47#include <formula/opcode.hxx>
48#include <o3tl/safeint.hxx>
49#include <svl/numformat.hxx>
50#include <svl/sharedstring.hxx>
51
52#include <sfx2/objsh.hxx>
53#include <vcl/svapp.hxx>
54
55#include <com/sun/star/beans/UnknownPropertyException.hpp>
56#include <com/sun/star/chart/ChartDataRowSource.hpp>
57#include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
58#include <com/sun/star/frame/XModel.hpp>
62
63#include <limits>
64
66 "com.sun.star.chart2.data.DataProvider")
68 "com.sun.star.chart2.data.DataSource")
70 "com.sun.star.chart2.data.DataSequence")
71
72using namespace ::com::sun::star;
73using namespace ::formula;
74using ::com::sun::star::uno::Sequence;
75using ::std::unique_ptr;
76using ::std::vector;
77using ::std::distance;
78using ::std::shared_ptr;
79
80namespace
81{
82o3tl::span<const SfxItemPropertyMapEntry> lcl_GetDataProviderPropertyMap()
83{
84 static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
85 {
88 };
89 return aDataProviderPropertyMap_Impl;
90}
91
93{
94 static const SfxItemPropertyMapEntry aDataSequencePropertyMap_Impl[] =
95 {
99 };
100 return aDataSequencePropertyMap_Impl;
101}
102
103struct lcl_appendTableNumber
104{
105 explicit lcl_appendTableNumber( OUStringBuffer & rBuffer ) :
106 m_rBuffer( rBuffer )
107 {}
108 void operator() ( SCTAB nTab )
109 {
110 // there is no append with SCTAB or sal_Int16
111 m_rBuffer.append( static_cast< sal_Int32 >( nTab ));
112 m_rBuffer.append( ' ' );
113 }
114private:
115 OUStringBuffer & m_rBuffer;
116};
117
118OUString lcl_createTableNumberList( const ::std::vector< SCTAB > & rTableVector )
119{
120 OUStringBuffer aBuffer;
121 ::std::for_each( rTableVector.begin(), rTableVector.end(), lcl_appendTableNumber( aBuffer ));
122 // remove last trailing ' '
123 if( !aBuffer.isEmpty() )
124 aBuffer.setLength( aBuffer.getLength() - 1 );
125 return aBuffer.makeStringAndClear();
126}
127
128uno::Reference< frame::XModel > lcl_GetXModel( const ScDocument * pDoc )
129{
130 uno::Reference< frame::XModel > xModel;
131 SfxObjectShell * pObjSh( pDoc ? pDoc->GetDocumentShell() : nullptr );
132 if( pObjSh )
133 xModel.set( pObjSh->GetModel());
134 return xModel;
135}
136
137struct TokenTable
138{
139 SCROW mnRowCount;
140 SCCOL mnColCount;
141 vector<std::unique_ptr<FormulaToken>> maTokens;
142
143 // noncopyable
144 TokenTable(const TokenTable&) = delete;
145 const TokenTable& operator=(const TokenTable&) = delete;
146
147 TokenTable()
148 : mnRowCount(0)
149 , mnColCount(0)
150 {
151 }
152
153 void init( SCCOL nColCount, SCROW nRowCount )
154 {
155 mnColCount = nColCount;
156 mnRowCount = nRowCount;
157 maTokens.reserve(mnColCount*mnRowCount);
158 }
159 void clear()
160 {
161 for (auto & rToken : maTokens)
162 rToken.reset();
163 }
164
165 void push_back( std::unique_ptr<FormulaToken> pToken )
166 {
167 maTokens.push_back( std::move(pToken) );
168 OSL_ENSURE( maTokens.size()<= o3tl::make_unsigned( mnColCount*mnRowCount ), "too many tokens" );
169 }
170
171 sal_uInt32 getIndex(SCCOL nCol, SCROW nRow) const
172 {
173 OSL_ENSURE( nCol<mnColCount, "wrong column index" );
174 OSL_ENSURE( nRow<mnRowCount, "wrong row index" );
175 sal_uInt32 nRet = static_cast<sal_uInt32>(nCol*mnRowCount + nRow);
176 OSL_ENSURE( maTokens.size()>= o3tl::make_unsigned( mnColCount*mnRowCount ), "too few tokens" );
177 return nRet;
178 }
179
180 vector<ScTokenRef> getColRanges(const ScDocument* pDoc, SCCOL nCol) const;
181 vector<ScTokenRef> getRowRanges(const ScDocument* pDoc, SCROW nRow) const;
182 vector<ScTokenRef> getAllRanges(const ScDocument* pDoc) const;
183};
184
185vector<ScTokenRef> TokenTable::getColRanges(const ScDocument* pDoc, SCCOL nCol) const
186{
187 if (nCol >= mnColCount)
188 return vector<ScTokenRef>();
189 if( mnRowCount<=0 )
190 return vector<ScTokenRef>();
191
192 vector<ScTokenRef> aTokens;
193 sal_uInt32 nLast = getIndex(nCol, mnRowCount-1);
194 for (sal_uInt32 i = getIndex(nCol, 0); i <= nLast; ++i)
195 {
196 FormulaToken* p = maTokens[i].get();
197 if (!p)
198 continue;
199
200 ScTokenRef pCopy(p->Clone());
201 ScRefTokenHelper::join(pDoc, aTokens, pCopy, ScAddress());
202 }
203 return aTokens;
204}
205
206vector<ScTokenRef> TokenTable::getRowRanges(const ScDocument* pDoc, SCROW nRow) const
207{
208 if (nRow >= mnRowCount)
209 return vector<ScTokenRef>();
210 if( mnColCount<=0 )
211 return vector<ScTokenRef>();
212
213 vector<ScTokenRef> aTokens;
214 sal_uInt32 nLast = getIndex(mnColCount-1, nRow);
215 for (sal_uInt32 i = getIndex(0, nRow); i <= nLast; i += mnRowCount)
216 {
217 FormulaToken* p = maTokens[i].get();
218 if (!p)
219 continue;
220
221 ScTokenRef p2(p->Clone());
222 ScRefTokenHelper::join(pDoc, aTokens, p2, ScAddress());
223 }
224 return aTokens;
225}
226
227vector<ScTokenRef> TokenTable::getAllRanges(const ScDocument* pDoc) const
228{
229 vector<ScTokenRef> aTokens;
230 sal_uInt32 nStop = mnColCount*mnRowCount;
231 for (sal_uInt32 i = 0; i < nStop; i++)
232 {
233 FormulaToken* p = maTokens[i].get();
234 if (!p)
235 continue;
236
237 ScTokenRef p2(p->Clone());
238 ScRefTokenHelper::join(pDoc, aTokens, p2, ScAddress());
239 }
240 return aTokens;
241}
242
243typedef std::map<SCROW, std::unique_ptr<FormulaToken>> FormulaTokenMap;
244typedef std::map<sal_uInt32, FormulaTokenMap> FormulaTokenMapMap;
245
246class Chart2PositionMap
247{
248public:
249 Chart2PositionMap(SCCOL nColCount, SCROW nRowCount,
250 bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols,
251 ScDocument* pDoc );
252 ~Chart2PositionMap();
253
254 SCCOL getDataColCount() const { return mnDataColCount; }
255 SCROW getDataRowCount() const { return mnDataRowCount; }
256
257 vector<ScTokenRef> getLeftUpperCornerRanges() const;
258 vector<ScTokenRef> getAllColHeaderRanges() const;
259 vector<ScTokenRef> getAllRowHeaderRanges() const;
260
261 vector<ScTokenRef> getColHeaderRanges(SCCOL nChartCol) const;
262 vector<ScTokenRef> getRowHeaderRanges(SCROW nChartRow) const;
263
264 vector<ScTokenRef> getDataColRanges(SCCOL nCol) const;
265 vector<ScTokenRef> getDataRowRanges(SCROW nRow) const;
266
267private:
268 const ScDocument* mpDoc;
269 SCCOL mnDataColCount;
270 SCROW mnDataRowCount;
271
272 TokenTable maLeftUpperCorner; //nHeaderColCount*nHeaderRowCount
273 TokenTable maColHeaders; //mnDataColCount*nHeaderRowCount
274 TokenTable maRowHeaders; //nHeaderColCount*mnDataRowCount
275 TokenTable maData;//mnDataColCount*mnDataRowCount
276};
277
278Chart2PositionMap::Chart2PositionMap(SCCOL nAllColCount, SCROW nAllRowCount,
279 bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols, ScDocument* pDoc)
280{
281 mpDoc = pDoc;
282 // if bFillRowHeader is true, at least the first column serves as a row header.
283 // If more than one column is pure text all the first pure text columns are used as header.
284 // Likewise, if bFillColumnHeader is true, at least the first row serves as a column header.
285 // If more than one row is pure text all the first pure text rows are used as header.
286
287 SCROW nHeaderRowCount = (bFillColumnHeader && nAllColCount && nAllRowCount) ? 1 : 0;
288 SCCOL nHeaderColCount = (bFillRowHeader && nAllColCount && nAllRowCount) ? 1 : 0;
289
290 if( pDoc && (nHeaderColCount || nHeaderRowCount ) )
291 {
292 //check whether there is more than one text column or row that should be added to the headers
293 SCROW nMaxHeaderRow = nAllRowCount;
294 SCCOL nCol = 0;
295 for (auto it = rCols.begin(); it != rCols.end(); ++it, ++nCol)
296 {
297 // Skip header columns
298 if (nCol < nHeaderColCount)
299 continue;
300
301 const auto& rCol = *it;
302
303 bool bFoundValuesInCol = false;
304 bool bFoundAnythingInCol = false;
305 SCROW nRow = 0;
306 for (auto it2 = rCol.second.begin(); it2 != rCol.second.end(); ++it2, ++nRow)
307 {
308 const auto& rCell = *it2;
309
310 // Skip header rows
311 if (nRow < nHeaderRowCount || !rCell.second)
312 continue;
313
314 ScRange aRange;
315 bool bExternal = false;
316 StackVar eType = rCell.second->GetType();
318 bExternal = true;//lllll todo correct?
319 ScTokenRef pSharedToken(rCell.second->Clone());
320 ScRefTokenHelper::getRangeFromToken(pDoc, aRange, pSharedToken, ScAddress(), bExternal);
321 SCCOL nCol1=0, nCol2=0;
322 SCROW nRow1=0, nRow2=0;
323 SCTAB nTab1=0, nTab2=0;
324 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
325 if ( pDoc->HasValueData( nCol1, nRow1, nTab1 ) )
326 {
327 // Found some numeric data
328 bFoundValuesInCol = true;
329 nMaxHeaderRow = std::min(nMaxHeaderRow, nRow);
330 break;
331 }
332 if ( pDoc->HasData( nCol1, nRow1, nTab1 ) )
333 {
334 // Found some other data (non-numeric)
335 bFoundAnythingInCol = true;
336 }
337 else
338 {
339 // If cell is empty, it belongs to data
340 nMaxHeaderRow = std::min(nMaxHeaderRow, nRow);
341 }
342 }
343
344 if (nHeaderColCount && !bFoundValuesInCol && bFoundAnythingInCol && nCol == nHeaderColCount)
345 {
346 // There is no values in row, but some data. And this column is next to header
347 // So lets put it to header
348 nHeaderColCount++;
349 }
350 }
351
352 if (nHeaderRowCount)
353 {
354 nHeaderRowCount = nMaxHeaderRow;
355 }
356 }
357
358 mnDataColCount = nAllColCount - nHeaderColCount;
359 mnDataRowCount = nAllRowCount - nHeaderRowCount;
360
361 maLeftUpperCorner.init(nHeaderColCount,nHeaderRowCount);
362 maColHeaders.init(mnDataColCount,nHeaderRowCount);
363 maRowHeaders.init(nHeaderColCount,mnDataRowCount);
364 maData.init(mnDataColCount,mnDataRowCount);
365
366 FormulaTokenMapMap::iterator it1 = rCols.begin();
367 for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol)
368 {
369 if (it1 != rCols.end())
370 {
371 FormulaTokenMap& rCol = it1->second;
372 FormulaTokenMap::iterator it2 = rCol.begin();
373 for (SCROW nRow = 0; nRow < nAllRowCount; ++nRow)
374 {
375 std::unique_ptr<FormulaToken> pToken;
376 if (it2 != rCol.end())
377 {
378 pToken = std::move(it2->second);
379 ++it2;
380 }
381
382 if( nCol < nHeaderColCount )
383 {
384 if( nRow < nHeaderRowCount )
385 maLeftUpperCorner.push_back(std::move(pToken));
386 else
387 maRowHeaders.push_back(std::move(pToken));
388 }
389 else if( nRow < nHeaderRowCount )
390 maColHeaders.push_back(std::move(pToken));
391 else
392 maData.push_back(std::move(pToken));
393 }
394 ++it1;
395 }
396 }
397}
398
399Chart2PositionMap::~Chart2PositionMap()
400{
401 maLeftUpperCorner.clear();
402 maColHeaders.clear();
403 maRowHeaders.clear();
404 maData.clear();
405}
406
407vector<ScTokenRef> Chart2PositionMap::getLeftUpperCornerRanges() const
408{
409 return maLeftUpperCorner.getAllRanges(mpDoc);
410}
411vector<ScTokenRef> Chart2PositionMap::getAllColHeaderRanges() const
412{
413 return maColHeaders.getAllRanges(mpDoc);
414}
415vector<ScTokenRef> Chart2PositionMap::getAllRowHeaderRanges() const
416{
417 return maRowHeaders.getAllRanges(mpDoc);
418}
419vector<ScTokenRef> Chart2PositionMap::getColHeaderRanges(SCCOL nCol) const
420{
421 return maColHeaders.getColRanges(mpDoc, nCol);
422}
423vector<ScTokenRef> Chart2PositionMap::getRowHeaderRanges(SCROW nRow) const
424{
425 return maRowHeaders.getRowRanges(mpDoc, nRow);
426}
427
428vector<ScTokenRef> Chart2PositionMap::getDataColRanges(SCCOL nCol) const
429{
430 return maData.getColRanges(mpDoc, nCol);
431}
432
433vector<ScTokenRef> Chart2PositionMap::getDataRowRanges(SCROW nRow) const
434{
435 return maData.getRowRanges(mpDoc, nRow);
436}
437
442class Chart2Positioner
443{
444 enum GlueType
445 {
446 GLUETYPE_NA,
447 GLUETYPE_NONE,
448 GLUETYPE_COLS,
449 GLUETYPE_ROWS,
450 GLUETYPE_BOTH
451 };
452
453public:
454 Chart2Positioner(const Chart2Positioner&) = delete;
455 const Chart2Positioner& operator=(const Chart2Positioner&) = delete;
456
457 Chart2Positioner(ScDocument* pDoc, const vector<ScTokenRef>& rRefTokens) :
458 mrRefTokens(rRefTokens),
459 meGlue(GLUETYPE_NA),
460 mnStartCol(0),
461 mnStartRow(0),
462 mpDoc(pDoc),
463 mbColHeaders(false),
464 mbRowHeaders(false),
465 mbDummyUpperLeft(false)
466 {
467 }
468
469 void setHeaders(bool bColHeaders, bool bRowHeaders)
470 {
471 mbColHeaders = bColHeaders;
472 mbRowHeaders = bRowHeaders;
473 }
474
475 Chart2PositionMap* getPositionMap()
476 {
477 createPositionMap();
478 return mpPositionMap.get();
479 }
480
481private:
482 void invalidateGlue();
483 void glueState();
484 void calcGlueState(SCCOL nCols, SCROW nRows);
485 void createPositionMap();
486
487private:
488 const vector<ScTokenRef>& mrRefTokens;
489 std::unique_ptr<Chart2PositionMap> mpPositionMap;
490 GlueType meGlue;
491 SCCOL mnStartCol;
492 SCROW mnStartRow;
493 ScDocument* mpDoc;
494 bool mbColHeaders:1;
495 bool mbRowHeaders:1;
496 bool mbDummyUpperLeft:1;
497};
498
499void Chart2Positioner::invalidateGlue()
500{
501 meGlue = GLUETYPE_NA;
502 mpPositionMap.reset();
503}
504
505void Chart2Positioner::glueState()
506{
507 if (meGlue != GLUETYPE_NA)
508 return;
509
510 mbDummyUpperLeft = false;
511 if (mrRefTokens.size() <= 1)
512 {
513 // Source data consists of only one data range.
514 const ScTokenRef& p = mrRefTokens.front();
517 {
518 if (aData.Ref1.Tab() == aData.Ref2.Tab())
519 meGlue = GLUETYPE_NONE;
520 else
521 meGlue = GLUETYPE_COLS;
522 mnStartCol = aData.Ref1.Col();
523 mnStartRow = aData.Ref1.Row();
524 }
525 else
526 {
527 invalidateGlue();
528 mnStartCol = 0;
529 mnStartRow = 0;
530 }
531 return;
532 }
533
535 if (!ScRefTokenHelper::getDoubleRefDataFromToken(aData, mrRefTokens.front()))
536 {
537 SAL_WARN("sc", "Chart2Positioner::glueState getDoubleRefDataFromToken failed");
538 invalidateGlue();
539 mnStartCol = 0;
540 mnStartRow = 0;
541 return;
542 }
543 mnStartCol = aData.Ref1.Col();
544 mnStartRow = aData.Ref1.Row();
545
546 SCCOL nEndCol = 0;
547 SCROW nEndRow = 0;
548 for (const auto& rxToken : mrRefTokens)
549 {
551 SCCOLROW n1 = aData.Ref1.Col();
552 SCCOLROW n2 = aData.Ref2.Col();
553 if (n1 > mpDoc->MaxCol())
554 n1 = mpDoc->MaxCol();
555 if (n2 > mpDoc->MaxCol())
556 n2 = mpDoc->MaxCol();
557 if (n1 < mnStartCol)
558 mnStartCol = static_cast<SCCOL>(n1);
559 if (n2 > nEndCol)
560 nEndCol = static_cast<SCCOL>(n2);
561
562 n1 = aData.Ref1.Row();
563 n2 = aData.Ref2.Row();
564 if (n1 > mpDoc->MaxRow())
565 n1 = mpDoc->MaxRow();
566 if (n2 > mpDoc->MaxRow())
567 n2 = mpDoc->MaxRow();
568
569 if (n1 < mnStartRow)
570 mnStartRow = static_cast<SCROW>(n1);
571 if (n2 > nEndRow)
572 nEndRow = static_cast<SCROW>(n2);
573 }
574
575 if (mnStartCol == nEndCol)
576 {
577 // All source data is in a single column.
578 meGlue = GLUETYPE_ROWS;
579 return;
580 }
581
582 if (mnStartRow == nEndRow)
583 {
584 // All source data is in a single row.
585 meGlue = GLUETYPE_COLS;
586 return;
587 }
588
589 // total column size
590 SCCOL nC = nEndCol - mnStartCol + 1;
591
592 // total row size
593 SCROW nR = nEndRow - mnStartRow + 1;
594
595 // #i103540# prevent invalid vector size
596 if ((nC <= 0) || (nR <= 0))
597 {
598 invalidateGlue();
599 mnStartCol = 0;
600 mnStartRow = 0;
601 return;
602 }
603
604 calcGlueState(nC, nR);
605}
606
607enum State { Hole = 0, Occupied = 1, Free = 2, Glue = 3 };
608
609void Chart2Positioner::calcGlueState(SCCOL nColSize, SCROW nRowSize)
610{
611 // TODO: This code can use some space optimization. Using an array to
612 // store individual cell's states is terribly inefficient esp for large
613 // data ranges; let's use flat_segment_tree to reduce memory usage here.
614
615 sal_uInt32 nCR = static_cast<sal_uInt32>(nColSize*nRowSize);
616
617 vector<State> aCellStates(nCR, Hole);
618
619 // Mark all referenced cells "occupied".
620 for (const auto& rxToken : mrRefTokens)
621 {
624 SCCOL nCol1 = aData.Ref1.Col() - mnStartCol;
625 SCCOL nCol2 = aData.Ref2.Col() - mnStartCol;
626 SCROW nRow1 = aData.Ref1.Row() - mnStartRow;
627 SCROW nRow2 = aData.Ref2.Row() - mnStartRow;
628 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
629 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
630 {
631 size_t i = nCol*nRowSize + nRow;
632 aCellStates[i] = Occupied;
633 }
634 }
635
636 // If at least one cell in either the first column or first row is empty,
637 // we don't glue at all unless the whole column or row is empty; we expect
638 // all cells in the first column / row to be fully populated. If we have
639 // empty column or row, then we do glue by the column or row,
640 // respectively.
641
642 bool bGlue = true;
643 bool bGlueCols = false;
644 for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol)
645 {
646 for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
647 {
648 size_t i = nCol*nRowSize + nRow;
649 if (aCellStates[i] == Occupied)
650 {
651 if (nCol == 0 || nRow == 0)
652 break;
653
654 bGlue = false;
655 }
656 else
657 aCellStates[i] = Free;
658 }
659 size_t nLast = (nCol+1)*nRowSize - 1; // index for the last cell in the column.
660 if (bGlue && aCellStates[nLast] == Free)
661 {
662 // Whole column is empty.
663 aCellStates[nLast] = Glue;
664 bGlueCols = true;
665 }
666 }
667
668 bool bGlueRows = false;
669 for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
670 {
671 size_t i = nRow;
672 for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol, i += nRowSize)
673 {
674 if (aCellStates[i] == Occupied)
675 {
676 if (nCol == 0 || nRow == 0)
677 break;
678
679 bGlue = false;
680 }
681 else
682 aCellStates[i] = Free;
683 }
684 i = (nColSize-1)*nRowSize + nRow; // index for the row position in the last column.
685 if (bGlue && aCellStates[i] == Free)
686 {
687 // Whole row is empty.
688 aCellStates[i] = Glue;
689 bGlueRows = true;
690 }
691 }
692
693 size_t i = 1;
694 for (sal_uInt32 n = 1; bGlue && n < nCR; ++n, ++i)
695 if (aCellStates[i] == Hole)
696 bGlue = false;
697
698 if (bGlue)
699 {
700 if (bGlueCols && bGlueRows)
701 meGlue = GLUETYPE_BOTH;
702 else if (bGlueRows)
703 meGlue = GLUETYPE_ROWS;
704 else
705 meGlue = GLUETYPE_COLS;
706 if (aCellStates.front() != Occupied)
707 mbDummyUpperLeft = true;
708 }
709 else
710 meGlue = GLUETYPE_NONE;
711}
712
713void Chart2Positioner::createPositionMap()
714{
715 if (meGlue == GLUETYPE_NA && mpPositionMap)
716 mpPositionMap.reset();
717
718 if (mpPositionMap)
719 return;
720
721 glueState();
722
723 bool bNoGlue = (meGlue == GLUETYPE_NONE);
724 FormulaTokenMapMap aCols;
725 SCROW nNoGlueRow = 0;
726 for (const ScTokenRef& pToken : mrRefTokens)
727 {
728 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
729 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
731 if (bExternal)
732 aTabName = pToken->GetString();
733
736 break;
737 const ScSingleRefData& s = aData.Ref1;
738 const ScSingleRefData& e = aData.Ref2;
739 SCCOL nCol1 = s.Col(), nCol2 = e.Col();
740 SCROW nRow1 = s.Row(), nRow2 = e.Row();
741 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
742
743 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
744 {
745 // columns on secondary sheets are appended; we treat them as if
746 // all columns are on the same sheet. TODO: We can't assume that
747 // the column range is 16-bit; remove that restriction.
748 sal_uInt32 nInsCol = (static_cast<sal_uInt32>(nTab) << 16) |
749 (bNoGlue ? 0 : static_cast<sal_uInt32>(nCol1));
750
751 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol)
752 {
753 FormulaTokenMap& rCol = aCols[nInsCol];
754
755 auto nInsRow = bNoGlue ? nNoGlueRow : nRow1;
756 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow, ++nInsRow)
757 {
758 ScSingleRefData aCellData;
759 aCellData.InitFlags();
760 aCellData.SetFlag3D(true);
761 aCellData.SetColRel(false);
762 aCellData.SetRowRel(false);
763 aCellData.SetTabRel(false);
764 aCellData.SetAbsCol(nCol);
765 aCellData.SetAbsRow(nRow);
766 aCellData.SetAbsTab(nTab);
767
768 auto& rCell = rCol[nInsRow];
769 if (!rCell)
770 {
771 if (bExternal)
772 rCell.reset(new ScExternalSingleRefToken(nFileId, aTabName, aCellData));
773 else
774 rCell.reset(new ScSingleRefToken(mpDoc->GetSheetLimits(), aCellData));
775 }
776 }
777 }
778 }
779 nNoGlueRow += nRow2 - nRow1 + 1;
780 }
781
782 bool bFillRowHeader = mbRowHeaders;
783 bool bFillColumnHeader = mbColHeaders;
784
785 SCSIZE nAllColCount = static_cast<SCSIZE>(aCols.size());
786 SCSIZE nAllRowCount = 0;
787 if (!aCols.empty())
788 {
789 FormulaTokenMap& rCol = aCols.begin()->second;
790 if (mbDummyUpperLeft)
791 rCol.try_emplace( 0, nullptr ); // dummy for labeling
792 nAllRowCount = static_cast<SCSIZE>(rCol.size());
793 }
794
795 if( nAllColCount!=0 && nAllRowCount!=0 )
796 {
797 if (bNoGlue)
798 {
799 FormulaTokenMap& rFirstCol = aCols.begin()->second;
800 for (const auto& rFirstColEntry : rFirstCol)
801 {
802 SCROW nKey = rFirstColEntry.first;
803 for (auto& rEntry : aCols)
804 {
805 FormulaTokenMap& rCol = rEntry.second;
806 rCol.try_emplace( nKey, nullptr );
807 }
808 }
809 }
810 }
811 mpPositionMap.reset(
812 new Chart2PositionMap(
813 static_cast<SCCOL>(nAllColCount), static_cast<SCROW>(nAllRowCount),
814 bFillRowHeader, bFillColumnHeader, aCols, mpDoc));
815}
816
820class Tokens2RangeString
821{
822public:
823 Tokens2RangeString(ScDocument& rDoc, FormulaGrammar::Grammar eGram, sal_Unicode cRangeSep) :
824 mpRangeStr(std::make_shared<OUStringBuffer>()),
825 mpDoc(&rDoc),
826 meGrammar(eGram),
827 mcRangeSep(cRangeSep),
828 mbFirst(true)
829 {
830 }
831
832 void operator() (const ScTokenRef& rToken)
833 {
834 ScCompiler aCompiler(*mpDoc, ScAddress(0,0,0), meGrammar);
835 OUString aStr;
836 aCompiler.CreateStringFromToken(aStr, rToken.get());
837 if (mbFirst)
838 mbFirst = false;
839 else
840 mpRangeStr->append(mcRangeSep);
841 mpRangeStr->append(aStr);
842 }
843
844 void getString(OUString& rStr)
845 {
846 rStr = mpRangeStr->makeStringAndClear();
847 }
848
849private:
850 shared_ptr<OUStringBuffer> mpRangeStr;
851 ScDocument* mpDoc;
852 FormulaGrammar::Grammar meGrammar;
853 sal_Unicode mcRangeSep;
854 bool mbFirst;
855};
856
865class Tokens2RangeStringXML
866{
867public:
868 explicit Tokens2RangeStringXML(ScDocument& rDoc) :
869 mpRangeStr(std::make_shared<OUStringBuffer>()),
870 mpDoc(&rDoc),
871 mbFirst(true)
872 {
873 }
874
875 void operator() (const ScTokenRef& rToken)
876 {
877 if (mbFirst)
878 mbFirst = false;
879 else
880 mpRangeStr->append(mcRangeSep);
881
882 ScTokenRef aStart, aEnd;
883 bool bValidToken = splitRangeToken(*mpDoc, rToken, aStart, aEnd);
884 // Check there is a valid reference in named range
885 if (!bValidToken && rToken->GetType() == svIndex && rToken->GetOpCode() == ocName)
886 {
887 ScRangeData* pNameRange = mpDoc->FindRangeNameBySheetAndIndex(rToken->GetSheet(), rToken->GetIndex());
888 if (pNameRange->HasReferences())
889 {
890 const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
891 bValidToken = splitRangeToken(*mpDoc, aTempToken, aStart, aEnd);
892 }
893 }
894
895 OSL_ENSURE(bValidToken, "invalid token");
896 if (!bValidToken)
897 return;
898
899 ScCompiler aCompiler(*mpDoc, ScAddress(0,0,0), FormulaGrammar::GRAM_ENGLISH);
900 {
901 OUString aStr;
902 aCompiler.CreateStringFromToken(aStr, aStart.get());
903 mpRangeStr->append(aStr);
904 }
905 mpRangeStr->append(mcAddrSep);
906 {
907 OUString aStr;
908 aCompiler.CreateStringFromToken(aStr, aEnd.get());
909 mpRangeStr->append(aStr);
910 }
911 }
912
913 void getString(OUString& rStr)
914 {
915 rStr = mpRangeStr->makeStringAndClear();
916 }
917
918private:
919 static bool splitRangeToken(const ScDocument& rDoc, const ScTokenRef& pToken, ScTokenRef& rStart, ScTokenRef& rEnd)
920 {
922 bool bIsRefToken = ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken);
923 OSL_ENSURE(bIsRefToken, "invalid token");
924 if (!bIsRefToken)
925 return false;
926 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
927 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
929 if (bExternal)
930 aTabName = pToken->GetString();
931
932 // In saving to XML, we don't prepend address with '$'.
933 setRelative(aData.Ref1);
934 setRelative(aData.Ref2);
935
936 // In XML, the range must explicitly specify sheet name.
937 aData.Ref1.SetFlag3D(true);
938 aData.Ref2.SetFlag3D(true);
939
940 if (bExternal)
941 rStart.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref1));
942 else
943 rStart.reset(new ScSingleRefToken(rDoc.GetSheetLimits(), aData.Ref1));
944
945 if (bExternal)
946 rEnd.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref2));
947 else
948 rEnd.reset(new ScSingleRefToken(rDoc.GetSheetLimits(), aData.Ref2));
949 return true;
950 }
951
952 static void setRelative(ScSingleRefData& rData)
953 {
954 rData.SetColRel(true);
955 rData.SetRowRel(true);
956 rData.SetTabRel(true);
957 }
958
959private:
960 shared_ptr<OUStringBuffer> mpRangeStr;
961 ScDocument* mpDoc;
962 static const sal_Unicode mcRangeSep = ' ';
963 static const sal_Unicode mcAddrSep = ':';
964 bool mbFirst;
965};
966
967void lcl_convertTokensToString(OUString& rStr, const vector<ScTokenRef>& rTokens, ScDocument& rDoc)
968{
970 FormulaGrammar::Grammar eGrammar = rDoc.GetGrammar();
971 Tokens2RangeString func(rDoc, eGrammar, cRangeSep);
972 func = ::std::for_each(rTokens.begin(), rTokens.end(), func);
973 func.getString(rStr);
974}
975
976} // anonymous namespace
977
978// DataProvider ==============================================================
979
981 : m_pDocument( pDoc)
982 , m_aPropSet(lcl_GetDataProviderPropertyMap())
983 , m_bIncludeHiddenCells( true)
984{
985 if ( m_pDocument )
986 m_pDocument->AddUnoObject( *this);
987}
988
990{
992
993 if ( m_pDocument )
995}
996
998{
999 if ( rHint.GetId() == SfxHintId::Dying )
1000 {
1001 m_pDocument = nullptr;
1002 }
1003}
1004
1005sal_Bool SAL_CALL ScChart2DataProvider::createDataSourcePossible( const uno::Sequence< beans::PropertyValue >& aArguments )
1006{
1007 SolarMutexGuard aGuard;
1008 if( ! m_pDocument )
1009 return false;
1010
1011 OUString aRangeRepresentation;
1012 for(const auto& rArgument : aArguments)
1013 {
1014 if ( rArgument.Name == "CellRangeRepresentation" )
1015 {
1016 rArgument.Value >>= aRangeRepresentation;
1017 }
1018 }
1019
1020 vector<ScTokenRef> aTokens;
1023 aTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1024 return !aTokens.empty();
1025}
1026
1027namespace
1028{
1029
1030uno::Reference< chart2::data::XLabeledDataSequence > lcl_createLabeledDataSequenceFromTokens(
1031 vector< ScTokenRef > && aValueTokens, vector< ScTokenRef > && aLabelTokens,
1032 ScDocument* pDoc, bool bIncludeHiddenCells )
1033{
1034 uno::Reference< chart2::data::XLabeledDataSequence > xResult;
1035 bool bHasValues = !aValueTokens.empty();
1036 bool bHasLabel = !aLabelTokens.empty();
1037 if( bHasValues || bHasLabel )
1038 {
1039 try
1040 {
1041 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1042 if ( xContext.is() )
1043 {
1044 xResult.set( chart2::data::LabeledDataSequence::create(xContext), uno::UNO_QUERY_THROW );
1045 }
1046 if ( bHasValues )
1047 {
1048 uno::Reference< chart2::data::XDataSequence > xSeq( new ScChart2DataSequence( pDoc, std::move(aValueTokens), bIncludeHiddenCells ) );
1049 xResult->setValues( xSeq );
1050 }
1051 if ( bHasLabel )
1052 {
1053 //Labels should always include hidden cells, regardless of the bIncludeHiddenCells setting
1054 uno::Reference< chart2::data::XDataSequence > xLabelSeq( new ScChart2DataSequence( pDoc, std::move(aLabelTokens), true ) );
1055 xResult->setLabel( xLabelSeq );
1056 }
1057 }
1058 catch( const uno::Exception& )
1059 {
1060 }
1061 }
1062 return xResult;
1063}
1064
1074bool lcl_addUpperLeftCornerIfMissing(const ScDocument* pDoc, vector<ScTokenRef>& rRefTokens,
1075 SCROW nCornerRowCount, SCCOL nCornerColumnCount)
1076{
1077 using ::std::max;
1078 using ::std::min;
1079
1080 if (rRefTokens.empty())
1081 return false;
1082
1083 SCCOL nMinCol = pDoc->GetSheetLimits().GetMaxColCount();
1084 SCROW nMinRow = pDoc->GetSheetLimits().GetMaxRowCount();
1085 SCCOL nMaxCol = 0;
1086 SCROW nMaxRow = 0;
1087 SCTAB nTab = 0;
1088
1089 sal_uInt16 nFileId = 0;
1090 svl::SharedString aExtTabName;
1091 bool bExternal = false;
1092
1093 vector<ScTokenRef>::const_iterator itr = rRefTokens.begin(), itrEnd = rRefTokens.end();
1094
1095 // Get the first ref token.
1096 ScTokenRef pToken = *itr;
1097 switch (pToken->GetType())
1098 {
1099 case svSingleRef:
1100 {
1101 const ScSingleRefData& rData = *pToken->GetSingleRef();
1102 nMinCol = rData.Col();
1103 nMinRow = rData.Row();
1104 nMaxCol = rData.Col();
1105 nMaxRow = rData.Row();
1106 nTab = rData.Tab();
1107 }
1108 break;
1109 case svDoubleRef:
1110 {
1111 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1112 nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1113 nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1114 nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1115 nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1116 nTab = rData.Ref1.Tab();
1117 }
1118 break;
1120 {
1121 const ScSingleRefData& rData = *pToken->GetSingleRef();
1122 nMinCol = rData.Col();
1123 nMinRow = rData.Row();
1124 nMaxCol = rData.Col();
1125 nMaxRow = rData.Row();
1126 nTab = rData.Tab();
1127 nFileId = pToken->GetIndex();
1128 aExtTabName = pToken->GetString();
1129 bExternal = true;
1130 }
1131 break;
1133 {
1134 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1135 nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1136 nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1137 nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1138 nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1139 nTab = rData.Ref1.Tab();
1140 nFileId = pToken->GetIndex();
1141 aExtTabName = pToken->GetString();
1142 bExternal = true;
1143 }
1144 break;
1145 default:
1146 ;
1147 }
1148
1149 // Determine the minimum range enclosing all data ranges. Also make sure
1150 // that they are all on the same table.
1151
1152 for (++itr; itr != itrEnd; ++itr)
1153 {
1154 pToken = *itr;
1155 switch (pToken->GetType())
1156 {
1157 case svSingleRef:
1158 {
1159 const ScSingleRefData& rData = *pToken->GetSingleRef();
1160
1161 nMinCol = min(nMinCol, rData.Col());
1162 nMinRow = min(nMinRow, rData.Row());
1163 nMaxCol = max(nMaxCol, rData.Col());
1164 nMaxRow = max(nMaxRow, rData.Row());
1165 if (nTab != rData.Tab() || bExternal)
1166 return false;
1167 }
1168 break;
1169 case svDoubleRef:
1170 {
1171 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1172
1173 nMinCol = min(nMinCol, rData.Ref1.Col());
1174 nMinCol = min(nMinCol, rData.Ref2.Col());
1175 nMinRow = min(nMinRow, rData.Ref1.Row());
1176 nMinRow = min(nMinRow, rData.Ref2.Row());
1177
1178 nMaxCol = max(nMaxCol, rData.Ref1.Col());
1179 nMaxCol = max(nMaxCol, rData.Ref2.Col());
1180 nMaxRow = max(nMaxRow, rData.Ref1.Row());
1181 nMaxRow = max(nMaxRow, rData.Ref2.Row());
1182
1183 if (nTab != rData.Ref1.Tab() || bExternal)
1184 return false;
1185 }
1186 break;
1188 {
1189 if (!bExternal)
1190 return false;
1191
1192 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1193 return false;
1194
1195 const ScSingleRefData& rData = *pToken->GetSingleRef();
1196
1197 nMinCol = min(nMinCol, rData.Col());
1198 nMinRow = min(nMinRow, rData.Row());
1199 nMaxCol = max(nMaxCol, rData.Col());
1200 nMaxRow = max(nMaxRow, rData.Row());
1201 }
1202 break;
1204 {
1205 if (!bExternal)
1206 return false;
1207
1208 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1209 return false;
1210
1211 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1212
1213 nMinCol = min(nMinCol, rData.Ref1.Col());
1214 nMinCol = min(nMinCol, rData.Ref2.Col());
1215 nMinRow = min(nMinRow, rData.Ref1.Row());
1216 nMinRow = min(nMinRow, rData.Ref2.Row());
1217
1218 nMaxCol = max(nMaxCol, rData.Ref1.Col());
1219 nMaxCol = max(nMaxCol, rData.Ref2.Col());
1220 nMaxRow = max(nMaxRow, rData.Ref1.Row());
1221 nMaxRow = max(nMaxRow, rData.Ref2.Row());
1222 }
1223 break;
1224 default:
1225 ;
1226 }
1227 }
1228
1229 const auto & rSheetLimits = pDoc->GetSheetLimits();
1230 if (nMinRow >= nMaxRow || nMinCol >= nMaxCol ||
1231 nMinRow >= rSheetLimits.GetMaxRowCount() || nMinCol >= rSheetLimits.GetMaxColCount() ||
1232 nMaxRow >= rSheetLimits.GetMaxRowCount() || nMaxCol >= rSheetLimits.GetMaxColCount())
1233 {
1234 // Invalid range. Bail out.
1235 return false;
1236 }
1237
1238 // Check if the following conditions are met:
1239
1240 // 1) The upper-left corner cell is not included.
1241 // 2) The three adjacent cells of that corner cell are included.
1242
1243 bool bRight = false, bBottom = false, bDiagonal = false;
1244 for (const auto& rxToken : rRefTokens)
1245 {
1246 switch (rxToken->GetType())
1247 {
1248 case svSingleRef:
1250 {
1251 const ScSingleRefData& rData = *rxToken->GetSingleRef();
1252 if (rData.Col() == nMinCol && rData.Row() == nMinRow)
1253 // The corner cell is contained.
1254 return false;
1255
1256 if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow)
1257 bRight = true;
1258
1259 if (rData.Col() == nMinCol && rData.Row() == nMinRow+nCornerRowCount)
1260 bBottom = true;
1261
1262 if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow+nCornerRowCount)
1263 bDiagonal = true;
1264 }
1265 break;
1266 case svDoubleRef:
1268 {
1269 const ScComplexRefData& rData = *rxToken->GetDoubleRef();
1270 const ScSingleRefData& r1 = rData.Ref1;
1271 const ScSingleRefData& r2 = rData.Ref2;
1272 if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1273 r1.Row() <= nMinRow && nMinRow <= r2.Row())
1274 // The corner cell is contained.
1275 return false;
1276
1277 if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1278 r1.Row() <= nMinRow && nMinRow <= r2.Row())
1279 bRight = true;
1280
1281 if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1282 r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1283 bBottom = true;
1284
1285 if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1286 r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1287 bDiagonal = true;
1288 }
1289 break;
1290 default:
1291 ;
1292 }
1293 }
1294
1295 if (!bRight || !bBottom || !bDiagonal)
1296 // Not all the adjacent cells are included. Bail out.
1297 return false;
1298
1300 aData.InitFlags();
1301 aData.SetFlag3D(true);
1302 aData.SetAbsCol(nMinCol);
1303 aData.SetAbsRow(nMinRow);
1304 aData.SetAbsTab(nTab);
1305
1306 if( nCornerRowCount==1 && nCornerColumnCount==1 )
1307 {
1308 if (bExternal)
1309 {
1310 ScTokenRef pCorner(
1311 new ScExternalSingleRefToken(nFileId, aExtTabName, aData));
1312 ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1313 }
1314 else
1315 {
1316 ScTokenRef pCorner(new ScSingleRefToken(pDoc->GetSheetLimits(), aData));
1317 ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1318 }
1319 }
1320 else
1321 {
1322 ScSingleRefData aDataEnd(aData);
1323 aDataEnd.IncCol(nCornerColumnCount-1);
1324 aDataEnd.IncRow(nCornerRowCount-1);
1326 r.Ref1=aData;
1327 r.Ref2=aDataEnd;
1328 if (bExternal)
1329 {
1330 ScTokenRef pCorner(
1331 new ScExternalDoubleRefToken(nFileId, aExtTabName, r));
1332 ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1333 }
1334 else
1335 {
1336 ScTokenRef pCorner(new ScDoubleRefToken(pDoc->GetSheetLimits(), r));
1337 ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1338 }
1339 }
1340
1341 return true;
1342}
1343
1344#define SHRINK_RANGE_THRESHOLD 10000
1345
1346class ShrinkRefTokenToDataRange
1347{
1348 ScDocument* mpDoc;
1349public:
1350 explicit ShrinkRefTokenToDataRange(ScDocument* pDoc) : mpDoc(pDoc) {}
1351 void operator() (const ScTokenRef& rRef)
1352 {
1354 return;
1355
1356 // Don't assume an ScDoubleRefToken if it isn't. It can be at least an
1357 // ScSingleRefToken, then there isn't anything to shrink.
1358 if (rRef->GetType() != svDoubleRef)
1359 return;
1360
1361 ScComplexRefData& rData = *rRef->GetDoubleRef();
1362 ScSingleRefData& s = rData.Ref1;
1363 ScSingleRefData& e = rData.Ref2;
1364
1365 if(abs((e.Col()-s.Col())*(e.Row()-s.Row())) < SHRINK_RANGE_THRESHOLD)
1366 return;
1367
1368 SCCOL nMinCol = mpDoc->MaxCol(), nMaxCol = 0;
1369 SCROW nMinRow = mpDoc->MaxRow(), nMaxRow = 0;
1370
1371 // Determine the smallest range that encompasses the data ranges of all sheets.
1372 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
1373 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
1374 {
1375 SCCOL nCol1 = 0, nCol2 = mpDoc->MaxCol();
1376 SCROW nRow1 = 0, nRow2 = mpDoc->MaxRow();
1377 mpDoc->ShrinkToDataArea(nTab, nCol1, nRow1, nCol2, nRow2);
1378 nMinCol = std::min(nMinCol, nCol1);
1379 nMinRow = std::min(nMinRow, nRow1);
1380 nMaxCol = std::max(nMaxCol, nCol2);
1381 nMaxRow = std::max(nMaxRow, nRow2);
1382 }
1383
1384 // Shrink range to the data range if applicable.
1385 if (s.Col() < nMinCol)
1386 s.SetAbsCol(nMinCol);
1387 if (s.Row() < nMinRow)
1388 s.SetAbsRow(nMinRow);
1389 if (e.Col() > nMaxCol)
1390 e.SetAbsCol(nMaxCol);
1391 if (e.Row() > nMaxRow)
1392 e.SetAbsRow(nMaxRow);
1393 }
1394};
1395
1396void shrinkToDataRange(ScDocument* pDoc, vector<ScTokenRef>& rRefTokens)
1397{
1398 std::for_each(rRefTokens.begin(), rRefTokens.end(), ShrinkRefTokenToDataRange(pDoc));
1399}
1400
1401}
1402
1403uno::Reference< chart2::data::XDataSource> SAL_CALL
1405 const uno::Sequence< beans::PropertyValue >& aArguments )
1406{
1407 SolarMutexGuard aGuard;
1408 if ( ! m_pDocument )
1409 throw uno::RuntimeException();
1410
1411 uno::Reference< chart2::data::XDataSource> xResult;
1412 bool bLabel = true;
1413 bool bCategories = false;
1414 bool bOrientCol = true;
1415 OUString aRangeRepresentation;
1416 uno::Sequence< sal_Int32 > aSequenceMapping;
1417 bool bTimeBased = false;
1418 for(const auto& rArgument : aArguments)
1419 {
1420 if ( rArgument.Name == "DataRowSource" )
1421 {
1422 chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
1423 if( ! (rArgument.Value >>= eSource))
1424 {
1425 sal_Int32 nSource(0);
1426 if( rArgument.Value >>= nSource )
1427 eSource = static_cast< chart::ChartDataRowSource >( nSource );
1428 }
1429 bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
1430 }
1431 else if ( rArgument.Name == "FirstCellAsLabel" )
1432 {
1433 bLabel = ::cppu::any2bool(rArgument.Value);
1434 }
1435 else if ( rArgument.Name == "HasCategories" )
1436 {
1437 bCategories = ::cppu::any2bool(rArgument.Value);
1438 }
1439 else if ( rArgument.Name == "CellRangeRepresentation" )
1440 {
1441 rArgument.Value >>= aRangeRepresentation;
1442 }
1443 else if ( rArgument.Name == "SequenceMapping" )
1444 {
1445 rArgument.Value >>= aSequenceMapping;
1446 }
1447 else if ( rArgument.Name == "TimeBased" )
1448 {
1449 rArgument.Value >>= bTimeBased;
1450 }
1451 }
1452
1453 vector<ScTokenRef> aRefTokens;
1456 aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1457 if (aRefTokens.empty())
1458 // Invalid range representation. Bail out.
1459 throw lang::IllegalArgumentException();
1460
1461 SCTAB nTimeBasedStart = MAXTAB;
1462 SCTAB nTimeBasedEnd = 0;
1463 if(bTimeBased)
1464 {
1465 // limit to first sheet
1466 for(const auto& rxToken : aRefTokens)
1467 {
1468 if (rxToken->GetType() != svDoubleRef)
1469 continue;
1470
1471 ScComplexRefData& rData = *rxToken->GetDoubleRef();
1472 ScSingleRefData& s = rData.Ref1;
1473 ScSingleRefData& e = rData.Ref2;
1474
1475 nTimeBasedStart = std::min(nTimeBasedStart, s.Tab());
1476 nTimeBasedEnd = std::min(nTimeBasedEnd, e.Tab());
1477
1478 if(s.Tab() != e.Tab())
1479 e.SetAbsTab(s.Tab());
1480 }
1481 }
1482
1483 if(!bTimeBased)
1484 shrinkToDataRange(m_pDocument, aRefTokens);
1485
1486 if (bLabel)
1487 lcl_addUpperLeftCornerIfMissing(m_pDocument, aRefTokens, 1, 1); //#i90669#
1488
1489 bool bColHeaders = (bOrientCol ? bLabel : bCategories );
1490 bool bRowHeaders = (bOrientCol ? bCategories : bLabel );
1491
1492 Chart2Positioner aChPositioner(m_pDocument, aRefTokens);
1493 aChPositioner.setHeaders(bColHeaders, bRowHeaders);
1494
1495 const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap();
1496 if (!pChartMap)
1497 // No chart position map instance. Bail out.
1498 return xResult;
1499
1501 ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqs;
1502
1503 // Fill Categories
1504 if( bCategories )
1505 {
1506 vector<ScTokenRef> aValueTokens;
1507 if (bOrientCol)
1508 aValueTokens = pChartMap->getAllRowHeaderRanges();
1509 else
1510 aValueTokens = pChartMap->getAllColHeaderRanges();
1511
1512 vector<ScTokenRef> aLabelTokens(
1513 pChartMap->getLeftUpperCornerRanges());
1514
1515 uno::Reference< chart2::data::XLabeledDataSequence > xCategories = lcl_createLabeledDataSequenceFromTokens(
1516 std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1517 if ( xCategories.is() )
1518 {
1519 aSeqs.push_back( xCategories );
1520 }
1521 }
1522
1523 // Fill Series (values and label)
1524 sal_Int32 nCount = bOrientCol ? pChartMap->getDataColCount() : pChartMap->getDataRowCount();
1525 for (sal_Int32 i = 0; i < nCount; ++i)
1526 {
1527 vector<ScTokenRef> aValueTokens;
1528 vector<ScTokenRef> aLabelTokens;
1529 if (bOrientCol)
1530 {
1531 aValueTokens = pChartMap->getDataColRanges(static_cast<SCCOL>(i));
1532 aLabelTokens = pChartMap->getColHeaderRanges(static_cast<SCCOL>(i));
1533 }
1534 else
1535 {
1536 aValueTokens = pChartMap->getDataRowRanges(static_cast<SCROW>(i));
1537 aLabelTokens = pChartMap->getRowHeaderRanges(static_cast<SCROW>(i));
1538 }
1539 uno::Reference< chart2::data::XLabeledDataSequence > xChartSeries = lcl_createLabeledDataSequenceFromTokens(
1540 std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1541 if ( xChartSeries.is() && xChartSeries->getValues().is() && xChartSeries->getValues()->getData().hasElements() )
1542 {
1543 aSeqs.push_back( xChartSeries );
1544 }
1545 }
1546
1548
1549 //reorder labeled sequences according to aSequenceMapping
1550 ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqVector;
1551 aSeqVector.reserve(aSeqs.size());
1552 for (auto const& aSeq : aSeqs)
1553 {
1554 aSeqVector.push_back(aSeq);
1555 }
1556
1557 for( const sal_Int32 nNewIndex : std::as_const(aSequenceMapping) )
1558 {
1559 // note: assuming that the values in the sequence mapping are always non-negative
1560 ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > >::size_type nOldIndex( static_cast< sal_uInt32 >( nNewIndex ) );
1561 if( nOldIndex < aSeqVector.size() )
1562 {
1563 pDS->AddLabeledSequence( aSeqVector[nOldIndex] );
1564 aSeqVector[nOldIndex] = nullptr;
1565 }
1566 }
1567
1568 for(const uno::Reference< chart2::data::XLabeledDataSequence >& xSeq : aSeqVector)
1569 {
1570 if ( xSeq.is() )
1571 {
1572 pDS->AddLabeledSequence( xSeq );
1573 }
1574 }
1575
1576 xResult.set( pDS );
1577 return xResult;
1578}
1579
1580namespace
1581{
1582
1586class InsertTabNumber
1587{
1588public:
1589 InsertTabNumber() :
1590 mpTabNumVector(std::make_shared<vector<SCTAB>>())
1591 {
1592 }
1593
1594 void operator() (const ScTokenRef& pToken) const
1595 {
1596 if (!ScRefTokenHelper::isRef(pToken))
1597 return;
1598
1599 const ScSingleRefData& r = *pToken->GetSingleRef();
1600 mpTabNumVector->push_back(r.Tab());
1601 }
1602
1603 void getVector(vector<SCTAB>& rVector)
1604 {
1605 mpTabNumVector->swap(rVector);
1606 }
1607private:
1608 shared_ptr< vector<SCTAB> > mpTabNumVector;
1609};
1610
1611class RangeAnalyzer
1612{
1613public:
1614 RangeAnalyzer();
1615 void initRangeAnalyzer( const ScDocument* pDoc, const vector<ScTokenRef>& rTokens );
1616 void analyzeRange( sal_Int32& rnDataInRows, sal_Int32& rnDataInCols,
1617 bool& rbRowSourceAmbiguous ) const;
1618 bool inSameSingleRow( const RangeAnalyzer& rOther );
1619 bool inSameSingleColumn( const RangeAnalyzer& rOther );
1620 SCROW getRowCount() const { return mnRowCount; }
1621 SCCOL getColumnCount() const { return mnColumnCount; }
1622
1623private:
1624 bool mbEmpty;
1625 bool mbAmbiguous;
1626 SCROW mnRowCount;
1627 SCCOL mnColumnCount;
1628
1629 SCCOL mnStartColumn;
1630 SCROW mnStartRow;
1631};
1632
1633RangeAnalyzer::RangeAnalyzer()
1634 : mbEmpty(true)
1635 , mbAmbiguous(false)
1636 , mnRowCount(0)
1637 , mnColumnCount(0)
1638 , mnStartColumn(-1)
1639 , mnStartRow(-1)
1640{
1641}
1642
1643void RangeAnalyzer::initRangeAnalyzer( const ScDocument* pDoc, const vector<ScTokenRef>& rTokens )
1644{
1645 mnRowCount=0;
1646 mnColumnCount=0;
1647 mnStartColumn = -1;
1648 mnStartRow = -1;
1649 mbAmbiguous=false;
1650 if( rTokens.empty() )
1651 {
1652 mbEmpty=true;
1653 return;
1654 }
1655 mbEmpty=false;
1656
1657 for (const ScTokenRef& aRefToken : rTokens)
1658 {
1659 StackVar eVar = aRefToken->GetType();
1660 if (eVar == svDoubleRef || eVar == svExternalDoubleRef)
1661 {
1662 const ScComplexRefData& r = *aRefToken->GetDoubleRef();
1663 if (r.Ref1.Tab() == r.Ref2.Tab())
1664 {
1665 mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(r.Ref2.Col() - r.Ref1.Col())+1));
1666 mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(r.Ref2.Row() - r.Ref1.Row())+1));
1667 if( mnStartColumn == -1 )
1668 {
1669 mnStartColumn = r.Ref1.Col();
1670 mnStartRow = r.Ref1.Row();
1671 }
1672 else
1673 {
1674 if (mnStartColumn != r.Ref1.Col() && mnStartRow != r.Ref1.Row())
1675 mbAmbiguous=true;
1676 }
1677 }
1678 else
1679 mbAmbiguous=true;
1680 }
1681 else if (eVar == svSingleRef || eVar == svExternalSingleRef)
1682 {
1683 const ScSingleRefData& r = *aRefToken->GetSingleRef();
1684 mnColumnCount = std::max<SCCOL>( mnColumnCount, 1);
1685 mnRowCount = std::max<SCROW>( mnRowCount, 1);
1686 if( mnStartColumn == -1 )
1687 {
1688 mnStartColumn = r.Col();
1689 mnStartRow = r.Row();
1690 }
1691 else
1692 {
1693 if (mnStartColumn != r.Col() && mnStartRow != r.Row())
1694 mbAmbiguous=true;
1695 }
1696 }
1697 else if (eVar == svIndex && aRefToken->GetOpCode() == ocName)
1698 {
1699 ScRangeData* pNameRange = pDoc->FindRangeNameBySheetAndIndex(aRefToken->GetSheet(), aRefToken->GetIndex());
1700 ScRange aRange;
1701 if (pNameRange->IsReference(aRange))
1702 {
1703 mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(aRange.aEnd.Col() - aRange.aStart.Col()) + 1));
1704 mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(aRange.aEnd.Row() - aRange.aStart.Row()) + 1));
1705 if (mnStartColumn == -1)
1706 {
1707 mnStartColumn = aRange.aStart.Col();
1708 mnStartRow = aRange.aStart.Row();
1709 }
1710 else
1711 {
1712 if (mnStartColumn != aRange.aStart.Col() && mnStartRow != aRange.aStart.Row())
1713 mbAmbiguous = true;
1714 }
1715 }
1716 else
1717 mbAmbiguous = true;
1718 }
1719 else
1720 mbAmbiguous=true;
1721 }
1722}
1723
1724void RangeAnalyzer::analyzeRange( sal_Int32& rnDataInRows,
1725 sal_Int32& rnDataInCols,
1726 bool& rbRowSourceAmbiguous ) const
1727{
1728 if(!mbEmpty && !mbAmbiguous)
1729 {
1730 if( mnRowCount==1 && mnColumnCount>1 )
1731 ++rnDataInRows;
1732 else if( mnColumnCount==1 && mnRowCount>1 )
1733 ++rnDataInCols;
1734 else if( mnRowCount>1 && mnColumnCount>1 )
1735 rbRowSourceAmbiguous = true;
1736 }
1737 else if( !mbEmpty )
1738 rbRowSourceAmbiguous = true;
1739}
1740
1741bool RangeAnalyzer::inSameSingleRow( const RangeAnalyzer& rOther )
1742{
1743 return mnStartRow==rOther.mnStartRow &&
1744 mnRowCount==1 && rOther.mnRowCount==1;
1745}
1746
1747bool RangeAnalyzer::inSameSingleColumn( const RangeAnalyzer& rOther )
1748{
1749 return mnStartColumn==rOther.mnStartColumn &&
1750 mnColumnCount==1 && rOther.mnColumnCount==1;
1751}
1752
1753std::pair<OUString, OUString> constructKey(const uno::Reference< chart2::data::XLabeledDataSequence>& xNew)
1754{
1755 std::pair<OUString, OUString> aKey;
1756 if( xNew->getLabel().is() )
1757 aKey.first = xNew->getLabel()->getSourceRangeRepresentation();
1758 if( xNew->getValues().is() )
1759 aKey.second = xNew->getValues()->getSourceRangeRepresentation();
1760 return aKey;
1761}
1762
1763
1764} //end anonymous namespace
1765
1766uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments(
1767 const uno::Reference< chart2::data::XDataSource >& xDataSource )
1768{
1769 ::std::vector< beans::PropertyValue > aResult;
1770 bool bRowSourceDetected = false;
1771 bool bFirstCellAsLabel = false;
1772 bool bHasCategories = false;
1773 OUString sRangeRep;
1774
1775 bool bHasCategoriesLabels = false;
1776 vector<ScTokenRef> aAllCategoriesValuesTokens;
1777 vector<ScTokenRef> aAllSeriesLabelTokens;
1778
1779 chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS;
1780
1781 vector<ScTokenRef> aAllTokens;
1782
1783 // parse given data source and collect infos
1784 {
1785 SolarMutexGuard aGuard;
1786 OSL_ENSURE( m_pDocument, "No Document -> no detectArguments" );
1787 if(!m_pDocument ||!xDataSource.is())
1788 return comphelper::containerToSequence( aResult );
1789
1790 sal_Int32 nDataInRows = 0;
1791 sal_Int32 nDataInCols = 0;
1792 bool bRowSourceAmbiguous = false;
1793
1794 const Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences());
1795 const sal_Int32 nCount( aSequences.getLength());
1796 RangeAnalyzer aPrevLabel,aPrevValues;
1797 for( const uno::Reference< chart2::data::XLabeledDataSequence >& xLS : aSequences )
1798 {
1799 if( xLS.is() )
1800 {
1801 bool bThisIsCategories = false;
1802 if(!bHasCategories)
1803 {
1804 uno::Reference< beans::XPropertySet > xSeqProp( xLS->getValues(), uno::UNO_QUERY );
1805 OUString aRole;
1806 if( xSeqProp.is() && (xSeqProp->getPropertyValue("Role") >>= aRole) &&
1807 aRole == "categories" )
1808 bThisIsCategories = bHasCategories = true;
1809 }
1810
1811 RangeAnalyzer aLabel,aValues;
1812 // label
1813 uno::Reference< chart2::data::XDataSequence > xLabel( xLS->getLabel());
1814 if( xLabel.is())
1815 {
1816 bFirstCellAsLabel = true;
1817 vector<ScTokenRef> aTokens;
1820 aTokens, xLabel->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1821 aLabel.initRangeAnalyzer(m_pDocument, aTokens);
1822 for (const auto& rxToken : aTokens)
1823 {
1824 if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
1825 {
1826 ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
1827 if (pNameRange->HasReferences())
1828 {
1829 const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
1830 ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
1831 }
1832 else
1833 ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1834 }
1835 else
1836 ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1837 if(!bThisIsCategories)
1838 ScRefTokenHelper::join(m_pDocument, aAllSeriesLabelTokens, rxToken, ScAddress());
1839 }
1840 if(bThisIsCategories)
1841 bHasCategoriesLabels=true;
1842 }
1843 // values
1844 uno::Reference< chart2::data::XDataSequence > xValues( xLS->getValues());
1845 if( xValues.is())
1846 {
1847 vector<ScTokenRef> aTokens;
1850 aTokens, xValues->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1851 aValues.initRangeAnalyzer(m_pDocument, aTokens);
1852 for (const auto& rxToken : aTokens)
1853 {
1854 if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
1855 {
1856 ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
1857 if (pNameRange->HasReferences())
1858 {
1859 const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
1860 ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
1861 }
1862 else
1863 ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1864 }
1865 else
1866 ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1867 if(bThisIsCategories)
1868 ScRefTokenHelper::join(m_pDocument, aAllCategoriesValuesTokens, rxToken, ScAddress());
1869 }
1870 }
1871 //detect row source
1872 if(!bThisIsCategories || nCount==1) //categories might span multiple rows *and* columns, so they should be used for detection only if nothing else is available
1873 {
1874 if (!bRowSourceAmbiguous)
1875 {
1876 aValues.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1877 aLabel.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1878 if (nDataInRows > 1 && nDataInCols > 1)
1879 bRowSourceAmbiguous = true;
1880 else if( !bRowSourceAmbiguous && !nDataInRows && !nDataInCols )
1881 {
1882 if( aValues.inSameSingleColumn( aLabel ) )
1883 nDataInCols++;
1884 else if( aValues.inSameSingleRow( aLabel ) )
1885 nDataInRows++;
1886 else
1887 {
1888 //#i86188# also detect a single column split into rows correctly
1889 if( aValues.inSameSingleColumn( aPrevValues ) )
1890 nDataInRows++;
1891 else if( aValues.inSameSingleRow( aPrevValues ) )
1892 nDataInCols++;
1893 else if( aLabel.inSameSingleColumn( aPrevLabel ) )
1894 nDataInRows++;
1895 else if( aLabel.inSameSingleRow( aPrevLabel ) )
1896 nDataInCols++;
1897 }
1898 }
1899 }
1900 }
1901 aPrevValues=aValues;
1902 aPrevLabel=aLabel;
1903 }
1904 }
1905
1906 if (!bRowSourceAmbiguous)
1907 {
1908 bRowSourceDetected = true;
1909 eRowSource = ( nDataInCols > 0
1910 ? chart::ChartDataRowSource_COLUMNS
1911 : chart::ChartDataRowSource_ROWS );
1912 }
1913 else
1914 {
1915 // set DataRowSource to the better of the two ambiguities
1916 eRowSource = ( nDataInRows > nDataInCols
1917 ? chart::ChartDataRowSource_ROWS
1918 : chart::ChartDataRowSource_COLUMNS );
1919 }
1920
1921 }
1922
1923 // TableNumberList
1924 {
1925 vector<SCTAB> aTableNumVector;
1926 InsertTabNumber func;
1927 func = ::std::for_each(aAllTokens.begin(), aAllTokens.end(), func);
1928 func.getVector(aTableNumVector);
1929 aResult.emplace_back( "TableNumberList", -1,
1930 uno::Any( lcl_createTableNumberList( aTableNumVector ) ),
1931 beans::PropertyState_DIRECT_VALUE );
1932 }
1933
1934 if( bRowSourceDetected )
1935 {
1936 // DataRowSource (calculated before)
1937 aResult.emplace_back( "DataRowSource", -1,
1938 uno::Any( eRowSource ), beans::PropertyState_DIRECT_VALUE );
1939 // HasCategories
1940 aResult.emplace_back( "HasCategories", -1,
1941 uno::Any( bHasCategories ), beans::PropertyState_DIRECT_VALUE );
1942 // FirstCellAsLabel
1943 aResult.emplace_back( "FirstCellAsLabel", -1,
1944 uno::Any( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE );
1945 }
1946
1947 // Add the left upper corner to the range if it is missing.
1948 if (bRowSourceDetected && bFirstCellAsLabel && bHasCategories && !bHasCategoriesLabels )
1949 {
1950 RangeAnalyzer aTop,aLeft;
1951 if( eRowSource==chart::ChartDataRowSource_COLUMNS )
1952 {
1953 aTop.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
1954 aLeft.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
1955 }
1956 else
1957 {
1958 aTop.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
1959 aLeft.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
1960 }
1961 lcl_addUpperLeftCornerIfMissing(m_pDocument, aAllTokens, aTop.getRowCount(), aLeft.getColumnCount());//e.g. #i91212#
1962 }
1963
1964 // Get range string.
1965 lcl_convertTokensToString(sRangeRep, aAllTokens, *m_pDocument);
1966
1967 // add cell range property
1968 aResult.emplace_back( "CellRangeRepresentation", -1,
1969 uno::Any( sRangeRep ), beans::PropertyState_DIRECT_VALUE );
1970
1971 //Sequence Mapping
1972 bool const bSequencesReordered = true;//todo detect this above or detect this sequence mapping cheaper ...
1973 if( bSequencesReordered && bRowSourceDetected )
1974 {
1975 bool bDifferentIndexes = false;
1976
1977 std::vector< sal_Int32 > aSequenceMappingVector;
1978
1979 uno::Reference< chart2::data::XDataSource > xCompareDataSource;
1980 try
1981 {
1982 xCompareDataSource.set( createDataSource( comphelper::containerToSequence( aResult ) ) );
1983 }
1984 catch( const lang::IllegalArgumentException & )
1985 {
1986 // creation of data source to compare didn't work, so we cannot
1987 // create a sequence mapping
1988 }
1989
1990 if( xDataSource.is() && xCompareDataSource.is() )
1991 {
1992 const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aOldSequences =
1993 xCompareDataSource->getDataSequences();
1994 const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aNewSequences =
1995 xDataSource->getDataSequences();
1996
1997 std::map<std::pair<OUString, OUString>,sal_Int32> aOldEntryToIndex;
1998 for( sal_Int32 nIndex = 0, n = aOldSequences.getLength(); nIndex < n; nIndex++ )
1999 {
2000 const uno::Reference< chart2::data::XLabeledDataSequence>& xOld( aOldSequences[nIndex] );
2001 if( xOld.is() )
2002 {
2003 std::pair<OUString, OUString> aKey = constructKey(xOld);
2004 aOldEntryToIndex[aKey] = nIndex;
2005 }
2006 }
2007
2008 for( sal_Int32 nNewIndex = 0, n = aNewSequences.getLength(); nNewIndex < n; nNewIndex++ )
2009 {
2010 const uno::Reference< chart2::data::XLabeledDataSequence>& xNew( aNewSequences[nNewIndex] );
2011 if( !xNew.is() )
2012 continue;
2013
2014 std::pair<OUString, OUString> aKey = constructKey(xNew);
2015 if (aOldEntryToIndex.find(aKey) == aOldEntryToIndex.end())
2016 continue;
2017
2018 sal_Int32 nOldIndex = aOldEntryToIndex[aKey];
2019 if( nOldIndex != nNewIndex )
2020 bDifferentIndexes = true;
2021
2022 aSequenceMappingVector.push_back(nOldIndex);
2023 }
2024 }
2025
2026 if( bDifferentIndexes && !aSequenceMappingVector.empty() )
2027 {
2028 aResult.emplace_back( "SequenceMapping", -1,
2029 uno::Any( comphelper::containerToSequence(aSequenceMappingVector) )
2030 , beans::PropertyState_DIRECT_VALUE );
2031 }
2032 }
2033
2034 return comphelper::containerToSequence( aResult );
2035}
2036
2038{
2039 SolarMutexGuard aGuard;
2040 if( ! m_pDocument )
2041 return false;
2042
2043 vector<ScTokenRef> aTokens;
2046 aTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2047 return !aTokens.empty();
2048}
2049
2050uno::Reference< chart2::data::XDataSequence > SAL_CALL
2052 const OUString& aRangeRepresentation )
2053{
2054 SolarMutexGuard aGuard;
2055 uno::Reference< chart2::data::XDataSequence > xResult;
2056
2057 OSL_ENSURE( m_pDocument, "No Document -> no createDataSequenceByRangeRepresentation" );
2058 if(!m_pDocument || aRangeRepresentation.isEmpty())
2059 return xResult;
2060
2061 vector<ScTokenRef> aRefTokens;
2064 aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2065 if (aRefTokens.empty())
2066 return xResult;
2067
2068 shrinkToDataRange(m_pDocument, aRefTokens);
2069
2070 xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
2071
2072 return xResult;
2073}
2074
2075uno::Reference<chart2::data::XDataSequence> SAL_CALL
2077 const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/,
2078 const OUString& /*aRoleQualifier*/ )
2079{
2080 return uno::Reference<chart2::data::XDataSequence>();
2081}
2082
2083uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRangeSelection()
2084{
2085 uno::Reference< sheet::XRangeSelection > xResult;
2086
2087 uno::Reference< frame::XModel > xModel( lcl_GetXModel( m_pDocument ));
2088 if( xModel.is())
2089 xResult.set( xModel->getCurrentController(), uno::UNO_QUERY );
2090
2091 return xResult;
2092}
2093
2095 const Sequence<sheet::FormulaToken>& aTokens )
2096{
2097 if (!aTokens.hasElements())
2098 return false;
2099
2100 ScTokenArray aCode(*m_pDocument);
2102 return false;
2103
2104 sal_uInt16 n = aCode.GetLen();
2105 if (!n)
2106 return false;
2107
2109 const formula::FormulaToken* pFirst = aIter.First();
2110 const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2111 for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
2112 {
2113 switch (p->GetType())
2114 {
2115 case svSep:
2116 {
2117 switch (p->GetOpCode())
2118 {
2119 case ocSep:
2120 // separators are allowed.
2121 break;
2122 case ocOpen:
2123 if (p != pFirst)
2124 // open paran is allowed only as the first token.
2125 return false;
2126 break;
2127 case ocClose:
2128 if (p != pLast)
2129 // close paren is allowed only as the last token.
2130 return false;
2131 break;
2132 default:
2133 return false;
2134 }
2135 }
2136 break;
2137 case svSingleRef:
2138 case svDoubleRef:
2141 break;
2142 default:
2143 return false;
2144 }
2145 }
2146
2147 return true;
2148}
2149
2150uno::Reference<chart2::data::XDataSequence> SAL_CALL
2152 const Sequence<sheet::FormulaToken>& aTokens )
2153{
2154 uno::Reference<chart2::data::XDataSequence> xResult;
2155 if (!aTokens.hasElements())
2156 return xResult;
2157
2158 ScTokenArray aCode(*m_pDocument);
2160 return xResult;
2161
2162 sal_uInt16 n = aCode.GetLen();
2163 if (!n)
2164 return xResult;
2165
2166 vector<ScTokenRef> aRefTokens;
2168 const formula::FormulaToken* pFirst = aIter.First();
2169 const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2170 for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
2171 {
2172 switch (p->GetType())
2173 {
2174 case svSep:
2175 {
2176 switch (p->GetOpCode())
2177 {
2178 case ocSep:
2179 // separators are allowed.
2180 break;
2181 case ocOpen:
2182 if (p != pFirst)
2183 // open paran is allowed only as the first token.
2184 throw lang::IllegalArgumentException();
2185 break;
2186 case ocClose:
2187 if (p != pLast)
2188 // close paren is allowed only as the last token.
2189 throw lang::IllegalArgumentException();
2190 break;
2191 default:
2192 throw lang::IllegalArgumentException();
2193 }
2194 }
2195 break;
2196 case svIndex:
2197 case svString:
2198 case svSingleRef:
2199 case svDoubleRef:
2202 {
2203 ScTokenRef pNew(p->Clone());
2204 aRefTokens.push_back(pNew);
2205 }
2206 break;
2207 default:
2208 throw lang::IllegalArgumentException();
2209 }
2210 }
2211
2212 if (aRefTokens.empty())
2213 return xResult;
2214
2215 shrinkToDataRange(m_pDocument, aRefTokens);
2216
2217 xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
2218 return xResult;
2219}
2220
2221// XRangeXMLConversion ---------------------------------------------------
2222
2223OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const OUString& sRangeRepresentation )
2224{
2225 OUString aRet;
2226 if (!m_pDocument)
2227 return aRet;
2228
2229 if (sRangeRepresentation.isEmpty())
2230 // Empty data range is allowed.
2231 return aRet;
2232
2233 vector<ScTokenRef> aRefTokens;
2236 aRefTokens, sRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2237 if (aRefTokens.empty())
2238 {
2239 SAL_WARN("sc", "convertRangeToXML throw IllegalArgumentException from input of: " << sRangeRepresentation);
2240 throw lang::IllegalArgumentException();
2241 }
2242
2243 Tokens2RangeStringXML converter(*m_pDocument);
2244 converter = ::std::for_each(aRefTokens.begin(), aRefTokens.end(), converter);
2245 converter.getString(aRet);
2246
2247 return aRet;
2248}
2249
2250OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const OUString& sXMLRange )
2251{
2252 if (!m_pDocument)
2253 {
2254 // #i74062# When loading flat XML, this is called before the referenced sheets are in the document,
2255 // so the conversion has to take place directly with the strings, without looking up the sheets.
2256
2257 OUStringBuffer sRet;
2258 sal_Int32 nOffset = 0;
2259 while( nOffset >= 0 )
2260 {
2261 OUString sToken;
2262 ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset );
2263 if( nOffset >= 0 )
2264 {
2265 // convert one address (remove dots)
2266
2267 OUString aUIString(sToken);
2268
2269 sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0 );
2270 if ( nIndex >= 0 && nIndex < aUIString.getLength() - 1 &&
2271 aUIString[nIndex + 1] == '.' )
2272 aUIString = aUIString.replaceAt( nIndex + 1, 1, u"" );
2273
2274 if ( aUIString[0] == '.' )
2275 aUIString = aUIString.copy( 1 );
2276
2277 if( !sRet.isEmpty() )
2278 sRet.append( ';' );
2279 sRet.append( aUIString );
2280 }
2281 }
2282
2283 return sRet.makeStringAndClear();
2284 }
2285
2286 OUString aRet;
2288 return aRet;
2289}
2290
2291// DataProvider XPropertySet -------------------------------------------------
2292
2293uno::Reference< beans::XPropertySetInfo> SAL_CALL
2295{
2296 SolarMutexGuard aGuard;
2297 static uno::Reference<beans::XPropertySetInfo> aRef =
2299 return aRef;
2300}
2301
2303 const OUString& rPropertyName, const uno::Any& rValue)
2304{
2305 if ( rPropertyName != SC_UNONAME_INCLUDEHIDDENCELLS )
2306 throw beans::UnknownPropertyException(rPropertyName);
2307
2308 if ( !(rValue >>= m_bIncludeHiddenCells))
2309 throw lang::IllegalArgumentException();
2310
2311}
2312
2314 const OUString& rPropertyName)
2315{
2316 uno::Any aRet;
2317 if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2318 aRet <<= m_bIncludeHiddenCells;
2319 else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
2320 {
2321 // This is a read-only property.
2323 }
2324 else
2325 throw beans::UnknownPropertyException(rPropertyName);
2326 return aRet;
2327}
2328
2330 const OUString& /*rPropertyName*/,
2331 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
2332{
2333 OSL_FAIL( "Not yet implemented" );
2334}
2335
2337 const OUString& /*rPropertyName*/,
2338 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
2339{
2340 OSL_FAIL( "Not yet implemented" );
2341}
2342
2344 const OUString& /*rPropertyName*/,
2345 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
2346{
2347 OSL_FAIL( "Not yet implemented" );
2348}
2349
2351 const OUString& /*rPropertyName*/,
2352 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/ )
2353{
2354 OSL_FAIL( "Not yet implemented" );
2355}
2356
2357// DataSource ================================================================
2358
2360 : m_pDocument( pDoc)
2361{
2362 if ( m_pDocument )
2363 m_pDocument->AddUnoObject( *this);
2364}
2365
2367{
2369
2370 if ( m_pDocument )
2372}
2373
2375{
2376 if ( rHint.GetId() == SfxHintId::Dying )
2377 {
2378 m_pDocument = nullptr;
2379 }
2380}
2381
2382uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > SAL_CALL
2384{
2385 SolarMutexGuard aGuard;
2387}
2388
2389void ScChart2DataSource::AddLabeledSequence(const uno::Reference < chart2::data::XLabeledDataSequence >& xNew)
2390{
2391 m_aLabeledSequences.push_back(xNew);
2392}
2393
2394// DataSequence ==============================================================
2395
2397 : mfValue(std::numeric_limits<double>::quiet_NaN())
2398 , mbIsValue(false)
2399{
2400}
2401
2403 mrParent(rParent)
2404{
2405}
2406
2408{
2409}
2410
2412{
2413 mrParent.setDataChangedHint(true);
2414}
2415
2417 vector<ScTokenRef>&& rTokens,
2418 bool bIncludeHiddenCells )
2419 : m_xDataArray(new std::vector<Item>)
2420 , m_bIncludeHiddenCells( bIncludeHiddenCells)
2421 , m_nObjectId( 0 )
2422 , m_pDocument( pDoc)
2423 , m_aTokens(std::move(rTokens))
2425 , m_bGotDataChangedHint(false)
2427 , mbTimeBased(false)
2428 , mnTimeBasedStart(0)
2429 , mnTimeBasedEnd(0)
2430 , mnCurrentTab(0)
2431{
2432 if ( m_pDocument )
2433 {
2434 m_pDocument->AddUnoObject( *this);
2436 }
2437 // FIXME: real implementation of identifier and it's mapping to ranges.
2438 // Reuse ScChartListener?
2439
2440 // BM: don't use names of named ranges but the UI range strings
2441// String aStr;
2442// rRangeList->Format( aStr, ScRefFlags::RANGE_ABS_3D, m_pDocument );
2443// m_aIdentifier = aStr;
2444
2445// m_aIdentifier = "ID_";
2446// static sal_Int32 nID = 0;
2447// m_aIdentifier += OUString::valueOf( ++nID);
2448}
2449
2454 , m_aRole(r.m_aRole)
2456 , m_nObjectId( 0 )
2457 , m_pDocument( pDoc)
2459 , m_bGotDataChangedHint(false)
2461 , mbTimeBased(false)
2462 , mnTimeBasedStart(0)
2463 , mnTimeBasedEnd(0)
2464 , mnCurrentTab(0)
2465{
2466 assert(pDoc);
2467
2468 // Clone tokens.
2469 m_aTokens.reserve(r.m_aTokens.size());
2470 for (const auto& rxToken : r.m_aTokens)
2471 {
2472 ScTokenRef p(rxToken->Clone());
2473 m_aTokens.push_back(p);
2474 }
2475
2476 m_pDocument->AddUnoObject( *this);
2478
2479 if (r.m_oRangeIndices)
2481
2482 if (!r.m_pExtRefListener)
2483 return;
2484
2485 // Re-register all external files that the old instance was
2486 // listening to.
2487
2490 const std::unordered_set<sal_uInt16>& rFileIds = r.m_pExtRefListener->getAllFileIds();
2491 for (const auto& rFileId : rFileIds)
2492 {
2493 pRefMgr->addLinkListener(rFileId, m_pExtRefListener.get());
2494 m_pExtRefListener->addFileId(rFileId);
2495 }
2496}
2497
2499{
2501
2502 if ( m_pDocument )
2503 {
2506 {
2508 if (pCLC)
2510 }
2512 }
2513
2514 m_pValueListener.reset();
2515}
2516
2518{
2519 if( !m_pValueListener || m_aValueListeners.empty() )
2520 return;
2521
2522 m_pValueListener->EndListeningAll();
2523
2524 if( !m_pDocument )
2525 return;
2526
2527 ScChartListenerCollection* pCLC = nullptr;
2529 {
2531 if (pCLC)
2533 }
2534
2535 for (const auto& rxToken : m_aTokens)
2536 {
2537 ScRange aRange;
2539 continue;
2540
2541 m_pDocument->StartListeningArea(aRange, false, m_pValueListener.get());
2542 if (pCLC)
2543 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
2544 }
2545}
2546
2548{
2550
2551 if (!m_xDataArray->empty())
2552 return;
2553
2555
2556 ::std::vector<sal_Int32> aHiddenValues;
2557 sal_Int32 nDataCount = 0;
2558
2559 for (const auto& rxToken : m_aTokens)
2560 {
2562 {
2563 nDataCount += FillCacheFromExternalRef(rxToken);
2564 }
2565 else
2566 {
2567 ScRange aRange;
2569 continue;
2570
2571 SCCOL nLastCol = -1;
2572 SCROW nLastRow = -1;
2573 for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
2574 {
2575 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
2576 {
2578 m_pDocument->InitColumnBlockPosition( hint, nTab, nCol );
2579 for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
2580 {
2581 if (nRow == aRange.aEnd.Row())
2582 {
2583 // Excel behavior: if the last row is the totals row, the data
2584 // is not added to the chart. If it's not the last row, the data
2585 // is added like normal.
2586 const auto* pData = m_pDocument->GetDBAtCursor(
2587 nCol, nRow, nTab,
2589 );
2590 if (pData && pData->HasTotals())
2591 {
2592 ScRange aTempRange;
2593 pData->GetArea(aTempRange);
2594 if (aTempRange.aEnd.Row() == nRow)
2595 {
2596 // Current row is totals row, skip
2597 break;
2598 }
2599 }
2600 }
2601 bool bColHidden = m_pDocument->ColHidden(nCol, nTab, nullptr, &nLastCol);
2602 bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, nullptr, &nLastRow);
2603
2604 if (bColHidden || bRowHidden)
2605 {
2606 // hidden cell
2607 aHiddenValues.push_back(nDataCount-1);
2608
2610 continue;
2611 }
2612
2613 Item aItem;
2614
2615 ScAddress aAdr(nCol, nRow, nTab);
2616 aItem.maString = m_pDocument->GetString(aAdr);
2617
2618 ScRefCellValue aCell(*m_pDocument, aAdr, hint);
2619 switch (aCell.getType())
2620 {
2621 case CELLTYPE_VALUE:
2622 aItem.mfValue = aCell.getValue();
2623 aItem.mbIsValue = true;
2624 break;
2625 case CELLTYPE_FORMULA:
2626 {
2627 ScFormulaCell* pFCell = aCell.getFormula();
2628 FormulaError nErr = pFCell->GetErrCode();
2629 if (nErr != FormulaError::NONE)
2630 break;
2631
2632 if (pFCell->IsValue())
2633 {
2634 aItem.mfValue = pFCell->GetValue();
2635 aItem.mbIsValue = true;
2636 }
2637 }
2638 break;
2639 case CELLTYPE_EDIT:
2640 case CELLTYPE_NONE:
2641 case CELLTYPE_STRING:
2642 default:
2643 ; // do nothing
2644 }
2645
2646 aItem.mAddress = ScAddress(nCol, nRow, nTab);
2647
2648 m_xDataArray->push_back(std::move(aItem));
2649 ++nDataCount;
2650 }
2651 }
2652 }
2653 }
2654 }
2655
2656 // convert the hidden cell list to sequence.
2657 m_aHiddenValues.realloc(aHiddenValues.size());
2658 std::copy(
2659 aHiddenValues.begin(), aHiddenValues.end(), m_aHiddenValues.getArray());
2660
2661 // Clear the data series cache when the array is re-built.
2662 m_aMixedDataCache.realloc(0);
2663}
2664
2666{
2668 {
2669 m_xDataArray.reset(new std::vector<Item>);
2670 m_pDocument->BroadcastUno(ScHint(SfxHintId::ScDataChanged, ScAddress()));
2672 m_bGotDataChangedHint = true;
2673 }
2674}
2675
2677{
2679 ScRange aRange;
2680 if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, pToken, ScAddress(), true))
2681 return 0;
2682
2683 sal_uInt16 nFileId = pToken->GetIndex();
2684 OUString aTabName = pToken->GetString().getString();
2685 ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, aTabName, aRange, nullptr);
2686 if (!pArray)
2687 // no external data exists for this range.
2688 return 0;
2689
2690 // Start listening for this external document.
2691 ExternalRefListener* pExtRefListener = GetExtRefListener();
2692 pRefMgr->addLinkListener(nFileId, pExtRefListener);
2693 pExtRefListener->addFileId(nFileId);
2694
2695 m_xDataArray.reset(new std::vector<Item>);
2696 ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, aTabName, false);
2697 sal_Int32 nDataCount = 0;
2698 FormulaTokenArrayPlainIterator aIter(*pArray);
2699 for (FormulaToken* p = aIter.First(); p; p = aIter.Next())
2700 {
2701 // Cached external range is always represented as a single
2702 // matrix token, although that might change in the future when
2703 // we introduce a new token type to store multi-table range
2704 // data.
2705
2706 if (p->GetType() != svMatrix)
2707 {
2708 OSL_FAIL("Cached array is not a matrix token.");
2709 continue;
2710 }
2711
2712 const ScMatrix* pMat = p->GetMatrix();
2713 SCSIZE nCSize, nRSize;
2714 pMat->GetDimensions(nCSize, nRSize);
2715 for (SCSIZE nC = 0; nC < nCSize; ++nC)
2716 {
2717 for (SCSIZE nR = 0; nR < nRSize; ++nR)
2718 {
2719 if (pMat->IsValue(nC, nR) || pMat->IsBoolean(nC, nR))
2720 {
2721 Item aItem;
2722
2723 aItem.mbIsValue = true;
2724 aItem.mfValue = pMat->GetDouble(nC, nR);
2725
2727 if (pFormatter)
2728 {
2729 const double fVal = aItem.mfValue;
2730 const Color* pColor = nullptr;
2731 sal_uInt32 nFmt = 0;
2732 if (pTable)
2733 {
2734 // Get the correct format index from the cache.
2735 SCCOL nCol = aRange.aStart.Col() + static_cast<SCCOL>(nC);
2736 SCROW nRow = aRange.aStart.Row() + static_cast<SCROW>(nR);
2737 pTable->getCell(nCol, nRow, &nFmt);
2738 }
2739 pFormatter->GetOutputString(fVal, nFmt, aItem.maString, &pColor);
2740 }
2741
2742 m_xDataArray->push_back(std::move(aItem));
2743 ++nDataCount;
2744 }
2745 else if (pMat->IsStringOrEmpty(nC, nR))
2746 {
2747 Item aItem;
2748
2749 aItem.mbIsValue = false;
2750 aItem.maString = pMat->GetString(nC, nR).getString();
2751
2752 m_xDataArray->push_back(std::move(aItem));
2753 ++nDataCount;
2754 }
2755 }
2756 }
2757 }
2758 return nDataCount;
2759}
2760
2762{
2763 if (!m_oRangeIndices)
2764 return;
2765
2766 for ( size_t i = 0, nCount = rRanges.size(); i < nCount; ++i )
2767 {
2768 ScTokenRef pToken;
2769 const ScRange & rRange = rRanges[i];
2770
2772 sal_uInt32 nOrigPos = (*m_oRangeIndices)[i];
2773 m_aTokens[nOrigPos] = pToken;
2774 }
2775
2776 RefChanged();
2777
2778 // any change of the range address is broadcast to value (modify) listeners
2779 if ( !m_aValueListeners.empty() )
2780 m_bGotDataChangedHint = true;
2781}
2782
2784{
2785 if (!m_pExtRefListener)
2787
2788 return m_pExtRefListener.get();
2789}
2790
2792{
2793 if (!m_pExtRefListener)
2794 return;
2795
2796 const std::unordered_set<sal_uInt16>& rFileIds = m_pExtRefListener->getAllFileIds();
2798 for (const auto& rFileId : rFileIds)
2799 pRefMgr->removeLinkListener(rFileId, m_pExtRefListener.get());
2800
2801 m_pExtRefListener.reset();
2802}
2803
2804
2806{
2807 if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
2808 {
2809 // Create a range list from the token list, have the range list
2810 // updated, and bring the change back to the token list.
2811
2812 ScRangeList aRanges;
2813 m_oRangeIndices.emplace();
2814 vector<ScTokenRef>::const_iterator itrBeg = m_aTokens.begin(), itrEnd = m_aTokens.end();
2815 for (vector<ScTokenRef>::const_iterator itr = itrBeg ;itr != itrEnd; ++itr)
2816 {
2818 {
2819 ScRange aRange;
2821 aRanges.push_back(aRange);
2822 sal_uInt32 nPos = distance(itrBeg, itr);
2823 m_oRangeIndices->push_back(nPos);
2824 }
2825 }
2826
2827 assert(m_oRangeIndices->size() == aRanges.size() &&
2828 "range list and range index list have different sizes.");
2829
2830 unique_ptr<ScRangeList> pUndoRanges;
2831 if ( m_pDocument->HasUnoRefUndo() )
2832 pUndoRanges.reset(new ScRangeList(aRanges));
2833
2834 const ScUpdateRefHint& rRef = static_cast<const ScUpdateRefHint&>(rHint);
2835 bool bChanged = aRanges.UpdateReference(
2836 rRef.GetMode(), m_pDocument, rRef.GetRange(), rRef.GetDx(), rRef.GetDy(), rRef.GetDz());
2837
2838 if (bChanged)
2839 {
2840 // TODO: This should be an assert, but tdf#144537 triggers it.
2841 SAL_WARN_IF(m_oRangeIndices->size() == aRanges.size(),
2842 "sc.ui", "range list and range index list have different sizes after the reference update.");
2843
2844 // Bring the change back from the range list to the token list.
2845 UpdateTokensFromRanges(aRanges);
2846
2847 if (pUndoRanges)
2848 m_pDocument->AddUnoRefChange(m_nObjectId, *pUndoRanges);
2849 }
2850 }
2851 else if ( auto pUndoHint = dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
2852 {
2853 do
2854 {
2855 if (pUndoHint->GetObjectId() != m_nObjectId)
2856 break;
2857
2858 // The hint object provides the old ranges. Restore the old state
2859 // from these ranges.
2860
2861 if (!m_oRangeIndices || m_oRangeIndices->empty())
2862 {
2863 assert(false && " faulty range indices");
2864 break;
2865 }
2866
2867 const ScRangeList& rRanges = pUndoHint->GetRanges();
2868
2869 size_t nCount = rRanges.size();
2870 if (nCount != m_oRangeIndices->size())
2871 {
2872 assert(false && "range count and range index count differ.");
2873 break;
2874 }
2875
2876 UpdateTokensFromRanges(rRanges);
2877 }
2878 while (false);
2879 }
2880 else
2881 {
2882 const SfxHintId nId = rHint.GetId();
2883 if ( nId ==SfxHintId::Dying )
2884 {
2885 m_pDocument = nullptr;
2886 }
2887 else if ( nId == SfxHintId::DataChanged )
2888 {
2889 // delayed broadcast as in ScCellRangesBase
2890
2892 {
2893 m_xDataArray.reset(new std::vector<Item>);
2894 lang::EventObject aEvent;
2895 aEvent.Source = getXWeak();
2896
2897 if( m_pDocument )
2898 {
2899 for (const uno::Reference<util::XModifyListener> & xListener: m_aValueListeners)
2900 m_pDocument->AddUnoListenerCall( xListener, aEvent );
2901 }
2902
2903 m_bGotDataChangedHint = false;
2904 }
2905 }
2906 else if ( nId == SfxHintId::ScCalcAll )
2907 {
2908 // broadcast from DoHardRecalc - set m_bGotDataChangedHint
2909 // (SfxHintId::DataChanged follows separately)
2910
2911 if ( !m_aValueListeners.empty() )
2912 m_bGotDataChangedHint = true;
2913 }
2914 else if (nId == SfxHintId::ScClearCache)
2915 {
2916 // necessary after import
2917 m_xDataArray.reset(new std::vector<Item>);
2918 }
2919 }
2920}
2921
2922IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, const SfxHint&, rHint, void )
2923{
2924 if ( m_pDocument && (rHint.GetId() == SfxHintId::ScDataChanged) )
2925 {
2926 // This may be called several times for a single change, if several formulas
2927 // in the range are notified. So only a flag is set that is checked when
2928 // SfxHintId::DataChanged is received.
2929
2930 setDataChangedHint(true);
2931 }
2932}
2933
2935 ScChart2DataSequence& rParent, ScDocument* pDoc) :
2936 mrParent(rParent),
2937 mpDoc(pDoc)
2938{
2939}
2940
2942{
2943 if (!mpDoc || mpDoc->IsInDtorClear())
2944 // The document is being destroyed. Do nothing.
2945 return;
2946
2947 // Make sure to remove all pointers to this object.
2948 mpDoc->GetExternalRefManager()->removeLinkListener(this);
2949}
2950
2952{
2953 switch (eType)
2954 {
2956 {
2957 if (maFileIds.count(nFileId))
2958 // We are listening to this external document.
2959 mrParent.RebuildDataCache();
2960 }
2961 break;
2963 maFileIds.erase(nFileId);
2964 break;
2966 mpDoc = nullptr;
2967 break;
2968 }
2969}
2970
2972{
2973 maFileIds.insert(nFileId);
2974}
2975
2976uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
2977{
2978 SolarMutexGuard aGuard;
2979 if ( !m_pDocument)
2980 throw uno::RuntimeException();
2981
2983
2984 if (!m_aMixedDataCache.hasElements())
2985 {
2986 // Build a cache for the 1st time...
2987
2988 sal_Int32 nCount = m_xDataArray->size();
2989 m_aMixedDataCache.realloc(nCount);
2990 uno::Any* pArr = m_aMixedDataCache.getArray();
2991 for (const Item &rItem : *m_xDataArray)
2992 {
2993 if (rItem.mbIsValue)
2994 *pArr <<= rItem.mfValue;
2995 else if (rItem.maString.isEmpty())
2996 {
2997 ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
2998 if (aCell.isEmpty())
2999 *pArr = uno::Any();
3000 else
3001 *pArr <<= rItem.maString;
3002 }
3003 else
3004 *pArr <<= rItem.maString;
3005 ++pArr;
3006 }
3007 }
3008 return m_aMixedDataCache;
3009}
3010
3011// XNumericalDataSequence --------------------------------------------------
3012
3013uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData()
3014{
3015 SolarMutexGuard aGuard;
3016 if ( !m_pDocument)
3017 throw uno::RuntimeException();
3018
3020
3021 sal_Int32 nCount = m_xDataArray->size();
3022 uno::Sequence<double> aSeq(nCount);
3023 double* pArr = aSeq.getArray();
3024 for (const Item& rItem : *m_xDataArray)
3025 {
3026 *pArr = rItem.mbIsValue ? rItem.mfValue : std::numeric_limits<double>::quiet_NaN();
3027 ++pArr;
3028 }
3029
3030 return aSeq;
3031}
3032
3033// XTextualDataSequence --------------------------------------------------
3034
3035uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::getTextualData()
3036{
3037 SolarMutexGuard aGuard;
3038 uno::Sequence<OUString> aSeq;
3039 if ( !m_pDocument )
3040 throw uno::RuntimeException();
3041
3043
3044 sal_Int32 nCount = m_xDataArray->size();
3045 if ( nCount > 0 )
3046 {
3047 aSeq = uno::Sequence<OUString>(nCount);
3048 OUString* pArr = aSeq.getArray();
3049 for (const Item& rItem : *m_xDataArray)
3050 {
3051 *pArr = rItem.maString;
3052 ++pArr;
3053 }
3054 }
3055 else if ( m_aTokens.front() )
3056 {
3057 if( m_aTokens.front()->GetType() == svString )
3058 {
3059 aSeq = uno::Sequence<OUString> { m_aTokens.front()->GetString().getString() };
3060 }
3061 }
3062
3063 return aSeq;
3064}
3065
3067{
3068 SolarMutexGuard aGuard;
3069 OUString aStr;
3070 OSL_ENSURE( m_pDocument, "No Document -> no SourceRangeRepresentation" );
3071 if (m_pDocument)
3072 lcl_convertTokensToString(aStr, m_aTokens, *m_pDocument);
3073
3074 return aStr;
3075}
3076
3077namespace {
3078
3083class AccumulateRangeSize
3084{
3085public:
3086 AccumulateRangeSize(const ScDocument* pDoc) :
3087 mpDoc(pDoc), mnCols(0), mnRows(0) {}
3088
3089 void operator() (const ScTokenRef& pToken)
3090 {
3091 ScRange r;
3092 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3093 ScRefTokenHelper::getRangeFromToken(mpDoc, r, pToken, ScAddress(), bExternal);
3094 r.PutInOrder();
3095 mnCols += r.aEnd.Col() - r.aStart.Col() + 1;
3096 mnRows += r.aEnd.Row() - r.aStart.Row() + 1;
3097 }
3098
3099 SCCOL getCols() const { return mnCols; }
3100 SCROW getRows() const { return mnRows; }
3101private:
3102 const ScDocument* mpDoc;
3103 SCCOL mnCols;
3104 SCROW mnRows;
3105};
3106
3111class GenerateLabelStrings
3112{
3113public:
3114 GenerateLabelStrings(const ScDocument* pDoc, sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) :
3115 mpDoc(pDoc),
3116 mpLabels(std::make_shared<Sequence<OUString>>(nSize)),
3117 meOrigin(eOrigin),
3118 mnCount(0),
3119 mbColumn(bColumn) {}
3120
3121 void operator() (const ScTokenRef& pToken)
3122 {
3123 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3124 ScRange aRange;
3125 ScRefTokenHelper::getRangeFromToken(mpDoc, aRange, pToken, ScAddress(), bExternal);
3126 OUString* pArr = mpLabels->getArray();
3127 if (mbColumn)
3128 {
3129 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
3130 {
3131 if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3132 {
3133 OUString aString = ScResId(STR_COLUMN) + " ";
3134 ScAddress aPos( nCol, 0, 0 );
3135 OUString aColStr(aPos.Format(ScRefFlags::COL_VALID));
3136 aString += aColStr;
3137 pArr[mnCount] = aString;
3138 }
3139 else //only indices for categories
3140 pArr[mnCount] = OUString::number( mnCount+1 );
3141 ++mnCount;
3142 }
3143 }
3144 else
3145 {
3146 for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
3147 {
3148 if (meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3149 {
3150 OUString aString = ScResId(STR_ROW) +
3151 " " + OUString::number( nRow+1 );
3152 pArr[mnCount] = aString;
3153 }
3154 else //only indices for categories
3155 pArr[mnCount] = OUString::number( mnCount+1 );
3156 ++mnCount;
3157 }
3158 }
3159 }
3160
3161 const Sequence<OUString>& getLabels() const { return *mpLabels; }
3162
3163private:
3164 const ScDocument* mpDoc;
3165 shared_ptr< Sequence<OUString> > mpLabels;
3166 chart2::data::LabelOrigin meOrigin;
3167 sal_Int32 mnCount;
3168 bool mbColumn;
3169};
3170
3171}
3172
3173uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
3174{
3175 SolarMutexGuard aGuard;
3176 if ( !m_pDocument)
3177 throw uno::RuntimeException();
3178
3179 // Determine the total size of all ranges.
3180 AccumulateRangeSize func(m_pDocument);
3181 func = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), func);
3182 SCCOL nCols = func.getCols();
3183 SCROW nRows = func.getRows();
3184
3185 // Determine whether this is column-major or row-major.
3186 bool bColumn = true;
3187 if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
3188 (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
3189 {
3190 if (nRows > nCols)
3191 {
3192 bColumn = eOrigin == chart2::data::LabelOrigin_SHORT_SIDE;
3193 }
3194 else if (nCols > nRows)
3195 {
3196 bColumn = eOrigin != chart2::data::LabelOrigin_SHORT_SIDE;
3197 }
3198 else
3199 return Sequence<OUString>();
3200 }
3201
3202 // Generate label strings based on the info so far.
3203 sal_Int32 nCount = bColumn ? nCols : nRows;
3204 GenerateLabelStrings genLabels(m_pDocument, nCount, eOrigin, bColumn);
3205 genLabels = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), genLabels);
3206 Sequence<OUString> aSeq = genLabels.getLabels();
3207
3208 return aSeq;
3209}
3210
3211namespace {
3212
3213sal_uInt32 getDisplayNumberFormat(const ScDocument* pDoc, const ScAddress& rPos)
3214{
3215 sal_uInt32 nFormat = pDoc->GetNumberFormat(rPos); // original format from cell.
3216 return nFormat;
3217}
3218
3219}
3220
3221::sal_Int32 SAL_CALL ScChart2DataSequence::getNumberFormatKeyByIndex( ::sal_Int32 nIndex )
3222{
3223 SolarMutexGuard aGuard;
3225
3226 if (nIndex == -1)
3227 {
3228 // return format of first non-empty cell
3229 // TODO: use nicer heuristic
3230 for (const Item& rItem : *m_xDataArray)
3231 {
3232 ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
3233 if (!aCell.isEmpty() && aCell.hasNumeric())
3234 {
3235 return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, rItem.mAddress));
3236 }
3237 }
3238
3239 // we could not find a non-empty cell
3240 return 0;
3241 }
3242
3243 if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= m_xDataArray->size())
3244 {
3245 SAL_WARN("sc.ui", "Passed invalid index to getNumberFormatKeyByIndex(). Will return default value '0'.");
3246 return 0;
3247 }
3248
3249 return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, m_xDataArray->at(nIndex).mAddress));
3250}
3251
3252// XCloneable ================================================================
3253
3254uno::Reference< util::XCloneable > SAL_CALL ScChart2DataSequence::createClone()
3255{
3256 SolarMutexGuard aGuard;
3257
3259 return p;
3260}
3261
3262// XModifyBroadcaster ========================================================
3263
3264void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3265{
3266 // like ScCellRangesBase::addModifyListener
3267 SolarMutexGuard aGuard;
3268 if (m_aTokens.empty())
3269 return;
3270
3271 ScRangeList aRanges;
3273 m_aValueListeners.emplace_back( aListener );
3274
3275 if ( m_aValueListeners.size() != 1 )
3276 return;
3277
3278 if (!m_pValueListener)
3279 m_pValueListener.reset(new ScLinkListener( LINK( this, ScChart2DataSequence, ValueListenerHdl ) ));
3280
3281 if (!m_pHiddenListener)
3282 m_pHiddenListener.reset(new HiddenRangeListener(*this));
3283
3284 if( m_pDocument )
3285 {
3287 for (const auto& rxToken : m_aTokens)
3288 {
3289 ScRange aRange;
3291 continue;
3292
3293 m_pDocument->StartListeningArea( aRange, false, m_pValueListener.get() );
3294 if (pCLC)
3295 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
3296 }
3297 }
3298
3299 acquire(); // don't lose this object (one ref for all listeners)
3300}
3301
3302void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3303{
3304 // like ScCellRangesBase::removeModifyListener
3305
3306 SolarMutexGuard aGuard;
3307 if (m_aTokens.empty())
3308 return;
3309
3310 rtl::Reference<ScChart2DataSequence> xSelfHold(this); // in case the listeners have the last ref
3311
3312 sal_uInt16 nCount = m_aValueListeners.size();
3313 for ( sal_uInt16 n=nCount; n--; )
3314 {
3315 uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
3316 if ( rObj == aListener )
3317 {
3318 m_aValueListeners.erase( m_aValueListeners.begin() + n );
3319
3320 if ( m_aValueListeners.empty() )
3321 {
3322 if (m_pValueListener)
3323 m_pValueListener->EndListeningAll();
3324
3326 {
3328 if (pCLC)
3330 }
3331
3332 release(); // release the ref for the listeners
3333 }
3334
3335 break;
3336 }
3337 }
3338}
3339
3340// DataSequence XPropertySet -------------------------------------------------
3341
3342uno::Reference< beans::XPropertySetInfo> SAL_CALL
3344{
3345 SolarMutexGuard aGuard;
3346 static uno::Reference<beans::XPropertySetInfo> aRef =
3348 return aRef;
3349}
3350
3352 const OUString& rPropertyName, const uno::Any& rValue)
3353{
3354 if ( rPropertyName == SC_UNONAME_ROLE )
3355 {
3356 if ( !(rValue >>= m_aRole))
3357 throw lang::IllegalArgumentException();
3358 }
3359 else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3360 {
3361 bool bOldValue = m_bIncludeHiddenCells;
3362 if ( !(rValue >>= m_bIncludeHiddenCells))
3363 throw lang::IllegalArgumentException();
3364 if( bOldValue != m_bIncludeHiddenCells )
3365 m_xDataArray.reset(new std::vector<Item>);//data array is dirty now
3366 }
3367 else if( rPropertyName == "TimeBased" )
3368 {
3369 bool bTimeBased = mbTimeBased;
3370 rValue>>= bTimeBased;
3371 mbTimeBased = bTimeBased;
3372 }
3373 else
3374 throw beans::UnknownPropertyException(rPropertyName);
3375 // TODO: support optional properties
3376}
3377
3378uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue(const OUString& rPropertyName)
3379{
3380 uno::Any aRet;
3381 if ( rPropertyName == SC_UNONAME_ROLE )
3382 aRet <<= m_aRole;
3383 else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3384 aRet <<= m_bIncludeHiddenCells;
3385 else if ( rPropertyName == SC_UNONAME_HIDDENVALUES )
3386 {
3387 // This property is read-only thus cannot be set externally via
3388 // setPropertyValue(...).
3390 aRet <<= m_aHiddenValues;
3391 }
3392 else if (rPropertyName == SC_UNONAME_TIME_BASED)
3393 {
3394 aRet <<= mbTimeBased;
3395 }
3396 else if (rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
3397 {
3398 // Read-only property. It returns whether or not the label value is a
3399 // direct user input, rather than an indirect reference.
3400 bool bHasStringLabel = false;
3401 if (m_aTokens.size() == 1)
3402 {
3403 const formula::FormulaToken& rToken = *m_aTokens[0];
3404 bHasStringLabel = rToken.GetType() == formula::svString;
3405 }
3406 aRet <<= bHasStringLabel;
3407 }
3408 else
3409 throw beans::UnknownPropertyException(rPropertyName);
3410 // TODO: support optional properties
3411 return aRet;
3412}
3413
3415 const OUString& /*rPropertyName*/,
3416 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
3417{
3418 // FIXME: real implementation
3419 OSL_FAIL( "Not yet implemented" );
3420}
3421
3423 const OUString& /*rPropertyName*/,
3424 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
3425{
3426 // FIXME: real implementation
3427 OSL_FAIL( "Not yet implemented" );
3428}
3429
3431 const OUString& /*rPropertyName*/,
3432 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3433{
3434 // FIXME: real implementation
3435 OSL_FAIL( "Not yet implemented" );
3436}
3437
3439 const OUString& /*rPropertyName*/,
3440 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3441{
3442 // FIXME: real implementation
3443 OSL_FAIL( "Not yet implemented" );
3444}
3445
3447{
3449}
3450
3452{
3453 if(!mbTimeBased)
3454 return true;
3455
3457 {
3458 if(bWrap)
3460 return false;
3461 }
3462
3463 for(const auto& rxToken : m_aTokens)
3464 {
3465 if (rxToken->GetType() != svDoubleRef)
3466 continue;
3467
3468 ScComplexRefData& rData = *rxToken->GetDoubleRef();
3469 ScSingleRefData& s = rData.Ref1;
3470 ScSingleRefData& e = rData.Ref2;
3471
3472 s.IncTab(1);
3473 e.IncTab(1);
3474 }
3475
3476 ++mnCurrentTab;
3477
3479
3480 return true;
3481}
3482
3483void ScChart2DataSequence::setRange(sal_Int32 nStart, sal_Int32 nEnd)
3484{
3485 mnTimeBasedStart = nStart;
3486 mnTimeBasedEnd = nEnd;
3488}
3489
3491{
3492 if(nPoint > mnTimeBasedEnd - mnTimeBasedStart)
3493 return false;
3494
3495 SCTAB nTab = mnTimeBasedStart + nPoint;
3496 for(const auto& rxToken : m_aTokens)
3497 {
3498 if (rxToken->GetType() != svDoubleRef)
3499 continue;
3500
3501 ScComplexRefData& rData = *rxToken->GetDoubleRef();
3502 ScSingleRefData& s = rData.Ref1;
3503 ScSingleRefData& e = rData.Ref2;
3504
3505 s.SetAbsTab(nTab);
3506 e.SetAbsTab(nTab);
3507 }
3508
3509 mnCurrentTab = nTab;
3510
3512
3513 return true;
3514}
3515
3516/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SCTAB MAXTAB
Definition: address.hxx:70
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
BaseContainerNodeSharedPtr & mrParent
AnyEventRef aEvent
FILE * init(int, char **)
SC_SIMPLE_SERVICE_INFO(ScChart2DataProvider, "ScChart2DataProvider", "com.sun.star.chart2.data.DataProvider") SC_SIMPLE_SERVICE_INFO(ScChart2DataSource
#define SHRINK_RANGE_THRESHOLD
Definition: chart2uno.cxx:1344
ScChart2DataSource
Definition: chart2uno.cxx:67
IMPL_LINK(ScChart2DataSequence, ValueListenerHdl, const SfxHint &, rHint, void)
Definition: chart2uno.cxx:2922
SCTAB Tab() const
Definition: address.hxx:283
SCROW Row() const
Definition: address.hxx:274
SCCOL Col() const
Definition: address.hxx:279
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByRangeRepresentation(const OUString &aRangeRepresentation) override
Definition: chart2uno.cxx:2051
virtual void SAL_CALL addVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:2343
virtual css::uno::Reference< css::sheet::XRangeSelection > SAL_CALL getRangeSelection() override
Definition: chart2uno.cxx:2083
virtual void SAL_CALL removePropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &rListener) override
Definition: chart2uno.cxx:2336
virtual OUString SAL_CALL convertRangeFromXML(const OUString &sXMLRange) override
Definition: chart2uno.cxx:2250
virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL detectArguments(const css::uno::Reference< css::chart2::data::XDataSource > &xDataSource) override
Definition: chart2uno.cxx:1766
virtual ~ScChart2DataProvider() override
Definition: chart2uno.cxx:989
virtual OUString SAL_CALL convertRangeToXML(const OUString &sRangeRepresentation) override
Definition: chart2uno.cxx:2223
ScDocument * m_pDocument
Definition: chart2uno.hxx:147
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByValueArray(const OUString &aRole, const OUString &aRangeRepresentation, const OUString &aRoleQualifier) override
Definition: chart2uno.cxx:2076
virtual void SAL_CALL removeVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:2350
virtual sal_Bool SAL_CALL createDataSequenceByRangeRepresentationPossible(const OUString &aRangeRepresentation) override
Definition: chart2uno.cxx:2037
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: chart2uno.cxx:997
virtual sal_Bool SAL_CALL createDataSourcePossible(const css::uno::Sequence< css::beans::PropertyValue > &aArguments) override
Definition: chart2uno.cxx:1005
virtual css::uno::Any SAL_CALL getPropertyValue(const OUString &rPropertyName) override
Definition: chart2uno.cxx:2313
virtual void SAL_CALL setPropertyValue(const OUString &rPropertyName, const css::uno::Any &rValue) override
Definition: chart2uno.cxx:2302
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByFormulaTokens(const css::uno::Sequence< css::sheet::FormulaToken > &aTokens) override
Definition: chart2uno.cxx:2151
ScChart2DataProvider(ScDocument *pDoc)
Definition: chart2uno.cxx:980
SfxItemPropertySet m_aPropSet
Definition: chart2uno.hxx:148
virtual sal_Bool SAL_CALL createDataSequenceByFormulaTokensPossible(const css::uno::Sequence< css::sheet::FormulaToken > &aTokens) override
Definition: chart2uno.cxx:2094
virtual void SAL_CALL addPropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &xListener) override
Definition: chart2uno.cxx:2329
virtual css::uno::Reference< css::chart2::data::XDataSource > SAL_CALL createDataSource(const css::uno::Sequence< css::beans::PropertyValue > &aArguments) override
Definition: chart2uno.cxx:1404
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
Definition: chart2uno.cxx:2294
ExternalRefListener(ScChart2DataSequence &rParent, ScDocument *pDoc)
Definition: chart2uno.cxx:2934
virtual void notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType) override
Definition: chart2uno.cxx:2951
HiddenRangeListener(ScChart2DataSequence &rParent)
Definition: chart2uno.cxx:2402
css::chart2::data::DataSequenceRole m_aRole
Definition: chart2uno.hxx:367
void StopListeningToAllExternalRefs()
Definition: chart2uno.cxx:2791
std::unique_ptr< HiddenRangeListener > m_pHiddenListener
Definition: chart2uno.hxx:380
XModifyListenerArr_Impl m_aValueListeners
Definition: chart2uno.hxx:383
virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override
Definition: chart2uno.cxx:3254
virtual OUString SAL_CALL getSourceRangeRepresentation() override
Definition: chart2uno.cxx:3066
std::vector< ScTokenRef > m_aTokens
Definition: chart2uno.hxx:373
ScChart2DataSequence(ScDocument *pDoc, ::std::vector< ScTokenRef > &&rTokens, bool bIncludeHiddenCells)
virtual css::uno::Sequence< OUString > SAL_CALL generateLabel(css::chart2::data::LabelOrigin nOrigin) override
Definition: chart2uno.cxx:3173
virtual void SAL_CALL addPropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &xListener) override
Definition: chart2uno.cxx:3414
void setDataChangedHint(bool b)
Definition: chart2uno.cxx:3446
ExternalRefListener * GetExtRefListener()
Definition: chart2uno.cxx:2783
virtual void SAL_CALL setPropertyValue(const OUString &rPropertyName, const css::uno::Any &rValue) override
Definition: chart2uno.cxx:3351
std::unique_ptr< ExternalRefListener > m_pExtRefListener
Definition: chart2uno.hxx:377
css::uno::Sequence< css::uno::Any > m_aMixedDataCache
Cached data for getData.
Definition: chart2uno.hxx:362
ScDocument * m_pDocument
Definition: chart2uno.hxx:372
std::shared_ptr< std::vector< Item > > m_xDataArray
This vector contains the cached data which was calculated with BuildDataCache().
Definition: chart2uno.hxx:355
virtual void SAL_CALL addVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:3430
virtual void SAL_CALL removePropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &rListener) override
Definition: chart2uno.cxx:3422
virtual void SAL_CALL addModifyListener(const css::uno::Reference< css::util::XModifyListener > &aListener) override
Definition: chart2uno.cxx:3264
virtual sal_Bool SAL_CALL switchToNext(sal_Bool bWrap) override
Definition: chart2uno.cxx:3451
virtual css::uno::Sequence< OUString > SAL_CALL getTextualData() override
Definition: chart2uno.cxx:3035
void UpdateTokensFromRanges(const ScRangeList &rRanges)
Definition: chart2uno.cxx:2761
std::optional< std::vector< sal_uInt32 > > m_oRangeIndices
Definition: chart2uno.hxx:375
virtual css::uno::Sequence< css::uno::Any > SAL_CALL getData() override
Definition: chart2uno.cxx:2976
virtual void SAL_CALL setRange(sal_Int32 nStart, sal_Int32 nEnd) override
Definition: chart2uno.cxx:3483
virtual css::uno::Any SAL_CALL getPropertyValue(const OUString &rPropertyName) override
Definition: chart2uno.cxx:3378
virtual void SAL_CALL removeVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:3438
virtual sal_Bool SAL_CALL setToPointInTime(sal_Int32 nPoint) override
Definition: chart2uno.cxx:3490
std::unique_ptr< ScLinkListener > m_pValueListener
Definition: chart2uno.hxx:382
SfxItemPropertySet m_aPropSet
Definition: chart2uno.hxx:378
sal_Int32 FillCacheFromExternalRef(const ScTokenRef &pToken)
Definition: chart2uno.cxx:2676
virtual void SAL_CALL removeModifyListener(const css::uno::Reference< css::util::XModifyListener > &aListener) override
Definition: chart2uno.cxx:3302
void BuildDataCache()
Build an internal data array to cache the data ranges, and other information such as hidden values.
Definition: chart2uno.cxx:2547
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: chart2uno.cxx:2805
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
Definition: chart2uno.cxx:3343
virtual ::sal_Int32 SAL_CALL getNumberFormatKeyByIndex(::sal_Int32 nIndex) override
Get the number format key for the n-th data entry If nIndex == -1, then you will get the number forma...
Definition: chart2uno.cxx:3221
css::uno::Sequence< sal_Int32 > m_aHiddenValues
Definition: chart2uno.hxx:364
virtual ~ScChart2DataSequence() override
Definition: chart2uno.cxx:2498
virtual css::uno::Sequence< double > SAL_CALL getNumericalData() override
Definition: chart2uno.cxx:3013
std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > m_aLabeledSequences
Definition: chart2uno.hxx:186
ScChart2DataSource(ScDocument *pDoc)
Definition: chart2uno.cxx:2359
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: chart2uno.cxx:2374
void AddLabeledSequence(const css::uno::Reference< css::chart2::data::XLabeledDataSequence > &xNew)
Definition: chart2uno.cxx:2389
virtual css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > SAL_CALL getDataSequences() override
Definition: chart2uno.cxx:2383
virtual ~ScChart2DataSource() override
Definition: chart2uno.cxx:2366
ScDocument * m_pDocument
Definition: chart2uno.hxx:185
void EndListeningHiddenRange(ScChartHiddenRangeListener *pListener)
Remove all ranges associated with passed listener instance from the list of hidden range listeners.
Definition: chartlis.cxx:624
void StartListeningHiddenRange(const ScRange &rRange, ScChartHiddenRangeListener *pListener)
Start listening on hide/show change within specified cell range.
Definition: chartlis.cxx:619
ScSheetLimits & GetSheetLimits() const
Definition: document.hxx:898
SC_DLLPUBLIC sal_uInt32 GetNumberFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3640
bool ShrinkToDataArea(SCTAB nTab, SCCOL &rStartCol, SCROW &rStartRow, SCCOL &rEndCol, SCROW &rEndRow) const
Shrink a range to only include data area.
Definition: document.cxx:1018
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:892
const ScDBData * GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: documen3.cxx:322
ScRangeData * FindRangeNameBySheetAndIndex(SCTAB nTab, sal_uInt16 nIndex) const
Find a named expression / range name in either global or a local scope.
Definition: documen3.cxx:269
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:893
void AddUnoRefChange(sal_Int64 nId, const ScRangeList &rOldRanges)
Definition: documen3.cxx:1002
SC_DLLPUBLIC ScChartListenerCollection * GetChartListenerCollection() const
Definition: document.hxx:2233
SC_DLLPUBLIC bool InitColumnBlockPosition(sc::ColumnBlockPosition &rBlockPos, SCTAB nTab, SCCOL nCol)
Definition: document.cxx:2628
SC_DLLPUBLIC ScExternalRefManager * GetExternalRefManager() const
Definition: documen3.cxx:625
void AddUnoObject(SfxListener &rObject)
Definition: documen3.cxx:901
SC_DLLPUBLIC bool HasData(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: documen5.cxx:529
SC_DLLPUBLIC bool RowHidden(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4416
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1010
void StartListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: documen7.cxx:35
bool HasUnoRefUndo() const
Definition: document.hxx:1090
bool PastingDrawFromOtherDoc() const
Definition: document.hxx:2527
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1083
SC_DLLPUBLIC bool HasValueData(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3750
void AddUnoListenerCall(const css::uno::Reference< css::util::XModifyListener > &rListener, const css::lang::EventObject &rEvent)
Definition: documen3.cxx:980
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:467
sal_Int64 GetNewUnoId()
Definition: document.hxx:1093
SC_DLLPUBLIC bool ColHidden(SCCOL nCol, SCTAB nTab, SCCOL *pFirstCol=nullptr, SCCOL *pLastCol=nullptr) const
Definition: document.cxx:4430
SC_DLLPUBLIC OUString GetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext *pContext=nullptr) const
Definition: document.cxx:3505
void RemoveUnoObject(SfxListener &rObject)
Definition: documen3.cxx:909
void BroadcastUno(const SfxHint &rHint)
Definition: documen3.cxx:952
std::shared_ptr< Table > TableTypeRef
std::shared_ptr< ScTokenArray > TokenArrayRef
void addLinkListener(sal_uInt16 nFileId, LinkListener *pListener)
Register a new link listener to a specified external document.
ScExternalRefCache::TableTypeRef getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
Get a cache table instance for specified table and table index.
void removeLinkListener(sal_uInt16 nFileId, LinkListener *pListener)
Remove an existing link listener.
ScExternalRefCache::TokenArrayRef getDoubleRefTokens(sal_uInt16 nFileId, const OUString &rTabName, const ScRange &rRange, const ScAddress *pCurPos)
Get an array of tokens that consist of the specified external cell range.
double GetValue()
FormulaError GetErrCode()
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:101
svl::SharedString GetString(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3238
bool IsStringOrEmpty(SCSIZE nIndex) const
Definition: scmatrix.cxx:3258
bool IsBoolean(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3303
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3223
void GetDimensions(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:3143
bool IsValue(SCSIZE nIndex) const
Definition: scmatrix.cxx:3288
SC_DLLPUBLIC bool IsReference(ScRange &rRef) const
Definition: rangenam.cxx:371
ScTokenArray * GetCode()
Definition: rangenam.hxx:119
bool HasReferences() const
Definition: rangenam.cxx:520
void push_back(const ScRange &rRange)
Definition: rangelst.cxx:1137
size_t size() const
Definition: rangelst.hxx:89
bool UpdateReference(UpdateRefMode, const ScDocument *, const ScRange &rWhere, SCCOL nDx, SCROW nDy, SCTAB nDz)
Definition: rangelst.cxx:357
static void GetStringFromXMLRangeString(OUString &rString, std::u16string_view rXMLRange, const ScDocument &rDoc)
XML Range to Calc Range.
Definition: rangeutl.cxx:806
static sal_Int32 IndexOf(std::u16string_view rString, sal_Unicode cSearchChar, sal_Int32 nOffset, sal_Unicode cQuote='\'')
Definition: rangeutl.cxx:374
static void GetTokenByOffset(OUString &rToken, std::u16string_view rString, sal_Int32 &nOffset, sal_Unicode cSeparator=' ', sal_Unicode cQuote='\'')
Definition: rangeutl.cxx:414
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:690
void PutInOrder()
Definition: address.hxx:622
ScAddress aEnd
Definition: address.hxx:498
ScAddress aStart
Definition: address.hxx:497
static SC_DLLPUBLIC bool ConvertToTokenArray(ScDocument &rDoc, ScTokenArray &rTokenArray, const css::uno::Sequence< css::sheet::FormulaToken > &rSequence)
Definition: tokenuno.cxx:374
Hint to restore a UNO object to its old state (used during undo).
Definition: unoreflist.hxx:61
const ScRange & GetRange() const
Definition: hints.hxx:60
SCCOL GetDx() const
Definition: hints.hxx:61
SCTAB GetDz() const
Definition: hints.hxx:63
SCROW GetDy() const
Definition: hints.hxx:62
UpdateRefMode GetMode() const
Definition: hints.hxx:59
SfxHintId GetId() const
const SfxItemPropertyMap & getPropertyMap() const
css::uno::Reference< css::frame::XModel3 > GetModel() const
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, const Color **ppColor, bool bUseStarFormat=false)
css::uno::Type const & get()
static sal_Unicode GetNativeSymbolChar(OpCode eOp)
const FormulaToken * CreateStringFromToken(OUString &rFormula, const FormulaToken *pToken)
sal_uInt16 GetLen() const
FormulaToken ** GetArray() const
FormulaToken * FirstToken() const
StackVar GetType() const
const OUString & getString() const
static const SharedString & getEmptyString()
int nCount
@ AREA
entire area
std::size_t mnCount
float u
#define max(a, b)
FormulaError
DocumentType eType
@ CELLTYPE_EDIT
Definition: global.hxx:277
@ CELLTYPE_STRING
Definition: global.hxx:275
@ CELLTYPE_FORMULA
Definition: global.hxx:276
@ CELLTYPE_NONE
Definition: global.hxx:273
@ CELLTYPE_VALUE
Definition: global.hxx:274
SfxHintId
double distance
Sequence< PropertyValue > aArguments
sal_Int32 nIndex
void * p
sal_Int64 n
sal_uInt16 nPos
Sequence< sal_Int8 > aSeq
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
std::vector< sal_Int8, boost::noinit_adaptor< std::allocator< sal_Int8 > > > maData
aStr
std::unique_ptr< sal_Int32[]> pData
int n2
int n1
constexpr OUStringLiteral aData
bool SC_DLLPUBLIC isRef(const ScTokenRef &pToken)
void getRangeListFromTokens(const ScDocument *pDoc, ScRangeList &rRangeList, const ::std::vector< ScTokenRef > &pTokens, const ScAddress &rPos)
void compileRangeRepresentation(::std::vector< ScTokenRef > &rRefTokens, const OUString &rRangeStr, ScDocument &rDoc, const sal_Unicode cSep, ::formula::FormulaGrammar::Grammar eGrammar, bool bOnly3DRef=false)
Compile an array of reference tokens from a data source range string.
bool getRangeFromToken(const ScDocument *pDoc, ScRange &rRange, const ScTokenRef &pToken, const ScAddress &rPos, bool bExternal=false)
void getTokenFromRange(const ScDocument *pDoc, ScTokenRef &pToken, const ScRange &rRange)
Create a double reference token from a range object.
bool SC_DLLPUBLIC isExternalRef(const ScTokenRef &pToken)
void SC_DLLPUBLIC join(const ScDocument *pDoc, ::std::vector< ScTokenRef > &rTokens, const ScTokenRef &pToken, const ScAddress &rPos)
bool getDoubleRefDataFromToken(ScComplexRefData &rData, const ScTokenRef &pToken)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
OUString getString(const Any &_rAny)
StackVar
svIndex
svExternalDoubleRef
svExternalName
svSep
svDoubleRef
svExternal
svExternalSingleRef
svString
svMatrix
svSingleRef
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
std::shared_ptr< T > make_shared(Args &&... args)
static o3tl::span< const SfxItemPropertyMapEntry > lcl_GetDataSequencePropertyMap()
State
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
SwNodeOffset abs(const SwNodeOffset &a)
sal_Int16 nId
ocClose
ocOpen
ocSep
ocName
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
Complex reference (a range) into the sheet.
Definition: refdata.hxx:123
ScSingleRefData Ref2
Definition: refdata.hxx:125
ScSingleRefData Ref1
Definition: refdata.hxx:124
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
ScFormulaCell * getFormula() const
Definition: cellvalue.hxx:137
bool isEmpty() const
Definition: cellvalue.cxx:667
bool hasNumeric() const
Definition: cellvalue.cxx:619
double getValue()
Definition: cellvalue.cxx:629
CellType getType() const
Definition: cellvalue.hxx:133
SCROW GetMaxRowCount() const
Definition: sheetlimits.hxx:66
SCCOL GetMaxColCount() const
Definition: sheetlimits.hxx:68
Single reference (one address) into the sheet.
Definition: refdata.hxx:30
void SetAbsCol(SCCOL nVal)
Definition: refdata.cxx:59
void SetAbsTab(SCTAB nVal)
Definition: refdata.cxx:93
SCCOL Col() const
Definition: refdata.cxx:247
void SetRowRel(bool bVal)
Definition: refdata.hxx:66
SCTAB Tab() const
Definition: refdata.cxx:254
void SetTabRel(bool bVal)
Definition: refdata.hxx:68
SCROW Row() const
Definition: refdata.cxx:240
void SetAbsRow(SCROW nVal)
Definition: refdata.cxx:76
void SetFlag3D(bool bVal)
Definition: refdata.hxx:89
void IncTab(SCTAB nInc)
Definition: refdata.cxx:105
void InitFlags()
No default ctor, because used in ScRawToken union, set InitFlags!
Definition: refdata.hxx:54
void SetColRel(bool bVal)
Definition: refdata.hxx:64
Store position data for column array storage.
Reference< XModel > xModel
unsigned char sal_Bool
sal_uInt16 sal_Unicode
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:23
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
::boost::intrusive_ptr< formula::FormulaToken > ScTokenRef
Definition: types.hxx:29
sal_Int32 SCROW
Definition: types.hxx:17
OUString aLabel
constexpr OUStringLiteral SC_UNONAME_TIME_BASED
Definition: unonames.hxx:699
constexpr OUStringLiteral SC_UNONAME_HIDDENVALUES
Definition: unonames.hxx:695
constexpr OUStringLiteral SC_UNONAME_ROLE
Definition: unonames.hxx:694
constexpr OUStringLiteral SC_UNONAME_USE_INTERNAL_DATA_PROVIDER
Definition: unonames.hxx:697
constexpr OUStringLiteral SC_UNONAME_INCLUDEHIDDENCELLS
Definition: unonames.hxx:696
constexpr OUStringLiteral SC_UNONAME_HAS_STRING_LABEL
Definition: unonames.hxx:698
std::unique_ptr< char[]> aBuffer