comctl32: Validate text entered in a datetime by the user.

This commit is contained in:
Vincent Povirk 2011-03-09 15:30:54 -06:00 committed by Alexandre Julliard
parent 7b0a3128fb
commit 08a4c8611b
1 changed files with 106 additions and 82 deletions

View File

@ -73,6 +73,8 @@ typedef struct
BOOL bCalDepressed; /* TRUE = cal button is depressed */ BOOL bCalDepressed; /* TRUE = cal button is depressed */
int bDropdownEnabled; int bDropdownEnabled;
int select; int select;
WCHAR charsEntered[4];
int nCharsEntered;
HFONT hFont; HFONT hFont;
int nrFieldsAllocated; int nrFieldsAllocated;
int nrFields; int nrFields;
@ -697,6 +699,13 @@ DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc)
/* fill if focused */ /* fill if focused */
HBRUSH hbr = CreateSolidBrush (comctl32_color.clrActiveCaption); HBRUSH hbr = CreateSolidBrush (comctl32_color.clrActiveCaption);
if (infoPtr->nCharsEntered)
{
memcpy(txt, infoPtr->charsEntered, infoPtr->nCharsEntered * sizeof(WCHAR));
txt[infoPtr->nCharsEntered] = 0;
GetTextExtentPoint32W (hdc, txt, strlenW(txt), &size);
}
selection.left = 0; selection.left = 0;
selection.top = 0; selection.top = 0;
selection.right = size.cx; selection.right = size.cx;
@ -756,6 +765,68 @@ static int DATETIME_GetPrevDateField(const DATETIME_INFO *infoPtr, int i)
return -1; return -1;
} }
static void
DATETIME_ApplySelectedField (DATETIME_INFO *infoPtr)
{
int fieldNum = infoPtr->select & DTHT_DATEFIELD;
int i, val=0;
SYSTEMTIME date = infoPtr->date;
if (infoPtr->select == -1 || infoPtr->nCharsEntered == 0)
return;
for (i=0; i<infoPtr->nCharsEntered; i++)
val = val * 10 + infoPtr->charsEntered[i] - '0';
infoPtr->nCharsEntered = 0;
switch (infoPtr->fieldspec[fieldNum]) {
case ONEDIGITYEAR:
case TWODIGITYEAR:
date.wYear = date.wYear - (date.wYear%100) + val;
break;
case INVALIDFULLYEAR:
case FULLYEAR:
date.wYear = val;
break;
case ONEDIGITMONTH:
case TWODIGITMONTH:
date.wMonth = val;
break;
case ONEDIGITDAY:
case TWODIGITDAY:
date.wDay = val;
break;
case ONEDIGIT12HOUR:
case TWODIGIT12HOUR:
case ONEDIGIT24HOUR:
case TWODIGIT24HOUR:
/* FIXME: Preserve AM/PM for 12HOUR? */
date.wHour = val;
break;
case ONEDIGITMINUTE:
case TWODIGITMINUTE:
date.wMinute = val;
break;
case ONEDIGITSECOND:
case TWODIGITSECOND:
date.wSecond = val;
break;
}
if (DATETIME_SetSystemTime(infoPtr, GDT_VALID, &date))
DATETIME_SendDateTimeChangeNotify (infoPtr);
}
static void
DATETIME_SetSelectedField (DATETIME_INFO *infoPtr, int select)
{
DATETIME_ApplySelectedField(infoPtr);
infoPtr->select = select;
infoPtr->nCharsEntered = 0;
}
static LRESULT static LRESULT
DATETIME_LButtonDown (DATETIME_INFO *infoPtr, INT x, INT y) DATETIME_LButtonDown (DATETIME_INFO *infoPtr, INT x, INT y)
{ {
@ -784,7 +855,8 @@ DATETIME_LButtonDown (DATETIME_INFO *infoPtr, INT x, INT y)
if (infoPtr->fieldspec[new] == FULLDAY) return 0; if (infoPtr->fieldspec[new] == FULLDAY) return 0;
} }
} }
infoPtr->select = new;
DATETIME_SetSelectedField(infoPtr, new);
if (infoPtr->select == DTHT_MCPOPUP) { if (infoPtr->select == DTHT_MCPOPUP) {
RECT rcMonthCal; RECT rcMonthCal;
@ -962,6 +1034,7 @@ DATETIME_KeyDown (DATETIME_INFO *infoPtr, DWORD vkCode)
{ {
int fieldNum = infoPtr->select & DTHT_DATEFIELD; int fieldNum = infoPtr->select & DTHT_DATEFIELD;
int wrap = 0; int wrap = 0;
int new;
if (!(infoPtr->haveFocus)) return 0; if (!(infoPtr->haveFocus)) return 0;
if ((fieldNum==0) && (infoPtr->select)) return 0; if ((fieldNum==0) && (infoPtr->select)) return 0;
@ -973,40 +1046,50 @@ DATETIME_KeyDown (DATETIME_INFO *infoPtr, DWORD vkCode)
switch (vkCode) { switch (vkCode) {
case VK_ADD: case VK_ADD:
case VK_UP: case VK_UP:
infoPtr->nCharsEntered = 0;
DATETIME_IncreaseField (infoPtr, fieldNum, 1); DATETIME_IncreaseField (infoPtr, fieldNum, 1);
DATETIME_SendDateTimeChangeNotify (infoPtr); DATETIME_SendDateTimeChangeNotify (infoPtr);
break; break;
case VK_SUBTRACT: case VK_SUBTRACT:
case VK_DOWN: case VK_DOWN:
infoPtr->nCharsEntered = 0;
DATETIME_IncreaseField (infoPtr, fieldNum, -1); DATETIME_IncreaseField (infoPtr, fieldNum, -1);
DATETIME_SendDateTimeChangeNotify (infoPtr); DATETIME_SendDateTimeChangeNotify (infoPtr);
break; break;
case VK_HOME: case VK_HOME:
infoPtr->nCharsEntered = 0;
DATETIME_IncreaseField (infoPtr, fieldNum, INT_MIN); DATETIME_IncreaseField (infoPtr, fieldNum, INT_MIN);
DATETIME_SendDateTimeChangeNotify (infoPtr); DATETIME_SendDateTimeChangeNotify (infoPtr);
break; break;
case VK_END: case VK_END:
infoPtr->nCharsEntered = 0;
DATETIME_IncreaseField (infoPtr, fieldNum, INT_MAX); DATETIME_IncreaseField (infoPtr, fieldNum, INT_MAX);
DATETIME_SendDateTimeChangeNotify (infoPtr); DATETIME_SendDateTimeChangeNotify (infoPtr);
break; break;
case VK_LEFT: case VK_LEFT:
new = infoPtr->select;
do { do {
if (infoPtr->select == 0) { if (new == 0) {
infoPtr->select = infoPtr->nrFields - 1; new = new - 1;
wrap++; wrap++;
} else { } else {
infoPtr->select--; new--;
} }
} while ((infoPtr->fieldspec[infoPtr->select] & DT_STRING) && (wrap<2)); } while ((infoPtr->fieldspec[new] & DT_STRING) && (wrap<2));
if (new != infoPtr->select)
DATETIME_SetSelectedField(infoPtr, new);
break; break;
case VK_RIGHT: case VK_RIGHT:
new = infoPtr->select;
do { do {
infoPtr->select++; new++;
if (infoPtr->select==infoPtr->nrFields) { if (new==infoPtr->nrFields) {
infoPtr->select = 0; new = 0;
wrap++; wrap++;
} }
} while ((infoPtr->fieldspec[infoPtr->select] & DT_STRING) && (wrap<2)); } while ((infoPtr->fieldspec[new] & DT_STRING) && (wrap<2));
if (new != infoPtr->select)
DATETIME_SetSelectedField(infoPtr, new);
break; break;
} }
@ -1022,80 +1105,20 @@ DATETIME_Char (DATETIME_INFO *infoPtr, WPARAM vkCode)
int fieldNum = infoPtr->select & DTHT_DATEFIELD; int fieldNum = infoPtr->select & DTHT_DATEFIELD;
if (vkCode >= '0' && vkCode <= '9') { if (vkCode >= '0' && vkCode <= '9') {
int num = vkCode-'0'; int maxChars;
int newDays; int fieldSpec;
/* this is a somewhat simplified version of what Windows does */ infoPtr->charsEntered[infoPtr->nCharsEntered++] = vkCode;
SYSTEMTIME *date = &infoPtr->date;
switch (infoPtr->fieldspec[fieldNum]) { fieldSpec = infoPtr->fieldspec[fieldNum];
case ONEDIGITYEAR:
case TWODIGITYEAR: if (fieldSpec == INVALIDFULLYEAR || fieldSpec == FULLYEAR)
date->wYear = date->wYear - (date->wYear%100) + maxChars = 4;
(date->wYear%10)*10 + num; else
MONTHCAL_CalculateDayOfWeek(date, TRUE); maxChars = 2;
DATETIME_SendDateTimeChangeNotify (infoPtr);
break; if (maxChars == infoPtr->nCharsEntered)
case INVALIDFULLYEAR: DATETIME_ApplySelectedField(infoPtr);
case FULLYEAR:
/* reset current year initialy */
date->wYear = ((date->wYear/1000) ? 0 : 1)*(date->wYear%1000)*10 + num;
MONTHCAL_CalculateDayOfWeek(date, TRUE);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGITMONTH:
case TWODIGITMONTH:
if ((date->wMonth%10) > 1 || num > 2)
date->wMonth = num;
else
date->wMonth = (date->wMonth%10)*10+num;
MONTHCAL_CalculateDayOfWeek(date, TRUE);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGITDAY:
case TWODIGITDAY:
newDays = (date->wDay%10)*10+num;
if (newDays > MONTHCAL_MonthLength(date->wMonth, date->wYear))
date->wDay = num;
else
date->wDay = newDays;
MONTHCAL_CalculateDayOfWeek(date, TRUE);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGIT12HOUR:
case TWODIGIT12HOUR:
if ((date->wHour%10) > 1 || num > 2)
date->wHour = num;
else
date->wHour = (date->wHour%10)*10+num;
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGIT24HOUR:
case TWODIGIT24HOUR:
if ((date->wHour%10) > 2)
date->wHour = num;
else if ((date->wHour%10) == 2 && num > 3)
date->wHour = num;
else
date->wHour = (date->wHour%10)*10+num;
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGITMINUTE:
case TWODIGITMINUTE:
if ((date->wMinute%10) > 5)
date->wMinute = num;
else
date->wMinute = (date->wMinute%10)*10+num;
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGITSECOND:
case TWODIGITSECOND:
if ((date->wSecond%10) > 5)
date->wSecond = num;
else
date->wSecond = (date->wSecond%10)*10+num;
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
}
} }
return 0; return 0;
} }
@ -1133,6 +1156,7 @@ DATETIME_KillFocus (DATETIME_INFO *infoPtr, HWND lostFocus)
if (infoPtr->haveFocus) { if (infoPtr->haveFocus) {
DATETIME_SendSimpleNotify (infoPtr, NM_KILLFOCUS); DATETIME_SendSimpleNotify (infoPtr, NM_KILLFOCUS);
infoPtr->haveFocus = 0; infoPtr->haveFocus = 0;
DATETIME_SetSelectedField (infoPtr, -1);
} }
InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);