fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / unoobj / chart2uno.cxx
blob72b19665bd0a668d62eb1b0bbbdf77a140b89878
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 .
20 #include <sal/config.h>
22 #include <utility>
24 #include "chart2uno.hxx"
25 #include "miscuno.hxx"
26 #include "document.hxx"
27 #include "formulacell.hxx"
28 #include "chartpos.hxx"
29 #include "unonames.hxx"
30 #include "globstr.hrc"
31 #include "convuno.hxx"
32 #include "rangeutl.hxx"
33 #include "hints.hxx"
34 #include "unoreflist.hxx"
35 #include "compiler.hxx"
36 #include "reftokenhelper.hxx"
37 #include "chartlis.hxx"
38 #include "tokenuno.hxx"
39 #include "docsh.hxx"
40 #include "cellvalue.hxx"
41 #include "tokenarray.hxx"
42 #include "scmatrix.hxx"
43 #include <brdcst.hxx>
45 #include <formula/opcode.hxx>
46 #include <svl/sharedstring.hxx>
48 #include <sfx2/objsh.hxx>
49 #include <vcl/svapp.hxx>
51 #include <com/sun/star/beans/UnknownPropertyException.hpp>
52 #include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
53 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
54 #include <com/sun/star/table/XCellRange.hpp>
55 #include <com/sun/star/table/CellAddress.hpp>
56 #include <com/sun/star/text/XText.hpp>
57 #include <comphelper/extract.hxx>
58 #include <comphelper/processfactory.hxx>
60 #include <rtl/math.hxx>
61 #include <boost/checked_delete.hpp>
63 SC_SIMPLE_SERVICE_INFO( ScChart2DataProvider, "ScChart2DataProvider",
64 "com.sun.star.chart2.data.DataProvider")
65 SC_SIMPLE_SERVICE_INFO( ScChart2DataSource, "ScChart2DataSource",
66 "com.sun.star.chart2.data.DataSource")
67 SC_SIMPLE_SERVICE_INFO( ScChart2DataSequence, "ScChart2DataSequence",
68 "com.sun.star.chart2.data.DataSequence")
70 using namespace ::com::sun::star;
71 using namespace ::formula;
72 using ::com::sun::star::uno::Sequence;
73 using ::com::sun::star::uno::Reference;
74 using ::std::unique_ptr;
75 using ::std::vector;
76 using ::std::list;
77 using ::std::distance;
78 using ::std::unary_function;
79 using ::boost::shared_ptr;
81 namespace
83 const SfxItemPropertyMapEntry* lcl_GetDataProviderPropertyMap()
85 static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
87 { OUString(SC_UNONAME_INCLUDEHIDDENCELLS), 0, cppu::UnoType<bool>::get(), 0, 0 },
88 { OUString(SC_UNONAME_USE_INTERNAL_DATA_PROVIDER), 0, cppu::UnoType<bool>::get(), 0, 0 },
89 { OUString(), 0, css::uno::Type(), 0, 0 }
91 return aDataProviderPropertyMap_Impl;
94 const SfxItemPropertyMapEntry* lcl_GetDataSequencePropertyMap()
96 static const SfxItemPropertyMapEntry aDataSequencePropertyMap_Impl[] =
98 {OUString(SC_UNONAME_HIDDENVALUES), 0, cppu::UnoType<uno::Sequence<sal_Int32>>::get(), 0, 0 },
99 {OUString(SC_UNONAME_ROLE), 0, cppu::UnoType<com::sun::star::chart2::data::DataSequenceRole>::get(), 0, 0 },
100 {OUString(SC_UNONAME_INCLUDEHIDDENCELLS), 0, cppu::UnoType<bool>::get(), 0, 0 },
101 { OUString(), 0, css::uno::Type(), 0, 0 }
103 return aDataSequencePropertyMap_Impl;
106 template< typename T >
107 ::com::sun::star::uno::Sequence< T > lcl_VectorToSequence(
108 const ::std::vector< T > & rCont )
110 ::com::sun::star::uno::Sequence< T > aResult( rCont.size());
111 ::std::copy( rCont.begin(), rCont.end(), aResult.getArray());
112 return aResult;
115 struct lcl_appendTableNumber : public ::std::unary_function< SCTAB, void >
117 lcl_appendTableNumber( OUStringBuffer & rBuffer ) :
118 m_rBuffer( rBuffer )
120 void operator() ( SCTAB nTab )
122 // there is no append with SCTAB or sal_Int16
123 m_rBuffer.append( static_cast< sal_Int32 >( nTab ));
124 m_rBuffer.append( ' ' );
126 private:
127 OUStringBuffer & m_rBuffer;
130 OUString lcl_createTableNumberList( const ::std::list< SCTAB > & rTableList )
132 OUStringBuffer aBuffer;
133 ::std::for_each( rTableList.begin(), rTableList.end(), lcl_appendTableNumber( aBuffer ));
134 // remove last trailing ' '
135 if( !aBuffer.isEmpty() )
136 aBuffer.setLength( aBuffer.getLength() - 1 );
137 return aBuffer.makeStringAndClear();
140 uno::Reference< frame::XModel > lcl_GetXModel( ScDocument * pDoc )
142 uno::Reference< frame::XModel > xModel;
143 SfxObjectShell * pObjSh( pDoc ? pDoc->GetDocumentShell() : 0 );
144 if( pObjSh )
145 xModel.set( pObjSh->GetModel());
146 return xModel;
149 struct TokenTable : boost::noncopyable
151 SCROW mnRowCount;
152 SCCOL mnColCount;
153 vector<FormulaToken*> maTokens;
155 void init( SCCOL nColCount, SCROW nRowCount )
157 mnColCount = nColCount;
158 mnRowCount = nRowCount;
159 maTokens.reserve(mnColCount*mnRowCount);
161 void clear()
163 std::for_each(maTokens.begin(), maTokens.end(), boost::checked_deleter<FormulaToken>());
166 void push_back( FormulaToken* pToken )
168 maTokens.push_back( pToken );
169 OSL_ENSURE( maTokens.size()<= static_cast<sal_uInt32>( mnColCount*mnRowCount ), "too much tokens" );
172 sal_uInt32 getIndex(SCCOL nCol, SCROW nRow) const
174 OSL_ENSURE( nCol<mnColCount, "wrong column index" );
175 OSL_ENSURE( nRow<mnRowCount, "wrong row index" );
176 sal_uInt32 nRet = static_cast<sal_uInt32>(nCol*mnRowCount + nRow);
177 OSL_ENSURE( maTokens.size()>= static_cast<sal_uInt32>( mnColCount*mnRowCount ), "too few tokens" );
178 return nRet;
181 vector<ScTokenRef>* getColRanges(SCCOL nCol) const;
182 vector<ScTokenRef>* getRowRanges(SCROW nRow) const;
183 vector<ScTokenRef>* getAllRanges() const;
186 vector<ScTokenRef>* TokenTable::getColRanges(SCCOL nCol) const
188 if (nCol >= mnColCount)
189 return NULL;
190 if( mnRowCount<=0 )
191 return NULL;
193 unique_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
194 sal_uInt32 nLast = getIndex(nCol, mnRowCount-1);
195 for (sal_uInt32 i = getIndex(nCol, 0); i <= nLast; ++i)
197 FormulaToken* p = maTokens[i];
198 if (!p)
199 continue;
201 ScTokenRef pCopy(p->Clone());
202 ScRefTokenHelper::join(*pTokens, pCopy, ScAddress());
204 return pTokens.release();
207 vector<ScTokenRef>* TokenTable::getRowRanges(SCROW nRow) const
209 if (nRow >= mnRowCount)
210 return NULL;
211 if( mnColCount<=0 )
212 return NULL;
214 unique_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
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(p->Clone());
223 ScRefTokenHelper::join(*pTokens, p2, ScAddress());
225 return pTokens.release();
228 vector<ScTokenRef>* TokenTable::getAllRanges() const
230 unique_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
231 sal_uInt32 nStop = mnColCount*mnRowCount;
232 for (sal_uInt32 i = 0; i < nStop; i++)
234 FormulaToken* p = maTokens[i];
235 if (!p)
236 continue;
238 ScTokenRef p2(p->Clone());
239 ScRefTokenHelper::join(*pTokens, p2, ScAddress());
241 return pTokens.release();
244 typedef std::map<sal_uInt32, FormulaToken*> FormulaTokenMap;
245 typedef std::map<sal_uInt32, FormulaTokenMap*> FormulaTokenMapMap;
247 class Chart2PositionMap
249 public:
250 Chart2PositionMap(SCCOL nColCount, SCROW nRowCount,
251 bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols,
252 ScDocument* pDoc );
253 ~Chart2PositionMap();
255 SCCOL getDataColCount() const { return mnDataColCount; }
256 SCROW getDataRowCount() const { return mnDataRowCount; }
258 vector<ScTokenRef>* getLeftUpperCornerRanges() const;
259 vector<ScTokenRef>* getAllColHeaderRanges() const;
260 vector<ScTokenRef>* getAllRowHeaderRanges() const;
262 vector<ScTokenRef>* getColHeaderRanges(SCCOL nChartCol) const;
263 vector<ScTokenRef>* getRowHeaderRanges(SCROW nChartRow) const;
265 vector<ScTokenRef>* getDataColRanges(SCCOL nCol) const;
266 vector<ScTokenRef>* getDataRowRanges(SCROW nRow) const;
268 private:
269 SCCOL mnDataColCount;
270 SCROW mnDataRowCount;
272 TokenTable maLeftUpperCorner; //nHeaderColCount*nHeaderRowCount
273 TokenTable maColHeaders; //mnDataColCount*nHeaderRowCount
274 TokenTable maRowHeaders; //nHeaderColCount*mnDataRowCount
275 TokenTable maData;//mnDataColCount*mnDataRowCount
278 Chart2PositionMap::Chart2PositionMap(SCCOL nAllColCount, SCROW nAllRowCount,
279 bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols, ScDocument* pDoc)
281 // if bFillRowHeader is true, at least the first column serves as a row header.
282 // If more than one column is pure text all the first pure text columns are used as header.
283 // Likewise, if bFillColumnHeader is true, at least the first row serves as a column header.
284 // If more than one row is pure text all the first pure text rows are used as header.
286 SCROW nHeaderRowCount = (bFillColumnHeader && nAllColCount && nAllRowCount) ? 1 : 0;
287 SCCOL nHeaderColCount = (bFillRowHeader && nAllColCount && nAllRowCount) ? 1 : 0;
289 if( nHeaderColCount || nHeaderRowCount )
291 const SCCOL nInitialHeaderColCount = nHeaderColCount;
292 //check whether there is more than one text column or row that should be added to the headers
293 SCROW nSmallestValueRowIndex = nAllRowCount;
294 bool bFoundValues = false;
295 bool bFoundAnything = false;
296 FormulaTokenMapMap::const_iterator it1 = rCols.begin();
297 for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol)
299 if (it1 != rCols.end() && nCol>=nHeaderColCount)
301 bool bFoundValuesInRow = false;
302 FormulaTokenMap* pCol = it1->second;
303 FormulaTokenMap::const_iterator it2 = pCol->begin();
304 for (SCROW nRow = 0; !bFoundValuesInRow && nRow < nSmallestValueRowIndex && it2 != pCol->end(); ++nRow)
306 FormulaToken* pToken = it2->second;
307 if (pToken && nRow>=nHeaderRowCount)
309 ScRange aRange;
310 bool bExternal = false;
311 StackVar eType = pToken->GetType();
312 if( eType==svExternal || eType==svExternalSingleRef || eType==svExternalDoubleRef || eType==svExternalName )
313 bExternal = true;//lllll todo correct?
314 ScTokenRef pSharedToken(pToken->Clone());
315 ScRefTokenHelper::getRangeFromToken(aRange, pSharedToken, ScAddress(), bExternal);
316 SCCOL nCol1=0, nCol2=0;
317 SCROW nRow1=0, nRow2=0;
318 SCTAB nTab1=0, nTab2=0;
319 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
320 if (pDoc && pDoc->HasValueData( nCol1, nRow1, nTab1 ))
322 bFoundValuesInRow = bFoundValues = bFoundAnything = true;
323 nSmallestValueRowIndex = std::min( nSmallestValueRowIndex, nRow );
325 if( !bFoundAnything )
327 if (pDoc && pDoc->HasData( nCol1, nRow1, nTab1 ) )
328 bFoundAnything = true;
331 ++it2;
333 if(!bFoundValues && nHeaderColCount>0)
334 nHeaderColCount++;
336 ++it1;
338 if( bFoundAnything )
340 if(nHeaderRowCount>0)
342 if( bFoundValues )
343 nHeaderRowCount = nSmallestValueRowIndex;
344 else if( nAllRowCount>1 )
345 nHeaderRowCount = nAllRowCount-1;
348 else //if the cells are completely empty, just use single header rows and columns
349 nHeaderColCount = nInitialHeaderColCount;
352 mnDataColCount = nAllColCount - nHeaderColCount;
353 mnDataRowCount = nAllRowCount - nHeaderRowCount;
355 maLeftUpperCorner.init(nHeaderColCount,nHeaderRowCount);
356 maColHeaders.init(mnDataColCount,nHeaderRowCount);
357 maRowHeaders.init(nHeaderColCount,mnDataRowCount);
358 maData.init(mnDataColCount,mnDataRowCount);
360 FormulaTokenMapMap::const_iterator it1 = rCols.begin();
361 for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol)
363 if (it1 != rCols.end())
365 FormulaTokenMap* pCol = it1->second;
366 FormulaTokenMap::const_iterator it2 = pCol->begin();
367 for (SCROW nRow = 0; nRow < nAllRowCount; ++nRow)
369 FormulaToken* pToken = NULL;
370 if (it2 != pCol->end())
372 pToken = it2->second;
373 ++it2;
376 if( nCol < nHeaderColCount )
378 if( nRow < nHeaderRowCount )
379 maLeftUpperCorner.push_back(pToken);
380 else
381 maRowHeaders.push_back(pToken);
383 else if( nRow < nHeaderRowCount )
384 maColHeaders.push_back(pToken);
385 else
386 maData.push_back(pToken);
388 ++it1;
393 Chart2PositionMap::~Chart2PositionMap()
395 maLeftUpperCorner.clear();
396 maColHeaders.clear();
397 maRowHeaders.clear();
398 maData.clear();
401 vector<ScTokenRef>* Chart2PositionMap::getLeftUpperCornerRanges() const
403 return maLeftUpperCorner.getAllRanges();
405 vector<ScTokenRef>* Chart2PositionMap::getAllColHeaderRanges() const
407 return maColHeaders.getAllRanges();
409 vector<ScTokenRef>* Chart2PositionMap::getAllRowHeaderRanges() const
411 return maRowHeaders.getAllRanges();
413 vector<ScTokenRef>* Chart2PositionMap::getColHeaderRanges(SCCOL nCol) const
415 return maColHeaders.getColRanges( nCol);
417 vector<ScTokenRef>* Chart2PositionMap::getRowHeaderRanges(SCROW nRow) const
419 return maRowHeaders.getRowRanges( nRow);
422 vector<ScTokenRef>* Chart2PositionMap::getDataColRanges(SCCOL nCol) const
424 return maData.getColRanges( nCol);
427 vector<ScTokenRef>* Chart2PositionMap::getDataRowRanges(SCROW nRow) const
429 return maData.getRowRanges( nRow);
433 * Designed to be a drop-in replacement for ScChartPositioner, in order to
434 * handle external references.
436 class Chart2Positioner : boost::noncopyable
438 enum GlueType
440 GLUETYPE_NA,
441 GLUETYPE_NONE,
442 GLUETYPE_COLS,
443 GLUETYPE_ROWS,
444 GLUETYPE_BOTH
447 public:
448 Chart2Positioner(ScDocument* pDoc, const vector<ScTokenRef>& rRefTokens) :
449 mrRefTokens(rRefTokens),
450 mpPositionMap(NULL),
451 meGlue(GLUETYPE_NA),
452 mnStartCol(0),
453 mnStartRow(0),
454 mpDoc(pDoc),
455 mbColHeaders(false),
456 mbRowHeaders(false),
457 mbDummyUpperLeft(false)
461 ~Chart2Positioner()
465 void setHeaders(bool bColHeaders, bool bRowHeaders)
467 mbColHeaders = bColHeaders;
468 mbRowHeaders = bRowHeaders;
471 Chart2PositionMap* getPositionMap()
473 createPositionMap();
474 return mpPositionMap.get();
477 private:
478 void invalidateGlue();
479 void glueState();
480 void calcGlueState(SCCOL nCols, SCROW nRows);
481 void createPositionMap();
483 private:
484 const vector<ScTokenRef>& mrRefTokens;
485 boost::scoped_ptr<Chart2PositionMap> mpPositionMap;
486 GlueType meGlue;
487 SCCOL mnStartCol;
488 SCROW mnStartRow;
489 ScDocument* mpDoc;
490 bool mbColHeaders:1;
491 bool mbRowHeaders:1;
492 bool mbDummyUpperLeft:1;
495 void Chart2Positioner::invalidateGlue()
497 meGlue = GLUETYPE_NA;
498 mpPositionMap.reset();
501 void Chart2Positioner::glueState()
503 if (meGlue != GLUETYPE_NA)
504 return;
506 mbDummyUpperLeft = false;
507 if (mrRefTokens.size() <= 1)
509 // Source data consists of only one data range.
510 const ScTokenRef& p = mrRefTokens.front();
511 ScComplexRefData aData;
512 if (ScRefTokenHelper::getDoubleRefDataFromToken(aData, p))
514 if (aData.Ref1.Tab() == aData.Ref2.Tab())
515 meGlue = GLUETYPE_NONE;
516 else
517 meGlue = GLUETYPE_COLS;
518 mnStartCol = aData.Ref1.Col();
519 mnStartRow = aData.Ref1.Row();
521 else
523 invalidateGlue();
524 mnStartCol = 0;
525 mnStartRow = 0;
527 return;
530 ScComplexRefData aData;
531 ScRefTokenHelper::getDoubleRefDataFromToken(aData, mrRefTokens.front());
532 mnStartCol = aData.Ref1.Col();
533 mnStartRow = aData.Ref1.Row();
535 SCCOL nEndCol = 0;
536 SCROW nEndRow = 0;
537 for (vector<ScTokenRef>::const_iterator itr = mrRefTokens.begin(), itrEnd = mrRefTokens.end()
538 ; itr != itrEnd; ++itr)
540 ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr);
541 SCCOLROW n1 = aData.Ref1.Col();
542 SCCOLROW n2 = aData.Ref2.Col();
543 if (n1 > MAXCOL)
544 n1 = MAXCOL;
545 if (n2 > MAXCOL)
546 n2 = MAXCOL;
547 if (n1 < mnStartCol)
548 mnStartCol = static_cast<SCCOL>(n1);
549 if (n2 > nEndCol)
550 nEndCol = static_cast<SCCOL>(n2);
552 n1 = aData.Ref1.Row();
553 n2 = aData.Ref2.Row();
554 if (n1 > MAXROW)
555 n1 = MAXROW;
556 if (n2 > MAXROW)
557 n2 = MAXROW;
559 if (n1 < mnStartRow)
560 mnStartRow = static_cast<SCROW>(n1);
561 if (n2 > nEndRow)
562 nEndRow = static_cast<SCROW>(n2);
565 if (mnStartCol == nEndCol)
567 // All source data is in a single column.
568 meGlue = GLUETYPE_ROWS;
569 return;
572 if (mnStartRow == nEndRow)
574 // All source data is in a single row.
575 meGlue = GLUETYPE_COLS;
576 return;
579 // total column size
580 SCCOL nC = nEndCol - mnStartCol + 1;
582 // total row size
583 SCROW nR = nEndRow - mnStartRow + 1;
585 // #i103540# prevent invalid vector size
586 if ((nC <= 0) || (nR <= 0))
588 invalidateGlue();
589 mnStartCol = 0;
590 mnStartRow = 0;
591 return;
594 calcGlueState(nC, nR);
597 enum State { Hole = 0, Occupied = 1, Free = 2, Glue = 3 };
599 void Chart2Positioner::calcGlueState(SCCOL nColSize, SCROW nRowSize)
601 // TODO: This code can use some space optimization. Using an array to
602 // store individual cell's states is terribly inefficient esp for large
603 // data ranges; let's use flat_segment_tree to reduce memory usage here.
605 sal_uInt32 nCR = static_cast<sal_uInt32>(nColSize*nRowSize);
607 vector<State> aCellStates(nCR, Hole);
609 // Mark all referenced cells "occupied".
610 for (vector<ScTokenRef>::const_iterator itr = mrRefTokens.begin(), itrEnd = mrRefTokens.end();
611 itr != itrEnd; ++itr)
613 ScComplexRefData aData;
614 ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr);
615 SCCOL nCol1 = aData.Ref1.Col() - mnStartCol;
616 SCCOL nCol2 = aData.Ref2.Col() - mnStartCol;
617 SCROW nRow1 = aData.Ref1.Row() - mnStartRow;
618 SCROW nRow2 = aData.Ref2.Row() - mnStartRow;
619 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
620 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
622 size_t i = nCol*nRowSize + nRow;
623 aCellStates[i] = Occupied;
627 // If at least one cell in either the first column or first row is empty,
628 // we don't glue at all unless the whole column or row is empty; we expect
629 // all cells in the first column / row to be fully populated. If we have
630 // empty column or row, then we do glue by the column or row,
631 // respectively.
633 bool bGlue = true;
634 bool bGlueCols = false;
635 for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol)
637 for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
639 size_t i = nCol*nRowSize + nRow;
640 if (aCellStates[i] == Occupied)
642 if (nCol == 0 || nRow == 0)
643 break;
645 bGlue = false;
647 else
648 aCellStates[i] = Free;
650 size_t nLast = (nCol+1)*nRowSize - 1; // index for the last cell in the column.
651 if (bGlue && aCellStates[nLast] == Free)
653 // Whole column is empty.
654 aCellStates[nLast] = Glue;
655 bGlueCols = true;
659 bool bGlueRows = false;
660 for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
662 size_t i = nRow;
663 for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol, i += nRowSize)
665 if (aCellStates[i] == Occupied)
667 if (nCol == 0 || nRow == 0)
668 break;
670 bGlue = false;
672 else
673 aCellStates[i] = Free;
675 i = (nColSize-1)*nRowSize + nRow; // index for the row position in the last column.
676 if (bGlue && aCellStates[i] == Free)
678 // Whole row is empty.
679 aCellStates[i] = Glue;
680 bGlueRows = true;
684 size_t i = 1;
685 for (sal_uInt32 n = 1; bGlue && n < nCR; ++n, ++i)
686 if (aCellStates[i] == Hole)
687 bGlue = false;
689 if (bGlue)
691 if (bGlueCols && bGlueRows)
692 meGlue = GLUETYPE_BOTH;
693 else if (bGlueRows)
694 meGlue = GLUETYPE_ROWS;
695 else
696 meGlue = GLUETYPE_COLS;
697 if (aCellStates.front() != Occupied)
698 mbDummyUpperLeft = true;
700 else
701 meGlue = GLUETYPE_NONE;
704 void Chart2Positioner::createPositionMap()
706 if (meGlue == GLUETYPE_NA && mpPositionMap.get())
707 mpPositionMap.reset();
709 if (mpPositionMap.get())
710 return;
712 glueState();
714 bool bNoGlue = (meGlue == GLUETYPE_NONE);
715 unique_ptr<FormulaTokenMapMap> pCols(new FormulaTokenMapMap);
716 FormulaTokenMap* pCol = NULL;
717 SCROW nNoGlueRow = 0;
718 for (vector<ScTokenRef>::const_iterator itr = mrRefTokens.begin(), itrEnd = mrRefTokens.end();
719 itr != itrEnd; ++itr)
721 const ScTokenRef& pToken = *itr;
723 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
724 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
725 svl::SharedString aTabName = svl::SharedString::getEmptyString();
726 if (bExternal)
727 aTabName = pToken->GetString();
729 ScComplexRefData aData;
730 if( !ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr) )
731 break;
732 const ScSingleRefData& s = aData.Ref1;
733 const ScSingleRefData& e = aData.Ref2;
734 SCCOL nCol1 = s.Col(), nCol2 = e.Col();
735 SCROW nRow1 = s.Row(), nRow2 = e.Row();
736 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
738 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
740 // columns on secondary sheets are appended; we treat them as if
741 // all columns are on the same sheet. TODO: We can't assume that
742 // the column range is 16-bit; remove that restriction.
743 sal_uInt32 nInsCol = (static_cast<sal_uInt32>(nTab) << 16) |
744 (bNoGlue ? 0 : static_cast<sal_uInt32>(nCol1));
746 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol)
748 FormulaTokenMapMap::const_iterator it = pCols->find(nInsCol);
749 if (it == pCols->end())
751 pCol = new FormulaTokenMap;
752 (*pCols)[ nInsCol ] = pCol;
754 else
755 pCol = it->second;
757 sal_uInt32 nInsRow = static_cast<sal_uInt32>(bNoGlue ? nNoGlueRow : nRow1);
758 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow, ++nInsRow)
760 ScSingleRefData aCellData;
761 aCellData.InitFlags();
762 aCellData.SetFlag3D(true);
763 aCellData.SetColRel(false);
764 aCellData.SetRowRel(false);
765 aCellData.SetTabRel(false);
766 aCellData.SetAbsCol(nCol);
767 aCellData.SetAbsRow(nRow);
768 aCellData.SetAbsTab(nTab);
770 if (pCol->find(nInsRow) == pCol->end())
772 if (bExternal)
773 (*pCol)[ nInsRow ] = new ScExternalSingleRefToken(nFileId, aTabName, aCellData);
774 else
775 (*pCol)[ nInsRow ] = new ScSingleRefToken(aCellData);
780 nNoGlueRow += nRow2 - nRow1 + 1;
783 bool bFillRowHeader = mbRowHeaders;
784 bool bFillColumnHeader = mbColHeaders;
786 SCSIZE nAllColCount = static_cast<SCSIZE>(pCols->size());
787 SCSIZE nAllRowCount = 0;
788 if (!pCols->empty())
790 pCol = pCols->begin()->second;
791 if (mbDummyUpperLeft)
792 if (pCol->find(0) == pCol->end())
793 (*pCol)[ 0 ] = NULL; // Dummy fuer Beschriftung
794 nAllRowCount = static_cast<SCSIZE>(pCol->size());
797 if( nAllColCount!=0 && nAllRowCount!=0 )
799 if (bNoGlue)
801 FormulaTokenMap* pFirstCol = pCols->begin()->second;
802 for (FormulaTokenMap::const_iterator it1 = pFirstCol->begin(); it1 != pFirstCol->end(); ++it1)
804 sal_uInt32 nKey = it1->first;
805 for (FormulaTokenMapMap::const_iterator it2 = pCols->begin(); it2 != pCols->end(); ++it2)
807 pCol = it2->second;
808 if (pCol->find(nKey) == pCol->end())
809 (*pCol)[ nKey ] = NULL;
814 mpPositionMap.reset(
815 new Chart2PositionMap(
816 static_cast<SCCOL>(nAllColCount), static_cast<SCROW>(nAllRowCount),
817 bFillRowHeader, bFillColumnHeader, *pCols, mpDoc));
819 // Destroy all column instances.
820 for (FormulaTokenMapMap::const_iterator it = pCols->begin(); it != pCols->end(); ++it)
822 pCol = it->second;
823 delete pCol;
828 * Function object to create a range string from a token list.
830 class Tokens2RangeString : public unary_function<ScTokenRef, void>
832 public:
833 Tokens2RangeString(ScDocument* pDoc, FormulaGrammar::Grammar eGram, sal_Unicode cRangeSep) :
834 mpRangeStr(new OUStringBuffer),
835 mpDoc(pDoc),
836 meGrammar(eGram),
837 mcRangeSep(cRangeSep),
838 mbFirst(true)
842 Tokens2RangeString(const Tokens2RangeString& r) :
843 mpRangeStr(r.mpRangeStr),
844 mpDoc(r.mpDoc),
845 meGrammar(r.meGrammar),
846 mcRangeSep(r.mcRangeSep),
847 mbFirst(r.mbFirst)
851 void operator() (const ScTokenRef& rToken)
853 ScCompiler aCompiler(mpDoc, ScAddress(0,0,0));
854 aCompiler.SetGrammar(meGrammar);
855 OUString aStr;
856 aCompiler.CreateStringFromToken(aStr, rToken.get());
857 if (mbFirst)
858 mbFirst = false;
859 else
860 mpRangeStr->append(mcRangeSep);
861 mpRangeStr->append(aStr);
864 void getString(OUString& rStr)
866 rStr = mpRangeStr->makeStringAndClear();
869 private:
870 shared_ptr<OUStringBuffer> mpRangeStr;
871 ScDocument* mpDoc;
872 FormulaGrammar::Grammar meGrammar;
873 sal_Unicode mcRangeSep;
874 bool mbFirst;
878 * Function object to convert a list of tokens into a string form suitable
879 * for ODF export. In ODF, a range is expressed as
881 * (start cell address):(end cell address)
883 * and each address doesn't include any '$' symbols.
885 class Tokens2RangeStringXML : public unary_function<ScTokenRef, void>
887 public:
888 Tokens2RangeStringXML(ScDocument* pDoc) :
889 mpRangeStr(new OUStringBuffer),
890 mpDoc(pDoc),
891 mcRangeSep(' '),
892 mcAddrSep(':'),
893 mbFirst(true)
897 Tokens2RangeStringXML(const Tokens2RangeStringXML& r) :
898 mpRangeStr(r.mpRangeStr),
899 mpDoc(r.mpDoc),
900 mcRangeSep(r.mcRangeSep),
901 mcAddrSep(r.mcAddrSep),
902 mbFirst(r.mbFirst)
906 void operator() (const ScTokenRef& rToken)
908 if (mbFirst)
909 mbFirst = false;
910 else
911 mpRangeStr->append(mcRangeSep);
913 ScTokenRef aStart, aEnd;
914 bool bValidToken = splitRangeToken(rToken, aStart, aEnd);
915 OSL_ENSURE(bValidToken, "invalid token");
916 if (!bValidToken)
917 return;
918 ScCompiler aCompiler(mpDoc, ScAddress(0,0,0));
919 aCompiler.SetGrammar(FormulaGrammar::GRAM_ENGLISH);
921 OUString aStr;
922 aCompiler.CreateStringFromToken(aStr, aStart.get());
923 mpRangeStr->append(aStr);
925 mpRangeStr->append(mcAddrSep);
927 OUString aStr;
928 aCompiler.CreateStringFromToken(aStr, aEnd.get());
929 mpRangeStr->append(aStr);
933 void getString(OUString& rStr)
935 rStr = mpRangeStr->makeStringAndClear();
938 private:
939 static bool splitRangeToken(const ScTokenRef& pToken, ScTokenRef& rStart, ScTokenRef& rEnd)
941 ScComplexRefData aData;
942 bool bIsRefToken = ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken);
943 OSL_ENSURE(bIsRefToken, "invalid token");
944 if (!bIsRefToken)
945 return false;
946 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
947 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
948 svl::SharedString aTabName = svl::SharedString::getEmptyString();
949 if (bExternal)
950 aTabName = pToken->GetString();
952 // In saving to XML, we don't prepend address with '$'.
953 setRelative(aData.Ref1);
954 setRelative(aData.Ref2);
956 // In XML, the range must explicitly specify sheet name.
957 aData.Ref1.SetFlag3D(true);
958 aData.Ref2.SetFlag3D(true);
960 if (bExternal)
961 rStart.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref1));
962 else
963 rStart.reset(new ScSingleRefToken(aData.Ref1));
965 if (bExternal)
966 rEnd.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref2));
967 else
968 rEnd.reset(new ScSingleRefToken(aData.Ref2));
969 return true;
972 static void setRelative(ScSingleRefData& rData)
974 rData.SetColRel(true);
975 rData.SetRowRel(true);
976 rData.SetTabRel(true);
979 private:
980 shared_ptr<OUStringBuffer> mpRangeStr;
981 ScDocument* mpDoc;
982 sal_Unicode mcRangeSep;
983 sal_Unicode mcAddrSep;
984 bool mbFirst;
987 void lcl_convertTokensToString(OUString& rStr, const vector<ScTokenRef>& rTokens, ScDocument* pDoc)
989 const sal_Unicode cRangeSep = ScCompiler::GetNativeSymbolChar(ocSep);
990 FormulaGrammar::Grammar eGrammar = pDoc->GetGrammar();
991 Tokens2RangeString func(pDoc, eGrammar, cRangeSep);
992 func = ::std::for_each(rTokens.begin(), rTokens.end(), func);
993 func.getString(rStr);
996 } // anonymous namespace
998 // DataProvider ==============================================================
1000 ScChart2DataProvider::ScChart2DataProvider( ScDocument* pDoc )
1001 : m_pDocument( pDoc)
1002 , m_aPropSet(lcl_GetDataProviderPropertyMap())
1003 , m_bIncludeHiddenCells( true)
1005 if ( m_pDocument )
1006 m_pDocument->AddUnoObject( *this);
1009 ScChart2DataProvider::~ScChart2DataProvider()
1011 SolarMutexGuard g;
1013 if ( m_pDocument )
1014 m_pDocument->RemoveUnoObject( *this);
1017 void ScChart2DataProvider::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
1019 const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
1020 if ( pSimpleHint && pSimpleHint->GetId() == SFX_HINT_DYING )
1022 m_pDocument = NULL;
1026 sal_Bool SAL_CALL ScChart2DataProvider::createDataSourcePossible( const uno::Sequence< beans::PropertyValue >& aArguments )
1027 throw (uno::RuntimeException, std::exception)
1029 SolarMutexGuard aGuard;
1030 if( ! m_pDocument )
1031 return false;
1033 OUString aRangeRepresentation;
1034 for(sal_Int32 i = 0; i < aArguments.getLength(); ++i)
1036 if ( aArguments[i].Name == "CellRangeRepresentation" )
1038 aArguments[i].Value >>= aRangeRepresentation;
1042 vector<ScTokenRef> aTokens;
1043 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1044 ScRefTokenHelper::compileRangeRepresentation(
1045 aTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1046 return !aTokens.empty();
1049 namespace
1052 Reference< chart2::data::XLabeledDataSequence > lcl_createLabeledDataSequenceFromTokens(
1053 unique_ptr< vector< ScTokenRef > > && pValueTokens, unique_ptr< vector< ScTokenRef > > && pLabelTokens,
1054 ScDocument* pDoc, const Reference< chart2::data::XDataProvider >& xDP, bool bIncludeHiddenCells )
1056 Reference< chart2::data::XLabeledDataSequence > xResult;
1057 bool bHasValues = pValueTokens.get() && !pValueTokens->empty();
1058 bool bHasLabel = pLabelTokens.get() && !pLabelTokens->empty();
1059 if( bHasValues || bHasLabel )
1063 Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1064 if ( xContext.is() )
1066 xResult.set( chart2::data::LabeledDataSequence::create(xContext), uno::UNO_QUERY_THROW );
1068 if ( bHasValues )
1070 Reference< chart2::data::XDataSequence > xSeq( new ScChart2DataSequence( pDoc, xDP, pValueTokens.release(), bIncludeHiddenCells ) );
1071 xResult->setValues( xSeq );
1073 if ( bHasLabel )
1075 Reference< chart2::data::XDataSequence > xLabelSeq( new ScChart2DataSequence( pDoc, xDP, pLabelTokens.release(), bIncludeHiddenCells ) );
1076 xResult->setLabel( xLabelSeq );
1079 catch( const uno::Exception& )
1083 return xResult;
1087 * Check the current list of reference tokens, and add the upper left
1088 * corner of the minimum range that encloses all ranges if certain
1089 * conditions are met.
1091 * @param rRefTokens list of reference tokens
1093 * @return true if the corner was added, false otherwise.
1095 bool lcl_addUpperLeftCornerIfMissing(vector<ScTokenRef>& rRefTokens,
1096 SCROW nCornerRowCount=1, SCCOL nCornerColumnCount=1)
1098 using ::std::max;
1099 using ::std::min;
1101 if (rRefTokens.empty())
1102 return false;
1104 SCCOL nMinCol = MAXCOLCOUNT;
1105 SCROW nMinRow = MAXROWCOUNT;
1106 SCCOL nMaxCol = 0;
1107 SCROW nMaxRow = 0;
1108 SCTAB nTab = 0;
1110 sal_uInt16 nFileId = 0;
1111 svl::SharedString aExtTabName;
1112 bool bExternal = false;
1114 vector<ScTokenRef>::const_iterator itr = rRefTokens.begin(), itrEnd = rRefTokens.end();
1116 // Get the first ref token.
1117 ScTokenRef pToken = *itr;
1118 switch (pToken->GetType())
1120 case svSingleRef:
1122 const ScSingleRefData& rData = *pToken->GetSingleRef();
1123 nMinCol = rData.Col();
1124 nMinRow = rData.Row();
1125 nMaxCol = rData.Col();
1126 nMaxRow = rData.Row();
1127 nTab = rData.Tab();
1129 break;
1130 case svDoubleRef:
1132 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1133 nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1134 nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1135 nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1136 nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1137 nTab = rData.Ref1.Tab();
1139 break;
1140 case svExternalSingleRef:
1142 const ScSingleRefData& rData = *pToken->GetSingleRef();
1143 nMinCol = rData.Col();
1144 nMinRow = rData.Row();
1145 nMaxCol = rData.Col();
1146 nMaxRow = rData.Row();
1147 nTab = rData.Tab();
1148 nFileId = pToken->GetIndex();
1149 aExtTabName = pToken->GetString();
1150 bExternal = true;
1152 break;
1153 case svExternalDoubleRef:
1155 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1156 nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1157 nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1158 nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1159 nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1160 nTab = rData.Ref1.Tab();
1161 nFileId = pToken->GetIndex();
1162 aExtTabName = pToken->GetString();
1163 bExternal = true;
1165 break;
1166 default:
1170 // Determine the minimum range enclosing all data ranges. Also make sure
1171 // that they are all on the same table.
1173 for (++itr; itr != itrEnd; ++itr)
1175 pToken = *itr;
1176 switch (pToken->GetType())
1178 case svSingleRef:
1180 const ScSingleRefData& rData = *pToken->GetSingleRef();
1182 nMinCol = min(nMinCol, rData.Col());
1183 nMinRow = min(nMinRow, rData.Row());
1184 nMaxCol = max(nMaxCol, rData.Col());
1185 nMaxRow = max(nMaxRow, rData.Row());
1186 if (nTab != rData.Tab() || bExternal)
1187 return false;
1189 break;
1190 case svDoubleRef:
1192 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1194 nMinCol = min(nMinCol, rData.Ref1.Col());
1195 nMinCol = min(nMinCol, rData.Ref2.Col());
1196 nMinRow = min(nMinRow, rData.Ref1.Row());
1197 nMinRow = min(nMinRow, rData.Ref2.Row());
1199 nMaxCol = max(nMaxCol, rData.Ref1.Col());
1200 nMaxCol = max(nMaxCol, rData.Ref2.Col());
1201 nMaxRow = max(nMaxRow, rData.Ref1.Row());
1202 nMaxRow = max(nMaxRow, rData.Ref2.Row());
1204 if (nTab != rData.Ref1.Tab() || bExternal)
1205 return false;
1207 break;
1208 case svExternalSingleRef:
1210 if (!bExternal)
1211 return false;
1213 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1214 return false;
1216 const ScSingleRefData& rData = *pToken->GetSingleRef();
1218 nMinCol = min(nMinCol, rData.Col());
1219 nMinRow = min(nMinRow, rData.Row());
1220 nMaxCol = max(nMaxCol, rData.Col());
1221 nMaxRow = max(nMaxRow, rData.Row());
1223 break;
1224 case svExternalDoubleRef:
1226 if (!bExternal)
1227 return false;
1229 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1230 return false;
1232 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1234 nMinCol = min(nMinCol, rData.Ref1.Col());
1235 nMinCol = min(nMinCol, rData.Ref2.Col());
1236 nMinRow = min(nMinRow, rData.Ref1.Row());
1237 nMinRow = min(nMinRow, rData.Ref2.Row());
1239 nMaxCol = max(nMaxCol, rData.Ref1.Col());
1240 nMaxCol = max(nMaxCol, rData.Ref2.Col());
1241 nMaxRow = max(nMaxRow, rData.Ref1.Row());
1242 nMaxRow = max(nMaxRow, rData.Ref2.Row());
1244 break;
1245 default:
1250 if (nMinRow >= nMaxRow || nMinCol >= nMaxCol ||
1251 nMinRow >= MAXROWCOUNT || nMinCol >= MAXCOLCOUNT ||
1252 nMaxRow >= MAXROWCOUNT || nMaxCol >= MAXCOLCOUNT)
1254 // Invalid range. Bail out.
1255 return false;
1258 // Check if the following conditions are met:
1260 // 1) The upper-left corner cell is not included.
1261 // 2) The three adjacent cells of that corner cell are included.
1263 bool bRight = false, bBottom = false, bDiagonal = false;
1264 for (itr = rRefTokens.begin(); itr != itrEnd; ++itr)
1266 pToken = *itr;
1267 switch (pToken->GetType())
1269 case svSingleRef:
1270 case svExternalSingleRef:
1272 const ScSingleRefData& rData = *pToken->GetSingleRef();
1273 if (rData.Col() == nMinCol && rData.Row() == nMinRow)
1274 // The corner cell is contained.
1275 return false;
1277 if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow)
1278 bRight = true;
1280 if (rData.Col() == nMinCol && rData.Row() == nMinRow+nCornerRowCount)
1281 bBottom = true;
1283 if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow+nCornerRowCount)
1284 bDiagonal = true;
1286 break;
1287 case svDoubleRef:
1288 case svExternalDoubleRef:
1290 const ScComplexRefData& rData = *pToken->GetDoubleRef();
1291 const ScSingleRefData& r1 = rData.Ref1;
1292 const ScSingleRefData& r2 = rData.Ref2;
1293 if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1294 r1.Row() <= nMinRow && nMinRow <= r2.Row())
1295 // The corner cell is contained.
1296 return false;
1298 if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1299 r1.Row() <= nMinRow && nMinRow <= r2.Row())
1300 bRight = true;
1302 if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1303 r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1304 bBottom = true;
1306 if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1307 r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1308 bDiagonal = true;
1310 break;
1311 default:
1316 if (!bRight || !bBottom || !bDiagonal)
1317 // Not all the adjacent cells are included. Bail out.
1318 return false;
1320 ScSingleRefData aData;
1321 aData.InitFlags();
1322 aData.SetFlag3D(true);
1323 aData.SetAbsCol(nMinCol);
1324 aData.SetAbsRow(nMinRow);
1325 aData.SetAbsTab(nTab);
1327 if( nCornerRowCount==1 && nCornerColumnCount==1 )
1329 if (bExternal)
1331 ScTokenRef pCorner(
1332 new ScExternalSingleRefToken(nFileId, aExtTabName, aData));
1333 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1335 else
1337 ScTokenRef pCorner(new ScSingleRefToken(aData));
1338 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1341 else
1343 ScSingleRefData aDataEnd(aData);
1344 aDataEnd.IncCol(nCornerColumnCount-1);
1345 aDataEnd.IncRow(nCornerRowCount-1);
1346 ScComplexRefData r;
1347 r.Ref1=aData;
1348 r.Ref2=aDataEnd;
1349 if (bExternal)
1351 ScTokenRef pCorner(
1352 new ScExternalDoubleRefToken(nFileId, aExtTabName, r));
1353 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1355 else
1357 ScTokenRef pCorner(new ScDoubleRefToken(r));
1358 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1362 return true;
1365 #define SHRINK_RANGE_THRESHOLD 10000
1367 class ShrinkRefTokenToDataRange : std::unary_function<ScTokenRef, void>
1369 ScDocument* mpDoc;
1370 public:
1371 ShrinkRefTokenToDataRange(ScDocument* pDoc) : mpDoc(pDoc) {}
1372 void operator() (ScTokenRef& rRef)
1374 if (ScRefTokenHelper::isExternalRef(rRef))
1375 return;
1377 // Don't assume an ScDoubleRefToken if it isn't. It can be at least an
1378 // ScSingleRefToken, then there isn't anything to shrink.
1379 if (rRef->GetType() != svDoubleRef)
1380 return;
1382 ScComplexRefData& rData = *rRef->GetDoubleRef();
1383 ScSingleRefData& s = rData.Ref1;
1384 ScSingleRefData& e = rData.Ref2;
1386 if(abs((e.Col()-s.Col())*(e.Row()-s.Row())) < SHRINK_RANGE_THRESHOLD)
1387 return;
1389 SCCOL nMinCol = MAXCOL, nMaxCol = 0;
1390 SCROW nMinRow = MAXROW, nMaxRow = 0;
1392 // Determine the smallest range that encompasses the data ranges of all sheets.
1393 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
1394 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
1396 SCCOL nCol1 = 0, nCol2 = MAXCOL;
1397 SCROW nRow1 = 0, nRow2 = MAXROW;
1398 mpDoc->ShrinkToDataArea(nTab, nCol1, nRow1, nCol2, nRow2);
1399 nMinCol = std::min(nMinCol, nCol1);
1400 nMinRow = std::min(nMinRow, nRow1);
1401 nMaxCol = std::max(nMaxCol, nCol2);
1402 nMaxRow = std::max(nMaxRow, nRow2);
1405 // Shrink range to the data range if applicable.
1406 if (s.Col() < nMinCol)
1407 s.SetAbsCol(nMinCol);
1408 if (s.Row() < nMinRow)
1409 s.SetAbsRow(nMinRow);
1410 if (e.Col() > nMaxCol)
1411 e.SetAbsCol(nMaxCol);
1412 if (e.Row() > nMaxRow)
1413 e.SetAbsRow(nMaxRow);
1417 void shrinkToDataRange(ScDocument* pDoc, vector<ScTokenRef>& rRefTokens)
1419 std::for_each(rRefTokens.begin(), rRefTokens.end(), ShrinkRefTokenToDataRange(pDoc));
1424 uno::Reference< chart2::data::XDataSource> SAL_CALL
1425 ScChart2DataProvider::createDataSource(
1426 const uno::Sequence< beans::PropertyValue >& aArguments )
1427 throw( lang::IllegalArgumentException, uno::RuntimeException, std::exception)
1429 SolarMutexGuard aGuard;
1430 if ( ! m_pDocument )
1431 throw uno::RuntimeException();
1433 uno::Reference< chart2::data::XDataSource> xResult;
1434 bool bLabel = true;
1435 bool bCategories = false;
1436 bool bOrientCol = true;
1437 OUString aRangeRepresentation;
1438 uno::Sequence< sal_Int32 > aSequenceMapping;
1439 bool bTimeBased = false;
1440 for(sal_Int32 i = 0; i < aArguments.getLength(); ++i)
1442 if ( aArguments[i].Name == "DataRowSource" )
1444 chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
1445 if( ! (aArguments[i].Value >>= eSource))
1447 sal_Int32 nSource(0);
1448 if( aArguments[i].Value >>= nSource )
1449 eSource = (static_cast< chart::ChartDataRowSource >( nSource ));
1451 bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
1453 else if ( aArguments[i].Name == "FirstCellAsLabel" )
1455 bLabel = ::cppu::any2bool(aArguments[i].Value);
1457 else if ( aArguments[i].Name == "HasCategories" )
1459 bCategories = ::cppu::any2bool(aArguments[i].Value);
1461 else if ( aArguments[i].Name == "CellRangeRepresentation" )
1463 aArguments[i].Value >>= aRangeRepresentation;
1465 else if ( aArguments[i].Name == "SequenceMapping" )
1467 aArguments[i].Value >>= aSequenceMapping;
1469 else if ( aArguments[i].Name == "TimeBased" )
1471 aArguments[i].Value >>= bTimeBased;
1475 vector<ScTokenRef> aRefTokens;
1476 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1477 ScRefTokenHelper::compileRangeRepresentation(
1478 aRefTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1479 if (aRefTokens.empty())
1480 // Invalid range representation. Bail out.
1481 throw lang::IllegalArgumentException();
1483 SCTAB nTimeBasedStart = MAXTAB;
1484 SCTAB nTimeBasedEnd = 0;
1485 if(bTimeBased)
1487 // limit to first sheet
1488 for(vector<ScTokenRef>::iterator itr = aRefTokens.begin(),
1489 itrEnd = aRefTokens.end(); itr != itrEnd; ++itr)
1491 if ((*itr)->GetType() != svDoubleRef)
1492 continue;
1494 ScComplexRefData& rData = *(*itr)->GetDoubleRef();
1495 ScSingleRefData& s = rData.Ref1;
1496 ScSingleRefData& e = rData.Ref2;
1498 nTimeBasedStart = std::min(nTimeBasedStart, s.Tab());
1499 nTimeBasedEnd = std::min(nTimeBasedEnd, e.Tab());
1501 if(s.Tab() != e.Tab())
1502 e.SetAbsTab(s.Tab());
1506 if(!bTimeBased)
1507 shrinkToDataRange(m_pDocument, aRefTokens);
1509 if (bLabel)
1510 lcl_addUpperLeftCornerIfMissing(aRefTokens); //#i90669#
1512 bool bColHeaders = (bOrientCol ? bLabel : bCategories );
1513 bool bRowHeaders = (bOrientCol ? bCategories : bLabel );
1515 Chart2Positioner aChPositioner(m_pDocument, aRefTokens);
1516 aChPositioner.setHeaders(bColHeaders, bRowHeaders);
1518 const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap();
1519 if (!pChartMap)
1520 // No chart position map instance. Bail out.
1521 return xResult;
1523 ScChart2DataSource* pDS = NULL;
1524 ::std::list< Reference< chart2::data::XLabeledDataSequence > > aSeqs;
1526 // Fill Categories
1527 if( bCategories )
1529 unique_ptr< vector<ScTokenRef> > pValueTokens;
1530 if (bOrientCol)
1531 pValueTokens.reset(pChartMap->getAllRowHeaderRanges());
1532 else
1533 pValueTokens.reset(pChartMap->getAllColHeaderRanges());
1535 unique_ptr< vector<ScTokenRef> > pLabelTokens(
1536 pChartMap->getLeftUpperCornerRanges());
1538 Reference< chart2::data::XLabeledDataSequence > xCategories = lcl_createLabeledDataSequenceFromTokens(
1539 std::move(pValueTokens), std::move(pLabelTokens), m_pDocument, this, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1540 if ( xCategories.is() )
1542 aSeqs.push_back( xCategories );
1546 // Fill Serieses (values and label)
1547 sal_Int32 nCount = bOrientCol ? pChartMap->getDataColCount() : pChartMap->getDataRowCount();
1548 for (sal_Int32 i = 0; i < nCount; ++i)
1550 unique_ptr< vector<ScTokenRef> > pValueTokens;
1551 unique_ptr< vector<ScTokenRef> > pLabelTokens;
1552 if (bOrientCol)
1554 pValueTokens.reset(pChartMap->getDataColRanges(static_cast<SCCOL>(i)));
1555 pLabelTokens.reset(pChartMap->getColHeaderRanges(static_cast<SCCOL>(i)));
1557 else
1559 pValueTokens.reset(pChartMap->getDataRowRanges(static_cast<SCROW>(i)));
1560 pLabelTokens.reset(pChartMap->getRowHeaderRanges(static_cast<SCROW>(i)));
1562 Reference< chart2::data::XLabeledDataSequence > xChartSeries = lcl_createLabeledDataSequenceFromTokens(
1563 std::move(pValueTokens), std::move(pLabelTokens), m_pDocument, this, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1564 if ( xChartSeries.is() && xChartSeries->getValues().is() && xChartSeries->getValues()->getData().getLength() )
1566 aSeqs.push_back( xChartSeries );
1570 pDS = new ScChart2DataSource(m_pDocument);
1571 ::std::list< Reference< chart2::data::XLabeledDataSequence > >::iterator aItr( aSeqs.begin() );
1572 ::std::list< Reference< chart2::data::XLabeledDataSequence > >::iterator aEndItr( aSeqs.end() );
1574 //reorder labeled sequences according to aSequenceMapping
1575 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aSeqVector;
1576 while(aItr != aEndItr)
1578 aSeqVector.push_back(*aItr);
1579 ++aItr;
1582 ::std::map< sal_Int32, Reference< chart2::data::XLabeledDataSequence > > aSequenceMap;
1583 for( sal_Int32 nNewIndex = 0; nNewIndex < aSequenceMapping.getLength(); nNewIndex++ )
1585 // note: assuming that the values in the sequence mapping are always non-negative
1586 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::size_type nOldIndex( static_cast< sal_uInt32 >( aSequenceMapping[nNewIndex] ) );
1587 if( nOldIndex < aSeqVector.size() )
1589 pDS->AddLabeledSequence( aSeqVector[nOldIndex] );
1590 aSeqVector[nOldIndex] = 0;
1594 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::iterator aVectorItr( aSeqVector.begin() );
1595 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::iterator aVectorEndItr( aSeqVector.end() );
1596 while(aVectorItr != aVectorEndItr)
1598 Reference< chart2::data::XLabeledDataSequence > xSeq( *aVectorItr );
1599 if ( xSeq.is() )
1601 pDS->AddLabeledSequence( xSeq );
1603 ++aVectorItr;
1606 xResult.set( pDS );
1607 return xResult;
1610 namespace
1614 * Function object to create a list of table numbers from a token list.
1616 class InsertTabNumber : public unary_function<ScTokenRef, void>
1618 public:
1619 InsertTabNumber() :
1620 mpTabNumList(new list<SCTAB>())
1624 InsertTabNumber(const InsertTabNumber& r) :
1625 mpTabNumList(r.mpTabNumList)
1629 void operator() (const ScTokenRef& pToken) const
1631 if (!ScRefTokenHelper::isRef(pToken))
1632 return;
1634 const ScSingleRefData& r = *pToken->GetSingleRef();
1635 mpTabNumList->push_back(r.Tab());
1638 void getList(list<SCTAB>& rList)
1640 mpTabNumList->swap(rList);
1642 private:
1643 shared_ptr< list<SCTAB> > mpTabNumList;
1646 class RangeAnalyzer
1648 public:
1649 RangeAnalyzer();
1650 void initRangeAnalyzer( const vector<ScTokenRef>& rTokens );
1651 void analyzeRange( sal_Int32& rnDataInRows, sal_Int32& rnDataInCols,
1652 bool& rbRowSourceAmbiguous ) const;
1653 bool inSameSingleRow( RangeAnalyzer& rOther );
1654 bool inSameSingleColumn( RangeAnalyzer& rOther );
1655 SCROW getRowCount() { return mnRowCount; }
1656 SCCOL getColumnCount() { return mnColumnCount; }
1658 private:
1659 bool mbEmpty;
1660 bool mbAmbiguous;
1661 SCROW mnRowCount;
1662 SCCOL mnColumnCount;
1664 SCCOL mnStartColumn;
1665 SCROW mnStartRow;
1668 RangeAnalyzer::RangeAnalyzer()
1669 : mbEmpty(true)
1670 , mbAmbiguous(false)
1671 , mnRowCount(0)
1672 , mnColumnCount(0)
1673 , mnStartColumn(-1)
1674 , mnStartRow(-1)
1678 void RangeAnalyzer::initRangeAnalyzer( const vector<ScTokenRef>& rTokens )
1680 mnRowCount=0;
1681 mnColumnCount=0;
1682 mnStartColumn = -1;
1683 mnStartRow = -1;
1684 mbAmbiguous=false;
1685 if( rTokens.empty() )
1687 mbEmpty=true;
1688 return;
1690 mbEmpty=false;
1692 vector<ScTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
1693 for (; itr != itrEnd ; ++itr)
1695 ScTokenRef aRefToken = *itr;
1696 StackVar eVar = aRefToken->GetType();
1697 if (eVar == svDoubleRef || eVar == svExternalDoubleRef)
1699 const ScComplexRefData& r = *aRefToken->GetDoubleRef();
1700 if (r.Ref1.Tab() == r.Ref2.Tab())
1702 mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(r.Ref2.Col() - r.Ref1.Col())+1));
1703 mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(r.Ref2.Row() - r.Ref1.Row())+1));
1704 if( mnStartColumn == -1 )
1706 mnStartColumn = r.Ref1.Col();
1707 mnStartRow = r.Ref1.Row();
1709 else
1711 if (mnStartColumn != r.Ref1.Col() && mnStartRow != r.Ref1.Row())
1712 mbAmbiguous=true;
1715 else
1716 mbAmbiguous=true;
1718 else if (eVar == svSingleRef || eVar == svExternalSingleRef)
1720 const ScSingleRefData& r = *aRefToken->GetSingleRef();
1721 mnColumnCount = std::max<SCCOL>( mnColumnCount, 1);
1722 mnRowCount = std::max<SCROW>( mnRowCount, 1);
1723 if( mnStartColumn == -1 )
1725 mnStartColumn = r.Col();
1726 mnStartRow = r.Row();
1728 else
1730 if (mnStartColumn != r.Col() && mnStartRow != r.Row())
1731 mbAmbiguous=true;
1734 else
1735 mbAmbiguous=true;
1739 void RangeAnalyzer::analyzeRange( sal_Int32& rnDataInRows,
1740 sal_Int32& rnDataInCols,
1741 bool& rbRowSourceAmbiguous ) const
1743 if(!mbEmpty && !mbAmbiguous)
1745 if( mnRowCount==1 && mnColumnCount>1 )
1746 ++rnDataInRows;
1747 else if( mnColumnCount==1 && mnRowCount>1 )
1748 ++rnDataInCols;
1749 else if( mnRowCount>1 && mnColumnCount>1 )
1750 rbRowSourceAmbiguous = true;
1752 else if( !mbEmpty )
1753 rbRowSourceAmbiguous = true;
1756 bool RangeAnalyzer::inSameSingleRow( RangeAnalyzer& rOther )
1758 if( mnStartRow==rOther.mnStartRow &&
1759 mnRowCount==1 && rOther.mnRowCount==1 )
1760 return true;
1761 return false;
1764 bool RangeAnalyzer::inSameSingleColumn( RangeAnalyzer& rOther )
1766 if( mnStartColumn==rOther.mnStartColumn &&
1767 mnColumnCount==1 && rOther.mnColumnCount==1 )
1768 return true;
1769 return false;
1772 } //end anonymous namespace
1774 uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments(
1775 const uno::Reference< chart2::data::XDataSource >& xDataSource )
1776 throw (uno::RuntimeException, std::exception)
1778 ::std::vector< beans::PropertyValue > aResult;
1779 bool bRowSourceDetected = false;
1780 bool bFirstCellAsLabel = false;
1781 bool bHasCategories = false;
1782 OUString sRangeRep;
1784 bool bHasCategoriesLabels = false;
1785 vector<ScTokenRef> aAllCategoriesValuesTokens;
1786 vector<ScTokenRef> aAllSeriesLabelTokens;
1788 chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS;
1790 vector<ScTokenRef> aAllTokens;
1792 // parse given data source and collect infos
1794 SolarMutexGuard aGuard;
1795 OSL_ENSURE( m_pDocument, "No Document -> no detectArguments" );
1796 if(!m_pDocument ||!xDataSource.is())
1797 return lcl_VectorToSequence( aResult );
1799 sal_Int32 nDataInRows = 0;
1800 sal_Int32 nDataInCols = 0;
1801 bool bRowSourceAmbiguous = false;
1803 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences());
1804 const sal_Int32 nCount( aSequences.getLength());
1805 RangeAnalyzer aPrevLabel,aPrevValues;
1806 for( sal_Int32 nIdx=0; nIdx<nCount; ++nIdx )
1808 Reference< chart2::data::XLabeledDataSequence > xLS(aSequences[nIdx]);
1809 if( xLS.is() )
1811 bool bThisIsCategories = false;
1812 if(!bHasCategories)
1814 Reference< beans::XPropertySet > xSeqProp( xLS->getValues(), uno::UNO_QUERY );
1815 OUString aRole;
1816 if( xSeqProp.is() && (xSeqProp->getPropertyValue("Role") >>= aRole) &&
1817 aRole == "categories" )
1818 bThisIsCategories = bHasCategories = true;
1821 RangeAnalyzer aLabel,aValues;
1822 // label
1823 Reference< chart2::data::XDataSequence > xLabel( xLS->getLabel());
1824 if( xLabel.is())
1826 bFirstCellAsLabel = true;
1827 vector<ScTokenRef> aTokens;
1828 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1829 ScRefTokenHelper::compileRangeRepresentation(
1830 aTokens, xLabel->getSourceRangeRepresentation(), m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1831 aLabel.initRangeAnalyzer(aTokens);
1832 vector<ScTokenRef>::const_iterator itr = aTokens.begin(), itrEnd = aTokens.end();
1833 for (; itr != itrEnd; ++itr)
1835 ScRefTokenHelper::join(aAllTokens, *itr, ScAddress());
1836 if(!bThisIsCategories)
1837 ScRefTokenHelper::join(aAllSeriesLabelTokens, *itr, ScAddress());
1839 if(bThisIsCategories)
1840 bHasCategoriesLabels=true;
1842 // values
1843 Reference< chart2::data::XDataSequence > xValues( xLS->getValues());
1844 if( xValues.is())
1846 vector<ScTokenRef> aTokens;
1847 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1848 ScRefTokenHelper::compileRangeRepresentation(
1849 aTokens, xValues->getSourceRangeRepresentation(), m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1850 aValues.initRangeAnalyzer(aTokens);
1851 vector<ScTokenRef>::const_iterator itr = aTokens.begin(), itrEnd = aTokens.end();
1852 for (; itr != itrEnd; ++itr)
1854 ScRefTokenHelper::join(aAllTokens, *itr, ScAddress());
1855 if(bThisIsCategories)
1856 ScRefTokenHelper::join(aAllCategoriesValuesTokens, *itr, ScAddress());
1859 //detect row source
1860 if(!bThisIsCategories || nCount==1) //categories might span multiple rows *and* columns, so they should be used for detection only if nothing else is available
1862 if (!bRowSourceAmbiguous)
1864 aValues.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1865 aLabel.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1866 if (nDataInRows > 1 && nDataInCols > 1)
1867 bRowSourceAmbiguous = true;
1868 else if( !bRowSourceAmbiguous && !nDataInRows && !nDataInCols )
1870 if( aValues.inSameSingleColumn( aLabel ) )
1871 nDataInCols++;
1872 else if( aValues.inSameSingleRow( aLabel ) )
1873 nDataInRows++;
1874 else
1876 //#i86188# also detect a single column split into rows correctly
1877 if( aValues.inSameSingleColumn( aPrevValues ) )
1878 nDataInRows++;
1879 else if( aValues.inSameSingleRow( aPrevValues ) )
1880 nDataInCols++;
1881 else if( aLabel.inSameSingleColumn( aPrevLabel ) )
1882 nDataInRows++;
1883 else if( aLabel.inSameSingleRow( aPrevLabel ) )
1884 nDataInCols++;
1889 aPrevValues=aValues;
1890 aPrevLabel=aLabel;
1894 if (!bRowSourceAmbiguous)
1896 bRowSourceDetected = true;
1897 eRowSource = ( nDataInRows > 0
1898 ? chart::ChartDataRowSource_ROWS
1899 : chart::ChartDataRowSource_COLUMNS );
1901 else
1903 // set DataRowSource to the better of the two ambiguities
1904 eRowSource = ( nDataInRows > nDataInCols
1905 ? chart::ChartDataRowSource_ROWS
1906 : chart::ChartDataRowSource_COLUMNS );
1911 // TableNumberList
1913 list<SCTAB> aTableNumList;
1914 InsertTabNumber func;
1915 func = ::std::for_each(aAllTokens.begin(), aAllTokens.end(), func);
1916 func.getList(aTableNumList);
1917 aResult.push_back(
1918 beans::PropertyValue( OUString("TableNumberList"), -1,
1919 uno::makeAny( lcl_createTableNumberList( aTableNumList ) ),
1920 beans::PropertyState_DIRECT_VALUE ));
1923 // DataRowSource (calculated before)
1924 if( bRowSourceDetected )
1926 aResult.push_back(
1927 beans::PropertyValue( OUString("DataRowSource"), -1,
1928 uno::makeAny( eRowSource ), beans::PropertyState_DIRECT_VALUE ));
1931 // HasCategories
1932 if( bRowSourceDetected )
1934 aResult.push_back(
1935 beans::PropertyValue( OUString("HasCategories"), -1,
1936 uno::makeAny( bHasCategories ), beans::PropertyState_DIRECT_VALUE ));
1939 // FirstCellAsLabel
1940 if( bRowSourceDetected )
1942 aResult.push_back(
1943 beans::PropertyValue( OUString("FirstCellAsLabel"), -1,
1944 uno::makeAny( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE ));
1947 // Add the left upper corner to the range if it is missing.
1948 if (bRowSourceDetected && bFirstCellAsLabel && bHasCategories && !bHasCategoriesLabels )
1950 RangeAnalyzer aTop,aLeft;
1951 if( eRowSource==chart::ChartDataRowSource_COLUMNS )
1953 aTop.initRangeAnalyzer(aAllSeriesLabelTokens);
1954 aLeft.initRangeAnalyzer(aAllCategoriesValuesTokens);
1956 else
1958 aTop.initRangeAnalyzer(aAllCategoriesValuesTokens);
1959 aLeft.initRangeAnalyzer(aAllSeriesLabelTokens);
1961 lcl_addUpperLeftCornerIfMissing(aAllTokens, aTop.getRowCount(), aLeft.getColumnCount());//e.g. #i91212#
1964 // Get range string.
1965 lcl_convertTokensToString(sRangeRep, aAllTokens, m_pDocument);
1967 // add cell range property
1968 aResult.push_back(
1969 beans::PropertyValue( OUString("CellRangeRepresentation"), -1,
1970 uno::makeAny( sRangeRep ), beans::PropertyState_DIRECT_VALUE ));
1972 //Sequence Mapping
1973 bool bSequencesReordered = true;//todo detect this above or detect this sequence mapping cheaper ...
1974 if( bSequencesReordered && bRowSourceDetected )
1976 bool bDifferentIndexes = false;
1978 std::vector< sal_Int32 > aSequenceMappingVector;
1980 uno::Reference< chart2::data::XDataSource > xCompareDataSource;
1983 xCompareDataSource.set( this->createDataSource( lcl_VectorToSequence( aResult ) ) );
1985 catch( const lang::IllegalArgumentException & )
1987 // creation of data source to compare didn't work, so we cannot
1988 // create a sequence mapping
1991 if( xDataSource.is() && xCompareDataSource.is() )
1993 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > aOldSequences(
1994 xCompareDataSource->getDataSequences() );
1995 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aNewSequences(
1996 xDataSource->getDataSequences());
1998 OUString aOldLabel;
1999 OUString aNewLabel;
2000 OUString aOldValues;
2001 OUString aNewValues;
2002 OUString aEmpty;
2004 for( sal_Int32 nNewIndex = 0; nNewIndex < aNewSequences.getLength(); nNewIndex++ )
2006 uno::Reference< chart2::data::XLabeledDataSequence> xNew( aNewSequences[nNewIndex] );
2007 for( sal_Int32 nOldIndex = 0; nOldIndex < aOldSequences.getLength(); nOldIndex++ )
2009 uno::Reference< chart2::data::XLabeledDataSequence> xOld( aOldSequences[nOldIndex] );
2011 if( xOld.is() && xNew.is() )
2013 aOldLabel = aNewLabel = aOldValues = aNewValues = aEmpty;
2014 if( xOld.is() && xOld->getLabel().is() )
2015 aOldLabel = xOld->getLabel()->getSourceRangeRepresentation();
2016 if( xNew.is() && xNew->getLabel().is() )
2017 aNewLabel = xNew->getLabel()->getSourceRangeRepresentation();
2018 if( xOld.is() && xOld->getValues().is() )
2019 aOldValues = xOld->getValues()->getSourceRangeRepresentation();
2020 if( xNew.is() && xNew->getValues().is() )
2021 aNewValues = xNew->getValues()->getSourceRangeRepresentation();
2023 if( aOldLabel.equals(aNewLabel)
2024 && ( aOldValues.equals(aNewValues) ) )
2026 if( nOldIndex!=nNewIndex )
2027 bDifferentIndexes = true;
2028 aSequenceMappingVector.push_back(nOldIndex);
2029 break;
2036 if( bDifferentIndexes && !aSequenceMappingVector.empty() )
2038 aResult.push_back(
2039 beans::PropertyValue( OUString("SequenceMapping"), -1,
2040 uno::makeAny( lcl_VectorToSequence(aSequenceMappingVector) )
2041 , beans::PropertyState_DIRECT_VALUE ));
2045 return lcl_VectorToSequence( aResult );
2048 sal_Bool SAL_CALL ScChart2DataProvider::createDataSequenceByRangeRepresentationPossible( const OUString& aRangeRepresentation )
2049 throw (uno::RuntimeException, std::exception)
2051 SolarMutexGuard aGuard;
2052 if( ! m_pDocument )
2053 return false;
2055 vector<ScTokenRef> aTokens;
2056 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2057 ScRefTokenHelper::compileRangeRepresentation(
2058 aTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2059 return !aTokens.empty();
2062 uno::Reference< chart2::data::XDataSequence > SAL_CALL
2063 ScChart2DataProvider::createDataSequenceByRangeRepresentation(
2064 const OUString& aRangeRepresentation )
2065 throw (lang::IllegalArgumentException,
2066 uno::RuntimeException, std::exception)
2068 SolarMutexGuard aGuard;
2069 uno::Reference< chart2::data::XDataSequence > xResult;
2071 OSL_ENSURE( m_pDocument, "No Document -> no createDataSequenceByRangeRepresentation" );
2072 if(!m_pDocument || aRangeRepresentation.isEmpty())
2073 return xResult;
2075 vector<ScTokenRef> aRefTokens;
2076 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2077 ScRefTokenHelper::compileRangeRepresentation(
2078 aRefTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2079 if (aRefTokens.empty())
2080 return xResult;
2082 shrinkToDataRange(m_pDocument, aRefTokens);
2084 // ScChart2DataSequence manages the life cycle of pRefTokens.
2085 vector<ScTokenRef>* pRefTokens = new vector<ScTokenRef>();
2086 pRefTokens->swap(aRefTokens);
2087 xResult.set(new ScChart2DataSequence(m_pDocument, this, pRefTokens, m_bIncludeHiddenCells));
2089 return xResult;
2092 uno::Reference<chart2::data::XDataSequence> SAL_CALL
2093 ScChart2DataProvider::createDataSequenceByValueArray(
2094 const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/ )
2095 throw (css::lang::IllegalArgumentException, css::uno::RuntimeException, std::exception)
2097 return uno::Reference<chart2::data::XDataSequence>();
2100 uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRangeSelection()
2101 throw (uno::RuntimeException, std::exception)
2103 uno::Reference< sheet::XRangeSelection > xResult;
2105 uno::Reference< frame::XModel > xModel( lcl_GetXModel( m_pDocument ));
2106 if( xModel.is())
2107 xResult.set( xModel->getCurrentController(), uno::UNO_QUERY );
2109 return xResult;
2112 sal_Bool SAL_CALL ScChart2DataProvider::createDataSequenceByFormulaTokensPossible(
2113 const Sequence<sheet::FormulaToken>& aTokens )
2114 throw (uno::RuntimeException, std::exception)
2116 if (aTokens.getLength() <= 0)
2117 return false;
2119 ScTokenArray aCode;
2120 if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
2121 return false;
2123 sal_uInt16 n = aCode.GetLen();
2124 if (!n)
2125 return false;
2127 const formula::FormulaToken* pFirst = aCode.First();
2128 const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2129 for (const formula::FormulaToken* p = aCode.First(); p; p = aCode.Next())
2131 switch (p->GetType())
2133 case svSep:
2135 switch (p->GetOpCode())
2137 case ocSep:
2138 // separators are allowed.
2139 break;
2140 case ocOpen:
2141 if (p != pFirst)
2142 // open paran is allowed only as the first token.
2143 return false;
2144 break;
2145 case ocClose:
2146 if (p != pLast)
2147 // close paren is allowed only as the last token.
2148 return false;
2149 break;
2150 default:
2151 return false;
2154 break;
2155 case svSingleRef:
2156 case svDoubleRef:
2157 case svExternalSingleRef:
2158 case svExternalDoubleRef:
2159 break;
2160 default:
2161 return false;
2165 return true;
2168 Reference<chart2::data::XDataSequence> SAL_CALL
2169 ScChart2DataProvider::createDataSequenceByFormulaTokens(
2170 const Sequence<sheet::FormulaToken>& aTokens )
2171 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
2173 Reference<chart2::data::XDataSequence> xResult;
2174 if (aTokens.getLength() <= 0)
2175 return xResult;
2177 ScTokenArray aCode;
2178 if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
2179 return xResult;
2181 sal_uInt16 n = aCode.GetLen();
2182 if (!n)
2183 return xResult;
2185 vector<ScTokenRef> aRefTokens;
2186 const formula::FormulaToken* pFirst = aCode.First();
2187 const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2188 for (const formula::FormulaToken* p = aCode.First(); p; p = aCode.Next())
2190 switch (p->GetType())
2192 case svSep:
2194 switch (p->GetOpCode())
2196 case ocSep:
2197 // separators are allowed.
2198 break;
2199 case ocOpen:
2200 if (p != pFirst)
2201 // open paran is allowed only as the first token.
2202 throw lang::IllegalArgumentException();
2203 break;
2204 case ocClose:
2205 if (p != pLast)
2206 // close paren is allowed only as the last token.
2207 throw lang::IllegalArgumentException();
2208 break;
2209 default:
2210 throw lang::IllegalArgumentException();
2213 break;
2214 case svString:
2215 case svSingleRef:
2216 case svDoubleRef:
2217 case svExternalSingleRef:
2218 case svExternalDoubleRef:
2220 ScTokenRef pNew(p->Clone());
2221 aRefTokens.push_back(pNew);
2223 break;
2224 default:
2225 throw lang::IllegalArgumentException();
2229 if (aRefTokens.empty())
2230 return xResult;
2232 shrinkToDataRange(m_pDocument, aRefTokens);
2234 // ScChart2DataSequence manages the life cycle of pRefTokens.
2235 vector<ScTokenRef>* pRefTokens = new vector<ScTokenRef>();
2236 pRefTokens->swap(aRefTokens);
2237 xResult.set(new ScChart2DataSequence(m_pDocument, this, pRefTokens, m_bIncludeHiddenCells));
2238 return xResult;
2241 // XRangeXMLConversion ---------------------------------------------------
2243 OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const OUString& sRangeRepresentation )
2244 throw ( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
2246 OUString aRet;
2247 if (!m_pDocument)
2248 return aRet;
2250 if (sRangeRepresentation.isEmpty())
2251 // Empty data range is allowed.
2252 return aRet;
2254 vector<ScTokenRef> aRefTokens;
2255 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2256 ScRefTokenHelper::compileRangeRepresentation(
2257 aRefTokens, sRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2258 if (aRefTokens.empty())
2259 throw lang::IllegalArgumentException();
2261 Tokens2RangeStringXML converter(m_pDocument);
2262 converter = ::std::for_each(aRefTokens.begin(), aRefTokens.end(), converter);
2263 converter.getString(aRet);
2265 return aRet;
2268 OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const OUString& sXMLRange )
2269 throw ( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
2271 const sal_Unicode cSep = ' ';
2272 const sal_Unicode cQuote = '\'';
2274 if (!m_pDocument)
2276 // #i74062# When loading flat XML, this is called before the referenced sheets are in the document,
2277 // so the conversion has to take place directly with the strings, without looking up the sheets.
2279 OUStringBuffer sRet;
2280 sal_Int32 nOffset = 0;
2281 while( nOffset >= 0 )
2283 OUString sToken;
2284 ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset, cSep, cQuote );
2285 if( nOffset >= 0 )
2287 // convert one address (remove dots)
2289 OUString aUIString(sToken);
2291 sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0, cQuote );
2292 if ( nIndex >= 0 && nIndex < aUIString.getLength() - 1 &&
2293 aUIString[nIndex + 1] == '.' )
2294 aUIString = aUIString.replaceAt( nIndex + 1, 1, "" );
2296 if ( aUIString[0] == '.' )
2297 aUIString = aUIString.copy( 1 );
2299 if( !sRet.isEmpty() )
2300 sRet.append( ';' );
2301 sRet.append( aUIString );
2305 return sRet.makeStringAndClear();
2308 OUString aRet;
2309 ScRangeStringConverter::GetStringFromXMLRangeString(aRet, sXMLRange, m_pDocument);
2310 return aRet;
2313 // DataProvider XPropertySet -------------------------------------------------
2315 uno::Reference< beans::XPropertySetInfo> SAL_CALL
2316 ScChart2DataProvider::getPropertySetInfo() throw( uno::RuntimeException, std::exception)
2318 SolarMutexGuard aGuard;
2319 static uno::Reference<beans::XPropertySetInfo> aRef =
2320 new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
2321 return aRef;
2324 void SAL_CALL ScChart2DataProvider::setPropertyValue(
2325 const OUString& rPropertyName, const uno::Any& rValue)
2326 throw( beans::UnknownPropertyException,
2327 beans::PropertyVetoException,
2328 lang::IllegalArgumentException,
2329 lang::WrappedTargetException, uno::RuntimeException, std::exception)
2331 if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2333 if ( !(rValue >>= m_bIncludeHiddenCells))
2334 throw lang::IllegalArgumentException();
2336 else
2337 throw beans::UnknownPropertyException();
2340 uno::Any SAL_CALL ScChart2DataProvider::getPropertyValue(
2341 const OUString& rPropertyName)
2342 throw( beans::UnknownPropertyException,
2343 lang::WrappedTargetException, uno::RuntimeException, std::exception)
2345 uno::Any aRet;
2346 if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2347 aRet <<= m_bIncludeHiddenCells;
2348 else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
2350 // This is a read-only property.
2351 aRet <<= m_pDocument->PastingDrawFromOtherDoc();
2353 else
2354 throw beans::UnknownPropertyException();
2355 return aRet;
2358 void SAL_CALL ScChart2DataProvider::addPropertyChangeListener(
2359 const OUString& /*rPropertyName*/,
2360 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
2361 throw( beans::UnknownPropertyException,
2362 lang::WrappedTargetException, uno::RuntimeException, std::exception)
2364 OSL_FAIL( "Not yet implemented" );
2367 void SAL_CALL ScChart2DataProvider::removePropertyChangeListener(
2368 const OUString& /*rPropertyName*/,
2369 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
2370 throw( beans::UnknownPropertyException,
2371 lang::WrappedTargetException, uno::RuntimeException, std::exception)
2373 OSL_FAIL( "Not yet implemented" );
2376 void SAL_CALL ScChart2DataProvider::addVetoableChangeListener(
2377 const OUString& /*rPropertyName*/,
2378 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
2379 throw( beans::UnknownPropertyException,
2380 lang::WrappedTargetException, uno::RuntimeException, std::exception)
2382 OSL_FAIL( "Not yet implemented" );
2385 void SAL_CALL ScChart2DataProvider::removeVetoableChangeListener(
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" );
2394 // DataSource ================================================================
2396 ScChart2DataSource::ScChart2DataSource( ScDocument* pDoc)
2397 : m_pDocument( pDoc)
2399 if ( m_pDocument )
2400 m_pDocument->AddUnoObject( *this);
2403 ScChart2DataSource::~ScChart2DataSource()
2405 SolarMutexGuard g;
2407 if ( m_pDocument )
2408 m_pDocument->RemoveUnoObject( *this);
2411 void ScChart2DataSource::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
2413 const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
2414 if ( pSimpleHint && pSimpleHint->GetId() == SFX_HINT_DYING )
2416 m_pDocument = NULL;
2420 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > SAL_CALL
2421 ScChart2DataSource::getDataSequences() throw ( uno::RuntimeException, std::exception)
2423 SolarMutexGuard aGuard;
2425 LabeledList::const_iterator aItr(m_aLabeledSequences.begin());
2426 LabeledList::const_iterator aEndItr(m_aLabeledSequences.end());
2428 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aRet(m_aLabeledSequences.size());
2430 sal_Int32 i = 0;
2431 while (aItr != aEndItr)
2433 aRet[i] = *aItr;
2434 ++i;
2435 ++aItr;
2438 return aRet;
2441 void ScChart2DataSource::AddLabeledSequence(const uno::Reference < chart2::data::XLabeledDataSequence >& xNew)
2443 m_aLabeledSequences.push_back(xNew);
2446 // DataSequence ==============================================================
2448 ScChart2DataSequence::Item::Item() :
2449 mfValue(0.0), mbIsValue(false)
2451 ::rtl::math::setNan(&mfValue);
2454 ScChart2DataSequence::HiddenRangeListener::HiddenRangeListener(ScChart2DataSequence& rParent) :
2455 mrParent(rParent)
2459 ScChart2DataSequence::HiddenRangeListener::~HiddenRangeListener()
2463 void ScChart2DataSequence::HiddenRangeListener::notify()
2465 mrParent.setDataChangedHint(true);
2468 ScChart2DataSequence::ScChart2DataSequence( ScDocument* pDoc,
2469 const uno::Reference < chart2::data::XDataProvider >& xDP,
2470 vector<ScTokenRef>* pTokens,
2471 bool bIncludeHiddenCells )
2472 : m_bIncludeHiddenCells( bIncludeHiddenCells)
2473 , m_nObjectId( 0 )
2474 , m_pDocument( pDoc)
2475 , m_pTokens(pTokens)
2476 , m_pRangeIndices(NULL)
2477 , m_pExtRefListener(NULL)
2478 , m_xDataProvider( xDP)
2479 , m_aPropSet(lcl_GetDataSequencePropertyMap())
2480 , m_pHiddenListener(NULL)
2481 , m_pValueListener( NULL )
2482 , m_bGotDataChangedHint(false)
2483 , m_bExtDataRebuildQueued(false)
2484 , mbTimeBased(false)
2485 , mnTimeBasedStart(0)
2486 , mnTimeBasedEnd(0)
2487 , mnCurrentTab(0)
2489 OSL_ENSURE(pTokens, "reference token list is null");
2491 if ( m_pDocument )
2493 m_pDocument->AddUnoObject( *this);
2494 m_nObjectId = m_pDocument->GetNewUnoId();
2496 // FIXME: real implementation of identifier and it's mapping to ranges.
2497 // Reuse ScChartListener?
2499 // BM: don't use names of named ranges but the UI range strings
2500 // String aStr;
2501 // rRangeList->Format( aStr, SCR_ABS_3D, m_pDocument );
2502 // m_aIdentifier = aStr;
2504 // m_aIdentifier = "ID_";
2505 // static sal_Int32 nID = 0;
2506 // m_aIdentifier += OUString::valueOf( ++nID);
2509 ScChart2DataSequence::~ScChart2DataSequence()
2511 SolarMutexGuard g;
2513 if ( m_pDocument )
2515 m_pDocument->RemoveUnoObject( *this);
2516 if (m_pHiddenListener.get())
2518 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
2519 if (pCLC)
2520 pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
2522 StopListeningToAllExternalRefs();
2525 delete m_pValueListener;
2528 void ScChart2DataSequence::RefChanged()
2530 if( m_pValueListener && !m_aValueListeners.empty() )
2532 m_pValueListener->EndListeningAll();
2534 if( m_pDocument )
2536 ScChartListenerCollection* pCLC = NULL;
2537 if (m_pHiddenListener.get())
2539 pCLC = m_pDocument->GetChartListenerCollection();
2540 if (pCLC)
2541 pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
2544 vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
2545 for (; itr != itrEnd; ++itr)
2547 ScRange aRange;
2548 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress()))
2549 continue;
2551 m_pDocument->StartListeningArea(aRange, false, m_pValueListener);
2552 if (pCLC)
2553 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
2559 void ScChart2DataSequence::BuildDataCache()
2561 m_bExtDataRebuildQueued = false;
2563 if (!m_aDataArray.empty())
2564 return;
2566 if (!m_pTokens.get())
2568 OSL_FAIL("m_pTokens == NULL! Something is wrong.");
2569 return;
2572 StopListeningToAllExternalRefs();
2574 ::std::list<sal_Int32> aHiddenValues;
2575 sal_Int32 nDataCount = 0;
2576 sal_Int32 nHiddenValueCount = 0;
2578 for (vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
2579 itr != itrEnd; ++itr)
2581 if (ScRefTokenHelper::isExternalRef(*itr))
2583 nDataCount += FillCacheFromExternalRef(*itr);
2585 else
2587 ScRange aRange;
2588 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress()))
2589 continue;
2591 SCCOL nLastCol = -1;
2592 SCROW nLastRow = -1;
2593 for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
2595 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
2597 for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
2599 bool bColHidden = m_pDocument->ColHidden(nCol, nTab, NULL, &nLastCol);
2600 bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, NULL, &nLastRow);
2602 if (bColHidden || bRowHidden)
2604 // hidden cell
2605 ++nHiddenValueCount;
2606 aHiddenValues.push_back(nDataCount-1);
2608 if( !m_bIncludeHiddenCells )
2609 continue;
2612 Item aItem;
2614 ScAddress aAdr(nCol, nRow, nTab);
2615 aItem.maString = m_pDocument->GetString(aAdr);
2617 switch (m_pDocument->GetCellType(aAdr))
2619 case CELLTYPE_VALUE:
2620 aItem.mfValue = m_pDocument->GetValue(aAdr);
2621 aItem.mbIsValue = true;
2622 break;
2623 case CELLTYPE_FORMULA:
2625 ScFormulaCell* pFCell = m_pDocument->GetFormulaCell(aAdr);
2626 if (!pFCell)
2627 break;
2628 sal_uInt16 nErr = pFCell->GetErrCode();
2629 if (nErr)
2630 break;
2632 if (pFCell->IsValue())
2634 aItem.mfValue = pFCell->GetValue();
2635 aItem.mbIsValue = true;
2638 break;
2639 case CELLTYPE_EDIT:
2640 case CELLTYPE_NONE:
2641 case CELLTYPE_STRING:
2642 default:
2643 ; // do nothing
2646 m_aDataArray.push_back(aItem);
2647 ++nDataCount;
2654 // convert the hidden cell list to sequence.
2655 m_aHiddenValues.realloc(nHiddenValueCount);
2656 sal_Int32* pArr = m_aHiddenValues.getArray();
2657 ::std::list<sal_Int32>::const_iterator itr = aHiddenValues.begin(), itrEnd = aHiddenValues.end();
2658 for (;itr != itrEnd; ++itr, ++pArr)
2659 *pArr = *itr;
2661 // Clear the data series cache when the array is re-built.
2662 m_aMixedDataCache.realloc(0);
2665 void ScChart2DataSequence::RebuildDataCache()
2667 if (!m_bExtDataRebuildQueued)
2669 m_aDataArray.clear();
2670 m_pDocument->BroadcastUno(ScHint(SC_HINT_DATACHANGED, ScAddress()));
2671 m_bExtDataRebuildQueued = true;
2672 m_bGotDataChangedHint = true;
2676 sal_Int32 ScChart2DataSequence::FillCacheFromExternalRef(const ScTokenRef& pToken)
2678 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
2679 ScRange aRange;
2680 if (!ScRefTokenHelper::getRangeFromToken(aRange, pToken, ScAddress(), true))
2681 return 0;
2683 sal_uInt16 nFileId = pToken->GetIndex();
2684 OUString aTabName = pToken->GetString().getString();
2685 ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, aTabName, aRange, NULL);
2686 if (!pArray)
2687 // no external data exists for this range.
2688 return 0;
2690 // Start listening for this external document.
2691 ExternalRefListener* pExtRefListener = GetExtRefListener();
2692 pRefMgr->addLinkListener(nFileId, pExtRefListener);
2693 pExtRefListener->addFileId(nFileId);
2695 ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, aTabName, false, NULL);
2696 sal_Int32 nDataCount = 0;
2697 for (FormulaToken* p = pArray->First(); p; p = pArray->Next())
2699 // Cached external range is always represented as a single
2700 // matrix token, although that might change in the future when
2701 // we introduce a new token type to store multi-table range
2702 // data.
2704 if (p->GetType() != svMatrix)
2706 OSL_FAIL("Cached array is not a matrix token.");
2707 continue;
2710 const ScMatrix* pMat = p->GetMatrix();
2711 SCSIZE nCSize, nRSize;
2712 pMat->GetDimensions(nCSize, nRSize);
2713 for (SCSIZE nC = 0; nC < nCSize; ++nC)
2715 for (SCSIZE nR = 0; nR < nRSize; ++nR)
2717 if (pMat->IsValue(nC, nR) || pMat->IsBoolean(nC, nR))
2719 Item aItem;
2721 aItem.mbIsValue = true;
2722 aItem.mfValue = pMat->GetDouble(nC, nR);
2724 SvNumberFormatter* pFormatter = m_pDocument->GetFormatTable();
2725 if (pFormatter)
2727 const double fVal = aItem.mfValue;
2728 Color* pColor = NULL;
2729 sal_uInt32 nFmt = 0;
2730 if (pTable)
2732 // Get the correct format index from the cache.
2733 SCCOL nCol = aRange.aStart.Col() + static_cast<SCCOL>(nC);
2734 SCROW nRow = aRange.aStart.Row() + static_cast<SCROW>(nR);
2735 pTable->getCell(nCol, nRow, &nFmt);
2737 pFormatter->GetOutputString(fVal, nFmt, aItem.maString, &pColor);
2740 m_aDataArray.push_back(aItem);
2741 ++nDataCount;
2743 else if (pMat->IsString(nC, nR))
2745 Item aItem;
2747 aItem.mbIsValue = false;
2748 aItem.maString = pMat->GetString(nC, nR).getString();
2750 m_aDataArray.push_back(Item());
2751 ++nDataCount;
2756 return nDataCount;
2759 void ScChart2DataSequence::UpdateTokensFromRanges(const ScRangeList& rRanges)
2761 if (!m_pRangeIndices.get())
2762 return;
2764 for ( size_t i = 0, nCount = rRanges.size(); i < nCount; ++i )
2766 ScTokenRef pToken;
2767 const ScRange* pRange = rRanges[i];
2768 OSL_ENSURE(pRange, "range object is NULL.");
2770 ScRefTokenHelper::getTokenFromRange(pToken, *pRange);
2771 sal_uInt32 nOrigPos = (*m_pRangeIndices)[i];
2772 (*m_pTokens)[nOrigPos] = pToken;
2775 RefChanged();
2777 // any change of the range address is broadcast to value (modify) listeners
2778 if ( !m_aValueListeners.empty() )
2779 m_bGotDataChangedHint = true;
2782 ScChart2DataSequence::ExternalRefListener* ScChart2DataSequence::GetExtRefListener()
2784 if (!m_pExtRefListener.get())
2785 m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
2787 return m_pExtRefListener.get();
2790 void ScChart2DataSequence::StopListeningToAllExternalRefs()
2792 if (!m_pExtRefListener.get())
2793 return;
2795 const std::unordered_set<sal_uInt16>& rFileIds = m_pExtRefListener->getAllFileIds();
2796 std::unordered_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
2797 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
2798 for (; itr != itrEnd; ++itr)
2799 pRefMgr->removeLinkListener(*itr, m_pExtRefListener.get());
2801 m_pExtRefListener.reset();
2804 void ScChart2DataSequence::CopyData(const ScChart2DataSequence& r)
2806 if (!m_pDocument)
2808 OSL_FAIL("document instance is NULL!?");
2809 return;
2812 list<Item> aDataArray(r.m_aDataArray);
2813 m_aDataArray.swap(aDataArray);
2815 m_aHiddenValues = r.m_aHiddenValues;
2816 m_aRole = r.m_aRole;
2818 if (r.m_pRangeIndices.get())
2819 m_pRangeIndices.reset(new vector<sal_uInt32>(*r.m_pRangeIndices));
2821 if (r.m_pExtRefListener.get())
2823 // Re-register all external files that the old instance was
2824 // listening to.
2826 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
2827 m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
2828 const std::unordered_set<sal_uInt16>& rFileIds = r.m_pExtRefListener->getAllFileIds();
2829 std::unordered_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
2830 for (; itr != itrEnd; ++itr)
2832 pRefMgr->addLinkListener(*itr, m_pExtRefListener.get());
2833 m_pExtRefListener->addFileId(*itr);
2838 void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
2840 const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
2841 if ( pSimpleHint )
2843 sal_uLong nId = pSimpleHint->GetId();
2844 if ( nId ==SFX_HINT_DYING )
2846 m_pDocument = NULL;
2848 else if ( nId == SFX_HINT_DATACHANGED )
2850 // delayed broadcast as in ScCellRangesBase
2852 if ( m_bGotDataChangedHint && m_pDocument )
2854 m_aDataArray.clear();
2855 lang::EventObject aEvent;
2856 aEvent.Source.set((cppu::OWeakObject*)this);
2858 if( m_pDocument )
2860 for ( sal_uInt16 n=0; n<m_aValueListeners.size(); n++ )
2861 m_pDocument->AddUnoListenerCall( m_aValueListeners[n], aEvent );
2864 m_bGotDataChangedHint = false;
2867 else if ( nId == SC_HINT_CALCALL )
2869 // broadcast from DoHardRecalc - set m_bGotDataChangedHint
2870 // (SFX_HINT_DATACHANGED follows separately)
2872 if ( !m_aValueListeners.empty() )
2873 m_bGotDataChangedHint = true;
2876 else if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
2878 // Create a range list from the token list, have the range list
2879 // updated, and bring the change back to the token list.
2881 ScRangeList aRanges;
2882 m_pRangeIndices.reset(new vector<sal_uInt32>());
2883 vector<ScTokenRef>::const_iterator itrBeg = m_pTokens->begin(), itrEnd = m_pTokens->end();
2884 for (vector<ScTokenRef>::const_iterator itr = itrBeg ;itr != itrEnd; ++itr)
2886 if (!ScRefTokenHelper::isExternalRef(*itr))
2888 ScRange aRange;
2889 ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress());
2890 aRanges.Append(aRange);
2891 sal_uInt32 nPos = distance(itrBeg, itr);
2892 m_pRangeIndices->push_back(nPos);
2896 OSL_ENSURE(m_pRangeIndices->size() == static_cast<size_t>(aRanges.size()),
2897 "range list and range index list have different sizes.");
2899 unique_ptr<ScRangeList> pUndoRanges;
2900 if ( m_pDocument->HasUnoRefUndo() )
2901 pUndoRanges.reset(new ScRangeList(aRanges));
2903 const ScUpdateRefHint& rRef = static_cast<const ScUpdateRefHint&>(rHint);
2904 bool bChanged = aRanges.UpdateReference(
2905 rRef.GetMode(), m_pDocument, rRef.GetRange(), rRef.GetDx(), rRef.GetDy(), rRef.GetDz());
2907 if (bChanged)
2909 OSL_ENSURE(m_pRangeIndices->size() == aRanges.size(),
2910 "range list and range index list have different sizes after the reference update.");
2912 // Bring the change back from the range list to the token list.
2913 UpdateTokensFromRanges(aRanges);
2915 if (pUndoRanges.get())
2916 m_pDocument->AddUnoRefChange(m_nObjectId, *pUndoRanges);
2919 else if ( dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
2921 const ScUnoRefUndoHint& rUndoHint = static_cast<const ScUnoRefUndoHint&>(rHint);
2925 if (rUndoHint.GetObjectId() != m_nObjectId)
2926 break;
2928 // The hint object provides the old ranges. Restore the old state
2929 // from these ranges.
2931 if (!m_pRangeIndices.get() || m_pRangeIndices->empty())
2933 OSL_FAIL(" faulty range indices");
2934 break;
2937 const ScRangeList& rRanges = rUndoHint.GetRanges();
2939 size_t nCount = rRanges.size();
2940 if (nCount != m_pRangeIndices->size())
2942 OSL_FAIL("range count and range index count differ.");
2943 break;
2946 UpdateTokensFromRanges(rRanges);
2948 while (false);
2952 IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, SfxHint*, pHint )
2954 if ( m_pDocument && pHint && dynamic_cast<const SfxSimpleHint*>(pHint) &&
2955 static_cast<const SfxSimpleHint*>(pHint)->GetId() & SC_HINT_DATACHANGED)
2957 // This may be called several times for a single change, if several formulas
2958 // in the range are notified. So only a flag is set that is checked when
2959 // SFX_HINT_DATACHANGED is received.
2961 setDataChangedHint(true);
2963 return 0;
2966 ScChart2DataSequence::ExternalRefListener::ExternalRefListener(
2967 ScChart2DataSequence& rParent, ScDocument* pDoc) :
2968 ScExternalRefManager::LinkListener(),
2969 mrParent(rParent),
2970 mpDoc(pDoc)
2974 ScChart2DataSequence::ExternalRefListener::~ExternalRefListener()
2976 if (!mpDoc || mpDoc->IsInDtorClear())
2977 // The document is being destroyed. Do nothing.
2978 return;
2980 // Make sure to remove all pointers to this object.
2981 mpDoc->GetExternalRefManager()->removeLinkListener(this);
2984 void ScChart2DataSequence::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
2986 switch (eType)
2988 case ScExternalRefManager::LINK_MODIFIED:
2990 if (maFileIds.count(nFileId))
2991 // We are listening to this external document.
2992 mrParent.RebuildDataCache();
2994 break;
2995 case ScExternalRefManager::LINK_BROKEN:
2996 removeFileId(nFileId);
2997 break;
3001 void ScChart2DataSequence::ExternalRefListener::addFileId(sal_uInt16 nFileId)
3003 maFileIds.insert(nFileId);
3006 void ScChart2DataSequence::ExternalRefListener::removeFileId(sal_uInt16 nFileId)
3008 maFileIds.erase(nFileId);
3011 uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
3012 throw (uno::RuntimeException, std::exception)
3014 SolarMutexGuard aGuard;
3015 if ( !m_pDocument)
3016 throw uno::RuntimeException();
3018 BuildDataCache();
3020 if (!m_aMixedDataCache.getLength())
3022 // Build a cache for the 1st time...
3024 sal_Int32 nCount = m_aDataArray.size();
3025 m_aMixedDataCache.realloc(nCount);
3026 uno::Any* pArr = m_aMixedDataCache.getArray();
3027 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3028 for (; itr != itrEnd; ++itr, ++pArr)
3030 if (itr->mbIsValue)
3031 *pArr <<= itr->mfValue;
3032 else
3033 *pArr <<= itr->maString;
3036 return m_aMixedDataCache;
3039 // XNumericalDataSequence --------------------------------------------------
3041 uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData()
3042 throw (uno::RuntimeException, std::exception)
3044 SolarMutexGuard aGuard;
3045 if ( !m_pDocument)
3046 throw uno::RuntimeException();
3048 BuildDataCache();
3050 double fNAN;
3051 ::rtl::math::setNan(&fNAN);
3053 sal_Int32 nCount = m_aDataArray.size();
3054 uno::Sequence<double> aSeq(nCount);
3055 double* pArr = aSeq.getArray();
3056 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3057 for (; itr != itrEnd; ++itr, ++pArr)
3058 *pArr = itr->mbIsValue ? itr->mfValue : fNAN;
3060 return aSeq;
3063 // XTextualDataSequence --------------------------------------------------
3065 uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::getTextualData()
3066 throw (uno::RuntimeException, std::exception)
3068 SolarMutexGuard aGuard;
3069 uno::Sequence<OUString> aSeq;
3070 if ( !m_pDocument )
3071 throw uno::RuntimeException();
3073 BuildDataCache();
3075 sal_Int32 nCount = m_aDataArray.size();
3076 if ( nCount > 0 )
3078 aSeq = uno::Sequence<OUString>(nCount);
3079 OUString* pArr = aSeq.getArray();
3080 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3081 for(; itr != itrEnd; ++itr, ++pArr)
3082 *pArr = itr->maString;
3084 else if ( m_pTokens.get() && m_pTokens->front() )
3086 if( m_pTokens->front()->GetType() == svString )
3088 aSeq = uno::Sequence<OUString>(1);
3089 aSeq[0] = m_pTokens->front()->GetString().getString();
3093 return aSeq;
3096 OUString SAL_CALL ScChart2DataSequence::getSourceRangeRepresentation()
3097 throw ( uno::RuntimeException, std::exception)
3099 SolarMutexGuard aGuard;
3100 OUString aStr;
3101 OSL_ENSURE( m_pDocument, "No Document -> no SourceRangeRepresentation" );
3102 if (m_pDocument && m_pTokens.get())
3103 lcl_convertTokensToString(aStr, *m_pTokens, m_pDocument);
3105 return aStr;
3108 namespace {
3111 * This function object is used to accumulatively count the numbers of
3112 * columns and rows in all reference tokens.
3114 class AccumulateRangeSize : public unary_function<ScTokenRef, void>
3116 public:
3117 AccumulateRangeSize() :
3118 mnCols(0), mnRows(0) {}
3120 AccumulateRangeSize(const AccumulateRangeSize& r) :
3121 mnCols(r.mnCols), mnRows(r.mnRows) {}
3123 void operator() (const ScTokenRef& pToken)
3125 ScRange r;
3126 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3127 ScRefTokenHelper::getRangeFromToken(r, pToken, ScAddress(), bExternal);
3128 r.Justify();
3129 mnCols += r.aEnd.Col() - r.aStart.Col() + 1;
3130 mnRows += r.aEnd.Row() - r.aStart.Row() + 1;
3133 SCCOL getCols() const { return mnCols; }
3134 SCROW getRows() const { return mnRows; }
3135 private:
3136 SCCOL mnCols;
3137 SCROW mnRows;
3141 * This function object is used to generate label strings from a list of
3142 * reference tokens.
3144 class GenerateLabelStrings : public unary_function<ScTokenRef, void>
3146 public:
3147 GenerateLabelStrings(sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) :
3148 mpLabels(new Sequence<OUString>(nSize)),
3149 meOrigin(eOrigin),
3150 mnCount(0),
3151 mbColumn(bColumn) {}
3153 GenerateLabelStrings(const GenerateLabelStrings& r) :
3154 mpLabels(r.mpLabels),
3155 meOrigin(r.meOrigin),
3156 mnCount(r.mnCount),
3157 mbColumn(r.mbColumn) {}
3159 void operator() (const ScTokenRef& pToken)
3161 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3162 ScRange aRange;
3163 ScRefTokenHelper::getRangeFromToken(aRange, pToken, ScAddress(), bExternal);
3164 OUString* pArr = mpLabels->getArray();
3165 if (mbColumn)
3167 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
3169 if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3171 OUString aString = ScGlobal::GetRscString(STR_COLUMN);
3172 aString += " ";
3173 ScAddress aPos( nCol, 0, 0 );
3174 OUString aColStr(aPos.Format(SCA_VALID_COL, NULL));
3175 aString += aColStr;
3176 pArr[mnCount] = aString;
3178 else //only indices for categories
3179 pArr[mnCount] = OUString::number( mnCount+1 );
3180 ++mnCount;
3183 else
3185 for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
3187 if (meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3189 OUString aString = ScGlobal::GetRscString(STR_ROW) +
3190 " " + OUString::number( nRow+1 );
3191 pArr[mnCount] = aString;
3193 else //only indices for categories
3194 pArr[mnCount] = OUString::number( mnCount+1 );
3195 ++mnCount;
3200 Sequence<OUString> getLabels() const { return *mpLabels; }
3202 private:
3203 shared_ptr< Sequence<OUString> > mpLabels;
3204 chart2::data::LabelOrigin meOrigin;
3205 sal_Int32 mnCount;
3206 bool mbColumn;
3211 uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
3212 throw (uno::RuntimeException, std::exception)
3214 SolarMutexGuard aGuard;
3215 if ( !m_pDocument)
3216 throw uno::RuntimeException();
3218 if (!m_pTokens.get())
3219 return Sequence<OUString>();
3221 // Determine the total size of all ranges.
3222 AccumulateRangeSize func;
3223 func = ::std::for_each(m_pTokens->begin(), m_pTokens->end(), func);
3224 SCCOL nCols = func.getCols();
3225 SCROW nRows = func.getRows();
3227 // Detemine whether this is column-major or row-major.
3228 bool bColumn = true;
3229 if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
3230 (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
3232 if (nRows > nCols)
3234 if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
3235 bColumn = true;
3236 else
3237 bColumn = false;
3239 else if (nCols > nRows)
3241 if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
3242 bColumn = false;
3243 else
3244 bColumn = true;
3246 else
3247 return Sequence<OUString>();
3250 // Generate label strings based on the info so far.
3251 sal_Int32 nCount = bColumn ? nCols : nRows;
3252 GenerateLabelStrings genLabels(nCount, eOrigin, bColumn);
3253 genLabels = ::std::for_each(m_pTokens->begin(), m_pTokens->end(), genLabels);
3254 Sequence<OUString> aSeq = genLabels.getLabels();
3256 return aSeq;
3259 namespace {
3261 sal_uLong getDisplayNumberFormat(ScDocument* pDoc, const ScAddress& rPos)
3263 sal_uLong nFormat = pDoc->GetNumberFormat(rPos); // original format from cell.
3264 return nFormat;
3269 ::sal_Int32 SAL_CALL ScChart2DataSequence::getNumberFormatKeyByIndex( ::sal_Int32 nIndex )
3270 throw (lang::IndexOutOfBoundsException, uno::RuntimeException, std::exception)
3272 // index -1 means a heuristic value for the entire sequence
3273 bool bGetSeriesFormat = (nIndex == -1);
3275 SolarMutexGuard aGuard;
3276 if ( !m_pDocument || !m_pTokens.get())
3277 return 0;
3279 // TODO: Handle external references too.
3281 sal_Int32 nCount = 0;
3283 ScRangeList aRanges;
3284 ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens, ScAddress());
3285 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
3287 ScRange* p = aRanges[i];
3288 for (SCTAB nTab = p->aStart.Tab(); nTab <= p->aEnd.Tab(); ++nTab)
3290 for (SCCOL nCol = p->aStart.Col(); nCol <= p->aEnd.Col(); ++nCol)
3292 if (!m_bIncludeHiddenCells)
3294 // Skip hidden columns.
3295 SCCOL nLastCol = -1;
3296 bool bColHidden = m_pDocument->ColHidden(nCol, nTab, NULL, &nLastCol);
3297 if (bColHidden)
3299 nCol = nLastCol;
3300 continue;
3304 for (SCROW nRow = p->aStart.Row(); nRow <= p->aEnd.Row(); ++nRow)
3306 if (!m_bIncludeHiddenCells)
3308 // Skip hidden rows.
3309 SCROW nLastRow = -1;
3310 bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, NULL, &nLastRow);
3311 if (bRowHidden)
3313 nRow = nLastRow;
3314 continue;
3318 ScAddress aPos(nCol, nRow, nTab);
3320 if( bGetSeriesFormat )
3322 // TODO: use nicer heuristic
3323 // return format of first non-empty cell
3324 ScRefCellValue aCell;
3325 aCell.assign(*m_pDocument, aPos);
3326 if (!aCell.isEmpty())
3327 return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, aPos));
3329 else if( nCount == nIndex )
3331 return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, aPos));
3333 ++nCount;
3338 return 0;
3341 // XCloneable ================================================================
3343 uno::Reference< util::XCloneable > SAL_CALL ScChart2DataSequence::createClone()
3344 throw (uno::RuntimeException, std::exception)
3346 SolarMutexGuard aGuard;
3348 unique_ptr< vector<ScTokenRef> > pTokensNew;
3349 if (m_pTokens.get())
3351 // Clone tokens.
3352 pTokensNew.reset(new vector<ScTokenRef>);
3353 pTokensNew->reserve(m_pTokens->size());
3354 vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
3355 for (; itr != itrEnd; ++itr)
3357 ScTokenRef p((*itr)->Clone());
3358 pTokensNew->push_back(p);
3362 unique_ptr<ScChart2DataSequence> p(new ScChart2DataSequence(m_pDocument, m_xDataProvider, pTokensNew.release(), m_bIncludeHiddenCells));
3363 p->CopyData(*this);
3364 Reference< util::XCloneable > xClone(p.release());
3366 return xClone;
3369 // XModifyBroadcaster ========================================================
3371 void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3372 throw (uno::RuntimeException, std::exception)
3374 // like ScCellRangesBase::addModifyListener
3375 SolarMutexGuard aGuard;
3376 if (!m_pTokens.get() || m_pTokens->empty())
3377 return;
3379 ScRangeList aRanges;
3380 ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens, ScAddress());
3381 uno::Reference<util::XModifyListener> *pObj =
3382 new uno::Reference<util::XModifyListener>( aListener );
3383 m_aValueListeners.push_back( pObj );
3385 if ( m_aValueListeners.size() == 1 )
3387 if (!m_pValueListener)
3388 m_pValueListener = new ScLinkListener( LINK( this, ScChart2DataSequence, ValueListenerHdl ) );
3390 if (!m_pHiddenListener.get())
3391 m_pHiddenListener.reset(new HiddenRangeListener(*this));
3393 if( m_pDocument )
3395 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
3396 vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
3397 for (; itr != itrEnd; ++itr)
3399 ScRange aRange;
3400 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress()))
3401 continue;
3403 m_pDocument->StartListeningArea( aRange, false, m_pValueListener );
3404 if (pCLC)
3405 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
3409 acquire(); // don't lose this object (one ref for all listeners)
3413 void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3414 throw (uno::RuntimeException, std::exception)
3416 // like ScCellRangesBase::removeModifyListener
3418 SolarMutexGuard aGuard;
3419 if (!m_pTokens.get() || m_pTokens->empty())
3420 return;
3422 acquire(); // in case the listeners have the last ref - released below
3424 sal_uInt16 nCount = m_aValueListeners.size();
3425 for ( sal_uInt16 n=nCount; n--; )
3427 uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
3428 if ( rObj == aListener )
3430 m_aValueListeners.erase( m_aValueListeners.begin() + n );
3432 if ( m_aValueListeners.empty() )
3434 if (m_pValueListener)
3435 m_pValueListener->EndListeningAll();
3437 if (m_pHiddenListener.get() && m_pDocument)
3439 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
3440 if (pCLC)
3441 pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
3444 release(); // release the ref for the listeners
3447 break;
3451 release(); // might delete this object
3454 // DataSequence XPropertySet -------------------------------------------------
3456 uno::Reference< beans::XPropertySetInfo> SAL_CALL
3457 ScChart2DataSequence::getPropertySetInfo() throw( uno::RuntimeException, std::exception)
3459 SolarMutexGuard aGuard;
3460 static uno::Reference<beans::XPropertySetInfo> aRef =
3461 new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
3462 return aRef;
3465 void SAL_CALL ScChart2DataSequence::setPropertyValue(
3466 const OUString& rPropertyName, const uno::Any& rValue)
3467 throw( beans::UnknownPropertyException,
3468 beans::PropertyVetoException,
3469 lang::IllegalArgumentException,
3470 lang::WrappedTargetException, uno::RuntimeException, std::exception)
3472 if ( rPropertyName == SC_UNONAME_ROLE )
3474 if ( !(rValue >>= m_aRole))
3475 throw lang::IllegalArgumentException();
3477 else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3479 bool bOldValue = m_bIncludeHiddenCells;
3480 if ( !(rValue >>= m_bIncludeHiddenCells))
3481 throw lang::IllegalArgumentException();
3482 if( bOldValue != m_bIncludeHiddenCells )
3483 m_aDataArray.clear();//data array is dirty now
3485 else if( rPropertyName == "TimeBased" )
3487 bool bTimeBased = mbTimeBased;
3488 rValue>>= bTimeBased;
3489 mbTimeBased = bTimeBased;
3491 else
3492 throw beans::UnknownPropertyException();
3493 // TODO: support optional properties
3496 uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue(const OUString& rPropertyName)
3497 throw(beans::UnknownPropertyException,
3498 lang::WrappedTargetException,
3499 uno::RuntimeException,
3500 std::exception)
3502 uno::Any aRet;
3503 if ( rPropertyName == SC_UNONAME_ROLE )
3504 aRet <<= m_aRole;
3505 else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3506 aRet <<= m_bIncludeHiddenCells;
3507 else if ( rPropertyName == SC_UNONAME_HIDDENVALUES )
3509 // This property is read-only thus cannot be set externally via
3510 // setPropertyValue(...).
3511 BuildDataCache();
3512 aRet <<= m_aHiddenValues;
3514 else if (rPropertyName == SC_UNONAME_TIME_BASED)
3516 aRet <<= mbTimeBased;
3518 else if (rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
3520 // Read-only property. It returns whether or not the label value is a
3521 // direct user input, rather than an indirect reference.
3522 bool bHasStringLabel = false;
3523 if (m_pTokens->size() == 1)
3525 const formula::FormulaToken& rToken = *(*m_pTokens)[0];
3526 bHasStringLabel = rToken.GetType() == formula::svString;
3528 aRet <<= bHasStringLabel;
3530 else
3531 throw beans::UnknownPropertyException();
3532 // TODO: support optional properties
3533 return aRet;
3536 void SAL_CALL ScChart2DataSequence::addPropertyChangeListener(
3537 const OUString& /*rPropertyName*/,
3538 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
3539 throw( beans::UnknownPropertyException,
3540 lang::WrappedTargetException, uno::RuntimeException, std::exception)
3542 // FIXME: real implementation
3543 OSL_FAIL( "Not yet implemented" );
3546 void SAL_CALL ScChart2DataSequence::removePropertyChangeListener(
3547 const OUString& /*rPropertyName*/,
3548 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
3549 throw( beans::UnknownPropertyException,
3550 lang::WrappedTargetException, uno::RuntimeException, std::exception)
3552 // FIXME: real implementation
3553 OSL_FAIL( "Not yet implemented" );
3556 void SAL_CALL ScChart2DataSequence::addVetoableChangeListener(
3557 const OUString& /*rPropertyName*/,
3558 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3559 throw( beans::UnknownPropertyException,
3560 lang::WrappedTargetException, uno::RuntimeException, std::exception)
3562 // FIXME: real implementation
3563 OSL_FAIL( "Not yet implemented" );
3566 void SAL_CALL ScChart2DataSequence::removeVetoableChangeListener(
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" );
3576 void ScChart2DataSequence::setDataChangedHint(bool b)
3578 m_bGotDataChangedHint = b;
3581 sal_Bool ScChart2DataSequence::switchToNext(sal_Bool bWrap)
3582 throw (uno::RuntimeException, std::exception)
3584 if(!m_pTokens || !mbTimeBased)
3585 return sal_True;
3587 if(mnCurrentTab >= mnTimeBasedEnd)
3589 if(bWrap)
3590 setToPointInTime(0);
3591 return false;
3594 for(vector<ScTokenRef>::iterator itr = m_pTokens->begin(),
3595 itrEnd = m_pTokens->end(); itr != itrEnd; ++itr)
3597 if ((*itr)->GetType() != svDoubleRef)
3598 continue;
3600 ScComplexRefData& rData = *(*itr)->GetDoubleRef();
3601 ScSingleRefData& s = rData.Ref1;
3602 ScSingleRefData& e = rData.Ref2;
3604 s.IncTab(1);
3605 e.IncTab(1);
3608 ++mnCurrentTab;
3610 RebuildDataCache();
3612 return sal_True;
3615 void ScChart2DataSequence::setRange(sal_Int32 nStart, sal_Int32 nEnd)
3616 throw (uno::RuntimeException, std::exception)
3618 mnTimeBasedStart = nStart;
3619 mnTimeBasedEnd = nEnd;
3620 mnCurrentTab = mnTimeBasedStart;
3623 sal_Bool ScChart2DataSequence::setToPointInTime(sal_Int32 nPoint)
3624 throw (uno::RuntimeException, std::exception)
3626 if(!m_pTokens)
3627 return sal_True;
3629 if(nPoint > mnTimeBasedEnd - mnTimeBasedStart)
3630 return false;
3632 SCTAB nTab = mnTimeBasedStart + nPoint;
3633 for(vector<ScTokenRef>::iterator itr = m_pTokens->begin(),
3634 itrEnd = m_pTokens->end(); itr != itrEnd; ++itr)
3636 if ((*itr)->GetType() != svDoubleRef)
3637 continue;
3639 ScComplexRefData& rData = *(*itr)->GetDoubleRef();
3640 ScSingleRefData& s = rData.Ref1;
3641 ScSingleRefData& e = rData.Ref2;
3643 s.SetAbsTab(nTab);
3644 e.SetAbsTab(nTab);
3647 mnCurrentTab = nTab;
3649 RebuildDataCache();
3651 return sal_True;
3654 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */