1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <drawingml/chart/titleconverter.hxx>
22 #include <com/sun/star/chart/ChartLegendExpansion.hpp>
23 #include <com/sun/star/chart2/FormattedString.hpp>
24 #include <com/sun/star/chart2/LegendPosition.hpp>
25 #include <com/sun/star/chart2/XDiagram.hpp>
26 #include <com/sun/star/chart2/XLegend.hpp>
27 #include <com/sun/star/chart2/XTitle.hpp>
28 #include <com/sun/star/chart2/XTitled.hpp>
29 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
30 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
31 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
33 #include <comphelper/sequence.hxx>
34 #include <osl/diagnose.h>
35 #include <drawingml/textbody.hxx>
36 #include <drawingml/textparagraph.hxx>
37 #include <drawingml/chart/datasourceconverter.hxx>
38 #include <drawingml/chart/titlemodel.hxx>
39 #include <oox/token/properties.hxx>
40 #include <oox/token/tokens.hxx>
41 #include <com/sun/star/chart2/RelativePosition.hpp>
42 #include <com/sun/star/drawing/Alignment.hpp>
44 #include <oox/drawingml/chart/modelbase.hxx>
45 namespace oox::drawingml::chart
{
47 using namespace ::com::sun::star::chart2
;
48 using namespace ::com::sun::star::chart2::data
;
49 using namespace ::com::sun::star::drawing
;
50 using namespace ::com::sun::star::uno
;
53 TextConverter::TextConverter( const ConverterRoot
& rParent
, TextModel
& rModel
) :
54 ConverterBase
< TextModel
>( rParent
, rModel
)
58 TextConverter::~TextConverter()
62 Reference
< XDataSequence
> TextConverter::createDataSequence( const OUString
& rRole
)
64 Reference
< XDataSequence
> xDataSeq
;
65 if( mrModel
.mxDataSeq
.is() )
67 DataSequenceConverter
aDataSeqConv( *this, *mrModel
.mxDataSeq
);
68 xDataSeq
= aDataSeqConv
.createDataSequence( rRole
);
73 Sequence
< Reference
< XFormattedString
> > TextConverter::createStringSequence(
74 const OUString
& rDefaultText
, const ModelRef
< TextBody
>& rxTextProp
, ObjectType eObjType
)
76 OSL_ENSURE( !mrModel
.mxDataSeq
|| !mrModel
.mxTextBody
, "TextConverter::createStringSequence - linked string and rich text found" );
77 ::std::vector
< Reference
< XFormattedString
> > aStringVec
;
78 if( mrModel
.mxTextBody
.is() )
80 // rich-formatted text objects can be created, but currently Chart2 is not able to show them
81 const TextParagraphVector
& rTextParas
= mrModel
.mxTextBody
->getParagraphs();
82 for( TextParagraphVector::const_iterator aPIt
= rTextParas
.begin(), aPEnd
= rTextParas
.end(); aPIt
!= aPEnd
; ++aPIt
)
84 const TextParagraph
& rTextPara
= **aPIt
;
85 const TextCharacterProperties
& rParaProps
= rTextPara
.getProperties().getTextCharacterProperties();
86 for( TextRunVector::const_iterator aRIt
= rTextPara
.getRuns().begin(), aREnd
= rTextPara
.getRuns().end(); aRIt
!= aREnd
; ++aRIt
)
88 const TextRun
& rTextRun
= **aRIt
;
89 bool bAddNewLine
= ((aRIt
+ 1 == aREnd
) && (aPIt
+ 1 != aPEnd
)) || rTextRun
.isLineBreak();
90 Reference
< XFormattedString
> xFmtStr
= appendFormattedString( aStringVec
, rTextRun
.getText(), bAddNewLine
);
91 PropertySet
aPropSet( xFmtStr
);
92 TextCharacterProperties aRunProps
;
93 if (rParaProps
.mbHasEmptyParaProperties
&& rxTextProp
.is() && rxTextProp
->hasParagraphProperties())
95 const TextParagraphVector rDefTextParas
= rxTextProp
->getParagraphs();
96 TextParagraphVector::const_iterator aDefPIt
= rDefTextParas
.begin();
97 const TextParagraph
& rDefTextPara
= **aDefPIt
;
98 aRunProps
= rDefTextPara
.getProperties().getTextCharacterProperties();
101 aRunProps
= rParaProps
;
102 aRunProps
.assignUsed( rTextRun
.getTextCharacterProperties() );
103 getFormatter().convertTextFormatting( aPropSet
, aRunProps
, eObjType
);
110 // try to create string from linked data
111 if( mrModel
.mxDataSeq
.is() && !mrModel
.mxDataSeq
->maData
.empty() )
112 mrModel
.mxDataSeq
->maData
.begin()->second
>>= aString
;
113 // no linked string -> fall back to default string
114 if( aString
.isEmpty() )
115 aString
= rDefaultText
;
117 // create formatted string object
118 if( !aString
.isEmpty() )
120 Reference
< XFormattedString
> xFmtStr
= appendFormattedString( aStringVec
, aString
, false );
121 PropertySet
aPropSet( xFmtStr
);
122 getFormatter().convertTextFormatting( aPropSet
, rxTextProp
, eObjType
);
126 return comphelper::containerToSequence( aStringVec
);
129 Reference
< XFormattedString
> TextConverter::appendFormattedString(
130 ::std::vector
< Reference
< XFormattedString
> >& orStringVec
, const OUString
& rString
, bool bAddNewLine
) const
132 Reference
< XFormattedString2
> xFmtStr
;
135 xFmtStr
= FormattedString::create( ConverterRoot::getComponentContext() );
136 xFmtStr
->setString( bAddNewLine
? (rString
+ "\n") : rString
);
137 orStringVec
.emplace_back(xFmtStr
);
145 TitleConverter::TitleConverter( const ConverterRoot
& rParent
, TitleModel
& rModel
) :
146 ConverterBase
< TitleModel
>( rParent
, rModel
)
150 TitleConverter::~TitleConverter()
154 void TitleConverter::convertFromModel( const Reference
< XTitled
>& rxTitled
, const OUString
& rAutoTitle
, ObjectType eObjType
, sal_Int32 nMainIdx
, sal_Int32 nSubIdx
)
159 // create the formatted strings
160 TextModel
& rText
= mrModel
.mxText
.getOrCreate();
161 TextConverter
aTextConv( *this, rText
);
162 Sequence
< Reference
< XFormattedString
> > aStringSeq
= aTextConv
.createStringSequence( rAutoTitle
, mrModel
.mxTextProp
, eObjType
);
163 if( !aStringSeq
.hasElements() )
168 // create the title object and set the string data
169 Reference
< XTitle
> xTitle( createInstance( u
"com.sun.star.chart2.Title"_ustr
), UNO_QUERY_THROW
);
170 xTitle
->setText( aStringSeq
);
171 rxTitled
->setTitleObject( xTitle
);
173 // frame formatting (text formatting already done in TextConverter::createStringSequence())
174 PropertySet
aPropSet( xTitle
);
175 getFormatter().convertFrameFormatting( aPropSet
, mrModel
.mxShapeProp
, eObjType
);
178 OSL_ENSURE( !mrModel
.mxTextProp
|| !rText
.mxTextBody
, "TitleConverter::convertFromModel - multiple text properties" );
179 ModelRef
< TextBody
> xTextProp
= mrModel
.mxTextProp
.is() ? mrModel
.mxTextProp
: rText
.mxTextBody
;
180 ObjectFormatter::convertTextRotation( aPropSet
, xTextProp
, true, mrModel
.mnDefaultRotation
);
182 // register the title and layout data for conversion of position
183 registerTitleLayout( xTitle
, mrModel
.mxLayout
, eObjType
, nMainIdx
, nSubIdx
);
190 LegendConverter::LegendConverter( const ConverterRoot
& rParent
, LegendModel
& rModel
) :
191 ConverterBase
< LegendModel
>( rParent
, rModel
)
195 LegendConverter::~LegendConverter()
199 void LegendConverter::convertFromModel( const Reference
< XDiagram
>& rxDiagram
)
201 if( !rxDiagram
.is() )
206 namespace cssc
= css::chart
;
207 namespace cssc2
= css::chart2
;
210 Reference
< XLegend
> xLegend( createInstance( u
"com.sun.star.chart2.Legend"_ustr
), UNO_QUERY_THROW
);
211 rxDiagram
->setLegend( xLegend
);
212 PropertySet
aPropSet( xLegend
);
213 aPropSet
.setProperty( PROP_Show
, true );
216 getFormatter().convertFormatting( aPropSet
, mrModel
.mxShapeProp
, mrModel
.mxTextProp
, OBJECTTYPE_LEGEND
);
218 // predefined legend position and expansion
219 cssc2::LegendPosition eLegendPos
= cssc2::LegendPosition_LINE_END
;
220 cssc::ChartLegendExpansion eLegendExpand
= cssc::ChartLegendExpansion_CUSTOM
;
221 RelativePosition eRelPos
;
222 bool bTopRight
=false;
223 switch( mrModel
.mnPosition
)
226 eLegendPos
= cssc2::LegendPosition_LINE_START
;
227 eLegendExpand
= cssc::ChartLegendExpansion_HIGH
;
230 eLegendPos
= cssc2::LegendPosition_LINE_END
;
231 eLegendExpand
= cssc::ChartLegendExpansion_HIGH
;
233 case XML_tr
: // top-right not supported
235 eRelPos
.Secondary
=0;
236 eRelPos
.Anchor
= Alignment_TOP_RIGHT
;
240 eLegendPos
= cssc2::LegendPosition_PAGE_START
;
241 eLegendExpand
= cssc::ChartLegendExpansion_WIDE
;
244 eLegendPos
= cssc2::LegendPosition_PAGE_END
;
245 eLegendExpand
= cssc::ChartLegendExpansion_WIDE
;
248 bool bManualLayout
=false;
249 // manual positioning and size
250 if( mrModel
.mxLayout
)
252 LayoutConverter
aLayoutConv( *this, *mrModel
.mxLayout
);
253 // manual size needs ChartLegendExpansion_CUSTOM
254 if( aLayoutConv
.convertFromModel( aPropSet
) )
256 eLegendExpand
= cssc::ChartLegendExpansion_CUSTOM
;
258 bManualLayout
= !aLayoutConv
.getAutoLayout();
261 // set position and expansion properties
262 aPropSet
.setProperty( PROP_AnchorPosition
, eLegendPos
);
263 aPropSet
.setProperty( PROP_Expansion
, eLegendExpand
);
265 if (bTopRight
&& !bManualLayout
)
266 aPropSet
.setProperty( PROP_RelativePosition
, Any(eRelPos
));
268 aPropSet
.setProperty(PROP_Overlay
, mrModel
.mbOverlay
);
270 if (mrModel
.maLegendEntries
.size() > 0)
271 legendEntriesFormatting(rxDiagram
);
278 void LegendConverter::legendEntriesFormatting(const Reference
<XDiagram
>& rxDiagram
)
280 Reference
<XCoordinateSystemContainer
> xCooSysContainer(rxDiagram
, UNO_QUERY_THROW
);
281 const Sequence
<Reference
<XCoordinateSystem
>> xCooSysSequence(xCooSysContainer
->getCoordinateSystems());
282 if (!xCooSysSequence
.hasElements())
285 sal_Int32 nIndex
= 0;
286 for (const auto& rCooSys
: xCooSysSequence
)
288 PropertySet
aCooSysProp(rCooSys
);
289 bool bSwapXAndY
= aCooSysProp
.getBoolProperty(PROP_SwapXAndYAxis
);
291 Reference
<XChartTypeContainer
> xChartTypeContainer(rCooSys
, UNO_QUERY_THROW
);
292 const Sequence
<Reference
<XChartType
>> xChartTypeSequence(xChartTypeContainer
->getChartTypes());
293 if (!xChartTypeSequence
.hasElements())
296 for (const auto& rCT
: xChartTypeSequence
)
298 Reference
<XDataSeriesContainer
> xDSCont(rCT
, UNO_QUERY
);
303 = rCT
->getChartType().equalsIgnoreAsciiCase("com.sun.star.chart2.PieChartType");
306 PropertySet
xChartTypeProp(rCT
);
307 bIsPie
= !xChartTypeProp
.getBoolProperty(PROP_UseRings
);
309 const Sequence
<Reference
<XDataSeries
>> aDataSeriesSeq
= xDSCont
->getDataSeries();
311 nIndex
+= aDataSeriesSeq
.getLength() - 1;
312 for (const auto& rDataSeries
: aDataSeriesSeq
)
314 PropertySet
aSeriesProp(rDataSeries
);
315 bool bVaryColorsByPoint
= aSeriesProp
.getBoolProperty(PROP_VaryColorsByPoint
);
317 if (bVaryColorsByPoint
|| bIsPie
)
319 Reference
<XDataSource
> xDSrc(rDataSeries
, UNO_QUERY
);
323 const Sequence
<Reference
<XLabeledDataSequence
> > aDataSeqs
= xDSrc
->getDataSequences();
324 std::vector
<sal_Int32
> deletedLegendEntries
;
326 for (const auto& rDataSeq
: aDataSeqs
)
328 Reference
<XDataSequence
> xValues
= rDataSeq
->getValues();
332 sal_Int32 nDataSeqSize
= xValues
->getData().getLength();
333 for (sal_Int32 i
= 0; i
< nDataSeqSize
; ++i
)
335 for (const auto& rLegendEntry
: mrModel
.maLegendEntries
)
337 if (nIndex
== rLegendEntry
->mnLegendEntryIdx
&& rLegendEntry
->mbLabelDeleted
)
339 deletedLegendEntries
.push_back(j
+ i
);
347 if (deletedLegendEntries
.size() > 0)
348 aSeriesProp
.setProperty(PROP_DeletedLegendEntries
, comphelper::containerToSequence(deletedLegendEntries
));
352 for (const auto& rLegendEntry
: mrModel
.maLegendEntries
)
354 if (nIndex
== rLegendEntry
->mnLegendEntryIdx
)
356 aSeriesProp
.setProperty(PROP_ShowLegendEntry
, !rLegendEntry
->mbLabelDeleted
);
360 bSwapXAndY
? nIndex
-- : nIndex
++;
364 nIndex
+= aDataSeriesSeq
.getLength() + 1;
369 } // namespace oox::drawingml::chart
371 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */