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