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