Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <memory>
21 : #include <algorithm>
22 :
23 : #include <com/sun/star/chart/ChartDataRowSource.hpp>
24 : #include <com/sun/star/chart2/data/LabelOrigin.hpp>
25 : #include <cppuhelper/interfacecontainer.hxx>
26 : #include <osl/mutex.hxx>
27 : #include <vcl/svapp.hxx>
28 : #include <svl/zforlist.hxx> // SvNumberFormatter
29 : #include <svx/charthelper.hxx>
30 :
31 : #include <XMLRangeHelper.hxx>
32 : #include <unochart.hxx>
33 : #include <swtable.hxx>
34 : #include <unoprnms.hxx>
35 : #include <unomap.hxx>
36 : #include <unomid.h>
37 : #include <unocrsr.hxx>
38 : #include <unotbl.hxx>
39 : #include <doc.hxx>
40 : #include <frmfmt.hxx>
41 : #include <docsh.hxx>
42 : #include <ndole.hxx>
43 : #include <swtypes.hxx>
44 : #include <unocore.hrc>
45 : #include <docary.hxx>
46 : #include <comphelper/servicehelper.hxx>
47 : #include <comphelper/string.hxx>
48 :
49 : #define SN_DATA_PROVIDER "com.sun.star.chart2.data.DataProvider"
50 : #define SN_DATA_SOURCE "com.sun.star.chart2.data.DataSource"
51 : #define SN_DATA_SEQUENCE "com.sun.star.chart2.data.DataSequence"
52 : #define SN_LABELED_DATA_SEQUENCE "com.sun.star.chart2.data.LabeledDataSequence"
53 :
54 : using namespace ::com::sun::star;
55 : using ::rtl::OUString;
56 :
57 : // from unotbl.cxx
58 : extern void sw_GetCellPosition( const String &rCellName, sal_Int32 &rColumn, sal_Int32 &rRow);
59 : extern String sw_GetCellName( sal_Int32 nColumn, sal_Int32 nRow );
60 : extern int sw_CompareCellsByColFirst( const String &rCellName1, const String &rCellName2 );
61 : extern int sw_CompareCellsByRowFirst( const String &rCellName1, const String &rCellName2 );
62 : extern int sw_CompareCellRanges(
63 : const String &rRange1StartCell, const String &rRange1EndCell,
64 : const String &rRange2StartCell, const String &rRange2EndCell,
65 : sal_Bool bCmpColsFirst );
66 : extern void sw_NormalizeRange( String &rCell1, String &rCell2 );
67 :
68 : //static
69 0 : void SwChartHelper::DoUpdateAllCharts( SwDoc* pDoc )
70 : {
71 0 : if (!pDoc)
72 0 : return;
73 :
74 0 : uno::Reference< frame::XModel > xRes;
75 :
76 : SwOLENode *pONd;
77 : SwStartNode *pStNd;
78 0 : SwNodeIndex aIdx( *pDoc->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
79 0 : while( 0 != (pStNd = aIdx.GetNode().GetStartNode()) )
80 : {
81 0 : ++aIdx;
82 0 : if (0 != ( pONd = aIdx.GetNode().GetOLENode() ) &&
83 0 : ChartHelper::IsChart( pONd->GetOLEObj().GetObject() ) )
84 : {
85 : // Load the object and set modified
86 :
87 0 : uno::Reference < embed::XEmbeddedObject > xIP = pONd->GetOLEObj().GetOleRef();
88 0 : if ( svt::EmbeddedObjectRef::TryRunningState( xIP ) )
89 : {
90 : try
91 : {
92 0 : uno::Reference< util::XModifiable > xModif( xIP->getComponent(), uno::UNO_QUERY_THROW );
93 0 : xModif->setModified( sal_True );
94 : }
95 0 : catch ( uno::Exception& )
96 : {
97 : }
98 :
99 0 : }
100 : }
101 0 : aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 );
102 0 : }
103 : }
104 :
105 94 : SwChartLockController_Helper::SwChartLockController_Helper( SwDoc *pDocument ) :
106 : pDoc( pDocument )
107 94 : , bIsLocked( false )
108 : {
109 94 : aUnlockTimer.SetTimeout( 1500 );
110 94 : aUnlockTimer.SetTimeoutHdl( LINK( this, SwChartLockController_Helper, DoUnlockAllCharts ));
111 94 : }
112 :
113 188 : SwChartLockController_Helper::~SwChartLockController_Helper()
114 : {
115 94 : if (pDoc) // still connected?
116 0 : Disconnect();
117 94 : }
118 :
119 0 : void SwChartLockController_Helper::StartOrContinueLocking()
120 : {
121 0 : if (!bIsLocked)
122 0 : LockAllCharts();
123 0 : aUnlockTimer.Start(); // start or continue time of locking
124 0 : }
125 :
126 94 : void SwChartLockController_Helper::Disconnect()
127 : {
128 94 : aUnlockTimer.Stop();
129 94 : UnlockAllCharts();
130 94 : pDoc = 0;
131 94 : }
132 :
133 94 : void SwChartLockController_Helper::LockUnlockAllCharts( sal_Bool bLock )
134 : {
135 94 : if (!pDoc)
136 94 : return;
137 :
138 94 : const SwFrmFmts& rTblFmts = *pDoc->GetTblFrmFmts();
139 138 : for( sal_uInt16 n = 0; n < rTblFmts.size(); ++n )
140 : {
141 : SwTable* pTmpTbl;
142 : const SwTableNode* pTblNd;
143 44 : SwFrmFmt* pFmt = rTblFmts[ n ];
144 :
145 88 : if( 0 != ( pTmpTbl = SwTable::FindTable( pFmt ) ) &&
146 : 0 != ( pTblNd = pTmpTbl->GetTableNode() ) &&
147 44 : pTblNd->GetNodes().IsDocNodes() )
148 : {
149 44 : uno::Reference< frame::XModel > xRes;
150 : SwOLENode *pONd;
151 : SwStartNode *pStNd;
152 44 : SwNodeIndex aIdx( *pDoc->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
153 208 : while( 0 != (pStNd = aIdx.GetNode().GetStartNode()) )
154 : {
155 120 : ++aIdx;
156 120 : if (0 != ( pONd = aIdx.GetNode().GetOLENode() ) &&
157 0 : pONd->GetChartTblName().Len() > 0 /* is chart object? */)
158 : {
159 0 : uno::Reference < embed::XEmbeddedObject > xIP = pONd->GetOLEObj().GetOleRef();
160 0 : if ( svt::EmbeddedObjectRef::TryRunningState( xIP ) )
161 : {
162 0 : xRes = uno::Reference < frame::XModel >( xIP->getComponent(), uno::UNO_QUERY );
163 0 : if (xRes.is())
164 : {
165 0 : if (bLock)
166 0 : xRes->lockControllers();
167 : else
168 0 : xRes->unlockControllers();
169 : }
170 0 : }
171 : }
172 120 : aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 );
173 44 : }
174 : }
175 : }
176 :
177 94 : bIsLocked = bLock;
178 : }
179 :
180 0 : IMPL_LINK( SwChartLockController_Helper, DoUnlockAllCharts, Timer *, /*pTimer*/ )
181 : {
182 0 : UnlockAllCharts();
183 0 : return 0;
184 : }
185 :
186 0 : static osl::Mutex & GetChartMutex()
187 : {
188 0 : static osl::Mutex aMutex;
189 0 : return aMutex;
190 : }
191 :
192 0 : static void LaunchModifiedEvent(
193 : ::cppu::OInterfaceContainerHelper &rICH,
194 : const uno::Reference< uno::XInterface > &rxI )
195 : {
196 0 : lang::EventObject aEvtObj( rxI );
197 0 : cppu::OInterfaceIteratorHelper aIt( rICH );
198 0 : while (aIt.hasMoreElements())
199 : {
200 0 : uno::Reference< util::XModifyListener > xRef( aIt.next(), uno::UNO_QUERY );
201 0 : if (xRef.is())
202 0 : xRef->modified( aEvtObj );
203 0 : }
204 0 : }
205 :
206 : // rCellRangeName needs to be of one of the following formats:
207 : // - e.g. "A2:E5" or
208 : // - e.g. "Table1.A2:E5"
209 0 : bool FillRangeDescriptor(
210 : SwRangeDescriptor &rDesc,
211 : const String &rCellRangeName )
212 : {
213 0 : xub_StrLen nToken = STRING_NOTFOUND == rCellRangeName.Search('.') ? 0 : 1;
214 0 : String aCellRangeNoTableName( rCellRangeName.GetToken( nToken, '.' ) );
215 0 : String aTLName( aCellRangeNoTableName.GetToken(0, ':') ); // name of top left cell
216 0 : String aBRName( aCellRangeNoTableName.GetToken(1, ':') ); // name of bottom right cell
217 0 : if(!aTLName.Len() || !aBRName.Len())
218 0 : return false;
219 :
220 0 : rDesc.nTop = rDesc.nLeft = rDesc.nBottom = rDesc.nRight = -1;
221 0 : sw_GetCellPosition( aTLName, rDesc.nLeft, rDesc.nTop );
222 0 : sw_GetCellPosition( aBRName, rDesc.nRight, rDesc.nBottom );
223 0 : rDesc.Normalize();
224 : OSL_ENSURE( rDesc.nTop != -1 &&
225 : rDesc.nLeft != -1 &&
226 : rDesc.nBottom != -1 &&
227 : rDesc.nRight != -1,
228 : "failed to get range descriptor" );
229 : OSL_ENSURE( rDesc.nTop <= rDesc.nBottom && rDesc.nLeft <= rDesc.nRight,
230 : "invalid range descriptor");
231 0 : return true;
232 : }
233 :
234 0 : static String GetCellRangeName( SwFrmFmt &rTblFmt, SwUnoCrsr &rTblCrsr )
235 : {
236 0 : String aRes;
237 :
238 : //!! see also SwXTextTableCursor::getRangeName
239 :
240 0 : SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(&rTblCrsr);
241 0 : if (!pUnoTblCrsr)
242 0 : return String();
243 0 : pUnoTblCrsr->MakeBoxSels();
244 :
245 : const SwStartNode* pStart;
246 0 : const SwTableBox* pStartBox = 0;
247 0 : const SwTableBox* pEndBox = 0;
248 :
249 0 : pStart = pUnoTblCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
250 0 : if (pStart)
251 : {
252 0 : const SwTable* pTable = SwTable::FindTable( &rTblFmt );
253 0 : pEndBox = pTable->GetTblBox( pStart->GetIndex());
254 0 : aRes = pEndBox->GetName();
255 :
256 0 : if(pUnoTblCrsr->HasMark())
257 : {
258 0 : pStart = pUnoTblCrsr->GetMark()->nNode.GetNode().FindTableBoxStartNode();
259 0 : pStartBox = pTable->GetTblBox( pStart->GetIndex());
260 : }
261 : OSL_ENSURE( pStartBox, "start box not found" );
262 : OSL_ENSURE( pEndBox, "end box not found" );
263 : // need to switch start and end?
264 0 : if (*pUnoTblCrsr->GetPoint() < *pUnoTblCrsr->GetMark())
265 : {
266 0 : const SwTableBox* pTmpBox = pStartBox;
267 0 : pStartBox = pEndBox;
268 0 : pEndBox = pTmpBox;
269 : }
270 :
271 0 : aRes = pStartBox->GetName();
272 0 : aRes += (sal_Unicode)':';
273 0 : if (pEndBox)
274 0 : aRes += pEndBox->GetName();
275 : else
276 0 : aRes += pStartBox->GetName();
277 : }
278 :
279 0 : return aRes;
280 : }
281 :
282 0 : static String GetRangeRepFromTableAndCells( const String &rTableName,
283 : const String &rStartCell, const String &rEndCell,
284 : sal_Bool bForceEndCellName )
285 : {
286 : OSL_ENSURE( rTableName.Len(), "table name missing" );
287 : OSL_ENSURE( rStartCell.Len(), "cell name missing" );
288 0 : String aRes( rTableName );
289 0 : aRes += (sal_Unicode) '.';
290 0 : aRes += rStartCell;
291 :
292 0 : if (rEndCell.Len())
293 : {
294 0 : aRes += (sal_Unicode) ':';
295 0 : aRes += rEndCell;
296 : }
297 0 : else if (bForceEndCellName)
298 : {
299 0 : aRes += (sal_Unicode) ':';
300 0 : aRes += rStartCell;
301 : }
302 :
303 0 : return aRes;
304 : }
305 :
306 0 : static bool GetTableAndCellsFromRangeRep(
307 : const OUString &rRangeRepresentation,
308 : String &rTblName,
309 : String &rStartCell,
310 : String &rEndCell,
311 : bool bSortStartEndCells = true )
312 : {
313 : // parse range representation for table name and cell/range names
314 : // accepted format sth like: "Table1.A2:C5" , "Table2.A2.1:B3.2"
315 0 : String aTblName; // table name
316 0 : OUString aRange; // cell range
317 0 : String aStartCell; // name of top left cell
318 0 : String aEndCell; // name of bottom right cell
319 0 : sal_Int32 nIdx = rRangeRepresentation.indexOf( '.' );
320 0 : if (nIdx >= 0)
321 : {
322 0 : aTblName = rRangeRepresentation.copy( 0, nIdx );
323 0 : aRange = rRangeRepresentation.copy( nIdx + 1 );
324 0 : sal_Int32 nPos = aRange.indexOf( ':' );
325 0 : if (nPos >= 0) // a cell-range like "Table1.A2:D4"
326 : {
327 0 : aStartCell = aRange.copy( 0, nPos );
328 0 : aEndCell = aRange.copy( nPos + 1 );
329 :
330 : // need to switch start and end cell ?
331 : // (does not check for normalization here)
332 0 : if (bSortStartEndCells && 1 == sw_CompareCellsByColFirst( aStartCell, aEndCell ))
333 : {
334 0 : String aTmp( aStartCell );
335 0 : aStartCell = aEndCell;
336 0 : aEndCell = aTmp;
337 : }
338 : }
339 : else // a single cell like in "Table1.B3"
340 : {
341 0 : aStartCell = aEndCell = aRange;
342 : }
343 : }
344 :
345 0 : bool bSuccess = aTblName.Len() != 0 &&
346 0 : aStartCell.Len() != 0 && aEndCell.Len() != 0;
347 0 : if (bSuccess)
348 : {
349 0 : rTblName = aTblName;
350 0 : rStartCell = aStartCell;
351 0 : rEndCell = aEndCell;
352 : }
353 0 : return bSuccess;
354 : }
355 :
356 0 : static void GetTableByName( const SwDoc &rDoc, const String &rTableName,
357 : SwFrmFmt **ppTblFmt, SwTable **ppTable)
358 : {
359 0 : SwFrmFmt *pTblFmt = NULL;
360 :
361 : // find frame format of table
362 : //! see SwXTextTables::getByName
363 0 : sal_uInt16 nCount = rDoc.GetTblFrmFmtCount(true);
364 0 : for (sal_uInt16 i = 0; i < nCount && !pTblFmt; ++i)
365 : {
366 0 : SwFrmFmt& rTblFmt = rDoc.GetTblFrmFmt(i, true);
367 0 : if(rTableName == rTblFmt.GetName())
368 0 : pTblFmt = &rTblFmt;
369 : }
370 :
371 0 : if (ppTblFmt)
372 0 : *ppTblFmt = pTblFmt;
373 :
374 0 : if (ppTable)
375 0 : *ppTable = pTblFmt ? SwTable::FindTable( pTblFmt ) : 0;
376 0 : }
377 :
378 0 : static void GetFormatAndCreateCursorFromRangeRep(
379 : const SwDoc *pDoc,
380 : const OUString &rRangeRepresentation, // must be a single range (i.e. so called sub-range)
381 : SwFrmFmt **ppTblFmt, // will be set to the table format of the table used in the range representation
382 : SwUnoCrsr **ppUnoCrsr ) // will be set to cursor spanning the cell range
383 : // (cursor will be created!)
384 : {
385 0 : String aTblName; // table name
386 0 : String aStartCell; // name of top left cell
387 0 : String aEndCell; // name of bottom right cell
388 : bool bNamesFound = GetTableAndCellsFromRangeRep( rRangeRepresentation,
389 0 : aTblName, aStartCell, aEndCell );
390 :
391 0 : if (!bNamesFound)
392 : {
393 0 : if (ppTblFmt)
394 0 : *ppTblFmt = NULL;
395 0 : if (ppUnoCrsr)
396 0 : *ppUnoCrsr = NULL;
397 : }
398 : else
399 : {
400 0 : SwFrmFmt *pTblFmt = NULL;
401 :
402 : // is the correct table format already provided?
403 0 : if (*ppTblFmt != NULL && (*ppTblFmt)->GetName() == aTblName)
404 0 : pTblFmt = *ppTblFmt;
405 0 : else if (ppTblFmt)
406 0 : GetTableByName( *pDoc, aTblName, &pTblFmt, NULL );
407 :
408 0 : if (ppTblFmt)
409 0 : *ppTblFmt = pTblFmt;
410 :
411 0 : if (ppUnoCrsr != NULL)
412 : {
413 0 : *ppUnoCrsr = NULL; // default result in case of failure
414 :
415 0 : SwTable *pTable = pTblFmt ? SwTable::FindTable( pTblFmt ) : 0;
416 : // create new SwUnoCrsr spanning the specified range
417 : //! see also SwXTextTable::GetRangeByName
418 : // #i80314#
419 : // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTblBox(..)>
420 : const SwTableBox* pTLBox =
421 0 : pTable ? pTable->GetTblBox( aStartCell, true ) : 0;
422 0 : if(pTLBox)
423 : {
424 : // hier muessen die Actions aufgehoben werden
425 0 : UnoActionRemoveContext aRemoveContext(pTblFmt->GetDoc());
426 0 : const SwStartNode* pSttNd = pTLBox->GetSttNd();
427 0 : SwPosition aPos(*pSttNd);
428 : // set cursor to top left box of range
429 0 : SwUnoCrsr* pUnoCrsr = pTblFmt->GetDoc()->CreateUnoCrsr(aPos, true);
430 0 : pUnoCrsr->Move( fnMoveForward, fnGoNode );
431 0 : pUnoCrsr->SetRemainInSection( sal_False );
432 : // #i80314#
433 : // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTblBox(..)>
434 0 : const SwTableBox* pBRBox = pTable->GetTblBox( aEndCell, true );
435 0 : if(pBRBox)
436 : {
437 0 : pUnoCrsr->SetMark();
438 0 : pUnoCrsr->GetPoint()->nNode = *pBRBox->GetSttNd();
439 0 : pUnoCrsr->Move( fnMoveForward, fnGoNode );
440 : SwUnoTableCrsr* pCrsr =
441 0 : dynamic_cast<SwUnoTableCrsr*>(pUnoCrsr);
442 0 : pCrsr->MakeBoxSels();
443 :
444 0 : if (ppUnoCrsr)
445 0 : *ppUnoCrsr = pCrsr;
446 : }
447 : else
448 : {
449 0 : delete pUnoCrsr;
450 0 : }
451 : }
452 : }
453 0 : }
454 0 : }
455 :
456 0 : static bool GetSubranges( const OUString &rRangeRepresentation,
457 : uno::Sequence< OUString > &rSubRanges, bool bNormalize )
458 : {
459 0 : bool bRes = true;
460 0 : String aRangesStr( rRangeRepresentation );
461 0 : xub_StrLen nLen = comphelper::string::getTokenCount(aRangesStr, ';');
462 0 : uno::Sequence< OUString > aRanges( nLen );
463 :
464 0 : sal_Int32 nCnt = 0;
465 0 : if (nLen != 0)
466 : {
467 0 : OUString *pRanges = aRanges.getArray();
468 0 : String aFirstTable;
469 0 : for ( xub_StrLen i = 0; i < nLen && bRes; ++i)
470 : {
471 0 : String aRange( aRangesStr.GetToken( i, ';' ) );
472 0 : if (aRange.Len())
473 : {
474 0 : pRanges[nCnt] = aRange;
475 :
476 0 : String aTableName, aStartCell, aEndCell;
477 0 : if (!GetTableAndCellsFromRangeRep( aRange,
478 0 : aTableName, aStartCell, aEndCell ))
479 0 : bRes = false;
480 :
481 0 : if (bNormalize)
482 : {
483 0 : sw_NormalizeRange( aStartCell, aEndCell );
484 : pRanges[nCnt] = GetRangeRepFromTableAndCells( aTableName,
485 0 : aStartCell, aEndCell, sal_True );
486 : }
487 :
488 : // make sure to use only a single table
489 0 : if (nCnt == 0)
490 0 : aFirstTable = aTableName;
491 : else
492 0 : if (aFirstTable != aTableName) bRes = false;
493 :
494 0 : ++nCnt;
495 : }
496 0 : }
497 : }
498 0 : aRanges.realloc( nCnt );
499 :
500 0 : rSubRanges = aRanges;
501 0 : return bRes;
502 : }
503 :
504 0 : static void SortSubranges( uno::Sequence< OUString > &rSubRanges, sal_Bool bCmpByColumn )
505 : {
506 0 : sal_Int32 nLen = rSubRanges.getLength();
507 0 : OUString *pSubRanges = rSubRanges.getArray();
508 :
509 0 : String aSmallestTblName;
510 0 : String aSmallestStartCell;
511 0 : String aSmallestEndCell;
512 :
513 0 : for (sal_Int32 i = 0; i < nLen; ++i)
514 : {
515 0 : sal_Int32 nIdxOfSmallest = i;
516 : GetTableAndCellsFromRangeRep( pSubRanges[nIdxOfSmallest],
517 0 : aSmallestTblName, aSmallestStartCell, aSmallestEndCell );
518 0 : if (aSmallestEndCell.Len() == 0)
519 0 : aSmallestEndCell = aSmallestStartCell;
520 :
521 0 : for (sal_Int32 k = i+1; k < nLen; ++k)
522 : {
523 : // get cell names for sub range
524 0 : String aTblName;
525 0 : String aStartCell;
526 0 : String aEndCell;
527 : GetTableAndCellsFromRangeRep( pSubRanges[k],
528 0 : aTblName, aStartCell, aEndCell );
529 0 : if (aEndCell.Len() == 0)
530 0 : aEndCell = aStartCell;
531 :
532 : // compare cell ranges ( is the new one smaller? )
533 0 : if (-1 == sw_CompareCellRanges( aStartCell, aEndCell,
534 0 : aSmallestStartCell, aSmallestEndCell, bCmpByColumn ))
535 : {
536 0 : nIdxOfSmallest = k;
537 0 : aSmallestTblName = aTblName;
538 0 : aSmallestStartCell = aStartCell;
539 0 : aSmallestEndCell = aEndCell;
540 : }
541 0 : }
542 :
543 : // move smallest element to the start of the not sorted area
544 0 : OUString aTmp( pSubRanges[ nIdxOfSmallest ] );
545 0 : pSubRanges[ nIdxOfSmallest ] = pSubRanges[ i ];
546 0 : pSubRanges[ i ] = aTmp;
547 0 : }
548 0 : }
549 :
550 0 : SwChartDataProvider::SwChartDataProvider( const SwDoc* pSwDoc ) :
551 0 : aEvtListeners( GetChartMutex() ),
552 0 : pDoc( pSwDoc )
553 : {
554 0 : bDisposed = sal_False;
555 0 : }
556 :
557 0 : SwChartDataProvider::~SwChartDataProvider()
558 : {
559 0 : }
560 :
561 0 : uno::Reference< chart2::data::XDataSource > SwChartDataProvider::Impl_createDataSource(
562 : const uno::Sequence< beans::PropertyValue >& rArguments, sal_Bool bTestOnly )
563 : throw (lang::IllegalArgumentException, uno::RuntimeException)
564 : {
565 0 : SolarMutexGuard aGuard;
566 0 : if (bDisposed)
567 0 : throw lang::DisposedException();
568 :
569 0 : uno::Reference< chart2::data::XDataSource > xRes;
570 :
571 0 : if (!pDoc)
572 0 : throw uno::RuntimeException();
573 :
574 : // get arguments
575 0 : OUString aRangeRepresentation;
576 0 : uno::Sequence< sal_Int32 > aSequenceMapping;
577 0 : sal_Bool bFirstIsLabel = sal_False;
578 0 : sal_Bool bDtaSrcIsColumns = sal_True; // true : DataSource will be sequence of columns
579 : // false: DataSource will be sequence of rows
580 0 : OUString aChartOleObjectName;//work around wrong writer ranges ( see Issue 58464 )
581 0 : sal_Int32 nArgs = rArguments.getLength();
582 : OSL_ENSURE( nArgs != 0, "no properties provided" );
583 0 : if (nArgs == 0)
584 : return xRes;
585 0 : const beans::PropertyValue *pArg = rArguments.getConstArray();
586 0 : for (sal_Int32 i = 0; i < nArgs; ++i)
587 : {
588 0 : if ( pArg[i].Name == "DataRowSource" )
589 : {
590 : chart::ChartDataRowSource eSource;
591 0 : if (!(pArg[i].Value >>= eSource))
592 : {
593 0 : sal_Int32 nTmp = 0;
594 0 : if (!(pArg[i].Value >>= nTmp))
595 0 : throw lang::IllegalArgumentException();
596 0 : eSource = static_cast< chart::ChartDataRowSource >( nTmp );
597 : }
598 0 : bDtaSrcIsColumns = eSource == chart::ChartDataRowSource_COLUMNS;
599 : }
600 0 : else if ( pArg[i].Name == "FirstCellAsLabel" )
601 : {
602 0 : if (!(pArg[i].Value >>= bFirstIsLabel))
603 0 : throw lang::IllegalArgumentException();
604 : }
605 0 : else if ( pArg[i].Name == "CellRangeRepresentation" )
606 : {
607 0 : if (!(pArg[i].Value >>= aRangeRepresentation))
608 0 : throw lang::IllegalArgumentException();
609 : }
610 0 : else if ( pArg[i].Name == "SequenceMapping" )
611 : {
612 0 : if (!(pArg[i].Value >>= aSequenceMapping))
613 0 : throw lang::IllegalArgumentException();
614 : }
615 0 : else if ( pArg[i].Name == "ChartOleObjectName" )
616 : {
617 0 : if (!(pArg[i].Value >>= aChartOleObjectName))
618 0 : throw lang::IllegalArgumentException();
619 : }
620 : }
621 :
622 0 : uno::Sequence< OUString > aSubRanges;
623 : // get sub-ranges and check that they all are from the very same table
624 0 : sal_Bool bOk = GetSubranges( aRangeRepresentation, aSubRanges, sal_True );
625 :
626 0 : if (!bOk && pDoc && !aChartOleObjectName.isEmpty() )
627 : {
628 : //try to correct the range here
629 : //work around wrong writer ranges ( see Issue 58464 )
630 0 : String aChartTableName;
631 :
632 0 : const SwNodes& rNodes = pDoc->GetNodes();
633 0 : for( sal_uLong nN = rNodes.Count(); nN--; )
634 : {
635 0 : SwNodePtr pNode = rNodes[nN];
636 0 : if( !pNode )
637 0 : continue;
638 0 : const SwOLENode* pOleNode = pNode->GetOLENode();
639 0 : if( !pOleNode )
640 0 : continue;
641 0 : const SwOLEObj& rOObj = pOleNode->GetOLEObj();
642 0 : if( aChartOleObjectName.equals( rOObj.GetCurrentPersistName() ) )
643 : {
644 0 : aChartTableName = pOleNode->GetChartTblName();
645 0 : break;
646 : }
647 : }
648 :
649 0 : if( aChartTableName.Len() )
650 : {
651 : //the wrong range is still shifted one row down
652 : //thus the first row is missing and an invalid row at the end is added.
653 : //Therefore we need to shift the range one row up
654 : SwRangeDescriptor aDesc;
655 0 : if (aRangeRepresentation.isEmpty())
656 : return xRes; // we cant handle this thus returning an empty references
657 0 : aRangeRepresentation = aRangeRepresentation.copy( 1 ); // get rid of '.' to have only the cell range left
658 0 : FillRangeDescriptor( aDesc, aRangeRepresentation );
659 0 : aDesc.Normalize();
660 0 : if (aDesc.nTop <= 0) // no chance to shift the range one row up?
661 : return xRes; // we cant handle this thus returning an empty references
662 0 : aDesc.nTop -= 1;
663 0 : aDesc.nBottom -= 1;
664 :
665 0 : String aNewStartCell( sw_GetCellName( aDesc.nLeft, aDesc.nTop ) );
666 0 : String aNewEndCell( sw_GetCellName( aDesc.nRight, aDesc.nBottom ) );
667 : aRangeRepresentation = GetRangeRepFromTableAndCells(
668 0 : aChartTableName, aNewStartCell, aNewEndCell, sal_True );
669 0 : bOk = GetSubranges( aRangeRepresentation, aSubRanges, sal_True );
670 0 : }
671 : }
672 0 : if (!bOk) // different tables used, or incorrect range specifiers
673 0 : throw lang::IllegalArgumentException();
674 :
675 0 : SortSubranges( aSubRanges, bDtaSrcIsColumns );
676 0 : const OUString *pSubRanges = aSubRanges.getConstArray();
677 : #if OSL_DEBUG_LEVEL > 1
678 : {
679 : sal_Int32 nSR = aSubRanges.getLength();
680 : OUString *pSR = aSubRanges.getArray();
681 : OUString aRg;
682 : for (sal_Int32 i = 0; i < nSR; ++i)
683 : {
684 : aRg = pSR[i];
685 : }
686 : }
687 : #endif
688 :
689 : // get table format for that single table from above
690 0 : SwFrmFmt *pTblFmt = 0; // pointer to table format
691 0 : SwUnoCrsr *pUnoCrsr = 0; // here required to check if the cells in the range do actually exist
692 0 : std::auto_ptr< SwUnoCrsr > pAuto( pUnoCrsr ); // to end lifetime of object pointed to by pUnoCrsr
693 0 : if (aSubRanges.getLength() > 0)
694 0 : GetFormatAndCreateCursorFromRangeRep( pDoc, pSubRanges[0], &pTblFmt, &pUnoCrsr );
695 0 : if (!pTblFmt || !pUnoCrsr)
696 0 : throw lang::IllegalArgumentException();
697 :
698 0 : if(pTblFmt)
699 : {
700 0 : SwTable* pTable = SwTable::FindTable( pTblFmt );
701 0 : if(pTable->IsTblComplex())
702 : return xRes; // we cant handle this thus returning an empty references
703 : else
704 : {
705 : // get a character map in the size of the table to mark
706 : // all the ranges to use in
707 0 : sal_Int32 nRows = pTable->GetTabLines().size();
708 0 : sal_Int32 nCols = pTable->GetTabLines().front()->GetTabBoxes().size();
709 0 : std::vector< std::vector< sal_Char > > aMap( nRows );
710 0 : for (sal_Int32 i = 0; i < nRows; ++i)
711 0 : aMap[i].resize( nCols );
712 :
713 : // iterate over subranges and mark used cells in above map
714 : //!! by proceeding this way we automatically get rid of
715 : //!! multiple listed or overlapping cell ranges which should
716 : //!! just be ignored silently
717 0 : sal_Int32 nSubRanges = aSubRanges.getLength();
718 0 : for (sal_Int32 i = 0; i < nSubRanges; ++i)
719 : {
720 0 : String aTblName, aStartCell, aEndCell;
721 : bool bOk2 = GetTableAndCellsFromRangeRep(
722 0 : pSubRanges[i], aTblName, aStartCell, aEndCell );
723 : (void) bOk2;
724 : OSL_ENSURE( bOk2, "failed to get table and start/end cells" );
725 :
726 : sal_Int32 nStartRow, nStartCol, nEndRow, nEndCol;
727 0 : sw_GetCellPosition( aStartCell, nStartCol, nStartRow );
728 0 : sw_GetCellPosition( aEndCell, nEndCol, nEndRow );
729 : OSL_ENSURE( nStartRow <= nEndRow && nStartCol <= nEndCol,
730 : "cell range not normalized");
731 :
732 : // test if the ranges span more than the available cells
733 0 : if( nStartRow < 0 || nEndRow >= nRows ||
734 : nStartCol < 0 || nEndCol >= nCols )
735 : {
736 0 : throw lang::IllegalArgumentException();
737 : }
738 0 : for (sal_Int32 k1 = nStartRow; k1 <= nEndRow; ++k1)
739 : {
740 0 : for (sal_Int32 k2 = nStartCol; k2 <= nEndCol; ++k2)
741 0 : aMap[k1][k2] = 'x';
742 : }
743 0 : }
744 :
745 : //
746 : // find label and data sequences to use
747 : //
748 : sal_Int32 oi; // outer index (slower changing index)
749 : sal_Int32 ii; // inner index (faster changing index)
750 0 : sal_Int32 oiEnd = bDtaSrcIsColumns ? nCols : nRows;
751 0 : sal_Int32 iiEnd = bDtaSrcIsColumns ? nRows : nCols;
752 0 : std::vector< sal_Int32 > aLabelIdx( oiEnd );
753 0 : std::vector< sal_Int32 > aDataStartIdx( oiEnd );
754 0 : std::vector< sal_Int32 > aDataLen( oiEnd );
755 0 : for (oi = 0; oi < oiEnd; ++oi)
756 : {
757 0 : aLabelIdx[oi] = -1;
758 0 : aDataStartIdx[oi] = -1;
759 0 : aDataLen[oi] = 0;
760 : }
761 : //
762 0 : for (oi = 0; oi < oiEnd; ++oi)
763 : {
764 0 : ii = 0;
765 0 : while (ii < iiEnd)
766 : {
767 0 : sal_Char &rChar = bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii];
768 :
769 : // label should be used but is not yet found?
770 0 : if (rChar == 'x' && bFirstIsLabel && aLabelIdx[oi] == -1)
771 : {
772 0 : aLabelIdx[oi] = ii;
773 0 : rChar = 'L'; // setting a different char for labels here
774 : // makes the test for the data sequence below
775 : // easier
776 : }
777 :
778 : // find data sequence
779 0 : if (rChar == 'x' && aDataStartIdx[oi] == -1)
780 : {
781 0 : aDataStartIdx[oi] = ii;
782 :
783 : // get length of data sequence
784 0 : sal_Int32 nL = 0;
785 : sal_Char c;
786 0 : while (ii< iiEnd && 'x' == (c = bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii]))
787 : {
788 0 : ++nL; ++ii;
789 : }
790 0 : aDataLen[oi] = nL;
791 :
792 : // check that there is no other seperate sequence of data
793 : // to be found because that is not supported
794 0 : while (ii < iiEnd)
795 : {
796 0 : if ('x' == (c = bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii]))
797 0 : throw lang::IllegalArgumentException();
798 0 : ++ii;
799 : }
800 : }
801 : else
802 0 : ++ii;
803 : }
804 : }
805 :
806 : // make some other consistency checks while calculating
807 : // the number of XLabeledDataSequence to build:
808 : // - labels should always be used or not at all
809 : // - the data sequences should have equal non-zero length
810 0 : sal_Int32 nNumLDS = 0;
811 0 : if (oiEnd > 0)
812 : {
813 0 : sal_Int32 nFirstSeqLen = 0;
814 0 : sal_Int32 nFirstSeqLabelIdx = -1;
815 0 : for (oi = 0; oi < oiEnd; ++oi)
816 : {
817 0 : bool bFirstFound = false;
818 : // row/col used at all?
819 0 : if (aDataStartIdx[oi] != -1 &&
820 0 : (!bFirstIsLabel || aLabelIdx[oi] != -1))
821 : {
822 0 : ++nNumLDS;
823 0 : if (!bFirstFound)
824 : {
825 0 : nFirstSeqLen = aDataLen[oi];
826 0 : nFirstSeqLabelIdx = aLabelIdx[oi];
827 0 : bFirstFound = true;
828 : }
829 : else
830 : {
831 0 : if (nFirstSeqLen != aDataLen[oi] ||
832 0 : nFirstSeqLabelIdx != aLabelIdx[oi])
833 0 : throw lang::IllegalArgumentException();
834 : }
835 : }
836 : }
837 : }
838 0 : if (nNumLDS == 0)
839 0 : throw lang::IllegalArgumentException();
840 :
841 : // now we should have all necessary data to build a proper DataSource
842 : // thus if we came this far there should be no further problem
843 0 : if (bTestOnly)
844 : return xRes; // have createDataSourcePossible return true
845 :
846 : // create data source from found label and data sequences
847 0 : uno::Sequence< uno::Reference< chart2::data::XDataSequence > > aLabelSeqs( nNumLDS );
848 0 : uno::Reference< chart2::data::XDataSequence > *pLabelSeqs = aLabelSeqs.getArray();
849 0 : uno::Sequence< uno::Reference< chart2::data::XDataSequence > > aDataSeqs( nNumLDS );
850 0 : uno::Reference< chart2::data::XDataSequence > *pDataSeqs = aDataSeqs.getArray();
851 0 : sal_Int32 nSeqsIdx = 0;
852 0 : for (oi = 0; oi < oiEnd; ++oi)
853 : {
854 : // row/col not used? (see if-statement above where nNumLDS was counted)
855 0 : if (!(aDataStartIdx[oi] != -1 &&
856 0 : (!bFirstIsLabel || aLabelIdx[oi] != -1)))
857 0 : continue;
858 :
859 : // get cell ranges for label and data
860 : //
861 : SwRangeDescriptor aLabelDesc;
862 : SwRangeDescriptor aDataDesc;
863 0 : if (bDtaSrcIsColumns) // use columns
864 : {
865 0 : aLabelDesc.nTop = aLabelIdx[oi];
866 0 : aLabelDesc.nLeft = oi;
867 0 : aLabelDesc.nBottom = aLabelDesc.nTop;
868 0 : aLabelDesc.nRight = oi;
869 :
870 0 : aDataDesc.nTop = aDataStartIdx[oi];
871 0 : aDataDesc.nLeft = oi;
872 0 : aDataDesc.nBottom = aDataDesc.nTop + aDataLen[oi] - 1;
873 0 : aDataDesc.nRight = oi;
874 : }
875 : else // use rows
876 : {
877 0 : aLabelDesc.nTop = oi;
878 0 : aLabelDesc.nLeft = aLabelIdx[oi];
879 0 : aLabelDesc.nBottom = oi;
880 0 : aLabelDesc.nRight = aLabelDesc.nLeft;
881 :
882 0 : aDataDesc.nTop = oi;
883 0 : aDataDesc.nLeft = aDataStartIdx[oi];
884 0 : aDataDesc.nBottom = oi;
885 0 : aDataDesc.nRight = aDataDesc.nLeft + aDataLen[oi] - 1;
886 : }
887 0 : String aBaseName( pTblFmt->GetName() );
888 0 : aBaseName += '.';
889 : //
890 0 : String aLabelRange;
891 0 : if (aLabelIdx[oi] != -1)
892 : {
893 0 : aLabelRange += aBaseName;
894 0 : aLabelRange += sw_GetCellName( aLabelDesc.nLeft, aLabelDesc.nTop );
895 0 : aLabelRange += ':';
896 0 : aLabelRange += sw_GetCellName( aLabelDesc.nRight, aLabelDesc.nBottom );
897 : }
898 : //
899 0 : String aDataRange;
900 0 : if (aDataStartIdx[oi] != -1)
901 : {
902 0 : aDataRange += aBaseName;
903 0 : aDataRange += sw_GetCellName( aDataDesc.nLeft, aDataDesc.nTop );
904 0 : aDataRange += ':';
905 0 : aDataRange += sw_GetCellName( aDataDesc.nRight, aDataDesc.nBottom );
906 : }
907 :
908 : // get cursors spanning the cell ranges for label and data
909 0 : SwUnoCrsr *pLabelUnoCrsr = 0;
910 0 : SwUnoCrsr *pDataUnoCrsr = 0;
911 0 : GetFormatAndCreateCursorFromRangeRep( pDoc, aLabelRange, &pTblFmt, &pLabelUnoCrsr);
912 0 : GetFormatAndCreateCursorFromRangeRep( pDoc, aDataRange, &pTblFmt, &pDataUnoCrsr);
913 :
914 : // create XDataSequence's from cursors
915 0 : if (pLabelUnoCrsr)
916 0 : pLabelSeqs[ nSeqsIdx ] = new SwChartDataSequence( *this, *pTblFmt, pLabelUnoCrsr );
917 : OSL_ENSURE( pDataUnoCrsr, "pointer to data sequence missing" );
918 0 : if (pDataUnoCrsr)
919 0 : pDataSeqs [ nSeqsIdx ] = new SwChartDataSequence( *this, *pTblFmt, pDataUnoCrsr );
920 0 : if (pLabelUnoCrsr || pDataUnoCrsr)
921 0 : ++nSeqsIdx;
922 0 : }
923 : OSL_ENSURE( nSeqsIdx == nNumLDS,
924 : "mismatch between sequence size and num,ber of entries" );
925 :
926 : // build data source from data and label sequences
927 0 : uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLDS( nNumLDS );
928 0 : uno::Reference< chart2::data::XLabeledDataSequence > *pLDS = aLDS.getArray();
929 0 : for (sal_Int32 i = 0; i < nNumLDS; ++i)
930 : {
931 0 : SwChartLabeledDataSequence *pLabeledDtaSeq = new SwChartLabeledDataSequence;
932 0 : pLabeledDtaSeq->setLabel( pLabelSeqs[i] );
933 0 : pLabeledDtaSeq->setValues( pDataSeqs[i] );
934 0 : pLDS[i] = pLabeledDtaSeq;
935 : }
936 :
937 : // apply 'SequenceMapping' if it was provided
938 0 : sal_Int32 nSequenceMappingLen = aSequenceMapping.getLength();
939 0 : if (nSequenceMappingLen)
940 : {
941 0 : sal_Int32 *pSequenceMapping = aSequenceMapping.getArray();
942 0 : uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aOld_LDS( aLDS );
943 0 : uno::Reference< chart2::data::XLabeledDataSequence > *pOld_LDS = aOld_LDS.getArray();
944 :
945 0 : sal_Int32 nNewCnt = 0;
946 0 : for (sal_Int32 i = 0; i < nSequenceMappingLen; ++i)
947 : {
948 : // check that index to be used is valid
949 : // and has not yet been used
950 0 : sal_Int32 nIdx = pSequenceMapping[i];
951 0 : if (0 <= nIdx && nIdx < nNumLDS && pOld_LDS[nIdx].is())
952 : {
953 0 : pLDS[nNewCnt++] = pOld_LDS[nIdx];
954 :
955 : // mark index as being used already (avoids duplicate entries)
956 0 : pOld_LDS[nIdx].clear();
957 : }
958 : }
959 : // add not yet used 'old' sequences to new one
960 0 : for (sal_Int32 i = 0; i < nNumLDS; ++i)
961 : {
962 : #if OSL_DEBUG_LEVEL > 1
963 : if (!pOld_LDS[i].is())
964 : i = i;
965 : #endif
966 0 : if (pOld_LDS[i].is())
967 0 : pLDS[nNewCnt++] = pOld_LDS[i];
968 : }
969 0 : OSL_ENSURE( nNewCnt == nNumLDS, "unexpected size of resulting sequence" );
970 : }
971 :
972 0 : xRes = new SwChartDataSource( aLDS );
973 : }
974 : }
975 :
976 0 : return xRes;
977 : }
978 :
979 0 : sal_Bool SAL_CALL SwChartDataProvider::createDataSourcePossible(
980 : const uno::Sequence< beans::PropertyValue >& rArguments )
981 : throw (uno::RuntimeException)
982 : {
983 0 : SolarMutexGuard aGuard;
984 :
985 0 : sal_Bool bPossible = sal_True;
986 : try
987 : {
988 0 : Impl_createDataSource( rArguments, sal_True );
989 : }
990 0 : catch (lang::IllegalArgumentException &)
991 : {
992 0 : bPossible = sal_False;
993 : }
994 :
995 0 : return bPossible;
996 : }
997 :
998 0 : uno::Reference< chart2::data::XDataSource > SAL_CALL SwChartDataProvider::createDataSource(
999 : const uno::Sequence< beans::PropertyValue >& rArguments )
1000 : throw (lang::IllegalArgumentException, uno::RuntimeException)
1001 : {
1002 0 : SolarMutexGuard aGuard;
1003 0 : return Impl_createDataSource( rArguments );
1004 : }
1005 :
1006 : ////////////////////////////////////////////////////////////
1007 : // SwChartDataProvider::GetBrokenCellRangeForExport
1008 : //
1009 : // fix for #i79009
1010 : // we need to return a property that has the same value as the property
1011 : // 'CellRangeRepresentation' but for all rows which are increased by one.
1012 : // E.g. Table1:A1:D5 -> Table1:A2:D6
1013 : // Since the problem is only for old charts which did not support multiple
1014 : // we do not need to provide that property/string if the 'CellRangeRepresentation'
1015 : // contains multiple ranges.
1016 0 : OUString SwChartDataProvider::GetBrokenCellRangeForExport(
1017 : const OUString &rCellRangeRepresentation )
1018 : {
1019 0 : OUString aRes;
1020 :
1021 : // check that we do not have multiple ranges
1022 0 : if (-1 == rCellRangeRepresentation.indexOf( ';' ))
1023 : {
1024 : // get current cell and table names
1025 0 : String aTblName, aStartCell, aEndCell;
1026 : GetTableAndCellsFromRangeRep( rCellRangeRepresentation,
1027 0 : aTblName, aStartCell, aEndCell, false );
1028 0 : sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1;
1029 0 : sw_GetCellPosition( aStartCell, nStartCol, nStartRow );
1030 0 : sw_GetCellPosition( aEndCell, nEndCol, nEndRow );
1031 :
1032 : // get new cell names
1033 0 : ++nStartRow;
1034 0 : ++nEndRow;
1035 0 : aStartCell = sw_GetCellName( nStartCol, nStartRow );
1036 0 : aEndCell = sw_GetCellName( nEndCol, nEndRow );
1037 :
1038 : aRes = GetRangeRepFromTableAndCells( aTblName,
1039 0 : aStartCell, aEndCell, sal_False );
1040 : }
1041 :
1042 0 : return aRes;
1043 : }
1044 :
1045 0 : uno::Sequence< beans::PropertyValue > SAL_CALL SwChartDataProvider::detectArguments(
1046 : const uno::Reference< chart2::data::XDataSource >& xDataSource )
1047 : throw (uno::RuntimeException)
1048 : {
1049 0 : SolarMutexGuard aGuard;
1050 0 : if (bDisposed)
1051 0 : throw lang::DisposedException();
1052 :
1053 0 : uno::Sequence< beans::PropertyValue > aResult;
1054 0 : if (!xDataSource.is())
1055 : return aResult;
1056 :
1057 0 : const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aDS_LDS( xDataSource->getDataSequences() );
1058 0 : const uno::Reference< chart2::data::XLabeledDataSequence > *pDS_LDS = aDS_LDS.getConstArray();
1059 0 : sal_Int32 nNumDS_LDS = aDS_LDS.getLength();
1060 :
1061 0 : if (nNumDS_LDS == 0)
1062 : {
1063 : OSL_FAIL( "XLabeledDataSequence in data source contains 0 entries" );
1064 : return aResult;
1065 : }
1066 :
1067 0 : SwFrmFmt *pTableFmt = 0;
1068 0 : SwTable *pTable = 0;
1069 0 : String aTableName;
1070 0 : sal_Int32 nTableRows = 0;
1071 0 : sal_Int32 nTableCols = 0;
1072 :
1073 : // data used to build 'CellRangeRepresentation' from later on
1074 0 : std::vector< std::vector< sal_Char > > aMap;
1075 :
1076 0 : uno::Sequence< sal_Int32 > aSequenceMapping( nNumDS_LDS );
1077 0 : sal_Int32 *pSequenceMapping = aSequenceMapping.getArray();
1078 :
1079 0 : String aCellRanges;
1080 0 : sal_Int16 nDtaSrcIsColumns = -1;// -1: don't know yet, 0: false, 1: true -2: neither
1081 0 : sal_Int32 nLabelSeqLen = -1; // used to see if labels are always used or not and have
1082 : // the expected size of 1 (i.e. if FirstCellAsLabel can
1083 : // be determined)
1084 : // -1: don't know yet, 0: not used, 1: always a single labe cell, ...
1085 : // -2: neither/failed
1086 0 : for (sal_Int32 nDS1 = 0; nDS1 < nNumDS_LDS; ++nDS1)
1087 : {
1088 0 : uno::Reference< chart2::data::XLabeledDataSequence > xLabeledDataSequence( pDS_LDS[nDS1] );
1089 0 : if( !xLabeledDataSequence.is() )
1090 : {
1091 : OSL_FAIL("got NULL for XLabeledDataSequence from Data source");
1092 0 : continue;
1093 : }
1094 0 : const uno::Reference< chart2::data::XDataSequence > xCurLabel( xLabeledDataSequence->getLabel(), uno::UNO_QUERY );
1095 0 : const uno::Reference< chart2::data::XDataSequence > xCurValues( xLabeledDataSequence->getValues(), uno::UNO_QUERY );
1096 :
1097 : // get sequence lengths for label and values.
1098 : // (0 length is Ok)
1099 0 : sal_Int32 nCurLabelSeqLen = -1;
1100 0 : sal_Int32 nCurValuesSeqLen = -1;
1101 0 : if (xCurLabel.is())
1102 0 : nCurLabelSeqLen = xCurLabel->getData().getLength();
1103 0 : if (xCurValues.is())
1104 0 : nCurValuesSeqLen = xCurValues->getData().getLength();
1105 :
1106 : // check for consistent use of 'first cell as label'
1107 0 : if (nLabelSeqLen == -1) // set initial value to compare with below further on
1108 0 : nLabelSeqLen = nCurLabelSeqLen;
1109 0 : if (nLabelSeqLen != nCurLabelSeqLen)
1110 0 : nLabelSeqLen = -2; // failed / no consistent use of label cells
1111 :
1112 : // get table and cell names for label and values data sequences
1113 : // (start and end cell will be sorted, i.e. start cell <= end cell)
1114 0 : String aLabelTblName, aLabelStartCell, aLabelEndCell;
1115 0 : String aValuesTblName, aValuesStartCell, aValuesEndCell;
1116 0 : String aLabelRange, aValuesRange;
1117 0 : if (xCurLabel.is())
1118 0 : aLabelRange = xCurLabel->getSourceRangeRepresentation();
1119 0 : if (xCurValues.is())
1120 0 : aValuesRange = xCurValues->getSourceRangeRepresentation();
1121 0 : if ((aLabelRange.Len() && !GetTableAndCellsFromRangeRep( aLabelRange,
1122 0 : aLabelTblName, aLabelStartCell, aLabelEndCell )) ||
1123 : !GetTableAndCellsFromRangeRep( aValuesRange,
1124 0 : aValuesTblName, aValuesStartCell, aValuesEndCell ))
1125 : {
1126 : return aResult; // failed -> return empty property sequence
1127 : }
1128 :
1129 : // make sure all sequences use the same table
1130 0 : if (!aTableName.Len())
1131 0 : aTableName = aValuesTblName; // get initial value to compare with
1132 0 : if (!aTableName.Len() ||
1133 0 : aTableName != aValuesTblName ||
1134 0 : (aLabelTblName.Len() && aTableName != aLabelTblName))
1135 : {
1136 : return aResult; // failed -> return empty property sequence
1137 : }
1138 :
1139 :
1140 : // try to get 'DataRowSource' value (ROWS or COLUMNS) from inspecting
1141 : // first and last cell used in both sequences
1142 : //
1143 0 : sal_Int32 nFirstCol = -1, nFirstRow = -1, nLastCol = -1, nLastRow = -1;
1144 0 : String aCell( aLabelStartCell.Len() ? aLabelStartCell : aValuesStartCell );
1145 : OSL_ENSURE( aCell.Len() , "start cell missing?" );
1146 0 : sw_GetCellPosition( aCell, nFirstCol, nFirstRow);
1147 0 : sw_GetCellPosition( aValuesEndCell, nLastCol, nLastRow);
1148 : //
1149 0 : sal_Int16 nDirection = -1; // -1: not yet set, 0: columns, 1: rows, -2: failed
1150 0 : if (nFirstCol == nLastCol && nFirstRow == nLastRow) // a single cell...
1151 : {
1152 : OSL_ENSURE( nCurLabelSeqLen == 0 && nCurValuesSeqLen == 1,
1153 : "trying to determine 'DataRowSource': something's fishy... should have been a single cell");
1154 : (void)nCurValuesSeqLen;
1155 0 : nDirection = 0; // default direction for a single cell should be 'columns'
1156 : }
1157 : else // more than one cell is availabale (in values and label together!)
1158 : {
1159 0 : if (nFirstCol == nLastCol && nFirstRow != nLastRow)
1160 0 : nDirection = 1;
1161 0 : else if (nFirstCol != nLastCol && nFirstRow == nLastRow)
1162 0 : nDirection = 0;
1163 : else
1164 : {
1165 : OSL_FAIL( "trying to determine 'DataRowSource': unexpected case found" );
1166 0 : nDirection = -2;
1167 : }
1168 : }
1169 : // check for consistent direction of data source
1170 0 : if (nDtaSrcIsColumns == -1) // set initial value to compare with below
1171 0 : nDtaSrcIsColumns = nDirection;
1172 0 : if (nDtaSrcIsColumns != nDirection)
1173 : {
1174 0 : nDtaSrcIsColumns = -2; // failed
1175 : }
1176 :
1177 :
1178 0 : if (nDtaSrcIsColumns == 0 || nDtaSrcIsColumns == 1)
1179 : {
1180 : // build data to obtain 'SequenceMapping' later on
1181 : //
1182 : OSL_ENSURE( nDtaSrcIsColumns == 0 || /* rows */
1183 : nDtaSrcIsColumns == 1, /* columns */
1184 : "unexpected value for 'nDtaSrcIsColumns'" );
1185 0 : pSequenceMapping[nDS1] = nDtaSrcIsColumns ? nFirstCol : nFirstRow;
1186 :
1187 :
1188 : // build data used to determine 'CellRangeRepresentation' later on
1189 : //
1190 0 : GetTableByName( *pDoc, aTableName, &pTableFmt, &pTable );
1191 0 : if (!pTable || pTable->IsTblComplex())
1192 : return aResult; // failed -> return empty property sequence
1193 0 : nTableRows = pTable->GetTabLines().size();
1194 0 : nTableCols = pTable->GetTabLines().front()->GetTabBoxes().size();
1195 0 : aMap.resize( nTableRows );
1196 0 : for (sal_Int32 i = 0; i < nTableRows; ++i)
1197 0 : aMap[i].resize( nTableCols );
1198 : //
1199 0 : if (aLabelStartCell.Len() && aLabelEndCell.Len())
1200 : {
1201 0 : sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1;
1202 0 : sw_GetCellPosition( aLabelStartCell, nStartCol, nStartRow );
1203 0 : sw_GetCellPosition( aLabelEndCell, nEndCol, nEndRow );
1204 0 : if (nStartRow < 0 || nEndRow >= nTableRows ||
1205 : nStartCol < 0 || nEndCol >= nTableCols)
1206 : {
1207 : return aResult; // failed -> return empty property sequence
1208 : }
1209 0 : for (sal_Int32 i = nStartRow; i <= nEndRow; ++i)
1210 : {
1211 0 : for (sal_Int32 k = nStartCol; k <= nEndCol; ++k)
1212 : {
1213 0 : sal_Char &rChar = aMap[i][k];
1214 0 : if (rChar == '\0') // check for overlapping values and/or labels
1215 0 : rChar = 'L';
1216 : else
1217 : return aResult; // failed -> return empty property sequence
1218 : }
1219 : }
1220 : }
1221 0 : if (aValuesStartCell.Len() && aValuesEndCell.Len())
1222 : {
1223 0 : sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1;
1224 0 : sw_GetCellPosition( aValuesStartCell, nStartCol, nStartRow );
1225 0 : sw_GetCellPosition( aValuesEndCell, nEndCol, nEndRow );
1226 0 : if (nStartRow < 0 || nEndRow >= nTableRows ||
1227 : nStartCol < 0 || nEndCol >= nTableCols)
1228 : {
1229 : return aResult; // failed -> return empty property sequence
1230 : }
1231 0 : for (sal_Int32 i = nStartRow; i <= nEndRow; ++i)
1232 : {
1233 0 : for (sal_Int32 k = nStartCol; k <= nEndCol; ++k)
1234 : {
1235 0 : sal_Char &rChar = aMap[i][k];
1236 0 : if (rChar == '\0') // check for overlapping values and/or labels
1237 0 : rChar = 'x';
1238 : else
1239 : return aResult; // failed -> return empty property sequence
1240 : }
1241 : }
1242 : }
1243 : }
1244 :
1245 : #if OSL_DEBUG_LEVEL > 0
1246 : // do some extra sanity checking that the length of the sequences
1247 : // matches their range representation
1248 : {
1249 : sal_Int32 nStartRow = -1, nStartCol = -1, nEndRow = -1, nEndCol = -1;
1250 : if (xCurLabel.is())
1251 : {
1252 : sw_GetCellPosition( aLabelStartCell, nStartCol, nStartRow);
1253 : sw_GetCellPosition( aLabelEndCell, nEndCol, nEndRow);
1254 : OSL_ENSURE( (nStartCol == nEndCol && (nEndRow - nStartRow + 1) == xCurLabel->getData().getLength()) ||
1255 : (nStartRow == nEndRow && (nEndCol - nStartCol + 1) == xCurLabel->getData().getLength()),
1256 : "label sequence length does not match range representation!" );
1257 : }
1258 : if (xCurValues.is())
1259 : {
1260 : sw_GetCellPosition( aValuesStartCell, nStartCol, nStartRow);
1261 : sw_GetCellPosition( aValuesEndCell, nEndCol, nEndRow);
1262 : OSL_ENSURE( (nStartCol == nEndCol && (nEndRow - nStartRow + 1) == xCurValues->getData().getLength()) ||
1263 : (nStartRow == nEndRow && (nEndCol - nStartCol + 1) == xCurValues->getData().getLength()),
1264 : "value sequence length does not match range representation!" );
1265 : }
1266 : }
1267 : #endif
1268 0 : } // for
1269 :
1270 :
1271 : // build value for 'CellRangeRepresentation'
1272 : //
1273 0 : String aCellRangeBase( aTableName );
1274 0 : aCellRangeBase += '.';
1275 0 : String aCurRange;
1276 0 : for (sal_Int32 i = 0; i < nTableRows; ++i)
1277 : {
1278 0 : for (sal_Int32 k = 0; k < nTableCols; ++k)
1279 : {
1280 0 : if (aMap[i][k] != '\0') // top-left cell of a sub-range found
1281 : {
1282 : // find rectangular sub-range to use
1283 0 : sal_Int32 nRowIndex1 = i; // row index
1284 0 : sal_Int32 nColIndex1 = k; // column index
1285 0 : sal_Int32 nRowSubLen = 0;
1286 0 : sal_Int32 nColSubLen = 0;
1287 0 : while (nRowIndex1 < nTableRows && aMap[nRowIndex1++][k] != '\0')
1288 0 : ++nRowSubLen;
1289 : // be aware of shifted sequences!
1290 : // (according to the checks done prior the length should be ok)
1291 0 : while (nColIndex1 < nTableCols && aMap[i][nColIndex1] != '\0'
1292 0 : && aMap[i + nRowSubLen-1][nColIndex1] != '\0')
1293 : {
1294 0 : ++nColIndex1;
1295 0 : ++nColSubLen;
1296 : }
1297 0 : String aStartCell( sw_GetCellName( k, i ) );
1298 0 : String aEndCell( sw_GetCellName( k + nColSubLen - 1, i + nRowSubLen - 1) );
1299 0 : aCurRange = aCellRangeBase;
1300 0 : aCurRange += aStartCell;
1301 0 : aCurRange += ':';
1302 0 : aCurRange += aEndCell;
1303 0 : if (aCellRanges.Len())
1304 0 : aCellRanges += ';';
1305 0 : aCellRanges += aCurRange;
1306 :
1307 : // clear already found sub-range from map
1308 0 : for (sal_Int32 nRowIndex2 = 0; nRowIndex2 < nRowSubLen; ++nRowIndex2)
1309 0 : for (sal_Int32 nColumnIndex2 = 0; nColumnIndex2 < nColSubLen; ++nColumnIndex2)
1310 0 : aMap[i + nRowIndex2][k + nColumnIndex2] = '\0';
1311 : }
1312 : }
1313 : }
1314 : // to be nice to the user we now sort the cell ranges according to
1315 : // rows or columns depending on the direction used in the data source
1316 0 : uno::Sequence< OUString > aSortedRanges;
1317 0 : GetSubranges( aCellRanges, aSortedRanges, sal_False /*sub ranges should already be normalized*/ );
1318 0 : SortSubranges( aSortedRanges, (nDtaSrcIsColumns == 1) );
1319 0 : sal_Int32 nSortedRanges = aSortedRanges.getLength();
1320 0 : const OUString *pSortedRanges = aSortedRanges.getConstArray();
1321 0 : OUString aSortedCellRanges;
1322 0 : for (sal_Int32 i = 0; i < nSortedRanges; ++i)
1323 : {
1324 0 : if (!aSortedCellRanges.isEmpty())
1325 0 : aSortedCellRanges += OUString::valueOf( (sal_Unicode) ';');
1326 0 : aSortedCellRanges += pSortedRanges[i];
1327 : }
1328 :
1329 :
1330 : // build value for 'SequenceMapping'
1331 : //
1332 0 : uno::Sequence< sal_Int32 > aSortedMapping( aSequenceMapping );
1333 0 : sal_Int32 *pSortedMapping = aSortedMapping.getArray();
1334 0 : std::sort( pSortedMapping, pSortedMapping + aSortedMapping.getLength() );
1335 : OSL_ENSURE( aSortedMapping.getLength() == nNumDS_LDS, "unexpected size of sequence" );
1336 0 : bool bNeedSequenceMapping = false;
1337 0 : for (sal_Int32 i = 0; i < nNumDS_LDS; ++i)
1338 : {
1339 : sal_Int32 *pIt = std::find( pSortedMapping, pSortedMapping + nNumDS_LDS,
1340 0 : pSequenceMapping[i] );
1341 : OSL_ENSURE( pIt, "index not found" );
1342 0 : if (!pIt)
1343 : return aResult; // failed -> return empty property sequence
1344 0 : pSequenceMapping[i] = pIt - pSortedMapping;
1345 :
1346 0 : if (i != pSequenceMapping[i])
1347 0 : bNeedSequenceMapping = true;
1348 : }
1349 :
1350 : // check if 'SequenceMapping' is actually not required...
1351 : // (don't write unnecessary properties to the XML file)
1352 0 : if (!bNeedSequenceMapping)
1353 0 : aSequenceMapping.realloc(0);
1354 :
1355 : //
1356 : // build resulting properties
1357 : //
1358 : OSL_ENSURE(nLabelSeqLen >= 0 || nLabelSeqLen == -2 /*not used*/,
1359 : "unexpected value for 'nLabelSeqLen'" );
1360 0 : sal_Bool bFirstCellIsLabel = sal_False; // default value if 'nLabelSeqLen' could not properly determined
1361 0 : if (nLabelSeqLen > 0) // == 0 means no label sequence in use
1362 0 : bFirstCellIsLabel = sal_True;
1363 : //
1364 : OSL_ENSURE( !aSortedCellRanges.isEmpty(), "CellRangeRepresentation missing" );
1365 0 : OUString aBrokenCellRangeForExport( GetBrokenCellRangeForExport( aSortedCellRanges ) );
1366 : //
1367 0 : aResult.realloc(5);
1368 0 : sal_Int32 nProps = 0;
1369 0 : aResult[nProps ].Name = C2U("FirstCellAsLabel");
1370 0 : aResult[nProps++].Value <<= bFirstCellIsLabel;
1371 0 : aResult[nProps ].Name = C2U("CellRangeRepresentation");
1372 0 : aResult[nProps++].Value <<= aSortedCellRanges;
1373 0 : if (!aBrokenCellRangeForExport.isEmpty())
1374 : {
1375 0 : aResult[nProps ].Name = C2U("BrokenCellRangeForExport");
1376 0 : aResult[nProps++].Value <<= aBrokenCellRangeForExport;
1377 : }
1378 0 : if (nDtaSrcIsColumns == 0 || nDtaSrcIsColumns == 1)
1379 : {
1380 : chart::ChartDataRowSource eDataRowSource = (nDtaSrcIsColumns == 1) ?
1381 0 : chart::ChartDataRowSource_COLUMNS : chart::ChartDataRowSource_ROWS;
1382 0 : aResult[nProps ].Name = C2U("DataRowSource");
1383 0 : aResult[nProps++].Value <<= eDataRowSource;
1384 :
1385 0 : if (aSequenceMapping.getLength() != 0)
1386 : {
1387 0 : aResult[nProps ].Name = C2U("SequenceMapping");
1388 0 : aResult[nProps++].Value <<= aSequenceMapping;
1389 : }
1390 : }
1391 0 : aResult.realloc( nProps );
1392 :
1393 0 : return aResult;
1394 : }
1395 :
1396 0 : uno::Reference< chart2::data::XDataSequence > SwChartDataProvider::Impl_createDataSequenceByRangeRepresentation(
1397 : const OUString& rRangeRepresentation, sal_Bool bTestOnly )
1398 : throw (lang::IllegalArgumentException, uno::RuntimeException)
1399 : {
1400 0 : if (bDisposed)
1401 0 : throw lang::DisposedException();
1402 :
1403 0 : SwFrmFmt *pTblFmt = 0; // pointer to table format
1404 0 : SwUnoCrsr *pUnoCrsr = 0; // pointer to new created cursor spanning the cell range
1405 : GetFormatAndCreateCursorFromRangeRep( pDoc, rRangeRepresentation,
1406 0 : &pTblFmt, &pUnoCrsr );
1407 0 : if (!pTblFmt || !pUnoCrsr)
1408 0 : throw lang::IllegalArgumentException();
1409 :
1410 : // check that cursors point and mark are in a single row or column.
1411 0 : String aCellRange( GetCellRangeName( *pTblFmt, *pUnoCrsr ) );
1412 : SwRangeDescriptor aDesc;
1413 0 : FillRangeDescriptor( aDesc, aCellRange );
1414 0 : if (aDesc.nTop != aDesc.nBottom && aDesc.nLeft != aDesc.nRight)
1415 0 : throw lang::IllegalArgumentException();
1416 :
1417 : OSL_ENSURE( pTblFmt && pUnoCrsr, "table format or cursor missing" );
1418 0 : uno::Reference< chart2::data::XDataSequence > xDataSeq;
1419 0 : if (!bTestOnly)
1420 0 : xDataSeq = new SwChartDataSequence( *this, *pTblFmt, pUnoCrsr );
1421 :
1422 0 : return xDataSeq;
1423 : }
1424 :
1425 0 : sal_Bool SAL_CALL SwChartDataProvider::createDataSequenceByRangeRepresentationPossible(
1426 : const OUString& rRangeRepresentation )
1427 : throw (uno::RuntimeException)
1428 : {
1429 0 : SolarMutexGuard aGuard;
1430 :
1431 0 : sal_Bool bPossible = sal_True;
1432 : try
1433 : {
1434 0 : Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation, sal_True );
1435 : }
1436 0 : catch (lang::IllegalArgumentException &)
1437 : {
1438 0 : bPossible = sal_False;
1439 : }
1440 :
1441 0 : return bPossible;
1442 : }
1443 :
1444 0 : uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartDataProvider::createDataSequenceByRangeRepresentation(
1445 : const OUString& rRangeRepresentation )
1446 : throw (lang::IllegalArgumentException, uno::RuntimeException)
1447 : {
1448 0 : SolarMutexGuard aGuard;
1449 0 : return Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation );
1450 : }
1451 :
1452 0 : uno::Reference< sheet::XRangeSelection > SAL_CALL SwChartDataProvider::getRangeSelection( )
1453 : throw (uno::RuntimeException)
1454 : {
1455 : // note: it is no error to return nothing here
1456 0 : return uno::Reference< sheet::XRangeSelection >();
1457 : }
1458 :
1459 0 : void SAL_CALL SwChartDataProvider::dispose( )
1460 : throw (uno::RuntimeException)
1461 : {
1462 0 : bool bMustDispose( false );
1463 : {
1464 0 : osl::MutexGuard aGuard( GetChartMutex() );
1465 0 : bMustDispose = !bDisposed;
1466 0 : if (!bDisposed)
1467 0 : bDisposed = sal_True;
1468 : }
1469 0 : if (bMustDispose)
1470 : {
1471 : // dispose all data-sequences
1472 0 : Map_Set_DataSequenceRef_t::iterator aIt( aDataSequences.begin() );
1473 0 : while (aIt != aDataSequences.end())
1474 : {
1475 0 : DisposeAllDataSequences( (*aIt).first );
1476 0 : ++aIt;
1477 : }
1478 : // release all references to data-sequences
1479 0 : aDataSequences.clear();
1480 :
1481 : // require listeners to release references to this object
1482 0 : lang::EventObject aEvtObj( dynamic_cast< chart2::data::XDataSequence * >(this) );
1483 0 : aEvtListeners.disposeAndClear( aEvtObj );
1484 : }
1485 0 : }
1486 :
1487 0 : void SAL_CALL SwChartDataProvider::addEventListener(
1488 : const uno::Reference< lang::XEventListener >& rxListener )
1489 : throw (uno::RuntimeException)
1490 : {
1491 0 : osl::MutexGuard aGuard( GetChartMutex() );
1492 0 : if (!bDisposed && rxListener.is())
1493 0 : aEvtListeners.addInterface( rxListener );
1494 0 : }
1495 :
1496 0 : void SAL_CALL SwChartDataProvider::removeEventListener(
1497 : const uno::Reference< lang::XEventListener >& rxListener )
1498 : throw (uno::RuntimeException)
1499 : {
1500 0 : osl::MutexGuard aGuard( GetChartMutex() );
1501 0 : if (!bDisposed && rxListener.is())
1502 0 : aEvtListeners.removeInterface( rxListener );
1503 0 : }
1504 :
1505 0 : OUString SAL_CALL SwChartDataProvider::getImplementationName( )
1506 : throw (uno::RuntimeException)
1507 : {
1508 0 : return C2U("SwChartDataProvider");
1509 : }
1510 :
1511 0 : sal_Bool SAL_CALL SwChartDataProvider::supportsService(
1512 : const OUString& rServiceName )
1513 : throw (uno::RuntimeException)
1514 : {
1515 0 : SolarMutexGuard aGuard;
1516 0 : return rServiceName == SN_DATA_PROVIDER;
1517 : }
1518 :
1519 0 : uno::Sequence< OUString > SAL_CALL SwChartDataProvider::getSupportedServiceNames( )
1520 : throw (uno::RuntimeException)
1521 : {
1522 0 : SolarMutexGuard aGuard;
1523 0 : uno::Sequence< OUString > aRes(1);
1524 0 : aRes.getArray()[0] = C2U( SN_DATA_PROVIDER );
1525 0 : return aRes;
1526 : }
1527 :
1528 0 : void SwChartDataProvider::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew)
1529 : {
1530 : // actually this function should be superfluous (need to check later)
1531 0 : ClientModify(this, pOld, pNew );
1532 0 : }
1533 :
1534 0 : void SwChartDataProvider::AddDataSequence( const SwTable &rTable, uno::Reference< chart2::data::XDataSequence > &rxDataSequence )
1535 : {
1536 0 : aDataSequences[ &rTable ].insert( rxDataSequence );
1537 0 : }
1538 :
1539 0 : void SwChartDataProvider::RemoveDataSequence( const SwTable &rTable, uno::Reference< chart2::data::XDataSequence > &rxDataSequence )
1540 : {
1541 0 : aDataSequences[ &rTable ].erase( rxDataSequence );
1542 0 : }
1543 :
1544 0 : void SwChartDataProvider::InvalidateTable( const SwTable *pTable )
1545 : {
1546 : OSL_ENSURE( pTable, "table pointer is NULL" );
1547 0 : if (pTable)
1548 : {
1549 0 : if (!bDisposed)
1550 0 : pTable->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking();
1551 :
1552 0 : const Set_DataSequenceRef_t &rSet = aDataSequences[ pTable ];
1553 0 : Set_DataSequenceRef_t::const_iterator aIt( rSet.begin() );
1554 0 : while (aIt != rSet.end())
1555 : {
1556 0 : uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5
1557 0 : uno::Reference< util::XModifiable > xRef( xTemp, uno::UNO_QUERY );
1558 0 : if (xRef.is())
1559 : {
1560 : // mark the sequence as 'dirty' and notify listeners
1561 0 : xRef->setModified( sal_True );
1562 : }
1563 0 : ++aIt;
1564 0 : }
1565 : }
1566 0 : }
1567 :
1568 0 : sal_Bool SwChartDataProvider::DeleteBox( const SwTable *pTable, const SwTableBox &rBox )
1569 : {
1570 0 : sal_Bool bRes = sal_False;
1571 : OSL_ENSURE( pTable, "table pointer is NULL" );
1572 0 : if (pTable)
1573 : {
1574 0 : if (!bDisposed)
1575 0 : pTable->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking();
1576 :
1577 0 : Set_DataSequenceRef_t &rSet = aDataSequences[ pTable ];
1578 :
1579 : // iterate over all data-sequences for that table...
1580 0 : Set_DataSequenceRef_t::iterator aIt( rSet.begin() );
1581 0 : Set_DataSequenceRef_t::iterator aEndIt( rSet.end() );
1582 0 : Set_DataSequenceRef_t::iterator aDelIt; // iterator used for deletion when appropriate
1583 0 : while (aIt != aEndIt)
1584 : {
1585 0 : SwChartDataSequence *pDataSeq = 0;
1586 0 : sal_Bool bNowEmpty = sal_False;
1587 :
1588 : // check if weak reference is still valid...
1589 0 : uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5
1590 0 : uno::Reference< chart2::data::XDataSequence > xRef( xTemp, uno::UNO_QUERY );
1591 0 : if (xRef.is())
1592 : {
1593 : // then delete that table box (check if implementation cursor needs to be adjusted)
1594 0 : pDataSeq = static_cast< SwChartDataSequence * >( xRef.get() );
1595 0 : if (pDataSeq)
1596 : {
1597 : #if OSL_DEBUG_LEVEL > 1
1598 : OUString aRangeStr( pDataSeq->getSourceRangeRepresentation() );
1599 : #endif
1600 0 : bNowEmpty = pDataSeq->DeleteBox( rBox );
1601 0 : if (bNowEmpty)
1602 0 : aDelIt = aIt;
1603 : }
1604 : }
1605 0 : ++aIt;
1606 :
1607 0 : if (bNowEmpty)
1608 : {
1609 0 : rSet.erase( aDelIt );
1610 0 : if (pDataSeq)
1611 0 : pDataSeq->dispose(); // the current way to tell chart that sth. got removed
1612 : }
1613 0 : }
1614 : }
1615 0 : return bRes;
1616 : }
1617 :
1618 0 : void SwChartDataProvider::DisposeAllDataSequences( const SwTable *pTable )
1619 : {
1620 : OSL_ENSURE( pTable, "table pointer is NULL" );
1621 0 : if (pTable)
1622 : {
1623 0 : if (!bDisposed)
1624 0 : pTable->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking();
1625 :
1626 : //! make a copy of the STL container!
1627 : //! This is necessary since calling 'dispose' will implicitly remove an element
1628 : //! of the original container, and thus any iterator in the original container
1629 : //! would become invalid.
1630 0 : const Set_DataSequenceRef_t aSet( aDataSequences[ pTable ] );
1631 :
1632 0 : Set_DataSequenceRef_t::const_iterator aIt( aSet.begin() );
1633 0 : Set_DataSequenceRef_t::const_iterator aEndIt( aSet.end() );
1634 0 : while (aIt != aEndIt)
1635 : {
1636 0 : uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5
1637 0 : uno::Reference< lang::XComponent > xRef( xTemp, uno::UNO_QUERY );
1638 0 : if (xRef.is())
1639 : {
1640 0 : xRef->dispose();
1641 : }
1642 0 : ++aIt;
1643 0 : }
1644 : }
1645 0 : }
1646 :
1647 : ////////////////////////////////////////
1648 : // SwChartDataProvider::AddRowCols tries to notify charts of added columns
1649 : // or rows and extends the value sequence respectively (if possible).
1650 : // If those can be added to the end of existing value data-sequences those
1651 : // sequences get mofdified accordingly and will send a modification
1652 : // notification (calling 'setModified').
1653 : //
1654 : // Since this function is a work-around for non existent Writer core functionality
1655 : // (no arbitrary multi-selection in tables that can be used to define a
1656 : // data-sequence) this function will be somewhat unreliable.
1657 : // For example we will only try to adapt value sequences. For this we assume
1658 : // that a sequence of length 1 is a label sequence and those with length >= 2
1659 : // we presume to be value sequences. Also new cells can only be added in the
1660 : // direction the value sequence is already pointing (rows / cols) and at the
1661 : // start or end of the values data-sequence.
1662 : // Nothing needs to be done if the new cells are in between the table cursors
1663 : // point and mark since data-sequence are considered to consist of all cells
1664 : // between those.
1665 : // New rows/cols need to be added already to the table before calling
1666 : // this function.
1667 : //
1668 0 : void SwChartDataProvider::AddRowCols(
1669 : const SwTable &rTable,
1670 : const SwSelBoxes& rBoxes,
1671 : sal_uInt16 nLines, sal_Bool bBehind )
1672 : {
1673 0 : if (rTable.IsTblComplex())
1674 0 : return;
1675 :
1676 0 : const size_t nBoxes = rBoxes.size();
1677 0 : if (nBoxes < 1 || nLines < 1)
1678 0 : return;
1679 :
1680 0 : SwTableBox* pFirstBox = rBoxes[0];
1681 0 : SwTableBox* pLastBox = rBoxes.back();
1682 :
1683 0 : if (pFirstBox && pLastBox)
1684 : {
1685 0 : sal_Int32 nFirstCol = -1, nFirstRow = -1, nLastCol = -1, nLastRow = -1;
1686 0 : sw_GetCellPosition( pFirstBox->GetName(), nFirstCol, nFirstRow );
1687 0 : sw_GetCellPosition( pLastBox->GetName(), nLastCol, nLastRow );
1688 :
1689 0 : bool bAddCols = false; // default; also to be used if nBoxes == 1 :-/
1690 0 : if (nFirstCol == nLastCol && nFirstRow != nLastRow)
1691 0 : bAddCols = true;
1692 0 : if (nFirstCol == nLastCol || nFirstRow == nLastRow)
1693 : {
1694 : //get range of indices in col/rows for new cells
1695 0 : sal_Int32 nFirstNewCol = nFirstCol;
1696 0 : sal_Int32 nFirstNewRow = bBehind ? nFirstRow + 1 : nFirstRow - nLines;
1697 0 : if (bAddCols)
1698 : {
1699 : OSL_ENSURE( nFirstCol == nLastCol, "column indices seem broken" );
1700 0 : nFirstNewCol = bBehind ? nFirstCol + 1 : nFirstCol - nLines;
1701 0 : nFirstNewRow = nFirstRow;
1702 : }
1703 :
1704 : // iterate over all data-sequences for the table
1705 0 : const Set_DataSequenceRef_t &rSet = aDataSequences[ &rTable ];
1706 0 : Set_DataSequenceRef_t::const_iterator aIt( rSet.begin() );
1707 0 : while (aIt != rSet.end())
1708 : {
1709 0 : uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5
1710 0 : uno::Reference< chart2::data::XTextualDataSequence > xRef( xTemp, uno::UNO_QUERY );
1711 0 : if (xRef.is())
1712 : {
1713 0 : const sal_Int32 nLen = xRef->getTextualData().getLength();
1714 0 : if (nLen > 1) // value data-sequence ?
1715 : {
1716 0 : SwChartDataSequence *pDataSeq = 0;
1717 0 : uno::Reference< lang::XUnoTunnel > xTunnel( xRef, uno::UNO_QUERY );
1718 0 : if(xTunnel.is())
1719 : {
1720 : pDataSeq = reinterpret_cast< SwChartDataSequence * >(
1721 0 : sal::static_int_cast< sal_IntPtr >( xTunnel->getSomething( SwChartDataSequence::getUnoTunnelId() )));
1722 :
1723 0 : if (pDataSeq)
1724 : {
1725 : SwRangeDescriptor aDesc;
1726 0 : pDataSeq->FillRangeDesc( aDesc );
1727 :
1728 0 : chart::ChartDataRowSource eDRSource = chart::ChartDataRowSource_COLUMNS;
1729 0 : if (aDesc.nTop == aDesc.nBottom && aDesc.nLeft != aDesc.nRight)
1730 0 : eDRSource = chart::ChartDataRowSource_ROWS;
1731 :
1732 0 : if (!bAddCols && eDRSource == chart::ChartDataRowSource_COLUMNS)
1733 : {
1734 : // add rows: extend affected columns by newly added row cells
1735 0 : pDataSeq->ExtendTo( true, nFirstNewRow, nLines );
1736 : }
1737 0 : else if (bAddCols && eDRSource == chart::ChartDataRowSource_ROWS)
1738 : {
1739 : // add cols: extend affected rows by newly added column cells
1740 0 : pDataSeq->ExtendTo( false, nFirstNewCol, nLines );
1741 : }
1742 : }
1743 0 : }
1744 : }
1745 : }
1746 0 : ++aIt;
1747 0 : }
1748 :
1749 : }
1750 : }
1751 : }
1752 :
1753 : // XRangeXMLConversion ---------------------------------------------------
1754 0 : rtl::OUString SAL_CALL SwChartDataProvider::convertRangeToXML( const rtl::OUString& rRangeRepresentation )
1755 : throw ( uno::RuntimeException, lang::IllegalArgumentException )
1756 : {
1757 0 : SolarMutexGuard aGuard;
1758 0 : if (bDisposed)
1759 0 : throw lang::DisposedException();
1760 :
1761 0 : String aRes;
1762 0 : String aRangeRepresentation( rRangeRepresentation );
1763 :
1764 : // multiple ranges are delimeted by a ';' like in
1765 : // "Table1.A1:A4;Table1.C2:C5" the same table must be used in all ranges!
1766 0 : xub_StrLen nNumRanges = comphelper::string::getTokenCount(aRangeRepresentation, ';');
1767 0 : SwTable* pFirstFoundTable = 0; // to check that only one table will be used
1768 0 : for (sal_uInt16 i = 0; i < nNumRanges; ++i)
1769 : {
1770 0 : String aRange( aRangeRepresentation.GetToken(i, ';') );
1771 0 : SwFrmFmt *pTblFmt = 0; // pointer to table format
1772 0 : GetFormatAndCreateCursorFromRangeRep( pDoc, aRange, &pTblFmt, NULL );
1773 0 : if (!pTblFmt)
1774 0 : throw lang::IllegalArgumentException();
1775 0 : SwTable* pTable = SwTable::FindTable( pTblFmt );
1776 0 : if (pTable->IsTblComplex())
1777 0 : throw uno::RuntimeException();
1778 :
1779 : // check that there is only one table used in all ranges
1780 0 : if (!pFirstFoundTable)
1781 0 : pFirstFoundTable = pTable;
1782 0 : if (pTable != pFirstFoundTable)
1783 0 : throw lang::IllegalArgumentException();
1784 :
1785 0 : String aTblName;
1786 0 : String aStartCell;
1787 0 : String aEndCell;
1788 0 : if (!GetTableAndCellsFromRangeRep( aRange, aTblName, aStartCell, aEndCell ))
1789 0 : throw lang::IllegalArgumentException();
1790 :
1791 : sal_Int32 nCol, nRow;
1792 0 : sw_GetCellPosition( aStartCell, nCol, nRow );
1793 0 : if (nCol < 0 || nRow < 0)
1794 0 : throw uno::RuntimeException();
1795 :
1796 : //!! following objects/functions are implemented in XMLRangeHelper.?xx
1797 : //!! which is a copy of the respective file from chart2 !!
1798 0 : XMLRangeHelper::CellRange aCellRange;
1799 0 : aCellRange.aTableName = aTblName;
1800 0 : aCellRange.aUpperLeft.nColumn = nCol;
1801 0 : aCellRange.aUpperLeft.nRow = nRow;
1802 0 : aCellRange.aUpperLeft.bIsEmpty = false;
1803 0 : if (aStartCell != aEndCell && aEndCell.Len() != 0)
1804 : {
1805 0 : sw_GetCellPosition( aEndCell, nCol, nRow );
1806 0 : if (nCol < 0 || nRow < 0)
1807 0 : throw uno::RuntimeException();
1808 :
1809 0 : aCellRange.aLowerRight.nColumn = nCol;
1810 0 : aCellRange.aLowerRight.nRow = nRow;
1811 0 : aCellRange.aLowerRight.bIsEmpty = false;
1812 : }
1813 0 : String aTmp( XMLRangeHelper::getXMLStringFromCellRange( aCellRange ) );
1814 0 : if (aRes.Len()) // in case of multiple ranges add delimeter
1815 0 : aRes.AppendAscii( " " );
1816 0 : aRes += aTmp;
1817 0 : }
1818 :
1819 0 : return aRes;
1820 : }
1821 :
1822 0 : rtl::OUString SAL_CALL SwChartDataProvider::convertRangeFromXML( const rtl::OUString& rXMLRange )
1823 : throw ( uno::RuntimeException, lang::IllegalArgumentException )
1824 : {
1825 0 : SolarMutexGuard aGuard;
1826 0 : if (bDisposed)
1827 0 : throw lang::DisposedException();
1828 :
1829 0 : String aRes;
1830 0 : String aXMLRange( rXMLRange );
1831 :
1832 : // multiple ranges are delimeted by a ' ' like in
1833 : // "Table1.$A$1:.$A$4 Table1.$C$2:.$C$5" the same table must be used in all ranges!
1834 0 : xub_StrLen nNumRanges = comphelper::string::getTokenCount(aXMLRange, ' ');
1835 0 : rtl::OUString aFirstFoundTable; // to check that only one table will be used
1836 0 : for (sal_uInt16 i = 0; i < nNumRanges; ++i)
1837 : {
1838 0 : String aRange( aXMLRange.GetToken(i, ' ') );
1839 :
1840 : //!! following objects and function are implemented in XMLRangeHelper.?xx
1841 : //!! which is a copy of the respective file from chart2 !!
1842 0 : XMLRangeHelper::CellRange aCellRange( XMLRangeHelper::getCellRangeFromXMLString( aRange ));
1843 :
1844 : // check that there is only one table used in all ranges
1845 0 : if (aFirstFoundTable.isEmpty())
1846 0 : aFirstFoundTable = aCellRange.aTableName;
1847 0 : if (aCellRange.aTableName != aFirstFoundTable)
1848 0 : throw lang::IllegalArgumentException();
1849 :
1850 0 : OUString aTmp( aCellRange.aTableName );
1851 0 : aTmp += OUString::valueOf((sal_Unicode) '.');
1852 : aTmp += sw_GetCellName( aCellRange.aUpperLeft.nColumn,
1853 0 : aCellRange.aUpperLeft.nRow );
1854 : // does cell range consist of more than a single cell?
1855 0 : if (!aCellRange.aLowerRight.bIsEmpty)
1856 : {
1857 0 : aTmp += OUString::valueOf((sal_Unicode) ':');
1858 : aTmp += sw_GetCellName( aCellRange.aLowerRight.nColumn,
1859 0 : aCellRange.aLowerRight.nRow );
1860 : }
1861 :
1862 0 : if (aRes.Len()) // in case of multiple ranges add delimeter
1863 0 : aRes.AppendAscii( ";" );
1864 0 : aRes += String(aTmp);
1865 0 : }
1866 :
1867 0 : return aRes;
1868 : }
1869 :
1870 0 : SwChartDataSource::SwChartDataSource(
1871 : const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > &rLDS ) :
1872 0 : aLDS( rLDS )
1873 : {
1874 0 : }
1875 :
1876 0 : SwChartDataSource::~SwChartDataSource()
1877 : {
1878 0 : }
1879 :
1880 0 : uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > SAL_CALL SwChartDataSource::getDataSequences( )
1881 : throw (uno::RuntimeException)
1882 : {
1883 0 : SolarMutexGuard aGuard;
1884 0 : return aLDS;
1885 : }
1886 :
1887 0 : OUString SAL_CALL SwChartDataSource::getImplementationName( )
1888 : throw (uno::RuntimeException)
1889 : {
1890 0 : SolarMutexGuard aGuard;
1891 0 : return C2U("SwChartDataSource");
1892 : }
1893 :
1894 0 : sal_Bool SAL_CALL SwChartDataSource::supportsService(
1895 : const OUString& rServiceName )
1896 : throw (uno::RuntimeException)
1897 : {
1898 0 : SolarMutexGuard aGuard;
1899 0 : return rServiceName == SN_DATA_SOURCE;
1900 : }
1901 :
1902 0 : uno::Sequence< OUString > SAL_CALL SwChartDataSource::getSupportedServiceNames( )
1903 : throw (uno::RuntimeException)
1904 : {
1905 0 : SolarMutexGuard aGuard;
1906 0 : uno::Sequence< OUString > aRes(1);
1907 0 : aRes.getArray()[0] = C2U( SN_DATA_SOURCE );
1908 0 : return aRes;
1909 : }
1910 :
1911 0 : SwChartDataSequence::SwChartDataSequence(
1912 : SwChartDataProvider &rProvider,
1913 : SwFrmFmt &rTblFmt,
1914 : SwUnoCrsr *pTableCursor ) :
1915 : SwClient( &rTblFmt ),
1916 0 : aEvtListeners( GetChartMutex() ),
1917 0 : aModifyListeners( GetChartMutex() ),
1918 : aRowLabelText( SW_RES( STR_CHART2_ROW_LABEL_TEXT ) ),
1919 : aColLabelText( SW_RES( STR_CHART2_COL_LABEL_TEXT ) ),
1920 : xDataProvider( &rProvider ),
1921 : pDataProvider( &rProvider ),
1922 : pTblCrsr( pTableCursor ),
1923 : aCursorDepend( this, pTableCursor ),
1924 0 : _pPropSet( aSwMapProvider.GetPropertySet( PROPERTY_MAP_CHART2_DATA_SEQUENCE ) )
1925 : {
1926 0 : bDisposed = sal_False;
1927 :
1928 0 : acquire();
1929 : try
1930 : {
1931 0 : const SwTable* pTable = SwTable::FindTable( &rTblFmt );
1932 0 : if (pTable)
1933 : {
1934 0 : uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY );
1935 0 : pDataProvider->AddDataSequence( *pTable, xRef );
1936 0 : pDataProvider->addEventListener( dynamic_cast< lang::XEventListener * >(this) );
1937 : }
1938 : else {
1939 : OSL_FAIL( "table missing" );
1940 : }
1941 : }
1942 0 : catch (uno::RuntimeException &)
1943 : {
1944 0 : throw;
1945 : }
1946 0 : catch (uno::Exception &)
1947 : {
1948 : }
1949 0 : release();
1950 :
1951 : #if OSL_DEBUG_LEVEL > 0
1952 : // check if it can properly convert into a SwUnoTableCrsr
1953 : // which is required for some functions
1954 : SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr);
1955 : OSL_ENSURE(pUnoTblCrsr, "SwChartDataSequence: cursor not SwUnoTableCrsr");
1956 : (void) pUnoTblCrsr;
1957 : #endif
1958 0 : }
1959 :
1960 0 : SwChartDataSequence::SwChartDataSequence( const SwChartDataSequence &rObj ) :
1961 : SwChartDataSequenceBaseClass(),
1962 0 : SwClient( rObj.GetFrmFmt() ),
1963 0 : aEvtListeners( GetChartMutex() ),
1964 0 : aModifyListeners( GetChartMutex() ),
1965 : aRole( rObj.aRole ),
1966 : aRowLabelText( SW_RES(STR_CHART2_ROW_LABEL_TEXT) ),
1967 : aColLabelText( SW_RES(STR_CHART2_COL_LABEL_TEXT) ),
1968 : xDataProvider( rObj.pDataProvider ),
1969 : pDataProvider( rObj.pDataProvider ),
1970 0 : pTblCrsr( rObj.pTblCrsr->Clone() ),
1971 : aCursorDepend( this, pTblCrsr ),
1972 0 : _pPropSet( rObj._pPropSet )
1973 : {
1974 0 : bDisposed = sal_False;
1975 :
1976 0 : acquire();
1977 : try
1978 : {
1979 0 : const SwTable* pTable = SwTable::FindTable( GetFrmFmt() );
1980 0 : if (pTable)
1981 : {
1982 0 : uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY );
1983 0 : pDataProvider->AddDataSequence( *pTable, xRef );
1984 0 : pDataProvider->addEventListener( dynamic_cast< lang::XEventListener * >(this) );
1985 : }
1986 : else {
1987 : OSL_FAIL( "table missing" );
1988 : }
1989 : }
1990 0 : catch (uno::RuntimeException &)
1991 : {
1992 0 : throw;
1993 : }
1994 0 : catch (uno::Exception &)
1995 : {
1996 : }
1997 0 : release();
1998 :
1999 : #if OSL_DEBUG_LEVEL > 0
2000 : // check if it can properly convert into a SwUnoTableCrsr
2001 : // which is required for some functions
2002 : SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr);
2003 : OSL_ENSURE(pUnoTblCrsr, "SwChartDataSequence: cursor not SwUnoTableCrsr");
2004 : (void) pUnoTblCrsr;
2005 : #endif
2006 0 : }
2007 :
2008 0 : SwChartDataSequence::~SwChartDataSequence()
2009 : {
2010 : // since the data-provider holds only weak references to the data-sequence
2011 : // there should be no need here to release them explicitly...
2012 :
2013 0 : delete pTblCrsr;
2014 0 : }
2015 :
2016 : namespace
2017 : {
2018 : class theSwChartDataSequenceUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwChartDataSequenceUnoTunnelId > {};
2019 : }
2020 :
2021 0 : const uno::Sequence< sal_Int8 > & SwChartDataSequence::getUnoTunnelId()
2022 : {
2023 0 : return theSwChartDataSequenceUnoTunnelId::get().getSeq();
2024 : }
2025 :
2026 0 : sal_Int64 SAL_CALL SwChartDataSequence::getSomething( const uno::Sequence< sal_Int8 > &rId )
2027 : throw(uno::RuntimeException)
2028 : {
2029 0 : if( rId.getLength() == 16
2030 0 : && 0 == memcmp( getUnoTunnelId().getConstArray(),
2031 0 : rId.getConstArray(), 16 ) )
2032 : {
2033 0 : return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(this) );
2034 : }
2035 0 : return 0;
2036 : }
2037 :
2038 0 : uno::Sequence< uno::Any > SAL_CALL SwChartDataSequence::getData( )
2039 : throw (uno::RuntimeException)
2040 : {
2041 0 : SolarMutexGuard aGuard;
2042 0 : if (bDisposed)
2043 0 : throw lang::DisposedException();
2044 :
2045 0 : uno::Sequence< uno::Any > aRes;
2046 0 : SwFrmFmt* pTblFmt = GetFrmFmt();
2047 0 : if(pTblFmt)
2048 : {
2049 0 : SwTable* pTable = SwTable::FindTable( pTblFmt );
2050 0 : if(!pTable->IsTblComplex())
2051 : {
2052 : SwRangeDescriptor aDesc;
2053 0 : if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) ))
2054 : {
2055 : //!! make copy of pTblCrsr (SwUnoCrsr )
2056 : // keep original cursor and make copy of it that gets handed
2057 : // over to the SwXCellRange object which takes ownership and
2058 : // thus will destroy the copy later.
2059 0 : SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc );
2060 0 : aRange.GetDataSequence( &aRes, 0, 0 );
2061 : }
2062 : }
2063 : }
2064 0 : return aRes;
2065 : }
2066 :
2067 0 : OUString SAL_CALL SwChartDataSequence::getSourceRangeRepresentation( )
2068 : throw (uno::RuntimeException)
2069 : {
2070 0 : SolarMutexGuard aGuard;
2071 0 : if (bDisposed)
2072 0 : throw lang::DisposedException();
2073 :
2074 0 : String aRes;
2075 0 : SwFrmFmt* pTblFmt = GetFrmFmt();
2076 0 : if (pTblFmt)
2077 : {
2078 0 : aRes = pTblFmt->GetName();
2079 0 : String aCellRange( GetCellRangeName( *pTblFmt, *pTblCrsr ) );
2080 : OSL_ENSURE( aCellRange.Len() != 0, "failed to get cell range" );
2081 0 : aRes += (sal_Unicode) '.';
2082 0 : aRes += aCellRange;
2083 : }
2084 0 : return aRes;
2085 : }
2086 :
2087 0 : uno::Sequence< OUString > SAL_CALL SwChartDataSequence::generateLabel(
2088 : chart2::data::LabelOrigin eLabelOrigin )
2089 : throw (uno::RuntimeException)
2090 : {
2091 0 : SolarMutexGuard aGuard;
2092 0 : if (bDisposed)
2093 0 : throw lang::DisposedException();
2094 :
2095 0 : uno::Sequence< OUString > aLabels;
2096 :
2097 : {
2098 : SwRangeDescriptor aDesc;
2099 0 : bool bOk = false;
2100 0 : SwFrmFmt* pTblFmt = GetFrmFmt();
2101 0 : SwTable* pTable = pTblFmt ? SwTable::FindTable( pTblFmt ) : 0;
2102 0 : if (!pTblFmt || !pTable || pTable->IsTblComplex())
2103 0 : throw uno::RuntimeException();
2104 : else
2105 : {
2106 0 : String aCellRange( GetCellRangeName( *pTblFmt, *pTblCrsr ) );
2107 : OSL_ENSURE( aCellRange.Len() != 0, "failed to get cell range" );
2108 0 : bOk = FillRangeDescriptor( aDesc, aCellRange );
2109 0 : OSL_ENSURE( bOk, "falied to get SwRangeDescriptor" );
2110 : }
2111 0 : if (bOk)
2112 : {
2113 0 : aDesc.Normalize();
2114 0 : sal_Int32 nColSpan = aDesc.nRight - aDesc.nLeft + 1;
2115 0 : sal_Int32 nRowSpan = aDesc.nBottom - aDesc.nTop + 1;
2116 : OSL_ENSURE( nColSpan == 1 || nRowSpan == 1,
2117 : "unexpected range of selected cells" );
2118 :
2119 0 : String aTxt; // label text to be returned
2120 0 : bool bReturnEmptyTxt = false;
2121 0 : bool bUseCol = true;
2122 0 : if (eLabelOrigin == chart2::data::LabelOrigin_COLUMN)
2123 0 : bUseCol = true;
2124 0 : else if (eLabelOrigin == chart2::data::LabelOrigin_ROW)
2125 0 : bUseCol = false;
2126 0 : else if (eLabelOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
2127 : {
2128 0 : bUseCol = nColSpan < nRowSpan;
2129 0 : bReturnEmptyTxt = nColSpan == nRowSpan;
2130 : }
2131 0 : else if (eLabelOrigin == chart2::data::LabelOrigin_LONG_SIDE)
2132 : {
2133 0 : bUseCol = nColSpan > nRowSpan;
2134 0 : bReturnEmptyTxt = nColSpan == nRowSpan;
2135 : }
2136 : else {
2137 : OSL_FAIL( "unexpected case" );
2138 : }
2139 :
2140 : // build label sequence
2141 : //
2142 0 : sal_Int32 nSeqLen = bUseCol ? nColSpan : nRowSpan;
2143 0 : aLabels.realloc( nSeqLen );
2144 0 : OUString *pLabels = aLabels.getArray();
2145 0 : for (sal_Int32 i = 0; i < nSeqLen; ++i)
2146 : {
2147 0 : if (!bReturnEmptyTxt)
2148 : {
2149 0 : aTxt = bUseCol ? aColLabelText : aRowLabelText;
2150 0 : sal_Int32 nCol = aDesc.nLeft;
2151 0 : sal_Int32 nRow = aDesc.nTop;
2152 0 : if (bUseCol)
2153 0 : nCol = nCol + i;
2154 : else
2155 0 : nRow = nRow + i;
2156 0 : String aCellName( sw_GetCellName( nCol, nRow ) );
2157 :
2158 0 : xub_StrLen nLen = aCellName.Len();
2159 0 : if (nLen)
2160 : {
2161 0 : const sal_Unicode *pBuf = aCellName.GetBuffer();
2162 0 : const sal_Unicode *pEnd = pBuf + nLen;
2163 0 : while (pBuf < pEnd && !('0' <= *pBuf && *pBuf <= '9'))
2164 0 : ++pBuf;
2165 : // start of number found?
2166 0 : if (pBuf < pEnd && ('0' <= *pBuf && *pBuf <= '9'))
2167 : {
2168 0 : String aRplc;
2169 0 : String aNew;
2170 0 : if (bUseCol)
2171 : {
2172 0 : aRplc = rtl::OUString("%COLUMNLETTER");
2173 0 : aNew = rtl::OUString(aCellName.GetBuffer(), pBuf - aCellName.GetBuffer());
2174 : }
2175 : else
2176 : {
2177 0 : aRplc = rtl::OUString("%ROWNUMBER");
2178 0 : aNew = rtl::OUString(pBuf, (aCellName.GetBuffer() + nLen) - pBuf);
2179 : }
2180 0 : xub_StrLen nPos = aTxt.Search( aRplc );
2181 0 : if (nPos != STRING_NOTFOUND)
2182 0 : aTxt = aTxt.Replace( nPos, aRplc.Len(), aNew );
2183 : }
2184 0 : }
2185 : }
2186 0 : pLabels[i] = aTxt;
2187 0 : }
2188 : }
2189 : }
2190 :
2191 0 : return aLabels;
2192 : }
2193 :
2194 0 : ::sal_Int32 SAL_CALL SwChartDataSequence::getNumberFormatKeyByIndex(
2195 : ::sal_Int32 /*nIndex*/ )
2196 : throw (lang::IndexOutOfBoundsException,
2197 : uno::RuntimeException)
2198 : {
2199 0 : return 0;
2200 : }
2201 :
2202 0 : uno::Sequence< OUString > SAL_CALL SwChartDataSequence::getTextualData( )
2203 : throw (uno::RuntimeException)
2204 : {
2205 0 : SolarMutexGuard aGuard;
2206 0 : if (bDisposed)
2207 0 : throw lang::DisposedException();
2208 :
2209 0 : uno::Sequence< OUString > aRes;
2210 0 : SwFrmFmt* pTblFmt = GetFrmFmt();
2211 0 : if(pTblFmt)
2212 : {
2213 0 : SwTable* pTable = SwTable::FindTable( pTblFmt );
2214 0 : if(!pTable->IsTblComplex())
2215 : {
2216 : SwRangeDescriptor aDesc;
2217 0 : if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) ))
2218 : {
2219 : //!! make copy of pTblCrsr (SwUnoCrsr )
2220 : // keep original cursor and make copy of it that gets handed
2221 : // over to the SwXCellRange object which takes ownership and
2222 : // thus will destroy the copy later.
2223 0 : SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc );
2224 0 : aRange.GetDataSequence( 0, &aRes, 0 );
2225 : }
2226 : }
2227 : }
2228 0 : return aRes;
2229 : }
2230 :
2231 0 : uno::Sequence< double > SAL_CALL SwChartDataSequence::getNumericalData( )
2232 : throw (uno::RuntimeException)
2233 : {
2234 0 : SolarMutexGuard aGuard;
2235 0 : if (bDisposed)
2236 0 : throw lang::DisposedException();
2237 :
2238 0 : uno::Sequence< double > aRes;
2239 0 : SwFrmFmt* pTblFmt = GetFrmFmt();
2240 0 : if(pTblFmt)
2241 : {
2242 0 : SwTable* pTable = SwTable::FindTable( pTblFmt );
2243 0 : if(!pTable->IsTblComplex())
2244 : {
2245 : SwRangeDescriptor aDesc;
2246 0 : if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) ))
2247 : {
2248 : //!! make copy of pTblCrsr (SwUnoCrsr )
2249 : // keep original cursor and make copy of it that gets handed
2250 : // over to the SwXCellRange object which takes ownership and
2251 : // thus will destroy the copy later.
2252 0 : SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc );
2253 :
2254 : // get numerical values and make an effort to return the
2255 : // numerical value for text formatted cells
2256 0 : aRange.GetDataSequence( 0, 0, &aRes, sal_True );
2257 : }
2258 : }
2259 : }
2260 0 : return aRes;
2261 : }
2262 :
2263 0 : uno::Reference< util::XCloneable > SAL_CALL SwChartDataSequence::createClone( )
2264 : throw (uno::RuntimeException)
2265 : {
2266 0 : SolarMutexGuard aGuard;
2267 0 : if (bDisposed)
2268 0 : throw lang::DisposedException();
2269 0 : return new SwChartDataSequence( *this );
2270 : }
2271 :
2272 0 : uno::Reference< beans::XPropertySetInfo > SAL_CALL SwChartDataSequence::getPropertySetInfo( )
2273 : throw (uno::RuntimeException)
2274 : {
2275 0 : SolarMutexGuard aGuard;
2276 0 : if (bDisposed)
2277 0 : throw lang::DisposedException();
2278 :
2279 0 : static uno::Reference< beans::XPropertySetInfo > xRes = _pPropSet->getPropertySetInfo();
2280 0 : return xRes;
2281 : }
2282 :
2283 0 : void SAL_CALL SwChartDataSequence::setPropertyValue(
2284 : const OUString& rPropertyName,
2285 : const uno::Any& rValue )
2286 : throw (beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException)
2287 : {
2288 0 : SolarMutexGuard aGuard;
2289 0 : if (bDisposed)
2290 0 : throw lang::DisposedException();
2291 :
2292 0 : if (rPropertyName.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE )))
2293 : {
2294 0 : if ( !(rValue >>= aRole) )
2295 0 : throw lang::IllegalArgumentException();
2296 : }
2297 : else
2298 0 : throw beans::UnknownPropertyException();
2299 0 : }
2300 :
2301 0 : uno::Any SAL_CALL SwChartDataSequence::getPropertyValue(
2302 : const OUString& rPropertyName )
2303 : throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
2304 : {
2305 0 : SolarMutexGuard aGuard;
2306 0 : if (bDisposed)
2307 0 : throw lang::DisposedException();
2308 :
2309 0 : uno::Any aRes;
2310 0 : if (rPropertyName.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE )))
2311 0 : aRes <<= aRole;
2312 : else
2313 0 : throw beans::UnknownPropertyException();
2314 :
2315 0 : return aRes;
2316 : }
2317 :
2318 0 : void SAL_CALL SwChartDataSequence::addPropertyChangeListener(
2319 : const OUString& /*rPropertyName*/,
2320 : const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ )
2321 : throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
2322 : {
2323 : OSL_FAIL( "not implemented" );
2324 0 : }
2325 :
2326 0 : void SAL_CALL SwChartDataSequence::removePropertyChangeListener(
2327 : const OUString& /*rPropertyName*/,
2328 : const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ )
2329 : throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
2330 : {
2331 : OSL_FAIL( "not implemented" );
2332 0 : }
2333 :
2334 0 : void SAL_CALL SwChartDataSequence::addVetoableChangeListener(
2335 : const OUString& /*rPropertyName*/,
2336 : const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ )
2337 : throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
2338 : {
2339 : OSL_FAIL( "not implemented" );
2340 0 : }
2341 :
2342 0 : void SAL_CALL SwChartDataSequence::removeVetoableChangeListener(
2343 : const OUString& /*rPropertyName*/,
2344 : const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ )
2345 : throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
2346 : {
2347 : OSL_FAIL( "not implemented" );
2348 0 : }
2349 :
2350 0 : OUString SAL_CALL SwChartDataSequence::getImplementationName( )
2351 : throw (uno::RuntimeException)
2352 : {
2353 0 : return C2U("SwChartDataSequence");
2354 : }
2355 :
2356 0 : sal_Bool SAL_CALL SwChartDataSequence::supportsService(
2357 : const OUString& rServiceName )
2358 : throw (uno::RuntimeException)
2359 : {
2360 0 : return rServiceName == SN_DATA_SEQUENCE;
2361 : }
2362 :
2363 0 : uno::Sequence< OUString > SAL_CALL SwChartDataSequence::getSupportedServiceNames( )
2364 : throw (uno::RuntimeException)
2365 : {
2366 0 : SolarMutexGuard aGuard;
2367 0 : uno::Sequence< OUString > aRes(1);
2368 0 : aRes.getArray()[0] = C2U( SN_DATA_SEQUENCE );
2369 0 : return aRes;
2370 : }
2371 :
2372 0 : void SwChartDataSequence::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew)
2373 : {
2374 0 : ClientModify(this, pOld, pNew );
2375 :
2376 : // table was deleted or cursor was deleted
2377 0 : if(!GetRegisteredIn() || !aCursorDepend.GetRegisteredIn())
2378 : {
2379 0 : pTblCrsr = 0;
2380 0 : dispose();
2381 : }
2382 : else
2383 : {
2384 0 : setModified( sal_True );
2385 : }
2386 0 : }
2387 :
2388 0 : sal_Bool SAL_CALL SwChartDataSequence::isModified( )
2389 : throw (uno::RuntimeException)
2390 : {
2391 0 : SolarMutexGuard aGuard;
2392 0 : if (bDisposed)
2393 0 : throw lang::DisposedException();
2394 :
2395 0 : return sal_True;
2396 : }
2397 :
2398 0 : void SAL_CALL SwChartDataSequence::setModified(
2399 : ::sal_Bool bModified )
2400 : throw (beans::PropertyVetoException, uno::RuntimeException)
2401 : {
2402 0 : SolarMutexGuard aGuard;
2403 0 : if (bDisposed)
2404 0 : throw lang::DisposedException();
2405 :
2406 0 : if (bModified)
2407 0 : LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) );
2408 0 : }
2409 :
2410 0 : void SAL_CALL SwChartDataSequence::addModifyListener(
2411 : const uno::Reference< util::XModifyListener >& rxListener )
2412 : throw (uno::RuntimeException)
2413 : {
2414 0 : osl::MutexGuard aGuard( GetChartMutex() );
2415 0 : if (!bDisposed && rxListener.is())
2416 0 : aModifyListeners.addInterface( rxListener );
2417 0 : }
2418 :
2419 0 : void SAL_CALL SwChartDataSequence::removeModifyListener(
2420 : const uno::Reference< util::XModifyListener >& rxListener )
2421 : throw (uno::RuntimeException)
2422 : {
2423 0 : osl::MutexGuard aGuard( GetChartMutex() );
2424 0 : if (!bDisposed && rxListener.is())
2425 0 : aModifyListeners.removeInterface( rxListener );
2426 0 : }
2427 :
2428 0 : void SAL_CALL SwChartDataSequence::disposing( const lang::EventObject& rSource )
2429 : throw (uno::RuntimeException)
2430 : {
2431 0 : if (bDisposed)
2432 0 : throw lang::DisposedException();
2433 0 : if (rSource.Source == xDataProvider)
2434 : {
2435 0 : pDataProvider = 0;
2436 0 : xDataProvider.clear();
2437 : }
2438 0 : }
2439 :
2440 0 : void SAL_CALL SwChartDataSequence::dispose( )
2441 : throw (uno::RuntimeException)
2442 : {
2443 0 : bool bMustDispose( false );
2444 : {
2445 0 : osl::MutexGuard aGuard( GetChartMutex() );
2446 0 : bMustDispose = !bDisposed;
2447 0 : if (!bDisposed)
2448 0 : bDisposed = sal_True;
2449 : }
2450 0 : if (bMustDispose)
2451 : {
2452 0 : bDisposed = sal_True;
2453 0 : if (pDataProvider)
2454 : {
2455 0 : const SwTable* pTable = SwTable::FindTable( GetFrmFmt() );
2456 0 : if (pTable)
2457 : {
2458 0 : uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY );
2459 0 : pDataProvider->RemoveDataSequence( *pTable, xRef );
2460 : }
2461 : else {
2462 : OSL_FAIL( "table missing" );
2463 : }
2464 : }
2465 :
2466 : // require listeners to release references to this object
2467 0 : lang::EventObject aEvtObj( dynamic_cast< chart2::data::XDataSequence * >(this) );
2468 0 : aModifyListeners.disposeAndClear( aEvtObj );
2469 0 : aEvtListeners.disposeAndClear( aEvtObj );
2470 : }
2471 0 : }
2472 :
2473 0 : void SAL_CALL SwChartDataSequence::addEventListener(
2474 : const uno::Reference< lang::XEventListener >& rxListener )
2475 : throw (uno::RuntimeException)
2476 : {
2477 0 : osl::MutexGuard aGuard( GetChartMutex() );
2478 0 : if (!bDisposed && rxListener.is())
2479 0 : aEvtListeners.addInterface( rxListener );
2480 0 : }
2481 :
2482 0 : void SAL_CALL SwChartDataSequence::removeEventListener(
2483 : const uno::Reference< lang::XEventListener >& rxListener )
2484 : throw (uno::RuntimeException)
2485 : {
2486 0 : osl::MutexGuard aGuard( GetChartMutex() );
2487 0 : if (!bDisposed && rxListener.is())
2488 0 : aEvtListeners.removeInterface( rxListener );
2489 0 : }
2490 :
2491 0 : sal_Bool SwChartDataSequence::DeleteBox( const SwTableBox &rBox )
2492 : {
2493 : #if OSL_DEBUG_LEVEL > 1
2494 : String aBoxName( rBox.GetName() );
2495 : #endif
2496 :
2497 : // to be set if the last box of the data-sequence was removed here
2498 0 : sal_Bool bNowEmpty = sal_False;
2499 :
2500 : // if the implementation cursor gets affected (i.e. thew box where it is located
2501 : // in gets removed) we need to move it before that... (otherwise it does not need to change)
2502 : //
2503 0 : const SwStartNode* pPointStartNode = pTblCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
2504 0 : const SwStartNode* pMarkStartNode = pTblCrsr->GetMark()->nNode.GetNode().FindTableBoxStartNode();
2505 : //
2506 0 : if (!pTblCrsr->HasMark() || (pPointStartNode == rBox.GetSttNd() && pMarkStartNode == rBox.GetSttNd()))
2507 : {
2508 0 : bNowEmpty = sal_True;
2509 : }
2510 0 : else if (pPointStartNode == rBox.GetSttNd() || pMarkStartNode == rBox.GetSttNd())
2511 : {
2512 0 : sal_Int32 nPointRow = -1, nPointCol = -1;
2513 0 : sal_Int32 nMarkRow = -1, nMarkCol = -1;
2514 0 : const SwTable* pTable = SwTable::FindTable( GetFrmFmt() );
2515 0 : String aPointCellName( pTable->GetTblBox( pPointStartNode->GetIndex() )->GetName() );
2516 0 : String aMarkCellName( pTable->GetTblBox( pMarkStartNode->GetIndex() )->GetName() );
2517 :
2518 0 : sw_GetCellPosition( aPointCellName, nPointCol, nPointRow );
2519 0 : sw_GetCellPosition( aMarkCellName, nMarkCol, nMarkRow );
2520 : OSL_ENSURE( nPointRow >= 0 && nPointCol >= 0, "invalid row and col" );
2521 : OSL_ENSURE( nMarkRow >= 0 && nMarkCol >= 0, "invalid row and col" );
2522 :
2523 : // move vertical or horizontal?
2524 : OSL_ENSURE( nPointRow == nMarkRow || nPointCol == nMarkCol,
2525 : "row/col indices not matching" );
2526 : OSL_ENSURE( nPointRow != nMarkRow || nPointCol != nMarkCol,
2527 : "point and mark are identical" );
2528 0 : bool bMoveVertical = (nPointCol == nMarkCol);
2529 0 : bool bMoveHorizontal = (nPointRow == nMarkRow);
2530 :
2531 : // get movement direction
2532 0 : bool bMoveLeft = false; // move left or right?
2533 0 : bool bMoveUp = false; // move up or down?
2534 0 : if (bMoveVertical)
2535 : {
2536 0 : if (pPointStartNode == rBox.GetSttNd()) // move point?
2537 0 : bMoveUp = nPointRow > nMarkRow;
2538 : else // move mark
2539 0 : bMoveUp = nMarkRow > nPointRow;
2540 : }
2541 0 : else if (bMoveHorizontal)
2542 : {
2543 0 : if (pPointStartNode == rBox.GetSttNd()) // move point?
2544 0 : bMoveLeft = nPointCol > nMarkCol;
2545 : else // move mark
2546 0 : bMoveLeft = nMarkCol > nPointCol;
2547 : }
2548 : else {
2549 : OSL_FAIL( "neither vertical nor horizontal movement" );
2550 : }
2551 :
2552 : // get new box (position) to use...
2553 0 : sal_Int32 nRow = (pPointStartNode == rBox.GetSttNd()) ? nPointRow : nMarkRow;
2554 0 : sal_Int32 nCol = (pPointStartNode == rBox.GetSttNd()) ? nPointCol : nMarkCol;
2555 0 : if (bMoveVertical)
2556 0 : nRow += bMoveUp ? -1 : +1;
2557 0 : if (bMoveHorizontal)
2558 0 : nCol += bMoveLeft ? -1 : +1;
2559 0 : String aNewCellName = sw_GetCellName( nCol, nRow );
2560 0 : SwTableBox* pNewBox = (SwTableBox*) pTable->GetTblBox( aNewCellName );
2561 :
2562 0 : if (pNewBox) // set new position (cell range) to use
2563 : {
2564 : // So erh lt man den ersten Inhaltsnode in einer gegebenen Zelle:
2565 : // Zun chst einen SwNodeIndex auf den Node hinter dem SwStartNode der Box...
2566 0 : SwNodeIndex aIdx( *pNewBox->GetSttNd(), +1 );
2567 : // Dies kann ein SwCntntNode sein, kann aber auch ein Tabellen oder Sectionnode sein,
2568 : // deshalb das GoNext;
2569 0 : SwCntntNode *pCNd = aIdx.GetNode().GetCntntNode();
2570 0 : if (!pCNd)
2571 0 : pCNd = GetFrmFmt()->GetDoc()->GetNodes().GoNext( &aIdx );
2572 : //und damit kann man z.B. eine SwPosition erzeugen:
2573 0 : SwPosition aNewPos( *pCNd ); // new position to beused with cursor
2574 :
2575 : // if the mark is to be changed make sure there is one...
2576 0 : if (pMarkStartNode == rBox.GetSttNd() && !pTblCrsr->HasMark())
2577 0 : pTblCrsr->SetMark();
2578 :
2579 : // set cursor to new position...
2580 0 : SwPosition *pPos = (pPointStartNode == rBox.GetSttNd()) ?
2581 0 : pTblCrsr->GetPoint() : pTblCrsr->GetMark();
2582 0 : if (pPos)
2583 : {
2584 0 : pPos->nNode = aNewPos.nNode;
2585 0 : pPos->nContent = aNewPos.nContent;
2586 : }
2587 : else {
2588 : OSL_FAIL( "neither point nor mark available for change" );
2589 0 : }
2590 : }
2591 : else {
2592 : OSL_FAIL( "failed to get position" );
2593 0 : }
2594 : }
2595 :
2596 0 : return bNowEmpty;
2597 : }
2598 :
2599 0 : void SwChartDataSequence::FillRangeDesc( SwRangeDescriptor &rRangeDesc ) const
2600 : {
2601 0 : SwFrmFmt* pTblFmt = GetFrmFmt();
2602 0 : if(pTblFmt)
2603 : {
2604 0 : SwTable* pTable = SwTable::FindTable( pTblFmt );
2605 0 : if(!pTable->IsTblComplex())
2606 : {
2607 0 : FillRangeDescriptor( rRangeDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) );
2608 : }
2609 : }
2610 0 : }
2611 :
2612 : /**
2613 : SwChartDataSequence::ExtendTo
2614 :
2615 : extends the data-sequence by new cells added at the end of the direction
2616 : the data-sequence points to.
2617 : If the cells are already within the range of the sequence nothing needs
2618 : to be done.
2619 : If the cells are beyond the end of the sequence (are not adjacent to the
2620 : current last cell) nothing can be done. Only if the cells are adjacent to
2621 : the last cell they can be added.
2622 :
2623 : @returns true if the data-sequence was changed.
2624 : @param bExtendCols
2625 : specifies if columns or rows are to be extended
2626 : @param nFirstNew
2627 : index of first new row/col to be included in data-sequence
2628 : @param nLastNew
2629 : index of last new row/col to be included in data-sequence
2630 : */
2631 0 : bool SwChartDataSequence::ExtendTo( bool bExtendCol,
2632 : sal_Int32 nFirstNew, sal_Int32 nCount )
2633 : {
2634 0 : bool bChanged = false;
2635 :
2636 0 : SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr);
2637 : //pUnoTblCrsr->MakeBoxSels();
2638 :
2639 0 : const SwStartNode *pStartNd = 0;
2640 0 : const SwTableBox *pStartBox = 0;
2641 0 : const SwTableBox *pEndBox = 0;
2642 :
2643 0 : const SwTable* pTable = SwTable::FindTable( GetFrmFmt() );
2644 : OSL_ENSURE( !pTable->IsTblComplex(), "table too complex" );
2645 0 : if (nCount < 1 || nFirstNew < 0 || pTable->IsTblComplex())
2646 0 : return false;
2647 :
2648 : //
2649 : // get range descriptor (cell range) for current data-sequence
2650 : //
2651 0 : pStartNd = pUnoTblCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
2652 0 : pEndBox = pTable->GetTblBox( pStartNd->GetIndex() );
2653 0 : const String aEndBox( pEndBox->GetName() );
2654 : //
2655 0 : pStartNd = pUnoTblCrsr->GetMark()->nNode.GetNode().FindTableBoxStartNode();
2656 0 : pStartBox = pTable->GetTblBox( pStartNd->GetIndex() );
2657 0 : const String aStartBox( pStartBox->GetName() );
2658 : //
2659 0 : String aCellRange( aStartBox ); // note that cell range here takes the newly added rows/cols already into account
2660 0 : aCellRange.AppendAscii( ":" );
2661 0 : aCellRange += aEndBox;
2662 : SwRangeDescriptor aDesc;
2663 0 : FillRangeDescriptor( aDesc, aCellRange );
2664 :
2665 0 : String aNewStartCell;
2666 0 : String aNewEndCell;
2667 0 : if (bExtendCol && aDesc.nBottom + 1 == nFirstNew)
2668 : {
2669 : // new column cells adjacent to the bottom of the
2670 : // current data-sequence to be added...
2671 : OSL_ENSURE( aDesc.nLeft == aDesc.nRight, "data-sequence is not a column" );
2672 0 : aNewStartCell = sw_GetCellName(aDesc.nLeft, aDesc.nTop);
2673 0 : aNewEndCell = sw_GetCellName(aDesc.nRight, aDesc.nBottom + nCount);
2674 0 : bChanged = true;
2675 : }
2676 0 : else if (bExtendCol && aDesc.nTop - nCount == nFirstNew)
2677 : {
2678 : // new column cells adjacent to the top of the
2679 : // current data-sequence to be added...
2680 : OSL_ENSURE( aDesc.nLeft == aDesc.nRight, "data-sequence is not a column" );
2681 0 : aNewStartCell = sw_GetCellName(aDesc.nLeft, aDesc.nTop - nCount);
2682 0 : aNewEndCell = sw_GetCellName(aDesc.nRight, aDesc.nBottom);
2683 0 : bChanged = true;
2684 : }
2685 0 : else if (!bExtendCol && aDesc.nRight + 1 == nFirstNew)
2686 : {
2687 : // new row cells adjacent to the right of the
2688 : // current data-sequence to be added...
2689 : OSL_ENSURE( aDesc.nTop == aDesc.nBottom, "data-sequence is not a row" );
2690 0 : aNewStartCell = sw_GetCellName(aDesc.nLeft, aDesc.nTop);
2691 0 : aNewEndCell = sw_GetCellName(aDesc.nRight + nCount, aDesc.nBottom);
2692 0 : bChanged = true;
2693 : }
2694 0 : else if (!bExtendCol && aDesc.nLeft - nCount == nFirstNew)
2695 : {
2696 : // new row cells adjacent to the left of the
2697 : // current data-sequence to be added...
2698 : OSL_ENSURE( aDesc.nTop == aDesc.nBottom, "data-sequence is not a row" );
2699 0 : aNewStartCell = sw_GetCellName(aDesc.nLeft - nCount, aDesc.nTop);
2700 0 : aNewEndCell = sw_GetCellName(aDesc.nRight, aDesc.nBottom);
2701 0 : bChanged = true;
2702 : }
2703 :
2704 0 : if (bChanged)
2705 : {
2706 : // move table cursor to new start and end of data-sequence
2707 0 : const SwTableBox *pNewStartBox = pTable->GetTblBox( aNewStartCell );
2708 0 : const SwTableBox *pNewEndBox = pTable->GetTblBox( aNewEndCell );
2709 0 : pUnoTblCrsr->SetMark();
2710 0 : pUnoTblCrsr->GetPoint()->nNode = *pNewEndBox->GetSttNd();
2711 0 : pUnoTblCrsr->GetMark()->nNode = *pNewStartBox->GetSttNd();
2712 0 : pUnoTblCrsr->Move( fnMoveForward, fnGoNode );
2713 0 : pUnoTblCrsr->MakeBoxSels();
2714 : }
2715 :
2716 0 : return bChanged;
2717 : }
2718 :
2719 0 : SwChartLabeledDataSequence::SwChartLabeledDataSequence() :
2720 0 : aEvtListeners( GetChartMutex() ),
2721 0 : aModifyListeners( GetChartMutex() )
2722 : {
2723 0 : bDisposed = sal_False;
2724 0 : }
2725 :
2726 0 : SwChartLabeledDataSequence::~SwChartLabeledDataSequence()
2727 : {
2728 0 : }
2729 :
2730 0 : uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartLabeledDataSequence::getValues( )
2731 : throw (uno::RuntimeException)
2732 : {
2733 0 : SolarMutexGuard aGuard;
2734 0 : if (bDisposed)
2735 0 : throw lang::DisposedException();
2736 0 : return xData;
2737 : }
2738 :
2739 0 : void SwChartLabeledDataSequence::SetDataSequence(
2740 : uno::Reference< chart2::data::XDataSequence >& rxDest,
2741 : const uno::Reference< chart2::data::XDataSequence >& rxSource)
2742 : {
2743 0 : uno::Reference< util::XModifyListener > xML( dynamic_cast< util::XModifyListener* >(this), uno::UNO_QUERY );
2744 0 : uno::Reference< lang::XEventListener > xEL( dynamic_cast< lang::XEventListener* >(this), uno::UNO_QUERY );
2745 :
2746 : // stop listening to old data-sequence
2747 0 : uno::Reference< util::XModifyBroadcaster > xMB( rxDest, uno::UNO_QUERY );
2748 0 : if (xMB.is())
2749 0 : xMB->removeModifyListener( xML );
2750 0 : uno::Reference< lang::XComponent > xC( rxDest, uno::UNO_QUERY );
2751 0 : if (xC.is())
2752 0 : xC->removeEventListener( xEL );
2753 :
2754 0 : rxDest = rxSource;
2755 :
2756 : // start listening to new data-sequence
2757 0 : xC = uno::Reference< lang::XComponent >( rxDest, uno::UNO_QUERY );
2758 0 : if (xC.is())
2759 0 : xC->addEventListener( xEL );
2760 0 : xMB = uno::Reference< util::XModifyBroadcaster >( rxDest, uno::UNO_QUERY );
2761 0 : if (xMB.is())
2762 0 : xMB->addModifyListener( xML );
2763 0 : }
2764 :
2765 0 : void SAL_CALL SwChartLabeledDataSequence::setValues(
2766 : const uno::Reference< chart2::data::XDataSequence >& rxSequence )
2767 : throw (uno::RuntimeException)
2768 : {
2769 0 : SolarMutexGuard aGuard;
2770 0 : if (bDisposed)
2771 0 : throw lang::DisposedException();
2772 :
2773 0 : if (xData != rxSequence)
2774 : {
2775 0 : SetDataSequence( xData, rxSequence );
2776 : // inform listeners of changes
2777 0 : LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) );
2778 0 : }
2779 0 : }
2780 :
2781 0 : uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartLabeledDataSequence::getLabel( )
2782 : throw (uno::RuntimeException)
2783 : {
2784 0 : SolarMutexGuard aGuard;
2785 0 : if (bDisposed)
2786 0 : throw lang::DisposedException();
2787 0 : return xLabels;
2788 : }
2789 :
2790 0 : void SAL_CALL SwChartLabeledDataSequence::setLabel(
2791 : const uno::Reference< chart2::data::XDataSequence >& rxSequence )
2792 : throw (uno::RuntimeException)
2793 : {
2794 0 : SolarMutexGuard aGuard;
2795 0 : if (bDisposed)
2796 0 : throw lang::DisposedException();
2797 :
2798 0 : if (xLabels != rxSequence)
2799 : {
2800 0 : SetDataSequence( xLabels, rxSequence );
2801 : // inform listeners of changes
2802 0 : LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) );
2803 0 : }
2804 0 : }
2805 :
2806 0 : uno::Reference< util::XCloneable > SAL_CALL SwChartLabeledDataSequence::createClone( )
2807 : throw (uno::RuntimeException)
2808 : {
2809 0 : SolarMutexGuard aGuard;
2810 0 : if (bDisposed)
2811 0 : throw lang::DisposedException();
2812 :
2813 0 : uno::Reference< util::XCloneable > xRes;
2814 :
2815 0 : uno::Reference< util::XCloneable > xDataCloneable( xData, uno::UNO_QUERY );
2816 0 : uno::Reference< util::XCloneable > xLabelsCloneable( xLabels, uno::UNO_QUERY );
2817 0 : SwChartLabeledDataSequence *pRes = new SwChartLabeledDataSequence();
2818 0 : if (xDataCloneable.is())
2819 : {
2820 0 : uno::Reference< chart2::data::XDataSequence > xDataClone( xDataCloneable->createClone(), uno::UNO_QUERY );
2821 0 : pRes->setValues( xDataClone );
2822 : }
2823 :
2824 0 : if (xLabelsCloneable.is())
2825 : {
2826 0 : uno::Reference< chart2::data::XDataSequence > xLabelsClone( xLabelsCloneable->createClone(), uno::UNO_QUERY );
2827 0 : pRes->setLabel( xLabelsClone );
2828 : }
2829 0 : xRes = pRes;
2830 0 : return xRes;
2831 : }
2832 :
2833 0 : OUString SAL_CALL SwChartLabeledDataSequence::getImplementationName( )
2834 : throw (uno::RuntimeException)
2835 : {
2836 0 : return C2U("SwChartLabeledDataSequence");
2837 : }
2838 :
2839 0 : sal_Bool SAL_CALL SwChartLabeledDataSequence::supportsService(
2840 : const OUString& rServiceName )
2841 : throw (uno::RuntimeException)
2842 : {
2843 0 : return rServiceName == SN_LABELED_DATA_SEQUENCE;
2844 : }
2845 :
2846 0 : uno::Sequence< OUString > SAL_CALL SwChartLabeledDataSequence::getSupportedServiceNames( )
2847 : throw (uno::RuntimeException)
2848 : {
2849 0 : SolarMutexGuard aGuard;
2850 0 : uno::Sequence< OUString > aRes(1);
2851 0 : aRes.getArray()[0] = C2U( SN_LABELED_DATA_SEQUENCE );
2852 0 : return aRes;
2853 : }
2854 :
2855 0 : void SAL_CALL SwChartLabeledDataSequence::disposing(
2856 : const lang::EventObject& rSource )
2857 : throw (uno::RuntimeException)
2858 : {
2859 0 : osl::MutexGuard aGuard( GetChartMutex() );
2860 0 : uno::Reference< uno::XInterface > xRef( rSource.Source );
2861 0 : if (xRef == xData)
2862 0 : xData.clear();
2863 0 : if (xRef == xLabels)
2864 0 : xLabels.clear();
2865 0 : if (!xData.is() && !xLabels.is())
2866 0 : dispose();
2867 0 : }
2868 :
2869 0 : void SAL_CALL SwChartLabeledDataSequence::modified(
2870 : const lang::EventObject& rEvent )
2871 : throw (uno::RuntimeException)
2872 : {
2873 0 : if (rEvent.Source == xData || rEvent.Source == xLabels)
2874 : {
2875 0 : LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) );
2876 : }
2877 0 : }
2878 :
2879 0 : void SAL_CALL SwChartLabeledDataSequence::addModifyListener(
2880 : const uno::Reference< util::XModifyListener >& rxListener )
2881 : throw (uno::RuntimeException)
2882 : {
2883 0 : osl::MutexGuard aGuard( GetChartMutex() );
2884 0 : if (!bDisposed && rxListener.is())
2885 0 : aModifyListeners.addInterface( rxListener );
2886 0 : }
2887 :
2888 0 : void SAL_CALL SwChartLabeledDataSequence::removeModifyListener(
2889 : const uno::Reference< util::XModifyListener >& rxListener )
2890 : throw (uno::RuntimeException)
2891 : {
2892 0 : osl::MutexGuard aGuard( GetChartMutex() );
2893 0 : if (!bDisposed && rxListener.is())
2894 0 : aModifyListeners.removeInterface( rxListener );
2895 0 : }
2896 :
2897 0 : void SAL_CALL SwChartLabeledDataSequence::dispose( )
2898 : throw (uno::RuntimeException)
2899 : {
2900 0 : bool bMustDispose( false );
2901 : {
2902 0 : osl::MutexGuard aGuard( GetChartMutex() );
2903 0 : bMustDispose = !bDisposed;
2904 0 : if (!bDisposed)
2905 0 : bDisposed = sal_True;
2906 : }
2907 0 : if (bMustDispose)
2908 : {
2909 0 : bDisposed = sal_True;
2910 :
2911 : // require listeners to release references to this object
2912 0 : lang::EventObject aEvtObj( dynamic_cast< chart2::data::XLabeledDataSequence * >(this) );
2913 0 : aModifyListeners.disposeAndClear( aEvtObj );
2914 0 : aEvtListeners.disposeAndClear( aEvtObj );
2915 : }
2916 0 : }
2917 :
2918 0 : void SAL_CALL SwChartLabeledDataSequence::addEventListener(
2919 : const uno::Reference< lang::XEventListener >& rxListener )
2920 : throw (uno::RuntimeException)
2921 : {
2922 0 : osl::MutexGuard aGuard( GetChartMutex() );
2923 0 : if (!bDisposed && rxListener.is())
2924 0 : aEvtListeners.addInterface( rxListener );
2925 0 : }
2926 :
2927 0 : void SAL_CALL SwChartLabeledDataSequence::removeEventListener(
2928 : const uno::Reference< lang::XEventListener >& rxListener )
2929 : throw (uno::RuntimeException)
2930 : {
2931 0 : osl::MutexGuard aGuard( GetChartMutex() );
2932 0 : if (!bDisposed && rxListener.is())
2933 0 : aEvtListeners.removeInterface( rxListener );
2934 0 : }
2935 :
2936 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|