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