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 <sal/config.h>
21
22 #include <map>
23
24 #include <ObjectIdentifier.hxx>
25 #include <TitleHelper.hxx>
26 #include <ChartModel.hxx>
27 #include <ChartModelHelper.hxx>
28 #include <AxisHelper.hxx>
29 #include <servicenames_charttypes.hxx>
30 #include <DiagramHelper.hxx>
31 #include <unonames.hxx>
32
33 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
34 #include <com/sun/star/chart2/XChartDocument.hpp>
35 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
36 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
37 #include <com/sun/star/chart2/XAxis.hpp>
38 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
39 #include <com/sun/star/awt/Point.hpp>
40 #include <com/sun/star/drawing/XShape.hpp>
41
42 #include <rtl/ustrbuf.hxx>
43 #include <tools/diagnose_ex.h>
44
45 namespace com::sun::star::drawing { class XShape; }
46
47 namespace chart
48 {
49 using namespace ::com::sun::star;
50 using namespace ::com::sun::star::chart2;
51
52 using ::com::sun::star::uno::Reference;
53 using ::com::sun::star::uno::Any;
54
55 const char m_aMultiClick[] = "MultiClick";
56 const char m_aDragMethodEquals[] = "DragMethod=";
57 const char m_aDragParameterEquals[] = "DragParameter=";
58 const char m_aProtocol[] = "CID/";
59 const OUString m_aPieSegmentDragMethodServiceName("PieSegmentDragging");
60
61 namespace
62 {
63
lcl_createClassificationStringForType(ObjectType eObjectType,std::u16string_view rDragMethodServiceName,std::u16string_view rDragParameterString)64 OUString lcl_createClassificationStringForType( ObjectType eObjectType
65 , std::u16string_view rDragMethodServiceName
66 , std::u16string_view rDragParameterString
67 )
68 {
69 OUStringBuffer aRet;
70 switch( eObjectType )
71 {
72 //these object types are all selected only after their parents was selected before
73 case OBJECTTYPE_LEGEND_ENTRY: //parent is intended to be OBJECTTYPE_LEGEND
74 case OBJECTTYPE_DATA_POINT: //parent is intended to be OBJECTTYPE_DATA_SERIES
75 case OBJECTTYPE_DATA_LABEL: //parent is intended to be OBJECTTYPE_DATA_LABELS
76 case OBJECTTYPE_DATA_ERRORS_X: //parent is intended to be OBJECTTYPE_DATA_ERRORS
77 case OBJECTTYPE_DATA_ERRORS_Y: //parent is intended to be OBJECTTYPE_DATA_ERRORS
78 case OBJECTTYPE_DATA_ERRORS_Z: //parent is intended to be OBJECTTYPE_DATA_ERRORS
79 aRet=m_aMultiClick;
80 break;
81 default:
82 break;//empty string
83 }
84 if( !rDragMethodServiceName.empty() )
85 {
86 if( !aRet.isEmpty() )
87 aRet.append(":");
88 aRet.append( m_aDragMethodEquals );
89 aRet.append( rDragMethodServiceName );
90
91 if( !rDragParameterString.empty() )
92 {
93 if( !aRet.isEmpty() )
94 aRet.append(":");
95 aRet.append( m_aDragParameterEquals );
96 aRet.append( rDragParameterString );
97 }
98 }
99 return aRet.makeStringAndClear();
100 }
101
102 typedef std::map< TitleHelper::eTitleType, OUString > tTitleMap;
lcl_getTitleMap()103 const tTitleMap& lcl_getTitleMap()
104 {
105 //maps the title type to the ParentParticle for that title
106 static tTitleMap s_aTitleMap{
107 {TitleHelper::MAIN_TITLE, ""},
108 {TitleHelper::SUB_TITLE, "D=0"},
109 {TitleHelper::X_AXIS_TITLE, "D=0:CS=0:Axis=0,0"},
110 {TitleHelper::Y_AXIS_TITLE, "D=0:CS=0:Axis=1,0"},
111 {TitleHelper::Z_AXIS_TITLE, "D=0:CS=0:Axis=2,0"},
112 {TitleHelper::SECONDARY_X_AXIS_TITLE, "D=0:CS=0:Axis=0,1"},
113 {TitleHelper::SECONDARY_Y_AXIS_TITLE, "D=0:CS=0:Axis=1,1"}};
114 return s_aTitleMap;
115 }
116
lcl_getTitleParentParticle(TitleHelper::eTitleType aTitleType)117 OUString lcl_getTitleParentParticle( TitleHelper::eTitleType aTitleType )
118 {
119 OUString aRet;
120
121 const tTitleMap& rMap = lcl_getTitleMap();
122 tTitleMap::const_iterator aIt( rMap.find( aTitleType ) );
123 if( aIt != rMap.end())
124 aRet = (*aIt).second;
125
126 return aRet;
127 }
128
lcl_getFirstStockChartType(const Reference<frame::XModel> & xChartModel)129 Reference<XChartType> lcl_getFirstStockChartType( const Reference< frame::XModel >& xChartModel )
130 {
131 Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) );
132 if(!xDiagram.is())
133 return nullptr;
134
135 //iterate through all coordinate systems
136 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
137 if( !xCooSysContainer.is())
138 return nullptr;
139
140 const uno::Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
141 for( Reference< XCoordinateSystem > const & coords : aCooSysList )
142 {
143 //iterate through all chart types in the current coordinate system
144 Reference< XChartTypeContainer > xChartTypeContainer( coords, uno::UNO_QUERY );
145 if( !xChartTypeContainer.is() )
146 continue;
147
148 const uno::Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
149 for( Reference< XChartType > const & xChartType : aChartTypeList )
150 {
151 if(!xChartType.is())
152 continue;
153 OUString aChartType = xChartType->getChartType();
154 if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) )
155 return xChartType;
156 }
157 }
158 return nullptr;
159 }
160
lcl_getIndexStringAfterString(const OUString & rString,const OUString & rSearchString)161 OUString lcl_getIndexStringAfterString( const OUString& rString, const OUString& rSearchString )
162 {
163 OUStringBuffer aRet;
164
165 sal_Int32 nIndexStart = rString.lastIndexOf( rSearchString );
166 if( nIndexStart != -1 )
167 {
168 nIndexStart += rSearchString.getLength();
169 sal_Int32 nIndexEnd = rString.getLength();
170 sal_Int32 nNextColon = rString.indexOf( ':', nIndexStart );
171 if( nNextColon != -1 )
172 nIndexEnd = nNextColon;
173 aRet = rString.subView(nIndexStart,nIndexEnd-nIndexStart);
174 }
175
176 return aRet.makeStringAndClear();
177 }
178
lcl_StringToIndex(const OUString & rIndexString)179 sal_Int32 lcl_StringToIndex( const OUString& rIndexString )
180 {
181 sal_Int32 nRet = -1;
182 if( !rIndexString.isEmpty() )
183 {
184 nRet = rIndexString.toInt32();
185 if( nRet < -1 )
186 nRet = -1;
187 }
188 return nRet;
189 }
190
lcl_parseCooSysIndices(sal_Int32 & rnDiagram,sal_Int32 & rnCooSys,const OUString & rString)191 void lcl_parseCooSysIndices( sal_Int32& rnDiagram, sal_Int32& rnCooSys, const OUString& rString )
192 {
193 rnDiagram = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, "D=" ) );
194 rnCooSys = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, "CS=" ) );
195 }
196
lcl_parseAxisIndices(sal_Int32 & rnDimensionIndex,sal_Int32 & rnAxisIndex,const OUString & rString)197 void lcl_parseAxisIndices( sal_Int32& rnDimensionIndex, sal_Int32& rnAxisIndex, const OUString& rString )
198 {
199 OUString aAxisIndexString = lcl_getIndexStringAfterString( rString, ":Axis=" );
200 sal_Int32 nCharacterIndex=0;
201 rnDimensionIndex = lcl_StringToIndex( aAxisIndexString.getToken( 0, ',', nCharacterIndex ) );
202 rnAxisIndex = lcl_StringToIndex( aAxisIndexString.getToken( 0, ',', nCharacterIndex ) );
203 }
204
lcl_parseGridIndices(sal_Int32 & rnSubGridIndex,const OUString & rString)205 void lcl_parseGridIndices( sal_Int32& rnSubGridIndex, const OUString& rString )
206 {
207 rnSubGridIndex = -1;
208 rnSubGridIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, ":SubGrid=" ) );
209 }
210
lcl_parseSeriesIndices(sal_Int32 & rnChartTypeIndex,sal_Int32 & rnSeriesIndex,sal_Int32 & rnPointIndex,const OUString & rString)211 void lcl_parseSeriesIndices( sal_Int32& rnChartTypeIndex, sal_Int32& rnSeriesIndex, sal_Int32& rnPointIndex, const OUString& rString )
212 {
213 rnChartTypeIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, "CT=" ) );
214 rnSeriesIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, "Series=" ) );
215 rnPointIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, "Point=" ) );
216 }
217
lcl_getDiagramAndCooSys(const OUString & rObjectCID,const Reference<frame::XModel> & xChartModel,Reference<XDiagram> & xDiagram,Reference<XCoordinateSystem> & xCooSys)218 void lcl_getDiagramAndCooSys( const OUString& rObjectCID
219 , const Reference< frame::XModel >& xChartModel
220 , Reference< XDiagram >& xDiagram
221 , Reference< XCoordinateSystem >& xCooSys )
222 {
223 sal_Int32 nDiagramIndex = -1;
224 sal_Int32 nCooSysIndex = -1;
225 lcl_parseCooSysIndices( nDiagramIndex, nCooSysIndex, rObjectCID );
226 xDiagram = ChartModelHelper::findDiagram( xChartModel );//todo use nDiagramIndex when more than one diagram is possible in future
227 if( !xDiagram.is() )
228 return;
229
230 if( nCooSysIndex > -1 )
231 {
232 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
233 if( xCooSysContainer.is() )
234 {
235 uno::Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
236 if( nCooSysIndex < aCooSysList.getLength() )
237 xCooSys = aCooSysList[nCooSysIndex];
238 }
239 }
240 }
241
242 } //anonymous namespace
243
ObjectIdentifier()244 ObjectIdentifier::ObjectIdentifier()
245 :m_aObjectCID( OUString() )
246 {
247 }
248
ObjectIdentifier(const OUString & rObjectCID)249 ObjectIdentifier::ObjectIdentifier( const OUString& rObjectCID )
250 :m_aObjectCID( rObjectCID )
251 {
252 }
253
ObjectIdentifier(const Reference<drawing::XShape> & rxShape)254 ObjectIdentifier::ObjectIdentifier( const Reference< drawing::XShape >& rxShape )
255 :m_aObjectCID( OUString() )
256 ,m_xAdditionalShape( rxShape )
257 {
258 }
259
ObjectIdentifier(const Any & rAny)260 ObjectIdentifier::ObjectIdentifier( const Any& rAny )
261 :m_aObjectCID( OUString() )
262 {
263 const uno::Type& rType = rAny.getValueType();
264 if ( rType == cppu::UnoType<OUString>::get() )
265 {
266 rAny >>= m_aObjectCID;
267 }
268 else if ( rType == cppu::UnoType< drawing::XShape >::get() )
269 {
270 rAny >>= m_xAdditionalShape;
271 }
272 }
273
operator ==(const ObjectIdentifier & rOID) const274 bool ObjectIdentifier::operator==( const ObjectIdentifier& rOID ) const
275 {
276 return areIdenticalObjects( m_aObjectCID, rOID.m_aObjectCID ) &&
277 ( m_xAdditionalShape == rOID.m_xAdditionalShape );
278 }
279
operator !=(const ObjectIdentifier & rOID) const280 bool ObjectIdentifier::operator!=( const ObjectIdentifier& rOID ) const
281 {
282 return !operator==( rOID );
283 }
284
operator <(const ObjectIdentifier & rOID) const285 bool ObjectIdentifier::operator<( const ObjectIdentifier& rOID ) const
286 {
287 bool bReturn = false;
288 if ( !(m_aObjectCID.isEmpty() || rOID.m_aObjectCID.isEmpty()) )
289 {
290 bReturn = ( m_aObjectCID.compareTo( rOID.m_aObjectCID ) < 0 );
291 }
292 else if ( !m_aObjectCID.isEmpty() )
293 {
294 bReturn = true;
295 }
296 else if ( !rOID.m_aObjectCID.isEmpty() )
297 {
298 bReturn = false;
299 }
300 else if ( m_xAdditionalShape.is() && rOID.m_xAdditionalShape.is() )
301 {
302 bReturn = ( m_xAdditionalShape < rOID.m_xAdditionalShape );
303 }
304 return bReturn;
305 }
306
createClassifiedIdentifierForObject(const Reference<uno::XInterface> & xObject,ChartModel & rModel)307 OUString ObjectIdentifier::createClassifiedIdentifierForObject(
308 const Reference< uno::XInterface >& xObject
309 , ChartModel& rModel)
310 {
311 OUString aRet;
312
313 enum ObjectType eObjectType = OBJECTTYPE_UNKNOWN;
314 const OUString aObjectID;
315 OUString aParentParticle;
316 const OUString aDragMethodServiceName;
317 const OUString aDragParameterString;
318
319 try
320 {
321 //title
322 Reference< XTitle > xTitle( xObject, uno::UNO_QUERY );
323 if( xTitle.is() )
324 {
325 TitleHelper::eTitleType aTitleType;
326 if( TitleHelper::getTitleType( aTitleType, xTitle, rModel ) )
327 {
328 eObjectType = OBJECTTYPE_TITLE;
329 aParentParticle = lcl_getTitleParentParticle( aTitleType );
330 aRet = ObjectIdentifier::createClassifiedIdentifierWithParent(
331 eObjectType, aObjectID, aParentParticle, aDragMethodServiceName, aDragParameterString );
332 }
333 return aRet;
334
335 }
336
337 //axis
338 Reference< XAxis > xAxis( xObject, uno::UNO_QUERY );
339 if( xAxis.is() )
340 {
341 Reference< XCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( xAxis, rModel.getFirstDiagram() ) );
342 OUString aCooSysParticle( createParticleForCoordinateSystem( xCooSys, rModel ) );
343 sal_Int32 nDimensionIndex=-1;
344 sal_Int32 nAxisIndex=-1;
345 AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex );
346 OUString aAxisParticle( createParticleForAxis( nDimensionIndex, nAxisIndex ) );
347 return createClassifiedIdentifierForParticles( aCooSysParticle, aAxisParticle );
348 }
349
350 //legend
351 Reference< XLegend > xLegend( xObject, uno::UNO_QUERY );
352 if( xLegend.is() )
353 {
354 return createClassifiedIdentifierForParticle( createParticleForLegend( rModel ) );
355 }
356
357 //diagram
358 Reference< XDiagram > xDiagram( xObject, uno::UNO_QUERY );
359 if( xDiagram.is() )
360 {
361 return createClassifiedIdentifierForParticle( createParticleForDiagram() );
362 }
363
364 //todo
365 //XDataSeries
366 //CooSys
367 //charttype
368 //datapoint?
369 //Gridproperties
370 }
371 catch(const uno::Exception&)
372 {
373 DBG_UNHANDLED_EXCEPTION("chart2");
374 }
375
376 if( eObjectType != OBJECTTYPE_UNKNOWN )
377 {
378 aRet = ObjectIdentifier::createClassifiedIdentifierWithParent(
379 eObjectType, aObjectID, aParentParticle, aDragMethodServiceName, aDragParameterString );
380 }
381 else
382 {
383 OSL_FAIL("give object could not be identified in createClassifiedIdentifierForObject");
384 }
385
386 return aRet;
387 }
388
createClassifiedIdentifierForObject(const Reference<uno::XInterface> & xObject,const Reference<frame::XModel> & xChartModel)389 OUString ObjectIdentifier::createClassifiedIdentifierForObject(
390 const Reference< uno::XInterface >& xObject
391 , const Reference< frame::XModel >& xChartModel )
392 {
393 OUString aRet;
394
395 enum ObjectType eObjectType = OBJECTTYPE_UNKNOWN;
396 const OUString aObjectID;
397 OUString aParentParticle;
398 const OUString aDragMethodServiceName;
399 const OUString aDragParameterString;
400
401 try
402 {
403 //title
404 Reference< XTitle > xTitle( xObject, uno::UNO_QUERY );
405 if( xTitle.is() )
406 {
407 TitleHelper::eTitleType aTitleType;
408 if( TitleHelper::getTitleType( aTitleType, xTitle, xChartModel ) )
409 {
410 eObjectType = OBJECTTYPE_TITLE;
411 aParentParticle = lcl_getTitleParentParticle( aTitleType );
412 aRet = ObjectIdentifier::createClassifiedIdentifierWithParent(
413 eObjectType, aObjectID, aParentParticle, aDragMethodServiceName, aDragParameterString );
414 }
415 return aRet;
416
417 }
418
419 //axis
420 Reference< XAxis > xAxis( xObject, uno::UNO_QUERY );
421 if( xAxis.is() )
422 {
423 Reference< XCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( xAxis, ChartModelHelper::findDiagram( xChartModel ) ) );
424 OUString aCooSysParticle( createParticleForCoordinateSystem( xCooSys, xChartModel ) );
425 sal_Int32 nDimensionIndex=-1;
426 sal_Int32 nAxisIndex=-1;
427 AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex );
428 OUString aAxisParticle( createParticleForAxis( nDimensionIndex, nAxisIndex ) );
429 return createClassifiedIdentifierForParticles( aCooSysParticle, aAxisParticle );
430 }
431
432 //legend
433 Reference< XLegend > xLegend( xObject, uno::UNO_QUERY );
434 if( xLegend.is() )
435 {
436 return createClassifiedIdentifierForParticle( createParticleForLegend( xChartModel ) );
437 }
438
439 //diagram
440 Reference< XDiagram > xDiagram( xObject, uno::UNO_QUERY );
441 if( xDiagram.is() )
442 {
443 return createClassifiedIdentifierForParticle( createParticleForDiagram() );
444 }
445
446 //todo
447 //XDataSeries
448 //CooSys
449 //charttype
450 //datapoint?
451 //Gridproperties
452 }
453 catch(const uno::Exception&)
454 {
455 DBG_UNHANDLED_EXCEPTION("chart2");
456 }
457
458 if( eObjectType != OBJECTTYPE_UNKNOWN )
459 {
460 aRet = ObjectIdentifier::createClassifiedIdentifierWithParent(
461 eObjectType, aObjectID, aParentParticle, aDragMethodServiceName, aDragParameterString );
462 }
463 else
464 {
465 OSL_FAIL("give object could not be identified in createClassifiedIdentifierForObject");
466 }
467
468 return aRet;
469 }
470
createClassifiedIdentifierForParticle(const OUString & rParticle)471 OUString ObjectIdentifier::createClassifiedIdentifierForParticle(
472 const OUString& rParticle )
473 {
474 return ObjectIdentifier::createClassifiedIdentifierForParticles( rParticle, OUString() );
475 }
476
createClassifiedIdentifierForParticles(const OUString & rParentParticle,const OUString & rChildParticle,std::u16string_view rDragMethodServiceName,std::u16string_view rDragParameterString)477 OUString ObjectIdentifier::createClassifiedIdentifierForParticles(
478 const OUString& rParentParticle
479 , const OUString& rChildParticle
480 , std::u16string_view rDragMethodServiceName
481 , std::u16string_view rDragParameterString )
482 {
483 ObjectType eObjectType( ObjectIdentifier::getObjectType( rChildParticle ) );
484 if( eObjectType == OBJECTTYPE_UNKNOWN )
485 eObjectType = ObjectIdentifier::getObjectType( rParentParticle );
486
487 OUStringBuffer aRet( m_aProtocol );
488 aRet.append( lcl_createClassificationStringForType( eObjectType, rDragMethodServiceName, rDragParameterString ));
489 if(aRet.getLength() > static_cast<sal_Int32>(strlen(m_aProtocol)))
490 aRet.append("/");
491
492 if(!rParentParticle.isEmpty())
493 {
494 aRet.append(rParentParticle);
495 if( !rChildParticle.isEmpty() )
496 aRet.append(":");
497 }
498 aRet.append(rChildParticle);
499
500 return aRet.makeStringAndClear();
501 }
502
createParticleForDiagram()503 OUString ObjectIdentifier::createParticleForDiagram()
504 {
505 //TODO: if more than one diagram is implemented, add the correct diagram index here
506 return "D=0";
507 }
508
createParticleForCoordinateSystem(const Reference<XCoordinateSystem> & xCooSys,ChartModel & rModel)509 OUString ObjectIdentifier::createParticleForCoordinateSystem(
510 const Reference< XCoordinateSystem >& xCooSys
511 , ChartModel& rModel )
512 {
513 OUString aRet;
514
515 Reference< XDiagram > xDiagram( rModel.getFirstDiagram() );
516 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
517 if( xCooSysContainer.is() )
518 {
519 sal_Int32 nCooSysIndex = 0;
520 uno::Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
521 for( ; nCooSysIndex < aCooSysList.getLength(); ++nCooSysIndex )
522 {
523 Reference< XCoordinateSystem > xCurrentCooSys( aCooSysList[nCooSysIndex] );
524 if( xCooSys == xCurrentCooSys )
525 {
526 aRet = ObjectIdentifier::createParticleForDiagram() + ":CS=" + OUString::number( nCooSysIndex );
527 break;
528 }
529 }
530 }
531
532 return aRet;
533 }
534
createParticleForCoordinateSystem(const Reference<XCoordinateSystem> & xCooSys,const Reference<frame::XModel> & xChartModel)535 OUString ObjectIdentifier::createParticleForCoordinateSystem(
536 const Reference< XCoordinateSystem >& xCooSys
537 , const Reference< frame::XModel >& xChartModel )
538 {
539 OUString aRet;
540
541 Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) );
542 Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
543 if( xCooSysContainer.is() )
544 {
545 sal_Int32 nCooSysIndex = 0;
546 uno::Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
547 for( ; nCooSysIndex < aCooSysList.getLength(); ++nCooSysIndex )
548 {
549 Reference< XCoordinateSystem > xCurrentCooSys( aCooSysList[nCooSysIndex] );
550 if( xCooSys == xCurrentCooSys )
551 {
552 aRet = ObjectIdentifier::createParticleForDiagram() + ":CS=" + OUString::number( nCooSysIndex );
553 break;
554 }
555 }
556 }
557
558 return aRet;
559 }
560
createParticleForAxis(sal_Int32 nDimensionIndex,sal_Int32 nAxisIndex)561 OUString ObjectIdentifier::createParticleForAxis(
562 sal_Int32 nDimensionIndex
563 , sal_Int32 nAxisIndex )
564 {
565 return "Axis=" +
566 OUString::number( nDimensionIndex ) +
567 "," +
568 OUString::number( nAxisIndex );
569 }
570
createParticleForGrid(sal_Int32 nDimensionIndex,sal_Int32 nAxisIndex)571 OUString ObjectIdentifier::createParticleForGrid(
572 sal_Int32 nDimensionIndex
573 , sal_Int32 nAxisIndex )
574 {
575 OUString aRet = "Axis=" + OUString::number( nDimensionIndex )
576 + "," + OUString::number( nAxisIndex ) + ":Grid=0";
577
578 return aRet;
579 }
580
createClassifiedIdentifierForGrid(const Reference<XAxis> & xAxis,const Reference<frame::XModel> & xChartModel,sal_Int32 nSubGridIndex)581 OUString ObjectIdentifier::createClassifiedIdentifierForGrid(
582 const Reference< XAxis >& xAxis
583 , const Reference< frame::XModel >& xChartModel
584 , sal_Int32 nSubGridIndex )
585 {
586 //-1: main grid, 0: first subgrid etc
587
588 OUString aAxisCID( createClassifiedIdentifierForObject( xAxis, xChartModel ) );
589 OUString aGridCID( addChildParticle( aAxisCID
590 , createChildParticleWithIndex( OBJECTTYPE_GRID, 0 ) ) );
591 if( nSubGridIndex >= 0 )
592 {
593 aGridCID = addChildParticle( aGridCID
594 , createChildParticleWithIndex( OBJECTTYPE_SUBGRID, 0 ) );
595 }
596 return aGridCID;
597 }
598
createParticleForSeries(sal_Int32 nDiagramIndex,sal_Int32 nCooSysIndex,sal_Int32 nChartTypeIndex,sal_Int32 nSeriesIndex)599 OUString ObjectIdentifier::createParticleForSeries(
600 sal_Int32 nDiagramIndex, sal_Int32 nCooSysIndex
601 , sal_Int32 nChartTypeIndex, sal_Int32 nSeriesIndex )
602 {
603 return
604 "D=" + OUString::number( nDiagramIndex ) +
605 ":CS=" + OUString::number( nCooSysIndex ) +
606 ":CT=" + OUString::number( nChartTypeIndex ) +
607 ":" + getStringForType( OBJECTTYPE_DATA_SERIES ) + "=" +
608 OUString::number( nSeriesIndex );
609 }
610
createParticleForLegend(ChartModel &)611 OUString ObjectIdentifier::createParticleForLegend( ChartModel& )
612 {
613 //todo: if more than one diagram is implemented, find the correct diagram which is owner of the given legend
614
615 return ObjectIdentifier::createParticleForDiagram() + ":" + getStringForType( OBJECTTYPE_LEGEND ) + "=";
616 }
617
createParticleForLegend(const Reference<frame::XModel> &)618 OUString ObjectIdentifier::createParticleForLegend(
619 const Reference< frame::XModel >& )
620 {
621 //todo: if more than one diagram is implemented, find the correct diagram which is owner of the given legend
622
623 return ObjectIdentifier::createParticleForDiagram() + ":" + getStringForType( OBJECTTYPE_LEGEND ) + "=";
624 }
625
createClassifiedIdentifier(enum ObjectType eObjectType,std::u16string_view rParticleID)626 OUString ObjectIdentifier::createClassifiedIdentifier(
627 enum ObjectType eObjectType //e.g. OBJECTTYPE_DATA_SERIES
628 , std::u16string_view rParticleID )//e.g. SeriesID
629 {
630 return createClassifiedIdentifierWithParent(
631 eObjectType, rParticleID, u"" );
632 }
633
createClassifiedIdentifierWithParent(enum ObjectType eObjectType,std::u16string_view rParticleID,std::u16string_view rParentPartical,std::u16string_view rDragMethodServiceName,std::u16string_view rDragParameterString)634 OUString ObjectIdentifier::createClassifiedIdentifierWithParent(
635 enum ObjectType eObjectType //e.g. OBJECTTYPE_DATA_POINT or OBJECTTYPE_GRID
636 , std::u16string_view rParticleID //e.g. Point Index or SubGrid Index
637 , std::u16string_view rParentPartical //e.g. "Series=SeriesID" or "Grid=GridId"
638 , std::u16string_view rDragMethodServiceName
639 , std::u16string_view rDragParameterString
640 )
641 //, bool bIsMultiClickObject ) //e.g. true
642 {
643 //e.g. "MultiClick/Series=2:Point=34"
644
645 OUStringBuffer aRet( m_aProtocol );
646 aRet.append( lcl_createClassificationStringForType( eObjectType, rDragMethodServiceName, rDragParameterString ));
647 if(aRet.getLength() > static_cast<sal_Int32>(strlen(m_aProtocol)))
648 aRet.append("/");
649 aRet.append(rParentPartical);
650 if(!rParentPartical.empty())
651 aRet.append(":");
652
653 aRet.append(getStringForType( eObjectType ));
654 aRet.append("=");
655 aRet.append(rParticleID);
656
657 return aRet.makeStringAndClear();
658 }
659
getPieSegmentDragMethodServiceName()660 const OUString& ObjectIdentifier::getPieSegmentDragMethodServiceName()
661 {
662 return m_aPieSegmentDragMethodServiceName;
663 }
664
createPieSegmentDragParameterString(sal_Int32 nOffsetPercent,const awt::Point & rMinimumPosition,const awt::Point & rMaximumPosition)665 OUString ObjectIdentifier::createPieSegmentDragParameterString(
666 sal_Int32 nOffsetPercent
667 , const awt::Point& rMinimumPosition
668 , const awt::Point& rMaximumPosition )
669 {
670 OUString aRet = OUString::number( nOffsetPercent )
671 + "," + OUString::number( rMinimumPosition.X )
672 + "," + OUString::number( rMinimumPosition.Y )
673 + "," + OUString::number( rMaximumPosition.X )
674 + "," + OUString::number( rMaximumPosition.Y );
675 return aRet;
676 }
677
parsePieSegmentDragParameterString(const OUString & rDragParameterString,sal_Int32 & rOffsetPercent,awt::Point & rMinimumPosition,awt::Point & rMaximumPosition)678 bool ObjectIdentifier::parsePieSegmentDragParameterString(
679 const OUString& rDragParameterString
680 , sal_Int32& rOffsetPercent
681 , awt::Point& rMinimumPosition
682 , awt::Point& rMaximumPosition )
683 {
684 sal_Int32 nCharacterIndex = 0;
685
686 OUString aValueString( rDragParameterString.getToken( 0, ',', nCharacterIndex ) );
687 rOffsetPercent = aValueString.toInt32();
688 if( nCharacterIndex < 0 )
689 return false;
690
691 aValueString = rDragParameterString.getToken( 0, ',', nCharacterIndex );
692 rMinimumPosition.X = aValueString.toInt32();
693 if( nCharacterIndex < 0 )
694 return false;
695
696 aValueString = rDragParameterString.getToken( 0, ',', nCharacterIndex );
697 rMinimumPosition.Y = aValueString.toInt32();
698 if( nCharacterIndex < 0 )
699 return false;
700
701 aValueString = rDragParameterString.getToken( 0, ',', nCharacterIndex );
702 rMaximumPosition.X = aValueString.toInt32();
703 if( nCharacterIndex < 0 )
704 return false;
705
706 aValueString = rDragParameterString.getToken( 0, ',', nCharacterIndex );
707 rMaximumPosition.Y = aValueString.toInt32();
708 return nCharacterIndex >= 0;
709 }
710
getDragMethodServiceName(const OUString & rCID)711 OUString ObjectIdentifier::getDragMethodServiceName( const OUString& rCID )
712 {
713 OUString aRet;
714
715 sal_Int32 nIndexStart = rCID.indexOf( m_aDragMethodEquals );
716 if( nIndexStart != -1 )
717 {
718 nIndexStart = rCID.indexOf( '=', nIndexStart );
719 if( nIndexStart != -1 )
720 {
721 nIndexStart++;
722 sal_Int32 nNextSlash = rCID.indexOf( '/', nIndexStart );
723 if( nNextSlash != -1 )
724 {
725 sal_Int32 nIndexEnd = nNextSlash;
726 sal_Int32 nNextColon = rCID.indexOf( ':', nIndexStart );
727 if( nNextColon < nNextSlash )
728 nIndexEnd = nNextColon;
729 aRet = rCID.copy(nIndexStart,nIndexEnd-nIndexStart);
730 }
731 }
732 }
733 return aRet;
734 }
735
getDragParameterString(const OUString & rCID)736 OUString ObjectIdentifier::getDragParameterString( const OUString& rCID )
737 {
738 OUString aRet;
739
740 sal_Int32 nIndexStart = rCID.indexOf( m_aDragParameterEquals );
741 if( nIndexStart != -1 )
742 {
743 nIndexStart = rCID.indexOf( '=', nIndexStart );
744 if( nIndexStart != -1 )
745 {
746 nIndexStart++;
747 sal_Int32 nNextSlash = rCID.indexOf( '/', nIndexStart );
748 if( nNextSlash != -1 )
749 {
750 sal_Int32 nIndexEnd = nNextSlash;
751 sal_Int32 nNextColon = rCID.indexOf( ':', nIndexStart );
752 if( nNextColon < nNextSlash )
753 nIndexEnd = nNextColon;
754 aRet = rCID.copy(nIndexStart,nIndexEnd-nIndexStart);
755 }
756 }
757 }
758 return aRet;
759 }
760
isDragableObject(const OUString & rClassifiedIdentifier)761 bool ObjectIdentifier::isDragableObject( const OUString& rClassifiedIdentifier )
762 {
763 bool bReturn = false;
764 ObjectType eObjectType = ObjectIdentifier::getObjectType( rClassifiedIdentifier );
765 switch( eObjectType )
766 {
767 case OBJECTTYPE_TITLE:
768 case OBJECTTYPE_LEGEND:
769 case OBJECTTYPE_DIAGRAM:
770 case OBJECTTYPE_DATA_LABEL:
771 case OBJECTTYPE_DATA_CURVE_EQUATION:
772 //case OBJECTTYPE_DIAGRAM_WALL:
773 bReturn = true;
774 break;
775 default:
776 OUString aDragMethodServiceName( ObjectIdentifier::getDragMethodServiceName( rClassifiedIdentifier ) );
777 bReturn = !aDragMethodServiceName.isEmpty();
778 break;
779 }
780 return bReturn;
781 }
782
isDragableObject() const783 bool ObjectIdentifier::isDragableObject() const
784 {
785 bool bReturn = false;
786 if ( isAutoGeneratedObject() )
787 {
788 bReturn = isDragableObject( m_aObjectCID );
789 }
790 else if ( isAdditionalShape() )
791 {
792 bReturn = true;
793 }
794 return bReturn;
795 }
796
isRotateableObject(const OUString & rClassifiedIdentifier)797 bool ObjectIdentifier::isRotateableObject( const OUString& rClassifiedIdentifier )
798 {
799 bool bReturn = false;
800 ObjectType eObjectType = ObjectIdentifier::getObjectType( rClassifiedIdentifier );
801 switch( eObjectType )
802 {
803 case OBJECTTYPE_DIAGRAM:
804 //case OBJECTTYPE_DIAGRAM_WALL:
805 bReturn = true;
806 break;
807 default:
808 bReturn = false;
809 break;
810 }
811 return bReturn;
812 }
813
isMultiClickObject(const OUString & rClassifiedIdentifier)814 bool ObjectIdentifier::isMultiClickObject( const OUString& rClassifiedIdentifier )
815 {
816 //the name of a shape is it's ClassifiedIdentifier
817
818 //a MultiClickObject is an object that is selectable by more than one click only ;
819 //before a MultiClickObject can be selected it is necessary that a named parent group object
820 //was selected before;
821
822 //!!!!! by definition the name of a MultiClickObject starts with "CID/MultiClick:"
823 bool bRet = rClassifiedIdentifier.match( m_aMultiClick, strlen(m_aProtocol) );
824 return bRet;
825 }
826
areSiblings(const OUString & rCID1,const OUString & rCID2)827 bool ObjectIdentifier::areSiblings( const OUString& rCID1, const OUString& rCID2 )
828 {
829 bool bRet=false;
830 sal_Int32 nLastSign1 = rCID1.lastIndexOf( '=' );
831 sal_Int32 nLastSign2 = rCID2.lastIndexOf( '=' );
832 if( nLastSign1 == rCID1.indexOf( '=' ) )//CID cannot be sibling if only one "=" occurs
833 bRet=false;
834 else if( nLastSign2 == rCID2.indexOf( '=' ) )//CID cannot be sibling if only one "=" occurs
835 bRet=false;
836 else if( ObjectIdentifier::areIdenticalObjects( rCID1, rCID2 ) )
837 bRet=false;
838 else
839 {
840 OUString aParent1( ObjectIdentifier::getFullParentParticle( rCID1 ) );
841 if( !aParent1.isEmpty() )
842 {
843 OUString aParent2( ObjectIdentifier::getFullParentParticle( rCID2 ) );
844 bRet=aParent1 == aParent2;
845 }
846 //legend entries are special:
847 if(!bRet)
848 {
849 if( getObjectType(rCID1) == OBJECTTYPE_LEGEND_ENTRY
850 && getObjectType(rCID2) == OBJECTTYPE_LEGEND_ENTRY )
851 bRet = true;
852 }
853 }
854 return bRet;
855 }
856
areIdenticalObjects(const OUString & rCID1,const OUString & rCID2)857 bool ObjectIdentifier::areIdenticalObjects( const OUString& rCID1, const OUString& rCID2 )
858 {
859 if( rCID1 == rCID2 )
860 return true;
861 //draggable pie or donut segments need special treatment, as their CIDs do change with offset
862 {
863 if( rCID1.indexOf( m_aPieSegmentDragMethodServiceName ) < 0
864 || rCID2.indexOf( m_aPieSegmentDragMethodServiceName ) < 0 )
865 return false;
866
867 OUString aID1( ObjectIdentifier::getObjectID( rCID1 ) );
868 OUString aID2( ObjectIdentifier::getObjectID( rCID2 ) );
869 if( !aID1.isEmpty() && aID1 == aID2 )
870 return true;
871 }
872 return false;
873 }
874
getStringForType(ObjectType eObjectType)875 OUString ObjectIdentifier::getStringForType( ObjectType eObjectType )
876 {
877 OUString aRet;
878 switch( eObjectType )
879 {
880 case OBJECTTYPE_PAGE:
881 aRet="Page";
882 break;
883 case OBJECTTYPE_TITLE:
884 aRet="Title";
885 break;
886 case OBJECTTYPE_LEGEND:
887 aRet="Legend";
888 break;
889 case OBJECTTYPE_LEGEND_ENTRY:
890 aRet="LegendEntry";
891 break;
892 case OBJECTTYPE_DIAGRAM:
893 aRet="D";
894 break;
895 case OBJECTTYPE_DIAGRAM_WALL:
896 aRet="DiagramWall";
897 break;
898 case OBJECTTYPE_DIAGRAM_FLOOR:
899 aRet="DiagramFloor";
900 break;
901 case OBJECTTYPE_AXIS:
902 aRet="Axis";
903 break;
904 case OBJECTTYPE_AXIS_UNITLABEL:
905 aRet="AxisUnitLabel";
906 break;
907 case OBJECTTYPE_GRID:
908 aRet="Grid";
909 break;
910 case OBJECTTYPE_SUBGRID:
911 aRet="SubGrid";
912 break;
913 case OBJECTTYPE_DATA_SERIES:
914 aRet="Series";
915 break;
916 case OBJECTTYPE_DATA_POINT:
917 aRet="Point";
918 break;
919 case OBJECTTYPE_DATA_LABELS:
920 aRet="DataLabels";
921 break;
922 case OBJECTTYPE_DATA_LABEL:
923 aRet="DataLabel";
924 break;
925 case OBJECTTYPE_DATA_ERRORS_X:
926 aRet="ErrorsX";
927 break;
928 case OBJECTTYPE_DATA_ERRORS_Y:
929 aRet="ErrorsY";
930 break;
931 case OBJECTTYPE_DATA_ERRORS_Z:
932 aRet="ErrorsZ";
933 break;
934 case OBJECTTYPE_DATA_CURVE:
935 aRet="Curve";
936 break;
937 case OBJECTTYPE_DATA_CURVE_EQUATION:
938 aRet="Equation";
939 break;
940 case OBJECTTYPE_DATA_AVERAGE_LINE:
941 aRet="Average";
942 break;
943 case OBJECTTYPE_DATA_STOCK_RANGE:
944 aRet="StockRange";
945 break;
946 case OBJECTTYPE_DATA_STOCK_LOSS:
947 aRet="StockLoss";
948 break;
949 case OBJECTTYPE_DATA_STOCK_GAIN:
950 aRet="StockGain";
951 break;
952 default: //OBJECTTYPE_UNKNOWN
953 ;
954 }
955 return aRet;
956 }
957
getObjectType(const OUString & rCID)958 ObjectType ObjectIdentifier::getObjectType( const OUString& rCID )
959 {
960 ObjectType eRet;
961 sal_Int32 nLastSign = rCID.lastIndexOf( ':' );//last sign before the type string
962 if(nLastSign==-1)
963 nLastSign = rCID.lastIndexOf( '/' );
964 if(nLastSign==-1)
965 {
966 sal_Int32 nEndIndex = rCID.lastIndexOf( '=' );
967 if(nEndIndex==-1)
968 return OBJECTTYPE_UNKNOWN;
969 nLastSign = 0;
970 }
971 if( nLastSign>0 )
972 nLastSign++;
973
974 if( rCID.match("Page",nLastSign) )
975 eRet = OBJECTTYPE_PAGE;
976 else if( rCID.match("Title",nLastSign) )
977 eRet = OBJECTTYPE_TITLE;
978 else if( rCID.match("LegendEntry",nLastSign) )
979 eRet = OBJECTTYPE_LEGEND_ENTRY;
980 else if( rCID.match("Legend",nLastSign) )
981 eRet = OBJECTTYPE_LEGEND;
982 else if( rCID.match("DiagramWall",nLastSign) )
983 eRet = OBJECTTYPE_DIAGRAM_WALL;
984 else if( rCID.match("DiagramFloor",nLastSign) )
985 eRet = OBJECTTYPE_DIAGRAM_FLOOR;
986 else if( rCID.match("D=",nLastSign) )
987 eRet = OBJECTTYPE_DIAGRAM;
988 else if( rCID.match("AxisUnitLabel",nLastSign) )
989 eRet = OBJECTTYPE_AXIS_UNITLABEL;
990 else if( rCID.match("Axis",nLastSign) )
991 eRet = OBJECTTYPE_AXIS;
992 else if( rCID.match("Grid",nLastSign) )
993 eRet = OBJECTTYPE_GRID;
994 else if( rCID.match("SubGrid",nLastSign) )
995 eRet = OBJECTTYPE_SUBGRID;
996 else if( rCID.match("Series",nLastSign) )
997 eRet = OBJECTTYPE_DATA_SERIES;
998 else if( rCID.match("Point",nLastSign) )
999 eRet = OBJECTTYPE_DATA_POINT;
1000 else if( rCID.match("DataLabels",nLastSign) )
1001 eRet = OBJECTTYPE_DATA_LABELS;
1002 else if( rCID.match("DataLabel",nLastSign) )
1003 eRet = OBJECTTYPE_DATA_LABEL;
1004 else if( rCID.match("ErrorsX",nLastSign) )
1005 eRet = OBJECTTYPE_DATA_ERRORS_X;
1006 else if( rCID.match("ErrorsY",nLastSign) )
1007 eRet = OBJECTTYPE_DATA_ERRORS_Y;
1008 else if( rCID.match("ErrorsZ",nLastSign) )
1009 eRet = OBJECTTYPE_DATA_ERRORS_Z;
1010 else if( rCID.match("Curve",nLastSign) )
1011 eRet = OBJECTTYPE_DATA_CURVE;
1012 else if( rCID.match("Equation",nLastSign) )
1013 eRet = OBJECTTYPE_DATA_CURVE_EQUATION;
1014 else if( rCID.match("Average",nLastSign) )
1015 eRet = OBJECTTYPE_DATA_AVERAGE_LINE;
1016 else if( rCID.match("StockRange",nLastSign) )
1017 eRet = OBJECTTYPE_DATA_STOCK_RANGE;
1018 else if( rCID.match("StockLoss",nLastSign) )
1019 eRet = OBJECTTYPE_DATA_STOCK_LOSS;
1020 else if( rCID.match("StockGain",nLastSign) )
1021 eRet = OBJECTTYPE_DATA_STOCK_GAIN;
1022 else
1023 eRet = OBJECTTYPE_UNKNOWN;
1024
1025 return eRet;
1026 }
1027
getObjectType() const1028 ObjectType ObjectIdentifier::getObjectType() const
1029 {
1030 ObjectType eObjectType( OBJECTTYPE_UNKNOWN );
1031 if ( isAutoGeneratedObject() )
1032 {
1033 eObjectType = getObjectType( m_aObjectCID );
1034 }
1035 else if ( isAdditionalShape() )
1036 {
1037 eObjectType = OBJECTTYPE_SHAPE;
1038 }
1039 return eObjectType;
1040 }
1041
createDataCurveCID(std::u16string_view rSeriesParticle,sal_Int32 nCurveIndex,bool bAverageLine)1042 OUString ObjectIdentifier::createDataCurveCID(
1043 std::u16string_view rSeriesParticle
1044 , sal_Int32 nCurveIndex
1045 , bool bAverageLine )
1046 {
1047 OUString aParticleID( OUString::number( nCurveIndex ) );
1048 ObjectType eType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE;
1049 return createClassifiedIdentifierWithParent( eType, aParticleID, rSeriesParticle );
1050 }
1051
createDataCurveEquationCID(std::u16string_view rSeriesParticle,sal_Int32 nCurveIndex)1052 OUString ObjectIdentifier::createDataCurveEquationCID(
1053 std::u16string_view rSeriesParticle
1054 , sal_Int32 nCurveIndex )
1055 {
1056 OUString aParticleID( OUString::number( nCurveIndex ) );
1057 return createClassifiedIdentifierWithParent( OBJECTTYPE_DATA_CURVE_EQUATION, aParticleID, rSeriesParticle );
1058 }
1059
addChildParticle(const OUString & rParticle,std::u16string_view rChildParticle)1060 OUString ObjectIdentifier::addChildParticle( const OUString& rParticle, std::u16string_view rChildParticle )
1061 {
1062 OUStringBuffer aRet(rParticle);
1063
1064 if( !aRet.isEmpty() && !rChildParticle.empty() )
1065 aRet.append(":");
1066 if( !rChildParticle.empty() )
1067 aRet.append(rChildParticle);
1068
1069 return aRet.makeStringAndClear();
1070 }
1071
createChildParticleWithIndex(ObjectType eObjectType,sal_Int32 nIndex)1072 OUString ObjectIdentifier::createChildParticleWithIndex( ObjectType eObjectType, sal_Int32 nIndex )
1073 {
1074 OUStringBuffer aRet( getStringForType( eObjectType ) );
1075 if( !aRet.isEmpty() )
1076 {
1077 aRet.append("=");
1078 aRet.append(nIndex);
1079 }
1080 return aRet.makeStringAndClear();
1081 }
1082
getIndexFromParticleOrCID(const OUString & rParticleOrCID)1083 sal_Int32 ObjectIdentifier::getIndexFromParticleOrCID( const OUString& rParticleOrCID )
1084 {
1085 const OUString aIndexString = lcl_getIndexStringAfterString( rParticleOrCID, "=" );
1086 return lcl_StringToIndex( aIndexString.getToken( 0, ',' ) );
1087 }
1088
createSeriesSubObjectStub(ObjectType eSubObjectType,const OUString & rSeriesParticle,std::u16string_view rDragMethodServiceName,std::u16string_view rDragParameterString)1089 OUString ObjectIdentifier::createSeriesSubObjectStub( ObjectType eSubObjectType
1090 , const OUString& rSeriesParticle
1091 , std::u16string_view rDragMethodServiceName
1092 , std::u16string_view rDragParameterString )
1093 {
1094 OUString aChildParticle = getStringForType( eSubObjectType ) + "=";
1095
1096 return createClassifiedIdentifierForParticles(
1097 rSeriesParticle, aChildParticle
1098 , rDragMethodServiceName, rDragParameterString );
1099 }
1100
createPointCID(std::u16string_view rPointCID_Stub,sal_Int32 nIndex)1101 OUString ObjectIdentifier::createPointCID( std::u16string_view rPointCID_Stub, sal_Int32 nIndex )
1102 {
1103 return rPointCID_Stub + OUString::number( nIndex );
1104 }
1105
getParticleID(const OUString & rCID)1106 OUString ObjectIdentifier::getParticleID( const OUString& rCID )
1107 {
1108 OUString aRet;
1109 sal_Int32 nLast = rCID.lastIndexOf('=');
1110 if(nLast>=0)
1111 aRet = rCID.copy(++nLast);
1112 return aRet;
1113 }
1114
getFullParentParticle(const OUString & rCID)1115 OUString ObjectIdentifier::getFullParentParticle( const OUString& rCID )
1116 {
1117 OUString aRet;
1118
1119 sal_Int32 nStartPos = rCID.lastIndexOf('/');
1120 if( nStartPos>=0 )
1121 {
1122 nStartPos++;
1123 sal_Int32 nEndPos = rCID.lastIndexOf(':');
1124 if( nEndPos>=0 && nStartPos < nEndPos )
1125 {
1126 aRet = rCID.copy(nStartPos,nEndPos-nStartPos);
1127 }
1128 }
1129
1130 return aRet;
1131 }
1132
getObjectID(const OUString & rCID)1133 OUString ObjectIdentifier::getObjectID( const OUString& rCID )
1134 {
1135 OUString aRet;
1136
1137 sal_Int32 nStartPos = rCID.lastIndexOf('/');
1138 if( nStartPos>=0 )
1139 {
1140 nStartPos++;
1141 sal_Int32 nEndPos = rCID.getLength();
1142 aRet = rCID.copy(nStartPos,nEndPos-nStartPos);
1143 }
1144
1145 return aRet;
1146 }
1147
isCID(const OUString & rName)1148 bool ObjectIdentifier::isCID( const OUString& rName )
1149 {
1150 return !rName.isEmpty() && rName.match( m_aProtocol );
1151 }
1152
getObjectPropertySet(const OUString & rObjectCID,const Reference<chart2::XChartDocument> & xChartDocument)1153 Reference< beans::XPropertySet > ObjectIdentifier::getObjectPropertySet(
1154 const OUString& rObjectCID,
1155 const Reference< chart2::XChartDocument >& xChartDocument )
1156 {
1157 return ObjectIdentifier::getObjectPropertySet(
1158 rObjectCID, Reference< frame::XModel >( xChartDocument ));
1159 }
1160
getObjectPropertySet(const OUString & rObjectCID,const Reference<frame::XModel> & xChartModel)1161 Reference< beans::XPropertySet > ObjectIdentifier::getObjectPropertySet(
1162 const OUString& rObjectCID
1163 , const Reference< frame::XModel >& xChartModel )
1164 {
1165 //return the model object that is indicated by rObjectCID
1166 if(rObjectCID.isEmpty())
1167 return nullptr;
1168 if(!xChartModel.is())
1169 return nullptr;
1170
1171 Reference< beans::XPropertySet > xObjectProperties;
1172 try
1173 {
1174 ObjectType eObjectType = ObjectIdentifier::getObjectType( rObjectCID );
1175 OUString aParticleID = ObjectIdentifier::getParticleID( rObjectCID );
1176
1177 Reference< XDiagram > xDiagram;
1178 Reference< XCoordinateSystem > xCooSys;
1179 lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys );
1180
1181 switch(eObjectType)
1182 {
1183 case OBJECTTYPE_PAGE:
1184 {
1185 Reference< XChartDocument > xChartDocument( xChartModel, uno::UNO_QUERY );
1186 if( xChartDocument.is())
1187 xObjectProperties.set( xChartDocument->getPageBackground() );
1188 }
1189 break;
1190 case OBJECTTYPE_TITLE:
1191 {
1192 TitleHelper::eTitleType aTitleType = getTitleTypeForCID( rObjectCID );
1193 Reference< XTitle > xTitle( TitleHelper::getTitle( aTitleType, xChartModel ) );
1194 xObjectProperties.set( xTitle, uno::UNO_QUERY );
1195 }
1196 break;
1197 case OBJECTTYPE_LEGEND:
1198 {
1199 if( xDiagram.is() )
1200 xObjectProperties.set( xDiagram->getLegend(), uno::UNO_QUERY );
1201 }
1202 break;
1203 case OBJECTTYPE_LEGEND_ENTRY:
1204 break;
1205 case OBJECTTYPE_DIAGRAM:
1206 {
1207 xObjectProperties.set( xDiagram, uno::UNO_QUERY );
1208 }
1209 break;
1210 case OBJECTTYPE_DIAGRAM_WALL:
1211 {
1212 if( xDiagram.is() )
1213 xObjectProperties.set( xDiagram->getWall() );
1214 }
1215 break;
1216 case OBJECTTYPE_DIAGRAM_FLOOR:
1217 {
1218 if( xDiagram.is() )
1219 xObjectProperties.set( xDiagram->getFloor() );
1220 }
1221 break;
1222 case OBJECTTYPE_AXIS:
1223 {
1224 sal_Int32 nDimensionIndex = -1;
1225 sal_Int32 nAxisIndex = -1;
1226 lcl_parseAxisIndices( nDimensionIndex, nAxisIndex, rObjectCID );
1227
1228 Reference< chart2::XAxis > xAxis(
1229 AxisHelper::getAxis( nDimensionIndex, nAxisIndex, xCooSys ) );
1230 if( xAxis.is() )
1231 xObjectProperties.set( xAxis, uno::UNO_QUERY );
1232 }
1233 break;
1234 case OBJECTTYPE_AXIS_UNITLABEL:
1235 break;
1236 case OBJECTTYPE_GRID:
1237 case OBJECTTYPE_SUBGRID:
1238 {
1239 sal_Int32 nDimensionIndex = -1;
1240 sal_Int32 nAxisIndex = -1;
1241 lcl_parseAxisIndices( nDimensionIndex, nAxisIndex, rObjectCID );
1242
1243 sal_Int32 nSubGridIndex = -1;
1244 lcl_parseGridIndices( nSubGridIndex, rObjectCID );
1245
1246 xObjectProperties.set( AxisHelper::getGridProperties( xCooSys , nDimensionIndex, nAxisIndex, nSubGridIndex ) );
1247 }
1248 break;
1249 case OBJECTTYPE_DATA_LABELS:
1250 case OBJECTTYPE_DATA_SERIES:
1251 {
1252 Reference< XDataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID(
1253 rObjectCID, xChartModel ) );
1254 if( xSeries.is() )
1255 xObjectProperties.set( xSeries, uno::UNO_QUERY );
1256
1257 break;
1258 }
1259 case OBJECTTYPE_DATA_LABEL:
1260 case OBJECTTYPE_DATA_POINT:
1261 {
1262 Reference< XDataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID(
1263 rObjectCID, xChartModel ) );
1264 if(xSeries.is())
1265 {
1266 sal_Int32 nIndex = aParticleID.toInt32();
1267 xObjectProperties = xSeries->getDataPointByIndex( nIndex );
1268 }
1269 break;
1270 }
1271 case OBJECTTYPE_DATA_ERRORS_X:
1272 case OBJECTTYPE_DATA_ERRORS_Y:
1273 case OBJECTTYPE_DATA_ERRORS_Z:
1274 {
1275 Reference< XDataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID(
1276 rObjectCID, xChartModel ) );
1277 if(xSeries.is())
1278 {
1279 Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY );
1280 Reference< beans::XPropertySet > xErrorBarProp;
1281 if( xSeriesProp.is() )
1282 {
1283 OUString errorBar;
1284
1285 if ( eObjectType == OBJECTTYPE_DATA_ERRORS_X)
1286 errorBar = CHART_UNONAME_ERRORBAR_X;
1287 else if (eObjectType == OBJECTTYPE_DATA_ERRORS_Y)
1288 errorBar = CHART_UNONAME_ERRORBAR_Y;
1289 else
1290 errorBar = "ErrorBarZ";
1291
1292 xSeriesProp->getPropertyValue( errorBar ) >>= xErrorBarProp;
1293 xObjectProperties = xErrorBarProp;
1294 }
1295 }
1296 break;
1297 }
1298 case OBJECTTYPE_DATA_AVERAGE_LINE:
1299 case OBJECTTYPE_DATA_CURVE:
1300 case OBJECTTYPE_DATA_CURVE_EQUATION:
1301 {
1302 Reference< XRegressionCurveContainer > xRegressionContainer( ObjectIdentifier::getDataSeriesForCID(
1303 rObjectCID, xChartModel ), uno::UNO_QUERY );
1304 if(xRegressionContainer.is())
1305 {
1306 sal_Int32 nIndex = aParticleID.toInt32();
1307 uno::Sequence< Reference< XRegressionCurve > > aCurveList =
1308 xRegressionContainer->getRegressionCurves();
1309 if( nIndex >= 0 && nIndex <aCurveList.getLength() )
1310 {
1311 if( eObjectType == OBJECTTYPE_DATA_CURVE_EQUATION )
1312 xObjectProperties.set( aCurveList[nIndex]->getEquationProperties());
1313 else
1314 xObjectProperties.set( aCurveList[nIndex], uno::UNO_QUERY );
1315 }
1316 }
1317 break;
1318 }
1319 case OBJECTTYPE_DATA_STOCK_RANGE:
1320 break;
1321 case OBJECTTYPE_DATA_STOCK_LOSS:
1322 {
1323 Reference<XChartType> xChartType( lcl_getFirstStockChartType( xChartModel ) );
1324 Reference< beans::XPropertySet > xChartTypeProps( xChartType, uno::UNO_QUERY );
1325 if(xChartTypeProps.is())
1326 xChartTypeProps->getPropertyValue( "BlackDay" ) >>= xObjectProperties;
1327 }
1328 break;
1329 case OBJECTTYPE_DATA_STOCK_GAIN:
1330 {
1331 Reference<XChartType> xChartType( lcl_getFirstStockChartType( xChartModel ) );
1332 Reference< beans::XPropertySet > xChartTypeProps( xChartType, uno::UNO_QUERY );
1333 if(xChartTypeProps.is())
1334 xChartTypeProps->getPropertyValue( "WhiteDay" ) >>= xObjectProperties;
1335 }
1336 break;
1337 default: //OBJECTTYPE_UNKNOWN
1338 break;
1339 }
1340 }
1341 catch(const uno::Exception&)
1342 {
1343 DBG_UNHANDLED_EXCEPTION("chart2");
1344 }
1345 return xObjectProperties;
1346 }
1347
getAxisForCID(const OUString & rObjectCID,const Reference<frame::XModel> & xChartModel)1348 Reference< XAxis > ObjectIdentifier::getAxisForCID(
1349 const OUString& rObjectCID
1350 , const Reference< frame::XModel >& xChartModel )
1351 {
1352 Reference< XDiagram > xDiagram;
1353 Reference< XCoordinateSystem > xCooSys;
1354 lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys );
1355
1356 sal_Int32 nDimensionIndex = -1;
1357 sal_Int32 nAxisIndex = -1;
1358 lcl_parseAxisIndices( nDimensionIndex, nAxisIndex, rObjectCID );
1359
1360 return AxisHelper::getAxis( nDimensionIndex, nAxisIndex, xCooSys );
1361 }
1362
getDataSeriesForCID(const OUString & rObjectCID,const Reference<frame::XModel> & xChartModel)1363 Reference< XDataSeries > ObjectIdentifier::getDataSeriesForCID(
1364 const OUString& rObjectCID
1365 , const Reference< frame::XModel >& xChartModel )
1366 {
1367 Reference< XDataSeries > xSeries;
1368
1369 Reference< XDiagram > xDiagram;
1370 Reference< XCoordinateSystem > xCooSys;
1371 lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys );
1372
1373 sal_Int32 nChartTypeIndex = -1;
1374 sal_Int32 nSeriesIndex = -1;
1375 sal_Int32 nPointIndex = -1;
1376 lcl_parseSeriesIndices( nChartTypeIndex, nSeriesIndex, nPointIndex, rObjectCID );
1377
1378 Reference< XDataSeriesContainer > xDataSeriesContainer( DiagramHelper::getChartTypeByIndex( xDiagram, nChartTypeIndex ), uno::UNO_QUERY );
1379 if( xDataSeriesContainer.is() )
1380 {
1381 uno::Sequence< uno::Reference< XDataSeries > > aDataSeriesSeq( xDataSeriesContainer->getDataSeries() );
1382 if( nSeriesIndex >= 0 && nSeriesIndex < aDataSeriesSeq.getLength() )
1383 xSeries.set( aDataSeriesSeq[nSeriesIndex] );
1384 }
1385
1386 return xSeries;
1387 }
1388
getDiagramForCID(const OUString & rObjectCID,const uno::Reference<frame::XModel> & xChartModel)1389 Reference< XDiagram > ObjectIdentifier::getDiagramForCID(
1390 const OUString& rObjectCID
1391 , const uno::Reference< frame::XModel >& xChartModel )
1392 {
1393 Reference< XDiagram > xDiagram;
1394
1395 Reference< XCoordinateSystem > xCooSys;
1396 lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys );
1397
1398 return xDiagram;
1399 }
1400
getTitleTypeForCID(const OUString & rCID)1401 TitleHelper::eTitleType ObjectIdentifier::getTitleTypeForCID( const OUString& rCID )
1402 {
1403 TitleHelper::eTitleType eRet( TitleHelper::MAIN_TITLE );
1404
1405 OUString aParentParticle = ObjectIdentifier::getFullParentParticle( rCID );
1406 const tTitleMap& rMap = lcl_getTitleMap();
1407 tTitleMap::const_iterator aIt = std::find_if(rMap.begin(), rMap.end(),
1408 [&aParentParticle](tTitleMap::const_reference rEntry) { return aParentParticle == rEntry.second; });
1409 if (aIt != rMap.end())
1410 eRet = (*aIt).first;
1411
1412 return eRet;
1413 }
1414
getSeriesParticleFromCID(const OUString & rCID)1415 OUString ObjectIdentifier::getSeriesParticleFromCID( const OUString& rCID )
1416 {
1417 sal_Int32 nDiagramIndex = -1;
1418 sal_Int32 nCooSysIndex = -1;
1419 lcl_parseCooSysIndices( nDiagramIndex, nCooSysIndex, rCID );
1420
1421 sal_Int32 nChartTypeIndex = -1;
1422 sal_Int32 nSeriesIndex = -1;
1423 sal_Int32 nPointIndex = -1;
1424 lcl_parseSeriesIndices( nChartTypeIndex, nSeriesIndex, nPointIndex, rCID );
1425
1426 return ObjectIdentifier::createParticleForSeries( nDiagramIndex, nCooSysIndex, nChartTypeIndex, nSeriesIndex );
1427 }
1428
getMovedSeriesCID(const OUString & rObjectCID,bool bForward)1429 OUString ObjectIdentifier::getMovedSeriesCID( const OUString& rObjectCID, bool bForward )
1430 {
1431 sal_Int32 nDiagramIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, "CID/D=" ) );
1432 sal_Int32 nCooSysIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, "CS=" ) );
1433 sal_Int32 nChartTypeIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, "CT=" ) );
1434 sal_Int32 nSeriesIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, "Series=" ) );
1435
1436 if( bForward )
1437 nSeriesIndex--;
1438 else
1439 nSeriesIndex++;
1440
1441 OUString aRet = ObjectIdentifier::createParticleForSeries( nDiagramIndex, nCooSysIndex, nChartTypeIndex, nSeriesIndex );
1442 return ObjectIdentifier::createClassifiedIdentifierForParticle( aRet );
1443 }
1444
isValid() const1445 bool ObjectIdentifier::isValid() const
1446 {
1447 return ( isAutoGeneratedObject() || isAdditionalShape() );
1448 }
1449
isAutoGeneratedObject() const1450 bool ObjectIdentifier::isAutoGeneratedObject() const
1451 {
1452 return ( !m_aObjectCID.isEmpty() );
1453 }
1454
isAdditionalShape() const1455 bool ObjectIdentifier::isAdditionalShape() const
1456 {
1457 return m_xAdditionalShape.is();
1458 }
1459
getAny() const1460 Any ObjectIdentifier::getAny() const
1461 {
1462 Any aAny;
1463 if ( isAutoGeneratedObject() )
1464 {
1465 aAny <<= getObjectCID();
1466 }
1467 else if ( isAdditionalShape() )
1468 {
1469 aAny <<= getAdditionalShape();
1470 }
1471 return aAny;
1472 }
1473
1474 } //namespace chart
1475
1476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1477