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