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