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
536 mnStartCol = aData.Ref1.Col();
537 mnStartRow = aData.Ref1.Row();
538
539 SCCOL nEndCol = 0;
540 SCROW nEndRow = 0;
541 for (const auto& rxToken : mrRefTokens)
542 {
544 SCCOLROW n1 = aData.Ref1.Col();
545 SCCOLROW n2 = aData.Ref2.Col();
546 if (n1 > mpDoc->MaxCol())
547 n1 = mpDoc->MaxCol();
548 if (n2 > mpDoc->MaxCol())
549 n2 = mpDoc->MaxCol();
550 if (n1 < mnStartCol)
551 mnStartCol = static_cast<SCCOL>(n1);
552 if (n2 > nEndCol)
553 nEndCol = static_cast<SCCOL>(n2);
554
555 n1 = aData.Ref1.Row();
556 n2 = aData.Ref2.Row();
557 if (n1 > mpDoc->MaxRow())
558 n1 = mpDoc->MaxRow();
559 if (n2 > mpDoc->MaxRow())
560 n2 = mpDoc->MaxRow();
561
562 if (n1 < mnStartRow)
563 mnStartRow = static_cast<SCROW>(n1);
564 if (n2 > nEndRow)
565 nEndRow = static_cast<SCROW>(n2);
566 }
567
568 if (mnStartCol == nEndCol)
569 {
570 // All source data is in a single column.
571 meGlue = GLUETYPE_ROWS;
572 return;
573 }
574
575 if (mnStartRow == nEndRow)
576 {
577 // All source data is in a single row.
578 meGlue = GLUETYPE_COLS;
579 return;
580 }
581
582 // total column size
583 SCCOL nC = nEndCol - mnStartCol + 1;
584
585 // total row size
586 SCROW nR = nEndRow - mnStartRow + 1;
587
588 // #i103540# prevent invalid vector size
589 if ((nC <= 0) || (nR <= 0))
590 {
591 invalidateGlue();
592 mnStartCol = 0;
593 mnStartRow = 0;
594 return;
595 }
596
597 calcGlueState(nC, nR);
598}
599
600enum State { Hole = 0, Occupied = 1, Free = 2, Glue = 3 };
601
602void Chart2Positioner::calcGlueState(SCCOL nColSize, SCROW nRowSize)
603{
604 // TODO: This code can use some space optimization. Using an array to
605 // store individual cell's states is terribly inefficient esp for large
606 // data ranges; let's use flat_segment_tree to reduce memory usage here.
607
608 sal_uInt32 nCR = static_cast<sal_uInt32>(nColSize*nRowSize);
609
610 vector<State> aCellStates(nCR, Hole);
611
612 // Mark all referenced cells "occupied".
613 for (const auto& rxToken : mrRefTokens)
614 {
617 SCCOL nCol1 = aData.Ref1.Col() - mnStartCol;
618 SCCOL nCol2 = aData.Ref2.Col() - mnStartCol;
619 SCROW nRow1 = aData.Ref1.Row() - mnStartRow;
620 SCROW nRow2 = aData.Ref2.Row() - mnStartRow;
621 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
622 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
623 {
624 size_t i = nCol*nRowSize + nRow;
625 aCellStates[i] = Occupied;
626 }
627 }
628
629 // If at least one cell in either the first column or first row is empty,
630 // we don't glue at all unless the whole column or row is empty; we expect
631 // all cells in the first column / row to be fully populated. If we have
632 // empty column or row, then we do glue by the column or row,
633 // respectively.
634
635 bool bGlue = true;
636 bool bGlueCols = false;
637 for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol)
638 {
639 for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
640 {
641 size_t i = nCol*nRowSize + nRow;
642 if (aCellStates[i] == Occupied)
643 {
644 if (nCol == 0 || nRow == 0)
645 break;
646
647 bGlue = false;
648 }
649 else
650 aCellStates[i] = Free;
651 }
652 size_t nLast = (nCol+1)*nRowSize - 1; // index for the last cell in the column.
653 if (bGlue && aCellStates[nLast] == Free)
654 {
655 // Whole column is empty.
656 aCellStates[nLast] = Glue;
657 bGlueCols = true;
658 }
659 }
660
661 bool bGlueRows = false;
662 for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
663 {
664 size_t i = nRow;
665 for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol, i += nRowSize)
666 {
667 if (aCellStates[i] == Occupied)
668 {
669 if (nCol == 0 || nRow == 0)
670 break;
671
672 bGlue = false;
673 }
674 else
675 aCellStates[i] = Free;
676 }
677 i = (nColSize-1)*nRowSize + nRow; // index for the row position in the last column.
678 if (bGlue && aCellStates[i] == Free)
679 {
680 // Whole row is empty.
681 aCellStates[i] = Glue;
682 bGlueRows = true;
683 }
684 }
685
686 size_t i = 1;
687 for (sal_uInt32 n = 1; bGlue && n < nCR; ++n, ++i)
688 if (aCellStates[i] == Hole)
689 bGlue = false;
690
691 if (bGlue)
692 {
693 if (bGlueCols && bGlueRows)
694 meGlue = GLUETYPE_BOTH;
695 else if (bGlueRows)
696 meGlue = GLUETYPE_ROWS;
697 else
698 meGlue = GLUETYPE_COLS;
699 if (aCellStates.front() != Occupied)
700 mbDummyUpperLeft = true;
701 }
702 else
703 meGlue = GLUETYPE_NONE;
704}
705
706void Chart2Positioner::createPositionMap()
707{
708 if (meGlue == GLUETYPE_NA && mpPositionMap)
709 mpPositionMap.reset();
710
711 if (mpPositionMap)
712 return;
713
714 glueState();
715
716 bool bNoGlue = (meGlue == GLUETYPE_NONE);
717 FormulaTokenMapMap aCols;
718 SCROW nNoGlueRow = 0;
719 for (const ScTokenRef& pToken : mrRefTokens)
720 {
721 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
722 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
724 if (bExternal)
725 aTabName = pToken->GetString();
726
729 break;
730 const ScSingleRefData& s = aData.Ref1;
731 const ScSingleRefData& e = aData.Ref2;
732 SCCOL nCol1 = s.Col(), nCol2 = e.Col();
733 SCROW nRow1 = s.Row(), nRow2 = e.Row();
734 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
735
736 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
737 {
738 // columns on secondary sheets are appended; we treat them as if
739 // all columns are on the same sheet. TODO: We can't assume that
740 // the column range is 16-bit; remove that restriction.
741 sal_uInt32 nInsCol = (static_cast<sal_uInt32>(nTab) << 16) |
742 (bNoGlue ? 0 : static_cast<sal_uInt32>(nCol1));
743
744 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol)
745 {
746 FormulaTokenMap& rCol = aCols[nInsCol];
747
748 auto nInsRow = bNoGlue ? nNoGlueRow : nRow1;
749 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow, ++nInsRow)
750 {
751 ScSingleRefData aCellData;
752 aCellData.InitFlags();
753 aCellData.SetFlag3D(true);
754 aCellData.SetColRel(false);
755 aCellData.SetRowRel(false);
756 aCellData.SetTabRel(false);
757 aCellData.SetAbsCol(nCol);
758 aCellData.SetAbsRow(nRow);
759 aCellData.SetAbsTab(nTab);
760
761 auto& rCell = rCol[nInsRow];
762 if (!rCell)
763 {
764 if (bExternal)
765 rCell.reset(new ScExternalSingleRefToken(nFileId, aTabName, aCellData));
766 else
767 rCell.reset(new ScSingleRefToken(mpDoc->GetSheetLimits(), aCellData));
768 }
769 }
770 }
771 }
772 nNoGlueRow += nRow2 - nRow1 + 1;
773 }
774
775 bool bFillRowHeader = mbRowHeaders;
776 bool bFillColumnHeader = mbColHeaders;
777
778 SCSIZE nAllColCount = static_cast<SCSIZE>(aCols.size());
779 SCSIZE nAllRowCount = 0;
780 if (!aCols.empty())
781 {
782 FormulaTokenMap& rCol = aCols.begin()->second;
783 if (mbDummyUpperLeft)
784 rCol.try_emplace( 0, nullptr ); // dummy for labeling
785 nAllRowCount = static_cast<SCSIZE>(rCol.size());
786 }
787
788 if( nAllColCount!=0 && nAllRowCount!=0 )
789 {
790 if (bNoGlue)
791 {
792 FormulaTokenMap& rFirstCol = aCols.begin()->second;
793 for (const auto& rFirstColEntry : rFirstCol)
794 {
795 SCROW nKey = rFirstColEntry.first;
796 for (auto& rEntry : aCols)
797 {
798 FormulaTokenMap& rCol = rEntry.second;
799 rCol.try_emplace( nKey, nullptr );
800 }
801 }
802 }
803 }
804 mpPositionMap.reset(
805 new Chart2PositionMap(
806 static_cast<SCCOL>(nAllColCount), static_cast<SCROW>(nAllRowCount),
807 bFillRowHeader, bFillColumnHeader, aCols, mpDoc));
808}
809
813class Tokens2RangeString
814{
815public:
816 Tokens2RangeString(ScDocument& rDoc, FormulaGrammar::Grammar eGram, sal_Unicode cRangeSep) :
817 mpRangeStr(std::make_shared<OUStringBuffer>()),
818 mpDoc(&rDoc),
819 meGrammar(eGram),
820 mcRangeSep(cRangeSep),
821 mbFirst(true)
822 {
823 }
824
825 void operator() (const ScTokenRef& rToken)
826 {
827 ScCompiler aCompiler(*mpDoc, ScAddress(0,0,0), meGrammar);
828 OUString aStr;
829 aCompiler.CreateStringFromToken(aStr, rToken.get());
830 if (mbFirst)
831 mbFirst = false;
832 else
833 mpRangeStr->append(mcRangeSep);
834 mpRangeStr->append(aStr);
835 }
836
837 void getString(OUString& rStr)
838 {
839 rStr = mpRangeStr->makeStringAndClear();
840 }
841
842private:
843 shared_ptr<OUStringBuffer> mpRangeStr;
844 ScDocument* mpDoc;
845 FormulaGrammar::Grammar meGrammar;
846 sal_Unicode mcRangeSep;
847 bool mbFirst;
848};
849
858class Tokens2RangeStringXML
859{
860public:
861 explicit Tokens2RangeStringXML(ScDocument& rDoc) :
862 mpRangeStr(std::make_shared<OUStringBuffer>()),
863 mpDoc(&rDoc),
864 mbFirst(true)
865 {
866 }
867
868 void operator() (const ScTokenRef& rToken)
869 {
870 if (mbFirst)
871 mbFirst = false;
872 else
873 mpRangeStr->append(mcRangeSep);
874
875 ScTokenRef aStart, aEnd;
876 bool bValidToken = splitRangeToken(*mpDoc, rToken, aStart, aEnd);
877 // Check there is a valid reference in named range
878 if (!bValidToken && rToken->GetType() == svIndex && rToken->GetOpCode() == ocName)
879 {
880 ScRangeData* pNameRange = mpDoc->FindRangeNameBySheetAndIndex(rToken->GetSheet(), rToken->GetIndex());
881 if (pNameRange->HasReferences())
882 {
883 const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
884 bValidToken = splitRangeToken(*mpDoc, aTempToken, aStart, aEnd);
885 }
886 }
887
888 OSL_ENSURE(bValidToken, "invalid token");
889 if (!bValidToken)
890 return;
891
892 ScCompiler aCompiler(*mpDoc, ScAddress(0,0,0), FormulaGrammar::GRAM_ENGLISH);
893 {
894 OUString aStr;
895 aCompiler.CreateStringFromToken(aStr, aStart.get());
896 mpRangeStr->append(aStr);
897 }
898 mpRangeStr->append(mcAddrSep);
899 {
900 OUString aStr;
901 aCompiler.CreateStringFromToken(aStr, aEnd.get());
902 mpRangeStr->append(aStr);
903 }
904 }
905
906 void getString(OUString& rStr)
907 {
908 rStr = mpRangeStr->makeStringAndClear();
909 }
910
911private:
912 static bool splitRangeToken(const ScDocument& rDoc, const ScTokenRef& pToken, ScTokenRef& rStart, ScTokenRef& rEnd)
913 {
915 bool bIsRefToken = ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken);
916 OSL_ENSURE(bIsRefToken, "invalid token");
917 if (!bIsRefToken)
918 return false;
919 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
920 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
922 if (bExternal)
923 aTabName = pToken->GetString();
924
925 // In saving to XML, we don't prepend address with '$'.
926 setRelative(aData.Ref1);
927 setRelative(aData.Ref2);
928
929 // In XML, the range must explicitly specify sheet name.
930 aData.Ref1.SetFlag3D(true);
931 aData.Ref2.SetFlag3D(true);
932
933 if (bExternal)
934 rStart.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref1));
935 else
936 rStart.reset(new ScSingleRefToken(rDoc.GetSheetLimits(), aData.Ref1));
937
938 if (bExternal)
939 rEnd.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref2));
940 else
941 rEnd.reset(new ScSingleRefToken(rDoc.GetSheetLimits(), aData.Ref2));
942 return true;
943 }
944
945 static void setRelative(ScSingleRefData& rData)
946 {
947 rData.SetColRel(true);
948 rData.SetRowRel(true);
949 rData.SetTabRel(true);
950 }
951
952private:
953 shared_ptr<OUStringBuffer> mpRangeStr;
954 ScDocument* mpDoc;
955 static const sal_Unicode mcRangeSep = ' ';
956 static const sal_Unicode mcAddrSep = ':';
957 bool mbFirst;
958};
959
960void lcl_convertTokensToString(OUString& rStr, const vector<ScTokenRef>& rTokens, ScDocument& rDoc)
961{
963 FormulaGrammar::Grammar eGrammar = rDoc.GetGrammar();
964 Tokens2RangeString func(rDoc, eGrammar, cRangeSep);
965 func = ::std::for_each(rTokens.begin(), rTokens.end(), func);
966 func.getString(rStr);
967}
968
969} // anonymous namespace
970
971// DataProvider ==============================================================
972
974 : m_pDocument( pDoc)
975 , m_aPropSet(lcl_GetDataProviderPropertyMap())
976 , m_bIncludeHiddenCells( true)
977{
978 if ( m_pDocument )
979 m_pDocument->AddUnoObject( *this);
980}
981
983{
985
986 if ( m_pDocument )
988}
989
991{
992 if ( rHint.GetId() == SfxHintId::Dying )
993 {
994 m_pDocument = nullptr;
995 }
996}
997
998sal_Bool SAL_CALL ScChart2DataProvider::createDataSourcePossible( const uno::Sequence< beans::PropertyValue >& aArguments )
999{
1000 SolarMutexGuard aGuard;
1001 if( ! m_pDocument )
1002 return false;
1003
1004 OUString aRangeRepresentation;
1005 for(const auto& rArgument : aArguments)
1006 {
1007 if ( rArgument.Name == "CellRangeRepresentation" )
1008 {
1009 rArgument.Value >>= aRangeRepresentation;
1010 }
1011 }
1012
1013 vector<ScTokenRef> aTokens;
1016 aTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1017 return !aTokens.empty();
1018}
1019
1020namespace
1021{
1022
1023uno::Reference< chart2::data::XLabeledDataSequence > lcl_createLabeledDataSequenceFromTokens(
1024 vector< ScTokenRef > && aValueTokens, vector< ScTokenRef > && aLabelTokens,
1025 ScDocument* pDoc, bool bIncludeHiddenCells )
1026{
1027 uno::Reference< chart2::data::XLabeledDataSequence > xResult;
1028 bool bHasValues = !aValueTokens.empty();
1029 bool bHasLabel = !aLabelTokens.empty();
1030 if( bHasValues || bHasLabel )
1031 {
1032 try
1033 {
1034 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1035 if ( xContext.is() )
1036 {
1037 xResult.set( chart2::data::LabeledDataSequence::create(xContext), uno::UNO_QUERY_THROW );
1038 }
1039 if ( bHasValues )
1040 {
1041 uno::Reference< chart2::data::XDataSequence > xSeq( new ScChart2DataSequence( pDoc, std::move(aValueTokens), bIncludeHiddenCells ) );
1042 xResult->setValues( xSeq );
1043 }
1044 if ( bHasLabel )
1045 {
1046 //Labels should always include hidden cells, regardless of the bIncludeHiddenCells setting
1047 uno::Reference< chart2::data::XDataSequence > xLabelSeq( new ScChart2DataSequence( pDoc, std::move(aLabelTokens), true ) );
1048 xResult->setLabel( xLabelSeq );
1049 }
1050 }
1051 catch( const uno::Exception& )
1052 {
1053 }
1054 }
1055 return xResult;
1056}
1057
1067bool lcl_addUpperLeftCornerIfMissing(const ScDocument* pDoc, vector<ScTokenRef>& rRefTokens,
1068 SCROW nCornerRowCount, SCCOL nCornerColumnCount)
1069{
1070 using ::std::max;
1071 using ::std::min;
1072
1073 if (rRefTokens.empty())
1074 return false;
1075
1076 SCCOL nMinCol = pDoc->GetSheetLimits().GetMaxColCount();
1077 SCROW nMinRow = pDoc->GetSheetLimits().GetMaxRowCount();
1078 SCCOL nMaxCol = 0;
1079 SCROW nMaxRow = 0;
1080 SCTAB nTab = 0;
1081
1082 sal_uInt16 nFileId = 0;
1083 svl::SharedString aExtTabName;
1084 bool bExternal = false;
1085
1086 vector<ScTokenRef>::const_iterator itr = rRefTokens.begin(), itrEnd = rRefTokens.end();
1087
1088 // Get the first ref token.
1089 ScTokenRef pToken = *itr;
1090 switch (pToken->GetType())
1091 {
1092 case svSingleRef:
1093 {
1094 const ScSingleRefData& rData = *pToken->GetSingleRef();
1095 nMinCol = rData.Col();
1096 nMinRow = rData.Row();
1097 nMaxCol = rData.Col();
1098 nMaxRow = rData.Row();
1099 nTab = rData.Tab();
1100 }
1101 break;
1102 case svDoubleRef:
1103 {
1104 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1105 nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1106 nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1107 nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1108 nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1109 nTab = rData.Ref1.Tab();
1110 }
1111 break;
1113 {
1114 const ScSingleRefData& rData = *pToken->GetSingleRef();
1115 nMinCol = rData.Col();
1116 nMinRow = rData.Row();
1117 nMaxCol = rData.Col();
1118 nMaxRow = rData.Row();
1119 nTab = rData.Tab();
1120 nFileId = pToken->GetIndex();
1121 aExtTabName = pToken->GetString();
1122 bExternal = true;
1123 }
1124 break;
1126 {
1127 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1128 nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1129 nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1130 nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1131 nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1132 nTab = rData.Ref1.Tab();
1133 nFileId = pToken->GetIndex();
1134 aExtTabName = pToken->GetString();
1135 bExternal = true;
1136 }
1137 break;
1138 default:
1139 ;
1140 }
1141
1142 // Determine the minimum range enclosing all data ranges. Also make sure
1143 // that they are all on the same table.
1144
1145 for (++itr; itr != itrEnd; ++itr)
1146 {
1147 pToken = *itr;
1148 switch (pToken->GetType())
1149 {
1150 case svSingleRef:
1151 {
1152 const ScSingleRefData& rData = *pToken->GetSingleRef();
1153
1154 nMinCol = min(nMinCol, rData.Col());
1155 nMinRow = min(nMinRow, rData.Row());
1156 nMaxCol = max(nMaxCol, rData.Col());
1157 nMaxRow = max(nMaxRow, rData.Row());
1158 if (nTab != rData.Tab() || bExternal)
1159 return false;
1160 }
1161 break;
1162 case svDoubleRef:
1163 {
1164 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1165
1166 nMinCol = min(nMinCol, rData.Ref1.Col());
1167 nMinCol = min(nMinCol, rData.Ref2.Col());
1168 nMinRow = min(nMinRow, rData.Ref1.Row());
1169 nMinRow = min(nMinRow, rData.Ref2.Row());
1170
1171 nMaxCol = max(nMaxCol, rData.Ref1.Col());
1172 nMaxCol = max(nMaxCol, rData.Ref2.Col());
1173 nMaxRow = max(nMaxRow, rData.Ref1.Row());
1174 nMaxRow = max(nMaxRow, rData.Ref2.Row());
1175
1176 if (nTab != rData.Ref1.Tab() || bExternal)
1177 return false;
1178 }
1179 break;
1181 {
1182 if (!bExternal)
1183 return false;
1184
1185 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1186 return false;
1187
1188 const ScSingleRefData& rData = *pToken->GetSingleRef();
1189
1190 nMinCol = min(nMinCol, rData.Col());
1191 nMinRow = min(nMinRow, rData.Row());
1192 nMaxCol = max(nMaxCol, rData.Col());
1193 nMaxRow = max(nMaxRow, rData.Row());
1194 }
1195 break;
1197 {
1198 if (!bExternal)
1199 return false;
1200
1201 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1202 return false;
1203
1204 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1205
1206 nMinCol = min(nMinCol, rData.Ref1.Col());
1207 nMinCol = min(nMinCol, rData.Ref2.Col());
1208 nMinRow = min(nMinRow, rData.Ref1.Row());
1209 nMinRow = min(nMinRow, rData.Ref2.Row());
1210
1211 nMaxCol = max(nMaxCol, rData.Ref1.Col());
1212 nMaxCol = max(nMaxCol, rData.Ref2.Col());
1213 nMaxRow = max(nMaxRow, rData.Ref1.Row());
1214 nMaxRow = max(nMaxRow, rData.Ref2.Row());
1215 }
1216 break;
1217 default:
1218 ;
1219 }
1220 }
1221
1222 const auto & rSheetLimits = pDoc->GetSheetLimits();
1223 if (nMinRow >= nMaxRow || nMinCol >= nMaxCol ||
1224 nMinRow >= rSheetLimits.GetMaxRowCount() || nMinCol >= rSheetLimits.GetMaxColCount() ||
1225 nMaxRow >= rSheetLimits.GetMaxRowCount() || nMaxCol >= rSheetLimits.GetMaxColCount())
1226 {
1227 // Invalid range. Bail out.
1228 return false;
1229 }
1230
1231 // Check if the following conditions are met:
1232
1233 // 1) The upper-left corner cell is not included.
1234 // 2) The three adjacent cells of that corner cell are included.
1235
1236 bool bRight = false, bBottom = false, bDiagonal = false;
1237 for (const auto& rxToken : rRefTokens)
1238 {
1239 switch (rxToken->GetType())
1240 {
1241 case svSingleRef:
1243 {
1244 const ScSingleRefData& rData = *rxToken->GetSingleRef();
1245 if (rData.Col() == nMinCol && rData.Row() == nMinRow)
1246 // The corner cell is contained.
1247 return false;
1248
1249 if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow)
1250 bRight = true;
1251
1252 if (rData.Col() == nMinCol && rData.Row() == nMinRow+nCornerRowCount)
1253 bBottom = true;
1254
1255 if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow+nCornerRowCount)
1256 bDiagonal = true;
1257 }
1258 break;
1259 case svDoubleRef:
1261 {
1262 const ScComplexRefData& rData = *rxToken->GetDoubleRef();
1263 const ScSingleRefData& r1 = rData.Ref1;
1264 const ScSingleRefData& r2 = rData.Ref2;
1265 if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1266 r1.Row() <= nMinRow && nMinRow <= r2.Row())
1267 // The corner cell is contained.
1268 return false;
1269
1270 if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1271 r1.Row() <= nMinRow && nMinRow <= r2.Row())
1272 bRight = true;
1273
1274 if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1275 r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1276 bBottom = true;
1277
1278 if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1279 r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1280 bDiagonal = true;
1281 }
1282 break;
1283 default:
1284 ;
1285 }
1286 }
1287
1288 if (!bRight || !bBottom || !bDiagonal)
1289 // Not all the adjacent cells are included. Bail out.
1290 return false;
1291
1293 aData.InitFlags();
1294 aData.SetFlag3D(true);
1295 aData.SetAbsCol(nMinCol);
1296 aData.SetAbsRow(nMinRow);
1297 aData.SetAbsTab(nTab);
1298
1299 if( nCornerRowCount==1 && nCornerColumnCount==1 )
1300 {
1301 if (bExternal)
1302 {
1303 ScTokenRef pCorner(
1304 new ScExternalSingleRefToken(nFileId, aExtTabName, aData));
1305 ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1306 }
1307 else
1308 {
1309 ScTokenRef pCorner(new ScSingleRefToken(pDoc->GetSheetLimits(), aData));
1310 ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1311 }
1312 }
1313 else
1314 {
1315 ScSingleRefData aDataEnd(aData);
1316 aDataEnd.IncCol(nCornerColumnCount-1);
1317 aDataEnd.IncRow(nCornerRowCount-1);
1319 r.Ref1=aData;
1320 r.Ref2=aDataEnd;
1321 if (bExternal)
1322 {
1323 ScTokenRef pCorner(
1324 new ScExternalDoubleRefToken(nFileId, aExtTabName, r));
1325 ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1326 }
1327 else
1328 {
1329 ScTokenRef pCorner(new ScDoubleRefToken(pDoc->GetSheetLimits(), r));
1330 ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1331 }
1332 }
1333
1334 return true;
1335}
1336
1337#define SHRINK_RANGE_THRESHOLD 10000
1338
1339class ShrinkRefTokenToDataRange
1340{
1341 ScDocument* mpDoc;
1342public:
1343 explicit ShrinkRefTokenToDataRange(ScDocument* pDoc) : mpDoc(pDoc) {}
1344 void operator() (const ScTokenRef& rRef)
1345 {
1347 return;
1348
1349 // Don't assume an ScDoubleRefToken if it isn't. It can be at least an
1350 // ScSingleRefToken, then there isn't anything to shrink.
1351 if (rRef->GetType() != svDoubleRef)
1352 return;
1353
1354 ScComplexRefData& rData = *rRef->GetDoubleRef();
1355 ScSingleRefData& s = rData.Ref1;
1356 ScSingleRefData& e = rData.Ref2;
1357
1358 if(abs((e.Col()-s.Col())*(e.Row()-s.Row())) < SHRINK_RANGE_THRESHOLD)
1359 return;
1360
1361 SCCOL nMinCol = mpDoc->MaxCol(), nMaxCol = 0;
1362 SCROW nMinRow = mpDoc->MaxRow(), nMaxRow = 0;
1363
1364 // Determine the smallest range that encompasses the data ranges of all sheets.
1365 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
1366 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
1367 {
1368 SCCOL nCol1 = 0, nCol2 = mpDoc->MaxCol();
1369 SCROW nRow1 = 0, nRow2 = mpDoc->MaxRow();
1370 mpDoc->ShrinkToDataArea(nTab, nCol1, nRow1, nCol2, nRow2);
1371 nMinCol = std::min(nMinCol, nCol1);
1372 nMinRow = std::min(nMinRow, nRow1);
1373 nMaxCol = std::max(nMaxCol, nCol2);
1374 nMaxRow = std::max(nMaxRow, nRow2);
1375 }
1376
1377 // Shrink range to the data range if applicable.
1378 if (s.Col() < nMinCol)
1379 s.SetAbsCol(nMinCol);
1380 if (s.Row() < nMinRow)
1381 s.SetAbsRow(nMinRow);
1382 if (e.Col() > nMaxCol)
1383 e.SetAbsCol(nMaxCol);
1384 if (e.Row() > nMaxRow)
1385 e.SetAbsRow(nMaxRow);
1386 }
1387};
1388
1389void shrinkToDataRange(ScDocument* pDoc, vector<ScTokenRef>& rRefTokens)
1390{
1391 std::for_each(rRefTokens.begin(), rRefTokens.end(), ShrinkRefTokenToDataRange(pDoc));
1392}
1393
1394}
1395
1396uno::Reference< chart2::data::XDataSource> SAL_CALL
1398 const uno::Sequence< beans::PropertyValue >& aArguments )
1399{
1400 SolarMutexGuard aGuard;
1401 if ( ! m_pDocument )
1402 throw uno::RuntimeException();
1403
1404 // This is expensive to compute and we get called more than once, so cache
1406 return mxCreatedDataSource;
1408
1409 bool bLabel = true;
1410 bool bCategories = false;
1411 bool bOrientCol = true;
1412 OUString aRangeRepresentation;
1413 uno::Sequence< sal_Int32 > aSequenceMapping;
1414 bool bTimeBased = false;
1415 for(const auto& rArgument : aArguments)
1416 {
1417 if ( rArgument.Name == "DataRowSource" )
1418 {
1419 chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
1420 if( ! (rArgument.Value >>= eSource))
1421 {
1422 sal_Int32 nSource(0);
1423 if( rArgument.Value >>= nSource )
1424 eSource = static_cast< chart::ChartDataRowSource >( nSource );
1425 }
1426 bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
1427 }
1428 else if ( rArgument.Name == "FirstCellAsLabel" )
1429 {
1430 bLabel = ::cppu::any2bool(rArgument.Value);
1431 }
1432 else if ( rArgument.Name == "HasCategories" )
1433 {
1434 bCategories = ::cppu::any2bool(rArgument.Value);
1435 }
1436 else if ( rArgument.Name == "CellRangeRepresentation" )
1437 {
1438 rArgument.Value >>= aRangeRepresentation;
1439 }
1440 else if ( rArgument.Name == "SequenceMapping" )
1441 {
1442 rArgument.Value >>= aSequenceMapping;
1443 }
1444 else if ( rArgument.Name == "TimeBased" )
1445 {
1446 rArgument.Value >>= bTimeBased;
1447 }
1448 }
1449
1450 vector<ScTokenRef> aRefTokens;
1453 aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1454 if (aRefTokens.empty())
1455 // Invalid range representation. Bail out.
1456 throw lang::IllegalArgumentException();
1457
1458 SCTAB nTimeBasedStart = MAXTAB;
1459 SCTAB nTimeBasedEnd = 0;
1460 if(bTimeBased)
1461 {
1462 // limit to first sheet
1463 for(const auto& rxToken : aRefTokens)
1464 {
1465 if (rxToken->GetType() != svDoubleRef)
1466 continue;
1467
1468 ScComplexRefData& rData = *rxToken->GetDoubleRef();
1469 ScSingleRefData& s = rData.Ref1;
1470 ScSingleRefData& e = rData.Ref2;
1471
1472 nTimeBasedStart = std::min(nTimeBasedStart, s.Tab());
1473 nTimeBasedEnd = std::min(nTimeBasedEnd, e.Tab());
1474
1475 if(s.Tab() != e.Tab())
1476 e.SetAbsTab(s.Tab());
1477 }
1478 }
1479
1480 if(!bTimeBased)
1481 shrinkToDataRange(m_pDocument, aRefTokens);
1482
1483 if (bLabel)
1484 lcl_addUpperLeftCornerIfMissing(m_pDocument, aRefTokens, 1, 1); //#i90669#
1485
1486 bool bColHeaders = (bOrientCol ? bLabel : bCategories );
1487 bool bRowHeaders = (bOrientCol ? bCategories : bLabel );
1488
1489 Chart2Positioner aChPositioner(m_pDocument, aRefTokens);
1490 aChPositioner.setHeaders(bColHeaders, bRowHeaders);
1491
1492 const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap();
1493 if (!pChartMap)
1494 // No chart position map instance. Bail out.
1495 return mxCreatedDataSource;
1496
1498 ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqs;
1499
1500 // Fill Categories
1501 if( bCategories )
1502 {
1503 vector<ScTokenRef> aValueTokens;
1504 if (bOrientCol)
1505 aValueTokens = pChartMap->getAllRowHeaderRanges();
1506 else
1507 aValueTokens = pChartMap->getAllColHeaderRanges();
1508
1509 vector<ScTokenRef> aLabelTokens(
1510 pChartMap->getLeftUpperCornerRanges());
1511
1512 uno::Reference< chart2::data::XLabeledDataSequence > xCategories = lcl_createLabeledDataSequenceFromTokens(
1513 std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1514 if ( xCategories.is() )
1515 {
1516 aSeqs.push_back( xCategories );
1517 }
1518 }
1519
1520 // Fill Series (values and label)
1521 sal_Int32 nCount = bOrientCol ? pChartMap->getDataColCount() : pChartMap->getDataRowCount();
1522 for (sal_Int32 i = 0; i < nCount; ++i)
1523 {
1524 vector<ScTokenRef> aValueTokens;
1525 vector<ScTokenRef> aLabelTokens;
1526 if (bOrientCol)
1527 {
1528 aValueTokens = pChartMap->getDataColRanges(static_cast<SCCOL>(i));
1529 aLabelTokens = pChartMap->getColHeaderRanges(static_cast<SCCOL>(i));
1530 }
1531 else
1532 {
1533 aValueTokens = pChartMap->getDataRowRanges(static_cast<SCROW>(i));
1534 aLabelTokens = pChartMap->getRowHeaderRanges(static_cast<SCROW>(i));
1535 }
1536 uno::Reference< chart2::data::XLabeledDataSequence > xChartSeries = lcl_createLabeledDataSequenceFromTokens(
1537 std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1538 if ( xChartSeries.is() && xChartSeries->getValues().is() && xChartSeries->getValues()->getData().hasElements() )
1539 {
1540 aSeqs.push_back( xChartSeries );
1541 }
1542 }
1543
1545
1546 //reorder labeled sequences according to aSequenceMapping
1547 ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqVector;
1548 aSeqVector.reserve(aSeqs.size());
1549 for (auto const& aSeq : aSeqs)
1550 {
1551 aSeqVector.push_back(aSeq);
1552 }
1553
1554 for( const sal_Int32 nNewIndex : std::as_const(aSequenceMapping) )
1555 {
1556 // note: assuming that the values in the sequence mapping are always non-negative
1557 ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > >::size_type nOldIndex( static_cast< sal_uInt32 >( nNewIndex ) );
1558 if( nOldIndex < aSeqVector.size() )
1559 {
1560 pDS->AddLabeledSequence( aSeqVector[nOldIndex] );
1561 aSeqVector[nOldIndex] = nullptr;
1562 }
1563 }
1564
1565 for(const uno::Reference< chart2::data::XLabeledDataSequence >& xSeq : aSeqVector)
1566 {
1567 if ( xSeq.is() )
1568 {
1569 pDS->AddLabeledSequence( xSeq );
1570 }
1571 }
1572
1573 mxCreatedDataSource.set(pDS);
1574 return mxCreatedDataSource;
1575}
1576
1577namespace
1578{
1579
1583class InsertTabNumber
1584{
1585public:
1586 InsertTabNumber() :
1587 mpTabNumVector(std::make_shared<vector<SCTAB>>())
1588 {
1589 }
1590
1591 void operator() (const ScTokenRef& pToken) const
1592 {
1593 if (!ScRefTokenHelper::isRef(pToken))
1594 return;
1595
1596 const ScSingleRefData& r = *pToken->GetSingleRef();
1597 mpTabNumVector->push_back(r.Tab());
1598 }
1599
1600 void getVector(vector<SCTAB>& rVector)
1601 {
1602 mpTabNumVector->swap(rVector);
1603 }
1604private:
1605 shared_ptr< vector<SCTAB> > mpTabNumVector;
1606};
1607
1608class RangeAnalyzer
1609{
1610public:
1611 RangeAnalyzer();
1612 void initRangeAnalyzer( const ScDocument* pDoc, const vector<ScTokenRef>& rTokens );
1613 void analyzeRange( sal_Int32& rnDataInRows, sal_Int32& rnDataInCols,
1614 bool& rbRowSourceAmbiguous ) const;
1615 bool inSameSingleRow( const RangeAnalyzer& rOther );
1616 bool inSameSingleColumn( const RangeAnalyzer& rOther );
1617 SCROW getRowCount() const { return mnRowCount; }
1618 SCCOL getColumnCount() const { return mnColumnCount; }
1619
1620private:
1621 bool mbEmpty;
1622 bool mbAmbiguous;
1623 SCROW mnRowCount;
1624 SCCOL mnColumnCount;
1625
1626 SCCOL mnStartColumn;
1627 SCROW mnStartRow;
1628};
1629
1630RangeAnalyzer::RangeAnalyzer()
1631 : mbEmpty(true)
1632 , mbAmbiguous(false)
1633 , mnRowCount(0)
1634 , mnColumnCount(0)
1635 , mnStartColumn(-1)
1636 , mnStartRow(-1)
1637{
1638}
1639
1640void RangeAnalyzer::initRangeAnalyzer( const ScDocument* pDoc, const vector<ScTokenRef>& rTokens )
1641{
1642 mnRowCount=0;
1643 mnColumnCount=0;
1644 mnStartColumn = -1;
1645 mnStartRow = -1;
1646 mbAmbiguous=false;
1647 if( rTokens.empty() )
1648 {
1649 mbEmpty=true;
1650 return;
1651 }
1652 mbEmpty=false;
1653
1654 for (const ScTokenRef& aRefToken : rTokens)
1655 {
1656 StackVar eVar = aRefToken->GetType();
1657 if (eVar == svDoubleRef || eVar == svExternalDoubleRef)
1658 {
1659 const ScComplexRefData& r = *aRefToken->GetDoubleRef();
1660 if (r.Ref1.Tab() == r.Ref2.Tab())
1661 {
1662 mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(r.Ref2.Col() - r.Ref1.Col())+1));
1663 mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(r.Ref2.Row() - r.Ref1.Row())+1));
1664 if( mnStartColumn == -1 )
1665 {
1666 mnStartColumn = r.Ref1.Col();
1667 mnStartRow = r.Ref1.Row();
1668 }
1669 else
1670 {
1671 if (mnStartColumn != r.Ref1.Col() && mnStartRow != r.Ref1.Row())
1672 mbAmbiguous=true;
1673 }
1674 }
1675 else
1676 mbAmbiguous=true;
1677 }
1678 else if (eVar == svSingleRef || eVar == svExternalSingleRef)
1679 {
1680 const ScSingleRefData& r = *aRefToken->GetSingleRef();
1681 mnColumnCount = std::max<SCCOL>( mnColumnCount, 1);
1682 mnRowCount = std::max<SCROW>( mnRowCount, 1);
1683 if( mnStartColumn == -1 )
1684 {
1685 mnStartColumn = r.Col();
1686 mnStartRow = r.Row();
1687 }
1688 else
1689 {
1690 if (mnStartColumn != r.Col() && mnStartRow != r.Row())
1691 mbAmbiguous=true;
1692 }
1693 }
1694 else if (eVar == svIndex && aRefToken->GetOpCode() == ocName)
1695 {
1696 ScRangeData* pNameRange = pDoc->FindRangeNameBySheetAndIndex(aRefToken->GetSheet(), aRefToken->GetIndex());
1697 ScRange aRange;
1698 if (pNameRange->IsReference(aRange))
1699 {
1700 mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(aRange.aEnd.Col() - aRange.aStart.Col()) + 1));
1701 mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(aRange.aEnd.Row() - aRange.aStart.Row()) + 1));
1702 if (mnStartColumn == -1)
1703 {
1704 mnStartColumn = aRange.aStart.Col();
1705 mnStartRow = aRange.aStart.Row();
1706 }
1707 else
1708 {
1709 if (mnStartColumn != aRange.aStart.Col() && mnStartRow != aRange.aStart.Row())
1710 mbAmbiguous = true;
1711 }
1712 }
1713 else
1714 mbAmbiguous = true;
1715 }
1716 else
1717 mbAmbiguous=true;
1718 }
1719}
1720
1721void RangeAnalyzer::analyzeRange( sal_Int32& rnDataInRows,
1722 sal_Int32& rnDataInCols,
1723 bool& rbRowSourceAmbiguous ) const
1724{
1725 if(!mbEmpty && !mbAmbiguous)
1726 {
1727 if( mnRowCount==1 && mnColumnCount>1 )
1728 ++rnDataInRows;
1729 else if( mnColumnCount==1 && mnRowCount>1 )
1730 ++rnDataInCols;
1731 else if( mnRowCount>1 && mnColumnCount>1 )
1732 rbRowSourceAmbiguous = true;
1733 }
1734 else if( !mbEmpty )
1735 rbRowSourceAmbiguous = true;
1736}
1737
1738bool RangeAnalyzer::inSameSingleRow( const RangeAnalyzer& rOther )
1739{
1740 return mnStartRow==rOther.mnStartRow &&
1741 mnRowCount==1 && rOther.mnRowCount==1;
1742}
1743
1744bool RangeAnalyzer::inSameSingleColumn( const RangeAnalyzer& rOther )
1745{
1746 return mnStartColumn==rOther.mnStartColumn &&
1747 mnColumnCount==1 && rOther.mnColumnCount==1;
1748}
1749
1750std::pair<OUString, OUString> constructKey(const uno::Reference< chart2::data::XLabeledDataSequence>& xNew)
1751{
1752 std::pair<OUString, OUString> aKey;
1753 if( xNew->getLabel().is() )
1754 aKey.first = xNew->getLabel()->getSourceRangeRepresentation();
1755 if( xNew->getValues().is() )
1756 aKey.second = xNew->getValues()->getSourceRangeRepresentation();
1757 return aKey;
1758}
1759
1760
1761} //end anonymous namespace
1762
1763uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments(
1764 const uno::Reference< chart2::data::XDataSource >& xDataSource )
1765{
1766 // Cache these because this is expensive to compute and we get called more than once
1767 if (xDataSource == mxCachedDataSource)
1768 return maCachedArguments;
1769
1770 ::std::vector< beans::PropertyValue > aResult;
1771 bool bRowSourceDetected = false;
1772 bool bFirstCellAsLabel = false;
1773 bool bHasCategories = false;
1774 OUString sRangeRep;
1775
1776 bool bHasCategoriesLabels = false;
1777 vector<ScTokenRef> aAllCategoriesValuesTokens;
1778 vector<ScTokenRef> aAllSeriesLabelTokens;
1779
1780 chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS;
1781
1782 vector<ScTokenRef> aAllTokens;
1783
1784 // parse given data source and collect infos
1785 {
1786 SolarMutexGuard aGuard;
1787 OSL_ENSURE( m_pDocument, "No Document -> no detectArguments" );
1788 if(!m_pDocument ||!xDataSource.is())
1789 return comphelper::containerToSequence( aResult );
1790
1791 sal_Int32 nDataInRows = 0;
1792 sal_Int32 nDataInCols = 0;
1793 bool bRowSourceAmbiguous = false;
1794
1795 const Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences());
1796 const sal_Int32 nCount( aSequences.getLength());
1797 RangeAnalyzer aPrevLabel,aPrevValues;
1798 for( const uno::Reference< chart2::data::XLabeledDataSequence >& xLS : aSequences )
1799 {
1800 if( xLS.is() )
1801 {
1802 bool bThisIsCategories = false;
1803 if(!bHasCategories)
1804 {
1805 uno::Reference< beans::XPropertySet > xSeqProp( xLS->getValues(), uno::UNO_QUERY );
1806 OUString aRole;
1807 if( xSeqProp.is() && (xSeqProp->getPropertyValue("Role") >>= aRole) &&
1808 aRole == "categories" )
1809 bThisIsCategories = bHasCategories = true;
1810 }
1811
1812 RangeAnalyzer aLabel,aValues;
1813 // label
1814 uno::Reference< chart2::data::XDataSequence > xLabel( xLS->getLabel());
1815 if( xLabel.is())
1816 {
1817 bFirstCellAsLabel = true;
1818 vector<ScTokenRef> aTokens;
1821 aTokens, xLabel->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1822 aLabel.initRangeAnalyzer(m_pDocument, aTokens);
1823 for (const auto& rxToken : aTokens)
1824 {
1825 if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
1826 {
1827 ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
1828 if (pNameRange->HasReferences())
1829 {
1830 const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
1831 ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
1832 }
1833 else
1834 ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1835 }
1836 else
1837 ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1838 if(!bThisIsCategories)
1839 ScRefTokenHelper::join(m_pDocument, aAllSeriesLabelTokens, rxToken, ScAddress());
1840 }
1841 if(bThisIsCategories)
1842 bHasCategoriesLabels=true;
1843 }
1844 // values
1845 uno::Reference< chart2::data::XDataSequence > xValues( xLS->getValues());
1846 if( xValues.is())
1847 {
1848 vector<ScTokenRef> aTokens;
1851 aTokens, xValues->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1852 aValues.initRangeAnalyzer(m_pDocument, aTokens);
1853 for (const auto& rxToken : aTokens)
1854 {
1855 if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
1856 {
1857 ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
1858 if (pNameRange->HasReferences())
1859 {
1860 const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
1861 ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
1862 }
1863 else
1864 ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1865 }
1866 else
1867 ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1868 if(bThisIsCategories)
1869 ScRefTokenHelper::join(m_pDocument, aAllCategoriesValuesTokens, rxToken, ScAddress());
1870 }
1871 }
1872 //detect row source
1873 if(!bThisIsCategories || nCount==1) //categories might span multiple rows *and* columns, so they should be used for detection only if nothing else is available
1874 {
1875 if (!bRowSourceAmbiguous)
1876 {
1877 aValues.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1878 aLabel.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1879 if (nDataInRows > 1 && nDataInCols > 1)
1880 bRowSourceAmbiguous = true;
1881 else if( !bRowSourceAmbiguous && !nDataInRows && !nDataInCols )
1882 {
1883 if( aValues.inSameSingleColumn( aLabel ) )
1884 nDataInCols++;
1885 else if( aValues.inSameSingleRow( aLabel ) )
1886 nDataInRows++;
1887 else
1888 {
1889 //#i86188# also detect a single column split into rows correctly
1890 if( aValues.inSameSingleColumn( aPrevValues ) )
1891 nDataInRows++;
1892 else if( aValues.inSameSingleRow( aPrevValues ) )
1893 nDataInCols++;
1894 else if( aLabel.inSameSingleColumn( aPrevLabel ) )
1895 nDataInRows++;
1896 else if( aLabel.inSameSingleRow( aPrevLabel ) )
1897 nDataInCols++;
1898 }
1899 }
1900 }
1901 }
1902 aPrevValues=aValues;
1903 aPrevLabel=aLabel;
1904 }
1905 }
1906
1907 if (!bRowSourceAmbiguous)
1908 {
1909 bRowSourceDetected = true;
1910 eRowSource = ( nDataInCols > 0
1911 ? chart::ChartDataRowSource_COLUMNS
1912 : chart::ChartDataRowSource_ROWS );
1913 }
1914 else
1915 {
1916 // set DataRowSource to the better of the two ambiguities
1917 eRowSource = ( nDataInRows > nDataInCols
1918 ? chart::ChartDataRowSource_ROWS
1919 : chart::ChartDataRowSource_COLUMNS );
1920 }
1921
1922 }
1923
1924 // TableNumberList
1925 {
1926 vector<SCTAB> aTableNumVector;
1927 InsertTabNumber func;
1928 func = ::std::for_each(aAllTokens.begin(), aAllTokens.end(), func);
1929 func.getVector(aTableNumVector);
1930 aResult.emplace_back( "TableNumberList", -1,
1931 uno::Any( lcl_createTableNumberList( aTableNumVector ) ),
1932 beans::PropertyState_DIRECT_VALUE );
1933 }
1934
1935 if( bRowSourceDetected )
1936 {
1937 // DataRowSource (calculated before)
1938 aResult.emplace_back( "DataRowSource", -1,
1939 uno::Any( eRowSource ), beans::PropertyState_DIRECT_VALUE );
1940 // HasCategories
1941 aResult.emplace_back( "HasCategories", -1,
1942 uno::Any( bHasCategories ), beans::PropertyState_DIRECT_VALUE );
1943 // FirstCellAsLabel
1944 aResult.emplace_back( "FirstCellAsLabel", -1,
1945 uno::Any( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE );
1946 }
1947
1948 // Add the left upper corner to the range if it is missing.
1949 if (bRowSourceDetected && bFirstCellAsLabel && bHasCategories && !bHasCategoriesLabels )
1950 {
1951 RangeAnalyzer aTop,aLeft;
1952 if( eRowSource==chart::ChartDataRowSource_COLUMNS )
1953 {
1954 aTop.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
1955 aLeft.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
1956 }
1957 else
1958 {
1959 aTop.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
1960 aLeft.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
1961 }
1962 lcl_addUpperLeftCornerIfMissing(m_pDocument, aAllTokens, aTop.getRowCount(), aLeft.getColumnCount());//e.g. #i91212#
1963 }
1964
1965 // Get range string.
1966 lcl_convertTokensToString(sRangeRep, aAllTokens, *m_pDocument);
1967
1968 // add cell range property
1969 aResult.emplace_back( "CellRangeRepresentation", -1,
1970 uno::Any( sRangeRep ), beans::PropertyState_DIRECT_VALUE );
1971
1972 //Sequence Mapping
1973 bool const bSequencesReordered = true;//todo detect this above or detect this sequence mapping cheaper ...
1974 if( bSequencesReordered && bRowSourceDetected )
1975 {
1976 bool bDifferentIndexes = false;
1977
1978 std::vector< sal_Int32 > aSequenceMappingVector;
1979
1980 uno::Reference< chart2::data::XDataSource > xCompareDataSource;
1981 try
1982 {
1983 xCompareDataSource.set( createDataSource( comphelper::containerToSequence( aResult ) ) );
1984 }
1985 catch( const lang::IllegalArgumentException & )
1986 {
1987 // creation of data source to compare didn't work, so we cannot
1988 // create a sequence mapping
1989 }
1990
1991 if( xDataSource.is() && xCompareDataSource.is() )
1992 {
1993 const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aOldSequences =
1994 xCompareDataSource->getDataSequences();
1995 const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aNewSequences =
1996 xDataSource->getDataSequences();
1997
1998 std::map<std::pair<OUString, OUString>,sal_Int32> aOldEntryToIndex;
1999 for( sal_Int32 nIndex = 0, n = aOldSequences.getLength(); nIndex < n; nIndex++ )
2000 {
2001 const uno::Reference< chart2::data::XLabeledDataSequence>& xOld( aOldSequences[nIndex] );
2002 if( xOld.is() )
2003 {
2004 std::pair<OUString, OUString> aKey = constructKey(xOld);
2005 aOldEntryToIndex[aKey] = nIndex;
2006 }
2007 }
2008
2009 for( sal_Int32 nNewIndex = 0, n = aNewSequences.getLength(); nNewIndex < n; nNewIndex++ )
2010 {
2011 const uno::Reference< chart2::data::XLabeledDataSequence>& xNew( aNewSequences[nNewIndex] );
2012 if( !xNew.is() )
2013 continue;
2014
2015 std::pair<OUString, OUString> aKey = constructKey(xNew);
2016 if (aOldEntryToIndex.find(aKey) == aOldEntryToIndex.end())
2017 continue;
2018
2019 sal_Int32 nOldIndex = aOldEntryToIndex[aKey];
2020 if( nOldIndex != nNewIndex )
2021 bDifferentIndexes = true;
2022
2023 aSequenceMappingVector.push_back(nOldIndex);
2024 }
2025 }
2026
2027 if( bDifferentIndexes && !aSequenceMappingVector.empty() )
2028 {
2029 aResult.emplace_back( "SequenceMapping", -1,
2030 uno::Any( comphelper::containerToSequence(aSequenceMappingVector) )
2031 , beans::PropertyState_DIRECT_VALUE );
2032 }
2033 }
2034
2035 mxCachedDataSource = xDataSource;
2037
2038 return maCachedArguments;
2039}
2040
2042{
2043 SolarMutexGuard aGuard;
2044 if( ! m_pDocument )
2045 return false;
2046
2047 vector<ScTokenRef> aTokens;
2050 aTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2051 return !aTokens.empty();
2052}
2053
2054uno::Reference< chart2::data::XDataSequence > SAL_CALL
2056 const OUString& aRangeRepresentation )
2057{
2058 SolarMutexGuard aGuard;
2059 uno::Reference< chart2::data::XDataSequence > xResult;
2060
2061 OSL_ENSURE( m_pDocument, "No Document -> no createDataSequenceByRangeRepresentation" );
2062 if(!m_pDocument || aRangeRepresentation.isEmpty())
2063 return xResult;
2064
2065 vector<ScTokenRef> aRefTokens;
2068 aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2069 if (aRefTokens.empty())
2070 return xResult;
2071
2072 shrinkToDataRange(m_pDocument, aRefTokens);
2073
2074 xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
2075
2076 return xResult;
2077}
2078
2079uno::Reference<chart2::data::XDataSequence> SAL_CALL
2081 const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/,
2082 const OUString& /*aRoleQualifier*/ )
2083{
2084 return uno::Reference<chart2::data::XDataSequence>();
2085}
2086
2087uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRangeSelection()
2088{
2089 uno::Reference< sheet::XRangeSelection > xResult;
2090
2091 uno::Reference< frame::XModel > xModel( lcl_GetXModel( m_pDocument ));
2092 if( xModel.is())
2093 xResult.set( xModel->getCurrentController(), uno::UNO_QUERY );
2094
2095 return xResult;
2096}
2097
2099 const Sequence<sheet::FormulaToken>& aTokens )
2100{
2101 if (!aTokens.hasElements())
2102 return false;
2103
2104 ScTokenArray aCode(*m_pDocument);
2106 return false;
2107
2108 sal_uInt16 n = aCode.GetLen();
2109 if (!n)
2110 return false;
2111
2113 const formula::FormulaToken* pFirst = aIter.First();
2114 const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2115 for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
2116 {
2117 switch (p->GetType())
2118 {
2119 case svSep:
2120 {
2121 switch (p->GetOpCode())
2122 {
2123 case ocSep:
2124 // separators are allowed.
2125 break;
2126 case ocOpen:
2127 if (p != pFirst)
2128 // open paran is allowed only as the first token.
2129 return false;
2130 break;
2131 case ocClose:
2132 if (p != pLast)
2133 // close paren is allowed only as the last token.
2134 return false;
2135 break;
2136 default:
2137 return false;
2138 }
2139 }
2140 break;
2141 case svSingleRef:
2142 case svDoubleRef:
2145 break;
2146 default:
2147 return false;
2148 }
2149 }
2150
2151 return true;
2152}
2153
2154uno::Reference<chart2::data::XDataSequence> SAL_CALL
2156 const Sequence<sheet::FormulaToken>& aTokens )
2157{
2158 uno::Reference<chart2::data::XDataSequence> xResult;
2159 if (!aTokens.hasElements())
2160 return xResult;
2161
2162 ScTokenArray aCode(*m_pDocument);
2164 return xResult;
2165
2166 sal_uInt16 n = aCode.GetLen();
2167 if (!n)
2168 return xResult;
2169
2170 vector<ScTokenRef> aRefTokens;
2172 const formula::FormulaToken* pFirst = aIter.First();
2173 const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2174 for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
2175 {
2176 switch (p->GetType())
2177 {
2178 case svSep:
2179 {
2180 switch (p->GetOpCode())
2181 {
2182 case ocSep:
2183 // separators are allowed.
2184 break;
2185 case ocOpen:
2186 if (p != pFirst)
2187 // open paran is allowed only as the first token.
2188 throw lang::IllegalArgumentException();
2189 break;
2190 case ocClose:
2191 if (p != pLast)
2192 // close paren is allowed only as the last token.
2193 throw lang::IllegalArgumentException();
2194 break;
2195 default:
2196 throw lang::IllegalArgumentException();
2197 }
2198 }
2199 break;
2200 case svIndex:
2201 case svString:
2202 case svSingleRef:
2203 case svDoubleRef:
2206 {
2207 ScTokenRef pNew(p->Clone());
2208 aRefTokens.push_back(pNew);
2209 }
2210 break;
2211 default:
2212 throw lang::IllegalArgumentException();
2213 }
2214 }
2215
2216 if (aRefTokens.empty())
2217 return xResult;
2218
2219 shrinkToDataRange(m_pDocument, aRefTokens);
2220
2221 xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
2222 return xResult;
2223}
2224
2225// XRangeXMLConversion ---------------------------------------------------
2226
2227OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const OUString& sRangeRepresentation )
2228{
2229 OUString aRet;
2230 if (!m_pDocument)
2231 return aRet;
2232
2233 if (sRangeRepresentation.isEmpty())
2234 // Empty data range is allowed.
2235 return aRet;
2236
2237 vector<ScTokenRef> aRefTokens;
2240 aRefTokens, sRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2241 if (aRefTokens.empty())
2242 {
2243 SAL_WARN("sc", "convertRangeToXML throw IllegalArgumentException from input of: " << sRangeRepresentation);
2244 throw lang::IllegalArgumentException();
2245 }
2246
2247 Tokens2RangeStringXML converter(*m_pDocument);
2248 converter = ::std::for_each(aRefTokens.begin(), aRefTokens.end(), converter);
2249 converter.getString(aRet);
2250
2251 return aRet;
2252}
2253
2254OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const OUString& sXMLRange )
2255{
2256 if (!m_pDocument)
2257 {
2258 // #i74062# When loading flat XML, this is called before the referenced sheets are in the document,
2259 // so the conversion has to take place directly with the strings, without looking up the sheets.
2260
2261 OUStringBuffer sRet;
2262 sal_Int32 nOffset = 0;
2263 while( nOffset >= 0 )
2264 {
2265 OUString sToken;
2266 ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset );
2267 if( nOffset >= 0 )
2268 {
2269 // convert one address (remove dots)
2270
2271 OUString aUIString(sToken);
2272
2273 sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0 );
2274 if ( nIndex >= 0 && nIndex < aUIString.getLength() - 1 &&
2275 aUIString[nIndex + 1] == '.' )
2276 aUIString = aUIString.replaceAt( nIndex + 1, 1, u"" );
2277
2278 if ( aUIString[0] == '.' )
2279 aUIString = aUIString.copy( 1 );
2280
2281 if( !sRet.isEmpty() )
2282 sRet.append( ';' );
2283 sRet.append( aUIString );
2284 }
2285 }
2286
2287 return sRet.makeStringAndClear();
2288 }
2289
2290 OUString aRet;
2292 return aRet;
2293}
2294
2295// DataProvider XPropertySet -------------------------------------------------
2296
2297uno::Reference< beans::XPropertySetInfo> SAL_CALL
2299{
2300 SolarMutexGuard aGuard;
2301 static uno::Reference<beans::XPropertySetInfo> aRef =
2303 return aRef;
2304}
2305
2307 const OUString& rPropertyName, const uno::Any& rValue)
2308{
2309 if ( rPropertyName != SC_UNONAME_INCLUDEHIDDENCELLS )
2310 throw beans::UnknownPropertyException(rPropertyName);
2311
2312 if ( !(rValue >>= m_bIncludeHiddenCells))
2313 throw lang::IllegalArgumentException();
2314
2315}
2316
2318 const OUString& rPropertyName)
2319{
2320 uno::Any aRet;
2321 if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2322 aRet <<= m_bIncludeHiddenCells;
2323 else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
2324 {
2325 // This is a read-only property.
2327 }
2328 else
2329 throw beans::UnknownPropertyException(rPropertyName);
2330 return aRet;
2331}
2332
2334 const OUString& /*rPropertyName*/,
2335 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
2336{
2337 OSL_FAIL( "Not yet implemented" );
2338}
2339
2341 const OUString& /*rPropertyName*/,
2342 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
2343{
2344 OSL_FAIL( "Not yet implemented" );
2345}
2346
2348 const OUString& /*rPropertyName*/,
2349 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
2350{
2351 OSL_FAIL( "Not yet implemented" );
2352}
2353
2355 const OUString& /*rPropertyName*/,
2356 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/ )
2357{
2358 OSL_FAIL( "Not yet implemented" );
2359}
2360
2361// DataSource ================================================================
2362
2364 : m_pDocument( pDoc)
2365{
2366 if ( m_pDocument )
2367 m_pDocument->AddUnoObject( *this);
2368}
2369
2371{
2373
2374 if ( m_pDocument )
2376}
2377
2379{
2380 if ( rHint.GetId() == SfxHintId::Dying )
2381 {
2382 m_pDocument = nullptr;
2383 }
2384}
2385
2386uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > SAL_CALL
2388{
2389 SolarMutexGuard aGuard;
2391}
2392
2393void ScChart2DataSource::AddLabeledSequence(const uno::Reference < chart2::data::XLabeledDataSequence >& xNew)
2394{
2395 m_aLabeledSequences.push_back(xNew);
2396}
2397
2398// DataSequence ==============================================================
2399
2401 : mfValue(std::numeric_limits<double>::quiet_NaN())
2402 , mbIsValue(false)
2403{
2404}
2405
2407 mrParent(rParent)
2408{
2409}
2410
2412{
2413}
2414
2416{
2417 mrParent.setDataChangedHint(true);
2418}
2419
2421 vector<ScTokenRef>&& rTokens,
2422 bool bIncludeHiddenCells )
2423 : m_bIncludeHiddenCells( bIncludeHiddenCells)
2424 , m_nObjectId( 0 )
2425 , m_pDocument( pDoc)
2426 , m_aTokens(std::move(rTokens))
2428 , m_bGotDataChangedHint(false)
2430 , mbTimeBased(false)
2431 , mnTimeBasedStart(0)
2432 , mnTimeBasedEnd(0)
2433 , mnCurrentTab(0)
2434{
2435 if ( m_pDocument )
2436 {
2437 m_pDocument->AddUnoObject( *this);
2439 }
2440 // FIXME: real implementation of identifier and it's mapping to ranges.
2441 // Reuse ScChartListener?
2442
2443 // BM: don't use names of named ranges but the UI range strings
2444// String aStr;
2445// rRangeList->Format( aStr, ScRefFlags::RANGE_ABS_3D, m_pDocument );
2446// m_aIdentifier = aStr;
2447
2448// m_aIdentifier = "ID_";
2449// static sal_Int32 nID = 0;
2450// m_aIdentifier += OUString::valueOf( ++nID);
2451}
2452
2454{
2456
2457 if ( m_pDocument )
2458 {
2461 {
2463 if (pCLC)
2465 }
2467 }
2468
2469 m_pValueListener.reset();
2470}
2471
2473{
2474 if( !m_pValueListener || m_aValueListeners.empty() )
2475 return;
2476
2477 m_pValueListener->EndListeningAll();
2478
2479 if( !m_pDocument )
2480 return;
2481
2482 ScChartListenerCollection* pCLC = nullptr;
2484 {
2486 if (pCLC)
2488 }
2489
2490 for (const auto& rxToken : m_aTokens)
2491 {
2492 ScRange aRange;
2494 continue;
2495
2496 m_pDocument->StartListeningArea(aRange, false, m_pValueListener.get());
2497 if (pCLC)
2498 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
2499 }
2500}
2501
2503{
2505
2506 if (!m_aDataArray.empty())
2507 return;
2508
2510
2511 ::std::vector<sal_Int32> aHiddenValues;
2512 sal_Int32 nDataCount = 0;
2513
2514 for (const auto& rxToken : m_aTokens)
2515 {
2517 {
2518 nDataCount += FillCacheFromExternalRef(rxToken);
2519 }
2520 else
2521 {
2522 ScRange aRange;
2524 continue;
2525
2526 SCCOL nLastCol = -1;
2527 SCROW nLastRow = -1;
2528 for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
2529 {
2530 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
2531 {
2533 m_pDocument->InitColumnBlockPosition( hint, nTab, nCol );
2534 for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
2535 {
2536 bool bColHidden = m_pDocument->ColHidden(nCol, nTab, nullptr, &nLastCol);
2537 bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, nullptr, &nLastRow);
2538
2539 if (bColHidden || bRowHidden)
2540 {
2541 // hidden cell
2542 aHiddenValues.push_back(nDataCount-1);
2543
2545 continue;
2546 }
2547
2548 Item aItem;
2549
2550 ScAddress aAdr(nCol, nRow, nTab);
2551 aItem.maString = m_pDocument->GetString(aAdr);
2552
2553 ScRefCellValue aCell(*m_pDocument, aAdr, hint);
2554 switch (aCell.getType())
2555 {
2556 case CELLTYPE_VALUE:
2557 aItem.mfValue = aCell.getValue();
2558 aItem.mbIsValue = true;
2559 break;
2560 case CELLTYPE_FORMULA:
2561 {
2562 ScFormulaCell* pFCell = aCell.getFormula();
2563 FormulaError nErr = pFCell->GetErrCode();
2564 if (nErr != FormulaError::NONE)
2565 break;
2566
2567 if (pFCell->IsValue())
2568 {
2569 aItem.mfValue = pFCell->GetValue();
2570 aItem.mbIsValue = true;
2571 }
2572 }
2573 break;
2574 case CELLTYPE_EDIT:
2575 case CELLTYPE_NONE:
2576 case CELLTYPE_STRING:
2577 default:
2578 ; // do nothing
2579 }
2580
2581 aItem.mAddress = ScAddress(nCol, nRow, nTab);
2582
2583 m_aDataArray.push_back(std::move(aItem));
2584 ++nDataCount;
2585 }
2586 }
2587 }
2588 }
2589 }
2590
2591 // convert the hidden cell list to sequence.
2592 m_aHiddenValues.realloc(aHiddenValues.size());
2593 std::copy(
2594 aHiddenValues.begin(), aHiddenValues.end(), m_aHiddenValues.getArray());
2595
2596 // Clear the data series cache when the array is re-built.
2597 m_aMixedDataCache.realloc(0);
2598}
2599
2601{
2603 {
2604 m_aDataArray.clear();
2605 m_pDocument->BroadcastUno(ScHint(SfxHintId::ScDataChanged, ScAddress()));
2607 m_bGotDataChangedHint = true;
2608 }
2609}
2610
2612{
2614 ScRange aRange;
2615 if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, pToken, ScAddress(), true))
2616 return 0;
2617
2618 sal_uInt16 nFileId = pToken->GetIndex();
2619 OUString aTabName = pToken->GetString().getString();
2620 ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, aTabName, aRange, nullptr);
2621 if (!pArray)
2622 // no external data exists for this range.
2623 return 0;
2624
2625 // Start listening for this external document.
2626 ExternalRefListener* pExtRefListener = GetExtRefListener();
2627 pRefMgr->addLinkListener(nFileId, pExtRefListener);
2628 pExtRefListener->addFileId(nFileId);
2629
2630 ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, aTabName, false);
2631 sal_Int32 nDataCount = 0;
2632 FormulaTokenArrayPlainIterator aIter(*pArray);
2633 for (FormulaToken* p = aIter.First(); p; p = aIter.Next())
2634 {
2635 // Cached external range is always represented as a single
2636 // matrix token, although that might change in the future when
2637 // we introduce a new token type to store multi-table range
2638 // data.
2639
2640 if (p->GetType() != svMatrix)
2641 {
2642 OSL_FAIL("Cached array is not a matrix token.");
2643 continue;
2644 }
2645
2646 const ScMatrix* pMat = p->GetMatrix();
2647 SCSIZE nCSize, nRSize;
2648 pMat->GetDimensions(nCSize, nRSize);
2649 for (SCSIZE nC = 0; nC < nCSize; ++nC)
2650 {
2651 for (SCSIZE nR = 0; nR < nRSize; ++nR)
2652 {
2653 if (pMat->IsValue(nC, nR) || pMat->IsBoolean(nC, nR))
2654 {
2655 Item aItem;
2656
2657 aItem.mbIsValue = true;
2658 aItem.mfValue = pMat->GetDouble(nC, nR);
2659
2661 if (pFormatter)
2662 {
2663 const double fVal = aItem.mfValue;
2664 const Color* pColor = nullptr;
2665 sal_uInt32 nFmt = 0;
2666 if (pTable)
2667 {
2668 // Get the correct format index from the cache.
2669 SCCOL nCol = aRange.aStart.Col() + static_cast<SCCOL>(nC);
2670 SCROW nRow = aRange.aStart.Row() + static_cast<SCROW>(nR);
2671 pTable->getCell(nCol, nRow, &nFmt);
2672 }
2673 pFormatter->GetOutputString(fVal, nFmt, aItem.maString, &pColor);
2674 }
2675
2676 m_aDataArray.push_back(aItem);
2677 ++nDataCount;
2678 }
2679 else if (pMat->IsStringOrEmpty(nC, nR))
2680 {
2681 Item aItem;
2682
2683 aItem.mbIsValue = false;
2684 aItem.maString = pMat->GetString(nC, nR).getString();
2685
2686 m_aDataArray.emplace_back(aItem);
2687 ++nDataCount;
2688 }
2689 }
2690 }
2691 }
2692 return nDataCount;
2693}
2694
2696{
2697 if (!m_oRangeIndices)
2698 return;
2699
2700 for ( size_t i = 0, nCount = rRanges.size(); i < nCount; ++i )
2701 {
2702 ScTokenRef pToken;
2703 const ScRange & rRange = rRanges[i];
2704
2706 sal_uInt32 nOrigPos = (*m_oRangeIndices)[i];
2707 m_aTokens[nOrigPos] = pToken;
2708 }
2709
2710 RefChanged();
2711
2712 // any change of the range address is broadcast to value (modify) listeners
2713 if ( !m_aValueListeners.empty() )
2714 m_bGotDataChangedHint = true;
2715}
2716
2718{
2719 if (!m_pExtRefListener)
2721
2722 return m_pExtRefListener.get();
2723}
2724
2726{
2727 if (!m_pExtRefListener)
2728 return;
2729
2730 const std::unordered_set<sal_uInt16>& rFileIds = m_pExtRefListener->getAllFileIds();
2732 for (const auto& rFileId : rFileIds)
2733 pRefMgr->removeLinkListener(rFileId, m_pExtRefListener.get());
2734
2735 m_pExtRefListener.reset();
2736}
2737
2739{
2740 if (!m_pDocument)
2741 {
2742 OSL_FAIL("document instance is nullptr!?");
2743 return;
2744 }
2745
2746 std::vector<Item> aDataArray(r.m_aDataArray);
2747 m_aDataArray.swap(aDataArray);
2748
2750 m_aRole = r.m_aRole;
2751
2752 if (r.m_oRangeIndices)
2754
2755 if (!r.m_pExtRefListener)
2756 return;
2757
2758 // Re-register all external files that the old instance was
2759 // listening to.
2760
2763 const std::unordered_set<sal_uInt16>& rFileIds = r.m_pExtRefListener->getAllFileIds();
2764 for (const auto& rFileId : rFileIds)
2765 {
2766 pRefMgr->addLinkListener(rFileId, m_pExtRefListener.get());
2767 m_pExtRefListener->addFileId(rFileId);
2768 }
2769}
2770
2772{
2773 if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
2774 {
2775 // Create a range list from the token list, have the range list
2776 // updated, and bring the change back to the token list.
2777
2778 ScRangeList aRanges;
2779 m_oRangeIndices.emplace();
2780 vector<ScTokenRef>::const_iterator itrBeg = m_aTokens.begin(), itrEnd = m_aTokens.end();
2781 for (vector<ScTokenRef>::const_iterator itr = itrBeg ;itr != itrEnd; ++itr)
2782 {
2784 {
2785 ScRange aRange;
2787 aRanges.push_back(aRange);
2788 sal_uInt32 nPos = distance(itrBeg, itr);
2789 m_oRangeIndices->push_back(nPos);
2790 }
2791 }
2792
2793 assert(m_oRangeIndices->size() == aRanges.size() &&
2794 "range list and range index list have different sizes.");
2795
2796 unique_ptr<ScRangeList> pUndoRanges;
2797 if ( m_pDocument->HasUnoRefUndo() )
2798 pUndoRanges.reset(new ScRangeList(aRanges));
2799
2800 const ScUpdateRefHint& rRef = static_cast<const ScUpdateRefHint&>(rHint);
2801 bool bChanged = aRanges.UpdateReference(
2802 rRef.GetMode(), m_pDocument, rRef.GetRange(), rRef.GetDx(), rRef.GetDy(), rRef.GetDz());
2803
2804 if (bChanged)
2805 {
2806 // TODO: This should be an assert, but tdf#144537 triggers it.
2807 SAL_WARN_IF(m_oRangeIndices->size() == aRanges.size(),
2808 "sc.ui", "range list and range index list have different sizes after the reference update.");
2809
2810 // Bring the change back from the range list to the token list.
2811 UpdateTokensFromRanges(aRanges);
2812
2813 if (pUndoRanges)
2814 m_pDocument->AddUnoRefChange(m_nObjectId, *pUndoRanges);
2815 }
2816 }
2817 else if ( auto pUndoHint = dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
2818 {
2819 do
2820 {
2821 if (pUndoHint->GetObjectId() != m_nObjectId)
2822 break;
2823
2824 // The hint object provides the old ranges. Restore the old state
2825 // from these ranges.
2826
2827 if (!m_oRangeIndices || m_oRangeIndices->empty())
2828 {
2829 assert(false && " faulty range indices");
2830 break;
2831 }
2832
2833 const ScRangeList& rRanges = pUndoHint->GetRanges();
2834
2835 size_t nCount = rRanges.size();
2836 if (nCount != m_oRangeIndices->size())
2837 {
2838 assert(false && "range count and range index count differ.");
2839 break;
2840 }
2841
2842 UpdateTokensFromRanges(rRanges);
2843 }
2844 while (false);
2845 }
2846 else
2847 {
2848 const SfxHintId nId = rHint.GetId();
2849 if ( nId ==SfxHintId::Dying )
2850 {
2851 m_pDocument = nullptr;
2852 }
2853 else if ( nId == SfxHintId::DataChanged )
2854 {
2855 // delayed broadcast as in ScCellRangesBase
2856
2858 {
2859 m_aDataArray.clear();
2860 lang::EventObject aEvent;
2861 aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
2862
2863 if( m_pDocument )
2864 {
2865 for (const uno::Reference<util::XModifyListener> & xListener: m_aValueListeners)
2866 m_pDocument->AddUnoListenerCall( xListener, aEvent );
2867 }
2868
2869 m_bGotDataChangedHint = false;
2870 }
2871 }
2872 else if ( nId == SfxHintId::ScCalcAll )
2873 {
2874 // broadcast from DoHardRecalc - set m_bGotDataChangedHint
2875 // (SfxHintId::DataChanged follows separately)
2876
2877 if ( !m_aValueListeners.empty() )
2878 m_bGotDataChangedHint = true;
2879 }
2880 else if (nId == SfxHintId::ScClearCache)
2881 {
2882 // necessary after import
2883 m_aDataArray.clear();
2884 }
2885 }
2886}
2887
2888IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, const SfxHint&, rHint, void )
2889{
2890 if ( m_pDocument && (rHint.GetId() == SfxHintId::ScDataChanged) )
2891 {
2892 // This may be called several times for a single change, if several formulas
2893 // in the range are notified. So only a flag is set that is checked when
2894 // SfxHintId::DataChanged is received.
2895
2896 setDataChangedHint(true);
2897 }
2898}
2899
2901 ScChart2DataSequence& rParent, ScDocument* pDoc) :
2902 mrParent(rParent),
2903 mpDoc(pDoc)
2904{
2905}
2906
2908{
2909 if (!mpDoc || mpDoc->IsInDtorClear())
2910 // The document is being destroyed. Do nothing.
2911 return;
2912
2913 // Make sure to remove all pointers to this object.
2914 mpDoc->GetExternalRefManager()->removeLinkListener(this);
2915}
2916
2918{
2919 switch (eType)
2920 {
2922 {
2923 if (maFileIds.count(nFileId))
2924 // We are listening to this external document.
2925 mrParent.RebuildDataCache();
2926 }
2927 break;
2929 maFileIds.erase(nFileId);
2930 break;
2932 mpDoc = nullptr;
2933 break;
2934 }
2935}
2936
2938{
2939 maFileIds.insert(nFileId);
2940}
2941
2942uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
2943{
2944 SolarMutexGuard aGuard;
2945 if ( !m_pDocument)
2946 throw uno::RuntimeException();
2947
2949
2950 if (!m_aMixedDataCache.hasElements())
2951 {
2952 // Build a cache for the 1st time...
2953
2954 sal_Int32 nCount = m_aDataArray.size();
2955 m_aMixedDataCache.realloc(nCount);
2956 uno::Any* pArr = m_aMixedDataCache.getArray();
2957 for (const Item &rItem : m_aDataArray)
2958 {
2959 if (rItem.mbIsValue)
2960 *pArr <<= rItem.mfValue;
2961 else if (rItem.maString.isEmpty())
2962 {
2963 ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
2964 if (aCell.isEmpty())
2965 *pArr = uno::Any();
2966 else
2967 *pArr <<= rItem.maString;
2968 }
2969 else
2970 *pArr <<= rItem.maString;
2971 ++pArr;
2972 }
2973 }
2974 return m_aMixedDataCache;
2975}
2976
2977// XNumericalDataSequence --------------------------------------------------
2978
2979uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData()
2980{
2981 SolarMutexGuard aGuard;
2982 if ( !m_pDocument)
2983 throw uno::RuntimeException();
2984
2986
2987 sal_Int32 nCount = m_aDataArray.size();
2988 uno::Sequence<double> aSeq(nCount);
2989 double* pArr = aSeq.getArray();
2990 for (const Item& rItem : m_aDataArray)
2991 {
2992 *pArr = rItem.mbIsValue ? rItem.mfValue : std::numeric_limits<double>::quiet_NaN();
2993 ++pArr;
2994 }
2995
2996 return aSeq;
2997}
2998
2999// XTextualDataSequence --------------------------------------------------
3000
3001uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::getTextualData()
3002{
3003 SolarMutexGuard aGuard;
3004 uno::Sequence<OUString> aSeq;
3005 if ( !m_pDocument )
3006 throw uno::RuntimeException();
3007
3009
3010 sal_Int32 nCount = m_aDataArray.size();
3011 if ( nCount > 0 )
3012 {
3013 aSeq = uno::Sequence<OUString>(nCount);
3014 OUString* pArr = aSeq.getArray();
3015 for (const Item& rItem : m_aDataArray)
3016 {
3017 *pArr = rItem.maString;
3018 ++pArr;
3019 }
3020 }
3021 else if ( m_aTokens.front() )
3022 {
3023 if( m_aTokens.front()->GetType() == svString )
3024 {
3025 aSeq = uno::Sequence<OUString> { m_aTokens.front()->GetString().getString() };
3026 }
3027 }
3028
3029 return aSeq;
3030}
3031
3033{
3034 SolarMutexGuard aGuard;
3035 OUString aStr;
3036 OSL_ENSURE( m_pDocument, "No Document -> no SourceRangeRepresentation" );
3037 if (m_pDocument)
3038 lcl_convertTokensToString(aStr, m_aTokens, *m_pDocument);
3039
3040 return aStr;
3041}
3042
3043namespace {
3044
3049class AccumulateRangeSize
3050{
3051public:
3052 AccumulateRangeSize(const ScDocument* pDoc) :
3053 mpDoc(pDoc), mnCols(0), mnRows(0) {}
3054
3055 void operator() (const ScTokenRef& pToken)
3056 {
3057 ScRange r;
3058 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3059 ScRefTokenHelper::getRangeFromToken(mpDoc, r, pToken, ScAddress(), bExternal);
3060 r.PutInOrder();
3061 mnCols += r.aEnd.Col() - r.aStart.Col() + 1;
3062 mnRows += r.aEnd.Row() - r.aStart.Row() + 1;
3063 }
3064
3065 SCCOL getCols() const { return mnCols; }
3066 SCROW getRows() const { return mnRows; }
3067private:
3068 const ScDocument* mpDoc;
3069 SCCOL mnCols;
3070 SCROW mnRows;
3071};
3072
3077class GenerateLabelStrings
3078{
3079public:
3080 GenerateLabelStrings(const ScDocument* pDoc, sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) :
3081 mpDoc(pDoc),
3082 mpLabels(std::make_shared<Sequence<OUString>>(nSize)),
3083 meOrigin(eOrigin),
3084 mnCount(0),
3085 mbColumn(bColumn) {}
3086
3087 void operator() (const ScTokenRef& pToken)
3088 {
3089 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3090 ScRange aRange;
3091 ScRefTokenHelper::getRangeFromToken(mpDoc, aRange, pToken, ScAddress(), bExternal);
3092 OUString* pArr = mpLabels->getArray();
3093 if (mbColumn)
3094 {
3095 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
3096 {
3097 if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3098 {
3099 OUString aString = ScResId(STR_COLUMN) + " ";
3100 ScAddress aPos( nCol, 0, 0 );
3101 OUString aColStr(aPos.Format(ScRefFlags::COL_VALID));
3102 aString += aColStr;
3103 pArr[mnCount] = aString;
3104 }
3105 else //only indices for categories
3106 pArr[mnCount] = OUString::number( mnCount+1 );
3107 ++mnCount;
3108 }
3109 }
3110 else
3111 {
3112 for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
3113 {
3114 if (meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3115 {
3116 OUString aString = ScResId(STR_ROW) +
3117 " " + OUString::number( nRow+1 );
3118 pArr[mnCount] = aString;
3119 }
3120 else //only indices for categories
3121 pArr[mnCount] = OUString::number( mnCount+1 );
3122 ++mnCount;
3123 }
3124 }
3125 }
3126
3127 const Sequence<OUString>& getLabels() const { return *mpLabels; }
3128
3129private:
3130 const ScDocument* mpDoc;
3131 shared_ptr< Sequence<OUString> > mpLabels;
3132 chart2::data::LabelOrigin meOrigin;
3133 sal_Int32 mnCount;
3134 bool mbColumn;
3135};
3136
3137}
3138
3139uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
3140{
3141 SolarMutexGuard aGuard;
3142 if ( !m_pDocument)
3143 throw uno::RuntimeException();
3144
3145 // Determine the total size of all ranges.
3146 AccumulateRangeSize func(m_pDocument);
3147 func = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), func);
3148 SCCOL nCols = func.getCols();
3149 SCROW nRows = func.getRows();
3150
3151 // Determine whether this is column-major or row-major.
3152 bool bColumn = true;
3153 if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
3154 (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
3155 {
3156 if (nRows > nCols)
3157 {
3158 bColumn = eOrigin == chart2::data::LabelOrigin_SHORT_SIDE;
3159 }
3160 else if (nCols > nRows)
3161 {
3162 bColumn = eOrigin != chart2::data::LabelOrigin_SHORT_SIDE;
3163 }
3164 else
3165 return Sequence<OUString>();
3166 }
3167
3168 // Generate label strings based on the info so far.
3169 sal_Int32 nCount = bColumn ? nCols : nRows;
3170 GenerateLabelStrings genLabels(m_pDocument, nCount, eOrigin, bColumn);
3171 genLabels = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), genLabels);
3172 Sequence<OUString> aSeq = genLabels.getLabels();
3173
3174 return aSeq;
3175}
3176
3177namespace {
3178
3179sal_uInt32 getDisplayNumberFormat(const ScDocument* pDoc, const ScAddress& rPos)
3180{
3181 sal_uInt32 nFormat = pDoc->GetNumberFormat(rPos); // original format from cell.
3182 return nFormat;
3183}
3184
3185}
3186
3187::sal_Int32 SAL_CALL ScChart2DataSequence::getNumberFormatKeyByIndex( ::sal_Int32 nIndex )
3188{
3189 SolarMutexGuard aGuard;
3191
3192 if (nIndex == -1)
3193 {
3194 // return format of first non-empty cell
3195 // TODO: use nicer heuristic
3196 for (const Item& rItem : m_aDataArray)
3197 {
3198 ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
3199 if (!aCell.isEmpty() && aCell.hasNumeric())
3200 {
3201 return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, rItem.mAddress));
3202 }
3203 }
3204
3205 // we could not find a non-empty cell
3206 return 0;
3207 }
3208
3209 if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= m_aDataArray.size())
3210 {
3211 SAL_WARN("sc.ui", "Passed invalid index to getNumberFormatKeyByIndex(). Will return default value '0'.");
3212 return 0;
3213 }
3214
3215 return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, m_aDataArray.at(nIndex).mAddress));
3216}
3217
3218// XCloneable ================================================================
3219
3220uno::Reference< util::XCloneable > SAL_CALL ScChart2DataSequence::createClone()
3221{
3222 SolarMutexGuard aGuard;
3223
3224 // Clone tokens.
3225 vector<ScTokenRef> aTokensNew;
3226 aTokensNew.reserve(m_aTokens.size());
3227 for (const auto& rxToken : m_aTokens)
3228 {
3229 ScTokenRef p(rxToken->Clone());
3230 aTokensNew.push_back(p);
3231 }
3232
3234 p->CopyData(*this);
3235 return p;
3236}
3237
3238// XModifyBroadcaster ========================================================
3239
3240void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3241{
3242 // like ScCellRangesBase::addModifyListener
3243 SolarMutexGuard aGuard;
3244 if (m_aTokens.empty())
3245 return;
3246
3247 ScRangeList aRanges;
3249 m_aValueListeners.emplace_back( aListener );
3250
3251 if ( m_aValueListeners.size() != 1 )
3252 return;
3253
3254 if (!m_pValueListener)
3255 m_pValueListener.reset(new ScLinkListener( LINK( this, ScChart2DataSequence, ValueListenerHdl ) ));
3256
3257 if (!m_pHiddenListener)
3258 m_pHiddenListener.reset(new HiddenRangeListener(*this));
3259
3260 if( m_pDocument )
3261 {
3263 for (const auto& rxToken : m_aTokens)
3264 {
3265 ScRange aRange;
3267 continue;
3268
3269 m_pDocument->StartListeningArea( aRange, false, m_pValueListener.get() );
3270 if (pCLC)
3271 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
3272 }
3273 }
3274
3275 acquire(); // don't lose this object (one ref for all listeners)
3276}
3277
3278void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3279{
3280 // like ScCellRangesBase::removeModifyListener
3281
3282 SolarMutexGuard aGuard;
3283 if (m_aTokens.empty())
3284 return;
3285
3286 rtl::Reference<ScChart2DataSequence> xSelfHold(this); // in case the listeners have the last ref
3287
3288 sal_uInt16 nCount = m_aValueListeners.size();
3289 for ( sal_uInt16 n=nCount; n--; )
3290 {
3291 uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
3292 if ( rObj == aListener )
3293 {
3294 m_aValueListeners.erase( m_aValueListeners.begin() + n );
3295
3296 if ( m_aValueListeners.empty() )
3297 {
3298 if (m_pValueListener)
3299 m_pValueListener->EndListeningAll();
3300
3302 {
3304 if (pCLC)
3306 }
3307
3308 release(); // release the ref for the listeners
3309 }
3310
3311 break;
3312 }
3313 }
3314}
3315
3316// DataSequence XPropertySet -------------------------------------------------
3317
3318uno::Reference< beans::XPropertySetInfo> SAL_CALL
3320{
3321 SolarMutexGuard aGuard;
3322 static uno::Reference<beans::XPropertySetInfo> aRef =
3324 return aRef;
3325}
3326
3328 const OUString& rPropertyName, const uno::Any& rValue)
3329{
3330 if ( rPropertyName == SC_UNONAME_ROLE )
3331 {
3332 if ( !(rValue >>= m_aRole))
3333 throw lang::IllegalArgumentException();
3334 }
3335 else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3336 {
3337 bool bOldValue = m_bIncludeHiddenCells;
3338 if ( !(rValue >>= m_bIncludeHiddenCells))
3339 throw lang::IllegalArgumentException();
3340 if( bOldValue != m_bIncludeHiddenCells )
3341 m_aDataArray.clear();//data array is dirty now
3342 }
3343 else if( rPropertyName == "TimeBased" )
3344 {
3345 bool bTimeBased = mbTimeBased;
3346 rValue>>= bTimeBased;
3347 mbTimeBased = bTimeBased;
3348 }
3349 else
3350 throw beans::UnknownPropertyException(rPropertyName);
3351 // TODO: support optional properties
3352}
3353
3354uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue(const OUString& rPropertyName)
3355{
3356 uno::Any aRet;
3357 if ( rPropertyName == SC_UNONAME_ROLE )
3358 aRet <<= m_aRole;
3359 else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3360 aRet <<= m_bIncludeHiddenCells;
3361 else if ( rPropertyName == SC_UNONAME_HIDDENVALUES )
3362 {
3363 // This property is read-only thus cannot be set externally via
3364 // setPropertyValue(...).
3366 aRet <<= m_aHiddenValues;
3367 }
3368 else if (rPropertyName == SC_UNONAME_TIME_BASED)
3369 {
3370 aRet <<= mbTimeBased;
3371 }
3372 else if (rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
3373 {
3374 // Read-only property. It returns whether or not the label value is a
3375 // direct user input, rather than an indirect reference.
3376 bool bHasStringLabel = false;
3377 if (m_aTokens.size() == 1)
3378 {
3379 const formula::FormulaToken& rToken = *m_aTokens[0];
3380 bHasStringLabel = rToken.GetType() == formula::svString;
3381 }
3382 aRet <<= bHasStringLabel;
3383 }
3384 else
3385 throw beans::UnknownPropertyException(rPropertyName);
3386 // TODO: support optional properties
3387 return aRet;
3388}
3389
3391 const OUString& /*rPropertyName*/,
3392 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
3393{
3394 // FIXME: real implementation
3395 OSL_FAIL( "Not yet implemented" );
3396}
3397
3399 const OUString& /*rPropertyName*/,
3400 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
3401{
3402 // FIXME: real implementation
3403 OSL_FAIL( "Not yet implemented" );
3404}
3405
3407 const OUString& /*rPropertyName*/,
3408 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3409{
3410 // FIXME: real implementation
3411 OSL_FAIL( "Not yet implemented" );
3412}
3413
3415 const OUString& /*rPropertyName*/,
3416 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3417{
3418 // FIXME: real implementation
3419 OSL_FAIL( "Not yet implemented" );
3420}
3421
3423{
3425}
3426
3428{
3429 if(!mbTimeBased)
3430 return true;
3431
3433 {
3434 if(bWrap)
3436 return false;
3437 }
3438
3439 for(const auto& rxToken : m_aTokens)
3440 {
3441 if (rxToken->GetType() != svDoubleRef)
3442 continue;
3443
3444 ScComplexRefData& rData = *rxToken->GetDoubleRef();
3445 ScSingleRefData& s = rData.Ref1;
3446 ScSingleRefData& e = rData.Ref2;
3447
3448 s.IncTab(1);
3449 e.IncTab(1);
3450 }
3451
3452 ++mnCurrentTab;
3453
3455
3456 return true;
3457}
3458
3459void ScChart2DataSequence::setRange(sal_Int32 nStart, sal_Int32 nEnd)
3460{
3461 mnTimeBasedStart = nStart;
3462 mnTimeBasedEnd = nEnd;
3464}
3465
3467{
3468 if(nPoint > mnTimeBasedEnd - mnTimeBasedStart)
3469 return false;
3470
3471 SCTAB nTab = mnTimeBasedStart + nPoint;
3472 for(const auto& rxToken : m_aTokens)
3473 {
3474 if (rxToken->GetType() != svDoubleRef)
3475 continue;
3476
3477 ScComplexRefData& rData = *rxToken->GetDoubleRef();
3478 ScSingleRefData& s = rData.Ref1;
3479 ScSingleRefData& e = rData.Ref2;
3480
3481 s.SetAbsTab(nTab);
3482 e.SetAbsTab(nTab);
3483 }
3484
3485 mnCurrentTab = nTab;
3486
3488
3489 return true;
3490}
3491
3492/* 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:1337
ScChart2DataSource
Definition: chart2uno.cxx:67
IMPL_LINK(ScChart2DataSequence, ValueListenerHdl, const SfxHint &, rHint, void)
Definition: chart2uno.cxx:2888
SCTAB Tab() const
Definition: address.hxx:283
SCROW Row() const
Definition: address.hxx:274
SCCOL Col() const
Definition: address.hxx:279
css::uno::Sequence< css::beans::PropertyValue > maCreateDataSourceArguments
Definition: chart2uno.hxx:152
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByRangeRepresentation(const OUString &aRangeRepresentation) override
Definition: chart2uno.cxx:2055
virtual void SAL_CALL addVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:2347
virtual css::uno::Reference< css::sheet::XRangeSelection > SAL_CALL getRangeSelection() override
Definition: chart2uno.cxx:2087
virtual void SAL_CALL removePropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &rListener) override
Definition: chart2uno.cxx:2340
virtual OUString SAL_CALL convertRangeFromXML(const OUString &sXMLRange) override
Definition: chart2uno.cxx:2254
virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL detectArguments(const css::uno::Reference< css::chart2::data::XDataSource > &xDataSource) override
Definition: chart2uno.cxx:1763
virtual ~ScChart2DataProvider() override
Definition: chart2uno.cxx:982
virtual OUString SAL_CALL convertRangeToXML(const OUString &sRangeRepresentation) override
Definition: chart2uno.cxx:2227
ScDocument * m_pDocument
Definition: chart2uno.hxx:147
css::uno::Sequence< css::beans::PropertyValue > maCachedArguments
Definition: chart2uno.hxx:151
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByValueArray(const OUString &aRole, const OUString &aRangeRepresentation, const OUString &aRoleQualifier) override
Definition: chart2uno.cxx:2080
css::uno::Reference< css::chart2::data::XDataSource > mxCreatedDataSource
Definition: chart2uno.hxx:153
virtual void SAL_CALL removeVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:2354
virtual sal_Bool SAL_CALL createDataSequenceByRangeRepresentationPossible(const OUString &aRangeRepresentation) override
Definition: chart2uno.cxx:2041
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: chart2uno.cxx:990
virtual sal_Bool SAL_CALL createDataSourcePossible(const css::uno::Sequence< css::beans::PropertyValue > &aArguments) override
Definition: chart2uno.cxx:998
css::uno::Reference< css::chart2::data::XDataSource > mxCachedDataSource
Definition: chart2uno.hxx:150
virtual css::uno::Any SAL_CALL getPropertyValue(const OUString &rPropertyName) override
Definition: chart2uno.cxx:2317
virtual void SAL_CALL setPropertyValue(const OUString &rPropertyName, const css::uno::Any &rValue) override
Definition: chart2uno.cxx:2306
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByFormulaTokens(const css::uno::Sequence< css::sheet::FormulaToken > &aTokens) override
Definition: chart2uno.cxx:2155
ScChart2DataProvider(ScDocument *pDoc)
Definition: chart2uno.cxx:973
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:2098
virtual void SAL_CALL addPropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &xListener) override
Definition: chart2uno.cxx:2333
virtual css::uno::Reference< css::chart2::data::XDataSource > SAL_CALL createDataSource(const css::uno::Sequence< css::beans::PropertyValue > &aArguments) override
Definition: chart2uno.cxx:1397
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
Definition: chart2uno.cxx:2298
ExternalRefListener(ScChart2DataSequence &rParent, ScDocument *pDoc)
Definition: chart2uno.cxx:2900
virtual void notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType) override
Definition: chart2uno.cxx:2917
HiddenRangeListener(ScChart2DataSequence &rParent)
Definition: chart2uno.cxx:2406
css::chart2::data::DataSequenceRole m_aRole
Definition: chart2uno.hxx:370
void StopListeningToAllExternalRefs()
Definition: chart2uno.cxx:2725
std::unique_ptr< HiddenRangeListener > m_pHiddenListener
Definition: chart2uno.hxx:383
XModifyListenerArr_Impl m_aValueListeners
Definition: chart2uno.hxx:386
virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override
Definition: chart2uno.cxx:3220
virtual OUString SAL_CALL getSourceRangeRepresentation() override
Definition: chart2uno.cxx:3032
std::vector< ScTokenRef > m_aTokens
Definition: chart2uno.hxx:376
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:3139
virtual void SAL_CALL addPropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &xListener) override
Definition: chart2uno.cxx:3390
void setDataChangedHint(bool b)
Definition: chart2uno.cxx:3422
ExternalRefListener * GetExtRefListener()
Definition: chart2uno.cxx:2717
virtual void SAL_CALL setPropertyValue(const OUString &rPropertyName, const css::uno::Any &rValue) override
Definition: chart2uno.cxx:3327
std::unique_ptr< ExternalRefListener > m_pExtRefListener
Definition: chart2uno.hxx:380
css::uno::Sequence< css::uno::Any > m_aMixedDataCache
Cached data for getData.
Definition: chart2uno.hxx:365
ScDocument * m_pDocument
Definition: chart2uno.hxx:375
virtual void SAL_CALL addVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:3406
virtual void SAL_CALL removePropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &rListener) override
Definition: chart2uno.cxx:3398
virtual void SAL_CALL addModifyListener(const css::uno::Reference< css::util::XModifyListener > &aListener) override
Definition: chart2uno.cxx:3240
virtual sal_Bool SAL_CALL switchToNext(sal_Bool bWrap) override
Definition: chart2uno.cxx:3427
virtual css::uno::Sequence< OUString > SAL_CALL getTextualData() override
Definition: chart2uno.cxx:3001
void UpdateTokensFromRanges(const ScRangeList &rRanges)
Definition: chart2uno.cxx:2695
std::optional< std::vector< sal_uInt32 > > m_oRangeIndices
Definition: chart2uno.hxx:378
virtual css::uno::Sequence< css::uno::Any > SAL_CALL getData() override
Definition: chart2uno.cxx:2942
std::vector< Item > m_aDataArray
This vector contains the cached data which was calculated with BuildDataCache().
Definition: chart2uno.hxx:358
virtual void SAL_CALL setRange(sal_Int32 nStart, sal_Int32 nEnd) override
Definition: chart2uno.cxx:3459
virtual css::uno::Any SAL_CALL getPropertyValue(const OUString &rPropertyName) override
Definition: chart2uno.cxx:3354
virtual void SAL_CALL removeVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:3414
virtual sal_Bool SAL_CALL setToPointInTime(sal_Int32 nPoint) override
Definition: chart2uno.cxx:3466
std::unique_ptr< ScLinkListener > m_pValueListener
Definition: chart2uno.hxx:385
SfxItemPropertySet m_aPropSet
Definition: chart2uno.hxx:381
sal_Int32 FillCacheFromExternalRef(const ScTokenRef &pToken)
Definition: chart2uno.cxx:2611
virtual void SAL_CALL removeModifyListener(const css::uno::Reference< css::util::XModifyListener > &aListener) override
Definition: chart2uno.cxx:3278
void BuildDataCache()
Build an internal data array to cache the data ranges, and other information such as hidden values.
Definition: chart2uno.cxx:2502
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: chart2uno.cxx:2771
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
Definition: chart2uno.cxx:3319
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:3187
void CopyData(const ScChart2DataSequence &r)
Definition: chart2uno.cxx:2738
css::uno::Sequence< sal_Int32 > m_aHiddenValues
Definition: chart2uno.hxx:367
virtual ~ScChart2DataSequence() override
Definition: chart2uno.cxx:2453
virtual css::uno::Sequence< double > SAL_CALL getNumericalData() override
Definition: chart2uno.cxx:2979
std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > m_aLabeledSequences
Definition: chart2uno.hxx:190
ScChart2DataSource(ScDocument *pDoc)
Definition: chart2uno.cxx:2363
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: chart2uno.cxx:2378
void AddLabeledSequence(const css::uno::Reference< css::chart2::data::XLabeledDataSequence > &xNew)
Definition: chart2uno.cxx:2393
virtual css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > SAL_CALL getDataSequences() override
Definition: chart2uno.cxx:2387
virtual ~ScChart2DataSource() override
Definition: chart2uno.cxx:2370
ScDocument * m_pDocument
Definition: chart2uno.hxx:189
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:897
SC_DLLPUBLIC sal_uInt32 GetNumberFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3685
bool ShrinkToDataArea(SCTAB nTab, SCCOL &rStartCol, SCROW &rStartRow, SCCOL &rEndCol, SCROW &rEndRow) const
Shrink a range to only include data area.
Definition: document.cxx:1043
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:891
ScRangeData * FindRangeNameBySheetAndIndex(SCTAB nTab, sal_uInt16 nIndex) const
Find a named expression / range name in either global or a local scope.
Definition: documen3.cxx:275
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:892
void AddUnoRefChange(sal_Int64 nId, const ScRangeList &rOldRanges)
Definition: documen3.cxx:1008
SC_DLLPUBLIC ScChartListenerCollection * GetChartListenerCollection() const
Definition: document.hxx:2228
SC_DLLPUBLIC bool InitColumnBlockPosition(sc::ColumnBlockPosition &rBlockPos, SCTAB nTab, SCCOL nCol)
Definition: document.cxx:2662
SC_DLLPUBLIC ScExternalRefManager * GetExternalRefManager() const
Definition: documen3.cxx:633
void AddUnoObject(SfxListener &rObject)
Definition: documen3.cxx:907
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:4492
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1008
void StartListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: documen7.cxx:35
bool HasUnoRefUndo() const
Definition: document.hxx:1088
bool PastingDrawFromOtherDoc() const
Definition: document.hxx:2518
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1081
SC_DLLPUBLIC bool HasValueData(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3806
void AddUnoListenerCall(const css::uno::Reference< css::util::XModifyListener > &rListener, const css::lang::EventObject &rEvent)
Definition: documen3.cxx:986
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:461
sal_Int64 GetNewUnoId()
Definition: document.hxx:1091
SC_DLLPUBLIC bool ColHidden(SCCOL nCol, SCTAB nTab, SCCOL *pFirstCol=nullptr, SCCOL *pLastCol=nullptr) const
Definition: document.cxx:4508
SC_DLLPUBLIC OUString GetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext *pContext=nullptr) const
Definition: document.cxx:3544
void RemoveUnoObject(SfxListener &rObject)
Definition: documen3.cxx:915
void BroadcastUno(const SfxHint &rHint)
Definition: documen3.cxx:958
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:3026
bool IsStringOrEmpty(SCSIZE nIndex) const
Definition: scmatrix.cxx:3046
bool IsBoolean(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3091
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3011
void GetDimensions(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:2931
bool IsValue(SCSIZE nIndex) const
Definition: scmatrix.cxx:3076
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 sal_Int32 IndexOf(const OUString &rString, sal_Unicode cSearchChar, sal_Int32 nOffset, sal_Unicode cQuote='\'')
Definition: rangeutl.cxx:374
static void GetTokenByOffset(OUString &rToken, const OUString &rString, sal_Int32 &nOffset, sal_Unicode cSeparator=' ', sal_Unicode cQuote='\'')
Definition: rangeutl.cxx:414
static void GetStringFromXMLRangeString(OUString &rString, const OUString &rXMLRange, const ScDocument &rDoc)
XML Range to Calc Range.
Definition: rangeutl.cxx:806
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
std::size_t mnCount
float u
#define max(a, b)
FormulaError
DocumentType eType
@ CELLTYPE_EDIT
Definition: global.hxx:276
@ CELLTYPE_STRING
Definition: global.hxx:274
@ CELLTYPE_FORMULA
Definition: global.hxx:275
@ CELLTYPE_NONE
Definition: global.hxx:272
@ CELLTYPE_VALUE
Definition: global.hxx:273
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
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
#define SC_UNONAME_HIDDENVALUES
Definition: unonames.hxx:686
#define SC_UNONAME_HAS_STRING_LABEL
Definition: unonames.hxx:689
#define SC_UNONAME_USE_INTERNAL_DATA_PROVIDER
Definition: unonames.hxx:688
#define SC_UNONAME_TIME_BASED
Definition: unonames.hxx:690
#define SC_UNONAME_ROLE
Definition: unonames.hxx:685
#define SC_UNONAME_INCLUDEHIDDENCELLS
Definition: unonames.hxx:687
std::unique_ptr< char[]> aBuffer