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