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