From 6a98d038575cd24641450ad6f2bc2f9cc16ab134 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Wed, 9 Mar 2011 15:30:54 -0600 Subject: [PATCH] comctl32: Validate text entered in a datetime by the user. --- dlls/comctl32/datetime.c | 190 ++++++++++++++++++++++++++-------------------- 1 files changed, 107 insertions(+), 83 deletions(-) diff --git a/dlls/comctl32/datetime.c b/dlls/comctl32/datetime.c index ed625e9..5406ce1 100644 --- a/dlls/comctl32/datetime.c +++ b/dlls/comctl32/datetime.c @@ -73,6 +73,8 @@ typedef struct BOOL bCalDepressed; /* TRUE = cal button is depressed */ int bDropdownEnabled; int select; + WCHAR charsEntered[4]; + int nCharsEntered; HFONT hFont; int nrFieldsAllocated; int nrFields; @@ -697,6 +699,13 @@ DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc) /* fill if focused */ 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.top = 0; selection.right = size.cx; @@ -756,6 +765,68 @@ static int DATETIME_GetPrevDateField(const DATETIME_INFO *infoPtr, int i) 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; inCharsEntered; 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 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; } } - infoPtr->select = new; + + DATETIME_SetSelectedField(infoPtr, new); if (infoPtr->select == DTHT_MCPOPUP) { RECT rcMonthCal; @@ -962,6 +1034,7 @@ DATETIME_KeyDown (DATETIME_INFO *infoPtr, DWORD vkCode) { int fieldNum = infoPtr->select & DTHT_DATEFIELD; int wrap = 0; + int new; if (!(infoPtr->haveFocus)) return 0; if ((fieldNum==0) && (infoPtr->select)) return 0; @@ -973,40 +1046,50 @@ DATETIME_KeyDown (DATETIME_INFO *infoPtr, DWORD vkCode) switch (vkCode) { case VK_ADD: case VK_UP: + infoPtr->nCharsEntered = 0; DATETIME_IncreaseField (infoPtr, fieldNum, 1); DATETIME_SendDateTimeChangeNotify (infoPtr); break; case VK_SUBTRACT: case VK_DOWN: + infoPtr->nCharsEntered = 0; DATETIME_IncreaseField (infoPtr, fieldNum, -1); DATETIME_SendDateTimeChangeNotify (infoPtr); break; case VK_HOME: + infoPtr->nCharsEntered = 0; DATETIME_IncreaseField (infoPtr, fieldNum, INT_MIN); DATETIME_SendDateTimeChangeNotify (infoPtr); break; case VK_END: + infoPtr->nCharsEntered = 0; DATETIME_IncreaseField (infoPtr, fieldNum, INT_MAX); DATETIME_SendDateTimeChangeNotify (infoPtr); break; case VK_LEFT: + new = infoPtr->select; do { - if (infoPtr->select == 0) { - infoPtr->select = infoPtr->nrFields - 1; + if (new == 0) { + new = new - 1; wrap++; } 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; case VK_RIGHT: + new = infoPtr->select; do { - infoPtr->select++; - if (infoPtr->select==infoPtr->nrFields) { - infoPtr->select = 0; + new++; + if (new==infoPtr->nrFields) { + new = 0; 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; } @@ -1022,80 +1105,20 @@ DATETIME_Char (DATETIME_INFO *infoPtr, WPARAM vkCode) int fieldNum = infoPtr->select & DTHT_DATEFIELD; if (vkCode >= '0' && vkCode <= '9') { - int num = vkCode-'0'; - int newDays; - - /* this is a somewhat simplified version of what Windows does */ - SYSTEMTIME *date = &infoPtr->date; - switch (infoPtr->fieldspec[fieldNum]) { - case ONEDIGITYEAR: - case TWODIGITYEAR: - date->wYear = date->wYear - (date->wYear%100) + - (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 - date->wSecond = (date->wSecond%10)*10+num; - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - } + int maxChars; + int fieldSpec; + + infoPtr->charsEntered[infoPtr->nCharsEntered++] = vkCode; + + fieldSpec = infoPtr->fieldspec[fieldNum]; + + if (fieldSpec == INVALIDFULLYEAR || fieldSpec == FULLYEAR) + maxChars = 4; + else + maxChars = 2; + + if (maxChars == infoPtr->nCharsEntered) + DATETIME_ApplySelectedField(infoPtr); } return 0; } @@ -1133,6 +1156,7 @@ DATETIME_KillFocus (DATETIME_INFO *infoPtr, HWND lostFocus) if (infoPtr->haveFocus) { DATETIME_SendSimpleNotify (infoPtr, NM_KILLFOCUS); infoPtr->haveFocus = 0; + DATETIME_SetSelectedField (infoPtr, -1); } InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); -- 1.7.1