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  // This is expensive to compute and we get called more than once, so cache
1407  if (maCreateDataSourceArguments == aArguments)
1408  return mxCreatedDataSource;
1409  maCreateDataSourceArguments = aArguments;
1410 
1411  bool bLabel = true;
1412  bool bCategories = false;
1413  bool bOrientCol = true;
1414  OUString aRangeRepresentation;
1415  uno::Sequence< sal_Int32 > aSequenceMapping;
1416  bool bTimeBased = false;
1417  for(const auto& rArgument : aArguments)
1418  {
1419  if ( rArgument.Name == "DataRowSource" )
1420  {
1421  chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
1422  if( ! (rArgument.Value >>= eSource))
1423  {
1424  sal_Int32 nSource(0);
1425  if( rArgument.Value >>= nSource )
1426  eSource = static_cast< chart::ChartDataRowSource >( nSource );
1427  }
1428  bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
1429  }
1430  else if ( rArgument.Name == "FirstCellAsLabel" )
1431  {
1432  bLabel = ::cppu::any2bool(rArgument.Value);
1433  }
1434  else if ( rArgument.Name == "HasCategories" )
1435  {
1436  bCategories = ::cppu::any2bool(rArgument.Value);
1437  }
1438  else if ( rArgument.Name == "CellRangeRepresentation" )
1439  {
1440  rArgument.Value >>= aRangeRepresentation;
1441  }
1442  else if ( rArgument.Name == "SequenceMapping" )
1443  {
1444  rArgument.Value >>= aSequenceMapping;
1445  }
1446  else if ( rArgument.Name == "TimeBased" )
1447  {
1448  rArgument.Value >>= bTimeBased;
1449  }
1450  }
1451 
1452  vector<ScTokenRef> aRefTokens;
1455  aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1456  if (aRefTokens.empty())
1457  // Invalid range representation. Bail out.
1458  throw lang::IllegalArgumentException();
1459 
1460  SCTAB nTimeBasedStart = MAXTAB;
1461  SCTAB nTimeBasedEnd = 0;
1462  if(bTimeBased)
1463  {
1464  // limit to first sheet
1465  for(const auto& rxToken : aRefTokens)
1466  {
1467  if (rxToken->GetType() != svDoubleRef)
1468  continue;
1469 
1470  ScComplexRefData& rData = *rxToken->GetDoubleRef();
1471  ScSingleRefData& s = rData.Ref1;
1472  ScSingleRefData& e = rData.Ref2;
1473 
1474  nTimeBasedStart = std::min(nTimeBasedStart, s.Tab());
1475  nTimeBasedEnd = std::min(nTimeBasedEnd, e.Tab());
1476 
1477  if(s.Tab() != e.Tab())
1478  e.SetAbsTab(s.Tab());
1479  }
1480  }
1481 
1482  if(!bTimeBased)
1483  shrinkToDataRange(m_pDocument, aRefTokens);
1484 
1485  if (bLabel)
1486  lcl_addUpperLeftCornerIfMissing(m_pDocument, aRefTokens, 1, 1); //#i90669#
1487 
1488  bool bColHeaders = (bOrientCol ? bLabel : bCategories );
1489  bool bRowHeaders = (bOrientCol ? bCategories : bLabel );
1490 
1491  Chart2Positioner aChPositioner(m_pDocument, aRefTokens);
1492  aChPositioner.setHeaders(bColHeaders, bRowHeaders);
1493 
1494  const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap();
1495  if (!pChartMap)
1496  // No chart position map instance. Bail out.
1497  return mxCreatedDataSource;
1498 
1500  ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqs;
1501 
1502  // Fill Categories
1503  if( bCategories )
1504  {
1505  vector<ScTokenRef> aValueTokens;
1506  if (bOrientCol)
1507  aValueTokens = pChartMap->getAllRowHeaderRanges();
1508  else
1509  aValueTokens = pChartMap->getAllColHeaderRanges();
1510 
1511  vector<ScTokenRef> aLabelTokens(
1512  pChartMap->getLeftUpperCornerRanges());
1513 
1514  uno::Reference< chart2::data::XLabeledDataSequence > xCategories = lcl_createLabeledDataSequenceFromTokens(
1515  std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1516  if ( xCategories.is() )
1517  {
1518  aSeqs.push_back( xCategories );
1519  }
1520  }
1521 
1522  // Fill Series (values and label)
1523  sal_Int32 nCount = bOrientCol ? pChartMap->getDataColCount() : pChartMap->getDataRowCount();
1524  for (sal_Int32 i = 0; i < nCount; ++i)
1525  {
1526  vector<ScTokenRef> aValueTokens;
1527  vector<ScTokenRef> aLabelTokens;
1528  if (bOrientCol)
1529  {
1530  aValueTokens = pChartMap->getDataColRanges(static_cast<SCCOL>(i));
1531  aLabelTokens = pChartMap->getColHeaderRanges(static_cast<SCCOL>(i));
1532  }
1533  else
1534  {
1535  aValueTokens = pChartMap->getDataRowRanges(static_cast<SCROW>(i));
1536  aLabelTokens = pChartMap->getRowHeaderRanges(static_cast<SCROW>(i));
1537  }
1538  uno::Reference< chart2::data::XLabeledDataSequence > xChartSeries = lcl_createLabeledDataSequenceFromTokens(
1539  std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1540  if ( xChartSeries.is() && xChartSeries->getValues().is() && xChartSeries->getValues()->getData().hasElements() )
1541  {
1542  aSeqs.push_back( xChartSeries );
1543  }
1544  }
1545 
1546  pDS = new ScChart2DataSource(m_pDocument);
1547 
1548  //reorder labeled sequences according to aSequenceMapping
1549  ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqVector;
1550  aSeqVector.reserve(aSeqs.size());
1551  for (auto const& aSeq : aSeqs)
1552  {
1553  aSeqVector.push_back(aSeq);
1554  }
1555 
1556  for( const sal_Int32 nNewIndex : std::as_const(aSequenceMapping) )
1557  {
1558  // note: assuming that the values in the sequence mapping are always non-negative
1559  ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > >::size_type nOldIndex( static_cast< sal_uInt32 >( nNewIndex ) );
1560  if( nOldIndex < aSeqVector.size() )
1561  {
1562  pDS->AddLabeledSequence( aSeqVector[nOldIndex] );
1563  aSeqVector[nOldIndex] = nullptr;
1564  }
1565  }
1566 
1567  for(const uno::Reference< chart2::data::XLabeledDataSequence >& xSeq : aSeqVector)
1568  {
1569  if ( xSeq.is() )
1570  {
1571  pDS->AddLabeledSequence( xSeq );
1572  }
1573  }
1574 
1575  mxCreatedDataSource.set(pDS);
1576  return mxCreatedDataSource;
1577 }
1578 
1579 namespace
1580 {
1581 
1585 class InsertTabNumber
1586 {
1587 public:
1588  InsertTabNumber() :
1589  mpTabNumVector(std::make_shared<vector<SCTAB>>())
1590  {
1591  }
1592 
1593  void operator() (const ScTokenRef& pToken) const
1594  {
1595  if (!ScRefTokenHelper::isRef(pToken))
1596  return;
1597 
1598  const ScSingleRefData& r = *pToken->GetSingleRef();
1599  mpTabNumVector->push_back(r.Tab());
1600  }
1601 
1602  void getVector(vector<SCTAB>& rVector)
1603  {
1604  mpTabNumVector->swap(rVector);
1605  }
1606 private:
1607  shared_ptr< vector<SCTAB> > mpTabNumVector;
1608 };
1609 
1610 class RangeAnalyzer
1611 {
1612 public:
1613  RangeAnalyzer();
1614  void initRangeAnalyzer( const ScDocument* pDoc, const vector<ScTokenRef>& rTokens );
1615  void analyzeRange( sal_Int32& rnDataInRows, sal_Int32& rnDataInCols,
1616  bool& rbRowSourceAmbiguous ) const;
1617  bool inSameSingleRow( const RangeAnalyzer& rOther );
1618  bool inSameSingleColumn( const RangeAnalyzer& rOther );
1619  SCROW getRowCount() const { return mnRowCount; }
1620  SCCOL getColumnCount() const { return mnColumnCount; }
1621 
1622 private:
1623  bool mbEmpty;
1624  bool mbAmbiguous;
1625  SCROW mnRowCount;
1626  SCCOL mnColumnCount;
1627 
1628  SCCOL mnStartColumn;
1629  SCROW mnStartRow;
1630 };
1631 
1632 RangeAnalyzer::RangeAnalyzer()
1633  : mbEmpty(true)
1634  , mbAmbiguous(false)
1635  , mnRowCount(0)
1636  , mnColumnCount(0)
1637  , mnStartColumn(-1)
1638  , mnStartRow(-1)
1639 {
1640 }
1641 
1642 void RangeAnalyzer::initRangeAnalyzer( const ScDocument* pDoc, const vector<ScTokenRef>& rTokens )
1643 {
1644  mnRowCount=0;
1645  mnColumnCount=0;
1646  mnStartColumn = -1;
1647  mnStartRow = -1;
1648  mbAmbiguous=false;
1649  if( rTokens.empty() )
1650  {
1651  mbEmpty=true;
1652  return;
1653  }
1654  mbEmpty=false;
1655 
1656  for (const ScTokenRef& aRefToken : rTokens)
1657  {
1658  StackVar eVar = aRefToken->GetType();
1659  if (eVar == svDoubleRef || eVar == svExternalDoubleRef)
1660  {
1661  const ScComplexRefData& r = *aRefToken->GetDoubleRef();
1662  if (r.Ref1.Tab() == r.Ref2.Tab())
1663  {
1664  mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(r.Ref2.Col() - r.Ref1.Col())+1));
1665  mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(r.Ref2.Row() - r.Ref1.Row())+1));
1666  if( mnStartColumn == -1 )
1667  {
1668  mnStartColumn = r.Ref1.Col();
1669  mnStartRow = r.Ref1.Row();
1670  }
1671  else
1672  {
1673  if (mnStartColumn != r.Ref1.Col() && mnStartRow != r.Ref1.Row())
1674  mbAmbiguous=true;
1675  }
1676  }
1677  else
1678  mbAmbiguous=true;
1679  }
1680  else if (eVar == svSingleRef || eVar == svExternalSingleRef)
1681  {
1682  const ScSingleRefData& r = *aRefToken->GetSingleRef();
1683  mnColumnCount = std::max<SCCOL>( mnColumnCount, 1);
1684  mnRowCount = std::max<SCROW>( mnRowCount, 1);
1685  if( mnStartColumn == -1 )
1686  {
1687  mnStartColumn = r.Col();
1688  mnStartRow = r.Row();
1689  }
1690  else
1691  {
1692  if (mnStartColumn != r.Col() && mnStartRow != r.Row())
1693  mbAmbiguous=true;
1694  }
1695  }
1696  else if (eVar == svIndex && aRefToken->GetOpCode() == ocName)
1697  {
1698  ScRangeData* pNameRange = pDoc->FindRangeNameBySheetAndIndex(aRefToken->GetSheet(), aRefToken->GetIndex());
1699  ScRange aRange;
1700  if (pNameRange->IsReference(aRange))
1701  {
1702  mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(aRange.aEnd.Col() - aRange.aStart.Col()) + 1));
1703  mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(aRange.aEnd.Row() - aRange.aStart.Row()) + 1));
1704  if (mnStartColumn == -1)
1705  {
1706  mnStartColumn = aRange.aStart.Col();
1707  mnStartRow = aRange.aStart.Row();
1708  }
1709  else
1710  {
1711  if (mnStartColumn != aRange.aStart.Col() && mnStartRow != aRange.aStart.Row())
1712  mbAmbiguous = true;
1713  }
1714  }
1715  else
1716  mbAmbiguous = true;
1717  }
1718  else
1719  mbAmbiguous=true;
1720  }
1721 }
1722 
1723 void RangeAnalyzer::analyzeRange( sal_Int32& rnDataInRows,
1724  sal_Int32& rnDataInCols,
1725  bool& rbRowSourceAmbiguous ) const
1726 {
1727  if(!mbEmpty && !mbAmbiguous)
1728  {
1729  if( mnRowCount==1 && mnColumnCount>1 )
1730  ++rnDataInRows;
1731  else if( mnColumnCount==1 && mnRowCount>1 )
1732  ++rnDataInCols;
1733  else if( mnRowCount>1 && mnColumnCount>1 )
1734  rbRowSourceAmbiguous = true;
1735  }
1736  else if( !mbEmpty )
1737  rbRowSourceAmbiguous = true;
1738 }
1739 
1740 bool RangeAnalyzer::inSameSingleRow( const RangeAnalyzer& rOther )
1741 {
1742  return mnStartRow==rOther.mnStartRow &&
1743  mnRowCount==1 && rOther.mnRowCount==1;
1744 }
1745 
1746 bool RangeAnalyzer::inSameSingleColumn( const RangeAnalyzer& rOther )
1747 {
1748  return mnStartColumn==rOther.mnStartColumn &&
1749  mnColumnCount==1 && rOther.mnColumnCount==1;
1750 }
1751 
1752 std::pair<OUString, OUString> constructKey(const uno::Reference< chart2::data::XLabeledDataSequence>& xNew)
1753 {
1754  std::pair<OUString, OUString> aKey;
1755  if( xNew->getLabel().is() )
1756  aKey.first = xNew->getLabel()->getSourceRangeRepresentation();
1757  if( xNew->getValues().is() )
1758  aKey.second = xNew->getValues()->getSourceRangeRepresentation();
1759  return aKey;
1760 }
1761 
1762 
1763 } //end anonymous namespace
1764 
1765 uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments(
1766  const uno::Reference< chart2::data::XDataSource >& xDataSource )
1767 {
1768  // Cache these because this is expensive to compute and we get called more than once
1769  if (xDataSource == mxCachedDataSource)
1770  return maCachedArguments;
1771 
1772  ::std::vector< beans::PropertyValue > aResult;
1773  bool bRowSourceDetected = false;
1774  bool bFirstCellAsLabel = false;
1775  bool bHasCategories = false;
1776  OUString sRangeRep;
1777 
1778  bool bHasCategoriesLabels = false;
1779  vector<ScTokenRef> aAllCategoriesValuesTokens;
1780  vector<ScTokenRef> aAllSeriesLabelTokens;
1781 
1782  chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS;
1783 
1784  vector<ScTokenRef> aAllTokens;
1785 
1786  // parse given data source and collect infos
1787  {
1788  SolarMutexGuard aGuard;
1789  OSL_ENSURE( m_pDocument, "No Document -> no detectArguments" );
1790  if(!m_pDocument ||!xDataSource.is())
1791  return comphelper::containerToSequence( aResult );
1792 
1793  sal_Int32 nDataInRows = 0;
1794  sal_Int32 nDataInCols = 0;
1795  bool bRowSourceAmbiguous = false;
1796 
1797  const Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences());
1798  const sal_Int32 nCount( aSequences.getLength());
1799  RangeAnalyzer aPrevLabel,aPrevValues;
1800  for( const uno::Reference< chart2::data::XLabeledDataSequence >& xLS : aSequences )
1801  {
1802  if( xLS.is() )
1803  {
1804  bool bThisIsCategories = false;
1805  if(!bHasCategories)
1806  {
1807  uno::Reference< beans::XPropertySet > xSeqProp( xLS->getValues(), uno::UNO_QUERY );
1808  OUString aRole;
1809  if( xSeqProp.is() && (xSeqProp->getPropertyValue("Role") >>= aRole) &&
1810  aRole == "categories" )
1811  bThisIsCategories = bHasCategories = true;
1812  }
1813 
1814  RangeAnalyzer aLabel,aValues;
1815  // label
1816  uno::Reference< chart2::data::XDataSequence > xLabel( xLS->getLabel());
1817  if( xLabel.is())
1818  {
1819  bFirstCellAsLabel = true;
1820  vector<ScTokenRef> aTokens;
1823  aTokens, xLabel->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1824  aLabel.initRangeAnalyzer(m_pDocument, aTokens);
1825  for (const auto& rxToken : aTokens)
1826  {
1827  if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
1828  {
1829  ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
1830  if (pNameRange->HasReferences())
1831  {
1832  const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
1833  ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
1834  }
1835  else
1836  ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1837  }
1838  else
1839  ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1840  if(!bThisIsCategories)
1841  ScRefTokenHelper::join(m_pDocument, aAllSeriesLabelTokens, rxToken, ScAddress());
1842  }
1843  if(bThisIsCategories)
1844  bHasCategoriesLabels=true;
1845  }
1846  // values
1847  uno::Reference< chart2::data::XDataSequence > xValues( xLS->getValues());
1848  if( xValues.is())
1849  {
1850  vector<ScTokenRef> aTokens;
1853  aTokens, xValues->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1854  aValues.initRangeAnalyzer(m_pDocument, aTokens);
1855  for (const auto& rxToken : aTokens)
1856  {
1857  if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
1858  {
1859  ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
1860  if (pNameRange->HasReferences())
1861  {
1862  const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
1863  ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
1864  }
1865  else
1866  ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1867  }
1868  else
1869  ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
1870  if(bThisIsCategories)
1871  ScRefTokenHelper::join(m_pDocument, aAllCategoriesValuesTokens, rxToken, ScAddress());
1872  }
1873  }
1874  //detect row source
1875  if(!bThisIsCategories || nCount==1) //categories might span multiple rows *and* columns, so they should be used for detection only if nothing else is available
1876  {
1877  if (!bRowSourceAmbiguous)
1878  {
1879  aValues.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1880  aLabel.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1881  if (nDataInRows > 1 && nDataInCols > 1)
1882  bRowSourceAmbiguous = true;
1883  else if( !bRowSourceAmbiguous && !nDataInRows && !nDataInCols )
1884  {
1885  if( aValues.inSameSingleColumn( aLabel ) )
1886  nDataInCols++;
1887  else if( aValues.inSameSingleRow( aLabel ) )
1888  nDataInRows++;
1889  else
1890  {
1891  //#i86188# also detect a single column split into rows correctly
1892  if( aValues.inSameSingleColumn( aPrevValues ) )
1893  nDataInRows++;
1894  else if( aValues.inSameSingleRow( aPrevValues ) )
1895  nDataInCols++;
1896  else if( aLabel.inSameSingleColumn( aPrevLabel ) )
1897  nDataInRows++;
1898  else if( aLabel.inSameSingleRow( aPrevLabel ) )
1899  nDataInCols++;
1900  }
1901  }
1902  }
1903  }
1904  aPrevValues=aValues;
1905  aPrevLabel=aLabel;
1906  }
1907  }
1908 
1909  if (!bRowSourceAmbiguous)
1910  {
1911  bRowSourceDetected = true;
1912  eRowSource = ( nDataInCols > 0
1913  ? chart::ChartDataRowSource_COLUMNS
1914  : chart::ChartDataRowSource_ROWS );
1915  }
1916  else
1917  {
1918  // set DataRowSource to the better of the two ambiguities
1919  eRowSource = ( nDataInRows > nDataInCols
1920  ? chart::ChartDataRowSource_ROWS
1921  : chart::ChartDataRowSource_COLUMNS );
1922  }
1923 
1924  }
1925 
1926  // TableNumberList
1927  {
1928  vector<SCTAB> aTableNumVector;
1929  InsertTabNumber func;
1930  func = ::std::for_each(aAllTokens.begin(), aAllTokens.end(), func);
1931  func.getVector(aTableNumVector);
1932  aResult.emplace_back( "TableNumberList", -1,
1933  uno::Any( lcl_createTableNumberList( aTableNumVector ) ),
1934  beans::PropertyState_DIRECT_VALUE );
1935  }
1936 
1937  if( bRowSourceDetected )
1938  {
1939  // DataRowSource (calculated before)
1940  aResult.emplace_back( "DataRowSource", -1,
1941  uno::Any( eRowSource ), beans::PropertyState_DIRECT_VALUE );
1942  // HasCategories
1943  aResult.emplace_back( "HasCategories", -1,
1944  uno::Any( bHasCategories ), beans::PropertyState_DIRECT_VALUE );
1945  // FirstCellAsLabel
1946  aResult.emplace_back( "FirstCellAsLabel", -1,
1947  uno::Any( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE );
1948  }
1949 
1950  // Add the left upper corner to the range if it is missing.
1951  if (bRowSourceDetected && bFirstCellAsLabel && bHasCategories && !bHasCategoriesLabels )
1952  {
1953  RangeAnalyzer aTop,aLeft;
1954  if( eRowSource==chart::ChartDataRowSource_COLUMNS )
1955  {
1956  aTop.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
1957  aLeft.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
1958  }
1959  else
1960  {
1961  aTop.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
1962  aLeft.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
1963  }
1964  lcl_addUpperLeftCornerIfMissing(m_pDocument, aAllTokens, aTop.getRowCount(), aLeft.getColumnCount());//e.g. #i91212#
1965  }
1966 
1967  // Get range string.
1968  lcl_convertTokensToString(sRangeRep, aAllTokens, *m_pDocument);
1969 
1970  // add cell range property
1971  aResult.emplace_back( "CellRangeRepresentation", -1,
1972  uno::Any( sRangeRep ), beans::PropertyState_DIRECT_VALUE );
1973 
1974  //Sequence Mapping
1975  bool const bSequencesReordered = true;//todo detect this above or detect this sequence mapping cheaper ...
1976  if( bSequencesReordered && bRowSourceDetected )
1977  {
1978  bool bDifferentIndexes = false;
1979 
1980  std::vector< sal_Int32 > aSequenceMappingVector;
1981 
1982  uno::Reference< chart2::data::XDataSource > xCompareDataSource;
1983  try
1984  {
1985  xCompareDataSource.set( createDataSource( comphelper::containerToSequence( aResult ) ) );
1986  }
1987  catch( const lang::IllegalArgumentException & )
1988  {
1989  // creation of data source to compare didn't work, so we cannot
1990  // create a sequence mapping
1991  }
1992 
1993  if( xDataSource.is() && xCompareDataSource.is() )
1994  {
1995  const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aOldSequences =
1996  xCompareDataSource->getDataSequences();
1997  const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aNewSequences =
1998  xDataSource->getDataSequences();
1999 
2000  std::map<std::pair<OUString, OUString>,sal_Int32> aOldEntryToIndex;
2001  for( sal_Int32 nIndex = 0, n = aOldSequences.getLength(); nIndex < n; nIndex++ )
2002  {
2003  const uno::Reference< chart2::data::XLabeledDataSequence>& xOld( aOldSequences[nIndex] );
2004  if( xOld.is() )
2005  {
2006  std::pair<OUString, OUString> aKey = constructKey(xOld);
2007  aOldEntryToIndex[aKey] = nIndex;
2008  }
2009  }
2010 
2011  for( sal_Int32 nNewIndex = 0, n = aNewSequences.getLength(); nNewIndex < n; nNewIndex++ )
2012  {
2013  const uno::Reference< chart2::data::XLabeledDataSequence>& xNew( aNewSequences[nNewIndex] );
2014  if( !xNew.is() )
2015  continue;
2016 
2017  std::pair<OUString, OUString> aKey = constructKey(xNew);
2018  if (aOldEntryToIndex.find(aKey) == aOldEntryToIndex.end())
2019  continue;
2020 
2021  sal_Int32 nOldIndex = aOldEntryToIndex[aKey];
2022  if( nOldIndex != nNewIndex )
2023  bDifferentIndexes = true;
2024 
2025  aSequenceMappingVector.push_back(nOldIndex);
2026  }
2027  }
2028 
2029  if( bDifferentIndexes && !aSequenceMappingVector.empty() )
2030  {
2031  aResult.emplace_back( "SequenceMapping", -1,
2032  uno::Any( comphelper::containerToSequence(aSequenceMappingVector) )
2033  , beans::PropertyState_DIRECT_VALUE );
2034  }
2035  }
2036 
2037  mxCachedDataSource = xDataSource;
2039 
2040  return maCachedArguments;
2041 }
2042 
2044 {
2045  SolarMutexGuard aGuard;
2046  if( ! m_pDocument )
2047  return false;
2048 
2049  vector<ScTokenRef> aTokens;
2052  aTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2053  return !aTokens.empty();
2054 }
2055 
2056 uno::Reference< chart2::data::XDataSequence > SAL_CALL
2058  const OUString& aRangeRepresentation )
2059 {
2060  SolarMutexGuard aGuard;
2061  uno::Reference< chart2::data::XDataSequence > xResult;
2062 
2063  OSL_ENSURE( m_pDocument, "No Document -> no createDataSequenceByRangeRepresentation" );
2064  if(!m_pDocument || aRangeRepresentation.isEmpty())
2065  return xResult;
2066 
2067  vector<ScTokenRef> aRefTokens;
2070  aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2071  if (aRefTokens.empty())
2072  return xResult;
2073 
2074  shrinkToDataRange(m_pDocument, aRefTokens);
2075 
2076  xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
2077 
2078  return xResult;
2079 }
2080 
2081 uno::Reference<chart2::data::XDataSequence> SAL_CALL
2083  const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/,
2084  const OUString& /*aRoleQualifier*/ )
2085 {
2086  return uno::Reference<chart2::data::XDataSequence>();
2087 }
2088 
2089 uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRangeSelection()
2090 {
2091  uno::Reference< sheet::XRangeSelection > xResult;
2092 
2093  uno::Reference< frame::XModel > xModel( lcl_GetXModel( m_pDocument ));
2094  if( xModel.is())
2095  xResult.set( xModel->getCurrentController(), uno::UNO_QUERY );
2096 
2097  return xResult;
2098 }
2099 
2101  const Sequence<sheet::FormulaToken>& aTokens )
2102 {
2103  if (!aTokens.hasElements())
2104  return false;
2105 
2106  ScTokenArray aCode(*m_pDocument);
2107  if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
2108  return false;
2109 
2110  sal_uInt16 n = aCode.GetLen();
2111  if (!n)
2112  return false;
2113 
2115  const formula::FormulaToken* pFirst = aIter.First();
2116  const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2117  for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
2118  {
2119  switch (p->GetType())
2120  {
2121  case svSep:
2122  {
2123  switch (p->GetOpCode())
2124  {
2125  case ocSep:
2126  // separators are allowed.
2127  break;
2128  case ocOpen:
2129  if (p != pFirst)
2130  // open paran is allowed only as the first token.
2131  return false;
2132  break;
2133  case ocClose:
2134  if (p != pLast)
2135  // close paren is allowed only as the last token.
2136  return false;
2137  break;
2138  default:
2139  return false;
2140  }
2141  }
2142  break;
2143  case svSingleRef:
2144  case svDoubleRef:
2145  case svExternalSingleRef:
2146  case svExternalDoubleRef:
2147  break;
2148  default:
2149  return false;
2150  }
2151  }
2152 
2153  return true;
2154 }
2155 
2156 uno::Reference<chart2::data::XDataSequence> SAL_CALL
2158  const Sequence<sheet::FormulaToken>& aTokens )
2159 {
2160  uno::Reference<chart2::data::XDataSequence> xResult;
2161  if (!aTokens.hasElements())
2162  return xResult;
2163 
2164  ScTokenArray aCode(*m_pDocument);
2165  if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
2166  return xResult;
2167 
2168  sal_uInt16 n = aCode.GetLen();
2169  if (!n)
2170  return xResult;
2171 
2172  vector<ScTokenRef> aRefTokens;
2174  const formula::FormulaToken* pFirst = aIter.First();
2175  const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2176  for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
2177  {
2178  switch (p->GetType())
2179  {
2180  case svSep:
2181  {
2182  switch (p->GetOpCode())
2183  {
2184  case ocSep:
2185  // separators are allowed.
2186  break;
2187  case ocOpen:
2188  if (p != pFirst)
2189  // open paran is allowed only as the first token.
2190  throw lang::IllegalArgumentException();
2191  break;
2192  case ocClose:
2193  if (p != pLast)
2194  // close paren is allowed only as the last token.
2195  throw lang::IllegalArgumentException();
2196  break;
2197  default:
2198  throw lang::IllegalArgumentException();
2199  }
2200  }
2201  break;
2202  case svIndex:
2203  case svString:
2204  case svSingleRef:
2205  case svDoubleRef:
2206  case svExternalSingleRef:
2207  case svExternalDoubleRef:
2208  {
2209  ScTokenRef pNew(p->Clone());
2210  aRefTokens.push_back(pNew);
2211  }
2212  break;
2213  default:
2214  throw lang::IllegalArgumentException();
2215  }
2216  }
2217 
2218  if (aRefTokens.empty())
2219  return xResult;
2220 
2221  shrinkToDataRange(m_pDocument, aRefTokens);
2222 
2223  xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
2224  return xResult;
2225 }
2226 
2227 // XRangeXMLConversion ---------------------------------------------------
2228 
2229 OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const OUString& sRangeRepresentation )
2230 {
2231  OUString aRet;
2232  if (!m_pDocument)
2233  return aRet;
2234 
2235  if (sRangeRepresentation.isEmpty())
2236  // Empty data range is allowed.
2237  return aRet;
2238 
2239  vector<ScTokenRef> aRefTokens;
2242  aRefTokens, sRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2243  if (aRefTokens.empty())
2244  throw lang::IllegalArgumentException();
2245 
2246  Tokens2RangeStringXML converter(*m_pDocument);
2247  converter = ::std::for_each(aRefTokens.begin(), aRefTokens.end(), converter);
2248  converter.getString(aRet);
2249 
2250  return aRet;
2251 }
2252 
2253 OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const OUString& sXMLRange )
2254 {
2255  if (!m_pDocument)
2256  {
2257  // #i74062# When loading flat XML, this is called before the referenced sheets are in the document,
2258  // so the conversion has to take place directly with the strings, without looking up the sheets.
2259 
2260  OUStringBuffer sRet;
2261  sal_Int32 nOffset = 0;
2262  while( nOffset >= 0 )
2263  {
2264  OUString sToken;
2265  ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset );
2266  if( nOffset >= 0 )
2267  {
2268  // convert one address (remove dots)
2269 
2270  OUString aUIString(sToken);
2271 
2272  sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0 );
2273  if ( nIndex >= 0 && nIndex < aUIString.getLength() - 1 &&
2274  aUIString[nIndex + 1] == '.' )
2275  aUIString = aUIString.replaceAt( nIndex + 1, 1, u"" );
2276 
2277  if ( aUIString[0] == '.' )
2278  aUIString = aUIString.copy( 1 );
2279 
2280  if( !sRet.isEmpty() )
2281  sRet.append( ';' );
2282  sRet.append( aUIString );
2283  }
2284  }
2285 
2286  return sRet.makeStringAndClear();
2287  }
2288 
2289  OUString aRet;
2291  return aRet;
2292 }
2293 
2294 // DataProvider XPropertySet -------------------------------------------------
2295 
2296 uno::Reference< beans::XPropertySetInfo> SAL_CALL
2298 {
2299  SolarMutexGuard aGuard;
2300  static uno::Reference<beans::XPropertySetInfo> aRef =
2302  return aRef;
2303 }
2304 
2306  const OUString& rPropertyName, const uno::Any& rValue)
2307 {
2308  if ( rPropertyName != SC_UNONAME_INCLUDEHIDDENCELLS )
2309  throw beans::UnknownPropertyException(rPropertyName);
2310 
2311  if ( !(rValue >>= m_bIncludeHiddenCells))
2312  throw lang::IllegalArgumentException();
2313 
2314 }
2315 
2317  const OUString& rPropertyName)
2318 {
2319  uno::Any aRet;
2320  if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2321  aRet <<= m_bIncludeHiddenCells;
2322  else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
2323  {
2324  // This is a read-only property.
2326  }
2327  else
2328  throw beans::UnknownPropertyException(rPropertyName);
2329  return aRet;
2330 }
2331 
2333  const OUString& /*rPropertyName*/,
2334  const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
2335 {
2336  OSL_FAIL( "Not yet implemented" );
2337 }
2338 
2340  const OUString& /*rPropertyName*/,
2341  const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
2342 {
2343  OSL_FAIL( "Not yet implemented" );
2344 }
2345 
2347  const OUString& /*rPropertyName*/,
2348  const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
2349 {
2350  OSL_FAIL( "Not yet implemented" );
2351 }
2352 
2354  const OUString& /*rPropertyName*/,
2355  const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/ )
2356 {
2357  OSL_FAIL( "Not yet implemented" );
2358 }
2359 
2360 // DataSource ================================================================
2361 
2363  : m_pDocument( pDoc)
2364 {
2365  if ( m_pDocument )
2366  m_pDocument->AddUnoObject( *this);
2367 }
2368 
2370 {
2371  SolarMutexGuard g;
2372 
2373  if ( m_pDocument )
2374  m_pDocument->RemoveUnoObject( *this);
2375 }
2376 
2378 {
2379  if ( rHint.GetId() == SfxHintId::Dying )
2380  {
2381  m_pDocument = nullptr;
2382  }
2383 }
2384 
2385 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > SAL_CALL
2387 {
2388  SolarMutexGuard aGuard;
2390 }
2391 
2392 void ScChart2DataSource::AddLabeledSequence(const uno::Reference < chart2::data::XLabeledDataSequence >& xNew)
2393 {
2394  m_aLabeledSequences.push_back(xNew);
2395 }
2396 
2397 // DataSequence ==============================================================
2398 
2400  : mfValue(std::numeric_limits<double>::quiet_NaN())
2401  , mbIsValue(false)
2402 {
2403 }
2404 
2406  mrParent(rParent)
2407 {
2408 }
2409 
2411 {
2412 }
2413 
2415 {
2416  mrParent.setDataChangedHint(true);
2417 }
2418 
2420  vector<ScTokenRef>&& rTokens,
2421  bool bIncludeHiddenCells )
2422  : m_bIncludeHiddenCells( bIncludeHiddenCells)
2423  , m_nObjectId( 0 )
2424  , m_pDocument( pDoc)
2425  , m_aTokens(std::move(rTokens))
2429  , mbTimeBased(false)
2430  , mnTimeBasedStart(0)
2431  , mnTimeBasedEnd(0)
2432  , mnCurrentTab(0)
2433 {
2434  if ( m_pDocument )
2435  {
2436  m_pDocument->AddUnoObject( *this);
2438  }
2439  // FIXME: real implementation of identifier and it's mapping to ranges.
2440  // Reuse ScChartListener?
2441 
2442  // BM: don't use names of named ranges but the UI range strings
2443 // String aStr;
2444 // rRangeList->Format( aStr, ScRefFlags::RANGE_ABS_3D, m_pDocument );
2445 // m_aIdentifier = aStr;
2446 
2447 // m_aIdentifier = "ID_";
2448 // static sal_Int32 nID = 0;
2449 // m_aIdentifier += OUString::valueOf( ++nID);
2450 }
2451 
2453 {
2454  SolarMutexGuard g;
2455 
2456  if ( m_pDocument )
2457  {
2458  m_pDocument->RemoveUnoObject( *this);
2459  if (m_pHiddenListener)
2460  {
2462  if (pCLC)
2464  }
2466  }
2467 
2468  m_pValueListener.reset();
2469 }
2470 
2472 {
2473  if( !m_pValueListener || m_aValueListeners.empty() )
2474  return;
2475 
2476  m_pValueListener->EndListeningAll();
2477 
2478  if( !m_pDocument )
2479  return;
2480 
2481  ScChartListenerCollection* pCLC = nullptr;
2482  if (m_pHiddenListener)
2483  {
2485  if (pCLC)
2487  }
2488 
2489  for (const auto& rxToken : m_aTokens)
2490  {
2491  ScRange aRange;
2492  if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
2493  continue;
2494 
2495  m_pDocument->StartListeningArea(aRange, false, m_pValueListener.get());
2496  if (pCLC)
2497  pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
2498  }
2499 }
2500 
2502 {
2503  m_bExtDataRebuildQueued = false;
2504 
2505  if (!m_aDataArray.empty())
2506  return;
2507 
2509 
2510  ::std::vector<sal_Int32> aHiddenValues;
2511  sal_Int32 nDataCount = 0;
2512 
2513  for (const auto& rxToken : m_aTokens)
2514  {
2515  if (ScRefTokenHelper::isExternalRef(rxToken))
2516  {
2517  nDataCount += FillCacheFromExternalRef(rxToken);
2518  }
2519  else
2520  {
2521  ScRange aRange;
2522  if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
2523  continue;
2524 
2525  SCCOL nLastCol = -1;
2526  SCROW nLastRow = -1;
2527  for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
2528  {
2529  for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
2530  {
2532  m_pDocument->InitColumnBlockPosition( hint, nTab, nCol );
2533  for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
2534  {
2535  bool bColHidden = m_pDocument->ColHidden(nCol, nTab, nullptr, &nLastCol);
2536  bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, nullptr, &nLastRow);
2537 
2538  if (bColHidden || bRowHidden)
2539  {
2540  // hidden cell
2541  aHiddenValues.push_back(nDataCount-1);
2542 
2543  if( !m_bIncludeHiddenCells )
2544  continue;
2545  }
2546 
2547  Item aItem;
2548 
2549  ScAddress aAdr(nCol, nRow, nTab);
2550  aItem.maString = m_pDocument->GetString(aAdr);
2551 
2552  ScRefCellValue aCell(*m_pDocument, aAdr, hint);
2553  switch (aCell.meType)
2554  {
2555  case CELLTYPE_VALUE:
2556  aItem.mfValue = aCell.getValue();
2557  aItem.mbIsValue = true;
2558  break;
2559  case CELLTYPE_FORMULA:
2560  {
2561  ScFormulaCell* pFCell = aCell.mpFormula;
2562  FormulaError nErr = pFCell->GetErrCode();
2563  if (nErr != FormulaError::NONE)
2564  break;
2565 
2566  if (pFCell->IsValue())
2567  {
2568  aItem.mfValue = pFCell->GetValue();
2569  aItem.mbIsValue = true;
2570  }
2571  }
2572  break;
2573  case CELLTYPE_EDIT:
2574  case CELLTYPE_NONE:
2575  case CELLTYPE_STRING:
2576  default:
2577  ; // do nothing
2578  }
2579 
2580  aItem.mAddress = ScAddress(nCol, nRow, nTab);
2581 
2582  m_aDataArray.push_back(std::move(aItem));
2583  ++nDataCount;
2584  }
2585  }
2586  }
2587  }
2588  }
2589 
2590  // convert the hidden cell list to sequence.
2591  m_aHiddenValues.realloc(aHiddenValues.size());
2592  std::copy(
2593  aHiddenValues.begin(), aHiddenValues.end(), m_aHiddenValues.getArray());
2594 
2595  // Clear the data series cache when the array is re-built.
2596  m_aMixedDataCache.realloc(0);
2597 }
2598 
2600 {
2602  {
2603  m_aDataArray.clear();
2604  m_pDocument->BroadcastUno(ScHint(SfxHintId::ScDataChanged, ScAddress()));
2605  m_bExtDataRebuildQueued = true;
2606  m_bGotDataChangedHint = true;
2607  }
2608 }
2609 
2611 {
2613  ScRange aRange;
2614  if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, pToken, ScAddress(), true))
2615  return 0;
2616 
2617  sal_uInt16 nFileId = pToken->GetIndex();
2618  OUString aTabName = pToken->GetString().getString();
2619  ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, aTabName, aRange, nullptr);
2620  if (!pArray)
2621  // no external data exists for this range.
2622  return 0;
2623 
2624  // Start listening for this external document.
2625  ExternalRefListener* pExtRefListener = GetExtRefListener();
2626  pRefMgr->addLinkListener(nFileId, pExtRefListener);
2627  pExtRefListener->addFileId(nFileId);
2628 
2629  ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, aTabName, false);
2630  sal_Int32 nDataCount = 0;
2631  FormulaTokenArrayPlainIterator aIter(*pArray);
2632  for (FormulaToken* p = aIter.First(); p; p = aIter.Next())
2633  {
2634  // Cached external range is always represented as a single
2635  // matrix token, although that might change in the future when
2636  // we introduce a new token type to store multi-table range
2637  // data.
2638 
2639  if (p->GetType() != svMatrix)
2640  {
2641  OSL_FAIL("Cached array is not a matrix token.");
2642  continue;
2643  }
2644 
2645  const ScMatrix* pMat = p->GetMatrix();
2646  SCSIZE nCSize, nRSize;
2647  pMat->GetDimensions(nCSize, nRSize);
2648  for (SCSIZE nC = 0; nC < nCSize; ++nC)
2649  {
2650  for (SCSIZE nR = 0; nR < nRSize; ++nR)
2651  {
2652  if (pMat->IsValue(nC, nR) || pMat->IsBoolean(nC, nR))
2653  {
2654  Item aItem;
2655 
2656  aItem.mbIsValue = true;
2657  aItem.mfValue = pMat->GetDouble(nC, nR);
2658 
2659  SvNumberFormatter* pFormatter = m_pDocument->GetFormatTable();
2660  if (pFormatter)
2661  {
2662  const double fVal = aItem.mfValue;
2663  const Color* pColor = nullptr;
2664  sal_uInt32 nFmt = 0;
2665  if (pTable)
2666  {
2667  // Get the correct format index from the cache.
2668  SCCOL nCol = aRange.aStart.Col() + static_cast<SCCOL>(nC);
2669  SCROW nRow = aRange.aStart.Row() + static_cast<SCROW>(nR);
2670  pTable->getCell(nCol, nRow, &nFmt);
2671  }
2672  pFormatter->GetOutputString(fVal, nFmt, aItem.maString, &pColor);
2673  }
2674 
2675  m_aDataArray.push_back(aItem);
2676  ++nDataCount;
2677  }
2678  else if (pMat->IsStringOrEmpty(nC, nR))
2679  {
2680  Item aItem;
2681 
2682  aItem.mbIsValue = false;
2683  aItem.maString = pMat->GetString(nC, nR).getString();
2684 
2685  m_aDataArray.emplace_back(aItem);
2686  ++nDataCount;
2687  }
2688  }
2689  }
2690  }
2691  return nDataCount;
2692 }
2693 
2695 {
2696  if (!m_oRangeIndices)
2697  return;
2698 
2699  for ( size_t i = 0, nCount = rRanges.size(); i < nCount; ++i )
2700  {
2701  ScTokenRef pToken;
2702  const ScRange & rRange = rRanges[i];
2703 
2705  sal_uInt32 nOrigPos = (*m_oRangeIndices)[i];
2706  m_aTokens[nOrigPos] = pToken;
2707  }
2708 
2709  RefChanged();
2710 
2711  // any change of the range address is broadcast to value (modify) listeners
2712  if ( !m_aValueListeners.empty() )
2713  m_bGotDataChangedHint = true;
2714 }
2715 
2717 {
2718  if (!m_pExtRefListener)
2720 
2721  return m_pExtRefListener.get();
2722 }
2723 
2725 {
2726  if (!m_pExtRefListener)
2727  return;
2728 
2729  const std::unordered_set<sal_uInt16>& rFileIds = m_pExtRefListener->getAllFileIds();
2731  for (const auto& rFileId : rFileIds)
2732  pRefMgr->removeLinkListener(rFileId, m_pExtRefListener.get());
2733 
2734  m_pExtRefListener.reset();
2735 }
2736 
2737 void ScChart2DataSequence::CopyData(const ScChart2DataSequence& r)
2738 {
2739  if (!m_pDocument)
2740  {
2741  OSL_FAIL("document instance is nullptr!?");
2742  return;
2743  }
2744 
2745  std::vector<Item> aDataArray(r.m_aDataArray);
2746  m_aDataArray.swap(aDataArray);
2747 
2749  m_aRole = r.m_aRole;
2750 
2751  if (r.m_oRangeIndices)
2753 
2754  if (!r.m_pExtRefListener)
2755  return;
2756 
2757  // Re-register all external files that the old instance was
2758  // listening to.
2759 
2762  const std::unordered_set<sal_uInt16>& rFileIds = r.m_pExtRefListener->getAllFileIds();
2763  for (const auto& rFileId : rFileIds)
2764  {
2765  pRefMgr->addLinkListener(rFileId, m_pExtRefListener.get());
2766  m_pExtRefListener->addFileId(rFileId);
2767  }
2768 }
2769 
2771 {
2772  if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
2773  {
2774  // Create a range list from the token list, have the range list
2775  // updated, and bring the change back to the token list.
2776 
2777  ScRangeList aRanges;
2778  m_oRangeIndices.emplace();
2779  vector<ScTokenRef>::const_iterator itrBeg = m_aTokens.begin(), itrEnd = m_aTokens.end();
2780  for (vector<ScTokenRef>::const_iterator itr = itrBeg ;itr != itrEnd; ++itr)
2781  {
2783  {
2784  ScRange aRange;
2786  aRanges.push_back(aRange);
2787  sal_uInt32 nPos = distance(itrBeg, itr);
2788  m_oRangeIndices->push_back(nPos);
2789  }
2790  }
2791 
2792  assert(m_oRangeIndices->size() == aRanges.size() &&
2793  "range list and range index list have different sizes.");
2794 
2795  unique_ptr<ScRangeList> pUndoRanges;
2796  if ( m_pDocument->HasUnoRefUndo() )
2797  pUndoRanges.reset(new ScRangeList(aRanges));
2798 
2799  const ScUpdateRefHint& rRef = static_cast<const ScUpdateRefHint&>(rHint);
2800  bool bChanged = aRanges.UpdateReference(
2801  rRef.GetMode(), m_pDocument, rRef.GetRange(), rRef.GetDx(), rRef.GetDy(), rRef.GetDz());
2802 
2803  if (bChanged)
2804  {
2805  // TODO: This should be an assert, but tdf#144537 triggers it.
2806  SAL_WARN_IF(m_oRangeIndices->size() == aRanges.size(),
2807  "sc.ui", "range list and range index list have different sizes after the reference update.");
2808 
2809  // Bring the change back from the range list to the token list.
2810  UpdateTokensFromRanges(aRanges);
2811 
2812  if (pUndoRanges)
2813  m_pDocument->AddUnoRefChange(m_nObjectId, *pUndoRanges);
2814  }
2815  }
2816  else if ( auto pUndoHint = dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
2817  {
2818  do
2819  {
2820  if (pUndoHint->GetObjectId() != m_nObjectId)
2821  break;
2822 
2823  // The hint object provides the old ranges. Restore the old state
2824  // from these ranges.
2825 
2826  if (!m_oRangeIndices || m_oRangeIndices->empty())
2827  {
2828  assert(false && " faulty range indices");
2829  break;
2830  }
2831 
2832  const ScRangeList& rRanges = pUndoHint->GetRanges();
2833 
2834  size_t nCount = rRanges.size();
2835  if (nCount != m_oRangeIndices->size())
2836  {
2837  assert(false && "range count and range index count differ.");
2838  break;
2839  }
2840 
2841  UpdateTokensFromRanges(rRanges);
2842  }
2843  while (false);
2844  }
2845  else
2846  {
2847  const SfxHintId nId = rHint.GetId();
2848  if ( nId ==SfxHintId::Dying )
2849  {
2850  m_pDocument = nullptr;
2851  }
2852  else if ( nId == SfxHintId::DataChanged )
2853  {
2854  // delayed broadcast as in ScCellRangesBase
2855 
2857  {
2858  m_aDataArray.clear();
2859  lang::EventObject aEvent;
2860  aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
2861 
2862  if( m_pDocument )
2863  {
2864  for (const uno::Reference<util::XModifyListener> & xListener: m_aValueListeners)
2865  m_pDocument->AddUnoListenerCall( xListener, aEvent );
2866  }
2867 
2868  m_bGotDataChangedHint = false;
2869  }
2870  }
2871  else if ( nId == SfxHintId::ScCalcAll )
2872  {
2873  // broadcast from DoHardRecalc - set m_bGotDataChangedHint
2874  // (SfxHintId::DataChanged follows separately)
2875 
2876  if ( !m_aValueListeners.empty() )
2877  m_bGotDataChangedHint = true;
2878  }
2879  else if (nId == SfxHintId::ScClearCache)
2880  {
2881  // necessary after import
2882  m_aDataArray.clear();
2883  }
2884  }
2885 }
2886 
2887 IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, const SfxHint&, rHint, void )
2888 {
2889  if ( m_pDocument && (rHint.GetId() == SfxHintId::ScDataChanged) )
2890  {
2891  // This may be called several times for a single change, if several formulas
2892  // in the range are notified. So only a flag is set that is checked when
2893  // SfxHintId::DataChanged is received.
2894 
2895  setDataChangedHint(true);
2896  }
2897 }
2898 
2900  ScChart2DataSequence& rParent, ScDocument* pDoc) :
2901  mrParent(rParent),
2902  mpDoc(pDoc)
2903 {
2904 }
2905 
2907 {
2908  if (!mpDoc || mpDoc->IsInDtorClear())
2909  // The document is being destroyed. Do nothing.
2910  return;
2911 
2912  // Make sure to remove all pointers to this object.
2913  mpDoc->GetExternalRefManager()->removeLinkListener(this);
2914 }
2915 
2917 {
2918  switch (eType)
2919  {
2921  {
2922  if (maFileIds.count(nFileId))
2923  // We are listening to this external document.
2924  mrParent.RebuildDataCache();
2925  }
2926  break;
2928  maFileIds.erase(nFileId);
2929  break;
2931  mpDoc = nullptr;
2932  break;
2933  }
2934 }
2935 
2937 {
2938  maFileIds.insert(nFileId);
2939 }
2940 
2941 uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
2942 {
2943  SolarMutexGuard aGuard;
2944  if ( !m_pDocument)
2945  throw uno::RuntimeException();
2946 
2947  BuildDataCache();
2948 
2949  if (!m_aMixedDataCache.hasElements())
2950  {
2951  // Build a cache for the 1st time...
2952 
2953  sal_Int32 nCount = m_aDataArray.size();
2954  m_aMixedDataCache.realloc(nCount);
2955  uno::Any* pArr = m_aMixedDataCache.getArray();
2956  for (const Item &rItem : m_aDataArray)
2957  {
2958  if (rItem.mbIsValue)
2959  *pArr <<= rItem.mfValue;
2960  else if (rItem.maString.isEmpty())
2961  {
2962  ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
2963  if (aCell.isEmpty())
2964  *pArr = uno::Any();
2965  else
2966  *pArr <<= rItem.maString;
2967  }
2968  else
2969  *pArr <<= rItem.maString;
2970  ++pArr;
2971  }
2972  }
2973  return m_aMixedDataCache;
2974 }
2975 
2976 // XNumericalDataSequence --------------------------------------------------
2977 
2978 uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData()
2979 {
2980  SolarMutexGuard aGuard;
2981  if ( !m_pDocument)
2982  throw uno::RuntimeException();
2983 
2984  BuildDataCache();
2985 
2986  sal_Int32 nCount = m_aDataArray.size();
2987  uno::Sequence<double> aSeq(nCount);
2988  double* pArr = aSeq.getArray();
2989  for (const Item& rItem : m_aDataArray)
2990  {
2991  *pArr = rItem.mbIsValue ? rItem.mfValue : std::numeric_limits<double>::quiet_NaN();
2992  ++pArr;
2993  }
2994 
2995  return aSeq;
2996 }
2997 
2998 // XTextualDataSequence --------------------------------------------------
2999 
3000 uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::getTextualData()
3001 {
3002  SolarMutexGuard aGuard;
3003  uno::Sequence<OUString> aSeq;
3004  if ( !m_pDocument )
3005  throw uno::RuntimeException();
3006 
3007  BuildDataCache();
3008 
3009  sal_Int32 nCount = m_aDataArray.size();
3010  if ( nCount > 0 )
3011  {
3012  aSeq = uno::Sequence<OUString>(nCount);
3013  OUString* pArr = aSeq.getArray();
3014  for (const Item& rItem : m_aDataArray)
3015  {
3016  *pArr = rItem.maString;
3017  ++pArr;
3018  }
3019  }
3020  else if ( m_aTokens.front() )
3021  {
3022  if( m_aTokens.front()->GetType() == svString )
3023  {
3024  aSeq = uno::Sequence<OUString> { m_aTokens.front()->GetString().getString() };
3025  }
3026  }
3027 
3028  return aSeq;
3029 }
3030 
3032 {
3033  SolarMutexGuard aGuard;
3034  OUString aStr;
3035  OSL_ENSURE( m_pDocument, "No Document -> no SourceRangeRepresentation" );
3036  if (m_pDocument)
3037  lcl_convertTokensToString(aStr, m_aTokens, *m_pDocument);
3038 
3039  return aStr;
3040 }
3041 
3042 namespace {
3043 
3048 class AccumulateRangeSize
3049 {
3050 public:
3051  AccumulateRangeSize(const ScDocument* pDoc) :
3052  mpDoc(pDoc), mnCols(0), mnRows(0) {}
3053 
3054  void operator() (const ScTokenRef& pToken)
3055  {
3056  ScRange r;
3057  bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3058  ScRefTokenHelper::getRangeFromToken(mpDoc, r, pToken, ScAddress(), bExternal);
3059  r.PutInOrder();
3060  mnCols += r.aEnd.Col() - r.aStart.Col() + 1;
3061  mnRows += r.aEnd.Row() - r.aStart.Row() + 1;
3062  }
3063 
3064  SCCOL getCols() const { return mnCols; }
3065  SCROW getRows() const { return mnRows; }
3066 private:
3067  const ScDocument* mpDoc;
3068  SCCOL mnCols;
3069  SCROW mnRows;
3070 };
3071 
3076 class GenerateLabelStrings
3077 {
3078 public:
3079  GenerateLabelStrings(const ScDocument* pDoc, sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) :
3080  mpDoc(pDoc),
3081  mpLabels(std::make_shared<Sequence<OUString>>(nSize)),
3082  meOrigin(eOrigin),
3083  mnCount(0),
3084  mbColumn(bColumn) {}
3085 
3086  void operator() (const ScTokenRef& pToken)
3087  {
3088  bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3089  ScRange aRange;
3090  ScRefTokenHelper::getRangeFromToken(mpDoc, aRange, pToken, ScAddress(), bExternal);
3091  OUString* pArr = mpLabels->getArray();
3092  if (mbColumn)
3093  {
3094  for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
3095  {
3096  if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3097  {
3098  OUString aString = ScResId(STR_COLUMN) + " ";
3099  ScAddress aPos( nCol, 0, 0 );
3100  OUString aColStr(aPos.Format(ScRefFlags::COL_VALID));
3101  aString += aColStr;
3102  pArr[mnCount] = aString;
3103  }
3104  else //only indices for categories
3105  pArr[mnCount] = OUString::number( mnCount+1 );
3106  ++mnCount;
3107  }
3108  }
3109  else
3110  {
3111  for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
3112  {
3113  if (meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3114  {
3115  OUString aString = ScResId(STR_ROW) +
3116  " " + OUString::number( nRow+1 );
3117  pArr[mnCount] = aString;
3118  }
3119  else //only indices for categories
3120  pArr[mnCount] = OUString::number( mnCount+1 );
3121  ++mnCount;
3122  }
3123  }
3124  }
3125 
3126  const Sequence<OUString>& getLabels() const { return *mpLabels; }
3127 
3128 private:
3129  const ScDocument* mpDoc;
3130  shared_ptr< Sequence<OUString> > mpLabels;
3131  chart2::data::LabelOrigin meOrigin;
3132  sal_Int32 mnCount;
3133  bool mbColumn;
3134 };
3135 
3136 }
3137 
3138 uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
3139 {
3140  SolarMutexGuard aGuard;
3141  if ( !m_pDocument)
3142  throw uno::RuntimeException();
3143 
3144  // Determine the total size of all ranges.
3145  AccumulateRangeSize func(m_pDocument);
3146  func = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), func);
3147  SCCOL nCols = func.getCols();
3148  SCROW nRows = func.getRows();
3149 
3150  // Determine whether this is column-major or row-major.
3151  bool bColumn = true;
3152  if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
3153  (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
3154  {
3155  if (nRows > nCols)
3156  {
3157  bColumn = eOrigin == chart2::data::LabelOrigin_SHORT_SIDE;
3158  }
3159  else if (nCols > nRows)
3160  {
3161  bColumn = eOrigin != chart2::data::LabelOrigin_SHORT_SIDE;
3162  }
3163  else
3164  return Sequence<OUString>();
3165  }
3166 
3167  // Generate label strings based on the info so far.
3168  sal_Int32 nCount = bColumn ? nCols : nRows;
3169  GenerateLabelStrings genLabels(m_pDocument, nCount, eOrigin, bColumn);
3170  genLabels = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), genLabels);
3171  Sequence<OUString> aSeq = genLabels.getLabels();
3172 
3173  return aSeq;
3174 }
3175 
3176 namespace {
3177 
3178 sal_uInt32 getDisplayNumberFormat(const ScDocument* pDoc, const ScAddress& rPos)
3179 {
3180  sal_uInt32 nFormat = pDoc->GetNumberFormat(rPos); // original format from cell.
3181  return nFormat;
3182 }
3183 
3184 }
3185 
3186 ::sal_Int32 SAL_CALL ScChart2DataSequence::getNumberFormatKeyByIndex( ::sal_Int32 nIndex )
3187 {
3188  SolarMutexGuard aGuard;
3189  BuildDataCache();
3190 
3191  if (nIndex == -1)
3192  {
3193  // return format of first non-empty cell
3194  // TODO: use nicer heuristic
3195  for (const Item& rItem : m_aDataArray)
3196  {
3197  ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
3198  if (!aCell.isEmpty() && aCell.hasNumeric())
3199  {
3200  return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, rItem.mAddress));
3201  }
3202  }
3203 
3204  // we could not find a non-empty cell
3205  return 0;
3206  }
3207 
3208  if (nIndex < 0 || nIndex >= static_cast<sal_Int32>(m_aDataArray.size()))
3209  {
3210  SAL_WARN("sc.ui", "Passed invalid index to getNumberFormatKeyByIndex(). Will return default value '0'.");
3211  return 0;
3212  }
3213 
3214  return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, m_aDataArray.at(nIndex).mAddress));
3215 }
3216 
3217 // XCloneable ================================================================
3218 
3219 uno::Reference< util::XCloneable > SAL_CALL ScChart2DataSequence::createClone()
3220 {
3221  SolarMutexGuard aGuard;
3222 
3223  // Clone tokens.
3224  vector<ScTokenRef> aTokensNew;
3225  aTokensNew.reserve(m_aTokens.size());
3226  for (const auto& rxToken : m_aTokens)
3227  {
3228  ScTokenRef p(rxToken->Clone());
3229  aTokensNew.push_back(p);
3230  }
3231 
3233  p->CopyData(*this);
3234  return p;
3235 }
3236 
3237 // XModifyBroadcaster ========================================================
3238 
3239 void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3240 {
3241  // like ScCellRangesBase::addModifyListener
3242  SolarMutexGuard aGuard;
3243  if (m_aTokens.empty())
3244  return;
3245 
3246  ScRangeList aRanges;
3248  m_aValueListeners.emplace_back( aListener );
3249 
3250  if ( m_aValueListeners.size() != 1 )
3251  return;
3252 
3253  if (!m_pValueListener)
3254  m_pValueListener.reset(new ScLinkListener( LINK( this, ScChart2DataSequence, ValueListenerHdl ) ));
3255 
3256  if (!m_pHiddenListener)
3257  m_pHiddenListener.reset(new HiddenRangeListener(*this));
3258 
3259  if( m_pDocument )
3260  {
3262  for (const auto& rxToken : m_aTokens)
3263  {
3264  ScRange aRange;
3265  if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
3266  continue;
3267 
3268  m_pDocument->StartListeningArea( aRange, false, m_pValueListener.get() );
3269  if (pCLC)
3270  pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
3271  }
3272  }
3273 
3274  acquire(); // don't lose this object (one ref for all listeners)
3275 }
3276 
3277 void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3278 {
3279  // like ScCellRangesBase::removeModifyListener
3280 
3281  SolarMutexGuard aGuard;
3282  if (m_aTokens.empty())
3283  return;
3284 
3285  rtl::Reference<ScChart2DataSequence> xSelfHold(this); // in case the listeners have the last ref
3286 
3287  sal_uInt16 nCount = m_aValueListeners.size();
3288  for ( sal_uInt16 n=nCount; n--; )
3289  {
3290  uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
3291  if ( rObj == aListener )
3292  {
3293  m_aValueListeners.erase( m_aValueListeners.begin() + n );
3294 
3295  if ( m_aValueListeners.empty() )
3296  {
3297  if (m_pValueListener)
3298  m_pValueListener->EndListeningAll();
3299 
3301  {
3303  if (pCLC)
3305  }
3306 
3307  release(); // release the ref for the listeners
3308  }
3309 
3310  break;
3311  }
3312  }
3313 }
3314 
3315 // DataSequence XPropertySet -------------------------------------------------
3316 
3317 uno::Reference< beans::XPropertySetInfo> SAL_CALL
3319 {
3320  SolarMutexGuard aGuard;
3321  static uno::Reference<beans::XPropertySetInfo> aRef =
3323  return aRef;
3324 }
3325 
3327  const OUString& rPropertyName, const uno::Any& rValue)
3328 {
3329  if ( rPropertyName == SC_UNONAME_ROLE )
3330  {
3331  if ( !(rValue >>= m_aRole))
3332  throw lang::IllegalArgumentException();
3333  }
3334  else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3335  {
3336  bool bOldValue = m_bIncludeHiddenCells;
3337  if ( !(rValue >>= m_bIncludeHiddenCells))
3338  throw lang::IllegalArgumentException();
3339  if( bOldValue != m_bIncludeHiddenCells )
3340  m_aDataArray.clear();//data array is dirty now
3341  }
3342  else if( rPropertyName == "TimeBased" )
3343  {
3344  bool bTimeBased = mbTimeBased;
3345  rValue>>= bTimeBased;
3346  mbTimeBased = bTimeBased;
3347  }
3348  else
3349  throw beans::UnknownPropertyException(rPropertyName);
3350  // TODO: support optional properties
3351 }
3352 
3353 uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue(const OUString& rPropertyName)
3354 {
3355  uno::Any aRet;
3356  if ( rPropertyName == SC_UNONAME_ROLE )
3357  aRet <<= m_aRole;
3358  else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3359  aRet <<= m_bIncludeHiddenCells;
3360  else if ( rPropertyName == SC_UNONAME_HIDDENVALUES )
3361  {
3362  // This property is read-only thus cannot be set externally via
3363  // setPropertyValue(...).
3364  BuildDataCache();
3365  aRet <<= m_aHiddenValues;
3366  }
3367  else if (rPropertyName == SC_UNONAME_TIME_BASED)
3368  {
3369  aRet <<= mbTimeBased;
3370  }
3371  else if (rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
3372  {
3373  // Read-only property. It returns whether or not the label value is a
3374  // direct user input, rather than an indirect reference.
3375  bool bHasStringLabel = false;
3376  if (m_aTokens.size() == 1)
3377  {
3378  const formula::FormulaToken& rToken = *m_aTokens[0];
3379  bHasStringLabel = rToken.GetType() == formula::svString;
3380  }
3381  aRet <<= bHasStringLabel;
3382  }
3383  else
3384  throw beans::UnknownPropertyException(rPropertyName);
3385  // TODO: support optional properties
3386  return aRet;
3387 }
3388 
3390  const OUString& /*rPropertyName*/,
3391  const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
3392 {
3393  // FIXME: real implementation
3394  OSL_FAIL( "Not yet implemented" );
3395 }
3396 
3398  const OUString& /*rPropertyName*/,
3399  const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
3400 {
3401  // FIXME: real implementation
3402  OSL_FAIL( "Not yet implemented" );
3403 }
3404 
3406  const OUString& /*rPropertyName*/,
3407  const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3408 {
3409  // FIXME: real implementation
3410  OSL_FAIL( "Not yet implemented" );
3411 }
3412 
3414  const OUString& /*rPropertyName*/,
3415  const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3416 {
3417  // FIXME: real implementation
3418  OSL_FAIL( "Not yet implemented" );
3419 }
3420 
3422 {
3424 }
3425 
3427 {
3428  if(!mbTimeBased)
3429  return true;
3430 
3432  {
3433  if(bWrap)
3434  setToPointInTime(0);
3435  return false;
3436  }
3437 
3438  for(const auto& rxToken : m_aTokens)
3439  {
3440  if (rxToken->GetType() != svDoubleRef)
3441  continue;
3442 
3443  ScComplexRefData& rData = *rxToken->GetDoubleRef();
3444  ScSingleRefData& s = rData.Ref1;
3445  ScSingleRefData& e = rData.Ref2;
3446 
3447  s.IncTab(1);
3448  e.IncTab(1);
3449  }
3450 
3451  ++mnCurrentTab;
3452 
3453  RebuildDataCache();
3454 
3455  return true;
3456 }
3457 
3458 void ScChart2DataSequence::setRange(sal_Int32 nStart, sal_Int32 nEnd)
3459 {
3460  mnTimeBasedStart = nStart;
3461  mnTimeBasedEnd = nEnd;
3463 }
3464 
3466 {
3467  if(nPoint > mnTimeBasedEnd - mnTimeBasedStart)
3468  return false;
3469 
3470  SCTAB nTab = mnTimeBasedStart + nPoint;
3471  for(const auto& rxToken : m_aTokens)
3472  {
3473  if (rxToken->GetType() != svDoubleRef)
3474  continue;
3475 
3476  ScComplexRefData& rData = *rxToken->GetDoubleRef();
3477  ScSingleRefData& s = rData.Ref1;
3478  ScSingleRefData& e = rData.Ref2;
3479 
3480  s.SetAbsTab(nTab);
3481  e.SetAbsTab(nTab);
3482  }
3483 
3484  mnCurrentTab = nTab;
3485 
3486  RebuildDataCache();
3487 
3488  return true;
3489 }
3490 
3491 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Sequence< sal_Int32 > m_aHiddenValues
Definition: chart2uno.hxx:367
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:112
std::unique_ptr< HiddenRangeListener > m_pHiddenListener
Definition: chart2uno.hxx:383
virtual OUString SAL_CALL convertRangeFromXML(const OUString &sXMLRange) override
Definition: chart2uno.cxx:2253
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
svString
SCCOL Col() const
Definition: refdata.cxx:247
StackVar
#define SC_UNONAME_INCLUDEHIDDENCELLS
Definition: unonames.hxx:687
bool UpdateReference(UpdateRefMode, const ScDocument *, const ScRange &rWhere, SCCOL nDx, SCROW nDy, SCTAB nDz)
Definition: rangelst.cxx:357
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:2716
sal_Int32 nIndex
State
OUString getString() const
bool HasUnoRefUndo() const
Definition: document.hxx:1087
ScAddress aStart
Definition: address.hxx:497
#define SC_UNONAME_TIME_BASED
Definition: unonames.hxx:690
virtual css::uno::Sequence< OUString > SAL_CALL getTextualData() override
Definition: chart2uno.cxx:3000
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL detectArguments(const css::uno::Reference< css::chart2::data::XDataSource > &xDataSource) override
Definition: chart2uno.cxx:1765
svSep
ocName
bool SC_DLLPUBLIC isExternalRef(const ScTokenRef &pToken)
SCROW Row() const
Definition: address.hxx:274
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:688
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:148
virtual void SAL_CALL removeModifyListener(const css::uno::Reference< css::util::XModifyListener > &aListener) override
Definition: chart2uno.cxx:3277
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:68
ScDocument * m_pDocument
Definition: chart2uno.hxx:189
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
Definition: chart2uno.cxx:2297
virtual ~ScChart2DataSource() override
Definition: chart2uno.cxx:2369
SC_DLLPUBLIC bool InitColumnBlockPosition(sc::ColumnBlockPosition &rBlockPos, SCTAB nTab, SCCOL nCol)
Definition: document.cxx:2654
ocOpen
sal_Int64 n
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: chart2uno.cxx:2377
#define max(a, b)
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:2305
virtual void SAL_CALL addModifyListener(const css::uno::Reference< css::util::XModifyListener > &aListener) override
Definition: chart2uno.cxx:3239
std::optional< std::vector< sal_uInt32 > > m_oRangeIndices
Definition: chart2uno.hxx:378
ScAddress aEnd
Definition: address.hxx:498
void SetAbsRow(SCROW nVal)
Definition: refdata.cxx:76
static const SharedString & getEmptyString()
sal_Int64 GetNewUnoId()
Definition: document.hxx:1090
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:376
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1007
std::shared_ptr< T > make_shared(Args &&...args)
void SetRowRel(bool bVal)
Definition: refdata.hxx:66
SCROW GetMaxRowCount() const
Definition: sheetlimits.hxx:66
SwNodeOffset abs(const SwNodeOffset &a)
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:2916
css::uno::Sequence< css::uno::Any > m_aMixedDataCache
Cached data for getData.
Definition: chart2uno.hxx:365
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByValueArray(const OUString &aRole, const OUString &aRangeRepresentation, const OUString &aRoleQualifier) override
Definition: chart2uno.cxx:2082
void AddUnoRefChange(sal_Int64 nId, const ScRangeList &rOldRanges)
Definition: documen3.cxx:1002
void StopListeningToAllExternalRefs()
Definition: chart2uno.cxx:2724
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3010
virtual ~ScChart2DataProvider() override
Definition: chart2uno.cxx:984
SfxItemPropertySet m_aPropSet
Definition: chart2uno.hxx:381
sal_uInt16 sal_Unicode
css::chart2::data::DataSequenceRole m_aRole
Definition: chart2uno.hxx:370
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:891
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:685
double GetValue()
void StartListeningHiddenRange(const ScRange &rRange, ScChartHiddenRangeListener *pListener)
Start listening on hide/show change within specified cell range.
Definition: chartlis.cxx:620
FormulaError GetErrCode()
int nCount
SC_DLLPUBLIC OUString GetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext *pContext=nullptr) const
Definition: document.cxx:3536
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:3389
SC_DLLPUBLIC ScExternalRefManager * GetExternalRefManager() const
Definition: documen3.cxx:627
void push_back(const ScRange &rRange)
Definition: rangelst.cxx:1137
ScFormulaCell * mpFormula
Definition: cellvalue.hxx:110
SCTAB Tab() const
Definition: address.hxx:283
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:375
bool IsStringOrEmpty(SCSIZE nIndex) const
Definition: scmatrix.cxx:3045
virtual css::uno::Any SAL_CALL getPropertyValue(const OUString &rPropertyName) override
Definition: chart2uno.cxx:2316
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:3426
bool HasReferences() const
Definition: rangenam.cxx:520
sal_uInt16 GetLen() const
virtual void SAL_CALL removeVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:2353
ocSep
constexpr OUStringLiteral aData
DocumentType eType
virtual void SAL_CALL setRange(sal_Int32 nStart, sal_Int32 nEnd) override
Definition: chart2uno.cxx:3458
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:890
ScDocument * m_pDocument
Definition: chart2uno.hxx:147
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:459
SC_DLLPUBLIC bool ColHidden(SCCOL nCol, SCTAB nTab, SCCOL *pFirstCol=nullptr, SCCOL *pLastCol=nullptr) const
Definition: document.cxx:4495
bool PastingDrawFromOtherDoc() const
Definition: document.hxx:2516
HiddenRangeListener(ScChart2DataSequence &rParent)
Definition: chart2uno.cxx:2405
ScChart2DataSource(ScDocument *pDoc)
Definition: chart2uno.cxx:2362
virtual void SAL_CALL addPropertyChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &xListener) override
Definition: chart2uno.cxx:2332
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:2043
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:3413
void SetAbsCol(SCCOL nVal)
Definition: refdata.cxx:59
bool getDoubleRefDataFromToken(ScComplexRefData &rData, const ScTokenRef &pToken)
ScSheetLimits & GetSheetLimits() const
Definition: document.hxx:896
ScSingleRefData Ref1
Definition: refdata.hxx:124
bool IsBoolean(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3090
svIndex
css::uno::Reference< css::chart2::data::XDataSource > mxCachedDataSource
Definition: chart2uno.hxx:150
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Definition: chart2uno.cxx:2770
ExternalRefListener(ScChart2DataSequence &rParent, ScDocument *pDoc)
Definition: chart2uno.cxx:2899
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:1035
virtual sal_Bool SAL_CALL setToPointInTime(sal_Int32 nPoint) override
Definition: chart2uno.cxx:3465
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:952
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:2501
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:690
virtual css::uno::Any SAL_CALL getPropertyValue(const OUString &rPropertyName) override
Definition: chart2uno.cxx:3353
#define SC_UNONAME_HAS_STRING_LABEL
Definition: unonames.hxx:689
std::size_t mnCount
const SCTAB MAXTAB
Definition: address.hxx:70
void SetAbsTab(SCTAB nVal)
Definition: refdata.cxx:93
css::uno::Reference< css::chart2::data::XDataSource > mxCreatedDataSource
Definition: chart2uno.hxx:153
SC_DLLPUBLIC bool HasValueData(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3798
std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > m_aLabeledSequences
Definition: chart2uno.hxx:190
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByRangeRepresentation(const OUString &aRangeRepresentation) override
Definition: chart2uno.cxx:2057
SCTAB Tab() const
Definition: refdata.cxx:254
svSingleRef
FormulaError
SCCOL Col() const
Definition: address.hxx:279
void AddUnoObject(SfxListener &rObject)
Definition: documen3.cxx:901
svDoubleRef
virtual OUString SAL_CALL convertRangeToXML(const OUString &sRangeRepresentation) override
Definition: chart2uno.cxx:2229
CellType meType
Definition: cellvalue.hxx:105
sal_Int32 SCROW
Definition: types.hxx:17
void PutInOrder()
Definition: address.hxx:622
void EndListeningHiddenRange(ScChartHiddenRangeListener *pListener)
Remove all ranges associated with passed listener instance from the list of hidden range listeners...
Definition: chartlis.cxx:625
std::unique_ptr< ExternalRefListener > m_pExtRefListener
Definition: chart2uno.hxx:380
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:3186
css::uno::Sequence< css::beans::PropertyValue > maCreateDataSourceArguments
Definition: chart2uno.hxx:152
void setDataChangedHint(bool b)
Definition: chart2uno.cxx:3421
void CopyData(const ScChart2DataSequence &r)
Definition: chart2uno.cxx:2737
#define SAL_WARN_IF(condition, area, stream)
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:358
static const SfxItemPropertyMapEntry * lcl_GetDataSequencePropertyMap()
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
XModifyListenerArr_Impl m_aValueListeners
Definition: chart2uno.hxx:386
#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:3405
std::shared_ptr< ScTokenArray > TokenArrayRef
std::shared_ptr< Table > TableTypeRef
virtual css::uno::Reference< css::sheet::XRangeSelection > SAL_CALL getRangeSelection() override
Definition: chart2uno.cxx:2089
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:909
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:3397
std::unique_ptr< ScLinkListener > m_pValueListener
Definition: chart2uno.hxx:385
SC_DLLPUBLIC bool HasData(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: documen5.cxx:529
OUString aLabel
void * p
Reference< XComponentContext > getProcessComponentContext()
SC_DLLPUBLIC ScChartListenerCollection * GetChartListenerCollection() const
Definition: document.hxx:2226
Sequence< sal_Int8 > aSeq
virtual css::uno::Sequence< double > SAL_CALL getNumericalData() override
Definition: chart2uno.cxx:2978
double getValue()
Definition: cellvalue.cxx:632
FILE * init(int, char **)
void UpdateTokensFromRanges(const ScRangeList &rRanges)
Definition: chart2uno.cxx:2694
SC_DLLPUBLIC bool RowHidden(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4479
SC_DLLPUBLIC bool IsReference(ScRange &rRef) const
Definition: rangenam.cxx:370
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:2887
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:980
virtual css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > SAL_CALL getDataSequences() override
Definition: chart2uno.cxx:2386
virtual void SAL_CALL addVetoableChangeListener(const OUString &rPropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &rListener) override
Definition: chart2uno.cxx:2346
virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByFormulaTokens(const css::uno::Sequence< css::sheet::FormulaToken > &aTokens) override
Definition: chart2uno.cxx:2157
virtual OUString SAL_CALL getSourceRangeRepresentation() override
Definition: chart2uno.cxx:3031
static sal_Int32 IndexOf(const OUString &rString, sal_Unicode cSearchChar, sal_Int32 nOffset, sal_Unicode cQuote= '\'')
Definition: rangeutl.cxx:374
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1080
#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:3219
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:2339
sal_Int32 FillCacheFromExternalRef(const ScTokenRef &pToken)
Definition: chart2uno.cxx:2610
css::uno::Sequence< css::beans::PropertyValue > maCachedArguments
Definition: chart2uno.hxx:151
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:806
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:2452
static void GetTokenByOffset(OUString &rToken, const OUString &rString, sal_Int32 &nOffset, sal_Unicode cSeparator= ' ', sal_Unicode cQuote= '\'')
Definition: rangeutl.cxx:414
virtual css::uno::Sequence< css::uno::Any > SAL_CALL getData() override
Definition: chart2uno.cxx:2941
StackVar GetType() const
void AddLabeledSequence(const css::uno::Reference< css::chart2::data::XLabeledDataSequence > &xNew)
Definition: chart2uno.cxx:2392
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:3326
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:2100
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:686
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
Definition: chart2uno.cxx:3318
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:3138
SC_DLLPUBLIC sal_uInt32 GetNumberFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3677
bool m_bDetectedRangeSegmentation false
virtual css::uno::Reference< css::chart2::data::XDataSource > SAL_CALL createDataSource(const css::uno::Sequence< css::beans::PropertyValue > &aArguments) override
Definition: chart2uno.cxx:1399