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