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