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