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