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

Alexandre Julliard julliard at winehq.org
Thu Mar 10 11:30:24 CST 2011


Module: wine
Branch: master
Commit: 08a4c8611b277d1153b9f4bbad600de6af234d29
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=08a4c8611b277d1153b9f4bbad600de6af234d29

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Wed Mar  9 15:30:54 2011 -0600

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..8269758 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; 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
 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);




More information about the wine-cvs mailing list