Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / ui / unoobj / chart2uno.cxx
blob8754057dc8936e7869a30411a21d61c78e8bbb84
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "chart2uno.hxx"
22 #include "miscuno.hxx"
23 #include "document.hxx"
24 #include "formulacell.hxx"
25 #include "chartpos.hxx"
26 #include "unonames.hxx"
27 #include "globstr.hrc"
28 #include "convuno.hxx"
29 #include "rangeutl.hxx"
30 #include "hints.hxx"
31 #include "unoreflist.hxx"
32 #include "compiler.hxx"
33 #include "reftokenhelper.hxx"
34 #include "chartlis.hxx"
35 #include "stlalgorithm.hxx"
36 #include "tokenuno.hxx"
37 #include "docsh.hxx"
38 #include "cellvalue.hxx"
39 #include "tokenarray.hxx"
40 #include "scmatrix.hxx"
42 #include "formula/opcode.hxx"
43 #include "svl/sharedstring.hxx"
45 #include <sfx2/objsh.hxx>
46 #include <vcl/svapp.hxx>
48 #include <com/sun/star/beans/UnknownPropertyException.hpp>
49 #include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
50 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
51 #include <com/sun/star/table/XCellRange.hpp>
52 #include <com/sun/star/table/CellAddress.hpp>
53 #include <com/sun/star/text/XText.hpp>
54 #include <comphelper/extract.hxx>
55 #include <comphelper/processfactory.hxx>
57 #include <rtl/math.hxx>
59 SC_SIMPLE_SERVICE_INFO( ScChart2DataProvider, "ScChart2DataProvider",
60 "com.sun.star.chart2.data.DataProvider")
61 SC_SIMPLE_SERVICE_INFO( ScChart2DataSource, "ScChart2DataSource",
62 "com.sun.star.chart2.data.DataSource")
63 SC_SIMPLE_SERVICE_INFO( ScChart2DataSequence, "ScChart2DataSequence",
64 "com.sun.star.chart2.data.DataSequence")
66 using namespace ::com::sun::star;
67 using namespace ::formula;
68 using ::com::sun::star::uno::Sequence;
69 using ::com::sun::star::uno::Reference;
70 using ::std::auto_ptr;
71 using ::std::vector;
72 using ::std::list;
73 using ::std::distance;
74 using ::std::unary_function;
75 using ::boost::shared_ptr;
77 namespace
79 const SfxItemPropertyMapEntry* lcl_GetDataProviderPropertyMap()
81 static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
83 { MAP_CHAR_LEN(SC_UNONAME_INCLUDEHIDDENCELLS), 0, &getBooleanCppuType(), 0, 0 },
84 { MAP_CHAR_LEN(SC_UNONAME_USE_INTERNAL_DATA_PROVIDER), 0, &getBooleanCppuType(), 0, 0 },
85 {0,0,0,0,0,0}
87 return aDataProviderPropertyMap_Impl;
90 const SfxItemPropertyMapEntry* lcl_GetDataSequencePropertyMap()
92 static const SfxItemPropertyMapEntry aDataSequencePropertyMap_Impl[] =
94 {MAP_CHAR_LEN(SC_UNONAME_HIDDENVALUES), 0, &getCppuType((uno::Sequence<sal_Int32>*)0 ), 0, 0 },
95 {MAP_CHAR_LEN(SC_UNONAME_ROLE), 0, &getCppuType((::com::sun::star::chart2::data::DataSequenceRole*)0), 0, 0 },
96 {MAP_CHAR_LEN(SC_UNONAME_INCLUDEHIDDENCELLS), 0, &getBooleanCppuType(), 0, 0 },
97 {0,0,0,0,0,0}
99 return aDataSequencePropertyMap_Impl;
102 template< typename T >
103 ::com::sun::star::uno::Sequence< T > lcl_VectorToSequence(
104 const ::std::vector< T > & rCont )
106 ::com::sun::star::uno::Sequence< T > aResult( rCont.size());
107 ::std::copy( rCont.begin(), rCont.end(), aResult.getArray());
108 return aResult;
111 struct lcl_appendTableNumber : public ::std::unary_function< SCTAB, void >
113 lcl_appendTableNumber( OUStringBuffer & rBuffer ) :
114 m_rBuffer( rBuffer )
116 void operator() ( SCTAB nTab )
118 // there is no append with SCTAB or sal_Int16
119 m_rBuffer.append( static_cast< sal_Int32 >( nTab ));
120 m_rBuffer.append( ' ' );
122 private:
123 OUStringBuffer & m_rBuffer;
126 OUString lcl_createTableNumberList( const ::std::list< SCTAB > & rTableList )
128 OUStringBuffer aBuffer;
129 ::std::for_each( rTableList.begin(), rTableList.end(), lcl_appendTableNumber( aBuffer ));
130 // remove last trailing ' '
131 if( !aBuffer.isEmpty() )
132 aBuffer.setLength( aBuffer.getLength() - 1 );
133 return aBuffer.makeStringAndClear();
136 uno::Reference< frame::XModel > lcl_GetXModel( ScDocument * pDoc )
138 uno::Reference< frame::XModel > xModel;
139 SfxObjectShell * pObjSh( pDoc ? pDoc->GetDocumentShell() : 0 );
140 if( pObjSh )
141 xModel.set( pObjSh->GetModel());
142 return xModel;
145 struct TokenTable : boost::noncopyable
147 SCROW mnRowCount;
148 SCCOL mnColCount;
149 vector<FormulaToken*> maTokens;
151 void init( SCCOL nColCount, SCROW nRowCount )
153 mnColCount = nColCount;
154 mnRowCount = nRowCount;
155 maTokens.reserve(mnColCount*mnRowCount);
157 void clear()
159 ::std::for_each(maTokens.begin(), maTokens.end(), ScDeleteObjectByPtr<FormulaToken>());
162 void push_back( FormulaToken* pToken )
164 maTokens.push_back( pToken );
165 OSL_ENSURE( maTokens.size()<= static_cast<sal_uInt32>( mnColCount*mnRowCount ), "too much tokens" );
168 sal_uInt32 getIndex(SCCOL nCol, SCROW nRow) const
170 OSL_ENSURE( nCol<mnColCount, "wrong column index" );
171 OSL_ENSURE( nRow<mnRowCount, "wrong row index" );
172 sal_uInt32 nRet = static_cast<sal_uInt32>(nCol*mnRowCount + nRow);
173 OSL_ENSURE( maTokens.size()>= static_cast<sal_uInt32>( mnColCount*mnRowCount ), "too few tokens" );
174 return nRet;
177 vector<ScTokenRef>* getColRanges(SCCOL nCol) const;
178 vector<ScTokenRef>* getRowRanges(SCROW nRow) const;
179 vector<ScTokenRef>* getAllRanges() const;
182 vector<ScTokenRef>* TokenTable::getColRanges(SCCOL nCol) const
184 if (nCol >= mnColCount)
185 return NULL;
186 if( mnRowCount<=0 )
187 return NULL;
189 SAL_WNODEPRECATED_DECLARATIONS_PUSH
190 auto_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
191 SAL_WNODEPRECATED_DECLARATIONS_POP
192 sal_uInt32 nLast = getIndex(nCol, mnRowCount-1);
193 for (sal_uInt32 i = getIndex(nCol, 0); i <= nLast; ++i)
195 FormulaToken* p = maTokens[i];
196 if (!p)
197 continue;
199 ScTokenRef pCopy(static_cast<ScToken*>(p->Clone()));
200 ScRefTokenHelper::join(*pTokens, pCopy, ScAddress());
202 return pTokens.release();
205 vector<ScTokenRef>* TokenTable::getRowRanges(SCROW nRow) const
207 if (nRow >= mnRowCount)
208 return NULL;
209 if( mnColCount<=0 )
210 return NULL;
212 SAL_WNODEPRECATED_DECLARATIONS_PUSH
213 auto_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
214 SAL_WNODEPRECATED_DECLARATIONS_POP
215 sal_uInt32 nLast = getIndex(mnColCount-1, nRow);
216 for (sal_uInt32 i = getIndex(0, nRow); i <= nLast; i += mnRowCount)
218 FormulaToken* p = maTokens[i];
219 if (!p)
220 continue;
222 ScTokenRef p2(static_cast<ScToken*>(p->Clone()));
223 ScRefTokenHelper::join(*pTokens, p2, ScAddress());
225 return pTokens.release();
228 vector<ScTokenRef>* TokenTable::getAllRanges() const
230 SAL_WNODEPRECATED_DECLARATIONS_PUSH
231 auto_ptr< vector<ScTokenRef> > pTokens(new vector<ScTokenRef>);
232 SAL_WNODEPRECATED_DECLARATIONS_POP
233 sal_uInt32 nStop = mnColCount*mnRowCount;
234 for (sal_uInt32 i = 0; i < nStop; i++)
236 FormulaToken* p = maTokens[i];
237 if (!p)
238 continue;
240 ScTokenRef p2(static_cast<ScToken*>(p->Clone()));
241 ScRefTokenHelper::join(*pTokens, p2, ScAddress());
243 return pTokens.release();
246 // ============================================================================
248 typedef std::map<sal_uInt32, FormulaToken*> FormulaTokenMap;
249 typedef std::map<sal_uInt32, FormulaTokenMap*> FormulaTokenMapMap;
251 class Chart2PositionMap
253 public:
254 Chart2PositionMap(SCCOL nColCount, SCROW nRowCount,
255 bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols,
256 ScDocument* pDoc );
257 ~Chart2PositionMap();
259 SCCOL getDataColCount() const { return mnDataColCount; }
260 SCROW getDataRowCount() const { return mnDataRowCount; }
262 vector<ScTokenRef>* getLeftUpperCornerRanges() const;
263 vector<ScTokenRef>* getAllColHeaderRanges() const;
264 vector<ScTokenRef>* getAllRowHeaderRanges() const;
266 vector<ScTokenRef>* getColHeaderRanges(SCCOL nChartCol) const;
267 vector<ScTokenRef>* getRowHeaderRanges(SCROW nChartRow) const;
269 vector<ScTokenRef>* getDataColRanges(SCCOL nCol) const;
270 vector<ScTokenRef>* getDataRowRanges(SCROW nRow) const;
272 private:
273 SCCOL mnDataColCount;
274 SCROW mnDataRowCount;
276 TokenTable maLeftUpperCorner; //nHeaderColCount*nHeaderRowCount
277 TokenTable maColHeaders; //mnDataColCount*nHeaderRowCount
278 TokenTable maRowHeaders; //nHeaderColCount*mnDataRowCount
279 TokenTable maData;//mnDataColCount*mnDataRowCount
282 Chart2PositionMap::Chart2PositionMap(SCCOL nAllColCount, SCROW nAllRowCount,
283 bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols, ScDocument* pDoc)
285 // if bFillRowHeader is true, at least the first column serves as a row header.
286 // If more than one column is pure text all the first pure text columns are used as header.
287 // Likewise, if bFillColumnHeader is true, at least the first row serves as a column header.
288 // If more than one row is pure text all the first pure text rows are used as header.
290 SCROW nHeaderRowCount = (bFillColumnHeader && nAllColCount && nAllRowCount) ? 1 : 0;
291 SCCOL nHeaderColCount = (bFillRowHeader && nAllColCount && nAllRowCount) ? 1 : 0;
293 if( nHeaderColCount || nHeaderRowCount )
295 const SCCOL nInitialHeaderColCount = nHeaderColCount;
296 //check whether there is more than one text column or row that should be added to the headers
297 SCROW nSmallestValueRowIndex = nAllRowCount;
298 bool bFoundValues = false;
299 bool bFoundAnything = false;
300 FormulaTokenMapMap::const_iterator it1 = rCols.begin();
301 for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol)
303 if (it1 != rCols.end() && nCol>=nHeaderColCount)
305 bool bFoundValuesInRow = false;
306 FormulaTokenMap* pCol = it1->second;
307 FormulaTokenMap::const_iterator it2 = pCol->begin();
308 for (SCROW nRow = 0; !bFoundValuesInRow && nRow < nSmallestValueRowIndex && it2 != pCol->end(); ++nRow)
310 FormulaToken* pToken = it2->second;
311 if (pToken && nRow>=nHeaderRowCount)
313 ScRange aRange;
314 bool bExternal = false;
315 StackVar eType = pToken->GetType();
316 if( eType==svExternal || eType==svExternalSingleRef || eType==svExternalDoubleRef || eType==svExternalName )
317 bExternal = true;//lllll todo correct?
318 ScTokenRef pSharedToken(static_cast<ScToken*>(pToken->Clone()));
319 ScRefTokenHelper::getRangeFromToken(aRange, pSharedToken, ScAddress(), bExternal);
320 SCCOL nCol1=0, nCol2=0;
321 SCROW nRow1=0, nRow2=0;
322 SCTAB nTab1=0, nTab2=0;
323 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
324 if (pDoc && pDoc->HasValueData( nCol1, nRow1, nTab1 ))
326 bFoundValuesInRow = bFoundValues = bFoundAnything = true;
327 nSmallestValueRowIndex = std::min( nSmallestValueRowIndex, nRow );
329 if( !bFoundAnything )
331 if (pDoc && pDoc->HasData( nCol1, nRow1, nTab1 ) )
332 bFoundAnything = true;
335 ++it2;
337 if(!bFoundValues && nHeaderColCount>0)
338 nHeaderColCount++;
340 ++it1;
342 if( bFoundAnything )
344 if(nHeaderRowCount>0)
346 if( bFoundValues )
347 nHeaderRowCount = nSmallestValueRowIndex;
348 else if( nAllRowCount>1 )
349 nHeaderRowCount = nAllRowCount-1;
352 else //if the cells are completely empty, just use single header rows and columns
353 nHeaderColCount = nInitialHeaderColCount;
356 mnDataColCount = nAllColCount - nHeaderColCount;
357 mnDataRowCount = nAllRowCount - nHeaderRowCount;
359 maLeftUpperCorner.init(nHeaderColCount,nHeaderRowCount);
360 maColHeaders.init(mnDataColCount,nHeaderRowCount);
361 maRowHeaders.init(nHeaderColCount,mnDataRowCount);
362 maData.init(mnDataColCount,mnDataRowCount);
364 FormulaTokenMapMap::const_iterator it1 = rCols.begin();
365 for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol)
367 if (it1 != rCols.end())
369 FormulaTokenMap* pCol = it1->second;
370 FormulaTokenMap::const_iterator it2 = pCol->begin();
371 for (SCROW nRow = 0; nRow < nAllRowCount; ++nRow)
373 FormulaToken* pToken = NULL;
374 if (it2 != pCol->end())
376 pToken = it2->second;
377 ++it2;
380 if( nCol < nHeaderColCount )
382 if( nRow < nHeaderRowCount )
383 maLeftUpperCorner.push_back(pToken);
384 else
385 maRowHeaders.push_back(pToken);
387 else if( nRow < nHeaderRowCount )
388 maColHeaders.push_back(pToken);
389 else
390 maData.push_back(pToken);
392 ++it1;
397 Chart2PositionMap::~Chart2PositionMap()
399 maLeftUpperCorner.clear();
400 maColHeaders.clear();
401 maRowHeaders.clear();
402 maData.clear();
405 vector<ScTokenRef>* Chart2PositionMap::getLeftUpperCornerRanges() const
407 return maLeftUpperCorner.getAllRanges();
409 vector<ScTokenRef>* Chart2PositionMap::getAllColHeaderRanges() const
411 return maColHeaders.getAllRanges();
413 vector<ScTokenRef>* Chart2PositionMap::getAllRowHeaderRanges() const
415 return maRowHeaders.getAllRanges();
417 vector<ScTokenRef>* Chart2PositionMap::getColHeaderRanges(SCCOL nCol) const
419 return maColHeaders.getColRanges( nCol);
421 vector<ScTokenRef>* Chart2PositionMap::getRowHeaderRanges(SCROW nRow) const
423 return maRowHeaders.getRowRanges( nRow);
426 vector<ScTokenRef>* Chart2PositionMap::getDataColRanges(SCCOL nCol) const
428 return maData.getColRanges( nCol);
431 vector<ScTokenRef>* Chart2PositionMap::getDataRowRanges(SCROW nRow) const
433 return maData.getRowRanges( nRow);
436 // ----------------------------------------------------------------------------
439 * Designed to be a drop-in replacement for ScChartPositioner, in order to
440 * handle external references.
442 class Chart2Positioner : boost::noncopyable
444 enum GlueType
446 GLUETYPE_NA,
447 GLUETYPE_NONE,
448 GLUETYPE_COLS,
449 GLUETYPE_ROWS,
450 GLUETYPE_BOTH
453 public:
454 Chart2Positioner(ScDocument* pDoc, const vector<ScTokenRef>& rRefTokens) :
455 mrRefTokens(rRefTokens),
456 mpPositionMap(NULL),
457 meGlue(GLUETYPE_NA),
458 mpDoc(pDoc),
459 mbColHeaders(false),
460 mbRowHeaders(false),
461 mbDummyUpperLeft(false)
465 ~Chart2Positioner()
469 void setHeaders(bool bColHeaders, bool bRowHeaders)
471 mbColHeaders = bColHeaders;
472 mbRowHeaders = bRowHeaders;
475 Chart2PositionMap* getPositionMap()
477 createPositionMap();
478 return mpPositionMap.get();
481 private:
482 void invalidateGlue();
483 void glueState();
484 void calcGlueState(SCCOL nCols, SCROW nRows);
485 void createPositionMap();
487 private:
488 const vector<ScTokenRef>& mrRefTokens;
489 boost::scoped_ptr<Chart2PositionMap> mpPositionMap;
490 GlueType meGlue;
491 SCCOL mnStartCol;
492 SCROW mnStartRow;
493 ScDocument* mpDoc;
494 bool mbColHeaders:1;
495 bool mbRowHeaders:1;
496 bool mbDummyUpperLeft:1;
499 void Chart2Positioner::invalidateGlue()
501 meGlue = GLUETYPE_NA;
502 mpPositionMap.reset(NULL);
505 void Chart2Positioner::glueState()
507 if (meGlue != GLUETYPE_NA)
508 return;
510 mbDummyUpperLeft = false;
511 if (mrRefTokens.size() <= 1)
513 // Source data consists of only one data range.
514 const ScTokenRef& p = mrRefTokens.front();
515 ScComplexRefData aData;
516 if (ScRefTokenHelper::getDoubleRefDataFromToken(aData, p))
518 if (aData.Ref1.Tab() == aData.Ref2.Tab())
519 meGlue = GLUETYPE_NONE;
520 else
521 meGlue = GLUETYPE_COLS;
522 mnStartCol = aData.Ref1.Col();
523 mnStartRow = aData.Ref1.Row();
525 else
527 invalidateGlue();
528 mnStartCol = 0;
529 mnStartRow = 0;
531 return;
534 ScComplexRefData aData;
535 ScRefTokenHelper::getDoubleRefDataFromToken(aData, mrRefTokens.front());
536 mnStartCol = aData.Ref1.Col();
537 mnStartRow = aData.Ref1.Row();
539 SCCOL nEndCol = 0;
540 SCROW nEndRow = 0;
541 for (vector<ScTokenRef>::const_iterator itr = mrRefTokens.begin(), itrEnd = mrRefTokens.end()
542 ; itr != itrEnd; ++itr)
544 ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr);
545 SCCOLROW n1 = aData.Ref1.Col();
546 SCCOLROW n2 = aData.Ref2.Col();
547 if (n1 > MAXCOL)
548 n1 = MAXCOL;
549 if (n2 > MAXCOL)
550 n2 = MAXCOL;
551 if (n1 < mnStartCol)
552 mnStartCol = static_cast<SCCOL>(n1);
553 if (n2 > nEndCol)
554 nEndCol = static_cast<SCCOL>(n2);
556 n1 = aData.Ref1.Row();
557 n2 = aData.Ref2.Row();
558 if (n1 > MAXROW)
559 n1 = MAXROW;
560 if (n2 > MAXROW)
561 n2 = MAXROW;
563 if (n1 < mnStartRow)
564 mnStartRow = static_cast<SCROW>(n1);
565 if (n2 > nEndRow)
566 nEndRow = static_cast<SCROW>(n2);
569 if (mnStartCol == nEndCol)
571 // All source data is in a single column.
572 meGlue = GLUETYPE_ROWS;
573 return;
576 if (mnStartRow == nEndRow)
578 // All source data is in a single row.
579 meGlue = GLUETYPE_COLS;
580 return;
583 // total column size
584 SCCOL nC = nEndCol - mnStartCol + 1;
586 // total row size
587 SCROW nR = nEndRow - mnStartRow + 1;
589 // #i103540# prevent invalid vector size
590 if ((nC <= 0) || (nR <= 0))
592 invalidateGlue();
593 mnStartCol = 0;
594 mnStartRow = 0;
595 return;
598 calcGlueState(nC, nR);
601 enum State { Hole = 0, Occupied = 1, Free = 2, Glue = 3 };
603 void Chart2Positioner::calcGlueState(SCCOL nColSize, SCROW nRowSize)
605 // TODO: This code can use some space optimization. Using an array to
606 // store individual cell's states is terribly inefficient esp for large
607 // data ranges; let's use flat_segment_tree to reduce memory usage here.
609 sal_uInt32 nCR = static_cast<sal_uInt32>(nColSize*nRowSize);
611 vector<State> aCellStates(nCR, Hole);
613 // Mark all referenced cells "occupied".
614 for (vector<ScTokenRef>::const_iterator itr = mrRefTokens.begin(), itrEnd = mrRefTokens.end();
615 itr != itrEnd; ++itr)
617 ScComplexRefData aData;
618 ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr);
619 SCCOL nCol1 = aData.Ref1.Col() - mnStartCol;
620 SCCOL nCol2 = aData.Ref2.Col() - mnStartCol;
621 SCROW nRow1 = aData.Ref1.Row() - mnStartRow;
622 SCROW nRow2 = aData.Ref2.Row() - mnStartRow;
623 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
624 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
626 size_t i = nCol*nRowSize + nRow;
627 aCellStates[i] = Occupied;
631 // If at least one cell in either the first column or first row is empty,
632 // we don't glue at all unless the whole column or row is empty; we expect
633 // all cells in the first column / row to be fully populated. If we have
634 // empty column or row, then we do glue by the column or row,
635 // respectively.
637 bool bGlue = true;
638 bool bGlueCols = false;
639 for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol)
641 for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
643 size_t i = nCol*nRowSize + nRow;
644 if (aCellStates[i] == Occupied)
646 if (nCol == 0 || nRow == 0)
647 break;
649 bGlue = false;
651 else
652 aCellStates[i] = Free;
654 size_t nLast = (nCol+1)*nRowSize - 1; // index for the last cell in the column.
655 if (bGlue && aCellStates[nLast] == Free)
657 // Whole column is empty.
658 aCellStates[nLast] = Glue;
659 bGlueCols = true;
663 bool bGlueRows = false;
664 for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
666 size_t i = nRow;
667 for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol, i += nRowSize)
669 if (aCellStates[i] == Occupied)
671 if (nCol == 0 || nRow == 0)
672 break;
674 bGlue = false;
676 else
677 aCellStates[i] = Free;
679 i = (nColSize-1)*nRowSize + nRow; // index for the row position in the last column.
680 if (bGlue && aCellStates[i] == Free)
682 // Whole row is empty.
683 aCellStates[i] = Glue;
684 bGlueRows = true;
688 size_t i = 1;
689 for (sal_uInt32 n = 1; bGlue && n < nCR; ++n, ++i)
690 if (aCellStates[i] == Hole)
691 bGlue = false;
693 if (bGlue)
695 if (bGlueCols && bGlueRows)
696 meGlue = GLUETYPE_BOTH;
697 else if (bGlueRows)
698 meGlue = GLUETYPE_ROWS;
699 else
700 meGlue = GLUETYPE_COLS;
701 if (aCellStates.front() != Occupied)
702 mbDummyUpperLeft = true;
704 else
705 meGlue = GLUETYPE_NONE;
708 void Chart2Positioner::createPositionMap()
710 if (meGlue == GLUETYPE_NA && mpPositionMap.get())
711 mpPositionMap.reset(NULL);
713 if (mpPositionMap.get())
714 return;
716 glueState();
718 bool bNoGlue = (meGlue == GLUETYPE_NONE);
719 SAL_WNODEPRECATED_DECLARATIONS_PUSH
720 auto_ptr<FormulaTokenMapMap> pCols(new FormulaTokenMapMap);
721 SAL_WNODEPRECATED_DECLARATIONS_POP
722 FormulaTokenMap* pCol = NULL;
723 SCROW nNoGlueRow = 0;
724 for (vector<ScTokenRef>::const_iterator itr = mrRefTokens.begin(), itrEnd = mrRefTokens.end();
725 itr != itrEnd; ++itr)
727 const ScTokenRef& pToken = *itr;
729 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
730 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
731 svl::SharedString aTabName = svl::SharedString::getEmptyString();
732 if (bExternal)
733 aTabName = pToken->GetString();
735 ScComplexRefData aData;
736 if( !ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr) )
737 break;
738 const ScSingleRefData& s = aData.Ref1;
739 const ScSingleRefData& e = aData.Ref2;
740 SCCOL nCol1 = s.Col(), nCol2 = e.Col();
741 SCROW nRow1 = s.Row(), nRow2 = e.Row();
742 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
744 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
746 // columns on secondary sheets are appended; we treat them as if
747 // all columns are on the same sheet. TODO: We can't assume that
748 // the column range is 16-bit; remove that restriction.
749 sal_uInt32 nInsCol = (static_cast<sal_uInt32>(nTab) << 16) |
750 (bNoGlue ? 0 : static_cast<sal_uInt32>(nCol1));
752 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol)
754 FormulaTokenMapMap::const_iterator it = pCols->find(nInsCol);
755 if (it == pCols->end())
757 pCol = new FormulaTokenMap;
758 (*pCols)[ nInsCol ] = pCol;
760 else
761 pCol = it->second;
763 sal_uInt32 nInsRow = static_cast<sal_uInt32>(bNoGlue ? nNoGlueRow : nRow1);
764 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow, ++nInsRow)
766 ScSingleRefData aCellData;
767 aCellData.InitFlags();
768 aCellData.SetFlag3D(true);
769 aCellData.SetColRel(false);
770 aCellData.SetRowRel(false);
771 aCellData.SetTabRel(false);
772 aCellData.SetAbsCol(nCol);
773 aCellData.SetAbsRow(nRow);
774 aCellData.SetAbsTab(nTab);
776 if (pCol->find(nInsRow) == pCol->end())
778 if (bExternal)
779 (*pCol)[ nInsRow ] = new ScExternalSingleRefToken(nFileId, aTabName, aCellData);
780 else
781 (*pCol)[ nInsRow ] = new ScSingleRefToken(aCellData);
786 nNoGlueRow += nRow2 - nRow1 + 1;
789 bool bFillRowHeader = mbRowHeaders;
790 bool bFillColumnHeader = mbColHeaders;
792 SCSIZE nAllColCount = static_cast<SCSIZE>(pCols->size());
793 SCSIZE nAllRowCount = 0;
794 if (!pCols->empty())
796 pCol = pCols->begin()->second;
797 if (mbDummyUpperLeft)
798 if (pCol->find(0) == pCol->end())
799 (*pCol)[ 0 ] = NULL; // Dummy fuer Beschriftung
800 nAllRowCount = static_cast<SCSIZE>(pCol->size());
803 if( nAllColCount!=0 && nAllRowCount!=0 )
805 if (bNoGlue)
807 FormulaTokenMap* pFirstCol = pCols->begin()->second;
808 for (FormulaTokenMap::const_iterator it1 = pFirstCol->begin(); it1 != pFirstCol->end(); ++it1)
810 sal_uInt32 nKey = it1->first;
811 for (FormulaTokenMapMap::const_iterator it2 = pCols->begin(); it2 != pCols->end(); ++it2)
813 pCol = it2->second;
814 if (pCol->find(nKey) == pCol->end())
815 (*pCol)[ nKey ] = NULL;
820 mpPositionMap.reset(
821 new Chart2PositionMap(
822 static_cast<SCCOL>(nAllColCount), static_cast<SCROW>(nAllRowCount),
823 bFillRowHeader, bFillColumnHeader, *pCols, mpDoc));
825 // Destroy all column instances.
826 for (FormulaTokenMapMap::const_iterator it = pCols->begin(); it != pCols->end(); ++it)
828 pCol = it->second;
829 delete pCol;
833 // ============================================================================
836 * Function object to create a range string from a token list.
838 class Tokens2RangeString : public unary_function<ScTokenRef, void>
840 public:
841 Tokens2RangeString(ScDocument* pDoc, FormulaGrammar::Grammar eGram, sal_Unicode cRangeSep) :
842 mpRangeStr(new OUStringBuffer),
843 mpDoc(pDoc),
844 meGrammar(eGram),
845 mcRangeSep(cRangeSep),
846 mbFirst(true)
850 Tokens2RangeString(const Tokens2RangeString& r) :
851 mpRangeStr(r.mpRangeStr),
852 mpDoc(r.mpDoc),
853 meGrammar(r.meGrammar),
854 mcRangeSep(r.mcRangeSep),
855 mbFirst(r.mbFirst)
859 void operator() (const ScTokenRef& rToken)
861 ScCompiler aCompiler(mpDoc, ScAddress(0,0,0));
862 aCompiler.SetGrammar(meGrammar);
863 OUString aStr;
864 aCompiler.CreateStringFromToken(aStr, rToken.get());
865 if (mbFirst)
866 mbFirst = false;
867 else
868 mpRangeStr->append(mcRangeSep);
869 mpRangeStr->append(aStr);
872 void getString(OUString& rStr)
874 rStr = mpRangeStr->makeStringAndClear();
877 private:
878 shared_ptr<OUStringBuffer> mpRangeStr;
879 ScDocument* mpDoc;
880 FormulaGrammar::Grammar meGrammar;
881 sal_Unicode mcRangeSep;
882 bool mbFirst;
886 * Function object to convert a list of tokens into a string form suitable
887 * for ODF export. In ODF, a range is expressed as
889 * (start cell address):(end cell address)
891 * and each address doesn't include any '$' symbols.
893 class Tokens2RangeStringXML : public unary_function<ScTokenRef, void>
895 public:
896 Tokens2RangeStringXML(ScDocument* pDoc) :
897 mpRangeStr(new OUStringBuffer),
898 mpDoc(pDoc),
899 mcRangeSep(' '),
900 mcAddrSep(':'),
901 mbFirst(true)
905 Tokens2RangeStringXML(const Tokens2RangeStringXML& r) :
906 mpRangeStr(r.mpRangeStr),
907 mpDoc(r.mpDoc),
908 mcRangeSep(r.mcRangeSep),
909 mcAddrSep(r.mcAddrSep),
910 mbFirst(r.mbFirst)
914 void operator() (const ScTokenRef& rToken)
916 if (mbFirst)
917 mbFirst = false;
918 else
919 mpRangeStr->append(mcRangeSep);
921 ScTokenRef aStart, aEnd;
922 bool bValidToken = splitRangeToken(rToken, aStart, aEnd);
923 OSL_ENSURE(bValidToken, "invalid token");
924 if (!bValidToken)
925 return;
926 ScCompiler aCompiler(mpDoc, ScAddress(0,0,0));
927 aCompiler.SetGrammar(FormulaGrammar::GRAM_ENGLISH);
929 OUString aStr;
930 aCompiler.CreateStringFromToken(aStr, aStart.get());
931 mpRangeStr->append(aStr);
933 mpRangeStr->append(mcAddrSep);
935 OUString aStr;
936 aCompiler.CreateStringFromToken(aStr, aEnd.get());
937 mpRangeStr->append(aStr);
941 void getString(OUString& rStr)
943 rStr = mpRangeStr->makeStringAndClear();
946 private:
947 bool splitRangeToken(const ScTokenRef& pToken, ScTokenRef& rStart, ScTokenRef& rEnd) const
949 ScComplexRefData aData;
950 bool bIsRefToken = ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken);
951 OSL_ENSURE(bIsRefToken, "invalid token");
952 if (!bIsRefToken)
953 return false;
954 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
955 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
956 svl::SharedString aTabName = svl::SharedString::getEmptyString();
957 if (bExternal)
958 aTabName = pToken->GetString();
960 // In saving to XML, we don't prepend address with '$'.
961 setRelative(aData.Ref1);
962 setRelative(aData.Ref2);
964 // In XML, the range must explicitly specify sheet name.
965 aData.Ref1.SetFlag3D(true);
966 aData.Ref2.SetFlag3D(true);
968 if (bExternal)
969 rStart.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref1));
970 else
971 rStart.reset(new ScSingleRefToken(aData.Ref1));
973 if (bExternal)
974 rEnd.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref2));
975 else
976 rEnd.reset(new ScSingleRefToken(aData.Ref2));
977 return true;
980 void setRelative(ScSingleRefData& rData) const
982 rData.SetColRel(true);
983 rData.SetRowRel(true);
984 rData.SetTabRel(true);
987 private:
988 shared_ptr<OUStringBuffer> mpRangeStr;
989 ScDocument* mpDoc;
990 sal_Unicode mcRangeSep;
991 sal_Unicode mcAddrSep;
992 bool mbFirst;
995 void lcl_convertTokensToString(OUString& rStr, const vector<ScTokenRef>& rTokens, ScDocument* pDoc)
997 const sal_Unicode cRangeSep = ScCompiler::GetNativeSymbolChar(ocSep);
998 FormulaGrammar::Grammar eGrammar = pDoc->GetGrammar();
999 Tokens2RangeString func(pDoc, eGrammar, cRangeSep);
1000 func = ::std::for_each(rTokens.begin(), rTokens.end(), func);
1001 func.getString(rStr);
1004 } // anonymous namespace
1006 // DataProvider ==============================================================
1008 ScChart2DataProvider::ScChart2DataProvider( ScDocument* pDoc )
1009 : m_pDocument( pDoc)
1010 , m_aPropSet(lcl_GetDataProviderPropertyMap())
1011 , m_bIncludeHiddenCells( sal_True)
1013 if ( m_pDocument )
1014 m_pDocument->AddUnoObject( *this);
1017 ScChart2DataProvider::~ScChart2DataProvider()
1019 if ( m_pDocument )
1020 m_pDocument->RemoveUnoObject( *this);
1024 void ScChart2DataProvider::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
1026 if ( rHint.ISA( SfxSimpleHint ) &&
1027 ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
1029 m_pDocument = NULL;
1033 ::sal_Bool SAL_CALL ScChart2DataProvider::createDataSourcePossible( const uno::Sequence< beans::PropertyValue >& aArguments )
1034 throw (uno::RuntimeException)
1036 SolarMutexGuard aGuard;
1037 if( ! m_pDocument )
1038 return false;
1040 OUString aRangeRepresentation;
1041 for(sal_Int32 i = 0; i < aArguments.getLength(); ++i)
1043 if ( aArguments[i].Name == "CellRangeRepresentation" )
1045 aArguments[i].Value >>= aRangeRepresentation;
1049 vector<ScTokenRef> aTokens;
1050 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1051 ScRefTokenHelper::compileRangeRepresentation(
1052 aTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1053 return !aTokens.empty();
1056 namespace
1059 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1060 Reference< chart2::data::XLabeledDataSequence > lcl_createLabeledDataSequenceFromTokens(
1061 auto_ptr< vector< ScTokenRef > > pValueTokens, auto_ptr< vector< ScTokenRef > > pLabelTokens,
1062 ScDocument* pDoc, const Reference< chart2::data::XDataProvider >& xDP, bool bIncludeHiddenCells )
1064 Reference< chart2::data::XLabeledDataSequence > xResult;
1065 bool bHasValues = pValueTokens.get() && !pValueTokens->empty();
1066 bool bHasLabel = pLabelTokens.get() && !pLabelTokens->empty();
1067 if( bHasValues || bHasLabel )
1071 Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1072 if ( xContext.is() )
1074 xResult.set( chart2::data::LabeledDataSequence::create(xContext), uno::UNO_QUERY_THROW );
1076 if ( bHasValues )
1078 Reference< chart2::data::XDataSequence > xSeq( new ScChart2DataSequence( pDoc, xDP, pValueTokens.release(), bIncludeHiddenCells ) );
1079 xResult->setValues( xSeq );
1081 if ( bHasLabel )
1083 Reference< chart2::data::XDataSequence > xLabelSeq( new ScChart2DataSequence( pDoc, xDP, pLabelTokens.release(), bIncludeHiddenCells ) );
1084 xResult->setLabel( xLabelSeq );
1087 catch( const uno::Exception& )
1091 return xResult;
1093 SAL_WNODEPRECATED_DECLARATIONS_POP
1095 //----------------------------------------------------
1097 * Check the current list of reference tokens, and add the upper left
1098 * corner of the minimum range that encloses all ranges if certain
1099 * conditions are met.
1101 * @param rRefTokens list of reference tokens
1103 * @return true if the corner was added, false otherwise.
1105 bool lcl_addUpperLeftCornerIfMissing(vector<ScTokenRef>& rRefTokens,
1106 SCROW nCornerRowCount=1, SCCOL nCornerColumnCount=1)
1108 using ::std::max;
1109 using ::std::min;
1111 if (rRefTokens.empty())
1112 return false;
1114 SCCOL nMinCol = MAXCOLCOUNT;
1115 SCROW nMinRow = MAXROWCOUNT;
1116 SCCOL nMaxCol = 0;
1117 SCROW nMaxRow = 0;
1118 SCTAB nTab = 0;
1120 sal_uInt16 nFileId = 0;
1121 svl::SharedString aExtTabName;
1122 bool bExternal = false;
1124 vector<ScTokenRef>::const_iterator itr = rRefTokens.begin(), itrEnd = rRefTokens.end();
1126 // Get the first ref token.
1127 ScTokenRef pToken = *itr;
1128 switch (pToken->GetType())
1130 case svSingleRef:
1132 const ScSingleRefData& rData = pToken->GetSingleRef();
1133 nMinCol = rData.Col();
1134 nMinRow = rData.Row();
1135 nMaxCol = rData.Col();
1136 nMaxRow = rData.Row();
1137 nTab = rData.Tab();
1139 break;
1140 case svDoubleRef:
1142 const ScComplexRefData& rData = pToken->GetDoubleRef();
1143 nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1144 nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1145 nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1146 nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1147 nTab = rData.Ref1.Tab();
1149 break;
1150 case svExternalSingleRef:
1152 const ScSingleRefData& rData = pToken->GetSingleRef();
1153 nMinCol = rData.Col();
1154 nMinRow = rData.Row();
1155 nMaxCol = rData.Col();
1156 nMaxRow = rData.Row();
1157 nTab = rData.Tab();
1158 nFileId = pToken->GetIndex();
1159 aExtTabName = pToken->GetString();
1160 bExternal = true;
1162 break;
1163 case svExternalDoubleRef:
1165 const ScComplexRefData& rData = pToken->GetDoubleRef();
1166 nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
1167 nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
1168 nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
1169 nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
1170 nTab = rData.Ref1.Tab();
1171 nFileId = pToken->GetIndex();
1172 aExtTabName = pToken->GetString();
1173 bExternal = true;
1175 break;
1176 default:
1180 // Determine the minimum range enclosing all data ranges. Also make sure
1181 // that they are all on the same table.
1183 for (++itr; itr != itrEnd; ++itr)
1185 pToken = *itr;
1186 switch (pToken->GetType())
1188 case svSingleRef:
1190 const ScSingleRefData& rData = pToken->GetSingleRef();
1192 nMinCol = min(nMinCol, rData.Col());
1193 nMinRow = min(nMinRow, rData.Row());
1194 nMaxCol = max(nMaxCol, rData.Col());
1195 nMaxRow = max(nMaxRow, rData.Row());
1196 if (nTab != rData.Tab() || bExternal)
1197 return false;
1199 break;
1200 case svDoubleRef:
1202 const ScComplexRefData& rData = pToken->GetDoubleRef();
1204 nMinCol = min(nMinCol, rData.Ref1.Col());
1205 nMinCol = min(nMinCol, rData.Ref2.Col());
1206 nMinRow = min(nMinRow, rData.Ref1.Row());
1207 nMinRow = min(nMinRow, rData.Ref2.Row());
1209 nMaxCol = max(nMaxCol, rData.Ref1.Col());
1210 nMaxCol = max(nMaxCol, rData.Ref2.Col());
1211 nMaxRow = max(nMaxRow, rData.Ref1.Row());
1212 nMaxRow = max(nMaxRow, rData.Ref2.Row());
1214 if (nTab != rData.Ref1.Tab() || bExternal)
1215 return false;
1217 break;
1218 case svExternalSingleRef:
1220 if (!bExternal)
1221 return false;
1223 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1224 return false;
1226 const ScSingleRefData& rData = pToken->GetSingleRef();
1228 nMinCol = min(nMinCol, rData.Col());
1229 nMinRow = min(nMinRow, rData.Row());
1230 nMaxCol = max(nMaxCol, rData.Col());
1231 nMaxRow = max(nMaxRow, rData.Row());
1233 break;
1234 case svExternalDoubleRef:
1236 if (!bExternal)
1237 return false;
1239 if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
1240 return false;
1242 const ScComplexRefData& rData = pToken->GetDoubleRef();
1244 nMinCol = min(nMinCol, rData.Ref1.Col());
1245 nMinCol = min(nMinCol, rData.Ref2.Col());
1246 nMinRow = min(nMinRow, rData.Ref1.Row());
1247 nMinRow = min(nMinRow, rData.Ref2.Row());
1249 nMaxCol = max(nMaxCol, rData.Ref1.Col());
1250 nMaxCol = max(nMaxCol, rData.Ref2.Col());
1251 nMaxRow = max(nMaxRow, rData.Ref1.Row());
1252 nMaxRow = max(nMaxRow, rData.Ref2.Row());
1254 break;
1255 default:
1260 if (nMinRow >= nMaxRow || nMinCol >= nMaxCol ||
1261 nMinRow >= MAXROWCOUNT || nMinCol >= MAXCOLCOUNT ||
1262 nMaxRow >= MAXROWCOUNT || nMaxCol >= MAXCOLCOUNT)
1264 // Invalid range. Bail out.
1265 return false;
1268 // Check if the following conditions are met:
1270 // 1) The upper-left corner cell is not included.
1271 // 2) The three adjacent cells of that corner cell are included.
1273 bool bRight = false, bBottom = false, bDiagonal = false;
1274 for (itr = rRefTokens.begin(); itr != itrEnd; ++itr)
1276 pToken = *itr;
1277 switch (pToken->GetType())
1279 case svSingleRef:
1280 case svExternalSingleRef:
1282 const ScSingleRefData& rData = pToken->GetSingleRef();
1283 if (rData.Col() == nMinCol && rData.Row() == nMinRow)
1284 // The corner cell is contained.
1285 return false;
1287 if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow)
1288 bRight = true;
1290 if (rData.Col() == nMinCol && rData.Row() == nMinRow+nCornerRowCount)
1291 bBottom = true;
1293 if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow+nCornerRowCount)
1294 bDiagonal = true;
1296 break;
1297 case svDoubleRef:
1298 case svExternalDoubleRef:
1300 const ScComplexRefData& rData = pToken->GetDoubleRef();
1301 const ScSingleRefData& r1 = rData.Ref1;
1302 const ScSingleRefData& r2 = rData.Ref2;
1303 if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1304 r1.Row() <= nMinRow && nMinRow <= r2.Row())
1305 // The corner cell is contained.
1306 return false;
1308 if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1309 r1.Row() <= nMinRow && nMinRow <= r2.Row())
1310 bRight = true;
1312 if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
1313 r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1314 bBottom = true;
1316 if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
1317 r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
1318 bDiagonal = true;
1320 break;
1321 default:
1326 if (!bRight || !bBottom || !bDiagonal)
1327 // Not all the adjacent cells are included. Bail out.
1328 return false;
1330 ScSingleRefData aData;
1331 aData.InitFlags();
1332 aData.SetFlag3D(true);
1333 aData.SetAbsCol(nMinCol);
1334 aData.SetAbsRow(nMinRow);
1335 aData.SetAbsTab(nTab);
1337 if( nCornerRowCount==1 && nCornerColumnCount==1 )
1339 if (bExternal)
1341 ScTokenRef pCorner(
1342 new ScExternalSingleRefToken(nFileId, aExtTabName, aData));
1343 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1345 else
1347 ScTokenRef pCorner(new ScSingleRefToken(aData));
1348 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1351 else
1353 ScSingleRefData aDataEnd(aData);
1354 aDataEnd.IncCol(nCornerColumnCount-1);
1355 aDataEnd.IncRow(nCornerRowCount-1);
1356 ScComplexRefData r;
1357 r.Ref1=aData;
1358 r.Ref2=aDataEnd;
1359 if (bExternal)
1361 ScTokenRef pCorner(
1362 new ScExternalDoubleRefToken(nFileId, aExtTabName, r));
1363 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1365 else
1367 ScTokenRef pCorner(new ScDoubleRefToken(r));
1368 ScRefTokenHelper::join(rRefTokens, pCorner, ScAddress());
1372 return true;
1375 class ShrinkRefTokenToDataRange : std::unary_function<ScTokenRef, void>
1377 ScDocument* mpDoc;
1378 public:
1379 ShrinkRefTokenToDataRange(ScDocument* pDoc) : mpDoc(pDoc) {}
1380 void operator() (ScTokenRef& rRef)
1382 if (ScRefTokenHelper::isExternalRef(rRef))
1383 return;
1385 // Don't assume an ScDoubleRefToken if it isn't. It can be at least an
1386 // ScSingleRefToken, then there isn't anything to shrink.
1387 if (rRef->GetType() != svDoubleRef)
1388 return;
1390 ScComplexRefData& rData = rRef->GetDoubleRef();
1391 ScSingleRefData& s = rData.Ref1;
1392 ScSingleRefData& e = rData.Ref2;
1394 SCCOL nMinCol = MAXCOL, nMaxCol = 0;
1395 SCROW nMinRow = MAXROW, nMaxRow = 0;
1397 // Determine the smallest range that encompasses the data ranges of all sheets.
1398 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
1399 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
1401 SCCOL nCol1 = 0, nCol2 = MAXCOL;
1402 SCROW nRow1 = 0, nRow2 = MAXROW;
1403 mpDoc->ShrinkToDataArea(nTab, nCol1, nRow1, nCol2, nRow2);
1404 nMinCol = std::min(nMinCol, nCol1);
1405 nMinRow = std::min(nMinRow, nRow1);
1406 nMaxCol = std::max(nMaxCol, nCol2);
1407 nMaxRow = std::max(nMaxRow, nRow2);
1410 // Shrink range to the data range if applicable.
1411 if (s.Col() < nMinCol)
1412 s.SetAbsCol(nMinCol);
1413 if (s.Row() < nMinRow)
1414 s.SetAbsRow(nMinRow);
1415 if (e.Col() > nMaxCol)
1416 e.SetAbsCol(nMaxCol);
1417 if (e.Row() > nMaxRow)
1418 e.SetAbsRow(nMaxRow);
1422 void shrinkToDataRange(ScDocument* pDoc, vector<ScTokenRef>& rRefTokens)
1424 std::for_each(rRefTokens.begin(), rRefTokens.end(), ShrinkRefTokenToDataRange(pDoc));
1429 uno::Reference< chart2::data::XDataSource> SAL_CALL
1430 ScChart2DataProvider::createDataSource(
1431 const uno::Sequence< beans::PropertyValue >& aArguments )
1432 throw( lang::IllegalArgumentException, uno::RuntimeException)
1434 SolarMutexGuard aGuard;
1435 if ( ! m_pDocument )
1436 throw uno::RuntimeException();
1438 uno::Reference< chart2::data::XDataSource> xResult;
1439 bool bLabel = true;
1440 bool bCategories = false;
1441 bool bOrientCol = true;
1442 OUString aRangeRepresentation;
1443 uno::Sequence< sal_Int32 > aSequenceMapping;
1444 for(sal_Int32 i = 0; i < aArguments.getLength(); ++i)
1446 if ( aArguments[i].Name == "DataRowSource" )
1448 chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
1449 if( ! (aArguments[i].Value >>= eSource))
1451 sal_Int32 nSource(0);
1452 if( aArguments[i].Value >>= nSource )
1453 eSource = (static_cast< chart::ChartDataRowSource >( nSource ));
1455 bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
1457 else if ( aArguments[i].Name == "FirstCellAsLabel" )
1459 bLabel = ::cppu::any2bool(aArguments[i].Value);
1461 else if ( aArguments[i].Name == "HasCategories" )
1463 bCategories = ::cppu::any2bool(aArguments[i].Value);
1465 else if ( aArguments[i].Name == "CellRangeRepresentation" )
1467 aArguments[i].Value >>= aRangeRepresentation;
1469 else if ( aArguments[i].Name == "SequenceMapping" )
1471 aArguments[i].Value >>= aSequenceMapping;
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 shrinkToDataRange(m_pDocument, aRefTokens);
1485 if (bLabel)
1486 lcl_addUpperLeftCornerIfMissing(aRefTokens); //#i90669#
1488 bool bColHeaders = (bOrientCol ? bLabel : bCategories );
1489 bool bRowHeaders = (bOrientCol ? bCategories : bLabel );
1491 Chart2Positioner aChPositioner(m_pDocument, aRefTokens);
1492 aChPositioner.setHeaders(bColHeaders, bRowHeaders);
1494 const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap();
1495 if (!pChartMap)
1496 // No chart position map instance. Bail out.
1497 return xResult;
1499 ScChart2DataSource* pDS = NULL;
1500 ::std::list< Reference< chart2::data::XLabeledDataSequence > > aSeqs;
1502 // Fill Categories
1503 if( bCategories )
1505 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1506 auto_ptr< vector<ScTokenRef> > pValueTokens(NULL);
1507 SAL_WNODEPRECATED_DECLARATIONS_POP
1508 if (bOrientCol)
1509 pValueTokens.reset(pChartMap->getAllRowHeaderRanges());
1510 else
1511 pValueTokens.reset(pChartMap->getAllColHeaderRanges());
1513 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1514 auto_ptr< vector<ScTokenRef> > pLabelTokens(NULL);
1515 pLabelTokens.reset(pChartMap->getLeftUpperCornerRanges());
1516 SAL_WNODEPRECATED_DECLARATIONS_POP
1518 Reference< chart2::data::XLabeledDataSequence > xCategories = lcl_createLabeledDataSequenceFromTokens(
1519 pValueTokens, pLabelTokens, m_pDocument, this, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1520 if ( xCategories.is() )
1522 aSeqs.push_back( xCategories );
1526 // Fill Serieses (values and label)
1527 sal_Int32 nCount = bOrientCol ? pChartMap->getDataColCount() : pChartMap->getDataRowCount();
1528 for (sal_Int32 i = 0; i < nCount; ++i)
1530 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1531 auto_ptr< vector<ScTokenRef> > pValueTokens(NULL);
1532 auto_ptr< vector<ScTokenRef> > pLabelTokens(NULL);
1533 SAL_WNODEPRECATED_DECLARATIONS_POP
1534 if (bOrientCol)
1536 pValueTokens.reset(pChartMap->getDataColRanges(static_cast<SCCOL>(i)));
1537 pLabelTokens.reset(pChartMap->getColHeaderRanges(static_cast<SCCOL>(i)));
1539 else
1541 pValueTokens.reset(pChartMap->getDataRowRanges(static_cast<SCROW>(i)));
1542 pLabelTokens.reset(pChartMap->getRowHeaderRanges(static_cast<SCROW>(i)));
1544 Reference< chart2::data::XLabeledDataSequence > xChartSeries = lcl_createLabeledDataSequenceFromTokens(
1545 pValueTokens, pLabelTokens, m_pDocument, this, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
1546 if ( xChartSeries.is() && xChartSeries->getValues().is() && xChartSeries->getValues()->getData().getLength() )
1548 aSeqs.push_back( xChartSeries );
1552 pDS = new ScChart2DataSource(m_pDocument);
1553 ::std::list< Reference< chart2::data::XLabeledDataSequence > >::iterator aItr( aSeqs.begin() );
1554 ::std::list< Reference< chart2::data::XLabeledDataSequence > >::iterator aEndItr( aSeqs.end() );
1556 //reorder labeled sequences according to aSequenceMapping
1557 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aSeqVector;
1558 while(aItr != aEndItr)
1560 aSeqVector.push_back(*aItr);
1561 ++aItr;
1564 ::std::map< sal_Int32, Reference< chart2::data::XLabeledDataSequence > > aSequenceMap;
1565 for( sal_Int32 nNewIndex = 0; nNewIndex < aSequenceMapping.getLength(); nNewIndex++ )
1567 // note: assuming that the values in the sequence mapping are always non-negative
1568 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::size_type nOldIndex( static_cast< sal_uInt32 >( aSequenceMapping[nNewIndex] ) );
1569 if( nOldIndex < aSeqVector.size() )
1571 pDS->AddLabeledSequence( aSeqVector[nOldIndex] );
1572 aSeqVector[nOldIndex] = 0;
1576 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::iterator aVectorItr( aSeqVector.begin() );
1577 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::iterator aVectorEndItr( aSeqVector.end() );
1578 while(aVectorItr != aVectorEndItr)
1580 Reference< chart2::data::XLabeledDataSequence > xSeq( *aVectorItr );
1581 if ( xSeq.is() )
1583 pDS->AddLabeledSequence( xSeq );
1585 ++aVectorItr;
1588 xResult.set( pDS );
1589 return xResult;
1592 namespace
1596 * Function object to create a list of table numbers from a token list.
1598 class InsertTabNumber : public unary_function<ScTokenRef, void>
1600 public:
1601 InsertTabNumber() :
1602 mpTabNumList(new list<SCTAB>())
1606 InsertTabNumber(const InsertTabNumber& r) :
1607 mpTabNumList(r.mpTabNumList)
1611 void operator() (const ScTokenRef& pToken) const
1613 if (!ScRefTokenHelper::isRef(pToken))
1614 return;
1616 const ScSingleRefData& r = pToken->GetSingleRef();
1617 mpTabNumList->push_back(r.Tab());
1620 void getList(list<SCTAB>& rList)
1622 mpTabNumList->swap(rList);
1624 private:
1625 shared_ptr< list<SCTAB> > mpTabNumList;
1628 class RangeAnalyzer
1630 public:
1631 RangeAnalyzer();
1632 void initRangeAnalyzer( const vector<ScTokenRef>& rTokens );
1633 void analyzeRange( sal_Int32& rnDataInRows, sal_Int32& rnDataInCols,
1634 bool& rbRowSourceAmbiguous ) const;
1635 bool inSameSingleRow( RangeAnalyzer& rOther );
1636 bool inSameSingleColumn( RangeAnalyzer& rOther );
1637 SCROW getRowCount() { return mnRowCount; }
1638 SCCOL getColumnCount() { return mnColumnCount; }
1640 private:
1641 bool mbEmpty;
1642 bool mbAmbiguous;
1643 SCROW mnRowCount;
1644 SCCOL mnColumnCount;
1646 SCCOL mnStartColumn;
1647 SCROW mnStartRow;
1650 RangeAnalyzer::RangeAnalyzer()
1651 : mbEmpty(true)
1652 , mbAmbiguous(false)
1653 , mnRowCount(0)
1654 , mnColumnCount(0)
1655 , mnStartColumn(-1)
1656 , mnStartRow(-1)
1660 void RangeAnalyzer::initRangeAnalyzer( const vector<ScTokenRef>& rTokens )
1662 mnRowCount=0;
1663 mnColumnCount=0;
1664 mnStartColumn = -1;
1665 mnStartRow = -1;
1666 mbAmbiguous=false;
1667 if( rTokens.empty() )
1669 mbEmpty=true;
1670 return;
1672 mbEmpty=false;
1674 vector<ScTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
1675 for (; itr != itrEnd ; ++itr)
1677 ScTokenRef aRefToken = *itr;
1678 StackVar eVar = aRefToken->GetType();
1679 if (eVar == svDoubleRef || eVar == svExternalDoubleRef)
1681 const ScComplexRefData& r = aRefToken->GetDoubleRef();
1682 if (r.Ref1.Tab() == r.Ref2.Tab())
1684 mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(r.Ref2.Col() - r.Ref1.Col())+1));
1685 mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(r.Ref2.Row() - r.Ref1.Row())+1));
1686 if( mnStartColumn == -1 )
1688 mnStartColumn = r.Ref1.Col();
1689 mnStartRow = r.Ref1.Row();
1691 else
1693 if (mnStartColumn != r.Ref1.Col() && mnStartRow != r.Ref1.Row())
1694 mbAmbiguous=true;
1697 else
1698 mbAmbiguous=true;
1700 else if (eVar == svSingleRef || eVar == svExternalSingleRef)
1702 const ScSingleRefData& r = aRefToken->GetSingleRef();
1703 mnColumnCount = std::max<SCCOL>( mnColumnCount, 1);
1704 mnRowCount = std::max<SCROW>( mnRowCount, 1);
1705 if( mnStartColumn == -1 )
1707 mnStartColumn = r.Col();
1708 mnStartRow = r.Row();
1710 else
1712 if (mnStartColumn != r.Col() && mnStartRow != r.Row())
1713 mbAmbiguous=true;
1716 else
1717 mbAmbiguous=true;
1721 void RangeAnalyzer::analyzeRange( sal_Int32& rnDataInRows,
1722 sal_Int32& rnDataInCols,
1723 bool& rbRowSourceAmbiguous ) const
1725 if(!mbEmpty && !mbAmbiguous)
1727 if( mnRowCount==1 && mnColumnCount>1 )
1728 ++rnDataInRows;
1729 else if( mnColumnCount==1 && mnRowCount>1 )
1730 ++rnDataInCols;
1731 else if( mnRowCount>1 && mnColumnCount>1 )
1732 rbRowSourceAmbiguous = true;
1734 else if( !mbEmpty )
1735 rbRowSourceAmbiguous = true;
1738 bool RangeAnalyzer::inSameSingleRow( RangeAnalyzer& rOther )
1740 if( mnStartRow==rOther.mnStartRow &&
1741 mnRowCount==1 && rOther.mnRowCount==1 )
1742 return true;
1743 return false;
1746 bool RangeAnalyzer::inSameSingleColumn( RangeAnalyzer& rOther )
1748 if( mnStartColumn==rOther.mnStartColumn &&
1749 mnColumnCount==1 && rOther.mnColumnCount==1 )
1750 return true;
1751 return false;
1754 } //end anonymous namespace
1756 uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments(
1757 const uno::Reference< chart2::data::XDataSource >& xDataSource )
1758 throw (uno::RuntimeException)
1760 ::std::vector< beans::PropertyValue > aResult;
1761 bool bRowSourceDetected = false;
1762 bool bFirstCellAsLabel = false;
1763 bool bHasCategories = false;
1764 OUString sRangeRep;
1766 bool bHasCategoriesLabels = false;
1767 vector<ScTokenRef> aAllCategoriesValuesTokens;
1768 vector<ScTokenRef> aAllSeriesLabelTokens;
1770 chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS;
1772 vector<ScTokenRef> aAllTokens;
1774 // parse given data source and collect infos
1776 SolarMutexGuard aGuard;
1777 OSL_ENSURE( m_pDocument, "No Document -> no detectArguments" );
1778 if(!m_pDocument ||!xDataSource.is())
1779 return lcl_VectorToSequence( aResult );
1781 sal_Int32 nDataInRows = 0;
1782 sal_Int32 nDataInCols = 0;
1783 bool bRowSourceAmbiguous = false;
1785 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences());
1786 const sal_Int32 nCount( aSequences.getLength());
1787 RangeAnalyzer aPrevLabel,aPrevValues;
1788 for( sal_Int32 nIdx=0; nIdx<nCount; ++nIdx )
1790 Reference< chart2::data::XLabeledDataSequence > xLS(aSequences[nIdx]);
1791 if( xLS.is() )
1793 bool bThisIsCategories = false;
1794 if(!bHasCategories)
1796 Reference< beans::XPropertySet > xSeqProp( xLS->getValues(), uno::UNO_QUERY );
1797 OUString aRole;
1798 if( xSeqProp.is() && (xSeqProp->getPropertyValue("Role") >>= aRole) &&
1799 aRole == "categories" )
1800 bThisIsCategories = bHasCategories = true;
1803 RangeAnalyzer aLabel,aValues;
1804 // label
1805 Reference< chart2::data::XDataSequence > xLabel( xLS->getLabel());
1806 if( xLabel.is())
1808 bFirstCellAsLabel = true;
1809 vector<ScTokenRef> aTokens;
1810 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1811 ScRefTokenHelper::compileRangeRepresentation(
1812 aTokens, xLabel->getSourceRangeRepresentation(), m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1813 aLabel.initRangeAnalyzer(aTokens);
1814 vector<ScTokenRef>::const_iterator itr = aTokens.begin(), itrEnd = aTokens.end();
1815 for (; itr != itrEnd; ++itr)
1817 ScRefTokenHelper::join(aAllTokens, *itr, ScAddress());
1818 if(!bThisIsCategories)
1819 ScRefTokenHelper::join(aAllSeriesLabelTokens, *itr, ScAddress());
1821 if(bThisIsCategories)
1822 bHasCategoriesLabels=true;
1824 // values
1825 Reference< chart2::data::XDataSequence > xValues( xLS->getValues());
1826 if( xValues.is())
1828 vector<ScTokenRef> aTokens;
1829 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
1830 ScRefTokenHelper::compileRangeRepresentation(
1831 aTokens, xValues->getSourceRangeRepresentation(), m_pDocument, cSep, m_pDocument->GetGrammar(), true);
1832 aValues.initRangeAnalyzer(aTokens);
1833 vector<ScTokenRef>::const_iterator itr = aTokens.begin(), itrEnd = aTokens.end();
1834 for (; itr != itrEnd; ++itr)
1836 ScRefTokenHelper::join(aAllTokens, *itr, ScAddress());
1837 if(bThisIsCategories)
1838 ScRefTokenHelper::join(aAllCategoriesValuesTokens, *itr, ScAddress());
1841 //detect row source
1842 if(!bThisIsCategories || nCount==1) //categories might span multiple rows *and* columns, so they should be used for detection only if nothing else is available
1844 if (!bRowSourceAmbiguous)
1846 aValues.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1847 aLabel.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
1848 if (nDataInRows > 1 && nDataInCols > 1)
1849 bRowSourceAmbiguous = true;
1850 else if( !bRowSourceAmbiguous && !nDataInRows && !nDataInCols )
1852 if( aValues.inSameSingleColumn( aLabel ) )
1853 nDataInCols++;
1854 else if( aValues.inSameSingleRow( aLabel ) )
1855 nDataInRows++;
1856 else
1858 //#i86188# also detect a single column split into rows correctly
1859 if( aValues.inSameSingleColumn( aPrevValues ) )
1860 nDataInRows++;
1861 else if( aValues.inSameSingleRow( aPrevValues ) )
1862 nDataInCols++;
1863 else if( aLabel.inSameSingleColumn( aPrevLabel ) )
1864 nDataInRows++;
1865 else if( aLabel.inSameSingleRow( aPrevLabel ) )
1866 nDataInCols++;
1871 aPrevValues=aValues;
1872 aPrevLabel=aLabel;
1876 if (!bRowSourceAmbiguous)
1878 bRowSourceDetected = true;
1879 eRowSource = ( nDataInRows > 0
1880 ? chart::ChartDataRowSource_ROWS
1881 : chart::ChartDataRowSource_COLUMNS );
1883 else
1885 // set DataRowSource to the better of the two ambiguities
1886 eRowSource = ( nDataInRows > nDataInCols
1887 ? chart::ChartDataRowSource_ROWS
1888 : chart::ChartDataRowSource_COLUMNS );
1893 // TableNumberList
1895 list<SCTAB> aTableNumList;
1896 InsertTabNumber func;
1897 func = ::std::for_each(aAllTokens.begin(), aAllTokens.end(), func);
1898 func.getList(aTableNumList);
1899 aResult.push_back(
1900 beans::PropertyValue( OUString("TableNumberList"), -1,
1901 uno::makeAny( lcl_createTableNumberList( aTableNumList ) ),
1902 beans::PropertyState_DIRECT_VALUE ));
1905 // DataRowSource (calculated before)
1906 if( bRowSourceDetected )
1908 aResult.push_back(
1909 beans::PropertyValue( OUString("DataRowSource"), -1,
1910 uno::makeAny( eRowSource ), beans::PropertyState_DIRECT_VALUE ));
1913 // HasCategories
1914 if( bRowSourceDetected )
1916 aResult.push_back(
1917 beans::PropertyValue( OUString("HasCategories"), -1,
1918 uno::makeAny( bHasCategories ), beans::PropertyState_DIRECT_VALUE ));
1921 // FirstCellAsLabel
1922 if( bRowSourceDetected )
1924 aResult.push_back(
1925 beans::PropertyValue( OUString("FirstCellAsLabel"), -1,
1926 uno::makeAny( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE ));
1929 // Add the left upper corner to the range if it is missing.
1930 if (bRowSourceDetected && bFirstCellAsLabel && bHasCategories && !bHasCategoriesLabels )
1932 RangeAnalyzer aTop,aLeft;
1933 if( eRowSource==chart::ChartDataRowSource_COLUMNS )
1935 aTop.initRangeAnalyzer(aAllSeriesLabelTokens);
1936 aLeft.initRangeAnalyzer(aAllCategoriesValuesTokens);
1938 else
1940 aTop.initRangeAnalyzer(aAllCategoriesValuesTokens);
1941 aLeft.initRangeAnalyzer(aAllSeriesLabelTokens);
1943 lcl_addUpperLeftCornerIfMissing(aAllTokens, aTop.getRowCount(), aLeft.getColumnCount());//e.g. #i91212#
1946 // Get range string.
1947 lcl_convertTokensToString(sRangeRep, aAllTokens, m_pDocument);
1949 // add cell range property
1950 aResult.push_back(
1951 beans::PropertyValue( OUString("CellRangeRepresentation"), -1,
1952 uno::makeAny( sRangeRep ), beans::PropertyState_DIRECT_VALUE ));
1954 //Sequence Mapping
1955 bool bSequencesReordered = true;//todo detect this above or detect this sequence mapping cheaper ...
1956 if( bSequencesReordered && bRowSourceDetected )
1958 bool bDifferentIndexes = false;
1960 std::vector< sal_Int32 > aSequenceMappingVector;
1962 uno::Reference< chart2::data::XDataSource > xCompareDataSource;
1965 xCompareDataSource.set( this->createDataSource( lcl_VectorToSequence( aResult ) ) );
1967 catch( const lang::IllegalArgumentException & )
1969 // creation of data source to compare didn't work, so we cannot
1970 // create a sequence mapping
1973 if( xDataSource.is() && xCompareDataSource.is() )
1975 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > aOldSequences(
1976 xCompareDataSource->getDataSequences() );
1977 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aNewSequences(
1978 xDataSource->getDataSequences());
1980 OUString aOldLabel;
1981 OUString aNewLabel;
1982 OUString aOldValues;
1983 OUString aNewValues;
1984 OUString aEmpty;
1986 for( sal_Int32 nNewIndex = 0; nNewIndex < aNewSequences.getLength(); nNewIndex++ )
1988 uno::Reference< chart2::data::XLabeledDataSequence> xNew( aNewSequences[nNewIndex] );
1989 for( sal_Int32 nOldIndex = 0; nOldIndex < aOldSequences.getLength(); nOldIndex++ )
1991 uno::Reference< chart2::data::XLabeledDataSequence> xOld( aOldSequences[nOldIndex] );
1993 if( xOld.is() && xNew.is() )
1995 aOldLabel = aNewLabel = aOldValues = aNewValues = aEmpty;
1996 if( xOld.is() && xOld->getLabel().is() )
1997 aOldLabel = xOld->getLabel()->getSourceRangeRepresentation();
1998 if( xNew.is() && xNew->getLabel().is() )
1999 aNewLabel = xNew->getLabel()->getSourceRangeRepresentation();
2000 if( xOld.is() && xOld->getValues().is() )
2001 aOldValues = xOld->getValues()->getSourceRangeRepresentation();
2002 if( xNew.is() && xNew->getValues().is() )
2003 aNewValues = xNew->getValues()->getSourceRangeRepresentation();
2005 if( aOldLabel.equals(aNewLabel)
2006 && ( aOldValues.equals(aNewValues) ) )
2008 if( nOldIndex!=nNewIndex )
2009 bDifferentIndexes = true;
2010 aSequenceMappingVector.push_back(nOldIndex);
2011 break;
2018 if( bDifferentIndexes && !aSequenceMappingVector.empty() )
2020 aResult.push_back(
2021 beans::PropertyValue( OUString("SequenceMapping"), -1,
2022 uno::makeAny( lcl_VectorToSequence(aSequenceMappingVector) )
2023 , beans::PropertyState_DIRECT_VALUE ));
2027 return lcl_VectorToSequence( aResult );
2030 ::sal_Bool SAL_CALL ScChart2DataProvider::createDataSequenceByRangeRepresentationPossible( const OUString& aRangeRepresentation )
2031 throw (uno::RuntimeException)
2033 SolarMutexGuard aGuard;
2034 if( ! m_pDocument )
2035 return false;
2037 vector<ScTokenRef> aTokens;
2038 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2039 ScRefTokenHelper::compileRangeRepresentation(
2040 aTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2041 return !aTokens.empty();
2044 uno::Reference< chart2::data::XDataSequence > SAL_CALL
2045 ScChart2DataProvider::createDataSequenceByRangeRepresentation(
2046 const OUString& aRangeRepresentation )
2047 throw (lang::IllegalArgumentException,
2048 uno::RuntimeException)
2050 SolarMutexGuard aGuard;
2051 uno::Reference< chart2::data::XDataSequence > xResult;
2053 OSL_ENSURE( m_pDocument, "No Document -> no createDataSequenceByRangeRepresentation" );
2054 if(!m_pDocument || aRangeRepresentation.isEmpty())
2055 return xResult;
2057 vector<ScTokenRef> aRefTokens;
2058 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2059 ScRefTokenHelper::compileRangeRepresentation(
2060 aRefTokens, aRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2061 if (aRefTokens.empty())
2062 return xResult;
2064 shrinkToDataRange(m_pDocument, aRefTokens);
2066 // ScChart2DataSequence manages the life cycle of pRefTokens.
2067 vector<ScTokenRef>* pRefTokens = new vector<ScTokenRef>();
2068 pRefTokens->swap(aRefTokens);
2069 xResult.set(new ScChart2DataSequence(m_pDocument, this, pRefTokens, m_bIncludeHiddenCells));
2071 return xResult;
2074 uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRangeSelection()
2075 throw (uno::RuntimeException)
2077 uno::Reference< sheet::XRangeSelection > xResult;
2079 uno::Reference< frame::XModel > xModel( lcl_GetXModel( m_pDocument ));
2080 if( xModel.is())
2081 xResult.set( xModel->getCurrentController(), uno::UNO_QUERY );
2083 return xResult;
2086 sal_Bool SAL_CALL ScChart2DataProvider::createDataSequenceByFormulaTokensPossible(
2087 const Sequence<sheet::FormulaToken>& aTokens )
2088 throw (uno::RuntimeException)
2090 if (aTokens.getLength() <= 0)
2091 return false;
2093 ScTokenArray aCode;
2094 if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
2095 return false;
2097 sal_uInt16 n = aCode.GetLen();
2098 if (!n)
2099 return false;
2101 const formula::FormulaToken* pFirst = aCode.First();
2102 const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2103 for (const formula::FormulaToken* p = aCode.First(); p; p = aCode.Next())
2105 switch (p->GetType())
2107 case svSep:
2109 switch (p->GetOpCode())
2111 case ocSep:
2112 // separators are allowed.
2113 break;
2114 case ocOpen:
2115 if (p != pFirst)
2116 // open paran is allowed only as the first token.
2117 return false;
2118 break;
2119 case ocClose:
2120 if (p != pLast)
2121 // close paren is allowed only as the last token.
2122 return false;
2123 break;
2124 default:
2125 return false;
2128 break;
2129 case svSingleRef:
2130 case svDoubleRef:
2131 case svExternalSingleRef:
2132 case svExternalDoubleRef:
2133 break;
2134 default:
2135 return false;
2139 return true;
2142 Reference<chart2::data::XDataSequence> SAL_CALL
2143 ScChart2DataProvider::createDataSequenceByFormulaTokens(
2144 const Sequence<sheet::FormulaToken>& aTokens )
2145 throw (lang::IllegalArgumentException, uno::RuntimeException)
2147 Reference<chart2::data::XDataSequence> xResult;
2148 if (aTokens.getLength() <= 0)
2149 return xResult;
2151 ScTokenArray aCode;
2152 if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
2153 return xResult;
2155 sal_uInt16 n = aCode.GetLen();
2156 if (!n)
2157 return xResult;
2159 vector<ScTokenRef> aRefTokens;
2160 const formula::FormulaToken* pFirst = aCode.First();
2161 const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
2162 for (const formula::FormulaToken* p = aCode.First(); p; p = aCode.Next())
2164 switch (p->GetType())
2166 case svSep:
2168 switch (p->GetOpCode())
2170 case ocSep:
2171 // separators are allowed.
2172 break;
2173 case ocOpen:
2174 if (p != pFirst)
2175 // open paran is allowed only as the first token.
2176 throw lang::IllegalArgumentException();
2177 break;
2178 case ocClose:
2179 if (p != pLast)
2180 // close paren is allowed only as the last token.
2181 throw lang::IllegalArgumentException();
2182 break;
2183 default:
2184 throw lang::IllegalArgumentException();
2187 break;
2188 case svString:
2189 case svSingleRef:
2190 case svDoubleRef:
2191 case svExternalSingleRef:
2192 case svExternalDoubleRef:
2194 ScTokenRef pNew(static_cast<ScToken*>(p->Clone()));
2195 aRefTokens.push_back(pNew);
2197 break;
2198 default:
2199 throw lang::IllegalArgumentException();
2203 if (aRefTokens.empty())
2204 return xResult;
2206 shrinkToDataRange(m_pDocument, aRefTokens);
2208 // ScChart2DataSequence manages the life cycle of pRefTokens.
2209 vector<ScTokenRef>* pRefTokens = new vector<ScTokenRef>();
2210 pRefTokens->swap(aRefTokens);
2211 xResult.set(new ScChart2DataSequence(m_pDocument, this, pRefTokens, m_bIncludeHiddenCells));
2212 return xResult;
2215 // XRangeXMLConversion ---------------------------------------------------
2217 OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const OUString& sRangeRepresentation )
2218 throw ( uno::RuntimeException, lang::IllegalArgumentException )
2220 OUString aRet;
2221 if (!m_pDocument)
2222 return aRet;
2224 if (sRangeRepresentation.isEmpty())
2225 // Empty data range is allowed.
2226 return aRet;
2228 vector<ScTokenRef> aRefTokens;
2229 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2230 ScRefTokenHelper::compileRangeRepresentation(
2231 aRefTokens, sRangeRepresentation, m_pDocument, cSep, m_pDocument->GetGrammar(), true);
2232 if (aRefTokens.empty())
2233 throw lang::IllegalArgumentException();
2235 Tokens2RangeStringXML converter(m_pDocument);
2236 converter = ::std::for_each(aRefTokens.begin(), aRefTokens.end(), converter);
2237 converter.getString(aRet);
2239 return aRet;
2242 OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const OUString& sXMLRange )
2243 throw ( uno::RuntimeException, lang::IllegalArgumentException )
2245 const sal_Unicode cSep = ' ';
2246 const sal_Unicode cQuote = '\'';
2248 if (!m_pDocument)
2250 // #i74062# When loading flat XML, this is called before the referenced sheets are in the document,
2251 // so the conversion has to take place directly with the strings, without looking up the sheets.
2253 OUStringBuffer sRet;
2254 sal_Int32 nOffset = 0;
2255 while( nOffset >= 0 )
2257 OUString sToken;
2258 ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset, cSep, cQuote );
2259 if( nOffset >= 0 )
2261 // convert one address (remove dots)
2263 OUString aUIString(sToken);
2265 sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0, cQuote );
2266 if ( nIndex >= 0 && nIndex < aUIString.getLength() - 1 &&
2267 aUIString[nIndex + 1] == '.' )
2268 aUIString = aUIString.replaceAt( nIndex + 1, 1, "" );
2270 if ( aUIString[0] == '.' )
2271 aUIString = aUIString.copy( 1 );
2273 if( !sRet.isEmpty() )
2274 sRet.append( ';' );
2275 sRet.append( aUIString );
2279 return sRet.makeStringAndClear();
2282 OUString aRet;
2283 ScRangeStringConverter::GetStringFromXMLRangeString(aRet, sXMLRange, m_pDocument);
2284 return aRet;
2287 // DataProvider XPropertySet -------------------------------------------------
2289 uno::Reference< beans::XPropertySetInfo> SAL_CALL
2290 ScChart2DataProvider::getPropertySetInfo() throw( uno::RuntimeException)
2292 SolarMutexGuard aGuard;
2293 static uno::Reference<beans::XPropertySetInfo> aRef =
2294 new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
2295 return aRef;
2299 void SAL_CALL ScChart2DataProvider::setPropertyValue(
2300 const OUString& rPropertyName, const uno::Any& rValue)
2301 throw( beans::UnknownPropertyException,
2302 beans::PropertyVetoException,
2303 lang::IllegalArgumentException,
2304 lang::WrappedTargetException, uno::RuntimeException)
2306 if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2308 if ( !(rValue >>= m_bIncludeHiddenCells))
2309 throw lang::IllegalArgumentException();
2311 else
2312 throw beans::UnknownPropertyException();
2316 uno::Any SAL_CALL ScChart2DataProvider::getPropertyValue(
2317 const OUString& rPropertyName)
2318 throw( beans::UnknownPropertyException,
2319 lang::WrappedTargetException, uno::RuntimeException)
2321 uno::Any aRet;
2322 if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
2323 aRet <<= m_bIncludeHiddenCells;
2324 else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
2326 // This is a read-only property.
2327 aRet <<= static_cast<sal_Bool>(m_pDocument->PastingDrawFromOtherDoc());
2329 else
2330 throw beans::UnknownPropertyException();
2331 return aRet;
2335 void SAL_CALL ScChart2DataProvider::addPropertyChangeListener(
2336 const OUString& /*rPropertyName*/,
2337 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
2338 throw( beans::UnknownPropertyException,
2339 lang::WrappedTargetException, uno::RuntimeException)
2341 OSL_FAIL( "Not yet implemented" );
2345 void SAL_CALL ScChart2DataProvider::removePropertyChangeListener(
2346 const OUString& /*rPropertyName*/,
2347 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
2348 throw( beans::UnknownPropertyException,
2349 lang::WrappedTargetException, uno::RuntimeException)
2351 OSL_FAIL( "Not yet implemented" );
2355 void SAL_CALL ScChart2DataProvider::addVetoableChangeListener(
2356 const OUString& /*rPropertyName*/,
2357 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
2358 throw( beans::UnknownPropertyException,
2359 lang::WrappedTargetException, uno::RuntimeException)
2361 OSL_FAIL( "Not yet implemented" );
2365 void SAL_CALL ScChart2DataProvider::removeVetoableChangeListener(
2366 const OUString& /*rPropertyName*/,
2367 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/ )
2368 throw( beans::UnknownPropertyException,
2369 lang::WrappedTargetException, uno::RuntimeException)
2371 OSL_FAIL( "Not yet implemented" );
2374 // DataSource ================================================================
2376 ScChart2DataSource::ScChart2DataSource( ScDocument* pDoc)
2377 : m_pDocument( pDoc)
2379 if ( m_pDocument )
2380 m_pDocument->AddUnoObject( *this);
2384 ScChart2DataSource::~ScChart2DataSource()
2386 if ( m_pDocument )
2387 m_pDocument->RemoveUnoObject( *this);
2391 void ScChart2DataSource::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
2393 if ( rHint.ISA( SfxSimpleHint ) &&
2394 ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
2396 m_pDocument = NULL;
2401 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > SAL_CALL
2402 ScChart2DataSource::getDataSequences() throw ( uno::RuntimeException)
2404 SolarMutexGuard aGuard;
2406 LabeledList::const_iterator aItr(m_aLabeledSequences.begin());
2407 LabeledList::const_iterator aEndItr(m_aLabeledSequences.end());
2409 uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aRet(m_aLabeledSequences.size());
2411 sal_Int32 i = 0;
2412 while (aItr != aEndItr)
2414 aRet[i] = *aItr;
2415 ++i;
2416 ++aItr;
2419 return aRet;
2422 void ScChart2DataSource::AddLabeledSequence(const uno::Reference < chart2::data::XLabeledDataSequence >& xNew)
2424 m_aLabeledSequences.push_back(xNew);
2428 // DataSequence ==============================================================
2430 ScChart2DataSequence::Item::Item() :
2431 mfValue(0.0), mbIsValue(false)
2433 ::rtl::math::setNan(&mfValue);
2436 ScChart2DataSequence::HiddenRangeListener::HiddenRangeListener(ScChart2DataSequence& rParent) :
2437 mrParent(rParent)
2441 ScChart2DataSequence::HiddenRangeListener::~HiddenRangeListener()
2445 void ScChart2DataSequence::HiddenRangeListener::notify()
2447 mrParent.setDataChangedHint(true);
2450 ScChart2DataSequence::ScChart2DataSequence( ScDocument* pDoc,
2451 const uno::Reference < chart2::data::XDataProvider >& xDP,
2452 vector<ScTokenRef>* pTokens,
2453 bool bIncludeHiddenCells )
2454 : m_bIncludeHiddenCells( bIncludeHiddenCells)
2455 , m_nObjectId( 0 )
2456 , m_pDocument( pDoc)
2457 , m_pTokens(pTokens)
2458 , m_pRangeIndices(NULL)
2459 , m_pExtRefListener(NULL)
2460 , m_xDataProvider( xDP)
2461 , m_aPropSet(lcl_GetDataSequencePropertyMap())
2462 , m_pHiddenListener(NULL)
2463 , m_pValueListener( NULL )
2464 , m_bGotDataChangedHint(false)
2465 , m_bExtDataRebuildQueued(false)
2467 OSL_ENSURE(pTokens, "reference token list is null");
2469 if ( m_pDocument )
2471 m_pDocument->AddUnoObject( *this);
2472 m_nObjectId = m_pDocument->GetNewUnoId();
2474 // FIXME: real implementation of identifier and it's mapping to ranges.
2475 // Reuse ScChartListener?
2477 // BM: don't use names of named ranges but the UI range strings
2478 // String aStr;
2479 // rRangeList->Format( aStr, SCR_ABS_3D, m_pDocument );
2480 // m_aIdentifier = aStr;
2482 // m_aIdentifier = "ID_";
2483 // static sal_Int32 nID = 0;
2484 // m_aIdentifier += OUString::valueOf( ++nID);
2487 ScChart2DataSequence::~ScChart2DataSequence()
2489 if ( m_pDocument )
2491 m_pDocument->RemoveUnoObject( *this);
2492 if (m_pHiddenListener.get())
2494 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
2495 if (pCLC)
2496 pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
2498 StopListeningToAllExternalRefs();
2501 delete m_pValueListener;
2504 void ScChart2DataSequence::RefChanged()
2506 if( m_pValueListener && !m_aValueListeners.empty() )
2508 m_pValueListener->EndListeningAll();
2510 if( m_pDocument )
2512 ScChartListenerCollection* pCLC = NULL;
2513 if (m_pHiddenListener.get())
2515 pCLC = m_pDocument->GetChartListenerCollection();
2516 if (pCLC)
2517 pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
2520 vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
2521 for (; itr != itrEnd; ++itr)
2523 ScRange aRange;
2524 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress()))
2525 continue;
2527 m_pDocument->StartListeningArea(aRange, m_pValueListener);
2528 if (pCLC)
2529 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
2535 void ScChart2DataSequence::BuildDataCache()
2537 m_bExtDataRebuildQueued = false;
2539 if (!m_aDataArray.empty())
2540 return;
2542 if (!m_pTokens.get())
2544 OSL_FAIL("m_pTokens == NULL! Something is wrong.");
2545 return;
2548 StopListeningToAllExternalRefs();
2550 ::std::list<sal_Int32> aHiddenValues;
2551 sal_Int32 nDataCount = 0;
2552 sal_Int32 nHiddenValueCount = 0;
2554 for (vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
2555 itr != itrEnd; ++itr)
2557 if (ScRefTokenHelper::isExternalRef(*itr))
2559 nDataCount += FillCacheFromExternalRef(*itr);
2561 else
2563 ScRange aRange;
2564 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress()))
2565 continue;
2567 SCCOL nLastCol = -1;
2568 SCROW nLastRow = -1;
2569 for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
2571 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
2573 for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
2575 bool bColHidden = m_pDocument->ColHidden(nCol, nTab, NULL, &nLastCol);
2576 bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, NULL, &nLastRow);
2578 if (bColHidden || bRowHidden)
2580 // hidden cell
2581 ++nHiddenValueCount;
2582 aHiddenValues.push_back(nDataCount-1);
2584 if( !m_bIncludeHiddenCells )
2585 continue;
2588 m_aDataArray.push_back(Item());
2589 Item& rItem = m_aDataArray.back();
2590 ++nDataCount;
2592 ScAddress aAdr(nCol, nRow, nTab);
2593 rItem.maString = m_pDocument->GetString(aAdr);
2595 switch (m_pDocument->GetCellType(aAdr))
2597 case CELLTYPE_VALUE:
2598 rItem.mfValue = m_pDocument->GetValue(aAdr);
2599 rItem.mbIsValue = true;
2600 break;
2601 case CELLTYPE_FORMULA:
2603 ScFormulaCell* pFCell = m_pDocument->GetFormulaCell(aAdr);
2604 sal_uInt16 nErr = pFCell->GetErrCode();
2605 if (nErr)
2606 break;
2608 if (pFCell->IsValue())
2610 rItem.mfValue = pFCell->GetValue();
2611 rItem.mbIsValue = true;
2614 break;
2615 case CELLTYPE_EDIT:
2616 case CELLTYPE_NONE:
2617 case CELLTYPE_STRING:
2618 default:
2619 ; // do nothing
2627 // convert the hidden cell list to sequence.
2628 m_aHiddenValues.realloc(nHiddenValueCount);
2629 sal_Int32* pArr = m_aHiddenValues.getArray();
2630 ::std::list<sal_Int32>::const_iterator itr = aHiddenValues.begin(), itrEnd = aHiddenValues.end();
2631 for (;itr != itrEnd; ++itr, ++pArr)
2632 *pArr = *itr;
2634 // Clear the data series cache when the array is re-built.
2635 m_aMixedDataCache.realloc(0);
2638 void ScChart2DataSequence::RebuildDataCache()
2640 if (!m_bExtDataRebuildQueued)
2642 m_aDataArray.clear();
2643 m_pDocument->BroadcastUno(ScHint(SC_HINT_DATACHANGED, ScAddress()));
2644 m_bExtDataRebuildQueued = true;
2645 m_bGotDataChangedHint = true;
2649 sal_Int32 ScChart2DataSequence::FillCacheFromExternalRef(const ScTokenRef& pToken)
2651 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
2652 ScRange aRange;
2653 if (!ScRefTokenHelper::getRangeFromToken(aRange, pToken, ScAddress(), true))
2654 return 0;
2656 sal_uInt16 nFileId = pToken->GetIndex();
2657 OUString aTabName = pToken->GetString().getString();
2658 ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, aTabName, aRange, NULL);
2659 if (!pArray)
2660 // no external data exists for this range.
2661 return 0;
2663 // Start listening for this external document.
2664 ExternalRefListener* pExtRefListener = GetExtRefListener();
2665 pRefMgr->addLinkListener(nFileId, pExtRefListener);
2666 pExtRefListener->addFileId(nFileId);
2668 ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, aTabName, false, NULL);
2669 sal_Int32 nDataCount = 0;
2670 for (FormulaToken* p = pArray->First(); p; p = pArray->Next())
2672 // Cached external range is always represented as a single
2673 // matrix token, although that might change in the future when
2674 // we introduce a new token type to store multi-table range
2675 // data.
2677 if (p->GetType() != svMatrix)
2679 OSL_FAIL("Cached array is not a matrix token.");
2680 continue;
2683 const ScMatrix* pMat = static_cast<ScToken*>(p)->GetMatrix();
2684 SCSIZE nCSize, nRSize;
2685 pMat->GetDimensions(nCSize, nRSize);
2686 for (SCSIZE nC = 0; nC < nCSize; ++nC)
2688 for (SCSIZE nR = 0; nR < nRSize; ++nR)
2690 if (pMat->IsValue(nC, nR) || pMat->IsBoolean(nC, nR))
2692 m_aDataArray.push_back(Item());
2693 Item& rItem = m_aDataArray.back();
2694 ++nDataCount;
2696 rItem.mbIsValue = true;
2697 rItem.mfValue = pMat->GetDouble(nC, nR);
2699 SvNumberFormatter* pFormatter = m_pDocument->GetFormatTable();
2700 if (pFormatter)
2702 OUString aStr;
2703 const double fVal = rItem.mfValue;
2704 Color* pColor = NULL;
2705 sal_uInt32 nFmt = 0;
2706 if (pTable)
2708 // Get the correct format index from the cache.
2709 SCCOL nCol = aRange.aStart.Col() + static_cast<SCCOL>(nC);
2710 SCROW nRow = aRange.aStart.Row() + static_cast<SCROW>(nR);
2711 pTable->getCell(nCol, nRow, &nFmt);
2713 pFormatter->GetOutputString(fVal, nFmt, aStr, &pColor);
2714 rItem.maString = aStr;
2717 else if (pMat->IsString(nC, nR))
2719 m_aDataArray.push_back(Item());
2720 Item& rItem = m_aDataArray.back();
2721 ++nDataCount;
2723 rItem.mbIsValue = false;
2724 rItem.maString = pMat->GetString(nC, nR).getString();
2729 return nDataCount;
2732 void ScChart2DataSequence::UpdateTokensFromRanges(const ScRangeList& rRanges)
2734 if (!m_pRangeIndices.get())
2735 return;
2737 for ( size_t i = 0, nCount = rRanges.size(); i < nCount; ++i )
2739 ScTokenRef pToken;
2740 const ScRange* pRange = rRanges[i];
2741 OSL_ENSURE(pRange, "range object is NULL.");
2743 ScRefTokenHelper::getTokenFromRange(pToken, *pRange);
2744 sal_uInt32 nOrigPos = (*m_pRangeIndices)[i];
2745 (*m_pTokens)[nOrigPos] = pToken;
2748 RefChanged();
2750 // any change of the range address is broadcast to value (modify) listeners
2751 if ( !m_aValueListeners.empty() )
2752 m_bGotDataChangedHint = true;
2755 ScChart2DataSequence::ExternalRefListener* ScChart2DataSequence::GetExtRefListener()
2757 if (!m_pExtRefListener.get())
2758 m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
2760 return m_pExtRefListener.get();
2763 void ScChart2DataSequence::StopListeningToAllExternalRefs()
2765 if (!m_pExtRefListener.get())
2766 return;
2768 const boost::unordered_set<sal_uInt16>& rFileIds = m_pExtRefListener->getAllFileIds();
2769 boost::unordered_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
2770 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
2771 for (; itr != itrEnd; ++itr)
2772 pRefMgr->removeLinkListener(*itr, m_pExtRefListener.get());
2774 m_pExtRefListener.reset(NULL);
2777 void ScChart2DataSequence::CopyData(const ScChart2DataSequence& r)
2779 if (!m_pDocument)
2781 OSL_FAIL("document instance is NULL!?");
2782 return;
2785 list<Item> aDataArray(r.m_aDataArray);
2786 m_aDataArray.swap(aDataArray);
2788 m_aHiddenValues = r.m_aHiddenValues;
2789 m_aRole = r.m_aRole;
2791 if (r.m_pRangeIndices.get())
2792 m_pRangeIndices.reset(new vector<sal_uInt32>(*r.m_pRangeIndices));
2794 if (r.m_pExtRefListener.get())
2796 // Re-register all external files that the old instance was
2797 // listening to.
2799 ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
2800 m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
2801 const boost::unordered_set<sal_uInt16>& rFileIds = r.m_pExtRefListener->getAllFileIds();
2802 boost::unordered_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
2803 for (; itr != itrEnd; ++itr)
2805 pRefMgr->addLinkListener(*itr, m_pExtRefListener.get());
2806 m_pExtRefListener->addFileId(*itr);
2811 void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
2813 if ( rHint.ISA( SfxSimpleHint ) )
2815 sal_uLong nId = static_cast<const SfxSimpleHint&>(rHint).GetId();
2816 if ( nId ==SFX_HINT_DYING )
2818 m_pDocument = NULL;
2820 else if ( nId == SFX_HINT_DATACHANGED )
2822 // delayed broadcast as in ScCellRangesBase
2824 if ( m_bGotDataChangedHint && m_pDocument )
2826 m_aDataArray.clear();
2827 lang::EventObject aEvent;
2828 aEvent.Source.set((cppu::OWeakObject*)this);
2830 if( m_pDocument )
2832 for ( sal_uInt16 n=0; n<m_aValueListeners.size(); n++ )
2833 m_pDocument->AddUnoListenerCall( m_aValueListeners[n], aEvent );
2836 m_bGotDataChangedHint = false;
2839 else if ( nId == SC_HINT_CALCALL )
2841 // broadcast from DoHardRecalc - set m_bGotDataChangedHint
2842 // (SFX_HINT_DATACHANGED follows separately)
2844 if ( !m_aValueListeners.empty() )
2845 m_bGotDataChangedHint = true;
2848 else if ( rHint.ISA( ScUpdateRefHint ) )
2850 // Create a range list from the token list, have the range list
2851 // updated, and bring the change back to the token list.
2853 ScRangeList aRanges;
2854 m_pRangeIndices.reset(new vector<sal_uInt32>());
2855 vector<ScTokenRef>::const_iterator itrBeg = m_pTokens->begin(), itrEnd = m_pTokens->end();
2856 for (vector<ScTokenRef>::const_iterator itr = itrBeg ;itr != itrEnd; ++itr)
2858 if (!ScRefTokenHelper::isExternalRef(*itr))
2860 ScRange aRange;
2861 ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress());
2862 aRanges.Append(aRange);
2863 sal_uInt32 nPos = distance(itrBeg, itr);
2864 m_pRangeIndices->push_back(nPos);
2868 OSL_ENSURE(m_pRangeIndices->size() == static_cast<size_t>(aRanges.size()),
2869 "range list and range index list have different sizes.");
2871 SAL_WNODEPRECATED_DECLARATIONS_PUSH
2872 auto_ptr<ScRangeList> pUndoRanges;
2873 SAL_WNODEPRECATED_DECLARATIONS_POP
2874 if ( m_pDocument->HasUnoRefUndo() )
2875 pUndoRanges.reset(new ScRangeList(aRanges));
2877 const ScUpdateRefHint& rRef = (const ScUpdateRefHint&)rHint;
2878 bool bChanged = aRanges.UpdateReference(
2879 rRef.GetMode(), m_pDocument, rRef.GetRange(), rRef.GetDx(), rRef.GetDy(), rRef.GetDz());
2881 if (bChanged)
2883 OSL_ENSURE(m_pRangeIndices->size() == aRanges.size(),
2884 "range list and range index list have different sizes after the reference update.");
2886 // Bring the change back from the range list to the token list.
2887 UpdateTokensFromRanges(aRanges);
2889 if (pUndoRanges.get())
2890 m_pDocument->AddUnoRefChange(m_nObjectId, *pUndoRanges);
2893 else if ( rHint.ISA( ScUnoRefUndoHint ) )
2895 const ScUnoRefUndoHint& rUndoHint = static_cast<const ScUnoRefUndoHint&>(rHint);
2899 if (rUndoHint.GetObjectId() != m_nObjectId)
2900 break;
2902 // The hint object provides the old ranges. Restore the old state
2903 // from these ranges.
2905 if (!m_pRangeIndices.get() || m_pRangeIndices->empty())
2907 OSL_FAIL(" faulty range indices");
2908 break;
2911 const ScRangeList& rRanges = rUndoHint.GetRanges();
2913 size_t nCount = rRanges.size();
2914 if (nCount != m_pRangeIndices->size())
2916 OSL_FAIL("range count and range index count differ.");
2917 break;
2920 UpdateTokensFromRanges(rRanges);
2922 while (false);
2927 IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, SfxHint*, pHint )
2929 if ( m_pDocument && pHint && pHint->ISA( SfxSimpleHint ) &&
2930 ((const SfxSimpleHint*)pHint)->GetId() & SC_HINT_DATACHANGED)
2932 // This may be called several times for a single change, if several formulas
2933 // in the range are notified. So only a flag is set that is checked when
2934 // SFX_HINT_DATACHANGED is received.
2936 setDataChangedHint(true);
2938 return 0;
2941 // ----------------------------------------------------------------------------
2943 ScChart2DataSequence::ExternalRefListener::ExternalRefListener(
2944 ScChart2DataSequence& rParent, ScDocument* pDoc) :
2945 ScExternalRefManager::LinkListener(),
2946 mrParent(rParent),
2947 mpDoc(pDoc)
2951 ScChart2DataSequence::ExternalRefListener::~ExternalRefListener()
2953 if (!mpDoc || mpDoc->IsInDtorClear())
2954 // The document is being destroyed. Do nothing.
2955 return;
2957 // Make sure to remove all pointers to this object.
2958 mpDoc->GetExternalRefManager()->removeLinkListener(this);
2961 void ScChart2DataSequence::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
2963 switch (eType)
2965 case ScExternalRefManager::LINK_MODIFIED:
2967 if (maFileIds.count(nFileId))
2968 // We are listening to this external document.
2969 mrParent.RebuildDataCache();
2971 break;
2972 case ScExternalRefManager::LINK_BROKEN:
2973 removeFileId(nFileId);
2974 break;
2978 void ScChart2DataSequence::ExternalRefListener::addFileId(sal_uInt16 nFileId)
2980 maFileIds.insert(nFileId);
2983 void ScChart2DataSequence::ExternalRefListener::removeFileId(sal_uInt16 nFileId)
2985 maFileIds.erase(nFileId);
2988 const boost::unordered_set<sal_uInt16>& ScChart2DataSequence::ExternalRefListener::getAllFileIds()
2990 return maFileIds;
2993 // ----------------------------------------------------------------------------
2995 uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
2996 throw ( uno::RuntimeException)
2998 SolarMutexGuard aGuard;
2999 if ( !m_pDocument)
3000 throw uno::RuntimeException();
3002 BuildDataCache();
3004 if (!m_aMixedDataCache.getLength())
3006 // Build a cache for the 1st time...
3008 sal_Int32 nCount = m_aDataArray.size();
3009 m_aMixedDataCache.realloc(nCount);
3010 uno::Any* pArr = m_aMixedDataCache.getArray();
3011 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3012 for (; itr != itrEnd; ++itr, ++pArr)
3014 if (itr->mbIsValue)
3015 *pArr <<= itr->mfValue;
3016 else
3017 *pArr <<= itr->maString;
3020 return m_aMixedDataCache;
3023 // XNumericalDataSequence --------------------------------------------------
3025 uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData()
3026 throw ( uno::RuntimeException)
3028 SolarMutexGuard aGuard;
3029 if ( !m_pDocument)
3030 throw uno::RuntimeException();
3032 BuildDataCache();
3034 double fNAN;
3035 ::rtl::math::setNan(&fNAN);
3037 sal_Int32 nCount = m_aDataArray.size();
3038 uno::Sequence<double> aSeq(nCount);
3039 double* pArr = aSeq.getArray();
3040 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3041 for (; itr != itrEnd; ++itr, ++pArr)
3042 *pArr = itr->mbIsValue ? itr->mfValue : fNAN;
3044 return aSeq;
3047 // XTextualDataSequence --------------------------------------------------
3049 uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::getTextualData( ) throw (uno::RuntimeException)
3051 SolarMutexGuard aGuard;
3052 uno::Sequence<OUString> aSeq;
3053 if ( !m_pDocument )
3054 throw uno::RuntimeException();
3056 BuildDataCache();
3058 sal_Int32 nCount = m_aDataArray.size();
3059 if ( nCount > 0 )
3061 aSeq = uno::Sequence<OUString>(nCount);
3062 OUString* pArr = aSeq.getArray();
3063 ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
3064 for(; itr != itrEnd; ++itr, ++pArr)
3065 *pArr = itr->maString;
3067 else if ( m_pTokens.get() && m_pTokens->front() )
3069 if( m_pTokens->front()->GetType() == svString )
3071 aSeq = uno::Sequence<OUString>(1);
3072 aSeq[0] = m_pTokens->front()->GetString().getString();
3076 return aSeq;
3079 OUString SAL_CALL ScChart2DataSequence::getSourceRangeRepresentation()
3080 throw ( uno::RuntimeException)
3082 SolarMutexGuard aGuard;
3083 OUString aStr;
3084 OSL_ENSURE( m_pDocument, "No Document -> no SourceRangeRepresentation" );
3085 if (m_pDocument && m_pTokens.get())
3086 lcl_convertTokensToString(aStr, *m_pTokens, m_pDocument);
3088 return aStr;
3091 namespace {
3094 * This function object is used to accumulatively count the numbers of
3095 * columns and rows in all reference tokens.
3097 class AccumulateRangeSize : public unary_function<ScTokenRef, void>
3099 public:
3100 AccumulateRangeSize() :
3101 mnCols(0), mnRows(0) {}
3103 AccumulateRangeSize(const AccumulateRangeSize& r) :
3104 mnCols(r.mnCols), mnRows(r.mnRows) {}
3106 void operator() (const ScTokenRef& pToken)
3108 ScRange r;
3109 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3110 ScRefTokenHelper::getRangeFromToken(r, pToken, ScAddress(), bExternal);
3111 r.Justify();
3112 mnCols += r.aEnd.Col() - r.aStart.Col() + 1;
3113 mnRows += r.aEnd.Row() - r.aStart.Row() + 1;
3116 SCCOL getCols() const { return mnCols; }
3117 SCROW getRows() const { return mnRows; }
3118 private:
3119 SCCOL mnCols;
3120 SCROW mnRows;
3124 * This function object is used to generate label strings from a list of
3125 * reference tokens.
3127 class GenerateLabelStrings : public unary_function<ScTokenRef, void>
3129 public:
3130 GenerateLabelStrings(sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) :
3131 mpLabels(new Sequence<OUString>(nSize)),
3132 meOrigin(eOrigin),
3133 mnCount(0),
3134 mbColumn(bColumn) {}
3136 GenerateLabelStrings(const GenerateLabelStrings& r) :
3137 mpLabels(r.mpLabels),
3138 meOrigin(r.meOrigin),
3139 mnCount(r.mnCount),
3140 mbColumn(r.mbColumn) {}
3142 void operator() (const ScTokenRef& pToken)
3144 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
3145 ScRange aRange;
3146 ScRefTokenHelper::getRangeFromToken(aRange, pToken, ScAddress(), bExternal);
3147 OUString* pArr = mpLabels->getArray();
3148 if (mbColumn)
3150 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
3152 if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3154 OUString aString = ScGlobal::GetRscString(STR_COLUMN);
3155 aString += " ";
3156 ScAddress aPos( nCol, 0, 0 );
3157 OUString aColStr(aPos.Format(SCA_VALID_COL, NULL));
3158 aString += aColStr;
3159 pArr[mnCount] = aString;
3161 else //only indices for categories
3162 pArr[mnCount] = OUString::number( mnCount+1 );
3163 ++mnCount;
3166 else
3168 for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
3170 if (meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
3172 OUString aString = ScGlobal::GetRscString(STR_ROW) +
3173 " " + OUString::number( nRow+1 );
3174 pArr[mnCount] = aString;
3176 else //only indices for categories
3177 pArr[mnCount] = OUString::number( mnCount+1 );
3178 ++mnCount;
3183 Sequence<OUString> getLabels() const { return *mpLabels; }
3185 private:
3186 shared_ptr< Sequence<OUString> > mpLabels;
3187 chart2::data::LabelOrigin meOrigin;
3188 sal_Int32 mnCount;
3189 bool mbColumn;
3194 uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
3195 throw (uno::RuntimeException)
3197 SolarMutexGuard aGuard;
3198 if ( !m_pDocument)
3199 throw uno::RuntimeException();
3201 if (!m_pTokens.get())
3202 return Sequence<OUString>();
3204 // Determine the total size of all ranges.
3205 AccumulateRangeSize func;
3206 func = ::std::for_each(m_pTokens->begin(), m_pTokens->end(), func);
3207 SCCOL nCols = func.getCols();
3208 SCROW nRows = func.getRows();
3210 // Detemine whether this is column-major or row-major.
3211 bool bColumn = true;
3212 if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
3213 (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
3215 if (nRows > nCols)
3217 if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
3218 bColumn = true;
3219 else
3220 bColumn = false;
3222 else if (nCols > nRows)
3224 if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
3225 bColumn = false;
3226 else
3227 bColumn = true;
3229 else
3230 return Sequence<OUString>();
3233 // Generate label strings based on the info so far.
3234 sal_Int32 nCount = bColumn ? nCols : nRows;
3235 GenerateLabelStrings genLabels(nCount, eOrigin, bColumn);
3236 genLabels = ::std::for_each(m_pTokens->begin(), m_pTokens->end(), genLabels);
3237 Sequence<OUString> aSeq = genLabels.getLabels();
3239 return aSeq;
3242 namespace {
3244 sal_uLong getDisplayNumberFormat(ScDocument* pDoc, const ScAddress& rPos)
3246 sal_uLong nFormat = pDoc->GetNumberFormat(rPos); // original format from cell.
3247 return nFormat;
3252 ::sal_Int32 SAL_CALL ScChart2DataSequence::getNumberFormatKeyByIndex( ::sal_Int32 nIndex )
3253 throw (lang::IndexOutOfBoundsException,
3254 uno::RuntimeException)
3256 // index -1 means a heuristic value for the entire sequence
3257 bool bGetSeriesFormat = (nIndex == -1);
3259 SolarMutexGuard aGuard;
3260 if ( !m_pDocument || !m_pTokens.get())
3261 return 0;
3263 // TODO: Handle external references too.
3265 sal_Int32 nCount = 0;
3267 ScRangeList aRanges;
3268 ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens, ScAddress());
3269 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
3271 ScRange* p = aRanges[i];
3272 for (SCTAB nTab = p->aStart.Tab(); nTab <= p->aEnd.Tab(); ++nTab)
3274 for (SCCOL nCol = p->aStart.Col(); nCol <= p->aEnd.Col(); ++nCol)
3276 if (!m_bIncludeHiddenCells)
3278 // Skip hidden columns.
3279 SCCOL nLastCol = -1;
3280 bool bColHidden = m_pDocument->ColHidden(nCol, nTab, NULL, &nLastCol);
3281 if (bColHidden)
3283 nCol = nLastCol;
3284 continue;
3288 for (SCROW nRow = p->aStart.Row(); nRow <= p->aEnd.Row(); ++nRow)
3290 if (!m_bIncludeHiddenCells)
3292 // Skip hidden rows.
3293 SCROW nLastRow = -1;
3294 bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, NULL, &nLastRow);
3295 if (bRowHidden)
3297 nRow = nLastRow;
3298 continue;
3302 ScAddress aPos(nCol, nRow, nTab);
3304 if( bGetSeriesFormat )
3306 // TODO: use nicer heuristic
3307 // return format of first non-empty cell
3308 ScRefCellValue aCell;
3309 aCell.assign(*m_pDocument, aPos);
3310 if (!aCell.isEmpty())
3311 return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, aPos));
3313 else if( nCount == nIndex )
3315 return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, aPos));
3317 ++nCount;
3322 return 0;
3325 // XCloneable ================================================================
3327 uno::Reference< util::XCloneable > SAL_CALL ScChart2DataSequence::createClone()
3328 throw (uno::RuntimeException)
3330 SolarMutexGuard aGuard;
3332 SAL_WNODEPRECATED_DECLARATIONS_PUSH
3333 auto_ptr< vector<ScTokenRef> > pTokensNew;
3334 SAL_WNODEPRECATED_DECLARATIONS_POP
3335 if (m_pTokens.get())
3337 // Clone tokens.
3338 pTokensNew.reset(new vector<ScTokenRef>);
3339 pTokensNew->reserve(m_pTokens->size());
3340 vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
3341 for (; itr != itrEnd; ++itr)
3343 ScTokenRef p(static_cast<ScToken*>((*itr)->Clone()));
3344 pTokensNew->push_back(p);
3348 SAL_WNODEPRECATED_DECLARATIONS_PUSH
3349 auto_ptr<ScChart2DataSequence> p(new ScChart2DataSequence(m_pDocument, m_xDataProvider, pTokensNew.release(), m_bIncludeHiddenCells));
3350 SAL_WNODEPRECATED_DECLARATIONS_POP
3351 p->CopyData(*this);
3352 Reference< util::XCloneable > xClone(p.release());
3354 return xClone;
3357 // XModifyBroadcaster ========================================================
3359 void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3360 throw (uno::RuntimeException)
3362 // like ScCellRangesBase::addModifyListener
3363 SolarMutexGuard aGuard;
3364 if (!m_pTokens.get() || m_pTokens->empty())
3365 return;
3367 ScRangeList aRanges;
3368 ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens, ScAddress());
3369 uno::Reference<util::XModifyListener> *pObj =
3370 new uno::Reference<util::XModifyListener>( aListener );
3371 m_aValueListeners.push_back( pObj );
3373 if ( m_aValueListeners.size() == 1 )
3375 if (!m_pValueListener)
3376 m_pValueListener = new ScLinkListener( LINK( this, ScChart2DataSequence, ValueListenerHdl ) );
3378 if (!m_pHiddenListener.get())
3379 m_pHiddenListener.reset(new HiddenRangeListener(*this));
3381 if( m_pDocument )
3383 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
3384 vector<ScTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
3385 for (; itr != itrEnd; ++itr)
3387 ScRange aRange;
3388 if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr, ScAddress()))
3389 continue;
3391 m_pDocument->StartListeningArea( aRange, m_pValueListener );
3392 if (pCLC)
3393 pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
3397 acquire(); // don't lose this object (one ref for all listeners)
3401 void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
3402 throw (uno::RuntimeException)
3404 // like ScCellRangesBase::removeModifyListener
3406 SolarMutexGuard aGuard;
3407 if (!m_pTokens.get() || m_pTokens->empty())
3408 return;
3410 acquire(); // in case the listeners have the last ref - released below
3412 sal_uInt16 nCount = m_aValueListeners.size();
3413 for ( sal_uInt16 n=nCount; n--; )
3415 uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
3416 if ( rObj == aListener )
3418 m_aValueListeners.erase( m_aValueListeners.begin() + n );
3420 if ( m_aValueListeners.empty() )
3422 if (m_pValueListener)
3423 m_pValueListener->EndListeningAll();
3425 if (m_pHiddenListener.get() && m_pDocument)
3427 ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
3428 if (pCLC)
3429 pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
3432 release(); // release the ref for the listeners
3435 break;
3439 release(); // might delete this object
3442 // DataSequence XPropertySet -------------------------------------------------
3444 uno::Reference< beans::XPropertySetInfo> SAL_CALL
3445 ScChart2DataSequence::getPropertySetInfo() throw( uno::RuntimeException)
3447 SolarMutexGuard aGuard;
3448 static uno::Reference<beans::XPropertySetInfo> aRef =
3449 new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
3450 return aRef;
3454 void SAL_CALL ScChart2DataSequence::setPropertyValue(
3455 const OUString& rPropertyName, const uno::Any& rValue)
3456 throw( beans::UnknownPropertyException,
3457 beans::PropertyVetoException,
3458 lang::IllegalArgumentException,
3459 lang::WrappedTargetException, uno::RuntimeException)
3461 if ( rPropertyName == SC_UNONAME_ROLE )
3463 if ( !(rValue >>= m_aRole))
3464 throw lang::IllegalArgumentException();
3466 else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3468 sal_Bool bOldValue = m_bIncludeHiddenCells;
3469 if ( !(rValue >>= m_bIncludeHiddenCells))
3470 throw lang::IllegalArgumentException();
3471 if( bOldValue != m_bIncludeHiddenCells )
3472 m_aDataArray.clear();//data array is dirty now
3474 else
3475 throw beans::UnknownPropertyException();
3476 // TODO: support optional properties
3480 uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue(
3481 const OUString& rPropertyName)
3482 throw( beans::UnknownPropertyException,
3483 lang::WrappedTargetException, uno::RuntimeException)
3485 uno::Any aRet;
3486 if ( rPropertyName == SC_UNONAME_ROLE )
3487 aRet <<= m_aRole;
3488 else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
3489 aRet <<= m_bIncludeHiddenCells;
3490 else if ( rPropertyName == SC_UNONAME_HIDDENVALUES )
3492 // This property is read-only thus cannot be set externally via
3493 // setPropertyValue(...).
3494 BuildDataCache();
3495 aRet <<= m_aHiddenValues;
3497 else
3498 throw beans::UnknownPropertyException();
3499 // TODO: support optional properties
3500 return aRet;
3504 void SAL_CALL ScChart2DataSequence::addPropertyChangeListener(
3505 const OUString& /*rPropertyName*/,
3506 const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
3507 throw( beans::UnknownPropertyException,
3508 lang::WrappedTargetException, uno::RuntimeException)
3510 // FIXME: real implementation
3511 OSL_FAIL( "Not yet implemented" );
3515 void SAL_CALL ScChart2DataSequence::removePropertyChangeListener(
3516 const OUString& /*rPropertyName*/,
3517 const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
3518 throw( beans::UnknownPropertyException,
3519 lang::WrappedTargetException, uno::RuntimeException)
3521 // FIXME: real implementation
3522 OSL_FAIL( "Not yet implemented" );
3526 void SAL_CALL ScChart2DataSequence::addVetoableChangeListener(
3527 const OUString& /*rPropertyName*/,
3528 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3529 throw( beans::UnknownPropertyException,
3530 lang::WrappedTargetException, uno::RuntimeException)
3532 // FIXME: real implementation
3533 OSL_FAIL( "Not yet implemented" );
3537 void SAL_CALL ScChart2DataSequence::removeVetoableChangeListener(
3538 const OUString& /*rPropertyName*/,
3539 const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
3540 throw( beans::UnknownPropertyException,
3541 lang::WrappedTargetException, uno::RuntimeException)
3543 // FIXME: real implementation
3544 OSL_FAIL( "Not yet implemented" );
3547 void ScChart2DataSequence::setDataChangedHint(bool b)
3549 m_bGotDataChangedHint = b;
3552 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */