Use correct object
[LibreOffice.git] / i18npool / source / defaultnumberingprovider / defaultnumberingprovider.cxx
blobb29689145b91aebbf266b238a90ed4cc379d9bf8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <defaultnumberingprovider.hxx>
21 #include <transliterationImpl.hxx>
22 #include <com/sun/star/i18n/NativeNumberMode.hpp>
23 #include <com/sun/star/lang/IllegalArgumentException.hpp>
24 #include <com/sun/star/style/NumberingType.hpp>
25 #include <com/sun/star/beans/PropertyValue.hpp>
26 #include <com/sun/star/configuration/theDefaultProvider.hpp>
27 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
28 #include <osl/diagnose.h>
29 #include <rtl/ref.hxx>
30 #include <localedata.hxx>
31 #include <nativenumbersupplier.hxx>
32 #include <string.h>
33 #include <comphelper/propertysequence.hxx>
34 #include <cppuhelper/supportsservice.hxx>
35 #include <officecfg/Office/Common.hxx>
37 // Cyrillic upper case
38 #define C_CYR_A "\xD0\x90"
39 #define C_CYR_B "\xD0\x91"
40 // Cyrillic lower case
41 #define S_CYR_A "\xD0\xB0"
42 #define S_CYR_B "\xD0\xB1"
44 //Greek upper case
45 #define C_GR_A "\xCE\x91"
46 #define C_GR_B "\xCE\x92"
47 //Greek lower case
48 #define S_GR_A "\xCE\xB1"
49 #define S_GR_B "\xCE\xB2"
51 //Hebrew
52 #define S_HE_ALEPH "\xD7\x90"
53 #define S_HE_YOD "\xD7\x99"
54 #define S_HE_QOF "\xD7\xA7"
56 //Arabic-Indic
57 #define S_AR_ONE "\xd9\xa1"
58 #define S_AR_TWO "\xd9\xa2"
59 #define S_AR_THREE "\xd9\xa3"
61 // East Arabic-Indic
62 #define S_FA_ONE "\xDB\xB1"
63 #define S_FA_TWO "\xDB\xB2"
64 #define S_FA_THREE "\xDB\xB3"
66 // Indic Devanagari
67 #define S_HI_ONE "\xE0\xA5\xA7"
68 #define S_HI_TWO "\xE0\xA5\xA8"
69 #define S_HI_THREE "\xE0\xA5\xA9"
71 // Chicago footnote symbols
72 #define S_DAGGER "\xE2\x80\xA0"
73 #define S_DBL_DAGGER "\xE2\x80\xA1"
74 #define S_SECTION "\xC2\xA7"
76 #include <sal/macros.h>
77 #include <rtl/ustring.hxx>
78 #include <rtl/ustrbuf.hxx>
80 #include <bullet.h>
82 using namespace com::sun::star;
83 using namespace com::sun::star::uno;
84 using namespace ::com::sun::star::i18n;
85 using namespace com::sun::star::lang;
87 namespace i18npool {
89 constexpr sal_Unicode table_Alphabet_ar[] = {
90 0x0623, 0x0628, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E,
91 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635,
92 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x0642,
93 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649
96 constexpr sal_Unicode table_Alphabet_ar_abjad[] = {
97 0x0627, 0x0628, 0x062c, 0x062f, 0x0647, 0x0648, 0x0632, 0x062d,
98 0x0637, 0x064a, 0x0643, 0x0644, 0x0645, 0x0646, 0x0633, 0x0639,
99 0x0641, 0x0635, 0x0642, 0x0631, 0x0634, 0x062a, 0x062b, 0x062e,
100 0x0630, 0x0636, 0x0638, 0x063a
103 constexpr sal_Unicode table_Alphabet_th[] = {
104 0x0E01, 0x0E02, 0x0E04, 0x0E07,
105 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
106 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
107 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
108 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
109 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E
112 constexpr sal_Unicode table_Alphabet_he[] = {
113 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
114 0x05D8, 0x05D9, 0x05DB, 0x05DC, 0x05DE, 0x05E0, 0x05E1, 0x05E2,
115 0x05E4, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA
118 constexpr sal_Unicode table_Alphabet_ne[] = {
119 0x0915, 0x0916, 0x0917, 0x0918, 0x0919, 0x091A, 0x091B, 0x091C,
120 0x091D, 0x091E, 0x091F, 0x0920, 0x0921, 0x0922, 0x0923, 0x0924,
121 0x0925, 0x0926, 0x0927, 0x0928, 0x092A, 0x092B, 0x092C, 0x092D,
122 0x092E, 0x092F, 0x0930, 0x0932, 0x0935, 0x0936, 0x0937, 0x0938,
123 0x0939
126 constexpr sal_Unicode table_Alphabet_km[] = {
127 0x1780, 0x1781, 0x1782, 0x1783, 0x1784, 0x1785, 0x1786, 0x1787,
128 0x1788, 0x1789, 0x178A, 0x178B, 0x178C, 0x178D, 0x178E, 0x178F,
129 0x1790, 0x1791, 0x1792, 0x1793, 0x1794, 0x1795, 0x1796, 0x1797,
130 0x1798, 0x1799, 0x179A, 0x179B, 0x179C, 0x179F,
131 0x17A0, 0x17A1, 0x17A2
134 constexpr sal_Unicode table_Alphabet_lo[] = {
135 0x0E81, 0x0E82, 0x0E84, 0x0E87, 0x0E88, 0x0E8A, 0x0E8D, 0x0E94,
136 0x0E95, 0x0E96, 0x0E97, 0x0E99, 0x0E9A, 0x0E9B, 0x0E9C,
137 0x0E9D, 0x0E9E, 0x0E9F, 0x0EA1, 0x0EA2, 0x0EA3, 0x0EA5, 0x0EA7,
138 0x0EAA, 0x0EAB, 0x0EAD, 0x0EAE, 0x0EAF, 0x0EAE, 0x0EDC, 0x0EDD
141 constexpr sal_Unicode table_Alphabet_dz[] = {
142 0x0F40, 0x0F41, 0x0F42, 0x0F44, 0x0F45, 0x0F46, 0x0F47, 0x0F49,
143 0x0F4F, 0x0F50, 0x0F51, 0x0F53, 0x0F54, 0x0F55, 0x0F56, 0x0F58,
144 0x0F59, 0x0F5A, 0x0F5B, 0x0F5D, 0x0F5E, 0x0F5F, 0x0F60, 0x0F61,
145 0x0F62, 0x0F63, 0x0F64, 0x0F66, 0x0F67, 0x0F68
148 constexpr sal_Unicode table_Alphabet_my[] = {
149 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007,
150 0x1008,/*0x1009,*/0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
151 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017,
152 0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
153 0x1020, 0x1021
156 // Bulgarian Cyrillic upper case letters
157 constexpr sal_Unicode table_CyrillicUpperLetter_bg[] = {
158 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418,
159 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422,
160 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042E,
161 0x042F
164 // Bulgarian cyrillic lower case letters
165 constexpr sal_Unicode table_CyrillicLowerLetter_bg[] = {
166 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438,
167 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442,
168 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044E,
169 0x044F
172 // Russian Cyrillic upper letters
173 constexpr sal_Unicode table_CyrillicUpperLetter_ru[] = {
174 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
175 0x0418, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420,
176 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428,
177 0x0429, 0x042B, 0x042D, 0x042E, 0x042F
180 // Russian cyrillic lower letters
181 constexpr sal_Unicode table_CyrillicLowerLetter_ru[] = {
182 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
183 0x0438, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440,
184 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448,
185 0x0449, 0x044B, 0x044D, 0x044E, 0x044F
188 // Serbian Cyrillic upper letters
189 constexpr sal_Unicode table_CyrillicUpperLetter_sr[] = {
190 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0402, 0x0415, 0x0416,
191 0x0417, 0x0418, 0x0408, 0x041A, 0x041B, 0x0409, 0x041C, 0x041D,
192 0x040A, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x040B, 0x0423,
193 0x0424, 0x0425, 0x0426, 0x0427, 0x040F, 0x0428
196 // Serbian cyrillic lower letters
197 constexpr sal_Unicode table_CyrillicLowerLetter_sr[] = {
198 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0452, 0x0435, 0x0436,
199 0x0437, 0x0438, 0x0458, 0x043A, 0x043B, 0x0459, 0x043C, 0x043D,
200 0x045A, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x045B, 0x0443,
201 0x0444, 0x0445, 0x0446, 0x0447, 0x045F, 0x0448
204 // Ukrainian Cyrillic upper letters
205 constexpr sal_Unicode table_CyrillicUpperLetter_uk[] = {
206 0x0410, 0x0411, 0x0412, 0x0413, 0x0490, 0x0414, 0x0415, 0x0404,
207 0x0416, 0x0417, 0x0418, 0x0406, 0x0407, 0x0419, 0x041A, 0x041B,
208 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423,
209 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042C, 0x042E,
210 0x042F
213 // Ukrainian cyrillic lower letters
214 constexpr sal_Unicode table_CyrillicLowerLetter_uk[] = {
215 0x0430, 0x0431, 0x0432, 0x0433, 0x0491, 0x0434, 0x0435, 0x0454,
216 0x0436, 0x0437, 0x0438, 0x0456, 0x0457, 0x0439, 0x043A, 0x043B,
217 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443,
218 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044C, 0x044E,
219 0x044F
222 constexpr sal_Unicode table_GreekUpperLetter[] = {
223 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x03DB, 0x0396, 0x0397, 0x0398,
224 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03DF,
225 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03E0
228 constexpr sal_Unicode table_GreekLowerLetter[] = {
229 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03DB, 0x03B6, 0x03B7, 0x03B8,
230 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03DF,
231 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03E1
234 constexpr sal_Unicode table_Alphabet_fa[] = {
235 0x0622, 0x0628, 0x067E, 0x062A, 0x062B, 0x062C, 0x0686, 0x062D,
236 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0698, 0x0633, 0x0634,
237 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x0640, 0x0641, 0x0642,
238 0x06A9, 0x06AF, 0x0644, 0x0645, 0x0646, 0x0648, 0x0647, 0x06CC
241 constexpr sal_Unicode upperLetter[] = {
242 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
243 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52,
244 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A
247 constexpr sal_Unicode lowerLetter[] = {
248 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
249 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
250 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
253 constexpr sal_Unicode table_Chicago[] = {
254 0x002a, 0x2020, 0x2021, 0x00a7
257 // Tables used for numbering in persian words
258 constexpr sal_Unicode table_PersianWord_decade1[][7]={
259 {0}, // 0
260 {0x06cc, 0x06a9, 0}, // 1
261 {0x062f, 0x0648, 0}, // 2
262 {0x0633, 0x0647, 0}, // 3
263 {0x0686, 0x0647, 0x0627, 0x0631, 0}, // 4
264 {0x067e, 0x0646, 0x062c, 0}, // 5
265 {0x0634, 0x0634, 0}, // 6
266 {0x0647, 0x0641, 0x062a, 0}, // 7
267 {0x0647, 0x0634, 0x062a, 0}, // 8
268 {0x0646, 0x0647, 0}, // 9
269 {0x062f, 0x0647, 0}, // 10
270 {0x06cc, 0x0627, 0x0632, 0x062f, 0x0647, 0}, // 11
271 {0x062f, 0x0648, 0x0627, 0x0632, 0x062f, 0x0647, 0}, // 12
272 {0x0633, 0x06cc, 0x0632, 0x062f, 0x0647, 0}, // 13
273 {0x0686, 0x0647, 0x0627, 0x0631, 0x062f, 0x0647, 0}, // 14
274 {0x067e, 0x0627, 0x0646, 0x0632, 0x062f, 0x0647, 0}, // 15
275 {0x0634, 0x0627, 0x0646, 0x0632, 0x062f, 0x0647, 0}, // 16
276 {0x0647, 0x0641, 0x062f, 0x0647, 0}, // 17
277 {0x0647, 0x062c, 0x062f, 0x0647, 0}, // 18
278 {0x0646, 0x0648, 0x0632, 0x062f, 0x0647, 0} // 19
281 constexpr sal_Unicode table_PersianWord_decade2[][6]={
282 {0x0628, 0x06cc, 0x0633, 0x062a, 0}, // 20
283 {0x0633, 0x06cc, 0}, // 30
284 {0x0686, 0x0647, 0x0644, 0}, // 40
285 {0x067e, 0x0646, 0x062c, 0x0627, 0x0647, 0}, // 50
286 {0x0634, 0x0635, 0x062a, 0}, // 60
287 {0x0647, 0x0641, 0x062a, 0x0627, 0x062f, 0}, // 70
288 {0x0647, 0x0634, 0x062a, 0x0627, 0x062f, 0}, // 80
289 {0x0646, 0x0648, 0x062f, 0} // 90
292 constexpr sal_Unicode table_PersianWord_decade3[][7]={
293 {0x0635, 0x062f, 0}, // 100
294 {0x062f, 0x0648, 0x06cc, 0x0633, 0x062a, 0}, // 200
295 {0x0633, 0x06cc, 0x0635, 0x062f, 0}, // 300
296 {0x0686, 0x0647, 0x0627, 0x0631, 0x0635, 0x062f, 0}, // 400
297 {0x067e, 0x0627, 0x0646, 0x0635, 0x062f, 0}, // 500
298 {0x0634, 0x0635, 0x062f, 0}, // 600
299 {0x0647, 0x0641, 0x062a, 0x0635, 0x062f, 0}, // 700
300 {0x0647, 0x0634, 0x062a, 0x0635, 0x062f, 0}, // 800
301 {0x0646, 0x0647, 0x0635, 0x062f, 0} // 900
304 constexpr sal_Unicode table_PersianWord_decadeX[][8]={
305 {0x0647, 0x0632, 0x0627, 0x0631, 0}, // 1000
306 {0x0645, 0x06cc, 0x0644, 0x06cc, 0x0648, 0x0646, 0}, // 1000000
307 {0x0645, 0x06cc, 0x0644, 0x06cc, 0x0627, 0x0631, 0x062f, 0} // 1000000000
310 constexpr sal_Unicode table_KoreanLegalWord_decade1[][3] = {
311 {0xd558, 0xb098, 0}, // 1
312 {0xb458, 0}, // 2
313 {0xc14b, 0}, // 3
314 {0xb137, 0}, // 4
315 {0xb2e4, 0xc12f, 0}, // 5
316 {0xc5ec, 0xc12f, 0}, // 6
317 {0xc77c, 0xacf1, 0}, // 7
318 {0xc5ec, 0xb35f, 0}, // 8
319 {0xc544, 0xd649, 0} // 9
322 constexpr sal_Unicode table_KoreanLegalWord_decade2[][3] = {
323 {0xc5f4, 0}, // 10
324 {0xc2a4, 0xbb3c, 0}, // 20
325 {0xc11c, 0xb978, 0}, // 30
326 {0xb9c8, 0xd754, 0}, // 40
327 {0xc270, 0}, // 50
328 {0xc608, 0xc21c, 0}, // 60
329 {0xc77c, 0xd754, 0}, // 70
330 {0xc5ec, 0xb4e0, 0}, // 80
331 {0xc544, 0xd754, 0} // 90
334 DefaultNumberingProvider::DefaultNumberingProvider( const Reference < XComponentContext >& rxContext ) : m_xContext(rxContext)
339 DefaultNumberingProvider::~DefaultNumberingProvider()
343 Sequence< Reference<container::XIndexAccess> >
344 DefaultNumberingProvider::getDefaultOutlineNumberings(const Locale& rLocale )
346 return LocaleDataImpl::get()->getOutlineNumberingLevels( rLocale );
349 Sequence< Sequence<beans::PropertyValue> >
350 DefaultNumberingProvider::getDefaultContinuousNumberingLevels( const Locale& rLocale )
352 return LocaleDataImpl::get()->getContinuousNumberingLevels( rLocale );
355 static OUString toRoman( sal_Int32 n )
358 // i, ii, iii, iv, v, vi, vii, vii, viii, ix
359 // (Dummy),1000,500,100,50,10,5,1
360 static const char coRomanArr[] = "MDCLXVI--"; // +2 Dummy entries !!
361 const char* cRomanStr = coRomanArr;
362 sal_uInt16 nMask = 1000;
363 sal_uInt32 nOver1000 = n / nMask;
364 n -= ( nOver1000 * nMask );
366 OUStringBuffer sTmp;
367 while(nOver1000--)
368 sTmp.append(*coRomanArr);
370 while( nMask )
372 sal_uInt8 nNumber = sal_uInt8( n / nMask );
373 sal_uInt8 nDiff = 1;
374 n %= nMask;
376 if( 5 < nNumber )
378 if( nNumber < 9 )
379 sTmp.append(*(cRomanStr-1));
380 ++nDiff;
381 nNumber -= 5;
383 switch( nNumber )
385 case 3: sTmp.append(*cRomanStr); [[fallthrough]];
386 case 2: sTmp.append(*cRomanStr); [[fallthrough]];
387 case 1: sTmp.append(*cRomanStr); break;
388 case 4: sTmp.append(OUStringChar(*cRomanStr) + OUStringChar(*(cRomanStr-nDiff))); break;
389 case 5: sTmp.append(*(cRomanStr-nDiff)); break;
392 nMask /= 10; // to the next decade
393 cRomanStr += 2;
395 return sTmp.makeStringAndClear();
398 // not used:
400 static
401 void lcl_formatChars( const sal_Unicode table[], int tableSize, int n, OUString& s )
403 // string representation of n is appended to s.
404 // if A=='A' then 0=>A, 1=>B, ..., 25=>Z, 26=>AA, 27=>AB, ...
405 // if A=='a' then 0=>a, 1=>b, ..., 25=>z, 26=>aa, 27=>ab, ...
407 if( n>=tableSize ) lcl_formatChars( table, tableSize, (n-tableSize)/tableSize, s );
409 s += OUStringChar( table[ n % tableSize ] );
412 static
413 void lcl_formatChars1( const sal_Unicode table[], int tableSize, int n, OUString& s )
415 // string representation of n is appended to s.
416 // if A=='A' then 0=>A, 1=>B, ..., 25=>Z, 26=>AA, 27=>BB, ...
417 // if A=='a' then 0=>a, 1=>b, ..., 25=>z, 26=>aa, 27=>bb, ...
419 int repeat_count = n / tableSize + 1;
421 for( int i=0; i<repeat_count; i++ )
422 s += OUStringChar( table[ n%tableSize ] );
425 static
426 void lcl_formatChars2( const sal_Unicode table_capital[], const sal_Unicode table_small[], int tableSize, int n, OUString& s )
428 // string representation of n is appended to s.
429 // if A=='A' then 0=>A, 1=>B, ..., 25=>Z, 26=>Aa, 27=>Ab, ...
431 if( n>=tableSize )
433 lcl_formatChars2( table_capital, table_small, tableSize, (n-tableSize)/tableSize, s );
434 s += OUStringChar( table_small[ n % tableSize ] );
435 } else
436 s += OUStringChar( table_capital[ n % tableSize ] );
439 static
440 void lcl_formatChars3( const sal_Unicode table_capital[], const sal_Unicode table_small[], int tableSize, int n, OUString& s )
442 // string representation of n is appended to s.
443 // if A=='A' then 0=>A, 1=>B, ..., 25=>Z, 26=>Aa, 27=>Bb, ...
445 int repeat_count = n / tableSize + 1;
446 s += OUStringChar( table_capital[ n%tableSize ] );
448 for( int i=1; i<repeat_count; i++ )
449 s += OUStringChar( table_small[ n%tableSize ] );
453 /** Returns number's representation in persian words up to 999999999999
454 respectively limited by sal_Int32 >=0.
455 The caller assures that nNumber is not negative.
457 @throws IllegalArgumentException
458 @throws RuntimeException
460 static
461 void lcl_formatPersianWord( sal_Int32 nNumber, OUString& rsResult )
463 OUStringBuffer aTemp(64);
464 OUString asPersianWord_conjunction = u" \u0648 "_ustr;
465 unsigned char nSection = 0;
467 while (int nPart = nNumber % 1000)
469 if (nSection)
471 if (nSection > std::size( table_PersianWord_decadeX))
472 throw IllegalArgumentException(); // does not happen with sal_Int32
473 aTemp.insert( 0, table_PersianWord_decadeX[nSection-1] + asPersianWord_conjunction );
476 unsigned int nDigit;
477 if ((nDigit = nPart % 100) < 20)
479 if (!aTemp.isEmpty())
480 aTemp.insert( 0, u' ');
481 aTemp.insert( 0, table_PersianWord_decade1[nDigit]);
483 else
485 if ((nDigit = nPart % 10) != 0)
487 if (!aTemp.isEmpty())
488 aTemp.insert( 0, asPersianWord_conjunction);
489 aTemp.insert( 0, table_PersianWord_decade1[nDigit]);
491 if ((nDigit = (nPart / 10) % 10) != 0)
493 if (!aTemp.isEmpty())
494 aTemp.insert( 0, asPersianWord_conjunction);
495 aTemp.insert( 0, table_PersianWord_decade2[nDigit-2]);
499 if ((nDigit = nPart / 100) != 0)
501 if (!aTemp.isEmpty())
502 aTemp.insert( 0, asPersianWord_conjunction);
503 aTemp.insert( 0, table_PersianWord_decade3[nDigit-1]);
506 nNumber /= 1000;
507 nSection++;
509 rsResult += aTemp;
512 static void lcl_formatKoreanLegalWord(sal_Int32 nNumber, OUString& rsResult) {
513 OUStringBuffer aTemp(64);
514 int digit1 = nNumber % 10;
515 int digit2 = nNumber / 10;
516 if (digit1 > 0)
517 aTemp.insert(0, (table_KoreanLegalWord_decade1[digit1 - 1]));
518 if (digit2 > 0)
519 aTemp.insert(0, (table_KoreanLegalWord_decade2[digit2 - 1]));
520 rsResult += aTemp;
523 // Greek Letter Numbering
525 // KERAIA separates numerals from other text
526 #define STIGMA u'\x03DB'
527 #define LEFT_KERAIA u'\x0375'
528 #define MYRIAD_SYM u'\x039C'
529 #define DOT_SYM u'.'
530 #define SIGMA_OFFSET 19
531 #define TAU_OFFSET 20
532 #define MYRIAD 10000
535 * Return the 1-999999 number's representation in the Greek numbering system.
536 * Adding a "left keraia" to represent numbers in the range 10000 ... 999999 is
537 * not orthodox, so it's better to use the myriad notation and call this method
538 * only for numbers up to 9999.
540 static
541 OUString gr_smallNum(const sal_Unicode table[], int n)
543 if (n > 9999)
544 throw IllegalArgumentException();
546 int i = 0;
547 OUStringBuffer sb;
548 for (int v = n; v > 0; v /= 10, i++) {
549 int digit = v % 10;
550 if (digit == 0)
551 continue;
553 sal_Unicode sign = table[(digit - 1) + 9 * (i % 3)];
554 if (sign == STIGMA) {
555 sb.insert(0, table[TAU_OFFSET]);
556 sb.insert(0, table[SIGMA_OFFSET]);
557 } else {
558 sb.insert(0, sign);
561 if (i > 2)
562 sb.insert(0, LEFT_KERAIA);
565 return sb.makeStringAndClear();
568 static
569 void lcl_formatCharsGR(const sal_Unicode table[], int n, OUString& s )
571 OUStringBuffer sb;
572 int myriadPower = 2;
574 for (int divisor = MYRIAD * MYRIAD; divisor > 1; divisor /= MYRIAD, myriadPower--) {
575 if (n > divisor - 1) {
577 * Follow the Diophantus representation of:
578 * A myriad sign, M(10000) as many times as the power
579 * followed by the multiplier for the myriad
580 * followed by a dot
581 * followed by the rest
582 * This is enough for 32-bit integers
584 for (int i = 0; i < myriadPower; i++)
585 sb.append(MYRIAD_SYM);
587 sb.append(gr_smallNum(table, n/divisor));
588 n %= divisor;
590 if (n > 0)
591 sb.append(DOT_SYM);
594 sb.append(gr_smallNum(table,n));
596 s += sb;
599 static
600 bool should_ignore( std::u16string_view s )
602 // return true if blank or null
603 return s == u" " || (!s.empty() && s[0]==0);
607 * Turn nNumber into a string and pad the result to nLimit by inserting zero characters at the
608 * start.
610 static OUString lcl_formatArabicZero(sal_Int32 nNumber, sal_Int32 nLimit)
612 OUString aRet = OUString::number(nNumber);
613 sal_Int32 nDiff = nLimit - aRet.getLength();
615 if (nDiff <= 0)
617 return aRet;
620 OUStringBuffer aBuffer;
621 aBuffer.setLength(nDiff);
622 for (sal_Int32 i = 0; i < nDiff; ++i)
624 aBuffer[i] = '0';
626 aBuffer.append(aRet);
627 return aBuffer.makeStringAndClear();
630 static
631 Any getPropertyByName( const Sequence<beans::PropertyValue>& aProperties,
632 const char* name )
634 auto pProp = std::find_if(aProperties.begin(), aProperties.end(),
635 [&name](const beans::PropertyValue& rProp) { return rProp.Name.equalsAscii(name); });
636 if (pProp != aProperties.end())
637 return pProp->Value;
638 throw IllegalArgumentException();
641 //XNumberingFormatter
642 OUString
643 DefaultNumberingProvider::makeNumberingString( const Sequence<beans::PropertyValue>& aProperties,
644 const Locale& aLocale )
646 // the Sequence of PropertyValues is expected to have at least 4 elements:
647 // elt Name Type purpose
650 // 0. "Prefix" OUString
651 // 1. "NumberingType" sal_Int16 type of formatting from style::NumberingType (roman, arabic, etc)
652 // 2. "Suffix" OUString
653 // ... ... ...
654 // n. "Value" sal_Int32 the number to be formatted
655 // example:
656 // given the Sequence { '(', NumberingType::ROMAN_UPPER, ')', ..., 7 }
657 // makeNumberingString() returns the string "(VII)".
659 // Q: why is the type of numType sal_Int16 instead of style::NumberingType?
660 // A: an Any can't hold a style::NumberingType for some reason.
661 // add.: style::NumberingType holds constants of type sal_Int16, it's not an enum type
663 sal_Int16 natNum = 0;
664 sal_Int16 tableSize = 0;
665 const sal_Unicode *table = nullptr; // initialize to avoid compiler warning
666 bool bRecycleSymbol = false;
667 OUString sNatNumParams;
668 Locale locale;
670 OUString prefix;
671 sal_Int16 numType = -1; // type of formatting from style::NumberingType (roman, arabic, etc)
672 OUString suffix;
673 sal_Int32 number = -1; // the number that needs to be formatted.
675 // int nProperties = aProperties.getLength();
676 // int last = nProperties-1;
678 for (auto const & prop : aProperties)
680 if (prop.Name == "Prefix")
681 prop.Value >>= prefix;
682 else if (prop.Name == "Suffix")
683 prop.Value >>= suffix;
684 else if (prop.Name == "NumberingType")
685 prop.Value >>= numType;
686 else if (prop.Name == "Value")
687 prop.Value >>= number;
690 if( number <= 0 )
691 throw IllegalArgumentException();
693 // start empty
694 OUString result;
696 // append prefix
697 if( !should_ignore(prefix) ) result += prefix;
699 // append formatted number
700 using namespace style::NumberingType;
701 switch( numType )
703 case CHARS_UPPER_LETTER:
704 lcl_formatChars( upperLetter, 26, number-1, result ); // 1=>A, 2=>B, ..., 26=>Z, 27=>AA, 28=>AB, ...
705 break;
706 case CHARS_LOWER_LETTER:
707 lcl_formatChars( lowerLetter, 26, number-1, result );
708 break;
709 case TEXT_NUMBER: // ordinal indicators (1st, 2nd, 3rd, ...)
710 natNum = NativeNumberMode::NATNUM12;
711 sNatNumParams = "capitalize ordinal-number";
712 locale = aLocale;
713 break;
714 case TEXT_CARDINAL: // cardinal number names (One, Two, Three, ...)
715 natNum = NativeNumberMode::NATNUM12;
716 sNatNumParams = "capitalize";
717 locale = aLocale;
718 break;
719 case TEXT_ORDINAL: // ordinal number names (First, Second, Third, ...)
720 natNum = NativeNumberMode::NATNUM12;
721 sNatNumParams = "capitalize ordinal";
722 locale = aLocale;
723 break;
724 case ROMAN_UPPER:
725 result += toRoman( number );
726 break;
727 case ROMAN_LOWER:
728 result += toRoman( number ).toAsciiLowerCase();
729 break;
730 case ARABIC:
731 result += OUString::number( number );
732 break;
733 case NUMBER_NONE:
734 return OUString(); // ignore prefix and suffix
735 case CHAR_SPECIAL:
736 // apparently, we're supposed to return an empty string in this case...
737 return OUString(); // ignore prefix and suffix
738 case PAGE_DESCRIPTOR:
739 case BITMAP:
740 OSL_ASSERT(false);
741 throw IllegalArgumentException();
742 case CHARS_UPPER_LETTER_N:
743 lcl_formatChars1( upperLetter, 26, number-1, result ); // 1=>A, 2=>B, ..., 26=>Z, 27=>AA, 28=>BB, ...
744 break;
745 case CHARS_LOWER_LETTER_N:
746 lcl_formatChars1( lowerLetter, 26, number-1, result ); // 1=>A, 2=>B, ..., 26=>Z, 27=>AA, 28=>BB, ...
747 break;
748 case TRANSLITERATION:
749 try {
750 const OUString tmp = OUString::number( number );
751 OUString transliteration;
752 getPropertyByName(aProperties, "Transliteration") >>= transliteration;
753 if ( !translit )
754 translit = new TransliterationImpl(m_xContext);
755 translit->loadModuleByImplName(transliteration, aLocale);
756 result += translit->transliterateString2String(tmp, 0, tmp.getLength());
757 } catch (Exception& ) {
758 // When transliteration property is missing, return default number (bug #101141#)
759 result += OUString::number( number );
760 // OSL_ASSERT(0);
761 // throw IllegalArgumentException();
763 break;
764 case NATIVE_NUMBERING:
765 natNum = NativeNumberMode::NATNUM1;
766 locale = aLocale;
767 break;
768 case FULLWIDTH_ARABIC:
769 natNum = NativeNumberMode::NATNUM3;
770 locale = aLocale;
771 break;
772 case NUMBER_LOWER_ZH:
773 natNum = NativeNumberMode::NATNUM12;
774 locale.Language = "zh";
775 break;
776 case NUMBER_UPPER_ZH:
777 natNum = NativeNumberMode::NATNUM5;
778 locale.Language = "zh";
779 break;
780 case NUMBER_UPPER_ZH_TW:
781 natNum = NativeNumberMode::NATNUM5;
782 locale.Language = "zh";
783 locale.Country = "TW";
784 break;
785 case NUMBER_TRADITIONAL_JA:
786 natNum = NativeNumberMode::NATNUM8;
787 locale.Language = "ja";
788 break;
789 case NUMBER_UPPER_KO:
790 natNum = NativeNumberMode::NATNUM8;
791 locale.Language = "ko";
792 break;
793 case NUMBER_HANGUL_KO:
794 natNum = NativeNumberMode::NATNUM11;
795 locale.Language = "ko";
796 break;
797 case NUMBER_DIGITAL_KO:
798 natNum = NativeNumberMode::NATNUM9;
799 locale.Language = "ko";
800 break;
801 case NUMBER_DIGITAL2_KO:
802 natNum = NativeNumberMode::NATNUM1;
803 locale.Language = "ko";
804 break;
805 case NUMBER_LEGAL_KO:
806 if (number < 1 || number >= 100)
808 natNum = NativeNumberMode::NATNUM11;
809 locale.Language = "ko";
811 else
813 lcl_formatKoreanLegalWord(number, result);
815 break;
817 case CIRCLE_NUMBER:
818 table = table_CircledNumber;
819 tableSize = std::size(table_CircledNumber);
820 break;
821 case TIAN_GAN_ZH:
822 table = table_TianGan_zh;
823 tableSize = std::size(table_TianGan_zh);
824 break;
825 case DI_ZI_ZH:
826 table = table_DiZi_zh;
827 tableSize = std::size(table_DiZi_zh);
828 break;
829 case AIU_FULLWIDTH_JA:
830 table = table_AIUFullWidth_ja_JP;
831 tableSize = std::size(table_AIUFullWidth_ja_JP);
832 bRecycleSymbol = true;
833 break;
834 case AIU_HALFWIDTH_JA:
835 table = table_AIUHalfWidth_ja_JP;
836 tableSize = std::size(table_AIUHalfWidth_ja_JP);
837 bRecycleSymbol = true;
838 break;
839 case IROHA_FULLWIDTH_JA:
840 table = table_IROHAFullWidth_ja_JP;
841 tableSize = std::size(table_IROHAFullWidth_ja_JP);
842 bRecycleSymbol = true;
843 break;
844 case IROHA_HALFWIDTH_JA:
845 table = table_IROHAHalfWidth_ja_JP;
846 tableSize = std::size(table_IROHAHalfWidth_ja_JP);
847 bRecycleSymbol = true;
848 break;
849 case HANGUL_JAMO_KO:
850 table = table_HangulJamo_ko;
851 tableSize = std::size(table_HangulJamo_ko);
852 bRecycleSymbol = true;
853 break;
854 case HANGUL_SYLLABLE_KO:
855 table = table_HangulSyllable_ko;
856 tableSize = std::size(table_HangulSyllable_ko);
857 bRecycleSymbol = true;
858 break;
859 case HANGUL_CIRCLED_JAMO_KO:
860 table = table_HangulCircledJamo_ko;
861 tableSize = std::size(table_HangulCircledJamo_ko);
862 bRecycleSymbol = true;
863 break;
864 case HANGUL_CIRCLED_SYLLABLE_KO:
865 table = table_HangulCircledSyllable_ko;
866 tableSize = std::size(table_HangulCircledSyllable_ko);
867 bRecycleSymbol = true;
868 break;
869 case CHARS_ARABIC:
870 lcl_formatChars(table_Alphabet_ar, std::size(table_Alphabet_ar), number - 1, result);
871 break;
872 case CHARS_ARABIC_ABJAD:
873 lcl_formatChars(table_Alphabet_ar_abjad, std::size(table_Alphabet_ar_abjad), number - 1, result);
874 break;
875 case NUMBER_ARABIC_INDIC:
876 natNum = NativeNumberMode::NATNUM1;
877 locale.Language = "ar";
878 break;
879 case NUMBER_EAST_ARABIC_INDIC:
880 natNum = NativeNumberMode::NATNUM1;
881 locale.Language = "fa";
882 break;
883 case NUMBER_INDIC_DEVANAGARI:
884 natNum = NativeNumberMode::NATNUM1;
885 locale.Language = "hi";
886 break;
887 case CHARS_THAI:
888 lcl_formatChars(table_Alphabet_th, std::size(table_Alphabet_th), number - 1, result);
889 break;
890 case CHARS_HEBREW:
891 lcl_formatChars(table_Alphabet_he, std::size(table_Alphabet_he), number - 1, result);
892 break;
893 case NUMBER_HEBREW:
894 natNum = NativeNumberMode::NATNUM1;
895 locale.Language = "he";
896 break;
897 case CHARS_NEPALI:
898 lcl_formatChars(table_Alphabet_ne, std::size(table_Alphabet_ne), number - 1, result);
899 break;
900 case CHARS_KHMER:
901 lcl_formatChars(table_Alphabet_km, std::size(table_Alphabet_km), number - 1, result);
902 break;
903 case CHARS_LAO:
904 lcl_formatChars(table_Alphabet_lo, std::size(table_Alphabet_lo), number - 1, result);
905 break;
906 case CHARS_MYANMAR:
907 lcl_formatChars(table_Alphabet_my, std::size(table_Alphabet_my), number - 1, result);
908 break;
909 case CHARS_TIBETAN:
910 lcl_formatChars(table_Alphabet_dz, std::size(table_Alphabet_dz), number - 1, result);
911 break;
912 case CHARS_CYRILLIC_UPPER_LETTER_BG:
913 lcl_formatChars2( table_CyrillicUpperLetter_bg,
914 table_CyrillicLowerLetter_bg,
915 std::size(table_CyrillicLowerLetter_bg), number-1,
916 result); // 1=>a, 2=>b, ..., 28=>z, 29=>Aa, 30=>Ab, ...
917 break;
918 case CHARS_CYRILLIC_LOWER_LETTER_BG:
919 lcl_formatChars( table_CyrillicLowerLetter_bg,
920 std::size(table_CyrillicLowerLetter_bg), number-1,
921 result); // 1=>a, 2=>b, ..., 28=>z, 29=>aa, 30=>ab, ...
922 break;
923 case CHARS_CYRILLIC_UPPER_LETTER_N_BG:
924 lcl_formatChars3( table_CyrillicUpperLetter_bg,
925 table_CyrillicLowerLetter_bg,
926 std::size(table_CyrillicLowerLetter_bg), number-1,
927 result); // 1=>a, 2=>b, ..., 28=>z, 29=>Aa, 30=>Bb, ...
928 break;
929 case CHARS_CYRILLIC_LOWER_LETTER_N_BG:
930 lcl_formatChars1( table_CyrillicLowerLetter_bg,
931 std::size(table_CyrillicLowerLetter_bg), number-1,
932 result); // 1=>a, 2=>b, ..., 28=>z, 29=>aa, 30=>bb, ...
933 break;
934 case CHARS_CYRILLIC_UPPER_LETTER_RU:
935 lcl_formatChars2( table_CyrillicUpperLetter_ru,
936 table_CyrillicLowerLetter_ru,
937 std::size(table_CyrillicLowerLetter_ru), number-1,
938 result); // 1=>a, 2=>b, ..., 27=>z, 28=>Aa, 29=>Ab, ...
939 break;
940 case CHARS_CYRILLIC_LOWER_LETTER_RU:
941 lcl_formatChars( table_CyrillicLowerLetter_ru,
942 std::size(table_CyrillicLowerLetter_ru), number-1,
943 result); // 1=>a, 2=>b, ..., 27=>z, 28=>aa, 29=>ab, ...
944 break;
945 case CHARS_CYRILLIC_UPPER_LETTER_N_RU:
946 lcl_formatChars3( table_CyrillicUpperLetter_ru,
947 table_CyrillicLowerLetter_ru,
948 std::size(table_CyrillicLowerLetter_ru), number-1,
949 result); // 1=>a, 2=>b, ..., 27=>z, 28=>Aa, 29=>Bb, ...
950 break;
951 case CHARS_CYRILLIC_LOWER_LETTER_N_RU:
952 lcl_formatChars1( table_CyrillicLowerLetter_ru,
953 std::size(table_CyrillicLowerLetter_ru), number-1,
954 result); // 1=>a, 2=>b, ..., 27=>z, 28=>aa, 29=>bb, ...
955 break;
956 case CHARS_CYRILLIC_UPPER_LETTER_SR:
957 lcl_formatChars2( table_CyrillicUpperLetter_sr,
958 table_CyrillicLowerLetter_sr,
959 std::size(table_CyrillicLowerLetter_sr), number-1,
960 result); // 1=>a, 2=>b, ..., 27=>z, 28=>Aa, 29=>Ab, ...
961 break;
962 case CHARS_CYRILLIC_LOWER_LETTER_SR:
963 lcl_formatChars( table_CyrillicLowerLetter_sr,
964 std::size(table_CyrillicLowerLetter_sr), number-1,
965 result); // 1=>a, 2=>b, ..., 27=>z, 28=>aa, 29=>ab, ...
966 break;
967 case CHARS_CYRILLIC_UPPER_LETTER_N_SR:
968 lcl_formatChars3( table_CyrillicUpperLetter_sr,
969 table_CyrillicLowerLetter_sr,
970 std::size(table_CyrillicLowerLetter_sr), number-1,
971 result); // 1=>a, 2=>b, ..., 27=>z, 28=>Aa, 29=>Bb, ...
972 break;
973 case CHARS_CYRILLIC_LOWER_LETTER_N_SR:
974 lcl_formatChars1( table_CyrillicLowerLetter_sr,
975 std::size(table_CyrillicLowerLetter_sr), number-1,
976 result); // 1=>a, 2=>b, ..., 27=>z, 28=>aa, 29=>bb, ...
977 break;
979 case CHARS_CYRILLIC_UPPER_LETTER_UK:
980 lcl_formatChars2( table_CyrillicUpperLetter_uk,
981 table_CyrillicLowerLetter_uk,
982 std::size(table_CyrillicLowerLetter_uk), number-1,
983 result);
984 break;
985 case CHARS_CYRILLIC_LOWER_LETTER_UK:
986 lcl_formatChars( table_CyrillicLowerLetter_uk,
987 std::size(table_CyrillicLowerLetter_uk), number-1,
988 result);
989 break;
990 case CHARS_CYRILLIC_UPPER_LETTER_N_UK:
991 lcl_formatChars3( table_CyrillicUpperLetter_uk,
992 table_CyrillicLowerLetter_uk,
993 std::size(table_CyrillicLowerLetter_uk), number-1,
994 result);
995 break;
996 case CHARS_CYRILLIC_LOWER_LETTER_N_UK:
997 lcl_formatChars1( table_CyrillicLowerLetter_uk,
998 std::size(table_CyrillicLowerLetter_uk), number-1,
999 result);
1000 break;
1002 case CHARS_GREEK_LOWER_LETTER:
1003 lcl_formatCharsGR( table_GreekLowerLetter, number, result);
1004 break;
1006 case CHARS_GREEK_UPPER_LETTER:
1007 lcl_formatCharsGR( table_GreekUpperLetter, number, result);
1008 break;
1010 case CHARS_PERSIAN:
1011 lcl_formatChars(table_Alphabet_fa, std::size(table_Alphabet_fa), number - 1, result);
1012 break;
1014 case CHARS_PERSIAN_WORD:
1015 lcl_formatPersianWord(number, result);
1016 break;
1018 case SYMBOL_CHICAGO:
1019 lcl_formatChars1( table_Chicago, 4, number-1, result ); // *, +, |, S, **, ++, ...
1020 break;
1022 case ARABIC_ZERO:
1023 result += lcl_formatArabicZero(number, 2);
1024 break;
1026 case ARABIC_ZERO3:
1027 result += lcl_formatArabicZero(number, 3);
1028 break;
1030 case ARABIC_ZERO4:
1031 result += lcl_formatArabicZero(number, 4);
1032 break;
1034 case ARABIC_ZERO5:
1035 result += lcl_formatArabicZero(number, 5);
1036 break;
1038 case SZEKELY_ROVAS: // Old Hungarian
1039 natNum = NativeNumberMode::NATNUM12;
1040 locale.Language = "hu-Hung";
1041 break;
1043 default:
1044 OSL_ASSERT(false);
1045 throw IllegalArgumentException();
1048 if (natNum) {
1049 if (!mxNatNum)
1050 mxNatNum.set(new NativeNumberSupplierService);
1051 result += mxNatNum->getNativeNumberStringParams(OUString::number(number), locale,
1052 natNum, sNatNumParams);
1053 } else if (tableSize) {
1054 if ( number > tableSize && !bRecycleSymbol)
1055 result += OUString::number( number);
1056 else
1057 result += OUStringChar(table[--number % tableSize]);
1060 // append suffix
1061 if( !should_ignore(suffix) ) result += suffix;
1063 return result;
1066 #define LANG_ALL (1 << 0)
1067 #define LANG_CJK (1 << 1)
1068 #define LANG_CTL (1 << 2)
1070 struct Supported_NumberingType
1072 const char* cSymbol;
1073 sal_Int16 nType;
1074 sal_Int16 langOption;
1075 Supported_NumberingType(sal_Int16 nType_, const char* pSymbol, sal_Int16 opt)
1076 : cSymbol(pSymbol), nType(nType_), langOption(opt) {}
1078 const Supported_NumberingType aSupportedTypes[] =
1080 {style::NumberingType::CHARS_UPPER_LETTER, "A", LANG_ALL},
1081 {style::NumberingType::CHARS_LOWER_LETTER, "a", LANG_ALL},
1082 {style::NumberingType::ROMAN_UPPER, "I", LANG_ALL},
1083 {style::NumberingType::ROMAN_LOWER, "i", LANG_ALL},
1084 {style::NumberingType::ARABIC, "1", LANG_ALL},
1085 {style::NumberingType::NUMBER_NONE, "''", LANG_ALL},
1086 {style::NumberingType::CHAR_SPECIAL, "Bullet", LANG_ALL},
1087 {style::NumberingType::PAGE_DESCRIPTOR, "Page", LANG_ALL},
1088 {style::NumberingType::BITMAP, "Bitmap", LANG_ALL},
1089 {style::NumberingType::SYMBOL_CHICAGO, "*, " S_DAGGER ", " S_DBL_DAGGER ", " S_SECTION ", **, " S_DAGGER S_DAGGER ", ...", LANG_ALL},
1090 {style::NumberingType::TEXT_NUMBER, "1st", LANG_ALL},
1091 {style::NumberingType::TEXT_CARDINAL, "One", LANG_ALL},
1092 {style::NumberingType::TEXT_ORDINAL, "First", LANG_ALL},
1093 {style::NumberingType::CHARS_UPPER_LETTER_N, "AAA", LANG_ALL},
1094 {style::NumberingType::CHARS_LOWER_LETTER_N, "aaa", LANG_ALL},
1095 {style::NumberingType::NATIVE_NUMBERING, "Native Numbering", LANG_CJK|LANG_CTL},
1096 {style::NumberingType::FULLWIDTH_ARABIC, nullptr, LANG_CJK},
1097 {style::NumberingType::CIRCLE_NUMBER, nullptr, LANG_CJK},
1098 // The cSymbol is defined here for compatibility with files created by old releases.
1099 // Otherwise if nullptr, these 3 digits may change as NATNUM12 depends on 3rd-party lib.
1100 {style::NumberingType::NUMBER_LOWER_ZH, "一, 二, 三, ...", LANG_CJK},
1101 {style::NumberingType::NUMBER_UPPER_ZH, nullptr, LANG_CJK},
1102 {style::NumberingType::NUMBER_UPPER_ZH_TW, nullptr, LANG_CJK},
1103 {style::NumberingType::TIAN_GAN_ZH, nullptr, LANG_CJK},
1104 {style::NumberingType::DI_ZI_ZH, nullptr, LANG_CJK},
1105 {style::NumberingType::NUMBER_TRADITIONAL_JA, nullptr, LANG_CJK},
1106 {style::NumberingType::AIU_FULLWIDTH_JA, nullptr, LANG_CJK},
1107 {style::NumberingType::AIU_HALFWIDTH_JA, nullptr, LANG_CJK},
1108 {style::NumberingType::IROHA_FULLWIDTH_JA, nullptr, LANG_CJK},
1109 {style::NumberingType::IROHA_HALFWIDTH_JA, nullptr, LANG_CJK},
1110 {style::NumberingType::NUMBER_UPPER_KO, nullptr, LANG_CJK},
1111 {style::NumberingType::NUMBER_HANGUL_KO, nullptr, LANG_CJK},
1112 {style::NumberingType::HANGUL_JAMO_KO, nullptr, LANG_CJK},
1113 {style::NumberingType::HANGUL_SYLLABLE_KO, nullptr, LANG_CJK},
1114 {style::NumberingType::HANGUL_CIRCLED_JAMO_KO, nullptr, LANG_CJK},
1115 {style::NumberingType::HANGUL_CIRCLED_SYLLABLE_KO, nullptr, LANG_CJK},
1116 {style::NumberingType::NUMBER_LEGAL_KO, nullptr, LANG_CJK},
1117 {style::NumberingType::NUMBER_DIGITAL_KO, nullptr, LANG_CJK},
1118 {style::NumberingType::NUMBER_DIGITAL2_KO, nullptr, LANG_CJK},
1119 {style::NumberingType::CHARS_ARABIC, nullptr, LANG_CTL},
1120 {style::NumberingType::CHARS_ARABIC_ABJAD, nullptr, LANG_CTL},
1121 {style::NumberingType::NUMBER_ARABIC_INDIC, S_AR_ONE ", " S_AR_TWO ", " S_AR_THREE ", ...", LANG_CTL},
1122 {style::NumberingType::NUMBER_EAST_ARABIC_INDIC, S_FA_ONE ", " S_FA_TWO ", " S_FA_THREE ", ...", LANG_CTL},
1123 {style::NumberingType::NUMBER_INDIC_DEVANAGARI, S_HI_ONE ", " S_HI_TWO ", " S_HI_THREE ", ...", LANG_CTL},
1124 {style::NumberingType::CHARS_THAI, nullptr, LANG_CTL},
1125 {style::NumberingType::CHARS_HEBREW, nullptr, LANG_CTL},
1126 {style::NumberingType::NUMBER_HEBREW, S_HE_ALEPH ", " S_HE_YOD ", " S_HE_QOF ", ...", LANG_CTL},
1127 {style::NumberingType::CHARS_NEPALI, nullptr, LANG_CTL},
1128 {style::NumberingType::CHARS_KHMER, nullptr, LANG_CTL},
1129 {style::NumberingType::CHARS_LAO, nullptr, LANG_CTL},
1130 {style::NumberingType::CHARS_MYANMAR, nullptr, LANG_CTL},
1131 {style::NumberingType::CHARS_TIBETAN, nullptr, LANG_CTL},
1132 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_BG, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_A S_CYR_B ", ... (bg)", LANG_ALL},
1133 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_BG, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_A S_CYR_B ", ... (bg)", LANG_ALL},
1134 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_N_BG, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_B S_CYR_B ", ... (bg)", LANG_ALL},
1135 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_N_BG, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_B S_CYR_B ", ... (bg)", LANG_ALL},
1136 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_RU, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_A S_CYR_B ", ... (ru)", LANG_ALL},
1137 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_RU, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_A S_CYR_B ", ... (ru)", LANG_ALL},
1138 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_N_RU, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_B S_CYR_B ", ... (ru)", LANG_ALL},
1139 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_N_RU, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_B S_CYR_B ", ... (ru)", LANG_ALL},
1140 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_SR, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_A S_CYR_B ", ... (sr)", LANG_ALL},
1141 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_SR, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_A S_CYR_B ", ... (sr)", LANG_ALL},
1142 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_N_SR, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_B S_CYR_B ", ... (sr)", LANG_ALL},
1143 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_N_SR, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_B S_CYR_B ", ... (sr)", LANG_ALL},
1144 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_UK, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_A S_CYR_B ", ... (uk)", LANG_ALL},
1145 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_UK, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_A S_CYR_B ", ... (uk)", LANG_ALL},
1146 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_N_UK, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_B S_CYR_B ", ... (uk)", LANG_ALL},
1147 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_N_UK, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_B S_CYR_B ", ... (uk)", LANG_ALL},
1148 {style::NumberingType::CHARS_PERSIAN, nullptr, LANG_CTL},
1149 {style::NumberingType::CHARS_PERSIAN_WORD, nullptr, LANG_CTL},
1150 {style::NumberingType::SZEKELY_ROVAS, nullptr, LANG_CTL},
1151 {style::NumberingType::CHARS_GREEK_UPPER_LETTER, C_GR_A ", " C_GR_B ", ... (gr)", LANG_ALL},
1152 {style::NumberingType::CHARS_GREEK_LOWER_LETTER, S_GR_A ", " S_GR_B ", ... (gr)", LANG_ALL},
1153 {style::NumberingType::ARABIC_ZERO, "01, 02, 03, ...", LANG_ALL},
1154 {style::NumberingType::ARABIC_ZERO3, "001, 002, 003, ...", LANG_ALL},
1155 {style::NumberingType::ARABIC_ZERO4, "0001, 0002, 0003, ...", LANG_ALL},
1156 {style::NumberingType::ARABIC_ZERO5, "00001, 00002, 00003, ...", LANG_ALL},
1158 const sal_Int32 nSupported_NumberingTypes = std::size(aSupportedTypes);
1160 OUString DefaultNumberingProvider::makeNumberingIdentifier(sal_Int16 index)
1162 if (index < 0 || index >= nSupported_NumberingTypes)
1163 throw RuntimeException();
1165 if (aSupportedTypes[index].cSymbol)
1166 return OUString(aSupportedTypes[index].cSymbol, strlen(aSupportedTypes[index].cSymbol), RTL_TEXTENCODING_UTF8);
1167 else {
1168 OUStringBuffer result;
1169 Locale aLocale(u"en"_ustr, OUString(), OUString());
1170 Sequence<beans::PropertyValue> aProperties(2);
1171 auto aPropertiesRange = asNonConstRange(aProperties);
1172 aPropertiesRange[0].Name = "NumberingType";
1173 aPropertiesRange[0].Value <<= aSupportedTypes[index].nType;
1174 aPropertiesRange[1].Name = "Value";
1175 for (sal_Int32 j = 1; j <= 3; j++) {
1176 aPropertiesRange[1].Value <<= j;
1177 result.append( makeNumberingString( aProperties, aLocale ) + ", " );
1179 result.append("...");
1180 // Make known duplicate generated identifiers unique.
1181 // Note this alone works only for newly added numberings, if duplicates
1182 // are in the wild further handling is needed when loading documents
1183 // and asking for numberings.
1184 switch (aSupportedTypes[index].nType)
1186 case css::style::NumberingType::NUMBER_DIGITAL_KO:
1187 // Duplicate of NUMBER_HANGUL_KO.
1188 result.append(" (ko-x-digital)");
1189 break;
1190 case css::style::NumberingType::NUMBER_DIGITAL2_KO:
1191 // Duplicate of NUMBER_LOWER_ZH.
1192 result.append(" (ko)");
1193 break;
1194 default:
1195 ; // nothing
1197 return result.makeStringAndClear();
1201 bool
1202 DefaultNumberingProvider::isScriptFlagEnabled(const OUString& aName)
1204 if (! xHierarchicalNameAccess.is())
1205 xHierarchicalNameAccess = officecfg::Office::Common::I18N::get();
1207 Any aEnabled = xHierarchicalNameAccess->getByHierarchicalName(aName);
1209 bool enabled = false;
1211 aEnabled >>= enabled;
1213 return enabled;
1216 Sequence< sal_Int16 > DefaultNumberingProvider::getSupportedNumberingTypes( )
1218 Sequence< sal_Int16 > aRet(nSupported_NumberingTypes );
1219 sal_Int16* pArray = aRet.getArray();
1221 bool cjkEnabled = isScriptFlagEnabled(u"CJK/CJKFont"_ustr);
1222 bool ctlEnabled = isScriptFlagEnabled(u"CTL/CTLFont"_ustr);
1224 for(sal_Int16 i = 0; i < nSupported_NumberingTypes; i++) {
1225 if ( (aSupportedTypes[i].langOption & LANG_ALL) ||
1226 ((aSupportedTypes[i].langOption & LANG_CJK) && cjkEnabled) ||
1227 ((aSupportedTypes[i].langOption & LANG_CTL) && ctlEnabled) )
1228 pArray[i] = aSupportedTypes[i].nType;
1230 return aRet;
1233 sal_Int16 DefaultNumberingProvider::getNumberingType( const OUString& rNumberingIdentifier )
1235 auto it = maSupportedTypesCache.find(rNumberingIdentifier);
1236 if (it != maSupportedTypesCache.end())
1237 return it->second->nType;
1238 for(sal_Int16 i = 0; i < nSupported_NumberingTypes; i++)
1239 if(rNumberingIdentifier == makeNumberingIdentifier(i))
1241 maSupportedTypesCache.emplace(rNumberingIdentifier, &aSupportedTypes[i]);
1242 return aSupportedTypes[i].nType;
1244 throw RuntimeException();
1247 sal_Bool DefaultNumberingProvider::hasNumberingType( const OUString& rNumberingIdentifier )
1249 auto it = maSupportedTypesCache.find(rNumberingIdentifier);
1250 if (it != maSupportedTypesCache.end())
1251 return true;
1252 for(sal_Int16 i = 0; i < nSupported_NumberingTypes; i++)
1253 if(rNumberingIdentifier == makeNumberingIdentifier(i))
1255 maSupportedTypesCache.emplace(rNumberingIdentifier, &aSupportedTypes[i]);
1256 return true;
1258 return false;
1261 OUString DefaultNumberingProvider::getNumberingIdentifier( sal_Int16 nNumberingType )
1263 for(sal_Int16 i = 0; i < nSupported_NumberingTypes; i++)
1264 if(nNumberingType == aSupportedTypes[i].nType)
1265 return makeNumberingIdentifier(i);
1266 return OUString();
1269 OUString DefaultNumberingProvider::getImplementationName()
1271 return u"com.sun.star.text.DefaultNumberingProvider"_ustr;
1274 sal_Bool DefaultNumberingProvider::supportsService(const OUString& rServiceName)
1276 return cppu::supportsService(this, rServiceName);
1279 Sequence< OUString > DefaultNumberingProvider::getSupportedServiceNames()
1281 Sequence< OUString > aRet { u"com.sun.star.text.DefaultNumberingProvider"_ustr };
1282 return aRet;
1287 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1288 com_sun_star_text_DefaultNumberingProvider_get_implementation(
1289 css::uno::XComponentContext *context,
1290 css::uno::Sequence<css::uno::Any> const &)
1292 return cppu::acquire(new i18npool::DefaultNumberingProvider(context));
1295 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */