Line data Source code
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 <algorithm>
23 :
24 : #include <tools/diagnose_ex.h>
25 : #include <comphelper/processfactory.hxx>
26 : #include <comphelper/string.hxx>
27 : #include <tools/rc.h>
28 : #include <vcl/svapp.hxx>
29 : #include <vcl/event.hxx>
30 : #include <vcl/field.hxx>
31 : #include <vcl/unohelp.hxx>
32 : #include <vcl/settings.hxx>
33 :
34 : #include <svdata.hxx>
35 :
36 : #include <i18nlangtag/mslangid.hxx>
37 :
38 : #include <com/sun/star/lang/Locale.hpp>
39 : #include <com/sun/star/i18n/XCharacterClassification.hpp>
40 : #include <com/sun/star/i18n/KCharacterType.hpp>
41 :
42 : #include <unotools/localedatawrapper.hxx>
43 : #include <unotools/calendarwrapper.hxx>
44 : #include <unotools/charclass.hxx>
45 : #include <unotools/misccfg.hxx>
46 :
47 : using namespace ::com::sun::star;
48 : using namespace ::comphelper;
49 :
50 : #define EDITMASK_LITERAL 'L'
51 : #define EDITMASK_ALPHA 'a'
52 : #define EDITMASK_UPPERALPHA 'A'
53 : #define EDITMASK_ALPHANUM 'c'
54 : #define EDITMASK_UPPERALPHANUM 'C'
55 : #define EDITMASK_NUM 'N'
56 : #define EDITMASK_NUMSPACE 'n'
57 : #define EDITMASK_ALLCHAR 'x'
58 : #define EDITMASK_UPPERALLCHAR 'X'
59 :
60 71 : uno::Reference< i18n::XCharacterClassification > ImplGetCharClass()
61 : {
62 71 : static uno::Reference< i18n::XCharacterClassification > xCharClass;
63 71 : if ( !xCharClass.is() )
64 2 : xCharClass = vcl::unohelper::CreateCharacterClassification();
65 :
66 71 : return xCharClass;
67 : }
68 :
69 328 : static sal_Unicode* ImplAddString( sal_Unicode* pBuf, const OUString& rStr )
70 : {
71 328 : if ( rStr.getLength() == 1 )
72 328 : *pBuf++ = rStr[0];
73 0 : else if ( rStr.isEmpty() )
74 : ;
75 : else
76 : {
77 0 : memcpy( pBuf, rStr.getStr(), rStr.getLength() * sizeof(sal_Unicode) );
78 0 : pBuf += rStr.getLength();
79 : }
80 328 : return pBuf;
81 : }
82 :
83 492 : static sal_Unicode* ImplAddNum( sal_Unicode* pBuf, sal_uLong nNumber, int nMinLen )
84 : {
85 : // fill temp buffer with digits
86 : sal_Unicode aTempBuf[30];
87 492 : sal_Unicode* pTempBuf = aTempBuf;
88 807 : do
89 : {
90 807 : *pTempBuf = (sal_Unicode)(nNumber % 10) + '0';
91 807 : pTempBuf++;
92 807 : nNumber /= 10;
93 807 : if ( nMinLen )
94 807 : nMinLen--;
95 : }
96 : while ( nNumber );
97 :
98 : // fill with zeros up to the minimal length
99 1349 : while ( nMinLen > 0 )
100 : {
101 365 : *pBuf = '0';
102 365 : pBuf++;
103 365 : nMinLen--;
104 : }
105 :
106 : // copy temp buffer to real buffer
107 807 : do
108 : {
109 807 : pTempBuf--;
110 807 : *pBuf = *pTempBuf;
111 807 : pBuf++;
112 : }
113 : while ( pTempBuf != aTempBuf );
114 :
115 492 : return pBuf;
116 : }
117 :
118 933 : static sal_uInt16 ImplGetNum( const sal_Unicode*& rpBuf, bool& rbError )
119 : {
120 933 : if ( !*rpBuf )
121 : {
122 0 : rbError = true;
123 0 : return 0;
124 : }
125 :
126 933 : sal_uInt16 nNumber = 0;
127 4102 : while( ( *rpBuf >= '0' ) && ( *rpBuf <= '9' ) )
128 : {
129 2236 : nNumber *= 10;
130 2236 : nNumber += *rpBuf - '0';
131 2236 : rpBuf++;
132 : }
133 :
134 933 : return nNumber;
135 : }
136 :
137 933 : static void ImplSkipDelimiters( const sal_Unicode*& rpBuf )
138 : {
139 4043 : while( ( *rpBuf == ',' ) || ( *rpBuf == '.' ) || ( *rpBuf == ';' ) ||
140 3110 : ( *rpBuf == ':' ) || ( *rpBuf == '-' ) || ( *rpBuf == '/' ) )
141 : {
142 622 : rpBuf++;
143 : }
144 933 : }
145 :
146 71 : static bool ImplIsPatternChar( sal_Unicode cChar, sal_Char cEditMask )
147 : {
148 71 : sal_Int32 nType = 0;
149 :
150 : try
151 : {
152 71 : OUString aCharStr(cChar);
153 142 : nType = ImplGetCharClass()->getStringType( aCharStr, 0, aCharStr.getLength(),
154 142 : Application::GetSettings().GetLanguageTag().getLocale() );
155 : }
156 0 : catch (const ::com::sun::star::uno::Exception&)
157 : {
158 : SAL_WARN( "vcl.control", "ImplIsPatternChar: Exception caught!" );
159 : DBG_UNHANDLED_EXCEPTION();
160 0 : return false;
161 : }
162 :
163 71 : if ( (cEditMask == EDITMASK_ALPHA) || (cEditMask == EDITMASK_UPPERALPHA) )
164 : {
165 0 : if( !CharClass::isLetterType( nType ) )
166 0 : return false;
167 : }
168 71 : else if ( cEditMask == EDITMASK_NUM )
169 : {
170 41 : if( !CharClass::isNumericType( nType ) )
171 41 : return false;
172 : }
173 30 : else if ( (cEditMask == EDITMASK_ALPHANUM) || (cEditMask == EDITMASK_UPPERALPHANUM) )
174 : {
175 48 : if( !CharClass::isLetterNumericType( nType ) )
176 0 : return false;
177 : }
178 6 : else if ( (cEditMask == EDITMASK_ALLCHAR) || (cEditMask == EDITMASK_UPPERALLCHAR) )
179 : {
180 0 : if ( cChar < 32 )
181 0 : return false;
182 : }
183 6 : else if ( cEditMask == EDITMASK_NUMSPACE )
184 : {
185 0 : if ( !CharClass::isNumericType( nType ) && ( cChar != ' ' ) )
186 0 : return false;
187 : }
188 : else
189 6 : return false;
190 :
191 24 : return true;
192 : }
193 :
194 71 : static sal_Unicode ImplPatternChar( sal_Unicode cChar, sal_Char cEditMask )
195 : {
196 71 : if ( ImplIsPatternChar( cChar, cEditMask ) )
197 : {
198 24 : if ( (cEditMask == EDITMASK_UPPERALPHA) ||
199 24 : (cEditMask == EDITMASK_UPPERALPHANUM) ||
200 : ( cEditMask == EDITMASK_UPPERALLCHAR ) )
201 : {
202 0 : cChar = ImplGetCharClass()->toUpper(OUString(cChar), 0, 1,
203 0 : Application::GetSettings().GetLanguageTag().getLocale())[0];
204 : }
205 24 : return cChar;
206 : }
207 : else
208 47 : return 0;
209 : }
210 :
211 0 : static bool ImplCommaPointCharEqual( sal_Unicode c1, sal_Unicode c2 )
212 : {
213 0 : if ( c1 == c2 )
214 0 : return true;
215 0 : else if ( ((c1 == '.') || (c1 == ',')) &&
216 0 : ((c2 == '.') || (c2 == ',')) )
217 0 : return true;
218 : else
219 0 : return false;
220 : }
221 :
222 96 : static OUString ImplPatternReformat( const OUString& rStr,
223 : const OString& rEditMask,
224 : const OUString& rLiteralMask,
225 : sal_uInt16 nFormatFlags )
226 : {
227 96 : if (rEditMask.isEmpty())
228 53 : return rStr;
229 :
230 43 : OUString aStr = rStr;
231 86 : OUStringBuffer aOutStr = OUString(rLiteralMask);
232 : sal_Unicode cTempChar;
233 : sal_Unicode cChar;
234 : sal_Unicode cLiteral;
235 : sal_Char cMask;
236 43 : sal_Int32 nStrIndex = 0;
237 43 : sal_Int32 i = 0;
238 : sal_Int32 n;
239 :
240 157 : while ( i < rEditMask.getLength() )
241 : {
242 103 : if ( nStrIndex >= aStr.getLength() )
243 32 : break;
244 :
245 71 : cChar = aStr[nStrIndex];
246 71 : cLiteral = rLiteralMask[i];
247 71 : cMask = rEditMask[i];
248 :
249 : // current position is a literal
250 71 : if ( cMask == EDITMASK_LITERAL )
251 : {
252 : // if it is a literal copy otherwise ignore because it might be the next valid
253 : // character of the string
254 0 : if ( ImplCommaPointCharEqual( cChar, cLiteral ) )
255 0 : nStrIndex++;
256 : else
257 : {
258 : // Otherwise we check if it is a invalid character. This is the case if it does not
259 : // fit in the pattern of the next non-literal character.
260 0 : n = i+1;
261 0 : while ( n < rEditMask.getLength() )
262 : {
263 0 : if ( rEditMask[n] != EDITMASK_LITERAL )
264 : {
265 0 : if ( !ImplIsPatternChar( cChar, rEditMask[n] ) )
266 0 : nStrIndex++;
267 0 : break;
268 : }
269 :
270 0 : n++;
271 : }
272 : }
273 : }
274 : else
275 : {
276 : // valid character at this position
277 71 : cTempChar = ImplPatternChar( cChar, cMask );
278 71 : if ( cTempChar )
279 : {
280 : // use this character
281 24 : aOutStr[i] = cTempChar;
282 24 : nStrIndex++;
283 : }
284 : else
285 : {
286 : // copy if it is a literal character
287 47 : if ( cLiteral == cChar )
288 38 : nStrIndex++;
289 : else
290 : {
291 : // If the invalid character might be the next literal character then we jump
292 : // ahead to it, otherwise we ignore it. Do only if empty literals are allowed.
293 9 : if ( nFormatFlags & PATTERN_FORMAT_EMPTYLITERALS )
294 : {
295 0 : n = i;
296 0 : while ( n < rEditMask.getLength() )
297 : {
298 0 : if ( rEditMask[n] == EDITMASK_LITERAL )
299 : {
300 0 : if ( ImplCommaPointCharEqual( cChar, rLiteralMask[n] ) )
301 0 : i = n+1;
302 :
303 0 : break;
304 : }
305 :
306 0 : n++;
307 : }
308 : }
309 :
310 9 : nStrIndex++;
311 9 : continue;
312 : }
313 : }
314 : }
315 :
316 62 : i++;
317 : }
318 :
319 86 : return aOutStr.makeStringAndClear();
320 : }
321 :
322 0 : static void ImplPatternMaxPos( const OUString& rStr, const OString& rEditMask,
323 : sal_uInt16 nFormatFlags, bool bSameMask,
324 : sal_Int32 nCursorPos, sal_Int32& rPos )
325 : {
326 :
327 : // last position must not be longer than the contained string
328 0 : sal_Int32 nMaxPos = rStr.getLength();
329 :
330 : // if non empty literals are allowed ignore blanks at the end as well
331 0 : if ( bSameMask && !(nFormatFlags & PATTERN_FORMAT_EMPTYLITERALS) )
332 : {
333 0 : while ( nMaxPos )
334 : {
335 0 : if ( (rEditMask[nMaxPos-1] != EDITMASK_LITERAL) &&
336 0 : (rStr[nMaxPos-1] != ' ') )
337 0 : break;
338 0 : nMaxPos--;
339 : }
340 :
341 : // if we are in front of a literal, continue search until first character after the literal
342 0 : sal_Int32 nTempPos = nMaxPos;
343 0 : while ( nTempPos < rEditMask.getLength() )
344 : {
345 0 : if ( rEditMask[nTempPos] != EDITMASK_LITERAL )
346 : {
347 0 : nMaxPos = nTempPos;
348 0 : break;
349 : }
350 0 : nTempPos++;
351 : }
352 : }
353 :
354 0 : if ( rPos > nMaxPos )
355 0 : rPos = nMaxPos;
356 :
357 : // character should not move left
358 0 : if ( rPos < nCursorPos )
359 0 : rPos = nCursorPos;
360 0 : }
361 :
362 0 : static void ImplPatternProcessStrictModify( Edit* pEdit,
363 : const OString& rEditMask,
364 : const OUString& rLiteralMask,
365 : sal_uInt16 nFormatFlags, bool bSameMask )
366 : {
367 0 : OUString aText = pEdit->GetText();
368 :
369 : // remove leading blanks
370 0 : if ( bSameMask && !(nFormatFlags & PATTERN_FORMAT_EMPTYLITERALS) )
371 : {
372 0 : sal_Int32 i = 0;
373 0 : sal_Int32 nMaxLen = aText.getLength();
374 0 : while ( i < nMaxLen )
375 : {
376 0 : if ( (rEditMask[i] != EDITMASK_LITERAL) &&
377 0 : (aText[i] != ' ') )
378 0 : break;
379 :
380 0 : i++;
381 : }
382 : // keep all literal characters
383 0 : while ( i && (rEditMask[i] == EDITMASK_LITERAL) )
384 0 : i--;
385 0 : aText = aText.copy( i );
386 : }
387 :
388 0 : OUString aNewText = ImplPatternReformat( aText, rEditMask, rLiteralMask, nFormatFlags );
389 0 : if ( aNewText != aText )
390 : {
391 : // adjust selection such that it remains at the end if it was there before
392 0 : Selection aSel = pEdit->GetSelection();
393 0 : sal_Int64 nMaxSel = std::max( aSel.Min(), aSel.Max() );
394 0 : if ( nMaxSel >= aText.getLength() )
395 : {
396 0 : sal_Int32 nMaxPos = aNewText.getLength();
397 0 : ImplPatternMaxPos( aNewText, rEditMask, nFormatFlags, bSameMask, nMaxSel, nMaxPos );
398 0 : if ( aSel.Min() == aSel.Max() )
399 : {
400 0 : aSel.Min() = nMaxPos;
401 0 : aSel.Max() = aSel.Min();
402 : }
403 0 : else if ( aSel.Min() > aSel.Max() )
404 0 : aSel.Min() = nMaxPos;
405 : else
406 0 : aSel.Max() = nMaxPos;
407 : }
408 0 : pEdit->SetText( aNewText, aSel );
409 0 : }
410 0 : }
411 :
412 0 : static sal_Int32 ImplPatternLeftPos(const OString& rEditMask, sal_Int32 nCursorPos)
413 : {
414 : // search non-literal predecessor
415 0 : sal_Int32 nNewPos = nCursorPos;
416 0 : sal_Int32 nTempPos = nNewPos;
417 0 : while ( nTempPos )
418 : {
419 0 : if ( rEditMask[nTempPos-1] != EDITMASK_LITERAL )
420 : {
421 0 : nNewPos = nTempPos-1;
422 0 : break;
423 : }
424 0 : nTempPos--;
425 : }
426 0 : return nNewPos;
427 : }
428 :
429 0 : static sal_Int32 ImplPatternRightPos( const OUString& rStr, const OString& rEditMask,
430 : sal_uInt16 nFormatFlags, bool bSameMask,
431 : sal_Int32 nCursorPos )
432 : {
433 : // search non-literal successor
434 0 : sal_Int32 nNewPos = nCursorPos;
435 0 : sal_Int32 nTempPos = nNewPos;
436 0 : while ( nTempPos < rEditMask.getLength() )
437 : {
438 0 : if ( rEditMask[nTempPos+1] != EDITMASK_LITERAL )
439 : {
440 0 : nNewPos = nTempPos+1;
441 0 : break;
442 : }
443 0 : nTempPos++;
444 : }
445 0 : ImplPatternMaxPos( rStr, rEditMask, nFormatFlags, bSameMask, nCursorPos, nNewPos );
446 0 : return nNewPos;
447 : }
448 :
449 0 : static bool ImplPatternProcessKeyInput( Edit* pEdit, const KeyEvent& rKEvt,
450 : const OString& rEditMask,
451 : const OUString& rLiteralMask,
452 : bool bStrictFormat,
453 : sal_uInt16 nFormatFlags,
454 : bool bSameMask,
455 : bool& rbInKeyInput )
456 : {
457 0 : if ( rEditMask.isEmpty() || !bStrictFormat )
458 0 : return false;
459 :
460 0 : Selection aOldSel = pEdit->GetSelection();
461 0 : vcl::KeyCode aCode = rKEvt.GetKeyCode();
462 0 : sal_Unicode cChar = rKEvt.GetCharCode();
463 0 : sal_uInt16 nKeyCode = aCode.GetCode();
464 0 : bool bShift = aCode.IsShift();
465 0 : sal_Int32 nCursorPos = static_cast<sal_Int32>(aOldSel.Max());
466 : sal_Int32 nNewPos;
467 : sal_Int32 nTempPos;
468 :
469 0 : if ( nKeyCode && !aCode.IsMod1() && !aCode.IsMod2() )
470 : {
471 0 : if ( nKeyCode == KEY_LEFT )
472 : {
473 0 : Selection aSel( ImplPatternLeftPos( rEditMask, nCursorPos ) );
474 0 : if ( bShift )
475 0 : aSel.Min() = aOldSel.Min();
476 0 : pEdit->SetSelection( aSel );
477 0 : return true;
478 : }
479 0 : else if ( nKeyCode == KEY_RIGHT )
480 : {
481 : // Use the start of selection as minimum; even a small position is allowed in case that
482 : // all was selected by the focus
483 0 : Selection aSel( aOldSel );
484 0 : aSel.Justify();
485 0 : nCursorPos = aSel.Min();
486 0 : aSel.Max() = ImplPatternRightPos( pEdit->GetText(), rEditMask, nFormatFlags, bSameMask, nCursorPos );
487 0 : if ( bShift )
488 0 : aSel.Min() = aOldSel.Min();
489 : else
490 0 : aSel.Min() = aSel.Max();
491 0 : pEdit->SetSelection( aSel );
492 0 : return true;
493 : }
494 0 : else if ( nKeyCode == KEY_HOME )
495 : {
496 : // Home is the position of the first non-literal character
497 0 : nNewPos = 0;
498 0 : while ( (nNewPos < rEditMask.getLength()) &&
499 0 : (rEditMask[nNewPos] == EDITMASK_LITERAL) )
500 0 : nNewPos++;
501 :
502 : // Home should not move to the right
503 0 : if ( nCursorPos < nNewPos )
504 0 : nNewPos = nCursorPos;
505 0 : Selection aSel( nNewPos );
506 0 : if ( bShift )
507 0 : aSel.Min() = aOldSel.Min();
508 0 : pEdit->SetSelection( aSel );
509 0 : return true;
510 : }
511 0 : else if ( nKeyCode == KEY_END )
512 : {
513 : // End is position of last non-literal character
514 0 : nNewPos = rEditMask.getLength();
515 0 : while ( nNewPos &&
516 0 : (rEditMask[nNewPos-1] == EDITMASK_LITERAL) )
517 0 : nNewPos--;
518 : // Use the start of selection as minimum; even a small position is allowed in case that
519 : // all was selected by the focus
520 0 : Selection aSel( aOldSel );
521 0 : aSel.Justify();
522 0 : nCursorPos = static_cast<sal_Int32>(aSel.Min());
523 0 : ImplPatternMaxPos( pEdit->GetText(), rEditMask, nFormatFlags, bSameMask, nCursorPos, nNewPos );
524 0 : aSel.Max() = nNewPos;
525 0 : if ( bShift )
526 0 : aSel.Min() = aOldSel.Min();
527 : else
528 0 : aSel.Min() = aSel.Max();
529 0 : pEdit->SetSelection( aSel );
530 0 : return true;
531 : }
532 0 : else if ( (nKeyCode == KEY_BACKSPACE) || (nKeyCode == KEY_DELETE) )
533 : {
534 0 : OUString aOldStr( pEdit->GetText() );
535 0 : OUStringBuffer aStr( aOldStr );
536 0 : Selection aSel = aOldSel;
537 :
538 0 : aSel.Justify();
539 0 : nNewPos = static_cast<sal_Int32>(aSel.Min());
540 :
541 : // if selection then delete it
542 0 : if ( aSel.Len() )
543 : {
544 0 : if ( bSameMask )
545 0 : aStr.remove( static_cast<sal_Int32>(aSel.Min()), static_cast<sal_Int32>(aSel.Len()) );
546 : else
547 : {
548 0 : OUString aRep = rLiteralMask.copy( static_cast<sal_Int32>(aSel.Min()), static_cast<sal_Int32>(aSel.Len()) );
549 0 : aStr.remove( aSel.Min(), aRep.getLength() );
550 0 : aStr.insert( aSel.Min(), aRep );
551 : }
552 : }
553 : else
554 : {
555 0 : if ( nKeyCode == KEY_BACKSPACE )
556 : {
557 0 : nTempPos = nNewPos;
558 0 : nNewPos = ImplPatternLeftPos( rEditMask, nTempPos );
559 : }
560 : else
561 0 : nTempPos = ImplPatternRightPos( aStr.toString(), rEditMask, nFormatFlags, bSameMask, nNewPos );
562 :
563 0 : if ( nNewPos != nTempPos )
564 : {
565 0 : if ( bSameMask )
566 : {
567 0 : if ( rEditMask[nNewPos] != EDITMASK_LITERAL )
568 0 : aStr.remove( nNewPos, 1 );
569 : }
570 : else
571 : {
572 0 : aStr[nNewPos] = rLiteralMask[nNewPos];
573 : }
574 : }
575 : }
576 :
577 0 : if ( aOldStr != aStr.toString() )
578 : {
579 0 : if ( bSameMask )
580 0 : aStr = ImplPatternReformat( aStr.toString(), rEditMask, rLiteralMask, nFormatFlags );
581 0 : rbInKeyInput = true;
582 0 : pEdit->SetText( aStr.toString(), Selection( nNewPos ) );
583 0 : pEdit->SetModifyFlag();
584 0 : pEdit->Modify();
585 0 : rbInKeyInput = false;
586 : }
587 : else
588 0 : pEdit->SetSelection( Selection( nNewPos ) );
589 :
590 0 : return true;
591 : }
592 0 : else if ( nKeyCode == KEY_INSERT )
593 : {
594 : // you can only set InsertModus for a PatternField if the
595 : // mask is equal at all input positions
596 0 : if ( !bSameMask )
597 : {
598 0 : return true;
599 : }
600 : }
601 : }
602 :
603 0 : if ( rKEvt.GetKeyCode().IsMod2() || (cChar < 32) || (cChar == 127) )
604 0 : return false;
605 :
606 0 : Selection aSel = aOldSel;
607 0 : aSel.Justify();
608 0 : nNewPos = aSel.Min();
609 :
610 0 : if ( nNewPos < rEditMask.getLength() )
611 : {
612 0 : sal_Unicode cPattChar = ImplPatternChar( cChar, rEditMask[nNewPos] );
613 0 : if ( cPattChar )
614 0 : cChar = cPattChar;
615 : else
616 : {
617 : // If no valid character, check if the user wanted to jump to next literal. We do this
618 : // only if we're after a character, so that literals that were skipped automatically
619 : // do not influence the position anymore.
620 0 : if ( nNewPos &&
621 0 : (rEditMask[nNewPos-1] != EDITMASK_LITERAL) &&
622 0 : !aSel.Len() )
623 : {
624 : // search for next character not being a literal
625 0 : nTempPos = nNewPos;
626 0 : while ( nTempPos < rEditMask.getLength() )
627 : {
628 0 : if ( rEditMask[nTempPos] == EDITMASK_LITERAL )
629 : {
630 : // only valid if no literal present
631 0 : if ( (rEditMask[nTempPos+1] != EDITMASK_LITERAL ) &&
632 0 : ImplCommaPointCharEqual( cChar, rLiteralMask[nTempPos] ) )
633 : {
634 0 : nTempPos++;
635 0 : ImplPatternMaxPos( pEdit->GetText(), rEditMask, nFormatFlags, bSameMask, nNewPos, nTempPos );
636 0 : if ( nTempPos > nNewPos )
637 : {
638 0 : pEdit->SetSelection( Selection( nTempPos ) );
639 0 : return true;
640 : }
641 : }
642 0 : break;
643 : }
644 0 : nTempPos++;
645 : }
646 : }
647 :
648 0 : cChar = 0;
649 : }
650 : }
651 : else
652 0 : cChar = 0;
653 0 : if ( cChar )
654 : {
655 0 : OUStringBuffer aStr = pEdit->GetText();
656 0 : bool bError = false;
657 0 : if ( bSameMask && pEdit->IsInsertMode() )
658 : {
659 : // crop spaces and literals at the end until current position
660 0 : sal_Int32 n = aStr.getLength();
661 0 : while ( n && (n > nNewPos) )
662 : {
663 0 : if ( (aStr[n-1] != ' ') &&
664 0 : ((n > rEditMask.getLength()) || (rEditMask[n-1] != EDITMASK_LITERAL)) )
665 0 : break;
666 :
667 0 : n--;
668 : }
669 0 : aStr.truncate( n );
670 :
671 0 : if ( aSel.Len() )
672 0 : aStr.remove( aSel.Min(), aSel.Len() );
673 :
674 0 : if ( aStr.getLength() < rEditMask.getLength() )
675 : {
676 : // possibly extend string until cursor position
677 0 : if ( aStr.getLength() < nNewPos )
678 0 : aStr.append( rLiteralMask.copy( aStr.getLength(), nNewPos-aStr.getLength() ));
679 0 : if ( nNewPos < aStr.getLength() )
680 0 : aStr.insert( cChar, nNewPos );
681 0 : else if ( nNewPos < rEditMask.getLength() )
682 0 : aStr.append(cChar);
683 0 : aStr = ImplPatternReformat( aStr.toString(), rEditMask, rLiteralMask, nFormatFlags );
684 : }
685 : else
686 0 : bError = true;
687 : }
688 : else
689 : {
690 0 : if ( aSel.Len() )
691 : {
692 : // delete selection
693 0 : OUString aRep = rLiteralMask.copy( aSel.Min(), aSel.Len() );
694 0 : aStr.remove( aSel.Min(), aRep.getLength() );
695 0 : aStr.insert( aSel.Min(), aRep );
696 : }
697 :
698 0 : if ( nNewPos < aStr.getLength() )
699 0 : aStr[nNewPos] = cChar;
700 0 : else if ( nNewPos < rEditMask.getLength() )
701 0 : aStr.append(cChar);
702 : }
703 :
704 0 : if ( !bError )
705 : {
706 0 : rbInKeyInput = true;
707 0 : Selection aNewSel( ImplPatternRightPos( aStr.toString(), rEditMask, nFormatFlags, bSameMask, nNewPos ) );
708 0 : pEdit->SetText( aStr.toString(), aNewSel );
709 0 : pEdit->SetModifyFlag();
710 0 : pEdit->Modify();
711 0 : rbInKeyInput = false;
712 0 : }
713 : }
714 :
715 0 : return true;
716 : }
717 :
718 81 : void PatternFormatter::ImplSetMask(const OString& rEditMask, const OUString& rLiteralMask)
719 : {
720 81 : m_aEditMask = rEditMask;
721 81 : maLiteralMask = rLiteralMask;
722 81 : mbSameMask = true;
723 :
724 81 : if ( m_aEditMask.getLength() != maLiteralMask.getLength() )
725 : {
726 14 : OUStringBuffer aBuf(maLiteralMask);
727 14 : if (m_aEditMask.getLength() < aBuf.getLength())
728 0 : aBuf.remove(m_aEditMask.getLength(), aBuf.getLength() - m_aEditMask.getLength());
729 : else
730 14 : comphelper::string::padToLength(aBuf, m_aEditMask.getLength(), ' ');
731 14 : maLiteralMask = aBuf.makeStringAndClear();
732 : }
733 :
734 : // Strict mode allows only the input mode if only equal characters are allowed as mask and if
735 : // only spaces are specified which are not allowed by the mask
736 81 : sal_Int32 i = 0;
737 81 : sal_Char c = 0;
738 183 : while ( i < rEditMask.getLength() )
739 : {
740 51 : sal_Char cTemp = rEditMask[i];
741 51 : if ( cTemp != EDITMASK_LITERAL )
742 : {
743 51 : if ( (cTemp == EDITMASK_ALLCHAR) ||
744 51 : (cTemp == EDITMASK_UPPERALLCHAR) ||
745 : (cTemp == EDITMASK_NUMSPACE) )
746 : {
747 0 : mbSameMask = false;
748 0 : break;
749 : }
750 51 : if ( i < rLiteralMask.getLength() )
751 : {
752 31 : if ( rLiteralMask[i] != ' ' )
753 : {
754 27 : mbSameMask = false;
755 27 : break;
756 : }
757 : }
758 24 : if ( !c )
759 9 : c = cTemp;
760 24 : if ( cTemp != c )
761 : {
762 3 : mbSameMask = false;
763 3 : break;
764 : }
765 : }
766 21 : i++;
767 : }
768 81 : }
769 :
770 8 : PatternFormatter::PatternFormatter()
771 : {
772 8 : mnFormatFlags = 0;
773 8 : mbSameMask = true;
774 8 : mbInPattKeyInput = false;
775 8 : }
776 :
777 0 : PatternFormatter::~PatternFormatter()
778 : {
779 0 : }
780 :
781 81 : void PatternFormatter::SetMask( const OString& rEditMask,
782 : const OUString& rLiteralMask )
783 : {
784 81 : ImplSetMask( rEditMask, rLiteralMask );
785 81 : ReformatAll();
786 81 : }
787 :
788 81 : void PatternFormatter::SetString( const OUString& rStr )
789 : {
790 81 : maFieldString = rStr;
791 81 : if ( GetField() )
792 : {
793 81 : GetField()->SetText( rStr );
794 81 : MarkToBeReformatted( false );
795 : }
796 81 : }
797 :
798 0 : OUString PatternFormatter::GetString() const
799 : {
800 0 : if ( !GetField() )
801 0 : return OUString();
802 : else
803 0 : return ImplPatternReformat( GetField()->GetText(), m_aEditMask, maLiteralMask, mnFormatFlags );
804 : }
805 :
806 96 : void PatternFormatter::Reformat()
807 : {
808 96 : if ( GetField() )
809 : {
810 96 : ImplSetText( ImplPatternReformat( GetField()->GetText(), m_aEditMask, maLiteralMask, mnFormatFlags ) );
811 96 : if ( !mbSameMask && IsStrictFormat() && !GetField()->IsReadOnly() )
812 0 : GetField()->SetInsertMode( false );
813 : }
814 96 : }
815 :
816 8 : PatternField::PatternField( vcl::Window* pParent, WinBits nWinStyle ) :
817 8 : SpinField( pParent, nWinStyle )
818 : {
819 8 : SetField( this );
820 8 : Reformat();
821 8 : }
822 :
823 0 : bool PatternField::PreNotify( NotifyEvent& rNEvt )
824 : {
825 0 : if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
826 : {
827 0 : if ( ImplPatternProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
828 0 : IsStrictFormat(), GetFormatFlags(),
829 0 : ImplIsSameMask(), ImplGetInPattKeyInput() ) )
830 0 : return true;
831 : }
832 :
833 0 : return SpinField::PreNotify( rNEvt );
834 : }
835 :
836 8 : bool PatternField::Notify( NotifyEvent& rNEvt )
837 : {
838 8 : if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
839 0 : MarkToBeReformatted( false );
840 8 : else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
841 : {
842 0 : if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
843 0 : Reformat();
844 : }
845 :
846 8 : return SpinField::Notify( rNEvt );
847 : }
848 :
849 0 : void PatternField::Modify()
850 : {
851 0 : if ( !ImplGetInPattKeyInput() )
852 : {
853 0 : if ( IsStrictFormat() )
854 0 : ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), GetFormatFlags(), ImplIsSameMask() );
855 : else
856 0 : MarkToBeReformatted( true );
857 : }
858 :
859 0 : SpinField::Modify();
860 0 : }
861 :
862 0 : PatternBox::PatternBox( vcl::Window* pParent, WinBits nWinStyle ) :
863 0 : ComboBox( pParent, nWinStyle )
864 : {
865 0 : SetField( this );
866 0 : Reformat();
867 0 : }
868 :
869 0 : bool PatternBox::PreNotify( NotifyEvent& rNEvt )
870 : {
871 0 : if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
872 : {
873 0 : if ( ImplPatternProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
874 0 : IsStrictFormat(), GetFormatFlags(),
875 0 : ImplIsSameMask(), ImplGetInPattKeyInput() ) )
876 0 : return true;
877 : }
878 :
879 0 : return ComboBox::PreNotify( rNEvt );
880 : }
881 :
882 0 : bool PatternBox::Notify( NotifyEvent& rNEvt )
883 : {
884 0 : if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
885 0 : MarkToBeReformatted( false );
886 0 : else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
887 : {
888 0 : if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
889 0 : Reformat();
890 : }
891 :
892 0 : return ComboBox::Notify( rNEvt );
893 : }
894 :
895 0 : void PatternBox::Modify()
896 : {
897 0 : if ( !ImplGetInPattKeyInput() )
898 : {
899 0 : if ( IsStrictFormat() )
900 0 : ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), GetFormatFlags(), ImplIsSameMask() );
901 : else
902 0 : MarkToBeReformatted( true );
903 : }
904 :
905 0 : ComboBox::Modify();
906 0 : }
907 :
908 0 : void PatternBox::ReformatAll()
909 : {
910 0 : OUString aStr;
911 0 : SetUpdateMode( false );
912 0 : sal_uInt16 nEntryCount = GetEntryCount();
913 0 : for ( sal_uInt16 i=0; i < nEntryCount; i++ )
914 : {
915 0 : aStr = ImplPatternReformat( GetEntry( i ), GetEditMask(), GetLiteralMask(), GetFormatFlags() );
916 0 : RemoveEntryAt(i);
917 0 : InsertEntry( aStr, i );
918 : }
919 0 : PatternFormatter::Reformat();
920 0 : SetUpdateMode( true );
921 0 : }
922 :
923 4 : static ExtDateFieldFormat ImplGetExtFormat( DateFormat eOld )
924 : {
925 4 : switch( eOld )
926 : {
927 0 : case DMY: return XTDATEF_SHORT_DDMMYY;
928 4 : case MDY: return XTDATEF_SHORT_MMDDYY;
929 0 : default: return XTDATEF_SHORT_YYMMDD;
930 : }
931 : }
932 :
933 166 : static sal_uInt16 ImplCutNumberFromString( OUString& rStr )
934 : {
935 166 : sal_Int32 i1 = 0;
936 1113 : while (i1 != rStr.getLength() && !(rStr[i1] >= '0' && rStr[i1] <= '9')) {
937 781 : ++i1;
938 : }
939 166 : sal_Int32 i2 = i1;
940 682 : while (i2 != rStr.getLength() && rStr[i2] >= '0' && rStr[i2] <= '9') {
941 350 : ++i2;
942 : }
943 166 : sal_Int32 nValue = rStr.copy(i1, i2-i1).toInt32();
944 166 : rStr = rStr.copy(std::min(i2+1, rStr.getLength()));
945 166 : return nValue;
946 : }
947 :
948 788 : static bool ImplCutMonthName( OUString& rStr, const OUString& _rLookupMonthName )
949 : {
950 788 : sal_Int32 index = 0;
951 788 : rStr = rStr.replaceFirst(_rLookupMonthName, OUString(), &index);
952 788 : return index >= 0;
953 : }
954 :
955 78 : static sal_uInt16 ImplCutMonthFromString( OUString& rStr, const CalendarWrapper& rCalendarWrapper )
956 : {
957 : // search for a month' name
958 438 : for ( sal_uInt16 i=1; i <= 12; i++ )
959 : {
960 428 : OUString aMonthName = rCalendarWrapper.getMonths()[i-1].FullName;
961 : // long month name?
962 428 : if ( ImplCutMonthName( rStr, aMonthName ) )
963 68 : return i;
964 :
965 : // short month name?
966 720 : OUString aAbbrevMonthName = rCalendarWrapper.getMonths()[i-1].AbbrevName;
967 360 : if ( ImplCutMonthName( rStr, aAbbrevMonthName ) )
968 0 : return i;
969 360 : }
970 :
971 10 : return ImplCutNumberFromString( rStr );
972 : }
973 :
974 513 : static OUString ImplGetDateSep( const LocaleDataWrapper& rLocaleDataWrapper, ExtDateFieldFormat eFormat )
975 : {
976 513 : if ( ( eFormat == XTDATEF_SHORT_YYMMDD_DIN5008 ) || ( eFormat == XTDATEF_SHORT_YYYYMMDD_DIN5008 ) )
977 0 : return OUString("-");
978 : else
979 513 : return rLocaleDataWrapper.getDateSep();
980 : }
981 :
982 0 : static bool ImplDateProcessKeyInput( Edit*, const KeyEvent& rKEvt, ExtDateFieldFormat eFormat,
983 : const LocaleDataWrapper& rLocaleDataWrapper )
984 : {
985 0 : sal_Unicode cChar = rKEvt.GetCharCode();
986 0 : sal_uInt16 nGroup = rKEvt.GetKeyCode().GetGroup();
987 0 : if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
988 0 : (nGroup == KEYGROUP_MISC)||
989 0 : ((cChar >= '0') && (cChar <= '9')) ||
990 0 : (cChar == ImplGetDateSep( rLocaleDataWrapper, eFormat )[0]) )
991 0 : return false;
992 : else
993 0 : return true;
994 : }
995 :
996 392 : static bool ImplDateGetValue( const OUString& rStr, Date& rDate, ExtDateFieldFormat eDateFormat,
997 : const LocaleDataWrapper& rLocaleDataWrapper, const CalendarWrapper& rCalendarWrapper,
998 : const AllSettings& )
999 : {
1000 392 : sal_uInt16 nDay = 0;
1001 392 : sal_uInt16 nMonth = 0;
1002 392 : sal_uInt16 nYear = 0;
1003 392 : bool bError = false;
1004 392 : OUString aStr( rStr );
1005 :
1006 392 : if ( eDateFormat == XTDATEF_SYSTEM_LONG )
1007 : {
1008 78 : DateFormat eFormat = rLocaleDataWrapper.getLongDateFormat();
1009 78 : switch( eFormat )
1010 : {
1011 : case MDY:
1012 78 : nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
1013 78 : nDay = ImplCutNumberFromString( aStr );
1014 78 : nYear = ImplCutNumberFromString( aStr );
1015 78 : break;
1016 : case DMY:
1017 0 : nDay = ImplCutNumberFromString( aStr );
1018 0 : nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
1019 0 : nYear = ImplCutNumberFromString( aStr );
1020 0 : break;
1021 : case YMD:
1022 : default:
1023 0 : nYear = ImplCutNumberFromString( aStr );
1024 0 : nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
1025 0 : nDay = ImplCutNumberFromString( aStr );
1026 0 : break;
1027 : }
1028 : }
1029 : else
1030 : {
1031 314 : bool bYear = true;
1032 :
1033 : // Check if year is present:
1034 314 : OUString aDateSep = ImplGetDateSep( rLocaleDataWrapper, eDateFormat );
1035 314 : sal_Int32 nSepPos = aStr.indexOf( aDateSep );
1036 314 : if ( nSepPos < 0 )
1037 3 : return false;
1038 311 : nSepPos = aStr.indexOf( aDateSep, nSepPos+1 );
1039 311 : if ( ( nSepPos < 0 ) || ( nSepPos == (aStr.getLength()-1) ) )
1040 : {
1041 0 : bYear = false;
1042 0 : nYear = Date( Date::SYSTEM ).GetYear();
1043 : }
1044 :
1045 311 : const sal_Unicode* pBuf = aStr.getStr();
1046 311 : ImplSkipDelimiters( pBuf );
1047 :
1048 311 : switch ( eDateFormat )
1049 : {
1050 : case XTDATEF_SHORT_DDMMYY:
1051 : case XTDATEF_SHORT_DDMMYYYY:
1052 : {
1053 7 : nDay = ImplGetNum( pBuf, bError );
1054 7 : ImplSkipDelimiters( pBuf );
1055 7 : nMonth = ImplGetNum( pBuf, bError );
1056 7 : ImplSkipDelimiters( pBuf );
1057 7 : if ( bYear )
1058 7 : nYear = ImplGetNum( pBuf, bError );
1059 : }
1060 7 : break;
1061 : case XTDATEF_SHORT_MMDDYY:
1062 : case XTDATEF_SHORT_MMDDYYYY:
1063 : {
1064 304 : nMonth = ImplGetNum( pBuf, bError );
1065 304 : ImplSkipDelimiters( pBuf );
1066 304 : nDay = ImplGetNum( pBuf, bError );
1067 304 : ImplSkipDelimiters( pBuf );
1068 304 : if ( bYear )
1069 304 : nYear = ImplGetNum( pBuf, bError );
1070 : }
1071 304 : break;
1072 : case XTDATEF_SHORT_YYMMDD:
1073 : case XTDATEF_SHORT_YYYYMMDD:
1074 : case XTDATEF_SHORT_YYMMDD_DIN5008:
1075 : case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1076 : {
1077 0 : if ( bYear )
1078 0 : nYear = ImplGetNum( pBuf, bError );
1079 0 : ImplSkipDelimiters( pBuf );
1080 0 : nMonth = ImplGetNum( pBuf, bError );
1081 0 : ImplSkipDelimiters( pBuf );
1082 0 : nDay = ImplGetNum( pBuf, bError );
1083 : }
1084 0 : break;
1085 :
1086 : default:
1087 : {
1088 : OSL_FAIL( "DateFormat???" );
1089 : }
1090 311 : }
1091 : }
1092 :
1093 389 : if ( bError || !nDay || !nMonth )
1094 130 : return false;
1095 :
1096 259 : Date aNewDate( nDay, nMonth, nYear );
1097 259 : DateFormatter::ExpandCentury( aNewDate, utl::MiscCfg().GetYear2000() );
1098 259 : if ( aNewDate.IsValidDate() )
1099 : {
1100 257 : rDate = aNewDate;
1101 257 : return true;
1102 : }
1103 2 : return false;
1104 : }
1105 :
1106 175 : bool DateFormatter::ImplDateReformat( const OUString& rStr, OUString& rOutStr, const AllSettings& rSettings )
1107 : {
1108 175 : Date aDate( 0, 0, 0 );
1109 175 : if ( !ImplDateGetValue( rStr, aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1110 75 : return true;
1111 :
1112 100 : Date aTempDate = aDate;
1113 100 : if ( aTempDate > GetMax() )
1114 25 : aTempDate = GetMax();
1115 75 : else if ( aTempDate < GetMin() )
1116 2 : aTempDate = GetMin();
1117 :
1118 100 : if ( GetErrorHdl().IsSet() && (aDate != aTempDate) )
1119 : {
1120 0 : maCorrectedDate = aTempDate;
1121 0 : if( !GetErrorHdl().Call( this ) )
1122 : {
1123 0 : maCorrectedDate = Date( Date::SYSTEM );
1124 0 : return false;
1125 : }
1126 : else
1127 0 : maCorrectedDate = Date( Date::SYSTEM );
1128 : }
1129 :
1130 100 : rOutStr = ImplGetDateAsText( aTempDate, rSettings );
1131 :
1132 100 : return true;
1133 : }
1134 :
1135 199 : OUString DateFormatter::ImplGetDateAsText( const Date& rDate,
1136 : const AllSettings& ) const
1137 : {
1138 199 : bool bShowCentury = false;
1139 199 : switch ( GetExtDateFormat() )
1140 : {
1141 : case XTDATEF_SYSTEM_SHORT_YYYY:
1142 : case XTDATEF_SYSTEM_LONG:
1143 : case XTDATEF_SHORT_DDMMYYYY:
1144 : case XTDATEF_SHORT_MMDDYYYY:
1145 : case XTDATEF_SHORT_YYYYMMDD:
1146 : case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1147 : {
1148 91 : bShowCentury = true;
1149 : }
1150 91 : break;
1151 : default:
1152 : {
1153 108 : bShowCentury = false;
1154 : }
1155 : }
1156 :
1157 199 : if ( !bShowCentury )
1158 : {
1159 : // Check if I have to use force showing the century
1160 108 : sal_uInt16 nTwoDigitYearStart = utl::MiscCfg().GetYear2000();
1161 108 : sal_uInt16 nYear = rDate.GetYear();
1162 :
1163 : // If year is not in double digit range
1164 108 : if ( (nYear < nTwoDigitYearStart) || (nYear >= nTwoDigitYearStart+100) )
1165 38 : bShowCentury = true;
1166 : }
1167 :
1168 : sal_Unicode aBuf[128];
1169 199 : sal_Unicode* pBuf = aBuf;
1170 :
1171 199 : OUString aDateSep = ImplGetDateSep( ImplGetLocaleDataWrapper(), GetExtDateFormat( true ) );
1172 199 : sal_uInt16 nDay = rDate.GetDay();
1173 199 : sal_uInt16 nMonth = rDate.GetMonth();
1174 199 : sal_uInt16 nYear = rDate.GetYear();
1175 199 : sal_uInt16 nYearLen = bShowCentury ? 4 : 2;
1176 :
1177 199 : if ( !bShowCentury )
1178 70 : nYear %= 100;
1179 :
1180 199 : switch ( GetExtDateFormat( true ) )
1181 : {
1182 : case XTDATEF_SYSTEM_LONG:
1183 : {
1184 35 : return ImplGetLocaleDataWrapper().getLongDate( rDate, GetCalendarWrapper(), 1, false, 1, !bShowCentury );
1185 : }
1186 : case XTDATEF_SHORT_DDMMYY:
1187 : case XTDATEF_SHORT_DDMMYYYY:
1188 : {
1189 3 : pBuf = ImplAddNum( pBuf, nDay, 2 );
1190 3 : pBuf = ImplAddString( pBuf, aDateSep );
1191 3 : pBuf = ImplAddNum( pBuf, nMonth, 2 );
1192 3 : pBuf = ImplAddString( pBuf, aDateSep );
1193 3 : pBuf = ImplAddNum( pBuf, nYear, nYearLen );
1194 : }
1195 3 : break;
1196 : case XTDATEF_SHORT_MMDDYY:
1197 : case XTDATEF_SHORT_MMDDYYYY:
1198 : {
1199 161 : pBuf = ImplAddNum( pBuf, nMonth, 2 );
1200 161 : pBuf = ImplAddString( pBuf, aDateSep );
1201 161 : pBuf = ImplAddNum( pBuf, nDay, 2 );
1202 161 : pBuf = ImplAddString( pBuf, aDateSep );
1203 161 : pBuf = ImplAddNum( pBuf, nYear, nYearLen );
1204 : }
1205 161 : break;
1206 : case XTDATEF_SHORT_YYMMDD:
1207 : case XTDATEF_SHORT_YYYYMMDD:
1208 : case XTDATEF_SHORT_YYMMDD_DIN5008:
1209 : case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1210 : {
1211 0 : pBuf = ImplAddNum( pBuf, nYear, nYearLen );
1212 0 : pBuf = ImplAddString( pBuf, aDateSep );
1213 0 : pBuf = ImplAddNum( pBuf, nMonth, 2 );
1214 0 : pBuf = ImplAddString( pBuf, aDateSep );
1215 0 : pBuf = ImplAddNum( pBuf, nDay, 2 );
1216 : }
1217 0 : break;
1218 : default:
1219 : {
1220 : OSL_FAIL( "DateFormat???" );
1221 : }
1222 : }
1223 :
1224 164 : return OUString(aBuf, pBuf-aBuf);
1225 : }
1226 :
1227 2 : static void ImplDateIncrementDay( Date& rDate, bool bUp )
1228 : {
1229 2 : DateFormatter::ExpandCentury( rDate );
1230 :
1231 2 : if ( bUp )
1232 : {
1233 2 : if ( (rDate.GetDay() != 31) || (rDate.GetMonth() != 12) || (rDate.GetYear() != 9999) )
1234 2 : ++rDate;
1235 : }
1236 : else
1237 : {
1238 0 : if ( (rDate.GetDay() != 1 ) || (rDate.GetMonth() != 1) || (rDate.GetYear() != 0) )
1239 0 : --rDate;
1240 : }
1241 2 : }
1242 :
1243 4 : static void ImplDateIncrementMonth( Date& rDate, bool bUp )
1244 : {
1245 4 : DateFormatter::ExpandCentury( rDate );
1246 :
1247 4 : sal_uInt16 nMonth = rDate.GetMonth();
1248 4 : sal_uInt16 nYear = rDate.GetYear();
1249 4 : if ( bUp )
1250 : {
1251 2 : if ( (nMonth == 12) && (nYear < 9999) )
1252 : {
1253 0 : rDate.SetMonth( 1 );
1254 0 : rDate.SetYear( nYear + 1 );
1255 : }
1256 : else
1257 : {
1258 2 : if ( nMonth < 12 )
1259 2 : rDate.SetMonth( nMonth + 1 );
1260 : }
1261 : }
1262 : else
1263 : {
1264 2 : if ( (nMonth == 1) && (nYear > 0) )
1265 : {
1266 0 : rDate.SetMonth( 12 );
1267 0 : rDate.SetYear( nYear - 1 );
1268 : }
1269 : else
1270 : {
1271 2 : if ( nMonth > 1 )
1272 2 : rDate.SetMonth( nMonth - 1 );
1273 : }
1274 : }
1275 :
1276 4 : sal_uInt16 nDaysInMonth = Date::GetDaysInMonth( rDate.GetMonth(), rDate.GetYear());
1277 4 : if ( rDate.GetDay() > nDaysInMonth )
1278 0 : rDate.SetDay( nDaysInMonth );
1279 4 : }
1280 :
1281 0 : static void ImplDateIncrementYear( Date& rDate, bool bUp )
1282 : {
1283 0 : DateFormatter::ExpandCentury( rDate );
1284 :
1285 0 : sal_uInt16 nYear = rDate.GetYear();
1286 0 : sal_uInt16 nMonth = rDate.GetMonth();
1287 0 : if ( bUp )
1288 : {
1289 0 : if ( nYear < 9999 )
1290 0 : rDate.SetYear( nYear + 1 );
1291 : }
1292 : else
1293 : {
1294 0 : if ( nYear > 0 )
1295 0 : rDate.SetYear( nYear - 1 );
1296 : }
1297 0 : if (nMonth == 2)
1298 : {
1299 : // Handle February 29 from leap year to non-leap year.
1300 0 : sal_uInt16 nDay = rDate.GetDay();
1301 0 : if (nDay > 28)
1302 : {
1303 : // The check would not be necessary if it was guaranteed that the
1304 : // date was valid before and actually was a leap year,
1305 : // de-/incrementing a leap year with 29 always results in 28.
1306 0 : sal_uInt16 nDaysInMonth = Date::GetDaysInMonth( nMonth, rDate.GetYear());
1307 0 : if (nDay > nDaysInMonth)
1308 0 : rDate.SetDay( nDaysInMonth);
1309 : }
1310 : }
1311 0 : }
1312 :
1313 46 : bool DateFormatter::ImplAllowMalformedInput() const
1314 : {
1315 46 : return !IsEnforceValidValue();
1316 : }
1317 :
1318 6 : void DateField::ImplDateSpinArea( bool bUp )
1319 : {
1320 : // increment days if all is selected
1321 6 : if ( GetField() )
1322 : {
1323 6 : Date aDate( GetDate() );
1324 6 : Selection aSelection = GetField()->GetSelection();
1325 6 : aSelection.Justify();
1326 6 : OUString aText( GetText() );
1327 6 : if ( (sal_Int32)aSelection.Len() == aText.getLength() )
1328 2 : ImplDateIncrementDay( aDate, bUp );
1329 : else
1330 : {
1331 4 : sal_Int8 nDateArea = 0;
1332 :
1333 4 : ExtDateFieldFormat eFormat = GetExtDateFormat( true );
1334 4 : if ( eFormat == XTDATEF_SYSTEM_LONG )
1335 : {
1336 4 : eFormat = ImplGetExtFormat( ImplGetLocaleDataWrapper().getLongDateFormat() );
1337 4 : nDateArea = 1;
1338 : }
1339 : else
1340 : {
1341 : // search area
1342 0 : sal_Int32 nPos = 0;
1343 0 : OUString aDateSep = ImplGetDateSep( ImplGetLocaleDataWrapper(), eFormat );
1344 0 : for ( sal_Int8 i = 1; i <= 3; i++ )
1345 : {
1346 0 : nPos = aText.indexOf( aDateSep, nPos );
1347 0 : if ( nPos >= (sal_Int32)aSelection.Max() )
1348 : {
1349 0 : nDateArea = i;
1350 0 : break;
1351 : }
1352 : else
1353 0 : nPos++;
1354 0 : }
1355 : }
1356 :
1357 4 : switch( eFormat )
1358 : {
1359 : case XTDATEF_SHORT_MMDDYY:
1360 : case XTDATEF_SHORT_MMDDYYYY:
1361 4 : switch( nDateArea )
1362 : {
1363 4 : case 1: ImplDateIncrementMonth( aDate, bUp );
1364 4 : break;
1365 0 : case 2: ImplDateIncrementDay( aDate, bUp );
1366 0 : break;
1367 0 : case 3: ImplDateIncrementYear( aDate, bUp );
1368 0 : break;
1369 : }
1370 4 : break;
1371 : case XTDATEF_SHORT_DDMMYY:
1372 : case XTDATEF_SHORT_DDMMYYYY:
1373 0 : switch( nDateArea )
1374 : {
1375 0 : case 1: ImplDateIncrementDay( aDate, bUp );
1376 0 : break;
1377 0 : case 2: ImplDateIncrementMonth( aDate, bUp );
1378 0 : break;
1379 0 : case 3: ImplDateIncrementYear( aDate, bUp );
1380 0 : break;
1381 : }
1382 0 : break;
1383 : case XTDATEF_SHORT_YYMMDD:
1384 : case XTDATEF_SHORT_YYYYMMDD:
1385 : case XTDATEF_SHORT_YYMMDD_DIN5008:
1386 : case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1387 0 : switch( nDateArea )
1388 : {
1389 0 : case 1: ImplDateIncrementYear( aDate, bUp );
1390 0 : break;
1391 0 : case 2: ImplDateIncrementMonth( aDate, bUp );
1392 0 : break;
1393 0 : case 3: ImplDateIncrementDay( aDate, bUp );
1394 0 : break;
1395 : }
1396 0 : break;
1397 : default:
1398 : OSL_FAIL( "invalid conversion" );
1399 0 : break;
1400 : }
1401 : }
1402 :
1403 6 : ImplNewFieldValue( aDate );
1404 : }
1405 6 : }
1406 :
1407 34 : void DateFormatter::ImplInit()
1408 : {
1409 34 : mbLongFormat = false;
1410 34 : mbShowDateCentury = true;
1411 34 : mpCalendarWrapper = NULL;
1412 34 : mnDateFormat = 0xFFFF;
1413 34 : mnExtDateFormat = XTDATEF_SYSTEM_SHORT;
1414 34 : }
1415 :
1416 34 : DateFormatter::DateFormatter() :
1417 : maFieldDate( 0 ),
1418 : maLastDate( 0 ),
1419 : maMin( 1, 1, 1900 ),
1420 : maMax( 31, 12, 2200 ),
1421 : maCorrectedDate( Date::SYSTEM ),
1422 34 : mbEnforceValidValue( true )
1423 : {
1424 34 : ImplInit();
1425 34 : }
1426 :
1427 0 : DateFormatter::~DateFormatter()
1428 : {
1429 0 : delete mpCalendarWrapper;
1430 0 : mpCalendarWrapper = NULL;
1431 0 : }
1432 :
1433 0 : void DateFormatter::SetLocale( const ::com::sun::star::lang::Locale& rLocale )
1434 : {
1435 0 : delete mpCalendarWrapper;
1436 0 : mpCalendarWrapper = NULL;
1437 0 : FormatterBase::SetLocale( rLocale );
1438 0 : }
1439 :
1440 427 : CalendarWrapper& DateFormatter::GetCalendarWrapper() const
1441 : {
1442 427 : if ( !mpCalendarWrapper )
1443 : {
1444 34 : const_cast<DateFormatter*>(this)->mpCalendarWrapper = new CalendarWrapper( comphelper::getProcessComponentContext() );
1445 34 : mpCalendarWrapper->loadDefaultCalendar( GetLocale() );
1446 : }
1447 :
1448 427 : return *mpCalendarWrapper;
1449 : }
1450 :
1451 49 : void DateFormatter::SetExtDateFormat( ExtDateFieldFormat eFormat )
1452 : {
1453 49 : mnExtDateFormat = eFormat;
1454 49 : ReformatAll();
1455 49 : }
1456 :
1457 999 : ExtDateFieldFormat DateFormatter::GetExtDateFormat( bool bResolveSystemFormat ) const
1458 : {
1459 999 : ExtDateFieldFormat eDateFormat = (ExtDateFieldFormat)mnExtDateFormat;
1460 :
1461 999 : if ( bResolveSystemFormat && ( eDateFormat <= XTDATEF_SYSTEM_SHORT_YYYY ) )
1462 : {
1463 544 : bool bShowCentury = (eDateFormat == XTDATEF_SYSTEM_SHORT_YYYY);
1464 544 : switch ( ImplGetLocaleDataWrapper().getDateFormat() )
1465 : {
1466 0 : case DMY: eDateFormat = bShowCentury ? XTDATEF_SHORT_DDMMYYYY : XTDATEF_SHORT_DDMMYY;
1467 0 : break;
1468 544 : case MDY: eDateFormat = bShowCentury ? XTDATEF_SHORT_MMDDYYYY : XTDATEF_SHORT_MMDDYY;
1469 544 : break;
1470 0 : default: eDateFormat = bShowCentury ? XTDATEF_SHORT_YYYYMMDD : XTDATEF_SHORT_YYMMDD;
1471 :
1472 : }
1473 : }
1474 :
1475 999 : return eDateFormat;
1476 : }
1477 :
1478 148 : void DateFormatter::ReformatAll()
1479 : {
1480 148 : Reformat();
1481 148 : }
1482 :
1483 44 : void DateFormatter::SetMin( const Date& rNewMin )
1484 : {
1485 44 : maMin = rNewMin;
1486 44 : if ( !IsEmptyFieldValue() )
1487 38 : ReformatAll();
1488 44 : }
1489 :
1490 44 : void DateFormatter::SetMax( const Date& rNewMax )
1491 : {
1492 44 : maMax = rNewMax;
1493 44 : if ( !IsEmptyFieldValue() )
1494 38 : ReformatAll();
1495 44 : }
1496 :
1497 4 : void DateFormatter::SetLongFormat( bool bLong )
1498 : {
1499 4 : mbLongFormat = bLong;
1500 :
1501 : // #91913# Remove LongFormat and DateShowCentury - redundant
1502 4 : if ( bLong )
1503 : {
1504 4 : SetExtDateFormat( XTDATEF_SYSTEM_LONG );
1505 : }
1506 : else
1507 : {
1508 0 : if( mnExtDateFormat == XTDATEF_SYSTEM_LONG )
1509 0 : SetExtDateFormat( XTDATEF_SYSTEM_SHORT );
1510 : }
1511 :
1512 4 : ReformatAll();
1513 4 : }
1514 :
1515 6 : void DateFormatter::SetShowDateCentury( bool bShowDateCentury )
1516 : {
1517 6 : mbShowDateCentury = bShowDateCentury;
1518 :
1519 : // #91913# Remove LongFormat and DateShowCentury - redundant
1520 6 : if ( bShowDateCentury )
1521 : {
1522 6 : switch ( GetExtDateFormat() )
1523 : {
1524 : case XTDATEF_SYSTEM_SHORT:
1525 : case XTDATEF_SYSTEM_SHORT_YY:
1526 3 : SetExtDateFormat( XTDATEF_SYSTEM_SHORT_YYYY ); break;
1527 : case XTDATEF_SHORT_DDMMYY:
1528 0 : SetExtDateFormat( XTDATEF_SHORT_DDMMYYYY ); break;
1529 : case XTDATEF_SHORT_MMDDYY:
1530 0 : SetExtDateFormat( XTDATEF_SHORT_MMDDYYYY ); break;
1531 : case XTDATEF_SHORT_YYMMDD:
1532 0 : SetExtDateFormat( XTDATEF_SHORT_YYYYMMDD ); break;
1533 : case XTDATEF_SHORT_YYMMDD_DIN5008:
1534 0 : SetExtDateFormat( XTDATEF_SHORT_YYYYMMDD_DIN5008 ); break;
1535 : default:
1536 : ;
1537 : }
1538 : }
1539 : else
1540 : {
1541 0 : switch ( GetExtDateFormat() )
1542 : {
1543 : case XTDATEF_SYSTEM_SHORT:
1544 : case XTDATEF_SYSTEM_SHORT_YYYY:
1545 0 : SetExtDateFormat( XTDATEF_SYSTEM_SHORT_YY ); break;
1546 : case XTDATEF_SHORT_DDMMYYYY:
1547 0 : SetExtDateFormat( XTDATEF_SHORT_DDMMYY ); break;
1548 : case XTDATEF_SHORT_MMDDYYYY:
1549 0 : SetExtDateFormat( XTDATEF_SHORT_MMDDYY ); break;
1550 : case XTDATEF_SHORT_YYYYMMDD:
1551 0 : SetExtDateFormat( XTDATEF_SHORT_YYMMDD ); break;
1552 : case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1553 0 : SetExtDateFormat( XTDATEF_SHORT_YYMMDD_DIN5008 ); break;
1554 : default:
1555 : ;
1556 : }
1557 : }
1558 :
1559 6 : ReformatAll();
1560 6 : }
1561 :
1562 89 : void DateFormatter::SetDate( const Date& rNewDate )
1563 : {
1564 89 : SetUserDate( rNewDate );
1565 89 : maFieldDate = maLastDate;
1566 89 : maLastDate = GetDate();
1567 89 : }
1568 :
1569 89 : void DateFormatter::SetUserDate( const Date& rNewDate )
1570 : {
1571 89 : ImplSetUserDate( rNewDate );
1572 89 : }
1573 :
1574 99 : void DateFormatter::ImplSetUserDate( const Date& rNewDate, Selection* pNewSelection )
1575 : {
1576 99 : Date aNewDate = rNewDate;
1577 99 : if ( aNewDate > maMax )
1578 15 : aNewDate = maMax;
1579 84 : else if ( aNewDate < maMin )
1580 21 : aNewDate = maMin;
1581 99 : maLastDate = aNewDate;
1582 :
1583 99 : if ( GetField() )
1584 99 : ImplSetText( ImplGetDateAsText( aNewDate, GetFieldSettings() ), pNewSelection );
1585 99 : }
1586 :
1587 10 : void DateFormatter::ImplNewFieldValue( const Date& rDate )
1588 : {
1589 10 : if ( GetField() )
1590 : {
1591 10 : Selection aSelection = GetField()->GetSelection();
1592 10 : aSelection.Justify();
1593 10 : OUString aText = GetField()->GetText();
1594 :
1595 : // If selected until the end then keep it that way
1596 10 : if ( (sal_Int32)aSelection.Max() == aText.getLength() )
1597 : {
1598 10 : if ( !aSelection.Len() )
1599 10 : aSelection.Min() = SELECTION_MAX;
1600 10 : aSelection.Max() = SELECTION_MAX;
1601 : }
1602 :
1603 10 : Date aOldLastDate = maLastDate;
1604 10 : ImplSetUserDate( rDate, &aSelection );
1605 10 : maLastDate = aOldLastDate;
1606 :
1607 : // Modify at Edit is only set at KeyInput
1608 10 : if ( GetField()->GetText() != aText )
1609 : {
1610 10 : GetField()->SetModifyFlag();
1611 10 : GetField()->Modify();
1612 10 : }
1613 : }
1614 10 : }
1615 :
1616 117 : Date DateFormatter::GetDate() const
1617 : {
1618 117 : Date aDate( 0, 0, 0 );
1619 :
1620 117 : if ( GetField() )
1621 : {
1622 117 : if ( ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1623 : {
1624 71 : if ( aDate > maMax )
1625 2 : aDate = maMax;
1626 69 : else if ( aDate < maMin )
1627 0 : aDate = maMin;
1628 : }
1629 : else
1630 : {
1631 : // !!! We should find out why dates are treated differently than other fields (see
1632 : // also bug: 52384)
1633 :
1634 46 : if ( !ImplAllowMalformedInput() )
1635 : {
1636 41 : if ( maLastDate.GetDate() )
1637 41 : aDate = maLastDate;
1638 0 : else if ( !IsEmptyFieldValueEnabled() )
1639 0 : aDate = Date( Date::SYSTEM );
1640 : }
1641 : else
1642 5 : aDate = GetInvalidDate();
1643 : }
1644 : }
1645 :
1646 117 : return aDate;
1647 : }
1648 :
1649 2 : void DateFormatter::SetEmptyDate()
1650 : {
1651 2 : FormatterBase::SetEmptyFieldValue();
1652 2 : }
1653 :
1654 28 : bool DateFormatter::IsEmptyDate() const
1655 : {
1656 28 : bool bEmpty = FormatterBase::IsEmptyFieldValue();
1657 :
1658 28 : if ( GetField() && MustBeReformatted() && IsEmptyFieldValueEnabled() )
1659 : {
1660 24 : if ( GetField()->GetText().isEmpty() )
1661 : {
1662 4 : bEmpty = true;
1663 : }
1664 20 : else if ( !maLastDate.GetDate() )
1665 : {
1666 0 : Date aDate( Date::EMPTY );
1667 0 : bEmpty = !ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() );
1668 : }
1669 : }
1670 28 : return bEmpty;
1671 : }
1672 :
1673 182 : void DateFormatter::Reformat()
1674 : {
1675 182 : if ( !GetField() )
1676 7 : return;
1677 :
1678 182 : if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
1679 7 : return;
1680 :
1681 175 : OUString aStr;
1682 175 : bool bOK = ImplDateReformat( GetField()->GetText(), aStr, GetFieldSettings() );
1683 175 : if( !bOK )
1684 0 : return;
1685 :
1686 175 : if ( !aStr.isEmpty() )
1687 : {
1688 100 : ImplSetText( aStr );
1689 100 : ImplDateGetValue( aStr, maLastDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() );
1690 : }
1691 : else
1692 : {
1693 75 : if ( maLastDate.GetDate() )
1694 35 : SetDate( maLastDate );
1695 40 : else if ( !IsEmptyFieldValueEnabled() )
1696 34 : SetDate( Date( Date::SYSTEM ) );
1697 : else
1698 : {
1699 6 : ImplSetText( OUString() );
1700 6 : SetEmptyFieldValueData( true );
1701 : }
1702 175 : }
1703 : }
1704 :
1705 6 : void DateFormatter::ExpandCentury( Date& rDate )
1706 : {
1707 6 : ExpandCentury( rDate, utl::MiscCfg().GetYear2000() );
1708 6 : }
1709 :
1710 265 : void DateFormatter::ExpandCentury( Date& rDate, sal_uInt16 nTwoDigitYearStart )
1711 : {
1712 265 : sal_uInt16 nDateYear = rDate.GetYear();
1713 265 : if ( nDateYear < 100 )
1714 : {
1715 152 : sal_uInt16 nCentury = nTwoDigitYearStart / 100;
1716 152 : if ( nDateYear < (nTwoDigitYearStart % 100) )
1717 144 : nCentury++;
1718 152 : rDate.SetYear( nDateYear + (nCentury*100) );
1719 : }
1720 265 : }
1721 :
1722 34 : DateField::DateField( vcl::Window* pParent, WinBits nWinStyle ) :
1723 : SpinField( pParent, nWinStyle ),
1724 34 : maFirst( GetMin() ),
1725 68 : maLast( GetMax() )
1726 : {
1727 34 : SetField( this );
1728 34 : SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
1729 34 : Reformat();
1730 34 : ResetLastDate();
1731 34 : }
1732 :
1733 0 : bool DateField::PreNotify( NotifyEvent& rNEvt )
1734 : {
1735 0 : if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && IsStrictFormat() &&
1736 0 : ( GetExtDateFormat() != XTDATEF_SYSTEM_LONG ) &&
1737 0 : !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1738 : {
1739 0 : if ( ImplDateProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetExtDateFormat( true ), ImplGetLocaleDataWrapper() ) )
1740 0 : return true;
1741 : }
1742 :
1743 0 : return SpinField::PreNotify( rNEvt );
1744 : }
1745 :
1746 60 : bool DateField::Notify( NotifyEvent& rNEvt )
1747 : {
1748 60 : if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
1749 0 : MarkToBeReformatted( false );
1750 60 : else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
1751 : {
1752 0 : if ( MustBeReformatted() )
1753 : {
1754 : // !!! We should find out why dates are treated differently than other fields (see
1755 : // also bug: 52384)
1756 :
1757 0 : bool bTextLen = !GetText().isEmpty();
1758 0 : if ( bTextLen || !IsEmptyFieldValueEnabled() )
1759 : {
1760 0 : if ( !ImplAllowMalformedInput() )
1761 0 : Reformat();
1762 : else
1763 : {
1764 0 : Date aDate( 0, 0, 0 );
1765 0 : if ( ImplDateGetValue( GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1766 : // even with strict text analysis, our text is a valid date -> do a complete
1767 : // reformat
1768 0 : Reformat();
1769 : }
1770 : }
1771 0 : else if ( !bTextLen && IsEmptyFieldValueEnabled() )
1772 : {
1773 0 : ResetLastDate();
1774 0 : SetEmptyFieldValueData( true );
1775 : }
1776 : }
1777 : }
1778 :
1779 60 : return SpinField::Notify( rNEvt );
1780 : }
1781 :
1782 314 : void DateField::DataChanged( const DataChangedEvent& rDCEvt )
1783 : {
1784 314 : SpinField::DataChanged( rDCEvt );
1785 :
1786 314 : if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & (AllSettingsFlags::LOCALE|AllSettingsFlags::MISC)) )
1787 : {
1788 0 : if ( IsDefaultLocale() && ( rDCEvt.GetFlags() & AllSettingsFlags::LOCALE ) )
1789 0 : ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
1790 0 : ReformatAll();
1791 : }
1792 314 : }
1793 :
1794 92 : void DateField::Modify()
1795 : {
1796 92 : MarkToBeReformatted( true );
1797 92 : SpinField::Modify();
1798 92 : }
1799 :
1800 4 : void DateField::Up()
1801 : {
1802 4 : ImplDateSpinArea( true );
1803 4 : SpinField::Up();
1804 4 : }
1805 :
1806 2 : void DateField::Down()
1807 : {
1808 2 : ImplDateSpinArea( false );
1809 2 : SpinField::Down();
1810 2 : }
1811 :
1812 2 : void DateField::First()
1813 : {
1814 2 : ImplNewFieldValue( maFirst );
1815 2 : SpinField::First();
1816 2 : }
1817 :
1818 2 : void DateField::Last()
1819 : {
1820 2 : ImplNewFieldValue( maLast );
1821 2 : SpinField::Last();
1822 2 : }
1823 :
1824 0 : DateBox::DateBox( vcl::Window* pParent, WinBits nWinStyle ) :
1825 0 : ComboBox( pParent, nWinStyle )
1826 : {
1827 0 : SetField( this );
1828 0 : SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
1829 0 : Reformat();
1830 0 : }
1831 :
1832 0 : bool DateBox::PreNotify( NotifyEvent& rNEvt )
1833 : {
1834 0 : if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && IsStrictFormat() &&
1835 0 : ( GetExtDateFormat() != XTDATEF_SYSTEM_LONG ) &&
1836 0 : !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1837 : {
1838 0 : if ( ImplDateProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetExtDateFormat( true ), ImplGetLocaleDataWrapper() ) )
1839 0 : return true;
1840 : }
1841 :
1842 0 : return ComboBox::PreNotify( rNEvt );
1843 : }
1844 :
1845 0 : void DateBox::DataChanged( const DataChangedEvent& rDCEvt )
1846 : {
1847 0 : ComboBox::DataChanged( rDCEvt );
1848 :
1849 0 : if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
1850 : {
1851 0 : if ( IsDefaultLocale() )
1852 0 : ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
1853 0 : ReformatAll();
1854 : }
1855 0 : }
1856 :
1857 0 : bool DateBox::Notify( NotifyEvent& rNEvt )
1858 : {
1859 0 : if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
1860 0 : MarkToBeReformatted( false );
1861 0 : else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
1862 : {
1863 0 : if ( MustBeReformatted() )
1864 : {
1865 0 : bool bTextLen = !GetText().isEmpty();
1866 0 : if ( bTextLen || !IsEmptyFieldValueEnabled() )
1867 0 : Reformat();
1868 0 : else if ( !bTextLen && IsEmptyFieldValueEnabled() )
1869 : {
1870 0 : ResetLastDate();
1871 0 : SetEmptyFieldValueData( true );
1872 : }
1873 : }
1874 : }
1875 :
1876 0 : return ComboBox::Notify( rNEvt );
1877 : }
1878 :
1879 0 : void DateBox::Modify()
1880 : {
1881 0 : MarkToBeReformatted( true );
1882 0 : ComboBox::Modify();
1883 0 : }
1884 :
1885 0 : void DateBox::ReformatAll()
1886 : {
1887 0 : OUString aStr;
1888 0 : SetUpdateMode( false );
1889 0 : sal_uInt16 nEntryCount = GetEntryCount();
1890 0 : for ( sal_uInt16 i=0; i < nEntryCount; i++ )
1891 : {
1892 0 : ImplDateReformat( GetEntry( i ), aStr, GetFieldSettings() );
1893 0 : RemoveEntryAt(i);
1894 0 : InsertEntry( aStr, i );
1895 : }
1896 0 : DateFormatter::Reformat();
1897 0 : SetUpdateMode( true );
1898 0 : }
1899 :
1900 0 : static bool ImplTimeProcessKeyInput( Edit*, const KeyEvent& rKEvt,
1901 : bool bStrictFormat, bool bDuration,
1902 : TimeFieldFormat eFormat,
1903 : const LocaleDataWrapper& rLocaleDataWrapper )
1904 : {
1905 0 : sal_Unicode cChar = rKEvt.GetCharCode();
1906 :
1907 0 : if ( !bStrictFormat )
1908 0 : return false;
1909 : else
1910 : {
1911 0 : sal_uInt16 nGroup = rKEvt.GetKeyCode().GetGroup();
1912 0 : if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
1913 0 : (nGroup == KEYGROUP_MISC) ||
1914 0 : ((cChar >= '0') && (cChar <= '9')) ||
1915 0 : string::equals(rLocaleDataWrapper.getTimeSep(), cChar) ||
1916 0 : (rLocaleDataWrapper.getTimeAM().indexOf(cChar) != -1) ||
1917 0 : (rLocaleDataWrapper.getTimePM().indexOf(cChar) != -1) ||
1918 : // Accept AM/PM:
1919 0 : (cChar == 'a') || (cChar == 'A') || (cChar == 'm') || (cChar == 'M') || (cChar == 'p') || (cChar == 'P') ||
1920 0 : ((eFormat == TimeFieldFormat::F_100TH_SEC) && string::equals(rLocaleDataWrapper.getTime100SecSep(), cChar)) ||
1921 0 : ((eFormat == TimeFieldFormat::F_SEC_CS) && string::equals(rLocaleDataWrapper.getTime100SecSep(), cChar)) ||
1922 0 : (bDuration && (cChar == '-')) )
1923 0 : return false;
1924 : else
1925 0 : return true;
1926 : }
1927 : }
1928 :
1929 12 : static bool ImplIsOnlyDigits( const OUStringBuffer& _rStr )
1930 : {
1931 12 : const sal_Unicode* _pChr = _rStr.getStr();
1932 36 : for ( sal_Int32 i = 0; i < _rStr.getLength(); ++i, ++_pChr )
1933 : {
1934 24 : if ( *_pChr < '0' || *_pChr > '9' )
1935 0 : return false;
1936 : }
1937 12 : return true;
1938 : }
1939 :
1940 440 : static bool ImplIsValidTimePortion( bool _bSkipInvalidCharacters, const OUStringBuffer& _rStr )
1941 : {
1942 440 : if ( !_bSkipInvalidCharacters )
1943 : {
1944 12 : if ( ( _rStr.getLength() > 2 ) || _rStr.isEmpty() || !ImplIsOnlyDigits( _rStr ) )
1945 0 : return false;
1946 : }
1947 440 : return true;
1948 : }
1949 :
1950 440 : static bool ImplCutTimePortion( OUStringBuffer& _rStr, sal_Int32 _nSepPos, bool _bSkipInvalidCharacters, short* _pPortion )
1951 : {
1952 440 : OUString sPortion(_rStr.getStr(), _nSepPos );
1953 880 : _rStr = _nSepPos < _rStr.getLength()
1954 440 : ? _rStr.copy( _nSepPos + 1 ) : OUStringBuffer();
1955 :
1956 440 : if ( !ImplIsValidTimePortion( _bSkipInvalidCharacters, sPortion ) )
1957 0 : return false;
1958 440 : *_pPortion = (short)sPortion.toInt32();
1959 440 : return true;
1960 : }
1961 :
1962 364 : static bool ImplTimeGetValue( const OUString& rStr, tools::Time& rTime,
1963 : TimeFieldFormat eFormat, bool bDuration,
1964 : const LocaleDataWrapper& rLocaleDataWrapper, bool _bSkipInvalidCharacters = true )
1965 : {
1966 364 : OUStringBuffer aStr = rStr;
1967 364 : short nHour = 0;
1968 364 : short nMinute = 0;
1969 364 : short nSecond = 0;
1970 364 : sal_Int64 nNanoSec = 0;
1971 364 : tools::Time aTime( 0, 0, 0 );
1972 :
1973 364 : if ( rStr.isEmpty() )
1974 12 : return false;
1975 :
1976 : // Search for separators
1977 352 : if (!rLocaleDataWrapper.getTimeSep().isEmpty())
1978 : {
1979 352 : OUStringBuffer aSepStr(",.;:/");
1980 352 : if ( !bDuration )
1981 341 : aSepStr.append('-');
1982 :
1983 : // Replace characters above by the separator character
1984 2453 : for (sal_Int32 i = 0; i < aSepStr.getLength(); ++i)
1985 : {
1986 2101 : if (string::equals(rLocaleDataWrapper.getTimeSep(), aSepStr[i]))
1987 352 : continue;
1988 12786 : for ( sal_Int32 j = 0; j < aStr.getLength(); j++ )
1989 : {
1990 11037 : if (aStr[j] == aSepStr[i])
1991 0 : aStr[j] = rLocaleDataWrapper.getTimeSep()[0];
1992 : }
1993 352 : }
1994 : }
1995 :
1996 352 : bool bNegative = false;
1997 352 : sal_Int32 nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
1998 352 : if ( aStr[0] == '-' )
1999 0 : bNegative = true;
2000 352 : if ( eFormat != TimeFieldFormat::F_SEC_CS )
2001 : {
2002 352 : if ( nSepPos < 0 )
2003 16 : nSepPos = aStr.getLength();
2004 352 : if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nHour ) )
2005 0 : return false;
2006 :
2007 352 : nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2008 352 : if ( !aStr.isEmpty() && aStr[0] == '-' )
2009 0 : bNegative = true;
2010 352 : if ( nSepPos >= 0 )
2011 : {
2012 88 : if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nMinute ) )
2013 0 : return false;
2014 :
2015 88 : nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2016 88 : if ( !aStr.isEmpty() && aStr[0] == '-' )
2017 0 : bNegative = true;
2018 88 : if ( nSepPos >= 0 )
2019 : {
2020 0 : if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nSecond ) )
2021 0 : return false;
2022 0 : if ( !aStr.isEmpty() && aStr[0] == '-' )
2023 0 : bNegative = true;
2024 0 : nNanoSec = aStr.toString().toInt64();
2025 : }
2026 : else
2027 88 : nSecond = (short)aStr.toString().toInt32();
2028 : }
2029 : else
2030 264 : nMinute = (short)aStr.toString().toInt32();
2031 : }
2032 0 : else if ( nSepPos < 0 )
2033 : {
2034 0 : nSecond = (short)aStr.toString().toInt32();
2035 0 : nMinute += nSecond / 60;
2036 0 : nSecond %= 60;
2037 0 : nHour += nMinute / 60;
2038 0 : nMinute %= 60;
2039 : }
2040 : else
2041 : {
2042 0 : nSecond = (short)aStr.copy( 0, nSepPos ).toString().toInt32();
2043 0 : aStr.remove( 0, nSepPos+1 );
2044 :
2045 0 : nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2046 0 : if ( !aStr.isEmpty() && aStr[0] == '-' )
2047 0 : bNegative = true;
2048 0 : if ( nSepPos >= 0 )
2049 : {
2050 0 : nMinute = nSecond;
2051 0 : nSecond = (short)aStr.copy( 0, nSepPos ).toString().toInt32();
2052 0 : aStr.remove( 0, nSepPos+1 );
2053 :
2054 0 : nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2055 0 : if ( !aStr.isEmpty() && aStr[0] == '-' )
2056 0 : bNegative = true;
2057 0 : if ( nSepPos >= 0 )
2058 : {
2059 0 : nHour = nMinute;
2060 0 : nMinute = nSecond;
2061 0 : nSecond = (short)aStr.copy( 0, nSepPos ).toString().toInt32();
2062 0 : aStr.remove( 0, nSepPos+1 );
2063 : }
2064 : else
2065 : {
2066 0 : nHour += nMinute / 60;
2067 0 : nMinute %= 60;
2068 : }
2069 : }
2070 : else
2071 : {
2072 0 : nMinute += nSecond / 60;
2073 0 : nSecond %= 60;
2074 0 : nHour += nMinute / 60;
2075 0 : nMinute %= 60;
2076 : }
2077 0 : nNanoSec = aStr.toString().toInt64();
2078 : }
2079 :
2080 352 : if ( nNanoSec )
2081 : {
2082 : assert(aStr.getLength() >= 1);
2083 :
2084 0 : sal_Int32 nLen = 1; // at least one digit, otherwise nNanoSec==0
2085 :
2086 0 : while ( aStr.getLength() > nLen && aStr[nLen] >= '0' && aStr[nLen] <= '9' )
2087 0 : nLen++;
2088 :
2089 0 : while ( nLen < 9)
2090 : {
2091 0 : nNanoSec *= 10;
2092 0 : ++nLen;
2093 : }
2094 0 : while ( nLen > 9 )
2095 : {
2096 : // round if negative?
2097 0 : nNanoSec = (nNanoSec + 5) / 10;
2098 0 : --nLen;
2099 : }
2100 : }
2101 :
2102 : assert(nNanoSec > -1000000000 && nNanoSec < 1000000000);
2103 352 : if ( (nMinute > 59) || (nSecond > 59) || (nNanoSec > 1000000000) )
2104 0 : return false;
2105 :
2106 352 : if ( eFormat == TimeFieldFormat::F_NONE )
2107 255 : nSecond = nNanoSec = 0;
2108 97 : else if ( eFormat == TimeFieldFormat::F_SEC )
2109 97 : nNanoSec = 0;
2110 :
2111 352 : if ( !bDuration )
2112 : {
2113 682 : if ( bNegative || (nHour < 0) || (nMinute < 0) ||
2114 682 : (nSecond < 0) || (nNanoSec < 0) )
2115 0 : return false;
2116 :
2117 341 : OUString aUpperCaseStr = aStr.toString().toAsciiUpperCase();
2118 682 : OUString aAM(rLocaleDataWrapper.getTimeAM().toAsciiUpperCase());
2119 682 : OUString aPM(rLocaleDataWrapper.getTimePM().toAsciiUpperCase());
2120 682 : OUString aAM2("AM"); // aAM is localized
2121 682 : OUString aPM2("PM"); // aPM is localized
2122 :
2123 341 : if ( (nHour < 12) && ( ( aUpperCaseStr.indexOf( aPM ) >= 0 ) || ( aUpperCaseStr.indexOf( aPM2 ) >= 0 ) ) )
2124 0 : nHour += 12;
2125 :
2126 341 : if ( (nHour == 12) && ( ( aUpperCaseStr.indexOf( aAM ) >= 0 ) || ( aUpperCaseStr.indexOf( aAM2 ) >= 0 ) ) )
2127 0 : nHour = 0;
2128 :
2129 682 : aTime = tools::Time( (sal_uInt16)nHour, (sal_uInt16)nMinute, (sal_uInt16)nSecond,
2130 682 : (sal_uInt32)nNanoSec );
2131 : }
2132 : else
2133 : {
2134 : assert( !bNegative || (nHour < 0) || (nMinute < 0) ||
2135 : (nSecond < 0) || (nNanoSec < 0) );
2136 22 : if ( bNegative || (nHour < 0) || (nMinute < 0) ||
2137 22 : (nSecond < 0) || (nNanoSec < 0) )
2138 : {
2139 : // LEM TODO: this looks weird... I think buggy when parsing "05:-02:18"
2140 0 : bNegative = true;
2141 0 : nHour = nHour < 0 ? -nHour : nHour;
2142 0 : nMinute = nMinute < 0 ? -nMinute : nMinute;
2143 0 : nSecond = nSecond < 0 ? -nSecond : nSecond;
2144 0 : nNanoSec = nNanoSec < 0 ? -nNanoSec : nNanoSec;
2145 : }
2146 :
2147 22 : aTime = tools::Time( (sal_uInt16)nHour, (sal_uInt16)nMinute, (sal_uInt16)nSecond,
2148 11 : (sal_uInt32)nNanoSec );
2149 11 : if ( bNegative )
2150 0 : aTime = -aTime;
2151 : }
2152 :
2153 352 : rTime = aTime;
2154 :
2155 352 : return true;
2156 : }
2157 :
2158 162 : bool TimeFormatter::ImplTimeReformat( const OUString& rStr, OUString& rOutStr )
2159 : {
2160 162 : tools::Time aTime( 0, 0, 0 );
2161 162 : if ( !ImplTimeGetValue( rStr, aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() ) )
2162 10 : return true;
2163 :
2164 152 : tools::Time aTempTime = aTime;
2165 152 : if ( aTempTime > GetMax() )
2166 0 : aTempTime = GetMax() ;
2167 152 : else if ( aTempTime < GetMin() )
2168 23 : aTempTime = GetMin();
2169 :
2170 152 : if ( GetErrorHdl().IsSet() && (aTime != aTempTime) )
2171 : {
2172 0 : maCorrectedTime = aTempTime;
2173 0 : if ( !GetErrorHdl().Call( this ) )
2174 : {
2175 0 : maCorrectedTime = tools::Time( tools::Time::SYSTEM );
2176 0 : return false;
2177 : }
2178 : else
2179 0 : maCorrectedTime = tools::Time( tools::Time::SYSTEM );
2180 : }
2181 :
2182 152 : bool bSecond = false;
2183 152 : bool b100Sec = false;
2184 152 : if ( meFormat != TimeFieldFormat::F_NONE )
2185 44 : bSecond = true;
2186 152 : if ( meFormat == TimeFieldFormat::F_100TH_SEC )
2187 0 : b100Sec = true;
2188 :
2189 152 : if ( meFormat == TimeFieldFormat::F_SEC_CS )
2190 : {
2191 0 : sal_uLong n = aTempTime.GetHour() * 3600L;
2192 0 : n += aTempTime.GetMin() * 60L;
2193 0 : n += aTempTime.GetSec();
2194 0 : rOutStr = OUString::number( n );
2195 0 : rOutStr += ImplGetLocaleDataWrapper().getTime100SecSep();
2196 0 : std::ostringstream ostr;
2197 0 : ostr.fill('0');
2198 0 : ostr.width(9);
2199 0 : ostr << aTempTime.GetNanoSec();
2200 0 : rOutStr += OUString::createFromAscii(ostr.str().c_str());
2201 : }
2202 152 : else if ( mbDuration )
2203 5 : rOutStr = ImplGetLocaleDataWrapper().getDuration( aTempTime, bSecond, b100Sec );
2204 : else
2205 : {
2206 147 : rOutStr = ImplGetLocaleDataWrapper().getTime( aTempTime, bSecond, b100Sec );
2207 147 : if ( GetTimeFormat() == HOUR_12 )
2208 : {
2209 46 : if ( aTempTime.GetHour() > 12 )
2210 : {
2211 0 : tools::Time aT( aTempTime );
2212 0 : aT.SetHour( aT.GetHour() % 12 );
2213 0 : rOutStr = ImplGetLocaleDataWrapper().getTime( aT, bSecond, b100Sec );
2214 : }
2215 : // Don't use LocaleDataWrapper, we want AM/PM
2216 46 : if ( aTempTime.GetHour() < 12 )
2217 46 : rOutStr += "AM"; // ImplGetLocaleDataWrapper().getTimeAM();
2218 : else
2219 0 : rOutStr += "PM"; // ImplGetLocaleDataWrapper().getTimePM();
2220 : }
2221 : }
2222 :
2223 152 : return true;
2224 : }
2225 50 : bool TimeFormatter::ImplAllowMalformedInput() const
2226 : {
2227 50 : return !IsEnforceValidValue();
2228 : }
2229 :
2230 6 : void TimeField::ImplTimeSpinArea( bool bUp )
2231 : {
2232 6 : if ( GetField() )
2233 : {
2234 6 : sal_Int32 nTimeArea = 0;
2235 6 : tools::Time aTime( GetTime() );
2236 6 : OUString aText( GetText() );
2237 6 : Selection aSelection( GetField()->GetSelection() );
2238 :
2239 : // Area search
2240 6 : if ( GetFormat() != TimeFieldFormat::F_SEC_CS )
2241 : {
2242 : //Which area is the cursor in of HH:MM:SS.TT
2243 10 : for ( sal_Int32 i = 1, nPos = 0; i <= 4; i++ )
2244 : {
2245 10 : sal_Int32 nPos1 = aText.indexOf( ImplGetLocaleDataWrapper().getTimeSep(), nPos );
2246 10 : sal_Int32 nPos2 = aText.indexOf( ImplGetLocaleDataWrapper().getTime100SecSep(), nPos );
2247 : //which ever comes first, bearing in mind that one might not be there
2248 10 : if (nPos1 >= 0 && nPos2 >= 0)
2249 0 : nPos = nPos1 < nPos2 ? nPos1 : nPos2;
2250 10 : else if (nPos1 >= 0)
2251 4 : nPos = nPos1;
2252 : else
2253 6 : nPos = nPos2;
2254 10 : if ( nPos < 0 || nPos >= aSelection.Max() )
2255 : {
2256 6 : nTimeArea = i;
2257 6 : break;
2258 : }
2259 : else
2260 4 : nPos++;
2261 : }
2262 : }
2263 : else
2264 : {
2265 0 : sal_Int32 nPos = aText.indexOf( ImplGetLocaleDataWrapper().getTime100SecSep() );
2266 0 : if ( nPos < 0 || nPos >= aSelection.Max() )
2267 0 : nTimeArea = 3;
2268 : else
2269 0 : nTimeArea = 4;
2270 : }
2271 :
2272 6 : if ( nTimeArea )
2273 : {
2274 6 : tools::Time aAddTime( 0, 0, 0 );
2275 6 : if ( nTimeArea == 1 )
2276 2 : aAddTime = tools::Time( 1, 0 );
2277 4 : else if ( nTimeArea == 2 )
2278 4 : aAddTime = tools::Time( 0, 1 );
2279 0 : else if ( nTimeArea == 3 )
2280 0 : aAddTime = tools::Time( 0, 0, 1 );
2281 0 : else if ( nTimeArea == 4 )
2282 0 : aAddTime = tools::Time( 0, 0, 0, 1 );
2283 :
2284 6 : if ( !bUp )
2285 2 : aAddTime = -aAddTime;
2286 :
2287 6 : aTime += aAddTime;
2288 6 : if ( !IsDuration() )
2289 : {
2290 6 : tools::Time aAbsMaxTime( 23, 59, 59, 999999999 );
2291 6 : if ( aTime > aAbsMaxTime )
2292 0 : aTime = aAbsMaxTime;
2293 6 : tools::Time aAbsMinTime( 0, 0 );
2294 6 : if ( aTime < aAbsMinTime )
2295 0 : aTime = aAbsMinTime;
2296 : }
2297 6 : ImplNewFieldValue( aTime );
2298 6 : }
2299 :
2300 : }
2301 6 : }
2302 :
2303 18 : void TimeFormatter::ImplInit()
2304 : {
2305 18 : meFormat = TimeFieldFormat::F_NONE;
2306 18 : mbDuration = false;
2307 18 : mnTimeFormat = HOUR_24; // Should become a ExtTimeFieldFormat in next implementation, merge with mbDuration and meFormat
2308 18 : }
2309 :
2310 18 : TimeFormatter::TimeFormatter() :
2311 : maLastTime( 0, 0 ),
2312 : maMin( 0, 0 ),
2313 : maMax( 23, 59, 59, 999999999 ),
2314 : maCorrectedTime( tools::Time::SYSTEM ),
2315 : mbEnforceValidValue( true ),
2316 18 : maFieldTime( 0, 0 )
2317 : {
2318 18 : ImplInit();
2319 18 : }
2320 :
2321 0 : TimeFormatter::~TimeFormatter()
2322 : {
2323 0 : }
2324 :
2325 149 : void TimeFormatter::ReformatAll()
2326 : {
2327 149 : Reformat();
2328 149 : }
2329 :
2330 30 : void TimeFormatter::SetMin( const tools::Time& rNewMin )
2331 : {
2332 30 : maMin = rNewMin;
2333 30 : if ( !IsEmptyFieldValue() )
2334 30 : ReformatAll();
2335 30 : }
2336 :
2337 30 : void TimeFormatter::SetMax( const tools::Time& rNewMax )
2338 : {
2339 30 : maMax = rNewMax;
2340 30 : if ( !IsEmptyFieldValue() )
2341 30 : ReformatAll();
2342 30 : }
2343 :
2344 25 : void TimeFormatter::SetTimeFormat( TimeFormatter::TimeFormat eNewFormat )
2345 : {
2346 25 : mnTimeFormat = sal::static_int_cast<sal_uInt16>(eNewFormat);
2347 25 : }
2348 :
2349 :
2350 26 : void TimeFormatter::SetFormat( TimeFieldFormat eNewFormat )
2351 : {
2352 26 : meFormat = eNewFormat;
2353 26 : ReformatAll();
2354 26 : }
2355 :
2356 26 : void TimeFormatter::SetDuration( bool bNewDuration )
2357 : {
2358 26 : mbDuration = bNewDuration;
2359 26 : ReformatAll();
2360 26 : }
2361 :
2362 16 : void TimeFormatter::SetTime( const tools::Time& rNewTime )
2363 : {
2364 16 : SetUserTime( rNewTime );
2365 16 : maFieldTime = maLastTime;
2366 16 : SetEmptyFieldValueData( false );
2367 16 : }
2368 :
2369 10 : void TimeFormatter::ImplNewFieldValue( const tools::Time& rTime )
2370 : {
2371 10 : if ( GetField() )
2372 : {
2373 10 : Selection aSelection = GetField()->GetSelection();
2374 10 : aSelection.Justify();
2375 10 : OUString aText = GetField()->GetText();
2376 :
2377 : // If selected until the end then keep it that way
2378 10 : if ( (sal_Int32)aSelection.Max() == aText.getLength() )
2379 : {
2380 10 : if ( !aSelection.Len() )
2381 10 : aSelection.Min() = SELECTION_MAX;
2382 10 : aSelection.Max() = SELECTION_MAX;
2383 : }
2384 :
2385 10 : tools::Time aOldLastTime = maLastTime;
2386 10 : ImplSetUserTime( rTime, &aSelection );
2387 10 : maLastTime = aOldLastTime;
2388 :
2389 : // Modify at Edit is only set at KeyInput
2390 10 : if ( GetField()->GetText() != aText )
2391 : {
2392 8 : GetField()->SetModifyFlag();
2393 8 : GetField()->Modify();
2394 10 : }
2395 : }
2396 10 : }
2397 :
2398 52 : void TimeFormatter::ImplSetUserTime( const tools::Time& rNewTime, Selection* pNewSelection )
2399 : {
2400 52 : tools::Time aNewTime = rNewTime;
2401 52 : if ( aNewTime > GetMax() )
2402 4 : aNewTime = GetMax();
2403 48 : else if ( aNewTime < GetMin() )
2404 0 : aNewTime = GetMin();
2405 52 : maLastTime = aNewTime;
2406 :
2407 52 : if ( GetField() )
2408 : {
2409 52 : OUString aStr;
2410 52 : bool bSec = false;
2411 52 : bool b100Sec = false;
2412 52 : if ( meFormat != TimeFieldFormat::F_NONE )
2413 11 : bSec = true;
2414 52 : if ( meFormat == TimeFieldFormat::F_100TH_SEC || meFormat == TimeFieldFormat::F_SEC_CS )
2415 0 : b100Sec = true;
2416 52 : if ( meFormat == TimeFieldFormat::F_SEC_CS )
2417 : {
2418 0 : sal_uLong n = aNewTime.GetHour() * 3600L;
2419 0 : n += aNewTime.GetMin() * 60L;
2420 0 : n += aNewTime.GetSec();
2421 0 : aStr = OUString::number( n );
2422 0 : aStr += ImplGetLocaleDataWrapper().getTime100SecSep();
2423 0 : std::ostringstream ostr;
2424 0 : ostr.fill('0');
2425 0 : ostr.width(9);
2426 0 : ostr << aNewTime.GetNanoSec();
2427 0 : aStr += OUString::createFromAscii(ostr.str().c_str());
2428 : }
2429 52 : else if ( mbDuration )
2430 : {
2431 1 : aStr = ImplGetLocaleDataWrapper().getDuration( aNewTime, bSec, b100Sec );
2432 : }
2433 : else
2434 : {
2435 51 : aStr = ImplGetLocaleDataWrapper().getTime( aNewTime, bSec, b100Sec );
2436 51 : if ( GetTimeFormat() == HOUR_12 )
2437 : {
2438 11 : if ( aNewTime.GetHour() > 12 )
2439 : {
2440 0 : tools::Time aT( aNewTime );
2441 0 : aT.SetHour( aT.GetHour() % 12 );
2442 0 : aStr = ImplGetLocaleDataWrapper().getTime( aT, bSec, b100Sec );
2443 : }
2444 : // Don't use LocaleDataWrapper, we want AM/PM
2445 11 : if ( aNewTime.GetHour() < 12 )
2446 11 : aStr += "AM"; // ImplGetLocaleDataWrapper().getTimeAM();
2447 : else
2448 0 : aStr += "PM"; // ImplGetLocaleDataWrapper().getTimePM();
2449 : }
2450 : }
2451 :
2452 52 : ImplSetText( aStr, pNewSelection );
2453 : }
2454 52 : }
2455 :
2456 42 : void TimeFormatter::SetUserTime( const tools::Time& rNewTime )
2457 : {
2458 42 : ImplSetUserTime( rNewTime );
2459 42 : }
2460 :
2461 50 : tools::Time TimeFormatter::GetTime() const
2462 : {
2463 50 : tools::Time aTime( 0, 0, 0 );
2464 :
2465 50 : if ( GetField() )
2466 : {
2467 50 : bool bAllowMailformed = ImplAllowMalformedInput();
2468 50 : if ( ImplTimeGetValue( GetField()->GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), !bAllowMailformed ) )
2469 : {
2470 48 : if ( aTime > GetMax() )
2471 0 : aTime = GetMax();
2472 48 : else if ( aTime < GetMin() )
2473 0 : aTime = GetMin();
2474 : }
2475 : else
2476 : {
2477 2 : if ( bAllowMailformed )
2478 0 : aTime = GetInvalidTime();
2479 : else
2480 2 : aTime = maLastTime;
2481 : }
2482 : }
2483 :
2484 50 : return aTime;
2485 : }
2486 :
2487 167 : void TimeFormatter::Reformat()
2488 : {
2489 167 : if ( !GetField() )
2490 5 : return;
2491 :
2492 167 : if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
2493 5 : return;
2494 :
2495 162 : OUString aStr;
2496 162 : bool bOK = ImplTimeReformat( GetField()->GetText(), aStr );
2497 162 : if ( !bOK )
2498 0 : return;
2499 :
2500 162 : if ( !aStr.isEmpty() )
2501 : {
2502 152 : ImplSetText( aStr );
2503 152 : ImplTimeGetValue( aStr, maLastTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() );
2504 : }
2505 : else
2506 10 : SetTime( maLastTime );
2507 : }
2508 :
2509 18 : TimeField::TimeField( vcl::Window* pParent, WinBits nWinStyle ) :
2510 : SpinField( pParent, nWinStyle ),
2511 18 : maFirst( GetMin() ),
2512 36 : maLast( GetMax() )
2513 : {
2514 18 : SetField( this );
2515 18 : SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, false, false ) );
2516 18 : Reformat();
2517 18 : }
2518 :
2519 0 : bool TimeField::PreNotify( NotifyEvent& rNEvt )
2520 : {
2521 0 : if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
2522 : {
2523 0 : if ( ImplTimeProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
2524 0 : return true;
2525 : }
2526 :
2527 0 : return SpinField::PreNotify( rNEvt );
2528 : }
2529 :
2530 19 : bool TimeField::Notify( NotifyEvent& rNEvt )
2531 : {
2532 19 : if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
2533 0 : MarkToBeReformatted( false );
2534 19 : else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
2535 : {
2536 0 : if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
2537 : {
2538 0 : if ( !ImplAllowMalformedInput() )
2539 0 : Reformat();
2540 : else
2541 : {
2542 0 : tools::Time aTime( 0, 0, 0 );
2543 0 : if ( ImplTimeGetValue( GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), false ) )
2544 : // even with strict text analysis, our text is a valid time -> do a complete
2545 : // reformat
2546 0 : Reformat();
2547 : }
2548 : }
2549 : }
2550 :
2551 19 : return SpinField::Notify( rNEvt );
2552 : }
2553 :
2554 292 : void TimeField::DataChanged( const DataChangedEvent& rDCEvt )
2555 : {
2556 292 : SpinField::DataChanged( rDCEvt );
2557 :
2558 292 : if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
2559 : {
2560 0 : if ( IsDefaultLocale() )
2561 0 : ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
2562 0 : ReformatAll();
2563 : }
2564 292 : }
2565 :
2566 58 : void TimeField::Modify()
2567 : {
2568 58 : MarkToBeReformatted( true );
2569 58 : SpinField::Modify();
2570 58 : }
2571 :
2572 4 : void TimeField::Up()
2573 : {
2574 4 : ImplTimeSpinArea( true );
2575 4 : SpinField::Up();
2576 4 : }
2577 :
2578 2 : void TimeField::Down()
2579 : {
2580 2 : ImplTimeSpinArea( false );
2581 2 : SpinField::Down();
2582 2 : }
2583 :
2584 2 : void TimeField::First()
2585 : {
2586 2 : ImplNewFieldValue( maFirst );
2587 2 : SpinField::First();
2588 2 : }
2589 :
2590 2 : void TimeField::Last()
2591 : {
2592 2 : ImplNewFieldValue( maLast );
2593 2 : SpinField::Last();
2594 2 : }
2595 :
2596 26 : void TimeField::SetExtFormat( ExtTimeFieldFormat eFormat )
2597 : {
2598 26 : switch ( eFormat )
2599 : {
2600 : case EXTTIMEF_24H_SHORT:
2601 : {
2602 10 : SetTimeFormat( HOUR_24 );
2603 10 : SetDuration( false );
2604 10 : SetFormat( TimeFieldFormat::F_NONE );
2605 : }
2606 10 : break;
2607 : case EXTTIMEF_24H_LONG:
2608 : {
2609 6 : SetTimeFormat( HOUR_24 );
2610 6 : SetDuration( false );
2611 6 : SetFormat( TimeFieldFormat::F_SEC );
2612 : }
2613 6 : break;
2614 : case EXTTIMEF_12H_SHORT:
2615 : {
2616 6 : SetTimeFormat( HOUR_12 );
2617 6 : SetDuration( false );
2618 6 : SetFormat( TimeFieldFormat::F_NONE );
2619 : }
2620 6 : break;
2621 : case EXTTIMEF_12H_LONG:
2622 : {
2623 3 : SetTimeFormat( HOUR_12 );
2624 3 : SetDuration( false );
2625 3 : SetFormat( TimeFieldFormat::F_SEC );
2626 : }
2627 3 : break;
2628 : case EXTTIMEF_DURATION_SHORT:
2629 : {
2630 1 : SetDuration( true );
2631 1 : SetFormat( TimeFieldFormat::F_NONE );
2632 : }
2633 1 : break;
2634 : case EXTTIMEF_DURATION_LONG:
2635 : {
2636 0 : SetDuration( true );
2637 0 : SetFormat( TimeFieldFormat::F_SEC );
2638 : }
2639 0 : break;
2640 : default: OSL_FAIL( "ExtTimeFieldFormat unknown!" );
2641 : }
2642 :
2643 26 : if ( GetField() && !GetField()->GetText().isEmpty() )
2644 26 : SetUserTime( GetTime() );
2645 26 : ReformatAll();
2646 26 : }
2647 :
2648 0 : TimeBox::TimeBox( vcl::Window* pParent, WinBits nWinStyle ) :
2649 0 : ComboBox( pParent, nWinStyle )
2650 : {
2651 0 : SetField( this );
2652 0 : SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, false, false ) );
2653 0 : Reformat();
2654 0 : }
2655 :
2656 0 : bool TimeBox::PreNotify( NotifyEvent& rNEvt )
2657 : {
2658 0 : if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
2659 : {
2660 0 : if ( ImplTimeProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
2661 0 : return true;
2662 : }
2663 :
2664 0 : return ComboBox::PreNotify( rNEvt );
2665 : }
2666 :
2667 0 : bool TimeBox::Notify( NotifyEvent& rNEvt )
2668 : {
2669 0 : if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
2670 0 : MarkToBeReformatted( false );
2671 0 : else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
2672 : {
2673 0 : if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
2674 0 : Reformat();
2675 : }
2676 :
2677 0 : return ComboBox::Notify( rNEvt );
2678 : }
2679 :
2680 0 : void TimeBox::DataChanged( const DataChangedEvent& rDCEvt )
2681 : {
2682 0 : ComboBox::DataChanged( rDCEvt );
2683 :
2684 0 : if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
2685 : {
2686 0 : if ( IsDefaultLocale() )
2687 0 : ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
2688 0 : ReformatAll();
2689 : }
2690 0 : }
2691 :
2692 0 : void TimeBox::Modify()
2693 : {
2694 0 : MarkToBeReformatted( true );
2695 0 : ComboBox::Modify();
2696 0 : }
2697 :
2698 0 : void TimeBox::ReformatAll()
2699 : {
2700 0 : OUString aStr;
2701 0 : SetUpdateMode( false );
2702 0 : sal_uInt16 nEntryCount = GetEntryCount();
2703 0 : for ( sal_uInt16 i=0; i < nEntryCount; i++ )
2704 : {
2705 0 : ImplTimeReformat( GetEntry( i ), aStr );
2706 0 : RemoveEntryAt(i);
2707 0 : InsertEntry( aStr, i );
2708 : }
2709 0 : TimeFormatter::Reformat();
2710 0 : SetUpdateMode( true );
2711 801 : }
2712 :
2713 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|