xref: /aoo42x/main/vcl/source/control/field2.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 #include <tools/debug.hxx>
31 
32 #include <tools/rc.h>
33 
34 #include <vcl/svapp.hxx>
35 #include <vcl/sound.hxx>
36 #include <vcl/event.hxx>
37 #include <vcl/field.hxx>
38 #include <vcl/unohelp.hxx>
39 
40 #include <svdata.hxx>
41 
42 #include <i18npool/mslangid.hxx>
43 
44 #include <com/sun/star/lang/Locale.hpp>
45 #include <com/sun/star/i18n/XCharacterClassification.hpp>
46 #include <com/sun/star/i18n/KCharacterType.hpp>
47 
48 
49 #include <unotools/localedatawrapper.hxx>
50 #include <unotools/calendarwrapper.hxx>
51 #include <unotools/charclass.hxx>
52 #include <unotools/misccfg.hxx>
53 
54 using namespace ::com::sun::star;
55 
56 // =======================================================================
57 
58 #define EDITMASK_LITERAL       'L'
59 #define EDITMASK_ALPHA         'a'
60 #define EDITMASK_UPPERALPHA    'A'
61 #define EDITMASK_ALPHANUM      'c'
62 #define EDITMASK_UPPERALPHANUM 'C'
63 #define EDITMASK_NUM           'N'
64 #define EDITMASK_NUMSPACE      'n'
65 #define EDITMASK_ALLCHAR       'x'
66 #define EDITMASK_UPPERALLCHAR  'X'
67 
68 uno::Reference< i18n::XCharacterClassification > ImplGetCharClass()
69 {
70     static uno::Reference< i18n::XCharacterClassification > xCharClass;
71     if ( !xCharClass.is() )
72         xCharClass = vcl::unohelper::CreateCharacterClassification();
73 
74     return xCharClass;
75 }
76 
77 // -----------------------------------------------------------------------
78 
79 static sal_Unicode* ImplAddString( sal_Unicode* pBuf, const String& rStr )
80 {
81 	if ( rStr.Len() == 1 )
82 		*pBuf++ = rStr.GetChar(0);
83 	else if ( rStr.Len() == 0 )
84 		;
85 	else
86 	{
87 		memcpy( pBuf, rStr.GetBuffer(), rStr.Len() * sizeof(sal_Unicode) );
88 		pBuf += rStr.Len();
89 	}
90 	return pBuf;
91 }
92 
93 // -----------------------------------------------------------------------
94 
95 static sal_Unicode* ImplAddNum( sal_Unicode* pBuf, sal_uLong nNumber, int nMinLen )
96 {
97 	// fill temp buffer with digits
98     sal_Unicode aTempBuf[30];
99     sal_Unicode* pTempBuf = aTempBuf;
100     do
101     {
102         *pTempBuf = (sal_Unicode)(nNumber % 10) + '0';
103         pTempBuf++;
104         nNumber /= 10;
105         if ( nMinLen )
106             nMinLen--;
107     }
108     while ( nNumber );
109 
110     // fill with zeros up to the minimal length
111     while ( nMinLen > 0 )
112     {
113         *pBuf = '0';
114         pBuf++;
115         nMinLen--;
116     }
117 
118     // copy temp buffer to real buffer
119     do
120     {
121         pTempBuf--;
122         *pBuf = *pTempBuf;
123         pBuf++;
124     }
125     while ( pTempBuf != aTempBuf );
126 
127     return pBuf;
128 }
129 
130 // -----------------------------------------------------------------------
131 
132 static sal_uInt16 ImplGetNum( const sal_Unicode*& rpBuf, sal_Bool& rbError )
133 {
134     if ( !*rpBuf )
135     {
136         rbError = sal_True;
137         return 0;
138     }
139 
140     sal_uInt16 nNumber = 0;
141     while( ( *rpBuf >= '0' ) && ( *rpBuf <= '9' ) )
142     {
143         nNumber *= 10;
144         nNumber += *rpBuf - '0';
145         rpBuf++;
146     }
147 
148     return nNumber;
149 }
150 
151 // -----------------------------------------------------------------------
152 
153 static void ImplSkipDelimiters( const sal_Unicode*& rpBuf )
154 {
155     while( ( *rpBuf == ',' ) || ( *rpBuf == '.' ) || ( *rpBuf == ';' ) ||
156            ( *rpBuf == ':' ) || ( *rpBuf == '-' ) || ( *rpBuf == '/' ) )
157     {
158         rpBuf++;
159     }
160 }
161 
162 // -----------------------------------------------------------------------
163 
164 static int ImplIsPatternChar( xub_Unicode cChar, sal_Char cEditMask )
165 {
166     sal_Int32 nType = 0;
167 
168     try
169 	{
170         String aCharStr( cChar );
171         nType = ImplGetCharClass()->getStringType( aCharStr, 0, aCharStr.Len(), Application::GetSettings().GetLocale() );
172     }
173     catch ( ::com::sun::star::uno::Exception& )
174     {
175 		DBG_ERRORFILE( "ImplIsPatternChar: Exception caught!" );
176 		return sal_False;
177 	}
178 
179     if ( (cEditMask == EDITMASK_ALPHA) || (cEditMask == EDITMASK_UPPERALPHA) )
180     {
181         if( !CharClass::isLetterType( nType ) )
182             return sal_False;
183     }
184     else if ( cEditMask == EDITMASK_NUM )
185     {
186         if( !CharClass::isNumericType( nType ) )
187             return sal_False;
188     }
189     else if ( (cEditMask == EDITMASK_ALPHANUM) || (cEditMask == EDITMASK_UPPERALPHANUM) )
190     {
191         if( !CharClass::isLetterNumericType( nType ) )
192             return sal_False;
193     }
194     else if ( (cEditMask == EDITMASK_ALLCHAR) || (cEditMask == EDITMASK_UPPERALLCHAR) )
195     {
196         if ( cChar < 32 )
197             return sal_False;
198     }
199     else if ( cEditMask == EDITMASK_NUMSPACE )
200     {
201         if ( !CharClass::isNumericType( nType ) && ( cChar != ' ' ) )
202             return sal_False;
203     }
204     else
205         return sal_False;
206 
207     return sal_True;
208 }
209 
210 // -----------------------------------------------------------------------
211 
212 static xub_Unicode ImplPatternChar( xub_Unicode cChar, sal_Char cEditMask )
213 {
214     if ( ImplIsPatternChar( cChar, cEditMask ) )
215     {
216         if ( (cEditMask == EDITMASK_UPPERALPHA) ||
217              (cEditMask == EDITMASK_UPPERALPHANUM) ||
218              ( cEditMask == EDITMASK_UPPERALLCHAR ) )
219         {
220             cChar = ImplGetCharClass()->toUpper( String(cChar),0,1,Application::GetSettings().GetLocale() )[0];
221         }
222         return cChar;
223     }
224     else
225         return 0;
226 }
227 
228 // -----------------------------------------------------------------------
229 
230 static int ImplKommaPointCharEqual( xub_Unicode c1, xub_Unicode c2 )
231 {
232     if ( c1 == c2 )
233         return sal_True;
234     else if ( ((c1 == '.') || (c1 == ',')) &&
235               ((c2 == '.') || (c2 == ',')) )
236         return sal_True;
237     else
238         return sal_False;
239 }
240 
241 // -----------------------------------------------------------------------
242 
243 static XubString ImplPatternReformat( const XubString& rStr,
244                                       const ByteString& rEditMask,
245                                       const XubString& rLiteralMask,
246                                       sal_uInt16 nFormatFlags )
247 {
248     if ( !rEditMask.Len() )
249         return rStr;
250 
251     XubString   aStr    = rStr;
252     XubString   aOutStr = rLiteralMask;
253     xub_Unicode cTempChar;
254     xub_Unicode cChar;
255     xub_Unicode cLiteral;
256     sal_Char    cMask;
257     xub_StrLen  nStrIndex = 0;
258     xub_StrLen  i = 0;
259     xub_StrLen  n;
260 
261     while ( i < rEditMask.Len() )
262     {
263         if ( nStrIndex >= aStr.Len() )
264             break;
265 
266         cChar = aStr.GetChar(nStrIndex);
267         cLiteral = rLiteralMask.GetChar(i);
268         cMask = rEditMask.GetChar(i);
269 
270         // Aktuelle Position ein Literal
271         if ( cMask == EDITMASK_LITERAL )
272         {
273             // Wenn es das Literal-Zeichen ist, uebernehmen, ansonsten
274             // ignorieren, da es das naechste gueltige Zeichen vom String
275             // sein kann
276             if ( ImplKommaPointCharEqual( cChar, cLiteral ) )
277                 nStrIndex++;
278             else
279             {
280                 // Ansonsten testen wir, ob es ein ungueltiges Zeichen ist.
281                 // Dies ist dann der Fall, wenn es nicht in das Muster
282                 // des naechsten nicht Literal-Zeichens passt
283                 n = i+1;
284                 while ( n < rEditMask.Len() )
285                 {
286                     if ( rEditMask.GetChar(n) != EDITMASK_LITERAL )
287                     {
288                         if ( !ImplIsPatternChar( cChar, rEditMask.GetChar(n) ) )
289                             nStrIndex++;
290                         break;
291                     }
292 
293                     n++;
294                 }
295             }
296         }
297         else
298         {
299             // Gueltiges Zeichen an der Stelle
300             cTempChar = ImplPatternChar( cChar, cMask );
301             if ( cTempChar )
302             {
303                 // dann Zeichen uebernehmen
304                 aOutStr.SetChar( i, cTempChar );
305                 nStrIndex++;
306             }
307             else
308             {
309                 // Wenn es das Literalzeichen ist, uebernehmen
310                 if ( cLiteral == cChar )
311                     nStrIndex++;
312                 else
313                 {
314                     // Wenn das ungueltige Zeichen das naechste Literalzeichen
315                     // sein kann, dann springen wir bis dahin vor, ansonten
316                     // das Zeichen ignorieren
317                     // Nur machen, wenn leere Literale erlaubt sind
318                     if ( nFormatFlags & PATTERN_FORMAT_EMPTYLITERALS )
319                     {
320                         n = i;
321                         while ( n < rEditMask.Len() )
322                         {
323                             if ( rEditMask.GetChar( n ) == EDITMASK_LITERAL )
324                             {
325                                 if ( ImplKommaPointCharEqual( cChar, rLiteralMask.GetChar( n ) ) )
326                                     i = n+1;
327 
328                                 break;
329                             }
330 
331                             n++;
332                         }
333                     }
334 
335                     nStrIndex++;
336                     continue;
337                 }
338             }
339         }
340 
341         i++;
342     }
343 
344     return aOutStr;
345 }
346 
347 // -----------------------------------------------------------------------
348 
349 static void ImplPatternMaxPos( const XubString rStr, const ByteString& rEditMask,
350                                sal_uInt16 nFormatFlags, sal_Bool bSameMask,
351                                sal_uInt16 nCursorPos, sal_uInt16& rPos )
352 {
353 
354     // Letzte Position darf nicht groesser als der enthaltene String sein
355     xub_StrLen nMaxPos = rStr.Len();
356 
357     // Wenn keine leeren Literale erlaubt sind, auch Leerzeichen
358     // am Ende ignorieren
359     if ( bSameMask && !(nFormatFlags & PATTERN_FORMAT_EMPTYLITERALS) )
360     {
361         while ( nMaxPos )
362         {
363             if ( (rEditMask.GetChar(nMaxPos-1) != EDITMASK_LITERAL) &&
364                  (rStr.GetChar(nMaxPos-1) != ' ') )
365                 break;
366             nMaxPos--;
367         }
368 
369         // Wenn wir vor einem Literal stehen, dann solange weitersuchen,
370         // bis erste Stelle nach Literal
371         xub_StrLen nTempPos = nMaxPos;
372         while ( nTempPos < rEditMask.Len() )
373         {
374             if ( rEditMask.GetChar(nTempPos) != EDITMASK_LITERAL )
375             {
376                 nMaxPos = nTempPos;
377                 break;
378             }
379             nTempPos++;
380         }
381     }
382 
383     if ( rPos > nMaxPos )
384         rPos = nMaxPos;
385     // Zeichen sollte nicht nach links wandern
386     if ( rPos < nCursorPos )
387         rPos = nCursorPos;
388 }
389 
390 // -----------------------------------------------------------------------
391 
392 static void ImplPatternProcessStrictModify( Edit* pEdit,
393                                             const ByteString& rEditMask,
394                                             const XubString& rLiteralMask,
395                                             sal_uInt16 nFormatFlags, sal_Bool bSameMask )
396 {
397     XubString aText = pEdit->GetText();
398 
399     // Leerzeichen am Anfang entfernen
400     if ( bSameMask && !(nFormatFlags & PATTERN_FORMAT_EMPTYLITERALS) )
401     {
402         xub_StrLen i = 0;
403         xub_StrLen nMaxLen = aText.Len();
404         while ( i < nMaxLen )
405         {
406             if ( (rEditMask.GetChar( i ) != EDITMASK_LITERAL) &&
407                  (aText.GetChar( i ) != ' ') )
408                 break;
409 
410             i++;
411         }
412         // Alle Literalzeichen beibehalten
413         while ( i && (rEditMask.GetChar( i ) == EDITMASK_LITERAL) )
414             i--;
415         aText.Erase( 0, i );
416     }
417 
418     XubString aNewText = ImplPatternReformat( aText, rEditMask, rLiteralMask, nFormatFlags );
419     if ( aNewText != aText )
420     {
421         // Selection so anpassen, das diese wenn sie vorher am Ende
422         // stand, immer noch am Ende steht
423         Selection aSel = pEdit->GetSelection();
424         sal_uLong nMaxSel = Max( aSel.Min(), aSel.Max() );
425         if ( nMaxSel >= aText.Len() )
426         {
427             xub_StrLen nMaxPos = aNewText.Len();
428             ImplPatternMaxPos( aNewText, rEditMask, nFormatFlags, bSameMask, (xub_StrLen)nMaxSel, nMaxPos );
429             if ( aSel.Min() == aSel.Max() )
430             {
431                 aSel.Min() = nMaxPos;
432                 aSel.Max() = aSel.Min();
433             }
434             else if ( aSel.Min() > aSel.Max() )
435                 aSel.Min() = nMaxPos;
436             else
437                 aSel.Max() = nMaxPos;
438         }
439         pEdit->SetText( aNewText, aSel );
440     }
441 }
442 
443 // -----------------------------------------------------------------------
444 
445 static xub_StrLen ImplPatternLeftPos( const ByteString& rEditMask, xub_StrLen nCursorPos )
446 {
447     // Vorheriges Zeichen suchen, was kein Literal ist
448     xub_StrLen nNewPos = nCursorPos;
449     xub_StrLen nTempPos = nNewPos;
450     while ( nTempPos )
451     {
452         if ( rEditMask.GetChar(nTempPos-1) != EDITMASK_LITERAL )
453         {
454             nNewPos = nTempPos-1;
455             break;
456         }
457         nTempPos--;
458     }
459     return nNewPos;
460 }
461 
462 // -----------------------------------------------------------------------
463 
464 static xub_StrLen ImplPatternRightPos( const XubString& rStr, const ByteString& rEditMask,
465                                        sal_uInt16 nFormatFlags, sal_Bool bSameMask,
466                                        xub_StrLen nCursorPos )
467 {
468     // Naechstes Zeichen suchen, was kein Literal ist
469     xub_StrLen nNewPos = nCursorPos;
470     xub_StrLen nTempPos = nNewPos;
471     while ( nTempPos < rEditMask.Len() )
472     {
473         if ( rEditMask.GetChar(nTempPos+1) != EDITMASK_LITERAL )
474         {
475             nNewPos = nTempPos+1;
476             break;
477         }
478         nTempPos++;
479     }
480     ImplPatternMaxPos( rStr, rEditMask, nFormatFlags, bSameMask, nCursorPos, nNewPos );
481     return nNewPos;
482 }
483 
484 // -----------------------------------------------------------------------
485 
486 static sal_Bool ImplPatternProcessKeyInput( Edit* pEdit, const KeyEvent& rKEvt,
487                                         const ByteString& rEditMask,
488                                         const XubString& rLiteralMask,
489                                         sal_Bool bStrictFormat,
490                                         sal_uInt16 nFormatFlags,
491                                         sal_Bool bSameMask,
492                                         sal_Bool& rbInKeyInput )
493 {
494     if ( !rEditMask.Len() || !bStrictFormat )
495         return sal_False;
496 
497     Selection   aOldSel     = pEdit->GetSelection();
498     KeyCode     aCode       = rKEvt.GetKeyCode();
499     xub_Unicode cChar       = rKEvt.GetCharCode();
500     sal_uInt16      nKeyCode    = aCode.GetCode();
501     sal_Bool        bShift      = aCode.IsShift();
502     xub_StrLen  nCursorPos  = (xub_StrLen)aOldSel.Max();
503     xub_StrLen  nNewPos;
504     xub_StrLen  nTempPos;
505 
506     if ( nKeyCode && !aCode.IsMod1() && !aCode.IsMod2() )
507     {
508         if ( nKeyCode == KEY_LEFT )
509         {
510             Selection aSel( ImplPatternLeftPos( rEditMask, nCursorPos ) );
511             if ( bShift )
512                 aSel.Min() = aOldSel.Min();
513             pEdit->SetSelection( aSel );
514             return sal_True;
515         }
516         else if ( nKeyCode == KEY_RIGHT )
517         {
518             // Hier nehmen wir Selectionsanfang als minimum, da falls durch
519             // Focus alles selektiert ist, ist eine kleine Position schon
520             // erlaubt.
521             Selection aSel( aOldSel );
522             aSel.Justify();
523             nCursorPos = (xub_StrLen)aSel.Min();
524             aSel.Max() = ImplPatternRightPos( pEdit->GetText(), rEditMask, nFormatFlags, bSameMask, nCursorPos );
525             if ( bShift )
526                 aSel.Min() = aOldSel.Min();
527             else
528                 aSel.Min() = aSel.Max();
529             pEdit->SetSelection( aSel );
530             return sal_True;
531         }
532         else if ( nKeyCode == KEY_HOME )
533         {
534             // Home ist Position des ersten nicht literalen Zeichens
535             nNewPos = 0;
536             while ( (nNewPos < rEditMask.Len()) &&
537                     (rEditMask.GetChar(nNewPos) == EDITMASK_LITERAL) )
538                 nNewPos++;
539             // Home sollte nicht nach rechts wandern
540             if ( nCursorPos < nNewPos )
541                 nNewPos = nCursorPos;
542             Selection aSel( nNewPos );
543             if ( bShift )
544                 aSel.Min() = aOldSel.Min();
545             pEdit->SetSelection( aSel );
546             return sal_True;
547         }
548         else if ( nKeyCode == KEY_END )
549         {
550             // End ist die Position des letzten nicht literalen Zeichens
551             nNewPos = rEditMask.Len();
552             while ( nNewPos &&
553                     (rEditMask.GetChar(nNewPos-1) == EDITMASK_LITERAL) )
554                 nNewPos--;
555             // Hier nehmen wir Selectionsanfang als minimum, da falls durch
556             // Focus alles selektiert ist, ist eine kleine Position schon
557             // erlaubt.
558             Selection aSel( aOldSel );
559             aSel.Justify();
560             nCursorPos = (xub_StrLen)aSel.Min();
561             ImplPatternMaxPos( pEdit->GetText(), rEditMask, nFormatFlags, bSameMask, nCursorPos, nNewPos );
562             aSel.Max() = nNewPos;
563             if ( bShift )
564                 aSel.Min() = aOldSel.Min();
565             else
566                 aSel.Min() = aSel.Max();
567             pEdit->SetSelection( aSel );
568             return sal_True;
569         }
570         else if ( (nKeyCode == KEY_BACKSPACE) || (nKeyCode == KEY_DELETE) )
571         {
572             XubString   aStr( pEdit->GetText() );
573             XubString   aOldStr = aStr;
574             Selection   aSel = aOldSel;
575 
576             aSel.Justify();
577             nNewPos = (xub_StrLen)aSel.Min();
578 
579             // Wenn Selection, dann diese Loeschen
580             if ( aSel.Len() )
581             {
582                 if ( bSameMask )
583                     aStr.Erase( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() );
584                 else
585                 {
586                     XubString aRep = rLiteralMask.Copy( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() );
587                     aStr.Replace( (xub_StrLen)aSel.Min(), aRep.Len(), aRep );
588                 }
589             }
590             else
591             {
592                 if ( nKeyCode == KEY_BACKSPACE )
593                 {
594                     nTempPos = nNewPos;
595                     nNewPos = ImplPatternLeftPos( rEditMask, nTempPos );
596                 }
597                 else
598                     nTempPos = ImplPatternRightPos( aStr, rEditMask, nFormatFlags, bSameMask, nNewPos );
599 
600                 if ( nNewPos != nTempPos )
601                 {
602                     if ( bSameMask )
603                     {
604                         if ( rEditMask.GetChar( nNewPos ) != EDITMASK_LITERAL )
605                             aStr.Erase( nNewPos, 1 );
606                     }
607                     else
608                     {
609                         XubString aTempStr = rLiteralMask.Copy( nNewPos, 1 );
610                         aStr.Replace( nNewPos, aTempStr.Len(), aTempStr );
611                     }
612                 }
613             }
614 
615             if ( aOldStr != aStr )
616             {
617                 if ( bSameMask )
618                     aStr = ImplPatternReformat( aStr, rEditMask, rLiteralMask, nFormatFlags );
619                 rbInKeyInput = sal_True;
620                 pEdit->SetText( aStr, Selection( nNewPos ) );
621                 pEdit->SetModifyFlag();
622                 pEdit->Modify();
623                 rbInKeyInput = sal_False;
624             }
625             else
626                 pEdit->SetSelection( Selection( nNewPos ) );
627 
628             return sal_True;
629         }
630         else if ( nKeyCode == KEY_INSERT )
631         {
632             // InsertModus kann man beim PatternField nur einstellen,
633             // wenn Maske an jeder Eingabeposition die gleiche
634             // ist
635             if ( !bSameMask )
636             {
637                 Sound::Beep();
638                 return sal_True;
639             }
640         }
641     }
642 
643     if ( rKEvt.GetKeyCode().IsMod2() || (cChar < 32) || (cChar == 127) )
644         return sal_False;
645 
646     Selection aSel = aOldSel;
647     aSel.Justify();
648     nNewPos = (xub_StrLen)aSel.Min();
649 
650     if ( nNewPos < rEditMask.Len() )
651     {
652         xub_Unicode cPattChar = ImplPatternChar( cChar, rEditMask.GetChar(nNewPos) );
653         if ( cPattChar )
654             cChar = cPattChar;
655         else
656         {
657             // Wenn kein gueltiges Zeichen, dann testen wir, ob der
658             // Anwender zum naechsten Literal springen wollte. Dies machen
659             // wir nur, wenn er hinter einem Zeichen steht, damit
660             // eingebene Literale die automatisch uebersprungenen wurden
661             // nicht dazu fuehren, das der Anwender dann da steht, wo
662             // er nicht stehen wollte.
663             if ( nNewPos &&
664                  (rEditMask.GetChar(nNewPos-1) != EDITMASK_LITERAL) &&
665                  !aSel.Len() )
666             {
667                 // Naechstes Zeichen suchen, was kein Literal ist
668                 nTempPos = nNewPos;
669                 while ( nTempPos < rEditMask.Len() )
670                 {
671                     if ( rEditMask.GetChar(nTempPos) == EDITMASK_LITERAL )
672                     {
673                         // Gilt nur, wenn ein Literalzeichen vorhanden
674                         if ( (rEditMask.GetChar(nTempPos+1) != EDITMASK_LITERAL ) &&
675                              ImplKommaPointCharEqual( cChar, rLiteralMask.GetChar(nTempPos) ) )
676                         {
677                             nTempPos++;
678                             ImplPatternMaxPos( pEdit->GetText(), rEditMask, nFormatFlags, bSameMask, nNewPos, nTempPos );
679                             if ( nTempPos > nNewPos )
680                             {
681                                 pEdit->SetSelection( Selection( nTempPos ) );
682                                 return sal_True;
683                             }
684                         }
685                         break;
686                     }
687                     nTempPos++;
688                 }
689             }
690 
691             cChar = 0;
692         }
693     }
694     else
695         cChar = 0;
696     if ( cChar )
697     {
698         XubString   aStr = pEdit->GetText();
699         sal_Bool        bError = sal_False;
700         if ( bSameMask && pEdit->IsInsertMode() )
701         {
702             // Text um Spacezeichen und Literale am Ende kuerzen, bis zur
703             // aktuellen Position
704             xub_StrLen n = aStr.Len();
705             while ( n && (n > nNewPos) )
706             {
707                 if ( (aStr.GetChar( n-1 ) != ' ') &&
708                      ((n > rEditMask.Len()) || (rEditMask.GetChar(n-1) != EDITMASK_LITERAL)) )
709                     break;
710 
711                 n--;
712             }
713             aStr.Erase( n );
714 
715             if ( aSel.Len() )
716                 aStr.Erase( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() );
717 
718             if ( aStr.Len() < rEditMask.Len() )
719             {
720                 // String evtl. noch bis Cursor-Position erweitern
721                 if ( aStr.Len() < nNewPos )
722                     aStr += rLiteralMask.Copy( aStr.Len(), nNewPos-aStr.Len() );
723                 if ( nNewPos < aStr.Len() )
724                     aStr.Insert( cChar, nNewPos );
725                 else if ( nNewPos < rEditMask.Len() )
726                     aStr += cChar;
727                 aStr = ImplPatternReformat( aStr, rEditMask, rLiteralMask, nFormatFlags );
728             }
729             else
730                 bError = sal_True;
731         }
732         else
733         {
734             if ( aSel.Len() )
735             {
736                 // Selection loeschen
737                 XubString aRep = rLiteralMask.Copy( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() );
738                 aStr.Replace( (xub_StrLen)aSel.Min(), aRep.Len(), aRep );
739             }
740 
741             if ( nNewPos < aStr.Len() )
742                 aStr.SetChar( nNewPos, cChar );
743             else if ( nNewPos < rEditMask.Len() )
744                 aStr += cChar;
745         }
746 
747         if ( bError )
748             Sound::Beep();
749         else
750         {
751             rbInKeyInput = sal_True;
752             Selection aNewSel( ImplPatternRightPos( aStr, rEditMask, nFormatFlags, bSameMask, nNewPos ) );
753             pEdit->SetText( aStr, aNewSel );
754             pEdit->SetModifyFlag();
755             pEdit->Modify();
756             rbInKeyInput = sal_False;
757         }
758     }
759     else
760         Sound::Beep();
761 
762     return sal_True;
763 }
764 
765 // -----------------------------------------------------------------------
766 
767 void PatternFormatter::ImplSetMask( const ByteString& rEditMask,
768                                     const XubString& rLiteralMask )
769 {
770     maEditMask      = rEditMask;
771     maLiteralMask   = rLiteralMask;
772     mbSameMask      = sal_True;
773 
774     if ( maEditMask.Len() != maLiteralMask.Len() )
775     {
776         if ( maEditMask.Len() < maLiteralMask.Len() )
777             maLiteralMask.Erase( maEditMask.Len() );
778         else
779             maLiteralMask.Expand( maEditMask.Len(), ' ' );
780     }
781 
782     // StrictModus erlaubt nur Input-Mode, wenn als Maske nur
783     // gleiche Zeichen zugelassen werden und als Vorgabe nur
784     // Spacezeichen vorgegeben werden, die durch die Maske
785     // nicht zugelassen sind
786     xub_StrLen  i = 0;
787     sal_Char    c = 0;
788     while ( i < rEditMask.Len() )
789     {
790         sal_Char cTemp = rEditMask.GetChar( i );
791         if ( cTemp != EDITMASK_LITERAL )
792         {
793             if ( (cTemp == EDITMASK_ALLCHAR) ||
794                  (cTemp == EDITMASK_UPPERALLCHAR) ||
795                  (cTemp == EDITMASK_NUMSPACE) )
796             {
797                 mbSameMask = sal_False;
798                 break;
799             }
800             if ( i < rLiteralMask.Len() )
801             {
802                 if ( rLiteralMask.GetChar( i ) != ' ' )
803                 {
804                     mbSameMask = sal_False;
805                     break;
806                 }
807             }
808             if ( !c )
809                 c = cTemp;
810             if ( cTemp != c )
811             {
812                 mbSameMask = sal_False;
813                 break;
814             }
815         }
816         i++;
817     }
818 }
819 
820 // -----------------------------------------------------------------------
821 
822 PatternFormatter::PatternFormatter()
823 {
824     mnFormatFlags       = 0;
825     mbSameMask          = sal_True;
826     mbInPattKeyInput    = sal_False;
827 }
828 
829 // -----------------------------------------------------------------------
830 
831 void PatternFormatter::ImplLoadRes( const ResId& rResId )
832 {
833     ByteString  aEditMask;
834     XubString   aLiteralMask;
835     ResMgr*     pMgr = rResId.GetResMgr();
836     if( pMgr )
837     {
838         sal_uLong       nMask = pMgr->ReadLong();
839 
840         if ( PATTERNFORMATTER_STRICTFORMAT & nMask )
841             SetStrictFormat( (sal_Bool)pMgr->ReadShort() );
842 
843         if ( PATTERNFORMATTER_EDITMASK & nMask )
844             aEditMask = ByteString( pMgr->ReadString(), RTL_TEXTENCODING_ASCII_US );
845 
846         if ( PATTERNFORMATTER_LITTERALMASK & nMask )
847             aLiteralMask = pMgr->ReadString();
848 
849         if ( (PATTERNFORMATTER_EDITMASK | PATTERNFORMATTER_LITTERALMASK) & nMask )
850             ImplSetMask( aEditMask, aLiteralMask );
851     }
852 }
853 
854 // -----------------------------------------------------------------------
855 
856 PatternFormatter::~PatternFormatter()
857 {
858 }
859 
860 // -----------------------------------------------------------------------
861 
862 void PatternFormatter::SetMask( const ByteString& rEditMask,
863                                 const XubString& rLiteralMask )
864 {
865     ImplSetMask( rEditMask, rLiteralMask );
866     ReformatAll();
867 }
868 
869 // -----------------------------------------------------------------------
870 
871 void PatternFormatter::SetString( const XubString& rStr )
872 {
873     maFieldString = rStr;
874     if ( GetField() )
875     {
876         GetField()->SetText( rStr );
877         MarkToBeReformatted( sal_False );
878     }
879 }
880 
881 // -----------------------------------------------------------------------
882 
883 XubString PatternFormatter::GetString() const
884 {
885     if ( !GetField() )
886         return ImplGetSVEmptyStr();
887     else
888         return ImplPatternReformat( GetField()->GetText(), maEditMask, maLiteralMask, mnFormatFlags );
889 }
890 
891 // -----------------------------------------------------------------------
892 
893 void PatternFormatter::Reformat()
894 {
895     if ( GetField() )
896     {
897         ImplSetText( ImplPatternReformat( GetField()->GetText(), maEditMask, maLiteralMask, mnFormatFlags ) );
898         if ( !mbSameMask && IsStrictFormat() && !GetField()->IsReadOnly() )
899             GetField()->SetInsertMode( sal_False );
900     }
901 }
902 
903 // -----------------------------------------------------------------------
904 
905 void PatternFormatter::SelectFixedFont()
906 {
907     if ( GetField() )
908     {
909         Font aFont = OutputDevice::GetDefaultFont( DEFAULTFONT_FIXED, Application::GetSettings().GetLanguage(), 0 );
910         Font aControlFont;
911         aControlFont.SetName( aFont.GetName() );
912         aControlFont.SetFamily( aFont.GetFamily() );
913         aControlFont.SetPitch( aFont.GetPitch() );
914         GetField()->SetControlFont( aControlFont );
915     }
916 }
917 
918 // -----------------------------------------------------------------------
919 
920 PatternField::PatternField( Window* pParent, WinBits nWinStyle ) :
921     SpinField( pParent, nWinStyle )
922 {
923     SetField( this );
924     Reformat();
925 }
926 
927 // -----------------------------------------------------------------------
928 
929 PatternField::PatternField( Window* pParent, const ResId& rResId ) :
930     SpinField( WINDOW_PATTERNFIELD )
931 {
932     rResId.SetRT( RSC_PATTERNFIELD );
933     WinBits nStyle = ImplInitRes( rResId );
934     ImplInit( pParent, nStyle );
935     SetField( this );
936     SpinField::ImplLoadRes( rResId );
937     PatternFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
938     Reformat();
939 
940     if ( !(nStyle & WB_HIDE ) )
941         Show();
942 }
943 
944 // -----------------------------------------------------------------------
945 
946 PatternField::~PatternField()
947 {
948 }
949 
950 // -----------------------------------------------------------------------
951 
952 long PatternField::PreNotify( NotifyEvent& rNEvt )
953 {
954     if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
955     {
956         if ( ImplPatternProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
957                                          IsStrictFormat(), GetFormatFlags(),
958                                          ImplIsSameMask(), ImplGetInPattKeyInput() ) )
959             return 1;
960     }
961 
962     return SpinField::PreNotify( rNEvt );
963 }
964 
965 // -----------------------------------------------------------------------
966 
967 long PatternField::Notify( NotifyEvent& rNEvt )
968 {
969     if ( rNEvt.GetType() == EVENT_GETFOCUS )
970         MarkToBeReformatted( sal_False );
971     else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
972     {
973         if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
974             Reformat();
975     }
976 
977     return SpinField::Notify( rNEvt );
978 }
979 
980 // -----------------------------------------------------------------------
981 
982 void PatternField::Modify()
983 {
984     if ( !ImplGetInPattKeyInput() )
985     {
986         if ( IsStrictFormat() )
987             ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), GetFormatFlags(), ImplIsSameMask() );
988         else
989             MarkToBeReformatted( sal_True );
990     }
991 
992     SpinField::Modify();
993 }
994 
995 // -----------------------------------------------------------------------
996 
997 PatternBox::PatternBox( Window* pParent, WinBits nWinStyle ) :
998     ComboBox( pParent, nWinStyle )
999 {
1000     SetField( this );
1001     Reformat();
1002 }
1003 
1004 // -----------------------------------------------------------------------
1005 
1006 PatternBox::PatternBox( Window* pParent, const ResId& rResId ) :
1007     ComboBox( WINDOW_PATTERNBOX )
1008 {
1009     rResId.SetRT( RSC_PATTERNBOX );
1010     WinBits nStyle = ImplInitRes( rResId );
1011     ImplInit( pParent, nStyle );
1012 
1013     SetField( this );
1014     ComboBox::ImplLoadRes( rResId );
1015     PatternFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
1016     Reformat();
1017 
1018     if ( !(nStyle & WB_HIDE ) )
1019         Show();
1020 }
1021 
1022 // -----------------------------------------------------------------------
1023 
1024 PatternBox::~PatternBox()
1025 {
1026 }
1027 
1028 // -----------------------------------------------------------------------
1029 
1030 long PatternBox::PreNotify( NotifyEvent& rNEvt )
1031 {
1032     if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1033     {
1034         if ( ImplPatternProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
1035                                          IsStrictFormat(), GetFormatFlags(),
1036                                          ImplIsSameMask(), ImplGetInPattKeyInput() ) )
1037             return 1;
1038     }
1039 
1040     return ComboBox::PreNotify( rNEvt );
1041 }
1042 
1043 // -----------------------------------------------------------------------
1044 
1045 long PatternBox::Notify( NotifyEvent& rNEvt )
1046 {
1047     if ( rNEvt.GetType() == EVENT_GETFOCUS )
1048         MarkToBeReformatted( sal_False );
1049     else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
1050     {
1051         if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
1052             Reformat();
1053     }
1054 
1055     return ComboBox::Notify( rNEvt );
1056 }
1057 
1058 // -----------------------------------------------------------------------
1059 
1060 void PatternBox::Modify()
1061 {
1062     if ( !ImplGetInPattKeyInput() )
1063     {
1064         if ( IsStrictFormat() )
1065             ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), GetFormatFlags(), ImplIsSameMask() );
1066         else
1067             MarkToBeReformatted( sal_True );
1068     }
1069 
1070     ComboBox::Modify();
1071 }
1072 
1073 // -----------------------------------------------------------------------
1074 
1075 void PatternBox::ReformatAll()
1076 {
1077     XubString aStr;
1078     SetUpdateMode( sal_False );
1079     sal_uInt16 nEntryCount = GetEntryCount();
1080     for ( sal_uInt16 i=0; i < nEntryCount; i++ )
1081     {
1082         aStr = ImplPatternReformat( GetEntry( i ), GetEditMask(), GetLiteralMask(), GetFormatFlags() );
1083         RemoveEntry( i );
1084         InsertEntry( aStr, i );
1085     }
1086     PatternFormatter::Reformat();
1087     SetUpdateMode( sal_True );
1088 }
1089 
1090 // -----------------------------------------------------------------------
1091 
1092 void PatternBox::InsertString( const XubString& rStr, sal_uInt16 nPos )
1093 {
1094     ComboBox::InsertEntry( ImplPatternReformat( rStr, GetEditMask(), GetLiteralMask(), GetFormatFlags() ), nPos );
1095 }
1096 
1097 // -----------------------------------------------------------------------
1098 
1099 void PatternBox::RemoveString( const XubString& rStr )
1100 {
1101     ComboBox::RemoveEntry( ImplPatternReformat( rStr, GetEditMask(), GetLiteralMask(), GetFormatFlags() ) );
1102 }
1103 
1104 // -----------------------------------------------------------------------
1105 
1106 XubString PatternBox::GetString( sal_uInt16 nPos ) const
1107 {
1108     return ImplPatternReformat( ComboBox::GetEntry( nPos ), GetEditMask(), GetLiteralMask(), GetFormatFlags() );
1109 }
1110 
1111 // -----------------------------------------------------------------------
1112 
1113 sal_uInt16 PatternBox::GetStringPos( const XubString& rStr ) const
1114 {
1115     return ComboBox::GetEntryPos( ImplPatternReformat( rStr, GetEditMask(), GetLiteralMask(), GetFormatFlags() ) );
1116 }
1117 
1118 // =======================================================================
1119 
1120 static ExtDateFieldFormat ImplGetExtFormat( DateFormat eOld )
1121 {
1122     switch( eOld )
1123     {
1124         case DMY:   return XTDATEF_SHORT_DDMMYY;
1125         case MDY:   return XTDATEF_SHORT_MMDDYY;
1126         default:    return XTDATEF_SHORT_YYMMDD;
1127     }
1128 }
1129 
1130 // -----------------------------------------------------------------------
1131 
1132 static sal_uInt16 ImplCutNumberFromString( XubString& rStr )
1133 {
1134     // Nach Zahl suchen
1135     while ( rStr.Len() && !(rStr.GetChar( 0 ) >= '0' && rStr.GetChar( 0 ) <= '9') )
1136         rStr.Erase( 0, 1 );
1137     if ( !rStr.Len() )
1138         return 0;
1139     XubString aNumStr;
1140     while ( rStr.Len() && (rStr.GetChar( 0 ) >= '0' && rStr.GetChar( 0 ) <= '9') )
1141     {
1142         aNumStr.Insert( rStr.GetChar( 0 ) );
1143         rStr.Erase( 0, 1 );
1144     }
1145     return (sal_uInt16)aNumStr.ToInt32();
1146 }
1147 
1148 // -----------------------------------------------------------------------
1149 
1150 static sal_Bool ImplCutMonthName( XubString& rStr, const XubString& _rLookupMonthName )
1151 {
1152     sal_uInt16 nPos = rStr.Search( _rLookupMonthName );
1153     if ( nPos != STRING_NOTFOUND )
1154     {
1155         rStr.Erase( 0, nPos + _rLookupMonthName.Len() );
1156         return sal_True;
1157     }
1158     return sal_False;
1159 }
1160 
1161 // -----------------------------------------------------------------------
1162 
1163 static sal_uInt16 ImplCutMonthFromString( XubString& rStr, const CalendarWrapper& rCalendarWrapper )
1164 {
1165     // search for a month' name
1166     for ( sal_uInt16 i=1; i <= 12; i++ )
1167     {
1168         String aMonthName = rCalendarWrapper.getMonths()[i-1].FullName;
1169         // long month name?
1170         if ( ImplCutMonthName( rStr, aMonthName ) )
1171             return i;
1172 
1173         // short month name?
1174         String aAbbrevMonthName = rCalendarWrapper.getMonths()[i-1].AbbrevName;
1175         if ( ImplCutMonthName( rStr, aAbbrevMonthName ) )
1176             return i;
1177     }
1178 
1179     return ImplCutNumberFromString( rStr );
1180 }
1181 
1182 // -----------------------------------------------------------------------
1183 
1184 static String ImplGetDateSep( const LocaleDataWrapper& rLocaleDataWrapper, ExtDateFieldFormat eFormat )
1185 {
1186     String aDateSep = rLocaleDataWrapper.getDateSep();
1187 
1188     if ( ( eFormat == XTDATEF_SHORT_YYMMDD_DIN5008 ) || ( eFormat == XTDATEF_SHORT_YYYYMMDD_DIN5008 ) )
1189         aDateSep = String( RTL_CONSTASCII_USTRINGPARAM( "-" ) );
1190 
1191     return aDateSep;
1192 }
1193 
1194 static sal_Bool ImplDateProcessKeyInput( Edit*, const KeyEvent& rKEvt, ExtDateFieldFormat eFormat,
1195                                      const LocaleDataWrapper& rLocaleDataWrapper  )
1196 {
1197     xub_Unicode cChar = rKEvt.GetCharCode();
1198     sal_uInt16 nGroup = rKEvt.GetKeyCode().GetGroup();
1199     if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
1200          (nGroup == KEYGROUP_MISC)||
1201          ((cChar >= '0') && (cChar <= '9')) ||
1202          (cChar == ImplGetDateSep( rLocaleDataWrapper, eFormat ).GetChar(0) ) )
1203         return sal_False;
1204     else
1205         return sal_True;
1206 }
1207 
1208 // -----------------------------------------------------------------------
1209 
1210 static sal_Bool ImplDateGetValue( const XubString& rStr, Date& rDate, ExtDateFieldFormat eDateFormat,
1211                               const LocaleDataWrapper& rLocaleDataWrapper, const CalendarWrapper& rCalendarWrapper,
1212                               const AllSettings& )
1213 {
1214     sal_uInt16 nDay = 0;
1215     sal_uInt16 nMonth = 0;
1216     sal_uInt16 nYear = 0;
1217     sal_Bool bYear = sal_True;
1218     sal_Bool bError = sal_False;
1219     String aStr( rStr );
1220 
1221     if ( eDateFormat == XTDATEF_SYSTEM_LONG )
1222     {
1223         DateFormat eFormat = rLocaleDataWrapper.getLongDateFormat();
1224         switch( eFormat )
1225         {
1226             case MDY:
1227                 nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
1228                 nDay = ImplCutNumberFromString( aStr );
1229                 nYear  = ImplCutNumberFromString( aStr );
1230                 break;
1231             case DMY:
1232                 nDay = ImplCutNumberFromString( aStr );
1233                 nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
1234                 nYear  = ImplCutNumberFromString( aStr );
1235                 break;
1236             case YMD:
1237             default:
1238                 nYear = ImplCutNumberFromString( aStr );
1239                 nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper );
1240                 nDay  = ImplCutNumberFromString( aStr );
1241                 break;
1242         }
1243     }
1244     else
1245     {
1246         // Check if year is present:
1247         String aDateSep = ImplGetDateSep( rLocaleDataWrapper, eDateFormat );
1248         sal_uInt16 nSepPos = aStr.Search( aDateSep );
1249         if ( nSepPos == STRING_NOTFOUND )
1250             return sal_False;
1251         nSepPos = aStr.Search( aDateSep, nSepPos+1 );
1252         if ( ( nSepPos == STRING_NOTFOUND ) || ( nSepPos == (aStr.Len()-1) ) )
1253         {
1254             bYear = sal_False;
1255             nYear = Date().GetYear();
1256         }
1257 
1258         const sal_Unicode* pBuf = aStr.GetBuffer();
1259         ImplSkipDelimiters( pBuf );
1260 
1261         switch ( eDateFormat )
1262         {
1263             case XTDATEF_SHORT_DDMMYY:
1264             case XTDATEF_SHORT_DDMMYYYY:
1265             {
1266                 nDay = ImplGetNum( pBuf, bError );
1267                 ImplSkipDelimiters( pBuf );
1268                 nMonth = ImplGetNum( pBuf, bError );
1269                 ImplSkipDelimiters( pBuf );
1270                 if ( bYear )
1271                     nYear = ImplGetNum( pBuf, bError );
1272             }
1273             break;
1274             case XTDATEF_SHORT_MMDDYY:
1275             case XTDATEF_SHORT_MMDDYYYY:
1276             {
1277                 nMonth = ImplGetNum( pBuf, bError );
1278                 ImplSkipDelimiters( pBuf );
1279                 nDay = ImplGetNum( pBuf, bError );
1280                 ImplSkipDelimiters( pBuf );
1281                 if ( bYear )
1282                     nYear = ImplGetNum( pBuf, bError );
1283             }
1284             break;
1285             case XTDATEF_SHORT_YYMMDD:
1286             case XTDATEF_SHORT_YYYYMMDD:
1287             case XTDATEF_SHORT_YYMMDD_DIN5008:
1288             case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1289             {
1290                 if ( bYear )
1291                     nYear = ImplGetNum( pBuf, bError );
1292                 ImplSkipDelimiters( pBuf );
1293                 nMonth = ImplGetNum( pBuf, bError );
1294                 ImplSkipDelimiters( pBuf );
1295                 nDay = ImplGetNum( pBuf, bError );
1296             }
1297             break;
1298 
1299             default:
1300             {
1301                 DBG_ERROR( "DateFormat???" );
1302             }
1303         }
1304     }
1305 
1306     if ( bError || !nDay || !nMonth )
1307         return sal_False;
1308 
1309     Date aNewDate( nDay, nMonth, nYear );
1310 	DateFormatter::ExpandCentury( aNewDate, utl::MiscCfg().GetYear2000() );
1311     if ( aNewDate.IsValid() )
1312     {
1313         rDate = aNewDate;
1314         return sal_True;
1315     }
1316     return sal_False;
1317 }
1318 
1319 // -----------------------------------------------------------------------
1320 
1321 sal_Bool DateFormatter::ImplDateReformat( const XubString& rStr, XubString& rOutStr, const AllSettings& rSettings )
1322 {
1323     Date aDate( 0, 0, 0 );
1324     if ( !ImplDateGetValue( rStr, aDate, GetExtDateFormat(sal_True), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1325         return sal_True;
1326 
1327     Date aTempDate = aDate;
1328     if ( aTempDate > GetMax() )
1329         aTempDate = GetMax();
1330     else if ( aTempDate < GetMin() )
1331         aTempDate = GetMin();
1332 
1333     if ( GetErrorHdl().IsSet() && (aDate != aTempDate) )
1334     {
1335         maCorrectedDate = aTempDate;
1336         if( !GetErrorHdl().Call( this ) )
1337         {
1338             maCorrectedDate = Date();
1339             return sal_False;
1340         }
1341         else
1342             maCorrectedDate = Date();
1343     }
1344 
1345     rOutStr = ImplGetDateAsText( aTempDate, rSettings );
1346 
1347     return sal_True;
1348 }
1349 
1350 // -----------------------------------------------------------------------
1351 
1352 XubString DateFormatter::ImplGetDateAsText( const Date& rDate,
1353                                             const AllSettings& ) const
1354 {
1355     sal_Bool bShowCentury = sal_False;
1356     switch ( GetExtDateFormat() )
1357     {
1358         case XTDATEF_SYSTEM_SHORT_YYYY:
1359         case XTDATEF_SYSTEM_LONG:
1360         case XTDATEF_SHORT_DDMMYYYY:
1361         case XTDATEF_SHORT_MMDDYYYY:
1362         case XTDATEF_SHORT_YYYYMMDD:
1363         case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1364         {
1365             bShowCentury = sal_True;
1366         }
1367         break;
1368         default:
1369         {
1370             bShowCentury = sal_False;
1371         }
1372     }
1373 
1374     if ( !bShowCentury )
1375     {
1376         // Check if I have to use force showing the century
1377         sal_uInt16 nTwoDigitYearStart = utl::MiscCfg().GetYear2000();
1378         sal_uInt16 nYear = rDate.GetYear();
1379 
1380         // Wenn Jahr nicht im 2stelligen Grenzbereich liegt,
1381         if ( (nYear < nTwoDigitYearStart) || (nYear >= nTwoDigitYearStart+100) )
1382             bShowCentury = sal_True;
1383     }
1384 
1385     sal_Unicode aBuf[128];
1386     sal_Unicode* pBuf = aBuf;
1387 
1388     String aDateSep = ImplGetDateSep( ImplGetLocaleDataWrapper(), GetExtDateFormat( sal_True ) );
1389     sal_uInt16 nDay = rDate.GetDay();
1390     sal_uInt16 nMonth = rDate.GetMonth();
1391     sal_uInt16 nYear = rDate.GetYear();
1392     sal_uInt16 nYearLen = bShowCentury ? 4 : 2;
1393 
1394     if ( !bShowCentury )
1395         nYear %= 100;
1396 
1397     switch ( GetExtDateFormat( sal_True ) )
1398     {
1399         case XTDATEF_SYSTEM_LONG:
1400         {
1401             return ImplGetLocaleDataWrapper().getLongDate( rDate, GetCalendarWrapper(), 1, sal_False, 1, !bShowCentury );
1402         }
1403         case XTDATEF_SHORT_DDMMYY:
1404         case XTDATEF_SHORT_DDMMYYYY:
1405         {
1406             pBuf = ImplAddNum( pBuf, nDay, 2 );
1407             pBuf = ImplAddString( pBuf, aDateSep );
1408             pBuf = ImplAddNum( pBuf, nMonth, 2 );
1409             pBuf = ImplAddString( pBuf, aDateSep );
1410             pBuf = ImplAddNum( pBuf, nYear, nYearLen );
1411         }
1412         break;
1413         case XTDATEF_SHORT_MMDDYY:
1414         case XTDATEF_SHORT_MMDDYYYY:
1415         {
1416             pBuf = ImplAddNum( pBuf, nMonth, 2 );
1417             pBuf = ImplAddString( pBuf, aDateSep );
1418             pBuf = ImplAddNum( pBuf, nDay, 2 );
1419             pBuf = ImplAddString( pBuf, aDateSep );
1420             pBuf = ImplAddNum( pBuf, nYear, nYearLen );
1421         }
1422         break;
1423         case XTDATEF_SHORT_YYMMDD:
1424         case XTDATEF_SHORT_YYYYMMDD:
1425         case XTDATEF_SHORT_YYMMDD_DIN5008:
1426         case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1427         {
1428             pBuf = ImplAddNum( pBuf, nYear, nYearLen );
1429             pBuf = ImplAddString( pBuf, aDateSep );
1430             pBuf = ImplAddNum( pBuf, nMonth, 2 );
1431             pBuf = ImplAddString( pBuf, aDateSep );
1432             pBuf = ImplAddNum( pBuf, nDay, 2 );
1433         }
1434         break;
1435         default:
1436         {
1437             DBG_ERROR( "DateFormat???" );
1438         }
1439     }
1440 
1441     return String( aBuf, (xub_StrLen)(sal_uLong)(pBuf-aBuf) );
1442 }
1443 
1444 // -----------------------------------------------------------------------
1445 
1446 static void ImplDateIncrementDay( Date& rDate, sal_Bool bUp )
1447 {
1448     DateFormatter::ExpandCentury( rDate );
1449 
1450     if ( bUp )
1451     {
1452         if ( (rDate.GetDay() != 31) || (rDate.GetMonth() != 12) || (rDate.GetYear() != 9999) )
1453             rDate++;
1454     }
1455     else
1456     {
1457         if ( (rDate.GetDay() != 1 ) || (rDate.GetMonth() != 1) || (rDate.GetYear() != 0) )
1458             rDate--;
1459     }
1460 }
1461 
1462 // -----------------------------------------------------------------------
1463 
1464 static void ImplDateIncrementMonth( Date& rDate, sal_Bool bUp )
1465 {
1466     DateFormatter::ExpandCentury( rDate );
1467 
1468     sal_uInt16 nMonth = rDate.GetMonth();
1469     sal_uInt16 nYear = rDate.GetYear();
1470     if ( bUp )
1471     {
1472         if ( (nMonth == 12) && (nYear < 9999) )
1473         {
1474             rDate.SetMonth( 1 );
1475             rDate.SetYear( nYear + 1 );
1476         }
1477         else
1478         {
1479             if ( nMonth < 12 )
1480                 rDate.SetMonth( nMonth + 1 );
1481         }
1482     }
1483     else
1484     {
1485         if ( (nMonth == 1) && (nYear > 0) )
1486         {
1487             rDate.SetMonth( 12 );
1488             rDate.SetYear( nYear - 1 );
1489         }
1490         else
1491         {
1492             if ( nMonth > 1 )
1493                 rDate.SetMonth( nMonth - 1 );
1494         }
1495     }
1496 
1497     sal_uInt16 nDaysInMonth = rDate.GetDaysInMonth();
1498     if ( rDate.GetDay() > nDaysInMonth )
1499         rDate.SetDay( nDaysInMonth );
1500 }
1501 
1502 // -----------------------------------------------------------------------
1503 
1504 static void ImplDateIncrementYear( Date& rDate, sal_Bool bUp )
1505 {
1506     DateFormatter::ExpandCentury( rDate );
1507 
1508     sal_uInt16 nYear = rDate.GetYear();
1509     if ( bUp )
1510     {
1511         if ( nYear < 9999 )
1512             rDate.SetYear( nYear + 1 );
1513     }
1514     else
1515     {
1516         if ( nYear > 0 )
1517             rDate.SetYear( nYear - 1 );
1518     }
1519 }
1520 
1521 // -----------------------------------------------------------------------
1522 sal_Bool DateFormatter::ImplAllowMalformedInput() const
1523 {
1524     return !IsEnforceValidValue();
1525 }
1526 
1527 // -----------------------------------------------------------------------
1528 
1529 void DateField::ImplDateSpinArea( sal_Bool bUp )
1530 {
1531     // Wenn alles selektiert ist, Tage hochzaehlen
1532     if ( GetField() )
1533     {
1534         Date aDate( GetDate() );
1535         Selection aSelection = GetField()->GetSelection();
1536         aSelection.Justify();
1537         XubString aText( GetText() );
1538         if ( (xub_StrLen)aSelection.Len() == aText.Len() )
1539             ImplDateIncrementDay( aDate, bUp );
1540         else
1541         {
1542             xub_StrLen nDateArea = 0;
1543 
1544             ExtDateFieldFormat eFormat = GetExtDateFormat( sal_True );
1545             if ( eFormat == XTDATEF_SYSTEM_LONG )
1546             {
1547                 eFormat = ImplGetExtFormat( ImplGetLocaleDataWrapper().getLongDateFormat() );
1548                 nDateArea = 1;
1549             }
1550             else
1551             {
1552                 // Area suchen
1553                 xub_StrLen nPos = 0;
1554                 String aDateSep = ImplGetDateSep( ImplGetLocaleDataWrapper(), eFormat );
1555                 for ( xub_StrLen i = 1; i <= 3; i++ )
1556                 {
1557                     nPos = aText.Search( aDateSep, nPos );
1558                     if ( nPos >= (sal_uInt16)aSelection.Max() )
1559                     {
1560                         nDateArea = i;
1561                         break;
1562                     }
1563                     else
1564                         nPos++;
1565                 }
1566             }
1567 
1568 
1569             switch( eFormat )
1570             {
1571                 case XTDATEF_SHORT_MMDDYY:
1572                 case XTDATEF_SHORT_MMDDYYYY:
1573                 switch( nDateArea )
1574                 {
1575                     case 1: ImplDateIncrementMonth( aDate, bUp );
1576                             break;
1577                     case 2: ImplDateIncrementDay( aDate, bUp );
1578                             break;
1579                     case 3: ImplDateIncrementYear( aDate, bUp );
1580                             break;
1581                 }
1582                 break;
1583                 case XTDATEF_SHORT_DDMMYY:
1584                 case XTDATEF_SHORT_DDMMYYYY:
1585                 switch( nDateArea )
1586                 {
1587                     case 1: ImplDateIncrementDay( aDate, bUp );
1588                             break;
1589                     case 2: ImplDateIncrementMonth( aDate, bUp );
1590                             break;
1591                     case 3: ImplDateIncrementYear( aDate, bUp );
1592                             break;
1593                 }
1594                 break;
1595                 case XTDATEF_SHORT_YYMMDD:
1596                 case XTDATEF_SHORT_YYYYMMDD:
1597                 case XTDATEF_SHORT_YYMMDD_DIN5008:
1598                 case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1599                 switch( nDateArea )
1600                 {
1601                     case 1: ImplDateIncrementYear( aDate, bUp );
1602                             break;
1603                     case 2: ImplDateIncrementMonth( aDate, bUp );
1604                             break;
1605                     case 3: ImplDateIncrementDay( aDate, bUp );
1606                             break;
1607                 }
1608                 break;
1609                 default:
1610                     DBG_ERROR( "invalid conversion" );
1611                     break;
1612             }
1613         }
1614 
1615         ImplNewFieldValue( aDate );
1616     }
1617 }
1618 
1619 // -----------------------------------------------------------------------
1620 
1621 void DateFormatter::ImplInit()
1622 {
1623     mbLongFormat        = sal_False;
1624     mbShowDateCentury   = sal_True;
1625     mpCalendarWrapper   = NULL;
1626     mnDateFormat        = 0xFFFF;
1627     mnExtDateFormat     = XTDATEF_SYSTEM_SHORT;
1628 }
1629 
1630 // -----------------------------------------------------------------------
1631 
1632 DateFormatter::DateFormatter() :
1633     maFieldDate( 0 ),
1634     maLastDate( 0 ),
1635     maMin( 1, 1, 1900 ),
1636     maMax( 31, 12, 2200 ),
1637     mbEnforceValidValue( sal_True )
1638 {
1639     ImplInit();
1640 }
1641 
1642 // -----------------------------------------------------------------------
1643 
1644 void DateFormatter::ImplLoadRes( const ResId& rResId )
1645 {
1646     ResMgr*     pMgr = rResId.GetResMgr();
1647     if( pMgr )
1648     {
1649         sal_uLong       nMask = pMgr->ReadLong();
1650 
1651         if ( DATEFORMATTER_MIN & nMask )
1652         {
1653             maMin = Date( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
1654             pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE*)pMgr->GetClass() ) );
1655         }
1656         if ( DATEFORMATTER_MAX & nMask )
1657         {
1658             maMax = Date( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
1659             pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE*)pMgr->GetClass() ) );
1660         }
1661         if ( DATEFORMATTER_LONGFORMAT & nMask )
1662             mbLongFormat = (sal_Bool)pMgr->ReadShort();
1663 
1664         if ( DATEFORMATTER_STRICTFORMAT & nMask )
1665             SetStrictFormat( (sal_Bool)pMgr->ReadShort() );
1666 
1667         if ( DATEFORMATTER_VALUE & nMask )
1668         {
1669             maFieldDate = Date( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
1670             pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE*)pMgr->GetClass() ) );
1671             if ( maFieldDate > maMax )
1672                 maFieldDate = maMax;
1673             if ( maFieldDate < maMin )
1674                 maFieldDate = maMin;
1675             maLastDate = maFieldDate;
1676         }
1677     }
1678 }
1679 
1680 // -----------------------------------------------------------------------
1681 
1682 DateFormatter::~DateFormatter()
1683 {
1684     delete mpCalendarWrapper;
1685     mpCalendarWrapper = NULL;
1686 }
1687 
1688 // -----------------------------------------------------------------------
1689 
1690 void DateFormatter::SetLocale( const ::com::sun::star::lang::Locale& rLocale )
1691 {
1692     delete mpCalendarWrapper;
1693     mpCalendarWrapper = NULL;
1694     FormatterBase::SetLocale( rLocale );
1695 }
1696 
1697 
1698 // -----------------------------------------------------------------------
1699 
1700 CalendarWrapper& DateFormatter::GetCalendarWrapper() const
1701 {
1702     if ( !mpCalendarWrapper )
1703     {
1704         ((DateFormatter*)this)->mpCalendarWrapper = new CalendarWrapper( vcl::unohelper::GetMultiServiceFactory() );
1705         mpCalendarWrapper->loadDefaultCalendar( GetLocale() );
1706     }
1707 
1708     return *mpCalendarWrapper;
1709 }
1710 
1711 // -----------------------------------------------------------------------
1712 
1713 void DateFormatter::SetExtDateFormat( ExtDateFieldFormat eFormat )
1714 {
1715     mnExtDateFormat = eFormat;
1716     ReformatAll();
1717 }
1718 
1719 // -----------------------------------------------------------------------
1720 
1721 ExtDateFieldFormat DateFormatter::GetExtDateFormat( sal_Bool bResolveSystemFormat ) const
1722 {
1723     ExtDateFieldFormat eDateFormat = (ExtDateFieldFormat)mnExtDateFormat;
1724 
1725     if ( bResolveSystemFormat && ( eDateFormat <= XTDATEF_SYSTEM_SHORT_YYYY ) )
1726     {
1727         sal_Bool bShowCentury = (eDateFormat == XTDATEF_SYSTEM_SHORT_YYYY);
1728         switch ( ImplGetLocaleDataWrapper().getDateFormat() )
1729         {
1730             case DMY:   eDateFormat = bShowCentury ? XTDATEF_SHORT_DDMMYYYY : XTDATEF_SHORT_DDMMYY;
1731                         break;
1732             case MDY:   eDateFormat = bShowCentury ? XTDATEF_SHORT_MMDDYYYY : XTDATEF_SHORT_MMDDYY;
1733                         break;
1734             default:    eDateFormat = bShowCentury ? XTDATEF_SHORT_YYYYMMDD : XTDATEF_SHORT_YYMMDD;
1735 
1736         }
1737     }
1738 
1739     return eDateFormat;
1740 }
1741 
1742 // -----------------------------------------------------------------------
1743 
1744 void DateFormatter::ReformatAll()
1745 {
1746     Reformat();
1747 }
1748 
1749 // -----------------------------------------------------------------------
1750 
1751 void DateFormatter::SetMin( const Date& rNewMin )
1752 {
1753     maMin = rNewMin;
1754     if ( !IsEmptyFieldValue() )
1755         ReformatAll();
1756 }
1757 
1758 // -----------------------------------------------------------------------
1759 
1760 void DateFormatter::SetMax( const Date& rNewMax )
1761 {
1762     maMax = rNewMax;
1763     if ( !IsEmptyFieldValue() )
1764         ReformatAll();
1765 }
1766 
1767 // -----------------------------------------------------------------------
1768 
1769 void DateFormatter::SetLongFormat( sal_Bool bLong )
1770 {
1771     mbLongFormat = bLong;
1772 
1773     // #91913# Remove LongFormat and DateShowCentury - redundant
1774     if ( bLong )
1775     {
1776         SetExtDateFormat( XTDATEF_SYSTEM_LONG );
1777     }
1778     else
1779     {
1780         if( mnExtDateFormat == XTDATEF_SYSTEM_LONG )
1781             SetExtDateFormat( XTDATEF_SYSTEM_SHORT );
1782     }
1783 
1784     ReformatAll();
1785 }
1786 
1787 // -----------------------------------------------------------------------
1788 
1789 void DateFormatter::SetShowDateCentury( sal_Bool bShowDateCentury )
1790 {
1791     mbShowDateCentury = bShowDateCentury;
1792 
1793     // #91913# Remove LongFormat and DateShowCentury - redundant
1794     if ( bShowDateCentury )
1795     {
1796         switch ( GetExtDateFormat() )
1797         {
1798             case XTDATEF_SYSTEM_SHORT:
1799             case XTDATEF_SYSTEM_SHORT_YY:
1800                 SetExtDateFormat( XTDATEF_SYSTEM_SHORT_YYYY );  break;
1801             case XTDATEF_SHORT_DDMMYY:
1802                 SetExtDateFormat( XTDATEF_SHORT_DDMMYYYY );     break;
1803             case XTDATEF_SHORT_MMDDYY:
1804                 SetExtDateFormat( XTDATEF_SHORT_MMDDYYYY );     break;
1805             case XTDATEF_SHORT_YYMMDD:
1806                 SetExtDateFormat( XTDATEF_SHORT_YYYYMMDD );     break;
1807             case XTDATEF_SHORT_YYMMDD_DIN5008:
1808                 SetExtDateFormat( XTDATEF_SHORT_YYYYMMDD_DIN5008 ); break;
1809             default:
1810                 ;
1811         }
1812     }
1813     else
1814     {
1815         switch ( GetExtDateFormat() )
1816         {
1817             case XTDATEF_SYSTEM_SHORT:
1818             case XTDATEF_SYSTEM_SHORT_YYYY:
1819                 SetExtDateFormat( XTDATEF_SYSTEM_SHORT_YY );    break;
1820             case XTDATEF_SHORT_DDMMYYYY:
1821                 SetExtDateFormat( XTDATEF_SHORT_DDMMYY );       break;
1822             case XTDATEF_SHORT_MMDDYYYY:
1823                 SetExtDateFormat( XTDATEF_SHORT_MMDDYY );       break;
1824             case XTDATEF_SHORT_YYYYMMDD:
1825                 SetExtDateFormat( XTDATEF_SHORT_YYMMDD );       break;
1826             case XTDATEF_SHORT_YYYYMMDD_DIN5008:
1827                 SetExtDateFormat( XTDATEF_SHORT_YYMMDD_DIN5008 );  break;
1828             default:
1829                 ;
1830         }
1831     }
1832 
1833     ReformatAll();
1834 }
1835 
1836 // -----------------------------------------------------------------------
1837 
1838 void DateFormatter::SetDate( const Date& rNewDate )
1839 {
1840     SetUserDate( rNewDate );
1841     maFieldDate = maLastDate;
1842     maLastDate = GetDate();
1843 }
1844 
1845 // -----------------------------------------------------------------------
1846 
1847 void DateFormatter::SetUserDate( const Date& rNewDate )
1848 {
1849     ImplSetUserDate( rNewDate );
1850 }
1851 
1852 // -----------------------------------------------------------------------
1853 
1854 void DateFormatter::ImplSetUserDate( const Date& rNewDate, Selection* pNewSelection )
1855 {
1856     Date aNewDate = rNewDate;
1857     if ( aNewDate > maMax )
1858         aNewDate = maMax;
1859     else if ( aNewDate < maMin )
1860         aNewDate = maMin;
1861     maLastDate = aNewDate;
1862 
1863     if ( GetField() )
1864         ImplSetText( ImplGetDateAsText( aNewDate, GetFieldSettings() ), pNewSelection );
1865 }
1866 
1867 // -----------------------------------------------------------------------
1868 
1869 void DateFormatter::ImplNewFieldValue( const Date& rDate )
1870 {
1871     if ( GetField() )
1872     {
1873         Selection aSelection = GetField()->GetSelection();
1874         aSelection.Justify();
1875         XubString aText = GetField()->GetText();
1876         // Wenn bis ans Ende selektiert war, soll das auch so bleiben...
1877         if ( (xub_StrLen)aSelection.Max() == aText.Len() )
1878         {
1879             if ( !aSelection.Len() )
1880                 aSelection.Min() = SELECTION_MAX;
1881             aSelection.Max() = SELECTION_MAX;
1882         }
1883 
1884         Date aOldLastDate  = maLastDate;
1885         ImplSetUserDate( rDate, &aSelection );
1886         maLastDate = aOldLastDate;
1887 
1888         // Modify am Edit wird nur bei KeyInput gesetzt...
1889         if ( GetField()->GetText() != aText )
1890         {
1891             GetField()->SetModifyFlag();
1892             GetField()->Modify();
1893         }
1894     }
1895 }
1896 
1897 // -----------------------------------------------------------------------
1898 
1899 Date DateFormatter::GetDate() const
1900 {
1901     Date aDate( 0, 0, 0 );
1902 
1903     if ( GetField() )
1904     {
1905         if ( ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(sal_True), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1906         {
1907             if ( aDate > maMax )
1908                 aDate = maMax;
1909             else if ( aDate < maMin )
1910                 aDate = maMin;
1911         }
1912         else
1913         {
1914             // !!! TH-18.2.99: Wenn wir Zeit haben sollte einmal
1915             // !!! geklaert werden, warum dieses beim Datum gegenueber
1916             // !!! allen anderen Feldern anders behandelt wird.
1917             // !!! Siehe dazu Bug: 52304
1918 
1919             if ( !ImplAllowMalformedInput() )
1920             {
1921                 if ( maLastDate.GetDate() )
1922                     aDate = maLastDate;
1923                 else if ( !IsEmptyFieldValueEnabled() )
1924                     aDate = Date();
1925             }
1926             else
1927                 aDate = GetInvalidDate();
1928         }
1929     }
1930 
1931     return aDate;
1932 }
1933 
1934 // -----------------------------------------------------------------------
1935 
1936 Date DateFormatter::GetRealDate() const
1937 {
1938     // !!! TH-18.2.99: Wenn wir Zeit haben sollte dieses auch einmal
1939     // !!! fuer die Numeric-Klassen eingebaut werden.
1940 
1941     Date aDate( 0, 0, 0 );
1942 
1943     if ( GetField() )
1944     {
1945         if ( !ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(sal_True), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1946             if ( ImplAllowMalformedInput() )
1947                 aDate = GetInvalidDate();
1948     }
1949 
1950     return aDate;
1951 }
1952 
1953 // -----------------------------------------------------------------------
1954 
1955 void DateFormatter::SetEmptyDate()
1956 {
1957     FormatterBase::SetEmptyFieldValue();
1958 }
1959 
1960 // -----------------------------------------------------------------------
1961 
1962 sal_Bool DateFormatter::IsEmptyDate() const
1963 {
1964     sal_Bool bEmpty = FormatterBase::IsEmptyFieldValue();
1965 
1966     if ( GetField() && MustBeReformatted() && IsEmptyFieldValueEnabled() )
1967     {
1968         if ( !GetField()->GetText().Len() )
1969         {
1970             bEmpty = sal_True;
1971         }
1972         else if ( !maLastDate.GetDate() )
1973         {
1974             Date aDate;
1975             bEmpty = !ImplDateGetValue( GetField()->GetText(), aDate, GetExtDateFormat(sal_True), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() );
1976         }
1977     }
1978     return bEmpty;
1979 }
1980 
1981 // -----------------------------------------------------------------------
1982 
1983 sal_Bool DateFormatter::IsDateModified() const
1984 {
1985     if ( ImplGetEmptyFieldValue() )
1986         return !IsEmptyDate();
1987     else if ( GetDate() != maFieldDate )
1988         return sal_True;
1989     else
1990         return sal_False;
1991 }
1992 
1993 // -----------------------------------------------------------------------
1994 
1995 void DateFormatter::Reformat()
1996 {
1997     if ( !GetField() )
1998         return;
1999 
2000     if ( !GetField()->GetText().Len() && ImplGetEmptyFieldValue() )
2001         return;
2002 
2003     XubString aStr;
2004     sal_Bool bOK = ImplDateReformat( GetField()->GetText(), aStr, GetFieldSettings() );
2005     if( !bOK )
2006         return;
2007 
2008     if ( aStr.Len() )
2009     {
2010         ImplSetText( aStr );
2011         ImplDateGetValue( aStr, maLastDate, GetExtDateFormat(sal_True), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() );
2012     }
2013     else
2014     {
2015         if ( maLastDate.GetDate() )
2016             SetDate( maLastDate );
2017         else if ( !IsEmptyFieldValueEnabled() )
2018             SetDate( Date() );
2019         else
2020         {
2021             ImplSetText( ImplGetSVEmptyStr() );
2022             SetEmptyFieldValueData( sal_True );
2023         }
2024     }
2025 }
2026 
2027 // -----------------------------------------------------------------------
2028 
2029 void DateFormatter::ExpandCentury( Date& rDate )
2030 {
2031     ExpandCentury( rDate, utl::MiscCfg().GetYear2000() );
2032 }
2033 
2034 // -----------------------------------------------------------------------
2035 
2036 void DateFormatter::ExpandCentury( Date& rDate, sal_uInt16 nTwoDigitYearStart )
2037 {
2038     sal_uInt16 nDateYear = rDate.GetYear();
2039     if ( nDateYear < 100 )
2040     {
2041         sal_uInt16 nCentury = nTwoDigitYearStart / 100;
2042         if ( nDateYear < (nTwoDigitYearStart % 100) )
2043             nCentury++;
2044         rDate.SetYear( nDateYear + (nCentury*100) );
2045     }
2046 }
2047 
2048 // -----------------------------------------------------------------------
2049 
2050 DateField::DateField( Window* pParent, WinBits nWinStyle ) :
2051     SpinField( pParent, nWinStyle ),
2052     maFirst( GetMin() ),
2053     maLast( GetMax() )
2054 {
2055     SetField( this );
2056     SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
2057     Reformat();
2058     ResetLastDate();
2059 }
2060 
2061 // -----------------------------------------------------------------------
2062 
2063 DateField::DateField( Window* pParent, const ResId& rResId ) :
2064     SpinField( WINDOW_DATEFIELD ),
2065     maFirst( GetMin() ),
2066     maLast( GetMax() )
2067 {
2068     rResId.SetRT( RSC_DATEFIELD );
2069     WinBits nStyle = ImplInitRes( rResId );
2070     SpinField::ImplInit( pParent, nStyle );
2071     SetField( this );
2072     SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
2073     ImplLoadRes( rResId );
2074 
2075     if ( !(nStyle & WB_HIDE ) )
2076         Show();
2077 
2078     ResetLastDate();
2079 }
2080 
2081 // -----------------------------------------------------------------------
2082 
2083 void DateField::ImplLoadRes( const ResId& rResId )
2084 {
2085     SpinField::ImplLoadRes( rResId );
2086 
2087     ResMgr* pMgr = rResId.GetResMgr();
2088     if( pMgr )
2089     {
2090         DateFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
2091 
2092         sal_uLong  nMask = ReadLongRes();
2093         if ( DATEFIELD_FIRST & nMask )
2094         {
2095             maFirst = Date( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
2096             IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
2097         }
2098         if ( DATEFIELD_LAST & nMask )
2099         {
2100             maLast = Date( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
2101             IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
2102         }
2103     }
2104 
2105     Reformat();
2106 }
2107 
2108 // -----------------------------------------------------------------------
2109 
2110 DateField::~DateField()
2111 {
2112 }
2113 
2114 // -----------------------------------------------------------------------
2115 
2116 long DateField::PreNotify( NotifyEvent& rNEvt )
2117 {
2118     if ( (rNEvt.GetType() == EVENT_KEYINPUT) && IsStrictFormat() &&
2119          ( GetExtDateFormat() != XTDATEF_SYSTEM_LONG ) &&
2120          !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
2121     {
2122         if ( ImplDateProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetExtDateFormat( sal_True ), ImplGetLocaleDataWrapper() ) )
2123             return 1;
2124     }
2125 
2126     return SpinField::PreNotify( rNEvt );
2127 }
2128 
2129 // -----------------------------------------------------------------------
2130 
2131 long DateField::Notify( NotifyEvent& rNEvt )
2132 {
2133     if ( rNEvt.GetType() == EVENT_GETFOCUS )
2134         MarkToBeReformatted( sal_False );
2135     else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
2136     {
2137         if ( MustBeReformatted() )
2138         {
2139             // !!! TH-18.2.99: Wenn wir Zeit haben sollte einmal
2140             // !!! geklaert werden, warum dieses beim Datum gegenueber
2141             // !!! allen anderen Feldern anders behandelt wird.
2142             // !!! Siehe dazu Bug: 52304
2143 
2144             sal_Bool bTextLen = GetText().Len() != 0;
2145             if ( bTextLen || !IsEmptyFieldValueEnabled() )
2146             {
2147                 if ( !ImplAllowMalformedInput() )
2148                     Reformat();
2149                 else
2150                 {
2151                     Date aDate( 0, 0, 0 );
2152                     if ( ImplDateGetValue( GetText(), aDate, GetExtDateFormat(sal_True), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
2153                         // even with strict text analysis, our text is a valid date -> do a complete
2154                         // reformat
2155                         Reformat();
2156                 }
2157             }
2158             else if ( !bTextLen && IsEmptyFieldValueEnabled() )
2159             {
2160                 ResetLastDate();
2161                 SetEmptyFieldValueData( sal_True );
2162             }
2163         }
2164     }
2165 
2166     return SpinField::Notify( rNEvt );
2167 }
2168 
2169 // -----------------------------------------------------------------------
2170 
2171 void DateField::DataChanged( const DataChangedEvent& rDCEvt )
2172 {
2173     SpinField::DataChanged( rDCEvt );
2174 
2175     if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & (SETTINGS_LOCALE|SETTINGS_MISC)) )
2176     {
2177         if ( IsDefaultLocale() && ( rDCEvt.GetFlags() & SETTINGS_LOCALE ) )
2178             ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
2179         ReformatAll();
2180     }
2181 }
2182 
2183 // -----------------------------------------------------------------------
2184 
2185 void DateField::Modify()
2186 {
2187     MarkToBeReformatted( sal_True );
2188     SpinField::Modify();
2189 }
2190 
2191 // -----------------------------------------------------------------------
2192 
2193 void DateField::Up()
2194 {
2195     ImplDateSpinArea( sal_True );
2196     SpinField::Up();
2197 }
2198 
2199 // -----------------------------------------------------------------------
2200 
2201 void DateField::Down()
2202 {
2203     ImplDateSpinArea( sal_False );
2204     SpinField::Down();
2205 }
2206 
2207 // -----------------------------------------------------------------------
2208 
2209 void DateField::First()
2210 {
2211     ImplNewFieldValue( maFirst );
2212     SpinField::First();
2213 }
2214 
2215 // -----------------------------------------------------------------------
2216 
2217 void DateField::Last()
2218 {
2219     ImplNewFieldValue( maLast );
2220     SpinField::Last();
2221 }
2222 
2223 // -----------------------------------------------------------------------
2224 
2225 DateBox::DateBox( Window* pParent, WinBits nWinStyle ) :
2226     ComboBox( pParent, nWinStyle )
2227 {
2228     SetField( this );
2229     SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
2230     Reformat();
2231 }
2232 
2233 // -----------------------------------------------------------------------
2234 
2235 DateBox::DateBox( Window* pParent, const ResId& rResId ) :
2236     ComboBox( WINDOW_DATEBOX )
2237 {
2238     rResId.SetRT( RSC_DATEBOX );
2239     WinBits nStyle = ImplInitRes( rResId );
2240     ComboBox::ImplInit( pParent, nStyle );
2241     SetField( this );
2242     SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
2243     ComboBox::ImplLoadRes( rResId );
2244     ResMgr* pMgr = rResId.GetResMgr();
2245     if( pMgr )
2246         DateFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
2247     Reformat();
2248 
2249     if ( !( nStyle & WB_HIDE ) )
2250         Show();
2251 }
2252 
2253 // -----------------------------------------------------------------------
2254 
2255 DateBox::~DateBox()
2256 {
2257 }
2258 
2259 // -----------------------------------------------------------------------
2260 
2261 long DateBox::PreNotify( NotifyEvent& rNEvt )
2262 {
2263     if ( (rNEvt.GetType() == EVENT_KEYINPUT) && IsStrictFormat() &&
2264          ( GetExtDateFormat() != XTDATEF_SYSTEM_LONG ) &&
2265          !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
2266     {
2267         if ( ImplDateProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), GetExtDateFormat( sal_True ), ImplGetLocaleDataWrapper() ) )
2268             return 1;
2269     }
2270 
2271     return ComboBox::PreNotify( rNEvt );
2272 }
2273 
2274 // -----------------------------------------------------------------------
2275 
2276 void DateBox::DataChanged( const DataChangedEvent& rDCEvt )
2277 {
2278     ComboBox::DataChanged( rDCEvt );
2279 
2280     if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
2281     {
2282         if ( IsDefaultLocale() )
2283             ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
2284         ReformatAll();
2285     }
2286 }
2287 
2288 // -----------------------------------------------------------------------
2289 
2290 long DateBox::Notify( NotifyEvent& rNEvt )
2291 {
2292     if ( rNEvt.GetType() == EVENT_GETFOCUS )
2293         MarkToBeReformatted( sal_False );
2294     else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
2295     {
2296         if ( MustBeReformatted() )
2297         {
2298             sal_Bool bTextLen = GetText().Len() != 0;
2299             if ( bTextLen || !IsEmptyFieldValueEnabled() )
2300                 Reformat();
2301             else if ( !bTextLen && IsEmptyFieldValueEnabled() )
2302             {
2303                 ResetLastDate();
2304                 SetEmptyFieldValueData( sal_True );
2305             }
2306         }
2307     }
2308 
2309     return ComboBox::Notify( rNEvt );
2310 }
2311 
2312 // -----------------------------------------------------------------------
2313 
2314 void DateBox::Modify()
2315 {
2316     MarkToBeReformatted( sal_True );
2317     ComboBox::Modify();
2318 }
2319 
2320 // -----------------------------------------------------------------------
2321 
2322 void DateBox::ReformatAll()
2323 {
2324     XubString aStr;
2325     SetUpdateMode( sal_False );
2326     sal_uInt16 nEntryCount = GetEntryCount();
2327     for ( sal_uInt16 i=0; i < nEntryCount; i++ )
2328     {
2329         ImplDateReformat( GetEntry( i ), aStr, GetFieldSettings() );
2330         RemoveEntry( i );
2331         InsertEntry( aStr, i );
2332     }
2333     DateFormatter::Reformat();
2334     SetUpdateMode( sal_True );
2335 }
2336 
2337 // -----------------------------------------------------------------------
2338 
2339 void DateBox::InsertDate( const Date& rDate, sal_uInt16 nPos )
2340 {
2341     Date aDate = rDate;
2342     if ( aDate > GetMax() )
2343         aDate = GetMax();
2344     else if ( aDate < GetMin() )
2345         aDate = GetMin();
2346 
2347     ComboBox::InsertEntry( ImplGetDateAsText( aDate, GetFieldSettings() ), nPos );
2348 }
2349 
2350 // -----------------------------------------------------------------------
2351 
2352 void DateBox::RemoveDate( const Date& rDate )
2353 {
2354     ComboBox::RemoveEntry( ImplGetDateAsText( rDate, GetFieldSettings() ) );
2355 }
2356 
2357 // -----------------------------------------------------------------------
2358 
2359 Date DateBox::GetDate( sal_uInt16 nPos ) const
2360 {
2361     Date aDate( 0, 0, 0 );
2362     ImplDateGetValue( ComboBox::GetEntry( nPos ), aDate, GetExtDateFormat(sal_True), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetSettings() );
2363     return aDate;
2364 }
2365 
2366 // -----------------------------------------------------------------------
2367 
2368 sal_uInt16 DateBox::GetDatePos( const Date& rDate ) const
2369 {
2370     XubString aStr;
2371     if ( IsLongFormat() )
2372         aStr = ImplGetLocaleDataWrapper().getLongDate( rDate, GetCalendarWrapper(), 1, sal_False, 1, !IsShowDateCentury() );
2373     else
2374         aStr = ImplGetLocaleDataWrapper().getDate( rDate );
2375     return ComboBox::GetEntryPos( aStr );
2376 }
2377 
2378 // -----------------------------------------------------------------------
2379 
2380 static sal_Bool ImplTimeProcessKeyInput( Edit*, const KeyEvent& rKEvt,
2381                                      sal_Bool bStrictFormat, sal_Bool bDuration,
2382                                      TimeFieldFormat eFormat,
2383                                      const LocaleDataWrapper& rLocaleDataWrapper  )
2384 {
2385     xub_Unicode cChar = rKEvt.GetCharCode();
2386 
2387     if ( !bStrictFormat )
2388         return sal_False;
2389     else
2390     {
2391         sal_uInt16 nGroup = rKEvt.GetKeyCode().GetGroup();
2392         if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
2393              (nGroup == KEYGROUP_MISC)   ||
2394              ((cChar >= '0') && (cChar <= '9')) ||
2395              (cChar == rLocaleDataWrapper.getTimeSep()) ||
2396              ( ( rLocaleDataWrapper.getTimeAM().Search( cChar ) != STRING_NOTFOUND ) ) ||
2397              ( ( rLocaleDataWrapper.getTimePM().Search( cChar ) != STRING_NOTFOUND ) ) ||
2398              // Accept AM/PM:
2399              (cChar == 'a') || (cChar == 'A') || (cChar == 'm') || (cChar == 'M') || (cChar == 'p') || (cChar == 'P') ||
2400              ((eFormat == TIMEF_100TH_SEC) && (cChar == rLocaleDataWrapper.getTime100SecSep())) ||
2401              ((eFormat == TIMEF_SEC_CS) && (cChar == rLocaleDataWrapper.getTime100SecSep())) ||
2402              (bDuration && (cChar == '-')) )
2403             return sal_False;
2404         else
2405             return sal_True;
2406     }
2407 }
2408 
2409 // -----------------------------------------------------------------------
2410 
2411 static sal_Bool ImplIsOnlyDigits( const String& _rStr )
2412 {
2413     const sal_Unicode* _pChr = _rStr.GetBuffer();
2414     for ( xub_StrLen i = 0; i < _rStr.Len(); ++i, ++_pChr )
2415     {
2416         if ( *_pChr < '0' || *_pChr > '9' )
2417             return sal_False;
2418     }
2419     return sal_True;
2420 }
2421 
2422 // -----------------------------------------------------------------------
2423 
2424 static sal_Bool ImplIsValidTimePortion( sal_Bool _bSkipInvalidCharacters, const String& _rStr )
2425 {
2426     if ( !_bSkipInvalidCharacters )
2427     {
2428         if ( ( _rStr.Len() > 2 ) || ( _rStr.Len() < 1 ) || !ImplIsOnlyDigits( _rStr ) )
2429             return sal_False;
2430     }
2431     return sal_True;
2432 }
2433 
2434 // -----------------------------------------------------------------------
2435 
2436 static sal_Bool ImplCutTimePortion( String& _rStr, xub_StrLen _nSepPos, sal_Bool _bSkipInvalidCharacters, short* _pPortion )
2437 {
2438     String sPortion = _rStr.Copy( 0, _nSepPos );
2439     _rStr.Erase( 0, _nSepPos + 1 );
2440 
2441     if ( !ImplIsValidTimePortion( _bSkipInvalidCharacters, sPortion ) )
2442         return sal_False;
2443     *_pPortion = (short)sPortion.ToInt32();
2444     return sal_True;
2445 }
2446 
2447 // -----------------------------------------------------------------------
2448 
2449 static sal_Bool ImplTimeGetValue( const XubString& rStr, Time& rTime,
2450                               TimeFieldFormat eFormat, sal_Bool bDuration,
2451                               const LocaleDataWrapper& rLocaleDataWrapper, sal_Bool _bSkipInvalidCharacters = sal_True )
2452 {
2453     XubString   aStr    = rStr;
2454     short       nHour   = 0;
2455     short       nMinute = 0;
2456     short       nSecond = 0;
2457     short       n100Sec = 0;
2458     Time        aTime( 0, 0, 0 );
2459 
2460     if ( !rStr.Len() )
2461         return sal_False;
2462 
2463     // Nach Separatoren suchen
2464     if ( rLocaleDataWrapper.getTimeSep().Len() )
2465     {
2466         XubString aSepStr( RTL_CONSTASCII_USTRINGPARAM( ",.;:/" ) );
2467         if ( !bDuration )
2468             aSepStr.Append( '-' );
2469 
2470         // Die obigen Zeichen durch das Separatorzeichen ersetzen
2471         for ( xub_StrLen i = 0; i < aSepStr.Len(); i++ )
2472         {
2473             if ( aSepStr.GetChar( i ) == rLocaleDataWrapper.getTimeSep() )
2474                 continue;
2475             for ( xub_StrLen j = 0; j < aStr.Len(); j++ )
2476             {
2477                 if ( aStr.GetChar( j ) == aSepStr.GetChar( i ) )
2478                     aStr.SetChar( j, rLocaleDataWrapper.getTimeSep().GetChar(0) );
2479             }
2480         }
2481     }
2482 
2483     sal_Bool bNegative = sal_False;
2484     xub_StrLen nSepPos = aStr.Search( rLocaleDataWrapper.getTimeSep() );
2485     if ( aStr.GetChar( 0 ) == '-' )
2486         bNegative = sal_True;
2487     if ( eFormat != TIMEF_SEC_CS )
2488     {
2489         if ( nSepPos == STRING_NOTFOUND )
2490             nSepPos = aStr.Len();
2491         if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nHour ) )
2492             return sal_False;
2493 
2494         nSepPos = aStr.Search( rLocaleDataWrapper.getTimeSep() );
2495         if ( aStr.GetChar( 0 ) == '-' )
2496             bNegative = sal_True;
2497         if ( nSepPos != STRING_NOTFOUND )
2498         {
2499             if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nMinute ) )
2500                 return sal_False;
2501 
2502             nSepPos = aStr.Search( rLocaleDataWrapper.getTimeSep() );
2503             if ( aStr.GetChar( 0 ) == '-' )
2504                 bNegative = sal_True;
2505             if ( nSepPos != STRING_NOTFOUND )
2506             {
2507                 if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nSecond ) )
2508                     return sal_False;
2509                 if ( aStr.GetChar( 0 ) == '-' )
2510                     bNegative = sal_True;
2511                 n100Sec = (short)aStr.ToInt32();
2512             }
2513             else
2514                 nSecond = (short)aStr.ToInt32();
2515         }
2516         else
2517             nMinute = (short)aStr.ToInt32();
2518     }
2519     else if ( nSepPos == STRING_NOTFOUND )
2520     {
2521         nSecond = (short)aStr.ToInt32();
2522         nMinute += nSecond / 60;
2523         nSecond %= 60;
2524         nHour += nMinute / 60;
2525         nMinute %= 60;
2526     }
2527     else
2528     {
2529         nSecond = (short)aStr.Copy( 0, nSepPos ).ToInt32();
2530         aStr.Erase( 0, nSepPos+1 );
2531 
2532         nSepPos = aStr.Search( rLocaleDataWrapper.getTimeSep() );
2533         if ( aStr.GetChar( 0 ) == '-' )
2534             bNegative = sal_True;
2535         if ( nSepPos != STRING_NOTFOUND )
2536         {
2537             nMinute = nSecond;
2538             nSecond = (short)aStr.Copy( 0, nSepPos ).ToInt32();
2539             aStr.Erase( 0, nSepPos+1 );
2540 
2541             nSepPos = aStr.Search( rLocaleDataWrapper.getTimeSep() );
2542             if ( aStr.GetChar( 0 ) == '-' )
2543                 bNegative = sal_True;
2544             if ( nSepPos != STRING_NOTFOUND )
2545             {
2546                 nHour   = nMinute;
2547                 nMinute = nSecond;
2548                 nSecond = (short)aStr.Copy( 0, nSepPos ).ToInt32();
2549                 aStr.Erase( 0, nSepPos+1 );
2550             }
2551             else
2552             {
2553                 nHour += nMinute / 60;
2554                 nMinute %= 60;
2555             }
2556         }
2557         else
2558         {
2559             nMinute += nSecond / 60;
2560             nSecond %= 60;
2561             nHour += nMinute / 60;
2562             nMinute %= 60;
2563         }
2564         n100Sec = (short)aStr.ToInt32();
2565 
2566         if ( n100Sec )
2567         {
2568             xub_StrLen nLen = 1; // mindestens eine Ziffer, weil sonst n100Sec==0
2569 
2570             while ( aStr.GetChar(nLen) >= '0' && aStr.GetChar(nLen) <= '9' )
2571                 nLen++;
2572 
2573             if ( nLen > 2 )
2574             {
2575                 while( nLen > 3 )
2576                 {
2577                     n100Sec = n100Sec / 10;
2578                     nLen--;
2579                 }
2580                 // Rundung bei negativen Zahlen???
2581                 n100Sec = (n100Sec + 5) / 10;
2582             }
2583             else
2584             {
2585                 while( nLen < 2 )
2586                 {
2587                     n100Sec = n100Sec * 10;
2588                     nLen++;
2589                 }
2590             }
2591         }
2592     }
2593 
2594     if ( (nMinute > 59) || (nSecond > 59) || (n100Sec > 100) )
2595         return sal_False;
2596 
2597     if ( eFormat == TIMEF_NONE )
2598         nSecond = n100Sec = 0;
2599     else if ( eFormat == TIMEF_SEC )
2600         n100Sec = 0;
2601 
2602     if ( !bDuration )
2603     {
2604         if ( bNegative || (nHour < 0) || (nMinute < 0) ||
2605              (nSecond < 0) || (n100Sec < 0) )
2606             return sal_False;
2607 
2608         aStr.ToUpperAscii();
2609         XubString aAM( rLocaleDataWrapper.getTimeAM() );
2610         XubString aPM( rLocaleDataWrapper.getTimePM() );
2611         aAM.ToUpperAscii();
2612         aPM.ToUpperAscii();
2613         XubString aAM2( RTL_CONSTASCII_USTRINGPARAM( "AM" ) );  // aAM is localized
2614         XubString aPM2( RTL_CONSTASCII_USTRINGPARAM( "PM" ) );  // aPM is localized
2615 
2616         if ( (nHour < 12) && ( ( aStr.Search( aPM ) != STRING_NOTFOUND ) || ( aStr.Search( aPM2 ) != STRING_NOTFOUND ) ) )
2617             nHour += 12;
2618 
2619         if ( (nHour == 12) && ( ( aStr.Search( aAM ) != STRING_NOTFOUND ) || ( aStr.Search( aAM2 ) != STRING_NOTFOUND ) ) )
2620             nHour = 0;
2621 
2622         aTime = Time( (sal_uInt16)nHour, (sal_uInt16)nMinute, (sal_uInt16)nSecond,
2623                       (sal_uInt16)n100Sec );
2624     }
2625     else
2626     {
2627         if ( bNegative || (nHour < 0) || (nMinute < 0) ||
2628              (nSecond < 0) || (n100Sec < 0) )
2629         {
2630             bNegative   = sal_True;
2631             nHour       = nHour < 0 ? -nHour : nHour;
2632             nMinute     = nMinute < 0 ? -nMinute : nMinute;
2633             nSecond     = nSecond < 0 ? -nSecond : nSecond;
2634             n100Sec     = n100Sec < 0 ? -n100Sec : n100Sec;
2635         }
2636 
2637         aTime = Time( (sal_uInt16)nHour, (sal_uInt16)nMinute, (sal_uInt16)nSecond,
2638                       (sal_uInt16)n100Sec );
2639         if ( bNegative )
2640             aTime = -aTime;
2641     }
2642 
2643     rTime = aTime;
2644 
2645     return sal_True;
2646 }
2647 
2648 // -----------------------------------------------------------------------
2649 
2650 sal_Bool TimeFormatter::ImplTimeReformat( const XubString& rStr, XubString& rOutStr )
2651 {
2652     Time aTime( 0, 0, 0 );
2653     if ( !ImplTimeGetValue( rStr, aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() ) )
2654         return sal_True;
2655 
2656     Time aTempTime = aTime;
2657     if ( aTempTime > GetMax() )
2658         aTempTime = GetMax() ;
2659     else if ( aTempTime < GetMin() )
2660         aTempTime = GetMin();
2661 
2662     if ( GetErrorHdl().IsSet() && (aTime != aTempTime) )
2663     {
2664         maCorrectedTime = aTempTime;
2665         if ( !GetErrorHdl().Call( this ) )
2666         {
2667             maCorrectedTime = Time();
2668             return sal_False;
2669         }
2670         else
2671             maCorrectedTime = Time();
2672     }
2673 
2674     sal_Bool bSecond = sal_False;
2675     sal_Bool b100Sec = sal_False;
2676     if ( meFormat != TIMEF_NONE )
2677         bSecond = sal_True;
2678     if ( meFormat == TIMEF_100TH_SEC )
2679         b100Sec = sal_True;
2680 
2681     if ( meFormat == TIMEF_SEC_CS )
2682     {
2683         sal_uLong n  = aTempTime.GetHour() * 3600L;
2684         n       += aTempTime.GetMin()  * 60L;
2685         n       += aTempTime.GetSec();
2686         rOutStr  = String::CreateFromInt32( n );
2687         rOutStr += ImplGetLocaleDataWrapper().getTime100SecSep();
2688         if ( aTempTime.Get100Sec() < 10 )
2689             rOutStr += '0';
2690         rOutStr += String::CreateFromInt32( aTempTime.Get100Sec() );
2691     }
2692     else if ( mbDuration )
2693         rOutStr = ImplGetLocaleDataWrapper().getDuration( aTempTime, bSecond, b100Sec );
2694     else
2695     {
2696         rOutStr = ImplGetLocaleDataWrapper().getTime( aTempTime, bSecond, b100Sec );
2697         if ( GetTimeFormat() == HOUR_12 )
2698         {
2699             if ( aTempTime.GetHour() > 12 )
2700             {
2701                 Time aT( aTempTime );
2702                 aT.SetHour( aT.GetHour() % 12 );
2703                 rOutStr = ImplGetLocaleDataWrapper().getTime( aT, bSecond, b100Sec );
2704             }
2705             // Don't use LocaleDataWrapper, we want AM/PM
2706             if ( aTempTime.GetHour() < 12 )
2707                 rOutStr += String( RTL_CONSTASCII_USTRINGPARAM( "AM" ) ); // ImplGetLocaleDataWrapper().getTimeAM();
2708             else
2709                 rOutStr += String( RTL_CONSTASCII_USTRINGPARAM( "PM" ) ); // ImplGetLocaleDataWrapper().getTimePM();
2710         }
2711     }
2712 
2713     return sal_True;
2714 }
2715 
2716 // -----------------------------------------------------------------------
2717 sal_Bool TimeFormatter::ImplAllowMalformedInput() const
2718 {
2719     return !IsEnforceValidValue();
2720 }
2721 
2722 // -----------------------------------------------------------------------
2723 
2724 void TimeField::ImplTimeSpinArea( sal_Bool bUp )
2725 {
2726     if ( GetField() )
2727     {
2728         xub_StrLen nTimeArea = 0;
2729         Time aTime( GetTime() );
2730         XubString aText( GetText() );
2731         Selection aSelection( GetField()->GetSelection() );
2732 
2733         // Area suchen
2734         if ( GetFormat() != TIMEF_SEC_CS )
2735         {
2736             for ( xub_StrLen i = 1, nPos = 0; i <= 4; i++ )
2737             {
2738                 xub_StrLen nPos1 = aText.Search( ImplGetLocaleDataWrapper().getTimeSep(), nPos );
2739                 xub_StrLen nPos2 = aText.Search( ImplGetLocaleDataWrapper().getTime100SecSep(), nPos );
2740                 nPos = nPos1 < nPos2 ? nPos1 : nPos2;
2741                 if ( nPos >= (xub_StrLen)aSelection.Max() )
2742                 {
2743                     nTimeArea = i;
2744                     break;
2745                 }
2746                 else
2747                     nPos++;
2748             }
2749         }
2750         else
2751         {
2752             xub_StrLen nPos = aText.Search( ImplGetLocaleDataWrapper().getTime100SecSep() );
2753             if ( nPos == STRING_NOTFOUND || nPos >= (xub_StrLen)aSelection.Max() )
2754                 nTimeArea = 3;
2755             else
2756                 nTimeArea = 4;
2757         }
2758 
2759         if ( nTimeArea )
2760         {
2761             Time aAddTime( 0, 0, 0 );
2762             if ( nTimeArea == 1 )
2763                 aAddTime = Time( 1, 0 );
2764             else if ( nTimeArea == 2 )
2765                 aAddTime = Time( 0, 1 );
2766             else if ( nTimeArea == 3 )
2767                 aAddTime = Time( 0, 0, 1 );
2768             else if ( nTimeArea == 4 )
2769                 aAddTime = Time( 0, 0, 0, 1 );
2770 
2771             if ( !bUp )
2772                 aAddTime = -aAddTime;
2773 
2774             aTime += aAddTime;
2775             if ( !IsDuration() )
2776             {
2777                 Time aAbsMaxTime( 23, 59, 59, 99 );
2778                 if ( aTime > aAbsMaxTime )
2779                     aTime = aAbsMaxTime;
2780                 Time aAbsMinTime( 0, 0 );
2781                 if ( aTime < aAbsMinTime )
2782                     aTime = aAbsMinTime;
2783             }
2784             ImplNewFieldValue( aTime );
2785         }
2786 
2787     }
2788 }
2789 
2790 // -----------------------------------------------------------------------
2791 
2792 void TimeFormatter::ImplInit()
2793 {
2794     meFormat        = TIMEF_NONE;
2795     mbDuration      = sal_False;
2796     mnTimeFormat    = HOUR_24;  // Should become a ExtTimeFieldFormat in next implementation, merge with mbDuration and meFormat
2797 }
2798 
2799 // -----------------------------------------------------------------------
2800 
2801 TimeFormatter::TimeFormatter() :
2802     maLastTime( 0, 0 ),
2803     maMin( 0, 0 ),
2804     maMax( 23, 59, 59, 99 ),
2805     mbEnforceValidValue( sal_True ),
2806     maFieldTime( 0, 0 )
2807 {
2808     ImplInit();
2809 }
2810 
2811 // -----------------------------------------------------------------------
2812 
2813 void TimeFormatter::ImplLoadRes( const ResId& rResId )
2814 {
2815     ResMgr* pMgr = rResId.GetResMgr();
2816     if( pMgr )
2817     {
2818         sal_uLong   nMask = pMgr->ReadLong();
2819 
2820         if ( TIMEFORMATTER_MIN & nMask )
2821         {
2822             SetMin( Time( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) ) );
2823             pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE *)pMgr->GetClass() ) );
2824         }
2825 
2826         if ( TIMEFORMATTER_MAX & nMask )
2827         {
2828             SetMax( Time( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) ) );
2829             pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE *)pMgr->GetClass() ) );
2830         }
2831 
2832         if ( TIMEFORMATTER_TIMEFIELDFORMAT & nMask )
2833             meFormat = (TimeFieldFormat)pMgr->ReadLong();
2834 
2835         if ( TIMEFORMATTER_DURATION & nMask )
2836             mbDuration = (sal_Bool)pMgr->ReadShort();
2837 
2838         if ( TIMEFORMATTER_STRICTFORMAT & nMask )
2839             SetStrictFormat( (sal_Bool)pMgr->ReadShort() );
2840 
2841         if ( TIMEFORMATTER_VALUE & nMask )
2842         {
2843             maFieldTime = Time( ResId( (RSHEADER_TYPE *)pMgr->GetClass(), *pMgr ) );
2844             if ( maFieldTime > GetMax() )
2845                 maFieldTime = GetMax();
2846             if ( maFieldTime < GetMin() )
2847                 maFieldTime = GetMin();
2848             maLastTime = maFieldTime;
2849 
2850             pMgr->Increment( pMgr->GetObjSize( (RSHEADER_TYPE *)pMgr->GetClass() ) );
2851         }
2852     }
2853 }
2854 
2855 // -----------------------------------------------------------------------
2856 
2857 TimeFormatter::~TimeFormatter()
2858 {
2859 }
2860 
2861 // -----------------------------------------------------------------------
2862 
2863 void TimeFormatter::ReformatAll()
2864 {
2865     Reformat();
2866 }
2867 
2868 // -----------------------------------------------------------------------
2869 
2870 void TimeFormatter::SetMin( const Time& rNewMin )
2871 {
2872     maMin = rNewMin;
2873     if ( !IsEmptyFieldValue() )
2874         ReformatAll();
2875 }
2876 
2877 // -----------------------------------------------------------------------
2878 
2879 void TimeFormatter::SetMax( const Time& rNewMax )
2880 {
2881     maMax = rNewMax;
2882     if ( !IsEmptyFieldValue() )
2883         ReformatAll();
2884 }
2885 
2886 // -----------------------------------------------------------------------
2887 
2888 void TimeFormatter::SetTimeFormat( TimeFormatter::TimeFormat eNewFormat )
2889 {
2890     mnTimeFormat = sal::static_int_cast<sal_uInt16>(eNewFormat);
2891 }
2892 
2893 // -----------------------------------------------------------------------
2894 
2895 TimeFormatter::TimeFormat TimeFormatter::GetTimeFormat() const
2896 {
2897     return (TimeFormat)mnTimeFormat;
2898 }
2899 
2900 // -----------------------------------------------------------------------
2901 
2902 void TimeFormatter::SetFormat( TimeFieldFormat eNewFormat )
2903 {
2904     meFormat = eNewFormat;
2905     ReformatAll();
2906 }
2907 
2908 // -----------------------------------------------------------------------
2909 
2910 void TimeFormatter::SetDuration( sal_Bool bNewDuration )
2911 {
2912     mbDuration = bNewDuration;
2913     ReformatAll();
2914 }
2915 
2916 // -----------------------------------------------------------------------
2917 
2918 void TimeFormatter::SetTime( const Time& rNewTime )
2919 {
2920     SetUserTime( rNewTime );
2921     maFieldTime = maLastTime;
2922     SetEmptyFieldValueData( sal_False );
2923 }
2924 
2925 // -----------------------------------------------------------------------
2926 
2927 void TimeFormatter::ImplNewFieldValue( const Time& rTime )
2928 {
2929     if ( GetField() )
2930     {
2931         Selection aSelection = GetField()->GetSelection();
2932         aSelection.Justify();
2933         XubString aText = GetField()->GetText();
2934         // Wenn bis ans Ende selektiert war, soll das auch so bleiben...
2935         if ( (xub_StrLen)aSelection.Max() == aText.Len() )
2936         {
2937             if ( !aSelection.Len() )
2938                 aSelection.Min() = SELECTION_MAX;
2939             aSelection.Max() = SELECTION_MAX;
2940         }
2941 
2942         Time aOldLastTime = maLastTime;
2943         ImplSetUserTime( rTime, &aSelection );
2944         maLastTime = aOldLastTime;
2945 
2946         // Modify am Edit wird nur bei KeyInput gesetzt...
2947         if ( GetField()->GetText() != aText )
2948         {
2949             GetField()->SetModifyFlag();
2950             GetField()->Modify();
2951         }
2952     }
2953 }
2954 
2955 // -----------------------------------------------------------------------
2956 
2957 void TimeFormatter::ImplSetUserTime( const Time& rNewTime, Selection* pNewSelection )
2958 {
2959     Time aNewTime = rNewTime;
2960     if ( aNewTime > GetMax() )
2961         aNewTime = GetMax();
2962     else if ( aNewTime < GetMin() )
2963         aNewTime = GetMin();
2964     maLastTime = aNewTime;
2965 
2966     if ( GetField() )
2967     {
2968         XubString aStr;
2969         sal_Bool bSec    = sal_False;
2970         sal_Bool b100Sec = sal_False;
2971         if ( meFormat != TIMEF_NONE )
2972             bSec = sal_True;
2973         if ( meFormat == TIMEF_100TH_SEC || meFormat == TIMEF_SEC_CS )
2974             b100Sec = sal_True;
2975         if ( meFormat == TIMEF_SEC_CS )
2976         {
2977             sal_uLong n  = aNewTime.GetHour() * 3600L;
2978             n       += aNewTime.GetMin()  * 60L;
2979             n       += aNewTime.GetSec();
2980             aStr     = String::CreateFromInt32( n );
2981             aStr    += ImplGetLocaleDataWrapper().getTime100SecSep();
2982             if ( aNewTime.Get100Sec() < 10 )
2983                 aStr += '0';
2984             aStr += String::CreateFromInt32( aNewTime.Get100Sec() );
2985         }
2986         else if ( mbDuration )
2987         {
2988             aStr = ImplGetLocaleDataWrapper().getDuration( aNewTime, bSec, b100Sec );
2989         }
2990         else
2991         {
2992             aStr = ImplGetLocaleDataWrapper().getTime( aNewTime, bSec, b100Sec );
2993             if ( GetTimeFormat() == HOUR_12 )
2994             {
2995                 if ( aNewTime.GetHour() > 12 )
2996                 {
2997                     Time aT( aNewTime );
2998                     aT.SetHour( aT.GetHour() % 12 );
2999                     aStr = ImplGetLocaleDataWrapper().getTime( aT, bSec, b100Sec );
3000                 }
3001                 // Don't use LocaleDataWrapper, we want AM/PM
3002                 if ( aNewTime.GetHour() < 12 )
3003                     aStr += String( RTL_CONSTASCII_USTRINGPARAM( "AM" ) ); // ImplGetLocaleDataWrapper().getTimeAM();
3004                 else
3005                     aStr += String( RTL_CONSTASCII_USTRINGPARAM( "PM" ) ); // ImplGetLocaleDataWrapper().getTimePM();
3006             }
3007         }
3008 
3009         ImplSetText( aStr, pNewSelection );
3010     }
3011 }
3012 
3013 // -----------------------------------------------------------------------
3014 
3015 void TimeFormatter::SetUserTime( const Time& rNewTime )
3016 {
3017     ImplSetUserTime( rNewTime );
3018 }
3019 
3020 // -----------------------------------------------------------------------
3021 
3022 Time TimeFormatter::GetTime() const
3023 {
3024     Time aTime( 0, 0, 0 );
3025 
3026     if ( GetField() )
3027     {
3028         sal_Bool bAllowMailformed = ImplAllowMalformedInput();
3029         if ( ImplTimeGetValue( GetField()->GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), !bAllowMailformed ) )
3030         {
3031             if ( aTime > GetMax() )
3032                 aTime = GetMax();
3033             else if ( aTime < GetMin() )
3034                 aTime = GetMin();
3035         }
3036         else
3037         {
3038             if ( bAllowMailformed )
3039                 aTime = GetInvalidTime();
3040             else
3041                 aTime = maLastTime;
3042         }
3043     }
3044 
3045     return aTime;
3046 }
3047 
3048 // -----------------------------------------------------------------------
3049 
3050 Time TimeFormatter::GetRealTime() const
3051 {
3052     Time aTime( 0, 0, 0 );
3053 
3054     if ( GetField() )
3055     {
3056         sal_Bool bAllowMailformed = ImplAllowMalformedInput();
3057         if ( !ImplTimeGetValue( GetField()->GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), !bAllowMailformed ) )
3058             if ( bAllowMailformed )
3059                 aTime = GetInvalidTime();
3060     }
3061 
3062     return aTime;
3063 }
3064 
3065 // -----------------------------------------------------------------------
3066 
3067 sal_Bool TimeFormatter::IsTimeModified() const
3068 {
3069     if ( ImplGetEmptyFieldValue() )
3070         return !IsEmptyTime();
3071     else if ( GetTime() != maFieldTime )
3072         return sal_True;
3073     else
3074         return sal_False;
3075 }
3076 
3077 // -----------------------------------------------------------------------
3078 
3079 void TimeFormatter::Reformat()
3080 {
3081     if ( !GetField() )
3082         return;
3083 
3084     if ( !GetField()->GetText().Len() && ImplGetEmptyFieldValue() )
3085         return;
3086 
3087     XubString aStr;
3088     sal_Bool bOK = ImplTimeReformat( GetField()->GetText(), aStr );
3089     if ( !bOK )
3090         return;
3091 
3092     if ( aStr.Len() )
3093     {
3094         ImplSetText( aStr );
3095         ImplTimeGetValue( aStr, maLastTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() );
3096     }
3097     else
3098         SetTime( maLastTime );
3099 }
3100 
3101 // -----------------------------------------------------------------------
3102 
3103 TimeField::TimeField( Window* pParent, WinBits nWinStyle ) :
3104     SpinField( pParent, nWinStyle ),
3105     maFirst( GetMin() ),
3106     maLast( GetMax() )
3107 {
3108     SetField( this );
3109     SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, sal_False, sal_False ) );
3110     Reformat();
3111 }
3112 
3113 // -----------------------------------------------------------------------
3114 
3115 TimeField::TimeField( Window* pParent, const ResId& rResId ) :
3116     SpinField( WINDOW_TIMEFIELD ),
3117     maFirst( GetMin() ),
3118     maLast( GetMax() )
3119 {
3120     rResId.SetRT( RSC_TIMEFIELD );
3121     WinBits nStyle = ImplInitRes( rResId );
3122     SpinField::ImplInit( pParent, nStyle );
3123     SetField( this );
3124     SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, sal_False, sal_False ) );
3125     ImplLoadRes( rResId );
3126 
3127     if ( !(nStyle & WB_HIDE ) )
3128         Show();
3129 }
3130 
3131 // -----------------------------------------------------------------------
3132 
3133 void TimeField::ImplLoadRes( const ResId& rResId )
3134 {
3135     SpinField::ImplLoadRes( rResId );
3136     ResMgr* pMgr = rResId.GetResMgr();
3137     if( pMgr )
3138     {
3139         TimeFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
3140 
3141         sal_uLong      nMask = ReadLongRes();
3142 
3143         if ( TIMEFIELD_FIRST & nMask )
3144         {
3145             maFirst = Time( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
3146             IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
3147         }
3148         if ( TIMEFIELD_LAST & nMask )
3149         {
3150             maLast = Time( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
3151             IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
3152         }
3153     }
3154 
3155     Reformat();
3156 }
3157 
3158 // -----------------------------------------------------------------------
3159 
3160 TimeField::~TimeField()
3161 {
3162 }
3163 
3164 // -----------------------------------------------------------------------
3165 
3166 long TimeField::PreNotify( NotifyEvent& rNEvt )
3167 {
3168     if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
3169     {
3170         if ( ImplTimeProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
3171             return 1;
3172     }
3173 
3174     return SpinField::PreNotify( rNEvt );
3175 }
3176 
3177 // -----------------------------------------------------------------------
3178 
3179 long TimeField::Notify( NotifyEvent& rNEvt )
3180 {
3181     if ( rNEvt.GetType() == EVENT_GETFOCUS )
3182         MarkToBeReformatted( sal_False );
3183     else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
3184     {
3185         if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
3186         {
3187             if ( !ImplAllowMalformedInput() )
3188                 Reformat();
3189             else
3190             {
3191                 Time aTime( 0, 0, 0 );
3192                 if ( ImplTimeGetValue( GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), sal_False ) )
3193                     // even with strict text analysis, our text is a valid time -> do a complete
3194                     // reformat
3195                     Reformat();
3196             }
3197         }
3198     }
3199 
3200     return SpinField::Notify( rNEvt );
3201 }
3202 
3203 // -----------------------------------------------------------------------
3204 
3205 void TimeField::DataChanged( const DataChangedEvent& rDCEvt )
3206 {
3207     SpinField::DataChanged( rDCEvt );
3208 
3209     if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
3210     {
3211         if ( IsDefaultLocale() )
3212             ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
3213         ReformatAll();
3214     }
3215 }
3216 
3217 // -----------------------------------------------------------------------
3218 
3219 void TimeField::Modify()
3220 {
3221     MarkToBeReformatted( sal_True );
3222     SpinField::Modify();
3223 }
3224 
3225 // -----------------------------------------------------------------------
3226 
3227 void TimeField::Up()
3228 {
3229     ImplTimeSpinArea( sal_True );
3230     SpinField::Up();
3231 }
3232 
3233 // -----------------------------------------------------------------------
3234 
3235 void TimeField::Down()
3236 {
3237     ImplTimeSpinArea( sal_False );
3238     SpinField::Down();
3239 }
3240 
3241 // -----------------------------------------------------------------------
3242 
3243 void TimeField::First()
3244 {
3245     ImplNewFieldValue( maFirst );
3246     SpinField::First();
3247 }
3248 
3249 // -----------------------------------------------------------------------
3250 
3251 void TimeField::Last()
3252 {
3253     ImplNewFieldValue( maLast );
3254     SpinField::Last();
3255 }
3256 
3257 // -----------------------------------------------------------------------
3258 
3259 void TimeField::SetExtFormat( ExtTimeFieldFormat eFormat )
3260 {
3261     switch ( eFormat )
3262     {
3263         case EXTTIMEF_24H_SHORT:
3264         {
3265             SetTimeFormat( HOUR_24 );
3266             SetDuration( sal_False );
3267             SetFormat( TIMEF_NONE );
3268         }
3269         break;
3270         case EXTTIMEF_24H_LONG:
3271         {
3272             SetTimeFormat( HOUR_24 );
3273             SetDuration( sal_False );
3274             SetFormat( TIMEF_SEC );
3275         }
3276         break;
3277         case EXTTIMEF_12H_SHORT:
3278         {
3279             SetTimeFormat( HOUR_12 );
3280             SetDuration( sal_False );
3281             SetFormat( TIMEF_NONE );
3282         }
3283         break;
3284         case EXTTIMEF_12H_LONG:
3285         {
3286             SetTimeFormat( HOUR_12 );
3287             SetDuration( sal_False );
3288             SetFormat( TIMEF_SEC );
3289         }
3290         break;
3291         case EXTTIMEF_DURATION_SHORT:
3292         {
3293             SetDuration( sal_True );
3294             SetFormat( TIMEF_NONE );
3295         }
3296         break;
3297         case EXTTIMEF_DURATION_LONG:
3298         {
3299             SetDuration( sal_True );
3300             SetFormat( TIMEF_SEC );
3301         }
3302         break;
3303         default:    DBG_ERROR( "ExtTimeFieldFormat unknown!" );
3304     }
3305 
3306     if ( GetField() && GetField()->GetText().Len() )
3307         SetUserTime( GetTime() );
3308     ReformatAll();
3309 }
3310 
3311 // -----------------------------------------------------------------------
3312 
3313 TimeBox::TimeBox( Window* pParent, WinBits nWinStyle ) :
3314     ComboBox( pParent, nWinStyle )
3315 {
3316     SetField( this );
3317     SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, sal_False, sal_False ) );
3318     Reformat();
3319 }
3320 
3321 // -----------------------------------------------------------------------
3322 
3323 TimeBox::TimeBox( Window* pParent, const ResId& rResId ) :
3324     ComboBox( WINDOW_TIMEBOX )
3325 {
3326     rResId.SetRT( RSC_TIMEBOX );
3327     WinBits nStyle = ImplInitRes( rResId );
3328     ComboBox::ImplInit( pParent, nStyle );
3329     SetField( this );
3330     SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, sal_False, sal_False ) );
3331     ComboBox::ImplLoadRes( rResId );
3332     ResMgr* pMgr = rResId.GetResMgr();
3333     if( pMgr )
3334         TimeFormatter::ImplLoadRes( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) );
3335     Reformat();
3336 
3337     if ( !(nStyle & WB_HIDE) )
3338         Show();
3339 }
3340 
3341 // -----------------------------------------------------------------------
3342 
3343 TimeBox::~TimeBox()
3344 {
3345 }
3346 
3347 // -----------------------------------------------------------------------
3348 
3349 long TimeBox::PreNotify( NotifyEvent& rNEvt )
3350 {
3351     if ( (rNEvt.GetType() == EVENT_KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
3352     {
3353         if ( ImplTimeProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
3354             return 1;
3355     }
3356 
3357     return ComboBox::PreNotify( rNEvt );
3358 }
3359 
3360 // -----------------------------------------------------------------------
3361 
3362 long TimeBox::Notify( NotifyEvent& rNEvt )
3363 {
3364     if ( rNEvt.GetType() == EVENT_GETFOCUS )
3365         MarkToBeReformatted( sal_False );
3366     else if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
3367     {
3368         if ( MustBeReformatted() && (GetText().Len() || !IsEmptyFieldValueEnabled()) )
3369             Reformat();
3370     }
3371 
3372     return ComboBox::Notify( rNEvt );
3373 }
3374 
3375 // -----------------------------------------------------------------------
3376 
3377 void TimeBox::DataChanged( const DataChangedEvent& rDCEvt )
3378 {
3379     ComboBox::DataChanged( rDCEvt );
3380 
3381     if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_LOCALE) )
3382     {
3383         if ( IsDefaultLocale() )
3384             ImplGetLocaleDataWrapper().setLocale( GetSettings().GetLocale() );
3385         ReformatAll();
3386     }
3387 }
3388 
3389 // -----------------------------------------------------------------------
3390 
3391 void TimeBox::Modify()
3392 {
3393     MarkToBeReformatted( sal_True );
3394     ComboBox::Modify();
3395 }
3396 
3397 // -----------------------------------------------------------------------
3398 
3399 void TimeBox::ReformatAll()
3400 {
3401     XubString aStr;
3402     SetUpdateMode( sal_False );
3403     sal_uInt16 nEntryCount = GetEntryCount();
3404     for ( sal_uInt16 i=0; i < nEntryCount; i++ )
3405     {
3406         ImplTimeReformat( GetEntry( i ), aStr );
3407         RemoveEntry( i );
3408         InsertEntry( aStr, i );
3409     }
3410     TimeFormatter::Reformat();
3411     SetUpdateMode( sal_True );
3412 }
3413 
3414 // -----------------------------------------------------------------------
3415 
3416 void TimeBox::InsertTime( const Time& rTime, sal_uInt16 nPos )
3417 {
3418     Time aTime = rTime;
3419     if ( aTime > GetMax() )
3420         aTime = GetMax();
3421     else if ( aTime < GetMin() )
3422         aTime = GetMin();
3423 
3424     sal_Bool bSec    = sal_False;
3425     sal_Bool b100Sec = sal_False;
3426     if ( GetFormat() == TIMEF_SEC )
3427         bSec = sal_True;
3428     if ( GetFormat() == TIMEF_100TH_SEC || GetFormat() == TIMEF_SEC_CS )
3429         bSec = b100Sec = sal_True;
3430     ComboBox::InsertEntry( ImplGetLocaleDataWrapper().getTime( aTime, bSec, b100Sec ), nPos );
3431 }
3432 
3433 // -----------------------------------------------------------------------
3434 
3435 void TimeBox::RemoveTime( const Time& rTime )
3436 {
3437     sal_Bool bSec    = sal_False;
3438     sal_Bool b100Sec = sal_False;
3439     if ( GetFormat() == TIMEF_SEC )
3440         bSec = sal_True;
3441     if ( GetFormat() == TIMEF_100TH_SEC || TIMEF_SEC_CS )
3442         bSec = b100Sec = sal_True;
3443     ComboBox::RemoveEntry( ImplGetLocaleDataWrapper().getTime( rTime, bSec, b100Sec ) );
3444 }
3445 
3446 // -----------------------------------------------------------------------
3447 
3448 Time TimeBox::GetTime( sal_uInt16 nPos ) const
3449 {
3450     Time aTime( 0, 0, 0 );
3451     ImplTimeGetValue( ComboBox::GetEntry( nPos ), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() );
3452     return aTime;
3453 }
3454 
3455 // -----------------------------------------------------------------------
3456 
3457 sal_uInt16 TimeBox::GetTimePos( const Time& rTime ) const
3458 {
3459     sal_Bool bSec    = sal_False;
3460     sal_Bool b100Sec = sal_False;
3461     if ( GetFormat() == TIMEF_SEC )
3462         bSec = sal_True;
3463     if ( GetFormat() == TIMEF_100TH_SEC || TIMEF_SEC_CS )
3464         bSec = b100Sec = sal_True;
3465     return ComboBox::GetEntryPos( ImplGetLocaleDataWrapper().getTime( rTime, bSec, b100Sec ) );
3466 }
3467