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