File: | home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx |
Warning: | line 1669, column 24 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 <xechart.hxx> | |||
21 | ||||
22 | #include <com/sun/star/i18n/XBreakIterator.hpp> | |||
23 | #include <com/sun/star/i18n/ScriptType.hpp> | |||
24 | #include <com/sun/star/drawing/FillStyle.hpp> | |||
25 | #include <com/sun/star/drawing/XShapes.hpp> | |||
26 | #include <com/sun/star/chart/XChartDocument.hpp> | |||
27 | #include <com/sun/star/chart/ChartAxisLabelPosition.hpp> | |||
28 | #include <com/sun/star/chart/ChartAxisPosition.hpp> | |||
29 | #include <com/sun/star/chart/ChartLegendExpansion.hpp> | |||
30 | #include <com/sun/star/chart/DataLabelPlacement.hpp> | |||
31 | #include <com/sun/star/chart/ErrorBarStyle.hpp> | |||
32 | #include <com/sun/star/chart/MissingValueTreatment.hpp> | |||
33 | #include <com/sun/star/chart/TimeInterval.hpp> | |||
34 | #include <com/sun/star/chart/TimeUnit.hpp> | |||
35 | #include <com/sun/star/chart/XAxisSupplier.hpp> | |||
36 | #include <com/sun/star/chart/XDiagramPositioning.hpp> | |||
37 | #include <com/sun/star/chart2/XChartDocument.hpp> | |||
38 | #include <com/sun/star/chart2/XDiagram.hpp> | |||
39 | #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> | |||
40 | #include <com/sun/star/chart2/XChartTypeContainer.hpp> | |||
41 | #include <com/sun/star/chart2/XDataSeriesContainer.hpp> | |||
42 | #include <com/sun/star/chart2/XRegressionCurveContainer.hpp> | |||
43 | #include <com/sun/star/chart2/XTitled.hpp> | |||
44 | #include <com/sun/star/chart2/XColorScheme.hpp> | |||
45 | #include <com/sun/star/chart2/data/XDataSource.hpp> | |||
46 | #include <com/sun/star/chart2/AxisType.hpp> | |||
47 | #include <com/sun/star/chart2/CurveStyle.hpp> | |||
48 | #include <com/sun/star/chart2/DataPointGeometry3D.hpp> | |||
49 | #include <com/sun/star/chart2/DataPointLabel.hpp> | |||
50 | #include <com/sun/star/chart2/LegendPosition.hpp> | |||
51 | #include <com/sun/star/chart2/RelativePosition.hpp> | |||
52 | #include <com/sun/star/chart2/RelativeSize.hpp> | |||
53 | #include <com/sun/star/chart2/StackingDirection.hpp> | |||
54 | #include <com/sun/star/chart2/TickmarkStyle.hpp> | |||
55 | ||||
56 | #include <tools/gen.hxx> | |||
57 | #include <vcl/outdev.hxx> | |||
58 | #include <filter/msfilter/escherex.hxx> | |||
59 | ||||
60 | #include <document.hxx> | |||
61 | #include <compiler.hxx> | |||
62 | #include <tokenarray.hxx> | |||
63 | #include <xeescher.hxx> | |||
64 | #include <xeformula.hxx> | |||
65 | #include <xehelper.hxx> | |||
66 | #include <xepage.hxx> | |||
67 | #include <xestyle.hxx> | |||
68 | #include <xltools.hxx> | |||
69 | ||||
70 | #include <memory> | |||
71 | ||||
72 | using ::com::sun::star::uno::Any; | |||
73 | using ::com::sun::star::uno::Reference; | |||
74 | using ::com::sun::star::uno::Sequence; | |||
75 | using ::com::sun::star::uno::UNO_QUERY; | |||
76 | using ::com::sun::star::uno::UNO_QUERY_THROW; | |||
77 | using ::com::sun::star::uno::UNO_SET_THROW; | |||
78 | using ::com::sun::star::uno::Exception; | |||
79 | using ::com::sun::star::beans::XPropertySet; | |||
80 | using ::com::sun::star::i18n::XBreakIterator; | |||
81 | using ::com::sun::star::frame::XModel; | |||
82 | using ::com::sun::star::drawing::XShape; | |||
83 | using ::com::sun::star::drawing::XShapes; | |||
84 | ||||
85 | using ::com::sun::star::chart2::IncrementData; | |||
86 | using ::com::sun::star::chart2::RelativePosition; | |||
87 | using ::com::sun::star::chart2::RelativeSize; | |||
88 | using ::com::sun::star::chart2::ScaleData; | |||
89 | using ::com::sun::star::chart2::SubIncrement; | |||
90 | using ::com::sun::star::chart2::XAxis; | |||
91 | using ::com::sun::star::chart2::XChartDocument; | |||
92 | using ::com::sun::star::chart2::XChartTypeContainer; | |||
93 | using ::com::sun::star::chart2::XColorScheme; | |||
94 | using ::com::sun::star::chart2::XCoordinateSystem; | |||
95 | using ::com::sun::star::chart2::XCoordinateSystemContainer; | |||
96 | using ::com::sun::star::chart2::XChartType; | |||
97 | using ::com::sun::star::chart2::XDataSeries; | |||
98 | using ::com::sun::star::chart2::XDataSeriesContainer; | |||
99 | using ::com::sun::star::chart2::XDiagram; | |||
100 | using ::com::sun::star::chart2::XFormattedString; | |||
101 | using ::com::sun::star::chart2::XLegend; | |||
102 | using ::com::sun::star::chart2::XRegressionCurve; | |||
103 | using ::com::sun::star::chart2::XRegressionCurveContainer; | |||
104 | using ::com::sun::star::chart2::XTitle; | |||
105 | using ::com::sun::star::chart2::XTitled; | |||
106 | ||||
107 | using ::com::sun::star::chart2::data::XDataSequence; | |||
108 | using ::com::sun::star::chart2::data::XDataSource; | |||
109 | using ::com::sun::star::chart2::data::XLabeledDataSequence; | |||
110 | ||||
111 | using ::formula::FormulaToken; | |||
112 | using ::formula::FormulaTokenArrayPlainIterator; | |||
113 | ||||
114 | namespace cssc = ::com::sun::star::chart; | |||
115 | namespace cssc2 = ::com::sun::star::chart2; | |||
116 | ||||
117 | // Helpers ==================================================================== | |||
118 | ||||
119 | namespace { | |||
120 | ||||
121 | XclExpStream& operator<<( XclExpStream& rStrm, const XclChRectangle& rRect ) | |||
122 | { | |||
123 | return rStrm << rRect.mnX << rRect.mnY << rRect.mnWidth << rRect.mnHeight; | |||
124 | } | |||
125 | ||||
126 | void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef const & xRec ) | |||
127 | { | |||
128 | if( xRec ) | |||
129 | xRec->Save( rStrm ); | |||
130 | } | |||
131 | ||||
132 | /** Saves the passed record (group) together with a leading value record. */ | |||
133 | template< typename Type > | |||
134 | void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef const & xRec, sal_uInt16 nRecId, Type nValue ) | |||
135 | { | |||
136 | if( xRec ) | |||
137 | { | |||
138 | XclExpValueRecord< Type >( nRecId, nValue ).Save( rStrm ); | |||
139 | xRec->Save( rStrm ); | |||
140 | } | |||
141 | } | |||
142 | ||||
143 | template<typename ValueType, typename KeyType> | |||
144 | void lclSaveRecord(XclExpStream& rStrm, ValueType* pRec, sal_uInt16 nRecId, KeyType nValue) | |||
145 | { | |||
146 | if (pRec) | |||
147 | { | |||
148 | XclExpValueRecord<KeyType>(nRecId, nValue).Save(rStrm); | |||
149 | pRec->Save(rStrm); | |||
150 | } | |||
151 | } | |||
152 | ||||
153 | void lclWriteChFrBlockRecord( XclExpStream& rStrm, const XclChFrBlock& rFrBlock, bool bBegin ) | |||
154 | { | |||
155 | sal_uInt16 nRecId = bBegin ? EXC_ID_CHFRBLOCKBEGIN : EXC_ID_CHFRBLOCKEND; | |||
156 | rStrm.StartRecord( nRecId, 12 ); | |||
157 | rStrm << nRecId << EXC_FUTUREREC_EMPTYFLAGS << rFrBlock.mnType << rFrBlock.mnContext << rFrBlock.mnValue1 << rFrBlock.mnValue2; | |||
158 | rStrm.EndRecord(); | |||
159 | } | |||
160 | ||||
161 | template< typename Type > | |||
162 | bool lclIsAutoAnyOrGetValue( Type& rValue, const Any& rAny ) | |||
163 | { | |||
164 | return !rAny.hasValue() || !(rAny >>= rValue); | |||
165 | } | |||
166 | ||||
167 | bool lclIsAutoAnyOrGetScaledValue( double& rfValue, const Any& rAny, bool bLogScale ) | |||
168 | { | |||
169 | bool bIsAuto = lclIsAutoAnyOrGetValue( rfValue, rAny ); | |||
170 | if( !bIsAuto && bLogScale ) | |||
171 | rfValue = log( rfValue ) / log( 10.0 ); | |||
172 | return bIsAuto; | |||
173 | } | |||
174 | ||||
175 | sal_uInt16 lclGetTimeValue( const XclExpRoot& rRoot, double fSerialDate, sal_uInt16 nTimeUnit ) | |||
176 | { | |||
177 | DateTime aDateTime = rRoot.GetDateTimeFromDouble( fSerialDate ); | |||
178 | switch( nTimeUnit ) | |||
179 | { | |||
180 | case EXC_CHDATERANGE_DAYS: | |||
181 | return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16((sal_uInt16) 0xFFFF) ); | |||
182 | case EXC_CHDATERANGE_MONTHS: | |||
183 | return ::limit_cast< sal_uInt16, sal_uInt16 >( 12 * (aDateTime.GetYear() - rRoot.GetBaseYear()) + aDateTime.GetMonth() - 1, 0, SAL_MAX_INT16((sal_Int16) 0x7FFF) ); | |||
184 | case EXC_CHDATERANGE_YEARS: | |||
185 | return ::limit_cast< sal_uInt16, sal_uInt16 >( aDateTime.GetYear() - rRoot.GetBaseYear(), 0, SAL_MAX_INT16((sal_Int16) 0x7FFF) ); | |||
186 | default: | |||
187 | OSL_ENSURE( false, "lclGetTimeValue - unexpected time unit" )do { if (true && (!(false))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "187" ": "), "%s", "lclGetTimeValue - unexpected time unit" ); } } while (false); | |||
188 | } | |||
189 | return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16((sal_uInt16) 0xFFFF) ); | |||
190 | } | |||
191 | ||||
192 | bool lclConvertTimeValue( const XclExpRoot& rRoot, sal_uInt16& rnValue, const Any& rAny, sal_uInt16 nTimeUnit ) | |||
193 | { | |||
194 | double fSerialDate = 0; | |||
195 | bool bAuto = lclIsAutoAnyOrGetValue( fSerialDate, rAny ); | |||
196 | if( !bAuto ) | |||
197 | rnValue = lclGetTimeValue( rRoot, fSerialDate, nTimeUnit ); | |||
198 | return bAuto; | |||
199 | } | |||
200 | ||||
201 | sal_uInt16 lclGetTimeUnit( sal_Int32 nApiTimeUnit ) | |||
202 | { | |||
203 | switch( nApiTimeUnit ) | |||
204 | { | |||
205 | case cssc::TimeUnit::DAY: return EXC_CHDATERANGE_DAYS; | |||
206 | case cssc::TimeUnit::MONTH: return EXC_CHDATERANGE_MONTHS; | |||
207 | case cssc::TimeUnit::YEAR: return EXC_CHDATERANGE_YEARS; | |||
208 | default: OSL_ENSURE( false, "lclGetTimeUnit - unexpected time unit" )do { if (true && (!(false))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "208" ": "), "%s", "lclGetTimeUnit - unexpected time unit" ); } } while (false); | |||
209 | } | |||
210 | return EXC_CHDATERANGE_DAYS; | |||
211 | } | |||
212 | ||||
213 | bool lclConvertTimeInterval( sal_uInt16& rnValue, sal_uInt16& rnTimeUnit, const Any& rAny ) | |||
214 | { | |||
215 | cssc::TimeInterval aInterval; | |||
216 | bool bAuto = lclIsAutoAnyOrGetValue( aInterval, rAny ); | |||
217 | if( !bAuto ) | |||
218 | { | |||
219 | rnValue = ::limit_cast< sal_uInt16, sal_Int32 >( aInterval.Number, 1, SAL_MAX_UINT16((sal_uInt16) 0xFFFF) ); | |||
220 | rnTimeUnit = lclGetTimeUnit( aInterval.TimeUnit ); | |||
221 | } | |||
222 | return bAuto; | |||
223 | } | |||
224 | ||||
225 | } // namespace | |||
226 | ||||
227 | // Common ===================================================================== | |||
228 | ||||
229 | /** Stores global data needed in various classes of the Chart export filter. */ | |||
230 | struct XclExpChRootData : public XclChRootData | |||
231 | { | |||
232 | typedef ::std::vector< XclChFrBlock > XclChFrBlockVector; | |||
233 | ||||
234 | XclExpChChart& mrChartData; /// The chart data object. | |||
235 | XclChFrBlockVector maWrittenFrBlocks; /// Stack of future record levels already written out. | |||
236 | XclChFrBlockVector maUnwrittenFrBlocks; /// Stack of future record levels not yet written out. | |||
237 | ||||
238 | explicit XclExpChRootData( XclExpChChart& rChartData ) : mrChartData( rChartData ) {} | |||
239 | ||||
240 | /** Registers a new future record level. */ | |||
241 | void RegisterFutureRecBlock( const XclChFrBlock& rFrBlock ); | |||
242 | /** Initializes the current future record level (writes all unwritten CHFRBLOCKBEGIN records). */ | |||
243 | void InitializeFutureRecBlock( XclExpStream& rStrm ); | |||
244 | /** Finalizes the current future record level (writes CHFRBLOCKEND record if needed). */ | |||
245 | void FinalizeFutureRecBlock( XclExpStream& rStrm ); | |||
246 | }; | |||
247 | ||||
248 | void XclExpChRootData::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock ) | |||
249 | { | |||
250 | maUnwrittenFrBlocks.push_back( rFrBlock ); | |||
251 | } | |||
252 | ||||
253 | void XclExpChRootData::InitializeFutureRecBlock( XclExpStream& rStrm ) | |||
254 | { | |||
255 | // first call from a future record writes all missing CHFRBLOCKBEGIN records | |||
256 | if( maUnwrittenFrBlocks.empty() ) | |||
257 | return; | |||
258 | ||||
259 | // write the leading CHFRINFO record | |||
260 | if( maWrittenFrBlocks.empty() ) | |||
261 | { | |||
262 | rStrm.StartRecord( EXC_ID_CHFRINFO, 20 ); | |||
263 | rStrm << EXC_ID_CHFRINFO << EXC_FUTUREREC_EMPTYFLAGS << EXC_CHFRINFO_EXCELXP2003 << EXC_CHFRINFO_EXCELXP2003 << sal_uInt16( 3 ); | |||
264 | rStrm << sal_uInt16( 0x0850 ) << sal_uInt16( 0x085A ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x086A ) << sal_uInt16( 0x086B ); | |||
265 | rStrm.EndRecord(); | |||
266 | } | |||
267 | // write all unwritten CHFRBLOCKBEGIN records | |||
268 | for( const auto& rUnwrittenFrBlock : maUnwrittenFrBlocks ) | |||
269 | { | |||
270 | OSL_ENSURE( rUnwrittenFrBlock.mnType != EXC_CHFRBLOCK_TYPE_UNKNOWN, "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type" )do { if (true && (!(rUnwrittenFrBlock.mnType != EXC_CHFRBLOCK_TYPE_UNKNOWN ))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "270" ": "), "%s", "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type" ); } } while (false); | |||
271 | lclWriteChFrBlockRecord( rStrm, rUnwrittenFrBlock, true ); | |||
272 | } | |||
273 | // move all record infos to vector of written blocks | |||
274 | maWrittenFrBlocks.insert( maWrittenFrBlocks.end(), maUnwrittenFrBlocks.begin(), maUnwrittenFrBlocks.end() ); | |||
275 | maUnwrittenFrBlocks.clear(); | |||
276 | } | |||
277 | ||||
278 | void XclExpChRootData::FinalizeFutureRecBlock( XclExpStream& rStrm ) | |||
279 | { | |||
280 | OSL_ENSURE( !maUnwrittenFrBlocks.empty() || !maWrittenFrBlocks.empty(), "XclExpChRootData::FinalizeFutureRecBlock - no future record level found" )do { if (true && (!(!maUnwrittenFrBlocks.empty() || ! maWrittenFrBlocks.empty()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "280" ": "), "%s", "XclExpChRootData::FinalizeFutureRecBlock - no future record level found" ); } } while (false); | |||
281 | if( !maUnwrittenFrBlocks.empty() ) | |||
282 | { | |||
283 | // no future record has been written, just forget the topmost level | |||
284 | maUnwrittenFrBlocks.pop_back(); | |||
285 | } | |||
286 | else if( !maWrittenFrBlocks.empty() ) | |||
287 | { | |||
288 | // write the CHFRBLOCKEND record for the topmost block and delete it | |||
289 | lclWriteChFrBlockRecord( rStrm, maWrittenFrBlocks.back(), false ); | |||
290 | maWrittenFrBlocks.pop_back(); | |||
291 | } | |||
292 | } | |||
293 | ||||
294 | XclExpChRoot::XclExpChRoot( const XclExpRoot& rRoot, XclExpChChart& rChartData ) : | |||
295 | XclExpRoot( rRoot ), | |||
296 | mxChData( std::make_shared<XclExpChRootData>( rChartData ) ) | |||
297 | { | |||
298 | } | |||
299 | ||||
300 | XclExpChRoot::~XclExpChRoot() | |||
301 | { | |||
302 | } | |||
303 | ||||
304 | Reference< XChartDocument > const & XclExpChRoot::GetChartDocument() const | |||
305 | { | |||
306 | return mxChData->mxChartDoc; | |||
307 | } | |||
308 | ||||
309 | XclExpChChart& XclExpChRoot::GetChartData() const | |||
310 | { | |||
311 | return mxChData->mrChartData; | |||
312 | } | |||
313 | ||||
314 | const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType ) const | |||
315 | { | |||
316 | return mxChData->mxTypeInfoProv->GetTypeInfo( eType ); | |||
317 | } | |||
318 | ||||
319 | const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( const OUString& rServiceName ) const | |||
320 | { | |||
321 | return mxChData->mxTypeInfoProv->GetTypeInfoFromService( rServiceName ); | |||
322 | } | |||
323 | ||||
324 | const XclChFormatInfo& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType ) const | |||
325 | { | |||
326 | return mxChData->mxFmtInfoProv->GetFormatInfo( eObjType ); | |||
327 | } | |||
328 | ||||
329 | void XclExpChRoot::InitConversion( css::uno::Reference< css::chart2::XChartDocument > const & xChartDoc, const tools::Rectangle& rChartRect ) const | |||
330 | { | |||
331 | mxChData->InitConversion( GetRoot(), xChartDoc, rChartRect ); | |||
332 | } | |||
333 | ||||
334 | void XclExpChRoot::FinishConversion() const | |||
335 | { | |||
336 | mxChData->FinishConversion(); | |||
337 | } | |||
338 | ||||
339 | bool XclExpChRoot::IsSystemColor( const Color& rColor, sal_uInt16 nSysColorIdx ) const | |||
340 | { | |||
341 | XclExpPalette& rPal = GetPalette(); | |||
342 | return rPal.IsSystemColor( nSysColorIdx ) && (rColor == rPal.GetDefColor( nSysColorIdx )); | |||
343 | } | |||
344 | ||||
345 | void XclExpChRoot::SetSystemColor( Color& rColor, sal_uInt32& rnColorId, sal_uInt16 nSysColorIdx ) const | |||
346 | { | |||
347 | OSL_ENSURE( GetPalette().IsSystemColor( nSysColorIdx ), "XclExpChRoot::SetSystemColor - invalid color index" )do { if (true && (!(GetPalette().IsSystemColor( nSysColorIdx )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "347" ": "), "%s", "XclExpChRoot::SetSystemColor - invalid color index" ); } } while (false); | |||
348 | rColor = GetPalette().GetDefColor( nSysColorIdx ); | |||
349 | rnColorId = XclExpPalette::GetColorIdFromIndex( nSysColorIdx ); | |||
350 | } | |||
351 | ||||
352 | sal_Int32 XclExpChRoot::CalcChartXFromHmm( sal_Int32 nPosX ) const | |||
353 | { | |||
354 | return ::limit_cast< sal_Int32, double >( (nPosX - mxChData->mnBorderGapX) / mxChData->mfUnitSizeX, 0, EXC_CHART_TOTALUNITS ); | |||
355 | } | |||
356 | ||||
357 | sal_Int32 XclExpChRoot::CalcChartYFromHmm( sal_Int32 nPosY ) const | |||
358 | { | |||
359 | return ::limit_cast< sal_Int32, double >( (nPosY - mxChData->mnBorderGapY) / mxChData->mfUnitSizeY, 0, EXC_CHART_TOTALUNITS ); | |||
360 | } | |||
361 | ||||
362 | XclChRectangle XclExpChRoot::CalcChartRectFromHmm( const css::awt::Rectangle& rRect ) const | |||
363 | { | |||
364 | XclChRectangle aRect; | |||
365 | aRect.mnX = CalcChartXFromHmm( rRect.X ); | |||
366 | aRect.mnY = CalcChartYFromHmm( rRect.Y ); | |||
367 | aRect.mnWidth = CalcChartXFromHmm( rRect.Width ); | |||
368 | aRect.mnHeight = CalcChartYFromHmm( rRect.Height ); | |||
369 | return aRect; | |||
370 | } | |||
371 | ||||
372 | void XclExpChRoot::ConvertLineFormat( XclChLineFormat& rLineFmt, | |||
373 | const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const | |||
374 | { | |||
375 | GetChartPropSetHelper().ReadLineProperties( | |||
376 | rLineFmt, *mxChData->mxLineDashTable, rPropSet, ePropMode ); | |||
377 | } | |||
378 | ||||
379 | bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat& rAreaFmt, | |||
380 | const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const | |||
381 | { | |||
382 | return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt, rPropSet, ePropMode ); | |||
383 | } | |||
384 | ||||
385 | void XclExpChRoot::ConvertEscherFormat( | |||
386 | XclChEscherFormat& rEscherFmt, XclChPicFormat& rPicFmt, | |||
387 | const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const | |||
388 | { | |||
389 | GetChartPropSetHelper().ReadEscherProperties( rEscherFmt, rPicFmt, | |||
390 | *mxChData->mxGradientTable, *mxChData->mxHatchTable, *mxChData->mxBitmapTable, rPropSet, ePropMode ); | |||
391 | } | |||
392 | ||||
393 | sal_uInt16 XclExpChRoot::ConvertFont( const ScfPropertySet& rPropSet, sal_Int16 nScript ) const | |||
394 | { | |||
395 | XclFontData aFontData; | |||
396 | GetFontPropSetHelper().ReadFontProperties( aFontData, rPropSet, EXC_FONTPROPSET_CHART, nScript ); | |||
397 | return GetFontBuffer().Insert( aFontData, EXC_COLOR_CHARTTEXT ); | |||
398 | } | |||
399 | ||||
400 | sal_uInt16 XclExpChRoot::ConvertPieRotation( const ScfPropertySet& rPropSet ) | |||
401 | { | |||
402 | sal_Int32 nApiRot = 0; | |||
403 | rPropSet.GetProperty( nApiRot, EXC_CHPROP_STARTINGANGLE"StartingAngle" ); | |||
404 | return static_cast< sal_uInt16 >( (450 - (nApiRot % 360)) % 360 ); | |||
405 | } | |||
406 | ||||
407 | void XclExpChRoot::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock ) | |||
408 | { | |||
409 | mxChData->RegisterFutureRecBlock( rFrBlock ); | |||
410 | } | |||
411 | ||||
412 | void XclExpChRoot::InitializeFutureRecBlock( XclExpStream& rStrm ) | |||
413 | { | |||
414 | mxChData->InitializeFutureRecBlock( rStrm ); | |||
415 | } | |||
416 | ||||
417 | void XclExpChRoot::FinalizeFutureRecBlock( XclExpStream& rStrm ) | |||
418 | { | |||
419 | mxChData->FinalizeFutureRecBlock( rStrm ); | |||
420 | } | |||
421 | ||||
422 | XclExpChGroupBase::XclExpChGroupBase( const XclExpChRoot& rRoot, | |||
423 | sal_uInt16 nFrType, sal_uInt16 nRecId, std::size_t nRecSize ) : | |||
424 | XclExpRecord( nRecId, nRecSize ), | |||
425 | XclExpChRoot( rRoot ), | |||
426 | maFrBlock( nFrType ) | |||
427 | { | |||
428 | } | |||
429 | ||||
430 | XclExpChGroupBase::~XclExpChGroupBase() | |||
431 | { | |||
432 | } | |||
433 | ||||
434 | void XclExpChGroupBase::Save( XclExpStream& rStrm ) | |||
435 | { | |||
436 | // header record | |||
437 | XclExpRecord::Save( rStrm ); | |||
438 | // group records | |||
439 | if( !HasSubRecords() ) | |||
440 | return; | |||
441 | ||||
442 | // register the future record context corresponding to this record group | |||
443 | RegisterFutureRecBlock( maFrBlock ); | |||
444 | // CHBEGIN record | |||
445 | XclExpEmptyRecord( EXC_ID_CHBEGIN ).Save( rStrm ); | |||
446 | // embedded records | |||
447 | WriteSubRecords( rStrm ); | |||
448 | // finalize the future records, must be done before the closing CHEND | |||
449 | FinalizeFutureRecBlock( rStrm ); | |||
450 | // CHEND record | |||
451 | XclExpEmptyRecord( EXC_ID_CHEND ).Save( rStrm ); | |||
452 | } | |||
453 | ||||
454 | bool XclExpChGroupBase::HasSubRecords() const | |||
455 | { | |||
456 | return true; | |||
457 | } | |||
458 | ||||
459 | void XclExpChGroupBase::SetFutureRecordContext( sal_uInt16 nFrContext, sal_uInt16 nFrValue1, sal_uInt16 nFrValue2 ) | |||
460 | { | |||
461 | maFrBlock.mnContext = nFrContext; | |||
462 | maFrBlock.mnValue1 = nFrValue1; | |||
463 | maFrBlock.mnValue2 = nFrValue2; | |||
464 | } | |||
465 | ||||
466 | XclExpChFutureRecordBase::XclExpChFutureRecordBase( const XclExpChRoot& rRoot, | |||
467 | XclFutureRecType eRecType, sal_uInt16 nRecId, std::size_t nRecSize ) : | |||
468 | XclExpFutureRecord( eRecType, nRecId, nRecSize ), | |||
469 | XclExpChRoot( rRoot ) | |||
470 | { | |||
471 | } | |||
472 | ||||
473 | void XclExpChFutureRecordBase::Save( XclExpStream& rStrm ) | |||
474 | { | |||
475 | InitializeFutureRecBlock( rStrm ); | |||
476 | XclExpFutureRecord::Save( rStrm ); | |||
477 | } | |||
478 | ||||
479 | // Frame formatting =========================================================== | |||
480 | ||||
481 | XclExpChFramePos::XclExpChFramePos( sal_uInt16 nTLMode ) : | |||
482 | XclExpRecord( EXC_ID_CHFRAMEPOS, 20 ) | |||
483 | { | |||
484 | maData.mnTLMode = nTLMode; | |||
485 | maData.mnBRMode = EXC_CHFRAMEPOS_PARENT; | |||
486 | } | |||
487 | ||||
488 | void XclExpChFramePos::WriteBody( XclExpStream& rStrm ) | |||
489 | { | |||
490 | rStrm << maData.mnTLMode << maData.mnBRMode << maData.maRect; | |||
491 | } | |||
492 | ||||
493 | XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot& rRoot ) : | |||
494 | XclExpRecord( EXC_ID_CHLINEFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 10 ), | |||
495 | mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ) | |||
496 | { | |||
497 | } | |||
498 | ||||
499 | void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType ) | |||
500 | { | |||
501 | switch( eDefFrameType ) | |||
502 | { | |||
503 | case EXC_CHFRAMETYPE_AUTO: | |||
504 | SetAuto( true ); | |||
505 | break; | |||
506 | case EXC_CHFRAMETYPE_INVISIBLE: | |||
507 | SetAuto( false ); | |||
508 | maData.mnPattern = EXC_CHLINEFORMAT_NONE; | |||
509 | break; | |||
510 | default: | |||
511 | OSL_FAIL( "XclExpChLineFormat::SetDefault - unknown frame type" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "511" ": "), "%s", "XclExpChLineFormat::SetDefault - unknown frame type" ); } } while (false); | |||
512 | } | |||
513 | } | |||
514 | ||||
515 | void XclExpChLineFormat::Convert( const XclExpChRoot& rRoot, | |||
516 | const ScfPropertySet& rPropSet, XclChObjectType eObjType ) | |||
517 | { | |||
518 | const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType ); | |||
519 | rRoot.ConvertLineFormat( maData, rPropSet, rFmtInfo.mePropMode ); | |||
520 | if( HasLine() ) | |||
521 | { | |||
522 | // detect system color, set color identifier (TODO: detect automatic series line) | |||
523 | if( (eObjType != EXC_CHOBJTYPE_LINEARSERIES) && rRoot.IsSystemColor( maData.maColor, rFmtInfo.mnAutoLineColorIdx ) ) | |||
524 | { | |||
525 | // store color index from automatic format data | |||
526 | mnColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoLineColorIdx ); | |||
527 | // try to set automatic mode | |||
528 | bool bAuto = (maData.mnPattern == EXC_CHLINEFORMAT_SOLID) && (maData.mnWeight == rFmtInfo.mnAutoLineWeight); | |||
529 | ::set_flag( maData.mnFlags, EXC_CHLINEFORMAT_AUTO, bAuto ); | |||
530 | } | |||
531 | else | |||
532 | { | |||
533 | // user defined color - register in palette | |||
534 | mnColorId = rRoot.GetPalette().InsertColor( maData.maColor, EXC_COLOR_CHARTLINE ); | |||
535 | } | |||
536 | } | |||
537 | else | |||
538 | { | |||
539 | // no line - set default system color | |||
540 | rRoot.SetSystemColor( maData.maColor, mnColorId, EXC_COLOR_CHWINDOWTEXT ); | |||
541 | } | |||
542 | } | |||
543 | ||||
544 | bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType ) const | |||
545 | { | |||
546 | return | |||
547 | ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasLine()) || | |||
548 | ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto()); | |||
549 | } | |||
550 | ||||
551 | void XclExpChLineFormat::WriteBody( XclExpStream& rStrm ) | |||
552 | { | |||
553 | rStrm << maData.maColor << maData.mnPattern << maData.mnWeight << maData.mnFlags; | |||
554 | if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 ) | |||
555 | rStrm << rStrm.GetRoot().GetPalette().GetColorIndex( mnColorId ); | |||
556 | } | |||
557 | ||||
558 | namespace { | |||
559 | ||||
560 | /** Creates a CHLINEFORMAT record from the passed property set. */ | |||
561 | XclExpChLineFormatRef lclCreateLineFormat( const XclExpChRoot& rRoot, | |||
562 | const ScfPropertySet& rPropSet, XclChObjectType eObjType ) | |||
563 | { | |||
564 | XclExpChLineFormatRef xLineFmt = new XclExpChLineFormat( rRoot ); | |||
565 | xLineFmt->Convert( rRoot, rPropSet, eObjType ); | |||
566 | const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType ); | |||
567 | if( rFmtInfo.mbDeleteDefFrame && xLineFmt->IsDefault( rFmtInfo.meDefFrameType ) ) | |||
568 | xLineFmt.clear(); | |||
569 | return xLineFmt; | |||
570 | } | |||
571 | ||||
572 | } // namespace | |||
573 | ||||
574 | XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot& rRoot ) : | |||
575 | XclExpRecord( EXC_ID_CHAREAFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 16 : 12 ), | |||
576 | mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ), | |||
577 | mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ) | |||
578 | { | |||
579 | } | |||
580 | ||||
581 | bool XclExpChAreaFormat::Convert( const XclExpChRoot& rRoot, | |||
582 | const ScfPropertySet& rPropSet, XclChObjectType eObjType ) | |||
583 | { | |||
584 | const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType ); | |||
585 | bool bComplexFill = rRoot.ConvertAreaFormat( maData, rPropSet, rFmtInfo.mePropMode ); | |||
586 | if( HasArea() ) | |||
587 | { | |||
588 | bool bSolid = maData.mnPattern == EXC_PATT_SOLID; | |||
589 | // detect system color, set color identifier (TODO: detect automatic series area) | |||
590 | if( (eObjType != EXC_CHOBJTYPE_FILLEDSERIES) && rRoot.IsSystemColor( maData.maPattColor, rFmtInfo.mnAutoPattColorIdx ) ) | |||
591 | { | |||
592 | // store color index from automatic format data | |||
593 | mnPattColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoPattColorIdx ); | |||
594 | // set automatic mode | |||
595 | ::set_flag( maData.mnFlags, EXC_CHAREAFORMAT_AUTO, bSolid ); | |||
596 | } | |||
597 | else | |||
598 | { | |||
599 | // user defined color - register color in palette | |||
600 | mnPattColorId = rRoot.GetPalette().InsertColor( maData.maPattColor, EXC_COLOR_CHARTAREA ); | |||
601 | } | |||
602 | // background color (default system color for solid fills) | |||
603 | if( bSolid ) | |||
604 | rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT ); | |||
605 | else | |||
606 | mnBackColorId = rRoot.GetPalette().InsertColor( maData.maBackColor, EXC_COLOR_CHARTAREA ); | |||
607 | } | |||
608 | else | |||
609 | { | |||
610 | // no area - set default system colors | |||
611 | rRoot.SetSystemColor( maData.maPattColor, mnPattColorId, EXC_COLOR_CHWINDOWBACK ); | |||
612 | rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT ); | |||
613 | } | |||
614 | return bComplexFill; | |||
615 | } | |||
616 | ||||
617 | void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType ) | |||
618 | { | |||
619 | switch( eDefFrameType ) | |||
620 | { | |||
621 | case EXC_CHFRAMETYPE_AUTO: | |||
622 | SetAuto( true ); | |||
623 | break; | |||
624 | case EXC_CHFRAMETYPE_INVISIBLE: | |||
625 | SetAuto( false ); | |||
626 | maData.mnPattern = EXC_PATT_NONE; | |||
627 | break; | |||
628 | default: | |||
629 | OSL_FAIL( "XclExpChAreaFormat::SetDefault - unknown frame type" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "629" ": "), "%s", "XclExpChAreaFormat::SetDefault - unknown frame type" ); } } while (false); | |||
630 | } | |||
631 | } | |||
632 | ||||
633 | bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType ) const | |||
634 | { | |||
635 | return | |||
636 | ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasArea()) || | |||
637 | ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto()); | |||
638 | } | |||
639 | ||||
640 | void XclExpChAreaFormat::WriteBody( XclExpStream& rStrm ) | |||
641 | { | |||
642 | rStrm << maData.maPattColor << maData.maBackColor << maData.mnPattern << maData.mnFlags; | |||
643 | if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 ) | |||
644 | { | |||
645 | const XclExpPalette& rPal = rStrm.GetRoot().GetPalette(); | |||
646 | rStrm << rPal.GetColorIndex( mnPattColorId ) << rPal.GetColorIndex( mnBackColorId ); | |||
647 | } | |||
648 | } | |||
649 | ||||
650 | XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot& rRoot ) : | |||
651 | XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_UNKNOWN, EXC_ID_CHESCHERFORMAT ), | |||
652 | mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ), | |||
653 | mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ) | |||
654 | { | |||
655 | OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8 )do { if (true && (!(GetBiff() == EXC_BIFF8))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "655" ": "), "%s", "Unknown BIFF type!"); } } while (false ); | |||
656 | } | |||
657 | ||||
658 | void XclExpChEscherFormat::Convert( const ScfPropertySet& rPropSet, XclChObjectType eObjType ) | |||
659 | { | |||
660 | const XclChFormatInfo& rFmtInfo = GetFormatInfo( eObjType ); | |||
661 | ConvertEscherFormat( maData, maPicFmt, rPropSet, rFmtInfo.mePropMode ); | |||
662 | // register colors in palette | |||
663 | mnColor1Id = RegisterColor( ESCHER_Prop_fillColor385 ); | |||
664 | mnColor2Id = RegisterColor( ESCHER_Prop_fillBackColor387 ); | |||
665 | } | |||
666 | ||||
667 | bool XclExpChEscherFormat::IsValid() const | |||
668 | { | |||
669 | return static_cast< bool >(maData.mxEscherSet); | |||
670 | } | |||
671 | ||||
672 | void XclExpChEscherFormat::Save( XclExpStream& rStrm ) | |||
673 | { | |||
674 | if( maData.mxEscherSet ) | |||
675 | { | |||
676 | // replace RGB colors with palette indexes in the Escher container | |||
677 | const XclExpPalette& rPal = GetPalette(); | |||
678 | maData.mxEscherSet->AddOpt( ESCHER_Prop_fillColor385, 0x08000000 | rPal.GetColorIndex( mnColor1Id ) ); | |||
679 | maData.mxEscherSet->AddOpt( ESCHER_Prop_fillBackColor387, 0x08000000 | rPal.GetColorIndex( mnColor2Id ) ); | |||
680 | ||||
681 | // save the record group | |||
682 | XclExpChGroupBase::Save( rStrm ); | |||
683 | } | |||
684 | } | |||
685 | ||||
686 | bool XclExpChEscherFormat::HasSubRecords() const | |||
687 | { | |||
688 | // no subrecords for gradients | |||
689 | return maPicFmt.mnBmpMode != EXC_CHPICFORMAT_NONE; | |||
690 | } | |||
691 | ||||
692 | void XclExpChEscherFormat::WriteSubRecords( XclExpStream& rStrm ) | |||
693 | { | |||
694 | rStrm.StartRecord( EXC_ID_CHPICFORMAT, 14 ); | |||
695 | rStrm << maPicFmt.mnBmpMode << sal_uInt16( 0 ) << maPicFmt.mnFlags << maPicFmt.mfScale; | |||
696 | rStrm.EndRecord(); | |||
697 | } | |||
698 | ||||
699 | sal_uInt32 XclExpChEscherFormat::RegisterColor( sal_uInt16 nPropId ) | |||
700 | { | |||
701 | sal_uInt32 nBGRValue; | |||
702 | if( maData.mxEscherSet && maData.mxEscherSet->GetOpt( nPropId, nBGRValue ) ) | |||
703 | { | |||
704 | // swap red and blue | |||
705 | Color aColor( nBGRValue & 0xff, (nBGRValue >> 8) & 0xff, (nBGRValue >> 16) & 0xff ); | |||
706 | return GetPalette().InsertColor( aColor, EXC_COLOR_CHARTAREA ); | |||
707 | } | |||
708 | return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ); | |||
709 | } | |||
710 | ||||
711 | void XclExpChEscherFormat::WriteBody( XclExpStream& rStrm ) | |||
712 | { | |||
713 | OSL_ENSURE( maData.mxEscherSet, "XclExpChEscherFormat::WriteBody - missing property container" )do { if (true && (!(maData.mxEscherSet))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "713" ": "), "%s", "XclExpChEscherFormat::WriteBody - missing property container" ); } } while (false); | |||
714 | // write Escher property container via temporary memory stream | |||
715 | SvMemoryStream aMemStrm; | |||
716 | maData.mxEscherSet->Commit( aMemStrm ); | |||
717 | aMemStrm.Flush(); | |||
718 | aMemStrm.Seek( STREAM_SEEK_TO_BEGIN0L ); | |||
719 | rStrm.CopyFromStream( aMemStrm ); | |||
720 | } | |||
721 | ||||
722 | XclExpChFrameBase::XclExpChFrameBase() | |||
723 | { | |||
724 | } | |||
725 | ||||
726 | XclExpChFrameBase::~XclExpChFrameBase() | |||
727 | { | |||
728 | } | |||
729 | ||||
730 | void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot& rRoot, | |||
731 | const ScfPropertySet& rPropSet, XclChObjectType eObjType ) | |||
732 | { | |||
733 | // line format | |||
734 | mxLineFmt = new XclExpChLineFormat( rRoot ); | |||
735 | mxLineFmt->Convert( rRoot, rPropSet, eObjType ); | |||
736 | // area format (only for frame objects) | |||
737 | if( !rRoot.GetFormatInfo( eObjType ).mbIsFrame ) | |||
738 | return; | |||
739 | ||||
740 | mxAreaFmt = new XclExpChAreaFormat( rRoot ); | |||
741 | bool bComplexFill = mxAreaFmt->Convert( rRoot, rPropSet, eObjType ); | |||
742 | if( (rRoot.GetBiff() == EXC_BIFF8) && bComplexFill ) | |||
743 | { | |||
744 | mxEscherFmt = new XclExpChEscherFormat( rRoot ); | |||
745 | mxEscherFmt->Convert( rPropSet, eObjType ); | |||
746 | if( mxEscherFmt->IsValid() ) | |||
747 | mxAreaFmt->SetAuto( false ); | |||
748 | else | |||
749 | mxEscherFmt.clear(); | |||
750 | } | |||
751 | } | |||
752 | ||||
753 | void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot& rRoot, | |||
754 | XclChFrameType eDefFrameType, bool bIsFrame ) | |||
755 | { | |||
756 | // line format | |||
757 | mxLineFmt = new XclExpChLineFormat( rRoot ); | |||
758 | mxLineFmt->SetDefault( eDefFrameType ); | |||
759 | // area format (only for frame objects) | |||
760 | if( bIsFrame ) | |||
761 | { | |||
762 | mxAreaFmt = new XclExpChAreaFormat( rRoot ); | |||
763 | mxAreaFmt->SetDefault( eDefFrameType ); | |||
764 | mxEscherFmt.clear(); | |||
765 | } | |||
766 | } | |||
767 | ||||
768 | bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType ) const | |||
769 | { | |||
770 | return | |||
771 | (!mxLineFmt || mxLineFmt->IsDefault( eDefFrameType )) && | |||
772 | (!mxAreaFmt || mxAreaFmt->IsDefault( eDefFrameType )); | |||
773 | } | |||
774 | ||||
775 | void XclExpChFrameBase::WriteFrameRecords( XclExpStream& rStrm ) | |||
776 | { | |||
777 | lclSaveRecord( rStrm, mxLineFmt ); | |||
778 | lclSaveRecord( rStrm, mxAreaFmt ); | |||
779 | lclSaveRecord( rStrm, mxEscherFmt ); | |||
780 | } | |||
781 | ||||
782 | XclExpChFrame::XclExpChFrame( const XclExpChRoot& rRoot, XclChObjectType eObjType ) : | |||
783 | XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_FRAME, EXC_ID_CHFRAME, 4 ), | |||
784 | meObjType( eObjType ) | |||
785 | { | |||
786 | } | |||
787 | ||||
788 | void XclExpChFrame::Convert( const ScfPropertySet& rPropSet ) | |||
789 | { | |||
790 | ConvertFrameBase( GetChRoot(), rPropSet, meObjType ); | |||
791 | } | |||
792 | ||||
793 | void XclExpChFrame::SetAutoFlags( bool bAutoPos, bool bAutoSize ) | |||
794 | { | |||
795 | ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOPOS, bAutoPos ); | |||
796 | ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOSIZE, bAutoSize ); | |||
797 | } | |||
798 | ||||
799 | bool XclExpChFrame::IsDefault() const | |||
800 | { | |||
801 | return IsDefaultFrameBase( GetFormatInfo( meObjType ).meDefFrameType ); | |||
802 | } | |||
803 | ||||
804 | bool XclExpChFrame::IsDeleteable() const | |||
805 | { | |||
806 | return IsDefault() && GetFormatInfo( meObjType ).mbDeleteDefFrame; | |||
807 | } | |||
808 | ||||
809 | void XclExpChFrame::Save( XclExpStream& rStrm ) | |||
810 | { | |||
811 | switch( meObjType ) | |||
812 | { | |||
813 | // wall/floor frame without CHFRAME header record | |||
814 | case EXC_CHOBJTYPE_WALL3D: | |||
815 | case EXC_CHOBJTYPE_FLOOR3D: | |||
816 | WriteFrameRecords( rStrm ); | |||
817 | break; | |||
818 | default: | |||
819 | XclExpChGroupBase::Save( rStrm ); | |||
820 | } | |||
821 | } | |||
822 | ||||
823 | void XclExpChFrame::WriteSubRecords( XclExpStream& rStrm ) | |||
824 | { | |||
825 | WriteFrameRecords( rStrm ); | |||
826 | } | |||
827 | ||||
828 | void XclExpChFrame::WriteBody( XclExpStream& rStrm ) | |||
829 | { | |||
830 | rStrm << maData.mnFormat << maData.mnFlags; | |||
831 | } | |||
832 | ||||
833 | namespace { | |||
834 | ||||
835 | /** Creates a CHFRAME record from the passed property set. */ | |||
836 | XclExpChFrameRef lclCreateFrame( const XclExpChRoot& rRoot, | |||
837 | const ScfPropertySet& rPropSet, XclChObjectType eObjType ) | |||
838 | { | |||
839 | XclExpChFrameRef xFrame = new XclExpChFrame( rRoot, eObjType ); | |||
840 | xFrame->Convert( rPropSet ); | |||
841 | if( xFrame->IsDeleteable() ) | |||
842 | xFrame.clear(); | |||
843 | return xFrame; | |||
844 | } | |||
845 | ||||
846 | } // namespace | |||
847 | ||||
848 | // Source links =============================================================== | |||
849 | ||||
850 | namespace { | |||
851 | ||||
852 | void lclAddDoubleRefData( | |||
853 | ScTokenArray& orArray, const FormulaToken& rToken, | |||
854 | SCTAB nScTab1, SCCOL nScCol1, SCROW nScRow1, | |||
855 | SCTAB nScTab2, SCCOL nScCol2, SCROW nScRow2 ) | |||
856 | { | |||
857 | ScComplexRefData aComplexRef; | |||
858 | aComplexRef.InitRange(ScRange(nScCol1,nScRow1,nScTab1,nScCol2,nScRow2,nScTab2)); | |||
859 | aComplexRef.Ref1.SetFlag3D( true ); | |||
860 | ||||
861 | if( orArray.GetLen() > 0 ) | |||
862 | orArray.AddOpCode( ocUnion ); | |||
863 | ||||
864 | OSL_ENSURE( (rToken.GetType() == ::formula::svDoubleRef) || (rToken.GetType() == ::formula::svExternalDoubleRef),do { if (true && (!((rToken.GetType() == ::formula::svDoubleRef ) || (rToken.GetType() == ::formula::svExternalDoubleRef)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "865" ": "), "%s", "lclAddDoubleRefData - double reference token expected" ); } } while (false) | |||
865 | "lclAddDoubleRefData - double reference token expected")do { if (true && (!((rToken.GetType() == ::formula::svDoubleRef ) || (rToken.GetType() == ::formula::svExternalDoubleRef)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "865" ": "), "%s", "lclAddDoubleRefData - double reference token expected" ); } } while (false); | |||
866 | if( rToken.GetType() == ::formula::svExternalDoubleRef ) | |||
867 | orArray.AddExternalDoubleReference( | |||
868 | rToken.GetIndex(), rToken.GetString(), aComplexRef); | |||
869 | else | |||
870 | orArray.AddDoubleReference( aComplexRef ); | |||
871 | } | |||
872 | ||||
873 | } // namespace | |||
874 | ||||
875 | XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot& rRoot, sal_uInt8 nDestType ) : | |||
876 | XclExpRecord( EXC_ID_CHSOURCELINK ), | |||
877 | XclExpChRoot( rRoot ) | |||
878 | { | |||
879 | maData.mnDestType = nDestType; | |||
880 | maData.mnLinkType = EXC_CHSRCLINK_DIRECTLY; | |||
881 | } | |||
882 | ||||
883 | sal_uInt16 XclExpChSourceLink::ConvertDataSequence( Reference< XDataSequence > const & xDataSeq, bool bSplitToColumns, sal_uInt16 nDefCount ) | |||
884 | { | |||
885 | mxLinkFmla.reset(); | |||
886 | maData.mnLinkType = EXC_CHSRCLINK_DEFAULT; | |||
887 | ||||
888 | if( !xDataSeq.is() ) | |||
889 | return nDefCount; | |||
890 | ||||
891 | // Compile the range representation string into token array. Note that the | |||
892 | // source range text depends on the current grammar. | |||
893 | OUString aRangeRepr = xDataSeq->getSourceRangeRepresentation(); | |||
894 | ScCompiler aComp( GetDoc(), ScAddress(), GetDoc().GetGrammar() ); | |||
895 | std::unique_ptr<ScTokenArray> pArray(aComp.CompileString(aRangeRepr)); | |||
896 | if( !pArray ) | |||
897 | return nDefCount; | |||
898 | ||||
899 | ScTokenArray aArray(GetRoot().GetDoc()); | |||
900 | sal_uInt32 nValueCount = 0; | |||
901 | FormulaTokenArrayPlainIterator aIter(*pArray); | |||
902 | for( const FormulaToken* pToken = aIter.First(); pToken; pToken = aIter.Next() ) | |||
903 | { | |||
904 | switch( pToken->GetType() ) | |||
905 | { | |||
906 | case ::formula::svSingleRef: | |||
907 | case ::formula::svExternalSingleRef: | |||
908 | // for a single ref token, just add it to the new token array as is | |||
909 | if( aArray.GetLen() > 0 ) | |||
910 | aArray.AddOpCode( ocUnion ); | |||
911 | aArray.AddToken( *pToken ); | |||
912 | ++nValueCount; | |||
913 | break; | |||
914 | ||||
915 | case ::formula::svDoubleRef: | |||
916 | case ::formula::svExternalDoubleRef: | |||
917 | { | |||
918 | // split 3-dimensional ranges into single sheets | |||
919 | const ScComplexRefData& rComplexRef = *pToken->GetDoubleRef(); | |||
920 | ScAddress aAbs1 = rComplexRef.Ref1.toAbs(GetRoot().GetDoc(), ScAddress()); | |||
921 | ScAddress aAbs2 = rComplexRef.Ref2.toAbs(GetRoot().GetDoc(), ScAddress()); | |||
922 | for (SCTAB nScTab = aAbs1.Tab(); nScTab <= aAbs2.Tab(); ++nScTab) | |||
923 | { | |||
924 | // split 2-dimensional ranges into single columns | |||
925 | if (bSplitToColumns && (aAbs1.Col() < aAbs2.Col()) && (aAbs1.Row() < aAbs2.Row())) | |||
926 | for (SCCOL nScCol = aAbs1.Col(); nScCol <= aAbs2.Col(); ++nScCol) | |||
927 | lclAddDoubleRefData(aArray, *pToken, nScTab, nScCol, aAbs1.Row(), nScTab, nScCol, aAbs2.Row()); | |||
928 | else | |||
929 | lclAddDoubleRefData(aArray, *pToken, nScTab, aAbs1.Col(), aAbs1.Row(), nScTab, aAbs2.Col(), aAbs2.Row()); | |||
930 | } | |||
931 | sal_uInt32 nTabs = static_cast<sal_uInt32>(aAbs2.Tab() - aAbs1.Tab() + 1); | |||
932 | sal_uInt32 nCols = static_cast<sal_uInt32>(aAbs2.Col() - aAbs1.Col() + 1); | |||
933 | sal_uInt32 nRows = static_cast<sal_uInt32>(aAbs2.Row() - aAbs1.Row() + 1); | |||
934 | nValueCount += nCols * nRows * nTabs; | |||
935 | } | |||
936 | break; | |||
937 | ||||
938 | default:; | |||
939 | } | |||
940 | } | |||
941 | ||||
942 | const ScAddress aBaseCell; | |||
943 | mxLinkFmla = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aArray, &aBaseCell ); | |||
944 | maData.mnLinkType = EXC_CHSRCLINK_WORKSHEET; | |||
945 | return ulimit_cast< sal_uInt16 >( nValueCount, EXC_CHDATAFORMAT_MAXPOINTCOUNT ); | |||
946 | } | |||
947 | ||||
948 | void XclExpChSourceLink::ConvertString( const OUString& aString ) | |||
949 | { | |||
950 | mxString = XclExpStringHelper::CreateString( GetRoot(), aString, XclStrFlags::ForceUnicode | XclStrFlags::EightBitLength | XclStrFlags::SeparateFormats ); | |||
951 | } | |||
952 | ||||
953 | sal_uInt16 XclExpChSourceLink::ConvertStringSequence( const Sequence< Reference< XFormattedString > >& rStringSeq ) | |||
954 | { | |||
955 | mxString.reset(); | |||
956 | sal_uInt16 nFontIdx = EXC_FONT_APP; | |||
957 | if( rStringSeq.hasElements() ) | |||
958 | { | |||
959 | mxString = XclExpStringHelper::CreateString( GetRoot(), OUString(), XclStrFlags::ForceUnicode | XclStrFlags::EightBitLength | XclStrFlags::SeparateFormats ); | |||
960 | Reference< XBreakIterator > xBreakIt = GetDoc().GetBreakIterator(); | |||
961 | namespace ApiScriptType = ::com::sun::star::i18n::ScriptType; | |||
962 | ||||
963 | // convert all formatted string entries from the sequence | |||
964 | for( const Reference< XFormattedString >& rString : rStringSeq ) | |||
965 | { | |||
966 | if( rString.is() ) | |||
967 | { | |||
968 | sal_uInt16 nWstrnFontIdx = EXC_FONT_NOTFOUND; | |||
969 | sal_uInt16 nAsianFontIdx = EXC_FONT_NOTFOUND; | |||
970 | sal_uInt16 nCmplxFontIdx = EXC_FONT_NOTFOUND; | |||
971 | OUString aText = rString->getString(); | |||
972 | ScfPropertySet aStrProp( rString ); | |||
973 | ||||
974 | // #i63255# get script type for leading weak characters | |||
975 | sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText ); | |||
976 | ||||
977 | // process all script portions | |||
978 | sal_Int32 nPortionPos = 0; | |||
979 | sal_Int32 nTextLen = aText.getLength(); | |||
980 | while( nPortionPos < nTextLen ) | |||
981 | { | |||
982 | // get script type and end position of next script portion | |||
983 | sal_Int16 nScript = xBreakIt->getScriptType( aText, nPortionPos ); | |||
984 | sal_Int32 nPortionEnd = xBreakIt->endOfScript( aText, nPortionPos, nScript ); | |||
985 | ||||
986 | // reuse previous script for following weak portions | |||
987 | if( nScript == ApiScriptType::WEAK ) | |||
988 | nScript = nLastScript; | |||
989 | ||||
990 | // Excel start position of this portion | |||
991 | sal_uInt16 nXclPortionStart = mxString->Len(); | |||
992 | // add portion text to Excel string | |||
993 | XclExpStringHelper::AppendString( *mxString, GetRoot(), aText.copy( nPortionPos, nPortionEnd - nPortionPos ) ); | |||
994 | if( nXclPortionStart < mxString->Len() ) | |||
995 | { | |||
996 | // find font index variable dependent on script type | |||
997 | sal_uInt16& rnFontIdx = (nScript == ApiScriptType::COMPLEX) ? nCmplxFontIdx : | |||
998 | ((nScript == ApiScriptType::ASIAN) ? nAsianFontIdx : nWstrnFontIdx); | |||
999 | ||||
1000 | // insert font into buffer (if not yet done) | |||
1001 | if( rnFontIdx == EXC_FONT_NOTFOUND ) | |||
1002 | rnFontIdx = ConvertFont( aStrProp, nScript ); | |||
1003 | ||||
1004 | // insert font index into format run vector | |||
1005 | mxString->AppendFormat( nXclPortionStart, rnFontIdx ); | |||
1006 | } | |||
1007 | ||||
1008 | // go to next script portion | |||
1009 | nLastScript = nScript; | |||
1010 | nPortionPos = nPortionEnd; | |||
1011 | } | |||
1012 | } | |||
1013 | } | |||
1014 | if( !mxString->IsEmpty() ) | |||
1015 | { | |||
1016 | // get leading font index | |||
1017 | const XclFormatRunVec& rFormats = mxString->GetFormats(); | |||
1018 | OSL_ENSURE( !rFormats.empty() && (rFormats.front().mnChar == 0),do { if (true && (!(!rFormats.empty() && (rFormats .front().mnChar == 0)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "1019" ": "), "%s", "XclExpChSourceLink::ConvertStringSequenc - missing leading format" ); } } while (false) | |||
1019 | "XclExpChSourceLink::ConvertStringSequenc - missing leading format" )do { if (true && (!(!rFormats.empty() && (rFormats .front().mnChar == 0)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "1019" ": "), "%s", "XclExpChSourceLink::ConvertStringSequenc - missing leading format" ); } } while (false); | |||
1020 | // remove leading format run, if entire string is equally formatted | |||
1021 | if( rFormats.size() == 1 ) | |||
1022 | nFontIdx = mxString->RemoveLeadingFont(); | |||
1023 | else if( !rFormats.empty() ) | |||
1024 | nFontIdx = rFormats.front().mnFontIdx; | |||
1025 | // add trailing format run, if string is rich-formatted | |||
1026 | if( mxString->IsRich() ) | |||
1027 | mxString->AppendTrailingFormat( EXC_FONT_APP ); | |||
1028 | } | |||
1029 | } | |||
1030 | return nFontIdx; | |||
1031 | } | |||
1032 | ||||
1033 | void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet& rPropSet, bool bPercent ) | |||
1034 | { | |||
1035 | sal_Int32 nApiNumFmt = 0; | |||
1036 | if( bPercent ? rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_PERCENTAGENUMFMT"PercentageNumberFormat" ) : rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT"NumberFormat" ) ) | |||
1037 | { | |||
1038 | ::set_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT ); | |||
1039 | maData.mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) ); | |||
1040 | } | |||
1041 | } | |||
1042 | ||||
1043 | void XclExpChSourceLink::AppendString( const OUString& rStr ) | |||
1044 | { | |||
1045 | if (!mxString) | |||
1046 | return; | |||
1047 | XclExpStringHelper::AppendString( *mxString, GetRoot(), rStr ); | |||
1048 | } | |||
1049 | ||||
1050 | void XclExpChSourceLink::Save( XclExpStream& rStrm ) | |||
1051 | { | |||
1052 | // CHFORMATRUNS record | |||
1053 | if( mxString && mxString->IsRich() ) | |||
1054 | { | |||
1055 | std::size_t nRecSize = (1 + mxString->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8) ? 2 : 1); | |||
1056 | rStrm.StartRecord( EXC_ID_CHFORMATRUNS, nRecSize ); | |||
1057 | mxString->WriteFormats( rStrm, true ); | |||
1058 | rStrm.EndRecord(); | |||
1059 | } | |||
1060 | // CHSOURCELINK record | |||
1061 | XclExpRecord::Save( rStrm ); | |||
1062 | // CHSTRING record | |||
1063 | if( mxString && !mxString->IsEmpty() ) | |||
1064 | { | |||
1065 | rStrm.StartRecord( EXC_ID_CHSTRING, 2 + mxString->GetSize() ); | |||
1066 | rStrm << sal_uInt16( 0 ) << *mxString; | |||
1067 | rStrm.EndRecord(); | |||
1068 | } | |||
1069 | } | |||
1070 | ||||
1071 | void XclExpChSourceLink::WriteBody( XclExpStream& rStrm ) | |||
1072 | { | |||
1073 | rStrm << maData.mnDestType | |||
1074 | << maData.mnLinkType | |||
1075 | << maData.mnFlags | |||
1076 | << maData.mnNumFmtIdx | |||
1077 | << mxLinkFmla; | |||
1078 | } | |||
1079 | ||||
1080 | // Text ======================================================================= | |||
1081 | ||||
1082 | XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx ) : | |||
1083 | XclExpUInt16Record( EXC_ID_CHFONT, nFontIdx ) | |||
1084 | { | |||
1085 | } | |||
1086 | ||||
1087 | XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget, const XclChDataPointPos& rPointPos ) : | |||
1088 | XclExpRecord( EXC_ID_CHOBJECTLINK, 6 ) | |||
1089 | { | |||
1090 | maData.mnTarget = nLinkTarget; | |||
1091 | maData.maPointPos = rPointPos; | |||
1092 | } | |||
1093 | ||||
1094 | void XclExpChObjectLink::WriteBody( XclExpStream& rStrm ) | |||
1095 | { | |||
1096 | rStrm << maData.mnTarget << maData.maPointPos.mnSeriesIdx << maData.maPointPos.mnPointIdx; | |||
1097 | } | |||
1098 | ||||
1099 | XclExpChFrLabelProps::XclExpChFrLabelProps( const XclExpChRoot& rRoot ) : | |||
1100 | XclExpChFutureRecordBase( rRoot, EXC_FUTUREREC_UNUSEDREF, EXC_ID_CHFRLABELPROPS, 4 ) | |||
1101 | { | |||
1102 | } | |||
1103 | ||||
1104 | void XclExpChFrLabelProps::Convert( const ScfPropertySet& rPropSet, | |||
1105 | bool bShowCateg, bool bShowValue, bool bShowPercent, bool bShowBubble ) | |||
1106 | { | |||
1107 | // label value flags | |||
1108 | ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWSERIES, false ); | |||
1109 | ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWCATEG, bShowCateg ); | |||
1110 | ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWVALUE, bShowValue ); | |||
1111 | ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWPERCENT, bShowPercent ); | |||
1112 | ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWBUBBLE, bShowBubble ); | |||
1113 | ||||
1114 | // label value separator | |||
1115 | maData.maSeparator = rPropSet.GetStringProperty( EXC_CHPROP_LABELSEPARATOR"LabelSeparator" ); | |||
1116 | if( maData.maSeparator.isEmpty() ) | |||
1117 | maData.maSeparator = " "; | |||
1118 | } | |||
1119 | ||||
1120 | void XclExpChFrLabelProps::WriteBody( XclExpStream& rStrm ) | |||
1121 | { | |||
1122 | XclExpString aXclSep( maData.maSeparator, XclStrFlags::ForceUnicode | XclStrFlags::SmartFlags ); | |||
1123 | rStrm << maData.mnFlags << aXclSep; | |||
1124 | } | |||
1125 | ||||
1126 | XclExpChFontBase::~XclExpChFontBase() | |||
1127 | { | |||
1128 | } | |||
1129 | ||||
1130 | void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, sal_uInt16 nFontIdx ) | |||
1131 | { | |||
1132 | if( const XclExpFont* pFont = rRoot.GetFontBuffer().GetFont( nFontIdx ) ) | |||
1133 | { | |||
1134 | XclExpChFontRef xFont = new XclExpChFont( nFontIdx ); | |||
1135 | SetFont( xFont, pFont->GetFontData().maColor, pFont->GetFontColorId() ); | |||
1136 | } | |||
1137 | } | |||
1138 | ||||
1139 | void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet ) | |||
1140 | { | |||
1141 | ConvertFontBase( rRoot, rRoot.ConvertFont( rPropSet, rRoot.GetDefApiScript() ) ); | |||
1142 | } | |||
1143 | ||||
1144 | void XclExpChFontBase::ConvertRotationBase(const ScfPropertySet& rPropSet, bool bSupportsStacked ) | |||
1145 | { | |||
1146 | sal_uInt16 nRotation = XclChPropSetHelper::ReadRotationProperties( rPropSet, bSupportsStacked ); | |||
1147 | SetRotation( nRotation ); | |||
1148 | } | |||
1149 | ||||
1150 | XclExpChText::XclExpChText( const XclExpChRoot& rRoot ) : | |||
1151 | XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TEXT, EXC_ID_CHTEXT, (rRoot.GetBiff() == EXC_BIFF8) ? 32 : 26 ), | |||
1152 | mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ) | |||
1153 | { | |||
1154 | } | |||
1155 | ||||
1156 | void XclExpChText::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId ) | |||
1157 | { | |||
1158 | mxFont = xFont; | |||
1159 | maData.maTextColor = rColor; | |||
1160 | ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, rColor == COL_AUTO ); | |||
1161 | mnTextColorId = nColorId; | |||
1162 | } | |||
1163 | ||||
1164 | void XclExpChText::SetRotation( sal_uInt16 nRotation ) | |||
1165 | { | |||
1166 | maData.mnRotation = nRotation; | |||
1167 | ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 8, 3 ); | |||
1168 | } | |||
1169 | ||||
1170 | void XclExpChText::ConvertTitle( Reference< XTitle > const & xTitle, sal_uInt16 nTarget, const OUString* pSubTitle ) | |||
1171 | { | |||
1172 | switch( nTarget ) | |||
1173 | { | |||
1174 | case EXC_CHOBJLINK_TITLE: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_TITLE ); break; | |||
1175 | case EXC_CHOBJLINK_YAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 1 ); break; | |||
1176 | case EXC_CHOBJLINK_XAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE ); break; | |||
1177 | case EXC_CHOBJLINK_ZAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 2 ); break; | |||
1178 | } | |||
1179 | ||||
1180 | mxSrcLink.clear(); | |||
1181 | mxObjLink = new XclExpChObjectLink( nTarget, XclChDataPointPos( 0, 0 ) ); | |||
1182 | ||||
1183 | if( xTitle.is() ) | |||
1184 | { | |||
1185 | // title frame formatting | |||
1186 | ScfPropertySet aTitleProp( xTitle ); | |||
1187 | mxFrame = lclCreateFrame( GetChRoot(), aTitleProp, EXC_CHOBJTYPE_TEXT ); | |||
1188 | ||||
1189 | // string sequence | |||
1190 | mxSrcLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ); | |||
1191 | sal_uInt16 nFontIdx = mxSrcLink->ConvertStringSequence( xTitle->getText() ); | |||
1192 | if (pSubTitle) | |||
1193 | { | |||
1194 | // append subtitle as the 2nd line of the title. | |||
1195 | OUString aSubTitle = "\n" + *pSubTitle; | |||
1196 | mxSrcLink->AppendString(aSubTitle); | |||
1197 | } | |||
1198 | ||||
1199 | ConvertFontBase( GetChRoot(), nFontIdx ); | |||
1200 | ||||
1201 | // rotation | |||
1202 | ConvertRotationBase( aTitleProp, true ); | |||
1203 | ||||
1204 | // manual text position - only for main title | |||
1205 | mxFramePos = new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT ); | |||
1206 | if( nTarget == EXC_CHOBJLINK_TITLE ) | |||
1207 | { | |||
1208 | Any aRelPos; | |||
1209 | if( aTitleProp.GetAnyProperty( aRelPos, EXC_CHPROP_RELATIVEPOSITION"RelativePosition" ) && aRelPos.has< RelativePosition >() ) try | |||
1210 | { | |||
1211 | // calculate absolute position for CHTEXT record | |||
1212 | Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW ); | |||
1213 | Reference< XShape > xTitleShape( xChart1Doc->getTitle(), UNO_SET_THROW ); | |||
1214 | css::awt::Point aPos = xTitleShape->getPosition(); | |||
1215 | css::awt::Size aSize = xTitleShape->getSize(); | |||
1216 | css::awt::Rectangle aRect( aPos.X, aPos.Y, aSize.Width, aSize.Height ); | |||
1217 | maData.maRect = CalcChartRectFromHmm( aRect ); | |||
1218 | ::insert_value( maData.mnFlags2, EXC_CHTEXT_POS_MOVED, 0, 4 ); | |||
1219 | // manual title position implies manual plot area | |||
1220 | GetChartData().SetManualPlotArea(); | |||
1221 | // calculate the default title position in chart units | |||
1222 | sal_Int32 nDefPosX = ::std::max< sal_Int32 >( (EXC_CHART_TOTALUNITS - maData.maRect.mnWidth) / 2, 0 ); | |||
1223 | sal_Int32 nDefPosY = 85; | |||
1224 | // set the position relative to the standard position | |||
1225 | XclChRectangle& rFrameRect = mxFramePos->GetFramePosData().maRect; | |||
1226 | rFrameRect.mnX = maData.maRect.mnX - nDefPosX; | |||
1227 | rFrameRect.mnY = maData.maRect.mnY - nDefPosY; | |||
1228 | } | |||
1229 | catch( Exception& ) | |||
1230 | { | |||
1231 | } | |||
1232 | } | |||
1233 | } | |||
1234 | else | |||
1235 | { | |||
1236 | ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED ); | |||
1237 | } | |||
1238 | } | |||
1239 | ||||
1240 | void XclExpChText::ConvertLegend( const ScfPropertySet& rPropSet ) | |||
1241 | { | |||
1242 | ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT ); | |||
1243 | ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOGEN ); | |||
1244 | ConvertFontBase( GetChRoot(), rPropSet ); | |||
1245 | } | |||
1246 | ||||
1247 | bool XclExpChText::ConvertDataLabel( const ScfPropertySet& rPropSet, | |||
1248 | const XclChTypeInfo& rTypeInfo, const XclChDataPointPos& rPointPos ) | |||
1249 | { | |||
1250 | SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_DATALABEL, rPointPos.mnPointIdx, rPointPos.mnSeriesIdx ); | |||
1251 | ||||
1252 | cssc2::DataPointLabel aPointLabel; | |||
1253 | if( !rPropSet.GetProperty( aPointLabel, EXC_CHPROP_LABEL"Label" ) ) | |||
1254 | return false; | |||
1255 | ||||
1256 | // percentage only allowed in pie and donut charts | |||
1257 | bool bIsPie = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE; | |||
1258 | // bubble sizes only allowed in bubble charts | |||
1259 | bool bIsBubble = rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES; | |||
1260 | OSL_ENSURE( (GetBiff() == EXC_BIFF8) || !bIsBubble, "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8" )do { if (true && (!((GetBiff() == EXC_BIFF8) || !bIsBubble ))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "1260" ": "), "%s", "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8" ); } } while (false); | |||
1261 | ||||
1262 | // raw show flags | |||
1263 | bool bShowValue = !bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size | |||
1264 | bool bShowPercent = bIsPie && aPointLabel.ShowNumberInPercent; // percentage only in pie/donut charts | |||
1265 | bool bShowCateg = aPointLabel.ShowCategoryName; | |||
1266 | bool bShowBubble = bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size | |||
1267 | bool bShowAny = bShowValue || bShowPercent || bShowCateg || bShowBubble; | |||
1268 | ||||
1269 | // create the CHFRLABELPROPS record for extended settings in BIFF8 | |||
1270 | if( bShowAny && (GetBiff() == EXC_BIFF8) ) | |||
1271 | { | |||
1272 | mxLabelProps = new XclExpChFrLabelProps( GetChRoot() ); | |||
1273 | mxLabelProps->Convert( rPropSet, bShowCateg, bShowValue, bShowPercent, bShowBubble ); | |||
1274 | } | |||
1275 | ||||
1276 | // restrict to combinations allowed in CHTEXT | |||
1277 | if( bShowPercent ) bShowValue = false; // percent wins over value | |||
1278 | if( bShowValue ) bShowCateg = false; // value wins over category | |||
1279 | if( bShowValue || bShowCateg ) bShowBubble = false; // value or category wins over bubble size | |||
1280 | ||||
1281 | // set all flags | |||
1282 | ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT ); | |||
1283 | ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bShowValue ); | |||
1284 | ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bShowPercent ); | |||
1285 | ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bShowCateg ); | |||
1286 | ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bShowPercent && bShowCateg ); | |||
1287 | ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWBUBBLE, bShowBubble ); | |||
1288 | ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL, bShowAny && aPointLabel.ShowLegendSymbol ); | |||
1289 | ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bShowAny ); | |||
1290 | ||||
1291 | if( bShowAny ) | |||
1292 | { | |||
1293 | // font settings | |||
1294 | ConvertFontBase( GetChRoot(), rPropSet ); | |||
1295 | ConvertRotationBase( rPropSet, false ); | |||
1296 | // label placement | |||
1297 | sal_Int32 nPlacement = 0; | |||
1298 | sal_uInt16 nLabelPos = EXC_CHTEXT_POS_AUTO; | |||
1299 | if( rPropSet.GetProperty( nPlacement, EXC_CHPROP_LABELPLACEMENT"LabelPlacement" ) ) | |||
1300 | { | |||
1301 | using namespace cssc::DataLabelPlacement; | |||
1302 | if( nPlacement == rTypeInfo.mnDefaultLabelPos ) | |||
1303 | { | |||
1304 | nLabelPos = EXC_CHTEXT_POS_DEFAULT; | |||
1305 | } | |||
1306 | else switch( nPlacement ) | |||
1307 | { | |||
1308 | case AVOID_OVERLAP: nLabelPos = EXC_CHTEXT_POS_AUTO; break; | |||
1309 | case CENTER: nLabelPos = EXC_CHTEXT_POS_CENTER; break; | |||
1310 | case TOP: nLabelPos = EXC_CHTEXT_POS_ABOVE; break; | |||
1311 | case TOP_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break; | |||
1312 | case LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break; | |||
1313 | case BOTTOM_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break; | |||
1314 | case BOTTOM: nLabelPos = EXC_CHTEXT_POS_BELOW; break; | |||
1315 | case BOTTOM_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break; | |||
1316 | case RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break; | |||
1317 | case TOP_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break; | |||
1318 | case INSIDE: nLabelPos = EXC_CHTEXT_POS_INSIDE; break; | |||
1319 | case OUTSIDE: nLabelPos = EXC_CHTEXT_POS_OUTSIDE; break; | |||
1320 | case NEAR_ORIGIN: nLabelPos = EXC_CHTEXT_POS_AXIS; break; | |||
1321 | default: OSL_FAIL( "XclExpChText::ConvertDataLabel - unknown label placement type" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "1321" ": "), "%s", "XclExpChText::ConvertDataLabel - unknown label placement type" ); } } while (false); | |||
1322 | } | |||
1323 | } | |||
1324 | ::insert_value( maData.mnFlags2, nLabelPos, 0, 4 ); | |||
1325 | // source link (contains number format) | |||
1326 | mxSrcLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ); | |||
1327 | if( bShowValue || bShowPercent ) | |||
1328 | // percentage format wins over value format | |||
1329 | mxSrcLink->ConvertNumFmt( rPropSet, bShowPercent ); | |||
1330 | // object link | |||
1331 | mxObjLink = new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ); | |||
1332 | } | |||
1333 | ||||
1334 | /* Return true to indicate valid label settings: | |||
1335 | - for existing labels at entire series | |||
1336 | - for any settings at single data point (to be able to delete a point label) */ | |||
1337 | return bShowAny || (rPointPos.mnPointIdx != EXC_CHDATAFORMAT_ALLPOINTS); | |||
1338 | } | |||
1339 | ||||
1340 | void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet& rPropSet, const XclChDataPointPos& rPointPos ) | |||
1341 | { | |||
1342 | // required flags | |||
1343 | ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT ); | |||
1344 | if( GetBiff() == EXC_BIFF8 ) | |||
1345 | ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ); // must set this to make equation visible in Excel | |||
1346 | // frame formatting | |||
1347 | mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_TEXT ); | |||
1348 | // font settings | |||
1349 | maData.mnHAlign = EXC_CHTEXT_ALIGN_TOPLEFT; | |||
1350 | maData.mnVAlign = EXC_CHTEXT_ALIGN_TOPLEFT; | |||
1351 | ConvertFontBase( GetChRoot(), rPropSet ); | |||
1352 | // source link (contains number format) | |||
1353 | mxSrcLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ); | |||
1354 | mxSrcLink->ConvertNumFmt( rPropSet, false ); | |||
1355 | // object link | |||
1356 | mxObjLink = new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ); | |||
1357 | } | |||
1358 | ||||
1359 | sal_uInt16 XclExpChText::GetAttLabelFlags() const | |||
1360 | { | |||
1361 | sal_uInt16 nFlags = 0; | |||
1362 | ::set_flag( nFlags, EXC_CHATTLABEL_SHOWVALUE, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE ) ); | |||
1363 | ::set_flag( nFlags, EXC_CHATTLABEL_SHOWPERCENT, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT ) ); | |||
1364 | ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEGPERC, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC ) ); | |||
1365 | ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEG, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ) ); | |||
1366 | return nFlags; | |||
1367 | } | |||
1368 | ||||
1369 | void XclExpChText::WriteSubRecords( XclExpStream& rStrm ) | |||
1370 | { | |||
1371 | // CHFRAMEPOS record | |||
1372 | lclSaveRecord( rStrm, mxFramePos ); | |||
1373 | // CHFONT record | |||
1374 | lclSaveRecord( rStrm, mxFont ); | |||
1375 | // CHSOURCELINK group | |||
1376 | lclSaveRecord( rStrm, mxSrcLink ); | |||
1377 | // CHFRAME group | |||
1378 | lclSaveRecord( rStrm, mxFrame ); | |||
1379 | // CHOBJECTLINK record | |||
1380 | lclSaveRecord( rStrm, mxObjLink ); | |||
1381 | // CHFRLABELPROPS record | |||
1382 | lclSaveRecord( rStrm, mxLabelProps ); | |||
1383 | } | |||
1384 | ||||
1385 | void XclExpChText::WriteBody( XclExpStream& rStrm ) | |||
1386 | { | |||
1387 | rStrm << maData.mnHAlign | |||
1388 | << maData.mnVAlign | |||
1389 | << maData.mnBackMode | |||
1390 | << maData.maTextColor | |||
1391 | << maData.maRect | |||
1392 | << maData.mnFlags; | |||
1393 | ||||
1394 | if( GetBiff() == EXC_BIFF8 ) | |||
1395 | { | |||
1396 | rStrm << GetPalette().GetColorIndex( mnTextColorId ) | |||
1397 | << maData.mnFlags2 | |||
1398 | << maData.mnRotation; | |||
1399 | } | |||
1400 | } | |||
1401 | ||||
1402 | namespace { | |||
1403 | ||||
1404 | /** Creates and returns an Excel text object from the passed title. */ | |||
1405 | XclExpChTextRef lclCreateTitle( const XclExpChRoot& rRoot, Reference< XTitled > const & xTitled, sal_uInt16 nTarget, | |||
1406 | const OUString* pSubTitle = nullptr ) | |||
1407 | { | |||
1408 | Reference< XTitle > xTitle; | |||
1409 | if( xTitled.is() ) | |||
1410 | xTitle = xTitled->getTitleObject(); | |||
1411 | ||||
1412 | XclExpChTextRef xText = new XclExpChText( rRoot ); | |||
1413 | xText->ConvertTitle( xTitle, nTarget, pSubTitle ); | |||
1414 | /* Do not delete the CHTEXT group for the main title. A missing CHTEXT | |||
1415 | will be interpreted as auto-generated title showing the series title in | |||
1416 | charts that contain exactly one data series. */ | |||
1417 | if( (nTarget != EXC_CHOBJLINK_TITLE) && !xText->HasString() ) | |||
1418 | xText.clear(); | |||
1419 | ||||
1420 | return xText; | |||
1421 | } | |||
1422 | ||||
1423 | } | |||
1424 | ||||
1425 | // Data series ================================================================ | |||
1426 | ||||
1427 | XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot& rRoot ) : | |||
1428 | XclExpRecord( EXC_ID_CHMARKERFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 20 : 12 ), | |||
1429 | mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ), | |||
1430 | mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ) | |||
1431 | { | |||
1432 | } | |||
1433 | ||||
1434 | void XclExpChMarkerFormat::Convert( const XclExpChRoot& rRoot, | |||
1435 | const ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx ) | |||
1436 | { | |||
1437 | XclChPropSetHelper::ReadMarkerProperties( maData, rPropSet, nFormatIdx ); | |||
1438 | /* Set marker line/fill color to series line color. | |||
1439 | TODO: remove this if OOChart supports own colors in markers. */ | |||
1440 | Color aLineColor; | |||
1441 | if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR"Color" ) ) | |||
1442 | maData.maLineColor = maData.maFillColor = aLineColor; | |||
1443 | // register colors in palette | |||
1444 | RegisterColors( rRoot ); | |||
1445 | } | |||
1446 | ||||
1447 | void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot& rRoot, | |||
1448 | const ScfPropertySet& rPropSet, bool bCloseSymbol ) | |||
1449 | { | |||
1450 | // clear the automatic flag | |||
1451 | ::set_flag( maData.mnFlags, EXC_CHMARKERFORMAT_AUTO, false ); | |||
1452 | // symbol type and color | |||
1453 | if( bCloseSymbol ) | |||
1454 | { | |||
1455 | // set symbol type for the 'close' data series | |||
1456 | maData.mnMarkerType = EXC_CHMARKERFORMAT_DOWJ; | |||
1457 | maData.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE; | |||
1458 | // set symbol line/fill color to series line color | |||
1459 | Color aLineColor; | |||
1460 | if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR"Color" ) ) | |||
1461 | { | |||
1462 | maData.maLineColor = maData.maFillColor = aLineColor; | |||
1463 | RegisterColors( rRoot ); | |||
1464 | } | |||
1465 | } | |||
1466 | else | |||
1467 | { | |||
1468 | // set invisible symbol | |||
1469 | maData.mnMarkerType = EXC_CHMARKERFORMAT_NOSYMBOL; | |||
1470 | } | |||
1471 | } | |||
1472 | ||||
1473 | void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot& rRoot ) | |||
1474 | { | |||
1475 | if( HasMarker() ) | |||
1476 | { | |||
1477 | if( HasLineColor() ) | |||
1478 | mnLineColorId = rRoot.GetPalette().InsertColor( maData.maLineColor, EXC_COLOR_CHARTLINE ); | |||
1479 | if( HasFillColor() ) | |||
1480 | mnFillColorId = rRoot.GetPalette().InsertColor( maData.maFillColor, EXC_COLOR_CHARTAREA ); | |||
1481 | } | |||
1482 | } | |||
1483 | ||||
1484 | void XclExpChMarkerFormat::WriteBody( XclExpStream& rStrm ) | |||
1485 | { | |||
1486 | rStrm << maData.maLineColor << maData.maFillColor << maData.mnMarkerType << maData.mnFlags; | |||
1487 | if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 ) | |||
1488 | { | |||
1489 | const XclExpPalette& rPal = rStrm.GetRoot().GetPalette(); | |||
1490 | rStrm << rPal.GetColorIndex( mnLineColorId ) << rPal.GetColorIndex( mnFillColorId ) << maData.mnMarkerSize; | |||
1491 | } | |||
1492 | } | |||
1493 | ||||
1494 | XclExpChPieFormat::XclExpChPieFormat() : | |||
1495 | XclExpUInt16Record( EXC_ID_CHPIEFORMAT, 0 ) | |||
1496 | { | |||
1497 | } | |||
1498 | ||||
1499 | void XclExpChPieFormat::Convert( const ScfPropertySet& rPropSet ) | |||
1500 | { | |||
1501 | double fApiDist(0.0); | |||
1502 | if( rPropSet.GetProperty( fApiDist, EXC_CHPROP_OFFSET"Offset" ) ) | |||
1503 | SetValue( limit_cast< sal_uInt16 >( fApiDist * 100.0, 0, 100 ) ); | |||
1504 | } | |||
1505 | ||||
1506 | XclExpCh3dDataFormat::XclExpCh3dDataFormat() : | |||
1507 | XclExpRecord( EXC_ID_CH3DDATAFORMAT, 2 ) | |||
1508 | { | |||
1509 | } | |||
1510 | ||||
1511 | void XclExpCh3dDataFormat::Convert( const ScfPropertySet& rPropSet ) | |||
1512 | { | |||
1513 | sal_Int32 nApiType(0); | |||
1514 | if( !rPropSet.GetProperty( nApiType, EXC_CHPROP_GEOMETRY3D"Geometry3D" ) ) | |||
1515 | return; | |||
1516 | ||||
1517 | using namespace cssc2::DataPointGeometry3D; | |||
1518 | switch( nApiType ) | |||
1519 | { | |||
1520 | case CUBOID: | |||
1521 | maData.mnBase = EXC_CH3DDATAFORMAT_RECT; | |||
1522 | maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT; | |||
1523 | break; | |||
1524 | case PYRAMID: | |||
1525 | maData.mnBase = EXC_CH3DDATAFORMAT_RECT; | |||
1526 | maData.mnTop = EXC_CH3DDATAFORMAT_SHARP; | |||
1527 | break; | |||
1528 | case CYLINDER: | |||
1529 | maData.mnBase = EXC_CH3DDATAFORMAT_CIRC; | |||
1530 | maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT; | |||
1531 | break; | |||
1532 | case CONE: | |||
1533 | maData.mnBase = EXC_CH3DDATAFORMAT_CIRC; | |||
1534 | maData.mnTop = EXC_CH3DDATAFORMAT_SHARP; | |||
1535 | break; | |||
1536 | default: | |||
1537 | OSL_FAIL( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "1537" ": "), "%s", "XclExpCh3dDataFormat::Convert - unknown 3D bar format" ); } } while (false); | |||
1538 | } | |||
1539 | } | |||
1540 | ||||
1541 | void XclExpCh3dDataFormat::WriteBody( XclExpStream& rStrm ) | |||
1542 | { | |||
1543 | rStrm << maData.mnBase << maData.mnTop; | |||
1544 | } | |||
1545 | ||||
1546 | XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags ) : | |||
1547 | XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL, nFlags ) | |||
1548 | { | |||
1549 | } | |||
1550 | ||||
1551 | XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot& rRoot, | |||
1552 | const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx ) : | |||
1553 | XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DATAFORMAT, EXC_ID_CHDATAFORMAT, 8 ) | |||
1554 | { | |||
1555 | maData.maPointPos = rPointPos; | |||
1556 | maData.mnFormatIdx = nFormatIdx; | |||
1557 | } | |||
1558 | ||||
1559 | void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo ) | |||
1560 | { | |||
1561 | // line and area formatting | |||
1562 | ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType() ); | |||
1563 | ||||
1564 | // data point symbols | |||
1565 | bool bIsFrame = rTypeInfo.IsSeriesFrameFormat(); | |||
1566 | if( !bIsFrame ) | |||
1567 | { | |||
1568 | mxMarkerFmt = new XclExpChMarkerFormat( GetChRoot() ); | |||
1569 | mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx ); | |||
1570 | } | |||
1571 | ||||
1572 | // pie segments | |||
1573 | if( rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE ) | |||
1574 | { | |||
1575 | mxPieFmt = new XclExpChPieFormat(); | |||
1576 | mxPieFmt->Convert( rPropSet ); | |||
1577 | } | |||
1578 | ||||
1579 | // 3D bars (only allowed for entire series in BIFF8) | |||
1580 | if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8) && rTypeInfo.mb3dChart && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) ) | |||
1581 | { | |||
1582 | mx3dDataFmt = new XclExpCh3dDataFormat(); | |||
1583 | mx3dDataFmt->Convert( rPropSet ); | |||
1584 | } | |||
1585 | ||||
1586 | // spline | |||
1587 | if( IsSeriesFormat() && rTypeInfo.mbSpline && !bIsFrame ) | |||
1588 | mxSeriesFmt = new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT, EXC_CHSERIESFORMAT_SMOOTHED ); | |||
1589 | ||||
1590 | // data point labels | |||
1591 | XclExpChTextRef xLabel = new XclExpChText( GetChRoot() ); | |||
1592 | if( xLabel->ConvertDataLabel( rPropSet, rTypeInfo, maData.maPointPos ) ) | |||
1593 | { | |||
1594 | // CHTEXT groups for data labels are stored in global CHCHART group | |||
1595 | GetChartData().SetDataLabel( xLabel ); | |||
1596 | mxAttLabel = new XclExpChAttachedLabel( xLabel->GetAttLabelFlags() ); | |||
1597 | } | |||
1598 | } | |||
1599 | ||||
1600 | void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet& rPropSet, bool bCloseSymbol ) | |||
1601 | { | |||
1602 | // set line format to invisible | |||
1603 | SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, false ); | |||
1604 | // set symbols to invisible or to 'close' series symbol | |||
1605 | mxMarkerFmt = new XclExpChMarkerFormat( GetChRoot() ); | |||
1606 | mxMarkerFmt->ConvertStockSymbol( GetChRoot(), rPropSet, bCloseSymbol ); | |||
1607 | } | |||
1608 | ||||
1609 | void XclExpChDataFormat::ConvertLine( const ScfPropertySet& rPropSet, XclChObjectType eObjType ) | |||
1610 | { | |||
1611 | ConvertFrameBase( GetChRoot(), rPropSet, eObjType ); | |||
1612 | } | |||
1613 | ||||
1614 | void XclExpChDataFormat::WriteSubRecords( XclExpStream& rStrm ) | |||
1615 | { | |||
1616 | lclSaveRecord( rStrm, mx3dDataFmt ); | |||
1617 | WriteFrameRecords( rStrm ); | |||
1618 | lclSaveRecord( rStrm, mxPieFmt ); | |||
1619 | lclSaveRecord( rStrm, mxMarkerFmt ); | |||
1620 | lclSaveRecord( rStrm, mxSeriesFmt ); | |||
1621 | lclSaveRecord( rStrm, mxAttLabel ); | |||
1622 | } | |||
1623 | ||||
1624 | void XclExpChDataFormat::WriteBody( XclExpStream& rStrm ) | |||
1625 | { | |||
1626 | rStrm << maData.maPointPos.mnPointIdx | |||
1627 | << maData.maPointPos.mnSeriesIdx | |||
1628 | << maData.mnFormatIdx | |||
1629 | << maData.mnFlags; | |||
1630 | } | |||
1631 | ||||
1632 | XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot& rRoot ) : | |||
1633 | XclExpRecord( EXC_ID_CHSERTRENDLINE, 28 ), | |||
1634 | XclExpChRoot( rRoot ) | |||
1635 | { | |||
1636 | } | |||
1637 | ||||
1638 | bool XclExpChSerTrendLine::Convert( Reference< XRegressionCurve > const & xRegCurve, sal_uInt16 nSeriesIdx ) | |||
1639 | { | |||
1640 | if( !xRegCurve.is() ) | |||
1641 | return false; | |||
1642 | ||||
1643 | // trend line type | |||
1644 | ScfPropertySet aCurveProp( xRegCurve ); | |||
1645 | ||||
1646 | OUString aService = aCurveProp.GetServiceName(); | |||
1647 | if( aService == "com.sun.star.chart2.LinearRegressionCurve" ) | |||
1648 | { | |||
1649 | maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL; | |||
1650 | maData.mnOrder = 1; | |||
1651 | } | |||
1652 | else if( aService == "com.sun.star.chart2.ExponentialRegressionCurve" ) | |||
1653 | { | |||
1654 | maData.mnLineType = EXC_CHSERTREND_EXPONENTIAL; | |||
1655 | } | |||
1656 | else if( aService == "com.sun.star.chart2.LogarithmicRegressionCurve" ) | |||
1657 | { | |||
1658 | maData.mnLineType = EXC_CHSERTREND_LOGARITHMIC; | |||
1659 | } | |||
1660 | else if( aService == "com.sun.star.chart2.PotentialRegressionCurve" ) | |||
1661 | { | |||
1662 | maData.mnLineType = EXC_CHSERTREND_POWER; | |||
1663 | } | |||
1664 | else if( aService == "com.sun.star.chart2.PolynomialRegressionCurve" ) | |||
1665 | { | |||
1666 | maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL; | |||
1667 | sal_Int32 aDegree; | |||
1668 | aCurveProp.GetProperty(aDegree, EXC_CHPROP_POLYNOMIAL_DEGREE"PolynomialDegree"); | |||
1669 | maData.mnOrder = static_cast<sal_uInt8> (aDegree); | |||
| ||||
1670 | } | |||
1671 | else if( aService == "com.sun.star.chart2.MovingAverageRegressionCurve" ) | |||
1672 | { | |||
1673 | maData.mnLineType = EXC_CHSERTREND_MOVING_AVG; | |||
1674 | sal_Int32 aPeriod; | |||
1675 | aCurveProp.GetProperty(aPeriod, EXC_CHPROP_MOVING_AVERAGE_PERIOD"MovingAveragePeriod"); | |||
1676 | maData.mnOrder = static_cast<sal_uInt8> (aPeriod); | |||
1677 | } | |||
1678 | else | |||
1679 | { | |||
1680 | return false; | |||
1681 | } | |||
1682 | ||||
1683 | aCurveProp.GetProperty(maData.mfForecastFor, EXC_CHPROP_EXTRAPOLATE_FORWARD"ExtrapolateForward"); | |||
1684 | aCurveProp.GetProperty(maData.mfForecastBack, EXC_CHPROP_EXTRAPOLATE_BACKWARD"ExtrapolateBackward"); | |||
1685 | bool bIsForceIntercept = false; | |||
1686 | aCurveProp.GetProperty(bIsForceIntercept, EXC_CHPROP_FORCE_INTERCEPT"ForceIntercept"); | |||
1687 | if (bIsForceIntercept) | |||
1688 | aCurveProp.GetProperty(maData.mfIntercept, EXC_CHPROP_INTERCEPT_VALUE"InterceptValue"); | |||
1689 | ||||
1690 | // line formatting | |||
1691 | XclChDataPointPos aPointPos( nSeriesIdx ); | |||
1692 | mxDataFmt = new XclExpChDataFormat( GetChRoot(), aPointPos, 0 ); | |||
1693 | mxDataFmt->ConvertLine( aCurveProp, EXC_CHOBJTYPE_TRENDLINE ); | |||
1694 | ||||
1695 | // #i83100# show equation and correlation coefficient | |||
1696 | ScfPropertySet aEquationProp( xRegCurve->getEquationProperties() ); | |||
1697 | maData.mnShowEquation = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWEQUATION"ShowEquation" ) ? 1 : 0; | |||
1698 | maData.mnShowRSquared = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION"ShowCorrelationCoefficient" ) ? 1 : 0; | |||
1699 | ||||
1700 | // #i83100# formatting of the equation text box | |||
1701 | if( (maData.mnShowEquation != 0) || (maData.mnShowRSquared != 0) ) | |||
1702 | { | |||
1703 | mxLabel = new XclExpChText( GetChRoot() ); | |||
1704 | mxLabel->ConvertTrendLineEquation( aEquationProp, aPointPos ); | |||
1705 | } | |||
1706 | ||||
1707 | // missing features | |||
1708 | // #i5085# manual trend line size | |||
1709 | // #i34093# manual crossing point | |||
1710 | return true; | |||
1711 | } | |||
1712 | ||||
1713 | void XclExpChSerTrendLine::WriteBody( XclExpStream& rStrm ) | |||
1714 | { | |||
1715 | rStrm << maData.mnLineType | |||
1716 | << maData.mnOrder | |||
1717 | << maData.mfIntercept | |||
1718 | << maData.mnShowEquation | |||
1719 | << maData.mnShowRSquared | |||
1720 | << maData.mfForecastFor | |||
1721 | << maData.mfForecastBack; | |||
1722 | } | |||
1723 | ||||
1724 | XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot& rRoot, sal_uInt8 nBarType ) : | |||
1725 | XclExpRecord( EXC_ID_CHSERERRORBAR, 14 ), | |||
1726 | XclExpChRoot( rRoot ) | |||
1727 | { | |||
1728 | maData.mnBarType = nBarType; | |||
1729 | } | |||
1730 | ||||
1731 | bool XclExpChSerErrorBar::Convert( XclExpChSourceLink& rValueLink, sal_uInt16& rnValueCount, const ScfPropertySet& rPropSet ) | |||
1732 | { | |||
1733 | sal_Int32 nBarStyle = 0; | |||
1734 | bool bOk = rPropSet.GetProperty( nBarStyle, EXC_CHPROP_ERRORBARSTYLE"ErrorBarStyle" ); | |||
1735 | if( bOk ) | |||
1736 | { | |||
1737 | switch( nBarStyle ) | |||
1738 | { | |||
1739 | case cssc::ErrorBarStyle::ABSOLUTE: | |||
1740 | maData.mnSourceType = EXC_CHSERERR_FIXED; | |||
1741 | rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR"PositiveError" ); | |||
1742 | break; | |||
1743 | case cssc::ErrorBarStyle::RELATIVE: | |||
1744 | maData.mnSourceType = EXC_CHSERERR_PERCENT; | |||
1745 | rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR"PositiveError" ); | |||
1746 | break; | |||
1747 | case cssc::ErrorBarStyle::STANDARD_DEVIATION: | |||
1748 | maData.mnSourceType = EXC_CHSERERR_STDDEV; | |||
1749 | rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_WEIGHT"Weight" ); | |||
1750 | break; | |||
1751 | case cssc::ErrorBarStyle::STANDARD_ERROR: | |||
1752 | maData.mnSourceType = EXC_CHSERERR_STDERR; | |||
1753 | break; | |||
1754 | case cssc::ErrorBarStyle::FROM_DATA: | |||
1755 | { | |||
1756 | bOk = false; | |||
1757 | maData.mnSourceType = EXC_CHSERERR_CUSTOM; | |||
1758 | Reference< XDataSource > xDataSource( rPropSet.GetApiPropertySet(), UNO_QUERY ); | |||
1759 | if( xDataSource.is() ) | |||
1760 | { | |||
1761 | // find first sequence with current role | |||
1762 | OUString aRole = XclChartHelper::GetErrorBarValuesRole( maData.mnBarType ); | |||
1763 | Reference< XDataSequence > xValueSeq; | |||
1764 | ||||
1765 | const Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences(); | |||
1766 | for( const Reference< XLabeledDataSequence >& rLabeledSeq : aLabeledSeqVec ) | |||
1767 | { | |||
1768 | Reference< XDataSequence > xTmpValueSeq = rLabeledSeq->getValues(); | |||
1769 | ScfPropertySet aValueProp( xTmpValueSeq ); | |||
1770 | OUString aCurrRole; | |||
1771 | if( aValueProp.GetProperty( aCurrRole, EXC_CHPROP_ROLE"Role" ) && (aCurrRole == aRole) ) | |||
1772 | { | |||
1773 | xValueSeq = xTmpValueSeq; | |||
1774 | break; | |||
1775 | } | |||
1776 | } | |||
1777 | if( xValueSeq.is() ) | |||
1778 | { | |||
1779 | // #i86465# pass value count back to series | |||
1780 | rnValueCount = maData.mnValueCount = rValueLink.ConvertDataSequence( xValueSeq, true ); | |||
1781 | bOk = maData.mnValueCount > 0; | |||
1782 | } | |||
1783 | } | |||
1784 | } | |||
1785 | break; | |||
1786 | default: | |||
1787 | bOk = false; | |||
1788 | } | |||
1789 | } | |||
1790 | return bOk; | |||
1791 | } | |||
1792 | ||||
1793 | void XclExpChSerErrorBar::WriteBody( XclExpStream& rStrm ) | |||
1794 | { | |||
1795 | rStrm << maData.mnBarType | |||
1796 | << maData.mnSourceType | |||
1797 | << maData.mnLineEnd | |||
1798 | << sal_uInt8( 1 ) // must be 1 to make line visible | |||
1799 | << maData.mfValue | |||
1800 | << maData.mnValueCount; | |||
1801 | } | |||
1802 | ||||
1803 | namespace { | |||
1804 | ||||
1805 | /** Returns the property set of the specified data point. */ | |||
1806 | ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > const & xDataSeries, sal_Int32 nPointIdx ) | |||
1807 | { | |||
1808 | ScfPropertySet aPropSet; | |||
1809 | try | |||
1810 | { | |||
1811 | aPropSet.Set( xDataSeries->getDataPointByIndex( nPointIdx ) ); | |||
1812 | } | |||
1813 | catch( Exception& ) | |||
1814 | { | |||
1815 | OSL_FAIL( "lclGetPointPropSet - no data point property set" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "1815" ": "), "%s", "lclGetPointPropSet - no data point property set" ); } } while (false); | |||
1816 | } | |||
1817 | return aPropSet; | |||
1818 | } | |||
1819 | ||||
1820 | } // namespace | |||
1821 | ||||
1822 | XclExpChSeries::XclExpChSeries( const XclExpChRoot& rRoot, sal_uInt16 nSeriesIdx ) : | |||
1823 | XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_SERIES, EXC_ID_CHSERIES, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 8 ), | |||
1824 | mnGroupIdx( EXC_CHSERGROUP_NONE ), | |||
1825 | mnSeriesIdx( nSeriesIdx ), | |||
1826 | mnParentIdx( EXC_CHSERIES_INVALID ) | |||
1827 | { | |||
1828 | // CHSOURCELINK records are always required, even if unused | |||
1829 | mxTitleLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ); | |||
1830 | mxValueLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES ); | |||
1831 | mxCategLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY ); | |||
1832 | if( GetBiff() == EXC_BIFF8 ) | |||
1833 | mxBubbleLink = new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES ); | |||
1834 | } | |||
1835 | ||||
1836 | bool XclExpChSeries::ConvertDataSeries( | |||
1837 | Reference< XDiagram > const & xDiagram, Reference< XDataSeries > const & xDataSeries, | |||
1838 | const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx ) | |||
1839 | { | |||
1840 | bool bOk = false; | |||
1841 | Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY ); | |||
1842 | if( xDataSource.is() ) | |||
1843 | { | |||
1844 | Reference< XDataSequence > xYValueSeq, xTitleSeq, xXValueSeq, xBubbleSeq; | |||
1845 | ||||
1846 | // find first sequence with role 'values-y' | |||
1847 | const Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences(); | |||
1848 | for( const Reference< XLabeledDataSequence >& rLabeledSeq : aLabeledSeqVec ) | |||
1849 | { | |||
1850 | Reference< XDataSequence > xTmpValueSeq = rLabeledSeq->getValues(); | |||
1851 | ScfPropertySet aValueProp( xTmpValueSeq ); | |||
1852 | OUString aRole; | |||
1853 | if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE"Role" ) ) | |||
1854 | { | |||
1855 | if( !xYValueSeq.is() && (aRole == EXC_CHPROP_ROLE_YVALUES"values-y") ) | |||
1856 | { | |||
1857 | xYValueSeq = xTmpValueSeq; | |||
1858 | if( !xTitleSeq.is() ) | |||
1859 | xTitleSeq = rLabeledSeq->getLabel(); // ignore role of label sequence | |||
1860 | } | |||
1861 | else if( !xXValueSeq.is() && !rTypeInfo.mbCategoryAxis && (aRole == EXC_CHPROP_ROLE_XVALUES"values-x") ) | |||
1862 | { | |||
1863 | xXValueSeq = xTmpValueSeq; | |||
1864 | } | |||
1865 | else if( !xBubbleSeq.is() && (rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES) && (aRole == EXC_CHPROP_ROLE_SIZEVALUES"values-size") ) | |||
1866 | { | |||
1867 | xBubbleSeq = xTmpValueSeq; | |||
1868 | xTitleSeq = rLabeledSeq->getLabel(); // ignore role of label sequence | |||
1869 | } | |||
1870 | } | |||
1871 | } | |||
1872 | ||||
1873 | bOk = xYValueSeq.is(); | |||
1874 | if( bOk ) | |||
1875 | { | |||
1876 | // chart type group index | |||
1877 | mnGroupIdx = nGroupIdx; | |||
1878 | ||||
1879 | // convert source links | |||
1880 | maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true ); | |||
1881 | mxTitleLink->ConvertDataSequence( xTitleSeq, true ); | |||
1882 | ||||
1883 | // X values of XY charts | |||
1884 | maData.mnCategCount = mxCategLink->ConvertDataSequence( xXValueSeq, false, maData.mnValueCount ); | |||
1885 | ||||
1886 | // size values of bubble charts | |||
1887 | if( mxBubbleLink ) | |||
1888 | mxBubbleLink->ConvertDataSequence( xBubbleSeq, false, maData.mnValueCount ); | |||
1889 | ||||
1890 | // series formatting | |||
1891 | XclChDataPointPos aPointPos( mnSeriesIdx ); | |||
1892 | ScfPropertySet aSeriesProp( xDataSeries ); | |||
1893 | mxSeriesFmt = new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ); | |||
1894 | mxSeriesFmt->ConvertDataSeries( aSeriesProp, rTypeInfo ); | |||
1895 | ||||
1896 | // trend lines | |||
1897 | CreateTrendLines( xDataSeries ); | |||
1898 | ||||
1899 | // error bars | |||
1900 | CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARX"ErrorBarX", EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS ); | |||
1901 | CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARY"ErrorBarY", EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS ); | |||
1902 | ||||
1903 | if( maData.mnValueCount > 0 ) | |||
1904 | { | |||
1905 | const sal_Int32 nMaxPointCount = maData.mnValueCount; | |||
1906 | ||||
1907 | /* #i91063# Create missing fill properties in pie/doughnut charts. | |||
1908 | If freshly created (never saved to ODF), these charts show | |||
1909 | varying point colors but do not return these points via API. */ | |||
1910 | if( xDiagram.is() && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE) ) | |||
1911 | { | |||
1912 | Reference< XColorScheme > xColorScheme = xDiagram->getDefaultColorScheme(); | |||
1913 | if( xColorScheme.is() ) | |||
1914 | { | |||
1915 | const OUString aFillStyleName = "FillStyle"; | |||
1916 | const OUString aColorName = "Color"; | |||
1917 | namespace cssd = ::com::sun::star::drawing; | |||
1918 | for( sal_Int32 nPointIdx = 0; nPointIdx < nMaxPointCount; ++nPointIdx ) | |||
1919 | { | |||
1920 | aPointPos.mnPointIdx = static_cast< sal_uInt16 >( nPointIdx ); | |||
1921 | ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx ); | |||
1922 | // test that the point fill style is solid, but no color is set | |||
1923 | cssd::FillStyle eFillStyle = cssd::FillStyle_NONE; | |||
1924 | if( aPointProp.GetProperty( eFillStyle, aFillStyleName ) && | |||
1925 | (eFillStyle == cssd::FillStyle_SOLID) && | |||
1926 | !aPointProp.HasProperty( aColorName ) ) | |||
1927 | { | |||
1928 | aPointProp.SetProperty( aColorName, xColorScheme->getColorByIndex( nPointIdx ) ); | |||
1929 | } | |||
1930 | } | |||
1931 | } | |||
1932 | } | |||
1933 | ||||
1934 | // data point formatting | |||
1935 | Sequence< sal_Int32 > aPointIndexes; | |||
1936 | if( aSeriesProp.GetProperty( aPointIndexes, EXC_CHPROP_ATTRIBDATAPOINTS"AttributedDataPoints" ) && aPointIndexes.hasElements() ) | |||
1937 | { | |||
1938 | for( const sal_Int32 nPointIndex : aPointIndexes ) | |||
1939 | { | |||
1940 | if (nPointIndex >= nMaxPointCount) | |||
1941 | break; | |||
1942 | aPointPos.mnPointIdx = static_cast< sal_uInt16 >( nPointIndex ); | |||
1943 | ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIndex ); | |||
1944 | XclExpChDataFormatRef xPointFmt = new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ); | |||
1945 | xPointFmt->ConvertDataSeries( aPointProp, rTypeInfo ); | |||
1946 | maPointFmts.AppendRecord( xPointFmt ); | |||
1947 | } | |||
1948 | } | |||
1949 | } | |||
1950 | } | |||
1951 | } | |||
1952 | return bOk; | |||
1953 | } | |||
1954 | ||||
1955 | bool XclExpChSeries::ConvertStockSeries( css::uno::Reference< css::chart2::XDataSeries > const & xDataSeries, | |||
1956 | const OUString& rValueRole, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx, bool bCloseSymbol ) | |||
1957 | { | |||
1958 | bool bOk = false; | |||
1959 | Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY ); | |||
1960 | if( xDataSource.is() ) | |||
1961 | { | |||
1962 | Reference< XDataSequence > xYValueSeq, xTitleSeq; | |||
1963 | ||||
1964 | // find first sequence with passed role | |||
1965 | const Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences(); | |||
1966 | for( const Reference< XLabeledDataSequence >& rLabeledSeq : aLabeledSeqVec ) | |||
1967 | { | |||
1968 | Reference< XDataSequence > xTmpValueSeq = rLabeledSeq->getValues(); | |||
1969 | ScfPropertySet aValueProp( xTmpValueSeq ); | |||
1970 | OUString aRole; | |||
1971 | if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE"Role" ) && (aRole == rValueRole) ) | |||
1972 | { | |||
1973 | xYValueSeq = xTmpValueSeq; | |||
1974 | xTitleSeq = rLabeledSeq->getLabel(); // ignore role of label sequence | |||
1975 | break; | |||
1976 | } | |||
1977 | } | |||
1978 | ||||
1979 | bOk = xYValueSeq.is(); | |||
1980 | if( bOk ) | |||
1981 | { | |||
1982 | // chart type group index | |||
1983 | mnGroupIdx = nGroupIdx; | |||
1984 | // convert source links | |||
1985 | maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true ); | |||
1986 | mxTitleLink->ConvertDataSequence( xTitleSeq, true ); | |||
1987 | // series formatting | |||
1988 | ScfPropertySet aSeriesProp( xDataSeries ); | |||
1989 | mxSeriesFmt = new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), nFormatIdx ); | |||
1990 | mxSeriesFmt->ConvertStockSeries( aSeriesProp, bCloseSymbol ); | |||
1991 | } | |||
1992 | } | |||
1993 | return bOk; | |||
1994 | } | |||
1995 | ||||
1996 | bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries& rParent, Reference< XRegressionCurve > const & xRegCurve ) | |||
1997 | { | |||
1998 | InitFromParent( rParent ); | |||
1999 | ||||
2000 | mxTrendLine = new XclExpChSerTrendLine( GetChRoot() ); | |||
2001 | bool bOk = mxTrendLine->Convert( xRegCurve, mnSeriesIdx ); | |||
2002 | if( bOk ) | |||
2003 | { | |||
2004 | OUString aName; | |||
2005 | ScfPropertySet aProperties( xRegCurve ); | |||
2006 | aProperties.GetProperty(aName, EXC_CHPROP_CURVENAME"CurveName"); | |||
2007 | mxTitleLink->ConvertString(aName); | |||
2008 | ||||
2009 | mxSeriesFmt = mxTrendLine->GetDataFormat(); | |||
2010 | GetChartData().SetDataLabel( mxTrendLine->GetDataLabel() ); | |||
2011 | } | |||
2012 | return bOk; | |||
2013 | } | |||
2014 | ||||
2015 | bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries& rParent, const ScfPropertySet& rPropSet, sal_uInt8 nBarId ) | |||
2016 | { | |||
2017 | InitFromParent( rParent ); | |||
2018 | // error bar settings | |||
2019 | mxErrorBar = new XclExpChSerErrorBar( GetChRoot(), nBarId ); | |||
2020 | bool bOk = mxErrorBar->Convert( *mxValueLink, maData.mnValueCount, rPropSet ); | |||
2021 | if( bOk ) | |||
2022 | { | |||
2023 | // error bar formatting | |||
2024 | mxSeriesFmt = new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), 0 ); | |||
2025 | mxSeriesFmt->ConvertLine( rPropSet, EXC_CHOBJTYPE_ERRORBAR ); | |||
2026 | } | |||
2027 | return bOk; | |||
2028 | } | |||
2029 | ||||
2030 | void XclExpChSeries::ConvertCategSequence( Reference< XLabeledDataSequence > const & xCategSeq ) | |||
2031 | { | |||
2032 | if( xCategSeq.is() ) | |||
2033 | maData.mnCategCount = mxCategLink->ConvertDataSequence( xCategSeq->getValues(), false ); | |||
2034 | } | |||
2035 | ||||
2036 | void XclExpChSeries::WriteSubRecords( XclExpStream& rStrm ) | |||
2037 | { | |||
2038 | lclSaveRecord( rStrm, mxTitleLink ); | |||
2039 | lclSaveRecord( rStrm, mxValueLink ); | |||
2040 | lclSaveRecord( rStrm, mxCategLink ); | |||
2041 | lclSaveRecord( rStrm, mxBubbleLink ); | |||
2042 | lclSaveRecord( rStrm, mxSeriesFmt ); | |||
2043 | maPointFmts.Save( rStrm ); | |||
2044 | if( mnGroupIdx != EXC_CHSERGROUP_NONE ) | |||
2045 | XclExpUInt16Record( EXC_ID_CHSERGROUP, mnGroupIdx ).Save( rStrm ); | |||
2046 | if( mnParentIdx != EXC_CHSERIES_INVALID ) | |||
2047 | XclExpUInt16Record( EXC_ID_CHSERPARENT, mnParentIdx ).Save( rStrm ); | |||
2048 | lclSaveRecord( rStrm, mxTrendLine ); | |||
2049 | lclSaveRecord( rStrm, mxErrorBar ); | |||
2050 | } | |||
2051 | ||||
2052 | void XclExpChSeries::InitFromParent( const XclExpChSeries& rParent ) | |||
2053 | { | |||
2054 | // index to parent series is stored 1-based | |||
2055 | mnParentIdx = rParent.mnSeriesIdx + 1; | |||
2056 | /* #i86465# MSO2007 SP1 expects correct point counts in child series | |||
2057 | (there was no problem in Excel2003 or Excel2007 without SP1...) */ | |||
2058 | maData.mnCategCount = rParent.maData.mnCategCount; | |||
2059 | maData.mnValueCount = rParent.maData.mnValueCount; | |||
2060 | } | |||
2061 | ||||
2062 | void XclExpChSeries::CreateTrendLines( css::uno::Reference< css::chart2::XDataSeries > const & xDataSeries ) | |||
2063 | { | |||
2064 | Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY ); | |||
2065 | if( xRegCurveCont.is() ) | |||
| ||||
2066 | { | |||
2067 | const Sequence< Reference< XRegressionCurve > > aRegCurveSeq = xRegCurveCont->getRegressionCurves(); | |||
2068 | for( const Reference< XRegressionCurve >& rRegCurve : aRegCurveSeq ) | |||
2069 | { | |||
2070 | XclExpChSeriesRef xSeries = GetChartData().CreateSeries(); | |||
2071 | if( xSeries && !xSeries->ConvertTrendLine( *this, rRegCurve ) ) | |||
2072 | GetChartData().RemoveLastSeries(); | |||
2073 | } | |||
2074 | } | |||
2075 | } | |||
2076 | ||||
2077 | void XclExpChSeries::CreateErrorBars( const ScfPropertySet& rPropSet, | |||
2078 | const OUString& rBarPropName, sal_uInt8 nPosBarId, sal_uInt8 nNegBarId ) | |||
2079 | { | |||
2080 | Reference< XPropertySet > xErrorBar; | |||
2081 | if( rPropSet.GetProperty( xErrorBar, rBarPropName ) && xErrorBar.is() ) | |||
2082 | { | |||
2083 | ScfPropertySet aErrorProp( xErrorBar ); | |||
2084 | CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWPOSITIVEERROR"ShowPositiveError", nPosBarId ); | |||
2085 | CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWNEGATIVEERROR"ShowNegativeError", nNegBarId ); | |||
2086 | } | |||
2087 | } | |||
2088 | ||||
2089 | void XclExpChSeries::CreateErrorBar( const ScfPropertySet& rPropSet, | |||
2090 | const OUString& rShowPropName, sal_uInt8 nBarId ) | |||
2091 | { | |||
2092 | if( rPropSet.GetBoolProperty( rShowPropName ) ) | |||
2093 | { | |||
2094 | XclExpChSeriesRef xSeries = GetChartData().CreateSeries(); | |||
2095 | if( xSeries && !xSeries->ConvertErrorBar( *this, rPropSet, nBarId ) ) | |||
2096 | GetChartData().RemoveLastSeries(); | |||
2097 | } | |||
2098 | } | |||
2099 | ||||
2100 | void XclExpChSeries::WriteBody( XclExpStream& rStrm ) | |||
2101 | { | |||
2102 | rStrm << maData.mnCategType << maData.mnValueType << maData.mnCategCount << maData.mnValueCount; | |||
2103 | if( GetBiff() == EXC_BIFF8 ) | |||
2104 | rStrm << maData.mnBubbleType << maData.mnBubbleCount; | |||
2105 | } | |||
2106 | ||||
2107 | // Chart type groups ========================================================== | |||
2108 | ||||
2109 | XclExpChType::XclExpChType( const XclExpChRoot& rRoot ) : | |||
2110 | XclExpRecord( EXC_ID_CHUNKNOWN ), | |||
2111 | XclExpChRoot( rRoot ), | |||
2112 | maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) ) | |||
2113 | { | |||
2114 | } | |||
2115 | ||||
2116 | void XclExpChType::Convert( Reference< XDiagram > const & xDiagram, Reference< XChartType > const & xChartType, | |||
2117 | sal_Int32 nApiAxesSetIdx, bool bSwappedAxesSet, bool bHasXLabels ) | |||
2118 | { | |||
2119 | if( !xChartType.is() ) | |||
2120 | return; | |||
2121 | ||||
2122 | maTypeInfo = GetChartTypeInfo( xChartType->getChartType() ); | |||
2123 | // special handling for some chart types | |||
2124 | switch( maTypeInfo.meTypeCateg ) | |||
2125 | { | |||
2126 | case EXC_CHTYPECATEG_BAR: | |||
2127 | { | |||
2128 | maTypeInfo = GetChartTypeInfo( bSwappedAxesSet ? EXC_CHTYPEID_HORBAR : EXC_CHTYPEID_BAR ); | |||
2129 | ::set_flag( maData.mnFlags, EXC_CHBAR_HORIZONTAL, bSwappedAxesSet ); | |||
2130 | ScfPropertySet aTypeProp( xChartType ); | |||
2131 | Sequence< sal_Int32 > aInt32Seq; | |||
2132 | maData.mnOverlap = 0; | |||
2133 | if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_OVERLAPSEQ"OverlapSequence" ) && (nApiAxesSetIdx < aInt32Seq.getLength()) ) | |||
2134 | maData.mnOverlap = limit_cast< sal_Int16 >( -aInt32Seq[ nApiAxesSetIdx ], -100, 100 ); | |||
2135 | maData.mnGap = 150; | |||
2136 | if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_GAPWIDTHSEQ"GapwidthSequence" ) && (nApiAxesSetIdx < aInt32Seq.getLength()) ) | |||
2137 | maData.mnGap = limit_cast< sal_uInt16 >( aInt32Seq[ nApiAxesSetIdx ], 0, 500 ); | |||
2138 | } | |||
2139 | break; | |||
2140 | case EXC_CHTYPECATEG_RADAR: | |||
2141 | ::set_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS, bHasXLabels ); | |||
2142 | break; | |||
2143 | case EXC_CHTYPECATEG_PIE: | |||
2144 | { | |||
2145 | ScfPropertySet aTypeProp( xChartType ); | |||
2146 | bool bDonut = aTypeProp.GetBoolProperty( EXC_CHPROP_USERINGS"UseRings" ); | |||
2147 | maTypeInfo = GetChartTypeInfo( bDonut ? EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE ); | |||
2148 | maData.mnPieHole = bDonut ? 50 : 0; | |||
2149 | // #i85166# starting angle of first pie slice | |||
2150 | ScfPropertySet aDiaProp( xDiagram ); | |||
2151 | maData.mnRotation = XclExpChRoot::ConvertPieRotation( aDiaProp ); | |||
2152 | } | |||
2153 | break; | |||
2154 | case EXC_CHTYPECATEG_SCATTER: | |||
2155 | if( GetBiff() == EXC_BIFF8 ) | |||
2156 | ::set_flag( maData.mnFlags, EXC_CHSCATTER_BUBBLES, maTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES ); | |||
2157 | break; | |||
2158 | default:; | |||
2159 | } | |||
2160 | SetRecId( maTypeInfo.mnRecId ); | |||
2161 | } | |||
2162 | ||||
2163 | void XclExpChType::SetStacked( bool bPercent ) | |||
2164 | { | |||
2165 | switch( maTypeInfo.meTypeCateg ) | |||
2166 | { | |||
2167 | case EXC_CHTYPECATEG_LINE: | |||
2168 | ::set_flag( maData.mnFlags, EXC_CHLINE_STACKED ); | |||
2169 | ::set_flag( maData.mnFlags, EXC_CHLINE_PERCENT, bPercent ); | |||
2170 | break; | |||
2171 | case EXC_CHTYPECATEG_BAR: | |||
2172 | ::set_flag( maData.mnFlags, EXC_CHBAR_STACKED ); | |||
2173 | ::set_flag( maData.mnFlags, EXC_CHBAR_PERCENT, bPercent ); | |||
2174 | maData.mnOverlap = -100; | |||
2175 | break; | |||
2176 | default:; | |||
2177 | } | |||
2178 | } | |||
2179 | ||||
2180 | void XclExpChType::WriteBody( XclExpStream& rStrm ) | |||
2181 | { | |||
2182 | switch( GetRecId() ) | |||
2183 | { | |||
2184 | case EXC_ID_CHBAR: | |||
2185 | rStrm << maData.mnOverlap << maData.mnGap << maData.mnFlags; | |||
2186 | break; | |||
2187 | ||||
2188 | case EXC_ID_CHLINE: | |||
2189 | case EXC_ID_CHAREA: | |||
2190 | case EXC_ID_CHRADARLINE: | |||
2191 | case EXC_ID_CHRADARAREA: | |||
2192 | rStrm << maData.mnFlags; | |||
2193 | break; | |||
2194 | ||||
2195 | case EXC_ID_CHPIE: | |||
2196 | rStrm << maData.mnRotation << maData.mnPieHole; | |||
2197 | if( GetBiff() == EXC_BIFF8 ) | |||
2198 | rStrm << maData.mnFlags; | |||
2199 | break; | |||
2200 | ||||
2201 | case EXC_ID_CHSCATTER: | |||
2202 | if( GetBiff() == EXC_BIFF8 ) | |||
2203 | rStrm << maData.mnBubbleSize << maData.mnBubbleType << maData.mnFlags; | |||
2204 | break; | |||
2205 | ||||
2206 | default: | |||
2207 | OSL_FAIL( "XclExpChType::WriteBody - unknown chart type" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "2207" ": "), "%s", "XclExpChType::WriteBody - unknown chart type" ); } } while (false); | |||
2208 | } | |||
2209 | } | |||
2210 | ||||
2211 | XclExpChChart3d::XclExpChChart3d() : | |||
2212 | XclExpRecord( EXC_ID_CHCHART3D, 14 ) | |||
2213 | { | |||
2214 | } | |||
2215 | ||||
2216 | void XclExpChChart3d::Convert( const ScfPropertySet& rPropSet, bool b3dWallChart ) | |||
2217 | { | |||
2218 | sal_Int32 nRotationY = 0; | |||
2219 | rPropSet.GetProperty( nRotationY, EXC_CHPROP_ROTATIONVERTICAL"RotationVertical" ); | |||
2220 | sal_Int32 nRotationX = 0; | |||
2221 | rPropSet.GetProperty( nRotationX, EXC_CHPROP_ROTATIONHORIZONTAL"RotationHorizontal" ); | |||
2222 | sal_Int32 nPerspective = 15; | |||
2223 | rPropSet.GetProperty( nPerspective, EXC_CHPROP_PERSPECTIVE"Perspective" ); | |||
2224 | ||||
2225 | if( b3dWallChart ) | |||
2226 | { | |||
2227 | // Y rotation (Excel [0..359], Chart2 [-179,180]) | |||
2228 | if( nRotationY < 0 ) nRotationY += 360; | |||
2229 | maData.mnRotation = static_cast< sal_uInt16 >( nRotationY ); | |||
2230 | // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180]) | |||
2231 | maData.mnElevation = limit_cast< sal_Int16 >( nRotationX, -90, 90 ); | |||
2232 | // perspective (Excel and Chart2 [0,100]) | |||
2233 | maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 ); | |||
2234 | // flags | |||
2235 | maData.mnFlags = 0; | |||
2236 | ::set_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D, !rPropSet.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES"RightAngledAxes" ) ); | |||
2237 | ::set_flag( maData.mnFlags, EXC_CHCHART3D_AUTOHEIGHT ); | |||
2238 | ::set_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS ); | |||
2239 | } | |||
2240 | else | |||
2241 | { | |||
2242 | // Y rotation not used in pie charts, but 'first pie slice angle' | |||
2243 | maData.mnRotation = XclExpChRoot::ConvertPieRotation( rPropSet ); | |||
2244 | // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80]) | |||
2245 | maData.mnElevation = limit_cast< sal_Int16 >( (nRotationX + 270) % 180, 10, 80 ); | |||
2246 | // perspective (Excel and Chart2 [0,100]) | |||
2247 | maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 ); | |||
2248 | // flags | |||
2249 | maData.mnFlags = 0; | |||
2250 | } | |||
2251 | } | |||
2252 | ||||
2253 | void XclExpChChart3d::WriteBody( XclExpStream& rStrm ) | |||
2254 | { | |||
2255 | rStrm << maData.mnRotation | |||
2256 | << maData.mnElevation | |||
2257 | << maData.mnEyeDist | |||
2258 | << maData.mnRelHeight | |||
2259 | << maData.mnRelDepth | |||
2260 | << maData.mnDepthGap | |||
2261 | << maData.mnFlags; | |||
2262 | } | |||
2263 | ||||
2264 | XclExpChLegend::XclExpChLegend( const XclExpChRoot& rRoot ) : | |||
2265 | XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_LEGEND, EXC_ID_CHLEGEND, 20 ) | |||
2266 | { | |||
2267 | } | |||
2268 | ||||
2269 | void XclExpChLegend::Convert( const ScfPropertySet& rPropSet ) | |||
2270 | { | |||
2271 | // frame properties | |||
2272 | mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_LEGEND ); | |||
2273 | // text properties | |||
2274 | mxText = new XclExpChText( GetChRoot() ); | |||
2275 | mxText->ConvertLegend( rPropSet ); | |||
2276 | ||||
2277 | // legend position and size | |||
2278 | Any aRelPosAny, aRelSizeAny; | |||
2279 | rPropSet.GetAnyProperty( aRelPosAny, EXC_CHPROP_RELATIVEPOSITION"RelativePosition" ); | |||
2280 | rPropSet.GetAnyProperty( aRelSizeAny, EXC_CHPROP_RELATIVESIZE"RelativeSize" ); | |||
2281 | cssc::ChartLegendExpansion eApiExpand = cssc::ChartLegendExpansion_CUSTOM; | |||
2282 | rPropSet.GetProperty( eApiExpand, EXC_CHPROP_EXPANSION"Expansion" ); | |||
2283 | if( aRelPosAny.has< RelativePosition >() || ((eApiExpand == cssc::ChartLegendExpansion_CUSTOM) && aRelSizeAny.has< RelativeSize >()) ) | |||
2284 | { | |||
2285 | try | |||
2286 | { | |||
2287 | /* The 'RelativePosition' or 'RelativeSize' properties are used as | |||
2288 | indicator of manually changed legend position/size, but due to | |||
2289 | the different anchor modes used by this property (in the | |||
2290 | RelativePosition.Anchor member) it cannot be used to calculate | |||
2291 | the position easily. For this, the Chart1 API will be used | |||
2292 | instead. */ | |||
2293 | Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW ); | |||
2294 | Reference< XShape > xChart1Legend( xChart1Doc->getLegend(), UNO_SET_THROW ); | |||
2295 | // coordinates in CHLEGEND record written but not used by Excel | |||
2296 | mxFramePos = new XclExpChFramePos( EXC_CHFRAMEPOS_CHARTSIZE ); | |||
2297 | XclChFramePos& rFramePos = mxFramePos->GetFramePosData(); | |||
2298 | rFramePos.mnTLMode = EXC_CHFRAMEPOS_CHARTSIZE; | |||
2299 | css::awt::Point aLegendPos = xChart1Legend->getPosition(); | |||
2300 | rFramePos.maRect.mnX = maData.maRect.mnX = CalcChartXFromHmm( aLegendPos.X ); | |||
2301 | rFramePos.maRect.mnY = maData.maRect.mnY = CalcChartYFromHmm( aLegendPos.Y ); | |||
2302 | // legend size, Excel expects points in CHFRAMEPOS record | |||
2303 | rFramePos.mnBRMode = EXC_CHFRAMEPOS_ABSSIZE_POINTS; | |||
2304 | css::awt::Size aLegendSize = xChart1Legend->getSize(); | |||
2305 | rFramePos.maRect.mnWidth = static_cast< sal_uInt16 >( aLegendSize.Width * EXC_POINTS_PER_HMM + 0.5 ); | |||
2306 | rFramePos.maRect.mnHeight = static_cast< sal_uInt16 >( aLegendSize.Height * EXC_POINTS_PER_HMM + 0.5 ); | |||
2307 | maData.maRect.mnWidth = CalcChartXFromHmm( aLegendSize.Width ); | |||
2308 | maData.maRect.mnHeight = CalcChartYFromHmm( aLegendSize.Height ); | |||
2309 | eApiExpand = cssc::ChartLegendExpansion_CUSTOM; | |||
2310 | // manual legend position implies manual plot area | |||
2311 | GetChartData().SetManualPlotArea(); | |||
2312 | maData.mnDockMode = EXC_CHLEGEND_NOTDOCKED; | |||
2313 | // a CHFRAME record with cleared auto flags is needed | |||
2314 | if( !mxFrame ) | |||
2315 | mxFrame = new XclExpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ); | |||
2316 | mxFrame->SetAutoFlags( false, false ); | |||
2317 | } | |||
2318 | catch( Exception& ) | |||
2319 | { | |||
2320 | OSL_FAIL( "XclExpChLegend::Convert - cannot get legend shape" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "2320" ": "), "%s", "XclExpChLegend::Convert - cannot get legend shape" ); } } while (false); | |||
2321 | maData.mnDockMode = EXC_CHLEGEND_RIGHT; | |||
2322 | eApiExpand = cssc::ChartLegendExpansion_HIGH; | |||
2323 | } | |||
2324 | } | |||
2325 | else | |||
2326 | { | |||
2327 | cssc2::LegendPosition eApiPos = cssc2::LegendPosition_LINE_END; | |||
2328 | rPropSet.GetProperty( eApiPos, EXC_CHPROP_ANCHORPOSITION"AnchorPosition" ); | |||
2329 | switch( eApiPos ) | |||
2330 | { | |||
2331 | case cssc2::LegendPosition_LINE_START: maData.mnDockMode = EXC_CHLEGEND_LEFT; break; | |||
2332 | case cssc2::LegendPosition_LINE_END: maData.mnDockMode = EXC_CHLEGEND_RIGHT; break; | |||
2333 | case cssc2::LegendPosition_PAGE_START: maData.mnDockMode = EXC_CHLEGEND_TOP; break; | |||
2334 | case cssc2::LegendPosition_PAGE_END: maData.mnDockMode = EXC_CHLEGEND_BOTTOM; break; | |||
2335 | default: | |||
2336 | OSL_FAIL( "XclExpChLegend::Convert - unrecognized legend position" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "2336" ": "), "%s", "XclExpChLegend::Convert - unrecognized legend position" ); } } while (false); | |||
2337 | maData.mnDockMode = EXC_CHLEGEND_RIGHT; | |||
2338 | eApiExpand = cssc::ChartLegendExpansion_HIGH; | |||
2339 | } | |||
2340 | } | |||
2341 | ::set_flag( maData.mnFlags, EXC_CHLEGEND_STACKED, eApiExpand == cssc::ChartLegendExpansion_HIGH ); | |||
2342 | ||||
2343 | // other flags | |||
2344 | ::set_flag( maData.mnFlags, EXC_CHLEGEND_AUTOSERIES ); | |||
2345 | const sal_uInt16 nAutoFlags = EXC_CHLEGEND_DOCKED | EXC_CHLEGEND_AUTOPOSX | EXC_CHLEGEND_AUTOPOSY; | |||
2346 | ::set_flag( maData.mnFlags, nAutoFlags, maData.mnDockMode != EXC_CHLEGEND_NOTDOCKED ); | |||
2347 | } | |||
2348 | ||||
2349 | void XclExpChLegend::WriteSubRecords( XclExpStream& rStrm ) | |||
2350 | { | |||
2351 | lclSaveRecord( rStrm, mxFramePos ); | |||
2352 | lclSaveRecord( rStrm, mxText ); | |||
2353 | lclSaveRecord( rStrm, mxFrame ); | |||
2354 | } | |||
2355 | ||||
2356 | void XclExpChLegend::WriteBody( XclExpStream& rStrm ) | |||
2357 | { | |||
2358 | rStrm << maData.maRect << maData.mnDockMode << maData.mnSpacing << maData.mnFlags; | |||
2359 | } | |||
2360 | ||||
2361 | XclExpChDropBar::XclExpChDropBar( const XclExpChRoot& rRoot, XclChObjectType eObjType ) : | |||
2362 | XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DROPBAR, EXC_ID_CHDROPBAR, 2 ), | |||
2363 | meObjType( eObjType ) | |||
2364 | { | |||
2365 | } | |||
2366 | ||||
2367 | void XclExpChDropBar::Convert( const ScfPropertySet& rPropSet ) | |||
2368 | { | |||
2369 | if( rPropSet.Is() ) | |||
2370 | ConvertFrameBase( GetChRoot(), rPropSet, meObjType ); | |||
2371 | else | |||
2372 | SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, true ); | |||
2373 | } | |||
2374 | ||||
2375 | void XclExpChDropBar::WriteSubRecords( XclExpStream& rStrm ) | |||
2376 | { | |||
2377 | WriteFrameRecords( rStrm ); | |||
2378 | } | |||
2379 | ||||
2380 | void XclExpChDropBar::WriteBody( XclExpStream& rStrm ) | |||
2381 | { | |||
2382 | rStrm << sal_uInt16(100); // Distance between bars (CHDROPBAR record). | |||
2383 | } | |||
2384 | ||||
2385 | XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot& rRoot, sal_uInt16 nGroupIdx ) : | |||
2386 | XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TYPEGROUP, EXC_ID_CHTYPEGROUP, 20 ), | |||
2387 | maType( rRoot ), | |||
2388 | maTypeInfo( maType.GetTypeInfo() ) | |||
2389 | { | |||
2390 | maData.mnGroupIdx = nGroupIdx; | |||
2391 | } | |||
2392 | ||||
2393 | void XclExpChTypeGroup::ConvertType( | |||
2394 | Reference< XDiagram > const & xDiagram, Reference< XChartType > const & xChartType, | |||
2395 | sal_Int32 nApiAxesSetIdx, bool b3dChart, bool bSwappedAxesSet, bool bHasXLabels ) | |||
2396 | { | |||
2397 | // chart type settings | |||
2398 | maType.Convert( xDiagram, xChartType, nApiAxesSetIdx, bSwappedAxesSet, bHasXLabels ); | |||
2399 | ||||
2400 | // spline - TODO: get from single series (#i66858#) | |||
2401 | ScfPropertySet aTypeProp( xChartType ); | |||
2402 | cssc2::CurveStyle eCurveStyle; | |||
2403 | bool bSpline = aTypeProp.GetProperty( eCurveStyle, EXC_CHPROP_CURVESTYLE"CurveStyle" ) && | |||
2404 | (eCurveStyle != cssc2::CurveStyle_LINES); | |||
2405 | ||||
2406 | // extended type info | |||
2407 | maTypeInfo.Set( maType.GetTypeInfo(), b3dChart, bSpline ); | |||
2408 | ||||
2409 | // 3d chart settings | |||
2410 | if( maTypeInfo.mb3dChart ) // only true, if Excel chart supports 3d mode | |||
2411 | { | |||
2412 | mxChart3d = new XclExpChChart3d(); | |||
2413 | ScfPropertySet aDiaProp( xDiagram ); | |||
2414 | mxChart3d->Convert( aDiaProp, Is3dWallChart() ); | |||
2415 | } | |||
2416 | } | |||
2417 | ||||
2418 | void XclExpChTypeGroup::ConvertSeries( | |||
2419 | Reference< XDiagram > const & xDiagram, Reference< XChartType > const & xChartType, | |||
2420 | sal_Int32 nGroupAxesSetIdx, bool bPercent, bool bConnectBars ) | |||
2421 | { | |||
2422 | Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY ); | |||
2423 | if( !xSeriesCont.is() ) | |||
2424 | return; | |||
2425 | ||||
2426 | std::vector< Reference< XDataSeries > > aSeriesVec; | |||
2427 | ||||
2428 | // copy data series attached to the current axes set to the vector | |||
2429 | const Sequence< Reference< XDataSeries > > aSeriesSeq = xSeriesCont->getDataSeries(); | |||
2430 | for( const Reference< XDataSeries >& rSeries : aSeriesSeq ) | |||
2431 | { | |||
2432 | ScfPropertySet aSeriesProp( rSeries ); | |||
2433 | sal_Int32 nSeriesAxesSetIdx(0); | |||
2434 | if( aSeriesProp.GetProperty( nSeriesAxesSetIdx, EXC_CHPROP_ATTAXISINDEX"AttachedAxisIndex" ) && (nSeriesAxesSetIdx == nGroupAxesSetIdx) ) | |||
2435 | aSeriesVec.push_back( rSeries ); | |||
2436 | } | |||
2437 | ||||
2438 | // Are there any series in the current axes set? | |||
2439 | if( aSeriesVec.empty() ) | |||
2440 | return; | |||
2441 | ||||
2442 | // stacking direction (stacked/percent/deep 3d) from first series | |||
2443 | ScfPropertySet aSeriesProp( aSeriesVec.front() ); | |||
2444 | cssc2::StackingDirection eStacking; | |||
2445 | if( !aSeriesProp.GetProperty( eStacking, EXC_CHPROP_STACKINGDIR"StackingDirection" ) ) | |||
2446 | eStacking = cssc2::StackingDirection_NO_STACKING; | |||
2447 | ||||
2448 | // stacked or percent chart | |||
2449 | if( maTypeInfo.mbSupportsStacking && (eStacking == cssc2::StackingDirection_Y_STACKING) ) | |||
2450 | { | |||
2451 | // percent overrides simple stacking | |||
2452 | maType.SetStacked( bPercent ); | |||
2453 | ||||
2454 | // connected data points (only in stacked bar charts) | |||
2455 | if (bConnectBars && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR)) | |||
2456 | { | |||
2457 | sal_uInt16 nKey = EXC_CHCHARTLINE_CONNECT; | |||
2458 | m_ChartLines.insert(std::make_pair(nKey, std::make_unique<XclExpChLineFormat>(GetChRoot()))); | |||
2459 | } | |||
2460 | } | |||
2461 | else | |||
2462 | { | |||
2463 | // reverse series order for some unstacked 2D chart types | |||
2464 | if( maTypeInfo.mbReverseSeries && !Is3dChart() ) | |||
2465 | ::std::reverse( aSeriesVec.begin(), aSeriesVec.end() ); | |||
2466 | } | |||
2467 | ||||
2468 | // deep 3d chart or clustered 3d chart (stacked is not clustered) | |||
2469 | if( (eStacking == cssc2::StackingDirection_NO_STACKING) && Is3dWallChart() ) | |||
2470 | mxChart3d->SetClustered(); | |||
2471 | ||||
2472 | // varied point colors | |||
2473 | ::set_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS, aSeriesProp.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY"VaryColorsByPoint" ) ); | |||
2474 | ||||
2475 | // process all series | |||
2476 | for( const auto& rxSeries : aSeriesVec ) | |||
2477 | { | |||
2478 | // create Excel series object, stock charts need special processing | |||
2479 | if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK ) | |||
2480 | CreateAllStockSeries( xChartType, rxSeries ); | |||
2481 | else | |||
2482 | CreateDataSeries( xDiagram, rxSeries ); | |||
2483 | } | |||
2484 | } | |||
2485 | ||||
2486 | void XclExpChTypeGroup::ConvertCategSequence( Reference< XLabeledDataSequence > const & xCategSeq ) | |||
2487 | { | |||
2488 | for( size_t nIdx = 0, nSize = maSeries.GetSize(); nIdx < nSize; ++nIdx ) | |||
2489 | maSeries.GetRecord( nIdx )->ConvertCategSequence( xCategSeq ); | |||
2490 | } | |||
2491 | ||||
2492 | void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet& rPropSet ) | |||
2493 | { | |||
2494 | if( rPropSet.GetBoolProperty( EXC_CHPROP_SHOW"Show" ) ) | |||
2495 | { | |||
2496 | mxLegend = new XclExpChLegend( GetChRoot() ); | |||
2497 | mxLegend->Convert( rPropSet ); | |||
2498 | } | |||
2499 | } | |||
2500 | ||||
2501 | void XclExpChTypeGroup::WriteSubRecords( XclExpStream& rStrm ) | |||
2502 | { | |||
2503 | maType.Save( rStrm ); | |||
2504 | lclSaveRecord( rStrm, mxChart3d ); | |||
2505 | lclSaveRecord( rStrm, mxLegend ); | |||
2506 | lclSaveRecord( rStrm, mxUpBar ); | |||
2507 | lclSaveRecord( rStrm, mxDownBar ); | |||
2508 | for (auto const& it : m_ChartLines) | |||
2509 | { | |||
2510 | lclSaveRecord( rStrm, it.second.get(), EXC_ID_CHCHARTLINE, it.first ); | |||
2511 | } | |||
2512 | } | |||
2513 | ||||
2514 | sal_uInt16 XclExpChTypeGroup::GetFreeFormatIdx() const | |||
2515 | { | |||
2516 | return static_cast< sal_uInt16 >( maSeries.GetSize() ); | |||
2517 | } | |||
2518 | ||||
2519 | void XclExpChTypeGroup::CreateDataSeries( | |||
2520 | Reference< XDiagram > const & xDiagram, Reference< XDataSeries > const & xDataSeries ) | |||
2521 | { | |||
2522 | // let chart create series object with correct series index | |||
2523 | XclExpChSeriesRef xSeries = GetChartData().CreateSeries(); | |||
2524 | if( xSeries ) | |||
2525 | { | |||
2526 | if( xSeries->ConvertDataSeries( xDiagram, xDataSeries, maTypeInfo, GetGroupIdx(), GetFreeFormatIdx() ) ) | |||
2527 | maSeries.AppendRecord( xSeries ); | |||
2528 | else | |||
2529 | GetChartData().RemoveLastSeries(); | |||
2530 | } | |||
2531 | } | |||
2532 | ||||
2533 | void XclExpChTypeGroup::CreateAllStockSeries( | |||
2534 | Reference< XChartType > const & xChartType, Reference< XDataSeries > const & xDataSeries ) | |||
2535 | { | |||
2536 | // create existing series objects | |||
2537 | bool bHasOpen = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_OPENVALUES"values-first", false ); | |||
2538 | bool bHasHigh = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_HIGHVALUES"values-max", false ); | |||
2539 | bool bHasLow = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_LOWVALUES"values-min", false ); | |||
2540 | bool bHasClose = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_CLOSEVALUES"values-last", !bHasOpen ); | |||
2541 | ||||
2542 | // formatting of special stock chart elements | |||
2543 | ScfPropertySet aTypeProp( xChartType ); | |||
2544 | // hi-lo lines | |||
2545 | if( bHasHigh && bHasLow && aTypeProp.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW"ShowHighLow" ) ) | |||
2546 | { | |||
2547 | ScfPropertySet aSeriesProp( xDataSeries ); | |||
2548 | XclExpChLineFormatRef xLineFmt = new XclExpChLineFormat( GetChRoot() ); | |||
2549 | xLineFmt->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE ); | |||
2550 | sal_uInt16 nKey = EXC_CHCHARTLINE_HILO; | |||
2551 | m_ChartLines.insert(std::make_pair(nKey, std::make_unique<XclExpChLineFormat>(GetChRoot()))); | |||
2552 | } | |||
2553 | // dropbars | |||
2554 | if( !(bHasOpen && bHasClose) ) | |||
2555 | return; | |||
2556 | ||||
2557 | // dropbar type is dependent on position in the file - always create both | |||
2558 | Reference< XPropertySet > xWhitePropSet, xBlackPropSet; | |||
2559 | // white dropbar format | |||
2560 | aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY"WhiteDay" ); | |||
2561 | ScfPropertySet aWhiteProp( xWhitePropSet ); | |||
2562 | mxUpBar = new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_WHITEDROPBAR ); | |||
2563 | mxUpBar->Convert( aWhiteProp ); | |||
2564 | // black dropbar format | |||
2565 | aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY"BlackDay" ); | |||
2566 | ScfPropertySet aBlackProp( xBlackPropSet ); | |||
2567 | mxDownBar = new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_BLACKDROPBAR ); | |||
2568 | mxDownBar->Convert( aBlackProp ); | |||
2569 | } | |||
2570 | ||||
2571 | bool XclExpChTypeGroup::CreateStockSeries( Reference< XDataSeries > const & xDataSeries, | |||
2572 | const OUString& rValueRole, bool bCloseSymbol ) | |||
2573 | { | |||
2574 | bool bOk = false; | |||
2575 | // let chart create series object with correct series index | |||
2576 | XclExpChSeriesRef xSeries = GetChartData().CreateSeries(); | |||
2577 | if( xSeries ) | |||
2578 | { | |||
2579 | bOk = xSeries->ConvertStockSeries( xDataSeries, | |||
2580 | rValueRole, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol ); | |||
2581 | if( bOk ) | |||
2582 | maSeries.AppendRecord( xSeries ); | |||
2583 | else | |||
2584 | GetChartData().RemoveLastSeries(); | |||
2585 | } | |||
2586 | return bOk; | |||
2587 | } | |||
2588 | ||||
2589 | void XclExpChTypeGroup::WriteBody( XclExpStream& rStrm ) | |||
2590 | { | |||
2591 | rStrm.WriteZeroBytes( 16 ); | |||
2592 | rStrm << maData.mnFlags << maData.mnGroupIdx; | |||
2593 | } | |||
2594 | ||||
2595 | // Axes ======================================================================= | |||
2596 | ||||
2597 | XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot& rRoot ) : | |||
2598 | XclExpRecord( EXC_ID_CHLABELRANGE, 8 ), | |||
2599 | XclExpChRoot( rRoot ) | |||
2600 | { | |||
2601 | } | |||
2602 | ||||
2603 | void XclExpChLabelRange::Convert( const ScaleData& rScaleData, const ScfPropertySet& rChart1Axis, bool bMirrorOrient ) | |||
2604 | { | |||
2605 | /* Base time unit (using the property 'ExplicitTimeIncrement' from the old | |||
2606 | chart API allows to detect axis type (date axis, if property exists), | |||
2607 | and to receive the base time unit currently used in case the base time | |||
2608 | unit is set to 'automatic'. */ | |||
2609 | cssc::TimeIncrement aTimeIncrement; | |||
2610 | if( rChart1Axis.GetProperty( aTimeIncrement, EXC_CHPROP_EXPTIMEINCREMENT"ExplicitTimeIncrement" ) ) | |||
2611 | { | |||
2612 | // property exists -> this is a date axis currently | |||
2613 | ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ); | |||
2614 | ||||
2615 | // automatic base time unit, if the UNO Any 'rScaleData.TimeIncrement.TimeResolution' does not contain a valid value... | |||
2616 | bool bAutoBase = !rScaleData.TimeIncrement.TimeResolution.has< cssc::TimeIncrement >(); | |||
2617 | ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOBASE, bAutoBase ); | |||
2618 | ||||
2619 | // ...but get the current base time unit from the property of the old chart API | |||
2620 | sal_Int32 nApiTimeUnit = 0; | |||
2621 | bool bValidBaseUnit = aTimeIncrement.TimeResolution >>= nApiTimeUnit; | |||
2622 | OSL_ENSURE( bValidBaseUnit, "XclExpChLabelRange::Convert - cannot get base time unit" )do { if (true && (!(bValidBaseUnit))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/excel/xechart.cxx" ":" "2622" ": "), "%s", "XclExpChLabelRange::Convert - cannot get base time unit" ); } } while (false); | |||
2623 | maDateData.mnBaseUnit = bValidBaseUnit ? lclGetTimeUnit( nApiTimeUnit ) : EXC_CHDATERANGE_DAYS; | |||
2624 | ||||
2625 | /* Min/max values depend on base time unit, they specify the number of | |||
2626 | days, months, or years starting from null date. */ | |||
2627 | bool bAutoMin = lclConvertTimeValue( GetRoot(), maDateData.mnMinDate, rScaleData.Minimum, maDateData.mnBaseUnit ); | |||
2628 | ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMIN, bAutoMin ); | |||
2629 | bool bAutoMax = lclConvertTimeValue( GetRoot(), maDateData.mnMaxDate, rScaleData.Maximum, maDateData.mnBaseUnit ); | |||
2630 | ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAX, bAutoMax ); | |||
2631 | } | |||
2632 | ||||
2633 | // automatic axis type detection | |||
2634 | ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTODATE, rScaleData.AutoDateAxis ); | |||
2635 | ||||
2636 | // increment | |||
2637 | bool bAutoMajor = lclConvertTimeInterval( maDateData.mnMajorStep, maDateData.mnMajorUnit, rScaleData.TimeIncrement.MajorTimeInterval ); | |||
2638 | ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAJOR, bAutoMajor ); | |||
2639 | bool bAutoMinor = lclConvertTimeInterval( maDateData.mnMinorStep, maDateData.mnMinorUnit, rScaleData.TimeIncrement.MinorTimeInterval ); | |||
2640 | ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMINOR, bAutoMinor ); | |||
2641 | ||||
2642 | // origin | |||
2643 | double fOrigin = 0.0; | |||
2644 | if( !lclIsAutoAnyOrGetValue( fOrigin, rScaleData.Origin ) ) | |||
2645 | maLabelData.mnCross = limit_cast< sal_uInt16 >( fOrigin, 1, 31999 ); | |||
2646 | ||||
2647 | // reverse order | |||
2648 | if( (rScaleData.Orientation == cssc2::AxisOrientation_REVERSE) != bMirrorOrient ) | |||
2649 | ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_REVERSE ); | |||
2650 | } | |||
2651 | ||||
2652 | void XclExpChLabelRange::ConvertAxisPosition( const ScfPropertySet& rPropSet ) | |||
2653 | { | |||
2654 | cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE; | |||
2655 | rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION"CrossoverPosition" ); | |||
2656 | double fCrossingPos = 1.0; | |||
2657 | rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE"CrossoverValue" ); | |||
2658 | ||||
2659 | bool bDateAxis = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ); | |||
2660 | switch( eAxisPos ) | |||
2661 | { | |||
2662 | case cssc::ChartAxisPosition_ZERO: | |||
2663 | case cssc::ChartAxisPosition_START: | |||
2664 | maLabelData.mnCross = 1; | |||
2665 | ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS ); | |||
2666 | break; | |||
2667 | case cssc::ChartAxisPosition_END: | |||
2668 | ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_MAXCROSS ); | |||
2669 | break; | |||
2670 | case cssc::ChartAxisPosition_VALUE: | |||
2671 | maLabelData.mnCross = limit_cast< sal_uInt16 >( fCrossingPos, 1, 31999 ); | |||
2672 | ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS, false ); | |||
2673 | if( bDateAxis ) | |||
2674 | maDateData.mnCross = lclGetTimeValue( GetRoot(), fCrossingPos, maDateData.mnBaseUnit ); | |||
2675 | break; | |||
2676 | default: | |||
2677 | maLabelData.mnCross = 1; | |||
2678 | ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS ); | |||
2679 | } | |||
2680 | } | |||
2681 | ||||
2682 | void XclExpChLabelRange::Save( XclExpStream& rStrm ) | |||
2683 | { | |||
2684 | // the CHLABELRANGE record | |||
2685 | XclExpRecord::Save( rStrm ); | |||
2686 | ||||
2687 | // the CHDATERANGE record with date axis settings (BIFF8 only) | |||
2688 | if( GetBiff() != EXC_BIFF8 ) | |||
2689 | return; | |||
2690 | ||||
2691 | rStrm.StartRecord( EXC_ID_CHDATERANGE, 18 ); | |||
2692 | rStrm << maDateData.mnMinDate | |||
2693 | << maDateData.mnMaxDate | |||
2694 | << maDateData.mnMajorStep | |||
2695 | << maDateData.mnMajorUnit | |||
2696 | << maDateData.mnMinorStep | |||
2697 | << maDateData.mnMinorUnit | |||
2698 | << maDateData.mnBaseUnit | |||
2699 | << maDateData.mnCross | |||
2700 | << maDateData.mnFlags; | |||
2701 | rStrm.EndRecord(); | |||
2702 | } | |||
2703 | ||||
2704 | void XclExpChLabelRange::WriteBody( XclExpStream& rStrm ) | |||
2705 | { | |||
2706 | rStrm << maLabelData.mnCross << maLabelData.mnLabelFreq << maLabelData.mnTickFreq << maLabelData.mnFlags; | |||
2707 | } | |||
2708 | ||||
2709 | XclExpChValueRange::XclExpChValueRange( const XclExpChRoot& rRoot ) : | |||
2710 | XclExpRecord( EXC_ID_CHVALUERANGE, 42 ), | |||
2711 | XclExpChRoot( rRoot ) | |||
2712 | { | |||
2713 | } | |||
2714 | ||||
2715 | void XclExpChValueRange::Convert( const ScaleData& rScaleData ) | |||
2716 | { | |||
2717 | // scaling algorithm | |||
2718 | bool bLogScale = ScfApiHelper::GetServiceName( rScaleData.Scaling ) == "com.sun.star.chart2.LogarithmicScaling"; | |||
2719 | ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, bLogScale ); | |||
2720 | ||||
2721 | // min/max | |||
2722 | bool bAutoMin = lclIsAutoAnyOrGetScaledValue( maData.mfMin, rScaleData.Minimum, bLogScale ); | |||
2723 | ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN, bAutoMin ); | |||
2724 | bool bAutoMax = lclIsAutoAnyOrGetScaledValue( maData.mfMax, rScaleData.Maximum, bLogScale ); | |||
2725 | ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX, bAutoMax ); | |||
2726 | ||||
2727 | // origin | |||
2728 | bool bAutoCross = lclIsAutoAnyOrGetScaledValue( maData.mfCross, rScaleData.Origin, bLogScale ); | |||
2729 | ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, bAutoCross ); | |||
2730 | ||||
2731 | // major increment | |||
2732 | const IncrementData& rIncrementData = rScaleData.IncrementData; | |||
2733 | const bool bAutoMajor = lclIsAutoAnyOrGetValue( maData.mfMajorStep, rIncrementData.Distance ) || (maData.mfMajorStep <= 0.0); | |||
2734 | ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR, bAutoMajor ); | |||
2735 | // minor increment | |||
2736 | const Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements; | |||
2737 | sal_Int32 nCount = 0; | |||
2738 | ||||
2739 | // tdf#114168 If IntervalCount is 5, then enable automatic minor calculation. | |||
2740 | // During import, if minorUnit is set and majorUnit not, then it is impossible | |||
2741 | // to calculate IntervalCount. | |||
2742 | const bool bAutoMinor = bLogScale || bAutoMajor || !rSubIncrementSeq.hasElements() || | |||
2743 | lclIsAutoAnyOrGetValue( nCount, rSubIncrementSeq[ 0 ].IntervalCount ) || (nCount < 1) || (nCount == 5); | |||
2744 | ||||
2745 | if( maData.mfMajorStep && !bAutoMinor ) | |||
2746 | maData.mfMinorStep = maData.mfMajorStep / nCount; | |||
2747 | ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR, bAutoMinor ); | |||
2748 | ||||
2749 | // reverse order | |||
2750 | ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE, rScaleData.Orientation == cssc2::AxisOrientation_REVERSE ); | |||
2751 | } | |||
2752 | ||||
2753 | void XclExpChValueRange::ConvertAxisPosition( const ScfPropertySet& rPropSet ) | |||
2754 | { | |||
2755 | cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE; | |||
2756 | double fCrossingPos = 0.0; | |||
2757 | if( !(rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION"CrossoverPosition" ) && rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE"CrossoverValue" )) ) | |||
2758 | return; | |||
2759 | ||||
2760 | switch( eAxisPos ) | |||
2761 | { | |||
2762 | case cssc::ChartAxisPosition_ZERO: | |||
2763 | case cssc::ChartAxisPosition_START: | |||
2764 | ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS ); | |||
2765 | break; | |||
2766 | case cssc::ChartAxisPosition_END: | |||
2767 | ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS ); | |||
2768 | break; | |||
2769 | case cssc::ChartAxisPosition_VALUE: | |||
2770 | ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, false ); | |||
2771 | maData.mfCross = ::get_flagvalue< double >( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, log( fCrossingPos ) / log( 10.0 ), fCrossingPos ); | |||
2772 | break; | |||
2773 | default: | |||
2774 | ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS ); | |||
2775 | } | |||
2776 | } | |||
2777 | ||||
2778 | void XclExpChValueRange::WriteBody( XclExpStream& rStrm ) | |||
2779 | { | |||
2780 | rStrm << maData.mfMin | |||
2781 | << maData.mfMax | |||
2782 | << maData.mfMajorStep | |||
2783 | << maData.mfMinorStep | |||
2784 | << maData.mfCross | |||
2785 | << maData.mnFlags; | |||
2786 | } | |||
2787 | ||||
2788 | namespace { | |||
2789 | ||||
2790 | sal_uInt8 lclGetXclTickPos( sal_Int32 nApiTickmarks ) | |||
2791 | { | |||
2792 | using namespace cssc2::TickmarkStyle; | |||
2793 | sal_uInt8 nXclTickPos = 0; | |||
2794 | ::set_flag( nXclTickPos, EXC_CHTICK_INSIDE, ::get_flag( nApiTickmarks, INNER ) ); | |||
2795 | ::set_flag( nXclTickPos, EXC_CHTICK_OUTSIDE, ::get_flag( nApiTickmarks, OUTER ) ); | |||
2796 | return nXclTickPos; | |||
2797 | } | |||
2798 | ||||
2799 | } // namespace | |||
2800 | ||||
2801 | XclExpChTick::XclExpChTick( const XclExpChRoot& rRoot ) : | |||
2802 | XclExpRecord( EXC_ID_CHTICK, (rRoot.GetBiff() == EXC_BIFF8) ? 30 : 26 ), | |||
2803 | XclExpChRoot( rRoot ), | |||
2804 | mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ) | |||
2805 | { | |||
2806 | } | |||
2807 | ||||
2808 | void XclExpChTick::Convert( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nAxisType ) | |||
2809 | { | |||
2810 | // tick mark style | |||
2811 | sal_Int32 nApiTickmarks = 0; | |||
2812 | if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MAJORTICKS"MajorTickmarks" ) ) | |||
2813 | maData.mnMajor = lclGetXclTickPos( nApiTickmarks ); | |||
2814 | if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MINORTICKS"MinorTickmarks" ) ) | |||
2815 | maData.mnMinor = lclGetXclTickPos( nApiTickmarks ); | |||
2816 | ||||
2817 | // axis labels | |||
2818 | if( (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) && (nAxisType == EXC_CHAXIS_X) ) | |||
2819 | { | |||
2820 | /* Radar charts disable their category labels via chart type, not via | |||
2821 | axis, and axis labels are always 'near axis'. */ | |||
2822 | maData.mnLabelPos = EXC_CHTICK_NEXT; | |||
2823 | } | |||
2824 | else if( !rPropSet.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS"DisplayLabels" ) ) | |||
2825 | { | |||
2826 | // no labels | |||
2827 | maData.mnLabelPos = EXC_CHTICK_NOLABEL; | |||
2828 | } | |||
2829 | else if( rTypeInfo.mb3dChart && (nAxisType == EXC_CHAXIS_Y) ) | |||
2830 | { | |||
2831 | // Excel expects 'near axis' at Y axes in 3D charts | |||
2832 | maData.mnLabelPos = EXC_CHTICK_NEXT; | |||
2833 | } | |||
2834 | else | |||
2835 | { | |||
2836 | cssc::ChartAxisLabelPosition eApiLabelPos = cssc::ChartAxisLabelPosition_NEAR_AXIS; | |||
2837 | rPropSet.GetProperty( eApiLabelPos, EXC_CHPROP_LABELPOSITION"LabelPosition" ); | |||
2838 | switch( eApiLabelPos ) | |||
2839 | { | |||
2840 | case cssc::ChartAxisLabelPosition_NEAR_AXIS: | |||
2841 | case cssc::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE: maData.mnLabelPos = EXC_CHTICK_NEXT; break; | |||
2842 | case cssc::ChartAxisLabelPosition_OUTSIDE_START: maData.mnLabelPos = EXC_CHTICK_LOW; break; | |||
2843 | case cssc::ChartAxisLabelPosition_OUTSIDE_END: maData.mnLabelPos = EXC_CHTICK_HIGH; break; | |||
2844 | default: maData.mnLabelPos = EXC_CHTICK_NEXT; | |||
2845 | } | |||
2846 | } | |||
2847 | } | |||
2848 | ||||
2849 | void XclExpChTick::SetFontColor( const Color& rColor, sal_uInt32 nColorId ) | |||
2850 | { | |||
2851 | maData.maTextColor = rColor; | |||
2852 | ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR, rColor == COL_AUTO ); | |||
2853 | mnTextColorId = nColorId; | |||
2854 | } | |||
2855 | ||||
2856 | void XclExpChTick::SetRotation( sal_uInt16 nRotation ) | |||
2857 | { | |||
2858 | maData.mnRotation = nRotation; | |||
2859 | ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOROT, false ); | |||
2860 | ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 2, 3 ); | |||
2861 | } | |||
2862 | ||||
2863 | void XclExpChTick::WriteBody( XclExpStream& rStrm ) | |||
2864 | { | |||
2865 | rStrm << maData.mnMajor | |||
2866 | << maData.mnMinor | |||
2867 | << maData.mnLabelPos | |||
2868 | << maData.mnBackMode; | |||
2869 | rStrm.WriteZeroBytes( 16 ); | |||
2870 | rStrm << maData.maTextColor | |||
2871 | << maData.mnFlags; | |||
2872 | if( GetBiff() == EXC_BIFF8 ) | |||
2873 | rStrm << GetPalette().GetColorIndex( mnTextColorId ) << maData.mnRotation; | |||
2874 | } | |||
2875 | ||||
2876 | namespace { | |||
2877 | ||||
2878 | /** Returns an API axis object from the passed coordinate system. */ | |||
2879 | Reference< XAxis > lclGetApiAxis( Reference< XCoordinateSystem > const & xCoordSystem, | |||
2880 | sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx ) | |||
2881 | { | |||
2882 | Reference< XAxis > xAxis; | |||
2883 | if( (nApiAxisDim >= 0) && xCoordSystem.is() ) try | |||
2884 | { | |||
2885 | xAxis = xCoordSystem->getAxisByDimension( nApiAxisDim, nApiAxesSetIdx ); | |||
2886 | } | |||
2887 | catch( Exception& ) | |||
2888 | { | |||
2889 | } | |||
2890 | return xAxis; | |||
2891 | } | |||
2892 | ||||
2893 | Reference< cssc::XAxis > lclGetApiChart1Axis( Reference< XChartDocument > const & xChartDoc, | |||
2894 | sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx ) | |||
2895 | { | |||
2896 | Reference< cssc::XAxis > xChart1Axis; | |||
2897 | try | |||
2898 | { | |||
2899 | Reference< cssc::XChartDocument > xChart1Doc( xChartDoc, UNO_QUERY_THROW ); | |||
2900 | Reference< cssc::XAxisSupplier > xChart1AxisSupp( xChart1Doc->getDiagram(), UNO_QUERY_THROW ); | |||
2901 | switch( nApiAxesSetIdx ) | |||
2902 | { | |||
2903 | case EXC_CHART_AXESSET_PRIMARY: | |||
2904 | xChart1Axis = xChart1AxisSupp->getAxis( nApiAxisDim ); | |||
2905 | break; | |||
2906 | case EXC_CHART_AXESSET_SECONDARY: | |||
2907 | xChart1Axis = xChart1AxisSupp->getSecondaryAxis( nApiAxisDim ); | |||
2908 | break; | |||
2909 | } | |||
2910 | } | |||
2911 | catch( Exception& ) | |||
2912 | { | |||
2913 | } | |||
2914 | return xChart1Axis; | |||
2915 | } | |||
2916 | ||||
2917 | } // namespace | |||
2918 | ||||
2919 | XclExpChAxis::XclExpChAxis( const XclExpChRoot& rRoot, sal_uInt16 nAxisType ) : | |||
2920 | XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXIS, EXC_ID_CHAXIS, 18 ), | |||
2921 | mnNumFmtIdx( EXC_FORMAT_NOTFOUND ) | |||
2922 | { | |||
2923 | maData.mnType = nAxisType; | |||
2924 | } | |||
2925 | ||||
2926 | void XclExpChAxis::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId ) | |||
2927 | { | |||
2928 | mxFont = xFont; | |||
2929 | if( mxTick ) | |||
2930 | mxTick->SetFontColor( rColor, nColorId ); | |||
2931 | } | |||
2932 | ||||
2933 | void XclExpChAxis::SetRotation( sal_uInt16 nRotation ) | |||
2934 | { | |||
2935 | if( mxTick ) | |||
2936 | mxTick->SetRotation( nRotation ); | |||
2937 | } | |||
2938 | ||||
2939 | void XclExpChAxis::Convert( Reference< XAxis > const & xAxis, Reference< XAxis > const & xCrossingAxis, | |||
2940 | Reference< cssc::XAxis > const & xChart1Axis, const XclChExtTypeInfo& rTypeInfo ) | |||
2941 | { | |||
2942 | ScfPropertySet aAxisProp( xAxis ); | |||
2943 | bool bCategoryAxis = ((GetAxisType() == EXC_CHAXIS_X) && rTypeInfo.mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z); | |||
2944 | ||||
2945 | // axis line format ------------------------------------------------------- | |||
2946 | ||||
2947 | mxAxisLine = new XclExpChLineFormat( GetChRoot() ); | |||
2948 | mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE ); | |||
2949 | // #i58688# axis enabled | |||
2950 | mxAxisLine->SetShowAxis( aAxisProp.GetBoolProperty( EXC_CHPROP_SHOW"Show" ) ); | |||
2951 | ||||
2952 | // axis scaling and increment --------------------------------------------- | |||
2953 | ||||
2954 | ScfPropertySet aCrossingProp( xCrossingAxis ); | |||
2955 | if( bCategoryAxis ) | |||
2956 | { | |||
2957 | mxLabelRange = new XclExpChLabelRange( GetChRoot() ); | |||
2958 | mxLabelRange->SetTicksBetweenCateg( rTypeInfo.mbTicksBetweenCateg ); | |||
2959 | if( xAxis.is() ) | |||
2960 | { | |||
2961 | ScfPropertySet aChart1AxisProp( xChart1Axis ); | |||
2962 | // #i71684# radar charts have reversed rotation direction | |||
2963 | mxLabelRange->Convert( xAxis->getScaleData(), aChart1AxisProp, (GetAxisType() == EXC_CHAXIS_X) && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) ); | |||
2964 | } | |||
2965 | // get position of crossing axis on this axis from passed axis object | |||
2966 | if( aCrossingProp.Is() ) | |||
2967 | mxLabelRange->ConvertAxisPosition( aCrossingProp ); | |||
2968 | } | |||
2969 | else | |||
2970 | { | |||
2971 | mxValueRange = new XclExpChValueRange( GetChRoot() ); | |||
2972 | if( xAxis.is() ) | |||
2973 | mxValueRange->Convert( xAxis->getScaleData() ); | |||
2974 | // get position of crossing axis on this axis from passed axis object | |||
2975 | if( aCrossingProp.Is() ) | |||
2976 | mxValueRange->ConvertAxisPosition( aCrossingProp ); | |||
2977 | } | |||
2978 | ||||
2979 | // axis caption text ------------------------------------------------------ | |||
2980 | ||||
2981 | // axis ticks properties | |||
2982 | mxTick = new XclExpChTick( GetChRoot() ); | |||
2983 | mxTick->Convert( aAxisProp, rTypeInfo, GetAxisType() ); | |||
2984 | ||||
2985 | // axis label formatting and rotation | |||
2986 | ConvertFontBase( GetChRoot(), aAxisProp ); | |||
2987 | ConvertRotationBase( aAxisProp, true ); | |||
2988 | ||||
2989 | // axis number format | |||
2990 | sal_Int32 nApiNumFmt = 0; | |||
2991 | if( !bCategoryAxis && aAxisProp.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT"NumberFormat" ) ) | |||
2992 | { | |||
2993 | bool bLinkNumberFmtToSource = false; | |||
2994 | if ( !aAxisProp.GetProperty( bLinkNumberFmtToSource, EXC_CHPROP_NUMBERFORMAT_LINKSRC"LinkNumberFormatToSource" ) || !bLinkNumberFmtToSource ) | |||
2995 | mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) ); | |||
2996 | } | |||
2997 | ||||
2998 | // grid ------------------------------------------------------------------- | |||
2999 | ||||
3000 | if( !xAxis.is() ) | |||
3001 | return; | |||
3002 | ||||
3003 | // main grid | |||
3004 | ScfPropertySet aGridProp( xAxis->getGridProperties() ); | |||
3005 | if( aGridProp.GetBoolProperty( EXC_CHPROP_SHOW"Show" ) ) | |||
3006 | mxMajorGrid = lclCreateLineFormat( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE ); | |||
3007 | // sub grid | |||
3008 | Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties(); | |||
3009 | if( aSubGridPropSeq.hasElements() ) | |||
3010 | { | |||
3011 | ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] ); | |||
3012 | if( aSubGridProp.GetBoolProperty( EXC_CHPROP_SHOW"Show" ) ) | |||
3013 | mxMinorGrid = lclCreateLineFormat( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE ); | |||
3014 | } | |||
3015 | } | |||
3016 | ||||
3017 | void XclExpChAxis::ConvertWall( css::uno::Reference< css::chart2::XDiagram > const & xDiagram ) | |||
3018 | { | |||
3019 | if( !xDiagram.is() ) | |||
3020 | return; | |||
3021 | ||||
3022 | switch( GetAxisType() ) | |||
3023 | { | |||
3024 | case EXC_CHAXIS_X: | |||
3025 | { | |||
3026 | ScfPropertySet aWallProp( xDiagram->getWall() ); | |||
3027 | mxWallFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_WALL3D ); | |||
3028 | } | |||
3029 | break; | |||
3030 | case EXC_CHAXIS_Y: | |||
3031 | { | |||
3032 | ScfPropertySet aFloorProp( xDiagram->getFloor() ); | |||
3033 | mxWallFrame = lclCreateFrame( GetChRoot(), aFloorProp, EXC_CHOBJTYPE_FLOOR3D ); | |||
3034 | } | |||
3035 | break; | |||
3036 | default: | |||
3037 | mxWallFrame.clear(); | |||
3038 | } | |||
3039 | } | |||
3040 | ||||
3041 | void XclExpChAxis::WriteSubRecords( XclExpStream& rStrm ) | |||
3042 | { | |||
3043 | lclSaveRecord( rStrm, mxLabelRange ); | |||
3044 | lclSaveRecord( rStrm, mxValueRange ); | |||
3045 | if( mnNumFmtIdx != EXC_FORMAT_NOTFOUND ) | |||
3046 | XclExpUInt16Record( EXC_ID_CHFORMAT, mnNumFmtIdx ).Save( rStrm ); | |||
3047 | lclSaveRecord( rStrm, mxTick ); | |||
3048 | lclSaveRecord( rStrm, mxFont ); | |||
3049 | lclSaveRecord( rStrm, mxAxisLine, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_AXISLINE ); | |||
3050 | lclSaveRecord( rStrm, mxMajorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MAJORGRID ); | |||
3051 | lclSaveRecord( rStrm, mxMinorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MINORGRID ); | |||
3052 | lclSaveRecord( rStrm, mxWallFrame, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_WALLS ); | |||
3053 | } | |||
3054 | ||||
3055 | void XclExpChAxis::WriteBody( XclExpStream& rStrm ) | |||
3056 | { | |||
3057 | rStrm << maData.mnType; | |||
3058 | rStrm.WriteZeroBytes( 16 ); | |||
3059 | } | |||
3060 | ||||
3061 | XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot& rRoot, sal_uInt16 nAxesSetId ) : | |||
3062 | XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXESSET, EXC_ID_CHAXESSET, 18 ) | |||
3063 | { | |||
3064 | maData.mnAxesSetId = nAxesSetId; | |||
3065 | SetFutureRecordContext( 0, nAxesSetId ); | |||
3066 | ||||
3067 | /* Need to set a reasonable size for the plot area, otherwise Excel will | |||
3068 | move away embedded shapes while auto-sizing the plot area. This is just | |||
3069 | a wild guess, but will be fixed with implementing manual positioning of | |||
3070 | chart elements. */ | |||
3071 | maData.maRect.mnX = 262; | |||
3072 | maData.maRect.mnY = 626; | |||
3073 | maData.maRect.mnWidth = 3187; | |||
3074 | maData.maRect.mnHeight = 2633; | |||
3075 | } | |||
3076 | ||||
3077 | sal_uInt16 XclExpChAxesSet::Convert( Reference< XDiagram > const & xDiagram, sal_uInt16 nFirstGroupIdx ) | |||
3078 | { | |||
3079 | /* First unused chart type group index is passed to be able to continue | |||
3080 | counting of chart type groups for secondary axes set. */ | |||
3081 | sal_uInt16 nGroupIdx = nFirstGroupIdx; | |||
3082 | Reference< XCoordinateSystemContainer > xCoordSysCont( xDiagram, UNO_QUERY ); | |||
3083 | if( xCoordSysCont.is() ) | |||
3084 | { | |||
3085 | Sequence< Reference< XCoordinateSystem > > aCoordSysSeq = xCoordSysCont->getCoordinateSystems(); | |||
3086 | if( aCoordSysSeq.hasElements() ) | |||
3087 | { | |||
3088 | /* Process first coordinate system only. Import filter puts all | |||
3089 | chart types into one coordinate system. */ | |||
3090 | Reference< XCoordinateSystem > xCoordSystem = aCoordSysSeq[ 0 ]; | |||
3091 | sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex(); | |||
3092 | ||||
3093 | // 3d mode | |||
3094 | bool b3dChart = xCoordSystem.is() && (xCoordSystem->getDimension() == 3); | |||
3095 | ||||
3096 | // percent charts | |||
3097 | namespace ApiAxisType = cssc2::AxisType; | |||
3098 | Reference< XAxis > xApiYAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_Y, nApiAxesSetIdx ); | |||
3099 | bool bPercent = xApiYAxis.is() && (xApiYAxis->getScaleData().AxisType == ApiAxisType::PERCENT); | |||
3100 | ||||
3101 | // connector lines in bar charts | |||
3102 | ScfPropertySet aDiaProp( xDiagram ); | |||
3103 | bool bConnectBars = aDiaProp.GetBoolProperty( EXC_CHPROP_CONNECTBARS"ConnectBars" ); | |||
3104 | ||||
3105 | // swapped axes sets | |||
3106 | ScfPropertySet aCoordSysProp( xCoordSystem ); | |||
3107 | bool bSwappedAxesSet = aCoordSysProp.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS"SwapXAndYAxis" ); | |||
3108 | ||||
3109 | // X axis for later use | |||
3110 | Reference< XAxis > xApiXAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_X, nApiAxesSetIdx ); | |||
3111 | // X axis labels | |||
3112 | ScfPropertySet aXAxisProp( xApiXAxis ); | |||
3113 | bool bHasXLabels = aXAxisProp.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS"DisplayLabels" ); | |||
3114 | ||||
3115 | // process chart types | |||
3116 | Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY ); | |||
3117 | if( xChartTypeCont.is() ) | |||
3118 | { | |||
3119 | const Sequence< Reference< XChartType > > aChartTypeSeq = xChartTypeCont->getChartTypes(); | |||
3120 | for( const Reference< XChartType >& rChartType : aChartTypeSeq ) | |||
3121 | { | |||
3122 | XclExpChTypeGroupRef xTypeGroup = new XclExpChTypeGroup( GetChRoot(), nGroupIdx ); | |||
3123 | xTypeGroup->ConvertType( xDiagram, rChartType, nApiAxesSetIdx, b3dChart, bSwappedAxesSet, bHasXLabels ); | |||
3124 | /* If new chart type group cannot be inserted into a combination | |||
3125 | chart with existing type groups, insert all series into last | |||
3126 | contained chart type group instead of creating a new group. */ | |||
3127 | XclExpChTypeGroupRef xLastGroup = GetLastTypeGroup(); | |||
3128 | if( xLastGroup && !(xTypeGroup->IsCombinable2d() && xLastGroup->IsCombinable2d()) ) | |||
3129 | { | |||
3130 | xLastGroup->ConvertSeries( xDiagram, rChartType, nApiAxesSetIdx, bPercent, bConnectBars ); | |||
3131 | } | |||
3132 | else | |||
3133 | { | |||
3134 | xTypeGroup->ConvertSeries( xDiagram, rChartType, nApiAxesSetIdx, bPercent, bConnectBars ); | |||
3135 | if( xTypeGroup->IsValidGroup() ) | |||
3136 | { | |||
3137 | maTypeGroups.AppendRecord( xTypeGroup ); | |||
3138 | ++nGroupIdx; | |||
3139 | } | |||
3140 | } | |||
3141 | } | |||
3142 | } | |||
3143 | ||||
3144 | if( XclExpChTypeGroup* pGroup = GetFirstTypeGroup().get() ) | |||
3145 | { | |||
3146 | const XclChExtTypeInfo& rTypeInfo = pGroup->GetTypeInfo(); | |||
3147 | ||||
3148 | // create axes according to chart type (no axes for pie and donut charts) | |||
3149 | if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE ) | |||
3150 | { | |||
3151 | ConvertAxis( mxXAxis, EXC_CHAXIS_X, mxXAxisTitle, EXC_CHOBJLINK_XAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_Y ); | |||
3152 | ConvertAxis( mxYAxis, EXC_CHAXIS_Y, mxYAxisTitle, EXC_CHOBJLINK_YAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_X ); | |||
3153 | if( pGroup->Is3dDeepChart() ) | |||
3154 | ConvertAxis( mxZAxis, EXC_CHAXIS_Z, mxZAxisTitle, EXC_CHOBJLINK_ZAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_NONE ); | |||
3155 | } | |||
3156 | ||||
3157 | // X axis category ranges | |||
3158 | if( rTypeInfo.mbCategoryAxis && xApiXAxis.is() ) | |||
3159 | { | |||
3160 | const ScaleData aScaleData = xApiXAxis->getScaleData(); | |||
3161 | for( size_t nIdx = 0, nSize = maTypeGroups.GetSize(); nIdx < nSize; ++nIdx ) | |||
3162 | maTypeGroups.GetRecord( nIdx )->ConvertCategSequence( aScaleData.Categories ); | |||
3163 | } | |||
3164 | ||||
3165 | // legend | |||
3166 | if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) ) | |||
3167 | { | |||
3168 | Reference< XLegend > xLegend = xDiagram->getLegend(); | |||
3169 | if( xLegend.is() ) | |||
3170 | { | |||
3171 | ScfPropertySet aLegendProp( xLegend ); | |||
3172 | pGroup->ConvertLegend( aLegendProp ); | |||
3173 | } | |||
3174 | } | |||
3175 | } | |||
3176 | } | |||
3177 | } | |||
3178 | ||||
3179 | // wall/floor/diagram frame formatting | |||
3180 | if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) ) | |||
3181 | { | |||
3182 | XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup(); | |||
3183 | if( xTypeGroup && xTypeGroup->Is3dWallChart() ) | |||
3184 | { | |||
3185 | // wall/floor formatting (3D charts) | |||
3186 | if( mxXAxis ) | |||
3187 | mxXAxis->ConvertWall( xDiagram ); | |||
3188 | if( mxYAxis ) | |||
3189 | mxYAxis->ConvertWall( xDiagram ); | |||
3190 | } | |||
3191 | else | |||
3192 | { | |||
3193 | // diagram background formatting | |||
3194 | ScfPropertySet aWallProp( xDiagram->getWall() ); | |||
3195 | mxPlotFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_PLOTFRAME ); | |||
3196 | } | |||
3197 | } | |||
3198 | ||||
3199 | // inner and outer plot area position and size | |||
3200 | try | |||
3201 | { | |||
3202 | Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW ); | |||
3203 | Reference< cssc::XDiagramPositioning > xPositioning( xChart1Doc->getDiagram(), UNO_QUERY_THROW ); | |||
3204 | // set manual flag in chart data | |||
3205 | if( !xPositioning->isAutomaticDiagramPositioning() ) | |||
3206 | GetChartData().SetManualPlotArea(); | |||
3207 | // the CHAXESSET record contains the inner plot area | |||
3208 | maData.maRect = CalcChartRectFromHmm( xPositioning->calculateDiagramPositionExcludingAxes() ); | |||
3209 | // the embedded CHFRAMEPOS record contains the outer plot area | |||
3210 | mxFramePos = new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT ); | |||
3211 | // for pie charts, always use inner plot area size to exclude the data labels as Excel does | |||
3212 | const XclExpChTypeGroup* pFirstTypeGroup = GetFirstTypeGroup().get(); | |||
3213 | bool bPieChart = pFirstTypeGroup && (pFirstTypeGroup->GetTypeInfo().meTypeCateg == EXC_CHTYPECATEG_PIE); | |||
3214 | mxFramePos->GetFramePosData().maRect = bPieChart ? maData.maRect : | |||
3215 | CalcChartRectFromHmm( xPositioning->calculateDiagramPositionIncludingAxes() ); | |||
3216 | } | |||
3217 | catch( Exception& ) | |||
3218 | { | |||
3219 | } | |||
3220 | ||||
3221 | // return first unused chart type group index for next axes set | |||
3222 | return nGroupIdx; | |||
3223 | } | |||
3224 | ||||
3225 | bool XclExpChAxesSet::Is3dChart() const | |||
3226 | { | |||
3227 | XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup(); | |||
3228 | return xTypeGroup && xTypeGroup->Is3dChart(); | |||
3229 | } | |||
3230 | ||||
3231 | void XclExpChAxesSet::WriteSubRecords( XclExpStream& rStrm ) | |||
3232 | { | |||
3233 | lclSaveRecord( rStrm, mxFramePos ); | |||
3234 | lclSaveRecord( rStrm, mxXAxis ); | |||
3235 | lclSaveRecord( rStrm, mxYAxis ); | |||
3236 | lclSaveRecord( rStrm, mxZAxis ); | |||
3237 | lclSaveRecord( rStrm, mxXAxisTitle ); | |||
3238 | lclSaveRecord( rStrm, mxYAxisTitle ); | |||
3239 | lclSaveRecord( rStrm, mxZAxisTitle ); | |||
3240 | if( mxPlotFrame ) | |||
3241 | { | |||
3242 | XclExpEmptyRecord( EXC_ID_CHPLOTFRAME ).Save( rStrm ); | |||
3243 | mxPlotFrame->Save( rStrm ); | |||
3244 | } | |||
3245 | maTypeGroups.Save( rStrm ); | |||
3246 | } | |||
3247 | ||||
3248 | XclExpChTypeGroupRef XclExpChAxesSet::GetFirstTypeGroup() const | |||
3249 | { | |||
3250 | return maTypeGroups.GetFirstRecord(); | |||
3251 | } | |||
3252 | ||||
3253 | XclExpChTypeGroupRef XclExpChAxesSet::GetLastTypeGroup() const | |||
3254 | { | |||
3255 | return maTypeGroups.GetLastRecord(); | |||
3256 | } | |||
3257 | ||||
3258 | void XclExpChAxesSet::ConvertAxis( | |||
3259 | XclExpChAxisRef& rxChAxis, sal_uInt16 nAxisType, | |||
3260 | XclExpChTextRef& rxChAxisTitle, sal_uInt16 nTitleTarget, | |||
3261 | Reference< XCoordinateSystem > const & xCoordSystem, const XclChExtTypeInfo& rTypeInfo, | |||
3262 | sal_Int32 nCrossingAxisDim ) | |||
3263 | { | |||
3264 | // create and convert axis object | |||
3265 | rxChAxis = new XclExpChAxis( GetChRoot(), nAxisType ); | |||
3266 | sal_Int32 nApiAxisDim = rxChAxis->GetApiAxisDimension(); | |||
3267 | sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex(); | |||
3268 | Reference< XAxis > xAxis = lclGetApiAxis( xCoordSystem, nApiAxisDim, nApiAxesSetIdx ); | |||
3269 | Reference< XAxis > xCrossingAxis = lclGetApiAxis( xCoordSystem, nCrossingAxisDim, nApiAxesSetIdx ); | |||
3270 | Reference< cssc::XAxis > xChart1Axis = lclGetApiChart1Axis( GetChartDocument(), nApiAxisDim, nApiAxesSetIdx ); | |||
3271 | rxChAxis->Convert( xAxis, xCrossingAxis, xChart1Axis, rTypeInfo ); | |||
3272 | ||||
3273 | // create and convert axis title | |||
3274 | Reference< XTitled > xTitled( xAxis, UNO_QUERY ); | |||
3275 | rxChAxisTitle = lclCreateTitle( GetChRoot(), xTitled, nTitleTarget ); | |||
3276 | } | |||
3277 | ||||
3278 | void XclExpChAxesSet::WriteBody( XclExpStream& rStrm ) | |||
3279 | { | |||
3280 | rStrm << maData.mnAxesSetId << maData.maRect; | |||
3281 | } | |||
3282 | ||||
3283 | // The chart object =========================================================== | |||
3284 | ||||
3285 | static void lcl_getChartSubTitle(const Reference<XChartDocument>& xChartDoc, | |||
3286 | OUString& rSubTitle) | |||
3287 | { | |||
3288 | Reference< css::chart::XChartDocument > xChartDoc1(xChartDoc, UNO_QUERY); | |||
3289 | if (!xChartDoc1.is()) | |||
3290 | return; | |||
3291 | ||||
3292 | Reference< XPropertySet > xProp(xChartDoc1->getSubTitle(), UNO_QUERY); | |||
3293 | if (!xProp.is()) | |||
3294 | return; | |||
3295 | ||||
3296 | OUString aTitle; | |||
3297 | Any any = xProp->getPropertyValue("String"); | |||
3298 | if (any >>= aTitle) | |||
3299 | rSubTitle = aTitle; | |||
3300 | } | |||
3301 | ||||
3302 | XclExpChChart::XclExpChChart( const XclExpRoot& rRoot, | |||
3303 | Reference< XChartDocument > const & xChartDoc, const tools::Rectangle& rChartRect ) : | |||
3304 | XclExpChGroupBase( XclExpChRoot( rRoot, *this ), EXC_CHFRBLOCK_TYPE_CHART, EXC_ID_CHCHART, 16 ) | |||
3305 | { | |||
3306 | Size aPtSize = OutputDevice::LogicToLogic( rChartRect.GetSize(), MapMode( MapUnit::Map100thMM ), MapMode( MapUnit::MapPoint ) ); | |||
3307 | // rectangle is stored in 16.16 fixed-point format | |||
3308 | maRect.mnX = maRect.mnY = 0; | |||
3309 | maRect.mnWidth = static_cast< sal_Int32 >( aPtSize.Width() << 16 ); | |||
3310 | maRect.mnHeight = static_cast< sal_Int32 >( aPtSize.Height() << 16 ); | |||
3311 | ||||
3312 | // global chart properties (default values) | |||
3313 | ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, false ); | |||
3314 | ::set_flag( maProps.mnFlags, EXC_CHPROPS_MANPLOTAREA ); | |||
3315 | maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP; | |||
3316 | ||||
3317 | // always create both axes set objects | |||
3318 | mxPrimAxesSet = std::make_shared<XclExpChAxesSet>( GetChRoot(), EXC_CHAXESSET_PRIMARY ); | |||
3319 | mxSecnAxesSet = std::make_shared<XclExpChAxesSet>( GetChRoot(), EXC_CHAXESSET_SECONDARY ); | |||
3320 | ||||
3321 | if( !xChartDoc.is() ) | |||
3322 | return; | |||
3323 | ||||
3324 | Reference< XDiagram > xDiagram = xChartDoc->getFirstDiagram(); | |||
3325 | ||||
3326 | // global chart properties (only 'include hidden cells' attribute for now) | |||
3327 | ScfPropertySet aDiagramProp( xDiagram ); | |||
3328 | bool bIncludeHidden = aDiagramProp.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS"IncludeHiddenCells" ); | |||
3329 | ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, !bIncludeHidden ); | |||
3330 | ||||
3331 | // initialize API conversion (remembers xChartDoc and rChartRect internally) | |||
3332 | InitConversion( xChartDoc, rChartRect ); | |||
3333 | ||||
3334 | // chart frame | |||
3335 | ScfPropertySet aFrameProp( xChartDoc->getPageBackground() ); | |||
3336 | mxFrame = lclCreateFrame( GetChRoot(), aFrameProp, EXC_CHOBJTYPE_BACKGROUND ); | |||
3337 | ||||
3338 | // chart title | |||
3339 | Reference< XTitled > xTitled( xChartDoc, UNO_QUERY ); | |||
3340 | OUString aSubTitle; | |||
3341 | lcl_getChartSubTitle(xChartDoc, aSubTitle); | |||
3342 | mxTitle = lclCreateTitle( GetChRoot(), xTitled, EXC_CHOBJLINK_TITLE, | |||
3343 | !aSubTitle.isEmpty() ? &aSubTitle : nullptr ); | |||
3344 | ||||
3345 | // diagrams (axes sets) | |||
3346 | sal_uInt16 nFreeGroupIdx = mxPrimAxesSet->Convert( xDiagram, 0 ); | |||
3347 | if( !mxPrimAxesSet->Is3dChart() ) | |||
3348 | mxSecnAxesSet->Convert( xDiagram, nFreeGroupIdx ); | |||
3349 | ||||
3350 | // treatment of missing values | |||
3351 | ScfPropertySet aDiaProp( xDiagram ); | |||
3352 | sal_Int32 nMissingValues = 0; | |||
3353 | if( aDiaProp.GetProperty( nMissingValues, EXC_CHPROP_MISSINGVALUETREATMENT"MissingValueTreatment" ) ) | |||
3354 | { | |||
3355 | using namespace cssc::MissingValueTreatment; | |||
3356 | switch( nMissingValues ) | |||
3357 | { | |||
3358 | case LEAVE_GAP: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP; break; | |||
3359 | case USE_ZERO: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_ZERO; break; | |||
3360 | case CONTINUE: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_INTERPOLATE; break; | |||
3361 | } | |||
3362 | } | |||
3363 | ||||
3364 | // finish API conversion | |||
3365 | FinishConversion(); | |||
3366 | } | |||
3367 | ||||
3368 | XclExpChSeriesRef XclExpChChart::CreateSeries() | |||
3369 | { | |||
3370 | XclExpChSeriesRef xSeries; | |||
3371 | sal_uInt16 nSeriesIdx = static_cast< sal_uInt16 >( maSeries.GetSize() ); | |||
3372 | if( nSeriesIdx <= EXC_CHSERIES_MAXSERIES ) | |||
3373 | { | |||
3374 | xSeries = new XclExpChSeries( GetChRoot(), nSeriesIdx ); | |||
3375 | maSeries.AppendRecord( xSeries ); | |||
3376 | } | |||
3377 | return xSeries; | |||
3378 | } | |||
3379 | ||||
3380 | void XclExpChChart::RemoveLastSeries() | |||
3381 | { | |||
3382 | if( !maSeries.IsEmpty() ) | |||
3383 | maSeries.RemoveRecord( maSeries.GetSize() - 1 ); | |||
3384 | } | |||
3385 | ||||
3386 | void XclExpChChart::SetDataLabel( XclExpChTextRef const & xText ) | |||
3387 | { | |||
3388 | if( xText ) | |||
3389 | maLabels.AppendRecord( xText ); | |||
3390 | } | |||
3391 | ||||
3392 | void XclExpChChart::SetManualPlotArea() | |||
3393 | { | |||
3394 | // this flag does not exist in BIFF5 | |||
3395 | if( GetBiff() == EXC_BIFF8 ) | |||
3396 | ::set_flag( maProps.mnFlags, EXC_CHPROPS_USEMANPLOTAREA ); | |||
3397 | } | |||
3398 | ||||
3399 | void XclExpChChart::WriteSubRecords( XclExpStream& rStrm ) | |||
3400 | { | |||
3401 | // background format | |||
3402 | lclSaveRecord( rStrm, mxFrame ); | |||
3403 | ||||
3404 | // data series | |||
3405 | maSeries.Save( rStrm ); | |||
3406 | ||||
3407 | // CHPROPERTIES record | |||
3408 | rStrm.StartRecord( EXC_ID_CHPROPERTIES, 4 ); | |||
3409 | rStrm << maProps.mnFlags << maProps.mnEmptyMode << sal_uInt8( 0 ); | |||
3410 | rStrm.EndRecord(); | |||
3411 | ||||
3412 | // axes sets (always save primary axes set) | |||
3413 | sal_uInt16 nUsedAxesSets = mxSecnAxesSet->IsValidAxesSet() ? 2 : 1; | |||
3414 | XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS, nUsedAxesSets ).Save( rStrm ); | |||
3415 | mxPrimAxesSet->Save( rStrm ); | |||
3416 | if( mxSecnAxesSet->IsValidAxesSet() ) | |||
3417 | mxSecnAxesSet->Save( rStrm ); | |||
3418 | ||||
3419 | // chart title and data labels | |||
3420 | lclSaveRecord( rStrm, mxTitle ); | |||
3421 | maLabels.Save( rStrm ); | |||
3422 | } | |||
3423 | ||||
3424 | void XclExpChChart::WriteBody( XclExpStream& rStrm ) | |||
3425 | { | |||
3426 | rStrm << maRect; | |||
3427 | } | |||
3428 | ||||
3429 | XclExpChartDrawing::XclExpChartDrawing( const XclExpRoot& rRoot, | |||
3430 | const Reference< XModel >& rxModel, const Size& rChartSize ) : | |||
3431 | XclExpRoot( rRoot ) | |||
3432 | { | |||
3433 | if( rChartSize.IsEmpty() ) | |||
3434 | return; | |||
3435 | ||||
3436 | ScfPropertySet aPropSet( rxModel ); | |||
3437 | Reference< XShapes > xShapes; | |||
3438 | if( !(aPropSet.GetProperty( xShapes, EXC_CHPROP_ADDITIONALSHAPES"AdditionalShapes" ) && xShapes.is() && (xShapes->getCount() > 0)) ) | |||
3439 | return; | |||
3440 | ||||
3441 | /* Create a new independent object manager with own DFF stream for the | |||
3442 | DGCONTAINER, pass global manager as parent for shared usage of | |||
3443 | global DFF data (picture container etc.). */ | |||
3444 | mxObjMgr = std::make_shared<XclExpEmbeddedObjectManager>( GetObjectManager(), rChartSize, EXC_CHART_TOTALUNITS, EXC_CHART_TOTALUNITS ); | |||
3445 | // initialize the drawing object list | |||
3446 | mxObjMgr->StartSheet(); | |||
3447 | // process the draw page (convert all shapes) | |||
3448 | mxObjRecs = mxObjMgr->ProcessDrawing( xShapes ); | |||
3449 | // finalize the DFF stream | |||
3450 | mxObjMgr->EndDocument(); | |||
3451 | } | |||
3452 | ||||
3453 | XclExpChartDrawing::~XclExpChartDrawing() | |||
3454 | { | |||
3455 | } | |||
3456 | ||||
3457 | void XclExpChartDrawing::Save( XclExpStream& rStrm ) | |||
3458 | { | |||
3459 | if( mxObjRecs ) | |||
3460 | mxObjRecs->Save( rStrm ); | |||
3461 | } | |||
3462 | ||||
3463 | XclExpChart::XclExpChart( const XclExpRoot& rRoot, Reference< XModel > const & xModel, const tools::Rectangle& rChartRect ) : | |||
3464 | XclExpSubStream( EXC_BOF_CHART ), | |||
3465 | XclExpRoot( rRoot ) | |||
3466 | { | |||
3467 | AppendNewRecord( new XclExpChartPageSettings( rRoot ) ); | |||
3468 | AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT, false ) ); | |||
3469 | AppendNewRecord( new XclExpChartDrawing( rRoot, xModel, rChartRect.GetSize() ) ); | |||
3470 | AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS, EXC_CHUNITS_TWIPS ) ); | |||
3471 | ||||
3472 | Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY ); | |||
3473 | AppendNewRecord( new XclExpChChart( rRoot, xChartDoc, rChartRect ) ); | |||
3474 | } | |||
3475 | ||||
3476 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_COM_SUN_STAR_UNO_REFERENCE_H |
20 | #define INCLUDED_COM_SUN_STAR_UNO_REFERENCE_H |
21 | |
22 | #include "sal/config.h" |
23 | |
24 | #include <cassert> |
25 | #include <cstddef> |
26 | |
27 | #if defined LIBO_INTERNAL_ONLY1 |
28 | #include <type_traits> |
29 | #endif |
30 | |
31 | #include "rtl/alloc.h" |
32 | |
33 | namespace com |
34 | { |
35 | namespace sun |
36 | { |
37 | namespace star |
38 | { |
39 | namespace uno |
40 | { |
41 | |
42 | class RuntimeException; |
43 | class XInterface; |
44 | class Type; |
45 | class Any; |
46 | |
47 | /** Enum defining UNO_REF_NO_ACQUIRE for setting reference without acquiring a given interface. |
48 | Deprecated, please use SAL_NO_ACQUIRE. |
49 | @deprecated |
50 | */ |
51 | enum UnoReference_NoAcquire |
52 | { |
53 | /** This enum value can be used for creating a reference granting a given interface, |
54 | i.e. transferring ownership to it. |
55 | */ |
56 | UNO_REF_NO_ACQUIRE |
57 | }; |
58 | |
59 | /** This base class serves as a base class for all template reference classes and |
60 | has been introduced due to compiler problems with templated operators ==, =!. |
61 | */ |
62 | class BaseReference |
63 | { |
64 | protected: |
65 | /** the interface pointer |
66 | */ |
67 | XInterface * _pInterface; |
68 | |
69 | /** Queries given interface for type rType. |
70 | |
71 | @param pInterface interface pointer |
72 | @param rType interface type |
73 | @return interface of demanded type (may be null) |
74 | */ |
75 | inline static XInterface * SAL_CALL iquery( XInterface * pInterface, const Type & rType ); |
76 | /** Queries given interface for type rType. |
77 | Throws a RuntimeException if the demanded interface cannot be queried. |
78 | |
79 | @param pInterface interface pointer |
80 | @param rType interface type |
81 | @return interface of demanded type |
82 | */ |
83 | inline static XInterface * SAL_CALL iquery_throw( XInterface * pInterface, const Type & rType ); |
84 | |
85 | public: |
86 | /** Gets interface pointer. This call does not acquire the interface. |
87 | |
88 | @return UNacquired interface pointer |
89 | */ |
90 | XInterface * SAL_CALL get() const |
91 | { return _pInterface; } |
92 | |
93 | /** Checks if reference is null. |
94 | |
95 | @return true if reference acquires an interface, i.e. true if it is not null |
96 | */ |
97 | bool SAL_CALL is() const |
98 | { return (NULL__null != _pInterface); } |
99 | |
100 | #if defined LIBO_INTERNAL_ONLY1 |
101 | /** Checks if reference is null. |
102 | |
103 | @return true if reference acquires an interface, i.e. true if it is not null |
104 | */ |
105 | explicit operator bool() const |
106 | { return is(); } |
107 | #endif |
108 | |
109 | /** Equality operator: compares two interfaces |
110 | Checks if both references are null or refer to the same object. |
111 | |
112 | @param pInterface another interface |
113 | @return true if both references are null or refer to the same object, false otherwise |
114 | */ |
115 | inline bool SAL_CALL operator == ( XInterface * pInterface ) const; |
116 | /** Inequality operator: compares two interfaces |
117 | Checks if both references are null or refer to the same object. |
118 | |
119 | @param pInterface another interface |
120 | @return false if both references are null or refer to the same object, true otherwise |
121 | */ |
122 | inline bool SAL_CALL operator != ( XInterface * pInterface ) const; |
123 | |
124 | /** Equality operator: compares two interfaces |
125 | Checks if both references are null or refer to the same object. |
126 | |
127 | @param rRef another reference |
128 | @return true if both references are null or refer to the same object, false otherwise |
129 | */ |
130 | inline bool SAL_CALL operator == ( const BaseReference & rRef ) const; |
131 | /** Inequality operator: compares two interfaces |
132 | Checks if both references are null or refer to the same object. |
133 | |
134 | @param rRef another reference |
135 | @return false if both references are null or refer to the same object, true otherwise |
136 | */ |
137 | inline bool SAL_CALL operator != ( const BaseReference & rRef ) const; |
138 | |
139 | /** Needed by some STL containers. |
140 | |
141 | @param rRef another reference |
142 | @return true, if this reference is less than rRef |
143 | */ |
144 | inline bool SAL_CALL operator < ( const BaseReference & rRef ) const; |
145 | }; |
146 | |
147 | /** Enum defining UNO_QUERY for implicit interface query. |
148 | */ |
149 | enum UnoReference_Query |
150 | { |
151 | /** This enum value can be used for implicit interface query. |
152 | */ |
153 | UNO_QUERY |
154 | }; |
155 | /** Enum defining UNO_QUERY_THROW for implicit interface query. |
156 | If the demanded interface is unavailable, then a RuntimeException is thrown. |
157 | */ |
158 | enum UnoReference_QueryThrow |
159 | { |
160 | /** This enum value can be used for implicit interface query. |
161 | */ |
162 | UNO_QUERY_THROW |
163 | }; |
164 | /** Enum defining UNO_SET_THROW for throwing if attempts are made to assign a null |
165 | interface |
166 | |
167 | @since UDK 3.2.8 |
168 | */ |
169 | enum UnoReference_SetThrow |
170 | { |
171 | UNO_SET_THROW |
172 | }; |
173 | |
174 | /** Template reference class for interface type derived from BaseReference. |
175 | A special constructor given the UNO_QUERY identifier queries interfaces |
176 | for reference type. |
177 | */ |
178 | template< class interface_type > |
179 | class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) Reference : public BaseReference |
180 | { |
181 | /** Queries given interface for type interface_type. |
182 | |
183 | @param pInterface interface pointer |
184 | @return interface of demanded type (may be null) |
185 | */ |
186 | inline static XInterface * SAL_CALL iquery( XInterface * pInterface ); |
187 | /** Queries given interface for type interface_type. |
188 | Throws a RuntimeException if the demanded interface cannot be queried. |
189 | |
190 | @param pInterface interface pointer |
191 | @return interface of demanded type |
192 | */ |
193 | inline static XInterface * SAL_CALL iquery_throw( XInterface * pInterface ); |
194 | /** Returns the given interface if it is not <NULL/>, throws a RuntimeException otherwise. |
195 | |
196 | @param pInterface interface pointer |
197 | @return pInterface |
198 | */ |
199 | inline static interface_type * SAL_CALL iset_throw( interface_type * pInterface ); |
200 | |
201 | /** Cast from an "interface pointer" (e.g., BaseReference::_pInterface) to a |
202 | pointer to this interface_type. |
203 | |
204 | To work around ambiguities in the case of multiple-inheritance interface |
205 | types (which inherit XInterface more than once), use reinterpret_cast |
206 | (resp. a sequence of two static_casts, to avoid warnings about |
207 | reinterpret_cast used between related classes) to switch from a pointer |
208 | to XInterface to a pointer to this derived interface_type. In |
209 | principle, this is not guaranteed to work. In practice, it seems to |
210 | work on all supported platforms. |
211 | */ |
212 | static interface_type * castFromXInterface(XInterface * p) { |
213 | return static_cast< interface_type * >(static_cast< void * >(p)); |
214 | } |
215 | |
216 | /** Cast from a pointer to this interface_type to an "interface pointer" |
217 | (e.g., BaseReference::_pInterface). |
218 | |
219 | To work around ambiguities in the case of multiple-inheritance interface |
220 | types (which inherit XInterface more than once), use reinterpret_cast |
221 | (resp. a sequence of two static_casts, to avoid warnings about |
222 | reinterpret_cast used between related classes) to switch from a pointer |
223 | to this derived interface_type to a pointer to XInterface. In |
224 | principle, this is not guaranteed to work. In practice, it seems to |
225 | work on all supported platforms. |
226 | */ |
227 | static XInterface * castToXInterface(interface_type * p) { |
228 | return static_cast< XInterface * >(static_cast< void * >(p)); |
229 | } |
230 | |
231 | public: |
232 | /// @cond INTERNAL |
233 | // these are here to force memory de/allocation to sal lib. |
234 | static void * SAL_CALL operator new ( ::size_t nSize ) |
235 | { return ::rtl_allocateMemory( nSize ); } |
236 | static void SAL_CALL operator delete ( void * pMem ) |
237 | { ::rtl_freeMemory( pMem ); } |
238 | static void * SAL_CALL operator new ( ::size_t, void * pMem ) |
239 | { return pMem; } |
240 | static void SAL_CALL operator delete ( void *, void * ) |
241 | {} |
242 | /// @endcond |
243 | |
244 | /** Destructor: Releases interface if set. |
245 | */ |
246 | inline ~Reference() COVERITY_NOEXCEPT_FALSE; |
247 | |
248 | /** Default Constructor: Sets null reference. |
249 | */ |
250 | inline Reference(); |
251 | |
252 | /** Copy constructor: Copies interface reference. |
253 | |
254 | @param rRef another reference |
255 | */ |
256 | inline Reference( const Reference< interface_type > & rRef ); |
257 | |
258 | #if defined LIBO_INTERNAL_ONLY1 |
259 | /** Move constructor |
260 | |
261 | @param rRef another reference |
262 | */ |
263 | inline Reference( Reference< interface_type > && rRef ) noexcept; |
264 | |
265 | /** Up-casting conversion constructor: Copies interface reference. |
266 | |
267 | Does not work for up-casts to ambiguous bases. For the special case of |
268 | up-casting to Reference< XInterface >, see the corresponding conversion |
269 | operator. |
270 | |
271 | @param rRef another reference |
272 | */ |
273 | template< class derived_type > |
274 | inline Reference( |
275 | const Reference< derived_type > & rRef, |
276 | std::enable_if_t< |
277 | std::is_base_of_v<interface_type, derived_type> |
278 | && !std::is_same_v<interface_type, XInterface>, void *> = nullptr); |
279 | #endif |
280 | |
281 | /** Constructor: Sets given interface pointer. |
282 | |
283 | @param pInterface an interface pointer |
284 | */ |
285 | inline Reference( interface_type * pInterface ); |
286 | |
287 | /** Constructor: Sets given interface pointer without acquiring it. |
288 | |
289 | @param pInterface another reference |
290 | @param dummy SAL_NO_ACQUIRE to force obvious distinction to other constructors |
291 | */ |
292 | inline Reference( interface_type * pInterface, __sal_NoAcquire dummy); |
293 | /** Constructor: Sets given interface pointer without acquiring it. |
294 | Deprecated, please use SAL_NO_ACQUIRE version. |
295 | |
296 | @deprecated |
297 | @param pInterface another reference |
298 | @param dummy UNO_REF_NO_ACQUIRE to force obvious distinction to other constructors |
299 | */ |
300 | inline SAL_DEPRECATED("use SAL_NO_ACQUIRE version")__attribute__((deprecated("use SAL_NO_ACQUIRE version"))) Reference( interface_type * pInterface, UnoReference_NoAcquire dummy ); |
301 | |
302 | /** Constructor: Queries given interface for reference interface type (interface_type). |
303 | |
304 | @param rRef another reference |
305 | @param dummy UNO_QUERY to force obvious distinction to other constructors |
306 | */ |
307 | inline Reference( const BaseReference & rRef, UnoReference_Query dummy ); |
308 | /** Constructor: Queries given interface for reference interface type (interface_type). |
309 | |
310 | @param pInterface an interface pointer |
311 | @param dummy UNO_QUERY to force obvious distinction to other constructors |
312 | */ |
313 | inline Reference( XInterface * pInterface, UnoReference_Query dummy); |
314 | /** Constructor: Queries given any for reference interface type (interface_type). |
315 | |
316 | @param rAny an any |
317 | @param dummy UNO_QUERY to force obvious distinction to other constructors |
318 | */ |
319 | inline Reference( const Any & rAny, UnoReference_Query dummy); |
320 | /** Constructor: Queries given interface for reference interface type (interface_type). |
321 | Throws a RuntimeException if the demanded interface cannot be queried. |
322 | |
323 | @param rRef another reference |
324 | @param dummy UNO_QUERY_THROW to force obvious distinction |
325 | to other constructors |
326 | */ |
327 | inline Reference( const BaseReference & rRef, UnoReference_QueryThrow dummy ); |
328 | #ifdef LIBO_INTERNAL_ONLY1 |
329 | /** |
330 | Prevent code from calling the QUERY_THROW constructor, when they meant to use the SET_THROW constructor. |
331 | */ |
332 | Reference( const Reference< interface_type > & rRef, UnoReference_QueryThrow dummy ) = delete; |
333 | #endif |
334 | /** Constructor: Queries given interface for reference interface type (interface_type). |
335 | Throws a RuntimeException if the demanded interface cannot be queried. |
336 | |
337 | @param pInterface an interface pointer |
338 | @param dummy UNO_QUERY_THROW to force obvious distinction |
339 | to other constructors |
340 | */ |
341 | inline Reference( XInterface * pInterface, UnoReference_QueryThrow dummy ); |
342 | /** Constructor: Queries given any for reference interface type (interface_type). |
343 | Throws a RuntimeException if the demanded interface cannot be queried. |
344 | |
345 | @param rAny an any |
346 | @param dummy UNO_QUERY_THROW to force obvious distinction |
347 | to other constructors |
348 | */ |
349 | inline Reference( const Any & rAny, UnoReference_QueryThrow dummy ); |
350 | /** Constructor: assigns from the given interface of the same type. Throws a RuntimeException |
351 | if the source interface is NULL. |
352 | |
353 | @param rRef another interface reference of the same type |
354 | @param dummy UNO_SET_THROW to distinguish from default copy constructor |
355 | |
356 | @since UDK 3.2.8 |
357 | */ |
358 | inline Reference( const Reference< interface_type > & rRef, UnoReference_SetThrow dummy ); |
359 | /** Constructor: assigns from the given interface of the same type. Throws a RuntimeException |
360 | if the source interface is NULL. |
361 | |
362 | @param pInterface an interface pointer |
363 | @param dummy UNO_SET_THROW to distinguish from default assignment constructor |
364 | |
365 | @since UDK 3.2.8 |
366 | */ |
367 | inline Reference( interface_type * pInterface, UnoReference_SetThrow dummy ); |
368 | |
369 | /** Cast operator to Reference< XInterface >: Reference objects are binary compatible and |
370 | any interface must be derived from com.sun.star.uno.XInterface. |
371 | This a useful direct cast possibility. |
372 | */ |
373 | SAL_CALL operator const Reference< XInterface > & () const |
374 | { return * reinterpret_cast< const Reference< XInterface > * >( this ); } |
375 | |
376 | /** Dereference operator: Used to call interface methods. |
377 | |
378 | @return UNacquired interface pointer |
379 | */ |
380 | interface_type * SAL_CALL operator -> () const { |
381 | assert(_pInterface != NULL)(static_cast <bool> (_pInterface != __null) ? void (0) : __assert_fail ("_pInterface != NULL", "/home/maarten/src/libreoffice/core/include/com/sun/star/uno/Reference.h" , 381, __extension__ __PRETTY_FUNCTION__)); |
382 | return castFromXInterface(_pInterface); |
383 | } |
384 | |
385 | /** Indirection operator. |
386 | |
387 | @since LibreOffice 6.3 |
388 | @return UNacquired interface reference |
389 | */ |
390 | interface_type & SAL_CALL operator * () const { |
391 | assert(_pInterface != NULL)(static_cast <bool> (_pInterface != __null) ? void (0) : __assert_fail ("_pInterface != NULL", "/home/maarten/src/libreoffice/core/include/com/sun/star/uno/Reference.h" , 391, __extension__ __PRETTY_FUNCTION__)); |
392 | return *castFromXInterface(_pInterface); |
393 | } |
394 | |
395 | /** Gets interface pointer. This call does not acquire the interface. |
396 | |
397 | @return UNacquired interface pointer |
398 | */ |
399 | interface_type * SAL_CALL get() const |
400 | { return castFromXInterface(_pInterface); } |
401 | |
402 | /** Clears reference, i.e. releases interface. Reference is null after clear() call. |
403 | */ |
404 | inline void SAL_CALL clear(); |
405 | |
406 | /** Sets the given interface. An interface already set will be released. |
407 | |
408 | @param rRef another reference |
409 | @return true, if non-null interface was set |
410 | */ |
411 | inline bool SAL_CALL set( const Reference< interface_type > & rRef ); |
412 | /** Sets the given interface. An interface already set will be released. |
413 | |
414 | @param pInterface another interface |
415 | @return true, if non-null interface was set |
416 | */ |
417 | inline bool SAL_CALL set( interface_type * pInterface ); |
418 | |
419 | /** Sets interface pointer without acquiring it. An interface already set will be released. |
420 | |
421 | @param pInterface an interface pointer |
422 | @param dummy SAL_NO_ACQUIRE to force obvious distinction to set methods |
423 | @return true, if non-null interface was set |
424 | */ |
425 | inline bool SAL_CALL set( interface_type * pInterface, __sal_NoAcquire dummy); |
426 | /** Sets interface pointer without acquiring it. An interface already set will be released. |
427 | Deprecated, please use SAL_NO_ACQUIRE version. |
428 | |
429 | @deprecated |
430 | @param pInterface an interface pointer |
431 | @param dummy UNO_REF_NO_ACQUIRE to force obvious distinction to set methods |
432 | @return true, if non-null interface was set |
433 | */ |
434 | inline SAL_DEPRECATED("use SAL_NO_ACQUIRE version")__attribute__((deprecated("use SAL_NO_ACQUIRE version"))) bool SAL_CALL set( interface_type * pInterface, UnoReference_NoAcquire dummy); |
435 | |
436 | /** Queries given interface for reference interface type (interface_type) and sets it. |
437 | An interface already set will be released. |
438 | |
439 | @param pInterface an interface pointer |
440 | @param dummy UNO_QUERY to force obvious distinction to set methods |
441 | @return true, if non-null interface was set |
442 | */ |
443 | inline bool SAL_CALL set( XInterface * pInterface, UnoReference_Query dummy ); |
444 | /** Queries given interface for reference interface type (interface_type) and sets it. |
445 | An interface already set will be released. |
446 | |
447 | @param rRef another reference |
448 | @param dummy UNO_QUERY to force obvious distinction to set methods |
449 | @return true, if non-null interface was set |
450 | */ |
451 | inline bool SAL_CALL set( const BaseReference & rRef, UnoReference_Query dummy); |
452 | |
453 | /** Queries given any for reference interface type (interface_type) |
454 | and sets it. An interface already set will be released. |
455 | |
456 | @param rAny |
457 | an Any containing an interface |
458 | @param dummy |
459 | UNO_QUERY to force obvious distinction |
460 | to set methods |
461 | @return |
462 | true, if non-null interface was set |
463 | */ |
464 | inline bool set( Any const & rAny, UnoReference_Query dummy ); |
465 | |
466 | /** Queries given interface for reference interface type (interface_type) and sets it. |
467 | An interface already set will be released. |
468 | Throws a RuntimeException if the demanded interface cannot be set. |
469 | |
470 | @param pInterface an interface pointer |
471 | @param dummy UNO_QUERY_THROW to force obvious distinction |
472 | to set methods |
473 | */ |
474 | inline void SAL_CALL set( XInterface * pInterface, UnoReference_QueryThrow dummy ); |
475 | /** Queries given interface for reference interface type (interface_type) and sets it. |
476 | An interface already set will be released. |
477 | Throws a RuntimeException if the demanded interface cannot be set. |
478 | |
479 | @param rRef another reference |
480 | @param dummy UNO_QUERY_THROW to force obvious distinction |
481 | to set methods |
482 | */ |
483 | inline void SAL_CALL set( const BaseReference & rRef, UnoReference_QueryThrow dummy ); |
484 | #ifdef LIBO_INTERNAL_ONLY1 |
485 | /** |
486 | Prevent code from calling the QUERY_THROW version, when they meant to use the SET_THROW version. |
487 | */ |
488 | void set( const Reference< interface_type > & rRef, UnoReference_QueryThrow dummy ) = delete; |
489 | #endif |
490 | |
491 | /** Queries given any for reference interface type (interface_type) and |
492 | sets it. An interface already set will be released. |
493 | Throws a RuntimeException if the demanded interface cannot be set. |
494 | |
495 | @param rAny |
496 | an Any containing an interface |
497 | @param dummy |
498 | UNO_QUERY_THROW to force obvious distinction to set methods |
499 | */ |
500 | inline void set( Any const & rAny, UnoReference_QueryThrow dummy); |
501 | /** sets the given interface |
502 | An interface already set will be released. |
503 | Throws a RuntimeException if the source interface is @b NULL. |
504 | |
505 | @param pInterface an interface pointer |
506 | @param dummy UNO_SET_THROW to force obvious distinction to other set methods |
507 | |
508 | @since UDK 3.2.8 |
509 | */ |
510 | inline void SAL_CALL set( interface_type * pInterface, UnoReference_SetThrow dummy); |
511 | /** sets the given interface |
512 | An interface already set will be released. |
513 | Throws a RuntimeException if the source interface is @b NULL. |
514 | |
515 | @param rRef an interface reference |
516 | @param dummy UNO_SET_THROW to force obvious distinction to other set methods |
517 | |
518 | @since UDK 3.2.8 |
519 | */ |
520 | inline void SAL_CALL set( const Reference< interface_type > & rRef, UnoReference_SetThrow dummy); |
521 | |
522 | |
523 | /** Assignment operator: Acquires given interface pointer and sets reference. |
524 | An interface already set will be released. |
525 | |
526 | @param pInterface an interface pointer |
527 | @return this reference |
528 | */ |
529 | inline Reference< interface_type > & SAL_CALL operator = ( interface_type * pInterface ); |
530 | /** Assignment operator: Acquires given interface reference and sets reference. |
531 | An interface already set will be released. |
532 | |
533 | @param rRef an interface reference |
534 | @return this reference |
535 | */ |
536 | inline Reference< interface_type > & SAL_CALL operator = ( const Reference< interface_type > & rRef ); |
537 | #if defined LIBO_INTERNAL_ONLY1 |
538 | /** Assignment move operator: Acquires given interface reference and sets reference. |
539 | An interface already set will be released. |
540 | |
541 | @param rRef an interface reference |
542 | @return this reference |
543 | */ |
544 | inline Reference< interface_type > & SAL_CALL operator = ( Reference< interface_type > && rRef ) noexcept; |
545 | #endif |
546 | /** Queries given interface reference for type interface_type. |
547 | |
548 | @param rRef interface reference |
549 | @return interface reference of demanded type (may be null) |
550 | */ |
551 | SAL_WARN_UNUSED_RESULT[[nodiscard]] inline static Reference< interface_type > SAL_CALL query( const BaseReference & rRef ); |
552 | /** Queries given interface for type interface_type. |
553 | |
554 | @param pInterface interface pointer |
555 | @return interface reference of demanded type (may be null) |
556 | */ |
557 | SAL_WARN_UNUSED_RESULT[[nodiscard]] inline static Reference< interface_type > SAL_CALL query( XInterface * pInterface ); |
558 | }; |
559 | |
560 | } |
561 | } |
562 | } |
563 | } |
564 | |
565 | #endif |
566 | |
567 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_RTL_USTRING_HXX | ||||||||
21 | #define INCLUDED_RTL_USTRING_HXX | ||||||||
22 | |||||||||
23 | #include "sal/config.h" | ||||||||
24 | |||||||||
25 | #include <cassert> | ||||||||
26 | #include <cstddef> | ||||||||
27 | #include <cstdlib> | ||||||||
28 | #include <limits> | ||||||||
29 | #include <new> | ||||||||
30 | #include <ostream> | ||||||||
31 | #include <utility> | ||||||||
32 | |||||||||
33 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
34 | #include <string_view> | ||||||||
35 | #include <type_traits> | ||||||||
36 | #endif | ||||||||
37 | |||||||||
38 | #include "rtl/ustring.h" | ||||||||
39 | #include "rtl/string.hxx" | ||||||||
40 | #include "rtl/stringutils.hxx" | ||||||||
41 | #include "rtl/textenc.h" | ||||||||
42 | |||||||||
43 | #ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" | ||||||||
44 | #include "config_global.h" | ||||||||
45 | #include "rtl/stringconcat.hxx" | ||||||||
46 | #endif | ||||||||
47 | |||||||||
48 | #ifdef RTL_STRING_UNITTEST | ||||||||
49 | extern bool rtl_string_unittest_invalid_conversion; | ||||||||
50 | #endif | ||||||||
51 | |||||||||
52 | // The unittest uses slightly different code to help check that the proper | ||||||||
53 | // calls are made. The class is put into a different namespace to make | ||||||||
54 | // sure the compiler generates a different (if generating also non-inline) | ||||||||
55 | // copy of the function and does not merge them together. The class | ||||||||
56 | // is "brought" into the proper rtl namespace by a typedef below. | ||||||||
57 | #ifdef RTL_STRING_UNITTEST | ||||||||
58 | #define rtl rtlunittest | ||||||||
59 | #endif | ||||||||
60 | |||||||||
61 | namespace rtl | ||||||||
62 | { | ||||||||
63 | |||||||||
64 | class OUStringBuffer; | ||||||||
65 | |||||||||
66 | #ifdef RTL_STRING_UNITTEST | ||||||||
67 | #undef rtl | ||||||||
68 | #endif | ||||||||
69 | |||||||||
70 | #if defined LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" | ||||||||
71 | /// @cond INTERNAL | ||||||||
72 | |||||||||
73 | /** | ||||||||
74 | A wrapper dressing a string literal as a static-refcount rtl_uString. | ||||||||
75 | |||||||||
76 | This class is not part of public API and is meant to be used only in LibreOffice code. | ||||||||
77 | @since LibreOffice 4.0 | ||||||||
78 | */ | ||||||||
79 | template<std::size_t N> class SAL_WARN_UNUSED__attribute__((warn_unused)) OUStringLiteral { | ||||||||
80 | static_assert(N != 0); | ||||||||
81 | static_assert(N - 1 <= std::numeric_limits<sal_Int32>::max(), "literal too long"); | ||||||||
82 | |||||||||
83 | public: | ||||||||
84 | #if HAVE_CPP_CONSTEVAL0 | ||||||||
85 | consteval | ||||||||
86 | #else | ||||||||
87 | constexpr | ||||||||
88 | #endif | ||||||||
89 | OUStringLiteral(char16_t const (&literal)[N]) { | ||||||||
90 | assertLayout(); | ||||||||
91 | assert(literal[N - 1] == '\0')(static_cast <bool> (literal[N - 1] == '\0') ? void (0) : __assert_fail ("literal[N - 1] == '\\0'", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 91, __extension__ __PRETTY_FUNCTION__)); | ||||||||
92 | //TODO: Use C++20 constexpr std::copy_n (P0202R3): | ||||||||
93 | for (std::size_t i = 0; i != N; ++i) { | ||||||||
94 | buffer[i] = literal[i]; | ||||||||
95 | } | ||||||||
96 | } | ||||||||
97 | |||||||||
98 | constexpr sal_Int32 getLength() const { return length; } | ||||||||
99 | |||||||||
100 | constexpr sal_Unicode const * getStr() const SAL_RETURNS_NONNULL__attribute__((returns_nonnull)) { return buffer; } | ||||||||
101 | |||||||||
102 | constexpr operator std::u16string_view() const { return {buffer, sal_uInt32(length)}; } | ||||||||
103 | |||||||||
104 | private: | ||||||||
105 | static constexpr void assertLayout() { | ||||||||
106 | // These static_asserts verifying the layout compatibility with rtl_uString cannot be class | ||||||||
107 | // member declarations, as offsetof requires a complete type, so defer them to here: | ||||||||
108 | static_assert(offsetof(OUStringLiteral, refCount)__builtin_offsetof(OUStringLiteral, refCount) == offsetof(rtl_uString, refCount)__builtin_offsetof(rtl_uString, refCount)); | ||||||||
109 | static_assert(std::is_same_v<decltype(refCount), decltype(rtl_uString::refCount)>); | ||||||||
110 | static_assert(offsetof(OUStringLiteral, length)__builtin_offsetof(OUStringLiteral, length) == offsetof(rtl_uString, length)__builtin_offsetof(rtl_uString, length)); | ||||||||
111 | static_assert(std::is_same_v<decltype(length), decltype(rtl_uString::length)>); | ||||||||
112 | static_assert(offsetof(OUStringLiteral, buffer)__builtin_offsetof(OUStringLiteral, buffer) == offsetof(rtl_uString, buffer)__builtin_offsetof(rtl_uString, buffer)); | ||||||||
113 | static_assert( | ||||||||
114 | std::is_same_v< | ||||||||
115 | std::remove_extent_t<decltype(buffer)>, | ||||||||
116 | std::remove_extent_t<decltype(rtl_uString::buffer)>>); | ||||||||
117 | } | ||||||||
118 | |||||||||
119 | // Same layout as rtl_uString (include/rtl/ustring.h): | ||||||||
120 | oslInterlockedCount refCount = 0x40000000; // SAL_STRING_STATIC_FLAG (sal/rtl/strimp.hxx) | ||||||||
121 | sal_Int32 length = N - 1; | ||||||||
122 | sal_Unicode buffer[N] = {}; //TODO: drop initialization for C++20 (P1331R2) | ||||||||
123 | }; | ||||||||
124 | |||||||||
125 | #if defined RTL_STRING_UNITTEST | ||||||||
126 | namespace libreoffice_internal { | ||||||||
127 | template<std::size_t N> struct ExceptConstCharArrayDetector<OUStringLiteral<N>> {}; | ||||||||
128 | template<std::size_t N> struct ExceptCharArrayDetector<OUStringLiteral<N>> {}; | ||||||||
129 | } | ||||||||
130 | #endif | ||||||||
131 | |||||||||
132 | /// @endcond | ||||||||
133 | #endif | ||||||||
134 | |||||||||
135 | /* ======================================================================= */ | ||||||||
136 | |||||||||
137 | /** | ||||||||
138 | This String class provides base functionality for C++ like Unicode | ||||||||
139 | character array handling. The advantage of this class is that it | ||||||||
140 | handles all the memory management for you - and it does it | ||||||||
141 | more efficiently. If you assign a string to another string, the | ||||||||
142 | data of both strings are shared (without any copy operation or | ||||||||
143 | memory allocation) as long as you do not change the string. This class | ||||||||
144 | also stores the length of the string, so that many operations are | ||||||||
145 | faster than the C-str-functions. | ||||||||
146 | |||||||||
147 | This class provides only readonly string handling. So you could create | ||||||||
148 | a string and you could only query the content from this string. | ||||||||
149 | It provides also functionality to change the string, but this results | ||||||||
150 | in every case in a new string instance (in the most cases with a | ||||||||
151 | memory allocation). You don't have functionality to change the | ||||||||
152 | content of the string. If you want to change the string content, then | ||||||||
153 | you should use the OStringBuffer class, which provides these | ||||||||
154 | functionalities and avoids too much memory allocation. | ||||||||
155 | |||||||||
156 | The design of this class is similar to the string classes in Java so | ||||||||
157 | less people should have understanding problems when they use this class. | ||||||||
158 | */ | ||||||||
159 | |||||||||
160 | class SAL_WARN_UNUSED__attribute__((warn_unused)) SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) OUString | ||||||||
161 | { | ||||||||
162 | public: | ||||||||
163 | /// @cond INTERNAL | ||||||||
164 | rtl_uString * pData; | ||||||||
165 | /// @endcond | ||||||||
166 | |||||||||
167 | /** | ||||||||
168 | New string containing no characters. | ||||||||
169 | */ | ||||||||
170 | OUString() | ||||||||
171 | { | ||||||||
172 | pData = NULL__null; | ||||||||
173 | rtl_uString_new( &pData ); | ||||||||
174 | } | ||||||||
175 | |||||||||
176 | /** | ||||||||
177 | New string from OUString. | ||||||||
178 | |||||||||
179 | @param str an OUString. | ||||||||
180 | */ | ||||||||
181 | OUString( const OUString & str ) | ||||||||
182 | { | ||||||||
183 | pData = str.pData; | ||||||||
184 | rtl_uString_acquire( pData ); | ||||||||
185 | } | ||||||||
186 | |||||||||
187 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
188 | /** | ||||||||
189 | Move constructor. | ||||||||
190 | |||||||||
191 | @param str an OUString. | ||||||||
192 | @since LibreOffice 5.2 | ||||||||
193 | */ | ||||||||
194 | OUString( OUString && str ) noexcept | ||||||||
195 | { | ||||||||
196 | pData = str.pData; | ||||||||
197 | str.pData = nullptr; | ||||||||
198 | rtl_uString_new( &str.pData ); | ||||||||
199 | } | ||||||||
200 | #endif | ||||||||
201 | |||||||||
202 | /** | ||||||||
203 | New string from OUString data. | ||||||||
204 | |||||||||
205 | @param str an OUString data. | ||||||||
206 | */ | ||||||||
207 | OUString( rtl_uString * str ) | ||||||||
208 | { | ||||||||
209 | pData = str; | ||||||||
210 | rtl_uString_acquire( pData ); | ||||||||
211 | } | ||||||||
212 | |||||||||
213 | /** New OUString from OUString data without acquiring it. Takeover of ownership. | ||||||||
214 | |||||||||
215 | The SAL_NO_ACQUIRE dummy parameter is only there to distinguish this | ||||||||
216 | from other constructors. | ||||||||
217 | |||||||||
218 | @param str | ||||||||
219 | OUString data | ||||||||
220 | */ | ||||||||
221 | OUString( rtl_uString * str, __sal_NoAcquire ) | ||||||||
222 | { pData = str; } | ||||||||
223 | |||||||||
224 | /** | ||||||||
225 | New string from a single Unicode character. | ||||||||
226 | |||||||||
227 | @param value a Unicode character. | ||||||||
228 | */ | ||||||||
229 | explicit OUString( sal_Unicode value ) | ||||||||
230 | : pData (NULL__null) | ||||||||
231 | { | ||||||||
232 | rtl_uString_newFromStr_WithLength( &pData, &value, 1 ); | ||||||||
233 | } | ||||||||
234 | |||||||||
235 | #if defined LIBO_INTERNAL_ONLY1 && !defined RTL_STRING_UNITTEST_CONCAT | ||||||||
236 | /// @cond INTERNAL | ||||||||
237 | // Catch inadvertent conversions to the above ctor (but still allow | ||||||||
238 | // construction from char literals): | ||||||||
239 | OUString(int) = delete; | ||||||||
240 | explicit OUString(char c): | ||||||||
241 | OUString(sal_Unicode(static_cast<unsigned char>(c))) | ||||||||
242 | {} | ||||||||
243 | /// @endcond | ||||||||
244 | #endif | ||||||||
245 | |||||||||
246 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
247 | |||||||||
248 | template<typename T> explicit OUString( | ||||||||
249 | T const & value, | ||||||||
250 | typename libreoffice_internal::CharPtrDetector<T, libreoffice_internal::Dummy>::TypeUtf16 | ||||||||
251 | = libreoffice_internal::Dummy()): | ||||||||
252 | pData(nullptr) | ||||||||
253 | { rtl_uString_newFromStr(&pData, value); } | ||||||||
254 | |||||||||
255 | template<typename T> explicit OUString( | ||||||||
256 | T & value, | ||||||||
257 | typename | ||||||||
258 | libreoffice_internal::NonConstCharArrayDetector<T, libreoffice_internal::Dummy>::TypeUtf16 | ||||||||
259 | = libreoffice_internal::Dummy()): | ||||||||
260 | pData(nullptr) | ||||||||
261 | { rtl_uString_newFromStr(&pData, value); } | ||||||||
262 | |||||||||
263 | #else | ||||||||
264 | |||||||||
265 | /** | ||||||||
266 | New string from a Unicode character buffer array. | ||||||||
267 | |||||||||
268 | @param value a NULL-terminated Unicode character array. | ||||||||
269 | */ | ||||||||
270 | OUString( const sal_Unicode * value ) | ||||||||
271 | { | ||||||||
272 | pData = NULL__null; | ||||||||
273 | rtl_uString_newFromStr( &pData, value ); | ||||||||
274 | } | ||||||||
275 | |||||||||
276 | #endif | ||||||||
277 | |||||||||
278 | /** | ||||||||
279 | New string from a Unicode character buffer array. | ||||||||
280 | |||||||||
281 | @param value a Unicode character array. | ||||||||
282 | @param length the number of character which should be copied. | ||||||||
283 | The character array length must be greater than | ||||||||
284 | or equal to this value. | ||||||||
285 | */ | ||||||||
286 | OUString( const sal_Unicode * value, sal_Int32 length ) | ||||||||
287 | { | ||||||||
288 | pData = NULL__null; | ||||||||
289 | rtl_uString_newFromStr_WithLength( &pData, value, length ); | ||||||||
290 | } | ||||||||
291 | |||||||||
292 | /** | ||||||||
293 | New string from an 8-Bit string literal that is expected to contain only | ||||||||
294 | characters in the ASCII set (i.e. first 128 characters). This constructor | ||||||||
295 | allows an efficient and convenient way to create OUString | ||||||||
296 | instances from ASCII literals. When creating strings from data that | ||||||||
297 | is not pure ASCII, it needs to be converted to OUString by explicitly | ||||||||
298 | providing the encoding to use for the conversion. | ||||||||
299 | |||||||||
300 | If there are any embedded \0's in the string literal, the result is undefined. | ||||||||
301 | Use the overload that explicitly accepts length. | ||||||||
302 | |||||||||
303 | @param literal the 8-bit ASCII string literal | ||||||||
304 | |||||||||
305 | @since LibreOffice 3.6 | ||||||||
306 | */ | ||||||||
307 | template< typename T > | ||||||||
308 | OUString( T& literal, typename libreoffice_internal::ConstCharArrayDetector< T, libreoffice_internal::Dummy >::Type = libreoffice_internal::Dummy() ) | ||||||||
309 | { | ||||||||
310 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 311, __extension__ __PRETTY_FUNCTION__)) | ||||||||
311 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 311, __extension__ __PRETTY_FUNCTION__)); | ||||||||
312 | pData = NULL__null; | ||||||||
313 | if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) { | ||||||||
314 | rtl_uString_new(&pData); | ||||||||
315 | } else { | ||||||||
316 | rtl_uString_newFromLiteral( | ||||||||
317 | &pData, | ||||||||
318 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
319 | literal), | ||||||||
320 | libreoffice_internal::ConstCharArrayDetector<T>::length, 0); | ||||||||
321 | } | ||||||||
322 | #ifdef RTL_STRING_UNITTEST | ||||||||
323 | rtl_string_unittest_const_literal = true; | ||||||||
324 | #endif | ||||||||
325 | } | ||||||||
326 | |||||||||
327 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
328 | /** @overload @since LibreOffice 5.3 */ | ||||||||
329 | template<typename T> OUString( | ||||||||
330 | T & literal, | ||||||||
331 | typename libreoffice_internal::ConstCharArrayDetector< | ||||||||
332 | T, libreoffice_internal::Dummy>::TypeUtf16 | ||||||||
333 | = libreoffice_internal::Dummy()): | ||||||||
334 | pData(nullptr) | ||||||||
335 | { | ||||||||
336 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 337, __extension__ __PRETTY_FUNCTION__)) | ||||||||
337 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 337, __extension__ __PRETTY_FUNCTION__)); | ||||||||
338 | if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) { | ||||||||
339 | rtl_uString_new(&pData); | ||||||||
340 | } else { | ||||||||
341 | rtl_uString_newFromStr_WithLength( | ||||||||
342 | &pData, | ||||||||
343 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
344 | literal), | ||||||||
345 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
346 | } | ||||||||
347 | } | ||||||||
348 | #endif | ||||||||
349 | |||||||||
350 | #if defined LIBO_INTERNAL_ONLY1 && defined RTL_STRING_UNITTEST | ||||||||
351 | /// @cond INTERNAL | ||||||||
352 | /** | ||||||||
353 | * Only used by unittests to detect incorrect conversions. | ||||||||
354 | * @internal | ||||||||
355 | */ | ||||||||
356 | template< typename T > | ||||||||
357 | OUString( T&, typename libreoffice_internal::ExceptConstCharArrayDetector< T >::Type = libreoffice_internal::Dummy() ) | ||||||||
358 | { | ||||||||
359 | pData = NULL__null; | ||||||||
360 | rtl_uString_newFromLiteral( &pData, "!!br0ken!!", 10, 0 ); // set to garbage | ||||||||
361 | rtl_string_unittest_invalid_conversion = true; | ||||||||
362 | } | ||||||||
363 | /** | ||||||||
364 | * Only used by unittests to detect incorrect conversions. | ||||||||
365 | * @internal | ||||||||
366 | */ | ||||||||
367 | template< typename T > | ||||||||
368 | OUString( const T&, typename libreoffice_internal::ExceptCharArrayDetector< T >::Type = libreoffice_internal::Dummy() ) | ||||||||
369 | { | ||||||||
370 | pData = NULL__null; | ||||||||
371 | rtl_uString_newFromLiteral( &pData, "!!br0ken!!", 10, 0 ); // set to garbage | ||||||||
372 | rtl_string_unittest_invalid_conversion = true; | ||||||||
373 | } | ||||||||
374 | /// @endcond | ||||||||
375 | #endif | ||||||||
376 | |||||||||
377 | #ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" | ||||||||
378 | /// @cond INTERNAL | ||||||||
379 | /** | ||||||||
380 | New string from a string literal. | ||||||||
381 | |||||||||
382 | @since LibreOffice 5.0 | ||||||||
383 | */ | ||||||||
384 | template<std::size_t N> OUString(OUStringLiteral<N> const & literal): | ||||||||
385 | pData(const_cast<rtl_uString *>(reinterpret_cast<rtl_uString const *>(&literal))) {} | ||||||||
386 | template<std::size_t N> OUString(OUStringLiteral<N> &&) = delete; | ||||||||
387 | /// @endcond | ||||||||
388 | #endif | ||||||||
389 | |||||||||
390 | /** | ||||||||
391 | New string from an 8-Bit character buffer array. | ||||||||
392 | |||||||||
393 | @param value An 8-Bit character array. | ||||||||
394 | @param length The number of character which should be converted. | ||||||||
395 | The 8-Bit character array length must be | ||||||||
396 | greater than or equal to this value. | ||||||||
397 | @param encoding The text encoding from which the 8-Bit character | ||||||||
398 | sequence should be converted. | ||||||||
399 | @param convertFlags Flags which control the conversion. | ||||||||
400 | see RTL_TEXTTOUNICODE_FLAGS_... | ||||||||
401 | |||||||||
402 | @exception std::bad_alloc is thrown if an out-of-memory condition occurs | ||||||||
403 | */ | ||||||||
404 | OUString( const char * value, sal_Int32 length, | ||||||||
405 | rtl_TextEncoding encoding, | ||||||||
406 | sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300 )) ) | ||||||||
407 | { | ||||||||
408 | pData = NULL__null; | ||||||||
409 | rtl_string2UString( &pData, value, length, encoding, convertFlags ); | ||||||||
410 | if (pData == NULL__null) { | ||||||||
411 | throw std::bad_alloc(); | ||||||||
412 | } | ||||||||
413 | } | ||||||||
414 | |||||||||
415 | /** Create a new string from an array of Unicode code points. | ||||||||
416 | |||||||||
417 | @param codePoints | ||||||||
418 | an array of at least codePointCount code points, which each must be in | ||||||||
419 | the range from 0 to 0x10FFFF, inclusive. May be null if codePointCount | ||||||||
420 | is zero. | ||||||||
421 | |||||||||
422 | @param codePointCount | ||||||||
423 | the non-negative number of code points. | ||||||||
424 | |||||||||
425 | @exception std::bad_alloc | ||||||||
426 | is thrown if either an out-of-memory condition occurs or the resulting | ||||||||
427 | number of UTF-16 code units would have been larger than SAL_MAX_INT32. | ||||||||
428 | |||||||||
429 | @since UDK 3.2.7 | ||||||||
430 | */ | ||||||||
431 | explicit OUString( | ||||||||
432 | sal_uInt32 const * codePoints, sal_Int32 codePointCount): | ||||||||
433 | pData(NULL__null) | ||||||||
434 | { | ||||||||
435 | rtl_uString_newFromCodePoints(&pData, codePoints, codePointCount); | ||||||||
436 | if (pData == NULL__null) { | ||||||||
437 | throw std::bad_alloc(); | ||||||||
438 | } | ||||||||
439 | } | ||||||||
440 | |||||||||
441 | #ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" | ||||||||
442 | /** | ||||||||
443 | @overload | ||||||||
444 | @internal | ||||||||
445 | */ | ||||||||
446 | template< typename T1, typename T2 > | ||||||||
447 | OUString( OUStringConcat< T1, T2 >&& c ) | ||||||||
448 | { | ||||||||
449 | const sal_Int32 l = c.length(); | ||||||||
450 | pData = rtl_uString_alloc( l ); | ||||||||
451 | if (l != 0) | ||||||||
452 | { | ||||||||
453 | sal_Unicode* end = c.addData( pData->buffer ); | ||||||||
454 | pData->length = l; | ||||||||
455 | *end = '\0'; | ||||||||
456 | // TODO realloc in case pData->length is noticeably smaller than l? | ||||||||
457 | } | ||||||||
458 | } | ||||||||
459 | |||||||||
460 | /** | ||||||||
461 | @overload | ||||||||
462 | @internal | ||||||||
463 | */ | ||||||||
464 | template< typename T > | ||||||||
465 | OUString( OUStringNumber< T >&& n ) | ||||||||
466 | : OUString( n.buf, n.length ) | ||||||||
467 | {} | ||||||||
468 | #endif | ||||||||
469 | |||||||||
470 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
471 | OUString(std::u16string_view sv) { | ||||||||
472 | if (sv.size() > sal_uInt32(std::numeric_limits<sal_Int32>::max())) { | ||||||||
473 | throw std::bad_alloc(); | ||||||||
474 | } | ||||||||
475 | pData = nullptr; | ||||||||
476 | rtl_uString_newFromStr_WithLength(&pData, sv.data(), sv.size()); | ||||||||
477 | } | ||||||||
478 | #endif | ||||||||
479 | |||||||||
480 | /** | ||||||||
481 | Release the string data. | ||||||||
482 | */ | ||||||||
483 | ~OUString() | ||||||||
484 | { | ||||||||
485 | rtl_uString_release( pData ); | ||||||||
486 | } | ||||||||
487 | |||||||||
488 | /** Provides an OUString const & passing a storage pointer of an | ||||||||
489 | rtl_uString * handle. | ||||||||
490 | It is more convenient to use C++ OUString member functions when dealing | ||||||||
491 | with rtl_uString * handles. Using this function avoids unnecessary | ||||||||
492 | acquire()/release() calls for a temporary OUString object. | ||||||||
493 | |||||||||
494 | @param ppHandle | ||||||||
495 | pointer to storage | ||||||||
496 | @return | ||||||||
497 | OUString const & based on given storage | ||||||||
498 | */ | ||||||||
499 | static OUString const & unacquired( rtl_uString * const * ppHandle ) | ||||||||
500 | { return * reinterpret_cast< OUString const * >( ppHandle ); } | ||||||||
501 | |||||||||
502 | /** | ||||||||
503 | Assign a new string. | ||||||||
504 | |||||||||
505 | @param str an OUString. | ||||||||
506 | */ | ||||||||
507 | OUString & operator=( const OUString & str ) | ||||||||
508 | { | ||||||||
509 | rtl_uString_assign( &pData, str.pData ); | ||||||||
510 | return *this; | ||||||||
511 | } | ||||||||
512 | |||||||||
513 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
514 | /** | ||||||||
515 | Move assign a new string. | ||||||||
516 | |||||||||
517 | @param str an OUString. | ||||||||
518 | @since LibreOffice 5.2 | ||||||||
519 | */ | ||||||||
520 | OUString & operator=( OUString && str ) noexcept | ||||||||
521 | { | ||||||||
522 | rtl_uString_release( pData ); | ||||||||
523 | pData = str.pData; | ||||||||
524 | str.pData = nullptr; | ||||||||
525 | rtl_uString_new( &str.pData ); | ||||||||
526 | return *this; | ||||||||
527 | } | ||||||||
528 | #endif | ||||||||
529 | |||||||||
530 | /** | ||||||||
531 | Assign a new string from an 8-Bit string literal that is expected to contain only | ||||||||
532 | characters in the ASCII set (i.e. first 128 characters). This operator | ||||||||
533 | allows an efficient and convenient way to assign OUString | ||||||||
534 | instances from ASCII literals. When assigning strings from data that | ||||||||
535 | is not pure ASCII, it needs to be converted to OUString by explicitly | ||||||||
536 | providing the encoding to use for the conversion. | ||||||||
537 | |||||||||
538 | @param literal the 8-bit ASCII string literal | ||||||||
539 | |||||||||
540 | @since LibreOffice 3.6 | ||||||||
541 | */ | ||||||||
542 | template< typename T > | ||||||||
543 | typename libreoffice_internal::ConstCharArrayDetector< T, OUString& >::Type operator=( T& literal ) | ||||||||
544 | { | ||||||||
545 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 546, __extension__ __PRETTY_FUNCTION__)) | ||||||||
546 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 546, __extension__ __PRETTY_FUNCTION__)); | ||||||||
547 | if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) { | ||||||||
548 | rtl_uString_new(&pData); | ||||||||
549 | } else { | ||||||||
550 | rtl_uString_newFromLiteral( | ||||||||
551 | &pData, | ||||||||
552 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
553 | literal), | ||||||||
554 | libreoffice_internal::ConstCharArrayDetector<T>::length, 0); | ||||||||
555 | } | ||||||||
556 | return *this; | ||||||||
557 | } | ||||||||
558 | |||||||||
559 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
560 | /** @overload @since LibreOffice 5.3 */ | ||||||||
561 | template<typename T> | ||||||||
562 | typename | ||||||||
563 | libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16 | ||||||||
564 | operator =(T & literal) { | ||||||||
565 | if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) { | ||||||||
566 | rtl_uString_new(&pData); | ||||||||
567 | } else { | ||||||||
568 | rtl_uString_newFromStr_WithLength( | ||||||||
569 | &pData, | ||||||||
570 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
571 | literal), | ||||||||
572 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
573 | } | ||||||||
574 | return *this; | ||||||||
575 | } | ||||||||
576 | |||||||||
577 | /** @overload @since LibreOffice 5.4 */ | ||||||||
578 | template<std::size_t N> OUString & operator =(OUStringLiteral<N> const & literal) { | ||||||||
579 | if (literal.getLength() == 0) { | ||||||||
580 | rtl_uString_new(&pData); | ||||||||
581 | } else { | ||||||||
582 | rtl_uString_newFromStr_WithLength(&pData, literal.getStr(), literal.getLength()); | ||||||||
583 | } | ||||||||
584 | return *this; | ||||||||
585 | } | ||||||||
586 | |||||||||
587 | template<typename T> | ||||||||
588 | OUString & operator =(OUStringNumber<T> && n) { | ||||||||
589 | // n.length should never be zero, so no need to add an optimization for that case | ||||||||
590 | rtl_uString_newFromStr_WithLength(&pData, n.buf, n.length); | ||||||||
591 | return *this; | ||||||||
592 | } | ||||||||
593 | |||||||||
594 | OUString & operator =(std::u16string_view sv) { | ||||||||
595 | if (sv.empty()) { | ||||||||
596 | rtl_uString_new(&pData); | ||||||||
597 | } else { | ||||||||
598 | rtl_uString_newFromStr_WithLength(&pData, sv.data(), sv.size()); | ||||||||
599 | } | ||||||||
600 | return *this; | ||||||||
601 | } | ||||||||
602 | #endif | ||||||||
603 | |||||||||
604 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
605 | /** | ||||||||
606 | Append the contents of an OUStringBuffer to this string. | ||||||||
607 | |||||||||
608 | @param str an OUStringBuffer. | ||||||||
609 | |||||||||
610 | @exception std::bad_alloc is thrown if an out-of-memory condition occurs | ||||||||
611 | @since LibreOffice 6.2 | ||||||||
612 | */ | ||||||||
613 | inline OUString & operator+=( const OUStringBuffer & str ) &; | ||||||||
614 | #endif | ||||||||
615 | |||||||||
616 | /** | ||||||||
617 | Append a string to this string. | ||||||||
618 | |||||||||
619 | @param str an OUString. | ||||||||
620 | |||||||||
621 | @exception std::bad_alloc is thrown if an out-of-memory condition occurs | ||||||||
622 | */ | ||||||||
623 | OUString & operator+=( const OUString & str ) | ||||||||
624 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
625 | & | ||||||||
626 | #endif | ||||||||
627 | { | ||||||||
628 | return internalAppend(str.pData); | ||||||||
629 | } | ||||||||
630 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
631 | void operator+=(OUString const &) && = delete; | ||||||||
632 | #endif | ||||||||
633 | |||||||||
634 | /** Append an ASCII string literal to this string. | ||||||||
635 | |||||||||
636 | @param literal an 8-bit ASCII-only string literal | ||||||||
637 | |||||||||
638 | @since LibreOffice 5.1 | ||||||||
639 | */ | ||||||||
640 | template<typename T> | ||||||||
641 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString &>::Type | ||||||||
642 | operator +=(T & literal) | ||||||||
643 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
644 | & | ||||||||
645 | #endif | ||||||||
646 | { | ||||||||
647 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 648, __extension__ __PRETTY_FUNCTION__)) | ||||||||
648 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 648, __extension__ __PRETTY_FUNCTION__)); | ||||||||
649 | rtl_uString_newConcatAsciiL( | ||||||||
650 | &pData, pData, | ||||||||
651 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), | ||||||||
652 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
653 | return *this; | ||||||||
654 | } | ||||||||
655 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
656 | template<typename T> | ||||||||
657 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString &>::Type | ||||||||
658 | operator +=(T &) && = delete; | ||||||||
659 | #endif | ||||||||
660 | |||||||||
661 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
662 | /** @overload @since LibreOffice 5.3 */ | ||||||||
663 | template<typename T> | ||||||||
664 | typename | ||||||||
665 | libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16 | ||||||||
666 | operator +=(T & literal) & { | ||||||||
667 | rtl_uString_newConcatUtf16L( | ||||||||
668 | &pData, pData, | ||||||||
669 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), | ||||||||
670 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
671 | return *this; | ||||||||
672 | } | ||||||||
673 | template<typename T> | ||||||||
674 | typename | ||||||||
675 | libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16 | ||||||||
676 | operator +=(T &) && = delete; | ||||||||
677 | |||||||||
678 | /** @overload @since LibreOffice 5.4 */ | ||||||||
679 | template<std::size_t N> OUString & operator +=(OUStringLiteral<N> const & literal) & { | ||||||||
680 | rtl_uString_newConcatUtf16L(&pData, pData, literal.getStr(), literal.getLength()); | ||||||||
681 | return *this; | ||||||||
682 | } | ||||||||
683 | template<std::size_t N> void operator +=(OUStringLiteral<N> const &) && = delete; | ||||||||
684 | |||||||||
685 | OUString & operator +=(std::u16string_view sv) & { | ||||||||
686 | if (sv.size() > sal_uInt32(std::numeric_limits<sal_Int32>::max())) { | ||||||||
687 | throw std::bad_alloc(); | ||||||||
688 | } | ||||||||
689 | rtl_uString_newConcatUtf16L(&pData, pData, sv.data(), sv.size()); | ||||||||
690 | return *this; | ||||||||
691 | } | ||||||||
692 | void operator +=(std::u16string_view) && = delete; | ||||||||
693 | #endif | ||||||||
694 | |||||||||
695 | #ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" | ||||||||
696 | /** | ||||||||
697 | @overload | ||||||||
698 | @internal | ||||||||
699 | */ | ||||||||
700 | template< typename T1, typename T2 > | ||||||||
701 | OUString& operator+=( OUStringConcat< T1, T2 >&& c ) & { | ||||||||
702 | sal_Int32 l = c.length(); | ||||||||
703 | if( l == 0 ) | ||||||||
704 | return *this; | ||||||||
705 | l += pData->length; | ||||||||
706 | rtl_uString_ensureCapacity( &pData, l ); | ||||||||
707 | sal_Unicode* end = c.addData( pData->buffer + pData->length ); | ||||||||
708 | *end = '\0'; | ||||||||
709 | pData->length = l; | ||||||||
710 | return *this; | ||||||||
711 | } | ||||||||
712 | template<typename T1, typename T2> void operator +=( | ||||||||
713 | OUStringConcat<T1, T2> &&) && = delete; | ||||||||
714 | |||||||||
715 | /** | ||||||||
716 | @overload | ||||||||
717 | @internal | ||||||||
718 | */ | ||||||||
719 | template< typename T > | ||||||||
720 | OUString& operator+=( OUStringNumber< T >&& n ) & { | ||||||||
721 | sal_Int32 l = n.length; | ||||||||
722 | if( l == 0 ) | ||||||||
723 | return *this; | ||||||||
724 | l += pData->length; | ||||||||
725 | rtl_uString_ensureCapacity( &pData, l ); | ||||||||
726 | sal_Unicode* end = addDataHelper( pData->buffer + pData->length, n.buf, n.length ); | ||||||||
727 | *end = '\0'; | ||||||||
728 | pData->length = l; | ||||||||
729 | return *this; | ||||||||
730 | } | ||||||||
731 | template<typename T> void operator +=( | ||||||||
732 | OUStringNumber<T> &&) && = delete; | ||||||||
733 | #endif | ||||||||
734 | |||||||||
735 | /** | ||||||||
736 | Clears the string, i.e, makes a zero-character string | ||||||||
737 | @since LibreOffice 4.4 | ||||||||
738 | */ | ||||||||
739 | void clear() | ||||||||
740 | { | ||||||||
741 | rtl_uString_new( &pData ); | ||||||||
742 | } | ||||||||
743 | |||||||||
744 | /** | ||||||||
745 | Returns the length of this string. | ||||||||
746 | |||||||||
747 | The length is equal to the number of Unicode characters in this string. | ||||||||
748 | |||||||||
749 | @return the length of the sequence of characters represented by this | ||||||||
750 | object. | ||||||||
751 | */ | ||||||||
752 | sal_Int32 getLength() const { return pData->length; } | ||||||||
753 | |||||||||
754 | /** | ||||||||
755 | Checks if a string is empty. | ||||||||
756 | |||||||||
757 | @return true if the string is empty; | ||||||||
758 | false, otherwise. | ||||||||
759 | |||||||||
760 | @since LibreOffice 3.4 | ||||||||
761 | */ | ||||||||
762 | bool isEmpty() const | ||||||||
763 | { | ||||||||
764 | return pData->length == 0; | ||||||||
765 | } | ||||||||
766 | |||||||||
767 | /** | ||||||||
768 | Returns a pointer to the Unicode character buffer for this string. | ||||||||
769 | |||||||||
770 | It isn't necessarily NULL terminated. | ||||||||
771 | |||||||||
772 | @return a pointer to the Unicode characters buffer for this object. | ||||||||
773 | */ | ||||||||
774 | const sal_Unicode * getStr() const SAL_RETURNS_NONNULL__attribute__((returns_nonnull)) { return pData->buffer; } | ||||||||
775 | |||||||||
776 | /** | ||||||||
777 | Access to individual characters. | ||||||||
778 | |||||||||
779 | @param index must be non-negative and less than length. | ||||||||
780 | |||||||||
781 | @return the character at the given index. | ||||||||
782 | |||||||||
783 | @since LibreOffice 3.5 | ||||||||
784 | */ | ||||||||
785 | sal_Unicode operator [](sal_Int32 index) const { | ||||||||
786 | // silence spurious -Werror=strict-overflow warnings from GCC 4.8.2 | ||||||||
787 | assert(index >= 0 && static_cast<sal_uInt32>(index) < static_cast<sal_uInt32>(getLength()))(static_cast <bool> (index >= 0 && static_cast <sal_uInt32>(index) < static_cast<sal_uInt32>( getLength())) ? void (0) : __assert_fail ("index >= 0 && static_cast<sal_uInt32>(index) < static_cast<sal_uInt32>(getLength())" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 787, __extension__ __PRETTY_FUNCTION__)); | ||||||||
788 | return getStr()[index]; | ||||||||
789 | } | ||||||||
790 | |||||||||
791 | /** | ||||||||
792 | Compares two strings. | ||||||||
793 | |||||||||
794 | The comparison is based on the numeric value of each character in | ||||||||
795 | the strings and return a value indicating their relationship. | ||||||||
796 | This function can't be used for language specific sorting. | ||||||||
797 | |||||||||
798 | @param str the object to be compared. | ||||||||
799 | @return 0 - if both strings are equal | ||||||||
800 | < 0 - if this string is less than the string argument | ||||||||
801 | > 0 - if this string is greater than the string argument | ||||||||
802 | */ | ||||||||
803 | sal_Int32 compareTo( const OUString & str ) const | ||||||||
804 | { | ||||||||
805 | return rtl_ustr_compare_WithLength( pData->buffer, pData->length, | ||||||||
806 | str.pData->buffer, str.pData->length ); | ||||||||
807 | } | ||||||||
808 | |||||||||
809 | /** | ||||||||
810 | Compares two strings with a maximum count of characters. | ||||||||
811 | |||||||||
812 | The comparison is based on the numeric value of each character in | ||||||||
813 | the strings and return a value indicating their relationship. | ||||||||
814 | This function can't be used for language specific sorting. | ||||||||
815 | |||||||||
816 | @param str the object to be compared. | ||||||||
817 | @param maxLength the maximum count of characters to be compared. | ||||||||
818 | @return 0 - if both strings are equal | ||||||||
819 | < 0 - if this string is less than the string argument | ||||||||
820 | > 0 - if this string is greater than the string argument | ||||||||
821 | |||||||||
822 | @since UDK 3.2.7 | ||||||||
823 | */ | ||||||||
824 | sal_Int32 compareTo( const OUString & str, sal_Int32 maxLength ) const | ||||||||
825 | { | ||||||||
826 | return rtl_ustr_shortenedCompare_WithLength( pData->buffer, pData->length, | ||||||||
827 | str.pData->buffer, str.pData->length, maxLength ); | ||||||||
828 | } | ||||||||
829 | |||||||||
830 | /** | ||||||||
831 | Compares two strings in reverse order. | ||||||||
832 | |||||||||
833 | The comparison is based on the numeric value of each character in | ||||||||
834 | the strings and return a value indicating their relationship. | ||||||||
835 | This function can't be used for language specific sorting. | ||||||||
836 | |||||||||
837 | @param str the object to be compared. | ||||||||
838 | @return 0 - if both strings are equal | ||||||||
839 | < 0 - if this string is less than the string argument | ||||||||
840 | > 0 - if this string is greater than the string argument | ||||||||
841 | */ | ||||||||
842 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
843 | sal_Int32 reverseCompareTo(std::u16string_view sv) const { | ||||||||
844 | return rtl_ustr_reverseCompare_WithLength( | ||||||||
845 | pData->buffer, pData->length, sv.data(), sv.size()); | ||||||||
846 | } | ||||||||
847 | #else | ||||||||
848 | sal_Int32 reverseCompareTo( const OUString & str ) const | ||||||||
849 | { | ||||||||
850 | return rtl_ustr_reverseCompare_WithLength( pData->buffer, pData->length, | ||||||||
851 | str.pData->buffer, str.pData->length ); | ||||||||
852 | } | ||||||||
853 | #endif | ||||||||
854 | |||||||||
855 | /** | ||||||||
856 | @overload | ||||||||
857 | This function accepts an ASCII string literal as its argument. | ||||||||
858 | @since LibreOffice 4.1 | ||||||||
859 | */ | ||||||||
860 | template< typename T > | ||||||||
861 | typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type reverseCompareTo( T& literal ) const | ||||||||
862 | { | ||||||||
863 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 864, __extension__ __PRETTY_FUNCTION__)) | ||||||||
864 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 864, __extension__ __PRETTY_FUNCTION__)); | ||||||||
865 | return rtl_ustr_asciil_reverseCompare_WithLength( | ||||||||
866 | pData->buffer, pData->length, | ||||||||
867 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), | ||||||||
868 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
869 | } | ||||||||
870 | |||||||||
871 | /** | ||||||||
872 | Perform a comparison of two strings. | ||||||||
873 | |||||||||
874 | The result is true if and only if second string | ||||||||
875 | represents the same sequence of characters as the first string. | ||||||||
876 | This function can't be used for language specific comparison. | ||||||||
877 | |||||||||
878 | @param str the object to be compared. | ||||||||
879 | @return true if the strings are equal; | ||||||||
880 | false, otherwise. | ||||||||
881 | */ | ||||||||
882 | bool equals( const OUString & str ) const | ||||||||
883 | { | ||||||||
884 | if ( pData->length != str.pData->length ) | ||||||||
885 | return false; | ||||||||
886 | if ( pData == str.pData ) | ||||||||
887 | return true; | ||||||||
888 | return rtl_ustr_reverseCompare_WithLength( pData->buffer, pData->length, | ||||||||
889 | str.pData->buffer, str.pData->length ) == 0; | ||||||||
890 | } | ||||||||
891 | |||||||||
892 | /** | ||||||||
893 | Perform an ASCII lowercase comparison of two strings. | ||||||||
894 | |||||||||
895 | The result is true if and only if second string | ||||||||
896 | represents the same sequence of characters as the first string, | ||||||||
897 | ignoring the case. | ||||||||
898 | Character values between 65 and 90 (ASCII A-Z) are interpreted as | ||||||||
899 | values between 97 and 122 (ASCII a-z). | ||||||||
900 | This function can't be used for language specific comparison. | ||||||||
901 | |||||||||
902 | @param str the object to be compared. | ||||||||
903 | @return true if the strings are equal; | ||||||||
904 | false, otherwise. | ||||||||
905 | */ | ||||||||
906 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
907 | bool equalsIgnoreAsciiCase(std::u16string_view sv) const { | ||||||||
908 | return | ||||||||
909 | rtl_ustr_compareIgnoreAsciiCase_WithLength( | ||||||||
910 | pData->buffer, pData->length, sv.data(), sv.size()) | ||||||||
911 | == 0; | ||||||||
912 | } | ||||||||
913 | #else | ||||||||
914 | bool equalsIgnoreAsciiCase( const OUString & str ) const | ||||||||
915 | { | ||||||||
916 | if ( pData->length != str.pData->length ) | ||||||||
917 | return false; | ||||||||
918 | if ( pData == str.pData ) | ||||||||
919 | return true; | ||||||||
920 | return rtl_ustr_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, | ||||||||
921 | str.pData->buffer, str.pData->length ) == 0; | ||||||||
922 | } | ||||||||
923 | #endif | ||||||||
924 | |||||||||
925 | /** | ||||||||
926 | Perform an ASCII lowercase comparison of two strings. | ||||||||
927 | |||||||||
928 | Compare the two strings with uppercase ASCII | ||||||||
929 | character values between 65 and 90 (ASCII A-Z) interpreted as | ||||||||
930 | values between 97 and 122 (ASCII a-z). | ||||||||
931 | This function can't be used for language specific comparison. | ||||||||
932 | |||||||||
933 | @param str the object to be compared. | ||||||||
934 | @return 0 - if both strings are equal | ||||||||
935 | < 0 - if this string is less than the string argument | ||||||||
936 | > 0 - if this string is greater than the string argument | ||||||||
937 | |||||||||
938 | @since LibreOffice 4.0 | ||||||||
939 | */ | ||||||||
940 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
941 | sal_Int32 compareToIgnoreAsciiCase(std::u16string_view sv) const { | ||||||||
942 | return rtl_ustr_compareIgnoreAsciiCase_WithLength( | ||||||||
943 | pData->buffer, pData->length, sv.data(), sv.size()); | ||||||||
944 | } | ||||||||
945 | #else | ||||||||
946 | sal_Int32 compareToIgnoreAsciiCase( const OUString & str ) const | ||||||||
947 | { | ||||||||
948 | return rtl_ustr_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, | ||||||||
949 | str.pData->buffer, str.pData->length ); | ||||||||
950 | } | ||||||||
951 | #endif | ||||||||
952 | |||||||||
953 | /** | ||||||||
954 | @overload | ||||||||
955 | This function accepts an ASCII string literal as its argument. | ||||||||
956 | @since LibreOffice 3.6 | ||||||||
957 | */ | ||||||||
958 | template< typename T > | ||||||||
959 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type equalsIgnoreAsciiCase( T& literal ) const | ||||||||
960 | { | ||||||||
961 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 962, __extension__ __PRETTY_FUNCTION__)) | ||||||||
962 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 962, __extension__ __PRETTY_FUNCTION__)); | ||||||||
963 | return | ||||||||
964 | (pData->length | ||||||||
965 | == libreoffice_internal::ConstCharArrayDetector<T>::length) | ||||||||
966 | && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( | ||||||||
967 | pData->buffer, pData->length, | ||||||||
968 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
969 | literal)) | ||||||||
970 | == 0); | ||||||||
971 | } | ||||||||
972 | |||||||||
973 | /** | ||||||||
974 | Match against a substring appearing in this string. | ||||||||
975 | |||||||||
976 | The result is true if and only if the second string appears as a substring | ||||||||
977 | of this string, at the given position. | ||||||||
978 | This function can't be used for language specific comparison. | ||||||||
979 | |||||||||
980 | @param str the object (substring) to be compared. | ||||||||
981 | @param fromIndex the index to start the comparison from. | ||||||||
982 | The index must be greater than or equal to 0 | ||||||||
983 | and less or equal as the string length. | ||||||||
984 | @return true if str match with the characters in the string | ||||||||
985 | at the given position; | ||||||||
986 | false, otherwise. | ||||||||
987 | */ | ||||||||
988 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
989 | bool match(std::u16string_view sv, sal_Int32 fromIndex = 0) const { | ||||||||
990 | return | ||||||||
991 | rtl_ustr_shortenedCompare_WithLength( | ||||||||
992 | pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size(), | ||||||||
993 | sv.size()) | ||||||||
994 | == 0; | ||||||||
995 | } | ||||||||
996 | #else | ||||||||
997 | bool match( const OUString & str, sal_Int32 fromIndex = 0 ) const | ||||||||
998 | { | ||||||||
999 | return rtl_ustr_shortenedCompare_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, | ||||||||
1000 | str.pData->buffer, str.pData->length, str.pData->length ) == 0; | ||||||||
1001 | } | ||||||||
1002 | #endif | ||||||||
1003 | |||||||||
1004 | /** | ||||||||
1005 | @overload | ||||||||
1006 | This function accepts an ASCII string literal as its argument. | ||||||||
1007 | @since LibreOffice 3.6 | ||||||||
1008 | */ | ||||||||
1009 | template< typename T > | ||||||||
1010 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type match( T& literal, sal_Int32 fromIndex = 0 ) const | ||||||||
1011 | { | ||||||||
1012 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1013, __extension__ __PRETTY_FUNCTION__)) | ||||||||
1013 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1013, __extension__ __PRETTY_FUNCTION__)); | ||||||||
1014 | return | ||||||||
1015 | rtl_ustr_ascii_shortenedCompare_WithLength( | ||||||||
1016 | pData->buffer+fromIndex, pData->length-fromIndex, | ||||||||
1017 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
1018 | literal), | ||||||||
1019 | libreoffice_internal::ConstCharArrayDetector<T>::length) | ||||||||
1020 | == 0; | ||||||||
1021 | } | ||||||||
1022 | |||||||||
1023 | /** | ||||||||
1024 | Match against a substring appearing in this string, ignoring the case of | ||||||||
1025 | ASCII letters. | ||||||||
1026 | |||||||||
1027 | The result is true if and only if the second string appears as a substring | ||||||||
1028 | of this string, at the given position. | ||||||||
1029 | Character values between 65 and 90 (ASCII A-Z) are interpreted as | ||||||||
1030 | values between 97 and 122 (ASCII a-z). | ||||||||
1031 | This function can't be used for language specific comparison. | ||||||||
1032 | |||||||||
1033 | @param str the object (substring) to be compared. | ||||||||
1034 | @param fromIndex the index to start the comparison from. | ||||||||
1035 | The index must be greater than or equal to 0 | ||||||||
1036 | and less than or equal to the string length. | ||||||||
1037 | @return true if str match with the characters in the string | ||||||||
1038 | at the given position; | ||||||||
1039 | false, otherwise. | ||||||||
1040 | */ | ||||||||
1041 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
1042 | bool matchIgnoreAsciiCase(std::u16string_view sv, sal_Int32 fromIndex = 0) const { | ||||||||
1043 | return | ||||||||
1044 | rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( | ||||||||
1045 | pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size(), | ||||||||
1046 | sv.size()) | ||||||||
1047 | == 0; | ||||||||
1048 | } | ||||||||
1049 | #else | ||||||||
1050 | bool matchIgnoreAsciiCase( const OUString & str, sal_Int32 fromIndex = 0 ) const | ||||||||
1051 | { | ||||||||
1052 | return rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, | ||||||||
1053 | str.pData->buffer, str.pData->length, | ||||||||
1054 | str.pData->length ) == 0; | ||||||||
1055 | } | ||||||||
1056 | #endif | ||||||||
1057 | |||||||||
1058 | /** | ||||||||
1059 | @overload | ||||||||
1060 | This function accepts an ASCII string literal as its argument. | ||||||||
1061 | @since LibreOffice 3.6 | ||||||||
1062 | */ | ||||||||
1063 | template< typename T > | ||||||||
1064 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type matchIgnoreAsciiCase( T& literal, sal_Int32 fromIndex = 0 ) const | ||||||||
1065 | { | ||||||||
1066 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1067, __extension__ __PRETTY_FUNCTION__)) | ||||||||
1067 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1067, __extension__ __PRETTY_FUNCTION__)); | ||||||||
1068 | return | ||||||||
1069 | rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( | ||||||||
1070 | pData->buffer+fromIndex, pData->length-fromIndex, | ||||||||
1071 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
1072 | literal), | ||||||||
1073 | libreoffice_internal::ConstCharArrayDetector<T>::length) | ||||||||
1074 | == 0; | ||||||||
1075 | } | ||||||||
1076 | |||||||||
1077 | /** | ||||||||
1078 | Compares two strings. | ||||||||
1079 | |||||||||
1080 | The comparison is based on the numeric value of each character in | ||||||||
1081 | the strings and return a value indicating their relationship. | ||||||||
1082 | Since this method is optimized for performance, the ASCII character | ||||||||
1083 | values are not converted in any way. The caller has to make sure that | ||||||||
1084 | all ASCII characters are in the allowed range between 0 and 127. | ||||||||
1085 | The ASCII string must be NULL-terminated. | ||||||||
1086 | This function can't be used for language specific sorting. | ||||||||
1087 | |||||||||
1088 | @param asciiStr the 8-Bit ASCII character string to be compared. | ||||||||
1089 | @return 0 - if both strings are equal | ||||||||
1090 | < 0 - if this string is less than the string argument | ||||||||
1091 | > 0 - if this string is greater than the string argument | ||||||||
1092 | */ | ||||||||
1093 | sal_Int32 compareToAscii( const char* asciiStr ) const | ||||||||
1094 | { | ||||||||
1095 | return rtl_ustr_ascii_compare_WithLength( pData->buffer, pData->length, asciiStr ); | ||||||||
1096 | } | ||||||||
1097 | |||||||||
1098 | /** | ||||||||
1099 | Compares two strings with a maximum count of characters. | ||||||||
1100 | |||||||||
1101 | The comparison is based on the numeric value of each character in | ||||||||
1102 | the strings and return a value indicating their relationship. | ||||||||
1103 | Since this method is optimized for performance, the ASCII character | ||||||||
1104 | values are not converted in any way. The caller has to make sure that | ||||||||
1105 | all ASCII characters are in the allowed range between 0 and 127. | ||||||||
1106 | The ASCII string must be NULL-terminated. | ||||||||
1107 | This function can't be used for language specific sorting. | ||||||||
1108 | |||||||||
1109 | @deprecated This is a confusing overload with unexpectedly different | ||||||||
1110 | semantics from the one-parameter form, so it is marked as deprecated. | ||||||||
1111 | Practically all uses compare the return value against zero and can thus | ||||||||
1112 | be replaced with uses of startsWith. | ||||||||
1113 | |||||||||
1114 | @param asciiStr the 8-Bit ASCII character string to be compared. | ||||||||
1115 | @param maxLength the maximum count of characters to be compared. | ||||||||
1116 | @return 0 - if both strings are equal | ||||||||
1117 | < 0 - if this string is less than the string argument | ||||||||
1118 | > 0 - if this string is greater than the string argument | ||||||||
1119 | */ | ||||||||
1120 | SAL_DEPRECATED(__attribute__((deprecated("replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)" ))) | ||||||||
1121 | "replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)")__attribute__((deprecated("replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)" ))) | ||||||||
1122 | sal_Int32 compareToAscii( const char * asciiStr, sal_Int32 maxLength ) const | ||||||||
1123 | { | ||||||||
1124 | return rtl_ustr_ascii_shortenedCompare_WithLength( pData->buffer, pData->length, | ||||||||
1125 | asciiStr, maxLength ); | ||||||||
1126 | } | ||||||||
1127 | |||||||||
1128 | /** | ||||||||
1129 | Compares two strings in reverse order. | ||||||||
1130 | |||||||||
1131 | This could be useful, if normally both strings start with the same | ||||||||
1132 | content. The comparison is based on the numeric value of each character | ||||||||
1133 | in the strings and return a value indicating their relationship. | ||||||||
1134 | Since this method is optimized for performance, the ASCII character | ||||||||
1135 | values are not converted in any way. The caller has to make sure that | ||||||||
1136 | all ASCII characters are in the allowed range between 0 and 127. | ||||||||
1137 | The ASCII string must be NULL-terminated and must be greater than | ||||||||
1138 | or equal to asciiStrLength. | ||||||||
1139 | This function can't be used for language specific sorting. | ||||||||
1140 | |||||||||
1141 | @param asciiStr the 8-Bit ASCII character string to be compared. | ||||||||
1142 | @param asciiStrLength the length of the ascii string | ||||||||
1143 | @return 0 - if both strings are equal | ||||||||
1144 | < 0 - if this string is less than the string argument | ||||||||
1145 | > 0 - if this string is greater than the string argument | ||||||||
1146 | */ | ||||||||
1147 | sal_Int32 reverseCompareToAsciiL( const char * asciiStr, sal_Int32 asciiStrLength ) const | ||||||||
1148 | { | ||||||||
1149 | return rtl_ustr_asciil_reverseCompare_WithLength( pData->buffer, pData->length, | ||||||||
1150 | asciiStr, asciiStrLength ); | ||||||||
1151 | } | ||||||||
1152 | |||||||||
1153 | /** | ||||||||
1154 | Perform a comparison of two strings. | ||||||||
1155 | |||||||||
1156 | The result is true if and only if second string | ||||||||
1157 | represents the same sequence of characters as the first string. | ||||||||
1158 | Since this method is optimized for performance, the ASCII character | ||||||||
1159 | values are not converted in any way. The caller has to make sure that | ||||||||
1160 | all ASCII characters are in the allowed range between 0 and 127. | ||||||||
1161 | The ASCII string must be NULL-terminated. | ||||||||
1162 | This function can't be used for language specific comparison. | ||||||||
1163 | |||||||||
1164 | @param asciiStr the 8-Bit ASCII character string to be compared. | ||||||||
1165 | @return true if the strings are equal; | ||||||||
1166 | false, otherwise. | ||||||||
1167 | */ | ||||||||
1168 | bool equalsAscii( const char* asciiStr ) const | ||||||||
1169 | { | ||||||||
1170 | return rtl_ustr_ascii_compare_WithLength( pData->buffer, pData->length, | ||||||||
1171 | asciiStr ) == 0; | ||||||||
1172 | } | ||||||||
1173 | |||||||||
1174 | /** | ||||||||
1175 | Perform a comparison of two strings. | ||||||||
1176 | |||||||||
1177 | The result is true if and only if second string | ||||||||
1178 | represents the same sequence of characters as the first string. | ||||||||
1179 | Since this method is optimized for performance, the ASCII character | ||||||||
1180 | values are not converted in any way. The caller has to make sure that | ||||||||
1181 | all ASCII characters are in the allowed range between 0 and 127. | ||||||||
1182 | The ASCII string must be NULL-terminated and must be greater than | ||||||||
1183 | or equal to asciiStrLength. | ||||||||
1184 | This function can't be used for language specific comparison. | ||||||||
1185 | |||||||||
1186 | @param asciiStr the 8-Bit ASCII character string to be compared. | ||||||||
1187 | @param asciiStrLength the length of the ascii string | ||||||||
1188 | @return true if the strings are equal; | ||||||||
1189 | false, otherwise. | ||||||||
1190 | */ | ||||||||
1191 | bool equalsAsciiL( const char* asciiStr, sal_Int32 asciiStrLength ) const | ||||||||
1192 | { | ||||||||
1193 | if ( pData->length != asciiStrLength
| ||||||||
1194 | return false; | ||||||||
1195 | |||||||||
1196 | return rtl_ustr_asciil_reverseEquals_WithLength( | ||||||||
1197 | pData->buffer, asciiStr, asciiStrLength ); | ||||||||
1198 | } | ||||||||
1199 | |||||||||
1200 | /** | ||||||||
1201 | Perform an ASCII lowercase comparison of two strings. | ||||||||
1202 | |||||||||
1203 | The result is true if and only if second string | ||||||||
1204 | represents the same sequence of characters as the first string, | ||||||||
1205 | ignoring the case. | ||||||||
1206 | Character values between 65 and 90 (ASCII A-Z) are interpreted as | ||||||||
1207 | values between 97 and 122 (ASCII a-z). | ||||||||
1208 | Since this method is optimized for performance, the ASCII character | ||||||||
1209 | values are not converted in any way. The caller has to make sure that | ||||||||
1210 | all ASCII characters are in the allowed range between 0 and 127. | ||||||||
1211 | The ASCII string must be NULL-terminated. | ||||||||
1212 | This function can't be used for language specific comparison. | ||||||||
1213 | |||||||||
1214 | @param asciiStr the 8-Bit ASCII character string to be compared. | ||||||||
1215 | @return true if the strings are equal; | ||||||||
1216 | false, otherwise. | ||||||||
1217 | */ | ||||||||
1218 | bool equalsIgnoreAsciiCaseAscii( const char * asciiStr ) const | ||||||||
1219 | { | ||||||||
1220 | return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr ) == 0; | ||||||||
1221 | } | ||||||||
1222 | |||||||||
1223 | /** | ||||||||
1224 | Compares two ASCII strings ignoring case | ||||||||
1225 | |||||||||
1226 | The comparison is based on the numeric value of each character in | ||||||||
1227 | the strings and return a value indicating their relationship. | ||||||||
1228 | Since this method is optimized for performance, the ASCII character | ||||||||
1229 | values are not converted in any way. The caller has to make sure that | ||||||||
1230 | all ASCII characters are in the allowed range between 0 and 127. | ||||||||
1231 | The ASCII string must be NULL-terminated. | ||||||||
1232 | This function can't be used for language specific sorting. | ||||||||
1233 | |||||||||
1234 | @param asciiStr the 8-Bit ASCII character string to be compared. | ||||||||
1235 | @return 0 - if both strings are equal | ||||||||
1236 | < 0 - if this string is less than the string argument | ||||||||
1237 | > 0 - if this string is greater than the string argument | ||||||||
1238 | |||||||||
1239 | @since LibreOffice 3.5 | ||||||||
1240 | */ | ||||||||
1241 | sal_Int32 compareToIgnoreAsciiCaseAscii( const char * asciiStr ) const | ||||||||
1242 | { | ||||||||
1243 | return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr ); | ||||||||
1244 | } | ||||||||
1245 | |||||||||
1246 | /** | ||||||||
1247 | Perform an ASCII lowercase comparison of two strings. | ||||||||
1248 | |||||||||
1249 | The result is true if and only if second string | ||||||||
1250 | represents the same sequence of characters as the first string, | ||||||||
1251 | ignoring the case. | ||||||||
1252 | Character values between 65 and 90 (ASCII A-Z) are interpreted as | ||||||||
1253 | values between 97 and 122 (ASCII a-z). | ||||||||
1254 | Since this method is optimized for performance, the ASCII character | ||||||||
1255 | values are not converted in any way. The caller has to make sure that | ||||||||
1256 | all ASCII characters are in the allowed range between 0 and 127. | ||||||||
1257 | The ASCII string must be NULL-terminated and must be greater than | ||||||||
1258 | or equal to asciiStrLength. | ||||||||
1259 | This function can't be used for language specific comparison. | ||||||||
1260 | |||||||||
1261 | @param asciiStr the 8-Bit ASCII character string to be compared. | ||||||||
1262 | @param asciiStrLength the length of the ascii string | ||||||||
1263 | @return true if the strings are equal; | ||||||||
1264 | false, otherwise. | ||||||||
1265 | */ | ||||||||
1266 | bool equalsIgnoreAsciiCaseAsciiL( const char * asciiStr, sal_Int32 asciiStrLength ) const | ||||||||
1267 | { | ||||||||
1268 | if ( pData->length != asciiStrLength ) | ||||||||
1269 | return false; | ||||||||
1270 | |||||||||
1271 | return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr ) == 0; | ||||||||
1272 | } | ||||||||
1273 | |||||||||
1274 | /** | ||||||||
1275 | Match against a substring appearing in this string. | ||||||||
1276 | |||||||||
1277 | The result is true if and only if the second string appears as a substring | ||||||||
1278 | of this string, at the given position. | ||||||||
1279 | Since this method is optimized for performance, the ASCII character | ||||||||
1280 | values are not converted in any way. The caller has to make sure that | ||||||||
1281 | all ASCII characters are in the allowed range between 0 and 127. | ||||||||
1282 | The ASCII string must be NULL-terminated and must be greater than or | ||||||||
1283 | equal to asciiStrLength. | ||||||||
1284 | This function can't be used for language specific comparison. | ||||||||
1285 | |||||||||
1286 | @param asciiStr the object (substring) to be compared. | ||||||||
1287 | @param asciiStrLength the length of asciiStr. | ||||||||
1288 | @param fromIndex the index to start the comparison from. | ||||||||
1289 | The index must be greater than or equal to 0 | ||||||||
1290 | and less than or equal to the string length. | ||||||||
1291 | @return true if str match with the characters in the string | ||||||||
1292 | at the given position; | ||||||||
1293 | false, otherwise. | ||||||||
1294 | */ | ||||||||
1295 | bool matchAsciiL( const char* asciiStr, sal_Int32 asciiStrLength, sal_Int32 fromIndex = 0 ) const | ||||||||
1296 | { | ||||||||
1297 | return rtl_ustr_ascii_shortenedCompare_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, | ||||||||
1298 | asciiStr, asciiStrLength ) == 0; | ||||||||
1299 | } | ||||||||
1300 | |||||||||
1301 | // This overload is left undefined, to detect calls of matchAsciiL that | ||||||||
1302 | // erroneously use RTL_CONSTASCII_USTRINGPARAM instead of | ||||||||
1303 | // RTL_CONSTASCII_STRINGPARAM (but would lead to ambiguities on 32 bit | ||||||||
1304 | // platforms): | ||||||||
1305 | #if SAL_TYPES_SIZEOFLONG8 == 8 | ||||||||
1306 | void matchAsciiL(char const *, sal_Int32, rtl_TextEncoding) const; | ||||||||
1307 | #endif | ||||||||
1308 | |||||||||
1309 | /** | ||||||||
1310 | Match against a substring appearing in this string, ignoring the case of | ||||||||
1311 | ASCII letters. | ||||||||
1312 | |||||||||
1313 | The result is true if and only if the second string appears as a substring | ||||||||
1314 | of this string, at the given position. | ||||||||
1315 | Character values between 65 and 90 (ASCII A-Z) are interpreted as | ||||||||
1316 | values between 97 and 122 (ASCII a-z). | ||||||||
1317 | Since this method is optimized for performance, the ASCII character | ||||||||
1318 | values are not converted in any way. The caller has to make sure that | ||||||||
1319 | all ASCII characters are in the allowed range between 0 and 127. | ||||||||
1320 | The ASCII string must be NULL-terminated and must be greater than or | ||||||||
1321 | equal to asciiStrLength. | ||||||||
1322 | This function can't be used for language specific comparison. | ||||||||
1323 | |||||||||
1324 | @param asciiStr the 8-Bit ASCII character string to be compared. | ||||||||
1325 | @param asciiStrLength the length of the ascii string | ||||||||
1326 | @param fromIndex the index to start the comparison from. | ||||||||
1327 | The index must be greater than or equal to 0 | ||||||||
1328 | and less than or equal to the string length. | ||||||||
1329 | @return true if str match with the characters in the string | ||||||||
1330 | at the given position; | ||||||||
1331 | false, otherwise. | ||||||||
1332 | */ | ||||||||
1333 | bool matchIgnoreAsciiCaseAsciiL( const char* asciiStr, sal_Int32 asciiStrLength, sal_Int32 fromIndex = 0 ) const | ||||||||
1334 | { | ||||||||
1335 | return rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, | ||||||||
1336 | asciiStr, asciiStrLength ) == 0; | ||||||||
1337 | } | ||||||||
1338 | |||||||||
1339 | // This overload is left undefined, to detect calls of | ||||||||
1340 | // matchIgnoreAsciiCaseAsciiL that erroneously use | ||||||||
1341 | // RTL_CONSTASCII_USTRINGPARAM instead of RTL_CONSTASCII_STRINGPARAM (but | ||||||||
1342 | // would lead to ambiguities on 32 bit platforms): | ||||||||
1343 | #if SAL_TYPES_SIZEOFLONG8 == 8 | ||||||||
1344 | void matchIgnoreAsciiCaseAsciiL(char const *, sal_Int32, rtl_TextEncoding) | ||||||||
1345 | const; | ||||||||
1346 | #endif | ||||||||
1347 | |||||||||
1348 | /** | ||||||||
1349 | Check whether this string starts with a given substring. | ||||||||
1350 | |||||||||
1351 | @param str the substring to be compared | ||||||||
1352 | |||||||||
1353 | @param rest if non-null, and this function returns true, then assign a | ||||||||
1354 | copy of the remainder of this string to *rest. Available since | ||||||||
1355 | LibreOffice 4.2 | ||||||||
1356 | |||||||||
1357 | @return true if and only if the given str appears as a substring at the | ||||||||
1358 | start of this string | ||||||||
1359 | |||||||||
1360 | @since LibreOffice 4.0 | ||||||||
1361 | */ | ||||||||
1362 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
1363 | bool startsWith(std::u16string_view sv, OUString * rest = nullptr) const { | ||||||||
1364 | auto const b = match(sv); | ||||||||
1365 | if (b && rest != nullptr) { | ||||||||
1366 | *rest = copy(sv.size()); | ||||||||
1367 | } | ||||||||
1368 | return b; | ||||||||
1369 | } | ||||||||
1370 | #else | ||||||||
1371 | bool startsWith(OUString const & str, OUString * rest = NULL__null) const { | ||||||||
1372 | bool b = match(str); | ||||||||
1373 | if (b && rest != NULL__null) { | ||||||||
1374 | *rest = copy(str.getLength()); | ||||||||
1375 | } | ||||||||
1376 | return b; | ||||||||
1377 | } | ||||||||
1378 | #endif | ||||||||
1379 | |||||||||
1380 | /** | ||||||||
1381 | @overload | ||||||||
1382 | This function accepts an ASCII string literal as its argument. | ||||||||
1383 | @since LibreOffice 4.0 | ||||||||
1384 | */ | ||||||||
1385 | template< typename T > | ||||||||
1386 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type startsWith( | ||||||||
1387 | T & literal, OUString * rest = NULL__null) const | ||||||||
1388 | { | ||||||||
1389 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1390, __extension__ __PRETTY_FUNCTION__)) | ||||||||
1390 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1390, __extension__ __PRETTY_FUNCTION__)); | ||||||||
1391 | bool b | ||||||||
1392 | = (libreoffice_internal::ConstCharArrayDetector<T>::length | ||||||||
1393 | <= sal_uInt32(pData->length)) | ||||||||
1394 | && rtl_ustr_asciil_reverseEquals_WithLength( | ||||||||
1395 | pData->buffer, | ||||||||
1396 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
1397 | literal), | ||||||||
1398 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
1399 | if (b && rest != NULL__null) { | ||||||||
1400 | *rest = copy( | ||||||||
1401 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
1402 | } | ||||||||
1403 | return b; | ||||||||
1404 | } | ||||||||
1405 | |||||||||
1406 | /** | ||||||||
1407 | Check whether this string starts with a given string, ignoring the case of | ||||||||
1408 | ASCII letters. | ||||||||
1409 | |||||||||
1410 | Character values between 65 and 90 (ASCII A-Z) are interpreted as | ||||||||
1411 | values between 97 and 122 (ASCII a-z). | ||||||||
1412 | This function can't be used for language specific comparison. | ||||||||
1413 | |||||||||
1414 | @param str the substring to be compared | ||||||||
1415 | |||||||||
1416 | @param rest if non-null, and this function returns true, then assign a | ||||||||
1417 | copy of the remainder of this string to *rest. Available since | ||||||||
1418 | LibreOffice 4.2 | ||||||||
1419 | |||||||||
1420 | @return true if and only if the given str appears as a substring at the | ||||||||
1421 | start of this string, ignoring the case of ASCII letters ("A"--"Z" and | ||||||||
1422 | "a"--"z") | ||||||||
1423 | |||||||||
1424 | @since LibreOffice 4.0 | ||||||||
1425 | */ | ||||||||
1426 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
1427 | bool startsWithIgnoreAsciiCase(std::u16string_view sv, OUString * rest = nullptr) const { | ||||||||
1428 | auto const b = matchIgnoreAsciiCase(sv); | ||||||||
1429 | if (b && rest != nullptr) { | ||||||||
1430 | *rest = copy(sv.size()); | ||||||||
1431 | } | ||||||||
1432 | return b; | ||||||||
1433 | } | ||||||||
1434 | #else | ||||||||
1435 | bool startsWithIgnoreAsciiCase(OUString const & str, OUString * rest = NULL__null) | ||||||||
1436 | const | ||||||||
1437 | { | ||||||||
1438 | bool b = matchIgnoreAsciiCase(str); | ||||||||
1439 | if (b && rest != NULL__null) { | ||||||||
1440 | *rest = copy(str.getLength()); | ||||||||
1441 | } | ||||||||
1442 | return b; | ||||||||
1443 | } | ||||||||
1444 | #endif | ||||||||
1445 | |||||||||
1446 | /** | ||||||||
1447 | @overload | ||||||||
1448 | This function accepts an ASCII string literal as its argument. | ||||||||
1449 | @since LibreOffice 4.0 | ||||||||
1450 | */ | ||||||||
1451 | template< typename T > | ||||||||
1452 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type | ||||||||
1453 | startsWithIgnoreAsciiCase(T & literal, OUString * rest = NULL__null) const | ||||||||
1454 | { | ||||||||
1455 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1456, __extension__ __PRETTY_FUNCTION__)) | ||||||||
1456 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1456, __extension__ __PRETTY_FUNCTION__)); | ||||||||
1457 | bool b | ||||||||
1458 | = (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths( | ||||||||
1459 | pData->buffer, | ||||||||
1460 | libreoffice_internal::ConstCharArrayDetector<T>::length, | ||||||||
1461 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
1462 | literal), | ||||||||
1463 | libreoffice_internal::ConstCharArrayDetector<T>::length) | ||||||||
1464 | == 0); | ||||||||
1465 | if (b && rest != NULL__null) { | ||||||||
1466 | *rest = copy( | ||||||||
1467 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
1468 | } | ||||||||
1469 | return b; | ||||||||
1470 | } | ||||||||
1471 | |||||||||
1472 | /** | ||||||||
1473 | Check whether this string ends with a given substring. | ||||||||
1474 | |||||||||
1475 | @param str the substring to be compared | ||||||||
1476 | |||||||||
1477 | @param rest if non-null, and this function returns true, then assign a | ||||||||
1478 | copy of the remainder of this string to *rest. Available since | ||||||||
1479 | LibreOffice 4.2 | ||||||||
1480 | |||||||||
1481 | @return true if and only if the given str appears as a substring at the | ||||||||
1482 | end of this string | ||||||||
1483 | |||||||||
1484 | @since LibreOffice 3.6 | ||||||||
1485 | */ | ||||||||
1486 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
1487 | bool endsWith(std::u16string_view sv, OUString * rest = nullptr) const { | ||||||||
1488 | auto const b = sv.size() <= sal_uInt32(pData->length) | ||||||||
1489 | && match(sv, pData->length - sv.size()); | ||||||||
1490 | if (b && rest != nullptr) { | ||||||||
1491 | *rest = copy(0, (pData->length - sv.size())); | ||||||||
1492 | } | ||||||||
1493 | return b; | ||||||||
1494 | } | ||||||||
1495 | #else | ||||||||
1496 | bool endsWith(OUString const & str, OUString * rest = NULL__null) const { | ||||||||
1497 | bool b = str.getLength() <= getLength() | ||||||||
1498 | && match(str, getLength() - str.getLength()); | ||||||||
1499 | if (b && rest != NULL__null) { | ||||||||
1500 | *rest = copy(0, getLength() - str.getLength()); | ||||||||
1501 | } | ||||||||
1502 | return b; | ||||||||
1503 | } | ||||||||
1504 | #endif | ||||||||
1505 | |||||||||
1506 | /** | ||||||||
1507 | @overload | ||||||||
1508 | This function accepts an ASCII string literal as its argument. | ||||||||
1509 | @since LibreOffice 3.6 | ||||||||
1510 | */ | ||||||||
1511 | template< typename T > | ||||||||
1512 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type | ||||||||
1513 | endsWith(T & literal, OUString * rest = NULL__null) const | ||||||||
1514 | { | ||||||||
1515 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1516, __extension__ __PRETTY_FUNCTION__)) | ||||||||
1516 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1516, __extension__ __PRETTY_FUNCTION__)); | ||||||||
1517 | bool b | ||||||||
1518 | = (libreoffice_internal::ConstCharArrayDetector<T>::length | ||||||||
1519 | <= sal_uInt32(pData->length)) | ||||||||
1520 | && rtl_ustr_asciil_reverseEquals_WithLength( | ||||||||
1521 | (pData->buffer + pData->length | ||||||||
1522 | - libreoffice_internal::ConstCharArrayDetector<T>::length), | ||||||||
1523 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
1524 | literal), | ||||||||
1525 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
1526 | if (b && rest != NULL__null) { | ||||||||
1527 | *rest = copy( | ||||||||
1528 | 0, | ||||||||
1529 | (getLength() | ||||||||
1530 | - libreoffice_internal::ConstCharArrayDetector<T>::length)); | ||||||||
1531 | } | ||||||||
1532 | return b; | ||||||||
1533 | } | ||||||||
1534 | |||||||||
1535 | /** | ||||||||
1536 | Check whether this string ends with a given ASCII string. | ||||||||
1537 | |||||||||
1538 | @param asciiStr a sequence of at least asciiStrLength ASCII characters | ||||||||
1539 | (bytes in the range 0x00--0x7F) | ||||||||
1540 | @param asciiStrLength the length of asciiStr; must be non-negative | ||||||||
1541 | @return true if this string ends with asciiStr; otherwise, false is | ||||||||
1542 | returned | ||||||||
1543 | |||||||||
1544 | @since UDK 3.2.7 | ||||||||
1545 | */ | ||||||||
1546 | bool endsWithAsciiL(char const * asciiStr, sal_Int32 asciiStrLength) | ||||||||
1547 | const | ||||||||
1548 | { | ||||||||
1549 | return asciiStrLength <= pData->length | ||||||||
1550 | && rtl_ustr_asciil_reverseEquals_WithLength( | ||||||||
1551 | pData->buffer + pData->length - asciiStrLength, asciiStr, | ||||||||
1552 | asciiStrLength); | ||||||||
1553 | } | ||||||||
1554 | |||||||||
1555 | /** | ||||||||
1556 | Check whether this string ends with a given string, ignoring the case of | ||||||||
1557 | ASCII letters. | ||||||||
1558 | |||||||||
1559 | Character values between 65 and 90 (ASCII A-Z) are interpreted as | ||||||||
1560 | values between 97 and 122 (ASCII a-z). | ||||||||
1561 | This function can't be used for language specific comparison. | ||||||||
1562 | |||||||||
1563 | @param str the substring to be compared | ||||||||
1564 | |||||||||
1565 | @param rest if non-null, and this function returns true, then assign a | ||||||||
1566 | copy of the remainder of this string to *rest. Available since | ||||||||
1567 | LibreOffice 4.2 | ||||||||
1568 | |||||||||
1569 | @return true if and only if the given str appears as a substring at the | ||||||||
1570 | end of this string, ignoring the case of ASCII letters ("A"--"Z" and | ||||||||
1571 | "a"--"z") | ||||||||
1572 | |||||||||
1573 | @since LibreOffice 3.6 | ||||||||
1574 | */ | ||||||||
1575 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
1576 | bool endsWithIgnoreAsciiCase(std::u16string_view sv, OUString * rest = nullptr) const { | ||||||||
1577 | auto const b = sv.size() <= sal_uInt32(pData->length) | ||||||||
1578 | && matchIgnoreAsciiCase(sv, pData->length - sv.size()); | ||||||||
1579 | if (b && rest != nullptr) { | ||||||||
1580 | *rest = copy(0, pData->length - sv.size()); | ||||||||
1581 | } | ||||||||
1582 | return b; | ||||||||
1583 | } | ||||||||
1584 | #else | ||||||||
1585 | bool endsWithIgnoreAsciiCase(OUString const & str, OUString * rest = NULL__null) const | ||||||||
1586 | { | ||||||||
1587 | bool b = str.getLength() <= getLength() | ||||||||
1588 | && matchIgnoreAsciiCase(str, getLength() - str.getLength()); | ||||||||
1589 | if (b && rest != NULL__null) { | ||||||||
1590 | *rest = copy(0, getLength() - str.getLength()); | ||||||||
1591 | } | ||||||||
1592 | return b; | ||||||||
1593 | } | ||||||||
1594 | #endif | ||||||||
1595 | |||||||||
1596 | /** | ||||||||
1597 | @overload | ||||||||
1598 | This function accepts an ASCII string literal as its argument. | ||||||||
1599 | @since LibreOffice 3.6 | ||||||||
1600 | */ | ||||||||
1601 | template< typename T > | ||||||||
1602 | typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type | ||||||||
1603 | endsWithIgnoreAsciiCase(T & literal, OUString * rest = NULL__null) const | ||||||||
1604 | { | ||||||||
1605 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1606, __extension__ __PRETTY_FUNCTION__)) | ||||||||
1606 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1606, __extension__ __PRETTY_FUNCTION__)); | ||||||||
1607 | bool b | ||||||||
1608 | = (libreoffice_internal::ConstCharArrayDetector<T>::length | ||||||||
1609 | <= sal_uInt32(pData->length)) | ||||||||
1610 | && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths( | ||||||||
1611 | (pData->buffer + pData->length | ||||||||
1612 | - libreoffice_internal::ConstCharArrayDetector<T>::length), | ||||||||
1613 | libreoffice_internal::ConstCharArrayDetector<T>::length, | ||||||||
1614 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
1615 | literal), | ||||||||
1616 | libreoffice_internal::ConstCharArrayDetector<T>::length) | ||||||||
1617 | == 0); | ||||||||
1618 | if (b && rest != NULL__null) { | ||||||||
1619 | *rest = copy( | ||||||||
1620 | 0, | ||||||||
1621 | (getLength() | ||||||||
1622 | - libreoffice_internal::ConstCharArrayDetector<T>::length)); | ||||||||
1623 | } | ||||||||
1624 | return b; | ||||||||
1625 | } | ||||||||
1626 | |||||||||
1627 | /** | ||||||||
1628 | Check whether this string ends with a given ASCII string, ignoring the | ||||||||
1629 | case of ASCII letters. | ||||||||
1630 | |||||||||
1631 | @param asciiStr a sequence of at least asciiStrLength ASCII characters | ||||||||
1632 | (bytes in the range 0x00--0x7F) | ||||||||
1633 | @param asciiStrLength the length of asciiStr; must be non-negative | ||||||||
1634 | @return true if this string ends with asciiStr, ignoring the case of ASCII | ||||||||
1635 | letters ("A"--"Z" and "a"--"z"); otherwise, false is returned | ||||||||
1636 | */ | ||||||||
1637 | bool endsWithIgnoreAsciiCaseAsciiL( | ||||||||
1638 | char const * asciiStr, sal_Int32 asciiStrLength) const | ||||||||
1639 | { | ||||||||
1640 | return asciiStrLength <= pData->length | ||||||||
1641 | && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths( | ||||||||
1642 | pData->buffer + pData->length - asciiStrLength, | ||||||||
1643 | asciiStrLength, asciiStr, asciiStrLength) | ||||||||
1644 | == 0); | ||||||||
1645 | } | ||||||||
1646 | |||||||||
1647 | friend bool operator == ( const OUString& rStr1, const OUString& rStr2 ) | ||||||||
1648 | { return rStr1.equals(rStr2); } | ||||||||
1649 | |||||||||
1650 | friend bool operator != ( const OUString& rStr1, const OUString& rStr2 ) | ||||||||
1651 | { return !(operator == ( rStr1, rStr2 )); } | ||||||||
1652 | |||||||||
1653 | friend bool operator < ( const OUString& rStr1, const OUString& rStr2 ) | ||||||||
1654 | { return rStr1.compareTo( rStr2 ) < 0; } | ||||||||
1655 | friend bool operator > ( const OUString& rStr1, const OUString& rStr2 ) | ||||||||
1656 | { return rStr1.compareTo( rStr2 ) > 0; } | ||||||||
1657 | friend bool operator <= ( const OUString& rStr1, const OUString& rStr2 ) | ||||||||
1658 | { return rStr1.compareTo( rStr2 ) <= 0; } | ||||||||
1659 | friend bool operator >= ( const OUString& rStr1, const OUString& rStr2 ) | ||||||||
1660 | { return rStr1.compareTo( rStr2 ) >= 0; } | ||||||||
1661 | |||||||||
1662 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
1663 | |||||||||
1664 | template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16 | ||||||||
1665 | operator ==(OUString const & s1, T const & s2) { | ||||||||
1666 | return rtl_ustr_compare_WithLength(s1.getStr(), s1.getLength(), s2, rtl_ustr_getLength(s2)) | ||||||||
1667 | == 0; | ||||||||
1668 | } | ||||||||
1669 | |||||||||
1670 | template<typename T> | ||||||||
1671 | friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16 | ||||||||
1672 | operator ==(OUString const & s1, T & s2) { | ||||||||
1673 | return rtl_ustr_compare_WithLength(s1.getStr(), s1.getLength(), s2, rtl_ustr_getLength(s2)) | ||||||||
1674 | == 0; | ||||||||
1675 | } | ||||||||
1676 | |||||||||
1677 | template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16 | ||||||||
1678 | operator ==(T const & s1, OUString const & s2) { | ||||||||
1679 | return rtl_ustr_compare_WithLength(s1, rtl_ustr_getLength(s1), s2.getStr(), s2.getLength()) | ||||||||
1680 | == 0; | ||||||||
1681 | } | ||||||||
1682 | |||||||||
1683 | template<typename T> | ||||||||
1684 | friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16 | ||||||||
1685 | operator ==(T & s1, OUString const & s2) { | ||||||||
1686 | return rtl_ustr_compare_WithLength(s1, rtl_ustr_getLength(s1), s2.getStr(), s2.getLength()) | ||||||||
1687 | == 0; | ||||||||
1688 | } | ||||||||
1689 | |||||||||
1690 | template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16 | ||||||||
1691 | operator !=(OUString const & s1, T const & s2) { return !(s1 == s2); } | ||||||||
1692 | |||||||||
1693 | template<typename T> | ||||||||
1694 | friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16 | ||||||||
1695 | operator !=(OUString const & s1, T & s2) { return !(s1 == s2); } | ||||||||
1696 | |||||||||
1697 | template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16 | ||||||||
1698 | operator !=(T const & s1, OUString const & s2) { return !(s1 == s2); } | ||||||||
1699 | |||||||||
1700 | template<typename T> | ||||||||
1701 | friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16 | ||||||||
1702 | operator !=(T & s1, OUString const & s2) { return !(s1 == s2); } | ||||||||
1703 | |||||||||
1704 | #else | ||||||||
1705 | |||||||||
1706 | friend bool operator == ( const OUString& rStr1, const sal_Unicode * pStr2 ) | ||||||||
1707 | { return rStr1.compareTo( pStr2 ) == 0; } | ||||||||
1708 | friend bool operator == ( const sal_Unicode * pStr1, const OUString& rStr2 ) | ||||||||
1709 | { return OUString( pStr1 ).compareTo( rStr2 ) == 0; } | ||||||||
1710 | |||||||||
1711 | friend bool operator != ( const OUString& rStr1, const sal_Unicode * pStr2 ) | ||||||||
1712 | { return !(operator == ( rStr1, pStr2 )); } | ||||||||
1713 | friend bool operator != ( const sal_Unicode * pStr1, const OUString& rStr2 ) | ||||||||
1714 | { return !(operator == ( pStr1, rStr2 )); } | ||||||||
1715 | |||||||||
1716 | #endif | ||||||||
1717 | |||||||||
1718 | /** | ||||||||
1719 | * Compare string to an ASCII string literal. | ||||||||
1720 | * | ||||||||
1721 | * This operator is equal to calling equalsAsciiL(). | ||||||||
1722 | * | ||||||||
1723 | * @since LibreOffice 3.6 | ||||||||
1724 | */ | ||||||||
1725 | template< typename T > | ||||||||
1726 | friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator==( const OUString& rString, T& literal ) | ||||||||
1727 | { | ||||||||
1728 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1729, __extension__ __PRETTY_FUNCTION__)) | ||||||||
1729 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1729, __extension__ __PRETTY_FUNCTION__)); | ||||||||
1730 | return rString.equalsAsciiL( | ||||||||
1731 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), | ||||||||
1732 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
1733 | } | ||||||||
1734 | /** | ||||||||
1735 | * Compare string to an ASCII string literal. | ||||||||
1736 | * | ||||||||
1737 | * This operator is equal to calling equalsAsciiL(). | ||||||||
1738 | * | ||||||||
1739 | * @since LibreOffice 3.6 | ||||||||
1740 | */ | ||||||||
1741 | template< typename T > | ||||||||
1742 | friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator==( T& literal, const OUString& rString ) | ||||||||
1743 | { | ||||||||
1744 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1745, __extension__ __PRETTY_FUNCTION__)) | ||||||||
1745 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1745, __extension__ __PRETTY_FUNCTION__)); | ||||||||
1746 | return rString.equalsAsciiL( | ||||||||
1747 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), | ||||||||
1748 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
1749 | } | ||||||||
1750 | /** | ||||||||
1751 | * Compare string to an ASCII string literal. | ||||||||
1752 | * | ||||||||
1753 | * This operator is equal to calling !equalsAsciiL(). | ||||||||
1754 | * | ||||||||
1755 | * @since LibreOffice 3.6 | ||||||||
1756 | */ | ||||||||
1757 | template< typename T > | ||||||||
1758 | friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator!=( const OUString& rString, T& literal ) | ||||||||
1759 | { | ||||||||
1760 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1761, __extension__ __PRETTY_FUNCTION__)) | ||||||||
1761 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1761, __extension__ __PRETTY_FUNCTION__)); | ||||||||
1762 | return !rString.equalsAsciiL( | ||||||||
1763 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), | ||||||||
1764 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
1765 | } | ||||||||
1766 | /** | ||||||||
1767 | * Compare string to an ASCII string literal. | ||||||||
1768 | * | ||||||||
1769 | * This operator is equal to calling !equalsAsciiL(). | ||||||||
1770 | * | ||||||||
1771 | * @since LibreOffice 3.6 | ||||||||
1772 | */ | ||||||||
1773 | template< typename T > | ||||||||
1774 | friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator!=( T& literal, const OUString& rString ) | ||||||||
1775 | { | ||||||||
1776 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1777, __extension__ __PRETTY_FUNCTION__)) | ||||||||
1777 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 1777, __extension__ __PRETTY_FUNCTION__)); | ||||||||
1778 | return !rString.equalsAsciiL( | ||||||||
1779 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), | ||||||||
1780 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
1781 | } | ||||||||
1782 | |||||||||
1783 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
1784 | /** @overload @since LibreOffice 5.3 */ | ||||||||
1785 | template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16 | ||||||||
1786 | operator ==(OUString const & string, T & literal) { | ||||||||
1787 | return | ||||||||
1788 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1789 | string.pData->buffer, string.pData->length, | ||||||||
1790 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
1791 | literal), | ||||||||
1792 | libreoffice_internal::ConstCharArrayDetector<T>::length) | ||||||||
1793 | == 0; | ||||||||
1794 | } | ||||||||
1795 | /** @overload @since LibreOffice 5.3 */ | ||||||||
1796 | template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16 | ||||||||
1797 | operator ==(T & literal, OUString const & string) { | ||||||||
1798 | return | ||||||||
1799 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1800 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
1801 | literal), | ||||||||
1802 | libreoffice_internal::ConstCharArrayDetector<T>::length, | ||||||||
1803 | string.pData->buffer, string.pData->length) | ||||||||
1804 | == 0; | ||||||||
1805 | } | ||||||||
1806 | /** @overload @since LibreOffice 5.3 */ | ||||||||
1807 | template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16 | ||||||||
1808 | operator !=(OUString const & string, T & literal) { | ||||||||
1809 | return | ||||||||
1810 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1811 | string.pData->buffer, string.pData->length, | ||||||||
1812 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
1813 | literal), | ||||||||
1814 | libreoffice_internal::ConstCharArrayDetector<T>::length) | ||||||||
1815 | != 0; | ||||||||
1816 | } | ||||||||
1817 | /** @overload @since LibreOffice 5.3 */ | ||||||||
1818 | template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16 | ||||||||
1819 | operator !=(T & literal, OUString const & string) { | ||||||||
1820 | return | ||||||||
1821 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1822 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer( | ||||||||
1823 | literal), | ||||||||
1824 | libreoffice_internal::ConstCharArrayDetector<T>::length, | ||||||||
1825 | string.pData->buffer, string.pData->length) | ||||||||
1826 | != 0; | ||||||||
1827 | } | ||||||||
1828 | #endif | ||||||||
1829 | |||||||||
1830 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
1831 | /// @cond INTERNAL | ||||||||
1832 | |||||||||
1833 | /* Comparison between OUString and OUStringLiteral. | ||||||||
1834 | |||||||||
1835 | @since LibreOffice 5.0 | ||||||||
1836 | */ | ||||||||
1837 | |||||||||
1838 | template<std::size_t N> | ||||||||
1839 | friend bool operator ==(OUString const & lhs, OUStringLiteral<N> const & rhs) { | ||||||||
1840 | return | ||||||||
1841 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1842 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()) | ||||||||
1843 | == 0; | ||||||||
1844 | } | ||||||||
1845 | |||||||||
1846 | template<std::size_t N> | ||||||||
1847 | friend bool operator !=(OUString const & lhs, OUStringLiteral<N> const & rhs) { | ||||||||
1848 | return | ||||||||
1849 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1850 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()) | ||||||||
1851 | != 0; | ||||||||
1852 | } | ||||||||
1853 | |||||||||
1854 | template<std::size_t N> | ||||||||
1855 | friend bool operator <(OUString const & lhs, OUStringLiteral<N> const & rhs) { | ||||||||
1856 | return | ||||||||
1857 | (rtl_ustr_compare_WithLength( | ||||||||
1858 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())) | ||||||||
1859 | < 0; | ||||||||
1860 | } | ||||||||
1861 | |||||||||
1862 | template<std::size_t N> | ||||||||
1863 | friend bool operator <=(OUString const & lhs, OUStringLiteral<N> const & rhs) { | ||||||||
1864 | return | ||||||||
1865 | (rtl_ustr_compare_WithLength( | ||||||||
1866 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())) | ||||||||
1867 | <= 0; | ||||||||
1868 | } | ||||||||
1869 | |||||||||
1870 | template<std::size_t N> | ||||||||
1871 | friend bool operator >(OUString const & lhs, OUStringLiteral<N> const & rhs) { | ||||||||
1872 | return | ||||||||
1873 | (rtl_ustr_compare_WithLength( | ||||||||
1874 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())) | ||||||||
1875 | > 0; | ||||||||
1876 | } | ||||||||
1877 | |||||||||
1878 | template<std::size_t N> | ||||||||
1879 | friend bool operator >=(OUString const & lhs, OUStringLiteral<N> const & rhs) { | ||||||||
1880 | return | ||||||||
1881 | (rtl_ustr_compare_WithLength( | ||||||||
1882 | lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())) | ||||||||
1883 | >= 0; | ||||||||
1884 | } | ||||||||
1885 | |||||||||
1886 | template<std::size_t N> | ||||||||
1887 | friend bool operator ==(OUStringLiteral<N> const & lhs, OUString const & rhs) { | ||||||||
1888 | return | ||||||||
1889 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1890 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length) | ||||||||
1891 | == 0; | ||||||||
1892 | } | ||||||||
1893 | |||||||||
1894 | template<std::size_t N> | ||||||||
1895 | friend bool operator !=(OUStringLiteral<N> const & lhs, OUString const & rhs) { | ||||||||
1896 | return | ||||||||
1897 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1898 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length) | ||||||||
1899 | != 0; | ||||||||
1900 | } | ||||||||
1901 | |||||||||
1902 | template<std::size_t N> | ||||||||
1903 | friend bool operator <(OUStringLiteral<N> const & lhs, OUString const & rhs) { | ||||||||
1904 | return | ||||||||
1905 | (rtl_ustr_compare_WithLength( | ||||||||
1906 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)) | ||||||||
1907 | < 0; | ||||||||
1908 | } | ||||||||
1909 | |||||||||
1910 | template<std::size_t N> | ||||||||
1911 | friend bool operator <=(OUStringLiteral<N> const & lhs, OUString const & rhs) { | ||||||||
1912 | return | ||||||||
1913 | (rtl_ustr_compare_WithLength( | ||||||||
1914 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)) | ||||||||
1915 | <= 0; | ||||||||
1916 | } | ||||||||
1917 | |||||||||
1918 | template<std::size_t N> | ||||||||
1919 | friend bool operator >(OUStringLiteral<N> const & lhs, OUString const & rhs) { | ||||||||
1920 | return | ||||||||
1921 | (rtl_ustr_compare_WithLength( | ||||||||
1922 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)) | ||||||||
1923 | > 0; | ||||||||
1924 | } | ||||||||
1925 | |||||||||
1926 | template<std::size_t N> | ||||||||
1927 | friend bool operator >=(OUStringLiteral<N> const & lhs, OUString const & rhs) { | ||||||||
1928 | return | ||||||||
1929 | (rtl_ustr_compare_WithLength( | ||||||||
1930 | lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)) | ||||||||
1931 | >= 0; | ||||||||
1932 | } | ||||||||
1933 | |||||||||
1934 | /// @endcond | ||||||||
1935 | #endif | ||||||||
1936 | |||||||||
1937 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
1938 | friend bool operator ==(OUString const & lhs, std::u16string_view rhs) { | ||||||||
1939 | return | ||||||||
1940 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1941 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()) | ||||||||
1942 | == 0; | ||||||||
1943 | } | ||||||||
1944 | |||||||||
1945 | friend bool operator !=(OUString const & lhs, std::u16string_view rhs) { | ||||||||
1946 | return | ||||||||
1947 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1948 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()) | ||||||||
1949 | != 0; | ||||||||
1950 | } | ||||||||
1951 | |||||||||
1952 | friend bool operator <(OUString const & lhs, std::u16string_view rhs) { | ||||||||
1953 | return | ||||||||
1954 | (rtl_ustr_compare_WithLength( | ||||||||
1955 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())) | ||||||||
1956 | < 0; | ||||||||
1957 | } | ||||||||
1958 | |||||||||
1959 | friend bool operator <=(OUString const & lhs, std::u16string_view rhs) { | ||||||||
1960 | return | ||||||||
1961 | (rtl_ustr_compare_WithLength( | ||||||||
1962 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())) | ||||||||
1963 | <= 0; | ||||||||
1964 | } | ||||||||
1965 | |||||||||
1966 | friend bool operator >(OUString const & lhs, std::u16string_view rhs) { | ||||||||
1967 | return | ||||||||
1968 | (rtl_ustr_compare_WithLength( | ||||||||
1969 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())) | ||||||||
1970 | > 0; | ||||||||
1971 | } | ||||||||
1972 | |||||||||
1973 | friend bool operator >=(OUString const & lhs, std::u16string_view rhs) { | ||||||||
1974 | return | ||||||||
1975 | (rtl_ustr_compare_WithLength( | ||||||||
1976 | lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())) | ||||||||
1977 | >= 0; | ||||||||
1978 | } | ||||||||
1979 | |||||||||
1980 | friend bool operator ==(std::u16string_view lhs, OUString const & rhs) { | ||||||||
1981 | return | ||||||||
1982 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1983 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length) | ||||||||
1984 | == 0; | ||||||||
1985 | } | ||||||||
1986 | |||||||||
1987 | friend bool operator !=(std::u16string_view lhs, OUString const & rhs) { | ||||||||
1988 | return | ||||||||
1989 | rtl_ustr_reverseCompare_WithLength( | ||||||||
1990 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length) | ||||||||
1991 | != 0; | ||||||||
1992 | } | ||||||||
1993 | |||||||||
1994 | friend bool operator <(std::u16string_view lhs, OUString const & rhs) { | ||||||||
1995 | return | ||||||||
1996 | (rtl_ustr_compare_WithLength( | ||||||||
1997 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)) | ||||||||
1998 | < 0; | ||||||||
1999 | } | ||||||||
2000 | |||||||||
2001 | friend bool operator <=(std::u16string_view lhs, OUString const & rhs) { | ||||||||
2002 | return | ||||||||
2003 | (rtl_ustr_compare_WithLength( | ||||||||
2004 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)) | ||||||||
2005 | <= 0; | ||||||||
2006 | } | ||||||||
2007 | |||||||||
2008 | friend bool operator >(std::u16string_view lhs, OUString const & rhs) { | ||||||||
2009 | return | ||||||||
2010 | (rtl_ustr_compare_WithLength( | ||||||||
2011 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)) | ||||||||
2012 | > 0; | ||||||||
2013 | } | ||||||||
2014 | |||||||||
2015 | friend bool operator >=(std::u16string_view lhs, OUString const & rhs) { | ||||||||
2016 | return | ||||||||
2017 | (rtl_ustr_compare_WithLength( | ||||||||
2018 | lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)) | ||||||||
2019 | >= 0; | ||||||||
2020 | } | ||||||||
2021 | #endif | ||||||||
2022 | |||||||||
2023 | /** | ||||||||
2024 | Returns a hashcode for this string. | ||||||||
2025 | |||||||||
2026 | @return a hash code value for this object. | ||||||||
2027 | |||||||||
2028 | @see rtl::OUStringHash for convenient use of std::unordered_map | ||||||||
2029 | */ | ||||||||
2030 | sal_Int32 hashCode() const | ||||||||
2031 | { | ||||||||
2032 | return rtl_ustr_hashCode_WithLength( pData->buffer, pData->length ); | ||||||||
2033 | } | ||||||||
2034 | |||||||||
2035 | /** | ||||||||
2036 | Returns the index within this string of the first occurrence of the | ||||||||
2037 | specified character, starting the search at the specified index. | ||||||||
2038 | |||||||||
2039 | @param ch character to be located. | ||||||||
2040 | @param fromIndex the index to start the search from. | ||||||||
2041 | The index must be greater than or equal to 0 | ||||||||
2042 | and less than or equal to the string length. | ||||||||
2043 | @return the index of the first occurrence of the character in the | ||||||||
2044 | character sequence represented by this string that is | ||||||||
2045 | greater than or equal to fromIndex, or | ||||||||
2046 | -1 if the character does not occur. | ||||||||
2047 | */ | ||||||||
2048 | sal_Int32 indexOf( sal_Unicode ch, sal_Int32 fromIndex = 0 ) const | ||||||||
2049 | { | ||||||||
2050 | sal_Int32 ret = rtl_ustr_indexOfChar_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, ch ); | ||||||||
2051 | return (ret < 0 ? ret : ret+fromIndex); | ||||||||
2052 | } | ||||||||
2053 | |||||||||
2054 | /** | ||||||||
2055 | Returns the index within this string of the last occurrence of the | ||||||||
2056 | specified character, searching backward starting at the end. | ||||||||
2057 | |||||||||
2058 | @param ch character to be located. | ||||||||
2059 | @return the index of the last occurrence of the character in the | ||||||||
2060 | character sequence represented by this string, or | ||||||||
2061 | -1 if the character does not occur. | ||||||||
2062 | */ | ||||||||
2063 | sal_Int32 lastIndexOf( sal_Unicode ch ) const | ||||||||
2064 | { | ||||||||
2065 | return rtl_ustr_lastIndexOfChar_WithLength( pData->buffer, pData->length, ch ); | ||||||||
2066 | } | ||||||||
2067 | |||||||||
2068 | /** | ||||||||
2069 | Returns the index within this string of the last occurrence of the | ||||||||
2070 | specified character, searching backward starting before the specified | ||||||||
2071 | index. | ||||||||
2072 | |||||||||
2073 | @param ch character to be located. | ||||||||
2074 | @param fromIndex the index before which to start the search. | ||||||||
2075 | @return the index of the last occurrence of the character in the | ||||||||
2076 | character sequence represented by this string that | ||||||||
2077 | is less than fromIndex, or -1 | ||||||||
2078 | if the character does not occur before that point. | ||||||||
2079 | */ | ||||||||
2080 | sal_Int32 lastIndexOf( sal_Unicode ch, sal_Int32 fromIndex ) const | ||||||||
2081 | { | ||||||||
2082 | return rtl_ustr_lastIndexOfChar_WithLength( pData->buffer, fromIndex, ch ); | ||||||||
2083 | } | ||||||||
2084 | |||||||||
2085 | /** | ||||||||
2086 | Returns the index within this string of the first occurrence of the | ||||||||
2087 | specified substring, starting at the specified index. | ||||||||
2088 | |||||||||
2089 | If str doesn't include any character, always -1 is | ||||||||
2090 | returned. This is also the case, if both strings are empty. | ||||||||
2091 | |||||||||
2092 | @param str the substring to search for. | ||||||||
2093 | @param fromIndex the index to start the search from. | ||||||||
2094 | @return If the string argument occurs one or more times as a substring | ||||||||
2095 | within this string at the starting index, then the index | ||||||||
2096 | of the first character of the first such substring is | ||||||||
2097 | returned. If it does not occur as a substring starting | ||||||||
2098 | at fromIndex or beyond, -1 is returned. | ||||||||
2099 | */ | ||||||||
2100 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
2101 | sal_Int32 indexOf(std::u16string_view sv, sal_Int32 fromIndex = 0) const { | ||||||||
2102 | auto const n = rtl_ustr_indexOfStr_WithLength( | ||||||||
2103 | pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size()); | ||||||||
2104 | return n < 0 ? n : n + fromIndex; | ||||||||
2105 | } | ||||||||
2106 | #else | ||||||||
2107 | sal_Int32 indexOf( const OUString & str, sal_Int32 fromIndex = 0 ) const | ||||||||
2108 | { | ||||||||
2109 | sal_Int32 ret = rtl_ustr_indexOfStr_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, | ||||||||
2110 | str.pData->buffer, str.pData->length ); | ||||||||
2111 | return (ret < 0 ? ret : ret+fromIndex); | ||||||||
2112 | } | ||||||||
2113 | #endif | ||||||||
2114 | |||||||||
2115 | /** | ||||||||
2116 | @overload | ||||||||
2117 | This function accepts an ASCII string literal as its argument. | ||||||||
2118 | @since LibreOffice 3.6 | ||||||||
2119 | */ | ||||||||
2120 | template< typename T > | ||||||||
2121 | typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type indexOf( T& literal, sal_Int32 fromIndex = 0 ) const | ||||||||
2122 | { | ||||||||
2123 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2124, __extension__ __PRETTY_FUNCTION__)) | ||||||||
2124 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2124, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2125 | sal_Int32 n = rtl_ustr_indexOfAscii_WithLength( | ||||||||
2126 | pData->buffer + fromIndex, pData->length - fromIndex, | ||||||||
2127 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), | ||||||||
2128 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
2129 | return n < 0 ? n : n + fromIndex; | ||||||||
2130 | } | ||||||||
2131 | |||||||||
2132 | /** | ||||||||
2133 | Returns the index within this string of the first occurrence of the | ||||||||
2134 | specified ASCII substring, starting at the specified index. | ||||||||
2135 | |||||||||
2136 | @param str | ||||||||
2137 | the substring to be searched for. Need not be null-terminated, but must | ||||||||
2138 | be at least as long as the specified len. Must only contain characters | ||||||||
2139 | in the ASCII range 0x00--7F. | ||||||||
2140 | |||||||||
2141 | @param len | ||||||||
2142 | the length of the substring; must be non-negative. | ||||||||
2143 | |||||||||
2144 | @param fromIndex | ||||||||
2145 | the index to start the search from. Must be in the range from zero to | ||||||||
2146 | the length of this string, inclusive. | ||||||||
2147 | |||||||||
2148 | @return | ||||||||
2149 | the index (starting at 0) of the first character of the first occurrence | ||||||||
2150 | of the substring within this string starting at the given fromIndex, or | ||||||||
2151 | -1 if the substring does not occur. If len is zero, -1 is returned. | ||||||||
2152 | |||||||||
2153 | @since UDK 3.2.7 | ||||||||
2154 | */ | ||||||||
2155 | sal_Int32 indexOfAsciiL( | ||||||||
2156 | char const * str, sal_Int32 len, sal_Int32 fromIndex = 0) const | ||||||||
2157 | { | ||||||||
2158 | sal_Int32 ret = rtl_ustr_indexOfAscii_WithLength( | ||||||||
2159 | pData->buffer + fromIndex, pData->length - fromIndex, str, len); | ||||||||
2160 | return ret < 0 ? ret : ret + fromIndex; | ||||||||
2161 | } | ||||||||
2162 | |||||||||
2163 | // This overload is left undefined, to detect calls of indexOfAsciiL that | ||||||||
2164 | // erroneously use RTL_CONSTASCII_USTRINGPARAM instead of | ||||||||
2165 | // RTL_CONSTASCII_STRINGPARAM (but would lead to ambiguities on 32 bit | ||||||||
2166 | // platforms): | ||||||||
2167 | #if SAL_TYPES_SIZEOFLONG8 == 8 | ||||||||
2168 | void indexOfAsciiL(char const *, sal_Int32 len, rtl_TextEncoding) const; | ||||||||
2169 | #endif | ||||||||
2170 | |||||||||
2171 | /** | ||||||||
2172 | Returns the index within this string of the last occurrence of | ||||||||
2173 | the specified substring, searching backward starting at the end. | ||||||||
2174 | |||||||||
2175 | The returned index indicates the starting index of the substring | ||||||||
2176 | in this string. | ||||||||
2177 | If str doesn't include any character, always -1 is | ||||||||
2178 | returned. This is also the case, if both strings are empty. | ||||||||
2179 | |||||||||
2180 | @param str the substring to search for. | ||||||||
2181 | @return If the string argument occurs one or more times as a substring | ||||||||
2182 | within this string, then the index of the first character of | ||||||||
2183 | the last such substring is returned. If it does not occur as | ||||||||
2184 | a substring, -1 is returned. | ||||||||
2185 | */ | ||||||||
2186 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
2187 | sal_Int32 lastIndexOf(std::u16string_view sv) const { | ||||||||
2188 | return rtl_ustr_lastIndexOfStr_WithLength( | ||||||||
2189 | pData->buffer, pData->length, sv.data(), sv.size()); | ||||||||
2190 | } | ||||||||
2191 | #else | ||||||||
2192 | sal_Int32 lastIndexOf( const OUString & str ) const | ||||||||
2193 | { | ||||||||
2194 | return rtl_ustr_lastIndexOfStr_WithLength( pData->buffer, pData->length, | ||||||||
2195 | str.pData->buffer, str.pData->length ); | ||||||||
2196 | } | ||||||||
2197 | #endif | ||||||||
2198 | |||||||||
2199 | /** | ||||||||
2200 | Returns the index within this string of the last occurrence of | ||||||||
2201 | the specified substring, searching backward starting before the specified | ||||||||
2202 | index. | ||||||||
2203 | |||||||||
2204 | The returned index indicates the starting index of the substring | ||||||||
2205 | in this string. | ||||||||
2206 | If str doesn't include any character, always -1 is | ||||||||
2207 | returned. This is also the case, if both strings are empty. | ||||||||
2208 | |||||||||
2209 | @param str the substring to search for. | ||||||||
2210 | @param fromIndex the index before which to start the search. | ||||||||
2211 | @return If the string argument occurs one or more times as a substring | ||||||||
2212 | within this string before the starting index, then the index | ||||||||
2213 | of the first character of the last such substring is | ||||||||
2214 | returned. Otherwise, -1 is returned. | ||||||||
2215 | */ | ||||||||
2216 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
2217 | sal_Int32 lastIndexOf(std::u16string_view sv, sal_Int32 fromIndex) const { | ||||||||
2218 | return rtl_ustr_lastIndexOfStr_WithLength(pData->buffer, fromIndex, sv.data(), sv.size()); | ||||||||
2219 | } | ||||||||
2220 | #else | ||||||||
2221 | sal_Int32 lastIndexOf( const OUString & str, sal_Int32 fromIndex ) const | ||||||||
2222 | { | ||||||||
2223 | return rtl_ustr_lastIndexOfStr_WithLength( pData->buffer, fromIndex, | ||||||||
2224 | str.pData->buffer, str.pData->length ); | ||||||||
2225 | } | ||||||||
2226 | #endif | ||||||||
2227 | |||||||||
2228 | /** | ||||||||
2229 | @overload | ||||||||
2230 | This function accepts an ASCII string literal as its argument. | ||||||||
2231 | @since LibreOffice 3.6 | ||||||||
2232 | */ | ||||||||
2233 | template< typename T > | ||||||||
2234 | typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type lastIndexOf( T& literal ) const | ||||||||
2235 | { | ||||||||
2236 | assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2237, __extension__ __PRETTY_FUNCTION__)) | ||||||||
2237 | libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2237, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2238 | return rtl_ustr_lastIndexOfAscii_WithLength( | ||||||||
2239 | pData->buffer, pData->length, | ||||||||
2240 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal), | ||||||||
2241 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
2242 | } | ||||||||
2243 | |||||||||
2244 | /** | ||||||||
2245 | Returns the index within this string of the last occurrence of the | ||||||||
2246 | specified ASCII substring. | ||||||||
2247 | |||||||||
2248 | @param str | ||||||||
2249 | the substring to be searched for. Need not be null-terminated, but must | ||||||||
2250 | be at least as long as the specified len. Must only contain characters | ||||||||
2251 | in the ASCII range 0x00--7F. | ||||||||
2252 | |||||||||
2253 | @param len | ||||||||
2254 | the length of the substring; must be non-negative. | ||||||||
2255 | |||||||||
2256 | @return | ||||||||
2257 | the index (starting at 0) of the first character of the last occurrence | ||||||||
2258 | of the substring within this string, or -1 if the substring does not | ||||||||
2259 | occur. If len is zero, -1 is returned. | ||||||||
2260 | |||||||||
2261 | @since UDK 3.2.7 | ||||||||
2262 | */ | ||||||||
2263 | sal_Int32 lastIndexOfAsciiL(char const * str, sal_Int32 len) const | ||||||||
2264 | { | ||||||||
2265 | return rtl_ustr_lastIndexOfAscii_WithLength( | ||||||||
2266 | pData->buffer, pData->length, str, len); | ||||||||
2267 | } | ||||||||
2268 | |||||||||
2269 | /** | ||||||||
2270 | Returns a new string that is a substring of this string. | ||||||||
2271 | |||||||||
2272 | The substring begins at the specified beginIndex. If | ||||||||
2273 | beginIndex is negative or be greater than the length of | ||||||||
2274 | this string, behaviour is undefined. | ||||||||
2275 | |||||||||
2276 | @param beginIndex the beginning index, inclusive. | ||||||||
2277 | @return the specified substring. | ||||||||
2278 | */ | ||||||||
2279 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString copy( sal_Int32 beginIndex ) const | ||||||||
2280 | { | ||||||||
2281 | return copy(beginIndex, getLength() - beginIndex); | ||||||||
2282 | } | ||||||||
2283 | |||||||||
2284 | /** | ||||||||
2285 | Returns a new string that is a substring of this string. | ||||||||
2286 | |||||||||
2287 | The substring begins at the specified beginIndex and contains count | ||||||||
2288 | characters. If either beginIndex or count are negative, | ||||||||
2289 | or beginIndex + count are greater than the length of this string | ||||||||
2290 | then behaviour is undefined. | ||||||||
2291 | |||||||||
2292 | @param beginIndex the beginning index, inclusive. | ||||||||
2293 | @param count the number of characters. | ||||||||
2294 | @return the specified substring. | ||||||||
2295 | */ | ||||||||
2296 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString copy( sal_Int32 beginIndex, sal_Int32 count ) const | ||||||||
2297 | { | ||||||||
2298 | rtl_uString *pNew = NULL__null; | ||||||||
2299 | rtl_uString_newFromSubString( &pNew, pData, beginIndex, count ); | ||||||||
2300 | return OUString( pNew, SAL_NO_ACQUIRE ); | ||||||||
2301 | } | ||||||||
2302 | |||||||||
2303 | /** | ||||||||
2304 | Concatenates the specified string to the end of this string. | ||||||||
2305 | |||||||||
2306 | @param str the string that is concatenated to the end | ||||||||
2307 | of this string. | ||||||||
2308 | @return a string that represents the concatenation of this string | ||||||||
2309 | followed by the string argument. | ||||||||
2310 | */ | ||||||||
2311 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString concat( const OUString & str ) const | ||||||||
2312 | { | ||||||||
2313 | rtl_uString* pNew = NULL__null; | ||||||||
2314 | rtl_uString_newConcat( &pNew, pData, str.pData ); | ||||||||
2315 | return OUString( pNew, SAL_NO_ACQUIRE ); | ||||||||
2316 | } | ||||||||
2317 | |||||||||
2318 | #ifndef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" | ||||||||
2319 | friend OUString operator+( const OUString& rStr1, const OUString& rStr2 ) | ||||||||
2320 | { | ||||||||
2321 | return rStr1.concat( rStr2 ); | ||||||||
2322 | } | ||||||||
2323 | #endif | ||||||||
2324 | |||||||||
2325 | /** | ||||||||
2326 | Returns a new string resulting from replacing n = count characters | ||||||||
2327 | from position index in this string with newStr. | ||||||||
2328 | |||||||||
2329 | @param index the replacing index in str. | ||||||||
2330 | The index must be greater than or equal to 0 and | ||||||||
2331 | less than or equal to the length of the string. | ||||||||
2332 | @param count the count of characters that will be replaced | ||||||||
2333 | The count must be greater than or equal to 0 and | ||||||||
2334 | less than or equal to the length of the string minus index. | ||||||||
2335 | @param newStr the new substring. | ||||||||
2336 | @return the new string. | ||||||||
2337 | */ | ||||||||
2338 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceAt( sal_Int32 index, sal_Int32 count, const OUString& newStr ) const | ||||||||
2339 | { | ||||||||
2340 | rtl_uString* pNew = NULL__null; | ||||||||
2341 | rtl_uString_newReplaceStrAt( &pNew, pData, index, count, newStr.pData ); | ||||||||
2342 | return OUString( pNew, SAL_NO_ACQUIRE ); | ||||||||
2343 | } | ||||||||
2344 | |||||||||
2345 | /** | ||||||||
2346 | Returns a new string resulting from replacing all occurrences of | ||||||||
2347 | oldChar in this string with newChar. | ||||||||
2348 | |||||||||
2349 | If the character oldChar does not occur in the character sequence | ||||||||
2350 | represented by this object, then the string is assigned with | ||||||||
2351 | str. | ||||||||
2352 | |||||||||
2353 | @param oldChar the old character. | ||||||||
2354 | @param newChar the new character. | ||||||||
2355 | @return a string derived from this string by replacing every | ||||||||
2356 | occurrence of oldChar with newChar. | ||||||||
2357 | */ | ||||||||
2358 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replace( sal_Unicode oldChar, sal_Unicode newChar ) const | ||||||||
2359 | { | ||||||||
2360 | rtl_uString* pNew = NULL__null; | ||||||||
2361 | rtl_uString_newReplace( &pNew, pData, oldChar, newChar ); | ||||||||
2362 | return OUString( pNew, SAL_NO_ACQUIRE ); | ||||||||
2363 | } | ||||||||
2364 | |||||||||
2365 | /** | ||||||||
2366 | Returns a new string resulting from replacing the first occurrence of a | ||||||||
2367 | given substring with another substring. | ||||||||
2368 | |||||||||
2369 | @param from the substring to be replaced | ||||||||
2370 | |||||||||
2371 | @param to the replacing substring | ||||||||
2372 | |||||||||
2373 | @param[in,out] index pointer to a start index; if the pointer is | ||||||||
2374 | non-null: upon entry to the function, its value is the index into this | ||||||||
2375 | string at which to start searching for the \p from substring, the value | ||||||||
2376 | must be non-negative and not greater than this string's length; upon exiting | ||||||||
2377 | the function its value is the index into this string at which the | ||||||||
2378 | replacement took place or -1 if no replacement took place; if the pointer | ||||||||
2379 | is null, searching always starts at index 0 | ||||||||
2380 | |||||||||
2381 | @since LibreOffice 3.6 | ||||||||
2382 | */ | ||||||||
2383 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
2384 | [[nodiscard]] OUString replaceFirst( | ||||||||
2385 | std::u16string_view from, std::u16string_view to, sal_Int32 * index = nullptr) const | ||||||||
2386 | { | ||||||||
2387 | rtl_uString * s = nullptr; | ||||||||
2388 | sal_Int32 i = 0; | ||||||||
2389 | rtl_uString_newReplaceFirstUtf16LUtf16L( | ||||||||
2390 | &s, pData, from.data(), from.size(), to.data(), to.size(), | ||||||||
2391 | index == nullptr ? &i : index); | ||||||||
2392 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2393 | } | ||||||||
2394 | #else | ||||||||
2395 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceFirst( | ||||||||
2396 | OUString const & from, OUString const & to, sal_Int32 * index = NULL__null) const | ||||||||
2397 | { | ||||||||
2398 | rtl_uString * s = NULL__null; | ||||||||
2399 | sal_Int32 i = 0; | ||||||||
2400 | rtl_uString_newReplaceFirst( | ||||||||
2401 | &s, pData, from.pData, to.pData, index == NULL__null ? &i : index); | ||||||||
2402 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2403 | } | ||||||||
2404 | #endif | ||||||||
2405 | |||||||||
2406 | /** | ||||||||
2407 | Returns a new string resulting from replacing the first occurrence of a | ||||||||
2408 | given substring with another substring. | ||||||||
2409 | |||||||||
2410 | @param from ASCII string literal, the substring to be replaced | ||||||||
2411 | |||||||||
2412 | @param to the replacing substring | ||||||||
2413 | |||||||||
2414 | @param[in,out] index pointer to a start index; if the pointer is | ||||||||
2415 | non-null: upon entry to the function, its value is the index into the this | ||||||||
2416 | string at which to start searching for the \p from substring, the value | ||||||||
2417 | must be non-negative and not greater than this string's length; upon exiting | ||||||||
2418 | the function its value is the index into this string at which the | ||||||||
2419 | replacement took place or -1 if no replacement took place; if the pointer | ||||||||
2420 | is null, searching always starts at index 0 | ||||||||
2421 | |||||||||
2422 | @since LibreOffice 3.6 | ||||||||
2423 | */ | ||||||||
2424 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
2425 | template<typename T> [[nodiscard]] | ||||||||
2426 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceFirst( | ||||||||
2427 | T & from, std::u16string_view to, sal_Int32 * index = nullptr) const | ||||||||
2428 | { | ||||||||
2429 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2429, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2430 | rtl_uString * s = nullptr; | ||||||||
2431 | sal_Int32 i = 0; | ||||||||
2432 | rtl_uString_newReplaceFirstAsciiLUtf16L( | ||||||||
2433 | &s, pData, libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from), | ||||||||
2434 | libreoffice_internal::ConstCharArrayDetector<T>::length, to.data(), to.size(), | ||||||||
2435 | index == nullptr ? &i : index); | ||||||||
2436 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2437 | } | ||||||||
2438 | #else | ||||||||
2439 | template< typename T > | ||||||||
2440 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceFirst( T& from, OUString const & to, | ||||||||
2441 | sal_Int32 * index = NULL__null) const | ||||||||
2442 | { | ||||||||
2443 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2443, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2444 | rtl_uString * s = NULL__null; | ||||||||
2445 | sal_Int32 i = 0; | ||||||||
2446 | rtl_uString_newReplaceFirstAsciiL( | ||||||||
2447 | &s, pData, | ||||||||
2448 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from), | ||||||||
2449 | libreoffice_internal::ConstCharArrayDetector<T>::length, to.pData, | ||||||||
2450 | index == NULL__null ? &i : index); | ||||||||
2451 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2452 | } | ||||||||
2453 | #endif | ||||||||
2454 | |||||||||
2455 | /** | ||||||||
2456 | Returns a new string resulting from replacing the first occurrence of a | ||||||||
2457 | given substring with another substring. | ||||||||
2458 | |||||||||
2459 | @param from the substring to be replaced | ||||||||
2460 | |||||||||
2461 | @param to ASCII string literal, the replacing substring | ||||||||
2462 | |||||||||
2463 | @param[in,out] index pointer to a start index; if the pointer is | ||||||||
2464 | non-null: upon entry to the function, its value is the index into the this | ||||||||
2465 | string at which to start searching for the \p from substring, the value | ||||||||
2466 | must be non-negative and not greater than this string's length; upon exiting | ||||||||
2467 | the function its value is the index into this string at which the | ||||||||
2468 | replacement took place or -1 if no replacement took place; if the pointer | ||||||||
2469 | is null, searching always starts at index 0 | ||||||||
2470 | |||||||||
2471 | @since LibreOffice 5.1 | ||||||||
2472 | */ | ||||||||
2473 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
2474 | template<typename T> [[nodiscard]] | ||||||||
2475 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceFirst( | ||||||||
2476 | std::u16string_view from, T & to, sal_Int32 * index = nullptr) const | ||||||||
2477 | { | ||||||||
2478 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2478, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2479 | rtl_uString * s = nullptr; | ||||||||
2480 | sal_Int32 i = 0; | ||||||||
2481 | rtl_uString_newReplaceFirstUtf16LAsciiL( | ||||||||
2482 | &s, pData, from.data(), from.size(), | ||||||||
2483 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to), | ||||||||
2484 | libreoffice_internal::ConstCharArrayDetector<T>::length, index == nullptr ? &i : index); | ||||||||
2485 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2486 | } | ||||||||
2487 | #else | ||||||||
2488 | template< typename T > | ||||||||
2489 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceFirst( OUString const & from, T& to, | ||||||||
2490 | sal_Int32 * index = NULL__null) const | ||||||||
2491 | { | ||||||||
2492 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2492, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2493 | rtl_uString * s = NULL__null; | ||||||||
2494 | sal_Int32 i = 0; | ||||||||
2495 | rtl_uString_newReplaceFirstToAsciiL( | ||||||||
2496 | &s, pData, from.pData, | ||||||||
2497 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to), | ||||||||
2498 | libreoffice_internal::ConstCharArrayDetector<T>::length, | ||||||||
2499 | index == NULL__null ? &i : index); | ||||||||
2500 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2501 | } | ||||||||
2502 | #endif | ||||||||
2503 | |||||||||
2504 | /** | ||||||||
2505 | Returns a new string resulting from replacing the first occurrence of a | ||||||||
2506 | given substring with another substring. | ||||||||
2507 | |||||||||
2508 | @param from ASCII string literal, the substring to be replaced | ||||||||
2509 | |||||||||
2510 | @param to ASCII string literal, the substring to be replaced | ||||||||
2511 | |||||||||
2512 | @param[in,out] index pointer to a start index; if the pointer is | ||||||||
2513 | non-null: upon entry to the function, its value is the index into the this | ||||||||
2514 | string at which to start searching for the \p from substring, the value | ||||||||
2515 | must be non-negative and not greater than this string's length; upon exiting | ||||||||
2516 | the function its value is the index into this string at which the | ||||||||
2517 | replacement took place or -1 if no replacement took place; if the pointer | ||||||||
2518 | is null, searching always starts at index 0 | ||||||||
2519 | |||||||||
2520 | @since LibreOffice 3.6 | ||||||||
2521 | */ | ||||||||
2522 | template< typename T1, typename T2 > | ||||||||
2523 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T1, typename libreoffice_internal::ConstCharArrayDetector< T2, OUString >::Type >::Type | ||||||||
2524 | replaceFirst( T1& from, T2& to, sal_Int32 * index = NULL__null) const | ||||||||
2525 | { | ||||||||
2526 | assert(libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T1>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2526, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2527 | assert(libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T2>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2527, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2528 | rtl_uString * s = NULL__null; | ||||||||
2529 | sal_Int32 i = 0; | ||||||||
2530 | rtl_uString_newReplaceFirstAsciiLAsciiL( | ||||||||
2531 | &s, pData, | ||||||||
2532 | libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from), | ||||||||
2533 | libreoffice_internal::ConstCharArrayDetector<T1>::length, | ||||||||
2534 | libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to), | ||||||||
2535 | libreoffice_internal::ConstCharArrayDetector<T2>::length, | ||||||||
2536 | index == NULL__null ? &i : index); | ||||||||
2537 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2538 | } | ||||||||
2539 | |||||||||
2540 | /** | ||||||||
2541 | Returns a new string resulting from replacing all occurrences of a given | ||||||||
2542 | substring with another substring. | ||||||||
2543 | |||||||||
2544 | Replacing subsequent occurrences picks up only after a given replacement. | ||||||||
2545 | That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx". | ||||||||
2546 | |||||||||
2547 | @param from the substring to be replaced | ||||||||
2548 | |||||||||
2549 | @param to the replacing substring | ||||||||
2550 | |||||||||
2551 | @param fromIndex the position in the string where we will begin searching | ||||||||
2552 | |||||||||
2553 | @since LibreOffice 4.0 | ||||||||
2554 | */ | ||||||||
2555 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
2556 | [[nodiscard]] OUString replaceAll( | ||||||||
2557 | std::u16string_view from, std::u16string_view to, sal_Int32 fromIndex = 0) const | ||||||||
2558 | { | ||||||||
2559 | rtl_uString * s = nullptr; | ||||||||
2560 | rtl_uString_newReplaceAllFromIndexUtf16LUtf16L( | ||||||||
2561 | &s, pData, from.data(), from.size(), to.data(), to.size(), fromIndex); | ||||||||
2562 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2563 | } | ||||||||
2564 | #else | ||||||||
2565 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceAll( | ||||||||
2566 | OUString const & from, OUString const & to, sal_Int32 fromIndex = 0) const | ||||||||
2567 | { | ||||||||
2568 | rtl_uString * s = NULL__null; | ||||||||
2569 | rtl_uString_newReplaceAllFromIndex(&s, pData, from.pData, to.pData, fromIndex); | ||||||||
2570 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2571 | } | ||||||||
2572 | #endif | ||||||||
2573 | |||||||||
2574 | /** | ||||||||
2575 | Returns a new string resulting from replacing all occurrences of a given | ||||||||
2576 | substring with another substring. | ||||||||
2577 | |||||||||
2578 | Replacing subsequent occurrences picks up only after a given replacement. | ||||||||
2579 | That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx". | ||||||||
2580 | |||||||||
2581 | @param from ASCII string literal, the substring to be replaced | ||||||||
2582 | |||||||||
2583 | @param to the replacing substring | ||||||||
2584 | |||||||||
2585 | @since LibreOffice 3.6 | ||||||||
2586 | */ | ||||||||
2587 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
2588 | template<typename T> [[nodiscard]] | ||||||||
2589 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceAll( | ||||||||
2590 | T & from, std::u16string_view to) const | ||||||||
2591 | { | ||||||||
2592 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2592, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2593 | rtl_uString * s = nullptr; | ||||||||
2594 | rtl_uString_newReplaceAllAsciiLUtf16L( | ||||||||
2595 | &s, pData, libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from), | ||||||||
2596 | libreoffice_internal::ConstCharArrayDetector<T>::length, to.data(), to.size()); | ||||||||
2597 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2598 | } | ||||||||
2599 | #else | ||||||||
2600 | template< typename T > | ||||||||
2601 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceAll( T& from, OUString const & to) const | ||||||||
2602 | { | ||||||||
2603 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2603, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2604 | rtl_uString * s = NULL__null; | ||||||||
2605 | rtl_uString_newReplaceAllAsciiL( | ||||||||
2606 | &s, pData, | ||||||||
2607 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from), | ||||||||
2608 | libreoffice_internal::ConstCharArrayDetector<T>::length, to.pData); | ||||||||
2609 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2610 | } | ||||||||
2611 | #endif | ||||||||
2612 | |||||||||
2613 | /** | ||||||||
2614 | Returns a new string resulting from replacing all occurrences of a given | ||||||||
2615 | substring with another substring. | ||||||||
2616 | |||||||||
2617 | Replacing subsequent occurrences picks up only after a given replacement. | ||||||||
2618 | That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx". | ||||||||
2619 | |||||||||
2620 | @param from the substring to be replaced | ||||||||
2621 | |||||||||
2622 | @param to ASCII string literal, the replacing substring | ||||||||
2623 | |||||||||
2624 | @since LibreOffice 5.1 | ||||||||
2625 | */ | ||||||||
2626 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
2627 | template<typename T> [[nodiscard]] | ||||||||
2628 | typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceAll( | ||||||||
2629 | std::u16string_view from, T & to) const | ||||||||
2630 | { | ||||||||
2631 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2631, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2632 | rtl_uString * s = nullptr; | ||||||||
2633 | rtl_uString_newReplaceAllUtf16LAsciiL( | ||||||||
2634 | &s, pData, from.data(), from.size(), | ||||||||
2635 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to), | ||||||||
2636 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
2637 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2638 | } | ||||||||
2639 | #else | ||||||||
2640 | template< typename T > | ||||||||
2641 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceAll( OUString const & from, T& to) const | ||||||||
2642 | { | ||||||||
2643 | assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2643, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2644 | rtl_uString * s = NULL__null; | ||||||||
2645 | rtl_uString_newReplaceAllToAsciiL( | ||||||||
2646 | &s, pData, from.pData, | ||||||||
2647 | libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to), | ||||||||
2648 | libreoffice_internal::ConstCharArrayDetector<T>::length); | ||||||||
2649 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2650 | } | ||||||||
2651 | #endif | ||||||||
2652 | |||||||||
2653 | /** | ||||||||
2654 | Returns a new string resulting from replacing all occurrences of a given | ||||||||
2655 | substring with another substring. | ||||||||
2656 | |||||||||
2657 | Replacing subsequent occurrences picks up only after a given replacement. | ||||||||
2658 | That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx". | ||||||||
2659 | |||||||||
2660 | @param from ASCII string literal, the substring to be replaced | ||||||||
2661 | |||||||||
2662 | @param to ASCII string literal, the substring to be replaced | ||||||||
2663 | |||||||||
2664 | @since LibreOffice 3.6 | ||||||||
2665 | */ | ||||||||
2666 | template< typename T1, typename T2 > | ||||||||
2667 | SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T1, typename libreoffice_internal::ConstCharArrayDetector< T2, OUString >::Type >::Type | ||||||||
2668 | replaceAll( T1& from, T2& to ) const | ||||||||
2669 | { | ||||||||
2670 | assert(libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T1>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2670, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2671 | assert(libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector <T2>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to)" , "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 2671, __extension__ __PRETTY_FUNCTION__)); | ||||||||
2672 | rtl_uString * s = NULL__null; | ||||||||
2673 | rtl_uString_newReplaceAllAsciiLAsciiL( | ||||||||
2674 | &s, pData, | ||||||||
2675 | libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from), | ||||||||
2676 | libreoffice_internal::ConstCharArrayDetector<T1>::length, | ||||||||
2677 | libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to), | ||||||||
2678 | libreoffice_internal::ConstCharArrayDetector<T2>::length); | ||||||||
2679 | return OUString(s, SAL_NO_ACQUIRE); | ||||||||
2680 | } | ||||||||
2681 | |||||||||
2682 | /** | ||||||||
2683 | Converts from this string all ASCII uppercase characters (65-90) | ||||||||
2684 | to ASCII lowercase characters (97-122). | ||||||||
2685 | |||||||||
2686 | This function can't be used for language specific conversion. | ||||||||
2687 | If the string doesn't contain characters which must be converted, | ||||||||
2688 | then the new string is assigned with str. | ||||||||
2689 | |||||||||
2690 | @return the string, converted to ASCII lowercase. | ||||||||
2691 | */ | ||||||||
2692 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString toAsciiLowerCase() const | ||||||||
2693 | { | ||||||||
2694 | rtl_uString* pNew = NULL__null; | ||||||||
2695 | rtl_uString_newToAsciiLowerCase( &pNew, pData ); | ||||||||
2696 | return OUString( pNew, SAL_NO_ACQUIRE ); | ||||||||
2697 | } | ||||||||
2698 | |||||||||
2699 | /** | ||||||||
2700 | Converts from this string all ASCII lowercase characters (97-122) | ||||||||
2701 | to ASCII uppercase characters (65-90). | ||||||||
2702 | |||||||||
2703 | This function can't be used for language specific conversion. | ||||||||
2704 | If the string doesn't contain characters which must be converted, | ||||||||
2705 | then the new string is assigned with str. | ||||||||
2706 | |||||||||
2707 | @return the string, converted to ASCII uppercase. | ||||||||
2708 | */ | ||||||||
2709 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString toAsciiUpperCase() const | ||||||||
2710 | { | ||||||||
2711 | rtl_uString* pNew = NULL__null; | ||||||||
2712 | rtl_uString_newToAsciiUpperCase( &pNew, pData ); | ||||||||
2713 | return OUString( pNew, SAL_NO_ACQUIRE ); | ||||||||
2714 | } | ||||||||
2715 | |||||||||
2716 | /** | ||||||||
2717 | Returns a new string resulting from removing white space from both ends | ||||||||
2718 | of the string. | ||||||||
2719 | |||||||||
2720 | All characters that have codes less than or equal to | ||||||||
2721 | 32 (the space character), and Unicode General Punctuation area Space | ||||||||
2722 | and some Control characters are considered to be white space (see | ||||||||
2723 | rtl_ImplIsWhitespace). | ||||||||
2724 | If the string doesn't contain white spaces at both ends, | ||||||||
2725 | then the new string is assigned with str. | ||||||||
2726 | |||||||||
2727 | @return the string, with white space removed from the front and end. | ||||||||
2728 | */ | ||||||||
2729 | SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString trim() const | ||||||||
2730 | { | ||||||||
2731 | rtl_uString* pNew = NULL__null; | ||||||||
2732 | rtl_uString_newTrim( &pNew, pData ); | ||||||||
2733 | return OUString( pNew, SAL_NO_ACQUIRE ); | ||||||||
2734 | } | ||||||||
2735 | |||||||||
2736 | /** | ||||||||
2737 | Returns a token in the string. | ||||||||
2738 | |||||||||
2739 | Example: | ||||||||
2740 | sal_Int32 nIndex = 0; | ||||||||
2741 | do | ||||||||
2742 | { | ||||||||
2743 | ... | ||||||||
2744 | OUString aToken = aStr.getToken( 0, ';', nIndex ); | ||||||||
2745 | ... | ||||||||
2746 | } | ||||||||
2747 | while ( nIndex >= 0 ); | ||||||||
2748 | |||||||||
2749 | @param token the number of the token to return | ||||||||
2750 | @param cTok the character which separate the tokens. | ||||||||
2751 | @param index the position at which the token is searched in the | ||||||||
2752 | string. | ||||||||
2753 | The index must not be greater than the length of the | ||||||||
2754 | string. | ||||||||
2755 | This param is set to the position of the | ||||||||
2756 | next token or to -1, if it is the last token. | ||||||||
2757 | @return the token; if either token or index is negative, an empty token | ||||||||
2758 | is returned (and index is set to -1) | ||||||||
2759 | */ | ||||||||
2760 | OUString getToken( sal_Int32 token, sal_Unicode cTok, sal_Int32& index ) const | ||||||||
2761 | { | ||||||||
2762 | rtl_uString * pNew = NULL__null; | ||||||||
2763 | index = rtl_uString_getToken( &pNew, pData, token, cTok, index ); | ||||||||
2764 | return OUString( pNew, SAL_NO_ACQUIRE ); | ||||||||
2765 | } | ||||||||
2766 | |||||||||
2767 | /** | ||||||||
2768 | Returns a token from the string. | ||||||||
2769 | |||||||||
2770 | The same as getToken(sal_Int32, sal_Unicode, sal_Int32 &), but always | ||||||||
2771 | passing in 0 as the start index in the third argument. | ||||||||
2772 | |||||||||
2773 | @param count the number of the token to return, starting with 0 | ||||||||
2774 | @param separator the character which separates the tokens | ||||||||
2775 | |||||||||
2776 | @return the given token, or an empty string | ||||||||
2777 | |||||||||
2778 | @since LibreOffice 3.6 | ||||||||
2779 | */ | ||||||||
2780 | OUString getToken(sal_Int32 count, sal_Unicode separator) const { | ||||||||
2781 | sal_Int32 n = 0; | ||||||||
2782 | return getToken(count, separator, n); | ||||||||
2783 | } | ||||||||
2784 | |||||||||
2785 | /** | ||||||||
2786 | Returns the Boolean value from this string. | ||||||||
2787 | |||||||||
2788 | This function can't be used for language specific conversion. | ||||||||
2789 | |||||||||
2790 | @return true, if the string is 1 or "True" in any ASCII case. | ||||||||
2791 | false in any other case. | ||||||||
2792 | */ | ||||||||
2793 | bool toBoolean() const | ||||||||
2794 | { | ||||||||
2795 | return rtl_ustr_toBoolean( pData->buffer ); | ||||||||
2796 | } | ||||||||
2797 | |||||||||
2798 | /** | ||||||||
2799 | Returns the first character from this string. | ||||||||
2800 | |||||||||
2801 | @return the first character from this string or 0, if this string | ||||||||
2802 | is empty. | ||||||||
2803 | */ | ||||||||
2804 | sal_Unicode toChar() const | ||||||||
2805 | { | ||||||||
2806 | return pData->buffer[0]; | ||||||||
2807 | } | ||||||||
2808 | |||||||||
2809 | /** | ||||||||
2810 | Returns the int32 value from this string. | ||||||||
2811 | |||||||||
2812 | This function can't be used for language specific conversion. | ||||||||
2813 | |||||||||
2814 | @param radix the radix (between 2 and 36) | ||||||||
2815 | @return the int32 represented from this string. | ||||||||
2816 | 0 if this string represents no number or one of too large | ||||||||
2817 | magnitude. | ||||||||
2818 | */ | ||||||||
2819 | sal_Int32 toInt32( sal_Int16 radix = 10 ) const | ||||||||
2820 | { | ||||||||
2821 | return rtl_ustr_toInt32( pData->buffer, radix ); | ||||||||
2822 | } | ||||||||
2823 | |||||||||
2824 | /** | ||||||||
2825 | Returns the uint32 value from this string. | ||||||||
2826 | |||||||||
2827 | This function can't be used for language specific conversion. | ||||||||
2828 | |||||||||
2829 | @param radix the radix (between 2 and 36) | ||||||||
2830 | @return the uint32 represented from this string. | ||||||||
2831 | 0 if this string represents no number or one of too large | ||||||||
2832 | magnitude. | ||||||||
2833 | |||||||||
2834 | @since LibreOffice 4.2 | ||||||||
2835 | */ | ||||||||
2836 | sal_uInt32 toUInt32( sal_Int16 radix = 10 ) const | ||||||||
2837 | { | ||||||||
2838 | return rtl_ustr_toUInt32( pData->buffer, radix ); | ||||||||
2839 | } | ||||||||
2840 | |||||||||
2841 | /** | ||||||||
2842 | Returns the int64 value from this string. | ||||||||
2843 | |||||||||
2844 | This function can't be used for language specific conversion. | ||||||||
2845 | |||||||||
2846 | @param radix the radix (between 2 and 36) | ||||||||
2847 | @return the int64 represented from this string. | ||||||||
2848 | 0 if this string represents no number or one of too large | ||||||||
2849 | magnitude. | ||||||||
2850 | */ | ||||||||
2851 | sal_Int64 toInt64( sal_Int16 radix = 10 ) const | ||||||||
2852 | { | ||||||||
2853 | return rtl_ustr_toInt64( pData->buffer, radix ); | ||||||||
2854 | } | ||||||||
2855 | |||||||||
2856 | /** | ||||||||
2857 | Returns the uint64 value from this string. | ||||||||
2858 | |||||||||
2859 | This function can't be used for language specific conversion. | ||||||||
2860 | |||||||||
2861 | @param radix the radix (between 2 and 36) | ||||||||
2862 | @return the uint64 represented from this string. | ||||||||
2863 | 0 if this string represents no number or one of too large | ||||||||
2864 | magnitude. | ||||||||
2865 | |||||||||
2866 | @since LibreOffice 4.1 | ||||||||
2867 | */ | ||||||||
2868 | sal_uInt64 toUInt64( sal_Int16 radix = 10 ) const | ||||||||
2869 | { | ||||||||
2870 | return rtl_ustr_toUInt64( pData->buffer, radix ); | ||||||||
2871 | } | ||||||||
2872 | |||||||||
2873 | /** | ||||||||
2874 | Returns the float value from this string. | ||||||||
2875 | |||||||||
2876 | This function can't be used for language specific conversion. | ||||||||
2877 | |||||||||
2878 | @return the float represented from this string. | ||||||||
2879 | 0.0 if this string represents no number. | ||||||||
2880 | */ | ||||||||
2881 | float toFloat() const | ||||||||
2882 | { | ||||||||
2883 | return rtl_ustr_toFloat( pData->buffer ); | ||||||||
2884 | } | ||||||||
2885 | |||||||||
2886 | /** | ||||||||
2887 | Returns the double value from this string. | ||||||||
2888 | |||||||||
2889 | This function can't be used for language specific conversion. | ||||||||
2890 | |||||||||
2891 | @return the double represented from this string. | ||||||||
2892 | 0.0 if this string represents no number. | ||||||||
2893 | */ | ||||||||
2894 | double toDouble() const | ||||||||
2895 | { | ||||||||
2896 | return rtl_ustr_toDouble( pData->buffer ); | ||||||||
2897 | } | ||||||||
2898 | |||||||||
2899 | |||||||||
2900 | /** | ||||||||
2901 | Return a canonical representation for a string. | ||||||||
2902 | |||||||||
2903 | A pool of strings, initially empty is maintained privately | ||||||||
2904 | by the string class. On invocation, if present in the pool | ||||||||
2905 | the original string will be returned. Otherwise this string, | ||||||||
2906 | or a copy thereof will be added to the pool and returned. | ||||||||
2907 | |||||||||
2908 | @return | ||||||||
2909 | a version of the string from the pool. | ||||||||
2910 | |||||||||
2911 | @exception std::bad_alloc is thrown if an out-of-memory condition occurs | ||||||||
2912 | |||||||||
2913 | @since UDK 3.2.7 | ||||||||
2914 | */ | ||||||||
2915 | OUString intern() const | ||||||||
2916 | { | ||||||||
2917 | rtl_uString * pNew = NULL__null; | ||||||||
2918 | rtl_uString_intern( &pNew, pData ); | ||||||||
2919 | if (pNew == NULL__null) { | ||||||||
2920 | throw std::bad_alloc(); | ||||||||
2921 | } | ||||||||
2922 | return OUString( pNew, SAL_NO_ACQUIRE ); | ||||||||
2923 | } | ||||||||
2924 | |||||||||
2925 | /** | ||||||||
2926 | Return a canonical representation for a converted string. | ||||||||
2927 | |||||||||
2928 | A pool of strings, initially empty is maintained privately | ||||||||
2929 | by the string class. On invocation, if present in the pool | ||||||||
2930 | the original string will be returned. Otherwise this string, | ||||||||
2931 | or a copy thereof will be added to the pool and returned. | ||||||||
2932 | |||||||||
2933 | @param value a 8-Bit character array. | ||||||||
2934 | @param length the number of character which should be converted. | ||||||||
2935 | The 8-Bit character array length must be | ||||||||
2936 | greater than or equal to this value. | ||||||||
2937 | @param encoding the text encoding from which the 8-Bit character | ||||||||
2938 | sequence should be converted. | ||||||||
2939 | @param convertFlags flags which controls the conversion. | ||||||||
2940 | see RTL_TEXTTOUNICODE_FLAGS_... | ||||||||
2941 | @param pInfo pointer to return conversion status or NULL. | ||||||||
2942 | |||||||||
2943 | @return | ||||||||
2944 | a version of the converted string from the pool. | ||||||||
2945 | |||||||||
2946 | @exception std::bad_alloc is thrown if an out-of-memory condition occurs | ||||||||
2947 | |||||||||
2948 | @since UDK 3.2.7 | ||||||||
2949 | */ | ||||||||
2950 | static OUString intern( const char * value, sal_Int32 length, | ||||||||
2951 | rtl_TextEncoding encoding, | ||||||||
2952 | sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300 )), | ||||||||
2953 | sal_uInt32 *pInfo = NULL__null ) | ||||||||
2954 | { | ||||||||
2955 | rtl_uString * pNew = NULL__null; | ||||||||
2956 | rtl_uString_internConvert( &pNew, value, length, encoding, | ||||||||
2957 | convertFlags, pInfo ); | ||||||||
2958 | if (pNew == NULL__null) { | ||||||||
2959 | throw std::bad_alloc(); | ||||||||
2960 | } | ||||||||
2961 | return OUString( pNew, SAL_NO_ACQUIRE ); | ||||||||
2962 | } | ||||||||
2963 | |||||||||
2964 | /** | ||||||||
2965 | Converts to an OString, signalling failure. | ||||||||
2966 | |||||||||
2967 | @param pTarget | ||||||||
2968 | An out parameter receiving the converted OString. Must not be null; the | ||||||||
2969 | contents are not modified if conversion fails (convertToOString returns | ||||||||
2970 | false). | ||||||||
2971 | |||||||||
2972 | @param nEncoding | ||||||||
2973 | The text encoding to convert into. Must be an octet encoding (i.e., | ||||||||
2974 | rtl_isOctetTextEncoding(nEncoding) must return true). | ||||||||
2975 | |||||||||
2976 | @param nFlags | ||||||||
2977 | A combination of RTL_UNICODETOTEXT_FLAGS that detail how to do the | ||||||||
2978 | conversion (see rtl_convertUnicodeToText). RTL_UNICODETOTEXT_FLAGS_FLUSH | ||||||||
2979 | need not be included, it is implicitly assumed. Typical uses are either | ||||||||
2980 | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | | ||||||||
2981 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR (fail if a Unicode character cannot | ||||||||
2982 | be converted to the target nEncoding) or OUSTRING_TO_OSTRING_CVTFLAGS | ||||||||
2983 | (make a best efforts conversion). | ||||||||
2984 | |||||||||
2985 | @return | ||||||||
2986 | True if the conversion succeeded, false otherwise. | ||||||||
2987 | */ | ||||||||
2988 | bool convertToString(OString * pTarget, rtl_TextEncoding nEncoding, | ||||||||
2989 | sal_uInt32 nFlags) const | ||||||||
2990 | { | ||||||||
2991 | return rtl_convertUStringToString(&pTarget->pData, pData->buffer, | ||||||||
2992 | pData->length, nEncoding, nFlags); | ||||||||
2993 | } | ||||||||
2994 | |||||||||
2995 | /** Iterate through this string based on code points instead of UTF-16 code | ||||||||
2996 | units. | ||||||||
2997 | |||||||||
2998 | See Chapter 3 of The Unicode Standard 5.0 (Addison--Wesley, 2006) for | ||||||||
2999 | definitions of the various terms used in this description. | ||||||||
3000 | |||||||||
3001 | This string is interpreted as a sequence of zero or more UTF-16 code | ||||||||
3002 | units. For each index into this sequence (from zero to one less than | ||||||||
3003 | the length of the sequence, inclusive), a code point represented | ||||||||
3004 | starting at the given index is computed as follows: | ||||||||
3005 | |||||||||
3006 | - If the UTF-16 code unit addressed by the index constitutes a | ||||||||
3007 | well-formed UTF-16 code unit sequence, the computed code point is the | ||||||||
3008 | scalar value encoded by that UTF-16 code unit sequence. | ||||||||
3009 | |||||||||
3010 | - Otherwise, if the index is at least two UTF-16 code units away from | ||||||||
3011 | the end of the sequence, and the sequence of two UTF-16 code units | ||||||||
3012 | addressed by the index constitutes a well-formed UTF-16 code unit | ||||||||
3013 | sequence, the computed code point is the scalar value encoded by that | ||||||||
3014 | UTF-16 code unit sequence. | ||||||||
3015 | |||||||||
3016 | - Otherwise, the computed code point is the UTF-16 code unit addressed | ||||||||
3017 | by the index. (This last case catches unmatched surrogates as well as | ||||||||
3018 | indices pointing into the middle of surrogate pairs.) | ||||||||
3019 | |||||||||
3020 | @param indexUtf16 | ||||||||
3021 | pointer to a UTF-16 based index into this string; must not be null. On | ||||||||
3022 | entry, the index must be in the range from zero to the length of this | ||||||||
3023 | string (in UTF-16 code units), inclusive. Upon successful return, the | ||||||||
3024 | index will be updated to address the UTF-16 code unit that is the given | ||||||||
3025 | incrementCodePoints away from the initial index. | ||||||||
3026 | |||||||||
3027 | @param incrementCodePoints | ||||||||
3028 | the number of code points to move the given *indexUtf16. If | ||||||||
3029 | non-negative, moving is done after determining the code point at the | ||||||||
3030 | index. If negative, moving is done before determining the code point | ||||||||
3031 | at the (then updated) index. The value must be such that the resulting | ||||||||
3032 | UTF-16 based index is in the range from zero to the length of this | ||||||||
3033 | string (in UTF-16 code units), inclusive. | ||||||||
3034 | |||||||||
3035 | @return | ||||||||
3036 | the code point (an integer in the range from 0 to 0x10FFFF, inclusive) | ||||||||
3037 | that is represented within this string starting at the index computed as | ||||||||
3038 | follows: If incrementCodePoints is non-negative, the index is the | ||||||||
3039 | initial value of *indexUtf16; if incrementCodePoints is negative, the | ||||||||
3040 | index is the updated value of *indexUtf16. In either case, the computed | ||||||||
3041 | index must be in the range from zero to one less than the length of this | ||||||||
3042 | string (in UTF-16 code units), inclusive. | ||||||||
3043 | |||||||||
3044 | @since UDK 3.2.7 | ||||||||
3045 | */ | ||||||||
3046 | sal_uInt32 iterateCodePoints( | ||||||||
3047 | sal_Int32 * indexUtf16, sal_Int32 incrementCodePoints = 1) const | ||||||||
3048 | { | ||||||||
3049 | return rtl_uString_iterateCodePoints( | ||||||||
3050 | pData, indexUtf16, incrementCodePoints); | ||||||||
3051 | } | ||||||||
3052 | |||||||||
3053 | /** | ||||||||
3054 | * Convert an OString to an OUString, assuming that the OString is | ||||||||
3055 | * UTF-8-encoded. | ||||||||
3056 | * | ||||||||
3057 | * @param rSource | ||||||||
3058 | * an OString to convert | ||||||||
3059 | * | ||||||||
3060 | * @since LibreOffice 4.4 | ||||||||
3061 | */ | ||||||||
3062 | static OUString fromUtf8(const OString& rSource) | ||||||||
3063 | { | ||||||||
3064 | OUString aTarget; | ||||||||
3065 | bool bSuccess = rtl_convertStringToUString(&aTarget.pData, | ||||||||
3066 | rSource.getStr(), | ||||||||
3067 | rSource.getLength(), | ||||||||
3068 | RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)), | ||||||||
3069 | RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR((sal_uInt32)0x0001)|RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR((sal_uInt32)0x0010)|RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR((sal_uInt32)0x0100)); | ||||||||
3070 | (void) bSuccess; | ||||||||
3071 | assert(bSuccess)(static_cast <bool> (bSuccess) ? void (0) : __assert_fail ("bSuccess", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 3071, __extension__ __PRETTY_FUNCTION__)); | ||||||||
3072 | return aTarget; | ||||||||
3073 | } | ||||||||
3074 | |||||||||
3075 | /** | ||||||||
3076 | * Convert this string to an OString, assuming that the string can be | ||||||||
3077 | * UTF-8-encoded successfully. | ||||||||
3078 | * | ||||||||
3079 | * In other words, you must not use this method on a random sequence of | ||||||||
3080 | * UTF-16 code units, but only at places where it is assumed that the | ||||||||
3081 | * content is a proper string. | ||||||||
3082 | * | ||||||||
3083 | * @since LibreOffice 4.4 | ||||||||
3084 | */ | ||||||||
3085 | OString toUtf8() const | ||||||||
3086 | { | ||||||||
3087 | OString aTarget; | ||||||||
3088 | bool bSuccess = rtl_convertUStringToString(&aTarget.pData, | ||||||||
3089 | getStr(), | ||||||||
3090 | getLength(), | ||||||||
3091 | RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)), | ||||||||
3092 | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR((sal_uInt32)0x0001)|RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR((sal_uInt32)0x0010)); | ||||||||
3093 | (void) bSuccess; | ||||||||
3094 | assert(bSuccess)(static_cast <bool> (bSuccess) ? void (0) : __assert_fail ("bSuccess", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx" , 3094, __extension__ __PRETTY_FUNCTION__)); | ||||||||
3095 | return aTarget; | ||||||||
3096 | } | ||||||||
3097 | |||||||||
3098 | #ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" | ||||||||
3099 | |||||||||
3100 | static OUStringNumber< int > number( int i, sal_Int16 radix = 10 ) | ||||||||
3101 | { | ||||||||
3102 | return OUStringNumber< int >( i, radix ); | ||||||||
3103 | } | ||||||||
3104 | static OUStringNumber< long long > number( long long ll, sal_Int16 radix = 10 ) | ||||||||
3105 | { | ||||||||
3106 | return OUStringNumber< long long >( ll, radix ); | ||||||||
3107 | } | ||||||||
3108 | static OUStringNumber< unsigned long long > number( unsigned long long ll, sal_Int16 radix = 10 ) | ||||||||
3109 | { | ||||||||
3110 | return OUStringNumber< unsigned long long >( ll, radix ); | ||||||||
3111 | } | ||||||||
3112 | static OUStringNumber< unsigned long long > number( unsigned int i, sal_Int16 radix = 10 ) | ||||||||
3113 | { | ||||||||
3114 | return number( static_cast< unsigned long long >( i ), radix ); | ||||||||
3115 | } | ||||||||
3116 | static OUStringNumber< long long > number( long i, sal_Int16 radix = 10) | ||||||||
3117 | { | ||||||||
3118 | return number( static_cast< long long >( i ), radix ); | ||||||||
3119 | } | ||||||||
3120 | static OUStringNumber< unsigned long long > number( unsigned long i, sal_Int16 radix = 10 ) | ||||||||
3121 | { | ||||||||
3122 | return number( static_cast< unsigned long long >( i ), radix ); | ||||||||
3123 | } | ||||||||
3124 | static OUStringNumber< float > number( float f ) | ||||||||
3125 | { | ||||||||
3126 | return OUStringNumber< float >( f ); | ||||||||
3127 | } | ||||||||
3128 | static OUStringNumber< double > number( double d ) | ||||||||
3129 | { | ||||||||
3130 | return OUStringNumber< double >( d ); | ||||||||
3131 | } | ||||||||
3132 | #else | ||||||||
3133 | /** | ||||||||
3134 | Returns the string representation of the integer argument. | ||||||||
3135 | |||||||||
3136 | This function can't be used for language specific conversion. | ||||||||
3137 | |||||||||
3138 | @param i an integer value | ||||||||
3139 | @param radix the radix (between 2 and 36) | ||||||||
3140 | @return a string with the string representation of the argument. | ||||||||
3141 | @since LibreOffice 4.1 | ||||||||
3142 | */ | ||||||||
3143 | static OUString number( int i, sal_Int16 radix = 10 ) | ||||||||
3144 | { | ||||||||
3145 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT3233]; | ||||||||
3146 | return OUString(aBuf, rtl_ustr_valueOfInt32(aBuf, i, radix)); | ||||||||
3147 | } | ||||||||
3148 | /// @overload | ||||||||
3149 | /// @since LibreOffice 4.1 | ||||||||
3150 | static OUString number( unsigned int i, sal_Int16 radix = 10 ) | ||||||||
3151 | { | ||||||||
3152 | return number( static_cast< unsigned long long >( i ), radix ); | ||||||||
3153 | } | ||||||||
3154 | /// @overload | ||||||||
3155 | /// @since LibreOffice 4.1 | ||||||||
3156 | static OUString number( long i, sal_Int16 radix = 10) | ||||||||
3157 | { | ||||||||
3158 | return number( static_cast< long long >( i ), radix ); | ||||||||
3159 | } | ||||||||
3160 | /// @overload | ||||||||
3161 | /// @since LibreOffice 4.1 | ||||||||
3162 | static OUString number( unsigned long i, sal_Int16 radix = 10 ) | ||||||||
3163 | { | ||||||||
3164 | return number( static_cast< unsigned long long >( i ), radix ); | ||||||||
3165 | } | ||||||||
3166 | /// @overload | ||||||||
3167 | /// @since LibreOffice 4.1 | ||||||||
3168 | static OUString number( long long ll, sal_Int16 radix = 10 ) | ||||||||
3169 | { | ||||||||
3170 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT6465]; | ||||||||
3171 | return OUString(aBuf, rtl_ustr_valueOfInt64(aBuf, ll, radix)); | ||||||||
3172 | } | ||||||||
3173 | /// @overload | ||||||||
3174 | /// @since LibreOffice 4.1 | ||||||||
3175 | static OUString number( unsigned long long ll, sal_Int16 radix = 10 ) | ||||||||
3176 | { | ||||||||
3177 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFUINT6465]; | ||||||||
3178 | return OUString(aBuf, rtl_ustr_valueOfUInt64(aBuf, ll, radix)); | ||||||||
3179 | } | ||||||||
3180 | |||||||||
3181 | /** | ||||||||
3182 | Returns the string representation of the float argument. | ||||||||
3183 | |||||||||
3184 | This function can't be used for language specific conversion. | ||||||||
3185 | |||||||||
3186 | @param f a float. | ||||||||
3187 | @return a string with the decimal representation of the argument. | ||||||||
3188 | @since LibreOffice 4.1 | ||||||||
3189 | */ | ||||||||
3190 | static OUString number( float f ) | ||||||||
3191 | { | ||||||||
3192 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFFLOAT15]; | ||||||||
3193 | return OUString(aBuf, rtl_ustr_valueOfFloat(aBuf, f)); | ||||||||
3194 | } | ||||||||
3195 | |||||||||
3196 | /** | ||||||||
3197 | Returns the string representation of the double argument. | ||||||||
3198 | |||||||||
3199 | This function can't be used for language specific conversion. | ||||||||
3200 | |||||||||
3201 | @param d a double. | ||||||||
3202 | @return a string with the decimal representation of the argument. | ||||||||
3203 | @since LibreOffice 4.1 | ||||||||
3204 | */ | ||||||||
3205 | static OUString number( double d ) | ||||||||
3206 | { | ||||||||
3207 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFDOUBLE25]; | ||||||||
3208 | return OUString(aBuf, rtl_ustr_valueOfDouble(aBuf, d)); | ||||||||
3209 | } | ||||||||
3210 | #endif | ||||||||
3211 | |||||||||
3212 | /** | ||||||||
3213 | Returns the string representation of the sal_Bool argument. | ||||||||
3214 | |||||||||
3215 | If the sal_Bool is true, the string "true" is returned. | ||||||||
3216 | If the sal_Bool is false, the string "false" is returned. | ||||||||
3217 | This function can't be used for language specific conversion. | ||||||||
3218 | |||||||||
3219 | @param b a sal_Bool. | ||||||||
3220 | @return a string with the string representation of the argument. | ||||||||
3221 | @deprecated use boolean() | ||||||||
3222 | */ | ||||||||
3223 | SAL_DEPRECATED("use boolean()")__attribute__((deprecated("use boolean()"))) static OUString valueOf( sal_Bool b ) | ||||||||
3224 | { | ||||||||
3225 | return boolean(b); | ||||||||
3226 | } | ||||||||
3227 | |||||||||
3228 | /** | ||||||||
3229 | Returns the string representation of the boolean argument. | ||||||||
3230 | |||||||||
3231 | If the argument is true, the string "true" is returned. | ||||||||
3232 | If the argument is false, the string "false" is returned. | ||||||||
3233 | This function can't be used for language specific conversion. | ||||||||
3234 | |||||||||
3235 | @param b a bool. | ||||||||
3236 | @return a string with the string representation of the argument. | ||||||||
3237 | @since LibreOffice 4.1 | ||||||||
3238 | */ | ||||||||
3239 | static OUString boolean( bool b ) | ||||||||
3240 | { | ||||||||
3241 | sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFBOOLEAN6]; | ||||||||
3242 | return OUString(aBuf, rtl_ustr_valueOfBoolean(aBuf, b)); | ||||||||
3243 | } | ||||||||
3244 | |||||||||
3245 | /** | ||||||||
3246 | Returns the string representation of the char argument. | ||||||||
3247 | |||||||||
3248 | @param c a character. | ||||||||
3249 | @return a string with the string representation of the argument. | ||||||||
3250 | @deprecated use operator, function or constructor taking char or sal_Unicode argument | ||||||||
3251 | */ | ||||||||
3252 | SAL_DEPRECATED("convert to OUString or use directly")__attribute__((deprecated("convert to OUString or use directly" ))) static OUString valueOf( sal_Unicode c ) | ||||||||
3253 | { | ||||||||
3254 | return OUString( &c, 1 ); | ||||||||
3255 | } | ||||||||
3256 | |||||||||
3257 | /** | ||||||||
3258 | Returns the string representation of the int argument. | ||||||||
3259 | |||||||||
3260 | This function can't be used for language specific conversion. | ||||||||
3261 | |||||||||
3262 | @param i a int32. | ||||||||
3263 | @param radix the radix (between 2 and 36) | ||||||||
3264 | @return a string with the string representation of the argument. | ||||||||
3265 | @deprecated use number() | ||||||||
3266 | */ | ||||||||
3267 | SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( sal_Int32 i, sal_Int16 radix = 10 ) | ||||||||
3268 | { | ||||||||
3269 | return number( i, radix ); | ||||||||
3270 | } | ||||||||
3271 | |||||||||
3272 | /** | ||||||||
3273 | Returns the string representation of the long argument. | ||||||||
3274 | |||||||||
3275 | This function can't be used for language specific conversion. | ||||||||
3276 | |||||||||
3277 | @param ll a int64. | ||||||||
3278 | @param radix the radix (between 2 and 36) | ||||||||
3279 | @return a string with the string representation of the argument. | ||||||||
3280 | @deprecated use number() | ||||||||
3281 | */ | ||||||||
3282 | SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( sal_Int64 ll, sal_Int16 radix = 10 ) | ||||||||
3283 | { | ||||||||
3284 | return number( ll, radix ); | ||||||||
3285 | } | ||||||||
3286 | |||||||||
3287 | /** | ||||||||
3288 | Returns the string representation of the float argument. | ||||||||
3289 | |||||||||
3290 | This function can't be used for language specific conversion. | ||||||||
3291 | |||||||||
3292 | @param f a float. | ||||||||
3293 | @return a string with the string representation of the argument. | ||||||||
3294 | @deprecated use number() | ||||||||
3295 | */ | ||||||||
3296 | SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( float f ) | ||||||||
3297 | { | ||||||||
3298 | return number(f); | ||||||||
3299 | } | ||||||||
3300 | |||||||||
3301 | /** | ||||||||
3302 | Returns the string representation of the double argument. | ||||||||
3303 | |||||||||
3304 | This function can't be used for language specific conversion. | ||||||||
3305 | |||||||||
3306 | @param d a double. | ||||||||
3307 | @return a string with the string representation of the argument. | ||||||||
3308 | @deprecated use number() | ||||||||
3309 | */ | ||||||||
3310 | SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( double d ) | ||||||||
3311 | { | ||||||||
3312 | return number(d); | ||||||||
3313 | } | ||||||||
3314 | |||||||||
3315 | /** | ||||||||
3316 | Returns an OUString copied without conversion from an ASCII | ||||||||
3317 | character string. | ||||||||
3318 | |||||||||
3319 | Since this method is optimized for performance, the ASCII character | ||||||||
3320 | values are not converted in any way. The caller has to make sure that | ||||||||
3321 | all ASCII characters are in the allowed range between 0 and 127. | ||||||||
3322 | The ASCII string must be NULL-terminated. | ||||||||
3323 | |||||||||
3324 | Note that for string literals it is simpler and more efficient | ||||||||
3325 | to directly use the OUString constructor. | ||||||||
3326 | |||||||||
3327 | @param value the 8-Bit ASCII character string | ||||||||
3328 | @return a string with the string representation of the argument. | ||||||||
3329 | */ | ||||||||
3330 | static OUString createFromAscii( const char * value ) | ||||||||
3331 | { | ||||||||
3332 | rtl_uString* pNew = NULL__null; | ||||||||
3333 | rtl_uString_newFromAscii( &pNew, value ); | ||||||||
3334 | return OUString( pNew, SAL_NO_ACQUIRE ); | ||||||||
3335 | } | ||||||||
3336 | |||||||||
3337 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
3338 | static OUString createFromAscii(std::string_view value) { | ||||||||
3339 | rtl_uString * p = nullptr; | ||||||||
3340 | rtl_uString_newFromLiteral(&p, value.data(), value.size(), 0); //TODO: check for overflow | ||||||||
3341 | return OUString(p, SAL_NO_ACQUIRE); | ||||||||
3342 | } | ||||||||
3343 | #endif | ||||||||
3344 | |||||||||
3345 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
3346 | operator std::u16string_view() const { return {getStr(), sal_uInt32(getLength())}; } | ||||||||
3347 | #endif | ||||||||
3348 | |||||||||
3349 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
3350 | // A wrapper for the first expression in an | ||||||||
3351 | // | ||||||||
3352 | // OUString::Concat(e1) + e2 + ... | ||||||||
3353 | // | ||||||||
3354 | // concatenation chain, when neither of the first two e1, e2 is one of our rtl string-related | ||||||||
3355 | // classes (so something like | ||||||||
3356 | // | ||||||||
3357 | // OUString s = "a" + (b ? std::u16string_view(u"c") : std::u16string_view(u"dd")); | ||||||||
3358 | // | ||||||||
3359 | // would not compile): | ||||||||
3360 | template<typename T> [[nodiscard]] static | ||||||||
3361 | typename std::enable_if_t< | ||||||||
3362 | ToStringHelper<T>::allowOUStringConcat, OUStringConcat<OUStringConcatMarker, T>> | ||||||||
3363 | Concat(T const & value) { return OUStringConcat<OUStringConcatMarker, T>({}, value); } | ||||||||
3364 | |||||||||
3365 | // This overload is needed so that an argument of type 'char const[N]' ends up as | ||||||||
3366 | // 'OUStringConcat<rtl::OUStringConcatMarker, char const[N]>' rather than as | ||||||||
3367 | // 'OUStringConcat<rtl::OUStringConcatMarker, char[N]>': | ||||||||
3368 | template<typename T, std::size_t N> [[nodiscard]] static | ||||||||
3369 | typename std::enable_if_t< | ||||||||
3370 | ToStringHelper<T[N]>::allowOUStringConcat, OUStringConcat<OUStringConcatMarker, T[N]>> | ||||||||
3371 | Concat(T (& value)[N]) { return OUStringConcat<OUStringConcatMarker, T[N]>({}, value); } | ||||||||
3372 | #endif | ||||||||
3373 | |||||||||
3374 | private: | ||||||||
3375 | OUString & internalAppend( rtl_uString* pOtherData ) | ||||||||
3376 | { | ||||||||
3377 | rtl_uString* pNewData = NULL__null; | ||||||||
3378 | rtl_uString_newConcat( &pNewData, pData, pOtherData ); | ||||||||
3379 | if (pNewData == NULL__null) { | ||||||||
3380 | throw std::bad_alloc(); | ||||||||
3381 | } | ||||||||
3382 | rtl_uString_assign(&pData, pNewData); | ||||||||
3383 | rtl_uString_release(pNewData); | ||||||||
3384 | return *this; | ||||||||
3385 | } | ||||||||
3386 | |||||||||
3387 | }; | ||||||||
3388 | |||||||||
3389 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
3390 | // Prevent the operator ==/!= overloads with 'sal_Unicode const *' parameter from | ||||||||
3391 | // being selected for nonsensical code like | ||||||||
3392 | // | ||||||||
3393 | // if (ouIdAttr == nullptr) | ||||||||
3394 | // | ||||||||
3395 | void operator ==(OUString const &, std::nullptr_t) = delete; | ||||||||
3396 | void operator ==(std::nullptr_t, OUString const &) = delete; | ||||||||
3397 | void operator !=(OUString const &, std::nullptr_t) = delete; | ||||||||
3398 | void operator !=(std::nullptr_t, OUString const &) = delete; | ||||||||
3399 | #endif | ||||||||
3400 | |||||||||
3401 | #if defined LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING" | ||||||||
3402 | /// @cond INTERNAL | ||||||||
3403 | |||||||||
3404 | /** | ||||||||
3405 | @internal | ||||||||
3406 | */ | ||||||||
3407 | template<> | ||||||||
3408 | struct ToStringHelper< OUString > | ||||||||
3409 | { | ||||||||
3410 | static std::size_t length( const OUString& s ) { return s.getLength(); } | ||||||||
3411 | static sal_Unicode* addData( sal_Unicode* buffer, const OUString& s ) { return addDataHelper( buffer, s.getStr(), s.getLength()); } | ||||||||
3412 | static const bool allowOStringConcat = false; | ||||||||
3413 | static const bool allowOUStringConcat = true; | ||||||||
3414 | }; | ||||||||
3415 | |||||||||
3416 | /** | ||||||||
3417 | @internal | ||||||||
3418 | */ | ||||||||
3419 | template<std::size_t N> | ||||||||
3420 | struct ToStringHelper< OUStringLiteral<N> > | ||||||||
3421 | { | ||||||||
3422 | static std::size_t length( const OUStringLiteral<N>& str ) { return str.getLength(); } | ||||||||
3423 | static sal_Unicode* addData( sal_Unicode* buffer, const OUStringLiteral<N>& str ) { return addDataHelper( buffer, str.getStr(), str.getLength() ); } | ||||||||
3424 | static const bool allowOStringConcat = false; | ||||||||
3425 | static const bool allowOUStringConcat = true; | ||||||||
3426 | }; | ||||||||
3427 | |||||||||
3428 | /** | ||||||||
3429 | @internal | ||||||||
3430 | */ | ||||||||
3431 | template< typename charT, typename traits, typename T1, typename T2 > | ||||||||
3432 | inline std::basic_ostream<charT, traits> & operator <<( | ||||||||
3433 | std::basic_ostream<charT, traits> & stream, OUStringConcat< T1, T2 >&& concat) | ||||||||
3434 | { | ||||||||
3435 | return stream << OUString( std::move(concat) ); | ||||||||
3436 | } | ||||||||
3437 | |||||||||
3438 | /// @endcond | ||||||||
3439 | #endif | ||||||||
3440 | |||||||||
3441 | /** A helper to use OUStrings with hash maps. | ||||||||
3442 | |||||||||
3443 | Instances of this class are unary function objects that can be used as | ||||||||
3444 | hash function arguments to std::unordered_map and similar constructs. | ||||||||
3445 | */ | ||||||||
3446 | struct OUStringHash | ||||||||
3447 | { | ||||||||
3448 | /** Compute a hash code for a string. | ||||||||
3449 | |||||||||
3450 | @param rString | ||||||||
3451 | a string. | ||||||||
3452 | |||||||||
3453 | @return | ||||||||
3454 | a hash code for the string. This hash code should not be stored | ||||||||
3455 | persistently, as its computation may change in later revisions. | ||||||||
3456 | */ | ||||||||
3457 | size_t operator()(const OUString& rString) const | ||||||||
3458 | { return static_cast<size_t>(rString.hashCode()); } | ||||||||
3459 | }; | ||||||||
3460 | |||||||||
3461 | /* ======================================================================= */ | ||||||||
3462 | |||||||||
3463 | /** Convert an OString to an OUString, using a specific text encoding. | ||||||||
3464 | |||||||||
3465 | The lengths of the two strings may differ (e.g., for double-byte | ||||||||
3466 | encodings, UTF-7, UTF-8). | ||||||||
3467 | |||||||||
3468 | @param rStr | ||||||||
3469 | an OString to convert. | ||||||||
3470 | |||||||||
3471 | @param encoding | ||||||||
3472 | the text encoding to use for conversion. | ||||||||
3473 | |||||||||
3474 | @param convertFlags | ||||||||
3475 | flags which control the conversion. Either use | ||||||||
3476 | OSTRING_TO_OUSTRING_CVTFLAGS, or see | ||||||||
3477 | <http://udk.openoffice.org/cpp/man/spec/textconversion.html> for more | ||||||||
3478 | details. | ||||||||
3479 | */ | ||||||||
3480 | inline OUString OStringToOUString( const OString & rStr, | ||||||||
3481 | rtl_TextEncoding encoding, | ||||||||
3482 | sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300 )) ) | ||||||||
3483 | { | ||||||||
3484 | return OUString( rStr.getStr(), rStr.getLength(), encoding, convertFlags ); | ||||||||
3485 | } | ||||||||
3486 | |||||||||
3487 | /** Convert an OUString to an OString, using a specific text encoding. | ||||||||
3488 | |||||||||
3489 | The lengths of the two strings may differ (e.g., for double-byte | ||||||||
3490 | encodings, UTF-7, UTF-8). | ||||||||
3491 | |||||||||
3492 | @param rUnicode | ||||||||
3493 | an OUString to convert. | ||||||||
3494 | |||||||||
3495 | @param encoding | ||||||||
3496 | the text encoding to use for conversion. | ||||||||
3497 | |||||||||
3498 | @param convertFlags | ||||||||
3499 | flags which control the conversion. Either use | ||||||||
3500 | OUSTRING_TO_OSTRING_CVTFLAGS, or see | ||||||||
3501 | <http://udk.openoffice.org/cpp/man/spec/textconversion.html> for more | ||||||||
3502 | details. | ||||||||
3503 | */ | ||||||||
3504 | inline OString OUStringToOString( const OUString & rUnicode, | ||||||||
3505 | rtl_TextEncoding encoding, | ||||||||
3506 | sal_uInt32 convertFlags = OUSTRING_TO_OSTRING_CVTFLAGS(((sal_uInt32)0x0006) | ((sal_uInt32)0x0060) | ((sal_uInt32)0x0100 ) | ((sal_uInt32)0x0400)) ) | ||||||||
3507 | { | ||||||||
3508 | return OString( rUnicode.getStr(), rUnicode.getLength(), encoding, convertFlags ); | ||||||||
3509 | } | ||||||||
3510 | |||||||||
3511 | /* ======================================================================= */ | ||||||||
3512 | |||||||||
3513 | /** | ||||||||
3514 | Support for rtl::OUString in std::ostream (and thus in | ||||||||
3515 | CPPUNIT_ASSERT or SAL_INFO macros, for example). | ||||||||
3516 | |||||||||
3517 | The rtl::OUString is converted to UTF-8. | ||||||||
3518 | |||||||||
3519 | @since LibreOffice 3.5. | ||||||||
3520 | */ | ||||||||
3521 | template< typename charT, typename traits > | ||||||||
3522 | inline std::basic_ostream<charT, traits> & operator <<( | ||||||||
3523 | std::basic_ostream<charT, traits> & stream, OUString const & rString) | ||||||||
3524 | { | ||||||||
3525 | return stream << | ||||||||
3526 | OUStringToOString(rString, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))); | ||||||||
3527 | // best effort; potentially loses data due to conversion failures | ||||||||
3528 | // (stray surrogate halves) and embedded null characters | ||||||||
3529 | } | ||||||||
3530 | |||||||||
3531 | } // namespace | ||||||||
3532 | |||||||||
3533 | #ifdef RTL_STRING_UNITTEST | ||||||||
3534 | namespace rtl | ||||||||
3535 | { | ||||||||
3536 | typedef rtlunittest::OUString OUString; | ||||||||
3537 | } | ||||||||
3538 | #endif | ||||||||
3539 | |||||||||
3540 | // In internal code, allow to use classes like OUString without having to | ||||||||
3541 | // explicitly refer to the rtl namespace, which is kind of superfluous given | ||||||||
3542 | // that OUString itself is namespaced by its OU prefix: | ||||||||
3543 | #if defined LIBO_INTERNAL_ONLY1 && !defined RTL_STRING_UNITTEST | ||||||||
3544 | using ::rtl::OUString; | ||||||||
3545 | using ::rtl::OUStringHash; | ||||||||
3546 | using ::rtl::OStringToOUString; | ||||||||
3547 | using ::rtl::OUStringToOString; | ||||||||
3548 | using ::rtl::OUStringLiteral; | ||||||||
3549 | using ::rtl::OUStringChar; | ||||||||
3550 | #endif | ||||||||
3551 | |||||||||
3552 | /// @cond INTERNAL | ||||||||
3553 | /** | ||||||||
3554 | Make OUString hashable by default for use in STL containers. | ||||||||
3555 | |||||||||
3556 | @since LibreOffice 6.0 | ||||||||
3557 | */ | ||||||||
3558 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
3559 | namespace std { | ||||||||
3560 | |||||||||
3561 | template<> | ||||||||
3562 | struct hash<::rtl::OUString> | ||||||||
3563 | { | ||||||||
3564 | std::size_t operator()(::rtl::OUString const & s) const | ||||||||
3565 | { return std::size_t(s.hashCode()); } | ||||||||
3566 | }; | ||||||||
3567 | |||||||||
3568 | } | ||||||||
3569 | |||||||||
3570 | #endif | ||||||||
3571 | /// @endcond | ||||||||
3572 | |||||||||
3573 | #endif /* _RTL_USTRING_HXX */ | ||||||||
3574 | |||||||||
3575 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_SC_SOURCE_FILTER_INC_FAPIHELPER_HXX |
21 | #define INCLUDED_SC_SOURCE_FILTER_INC_FAPIHELPER_HXX |
22 | |
23 | #include <com/sun/star/uno/Any.hxx> |
24 | #include <com/sun/star/uno/Reference.hxx> |
25 | #include <com/sun/star/uno/Sequence.hxx> |
26 | #include <osl/diagnose.h> |
27 | #include <tools/color.hxx> |
28 | #include "ftools.hxx" |
29 | |
30 | namespace com::sun::star { |
31 | namespace lang { class XMultiServiceFactory; } |
32 | } |
33 | |
34 | namespace com::sun::star::beans { struct NamedValue; } |
35 | namespace com::sun::star::beans { class XPropertySet; } |
36 | namespace com::sun::star::beans { class XMultiPropertySet; } |
37 | |
38 | namespace comphelper { class IDocPasswordVerifier; } |
39 | |
40 | // Static helper functions ==================================================== |
41 | |
42 | class SfxMedium; |
43 | class SfxObjectShell; |
44 | |
45 | /** Static API helper functions. */ |
46 | class ScfApiHelper |
47 | { |
48 | public: |
49 | /** Converts a non-empty vector into a UNO sequence containing elements of the same type. */ |
50 | template< typename Type > |
51 | static css::uno::Sequence< Type > |
52 | VectorToSequence( const ::std::vector< Type >& rVector ); |
53 | |
54 | /** Returns the service name provided via the XServiceName interface, or an empty string on error. */ |
55 | static OUString GetServiceName( const css::uno::Reference< css::uno::XInterface >& xInt ); |
56 | |
57 | /** Returns the multi service factory from a document shell. */ |
58 | static css::uno::Reference< css::lang::XMultiServiceFactory > GetServiceFactory( const SfxObjectShell* pShell ); |
59 | |
60 | /** Creates an instance from the passed service name, using the passed service factory. */ |
61 | static css::uno::Reference< css::uno::XInterface > CreateInstance( |
62 | const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory, |
63 | const OUString& rServiceName ); |
64 | |
65 | /** Creates an instance from the passed service name, using the service factory of the passed object. */ |
66 | static css::uno::Reference< css::uno::XInterface > CreateInstance( |
67 | const SfxObjectShell* pShell, |
68 | const OUString& rServiceName ); |
69 | |
70 | /** Creates an instance from the passed service name, using the process service factory. */ |
71 | static css::uno::Reference< css::uno::XInterface > CreateInstance( const OUString& rServiceName ); |
72 | |
73 | /** Opens a password dialog and returns the encryption data. |
74 | @return The encryption data or an empty sequence on 'Cancel' or any error. */ |
75 | static css::uno::Sequence< css::beans::NamedValue > QueryEncryptionDataForMedium( SfxMedium& rMedium, |
76 | ::comphelper::IDocPasswordVerifier& rVerifier, |
77 | const ::std::vector< OUString >* pDefaultPasswords ); |
78 | }; |
79 | |
80 | template< typename Type > |
81 | css::uno::Sequence< Type > ScfApiHelper::VectorToSequence( const ::std::vector< Type >& rVector ) |
82 | { |
83 | OSL_ENSURE( !rVector.empty(), "ScfApiHelper::VectorToSequence - vector is empty" )do { if (true && (!(!rVector.empty()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/inc/fapihelper.hxx" ":" "83" ": "), "%s", "ScfApiHelper::VectorToSequence - vector is empty" ); } } while (false); |
84 | return css::uno::Sequence<Type>(rVector.data(), static_cast< sal_Int32 >(rVector.size())); |
85 | } |
86 | |
87 | // Property sets ============================================================== |
88 | |
89 | /** A wrapper for a UNO property set. |
90 | |
91 | This class provides functions to silently get and set properties (without |
92 | exceptions, without the need to check validity of the UNO property set). |
93 | |
94 | An instance is constructed with the reference to a UNO property set or any |
95 | other interface (the constructor will query for the XPropertySet interface |
96 | then). The reference to the property set will be kept as long as the |
97 | instance of this class is alive. |
98 | |
99 | The functions GetProperties() and SetProperties() try to handle all passed |
100 | values at once, using the XMultiPropertySet interface. If the |
101 | implementation does not support the XMultiPropertySet interface, all |
102 | properties are handled separately in a loop. |
103 | */ |
104 | class ScfPropertySet |
105 | { |
106 | public: |
107 | explicit ScfPropertySet() {} |
108 | /** Constructs a property set wrapper with the passed UNO property set. */ |
109 | explicit ScfPropertySet( const css::uno::Reference< css::beans::XPropertySet > & xPropSet ) { Set( xPropSet ); } |
110 | /** Constructs a property set wrapper after querying the XPropertySet interface. */ |
111 | template< typename InterfaceType > |
112 | explicit ScfPropertySet( const css::uno::Reference< InterfaceType >& xInterface ) { Set( xInterface ); } |
113 | |
114 | ~ScfPropertySet(); |
115 | //TODO: |
116 | ScfPropertySet(ScfPropertySet const &) = default; |
117 | ScfPropertySet(ScfPropertySet &&) = default; |
118 | ScfPropertySet & operator =(ScfPropertySet const &) = default; |
119 | ScfPropertySet & operator =(ScfPropertySet &&) = default; |
120 | |
121 | /** Sets the passed UNO property set and releases the old UNO property set. */ |
122 | void Set( css::uno::Reference< css::beans::XPropertySet > const & xPropSet ); |
123 | /** Queries the passed interface for an XPropertySet and releases the old UNO property set. */ |
124 | template< typename InterfaceType > |
125 | void Set( css::uno::Reference< InterfaceType > xInterface ) |
126 | { Set( css::uno::Reference< css::beans::XPropertySet >( xInterface, css::uno::UNO_QUERY ) ); } |
127 | |
128 | /** Returns true, if the contained XPropertySet interface is valid. */ |
129 | bool Is() const { return mxPropSet.is(); } |
130 | |
131 | /** Returns the contained XPropertySet interface. */ |
132 | const css::uno::Reference< css::beans::XPropertySet >& GetApiPropertySet() const { return mxPropSet; } |
133 | |
134 | /** Returns the service name provided via the XServiceName interface, or an empty string on error. */ |
135 | OUString GetServiceName() const; |
136 | |
137 | // Get properties --------------------------------------------------------- |
138 | |
139 | /** Returns true, if the property set contains the specified property. */ |
140 | bool HasProperty( const OUString& rPropName ) const; |
141 | |
142 | /** Gets the specified property from the property set. |
143 | @return true, if the Any could be filled with the property value. */ |
144 | bool GetAnyProperty( css::uno::Any& rValue, const OUString& rPropName ) const; |
145 | |
146 | /** Gets the specified property from the property set. |
147 | @return true, if the passed variable could be filled with the property value. */ |
148 | template< typename Type > |
149 | bool GetProperty( Type& rValue, const OUString& rPropName ) const |
150 | { css::uno::Any aAny; return GetAnyProperty( aAny, rPropName ) && (aAny >>= rValue); } |
151 | |
152 | /** Gets the specified Boolean property from the property set. |
153 | @return true = property contains true; false = property contains false or error occurred. */ |
154 | bool GetBoolProperty( const OUString& rPropName ) const; |
155 | |
156 | /** Gets the specified Boolean property from the property set. */ |
157 | OUString GetStringProperty( const OUString& rPropName ) const; |
158 | |
159 | /** Gets the specified color property from the property set. |
160 | @return true, if the passed color variable could be filled with the property value. */ |
161 | bool GetColorProperty( Color& rColor, const OUString& rPropName ) const; |
162 | |
163 | /** Gets the specified properties from the property set. Tries to use the XMultiPropertySet interface. |
164 | @param rPropNames The property names. MUST be ordered alphabetically. |
165 | @param rValues The related property values. */ |
166 | void GetProperties( css::uno::Sequence< css::uno::Any >& rValues, const css::uno::Sequence< OUString >& rPropNames ) const; |
167 | |
168 | // Set properties --------------------------------------------------------- |
169 | |
170 | /** Puts the passed Any into the property set. */ |
171 | void SetAnyProperty( const OUString& rPropName, const css::uno::Any& rValue ); |
172 | |
173 | /** Puts the passed value into the property set. */ |
174 | template< typename Type > |
175 | void SetProperty( const OUString& rPropName, const Type& rValue ) |
176 | { SetAnyProperty( rPropName, css::uno::makeAny( rValue ) ); } |
177 | |
178 | /** Puts the passed Boolean value into the property set. */ |
179 | void SetBoolProperty( const OUString& rPropName, bool bValue ) |
180 | { SetAnyProperty( rPropName, css::uno::Any( bValue ) ); } |
181 | |
182 | /** Puts the passed string into the property set. */ |
183 | void SetStringProperty( const OUString& rPropName, const OUString& rValue ) |
184 | { SetProperty( rPropName, rValue ); } |
185 | |
186 | /** Puts the passed color into the property set. */ |
187 | void SetColorProperty( const OUString& rPropName, const Color& rColor ) |
188 | { SetProperty( rPropName, sal_Int32( rColor ) ); } |
189 | |
190 | /** Puts the passed properties into the property set. Tries to use the XMultiPropertySet interface. |
191 | @param rPropNames The property names. MUST be ordered alphabetically. |
192 | @param rValues The related property values. */ |
193 | void SetProperties( const css::uno::Sequence< OUString > & rPropNames, const css::uno::Sequence< css::uno::Any >& rValues ); |
194 | |
195 | private: |
196 | css::uno::Reference< css::beans::XPropertySet > mxPropSet; /// The mandatory property set interface. |
197 | css::uno::Reference< css::beans::XMultiPropertySet > mxMultiPropSet; /// The optional multi property set interface. |
198 | }; |
199 | |
200 | /** Generic helper class for reading from and writing to property sets. |
201 | |
202 | Usage: |
203 | 1) Call the constructor with a null-terminated array of ASCII strings. |
204 | 2a) Read properties from a property set: Call the ReadFromPropertySet() |
205 | function, then get the properties with the ReadValue() functions or the |
206 | operator>> stream operator. The properties are returned in order of the |
207 | array of property names passed in the constructor. |
208 | 2b) Write properties to a property set: Call InitializeWrite() to start a |
209 | new cycle. Set the values with the WriteValue() functions or the |
210 | operator<< stream operator. The order of the properties is equal to the |
211 | array of property names passed in the constructor. Finally, call the |
212 | WriteToPropertySet() function. |
213 | */ |
214 | class ScfPropSetHelper |
215 | { |
216 | public: |
217 | /** @param ppPropNames A null-terminated array of ASCII property names. */ |
218 | explicit ScfPropSetHelper( const char* const* ppcPropNames ); |
219 | |
220 | // read properties -------------------------------------------------------- |
221 | |
222 | /** Reads all values from the passed property set. */ |
223 | void ReadFromPropertySet( const ScfPropertySet& rPropSet ); |
224 | |
225 | /** Reads the next value from the value sequence. */ |
226 | template< typename Type > |
227 | void ReadValue( Type& rValue ); |
228 | /** Reads an Any from the value sequence. */ |
229 | void ReadValue( css::uno::Any& rAny ); |
230 | /** Reads a color value from the value sequence. */ |
231 | void ReadValue( Color& rColor ); |
232 | /** Reads a C++ boolean value from the value sequence. */ |
233 | void ReadValue( bool& rbValue ); |
234 | |
235 | // write properties ------------------------------------------------------- |
236 | |
237 | /** Must be called before reading or storing property values in the helper. */ |
238 | void InitializeWrite(); |
239 | |
240 | /** Writes the next value to the value sequence. */ |
241 | template< typename Type > |
242 | void WriteValue( const Type& rValue ); |
243 | /** Writes an Any to the value sequence. */ |
244 | void WriteValue( const css::uno::Any& rAny ); |
245 | /** Writes a color value to the value sequence. */ |
246 | void WriteValue( const Color& rColor ) |
247 | { WriteValue( sal_Int32( rColor ) ); } |
248 | /** Writes a C++ boolean value to the value sequence. */ |
249 | void WriteValue( bool rbValue ); |
250 | |
251 | /** Writes all values to the passed property set. */ |
252 | void WriteToPropertySet( ScfPropertySet& rPropSet ) const; |
253 | |
254 | private: |
255 | /** Returns a pointer to the next Any to be written to. */ |
256 | css::uno::Any* GetNextAny(); |
257 | |
258 | private: |
259 | css::uno::Sequence< OUString > maNameSeq; /// Sequence of property names. |
260 | css::uno::Sequence< css::uno::Any > maValueSeq; /// Sequence of property values. |
261 | ScfInt32Vec maNameOrder; /// Maps initial order to alphabetical order. |
262 | size_t mnNextIdx; /// Counter for next Any to be processed. |
263 | }; |
264 | |
265 | template< typename Type > |
266 | void ScfPropSetHelper::ReadValue( Type& rValue ) |
267 | { |
268 | css::uno::Any* pAny = GetNextAny(); |
269 | if (pAny) |
270 | *pAny >>= rValue; |
271 | } |
272 | |
273 | template< typename Type > |
274 | void ScfPropSetHelper::WriteValue( const Type& rValue ) |
275 | { |
276 | css::uno::Any* pAny = GetNextAny(); |
277 | if( pAny ) |
278 | *pAny <<= rValue; |
279 | } |
280 | |
281 | template< typename Type > |
282 | ScfPropSetHelper& operator>>( ScfPropSetHelper& rPropSetHelper, Type& rValue ) |
283 | { |
284 | rPropSetHelper.ReadValue( rValue ); |
285 | return rPropSetHelper; |
286 | } |
287 | |
288 | template< typename Type > |
289 | ScfPropSetHelper& operator<<( ScfPropSetHelper& rPropSetHelper, const Type& rValue ) |
290 | { |
291 | rPropSetHelper.WriteValue( rValue ); |
292 | return rPropSetHelper; |
293 | } |
294 | |
295 | #endif |
296 | |
297 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |