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