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"
24 #include <tools/diagnose_ex.h>
25 #include <comphelper/processfactory.hxx>
26 #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 <i18nlangtag/mslangid.hxx>
38 #include <com/sun/star/lang/Locale.hpp>
39 #include <com/sun/star/i18n/XCharacterClassification.hpp>
40 #include <com/sun/star/i18n/KCharacterType.hpp>
42 #include <unotools/localedatawrapper.hxx>
43 #include <unotools/calendarwrapper.hxx>
44 #include <unotools/charclass.hxx>
45 #include <unotools/misccfg.hxx>
47 using namespace ::com::sun::star
;
48 using namespace ::comphelper
;
50 #define EDITMASK_LITERAL 'L'
51 #define EDITMASK_ALPHA 'a'
52 #define EDITMASK_UPPERALPHA 'A'
53 #define EDITMASK_ALPHANUM 'c'
54 #define EDITMASK_UPPERALPHANUM 'C'
55 #define EDITMASK_NUM 'N'
56 #define EDITMASK_NUMSPACE 'n'
57 #define EDITMASK_ALLCHAR 'x'
58 #define EDITMASK_UPPERALLCHAR 'X'
60 uno::Reference
< i18n::XCharacterClassification
> const & ImplGetCharClass()
62 static uno::Reference
< i18n::XCharacterClassification
> xCharClass
;
63 if ( !xCharClass
.is() )
64 xCharClass
= vcl::unohelper::CreateCharacterClassification();
69 static sal_Unicode
* ImplAddString( sal_Unicode
* pBuf
, const OUString
& rStr
)
71 if ( rStr
.getLength() == 1 )
73 else if ( rStr
.isEmpty() )
77 memcpy( pBuf
, rStr
.getStr(), rStr
.getLength() * sizeof(sal_Unicode
) );
78 pBuf
+= rStr
.getLength();
83 static sal_Unicode
* ImplAddNum( sal_Unicode
* pBuf
, sal_uLong nNumber
, int nMinLen
)
85 // fill temp buffer with digits
86 sal_Unicode aTempBuf
[30];
87 sal_Unicode
* pTempBuf
= aTempBuf
;
90 *pTempBuf
= (sal_Unicode
)(nNumber
% 10) + '0';
98 // fill with zeros up to the minimal length
106 // copy temp buffer to real buffer
113 while ( pTempBuf
!= aTempBuf
);
118 static sal_Unicode
* ImplAddSNum( sal_Unicode
* pBuf
, sal_Int32 nNumber
, int nMinLen
)
125 return ImplAddNum( pBuf
, nNumber
, nMinLen
);
128 static sal_uInt16
ImplGetNum( const sal_Unicode
*& rpBuf
, bool& rbError
)
136 sal_uInt16 nNumber
= 0;
137 while( ( *rpBuf
>= '0' ) && ( *rpBuf
<= '9' ) )
140 nNumber
+= *rpBuf
- '0';
147 static void ImplSkipDelimiters( const sal_Unicode
*& rpBuf
)
149 while( ( *rpBuf
== ',' ) || ( *rpBuf
== '.' ) || ( *rpBuf
== ';' ) ||
150 ( *rpBuf
== ':' ) || ( *rpBuf
== '-' ) || ( *rpBuf
== '/' ) )
156 static bool ImplIsPatternChar( sal_Unicode cChar
, sal_Char cEditMask
)
162 OUString
aCharStr(cChar
);
163 nType
= ImplGetCharClass()->getStringType( aCharStr
, 0, aCharStr
.getLength(),
164 Application::GetSettings().GetLanguageTag().getLocale() );
166 catch (const css::uno::Exception
&)
168 SAL_WARN( "vcl.control", "ImplIsPatternChar: Exception caught!" );
169 DBG_UNHANDLED_EXCEPTION();
173 if ( (cEditMask
== EDITMASK_ALPHA
) || (cEditMask
== EDITMASK_UPPERALPHA
) )
175 if( !CharClass::isLetterType( nType
) )
178 else if ( cEditMask
== EDITMASK_NUM
)
180 if( !CharClass::isNumericType( nType
) )
183 else if ( (cEditMask
== EDITMASK_ALPHANUM
) || (cEditMask
== EDITMASK_UPPERALPHANUM
) )
185 if( !CharClass::isLetterNumericType( nType
) )
188 else if ( (cEditMask
== EDITMASK_ALLCHAR
) || (cEditMask
== EDITMASK_UPPERALLCHAR
) )
193 else if ( cEditMask
== EDITMASK_NUMSPACE
)
195 if ( !CharClass::isNumericType( nType
) && ( cChar
!= ' ' ) )
204 static sal_Unicode
ImplPatternChar( sal_Unicode cChar
, sal_Char cEditMask
)
206 if ( ImplIsPatternChar( cChar
, cEditMask
) )
208 if ( (cEditMask
== EDITMASK_UPPERALPHA
) ||
209 (cEditMask
== EDITMASK_UPPERALPHANUM
) ||
210 ( cEditMask
== EDITMASK_UPPERALLCHAR
) )
212 cChar
= ImplGetCharClass()->toUpper(OUString(cChar
), 0, 1,
213 Application::GetSettings().GetLanguageTag().getLocale())[0];
221 static bool ImplCommaPointCharEqual( sal_Unicode c1
, sal_Unicode c2
)
225 else if ( ((c1
== '.') || (c1
== ',')) &&
226 ((c2
== '.') || (c2
== ',')) )
232 static OUString
ImplPatternReformat( const OUString
& rStr
,
233 const OString
& rEditMask
,
234 const OUString
& rLiteralMask
,
235 sal_uInt16 nFormatFlags
)
237 if (rEditMask
.isEmpty())
240 OUStringBuffer aOutStr
= OUString(rLiteralMask
);
241 sal_Unicode cTempChar
;
243 sal_Unicode cLiteral
;
245 sal_Int32 nStrIndex
= 0;
249 while ( i
< rEditMask
.getLength() )
251 if ( nStrIndex
>= rStr
.getLength() )
254 cChar
= rStr
[nStrIndex
];
255 cLiteral
= rLiteralMask
[i
];
256 cMask
= rEditMask
[i
];
258 // current position is a literal
259 if ( cMask
== EDITMASK_LITERAL
)
261 // if it is a literal copy otherwise ignore because it might be the next valid
262 // character of the string
263 if ( ImplCommaPointCharEqual( cChar
, cLiteral
) )
267 // Otherwise we check if it is a invalid character. This is the case if it does not
268 // fit in the pattern of the next non-literal character.
270 while ( n
< rEditMask
.getLength() )
272 if ( rEditMask
[n
] != EDITMASK_LITERAL
)
274 if ( !ImplIsPatternChar( cChar
, rEditMask
[n
] ) )
285 // valid character at this position
286 cTempChar
= ImplPatternChar( cChar
, cMask
);
289 // use this character
290 aOutStr
[i
] = cTempChar
;
295 // copy if it is a literal character
296 if ( cLiteral
== cChar
)
300 // If the invalid character might be the next literal character then we jump
301 // ahead to it, otherwise we ignore it. Do only if empty literals are allowed.
302 if ( nFormatFlags
& PATTERN_FORMAT_EMPTYLITERALS
)
305 while ( n
< rEditMask
.getLength() )
307 if ( rEditMask
[n
] == EDITMASK_LITERAL
)
309 if ( ImplCommaPointCharEqual( cChar
, rLiteralMask
[n
] ) )
328 return aOutStr
.makeStringAndClear();
331 static void ImplPatternMaxPos( const OUString
& rStr
, const OString
& rEditMask
,
332 sal_uInt16 nFormatFlags
, bool bSameMask
,
333 sal_Int32 nCursorPos
, sal_Int32
& rPos
)
336 // last position must not be longer than the contained string
337 sal_Int32 nMaxPos
= rStr
.getLength();
339 // if non empty literals are allowed ignore blanks at the end as well
340 if ( bSameMask
&& !(nFormatFlags
& PATTERN_FORMAT_EMPTYLITERALS
) )
344 if ( (rEditMask
[nMaxPos
-1] != EDITMASK_LITERAL
) &&
345 (rStr
[nMaxPos
-1] != ' ') )
350 // if we are in front of a literal, continue search until first character after the literal
351 sal_Int32 nTempPos
= nMaxPos
;
352 while ( nTempPos
< rEditMask
.getLength() )
354 if ( rEditMask
[nTempPos
] != EDITMASK_LITERAL
)
363 if ( rPos
> nMaxPos
)
366 // character should not move left
367 if ( rPos
< nCursorPos
)
371 static void ImplPatternProcessStrictModify( Edit
* pEdit
,
372 const OString
& rEditMask
,
373 const OUString
& rLiteralMask
,
374 sal_uInt16 nFormatFlags
, bool bSameMask
)
376 OUString aText
= pEdit
->GetText();
378 // remove leading blanks
379 if ( bSameMask
&& !(nFormatFlags
& PATTERN_FORMAT_EMPTYLITERALS
) )
382 sal_Int32 nMaxLen
= aText
.getLength();
383 while ( i
< nMaxLen
)
385 if ( (rEditMask
[i
] != EDITMASK_LITERAL
) &&
391 // keep all literal characters
392 while ( i
&& (rEditMask
[i
] == EDITMASK_LITERAL
) )
394 aText
= aText
.copy( i
);
397 OUString aNewText
= ImplPatternReformat( aText
, rEditMask
, rLiteralMask
, nFormatFlags
);
398 if ( aNewText
!= aText
)
400 // adjust selection such that it remains at the end if it was there before
401 Selection aSel
= pEdit
->GetSelection();
402 sal_Int64 nMaxSel
= std::max( aSel
.Min(), aSel
.Max() );
403 if ( nMaxSel
>= aText
.getLength() )
405 sal_Int32 nMaxPos
= aNewText
.getLength();
406 ImplPatternMaxPos( aNewText
, rEditMask
, nFormatFlags
, bSameMask
, nMaxSel
, nMaxPos
);
407 if ( aSel
.Min() == aSel
.Max() )
409 aSel
.Min() = nMaxPos
;
410 aSel
.Max() = aSel
.Min();
412 else if ( aSel
.Min() > aSel
.Max() )
413 aSel
.Min() = nMaxPos
;
415 aSel
.Max() = nMaxPos
;
417 pEdit
->SetText( aNewText
, aSel
);
421 static sal_Int32
ImplPatternLeftPos(const OString
& rEditMask
, sal_Int32 nCursorPos
)
423 // search non-literal predecessor
424 sal_Int32 nNewPos
= nCursorPos
;
425 sal_Int32 nTempPos
= nNewPos
;
428 if ( rEditMask
[nTempPos
-1] != EDITMASK_LITERAL
)
430 nNewPos
= nTempPos
-1;
438 static sal_Int32
ImplPatternRightPos( const OUString
& rStr
, const OString
& rEditMask
,
439 sal_uInt16 nFormatFlags
, bool bSameMask
,
440 sal_Int32 nCursorPos
)
442 // search non-literal successor
443 sal_Int32 nNewPos
= nCursorPos
;
445 for(sal_Int32 nTempPos
= nNewPos
+1; nTempPos
< rEditMask
.getLength(); ++nTempPos
)
447 if ( rEditMask
[nTempPos
] != EDITMASK_LITERAL
)
453 ImplPatternMaxPos( rStr
, rEditMask
, nFormatFlags
, bSameMask
, nCursorPos
, nNewPos
);
457 static bool ImplPatternProcessKeyInput( Edit
* pEdit
, const KeyEvent
& rKEvt
,
458 const OString
& rEditMask
,
459 const OUString
& rLiteralMask
,
461 sal_uInt16 nFormatFlags
,
465 if ( rEditMask
.isEmpty() || !bStrictFormat
)
468 Selection aOldSel
= pEdit
->GetSelection();
469 vcl::KeyCode aCode
= rKEvt
.GetKeyCode();
470 sal_Unicode cChar
= rKEvt
.GetCharCode();
471 sal_uInt16 nKeyCode
= aCode
.GetCode();
472 bool bShift
= aCode
.IsShift();
473 sal_Int32 nCursorPos
= static_cast<sal_Int32
>(aOldSel
.Max());
477 if ( nKeyCode
&& !aCode
.IsMod1() && !aCode
.IsMod2() )
479 if ( nKeyCode
== KEY_LEFT
)
481 Selection
aSel( ImplPatternLeftPos( rEditMask
, nCursorPos
) );
483 aSel
.Min() = aOldSel
.Min();
484 pEdit
->SetSelection( aSel
);
487 else if ( nKeyCode
== KEY_RIGHT
)
489 // Use the start of selection as minimum; even a small position is allowed in case that
490 // all was selected by the focus
491 Selection
aSel( aOldSel
);
493 nCursorPos
= aSel
.Min();
494 aSel
.Max() = ImplPatternRightPos( pEdit
->GetText(), rEditMask
, nFormatFlags
, bSameMask
, nCursorPos
);
496 aSel
.Min() = aOldSel
.Min();
498 aSel
.Min() = aSel
.Max();
499 pEdit
->SetSelection( aSel
);
502 else if ( nKeyCode
== KEY_HOME
)
504 // Home is the position of the first non-literal character
506 while ( (nNewPos
< rEditMask
.getLength()) &&
507 (rEditMask
[nNewPos
] == EDITMASK_LITERAL
) )
510 // Home should not move to the right
511 if ( nCursorPos
< nNewPos
)
512 nNewPos
= nCursorPos
;
513 Selection
aSel( nNewPos
);
515 aSel
.Min() = aOldSel
.Min();
516 pEdit
->SetSelection( aSel
);
519 else if ( nKeyCode
== KEY_END
)
521 // End is position of last non-literal character
522 nNewPos
= rEditMask
.getLength();
524 (rEditMask
[nNewPos
-1] == EDITMASK_LITERAL
) )
526 // Use the start of selection as minimum; even a small position is allowed in case that
527 // all was selected by the focus
528 Selection
aSel( aOldSel
);
530 nCursorPos
= static_cast<sal_Int32
>(aSel
.Min());
531 ImplPatternMaxPos( pEdit
->GetText(), rEditMask
, nFormatFlags
, bSameMask
, nCursorPos
, nNewPos
);
532 aSel
.Max() = nNewPos
;
534 aSel
.Min() = aOldSel
.Min();
536 aSel
.Min() = aSel
.Max();
537 pEdit
->SetSelection( aSel
);
540 else if ( (nKeyCode
== KEY_BACKSPACE
) || (nKeyCode
== KEY_DELETE
) )
542 OUString
aOldStr( pEdit
->GetText() );
543 OUStringBuffer
aStr( aOldStr
);
544 Selection aSel
= aOldSel
;
547 nNewPos
= static_cast<sal_Int32
>(aSel
.Min());
549 // if selection then delete it
553 aStr
.remove( static_cast<sal_Int32
>(aSel
.Min()), static_cast<sal_Int32
>(aSel
.Len()) );
556 OUString aRep
= rLiteralMask
.copy( static_cast<sal_Int32
>(aSel
.Min()), static_cast<sal_Int32
>(aSel
.Len()) );
557 aStr
.remove( aSel
.Min(), aRep
.getLength() );
558 aStr
.insert( aSel
.Min(), aRep
);
563 if ( nKeyCode
== KEY_BACKSPACE
)
566 nNewPos
= ImplPatternLeftPos( rEditMask
, nTempPos
);
569 nTempPos
= ImplPatternRightPos( aStr
.toString(), rEditMask
, nFormatFlags
, bSameMask
, nNewPos
);
571 if ( nNewPos
!= nTempPos
)
575 if ( rEditMask
[nNewPos
] != EDITMASK_LITERAL
)
576 aStr
.remove( nNewPos
, 1 );
580 aStr
[nNewPos
] = rLiteralMask
[nNewPos
];
585 if ( aOldStr
!= aStr
.toString() )
588 aStr
= ImplPatternReformat( aStr
.toString(), rEditMask
, rLiteralMask
, nFormatFlags
);
590 pEdit
->SetText( aStr
.toString(), Selection( nNewPos
) );
591 pEdit
->SetModifyFlag();
593 rbInKeyInput
= false;
596 pEdit
->SetSelection( Selection( nNewPos
) );
600 else if ( nKeyCode
== KEY_INSERT
)
602 // you can only set InsertModus for a PatternField if the
603 // mask is equal at all input positions
611 if ( rKEvt
.GetKeyCode().IsMod2() || (cChar
< 32) || (cChar
== 127) )
614 Selection aSel
= aOldSel
;
616 nNewPos
= aSel
.Min();
618 if ( nNewPos
< rEditMask
.getLength() )
620 sal_Unicode cPattChar
= ImplPatternChar( cChar
, rEditMask
[nNewPos
] );
625 // If no valid character, check if the user wanted to jump to next literal. We do this
626 // only if we're after a character, so that literals that were skipped automatically
627 // do not influence the position anymore.
629 (rEditMask
[nNewPos
-1] != EDITMASK_LITERAL
) &&
632 // search for next character not being a literal
634 while ( nTempPos
< rEditMask
.getLength() )
636 if ( rEditMask
[nTempPos
] == EDITMASK_LITERAL
)
638 // only valid if no literal present
639 if ( (rEditMask
[nTempPos
+1] != EDITMASK_LITERAL
) &&
640 ImplCommaPointCharEqual( cChar
, rLiteralMask
[nTempPos
] ) )
643 ImplPatternMaxPos( pEdit
->GetText(), rEditMask
, nFormatFlags
, bSameMask
, nNewPos
, nTempPos
);
644 if ( nTempPos
> nNewPos
)
646 pEdit
->SetSelection( Selection( nTempPos
) );
663 OUStringBuffer aStr
= pEdit
->GetText();
665 if ( bSameMask
&& pEdit
->IsInsertMode() )
667 // crop spaces and literals at the end until current position
668 sal_Int32 n
= aStr
.getLength();
669 while ( n
&& (n
> nNewPos
) )
671 if ( (aStr
[n
-1] != ' ') &&
672 ((n
> rEditMask
.getLength()) || (rEditMask
[n
-1] != EDITMASK_LITERAL
)) )
680 aStr
.remove( aSel
.Min(), aSel
.Len() );
682 if ( aStr
.getLength() < rEditMask
.getLength() )
684 // possibly extend string until cursor position
685 if ( aStr
.getLength() < nNewPos
)
686 aStr
.append( rLiteralMask
.copy( aStr
.getLength(), nNewPos
-aStr
.getLength() ));
687 if ( nNewPos
< aStr
.getLength() )
688 aStr
.insert( cChar
, nNewPos
);
689 else if ( nNewPos
< rEditMask
.getLength() )
691 aStr
= ImplPatternReformat( aStr
.toString(), rEditMask
, rLiteralMask
, nFormatFlags
);
701 OUString aRep
= rLiteralMask
.copy( aSel
.Min(), aSel
.Len() );
702 aStr
.remove( aSel
.Min(), aRep
.getLength() );
703 aStr
.insert( aSel
.Min(), aRep
);
706 if ( nNewPos
< aStr
.getLength() )
707 aStr
[nNewPos
] = cChar
;
708 else if ( nNewPos
< rEditMask
.getLength() )
715 Selection
aNewSel( ImplPatternRightPos( aStr
.toString(), rEditMask
, nFormatFlags
, bSameMask
, nNewPos
) );
716 pEdit
->SetText( aStr
.toString(), aNewSel
);
717 pEdit
->SetModifyFlag();
719 rbInKeyInput
= false;
726 void PatternFormatter::ImplSetMask(const OString
& rEditMask
, const OUString
& rLiteralMask
)
728 m_aEditMask
= rEditMask
;
729 maLiteralMask
= rLiteralMask
;
732 if ( m_aEditMask
.getLength() != maLiteralMask
.getLength() )
734 OUStringBuffer
aBuf(maLiteralMask
);
735 if (m_aEditMask
.getLength() < aBuf
.getLength())
736 aBuf
.remove(m_aEditMask
.getLength(), aBuf
.getLength() - m_aEditMask
.getLength());
738 comphelper::string::padToLength(aBuf
, m_aEditMask
.getLength(), ' ');
739 maLiteralMask
= aBuf
.makeStringAndClear();
742 // Strict mode allows only the input mode if only equal characters are allowed as mask and if
743 // only spaces are specified which are not allowed by the mask
746 while ( i
< rEditMask
.getLength() )
748 sal_Char cTemp
= rEditMask
[i
];
749 if ( cTemp
!= EDITMASK_LITERAL
)
751 if ( (cTemp
== EDITMASK_ALLCHAR
) ||
752 (cTemp
== EDITMASK_UPPERALLCHAR
) ||
753 (cTemp
== EDITMASK_NUMSPACE
) )
758 if ( i
< rLiteralMask
.getLength() )
760 if ( rLiteralMask
[i
] != ' ' )
778 PatternFormatter::PatternFormatter()
781 mbInPattKeyInput
= false;
784 PatternFormatter::~PatternFormatter()
788 void PatternFormatter::SetMask( const OString
& rEditMask
,
789 const OUString
& rLiteralMask
)
791 ImplSetMask( rEditMask
, rLiteralMask
);
795 void PatternFormatter::SetString( const OUString
& rStr
)
797 maFieldString
= rStr
;
800 GetField()->SetText( rStr
);
801 MarkToBeReformatted( false );
805 OUString
PatternFormatter::GetString() const
810 return ImplPatternReformat( GetField()->GetText(), m_aEditMask
, maLiteralMask
, 0/*nFormatFlags*/ );
813 void PatternFormatter::Reformat()
817 ImplSetText( ImplPatternReformat( GetField()->GetText(), m_aEditMask
, maLiteralMask
, 0/*nFormatFlags*/ ) );
818 if ( !mbSameMask
&& IsStrictFormat() && !GetField()->IsReadOnly() )
819 GetField()->SetInsertMode( false );
823 PatternField::PatternField( vcl::Window
* pParent
, WinBits nWinStyle
) :
824 SpinField( pParent
, nWinStyle
)
830 void PatternField::dispose()
832 PatternFormatter::SetField( nullptr );
833 SpinField::dispose();
836 bool PatternField::PreNotify( NotifyEvent
& rNEvt
)
838 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
840 if ( ImplPatternProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
841 IsStrictFormat(), 0/*nFormatFlags*/,
842 ImplIsSameMask(), ImplGetInPattKeyInput() ) )
846 return SpinField::PreNotify( rNEvt
);
849 bool PatternField::EventNotify( NotifyEvent
& rNEvt
)
851 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
852 MarkToBeReformatted( false );
853 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
855 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
859 return SpinField::EventNotify( rNEvt
);
862 void PatternField::Modify()
864 if ( !ImplGetInPattKeyInput() )
866 if ( IsStrictFormat() )
867 ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), 0/*nFormatFlags*/, ImplIsSameMask() );
869 MarkToBeReformatted( true );
875 PatternBox::PatternBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
876 ComboBox( pParent
, nWinStyle
)
882 void PatternBox::dispose()
884 PatternFormatter::SetField( nullptr );
888 bool PatternBox::PreNotify( NotifyEvent
& rNEvt
)
890 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
892 if ( ImplPatternProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
893 IsStrictFormat(), 0/*nFormatFlags*/,
894 ImplIsSameMask(), ImplGetInPattKeyInput() ) )
898 return ComboBox::PreNotify( rNEvt
);
901 bool PatternBox::EventNotify( NotifyEvent
& rNEvt
)
903 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
904 MarkToBeReformatted( false );
905 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
907 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
911 return ComboBox::EventNotify( rNEvt
);
914 void PatternBox::Modify()
916 if ( !ImplGetInPattKeyInput() )
918 if ( IsStrictFormat() )
919 ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), 0/*nFormatFlags*/, ImplIsSameMask() );
921 MarkToBeReformatted( true );
927 void PatternBox::ReformatAll()
930 SetUpdateMode( false );
931 const sal_Int32 nEntryCount
= GetEntryCount();
932 for ( sal_Int32 i
=0; i
< nEntryCount
; ++i
)
934 aStr
= ImplPatternReformat( GetEntry( i
), GetEditMask(), GetLiteralMask(), 0/*nFormatFlags*/ );
936 InsertEntry( aStr
, i
);
938 PatternFormatter::Reformat();
939 SetUpdateMode( true );
942 static ExtDateFieldFormat
ImplGetExtFormat( DateFormat eOld
)
946 case DMY
: return ExtDateFieldFormat::ShortDDMMYY
;
947 case MDY
: return ExtDateFieldFormat::ShortMMDDYY
;
948 default: return ExtDateFieldFormat::ShortYYMMDD
;
952 static sal_uInt16
ImplCutNumberFromString( OUString
& rStr
)
955 while (i1
!= rStr
.getLength() && !(rStr
[i1
] >= '0' && rStr
[i1
] <= '9')) {
959 while (i2
!= rStr
.getLength() && rStr
[i2
] >= '0' && rStr
[i2
] <= '9') {
962 sal_Int32 nValue
= rStr
.copy(i1
, i2
-i1
).toInt32();
963 rStr
= rStr
.copy(std::min(i2
+1, rStr
.getLength()));
967 static bool ImplCutMonthName( OUString
& rStr
, const OUString
& _rLookupMonthName
)
970 rStr
= rStr
.replaceFirst(_rLookupMonthName
, "", &index
);
974 static sal_uInt16
ImplCutMonthFromString( OUString
& rStr
, const CalendarWrapper
& rCalendarWrapper
)
976 // search for a month' name
977 for ( sal_uInt16 i
=1; i
<= 12; i
++ )
979 OUString aMonthName
= rCalendarWrapper
.getMonths()[i
-1].FullName
;
981 if ( ImplCutMonthName( rStr
, aMonthName
) )
985 OUString aAbbrevMonthName
= rCalendarWrapper
.getMonths()[i
-1].AbbrevName
;
986 if ( ImplCutMonthName( rStr
, aAbbrevMonthName
) )
990 return ImplCutNumberFromString( rStr
);
993 static OUString
ImplGetDateSep( const LocaleDataWrapper
& rLocaleDataWrapper
, ExtDateFieldFormat eFormat
)
995 if ( ( eFormat
== ExtDateFieldFormat::ShortYYMMDD_DIN5008
) || ( eFormat
== ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
) )
996 return OUString("-");
998 return rLocaleDataWrapper
.getDateSep();
1001 static bool ImplDateProcessKeyInput( Edit
*, const KeyEvent
& rKEvt
, ExtDateFieldFormat eFormat
,
1002 const LocaleDataWrapper
& rLocaleDataWrapper
)
1004 sal_Unicode cChar
= rKEvt
.GetCharCode();
1005 sal_uInt16 nGroup
= rKEvt
.GetKeyCode().GetGroup();
1006 if ( (nGroup
== KEYGROUP_FKEYS
) || (nGroup
== KEYGROUP_CURSOR
) ||
1007 (nGroup
== KEYGROUP_MISC
)||
1008 ((cChar
>= '0') && (cChar
<= '9')) ||
1009 (cChar
== ImplGetDateSep( rLocaleDataWrapper
, eFormat
)[0]) )
1015 static bool ImplDateGetValue( const OUString
& rStr
, Date
& rDate
, ExtDateFieldFormat eDateFormat
,
1016 const LocaleDataWrapper
& rLocaleDataWrapper
, const CalendarWrapper
& rCalendarWrapper
,
1017 const AllSettings
& )
1019 sal_uInt16 nDay
= 0;
1020 sal_uInt16 nMonth
= 0;
1021 sal_uInt16 nYear
= 0;
1022 bool bError
= false;
1023 OUString
aStr( rStr
);
1025 if ( eDateFormat
== ExtDateFieldFormat::SystemLong
)
1027 DateFormat eFormat
= rLocaleDataWrapper
.getLongDateFormat();
1031 nMonth
= ImplCutMonthFromString( aStr
, rCalendarWrapper
);
1032 nDay
= ImplCutNumberFromString( aStr
);
1033 nYear
= ImplCutNumberFromString( aStr
);
1036 nDay
= ImplCutNumberFromString( aStr
);
1037 nMonth
= ImplCutMonthFromString( aStr
, rCalendarWrapper
);
1038 nYear
= ImplCutNumberFromString( aStr
);
1042 nYear
= ImplCutNumberFromString( aStr
);
1043 nMonth
= ImplCutMonthFromString( aStr
, rCalendarWrapper
);
1044 nDay
= ImplCutNumberFromString( aStr
);
1052 // Check if year is present:
1053 OUString aDateSep
= ImplGetDateSep( rLocaleDataWrapper
, eDateFormat
);
1054 sal_Int32 nSepPos
= aStr
.indexOf( aDateSep
);
1057 nSepPos
= aStr
.indexOf( aDateSep
, nSepPos
+1 );
1058 if ( ( nSepPos
< 0 ) || ( nSepPos
== (aStr
.getLength()-1) ) )
1061 nYear
= Date( Date::SYSTEM
).GetYearUnsigned();
1064 const sal_Unicode
* pBuf
= aStr
.getStr();
1065 ImplSkipDelimiters( pBuf
);
1067 switch ( eDateFormat
)
1069 case ExtDateFieldFormat::ShortDDMMYY
:
1070 case ExtDateFieldFormat::ShortDDMMYYYY
:
1072 nDay
= ImplGetNum( pBuf
, bError
);
1073 ImplSkipDelimiters( pBuf
);
1074 nMonth
= ImplGetNum( pBuf
, bError
);
1075 ImplSkipDelimiters( pBuf
);
1077 nYear
= ImplGetNum( pBuf
, bError
);
1080 case ExtDateFieldFormat::ShortMMDDYY
:
1081 case ExtDateFieldFormat::ShortMMDDYYYY
:
1083 nMonth
= ImplGetNum( pBuf
, bError
);
1084 ImplSkipDelimiters( pBuf
);
1085 nDay
= ImplGetNum( pBuf
, bError
);
1086 ImplSkipDelimiters( pBuf
);
1088 nYear
= ImplGetNum( pBuf
, bError
);
1091 case ExtDateFieldFormat::ShortYYMMDD
:
1092 case ExtDateFieldFormat::ShortYYYYMMDD
:
1093 case ExtDateFieldFormat::ShortYYMMDD_DIN5008
:
1094 case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
:
1097 nYear
= ImplGetNum( pBuf
, bError
);
1098 ImplSkipDelimiters( pBuf
);
1099 nMonth
= ImplGetNum( pBuf
, bError
);
1100 ImplSkipDelimiters( pBuf
);
1101 nDay
= ImplGetNum( pBuf
, bError
);
1107 OSL_FAIL( "DateFormat???" );
1112 if ( bError
|| !nDay
|| !nMonth
)
1115 Date
aNewDate( nDay
, nMonth
, nYear
);
1116 DateFormatter::ExpandCentury( aNewDate
, utl::MiscCfg().GetYear2000() );
1117 if ( aNewDate
.IsValidDate() )
1125 bool DateFormatter::ImplDateReformat( const OUString
& rStr
, OUString
& rOutStr
, const AllSettings
& rSettings
)
1127 Date
aDate( Date::EMPTY
);
1128 if ( !ImplDateGetValue( rStr
, aDate
, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1131 Date aTempDate
= aDate
;
1132 if ( aTempDate
> GetMax() )
1133 aTempDate
= GetMax();
1134 else if ( aTempDate
< GetMin() )
1135 aTempDate
= GetMin();
1137 rOutStr
= ImplGetDateAsText( aTempDate
, rSettings
);
1142 OUString
DateFormatter::ImplGetDateAsText( const Date
& rDate
,
1143 const AllSettings
& ) const
1145 bool bShowCentury
= false;
1146 switch ( GetExtDateFormat() )
1148 case ExtDateFieldFormat::SystemShortYYYY
:
1149 case ExtDateFieldFormat::SystemLong
:
1150 case ExtDateFieldFormat::ShortDDMMYYYY
:
1151 case ExtDateFieldFormat::ShortMMDDYYYY
:
1152 case ExtDateFieldFormat::ShortYYYYMMDD
:
1153 case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
:
1155 bShowCentury
= true;
1160 bShowCentury
= false;
1164 if ( !bShowCentury
)
1166 // Check if I have to use force showing the century
1167 sal_uInt16 nTwoDigitYearStart
= utl::MiscCfg().GetYear2000();
1168 sal_uInt16 nYear
= rDate
.GetYearUnsigned();
1170 // If year is not in double digit range
1171 if ( (nYear
< nTwoDigitYearStart
) || (nYear
>= nTwoDigitYearStart
+100) )
1172 bShowCentury
= true;
1175 sal_Unicode aBuf
[128];
1176 sal_Unicode
* pBuf
= aBuf
;
1178 OUString aDateSep
= ImplGetDateSep( ImplGetLocaleDataWrapper(), GetExtDateFormat( true ) );
1179 sal_uInt16 nDay
= rDate
.GetDay();
1180 sal_uInt16 nMonth
= rDate
.GetMonth();
1181 sal_Int16 nYear
= rDate
.GetYear();
1182 sal_uInt16 nYearLen
= bShowCentury
? 4 : 2;
1184 if ( !bShowCentury
)
1187 switch ( GetExtDateFormat( true ) )
1189 case ExtDateFieldFormat::SystemLong
:
1191 return ImplGetLocaleDataWrapper().getLongDate( rDate
, GetCalendarWrapper(), !bShowCentury
);
1193 case ExtDateFieldFormat::ShortDDMMYY
:
1194 case ExtDateFieldFormat::ShortDDMMYYYY
:
1196 pBuf
= ImplAddNum( pBuf
, nDay
, 2 );
1197 pBuf
= ImplAddString( pBuf
, aDateSep
);
1198 pBuf
= ImplAddNum( pBuf
, nMonth
, 2 );
1199 pBuf
= ImplAddString( pBuf
, aDateSep
);
1200 pBuf
= ImplAddSNum( pBuf
, nYear
, nYearLen
);
1203 case ExtDateFieldFormat::ShortMMDDYY
:
1204 case ExtDateFieldFormat::ShortMMDDYYYY
:
1206 pBuf
= ImplAddNum( pBuf
, nMonth
, 2 );
1207 pBuf
= ImplAddString( pBuf
, aDateSep
);
1208 pBuf
= ImplAddNum( pBuf
, nDay
, 2 );
1209 pBuf
= ImplAddString( pBuf
, aDateSep
);
1210 pBuf
= ImplAddSNum( pBuf
, nYear
, nYearLen
);
1213 case ExtDateFieldFormat::ShortYYMMDD
:
1214 case ExtDateFieldFormat::ShortYYYYMMDD
:
1215 case ExtDateFieldFormat::ShortYYMMDD_DIN5008
:
1216 case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
:
1218 pBuf
= ImplAddSNum( pBuf
, nYear
, nYearLen
);
1219 pBuf
= ImplAddString( pBuf
, aDateSep
);
1220 pBuf
= ImplAddNum( pBuf
, nMonth
, 2 );
1221 pBuf
= ImplAddString( pBuf
, aDateSep
);
1222 pBuf
= ImplAddNum( pBuf
, nDay
, 2 );
1227 OSL_FAIL( "DateFormat???" );
1231 return OUString(aBuf
, pBuf
-aBuf
);
1234 static void ImplDateIncrementDay( Date
& rDate
, bool bUp
)
1236 DateFormatter::ExpandCentury( rDate
);
1240 if ( (rDate
.GetDay() != 31) || (rDate
.GetMonth() != 12) || (rDate
.GetYear() != SAL_MAX_INT16
) )
1245 if ( (rDate
.GetDay() != 1 ) || (rDate
.GetMonth() != 1) || (rDate
.GetYear() != SAL_MIN_INT16
) )
1250 static void ImplDateIncrementMonth( Date
& rDate
, bool bUp
)
1252 DateFormatter::ExpandCentury( rDate
);
1254 sal_uInt16 nMonth
= rDate
.GetMonth();
1255 sal_Int16 nYear
= rDate
.GetYear();
1258 if ( (nMonth
== 12) && (nYear
< SAL_MAX_INT16
) )
1260 rDate
.SetMonth( 1 );
1261 rDate
.SetYear( rDate
.GetNextYear() );
1266 rDate
.SetMonth( nMonth
+ 1 );
1271 if ( (nMonth
== 1) && (nYear
> SAL_MIN_INT16
) )
1273 rDate
.SetMonth( 12 );
1274 rDate
.SetYear( rDate
.GetPrevYear() );
1279 rDate
.SetMonth( nMonth
- 1 );
1283 sal_uInt16 nDaysInMonth
= Date::GetDaysInMonth( rDate
.GetMonth(), rDate
.GetYear());
1284 if ( rDate
.GetDay() > nDaysInMonth
)
1285 rDate
.SetDay( nDaysInMonth
);
1288 static void ImplDateIncrementYear( Date
& rDate
, bool bUp
)
1290 DateFormatter::ExpandCentury( rDate
);
1292 sal_Int16 nYear
= rDate
.GetYear();
1293 sal_uInt16 nMonth
= rDate
.GetMonth();
1296 if ( nYear
< SAL_MAX_INT16
)
1297 rDate
.SetYear( rDate
.GetNextYear() );
1301 if ( nYear
> SAL_MIN_INT16
)
1302 rDate
.SetYear( rDate
.GetPrevYear() );
1306 // Handle February 29 from leap year to non-leap year.
1307 sal_uInt16 nDay
= rDate
.GetDay();
1310 // The check would not be necessary if it was guaranteed that the
1311 // date was valid before and actually was a leap year,
1312 // de-/incrementing a leap year with 29 always results in 28.
1313 sal_uInt16 nDaysInMonth
= Date::GetDaysInMonth( nMonth
, rDate
.GetYear());
1314 if (nDay
> nDaysInMonth
)
1315 rDate
.SetDay( nDaysInMonth
);
1320 bool DateFormatter::ImplAllowMalformedInput() const
1322 return !IsEnforceValidValue();
1325 void DateField::ImplDateSpinArea( bool bUp
)
1327 // increment days if all is selected
1330 Date
aDate( GetDate() );
1331 Selection aSelection
= GetField()->GetSelection();
1332 aSelection
.Justify();
1333 OUString
aText( GetText() );
1334 if ( (sal_Int32
)aSelection
.Len() == aText
.getLength() )
1335 ImplDateIncrementDay( aDate
, bUp
);
1338 sal_Int8 nDateArea
= 0;
1340 ExtDateFieldFormat eFormat
= GetExtDateFormat( true );
1341 if ( eFormat
== ExtDateFieldFormat::SystemLong
)
1343 eFormat
= ImplGetExtFormat( ImplGetLocaleDataWrapper().getLongDateFormat() );
1350 OUString aDateSep
= ImplGetDateSep( ImplGetLocaleDataWrapper(), eFormat
);
1351 for ( sal_Int8 i
= 1; i
<= 3; i
++ )
1353 nPos
= aText
.indexOf( aDateSep
, nPos
);
1354 if (nPos
< 0 || nPos
>= (sal_Int32
)aSelection
.Max())
1366 case ExtDateFieldFormat::ShortMMDDYY
:
1367 case ExtDateFieldFormat::ShortMMDDYYYY
:
1370 case 1: ImplDateIncrementMonth( aDate
, bUp
);
1372 case 2: ImplDateIncrementDay( aDate
, bUp
);
1374 case 3: ImplDateIncrementYear( aDate
, bUp
);
1378 case ExtDateFieldFormat::ShortDDMMYY
:
1379 case ExtDateFieldFormat::ShortDDMMYYYY
:
1382 case 1: ImplDateIncrementDay( aDate
, bUp
);
1384 case 2: ImplDateIncrementMonth( aDate
, bUp
);
1386 case 3: ImplDateIncrementYear( aDate
, bUp
);
1390 case ExtDateFieldFormat::ShortYYMMDD
:
1391 case ExtDateFieldFormat::ShortYYYYMMDD
:
1392 case ExtDateFieldFormat::ShortYYMMDD_DIN5008
:
1393 case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
:
1396 case 1: ImplDateIncrementYear( aDate
, bUp
);
1398 case 2: ImplDateIncrementMonth( aDate
, bUp
);
1400 case 3: ImplDateIncrementDay( aDate
, bUp
);
1405 OSL_FAIL( "invalid conversion" );
1410 ImplNewFieldValue( aDate
);
1414 void DateFormatter::ImplInit()
1416 mbLongFormat
= false;
1417 mbShowDateCentury
= true;
1418 mpCalendarWrapper
= nullptr;
1419 mnDateFormat
= 0xFFFF;
1420 mnExtDateFormat
= ExtDateFieldFormat::SystemShort
;
1423 DateFormatter::DateFormatter() :
1426 maMin( 1, 1, 1900 ),
1427 maMax( 31, 12, 2200 ),
1428 mbEnforceValidValue( true )
1433 DateFormatter::~DateFormatter()
1435 delete mpCalendarWrapper
;
1436 mpCalendarWrapper
= nullptr;
1439 void DateFormatter::SetLocale( const css::lang::Locale
& rLocale
)
1441 delete mpCalendarWrapper
;
1442 mpCalendarWrapper
= nullptr;
1443 FormatterBase::SetLocale( rLocale
);
1446 CalendarWrapper
& DateFormatter::GetCalendarWrapper() const
1448 if ( !mpCalendarWrapper
)
1450 const_cast<DateFormatter
*>(this)->mpCalendarWrapper
= new CalendarWrapper( comphelper::getProcessComponentContext() );
1451 mpCalendarWrapper
->loadDefaultCalendar( GetLocale() );
1454 return *mpCalendarWrapper
;
1457 void DateFormatter::SetExtDateFormat( ExtDateFieldFormat eFormat
)
1459 mnExtDateFormat
= eFormat
;
1463 ExtDateFieldFormat
DateFormatter::GetExtDateFormat( bool bResolveSystemFormat
) const
1465 ExtDateFieldFormat eDateFormat
= (ExtDateFieldFormat
)mnExtDateFormat
;
1467 if ( bResolveSystemFormat
&& ( eDateFormat
<= ExtDateFieldFormat::SystemShortYYYY
) )
1469 bool bShowCentury
= (eDateFormat
== ExtDateFieldFormat::SystemShortYYYY
);
1470 switch ( ImplGetLocaleDataWrapper().getDateFormat() )
1472 case DMY
: eDateFormat
= bShowCentury
? ExtDateFieldFormat::ShortDDMMYYYY
: ExtDateFieldFormat::ShortDDMMYY
;
1474 case MDY
: eDateFormat
= bShowCentury
? ExtDateFieldFormat::ShortMMDDYYYY
: ExtDateFieldFormat::ShortMMDDYY
;
1476 default: eDateFormat
= bShowCentury
? ExtDateFieldFormat::ShortYYYYMMDD
: ExtDateFieldFormat::ShortYYMMDD
;
1484 void DateFormatter::ReformatAll()
1489 void DateFormatter::SetMin( const Date
& rNewMin
)
1492 if ( !IsEmptyFieldValue() )
1496 void DateFormatter::SetMax( const Date
& rNewMax
)
1499 if ( !IsEmptyFieldValue() )
1503 void DateFormatter::SetLongFormat( bool bLong
)
1505 mbLongFormat
= bLong
;
1507 // #91913# Remove LongFormat and DateShowCentury - redundant
1510 SetExtDateFormat( ExtDateFieldFormat::SystemLong
);
1514 if( mnExtDateFormat
== ExtDateFieldFormat::SystemLong
)
1515 SetExtDateFormat( ExtDateFieldFormat::SystemShort
);
1521 void DateFormatter::SetShowDateCentury( bool bShowDateCentury
)
1523 mbShowDateCentury
= bShowDateCentury
;
1525 // #91913# Remove LongFormat and DateShowCentury - redundant
1526 if ( bShowDateCentury
)
1528 switch ( GetExtDateFormat() )
1530 case ExtDateFieldFormat::SystemShort
:
1531 case ExtDateFieldFormat::SystemShortYY
:
1532 SetExtDateFormat( ExtDateFieldFormat::SystemShortYYYY
); break;
1533 case ExtDateFieldFormat::ShortDDMMYY
:
1534 SetExtDateFormat( ExtDateFieldFormat::ShortDDMMYYYY
); break;
1535 case ExtDateFieldFormat::ShortMMDDYY
:
1536 SetExtDateFormat( ExtDateFieldFormat::ShortMMDDYYYY
); break;
1537 case ExtDateFieldFormat::ShortYYMMDD
:
1538 SetExtDateFormat( ExtDateFieldFormat::ShortYYYYMMDD
); break;
1539 case ExtDateFieldFormat::ShortYYMMDD_DIN5008
:
1540 SetExtDateFormat( ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
); break;
1547 switch ( GetExtDateFormat() )
1549 case ExtDateFieldFormat::SystemShort
:
1550 case ExtDateFieldFormat::SystemShortYYYY
:
1551 SetExtDateFormat( ExtDateFieldFormat::SystemShortYY
); break;
1552 case ExtDateFieldFormat::ShortDDMMYYYY
:
1553 SetExtDateFormat( ExtDateFieldFormat::ShortDDMMYY
); break;
1554 case ExtDateFieldFormat::ShortMMDDYYYY
:
1555 SetExtDateFormat( ExtDateFieldFormat::ShortMMDDYY
); break;
1556 case ExtDateFieldFormat::ShortYYYYMMDD
:
1557 SetExtDateFormat( ExtDateFieldFormat::ShortYYMMDD
); break;
1558 case ExtDateFieldFormat::ShortYYYYMMDD_DIN5008
:
1559 SetExtDateFormat( ExtDateFieldFormat::ShortYYMMDD_DIN5008
); break;
1568 void DateFormatter::SetDate( const Date
& rNewDate
)
1570 ImplSetUserDate( rNewDate
);
1571 maFieldDate
= maLastDate
;
1572 maLastDate
= GetDate();
1575 void DateFormatter::ImplSetUserDate( const Date
& rNewDate
, Selection
* pNewSelection
)
1577 Date aNewDate
= rNewDate
;
1578 if ( aNewDate
> maMax
)
1580 else if ( aNewDate
< maMin
)
1582 maLastDate
= aNewDate
;
1585 ImplSetText( ImplGetDateAsText( aNewDate
, GetFieldSettings() ), pNewSelection
);
1588 void DateFormatter::ImplNewFieldValue( const Date
& rDate
)
1592 Selection aSelection
= GetField()->GetSelection();
1593 aSelection
.Justify();
1594 OUString aText
= GetField()->GetText();
1596 // If selected until the end then keep it that way
1597 if ( (sal_Int32
)aSelection
.Max() == aText
.getLength() )
1599 if ( !aSelection
.Len() )
1600 aSelection
.Min() = SELECTION_MAX
;
1601 aSelection
.Max() = SELECTION_MAX
;
1604 Date aOldLastDate
= maLastDate
;
1605 ImplSetUserDate( rDate
, &aSelection
);
1606 maLastDate
= aOldLastDate
;
1608 // Modify at Edit is only set at KeyInput
1609 if ( GetField()->GetText() != aText
)
1611 GetField()->SetModifyFlag();
1612 GetField()->Modify();
1617 Date
DateFormatter::GetDate() const
1619 Date
aDate( Date::EMPTY
);
1623 if ( ImplDateGetValue( GetField()->GetText(), aDate
, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1625 if ( aDate
> maMax
)
1627 else if ( aDate
< maMin
)
1632 // !!! We should find out why dates are treated differently than other fields (see
1635 if ( !ImplAllowMalformedInput() )
1637 if ( maLastDate
.GetDate() )
1639 else if ( !IsEmptyFieldValueEnabled() )
1640 aDate
= Date( Date::SYSTEM
);
1643 aDate
= Date( Date::EMPTY
); // set invalid date
1650 void DateFormatter::SetEmptyDate()
1652 FormatterBase::SetEmptyFieldValue();
1655 bool DateFormatter::IsEmptyDate() const
1657 bool bEmpty
= FormatterBase::IsEmptyFieldValue();
1659 if ( GetField() && MustBeReformatted() && IsEmptyFieldValueEnabled() )
1661 if ( GetField()->GetText().isEmpty() )
1665 else if ( !maLastDate
.GetDate() )
1667 Date
aDate( Date::EMPTY
);
1668 bEmpty
= !ImplDateGetValue( GetField()->GetText(), aDate
, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() );
1674 void DateFormatter::Reformat()
1679 if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
1683 bool bOK
= ImplDateReformat( GetField()->GetText(), aStr
, GetFieldSettings() );
1687 if ( !aStr
.isEmpty() )
1689 ImplSetText( aStr
);
1690 ImplDateGetValue( aStr
, maLastDate
, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() );
1694 if ( maLastDate
.GetDate() )
1695 SetDate( maLastDate
);
1696 else if ( !IsEmptyFieldValueEnabled() )
1697 SetDate( Date( Date::SYSTEM
) );
1700 ImplSetText( OUString() );
1701 SetEmptyFieldValueData( true );
1706 void DateFormatter::ExpandCentury( Date
& rDate
)
1708 ExpandCentury( rDate
, utl::MiscCfg().GetYear2000() );
1711 void DateFormatter::ExpandCentury( Date
& rDate
, sal_uInt16 nTwoDigitYearStart
)
1713 sal_Int16 nDateYear
= rDate
.GetYear();
1714 if ( 0 <= nDateYear
&& nDateYear
< 100 )
1716 sal_uInt16 nCentury
= nTwoDigitYearStart
/ 100;
1717 if ( nDateYear
< (nTwoDigitYearStart
% 100) )
1719 rDate
.SetYear( nDateYear
+ (nCentury
*100) );
1723 DateField::DateField( vcl::Window
* pParent
, WinBits nWinStyle
) :
1724 SpinField( pParent
, nWinStyle
),
1725 maFirst( GetMin() ),
1729 SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
1734 void DateField::dispose()
1736 DateFormatter::SetField( nullptr );
1737 SpinField::dispose();
1740 bool DateField::PreNotify( NotifyEvent
& rNEvt
)
1742 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && IsStrictFormat() &&
1743 ( GetExtDateFormat() != ExtDateFieldFormat::SystemLong
) &&
1744 !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
1746 if ( ImplDateProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), GetExtDateFormat( true ), ImplGetLocaleDataWrapper() ) )
1750 return SpinField::PreNotify( rNEvt
);
1753 bool DateField::EventNotify( NotifyEvent
& rNEvt
)
1755 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
1756 MarkToBeReformatted( false );
1757 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
1759 if ( MustBeReformatted() )
1761 // !!! We should find out why dates are treated differently than other fields (see
1764 bool bTextLen
= !GetText().isEmpty();
1765 if ( bTextLen
|| !IsEmptyFieldValueEnabled() )
1767 if ( !ImplAllowMalformedInput() )
1771 Date
aDate( 0, 0, 0 );
1772 if ( ImplDateGetValue( GetText(), aDate
, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper(), GetFieldSettings() ) )
1773 // even with strict text analysis, our text is a valid date -> do a complete
1778 else if ( !bTextLen
&& IsEmptyFieldValueEnabled() )
1781 SetEmptyFieldValueData( true );
1786 return SpinField::EventNotify( rNEvt
);
1789 void DateField::DataChanged( const DataChangedEvent
& rDCEvt
)
1791 SpinField::DataChanged( rDCEvt
);
1793 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & (AllSettingsFlags::LOCALE
|AllSettingsFlags::MISC
)) )
1795 if ( IsDefaultLocale() && ( rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
1796 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
1801 void DateField::Modify()
1803 MarkToBeReformatted( true );
1804 SpinField::Modify();
1807 void DateField::Up()
1809 ImplDateSpinArea( true );
1813 void DateField::Down()
1815 ImplDateSpinArea( false );
1819 void DateField::First()
1821 ImplNewFieldValue( maFirst
);
1825 void DateField::Last()
1827 ImplNewFieldValue( maLast
);
1831 DateBox::DateBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
1832 ComboBox( pParent
, nWinStyle
)
1835 SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
1839 void DateBox::dispose()
1841 DateFormatter::SetField( nullptr );
1842 ComboBox::dispose();
1845 bool DateBox::PreNotify( NotifyEvent
& rNEvt
)
1847 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && IsStrictFormat() &&
1848 ( GetExtDateFormat() != ExtDateFieldFormat::SystemLong
) &&
1849 !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
1851 if ( ImplDateProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), GetExtDateFormat( true ), ImplGetLocaleDataWrapper() ) )
1855 return ComboBox::PreNotify( rNEvt
);
1858 void DateBox::DataChanged( const DataChangedEvent
& rDCEvt
)
1860 ComboBox::DataChanged( rDCEvt
);
1862 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
1864 if ( IsDefaultLocale() )
1865 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
1870 bool DateBox::EventNotify( NotifyEvent
& rNEvt
)
1872 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
1873 MarkToBeReformatted( false );
1874 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
1876 if ( MustBeReformatted() )
1878 bool bTextLen
= !GetText().isEmpty();
1879 if ( bTextLen
|| !IsEmptyFieldValueEnabled() )
1881 else if ( !bTextLen
&& IsEmptyFieldValueEnabled() )
1884 SetEmptyFieldValueData( true );
1889 return ComboBox::EventNotify( rNEvt
);
1892 void DateBox::Modify()
1894 MarkToBeReformatted( true );
1898 void DateBox::ReformatAll()
1901 SetUpdateMode( false );
1902 const sal_Int32 nEntryCount
= GetEntryCount();
1903 for ( sal_Int32 i
=0; i
< nEntryCount
; ++i
)
1905 ImplDateReformat( GetEntry( i
), aStr
, GetFieldSettings() );
1907 InsertEntry( aStr
, i
);
1909 DateFormatter::Reformat();
1910 SetUpdateMode( true );
1913 static bool ImplTimeProcessKeyInput( Edit
*, const KeyEvent
& rKEvt
,
1914 bool bStrictFormat
, bool bDuration
,
1915 TimeFieldFormat eFormat
,
1916 const LocaleDataWrapper
& rLocaleDataWrapper
)
1918 sal_Unicode cChar
= rKEvt
.GetCharCode();
1920 if ( !bStrictFormat
)
1924 sal_uInt16 nGroup
= rKEvt
.GetKeyCode().GetGroup();
1925 if ( (nGroup
== KEYGROUP_FKEYS
) || (nGroup
== KEYGROUP_CURSOR
) ||
1926 (nGroup
== KEYGROUP_MISC
) ||
1927 ((cChar
>= '0') && (cChar
<= '9')) ||
1928 string::equals(rLocaleDataWrapper
.getTimeSep(), cChar
) ||
1929 (rLocaleDataWrapper
.getTimeAM().indexOf(cChar
) != -1) ||
1930 (rLocaleDataWrapper
.getTimePM().indexOf(cChar
) != -1) ||
1932 (cChar
== 'a') || (cChar
== 'A') || (cChar
== 'm') || (cChar
== 'M') || (cChar
== 'p') || (cChar
== 'P') ||
1933 ((eFormat
== TimeFieldFormat::F_100TH_SEC
) && string::equals(rLocaleDataWrapper
.getTime100SecSep(), cChar
)) ||
1934 ((eFormat
== TimeFieldFormat::F_SEC_CS
) && string::equals(rLocaleDataWrapper
.getTime100SecSep(), cChar
)) ||
1935 (bDuration
&& (cChar
== '-')) )
1942 static bool ImplIsOnlyDigits( const OUStringBuffer
& _rStr
)
1944 const sal_Unicode
* _pChr
= _rStr
.getStr();
1945 for ( sal_Int32 i
= 0; i
< _rStr
.getLength(); ++i
, ++_pChr
)
1947 if ( *_pChr
< '0' || *_pChr
> '9' )
1953 static bool ImplIsValidTimePortion( bool _bSkipInvalidCharacters
, const OUStringBuffer
& _rStr
)
1955 if ( !_bSkipInvalidCharacters
)
1957 if ( ( _rStr
.getLength() > 2 ) || _rStr
.isEmpty() || !ImplIsOnlyDigits( _rStr
) )
1963 static bool ImplCutTimePortion( OUStringBuffer
& _rStr
, sal_Int32 _nSepPos
, bool _bSkipInvalidCharacters
, short* _pPortion
)
1965 OUString
sPortion(_rStr
.getStr(), _nSepPos
);
1966 _rStr
= _nSepPos
< _rStr
.getLength()
1967 ? _rStr
.copy( _nSepPos
+ 1 ) : OUStringBuffer();
1969 if ( !ImplIsValidTimePortion( _bSkipInvalidCharacters
, sPortion
) )
1971 *_pPortion
= (short)sPortion
.toInt32();
1975 static bool ImplTimeGetValue( const OUString
& rStr
, tools::Time
& rTime
,
1976 TimeFieldFormat eFormat
, bool bDuration
,
1977 const LocaleDataWrapper
& rLocaleDataWrapper
, bool _bSkipInvalidCharacters
= true )
1979 OUStringBuffer aStr
= rStr
;
1983 sal_Int64 nNanoSec
= 0;
1984 tools::Time
aTime( 0, 0, 0 );
1986 if ( rStr
.isEmpty() )
1989 // Search for separators
1990 if (!rLocaleDataWrapper
.getTimeSep().isEmpty())
1992 OUStringBuffer
aSepStr(",.;:/");
1994 aSepStr
.append('-');
1996 // Replace characters above by the separator character
1997 for (sal_Int32 i
= 0; i
< aSepStr
.getLength(); ++i
)
1999 if (string::equals(rLocaleDataWrapper
.getTimeSep(), aSepStr
[i
]))
2001 for ( sal_Int32 j
= 0; j
< aStr
.getLength(); j
++ )
2003 if (aStr
[j
] == aSepStr
[i
])
2004 aStr
[j
] = rLocaleDataWrapper
.getTimeSep()[0];
2009 bool bNegative
= false;
2010 sal_Int32 nSepPos
= aStr
.indexOf( rLocaleDataWrapper
.getTimeSep() );
2011 if ( aStr
[0] == '-' )
2013 if ( eFormat
!= TimeFieldFormat::F_SEC_CS
)
2016 nSepPos
= aStr
.getLength();
2017 if ( !ImplCutTimePortion( aStr
, nSepPos
, _bSkipInvalidCharacters
, &nHour
) )
2020 nSepPos
= aStr
.indexOf( rLocaleDataWrapper
.getTimeSep() );
2021 if ( !aStr
.isEmpty() && aStr
[0] == '-' )
2025 if ( !ImplCutTimePortion( aStr
, nSepPos
, _bSkipInvalidCharacters
, &nMinute
) )
2028 nSepPos
= aStr
.indexOf( rLocaleDataWrapper
.getTimeSep() );
2029 if ( !aStr
.isEmpty() && aStr
[0] == '-' )
2033 if ( !ImplCutTimePortion( aStr
, nSepPos
, _bSkipInvalidCharacters
, &nSecond
) )
2035 if ( !aStr
.isEmpty() && aStr
[0] == '-' )
2037 nNanoSec
= aStr
.toString().toInt64();
2040 nSecond
= (short)aStr
.toString().toInt32();
2043 nMinute
= (short)aStr
.toString().toInt32();
2045 else if ( nSepPos
< 0 )
2047 nSecond
= (short)aStr
.toString().toInt32();
2048 nMinute
+= nSecond
/ 60;
2050 nHour
+= nMinute
/ 60;
2055 nSecond
= (short)aStr
.copy( 0, nSepPos
).toString().toInt32();
2056 aStr
.remove( 0, nSepPos
+1 );
2058 nSepPos
= aStr
.indexOf( rLocaleDataWrapper
.getTimeSep() );
2059 if ( !aStr
.isEmpty() && aStr
[0] == '-' )
2064 nSecond
= (short)aStr
.copy( 0, nSepPos
).toString().toInt32();
2065 aStr
.remove( 0, nSepPos
+1 );
2067 nSepPos
= aStr
.indexOf( rLocaleDataWrapper
.getTimeSep() );
2068 if ( !aStr
.isEmpty() && aStr
[0] == '-' )
2074 nSecond
= (short)aStr
.copy( 0, nSepPos
).toString().toInt32();
2075 aStr
.remove( 0, nSepPos
+1 );
2079 nHour
+= nMinute
/ 60;
2085 nMinute
+= nSecond
/ 60;
2087 nHour
+= nMinute
/ 60;
2090 nNanoSec
= aStr
.toString().toInt64();
2095 assert(aStr
.getLength() >= 1);
2097 sal_Int32 nLen
= 1; // at least one digit, otherwise nNanoSec==0
2099 while ( aStr
.getLength() > nLen
&& aStr
[nLen
] >= '0' && aStr
[nLen
] <= '9' )
2109 // round if negative?
2110 nNanoSec
= (nNanoSec
+ 5) / 10;
2115 assert(nNanoSec
> -1000000000 && nNanoSec
< 1000000000);
2116 if ( (nMinute
> 59) || (nSecond
> 59) || (nNanoSec
> 1000000000) )
2119 if ( eFormat
== TimeFieldFormat::F_NONE
)
2120 nSecond
= nNanoSec
= 0;
2121 else if ( eFormat
== TimeFieldFormat::F_SEC
)
2126 if ( bNegative
|| (nHour
< 0) || (nMinute
< 0) ||
2127 (nSecond
< 0) || (nNanoSec
< 0) )
2130 OUString aUpperCaseStr
= aStr
.toString().toAsciiUpperCase();
2131 OUString
aAMlocalised(rLocaleDataWrapper
.getTimeAM().toAsciiUpperCase());
2132 OUString
aPMlocalised(rLocaleDataWrapper
.getTimePM().toAsciiUpperCase());
2134 if ( (nHour
< 12) && ( ( aUpperCaseStr
.indexOf( "PM" ) >= 0 ) || ( aUpperCaseStr
.indexOf( aPMlocalised
) >= 0 ) ) )
2137 if ( (nHour
== 12) && ( ( aUpperCaseStr
.indexOf( "AM" ) >= 0 ) || ( aUpperCaseStr
.indexOf( aAMlocalised
) >= 0 ) ) )
2140 aTime
= tools::Time( (sal_uInt16
)nHour
, (sal_uInt16
)nMinute
, (sal_uInt16
)nSecond
,
2141 (sal_uInt32
)nNanoSec
);
2145 assert( !bNegative
|| (nHour
< 0) || (nMinute
< 0) ||
2146 (nSecond
< 0) || (nNanoSec
< 0) );
2147 if ( bNegative
|| (nHour
< 0) || (nMinute
< 0) ||
2148 (nSecond
< 0) || (nNanoSec
< 0) )
2150 // LEM TODO: this looks weird... I think buggy when parsing "05:-02:18"
2152 nHour
= nHour
< 0 ? -nHour
: nHour
;
2153 nMinute
= nMinute
< 0 ? -nMinute
: nMinute
;
2154 nSecond
= nSecond
< 0 ? -nSecond
: nSecond
;
2155 nNanoSec
= nNanoSec
< 0 ? -nNanoSec
: nNanoSec
;
2158 aTime
= tools::Time( (sal_uInt16
)nHour
, (sal_uInt16
)nMinute
, (sal_uInt16
)nSecond
,
2159 (sal_uInt32
)nNanoSec
);
2169 bool TimeFormatter::ImplTimeReformat( const OUString
& rStr
, OUString
& rOutStr
)
2171 tools::Time
aTime( 0, 0, 0 );
2172 if ( !ImplTimeGetValue( rStr
, aTime
, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() ) )
2175 tools::Time aTempTime
= aTime
;
2176 if ( aTempTime
> GetMax() )
2177 aTempTime
= GetMax() ;
2178 else if ( aTempTime
< GetMin() )
2179 aTempTime
= GetMin();
2181 bool bSecond
= false;
2182 bool b100Sec
= false;
2183 if ( meFormat
!= TimeFieldFormat::F_NONE
)
2185 if ( meFormat
== TimeFieldFormat::F_100TH_SEC
)
2188 if ( meFormat
== TimeFieldFormat::F_SEC_CS
)
2190 sal_uLong n
= aTempTime
.GetHour() * 3600L;
2191 n
+= aTempTime
.GetMin() * 60L;
2192 n
+= aTempTime
.GetSec();
2193 rOutStr
= OUString::number( n
);
2194 rOutStr
+= ImplGetLocaleDataWrapper().getTime100SecSep();
2195 std::ostringstream ostr
;
2198 ostr
<< aTempTime
.GetNanoSec();
2199 rOutStr
+= OUString::createFromAscii(ostr
.str().c_str());
2201 else if ( mbDuration
)
2202 rOutStr
= ImplGetLocaleDataWrapper().getDuration( aTempTime
, bSecond
, b100Sec
);
2205 rOutStr
= ImplGetLocaleDataWrapper().getTime( aTempTime
, bSecond
, b100Sec
);
2206 if ( GetTimeFormat() == TimeFormat::Hour12
)
2208 if ( aTempTime
.GetHour() > 12 )
2210 tools::Time
aT( aTempTime
);
2211 aT
.SetHour( aT
.GetHour() % 12 );
2212 rOutStr
= ImplGetLocaleDataWrapper().getTime( aT
, bSecond
, b100Sec
);
2214 // Don't use LocaleDataWrapper, we want AM/PM
2215 if ( aTempTime
.GetHour() < 12 )
2216 rOutStr
+= "AM"; // ImplGetLocaleDataWrapper().getTimeAM();
2218 rOutStr
+= "PM"; // ImplGetLocaleDataWrapper().getTimePM();
2224 bool TimeFormatter::ImplAllowMalformedInput() const
2226 return !IsEnforceValidValue();
2229 void TimeField::ImplTimeSpinArea( bool bUp
)
2233 sal_Int32 nTimeArea
= 0;
2234 tools::Time
aTime( GetTime() );
2235 OUString
aText( GetText() );
2236 Selection
aSelection( GetField()->GetSelection() );
2239 if ( GetFormat() != TimeFieldFormat::F_SEC_CS
)
2241 //Which area is the cursor in of HH:MM:SS.TT
2242 for ( sal_Int32 i
= 1, nPos
= 0; i
<= 4; i
++ )
2244 sal_Int32 nPos1
= aText
.indexOf( ImplGetLocaleDataWrapper().getTimeSep(), nPos
);
2245 sal_Int32 nPos2
= aText
.indexOf( ImplGetLocaleDataWrapper().getTime100SecSep(), nPos
);
2246 //which ever comes first, bearing in mind that one might not be there
2247 if (nPos1
>= 0 && nPos2
>= 0)
2248 nPos
= nPos1
< nPos2
? nPos1
: nPos2
;
2249 else if (nPos1
>= 0)
2253 if ( nPos
< 0 || nPos
>= aSelection
.Max() )
2264 sal_Int32 nPos
= aText
.indexOf( ImplGetLocaleDataWrapper().getTime100SecSep() );
2265 if ( nPos
< 0 || nPos
>= aSelection
.Max() )
2273 tools::Time
aAddTime( 0, 0, 0 );
2274 if ( nTimeArea
== 1 )
2275 aAddTime
= tools::Time( 1, 0 );
2276 else if ( nTimeArea
== 2 )
2277 aAddTime
= tools::Time( 0, 1 );
2278 else if ( nTimeArea
== 3 )
2279 aAddTime
= tools::Time( 0, 0, 1 );
2280 else if ( nTimeArea
== 4 )
2281 aAddTime
= tools::Time( 0, 0, 0, 1 );
2284 aAddTime
= -aAddTime
;
2287 if ( !IsDuration() )
2289 tools::Time
aAbsMaxTime( 23, 59, 59, 999999999 );
2290 if ( aTime
> aAbsMaxTime
)
2291 aTime
= aAbsMaxTime
;
2292 tools::Time
aAbsMinTime( 0, 0 );
2293 if ( aTime
< aAbsMinTime
)
2294 aTime
= aAbsMinTime
;
2296 ImplNewFieldValue( aTime
);
2302 void TimeFormatter::ImplInit()
2304 meFormat
= TimeFieldFormat::F_NONE
;
2306 mnTimeFormat
= TimeFormat::Hour24
; // Should become a ExtTimeFieldFormat in next implementation, merge with mbDuration and meFormat
2309 TimeFormatter::TimeFormatter() :
2312 maMax( 23, 59, 59, 999999999 ),
2313 mbEnforceValidValue( true ),
2319 TimeFormatter::~TimeFormatter()
2323 void TimeFormatter::ReformatAll()
2328 void TimeFormatter::SetMin( const tools::Time
& rNewMin
)
2331 if ( !IsEmptyFieldValue() )
2335 void TimeFormatter::SetMax( const tools::Time
& rNewMax
)
2338 if ( !IsEmptyFieldValue() )
2342 void TimeFormatter::SetTimeFormat( TimeFormatter::TimeFormat eNewFormat
)
2344 mnTimeFormat
= eNewFormat
;
2348 void TimeFormatter::SetFormat( TimeFieldFormat eNewFormat
)
2350 meFormat
= eNewFormat
;
2354 void TimeFormatter::SetDuration( bool bNewDuration
)
2356 mbDuration
= bNewDuration
;
2360 void TimeFormatter::SetTime( const tools::Time
& rNewTime
)
2362 SetUserTime( rNewTime
);
2363 maFieldTime
= maLastTime
;
2364 SetEmptyFieldValueData( false );
2367 void TimeFormatter::ImplNewFieldValue( const tools::Time
& rTime
)
2371 Selection aSelection
= GetField()->GetSelection();
2372 aSelection
.Justify();
2373 OUString aText
= GetField()->GetText();
2375 // If selected until the end then keep it that way
2376 if ( (sal_Int32
)aSelection
.Max() == aText
.getLength() )
2378 if ( !aSelection
.Len() )
2379 aSelection
.Min() = SELECTION_MAX
;
2380 aSelection
.Max() = SELECTION_MAX
;
2383 tools::Time aOldLastTime
= maLastTime
;
2384 ImplSetUserTime( rTime
, &aSelection
);
2385 maLastTime
= aOldLastTime
;
2387 // Modify at Edit is only set at KeyInput
2388 if ( GetField()->GetText() != aText
)
2390 GetField()->SetModifyFlag();
2391 GetField()->Modify();
2396 void TimeFormatter::ImplSetUserTime( const tools::Time
& rNewTime
, Selection
* pNewSelection
)
2398 tools::Time aNewTime
= rNewTime
;
2399 if ( aNewTime
> GetMax() )
2400 aNewTime
= GetMax();
2401 else if ( aNewTime
< GetMin() )
2402 aNewTime
= GetMin();
2403 maLastTime
= aNewTime
;
2409 bool b100Sec
= false;
2410 if ( meFormat
!= TimeFieldFormat::F_NONE
)
2412 if ( meFormat
== TimeFieldFormat::F_100TH_SEC
|| meFormat
== TimeFieldFormat::F_SEC_CS
)
2414 if ( meFormat
== TimeFieldFormat::F_SEC_CS
)
2416 sal_uLong n
= aNewTime
.GetHour() * 3600L;
2417 n
+= aNewTime
.GetMin() * 60L;
2418 n
+= aNewTime
.GetSec();
2419 aStr
= OUString::number( n
);
2420 aStr
+= ImplGetLocaleDataWrapper().getTime100SecSep();
2421 std::ostringstream ostr
;
2424 ostr
<< aNewTime
.GetNanoSec();
2425 aStr
+= OUString::createFromAscii(ostr
.str().c_str());
2427 else if ( mbDuration
)
2429 aStr
= ImplGetLocaleDataWrapper().getDuration( aNewTime
, bSec
, b100Sec
);
2433 aStr
= ImplGetLocaleDataWrapper().getTime( aNewTime
, bSec
, b100Sec
);
2434 if ( GetTimeFormat() == TimeFormat::Hour12
)
2436 if ( aNewTime
.GetHour() > 12 )
2438 tools::Time
aT( aNewTime
);
2439 aT
.SetHour( aT
.GetHour() % 12 );
2440 aStr
= ImplGetLocaleDataWrapper().getTime( aT
, bSec
, b100Sec
);
2442 // Don't use LocaleDataWrapper, we want AM/PM
2443 if ( aNewTime
.GetHour() < 12 )
2444 aStr
+= "AM"; // ImplGetLocaleDataWrapper().getTimeAM();
2446 aStr
+= "PM"; // ImplGetLocaleDataWrapper().getTimePM();
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 ( ImplTimeGetValue( 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 bool bOK
= ImplTimeReformat( GetField()->GetText(), aStr
);
2498 if ( !aStr
.isEmpty() )
2500 ImplSetText( aStr
);
2501 ImplTimeGetValue( aStr
, maLastTime
, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() );
2504 SetTime( maLastTime
);
2507 TimeField::TimeField( vcl::Window
* pParent
, WinBits nWinStyle
) :
2508 SpinField( pParent
, nWinStyle
),
2509 maFirst( GetMin() ),
2513 SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime
, false ) );
2517 void TimeField::dispose()
2519 TimeFormatter::SetField( nullptr );
2520 SpinField::dispose();
2523 bool TimeField::PreNotify( NotifyEvent
& rNEvt
)
2525 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
2527 if ( ImplTimeProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
2531 return SpinField::PreNotify( rNEvt
);
2534 bool TimeField::EventNotify( NotifyEvent
& rNEvt
)
2536 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
2537 MarkToBeReformatted( false );
2538 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
2540 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
2542 if ( !ImplAllowMalformedInput() )
2546 tools::Time
aTime( 0, 0, 0 );
2547 if ( ImplTimeGetValue( GetText(), aTime
, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), false ) )
2548 // even with strict text analysis, our text is a valid time -> do a complete
2555 return SpinField::EventNotify( rNEvt
);
2558 void TimeField::DataChanged( const DataChangedEvent
& rDCEvt
)
2560 SpinField::DataChanged( rDCEvt
);
2562 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
2564 if ( IsDefaultLocale() )
2565 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
2570 void TimeField::Modify()
2572 MarkToBeReformatted( true );
2573 SpinField::Modify();
2576 void TimeField::Up()
2578 ImplTimeSpinArea( true );
2582 void TimeField::Down()
2584 ImplTimeSpinArea( false );
2588 void TimeField::First()
2590 ImplNewFieldValue( maFirst
);
2594 void TimeField::Last()
2596 ImplNewFieldValue( maLast
);
2600 void TimeField::SetExtFormat( ExtTimeFieldFormat eFormat
)
2604 case ExtTimeFieldFormat::Short24H
:
2606 SetTimeFormat( TimeFormat::Hour24
);
2607 SetDuration( false );
2608 SetFormat( TimeFieldFormat::F_NONE
);
2611 case ExtTimeFieldFormat::Long24H
:
2613 SetTimeFormat( TimeFormat::Hour24
);
2614 SetDuration( false );
2615 SetFormat( TimeFieldFormat::F_SEC
);
2618 case ExtTimeFieldFormat::Short12H
:
2620 SetTimeFormat( TimeFormat::Hour12
);
2621 SetDuration( false );
2622 SetFormat( TimeFieldFormat::F_NONE
);
2625 case ExtTimeFieldFormat::Long12H
:
2627 SetTimeFormat( TimeFormat::Hour12
);
2628 SetDuration( false );
2629 SetFormat( TimeFieldFormat::F_SEC
);
2632 case ExtTimeFieldFormat::ShortDuration
:
2634 SetDuration( true );
2635 SetFormat( TimeFieldFormat::F_NONE
);
2638 case ExtTimeFieldFormat::LongDuration
:
2640 SetDuration( true );
2641 SetFormat( TimeFieldFormat::F_SEC
);
2644 default: OSL_FAIL( "ExtTimeFieldFormat unknown!" );
2647 if ( GetField() && !GetField()->GetText().isEmpty() )
2648 SetUserTime( GetTime() );
2652 TimeBox::TimeBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
2653 ComboBox( pParent
, nWinStyle
)
2656 SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime
, false ) );
2660 void TimeBox::dispose()
2662 TimeFormatter::SetField( nullptr );
2663 ComboBox::dispose();
2666 bool TimeBox::PreNotify( NotifyEvent
& rNEvt
)
2668 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
2670 if ( ImplTimeProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
2674 return ComboBox::PreNotify( rNEvt
);
2677 bool TimeBox::EventNotify( NotifyEvent
& rNEvt
)
2679 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
2680 MarkToBeReformatted( false );
2681 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
2683 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
2687 return ComboBox::EventNotify( rNEvt
);
2690 void TimeBox::DataChanged( const DataChangedEvent
& rDCEvt
)
2692 ComboBox::DataChanged( rDCEvt
);
2694 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
2696 if ( IsDefaultLocale() )
2697 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
2702 void TimeBox::Modify()
2704 MarkToBeReformatted( true );
2708 void TimeBox::ReformatAll()
2711 SetUpdateMode( false );
2712 const sal_Int32 nEntryCount
= GetEntryCount();
2713 for ( sal_Int32 i
=0; i
< nEntryCount
; ++i
)
2715 ImplTimeReformat( GetEntry( i
), aStr
);
2717 InsertEntry( aStr
, i
);
2719 TimeFormatter::Reformat();
2720 SetUpdateMode( true );
2723 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */