LibreOffice Module vcl (master) 1
field2.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <algorithm>
23#include <string_view>
24
27#include <comphelper/string.hxx>
28#include <o3tl/string_view.hxx>
29#include <officecfg/Office/Common.hxx>
30#include <vcl/svapp.hxx>
31#include <vcl/event.hxx>
32#include <vcl/toolkit/field.hxx>
33#include <vcl/unohelp.hxx>
34#include <vcl/settings.hxx>
35#include <vcl/weldutils.hxx>
36
37#include <svdata.hxx>
38
39#include <com/sun/star/i18n/XCharacterClassification.hpp>
40#include <com/sun/star/i18n/CalendarFieldIndex.hdl>
41
45#include <svl/numformat.hxx>
46#include <svl/zforlist.hxx>
47
48using namespace ::com::sun::star;
49using namespace ::comphelper;
50
51#define EDITMASK_LITERAL 'L'
52#define EDITMASK_ALPHA 'a'
53#define EDITMASK_UPPERALPHA 'A'
54#define EDITMASK_ALPHANUM 'c'
55#define EDITMASK_UPPERALPHANUM 'C'
56#define EDITMASK_NUM 'N'
57#define EDITMASK_NUMSPACE 'n'
58#define EDITMASK_ALLCHAR 'x'
59#define EDITMASK_UPPERALLCHAR 'X'
60
61uno::Reference< i18n::XCharacterClassification > const & ImplGetCharClass()
62{
63 ImplSVData *const pSVData = ImplGetSVData();
64 assert(pSVData);
65
66 if (!pSVData->m_xCharClass.is())
67 {
69 }
70
71 return pSVData->m_xCharClass;
72}
73
74static sal_Unicode* ImplAddString( sal_Unicode* pBuf, const OUString& rStr )
75{
76 memcpy( pBuf, rStr.getStr(), rStr.getLength() * sizeof(sal_Unicode) );
77 pBuf += rStr.getLength();
78 return pBuf;
79}
80
81static sal_Unicode* ImplAddNum( sal_Unicode* pBuf, sal_uLong nNumber, int nMinLen )
82{
83 // fill temp buffer with digits
84 sal_Unicode aTempBuf[30];
85 sal_Unicode* pTempBuf = aTempBuf;
86 do
87 {
88 *pTempBuf = static_cast<sal_Unicode>(nNumber % 10) + '0';
89 pTempBuf++;
90 nNumber /= 10;
91 if ( nMinLen )
92 nMinLen--;
93 }
94 while ( nNumber );
95
96 // fill with zeros up to the minimal length
97 while ( nMinLen > 0 )
98 {
99 *pBuf = '0';
100 pBuf++;
101 nMinLen--;
102 }
103
104 // copy temp buffer to real buffer
105 do
106 {
107 pTempBuf--;
108 *pBuf = *pTempBuf;
109 pBuf++;
110 }
111 while ( pTempBuf != aTempBuf );
112
113 return pBuf;
114}
115
116static sal_Unicode* ImplAddSNum( sal_Unicode* pBuf, sal_Int32 nNumber, int nMinLen )
117{
118 if (nNumber < 0)
119 {
120 *pBuf++ = '-';
121 nNumber = -nNumber;
122 }
123 return ImplAddNum( pBuf, nNumber, nMinLen);
124}
125
126static sal_uInt16 ImplGetNum( const sal_Unicode*& rpBuf, bool& rbError )
127{
128 if ( !*rpBuf )
129 {
130 rbError = true;
131 return 0;
132 }
133
134 sal_uInt16 nNumber = 0;
135 while( ( *rpBuf >= '0' ) && ( *rpBuf <= '9' ) )
136 {
137 nNumber *= 10;
138 nNumber += *rpBuf - '0';
139 rpBuf++;
140 }
141
142 return nNumber;
143}
144
145static void ImplSkipDelimiters( const sal_Unicode*& rpBuf )
146{
147 while( ( *rpBuf == ',' ) || ( *rpBuf == '.' ) || ( *rpBuf == ';' ) ||
148 ( *rpBuf == ':' ) || ( *rpBuf == '-' ) || ( *rpBuf == '/' ) )
149 {
150 rpBuf++;
151 }
152}
153
154static bool ImplIsPatternChar( sal_Unicode cChar, char cEditMask )
155{
156 sal_Int32 nType = 0;
157
158 try
159 {
160 OUString aCharStr(cChar);
161 nType = ImplGetCharClass()->getCharacterType( aCharStr, 0,
162 Application::GetSettings().GetLanguageTag().getLocale() );
163 }
164 catch (const css::uno::Exception&)
165 {
166 DBG_UNHANDLED_EXCEPTION("vcl.control");
167 return false;
168 }
169
170 if ( (cEditMask == EDITMASK_ALPHA) || (cEditMask == EDITMASK_UPPERALPHA) )
171 {
173 return false;
174 }
175 else if ( cEditMask == EDITMASK_NUM )
176 {
178 return false;
179 }
180 else if ( (cEditMask == EDITMASK_ALPHANUM) || (cEditMask == EDITMASK_UPPERALPHANUM) )
181 {
183 return false;
184 }
185 else if ( (cEditMask == EDITMASK_ALLCHAR) || (cEditMask == EDITMASK_UPPERALLCHAR) )
186 {
187 if ( cChar < 32 )
188 return false;
189 }
190 else if ( cEditMask == EDITMASK_NUMSPACE )
191 {
192 if ( !CharClass::isNumericType( nType ) && ( cChar != ' ' ) )
193 return false;
194 }
195 else
196 return false;
197
198 return true;
199}
200
201static sal_Unicode ImplPatternChar( sal_Unicode cChar, char cEditMask )
202{
203 if ( ImplIsPatternChar( cChar, cEditMask ) )
204 {
205 if ( (cEditMask == EDITMASK_UPPERALPHA) ||
206 (cEditMask == EDITMASK_UPPERALPHANUM) ||
207 ( cEditMask == EDITMASK_UPPERALLCHAR ) )
208 {
209 cChar = ImplGetCharClass()->toUpper(OUString(cChar), 0, 1,
210 Application::GetSettings().GetLanguageTag().getLocale())[0];
211 }
212 return cChar;
213 }
214 else
215 return 0;
216}
217
219{
220 if ( c1 == c2 )
221 return true;
222 else if ( ((c1 == '.') || (c1 == ',')) &&
223 ((c2 == '.') || (c2 == ',')) )
224 return true;
225 else
226 return false;
227}
228
229static OUString ImplPatternReformat( const OUString& rStr,
230 const OString& rEditMask,
231 std::u16string_view rLiteralMask,
232 sal_uInt16 nFormatFlags )
233{
234 if (rEditMask.isEmpty())
235 return rStr;
236
237 OUStringBuffer aOutStr(rLiteralMask);
238 sal_Unicode cTempChar;
239 sal_Unicode cChar;
240 sal_Unicode cLiteral;
241 char cMask;
242 sal_Int32 nStrIndex = 0;
243 sal_Int32 i = 0;
244 sal_Int32 n;
245
246 while ( i < rEditMask.getLength() )
247 {
248 if ( nStrIndex >= rStr.getLength() )
249 break;
250
251 cChar = rStr[nStrIndex];
252 cLiteral = rLiteralMask[i];
253 cMask = rEditMask[i];
254
255 // current position is a literal
256 if ( cMask == EDITMASK_LITERAL )
257 {
258 // if it is a literal copy otherwise ignore because it might be the next valid
259 // character of the string
260 if ( ImplCommaPointCharEqual( cChar, cLiteral ) )
261 nStrIndex++;
262 else
263 {
264 // Otherwise we check if it is an invalid character. This is the case if it does not
265 // fit in the pattern of the next non-literal character.
266 n = i+1;
267 while ( n < rEditMask.getLength() )
268 {
269 if ( rEditMask[n] != EDITMASK_LITERAL )
270 {
271 if ( !ImplIsPatternChar( cChar, rEditMask[n] ) )
272 nStrIndex++;
273 break;
274 }
275
276 n++;
277 }
278 }
279 }
280 else
281 {
282 // valid character at this position
283 cTempChar = ImplPatternChar( cChar, cMask );
284 if ( cTempChar )
285 {
286 // use this character
287 aOutStr[i] = cTempChar;
288 nStrIndex++;
289 }
290 else
291 {
292 // copy if it is a literal character
293 if ( cLiteral == cChar )
294 nStrIndex++;
295 else
296 {
297 // If the invalid character might be the next literal character then we jump
298 // ahead to it, otherwise we ignore it. Do only if empty literals are allowed.
299 if ( nFormatFlags & PATTERN_FORMAT_EMPTYLITERALS )
300 {
301 n = i;
302 while ( n < rEditMask.getLength() )
303 {
304 if ( rEditMask[n] == EDITMASK_LITERAL )
305 {
306 if ( ImplCommaPointCharEqual( cChar, rLiteralMask[n] ) )
307 i = n+1;
308
309 break;
310 }
311
312 n++;
313 }
314 }
315
316 nStrIndex++;
317 continue;
318 }
319 }
320 }
321
322 i++;
323 }
324
325 return aOutStr.makeStringAndClear();
326}
327
328static void ImplPatternMaxPos( std::u16string_view rStr, const OString& rEditMask,
329 sal_uInt16 nFormatFlags, bool bSameMask,
330 sal_Int32 nCursorPos, sal_Int32& rPos )
331{
332
333 // last position must not be longer than the contained string
334 sal_Int32 nMaxPos = rStr.size();
335
336 // if non empty literals are allowed ignore blanks at the end as well
337 if ( bSameMask && !(nFormatFlags & PATTERN_FORMAT_EMPTYLITERALS) )
338 {
339 while ( nMaxPos )
340 {
341 if ( (rEditMask[nMaxPos-1] != EDITMASK_LITERAL) &&
342 (rStr[nMaxPos-1] != ' ') )
343 break;
344 nMaxPos--;
345 }
346
347 // if we are in front of a literal, continue search until first character after the literal
348 sal_Int32 nTempPos = nMaxPos;
349 while ( nTempPos < rEditMask.getLength() )
350 {
351 if ( rEditMask[nTempPos] != EDITMASK_LITERAL )
352 {
353 nMaxPos = nTempPos;
354 break;
355 }
356 nTempPos++;
357 }
358 }
359
360 if ( rPos > nMaxPos )
361 rPos = nMaxPos;
362
363 // character should not move left
364 if ( rPos < nCursorPos )
365 rPos = nCursorPos;
366}
367
368static OUString ImplPatternProcessStrictModify(const OUString& rText,
369 const OString& rEditMask,
370 std::u16string_view rLiteralMask,
371 bool bSameMask)
372{
373 OUString aText(rText);
374
375 // remove leading blanks
376 if (bSameMask && !rEditMask.isEmpty())
377 {
378 sal_Int32 i = 0;
379 sal_Int32 nMaxLen = aText.getLength();
380 while ( i < nMaxLen )
381 {
382 if ( (rEditMask[i] != EDITMASK_LITERAL) &&
383 (aText[i] != ' ') )
384 break;
385
386 i++;
387 }
388 // keep all literal characters
389 while ( i && (rEditMask[i] == EDITMASK_LITERAL) )
390 i--;
391 aText = aText.copy( i );
392 }
393
394 return ImplPatternReformat(aText, rEditMask, rLiteralMask, 0);
395}
396
398 const OString& rEditMask,
399 std::u16string_view rLiteralMask,
400 bool bSameMask )
401{
402 OUString aText = pEdit->GetText();
403 OUString aNewText = ImplPatternProcessStrictModify(aText,
404 rEditMask,
405 rLiteralMask,
406 bSameMask);
407
408 if ( aNewText == aText )
409 return;
410
411 // adjust selection such that it remains at the end if it was there before
412 Selection aSel = pEdit->GetSelection();
413 sal_Int64 nMaxSel = std::max( aSel.Min(), aSel.Max() );
414 if ( nMaxSel >= aText.getLength() )
415 {
416 sal_Int32 nMaxPos = aNewText.getLength();
417 ImplPatternMaxPos(aNewText, rEditMask, 0, bSameMask, nMaxSel, nMaxPos);
418 if ( aSel.Min() == aSel.Max() )
419 {
420 aSel.Min() = nMaxPos;
421 aSel.Max() = aSel.Min();
422 }
423 else if ( aSel.Min() > aSel.Max() )
424 aSel.Min() = nMaxPos;
425 else
426 aSel.Max() = nMaxPos;
427 }
428 pEdit->SetText( aNewText, aSel );
429}
430
432 const OString& rEditMask,
433 std::u16string_view rLiteralMask,
434 bool bSameMask )
435{
436 OUString aText = rEntry.get_text();
437 OUString aNewText = ImplPatternProcessStrictModify(aText,
438 rEditMask,
439 rLiteralMask,
440 bSameMask);
441
442 if (aNewText == aText)
443 return;
444
445 // adjust selection such that it remains at the end if it was there before
446 int nStartPos, nEndPos;
447 rEntry.get_selection_bounds(nStartPos, nEndPos);
448
449 int nMaxSel = std::max(nStartPos, nEndPos);
450 if (nMaxSel >= aText.getLength())
451 {
452 sal_Int32 nMaxPos = aNewText.getLength();
453 ImplPatternMaxPos(aNewText, rEditMask, 0, bSameMask, nMaxSel, nMaxPos);
454 if (nStartPos == nEndPos)
455 {
456 nStartPos = nMaxPos;
457 nEndPos = nMaxPos;
458 }
459 else if (nStartPos > nMaxPos)
460 nStartPos = nMaxPos;
461 else
462 nEndPos = nMaxPos;
463 }
464 rEntry.set_text(aNewText);
465 rEntry.select_region(nStartPos, nEndPos);
466}
467
468static sal_Int32 ImplPatternLeftPos(std::string_view rEditMask, sal_Int32 nCursorPos)
469{
470 // search non-literal predecessor
471 sal_Int32 nNewPos = nCursorPos;
472 sal_Int32 nTempPos = nNewPos;
473 while ( nTempPos )
474 {
475 if ( rEditMask[nTempPos-1] != EDITMASK_LITERAL )
476 {
477 nNewPos = nTempPos-1;
478 break;
479 }
480 nTempPos--;
481 }
482 return nNewPos;
483}
484
485static sal_Int32 ImplPatternRightPos( std::u16string_view rStr, const OString& rEditMask,
486 sal_uInt16 nFormatFlags, bool bSameMask,
487 sal_Int32 nCursorPos )
488{
489 // search non-literal successor
490 sal_Int32 nNewPos = nCursorPos;
491 ;
492 for(sal_Int32 nTempPos = nNewPos+1; nTempPos < rEditMask.getLength(); ++nTempPos )
493 {
494 if ( rEditMask[nTempPos] != EDITMASK_LITERAL )
495 {
496 nNewPos = nTempPos;
497 break;
498 }
499 }
500 ImplPatternMaxPos( rStr, rEditMask, nFormatFlags, bSameMask, nCursorPos, nNewPos );
501 return nNewPos;
502}
503
504namespace
505{
506 class IEditImplementation
507 {
508 public:
509 virtual ~IEditImplementation() {}
510
511 virtual OUString GetText() const = 0;
512 virtual void SetText(const OUString& rStr, const Selection& rSelection) = 0;
513
514 virtual Selection GetSelection() const = 0;
515 virtual void SetSelection(const Selection& rSelection) = 0;
516
517 virtual bool IsInsertMode() const = 0;
518
519 virtual void SetModified() = 0;
520 };
521}
522
523static bool ImplPatternProcessKeyInput( IEditImplementation& rEdit, const KeyEvent& rKEvt,
524 const OString& rEditMask,
525 std::u16string_view rLiteralMask,
526 bool bStrictFormat,
527 bool bSameMask,
528 bool& rbInKeyInput )
529{
530 if ( rEditMask.isEmpty() || !bStrictFormat )
531 return false;
532
533 sal_uInt16 nFormatFlags = 0;
534 Selection aOldSel = rEdit.GetSelection();
535 vcl::KeyCode aCode = rKEvt.GetKeyCode();
536 sal_Unicode cChar = rKEvt.GetCharCode();
537 sal_uInt16 nKeyCode = aCode.GetCode();
538 bool bShift = aCode.IsShift();
539 sal_Int32 nCursorPos = static_cast<sal_Int32>(aOldSel.Max());
540 sal_Int32 nNewPos;
541 sal_Int32 nTempPos;
542
543 if ( nKeyCode && !aCode.IsMod1() && !aCode.IsMod2() )
544 {
545 if ( nKeyCode == KEY_LEFT )
546 {
547 Selection aSel( ImplPatternLeftPos( rEditMask, nCursorPos ) );
548 if ( bShift )
549 aSel.Min() = aOldSel.Min();
550 rEdit.SetSelection( aSel );
551 return true;
552 }
553 else if ( nKeyCode == KEY_RIGHT )
554 {
555 // Use the start of selection as minimum; even a small position is allowed in case that
556 // all was selected by the focus
557 Selection aSel( aOldSel );
558 aSel.Normalize();
559 nCursorPos = aSel.Min();
560 aSel.Max() = ImplPatternRightPos( rEdit.GetText(), rEditMask, nFormatFlags, bSameMask, nCursorPos );
561 if ( bShift )
562 aSel.Min() = aOldSel.Min();
563 else
564 aSel.Min() = aSel.Max();
565 rEdit.SetSelection( aSel );
566 return true;
567 }
568 else if ( nKeyCode == KEY_HOME )
569 {
570 // Home is the position of the first non-literal character
571 nNewPos = 0;
572 while ( (nNewPos < rEditMask.getLength()) &&
573 (rEditMask[nNewPos] == EDITMASK_LITERAL) )
574 nNewPos++;
575
576 // Home should not move to the right
577 if ( nCursorPos < nNewPos )
578 nNewPos = nCursorPos;
579 Selection aSel( nNewPos );
580 if ( bShift )
581 aSel.Min() = aOldSel.Min();
582 rEdit.SetSelection( aSel );
583 return true;
584 }
585 else if ( nKeyCode == KEY_END )
586 {
587 // End is position of last non-literal character
588 nNewPos = rEditMask.getLength();
589 while ( nNewPos &&
590 (rEditMask[nNewPos-1] == EDITMASK_LITERAL) )
591 nNewPos--;
592 // Use the start of selection as minimum; even a small position is allowed in case that
593 // all was selected by the focus
594 Selection aSel( aOldSel );
595 aSel.Normalize();
596 nCursorPos = static_cast<sal_Int32>(aSel.Min());
597 ImplPatternMaxPos( rEdit.GetText(), rEditMask, nFormatFlags, bSameMask, nCursorPos, nNewPos );
598 aSel.Max() = nNewPos;
599 if ( bShift )
600 aSel.Min() = aOldSel.Min();
601 else
602 aSel.Min() = aSel.Max();
603 rEdit.SetSelection( aSel );
604 return true;
605 }
606 else if ( (nKeyCode == KEY_BACKSPACE) || (nKeyCode == KEY_DELETE) )
607 {
608 OUString aOldStr( rEdit.GetText() );
609 OUStringBuffer aStr( aOldStr );
610 Selection aSel = aOldSel;
611
612 aSel.Normalize();
613 nNewPos = static_cast<sal_Int32>(aSel.Min());
614
615 // if selection then delete it
616 if ( aSel.Len() )
617 {
618 if ( bSameMask )
619 aStr.remove( static_cast<sal_Int32>(aSel.Min()), static_cast<sal_Int32>(aSel.Len()) );
620 else
621 {
622 std::u16string_view aRep = rLiteralMask.substr( static_cast<sal_Int32>(aSel.Min()), static_cast<sal_Int32>(aSel.Len()) );
623 aStr.remove( aSel.Min(), aRep.size() );
624 aStr.insert( aSel.Min(), aRep );
625 }
626 }
627 else
628 {
629 if ( nKeyCode == KEY_BACKSPACE )
630 {
631 nTempPos = nNewPos;
632 nNewPos = ImplPatternLeftPos( rEditMask, nTempPos );
633 }
634 else
635 nTempPos = ImplPatternRightPos( aStr, rEditMask, nFormatFlags, bSameMask, nNewPos );
636
637 if ( nNewPos != nTempPos )
638 {
639 if ( bSameMask )
640 {
641 if ( rEditMask[nNewPos] != EDITMASK_LITERAL )
642 aStr.remove( nNewPos, 1 );
643 }
644 else
645 {
646 aStr[nNewPos] = rLiteralMask[nNewPos];
647 }
648 }
649 }
650
651 OUString sStr = aStr.makeStringAndClear();
652 if ( aOldStr != sStr )
653 {
654 if ( bSameMask )
655 sStr = ImplPatternReformat( sStr, rEditMask, rLiteralMask, nFormatFlags );
656 rbInKeyInput = true;
657 rEdit.SetText( sStr, Selection( nNewPos ) );
658 rEdit.SetModified();
659 rbInKeyInput = false;
660 }
661 else
662 rEdit.SetSelection( Selection( nNewPos ) );
663
664 return true;
665 }
666 else if ( nKeyCode == KEY_INSERT )
667 {
668 // you can only set InsertMode for a PatternField if the
669 // mask is equal at all input positions
670 if ( !bSameMask )
671 {
672 return true;
673 }
674 }
675 }
676
677 if ( rKEvt.GetKeyCode().IsMod2() || (cChar < 32) || (cChar == 127) )
678 return false;
679
680 Selection aSel = aOldSel;
681 aSel.Normalize();
682 nNewPos = aSel.Min();
683
684 if ( nNewPos < rEditMask.getLength() )
685 {
686 sal_Unicode cPattChar = ImplPatternChar( cChar, rEditMask[nNewPos] );
687 if ( cPattChar )
688 cChar = cPattChar;
689 else
690 {
691 // If no valid character, check if the user wanted to jump to next literal. We do this
692 // only if we're after a character, so that literals that were skipped automatically
693 // do not influence the position anymore.
694 if ( nNewPos &&
695 (rEditMask[nNewPos-1] != EDITMASK_LITERAL) &&
696 !aSel.Len() )
697 {
698 // search for next character not being a literal
699 nTempPos = nNewPos;
700 while ( nTempPos < rEditMask.getLength() )
701 {
702 if ( rEditMask[nTempPos] == EDITMASK_LITERAL )
703 {
704 // only valid if no literal present
705 if ( (rEditMask[nTempPos+1] != EDITMASK_LITERAL ) &&
706 ImplCommaPointCharEqual( cChar, rLiteralMask[nTempPos] ) )
707 {
708 nTempPos++;
709 ImplPatternMaxPos( rEdit.GetText(), rEditMask, nFormatFlags, bSameMask, nNewPos, nTempPos );
710 if ( nTempPos > nNewPos )
711 {
712 rEdit.SetSelection( Selection( nTempPos ) );
713 return true;
714 }
715 }
716 break;
717 }
718 nTempPos++;
719 }
720 }
721
722 cChar = 0;
723 }
724 }
725 else
726 cChar = 0;
727 if ( cChar )
728 {
729 OUStringBuffer aStr(rEdit.GetText());
730 bool bError = false;
731 if ( bSameMask && rEdit.IsInsertMode() )
732 {
733 // crop spaces and literals at the end until current position
734 sal_Int32 n = aStr.getLength();
735 while ( n && (n > nNewPos) )
736 {
737 if ( (aStr[n-1] != ' ') &&
738 ((n > rEditMask.getLength()) || (rEditMask[n-1] != EDITMASK_LITERAL)) )
739 break;
740
741 n--;
742 }
743 aStr.truncate( n );
744
745 if ( aSel.Len() )
746 aStr.remove( aSel.Min(), aSel.Len() );
747
748 if ( aStr.getLength() < rEditMask.getLength() )
749 {
750 // possibly extend string until cursor position
751 if ( aStr.getLength() < nNewPos )
752 aStr.append( rLiteralMask.substr(aStr.getLength(), nNewPos-aStr.getLength()) );
753 if ( nNewPos < aStr.getLength() )
754 aStr.insert( cChar, nNewPos );
755 else if ( nNewPos < rEditMask.getLength() )
756 aStr.append(cChar);
757 aStr = ImplPatternReformat( aStr.toString(), rEditMask, rLiteralMask, nFormatFlags );
758 }
759 else
760 bError = true;
761 }
762 else
763 {
764 if ( aSel.Len() )
765 {
766 // delete selection
767 std::u16string_view aRep = rLiteralMask.substr( aSel.Min(), aSel.Len() );
768 aStr.remove( aSel.Min(), aRep.size() );
769 aStr.insert( aSel.Min(), aRep );
770 }
771
772 if ( nNewPos < aStr.getLength() )
773 aStr[nNewPos] = cChar;
774 else if ( nNewPos < rEditMask.getLength() )
775 aStr.append(cChar);
776 }
777
778 if ( !bError )
779 {
780 rbInKeyInput = true;
781 const OUString sStr = aStr.makeStringAndClear();
782 Selection aNewSel( ImplPatternRightPos( sStr, rEditMask, nFormatFlags, bSameMask, nNewPos ) );
783 rEdit.SetText( sStr, aNewSel );
784 rEdit.SetModified();
785 rbInKeyInput = false;
786 }
787 }
788
789 return true;
790}
791
792namespace
793{
794 bool ImplSetMask(const OString& rEditMask, OUString& rLiteralMask)
795 {
796 bool bSameMask = true;
797
798 if (rEditMask.getLength() != rLiteralMask.getLength())
799 {
800 OUStringBuffer aBuf(rLiteralMask);
801 if (rEditMask.getLength() < aBuf.getLength())
802 aBuf.setLength(rEditMask.getLength());
803 else
804 comphelper::string::padToLength(aBuf, rEditMask.getLength(), ' ');
805 rLiteralMask = aBuf.makeStringAndClear();
806 }
807
808 // Strict mode allows only the input mode if only equal characters are allowed as mask and if
809 // only spaces are specified which are not allowed by the mask
810 sal_Int32 i = 0;
811 char c = 0;
812 while ( i < rEditMask.getLength() )
813 {
814 char cTemp = rEditMask[i];
815 if ( cTemp != EDITMASK_LITERAL )
816 {
817 if ( (cTemp == EDITMASK_ALLCHAR) ||
818 (cTemp == EDITMASK_UPPERALLCHAR) ||
819 (cTemp == EDITMASK_NUMSPACE) )
820 {
821 bSameMask = false;
822 break;
823 }
824 if ( i < rLiteralMask.getLength() )
825 {
826 if ( rLiteralMask[i] != ' ' )
827 {
828 bSameMask = false;
829 break;
830 }
831 }
832 if ( !c )
833 c = cTemp;
834 if ( cTemp != c )
835 {
836 bSameMask = false;
837 break;
838 }
839 }
840 i++;
841 }
842
843 return bSameMask;
844 }
845}
846
847PatternFormatter::PatternFormatter(Edit* pEdit)
848 : FormatterBase(pEdit)
849{
850 mbSameMask = true;
851 mbInPattKeyInput = false;
852}
853
854PatternFormatter::~PatternFormatter()
855{
856}
857
858void PatternFormatter::SetMask( const OString& rEditMask,
859 const OUString& rLiteralMask )
860{
861 m_aEditMask = rEditMask;
862 maLiteralMask = rLiteralMask;
863 mbSameMask = ImplSetMask(m_aEditMask, maLiteralMask);
864 ReformatAll();
865}
866
867namespace
868{
869 class EntryImplementation : public IEditImplementation
870 {
871 public:
872 EntryImplementation(weld::PatternFormatter& rFormatter)
873 : m_rFormatter(rFormatter)
874 , m_rEntry(rFormatter.get_widget())
875 {
876 }
877
878 virtual OUString GetText() const override
879 {
880 return m_rEntry.get_text();
881 }
882
883 virtual void SetText(const OUString& rStr, const Selection& rSelection) override
884 {
885 m_rEntry.set_text(rStr);
886 SetSelection(rSelection);
887 }
888
889 virtual Selection GetSelection() const override
890 {
891 int nStartPos, nEndPos;
892 m_rEntry.get_selection_bounds(nStartPos, nEndPos);
893 return Selection(nStartPos, nEndPos);
894 }
895
896 virtual void SetSelection(const Selection& rSelection) override
897 {
898 auto nMin = rSelection.Min();
899 auto nMax = rSelection.Max();
900 m_rEntry.select_region(nMin < 0 ? 0 : nMin, nMax == SELECTION_MAX ? -1 : nMax);
901 }
902
903 virtual bool IsInsertMode() const override
904 {
905 return !m_rEntry.get_overwrite_mode();
906 }
907
908 virtual void SetModified() override
909 {
910 m_rFormatter.Modify();
911 }
912
913 private:
914 weld::PatternFormatter& m_rFormatter;
915 weld::Entry& m_rEntry;
916 };
917}
918
919namespace weld
920{
922 {
923 if (bStrict != m_bStrictFormat)
924 {
925 m_bStrictFormat = bStrict;
926 if (m_bStrictFormat)
927 ReformatAll();
928 }
929 }
930
931 void PatternFormatter::SetMask(const OString& rEditMask,
932 const OUString& rLiteralMask)
933 {
934 m_aEditMask = rEditMask;
935 m_aLiteralMask = rLiteralMask;
936 m_bSameMask = ImplSetMask(m_aEditMask, m_aLiteralMask);
937 ReformatAll();
938 }
939
941 {
945 }
946
948 {
949 m_bReformat = false;
950 }
951
953 {
954 if (m_bReformat)
955 ReformatAll();
956 }
957
959 {
961 {
962 if (m_bStrictFormat)
964 else
965 m_bReformat = true;
966 }
968 }
969
970 IMPL_LINK(PatternFormatter, KeyInputHdl, const KeyEvent&, rKEvt, bool)
971 {
972 if (m_aKeyPressHdl.Call(rKEvt))
973 return true;
974 if (rKEvt.GetKeyCode().IsMod2())
975 return false;
976 EntryImplementation aAdapt(*this);
977 return ImplPatternProcessKeyInput(aAdapt, rKEvt, m_aEditMask, m_aLiteralMask,
978 m_bStrictFormat,
979 m_bSameMask, m_bInPattKeyInput);
980 }
981}
982
983void PatternFormatter::SetString( const OUString& rStr )
984{
985 if ( GetField() )
986 {
987 GetField()->SetText( rStr );
988 MarkToBeReformatted( false );
989 }
990}
991
992OUString PatternFormatter::GetString() const
993{
994 if ( !GetField() )
995 return OUString();
996 else
997 return ImplPatternReformat( GetField()->GetText(), m_aEditMask, maLiteralMask, 0/*nFormatFlags*/ );
998}
999
1000void PatternFormatter::Reformat()
1001{
1002 if ( GetField() )
1003 {
1004 ImplSetText( ImplPatternReformat( GetField()->GetText(), m_aEditMask, maLiteralMask, 0/*nFormatFlags*/ ) );
1005 if ( !mbSameMask && IsStrictFormat() && !GetField()->IsReadOnly() )
1006 GetField()->SetInsertMode( false );
1007 }
1008}
1009
1010PatternField::PatternField(vcl::Window* pParent, WinBits nWinStyle)
1011 : SpinField(pParent, nWinStyle)
1012 , PatternFormatter(this)
1013{
1014 Reformat();
1015}
1016
1017void PatternField::dispose()
1018{
1019 ClearField();
1021}
1022
1023namespace
1024{
1025 class EditImplementation : public IEditImplementation
1026 {
1027 public:
1028 EditImplementation(Edit& rEdit)
1029 : m_rEdit(rEdit)
1030 {
1031 }
1032
1033 virtual OUString GetText() const override
1034 {
1035 return m_rEdit.GetText();
1036 }
1037
1038 virtual void SetText(const OUString& rStr, const Selection& rSelection) override
1039 {
1040 m_rEdit.SetText(rStr, rSelection);
1041 }
1042
1043 virtual Selection GetSelection() const override
1044 {
1045 return m_rEdit.GetSelection();
1046 }
1047
1048 virtual void SetSelection(const Selection& rSelection) override
1049 {
1050 m_rEdit.SetSelection(rSelection);
1051 }
1052
1053 virtual bool IsInsertMode() const override
1054 {
1055 return m_rEdit.IsInsertMode();
1056 }
1057
1058 virtual void SetModified() override
1059 {
1060 m_rEdit.SetModifyFlag();
1061 m_rEdit.Modify();
1062 }
1063
1064 private:
1065 Edit& m_rEdit;
1066 };
1067}
1068
1069bool PatternField::PreNotify( NotifyEvent& rNEvt )
1070{
1071 if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1072 {
1073 EditImplementation aAdapt(*GetField());
1074 if ( ImplPatternProcessKeyInput( aAdapt, *rNEvt.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
1075 IsStrictFormat(),
1076 ImplIsSameMask(), ImplGetInPattKeyInput() ) )
1077 return true;
1078 }
1079
1080 return SpinField::PreNotify( rNEvt );
1081}
1082
1083bool PatternField::EventNotify( NotifyEvent& rNEvt )
1084{
1085 if ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
1086 MarkToBeReformatted( false );
1087 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
1088 {
1089 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1090 Reformat();
1091 }
1092
1093 return SpinField::EventNotify( rNEvt );
1094}
1095
1096void PatternField::Modify()
1097{
1098 if ( !ImplGetInPattKeyInput() )
1099 {
1100 if ( IsStrictFormat() )
1101 ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), ImplIsSameMask() );
1102 else
1103 MarkToBeReformatted( true );
1104 }
1105
1107}
1108
1109PatternBox::PatternBox(vcl::Window* pParent, WinBits nWinStyle)
1110 : ComboBox( pParent, nWinStyle )
1111 , PatternFormatter(this)
1112{
1113 Reformat();
1114}
1115
1116void PatternBox::dispose()
1117{
1118 ClearField();
1120}
1121
1122bool PatternBox::PreNotify( NotifyEvent& rNEvt )
1123{
1124 if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1125 {
1126 EditImplementation aAdapt(*GetField());
1127 if ( ImplPatternProcessKeyInput( aAdapt, *rNEvt.GetKeyEvent(), GetEditMask(), GetLiteralMask(),
1128 IsStrictFormat(),
1129 ImplIsSameMask(), ImplGetInPattKeyInput() ) )
1130 return true;
1131 }
1132
1133 return ComboBox::PreNotify( rNEvt );
1134}
1135
1136bool PatternBox::EventNotify( NotifyEvent& rNEvt )
1137{
1138 if ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
1139 MarkToBeReformatted( false );
1140 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
1141 {
1142 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1143 Reformat();
1144 }
1145
1146 return ComboBox::EventNotify( rNEvt );
1147}
1148
1149void PatternBox::Modify()
1150{
1151 if ( !ImplGetInPattKeyInput() )
1152 {
1153 if ( IsStrictFormat() )
1154 ImplPatternProcessStrictModify( GetField(), GetEditMask(), GetLiteralMask(), ImplIsSameMask() );
1155 else
1156 MarkToBeReformatted( true );
1157 }
1158
1160}
1161
1162void PatternBox::ReformatAll()
1163{
1164 OUString aStr;
1165 SetUpdateMode( false );
1166 const sal_Int32 nEntryCount = GetEntryCount();
1167 for ( sal_Int32 i=0; i < nEntryCount; ++i )
1168 {
1169 aStr = ImplPatternReformat( GetEntry( i ), GetEditMask(), GetLiteralMask(), 0/*nFormatFlags*/ );
1170 RemoveEntryAt(i);
1171 InsertEntry( aStr, i );
1172 }
1173 PatternFormatter::Reformat();
1174 SetUpdateMode( true );
1175}
1176
1178{
1179 switch( eOld )
1180 {
1181 case LongDateOrder::YDM:
1182 case LongDateOrder::DMY: return ExtDateFieldFormat::ShortDDMMYY;
1183 case LongDateOrder::MDY: return ExtDateFieldFormat::ShortMMDDYY;
1184 case LongDateOrder::YMD:
1185 default: return ExtDateFieldFormat::ShortYYMMDD;
1186 }
1187}
1188
1189static sal_uInt16 ImplCutNumberFromString( OUString& rStr )
1190{
1191 sal_Int32 i1 = 0;
1192 while (i1 != rStr.getLength() && (rStr[i1] < '0' || rStr[i1] > '9')) {
1193 ++i1;
1194 }
1195 sal_Int32 i2 = i1;
1196 while (i2 != rStr.getLength() && rStr[i2] >= '0' && rStr[i2] <= '9') {
1197 ++i2;
1198 }
1199 sal_Int32 nValue = o3tl::toInt32(rStr.subView(i1, i2-i1));
1200 rStr = rStr.copy(std::min(i2+1, rStr.getLength()));
1201 return nValue;
1202}
1203
1204static bool ImplCutMonthName( OUString& rStr, std::u16string_view _rLookupMonthName )
1205{
1206 sal_Int32 index = 0;
1207 rStr = rStr.replaceFirst(_rLookupMonthName, "", &index);
1208 return index >= 0;
1209}
1210
1211static sal_uInt16 ImplGetMonthFromCalendarItem( OUString& rStr, const uno::Sequence< i18n::CalendarItem2 >& rMonths )
1212{
1213 const sal_uInt16 nMonths = rMonths.getLength();
1214 for (sal_uInt16 i=0; i < nMonths; ++i)
1215 {
1216 // long month name?
1217 if ( ImplCutMonthName( rStr, rMonths[i].FullName ) )
1218 return i+1;
1219
1220 // short month name?
1221 if ( ImplCutMonthName( rStr, rMonths[i].AbbrevName ) )
1222 return i+1;
1223 }
1224 return 0;
1225}
1226
1227static sal_uInt16 ImplCutMonthFromString( OUString& rStr, OUString& rCalendarName,
1228 const LocaleDataWrapper& rLocaleData, const CalendarWrapper& rCalendarWrapper )
1229{
1230 const OUString aDefaultCalendarName( rCalendarWrapper.getUniqueID());
1231 rCalendarName = aDefaultCalendarName;
1232
1233 // Search for a month name of the loaded default calendar.
1234 const uno::Sequence< i18n::CalendarItem2 > aMonths = rCalendarWrapper.getMonths();
1235 sal_uInt16 nMonth = ImplGetMonthFromCalendarItem( rStr, aMonths);
1236 if (nMonth > 0)
1237 return nMonth;
1238
1239 // And also possessive genitive and partitive month names.
1240 const uno::Sequence< i18n::CalendarItem2 > aGenitiveMonths = rCalendarWrapper.getGenitiveMonths();
1241 if (aGenitiveMonths != aMonths)
1242 {
1243 nMonth = ImplGetMonthFromCalendarItem( rStr, aGenitiveMonths);
1244 if (nMonth > 0)
1245 return nMonth;
1246 }
1247 const uno::Sequence< i18n::CalendarItem2 > aPartitiveMonths = rCalendarWrapper.getPartitiveMonths();
1248 if (aPartitiveMonths != aMonths)
1249 {
1250 nMonth = ImplGetMonthFromCalendarItem( rStr, aPartitiveMonths);
1251 if (nMonth > 0)
1252 return nMonth;
1253 }
1254
1255 // Check if there are more calendars and try them if so, as the long date
1256 // format is obtained from the number formatter this is possible (e.g.
1257 // ar_DZ "[~hijri] ...")
1258 const uno::Sequence< i18n::Calendar2 > aCalendars = rLocaleData.getAllCalendars();
1259 if (aCalendars.getLength() > 1)
1260 {
1261 for (const auto& rCalendar : aCalendars)
1262 {
1263 if (rCalendar.Name != aDefaultCalendarName)
1264 {
1265 rCalendarName = rCalendar.Name;
1266
1267 nMonth = ImplGetMonthFromCalendarItem( rStr, rCalendar.Months);
1268 if (nMonth > 0)
1269 return nMonth;
1270
1271 if (rCalendar.Months != rCalendar.GenitiveMonths)
1272 {
1273 nMonth = ImplGetMonthFromCalendarItem( rStr, rCalendar.GenitiveMonths);
1274 if (nMonth > 0)
1275 return nMonth;
1276 }
1277
1278 if (rCalendar.Months != rCalendar.PartitiveMonths)
1279 {
1280 nMonth = ImplGetMonthFromCalendarItem( rStr, rCalendar.PartitiveMonths);
1281 if (nMonth > 0)
1282 return nMonth;
1283 }
1284
1285 rCalendarName = aDefaultCalendarName;
1286 }
1287 }
1288 }
1289
1290 return ImplCutNumberFromString( rStr );
1291}
1292
1293static OUString ImplGetDateSep( const LocaleDataWrapper& rLocaleDataWrapper, ExtDateFieldFormat eFormat )
1294{
1296 return "-";
1297 else
1298 return rLocaleDataWrapper.getDateSep();
1299}
1300
1301static bool ImplDateProcessKeyInput( const KeyEvent& rKEvt, ExtDateFieldFormat eFormat,
1302 const LocaleDataWrapper& rLocaleDataWrapper )
1303{
1304 sal_Unicode cChar = rKEvt.GetCharCode();
1305 sal_uInt16 nGroup = rKEvt.GetKeyCode().GetGroup();
1306 return !((nGroup == KEYGROUP_FKEYS) ||
1307 (nGroup == KEYGROUP_CURSOR) ||
1308 (nGroup == KEYGROUP_MISC)||
1309 ((cChar >= '0') && (cChar <= '9')) ||
1310 (cChar == ImplGetDateSep( rLocaleDataWrapper, eFormat )[0]));
1311}
1312
1313bool DateFormatter::TextToDate(const OUString& rStr, Date& rDate, ExtDateFieldFormat eDateOrder,
1314 const LocaleDataWrapper& rLocaleDataWrapper, const CalendarWrapper& rCalendarWrapper)
1315{
1316 sal_uInt16 nDay = 0;
1317 sal_uInt16 nMonth = 0;
1318 sal_uInt16 nYear = 0;
1319 bool bError = false;
1320 OUString aStr( rStr );
1321
1322 if ( eDateOrder == ExtDateFieldFormat::SystemLong )
1323 {
1324 OUString aCalendarName;
1325 LongDateOrder eFormat = rLocaleDataWrapper.getLongDateOrder();
1326 switch( eFormat )
1327 {
1328 case LongDateOrder::MDY:
1329 nMonth = ImplCutMonthFromString( aStr, aCalendarName, rLocaleDataWrapper, rCalendarWrapper );
1330 nDay = ImplCutNumberFromString( aStr );
1331 nYear = ImplCutNumberFromString( aStr );
1332 break;
1333 case LongDateOrder::DMY:
1334 nDay = ImplCutNumberFromString( aStr );
1335 nMonth = ImplCutMonthFromString( aStr, aCalendarName, rLocaleDataWrapper, rCalendarWrapper );
1336 nYear = ImplCutNumberFromString( aStr );
1337 break;
1338 case LongDateOrder::YDM:
1339 nYear = ImplCutNumberFromString( aStr );
1340 nDay = ImplCutNumberFromString( aStr );
1341 nMonth = ImplCutMonthFromString( aStr, aCalendarName, rLocaleDataWrapper, rCalendarWrapper );
1342 break;
1343 case LongDateOrder::YMD:
1344 default:
1345 nYear = ImplCutNumberFromString( aStr );
1346 nMonth = ImplCutMonthFromString( aStr, aCalendarName, rLocaleDataWrapper, rCalendarWrapper );
1347 nDay = ImplCutNumberFromString( aStr );
1348 break;
1349 }
1350 if (aCalendarName != "gregorian")
1351 {
1352 // Calendar widget is Gregorian, convert date.
1353 // Need full date.
1354 bError = !nDay || !nMonth || !nYear;
1355 if (!bError)
1356 {
1357 CalendarWrapper aCW( rLocaleDataWrapper.getComponentContext());
1358 aCW.loadCalendar( aCalendarName, rLocaleDataWrapper.getLoadedLanguageTag().getLocale());
1359 aCW.setDateTime(0.5); // get rid of current time, set some day noon
1360 aCW.setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay);
1361 aCW.setValue( i18n::CalendarFieldIndex::MONTH, nMonth - 1);
1362 aCW.setValue( i18n::CalendarFieldIndex::YEAR, nYear);
1363 bError = !aCW.isValid();
1364 if (!bError)
1365 {
1366 Date aDate = aCW.getEpochStart() + aCW.getDateTime();
1367 nYear = aDate.GetYear();
1368 nMonth = aDate.GetMonth();
1369 nDay = aDate.GetDay();
1370 }
1371 }
1372 }
1373 }
1374 else
1375 {
1376 bool bYear = true;
1377
1378 // Check if year is present:
1379 OUString aDateSep = ImplGetDateSep( rLocaleDataWrapper, eDateOrder );
1380 sal_Int32 nSepPos = aStr.indexOf( aDateSep );
1381 if ( nSepPos < 0 )
1382 return false;
1383 nSepPos = aStr.indexOf( aDateSep, nSepPos+1 );
1384 if ( ( nSepPos < 0 ) || ( nSepPos == (aStr.getLength()-1) ) )
1385 {
1386 bYear = false;
1387 nYear = Date( Date::SYSTEM ).GetYearUnsigned();
1388 }
1389
1390 const sal_Unicode* pBuf = aStr.getStr();
1391 ImplSkipDelimiters( pBuf );
1392
1393 switch ( eDateOrder )
1394 {
1397 {
1398 nDay = ImplGetNum( pBuf, bError );
1399 ImplSkipDelimiters( pBuf );
1400 nMonth = ImplGetNum( pBuf, bError );
1401 ImplSkipDelimiters( pBuf );
1402 if ( bYear )
1403 nYear = ImplGetNum( pBuf, bError );
1404 }
1405 break;
1408 {
1409 nMonth = ImplGetNum( pBuf, bError );
1410 ImplSkipDelimiters( pBuf );
1411 nDay = ImplGetNum( pBuf, bError );
1412 ImplSkipDelimiters( pBuf );
1413 if ( bYear )
1414 nYear = ImplGetNum( pBuf, bError );
1415 }
1416 break;
1421 {
1422 if ( bYear )
1423 nYear = ImplGetNum( pBuf, bError );
1424 ImplSkipDelimiters( pBuf );
1425 nMonth = ImplGetNum( pBuf, bError );
1426 ImplSkipDelimiters( pBuf );
1427 nDay = ImplGetNum( pBuf, bError );
1428 }
1429 break;
1430
1431 default:
1432 {
1433 OSL_FAIL( "DateOrder???" );
1434 }
1435 }
1436 }
1437
1438 if ( bError || !nDay || !nMonth )
1439 return false;
1440
1441 Date aNewDate( nDay, nMonth, nYear );
1442 DateFormatter::ExpandCentury( aNewDate, officecfg::Office::Common::DateFormat::TwoDigitYear::get() );
1443 if ( aNewDate.IsValidDate() )
1444 {
1445 rDate = aNewDate;
1446 return true;
1447 }
1448 return false;
1449}
1450
1451void DateFormatter::ImplDateReformat( const OUString& rStr, OUString& rOutStr )
1452{
1453 Date aDate( Date::EMPTY );
1454 if (!TextToDate(rStr, aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper()))
1455 return;
1456
1457 Date aTempDate = aDate;
1458 if ( aTempDate > GetMax() )
1459 aTempDate = GetMax();
1460 else if ( aTempDate < GetMin() )
1461 aTempDate = GetMin();
1462
1463 rOutStr = ImplGetDateAsText( aTempDate );
1464}
1465
1466namespace
1467{
1468 ExtDateFieldFormat ResolveSystemFormat(ExtDateFieldFormat eDateFormat, const LocaleDataWrapper& rLocaleData)
1469 {
1470 if (eDateFormat <= ExtDateFieldFormat::SystemShortYYYY)
1471 {
1472 bool bShowCentury = (eDateFormat == ExtDateFieldFormat::SystemShortYYYY);
1473 switch (rLocaleData.getDateOrder())
1474 {
1475 case DateOrder::DMY:
1477 break;
1478 case DateOrder::MDY:
1480 break;
1481 default:
1483 }
1484 }
1485 return eDateFormat;
1486 }
1487}
1488
1489OUString DateFormatter::FormatDate(const Date& rDate, ExtDateFieldFormat eExtFormat,
1490 const LocaleDataWrapper& rLocaleData,
1491 const Formatter::StaticFormatter& rStaticFormatter)
1492{
1493 bool bShowCentury = false;
1494 switch (eExtFormat)
1495 {
1502 {
1503 bShowCentury = true;
1504 }
1505 break;
1506 default:
1507 {
1508 bShowCentury = false;
1509 }
1510 }
1511
1512 if ( !bShowCentury )
1513 {
1514 // Check if I have to use force showing the century
1515 sal_uInt16 nTwoDigitYearStart = officecfg::Office::Common::DateFormat::TwoDigitYear::get();
1516 sal_uInt16 nYear = rDate.GetYearUnsigned();
1517
1518 // If year is not in double digit range
1519 if ( (nYear < nTwoDigitYearStart) || (nYear >= nTwoDigitYearStart+100) )
1520 bShowCentury = true;
1521 }
1522
1523 sal_Unicode aBuf[128];
1524 sal_Unicode* pBuf = aBuf;
1525
1526 eExtFormat = ResolveSystemFormat(eExtFormat, rLocaleData);
1527
1528 OUString aDateSep = ImplGetDateSep( rLocaleData, eExtFormat );
1529 sal_uInt16 nDay = rDate.GetDay();
1530 sal_uInt16 nMonth = rDate.GetMonth();
1531 sal_Int16 nYear = rDate.GetYear();
1532 sal_uInt16 nYearLen = bShowCentury ? 4 : 2;
1533
1534 if ( !bShowCentury )
1535 nYear %= 100;
1536
1537 switch (eExtFormat)
1538 {
1540 {
1541 SvNumberFormatter* pFormatter = rStaticFormatter;
1542 const LanguageTag aFormatterLang( pFormatter->GetLanguageTag());
1543 const sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_SYSTEM_LONG,
1544 rLocaleData.getLanguageTag().getLanguageType(false));
1545 OUString aStr;
1546 const Color* pCol;
1547 pFormatter->GetOutputString( rDate - pFormatter->GetNullDate(), nIndex, aStr, &pCol);
1548 // Reset to what other uses may expect.
1549 pFormatter->ChangeIntl( aFormatterLang.getLanguageType(false));
1550 return aStr;
1551 }
1554 {
1555 pBuf = ImplAddNum( pBuf, nDay, 2 );
1556 pBuf = ImplAddString( pBuf, aDateSep );
1557 pBuf = ImplAddNum( pBuf, nMonth, 2 );
1558 pBuf = ImplAddString( pBuf, aDateSep );
1559 pBuf = ImplAddSNum( pBuf, nYear, nYearLen );
1560 }
1561 break;
1564 {
1565 pBuf = ImplAddNum( pBuf, nMonth, 2 );
1566 pBuf = ImplAddString( pBuf, aDateSep );
1567 pBuf = ImplAddNum( pBuf, nDay, 2 );
1568 pBuf = ImplAddString( pBuf, aDateSep );
1569 pBuf = ImplAddSNum( pBuf, nYear, nYearLen );
1570 }
1571 break;
1576 {
1577 pBuf = ImplAddSNum( pBuf, nYear, nYearLen );
1578 pBuf = ImplAddString( pBuf, aDateSep );
1579 pBuf = ImplAddNum( pBuf, nMonth, 2 );
1580 pBuf = ImplAddString( pBuf, aDateSep );
1581 pBuf = ImplAddNum( pBuf, nDay, 2 );
1582 }
1583 break;
1584 default:
1585 {
1586 OSL_FAIL( "DateOrder???" );
1587 }
1588 }
1589
1590 return OUString(aBuf, pBuf-aBuf);
1591}
1592
1593OUString DateFormatter::ImplGetDateAsText( const Date& rDate ) const
1594{
1595 return DateFormatter::FormatDate(rDate, GetExtDateFormat(), ImplGetLocaleDataWrapper(), maStaticFormatter);
1596}
1597
1598static void ImplDateIncrementDay( Date& rDate, bool bUp )
1599{
1600 DateFormatter::ExpandCentury( rDate );
1601 rDate.AddDays( bUp ? 1 : -1 );
1602}
1603
1604static void ImplDateIncrementMonth( Date& rDate, bool bUp )
1605{
1606 DateFormatter::ExpandCentury( rDate );
1607 rDate.AddMonths( bUp ? 1 : -1 );
1608}
1609
1610static void ImplDateIncrementYear( Date& rDate, bool bUp )
1611{
1612 DateFormatter::ExpandCentury( rDate );
1613 rDate.AddYears( bUp ? 1 : -1 );
1614}
1615
1616bool DateFormatter::ImplAllowMalformedInput() const
1617{
1618 return !IsEnforceValidValue();
1619}
1620
1621int DateFormatter::GetDateArea(ExtDateFieldFormat& eFormat, std::u16string_view rText, int nCursor, const LocaleDataWrapper& rLocaleDataWrapper)
1622{
1623 sal_Int8 nDateArea = 0;
1624
1625 if ( eFormat == ExtDateFieldFormat::SystemLong )
1626 {
1627 eFormat = ImplGetExtFormat(rLocaleDataWrapper.getLongDateOrder());
1628 nDateArea = 1;
1629 }
1630 else
1631 {
1632 // search area
1633 size_t nPos = 0;
1634 OUString aDateSep = ImplGetDateSep(rLocaleDataWrapper, eFormat);
1635 for ( sal_Int8 i = 1; i <= 3; i++ )
1636 {
1637 nPos = rText.find( aDateSep, nPos );
1638 if (nPos == std::u16string_view::npos || static_cast<sal_Int32>(nPos) >= nCursor)
1639 {
1640 nDateArea = i;
1641 break;
1642 }
1643 else
1644 nPos++;
1645 }
1646 }
1647
1648 return nDateArea;
1649}
1650
1652{
1653 // increment days if all is selected
1654 if ( !GetField() )
1655 return;
1656
1657 Date aDate( GetDate() );
1658 Selection aSelection = GetField()->GetSelection();
1659 aSelection.Normalize();
1660 OUString aText( GetText() );
1661 if ( static_cast<sal_Int32>(aSelection.Len()) == aText.getLength() )
1662 ImplDateIncrementDay( aDate, bUp );
1663 else
1664 {
1665 ExtDateFieldFormat eFormat = GetExtDateFormat( true );
1666 sal_Int8 nDateArea = GetDateArea(eFormat, aText, aSelection.Max(), ImplGetLocaleDataWrapper());
1667
1668 switch( eFormat )
1669 {
1672 switch( nDateArea )
1673 {
1674 case 1: ImplDateIncrementMonth( aDate, bUp );
1675 break;
1676 case 2: ImplDateIncrementDay( aDate, bUp );
1677 break;
1678 case 3: ImplDateIncrementYear( aDate, bUp );
1679 break;
1680 }
1681 break;
1684 switch( nDateArea )
1685 {
1686 case 1: ImplDateIncrementDay( aDate, bUp );
1687 break;
1688 case 2: ImplDateIncrementMonth( aDate, bUp );
1689 break;
1690 case 3: ImplDateIncrementYear( aDate, bUp );
1691 break;
1692 }
1693 break;
1698 switch( nDateArea )
1699 {
1700 case 1: ImplDateIncrementYear( aDate, bUp );
1701 break;
1702 case 2: ImplDateIncrementMonth( aDate, bUp );
1703 break;
1704 case 3: ImplDateIncrementDay( aDate, bUp );
1705 break;
1706 }
1707 break;
1708 default:
1709 OSL_FAIL( "invalid conversion" );
1710 break;
1711 }
1712 }
1713
1714 ImplNewFieldValue( aDate );
1715}
1716
1717DateFormatter::DateFormatter(Edit* pEdit)
1718 : FormatterBase(pEdit)
1719 , maFieldDate(0)
1720 , maLastDate(0)
1721 , maMin(1, 1, 1900)
1722 , maMax(31, 12, 2200)
1723 , mbLongFormat(false)
1724 , mbShowDateCentury(true)
1725 , mnExtDateFormat(ExtDateFieldFormat::SystemShort)
1726 , mbEnforceValidValue(true)
1727{
1728}
1729
1730DateFormatter::~DateFormatter()
1731{
1732}
1733
1734CalendarWrapper& DateFormatter::GetCalendarWrapper() const
1735{
1736 if (!mxCalendarWrapper)
1737 {
1738 const_cast<DateFormatter*>(this)->mxCalendarWrapper.reset( new CalendarWrapper( comphelper::getProcessComponentContext() ) );
1739 mxCalendarWrapper->loadDefaultCalendar( GetLocale() );
1740 }
1741
1742 return *mxCalendarWrapper;
1743}
1744
1745void DateFormatter::SetExtDateFormat( ExtDateFieldFormat eFormat )
1746{
1747 mnExtDateFormat = eFormat;
1748 ReformatAll();
1749}
1750
1751ExtDateFieldFormat DateFormatter::GetExtDateFormat( bool bResolveSystemFormat ) const
1752{
1753 ExtDateFieldFormat eDateFormat = mnExtDateFormat;
1754
1755 if (bResolveSystemFormat)
1756 eDateFormat = ResolveSystemFormat(eDateFormat, ImplGetLocaleDataWrapper());
1757
1758 return eDateFormat;
1759}
1760
1761void DateFormatter::ReformatAll()
1762{
1763 Reformat();
1764}
1765
1766void DateFormatter::SetMin( const Date& rNewMin )
1767{
1768 maMin = rNewMin;
1769 if ( !IsEmptyFieldValue() )
1770 ReformatAll();
1771}
1772
1773void DateFormatter::SetMax( const Date& rNewMax )
1774{
1775 maMax = rNewMax;
1776 if ( !IsEmptyFieldValue() )
1777 ReformatAll();
1778}
1779
1780void DateFormatter::SetLongFormat( bool bLong )
1781{
1782 mbLongFormat = bLong;
1783
1784 // #91913# Remove LongFormat and DateShowCentury - redundant
1785 if ( bLong )
1786 {
1787 SetExtDateFormat( ExtDateFieldFormat::SystemLong );
1788 }
1789 else
1790 {
1791 if( mnExtDateFormat == ExtDateFieldFormat::SystemLong )
1792 SetExtDateFormat( ExtDateFieldFormat::SystemShort );
1793 }
1794
1795 ReformatAll();
1796}
1797
1798namespace
1799{
1800 ExtDateFieldFormat ChangeDateCentury(ExtDateFieldFormat eExtDateFormat, bool bShowDateCentury)
1801 {
1802 // #91913# Remove LongFormat and DateShowCentury - redundant
1803 if (bShowDateCentury)
1804 {
1805 switch (eExtDateFormat)
1806 {
1809 eExtDateFormat = ExtDateFieldFormat::SystemShortYYYY; break;
1811 eExtDateFormat = ExtDateFieldFormat::ShortDDMMYYYY; break;
1813 eExtDateFormat = ExtDateFieldFormat::ShortMMDDYYYY; break;
1815 eExtDateFormat = ExtDateFieldFormat::ShortYYYYMMDD; break;
1817 eExtDateFormat = ExtDateFieldFormat::ShortYYYYMMDD_DIN5008; break;
1818 default:
1819 ;
1820 }
1821 }
1822 else
1823 {
1824 switch (eExtDateFormat)
1825 {
1828 eExtDateFormat = ExtDateFieldFormat::SystemShortYY; break;
1830 eExtDateFormat = ExtDateFieldFormat::ShortDDMMYY; break;
1832 eExtDateFormat = ExtDateFieldFormat::ShortMMDDYY; break;
1834 eExtDateFormat = ExtDateFieldFormat::ShortYYMMDD; break;
1836 eExtDateFormat = ExtDateFieldFormat::ShortYYMMDD_DIN5008; break;
1837 default:
1838 ;
1839 }
1840 }
1841
1842 return eExtDateFormat;
1843 }
1844}
1845
1846void DateFormatter::SetShowDateCentury( bool bShowDateCentury )
1847{
1848 mbShowDateCentury = bShowDateCentury;
1849
1850 SetExtDateFormat(ChangeDateCentury(GetExtDateFormat(), bShowDateCentury));
1851
1852 ReformatAll();
1853}
1854
1855void DateFormatter::SetDate( const Date& rNewDate )
1856{
1857 ImplSetUserDate( rNewDate );
1858 maFieldDate = maLastDate;
1859 maLastDate = GetDate();
1860}
1861
1862void DateFormatter::ImplSetUserDate( const Date& rNewDate, Selection const * pNewSelection )
1863{
1864 Date aNewDate = rNewDate;
1865 if ( aNewDate > maMax )
1866 aNewDate = maMax;
1867 else if ( aNewDate < maMin )
1868 aNewDate = maMin;
1869 maLastDate = aNewDate;
1870
1871 if ( GetField() )
1872 ImplSetText( ImplGetDateAsText( aNewDate ), pNewSelection );
1873}
1874
1875void DateFormatter::ImplNewFieldValue( const Date& rDate )
1876{
1877 if ( !GetField() )
1878 return;
1879
1880 Selection aSelection = GetField()->GetSelection();
1881 aSelection.Normalize();
1882 OUString aText = GetField()->GetText();
1883
1884 // If selected until the end then keep it that way
1885 if ( static_cast<sal_Int32>(aSelection.Max()) == aText.getLength() )
1886 {
1887 if ( !aSelection.Len() )
1888 aSelection.Min() = SELECTION_MAX;
1889 aSelection.Max() = SELECTION_MAX;
1890 }
1891
1892 Date aOldLastDate = maLastDate;
1893 ImplSetUserDate( rDate, &aSelection );
1894 maLastDate = aOldLastDate;
1895
1896 // Modify at Edit is only set at KeyInput
1897 if ( GetField()->GetText() != aText )
1898 {
1899 GetField()->SetModifyFlag();
1900 GetField()->Modify();
1901 }
1902}
1903
1904Date DateFormatter::GetDate() const
1905{
1906 Date aDate( Date::EMPTY );
1907
1908 if ( GetField() )
1909 {
1910 if (TextToDate(GetField()->GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper()))
1911 {
1912 if ( aDate > maMax )
1913 aDate = maMax;
1914 else if ( aDate < maMin )
1915 aDate = maMin;
1916 }
1917 else
1918 {
1919 // !!! We should find out why dates are treated differently than other fields (see
1920 // also bug: 52384)
1921
1922 if ( !ImplAllowMalformedInput() )
1923 {
1924 if ( maLastDate.GetDate() )
1925 aDate = maLastDate;
1926 else if ( !IsEmptyFieldValueEnabled() )
1927 aDate = Date( Date::SYSTEM );
1928 }
1929 else
1930 aDate = Date( Date::EMPTY ); // set invalid date
1931 }
1932 }
1933
1934 return aDate;
1935}
1936
1937void DateFormatter::SetEmptyDate()
1938{
1940}
1941
1942bool DateFormatter::IsEmptyDate() const
1943{
1944 bool bEmpty = FormatterBase::IsEmptyFieldValue();
1945
1946 if ( GetField() && MustBeReformatted() && IsEmptyFieldValueEnabled() )
1947 {
1948 if ( GetField()->GetText().isEmpty() )
1949 {
1950 bEmpty = true;
1951 }
1952 else if ( !maLastDate.GetDate() )
1953 {
1954 Date aDate( Date::EMPTY );
1955 bEmpty = !TextToDate(GetField()->GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper());
1956 }
1957 }
1958 return bEmpty;
1959}
1960
1961void DateFormatter::Reformat()
1962{
1963 if ( !GetField() )
1964 return;
1965
1966 if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
1967 return;
1968
1969 OUString aStr;
1970 ImplDateReformat( GetField()->GetText(), aStr );
1971
1972 if ( !aStr.isEmpty() )
1973 {
1974 ImplSetText( aStr );
1975 (void)TextToDate(aStr, maLastDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper());
1976 }
1977 else
1978 {
1979 if ( maLastDate.GetDate() )
1980 SetDate( maLastDate );
1981 else if ( !IsEmptyFieldValueEnabled() )
1982 SetDate( Date( Date::SYSTEM ) );
1983 else
1984 {
1985 ImplSetText( OUString() );
1986 SetEmptyFieldValueData( true );
1987 }
1988 }
1989}
1990
1991void DateFormatter::ExpandCentury( Date& rDate )
1992{
1993 ExpandCentury(rDate, officecfg::Office::Common::DateFormat::TwoDigitYear::get());
1994}
1995
1996void DateFormatter::ExpandCentury( Date& rDate, sal_uInt16 nTwoDigitYearStart )
1997{
1998 sal_Int16 nDateYear = rDate.GetYear();
1999 if ( 0 <= nDateYear && nDateYear < 100 )
2000 {
2001 sal_uInt16 nCentury = nTwoDigitYearStart / 100;
2002 if ( nDateYear < (nTwoDigitYearStart % 100) )
2003 nCentury++;
2004 rDate.SetYear( nDateYear + (nCentury*100) );
2005 }
2006}
2007
2009 SpinField( pParent, nWinStyle ),
2010 DateFormatter(this),
2011 maFirst( GetMin() ),
2012 maLast( GetMax() )
2013{
2014 SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
2015 Reformat();
2016 ResetLastDate();
2017}
2018
2020{
2021 ClearField();
2023}
2024
2026{
2027 if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && IsStrictFormat() &&
2028 ( GetExtDateFormat() != ExtDateFieldFormat::SystemLong ) &&
2029 !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
2030 {
2031 if ( ImplDateProcessKeyInput( *rNEvt.GetKeyEvent(), GetExtDateFormat( true ), ImplGetLocaleDataWrapper() ) )
2032 return true;
2033 }
2034
2035 return SpinField::PreNotify( rNEvt );
2036}
2037
2039{
2040 if ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
2041 MarkToBeReformatted( false );
2042 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
2043 {
2044 if ( MustBeReformatted() )
2045 {
2046 // !!! We should find out why dates are treated differently than other fields (see
2047 // also bug: 52384)
2048
2049 bool bTextLen = !GetText().isEmpty();
2050 if ( bTextLen || !IsEmptyFieldValueEnabled() )
2051 {
2052 if ( !ImplAllowMalformedInput() )
2053 Reformat();
2054 else
2055 {
2056 Date aDate( 0, 0, 0 );
2057 if (TextToDate(GetText(), aDate, GetExtDateFormat(true), ImplGetLocaleDataWrapper(), GetCalendarWrapper()))
2058 // even with strict text analysis, our text is a valid date -> do a complete
2059 // reformat
2060 Reformat();
2061 }
2062 }
2063 else
2064 {
2065 ResetLastDate();
2066 SetEmptyFieldValueData( true );
2067 }
2068 }
2069 }
2070
2071 return SpinField::EventNotify( rNEvt );
2072}
2073
2075{
2076 SpinField::DataChanged( rDCEvt );
2077
2079 {
2080 if (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE)
2081 ImplResetLocaleDataWrapper();
2082 ReformatAll();
2083 }
2084}
2085
2087{
2088 MarkToBeReformatted( true );
2090}
2091
2093{
2094 ImplDateSpinArea( true );
2095 SpinField::Up();
2096}
2097
2099{
2100 ImplDateSpinArea( false );
2102}
2103
2105{
2106 ImplNewFieldValue( maFirst );
2108}
2109
2111{
2112 ImplNewFieldValue( maLast );
2114}
2115
2116DateBox::DateBox(vcl::Window* pParent, WinBits nWinStyle)
2117 : ComboBox( pParent, nWinStyle )
2118 , DateFormatter(this)
2119{
2120 SetText( ImplGetLocaleDataWrapper().getDate( ImplGetFieldDate() ) );
2121 Reformat();
2122}
2123
2124void DateBox::dispose()
2125{
2126 ClearField();
2128}
2129
2130bool DateBox::PreNotify( NotifyEvent& rNEvt )
2131{
2132 if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && IsStrictFormat() &&
2133 ( GetExtDateFormat() != ExtDateFieldFormat::SystemLong ) &&
2134 !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
2135 {
2136 if ( ImplDateProcessKeyInput( *rNEvt.GetKeyEvent(), GetExtDateFormat( true ), ImplGetLocaleDataWrapper() ) )
2137 return true;
2138 }
2139
2140 return ComboBox::PreNotify( rNEvt );
2141}
2142
2143void DateBox::DataChanged( const DataChangedEvent& rDCEvt )
2144{
2145 ComboBox::DataChanged( rDCEvt );
2146
2147 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
2148 {
2149 ImplResetLocaleDataWrapper();
2150 ReformatAll();
2151 }
2152}
2153
2154bool DateBox::EventNotify( NotifyEvent& rNEvt )
2155{
2156 if ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
2157 MarkToBeReformatted( false );
2158 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
2159 {
2160 if ( MustBeReformatted() )
2161 {
2162 bool bTextLen = !GetText().isEmpty();
2163 if ( bTextLen || !IsEmptyFieldValueEnabled() )
2164 Reformat();
2165 else
2166 {
2167 ResetLastDate();
2168 SetEmptyFieldValueData( true );
2169 }
2170 }
2171 }
2172
2173 return ComboBox::EventNotify( rNEvt );
2174}
2175
2176void DateBox::Modify()
2177{
2178 MarkToBeReformatted( true );
2180}
2181
2182void DateBox::ReformatAll()
2183{
2184 OUString aStr;
2185 SetUpdateMode( false );
2186 const sal_Int32 nEntryCount = GetEntryCount();
2187 for ( sal_Int32 i=0; i < nEntryCount; ++i )
2188 {
2189 ImplDateReformat( GetEntry( i ), aStr );
2190 RemoveEntryAt(i);
2191 InsertEntry( aStr, i );
2192 }
2193 DateFormatter::Reformat();
2194 SetUpdateMode( true );
2195}
2196
2197namespace weld
2198{
2200 {
2201 if (!m_xCalendarWrapper)
2202 {
2204 m_xCalendarWrapper->loadDefaultCalendar(Application::GetSettings().GetLanguageTag().getLocale());
2205 }
2206 return *m_xCalendarWrapper;
2207 }
2208
2209 void DateFormatter::SetShowDateCentury(bool bShowDateCentury)
2210 {
2211 m_eFormat = ChangeDateCentury(m_eFormat, bShowDateCentury);
2212
2213 ReFormat();
2214 }
2215
2216 void DateFormatter::SetDate(const Date& rDate)
2217 {
2218 auto nDate = rDate.GetDate();
2219 bool bForceOutput = GetEntryText().isEmpty() && rDate == GetDate();
2220 if (bForceOutput)
2221 {
2222 ImplSetValue(nDate, true);
2223 return;
2224 }
2225 SetValue(nDate);
2226 }
2227
2229 {
2230 return Date(GetValue());
2231 }
2232
2233 void DateFormatter::SetMin(const Date& rNewMin)
2234 {
2235 SetMinValue(rNewMin.GetDate());
2236 }
2237
2238 void DateFormatter::SetMax(const Date& rNewMax)
2239 {
2240 SetMaxValue(rNewMax.GetDate());
2241 }
2242
2243 OUString DateFormatter::FormatNumber(int nValue) const
2244 {
2246 return ::DateFormatter::FormatDate(Date(nValue), m_eFormat, rLocaleData, m_aStaticFormatter);
2247 }
2248
2250 {
2251 OUString sText = FormatNumber(GetValue());
2252 ImplSetTextImpl(sText, nullptr);
2253 return true;
2254 }
2255
2256 IMPL_LINK(DateFormatter, ParseInputHdl, sal_Int64*, result, TriState)
2257 {
2258 const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
2259
2260 Date aResult(Date::EMPTY);
2261 bool bRet = ::DateFormatter::TextToDate(GetEntryText(), aResult, ResolveSystemFormat(m_eFormat, rLocaleDataWrapper),
2262 rLocaleDataWrapper, GetCalendarWrapper());
2263 if (bRet)
2264 *result = aResult.GetDate();
2265
2266 return bRet ? TRISTATE_TRUE : TRISTATE_FALSE;
2267 }
2268}
2269
2270static bool ImplTimeProcessKeyInput( const KeyEvent& rKEvt,
2271 bool bStrictFormat, bool bDuration,
2272 TimeFieldFormat eFormat,
2273 const LocaleDataWrapper& rLocaleDataWrapper )
2274{
2275 sal_Unicode cChar = rKEvt.GetCharCode();
2276
2277 if ( !bStrictFormat )
2278 return false;
2279 else
2280 {
2281 sal_uInt16 nGroup = rKEvt.GetKeyCode().GetGroup();
2282 if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
2283 (nGroup == KEYGROUP_MISC) ||
2284 ((cChar >= '0') && (cChar <= '9')) ||
2285 rLocaleDataWrapper.getTimeSep() == OUStringChar(cChar) ||
2286 (rLocaleDataWrapper.getTimeAM().indexOf(cChar) != -1) ||
2287 (rLocaleDataWrapper.getTimePM().indexOf(cChar) != -1) ||
2288 // Accept AM/PM:
2289 (cChar == 'a') || (cChar == 'A') || (cChar == 'm') || (cChar == 'M') || (cChar == 'p') || (cChar == 'P') ||
2290 ((eFormat == TimeFieldFormat::F_SEC_CS) && rLocaleDataWrapper.getTime100SecSep() == OUStringChar(cChar)) ||
2291 (bDuration && (cChar == '-')) )
2292 return false;
2293 else
2294 return true;
2295 }
2296}
2297
2298static bool ImplIsOnlyDigits( const OUString& _rStr )
2299{
2300 const sal_Unicode* _pChr = _rStr.getStr();
2301 for ( sal_Int32 i = 0; i < _rStr.getLength(); ++i, ++_pChr )
2302 {
2303 if ( *_pChr < '0' || *_pChr > '9' )
2304 return false;
2305 }
2306 return true;
2307}
2308
2309static bool ImplIsValidTimePortion( bool _bSkipInvalidCharacters, const OUString& _rStr )
2310{
2311 if ( !_bSkipInvalidCharacters )
2312 {
2313 if ( ( _rStr.getLength() > 2 ) || _rStr.isEmpty() || !ImplIsOnlyDigits( _rStr ) )
2314 return false;
2315 }
2316 return true;
2317}
2318
2319static bool ImplCutTimePortion( OUStringBuffer& _rStr, sal_Int32 _nSepPos, bool _bSkipInvalidCharacters, short* _pPortion )
2320{
2321 OUString sPortion(_rStr.subView(0, _nSepPos));
2322
2323 if (_nSepPos < _rStr.getLength())
2324 _rStr.remove(0, _nSepPos + 1);
2325 else
2326 _rStr.truncate();
2327
2328 if ( !ImplIsValidTimePortion( _bSkipInvalidCharacters, sPortion ) )
2329 return false;
2330 *_pPortion = static_cast<short>(sPortion.toInt32());
2331 return true;
2332}
2333
2334bool TimeFormatter::TextToTime(std::u16string_view rStr, tools::Time& rTime,
2335 TimeFieldFormat eFormat,
2336 bool bDuration, const LocaleDataWrapper& rLocaleDataWrapper, bool _bSkipInvalidCharacters)
2337{
2338 OUStringBuffer aStr(rStr);
2339 short nHour = 0;
2340 short nMinute = 0;
2341 short nSecond = 0;
2342 sal_Int64 nNanoSec = 0;
2343 tools::Time aTime( 0, 0, 0 );
2344
2345 if ( rStr.empty() )
2346 return false;
2347
2348 // Search for separators
2349 if (!rLocaleDataWrapper.getTimeSep().isEmpty())
2350 {
2351 OUStringBuffer aSepStr(",.;:/");
2352 if ( !bDuration )
2353 aSepStr.append('-');
2354
2355 // Replace characters above by the separator character
2356 for (sal_Int32 i = 0; i < aSepStr.getLength(); ++i)
2357 {
2358 if (rLocaleDataWrapper.getTimeSep() == OUStringChar(aSepStr[i]))
2359 continue;
2360 for ( sal_Int32 j = 0; j < aStr.getLength(); j++ )
2361 {
2362 if (aStr[j] == aSepStr[i])
2363 aStr[j] = rLocaleDataWrapper.getTimeSep()[0];
2364 }
2365 }
2366 }
2367
2368 bool bNegative = false;
2369 sal_Int32 nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2370 if ( aStr[0] == '-' )
2371 bNegative = true;
2372 if ( eFormat != TimeFieldFormat::F_SEC_CS )
2373 {
2374 if ( nSepPos < 0 )
2375 nSepPos = aStr.getLength();
2376 if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nHour ) )
2377 return false;
2378
2379 nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2380 if ( !aStr.isEmpty() && aStr[0] == '-' )
2381 bNegative = true;
2382 if ( nSepPos >= 0 )
2383 {
2384 if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nMinute ) )
2385 return false;
2386
2387 nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2388 if ( !aStr.isEmpty() && aStr[0] == '-' )
2389 bNegative = true;
2390 if ( nSepPos >= 0 )
2391 {
2392 if ( !ImplCutTimePortion( aStr, nSepPos, _bSkipInvalidCharacters, &nSecond ) )
2393 return false;
2394 if ( !aStr.isEmpty() && aStr[0] == '-' )
2395 bNegative = true;
2396 nNanoSec = o3tl::toInt64(aStr);
2397 }
2398 else
2399 nSecond = static_cast<short>(o3tl::toInt32(aStr));
2400 }
2401 else
2402 nMinute = static_cast<short>(o3tl::toInt32(aStr));
2403 }
2404 else if ( nSepPos < 0 )
2405 {
2406 nSecond = static_cast<short>(o3tl::toInt32(aStr));
2407 nMinute += nSecond / 60;
2408 nSecond %= 60;
2409 nHour += nMinute / 60;
2410 nMinute %= 60;
2411 }
2412 else
2413 {
2414 nSecond = static_cast<short>(o3tl::toInt32(aStr.subView( 0, nSepPos )));
2415 aStr.remove( 0, nSepPos+1 );
2416
2417 nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2418 if ( !aStr.isEmpty() && aStr[0] == '-' )
2419 bNegative = true;
2420 if ( nSepPos >= 0 )
2421 {
2422 nMinute = nSecond;
2423 nSecond = static_cast<short>(o3tl::toInt32(aStr.subView( 0, nSepPos )));
2424 aStr.remove( 0, nSepPos+1 );
2425
2426 nSepPos = aStr.indexOf( rLocaleDataWrapper.getTimeSep() );
2427 if ( !aStr.isEmpty() && aStr[0] == '-' )
2428 bNegative = true;
2429 if ( nSepPos >= 0 )
2430 {
2431 nHour = nMinute;
2432 nMinute = nSecond;
2433 nSecond = static_cast<short>(o3tl::toInt32(aStr.subView( 0, nSepPos )));
2434 aStr.remove( 0, nSepPos+1 );
2435 }
2436 else
2437 {
2438 nHour += nMinute / 60;
2439 nMinute %= 60;
2440 }
2441 }
2442 else
2443 {
2444 nMinute += nSecond / 60;
2445 nSecond %= 60;
2446 nHour += nMinute / 60;
2447 nMinute %= 60;
2448 }
2449 nNanoSec = o3tl::toInt64(aStr);
2450 }
2451
2452 if ( nNanoSec )
2453 {
2454 assert(aStr.getLength() >= 1);
2455
2456 sal_Int32 nLen = 1; // at least one digit, otherwise nNanoSec==0
2457
2458 while ( aStr.getLength() > nLen && aStr[nLen] >= '0' && aStr[nLen] <= '9' )
2459 nLen++;
2460
2461 while ( nLen < 9)
2462 {
2463 nNanoSec *= 10;
2464 ++nLen;
2465 }
2466 while ( nLen > 9 )
2467 {
2468 // round if negative?
2469 nNanoSec = (nNanoSec + 5) / 10;
2470 --nLen;
2471 }
2472 }
2473
2474 assert(nNanoSec > -1000000000 && nNanoSec < 1000000000);
2475 if ( (nMinute > 59) || (nSecond > 59) || (nNanoSec > 1000000000) )
2476 return false;
2477
2478 if ( eFormat == TimeFieldFormat::F_NONE )
2479 nSecond = nNanoSec = 0;
2480 else if ( eFormat == TimeFieldFormat::F_SEC )
2481 nNanoSec = 0;
2482
2483 if ( !bDuration )
2484 {
2485 if ( bNegative || (nHour < 0) || (nMinute < 0) ||
2486 (nSecond < 0) || (nNanoSec < 0) )
2487 return false;
2488
2489 OUString aUpperCaseStr = aStr.toString().toAsciiUpperCase();
2490 OUString aAMlocalised(rLocaleDataWrapper.getTimeAM().toAsciiUpperCase());
2491 OUString aPMlocalised(rLocaleDataWrapper.getTimePM().toAsciiUpperCase());
2492
2493 if ( (nHour < 12) && ( ( aUpperCaseStr.indexOf( "PM" ) >= 0 ) || ( aUpperCaseStr.indexOf( aPMlocalised ) >= 0 ) ) )
2494 nHour += 12;
2495
2496 if ( (nHour == 12) && ( ( aUpperCaseStr.indexOf( "AM" ) >= 0 ) || ( aUpperCaseStr.indexOf( aAMlocalised ) >= 0 ) ) )
2497 nHour = 0;
2498
2499 aTime = tools::Time( static_cast<sal_uInt16>(nHour), static_cast<sal_uInt16>(nMinute), static_cast<sal_uInt16>(nSecond),
2500 static_cast<sal_uInt32>(nNanoSec) );
2501 }
2502 else
2503 {
2504 assert( !bNegative || (nHour < 0) || (nMinute < 0) ||
2505 (nSecond < 0) || (nNanoSec < 0) );
2506 if ( bNegative || (nHour < 0) || (nMinute < 0) ||
2507 (nSecond < 0) || (nNanoSec < 0) )
2508 {
2509 // LEM TODO: this looks weird... I think buggy when parsing "05:-02:18"
2510 bNegative = true;
2511 nHour = nHour < 0 ? -nHour : nHour;
2512 nMinute = nMinute < 0 ? -nMinute : nMinute;
2513 nSecond = nSecond < 0 ? -nSecond : nSecond;
2514 nNanoSec = nNanoSec < 0 ? -nNanoSec : nNanoSec;
2515 }
2516
2517 aTime = tools::Time( static_cast<sal_uInt16>(nHour), static_cast<sal_uInt16>(nMinute), static_cast<sal_uInt16>(nSecond),
2518 static_cast<sal_uInt32>(nNanoSec) );
2519 if ( bNegative )
2520 aTime = -aTime;
2521 }
2522
2523 rTime = aTime;
2524
2525 return true;
2526}
2527
2528void TimeFormatter::ImplTimeReformat( std::u16string_view rStr, OUString& rOutStr )
2529{
2530 tools::Time aTime( 0, 0, 0 );
2531 if ( !TextToTime( rStr, aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper() ) )
2532 return;
2533
2534 tools::Time aTempTime = aTime;
2535 if ( aTempTime > GetMax() )
2536 aTempTime = GetMax() ;
2537 else if ( aTempTime < GetMin() )
2538 aTempTime = GetMin();
2539
2540 bool bSecond = false;
2541 bool b100Sec = false;
2542 if ( meFormat != TimeFieldFormat::F_NONE )
2543 bSecond = true;
2544
2545 if ( meFormat == TimeFieldFormat::F_SEC_CS )
2546 {
2547 sal_uLong n = aTempTime.GetHour() * 3600L;
2548 n += aTempTime.GetMin() * 60L;
2549 n += aTempTime.GetSec();
2550 rOutStr = OUString::number( n );
2551 rOutStr += ImplGetLocaleDataWrapper().getTime100SecSep();
2552 std::ostringstream ostr;
2553 ostr.fill('0');
2554 ostr.width(9);
2555 ostr << aTempTime.GetNanoSec();
2556 rOutStr += OUString::createFromAscii(ostr.str());
2557 }
2558 else if ( mbDuration )
2559 rOutStr = ImplGetLocaleDataWrapper().getDuration( aTempTime, bSecond, b100Sec );
2560 else
2561 {
2562 rOutStr = ImplGetLocaleDataWrapper().getTime( aTempTime, bSecond, b100Sec );
2563 if ( GetTimeFormat() == TimeFormat::Hour12 )
2564 {
2565 if ( aTempTime.GetHour() > 12 )
2566 {
2567 tools::Time aT( aTempTime );
2568 aT.SetHour( aT.GetHour() % 12 );
2569 rOutStr = ImplGetLocaleDataWrapper().getTime( aT, bSecond, b100Sec );
2570 }
2571 // Don't use LocaleDataWrapper, we want AM/PM
2572 if ( aTempTime.GetHour() < 12 )
2573 rOutStr += "AM"; // ImplGetLocaleDataWrapper().getTimeAM();
2574 else
2575 rOutStr += "PM"; // ImplGetLocaleDataWrapper().getTimePM();
2576 }
2577 }
2578}
2579
2580bool TimeFormatter::ImplAllowMalformedInput() const
2581{
2582 return !IsEnforceValidValue();
2583}
2584
2585int TimeFormatter::GetTimeArea(TimeFieldFormat eFormat, std::u16string_view rText, int nCursor,
2586 const LocaleDataWrapper& rLocaleDataWrapper)
2587{
2588 int nTimeArea = 0;
2589
2590 // Area search
2591 if (eFormat != TimeFieldFormat::F_SEC_CS)
2592 {
2593 //Which area is the cursor in of HH:MM:SS.TT
2594 for ( size_t i = 1, nPos = 0; i <= 4; i++ )
2595 {
2596 size_t nPos1 = rText.find(rLocaleDataWrapper.getTimeSep(), nPos);
2597 size_t nPos2 = rText.find(rLocaleDataWrapper.getTime100SecSep(), nPos);
2598 //which ever comes first, bearing in mind that one might not be there
2599 if (nPos1 != std::u16string_view::npos && nPos2 != std::u16string_view::npos)
2600 nPos = std::min(nPos1, nPos2);
2601 else if (nPos1 != std::u16string_view::npos)
2602 nPos = nPos1;
2603 else
2604 nPos = nPos2;
2605 if (nPos == std::u16string_view::npos || static_cast<sal_Int32>(nPos) >= nCursor)
2606 {
2607 nTimeArea = i;
2608 break;
2609 }
2610 else
2611 nPos++;
2612 }
2613 }
2614 else
2615 {
2616 size_t nPos = rText.find(rLocaleDataWrapper.getTime100SecSep());
2617 if (nPos == std::u16string_view::npos || static_cast<sal_Int32>(nPos) >= nCursor)
2618 nTimeArea = 3;
2619 else
2620 nTimeArea = 4;
2621 }
2622
2623 return nTimeArea;
2624}
2625
2626tools::Time TimeFormatter::SpinTime(bool bUp, const tools::Time& rTime, TimeFieldFormat eFormat,
2627 bool bDuration, std::u16string_view rText, int nCursor,
2628 const LocaleDataWrapper& rLocaleDataWrapper)
2629{
2630 tools::Time aTime(rTime);
2631
2632 int nTimeArea = GetTimeArea(eFormat, rText, nCursor, rLocaleDataWrapper);
2633
2634 if ( nTimeArea )
2635 {
2636 tools::Time aAddTime( 0, 0, 0 );
2637 if ( nTimeArea == 1 )
2638 aAddTime = tools::Time( 1, 0 );
2639 else if ( nTimeArea == 2 )
2640 aAddTime = tools::Time( 0, 1 );
2641 else if ( nTimeArea == 3 )
2642 aAddTime = tools::Time( 0, 0, 1 );
2643 else if ( nTimeArea == 4 )
2644 aAddTime = tools::Time( 0, 0, 0, 1 );
2645
2646 if ( !bUp )
2647 aAddTime = -aAddTime;
2648
2649 aTime += aAddTime;
2650 if (!bDuration)
2651 {
2652 tools::Time aAbsMaxTime( 23, 59, 59, 999999999 );
2653 if ( aTime > aAbsMaxTime )
2654 aTime = aAbsMaxTime;
2655 tools::Time aAbsMinTime( 0, 0 );
2656 if ( aTime < aAbsMinTime )
2657 aTime = aAbsMinTime;
2658 }
2659 }
2660
2661 return aTime;
2662}
2663
2664void TimeField::ImplTimeSpinArea( bool bUp )
2665{
2666 if ( GetField() )
2667 {
2668 tools::Time aTime( GetTime() );
2669 OUString aText( GetText() );
2670 Selection aSelection( GetField()->GetSelection() );
2671
2672 aTime = TimeFormatter::SpinTime(bUp, aTime, GetFormat(), IsDuration(), aText, aSelection.Max(), ImplGetLocaleDataWrapper());
2673
2674 ImplNewFieldValue( aTime );
2675 }
2676}
2677
2678TimeFormatter::TimeFormatter(Edit* pEdit)
2679 : FormatterBase(pEdit)
2680 , maLastTime(0, 0)
2681 , maMin(0, 0)
2682 , maMax(23, 59, 59, 999999999)
2683 , meFormat(TimeFieldFormat::F_NONE)
2684 , mnTimeFormat(TimeFormat::Hour24) // Should become an ExtTimeFieldFormat in next implementation, merge with mbDuration and meFormat
2685 , mbDuration(false)
2686 , mbEnforceValidValue(true)
2687 , maFieldTime(0, 0)
2688{
2689}
2690
2691TimeFormatter::~TimeFormatter()
2692{
2693}
2694
2695void TimeFormatter::ReformatAll()
2696{
2697 Reformat();
2698}
2699
2700void TimeFormatter::SetMin( const tools::Time& rNewMin )
2701{
2702 maMin = rNewMin;
2703 if ( !IsEmptyFieldValue() )
2704 ReformatAll();
2705}
2706
2707void TimeFormatter::SetMax( const tools::Time& rNewMax )
2708{
2709 maMax = rNewMax;
2710 if ( !IsEmptyFieldValue() )
2711 ReformatAll();
2712}
2713
2714void TimeFormatter::SetTimeFormat( TimeFormat eNewFormat )
2715{
2716 mnTimeFormat = eNewFormat;
2717}
2718
2719
2720void TimeFormatter::SetFormat( TimeFieldFormat eNewFormat )
2721{
2722 meFormat = eNewFormat;
2723 ReformatAll();
2724}
2725
2726void TimeFormatter::SetDuration( bool bNewDuration )
2727{
2728 mbDuration = bNewDuration;
2729 ReformatAll();
2730}
2731
2732void TimeFormatter::SetTime( const tools::Time& rNewTime )
2733{
2734 SetUserTime( rNewTime );
2735 maFieldTime = maLastTime;
2736 SetEmptyFieldValueData( false );
2737}
2738
2739void TimeFormatter::ImplNewFieldValue( const tools::Time& rTime )
2740{
2741 if ( !GetField() )
2742 return;
2743
2744 Selection aSelection = GetField()->GetSelection();
2745 aSelection.Normalize();
2746 OUString aText = GetField()->GetText();
2747
2748 // If selected until the end then keep it that way
2749 if ( static_cast<sal_Int32>(aSelection.Max()) == aText.getLength() )
2750 {
2751 if ( !aSelection.Len() )
2752 aSelection.Min() = SELECTION_MAX;
2753 aSelection.Max() = SELECTION_MAX;
2754 }
2755
2756 tools::Time aOldLastTime = maLastTime;
2757 ImplSetUserTime( rTime, &aSelection );
2758 maLastTime = aOldLastTime;
2759
2760 // Modify at Edit is only set at KeyInput
2761 if ( GetField()->GetText() != aText )
2762 {
2763 GetField()->SetModifyFlag();
2764 GetField()->Modify();
2765 }
2766}
2767
2768OUString TimeFormatter::FormatTime(const tools::Time& rNewTime, TimeFieldFormat eFormat, TimeFormat eHourFormat, bool bDuration, const LocaleDataWrapper& rLocaleData)
2769{
2770 OUString aStr;
2771 bool bSec = false;
2772 bool b100Sec = false;
2773 if ( eFormat != TimeFieldFormat::F_NONE )
2774 bSec = true;
2775 if ( eFormat == TimeFieldFormat::F_SEC_CS )
2776 b100Sec = true;
2777 if ( eFormat == TimeFieldFormat::F_SEC_CS )
2778 {
2779 sal_uLong n = rNewTime.GetHour() * 3600L;
2780 n += rNewTime.GetMin() * 60L;
2781 n += rNewTime.GetSec();
2782 aStr = OUString::number( n ) + rLocaleData.getTime100SecSep();
2783 std::ostringstream ostr;
2784 ostr.fill('0');
2785 ostr.width(9);
2786 ostr << rNewTime.GetNanoSec();
2787 aStr += OUString::createFromAscii(ostr.str());
2788 }
2789 else if ( bDuration )
2790 {
2791 aStr = rLocaleData.getDuration( rNewTime, bSec, b100Sec );
2792 }
2793 else
2794 {
2795 aStr = rLocaleData.getTime( rNewTime, bSec, b100Sec );
2796 if ( eHourFormat == TimeFormat::Hour12 )
2797 {
2798 if ( rNewTime.GetHour() > 12 )
2799 {
2800 tools::Time aT( rNewTime );
2801 aT.SetHour( aT.GetHour() % 12 );
2802 aStr = rLocaleData.getTime( aT, bSec, b100Sec );
2803 }
2804 // Don't use LocaleDataWrapper, we want AM/PM
2805 if ( rNewTime.GetHour() < 12 )
2806 aStr += "AM"; // rLocaleData.getTimeAM();
2807 else
2808 aStr += "PM"; // rLocaleData.getTimePM();
2809 }
2810 }
2811
2812 return aStr;
2813}
2814
2815void TimeFormatter::ImplSetUserTime( const tools::Time& rNewTime, Selection const * pNewSelection )
2816{
2817 tools::Time aNewTime = rNewTime;
2818 if ( aNewTime > GetMax() )
2819 aNewTime = GetMax();
2820 else if ( aNewTime < GetMin() )
2821 aNewTime = GetMin();
2822 maLastTime = aNewTime;
2823
2824 if ( GetField() )
2825 {
2826 OUString aStr = TimeFormatter::FormatTime(aNewTime, meFormat, GetTimeFormat(), mbDuration, ImplGetLocaleDataWrapper());
2827 ImplSetText( aStr, pNewSelection );
2828 }
2829}
2830
2831void TimeFormatter::SetUserTime( const tools::Time& rNewTime )
2832{
2833 ImplSetUserTime( rNewTime );
2834}
2835
2836tools::Time TimeFormatter::GetTime() const
2837{
2838 tools::Time aTime( 0, 0, 0 );
2839
2840 if ( GetField() )
2841 {
2842 bool bAllowMalformed = ImplAllowMalformedInput();
2843 if ( TextToTime( GetField()->GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), !bAllowMalformed ) )
2844 {
2845 if ( aTime > GetMax() )
2846 aTime = GetMax();
2847 else if ( aTime < GetMin() )
2848 aTime = GetMin();
2849 }
2850 else
2851 {
2852 if ( bAllowMalformed )
2853 aTime = tools::Time( 99, 99, 99 ); // set invalid time
2854 else
2855 aTime = maLastTime;
2856 }
2857 }
2858
2859 return aTime;
2860}
2861
2862void TimeFormatter::Reformat()
2863{
2864 if ( !GetField() )
2865 return;
2866
2867 if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
2868 return;
2869
2870 OUString aStr;
2871 ImplTimeReformat( GetField()->GetText(), aStr );
2872
2873 if ( !aStr.isEmpty() )
2874 {
2875 ImplSetText( aStr );
2876 (void)TextToTime(aStr, maLastTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper());
2877 }
2878 else
2879 SetTime( maLastTime );
2880}
2881
2882TimeField::TimeField( vcl::Window* pParent, WinBits nWinStyle ) :
2883 SpinField( pParent, nWinStyle ),
2884 TimeFormatter(this),
2885 maFirst( GetMin() ),
2886 maLast( GetMax() )
2887{
2888 SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, false ) );
2889 Reformat();
2890}
2891
2892void TimeField::dispose()
2893{
2894 ClearField();
2896}
2897
2898bool TimeField::PreNotify( NotifyEvent& rNEvt )
2899{
2900 if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
2901 {
2902 if ( ImplTimeProcessKeyInput( *rNEvt.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
2903 return true;
2904 }
2905
2906 return SpinField::PreNotify( rNEvt );
2907}
2908
2909bool TimeField::EventNotify( NotifyEvent& rNEvt )
2910{
2911 if ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
2912 MarkToBeReformatted( false );
2913 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
2914 {
2915 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
2916 {
2917 if ( !ImplAllowMalformedInput() )
2918 Reformat();
2919 else
2920 {
2921 tools::Time aTime( 0, 0, 0 );
2922 if ( TextToTime( GetText(), aTime, GetFormat(), IsDuration(), ImplGetLocaleDataWrapper(), false ) )
2923 // even with strict text analysis, our text is a valid time -> do a complete
2924 // reformat
2925 Reformat();
2926 }
2927 }
2928 }
2929
2930 return SpinField::EventNotify( rNEvt );
2931}
2932
2933void TimeField::DataChanged( const DataChangedEvent& rDCEvt )
2934{
2935 SpinField::DataChanged( rDCEvt );
2936
2937 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
2938 {
2939 ImplResetLocaleDataWrapper();
2940 ReformatAll();
2941 }
2942}
2943
2944void TimeField::Modify()
2945{
2946 MarkToBeReformatted( true );
2948}
2949
2950void TimeField::Up()
2951{
2952 ImplTimeSpinArea( true );
2953 SpinField::Up();
2954}
2955
2956void TimeField::Down()
2957{
2958 ImplTimeSpinArea( false );
2960}
2961
2962void TimeField::First()
2963{
2964 ImplNewFieldValue( maFirst );
2966}
2967
2968void TimeField::Last()
2969{
2970 ImplNewFieldValue( maLast );
2972}
2973
2974void TimeField::SetExtFormat( ExtTimeFieldFormat eFormat )
2975{
2976 switch ( eFormat )
2977 {
2979 {
2980 SetTimeFormat( TimeFormat::Hour24 );
2981 SetDuration( false );
2983 }
2984 break;
2986 {
2987 SetTimeFormat( TimeFormat::Hour24 );
2988 SetDuration( false );
2990 }
2991 break;
2993 {
2994 SetTimeFormat( TimeFormat::Hour12 );
2995 SetDuration( false );
2997 }
2998 break;
3000 {
3001 SetTimeFormat( TimeFormat::Hour12 );
3002 SetDuration( false );
3004 }
3005 break;
3007 {
3008 SetDuration( true );
3010 }
3011 break;
3013 {
3014 SetDuration( true );
3016 }
3017 break;
3018 default: OSL_FAIL( "ExtTimeFieldFormat unknown!" );
3019 }
3020
3021 if ( GetField() && !GetField()->GetText().isEmpty() )
3022 SetUserTime( GetTime() );
3023 ReformatAll();
3024}
3025
3026TimeBox::TimeBox(vcl::Window* pParent, WinBits nWinStyle)
3027 : ComboBox(pParent, nWinStyle)
3028 , TimeFormatter(this)
3029{
3030 SetText( ImplGetLocaleDataWrapper().getTime( maFieldTime, false ) );
3031 Reformat();
3032}
3033
3034void TimeBox::dispose()
3035{
3036 ClearField();
3038}
3039
3040bool TimeBox::PreNotify( NotifyEvent& rNEvt )
3041{
3042 if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
3043 {
3044 if ( ImplTimeProcessKeyInput( *rNEvt.GetKeyEvent(), IsStrictFormat(), IsDuration(), GetFormat(), ImplGetLocaleDataWrapper() ) )
3045 return true;
3046 }
3047
3048 return ComboBox::PreNotify( rNEvt );
3049}
3050
3051bool TimeBox::EventNotify( NotifyEvent& rNEvt )
3052{
3053 if ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
3054 MarkToBeReformatted( false );
3055 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
3056 {
3057 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
3058 Reformat();
3059 }
3060
3061 return ComboBox::EventNotify( rNEvt );
3062}
3063
3064void TimeBox::DataChanged( const DataChangedEvent& rDCEvt )
3065{
3066 ComboBox::DataChanged( rDCEvt );
3067
3068 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
3069 {
3070 ImplResetLocaleDataWrapper();
3071 ReformatAll();
3072 }
3073}
3074
3075void TimeBox::Modify()
3076{
3077 MarkToBeReformatted( true );
3079}
3080
3081void TimeBox::ReformatAll()
3082{
3083 OUString aStr;
3084 SetUpdateMode( false );
3085 const sal_Int32 nEntryCount = GetEntryCount();
3086 for ( sal_Int32 i=0; i < nEntryCount; ++i )
3087 {
3088 ImplTimeReformat( GetEntry( i ), aStr );
3089 RemoveEntryAt(i);
3090 InsertEntry( aStr, i );
3091 }
3092 TimeFormatter::Reformat();
3093 SetUpdateMode( true );
3094}
3095
3096namespace weld
3097{
3099 {
3100 tools::Time aTime(0);
3101 aTime.MakeTimeFromMS(nValue);
3102 return aTime;
3103 }
3104
3106 {
3107 return rTime.GetMSFromTime();
3108 }
3109
3110 void TimeFormatter::SetTime(const tools::Time& rTime)
3111 {
3112 auto nTime = ConvertValue(rTime);
3113 bool bForceOutput = GetEntryText().isEmpty() && rTime == GetTime();
3114 if (bForceOutput)
3115 {
3116 ImplSetValue(nTime, true);
3117 return;
3118 }
3119 SetValue(nTime);
3120 }
3121
3123 {
3124 return ConvertValue(GetValue());
3125 }
3126
3127 void TimeFormatter::SetMin(const tools::Time& rNewMin)
3128 {
3129 SetMinValue(ConvertValue(rNewMin));
3130 }
3131
3132 void TimeFormatter::SetMax(const tools::Time& rNewMax)
3133 {
3134 SetMaxValue(ConvertValue(rNewMax));
3135 }
3136
3137 OUString TimeFormatter::FormatNumber(int nValue) const
3138 {
3140 return ::TimeFormatter::FormatTime(ConvertValue(nValue), m_eFormat, m_eTimeFormat, m_bDuration, rLocaleData);
3141 }
3142
3144 {
3145 OUString sText = FormatNumber(GetValue());
3146 ImplSetTextImpl(sText, nullptr);
3147 return true;
3148 }
3149
3150 IMPL_LINK(TimeFormatter, ParseInputHdl, sal_Int64*, result, TriState)
3151 {
3152 const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
3153
3154 tools::Time aResult(0);
3155 bool bRet = ::TimeFormatter::TextToTime(GetEntryText(), aResult, m_eFormat, m_bDuration, rLocaleDataWrapper);
3156 if (bRet)
3157 *result = ConvertValue(aResult);
3158
3159 return bRet ? TRISTATE_TRUE : TRISTATE_FALSE;
3160 }
3161
3162 IMPL_LINK(TimeFormatter, CursorChangedHdl, weld::Entry&, rEntry, void)
3163 {
3164 int nStartPos, nEndPos;
3165 rEntry.get_selection_bounds(nStartPos, nEndPos);
3166
3168 const int nTimeArea = ::TimeFormatter::GetTimeArea(m_eFormat, GetEntryText(), nEndPos, rLocaleData);
3169
3170 int nIncrements = 1;
3171
3172 if (nTimeArea == 1)
3173 nIncrements = 1000 * 60 * 60;
3174 else if (nTimeArea == 2)
3175 nIncrements = 1000 * 60;
3176 else if (nTimeArea == 3)
3177 nIncrements = 1000;
3178
3179 SetSpinSize(nIncrements);
3180 }
3181}
3182
3183/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const LocaleDataWrapper & GetLocaleDataWrapper() const
static const AllSettings & GetSettings()
Gets the application's settings.
Definition: svapp.cxx:655
css::uno::Sequence< css::i18n::CalendarItem2 > getGenitiveMonths() const
css::uno::Sequence< css::i18n::CalendarItem2 > getMonths() const
OUString getUniqueID() const
css::uno::Sequence< css::i18n::CalendarItem2 > getPartitiveMonths() const
static bool isLetterNumericType(sal_Int32 nType)
static bool isLetterType(sal_Int32 nType)
static bool isNumericType(sal_Int32 nType)
A widget used to choose from a list of items and which has an entry.
Definition: combobox.hxx:39
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: combobox.cxx:694
virtual void Modify() override
Definition: combobox.cxx:821
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects.
Definition: combobox.cxx:125
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: combobox.cxx:716
DataChangedEventType GetType() const
Definition: event.hxx:362
AllSettingsFlags GetFlags() const
Definition: event.hxx:363
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: field2.cxx:2038
virtual void Up() override
Definition: field2.cxx:2092
Date maLast
Definition: field.hxx:482
Date maFirst
Definition: field.hxx:481
virtual void First() override
Definition: field2.cxx:2104
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects.
Definition: field2.cxx:2019
virtual void Last() override
Definition: field2.cxx:2110
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: field2.cxx:2074
virtual void Modify() override
Definition: field2.cxx:2086
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: field2.cxx:2025
void ImplDateSpinArea(bool bUp)
Definition: field2.cxx:1651
virtual void Down() override
Definition: field2.cxx:2098
DateField(vcl::Window *pParent, WinBits nWinStyle)
Definition: field2.cxx:2008
sal_Int32 GetDate() const
void AddDays(sal_Int32 nAddDays)
sal_Int16 GetYear() const
sal_uInt16 GetDay() const
void AddYears(sal_Int16 nAddYears)
sal_uInt16 GetYearUnsigned() const
void SetYear(sal_Int16 nNewYear)
void AddMonths(sal_Int32 nAddMonths)
sal_uInt16 GetMonth() const
Definition: edit.hxx:56
virtual void Modify()
Definition: edit.cxx:2346
virtual void SetText(const OUString &rStr) override
Definition: edit.cxx:2577
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: edit.cxx:1931
virtual const Selection & GetSelection() const
Definition: edit.cxx:2500
virtual OUString GetText() const override
Definition: edit.cxx:2596
void SetEmptyFieldValue()
Definition: field.cxx:527
bool IsEmptyFieldValue() const
Definition: field.cxx:534
void SetValue(double dVal)
Definition: fmtfield.cxx:861
StaticFormatter m_aStaticFormatter
Definition: formatter.hxx:128
void ImplSetValue(double dValue, bool bForce)
Definition: fmtfield.cxx:740
void ReFormat()
Definition: fmtfield.cxx:688
double GetValue()
Definition: fmtfield.cxx:866
sal_Unicode GetCharCode() const
Definition: event.hxx:56
const vcl::KeyCode & GetKeyCode() const
Definition: event.hxx:57
LanguageType getLanguageType(bool bResolveSystem=true) const
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
css::uno::Sequence< css::i18n::Calendar2 > getAllCalendars() const
const OUString & getDateSep() const
const OUString & getTime100SecSep() const
const OUString & getTimeSep() const
const css::uno::Reference< css::uno::XComponentContext > & getComponentContext() const
const OUString & getTimeAM() const
LanguageTag getLoadedLanguageTag() const
OUString getDuration(const tools::Time &rTime, bool bSec=true, bool b100Sec=false) const
DateOrder getDateOrder() const
const OUString & getTimePM() const
OUString getTime(const tools::Time &rTime, bool bSec=true, bool b100Sec=false) const
LongDateOrder getLongDateOrder() const
const LanguageTag & getLanguageTag() const
const KeyEvent * GetKeyEvent() const
Definition: event.hxx:316
NotifyEventType GetType() const
Definition: event.hxx:308
tools::Long Min() const
tools::Long Len() const
void Normalize()
tools::Long Max() const
virtual void Last()
Definition: spinfld.cxx:374
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:485
virtual void First()
Definition: spinfld.cxx:369
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: spinfld.cxx:836
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:858
virtual void Down()
Definition: spinfld.cxx:364
virtual void Up()
Definition: spinfld.cxx:359
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects.
Definition: spinfld.cxx:352
const LanguageTag & GetLanguageTag() const
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, const Color **ppColor, bool bUseStarFormat=false)
const Date & GetNullDate() const
void ChangeIntl(LanguageType eLnge)
sal_uInt32 GetFormatIndex(NfIndexTableOffset, LanguageType eLnge=LANGUAGE_DONTKNOW)
sal_uInt16 GetSec() const
sal_uInt16 GetMin() const
sal_Int32 GetMSFromTime() const
sal_uInt16 GetHour() const
sal_uInt32 GetNanoSec() const
void MakeTimeFromMS(sal_Int32 nMS)
sal_uInt16 GetGroup() const
Definition: keycod.hxx:62
bool IsMod1() const
Definition: keycod.hxx:56
sal_uInt16 GetCode() const
Definition: keycod.hxx:49
bool IsShift() const
Definition: keycod.hxx:54
bool IsMod2() const
Definition: keycod.hxx:58
void SetShowDateCentury(bool bShowCentury)
Definition: field2.cxx:1846
std::unique_ptr< CalendarWrapper > m_xCalendarWrapper
Definition: weldutils.hxx:358
SAL_DLLPRIVATE OUString FormatNumber(int nValue) const
Definition: field2.cxx:2243
void SetMin(const Date &rNewMin)
Definition: field2.cxx:1766
SAL_DLLPRIVATE CalendarWrapper & GetCalendarWrapper() const
Definition: field2.cxx:1734
ExtDateFieldFormat m_eFormat
Definition: weldutils.hxx:357
void SetDate(const Date &rNewDate)
Definition: field2.cxx:1855
void SetMax(const Date &rNewMax)
Definition: field2.cxx:1773
virtual SAL_DLLPRIVATE void SetMinValue(double dMin) override
Definition: weldutils.cxx:205
virtual SAL_DLLPRIVATE void SetMaxValue(double dMin) override
Definition: weldutils.cxx:219
virtual SAL_DLLPRIVATE OUString GetEntryText() const override
Definition: weldutils.cxx:176
virtual bool get_editable() const =0
virtual void select_region(int nStartPos, int nEndPos)=0
virtual void set_text(const OUString &rText)=0
virtual bool get_selection_bounds(int &rStartPos, int &rEndPos)=0
virtual void set_overwrite_mode(bool bOn)=0
virtual OUString get_text() const =0
SAL_DLLPRIVATE void Modify()
Definition: field2.cxx:958
void SetMask(const OString &rEditMask, const OUString &rLiteralMask)
Definition: field2.cxx:858
Link< weld::Entry &, void > m_aModifyHdl
Definition: weldutils.hxx:386
SAL_DLLPRIVATE void EntryGainFocus()
Definition: field2.cxx:947
void SetStrictFormat(bool bStrict)
Definition: field2.cxx:921
SAL_DLLPRIVATE void EntryLostFocus()
Definition: field2.cxx:952
weld::Entry & m_rEntry
Definition: weldutils.hxx:385
void SetMin(const tools::Time &rNewMin)
Definition: field2.cxx:2700
void SetTime(const tools::Time &rNewTime)
Definition: field2.cxx:2732
SAL_DLLPRIVATE OUString FormatNumber(int nValue) const
Definition: field2.cxx:3137
TimeFormat m_eTimeFormat
Definition: weldutils.hxx:327
void SetMax(const tools::Time &rNewMax)
Definition: field2.cxx:2707
tools::Time GetTime()
Definition: field2.cxx:2836
static SAL_DLLPRIVATE tools::Time ConvertValue(int nValue)
Definition: field2.cxx:3098
TimeFieldFormat m_eFormat
Definition: weldutils.hxx:326
#define DBG_UNHANDLED_EXCEPTION(...)
virtual void SetText(const OUString &rStr) override
virtual SotClipboardFormatId GetFormat(const TransferableDataHelper &aHelper) override
static OUString ImplGetDateSep(const LocaleDataWrapper &rLocaleDataWrapper, ExtDateFieldFormat eFormat)
Definition: field2.cxx:1293
static bool ImplDateProcessKeyInput(const KeyEvent &rKEvt, ExtDateFieldFormat eFormat, const LocaleDataWrapper &rLocaleDataWrapper)
Definition: field2.cxx:1301
#define EDITMASK_UPPERALLCHAR
Definition: field2.cxx:59
static bool ImplCutMonthName(OUString &rStr, std::u16string_view _rLookupMonthName)
Definition: field2.cxx:1204
#define EDITMASK_NUMSPACE
Definition: field2.cxx:57
#define EDITMASK_UPPERALPHA
Definition: field2.cxx:53
static sal_Unicode * ImplAddString(sal_Unicode *pBuf, const OUString &rStr)
Definition: field2.cxx:74
static sal_Unicode * ImplAddSNum(sal_Unicode *pBuf, sal_Int32 nNumber, int nMinLen)
Definition: field2.cxx:116
#define EDITMASK_LITERAL
Definition: field2.cxx:51
static bool ImplCommaPointCharEqual(sal_Unicode c1, sal_Unicode c2)
Definition: field2.cxx:218
static sal_Unicode ImplPatternChar(sal_Unicode cChar, char cEditMask)
Definition: field2.cxx:201
static bool ImplTimeProcessKeyInput(const KeyEvent &rKEvt, bool bStrictFormat, bool bDuration, TimeFieldFormat eFormat, const LocaleDataWrapper &rLocaleDataWrapper)
Definition: field2.cxx:2270
#define EDITMASK_NUM
Definition: field2.cxx:56
static sal_Unicode * ImplAddNum(sal_Unicode *pBuf, sal_uLong nNumber, int nMinLen)
Definition: field2.cxx:81
static void ImplPatternMaxPos(std::u16string_view rStr, const OString &rEditMask, sal_uInt16 nFormatFlags, bool bSameMask, sal_Int32 nCursorPos, sal_Int32 &rPos)
Definition: field2.cxx:328
static sal_uInt16 ImplCutMonthFromString(OUString &rStr, OUString &rCalendarName, const LocaleDataWrapper &rLocaleData, const CalendarWrapper &rCalendarWrapper)
Definition: field2.cxx:1227
static OUString ImplPatternProcessStrictModify(const OUString &rText, const OString &rEditMask, std::u16string_view rLiteralMask, bool bSameMask)
Definition: field2.cxx:368
#define EDITMASK_UPPERALPHANUM
Definition: field2.cxx:55
static bool ImplPatternProcessKeyInput(IEditImplementation &rEdit, const KeyEvent &rKEvt, const OString &rEditMask, std::u16string_view rLiteralMask, bool bStrictFormat, bool bSameMask, bool &rbInKeyInput)
Definition: field2.cxx:523
static bool ImplIsOnlyDigits(const OUString &_rStr)
Definition: field2.cxx:2298
static bool ImplIsValidTimePortion(bool _bSkipInvalidCharacters, const OUString &_rStr)
Definition: field2.cxx:2309
static sal_uInt16 ImplCutNumberFromString(OUString &rStr)
Definition: field2.cxx:1189
#define EDITMASK_ALPHANUM
Definition: field2.cxx:54
static void ImplSkipDelimiters(const sal_Unicode *&rpBuf)
Definition: field2.cxx:145
static sal_uInt16 ImplGetNum(const sal_Unicode *&rpBuf, bool &rbError)
Definition: field2.cxx:126
static ExtDateFieldFormat ImplGetExtFormat(LongDateOrder eOld)
Definition: field2.cxx:1177
static bool ImplCutTimePortion(OUStringBuffer &_rStr, sal_Int32 _nSepPos, bool _bSkipInvalidCharacters, short *_pPortion)
Definition: field2.cxx:2319
static sal_Int32 ImplPatternRightPos(std::u16string_view rStr, const OString &rEditMask, sal_uInt16 nFormatFlags, bool bSameMask, sal_Int32 nCursorPos)
Definition: field2.cxx:485
static void ImplDateIncrementMonth(Date &rDate, bool bUp)
Definition: field2.cxx:1604
static sal_Int32 ImplPatternLeftPos(std::string_view rEditMask, sal_Int32 nCursorPos)
Definition: field2.cxx:468
static bool ImplIsPatternChar(sal_Unicode cChar, char cEditMask)
Definition: field2.cxx:154
#define EDITMASK_ALPHA
Definition: field2.cxx:52
static void ImplDateIncrementYear(Date &rDate, bool bUp)
Definition: field2.cxx:1610
static void ImplDateIncrementDay(Date &rDate, bool bUp)
Definition: field2.cxx:1598
static sal_uInt16 ImplGetMonthFromCalendarItem(OUString &rStr, const uno::Sequence< i18n::CalendarItem2 > &rMonths)
Definition: field2.cxx:1211
uno::Reference< i18n::XCharacterClassification > const & ImplGetCharClass()
Definition: field2.cxx:61
#define EDITMASK_ALLCHAR
Definition: field2.cxx:58
static OUString ImplPatternReformat(const OUString &rStr, const OString &rEditMask, std::u16string_view rLiteralMask, sal_uInt16 nFormatFlags)
Definition: field2.cxx:229
#define PATTERN_FORMAT_EMPTYLITERALS
Definition: field.hxx:527
constexpr OUStringLiteral IsReadOnly(u"IsReadOnly")
OUString FormatNumber(sal_uInt32 nNum, SvxNumType nFormat, LanguageType nLang=LANGUAGE_NONE)
sal_Int16 nValue
#define SELECTION_MAX
TriState
TRISTATE_FALSE
TRISTATE_TRUE
sal_Int32 nIndex
sal_Int64 n
constexpr sal_uInt16 KEY_HOME
Definition: keycodes.hxx:114
constexpr sal_uInt16 KEY_LEFT
Definition: keycodes.hxx:112
constexpr sal_uInt16 KEYGROUP_MISC
Definition: keycodes.hxx:41
constexpr sal_uInt16 KEYGROUP_FKEYS
Definition: keycodes.hxx:39
constexpr sal_uInt16 KEY_RIGHT
Definition: keycodes.hxx:113
constexpr sal_uInt16 KEY_DELETE
Definition: keycodes.hxx:125
constexpr sal_uInt16 KEY_INSERT
Definition: keycodes.hxx:124
constexpr sal_uInt16 KEY_BACKSPACE
Definition: keycodes.hxx:122
constexpr sal_uInt16 KEY_END
Definition: keycodes.hxx:115
constexpr sal_uInt16 KEYGROUP_CURSOR
Definition: keycodes.hxx:40
sal_uInt16 nPos
LongDateOrder
aStr
aBuf
const LanguageTag & getLocale()
OStringBuffer & padToLength(OStringBuffer &rBuffer, sal_Int32 nLength, char cFill='\0')
Reference< XComponentContext > getProcessComponentContext()
int i
index
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
sal_Int64 toInt64(std::u16string_view str, sal_Int16 radix=10)
Any GetTime(const OUString &val)
css::uno::Reference< css::i18n::XCharacterClassification > CreateCharacterClassification()
Definition: unohelp.cxx:43
sal_Int64 ConvertValue(sal_Int64 nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits, FieldUnit eInUnit, FieldUnit eOutUnit)
Definition: field.cxx:1027
IMPL_LINK_NOARG(HexColorControl, OnAsyncModifyHdl, void *, void)
IMPL_LINK(CustomWeld, DoResize, const Size &, rSize, void)
Definition: customweld.cxx:46
const char GetValue[]
QPRO_FUNC_TYPE nType
sal_uIntPtr sal_uLong
css::uno::Reference< css::i18n::XCharacterClassification > m_xCharClass
Definition: svdata.hxx:419
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:77
void SetFormat(LotusContext &rContext, SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt8 nFormat, sal_uInt8 nSt)
sal_uInt16 sal_Unicode
signed char sal_Int8
Any result
void GetSelection(struct ESelection &rSel, SvxTextForwarder const *pForwarder) noexcept
TimeFormat
Definition: vclenum.hxx:122
ExtDateFieldFormat
Definition: vclenum.hxx:135
TimeFieldFormat
Definition: vclenum.hxx:28
ExtTimeFieldFormat
Definition: vclenum.hxx:127
@ Short24H
the first 4 of these are only used by base/dbaccess
sal_Int64 WinBits
Definition: wintypes.hxx:109