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