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 0 : uno::Reference< i18n::XCharacterClassification > ImplGetCharClass()
61 : {
62 0 : static uno::Reference< i18n::XCharacterClassification > xCharClass;
63 0 : if ( !xCharClass.is() )
64 0 : xCharClass = vcl::unohelper::CreateCharacterClassification();
65 :
66 0 : return xCharClass;
67 : }
68 :
69 0 : static sal_Unicode* ImplAddString( sal_Unicode* pBuf, const OUString& rStr )
70 : {
71 0 : if ( rStr.getLength() == 1 )
72 0 : *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 0 : return pBuf;
81 : }
82 :
83 0 : 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 0 : sal_Unicode* pTempBuf = aTempBuf;
88 0 : do
89 : {
90 0 : *pTempBuf = (sal_Unicode)(nNumber % 10) + '0';
91 0 : pTempBuf++;
92 0 : nNumber /= 10;
93 0 : if ( nMinLen )
94 0 : nMinLen--;
95 : }
96 : while ( nNumber );
97 :
98 : // fill with zeros up to the minimal length
99 0 : while ( nMinLen > 0 )
100 : {
101 0 : *pBuf = '0';
102 0 : pBuf++;
103 0 : nMinLen--;
104 : }
105 :
106 : // copy temp buffer to real buffer
107 0 : do
108 : {
109 0 : pTempBuf--;
110 0 : *pBuf = *pTempBuf;
111 0 : pBuf++;
112 : }
113 : while ( pTempBuf != aTempBuf );
114 :
115 0 : return pBuf;
116 : }
117 :
118 0 : static sal_uInt16 ImplGetNum( const sal_Unicode*& rpBuf, bool& rbError )
119 : {
120 0 : if ( !*rpBuf )
121 : {
122 0 : rbError = true;
123 0 : return 0;
124 : }
125 :
126 0 : sal_uInt16 nNumber = 0;
127 0 : while( ( *rpBuf >= '0' ) && ( *rpBuf <= '9' ) )
128 : {
129 0 : nNumber *= 10;
130 0 : nNumber += *rpBuf - '0';
131 0 : rpBuf++;
132 : }
133 :
134 0 : return nNumber;
135 : }
136 :
137 0 : static void ImplSkipDelimiters( const sal_Unicode*& rpBuf )
138 : {
139 0 : while( ( *rpBuf == ',' ) || ( *rpBuf == '.' ) || ( *rpBuf == ';' ) ||
140 0 : ( *rpBuf == ':' ) || ( *rpBuf == '-' ) || ( *rpBuf == '/' ) )
141 : {
142 0 : rpBuf++;
143 : }
144 0 : }
145 :
146 0 : static bool ImplIsPatternChar( sal_Unicode cChar, sal_Char cEditMask )
147 : {
148 0 : sal_Int32 nType = 0;
149 :
150 : try
151 : {
152 0 : OUString aCharStr(cChar);
153 0 : nType = ImplGetCharClass()->getStringType( aCharStr, 0, aCharStr.getLength(),
154 0 : 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 0 : if ( (cEditMask == EDITMASK_ALPHA) || (cEditMask == EDITMASK_UPPERALPHA) )
164 : {
165 0 : if( !CharClass::isLetterType( nType ) )
166 0 : return false;
167 : }
168 0 : else if ( cEditMask == EDITMASK_NUM )
169 : {
170 0 : if( !CharClass::isNumericType( nType ) )
171 0 : return false;
172 : }
173 0 : else if ( (cEditMask == EDITMASK_ALPHANUM) || (cEditMask == EDITMASK_UPPERALPHANUM) )
174 : {
175 0 : if( !CharClass::isLetterNumericType( nType ) )
176 0 : return false;
177 : }
178 0 : else if ( (cEditMask == EDITMASK_ALLCHAR) || (cEditMask == EDITMASK_UPPERALLCHAR) )
179 : {
180 0 : if ( cChar < 32 )
181 0 : return false;
182 : }
183 0 : else if ( cEditMask == EDITMASK_NUMSPACE )
184 : {
185 0 : if ( !CharClass::isNumericType( nType ) && ( cChar != ' ' ) )
186 0 : return false;
187 : }
188 : else
189 0 : return false;
190 :
191 0 : return true;
192 : }
193 :
194 0 : static sal_Unicode ImplPatternChar( sal_Unicode cChar, sal_Char cEditMask )
195 : {
196 0 : if ( ImplIsPatternChar( cChar, cEditMask ) )
197 : {
198 0 : if ( (cEditMask == EDITMASK_UPPERALPHA) ||
199 0 : (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 0 : return cChar;
206 : }
207 : else
208 0 : 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 0 : static OUString ImplPatternReformat( const OUString& rStr,
223 : const OString& rEditMask,
224 : const OUString& rLiteralMask,
225 : sal_uInt16 nFormatFlags )
226 : {
227 0 : if (rEditMask.isEmpty())
228 0 : return rStr;
229 :
230 0 : OUString aStr = rStr;
231 0 : OUStringBuffer aOutStr = OUString(rLiteralMask);
232 : sal_Unicode cTempChar;
233 : sal_Unicode cChar;
234 : sal_Unicode cLiteral;
235 : sal_Char cMask;
236 0 : sal_Int32 nStrIndex = 0;
237 0 : sal_Int32 i = 0;
238 : sal_Int32 n;
239 :
240 0 : while ( i < rEditMask.getLength() )
241 : {
242 0 : if ( nStrIndex >= aStr.getLength() )
243 0 : break;
244 :
245 0 : cChar = aStr[nStrIndex];
246 0 : cLiteral = rLiteralMask[i];
247 0 : cMask = rEditMask[i];
248 :
249 : // current position is a literal
250 0 : 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 0 : cTempChar = ImplPatternChar( cChar, cMask );
278 0 : if ( cTempChar )
279 : {
280 : // use this character
281 0 : aOutStr[i] = cTempChar;
282 0 : nStrIndex++;
283 : }
284 : else
285 : {
286 : // copy if it is a literal character
287 0 : if ( cLiteral == cChar )
288 0 : 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 0 : 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 0 : nStrIndex++;
311 0 : continue;
312 : }
313 : }
314 : }
315 :
316 0 : i++;
317 : }
318 :
319 0 : 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 : 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 0 : void PatternFormatter::ImplSetMask(const OString& rEditMask, const OUString& rLiteralMask)
719 : {
720 0 : m_aEditMask = rEditMask;
721 0 : maLiteralMask = rLiteralMask;
722 0 : mbSameMask = true;
723 :
724 0 : if ( m_aEditMask.getLength() != maLiteralMask.getLength() )
725 : {
726 0 : OUStringBuffer aBuf(maLiteralMask);
727 0 : if (m_aEditMask.getLength() < aBuf.getLength())
728 0 : aBuf.remove(m_aEditMask.getLength(), aBuf.getLength() - m_aEditMask.getLength());
729 : else
730 0 : comphelper::string::padToLength(aBuf, m_aEditMask.getLength(), ' ');
731 0 : 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 0 : sal_Int32 i = 0;
737 0 : sal_Char c = 0;
738 0 : while ( i < rEditMask.getLength() )
739 : {
740 0 : sal_Char cTemp = rEditMask[i];
741 0 : if ( cTemp != EDITMASK_LITERAL )
742 : {
743 0 : if ( (cTemp == EDITMASK_ALLCHAR) ||
744 0 : (cTemp == EDITMASK_UPPERALLCHAR) ||
745 : (cTemp == EDITMASK_NUMSPACE) )
746 : {
747 0 : mbSameMask = false;
748 0 : break;
749 : }
750 0 : if ( i < rLiteralMask.getLength() )
751 : {
752 0 : if ( rLiteralMask[i] != ' ' )
753 : {
754 0 : mbSameMask = false;
755 0 : break;
756 : }
757 : }
758 0 : if ( !c )
759 0 : c = cTemp;
760 0 : if ( cTemp != c )
761 : {
762 0 : mbSameMask = false;
763 0 : break;
764 : }
765 : }
766 0 : i++;
767 : }
768 0 : }
769 :
770 0 : PatternFormatter::PatternFormatter()
771 : {
772 0 : mnFormatFlags = 0;
773 0 : mbSameMask = true;
774 0 : mbInPattKeyInput = false;
775 0 : }
776 :
777 0 : PatternFormatter::~PatternFormatter()
778 : {
779 0 : }
780 :
781 0 : void PatternFormatter::SetMask( const OString& rEditMask,
782 : const OUString& rLiteralMask )
783 : {
784 0 : ImplSetMask( rEditMask, rLiteralMask );
785 0 : ReformatAll();
786 0 : }
787 :
788 0 : void PatternFormatter::SetString( const OUString& rStr )
789 : {
790 0 : maFieldString = rStr;
791 0 : if ( GetField() )
792 : {
793 0 : GetField()->SetText( rStr );
794 0 : MarkToBeReformatted( false );
795 : }
796 0 : }
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 0 : void PatternFormatter::Reformat()
807 : {
808 0 : if ( GetField() )
809 : {
810 0 : ImplSetText( ImplPatternReformat( GetField()->GetText(), m_aEditMask, maLiteralMask, mnFormatFlags ) );
811 0 : if ( !mbSameMask && IsStrictFormat() && !GetField()->IsReadOnly() )
812 0 : GetField()->SetInsertMode( false );
813 : }
814 0 : }
815 :
816 0 : PatternField::PatternField( Window* pParent, WinBits nWinStyle ) :
817 0 : SpinField( pParent, nWinStyle )
818 : {
819 0 : SetField( this );
820 0 : Reformat();
821 0 : }
822 :
823 0 : PatternField::~PatternField()
824 : {
825 0 : }
826 :
827 0 : bool PatternField::PreNotify( NotifyEvent& rNEvt )
828 : {
829 0 : if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
830 : {
831 0 : if ( ImplPatternProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
832 0 : IsStrictFormat(), GetFormatFlags(),
833 0 : ImplIsSameMask(), ImplGetInPattKeyInput() ) )
834 0 : return true;
835 : }
836 :
837 0 : return SpinField::PreNotify( rNEvt );
838 : }
839 :
840 0 : bool PatternField::Notify( NotifyEvent& rNEvt )
841 : {
842 0 : if ( rNEvt.GetType() == EVENT_GETFOCUS )
843 0 : MarkToBeReformatted( false );
844 0 : else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
845 : {
846 0 : if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
847 0 : Reformat();
848 : }
849 :
850 0 : return SpinField::Notify( rNEvt );
851 : }
852 :
853 0 : void PatternField::Modify()
854 : {
855 0 : if ( !ImplGetInPattKeyInput() )
856 : {
857 0 : if ( IsStrictFormat() )
858 0 : ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), GetFormatFlags(), ImplIsSameMask() );
859 : else
860 0 : MarkToBeReformatted( true );
861 : }
862 :
863 0 : SpinField::Modify();
864 0 : }
865 :
866 0 : PatternBox::PatternBox( Window* pParent, WinBits nWinStyle ) :
867 0 : ComboBox( pParent, nWinStyle )
868 : {
869 0 : SetField( this );
870 0 : Reformat();
871 0 : }
872 :
873 0 : PatternBox::~PatternBox()
874 : {
875 0 : }
876 :
877 0 : bool PatternBox::PreNotify( NotifyEvent& rNEvt )
878 : {
879 0 : if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
880 : {
881 0 : if ( ImplPatternProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
882 0 : IsStrictFormat(), GetFormatFlags(),
883 0 : ImplIsSameMask(), ImplGetInPattKeyInput() ) )
884 0 : return true;
885 : }
886 :
887 0 : return ComboBox::PreNotify( rNEvt );
888 : }
889 :
890 0 : bool PatternBox::Notify( NotifyEvent& rNEvt )
891 : {
892 0 : if ( rNEvt.GetType() == EVENT_GETFOCUS )
893 0 : MarkToBeReformatted( false );
894 0 : else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
895 : {
896 0 : if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
897 0 : Reformat();
898 : }
899 :
900 0 : return ComboBox::Notify( rNEvt );
901 : }
902 :
903 0 : void PatternBox::Modify()
904 : {
905 0 : if ( !ImplGetInPattKeyInput() )
906 : {
907 0 : if ( IsStrictFormat() )
908 0 : ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), GetFormatFlags(), ImplIsSameMask() );
909 : else
910 0 : MarkToBeReformatted( true );
911 : }
912 :
913 0 : ComboBox::Modify();
914 0 : }
915 :
916 0 : void PatternBox::ReformatAll()
917 : {
918 0 : OUString aStr;
919 0 : SetUpdateMode( false );
920 0 : sal_uInt16 nEntryCount = GetEntryCount();
921 0 : for ( sal_uInt16 i=0; i < nEntryCount; i++ )
922 : {
923 0 : aStr = ImplPatternReformat( GetEntry( i ), GetEditMask(), GetLiteralMask(), GetFormatFlags() );
924 0 : RemoveEntryAt(i);
925 0 : InsertEntry( aStr, i );
926 : }
927 0 : PatternFormatter::Reformat();
928 0 : SetUpdateMode( true );
929 0 : }
930 :
931 0 : static ExtDateFieldFormat ImplGetExtFormat( DateFormat eOld )
932 : {
933 0 : switch( eOld )
934 : {
935 0 : case DMY: return XTDATEF_SHORT_DDMMYY;
936 0 : case MDY: return XTDATEF_SHORT_MMDDYY;
937 0 : default: return XTDATEF_SHORT_YYMMDD;
938 : }
939 : }
940 :
941 0 : static sal_uInt16 ImplCutNumberFromString( OUString& rStr )
942 : {
943 0 : sal_Int32 i1 = 0;
944 0 : while (i1 != rStr.getLength() && !(rStr[i1] >= '0' && rStr[i1] <= '9')) {
945 0 : ++i1;
946 : }
947 0 : sal_Int32 i2 = i1;
948 0 : while (i2 != rStr.getLength() && rStr[i2] >= '0' && rStr[i2] <= '9') {
949 0 : ++i2;
950 : }
951 0 : sal_Int32 nValue = rStr.copy(i1, i2-i1).toInt32();
952 0 : rStr = rStr.copy(std::min(i2+1, rStr.getLength()));
953 0 : return nValue;
954 : }
955 :
956 0 : static bool ImplCutMonthName( OUString& rStr, const OUString& _rLookupMonthName )
957 : {
958 0 : sal_Int32 index = 0;
959 0 : rStr = rStr.replaceFirst(_rLookupMonthName, OUString(), &index);
960 0 : return index >= 0;
961 : }
962 :
963 0 : static sal_uInt16 ImplCutMonthFromString( OUString& rStr, const CalendarWrapper& rCalendarWrapper )
964 : {
965 : // search for a month' name
966 0 : for ( sal_uInt16 i=1; i <= 12; i++ )
967 : {
968 0 : OUString aMonthName = rCalendarWrapper.getMonths()[i-1].FullName;
969 : // long month name?
970 0 : if ( ImplCutMonthName( rStr, aMonthName ) )
971 0 : return i;
972 :
973 : // short month name?
974 0 : OUString aAbbrevMonthName = rCalendarWrapper.getMonths()[i-1].AbbrevName;
975 0 : if ( ImplCutMonthName( rStr, aAbbrevMonthName ) )
976 0 : return i;
977 0 : }
978 :
979 0 : return ImplCutNumberFromString( rStr );
980 : }
981 :
982 0 : static OUString ImplGetDateSep( const LocaleDataWrapper& rLocaleDataWrapper, ExtDateFieldFormat eFormat )
983 : {
984 0 : if ( ( eFormat == XTDATEF_SHORT_YYMMDD_DIN5008 ) || ( eFormat == XTDATEF_SHORT_YYYYMMDD_DIN5008 ) )
985 0 : return OUString("-");
986 : else
987 0 : return rLocaleDataWrapper.getDateSep();
988 : }
989 :
990 0 : static bool ImplDateProcessKeyInput( Edit*, const KeyEvent& rKEvt, ExtDateFieldFormat eFormat,
991 : const LocaleDataWrapper& rLocaleDataWrapper )
992 : {
993 0 : sal_Unicode cChar = rKEvt.GetCharCode();
994 0 : sal_uInt16 nGroup = rKEvt.GetKeyCode().GetGroup();
995 0 : if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
996 0 : (nGroup == KEYGROUP_MISC)||
997 0 : ((cChar >= '0') && (cChar <= '9')) ||
998 0 : (cChar == ImplGetDateSep( rLocaleDataWrapper, eFormat )[0]) )
999 0 : return false;
1000 : else
1001 0 : return true;
1002 : }
1003 :
1004 0 : static bool ImplDateGetValue( const OUString& rStr, Date& rDate, ExtDateFieldFormat eDateFormat,
1005 : const LocaleDataWrapper& rLocaleDataWrapper, const CalendarWrapper& rCalendarWrapper,
1006 : const AllSettings& )
1007 : {
1008 0 : sal_uInt16 nDay = 0;
1009 0 : sal_uInt16 nMonth = 0;
1010 0 : sal_uInt16 nYear = 0;
1011 0 : bool bYear = true;
1012 0 : bool bError = false;
1013 0 : OUString aStr( rStr );
1014 :
1015 0 : if ( eDateFormat == XTDATEF_SYSTEM_LONG )
1016 : {
1017 0 : DateFormat eFormat = rLocaleDataWrapper.getLongDateFormat();
1018 0 : switch( eFormat )
1019 : {
1020 : case MDY:
1021 0 : nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
1022 0 : nDay = ImplCutNumberFromString( aStr );
1023 0 : nYear = ImplCutNumberFromString( aStr );
1024 0 : break;
1025 : case DMY:
1026 0 : nDay = ImplCutNumberFromString( aStr );
1027 0 : nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
1028 0 : nYear = ImplCutNumberFromString( aStr );
1029 0 : break;
1030 : case YMD:
1031 : default:
1032 0 : nYear = ImplCutNumberFromString( aStr );
1033 0 : nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
1034 0 : nDay = ImplCutNumberFromString( aStr );
1035 0 : break;
1036 : }
1037 : }
1038 : else
1039 : {
1040 : // Check if year is present:
1041 0 : OUString aDateSep = ImplGetDateSep( rLocaleDataWrapper, eDateFormat );
1042 0 : sal_Int32 nSepPos = aStr.indexOf( aDateSep );
1043 0 : if ( nSepPos < 0 )
1044 0 : return false;
1045 0 : nSepPos = aStr.indexOf( aDateSep, nSepPos+1 );
1046 0 : if ( ( nSepPos < 0 ) || ( nSepPos == (aStr.getLength()-1) ) )
1047 : {
1048 0 : bYear = false;
1049 0 : nYear = Date( Date::SYSTEM ).GetYear();
1050 : }
1051 :
1052 0 : const sal_Unicode* pBuf = aStr.getStr();
1053 0 : ImplSkipDelimiters( pBuf );
1054 :
1055 0 : switch ( eDateFormat )
1056 : {
1057 : case XTDATEF_SHORT_DDMMYY:
1058 : case XTDATEF_SHORT_DDMMYYYY:
1059 : {
1060 0 : nDay = ImplGetNum( pBuf, bError );
1061 0 : ImplSkipDelimiters( pBuf );
1062 0 : nMonth = ImplGetNum( pBuf, bError );
1063 0 : ImplSkipDelimiters( pBuf );
1064 0 : if ( bYear )
1065 0 : nYear = ImplGetNum( pBuf, bError );
1066 : }
1067 0 : break;
1068 : case XTDATEF_SHORT_MMDDYY:
1069 : case XTDATEF_SHORT_MMDDYYYY:
1070 : {
1071 0 : nMonth = ImplGetNum( pBuf, bError );
1072 0 : ImplSkipDelimiters( pBuf );
1073 0 : nDay = ImplGetNum( pBuf, bError );
1074 0 : ImplSkipDelimiters( pBuf );
1075 0 : if ( bYear )
1076 0 : nYear = ImplGetNum( pBuf, bError );
1077 : }
1078 0 : break;
1079 : case XTDATEF_SHORT_YYMMDD:
1080 : case XTDATEF_SHORT_YYYYMMDD:
1081 : case XTDATEF_SHORT_YYMMDD_DIN5008:
1082 : case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1083 : {
1084 0 : if ( bYear )
1085 0 : nYear = ImplGetNum( pBuf, bError );
1086 0 : ImplSkipDelimiters( pBuf );
1087 0 : nMonth = ImplGetNum( pBuf, bError );
1088 0 : ImplSkipDelimiters( pBuf );
1089 0 : nDay = ImplGetNum( pBuf, bError );
1090 : }
1091 0 : break;
1092 :
1093 : default:
1094 : {
1095 : OSL_FAIL( "DateFormat???" );
1096 : }
1097 0 : }
1098 : }
1099 :
1100 0 : if ( bError || !nDay || !nMonth )
1101 0 : return false;
1102 :
1103 0 : Date aNewDate( nDay, nMonth, nYear );
1104 0 : DateFormatter::ExpandCentury( aNewDate, utl::MiscCfg().GetYear2000() );
1105 0 : if ( aNewDate.IsValidDate() )
1106 : {
1107 0 : rDate = aNewDate;
1108 0 : return true;
1109 : }
1110 0 : return false;
1111 : }
1112 :
1113 0 : bool DateFormatter::ImplDateReformat( const OUString& rStr, OUString& rOutStr, const AllSettings& rSettings )
1114 : {
1115 0 : Date aDate( 0, 0, 0 );
1116 0 : if ( !ImplDateGetValue( rStr, aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1117 0 : return true;
1118 :
1119 0 : Date aTempDate = aDate;
1120 0 : if ( aTempDate > GetMax() )
1121 0 : aTempDate = GetMax();
1122 0 : else if ( aTempDate < GetMin() )
1123 0 : aTempDate = GetMin();
1124 :
1125 0 : if ( GetErrorHdl().IsSet() && (aDate != aTempDate) )
1126 : {
1127 0 : maCorrectedDate = aTempDate;
1128 0 : if( !GetErrorHdl().Call( this ) )
1129 : {
1130 0 : maCorrectedDate = Date( Date::SYSTEM );
1131 0 : return false;
1132 : }
1133 : else
1134 0 : maCorrectedDate = Date( Date::SYSTEM );
1135 : }
1136 :
1137 0 : rOutStr = ImplGetDateAsText( aTempDate, rSettings );
1138 :
1139 0 : return true;
1140 : }
1141 :
1142 0 : OUString DateFormatter::ImplGetDateAsText( const Date& rDate,
1143 : const AllSettings& ) const
1144 : {
1145 0 : bool bShowCentury = false;
1146 0 : switch ( GetExtDateFormat() )
1147 : {
1148 : case XTDATEF_SYSTEM_SHORT_YYYY:
1149 : case XTDATEF_SYSTEM_LONG:
1150 : case XTDATEF_SHORT_DDMMYYYY:
1151 : case XTDATEF_SHORT_MMDDYYYY:
1152 : case XTDATEF_SHORT_YYYYMMDD:
1153 : case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1154 : {
1155 0 : bShowCentury = true;
1156 : }
1157 0 : break;
1158 : default:
1159 : {
1160 0 : bShowCentury = false;
1161 : }
1162 : }
1163 :
1164 0 : if ( !bShowCentury )
1165 : {
1166 : // Check if I have to use force showing the century
1167 0 : sal_uInt16 nTwoDigitYearStart = utl::MiscCfg().GetYear2000();
1168 0 : sal_uInt16 nYear = rDate.GetYear();
1169 :
1170 : // If year is not in double digit range
1171 0 : if ( (nYear < nTwoDigitYearStart) || (nYear >= nTwoDigitYearStart+100) )
1172 0 : bShowCentury = true;
1173 : }
1174 :
1175 : sal_Unicode aBuf[128];
1176 0 : sal_Unicode* pBuf = aBuf;
1177 :
1178 0 : OUString aDateSep = ImplGetDateSep( ImplGetLocaleDataWrapper(), GetExtDateFormat( true ) );
1179 0 : sal_uInt16 nDay = rDate.GetDay();
1180 0 : sal_uInt16 nMonth = rDate.GetMonth();
1181 0 : sal_uInt16 nYear = rDate.GetYear();
1182 0 : sal_uInt16 nYearLen = bShowCentury ? 4 : 2;
1183 :
1184 0 : if ( !bShowCentury )
1185 0 : nYear %= 100;
1186 :
1187 0 : switch ( GetExtDateFormat( true ) )
1188 : {
1189 : case XTDATEF_SYSTEM_LONG:
1190 : {
1191 0 : return ImplGetLocaleDataWrapper().getLongDate( rDate, GetCalendarWrapper(), 1, false, 1, !bShowCentury );
1192 : }
1193 : case XTDATEF_SHORT_DDMMYY:
1194 : case XTDATEF_SHORT_DDMMYYYY:
1195 : {
1196 0 : pBuf = ImplAddNum( pBuf, nDay, 2 );
1197 0 : pBuf = ImplAddString( pBuf, aDateSep );
1198 0 : pBuf = ImplAddNum( pBuf, nMonth, 2 );
1199 0 : pBuf = ImplAddString( pBuf, aDateSep );
1200 0 : pBuf = ImplAddNum( pBuf, nYear, nYearLen );
1201 : }
1202 0 : break;
1203 : case XTDATEF_SHORT_MMDDYY:
1204 : case XTDATEF_SHORT_MMDDYYYY:
1205 : {
1206 0 : pBuf = ImplAddNum( pBuf, nMonth, 2 );
1207 0 : pBuf = ImplAddString( pBuf, aDateSep );
1208 0 : pBuf = ImplAddNum( pBuf, nDay, 2 );
1209 0 : pBuf = ImplAddString( pBuf, aDateSep );
1210 0 : pBuf = ImplAddNum( pBuf, nYear, nYearLen );
1211 : }
1212 0 : break;
1213 : case XTDATEF_SHORT_YYMMDD:
1214 : case XTDATEF_SHORT_YYYYMMDD:
1215 : case XTDATEF_SHORT_YYMMDD_DIN5008:
1216 : case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1217 : {
1218 0 : pBuf = ImplAddNum( pBuf, nYear, nYearLen );
1219 0 : pBuf = ImplAddString( pBuf, aDateSep );
1220 0 : pBuf = ImplAddNum( pBuf, nMonth, 2 );
1221 0 : pBuf = ImplAddString( pBuf, aDateSep );
1222 0 : pBuf = ImplAddNum( pBuf, nDay, 2 );
1223 : }
1224 0 : break;
1225 : default:
1226 : {
1227 : OSL_FAIL( "DateFormat???" );
1228 : }
1229 : }
1230 :
1231 0 : return OUString(aBuf, pBuf-aBuf);
1232 : }
1233 :
1234 0 : static void ImplDateIncrementDay( Date& rDate, bool bUp )
1235 : {
1236 0 : DateFormatter::ExpandCentury( rDate );
1237 :
1238 0 : if ( bUp )
1239 : {
1240 0 : if ( (rDate.GetDay() != 31) || (rDate.GetMonth() != 12) || (rDate.GetYear() != 9999) )
1241 0 : rDate++;
1242 : }
1243 : else
1244 : {
1245 0 : if ( (rDate.GetDay() != 1 ) || (rDate.GetMonth() != 1) || (rDate.GetYear() != 0) )
1246 0 : rDate--;
1247 : }
1248 0 : }
1249 :
1250 0 : static void ImplDateIncrementMonth( Date& rDate, bool bUp )
1251 : {
1252 0 : DateFormatter::ExpandCentury( rDate );
1253 :
1254 0 : sal_uInt16 nMonth = rDate.GetMonth();
1255 0 : sal_uInt16 nYear = rDate.GetYear();
1256 0 : if ( bUp )
1257 : {
1258 0 : if ( (nMonth == 12) && (nYear < 9999) )
1259 : {
1260 0 : rDate.SetMonth( 1 );
1261 0 : rDate.SetYear( nYear + 1 );
1262 : }
1263 : else
1264 : {
1265 0 : if ( nMonth < 12 )
1266 0 : rDate.SetMonth( nMonth + 1 );
1267 : }
1268 : }
1269 : else
1270 : {
1271 0 : if ( (nMonth == 1) && (nYear > 0) )
1272 : {
1273 0 : rDate.SetMonth( 12 );
1274 0 : rDate.SetYear( nYear - 1 );
1275 : }
1276 : else
1277 : {
1278 0 : if ( nMonth > 1 )
1279 0 : rDate.SetMonth( nMonth - 1 );
1280 : }
1281 : }
1282 :
1283 0 : sal_uInt16 nDaysInMonth = Date::GetDaysInMonth( rDate.GetMonth(), rDate.GetYear());
1284 0 : if ( rDate.GetDay() > nDaysInMonth )
1285 0 : rDate.SetDay( nDaysInMonth );
1286 0 : }
1287 :
1288 0 : static void ImplDateIncrementYear( Date& rDate, bool bUp )
1289 : {
1290 0 : DateFormatter::ExpandCentury( rDate );
1291 :
1292 0 : sal_uInt16 nYear = rDate.GetYear();
1293 0 : sal_uInt16 nMonth = rDate.GetMonth();
1294 0 : if ( bUp )
1295 : {
1296 0 : if ( nYear < 9999 )
1297 0 : rDate.SetYear( nYear + 1 );
1298 : }
1299 : else
1300 : {
1301 0 : if ( nYear > 0 )
1302 0 : rDate.SetYear( nYear - 1 );
1303 : }
1304 0 : if (nMonth == 2)
1305 : {
1306 : // Handle February 29 from leap year to non-leap year.
1307 0 : sal_uInt16 nDay = rDate.GetDay();
1308 0 : if (nDay > 28)
1309 : {
1310 : // The check would not be necessary if it was guaranteed that the
1311 : // date was valid before and actually was a leap year,
1312 : // de-/incrementing a leap year with 29 always results in 28.
1313 0 : sal_uInt16 nDaysInMonth = Date::GetDaysInMonth( nMonth, rDate.GetYear());
1314 0 : if (nDay > nDaysInMonth)
1315 0 : rDate.SetDay( nDaysInMonth);
1316 : }
1317 : }
1318 0 : }
1319 :
1320 0 : bool DateFormatter::ImplAllowMalformedInput() const
1321 : {
1322 0 : return !IsEnforceValidValue();
1323 : }
1324 :
1325 0 : void DateField::ImplDateSpinArea( bool bUp )
1326 : {
1327 : // increment days if all is selected
1328 0 : if ( GetField() )
1329 : {
1330 0 : Date aDate( GetDate() );
1331 0 : Selection aSelection = GetField()->GetSelection();
1332 0 : aSelection.Justify();
1333 0 : OUString aText( GetText() );
1334 0 : if ( (sal_Int32)aSelection.Len() == aText.getLength() )
1335 0 : ImplDateIncrementDay( aDate, bUp );
1336 : else
1337 : {
1338 0 : sal_Int8 nDateArea = 0;
1339 :
1340 0 : ExtDateFieldFormat eFormat = GetExtDateFormat( true );
1341 0 : if ( eFormat == XTDATEF_SYSTEM_LONG )
1342 : {
1343 0 : eFormat = ImplGetExtFormat( ImplGetLocaleDataWrapper().getLongDateFormat() );
1344 0 : nDateArea = 1;
1345 : }
1346 : else
1347 : {
1348 : // search area
1349 0 : sal_Int32 nPos = 0;
1350 0 : OUString aDateSep = ImplGetDateSep( ImplGetLocaleDataWrapper(), eFormat );
1351 0 : for ( sal_Int8 i = 1; i <= 3; i++ )
1352 : {
1353 0 : nPos = aText.indexOf( aDateSep, nPos );
1354 0 : if ( nPos >= (sal_Int32)aSelection.Max() )
1355 : {
1356 0 : nDateArea = i;
1357 0 : break;
1358 : }
1359 : else
1360 0 : nPos++;
1361 0 : }
1362 : }
1363 :
1364 0 : switch( eFormat )
1365 : {
1366 : case XTDATEF_SHORT_MMDDYY:
1367 : case XTDATEF_SHORT_MMDDYYYY:
1368 0 : switch( nDateArea )
1369 : {
1370 0 : case 1: ImplDateIncrementMonth( aDate, bUp );
1371 0 : break;
1372 0 : case 2: ImplDateIncrementDay( aDate, bUp );
1373 0 : break;
1374 0 : case 3: ImplDateIncrementYear( aDate, bUp );
1375 0 : break;
1376 : }
1377 0 : break;
1378 : case XTDATEF_SHORT_DDMMYY:
1379 : case XTDATEF_SHORT_DDMMYYYY:
1380 0 : switch( nDateArea )
1381 : {
1382 0 : case 1: ImplDateIncrementDay( aDate, bUp );
1383 0 : break;
1384 0 : case 2: ImplDateIncrementMonth( aDate, bUp );
1385 0 : break;
1386 0 : case 3: ImplDateIncrementYear( aDate, bUp );
1387 0 : break;
1388 : }
1389 0 : break;
1390 : case XTDATEF_SHORT_YYMMDD:
1391 : case XTDATEF_SHORT_YYYYMMDD:
1392 : case XTDATEF_SHORT_YYMMDD_DIN5008:
1393 : case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1394 0 : switch( nDateArea )
1395 : {
1396 0 : case 1: ImplDateIncrementYear( aDate, bUp );
1397 0 : break;
1398 0 : case 2: ImplDateIncrementMonth( aDate, bUp );
1399 0 : break;
1400 0 : case 3: ImplDateIncrementDay( aDate, bUp );
1401 0 : break;
1402 : }
1403 0 : break;
1404 : default:
1405 : OSL_FAIL( "invalid conversion" );
1406 0 : break;
1407 : }
1408 : }
1409 :
1410 0 : ImplNewFieldValue( aDate );
1411 : }
1412 0 : }
1413 :
1414 0 : void DateFormatter::ImplInit()
1415 : {
1416 0 : mbLongFormat = false;
1417 0 : mbShowDateCentury = true;
1418 0 : mpCalendarWrapper = NULL;
1419 0 : mnDateFormat = 0xFFFF;
1420 0 : mnExtDateFormat = XTDATEF_SYSTEM_SHORT;
1421 0 : }
1422 :
1423 0 : DateFormatter::DateFormatter() :
1424 : maFieldDate( 0 ),
1425 : maLastDate( 0 ),
1426 : maMin( 1, 1, 1900 ),
1427 : maMax( 31, 12, 2200 ),
1428 : maCorrectedDate( Date::SYSTEM ),
1429 0 : mbEnforceValidValue( true )
1430 : {
1431 0 : ImplInit();
1432 0 : }
1433 :
1434 0 : void DateFormatter::ImplLoadRes( const ResId& rResId )
1435 : {
1436 0 : ResMgr* pMgr = rResId.GetResMgr();
1437 0 : if( pMgr )
1438 : {
1439 0 : sal_uLong nMask = pMgr->ReadLong();
1440 :
1441 0 : if ( DATEFORMATTER_MIN & nMask )
1442 : {
1443 0 : maMin = Date( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
1444 0 : pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE*)pMgr->GetClass() ) );
1445 : }
1446 0 : if ( DATEFORMATTER_MAX & nMask )
1447 : {
1448 0 : maMax = Date( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
1449 0 : pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE*)pMgr->GetClass() ) );
1450 : }
1451 0 : if ( DATEFORMATTER_LONGFORMAT & nMask )
1452 0 : mbLongFormat = pMgr->ReadShort() != 0;
1453 :
1454 0 : if ( DATEFORMATTER_STRICTFORMAT & nMask )
1455 0 : SetStrictFormat( pMgr->ReadShort() != 0 );
1456 :
1457 0 : if ( DATEFORMATTER_VALUE & nMask )
1458 : {
1459 0 : maFieldDate = Date( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
1460 0 : pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE*)pMgr->GetClass() ) );
1461 0 : if ( maFieldDate > maMax )
1462 0 : maFieldDate = maMax;
1463 0 : if ( maFieldDate < maMin )
1464 0 : maFieldDate = maMin;
1465 0 : maLastDate = maFieldDate;
1466 : }
1467 : }
1468 0 : }
1469 :
1470 0 : DateFormatter::~DateFormatter()
1471 : {
1472 0 : delete mpCalendarWrapper;
1473 0 : mpCalendarWrapper = NULL;
1474 0 : }
1475 :
1476 0 : void DateFormatter::SetLocale( const ::com::sun::star::lang::Locale& rLocale )
1477 : {
1478 0 : delete mpCalendarWrapper;
1479 0 : mpCalendarWrapper = NULL;
1480 0 : FormatterBase::SetLocale( rLocale );
1481 0 : }
1482 :
1483 0 : CalendarWrapper& DateFormatter::GetCalendarWrapper() const
1484 : {
1485 0 : if ( !mpCalendarWrapper )
1486 : {
1487 0 : ((DateFormatter*)this)->mpCalendarWrapper = new CalendarWrapper( comphelper::getProcessComponentContext() );
1488 0 : mpCalendarWrapper->loadDefaultCalendar( GetLocale() );
1489 : }
1490 :
1491 0 : return *mpCalendarWrapper;
1492 : }
1493 :
1494 0 : void DateFormatter::SetExtDateFormat( ExtDateFieldFormat eFormat )
1495 : {
1496 0 : mnExtDateFormat = eFormat;
1497 0 : ReformatAll();
1498 0 : }
1499 :
1500 0 : ExtDateFieldFormat DateFormatter::GetExtDateFormat( bool bResolveSystemFormat ) const
1501 : {
1502 0 : ExtDateFieldFormat eDateFormat = (ExtDateFieldFormat)mnExtDateFormat;
1503 :
1504 0 : if ( bResolveSystemFormat && ( eDateFormat <= XTDATEF_SYSTEM_SHORT_YYYY ) )
1505 : {
1506 0 : bool bShowCentury = (eDateFormat == XTDATEF_SYSTEM_SHORT_YYYY);
1507 0 : switch ( ImplGetLocaleDataWrapper().getDateFormat() )
1508 : {
1509 0 : case DMY: eDateFormat = bShowCentury ? XTDATEF_SHORT_DDMMYYYY : XTDATEF_SHORT_DDMMYY;
1510 0 : break;
1511 0 : case MDY: eDateFormat = bShowCentury ? XTDATEF_SHORT_MMDDYYYY : XTDATEF_SHORT_MMDDYY;
1512 0 : break;
1513 0 : default: eDateFormat = bShowCentury ? XTDATEF_SHORT_YYYYMMDD : XTDATEF_SHORT_YYMMDD;
1514 :
1515 : }
1516 : }
1517 :
1518 0 : return eDateFormat;
1519 : }
1520 :
1521 0 : void DateFormatter::ReformatAll()
1522 : {
1523 0 : Reformat();
1524 0 : }
1525 :
1526 0 : void DateFormatter::SetMin( const Date& rNewMin )
1527 : {
1528 0 : maMin = rNewMin;
1529 0 : if ( !IsEmptyFieldValue() )
1530 0 : ReformatAll();
1531 0 : }
1532 :
1533 0 : void DateFormatter::SetMax( const Date& rNewMax )
1534 : {
1535 0 : maMax = rNewMax;
1536 0 : if ( !IsEmptyFieldValue() )
1537 0 : ReformatAll();
1538 0 : }
1539 :
1540 0 : void DateFormatter::SetLongFormat( bool bLong )
1541 : {
1542 0 : mbLongFormat = bLong;
1543 :
1544 : // #91913# Remove LongFormat and DateShowCentury - redundant
1545 0 : if ( bLong )
1546 : {
1547 0 : SetExtDateFormat( XTDATEF_SYSTEM_LONG );
1548 : }
1549 : else
1550 : {
1551 0 : if( mnExtDateFormat == XTDATEF_SYSTEM_LONG )
1552 0 : SetExtDateFormat( XTDATEF_SYSTEM_SHORT );
1553 : }
1554 :
1555 0 : ReformatAll();
1556 0 : }
1557 :
1558 0 : void DateFormatter::SetShowDateCentury( bool bShowDateCentury )
1559 : {
1560 0 : mbShowDateCentury = bShowDateCentury;
1561 :
1562 : // #91913# Remove LongFormat and DateShowCentury - redundant
1563 0 : if ( bShowDateCentury )
1564 : {
1565 0 : switch ( GetExtDateFormat() )
1566 : {
1567 : case XTDATEF_SYSTEM_SHORT:
1568 : case XTDATEF_SYSTEM_SHORT_YY:
1569 0 : SetExtDateFormat( XTDATEF_SYSTEM_SHORT_YYYY ); break;
1570 : case XTDATEF_SHORT_DDMMYY:
1571 0 : SetExtDateFormat( XTDATEF_SHORT_DDMMYYYY ); break;
1572 : case XTDATEF_SHORT_MMDDYY:
1573 0 : SetExtDateFormat( XTDATEF_SHORT_MMDDYYYY ); break;
1574 : case XTDATEF_SHORT_YYMMDD:
1575 0 : SetExtDateFormat( XTDATEF_SHORT_YYYYMMDD ); break;
1576 : case XTDATEF_SHORT_YYMMDD_DIN5008:
1577 0 : SetExtDateFormat( XTDATEF_SHORT_YYYYMMDD_DIN5008 ); break;
1578 : default:
1579 : ;
1580 : }
1581 : }
1582 : else
1583 : {
1584 0 : switch ( GetExtDateFormat() )
1585 : {
1586 : case XTDATEF_SYSTEM_SHORT:
1587 : case XTDATEF_SYSTEM_SHORT_YYYY:
1588 0 : SetExtDateFormat( XTDATEF_SYSTEM_SHORT_YY ); break;
1589 : case XTDATEF_SHORT_DDMMYYYY:
1590 0 : SetExtDateFormat( XTDATEF_SHORT_DDMMYY ); break;
1591 : case XTDATEF_SHORT_MMDDYYYY:
1592 0 : SetExtDateFormat( XTDATEF_SHORT_MMDDYY ); break;
1593 : case XTDATEF_SHORT_YYYYMMDD:
1594 0 : SetExtDateFormat( XTDATEF_SHORT_YYMMDD ); break;
1595 : case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1596 0 : SetExtDateFormat( XTDATEF_SHORT_YYMMDD_DIN5008 ); break;
1597 : default:
1598 : ;
1599 : }
1600 : }
1601 :
1602 0 : ReformatAll();
1603 0 : }
1604 :
1605 0 : void DateFormatter::SetDate( const Date& rNewDate )
1606 : {
1607 0 : SetUserDate( rNewDate );
1608 0 : maFieldDate = maLastDate;
1609 0 : maLastDate = GetDate();
1610 0 : }
1611 :
1612 0 : void DateFormatter::SetUserDate( const Date& rNewDate )
1613 : {
1614 0 : ImplSetUserDate( rNewDate );
1615 0 : }
1616 :
1617 0 : void DateFormatter::ImplSetUserDate( const Date& rNewDate, Selection* pNewSelection )
1618 : {
1619 0 : Date aNewDate = rNewDate;
1620 0 : if ( aNewDate > maMax )
1621 0 : aNewDate = maMax;
1622 0 : else if ( aNewDate < maMin )
1623 0 : aNewDate = maMin;
1624 0 : maLastDate = aNewDate;
1625 :
1626 0 : if ( GetField() )
1627 0 : ImplSetText( ImplGetDateAsText( aNewDate, GetFieldSettings() ), pNewSelection );
1628 0 : }
1629 :
1630 0 : void DateFormatter::ImplNewFieldValue( const Date& rDate )
1631 : {
1632 0 : if ( GetField() )
1633 : {
1634 0 : Selection aSelection = GetField()->GetSelection();
1635 0 : aSelection.Justify();
1636 0 : OUString aText = GetField()->GetText();
1637 :
1638 : // If selected until the end then keep it that way
1639 0 : if ( (sal_Int32)aSelection.Max() == aText.getLength() )
1640 : {
1641 0 : if ( !aSelection.Len() )
1642 0 : aSelection.Min() = SELECTION_MAX;
1643 0 : aSelection.Max() = SELECTION_MAX;
1644 : }
1645 :
1646 0 : Date aOldLastDate = maLastDate;
1647 0 : ImplSetUserDate( rDate, &aSelection );
1648 0 : maLastDate = aOldLastDate;
1649 :
1650 : // Modify at Edit is only set at KeyInput
1651 0 : if ( GetField()->GetText() != aText )
1652 : {
1653 0 : GetField()->SetModifyFlag();
1654 0 : GetField()->Modify();
1655 0 : }
1656 : }
1657 0 : }
1658 :
1659 0 : Date DateFormatter::GetDate() const
1660 : {
1661 0 : Date aDate( 0, 0, 0 );
1662 :
1663 0 : if ( GetField() )
1664 : {
1665 0 : if ( ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1666 : {
1667 0 : if ( aDate > maMax )
1668 0 : aDate = maMax;
1669 0 : else if ( aDate < maMin )
1670 0 : aDate = maMin;
1671 : }
1672 : else
1673 : {
1674 : // !!! We should find out why dates are treated differently than other fields (see
1675 : // also bug: 52384)
1676 :
1677 0 : if ( !ImplAllowMalformedInput() )
1678 : {
1679 0 : if ( maLastDate.GetDate() )
1680 0 : aDate = maLastDate;
1681 0 : else if ( !IsEmptyFieldValueEnabled() )
1682 0 : aDate = Date( Date::SYSTEM );
1683 : }
1684 : else
1685 0 : aDate = GetInvalidDate();
1686 : }
1687 : }
1688 :
1689 0 : return aDate;
1690 : }
1691 :
1692 0 : void DateFormatter::SetEmptyDate()
1693 : {
1694 0 : FormatterBase::SetEmptyFieldValue();
1695 0 : }
1696 :
1697 0 : bool DateFormatter::IsEmptyDate() const
1698 : {
1699 0 : bool bEmpty = FormatterBase::IsEmptyFieldValue();
1700 :
1701 0 : if ( GetField() && MustBeReformatted() && IsEmptyFieldValueEnabled() )
1702 : {
1703 0 : if ( GetField()->GetText().isEmpty() )
1704 : {
1705 0 : bEmpty = true;
1706 : }
1707 0 : else if ( !maLastDate.GetDate() )
1708 : {
1709 0 : Date aDate( Date::EMPTY );
1710 0 : bEmpty = !ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() );
1711 : }
1712 : }
1713 0 : return bEmpty;
1714 : }
1715 :
1716 0 : void DateFormatter::Reformat()
1717 : {
1718 0 : if ( !GetField() )
1719 0 : return;
1720 :
1721 0 : if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
1722 0 : return;
1723 :
1724 0 : OUString aStr;
1725 0 : bool bOK = ImplDateReformat( GetField()->GetText(), aStr, GetFieldSettings() );
1726 0 : if( !bOK )
1727 0 : return;
1728 :
1729 0 : if ( !aStr.isEmpty() )
1730 : {
1731 0 : ImplSetText( aStr );
1732 0 : ImplDateGetValue( aStr, maLastDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() );
1733 : }
1734 : else
1735 : {
1736 0 : if ( maLastDate.GetDate() )
1737 0 : SetDate( maLastDate );
1738 0 : else if ( !IsEmptyFieldValueEnabled() )
1739 0 : SetDate( Date( Date::SYSTEM ) );
1740 : else
1741 : {
1742 0 : ImplSetText( OUString() );
1743 0 : SetEmptyFieldValueData( true );
1744 : }
1745 0 : }
1746 : }
1747 :
1748 0 : void DateFormatter::ExpandCentury( Date& rDate )
1749 : {
1750 0 : ExpandCentury( rDate, utl::MiscCfg().GetYear2000() );
1751 0 : }
1752 :
1753 0 : void DateFormatter::ExpandCentury( Date& rDate, sal_uInt16 nTwoDigitYearStart )
1754 : {
1755 0 : sal_uInt16 nDateYear = rDate.GetYear();
1756 0 : if ( nDateYear < 100 )
1757 : {
1758 0 : sal_uInt16 nCentury = nTwoDigitYearStart / 100;
1759 0 : if ( nDateYear < (nTwoDigitYearStart % 100) )
1760 0 : nCentury++;
1761 0 : rDate.SetYear( nDateYear + (nCentury*100) );
1762 : }
1763 0 : }
1764 :
1765 0 : DateField::DateField( Window* pParent, WinBits nWinStyle ) :
1766 : SpinField( pParent, nWinStyle ),
1767 0 : maFirst( GetMin() ),
1768 0 : maLast( GetMax() )
1769 : {
1770 0 : SetField( this );
1771 0 : SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
1772 0 : Reformat();
1773 0 : ResetLastDate();
1774 0 : }
1775 :
1776 0 : DateField::DateField( Window* pParent, const ResId& rResId ) :
1777 : SpinField( WINDOW_DATEFIELD ),
1778 0 : maFirst( GetMin() ),
1779 0 : maLast( GetMax() )
1780 : {
1781 0 : rResId.SetRT( RSC_DATEFIELD );
1782 0 : WinBits nStyle = ImplInitRes( rResId );
1783 0 : SpinField::ImplInit( pParent, nStyle );
1784 0 : SetField( this );
1785 0 : SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
1786 0 : ImplLoadRes( rResId );
1787 :
1788 0 : if ( !(nStyle & WB_HIDE ) )
1789 0 : Show();
1790 :
1791 0 : ResetLastDate();
1792 0 : }
1793 :
1794 0 : void DateField::ImplLoadRes( const ResId& rResId )
1795 : {
1796 0 : SpinField::ImplLoadRes( rResId );
1797 :
1798 0 : ResMgr* pMgr = rResId.GetResMgr();
1799 0 : if( pMgr )
1800 : {
1801 0 : DateFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
1802 :
1803 0 : sal_uLong nMask = ReadLongRes();
1804 0 : if ( DATEFIELD_FIRST & nMask )
1805 : {
1806 0 : maFirst = Date( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
1807 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
1808 : }
1809 0 : if ( DATEFIELD_LAST & nMask )
1810 : {
1811 0 : maLast = Date( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
1812 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
1813 : }
1814 : }
1815 :
1816 0 : Reformat();
1817 0 : }
1818 :
1819 0 : DateField::~DateField()
1820 : {
1821 0 : }
1822 :
1823 0 : bool DateField::PreNotify( NotifyEvent& rNEvt )
1824 : {
1825 0 : if ( (rNEvt.GetType() == EVENT_KEYINPUT) && IsStrictFormat() &&
1826 0 : ( GetExtDateFormat() != XTDATEF_SYSTEM_LONG ) &&
1827 0 : !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1828 : {
1829 0 : if ( ImplDateProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetExtDateFormat( true ), ImplGetLocaleDataWrapper() ) )
1830 0 : return true;
1831 : }
1832 :
1833 0 : return SpinField::PreNotify( rNEvt );
1834 : }
1835 :
1836 0 : bool DateField::Notify( NotifyEvent& rNEvt )
1837 : {
1838 0 : if ( rNEvt.GetType() == EVENT_GETFOCUS )
1839 0 : MarkToBeReformatted( false );
1840 0 : else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
1841 : {
1842 0 : if ( MustBeReformatted() )
1843 : {
1844 : // !!! We should find out why dates are treated differently than other fields (see
1845 : // also bug: 52384)
1846 :
1847 0 : bool bTextLen = !GetText().isEmpty();
1848 0 : if ( bTextLen || !IsEmptyFieldValueEnabled() )
1849 : {
1850 0 : if ( !ImplAllowMalformedInput() )
1851 0 : Reformat();
1852 : else
1853 : {
1854 0 : Date aDate( 0, 0, 0 );
1855 0 : if ( ImplDateGetValue( GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1856 : // even with strict text analysis, our text is a valid date -> do a complete
1857 : // reformat
1858 0 : Reformat();
1859 : }
1860 : }
1861 0 : else if ( !bTextLen && IsEmptyFieldValueEnabled() )
1862 : {
1863 0 : ResetLastDate();
1864 0 : SetEmptyFieldValueData( true );
1865 : }
1866 : }
1867 : }
1868 :
1869 0 : return SpinField::Notify( rNEvt );
1870 : }
1871 :
1872 0 : void DateField::DataChanged( const DataChangedEvent& rDCEvt )
1873 : {
1874 0 : SpinField::DataChanged( rDCEvt );
1875 :
1876 0 : if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & (SETTINGS_LOCALE|SETTINGS_MISC)) )
1877 : {
1878 0 : if ( IsDefaultLocale() && ( rDCEvt.GetFlags() & SETTINGS_LOCALE ) )
1879 0 : ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
1880 0 : ReformatAll();
1881 : }
1882 0 : }
1883 :
1884 0 : void DateField::Modify()
1885 : {
1886 0 : MarkToBeReformatted( true );
1887 0 : SpinField::Modify();
1888 0 : }
1889 :
1890 0 : void DateField::Up()
1891 : {
1892 0 : ImplDateSpinArea( true );
1893 0 : SpinField::Up();
1894 0 : }
1895 :
1896 0 : void DateField::Down()
1897 : {
1898 0 : ImplDateSpinArea( false );
1899 0 : SpinField::Down();
1900 0 : }
1901 :
1902 0 : void DateField::First()
1903 : {
1904 0 : ImplNewFieldValue( maFirst );
1905 0 : SpinField::First();
1906 0 : }
1907 :
1908 0 : void DateField::Last()
1909 : {
1910 0 : ImplNewFieldValue( maLast );
1911 0 : SpinField::Last();
1912 0 : }
1913 :
1914 0 : DateBox::DateBox( Window* pParent, WinBits nWinStyle ) :
1915 0 : ComboBox( pParent, nWinStyle )
1916 : {
1917 0 : SetField( this );
1918 0 : SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
1919 0 : Reformat();
1920 0 : }
1921 :
1922 0 : DateBox::~DateBox()
1923 : {
1924 0 : }
1925 :
1926 0 : bool DateBox::PreNotify( NotifyEvent& rNEvt )
1927 : {
1928 0 : if ( (rNEvt.GetType() == EVENT_KEYINPUT) && IsStrictFormat() &&
1929 0 : ( GetExtDateFormat() != XTDATEF_SYSTEM_LONG ) &&
1930 0 : !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1931 : {
1932 0 : if ( ImplDateProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetExtDateFormat( true ), ImplGetLocaleDataWrapper() ) )
1933 0 : return true;
1934 : }
1935 :
1936 0 : return ComboBox::PreNotify( rNEvt );
1937 : }
1938 :
1939 0 : void DateBox::DataChanged( const DataChangedEvent& rDCEvt )
1940 : {
1941 0 : ComboBox::DataChanged( rDCEvt );
1942 :
1943 0 : if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
1944 : {
1945 0 : if ( IsDefaultLocale() )
1946 0 : ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
1947 0 : ReformatAll();
1948 : }
1949 0 : }
1950 :
1951 0 : bool DateBox::Notify( NotifyEvent& rNEvt )
1952 : {
1953 0 : if ( rNEvt.GetType() == EVENT_GETFOCUS )
1954 0 : MarkToBeReformatted( false );
1955 0 : else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
1956 : {
1957 0 : if ( MustBeReformatted() )
1958 : {
1959 0 : bool bTextLen = !GetText().isEmpty();
1960 0 : if ( bTextLen || !IsEmptyFieldValueEnabled() )
1961 0 : Reformat();
1962 0 : else if ( !bTextLen && IsEmptyFieldValueEnabled() )
1963 : {
1964 0 : ResetLastDate();
1965 0 : SetEmptyFieldValueData( true );
1966 : }
1967 : }
1968 : }
1969 :
1970 0 : return ComboBox::Notify( rNEvt );
1971 : }
1972 :
1973 0 : void DateBox::Modify()
1974 : {
1975 0 : MarkToBeReformatted( true );
1976 0 : ComboBox::Modify();
1977 0 : }
1978 :
1979 0 : void DateBox::ReformatAll()
1980 : {
1981 0 : OUString aStr;
1982 0 : SetUpdateMode( false );
1983 0 : sal_uInt16 nEntryCount = GetEntryCount();
1984 0 : for ( sal_uInt16 i=0; i < nEntryCount; i++ )
1985 : {
1986 0 : ImplDateReformat( GetEntry( i ), aStr, GetFieldSettings() );
1987 0 : RemoveEntryAt(i);
1988 0 : InsertEntry( aStr, i );
1989 : }
1990 0 : DateFormatter::Reformat();
1991 0 : SetUpdateMode( true );
1992 0 : }
1993 :
1994 0 : static bool ImplTimeProcessKeyInput( Edit*, const KeyEvent& rKEvt,
1995 : bool bStrictFormat, bool bDuration,
1996 : TimeFieldFormat eFormat,
1997 : const LocaleDataWrapper& rLocaleDataWrapper )
1998 : {
1999 0 : sal_Unicode cChar = rKEvt.GetCharCode();
2000 :
2001 0 : if ( !bStrictFormat )
2002 0 : return false;
2003 : else
2004 : {
2005 0 : sal_uInt16 nGroup = rKEvt.GetKeyCode().GetGroup();
2006 0 : if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
2007 0 : (nGroup == KEYGROUP_MISC) ||
2008 0 : ((cChar >= '0') && (cChar <= '9')) ||
2009 0 : string::equals(rLocaleDataWrapper.getTimeSep(), cChar) ||
2010 0 : (rLocaleDataWrapper.getTimeAM().indexOf(cChar) != -1) ||
2011 0 : (rLocaleDataWrapper.getTimePM().indexOf(cChar) != -1) ||
2012 : // Accept AM/PM:
2013 0 : (cChar == 'a') || (cChar == 'A') || (cChar == 'm') || (cChar == 'M') || (cChar == 'p') || (cChar == 'P') ||
2014 0 : ((eFormat == TIMEF_100TH_SEC) && string::equals(rLocaleDataWrapper.getTime100SecSep(), cChar)) ||
2015 0 : ((eFormat == TIMEF_SEC_CS) && string::equals(rLocaleDataWrapper.getTime100SecSep(), cChar)) ||
2016 0 : (bDuration && (cChar == '-')) )
2017 0 : return false;
2018 : else
2019 0 : return true;
2020 : }
2021 : }
2022 :
2023 0 : static bool ImplIsOnlyDigits( const OUStringBuffer& _rStr )
2024 : {
2025 0 : const sal_Unicode* _pChr = _rStr.getStr();
2026 0 : for ( sal_Int32 i = 0; i < _rStr.getLength(); ++i, ++_pChr )
2027 : {
2028 0 : if ( *_pChr < '0' || *_pChr > '9' )
2029 0 : return false;
2030 : }
2031 0 : return true;
2032 : }
2033 :
2034 0 : static bool ImplIsValidTimePortion( bool _bSkipInvalidCharacters, const OUStringBuffer& _rStr )
2035 : {
2036 0 : if ( !_bSkipInvalidCharacters )
2037 : {
2038 0 : if ( ( _rStr.getLength() > 2 ) || _rStr.isEmpty() || !ImplIsOnlyDigits( _rStr ) )
2039 0 : return false;
2040 : }
2041 0 : return true;
2042 : }
2043 :
2044 0 : static bool ImplCutTimePortion( OUStringBuffer& _rStr, sal_Int32 _nSepPos, bool _bSkipInvalidCharacters, short* _pPortion )
2045 : {
2046 0 : OUString sPortion(_rStr.getStr(), _nSepPos );
2047 0 : _rStr = _nSepPos < _rStr.getLength()
2048 0 : ? _rStr.copy( _nSepPos + 1 ) : OUStringBuffer();
2049 :
2050 0 : if ( !ImplIsValidTimePortion( _bSkipInvalidCharacters, sPortion ) )
2051 0 : return false;
2052 0 : *_pPortion = (short)sPortion.toInt32();
2053 0 : return true;
2054 : }
2055 :
2056 0 : static bool ImplTimeGetValue( const OUString& rStr, Time& rTime,
2057 : TimeFieldFormat eFormat, bool bDuration,
2058 : const LocaleDataWrapper& rLocaleDataWrapper, bool _bSkipInvalidCharacters = true )
2059 : {
2060 0 : OUStringBuffer aStr = rStr;
2061 0 : short nHour = 0;
2062 0 : short nMinute = 0;
2063 0 : short nSecond = 0;
2064 0 : sal_Int64 nNanoSec = 0;
2065 0 : Time aTime( 0, 0, 0 );
2066 :
2067 0 : if ( rStr.isEmpty() )
2068 0 : return false;
2069 :
2070 : // Search for separators
2071 0 : if (!rLocaleDataWrapper.getTimeSep().isEmpty())
2072 : {
2073 0 : OUStringBuffer aSepStr(",.;:/");
2074 0 : if ( !bDuration )
2075 0 : aSepStr.append('-');
2076 :
2077 : // Replace characters above by the separator character
2078 0 : for (sal_Int32 i = 0; i < aSepStr.getLength(); ++i)
2079 : {
2080 0 : if (string::equals(rLocaleDataWrapper.getTimeSep(), aSepStr[i]))
2081 0 : continue;
2082 0 : for ( sal_Int32 j = 0; j < aStr.getLength(); j++ )
2083 : {
2084 0 : if (aStr[j] == aSepStr[i])
2085 0 : aStr[j] = rLocaleDataWrapper.getTimeSep()[0];
2086 : }
2087 0 : }
2088 : }
2089 :
2090 0 : bool bNegative = false;
2091 0 : sal_Int32 nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2092 0 : if ( aStr[0] == '-' )
2093 0 : bNegative = true;
2094 0 : if ( eFormat != TIMEF_SEC_CS )
2095 : {
2096 0 : if ( nSepPos < 0 )
2097 0 : nSepPos = aStr.getLength();
2098 0 : if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nHour ) )
2099 0 : return false;
2100 :
2101 0 : nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2102 0 : if ( !aStr.isEmpty() && aStr[0] == '-' )
2103 0 : bNegative = true;
2104 0 : if ( nSepPos >= 0 )
2105 : {
2106 0 : if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nMinute ) )
2107 0 : return false;
2108 :
2109 0 : nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2110 0 : if ( !aStr.isEmpty() && aStr[0] == '-' )
2111 0 : bNegative = true;
2112 0 : if ( nSepPos >= 0 )
2113 : {
2114 0 : if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nSecond ) )
2115 0 : return false;
2116 0 : if ( !aStr.isEmpty() && aStr[0] == '-' )
2117 0 : bNegative = true;
2118 0 : nNanoSec = aStr.toString().toInt64();
2119 : }
2120 : else
2121 0 : nSecond = (short)aStr.toString().toInt32();
2122 : }
2123 : else
2124 0 : nMinute = (short)aStr.toString().toInt32();
2125 : }
2126 0 : else if ( nSepPos < 0 )
2127 : {
2128 0 : nSecond = (short)aStr.toString().toInt32();
2129 0 : nMinute += nSecond / 60;
2130 0 : nSecond %= 60;
2131 0 : nHour += nMinute / 60;
2132 0 : nMinute %= 60;
2133 : }
2134 : else
2135 : {
2136 0 : nSecond = (short)aStr.copy( 0, nSepPos ).toString().toInt32();
2137 0 : aStr.remove( 0, nSepPos+1 );
2138 :
2139 0 : nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2140 0 : if ( !aStr.isEmpty() && aStr[0] == '-' )
2141 0 : bNegative = true;
2142 0 : if ( nSepPos >= 0 )
2143 : {
2144 0 : nMinute = nSecond;
2145 0 : nSecond = (short)aStr.copy( 0, nSepPos ).toString().toInt32();
2146 0 : aStr.remove( 0, nSepPos+1 );
2147 :
2148 0 : nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2149 0 : if ( !aStr.isEmpty() && aStr[0] == '-' )
2150 0 : bNegative = true;
2151 0 : if ( nSepPos >= 0 )
2152 : {
2153 0 : nHour = nMinute;
2154 0 : nMinute = nSecond;
2155 0 : nSecond = (short)aStr.copy( 0, nSepPos ).toString().toInt32();
2156 0 : aStr.remove( 0, nSepPos+1 );
2157 : }
2158 : else
2159 : {
2160 0 : nHour += nMinute / 60;
2161 0 : nMinute %= 60;
2162 : }
2163 : }
2164 : else
2165 : {
2166 0 : nMinute += nSecond / 60;
2167 0 : nSecond %= 60;
2168 0 : nHour += nMinute / 60;
2169 0 : nMinute %= 60;
2170 : }
2171 0 : nNanoSec = aStr.toString().toInt64();
2172 : }
2173 :
2174 0 : if ( nNanoSec )
2175 : {
2176 : assert(aStr.getLength() >= 1);
2177 :
2178 0 : sal_Int32 nLen = 1; // at least one digit, otherwise nNanoSec==0
2179 :
2180 0 : while ( aStr.getLength() > nLen && aStr[nLen] >= '0' && aStr[nLen] <= '9' )
2181 0 : nLen++;
2182 :
2183 0 : while ( nLen < 9)
2184 : {
2185 0 : nNanoSec *= 10;
2186 0 : ++nLen;
2187 : }
2188 0 : while ( nLen > 9 )
2189 : {
2190 : // round if negative?
2191 0 : nNanoSec = (nNanoSec + 5) / 10;
2192 0 : --nLen;
2193 : }
2194 : }
2195 :
2196 : assert(nNanoSec > -1000000000 && nNanoSec < 1000000000);
2197 0 : if ( (nMinute > 59) || (nSecond > 59) || (nNanoSec > 1000000000) )
2198 0 : return false;
2199 :
2200 0 : if ( eFormat == TIMEF_NONE )
2201 0 : nSecond = nNanoSec = 0;
2202 0 : else if ( eFormat == TIMEF_SEC )
2203 0 : nNanoSec = 0;
2204 :
2205 0 : if ( !bDuration )
2206 : {
2207 0 : if ( bNegative || (nHour < 0) || (nMinute < 0) ||
2208 0 : (nSecond < 0) || (nNanoSec < 0) )
2209 0 : return false;
2210 :
2211 0 : OUString aUpperCaseStr = aStr.toString().toAsciiUpperCase();
2212 0 : OUString aAM(rLocaleDataWrapper.getTimeAM().toAsciiUpperCase());
2213 0 : OUString aPM(rLocaleDataWrapper.getTimePM().toAsciiUpperCase());
2214 0 : OUString aAM2("AM"); // aAM is localized
2215 0 : OUString aPM2("PM"); // aPM is localized
2216 :
2217 0 : if ( (nHour < 12) && ( ( aUpperCaseStr.indexOf( aPM ) >= 0 ) || ( aUpperCaseStr.indexOf( aPM2 ) >= 0 ) ) )
2218 0 : nHour += 12;
2219 :
2220 0 : if ( (nHour == 12) && ( ( aUpperCaseStr.indexOf( aAM ) >= 0 ) || ( aUpperCaseStr.indexOf( aAM2 ) >= 0 ) ) )
2221 0 : nHour = 0;
2222 :
2223 0 : aTime = Time( (sal_uInt16)nHour, (sal_uInt16)nMinute, (sal_uInt16)nSecond,
2224 0 : (sal_uInt32)nNanoSec );
2225 : }
2226 : else
2227 : {
2228 : assert( !bNegative || (nHour < 0) || (nMinute < 0) ||
2229 : (nSecond < 0) || (nNanoSec < 0) );
2230 0 : if ( bNegative || (nHour < 0) || (nMinute < 0) ||
2231 0 : (nSecond < 0) || (nNanoSec < 0) )
2232 : {
2233 : // LEM TODO: this looks weird... I think buggy when parsing "05:-02:18"
2234 0 : bNegative = true;
2235 0 : nHour = nHour < 0 ? -nHour : nHour;
2236 0 : nMinute = nMinute < 0 ? -nMinute : nMinute;
2237 0 : nSecond = nSecond < 0 ? -nSecond : nSecond;
2238 0 : nNanoSec = nNanoSec < 0 ? -nNanoSec : nNanoSec;
2239 : }
2240 :
2241 0 : aTime = Time( (sal_uInt16)nHour, (sal_uInt16)nMinute, (sal_uInt16)nSecond,
2242 0 : (sal_uInt32)nNanoSec );
2243 0 : if ( bNegative )
2244 0 : aTime = -aTime;
2245 : }
2246 :
2247 0 : rTime = aTime;
2248 :
2249 0 : return true;
2250 : }
2251 :
2252 0 : bool TimeFormatter::ImplTimeReformat( const OUString& rStr, OUString& rOutStr )
2253 : {
2254 0 : Time aTime( 0, 0, 0 );
2255 0 : if ( !ImplTimeGetValue( rStr, aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() ) )
2256 0 : return true;
2257 :
2258 0 : Time aTempTime = aTime;
2259 0 : if ( aTempTime > GetMax() )
2260 0 : aTempTime = GetMax() ;
2261 0 : else if ( aTempTime < GetMin() )
2262 0 : aTempTime = GetMin();
2263 :
2264 0 : if ( GetErrorHdl().IsSet() && (aTime != aTempTime) )
2265 : {
2266 0 : maCorrectedTime = aTempTime;
2267 0 : if ( !GetErrorHdl().Call( this ) )
2268 : {
2269 0 : maCorrectedTime = Time( Time::SYSTEM );
2270 0 : return false;
2271 : }
2272 : else
2273 0 : maCorrectedTime = Time( Time::SYSTEM );
2274 : }
2275 :
2276 0 : bool bSecond = false;
2277 0 : bool b100Sec = false;
2278 0 : if ( meFormat != TIMEF_NONE )
2279 0 : bSecond = true;
2280 0 : if ( meFormat == TIMEF_100TH_SEC )
2281 0 : b100Sec = true;
2282 :
2283 0 : if ( meFormat == TIMEF_SEC_CS )
2284 : {
2285 0 : sal_uLong n = aTempTime.GetHour() * 3600L;
2286 0 : n += aTempTime.GetMin() * 60L;
2287 0 : n += aTempTime.GetSec();
2288 0 : rOutStr = OUString::number( n );
2289 0 : rOutStr += ImplGetLocaleDataWrapper().getTime100SecSep();
2290 0 : std::ostringstream ostr;
2291 0 : ostr.fill('0');
2292 0 : ostr.width(9);
2293 0 : ostr << aTempTime.GetNanoSec();
2294 0 : rOutStr += OUString::createFromAscii(ostr.str().c_str());
2295 : }
2296 0 : else if ( mbDuration )
2297 0 : rOutStr = ImplGetLocaleDataWrapper().getDuration( aTempTime, bSecond, b100Sec );
2298 : else
2299 : {
2300 0 : rOutStr = ImplGetLocaleDataWrapper().getTime( aTempTime, bSecond, b100Sec );
2301 0 : if ( GetTimeFormat() == HOUR_12 )
2302 : {
2303 0 : if ( aTempTime.GetHour() > 12 )
2304 : {
2305 0 : Time aT( aTempTime );
2306 0 : aT.SetHour( aT.GetHour() % 12 );
2307 0 : rOutStr = ImplGetLocaleDataWrapper().getTime( aT, bSecond, b100Sec );
2308 : }
2309 : // Don't use LocaleDataWrapper, we want AM/PM
2310 0 : if ( aTempTime.GetHour() < 12 )
2311 0 : rOutStr += "AM"; // ImplGetLocaleDataWrapper().getTimeAM();
2312 : else
2313 0 : rOutStr += "PM"; // ImplGetLocaleDataWrapper().getTimePM();
2314 : }
2315 : }
2316 :
2317 0 : return true;
2318 : }
2319 0 : bool TimeFormatter::ImplAllowMalformedInput() const
2320 : {
2321 0 : return !IsEnforceValidValue();
2322 : }
2323 :
2324 0 : void TimeField::ImplTimeSpinArea( bool bUp )
2325 : {
2326 0 : if ( GetField() )
2327 : {
2328 0 : sal_Int32 nTimeArea = 0;
2329 0 : Time aTime( GetTime() );
2330 0 : OUString aText( GetText() );
2331 0 : Selection aSelection( GetField()->GetSelection() );
2332 :
2333 : // Area search
2334 0 : if ( GetFormat() != TIMEF_SEC_CS )
2335 : {
2336 : //Which area is the cursor in of HH:MM:SS.TT
2337 0 : for ( sal_Int32 i = 1, nPos = 0; i <= 4; i++ )
2338 : {
2339 0 : sal_Int32 nPos1 = aText.indexOf( ImplGetLocaleDataWrapper().getTimeSep(), nPos );
2340 0 : sal_Int32 nPos2 = aText.indexOf( ImplGetLocaleDataWrapper().getTime100SecSep(), nPos );
2341 : //which ever comes first, bearing in mind that one might not be there
2342 0 : if (nPos1 >= 0 && nPos2 >= 0)
2343 0 : nPos = nPos1 < nPos2 ? nPos1 : nPos2;
2344 0 : else if (nPos1 >= 0)
2345 0 : nPos = nPos1;
2346 : else
2347 0 : nPos = nPos2;
2348 0 : if ( nPos < 0 || nPos >= aSelection.Max() )
2349 : {
2350 0 : nTimeArea = i;
2351 0 : break;
2352 : }
2353 : else
2354 0 : nPos++;
2355 : }
2356 : }
2357 : else
2358 : {
2359 0 : sal_Int32 nPos = aText.indexOf( ImplGetLocaleDataWrapper().getTime100SecSep() );
2360 0 : if ( nPos < 0 || nPos >= aSelection.Max() )
2361 0 : nTimeArea = 3;
2362 : else
2363 0 : nTimeArea = 4;
2364 : }
2365 :
2366 0 : if ( nTimeArea )
2367 : {
2368 0 : Time aAddTime( 0, 0, 0 );
2369 0 : if ( nTimeArea == 1 )
2370 0 : aAddTime = Time( 1, 0 );
2371 0 : else if ( nTimeArea == 2 )
2372 0 : aAddTime = Time( 0, 1 );
2373 0 : else if ( nTimeArea == 3 )
2374 0 : aAddTime = Time( 0, 0, 1 );
2375 0 : else if ( nTimeArea == 4 )
2376 0 : aAddTime = Time( 0, 0, 0, 1 );
2377 :
2378 0 : if ( !bUp )
2379 0 : aAddTime = -aAddTime;
2380 :
2381 0 : aTime += aAddTime;
2382 0 : if ( !IsDuration() )
2383 : {
2384 0 : Time aAbsMaxTime( 23, 59, 59, 999999999 );
2385 0 : if ( aTime > aAbsMaxTime )
2386 0 : aTime = aAbsMaxTime;
2387 0 : Time aAbsMinTime( 0, 0 );
2388 0 : if ( aTime < aAbsMinTime )
2389 0 : aTime = aAbsMinTime;
2390 : }
2391 0 : ImplNewFieldValue( aTime );
2392 0 : }
2393 :
2394 : }
2395 0 : }
2396 :
2397 0 : void TimeFormatter::ImplInit()
2398 : {
2399 0 : meFormat = TIMEF_NONE;
2400 0 : mbDuration = false;
2401 0 : mnTimeFormat = HOUR_24; // Should become a ExtTimeFieldFormat in next implementation, merge with mbDuration and meFormat
2402 0 : }
2403 :
2404 0 : TimeFormatter::TimeFormatter() :
2405 : maLastTime( 0, 0 ),
2406 : maMin( 0, 0 ),
2407 : maMax( 23, 59, 59, 999999999 ),
2408 : maCorrectedTime( Time::SYSTEM ),
2409 : mbEnforceValidValue( true ),
2410 0 : maFieldTime( 0, 0 )
2411 : {
2412 0 : ImplInit();
2413 0 : }
2414 :
2415 0 : void TimeFormatter::ImplLoadRes( const ResId& rResId )
2416 : {
2417 0 : ResMgr* pMgr = rResId.GetResMgr();
2418 0 : if( pMgr )
2419 : {
2420 0 : sal_uLong nMask = pMgr->ReadLong();
2421 :
2422 0 : if ( TIMEFORMATTER_MIN & nMask )
2423 : {
2424 0 : SetMin( Time( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) ) );
2425 0 : pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE *)pMgr->GetClass() ) );
2426 : }
2427 :
2428 0 : if ( TIMEFORMATTER_MAX & nMask )
2429 : {
2430 0 : SetMax( Time( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) ) );
2431 0 : pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE *)pMgr->GetClass() ) );
2432 : }
2433 :
2434 0 : if ( TIMEFORMATTER_TIMEFIELDFORMAT & nMask )
2435 0 : meFormat = (TimeFieldFormat)pMgr->ReadLong();
2436 :
2437 0 : if ( TIMEFORMATTER_DURATION & nMask )
2438 0 : mbDuration = pMgr->ReadShort() != 0;
2439 :
2440 0 : if ( TIMEFORMATTER_STRICTFORMAT & nMask )
2441 0 : SetStrictFormat( pMgr->ReadShort() != 0 );
2442 :
2443 0 : if ( TIMEFORMATTER_VALUE & nMask )
2444 : {
2445 0 : maFieldTime = Time( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
2446 0 : if ( maFieldTime > GetMax() )
2447 0 : maFieldTime = GetMax();
2448 0 : if ( maFieldTime < GetMin() )
2449 0 : maFieldTime = GetMin();
2450 0 : maLastTime = maFieldTime;
2451 :
2452 0 : pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE *)pMgr->GetClass() ) );
2453 : }
2454 : }
2455 0 : }
2456 :
2457 0 : TimeFormatter::~TimeFormatter()
2458 : {
2459 0 : }
2460 :
2461 0 : void TimeFormatter::ReformatAll()
2462 : {
2463 0 : Reformat();
2464 0 : }
2465 :
2466 0 : void TimeFormatter::SetMin( const Time& rNewMin )
2467 : {
2468 0 : maMin = rNewMin;
2469 0 : if ( !IsEmptyFieldValue() )
2470 0 : ReformatAll();
2471 0 : }
2472 :
2473 0 : void TimeFormatter::SetMax( const Time& rNewMax )
2474 : {
2475 0 : maMax = rNewMax;
2476 0 : if ( !IsEmptyFieldValue() )
2477 0 : ReformatAll();
2478 0 : }
2479 :
2480 0 : void TimeFormatter::SetTimeFormat( TimeFormatter::TimeFormat eNewFormat )
2481 : {
2482 0 : mnTimeFormat = sal::static_int_cast<sal_uInt16>(eNewFormat);
2483 0 : }
2484 :
2485 0 : TimeFormatter::TimeFormat TimeFormatter::GetTimeFormat() const
2486 : {
2487 0 : return (TimeFormat)mnTimeFormat;
2488 : }
2489 :
2490 0 : void TimeFormatter::SetFormat( TimeFieldFormat eNewFormat )
2491 : {
2492 0 : meFormat = eNewFormat;
2493 0 : ReformatAll();
2494 0 : }
2495 :
2496 0 : void TimeFormatter::SetDuration( bool bNewDuration )
2497 : {
2498 0 : mbDuration = bNewDuration;
2499 0 : ReformatAll();
2500 0 : }
2501 :
2502 0 : void TimeFormatter::SetTime( const Time& rNewTime )
2503 : {
2504 0 : SetUserTime( rNewTime );
2505 0 : maFieldTime = maLastTime;
2506 0 : SetEmptyFieldValueData( false );
2507 0 : }
2508 :
2509 0 : void TimeFormatter::ImplNewFieldValue( const Time& rTime )
2510 : {
2511 0 : if ( GetField() )
2512 : {
2513 0 : Selection aSelection = GetField()->GetSelection();
2514 0 : aSelection.Justify();
2515 0 : OUString aText = GetField()->GetText();
2516 :
2517 : // If selected until the end then keep it that way
2518 0 : if ( (sal_Int32)aSelection.Max() == aText.getLength() )
2519 : {
2520 0 : if ( !aSelection.Len() )
2521 0 : aSelection.Min() = SELECTION_MAX;
2522 0 : aSelection.Max() = SELECTION_MAX;
2523 : }
2524 :
2525 0 : Time aOldLastTime = maLastTime;
2526 0 : ImplSetUserTime( rTime, &aSelection );
2527 0 : maLastTime = aOldLastTime;
2528 :
2529 : // Modify at Edit is only set at KeyInput
2530 0 : if ( GetField()->GetText() != aText )
2531 : {
2532 0 : GetField()->SetModifyFlag();
2533 0 : GetField()->Modify();
2534 0 : }
2535 : }
2536 0 : }
2537 :
2538 0 : void TimeFormatter::ImplSetUserTime( const Time& rNewTime, Selection* pNewSelection )
2539 : {
2540 0 : Time aNewTime = rNewTime;
2541 0 : if ( aNewTime > GetMax() )
2542 0 : aNewTime = GetMax();
2543 0 : else if ( aNewTime < GetMin() )
2544 0 : aNewTime = GetMin();
2545 0 : maLastTime = aNewTime;
2546 :
2547 0 : if ( GetField() )
2548 : {
2549 0 : OUString aStr;
2550 0 : bool bSec = false;
2551 0 : bool b100Sec = false;
2552 0 : if ( meFormat != TIMEF_NONE )
2553 0 : bSec = true;
2554 0 : if ( meFormat == TIMEF_100TH_SEC || meFormat == TIMEF_SEC_CS )
2555 0 : b100Sec = true;
2556 0 : if ( meFormat == TIMEF_SEC_CS )
2557 : {
2558 0 : sal_uLong n = aNewTime.GetHour() * 3600L;
2559 0 : n += aNewTime.GetMin() * 60L;
2560 0 : n += aNewTime.GetSec();
2561 0 : aStr = OUString::number( n );
2562 0 : aStr += ImplGetLocaleDataWrapper().getTime100SecSep();
2563 0 : std::ostringstream ostr;
2564 0 : ostr.fill('0');
2565 0 : ostr.width(9);
2566 0 : ostr << aNewTime.GetNanoSec();
2567 0 : aStr += OUString::createFromAscii(ostr.str().c_str());
2568 : }
2569 0 : else if ( mbDuration )
2570 : {
2571 0 : aStr = ImplGetLocaleDataWrapper().getDuration( aNewTime, bSec, b100Sec );
2572 : }
2573 : else
2574 : {
2575 0 : aStr = ImplGetLocaleDataWrapper().getTime( aNewTime, bSec, b100Sec );
2576 0 : if ( GetTimeFormat() == HOUR_12 )
2577 : {
2578 0 : if ( aNewTime.GetHour() > 12 )
2579 : {
2580 0 : Time aT( aNewTime );
2581 0 : aT.SetHour( aT.GetHour() % 12 );
2582 0 : aStr = ImplGetLocaleDataWrapper().getTime( aT, bSec, b100Sec );
2583 : }
2584 : // Don't use LocaleDataWrapper, we want AM/PM
2585 0 : if ( aNewTime.GetHour() < 12 )
2586 0 : aStr += "AM"; // ImplGetLocaleDataWrapper().getTimeAM();
2587 : else
2588 0 : aStr += "PM"; // ImplGetLocaleDataWrapper().getTimePM();
2589 : }
2590 : }
2591 :
2592 0 : ImplSetText( aStr, pNewSelection );
2593 : }
2594 0 : }
2595 :
2596 0 : void TimeFormatter::SetUserTime( const Time& rNewTime )
2597 : {
2598 0 : ImplSetUserTime( rNewTime );
2599 0 : }
2600 :
2601 0 : Time TimeFormatter::GetTime() const
2602 : {
2603 0 : Time aTime( 0, 0, 0 );
2604 :
2605 0 : if ( GetField() )
2606 : {
2607 0 : bool bAllowMailformed = ImplAllowMalformedInput();
2608 0 : if ( ImplTimeGetValue( GetField()->GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), !bAllowMailformed ) )
2609 : {
2610 0 : if ( aTime > GetMax() )
2611 0 : aTime = GetMax();
2612 0 : else if ( aTime < GetMin() )
2613 0 : aTime = GetMin();
2614 : }
2615 : else
2616 : {
2617 0 : if ( bAllowMailformed )
2618 0 : aTime = GetInvalidTime();
2619 : else
2620 0 : aTime = maLastTime;
2621 : }
2622 : }
2623 :
2624 0 : return aTime;
2625 : }
2626 :
2627 0 : void TimeFormatter::Reformat()
2628 : {
2629 0 : if ( !GetField() )
2630 0 : return;
2631 :
2632 0 : if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
2633 0 : return;
2634 :
2635 0 : OUString aStr;
2636 0 : bool bOK = ImplTimeReformat( GetField()->GetText(), aStr );
2637 0 : if ( !bOK )
2638 0 : return;
2639 :
2640 0 : if ( !aStr.isEmpty() )
2641 : {
2642 0 : ImplSetText( aStr );
2643 0 : ImplTimeGetValue( aStr, maLastTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() );
2644 : }
2645 : else
2646 0 : SetTime( maLastTime );
2647 : }
2648 :
2649 0 : TimeField::TimeField( Window* pParent, WinBits nWinStyle ) :
2650 : SpinField( pParent, nWinStyle ),
2651 0 : maFirst( GetMin() ),
2652 0 : maLast( GetMax() )
2653 : {
2654 0 : SetField( this );
2655 0 : SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, false, false ) );
2656 0 : Reformat();
2657 0 : }
2658 :
2659 0 : TimeField::TimeField( Window* pParent, const ResId& rResId ) :
2660 : SpinField( WINDOW_TIMEFIELD ),
2661 0 : maFirst( GetMin() ),
2662 0 : maLast( GetMax() )
2663 : {
2664 0 : rResId.SetRT( RSC_TIMEFIELD );
2665 0 : WinBits nStyle = ImplInitRes( rResId );
2666 0 : SpinField::ImplInit( pParent, nStyle );
2667 0 : SetField( this );
2668 0 : SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, false, false ) );
2669 0 : ImplLoadRes( rResId );
2670 :
2671 0 : if ( !(nStyle & WB_HIDE ) )
2672 0 : Show();
2673 0 : }
2674 :
2675 0 : void TimeField::ImplLoadRes( const ResId& rResId )
2676 : {
2677 0 : SpinField::ImplLoadRes( rResId );
2678 0 : ResMgr* pMgr = rResId.GetResMgr();
2679 0 : if( pMgr )
2680 : {
2681 0 : TimeFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
2682 :
2683 0 : sal_uLong nMask = ReadLongRes();
2684 :
2685 0 : if ( TIMEFIELD_FIRST & nMask )
2686 : {
2687 0 : maFirst = Time( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
2688 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
2689 : }
2690 0 : if ( TIMEFIELD_LAST & nMask )
2691 : {
2692 0 : maLast = Time( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
2693 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
2694 : }
2695 : }
2696 :
2697 0 : Reformat();
2698 0 : }
2699 :
2700 0 : TimeField::~TimeField()
2701 : {
2702 0 : }
2703 :
2704 0 : bool TimeField::PreNotify( NotifyEvent& rNEvt )
2705 : {
2706 0 : if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
2707 : {
2708 0 : if ( ImplTimeProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
2709 0 : return true;
2710 : }
2711 :
2712 0 : return SpinField::PreNotify( rNEvt );
2713 : }
2714 :
2715 0 : bool TimeField::Notify( NotifyEvent& rNEvt )
2716 : {
2717 0 : if ( rNEvt.GetType() == EVENT_GETFOCUS )
2718 0 : MarkToBeReformatted( false );
2719 0 : else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
2720 : {
2721 0 : if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
2722 : {
2723 0 : if ( !ImplAllowMalformedInput() )
2724 0 : Reformat();
2725 : else
2726 : {
2727 0 : Time aTime( 0, 0, 0 );
2728 0 : if ( ImplTimeGetValue( GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), false ) )
2729 : // even with strict text analysis, our text is a valid time -> do a complete
2730 : // reformat
2731 0 : Reformat();
2732 : }
2733 : }
2734 : }
2735 :
2736 0 : return SpinField::Notify( rNEvt );
2737 : }
2738 :
2739 0 : void TimeField::DataChanged( const DataChangedEvent& rDCEvt )
2740 : {
2741 0 : SpinField::DataChanged( rDCEvt );
2742 :
2743 0 : if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
2744 : {
2745 0 : if ( IsDefaultLocale() )
2746 0 : ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
2747 0 : ReformatAll();
2748 : }
2749 0 : }
2750 :
2751 0 : void TimeField::Modify()
2752 : {
2753 0 : MarkToBeReformatted( true );
2754 0 : SpinField::Modify();
2755 0 : }
2756 :
2757 0 : void TimeField::Up()
2758 : {
2759 0 : ImplTimeSpinArea( true );
2760 0 : SpinField::Up();
2761 0 : }
2762 :
2763 0 : void TimeField::Down()
2764 : {
2765 0 : ImplTimeSpinArea( false );
2766 0 : SpinField::Down();
2767 0 : }
2768 :
2769 0 : void TimeField::First()
2770 : {
2771 0 : ImplNewFieldValue( maFirst );
2772 0 : SpinField::First();
2773 0 : }
2774 :
2775 0 : void TimeField::Last()
2776 : {
2777 0 : ImplNewFieldValue( maLast );
2778 0 : SpinField::Last();
2779 0 : }
2780 :
2781 0 : void TimeField::SetExtFormat( ExtTimeFieldFormat eFormat )
2782 : {
2783 0 : switch ( eFormat )
2784 : {
2785 : case EXTTIMEF_24H_SHORT:
2786 : {
2787 0 : SetTimeFormat( HOUR_24 );
2788 0 : SetDuration( false );
2789 0 : SetFormat( TIMEF_NONE );
2790 : }
2791 0 : break;
2792 : case EXTTIMEF_24H_LONG:
2793 : {
2794 0 : SetTimeFormat( HOUR_24 );
2795 0 : SetDuration( false );
2796 0 : SetFormat( TIMEF_SEC );
2797 : }
2798 0 : break;
2799 : case EXTTIMEF_12H_SHORT:
2800 : {
2801 0 : SetTimeFormat( HOUR_12 );
2802 0 : SetDuration( false );
2803 0 : SetFormat( TIMEF_NONE );
2804 : }
2805 0 : break;
2806 : case EXTTIMEF_12H_LONG:
2807 : {
2808 0 : SetTimeFormat( HOUR_12 );
2809 0 : SetDuration( false );
2810 0 : SetFormat( TIMEF_SEC );
2811 : }
2812 0 : break;
2813 : case EXTTIMEF_DURATION_SHORT:
2814 : {
2815 0 : SetDuration( true );
2816 0 : SetFormat( TIMEF_NONE );
2817 : }
2818 0 : break;
2819 : case EXTTIMEF_DURATION_LONG:
2820 : {
2821 0 : SetDuration( true );
2822 0 : SetFormat( TIMEF_SEC );
2823 : }
2824 0 : break;
2825 : default: OSL_FAIL( "ExtTimeFieldFormat unknown!" );
2826 : }
2827 :
2828 0 : if ( GetField() && !GetField()->GetText().isEmpty() )
2829 0 : SetUserTime( GetTime() );
2830 0 : ReformatAll();
2831 0 : }
2832 :
2833 0 : TimeBox::TimeBox( Window* pParent, WinBits nWinStyle ) :
2834 0 : ComboBox( pParent, nWinStyle )
2835 : {
2836 0 : SetField( this );
2837 0 : SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, false, false ) );
2838 0 : Reformat();
2839 0 : }
2840 :
2841 0 : TimeBox::~TimeBox()
2842 : {
2843 0 : }
2844 :
2845 0 : bool TimeBox::PreNotify( NotifyEvent& rNEvt )
2846 : {
2847 0 : if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
2848 : {
2849 0 : if ( ImplTimeProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
2850 0 : return true;
2851 : }
2852 :
2853 0 : return ComboBox::PreNotify( rNEvt );
2854 : }
2855 :
2856 0 : bool TimeBox::Notify( NotifyEvent& rNEvt )
2857 : {
2858 0 : if ( rNEvt.GetType() == EVENT_GETFOCUS )
2859 0 : MarkToBeReformatted( false );
2860 0 : else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
2861 : {
2862 0 : if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
2863 0 : Reformat();
2864 : }
2865 :
2866 0 : return ComboBox::Notify( rNEvt );
2867 : }
2868 :
2869 0 : void TimeBox::DataChanged( const DataChangedEvent& rDCEvt )
2870 : {
2871 0 : ComboBox::DataChanged( rDCEvt );
2872 :
2873 0 : if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
2874 : {
2875 0 : if ( IsDefaultLocale() )
2876 0 : ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
2877 0 : ReformatAll();
2878 : }
2879 0 : }
2880 :
2881 0 : void TimeBox::Modify()
2882 : {
2883 0 : MarkToBeReformatted( true );
2884 0 : ComboBox::Modify();
2885 0 : }
2886 :
2887 0 : void TimeBox::ReformatAll()
2888 : {
2889 0 : OUString aStr;
2890 0 : SetUpdateMode( false );
2891 0 : sal_uInt16 nEntryCount = GetEntryCount();
2892 0 : for ( sal_uInt16 i=0; i < nEntryCount; i++ )
2893 : {
2894 0 : ImplTimeReformat( GetEntry( i ), aStr );
2895 0 : RemoveEntryAt(i);
2896 0 : InsertEntry( aStr, i );
2897 : }
2898 0 : TimeFormatter::Reformat();
2899 0 : SetUpdateMode( true );
2900 0 : }
2901 :
2902 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|