604 lines
16 KiB
C++
604 lines
16 KiB
C++
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
|
|
// DlgTime.cpp : implementation file
|
|
//
|
|
|
|
#include "precomp.h"
|
|
#include "resource.h"
|
|
#include "hmmverr.h"
|
|
#include "DlgTime.h"
|
|
#include "TimePicker.h"
|
|
#include "gc.h"
|
|
#include "grid.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
enum {ID_TIMEPICKER=100, ID_DATEPICKER};
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDlgTime dialog
|
|
|
|
|
|
CDlgTime::CDlgTime(CWnd* pParent /*=NULL*/)
|
|
: CDialog(CDlgTime::IDD, pParent)
|
|
{
|
|
//{{AFX_DATA_INIT(CDlgTime)
|
|
//}}AFX_DATA_INIT
|
|
|
|
m_pTimePicker = NULL;
|
|
m_pDatePicker = NULL;
|
|
m_bIsInterval = FALSE;
|
|
m_pgc = NULL;
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
CDlgTime::~CDlgTime()
|
|
{
|
|
delete m_pTimePicker;
|
|
if(!m_bIsInterval)
|
|
{
|
|
delete m_pDatePicker;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
void CDlgTime::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CDlgTime)
|
|
DDX_Control(pDX, IDC_TIME_LABEL, m_timeLabel);
|
|
DDX_Control(pDX, IDC_TIMEZONE, m_comboZone);
|
|
DDX_Control(pDX, IDC_INTERVAL, m_interval);
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
|
|
BEGIN_MESSAGE_MAP(CDlgTime, CDialog)
|
|
//{{AFX_MSG_MAP(CDlgTime)
|
|
ON_EN_SETFOCUS(IDC_INTERVAL, OnSetfocusInterval)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDlgTime message handlers
|
|
|
|
#define CX_MARGIN 10
|
|
#define CY_MARGIN 7
|
|
#define CY_DATE_HEIGHT 14
|
|
#define CY_DATETIME 28
|
|
|
|
BOOL CDlgTime::OnInitDialog()
|
|
{
|
|
CDialog::OnInitDialog();
|
|
|
|
|
|
// Combobox for time zones.
|
|
CRect rcComboClient;
|
|
m_comboZone.GetClientRect(rcComboClient);
|
|
int cyDateTime = rcComboClient.Height() + 3;
|
|
|
|
CRect rcClient;
|
|
GetClientRect(rcClient);
|
|
|
|
// date picker.
|
|
CRect rcTime;
|
|
rcTime.left = rcClient.left + CX_MARGIN;
|
|
rcTime.top = rcClient.top + CY_MARGIN;
|
|
rcTime.right = rcClient.right - CX_MARGIN;
|
|
rcTime.bottom = rcTime.top + cyDateTime;
|
|
|
|
|
|
BOOL bDidCreate;
|
|
|
|
if(m_bIsInterval)
|
|
{
|
|
m_pDatePicker = m_interval.FromHandle(m_interval.m_hWnd);
|
|
((CEdit *)m_pDatePicker)->SetLimitText(8);
|
|
((CEdit *)m_pDatePicker)->SetWindowText(m_days);
|
|
m_comboZone.ShowWindow(SW_HIDE);
|
|
m_timeLabel.ShowWindow(SW_HIDE);
|
|
SetWindowText(_T("Interval"));
|
|
}
|
|
else
|
|
{
|
|
m_interval.ShowWindow(SW_HIDE);
|
|
GetDlgItem(IDC_INTERVAL2)->ShowWindow(SW_HIDE);
|
|
// m_interval.DestroyWindow();
|
|
|
|
// use the DatePicker instead.
|
|
m_pDatePicker = new CTimePicker;
|
|
bDidCreate = ((CTimePicker*)m_pDatePicker)->CustomCreate(0, rcTime, this, ID_DATEPICKER);
|
|
if (bDidCreate)
|
|
{
|
|
((CTimePicker*)m_pDatePicker)->ShowWindow(SW_SHOW);
|
|
}
|
|
}
|
|
|
|
// time picker.
|
|
CRect rcDate;
|
|
rcDate.left = rcClient.left + CX_MARGIN;
|
|
rcDate.top = rcTime.bottom + 2 * CY_MARGIN;
|
|
rcDate.right = rcClient.right - CX_MARGIN;
|
|
rcDate.bottom = rcDate.top + cyDateTime;
|
|
|
|
m_pTimePicker = new CTimePicker;
|
|
bDidCreate = m_pTimePicker->CustomCreate(DTS_TIMEFORMAT, rcDate, this, ID_TIMEPICKER);
|
|
if(bDidCreate && m_bIsInterval)
|
|
{
|
|
/*
|
|
TCHAR buf[30];
|
|
// get the user defined time format string.
|
|
if(GetLocaleInfo(LOCALE_USER_DEFAULT,
|
|
LOCALE_STIMEFORMAT,
|
|
buf, 30))
|
|
{
|
|
//look for the last 's'.
|
|
|
|
// append 'X'.
|
|
*/
|
|
|
|
// set the format.
|
|
HWND picker = m_pTimePicker->GetSafeHwnd();
|
|
DateTime_SetFormat(picker, _T("HH'h 'mm'm 'ss's'"));
|
|
|
|
m_pTimePicker->ShowWindow(SW_SHOW);
|
|
}
|
|
|
|
SYSTEMTIME systime;
|
|
BOOL x = DateTime_SetSystemtime(m_pTimePicker->m_hWnd, GDT_VALID, &m_systime);
|
|
DateTime_GetSystemtime(m_pTimePicker->m_hWnd, &systime);
|
|
if(!m_bIsInterval)
|
|
{
|
|
DateTime_SetSystemtime(m_pDatePicker->m_hWnd, GDT_VALID, &m_systime);
|
|
}
|
|
|
|
LoadComboBoxWithZones();
|
|
|
|
int iZone = MapOffsetToZone(m_nOffsetMinutes);
|
|
m_comboZone.SetCurSel(iZone);
|
|
|
|
BOOL bIsReadOnly = m_pgc->IsReadonly();
|
|
|
|
if (bIsReadOnly) {
|
|
m_comboZone.EnableWindow(FALSE);
|
|
m_interval.EnableWindow(FALSE);
|
|
}
|
|
|
|
|
|
if (bIsReadOnly) {
|
|
m_comboZone.EnableWindow(FALSE);
|
|
m_timeLabel.EnableWindow(FALSE);
|
|
if (m_pTimePicker) {
|
|
m_pTimePicker->EnableWindow(FALSE);
|
|
}
|
|
if (m_pDatePicker) {
|
|
m_pDatePicker->EnableWindow(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
|
|
//**************************************************************
|
|
// CDlgTime::EditTime
|
|
//
|
|
// Edit a time value.
|
|
//
|
|
// Parameters:
|
|
// [in, out] COleVariant& varTime
|
|
// A variant which may either be a VT_BSTR or a VT_NULL.
|
|
// If it is a VT_BSTR, the bstrVal member contains the time
|
|
// string in DTMF format. If VT_NULL, a default time
|
|
// should be displayed in the dialog.
|
|
//
|
|
// Returns:
|
|
// The edited time is returned via the varTime parameter.
|
|
//
|
|
// DTMF time format: YYYYMMDDhhmmssuuuuuu+/-GGG
|
|
// Y = year, M = month, D = day, m = minute, s = seconds
|
|
// u = microseconds, G = offset from Greenwich mean time.
|
|
//
|
|
// DTMF interval format: DDDDDDDDhhmmssuuuuuu:000
|
|
// D = day, m = minute, s = seconds, u = microseconds.
|
|
//**************************************************************
|
|
BOOL CDlgTime::EditTime(CGridCell* pgcTime)
|
|
{
|
|
HWND hwndFocus = ::GetFocus();
|
|
m_pgc = pgcTime;
|
|
|
|
if(!pgcTime->IsValid())
|
|
{
|
|
if(IDOK != MessageBox(L"The cell value is not compatible with its type\nDo you wish to set the cell value to <empty> before continuing?", L"Invalid Value", MB_OKCANCEL))
|
|
return FALSE;
|
|
pgcTime->SetToNull();
|
|
}
|
|
|
|
SCODE sc;
|
|
BOOL bWasNull = pgcTime->IsNull();
|
|
|
|
// if null...
|
|
if(bWasNull)
|
|
{
|
|
// look at the qualifier.
|
|
m_bIsInterval = pgcTime->GetFlags() & CELLFLAG_INTERVAL;
|
|
}
|
|
else
|
|
{
|
|
// look at the actual value.
|
|
m_bIsInterval = pgcTime->IsInterval();
|
|
}
|
|
|
|
// put the cell's time into the class vars.
|
|
if(m_bIsInterval)
|
|
{
|
|
sc = pgcTime->GetInterval(m_days, m_systime);
|
|
m_nOffsetMinutes = 0;
|
|
ASSERT(sc == S_OK);
|
|
}
|
|
else
|
|
{
|
|
sc = pgcTime->GetTime(m_systime, m_nOffsetMinutes);
|
|
ASSERT(sc == S_OK);
|
|
}
|
|
|
|
// display the time editor.
|
|
pgcTime->Grid()->PreModalDialog();
|
|
int iResult = (int) DoModal();
|
|
pgcTime->Grid()->PostModalDialog();
|
|
if((iResult == IDOK) && (!m_pgc->IsReadonly()))
|
|
{
|
|
// move the new time back into the cell.
|
|
if(m_bIsInterval)
|
|
{
|
|
sc = pgcTime->SetInterval(m_days, m_systime);
|
|
ASSERT(sc == S_OK);
|
|
}
|
|
else
|
|
{
|
|
sc = pgcTime->SetTime(m_systime, m_nOffsetMinutes);
|
|
ASSERT(sc == S_OK);
|
|
}
|
|
|
|
if ((hwndFocus != NULL) && ::IsWindow(hwndFocus)) {
|
|
::SetFocus(hwndFocus);
|
|
}
|
|
return TRUE;
|
|
}
|
|
else // user cancelled....
|
|
{
|
|
// set it back to null.
|
|
if(bWasNull && !pgcTime->IsNull())
|
|
{
|
|
pgcTime->SetToNull();
|
|
}
|
|
}
|
|
|
|
if ((hwndFocus != NULL) && ::IsWindow(hwndFocus)) {
|
|
::SetFocus(hwndFocus);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
typedef struct tagZones
|
|
{
|
|
TCHAR* m_szZone;
|
|
int m_nMinutes;
|
|
} ZONE_MAP;
|
|
|
|
ZONE_MAP aZoneMap[] =
|
|
{
|
|
{_T("GMT -12:00"), -(12 * 60)},
|
|
{_T("GMT -11:00"), -(11 * 60)},
|
|
{_T("GMT -10:00"), -(10 * 60)},
|
|
{_T("GMT -09:00"), -(9 * 60)},
|
|
{_T("GMT -08:00"), -(8 * 60)},
|
|
{_T("GMT -07:00"), -(7 * 60)},
|
|
{_T("GMT -06:00"), -(6 * 60)},
|
|
{_T("GMT -05:00"), -(5 * 60)},
|
|
{_T("GMT -04:00"), -(4 * 60)},
|
|
{_T("GMT -03:30"), -(3 * 60 + 30)},
|
|
{_T("GMT -03:00"), -(3 * 60)},
|
|
{_T("GMT -02:00"), -(2 * 60)},
|
|
{_T("GMT -01:00"), -(1 * 60)},
|
|
{_T("GMT"), 0},
|
|
{_T("GMT +01:00"), (1 * 60)},
|
|
{_T("GMT +02:00"), (2 * 60)},
|
|
{_T("GMT +03:00"), (3 * 60)},
|
|
{_T("GMT +03:30"), (3 * 60 + 30)},
|
|
{_T("GMT +04:00"), (4 * 60)},
|
|
{_T("GMT +04:30"), (4 * 60 + 30)},
|
|
{_T("GMT +05:00"), (5 * 60)},
|
|
{_T("GMT +05:30"), (5 * 60 + 30)},
|
|
{_T("GMT +06:00"), (6 * 60)},
|
|
{_T("GMT +07:00"), (7 * 60)},
|
|
{_T("GMT +08:00"), (8 * 60)},
|
|
{_T("GMT +09:00"), (9 * 60)},
|
|
{_T("GMT +09:30"), (9 * 60 + 30)},
|
|
{_T("GMT +10:00"), (10 * 60)},
|
|
{_T("GMT +11:00"), (11 * 60)},
|
|
{_T("GMT +12:00"), (12 * 60)}
|
|
};
|
|
|
|
//----------------------------------------------------
|
|
void CDlgTime::LoadComboBoxWithZones()
|
|
{
|
|
int nZones = sizeof(aZoneMap) / sizeof(ZONE_MAP);
|
|
for (int iZone =0; iZone < nZones; ++iZone)
|
|
{
|
|
m_comboZone.AddString(aZoneMap[iZone].m_szZone);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
int CDlgTime::MapZoneToOffset()
|
|
{
|
|
int iZone = m_comboZone.GetCurSel();
|
|
ASSERT(iZone >= 0 && iZone < (sizeof(aZoneMap) / sizeof(ZONE_MAP)));
|
|
int nOffsetMinutes = aZoneMap[iZone].m_nMinutes;
|
|
return nOffsetMinutes;
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
int CDlgTime::MapOffsetToZone(int iOffsetMinutes)
|
|
{
|
|
int nZones = sizeof(aZoneMap) / sizeof(ZONE_MAP);
|
|
|
|
if (iOffsetMinutes < aZoneMap[0].m_nMinutes)
|
|
{
|
|
HmmvErrorMsg(IDS_ERR_TIMEZONE_RANGE, S_OK,
|
|
FALSE, NULL, _T(__FILE__), __LINE__);
|
|
return 0;
|
|
}
|
|
|
|
if (iOffsetMinutes > aZoneMap[nZones - 1].m_nMinutes)
|
|
{
|
|
HmmvErrorMsg(IDS_ERR_TIMEZONE_RANGE, S_OK,
|
|
FALSE, NULL, _T(__FILE__), __LINE__);
|
|
ASSERT(FALSE);
|
|
return nZones - 1;
|
|
}
|
|
|
|
|
|
|
|
for (int iZone =0; iZone < nZones; ++iZone)
|
|
{
|
|
if (iOffsetMinutes <= aZoneMap[iZone].m_nMinutes)
|
|
{
|
|
if (aZoneMap[iZone].m_nMinutes == iOffsetMinutes)
|
|
{
|
|
return iZone;
|
|
}
|
|
|
|
|
|
// The offset is sonewhere between this entry and
|
|
// the previous one. Pick the entry that is closest
|
|
// to the specified offset.
|
|
HmmvErrorMsg(IDS_ERR_TIMEZONE_RANGE, S_OK,
|
|
FALSE, NULL, _T(__FILE__), __LINE__);
|
|
|
|
int iDelta1 = iOffsetMinutes - aZoneMap[iZone-1].m_nMinutes;
|
|
int iDelta2 = aZoneMap[iZone].m_nMinutes - iOffsetMinutes;
|
|
ASSERT(iDelta1 > 0);
|
|
ASSERT(iDelta2 > 0);
|
|
if (iDelta1 > iDelta2)
|
|
{
|
|
return iZone;
|
|
}
|
|
else
|
|
{
|
|
return iZone - 1;
|
|
}
|
|
}
|
|
}
|
|
ASSERT(FALSE);
|
|
return nZones - 1;
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
void CDlgTime::OnOK()
|
|
{
|
|
if(m_bIsInterval)
|
|
{
|
|
m_pDatePicker->GetWindowText(m_days);
|
|
m_systime.wYear = 1900;
|
|
m_systime.wMonth = 1;
|
|
m_systime.wDayOfWeek = 1;
|
|
m_systime.wDay = 1;
|
|
}
|
|
else // itsa dateTime...
|
|
{
|
|
SYSTEMTIME systimeDate;
|
|
DWORD dwResultDate = DateTime_GetSystemtime(m_pDatePicker->m_hWnd, &systimeDate);
|
|
if(dwResultDate == GDT_VALID)
|
|
{
|
|
m_systime.wYear = systimeDate.wYear;
|
|
m_systime.wMonth = systimeDate.wMonth;
|
|
m_systime.wDayOfWeek = systimeDate.wDayOfWeek;
|
|
m_systime.wDay = systimeDate.wDay;
|
|
}
|
|
}
|
|
|
|
SYSTEMTIME systimeTime;
|
|
DWORD dwResultTime = DateTime_GetSystemtime(m_pTimePicker->m_hWnd, &systimeTime);
|
|
if(dwResultTime == GDT_VALID)
|
|
{
|
|
m_systime.wHour = systimeTime.wHour;
|
|
m_systime.wMinute = systimeTime.wMinute;
|
|
m_systime.wSecond = systimeTime.wSecond;
|
|
m_systime.wMilliseconds = systimeTime.wMilliseconds;
|
|
}
|
|
|
|
m_nOffsetMinutes = MapZoneToOffset();
|
|
|
|
CDialog::OnOK();
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
BOOL CDlgTime::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult )
|
|
{
|
|
LPNMHDR hdr = (LPNMHDR)lParam;
|
|
LPNMDATETIMECHANGE lpChange;
|
|
switch(hdr->code)
|
|
{
|
|
case DTN_DATETIMECHANGE:
|
|
{
|
|
lpChange = (LPNMDATETIMECHANGE)lParam;
|
|
DoDateTimeChange(lpChange);
|
|
}
|
|
break;
|
|
|
|
case DTN_FORMATQUERY:
|
|
{
|
|
LPNMDATETIMEFORMATQUERY lpDTFQuery = (LPNMDATETIMEFORMATQUERY)lParam;
|
|
// Process DTN_FORMATQUERY to ensure that the control
|
|
// displays callback information properly.
|
|
DoFormatQuery(hdr->hwndFrom, lpDTFQuery);
|
|
}
|
|
break;
|
|
|
|
case DTN_FORMAT:
|
|
{
|
|
LPNMDATETIMEFORMAT lpNMFormat = (LPNMDATETIMEFORMAT) lParam;
|
|
// Process DTN_FORMAT to supply information about callback
|
|
// fields (fields) in the DTP control.
|
|
DoFormat(hdr->hwndFrom, lpNMFormat);
|
|
}
|
|
break;
|
|
|
|
case DTN_WMKEYDOWN:
|
|
{
|
|
LPNMDATETIMEWMKEYDOWN lpDTKeystroke =
|
|
(LPNMDATETIMEWMKEYDOWN)lParam;
|
|
// Process DTN_WMKEYDOWN to respond to a user's keystroke in
|
|
// a callback field.
|
|
DoWMKeydown(hdr->hwndFrom, lpDTKeystroke);
|
|
}
|
|
break;
|
|
|
|
} // All of the above notifications require the owner to return zero.
|
|
return FALSE;
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
void CDlgTime::DoFormatQuery(HWND hwndDP,
|
|
LPNMDATETIMEFORMATQUERY lpDTFQuery)
|
|
{
|
|
HDC hdc;
|
|
HFONT hFont, hOrigFont;
|
|
|
|
// Prepare the device context for GetTextExtentPoint32 call.
|
|
hdc = ::GetDC(hwndDP);
|
|
hFont = (HFONT)GetFont();
|
|
|
|
if(!hFont)
|
|
hFont = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
|
|
|
|
hOrigFont = (HFONT)SelectObject(hdc, hFont);
|
|
|
|
// Check to see if this is the callback segment desired. If so,
|
|
// use the longest text segment to determine the maximum
|
|
// width of the callback field, and then place the information into
|
|
// the NMDATETIMEFORMATQUERY structure.
|
|
if(!_tcscmp(_T("XX"),lpDTFQuery->pszFormat))
|
|
GetTextExtentPoint32(hdc, _T("88888"), 5,
|
|
&lpDTFQuery->szMax);
|
|
|
|
// Reset the font in the device context; then release the context.
|
|
SelectObject(hdc,hOrigFont);
|
|
::ReleaseDC(hwndDP, hdc);
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
void CDlgTime::DoFormat(HWND hwndDP,
|
|
LPNMDATETIMEFORMAT lpDTFormat)
|
|
{
|
|
_stprintf(lpDTFormat->szDisplay,_T("%6.6u"),
|
|
lpDTFormat->st.wMilliseconds);
|
|
|
|
int x = 1;
|
|
}
|
|
//----------------------------------------------------
|
|
void CDlgTime::DoWMKeydown(HWND hwndDP,
|
|
LPNMDATETIMEWMKEYDOWN lpDTKeystroke)
|
|
{
|
|
short delta =1;
|
|
if(!_tcscmp(lpDTKeystroke->pszFormat,_T("XX")))
|
|
{
|
|
switch(lpDTKeystroke->nVirtKey)
|
|
{
|
|
case VK_DOWN:
|
|
case VK_SUBTRACT:
|
|
delta = -1; // fall through
|
|
case VK_UP:
|
|
case VK_ADD:
|
|
lpDTKeystroke->st.wMilliseconds += delta;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
void CDlgTime::DoDateTimeChange(LPNMDATETIMECHANGE lpChange)
|
|
{
|
|
switch(lpChange->nmhdr.idFrom)
|
|
{
|
|
case ID_DATEPICKER:
|
|
m_systime.wYear = lpChange->st.wYear;
|
|
m_systime.wMonth = lpChange->st.wMonth;
|
|
m_systime.wDay = lpChange->st.wDay;
|
|
break;
|
|
case ID_TIMEPICKER:
|
|
m_systime.wHour = lpChange->st.wHour;
|
|
m_systime.wMinute = lpChange->st.wMinute;
|
|
m_systime.wSecond = lpChange->st.wSecond;
|
|
m_systime.wMilliseconds = lpChange->st.wMilliseconds;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CDlgTime::OnSetfocusInterval()
|
|
{
|
|
m_interval.SetSel(0, -1);
|
|
}
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CEdtInterval
|
|
|
|
CEdtInterval::CEdtInterval()
|
|
{
|
|
}
|
|
|
|
CEdtInterval::~CEdtInterval()
|
|
{
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CEdtInterval, CEdit)
|
|
//{{AFX_MSG_MAP(CEdtInterval)
|
|
ON_WM_LBUTTONDOWN()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CEdtInterval message handlers
|
|
|
|
void CEdtInterval::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
CEdit::OnLButtonDown(nFlags, point);
|
|
SetSel(0, -1);
|
|
}
|