1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
23 #include <string_view>
25 #include <tools/diagnose_ex.h>
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/string.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/event.hxx>
30 #include <vcl/field.hxx>
31 #include <vcl/unohelp.hxx>
32 #include <vcl/settings.hxx>
36 #include <com/sun/star/i18n/XCharacterClassification.hpp>
38 #include <unotools/localedatawrapper.hxx>
39 #include <unotools/calendarwrapper.hxx>
40 #include <unotools/charclass.hxx>
41 #include <unotools/misccfg.hxx>
43 using namespace ::com::sun::star
;
44 using namespace ::comphelper
;
46 #define EDITMASK_LITERAL 'L'
47 #define EDITMASK_ALPHA 'a'
48 #define EDITMASK_UPPERALPHA 'A'
49 #define EDITMASK_ALPHANUM 'c'
50 #define EDITMASK_UPPERALPHANUM 'C'
51 #define EDITMASK_NUM 'N'
52 #define EDITMASK_NUMSPACE 'n'
53 #define EDITMASK_ALLCHAR 'x'
54 #define EDITMASK_UPPERALLCHAR 'X'
56 uno::Reference
< i18n::XCharacterClassification
> const & ImplGetCharClass()
58 ImplSVData
*const pSVData
= ImplGetSVData();
61 if (!pSVData
->m_xCharClass
.is())
63 pSVData
->m_xCharClass
= vcl::unohelper::CreateCharacterClassification();
66 return pSVData
->m_xCharClass
;
69 static sal_Unicode
* ImplAddString( sal_Unicode
* pBuf
, const OUString
& rStr
)
71 memcpy( pBuf
, rStr
.getStr(), rStr
.getLength() * sizeof(sal_Unicode
) );
72 pBuf
+= rStr
.getLength();
76 static sal_Unicode
* ImplAddNum( sal_Unicode
* pBuf
, sal_uLong nNumber
, int nMinLen
)
78 // fill temp buffer with digits
79 sal_Unicode aTempBuf
[30];
80 sal_Unicode
* pTempBuf
= aTempBuf
;
83 *pTempBuf
= static_cast<sal_Unicode
>(nNumber
% 10) + '0';
91 // fill with zeros up to the minimal length
99 // copy temp buffer to real buffer
106 while ( pTempBuf
!= aTempBuf
);
111 static sal_Unicode
* ImplAddSNum( sal_Unicode
* pBuf
, sal_Int32 nNumber
, int nMinLen
)
118 return ImplAddNum( pBuf
, nNumber
, nMinLen
);
121 static sal_uInt16
ImplGetNum( const sal_Unicode
*& rpBuf
, bool& rbError
)
129 sal_uInt16 nNumber
= 0;
130 while( ( *rpBuf
>= '0' ) && ( *rpBuf
<= '9' ) )
133 nNumber
+= *rpBuf
- '0';
140 static void ImplSkipDelimiters( const sal_Unicode
*& rpBuf
)
142 while( ( *rpBuf
== ',' ) || ( *rpBuf
== '.' ) || ( *rpBuf
== ';' ) ||
143 ( *rpBuf
== ':' ) || ( *rpBuf
== '-' ) || ( *rpBuf
== '/' ) )
149 static bool ImplIsPatternChar( sal_Unicode cChar
, sal_Char cEditMask
)
155 OUString
aCharStr(cChar
);
156 nType
= ImplGetCharClass()->getStringType( aCharStr
, 0, aCharStr
.getLength(),
157 Application::GetSettings().GetLanguageTag().getLocale() );
159 catch (const css::uno::Exception
&)
161 DBG_UNHANDLED_EXCEPTION("vcl.control");
165 if ( (cEditMask
== EDITMASK_ALPHA
) || (cEditMask
== EDITMASK_UPPERALPHA
) )
167 if( !CharClass::isLetterType( nType
) )
170 else if ( cEditMask
== EDITMASK_NUM
)
172 if( !CharClass::isNumericType( nType
) )
175 else if ( (cEditMask
== EDITMASK_ALPHANUM
) || (cEditMask
== EDITMASK_UPPERALPHANUM
) )
177 if( !CharClass::isLetterNumericType( nType
) )
180 else if ( (cEditMask
== EDITMASK_ALLCHAR
) || (cEditMask
== EDITMASK_UPPERALLCHAR
) )
185 else if ( cEditMask
== EDITMASK_NUMSPACE
)
187 if ( !CharClass::isNumericType( nType
) && ( cChar
!= ' ' ) )
196 static sal_Unicode
ImplPatternChar( sal_Unicode cChar
, sal_Char cEditMask
)
198 if ( ImplIsPatternChar( cChar
, cEditMask
) )
200 if ( (cEditMask
== EDITMASK_UPPERALPHA
) ||
201 (cEditMask
== EDITMASK_UPPERALPHANUM
) ||
202 ( cEditMask
== EDITMASK_UPPERALLCHAR
) )
204 cChar
= ImplGetCharClass()->toUpper(OUString(cChar
), 0, 1,
205 Application::GetSettings().GetLanguageTag().getLocale())[0];
213 static bool ImplCommaPointCharEqual( sal_Unicode c1
, sal_Unicode c2
)
217 else if ( ((c1
== '.') || (c1
== ',')) &&
218 ((c2
== '.') || (c2
== ',')) )
224 static OUString
ImplPatternReformat( const OUString
& rStr
,
225 const OString
& rEditMask
,
226 const OUString
& rLiteralMask
,
227 sal_uInt16 nFormatFlags
)
229 if (rEditMask
.isEmpty())
232 OUStringBuffer aOutStr
= rLiteralMask
;
233 sal_Unicode cTempChar
;
235 sal_Unicode cLiteral
;
237 sal_Int32 nStrIndex
= 0;
241 while ( i
< rEditMask
.getLength() )
243 if ( nStrIndex
>= rStr
.getLength() )
246 cChar
= rStr
[nStrIndex
];
247 cLiteral
= rLiteralMask
[i
];
248 cMask
= rEditMask
[i
];
250 // current position is a literal
251 if ( cMask
== EDITMASK_LITERAL
)
253 // if it is a literal copy otherwise ignore because it might be the next valid
254 // character of the string
255 if ( ImplCommaPointCharEqual( cChar
, cLiteral
) )
259 // Otherwise we check if it is an invalid character. This is the case if it does not
260 // fit in the pattern of the next non-literal character.
262 while ( n
< rEditMask
.getLength() )
264 if ( rEditMask
[n
] != EDITMASK_LITERAL
)
266 if ( !ImplIsPatternChar( cChar
, rEditMask
[n
] ) )
277 // valid character at this position
278 cTempChar
= ImplPatternChar( cChar
, cMask
);
281 // use this character
282 aOutStr
[i
] = cTempChar
;
287 // copy if it is a literal character
288 if ( cLiteral
== cChar
)
292 // If the invalid character might be the next literal character then we jump
293 // ahead to it, otherwise we ignore it. Do only if empty literals are allowed.
294 if ( nFormatFlags
& PATTERN_FORMAT_EMPTYLITERALS
)
297 while ( n
< rEditMask
.getLength() )
299 if ( rEditMask
[n
] == EDITMASK_LITERAL
)
301 if ( ImplCommaPointCharEqual( cChar
, rLiteralMask
[n
] ) )
320 return aOutStr
.makeStringAndClear();
323 static void ImplPatternMaxPos( const OUString
& rStr
, const OString
& rEditMask
,
324 sal_uInt16 nFormatFlags
, bool bSameMask
,
325 sal_Int32 nCursorPos
, sal_Int32
& rPos
)
328 // last position must not be longer than the contained string
329 sal_Int32 nMaxPos
= rStr
.getLength();
331 // if non empty literals are allowed ignore blanks at the end as well
332 if ( bSameMask
&& !(nFormatFlags
& PATTERN_FORMAT_EMPTYLITERALS
) )
336 if ( (rEditMask
[nMaxPos
-1] != EDITMASK_LITERAL
) &&
337 (rStr
[nMaxPos
-1] != ' ') )
342 // if we are in front of a literal, continue search until first character after the literal
343 sal_Int32 nTempPos
= nMaxPos
;
344 while ( nTempPos
< rEditMask
.getLength() )
346 if ( rEditMask
[nTempPos
] != EDITMASK_LITERAL
)
355 if ( rPos
> nMaxPos
)
358 // character should not move left
359 if ( rPos
< nCursorPos
)
363 static void ImplPatternProcessStrictModify( Edit
* pEdit
,
364 const OString
& rEditMask
,
365 const OUString
& rLiteralMask
,
368 OUString aText
= pEdit
->GetText();
370 // remove leading blanks
371 if (bSameMask
&& !rEditMask
.isEmpty())
374 sal_Int32 nMaxLen
= aText
.getLength();
375 while ( i
< nMaxLen
)
377 if ( (rEditMask
[i
] != EDITMASK_LITERAL
) &&
383 // keep all literal characters
384 while ( i
&& (rEditMask
[i
] == EDITMASK_LITERAL
) )
386 aText
= aText
.copy( i
);
389 OUString aNewText
= ImplPatternReformat(aText
, rEditMask
, rLiteralMask
, 0);
390 if ( aNewText
!= aText
)
392 // adjust selection such that it remains at the end if it was there before
393 Selection aSel
= pEdit
->GetSelection();
394 sal_Int64 nMaxSel
= std::max( aSel
.Min(), aSel
.Max() );
395 if ( nMaxSel
>= aText
.getLength() )
397 sal_Int32 nMaxPos
= aNewText
.getLength();
398 ImplPatternMaxPos(aNewText
, rEditMask
, 0, bSameMask
, nMaxSel
, nMaxPos
);
399 if ( aSel
.Min() == aSel
.Max() )
401 aSel
.Min() = nMaxPos
;
402 aSel
.Max() = aSel
.Min();
404 else if ( aSel
.Min() > aSel
.Max() )
405 aSel
.Min() = nMaxPos
;
407 aSel
.Max() = nMaxPos
;
409 pEdit
->SetText( aNewText
, aSel
);
413 static sal_Int32
ImplPatternLeftPos(const OString
& rEditMask
, sal_Int32 nCursorPos
)
415 // search non-literal predecessor
416 sal_Int32 nNewPos
= nCursorPos
;
417 sal_Int32 nTempPos
= nNewPos
;
420 if ( rEditMask
[nTempPos
-1] != EDITMASK_LITERAL
)
422 nNewPos
= nTempPos
-1;
430 static sal_Int32
ImplPatternRightPos( const OUString
& rStr
, const OString
& rEditMask
,
431 sal_uInt16 nFormatFlags
, bool bSameMask
,
432 sal_Int32 nCursorPos
)
434 // search non-literal successor
435 sal_Int32 nNewPos
= nCursorPos
;
437 for(sal_Int32 nTempPos
= nNewPos
+1; nTempPos
< rEditMask
.getLength(); ++nTempPos
)
439 if ( rEditMask
[nTempPos
] != EDITMASK_LITERAL
)
445 ImplPatternMaxPos( rStr
, rEditMask
, nFormatFlags
, bSameMask
, nCursorPos
, nNewPos
);
449 static bool ImplPatternProcessKeyInput( Edit
* pEdit
, const KeyEvent
& rKEvt
,
450 const OString
& rEditMask
,
451 const OUString
& rLiteralMask
,
456 if ( rEditMask
.isEmpty() || !bStrictFormat
)
459 sal_uInt16 nFormatFlags
= 0;
460 Selection aOldSel
= pEdit
->GetSelection();
461 vcl::KeyCode aCode
= rKEvt
.GetKeyCode();
462 sal_Unicode cChar
= rKEvt
.GetCharCode();
463 sal_uInt16 nKeyCode
= aCode
.GetCode();
464 bool bShift
= aCode
.IsShift();
465 sal_Int32 nCursorPos
= static_cast<sal_Int32
>(aOldSel
.Max());
469 if ( nKeyCode
&& !aCode
.IsMod1() && !aCode
.IsMod2() )
471 if ( nKeyCode
== KEY_LEFT
)
473 Selection
aSel( ImplPatternLeftPos( rEditMask
, nCursorPos
) );
475 aSel
.Min() = aOldSel
.Min();
476 pEdit
->SetSelection( aSel
);
479 else if ( nKeyCode
== KEY_RIGHT
)
481 // Use the start of selection as minimum; even a small position is allowed in case that
482 // all was selected by the focus
483 Selection
aSel( aOldSel
);
485 nCursorPos
= aSel
.Min();
486 aSel
.Max() = ImplPatternRightPos( pEdit
->GetText(), rEditMask
, nFormatFlags
, bSameMask
, nCursorPos
);
488 aSel
.Min() = aOldSel
.Min();
490 aSel
.Min() = aSel
.Max();
491 pEdit
->SetSelection( aSel
);
494 else if ( nKeyCode
== KEY_HOME
)
496 // Home is the position of the first non-literal character
498 while ( (nNewPos
< rEditMask
.getLength()) &&
499 (rEditMask
[nNewPos
] == EDITMASK_LITERAL
) )
502 // Home should not move to the right
503 if ( nCursorPos
< nNewPos
)
504 nNewPos
= nCursorPos
;
505 Selection
aSel( nNewPos
);
507 aSel
.Min() = aOldSel
.Min();
508 pEdit
->SetSelection( aSel
);
511 else if ( nKeyCode
== KEY_END
)
513 // End is position of last non-literal character
514 nNewPos
= rEditMask
.getLength();
516 (rEditMask
[nNewPos
-1] == EDITMASK_LITERAL
) )
518 // Use the start of selection as minimum; even a small position is allowed in case that
519 // all was selected by the focus
520 Selection
aSel( aOldSel
);
522 nCursorPos
= static_cast<sal_Int32
>(aSel
.Min());
523 ImplPatternMaxPos( pEdit
->GetText(), rEditMask
, nFormatFlags
, bSameMask
, nCursorPos
, nNewPos
);
524 aSel
.Max() = nNewPos
;
526 aSel
.Min() = aOldSel
.Min();
528 aSel
.Min() = aSel
.Max();
529 pEdit
->SetSelection( aSel
);
532 else if ( (nKeyCode
== KEY_BACKSPACE
) || (nKeyCode
== KEY_DELETE
) )
534 OUString
aOldStr( pEdit
->GetText() );
535 OUStringBuffer
aStr( aOldStr
);
536 Selection aSel
= aOldSel
;
539 nNewPos
= static_cast<sal_Int32
>(aSel
.Min());
541 // if selection then delete it
545 aStr
.remove( static_cast<sal_Int32
>(aSel
.Min()), static_cast<sal_Int32
>(aSel
.Len()) );
548 OUString aRep
= rLiteralMask
.copy( static_cast<sal_Int32
>(aSel
.Min()), static_cast<sal_Int32
>(aSel
.Len()) );
549 aStr
.remove( aSel
.Min(), aRep
.getLength() );
550 aStr
.insert( aSel
.Min(), aRep
);
555 if ( nKeyCode
== KEY_BACKSPACE
)
558 nNewPos
= ImplPatternLeftPos( rEditMask
, nTempPos
);
561 nTempPos
= ImplPatternRightPos( aStr
.toString(), rEditMask
, nFormatFlags
, bSameMask
, nNewPos
);
563 if ( nNewPos
!= nTempPos
)
567 if ( rEditMask
[nNewPos
] != EDITMASK_LITERAL
)
568 aStr
.remove( nNewPos
, 1 );
572 aStr
[nNewPos
] = rLiteralMask
[nNewPos
];
577 if ( aOldStr
!= aStr
.toString() )
580 aStr
= ImplPatternReformat( aStr
.toString(), rEditMask
, rLiteralMask
, nFormatFlags
);
582 pEdit
->SetText( aStr
.toString(), Selection( nNewPos
) );
583 pEdit
->SetModifyFlag();
585 rbInKeyInput
= false;
588 pEdit
->SetSelection( Selection( nNewPos
) );
592 else if ( nKeyCode
== KEY_INSERT
)
594 // you can only set InsertMode for a PatternField if the
595 // mask is equal at all input positions
603 if ( rKEvt
.GetKeyCode().IsMod2() || (cChar
< 32) || (cChar
== 127) )
606 Selection aSel
= aOldSel
;
608 nNewPos
= aSel
.Min();
610 if ( nNewPos
< rEditMask
.getLength() )
612 sal_Unicode cPattChar
= ImplPatternChar( cChar
, rEditMask
[nNewPos
] );
617 // If no valid character, check if the user wanted to jump to next literal. We do this
618 // only if we're after a character, so that literals that were skipped automatically
619 // do not influence the position anymore.
621 (rEditMask
[nNewPos
-1] != EDITMASK_LITERAL
) &&
624 // search for next character not being a literal
626 while ( nTempPos
< rEditMask
.getLength() )
628 if ( rEditMask
[nTempPos
] == EDITMASK_LITERAL
)
630 // only valid if no literal present
631 if ( (rEditMask
[nTempPos
+1] != EDITMASK_LITERAL
) &&
632 ImplCommaPointCharEqual( cChar
, rLiteralMask
[nTempPos
] ) )
635 ImplPatternMaxPos( pEdit
->GetText(), rEditMask
, nFormatFlags
, bSameMask
, nNewPos
, nTempPos
);
636 if ( nTempPos
> nNewPos
)
638 pEdit
->SetSelection( Selection( nTempPos
) );
655 OUStringBuffer aStr
= pEdit
->GetText();
657 if ( bSameMask
&& pEdit
->IsInsertMode() )
659 // crop spaces and literals at the end until current position
660 sal_Int32 n
= aStr
.getLength();
661 while ( n
&& (n
> nNewPos
) )
663 if ( (aStr
[n
-1] != ' ') &&
664 ((n
> rEditMask
.getLength()) || (rEditMask
[n
-1] != EDITMASK_LITERAL
)) )
672 aStr
.remove( aSel
.Min(), aSel
.Len() );
674 if ( aStr
.getLength() < rEditMask
.getLength() )
676 // possibly extend string until cursor position
677 if ( aStr
.getLength() < nNewPos
)
678 aStr
.append( std::u16string_view(rLiteralMask
).substr(aStr
.getLength(), nNewPos
-aStr
.getLength()) );
679 if ( nNewPos
< aStr
.getLength() )
680 aStr
.insert( cChar
, nNewPos
);
681 else if ( nNewPos
< rEditMask
.getLength() )
683 aStr
= ImplPatternReformat( aStr
.toString(), rEditMask
, rLiteralMask
, nFormatFlags
);
693 OUString aRep
= rLiteralMask
.copy( aSel
.Min(), aSel
.Len() );
694 aStr
.remove( aSel
.Min(), aRep
.getLength() );
695 aStr
.insert( aSel
.Min(), aRep
);
698 if ( nNewPos
< aStr
.getLength() )
699 aStr
[nNewPos
] = cChar
;
700 else if ( nNewPos
< rEditMask
.getLength() )
707 Selection
aNewSel( ImplPatternRightPos( aStr
.toString(), rEditMask
, nFormatFlags
, bSameMask
, nNewPos
) );
708 pEdit
->SetText( aStr
.toString(), aNewSel
);
709 pEdit
->SetModifyFlag();
711 rbInKeyInput
= false;
718 void PatternFormatter::ImplSetMask(const OString
& rEditMask
, const OUString
& rLiteralMask
)
720 m_aEditMask
= rEditMask
;
721 maLiteralMask
= rLiteralMask
;
724 if ( m_aEditMask
.getLength() != maLiteralMask
.getLength() )
726 OUStringBuffer
aBuf(maLiteralMask
);
727 if (m_aEditMask
.getLength() < aBuf
.getLength())
728 aBuf
.remove(m_aEditMask
.getLength(), aBuf
.getLength() - m_aEditMask
.getLength());
730 comphelper::string::padToLength(aBuf
, m_aEditMask
.getLength(), ' ');
731 maLiteralMask
= aBuf
.makeStringAndClear();
734 // Strict mode allows only the input mode if only equal characters are allowed as mask and if
735 // only spaces are specified which are not allowed by the mask
738 while ( i
< rEditMask
.getLength() )
740 sal_Char cTemp
= rEditMask
[i
];
741 if ( cTemp
!= EDITMASK_LITERAL
)
743 if ( (cTemp
== EDITMASK_ALLCHAR
) ||
744 (cTemp
== EDITMASK_UPPERALLCHAR
) ||
745 (cTemp
== EDITMASK_NUMSPACE
) )
750 if ( i
< rLiteralMask
.getLength() )
752 if ( rLiteralMask
[i
] != ' ' )
770 PatternFormatter::PatternFormatter(Edit
* pEdit
)
771 : FormatterBase(pEdit
)
774 mbInPattKeyInput
= false;
777 PatternFormatter::~PatternFormatter()
781 void PatternFormatter::SetMask( const OString
& rEditMask
,
782 const OUString
& rLiteralMask
)
784 ImplSetMask( rEditMask
, rLiteralMask
);
788 void PatternFormatter::SetString( const OUString
& rStr
)
792 GetField()->SetText( rStr
);
793 MarkToBeReformatted( false );
797 OUString
PatternFormatter::GetString() const
802 return ImplPatternReformat( GetField()->GetText(), m_aEditMask
, maLiteralMask
, 0/*nFormatFlags*/ );
805 void PatternFormatter::Reformat()
809 ImplSetText( ImplPatternReformat( GetField()->GetText(), m_aEditMask
, maLiteralMask
, 0/*nFormatFlags*/ ) );
810 if ( !mbSameMask
&& IsStrictFormat() && !GetField()->IsReadOnly() )
811 GetField()->SetInsertMode( false );
815 PatternField::PatternField(vcl::Window
* pParent
, WinBits nWinStyle
)
816 : SpinField(pParent
, nWinStyle
)
817 , PatternFormatter(this)
822 void PatternField::dispose()
825 SpinField::dispose();
828 bool PatternField::PreNotify( NotifyEvent
& rNEvt
)
830 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
832 if ( ImplPatternProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
834 ImplIsSameMask(), ImplGetInPattKeyInput() ) )
838 return SpinField::PreNotify( rNEvt
);
841 bool PatternField::EventNotify( NotifyEvent
& rNEvt
)
843 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
844 MarkToBeReformatted( false );
845 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
847 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
851 return SpinField::EventNotify( rNEvt
);
854 void PatternField::Modify()
856 if ( !ImplGetInPattKeyInput() )
858 if ( IsStrictFormat() )
859 ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), ImplIsSameMask() );
861 MarkToBeReformatted( true );
867 PatternBox::PatternBox(vcl::Window
* pParent
, WinBits nWinStyle
)
868 : ComboBox( pParent
, nWinStyle
)
869 , PatternFormatter(this)
874 void PatternBox::dispose()
880 bool PatternBox::PreNotify( NotifyEvent
& rNEvt
)
882 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
884 if ( ImplPatternProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
886 ImplIsSameMask(), ImplGetInPattKeyInput() ) )
890 return ComboBox::PreNotify( rNEvt
);
893 bool PatternBox::EventNotify( NotifyEvent
& rNEvt
)
895 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
896 MarkToBeReformatted( false );
897 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
899 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
903 return ComboBox::EventNotify( rNEvt
);
906 void PatternBox::Modify()
908 if ( !ImplGetInPattKeyInput() )
910 if ( IsStrictFormat() )
911 ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), ImplIsSameMask() );
913 MarkToBeReformatted( true );
919 void PatternBox::ReformatAll()
922 SetUpdateMode( false );
923 const sal_Int32 nEntryCount
= GetEntryCount();
924 for ( sal_Int32 i
=0; i
< nEntryCount
; ++i
)
926 aStr
= ImplPatternReformat( GetEntry( i
), GetEditMask(), GetLiteralMask(), 0/*nFormatFlags*/ );
928 InsertEntry( aStr
, i
);
930 PatternFormatter::Reformat();
931 SetUpdateMode( true );
934 static ExtDateFieldFormat
ImplGetExtFormat( DateOrder eOld
)
938 case DateOrder::DMY
: return ExtDateFieldFormat::ShortDDMMYY
;
939 case DateOrder::MDY
: return ExtDateFieldFormat::ShortMMDDYY
;
940 default: return ExtDateFieldFormat::ShortYYMMDD
;
944 static sal_uInt16
ImplCutNumberFromString( OUString
& rStr
)
947 while (i1
!= rStr
.getLength() && !(rStr
[i1
] >= '0' && rStr
[i1
] <= '9')) {
951 while (i2
!= rStr
.getLength() && rStr
[i2
] >= '0' && rStr
[i2
] <= '9') {
954 sal_Int32 nValue
= rStr
.copy(i1
, i2
-i1
).toInt32();
955 rStr
= rStr
.copy(std::min(i2
+1, rStr
.getLength()));
959 static bool ImplCutMonthName( OUString
& rStr
, const OUString
& _rLookupMonthName
)
962 rStr
= rStr
.replaceFirst(_rLookupMonthName
, "", &index
);
966 static sal_uInt16
ImplCutMonthFromString( OUString
& rStr
, const CalendarWrapper
& rCalendarWrapper
)
968 // search for a month' name
969 for ( sal_uInt16 i
=1; i
<= 12; i
++ )
971 OUString aMonthName
= rCalendarWrapper
.getMonths()[i
-1].FullName
;
973 if ( ImplCutMonthName( rStr
, aMonthName
) )
977 OUString aAbbrevMonthName
= rCalendarWrapper
.getMonths()[i
-1].AbbrevName
;
978 if ( ImplCutMonthName( rStr
, aAbbrevMonthName
) )
982 return ImplCutNumberFromString( rStr
);
985 static OUString
ImplGetDateSep( const LocaleDataWrapper
& rLocaleDataWrapper
, ExtDateFieldFormat eFormat
)
987 if ( ( eFormat
== ExtDateFieldFormat::ShortYYMMDD_DIN5008
) || ( eFormat
== ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
) )
990 return rLocaleDataWrapper
.getDateSep();
993 static bool ImplDateProcessKeyInput( const KeyEvent
& rKEvt
, ExtDateFieldFormat eFormat
,
994 const LocaleDataWrapper
& rLocaleDataWrapper
)
996 sal_Unicode cChar
= rKEvt
.GetCharCode();
997 sal_uInt16 nGroup
= rKEvt
.GetKeyCode().GetGroup();
998 return !((nGroup
== KEYGROUP_FKEYS
) ||
999 (nGroup
== KEYGROUP_CURSOR
) ||
1000 (nGroup
== KEYGROUP_MISC
)||
1001 ((cChar
>= '0') && (cChar
<= '9')) ||
1002 (cChar
== ImplGetDateSep( rLocaleDataWrapper
, eFormat
)[0]));
1005 static bool ImplDateGetValue( const OUString
& rStr
, Date
& rDate
, ExtDateFieldFormat eDateOrder
,
1006 const LocaleDataWrapper
& rLocaleDataWrapper
, const CalendarWrapper
& rCalendarWrapper
)
1008 sal_uInt16 nDay
= 0;
1009 sal_uInt16 nMonth
= 0;
1010 sal_uInt16 nYear
= 0;
1011 bool bError
= false;
1012 OUString
aStr( rStr
);
1014 if ( eDateOrder
== ExtDateFieldFormat::SystemLong
)
1016 DateOrder eFormat
= rLocaleDataWrapper
.getLongDateOrder();
1019 case DateOrder::MDY
:
1020 nMonth
= ImplCutMonthFromString( aStr
, rCalendarWrapper
);
1021 nDay
= ImplCutNumberFromString( aStr
);
1022 nYear
= ImplCutNumberFromString( aStr
);
1024 case DateOrder::DMY
:
1025 nDay
= ImplCutNumberFromString( aStr
);
1026 nMonth
= ImplCutMonthFromString( aStr
, rCalendarWrapper
);
1027 nYear
= ImplCutNumberFromString( aStr
);
1029 case DateOrder::YMD
:
1031 nYear
= ImplCutNumberFromString( aStr
);
1032 nMonth
= ImplCutMonthFromString( aStr
, rCalendarWrapper
);
1033 nDay
= ImplCutNumberFromString( aStr
);
1041 // Check if year is present:
1042 OUString aDateSep
= ImplGetDateSep( rLocaleDataWrapper
, eDateOrder
);
1043 sal_Int32 nSepPos
= aStr
.indexOf( aDateSep
);
1046 nSepPos
= aStr
.indexOf( aDateSep
, nSepPos
+1 );
1047 if ( ( nSepPos
< 0 ) || ( nSepPos
== (aStr
.getLength()-1) ) )
1050 nYear
= Date( Date::SYSTEM
).GetYearUnsigned();
1053 const sal_Unicode
* pBuf
= aStr
.getStr();
1054 ImplSkipDelimiters( pBuf
);
1056 switch ( eDateOrder
)
1058 case ExtDateFieldFormat::ShortDDMMYY
:
1059 case ExtDateFieldFormat::ShortDDMMYYYY
:
1061 nDay
= ImplGetNum( pBuf
, bError
);
1062 ImplSkipDelimiters( pBuf
);
1063 nMonth
= ImplGetNum( pBuf
, bError
);
1064 ImplSkipDelimiters( pBuf
);
1066 nYear
= ImplGetNum( pBuf
, bError
);
1069 case ExtDateFieldFormat::ShortMMDDYY
:
1070 case ExtDateFieldFormat::ShortMMDDYYYY
:
1072 nMonth
= ImplGetNum( pBuf
, bError
);
1073 ImplSkipDelimiters( pBuf
);
1074 nDay
= ImplGetNum( pBuf
, bError
);
1075 ImplSkipDelimiters( pBuf
);
1077 nYear
= ImplGetNum( pBuf
, bError
);
1080 case ExtDateFieldFormat::ShortYYMMDD
:
1081 case ExtDateFieldFormat::ShortYYYYMMDD
:
1082 case ExtDateFieldFormat::ShortYYMMDD_DIN5008
:
1083 case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
:
1086 nYear
= ImplGetNum( pBuf
, bError
);
1087 ImplSkipDelimiters( pBuf
);
1088 nMonth
= ImplGetNum( pBuf
, bError
);
1089 ImplSkipDelimiters( pBuf
);
1090 nDay
= ImplGetNum( pBuf
, bError
);
1096 OSL_FAIL( "DateOrder???" );
1101 if ( bError
|| !nDay
|| !nMonth
)
1104 Date
aNewDate( nDay
, nMonth
, nYear
);
1105 DateFormatter::ExpandCentury( aNewDate
, utl::MiscCfg().GetYear2000() );
1106 if ( aNewDate
.IsValidDate() )
1114 void DateFormatter::ImplDateReformat( const OUString
& rStr
, OUString
& rOutStr
)
1116 Date
aDate( Date::EMPTY
);
1117 if ( !ImplDateGetValue( rStr
, aDate
, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper() ) )
1120 Date aTempDate
= aDate
;
1121 if ( aTempDate
> GetMax() )
1122 aTempDate
= GetMax();
1123 else if ( aTempDate
< GetMin() )
1124 aTempDate
= GetMin();
1126 rOutStr
= ImplGetDateAsText( aTempDate
);
1129 OUString
DateFormatter::ImplGetDateAsText( const Date
& rDate
) const
1131 bool bShowCentury
= false;
1132 switch ( GetExtDateFormat() )
1134 case ExtDateFieldFormat::SystemShortYYYY
:
1135 case ExtDateFieldFormat::SystemLong
:
1136 case ExtDateFieldFormat::ShortDDMMYYYY
:
1137 case ExtDateFieldFormat::ShortMMDDYYYY
:
1138 case ExtDateFieldFormat::ShortYYYYMMDD
:
1139 case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
:
1141 bShowCentury
= true;
1146 bShowCentury
= false;
1150 if ( !bShowCentury
)
1152 // Check if I have to use force showing the century
1153 sal_uInt16 nTwoDigitYearStart
= utl::MiscCfg().GetYear2000();
1154 sal_uInt16 nYear
= rDate
.GetYearUnsigned();
1156 // If year is not in double digit range
1157 if ( (nYear
< nTwoDigitYearStart
) || (nYear
>= nTwoDigitYearStart
+100) )
1158 bShowCentury
= true;
1161 sal_Unicode aBuf
[128];
1162 sal_Unicode
* pBuf
= aBuf
;
1164 OUString aDateSep
= ImplGetDateSep( ImplGetLocaleDataWrapper(), GetExtDateFormat( true ) );
1165 sal_uInt16 nDay
= rDate
.GetDay();
1166 sal_uInt16 nMonth
= rDate
.GetMonth();
1167 sal_Int16 nYear
= rDate
.GetYear();
1168 sal_uInt16 nYearLen
= bShowCentury
? 4 : 2;
1170 if ( !bShowCentury
)
1173 switch ( GetExtDateFormat( true ) )
1175 case ExtDateFieldFormat::SystemLong
:
1177 return ImplGetLocaleDataWrapper().getLongDate( rDate
, GetCalendarWrapper(), !bShowCentury
);
1179 case ExtDateFieldFormat::ShortDDMMYY
:
1180 case ExtDateFieldFormat::ShortDDMMYYYY
:
1182 pBuf
= ImplAddNum( pBuf
, nDay
, 2 );
1183 pBuf
= ImplAddString( pBuf
, aDateSep
);
1184 pBuf
= ImplAddNum( pBuf
, nMonth
, 2 );
1185 pBuf
= ImplAddString( pBuf
, aDateSep
);
1186 pBuf
= ImplAddSNum( pBuf
, nYear
, nYearLen
);
1189 case ExtDateFieldFormat::ShortMMDDYY
:
1190 case ExtDateFieldFormat::ShortMMDDYYYY
:
1192 pBuf
= ImplAddNum( pBuf
, nMonth
, 2 );
1193 pBuf
= ImplAddString( pBuf
, aDateSep
);
1194 pBuf
= ImplAddNum( pBuf
, nDay
, 2 );
1195 pBuf
= ImplAddString( pBuf
, aDateSep
);
1196 pBuf
= ImplAddSNum( pBuf
, nYear
, nYearLen
);
1199 case ExtDateFieldFormat::ShortYYMMDD
:
1200 case ExtDateFieldFormat::ShortYYYYMMDD
:
1201 case ExtDateFieldFormat::ShortYYMMDD_DIN5008
:
1202 case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
:
1204 pBuf
= ImplAddSNum( pBuf
, nYear
, nYearLen
);
1205 pBuf
= ImplAddString( pBuf
, aDateSep
);
1206 pBuf
= ImplAddNum( pBuf
, nMonth
, 2 );
1207 pBuf
= ImplAddString( pBuf
, aDateSep
);
1208 pBuf
= ImplAddNum( pBuf
, nDay
, 2 );
1213 OSL_FAIL( "DateOrder???" );
1217 return OUString(aBuf
, pBuf
-aBuf
);
1220 static void ImplDateIncrementDay( Date
& rDate
, bool bUp
)
1222 DateFormatter::ExpandCentury( rDate
);
1226 if ( (rDate
.GetDay() != 31) || (rDate
.GetMonth() != 12) || (rDate
.GetYear() != SAL_MAX_INT16
) )
1231 if ( (rDate
.GetDay() != 1 ) || (rDate
.GetMonth() != 1) || (rDate
.GetYear() != SAL_MIN_INT16
) )
1236 static void ImplDateIncrementMonth( Date
& rDate
, bool bUp
)
1238 DateFormatter::ExpandCentury( rDate
);
1240 sal_uInt16 nMonth
= rDate
.GetMonth();
1241 sal_Int16 nYear
= rDate
.GetYear();
1244 if ( (nMonth
== 12) && (nYear
< SAL_MAX_INT16
) )
1246 rDate
.SetMonth( 1 );
1247 rDate
.SetYear( rDate
.GetNextYear() );
1252 rDate
.SetMonth( nMonth
+ 1 );
1257 if ( (nMonth
== 1) && (nYear
> SAL_MIN_INT16
) )
1259 rDate
.SetMonth( 12 );
1260 rDate
.SetYear( rDate
.GetPrevYear() );
1265 rDate
.SetMonth( nMonth
- 1 );
1269 sal_uInt16 nDaysInMonth
= Date::GetDaysInMonth( rDate
.GetMonth(), rDate
.GetYear());
1270 if ( rDate
.GetDay() > nDaysInMonth
)
1271 rDate
.SetDay( nDaysInMonth
);
1274 static void ImplDateIncrementYear( Date
& rDate
, bool bUp
)
1276 DateFormatter::ExpandCentury( rDate
);
1278 sal_Int16 nYear
= rDate
.GetYear();
1279 sal_uInt16 nMonth
= rDate
.GetMonth();
1282 if ( nYear
< SAL_MAX_INT16
)
1283 rDate
.SetYear( rDate
.GetNextYear() );
1287 if ( nYear
> SAL_MIN_INT16
)
1288 rDate
.SetYear( rDate
.GetPrevYear() );
1292 // Handle February 29 from leap year to non-leap year.
1293 sal_uInt16 nDay
= rDate
.GetDay();
1296 // The check would not be necessary if it was guaranteed that the
1297 // date was valid before and actually was a leap year,
1298 // de-/incrementing a leap year with 29 always results in 28.
1299 sal_uInt16 nDaysInMonth
= Date::GetDaysInMonth( nMonth
, rDate
.GetYear());
1300 if (nDay
> nDaysInMonth
)
1301 rDate
.SetDay( nDaysInMonth
);
1306 bool DateFormatter::ImplAllowMalformedInput() const
1308 return !IsEnforceValidValue();
1311 void DateField::ImplDateSpinArea( bool bUp
)
1313 // increment days if all is selected
1316 Date
aDate( GetDate() );
1317 Selection aSelection
= GetField()->GetSelection();
1318 aSelection
.Justify();
1319 OUString
aText( GetText() );
1320 if ( static_cast<sal_Int32
>(aSelection
.Len()) == aText
.getLength() )
1321 ImplDateIncrementDay( aDate
, bUp
);
1324 sal_Int8 nDateArea
= 0;
1326 ExtDateFieldFormat eFormat
= GetExtDateFormat( true );
1327 if ( eFormat
== ExtDateFieldFormat::SystemLong
)
1329 eFormat
= ImplGetExtFormat( ImplGetLocaleDataWrapper().getLongDateOrder() );
1336 OUString aDateSep
= ImplGetDateSep( ImplGetLocaleDataWrapper(), eFormat
);
1337 for ( sal_Int8 i
= 1; i
<= 3; i
++ )
1339 nPos
= aText
.indexOf( aDateSep
, nPos
);
1340 if (nPos
< 0 || nPos
>= static_cast<sal_Int32
>(aSelection
.Max()))
1352 case ExtDateFieldFormat::ShortMMDDYY
:
1353 case ExtDateFieldFormat::ShortMMDDYYYY
:
1356 case 1: ImplDateIncrementMonth( aDate
, bUp
);
1358 case 2: ImplDateIncrementDay( aDate
, bUp
);
1360 case 3: ImplDateIncrementYear( aDate
, bUp
);
1364 case ExtDateFieldFormat::ShortDDMMYY
:
1365 case ExtDateFieldFormat::ShortDDMMYYYY
:
1368 case 1: ImplDateIncrementDay( aDate
, bUp
);
1370 case 2: ImplDateIncrementMonth( aDate
, bUp
);
1372 case 3: ImplDateIncrementYear( aDate
, bUp
);
1376 case ExtDateFieldFormat::ShortYYMMDD
:
1377 case ExtDateFieldFormat::ShortYYYYMMDD
:
1378 case ExtDateFieldFormat::ShortYYMMDD_DIN5008
:
1379 case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
:
1382 case 1: ImplDateIncrementYear( aDate
, bUp
);
1384 case 2: ImplDateIncrementMonth( aDate
, bUp
);
1386 case 3: ImplDateIncrementDay( aDate
, bUp
);
1391 OSL_FAIL( "invalid conversion" );
1396 ImplNewFieldValue( aDate
);
1400 void DateFormatter::ImplInit()
1402 mbLongFormat
= false;
1403 mbShowDateCentury
= true;
1404 mpCalendarWrapper
= nullptr;
1405 mnExtDateFormat
= ExtDateFieldFormat::SystemShort
;
1408 DateFormatter::DateFormatter(Edit
* pEdit
) :
1409 FormatterBase(pEdit
),
1412 maMin( 1, 1, 1900 ),
1413 maMax( 31, 12, 2200 ),
1414 mbEnforceValidValue( true )
1419 DateFormatter::~DateFormatter()
1423 CalendarWrapper
& DateFormatter::GetCalendarWrapper() const
1425 if ( !mpCalendarWrapper
)
1427 const_cast<DateFormatter
*>(this)->mpCalendarWrapper
.reset( new CalendarWrapper( comphelper::getProcessComponentContext() ) );
1428 mpCalendarWrapper
->loadDefaultCalendar( GetLocale() );
1431 return *mpCalendarWrapper
;
1434 void DateFormatter::SetExtDateFormat( ExtDateFieldFormat eFormat
)
1436 mnExtDateFormat
= eFormat
;
1440 ExtDateFieldFormat
DateFormatter::GetExtDateFormat( bool bResolveSystemFormat
) const
1442 ExtDateFieldFormat eDateFormat
= mnExtDateFormat
;
1444 if ( bResolveSystemFormat
&& ( eDateFormat
<= ExtDateFieldFormat::SystemShortYYYY
) )
1446 bool bShowCentury
= (eDateFormat
== ExtDateFieldFormat::SystemShortYYYY
);
1447 switch ( ImplGetLocaleDataWrapper().getDateOrder() )
1449 case DateOrder::DMY
:
1450 eDateFormat
= bShowCentury
? ExtDateFieldFormat::ShortDDMMYYYY
: ExtDateFieldFormat::ShortDDMMYY
;
1452 case DateOrder::MDY
:
1453 eDateFormat
= bShowCentury
? ExtDateFieldFormat::ShortMMDDYYYY
: ExtDateFieldFormat::ShortMMDDYY
;
1456 eDateFormat
= bShowCentury
? ExtDateFieldFormat::ShortYYYYMMDD
: ExtDateFieldFormat::ShortYYMMDD
;
1463 void DateFormatter::ReformatAll()
1468 void DateFormatter::SetMin( const Date
& rNewMin
)
1471 if ( !IsEmptyFieldValue() )
1475 void DateFormatter::SetMax( const Date
& rNewMax
)
1478 if ( !IsEmptyFieldValue() )
1482 void DateFormatter::SetLongFormat( bool bLong
)
1484 mbLongFormat
= bLong
;
1486 // #91913# Remove LongFormat and DateShowCentury - redundant
1489 SetExtDateFormat( ExtDateFieldFormat::SystemLong
);
1493 if( mnExtDateFormat
== ExtDateFieldFormat::SystemLong
)
1494 SetExtDateFormat( ExtDateFieldFormat::SystemShort
);
1500 void DateFormatter::SetShowDateCentury( bool bShowDateCentury
)
1502 mbShowDateCentury
= bShowDateCentury
;
1504 // #91913# Remove LongFormat and DateShowCentury - redundant
1505 if ( bShowDateCentury
)
1507 switch ( GetExtDateFormat() )
1509 case ExtDateFieldFormat::SystemShort
:
1510 case ExtDateFieldFormat::SystemShortYY
:
1511 SetExtDateFormat( ExtDateFieldFormat::SystemShortYYYY
); break;
1512 case ExtDateFieldFormat::ShortDDMMYY
:
1513 SetExtDateFormat( ExtDateFieldFormat::ShortDDMMYYYY
); break;
1514 case ExtDateFieldFormat::ShortMMDDYY
:
1515 SetExtDateFormat( ExtDateFieldFormat::ShortMMDDYYYY
); break;
1516 case ExtDateFieldFormat::ShortYYMMDD
:
1517 SetExtDateFormat( ExtDateFieldFormat::ShortYYYYMMDD
); break;
1518 case ExtDateFieldFormat::ShortYYMMDD_DIN5008
:
1519 SetExtDateFormat( ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
); break;
1526 switch ( GetExtDateFormat() )
1528 case ExtDateFieldFormat::SystemShort
:
1529 case ExtDateFieldFormat::SystemShortYYYY
:
1530 SetExtDateFormat( ExtDateFieldFormat::SystemShortYY
); break;
1531 case ExtDateFieldFormat::ShortDDMMYYYY
:
1532 SetExtDateFormat( ExtDateFieldFormat::ShortDDMMYY
); break;
1533 case ExtDateFieldFormat::ShortMMDDYYYY
:
1534 SetExtDateFormat( ExtDateFieldFormat::ShortMMDDYY
); break;
1535 case ExtDateFieldFormat::ShortYYYYMMDD
:
1536 SetExtDateFormat( ExtDateFieldFormat::ShortYYMMDD
); break;
1537 case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
:
1538 SetExtDateFormat( ExtDateFieldFormat::ShortYYMMDD_DIN5008
); break;
1547 void DateFormatter::SetDate( const Date
& rNewDate
)
1549 ImplSetUserDate( rNewDate
);
1550 maFieldDate
= maLastDate
;
1551 maLastDate
= GetDate();
1554 void DateFormatter::ImplSetUserDate( const Date
& rNewDate
, Selection
const * pNewSelection
)
1556 Date aNewDate
= rNewDate
;
1557 if ( aNewDate
> maMax
)
1559 else if ( aNewDate
< maMin
)
1561 maLastDate
= aNewDate
;
1564 ImplSetText( ImplGetDateAsText( aNewDate
), pNewSelection
);
1567 void DateFormatter::ImplNewFieldValue( const Date
& rDate
)
1571 Selection aSelection
= GetField()->GetSelection();
1572 aSelection
.Justify();
1573 OUString aText
= GetField()->GetText();
1575 // If selected until the end then keep it that way
1576 if ( static_cast<sal_Int32
>(aSelection
.Max()) == aText
.getLength() )
1578 if ( !aSelection
.Len() )
1579 aSelection
.Min() = SELECTION_MAX
;
1580 aSelection
.Max() = SELECTION_MAX
;
1583 Date aOldLastDate
= maLastDate
;
1584 ImplSetUserDate( rDate
, &aSelection
);
1585 maLastDate
= aOldLastDate
;
1587 // Modify at Edit is only set at KeyInput
1588 if ( GetField()->GetText() != aText
)
1590 GetField()->SetModifyFlag();
1591 GetField()->Modify();
1596 Date
DateFormatter::GetDate() const
1598 Date
aDate( Date::EMPTY
);
1602 if ( ImplDateGetValue( GetField()->GetText(), aDate
, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper() ) )
1604 if ( aDate
> maMax
)
1606 else if ( aDate
< maMin
)
1611 // !!! We should find out why dates are treated differently than other fields (see
1614 if ( !ImplAllowMalformedInput() )
1616 if ( maLastDate
.GetDate() )
1618 else if ( !IsEmptyFieldValueEnabled() )
1619 aDate
= Date( Date::SYSTEM
);
1622 aDate
= Date( Date::EMPTY
); // set invalid date
1629 void DateFormatter::SetEmptyDate()
1631 FormatterBase::SetEmptyFieldValue();
1634 bool DateFormatter::IsEmptyDate() const
1636 bool bEmpty
= FormatterBase::IsEmptyFieldValue();
1638 if ( GetField() && MustBeReformatted() && IsEmptyFieldValueEnabled() )
1640 if ( GetField()->GetText().isEmpty() )
1644 else if ( !maLastDate
.GetDate() )
1646 Date
aDate( Date::EMPTY
);
1647 bEmpty
= !ImplDateGetValue( GetField()->GetText(), aDate
, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper() );
1653 void DateFormatter::Reformat()
1658 if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
1662 ImplDateReformat( GetField()->GetText(), aStr
);
1664 if ( !aStr
.isEmpty() )
1666 ImplSetText( aStr
);
1667 (void)ImplDateGetValue(aStr
, maLastDate
, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper());
1671 if ( maLastDate
.GetDate() )
1672 SetDate( maLastDate
);
1673 else if ( !IsEmptyFieldValueEnabled() )
1674 SetDate( Date( Date::SYSTEM
) );
1677 ImplSetText( OUString() );
1678 SetEmptyFieldValueData( true );
1683 void DateFormatter::ExpandCentury( Date
& rDate
)
1685 ExpandCentury( rDate
, utl::MiscCfg().GetYear2000() );
1688 void DateFormatter::ExpandCentury( Date
& rDate
, sal_uInt16 nTwoDigitYearStart
)
1690 sal_Int16 nDateYear
= rDate
.GetYear();
1691 if ( 0 <= nDateYear
&& nDateYear
< 100 )
1693 sal_uInt16 nCentury
= nTwoDigitYearStart
/ 100;
1694 if ( nDateYear
< (nTwoDigitYearStart
% 100) )
1696 rDate
.SetYear( nDateYear
+ (nCentury
*100) );
1700 DateField::DateField( vcl::Window
* pParent
, WinBits nWinStyle
) :
1701 SpinField( pParent
, nWinStyle
),
1702 DateFormatter(this),
1703 maFirst( GetMin() ),
1706 SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
1711 void DateField::dispose()
1714 SpinField::dispose();
1717 bool DateField::PreNotify( NotifyEvent
& rNEvt
)
1719 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && IsStrictFormat() &&
1720 ( GetExtDateFormat() != ExtDateFieldFormat::SystemLong
) &&
1721 !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
1723 if ( ImplDateProcessKeyInput( *rNEvt
.GetKeyEvent(), GetExtDateFormat( true ), ImplGetLocaleDataWrapper() ) )
1727 return SpinField::PreNotify( rNEvt
);
1730 bool DateField::EventNotify( NotifyEvent
& rNEvt
)
1732 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
1733 MarkToBeReformatted( false );
1734 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
1736 if ( MustBeReformatted() )
1738 // !!! We should find out why dates are treated differently than other fields (see
1741 bool bTextLen
= !GetText().isEmpty();
1742 if ( bTextLen
|| !IsEmptyFieldValueEnabled() )
1744 if ( !ImplAllowMalformedInput() )
1748 Date
aDate( 0, 0, 0 );
1749 if ( ImplDateGetValue( GetText(), aDate
, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper() ) )
1750 // even with strict text analysis, our text is a valid date -> do a complete
1758 SetEmptyFieldValueData( true );
1763 return SpinField::EventNotify( rNEvt
);
1766 void DateField::DataChanged( const DataChangedEvent
& rDCEvt
)
1768 SpinField::DataChanged( rDCEvt
);
1770 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & (AllSettingsFlags::LOCALE
|AllSettingsFlags::MISC
)) )
1772 if (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
)
1773 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
1778 void DateField::Modify()
1780 MarkToBeReformatted( true );
1781 SpinField::Modify();
1784 void DateField::Up()
1786 ImplDateSpinArea( true );
1790 void DateField::Down()
1792 ImplDateSpinArea( false );
1796 void DateField::First()
1798 ImplNewFieldValue( maFirst
);
1802 void DateField::Last()
1804 ImplNewFieldValue( maLast
);
1808 DateBox::DateBox(vcl::Window
* pParent
, WinBits nWinStyle
)
1809 : ComboBox( pParent
, nWinStyle
)
1810 , DateFormatter(this)
1812 SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
1816 void DateBox::dispose()
1819 ComboBox::dispose();
1822 bool DateBox::PreNotify( NotifyEvent
& rNEvt
)
1824 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && IsStrictFormat() &&
1825 ( GetExtDateFormat() != ExtDateFieldFormat::SystemLong
) &&
1826 !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
1828 if ( ImplDateProcessKeyInput( *rNEvt
.GetKeyEvent(), GetExtDateFormat( true ), ImplGetLocaleDataWrapper() ) )
1832 return ComboBox::PreNotify( rNEvt
);
1835 void DateBox::DataChanged( const DataChangedEvent
& rDCEvt
)
1837 ComboBox::DataChanged( rDCEvt
);
1839 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
1841 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
1846 bool DateBox::EventNotify( NotifyEvent
& rNEvt
)
1848 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
1849 MarkToBeReformatted( false );
1850 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
1852 if ( MustBeReformatted() )
1854 bool bTextLen
= !GetText().isEmpty();
1855 if ( bTextLen
|| !IsEmptyFieldValueEnabled() )
1860 SetEmptyFieldValueData( true );
1865 return ComboBox::EventNotify( rNEvt
);
1868 void DateBox::Modify()
1870 MarkToBeReformatted( true );
1874 void DateBox::ReformatAll()
1877 SetUpdateMode( false );
1878 const sal_Int32 nEntryCount
= GetEntryCount();
1879 for ( sal_Int32 i
=0; i
< nEntryCount
; ++i
)
1881 ImplDateReformat( GetEntry( i
), aStr
);
1883 InsertEntry( aStr
, i
);
1885 DateFormatter::Reformat();
1886 SetUpdateMode( true );
1889 static bool ImplTimeProcessKeyInput( const KeyEvent
& rKEvt
,
1890 bool bStrictFormat
, bool bDuration
,
1891 TimeFieldFormat eFormat
,
1892 const LocaleDataWrapper
& rLocaleDataWrapper
)
1894 sal_Unicode cChar
= rKEvt
.GetCharCode();
1896 if ( !bStrictFormat
)
1900 sal_uInt16 nGroup
= rKEvt
.GetKeyCode().GetGroup();
1901 if ( (nGroup
== KEYGROUP_FKEYS
) || (nGroup
== KEYGROUP_CURSOR
) ||
1902 (nGroup
== KEYGROUP_MISC
) ||
1903 ((cChar
>= '0') && (cChar
<= '9')) ||
1904 string::equals(rLocaleDataWrapper
.getTimeSep(), cChar
) ||
1905 (rLocaleDataWrapper
.getTimeAM().indexOf(cChar
) != -1) ||
1906 (rLocaleDataWrapper
.getTimePM().indexOf(cChar
) != -1) ||
1908 (cChar
== 'a') || (cChar
== 'A') || (cChar
== 'm') || (cChar
== 'M') || (cChar
== 'p') || (cChar
== 'P') ||
1909 ((eFormat
== TimeFieldFormat::F_SEC_CS
) && string::equals(rLocaleDataWrapper
.getTime100SecSep(), cChar
)) ||
1910 (bDuration
&& (cChar
== '-')) )
1917 static bool ImplIsOnlyDigits( const OUStringBuffer
& _rStr
)
1919 const sal_Unicode
* _pChr
= _rStr
.getStr();
1920 for ( sal_Int32 i
= 0; i
< _rStr
.getLength(); ++i
, ++_pChr
)
1922 if ( *_pChr
< '0' || *_pChr
> '9' )
1928 static bool ImplIsValidTimePortion( bool _bSkipInvalidCharacters
, const OUStringBuffer
& _rStr
)
1930 if ( !_bSkipInvalidCharacters
)
1932 if ( ( _rStr
.getLength() > 2 ) || _rStr
.isEmpty() || !ImplIsOnlyDigits( _rStr
) )
1938 static bool ImplCutTimePortion( OUStringBuffer
& _rStr
, sal_Int32 _nSepPos
, bool _bSkipInvalidCharacters
, short* _pPortion
)
1940 OUString
sPortion(_rStr
.getStr(), _nSepPos
);
1942 if (_nSepPos
< _rStr
.getLength())
1943 _rStr
.remove(0, _nSepPos
+ 1);
1947 if ( !ImplIsValidTimePortion( _bSkipInvalidCharacters
, sPortion
) )
1949 *_pPortion
= static_cast<short>(sPortion
.toInt32());
1953 bool TimeFormatter::TextToTime(const OUString
& rStr
, tools::Time
& rTime
, TimeFieldFormat eFormat
,
1954 bool bDuration
, const LocaleDataWrapper
& rLocaleDataWrapper
, bool _bSkipInvalidCharacters
)
1956 OUStringBuffer aStr
= rStr
;
1960 sal_Int64 nNanoSec
= 0;
1961 tools::Time
aTime( 0, 0, 0 );
1963 if ( rStr
.isEmpty() )
1966 // Search for separators
1967 if (!rLocaleDataWrapper
.getTimeSep().isEmpty())
1969 OUStringBuffer
aSepStr(",.;:/");
1971 aSepStr
.append('-');
1973 // Replace characters above by the separator character
1974 for (sal_Int32 i
= 0; i
< aSepStr
.getLength(); ++i
)
1976 if (string::equals(rLocaleDataWrapper
.getTimeSep(), aSepStr
[i
]))
1978 for ( sal_Int32 j
= 0; j
< aStr
.getLength(); j
++ )
1980 if (aStr
[j
] == aSepStr
[i
])
1981 aStr
[j
] = rLocaleDataWrapper
.getTimeSep()[0];
1986 bool bNegative
= false;
1987 sal_Int32 nSepPos
= aStr
.indexOf( rLocaleDataWrapper
.getTimeSep() );
1988 if ( aStr
[0] == '-' )
1990 if ( eFormat
!= TimeFieldFormat::F_SEC_CS
)
1993 nSepPos
= aStr
.getLength();
1994 if ( !ImplCutTimePortion( aStr
, nSepPos
, _bSkipInvalidCharacters
, &nHour
) )
1997 nSepPos
= aStr
.indexOf( rLocaleDataWrapper
.getTimeSep() );
1998 if ( !aStr
.isEmpty() && aStr
[0] == '-' )
2002 if ( !ImplCutTimePortion( aStr
, nSepPos
, _bSkipInvalidCharacters
, &nMinute
) )
2005 nSepPos
= aStr
.indexOf( rLocaleDataWrapper
.getTimeSep() );
2006 if ( !aStr
.isEmpty() && aStr
[0] == '-' )
2010 if ( !ImplCutTimePortion( aStr
, nSepPos
, _bSkipInvalidCharacters
, &nSecond
) )
2012 if ( !aStr
.isEmpty() && aStr
[0] == '-' )
2014 nNanoSec
= aStr
.toString().toInt64();
2017 nSecond
= static_cast<short>(aStr
.toString().toInt32());
2020 nMinute
= static_cast<short>(aStr
.toString().toInt32());
2022 else if ( nSepPos
< 0 )
2024 nSecond
= static_cast<short>(aStr
.toString().toInt32());
2025 nMinute
+= nSecond
/ 60;
2027 nHour
+= nMinute
/ 60;
2032 nSecond
= static_cast<short>(aStr
.copy( 0, nSepPos
).makeStringAndClear().toInt32());
2033 aStr
.remove( 0, nSepPos
+1 );
2035 nSepPos
= aStr
.indexOf( rLocaleDataWrapper
.getTimeSep() );
2036 if ( !aStr
.isEmpty() && aStr
[0] == '-' )
2041 nSecond
= static_cast<short>(aStr
.copy( 0, nSepPos
).makeStringAndClear().toInt32());
2042 aStr
.remove( 0, nSepPos
+1 );
2044 nSepPos
= aStr
.indexOf( rLocaleDataWrapper
.getTimeSep() );
2045 if ( !aStr
.isEmpty() && aStr
[0] == '-' )
2051 nSecond
= static_cast<short>(aStr
.copy( 0, nSepPos
).makeStringAndClear().toInt32());
2052 aStr
.remove( 0, nSepPos
+1 );
2056 nHour
+= nMinute
/ 60;
2062 nMinute
+= nSecond
/ 60;
2064 nHour
+= nMinute
/ 60;
2067 nNanoSec
= aStr
.toString().toInt64();
2072 assert(aStr
.getLength() >= 1);
2074 sal_Int32 nLen
= 1; // at least one digit, otherwise nNanoSec==0
2076 while ( aStr
.getLength() > nLen
&& aStr
[nLen
] >= '0' && aStr
[nLen
] <= '9' )
2086 // round if negative?
2087 nNanoSec
= (nNanoSec
+ 5) / 10;
2092 assert(nNanoSec
> -1000000000 && nNanoSec
< 1000000000);
2093 if ( (nMinute
> 59) || (nSecond
> 59) || (nNanoSec
> 1000000000) )
2096 if ( eFormat
== TimeFieldFormat::F_NONE
)
2097 nSecond
= nNanoSec
= 0;
2098 else if ( eFormat
== TimeFieldFormat::F_SEC
)
2103 if ( bNegative
|| (nHour
< 0) || (nMinute
< 0) ||
2104 (nSecond
< 0) || (nNanoSec
< 0) )
2107 OUString aUpperCaseStr
= aStr
.toString().toAsciiUpperCase();
2108 OUString
aAMlocalised(rLocaleDataWrapper
.getTimeAM().toAsciiUpperCase());
2109 OUString
aPMlocalised(rLocaleDataWrapper
.getTimePM().toAsciiUpperCase());
2111 if ( (nHour
< 12) && ( ( aUpperCaseStr
.indexOf( "PM" ) >= 0 ) || ( aUpperCaseStr
.indexOf( aPMlocalised
) >= 0 ) ) )
2114 if ( (nHour
== 12) && ( ( aUpperCaseStr
.indexOf( "AM" ) >= 0 ) || ( aUpperCaseStr
.indexOf( aAMlocalised
) >= 0 ) ) )
2117 aTime
= tools::Time( static_cast<sal_uInt16
>(nHour
), static_cast<sal_uInt16
>(nMinute
), static_cast<sal_uInt16
>(nSecond
),
2118 static_cast<sal_uInt32
>(nNanoSec
) );
2122 assert( !bNegative
|| (nHour
< 0) || (nMinute
< 0) ||
2123 (nSecond
< 0) || (nNanoSec
< 0) );
2124 if ( bNegative
|| (nHour
< 0) || (nMinute
< 0) ||
2125 (nSecond
< 0) || (nNanoSec
< 0) )
2127 // LEM TODO: this looks weird... I think buggy when parsing "05:-02:18"
2129 nHour
= nHour
< 0 ? -nHour
: nHour
;
2130 nMinute
= nMinute
< 0 ? -nMinute
: nMinute
;
2131 nSecond
= nSecond
< 0 ? -nSecond
: nSecond
;
2132 nNanoSec
= nNanoSec
< 0 ? -nNanoSec
: nNanoSec
;
2135 aTime
= tools::Time( static_cast<sal_uInt16
>(nHour
), static_cast<sal_uInt16
>(nMinute
), static_cast<sal_uInt16
>(nSecond
),
2136 static_cast<sal_uInt32
>(nNanoSec
) );
2146 void TimeFormatter::ImplTimeReformat( const OUString
& rStr
, OUString
& rOutStr
)
2148 tools::Time
aTime( 0, 0, 0 );
2149 if ( !TextToTime( rStr
, aTime
, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() ) )
2152 tools::Time aTempTime
= aTime
;
2153 if ( aTempTime
> GetMax() )
2154 aTempTime
= GetMax() ;
2155 else if ( aTempTime
< GetMin() )
2156 aTempTime
= GetMin();
2158 bool bSecond
= false;
2159 bool b100Sec
= false;
2160 if ( meFormat
!= TimeFieldFormat::F_NONE
)
2163 if ( meFormat
== TimeFieldFormat::F_SEC_CS
)
2165 sal_uLong n
= aTempTime
.GetHour() * 3600L;
2166 n
+= aTempTime
.GetMin() * 60L;
2167 n
+= aTempTime
.GetSec();
2168 rOutStr
= OUString::number( n
);
2169 rOutStr
+= ImplGetLocaleDataWrapper().getTime100SecSep();
2170 std::ostringstream ostr
;
2173 ostr
<< aTempTime
.GetNanoSec();
2174 rOutStr
+= OUString::createFromAscii(ostr
.str().c_str());
2176 else if ( mbDuration
)
2177 rOutStr
= ImplGetLocaleDataWrapper().getDuration( aTempTime
, bSecond
, b100Sec
);
2180 rOutStr
= ImplGetLocaleDataWrapper().getTime( aTempTime
, bSecond
, b100Sec
);
2181 if ( GetTimeFormat() == TimeFormat::Hour12
)
2183 if ( aTempTime
.GetHour() > 12 )
2185 tools::Time
aT( aTempTime
);
2186 aT
.SetHour( aT
.GetHour() % 12 );
2187 rOutStr
= ImplGetLocaleDataWrapper().getTime( aT
, bSecond
, b100Sec
);
2189 // Don't use LocaleDataWrapper, we want AM/PM
2190 if ( aTempTime
.GetHour() < 12 )
2191 rOutStr
+= "AM"; // ImplGetLocaleDataWrapper().getTimeAM();
2193 rOutStr
+= "PM"; // ImplGetLocaleDataWrapper().getTimePM();
2198 bool TimeFormatter::ImplAllowMalformedInput() const
2200 return !IsEnforceValidValue();
2203 int TimeFormatter::GetTimeArea(TimeFieldFormat eFormat
, const OUString
& rText
, int nCursor
,
2204 const LocaleDataWrapper
& rLocaleDataWrapper
)
2209 if (eFormat
!= TimeFieldFormat::F_SEC_CS
)
2211 //Which area is the cursor in of HH:MM:SS.TT
2212 for ( sal_Int32 i
= 1, nPos
= 0; i
<= 4; i
++ )
2214 sal_Int32 nPos1
= rText
.indexOf(rLocaleDataWrapper
.getTimeSep(), nPos
);
2215 sal_Int32 nPos2
= rText
.indexOf(rLocaleDataWrapper
.getTime100SecSep(), nPos
);
2216 //which ever comes first, bearing in mind that one might not be there
2217 if (nPos1
>= 0 && nPos2
>= 0)
2218 nPos
= std::min(nPos1
, nPos2
);
2219 else if (nPos1
>= 0)
2223 if (nPos
< 0 || nPos
>= nCursor
)
2234 sal_Int32 nPos
= rText
.indexOf(rLocaleDataWrapper
.getTime100SecSep());
2235 if (nPos
< 0 || nPos
>= nCursor
)
2244 tools::Time
TimeFormatter::SpinTime(bool bUp
, const tools::Time
& rTime
, TimeFieldFormat eFormat
,
2245 bool bDuration
, const OUString
& rText
, int nCursor
,
2246 const LocaleDataWrapper
& rLocaleDataWrapper
)
2248 tools::Time
aTime(rTime
);
2250 int nTimeArea
= GetTimeArea(eFormat
, rText
, nCursor
, rLocaleDataWrapper
);
2254 tools::Time
aAddTime( 0, 0, 0 );
2255 if ( nTimeArea
== 1 )
2256 aAddTime
= tools::Time( 1, 0 );
2257 else if ( nTimeArea
== 2 )
2258 aAddTime
= tools::Time( 0, 1 );
2259 else if ( nTimeArea
== 3 )
2260 aAddTime
= tools::Time( 0, 0, 1 );
2261 else if ( nTimeArea
== 4 )
2262 aAddTime
= tools::Time( 0, 0, 0, 1 );
2265 aAddTime
= -aAddTime
;
2270 tools::Time
aAbsMaxTime( 23, 59, 59, 999999999 );
2271 if ( aTime
> aAbsMaxTime
)
2272 aTime
= aAbsMaxTime
;
2273 tools::Time
aAbsMinTime( 0, 0 );
2274 if ( aTime
< aAbsMinTime
)
2275 aTime
= aAbsMinTime
;
2282 void TimeField::ImplTimeSpinArea( bool bUp
)
2286 tools::Time
aTime( GetTime() );
2287 OUString
aText( GetText() );
2288 Selection
aSelection( GetField()->GetSelection() );
2290 aTime
= TimeFormatter::SpinTime(bUp
, aTime
, GetFormat(), IsDuration(), aText
, aSelection
.Max(), ImplGetLocaleDataWrapper());
2292 ImplNewFieldValue( aTime
);
2296 void TimeFormatter::ImplInit()
2298 meFormat
= TimeFieldFormat::F_NONE
;
2300 mnTimeFormat
= TimeFormat::Hour24
; // Should become an ExtTimeFieldFormat in next implementation, merge with mbDuration and meFormat
2303 TimeFormatter::TimeFormatter(Edit
* pEdit
) :
2304 FormatterBase(pEdit
),
2307 maMax( 23, 59, 59, 999999999 ),
2308 mbEnforceValidValue( true ),
2314 TimeFormatter::~TimeFormatter()
2318 void TimeFormatter::ReformatAll()
2323 void TimeFormatter::SetMin( const tools::Time
& rNewMin
)
2326 if ( !IsEmptyFieldValue() )
2330 void TimeFormatter::SetMax( const tools::Time
& rNewMax
)
2333 if ( !IsEmptyFieldValue() )
2337 void TimeFormatter::SetTimeFormat( TimeFormat eNewFormat
)
2339 mnTimeFormat
= eNewFormat
;
2343 void TimeFormatter::SetFormat( TimeFieldFormat eNewFormat
)
2345 meFormat
= eNewFormat
;
2349 void TimeFormatter::SetDuration( bool bNewDuration
)
2351 mbDuration
= bNewDuration
;
2355 void TimeFormatter::SetTime( const tools::Time
& rNewTime
)
2357 SetUserTime( rNewTime
);
2358 maFieldTime
= maLastTime
;
2359 SetEmptyFieldValueData( false );
2362 void TimeFormatter::ImplNewFieldValue( const tools::Time
& rTime
)
2366 Selection aSelection
= GetField()->GetSelection();
2367 aSelection
.Justify();
2368 OUString aText
= GetField()->GetText();
2370 // If selected until the end then keep it that way
2371 if ( static_cast<sal_Int32
>(aSelection
.Max()) == aText
.getLength() )
2373 if ( !aSelection
.Len() )
2374 aSelection
.Min() = SELECTION_MAX
;
2375 aSelection
.Max() = SELECTION_MAX
;
2378 tools::Time aOldLastTime
= maLastTime
;
2379 ImplSetUserTime( rTime
, &aSelection
);
2380 maLastTime
= aOldLastTime
;
2382 // Modify at Edit is only set at KeyInput
2383 if ( GetField()->GetText() != aText
)
2385 GetField()->SetModifyFlag();
2386 GetField()->Modify();
2391 OUString
TimeFormatter::FormatTime(const tools::Time
& rNewTime
, TimeFieldFormat eFormat
, TimeFormat eHourFormat
, bool bDuration
, const LocaleDataWrapper
& rLocaleData
)
2395 bool b100Sec
= false;
2396 if ( eFormat
!= TimeFieldFormat::F_NONE
)
2398 if ( eFormat
== TimeFieldFormat::F_SEC_CS
)
2400 if ( eFormat
== TimeFieldFormat::F_SEC_CS
)
2402 sal_uLong n
= rNewTime
.GetHour() * 3600L;
2403 n
+= rNewTime
.GetMin() * 60L;
2404 n
+= rNewTime
.GetSec();
2405 aStr
= OUString::number( n
) + rLocaleData
.getTime100SecSep();
2406 std::ostringstream ostr
;
2409 ostr
<< rNewTime
.GetNanoSec();
2410 aStr
+= OUString::createFromAscii(ostr
.str().c_str());
2412 else if ( bDuration
)
2414 aStr
= rLocaleData
.getDuration( rNewTime
, bSec
, b100Sec
);
2418 aStr
= rLocaleData
.getTime( rNewTime
, bSec
, b100Sec
);
2419 if ( eHourFormat
== TimeFormat::Hour12
)
2421 if ( rNewTime
.GetHour() > 12 )
2423 tools::Time
aT( rNewTime
);
2424 aT
.SetHour( aT
.GetHour() % 12 );
2425 aStr
= rLocaleData
.getTime( aT
, bSec
, b100Sec
);
2427 // Don't use LocaleDataWrapper, we want AM/PM
2428 if ( rNewTime
.GetHour() < 12 )
2429 aStr
+= "AM"; // rLocaleData.getTimeAM();
2431 aStr
+= "PM"; // rLocaleData.getTimePM();
2438 void TimeFormatter::ImplSetUserTime( const tools::Time
& rNewTime
, Selection
const * pNewSelection
)
2440 tools::Time aNewTime
= rNewTime
;
2441 if ( aNewTime
> GetMax() )
2442 aNewTime
= GetMax();
2443 else if ( aNewTime
< GetMin() )
2444 aNewTime
= GetMin();
2445 maLastTime
= aNewTime
;
2449 OUString aStr
= TimeFormatter::FormatTime(aNewTime
, meFormat
, GetTimeFormat(), mbDuration
, ImplGetLocaleDataWrapper());
2450 ImplSetText( aStr
, pNewSelection
);
2454 void TimeFormatter::SetUserTime( const tools::Time
& rNewTime
)
2456 ImplSetUserTime( rNewTime
);
2459 tools::Time
TimeFormatter::GetTime() const
2461 tools::Time
aTime( 0, 0, 0 );
2465 bool bAllowMailformed
= ImplAllowMalformedInput();
2466 if ( TextToTime( GetField()->GetText(), aTime
, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), !bAllowMailformed
) )
2468 if ( aTime
> GetMax() )
2470 else if ( aTime
< GetMin() )
2475 if ( bAllowMailformed
)
2476 aTime
= tools::Time( 99, 99, 99 ); // set invalid time
2485 void TimeFormatter::Reformat()
2490 if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
2494 ImplTimeReformat( GetField()->GetText(), aStr
);
2496 if ( !aStr
.isEmpty() )
2498 ImplSetText( aStr
);
2499 (void)TextToTime(aStr
, maLastTime
, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper());
2502 SetTime( maLastTime
);
2505 TimeField::TimeField( vcl::Window
* pParent
, WinBits nWinStyle
) :
2506 SpinField( pParent
, nWinStyle
),
2507 TimeFormatter(this),
2508 maFirst( GetMin() ),
2511 SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime
, false ) );
2515 void TimeField::dispose()
2518 SpinField::dispose();
2521 bool TimeField::PreNotify( NotifyEvent
& rNEvt
)
2523 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
2525 if ( ImplTimeProcessKeyInput( *rNEvt
.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
2529 return SpinField::PreNotify( rNEvt
);
2532 bool TimeField::EventNotify( NotifyEvent
& rNEvt
)
2534 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
2535 MarkToBeReformatted( false );
2536 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
2538 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
2540 if ( !ImplAllowMalformedInput() )
2544 tools::Time
aTime( 0, 0, 0 );
2545 if ( TextToTime( GetText(), aTime
, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), false ) )
2546 // even with strict text analysis, our text is a valid time -> do a complete
2553 return SpinField::EventNotify( rNEvt
);
2556 void TimeField::DataChanged( const DataChangedEvent
& rDCEvt
)
2558 SpinField::DataChanged( rDCEvt
);
2560 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
2562 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
2567 void TimeField::Modify()
2569 MarkToBeReformatted( true );
2570 SpinField::Modify();
2573 void TimeField::Up()
2575 ImplTimeSpinArea( true );
2579 void TimeField::Down()
2581 ImplTimeSpinArea( false );
2585 void TimeField::First()
2587 ImplNewFieldValue( maFirst
);
2591 void TimeField::Last()
2593 ImplNewFieldValue( maLast
);
2597 void TimeField::SetExtFormat( ExtTimeFieldFormat eFormat
)
2601 case ExtTimeFieldFormat::Short24H
:
2603 SetTimeFormat( TimeFormat::Hour24
);
2604 SetDuration( false );
2605 SetFormat( TimeFieldFormat::F_NONE
);
2608 case ExtTimeFieldFormat::Long24H
:
2610 SetTimeFormat( TimeFormat::Hour24
);
2611 SetDuration( false );
2612 SetFormat( TimeFieldFormat::F_SEC
);
2615 default: OSL_FAIL( "ExtTimeFieldFormat unknown!" );
2618 if ( GetField() && !GetField()->GetText().isEmpty() )
2619 SetUserTime( GetTime() );
2623 TimeBox::TimeBox(vcl::Window
* pParent
, WinBits nWinStyle
)
2624 : ComboBox(pParent
, nWinStyle
)
2625 , TimeFormatter(this)
2627 SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime
, false ) );
2631 void TimeBox::dispose()
2634 ComboBox::dispose();
2637 bool TimeBox::PreNotify( NotifyEvent
& rNEvt
)
2639 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
2641 if ( ImplTimeProcessKeyInput( *rNEvt
.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
2645 return ComboBox::PreNotify( rNEvt
);
2648 bool TimeBox::EventNotify( NotifyEvent
& rNEvt
)
2650 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
2651 MarkToBeReformatted( false );
2652 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
2654 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
2658 return ComboBox::EventNotify( rNEvt
);
2661 void TimeBox::DataChanged( const DataChangedEvent
& rDCEvt
)
2663 ComboBox::DataChanged( rDCEvt
);
2665 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
2667 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
2672 void TimeBox::Modify()
2674 MarkToBeReformatted( true );
2678 void TimeBox::ReformatAll()
2681 SetUpdateMode( false );
2682 const sal_Int32 nEntryCount
= GetEntryCount();
2683 for ( sal_Int32 i
=0; i
< nEntryCount
; ++i
)
2685 ImplTimeReformat( GetEntry( i
), aStr
);
2687 InsertEntry( aStr
, i
);
2689 TimeFormatter::Reformat();
2690 SetUpdateMode( true );
2693 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */