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