File: | home/maarten/src/libreoffice/core/include/tools/ref.hxx |
Warning: | line 56, column 30 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 <com/sun/star/util/XModifiable.hpp> | |||
21 | #include <com/sun/star/chart/ChartDataRowSource.hpp> | |||
22 | #include <com/sun/star/chart2/XChartDocument.hpp> | |||
23 | #include <com/sun/star/chart2/data/XDataProvider.hpp> | |||
24 | #include <com/sun/star/chart2/data/XDataReceiver.hpp> | |||
25 | #include <com/sun/star/embed/XEmbeddedObject.hpp> | |||
26 | ||||
27 | #include <sfx2/objsh.hxx> | |||
28 | #include <svx/svditer.hxx> | |||
29 | #include <svx/svdoole2.hxx> | |||
30 | #include <svtools/embedhlp.hxx> | |||
31 | ||||
32 | #include <document.hxx> | |||
33 | #include <table.hxx> | |||
34 | #include <drwlayer.hxx> | |||
35 | #include <chartlis.hxx> | |||
36 | #include <chartlock.hxx> | |||
37 | #include <refupdat.hxx> | |||
38 | ||||
39 | #include <miscuno.hxx> | |||
40 | #include <chart2uno.hxx> | |||
41 | #include <charthelper.hxx> | |||
42 | ||||
43 | using namespace ::com::sun::star; | |||
44 | ||||
45 | static void lcl_GetChartParameters( const uno::Reference< chart2::XChartDocument >& xChartDoc, | |||
46 | OUString& rRanges, chart::ChartDataRowSource& rDataRowSource, | |||
47 | bool& rHasCategories, bool& rFirstCellAsLabel ) | |||
48 | { | |||
49 | rHasCategories = rFirstCellAsLabel = false; // default if not in sequence | |||
50 | ||||
51 | uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, uno::UNO_QUERY ); | |||
52 | ||||
53 | uno::Reference< chart2::data::XDataSource > xDataSource = xReceiver->getUsedData(); | |||
54 | uno::Reference< chart2::data::XDataProvider > xProvider = xChartDoc->getDataProvider(); | |||
55 | ||||
56 | if ( !xProvider.is() ) | |||
57 | return; | |||
58 | ||||
59 | const uno::Sequence< beans::PropertyValue > aArgs( xProvider->detectArguments( xDataSource ) ); | |||
60 | ||||
61 | for (const beans::PropertyValue& rProp : aArgs) | |||
62 | { | |||
63 | OUString aPropName(rProp.Name); | |||
64 | ||||
65 | if ( aPropName == "CellRangeRepresentation" ) | |||
66 | rProp.Value >>= rRanges; | |||
67 | else if ( aPropName == "DataRowSource" ) | |||
68 | rDataRowSource = static_cast<chart::ChartDataRowSource>(ScUnoHelpFunctions::GetEnumFromAny( rProp.Value )); | |||
69 | else if ( aPropName == "HasCategories" ) | |||
70 | rHasCategories = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value ); | |||
71 | else if ( aPropName == "FirstCellAsLabel" ) | |||
72 | rFirstCellAsLabel = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value ); | |||
73 | } | |||
74 | } | |||
75 | ||||
76 | static void lcl_SetChartParameters( const uno::Reference< chart2::data::XDataReceiver >& xReceiver, | |||
77 | const OUString& rRanges, chart::ChartDataRowSource eDataRowSource, | |||
78 | bool bHasCategories, bool bFirstCellAsLabel ) | |||
79 | { | |||
80 | if ( !xReceiver.is() ) | |||
81 | return; | |||
82 | ||||
83 | uno::Sequence< beans::PropertyValue > aArgs( 4 ); | |||
84 | aArgs[0] = beans::PropertyValue( | |||
85 | "CellRangeRepresentation", -1, | |||
86 | uno::makeAny( rRanges ), beans::PropertyState_DIRECT_VALUE ); | |||
87 | aArgs[1] = beans::PropertyValue( | |||
88 | "HasCategories", -1, | |||
89 | uno::makeAny( bHasCategories ), beans::PropertyState_DIRECT_VALUE ); | |||
90 | aArgs[2] = beans::PropertyValue( | |||
91 | "FirstCellAsLabel", -1, | |||
92 | uno::makeAny( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE ); | |||
93 | aArgs[3] = beans::PropertyValue( | |||
94 | "DataRowSource", -1, | |||
95 | uno::makeAny( eDataRowSource ), beans::PropertyState_DIRECT_VALUE ); | |||
96 | xReceiver->setArguments( aArgs ); | |||
97 | } | |||
98 | ||||
99 | bool ScDocument::HasChartAtPoint( SCTAB nTab, const Point& rPos, OUString& rName ) | |||
100 | { | |||
101 | if (mpDrawLayer && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]) | |||
102 | { | |||
103 | SdrPage* pPage = mpDrawLayer->GetPage(static_cast<sal_uInt16>(nTab)); | |||
104 | OSL_ENSURE(pPage,"Page ?")do { if (true && (!(pPage))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/documen5.cxx" ":" "104" ": "), "%s", "Page ?"); } } while (false); | |||
105 | ||||
106 | SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); | |||
107 | SdrObject* pObject = aIter.Next(); | |||
108 | while (pObject) | |||
109 | { | |||
110 | if ( pObject->GetObjIdentifier() == OBJ_OLE2 && | |||
111 | pObject->GetCurrentBoundRect().IsInside(rPos) ) | |||
112 | { | |||
113 | // also Chart-Objects that are not in the Collection | |||
114 | ||||
115 | if (IsChart(pObject)) | |||
116 | { | |||
117 | rName = static_cast<SdrOle2Obj*>(pObject)->GetPersistName(); | |||
118 | return true; | |||
119 | } | |||
120 | } | |||
121 | pObject = aIter.Next(); | |||
122 | } | |||
123 | } | |||
124 | ||||
125 | rName.clear(); | |||
126 | return false; // nothing found | |||
127 | } | |||
128 | ||||
129 | void ScDocument::UpdateChartArea( const OUString& rChartName, | |||
130 | const ScRange& rNewArea, bool bColHeaders, bool bRowHeaders, | |||
131 | bool bAdd ) | |||
132 | { | |||
133 | ScRangeListRef aRLR( new ScRangeList(rNewArea) ); | |||
| ||||
134 | UpdateChartArea( rChartName, aRLR, bColHeaders, bRowHeaders, bAdd ); | |||
135 | } | |||
136 | ||||
137 | uno::Reference< chart2::XChartDocument > ScDocument::GetChartByName( const OUString& rChartName ) | |||
138 | { | |||
139 | uno::Reference< chart2::XChartDocument > xReturn; | |||
140 | ||||
141 | if (mpDrawLayer) | |||
142 | { | |||
143 | sal_uInt16 nCount = mpDrawLayer->GetPageCount(); | |||
144 | SCTAB nSize = static_cast<SCTAB>(maTabs.size()); | |||
145 | for (sal_uInt16 nTab=0; nTab<nCount && nTab < nSize; nTab++) | |||
146 | { | |||
147 | SdrPage* pPage = mpDrawLayer->GetPage(nTab); | |||
148 | OSL_ENSURE(pPage,"Page ?")do { if (true && (!(pPage))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/documen5.cxx" ":" "148" ": "), "%s", "Page ?"); } } while (false); | |||
149 | ||||
150 | SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); | |||
151 | SdrObject* pObject = aIter.Next(); | |||
152 | while (pObject) | |||
153 | { | |||
154 | if ( pObject->GetObjIdentifier() == OBJ_OLE2 && | |||
155 | static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == rChartName ) | |||
156 | { | |||
157 | xReturn.set( ScChartHelper::GetChartFromSdrObject( pObject ) ); | |||
158 | return xReturn; | |||
159 | } | |||
160 | pObject = aIter.Next(); | |||
161 | } | |||
162 | } | |||
163 | } | |||
164 | return xReturn; | |||
165 | } | |||
166 | ||||
167 | void ScDocument::GetChartRanges( const OUString& rChartName, ::std::vector< ScRangeList >& rRangesVector, const ScDocument& rSheetNameDoc ) | |||
168 | { | |||
169 | rRangesVector.clear(); | |||
170 | uno::Reference< chart2::XChartDocument > xChartDoc( GetChartByName( rChartName ) ); | |||
171 | if ( xChartDoc.is() ) | |||
172 | { | |||
173 | std::vector< OUString > aRangeStrings; | |||
174 | ScChartHelper::GetChartRanges( xChartDoc, aRangeStrings ); | |||
175 | for(const OUString & aRangeString : aRangeStrings) | |||
176 | { | |||
177 | ScRangeList aRanges; | |||
178 | aRanges.Parse( aRangeString, rSheetNameDoc, rSheetNameDoc.GetAddressConvention() ); | |||
179 | rRangesVector.push_back(aRanges); | |||
180 | } | |||
181 | } | |||
182 | } | |||
183 | ||||
184 | void ScDocument::SetChartRanges( const OUString& rChartName, const ::std::vector< ScRangeList >& rRangesVector ) | |||
185 | { | |||
186 | uno::Reference< chart2::XChartDocument > xChartDoc( GetChartByName( rChartName ) ); | |||
187 | if ( !xChartDoc.is() ) | |||
188 | return; | |||
189 | ||||
190 | sal_Int32 nCount = static_cast<sal_Int32>( rRangesVector.size() ); | |||
191 | uno::Sequence< OUString > aRangeStrings(nCount); | |||
192 | for( sal_Int32 nN=0; nN<nCount; nN++ ) | |||
193 | { | |||
194 | ScRangeList aScRangeList( rRangesVector[nN] ); | |||
195 | OUString sRangeStr; | |||
196 | aScRangeList.Format( sRangeStr, ScRefFlags::RANGE_ABS_3D, *this, GetAddressConvention() ); | |||
197 | aRangeStrings[nN]=sRangeStr; | |||
198 | } | |||
199 | ScChartHelper::SetChartRanges( xChartDoc, aRangeStrings ); | |||
200 | } | |||
201 | ||||
202 | void ScDocument::GetOldChartParameters( const OUString& rName, | |||
203 | ScRangeList& rRanges, bool& rColHeaders, bool& rRowHeaders ) | |||
204 | { | |||
205 | // used for undo of changing chart source area | |||
206 | ||||
207 | if (!mpDrawLayer) | |||
208 | return; | |||
209 | ||||
210 | sal_uInt16 nCount = mpDrawLayer->GetPageCount(); | |||
211 | for (sal_uInt16 nTab=0; nTab<nCount && nTab < static_cast<SCTAB>(maTabs.size()); nTab++) | |||
212 | { | |||
213 | SdrPage* pPage = mpDrawLayer->GetPage(nTab); | |||
214 | OSL_ENSURE(pPage,"Page ?")do { if (true && (!(pPage))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/documen5.cxx" ":" "214" ": "), "%s", "Page ?"); } } while (false); | |||
215 | ||||
216 | SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); | |||
217 | SdrObject* pObject = aIter.Next(); | |||
218 | while (pObject) | |||
219 | { | |||
220 | if ( pObject->GetObjIdentifier() == OBJ_OLE2 && | |||
221 | static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == rName ) | |||
222 | { | |||
223 | uno::Reference< chart2::XChartDocument > xChartDoc( ScChartHelper::GetChartFromSdrObject( pObject ) ); | |||
224 | if ( xChartDoc.is() ) | |||
225 | { | |||
226 | chart::ChartDataRowSource eDataRowSource = chart::ChartDataRowSource_COLUMNS; | |||
227 | bool bHasCategories = false; | |||
228 | bool bFirstCellAsLabel = false; | |||
229 | OUString aRangesStr; | |||
230 | lcl_GetChartParameters( xChartDoc, aRangesStr, eDataRowSource, bHasCategories, bFirstCellAsLabel ); | |||
231 | ||||
232 | rRanges.Parse( aRangesStr, *this ); | |||
233 | if ( eDataRowSource == chart::ChartDataRowSource_COLUMNS ) | |||
234 | { | |||
235 | rRowHeaders = bHasCategories; | |||
236 | rColHeaders = bFirstCellAsLabel; | |||
237 | } | |||
238 | else | |||
239 | { | |||
240 | rColHeaders = bHasCategories; | |||
241 | rRowHeaders = bFirstCellAsLabel; | |||
242 | } | |||
243 | } | |||
244 | return; | |||
245 | } | |||
246 | pObject = aIter.Next(); | |||
247 | } | |||
248 | } | |||
249 | } | |||
250 | ||||
251 | void ScDocument::UpdateChartArea( const OUString& rChartName, | |||
252 | const ScRangeListRef& rNewList, bool bColHeaders, bool bRowHeaders, | |||
253 | bool bAdd ) | |||
254 | { | |||
255 | if (!mpDrawLayer) | |||
256 | return; | |||
257 | ||||
258 | for (SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]; nTab++) | |||
259 | { | |||
260 | SdrPage* pPage = mpDrawLayer->GetPage(static_cast<sal_uInt16>(nTab)); | |||
261 | OSL_ENSURE(pPage,"Page ?")do { if (true && (!(pPage))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/documen5.cxx" ":" "261" ": "), "%s", "Page ?"); } } while (false); | |||
262 | ||||
263 | SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); | |||
264 | SdrObject* pObject = aIter.Next(); | |||
265 | while (pObject) | |||
266 | { | |||
267 | if ( pObject->GetObjIdentifier() == OBJ_OLE2 && | |||
268 | static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == rChartName ) | |||
269 | { | |||
270 | uno::Reference< chart2::XChartDocument > xChartDoc( ScChartHelper::GetChartFromSdrObject( pObject ) ); | |||
271 | uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, uno::UNO_QUERY ); | |||
272 | if ( xChartDoc.is() && xReceiver.is() ) | |||
273 | { | |||
274 | ScRangeListRef aNewRanges; | |||
275 | chart::ChartDataRowSource eDataRowSource = chart::ChartDataRowSource_COLUMNS; | |||
276 | bool bHasCategories = false; | |||
277 | bool bFirstCellAsLabel = false; | |||
278 | OUString aRangesStr; | |||
279 | lcl_GetChartParameters( xChartDoc, aRangesStr, eDataRowSource, bHasCategories, bFirstCellAsLabel ); | |||
280 | ||||
281 | bool bInternalData = xChartDoc->hasInternalDataProvider(); | |||
282 | ||||
283 | if ( bAdd && !bInternalData ) | |||
284 | { | |||
285 | // append to old ranges, keep other settings | |||
286 | ||||
287 | aNewRanges = new ScRangeList; | |||
288 | aNewRanges->Parse( aRangesStr, *this ); | |||
289 | ||||
290 | for ( size_t nAdd = 0, nAddCount = rNewList->size(); nAdd < nAddCount; ++nAdd ) | |||
291 | aNewRanges->push_back( (*rNewList)[nAdd] ); | |||
292 | } | |||
293 | else | |||
294 | { | |||
295 | // directly use new ranges (only eDataRowSource is used from old settings) | |||
296 | ||||
297 | if ( eDataRowSource == chart::ChartDataRowSource_COLUMNS ) | |||
298 | { | |||
299 | bHasCategories = bRowHeaders; | |||
300 | bFirstCellAsLabel = bColHeaders; | |||
301 | } | |||
302 | else | |||
303 | { | |||
304 | bHasCategories = bColHeaders; | |||
305 | bFirstCellAsLabel = bRowHeaders; | |||
306 | } | |||
307 | aNewRanges = rNewList; | |||
308 | } | |||
309 | ||||
310 | if ( bInternalData && mpShell ) | |||
311 | { | |||
312 | // Calc -> DataProvider | |||
313 | uno::Reference< chart2::data::XDataProvider > xDataProvider = new ScChart2DataProvider( this ); | |||
314 | xReceiver->attachDataProvider( xDataProvider ); | |||
315 | uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( | |||
316 | mpShell->GetModel(), uno::UNO_QUERY ); | |||
317 | xReceiver->attachNumberFormatsSupplier( xNumberFormatsSupplier ); | |||
318 | } | |||
319 | ||||
320 | OUString sRangeStr; | |||
321 | aNewRanges->Format( sRangeStr, ScRefFlags::RANGE_ABS_3D, *this, GetAddressConvention() ); | |||
322 | ||||
323 | lcl_SetChartParameters( xReceiver, sRangeStr, eDataRowSource, bHasCategories, bFirstCellAsLabel ); | |||
324 | ||||
325 | pChartListenerCollection->ChangeListening( rChartName, aNewRanges ); | |||
326 | ||||
327 | return; // do not search anymore | |||
328 | } | |||
329 | } | |||
330 | pObject = aIter.Next(); | |||
331 | } | |||
332 | } | |||
333 | } | |||
334 | ||||
335 | void ScDocument::UpdateChart( const OUString& rChartName ) | |||
336 | { | |||
337 | if (!mpDrawLayer || bInDtorClear) | |||
338 | return; | |||
339 | uno::Reference< chart2::XChartDocument > xChartDoc( GetChartByName( rChartName ) ); | |||
340 | if (xChartDoc && (!mpShell || mpShell->IsEnableSetModified())) | |||
341 | { | |||
342 | try | |||
343 | { | |||
344 | uno::Reference< util::XModifiable > xModif( xChartDoc, uno::UNO_QUERY_THROW ); | |||
345 | if (apTemporaryChartLock) | |||
346 | apTemporaryChartLock->AlsoLockThisChart( uno::Reference< frame::XModel >( xModif, uno::UNO_QUERY ) ); | |||
347 | xModif->setModified( true ); | |||
348 | } | |||
349 | catch ( uno::Exception& ) | |||
350 | { | |||
351 | } | |||
352 | } | |||
353 | ||||
354 | // After the update, chart keeps track of its own data source ranges, | |||
355 | // the listener doesn't need to listen anymore, except the chart has | |||
356 | // an internal data provider. | |||
357 | if ( !( xChartDoc.is() && xChartDoc->hasInternalDataProvider() ) && pChartListenerCollection ) | |||
358 | { | |||
359 | pChartListenerCollection->ChangeListening( rChartName, new ScRangeList ); | |||
360 | } | |||
361 | } | |||
362 | ||||
363 | void ScDocument::RestoreChartListener( const OUString& rName ) | |||
364 | { | |||
365 | // Read the data ranges from the chart object, and start listening to those ranges again | |||
366 | // (called when a chart is saved, because then it might be swapped out and stop listening itself). | |||
367 | ||||
368 | uno::Reference< embed::XEmbeddedObject > xObject = FindOleObjectByName( rName ); | |||
369 | if ( !xObject.is() ) | |||
370 | return; | |||
371 | ||||
372 | uno::Reference< util::XCloseable > xComponent = xObject->getComponent(); | |||
373 | uno::Reference< chart2::XChartDocument > xChartDoc( xComponent, uno::UNO_QUERY ); | |||
374 | uno::Reference< chart2::data::XDataReceiver > xReceiver( xComponent, uno::UNO_QUERY ); | |||
375 | if ( !xChartDoc.is() || !xReceiver.is() || xChartDoc->hasInternalDataProvider() ) | |||
376 | return; | |||
377 | ||||
378 | const uno::Sequence<OUString> aRepresentations( xReceiver->getUsedRangeRepresentations() ); | |||
379 | ScRangeListRef aRanges = new ScRangeList; | |||
380 | for ( const auto& rRepresentation : aRepresentations ) | |||
381 | { | |||
382 | ScRange aRange; | |||
383 | ScAddress::Details aDetails(GetAddressConvention(), 0, 0); | |||
384 | if ( aRange.ParseAny( rRepresentation, *this, aDetails ) & ScRefFlags::VALID ) | |||
385 | aRanges->push_back( aRange ); | |||
386 | } | |||
387 | ||||
388 | pChartListenerCollection->ChangeListening( rName, aRanges ); | |||
389 | } | |||
390 | ||||
391 | void ScDocument::UpdateChartRef( UpdateRefMode eUpdateRefMode, | |||
392 | SCCOL nCol1, SCROW nRow1, SCTAB nTab1, | |||
393 | SCCOL nCol2, SCROW nRow2, SCTAB nTab2, | |||
394 | SCCOL nDx, SCROW nDy, SCTAB nDz ) | |||
395 | { | |||
396 | if (!mpDrawLayer) | |||
397 | return; | |||
398 | ||||
399 | ScChartListenerCollection::ListenersType& rListeners = pChartListenerCollection->getListeners(); | |||
400 | for (auto const& it : rListeners) | |||
401 | { | |||
402 | ScChartListener *const pChartListener = it.second.get(); | |||
403 | ScRangeListRef aRLR( pChartListener->GetRangeList() ); | |||
404 | ScRangeListRef aNewRLR( new ScRangeList ); | |||
405 | bool bChanged = false; | |||
406 | bool bDataChanged = false; | |||
407 | for ( size_t i = 0, nListSize = aRLR->size(); i < nListSize; ++i ) | |||
408 | { | |||
409 | ScRange& rRange = (*aRLR)[i]; | |||
410 | SCCOL theCol1 = rRange.aStart.Col(); | |||
411 | SCROW theRow1 = rRange.aStart.Row(); | |||
412 | SCTAB theTab1 = rRange.aStart.Tab(); | |||
413 | SCCOL theCol2 = rRange.aEnd.Col(); | |||
414 | SCROW theRow2 = rRange.aEnd.Row(); | |||
415 | SCTAB theTab2 = rRange.aEnd.Tab(); | |||
416 | ScRefUpdateRes eRes = ScRefUpdate::Update( | |||
417 | this, eUpdateRefMode, | |||
418 | nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, | |||
419 | nDx,nDy,nDz, | |||
420 | theCol1,theRow1,theTab1, | |||
421 | theCol2,theRow2,theTab2 ); | |||
422 | if ( eRes != UR_NOTHING ) | |||
423 | { | |||
424 | bChanged = true; | |||
425 | aNewRLR->push_back( ScRange( | |||
426 | theCol1, theRow1, theTab1, | |||
427 | theCol2, theRow2, theTab2 )); | |||
428 | if ( eUpdateRefMode == URM_INSDEL | |||
429 | && !bDataChanged | |||
430 | && (eRes == UR_INVALID || | |||
431 | ((rRange.aEnd.Col() - rRange.aStart.Col() | |||
432 | != theCol2 - theCol1) | |||
433 | || (rRange.aEnd.Row() - rRange.aStart.Row() | |||
434 | != theRow2 - theRow1) | |||
435 | || (rRange.aEnd.Tab() - rRange.aStart.Tab() | |||
436 | != theTab2 - theTab1))) ) | |||
437 | { | |||
438 | bDataChanged = true; | |||
439 | } | |||
440 | } | |||
441 | else | |||
442 | aNewRLR->push_back( rRange ); | |||
443 | } | |||
444 | if ( bChanged ) | |||
445 | { | |||
446 | // Force the chart to be loaded now, so it registers itself for UNO events. | |||
447 | // UNO broadcasts are done after UpdateChartRef, so the chart will get this | |||
448 | // reference change. | |||
449 | ||||
450 | uno::Reference<embed::XEmbeddedObject> xIPObj = | |||
451 | FindOleObjectByName(pChartListener->GetName()); | |||
452 | ||||
453 | svt::EmbeddedObjectRef::TryRunningState( xIPObj ); | |||
454 | ||||
455 | // After the change, chart keeps track of its own data source ranges, | |||
456 | // the listener doesn't need to listen anymore, except the chart has | |||
457 | // an internal data provider. | |||
458 | bool bInternalDataProvider = false; | |||
459 | if ( xIPObj.is() ) | |||
460 | { | |||
461 | try | |||
462 | { | |||
463 | uno::Reference< chart2::XChartDocument > xChartDoc( xIPObj->getComponent(), uno::UNO_QUERY_THROW ); | |||
464 | bInternalDataProvider = xChartDoc->hasInternalDataProvider(); | |||
465 | } | |||
466 | catch ( uno::Exception& ) | |||
467 | { | |||
468 | } | |||
469 | } | |||
470 | if ( bInternalDataProvider ) | |||
471 | { | |||
472 | pChartListener->ChangeListening( aNewRLR, bDataChanged ); | |||
473 | } | |||
474 | else | |||
475 | { | |||
476 | pChartListener->ChangeListening( new ScRangeList, bDataChanged ); | |||
477 | } | |||
478 | } | |||
479 | } | |||
480 | } | |||
481 | ||||
482 | void ScDocument::SetChartRangeList( const OUString& rChartName, | |||
483 | const ScRangeListRef& rNewRangeListRef ) | |||
484 | { | |||
485 | // called from ChartListener | |||
486 | ||||
487 | if (!mpDrawLayer) | |||
488 | return; | |||
489 | ||||
490 | for (SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]; nTab++) | |||
491 | { | |||
492 | SdrPage* pPage = mpDrawLayer->GetPage(static_cast<sal_uInt16>(nTab)); | |||
493 | OSL_ENSURE(pPage,"Page ?")do { if (true && (!(pPage))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/documen5.cxx" ":" "493" ": "), "%s", "Page ?"); } } while (false); | |||
494 | ||||
495 | SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); | |||
496 | SdrObject* pObject = aIter.Next(); | |||
497 | while (pObject) | |||
498 | { | |||
499 | if ( pObject->GetObjIdentifier() == OBJ_OLE2 && | |||
500 | static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == rChartName ) | |||
501 | { | |||
502 | uno::Reference< chart2::XChartDocument > xChartDoc( ScChartHelper::GetChartFromSdrObject( pObject ) ); | |||
503 | uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, uno::UNO_QUERY ); | |||
504 | if ( xChartDoc.is() && xReceiver.is() ) | |||
505 | { | |||
506 | chart::ChartDataRowSource eDataRowSource = chart::ChartDataRowSource_COLUMNS; | |||
507 | bool bHasCategories = false; | |||
508 | bool bFirstCellAsLabel = false; | |||
509 | OUString aRangesStr; | |||
510 | lcl_GetChartParameters( xChartDoc, aRangesStr, eDataRowSource, bHasCategories, bFirstCellAsLabel ); | |||
511 | ||||
512 | OUString sRangeStr; | |||
513 | rNewRangeListRef->Format( sRangeStr, ScRefFlags::RANGE_ABS_3D, *this, GetAddressConvention() ); | |||
514 | ||||
515 | lcl_SetChartParameters( xReceiver, sRangeStr, eDataRowSource, bHasCategories, bFirstCellAsLabel ); | |||
516 | ||||
517 | // don't modify pChartListenerCollection here, called from there | |||
518 | return; | |||
519 | } | |||
520 | } | |||
521 | pObject = aIter.Next(); | |||
522 | } | |||
523 | } | |||
524 | } | |||
525 | ||||
526 | bool ScDocument::HasData( SCCOL nCol, SCROW nRow, SCTAB nTab ) | |||
527 | { | |||
528 | if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] | |||
529 | && nCol < maTabs[nTab]->GetAllocatedColumnsCount()) | |||
530 | return maTabs[nTab]->HasData( nCol, nRow ); | |||
531 | else | |||
532 | return false; | |||
533 | } | |||
534 | ||||
535 | uno::Reference< embed::XEmbeddedObject > | |||
536 | ScDocument::FindOleObjectByName( const OUString& rName ) | |||
537 | { | |||
538 | if (!mpDrawLayer) | |||
539 | return uno::Reference< embed::XEmbeddedObject >(); | |||
540 | ||||
541 | // take the pages here from Draw-Layer, as they might not match with the tables | |||
542 | // (e.g. delete Redo of table; Draw-Redo happens before DeleteTab) | |||
543 | ||||
544 | sal_uInt16 nCount = mpDrawLayer->GetPageCount(); | |||
545 | for (sal_uInt16 nTab=0; nTab<nCount; nTab++) | |||
546 | { | |||
547 | SdrPage* pPage = mpDrawLayer->GetPage(nTab); | |||
548 | OSL_ENSURE(pPage,"Page ?")do { if (true && (!(pPage))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/documen5.cxx" ":" "548" ": "), "%s", "Page ?"); } } while (false); | |||
549 | ||||
550 | SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); | |||
551 | SdrObject* pObject = aIter.Next(); | |||
552 | while (pObject) | |||
553 | { | |||
554 | if ( pObject->GetObjIdentifier() == OBJ_OLE2 ) | |||
555 | { | |||
556 | SdrOle2Obj * pOleObject ( dynamic_cast< SdrOle2Obj * >( pObject )); | |||
557 | if( pOleObject && | |||
558 | pOleObject->GetPersistName() == rName ) | |||
559 | { | |||
560 | return pOleObject->GetObjRef(); | |||
561 | } | |||
562 | } | |||
563 | pObject = aIter.Next(); | |||
564 | } | |||
565 | } | |||
566 | ||||
567 | return uno::Reference< embed::XEmbeddedObject >(); | |||
568 | } | |||
569 | ||||
570 | void ScDocument::UpdateChartListenerCollection() | |||
571 | { | |||
572 | assert(pChartListenerCollection)(static_cast <bool> (pChartListenerCollection) ? void ( 0) : __assert_fail ("pChartListenerCollection", "/home/maarten/src/libreoffice/core/sc/source/core/data/documen5.cxx" , 572, __extension__ __PRETTY_FUNCTION__)); | |||
573 | ||||
574 | bChartListenerCollectionNeedsUpdate = false; | |||
575 | if (!mpDrawLayer) | |||
576 | return; | |||
577 | ||||
578 | for (SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++) | |||
579 | { | |||
580 | if (!maTabs[nTab]) | |||
581 | continue; | |||
582 | ||||
583 | SdrPage* pPage = mpDrawLayer->GetPage(static_cast<sal_uInt16>(nTab)); | |||
584 | OSL_ENSURE(pPage,"Page ?")do { if (true && (!(pPage))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/documen5.cxx" ":" "584" ": "), "%s", "Page ?"); } } while (false); | |||
585 | ||||
586 | if (!pPage) | |||
587 | continue; | |||
588 | ||||
589 | SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); | |||
590 | ScChartListenerCollection::StringSetType& rNonOleObjects = | |||
591 | pChartListenerCollection->getNonOleObjectNames(); | |||
592 | ||||
593 | for (SdrObject* pObject = aIter.Next(); pObject; pObject = aIter.Next()) | |||
594 | { | |||
595 | if ( pObject->GetObjIdentifier() != OBJ_OLE2 ) | |||
596 | continue; | |||
597 | ||||
598 | OUString aObjName = static_cast<SdrOle2Obj*>(pObject)->GetPersistName(); | |||
599 | ScChartListener* pListener = pChartListenerCollection->findByName(aObjName); | |||
600 | ||||
601 | if (pListener) | |||
602 | pListener->SetUsed(true); | |||
603 | else if (rNonOleObjects.count(aObjName) > 0) | |||
604 | { | |||
605 | // non-chart OLE object -> don't touch | |||
606 | } | |||
607 | else | |||
608 | { | |||
609 | uno::Reference< embed::XEmbeddedObject > xIPObj = static_cast<SdrOle2Obj*>(pObject)->GetObjRef(); | |||
610 | OSL_ENSURE( xIPObj.is(), "No embedded object is given!")do { if (true && (!(xIPObj.is()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/documen5.cxx" ":" "610" ": "), "%s", "No embedded object is given!"); } } while (false); | |||
611 | uno::Reference< css::chart2::data::XDataReceiver > xReceiver; | |||
612 | if( xIPObj.is()) | |||
613 | xReceiver.set( xIPObj->getComponent(), uno::UNO_QUERY ); | |||
614 | ||||
615 | // if the object is a chart2::XDataReceiver, we must attach as XDataProvider | |||
616 | if( xReceiver.is() && | |||
617 | !PastingDrawFromOtherDoc()) | |||
618 | { | |||
619 | // NOTE: this currently does not work as we are | |||
620 | // unable to set the data. So a chart from the | |||
621 | // same document is treated like a chart with | |||
622 | // own data for the time being. | |||
623 | ||||
624 | // data provider | |||
625 | // number formats supplier | |||
626 | ||||
627 | // data ? | |||
628 | // how to set?? Defined in XML-file, which is already loaded!!! | |||
629 | // => we have to do this stuff here, BEFORE the chart is actually loaded | |||
630 | } | |||
631 | ||||
632 | // put into list of other ole objects, so the object doesn't have to | |||
633 | // be swapped in the next time UpdateChartListenerCollection is called | |||
634 | //TODO: remove names when objects are no longer there? | |||
635 | // (object names aren't used again before reloading the document) | |||
636 | ||||
637 | rNonOleObjects.insert(aObjName); | |||
638 | } | |||
639 | } | |||
640 | } | |||
641 | // delete all that are not set SetUsed | |||
642 | pChartListenerCollection->FreeUnused(); | |||
643 | } | |||
644 | ||||
645 | void ScDocument::AddOLEObjectToCollection(const OUString& rName) | |||
646 | { | |||
647 | assert(pChartListenerCollection)(static_cast <bool> (pChartListenerCollection) ? void ( 0) : __assert_fail ("pChartListenerCollection", "/home/maarten/src/libreoffice/core/sc/source/core/data/documen5.cxx" , 647, __extension__ __PRETTY_FUNCTION__)); | |||
648 | ScChartListenerCollection::StringSetType& rNonOleObjects = | |||
649 | pChartListenerCollection->getNonOleObjectNames(); | |||
650 | ||||
651 | rNonOleObjects.insert(rName); | |||
652 | } | |||
653 | ||||
654 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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_TOOLS_REF_HXX | |||
20 | #define INCLUDED_TOOLS_REF_HXX | |||
21 | ||||
22 | #include <sal/config.h> | |||
23 | #include <cassert> | |||
24 | #include <tools/toolsdllapi.h> | |||
25 | #include <utility> | |||
26 | ||||
27 | /** | |||
28 | This implements similar functionality to boost::intrusive_ptr | |||
29 | */ | |||
30 | ||||
31 | namespace tools { | |||
32 | ||||
33 | /** T must be a class that extends SvRefBase */ | |||
34 | template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final { | |||
35 | public: | |||
36 | SvRef(): pObj(nullptr) {} | |||
37 | ||||
38 | SvRef(SvRef&& rObj) noexcept | |||
39 | { | |||
40 | pObj = rObj.pObj; | |||
41 | rObj.pObj = nullptr; | |||
42 | } | |||
43 | ||||
44 | SvRef(SvRef const & rObj): pObj(rObj.pObj) | |||
45 | { | |||
46 | if (pObj != nullptr) pObj->AddNextRef(); | |||
47 | } | |||
48 | ||||
49 | SvRef(T * pObjP): pObj(pObjP) | |||
50 | { | |||
51 | if (pObj != nullptr) pObj->AddFirstRef(); | |||
52 | } | |||
53 | ||||
54 | ~SvRef() | |||
55 | { | |||
56 | if (pObj != nullptr) pObj->ReleaseRef(); | |||
| ||||
57 | } | |||
58 | ||||
59 | void clear() | |||
60 | { | |||
61 | if (pObj != nullptr) { | |||
62 | T * pRefObj = pObj; | |||
63 | pObj = nullptr; | |||
64 | pRefObj->ReleaseRef(); | |||
65 | } | |||
66 | } | |||
67 | ||||
68 | SvRef & operator =(SvRef const & rObj) | |||
69 | { | |||
70 | if (rObj.pObj != nullptr) { | |||
71 | rObj.pObj->AddNextRef(); | |||
72 | } | |||
73 | T * pRefObj = pObj; | |||
74 | pObj = rObj.pObj; | |||
75 | if (pRefObj != nullptr) { | |||
76 | pRefObj->ReleaseRef(); | |||
77 | } | |||
78 | return *this; | |||
79 | } | |||
80 | ||||
81 | SvRef & operator =(SvRef && rObj) | |||
82 | { | |||
83 | if (pObj != nullptr) { | |||
84 | pObj->ReleaseRef(); | |||
85 | } | |||
86 | pObj = rObj.pObj; | |||
87 | rObj.pObj = nullptr; | |||
88 | return *this; | |||
89 | } | |||
90 | ||||
91 | bool is() const { return pObj != nullptr; } | |||
92 | ||||
93 | explicit operator bool() const { return is(); } | |||
94 | ||||
95 | T * get() const { return pObj; } | |||
96 | ||||
97 | T * operator ->() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail ("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 97, __extension__ __PRETTY_FUNCTION__)); return pObj; } | |||
98 | ||||
99 | T & operator *() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail ("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 99, __extension__ __PRETTY_FUNCTION__)); return *pObj; } | |||
100 | ||||
101 | bool operator ==(const SvRef<T> &rhs) const { return pObj == rhs.pObj; } | |||
102 | bool operator !=(const SvRef<T> &rhs) const { return !(*this == rhs); } | |||
103 | ||||
104 | private: | |||
105 | T * pObj; | |||
106 | }; | |||
107 | ||||
108 | /** | |||
109 | * This implements similar functionality to std::make_shared. | |||
110 | */ | |||
111 | template<typename T, typename... Args> | |||
112 | SvRef<T> make_ref(Args&& ... args) | |||
113 | { | |||
114 | return SvRef<T>(new T(std::forward<Args>(args)...)); | |||
115 | } | |||
116 | ||||
117 | } | |||
118 | ||||
119 | /** Classes that want to be referenced-counted via SvRef<T>, should extend this base class */ | |||
120 | class TOOLS_DLLPUBLIC__attribute__ ((visibility("default"))) SvRefBase | |||
121 | { | |||
122 | // work around a clang 3.5 optimization bug: if the bNoDelete is *first* | |||
123 | // it mis-compiles "if (--nRefCount == 0)" and never deletes any object | |||
124 | unsigned int nRefCount : 31; | |||
125 | // the only reason this is not bool is because MSVC cannot handle mixed type bitfields | |||
126 | unsigned int bNoDelete : 1; | |||
127 | ||||
128 | protected: | |||
129 | virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE; | |||
130 | ||||
131 | public: | |||
132 | SvRefBase() : nRefCount(0), bNoDelete(1) {} | |||
133 | SvRefBase(const SvRefBase &) : nRefCount(0), bNoDelete(1) {} | |||
134 | ||||
135 | SvRefBase & operator=(const SvRefBase &) { return *this; } | |||
136 | ||||
137 | void RestoreNoDelete() | |||
138 | { bNoDelete = 1; } | |||
139 | ||||
140 | void AddNextRef() | |||
141 | { | |||
142 | assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) && "Do not add refs to dead objects") ? void (0) : __assert_fail ("nRefCount < (1 << 30) && \"Do not add refs to dead objects\"" , "/home/maarten/src/libreoffice/core/include/tools/ref.hxx", 142, __extension__ __PRETTY_FUNCTION__)); | |||
143 | ++nRefCount; | |||
144 | } | |||
145 | ||||
146 | void AddFirstRef() | |||
147 | { | |||
148 | assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) && "Do not add refs to dead objects") ? void (0) : __assert_fail ("nRefCount < (1 << 30) && \"Do not add refs to dead objects\"" , "/home/maarten/src/libreoffice/core/include/tools/ref.hxx", 148, __extension__ __PRETTY_FUNCTION__)); | |||
149 | if( bNoDelete ) | |||
150 | bNoDelete = 0; | |||
151 | ++nRefCount; | |||
152 | } | |||
153 | ||||
154 | void ReleaseRef() | |||
155 | { | |||
156 | assert( nRefCount >= 1)(static_cast <bool> (nRefCount >= 1) ? void (0) : __assert_fail ("nRefCount >= 1", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 156, __extension__ __PRETTY_FUNCTION__)); | |||
157 | if( --nRefCount == 0 && !bNoDelete) | |||
158 | { | |||
159 | // I'm not sure about the original purpose of this line, but right now | |||
160 | // it serves the purpose that anything that attempts to do an AddRef() | |||
161 | // after an object is deleted will trip an assert. | |||
162 | nRefCount = 1 << 30; | |||
163 | delete this; | |||
164 | } | |||
165 | } | |||
166 | ||||
167 | unsigned int GetRefCount() const | |||
168 | { return nRefCount; } | |||
169 | }; | |||
170 | ||||
171 | template<typename T> | |||
172 | class SvCompatWeakBase; | |||
173 | ||||
174 | /** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T. | |||
175 | */ | |||
176 | template<typename T> | |||
177 | class SvCompatWeakHdl final : public SvRefBase | |||
178 | { | |||
179 | friend class SvCompatWeakBase<T>; | |||
180 | T* _pObj; | |||
181 | ||||
182 | SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {} | |||
183 | ||||
184 | public: | |||
185 | void ResetWeakBase( ) { _pObj = nullptr; } | |||
186 | T* GetObj() { return _pObj; } | |||
187 | }; | |||
188 | ||||
189 | /** We only have one place that extends this, in include/sfx2/frame.hxx, class SfxFrame. | |||
190 | Its function is to notify the SvCompatWeakHdl when an SfxFrame object is deleted. | |||
191 | */ | |||
192 | template<typename T> | |||
193 | class SvCompatWeakBase | |||
194 | { | |||
195 | tools::SvRef< SvCompatWeakHdl<T> > _xHdl; | |||
196 | ||||
197 | public: | |||
198 | /** Does not use initializer due to compiler warnings, | |||
199 | because the lifetime of the _xHdl object can exceed the lifetime of this class. | |||
200 | */ | |||
201 | SvCompatWeakBase( T* pObj ) { _xHdl = new SvCompatWeakHdl<T>( pObj ); } | |||
202 | ||||
203 | ~SvCompatWeakBase() { _xHdl->ResetWeakBase(); } | |||
204 | ||||
205 | SvCompatWeakHdl<T>* GetHdl() { return _xHdl.get(); } | |||
206 | }; | |||
207 | ||||
208 | /** We only have one weak reference in LO, in include/sfx2/frame.hxx, class SfxFrameWeak. | |||
209 | */ | |||
210 | template<typename T> | |||
211 | class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef | |||
212 | { | |||
213 | tools::SvRef< SvCompatWeakHdl<T> > _xHdl; | |||
214 | public: | |||
215 | SvCompatWeakRef( ) {} | |||
216 | SvCompatWeakRef( T* pObj ) | |||
217 | { if( pObj ) _xHdl = pObj->GetHdl(); } | |||
218 | #if defined(__COVERITY__) | |||
219 | ~SvCompatWeakRef() COVERITY_NOEXCEPT_FALSE {} | |||
220 | #endif | |||
221 | SvCompatWeakRef& operator = ( T * pObj ) | |||
222 | { _xHdl = pObj ? pObj->GetHdl() : nullptr; return *this; } | |||
223 | bool is() const | |||
224 | { return _xHdl.is() && _xHdl->GetObj(); } | |||
225 | explicit operator bool() const { return is(); } | |||
226 | T* operator -> () const | |||
227 | { return _xHdl.is() ? _xHdl->GetObj() : nullptr; } | |||
228 | operator T* () const | |||
229 | { return _xHdl.is() ? _xHdl->GetObj() : nullptr; } | |||
230 | }; | |||
231 | ||||
232 | #endif | |||
233 | ||||
234 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |