1 /* This file is part of the KDE project
2 
3    Copyright (C) 2010 Boudewijn Rempt
4    Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
5 
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public
8    License version 2 as published by the Free Software Foundation.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19  */
20 #include "KoOdfNumberDefinition.h"
21 
22 #include "KoXmlNS.h"
23 #include "KoXmlWriter.h"
24 #include "KoXmlReader.h"
25 
26 class Q_DECL_HIDDEN KoOdfNumberDefinition::Private
27 {
28 public:
29     QString prefix;
30     QString suffix;
31     KoOdfNumberDefinition::FormatSpecification formatSpecification;
32     bool letterSynchronization;
33 };
34 
KoOdfNumberDefinition()35 KoOdfNumberDefinition::KoOdfNumberDefinition()
36     : d(new Private())
37 {
38     d->formatSpecification = Numeric;
39     d->letterSynchronization = false;
40 }
41 
KoOdfNumberDefinition(const KoOdfNumberDefinition & other)42 KoOdfNumberDefinition::KoOdfNumberDefinition(const KoOdfNumberDefinition &other)
43     : d(new Private())
44 {
45     d->prefix = other.d->prefix;
46     d->suffix = other.d->suffix;
47     d->formatSpecification = other.d->formatSpecification;
48     d->letterSynchronization = other.d->letterSynchronization;
49 }
50 
operator =(const KoOdfNumberDefinition & other)51 KoOdfNumberDefinition &KoOdfNumberDefinition::operator=(const KoOdfNumberDefinition &other)
52 {
53     d->prefix = other.d->prefix;
54     d->suffix = other.d->suffix;
55     d->formatSpecification = other.d->formatSpecification;
56     d->letterSynchronization = other.d->letterSynchronization;
57 
58     return *this;
59 }
60 
~KoOdfNumberDefinition()61 KoOdfNumberDefinition::~KoOdfNumberDefinition()
62 {
63     delete d;
64 }
65 
loadOdf(const KoXmlElement & element)66 void KoOdfNumberDefinition::loadOdf(const KoXmlElement &element)
67 {
68     const QString format = element.attributeNS(KoXmlNS::style, "num-format", QString());
69     if (format.isEmpty()) {
70         //do nothing fall back to what we had.
71     }
72     else if (format[0] == '1') {
73         d->formatSpecification = Numeric;
74     }
75     else if (format[0] == 'a') {
76         d->formatSpecification = AlphabeticLowerCase;
77     }
78     else if (format[0] == 'A') {
79         d->formatSpecification = AlphabeticUpperCase;
80     }
81     else if (format[0] == 'i') {
82         d->formatSpecification = RomanLowerCase;
83     }
84     else if (format[0] == 'I') {
85         d->formatSpecification = RomanUpperCase;
86     }
87     else if (format == QString::fromUtf8("أ, ب, ت, ...")){
88         d->formatSpecification = ArabicAlphabet;
89     }
90     else if (format == QString::fromUtf8("ก, ข, ค, ...")){
91         d->formatSpecification = Thai;
92     }
93     else if (format == QString::fromUtf8("أ, ب, ج, ...")) {
94         d->formatSpecification = Abjad;
95     }
96     else if (format == QString::fromUtf8("ﺃ,ﺏ, ﺝ, ... ")) {
97         d->formatSpecification = AbjadMinor;
98     }
99     else if (format == QString::fromUtf8("౧, ౨, ౩, ...")) {
100         d->formatSpecification = Telugu;
101     }
102     else if (format == QString::fromUtf8("௧, ௨, ௪, ...")) {
103         d->formatSpecification = Tamil;
104     }
105     else if (format == QString::fromUtf8("୧, ୨, ୩, ...")) {
106         d->formatSpecification = Oriya;
107     }
108     else if (format == QString::fromUtf8("൧, ൨, ൩, ...")) {
109         d->formatSpecification = Malayalam;
110     }
111     else if (format == QString::fromUtf8("೧, ೨, ೩, ...")) {
112         d->formatSpecification = Kannada;
113     }
114     else if (format == QString::fromUtf8("੧, ੨, ੩, ...")) {
115         d->formatSpecification = Gurumukhi;
116     }
117     else if (format == QString::fromUtf8("૧, ૨, ૩, ...")) {
118         d->formatSpecification = Gujarati;
119     }
120     else if (format == QString::fromUtf8("১, ২, ৩, ...")) {
121         d->formatSpecification = Bengali;
122     }
123     else {
124         d->formatSpecification = Numeric;
125     }
126 
127     //The style:num-prefix and style:num-suffix attributes specify what to display before and after the number.
128     d->prefix = element.attributeNS(KoXmlNS::style, "num-prefix", d->prefix);
129     d->suffix = element.attributeNS(KoXmlNS::style, "num-suffix", d->suffix);
130 
131     d->letterSynchronization = (element.attributeNS(KoXmlNS::style, "num-letter-sync", d->letterSynchronization ? "true" : "false") == "true");
132 }
133 
saveOdf(KoXmlWriter * writer) const134 void KoOdfNumberDefinition::saveOdf(KoXmlWriter *writer) const
135 {
136     if (!d->prefix.isNull()) {
137         writer->addAttribute("style:num-prefix", d->prefix);
138     }
139 
140     if (!d->suffix.isNull()) {
141         writer->addAttribute("style:num-suffix", d->suffix);
142     }
143     QByteArray format;
144     switch(d->formatSpecification) {
145     case Numeric:
146         format = "1";
147         break;
148     case AlphabeticLowerCase:
149         format = "a";
150         break;
151     case AlphabeticUpperCase:
152         format = "A";
153         break;
154     case RomanLowerCase:
155         format = "i";
156         break;
157     case RomanUpperCase:
158         format = "I";
159         break;
160     case ArabicAlphabet:
161         format = "أ, ب, ت, ...";
162         break;
163     case Thai:
164         format = "ก, ข, ค, ...";
165         break;
166     case Telugu:
167         format = "౧, ౨, ౩, ...";
168         break;
169     case Tamil:
170         format = "௧, ௨, ௪, ...";
171         break;
172     case Oriya:
173         format = "୧, ୨, ୩, ...";
174         break;
175     case Malayalam:
176         format = "൧, ൨, ൩, ...";
177         break;
178     case Kannada:
179         format = "೧, ೨, ೩, ...";
180         break;
181     case Gurumukhi:
182         format = "੧, ੨, ੩, ...";
183         break;
184     case Gujarati:
185         format = "૧, ૨, ૩, ...";
186         break;
187     case Bengali:
188         format = "১, ২, ৩, ...";
189         break;
190     case Empty:
191     default:
192         ;
193     };
194     if (!format.isNull()) {
195         writer->addAttribute("style:num-format", format);
196     }
197 
198     if (d->letterSynchronization) {
199         writer->addAttribute("style:num-letter-sync", "true");
200     }
201 }
202 
formattedNumber(int number,KoOdfNumberDefinition * defaultDefinition) const203 QString KoOdfNumberDefinition::formattedNumber(int number, KoOdfNumberDefinition *defaultDefinition) const
204 {
205    switch(d->formatSpecification) {
206     case Numeric:
207         return QString::number(number);
208         break;
209 
210     case AlphabeticLowerCase:
211     {
212         if (d->letterSynchronization) {
213             int loop = (number-1)/26;
214             int rem = (number-1)%26;
215             QChar letter = (char)(rem+97);
216             QString alpha;
217             for (int i=0; i<=loop; i++) {
218                 alpha.append(letter);
219             }
220             return alpha;
221         } else {
222             int loop = (number-1)/26;
223             QChar letter;
224             QString alpha;
225             if (loop>0) {
226                 letter = (char)(loop+96);
227                 alpha.append(letter);
228             }
229             int rem = (number -1)%26;
230             letter = (char)(rem+97);
231             alpha.append(letter);
232             return alpha;
233         }
234         break;
235     }
236     case AlphabeticUpperCase:
237     {
238         if (d->letterSynchronization) {
239             int loop = (number-1)/26;
240             int rem = (number-1)%26;
241             QChar letter = (char)(rem+65);
242             QString alpha;
243             for (int i=0; i<=loop; i++) {
244                 alpha.append(letter);
245             }
246             return alpha;
247         } else {
248             int loop = (number-1)/26;
249             QChar letter;
250             QString alpha;
251             if (loop>0) {
252                 letter = (char)(loop+64);
253                 alpha.append(letter);
254             }
255             int rem = (number -1)%26;
256             letter = (char)(rem+65);
257             alpha.append(letter);
258             return alpha;
259         }
260         break;
261     }
262     case RomanLowerCase:
263     {
264         QString roman;
265         int loop = number/1000;
266         for (int i=1; i<=loop && number/1000!=0; i++) {
267              roman.append("m");
268         }
269         number = number%1000;
270         loop = number/500;
271         if (loop > 0) {
272             roman.append("d");
273         }
274         number = number%500;
275         loop = number/100;
276         for (int i=1; i<=loop && number/100!=0; i++) {
277             roman.append("c");
278         }
279         number = number%100;
280         loop = number/50;
281         if (loop > 0) {
282             roman.append("l");
283         }
284         number = number%50;
285         loop = number/10;
286         for (int i=1; i<=loop && number/10!=0; i++) {
287              roman.append("x");
288         }
289         number = number%10;
290         if (number>=5 && number<=8) {
291              loop = number%5;
292              roman.append("v");
293              for (int i=1;i<=loop;i++)
294                 roman.append("i");
295         }
296         else if (number==9) {
297              roman.append("ix");
298         }
299         else if (number>=1 && number<=3) {
300              for (int i=1; i<=number; i++)
301                 roman.append("i");
302         }
303         else if (number==4)
304             roman.append("iv");
305 
306         return roman;
307         break;
308     }
309     case RomanUpperCase:
310     {
311         QString roman;
312         int loop = number/1000;
313         for (int i=1; i<=loop && number/1000!=0; i++) {
314              roman.append("M");
315         }
316         number = number%1000;
317         loop = number/500;
318         if (loop > 0) {
319             roman.append("D");
320         }
321         number = number%500;
322         loop = number/100;
323         for (int i=1; i<=loop && number/100!=0; i++) {
324             roman.append("C");
325         }
326         number = number%100;
327         loop = number/50;
328         if (loop > 0) {
329              roman.append("L");
330         }
331         number = number%50;
332         loop = number/10;
333         for (int i=1; i<=loop && number/10!=0; i++) {
334              roman.append("X");
335         }
336         number = number%10;
337         if (number>=5 && number<=8) {
338              loop = number%5;
339              roman.append("V");
340              for (int i=1; i<=loop; i++)
341                 roman.append("I");
342         }
343         else if (number==9) {
344              roman.append("IX");
345         }
346         else if (number>=1 && number<=3) {
347              for (int i=1; i<=number; i++)
348                 roman.append("I");
349         }
350         else if (number==4)
351             roman.append("IV");
352 
353         return roman;
354     }
355     case Empty:
356         if (defaultDefinition) {
357             return defaultDefinition->formattedNumber(number);
358         }
359 
360         break;
361     default:
362         ;
363     };
364 
365     return "";
366 }
367 
368 
prefix() const369 QString KoOdfNumberDefinition::prefix() const
370 {
371     return d->prefix;
372 }
373 
setPrefix(const QString & prefix)374 void KoOdfNumberDefinition::setPrefix(const QString &prefix)
375 {
376     d->prefix = prefix;
377 }
378 
suffix() const379 QString KoOdfNumberDefinition::suffix() const
380 {
381     return d->suffix;
382 }
383 
setSuffix(const QString & suffix)384 void KoOdfNumberDefinition::setSuffix(const QString &suffix)
385 {
386     d->suffix = suffix;
387 }
388 
formatSpecification() const389 KoOdfNumberDefinition::FormatSpecification KoOdfNumberDefinition::formatSpecification() const
390 {
391     return d->formatSpecification;
392 }
393 
setFormatSpecification(FormatSpecification formatSpecification)394 void KoOdfNumberDefinition::setFormatSpecification(FormatSpecification formatSpecification)
395 {
396     d->formatSpecification = formatSpecification;
397 }
398 
letterSynchronization() const399 bool KoOdfNumberDefinition::letterSynchronization() const
400 {
401     return d->letterSynchronization;
402 }
403 
setLetterSynchronization(bool letterSynchronization)404 void KoOdfNumberDefinition::setLetterSynchronization(bool letterSynchronization)
405 {
406     d->letterSynchronization = letterSynchronization;
407 }
408