Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / sc / source / ui / unoobj / chart2uno.cxx
blob4792d86b4b78d46ba3a664568e7c2c2a6b0e00cb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "chart2uno.hxx"
22 #include "miscuno.hxx"
23 #include "document.hxx"
24 #include "formulacell.hxx"
25 #include "chartpos.hxx"
26 #include "unonames.hxx"
27 #include "globstr.hrc"
28 #include "convuno.hxx"
29 #include "rangeutl.hxx"
30 #include "hints.hxx"
31 #include "unoreflist.hxx"
32 #include "compiler.hxx"
33 #include "reftokenhelper.hxx"
34 #include "chartlis.hxx"
35 #include "tokenuno.hxx"
36 #include "docsh.hxx"
37 #include "cellvalue.hxx"
38 #include "tokenarray.hxx"
39 #include "scmatrix.hxx"
41 #include <formula/opcode.hxx>
42 #include <svl/sharedstring.hxx>
44 #include <sfx2/objsh.hxx>
45 #include <vcl/svapp.hxx>
47 #include <com/sun/star/beans/UnknownPropertyException.hpp>
48 #include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
49 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
50 #include <com/sun/star/table/XCellRange.hpp>
51 #include <com/sun/star/table/CellAddress.hpp>
52 #include <com/sun/star/text/XText.hpp>
53 #include <comphelper/extract.hxx>
54 #include <comphelper/processfactory.hxx>
56 #include <rtl/math.hxx>
57 #include <boost/checked_delete.hpp>
59 SC_SIMPLE_SERVICE_INFO( ScChart2DataProvider, "ScChart2DataProvider",
60 "com.sun.star.chart2.data.DataProvider")
61 SC_SIMPLE_SERVICE_INFO( ScChart2DataSource, "ScChart2DataSource",
62 "com.sun.star.chart2.data.DataSource")
63 SC_SIMPLE_SERVICE_INFO( ScChart2DataSequence, "ScChart2DataSequence",
64 "com.sun.star.chart2.data.DataSequence")
66 using namespace ::com::sun::star;
67 using namespace ::formula;
68 using ::com::sun::star::uno::Sequence;
69 using ::com::sun::star::uno::Reference;
70 using ::std::auto_ptr;
71 using ::std::vector;
72 using ::std::list;
73 using ::std::distance;
74 using ::std::unary_function;
75 using ::boost::shared_ptr;
77 namespace
79 const SfxItemPropertyMapEntry* lcl_GetDataProviderPropertyMap()
81 static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
83 { OUString(SC_UNONAME_INCLUDEHIDDENCELLS), 0, getBooleanCppuType(), 0, 0 },
84 { OUString(SC_UNONAME_USE_INTERNAL_DATA_PROVIDER), 0, getBooleanCppuType(), 0, 0 },
85 { OUString(), 0, css::uno::Type(), 0, 0 }
87 return aDataProviderPropertyMap_Impl;
90 const SfxItemPropertyMapEntry* lcl_GetDataSequencePropertyMap()
92 static const SfxItemPropertyMapEntry aDataSequencePropertyMap_Impl[] =
94 {OUString(SC_UNONAME_HIDDENVALUES), 0, getCppuType((uno::Sequence<sal_Int32>*)0 ), 0, 0 },
95 {OUString(SC_UNONAME_ROLE), 0, cppu::UnoType<com::sun::star::chart2::data::DataSequenceRole>::get(), 0, 0 },
96 {OUString(SC_UNONAME_INCLUDEHIDDENCELLS), 0, getBooleanCppuType(), 0, 0 },
97 { OUString(), 0, css::uno::Type(), 0, 0 }
99 return aDataSequencePropertyMap_Impl;
102 template< typename T >
103 ::com::sun::star::uno::Sequence< T > lcl_VectorToSequence(
104 const ::std::vector< T > & rCont )
106 ::com::sun::star::uno::Sequence< T > aResult( rCont.size());
107 ::std::copy( rCont.begin(), rCont.end(), aResult.getArray());
108 return aResult;
111 struct lcl_appendTableNumber : public ::std::unary_function< SCTAB, void >
113 lcl_appendTableNumber( OUStringBuffer & rBuffer ) :
114 m_rBuffer( rBuffer )
116 void operator() ( SCTAB nTab )
118 // there is no append with SCTAB or sal_Int16
119 m_rBuffer.append( static_cast< sal_Int32 >( nTab ));
120 m_rBuffer.append( ' ' );
122 private:
123 OUStringBuffer & m_rBuffer;
126 OUString lcl_createTableNumberList( const ::std::list< SCTAB > & rTableList )
128 OUStringBuffer aBuffer;
129 ::std::for_each( rTableList.begin(), rTableList.end(), lcl_appendTableNumber( aBuffer ));
130 // remove last trailing ' '
131 if( !aBuffer.isEmpty() )
132 aBuffer.setLength( aBuffer.getLength() - 1 );
133 return aBuffer.makeStringAndClear();
136 uno::Reference< frame::XModel > lcl_GetXModel( ScDocument * pDoc )
138 uno::Reference< frame::XModel > xModel;
139 SfxObjectShell * pObjSh( pDoc ? pDoc->GetDocumentShell() : 0 );
140 if( pObjSh )
141 xModel.set( pObjSh->GetModel());
142 return xModel;
145 struct TokenTable : boost::noncopyable
147 SCROW mnRowCount;
148 SCCOL mnColCount;
149 vector<FormulaToken*> maTokens;
151 void init( SCCOL nColCount, SCROW nRowCount )
153 mnColCount = nColCount;
154 mnRowCount = nRowCount;
155 maTokens.reserve(mnColCount*mnRowCount);
157 void clear()
159 std::for_each(maTokens.begin(), maTokens.end(), boost::checked_deleter<FormulaToken>());
162 void push_back( FormulaToken* pToken )
164 maTokens.push_back( pToken );
165 OSL_ENSURE( maTokens.size()<= static_cast<sal_uInt32>( mnColCount*mnRowCount ), "too much tokens" );
168 sal_uInt32 getIndex(SCCOL nCol, SCROW nRow) const
170 OSL_ENSURE( nCol<mnColCount, "wrong column index" );
171 OSL_ENSURE( nRow<mnRowCount, "wrong row index" );
172 sal_uInt32 nRet = static_cast<sal_uInt32>(nCol*mnRowCount + nRow);
173 OSL_ENSURE( maTokens.size()>= static_cast<sal_uInt32>( mnColCount*mnRowCount ), "too few tokens" );
174 return nRet;
177 vector<ScTokenRef>* getColRanges(SCCOL nCol) const;
178 vector<ScTokenRef>* getRowRanges(SCROW nRow) const;
179 vector<ScTokenRef>* getAllRanges() const;
182 vector<ScTokenRef>* TokenTable::getColRanges(SCCOL nCol) const
184 if (nCol >= mnColCount)
185 return NULL;
186 if( mnRowCount<=0 )
187 return NULL;
189 SAL_WNODEPRECATED_DECLARATIONS_PUSH
190 auto_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
191 SAL_WNODEPRECATED_DECLARATIONS_POP
192 sal_uInt32 nLast = getIndex(nCol, mnRowCount-1);
193 for (sal_uInt32 i = getIndex(nCol, 0); i <= nLast; ++i)
195 FormulaToken* p = maTokens[i];
196 if (!p)
197 continue;
199 ScTokenRef pCopy(static_cast<ScToken*>(p->Clone()));
200 ScRefTokenHelper::join(*pTokens, pCopy, ScAddress());
202 return pTokens.release();
205 vector<ScTokenRef>* TokenTable::getRowRanges(SCROW nRow) const
207 if (nRow >= mnRowCount)
208 return NULL;
209 if( mnColCount<=0 )
210 return NULL;
212 SAL_WNODEPRECATED_DECLARATIONS_PUSH
213 auto_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
214 SAL_WNODEPRECATED_DECLARATIONS_POP
215 sal_uInt32 nLast = getIndex(mnColCount-1, nRow);
216 for (sal_uInt32 i = getIndex(0, nRow); i <= nLast; i += mnRowCount)
218 FormulaToken* p = maTokens[i];
219 if (!p)
220 continue;
222 ScTokenRef p2(static_cast<ScToken*>(p->Clone()));
223 ScRefTokenHelper::join(*pTokens, p2, ScAddress());
225 return pTokens.release();
228 vector<ScTokenRef>* TokenTable::getAllRanges() const
230 SAL_WNODEPRECATED_DECLARATIONS_PUSH
231 auto_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
232 SAL_WNODEPRECATED_DECLARATIONS_POP
233 sal_uInt32 nStop = mnColCount*mnRowCount;
234 for (sal_uInt32 i = 0; i < nStop; i++)
236 FormulaToken* p = maTokens[i];
237 if (!p)
238 continue;
240 ScTokenRef p2(static_cast<ScToken*>(p->Clone()));
241 ScRefTokenHelper::join(*pTokens, p2, ScAddress());
243 return pTokens.release();
246 typedef std::map<sal_uInt32, FormulaToken*> FormulaTokenMap;
247 typedef std::map<sal_uInt32, FormulaTokenMap*> FormulaTokenMapMap;
249 class Chart2PositionMap
251 public:
252 Chart2PositionMap(SCCOL nColCount, SCROW nRowCount,
253 bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols,
254 ScDocument* pDoc );
255 ~Chart2PositionMap();
257 SCCOL getDataColCount() const { return mnDataColCount; }
258 SCROW getDataRowCount() const { return mnDataRowCount; }
260 vector<ScTokenRef>* getLeftUpperCornerRanges() const;
261 vector<ScTokenRef>* getAllColHeaderRanges() const;
262 vector<ScTokenRef>* getAllRowHeaderRanges() const;
264 vector<ScTokenRef>* getColHeaderRanges(SCCOL nChartCol) const;
265 vector<ScTokenRef>* getRowHeaderRanges(SCROW nChartRow) const;
267 vector<ScTokenRef>* getDataColRanges(SCCOL nCol) const;
268 vector<ScTokenRef>* getDataRowRanges(SCROW nRow) const;
270 private:
271 SCCOL mnDataColCount;
272 SCROW mnDataRowCount;
274 TokenTable maLeftUpperCorner; //nHeaderColCount*nHeaderRowCount
275 TokenTable maColHeaders; //mnDataColCount*nHeaderRowCount
276 TokenTable maRowHeaders; //nHeaderColCount*mnDataRowCount
277 TokenTable maData;//mnDataColCount*mnDataRowCount
280 Chart2PositionMap::Chart2PositionMap(SCCOL nAllColCount, SCROW nAllRowCount,
281 bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols, ScDocument* pDoc)
283 // if bFillRowHeader is true, at least the first column serves as a row header.
284 // If more than one column is pure text all the first pure text columns are used as header.
285 // Likewise, if bFillColumnHeader is true, at least the first row serves as a column header.
286 // If more than one row is pure text all the first pure text rows are used as header.
288 SCROW nHeaderRowCount = (bFillColumnHeader && nAllColCount && nAllRowCount) ? 1 : 0;
289 SCCOL nHeaderColCount = (bFillRowHeader && nAllColCount && nAllRowCount) ? 1 : 0;
291 if( nHeaderColCount || nHeaderRowCount )
293 const SCCOL nInitialHeaderColCount = nHeaderColCount;
294 //check whether there is more than one text column or row that should be added to the headers
295 SCROW nSmallestValueRowIndex = nAllRowCount;
296 bool bFoundValues = false;
297 bool bFoundAnything = false;
298 FormulaTokenMapMap::const_iterator it1 = rCols.begin();
299 for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol)
301 if (it1 != rCols.end() && nCol>=nHeaderColCount)
303 bool bFoundValuesInRow = false;
304 FormulaTokenMap* pCol = it1->second;
305 FormulaTokenMap::const_iterator it2 = pCol->begin();
306 for (SCROW nRow = 0; !bFoundValuesInRow && nRow < nSmallestValueRowIndex && it2 != pCol->end(); ++nRow)
308 FormulaToken* pToken = it2->second;
309 if (pToken && nRow>=nHeaderRowCount)
311 ScRange aRange;
312 bool bExternal = false;
313 StackVar eType = pToken->GetType();
314 if( eType==svExternal || eType==svExternalSingleRef || eType==svExternalDoubleRef || eType==svExternalName )
315 bExternal = true;//lllll todo correct?
316 ScTokenRef pSharedToken(static_cast<ScToken*>(pToken->Clone()));
317 ScRefTokenHelper::getRangeFromToken(aRange, pSharedToken, ScAddress(), bExternal);
318 SCCOL nCol1=0, nCol2=0;
319 SCROW nRow1=0, nRow2=0;
320 SCTAB nTab1=0, nTab2=0;
321 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
322 if (pDoc && pDoc->HasValueData( nCol1, nRow1, nTab1 ))
324 bFoundValuesInRow = bFoundValues = bFoundAnything = true;
325 nSmallestValueRowIndex = std::min( nSmallestValueRowIndex, nRow );
327 if( !bFoundAnything )
329 if (pDoc && pDoc->HasData( nCol1, nRow1, nTab1 ) )
330 bFoundAnything = true;
333 ++it2;
335 if(!bFoundValues && nHeaderColCount>0)
336 nHeaderColCount++;
338 ++it1;
340 if( bFoundAnything )
342 if(nHeaderRowCount>0)
344 if( bFoundValues )
345 nHeaderRowCount = nSmallestValueRowIndex;
346 else if( nAllRowCount>1 )
347 nHeaderRowCount = nAllRowCount-1;
350 else //if the cells are completely empty, just use single header rows and columns
351 nHeaderColCount = nInitialHeaderColCount;
354 mnDataColCount = nAllColCount - nHeaderColCount;
355 mnDataRowCount = nAllRowCount - nHeaderRowCount;
357 maLeftUpperCorner.init(nHeaderColCount,nHeaderRowCount);
358 maColHeaders.init(mnDataColCount,nHeaderRowCount);
359 maRowHeaders.init(nHeaderColCount,mnDataRowCount);
360 maData.init(mnDataColCount,mnDataRowCount);
362 FormulaTokenMapMap::const_iterator it1 = rCols.begin();
363 for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol)
365 if (it1 != rCols.end())
367 FormulaTokenMap* pCol = it1->second;
368 FormulaTokenMap::const_iterator it2 = pCol->begin();
369 for (SCROW nRow = 0; nRow < nAllRowCount; ++nRow)
371 FormulaToken* pToken = NULL;
372 if (it2 != pCol->end())
374 pToken = it2->second;
375 ++it2;
378 if( nCol < nHeaderColCount )
380 if( nRow < nHeaderRowCount )
381 maLeftUpperCorner.push_back(pToken);
382 else
383 maRowHeaders.push_back(pToken);
385 else if( nRow < nHeaderRowCount )
386 maColHeaders.push_back(pToken);
387 else
388 maData.push_back(pToken);
390 ++it1;
395 Chart2PositionMap::~Chart2PositionMap()
397 maLeftUpperCorner.clear();
398 maColHeaders.clear();
399 maRowHeaders.clear();
400 maData.clear();
403 vector<ScTokenRef>* Chart2PositionMap::getLeftUpperCornerRanges() const
405 return maLeftUpperCorner.getAllRanges();
407 vector<ScTokenRef>* Chart2PositionMap::getAllColHeaderRanges() const
409 return maColHeaders.getAllRanges();
411 vector<ScTokenRef>* Chart2PositionMap::getAllRowHeaderRanges() const
413 return maRowHeaders.getAllRanges();
415 vector<ScTokenRef>* Chart2PositionMap::getColHeaderRanges(SCCOL nCol) const
417 return maColHeaders.getColRanges( nCol);
419 vector<ScTokenRef>* Chart2PositionMap::getRowHeaderRanges(SCROW nRow) const
421 return maRowHeaders.getRowRanges( nRow);
424 vector<ScTokenRef>* Chart2PositionMap::getDataColRanges(SCCOL nCol) const
426 return maData.getColRanges( nCol);
429 vector<ScTokenRef>* Chart2PositionMap::getDataRowRanges(SCROW nRow) const
431 return maData.getRowRanges( nRow);
435 * Designed to be a drop-in replacement for ScChartPositioner, in order to
436 * handle external references.
438 class Chart2Positioner : boost::noncopyable
440 enum GlueType
442 GLUETYPE_NA,
443 GLUETYPE_NONE,
444 GLUETYPE_COLS,
445 GLUETYPE_ROWS,
446 GLUETYPE_BOTH
449 public:
450 Chart2Positioner(ScDocument* pDoc, const vector<ScTokenRef>& rRefTokens) :
451 mrRefTokens(rRefTokens),
452 mpPositionMap(NULL),
453 meGlue(GLUETYPE_NA),
454 mnStartCol(0),
455 mnStartRow(0),
456 mpDoc(pDoc),
457 mbColHeaders(false),
458 mbRowHeaders(false),
459 mbDummyUpperLeft(false)
463 ~Chart2Positioner()
467 void setHeaders(bool bColHeaders, bool bRowHeaders)
469 mbColHeaders = bColHeaders;
470 mbRowHeaders = bRowHeaders;
473 Chart2PositionMap* getPositionMap()
475 createPositionMap();
476 return mpPositionMap.get();
479 private:
480 void invalidateGlue();
481 void glueState();
482 void calcGlueState(SCCOL nCols, SCROW nRows);
483 void createPositionMap();
485 private:
486 const vector<ScTokenRef>& mrRefTokens;
487 boost::scoped_ptr<Chart2PositionMap> mpPositionMap;
488 GlueType meGlue;
489 SCCOL mnStartCol;
490 SCROW mnStartRow;
491 ScDocument* mpDoc;
492 bool mbColHeaders:1;
493 bool mbRowHeaders:1;
494 bool mbDummyUpperLeft:1;
497 void Chart2Positioner::invalidateGlue()
499 meGlue = GLUETYPE_NA;
500 mpPositionMap.reset();
503 void Chart2Positioner::glueState()
505 if (meGlue != GLUETYPE_NA)
506 return;
508 mbDummyUpperLeft = false;
509 if (mrRefTokens.size() <= 1)
511 // Source data consists of only one data range.
512 const ScTokenRef& p = mrRefTokens.front();
513 ScComplexRefData aData;
514 if (ScRefTokenHelper::getDoubleRefDataFromToken(aData, p))
516 if (aData.Ref1.Tab() == aData.Ref2.Tab())
517 meGlue = GLUETYPE_NONE;
518 else
519 meGlue = GLUETYPE_COLS;
520 mnStartCol = aData.Ref1.Col();
521 mnStartRow = aData.Ref1.Row();
523 else
525 invalidateGlue();
526 mnStartCol = 0;
527 mnStartRow = 0;
529 return;
532 ScComplexRefData aData;
533 ScRefTokenHelper::getDoubleRefDataFromToken(aData, mrRefTokens.front());
534 mnStartCol = aData.Ref1.Col();
535 mnStartRow = aData.Ref1.Row();
537 SCCOL nEndCol = 0;
538 SCROW nEndRow = 0;
539 for (vector<ScTokenRef>::const_iterator itr = mrRefTokens.begin(), itrEnd = mrRefTokens.end()
540 ; itr != itrEnd; ++itr)
542 ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr);
543 SCCOLROW n1 = aData.Ref1.Col();
544 SCCOLROW n2 = aData.Ref2.Col();
545 if (n1 > MAXCOL)
546 n1 = MAXCOL;
547 if (n2 > MAXCOL)
548 n2 = MAXCOL;
549 if (n1 < mnStartCol)
550 mnStartCol = static_cast<SCCOL>(n1);
551 if (n2 > nEndCol)
552 nEndCol = static_cast<SCCOL>(n2);
554 n1 = aData.Ref1.Row();
555 n2 = aData.Ref2.Row();
556 if (n1 > MAXROW)
557 n1 = MAXROW;
558 if (n2 > MAXROW)
559 n2 = MAXROW;
561 if (n1 < mnStartRow)
562 mnStartRow = static_cast<SCROW>(n1);
563 if (n2 > nEndRow)
564 nEndRow = static_cast<SCROW>(n2);
567 if (mnStartCol == nEndCol)
569 // All source data is in a single column.
570 meGlue = GLUETYPE_ROWS;
571 return;
574 if (mnStartRow == nEndRow)
576 // All source data is in a single row.
577 meGlue = GLUETYPE_COLS;
578 return;
581 // total column size
582 SCCOL nC = nEndCol - mnStartCol + 1;
584 // total row size
585 SCROW nR = nEndRow - mnStartRow + 1;
587 // #i103540# prevent invalid vector size
588 if ((nC <= 0) || (nR <= 0))
590 invalidateGlue();
591 mnStartCol = 0;
592 mnStartRow = 0;
593 return;
596 calcGlueState(nC, nR);
599 enum State { Hole = 0, Occupied = 1, Free = 2, Glue = 3 };
601 void Chart2Positioner::calcGlueState(SCCOL nColSize, SCROW nRowSize)
603 // TODO: This code can use some space optimization. Using an array to
604 // store individual cell's states is terribly inefficient esp for large
605 // data ranges; let's use flat_segment_tree to reduce memory usage here.
607 sal_uInt32 nCR = static_cast<sal_uInt32>(nColSize*nRowSize);
609 vector<State> aCellStates(nCR, Hole);
611 // Mark all referenced cells "occupied".
612 for (vector<ScTokenRef>::const_iterator itr = mrRefTokens.begin(), itrEnd = mrRefTokens.end();
613 itr != itrEnd; ++itr)
615 ScComplexRefData aData;
616 ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr);
617 SCCOL nCol1 = aData.Ref1.Col() - mnStartCol;
618 SCCOL nCol2 = aData.Ref2.Col() - mnStartCol;
619 SCROW nRow1 = aData.Ref1.Row() - mnStartRow;
620 SCROW nRow2 = aData.Ref2.Row() - mnStartRow;
621 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
622 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
624 size_t i = nCol*nRowSize + nRow;
625 aCellStates[i] = Occupied;
629 // If at least one cell in either the first column or first row is empty,
630 // we don't glue at all unless the whole column or row is empty; we expect
631 // all cells in the first column / row to be fully populated. If we have
632 // empty column or row, then we do glue by the column or row,
633 // respectively.
635 bool bGlue = true;
636 bool bGlueCols = false;
637 for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol)
639 for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
641 size_t i = nCol*nRowSize + nRow;
642 if (aCellStates[i] == Occupied)
644 if (nCol == 0 || nRow == 0)
645 break;
647 bGlue = false;
649 else
650 aCellStates[i] = Free;
652 size_t nLast = (nCol+1)*nRowSize - 1; // index for the last cell in the column.
653 if (bGlue && aCellStates[nLast] == Free)
655 // Whole column is empty.
656 aCellStates[nLast] = Glue;
657 bGlueCols = true;
661 bool bGlueRows = false;
662 for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
664 size_t i = nRow;
665 for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol, i += nRowSize)
667 if (aCellStates[i] == Occupied)
669 if (nCol == 0 || nRow == 0)
670 break;
672 bGlue = false;
674 else
675 aCellStates[i] = Free;
677 i = (nColSize-1)*nRowSize + nRow; // index for the row position in the last column.
678 if (bGlue && aCellStates[i] == Free)
680 // Whole row is empty.
681 aCellStates[i] = Glue;
682 bGlueRows = true;
686 size_t i = 1;
687 for (sal_uInt32 n = 1; bGlue && n < nCR; ++n, ++i)
688 if (aCellStates[i] == Hole)
689 bGlue = false;
691 if (bGlue)
693 if (bGlueCols && bGlueRows)
694 meGlue = GLUETYPE_BOTH;
695 else if (bGlueRows)
696 meGlue = GLUETYPE_ROWS;
697 else
698 meGlue = GLUETYPE_COLS;
699 if (aCellStates.front() != Occupied)
700 mbDummyUpperLeft = true;
702 else
703 meGlue = GLUETYPE_NONE;
706 void Chart2Positioner::createPositionMap()
708 if (meGlue == GLUETYPE_NA && mpPositionMap.get())
709 mpPositionMap.reset();
711 if (mpPositionMap.get())
712 return;
714 glueState();
716 bool bNoGlue = (meGlue == GLUETYPE_NONE);
717 SAL_WNODEPRECATED_DECLARATIONS_PUSH
718 auto_ptr<FormulaTokenMapMap> pCols(new FormulaTokenMapMap);
719 SAL_WNODEPRECATED_DECLARATIONS_POP
720 FormulaTokenMap* pCol = NULL;
721 SCROW nNoGlueRow = 0;
722 for (vector<ScTokenRef>::const_iterator itr = mrRefTokens.begin(), itrEnd = mrRefTokens.end();
723 itr != itrEnd; ++itr)
725 const ScTokenRef& pToken = *itr;
727 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
728 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
729 svl::SharedString aTabName = svl::SharedString::getEmptyString();
730 if (bExternal)
731 aTabName = pToken->GetString();
733 ScComplexRefData aData;
734 if( !ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr) )
735 break;
736 const ScSingleRefData& s = aData.Ref1;
737 const ScSingleRefData& e = aData.Ref2;
738 SCCOL nCol1 = s.Col(), nCol2 = e.Col();
739 SCROW nRow1 = s.Row(), nRow2 = e.Row();
740 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
742 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
744 // columns on secondary sheets are appended; we treat them as if
745 // all columns are on the same sheet. TODO: We can't assume that
746 // the column range is 16-bit; remove that restriction.
747 sal_uInt32 nInsCol = (static_cast<sal_uInt32>(nTab) << 16) |
748 (bNoGlue ? 0 : static_cast<sal_uInt32>(nCol1));
750 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol)
752 FormulaTokenMapMap::const_iterator it = pCols->find(nInsCol);
753 if (it == pCols->end())
755 pCol = new FormulaTokenMap;
756 (*pCols)[ nInsCol ] = pCol;
758 else
759 pCol = it->second;
761 sal_uInt32 nInsRow = static_cast<sal_uInt32>(bNoGlue ? nNoGlueRow : nRow1);
762 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow, ++nInsRow)
764 ScSingleRefData aCellData;
765 aCellData.InitFlags();
766 aCellData.SetFlag3D(true);
767 aCellData.SetColRel(false);
768 aCellData.SetRowRel(false);
769 aCellData.SetTabRel(false);
770 aCellData.SetAbsCol(nCol);
771 aCellData.SetAbsRow(nRow);
772 aCellData.SetAbsTab(nTab);
774 if (pCol->find(nInsRow) == pCol->end())
776 if (bExternal)
777 (*pCol)[ nInsRow ] = new ScExternalSingleRefToken(nFileId, aTabName, aCellData);
778 else
779 (*pCol)[ nInsRow ] = new ScSingleRefToken(aCellData);
784 nNoGlueRow += nRow2 - nRow1 + 1;
787 bool bFillRowHeader = mbRowHeaders;
788 bool bFillColumnHeader = mbColHeaders;
790 SCSIZE nAllColCount = static_cast<SCSIZE>(pCols->size());
791 SCSIZE nAllRowCount = 0;
792 if (!pCols->empty())
794 pCol = pCols->begin()->second;
795 if (mbDummyUpperLeft)
796 if (pCol->find(0) == pCol->end())
797 (*pCol)[ 0 ] = NULL; // Dummy fuer Beschriftung
798 nAllRowCount = static_cast<SCSIZE>(pCol->size());
801 if( nAllColCount!=0 && nAllRowCount!=0 )
803 if (bNoGlue)
805 FormulaTokenMap* pFirstCol = pCols->begin()->second;
806 for (FormulaTokenMap::const_iterator it1 = pFirstCol->begin(); it1 != pFirstCol->end(); ++it1)
808 sal_uInt32 nKey = it1->first;
809 for (FormulaTokenMapMap::const_iterator it2 = pCols->begin(); it2 != pCols->end(); ++it2)
811 pCol = it2->second;
812 if (pCol->find(nKey) == pCol->end())
813 (*pCol)[ nKey ] = NULL;
818 mpPositionMap.reset(
819 new Chart2PositionMap(
820 static_cast<SCCOL>(nAllColCount), static_cast<SCROW>(nAllRowCount),
821 bFillRowHeader, bFillColumnHeader, *pCols, mpDoc));
823 // Destroy all column instances.
824 for (FormulaTokenMapMap::const_iterator it = pCols->begin(); it != pCols->end(); ++it)
826 pCol = it->second;
827 delete pCol;
832 * Function object to create a range string from a token list.
834 class Tokens2RangeString : public unary_function<ScTokenRef, void>
836 public:
837 Tokens2RangeString(ScDocument* pDoc, FormulaGrammar::Grammar eGram, sal_Unicode cRangeSep) :
838 mpRangeStr(new OUStringBuffer),
839 mpDoc(pDoc),
840 meGrammar(eGram),
841 mcRangeSep(cRangeSep),
842 mbFirst(true)
846 Tokens2RangeString(const Tokens2RangeString& r) :
847 mpRangeStr(r.mpRangeStr),
848 mpDoc(r.mpDoc),
849 meGrammar(r.meGrammar),
850 mcRangeSep(r.mcRangeSep),
851 mbFirst(r.mbFirst)
855 void operator() (const ScTokenRef& rToken)
857 ScCompiler aCompiler(mpDoc, ScAddress(0,0,0));
858 aCompiler.SetGrammar(meGrammar);
859 OUString aStr;
860 aCompiler.CreateStringFromToken(aStr, rToken.get());
861 if (mbFirst)
862 mbFirst = false;
863 else
864 mpRangeStr->append(mcRangeSep);
865 mpRangeStr->append(aStr);
868 void getString(OUString& rStr)
870 rStr = mpRangeStr->makeStringAndClear();
873 private:
874 shared_ptr<OUStringBuffer> mpRangeStr;
875 ScDocument* mpDoc;
876 FormulaGrammar::Grammar meGrammar;
877 sal_Unicode mcRangeSep;
878 bool mbFirst;
882 * Function object to convert a list of tokens into a string form suitable
883 * for ODF export. In ODF, a range is expressed as
885 * (start cell address):(end cell address)
887 * and each address doesn't include any '$' symbols.
889 class Tokens2RangeStringXML : public unary_function<ScTokenRef, void>
891 public:
892 Tokens2RangeStringXML(ScDocument* pDoc) :
893 mpRangeStr(new OUStringBuffer),
894 mpDoc(pDoc),
895 mcRangeSep(' '),
896 mcAddrSep(':'),
897 mbFirst(true)
901 Tokens2RangeStringXML(const Tokens2RangeStringXML& r) :
902 mpRangeStr(r.mpRangeStr),
903 mpDoc(r.mpDoc),
904 mcRangeSep(r.mcRangeSep),
905 mcAddrSep(r.mcAddrSep),
906 mbFirst(r.mbFirst)
910 void operator() (const ScTokenRef& rToken)
912 if (mbFirst)
913 mbFirst = false;
914 else
915 mpRangeStr->append(mcRangeSep);
917 ScTokenRef aStart, aEnd;
918 bool bValidToken = splitRangeToken(rToken, aStart, aEnd);
919 OSL_ENSURE(bValidToken, "invalid token");
920 if (!bValidToken)
921 return;
922 ScCompiler aCompiler(mpDoc, ScAddress(0,0,0));
923 aCompiler.SetGrammar(FormulaGrammar::GRAM_ENGLISH);
925 OUString aStr;
926 aCompiler.CreateStringFromToken(aStr, aStart.get());
927 mpRangeStr->append(aStr);
929 mpRangeStr->append(mcAddrSep);
931 OUString aStr;
932 aCompiler.CreateStringFromToken(aStr, aEnd.get());
933 mpRangeStr->append(aStr);
937 void getString(OUString& rStr)
939 rStr = mpRangeStr->makeStringAndClear();
942 private:
943 bool splitRangeToken(const ScTokenRef& pToken, ScTokenRef& rStart, ScTokenRef& rEnd) const
945 ScComplexRefData aData;
946 bool bIsRefToken = ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken);
947 OSL_ENSURE(bIsRefToken, "invalid token");
948 if (!bIsRefToken)
949 return false;
950 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
951 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
952 svl::SharedString aTabName = svl::SharedString::getEmptyString();
953 if (bExternal)
954 aTabName = pToken->GetString();
956 // In saving to XML, we don't prepend address with '$'.
957 setRelative(aData.Ref1);
958 setRelative(aData.Ref2);
960 // In XML, the range must explicitly specify sheet name.
961 aData.Ref1.SetFlag3D(true);
962 aData.Ref2.SetFlag3D(true);
964 if (bExternal)
965 rStart.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref1));
966 else
967 rStart.reset(new ScSingleRefToken(aData.Ref1));
969 if (bExternal)
970 rEnd.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref2));
971 else
972 rEnd.reset(new ScSingleRefToken(aData.Ref2));
973 return true;
976 void setRelative(ScSingleRefData& rData) const
978 rData.SetColRel(true);
979 rData.SetRowRel(true);
980 rData.SetTabRel(true);
983 private:
984 shared_ptr<OUStringBuffer> mpRangeStr;
985 ScDocument* mpDoc;
986 sal_Unicode mcRangeSep;
987 sal_Unicode mcAddrSep;
988 bool mbFirst;
991 void lcl_convertTokensToString(OUString& rStr, const vector<ScTokenRef>& rTokens, ScDocument* pDoc)
993 const sal_Unicode cRangeSep = ScCompiler::GetNativeSymbolChar(ocSep);
994 FormulaGrammar::Grammar eGrammar = pDoc->GetGrammar();
995 Tokens2RangeString func(pDoc, eGrammar, cRangeSep);
996 func = ::std::for_each(rTokens.begin(), rTokens.end(), func);
997 func.getString(rStr);
1000 } // anonymous namespace
1002 // DataProvider ==============================================================
1004 ScChart2DataProvider::ScChart2DataProvider( ScDocument* pDoc )
1005 : m_pDocument( pDoc)
1006 , m_aPropSet(lcl_GetDataProviderPropertyMap())
1007 , m_bIncludeHiddenCells( true)
1009 if ( m_pDocument )
1010 m_pDocument->AddUnoObject( *this);
1013 ScChart2DataProvider::~ScChart2DataProvider()
1015 if ( m_pDocument )
1016 m_pDocument->RemoveUnoObject( *this);
1020 void ScChart2DataProvider::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
1022 if ( rHint.ISA( SfxSimpleHint ) &&
1023 ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
1025 m_pDocument = NULL;
1029 sal_Bool SAL_CALL ScChart2DataProvider::createDataSourcePossible( const uno::Sequence< beans::PropertyValue >& aArguments )
1030 throw (uno::RuntimeException, std::exception)
1032 SolarMutexGuard aGuard;
1033 if( ! m_pDocument )
1034 return false;
1036 OUString aRangeRepresentation;
1037 for(sal_Int32 i = 0; i < aArguments.getLength(); ++i)
1039 if ( aArguments[i].Name == "CellRangeRepresentation" )
1041 aArguments[i].Value >>= aRangeRepresentation;
1045 vector<ScTokenRef> aTokens;
1046 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1047 ScRefTokenHelper::compileRangeRepresentation(
1048 aTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1049 return !aTokens.empty();
1052 namespace
1055 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1056 Reference< chart2::data::XLabeledDataSequence > lcl_createLabeledDataSequenceFromTokens(
1057 auto_ptr< vector< ScTokenRef > > pValueTokens, auto_ptr< vector< ScTokenRef > > pLabelTokens,
1058 ScDocument* pDoc, const Reference< chart2::data::XDataProvider >& xDP, bool bIncludeHiddenCells )
1060 Reference< chart2::data::XLabeledDataSequence > xResult;
1061 bool bHasValues = pValueTokens.get() && !pValueTokens->empty();
1062 bool bHasLabel = pLabelTokens.get() && !pLabelTokens->empty();
1063 if( bHasValues || bHasLabel )
1067 Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1068 if ( xContext.is() )
1070 xResult.set( chart2::data::LabeledDataSequence::create(xContext), uno::UNO_QUERY_THROW );
1072 if ( bHasValues )
1074 Reference< chart2::data::XDataSequence > xSeq( new ScChart2DataSequence( pDoc, xDP, pValueTokens.release(), bIncludeHiddenCells ) );
1075 xResult->setValues( xSeq );
1077 if ( bHasLabel )
1079 Reference< chart2::data::XDataSequence > xLabelSeq( new ScChart2DataSequence( pDoc, xDP, pLabelTokens.release(), bIncludeHiddenCells ) );
1080 xResult->setLabel( xLabelSeq );
1083 catch( const uno::Exception& )
1087 return xResult;
1089 SAL_WNODEPRECATED_DECLARATIONS_POP
1093 * Check the current list of reference tokens, and add the upper left
1094 * corner of the minimum range that encloses all ranges if certain
1095 * conditions are met.
1097 * @param rRefTokens list of reference tokens
1099 * @return true if the corner was added, false otherwise.
1101 bool lcl_addUpperLeftCornerIfMissing(vector<ScTokenRef>& rRefTokens,
1102 SCROW nCornerRowCount=1, SCCOL nCornerColumnCount=1)
1104 using ::std::max;
1105 using ::std::min;
1107 if (rRefTokens.empty())
1108 return false;
1110 SCCOL nMinCol = MAXCOLCOUNT;
1111 SCROW nMinRow = MAXROWCOUNT;
1112 SCCOL nMaxCol = 0;
1113 SCROW nMaxRow = 0;
1114 SCTAB nTab = 0;
1116 sal_uInt16 nFileId = 0;
1117 svl::SharedString aExtTabName;
1118 bool bExternal = false;
1120 vector<ScTokenRef>::const_iterator itr = rRefTokens.begin(), itrEnd = rRefTokens.end();
1122 // Get the first ref token.
1123 ScTokenRef pToken = *itr;
1124 switch (pToken->GetType())
1126 case svSingleRef:
1128 const ScSingleRefData& rData = pToken->GetSingleRef();
1129 nMinCol = rData.Col();
1130 nMinRow = rData.Row();
1131 nMaxCol = rData.Col();
1132 nMaxRow = rData.Row();
1133 nTab = rData.Tab();
1135 break;
1136 case svDoubleRef:
1138 const ScComplexRefData& rData = pToken->GetDoubleRef();
1139 nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1140 nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1141 nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1142 nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1143 nTab = rData.Ref1.Tab();
1145 break;
1146 case svExternalSingleRef:
1148 const ScSingleRefData& rData = pToken->GetSingleRef();
1149 nMinCol = rData.Col();
1150 nMinRow = rData.Row();
1151 nMaxCol = rData.Col();
1152 nMaxRow = rData.Row();
1153 nTab = rData.Tab();
1154 nFileId = pToken->GetIndex();
1155 aExtTabName = pToken->GetString();
1156 bExternal = true;
1158 break;
1159 case svExternalDoubleRef:
1161 const ScComplexRefData& rData = pToken->GetDoubleRef();
1162 nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1163 nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1164 nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1165 nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1166 nTab = rData.Ref1.Tab();
1167 nFileId = pToken->GetIndex();
1168 aExtTabName = pToken->GetString();
1169 bExternal = true;
1171 break;
1172 default:
1176 // Determine the minimum range enclosing all data ranges. Also make sure
1177 // that they are all on the same table.
1179 for (++itr; itr != itrEnd; ++itr)
1181 pToken = *itr;
1182 switch (pToken->GetType())
1184 case svSingleRef:
1186 const ScSingleRefData& rData = pToken->GetSingleRef();
1188 nMinCol = min(nMinCol, rData.Col());
1189 nMinRow = min(nMinRow, rData.Row());
1190 nMaxCol = max(nMaxCol, rData.Col());
1191 nMaxRow = max(nMaxRow, rData.Row());
1192 if (nTab != rData.Tab() || bExternal)
1193 return false;
1195 break;
1196 case svDoubleRef:
1198 const ScComplexRefData& rData = pToken->GetDoubleRef();
1200 nMinCol = min(nMinCol, rData.Ref1.Col());
1201 nMinCol = min(nMinCol, rData.Ref2.Col());
1202 nMinRow = min(nMinRow, rData.Ref1.Row());
1203 nMinRow = min(nMinRow, rData.Ref2.Row());
1205 nMaxCol = max(nMaxCol, rData.Ref1.Col());
1206 nMaxCol = max(nMaxCol, rData.Ref2.Col());
1207 nMaxRow = max(nMaxRow, rData.Ref1.Row());
1208 nMaxRow = max(nMaxRow, rData.Ref2.Row());
1210 if (nTab != rData.Ref1.Tab() || bExternal)
1211 return false;
1213 break;
1214 case svExternalSingleRef:
1216 if (!bExternal)
1217 return false;
1219 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1220 return false;
1222 const ScSingleRefData& rData = pToken->GetSingleRef();
1224 nMinCol = min(nMinCol, rData.Col());
1225 nMinRow = min(nMinRow, rData.Row());
1226 nMaxCol = max(nMaxCol, rData.Col());
1227 nMaxRow = max(nMaxRow, rData.Row());
1229 break;
1230 case svExternalDoubleRef:
1232 if (!bExternal)
1233 return false;
1235 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1236 return false;
1238 const ScComplexRefData& rData = pToken->GetDoubleRef();
1240 nMinCol = min(nMinCol, rData.Ref1.Col());
1241 nMinCol = min(nMinCol, rData.Ref2.Col());
1242 nMinRow = min(nMinRow, rData.Ref1.Row());
1243 nMinRow = min(nMinRow, rData.Ref2.Row());
1245 nMaxCol = max(nMaxCol, rData.Ref1.Col());
1246 nMaxCol = max(nMaxCol, rData.Ref2.Col());
1247 nMaxRow = max(nMaxRow, rData.Ref1.Row());
1248 nMaxRow = max(nMaxRow, rData.Ref2.Row());
1250 break;
1251 default:
1256 if (nMinRow >= nMaxRow || nMinCol >= nMaxCol ||
1257 nMinRow >= MAXROWCOUNT || nMinCol >= MAXCOLCOUNT ||
1258 nMaxRow >= MAXROWCOUNT || nMaxCol >= MAXCOLCOUNT)
1260 // Invalid range. Bail out.
1261 return false;
1264 // Check if the following conditions are met:
1266 // 1) The upper-left corner cell is not included.
1267 // 2) The three adjacent cells of that corner cell are included.
1269 bool bRight = false, bBottom = false, bDiagonal = false;
1270 for (itr = rRefTokens.begin(); itr != itrEnd; ++itr)
1272 pToken = *itr;
1273 switch (pToken->GetType())
1275 case svSingleRef:
1276 case svExternalSingleRef:
1278 const ScSingleRefData& rData = pToken->GetSingleRef();
1279 if (rData.Col() == nMinCol && rData.Row() == nMinRow)
1280 // The corner cell is contained.
1281 return false;
1283 if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow)
1284 bRight = true;
1286 if (rData.Col() == nMinCol && rData.Row() == nMinRow+nCornerRowCount)
1287 bBottom = true;
1289 if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow+nCornerRowCount)
1290 bDiagonal = true;
1292 break;
1293 case svDoubleRef:
1294 case svExternalDoubleRef:
1296 const ScComplexRefData& rData = pToken->GetDoubleRef();
1297 const ScSingleRefData& r1 = rData.Ref1;
1298 const ScSingleRefData& r2 = rData.Ref2;
1299 if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1300 r1.Row() <= nMinRow && nMinRow <= r2.Row())
1301 // The corner cell is contained.
1302 return false;
1304 if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1305 r1.Row() <= nMinRow && nMinRow <= r2.Row())
1306 bRight = true;
1308 if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1309 r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1310 bBottom = true;
1312 if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1313 r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1314 bDiagonal = true;
1316 break;
1317 default:
1322 if (!bRight || !bBottom || !bDiagonal)
1323 // Not all the adjacent cells are included. Bail out.
1324 return false;
1326 ScSingleRefData aData;
1327 aData.InitFlags();
1328 aData.SetFlag3D(true);
1329 aData.SetAbsCol(nMinCol);
1330 aData.SetAbsRow(nMinRow);
1331 aData.SetAbsTab(nTab);
1333 if( nCornerRowCount==1 && nCornerColumnCount==1 )
1335 if (bExternal)
1337 ScTokenRef pCorner(
1338 new ScExternalSingleRefToken(nFileId, aExtTabName, aData));
1339 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1341 else
1343 ScTokenRef pCorner(new ScSingleRefToken(aData));
1344 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1347 else
1349 ScSingleRefData aDataEnd(aData);
1350 aDataEnd.IncCol(nCornerColumnCount-1);
1351 aDataEnd.IncRow(nCornerRowCount-1);
1352 ScComplexRefData r;
1353 r.Ref1=aData;
1354 r.Ref2=aDataEnd;
1355 if (bExternal)
1357 ScTokenRef pCorner(
1358 new ScExternalDoubleRefToken(nFileId, aExtTabName, r));
1359 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1361 else
1363 ScTokenRef pCorner(new ScDoubleRefToken(r));
1364 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1368 return true;
1371 #define SHRINK_RANGE_THRESHOLD 10000
1373 class ShrinkRefTokenToDataRange : std::unary_function<ScTokenRef, void>
1375 ScDocument* mpDoc;
1376 public:
1377 ShrinkRefTokenToDataRange(ScDocument* pDoc) : mpDoc(pDoc) {}
1378 void operator() (ScTokenRef& rRef)
1380 if (ScRefTokenHelper::isExternalRef(rRef))
1381 return;
1383 // Don't assume an ScDoubleRefToken if it isn't. It can be at least an
1384 // ScSingleRefToken, then there isn't anything to shrink.
1385 if (rRef->GetType() != svDoubleRef)
1386 return;
1388 ScComplexRefData& rData = rRef->GetDoubleRef();
1389 ScSingleRefData& s = rData.Ref1;
1390 ScSingleRefData& e = rData.Ref2;
1392 if(abs((e.Col()-s.Col())*(e.Row()-s.Row())) < SHRINK_RANGE_THRESHOLD)
1393 return;
1395 SCCOL nMinCol = MAXCOL, nMaxCol = 0;
1396 SCROW nMinRow = MAXROW, nMaxRow = 0;
1398 // Determine the smallest range that encompasses the data ranges of all sheets.
1399 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
1400 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
1402 SCCOL nCol1 = 0, nCol2 = MAXCOL;
1403 SCROW nRow1 = 0, nRow2 = MAXROW;
1404 mpDoc->ShrinkToDataArea(nTab, nCol1, nRow1, nCol2, nRow2);
1405 nMinCol = std::min(nMinCol, nCol1);
1406 nMinRow = std::min(nMinRow, nRow1);
1407 nMaxCol = std::max(nMaxCol, nCol2);
1408 nMaxRow = std::max(nMaxRow, nRow2);
1411 // Shrink range to the data range if applicable.
1412 if (s.Col() < nMinCol)
1413 s.SetAbsCol(nMinCol);
1414 if (s.Row() < nMinRow)
1415 s.SetAbsRow(nMinRow);
1416 if (e.Col() > nMaxCol)
1417 e.SetAbsCol(nMaxCol);
1418 if (e.Row() > nMaxRow)
1419 e.SetAbsRow(nMaxRow);
1423 void shrinkToDataRange(ScDocument* pDoc, vector<ScTokenRef>& rRefTokens)
1425 std::for_each(rRefTokens.begin(), rRefTokens.end(), ShrinkRefTokenToDataRange(pDoc));
1430 uno::Reference< chart2::data::XDataSource> SAL_CALL
1431 ScChart2DataProvider::createDataSource(
1432 const uno::Sequence< beans::PropertyValue >& aArguments )
1433 throw( lang::IllegalArgumentException, uno::RuntimeException, std::exception)
1435 SolarMutexGuard aGuard;
1436 if ( ! m_pDocument )
1437 throw uno::RuntimeException();
1439 uno::Reference< chart2::data::XDataSource> xResult;
1440 bool bLabel = true;
1441 bool bCategories = false;
1442 bool bOrientCol = true;
1443 OUString aRangeRepresentation;
1444 uno::Sequence< sal_Int32 > aSequenceMapping;
1445 bool bTimeBased = false;
1446 for(sal_Int32 i = 0; i < aArguments.getLength(); ++i)
1448 if ( aArguments[i].Name == "DataRowSource" )
1450 chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
1451 if( ! (aArguments[i].Value >>= eSource))
1453 sal_Int32 nSource(0);
1454 if( aArguments[i].Value >>= nSource )
1455 eSource = (static_cast< chart::ChartDataRowSource >( nSource ));
1457 bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
1459 else if ( aArguments[i].Name == "FirstCellAsLabel" )
1461 bLabel = ::cppu::any2bool(aArguments[i].Value);
1463 else if ( aArguments[i].Name == "HasCategories" )
1465 bCategories = ::cppu::any2bool(aArguments[i].Value);
1467 else if ( aArguments[i].Name == "CellRangeRepresentation" )
1469 aArguments[i].Value >>= aRangeRepresentation;
1471 else if ( aArguments[i].Name == "SequenceMapping" )
1473 aArguments[i].Value >>= aSequenceMapping;
1475 else if ( aArguments[i].Name == "TimeBased" )
1477 aArguments[i].Value >>= bTimeBased;
1481 vector<ScTokenRef> aRefTokens;
1482 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1483 ScRefTokenHelper::compileRangeRepresentation(
1484 aRefTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1485 if (aRefTokens.empty())
1486 // Invalid range representation. Bail out.
1487 throw lang::IllegalArgumentException();
1489 SCTAB nTimeBasedStart = MAXTAB;
1490 SCTAB nTimeBasedEnd = 0;
1491 if(bTimeBased)
1493 // limit to first sheet
1494 for(vector<ScTokenRef>::iterator itr = aRefTokens.begin(),
1495 itrEnd = aRefTokens.end(); itr != itrEnd; ++itr)
1497 if ((*itr)->GetType() != svDoubleRef)
1498 continue;
1500 ScComplexRefData& rData = (*itr)->GetDoubleRef();
1501 ScSingleRefData& s = rData.Ref1;
1502 ScSingleRefData& e = rData.Ref2;
1504 nTimeBasedStart = std::min(nTimeBasedStart, s.Tab());
1505 nTimeBasedEnd = std::min(nTimeBasedEnd, e.Tab());
1507 if(s.Tab() != e.Tab())
1508 e.SetAbsTab(s.Tab());
1512 if(!bTimeBased)
1513 shrinkToDataRange(m_pDocument, aRefTokens);
1515 if (bLabel)
1516 lcl_addUpperLeftCornerIfMissing(aRefTokens); //#i90669#
1518 bool bColHeaders = (bOrientCol ? bLabel : bCategories );
1519 bool bRowHeaders = (bOrientCol ? bCategories : bLabel );
1521 Chart2Positioner aChPositioner(m_pDocument, aRefTokens);
1522 aChPositioner.setHeaders(bColHeaders, bRowHeaders);
1524 const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap();
1525 if (!pChartMap)
1526 // No chart position map instance. Bail out.
1527 return xResult;
1529 ScChart2DataSource* pDS = NULL;
1530 ::std::list< Reference< chart2::data::XLabeledDataSequence > > aSeqs;
1532 // Fill Categories
1533 if( bCategories )
1535 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1536 auto_ptr< vector<ScTokenRef> > pValueTokens(NULL);
1537 SAL_WNODEPRECATED_DECLARATIONS_POP
1538 if (bOrientCol)
1539 pValueTokens.reset(pChartMap->getAllRowHeaderRanges());
1540 else
1541 pValueTokens.reset(pChartMap->getAllColHeaderRanges());
1543 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1544 auto_ptr< vector<ScTokenRef> > pLabelTokens(
1545 pChartMap->getLeftUpperCornerRanges());
1546 SAL_WNODEPRECATED_DECLARATIONS_POP
1548 Reference< chart2::data::XLabeledDataSequence > xCategories = lcl_createLabeledDataSequenceFromTokens(
1549 pValueTokens, pLabelTokens, m_pDocument, this, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1550 if ( xCategories.is() )
1552 aSeqs.push_back( xCategories );
1556 // Fill Serieses (values and label)
1557 sal_Int32 nCount = bOrientCol ? pChartMap->getDataColCount() : pChartMap->getDataRowCount();
1558 for (sal_Int32 i = 0; i < nCount; ++i)
1560 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1561 auto_ptr< vector<ScTokenRef> > pValueTokens(NULL);
1562 auto_ptr< vector<ScTokenRef> > pLabelTokens(NULL);
1563 SAL_WNODEPRECATED_DECLARATIONS_POP
1564 if (bOrientCol)
1566 pValueTokens.reset(pChartMap->getDataColRanges(static_cast<SCCOL>(i)));
1567 pLabelTokens.reset(pChartMap->getColHeaderRanges(static_cast<SCCOL>(i)));
1569 else
1571 pValueTokens.reset(pChartMap->getDataRowRanges(static_cast<SCROW>(i)));
1572 pLabelTokens.reset(pChartMap->getRowHeaderRanges(static_cast<SCROW>(i)));
1574 Reference< chart2::data::XLabeledDataSequence > xChartSeries = lcl_createLabeledDataSequenceFromTokens(
1575 pValueTokens, pLabelTokens, m_pDocument, this, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1576 if ( xChartSeries.is() && xChartSeries->getValues().is() && xChartSeries->getValues()->getData().getLength() )
1578 aSeqs.push_back( xChartSeries );
1582 pDS = new ScChart2DataSource(m_pDocument);
1583 ::std::list< Reference< chart2::data::XLabeledDataSequence > >::iterator aItr( aSeqs.begin() );
1584 ::std::list< Reference< chart2::data::XLabeledDataSequence > >::iterator aEndItr( aSeqs.end() );
1586 //reorder labeled sequences according to aSequenceMapping
1587 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aSeqVector;
1588 while(aItr != aEndItr)
1590 aSeqVector.push_back(*aItr);
1591 ++aItr;
1594 ::std::map< sal_Int32, Reference< chart2::data::XLabeledDataSequence > > aSequenceMap;
1595 for( sal_Int32 nNewIndex = 0; nNewIndex < aSequenceMapping.getLength(); nNewIndex++ )
1597 // note: assuming that the values in the sequence mapping are always non-negative
1598 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::size_type nOldIndex( static_cast< sal_uInt32 >( aSequenceMapping[nNewIndex] ) );
1599 if( nOldIndex < aSeqVector.size() )
1601 pDS->AddLabeledSequence( aSeqVector[nOldIndex] );
1602 aSeqVector[nOldIndex] = 0;
1606 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::iterator aVectorItr( aSeqVector.begin() );
1607 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::iterator aVectorEndItr( aSeqVector.end() );
1608 while(aVectorItr != aVectorEndItr)
1610 Reference< chart2::data::XLabeledDataSequence > xSeq( *aVectorItr );
1611 if ( xSeq.is() )
1613 pDS->AddLabeledSequence( xSeq );
1615 ++aVectorItr;
1618 xResult.set( pDS );
1619 return xResult;
1622 namespace
1626 * Function object to create a list of table numbers from a token list.
1628 class InsertTabNumber : public unary_function<ScTokenRef, void>
1630 public:
1631 InsertTabNumber() :
1632 mpTabNumList(new list<SCTAB>())
1636 InsertTabNumber(const InsertTabNumber& r) :
1637 mpTabNumList(r.mpTabNumList)
1641 void operator() (const ScTokenRef& pToken) const
1643 if (!ScRefTokenHelper::isRef(pToken))
1644 return;
1646 const ScSingleRefData& r = pToken->GetSingleRef();
1647 mpTabNumList->push_back(r.Tab());
1650 void getList(list<SCTAB>& rList)
1652 mpTabNumList->swap(rList);
1654 private:
1655 shared_ptr< list<SCTAB> > mpTabNumList;
1658 class RangeAnalyzer
1660 public:
1661 RangeAnalyzer();
1662 void initRangeAnalyzer( const vector<ScTokenRef>& rTokens );
1663 void analyzeRange( sal_Int32& rnDataInRows, sal_Int32& rnDataInCols,
1664 bool& rbRowSourceAmbiguous ) const;
1665 bool inSameSingleRow( RangeAnalyzer& rOther );
1666 bool inSameSingleColumn( RangeAnalyzer& rOther );
1667 SCROW getRowCount() { return mnRowCount; }
1668 SCCOL getColumnCount() { return mnColumnCount; }
1670 private:
1671 bool mbEmpty;
1672 bool mbAmbiguous;
1673 SCROW mnRowCount;
1674 SCCOL mnColumnCount;
1676 SCCOL mnStartColumn;
1677 SCROW mnStartRow;
1680 RangeAnalyzer::RangeAnalyzer()
1681 : mbEmpty(true)
1682 , mbAmbiguous(false)
1683 , mnRowCount(0)
1684 , mnColumnCount(0)
1685 , mnStartColumn(-1)
1686 , mnStartRow(-1)
1690 void RangeAnalyzer::initRangeAnalyzer( const vector<ScTokenRef>& rTokens )
1692 mnRowCount=0;
1693 mnColumnCount=0;
1694 mnStartColumn = -1;
1695 mnStartRow = -1;
1696 mbAmbiguous=false;
1697 if( rTokens.empty() )
1699 mbEmpty=true;
1700 return;
1702 mbEmpty=false;
1704 vector<ScTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
1705 for (; itr != itrEnd ; ++itr)
1707 ScTokenRef aRefToken = *itr;
1708 StackVar eVar = aRefToken->GetType();
1709 if (eVar == svDoubleRef || eVar == svExternalDoubleRef)
1711 const ScComplexRefData& r = aRefToken->GetDoubleRef();
1712 if (r.Ref1.Tab() == r.Ref2.Tab())
1714 mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(r.Ref2.Col() - r.Ref1.Col())+1));
1715 mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(r.Ref2.Row() - r.Ref1.Row())+1));
1716 if( mnStartColumn == -1 )
1718 mnStartColumn = r.Ref1.Col();
1719 mnStartRow = r.Ref1.Row();
1721 else
1723 if (mnStartColumn != r.Ref1.Col() && mnStartRow != r.Ref1.Row())
1724 mbAmbiguous=true;
1727 else
1728 mbAmbiguous=true;
1730 else if (eVar == svSingleRef || eVar == svExternalSingleRef)
1732 const ScSingleRefData& r = aRefToken->GetSingleRef();
1733 mnColumnCount = std::max<SCCOL>( mnColumnCount, 1);
1734 mnRowCount = std::max<SCROW>( mnRowCount, 1);
1735 if( mnStartColumn == -1 )
1737 mnStartColumn = r.Col();
1738 mnStartRow = r.Row();
1740 else
1742 if (mnStartColumn != r.Col() && mnStartRow != r.Row())
1743 mbAmbiguous=true;
1746 else
1747 mbAmbiguous=true;
1751 void RangeAnalyzer::analyzeRange( sal_Int32& rnDataInRows,
1752 sal_Int32& rnDataInCols,
1753 bool& rbRowSourceAmbiguous ) const
1755 if(!mbEmpty && !mbAmbiguous)
1757 if( mnRowCount==1 && mnColumnCount>1 )
1758 ++rnDataInRows;
1759 else if( mnColumnCount==1 && mnRowCount>1 )
1760 ++rnDataInCols;
1761 else if( mnRowCount>1 && mnColumnCount>1 )
1762 rbRowSourceAmbiguous = true;
1764 else if( !mbEmpty )
1765 rbRowSourceAmbiguous = true;
1768 bool RangeAnalyzer::inSameSingleRow( RangeAnalyzer& rOther )
1770 if( mnStartRow==rOther.mnStartRow &&
1771 mnRowCount==1 && rOther.mnRowCount==1 )
1772 return true;
1773 return false;
1776 bool RangeAnalyzer::inSameSingleColumn( RangeAnalyzer& rOther )
1778 if( mnStartColumn==rOther.mnStartColumn &&
1779 mnColumnCount==1 && rOther.mnColumnCount==1 )
1780 return true;
1781 return false;
1784 } //end anonymous namespace
1786 uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments(
1787 const uno::Reference< chart2::data::XDataSource >& xDataSource )
1788 throw (uno::RuntimeException, std::exception)
1790 ::std::vector< beans::PropertyValue > aResult;
1791 bool bRowSourceDetected = false;
1792 bool bFirstCellAsLabel = false;
1793 bool bHasCategories = false;
1794 OUString sRangeRep;
1796 bool bHasCategoriesLabels = false;
1797 vector<ScTokenRef> aAllCategoriesValuesTokens;
1798 vector<ScTokenRef> aAllSeriesLabelTokens;
1800 chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS;
1802 vector<ScTokenRef> aAllTokens;
1804 // parse given data source and collect infos
1806 SolarMutexGuard aGuard;
1807 OSL_ENSURE( m_pDocument, "No Document -> no detectArguments" );
1808 if(!m_pDocument ||!xDataSource.is())
1809 return lcl_VectorToSequence( aResult );
1811 sal_Int32 nDataInRows = 0;
1812 sal_Int32 nDataInCols = 0;
1813 bool bRowSourceAmbiguous = false;
1815 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences());
1816 const sal_Int32 nCount( aSequences.getLength());
1817 RangeAnalyzer aPrevLabel,aPrevValues;
1818 for( sal_Int32 nIdx=0; nIdx<nCount; ++nIdx )
1820 Reference< chart2::data::XLabeledDataSequence > xLS(aSequences[nIdx]);
1821 if( xLS.is() )
1823 bool bThisIsCategories = false;
1824 if(!bHasCategories)
1826 Reference< beans::XPropertySet > xSeqProp( xLS->getValues(), uno::UNO_QUERY );
1827 OUString aRole;
1828 if( xSeqProp.is() && (xSeqProp->getPropertyValue("Role") >>= aRole) &&
1829 aRole == "categories" )
1830 bThisIsCategories = bHasCategories = true;
1833 RangeAnalyzer aLabel,aValues;
1834 // label
1835 Reference< chart2::data::XDataSequence > xLabel( xLS->getLabel());
1836 if( xLabel.is())
1838 bFirstCellAsLabel = true;
1839 vector<ScTokenRef> aTokens;
1840 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1841 ScRefTokenHelper::compileRangeRepresentation(
1842 aTokens, xLabel->getSourceRangeRepresentation(), m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1843 aLabel.initRangeAnalyzer(aTokens);
1844 vector<ScTokenRef>::const_iterator itr = aTokens.begin(), itrEnd = aTokens.end();
1845 for (; itr != itrEnd; ++itr)
1847 ScRefTokenHelper::join(aAllTokens, *itr, ScAddress());
1848 if(!bThisIsCategories)
1849 ScRefTokenHelper::join(aAllSeriesLabelTokens, *itr, ScAddress());
1851 if(bThisIsCategories)
1852 bHasCategoriesLabels=true;
1854 // values
1855 Reference< chart2::data::XDataSequence > xValues( xLS->getValues());
1856 if( xValues.is())
1858 vector<ScTokenRef> aTokens;
1859 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1860 ScRefTokenHelper::compileRangeRepresentation(
1861 aTokens, xValues->getSourceRangeRepresentation(), m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1862 aValues.initRangeAnalyzer(aTokens);
1863 vector<ScTokenRef>::const_iterator itr = aTokens.begin(), itrEnd = aTokens.end();
1864 for (; itr != itrEnd; ++itr)
1866 ScRefTokenHelper::join(aAllTokens, *itr, ScAddress());
1867 if(bThisIsCategories)
1868 ScRefTokenHelper::join(aAllCategoriesValuesTokens, *itr, ScAddress());
1871 //detect row source
1872 if(!bThisIsCategories || nCount==1) //categories might span multiple rows *and* columns, so they should be used for detection only if nothing else is available
1874 if (!bRowSourceAmbiguous)
1876 aValues.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1877 aLabel.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1878 if (nDataInRows > 1 && nDataInCols > 1)
1879 bRowSourceAmbiguous = true;
1880 else if( !bRowSourceAmbiguous && !nDataInRows && !nDataInCols )
1882 if( aValues.inSameSingleColumn( aLabel ) )
1883 nDataInCols++;
1884 else if( aValues.inSameSingleRow( aLabel ) )
1885 nDataInRows++;
1886 else
1888 //#i86188# also detect a single column split into rows correctly
1889 if( aValues.inSameSingleColumn( aPrevValues ) )
1890 nDataInRows++;
1891 else if( aValues.inSameSingleRow( aPrevValues ) )
1892 nDataInCols++;
1893 else if( aLabel.inSameSingleColumn( aPrevLabel ) )
1894 nDataInRows++;
1895 else if( aLabel.inSameSingleRow( aPrevLabel ) )
1896 nDataInCols++;
1901 aPrevValues=aValues;
1902 aPrevLabel=aLabel;
1906 if (!bRowSourceAmbiguous)
1908 bRowSourceDetected = true;
1909 eRowSource = ( nDataInRows > 0
1910 ? chart::ChartDataRowSource_ROWS
1911 : chart::ChartDataRowSource_COLUMNS );
1913 else
1915 // set DataRowSource to the better of the two ambiguities
1916 eRowSource = ( nDataInRows > nDataInCols
1917 ? chart::ChartDataRowSource_ROWS
1918 : chart::ChartDataRowSource_COLUMNS );
1923 // TableNumberList
1925 list<SCTAB> aTableNumList;
1926 InsertTabNumber func;
1927 func = ::std::for_each(aAllTokens.begin(), aAllTokens.end(), func);
1928 func.getList(aTableNumList);
1929 aResult.push_back(
1930 beans::PropertyValue( OUString("TableNumberList"), -1,
1931 uno::makeAny( lcl_createTableNumberList( aTableNumList ) ),
1932 beans::PropertyState_DIRECT_VALUE ));
1935 // DataRowSource (calculated before)
1936 if( bRowSourceDetected )
1938 aResult.push_back(
1939 beans::PropertyValue( OUString("DataRowSource"), -1,
1940 uno::makeAny( eRowSource ), beans::PropertyState_DIRECT_VALUE ));
1943 // HasCategories
1944 if( bRowSourceDetected )
1946 aResult.push_back(
1947 beans::PropertyValue( OUString("HasCategories"), -1,
1948 uno::makeAny( bHasCategories ), beans::PropertyState_DIRECT_VALUE ));
1951 // FirstCellAsLabel
1952 if( bRowSourceDetected )
1954 aResult.push_back(
1955 beans::PropertyValue( OUString("FirstCellAsLabel"), -1,
1956 uno::makeAny( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE ));
1959 // Add the left upper corner to the range if it is missing.
1960 if (bRowSourceDetected && bFirstCellAsLabel && bHasCategories && !bHasCategoriesLabels )
1962 RangeAnalyzer aTop,aLeft;
1963 if( eRowSource==chart::ChartDataRowSource_COLUMNS )
1965 aTop.initRangeAnalyzer(aAllSeriesLabelTokens);
1966 aLeft.initRangeAnalyzer(aAllCategoriesValuesTokens);
1968 else
1970 aTop.initRangeAnalyzer(aAllCategoriesValuesTokens);
1971 aLeft.initRangeAnalyzer(aAllSeriesLabelTokens);
1973 lcl_addUpperLeftCornerIfMissing(aAllTokens, aTop.getRowCount(), aLeft.getColumnCount());//e.g. #i91212#
1976 // Get range string.
1977 lcl_convertTokensToString(sRangeRep, aAllTokens, m_pDocument);
1979 // add cell range property
1980 aResult.push_back(
1981 beans::PropertyValue( OUString("CellRangeRepresentation"), -1,
1982 uno::makeAny( sRangeRep ), beans::PropertyState_DIRECT_VALUE ));
1984 //Sequence Mapping
1985 bool bSequencesReordered = true;//todo detect this above or detect this sequence mapping cheaper ...
1986 if( bSequencesReordered && bRowSourceDetected )
1988 bool bDifferentIndexes = false;
1990 std::vector< sal_Int32 > aSequenceMappingVector;
1992 uno::Reference< chart2::data::XDataSource > xCompareDataSource;
1995 xCompareDataSource.set( this->createDataSource( lcl_VectorToSequence( aResult ) ) );
1997 catch( const lang::IllegalArgumentException & )
1999 // creation of data source to compare didn't work, so we cannot
2000 // create a sequence mapping
2003 if( xDataSource.is() && xCompareDataSource.is() )
2005 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > aOldSequences(
2006 xCompareDataSource->getDataSequences() );
2007 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aNewSequences(
2008 xDataSource->getDataSequences());
2010 OUString aOldLabel;
2011 OUString aNewLabel;
2012 OUString aOldValues;
2013 OUString aNewValues;
2014 OUString aEmpty;
2016 for( sal_Int32 nNewIndex = 0; nNewIndex < aNewSequences.getLength(); nNewIndex++ )
2018 uno::Reference< chart2::data::XLabeledDataSequence> xNew( aNewSequences[nNewIndex] );
2019 for( sal_Int32 nOldIndex = 0; nOldIndex < aOldSequences.getLength(); nOldIndex++ )
2021 uno::Reference< chart2::data::XLabeledDataSequence> xOld( aOldSequences[nOldIndex] );
2023 if( xOld.is() && xNew.is() )
2025 aOldLabel = aNewLabel = aOldValues = aNewValues = aEmpty;
2026 if( xOld.is() && xOld->getLabel().is() )
2027 aOldLabel = xOld->getLabel()->getSourceRangeRepresentation();
2028 if( xNew.is() && xNew->getLabel().is() )
2029 aNewLabel = xNew->getLabel()->getSourceRangeRepresentation();
2030 if( xOld.is() && xOld->getValues().is() )
2031 aOldValues = xOld->getValues()->getSourceRangeRepresentation();
2032 if( xNew.is() && xNew->getValues().is() )
2033 aNewValues = xNew->getValues()->getSourceRangeRepresentation();
2035 if( aOldLabel.equals(aNewLabel)
2036 && ( aOldValues.equals(aNewValues) ) )
2038 if( nOldIndex!=nNewIndex )
2039 bDifferentIndexes = true;
2040 aSequenceMappingVector.push_back(nOldIndex);
2041 break;
2048 if( bDifferentIndexes && !aSequenceMappingVector.empty() )
2050 aResult.push_back(
2051 beans::PropertyValue( OUString("SequenceMapping"), -1,
2052 uno::makeAny( lcl_VectorToSequence(aSequenceMappingVector) )
2053 , beans::PropertyState_DIRECT_VALUE ));
2057 return lcl_VectorToSequence( aResult );
2060 sal_Bool SAL_CALL ScChart2DataProvider::createDataSequenceByRangeRepresentationPossible( const OUString& aRangeRepresentation )
2061 throw (uno::RuntimeException, std::exception)
2063 SolarMutexGuard aGuard;
2064 if( ! m_pDocument )
2065 return false;
2067 vector<ScTokenRef> aTokens;
2068 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2069 ScRefTokenHelper::compileRangeRepresentation(
2070 aTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2071 return !aTokens.empty();
2074 uno::Reference< chart2::data::XDataSequence > SAL_CALL
2075 ScChart2DataProvider::createDataSequenceByRangeRepresentation(
2076 const OUString& aRangeRepresentation )
2077 throw (lang::IllegalArgumentException,
2078 uno::RuntimeException, std::exception)
2080 SolarMutexGuard aGuard;
2081 uno::Reference< chart2::data::XDataSequence > xResult;
2083 OSL_ENSURE( m_pDocument, "No Document -> no createDataSequenceByRangeRepresentation" );
2084 if(!m_pDocument || aRangeRepresentation.isEmpty())
2085 return xResult;
2087 vector<ScTokenRef> aRefTokens;
2088 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2089 ScRefTokenHelper::compileRangeRepresentation(
2090 aRefTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2091 if (aRefTokens.empty())
2092 return xResult;
2094 shrinkToDataRange(m_pDocument, aRefTokens);
2096 // ScChart2DataSequence manages the life cycle of pRefTokens.
2097 vector<ScTokenRef>* pRefTokens = new vector<ScTokenRef>();
2098 pRefTokens->swap(aRefTokens);
2099 xResult.set(new ScChart2DataSequence(m_pDocument, this, pRefTokens, m_bIncludeHiddenCells));
2101 return xResult;
2104 uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRangeSelection()
2105 throw (uno::RuntimeException, std::exception)
2107 uno::Reference< sheet::XRangeSelection > xResult;
2109 uno::Reference< frame::XModel > xModel( lcl_GetXModel( m_pDocument ));
2110 if( xModel.is())
2111 xResult.set( xModel->getCurrentController(), uno::UNO_QUERY );
2113 return xResult;
2116 sal_Bool SAL_CALL ScChart2DataProvider::createDataSequenceByFormulaTokensPossible(
2117 const Sequence<sheet::FormulaToken>& aTokens )
2118 throw (uno::RuntimeException, std::exception)
2120 if (aTokens.getLength() <= 0)
2121 return false;
2123 ScTokenArray aCode;
2124 if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
2125 return false;
2127 sal_uInt16 n = aCode.GetLen();
2128 if (!n)
2129 return false;
2131 const formula::FormulaToken* pFirst = aCode.First();
2132 const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2133 for (const formula::FormulaToken* p = aCode.First(); p; p = aCode.Next())
2135 switch (p->GetType())
2137 case svSep:
2139 switch (p->GetOpCode())
2141 case ocSep:
2142 // separators are allowed.
2143 break;
2144 case ocOpen:
2145 if (p != pFirst)
2146 // open paran is allowed only as the first token.
2147 return false;
2148 break;
2149 case ocClose:
2150 if (p != pLast)
2151 // close paren is allowed only as the last token.
2152 return false;
2153 break;
2154 default:
2155 return false;
2158 break;
2159 case svSingleRef:
2160 case svDoubleRef:
2161 case svExternalSingleRef:
2162 case svExternalDoubleRef:
2163 break;
2164 default:
2165 return false;
2169 return true;
2172 Reference<chart2::data::XDataSequence> SAL_CALL
2173 ScChart2DataProvider::createDataSequenceByFormulaTokens(
2174 const Sequence<sheet::FormulaToken>& aTokens )
2175 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
2177 Reference<chart2::data::XDataSequence> xResult;
2178 if (aTokens.getLength() <= 0)
2179 return xResult;
2181 ScTokenArray aCode;
2182 if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
2183 return xResult;
2185 sal_uInt16 n = aCode.GetLen();
2186 if (!n)
2187 return xResult;
2189 vector<ScTokenRef> aRefTokens;
2190 const formula::FormulaToken* pFirst = aCode.First();
2191 const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2192 for (const formula::FormulaToken* p = aCode.First(); p; p = aCode.Next())
2194 switch (p->GetType())
2196 case svSep:
2198 switch (p->GetOpCode())
2200 case ocSep:
2201 // separators are allowed.
2202 break;
2203 case ocOpen:
2204 if (p != pFirst)
2205 // open paran is allowed only as the first token.
2206 throw lang::IllegalArgumentException();
2207 break;
2208 case ocClose:
2209 if (p != pLast)
2210 // close paren is allowed only as the last token.
2211 throw lang::IllegalArgumentException();
2212 break;
2213 default:
2214 throw lang::IllegalArgumentException();
2217 break;
2218 case svString:
2219 case svSingleRef:
2220 case svDoubleRef:
2221 case svExternalSingleRef:
2222 case svExternalDoubleRef:
2224 ScTokenRef pNew(static_cast<ScToken*>(p->Clone()));
2225 aRefTokens.push_back(pNew);
2227 break;
2228 default:
2229 throw lang::IllegalArgumentException();
2233 if (aRefTokens.empty())
2234 return xResult;
2236 shrinkToDataRange(m_pDocument, aRefTokens);
2238 // ScChart2DataSequence manages the life cycle of pRefTokens.
2239 vector<ScTokenRef>* pRefTokens = new vector<ScTokenRef>();
2240 pRefTokens->swap(aRefTokens);
2241 xResult.set(new ScChart2DataSequence(m_pDocument, this, pRefTokens, m_bIncludeHiddenCells));
2242 return xResult;
2245 // XRangeXMLConversion ---------------------------------------------------
2247 OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const OUString& sRangeRepresentation )
2248 throw ( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
2250 OUString aRet;
2251 if (!m_pDocument)
2252 return aRet;
2254 if (sRangeRepresentation.isEmpty())
2255 // Empty data range is allowed.
2256 return aRet;
2258 vector<ScTokenRef> aRefTokens;
2259 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2260 ScRefTokenHelper::compileRangeRepresentation(
2261 aRefTokens, sRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2262 if (aRefTokens.empty())
2263 throw lang::IllegalArgumentException();
2265 Tokens2RangeStringXML converter(m_pDocument);
2266 converter = ::std::for_each(aRefTokens.begin(), aRefTokens.end(), converter);
2267 converter.getString(aRet);
2269 return aRet;
2272 OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const OUString& sXMLRange )
2273 throw ( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
2275 const sal_Unicode cSep = ' ';
2276 const sal_Unicode cQuote = '\'';
2278 if (!m_pDocument)
2280 // #i74062# When loading flat XML, this is called before the referenced sheets are in the document,
2281 // so the conversion has to take place directly with the strings, without looking up the sheets.
2283 OUStringBuffer sRet;
2284 sal_Int32 nOffset = 0;
2285 while( nOffset >= 0 )
2287 OUString sToken;
2288 ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset, cSep, cQuote );
2289 if( nOffset >= 0 )
2291 // convert one address (remove dots)
2293 OUString aUIString(sToken);
2295 sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0, cQuote );
2296 if ( nIndex >= 0 && nIndex < aUIString.getLength() - 1 &&
2297 aUIString[nIndex + 1] == '.' )
2298 aUIString = aUIString.replaceAt( nIndex + 1, 1, "" );
2300 if ( aUIString[0] == '.' )
2301 aUIString = aUIString.copy( 1 );
2303 if( !sRet.isEmpty() )
2304 sRet.append( ';' );
2305 sRet.append( aUIString );
2309 return sRet.makeStringAndClear();
2312 OUString aRet;
2313 ScRangeStringConverter::GetStringFromXMLRangeString(aRet, sXMLRange, m_pDocument);
2314 return aRet;
2317 // DataProvider XPropertySet -------------------------------------------------
2319 uno::Reference< beans::XPropertySetInfo> SAL_CALL
2320 ScChart2DataProvider::getPropertySetInfo() throw( uno::RuntimeException, std::exception)
2322 SolarMutexGuard aGuard;
2323 static uno::Reference<beans::XPropertySetInfo> aRef =
2324 new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
2325 return aRef;
2329 void SAL_CALL ScChart2DataProvider::setPropertyValue(
2330 const OUString& rPropertyName, const uno::Any& rValue)
2331 throw( beans::UnknownPropertyException,
2332 beans::PropertyVetoException,
2333 lang::IllegalArgumentException,
2334 lang::WrappedTargetException, uno::RuntimeException, std::exception)
2336 if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2338 if ( !(rValue >>= m_bIncludeHiddenCells))
2339 throw lang::IllegalArgumentException();
2341 else
2342 throw beans::UnknownPropertyException();
2346 uno::Any SAL_CALL ScChart2DataProvider::getPropertyValue(
2347 const OUString& rPropertyName)
2348 throw( beans::UnknownPropertyException,
2349 lang::WrappedTargetException, uno::RuntimeException, std::exception)
2351 uno::Any aRet;
2352 if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2353 aRet <<= m_bIncludeHiddenCells;
2354 else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
2356 // This is a read-only property.
2357 aRet <<= m_pDocument->PastingDrawFromOtherDoc();
2359 else
2360 throw beans::UnknownPropertyException();
2361 return aRet;
2365 void SAL_CALL ScChart2DataProvider::addPropertyChangeListener(
2366 const OUString& /*rPropertyName*/,
2367 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
2368 throw( beans::UnknownPropertyException,
2369 lang::WrappedTargetException, uno::RuntimeException, std::exception)
2371 OSL_FAIL( "Not yet implemented" );
2375 void SAL_CALL ScChart2DataProvider::removePropertyChangeListener(
2376 const OUString& /*rPropertyName*/,
2377 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
2378 throw( beans::UnknownPropertyException,
2379 lang::WrappedTargetException, uno::RuntimeException, std::exception)
2381 OSL_FAIL( "Not yet implemented" );
2385 void SAL_CALL ScChart2DataProvider::addVetoableChangeListener(
2386 const OUString& /*rPropertyName*/,
2387 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
2388 throw( beans::UnknownPropertyException,
2389 lang::WrappedTargetException, uno::RuntimeException, std::exception)
2391 OSL_FAIL( "Not yet implemented" );
2395 void SAL_CALL ScChart2DataProvider::removeVetoableChangeListener(
2396 const OUString& /*rPropertyName*/,
2397 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/ )
2398 throw( beans::UnknownPropertyException,
2399 lang::WrappedTargetException, uno::RuntimeException, std::exception)
2401 OSL_FAIL( "Not yet implemented" );
2404 // DataSource ================================================================
2406 ScChart2DataSource::ScChart2DataSource( ScDocument* pDoc)
2407 : m_pDocument( pDoc)
2409 if ( m_pDocument )
2410 m_pDocument->AddUnoObject( *this);
2414 ScChart2DataSource::~ScChart2DataSource()
2416 if ( m_pDocument )
2417 m_pDocument->RemoveUnoObject( *this);
2421 void ScChart2DataSource::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
2423 if ( rHint.ISA( SfxSimpleHint ) &&
2424 ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
2426 m_pDocument = NULL;
2431 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > SAL_CALL
2432 ScChart2DataSource::getDataSequences() throw ( uno::RuntimeException, std::exception)
2434 SolarMutexGuard aGuard;
2436 LabeledList::const_iterator aItr(m_aLabeledSequences.begin());
2437 LabeledList::const_iterator aEndItr(m_aLabeledSequences.end());
2439 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aRet(m_aLabeledSequences.size());
2441 sal_Int32 i = 0;
2442 while (aItr != aEndItr)
2444 aRet[i] = *aItr;
2445 ++i;
2446 ++aItr;
2449 return aRet;
2452 void ScChart2DataSource::AddLabeledSequence(const uno::Reference < chart2::data::XLabeledDataSequence >& xNew)
2454 m_aLabeledSequences.push_back(xNew);
2457 // DataSequence ==============================================================
2459 ScChart2DataSequence::Item::Item() :
2460 mfValue(0.0), mbIsValue(false)
2462 ::rtl::math::setNan(&mfValue);
2465 ScChart2DataSequence::HiddenRangeListener::HiddenRangeListener(ScChart2DataSequence& rParent) :
2466 mrParent(rParent)
2470 ScChart2DataSequence::HiddenRangeListener::~HiddenRangeListener()
2474 void ScChart2DataSequence::HiddenRangeListener::notify()
2476 mrParent.setDataChangedHint(true);
2479 ScChart2DataSequence::ScChart2DataSequence( ScDocument* pDoc,
2480 const uno::Reference < chart2::data::XDataProvider >& xDP,
2481 vector<ScTokenRef>* pTokens,
2482 bool bIncludeHiddenCells )
2483 : m_bIncludeHiddenCells( bIncludeHiddenCells)
2484 , m_nObjectId( 0 )
2485 , m_pDocument( pDoc)
2486 , m_pTokens(pTokens)
2487 , m_pRangeIndices(NULL)
2488 , m_pExtRefListener(NULL)
2489 , m_xDataProvider( xDP)
2490 , m_aPropSet(lcl_GetDataSequencePropertyMap())
2491 , m_pHiddenListener(NULL)
2492 , m_pValueListener( NULL )
2493 , m_bGotDataChangedHint(false)
2494 , m_bExtDataRebuildQueued(false)
2495 , mbTimeBased(false)
2496 , mnTimeBasedStart(0)
2497 , mnTimeBasedEnd(0)
2498 , mnCurrentTab(0)
2500 OSL_ENSURE(pTokens, "reference token list is null");
2502 if ( m_pDocument )
2504 m_pDocument->AddUnoObject( *this);
2505 m_nObjectId = m_pDocument->GetNewUnoId();
2507 // FIXME: real implementation of identifier and it's mapping to ranges.
2508 // Reuse ScChartListener?
2510 // BM: don't use names of named ranges but the UI range strings
2511 // String aStr;
2512 // rRangeList->Format( aStr, SCR_ABS_3D, m_pDocument );
2513 // m_aIdentifier = aStr;
2515 // m_aIdentifier = "ID_";
2516 // static sal_Int32 nID = 0;
2517 // m_aIdentifier += OUString::valueOf( ++nID);
2520 ScChart2DataSequence::~ScChart2DataSequence()
2522 if ( m_pDocument )
2524 m_pDocument->RemoveUnoObject( *this);
2525 if (m_pHiddenListener.get())
2527 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
2528 if (pCLC)
2529 pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
2531 StopListeningToAllExternalRefs();
2534 delete m_pValueListener;
2537 void ScChart2DataSequence::RefChanged()
2539 if( m_pValueListener && !m_aValueListeners.empty() )
2541 m_pValueListener->EndListeningAll();
2543 if( m_pDocument )
2545 ScChartListenerCollection* pCLC = NULL;
2546 if (m_pHiddenListener.get())
2548 pCLC = m_pDocument->GetChartListenerCollection();
2549 if (pCLC)
2550 pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
2553 vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
2554 for (; itr != itrEnd; ++itr)
2556 ScRange aRange;
2557 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress()))
2558 continue;
2560 m_pDocument->StartListeningArea(aRange, m_pValueListener);
2561 if (pCLC)
2562 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
2568 void ScChart2DataSequence::BuildDataCache()
2570 m_bExtDataRebuildQueued = false;
2572 if (!m_aDataArray.empty())
2573 return;
2575 if (!m_pTokens.get())
2577 OSL_FAIL("m_pTokens == NULL! Something is wrong.");
2578 return;
2581 StopListeningToAllExternalRefs();
2583 ::std::list<sal_Int32> aHiddenValues;
2584 sal_Int32 nDataCount = 0;
2585 sal_Int32 nHiddenValueCount = 0;
2587 for (vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
2588 itr != itrEnd; ++itr)
2590 if (ScRefTokenHelper::isExternalRef(*itr))
2592 nDataCount += FillCacheFromExternalRef(*itr);
2594 else
2596 ScRange aRange;
2597 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress()))
2598 continue;
2600 SCCOL nLastCol = -1;
2601 SCROW nLastRow = -1;
2602 for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
2604 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
2606 for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
2608 bool bColHidden = m_pDocument->ColHidden(nCol, nTab, NULL, &nLastCol);
2609 bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, NULL, &nLastRow);
2611 if (bColHidden || bRowHidden)
2613 // hidden cell
2614 ++nHiddenValueCount;
2615 aHiddenValues.push_back(nDataCount-1);
2617 if( !m_bIncludeHiddenCells )
2618 continue;
2621 m_aDataArray.push_back(Item());
2622 Item& rItem = m_aDataArray.back();
2623 ++nDataCount;
2625 ScAddress aAdr(nCol, nRow, nTab);
2626 rItem.maString = m_pDocument->GetString(aAdr);
2628 switch (m_pDocument->GetCellType(aAdr))
2630 case CELLTYPE_VALUE:
2631 rItem.mfValue = m_pDocument->GetValue(aAdr);
2632 rItem.mbIsValue = true;
2633 break;
2634 case CELLTYPE_FORMULA:
2636 ScFormulaCell* pFCell = m_pDocument->GetFormulaCell(aAdr);
2637 if (!pFCell)
2638 break;
2639 sal_uInt16 nErr = pFCell->GetErrCode();
2640 if (nErr)
2641 break;
2643 if (pFCell->IsValue())
2645 rItem.mfValue = pFCell->GetValue();
2646 rItem.mbIsValue = true;
2649 break;
2650 case CELLTYPE_EDIT:
2651 case CELLTYPE_NONE:
2652 case CELLTYPE_STRING:
2653 default:
2654 ; // do nothing
2662 // convert the hidden cell list to sequence.
2663 m_aHiddenValues.realloc(nHiddenValueCount);
2664 sal_Int32* pArr = m_aHiddenValues.getArray();
2665 ::std::list<sal_Int32>::const_iterator itr = aHiddenValues.begin(), itrEnd = aHiddenValues.end();
2666 for (;itr != itrEnd; ++itr, ++pArr)
2667 *pArr = *itr;
2669 // Clear the data series cache when the array is re-built.
2670 m_aMixedDataCache.realloc(0);
2673 void ScChart2DataSequence::RebuildDataCache()
2675 if (!m_bExtDataRebuildQueued)
2677 m_aDataArray.clear();
2678 m_pDocument->BroadcastUno(ScHint(SC_HINT_DATACHANGED, ScAddress()));
2679 m_bExtDataRebuildQueued = true;
2680 m_bGotDataChangedHint = true;
2684 sal_Int32 ScChart2DataSequence::FillCacheFromExternalRef(const ScTokenRef& pToken)
2686 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
2687 ScRange aRange;
2688 if (!ScRefTokenHelper::getRangeFromToken(aRange, pToken, ScAddress(), true))
2689 return 0;
2691 sal_uInt16 nFileId = pToken->GetIndex();
2692 OUString aTabName = pToken->GetString().getString();
2693 ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, aTabName, aRange, NULL);
2694 if (!pArray)
2695 // no external data exists for this range.
2696 return 0;
2698 // Start listening for this external document.
2699 ExternalRefListener* pExtRefListener = GetExtRefListener();
2700 pRefMgr->addLinkListener(nFileId, pExtRefListener);
2701 pExtRefListener->addFileId(nFileId);
2703 ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, aTabName, false, NULL);
2704 sal_Int32 nDataCount = 0;
2705 for (FormulaToken* p = pArray->First(); p; p = pArray->Next())
2707 // Cached external range is always represented as a single
2708 // matrix token, although that might change in the future when
2709 // we introduce a new token type to store multi-table range
2710 // data.
2712 if (p->GetType() != svMatrix)
2714 OSL_FAIL("Cached array is not a matrix token.");
2715 continue;
2718 const ScMatrix* pMat = static_cast<ScToken*>(p)->GetMatrix();
2719 SCSIZE nCSize, nRSize;
2720 pMat->GetDimensions(nCSize, nRSize);
2721 for (SCSIZE nC = 0; nC < nCSize; ++nC)
2723 for (SCSIZE nR = 0; nR < nRSize; ++nR)
2725 if (pMat->IsValue(nC, nR) || pMat->IsBoolean(nC, nR))
2727 m_aDataArray.push_back(Item());
2728 Item& rItem = m_aDataArray.back();
2729 ++nDataCount;
2731 rItem.mbIsValue = true;
2732 rItem.mfValue = pMat->GetDouble(nC, nR);
2734 SvNumberFormatter* pFormatter = m_pDocument->GetFormatTable();
2735 if (pFormatter)
2737 const double fVal = rItem.mfValue;
2738 Color* pColor = NULL;
2739 sal_uInt32 nFmt = 0;
2740 if (pTable)
2742 // Get the correct format index from the cache.
2743 SCCOL nCol = aRange.aStart.Col() + static_cast<SCCOL>(nC);
2744 SCROW nRow = aRange.aStart.Row() + static_cast<SCROW>(nR);
2745 pTable->getCell(nCol, nRow, &nFmt);
2747 pFormatter->GetOutputString(fVal, nFmt, rItem.maString, &pColor);
2750 else if (pMat->IsString(nC, nR))
2752 m_aDataArray.push_back(Item());
2753 Item& rItem = m_aDataArray.back();
2754 ++nDataCount;
2756 rItem.mbIsValue = false;
2757 rItem.maString = pMat->GetString(nC, nR).getString();
2762 return nDataCount;
2765 void ScChart2DataSequence::UpdateTokensFromRanges(const ScRangeList& rRanges)
2767 if (!m_pRangeIndices.get())
2768 return;
2770 for ( size_t i = 0, nCount = rRanges.size(); i < nCount; ++i )
2772 ScTokenRef pToken;
2773 const ScRange* pRange = rRanges[i];
2774 OSL_ENSURE(pRange, "range object is NULL.");
2776 ScRefTokenHelper::getTokenFromRange(pToken, *pRange);
2777 sal_uInt32 nOrigPos = (*m_pRangeIndices)[i];
2778 (*m_pTokens)[nOrigPos] = pToken;
2781 RefChanged();
2783 // any change of the range address is broadcast to value (modify) listeners
2784 if ( !m_aValueListeners.empty() )
2785 m_bGotDataChangedHint = true;
2788 ScChart2DataSequence::ExternalRefListener* ScChart2DataSequence::GetExtRefListener()
2790 if (!m_pExtRefListener.get())
2791 m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
2793 return m_pExtRefListener.get();
2796 void ScChart2DataSequence::StopListeningToAllExternalRefs()
2798 if (!m_pExtRefListener.get())
2799 return;
2801 const boost::unordered_set<sal_uInt16>& rFileIds = m_pExtRefListener->getAllFileIds();
2802 boost::unordered_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
2803 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
2804 for (; itr != itrEnd; ++itr)
2805 pRefMgr->removeLinkListener(*itr, m_pExtRefListener.get());
2807 m_pExtRefListener.reset();
2810 void ScChart2DataSequence::CopyData(const ScChart2DataSequence& r)
2812 if (!m_pDocument)
2814 OSL_FAIL("document instance is NULL!?");
2815 return;
2818 list<Item> aDataArray(r.m_aDataArray);
2819 m_aDataArray.swap(aDataArray);
2821 m_aHiddenValues = r.m_aHiddenValues;
2822 m_aRole = r.m_aRole;
2824 if (r.m_pRangeIndices.get())
2825 m_pRangeIndices.reset(new vector<sal_uInt32>(*r.m_pRangeIndices));
2827 if (r.m_pExtRefListener.get())
2829 // Re-register all external files that the old instance was
2830 // listening to.
2832 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
2833 m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
2834 const boost::unordered_set<sal_uInt16>& rFileIds = r.m_pExtRefListener->getAllFileIds();
2835 boost::unordered_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
2836 for (; itr != itrEnd; ++itr)
2838 pRefMgr->addLinkListener(*itr, m_pExtRefListener.get());
2839 m_pExtRefListener->addFileId(*itr);
2844 void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
2846 if ( rHint.ISA( SfxSimpleHint ) )
2848 sal_uLong nId = static_cast<const SfxSimpleHint&>(rHint).GetId();
2849 if ( nId ==SFX_HINT_DYING )
2851 m_pDocument = NULL;
2853 else if ( nId == SFX_HINT_DATACHANGED )
2855 // delayed broadcast as in ScCellRangesBase
2857 if ( m_bGotDataChangedHint && m_pDocument )
2859 m_aDataArray.clear();
2860 lang::EventObject aEvent;
2861 aEvent.Source.set((cppu::OWeakObject*)this);
2863 if( m_pDocument )
2865 for ( sal_uInt16 n=0; n<m_aValueListeners.size(); n++ )
2866 m_pDocument->AddUnoListenerCall( m_aValueListeners[n], aEvent );
2869 m_bGotDataChangedHint = false;
2872 else if ( nId == SC_HINT_CALCALL )
2874 // broadcast from DoHardRecalc - set m_bGotDataChangedHint
2875 // (SFX_HINT_DATACHANGED follows separately)
2877 if ( !m_aValueListeners.empty() )
2878 m_bGotDataChangedHint = true;
2881 else if ( rHint.ISA( ScUpdateRefHint ) )
2883 // Create a range list from the token list, have the range list
2884 // updated, and bring the change back to the token list.
2886 ScRangeList aRanges;
2887 m_pRangeIndices.reset(new vector<sal_uInt32>());
2888 vector<ScTokenRef>::const_iterator itrBeg = m_pTokens->begin(), itrEnd = m_pTokens->end();
2889 for (vector<ScTokenRef>::const_iterator itr = itrBeg ;itr != itrEnd; ++itr)
2891 if (!ScRefTokenHelper::isExternalRef(*itr))
2893 ScRange aRange;
2894 ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress());
2895 aRanges.Append(aRange);
2896 sal_uInt32 nPos = distance(itrBeg, itr);
2897 m_pRangeIndices->push_back(nPos);
2901 OSL_ENSURE(m_pRangeIndices->size() == static_cast<size_t>(aRanges.size()),
2902 "range list and range index list have different sizes.");
2904 SAL_WNODEPRECATED_DECLARATIONS_PUSH
2905 auto_ptr<ScRangeList> pUndoRanges;
2906 SAL_WNODEPRECATED_DECLARATIONS_POP
2907 if ( m_pDocument->HasUnoRefUndo() )
2908 pUndoRanges.reset(new ScRangeList(aRanges));
2910 const ScUpdateRefHint& rRef = (const ScUpdateRefHint&)rHint;
2911 bool bChanged = aRanges.UpdateReference(
2912 rRef.GetMode(), m_pDocument, rRef.GetRange(), rRef.GetDx(), rRef.GetDy(), rRef.GetDz());
2914 if (bChanged)
2916 OSL_ENSURE(m_pRangeIndices->size() == aRanges.size(),
2917 "range list and range index list have different sizes after the reference update.");
2919 // Bring the change back from the range list to the token list.
2920 UpdateTokensFromRanges(aRanges);
2922 if (pUndoRanges.get())
2923 m_pDocument->AddUnoRefChange(m_nObjectId, *pUndoRanges);
2926 else if ( rHint.ISA( ScUnoRefUndoHint ) )
2928 const ScUnoRefUndoHint& rUndoHint = static_cast<const ScUnoRefUndoHint&>(rHint);
2932 if (rUndoHint.GetObjectId() != m_nObjectId)
2933 break;
2935 // The hint object provides the old ranges. Restore the old state
2936 // from these ranges.
2938 if (!m_pRangeIndices.get() || m_pRangeIndices->empty())
2940 OSL_FAIL(" faulty range indices");
2941 break;
2944 const ScRangeList& rRanges = rUndoHint.GetRanges();
2946 size_t nCount = rRanges.size();
2947 if (nCount != m_pRangeIndices->size())
2949 OSL_FAIL("range count and range index count differ.");
2950 break;
2953 UpdateTokensFromRanges(rRanges);
2955 while (false);
2960 IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, SfxHint*, pHint )
2962 if ( m_pDocument && pHint && pHint->ISA( SfxSimpleHint ) &&
2963 ((const SfxSimpleHint*)pHint)->GetId() & SC_HINT_DATACHANGED)
2965 // This may be called several times for a single change, if several formulas
2966 // in the range are notified. So only a flag is set that is checked when
2967 // SFX_HINT_DATACHANGED is received.
2969 setDataChangedHint(true);
2971 return 0;
2974 ScChart2DataSequence::ExternalRefListener::ExternalRefListener(
2975 ScChart2DataSequence& rParent, ScDocument* pDoc) :
2976 ScExternalRefManager::LinkListener(),
2977 mrParent(rParent),
2978 mpDoc(pDoc)
2982 ScChart2DataSequence::ExternalRefListener::~ExternalRefListener()
2984 if (!mpDoc || mpDoc->IsInDtorClear())
2985 // The document is being destroyed. Do nothing.
2986 return;
2988 // Make sure to remove all pointers to this object.
2989 mpDoc->GetExternalRefManager()->removeLinkListener(this);
2992 void ScChart2DataSequence::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
2994 switch (eType)
2996 case ScExternalRefManager::LINK_MODIFIED:
2998 if (maFileIds.count(nFileId))
2999 // We are listening to this external document.
3000 mrParent.RebuildDataCache();
3002 break;
3003 case ScExternalRefManager::LINK_BROKEN:
3004 removeFileId(nFileId);
3005 break;
3009 void ScChart2DataSequence::ExternalRefListener::addFileId(sal_uInt16 nFileId)
3011 maFileIds.insert(nFileId);
3014 void ScChart2DataSequence::ExternalRefListener::removeFileId(sal_uInt16 nFileId)
3016 maFileIds.erase(nFileId);
3019 const boost::unordered_set<sal_uInt16>& ScChart2DataSequence::ExternalRefListener::getAllFileIds()
3021 return maFileIds;
3024 uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
3025 throw (uno::RuntimeException, std::exception)
3027 SolarMutexGuard aGuard;
3028 if ( !m_pDocument)
3029 throw uno::RuntimeException();
3031 BuildDataCache();
3033 if (!m_aMixedDataCache.getLength())
3035 // Build a cache for the 1st time...
3037 sal_Int32 nCount = m_aDataArray.size();
3038 m_aMixedDataCache.realloc(nCount);
3039 uno::Any* pArr = m_aMixedDataCache.getArray();
3040 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3041 for (; itr != itrEnd; ++itr, ++pArr)
3043 if (itr->mbIsValue)
3044 *pArr <<= itr->mfValue;
3045 else
3046 *pArr <<= itr->maString;
3049 return m_aMixedDataCache;
3052 // XNumericalDataSequence --------------------------------------------------
3054 uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData()
3055 throw (uno::RuntimeException, std::exception)
3057 SolarMutexGuard aGuard;
3058 if ( !m_pDocument)
3059 throw uno::RuntimeException();
3061 BuildDataCache();
3063 double fNAN;
3064 ::rtl::math::setNan(&fNAN);
3066 sal_Int32 nCount = m_aDataArray.size();
3067 uno::Sequence<double> aSeq(nCount);
3068 double* pArr = aSeq.getArray();
3069 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3070 for (; itr != itrEnd; ++itr, ++pArr)
3071 *pArr = itr->mbIsValue ? itr->mfValue : fNAN;
3073 return aSeq;
3076 // XTextualDataSequence --------------------------------------------------
3078 uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::getTextualData()
3079 throw (uno::RuntimeException, std::exception)
3081 SolarMutexGuard aGuard;
3082 uno::Sequence<OUString> aSeq;
3083 if ( !m_pDocument )
3084 throw uno::RuntimeException();
3086 BuildDataCache();
3088 sal_Int32 nCount = m_aDataArray.size();
3089 if ( nCount > 0 )
3091 aSeq = uno::Sequence<OUString>(nCount);
3092 OUString* pArr = aSeq.getArray();
3093 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3094 for(; itr != itrEnd; ++itr, ++pArr)
3095 *pArr = itr->maString;
3097 else if ( m_pTokens.get() && m_pTokens->front() )
3099 if( m_pTokens->front()->GetType() == svString )
3101 aSeq = uno::Sequence<OUString>(1);
3102 aSeq[0] = m_pTokens->front()->GetString().getString();
3106 return aSeq;
3109 OUString SAL_CALL ScChart2DataSequence::getSourceRangeRepresentation()
3110 throw ( uno::RuntimeException, std::exception)
3112 SolarMutexGuard aGuard;
3113 OUString aStr;
3114 OSL_ENSURE( m_pDocument, "No Document -> no SourceRangeRepresentation" );
3115 if (m_pDocument && m_pTokens.get())
3116 lcl_convertTokensToString(aStr, *m_pTokens, m_pDocument);
3118 return aStr;
3121 namespace {
3124 * This function object is used to accumulatively count the numbers of
3125 * columns and rows in all reference tokens.
3127 class AccumulateRangeSize : public unary_function<ScTokenRef, void>
3129 public:
3130 AccumulateRangeSize() :
3131 mnCols(0), mnRows(0) {}
3133 AccumulateRangeSize(const AccumulateRangeSize& r) :
3134 mnCols(r.mnCols), mnRows(r.mnRows) {}
3136 void operator() (const ScTokenRef& pToken)
3138 ScRange r;
3139 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3140 ScRefTokenHelper::getRangeFromToken(r, pToken, ScAddress(), bExternal);
3141 r.Justify();
3142 mnCols += r.aEnd.Col() - r.aStart.Col() + 1;
3143 mnRows += r.aEnd.Row() - r.aStart.Row() + 1;
3146 SCCOL getCols() const { return mnCols; }
3147 SCROW getRows() const { return mnRows; }
3148 private:
3149 SCCOL mnCols;
3150 SCROW mnRows;
3154 * This function object is used to generate label strings from a list of
3155 * reference tokens.
3157 class GenerateLabelStrings : public unary_function<ScTokenRef, void>
3159 public:
3160 GenerateLabelStrings(sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) :
3161 mpLabels(new Sequence<OUString>(nSize)),
3162 meOrigin(eOrigin),
3163 mnCount(0),
3164 mbColumn(bColumn) {}
3166 GenerateLabelStrings(const GenerateLabelStrings& r) :
3167 mpLabels(r.mpLabels),
3168 meOrigin(r.meOrigin),
3169 mnCount(r.mnCount),
3170 mbColumn(r.mbColumn) {}
3172 void operator() (const ScTokenRef& pToken)
3174 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3175 ScRange aRange;
3176 ScRefTokenHelper::getRangeFromToken(aRange, pToken, ScAddress(), bExternal);
3177 OUString* pArr = mpLabels->getArray();
3178 if (mbColumn)
3180 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
3182 if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3184 OUString aString = ScGlobal::GetRscString(STR_COLUMN);
3185 aString += " ";
3186 ScAddress aPos( nCol, 0, 0 );
3187 OUString aColStr(aPos.Format(SCA_VALID_COL, NULL));
3188 aString += aColStr;
3189 pArr[mnCount] = aString;
3191 else //only indices for categories
3192 pArr[mnCount] = OUString::number( mnCount+1 );
3193 ++mnCount;
3196 else
3198 for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
3200 if (meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3202 OUString aString = ScGlobal::GetRscString(STR_ROW) +
3203 " " + OUString::number( nRow+1 );
3204 pArr[mnCount] = aString;
3206 else //only indices for categories
3207 pArr[mnCount] = OUString::number( mnCount+1 );
3208 ++mnCount;
3213 Sequence<OUString> getLabels() const { return *mpLabels; }
3215 private:
3216 shared_ptr< Sequence<OUString> > mpLabels;
3217 chart2::data::LabelOrigin meOrigin;
3218 sal_Int32 mnCount;
3219 bool mbColumn;
3224 uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
3225 throw (uno::RuntimeException, std::exception)
3227 SolarMutexGuard aGuard;
3228 if ( !m_pDocument)
3229 throw uno::RuntimeException();
3231 if (!m_pTokens.get())
3232 return Sequence<OUString>();
3234 // Determine the total size of all ranges.
3235 AccumulateRangeSize func;
3236 func = ::std::for_each(m_pTokens->begin(), m_pTokens->end(), func);
3237 SCCOL nCols = func.getCols();
3238 SCROW nRows = func.getRows();
3240 // Detemine whether this is column-major or row-major.
3241 bool bColumn = true;
3242 if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
3243 (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
3245 if (nRows > nCols)
3247 if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
3248 bColumn = true;
3249 else
3250 bColumn = false;
3252 else if (nCols > nRows)
3254 if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
3255 bColumn = false;
3256 else
3257 bColumn = true;
3259 else
3260 return Sequence<OUString>();
3263 // Generate label strings based on the info so far.
3264 sal_Int32 nCount = bColumn ? nCols : nRows;
3265 GenerateLabelStrings genLabels(nCount, eOrigin, bColumn);
3266 genLabels = ::std::for_each(m_pTokens->begin(), m_pTokens->end(), genLabels);
3267 Sequence<OUString> aSeq = genLabels.getLabels();
3269 return aSeq;
3272 namespace {
3274 sal_uLong getDisplayNumberFormat(ScDocument* pDoc, const ScAddress& rPos)
3276 sal_uLong nFormat = pDoc->GetNumberFormat(rPos); // original format from cell.
3277 return nFormat;
3282 ::sal_Int32 SAL_CALL ScChart2DataSequence::getNumberFormatKeyByIndex( ::sal_Int32 nIndex )
3283 throw (lang::IndexOutOfBoundsException, uno::RuntimeException, std::exception)
3285 // index -1 means a heuristic value for the entire sequence
3286 bool bGetSeriesFormat = (nIndex == -1);
3288 SolarMutexGuard aGuard;
3289 if ( !m_pDocument || !m_pTokens.get())
3290 return 0;
3292 // TODO: Handle external references too.
3294 sal_Int32 nCount = 0;
3296 ScRangeList aRanges;
3297 ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens, ScAddress());
3298 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
3300 ScRange* p = aRanges[i];
3301 for (SCTAB nTab = p->aStart.Tab(); nTab <= p->aEnd.Tab(); ++nTab)
3303 for (SCCOL nCol = p->aStart.Col(); nCol <= p->aEnd.Col(); ++nCol)
3305 if (!m_bIncludeHiddenCells)
3307 // Skip hidden columns.
3308 SCCOL nLastCol = -1;
3309 bool bColHidden = m_pDocument->ColHidden(nCol, nTab, NULL, &nLastCol);
3310 if (bColHidden)
3312 nCol = nLastCol;
3313 continue;
3317 for (SCROW nRow = p->aStart.Row(); nRow <= p->aEnd.Row(); ++nRow)
3319 if (!m_bIncludeHiddenCells)
3321 // Skip hidden rows.
3322 SCROW nLastRow = -1;
3323 bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, NULL, &nLastRow);
3324 if (bRowHidden)
3326 nRow = nLastRow;
3327 continue;
3331 ScAddress aPos(nCol, nRow, nTab);
3333 if( bGetSeriesFormat )
3335 // TODO: use nicer heuristic
3336 // return format of first non-empty cell
3337 ScRefCellValue aCell;
3338 aCell.assign(*m_pDocument, aPos);
3339 if (!aCell.isEmpty())
3340 return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, aPos));
3342 else if( nCount == nIndex )
3344 return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, aPos));
3346 ++nCount;
3351 return 0;
3354 // XCloneable ================================================================
3356 uno::Reference< util::XCloneable > SAL_CALL ScChart2DataSequence::createClone()
3357 throw (uno::RuntimeException, std::exception)
3359 SolarMutexGuard aGuard;
3361 SAL_WNODEPRECATED_DECLARATIONS_PUSH
3362 auto_ptr< vector<ScTokenRef> > pTokensNew;
3363 SAL_WNODEPRECATED_DECLARATIONS_POP
3364 if (m_pTokens.get())
3366 // Clone tokens.
3367 pTokensNew.reset(new vector<ScTokenRef>);
3368 pTokensNew->reserve(m_pTokens->size());
3369 vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
3370 for (; itr != itrEnd; ++itr)
3372 ScTokenRef p(static_cast<ScToken*>((*itr)->Clone()));
3373 pTokensNew->push_back(p);
3377 SAL_WNODEPRECATED_DECLARATIONS_PUSH
3378 auto_ptr<ScChart2DataSequence> p(new ScChart2DataSequence(m_pDocument, m_xDataProvider, pTokensNew.release(), m_bIncludeHiddenCells));
3379 SAL_WNODEPRECATED_DECLARATIONS_POP
3380 p->CopyData(*this);
3381 Reference< util::XCloneable > xClone(p.release());
3383 return xClone;
3386 // XModifyBroadcaster ========================================================
3388 void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3389 throw (uno::RuntimeException, std::exception)
3391 // like ScCellRangesBase::addModifyListener
3392 SolarMutexGuard aGuard;
3393 if (!m_pTokens.get() || m_pTokens->empty())
3394 return;
3396 ScRangeList aRanges;
3397 ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens, ScAddress());
3398 uno::Reference<util::XModifyListener> *pObj =
3399 new uno::Reference<util::XModifyListener>( aListener );
3400 m_aValueListeners.push_back( pObj );
3402 if ( m_aValueListeners.size() == 1 )
3404 if (!m_pValueListener)
3405 m_pValueListener = new ScLinkListener( LINK( this, ScChart2DataSequence, ValueListenerHdl ) );
3407 if (!m_pHiddenListener.get())
3408 m_pHiddenListener.reset(new HiddenRangeListener(*this));
3410 if( m_pDocument )
3412 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
3413 vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
3414 for (; itr != itrEnd; ++itr)
3416 ScRange aRange;
3417 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress()))
3418 continue;
3420 m_pDocument->StartListeningArea( aRange, m_pValueListener );
3421 if (pCLC)
3422 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
3426 acquire(); // don't lose this object (one ref for all listeners)
3430 void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3431 throw (uno::RuntimeException, std::exception)
3433 // like ScCellRangesBase::removeModifyListener
3435 SolarMutexGuard aGuard;
3436 if (!m_pTokens.get() || m_pTokens->empty())
3437 return;
3439 acquire(); // in case the listeners have the last ref - released below
3441 sal_uInt16 nCount = m_aValueListeners.size();
3442 for ( sal_uInt16 n=nCount; n--; )
3444 uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
3445 if ( rObj == aListener )
3447 m_aValueListeners.erase( m_aValueListeners.begin() + n );
3449 if ( m_aValueListeners.empty() )
3451 if (m_pValueListener)
3452 m_pValueListener->EndListeningAll();
3454 if (m_pHiddenListener.get() && m_pDocument)
3456 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
3457 if (pCLC)
3458 pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
3461 release(); // release the ref for the listeners
3464 break;
3468 release(); // might delete this object
3471 // DataSequence XPropertySet -------------------------------------------------
3473 uno::Reference< beans::XPropertySetInfo> SAL_CALL
3474 ScChart2DataSequence::getPropertySetInfo() throw( uno::RuntimeException, std::exception)
3476 SolarMutexGuard aGuard;
3477 static uno::Reference<beans::XPropertySetInfo> aRef =
3478 new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
3479 return aRef;
3483 void SAL_CALL ScChart2DataSequence::setPropertyValue(
3484 const OUString& rPropertyName, const uno::Any& rValue)
3485 throw( beans::UnknownPropertyException,
3486 beans::PropertyVetoException,
3487 lang::IllegalArgumentException,
3488 lang::WrappedTargetException, uno::RuntimeException, std::exception)
3490 if ( rPropertyName == SC_UNONAME_ROLE )
3492 if ( !(rValue >>= m_aRole))
3493 throw lang::IllegalArgumentException();
3495 else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3497 bool bOldValue = m_bIncludeHiddenCells;
3498 if ( !(rValue >>= m_bIncludeHiddenCells))
3499 throw lang::IllegalArgumentException();
3500 if( bOldValue != m_bIncludeHiddenCells )
3501 m_aDataArray.clear();//data array is dirty now
3503 else if( rPropertyName == "TimeBased" )
3505 bool bTimeBased = mbTimeBased;
3506 rValue>>= bTimeBased;
3507 mbTimeBased = bTimeBased;
3509 else
3510 throw beans::UnknownPropertyException();
3511 // TODO: support optional properties
3515 uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue(const OUString& rPropertyName)
3516 throw(beans::UnknownPropertyException,
3517 lang::WrappedTargetException,
3518 uno::RuntimeException,
3519 std::exception)
3521 uno::Any aRet;
3522 if ( rPropertyName == SC_UNONAME_ROLE )
3523 aRet <<= m_aRole;
3524 else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3525 aRet <<= m_bIncludeHiddenCells;
3526 else if ( rPropertyName == SC_UNONAME_HIDDENVALUES )
3528 // This property is read-only thus cannot be set externally via
3529 // setPropertyValue(...).
3530 BuildDataCache();
3531 aRet <<= m_aHiddenValues;
3533 else if (rPropertyName == "TimeBased")
3535 aRet <<= mbTimeBased;
3537 else
3538 throw beans::UnknownPropertyException();
3539 // TODO: support optional properties
3540 return aRet;
3544 void SAL_CALL ScChart2DataSequence::addPropertyChangeListener(
3545 const OUString& /*rPropertyName*/,
3546 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
3547 throw( beans::UnknownPropertyException,
3548 lang::WrappedTargetException, uno::RuntimeException, std::exception)
3550 // FIXME: real implementation
3551 OSL_FAIL( "Not yet implemented" );
3555 void SAL_CALL ScChart2DataSequence::removePropertyChangeListener(
3556 const OUString& /*rPropertyName*/,
3557 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
3558 throw( beans::UnknownPropertyException,
3559 lang::WrappedTargetException, uno::RuntimeException, std::exception)
3561 // FIXME: real implementation
3562 OSL_FAIL( "Not yet implemented" );
3566 void SAL_CALL ScChart2DataSequence::addVetoableChangeListener(
3567 const OUString& /*rPropertyName*/,
3568 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3569 throw( beans::UnknownPropertyException,
3570 lang::WrappedTargetException, uno::RuntimeException, std::exception)
3572 // FIXME: real implementation
3573 OSL_FAIL( "Not yet implemented" );
3577 void SAL_CALL ScChart2DataSequence::removeVetoableChangeListener(
3578 const OUString& /*rPropertyName*/,
3579 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3580 throw( beans::UnknownPropertyException,
3581 lang::WrappedTargetException, uno::RuntimeException, std::exception)
3583 // FIXME: real implementation
3584 OSL_FAIL( "Not yet implemented" );
3587 void ScChart2DataSequence::setDataChangedHint(bool b)
3589 m_bGotDataChangedHint = b;
3592 sal_Bool ScChart2DataSequence::switchToNext(sal_Bool bWrap)
3593 throw (uno::RuntimeException, std::exception)
3595 if(!m_pTokens || !mbTimeBased)
3596 return sal_True;
3598 if(mnCurrentTab >= mnTimeBasedEnd)
3600 if(bWrap)
3601 setToPointInTime(0);
3602 return false;
3605 for(vector<ScTokenRef>::iterator itr = m_pTokens->begin(),
3606 itrEnd = m_pTokens->end(); itr != itrEnd; ++itr)
3608 if ((*itr)->GetType() != svDoubleRef)
3609 continue;
3611 ScComplexRefData& rData = (*itr)->GetDoubleRef();
3612 ScSingleRefData& s = rData.Ref1;
3613 ScSingleRefData& e = rData.Ref2;
3615 s.IncTab(1);
3616 e.IncTab(1);
3619 ++mnCurrentTab;
3621 RebuildDataCache();
3623 return sal_True;
3626 void ScChart2DataSequence::setRange(sal_Int32 nStart, sal_Int32 nEnd)
3627 throw (uno::RuntimeException, std::exception)
3629 mnTimeBasedStart = nStart;
3630 mnTimeBasedEnd = nEnd;
3631 mnCurrentTab = mnTimeBasedStart;
3634 sal_Bool ScChart2DataSequence::setToPointInTime(sal_Int32 nPoint)
3635 throw (uno::RuntimeException, std::exception)
3637 if(!m_pTokens)
3638 return sal_True;
3640 if(nPoint > mnTimeBasedEnd - mnTimeBasedStart)
3641 return false;
3643 SCTAB nTab = mnTimeBasedStart + nPoint;
3644 for(vector<ScTokenRef>::iterator itr = m_pTokens->begin(),
3645 itrEnd = m_pTokens->end(); itr != itrEnd; ++itr)
3647 if ((*itr)->GetType() != svDoubleRef)
3648 continue;
3650 ScComplexRefData& rData = (*itr)->GetDoubleRef();
3651 ScSingleRefData& s = rData.Ref1;
3652 ScSingleRefData& e = rData.Ref2;
3654 s.SetAbsTab(nTab);
3655 e.SetAbsTab(nTab);
3658 mnCurrentTab = nTab;
3660 RebuildDataCache();
3662 return sal_True;
3665 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */