File: | home/maarten/src/libreoffice/core/vcl/source/control/field.cxx |
Warning: | line 677, column 34 Division by zero |
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 <sal/config.h> | |||
21 | ||||
22 | #include <string_view> | |||
23 | ||||
24 | #include <sal/log.hxx> | |||
25 | #include <osl/diagnose.h> | |||
26 | ||||
27 | #include <comphelper/string.hxx> | |||
28 | ||||
29 | #include <vcl/builder.hxx> | |||
30 | #include <vcl/fieldvalues.hxx> | |||
31 | #include <vcl/toolkit/field.hxx> | |||
32 | #include <vcl/event.hxx> | |||
33 | #include <vcl/svapp.hxx> | |||
34 | #include <vcl/settings.hxx> | |||
35 | #include <vcl/uitest/uiobject.hxx> | |||
36 | #include <vcl/uitest/metricfielduiobject.hxx> | |||
37 | ||||
38 | #include <svdata.hxx> | |||
39 | ||||
40 | #include <i18nutil/unicode.hxx> | |||
41 | ||||
42 | #include <rtl/math.hxx> | |||
43 | ||||
44 | #include <unotools/localedatawrapper.hxx> | |||
45 | #include <boost/property_tree/ptree.hpp> | |||
46 | #include <tools/json_writer.hxx> | |||
47 | ||||
48 | using namespace ::com::sun::star; | |||
49 | using namespace ::comphelper; | |||
50 | ||||
51 | namespace | |||
52 | { | |||
53 | ||||
54 | std::string FieldUnitToString(FieldUnit unit) | |||
55 | { | |||
56 | switch(unit) | |||
57 | { | |||
58 | case FieldUnit::NONE: | |||
59 | return ""; | |||
60 | ||||
61 | case FieldUnit::MM: | |||
62 | return "mm"; | |||
63 | ||||
64 | case FieldUnit::CM: | |||
65 | return "cm"; | |||
66 | ||||
67 | case FieldUnit::M: | |||
68 | return "m"; | |||
69 | ||||
70 | case FieldUnit::KM: | |||
71 | return "km"; | |||
72 | ||||
73 | case FieldUnit::TWIP: | |||
74 | return "twip"; | |||
75 | ||||
76 | case FieldUnit::POINT: | |||
77 | return "point"; | |||
78 | ||||
79 | case FieldUnit::PICA: | |||
80 | return "pica"; | |||
81 | ||||
82 | case FieldUnit::INCH: | |||
83 | return "inch"; | |||
84 | ||||
85 | case FieldUnit::FOOT: | |||
86 | return "foot"; | |||
87 | ||||
88 | case FieldUnit::MILE: | |||
89 | return "mile"; | |||
90 | ||||
91 | case FieldUnit::CHAR: | |||
92 | return "char"; | |||
93 | ||||
94 | case FieldUnit::LINE: | |||
95 | return "line"; | |||
96 | ||||
97 | case FieldUnit::CUSTOM: | |||
98 | return "custom"; | |||
99 | ||||
100 | case FieldUnit::PERCENT: | |||
101 | return "percent"; | |||
102 | ||||
103 | case FieldUnit::MM_100TH: | |||
104 | return "mm100th"; | |||
105 | ||||
106 | case FieldUnit::PIXEL: | |||
107 | return "pixel"; | |||
108 | ||||
109 | case FieldUnit::DEGREE: | |||
110 | return "degree"; | |||
111 | ||||
112 | case FieldUnit::SECOND: | |||
113 | return "second"; | |||
114 | ||||
115 | case FieldUnit::MILLISECOND: | |||
116 | return "millisecond"; | |||
117 | } | |||
118 | ||||
119 | return ""; | |||
120 | } | |||
121 | ||||
122 | sal_Int64 ImplPower10( sal_uInt16 n ) | |||
123 | { | |||
124 | sal_uInt16 i; | |||
125 | sal_Int64 nValue = 1; | |||
126 | ||||
127 | for ( i=0; i < n; i++ ) | |||
128 | nValue *= 10; | |||
129 | ||||
130 | return nValue; | |||
131 | } | |||
132 | ||||
133 | bool ImplNumericProcessKeyInput( const KeyEvent& rKEvt, | |||
134 | bool bStrictFormat, bool bThousandSep, | |||
135 | const LocaleDataWrapper& rLocaleDataWrapper ) | |||
136 | { | |||
137 | if ( !bStrictFormat ) | |||
138 | return false; | |||
139 | else | |||
140 | { | |||
141 | sal_Unicode cChar = rKEvt.GetCharCode(); | |||
142 | sal_uInt16 nGroup = rKEvt.GetKeyCode().GetGroup(); | |||
143 | ||||
144 | return !((nGroup == KEYGROUP_FKEYS) || | |||
145 | (nGroup == KEYGROUP_CURSOR) || | |||
146 | (nGroup == KEYGROUP_MISC) || | |||
147 | ((cChar >= '0') && (cChar <= '9')) || | |||
148 | string::equals(rLocaleDataWrapper.getNumDecimalSep(), cChar) || | |||
149 | (bThousandSep && string::equals(rLocaleDataWrapper.getNumThousandSep(), cChar)) || | |||
150 | string::equals(rLocaleDataWrapper.getNumDecimalSepAlt(), cChar) || | |||
151 | (cChar == '-')); | |||
152 | } | |||
153 | } | |||
154 | ||||
155 | bool ImplNumericGetValue( const OUString& rStr, sal_Int64& rValue, | |||
156 | sal_uInt16 nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper, | |||
157 | bool bCurrency = false ) | |||
158 | { | |||
159 | OUString aStr = rStr; | |||
160 | OUStringBuffer aStr1, aStr2, aStrNum, aStrDenom; | |||
161 | bool bNegative = false; | |||
162 | bool bFrac = false; | |||
163 | sal_Int32 nDecPos, nFracDivPos; | |||
164 | sal_Int64 nValue; | |||
165 | ||||
166 | // react on empty string | |||
167 | if ( rStr.isEmpty() ) | |||
168 | return false; | |||
169 | ||||
170 | // remove leading and trailing spaces | |||
171 | aStr = aStr.trim(); | |||
172 | ||||
173 | ||||
174 | // find position of decimal point | |||
175 | nDecPos = aStr.indexOf( rLocaleDataWrapper.getNumDecimalSep() ); | |||
176 | if (nDecPos < 0 && !rLocaleDataWrapper.getNumDecimalSepAlt().isEmpty()) | |||
177 | nDecPos = aStr.indexOf( rLocaleDataWrapper.getNumDecimalSepAlt() ); | |||
178 | // find position of fraction | |||
179 | nFracDivPos = aStr.indexOf( '/' ); | |||
180 | ||||
181 | // parse fractional strings | |||
182 | if (nFracDivPos > 0) | |||
183 | { | |||
184 | bFrac = true; | |||
185 | sal_Int32 nFracNumPos = aStr.lastIndexOf(' ', nFracDivPos); | |||
186 | ||||
187 | // If in "a b/c" format. | |||
188 | if(nFracNumPos != -1 ) | |||
189 | { | |||
190 | aStr1.append(std::u16string_view(aStr).substr(0, nFracNumPos)); | |||
191 | aStrNum.append(std::u16string_view(aStr).substr(nFracNumPos+1, nFracDivPos-nFracNumPos-1)); | |||
192 | aStrDenom.append(std::u16string_view(aStr).substr(nFracDivPos+1)); | |||
193 | } | |||
194 | // "a/b" format, or not a fraction at all | |||
195 | else | |||
196 | { | |||
197 | aStrNum.append(std::u16string_view(aStr).substr(0, nFracDivPos)); | |||
198 | aStrDenom.append(std::u16string_view(aStr).substr(nFracDivPos+1)); | |||
199 | } | |||
200 | ||||
201 | } | |||
202 | // parse decimal strings | |||
203 | else if ( nDecPos >= 0) | |||
204 | { | |||
205 | aStr1.append(std::u16string_view(aStr).substr(0, nDecPos)); | |||
206 | aStr2.append(std::u16string_view(aStr).substr(nDecPos+1)); | |||
207 | } | |||
208 | else | |||
209 | aStr1 = aStr; | |||
210 | ||||
211 | // negative? | |||
212 | if ( bCurrency ) | |||
213 | { | |||
214 | if ( aStr.startsWith("(") && aStr.endsWith(")") ) | |||
215 | bNegative = true; | |||
216 | if ( !bNegative ) | |||
217 | { | |||
218 | for (sal_Int32 i=0; i < aStr.getLength(); i++ ) | |||
219 | { | |||
220 | if ( (aStr[i] >= '0') && (aStr[i] <= '9') ) | |||
221 | break; | |||
222 | else if ( aStr[i] == '-' ) | |||
223 | { | |||
224 | bNegative = true; | |||
225 | break; | |||
226 | } | |||
227 | } | |||
228 | } | |||
229 | if (!bNegative && !aStr.isEmpty()) | |||
230 | { | |||
231 | sal_uInt16 nFormat = rLocaleDataWrapper.getCurrNegativeFormat(); | |||
232 | if ( (nFormat == 3) || (nFormat == 6) || // $1- || 1-$ | |||
233 | (nFormat == 7) || (nFormat == 10) ) // 1$- || 1 $- | |||
234 | { | |||
235 | for (sal_Int32 i = aStr.getLength()-1; i > 0; --i ) | |||
236 | { | |||
237 | if ( (aStr[i] >= '0') && (aStr[i] <= '9') ) | |||
238 | break; | |||
239 | else if ( aStr[i] == '-' ) | |||
240 | { | |||
241 | bNegative = true; | |||
242 | break; | |||
243 | } | |||
244 | } | |||
245 | } | |||
246 | } | |||
247 | } | |||
248 | else | |||
249 | { | |||
250 | if ( !aStr1.isEmpty() && aStr1[0] == '-') | |||
251 | bNegative = true; | |||
252 | if ( !aStrNum.isEmpty() && aStrNum[0] == '-') // For non-mixed fractions | |||
253 | bNegative = true; | |||
254 | } | |||
255 | ||||
256 | // remove all unwanted characters | |||
257 | // For whole number | |||
258 | for (sal_Int32 i=0; i < aStr1.getLength(); ) | |||
259 | { | |||
260 | if ( (aStr1[i] >= '0') && (aStr1[i] <= '9') ) | |||
261 | i++; | |||
262 | else | |||
263 | aStr1.remove( i, 1 ); | |||
264 | } | |||
265 | // For decimal | |||
266 | if (!bFrac) { | |||
267 | for (sal_Int32 i=0; i < aStr2.getLength(); ) | |||
268 | { | |||
269 | if ((aStr2[i] >= '0') && (aStr2[i] <= '9')) | |||
270 | ++i; | |||
271 | else | |||
272 | aStr2.remove(i, 1); | |||
273 | } | |||
274 | } | |||
275 | else { | |||
276 | // for numerator | |||
277 | for (sal_Int32 i=0; i < aStrNum.getLength(); ) | |||
278 | { | |||
279 | if ((aStrNum[i] >= '0') && (aStrNum[i] <= '9')) | |||
280 | ++i; | |||
281 | else | |||
282 | aStrNum.remove(i, 1); | |||
283 | } | |||
284 | // for denominator | |||
285 | for (sal_Int32 i=0; i < aStrDenom.getLength(); ) | |||
286 | { | |||
287 | if ((aStrDenom[i] >= '0') && (aStrDenom[i] <= '9')) | |||
288 | ++i; | |||
289 | else | |||
290 | aStrDenom.remove(i, 1); | |||
291 | } | |||
292 | } | |||
293 | ||||
294 | ||||
295 | if ( !bFrac && aStr1.isEmpty() && aStr2.isEmpty() ) | |||
296 | return false; | |||
297 | else if ( bFrac && aStr1.isEmpty() && (aStrNum.isEmpty() || aStrDenom.isEmpty()) ) | |||
298 | return false; | |||
299 | ||||
300 | if ( aStr1.isEmpty() ) | |||
301 | aStr1 = "0"; | |||
302 | if ( bNegative ) | |||
303 | aStr1.insert(0, "-"); | |||
304 | ||||
305 | // Convert fractional strings | |||
306 | if (bFrac) { | |||
307 | // Convert to fraction | |||
308 | sal_Int64 nWholeNum = aStr1.makeStringAndClear().toInt64(); | |||
309 | sal_Int64 nNum = aStrNum.makeStringAndClear().toInt64(); | |||
310 | sal_Int64 nDenom = aStrDenom.makeStringAndClear().toInt64(); | |||
311 | if (nDenom == 0) return false; // Division by zero | |||
312 | double nFrac2Dec = nWholeNum + static_cast<double>(nNum)/nDenom; // Convert to double for floating point precision | |||
313 | OUStringBuffer aStrFrac; | |||
314 | aStrFrac.append(nFrac2Dec); | |||
315 | // Reconvert division result to string and parse | |||
316 | nDecPos = aStrFrac.indexOf('.'); | |||
317 | if ( nDecPos >= 0) | |||
318 | { | |||
319 | aStr1.append(aStrFrac.getStr(), nDecPos); | |||
320 | aStr2.append(aStrFrac.getStr()+nDecPos+1); | |||
321 | } | |||
322 | else | |||
323 | aStr1 = aStrFrac; | |||
324 | } | |||
325 | ||||
326 | // prune and round fraction | |||
327 | bool bRound = false; | |||
328 | if (aStr2.getLength() > nDecDigits) | |||
329 | { | |||
330 | if (aStr2[nDecDigits] >= '5') | |||
331 | bRound = true; | |||
332 | string::truncateToLength(aStr2, nDecDigits); | |||
333 | } | |||
334 | if (aStr2.getLength() < nDecDigits) | |||
335 | string::padToLength(aStr2, nDecDigits, '0'); | |||
336 | ||||
337 | aStr = aStr1.makeStringAndClear() + aStr2.makeStringAndClear(); | |||
338 | ||||
339 | // check range | |||
340 | nValue = aStr.toInt64(); | |||
341 | if( nValue == 0 ) | |||
342 | { | |||
343 | // check if string is equivalent to zero | |||
344 | sal_Int32 nIndex = bNegative ? 1 : 0; | |||
345 | while (nIndex < aStr.getLength() && aStr[nIndex] == '0') | |||
346 | ++nIndex; | |||
347 | if( nIndex < aStr.getLength() ) | |||
348 | { | |||
349 | rValue = bNegative ? SAL_MIN_INT64((sal_Int64) (-0x7FFFFFFFFFFFFFFFl - 1)) : SAL_MAX_INT64((sal_Int64) 0x7FFFFFFFFFFFFFFFl); | |||
350 | return true; | |||
351 | } | |||
352 | } | |||
353 | if (bRound) | |||
354 | { | |||
355 | if ( !bNegative ) | |||
356 | nValue++; | |||
357 | else | |||
358 | nValue--; | |||
359 | } | |||
360 | ||||
361 | rValue = nValue; | |||
362 | ||||
363 | return true; | |||
364 | } | |||
365 | ||||
366 | void ImplUpdateSeparatorString( OUString& io_rText, | |||
367 | const OUString& rOldDecSep, const OUString& rNewDecSep, | |||
368 | const OUString& rOldThSep, const OUString& rNewThSep ) | |||
369 | { | |||
370 | OUStringBuffer aBuf( io_rText.getLength() ); | |||
371 | sal_Int32 nIndexDec = 0, nIndexTh = 0, nIndex = 0; | |||
372 | ||||
373 | const sal_Unicode* pBuffer = io_rText.getStr(); | |||
374 | while( nIndex != -1 ) | |||
375 | { | |||
376 | nIndexDec = io_rText.indexOf( rOldDecSep, nIndex ); | |||
377 | nIndexTh = io_rText.indexOf( rOldThSep, nIndex ); | |||
378 | if( (nIndexTh != -1 && nIndexDec != -1 && nIndexTh < nIndexDec ) | |||
379 | || (nIndexTh != -1 && nIndexDec == -1) | |||
380 | ) | |||
381 | { | |||
382 | aBuf.append( pBuffer + nIndex, nIndexTh - nIndex ); | |||
383 | aBuf.append( rNewThSep ); | |||
384 | nIndex = nIndexTh + rOldThSep.getLength(); | |||
385 | } | |||
386 | else if( nIndexDec != -1 ) | |||
387 | { | |||
388 | aBuf.append( pBuffer + nIndex, nIndexDec - nIndex ); | |||
389 | aBuf.append( rNewDecSep ); | |||
390 | nIndex = nIndexDec + rOldDecSep.getLength(); | |||
391 | } | |||
392 | else | |||
393 | { | |||
394 | aBuf.append( pBuffer + nIndex ); | |||
395 | nIndex = -1; | |||
396 | } | |||
397 | } | |||
398 | ||||
399 | io_rText = aBuf.makeStringAndClear(); | |||
400 | } | |||
401 | ||||
402 | void ImplUpdateSeparators( const OUString& rOldDecSep, const OUString& rNewDecSep, | |||
403 | const OUString& rOldThSep, const OUString& rNewThSep, | |||
404 | Edit* pEdit ) | |||
405 | { | |||
406 | bool bChangeDec = (rOldDecSep != rNewDecSep); | |||
407 | bool bChangeTh = (rOldThSep != rNewThSep ); | |||
408 | ||||
409 | if( !(bChangeDec || bChangeTh) ) | |||
410 | return; | |||
411 | ||||
412 | bool bUpdateMode = pEdit->IsUpdateMode(); | |||
413 | pEdit->SetUpdateMode( false ); | |||
414 | OUString aText = pEdit->GetText(); | |||
415 | ImplUpdateSeparatorString( aText, rOldDecSep, rNewDecSep, rOldThSep, rNewThSep ); | |||
416 | pEdit->SetText( aText ); | |||
417 | ||||
418 | ComboBox* pCombo = dynamic_cast<ComboBox*>(pEdit); | |||
419 | if( pCombo ) | |||
420 | { | |||
421 | // update box entries | |||
422 | sal_Int32 nEntryCount = pCombo->GetEntryCount(); | |||
423 | for ( sal_Int32 i=0; i < nEntryCount; i++ ) | |||
424 | { | |||
425 | aText = pCombo->GetEntry( i ); | |||
426 | void* pEntryData = pCombo->GetEntryData( i ); | |||
427 | ImplUpdateSeparatorString( aText, rOldDecSep, rNewDecSep, rOldThSep, rNewThSep ); | |||
428 | pCombo->RemoveEntryAt(i); | |||
429 | pCombo->InsertEntry( aText, i ); | |||
430 | pCombo->SetEntryData( i, pEntryData ); | |||
431 | } | |||
432 | } | |||
433 | if( bUpdateMode ) | |||
434 | pEdit->SetUpdateMode( bUpdateMode ); | |||
435 | } | |||
436 | ||||
437 | } // namespace | |||
438 | ||||
439 | FormatterBase::FormatterBase(Edit* pField) | |||
440 | { | |||
441 | mpField = pField; | |||
442 | mpLocaleDataWrapper = nullptr; | |||
443 | mbReformat = false; | |||
444 | mbStrictFormat = false; | |||
445 | mbEmptyFieldValue = false; | |||
446 | mbEmptyFieldValueEnabled = false; | |||
447 | } | |||
448 | ||||
449 | FormatterBase::~FormatterBase() | |||
450 | { | |||
451 | } | |||
452 | ||||
453 | LocaleDataWrapper& FormatterBase::ImplGetLocaleDataWrapper() const | |||
454 | { | |||
455 | if ( !mpLocaleDataWrapper ) | |||
456 | { | |||
457 | const_cast<FormatterBase*>(this)->mpLocaleDataWrapper.reset( new LocaleDataWrapper( GetLanguageTag() ) ); | |||
458 | } | |||
459 | return *mpLocaleDataWrapper; | |||
460 | } | |||
461 | ||||
462 | const LocaleDataWrapper& FormatterBase::GetLocaleDataWrapper() const | |||
463 | { | |||
464 | return ImplGetLocaleDataWrapper(); | |||
465 | } | |||
466 | ||||
467 | void FormatterBase::Reformat() | |||
468 | { | |||
469 | } | |||
470 | ||||
471 | void FormatterBase::ReformatAll() | |||
472 | { | |||
473 | Reformat(); | |||
474 | }; | |||
475 | ||||
476 | void FormatterBase::SetStrictFormat( bool bStrict ) | |||
477 | { | |||
478 | if ( bStrict != mbStrictFormat ) | |||
479 | { | |||
480 | mbStrictFormat = bStrict; | |||
481 | if ( mbStrictFormat ) | |||
482 | ReformatAll(); | |||
483 | } | |||
484 | } | |||
485 | ||||
486 | const lang::Locale& FormatterBase::GetLocale() const | |||
487 | { | |||
488 | if ( mpField ) | |||
489 | return mpField->GetSettings().GetLanguageTag().getLocale(); | |||
490 | else | |||
491 | return Application::GetSettings().GetLanguageTag().getLocale(); | |||
492 | } | |||
493 | ||||
494 | const LanguageTag& FormatterBase::GetLanguageTag() const | |||
495 | { | |||
496 | if ( mpField ) | |||
497 | return mpField->GetSettings().GetLanguageTag(); | |||
498 | else | |||
499 | return Application::GetSettings().GetLanguageTag(); | |||
500 | } | |||
501 | ||||
502 | void FormatterBase::ImplSetText( const OUString& rText, Selection const * pNewSelection ) | |||
503 | { | |||
504 | if ( mpField ) | |||
505 | { | |||
506 | if (pNewSelection) | |||
507 | mpField->SetText(rText, *pNewSelection); | |||
508 | else | |||
509 | { | |||
510 | Selection aSel = mpField->GetSelection(); | |||
511 | aSel.Min() = aSel.Max(); | |||
512 | mpField->SetText(rText, aSel); | |||
513 | } | |||
514 | MarkToBeReformatted( false ); | |||
515 | } | |||
516 | } | |||
517 | ||||
518 | void FormatterBase::SetEmptyFieldValue() | |||
519 | { | |||
520 | if ( mpField ) | |||
521 | mpField->SetText( OUString() ); | |||
522 | mbEmptyFieldValue = true; | |||
523 | } | |||
524 | ||||
525 | bool FormatterBase::IsEmptyFieldValue() const | |||
526 | { | |||
527 | return (!mpField || mpField->GetText().isEmpty()); | |||
528 | } | |||
529 | ||||
530 | void NumericFormatter::FormatValue(Selection const * pNewSelection) | |||
531 | { | |||
532 | mbFormatting = true; | |||
533 | ImplSetText(CreateFieldText(mnLastValue), pNewSelection); | |||
534 | mbFormatting = false; | |||
535 | } | |||
536 | ||||
537 | void NumericFormatter::ImplNumericReformat() | |||
538 | { | |||
539 | mnLastValue = GetValue(); | |||
540 | FormatValue(); | |||
541 | } | |||
542 | ||||
543 | NumericFormatter::NumericFormatter(Edit* pEdit) | |||
544 | : FormatterBase(pEdit) | |||
545 | , mnLastValue(0) | |||
546 | , mnMin(0) | |||
547 | // a "large" value substantially smaller than SAL_MAX_INT64, to avoid | |||
548 | // overflow in computations using this "dummy" value | |||
549 | , mnMax(SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF)) | |||
550 | , mbFormatting(false) | |||
551 | , mnSpinSize(1) | |||
552 | // for fields | |||
553 | , mnFirst(mnMin) | |||
554 | , mnLast(mnMax) | |||
555 | , mnDecimalDigits(0) | |||
556 | , mbThousandSep(true) | |||
557 | { | |||
558 | ReformatAll(); | |||
559 | } | |||
560 | ||||
561 | NumericFormatter::~NumericFormatter() | |||
562 | { | |||
563 | } | |||
564 | ||||
565 | void NumericFormatter::SetMin( sal_Int64 nNewMin ) | |||
566 | { | |||
567 | mnMin = nNewMin; | |||
568 | if ( !IsEmptyFieldValue() ) | |||
569 | ReformatAll(); | |||
570 | } | |||
571 | ||||
572 | void NumericFormatter::SetMax( sal_Int64 nNewMax ) | |||
573 | { | |||
574 | mnMax = nNewMax; | |||
575 | if ( !IsEmptyFieldValue() ) | |||
576 | ReformatAll(); | |||
577 | } | |||
578 | ||||
579 | void NumericFormatter::SetUseThousandSep( bool bValue ) | |||
580 | { | |||
581 | mbThousandSep = bValue; | |||
582 | ReformatAll(); | |||
583 | } | |||
584 | ||||
585 | void NumericFormatter::SetDecimalDigits( sal_uInt16 nDigits ) | |||
586 | { | |||
587 | mnDecimalDigits = nDigits; | |||
588 | ReformatAll(); | |||
589 | } | |||
590 | ||||
591 | void NumericFormatter::SetValue( sal_Int64 nNewValue ) | |||
592 | { | |||
593 | SetUserValue( nNewValue ); | |||
594 | SetEmptyFieldValueData( false ); | |||
595 | } | |||
596 | ||||
597 | OUString NumericFormatter::CreateFieldText( sal_Int64 nValue ) const | |||
598 | { | |||
599 | return ImplGetLocaleDataWrapper().getNum( nValue, GetDecimalDigits(), IsUseThousandSep(), /*ShowTrailingZeros*/true ); | |||
600 | } | |||
601 | ||||
602 | void NumericFormatter::ImplSetUserValue( sal_Int64 nNewValue, Selection const * pNewSelection ) | |||
603 | { | |||
604 | nNewValue = ClipAgainstMinMax(nNewValue); | |||
605 | mnLastValue = nNewValue; | |||
606 | ||||
607 | if ( GetField() ) | |||
608 | FormatValue(pNewSelection); | |||
609 | } | |||
610 | ||||
611 | void NumericFormatter::SetUserValue( sal_Int64 nNewValue ) | |||
612 | { | |||
613 | ImplSetUserValue( nNewValue ); | |||
614 | } | |||
615 | ||||
616 | sal_Int64 NumericFormatter::GetValueFromString(const OUString& rStr) const | |||
617 | { | |||
618 | sal_Int64 nTempValue; | |||
619 | ||||
620 | if (ImplNumericGetValue(rStr, nTempValue, | |||
621 | GetDecimalDigits(), ImplGetLocaleDataWrapper())) | |||
622 | { | |||
623 | return ClipAgainstMinMax(nTempValue); | |||
624 | } | |||
625 | else | |||
626 | return mnLastValue; | |||
627 | } | |||
628 | ||||
629 | OUString NumericFormatter::GetValueString() const | |||
630 | { | |||
631 | return Application::GetSettings().GetNeutralLocaleDataWrapper(). | |||
632 | getNum(GetValue(), GetDecimalDigits(), false, false); | |||
633 | } | |||
634 | ||||
635 | // currently used by online | |||
636 | void NumericFormatter::SetValueFromString(const OUString& rStr) | |||
637 | { | |||
638 | sal_Int64 nValue; | |||
639 | ||||
640 | if (ImplNumericGetValue(rStr, nValue, GetDecimalDigits(), | |||
641 | Application::GetSettings().GetNeutralLocaleDataWrapper())) | |||
642 | { | |||
643 | ImplNewFieldValue(nValue); | |||
644 | } | |||
645 | else | |||
646 | { | |||
647 | SAL_WARN("vcl", "fail to convert the value: " << rStr )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "fail to convert the value: " << rStr) == 1 ) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "647" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "fail to convert the value: " << rStr), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "fail to convert the value: " << rStr; ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "647" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "fail to convert the value: " << rStr) == 1 ) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "647" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "fail to convert the value: " << rStr), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "fail to convert the value: " << rStr; ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "647" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
648 | } | |||
649 | } | |||
650 | ||||
651 | sal_Int64 NumericFormatter::GetValue() const | |||
652 | { | |||
653 | if (mbFormatting) //don't parse the entry if we're currently formatting what to put in it | |||
654 | return mnLastValue; | |||
655 | ||||
656 | return GetField() ? GetValueFromString(GetField()->GetText()) : 0; | |||
657 | } | |||
658 | ||||
659 | sal_Int64 NumericFormatter::Normalize( sal_Int64 nValue ) const | |||
660 | { | |||
661 | return (nValue * ImplPower10( GetDecimalDigits() ) ); | |||
662 | } | |||
663 | ||||
664 | sal_Int64 NumericFormatter::Denormalize( sal_Int64 nValue ) const | |||
665 | { | |||
666 | sal_Int64 nFactor = ImplPower10( GetDecimalDigits() ); | |||
667 | ||||
668 | if ((nValue < ( SAL_MIN_INT64((sal_Int64) (-0x7FFFFFFFFFFFFFFFl - 1)) + nFactor )) || | |||
669 | (nValue > ( SAL_MAX_INT64((sal_Int64) 0x7FFFFFFFFFFFFFFFl) - nFactor ))) | |||
670 | { | |||
671 | return ( nValue / nFactor ); | |||
672 | } | |||
673 | ||||
674 | if( nValue
| |||
675 | { | |||
676 | sal_Int64 nHalf = nFactor / 2; | |||
677 | return ((nValue - nHalf) / nFactor ); | |||
| ||||
678 | } | |||
679 | else | |||
680 | { | |||
681 | sal_Int64 nHalf = nFactor / 2; | |||
682 | return ((nValue + nHalf) / nFactor ); | |||
683 | } | |||
684 | } | |||
685 | ||||
686 | void NumericFormatter::Reformat() | |||
687 | { | |||
688 | if ( !GetField() ) | |||
689 | return; | |||
690 | ||||
691 | if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() ) | |||
692 | return; | |||
693 | ||||
694 | ImplNumericReformat(); | |||
695 | } | |||
696 | ||||
697 | void NumericFormatter::FieldUp() | |||
698 | { | |||
699 | sal_Int64 nValue = GetValue(); | |||
700 | sal_Int64 nRemainder = nValue % mnSpinSize; | |||
701 | if (nValue >= 0) | |||
702 | nValue = (nRemainder == 0) ? nValue + mnSpinSize : nValue + mnSpinSize - nRemainder; | |||
703 | else | |||
704 | nValue = (nRemainder == 0) ? nValue + mnSpinSize : nValue - nRemainder; | |||
705 | ||||
706 | nValue = ClipAgainstMinMax(nValue); | |||
707 | ||||
708 | ImplNewFieldValue( nValue ); | |||
709 | } | |||
710 | ||||
711 | void NumericFormatter::FieldDown() | |||
712 | { | |||
713 | sal_Int64 nValue = GetValue(); | |||
714 | sal_Int64 nRemainder = nValue % mnSpinSize; | |||
715 | if (nValue >= 0) | |||
716 | nValue = (nRemainder == 0) ? nValue - mnSpinSize : nValue - nRemainder; | |||
717 | else | |||
718 | nValue = (nRemainder == 0) ? nValue - mnSpinSize : nValue - mnSpinSize - nRemainder; | |||
719 | ||||
720 | nValue = ClipAgainstMinMax(nValue); | |||
721 | ||||
722 | ImplNewFieldValue( nValue ); | |||
723 | } | |||
724 | ||||
725 | void NumericFormatter::FieldFirst() | |||
726 | { | |||
727 | ImplNewFieldValue( mnFirst ); | |||
728 | } | |||
729 | ||||
730 | void NumericFormatter::FieldLast() | |||
731 | { | |||
732 | ImplNewFieldValue( mnLast ); | |||
733 | } | |||
734 | ||||
735 | void NumericFormatter::ImplNewFieldValue( sal_Int64 nNewValue ) | |||
736 | { | |||
737 | if ( !GetField() ) | |||
738 | return; | |||
739 | ||||
740 | // !!! We should check why we do not validate in ImplSetUserValue() if the value was | |||
741 | // changed. This should be done there as well since otherwise the call to Modify would not | |||
742 | // be allowed. Anyway, the paths from ImplNewFieldValue, ImplSetUserValue, and ImplSetText | |||
743 | // should be checked and clearly traced (with comment) in order to find out what happens. | |||
744 | ||||
745 | Selection aSelection = GetField()->GetSelection(); | |||
746 | aSelection.Justify(); | |||
747 | OUString aText = GetField()->GetText(); | |||
748 | // leave it as is if selected until end | |||
749 | if ( static_cast<sal_Int32>(aSelection.Max()) == aText.getLength() ) | |||
750 | { | |||
751 | if ( !aSelection.Len() ) | |||
752 | aSelection.Min() = SELECTION_MAX9223372036854775807L; | |||
753 | aSelection.Max() = SELECTION_MAX9223372036854775807L; | |||
754 | } | |||
755 | ||||
756 | sal_Int64 nOldLastValue = mnLastValue; | |||
757 | ImplSetUserValue( nNewValue, &aSelection ); | |||
758 | mnLastValue = nOldLastValue; | |||
759 | ||||
760 | // Modify during Edit is only set during KeyInput | |||
761 | if ( GetField()->GetText() != aText ) | |||
762 | { | |||
763 | GetField()->SetModifyFlag(); | |||
764 | GetField()->Modify(); | |||
765 | } | |||
766 | } | |||
767 | ||||
768 | sal_Int64 NumericFormatter::ClipAgainstMinMax(sal_Int64 nValue) const | |||
769 | { | |||
770 | if (nValue > mnMax) | |||
771 | nValue = mnMax; | |||
772 | else if (nValue < mnMin) | |||
773 | nValue = mnMin; | |||
774 | return nValue; | |||
775 | } | |||
776 | ||||
777 | namespace | |||
778 | { | |||
779 | Size calcMinimumSize(const Edit &rSpinField, const NumericFormatter &rFormatter) | |||
780 | { | |||
781 | OUStringBuffer aBuf; | |||
782 | sal_Int32 nTextLen; | |||
783 | ||||
784 | nTextLen = OUString(OUString::number(rFormatter.GetMin())).getLength(); | |||
785 | string::padToLength(aBuf, nTextLen, '9'); | |||
786 | Size aMinTextSize = rSpinField.CalcMinimumSizeForText( | |||
787 | rFormatter.CreateFieldText(aBuf.toString().toInt64())); | |||
788 | aBuf.setLength(0); | |||
789 | ||||
790 | nTextLen = OUString(OUString::number(rFormatter.GetMax())).getLength(); | |||
791 | string::padToLength(aBuf, nTextLen, '9'); | |||
792 | Size aMaxTextSize = rSpinField.CalcMinimumSizeForText( | |||
793 | rFormatter.CreateFieldText(aBuf.toString().toInt64())); | |||
794 | aBuf.setLength(0); | |||
795 | ||||
796 | Size aRet(std::max(aMinTextSize.Width(), aMaxTextSize.Width()), | |||
797 | std::max(aMinTextSize.Height(), aMaxTextSize.Height())); | |||
798 | ||||
799 | OUStringBuffer sBuf("999999999"); | |||
800 | sal_uInt16 nDigits = rFormatter.GetDecimalDigits(); | |||
801 | if (nDigits) | |||
802 | { | |||
803 | sBuf.append('.'); | |||
804 | string::padToLength(aBuf, aBuf.getLength() + nDigits, '9'); | |||
805 | } | |||
806 | aMaxTextSize = rSpinField.CalcMinimumSizeForText(sBuf.makeStringAndClear()); | |||
807 | aRet.setWidth( std::min(aRet.Width(), aMaxTextSize.Width()) ); | |||
808 | ||||
809 | return aRet; | |||
810 | } | |||
811 | } | |||
812 | ||||
813 | NumericBox::NumericBox(vcl::Window* pParent, WinBits nWinStyle) | |||
814 | : ComboBox(pParent, nWinStyle) | |||
815 | , NumericFormatter(this) | |||
816 | { | |||
817 | Reformat(); | |||
818 | if ( !(nWinStyle & WB_HIDE ) ) | |||
819 | Show(); | |||
820 | } | |||
821 | ||||
822 | void NumericBox::dispose() | |||
823 | { | |||
824 | ClearField(); | |||
825 | ComboBox::dispose(); | |||
826 | } | |||
827 | ||||
828 | Size NumericBox::CalcMinimumSize() const | |||
829 | { | |||
830 | Size aRet(calcMinimumSize(*this, *this)); | |||
831 | ||||
832 | if (IsDropDownBox()) | |||
833 | { | |||
834 | Size aComboSugg(ComboBox::CalcMinimumSize()); | |||
835 | aRet.setWidth( std::max(aRet.Width(), aComboSugg.Width()) ); | |||
836 | aRet.setHeight( std::max(aRet.Height(), aComboSugg.Height()) ); | |||
837 | } | |||
838 | ||||
839 | return aRet; | |||
840 | } | |||
841 | ||||
842 | bool NumericBox::PreNotify( NotifyEvent& rNEvt ) | |||
843 | { | |||
844 | if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() ) | |||
845 | { | |||
846 | if ( ImplNumericProcessKeyInput( *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) ) | |||
847 | return true; | |||
848 | } | |||
849 | ||||
850 | return ComboBox::PreNotify( rNEvt ); | |||
851 | } | |||
852 | ||||
853 | bool NumericBox::EventNotify( NotifyEvent& rNEvt ) | |||
854 | { | |||
855 | if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS ) | |||
856 | MarkToBeReformatted( false ); | |||
857 | else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS ) | |||
858 | { | |||
859 | if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) ) | |||
860 | Reformat(); | |||
861 | } | |||
862 | ||||
863 | return ComboBox::EventNotify( rNEvt ); | |||
864 | } | |||
865 | ||||
866 | void NumericBox::DataChanged( const DataChangedEvent& rDCEvt ) | |||
867 | { | |||
868 | ComboBox::DataChanged( rDCEvt ); | |||
869 | ||||
870 | if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) ) | |||
871 | { | |||
872 | OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep(); | |||
873 | OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep(); | |||
874 | ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() ); | |||
875 | OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep(); | |||
876 | OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep(); | |||
877 | ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this ); | |||
878 | ReformatAll(); | |||
879 | } | |||
880 | } | |||
881 | ||||
882 | void NumericBox::Modify() | |||
883 | { | |||
884 | MarkToBeReformatted( true ); | |||
885 | ComboBox::Modify(); | |||
886 | } | |||
887 | ||||
888 | void NumericBox::ImplNumericReformat( const OUString& rStr, sal_Int64& rValue, | |||
889 | OUString& rOutStr ) | |||
890 | { | |||
891 | if (ImplNumericGetValue(rStr, rValue, GetDecimalDigits(), ImplGetLocaleDataWrapper())) | |||
892 | { | |||
893 | sal_Int64 nTempVal = ClipAgainstMinMax(rValue); | |||
894 | rOutStr = CreateFieldText( nTempVal ); | |||
895 | } | |||
896 | } | |||
897 | ||||
898 | void NumericBox::ReformatAll() | |||
899 | { | |||
900 | sal_Int64 nValue; | |||
901 | OUString aStr; | |||
902 | SetUpdateMode( false ); | |||
903 | sal_Int32 nEntryCount = GetEntryCount(); | |||
904 | for ( sal_Int32 i=0; i < nEntryCount; i++ ) | |||
905 | { | |||
906 | ImplNumericReformat( GetEntry( i ), nValue, aStr ); | |||
907 | RemoveEntryAt(i); | |||
908 | InsertEntry( aStr, i ); | |||
909 | } | |||
910 | NumericFormatter::Reformat(); | |||
911 | SetUpdateMode( true ); | |||
912 | } | |||
913 | ||||
914 | static bool ImplMetricProcessKeyInput( const KeyEvent& rKEvt, | |||
915 | bool bUseThousandSep, const LocaleDataWrapper& rWrapper ) | |||
916 | { | |||
917 | // no meaningful strict format; therefore allow all characters | |||
918 | return ImplNumericProcessKeyInput( rKEvt, false, bUseThousandSep, rWrapper ); | |||
919 | } | |||
920 | ||||
921 | static OUString ImplMetricGetUnitText(const OUString& rStr) | |||
922 | { | |||
923 | // fetch unit text | |||
924 | OUStringBuffer aStr; | |||
925 | for (sal_Int32 i = rStr.getLength()-1; i >= 0; --i) | |||
926 | { | |||
927 | sal_Unicode c = rStr[i]; | |||
928 | if ( (c == '\'') || (c == '\"') || (c == '%') || (c == 0x2032) || (c == 0x2033) || unicode::isAlpha(c) || unicode::isControl(c) ) | |||
929 | aStr.insert(0, c); | |||
930 | else | |||
931 | { | |||
932 | if (!aStr.isEmpty()) | |||
933 | break; | |||
934 | } | |||
935 | } | |||
936 | return aStr.makeStringAndClear(); | |||
937 | } | |||
938 | ||||
939 | // #104355# support localized measurements | |||
940 | ||||
941 | static OUString ImplMetricToString( FieldUnit rUnit ) | |||
942 | { | |||
943 | // return unit's default string (ie, the first one ) | |||
944 | for (auto const& elem : ImplGetFieldUnits()) | |||
945 | { | |||
946 | if (elem.second == rUnit) | |||
947 | return elem.first; | |||
948 | } | |||
949 | ||||
950 | return OUString(); | |||
951 | } | |||
952 | ||||
953 | namespace vcl | |||
954 | { | |||
955 | FieldUnit StringToMetric(const OUString &rMetricString) | |||
956 | { | |||
957 | // return FieldUnit | |||
958 | OUString aStr = rMetricString.toAsciiLowerCase().replaceAll(" ", ""); | |||
959 | for (auto const& elem : ImplGetCleanedFieldUnits()) | |||
960 | { | |||
961 | if ( elem.first == aStr ) | |||
962 | return elem.second; | |||
963 | } | |||
964 | ||||
965 | return FieldUnit::NONE; | |||
966 | } | |||
967 | } | |||
968 | ||||
969 | static FieldUnit ImplMetricGetUnit(const OUString& rStr) | |||
970 | { | |||
971 | OUString aStr = ImplMetricGetUnitText(rStr); | |||
972 | return vcl::StringToMetric(aStr); | |||
973 | } | |||
974 | ||||
975 | #define K *1000L | |||
976 | #define M *1000000LL | |||
977 | #define X *5280L | |||
978 | ||||
979 | // twip in km = 254 / 14 400 000 000 | |||
980 | // expressions too big for default size 32 bit need LL to avoid overflow | |||
981 | ||||
982 | const sal_Int64 aImplFactor[sal_uInt16(FieldUnit::LINE) + 1] | |||
983 | [sal_uInt16(FieldUnit::LINE) + 1] = | |||
984 | { /* | |||
985 | mm/100 mm cm m km twip point pica inch foot mile char line */ | |||
986 | { 1, 100, 1 K, 100 K, 100 M, 2540, 2540, 2540, 2540,2540*12,2540*12 X , 53340, 396240}, | |||
987 | { 1, 1, 10, 1 K, 1 M, 2540, 2540, 2540, 2540,2540*12,2540*12 X , 5334, 396240}, | |||
988 | { 1, 1, 1, 100, 100 K, 254, 254, 254, 254, 254*12, 254*12 X , 5334, 39624}, | |||
989 | { 1, 1, 1, 1, 1 K, 254, 254, 254, 254, 254*12, 254*12 X , 533400, 39624}, | |||
990 | { 1, 1, 1, 1, 1, 254, 254, 254, 254, 254*12, 254*12 X ,533400 K, 39624}, | |||
991 | { 1440,144 K,144 K,14400 K,14400LL M, 1, 20, 240, 1440,1440*12,1440*12 X , 210, 3120}, | |||
992 | { 72, 7200, 7200, 720 K, 720 M, 1, 1, 12, 72, 72*12, 72*12 X , 210, 156}, | |||
993 | { 6, 600, 600, 60 K, 60 M, 1, 1, 1, 6, 6*12, 6*12 X , 210, 10}, | |||
994 | { 1, 100, 100, 10 K, 10 M, 1, 1, 1, 1, 12, 12 X , 210, 45}, | |||
995 | { 1, 100, 100, 10 K, 10 M, 1, 1, 1, 1, 1, 1 X , 210, 45}, | |||
996 | { 1, 100, 100, 10 K, 10 M, 1, 1, 1, 1, 1, 1 , 210, 45}, | |||
997 | { 144, 1440,14400, 14400, 14400, 1, 20, 240, 1440,1440*12, 1440*12 X, 1, 156 }, | |||
998 | { 720,72000,72000, 7200 K,7200LL M, 20, 10, 13, 11, 11*12, 11*12 X, 105, 1 } | |||
999 | }; | |||
1000 | #undef X | |||
1001 | #undef M | |||
1002 | #undef K | |||
1003 | ||||
1004 | static FieldUnit ImplMap2FieldUnit( MapUnit meUnit, long& nDecDigits ) | |||
1005 | { | |||
1006 | switch( meUnit ) | |||
1007 | { | |||
1008 | case MapUnit::Map100thMM : | |||
1009 | nDecDigits -= 2; | |||
1010 | return FieldUnit::MM; | |||
1011 | case MapUnit::Map10thMM : | |||
1012 | nDecDigits -= 1; | |||
1013 | return FieldUnit::MM; | |||
1014 | case MapUnit::MapMM : | |||
1015 | return FieldUnit::MM; | |||
1016 | case MapUnit::MapCM : | |||
1017 | return FieldUnit::CM; | |||
1018 | case MapUnit::Map1000thInch : | |||
1019 | nDecDigits -= 3; | |||
1020 | return FieldUnit::INCH; | |||
1021 | case MapUnit::Map100thInch : | |||
1022 | nDecDigits -= 2; | |||
1023 | return FieldUnit::INCH; | |||
1024 | case MapUnit::Map10thInch : | |||
1025 | nDecDigits -= 1; | |||
1026 | return FieldUnit::INCH; | |||
1027 | case MapUnit::MapInch : | |||
1028 | return FieldUnit::INCH; | |||
1029 | case MapUnit::MapPoint : | |||
1030 | return FieldUnit::POINT; | |||
1031 | case MapUnit::MapTwip : | |||
1032 | return FieldUnit::TWIP; | |||
1033 | default: | |||
1034 | OSL_FAIL( "default eInUnit" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1034" ": "), "%s", "default eInUnit"); } } while (false ); | |||
1035 | break; | |||
1036 | } | |||
1037 | return FieldUnit::NONE; | |||
1038 | } | |||
1039 | ||||
1040 | static double nonValueDoubleToValueDouble( double nValue ) | |||
1041 | { | |||
1042 | return std::isfinite( nValue ) ? nValue : 0.0; | |||
1043 | } | |||
1044 | ||||
1045 | namespace vcl | |||
1046 | { | |||
1047 | sal_Int64 ConvertValue(sal_Int64 nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits, | |||
1048 | FieldUnit eInUnit, FieldUnit eOutUnit) | |||
1049 | { | |||
1050 | double nDouble = nonValueDoubleToValueDouble(vcl::ConvertDoubleValue( | |||
1051 | static_cast<double>(nValue), mnBaseValue, nDecDigits, eInUnit, eOutUnit)); | |||
1052 | sal_Int64 nLong ; | |||
1053 | ||||
1054 | // caution: precision loss in double cast | |||
1055 | if ( nDouble <= double(SAL_MIN_INT64((sal_Int64) (-0x7FFFFFFFFFFFFFFFl - 1))) ) | |||
1056 | nLong = SAL_MIN_INT64((sal_Int64) (-0x7FFFFFFFFFFFFFFFl - 1)); | |||
1057 | else if ( nDouble >= double(SAL_MAX_INT64((sal_Int64) 0x7FFFFFFFFFFFFFFFl)) ) | |||
1058 | nLong = SAL_MAX_INT64((sal_Int64) 0x7FFFFFFFFFFFFFFFl); | |||
1059 | else | |||
1060 | nLong = static_cast<sal_Int64>( nDouble ); | |||
1061 | ||||
1062 | return nLong; | |||
1063 | } | |||
1064 | } | |||
1065 | ||||
1066 | namespace { | |||
1067 | ||||
1068 | bool checkConversionUnits(MapUnit eInUnit, FieldUnit eOutUnit) | |||
1069 | { | |||
1070 | return eOutUnit != FieldUnit::PERCENT | |||
1071 | && eOutUnit != FieldUnit::CUSTOM | |||
1072 | && eOutUnit != FieldUnit::NONE | |||
1073 | && eInUnit != MapUnit::MapPixel | |||
1074 | && eInUnit != MapUnit::MapSysFont | |||
1075 | && eInUnit != MapUnit::MapAppFont | |||
1076 | && eInUnit != MapUnit::MapRelative; | |||
1077 | } | |||
1078 | ||||
1079 | double convertValue( double nValue, long nDigits, FieldUnit eInUnit, FieldUnit eOutUnit ) | |||
1080 | { | |||
1081 | if ( nDigits < 0 ) | |||
1082 | { | |||
1083 | while ( nDigits ) | |||
1084 | { | |||
1085 | nValue += 5; | |||
1086 | nValue /= 10; | |||
1087 | nDigits++; | |||
1088 | } | |||
1089 | } | |||
1090 | else | |||
1091 | { | |||
1092 | nValue *= ImplPower10(nDigits); | |||
1093 | } | |||
1094 | ||||
1095 | if ( eInUnit != eOutUnit ) | |||
1096 | { | |||
1097 | sal_Int64 nDiv = aImplFactor[sal_uInt16(eInUnit)][sal_uInt16(eOutUnit)]; | |||
1098 | sal_Int64 nMult = aImplFactor[sal_uInt16(eOutUnit)][sal_uInt16(eInUnit)]; | |||
1099 | ||||
1100 | SAL_WARN_IF( nMult <= 0, "vcl", "illegal *" )do { if (true && (nMult <= 0)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "illegal *" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1100" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal *"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal *"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1100" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "illegal *") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1100" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal *"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal *"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1100" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1101 | SAL_WARN_IF( nDiv <= 0, "vcl", "illegal /" )do { if (true && (nDiv <= 0)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "illegal /" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1101" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal /"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal /"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1101" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "illegal /") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1101" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal /"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal /"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1101" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1102 | ||||
1103 | if ( nMult != 1 && nMult > 0) | |||
1104 | nValue *= nMult; | |||
1105 | if ( nDiv != 1 && nDiv > 0 ) | |||
1106 | { | |||
1107 | nValue += (nValue < 0) ? (-nDiv/2) : (nDiv/2); | |||
1108 | nValue /= nDiv; | |||
1109 | } | |||
1110 | } | |||
1111 | return nValue; | |||
1112 | } | |||
1113 | ||||
1114 | } | |||
1115 | ||||
1116 | namespace vcl | |||
1117 | { | |||
1118 | sal_Int64 ConvertValue( sal_Int64 nValue, sal_uInt16 nDigits, | |||
1119 | MapUnit eInUnit, FieldUnit eOutUnit ) | |||
1120 | { | |||
1121 | if ( !checkConversionUnits(eInUnit, eOutUnit) ) | |||
1122 | { | |||
1123 | OSL_FAIL( "invalid parameters" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1123" ": "), "%s", "invalid parameters"); } } while (false ); | |||
1124 | return nValue; | |||
1125 | } | |||
1126 | ||||
1127 | long nDecDigits = nDigits; | |||
1128 | FieldUnit eFieldUnit = ImplMap2FieldUnit( eInUnit, nDecDigits ); | |||
1129 | ||||
1130 | // Avoid sal_Int64 <-> double conversion issues if possible: | |||
1131 | if (eFieldUnit == eOutUnit && nDigits == 0) | |||
1132 | { | |||
1133 | return nValue; | |||
1134 | } | |||
1135 | ||||
1136 | return static_cast<sal_Int64>( | |||
1137 | nonValueDoubleToValueDouble( | |||
1138 | convertValue( nValue, nDecDigits, eFieldUnit, eOutUnit ) ) ); | |||
1139 | } | |||
1140 | ||||
1141 | double ConvertDoubleValue(double nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits, | |||
1142 | FieldUnit eInUnit, FieldUnit eOutUnit) | |||
1143 | { | |||
1144 | if ( eInUnit != eOutUnit ) | |||
1145 | { | |||
1146 | sal_Int64 nMult = 1, nDiv = 1; | |||
1147 | ||||
1148 | if (eInUnit == FieldUnit::PERCENT) | |||
1149 | { | |||
1150 | if ( (mnBaseValue <= 0) || (nValue <= 0) ) | |||
1151 | return nValue; | |||
1152 | nDiv = 100 * ImplPower10(nDecDigits); | |||
1153 | ||||
1154 | nMult = mnBaseValue; | |||
1155 | } | |||
1156 | else if ( eOutUnit == FieldUnit::PERCENT || | |||
1157 | eOutUnit == FieldUnit::CUSTOM || | |||
1158 | eOutUnit == FieldUnit::NONE || | |||
1159 | eOutUnit == FieldUnit::DEGREE || | |||
1160 | eOutUnit == FieldUnit::SECOND || | |||
1161 | eOutUnit == FieldUnit::MILLISECOND || | |||
1162 | eOutUnit == FieldUnit::PIXEL || | |||
1163 | eInUnit == FieldUnit::CUSTOM || | |||
1164 | eInUnit == FieldUnit::NONE || | |||
1165 | eInUnit == FieldUnit::DEGREE || | |||
1166 | eInUnit == FieldUnit::MILLISECOND || | |||
1167 | eInUnit == FieldUnit::PIXEL ) | |||
1168 | return nValue; | |||
1169 | else | |||
1170 | { | |||
1171 | if (eOutUnit == FieldUnit::MM_100TH) | |||
1172 | eOutUnit = FieldUnit::NONE; | |||
1173 | if (eInUnit == FieldUnit::MM_100TH) | |||
1174 | eInUnit = FieldUnit::NONE; | |||
1175 | ||||
1176 | nDiv = aImplFactor[sal_uInt16(eInUnit)][sal_uInt16(eOutUnit)]; | |||
1177 | nMult = aImplFactor[sal_uInt16(eOutUnit)][sal_uInt16(eInUnit)]; | |||
1178 | ||||
1179 | SAL_WARN_IF( nMult <= 0, "vcl", "illegal *" )do { if (true && (nMult <= 0)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "illegal *" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1179" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal *"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal *"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1179" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "illegal *") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1179" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal *"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal *"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1179" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1180 | SAL_WARN_IF( nDiv <= 0, "vcl", "illegal /" )do { if (true && (nDiv <= 0)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "illegal /" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1180" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal /"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal /"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1180" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "illegal /") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1180" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal /"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal /"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1180" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1181 | } | |||
1182 | ||||
1183 | if ( nMult != 1 && nMult > 0 ) | |||
1184 | nValue *= nMult; | |||
1185 | if ( nDiv != 1 && nDiv > 0 ) | |||
1186 | { | |||
1187 | nValue += ( nValue < 0 ) ? (-nDiv/2) : (nDiv/2); | |||
1188 | nValue /= nDiv; | |||
1189 | } | |||
1190 | } | |||
1191 | ||||
1192 | return nValue; | |||
1193 | } | |||
1194 | ||||
1195 | double ConvertDoubleValue(double nValue, sal_uInt16 nDigits, | |||
1196 | MapUnit eInUnit, FieldUnit eOutUnit) | |||
1197 | { | |||
1198 | if ( !checkConversionUnits(eInUnit, eOutUnit) ) | |||
1199 | { | |||
1200 | OSL_FAIL( "invalid parameters" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1200" ": "), "%s", "invalid parameters"); } } while (false ); | |||
1201 | return nValue; | |||
1202 | } | |||
1203 | ||||
1204 | long nDecDigits = nDigits; | |||
1205 | FieldUnit eFieldUnit = ImplMap2FieldUnit( eInUnit, nDecDigits ); | |||
1206 | ||||
1207 | return convertValue(nValue, nDecDigits, eFieldUnit, eOutUnit); | |||
1208 | } | |||
1209 | ||||
1210 | double ConvertDoubleValue(double nValue, sal_uInt16 nDigits, | |||
1211 | FieldUnit eInUnit, MapUnit eOutUnit) | |||
1212 | { | |||
1213 | if ( eInUnit == FieldUnit::PERCENT || | |||
1214 | eInUnit == FieldUnit::CUSTOM || | |||
1215 | eInUnit == FieldUnit::NONE || | |||
1216 | eInUnit == FieldUnit::DEGREE || | |||
1217 | eInUnit == FieldUnit::SECOND || | |||
1218 | eInUnit == FieldUnit::MILLISECOND || | |||
1219 | eInUnit == FieldUnit::PIXEL || | |||
1220 | eOutUnit == MapUnit::MapPixel || | |||
1221 | eOutUnit == MapUnit::MapSysFont || | |||
1222 | eOutUnit == MapUnit::MapAppFont || | |||
1223 | eOutUnit == MapUnit::MapRelative ) | |||
1224 | { | |||
1225 | OSL_FAIL( "invalid parameters" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1225" ": "), "%s", "invalid parameters"); } } while (false ); | |||
1226 | return nValue; | |||
1227 | } | |||
1228 | ||||
1229 | long nDecDigits = nDigits; | |||
1230 | FieldUnit eFieldUnit = ImplMap2FieldUnit( eOutUnit, nDecDigits ); | |||
1231 | ||||
1232 | if ( nDecDigits < 0 ) | |||
1233 | { | |||
1234 | nValue *= ImplPower10(-nDecDigits); | |||
1235 | } | |||
1236 | else | |||
1237 | { | |||
1238 | nValue /= ImplPower10(nDecDigits); | |||
1239 | } | |||
1240 | ||||
1241 | if ( eFieldUnit != eInUnit ) | |||
1242 | { | |||
1243 | sal_Int64 nDiv = aImplFactor[sal_uInt16(eInUnit)][sal_uInt16(eFieldUnit)]; | |||
1244 | sal_Int64 nMult = aImplFactor[sal_uInt16(eFieldUnit)][sal_uInt16(eInUnit)]; | |||
1245 | ||||
1246 | SAL_WARN_IF( nMult <= 0, "vcl", "illegal *" )do { if (true && (nMult <= 0)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "illegal *" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1246" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal *"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal *"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1246" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "illegal *") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1246" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal *"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal *"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1246" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1247 | SAL_WARN_IF( nDiv <= 0, "vcl", "illegal /" )do { if (true && (nDiv <= 0)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "illegal /" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1247" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal /"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal /"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1247" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "illegal /") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1247" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "illegal /"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "illegal /"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" ":" "1247" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1248 | ||||
1249 | if( nMult != 1 && nMult > 0 ) | |||
1250 | nValue *= nMult; | |||
1251 | if( nDiv != 1 && nDiv > 0 ) | |||
1252 | { | |||
1253 | nValue += (nValue < 0) ? (-nDiv/2) : (nDiv/2); | |||
1254 | nValue /= nDiv; | |||
1255 | } | |||
1256 | } | |||
1257 | return nValue; | |||
1258 | } | |||
1259 | } | |||
1260 | ||||
1261 | namespace vcl | |||
1262 | { | |||
1263 | bool TextToValue(const OUString& rStr, double& rValue, sal_Int64 nBaseValue, | |||
1264 | sal_uInt16 nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper, FieldUnit eUnit) | |||
1265 | { | |||
1266 | // Get value | |||
1267 | sal_Int64 nValue; | |||
1268 | if ( !ImplNumericGetValue( rStr, nValue, nDecDigits, rLocaleDataWrapper ) ) | |||
1269 | return false; | |||
1270 | ||||
1271 | // Determine unit | |||
1272 | FieldUnit eEntryUnit = ImplMetricGetUnit( rStr ); | |||
1273 | ||||
1274 | // Recalculate unit | |||
1275 | // caution: conversion to double loses precision | |||
1276 | rValue = vcl::ConvertDoubleValue(static_cast<double>(nValue), nBaseValue, nDecDigits, eEntryUnit, eUnit); | |||
1277 | ||||
1278 | return true; | |||
1279 | } | |||
1280 | } | |||
1281 | ||||
1282 | void MetricFormatter::ImplMetricReformat( const OUString& rStr, double& rValue, OUString& rOutStr ) | |||
1283 | { | |||
1284 | if (!vcl::TextToValue(rStr, rValue, 0, GetDecimalDigits(), ImplGetLocaleDataWrapper(), meUnit)) | |||
1285 | return; | |||
1286 | ||||
1287 | double nTempVal = rValue; | |||
1288 | // caution: precision loss in double cast | |||
1289 | if ( nTempVal > GetMax() ) | |||
1290 | nTempVal = static_cast<double>(GetMax()); | |||
1291 | else if ( nTempVal < GetMin()) | |||
1292 | nTempVal = static_cast<double>(GetMin()); | |||
1293 | rOutStr = CreateFieldText( static_cast<sal_Int64>(nTempVal) ); | |||
1294 | } | |||
1295 | ||||
1296 | MetricFormatter::MetricFormatter(Edit* pEdit) | |||
1297 | : NumericFormatter(pEdit) | |||
1298 | , meUnit(FieldUnit::NONE) | |||
1299 | { | |||
1300 | } | |||
1301 | ||||
1302 | MetricFormatter::~MetricFormatter() | |||
1303 | { | |||
1304 | } | |||
1305 | ||||
1306 | void MetricFormatter::SetUnit( FieldUnit eNewUnit ) | |||
1307 | { | |||
1308 | if (eNewUnit == FieldUnit::MM_100TH) | |||
1309 | { | |||
1310 | SetDecimalDigits( GetDecimalDigits() + 2 ); | |||
1311 | meUnit = FieldUnit::MM; | |||
1312 | } | |||
1313 | else | |||
1314 | meUnit = eNewUnit; | |||
1315 | ReformatAll(); | |||
1316 | } | |||
1317 | ||||
1318 | void MetricFormatter::SetCustomUnitText( const OUString& rStr ) | |||
1319 | { | |||
1320 | maCustomUnitText = rStr; | |||
1321 | ReformatAll(); | |||
1322 | } | |||
1323 | ||||
1324 | void MetricFormatter::SetValue( sal_Int64 nNewValue, FieldUnit eInUnit ) | |||
1325 | { | |||
1326 | SetUserValue( nNewValue, eInUnit ); | |||
1327 | } | |||
1328 | ||||
1329 | OUString MetricFormatter::CreateFieldText( sal_Int64 nValue ) const | |||
1330 | { | |||
1331 | //whether percent is separated from its number is locale | |||
1332 | //specific, pawn it off to icu to decide | |||
1333 | if (meUnit == FieldUnit::PERCENT) | |||
1334 | { | |||
1335 | double dValue = nValue; | |||
1336 | dValue /= ImplPower10(GetDecimalDigits()); | |||
1337 | return unicode::formatPercent(dValue, GetLanguageTag()); | |||
1338 | } | |||
1339 | ||||
1340 | OUString aStr = NumericFormatter::CreateFieldText( nValue ); | |||
1341 | ||||
1342 | if( meUnit == FieldUnit::CUSTOM ) | |||
1343 | aStr += maCustomUnitText; | |||
1344 | else | |||
1345 | { | |||
1346 | OUString aSuffix = ImplMetricToString( meUnit ); | |||
1347 | if (meUnit != FieldUnit::NONE && meUnit != FieldUnit::DEGREE && meUnit != FieldUnit::INCH && meUnit != FieldUnit::FOOT) | |||
1348 | aStr += " "; | |||
1349 | if (meUnit == FieldUnit::INCH) | |||
1350 | { | |||
1351 | OUString sDoublePrime = u"\u2033"; | |||
1352 | if (aSuffix != "\"" && aSuffix != sDoublePrime) | |||
1353 | aStr += " "; | |||
1354 | else | |||
1355 | aSuffix = sDoublePrime; | |||
1356 | } | |||
1357 | else if (meUnit == FieldUnit::FOOT) | |||
1358 | { | |||
1359 | OUString sPrime = u"\u2032"; | |||
1360 | if (aSuffix != "'" && aSuffix != sPrime) | |||
1361 | aStr += " "; | |||
1362 | else | |||
1363 | aSuffix = sPrime; | |||
1364 | } | |||
1365 | ||||
1366 | assert(meUnit != FieldUnit::PERCENT)(static_cast <bool> (meUnit != FieldUnit::PERCENT) ? void (0) : __assert_fail ("meUnit != FieldUnit::PERCENT", "/home/maarten/src/libreoffice/core/vcl/source/control/field.cxx" , 1366, __extension__ __PRETTY_FUNCTION__)); | |||
1367 | aStr += aSuffix; | |||
1368 | } | |||
1369 | return aStr; | |||
1370 | } | |||
1371 | ||||
1372 | void MetricFormatter::SetUserValue( sal_Int64 nNewValue, FieldUnit eInUnit ) | |||
1373 | { | |||
1374 | // convert to previously configured units | |||
1375 | nNewValue = vcl::ConvertValue( nNewValue, 0, GetDecimalDigits(), eInUnit, meUnit ); | |||
1376 | NumericFormatter::SetUserValue( nNewValue ); | |||
1377 | } | |||
1378 | ||||
1379 | sal_Int64 MetricFormatter::GetValueFromStringUnit(const OUString& rStr, FieldUnit eOutUnit) const | |||
1380 | { | |||
1381 | double nTempValue; | |||
1382 | // caution: precision loss in double cast | |||
1383 | if (!vcl::TextToValue(rStr, nTempValue, 0, GetDecimalDigits(), ImplGetLocaleDataWrapper(), meUnit)) | |||
1384 | nTempValue = static_cast<double>(mnLastValue); | |||
1385 | ||||
1386 | // caution: precision loss in double cast | |||
1387 | if (nTempValue > mnMax) | |||
1388 | nTempValue = static_cast<double>(mnMax); | |||
1389 | else if (nTempValue < mnMin) | |||
1390 | nTempValue = static_cast<double>(mnMin); | |||
1391 | ||||
1392 | // convert to requested units | |||
1393 | return vcl::ConvertValue(static_cast<sal_Int64>(nTempValue), 0, GetDecimalDigits(), meUnit, eOutUnit); | |||
1394 | } | |||
1395 | ||||
1396 | sal_Int64 MetricFormatter::GetValueFromString(const OUString& rStr) const | |||
1397 | { | |||
1398 | return GetValueFromStringUnit(rStr, FieldUnit::NONE); | |||
1399 | } | |||
1400 | ||||
1401 | sal_Int64 MetricFormatter::GetValue( FieldUnit eOutUnit ) const | |||
1402 | { | |||
1403 | return GetField() ? GetValueFromStringUnit(GetField()->GetText(), eOutUnit) : 0; | |||
1404 | } | |||
1405 | ||||
1406 | void MetricFormatter::SetValue( sal_Int64 nValue ) | |||
1407 | { | |||
1408 | // Implementation not inline, because it is a virtual Function | |||
1409 | SetValue( nValue, FieldUnit::NONE ); | |||
1410 | } | |||
1411 | ||||
1412 | void MetricFormatter::SetMin( sal_Int64 nNewMin, FieldUnit eInUnit ) | |||
1413 | { | |||
1414 | // convert to requested units | |||
1415 | NumericFormatter::SetMin(vcl::ConvertValue(nNewMin, 0, GetDecimalDigits(), eInUnit, meUnit)); | |||
1416 | } | |||
1417 | ||||
1418 | sal_Int64 MetricFormatter::GetMin( FieldUnit eOutUnit ) const | |||
1419 | { | |||
1420 | // convert to requested units | |||
1421 | return vcl::ConvertValue(NumericFormatter::GetMin(), 0, GetDecimalDigits(), meUnit, eOutUnit); | |||
1422 | } | |||
1423 | ||||
1424 | void MetricFormatter::SetMax( sal_Int64 nNewMax, FieldUnit eInUnit ) | |||
1425 | { | |||
1426 | // convert to requested units | |||
1427 | NumericFormatter::SetMax(vcl::ConvertValue(nNewMax, 0, GetDecimalDigits(), eInUnit, meUnit)); | |||
1428 | } | |||
1429 | ||||
1430 | sal_Int64 MetricFormatter::GetMax( FieldUnit eOutUnit ) const | |||
1431 | { | |||
1432 | // convert to requested units | |||
1433 | return vcl::ConvertValue(NumericFormatter::GetMax(), 0, GetDecimalDigits(), meUnit, eOutUnit); | |||
1434 | } | |||
1435 | ||||
1436 | void MetricFormatter::Reformat() | |||
1437 | { | |||
1438 | if ( !GetField() ) | |||
1439 | return; | |||
1440 | ||||
1441 | OUString aText = GetField()->GetText(); | |||
1442 | ||||
1443 | OUString aStr; | |||
1444 | // caution: precision loss in double cast | |||
1445 | double nTemp = static_cast<double>(mnLastValue); | |||
1446 | ImplMetricReformat( aText, nTemp, aStr ); | |||
1447 | mnLastValue = static_cast<sal_Int64>(nTemp); | |||
1448 | ||||
1449 | if ( !aStr.isEmpty() ) | |||
1450 | { | |||
1451 | ImplSetText( aStr ); | |||
1452 | } | |||
1453 | else | |||
1454 | SetValue( mnLastValue ); | |||
1455 | } | |||
1456 | ||||
1457 | sal_Int64 MetricFormatter::GetCorrectedValue( FieldUnit eOutUnit ) const | |||
1458 | { | |||
1459 | // convert to requested units | |||
1460 | return vcl::ConvertValue(0/*nCorrectedValue*/, 0, GetDecimalDigits(), | |||
1461 | meUnit, eOutUnit); | |||
1462 | } | |||
1463 | ||||
1464 | MetricField::MetricField(vcl::Window* pParent, WinBits nWinStyle) | |||
1465 | : SpinField(pParent, nWinStyle, WindowType::METRICFIELD) | |||
1466 | , MetricFormatter(this) | |||
1467 | { | |||
1468 | Reformat(); | |||
1469 | } | |||
1470 | ||||
1471 | void MetricField::dispose() | |||
1472 | { | |||
1473 | ClearField(); | |||
1474 | SpinField::dispose(); | |||
1475 | } | |||
1476 | ||||
1477 | Size MetricField::CalcMinimumSize() const | |||
1478 | { | |||
1479 | return calcMinimumSize(*this, *this); | |||
1480 | } | |||
1481 | ||||
1482 | bool MetricField::set_property(const OString &rKey, const OUString &rValue) | |||
1483 | { | |||
1484 | if (rKey == "digits") | |||
1485 | SetDecimalDigits(rValue.toInt32()); | |||
1486 | else if (rKey == "spin-size") | |||
1487 | SetSpinSize(rValue.toInt32()); | |||
1488 | else | |||
1489 | return SpinField::set_property(rKey, rValue); | |||
1490 | return true; | |||
1491 | } | |||
1492 | ||||
1493 | void MetricField::SetUnit( FieldUnit nNewUnit ) | |||
1494 | { | |||
1495 | sal_Int64 nRawMax = GetMax( nNewUnit ); | |||
1496 | sal_Int64 nMax = Denormalize( nRawMax ); | |||
| ||||
1497 | sal_Int64 nMin = Denormalize( GetMin( nNewUnit ) ); | |||
1498 | sal_Int64 nFirst = Denormalize( GetFirst( nNewUnit ) ); | |||
1499 | sal_Int64 nLast = Denormalize( GetLast( nNewUnit ) ); | |||
1500 | ||||
1501 | MetricFormatter::SetUnit( nNewUnit ); | |||
1502 | ||||
1503 | SetMax( Normalize( nMax ), nNewUnit ); | |||
1504 | SetMin( Normalize( nMin ), nNewUnit ); | |||
1505 | SetFirst( Normalize( nFirst ), nNewUnit ); | |||
1506 | SetLast( Normalize( nLast ), nNewUnit ); | |||
1507 | } | |||
1508 | ||||
1509 | void MetricField::SetFirst( sal_Int64 nNewFirst, FieldUnit eInUnit ) | |||
1510 | { | |||
1511 | // convert | |||
1512 | nNewFirst = vcl::ConvertValue(nNewFirst, 0, GetDecimalDigits(), eInUnit, meUnit); | |||
1513 | mnFirst = nNewFirst; | |||
1514 | } | |||
1515 | ||||
1516 | sal_Int64 MetricField::GetFirst( FieldUnit eOutUnit ) const | |||
1517 | { | |||
1518 | // convert | |||
1519 | return vcl::ConvertValue(mnFirst, 0, GetDecimalDigits(), meUnit, eOutUnit); | |||
1520 | } | |||
1521 | ||||
1522 | void MetricField::SetLast( sal_Int64 nNewLast, FieldUnit eInUnit ) | |||
1523 | { | |||
1524 | // convert | |||
1525 | nNewLast = vcl::ConvertValue(nNewLast, 0, GetDecimalDigits(), eInUnit, meUnit); | |||
1526 | mnLast = nNewLast; | |||
1527 | } | |||
1528 | ||||
1529 | sal_Int64 MetricField::GetLast( FieldUnit eOutUnit ) const | |||
1530 | { | |||
1531 | // convert | |||
1532 | return vcl::ConvertValue(mnLast, 0, GetDecimalDigits(), meUnit, eOutUnit); | |||
1533 | } | |||
1534 | ||||
1535 | bool MetricField::PreNotify( NotifyEvent& rNEvt ) | |||
1536 | { | |||
1537 | if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() ) | |||
1538 | { | |||
1539 | if ( ImplMetricProcessKeyInput( *rNEvt.GetKeyEvent(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) ) | |||
1540 | return true; | |||
1541 | } | |||
1542 | ||||
1543 | return SpinField::PreNotify( rNEvt ); | |||
1544 | } | |||
1545 | ||||
1546 | bool MetricField::EventNotify( NotifyEvent& rNEvt ) | |||
1547 | { | |||
1548 | if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS ) | |||
1549 | MarkToBeReformatted( false ); | |||
1550 | else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS ) | |||
1551 | { | |||
1552 | if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) ) | |||
1553 | Reformat(); | |||
1554 | } | |||
1555 | ||||
1556 | return SpinField::EventNotify( rNEvt ); | |||
1557 | } | |||
1558 | ||||
1559 | void MetricField::DataChanged( const DataChangedEvent& rDCEvt ) | |||
1560 | { | |||
1561 | SpinField::DataChanged( rDCEvt ); | |||
1562 | ||||
1563 | if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) ) | |||
1564 | { | |||
1565 | OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep(); | |||
1566 | OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep(); | |||
1567 | ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() ); | |||
1568 | OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep(); | |||
1569 | OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep(); | |||
1570 | ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this ); | |||
1571 | ReformatAll(); | |||
1572 | } | |||
1573 | } | |||
1574 | ||||
1575 | void MetricField::Modify() | |||
1576 | { | |||
1577 | MarkToBeReformatted( true ); | |||
1578 | SpinField::Modify(); | |||
1579 | } | |||
1580 | ||||
1581 | void MetricField::Up() | |||
1582 | { | |||
1583 | FieldUp(); | |||
1584 | SpinField::Up(); | |||
1585 | } | |||
1586 | ||||
1587 | void MetricField::Down() | |||
1588 | { | |||
1589 | FieldDown(); | |||
1590 | SpinField::Down(); | |||
1591 | } | |||
1592 | ||||
1593 | void MetricField::First() | |||
1594 | { | |||
1595 | FieldFirst(); | |||
1596 | SpinField::First(); | |||
1597 | } | |||
1598 | ||||
1599 | void MetricField::Last() | |||
1600 | { | |||
1601 | FieldLast(); | |||
1602 | SpinField::Last(); | |||
1603 | } | |||
1604 | ||||
1605 | void MetricField::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) | |||
1606 | { | |||
1607 | SpinField::DumpAsPropertyTree(rJsonWriter); | |||
1608 | rJsonWriter.put("min", GetMin()); | |||
1609 | rJsonWriter.put("max", GetMax()); | |||
1610 | rJsonWriter.put("unit", FieldUnitToString(GetUnit())); | |||
1611 | OUString sValue = Application::GetSettings().GetNeutralLocaleDataWrapper(). | |||
1612 | getNum(GetValue(), GetDecimalDigits(), false, false); | |||
1613 | rJsonWriter.put("value", sValue); | |||
1614 | } | |||
1615 | ||||
1616 | FactoryFunction MetricField::GetUITestFactory() const | |||
1617 | { | |||
1618 | return MetricFieldUIObject::create; | |||
1619 | } | |||
1620 | ||||
1621 | MetricBox::MetricBox(vcl::Window* pParent, WinBits nWinStyle) | |||
1622 | : ComboBox(pParent, nWinStyle) | |||
1623 | , MetricFormatter(this) | |||
1624 | { | |||
1625 | Reformat(); | |||
1626 | } | |||
1627 | ||||
1628 | void MetricBox::dispose() | |||
1629 | { | |||
1630 | ClearField(); | |||
1631 | ComboBox::dispose(); | |||
1632 | } | |||
1633 | ||||
1634 | Size MetricBox::CalcMinimumSize() const | |||
1635 | { | |||
1636 | Size aRet(calcMinimumSize(*this, *this)); | |||
1637 | ||||
1638 | if (IsDropDownBox()) | |||
1639 | { | |||
1640 | Size aComboSugg(ComboBox::CalcMinimumSize()); | |||
1641 | aRet.setWidth( std::max(aRet.Width(), aComboSugg.Width()) ); | |||
1642 | aRet.setHeight( std::max(aRet.Height(), aComboSugg.Height()) ); | |||
1643 | } | |||
1644 | ||||
1645 | return aRet; | |||
1646 | } | |||
1647 | ||||
1648 | bool MetricBox::PreNotify( NotifyEvent& rNEvt ) | |||
1649 | { | |||
1650 | if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() ) | |||
1651 | { | |||
1652 | if ( ImplMetricProcessKeyInput( *rNEvt.GetKeyEvent(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) ) | |||
1653 | return true; | |||
1654 | } | |||
1655 | ||||
1656 | return ComboBox::PreNotify( rNEvt ); | |||
1657 | } | |||
1658 | ||||
1659 | bool MetricBox::EventNotify( NotifyEvent& rNEvt ) | |||
1660 | { | |||
1661 | if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS ) | |||
1662 | MarkToBeReformatted( false ); | |||
1663 | else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS ) | |||
1664 | { | |||
1665 | if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) ) | |||
1666 | Reformat(); | |||
1667 | } | |||
1668 | ||||
1669 | return ComboBox::EventNotify( rNEvt ); | |||
1670 | } | |||
1671 | ||||
1672 | void MetricBox::DataChanged( const DataChangedEvent& rDCEvt ) | |||
1673 | { | |||
1674 | ComboBox::DataChanged( rDCEvt ); | |||
1675 | ||||
1676 | if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) ) | |||
1677 | { | |||
1678 | OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep(); | |||
1679 | OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep(); | |||
1680 | ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() ); | |||
1681 | OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep(); | |||
1682 | OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep(); | |||
1683 | ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this ); | |||
1684 | ReformatAll(); | |||
1685 | } | |||
1686 | } | |||
1687 | ||||
1688 | void MetricBox::Modify() | |||
1689 | { | |||
1690 | MarkToBeReformatted( true ); | |||
1691 | ComboBox::Modify(); | |||
1692 | } | |||
1693 | ||||
1694 | void MetricBox::ReformatAll() | |||
1695 | { | |||
1696 | double nValue; | |||
1697 | OUString aStr; | |||
1698 | SetUpdateMode( false ); | |||
1699 | sal_Int32 nEntryCount = GetEntryCount(); | |||
1700 | for ( sal_Int32 i=0; i < nEntryCount; i++ ) | |||
1701 | { | |||
1702 | ImplMetricReformat( GetEntry( i ), nValue, aStr ); | |||
1703 | RemoveEntryAt(i); | |||
1704 | InsertEntry( aStr, i ); | |||
1705 | } | |||
1706 | MetricFormatter::Reformat(); | |||
1707 | SetUpdateMode( true ); | |||
1708 | } | |||
1709 | ||||
1710 | static bool ImplCurrencyProcessKeyInput( const KeyEvent& rKEvt, | |||
1711 | bool bUseThousandSep, const LocaleDataWrapper& rWrapper ) | |||
1712 | { | |||
1713 | // no strict format set; therefore allow all characters | |||
1714 | return ImplNumericProcessKeyInput( rKEvt, false, bUseThousandSep, rWrapper ); | |||
1715 | } | |||
1716 | ||||
1717 | static bool ImplCurrencyGetValue( const OUString& rStr, sal_Int64& rValue, | |||
1718 | sal_uInt16 nDecDigits, const LocaleDataWrapper& rWrapper ) | |||
1719 | { | |||
1720 | // fetch number | |||
1721 | return ImplNumericGetValue( rStr, rValue, nDecDigits, rWrapper, true ); | |||
1722 | } | |||
1723 | ||||
1724 | void CurrencyFormatter::ImplCurrencyReformat( const OUString& rStr, OUString& rOutStr ) | |||
1725 | { | |||
1726 | sal_Int64 nValue; | |||
1727 | if ( !ImplNumericGetValue( rStr, nValue, GetDecimalDigits(), ImplGetLocaleDataWrapper(), true ) ) | |||
1728 | return; | |||
1729 | ||||
1730 | sal_Int64 nTempVal = nValue; | |||
1731 | if ( nTempVal > GetMax() ) | |||
1732 | nTempVal = GetMax(); | |||
1733 | else if ( nTempVal < GetMin()) | |||
1734 | nTempVal = GetMin(); | |||
1735 | rOutStr = CreateFieldText( nTempVal ); | |||
1736 | } | |||
1737 | ||||
1738 | CurrencyFormatter::CurrencyFormatter(Edit* pField) | |||
1739 | : NumericFormatter(pField) | |||
1740 | { | |||
1741 | } | |||
1742 | ||||
1743 | CurrencyFormatter::~CurrencyFormatter() | |||
1744 | { | |||
1745 | } | |||
1746 | ||||
1747 | void CurrencyFormatter::SetValue( sal_Int64 nNewValue ) | |||
1748 | { | |||
1749 | SetUserValue( nNewValue ); | |||
1750 | SetEmptyFieldValueData( false ); | |||
1751 | } | |||
1752 | ||||
1753 | OUString CurrencyFormatter::CreateFieldText( sal_Int64 nValue ) const | |||
1754 | { | |||
1755 | return ImplGetLocaleDataWrapper().getCurr( nValue, GetDecimalDigits(), | |||
1756 | ImplGetLocaleDataWrapper().getCurrSymbol(), | |||
1757 | IsUseThousandSep() ); | |||
1758 | } | |||
1759 | ||||
1760 | sal_Int64 CurrencyFormatter::GetValueFromString(const OUString& rStr) const | |||
1761 | { | |||
1762 | sal_Int64 nTempValue; | |||
1763 | if ( ImplCurrencyGetValue( rStr, nTempValue, GetDecimalDigits(), ImplGetLocaleDataWrapper() ) ) | |||
1764 | { | |||
1765 | return ClipAgainstMinMax(nTempValue); | |||
1766 | } | |||
1767 | else | |||
1768 | return mnLastValue; | |||
1769 | } | |||
1770 | ||||
1771 | void CurrencyFormatter::Reformat() | |||
1772 | { | |||
1773 | if ( !GetField() ) | |||
1774 | return; | |||
1775 | ||||
1776 | OUString aStr; | |||
1777 | ImplCurrencyReformat( GetField()->GetText(), aStr ); | |||
1778 | ||||
1779 | if ( !aStr.isEmpty() ) | |||
1780 | { | |||
1781 | ImplSetText( aStr ); | |||
1782 | sal_Int64 nTemp = mnLastValue; | |||
1783 | ImplCurrencyGetValue( aStr, nTemp, GetDecimalDigits(), ImplGetLocaleDataWrapper() ); | |||
1784 | mnLastValue = nTemp; | |||
1785 | } | |||
1786 | else | |||
1787 | SetValue( mnLastValue ); | |||
1788 | } | |||
1789 | ||||
1790 | CurrencyField::CurrencyField(vcl::Window* pParent, WinBits nWinStyle) | |||
1791 | : SpinField(pParent, nWinStyle) | |||
1792 | , CurrencyFormatter(this) | |||
1793 | { | |||
1794 | Reformat(); | |||
1795 | } | |||
1796 | ||||
1797 | void CurrencyField::dispose() | |||
1798 | { | |||
1799 | ClearField(); | |||
1800 | SpinField::dispose(); | |||
1801 | } | |||
1802 | ||||
1803 | bool CurrencyField::PreNotify( NotifyEvent& rNEvt ) | |||
1804 | { | |||
1805 | if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() ) | |||
1806 | { | |||
1807 | if ( ImplCurrencyProcessKeyInput( *rNEvt.GetKeyEvent(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) ) | |||
1808 | return true; | |||
1809 | } | |||
1810 | ||||
1811 | return SpinField::PreNotify( rNEvt ); | |||
1812 | } | |||
1813 | ||||
1814 | bool CurrencyField::EventNotify( NotifyEvent& rNEvt ) | |||
1815 | { | |||
1816 | if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS ) | |||
1817 | MarkToBeReformatted( false ); | |||
1818 | else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS ) | |||
1819 | { | |||
1820 | if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) ) | |||
1821 | Reformat(); | |||
1822 | } | |||
1823 | ||||
1824 | return SpinField::EventNotify( rNEvt ); | |||
1825 | } | |||
1826 | ||||
1827 | void CurrencyField::DataChanged( const DataChangedEvent& rDCEvt ) | |||
1828 | { | |||
1829 | SpinField::DataChanged( rDCEvt ); | |||
1830 | ||||
1831 | if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) ) | |||
1832 | { | |||
1833 | OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep(); | |||
1834 | OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep(); | |||
1835 | ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() ); | |||
1836 | OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep(); | |||
1837 | OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep(); | |||
1838 | ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this ); | |||
1839 | ReformatAll(); | |||
1840 | } | |||
1841 | } | |||
1842 | ||||
1843 | void CurrencyField::Modify() | |||
1844 | { | |||
1845 | MarkToBeReformatted( true ); | |||
1846 | SpinField::Modify(); | |||
1847 | } | |||
1848 | ||||
1849 | void CurrencyField::Up() | |||
1850 | { | |||
1851 | FieldUp(); | |||
1852 | SpinField::Up(); | |||
1853 | } | |||
1854 | ||||
1855 | void CurrencyField::Down() | |||
1856 | { | |||
1857 | FieldDown(); | |||
1858 | SpinField::Down(); | |||
1859 | } | |||
1860 | ||||
1861 | void CurrencyField::First() | |||
1862 | { | |||
1863 | FieldFirst(); | |||
1864 | SpinField::First(); | |||
1865 | } | |||
1866 | ||||
1867 | void CurrencyField::Last() | |||
1868 | { | |||
1869 | FieldLast(); | |||
1870 | SpinField::Last(); | |||
1871 | } | |||
1872 | ||||
1873 | CurrencyBox::CurrencyBox(vcl::Window* pParent, WinBits nWinStyle) | |||
1874 | : ComboBox(pParent, nWinStyle) | |||
1875 | , CurrencyFormatter(this) | |||
1876 | { | |||
1877 | Reformat(); | |||
1878 | } | |||
1879 | ||||
1880 | void CurrencyBox::dispose() | |||
1881 | { | |||
1882 | ClearField(); | |||
1883 | ComboBox::dispose(); | |||
1884 | } | |||
1885 | ||||
1886 | bool CurrencyBox::PreNotify( NotifyEvent& rNEvt ) | |||
1887 | { | |||
1888 | if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() ) | |||
1889 | { | |||
1890 | if ( ImplCurrencyProcessKeyInput( *rNEvt.GetKeyEvent(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) ) | |||
1891 | return true; | |||
1892 | } | |||
1893 | ||||
1894 | return ComboBox::PreNotify( rNEvt ); | |||
1895 | } | |||
1896 | ||||
1897 | bool CurrencyBox::EventNotify( NotifyEvent& rNEvt ) | |||
1898 | { | |||
1899 | if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS ) | |||
1900 | MarkToBeReformatted( false ); | |||
1901 | else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS ) | |||
1902 | { | |||
1903 | if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) ) | |||
1904 | Reformat(); | |||
1905 | } | |||
1906 | ||||
1907 | return ComboBox::EventNotify( rNEvt ); | |||
1908 | } | |||
1909 | ||||
1910 | void CurrencyBox::DataChanged( const DataChangedEvent& rDCEvt ) | |||
1911 | { | |||
1912 | ComboBox::DataChanged( rDCEvt ); | |||
1913 | ||||
1914 | if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) ) | |||
1915 | { | |||
1916 | OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep(); | |||
1917 | OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep(); | |||
1918 | ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() ); | |||
1919 | OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep(); | |||
1920 | OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep(); | |||
1921 | ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this ); | |||
1922 | ReformatAll(); | |||
1923 | } | |||
1924 | } | |||
1925 | ||||
1926 | void CurrencyBox::Modify() | |||
1927 | { | |||
1928 | MarkToBeReformatted( true ); | |||
1929 | ComboBox::Modify(); | |||
1930 | } | |||
1931 | ||||
1932 | void CurrencyBox::ReformatAll() | |||
1933 | { | |||
1934 | OUString aStr; | |||
1935 | SetUpdateMode( false ); | |||
1936 | sal_Int32 nEntryCount = GetEntryCount(); | |||
1937 | for ( sal_Int32 i=0; i < nEntryCount; i++ ) | |||
1938 | { | |||
1939 | ImplCurrencyReformat( GetEntry( i ), aStr ); | |||
1940 | RemoveEntryAt(i); | |||
1941 | InsertEntry( aStr, i ); | |||
1942 | } | |||
1943 | CurrencyFormatter::Reformat(); | |||
1944 | SetUpdateMode( true ); | |||
1945 | } | |||
1946 | ||||
1947 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |