Commit 08a4c861 authored by Vincent Povirk's avatar Vincent Povirk Committed by Alexandre Julliard

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

parent 7b0a3128
...@@ -73,6 +73,8 @@ typedef struct ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
MONTHCAL_CalculateDayOfWeek(date, TRUE);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case INVALIDFULLYEAR:
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 else
date->wSecond = (date->wSecond%10)*10+num; maxChars = 2;
DATETIME_SendDateTimeChangeNotify (infoPtr);
break; if (maxChars == infoPtr->nCharsEntered)
} DATETIME_ApplySelectedField(infoPtr);
} }
return 0; return 0;
} }
...@@ -1133,6 +1156,7 @@ DATETIME_KillFocus (DATETIME_INFO *infoPtr, HWND lostFocus) ...@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment