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