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