Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/unocore/unochart.cxx
Warning:line 1603, column 36
The left operand of '==' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name unochart.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/unocore/unochart.cxx

/home/maarten/src/libreoffice/core/sw/source/core/unocore/unochart.cxx

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

/home/maarten/src/libreoffice/core/include/com/sun/star/uno/Reference.h

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#ifndef INCLUDED_COM_SUN_STAR_UNO_REFERENCE_H
20#define INCLUDED_COM_SUN_STAR_UNO_REFERENCE_H
21
22#include "sal/config.h"
23
24#include <cassert>
25#include <cstddef>
26
27#if defined LIBO_INTERNAL_ONLY1
28#include <type_traits>
29#endif
30
31#include "rtl/alloc.h"
32
33namespace com
34{
35namespace sun
36{
37namespace star
38{
39namespace uno
40{
41
42class RuntimeException;
43class XInterface;
44class Type;
45class Any;
46
47/** Enum defining UNO_REF_NO_ACQUIRE for setting reference without acquiring a given interface.
48 Deprecated, please use SAL_NO_ACQUIRE.
49 @deprecated
50*/
51enum UnoReference_NoAcquire
52{
53 /** This enum value can be used for creating a reference granting a given interface,
54 i.e. transferring ownership to it.
55 */
56 UNO_REF_NO_ACQUIRE
57};
58
59/** This base class serves as a base class for all template reference classes and
60 has been introduced due to compiler problems with templated operators ==, =!.
61*/
62class BaseReference
63{
64protected:
65 /** the interface pointer
66 */
67 XInterface * _pInterface;
68
69 /** Queries given interface for type rType.
70
71 @param pInterface interface pointer
72 @param rType interface type
73 @return interface of demanded type (may be null)
74 */
75 inline static XInterface * SAL_CALL iquery( XInterface * pInterface, const Type & rType );
76 /** Queries given interface for type rType.
77 Throws a RuntimeException if the demanded interface cannot be queried.
78
79 @param pInterface interface pointer
80 @param rType interface type
81 @return interface of demanded type
82 */
83 inline static XInterface * SAL_CALL iquery_throw( XInterface * pInterface, const Type & rType );
84
85public:
86 /** Gets interface pointer. This call does not acquire the interface.
87
88 @return UNacquired interface pointer
89 */
90 XInterface * SAL_CALL get() const
91 { return _pInterface; }
92
93 /** Checks if reference is null.
94
95 @return true if reference acquires an interface, i.e. true if it is not null
96 */
97 bool SAL_CALL is() const
98 { return (NULL__null != _pInterface); }
16
Assuming NULL is not equal to field '_pInterface'
17
Returning the value 1, which participates in a condition later
99
100#if defined LIBO_INTERNAL_ONLY1
101 /** Checks if reference is null.
102
103 @return true if reference acquires an interface, i.e. true if it is not null
104 */
105 explicit operator bool() const
106 { return is(); }
107#endif
108
109 /** Equality operator: compares two interfaces
110 Checks if both references are null or refer to the same object.
111
112 @param pInterface another interface
113 @return true if both references are null or refer to the same object, false otherwise
114 */
115 inline bool SAL_CALL operator == ( XInterface * pInterface ) const;
116 /** Inequality operator: compares two interfaces
117 Checks if both references are null or refer to the same object.
118
119 @param pInterface another interface
120 @return false if both references are null or refer to the same object, true otherwise
121 */
122 inline bool SAL_CALL operator != ( XInterface * pInterface ) const;
123
124 /** Equality operator: compares two interfaces
125 Checks if both references are null or refer to the same object.
126
127 @param rRef another reference
128 @return true if both references are null or refer to the same object, false otherwise
129 */
130 inline bool SAL_CALL operator == ( const BaseReference & rRef ) const;
131 /** Inequality operator: compares two interfaces
132 Checks if both references are null or refer to the same object.
133
134 @param rRef another reference
135 @return false if both references are null or refer to the same object, true otherwise
136 */
137 inline bool SAL_CALL operator != ( const BaseReference & rRef ) const;
138
139 /** Needed by some STL containers.
140
141 @param rRef another reference
142 @return true, if this reference is less than rRef
143 */
144 inline bool SAL_CALL operator < ( const BaseReference & rRef ) const;
145};
146
147/** Enum defining UNO_QUERY for implicit interface query.
148*/
149enum UnoReference_Query
150{
151 /** This enum value can be used for implicit interface query.
152 */
153 UNO_QUERY
154};
155/** Enum defining UNO_QUERY_THROW for implicit interface query.
156 If the demanded interface is unavailable, then a RuntimeException is thrown.
157*/
158enum UnoReference_QueryThrow
159{
160 /** This enum value can be used for implicit interface query.
161 */
162 UNO_QUERY_THROW
163};
164/** Enum defining UNO_SET_THROW for throwing if attempts are made to assign a null
165 interface
166
167 @since UDK 3.2.8
168*/
169enum UnoReference_SetThrow
170{
171 UNO_SET_THROW
172};
173
174/** Template reference class for interface type derived from BaseReference.
175 A special constructor given the UNO_QUERY identifier queries interfaces
176 for reference type.
177*/
178template< class interface_type >
179class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) Reference : public BaseReference
180{
181 /** Queries given interface for type interface_type.
182
183 @param pInterface interface pointer
184 @return interface of demanded type (may be null)
185 */
186 inline static XInterface * SAL_CALL iquery( XInterface * pInterface );
187 /** Queries given interface for type interface_type.
188 Throws a RuntimeException if the demanded interface cannot be queried.
189
190 @param pInterface interface pointer
191 @return interface of demanded type
192 */
193 inline static XInterface * SAL_CALL iquery_throw( XInterface * pInterface );
194 /** Returns the given interface if it is not <NULL/>, throws a RuntimeException otherwise.
195
196 @param pInterface interface pointer
197 @return pInterface
198 */
199 inline static interface_type * SAL_CALL iset_throw( interface_type * pInterface );
200
201 /** Cast from an "interface pointer" (e.g., BaseReference::_pInterface) to a
202 pointer to this interface_type.
203
204 To work around ambiguities in the case of multiple-inheritance interface
205 types (which inherit XInterface more than once), use reinterpret_cast
206 (resp. a sequence of two static_casts, to avoid warnings about
207 reinterpret_cast used between related classes) to switch from a pointer
208 to XInterface to a pointer to this derived interface_type. In
209 principle, this is not guaranteed to work. In practice, it seems to
210 work on all supported platforms.
211 */
212 static interface_type * castFromXInterface(XInterface * p) {
213 return static_cast< interface_type * >(static_cast< void * >(p));
214 }
215
216 /** Cast from a pointer to this interface_type to an "interface pointer"
217 (e.g., BaseReference::_pInterface).
218
219 To work around ambiguities in the case of multiple-inheritance interface
220 types (which inherit XInterface more than once), use reinterpret_cast
221 (resp. a sequence of two static_casts, to avoid warnings about
222 reinterpret_cast used between related classes) to switch from a pointer
223 to this derived interface_type to a pointer to XInterface. In
224 principle, this is not guaranteed to work. In practice, it seems to
225 work on all supported platforms.
226 */
227 static XInterface * castToXInterface(interface_type * p) {
228 return static_cast< XInterface * >(static_cast< void * >(p));
229 }
230
231public:
232 /// @cond INTERNAL
233 // these are here to force memory de/allocation to sal lib.
234 static void * SAL_CALL operator new ( ::size_t nSize )
235 { return ::rtl_allocateMemory( nSize ); }
236 static void SAL_CALL operator delete ( void * pMem )
237 { ::rtl_freeMemory( pMem ); }
238 static void * SAL_CALL operator new ( ::size_t, void * pMem )
239 { return pMem; }
240 static void SAL_CALL operator delete ( void *, void * )
241 {}
242 /// @endcond
243
244 /** Destructor: Releases interface if set.
245 */
246 inline ~Reference() COVERITY_NOEXCEPT_FALSE;
247
248 /** Default Constructor: Sets null reference.
249 */
250 inline Reference();
251
252 /** Copy constructor: Copies interface reference.
253
254 @param rRef another reference
255 */
256 inline Reference( const Reference< interface_type > & rRef );
257
258#if defined LIBO_INTERNAL_ONLY1
259 /** Move constructor
260
261 @param rRef another reference
262 */
263 inline Reference( Reference< interface_type > && rRef ) noexcept;
264
265 /** Up-casting conversion constructor: Copies interface reference.
266
267 Does not work for up-casts to ambiguous bases. For the special case of
268 up-casting to Reference< XInterface >, see the corresponding conversion
269 operator.
270
271 @param rRef another reference
272 */
273 template< class derived_type >
274 inline Reference(
275 const Reference< derived_type > & rRef,
276 std::enable_if_t<
277 std::is_base_of_v<interface_type, derived_type>
278 && !std::is_same_v<interface_type, XInterface>, void *> = nullptr);
279#endif
280
281 /** Constructor: Sets given interface pointer.
282
283 @param pInterface an interface pointer
284 */
285 inline Reference( interface_type * pInterface );
286
287 /** Constructor: Sets given interface pointer without acquiring it.
288
289 @param pInterface another reference
290 @param dummy SAL_NO_ACQUIRE to force obvious distinction to other constructors
291 */
292 inline Reference( interface_type * pInterface, __sal_NoAcquire dummy);
293 /** Constructor: Sets given interface pointer without acquiring it.
294 Deprecated, please use SAL_NO_ACQUIRE version.
295
296 @deprecated
297 @param pInterface another reference
298 @param dummy UNO_REF_NO_ACQUIRE to force obvious distinction to other constructors
299 */
300 inline SAL_DEPRECATED("use SAL_NO_ACQUIRE version")__attribute__((deprecated("use SAL_NO_ACQUIRE version"))) Reference( interface_type * pInterface, UnoReference_NoAcquire dummy );
301
302 /** Constructor: Queries given interface for reference interface type (interface_type).
303
304 @param rRef another reference
305 @param dummy UNO_QUERY to force obvious distinction to other constructors
306 */
307 inline Reference( const BaseReference & rRef, UnoReference_Query dummy );
308 /** Constructor: Queries given interface for reference interface type (interface_type).
309
310 @param pInterface an interface pointer
311 @param dummy UNO_QUERY to force obvious distinction to other constructors
312 */
313 inline Reference( XInterface * pInterface, UnoReference_Query dummy);
314 /** Constructor: Queries given any for reference interface type (interface_type).
315
316 @param rAny an any
317 @param dummy UNO_QUERY to force obvious distinction to other constructors
318 */
319 inline Reference( const Any & rAny, UnoReference_Query dummy);
320 /** Constructor: Queries given interface for reference interface type (interface_type).
321 Throws a RuntimeException if the demanded interface cannot be queried.
322
323 @param rRef another reference
324 @param dummy UNO_QUERY_THROW to force obvious distinction
325 to other constructors
326 */
327 inline Reference( const BaseReference & rRef, UnoReference_QueryThrow dummy );
328#ifdef LIBO_INTERNAL_ONLY1
329 /**
330 Prevent code from calling the QUERY_THROW constructor, when they meant to use the SET_THROW constructor.
331 */
332 Reference( const Reference< interface_type > & rRef, UnoReference_QueryThrow dummy ) = delete;
333#endif
334 /** Constructor: Queries given interface for reference interface type (interface_type).
335 Throws a RuntimeException if the demanded interface cannot be queried.
336
337 @param pInterface an interface pointer
338 @param dummy UNO_QUERY_THROW to force obvious distinction
339 to other constructors
340 */
341 inline Reference( XInterface * pInterface, UnoReference_QueryThrow dummy );
342 /** Constructor: Queries given any for reference interface type (interface_type).
343 Throws a RuntimeException if the demanded interface cannot be queried.
344
345 @param rAny an any
346 @param dummy UNO_QUERY_THROW to force obvious distinction
347 to other constructors
348 */
349 inline Reference( const Any & rAny, UnoReference_QueryThrow dummy );
350 /** Constructor: assigns from the given interface of the same type. Throws a RuntimeException
351 if the source interface is NULL.
352
353 @param rRef another interface reference of the same type
354 @param dummy UNO_SET_THROW to distinguish from default copy constructor
355
356 @since UDK 3.2.8
357 */
358 inline Reference( const Reference< interface_type > & rRef, UnoReference_SetThrow dummy );
359 /** Constructor: assigns from the given interface of the same type. Throws a RuntimeException
360 if the source interface is NULL.
361
362 @param pInterface an interface pointer
363 @param dummy UNO_SET_THROW to distinguish from default assignment constructor
364
365 @since UDK 3.2.8
366 */
367 inline Reference( interface_type * pInterface, UnoReference_SetThrow dummy );
368
369 /** Cast operator to Reference< XInterface >: Reference objects are binary compatible and
370 any interface must be derived from com.sun.star.uno.XInterface.
371 This a useful direct cast possibility.
372 */
373 SAL_CALL operator const Reference< XInterface > & () const
374 { return * reinterpret_cast< const Reference< XInterface > * >( this ); }
375
376 /** Dereference operator: Used to call interface methods.
377
378 @return UNacquired interface pointer
379 */
380 interface_type * SAL_CALL operator -> () const {
381 assert(_pInterface != NULL)(static_cast <bool> (_pInterface != __null) ? void (0) :
__assert_fail ("_pInterface != NULL", "/home/maarten/src/libreoffice/core/include/com/sun/star/uno/Reference.h"
, 381, __extension__ __PRETTY_FUNCTION__))
;
382 return castFromXInterface(_pInterface);
383 }
384
385 /** Indirection operator.
386
387 @since LibreOffice 6.3
388 @return UNacquired interface reference
389 */
390 interface_type & SAL_CALL operator * () const {
391 assert(_pInterface != NULL)(static_cast <bool> (_pInterface != __null) ? void (0) :
__assert_fail ("_pInterface != NULL", "/home/maarten/src/libreoffice/core/include/com/sun/star/uno/Reference.h"
, 391, __extension__ __PRETTY_FUNCTION__))
;
392 return *castFromXInterface(_pInterface);
393 }
394
395 /** Gets interface pointer. This call does not acquire the interface.
396
397 @return UNacquired interface pointer
398 */
399 interface_type * SAL_CALL get() const
400 { return castFromXInterface(_pInterface); }
401
402 /** Clears reference, i.e. releases interface. Reference is null after clear() call.
403 */
404 inline void SAL_CALL clear();
405
406 /** Sets the given interface. An interface already set will be released.
407
408 @param rRef another reference
409 @return true, if non-null interface was set
410 */
411 inline bool SAL_CALL set( const Reference< interface_type > & rRef );
412 /** Sets the given interface. An interface already set will be released.
413
414 @param pInterface another interface
415 @return true, if non-null interface was set
416 */
417 inline bool SAL_CALL set( interface_type * pInterface );
418
419 /** Sets interface pointer without acquiring it. An interface already set will be released.
420
421 @param pInterface an interface pointer
422 @param dummy SAL_NO_ACQUIRE to force obvious distinction to set methods
423 @return true, if non-null interface was set
424 */
425 inline bool SAL_CALL set( interface_type * pInterface, __sal_NoAcquire dummy);
426 /** Sets interface pointer without acquiring it. An interface already set will be released.
427 Deprecated, please use SAL_NO_ACQUIRE version.
428
429 @deprecated
430 @param pInterface an interface pointer
431 @param dummy UNO_REF_NO_ACQUIRE to force obvious distinction to set methods
432 @return true, if non-null interface was set
433 */
434 inline SAL_DEPRECATED("use SAL_NO_ACQUIRE version")__attribute__((deprecated("use SAL_NO_ACQUIRE version"))) bool SAL_CALL set( interface_type * pInterface, UnoReference_NoAcquire dummy);
435
436 /** Queries given interface for reference interface type (interface_type) and sets it.
437 An interface already set will be released.
438
439 @param pInterface an interface pointer
440 @param dummy UNO_QUERY to force obvious distinction to set methods
441 @return true, if non-null interface was set
442 */
443 inline bool SAL_CALL set( XInterface * pInterface, UnoReference_Query dummy );
444 /** Queries given interface for reference interface type (interface_type) and sets it.
445 An interface already set will be released.
446
447 @param rRef another reference
448 @param dummy UNO_QUERY to force obvious distinction to set methods
449 @return true, if non-null interface was set
450 */
451 inline bool SAL_CALL set( const BaseReference & rRef, UnoReference_Query dummy);
452
453 /** Queries given any for reference interface type (interface_type)
454 and sets it. An interface already set will be released.
455
456 @param rAny
457 an Any containing an interface
458 @param dummy
459 UNO_QUERY to force obvious distinction
460 to set methods
461 @return
462 true, if non-null interface was set
463 */
464 inline bool set( Any const & rAny, UnoReference_Query dummy );
465
466 /** Queries given interface for reference interface type (interface_type) and sets it.
467 An interface already set will be released.
468 Throws a RuntimeException if the demanded interface cannot be set.
469
470 @param pInterface an interface pointer
471 @param dummy UNO_QUERY_THROW to force obvious distinction
472 to set methods
473 */
474 inline void SAL_CALL set( XInterface * pInterface, UnoReference_QueryThrow dummy );
475 /** Queries given interface for reference interface type (interface_type) and sets it.
476 An interface already set will be released.
477 Throws a RuntimeException if the demanded interface cannot be set.
478
479 @param rRef another reference
480 @param dummy UNO_QUERY_THROW to force obvious distinction
481 to set methods
482 */
483 inline void SAL_CALL set( const BaseReference & rRef, UnoReference_QueryThrow dummy );
484#ifdef LIBO_INTERNAL_ONLY1
485 /**
486 Prevent code from calling the QUERY_THROW version, when they meant to use the SET_THROW version.
487 */
488 void set( const Reference< interface_type > & rRef, UnoReference_QueryThrow dummy ) = delete;
489#endif
490
491 /** Queries given any for reference interface type (interface_type) and
492 sets it. An interface already set will be released.
493 Throws a RuntimeException if the demanded interface cannot be set.
494
495 @param rAny
496 an Any containing an interface
497 @param dummy
498 UNO_QUERY_THROW to force obvious distinction to set methods
499 */
500 inline void set( Any const & rAny, UnoReference_QueryThrow dummy);
501 /** sets the given interface
502 An interface already set will be released.
503 Throws a RuntimeException if the source interface is @b NULL.
504
505 @param pInterface an interface pointer
506 @param dummy UNO_SET_THROW to force obvious distinction to other set methods
507
508 @since UDK 3.2.8
509 */
510 inline void SAL_CALL set( interface_type * pInterface, UnoReference_SetThrow dummy);
511 /** sets the given interface
512 An interface already set will be released.
513 Throws a RuntimeException if the source interface is @b NULL.
514
515 @param rRef an interface reference
516 @param dummy UNO_SET_THROW to force obvious distinction to other set methods
517
518 @since UDK 3.2.8
519 */
520 inline void SAL_CALL set( const Reference< interface_type > & rRef, UnoReference_SetThrow dummy);
521
522
523 /** Assignment operator: Acquires given interface pointer and sets reference.
524 An interface already set will be released.
525
526 @param pInterface an interface pointer
527 @return this reference
528 */
529 inline Reference< interface_type > & SAL_CALL operator = ( interface_type * pInterface );
530 /** Assignment operator: Acquires given interface reference and sets reference.
531 An interface already set will be released.
532
533 @param rRef an interface reference
534 @return this reference
535 */
536 inline Reference< interface_type > & SAL_CALL operator = ( const Reference< interface_type > & rRef );
537#if defined LIBO_INTERNAL_ONLY1
538 /** Assignment move operator: Acquires given interface reference and sets reference.
539 An interface already set will be released.
540
541 @param rRef an interface reference
542 @return this reference
543 */
544 inline Reference< interface_type > & SAL_CALL operator = ( Reference< interface_type > && rRef ) noexcept;
545#endif
546 /** Queries given interface reference for type interface_type.
547
548 @param rRef interface reference
549 @return interface reference of demanded type (may be null)
550 */
551 SAL_WARN_UNUSED_RESULT[[nodiscard]] inline static Reference< interface_type > SAL_CALL query( const BaseReference & rRef );
552 /** Queries given interface for type interface_type.
553
554 @param pInterface interface pointer
555 @return interface reference of demanded type (may be null)
556 */
557 SAL_WARN_UNUSED_RESULT[[nodiscard]] inline static Reference< interface_type > SAL_CALL query( XInterface * pInterface );
558};
559
560}
561}
562}
563}
564
565#endif
566
567/* vim:set shiftwidth=4 softtabstop=4 expandtab: */