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