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