/*********************************************************************** * * FUNCTION: PrvUpdateTimeFields * * DESCRIPTION: Update the current time and new time displayed if they have * changed in the time zone dialog. Also used to update these * times in the daylight saving time dialog. * * PARAMETERS: frm - the time zone or daylight saving time dialog * * RETURNED: nothing * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * peter 4/13/00 Initial Revision * ***********************************************************************/ static void PrvUpdateTimeFields (FormPtr frm, DateTimeType *currentTimeP, DateTimeType *newTimeP, MemHandle currentTimeHandle, MemHandle newTimeHandle, UInt16 currentTimeFieldID, UInt16 newTimeFieldID) { DateTimeType now, then; UInt32 delta; TimSecondsToDateTime(TimGetSeconds(), &now); if (now.minute != currentTimeP->minute || now.hour != currentTimeP->hour || now.day != currentTimeP->day || now.month != currentTimeP->month || now.year != currentTimeP->year) { then = *currentTimeP; *currentTimeP = now; PrvSetTimeField(frm, currentTimeFieldID, currentTimeHandle, currentTimeP, true); if (FldGetTextLength(FrmGetObjectPtr (frm, FrmGetObjectIndex (frm, newTimeFieldID))) != 0) { delta = TimDateTimeToSeconds(newTimeP) - TimDateTimeToSeconds(&then); TimSecondsToDateTime(TimDateTimeToSeconds(currentTimeP) + delta, newTimeP); PrvSetTimeField(frm, newTimeFieldID, newTimeHandle, newTimeP, true); } } } // PrvUpdateTimeFields
//////////////////////////////////////////////////////////////////////// // FUNCTION: TimSetSeconds // // DESCRIPTION: This routine set the clock of the device to the date // and time passed as the number of seconds since 1/1/1904 // // PARAMETERS: (UInt32) seconds - Seconds since 1/1/1904. // // RETURNED: Returns nothing. // // REVISION HISTORY: // Name Date Description // ---- ---- ----------- // Jerry 5/10/01 Initial Revision //////////////////////////////////////////////////////////////////////// void TimSetSeconds (UInt32 seconds) { DateTimeType dateTime; TimSecondsToDateTime (seconds, &dateTime); VSetSystemTime (&dateTime); }
struct tm *localtime(const time_t *timer) { static struct tm tmDate; DateTimeType dt; UInt32 secs = *timer; // get ROM version UInt32 romVersion; Err e = FtrGet(sysFtrCreator, sysFtrNumROMVersion, &romVersion); // form 1/1/1904 12AM to 1/1/1970 12AM DateTimeType Epoch = {0, 0, 0, 1, 1, 1970, 0}; // timer supposed to be based on Epoch secs += TimDateTimeToSeconds(&Epoch); // DST really supported from OS v4.0 if (romVersion >= sysMakeROMVersion(4,0,0,sysROMStageRelease,0)) secs += (PrefGetPreference(prefTimeZone) + PrefGetPreference(prefDaylightSavingAdjustment)) * 60; else secs += (PrefGetPreference(prefMinutesWestOfGMT) - 720) * 60; // no sure about this one TimSecondsToDateTime (secs, &dt); tmDate.tm_sec = dt.second; tmDate.tm_min = dt.minute; tmDate.tm_hour = dt.hour; tmDate.tm_mday = dt.day; tmDate.tm_mon = dt.month - 1; tmDate.tm_year = dt.year - 1900; tmDate.tm_wday = dt.weekDay; return &tmDate; }
ulong time_seconds( void ) { #ifdef UNIX //UNIX: time_t t; time( &t ); return localtime( &t )->tm_sec; #endif #ifndef NONPALM //PALM: DateTimeType t; TimSecondsToDateTime( TimGetSeconds(), &t ); return t.second; #endif #ifdef WIN //WINDOWS: time_t t; time( &t ); return localtime( &t )->tm_sec; #endif #ifdef WINCE //WINDOWS CE: SYSTEMTIME st; GetLocalTime( &st ); return st.wSecond; #endif }
/***************************************************************************** * Function: GadgetDrawHintNext * Complexity: O(N), N = DmNumRecords * * Description: Draw info for closest upcoming event. *****************************************************************************/ void GadgetDrawHintNext(void) { MemHandle m; UInt16 index=0; DateTimeType dt; Boolean found=false, foundFirst=false; UInt16 curTime, curMinTind=0, wantCourse=0, curMinTime=0xFFFF; Int16 diffTime; TimeDBRecord *t; TimSecondsToDateTime(TimGetSeconds(), &dt); if ((dt.weekDay > 0) && (dt.weekDay <= gGadgetDaysNum)) { dt.weekDay = dt.weekDay-1; } else { dt.weekDay = 0; dt.hour = 0; dt.minute = 0; } curTime = dt.weekDay * GADGET_DAYVALUE + dt.hour * 60 + dt.minute; // Search for record nearest in _past_ to current time // NOTE: We assume that the types are sorted "times -> courses"! We use that to reduce everything to ONE while loop while( !found && ((m = DmQueryNextInCategory(DatabaseGetRef(), &index, DatabaseGetCat())) != NULL)) { Char *s=MemHandleLock(m); if (s[0] == TYPE_TIME) { t = (TimeDBRecord *)s; if ( GadgetEventIsVisible(t) ) { if (! foundFirst) { foundFirst = true; curMinTind = index; wantCourse = t->course; } diffTime = (t->day * GADGET_DAYVALUE + t->begin.hours * 60 + t->begin.minutes) - curTime; if ( (diffTime > 0) && (diffTime < curMinTime) ) { curMinTind = index; curMinTime = diffTime; wantCourse = t->course; } } } else if (s[0] == TYPE_COURSE) { CourseDBRecord c; UnpackCourse(&c, s); if (c.id == wantCourse) { gCourseIndex = index; gTimeIndex = curMinTind; found=true; } } MemHandleUnlock(m); index += 1; } if (! found || ! foundFirst) GadgetDrawHintErase(); else GadgetDrawHintCurrent(); }
//////////////////////////////////////////////////////////////////////// // FUNCTION: TimeAdjust // // DESCRIPTION: This routine return a new date +/- the time adjustment. // // PARAMETERS: (DateTimePtr) datetimeP - A DateType structure. // (Int32) adjustment - The Adjustment in seconds. // // RETURNED: Returns nothing. // // REVISION HISTORY: // Name Date Description // ---- ---- ----------- // Jerry 5/10/01 Initial Revision //////////////////////////////////////////////////////////////////////// void TimeAdjust (DateTimePtr datetimeP, Int32 adjustment) { UInt32 seconds; seconds = TimDateTimeToSeconds(datetimeP); seconds += adjustment; TimSecondsToDateTime (seconds, datetimeP); }
/***************************************************************************** * Function: GadgetDrawTimeline * * Description: Draws a line for the current time *****************************************************************************/ void GadgetDrawTimeline(GadgetTimelineDrawType drawType) { DateTimeType dt; TimeType now; TimSecondsToDateTime(TimGetSeconds(), &dt); if (drawType == gtDraw) { now.hours=dt.hour; now.minutes=dt.minute; gGadgetLastTimeline.hours=now.hours; gGadgetLastTimeline.minutes=now.minutes; GadgetDrawWeekdays(); } else { now.hours=gGadgetLastTimeline.hours; now.minutes=gGadgetLastTimeline.minutes; } if ( ((gGadgetCurScreen == GADGET_SCREEN_DAY) && (now.hours >= 8) && (now.hours < 20)) || ((gGadgetCurScreen == GADGET_SCREEN_NIGHT) && ((now.hours < 8) || (now.hours >= 20))) ) { UInt8 y, gadgetWidth; UInt16 gadgetIndex; FormType *frm; RectangleType bounds; RGBColorType red={0x00, 0xFF, 0x00, 0x00}, old; y = GadgetCalcTimeTop(now); frm = FrmGetActiveForm(); gadgetIndex = FrmGetObjectIndex(frm, gGadgetID); FrmGetObjectBounds(frm, gadgetIndex, &bounds); gadgetWidth=gGadgetDaysNum * gGadgetDaysWidth + gGadgetDaysNum - 1; WinInvertLine(bounds.topLeft.x+GADGET_BASELEFT+GADGET_LEFT, bounds.topLeft.y+GADGET_TOP+y, bounds.topLeft.x+GADGET_BASELEFT+GADGET_LEFT+gadgetWidth-1, bounds.topLeft.y+GADGET_TOP+y); if (drawType == gtDraw) { TNSetForeColorRGB(&red, &old); WinDrawPixel(bounds.topLeft.x+GADGET_BASELEFT+GADGET_LEFT+gGadgetDaysNum*gGadgetDaysWidth+gGadgetDaysNum+1, bounds.topLeft.y+GADGET_TOP+y); WinDrawLine(bounds.topLeft.x+GADGET_BASELEFT+GADGET_LEFT+gGadgetDaysNum*gGadgetDaysWidth+gGadgetDaysNum+2, bounds.topLeft.y+GADGET_TOP+y-1, bounds.topLeft.x+GADGET_BASELEFT+GADGET_LEFT+gGadgetDaysNum*gGadgetDaysWidth+gGadgetDaysNum+2, bounds.topLeft.y+GADGET_TOP+y+1); WinDrawLine(bounds.topLeft.x+GADGET_BASELEFT+GADGET_LEFT+gGadgetDaysNum*gGadgetDaysWidth+gGadgetDaysNum+3, bounds.topLeft.y+GADGET_TOP+y-2, bounds.topLeft.x+GADGET_BASELEFT+GADGET_LEFT+gGadgetDaysNum*gGadgetDaysWidth+gGadgetDaysNum+3, bounds.topLeft.y+GADGET_TOP+y+2); TNSetForeColorRGB(&old, NULL); } else if (drawType == gtErase) { RectangleType rect; RctSetRectangle(&rect, bounds.topLeft.x+GADGET_BASELEFT+GADGET_LEFT+gGadgetDaysNum*gGadgetDaysWidth+gGadgetDaysNum+1, bounds.topLeft.y+GADGET_TOP+y-2, bounds.topLeft.x+GADGET_BASELEFT+GADGET_LEFT+gGadgetDaysNum*gGadgetDaysWidth+gGadgetDaysNum+3, bounds.topLeft.y+GADGET_TOP+y+2); WinEraseRectangle(&rect, 0); } } }
/***************************************************************************** * Function: GadgetDrawWeekdays * * Description: Draws the weekdays, extra function since called in * GadgetDrawTimeline *****************************************************************************/ void GadgetDrawWeekdays(void) { UInt8 i; MemHandle mh; Char *text; RGBColorType color, prevColor; DateTimeType now; Int16 dow; RectangleType bounds, rect; UInt16 gadgetIndex; // Get info about Gadget gadgetIndex = FrmGetObjectIndex(gForm, gGadgetID); FrmGetObjectBounds(gForm, gadgetIndex, &bounds); // Initialize time constants TimSecondsToDateTime(TimGetSeconds(), &now); dow = DayOfWeek(now.month, now.day, now.year); RctSetRectangle(&rect, bounds.topLeft.x+GADGET_BASELEFT+GADGET_LEFT, bounds.topLeft.y, 130, FntLineHeight()+2); // Erase background WinEraseRectangle(&rect, 0); for (i=0; i < gGadgetDaysNum; ++i) { Int16 leftoff; mh = DmGetResource(strRsc, GADGET_STRINGS_WDAYSTART+i); text = MemHandleLock(mh); leftoff = (gGadgetDaysWidth+2 - FntLineWidth(text, MemPtrSize(text))) / 2; if (TNisColored() && (dow == i+1)) { color.r = 0xFF; color.g = 0x00; color.b = 0x00; TNSetTextColorRGB(&color, &prevColor); } WinDrawChars(text, StrLen(text), bounds.topLeft.x+GADGET_BASELEFT+GADGET_LEFT+i*gGadgetDaysWidth+i+leftoff+2, bounds.topLeft.y); if (dow == i+1) { if (TNisColored()) { TNSetTextColorRGB(&prevColor, NULL); } else { // Draw some kind of underline to determine current day Int16 lineWidth=FntLineWidth(text, StrLen(text)); WinDrawLine(rect.topLeft.x+i*gGadgetDaysWidth+i+leftoff+1, rect.topLeft.y+FntLineHeight(), rect.topLeft.x+i*gGadgetDaysWidth+i+leftoff+1+lineWidth, rect.topLeft.y+FntLineHeight()); } } MemHandleUnlock(mh); } }
/* Set start and end times from a given seconds */ static void SetSaneTimes(UInt32 secs, TimeType *startP, TimeType *endP) { DateTimeType date_time; TimSecondsToDateTime(secs, &date_time); if (secs % 60) TimAdjust(&date_time, (60 - (secs % 60))); startP->hours = date_time.hour; startP->minutes = date_time.minute; if (startP->hours != 23) { endP->hours = startP->hours+1; endP->minutes = startP->minutes; } else { endP->hours = startP->hours; endP->minutes = 59; } }
static struct tm * palmtimet2unixtm (const time_t t, struct tm *ptm) { DateTimeType dt; memset (&dt, 0, sizeof (dt)); memset (ptm, 0, sizeof (*ptm)); TimSecondsToDateTime (t, &dt); ptm->tm_sec = dt.second; ptm->tm_min = dt.minute; ptm->tm_hour = dt.hour; ptm->tm_mday = dt.day; ptm->tm_mon = dt.month; ptm->tm_year = dt.year; ptm->tm_wday = dt.weekDay; //ptm->tm_wday = DayOfWeek (dt.month, dt.day, dt.year); //ptm->tm_mday = DayOfMonth (dt.month, dt.day, dt.year); return ptm; }
bool_t GetDatePacked(datetime_t t, datepack_t *tp, bool_t Local) { DateTimeType Date; UInt32 ot; if (!tp || t == INVALID_DATETIME_T) return 0; memset(&Date, 0, sizeof(DateTimeType)); ot = DateTimeToPalm(t); if (Local) ot = TimUTCToTimeZone(ot, PrefGetPreference(prefTimeZone), PrefGetPreference(prefDaylightSavingAdjustment)); TimSecondsToDateTime(ot, &Date); tp->Second = Date.second; tp->Minute = Date.minute; tp->Hour = Date.hour; tp->Day = Date.day; tp->Month = Date.month; tp->Year = Date.year; tp->WeekDay = Date.weekDay; return 1; }
static void ExamDetailsFormInit(FormType *frm) { UInt16 selectedCourse=0; ListType *course; ControlType *course_tr, *date_tr, *time_tr; course = GetObjectPtr(LIST_exd_course); course_tr = GetObjectPtr(LIST_exd_course_trigger); date_tr = GetObjectPtr(SELECTOR_exd_date); time_tr = GetObjectPtr(SELECTOR_exd_time); gExamDetailsNumCourses = CountCourses(); gExamDetailsItemList = (Char **) MemPtrNew(gExamDetailsNumCourses * sizeof(Char *)); gExamDetailsItemIDs = (UInt16 *) MemPtrNew(gExamDetailsNumCourses * sizeof(UInt16)); gExamDetailsItemInd = (UInt16 *) MemPtrNew(gExamDetailsNumCourses * sizeof(UInt16)); if (gExamsLastSelRowUID == 0) { // ADD DateTimeType dt; selectedCourse = CourseListGen(gExamDetailsItemList, gExamDetailsItemIDs, gExamDetailsItemInd, gExamDetailsNumCourses, 0, CLIST_SEARCH_INDEX); TimSecondsToDateTime(TimGetSeconds(), &dt); gExamDetailsDate.year=dt.year-MAC_SHIT_YEAR_CONSTANT; gExamDetailsDate.month=dt.month; gExamDetailsDate.day=dt.day; gExamDetailsBegin.hours=14; gExamDetailsBegin.minutes=0; gExamDetailsEnd.hours=15; gExamDetailsEnd.minutes=30; } else { MemHandle mex, mRoom, old; ExamDBRecord *ex; UInt16 index=0; Char *buffer; FieldType *fldRoom; fldRoom=GetObjectPtr(FIELD_exd_room); DmFindRecordByID(DatabaseGetRefN(DB_MAIN), gExamsLastSelRowUID, &index); mex = DmQueryRecord(DatabaseGetRefN(DB_MAIN), index); ex = (ExamDBRecord *)MemHandleLock(mex); selectedCourse = CourseListGen(gExamDetailsItemList, gExamDetailsItemIDs, gExamDetailsItemInd, gExamDetailsNumCourses, ex->course, CLIST_SEARCH_ID); gExamDetailsDate.year=ex->date.year; gExamDetailsDate.month=ex->date.month; gExamDetailsDate.day=ex->date.day; gExamDetailsBegin.hours=ex->begin.hours; gExamDetailsBegin.minutes=ex->begin.minutes; gExamDetailsEnd.hours=ex->end.hours; gExamDetailsEnd.minutes=ex->end.minutes; // Copy contents to the memory handle mRoom=MemHandleNew(StrLen(ex->room)+1); buffer=(Char *)MemHandleLock(mRoom); MemSet(buffer, MemPtrSize(buffer), 0); StrNCopy(buffer, ex->room, StrLen(ex->room)); MemHandleUnlock(mRoom); // Load fields old = FldGetTextHandle(fldRoom); FldSetTextHandle(fldRoom, mRoom); if (old != NULL) MemHandleFree(old); MemHandleUnlock(mex); } LstSetListChoices(course, gExamDetailsItemList, gExamDetailsNumCourses); if (gExamDetailsNumCourses < 5) LstSetHeight(course, gExamDetailsNumCourses); else LstSetHeight(course, 5); LstSetSelection(course, selectedCourse); CtlSetLabel(course_tr, LstGetSelectionText(course, selectedCourse)); ExamDetailsSetTriggers(date_tr, time_tr); EditTimeSetSelectorText(time_tr, &gExamDetailsBegin, &gExamDetailsEnd, gExamDetailsTimeTrigger); }
void PrivDrawCell(void* table, Int16 row, Int16 column, RectanglePtr bounds) { char string[50]; FontID font = stdFont; if (g_CurrentRow != row) { if (g_CurrentMemHandle) { MemHandleUnlock(g_CurrentMemHandle); g_CurrentMemHandle = NULL; } } if (g_CurrentMemHandle == NULL) { Err err = GetSMSRecord(g_SmsDb, g_SelectedCategory, row + g_CurrentPage * TABLE_PAGE_SIZE, g_CurrentRecord, g_CurrentMemHandle, true); if (err) return; g_CurrentRow = row; } switch(column) { case 0: StrCopy(string, ""); if (g_SelectedCategory == CAT_INBOX) { if (IsRecordRead(&g_CurrentRecord)) { StrCopy(string, ""); } else { font = symbolFont; StrCopy(string, "\020"); } } else if (g_SelectedCategory == CAT_SENT) { if (IsRecordRequestReport(&g_CurrentRecord)) { font = symbolFont; if (IsRecordDelivered(&g_CurrentRecord)) { StrCopy(string, "\026"); } else { StrCopy(string, "\024"); } } } break; case 1: StrNCopy(string, g_CurrentRecord.personName, 48); if (StrLen(string) == 0) { StrNCopy(string, g_CurrentRecord.phoneNumber, 48); } break; case 2: StrNCopy(string, g_CurrentRecord.content, 48); break; case 3: { DateTimeType smsDatetime; TimSecondsToDateTime(g_CurrentRecord.time, &smsDatetime); UInt32 nowSeconds = TimGetSeconds(); DateTimeType nowDatetime; TimSecondsToDateTime(nowSeconds, &nowDatetime); if ((nowDatetime.year == smsDatetime.year) && (nowDatetime.month == smsDatetime.month) && (nowDatetime.day == smsDatetime.day)) { TimeToAscii(smsDatetime.hour, smsDatetime.minute, tfColon24h, string); } else { StrCopy(string, DayOfWeekInChinese[DayOfWeek(smsDatetime.month, smsDatetime.day, smsDatetime.year)]); DateTemplateToAscii(" ^3z-^0z", smsDatetime.month, smsDatetime.day, smsDatetime.year, string + 2, 47); } MemHandleUnlock(g_CurrentMemHandle); g_CurrentMemHandle = NULL; } break; default: StrCopy(string, ""); } WinPushDrawState(); RGBColorType foreColor, backColor; foreColor.index = 0; backColor.index = 0; if ((row == g_CurrentSelection) && (column != 0)) { foreColor.r = 255; foreColor.g = 255; foreColor.b = 255; backColor.r = 10; backColor.g = 36; backColor.b = 106; } else if (row % 2 == 0) { backColor.r = 255; backColor.g = 255; backColor.b = 255; foreColor.r = 0; foreColor.g = 0; foreColor.b = 0; } else { backColor.r = 220; backColor.g = 220; backColor.b = 220; foreColor.r = 0; foreColor.g = 0; foreColor.b = 0; } WinSetForeColorRGB(&foreColor, NULL); WinSetTextColorRGB(&foreColor, NULL); WinSetBackColorRGB(&backColor, NULL); WinSetUnderlineMode(noUnderline); FntSetFont(font); Int16 width = bounds->extent.x - 2; Int16 len = StrLen(string); Boolean noFit = false; FntCharsInWidth(string, &width, &len, &noFit); UInt16 x = bounds->topLeft.x; UInt16 y = bounds->topLeft.y; bounds->topLeft.x += - 1; bounds->topLeft.y += 0; bounds->extent.x += 2; bounds->extent.y += 0; WinEraseRectangle(bounds, 0); WinDrawGrayLine( bounds->topLeft.x + bounds->extent.x - 2, bounds->topLeft.y, bounds->topLeft.x + bounds->extent.x - 2, bounds->topLeft.y + bounds->extent.y);// - 2); WinDrawChars(string, len, x, y); WinPopDrawState(); }
/*********************************************************************** * * FUNCTION: NextRepeat * * DESCRIPTION: This routine computes the date of the next * occurrence of a repeating appointment. * * PARAMETERS: rec - a pointer to a DiddleBug record * date - passed: date to start from * returned: date of next occurrence * * RETURNED: true if the appointment occurs again * ***********************************************************************/ Boolean NextRepeat(DiddleBugRecordType* rec, DateTimeType* dateP) { /* ** Get the frequency on occurrence **(ex: every 2nd day, every 3rd month, etc). */ const UInt16 freq = rec->repeatInfo.repeatFrequency; Int16 i = 0; UInt16 day; UInt16 year; UInt16 adjust; UInt16 weeksDiff; UInt16 monthsDiff; UInt16 daysInMonth; UInt16 dayOfWeek; UInt16 apptWeekDay; UInt16 firstDayOfWeek; UInt16 daysTilNext; UInt16 monthsTilNext; UInt32 dateInDays; UInt32 startInDays; DateType start, date, when, next; DateTimeType nextReal; UInt32 startSecs, nextSecs; DateSecondsToDate(TimDateTimeToSeconds(dateP), &date); TimSecondsToDateTime(rec->alarmSecs, &nextReal); nextReal.year = dateP->year; nextReal.month = dateP->month; nextReal.day = dateP->day; nextReal.weekDay = dateP->weekDay; /* Calculate alarm date */ DateSecondsToDate(rec->alarmSecs, &when); /* Is the date passed after the end date of the appointment? */ if (DateCompare(date, rec->repeatInfo.repeatEndDate) > 0) return false; /* Is the date passed before the start date of the appointment? */ if (DateCompare(date, when) < 0) date = when; /* Get the date of the first occurrecne of the appointment. */ start = when; switch (rec->repeatInfo.repeatType) { /* Hourly repeating appointment */ case repeatHourly: startSecs = TimDateTimeToSeconds(dateP); nextSecs = rec->alarmSecs; while (nextSecs < startSecs) nextSecs += freq * hoursInSeconds; TimSecondsToDateTime(nextSecs, &nextReal); DateSecondsToDate(nextSecs, &next); break; /* Daily repeating appointment. */ case repeatDaily: dateInDays = DateToDays(date); startInDays = DateToDays(start); daysTilNext = (dateInDays - startInDays + freq - 1) / freq * freq; if (startInDays + daysTilNext > (UInt32) maxDays) return false; DateDaysToDate (startInDays + daysTilNext, &next); break; /* ** Weekly repeating appointment (ex: every Monday and Friday). ** Yes, weekly repeating appointment can occur more then once a ** week. */ case repeatWeekly: dateInDays = DateToDays(date); startInDays = DateToDays(start); firstDayOfWeek = (DayOfWeek (1, 1, firstYear) - rec->repeatInfo.repeatStartOfWeek + daysInWeek) % daysInWeek; dayOfWeek = DayOfWeek(date.month, date.day, date.year+firstYear); apptWeekDay = (dayOfWeek - rec->repeatInfo.repeatStartOfWeek + daysInWeek) % daysInWeek; /* ** Are we in a week in which the appointment occurrs, if not ** move to that start of the next week in which the appointment ** does occur. */ weeksDiff = (((dateInDays + firstDayOfWeek) / daysInWeek) - ((startInDays + firstDayOfWeek) / daysInWeek)) % freq; if (weeksDiff) { adjust = ((freq - weeksDiff) * daysInWeek) - apptWeekDay; apptWeekDay = 0; dayOfWeek = (dayOfWeek + adjust) % daysInWeek; } else { adjust = 0; } /* Find the next day on which the appointment repeats. */ for (; i < daysInWeek; i++) { if (rec->repeatInfo.repeatOn & (1 << dayOfWeek)) break; adjust++; if (++dayOfWeek == daysInWeek) dayOfWeek = 0; if (++apptWeekDay == daysInWeek) adjust += (freq - 1) * daysInWeek; } if (dateInDays + adjust > (UInt32) maxDays) return false; DateDaysToDate (dateInDays + adjust, &next); break; /* ** Monthly-by-day repeating appointment ** (ex: the 3rd Friday of every month). */ case repeatMonthlyByDay: /* Compute the number of month until the appointment repeats again. */ monthsTilNext = ((((date.year - start.year) * monthsInYear) + (date.month - start.month)) + freq - 1) / freq * freq; while (true) { year = start.year + (start.month - 1 + monthsTilNext) / monthsInYear; if (year >= numberOfYears) return false; next.year = year; next.month = (start.month - 1 + monthsTilNext) % monthsInYear + 1; dayOfWeek = DayOfWeek (next.month, 1, next.year+firstYear); if ((rec->repeatInfo.repeatOn % daysInWeek) >= dayOfWeek) day = rec->repeatInfo.repeatOn - dayOfWeek + 1; else day = rec->repeatInfo.repeatOn + daysInWeek - dayOfWeek + 1; /* ** If repeat-on day is between the last sunday and the last ** saturday, make sure we're not passed the end of the month. */ if ( (rec->repeatInfo.repeatOn >= domLastSun) && (day > DaysInMonth (next.month, next.year+firstYear))) { day -= daysInWeek; } next.day = day; /* ** Its posible that "next date" calculated above is ** before the date passed. If so, move forward ** by the length of the repeat freguency and preform ** the calculation again. */ if (DateToInt(date) > DateToInt(next)) monthsTilNext += freq; else break; } break; /* ** Monthly-by-date repeating appointment ** (ex: the 15th of every month). */ case repeatMonthlyByDate: /* Compute the number of month until the appointment repeats again. */ monthsDiff = (date.year - start.year) * monthsInYear + date.month - start.month; monthsTilNext = (monthsDiff + freq - 1) / freq * freq; if (date.day > start.day && !(monthsDiff % freq)) monthsTilNext += freq; year = start.year + (start.month - 1 + monthsTilNext) / monthsInYear; if (year >= numberOfYears) return false; next.year = year; next.month = (start.month - 1 + monthsTilNext) % monthsInYear + 1; next.day = start.day; /* Make sure we're not passed the last day of the month. */ daysInMonth = DaysInMonth(next.month, next.year+firstYear); if (next.day > daysInMonth) next.day = daysInMonth; break; /* Yearly repeating appointment. */ case repeatYearly: next.day = start.day; next.month = start.month; year = start.year + ((date.year - start.year + freq - 1) / freq * freq); if (date.month > start.month || (date.month == start.month && date.day > start.day)) year += freq; /* Specal leap day processing. */ if (next.month == february && next.day == 29 && next.day > DaysInMonth(next.month, year+firstYear)) { next.day = DaysInMonth (next.month, year+firstYear); } if (year >= numberOfYears) return false; next.year = year; break; default: /* ignore */ } /* Is the next occurrence after the end date of the appointment? */ if (DateCompare(next, rec->repeatInfo.repeatEndDate) > 0) return false; dateP->day = next.day; dateP->month = next.month; dateP->year = next.year + firstYear; dateP->hour = nextReal.hour; dateP->minute = nextReal.minute; dateP->second = nextReal.second; return true; }
UInt32 ApptGetAlarmTime (ApptDBRecordPtr apptRec, UInt32 currentTime) { UInt32 advance = 0; UInt32 alarmTime; DateType repeatDate; DateTimeType curDateTime; DateTimeType apptDateTime; if (!apptRec->alarm) { return apptNoTime; } // Non-repeating appointment? if (! apptRec->repeat) { // An alarm on an untimed event triggers at midnight. if (TimeToInt (apptRec->when->startTime) == apptNoTime) { apptDateTime.minute = 0; apptDateTime.hour = 0; } else { apptDateTime.minute = apptRec->when->startTime.minutes; apptDateTime.hour = apptRec->when->startTime.hours; } apptDateTime.second = 0; apptDateTime.day = apptRec->when->date.day; apptDateTime.month = apptRec->when->date.month; apptDateTime.year = apptRec->when->date.year + firstYear; // Compute the time of the alarm by adjusting the date and time // of the appointment by the length of the advance notice. advance = apptRec->alarm->advance; switch (apptRec->alarm->advanceUnit) { case aauMinutes: advance *= minutesInSeconds; break; case aauHours: advance *= hoursInSeconds; break; case aauDays: advance *= daysInSeconds; break; } alarmTime = TimDateTimeToSeconds (&apptDateTime) - advance; if (alarmTime >= currentTime) return (alarmTime); else return (0); } // Repeating appointment. TimSecondsToDateTime (currentTime, &curDateTime); repeatDate.year = curDateTime.year - firstYear; repeatDate.month = curDateTime.month; repeatDate.day = curDateTime.day; while (ApptNextRepeat (apptRec, &repeatDate)) { // An alarm on an untimed event triggers at midnight. if (TimeToInt (apptRec->when->startTime) == apptNoTime) { apptDateTime.minute = 0; apptDateTime.hour = 0; } else { apptDateTime.minute = apptRec->when->startTime.minutes; apptDateTime.hour = apptRec->when->startTime.hours; } apptDateTime.second = 0; apptDateTime.day = repeatDate.day; apptDateTime.month = repeatDate.month; apptDateTime.year = repeatDate.year + firstYear; // Compute the time of the alarm by adjusting the date and time // of the appointment by the length of the advance notice. switch (apptRec->alarm->advanceUnit) { case aauMinutes: advance = (UInt32) apptRec->alarm->advance * minutesInSeconds; break; case aauHours: advance = (UInt32) apptRec->alarm->advance * hoursInSeconds; break; case aauDays: advance = (UInt32) apptRec->alarm->advance * daysInSeconds; break; } alarmTime = TimDateTimeToSeconds (&apptDateTime) - advance; if (alarmTime >= currentTime) return (alarmTime); DateAdjust (&repeatDate, 1); } return (0); }
/*********************************************************************** * * FUNCTION: SelectTimeZone * * DESCRIPTION: Display a form showing a time zone and allow the user * to select a different time zone. This is the time zone * dialog as seen in Date & Dime panel * * PARAMETERS: * ioTimeZoneP <-> pointer to time zone to change * ioLocaleInTimeZoneP <-> Ptr to locale found in time zone. * titleP -> String title for the dialog. * showTimes -> True => show current and new times * anyLocale -> True => ignore ioLocaleInTimeZoneP on entry. * * RETURNED: * true if the OK button was pressed (in which case *ioTimeZoneP and * *ioCountryInTimeZoneP might be changed). * * HISTORY: * 03/02/00 peter Created by Peter Epstein. * 04/03/00 peter Allow NULL currentTimeP. * 04/12/00 peter API changed to get rid of trigger text * 04/14/00 peter Update current & new time as time passes * 07/31/00 kwk Use SysTicksPerSecond() routine vs. sysTicksPerSecond macro. * kwk Re-wrote to use set of resources (name, offset, country), * scrollbar vs. arrows, etc. * 08/01/00 kwk Support scroll-to-key. Fixed scrollbar/list sync bugs. * 08/02/00 kwk New API w/ioCountryInTimeZoneP and anyCountry parameters. * kwk Call FrmHandleEvent _after_ our event handling code has * decided that it doesn't want to handle the event, not before. * 08/03/00 kwk Call LstSetListChoices before calling LstGetVisibleItems, * as otherwise accessing the time zone picker from the * Setup app (when <showTimes> is false) gives you a two- * line high display because LstGetVisibleItems returns 0. * 08/18/00 kwk Play error sound if user writes letter that doesn't * match any entries. * kwk Don't select item if doing scroll-to-view for entry * that matches the letter the user wrote. * 08/21/00 kwk Scroll-to-view with text entry now scrolls to the top * of the list, versus the middle. * 10/09/00 peter Get rid of scroll bar and let list do the scrolling. * 11/17/00 CS Change ioCountryInTimeZoneP to ioLocaleInTimeZoneP, * (and anyCountry to anyLocale, but that doesn't matter), * since CountryType is only a UInt8, and this may * change someday. * ***********************************************************************/ Boolean SelectTimeZone(Int16 *ioTimeZoneP, LmLocaleType* ioLocaleInTimeZoneP, const Char *titleP, Boolean showTimes, Boolean anyLocale) { FormType* originalForm; FormType* dialog; EventType event; Boolean confirmed = false; Boolean done = false; Boolean adjustTimes = false; Boolean foundLocale = false; MemHandle currentTimeHandle, newTimeHandle; ListPtr listP; Int16 oldTimeZone, newTimeZone, testTimeZone; LmLocaleType newTimeZoneLocale; Int16 delta, closestDelta, timeZoneIndex, closestIndex; DateTimeType currentTime, newTime; TimeZoneEntryType* tzArrayP; UInt16 numTimeZones; MemHandle tzNamesH; if (showTimes) { TimSecondsToDateTime(TimGetSeconds(), ¤tTime); } oldTimeZone = *ioTimeZoneP; newTimeZone = oldTimeZone; newTimeZoneLocale = *ioLocaleInTimeZoneP; originalForm = FrmGetActiveForm(); dialog = (FormType *) FrmInitForm (TimeZoneDialogForm); listP = FrmGetObjectPtr (dialog, FrmGetObjectIndex (dialog, TimeZoneDialogTimeZoneList)); if (titleP) { FrmSetTitle (dialog, (Char *) titleP); } FrmSetActiveForm (dialog); // We need to call LstSetListChoices before calling LstSetHeight below, as otherwise // LstGetVisibleItems will return 0. tzArrayP = PrvCreateTimeZoneArray(&tzNamesH, &numTimeZones); LstSetListChoices(listP, (Char**)tzArrayP, numTimeZones); if (showTimes) { currentTimeHandle = MemHandleNew(timeStringLength + 1 + dowLongDateStrLength + 1); ErrFatalDisplayIf (!currentTimeHandle, "Out of memory"); newTimeHandle = MemHandleNew(timeStringLength + 1 + dowLongDateStrLength + 1); ErrFatalDisplayIf (!newTimeHandle, "Out of memory"); PrvSetTimeField(dialog, TimeZoneDialogCurrentTimeField, currentTimeHandle, ¤tTime, false); } else { // Hide the current and new time. FrmHideObject(dialog, FrmGetObjectIndex (dialog, TimeZoneDialogCurrentTimeLabel)); FrmHideObject(dialog, FrmGetObjectIndex (dialog, TimeZoneDialogCurrentTimeField)); FrmHideObject(dialog, FrmGetObjectIndex (dialog, TimeZoneDialogNewTimeLabel)); FrmHideObject(dialog, FrmGetObjectIndex (dialog, TimeZoneDialogNewTimeField)); // Make the list show more items to take up extra the space. LstSetHeight(listP, LstGetVisibleItems(listP) + extraTimeZonesToShowWhenNoTimes); } // Find the time zone in the list closest to the current time zone, and that // matches <*ioLocaleInTimeZoneP> if <anyLocale> is false. closestDelta = hoursInMinutes * hoursPerDay; // so big that all others will be smaller for (timeZoneIndex = 0; timeZoneIndex < numTimeZones; timeZoneIndex++) { Boolean checkDelta = anyLocale; testTimeZone = tzArrayP[timeZoneIndex].tzOffset; delta = Abs(testTimeZone - oldTimeZone); if (!anyLocale) { if (tzArrayP[timeZoneIndex].tzCountry == ioLocaleInTimeZoneP->country) { // If we haven't previously found a matching locale, reset the // delta so that this entry overrides any previous best entry. if (!foundLocale) { foundLocale = true; closestDelta = hoursInMinutes * hoursPerDay; } checkDelta = true; } // If we haven't yet found a matching locale, go for the closest delta. else { checkDelta = !foundLocale; } } // If we want to check the time zone delta, do it now. if (checkDelta && (delta < closestDelta)) { closestIndex = timeZoneIndex; closestDelta = delta; } } // Scroll so that time zone is in the center of the screen and select it if it's an exact match. LstSetTopItem(listP, max(0, closestIndex - (LstGetVisibleItems(listP) / 2))); if ((closestDelta == 0) && (anyLocale || foundLocale)) { LstSetSelection(listP, closestIndex); if (showTimes) { newTime = currentTime; PrvSetTimeField(dialog, TimeZoneDialogNewTimeField, newTimeHandle, &newTime, false); } } else { LstSetSelection(listP, noListSelection); } LstSetDrawFunction(listP, PrvTimeZoneListDrawItem); FrmDrawForm (dialog); while (!done) { Boolean handled = false; EvtGetEvent(&event, SysTicksPerSecond()); // so we can update the current and new time if (SysHandleEvent ((EventType *)&event)) { continue; } if (event.eType == nilEvent) { if (showTimes) { PrvUpdateTimeFields( dialog, ¤tTime, &newTime, currentTimeHandle, newTimeHandle, TimeZoneDialogCurrentTimeField, TimeZoneDialogNewTimeField); } } else if (event.eType == ctlSelectEvent) { handled = true; switch (event.data.ctlSelect.controlID) { case TimeZoneDialogOKButton: // Set the new time zone. *ioTimeZoneP = newTimeZone; *ioLocaleInTimeZoneP = newTimeZoneLocale; done = true; confirmed = true; break; case TimeZoneDialogCancelButton: done = true; break; default: ErrNonFatalDisplay("Unknown control in form"); break; } } // User tapped on a time zone in the list. else if (event.eType == lstSelectEvent) { UInt16 localeIndex; ErrNonFatalDisplayIf(event.data.lstSelect.listID != TimeZoneDialogTimeZoneList, "Unknown list in form"); newTimeZone = tzArrayP[event.data.lstSelect.selection].tzOffset; newTimeZoneLocale.country = tzArrayP[event.data.lstSelect.selection].tzCountry; newTimeZoneLocale.language = lmAnyLanguage; if (LmLocaleToIndex(&newTimeZoneLocale, &localeIndex) == errNone) { if (LmGetLocaleSetting( localeIndex, lmChoiceLocale, &newTimeZoneLocale, sizeof(newTimeZoneLocale))) { ErrNonFatalDisplay("Can\'t get locale"); } } adjustTimes = showTimes; handled = true; } else if (event.eType == keyDownEvent) { if (!TxtCharIsHardKey(event.data.keyDown.modifiers, event.data.keyDown.chr)) { // Hard scroll buttons if (EvtKeydownIsVirtual(&event)) { if (event.data.keyDown.chr == vchrPageUp) { handled = true; LstScrollList(listP, winUp, LstGetVisibleItems(listP) - 1); } else if (event.data.keyDown.chr == vchrPageDown) { handled = true; LstScrollList(listP, winDown, LstGetVisibleItems(listP) - 1); } } else if (TxtCharIsPrint(event.data.keyDown.chr)) { Int16 index; handled = true; index = PrvSearchTimeZoneNames(tzArrayP, numTimeZones, event.data.keyDown.chr); if (index != noListSelection) { Int16 delta = index - listP->topItem; if (delta < 0) { LstScrollList(listP, winUp, -delta); } else if (delta > 0) { LstScrollList(listP, winDown, delta); } } else { SndPlaySystemSound(sndError); } } } } else if (event.eType == appStopEvent) { EvtAddEventToQueue (&event); done = true; break; } // If we didn't handle the event, give the form code a crack at it. // This simulates the "normal" method of installing an event handler // for a form, which gets called, and then if it returns false, the // FrmHandleEvent routine gets called. if (!handled) { FrmHandleEvent(dialog, &event); } // If something changed, and we need to update our time display, // do it now. if (adjustTimes) { adjustTimes = false; newTime = currentTime; TimAdjust(&newTime, (Int32)(newTimeZone - oldTimeZone) * minutesInSeconds); PrvSetTimeField(dialog, TimeZoneDialogNewTimeField, newTimeHandle, &newTime, true); } } // end while true if (showTimes) { FldSetTextHandle(FrmGetObjectPtr (dialog, FrmGetObjectIndex (dialog, TimeZoneDialogCurrentTimeField)), NULL); FldSetTextHandle(FrmGetObjectPtr (dialog, FrmGetObjectIndex (dialog, TimeZoneDialogNewTimeField)), NULL); MemHandleFree(currentTimeHandle); MemHandleFree(newTimeHandle); } FrmEraseForm (dialog); FrmDeleteForm (dialog); FrmSetActiveForm(originalForm); PrvDeleteTimeZoneArray(tzArrayP, tzNamesH); return confirmed; } // SelectTimeZone