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