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  //Labels should always include hidden cells, regardless of the bIncludeHiddenCells setting
1035  uno::Reference< chart2::data::XDataSequence > xLabelSeq( new ScChart2DataSequence( pDoc, std::move(aLabelTokens), true ) );
1036  xResult->setLabel( xLabelSeq );
1037  }
1038  }
1039  catch( const uno::Exception& )
1040  {
1041  }
1042  }
1043  return xResult;
1044 }
1045 
1055 bool lcl_addUpperLeftCornerIfMissing(const ScDocument* pDoc, vector<ScTokenRef>& rRefTokens,
1056  SCROW nCornerRowCount, SCCOL nCornerColumnCount)
1057 {
1058  using ::std::max;
1059  using ::std::min;
1060 
1061  if (rRefTokens.empty())
1062  return false;
1063 
1064  SCCOL nMinCol = pDoc->GetSheetLimits().GetMaxColCount();
1065  SCROW nMinRow = pDoc->GetSheetLimits().GetMaxRowCount();
1066  SCCOL nMaxCol = 0;
1067  SCROW nMaxRow = 0;
1068  SCTAB nTab = 0;
1069 
1070  sal_uInt16 nFileId = 0;
1071  svl::SharedString aExtTabName;
1072  bool bExternal = false;
1073 
1074  vector<ScTokenRef>::const_iterator itr = rRefTokens.begin(), itrEnd = rRefTokens.end();
1075 
1076  // Get the first ref token.
1077  ScTokenRef pToken = *itr;
1078  switch (pToken->GetType())
1079  {
1080  case svSingleRef:
1081  {
1082  const ScSingleRefData& rData = *pToken->GetSingleRef();
1083  nMinCol = rData.Col();
1084  nMinRow = rData.Row();
1085  nMaxCol = rData.Col();
1086  nMaxRow = rData.Row();
1087  nTab = rData.Tab();
1088  }
1089  break;
1090  case svDoubleRef:
1091  {
1092  const ScComplexRefData& rData = *pToken->GetDoubleRef();
1093  nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1094  nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1095  nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1096  nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1097  nTab = rData.Ref1.Tab();
1098  }
1099  break;
1100  case svExternalSingleRef:
1101  {
1102  const ScSingleRefData& rData = *pToken->GetSingleRef();
1103  nMinCol = rData.Col();
1104  nMinRow = rData.Row();
1105  nMaxCol = rData.Col();
1106  nMaxRow = rData.Row();
1107  nTab = rData.Tab();
1108  nFileId = pToken->GetIndex();
1109  aExtTabName = pToken->GetString();
1110  bExternal = true;
1111  }
1112  break;
1113  case svExternalDoubleRef:
1114  {
1115  const ScComplexRefData& rData = *pToken->GetDoubleRef();
1116  nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1117  nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1118  nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1119  nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1120  nTab = rData.Ref1.Tab();
1121  nFileId = pToken->GetIndex();
1122  aExtTabName = pToken->GetString();
1123  bExternal = true;
1124  }
1125  break;
1126  default:
1127  ;
1128  }
1129 
1130  // Determine the minimum range enclosing all data ranges. Also make sure
1131  // that they are all on the same table.
1132 
1133  for (++itr; itr != itrEnd; ++itr)
1134  {
1135  pToken = *itr;
1136  switch (pToken->GetType())
1137  {
1138  case svSingleRef:
1139  {
1140  const ScSingleRefData& rData = *pToken->GetSingleRef();
1141 
1142  nMinCol = min(nMinCol, rData.Col());
1143  nMinRow = min(nMinRow, rData.Row());
1144  nMaxCol = max(nMaxCol, rData.Col());
1145  nMaxRow = max(nMaxRow, rData.Row());
1146  if (nTab != rData.Tab() || bExternal)
1147  return false;
1148  }
1149  break;
1150  case svDoubleRef:
1151  {
1152  const ScComplexRefData& rData = *pToken->GetDoubleRef();
1153 
1154  nMinCol = min(nMinCol, rData.Ref1.Col());
1155  nMinCol = min(nMinCol, rData.Ref2.Col());
1156  nMinRow = min(nMinRow, rData.Ref1.Row());
1157  nMinRow = min(nMinRow, rData.Ref2.Row());
1158 
1159  nMaxCol = max(nMaxCol, rData.Ref1.Col());
1160  nMaxCol = max(nMaxCol, rData.Ref2.Col());
1161  nMaxRow = max(nMaxRow, rData.Ref1.Row());
1162  nMaxRow = max(nMaxRow, rData.Ref2.Row());
1163 
1164  if (nTab != rData.Ref1.Tab() || bExternal)
1165  return false;
1166  }
1167  break;
1168  case svExternalSingleRef:
1169  {
1170  if (!bExternal)
1171  return false;
1172 
1173  if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1174  return false;
1175 
1176  const ScSingleRefData& rData = *pToken->GetSingleRef();
1177 
1178  nMinCol = min(nMinCol, rData.Col());
1179  nMinRow = min(nMinRow, rData.Row());
1180  nMaxCol = max(nMaxCol, rData.Col());
1181  nMaxRow = max(nMaxRow, rData.Row());
1182  }
1183  break;
1184  case svExternalDoubleRef:
1185  {
1186  if (!bExternal)
1187  return false;
1188 
1189  if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1190  return false;
1191 
1192  const ScComplexRefData& rData = *pToken->GetDoubleRef();
1193 
1194  nMinCol = min(nMinCol, rData.Ref1.Col());
1195  nMinCol = min(nMinCol, rData.Ref2.Col());
1196  nMinRow = min(nMinRow, rData.Ref1.Row());
1197  nMinRow = min(nMinRow, rData.Ref2.Row());
1198 
1199  nMaxCol = max(nMaxCol, rData.Ref1.Col());
1200  nMaxCol = max(nMaxCol, rData.Ref2.Col());
1201  nMaxRow = max(nMaxRow, rData.Ref1.Row());
1202  nMaxRow = max(nMaxRow, rData.Ref2.Row());
1203  }
1204  break;
1205  default:
1206  ;
1207  }
1208  }
1209 
1210  const auto & rSheetLimits = pDoc->GetSheetLimits();
1211  if (nMinRow >= nMaxRow || nMinCol >= nMaxCol ||
1212  nMinRow >= rSheetLimits.GetMaxRowCount() || nMinCol >= rSheetLimits.GetMaxColCount() ||
1213  nMaxRow >= rSheetLimits.GetMaxRowCount() || nMaxCol >= rSheetLimits.GetMaxColCount())
1214  {
1215  // Invalid range. Bail out.
1216  return false;
1217  }
1218 
1219  // Check if the following conditions are met:
1220 
1221  // 1) The upper-left corner cell is not included.
1222  // 2) The three adjacent cells of that corner cell are included.
1223 
1224  bool bRight = false, bBottom = false, bDiagonal = false;
1225  for (const auto& rxToken : rRefTokens)
1226  {
1227  switch (rxToken->GetType())
1228  {
1229  case svSingleRef:
1230  case svExternalSingleRef:
1231  {
1232  const ScSingleRefData& rData = *rxToken->GetSingleRef();
1233  if (rData.Col() == nMinCol && rData.Row() == nMinRow)
1234  // The corner cell is contained.
1235  return false;
1236 
1237  if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow)
1238  bRight = true;
1239 
1240  if (rData.Col() == nMinCol && rData.Row() == nMinRow+nCornerRowCount)
1241  bBottom = true;
1242 
1243  if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow+nCornerRowCount)
1244  bDiagonal = true;
1245  }
1246  break;
1247  case svDoubleRef:
1248  case svExternalDoubleRef:
1249  {
1250  const ScComplexRefData& rData = *rxToken->GetDoubleRef();
1251  const ScSingleRefData& r1 = rData.Ref1;
1252  const ScSingleRefData& r2 = rData.Ref2;
1253  if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1254  r1.Row() <= nMinRow && nMinRow <= r2.Row())
1255  // The corner cell is contained.
1256  return false;
1257 
1258  if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1259  r1.Row() <= nMinRow && nMinRow <= r2.Row())
1260  bRight = true;
1261 
1262  if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1263  r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1264  bBottom = true;
1265 
1266  if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1267  r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1268  bDiagonal = true;
1269  }
1270  break;
1271  default:
1272  ;
1273  }
1274  }
1275 
1276  if (!bRight || !bBottom || !bDiagonal)
1277  // Not all the adjacent cells are included. Bail out.
1278  return false;
1279 
1280  ScSingleRefData aData;
1281  aData.InitFlags();
1282  aData.SetFlag3D(true);
1283  aData.SetAbsCol(nMinCol);
1284  aData.SetAbsRow(nMinRow);
1285  aData.SetAbsTab(nTab);
1286 
1287  if( nCornerRowCount==1 && nCornerColumnCount==1 )
1288  {
1289  if (bExternal)
1290  {
1291  ScTokenRef pCorner(
1292  new ScExternalSingleRefToken(nFileId, aExtTabName, aData));
1293  ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1294  }
1295  else
1296  {
1297  ScTokenRef pCorner(new ScSingleRefToken(pDoc->GetSheetLimits(), aData));
1298  ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1299  }
1300  }
1301  else
1302  {
1303  ScSingleRefData aDataEnd(aData);
1304  aDataEnd.IncCol(nCornerColumnCount-1);
1305  aDataEnd.IncRow(nCornerRowCount-1);
1306  ScComplexRefData r;
1307  r.Ref1=aData;
1308  r.Ref2=aDataEnd;
1309  if (bExternal)
1310  {
1311  ScTokenRef pCorner(
1312  new ScExternalDoubleRefToken(nFileId, aExtTabName, r));
1313  ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1314  }
1315  else
1316  {
1317  ScTokenRef pCorner(new ScDoubleRefToken(pDoc->GetSheetLimits(), r));
1318  ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
1319  }
1320  }
1321 
1322  return true;
1323 }
1324 
1325 #define SHRINK_RANGE_THRESHOLD 10000
1326 
1327 class ShrinkRefTokenToDataRange
1328 {
1329  ScDocument* mpDoc;
1330 public:
1331  explicit ShrinkRefTokenToDataRange(ScDocument* pDoc) : mpDoc(pDoc) {}
1332  void operator() (const ScTokenRef& rRef)
1333  {
1335  return;
1336 
1337  // Don't assume an ScDoubleRefToken if it isn't. It can be at least an
1338  // ScSingleRefToken, then there isn't anything to shrink.
1339  if (rRef->GetType() != svDoubleRef)
1340  return;
1341 
1342  ScComplexRefData& rData = *rRef->GetDoubleRef();
1343  ScSingleRefData& s = rData.Ref1;
1344  ScSingleRefData& e = rData.Ref2;
1345 
1346  if(abs((e.Col()-s.Col())*(e.Row()-s.Row())) < SHRINK_RANGE_THRESHOLD)
1347  return;
1348 
1349  SCCOL nMinCol = mpDoc->MaxCol(), nMaxCol = 0;
1350  SCROW nMinRow = mpDoc->MaxRow(), nMaxRow = 0;
1351 
1352  // Determine the smallest range that encompasses the data ranges of all sheets.
1353  SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
1354  for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
1355  {
1356  SCCOL nCol1 = 0, nCol2 = mpDoc->MaxCol();
1357  SCROW nRow1 = 0, nRow2 = mpDoc->MaxRow();
1358  mpDoc->ShrinkToDataArea(nTab, nCol1, nRow1, nCol2, nRow2);
1359  nMinCol = std::min(nMinCol, nCol1);
1360  nMinRow = std::min(nMinRow, nRow1);
1361  nMaxCol = std::max(nMaxCol, nCol2);
1362  nMaxRow = std::max(nMaxRow, nRow2);
1363  }
1364 
1365  // Shrink range to the data range if applicable.
1366  if (s.Col() < nMinCol)
1367  s.SetAbsCol(nMinCol);
1368  if (s.Row() < nMinRow)
1369  s.SetAbsRow(nMinRow);
1370  if (e.Col() > nMaxCol)
1371  e.SetAbsCol(nMaxCol);
1372  if (e.Row() > nMaxRow)
1373  e.SetAbsRow(nMaxRow);
1374  }
1375 };
1376 
1377 void shrinkToDataRange(ScDocument* pDoc, vector<ScTokenRef>& rRefTokens)
1378 {
1379  std::for_each(rRefTokens.begin(), rRefTokens.end(), ShrinkRefTokenToDataRange(pDoc));
1380 }
1381 
1382 }
1383 
1384 uno::Reference< chart2::data::XDataSource> SAL_CALL
1386  const uno::Sequence< beans::PropertyValue >& aArguments )
1387 {
1388  SolarMutexGuard aGuard;
1389  if ( ! m_pDocument )
1390  throw uno::RuntimeException();
1391 
1392  uno::Reference< chart2::data::XDataSource> xResult;
1393  bool bLabel = true;
1394  bool bCategories = false;
1395  bool bOrientCol = true;
1396  OUString aRangeRepresentation;
1397  uno::Sequence< sal_Int32 > aSequenceMapping;
1398  bool bTimeBased = false;
1399  for(const auto& rArgument : aArguments)
1400  {
1401  if ( rArgument.Name == "DataRowSource" )
1402  {
1403  chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
1404  if( ! (rArgument.Value >>= eSource))
1405  {
1406  sal_Int32 nSource(0);
1407  if( rArgument.Value >>= nSource )
1408  eSource = static_cast< chart::ChartDataRowSource >( nSource );
1409  }
1410  bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
1411  }
1412  else if ( rArgument.Name == "FirstCellAsLabel" )
1413  {
1414  bLabel = ::cppu::any2bool(rArgument.Value);
1415  }
1416  else if ( rArgument.Name == "HasCategories" )
1417  {
1418  bCategories = ::cppu::any2bool(rArgument.Value);
1419  }
1420  else if ( rArgument.Name == "CellRangeRepresentation" )
1421  {
1422  rArgument.Value >>= aRangeRepresentation;
1423  }
1424  else if ( rArgument.Name == "SequenceMapping" )
1425  {
1426  rArgument.Value >>= aSequenceMapping;
1427  }
1428  else if ( rArgument.Name == "TimeBased" )
1429  {
1430  rArgument.Value >>= bTimeBased;
1431  }
1432  }
1433 
1434  vector<ScTokenRef> aRefTokens;
1437  aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1438  if (aRefTokens.empty())
1439  // Invalid range representation. Bail out.
1440  throw lang::IllegalArgumentException();
1441 
1442  SCTAB nTimeBasedStart = MAXTAB;
1443  SCTAB nTimeBasedEnd = 0;
1444  if(bTimeBased)
1445  {
1446  // limit to first sheet
1447  for(const auto& rxToken : aRefTokens)
1448  {
1449  if (rxToken->GetType() != svDoubleRef)
1450  continue;
1451 
1452  ScComplexRefData& rData = *rxToken->GetDoubleRef();
1453  ScSingleRefData& s = rData.Ref1;
1454  ScSingleRefData& e = rData.Ref2;
1455 
1456  nTimeBasedStart = std::min(nTimeBasedStart, s.Tab());
1457  nTimeBasedEnd = std::min(nTimeBasedEnd, e.Tab());
1458 
1459  if(s.Tab() != e.Tab())
1460  e.SetAbsTab(s.Tab());
1461  }
1462  }
1463 
1464  if(!bTimeBased)
1465  shrinkToDataRange(m_pDocument, aRefTokens);
1466 
1467  if (bLabel)
1468  lcl_addUpperLeftCornerIfMissing(m_pDocument, aRefTokens, 1, 1); //#i90669#
1469 
1470  bool bColHeaders = (bOrientCol ? bLabel : bCategories );
1471  bool bRowHeaders = (bOrientCol ? bCategories : bLabel );
1472 
1473  Chart2Positioner aChPositioner(m_pDocument, aRefTokens);
1474  aChPositioner.setHeaders(bColHeaders, bRowHeaders);
1475 
1476  const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap();
1477  if (!pChartMap)
1478  // No chart position map instance. Bail out.
1479  return xResult;
1480 
1481  ScChart2DataSource* pDS = nullptr;
1482  ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqs;
1483 
1484  // Fill Categories
1485  if( bCategories )
1486  {
1487  vector<ScTokenRef> aValueTokens;
1488  if (bOrientCol)
1489  aValueTokens = pChartMap->getAllRowHeaderRanges();
1490  else
1491  aValueTokens = pChartMap->getAllColHeaderRanges();
1492 
1493  vector<ScTokenRef> aLabelTokens(
1494  pChartMap->getLeftUpperCornerRanges());
1495 
1496  uno::Reference< chart2::data::XLabeledDataSequence > xCategories = lcl_createLabeledDataSequenceFromTokens(
1497  std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1498  if ( xCategories.is() )
1499  {
1500  aSeqs.push_back( xCategories );
1501  }
1502  }
1503 
1504  // Fill Series (values and label)
1505  sal_Int32 nCount = bOrientCol ? pChartMap->getDataColCount() : pChartMap->getDataRowCount();
1506  for (sal_Int32 i = 0; i < nCount; ++i)
1507  {
1508  vector<ScTokenRef> aValueTokens;
1509  vector<ScTokenRef> aLabelTokens;
1510  if (bOrientCol)
1511  {
1512  aValueTokens = pChartMap->getDataColRanges(static_cast<SCCOL>(i));
1513  aLabelTokens = pChartMap->getColHeaderRanges(static_cast<SCCOL>(i));
1514  }
1515  else
1516  {
1517  aValueTokens = pChartMap->getDataRowRanges(static_cast<SCROW>(i));
1518  aLabelTokens = pChartMap->getRowHeaderRanges(static_cast<SCROW>(i));
1519  }
1520  uno::Reference< chart2::data::XLabeledDataSequence > xChartSeries = lcl_createLabeledDataSequenceFromTokens(
1521  std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1522  if ( xChartSeries.is() && xChartSeries->getValues().is() && xChartSeries->getValues()->getData().hasElements() )
1523  {
1524  aSeqs.push_back( xChartSeries );
1525  }
1526  }
1527 
1528  pDS = new ScChart2DataSource(m_pDocument);
1529 
1530  //reorder labeled sequences according to aSequenceMapping
1531  ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqVector;
1532  aSeqVector.reserve(aSeqs.size());
1533  for (auto const& aSeq : aSeqs)
1534  {
1535  aSeqVector.push_back(aSeq);
1536  }
1537 
1538  for( const sal_Int32 nNewIndex : aSequenceMapping )
1539  {
1540  // note: assuming that the values in the sequence mapping are always non-negative
1541  ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > >::size_type nOldIndex( static_cast< sal_uInt32 >( nNewIndex ) );
1542  if( nOldIndex < aSeqVector.size() )
1543  {
1544  pDS->AddLabeledSequence( aSeqVector[nOldIndex] );
1545  aSeqVector[nOldIndex] = nullptr;
1546  }
1547  }
1548 
1549  for(const uno::Reference< chart2::data::XLabeledDataSequence >& xSeq : aSeqVector)
1550  {
1551  if ( xSeq.is() )
1552  {
1553  pDS->AddLabeledSequence( xSeq );
1554  }
1555  }
1556 
1557  xResult.set( pDS );
1558  return xResult;
1559 }
1560 
1561 namespace
1562 {
1563 
1567 class InsertTabNumber
1568 {
1569 public:
1570  InsertTabNumber() :
1571  mpTabNumVector(std::make_shared<vector<SCTAB>>())
1572  {
1573  }
1574 
1575  void operator() (const ScTokenRef& pToken) const
1576  {
1577  if (!ScRefTokenHelper::isRef(pToken))
1578  return;
1579 
1580  const ScSingleRefData& r = *pToken->GetSingleRef();
1581  mpTabNumVector->push_back(r.Tab());
1582  }
1583 
1584  void getVector(vector<SCTAB>& rVector)
1585  {
1586  mpTabNumVector->swap(rVector);
1587  }
1588 private:
1589  shared_ptr< vector<SCTAB> > mpTabNumVector;
1590 };
1591 
1592 class RangeAnalyzer
1593 {
1594 public:
1595  RangeAnalyzer();
1596  void initRangeAnalyzer( const vector<ScTokenRef>& rTokens );
1597  void analyzeRange( sal_Int32& rnDataInRows, sal_Int32& rnDataInCols,
1598  bool& rbRowSourceAmbiguous ) const;
1599  bool inSameSingleRow( const RangeAnalyzer& rOther );
1600  bool inSameSingleColumn( const RangeAnalyzer& rOther );
1601  SCROW getRowCount() const { return mnRowCount; }
1602  SCCOL getColumnCount() const { return mnColumnCount; }
1603 
1604 private:
1605  bool mbEmpty;
1606  bool mbAmbiguous;
1607  SCROW mnRowCount;
1608  SCCOL mnColumnCount;
1609 
1610  SCCOL mnStartColumn;
1611  SCROW mnStartRow;
1612 };
1613 
1614 RangeAnalyzer::RangeAnalyzer()
1615  : mbEmpty(true)
1616  , mbAmbiguous(false)
1617  , mnRowCount(0)
1618  , mnColumnCount(0)
1619  , mnStartColumn(-1)
1620  , mnStartRow(-1)
1621 {
1622 }
1623 
1624 void RangeAnalyzer::initRangeAnalyzer( const vector<ScTokenRef>& rTokens )
1625 {
1626  mnRowCount=0;
1627  mnColumnCount=0;
1628  mnStartColumn = -1;
1629  mnStartRow = -1;
1630  mbAmbiguous=false;
1631  if( rTokens.empty() )
1632  {
1633  mbEmpty=true;
1634  return;
1635  }
1636  mbEmpty=false;
1637 
1638  for (const ScTokenRef& aRefToken : rTokens)
1639  {
1640  StackVar eVar = aRefToken->GetType();
1641  if (eVar == svDoubleRef || eVar == svExternalDoubleRef)
1642  {
1643  const ScComplexRefData& r = *aRefToken->GetDoubleRef();
1644  if (r.Ref1.Tab() == r.Ref2.Tab())
1645  {
1646  mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(r.Ref2.Col() - r.Ref1.Col())+1));
1647  mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(r.Ref2.Row() - r.Ref1.Row())+1));
1648  if( mnStartColumn == -1 )
1649  {
1650  mnStartColumn = r.Ref1.Col();
1651  mnStartRow = r.Ref1.Row();
1652  }
1653  else
1654  {
1655  if (mnStartColumn != r.Ref1.Col() && mnStartRow != r.Ref1.Row())
1656  mbAmbiguous=true;
1657  }
1658  }
1659  else
1660  mbAmbiguous=true;
1661  }
1662  else if (eVar == svSingleRef || eVar == svExternalSingleRef)
1663  {
1664  const ScSingleRefData& r = *aRefToken->GetSingleRef();
1665  mnColumnCount = std::max<SCCOL>( mnColumnCount, 1);
1666  mnRowCount = std::max<SCROW>( mnRowCount, 1);
1667  if( mnStartColumn == -1 )
1668  {
1669  mnStartColumn = r.Col();
1670  mnStartRow = r.Row();
1671  }
1672  else
1673  {
1674  if (mnStartColumn != r.Col() && mnStartRow != r.Row())
1675  mbAmbiguous=true;
1676  }
1677  }
1678  else
1679  mbAmbiguous=true;
1680  }
1681 }
1682 
1683 void RangeAnalyzer::analyzeRange( sal_Int32& rnDataInRows,
1684  sal_Int32& rnDataInCols,
1685  bool& rbRowSourceAmbiguous ) const
1686 {
1687  if(!mbEmpty && !mbAmbiguous)
1688  {
1689  if( mnRowCount==1 && mnColumnCount>1 )
1690  ++rnDataInRows;
1691  else if( mnColumnCount==1 && mnRowCount>1 )
1692  ++rnDataInCols;
1693  else if( mnRowCount>1 && mnColumnCount>1 )
1694  rbRowSourceAmbiguous = true;
1695  }
1696  else if( !mbEmpty )
1697  rbRowSourceAmbiguous = true;
1698 }
1699 
1700 bool RangeAnalyzer::inSameSingleRow( const RangeAnalyzer& rOther )
1701 {
1702  return mnStartRow==rOther.mnStartRow &&
1703  mnRowCount==1 && rOther.mnRowCount==1;
1704 }
1705 
1706 bool RangeAnalyzer::inSameSingleColumn( const RangeAnalyzer& rOther )
1707 {
1708  return mnStartColumn==rOther.mnStartColumn &&
1709  mnColumnCount==1 && rOther.mnColumnCount==1;
1710 }
1711 
1712 std::pair<OUString, OUString> constructKey(const uno::Reference< chart2::data::XLabeledDataSequence>& xNew)
1713 {
1714  std::pair<OUString, OUString> aKey;
1715  if( xNew->getLabel().is() )
1716  aKey.first = xNew->getLabel()->getSourceRangeRepresentation();
1717  if( xNew->getValues().is() )
1718  aKey.second = xNew->getValues()->getSourceRangeRepresentation();
1719  return aKey;
1720 }
1721 
1722 
1723 } //end anonymous namespace
1724 
1725 uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments(
1726  const uno::Reference< chart2::data::XDataSource >& xDataSource )
1727 {
1728  ::std::vector< beans::PropertyValue > aResult;
1729  bool bRowSourceDetected = false;
1730  bool bFirstCellAsLabel = false;
1731  bool bHasCategories = false;
1732  OUString sRangeRep;
1733 
1734  bool bHasCategoriesLabels = false;
1735  vector<ScTokenRef> aAllCategoriesValuesTokens;
1736  vector<ScTokenRef> aAllSeriesLabelTokens;
1737 
1738  chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS;
1739 
1740  vector<ScTokenRef> aAllTokens;
1741 
1742  // parse given data source and collect infos
1743  {
1744  SolarMutexGuard aGuard;
1745  OSL_ENSURE( m_pDocument, "No Document -> no detectArguments" );
1746  if(!m_pDocument ||!xDataSource.is())
1747  return comphelper::containerToSequence( aResult );
1748 
1749  sal_Int32 nDataInRows = 0;
1750  sal_Int32 nDataInCols = 0;
1751  bool bRowSourceAmbiguous = false;
1752 
1753  const Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences());
1754  const sal_Int32 nCount( aSequences.getLength());
1755  RangeAnalyzer aPrevLabel,aPrevValues;
1756  for( const uno::Reference< chart2::data::XLabeledDataSequence >& xLS : aSequences )
1757  {
1758  if( xLS.is() )
1759  {
1760  bool bThisIsCategories = false;
1761  if(!bHasCategories)
1762  {
1763  uno::Reference< beans::XPropertySet > xSeqProp( xLS->getValues(), uno::UNO_QUERY );
1764  OUString aRole;
1765  if( xSeqProp.is() && (xSeqProp->getPropertyValue("Role") >>= aRole) &&
1766  aRole == "categories" )
1767  bThisIsCategories = bHasCategories = true;
1768  }
1769 
1770  RangeAnalyzer aLabel,aValues;
1771  // label
1772  uno::Reference< chart2::data::XDataSequence > xLabel( xLS->getLabel());
1773  if( xLabel.is())
1774  {
1775  bFirstCellAsLabel = true;
1776  vector<ScTokenRef> aTokens;
1779  aTokens, xLabel->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1780  aLabel.initRangeAnalyzer(aTokens);
1781  for (const auto& rxToken : aTokens)
1782  {
1783  ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1784  if(!bThisIsCategories)
1785  ScRefTokenHelper::join(m_pDocument, aAllSeriesLabelTokens, rxToken, ScAddress());
1786  }
1787  if(bThisIsCategories)
1788  bHasCategoriesLabels=true;
1789  }
1790  // values
1791  uno::Reference< chart2::data::XDataSequence > xValues( xLS->getValues());
1792  if( xValues.is())
1793  {
1794  vector<ScTokenRef> aTokens;
1797  aTokens, xValues->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1798  aValues.initRangeAnalyzer(aTokens);
1799  for (const auto& rxToken : aTokens)
1800  {
1801  ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1802  if(bThisIsCategories)
1803  ScRefTokenHelper::join(m_pDocument, aAllCategoriesValuesTokens, rxToken, ScAddress());
1804  }
1805  }
1806  //detect row source
1807  if(!bThisIsCategories || nCount==1) //categories might span multiple rows *and* columns, so they should be used for detection only if nothing else is available
1808  {
1809  if (!bRowSourceAmbiguous)
1810  {
1811  aValues.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1812  aLabel.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1813  if (nDataInRows > 1 && nDataInCols > 1)
1814  bRowSourceAmbiguous = true;
1815  else if( !bRowSourceAmbiguous && !nDataInRows && !nDataInCols )
1816  {
1817  if( aValues.inSameSingleColumn( aLabel ) )
1818  nDataInCols++;
1819  else if( aValues.inSameSingleRow( aLabel ) )
1820  nDataInRows++;
1821  else
1822  {
1823  //#i86188# also detect a single column split into rows correctly
1824  if( aValues.inSameSingleColumn( aPrevValues ) )
1825  nDataInRows++;
1826  else if( aValues.inSameSingleRow( aPrevValues ) )
1827  nDataInCols++;
1828  else if( aLabel.inSameSingleColumn( aPrevLabel ) )
1829  nDataInRows++;
1830  else if( aLabel.inSameSingleRow( aPrevLabel ) )
1831  nDataInCols++;
1832  }
1833  }
1834  }
1835  }
1836  aPrevValues=aValues;
1837  aPrevLabel=aLabel;
1838  }
1839  }
1840 
1841  if (!bRowSourceAmbiguous)
1842  {
1843  bRowSourceDetected = true;
1844  eRowSource = ( nDataInCols > 0
1845  ? chart::ChartDataRowSource_COLUMNS
1846  : chart::ChartDataRowSource_ROWS );
1847  }
1848  else
1849  {
1850  // set DataRowSource to the better of the two ambiguities
1851  eRowSource = ( nDataInRows > nDataInCols
1852  ? chart::ChartDataRowSource_ROWS
1853  : chart::ChartDataRowSource_COLUMNS );
1854  }
1855 
1856  }
1857 
1858  // TableNumberList
1859  {
1860  vector<SCTAB> aTableNumVector;
1861  InsertTabNumber func;
1862  func = ::std::for_each(aAllTokens.begin(), aAllTokens.end(), func);
1863  func.getVector(aTableNumVector);
1864  aResult.emplace_back( "TableNumberList", -1,
1865  uno::makeAny( lcl_createTableNumberList( aTableNumVector ) ),
1866  beans::PropertyState_DIRECT_VALUE );
1867  }
1868 
1869  if( bRowSourceDetected )
1870  {
1871  // DataRowSource (calculated before)
1872  aResult.emplace_back( "DataRowSource", -1,
1873  uno::makeAny( eRowSource ), beans::PropertyState_DIRECT_VALUE );
1874  // HasCategories
1875  aResult.emplace_back( "HasCategories", -1,
1876  uno::makeAny( bHasCategories ), beans::PropertyState_DIRECT_VALUE );
1877  // FirstCellAsLabel
1878  aResult.emplace_back( "FirstCellAsLabel", -1,
1879  uno::makeAny( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE );
1880  }
1881 
1882  // Add the left upper corner to the range if it is missing.
1883  if (bRowSourceDetected && bFirstCellAsLabel && bHasCategories && !bHasCategoriesLabels )
1884  {
1885  RangeAnalyzer aTop,aLeft;
1886  if( eRowSource==chart::ChartDataRowSource_COLUMNS )
1887  {
1888  aTop.initRangeAnalyzer(aAllSeriesLabelTokens);
1889  aLeft.initRangeAnalyzer(aAllCategoriesValuesTokens);
1890  }
1891  else
1892  {
1893  aTop.initRangeAnalyzer(aAllCategoriesValuesTokens);
1894  aLeft.initRangeAnalyzer(aAllSeriesLabelTokens);
1895  }
1896  lcl_addUpperLeftCornerIfMissing(m_pDocument, aAllTokens, aTop.getRowCount(), aLeft.getColumnCount());//e.g. #i91212#
1897  }
1898 
1899  // Get range string.
1900  lcl_convertTokensToString(sRangeRep, aAllTokens, *m_pDocument);
1901 
1902  // add cell range property
1903  aResult.emplace_back( "CellRangeRepresentation", -1,
1904  uno::makeAny( sRangeRep ), beans::PropertyState_DIRECT_VALUE );
1905 
1906  //Sequence Mapping
1907  bool const bSequencesReordered = true;//todo detect this above or detect this sequence mapping cheaper ...
1908  if( bSequencesReordered && bRowSourceDetected )
1909  {
1910  bool bDifferentIndexes = false;
1911 
1912  std::vector< sal_Int32 > aSequenceMappingVector;
1913 
1914  uno::Reference< chart2::data::XDataSource > xCompareDataSource;
1915  try
1916  {
1917  xCompareDataSource.set( createDataSource( comphelper::containerToSequence( aResult ) ) );
1918  }
1919  catch( const lang::IllegalArgumentException & )
1920  {
1921  // creation of data source to compare didn't work, so we cannot
1922  // create a sequence mapping
1923  }
1924 
1925  if( xDataSource.is() && xCompareDataSource.is() )
1926  {
1927  const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aOldSequences =
1928  xCompareDataSource->getDataSequences();
1929  const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aNewSequences =
1930  xDataSource->getDataSequences();
1931 
1932  std::map<std::pair<OUString, OUString>,sal_Int32> aOldEntryToIndex;
1933  for( sal_Int32 nIndex = 0, n = aOldSequences.getLength(); nIndex < n; nIndex++ )
1934  {
1935  const uno::Reference< chart2::data::XLabeledDataSequence>& xOld( aOldSequences[nIndex] );
1936  if( xOld.is() )
1937  {
1938  std::pair<OUString, OUString> aKey = constructKey(xOld);
1939  aOldEntryToIndex[aKey] = nIndex;
1940  }
1941  }
1942 
1943  for( sal_Int32 nNewIndex = 0, n = aNewSequences.getLength(); nNewIndex < n; nNewIndex++ )
1944  {
1945  const uno::Reference< chart2::data::XLabeledDataSequence>& xNew( aNewSequences[nNewIndex] );
1946  if( !xNew.is() )
1947  continue;
1948 
1949  std::pair<OUString, OUString> aKey = constructKey(xNew);
1950  if (aOldEntryToIndex.find(aKey) == aOldEntryToIndex.end())
1951  continue;
1952 
1953  sal_Int32 nOldIndex = aOldEntryToIndex[aKey];
1954  if( nOldIndex != nNewIndex )
1955  bDifferentIndexes = true;
1956 
1957  aSequenceMappingVector.push_back(nOldIndex);
1958  }
1959  }
1960 
1961  if( bDifferentIndexes && !aSequenceMappingVector.empty() )
1962  {
1963  aResult.emplace_back( "SequenceMapping", -1,
1964  uno::makeAny( comphelper::containerToSequence(aSequenceMappingVector) )
1965  , beans::PropertyState_DIRECT_VALUE );
1966  }
1967  }
1968 
1969  return comphelper::containerToSequence( aResult );
1970 }
1971 
1973 {
1974  SolarMutexGuard aGuard;
1975  if( ! m_pDocument )
1976  return false;
1977 
1978  vector<ScTokenRef> aTokens;
1981  aTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1982  return !aTokens.empty();
1983 }
1984 
1985 uno::Reference< chart2::data::XDataSequence > SAL_CALL
1987  const OUString& aRangeRepresentation )
1988 {
1989  SolarMutexGuard aGuard;
1990  uno::Reference< chart2::data::XDataSequence > xResult;
1991 
1992  OSL_ENSURE( m_pDocument, "No Document -> no createDataSequenceByRangeRepresentation" );
1993  if(!m_pDocument || aRangeRepresentation.isEmpty())
1994  return xResult;
1995 
1996  vector<ScTokenRef> aRefTokens;
1999  aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2000  if (aRefTokens.empty())
2001  return xResult;
2002 
2003  shrinkToDataRange(m_pDocument, aRefTokens);
2004 
2005  xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
2006 
2007  return xResult;
2008 }
2009 
2010 uno::Reference<chart2::data::XDataSequence> SAL_CALL
2012  const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/ )
2013 {
2014  return uno::Reference<chart2::data::XDataSequence>();
2015 }
2016 
2017 uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRangeSelection()
2018 {
2019  uno::Reference< sheet::XRangeSelection > xResult;
2020 
2021  uno::Reference< frame::XModel > xModel( lcl_GetXModel( m_pDocument ));
2022  if( xModel.is())
2023  xResult.set( xModel->getCurrentController(), uno::UNO_QUERY );
2024 
2025  return xResult;
2026 }
2027 
2029  const Sequence<sheet::FormulaToken>& aTokens )
2030 {
2031  if (!aTokens.hasElements())
2032  return false;
2033 
2034  ScTokenArray aCode(*m_pDocument);
2035  if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
2036  return false;
2037 
2038  sal_uInt16 n = aCode.GetLen();
2039  if (!n)
2040  return false;
2041 
2043  const formula::FormulaToken* pFirst = aIter.First();
2044  const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2045  for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
2046  {
2047  switch (p->GetType())
2048  {
2049  case svSep:
2050  {
2051  switch (p->GetOpCode())
2052  {
2053  case ocSep:
2054  // separators are allowed.
2055  break;
2056  case ocOpen:
2057  if (p != pFirst)
2058  // open paran is allowed only as the first token.
2059  return false;
2060  break;
2061  case ocClose:
2062  if (p != pLast)
2063  // close paren is allowed only as the last token.
2064  return false;
2065  break;
2066  default:
2067  return false;
2068  }
2069  }
2070  break;
2071  case svSingleRef:
2072  case svDoubleRef:
2073  case svExternalSingleRef:
2074  case svExternalDoubleRef:
2075  break;
2076  default:
2077  return false;
2078  }
2079  }
2080 
2081  return true;
2082 }
2083 
2084 uno::Reference<chart2::data::XDataSequence> SAL_CALL
2086  const Sequence<sheet::FormulaToken>& aTokens )
2087 {
2088  uno::Reference<chart2::data::XDataSequence> xResult;
2089  if (!aTokens.hasElements())
2090  return xResult;
2091 
2092  ScTokenArray aCode(*m_pDocument);
2093  if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
2094  return xResult;
2095 
2096  sal_uInt16 n = aCode.GetLen();
2097  if (!n)
2098  return xResult;
2099 
2100  vector<ScTokenRef> aRefTokens;
2102  const formula::FormulaToken* pFirst = aIter.First();
2103  const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2104  for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
2105  {
2106  switch (p->GetType())
2107  {
2108  case svSep:
2109  {
2110  switch (p->GetOpCode())
2111  {
2112  case ocSep:
2113  // separators are allowed.
2114  break;
2115  case ocOpen:
2116  if (p != pFirst)
2117  // open paran is allowed only as the first token.
2118  throw lang::IllegalArgumentException();
2119  break;
2120  case ocClose:
2121  if (p != pLast)
2122  // close paren is allowed only as the last token.
2123  throw lang::IllegalArgumentException();
2124  break;
2125  default:
2126  throw lang::IllegalArgumentException();
2127  }
2128  }
2129  break;
2130  case svString:
2131  case svSingleRef:
2132  case svDoubleRef:
2133  case svExternalSingleRef:
2134  case svExternalDoubleRef:
2135  {
2136  ScTokenRef pNew(p->Clone());
2137  aRefTokens.push_back(pNew);
2138  }
2139  break;
2140  default:
2141  throw lang::IllegalArgumentException();
2142  }
2143  }
2144 
2145  if (aRefTokens.empty())
2146  return xResult;
2147 
2148  shrinkToDataRange(m_pDocument, aRefTokens);
2149 
2150  xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
2151  return xResult;
2152 }
2153 
2154 // XRangeXMLConversion ---------------------------------------------------
2155 
2156 OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const OUString& sRangeRepresentation )
2157 {
2158  OUString aRet;
2159  if (!m_pDocument)
2160  return aRet;
2161 
2162  if (sRangeRepresentation.isEmpty())
2163  // Empty data range is allowed.
2164  return aRet;
2165 
2166  vector<ScTokenRef> aRefTokens;
2169  aRefTokens, sRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2170  if (aRefTokens.empty())
2171  throw lang::IllegalArgumentException();
2172 
2173  Tokens2RangeStringXML converter(*m_pDocument);
2174  converter = ::std::for_each(aRefTokens.begin(), aRefTokens.end(), converter);
2175  converter.getString(aRet);
2176 
2177  return aRet;
2178 }
2179 
2180 OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const OUString& sXMLRange )
2181 {
2182  if (!m_pDocument)
2183  {
2184  // #i74062# When loading flat XML, this is called before the referenced sheets are in the document,
2185  // so the conversion has to take place directly with the strings, without looking up the sheets.
2186 
2187  OUStringBuffer sRet;
2188  sal_Int32 nOffset = 0;
2189  while( nOffset >= 0 )
2190  {
2191  OUString sToken;
2192  ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset );
2193  if( nOffset >= 0 )
2194  {
2195  // convert one address (remove dots)
2196 
2197  OUString aUIString(sToken);
2198 
2199  sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0 );
2200  if ( nIndex >= 0 && nIndex < aUIString.getLength() - 1 &&
2201  aUIString[nIndex + 1] == '.' )
2202  aUIString = aUIString.replaceAt( nIndex + 1, 1, "" );
2203 
2204  if ( aUIString[0] == '.' )
2205  aUIString = aUIString.copy( 1 );
2206 
2207  if( !sRet.isEmpty() )
2208  sRet.append( ';' );
2209  sRet.append( aUIString );
2210  }
2211  }
2212 
2213  return sRet.makeStringAndClear();
2214  }
2215 
2216  OUString aRet;
2218  return aRet;
2219 }
2220 
2221 // DataProvider XPropertySet -------------------------------------------------
2222 
2223 uno::Reference< beans::XPropertySetInfo> SAL_CALL
2225 {
2226  SolarMutexGuard aGuard;
2227  static uno::Reference<beans::XPropertySetInfo> aRef =
2229  return aRef;
2230 }
2231 
2233  const OUString& rPropertyName, const uno::Any& rValue)
2234 {
2235  if ( rPropertyName != SC_UNONAME_INCLUDEHIDDENCELLS )
2236  throw beans::UnknownPropertyException(rPropertyName);
2237 
2238  if ( !(rValue >>= m_bIncludeHiddenCells))
2239  throw lang::IllegalArgumentException();
2240 
2241 }
2242 
2244  const OUString& rPropertyName)
2245 {
2246  uno::Any aRet;
2247  if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2248  aRet <<= m_bIncludeHiddenCells;
2249  else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
2250  {
2251  // This is a read-only property.
2253  }
2254  else
2255  throw beans::UnknownPropertyException(rPropertyName);
2256  return aRet;
2257 }
2258 
2260  const OUString& /*rPropertyName*/,
2261  const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
2262 {
2263  OSL_FAIL( "Not yet implemented" );
2264 }
2265 
2267  const OUString& /*rPropertyName*/,
2268  const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
2269 {
2270  OSL_FAIL( "Not yet implemented" );
2271 }
2272 
2274  const OUString& /*rPropertyName*/,
2275  const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
2276 {
2277  OSL_FAIL( "Not yet implemented" );
2278 }
2279 
2281  const OUString& /*rPropertyName*/,
2282  const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/ )
2283 {
2284  OSL_FAIL( "Not yet implemented" );
2285 }
2286 
2287 // DataSource ================================================================
2288 
2290  : m_pDocument( pDoc)
2291 {
2292  if ( m_pDocument )
2293  m_pDocument->AddUnoObject( *this);
2294 }
2295 
2297 {
2298  SolarMutexGuard g;
2299 
2300  if ( m_pDocument )
2301  m_pDocument->RemoveUnoObject( *this);
2302 }
2303 
2305 {
2306  if ( rHint.GetId() == SfxHintId::Dying )
2307  {
2308  m_pDocument = nullptr;
2309  }
2310 }
2311 
2312 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > SAL_CALL
2314 {
2315  SolarMutexGuard aGuard;
2317 }
2318 
2319 void ScChart2DataSource::AddLabeledSequence(const uno::Reference < chart2::data::XLabeledDataSequence >& xNew)
2320 {
2321  m_aLabeledSequences.push_back(xNew);
2322 }
2323 
2324 // DataSequence ==============================================================
2325 
2327  mfValue(0.0), mbIsValue(false)
2328 {
2329  ::rtl::math::setNan(&mfValue);
2330 }
2331 
2333  mrParent(rParent)
2334 {
2335 }
2336 
2338 {
2339 }
2340 
2342 {
2343  mrParent.setDataChangedHint(true);
2344 }
2345 
2347  vector<ScTokenRef>&& rTokens,
2348  bool bIncludeHiddenCells )
2349  : m_bIncludeHiddenCells( bIncludeHiddenCells)
2350  , m_nObjectId( 0 )
2351  , m_pDocument( pDoc)
2352  , m_aTokens(std::move(rTokens))
2354  , m_bGotDataChangedHint(false)
2355  , m_bExtDataRebuildQueued(false)
2356  , mbTimeBased(false)
2357  , mnTimeBasedStart(0)
2358  , mnTimeBasedEnd(0)
2359  , mnCurrentTab(0)
2360 {
2361  if ( m_pDocument )
2362  {
2363  m_pDocument->AddUnoObject( *this);
2365  }
2366  // FIXME: real implementation of identifier and it's mapping to ranges.
2367  // Reuse ScChartListener?
2368 
2369  // BM: don't use names of named ranges but the UI range strings
2370 // String aStr;
2371 // rRangeList->Format( aStr, ScRefFlags::RANGE_ABS_3D, m_pDocument );
2372 // m_aIdentifier = aStr;
2373 
2374 // m_aIdentifier = "ID_";
2375 // static sal_Int32 nID = 0;
2376 // m_aIdentifier += OUString::valueOf( ++nID);
2377 }
2378 
2380 {
2381  SolarMutexGuard g;
2382 
2383  if ( m_pDocument )
2384  {
2385  m_pDocument->RemoveUnoObject( *this);
2386  if (m_pHiddenListener)
2387  {
2389  if (pCLC)
2391  }
2393  }
2394 
2395  m_pValueListener.reset();
2396 }
2397 
2399 {
2400  if( !m_pValueListener || m_aValueListeners.empty() )
2401  return;
2402 
2403  m_pValueListener->EndListeningAll();
2404 
2405  if( !m_pDocument )
2406  return;
2407 
2408  ScChartListenerCollection* pCLC = nullptr;
2409  if (m_pHiddenListener)
2410  {
2412  if (pCLC)
2414  }
2415 
2416  for (const auto& rxToken : m_aTokens)
2417  {
2418  ScRange aRange;
2419  if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
2420  continue;
2421 
2422  m_pDocument->StartListeningArea(aRange, false, m_pValueListener.get());
2423  if (pCLC)
2424  pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
2425  }
2426 }
2427 
2429 {
2430  m_bExtDataRebuildQueued = false;
2431 
2432  if (!m_aDataArray.empty())
2433  return;
2434 
2436 
2437  ::std::vector<sal_Int32> aHiddenValues;
2438  sal_Int32 nDataCount = 0;
2439 
2440  for (const auto& rxToken : m_aTokens)
2441  {
2442  if (ScRefTokenHelper::isExternalRef(rxToken))
2443  {
2444  nDataCount += FillCacheFromExternalRef(rxToken);
2445  }
2446  else
2447  {
2448  ScRange aRange;
2449  if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
2450  continue;
2451 
2452  SCCOL nLastCol = -1;
2453  SCROW nLastRow = -1;
2454  for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
2455  {
2456  for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
2457  {
2459  m_pDocument->InitColumnBlockPosition( hint, nTab, nCol );
2460  for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
2461  {
2462  bool bColHidden = m_pDocument->ColHidden(nCol, nTab, nullptr, &nLastCol);
2463  bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, nullptr, &nLastRow);
2464 
2465  if (bColHidden || bRowHidden)
2466  {
2467  // hidden cell
2468  aHiddenValues.push_back(nDataCount-1);
2469 
2470  if( !m_bIncludeHiddenCells )
2471  continue;
2472  }
2473 
2474  Item aItem;
2475 
2476  ScAddress aAdr(nCol, nRow, nTab);
2477  aItem.maString = m_pDocument->GetString(aAdr);
2478 
2479  ScRefCellValue aCell(*m_pDocument, aAdr, hint);
2480  switch (aCell.meType)
2481  {
2482  case CELLTYPE_VALUE:
2483  aItem.mfValue = aCell.getValue();
2484  aItem.mbIsValue = true;
2485  break;
2486  case CELLTYPE_FORMULA:
2487  {
2488  ScFormulaCell* pFCell = aCell.mpFormula;
2489  FormulaError nErr = pFCell->GetErrCode();
2490  if (nErr != FormulaError::NONE)
2491  break;
2492 
2493  if (pFCell->IsValue())
2494  {
2495  aItem.mfValue = pFCell->GetValue();
2496  aItem.mbIsValue = true;
2497  }
2498  }
2499  break;
2500  case CELLTYPE_EDIT:
2501  case CELLTYPE_NONE:
2502  case CELLTYPE_STRING:
2503  default:
2504  ; // do nothing
2505  }
2506 
2507  aItem.mAddress = ScAddress(nCol, nRow, nTab);
2508 
2509  m_aDataArray.push_back(aItem);
2510  ++nDataCount;
2511  }
2512  }
2513  }
2514  }
2515  }
2516 
2517  // convert the hidden cell list to sequence.
2518  m_aHiddenValues.realloc(aHiddenValues.size());
2519  std::copy(
2520  aHiddenValues.begin(), aHiddenValues.end(), m_aHiddenValues.begin());
2521 
2522  // Clear the data series cache when the array is re-built.
2523  m_aMixedDataCache.realloc(0);
2524 }
2525 
2527 {
2529  {
2530  m_aDataArray.clear();
2531  m_pDocument->BroadcastUno(ScHint(SfxHintId::ScDataChanged, ScAddress()));
2532  m_bExtDataRebuildQueued = true;
2533  m_bGotDataChangedHint = true;
2534  }
2535 }
2536 
2538 {
2540  ScRange aRange;
2541  if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, pToken, ScAddress(), true))
2542  return 0;
2543 
2544  sal_uInt16 nFileId = pToken->GetIndex();
2545  OUString aTabName = pToken->GetString().getString();
2546  ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, aTabName, aRange, nullptr);
2547  if (!pArray)
2548  // no external data exists for this range.
2549  return 0;
2550 
2551  // Start listening for this external document.
2552  ExternalRefListener* pExtRefListener = GetExtRefListener();
2553  pRefMgr->addLinkListener(nFileId, pExtRefListener);
2554  pExtRefListener->addFileId(nFileId);
2555 
2556  ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, aTabName, false);
2557  sal_Int32 nDataCount = 0;
2558  FormulaTokenArrayPlainIterator aIter(*pArray);
2559  for (FormulaToken* p = aIter.First(); p; p = aIter.Next())
2560  {
2561  // Cached external range is always represented as a single
2562  // matrix token, although that might change in the future when
2563  // we introduce a new token type to store multi-table range
2564  // data.
2565 
2566  if (p->GetType() != svMatrix)
2567  {
2568  OSL_FAIL("Cached array is not a matrix token.");
2569  continue;
2570  }
2571 
2572  const ScMatrix* pMat = p->GetMatrix();
2573  SCSIZE nCSize, nRSize;
2574  pMat->GetDimensions(nCSize, nRSize);
2575  for (SCSIZE nC = 0; nC < nCSize; ++nC)
2576  {
2577  for (SCSIZE nR = 0; nR < nRSize; ++nR)
2578  {
2579  if (pMat->IsValue(nC, nR) || pMat->IsBoolean(nC, nR))
2580  {
2581  Item aItem;
2582 
2583  aItem.mbIsValue = true;
2584  aItem.mfValue = pMat->GetDouble(nC, nR);
2585 
2586  SvNumberFormatter* pFormatter = m_pDocument->GetFormatTable();
2587  if (pFormatter)
2588  {
2589  const double fVal = aItem.mfValue;
2590  const Color* pColor = nullptr;
2591  sal_uInt32 nFmt = 0;
2592  if (pTable)
2593  {
2594  // Get the correct format index from the cache.
2595  SCCOL nCol = aRange.aStart.Col() + static_cast<SCCOL>(nC);
2596  SCROW nRow = aRange.aStart.Row() + static_cast<SCROW>(nR);
2597  pTable->getCell(nCol, nRow, &nFmt);
2598  }
2599  pFormatter->GetOutputString(fVal, nFmt, aItem.maString, &pColor);
2600  }
2601 
2602  m_aDataArray.push_back(aItem);
2603  ++nDataCount;
2604  }
2605  else if (pMat->IsStringOrEmpty(nC, nR))
2606  {
2607  Item aItem;
2608 
2609  aItem.mbIsValue = false;
2610  aItem.maString = pMat->GetString(nC, nR).getString();
2611 
2612  m_aDataArray.emplace_back(aItem);
2613  ++nDataCount;
2614  }
2615  }
2616  }
2617  }
2618  return nDataCount;
2619 }
2620 
2622 {
2623  if (!m_pRangeIndices)
2624  return;
2625 
2626  for ( size_t i = 0, nCount = rRanges.size(); i < nCount; ++i )
2627  {
2628  ScTokenRef pToken;
2629  const ScRange & rRange = rRanges[i];
2630 
2632  sal_uInt32 nOrigPos = (*m_pRangeIndices)[i];
2633  m_aTokens[nOrigPos] = pToken;
2634  }
2635 
2636  RefChanged();
2637 
2638  // any change of the range address is broadcast to value (modify) listeners
2639  if ( !m_aValueListeners.empty() )
2640  m_bGotDataChangedHint = true;
2641 }
2642 
2644 {
2645  if (!m_pExtRefListener)
2647 
2648  return m_pExtRefListener.get();
2649 }
2650 
2652 {
2653  if (!m_pExtRefListener)
2654  return;
2655 
2656  const std::unordered_set<sal_uInt16>& rFileIds = m_pExtRefListener->getAllFileIds();
2658  for (const auto& rFileId : rFileIds)
2659  pRefMgr->removeLinkListener(rFileId, m_pExtRefListener.get());
2660 
2661  m_pExtRefListener.reset();
2662 }
2663 
2664 void ScChart2DataSequence::CopyData(const ScChart2DataSequence& r)
2665 {
2666  if (!m_pDocument)
2667  {
2668  OSL_FAIL("document instance is nullptr!?");
2669  return;
2670  }
2671 
2672  std::vector<Item> aDataArray(r.m_aDataArray);
2673  m_aDataArray.swap(aDataArray);
2674 
2676  m_aRole = r.m_aRole;
2677 
2678  if (r.m_pRangeIndices)
2679  m_pRangeIndices.reset(new vector<sal_uInt32>(*r.m_pRangeIndices));
2680 
2681  if (!r.m_pExtRefListener)
2682  return;
2683 
2684  // Re-register all external files that the old instance was
2685  // listening to.
2686 
2689  const std::unordered_set<sal_uInt16>& rFileIds = r.m_pExtRefListener->getAllFileIds();
2690  for (const auto& rFileId : rFileIds)
2691  {
2692  pRefMgr->addLinkListener(rFileId, m_pExtRefListener.get());
2693  m_pExtRefListener->addFileId(rFileId);
2694  }
2695 }
2696 
2698 {
2699  if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
2700  {
2701  // Create a range list from the token list, have the range list
2702  // updated, and bring the change back to the token list.
2703 
2704  ScRangeList aRanges;
2705  m_pRangeIndices.reset(new vector<sal_uInt32>);
2706  vector<ScTokenRef>::const_iterator itrBeg = m_aTokens.begin(), itrEnd = m_aTokens.end();
2707  for (vector<ScTokenRef>::const_iterator itr = itrBeg ;itr != itrEnd; ++itr)
2708  {
2710  {
2711  ScRange aRange;
2713  aRanges.push_back(aRange);
2714  sal_uInt32 nPos = distance(itrBeg, itr);
2715  m_pRangeIndices->push_back(nPos);
2716  }
2717  }
2718 
2719  OSL_ENSURE(m_pRangeIndices->size() == aRanges.size(),
2720  "range list and range index list have different sizes.");
2721 
2722  unique_ptr<ScRangeList> pUndoRanges;
2723  if ( m_pDocument->HasUnoRefUndo() )
2724  pUndoRanges.reset(new ScRangeList(aRanges));
2725 
2726  const ScUpdateRefHint& rRef = static_cast<const ScUpdateRefHint&>(rHint);
2727  bool bChanged = aRanges.UpdateReference(
2728  rRef.GetMode(), m_pDocument, rRef.GetRange(), rRef.GetDx(), rRef.GetDy(), rRef.GetDz());
2729 
2730  if (bChanged)
2731  {
2732  OSL_ENSURE(m_pRangeIndices->size() == aRanges.size(),
2733  "range list and range index list have different sizes after the reference update.");
2734 
2735  // Bring the change back from the range list to the token list.
2736  UpdateTokensFromRanges(aRanges);
2737 
2738  if (pUndoRanges)
2739  m_pDocument->AddUnoRefChange(m_nObjectId, *pUndoRanges);
2740  }
2741  }
2742  else if ( auto pUndoHint = dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
2743  {
2744  do
2745  {
2746  if (pUndoHint->GetObjectId() != m_nObjectId)
2747  break;
2748 
2749  // The hint object provides the old ranges. Restore the old state
2750  // from these ranges.
2751 
2752  if (!m_pRangeIndices || m_pRangeIndices->empty())
2753  {
2754  OSL_FAIL(" faulty range indices");
2755  break;
2756  }
2757 
2758  const ScRangeList& rRanges = pUndoHint->GetRanges();
2759 
2760  size_t nCount = rRanges.size();
2761  if (nCount != m_pRangeIndices->size())
2762  {
2763  OSL_FAIL("range count and range index count differ.");
2764  break;
2765  }
2766 
2767  UpdateTokensFromRanges(rRanges);
2768  }
2769  while (false);
2770  }
2771  else
2772  {
2773  const SfxHintId nId = rHint.GetId();
2774  if ( nId ==SfxHintId::Dying )
2775  {
2776  m_pDocument = nullptr;
2777  }
2778  else if ( nId == SfxHintId::DataChanged )
2779  {
2780  // delayed broadcast as in ScCellRangesBase
2781 
2783  {
2784  m_aDataArray.clear();
2785  lang::EventObject aEvent;
2786  aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
2787 
2788  if( m_pDocument )
2789  {
2790  for (const uno::Reference<util::XModifyListener> & xListener: m_aValueListeners)
2791  m_pDocument->AddUnoListenerCall( xListener, aEvent );
2792  }
2793 
2794  m_bGotDataChangedHint = false;
2795  }
2796  }
2797  else if ( nId == SfxHintId::ScCalcAll )
2798  {
2799  // broadcast from DoHardRecalc - set m_bGotDataChangedHint
2800  // (SfxHintId::DataChanged follows separately)
2801 
2802  if ( !m_aValueListeners.empty() )
2803  m_bGotDataChangedHint = true;
2804  }
2805  else if (nId == SfxHintId::ScClearCache)
2806  {
2807  // necessary after import
2808  m_aDataArray.clear();
2809  }
2810  }
2811 }
2812 
2813 IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, const SfxHint&, rHint, void )
2814 {
2815  if ( m_pDocument && (rHint.GetId() == SfxHintId::ScDataChanged) )
2816  {
2817  // This may be called several times for a single change, if several formulas
2818  // in the range are notified. So only a flag is set that is checked when
2819  // SfxHintId::DataChanged is received.
2820 
2821  setDataChangedHint(true);
2822  }
2823 }
2824 
2826  ScChart2DataSequence& rParent, ScDocument* pDoc) :
2827  ScExternalRefManager::LinkListener(),
2828  mrParent(rParent),
2829  mpDoc(pDoc)
2830 {
2831 }
2832 
2834 {
2835  if (!mpDoc || mpDoc->IsInDtorClear())
2836  // The document is being destroyed. Do nothing.
2837  return;
2838 
2839  // Make sure to remove all pointers to this object.
2840  mpDoc->GetExternalRefManager()->removeLinkListener(this);
2841 }
2842 
2844 {
2845  switch (eType)
2846  {
2848  {
2849  if (maFileIds.count(nFileId))
2850  // We are listening to this external document.
2851  mrParent.RebuildDataCache();
2852  }
2853  break;
2855  maFileIds.erase(nFileId);
2856  break;
2857  }
2858 }
2859 
2861 {
2862  maFileIds.insert(nFileId);
2863 }
2864 
2865 uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
2866 {
2867  SolarMutexGuard aGuard;
2868  if ( !m_pDocument)
2869  throw uno::RuntimeException();
2870 
2871  BuildDataCache();
2872 
2873  if (!m_aMixedDataCache.hasElements())
2874  {
2875  // Build a cache for the 1st time...
2876 
2877  sal_Int32 nCount = m_aDataArray.size();
2878  m_aMixedDataCache.realloc(nCount);
2879  uno::Any* pArr = m_aMixedDataCache.getArray();
2880  for (const Item &rItem : m_aDataArray)
2881  {
2882  if (rItem.mbIsValue)
2883  *pArr <<= rItem.mfValue;
2884  else if (rItem.maString.isEmpty())
2885  {
2886  ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
2887  if (aCell.isEmpty())
2888  *pArr = uno::Any();
2889  else
2890  *pArr <<= rItem.maString;
2891  }
2892  else
2893  *pArr <<= rItem.maString;
2894  ++pArr;
2895  }
2896  }
2897  return m_aMixedDataCache;
2898 }
2899 
2900 // XNumericalDataSequence --------------------------------------------------
2901 
2902 uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData()
2903 {
2904  SolarMutexGuard aGuard;
2905  if ( !m_pDocument)
2906  throw uno::RuntimeException();
2907 
2908  BuildDataCache();
2909 
2910  double fNAN;
2911  ::rtl::math::setNan(&fNAN);
2912 
2913  sal_Int32 nCount = m_aDataArray.size();
2914  uno::Sequence<double> aSeq(nCount);
2915  double* pArr = aSeq.getArray();
2916  for (const Item& rItem : m_aDataArray)
2917  {
2918  *pArr = rItem.mbIsValue ? rItem.mfValue : fNAN;
2919  ++pArr;
2920  }
2921 
2922  return aSeq;
2923 }
2924 
2925 // XTextualDataSequence --------------------------------------------------
2926 
2927 uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::getTextualData()
2928 {
2929  SolarMutexGuard aGuard;
2930  uno::Sequence<OUString> aSeq;
2931  if ( !m_pDocument )
2932  throw uno::RuntimeException();
2933 
2934  BuildDataCache();
2935 
2936  sal_Int32 nCount = m_aDataArray.size();
2937  if ( nCount > 0 )
2938  {
2939  aSeq = uno::Sequence<OUString>(nCount);
2940  OUString* pArr = aSeq.getArray();
2941  for (const Item& rItem : m_aDataArray)
2942  {
2943  *pArr = rItem.maString;
2944  ++pArr;
2945  }
2946  }
2947  else if ( m_aTokens.front() )
2948  {
2949  if( m_aTokens.front()->GetType() == svString )
2950  {
2951  aSeq = uno::Sequence<OUString>(1);
2952  aSeq[0] = m_aTokens.front()->GetString().getString();
2953  }
2954  }
2955 
2956  return aSeq;
2957 }
2958 
2960 {
2961  SolarMutexGuard aGuard;
2962  OUString aStr;
2963  OSL_ENSURE( m_pDocument, "No Document -> no SourceRangeRepresentation" );
2964  if (m_pDocument)
2965  lcl_convertTokensToString(aStr, m_aTokens, *m_pDocument);
2966 
2967  return aStr;
2968 }
2969 
2970 namespace {
2971 
2976 class AccumulateRangeSize
2977 {
2978 public:
2979  AccumulateRangeSize(const ScDocument* pDoc) :
2980  mpDoc(pDoc), mnCols(0), mnRows(0) {}
2981 
2982  void operator() (const ScTokenRef& pToken)
2983  {
2984  ScRange r;
2985  bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
2986  ScRefTokenHelper::getRangeFromToken(mpDoc, r, pToken, ScAddress(), bExternal);
2987  r.PutInOrder();
2988  mnCols += r.aEnd.Col() - r.aStart.Col() + 1;
2989  mnRows += r.aEnd.Row() - r.aStart.Row() + 1;
2990  }
2991 
2992  SCCOL getCols() const { return mnCols; }
2993  SCROW getRows() const { return mnRows; }
2994 private:
2995  const ScDocument* mpDoc;
2996  SCCOL mnCols;
2997  SCROW mnRows;
2998 };
2999 
3004 class GenerateLabelStrings
3005 {
3006 public:
3007  GenerateLabelStrings(const ScDocument* pDoc, sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) :
3008  mpDoc(pDoc),
3009  mpLabels(std::make_shared<Sequence<OUString>>(nSize)),
3010  meOrigin(eOrigin),
3011  mnCount(0),
3012  mbColumn(bColumn) {}
3013 
3014  void operator() (const ScTokenRef& pToken)
3015  {
3016  bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3017  ScRange aRange;
3018  ScRefTokenHelper::getRangeFromToken(mpDoc, aRange, pToken, ScAddress(), bExternal);
3019  OUString* pArr = mpLabels->getArray();
3020  if (mbColumn)
3021  {
3022  for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
3023  {
3024  if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3025  {
3026  OUString aString = ScResId(STR_COLUMN) + " ";
3027  ScAddress aPos( nCol, 0, 0 );
3028  OUString aColStr(aPos.Format(ScRefFlags::COL_VALID));
3029  aString += aColStr;
3030  pArr[mnCount] = aString;
3031  }
3032  else //only indices for categories
3033  pArr[mnCount] = OUString::number( mnCount+1 );
3034  ++mnCount;
3035  }
3036  }
3037  else
3038  {
3039  for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
3040  {
3041  if (meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3042  {
3043  OUString aString = ScResId(STR_ROW) +
3044  " " + OUString::number( nRow+1 );
3045  pArr[mnCount] = aString;
3046  }
3047  else //only indices for categories
3048  pArr[mnCount] = OUString::number( mnCount+1 );
3049  ++mnCount;
3050  }
3051  }
3052  }
3053 
3054  const Sequence<OUString>& getLabels() const { return *mpLabels; }
3055 
3056 private:
3057  const ScDocument* mpDoc;
3058  shared_ptr< Sequence<OUString> > mpLabels;
3059  chart2::data::LabelOrigin meOrigin;
3060  sal_Int32 mnCount;
3061  bool mbColumn;
3062 };
3063 
3064 }
3065 
3066 uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
3067 {
3068  SolarMutexGuard aGuard;
3069  if ( !m_pDocument)
3070  throw uno::RuntimeException();
3071 
3072  // Determine the total size of all ranges.
3073  AccumulateRangeSize func(m_pDocument);
3074  func = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), func);
3075  SCCOL nCols = func.getCols();
3076  SCROW nRows = func.getRows();
3077 
3078  // Determine whether this is column-major or row-major.
3079  bool bColumn = true;
3080  if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
3081  (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
3082  {
3083  if (nRows > nCols)
3084  {
3085  bColumn = eOrigin == chart2::data::LabelOrigin_SHORT_SIDE;
3086  }
3087  else if (nCols > nRows)
3088  {
3089  bColumn = eOrigin != chart2::data::LabelOrigin_SHORT_SIDE;
3090  }
3091  else
3092  return Sequence<OUString>();
3093  }
3094 
3095  // Generate label strings based on the info so far.
3096  sal_Int32 nCount = bColumn ? nCols : nRows;
3097  GenerateLabelStrings genLabels(m_pDocument, nCount, eOrigin, bColumn);
3098  genLabels = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), genLabels);
3099  Sequence<OUString> aSeq = genLabels.getLabels();
3100 
3101  return aSeq;
3102 }
3103 
3104 namespace {
3105 
3106 sal_uInt32 getDisplayNumberFormat(const ScDocument* pDoc, const ScAddress& rPos)
3107 {
3108  sal_uInt32 nFormat = pDoc->GetNumberFormat(rPos); // original format from cell.
3109  return nFormat;
3110 }
3111 
3112 }
3113 
3114 ::sal_Int32 SAL_CALL ScChart2DataSequence::getNumberFormatKeyByIndex( ::sal_Int32 nIndex )
3115 {
3116  SolarMutexGuard aGuard;
3117  BuildDataCache();
3118 
3119  if (nIndex == -1)
3120  {
3121  // return format of first non-empty cell
3122  // TODO: use nicer heuristic
3123  for (const Item& rItem : m_aDataArray)
3124  {
3125  ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
3126  if (!aCell.isEmpty() && aCell.hasNumeric())
3127  {
3128  return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, rItem.mAddress));
3129  }
3130  }
3131 
3132  // we could not find a non-empty cell
3133  return 0;
3134  }
3135 
3136  if (nIndex < 0 || nIndex >= static_cast<sal_Int32>(m_aDataArray.size()))
3137  {
3138  SAL_WARN("sc.ui", "Passed invalid index to getNumberFormatKeyByIndex(). Will return default value '0'.");
3139  return 0;
3140  }
3141 
3142  return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, m_aDataArray.at(nIndex).mAddress));
3143 }
3144 
3145 // XCloneable ================================================================
3146 
3147 uno::Reference< util::XCloneable > SAL_CALL ScChart2DataSequence::createClone()
3148 {
3149  SolarMutexGuard aGuard;
3150 
3151  // Clone tokens.
3152  vector<ScTokenRef> aTokensNew;
3153  aTokensNew.reserve(m_aTokens.size());
3154  for (const auto& rxToken : m_aTokens)
3155  {
3156  ScTokenRef p(rxToken->Clone());
3157  aTokensNew.push_back(p);
3158  }
3159 
3161  p->CopyData(*this);
3162  uno::Reference< util::XCloneable > xClone(p.get());
3163 
3164  return xClone;
3165 }
3166 
3167 // XModifyBroadcaster ========================================================
3168 
3169 void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3170 {
3171  // like ScCellRangesBase::addModifyListener
3172  SolarMutexGuard aGuard;
3173  if (m_aTokens.empty())
3174  return;
3175 
3176  ScRangeList aRanges;
3178  m_aValueListeners.emplace_back( aListener );
3179 
3180  if ( m_aValueListeners.size() != 1 )
3181  return;
3182 
3183  if (!m_pValueListener)
3184  m_pValueListener.reset(new ScLinkListener( LINK( this, ScChart2DataSequence, ValueListenerHdl ) ));
3185 
3186  if (!m_pHiddenListener)
3187  m_pHiddenListener.reset(new HiddenRangeListener(*this));
3188 
3189  if( m_pDocument )
3190  {
3192  for (const auto& rxToken : m_aTokens)
3193  {
3194  ScRange aRange;
3195  if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
3196  continue;
3197 
3198  m_pDocument->StartListeningArea( aRange, false, m_pValueListener.get() );
3199  if (pCLC)
3200  pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
3201  }
3202  }
3203 
3204  acquire(); // don't lose this object (one ref for all listeners)
3205 }
3206 
3207 void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3208 {
3209  // like ScCellRangesBase::removeModifyListener
3210 
3211  SolarMutexGuard aGuard;
3212  if (m_aTokens.empty())
3213  return;
3214 
3215  rtl::Reference<ScChart2DataSequence> xSelfHold(this); // in case the listeners have the last ref
3216 
3217  sal_uInt16 nCount = m_aValueListeners.size();
3218  for ( sal_uInt16 n=nCount; n--; )
3219  {
3220  uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
3221  if ( rObj == aListener )
3222  {
3223  m_aValueListeners.erase( m_aValueListeners.begin() + n );
3224 
3225  if ( m_aValueListeners.empty() )
3226  {
3227  if (m_pValueListener)
3228  m_pValueListener->EndListeningAll();
3229 
3231  {
3233  if (pCLC)
3235  }
3236 
3237  release(); // release the ref for the listeners
3238  }
3239 
3240  break;
3241  }
3242  }
3243 }
3244 
3245 // DataSequence XPropertySet -------------------------------------------------
3246 
3247 uno::Reference< beans::XPropertySetInfo> SAL_CALL
3249 {
3250  SolarMutexGuard aGuard;
3251  static uno::Reference<beans::XPropertySetInfo> aRef =
3253  return aRef;
3254 }
3255 
3257  const OUString& rPropertyName, const uno::Any& rValue)
3258 {
3259  if ( rPropertyName == SC_UNONAME_ROLE )
3260  {
3261  if ( !(rValue >>= m_aRole))
3262  throw lang::IllegalArgumentException();
3263  }
3264  else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3265  {
3266  bool bOldValue = m_bIncludeHiddenCells;
3267  if ( !(rValue >>= m_bIncludeHiddenCells))
3268  throw lang::IllegalArgumentException();
3269  if( bOldValue != m_bIncludeHiddenCells )
3270  m_aDataArray.clear();//data array is dirty now
3271  }
3272  else if( rPropertyName == "TimeBased" )
3273  {
3274  bool bTimeBased = mbTimeBased;
3275  rValue>>= bTimeBased;
3276  mbTimeBased = bTimeBased;
3277  }
3278  else
3279  throw beans::UnknownPropertyException(rPropertyName);
3280  // TODO: support optional properties
3281 }
3282 
3283 uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue(const OUString& rPropertyName)
3284 {
3285  uno::Any aRet;
3286  if ( rPropertyName == SC_UNONAME_ROLE )
3287  aRet <<= m_aRole;
3288  else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3289  aRet <<= m_bIncludeHiddenCells;
3290  else if ( rPropertyName == SC_UNONAME_HIDDENVALUES )
3291  {
3292  // This property is read-only thus cannot be set externally via
3293  // setPropertyValue(...).
3294  BuildDataCache();
3295  aRet <<= m_aHiddenValues;
3296  }
3297  else if (rPropertyName == SC_UNONAME_TIME_BASED)
3298  {
3299  aRet <<= mbTimeBased;
3300  }
3301  else if (rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
3302  {
3303  // Read-only property. It returns whether or not the label value is a
3304  // direct user input, rather than an indirect reference.
3305  bool bHasStringLabel = false;
3306  if (m_aTokens.size() == 1)
3307  {
3308  const formula::FormulaToken& rToken = *m_aTokens[0];
3309  bHasStringLabel = rToken.GetType() == formula::svString;
3310  }
3311  aRet <<= bHasStringLabel;
3312  }
3313  else
3314  throw beans::UnknownPropertyException(rPropertyName);
3315  // TODO: support optional properties
3316  return aRet;
3317 }
3318 
3320  const OUString& /*rPropertyName*/,
3321  const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
3322 {
3323  // FIXME: real implementation
3324  OSL_FAIL( "Not yet implemented" );
3325 }
3326 
3328  const OUString& /*rPropertyName*/,
3329  const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
3330 {
3331  // FIXME: real implementation
3332  OSL_FAIL( "Not yet implemented" );
3333 }
3334 
3336  const OUString& /*rPropertyName*/,
3337  const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3338 {
3339  // FIXME: real implementation
3340  OSL_FAIL( "Not yet implemented" );
3341 }
3342 
3344  const OUString& /*rPropertyName*/,
3345  const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3346 {
3347  // FIXME: real implementation
3348  OSL_FAIL( "Not yet implemented" );
3349 }
3350 
3352 {
3354 }
3355 
3357 {
3358  if(!mbTimeBased)
3359  return true;
3360 
3362  {
3363  if(bWrap)
3364  setToPointInTime(0);
3365  return false;
3366  }
3367 
3368  for(const auto& rxToken : m_aTokens)
3369  {
3370  if (rxToken->GetType() != svDoubleRef)
3371  continue;
3372 
3373  ScComplexRefData& rData = *rxToken->GetDoubleRef();
3374  ScSingleRefData& s = rData.Ref1;
3375  ScSingleRefData& e = rData.Ref2;
3376 
3377  s.IncTab(1);
3378  e.IncTab(1);
3379  }
3380 
3381  ++mnCurrentTab;
3382 
3383  RebuildDataCache();
3384 
3385  return true;
3386 }
3387 
3388 void ScChart2DataSequence::setRange(sal_Int32 nStart, sal_Int32 nEnd)
3389 {
3390  mnTimeBasedStart = nStart;
3391  mnTimeBasedEnd = nEnd;
3393 }
3394 
3396 {
3397  if(nPoint > mnTimeBasedEnd - mnTimeBasedStart)
3398  return false;
3399 
3400  SCTAB nTab = mnTimeBasedStart + nPoint;
3401  for(const auto& rxToken : m_aTokens)
3402  {
3403  if (rxToken->GetType() != svDoubleRef)
3404  continue;
3405 
3406  ScComplexRefData& rData = *rxToken->GetDoubleRef();
3407  ScSingleRefData& s = rData.Ref1;
3408  ScSingleRefData& e = rData.Ref2;
3409 
3410  s.SetAbsTab(nTab);
3411  e.SetAbsTab(nTab);
3412  }
3413 
3414  mnCurrentTab = nTab;
3415 
3416  RebuildDataCache();
3417 
3418  return true;
3419 }
3420 
3421 /* 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
virtual OUString SAL_CALL convertRangeFromXML(const OUString &sXMLRange) override
Definition: chart2uno.cxx:2180
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:369
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:2643
sal_Int32 nIndex
State
OUString getString() const
bool HasUnoRefUndo() const
Definition: document.hxx:1062
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:2927
virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL detectArguments(const css::uno::Reference< css::chart2::data::XDataSource > &xDataSource) override
Definition: chart2uno.cxx:1725
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()
#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:3207
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByValueArray(const OUString &aRole, const OUString &aRangeRepresentation) override
Definition: chart2uno.cxx:2011
void getRangeListFromTokens(const ScDocument *pDoc, ScRangeList &rRangeList, const ::std::vector< ScTokenRef > &pTokens, const ScAddress &rPos)
ScChart2DataSource
Definition: chart2uno.cxx:66
SCCOL GetMaxColCount() const
Definition: sheetlimits.hxx:64
ScDocument * m_pDocument
Definition: chart2uno.hxx:184
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
Definition: chart2uno.cxx:2224
virtual ~ScChart2DataSource() override
Definition: chart2uno.cxx:2296
SC_DLLPUBLIC bool InitColumnBlockPosition(sc::ColumnBlockPosition &rBlockPos, SCTAB nTab, SCCOL nCol)
Definition: document.cxx:2609
ocOpen
sal_Int64 n
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: chart2uno.cxx:2304
#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:2232
SC_DLLPUBLIC void GetNumberFormat(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt32 &rFormat) const
Definition: document.cxx:3639
virtual void SAL_CALL addModifyListener(const css::uno::Reference< css::util::XModifyListener > &aListener) override
Definition: chart2uno.cxx:3169
ScAddress aEnd
Definition: address.hxx:501
void SetAbsRow(SCROW nVal)
Definition: refdata.cxx:76
sal_Int64 GetNewUnoId()
Definition: document.hxx:1065
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:982
std::shared_ptr< T > make_shared(Args &&...args)
void SetRowRel(bool bVal)
Definition: refdata.hxx:67
SCROW GetMaxRowCount() const
Definition: sheetlimits.hxx:62
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:2843
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:993
void StopListeningToAllExternalRefs()
Definition: chart2uno.cxx:2651
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3058
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:60
int n2
const ScRange & GetRange() const
Definition: hints.hxx:61
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:870
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:3484
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:3319
SC_DLLPUBLIC ScExternalRefManager * GetExternalRefManager() const
Definition: documen3.cxx:617
void push_back(const ScRange &rRange)
Definition: rangelst.cxx:1142
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:3093
virtual css::uno::Any SAL_CALL getPropertyValue(const OUString &rPropertyName) override
Definition: chart2uno.cxx:2243
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:3356
sal_uInt16 GetLen() const
virtual void SAL_CALL removeVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:2280
ocSep
constexpr OUStringLiteral aData
DocumentType eType
virtual void SAL_CALL setRange(sal_Int32 nStart, sal_Int32 nEnd) override
Definition: chart2uno.cxx:3388
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:869
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:4443
bool PastingDrawFromOtherDoc() const
Definition: document.hxx:2420
HiddenRangeListener(ScChart2DataSequence &rParent)
Definition: chart2uno.cxx:2332
ScChart2DataSource(ScDocument *pDoc)
Definition: chart2uno.cxx:2289
virtual void SAL_CALL addPropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &xListener) override
Definition: chart2uno.cxx:2259
int i
svl::SharedString GetString(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3073
virtual sal_Bool SAL_CALL createDataSequenceByRangeRepresentationPossible(const OUString &aRangeRepresentation) override
Definition: chart2uno.cxx:1972
void SetFlag3D(bool bVal)
Definition: refdata.hxx:90
void GetDimensions(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:2978
sal_Int16 SCCOL
Definition: types.hxx:22
SCTAB GetDz() const
Definition: hints.hxx:64
virtual void SAL_CALL removeVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:3343
void SetAbsCol(SCCOL nVal)
Definition: refdata.cxx:59
bool getDoubleRefDataFromToken(ScComplexRefData &rData, const ScTokenRef &pToken)
ScSheetLimits & GetSheetLimits() const
Definition: document.hxx:871
ScSingleRefData Ref1
Definition: refdata.hxx:125
bool IsBoolean(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3138
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: chart2uno.cxx:2697
ExternalRefListener(ScChart2DataSequence &rParent, ScDocument *pDoc)
Definition: chart2uno.cxx:2825
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:89
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:1038
virtual sal_Bool SAL_CALL setToPointInTime(sal_Int32 nPoint) override
Definition: chart2uno.cxx:3395
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:943
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:2428
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:3283
#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:3763
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:1986
SCTAB Tab() const
Definition: refdata.cxx:254
svSingleRef
FormulaError
SCCOL Col() const
Definition: address.hxx:267
void AddUnoObject(SfxListener &rObject)
Definition: documen3.cxx:892
svDoubleRef
virtual OUString SAL_CALL convertRangeToXML(const OUString &sRangeRepresentation) override
Definition: chart2uno.cxx:2156
CellType meType
Definition: cellvalue.hxx:106
sal_Int32 SCROW
Definition: types.hxx:18
SC_DLLPUBLIC void PutInOrder()
Definition: address.cxx:1582
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:3114
void setDataChangedHint(bool b)
Definition: chart2uno.cxx:3351
void CopyData(const ScChart2DataSequence &r)
Definition: chart2uno.cxx:2664
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:1325
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:3335
std::shared_ptr< ScTokenArray > TokenArrayRef
std::shared_ptr< Table > TableTypeRef
virtual css::uno::Reference< css::sheet::XRangeSelection > SAL_CALL getRangeSelection() override
Definition: chart2uno.cxx:2017
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:900
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:3327
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:2140
Sequence< sal_Int8 > aSeq
virtual css::uno::Sequence< double > SAL_CALL getNumericalData() override
Definition: chart2uno.cxx:2902
double getValue()
Definition: cellvalue.cxx:632
FILE * init(int, char **)
void UpdateTokensFromRanges(const ScRangeList &rRanges)
Definition: chart2uno.cxx:2621
SC_DLLPUBLIC bool RowHidden(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4427
Complex reference (a range) into the sheet.
Definition: refdata.hxx:123
SCCOL GetDx() const
Definition: hints.hxx:62
IMPL_LINK(ScChart2DataSequence, ValueListenerHdl, const SfxHint &, rHint, void)
Definition: chart2uno.cxx:2813
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:971
virtual css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > SAL_CALL getDataSequences() override
Definition: chart2uno.cxx:2313
virtual void SAL_CALL addVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:2273
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByFormulaTokens(const css::uno::Sequence< css::sheet::FormulaToken > &aTokens) override
Definition: chart2uno.cxx:2085
virtual OUString SAL_CALL getSourceRangeRepresentation() override
Definition: chart2uno.cxx:2959
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:1055
#define SAL_WARN(area, stream)
bool IsValue(SCSIZE nIndex) const
Definition: scmatrix.cxx:3123
Reference< XModel > xModel
virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override
Definition: chart2uno.cxx:3147
Degree100 abs(Degree100 x)
void StartListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: documen7.cxx:34
virtual void SAL_CALL removePropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &rListener) override
Definition: chart2uno.cxx:2266
sal_Int32 FillCacheFromExternalRef(const ScTokenRef &pToken)
Definition: chart2uno.cxx:2537
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:2379
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:2865
StackVar GetType() const
void AddLabeledSequence(const css::uno::Reference< css::chart2::data::XLabeledDataSequence > &xNew)
Definition: chart2uno.cxx:2319
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:3256
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:2028
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:3248
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:63
virtual css::uno::Sequence< OUString > SAL_CALL generateLabel(css::chart2::data::LabelOrigin nOrigin) override
Definition: chart2uno.cxx:3066
virtual css::uno::Reference< css::chart2::data::XDataSource > SAL_CALL createDataSource(const css::uno::Sequence< css::beans::PropertyValue > &aArguments) override
Definition: chart2uno.cxx:1385