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 10 : 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 39 : const SfxItemPropertyMapEntry* lcl_GetDataProviderPropertyMap()
80 : {
81 : static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
82 : {
83 8 : { OUString(SC_UNONAME_INCLUDEHIDDENCELLS), 0, getBooleanCppuType(), 0, 0 },
84 8 : { OUString(SC_UNONAME_USE_INTERNAL_DATA_PROVIDER), 0, getBooleanCppuType(), 0, 0 },
85 : { OUString(), 0, css::uno::Type(), 0, 0 }
86 63 : };
87 39 : return aDataProviderPropertyMap_Impl;
88 : }
89 :
90 3275 : const SfxItemPropertyMapEntry* lcl_GetDataSequencePropertyMap()
91 : {
92 : static const SfxItemPropertyMapEntry aDataSequencePropertyMap_Impl[] =
93 : {
94 8 : {OUString(SC_UNONAME_HIDDENVALUES), 0, getCppuType((uno::Sequence<sal_Int32>*)0 ), 0, 0 },
95 8 : {OUString(SC_UNONAME_ROLE), 0, getCppuType((::com::sun::star::chart2::data::DataSequenceRole*)0), 0, 0 },
96 8 : {OUString(SC_UNONAME_INCLUDEHIDDENCELLS), 0, getBooleanCppuType(), 0, 0 },
97 : { OUString(), 0, css::uno::Type(), 0, 0 }
98 3307 : };
99 3275 : return aDataSequencePropertyMap_Impl;
100 : }
101 :
102 : template< typename T >
103 325 : ::com::sun::star::uno::Sequence< T > lcl_VectorToSequence(
104 : const ::std::vector< T > & rCont )
105 : {
106 325 : ::com::sun::star::uno::Sequence< T > aResult( rCont.size());
107 325 : ::std::copy( rCont.begin(), rCont.end(), aResult.getArray());
108 325 : return aResult;
109 : }
110 :
111 : struct lcl_appendTableNumber : public ::std::unary_function< SCTAB, void >
112 : {
113 169 : lcl_appendTableNumber( OUStringBuffer & rBuffer ) :
114 169 : m_rBuffer( rBuffer )
115 169 : {}
116 127 : void operator() ( SCTAB nTab )
117 : {
118 : // there is no append with SCTAB or sal_Int16
119 127 : m_rBuffer.append( static_cast< sal_Int32 >( nTab ));
120 127 : m_rBuffer.append( ' ' );
121 127 : }
122 : private:
123 : OUStringBuffer & m_rBuffer;
124 : };
125 :
126 169 : OUString lcl_createTableNumberList( const ::std::list< SCTAB > & rTableList )
127 : {
128 169 : OUStringBuffer aBuffer;
129 169 : ::std::for_each( rTableList.begin(), rTableList.end(), lcl_appendTableNumber( aBuffer ));
130 : // remove last trailing ' '
131 169 : if( !aBuffer.isEmpty() )
132 111 : aBuffer.setLength( aBuffer.getLength() - 1 );
133 169 : 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 3024 : struct TokenTable : boost::noncopyable
146 : {
147 : SCROW mnRowCount;
148 : SCCOL mnColCount;
149 : vector<FormulaToken*> maTokens;
150 :
151 1512 : void init( SCCOL nColCount, SCROW nRowCount )
152 : {
153 1512 : mnColCount = nColCount;
154 1512 : mnRowCount = nRowCount;
155 1512 : maTokens.reserve(mnColCount*mnRowCount);
156 1512 : }
157 1512 : void clear()
158 : {
159 1512 : ::std::for_each(maTokens.begin(), maTokens.end(), ScDeleteObjectByPtr<FormulaToken>());
160 1512 : }
161 :
162 6026 : void push_back( FormulaToken* pToken )
163 : {
164 6026 : maTokens.push_back( pToken );
165 : OSL_ENSURE( maTokens.size()<= static_cast<sal_uInt32>( mnColCount*mnRowCount ), "too much tokens" );
166 6026 : }
167 :
168 5874 : 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 5874 : 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 5874 : 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 3572 : vector<ScTokenRef>* TokenTable::getColRanges(SCCOL nCol) const
183 : {
184 3572 : if (nCol >= mnColCount)
185 0 : return NULL;
186 3572 : if( mnRowCount<=0 )
187 931 : return NULL;
188 :
189 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
190 2641 : auto_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
191 : SAL_WNODEPRECATED_DECLARATIONS_POP
192 2641 : sal_uInt32 nLast = getIndex(nCol, mnRowCount-1);
193 7306 : for (sal_uInt32 i = getIndex(nCol, 0); i <= nLast; ++i)
194 : {
195 4665 : FormulaToken* p = maTokens[i];
196 4665 : if (!p)
197 0 : continue;
198 :
199 4665 : ScTokenRef pCopy(static_cast<ScToken*>(p->Clone()));
200 4665 : ScRefTokenHelper::join(*pTokens, pCopy, ScAddress());
201 4665 : }
202 2641 : return pTokens.release();
203 : }
204 :
205 572 : vector<ScTokenRef>* TokenTable::getRowRanges(SCROW nRow) const
206 : {
207 572 : if (nRow >= mnRowCount)
208 0 : return NULL;
209 572 : if( mnColCount<=0 )
210 276 : return NULL;
211 :
212 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
213 296 : auto_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
214 : SAL_WNODEPRECATED_DECLARATIONS_POP
215 296 : sal_uInt32 nLast = getIndex(mnColCount-1, nRow);
216 1398 : for (sal_uInt32 i = getIndex(0, nRow); i <= nLast; i += mnRowCount)
217 : {
218 1102 : FormulaToken* p = maTokens[i];
219 1102 : if (!p)
220 0 : continue;
221 :
222 1102 : ScTokenRef p2(static_cast<ScToken*>(p->Clone()));
223 1102 : ScRefTokenHelper::join(*pTokens, p2, ScAddress());
224 1102 : }
225 296 : return pTokens.release();
226 : }
227 :
228 126 : vector<ScTokenRef>* TokenTable::getAllRanges() const
229 : {
230 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
231 126 : auto_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
232 : SAL_WNODEPRECATED_DECLARATIONS_POP
233 126 : sal_uInt32 nStop = mnColCount*mnRowCount;
234 385 : for (sal_uInt32 i = 0; i < nStop; i++)
235 : {
236 259 : FormulaToken* p = maTokens[i];
237 259 : if (!p)
238 0 : continue;
239 :
240 259 : ScTokenRef p2(static_cast<ScToken*>(p->Clone()));
241 259 : ScRefTokenHelper::join(*pTokens, p2, ScAddress());
242 259 : }
243 126 : 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 241 : SCCOL getDataColCount() const { return mnDataColCount; }
258 137 : 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 378 : Chart2PositionMap::Chart2PositionMap(SCCOL nAllColCount, SCROW nAllRowCount,
281 378 : 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 378 : SCROW nHeaderRowCount = (bFillColumnHeader && nAllColCount && nAllRowCount) ? 1 : 0;
289 378 : SCCOL nHeaderColCount = (bFillRowHeader && nAllColCount && nAllRowCount) ? 1 : 0;
290 :
291 378 : if( nHeaderColCount || nHeaderRowCount )
292 : {
293 99 : const SCCOL nInitialHeaderColCount = nHeaderColCount;
294 : //check whether there is more than one text column or row that should be added to the headers
295 99 : SCROW nSmallestValueRowIndex = nAllRowCount;
296 99 : bool bFoundValues = false;
297 99 : bool bFoundAnything = false;
298 99 : FormulaTokenMapMap::const_iterator it1 = rCols.begin();
299 1119 : for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol)
300 : {
301 1020 : if (it1 != rCols.end() && nCol>=nHeaderColCount)
302 : {
303 955 : bool bFoundValuesInRow = false;
304 955 : FormulaTokenMap* pCol = it1->second;
305 955 : FormulaTokenMap::const_iterator it2 = pCol->begin();
306 2014 : for (SCROW nRow = 0; !bFoundValuesInRow && nRow < nSmallestValueRowIndex && it2 != pCol->end(); ++nRow)
307 : {
308 1059 : FormulaToken* pToken = it2->second;
309 1059 : if (pToken && nRow>=nHeaderRowCount)
310 : {
311 178 : ScRange aRange;
312 178 : bool bExternal = false;
313 178 : StackVar eType = pToken->GetType();
314 178 : if( eType==svExternal || eType==svExternalSingleRef || eType==svExternalDoubleRef || eType==svExternalName )
315 0 : bExternal = true;//lllll todo correct?
316 178 : ScTokenRef pSharedToken(static_cast<ScToken*>(pToken->Clone()));
317 178 : ScRefTokenHelper::getRangeFromToken(aRange, pSharedToken, ScAddress(), bExternal);
318 178 : SCCOL nCol1=0, nCol2=0;
319 178 : SCROW nRow1=0, nRow2=0;
320 178 : SCTAB nTab1=0, nTab2=0;
321 178 : aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
322 178 : if (pDoc && pDoc->HasValueData( nCol1, nRow1, nTab1 ))
323 : {
324 98 : bFoundValuesInRow = bFoundValues = bFoundAnything = true;
325 98 : nSmallestValueRowIndex = std::min( nSmallestValueRowIndex, nRow );
326 : }
327 178 : if( !bFoundAnything )
328 : {
329 10 : if (pDoc && pDoc->HasData( nCol1, nRow1, nTab1 ) )
330 10 : bFoundAnything = true;
331 178 : }
332 : }
333 1059 : ++it2;
334 : }
335 955 : if(!bFoundValues && nHeaderColCount>0)
336 0 : nHeaderColCount++;
337 : }
338 1020 : ++it1;
339 : }
340 99 : if( bFoundAnything )
341 : {
342 98 : if(nHeaderRowCount>0)
343 : {
344 91 : if( bFoundValues )
345 91 : 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 1 : nHeaderColCount = nInitialHeaderColCount;
352 : }
353 :
354 378 : mnDataColCount = nAllColCount - nHeaderColCount;
355 378 : mnDataRowCount = nAllRowCount - nHeaderRowCount;
356 :
357 378 : maLeftUpperCorner.init(nHeaderColCount,nHeaderRowCount);
358 378 : maColHeaders.init(mnDataColCount,nHeaderRowCount);
359 378 : maRowHeaders.init(nHeaderColCount,mnDataRowCount);
360 378 : maData.init(mnDataColCount,mnDataRowCount);
361 :
362 378 : FormulaTokenMapMap::const_iterator it1 = rCols.begin();
363 3117 : for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol)
364 : {
365 2739 : if (it1 != rCols.end())
366 : {
367 2739 : FormulaTokenMap* pCol = it1->second;
368 2739 : FormulaTokenMap::const_iterator it2 = pCol->begin();
369 8765 : for (SCROW nRow = 0; nRow < nAllRowCount; ++nRow)
370 : {
371 6026 : FormulaToken* pToken = NULL;
372 6026 : if (it2 != pCol->end())
373 : {
374 6026 : pToken = it2->second;
375 6026 : ++it2;
376 : }
377 :
378 6026 : if( nCol < nHeaderColCount )
379 : {
380 243 : if( nRow < nHeaderRowCount )
381 58 : maLeftUpperCorner.push_back(pToken);
382 : else
383 185 : maRowHeaders.push_back(pToken);
384 : }
385 5783 : else if( nRow < nHeaderRowCount )
386 881 : maColHeaders.push_back(pToken);
387 : else
388 4902 : maData.push_back(pToken);
389 : }
390 2739 : ++it1;
391 : }
392 : }
393 378 : }
394 :
395 756 : Chart2PositionMap::~Chart2PositionMap()
396 : {
397 378 : maLeftUpperCorner.clear();
398 378 : maColHeaders.clear();
399 378 : maRowHeaders.clear();
400 378 : maData.clear();
401 378 : }
402 :
403 63 : vector<ScTokenRef>* Chart2PositionMap::getLeftUpperCornerRanges() const
404 : {
405 63 : return maLeftUpperCorner.getAllRanges();
406 : }
407 2 : vector<ScTokenRef>* Chart2PositionMap::getAllColHeaderRanges() const
408 : {
409 2 : return maColHeaders.getAllRanges();
410 : }
411 61 : vector<ScTokenRef>* Chart2PositionMap::getAllRowHeaderRanges() const
412 : {
413 61 : return maRowHeaders.getAllRanges();
414 : }
415 1786 : vector<ScTokenRef>* Chart2PositionMap::getColHeaderRanges(SCCOL nCol) const
416 : {
417 1786 : return maColHeaders.getColRanges( nCol);
418 : }
419 286 : vector<ScTokenRef>* Chart2PositionMap::getRowHeaderRanges(SCROW nRow) const
420 : {
421 286 : return maRowHeaders.getRowRanges( nRow);
422 : }
423 :
424 1786 : vector<ScTokenRef>* Chart2PositionMap::getDataColRanges(SCCOL nCol) const
425 : {
426 1786 : return maData.getColRanges( nCol);
427 : }
428 :
429 286 : vector<ScTokenRef>* Chart2PositionMap::getDataRowRanges(SCROW nRow) const
430 : {
431 286 : 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 378 : 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 378 : mbDummyUpperLeft(false)
460 : {
461 378 : }
462 :
463 378 : ~Chart2Positioner()
464 378 : {
465 378 : }
466 :
467 378 : void setHeaders(bool bColHeaders, bool bRowHeaders)
468 : {
469 378 : mbColHeaders = bColHeaders;
470 378 : mbRowHeaders = bRowHeaders;
471 378 : }
472 :
473 378 : Chart2PositionMap* getPositionMap()
474 : {
475 378 : createPositionMap();
476 378 : 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 378 : void Chart2Positioner::glueState()
504 : {
505 378 : if (meGlue != GLUETYPE_NA)
506 378 : return;
507 :
508 378 : mbDummyUpperLeft = false;
509 378 : if (mrRefTokens.size() <= 1)
510 : {
511 : // Source data consists of only one data range.
512 378 : const ScTokenRef& p = mrRefTokens.front();
513 : ScComplexRefData aData;
514 378 : if (ScRefTokenHelper::getDoubleRefDataFromToken(aData, p))
515 : {
516 378 : if (aData.Ref1.Tab() == aData.Ref2.Tab())
517 378 : meGlue = GLUETYPE_NONE;
518 : else
519 0 : meGlue = GLUETYPE_COLS;
520 378 : mnStartCol = aData.Ref1.Col();
521 378 : mnStartRow = aData.Ref1.Row();
522 : }
523 : else
524 : {
525 0 : invalidateGlue();
526 0 : mnStartCol = 0;
527 0 : mnStartRow = 0;
528 : }
529 378 : 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 378 : void Chart2Positioner::createPositionMap()
707 : {
708 378 : if (meGlue == GLUETYPE_NA && mpPositionMap.get())
709 0 : mpPositionMap.reset();
710 :
711 378 : if (mpPositionMap.get())
712 378 : return;
713 :
714 378 : glueState();
715 :
716 378 : bool bNoGlue = (meGlue == GLUETYPE_NONE);
717 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
718 378 : auto_ptr<FormulaTokenMapMap> pCols(new FormulaTokenMapMap);
719 : SAL_WNODEPRECATED_DECLARATIONS_POP
720 378 : FormulaTokenMap* pCol = NULL;
721 378 : SCROW nNoGlueRow = 0;
722 756 : for (vector<ScTokenRef>::const_iterator itr = mrRefTokens.begin(), itrEnd = mrRefTokens.end();
723 : itr != itrEnd; ++itr)
724 : {
725 378 : const ScTokenRef& pToken = *itr;
726 :
727 378 : bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
728 378 : sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
729 378 : svl::SharedString aTabName = svl::SharedString::getEmptyString();
730 378 : if (bExternal)
731 0 : aTabName = pToken->GetString();
732 :
733 : ScComplexRefData aData;
734 378 : if( !ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr) )
735 0 : break;
736 378 : const ScSingleRefData& s = aData.Ref1;
737 378 : const ScSingleRefData& e = aData.Ref2;
738 378 : SCCOL nCol1 = s.Col(), nCol2 = e.Col();
739 378 : SCROW nRow1 = s.Row(), nRow2 = e.Row();
740 378 : SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
741 :
742 756 : 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 378 : sal_uInt32 nInsCol = (static_cast<sal_uInt32>(nTab) << 16) |
748 378 : (bNoGlue ? 0 : static_cast<sal_uInt32>(nCol1));
749 :
750 3117 : for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol)
751 : {
752 2739 : FormulaTokenMapMap::const_iterator it = pCols->find(nInsCol);
753 2739 : if (it == pCols->end())
754 : {
755 2739 : pCol = new FormulaTokenMap;
756 2739 : (*pCols)[ nInsCol ] = pCol;
757 : }
758 : else
759 0 : pCol = it->second;
760 :
761 2739 : sal_uInt32 nInsRow = static_cast<sal_uInt32>(bNoGlue ? nNoGlueRow : nRow1);
762 8765 : for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow, ++nInsRow)
763 : {
764 : ScSingleRefData aCellData;
765 6026 : aCellData.InitFlags();
766 6026 : aCellData.SetFlag3D(true);
767 6026 : aCellData.SetColRel(false);
768 6026 : aCellData.SetRowRel(false);
769 6026 : aCellData.SetTabRel(false);
770 6026 : aCellData.SetAbsCol(nCol);
771 6026 : aCellData.SetAbsRow(nRow);
772 6026 : aCellData.SetAbsTab(nTab);
773 :
774 6026 : if (pCol->find(nInsRow) == pCol->end())
775 : {
776 6026 : if (bExternal)
777 0 : (*pCol)[ nInsRow ] = new ScExternalSingleRefToken(nFileId, aTabName, aCellData);
778 : else
779 6026 : (*pCol)[ nInsRow ] = new ScSingleRefToken(aCellData);
780 : }
781 : }
782 : }
783 : }
784 378 : nNoGlueRow += nRow2 - nRow1 + 1;
785 378 : }
786 :
787 378 : bool bFillRowHeader = mbRowHeaders;
788 378 : bool bFillColumnHeader = mbColHeaders;
789 :
790 378 : SCSIZE nAllColCount = static_cast<SCSIZE>(pCols->size());
791 378 : SCSIZE nAllRowCount = 0;
792 378 : if (!pCols->empty())
793 : {
794 378 : pCol = pCols->begin()->second;
795 378 : if (mbDummyUpperLeft)
796 0 : if (pCol->find(0) == pCol->end())
797 0 : (*pCol)[ 0 ] = NULL; // Dummy fuer Beschriftung
798 378 : nAllRowCount = static_cast<SCSIZE>(pCol->size());
799 : }
800 :
801 378 : if( nAllColCount!=0 && nAllRowCount!=0 )
802 : {
803 378 : if (bNoGlue)
804 : {
805 378 : FormulaTokenMap* pFirstCol = pCols->begin()->second;
806 1394 : for (FormulaTokenMap::const_iterator it1 = pFirstCol->begin(); it1 != pFirstCol->end(); ++it1)
807 : {
808 1016 : sal_uInt32 nKey = it1->first;
809 7042 : for (FormulaTokenMapMap::const_iterator it2 = pCols->begin(); it2 != pCols->end(); ++it2)
810 : {
811 6026 : pCol = it2->second;
812 6026 : 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 378 : bFillRowHeader, bFillColumnHeader, *pCols, mpDoc));
822 :
823 : // Destroy all column instances.
824 3117 : for (FormulaTokenMapMap::const_iterator it = pCols->begin(); it != pCols->end(); ++it)
825 : {
826 2739 : pCol = it->second;
827 2739 : delete pCol;
828 378 : }
829 : }
830 :
831 : /**
832 : * Function object to create a range string from a token list.
833 : */
834 99260 : class Tokens2RangeString : public unary_function<ScTokenRef, void>
835 : {
836 : public:
837 24815 : Tokens2RangeString(ScDocument* pDoc, FormulaGrammar::Grammar eGram, sal_Unicode cRangeSep) :
838 24815 : mpRangeStr(new OUStringBuffer),
839 : mpDoc(pDoc),
840 : meGrammar(eGram),
841 : mcRangeSep(cRangeSep),
842 49630 : mbFirst(true)
843 : {
844 24815 : }
845 :
846 49630 : Tokens2RangeString(const Tokens2RangeString& r) :
847 : mpRangeStr(r.mpRangeStr),
848 : mpDoc(r.mpDoc),
849 : meGrammar(r.meGrammar),
850 : mcRangeSep(r.mcRangeSep),
851 49630 : mbFirst(r.mbFirst)
852 : {
853 49630 : }
854 :
855 24773 : void operator() (const ScTokenRef& rToken)
856 : {
857 24773 : ScCompiler aCompiler(mpDoc, ScAddress(0,0,0));
858 24773 : aCompiler.SetGrammar(meGrammar);
859 49546 : OUString aStr;
860 24773 : aCompiler.CreateStringFromToken(aStr, rToken.get());
861 24773 : if (mbFirst)
862 24757 : mbFirst = false;
863 : else
864 16 : mpRangeStr->append(mcRangeSep);
865 49546 : mpRangeStr->append(aStr);
866 24773 : }
867 :
868 24815 : void getString(OUString& rStr)
869 : {
870 24815 : rStr = mpRangeStr->makeStringAndClear();
871 24815 : }
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 440 : class Tokens2RangeStringXML : public unary_function<ScTokenRef, void>
890 : {
891 : public:
892 110 : Tokens2RangeStringXML(ScDocument* pDoc) :
893 110 : mpRangeStr(new OUStringBuffer),
894 : mpDoc(pDoc),
895 : mcRangeSep(' '),
896 : mcAddrSep(':'),
897 220 : mbFirst(true)
898 : {
899 110 : }
900 :
901 220 : Tokens2RangeStringXML(const Tokens2RangeStringXML& r) :
902 : mpRangeStr(r.mpRangeStr),
903 : mpDoc(r.mpDoc),
904 : mcRangeSep(r.mcRangeSep),
905 : mcAddrSep(r.mcAddrSep),
906 220 : mbFirst(r.mbFirst)
907 : {
908 220 : }
909 :
910 116 : void operator() (const ScTokenRef& rToken)
911 : {
912 116 : if (mbFirst)
913 110 : mbFirst = false;
914 : else
915 6 : mpRangeStr->append(mcRangeSep);
916 :
917 230 : ScTokenRef aStart, aEnd;
918 116 : bool bValidToken = splitRangeToken(rToken, aStart, aEnd);
919 : OSL_ENSURE(bValidToken, "invalid token");
920 116 : if (!bValidToken)
921 118 : return;
922 228 : ScCompiler aCompiler(mpDoc, ScAddress(0,0,0));
923 114 : aCompiler.SetGrammar(FormulaGrammar::GRAM_ENGLISH);
924 : {
925 114 : OUString aStr;
926 114 : aCompiler.CreateStringFromToken(aStr, aStart.get());
927 114 : mpRangeStr->append(aStr);
928 : }
929 114 : mpRangeStr->append(mcAddrSep);
930 : {
931 114 : OUString aStr;
932 114 : aCompiler.CreateStringFromToken(aStr, aEnd.get());
933 114 : mpRangeStr->append(aStr);
934 114 : }
935 : }
936 :
937 110 : void getString(OUString& rStr)
938 : {
939 110 : rStr = mpRangeStr->makeStringAndClear();
940 110 : }
941 :
942 : private:
943 116 : bool splitRangeToken(const ScTokenRef& pToken, ScTokenRef& rStart, ScTokenRef& rEnd) const
944 : {
945 : ScComplexRefData aData;
946 116 : bool bIsRefToken = ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken);
947 : OSL_ENSURE(bIsRefToken, "invalid token");
948 116 : if (!bIsRefToken)
949 2 : return false;
950 114 : bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
951 114 : sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
952 114 : svl::SharedString aTabName = svl::SharedString::getEmptyString();
953 114 : if (bExternal)
954 0 : aTabName = pToken->GetString();
955 :
956 : // In saving to XML, we don't prepend address with '$'.
957 114 : setRelative(aData.Ref1);
958 114 : setRelative(aData.Ref2);
959 :
960 : // In XML, the range must explicitly specify sheet name.
961 114 : aData.Ref1.SetFlag3D(true);
962 114 : aData.Ref2.SetFlag3D(true);
963 :
964 114 : if (bExternal)
965 0 : rStart.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref1));
966 : else
967 114 : rStart.reset(new ScSingleRefToken(aData.Ref1));
968 :
969 114 : if (bExternal)
970 0 : rEnd.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref2));
971 : else
972 114 : rEnd.reset(new ScSingleRefToken(aData.Ref2));
973 114 : return true;
974 : }
975 :
976 228 : void setRelative(ScSingleRefData& rData) const
977 : {
978 228 : rData.SetColRel(true);
979 228 : rData.SetRowRel(true);
980 228 : rData.SetTabRel(true);
981 228 : }
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 24815 : void lcl_convertTokensToString(OUString& rStr, const vector<ScTokenRef>& rTokens, ScDocument* pDoc)
992 : {
993 24815 : const sal_Unicode cRangeSep = ScCompiler::GetNativeSymbolChar(ocSep);
994 24815 : FormulaGrammar::Grammar eGrammar = pDoc->GetGrammar();
995 24815 : Tokens2RangeString func(pDoc, eGrammar, cRangeSep);
996 24815 : func = ::std::for_each(rTokens.begin(), rTokens.end(), func);
997 24815 : func.getString(rStr);
998 24815 : }
999 :
1000 : } // anonymous namespace
1001 :
1002 : // DataProvider ==============================================================
1003 :
1004 39 : ScChart2DataProvider::ScChart2DataProvider( ScDocument* pDoc )
1005 : : m_pDocument( pDoc)
1006 : , m_aPropSet(lcl_GetDataProviderPropertyMap())
1007 39 : , m_bIncludeHiddenCells( true)
1008 : {
1009 39 : if ( m_pDocument )
1010 39 : m_pDocument->AddUnoObject( *this);
1011 39 : }
1012 :
1013 9 : ScChart2DataProvider::~ScChart2DataProvider()
1014 : {
1015 3 : if ( m_pDocument )
1016 0 : m_pDocument->RemoveUnoObject( *this);
1017 6 : }
1018 :
1019 :
1020 156 : void ScChart2DataProvider::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
1021 : {
1022 312 : if ( rHint.ISA( SfxSimpleHint ) &&
1023 156 : ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
1024 : {
1025 37 : m_pDocument = NULL;
1026 : }
1027 156 : }
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 2135 : 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 2135 : Reference< chart2::data::XLabeledDataSequence > xResult;
1061 2135 : bool bHasValues = pValueTokens.get() && !pValueTokens->empty();
1062 2135 : bool bHasLabel = pLabelTokens.get() && !pLabelTokens->empty();
1063 2135 : if( bHasValues || bHasLabel )
1064 : {
1065 : try
1066 : {
1067 2135 : Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1068 2135 : if ( xContext.is() )
1069 : {
1070 2135 : xResult.set( chart2::data::LabeledDataSequence::create(xContext), uno::UNO_QUERY_THROW );
1071 : }
1072 2135 : if ( bHasValues )
1073 : {
1074 2134 : Reference< chart2::data::XDataSequence > xSeq( new ScChart2DataSequence( pDoc, xDP, pValueTokens.release(), bIncludeHiddenCells ) );
1075 2134 : xResult->setValues( xSeq );
1076 : }
1077 2135 : if ( bHasLabel )
1078 : {
1079 923 : Reference< chart2::data::XDataSequence > xLabelSeq( new ScChart2DataSequence( pDoc, xDP, pLabelTokens.release(), bIncludeHiddenCells ) );
1080 923 : xResult->setLabel( xLabelSeq );
1081 2135 : }
1082 : }
1083 0 : catch( const uno::Exception& )
1084 : {
1085 : }
1086 : }
1087 2135 : 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 94 : bool lcl_addUpperLeftCornerIfMissing(vector<ScTokenRef>& rRefTokens,
1102 : SCROW nCornerRowCount=1, SCCOL nCornerColumnCount=1)
1103 : {
1104 : using ::std::max;
1105 : using ::std::min;
1106 :
1107 94 : if (rRefTokens.empty())
1108 0 : return false;
1109 :
1110 94 : SCCOL nMinCol = MAXCOLCOUNT;
1111 94 : SCROW nMinRow = MAXROWCOUNT;
1112 94 : SCCOL nMaxCol = 0;
1113 94 : SCROW nMaxRow = 0;
1114 94 : SCTAB nTab = 0;
1115 :
1116 94 : sal_uInt16 nFileId = 0;
1117 94 : svl::SharedString aExtTabName;
1118 94 : bool bExternal = false;
1119 :
1120 94 : vector<ScTokenRef>::const_iterator itr = rRefTokens.begin(), itrEnd = rRefTokens.end();
1121 :
1122 : // Get the first ref token.
1123 188 : ScTokenRef pToken = *itr;
1124 94 : switch (pToken->GetType())
1125 : {
1126 : case svSingleRef:
1127 : {
1128 1 : const ScSingleRefData& rData = pToken->GetSingleRef();
1129 1 : nMinCol = rData.Col();
1130 1 : nMinRow = rData.Row();
1131 1 : nMaxCol = rData.Col();
1132 1 : nMaxRow = rData.Row();
1133 1 : nTab = rData.Tab();
1134 : }
1135 1 : break;
1136 : case svDoubleRef:
1137 : {
1138 93 : const ScComplexRefData& rData = pToken->GetDoubleRef();
1139 93 : nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1140 93 : nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1141 93 : nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1142 93 : nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1143 93 : nTab = rData.Ref1.Tab();
1144 : }
1145 93 : 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 110 : for (++itr; itr != itrEnd; ++itr)
1180 : {
1181 16 : pToken = *itr;
1182 16 : switch (pToken->GetType())
1183 : {
1184 : case svSingleRef:
1185 : {
1186 16 : const ScSingleRefData& rData = pToken->GetSingleRef();
1187 :
1188 16 : nMinCol = min(nMinCol, rData.Col());
1189 16 : nMinRow = min(nMinRow, rData.Row());
1190 16 : nMaxCol = max(nMaxCol, rData.Col());
1191 16 : nMaxRow = max(nMaxRow, rData.Row());
1192 16 : if (nTab != rData.Tab() || bExternal)
1193 0 : return false;
1194 : }
1195 16 : 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 187 : if (nMinRow >= nMaxRow || nMinCol >= nMaxCol ||
1257 279 : nMinRow >= MAXROWCOUNT || nMinCol >= MAXCOLCOUNT ||
1258 186 : nMaxRow >= MAXROWCOUNT || nMaxCol >= MAXCOLCOUNT)
1259 : {
1260 : // Invalid range. Bail out.
1261 1 : 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 93 : bool bRight = false, bBottom = false, bDiagonal = false;
1270 125 : for (itr = rRefTokens.begin(); itr != itrEnd; ++itr)
1271 : {
1272 109 : pToken = *itr;
1273 109 : switch (pToken->GetType())
1274 : {
1275 : case svSingleRef:
1276 : case svExternalSingleRef:
1277 : {
1278 16 : const ScSingleRefData& rData = pToken->GetSingleRef();
1279 16 : if (rData.Col() == nMinCol && rData.Row() == nMinRow)
1280 : // The corner cell is contained.
1281 0 : return false;
1282 :
1283 16 : if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow)
1284 16 : bRight = true;
1285 :
1286 16 : if (rData.Col() == nMinCol && rData.Row() == nMinRow+nCornerRowCount)
1287 0 : bBottom = true;
1288 :
1289 16 : if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow+nCornerRowCount)
1290 0 : bDiagonal = true;
1291 : }
1292 16 : break;
1293 : case svDoubleRef:
1294 : case svExternalDoubleRef:
1295 : {
1296 93 : const ScComplexRefData& rData = pToken->GetDoubleRef();
1297 93 : const ScSingleRefData& r1 = rData.Ref1;
1298 93 : const ScSingleRefData& r2 = rData.Ref2;
1299 372 : if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1300 263 : r1.Row() <= nMinRow && nMinRow <= r2.Row())
1301 : // The corner cell is contained.
1302 77 : return false;
1303 :
1304 64 : if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1305 32 : r1.Row() <= nMinRow && nMinRow <= r2.Row())
1306 0 : bRight = true;
1307 :
1308 64 : if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1309 48 : r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1310 16 : bBottom = true;
1311 :
1312 64 : if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1313 48 : r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1314 16 : bDiagonal = true;
1315 : }
1316 16 : break;
1317 : default:
1318 : ;
1319 : }
1320 : }
1321 :
1322 16 : if (!bRight || !bBottom || !bDiagonal)
1323 : // Not all the adjacent cells are included. Bail out.
1324 0 : return false;
1325 :
1326 : ScSingleRefData aData;
1327 16 : aData.InitFlags();
1328 16 : aData.SetFlag3D(true);
1329 16 : aData.SetAbsCol(nMinCol);
1330 16 : aData.SetAbsRow(nMinRow);
1331 16 : aData.SetAbsTab(nTab);
1332 :
1333 16 : if( nCornerRowCount==1 && nCornerColumnCount==1 )
1334 : {
1335 16 : 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 16 : ScTokenRef pCorner(new ScSingleRefToken(aData));
1344 16 : ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1345 16 : }
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 110 : return true;
1369 : }
1370 :
1371 : class ShrinkRefTokenToDataRange : std::unary_function<ScTokenRef, void>
1372 : {
1373 : ScDocument* mpDoc;
1374 : public:
1375 596 : ShrinkRefTokenToDataRange(ScDocument* pDoc) : mpDoc(pDoc) {}
1376 612 : void operator() (ScTokenRef& rRef)
1377 : {
1378 612 : if (ScRefTokenHelper::isExternalRef(rRef))
1379 107 : 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 612 : if (rRef->GetType() != svDoubleRef)
1384 107 : return;
1385 :
1386 505 : ScComplexRefData& rData = rRef->GetDoubleRef();
1387 505 : ScSingleRefData& s = rData.Ref1;
1388 505 : ScSingleRefData& e = rData.Ref2;
1389 :
1390 505 : SCCOL nMinCol = MAXCOL, nMaxCol = 0;
1391 505 : SCROW nMinRow = MAXROW, nMaxRow = 0;
1392 :
1393 : // Determine the smallest range that encompasses the data ranges of all sheets.
1394 505 : SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
1395 1010 : for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
1396 : {
1397 505 : SCCOL nCol1 = 0, nCol2 = MAXCOL;
1398 505 : SCROW nRow1 = 0, nRow2 = MAXROW;
1399 505 : mpDoc->ShrinkToDataArea(nTab, nCol1, nRow1, nCol2, nRow2);
1400 505 : nMinCol = std::min(nMinCol, nCol1);
1401 505 : nMinRow = std::min(nMinRow, nRow1);
1402 505 : nMaxCol = std::max(nMaxCol, nCol2);
1403 505 : nMaxRow = std::max(nMaxRow, nRow2);
1404 : }
1405 :
1406 : // Shrink range to the data range if applicable.
1407 505 : if (s.Col() < nMinCol)
1408 0 : s.SetAbsCol(nMinCol);
1409 505 : if (s.Row() < nMinRow)
1410 0 : s.SetAbsRow(nMinRow);
1411 505 : if (e.Col() > nMaxCol)
1412 0 : e.SetAbsCol(nMaxCol);
1413 505 : if (e.Row() > nMaxRow)
1414 0 : e.SetAbsRow(nMaxRow);
1415 : }
1416 : };
1417 :
1418 596 : void shrinkToDataRange(ScDocument* pDoc, vector<ScTokenRef>& rRefTokens)
1419 : {
1420 596 : std::for_each(rRefTokens.begin(), rRefTokens.end(), ShrinkRefTokenToDataRange(pDoc));
1421 596 : }
1422 :
1423 : }
1424 :
1425 : uno::Reference< chart2::data::XDataSource> SAL_CALL
1426 436 : ScChart2DataProvider::createDataSource(
1427 : const uno::Sequence< beans::PropertyValue >& aArguments )
1428 : throw( lang::IllegalArgumentException, uno::RuntimeException, std::exception)
1429 : {
1430 436 : SolarMutexGuard aGuard;
1431 436 : if ( ! m_pDocument )
1432 0 : throw uno::RuntimeException();
1433 :
1434 436 : uno::Reference< chart2::data::XDataSource> xResult;
1435 436 : bool bLabel = true;
1436 436 : bool bCategories = false;
1437 436 : bool bOrientCol = true;
1438 872 : OUString aRangeRepresentation;
1439 872 : uno::Sequence< sal_Int32 > aSequenceMapping;
1440 436 : sal_Bool bTimeBased = false;
1441 2336 : for(sal_Int32 i = 0; i < aArguments.getLength(); ++i)
1442 : {
1443 1900 : if ( aArguments[i].Name == "DataRowSource" )
1444 : {
1445 436 : chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
1446 436 : 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 436 : bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
1453 : }
1454 1464 : else if ( aArguments[i].Name == "FirstCellAsLabel" )
1455 : {
1456 436 : bLabel = ::cppu::any2bool(aArguments[i].Value);
1457 : }
1458 1028 : else if ( aArguments[i].Name == "HasCategories" )
1459 : {
1460 436 : bCategories = ::cppu::any2bool(aArguments[i].Value);
1461 : }
1462 592 : else if ( aArguments[i].Name == "CellRangeRepresentation" )
1463 : {
1464 436 : aArguments[i].Value >>= aRangeRepresentation;
1465 : }
1466 156 : else if ( aArguments[i].Name == "SequenceMapping" )
1467 : {
1468 0 : aArguments[i].Value >>= aSequenceMapping;
1469 : }
1470 156 : else if ( aArguments[i].Name == "TimeBased" )
1471 : {
1472 0 : aArguments[i].Value >>= bTimeBased;
1473 : }
1474 : }
1475 :
1476 872 : vector<ScTokenRef> aRefTokens;
1477 436 : const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1478 : ScRefTokenHelper::compileRangeRepresentation(
1479 436 : aRefTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1480 436 : if (aRefTokens.empty())
1481 : // Invalid range representation. Bail out.
1482 58 : throw lang::IllegalArgumentException();
1483 :
1484 378 : SCTAB nTimeBasedStart = MAXTAB;
1485 378 : SCTAB nTimeBasedEnd = 0;
1486 378 : 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 378 : if(!bTimeBased)
1508 378 : shrinkToDataRange(m_pDocument, aRefTokens);
1509 :
1510 378 : if (bLabel)
1511 94 : lcl_addUpperLeftCornerIfMissing(aRefTokens); //#i90669#
1512 :
1513 378 : bool bColHeaders = (bOrientCol ? bLabel : bCategories );
1514 378 : bool bRowHeaders = (bOrientCol ? bCategories : bLabel );
1515 :
1516 756 : Chart2Positioner aChPositioner(m_pDocument, aRefTokens);
1517 378 : aChPositioner.setHeaders(bColHeaders, bRowHeaders);
1518 :
1519 378 : const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap();
1520 378 : if (!pChartMap)
1521 : // No chart position map instance. Bail out.
1522 0 : return xResult;
1523 :
1524 378 : ScChart2DataSource* pDS = NULL;
1525 756 : ::std::list< Reference< chart2::data::XLabeledDataSequence > > aSeqs;
1526 :
1527 : // Fill Categories
1528 378 : if( bCategories )
1529 : {
1530 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
1531 63 : auto_ptr< vector<ScTokenRef> > pValueTokens(NULL);
1532 : SAL_WNODEPRECATED_DECLARATIONS_POP
1533 63 : if (bOrientCol)
1534 61 : pValueTokens.reset(pChartMap->getAllRowHeaderRanges());
1535 : else
1536 2 : pValueTokens.reset(pChartMap->getAllColHeaderRanges());
1537 :
1538 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
1539 : auto_ptr< vector<ScTokenRef> > pLabelTokens(
1540 126 : pChartMap->getLeftUpperCornerRanges());
1541 : SAL_WNODEPRECATED_DECLARATIONS_POP
1542 :
1543 : Reference< chart2::data::XLabeledDataSequence > xCategories = lcl_createLabeledDataSequenceFromTokens(
1544 126 : pValueTokens, pLabelTokens, m_pDocument, this, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1545 63 : if ( xCategories.is() )
1546 : {
1547 63 : aSeqs.push_back( xCategories );
1548 63 : }
1549 : }
1550 :
1551 : // Fill Serieses (values and label)
1552 378 : sal_Int32 nCount = bOrientCol ? pChartMap->getDataColCount() : pChartMap->getDataRowCount();
1553 2450 : for (sal_Int32 i = 0; i < nCount; ++i)
1554 : {
1555 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
1556 2072 : auto_ptr< vector<ScTokenRef> > pValueTokens(NULL);
1557 4144 : auto_ptr< vector<ScTokenRef> > pLabelTokens(NULL);
1558 : SAL_WNODEPRECATED_DECLARATIONS_POP
1559 2072 : if (bOrientCol)
1560 : {
1561 1786 : pValueTokens.reset(pChartMap->getDataColRanges(static_cast<SCCOL>(i)));
1562 1786 : pLabelTokens.reset(pChartMap->getColHeaderRanges(static_cast<SCCOL>(i)));
1563 : }
1564 : else
1565 : {
1566 286 : pValueTokens.reset(pChartMap->getDataRowRanges(static_cast<SCROW>(i)));
1567 286 : pLabelTokens.reset(pChartMap->getRowHeaderRanges(static_cast<SCROW>(i)));
1568 : }
1569 : Reference< chart2::data::XLabeledDataSequence > xChartSeries = lcl_createLabeledDataSequenceFromTokens(
1570 4144 : pValueTokens, pLabelTokens, m_pDocument, this, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1571 2072 : if ( xChartSeries.is() && xChartSeries->getValues().is() && xChartSeries->getValues()->getData().getLength() )
1572 : {
1573 2072 : aSeqs.push_back( xChartSeries );
1574 : }
1575 2072 : }
1576 :
1577 378 : pDS = new ScChart2DataSource(m_pDocument);
1578 378 : ::std::list< Reference< chart2::data::XLabeledDataSequence > >::iterator aItr( aSeqs.begin() );
1579 378 : ::std::list< Reference< chart2::data::XLabeledDataSequence > >::iterator aEndItr( aSeqs.end() );
1580 :
1581 : //reorder labeled sequences according to aSequenceMapping
1582 756 : ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aSeqVector;
1583 2891 : while(aItr != aEndItr)
1584 : {
1585 2135 : aSeqVector.push_back(*aItr);
1586 2135 : ++aItr;
1587 : }
1588 :
1589 756 : ::std::map< sal_Int32, Reference< chart2::data::XLabeledDataSequence > > aSequenceMap;
1590 378 : 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 378 : ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::iterator aVectorItr( aSeqVector.begin() );
1602 378 : ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::iterator aVectorEndItr( aSeqVector.end() );
1603 2891 : while(aVectorItr != aVectorEndItr)
1604 : {
1605 2135 : Reference< chart2::data::XLabeledDataSequence > xSeq( *aVectorItr );
1606 2135 : if ( xSeq.is() )
1607 : {
1608 2135 : pDS->AddLabeledSequence( xSeq );
1609 : }
1610 2135 : ++aVectorItr;
1611 2135 : }
1612 :
1613 378 : xResult.set( pDS );
1614 814 : 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 676 : class InsertTabNumber : public unary_function<ScTokenRef, void>
1624 : {
1625 : public:
1626 169 : InsertTabNumber() :
1627 169 : mpTabNumList(new list<SCTAB>())
1628 : {
1629 169 : }
1630 :
1631 338 : InsertTabNumber(const InsertTabNumber& r) :
1632 338 : mpTabNumList(r.mpTabNumList)
1633 : {
1634 338 : }
1635 :
1636 127 : void operator() (const ScTokenRef& pToken) const
1637 : {
1638 127 : if (!ScRefTokenHelper::isRef(pToken))
1639 127 : return;
1640 :
1641 127 : const ScSingleRefData& r = pToken->GetSingleRef();
1642 127 : mpTabNumList->push_back(r.Tab());
1643 : }
1644 :
1645 169 : void getList(list<SCTAB>& rList)
1646 : {
1647 169 : mpTabNumList->swap(rList);
1648 169 : }
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 2056 : RangeAnalyzer::RangeAnalyzer()
1676 : : mbEmpty(true)
1677 : , mbAmbiguous(false)
1678 : , mnRowCount(0)
1679 : , mnColumnCount(0)
1680 : , mnStartColumn(-1)
1681 2056 : , mnStartRow(-1)
1682 : {
1683 2056 : }
1684 :
1685 1620 : void RangeAnalyzer::initRangeAnalyzer( const vector<ScTokenRef>& rTokens )
1686 : {
1687 1620 : mnRowCount=0;
1688 1620 : mnColumnCount=0;
1689 1620 : mnStartColumn = -1;
1690 1620 : mnStartRow = -1;
1691 1620 : mbAmbiguous=false;
1692 1620 : if( rTokens.empty() )
1693 : {
1694 0 : mbEmpty=true;
1695 1620 : return;
1696 : }
1697 1620 : mbEmpty=false;
1698 :
1699 1620 : vector<ScTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
1700 3240 : for (; itr != itrEnd ; ++itr)
1701 : {
1702 1620 : ScTokenRef aRefToken = *itr;
1703 1620 : StackVar eVar = aRefToken->GetType();
1704 1620 : if (eVar == svDoubleRef || eVar == svExternalDoubleRef)
1705 : {
1706 803 : const ScComplexRefData& r = aRefToken->GetDoubleRef();
1707 803 : if (r.Ref1.Tab() == r.Ref2.Tab())
1708 : {
1709 803 : mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(r.Ref2.Col() - r.Ref1.Col())+1));
1710 803 : mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(r.Ref2.Row() - r.Ref1.Row())+1));
1711 803 : if( mnStartColumn == -1 )
1712 : {
1713 803 : mnStartColumn = r.Ref1.Col();
1714 803 : 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 817 : else if (eVar == svSingleRef || eVar == svExternalSingleRef)
1726 : {
1727 804 : const ScSingleRefData& r = aRefToken->GetSingleRef();
1728 804 : mnColumnCount = std::max<SCCOL>( mnColumnCount, 1);
1729 804 : mnRowCount = std::max<SCROW>( mnRowCount, 1);
1730 804 : if( mnStartColumn == -1 )
1731 : {
1732 804 : mnStartColumn = r.Col();
1733 804 : mnStartRow = r.Row();
1734 : }
1735 : else
1736 : {
1737 0 : if (mnStartColumn != r.Col() && mnStartRow != r.Row())
1738 0 : mbAmbiguous=true;
1739 804 : }
1740 : }
1741 : else
1742 13 : mbAmbiguous=true;
1743 1620 : }
1744 : }
1745 :
1746 1618 : void RangeAnalyzer::analyzeRange( sal_Int32& rnDataInRows,
1747 : sal_Int32& rnDataInCols,
1748 : bool& rbRowSourceAmbiguous ) const
1749 : {
1750 1618 : if(!mbEmpty && !mbAmbiguous)
1751 : {
1752 3022 : if( mnRowCount==1 && mnColumnCount>1 )
1753 7 : ++rnDataInRows;
1754 1504 : else if( mnColumnCount==1 && mnRowCount>1 )
1755 750 : ++rnDataInCols;
1756 754 : else if( mnRowCount>1 && mnColumnCount>1 )
1757 0 : rbRowSourceAmbiguous = true;
1758 : }
1759 107 : else if( !mbEmpty )
1760 13 : rbRowSourceAmbiguous = true;
1761 1618 : }
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 4 : bool RangeAnalyzer::inSameSingleColumn( RangeAnalyzer& rOther )
1772 : {
1773 8 : if( mnStartColumn==rOther.mnStartColumn &&
1774 8 : mnColumnCount==1 && rOther.mnColumnCount==1 )
1775 4 : return true;
1776 0 : return false;
1777 : }
1778 :
1779 : } //end anonymous namespace
1780 :
1781 169 : uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments(
1782 : const uno::Reference< chart2::data::XDataSource >& xDataSource )
1783 : throw (uno::RuntimeException, std::exception)
1784 : {
1785 169 : ::std::vector< beans::PropertyValue > aResult;
1786 169 : bool bRowSourceDetected = false;
1787 169 : bool bFirstCellAsLabel = false;
1788 169 : bool bHasCategories = false;
1789 338 : OUString sRangeRep;
1790 :
1791 169 : bool bHasCategoriesLabels = false;
1792 338 : vector<ScTokenRef> aAllCategoriesValuesTokens;
1793 338 : vector<ScTokenRef> aAllSeriesLabelTokens;
1794 :
1795 169 : chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS;
1796 :
1797 338 : vector<ScTokenRef> aAllTokens;
1798 :
1799 : // parse given data source and collect infos
1800 : {
1801 169 : SolarMutexGuard aGuard;
1802 : OSL_ENSURE( m_pDocument, "No Document -> no detectArguments" );
1803 169 : if(!m_pDocument ||!xDataSource.is())
1804 0 : return lcl_VectorToSequence( aResult );
1805 :
1806 169 : sal_Int32 nDataInRows = 0;
1807 169 : sal_Int32 nDataInCols = 0;
1808 169 : bool bRowSourceAmbiguous = false;
1809 :
1810 338 : Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences());
1811 169 : const sal_Int32 nCount( aSequences.getLength());
1812 169 : RangeAnalyzer aPrevLabel,aPrevValues;
1813 1028 : for( sal_Int32 nIdx=0; nIdx<nCount; ++nIdx )
1814 : {
1815 859 : Reference< chart2::data::XLabeledDataSequence > xLS(aSequences[nIdx]);
1816 859 : if( xLS.is() )
1817 : {
1818 859 : bool bThisIsCategories = false;
1819 859 : if(!bHasCategories)
1820 : {
1821 219 : Reference< beans::XPropertySet > xSeqProp( xLS->getValues(), uno::UNO_QUERY );
1822 438 : OUString aRole;
1823 438 : if( xSeqProp.is() && (xSeqProp->getPropertyValue("Role") >>= aRole) &&
1824 219 : aRole == "categories" )
1825 269 : bThisIsCategories = bHasCategories = true;
1826 : }
1827 :
1828 859 : RangeAnalyzer aLabel,aValues;
1829 : // label
1830 859 : Reference< chart2::data::XDataSequence > xLabel( xLS->getLabel());
1831 859 : if( xLabel.is())
1832 : {
1833 761 : bFirstCellAsLabel = true;
1834 761 : vector<ScTokenRef> aTokens;
1835 761 : const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1836 : ScRefTokenHelper::compileRangeRepresentation(
1837 761 : aTokens, xLabel->getSourceRangeRepresentation(), m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1838 761 : aLabel.initRangeAnalyzer(aTokens);
1839 761 : vector<ScTokenRef>::const_iterator itr = aTokens.begin(), itrEnd = aTokens.end();
1840 1522 : for (; itr != itrEnd; ++itr)
1841 : {
1842 761 : ScRefTokenHelper::join(aAllTokens, *itr, ScAddress());
1843 761 : if(!bThisIsCategories)
1844 715 : ScRefTokenHelper::join(aAllSeriesLabelTokens, *itr, ScAddress());
1845 : }
1846 761 : if(bThisIsCategories)
1847 46 : bHasCategoriesLabels=true;
1848 : }
1849 : // values
1850 1718 : Reference< chart2::data::XDataSequence > xValues( xLS->getValues());
1851 859 : if( xValues.is())
1852 : {
1853 859 : vector<ScTokenRef> aTokens;
1854 859 : const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1855 : ScRefTokenHelper::compileRangeRepresentation(
1856 859 : aTokens, xValues->getSourceRangeRepresentation(), m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1857 859 : aValues.initRangeAnalyzer(aTokens);
1858 859 : vector<ScTokenRef>::const_iterator itr = aTokens.begin(), itrEnd = aTokens.end();
1859 1718 : for (; itr != itrEnd; ++itr)
1860 : {
1861 859 : ScRefTokenHelper::join(aAllTokens, *itr, ScAddress());
1862 859 : if(bThisIsCategories)
1863 50 : ScRefTokenHelper::join(aAllCategoriesValuesTokens, *itr, ScAddress());
1864 859 : }
1865 : }
1866 : //detect row source
1867 859 : 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 809 : if (!bRowSourceAmbiguous)
1870 : {
1871 809 : aValues.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1872 809 : aLabel.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1873 809 : if (nDataInRows > 1 && nDataInCols > 1)
1874 0 : bRowSourceAmbiguous = true;
1875 809 : else if( !bRowSourceAmbiguous && !nDataInRows && !nDataInCols )
1876 : {
1877 4 : if( aValues.inSameSingleColumn( aLabel ) )
1878 4 : 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 859 : aPrevValues=aValues;
1897 1718 : aPrevLabel=aLabel;
1898 : }
1899 859 : }
1900 :
1901 169 : if (!bRowSourceAmbiguous)
1902 : {
1903 156 : bRowSourceDetected = true;
1904 : eRowSource = ( nDataInRows > 0
1905 : ? chart::ChartDataRowSource_ROWS
1906 156 : : 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 13 : : chart::ChartDataRowSource_COLUMNS );
1914 169 : }
1915 :
1916 : }
1917 :
1918 : // TableNumberList
1919 : {
1920 169 : list<SCTAB> aTableNumList;
1921 338 : InsertTabNumber func;
1922 169 : func = ::std::for_each(aAllTokens.begin(), aAllTokens.end(), func);
1923 169 : func.getList(aTableNumList);
1924 : aResult.push_back(
1925 : beans::PropertyValue( OUString("TableNumberList"), -1,
1926 : uno::makeAny( lcl_createTableNumberList( aTableNumList ) ),
1927 338 : beans::PropertyState_DIRECT_VALUE ));
1928 : }
1929 :
1930 : // DataRowSource (calculated before)
1931 169 : if( bRowSourceDetected )
1932 : {
1933 : aResult.push_back(
1934 : beans::PropertyValue( OUString("DataRowSource"), -1,
1935 156 : uno::makeAny( eRowSource ), beans::PropertyState_DIRECT_VALUE ));
1936 : }
1937 :
1938 : // HasCategories
1939 169 : if( bRowSourceDetected )
1940 : {
1941 : aResult.push_back(
1942 : beans::PropertyValue( OUString("HasCategories"), -1,
1943 156 : uno::makeAny( bHasCategories ), beans::PropertyState_DIRECT_VALUE ));
1944 : }
1945 :
1946 : // FirstCellAsLabel
1947 169 : if( bRowSourceDetected )
1948 : {
1949 : aResult.push_back(
1950 : beans::PropertyValue( OUString("FirstCellAsLabel"), -1,
1951 156 : uno::makeAny( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE ));
1952 : }
1953 :
1954 : // Add the left upper corner to the range if it is missing.
1955 169 : 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 169 : lcl_convertTokensToString(sRangeRep, aAllTokens, m_pDocument);
1973 :
1974 : // add cell range property
1975 : aResult.push_back(
1976 : beans::PropertyValue( OUString("CellRangeRepresentation"), -1,
1977 169 : uno::makeAny( sRangeRep ), beans::PropertyState_DIRECT_VALUE ));
1978 :
1979 : //Sequence Mapping
1980 169 : bool bSequencesReordered = true;//todo detect this above or detect this sequence mapping cheaper ...
1981 169 : if( bSequencesReordered && bRowSourceDetected )
1982 : {
1983 156 : bool bDifferentIndexes = false;
1984 :
1985 156 : std::vector< sal_Int32 > aSequenceMappingVector;
1986 :
1987 312 : uno::Reference< chart2::data::XDataSource > xCompareDataSource;
1988 : try
1989 : {
1990 156 : xCompareDataSource.set( this->createDataSource( lcl_VectorToSequence( aResult ) ) );
1991 : }
1992 58 : 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 156 : if( xDataSource.is() && xCompareDataSource.is() )
1999 : {
2000 : uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > aOldSequences(
2001 98 : xCompareDataSource->getDataSequences() );
2002 : uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aNewSequences(
2003 196 : xDataSource->getDataSequences());
2004 :
2005 196 : OUString aOldLabel;
2006 196 : OUString aNewLabel;
2007 196 : OUString aOldValues;
2008 196 : OUString aNewValues;
2009 196 : OUString aEmpty;
2010 :
2011 931 : for( sal_Int32 nNewIndex = 0; nNewIndex < aNewSequences.getLength(); nNewIndex++ )
2012 : {
2013 833 : uno::Reference< chart2::data::XLabeledDataSequence> xNew( aNewSequences[nNewIndex] );
2014 5749 : for( sal_Int32 nOldIndex = 0; nOldIndex < aOldSequences.getLength(); nOldIndex++ )
2015 : {
2016 5733 : uno::Reference< chart2::data::XLabeledDataSequence> xOld( aOldSequences[nOldIndex] );
2017 :
2018 5733 : if( xOld.is() && xNew.is() )
2019 : {
2020 5733 : aOldLabel = aNewLabel = aOldValues = aNewValues = aEmpty;
2021 5733 : if( xOld.is() && xOld->getLabel().is() )
2022 5300 : aOldLabel = xOld->getLabel()->getSourceRangeRepresentation();
2023 5733 : if( xNew.is() && xNew->getLabel().is() )
2024 5268 : aNewLabel = xNew->getLabel()->getSourceRangeRepresentation();
2025 5733 : if( xOld.is() && xOld->getValues().is() )
2026 5733 : aOldValues = xOld->getValues()->getSourceRangeRepresentation();
2027 5733 : if( xNew.is() && xNew->getValues().is() )
2028 5733 : aNewValues = xNew->getValues()->getSourceRangeRepresentation();
2029 :
2030 11466 : if( aOldLabel.equals(aNewLabel)
2031 5733 : && ( aOldValues.equals(aNewValues) ) )
2032 : {
2033 817 : if( nOldIndex!=nNewIndex )
2034 0 : bDifferentIndexes = true;
2035 817 : aSequenceMappingVector.push_back(nOldIndex);
2036 817 : break;
2037 : }
2038 : }
2039 4916 : }
2040 931 : }
2041 : }
2042 :
2043 156 : 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 156 : }
2050 : }
2051 :
2052 338 : 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 186 : ScChart2DataProvider::createDataSequenceByRangeRepresentation(
2071 : const OUString& aRangeRepresentation )
2072 : throw (lang::IllegalArgumentException,
2073 : uno::RuntimeException, std::exception)
2074 : {
2075 186 : SolarMutexGuard aGuard;
2076 186 : uno::Reference< chart2::data::XDataSequence > xResult;
2077 :
2078 : OSL_ENSURE( m_pDocument, "No Document -> no createDataSequenceByRangeRepresentation" );
2079 186 : if(!m_pDocument || aRangeRepresentation.isEmpty())
2080 0 : return xResult;
2081 :
2082 372 : vector<ScTokenRef> aRefTokens;
2083 186 : const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2084 : ScRefTokenHelper::compileRangeRepresentation(
2085 186 : aRefTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2086 186 : if (aRefTokens.empty())
2087 7 : return xResult;
2088 :
2089 179 : shrinkToDataRange(m_pDocument, aRefTokens);
2090 :
2091 : // ScChart2DataSequence manages the life cycle of pRefTokens.
2092 179 : vector<ScTokenRef>* pRefTokens = new vector<ScTokenRef>();
2093 179 : pRefTokens->swap(aRefTokens);
2094 179 : xResult.set(new ScChart2DataSequence(m_pDocument, this, pRefTokens, m_bIncludeHiddenCells));
2095 :
2096 365 : 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 39 : ScChart2DataProvider::createDataSequenceByFormulaTokens(
2169 : const Sequence<sheet::FormulaToken>& aTokens )
2170 : throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
2171 : {
2172 39 : Reference<chart2::data::XDataSequence> xResult;
2173 39 : if (aTokens.getLength() <= 0)
2174 0 : return xResult;
2175 :
2176 78 : ScTokenArray aCode;
2177 39 : if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
2178 0 : return xResult;
2179 :
2180 39 : sal_uInt16 n = aCode.GetLen();
2181 39 : if (!n)
2182 0 : return xResult;
2183 :
2184 78 : vector<ScTokenRef> aRefTokens;
2185 39 : const formula::FormulaToken* pFirst = aCode.First();
2186 39 : const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2187 78 : for (const formula::FormulaToken* p = aCode.First(); p; p = aCode.Next())
2188 : {
2189 39 : 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 39 : ScTokenRef pNew(static_cast<ScToken*>(p->Clone()));
2220 39 : aRefTokens.push_back(pNew);
2221 : }
2222 39 : break;
2223 : default:
2224 0 : throw lang::IllegalArgumentException();
2225 : }
2226 : }
2227 :
2228 39 : if (aRefTokens.empty())
2229 0 : return xResult;
2230 :
2231 39 : shrinkToDataRange(m_pDocument, aRefTokens);
2232 :
2233 : // ScChart2DataSequence manages the life cycle of pRefTokens.
2234 39 : vector<ScTokenRef>* pRefTokens = new vector<ScTokenRef>();
2235 39 : pRefTokens->swap(aRefTokens);
2236 39 : xResult.set(new ScChart2DataSequence(m_pDocument, this, pRefTokens, m_bIncludeHiddenCells));
2237 39 : return xResult;
2238 : }
2239 :
2240 : // XRangeXMLConversion ---------------------------------------------------
2241 :
2242 110 : OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const OUString& sRangeRepresentation )
2243 : throw ( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
2244 : {
2245 110 : OUString aRet;
2246 110 : if (!m_pDocument)
2247 0 : return aRet;
2248 :
2249 110 : if (sRangeRepresentation.isEmpty())
2250 : // Empty data range is allowed.
2251 0 : return aRet;
2252 :
2253 220 : vector<ScTokenRef> aRefTokens;
2254 110 : const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2255 : ScRefTokenHelper::compileRangeRepresentation(
2256 110 : aRefTokens, sRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2257 110 : if (aRefTokens.empty())
2258 0 : throw lang::IllegalArgumentException();
2259 :
2260 220 : Tokens2RangeStringXML converter(m_pDocument);
2261 110 : converter = ::std::for_each(aRefTokens.begin(), aRefTokens.end(), converter);
2262 110 : converter.getString(aRet);
2263 :
2264 110 : return aRet;
2265 : }
2266 :
2267 109 : OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const OUString& sXMLRange )
2268 : throw ( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
2269 : {
2270 109 : const sal_Unicode cSep = ' ';
2271 109 : const sal_Unicode cQuote = '\'';
2272 :
2273 109 : 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 109 : OUString aRet;
2308 109 : ScRangeStringConverter::GetStringFromXMLRangeString(aRet, sXMLRange, m_pDocument);
2309 109 : 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 173 : 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 173 : if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2332 : {
2333 173 : if ( !(rValue >>= m_bIncludeHiddenCells))
2334 0 : throw lang::IllegalArgumentException();
2335 : }
2336 : else
2337 0 : throw beans::UnknownPropertyException();
2338 173 : }
2339 :
2340 :
2341 67 : uno::Any SAL_CALL ScChart2DataProvider::getPropertyValue(
2342 : const OUString& rPropertyName)
2343 : throw( beans::UnknownPropertyException,
2344 : lang::WrappedTargetException, uno::RuntimeException, std::exception)
2345 : {
2346 67 : uno::Any aRet;
2347 67 : if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2348 0 : aRet <<= m_bIncludeHiddenCells;
2349 67 : else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
2350 : {
2351 : // This is a read-only property.
2352 67 : aRet <<= static_cast<sal_Bool>(m_pDocument->PastingDrawFromOtherDoc());
2353 : }
2354 : else
2355 0 : throw beans::UnknownPropertyException();
2356 67 : 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 378 : ScChart2DataSource::ScChart2DataSource( ScDocument* pDoc)
2402 378 : : m_pDocument( pDoc)
2403 : {
2404 378 : if ( m_pDocument )
2405 378 : m_pDocument->AddUnoObject( *this);
2406 378 : }
2407 :
2408 :
2409 1134 : ScChart2DataSource::~ScChart2DataSource()
2410 : {
2411 378 : if ( m_pDocument )
2412 378 : m_pDocument->RemoveUnoObject( *this);
2413 756 : }
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 378 : ScChart2DataSource::getDataSequences() throw ( uno::RuntimeException, std::exception)
2428 : {
2429 378 : SolarMutexGuard aGuard;
2430 :
2431 378 : LabeledList::const_iterator aItr(m_aLabeledSequences.begin());
2432 378 : LabeledList::const_iterator aEndItr(m_aLabeledSequences.end());
2433 :
2434 378 : uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aRet(m_aLabeledSequences.size());
2435 :
2436 378 : sal_Int32 i = 0;
2437 2891 : while (aItr != aEndItr)
2438 : {
2439 2135 : aRet[i] = *aItr;
2440 2135 : ++i;
2441 2135 : ++aItr;
2442 : }
2443 :
2444 378 : return aRet;
2445 : }
2446 :
2447 2135 : void ScChart2DataSource::AddLabeledSequence(const uno::Reference < chart2::data::XLabeledDataSequence >& xNew)
2448 : {
2449 2135 : m_aLabeledSequences.push_back(xNew);
2450 2135 : }
2451 :
2452 : // DataSequence ==============================================================
2453 :
2454 5467 : ScChart2DataSequence::Item::Item() :
2455 5467 : mfValue(0.0), mbIsValue(false)
2456 : {
2457 5467 : ::rtl::math::setNan(&mfValue);
2458 5467 : }
2459 :
2460 3275 : ScChart2DataSequence::HiddenRangeListener::HiddenRangeListener(ScChart2DataSequence& rParent) :
2461 3275 : mrParent(rParent)
2462 : {
2463 3275 : }
2464 :
2465 6078 : ScChart2DataSequence::HiddenRangeListener::~HiddenRangeListener()
2466 : {
2467 6078 : }
2468 :
2469 0 : void ScChart2DataSequence::HiddenRangeListener::notify()
2470 : {
2471 0 : mrParent.setDataChangedHint(true);
2472 0 : }
2473 :
2474 3275 : 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 3275 : , mnCurrentTab(0)
2494 : {
2495 : OSL_ENSURE(pTokens, "reference token list is null");
2496 :
2497 3275 : if ( m_pDocument )
2498 : {
2499 3275 : m_pDocument->AddUnoObject( *this);
2500 3275 : 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 3275 : }
2514 :
2515 9117 : ScChart2DataSequence::~ScChart2DataSequence()
2516 : {
2517 3039 : if ( m_pDocument )
2518 : {
2519 2914 : m_pDocument->RemoveUnoObject( *this);
2520 2914 : if (m_pHiddenListener.get())
2521 : {
2522 2914 : ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
2523 2914 : if (pCLC)
2524 2914 : pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
2525 : }
2526 2914 : StopListeningToAllExternalRefs();
2527 : }
2528 :
2529 3039 : delete m_pValueListener;
2530 6078 : }
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 3975 : void ScChart2DataSequence::BuildDataCache()
2564 : {
2565 3975 : m_bExtDataRebuildQueued = false;
2566 :
2567 3975 : if (!m_aDataArray.empty())
2568 3192 : return;
2569 :
2570 2379 : if (!m_pTokens.get())
2571 : {
2572 : OSL_FAIL("m_pTokens == NULL! Something is wrong.");
2573 0 : return;
2574 : }
2575 :
2576 2379 : StopListeningToAllExternalRefs();
2577 :
2578 2379 : ::std::list<sal_Int32> aHiddenValues;
2579 2379 : sal_Int32 nDataCount = 0;
2580 2379 : sal_Int32 nHiddenValueCount = 0;
2581 :
2582 4758 : for (vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
2583 : itr != itrEnd; ++itr)
2584 : {
2585 2379 : if (ScRefTokenHelper::isExternalRef(*itr))
2586 : {
2587 0 : nDataCount += FillCacheFromExternalRef(*itr);
2588 : }
2589 : else
2590 : {
2591 2379 : ScRange aRange;
2592 2379 : if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress()))
2593 7 : continue;
2594 :
2595 2372 : SCCOL nLastCol = -1;
2596 2372 : SCROW nLastRow = -1;
2597 4744 : for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
2598 : {
2599 5629 : for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
2600 : {
2601 8724 : for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
2602 : {
2603 5467 : bool bColHidden = m_pDocument->ColHidden(nCol, nTab, NULL, &nLastCol);
2604 5467 : bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, NULL, &nLastRow);
2605 :
2606 5467 : 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 5467 : m_aDataArray.push_back(Item());
2617 5467 : Item& rItem = m_aDataArray.back();
2618 5467 : ++nDataCount;
2619 :
2620 5467 : ScAddress aAdr(nCol, nRow, nTab);
2621 5467 : rItem.maString = m_pDocument->GetString(aAdr);
2622 :
2623 5467 : switch (m_pDocument->GetCellType(aAdr))
2624 : {
2625 : case CELLTYPE_VALUE:
2626 2939 : rItem.mfValue = m_pDocument->GetValue(aAdr);
2627 2939 : rItem.mbIsValue = true;
2628 2939 : break;
2629 : case CELLTYPE_FORMULA:
2630 : {
2631 229 : ScFormulaCell* pFCell = m_pDocument->GetFormulaCell(aAdr);
2632 229 : if (!pFCell)
2633 0 : break;
2634 229 : sal_uInt16 nErr = pFCell->GetErrCode();
2635 229 : if (nErr)
2636 0 : break;
2637 :
2638 229 : if (pFCell->IsValue())
2639 : {
2640 229 : rItem.mfValue = pFCell->GetValue();
2641 229 : rItem.mbIsValue = true;
2642 : }
2643 : }
2644 229 : 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 2379 : m_aHiddenValues.realloc(nHiddenValueCount);
2659 2379 : sal_Int32* pArr = m_aHiddenValues.getArray();
2660 2379 : ::std::list<sal_Int32>::const_iterator itr = aHiddenValues.begin(), itrEnd = aHiddenValues.end();
2661 2379 : for (;itr != itrEnd; ++itr, ++pArr)
2662 0 : *pArr = *itr;
2663 :
2664 : // Clear the data series cache when the array is re-built.
2665 2379 : 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 5293 : void ScChart2DataSequence::StopListeningToAllExternalRefs()
2792 : {
2793 5293 : if (!m_pExtRefListener.get())
2794 10586 : 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 610 : void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
2840 : {
2841 610 : if ( rHint.ISA( SfxSimpleHint ) )
2842 : {
2843 610 : sal_uLong nId = static_cast<const SfxSimpleHint&>(rHint).GetId();
2844 610 : if ( nId ==SFX_HINT_DYING )
2845 : {
2846 355 : m_pDocument = NULL;
2847 : }
2848 255 : else if ( nId == SFX_HINT_DATACHANGED )
2849 : {
2850 : // delayed broadcast as in ScCellRangesBase
2851 :
2852 235 : if ( m_bGotDataChangedHint && m_pDocument )
2853 : {
2854 20 : m_aDataArray.clear();
2855 20 : lang::EventObject aEvent;
2856 20 : aEvent.Source.set((cppu::OWeakObject*)this);
2857 :
2858 20 : if( m_pDocument )
2859 : {
2860 40 : for ( sal_uInt16 n=0; n<m_aValueListeners.size(); n++ )
2861 20 : m_pDocument->AddUnoListenerCall( m_aValueListeners[n], aEvent );
2862 : }
2863 :
2864 20 : m_bGotDataChangedHint = false;
2865 : }
2866 : }
2867 20 : else if ( nId == SC_HINT_CALCALL )
2868 : {
2869 : // broadcast from DoHardRecalc - set m_bGotDataChangedHint
2870 : // (SFX_HINT_DATACHANGED follows separately)
2871 :
2872 20 : if ( !m_aValueListeners.empty() )
2873 20 : 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 610 : }
2953 :
2954 :
2955 706 : IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, SfxHint*, pHint )
2956 : {
2957 706 : if ( m_pDocument && pHint && pHint->ISA( SfxSimpleHint ) &&
2958 353 : ((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 353 : 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 2512 : uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
3020 : throw (uno::RuntimeException, std::exception)
3021 : {
3022 2512 : SolarMutexGuard aGuard;
3023 2512 : if ( !m_pDocument)
3024 0 : throw uno::RuntimeException();
3025 :
3026 2512 : BuildDataCache();
3027 :
3028 2512 : if (!m_aMixedDataCache.getLength())
3029 : {
3030 : // Build a cache for the 1st time...
3031 :
3032 2164 : sal_Int32 nCount = m_aDataArray.size();
3033 2164 : m_aMixedDataCache.realloc(nCount);
3034 2164 : uno::Any* pArr = m_aMixedDataCache.getArray();
3035 2164 : ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3036 7341 : for (; itr != itrEnd; ++itr, ++pArr)
3037 : {
3038 5177 : if (itr->mbIsValue)
3039 3057 : *pArr <<= itr->mfValue;
3040 : else
3041 2120 : *pArr <<= itr->maString;
3042 : }
3043 : }
3044 2512 : return m_aMixedDataCache;
3045 : }
3046 :
3047 : // XNumericalDataSequence --------------------------------------------------
3048 :
3049 586 : uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData()
3050 : throw (uno::RuntimeException, std::exception)
3051 : {
3052 586 : SolarMutexGuard aGuard;
3053 586 : if ( !m_pDocument)
3054 0 : throw uno::RuntimeException();
3055 :
3056 586 : BuildDataCache();
3057 :
3058 : double fNAN;
3059 586 : ::rtl::math::setNan(&fNAN);
3060 :
3061 586 : sal_Int32 nCount = m_aDataArray.size();
3062 586 : uno::Sequence<double> aSeq(nCount);
3063 586 : double* pArr = aSeq.getArray();
3064 586 : ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3065 3051 : for (; itr != itrEnd; ++itr, ++pArr)
3066 2465 : *pArr = itr->mbIsValue ? itr->mfValue : fNAN;
3067 :
3068 586 : return aSeq;
3069 : }
3070 :
3071 : // XTextualDataSequence --------------------------------------------------
3072 :
3073 505 : uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::getTextualData()
3074 : throw (uno::RuntimeException, std::exception)
3075 : {
3076 505 : SolarMutexGuard aGuard;
3077 505 : uno::Sequence<OUString> aSeq;
3078 505 : if ( !m_pDocument )
3079 0 : throw uno::RuntimeException();
3080 :
3081 505 : BuildDataCache();
3082 :
3083 505 : sal_Int32 nCount = m_aDataArray.size();
3084 505 : if ( nCount > 0 )
3085 : {
3086 499 : aSeq = uno::Sequence<OUString>(nCount);
3087 499 : OUString* pArr = aSeq.getArray();
3088 499 : ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3089 998 : for(; itr != itrEnd; ++itr, ++pArr)
3090 499 : *pArr = itr->maString;
3091 : }
3092 6 : else if ( m_pTokens.get() && m_pTokens->front() )
3093 : {
3094 6 : if( m_pTokens->front()->GetType() == svString )
3095 : {
3096 6 : aSeq = uno::Sequence<OUString>(1);
3097 6 : aSeq[0] = m_pTokens->front()->GetString().getString();
3098 : }
3099 : }
3100 :
3101 505 : return aSeq;
3102 : }
3103 :
3104 24646 : OUString SAL_CALL ScChart2DataSequence::getSourceRangeRepresentation()
3105 : throw ( uno::RuntimeException, std::exception)
3106 : {
3107 24646 : SolarMutexGuard aGuard;
3108 24646 : OUString aStr;
3109 : OSL_ENSURE( m_pDocument, "No Document -> no SourceRangeRepresentation" );
3110 24646 : if (m_pDocument && m_pTokens.get())
3111 24646 : lcl_convertTokensToString(aStr, *m_pTokens, m_pDocument);
3112 :
3113 24646 : 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 51 : AccumulateRangeSize() :
3126 51 : mnCols(0), mnRows(0) {}
3127 :
3128 102 : AccumulateRangeSize(const AccumulateRangeSize& r) :
3129 102 : mnCols(r.mnCols), mnRows(r.mnRows) {}
3130 :
3131 51 : void operator() (const ScTokenRef& pToken)
3132 : {
3133 51 : ScRange r;
3134 51 : bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3135 51 : ScRefTokenHelper::getRangeFromToken(r, pToken, ScAddress(), bExternal);
3136 51 : r.Justify();
3137 51 : mnCols += r.aEnd.Col() - r.aStart.Col() + 1;
3138 51 : mnRows += r.aEnd.Row() - r.aStart.Row() + 1;
3139 51 : }
3140 :
3141 51 : SCCOL getCols() const { return mnCols; }
3142 51 : 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 204 : class GenerateLabelStrings : public unary_function<ScTokenRef, void>
3153 : {
3154 : public:
3155 51 : GenerateLabelStrings(sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) :
3156 51 : mpLabels(new Sequence<OUString>(nSize)),
3157 : meOrigin(eOrigin),
3158 : mnCount(0),
3159 102 : mbColumn(bColumn) {}
3160 :
3161 102 : GenerateLabelStrings(const GenerateLabelStrings& r) :
3162 : mpLabels(r.mpLabels),
3163 : meOrigin(r.meOrigin),
3164 : mnCount(r.mnCount),
3165 102 : mbColumn(r.mbColumn) {}
3166 :
3167 51 : void operator() (const ScTokenRef& pToken)
3168 : {
3169 51 : bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3170 51 : ScRange aRange;
3171 51 : ScRefTokenHelper::getRangeFromToken(aRange, pToken, ScAddress(), bExternal);
3172 51 : OUString* pArr = mpLabels->getArray();
3173 51 : if (mbColumn)
3174 : {
3175 75 : for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
3176 : {
3177 48 : if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3178 : {
3179 21 : OUString aString = ScGlobal::GetRscString(STR_COLUMN);
3180 21 : aString += " ";
3181 21 : ScAddress aPos( nCol, 0, 0 );
3182 42 : OUString aColStr(aPos.Format(SCA_VALID_COL, NULL));
3183 21 : aString += aColStr;
3184 42 : pArr[mnCount] = aString;
3185 : }
3186 : else //only indices for categories
3187 27 : pArr[mnCount] = OUString::number( mnCount+1 );
3188 48 : ++mnCount;
3189 : }
3190 : }
3191 : else
3192 : {
3193 103 : for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
3194 : {
3195 79 : 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 79 : pArr[mnCount] = OUString::number( mnCount+1 );
3203 79 : ++mnCount;
3204 : }
3205 : }
3206 51 : }
3207 :
3208 51 : 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 51 : uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
3220 : throw (uno::RuntimeException, std::exception)
3221 : {
3222 51 : SolarMutexGuard aGuard;
3223 51 : if ( !m_pDocument)
3224 0 : throw uno::RuntimeException();
3225 :
3226 51 : if (!m_pTokens.get())
3227 0 : return Sequence<OUString>();
3228 :
3229 : // Determine the total size of all ranges.
3230 51 : AccumulateRangeSize func;
3231 51 : func = ::std::for_each(m_pTokens->begin(), m_pTokens->end(), func);
3232 51 : SCCOL nCols = func.getCols();
3233 51 : SCROW nRows = func.getRows();
3234 :
3235 : // Detemine whether this is column-major or row-major.
3236 51 : bool bColumn = true;
3237 51 : if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
3238 : (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
3239 : {
3240 51 : if (nRows > nCols)
3241 : {
3242 45 : if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
3243 21 : bColumn = true;
3244 : else
3245 24 : bColumn = false;
3246 : }
3247 6 : else if (nCols > nRows)
3248 : {
3249 6 : if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
3250 0 : bColumn = false;
3251 : else
3252 6 : bColumn = true;
3253 : }
3254 : else
3255 0 : return Sequence<OUString>();
3256 : }
3257 :
3258 : // Generate label strings based on the info so far.
3259 51 : sal_Int32 nCount = bColumn ? nCols : nRows;
3260 102 : GenerateLabelStrings genLabels(nCount, eOrigin, bColumn);
3261 51 : genLabels = ::std::for_each(m_pTokens->begin(), m_pTokens->end(), genLabels);
3262 102 : Sequence<OUString> aSeq = genLabels.getLabels();
3263 :
3264 102 : return aSeq;
3265 : }
3266 :
3267 : namespace {
3268 :
3269 2846 : sal_uLong getDisplayNumberFormat(ScDocument* pDoc, const ScAddress& rPos)
3270 : {
3271 2846 : sal_uLong nFormat = pDoc->GetNumberFormat(rPos); // original format from cell.
3272 2846 : return nFormat;
3273 : }
3274 :
3275 : }
3276 :
3277 2846 : ::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 2846 : bool bGetSeriesFormat = (nIndex == -1);
3282 :
3283 2846 : SolarMutexGuard aGuard;
3284 2846 : if ( !m_pDocument || !m_pTokens.get())
3285 0 : return 0;
3286 :
3287 : // TODO: Handle external references too.
3288 :
3289 2846 : sal_Int32 nCount = 0;
3290 :
3291 5692 : ScRangeList aRanges;
3292 2846 : ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens, ScAddress());
3293 2846 : for (size_t i = 0, n = aRanges.size(); i < n; ++i)
3294 : {
3295 2846 : ScRange* p = aRanges[i];
3296 2846 : for (SCTAB nTab = p->aStart.Tab(); nTab <= p->aEnd.Tab(); ++nTab)
3297 : {
3298 11972 : for (SCCOL nCol = p->aStart.Col(); nCol <= p->aEnd.Col(); ++nCol)
3299 : {
3300 11972 : if (!m_bIncludeHiddenCells)
3301 : {
3302 : // Skip hidden columns.
3303 11972 : SCCOL nLastCol = -1;
3304 11972 : bool bColHidden = m_pDocument->ColHidden(nCol, nTab, NULL, &nLastCol);
3305 11972 : if (bColHidden)
3306 : {
3307 0 : nCol = nLastCol;
3308 0 : continue;
3309 : }
3310 : }
3311 :
3312 21316 : for (SCROW nRow = p->aStart.Row(); nRow <= p->aEnd.Row(); ++nRow)
3313 : {
3314 12190 : if (!m_bIncludeHiddenCells)
3315 : {
3316 : // Skip hidden rows.
3317 12190 : SCROW nLastRow = -1;
3318 12190 : bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, NULL, &nLastRow);
3319 12190 : if (bRowHidden)
3320 : {
3321 0 : nRow = nLastRow;
3322 0 : continue;
3323 : }
3324 : }
3325 :
3326 12190 : ScAddress aPos(nCol, nRow, nTab);
3327 :
3328 12190 : if( bGetSeriesFormat )
3329 : {
3330 : // TODO: use nicer heuristic
3331 : // return format of first non-empty cell
3332 1162 : ScRefCellValue aCell;
3333 1162 : aCell.assign(*m_pDocument, aPos);
3334 1162 : if (!aCell.isEmpty())
3335 1136 : return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, aPos));
3336 : }
3337 11028 : else if( nCount == nIndex )
3338 : {
3339 1710 : return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, aPos));
3340 : }
3341 9344 : ++nCount;
3342 : }
3343 : }
3344 : }
3345 : }
3346 2846 : 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 3275 : void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3384 : throw (uno::RuntimeException, std::exception)
3385 : {
3386 : // like ScCellRangesBase::addModifyListener
3387 3275 : SolarMutexGuard aGuard;
3388 3275 : if (!m_pTokens.get() || m_pTokens->empty())
3389 3275 : return;
3390 :
3391 6550 : ScRangeList aRanges;
3392 3275 : ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens, ScAddress());
3393 : uno::Reference<util::XModifyListener> *pObj =
3394 3275 : new uno::Reference<util::XModifyListener>( aListener );
3395 3275 : m_aValueListeners.push_back( pObj );
3396 :
3397 3275 : if ( m_aValueListeners.size() == 1 )
3398 : {
3399 3275 : if (!m_pValueListener)
3400 3275 : m_pValueListener = new ScLinkListener( LINK( this, ScChart2DataSequence, ValueListenerHdl ) );
3401 :
3402 3275 : if (!m_pHiddenListener.get())
3403 3275 : m_pHiddenListener.reset(new HiddenRangeListener(*this));
3404 :
3405 3275 : if( m_pDocument )
3406 : {
3407 3275 : ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
3408 3275 : vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
3409 6550 : for (; itr != itrEnd; ++itr)
3410 : {
3411 3275 : ScRange aRange;
3412 3275 : if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress()))
3413 2 : continue;
3414 :
3415 3273 : m_pDocument->StartListeningArea( aRange, m_pValueListener );
3416 3273 : if (pCLC)
3417 3273 : pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
3418 : }
3419 : }
3420 :
3421 3275 : acquire(); // don't lose this object (one ref for all listeners)
3422 3275 : }
3423 : }
3424 :
3425 3039 : void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3426 : throw (uno::RuntimeException, std::exception)
3427 : {
3428 : // like ScCellRangesBase::removeModifyListener
3429 :
3430 3039 : SolarMutexGuard aGuard;
3431 3039 : if (!m_pTokens.get() || m_pTokens->empty())
3432 3039 : return;
3433 :
3434 3039 : acquire(); // in case the listeners have the last ref - released below
3435 :
3436 3039 : sal_uInt16 nCount = m_aValueListeners.size();
3437 6078 : for ( sal_uInt16 n=nCount; n--; )
3438 : {
3439 3039 : uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
3440 3039 : if ( rObj == aListener )
3441 : {
3442 3039 : m_aValueListeners.erase( m_aValueListeners.begin() + n );
3443 :
3444 3039 : if ( m_aValueListeners.empty() )
3445 : {
3446 3039 : if (m_pValueListener)
3447 3039 : m_pValueListener->EndListeningAll();
3448 :
3449 3039 : if (m_pHiddenListener.get() && m_pDocument)
3450 : {
3451 2914 : ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
3452 2914 : if (pCLC)
3453 2914 : pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
3454 : }
3455 :
3456 3039 : release(); // release the ref for the listeners
3457 : }
3458 :
3459 3039 : break;
3460 : }
3461 : }
3462 :
3463 3039 : release(); // might delete this object
3464 : }
3465 :
3466 : // DataSequence XPropertySet -------------------------------------------------
3467 :
3468 : uno::Reference< beans::XPropertySetInfo> SAL_CALL
3469 121 : ScChart2DataSequence::getPropertySetInfo() throw( uno::RuntimeException, std::exception)
3470 : {
3471 121 : SolarMutexGuard aGuard;
3472 : static uno::Reference<beans::XPropertySetInfo> aRef =
3473 121 : new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
3474 121 : return aRef;
3475 : }
3476 :
3477 :
3478 698 : 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 698 : if ( rPropertyName == SC_UNONAME_ROLE )
3486 : {
3487 562 : if ( !(rValue >>= m_aRole))
3488 0 : throw lang::IllegalArgumentException();
3489 : }
3490 136 : else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3491 : {
3492 136 : bool bOldValue = m_bIncludeHiddenCells;
3493 136 : if ( !(rValue >>= m_bIncludeHiddenCells))
3494 0 : throw lang::IllegalArgumentException();
3495 136 : 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 698 : }
3508 :
3509 :
3510 4689 : uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue(const OUString& rPropertyName)
3511 : throw(beans::UnknownPropertyException,
3512 : lang::WrappedTargetException,
3513 : uno::RuntimeException,
3514 : std::exception)
3515 : {
3516 4689 : uno::Any aRet;
3517 4689 : if ( rPropertyName == SC_UNONAME_ROLE )
3518 4317 : aRet <<= m_aRole;
3519 372 : else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3520 0 : aRet <<= m_bIncludeHiddenCells;
3521 372 : else if ( rPropertyName == SC_UNONAME_HIDDENVALUES )
3522 : {
3523 : // This property is read-only thus cannot be set externally via
3524 : // setPropertyValue(...).
3525 372 : BuildDataCache();
3526 372 : 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 4689 : 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: */
|