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