Esempio n. 1
0
/**
 * name:	ProfileList_AddNewItem
 * desc:	Ask's user for a type and adds new item to the list view
 * param:	pList	- pointer to the listview's data structure
 *			pszList	- database settings string, that identifies this category
 *
 * return:	TRUE or FALSE
 **/
static BOOLEAN ProfileList_AddNewItem(HWND hDlg, LPLISTCTRL pList, const PROFILEENTRY *pEntry)
{
	LPLCITEM pItem;
	LVITEM lvi;
	HANDLE hContact;

	if (PtrIsValid(pList) && (pItem = (LPLCITEM)mir_alloc(sizeof(LCITEM)))) {
		PSGetContact(hDlg, hContact);
		pItem->nType = CTRL_LIST_ITEM;
		pItem->wFlags = hContact ? CTRLF_HASCUSTOM : 0;
		pItem->iListItem = 0;
		pItem->pszText[0] = NULL;
		pItem->pszText[1] = NULL;
		// get category list
		pEntry->GetList((WPARAM)&pItem->idstrListCount, (LPARAM)&pItem->idstrList);

		lvi.mask = LVIF_PARAM|LVIF_STATE;
		lvi.stateMask = 0xFFFFFFFF;
		lvi.state = LVIS_FOCUSED|LVIS_SELECTED;
		lvi.iItem = ProfileList_GetInsertIndex(pList->hList, pEntry->szGroup);
		lvi.iSubItem = 0;
		lvi.lParam = (LPARAM)pItem;
		if ((lvi.iItem = ListView_InsertItem(pList->hList, &lvi)) >= 0) {
			ProfileList_BeginLabelEdit(pList, lvi.iItem, 0);
			return TRUE;
		}
		mir_free(pItem);
		MsgErr(hDlg, LPGENT("Sorry, but there is a problem with adding a new item of type \"%s\""), pEntry->szGroup);
	}	
	return FALSE;
}
Esempio n. 2
0
/**
 * name:	OnReminderChecked
 * class:	CAnnivEditCtrl
 * desc:	is called if reminder checkbox's state was changed
 * param:	none
 * return:	nothing
 **/
void CAnnivEditCtrl::OnReminderChecked()
{
	MCONTACT hContact;
	LPCSTR pszProto;
	int state;
	TCHAR buf[6];
	MAnnivDate *pCurrent = Current();

	PSGetContact(_hwndDlg, hContact);
	if (!hContact || !PSGetBaseProto(_hwndDlg, pszProto) || !pCurrent) 
	{
		EnableReminderCtrl(FALSE);
	}
	else
	{
		if (IsDlgButtonChecked(_hwndDlg, RADIO_REMIND1))
		{
			_itot(db_get_b(NULL, MODNAME, SET_REMIND_OFFSET, DEFVAL_REMIND_OFFSET), buf, 10);
			EnableWindow(GetDlgItem(_hwndDlg, EDIT_REMIND), FALSE);
			EnableWindow(GetDlgItem(_hwndDlg, SPIN_REMIND), FALSE);
			state = BST_INDETERMINATE;
		}
		else if (IsDlgButtonChecked(_hwndDlg, RADIO_REMIND2))
		{
			if (pCurrent->RemindOffset() == (WORD)-1)
			{
				_itot(db_get_b(NULL, MODNAME, SET_REMIND_OFFSET, DEFVAL_REMIND_OFFSET), buf, 10);
			}
			else
			{
				_itot(pCurrent->RemindOffset(), buf, 10);
			}
			EnableWindow(GetDlgItem(_hwndDlg, EDIT_REMIND), _ReminderEnabled);
			EnableWindow(GetDlgItem(_hwndDlg, SPIN_REMIND), _ReminderEnabled);
			state = BST_CHECKED;
		}
		else
		{
			*buf = 0;
			EnableWindow(GetDlgItem(_hwndDlg, EDIT_REMIND), FALSE);
			EnableWindow(GetDlgItem(_hwndDlg, SPIN_REMIND), FALSE);
			state = BST_UNCHECKED;
		}
		if (pCurrent->RemindOption() != state) 
		{
			pCurrent->RemindOption(state);
			if (!PspIsLocked(_hwndDlg)) 
			{
				pCurrent->SetFlags(MAnnivDate::MADF_REMINDER_CHANGED);
				SendMessage(GetParent(_hwndDlg), PSM_CHANGED, NULL, NULL);
			}
		}
		SetDlgItemText(_hwndDlg, EDIT_REMIND, buf);
	}
}
Esempio n. 3
0
/**
 * name:	EnableCurrentItem
 * class:	CAnnivEditCtrl
 * desc:	make control readonly if required
 * param:	none
 * return:	nothing
 **/
void CAnnivEditCtrl::EnableCurrentItem()
{
	MAnnivDate *pCurrent = Current();

	if (pCurrent) {
		MCONTACT hContact;
	
		PSGetContact(_hwndDlg, hContact);

		const BYTE bEnabled
			= !hContact ||
				(pCurrent->Flags() & CTRLF_HASCUSTOM) || 
				!(pCurrent->Flags() & (CTRLF_HASPROTO|CTRLF_HASMETA)) ||
				!db_get_b(NULL, MODNAME, SET_PROPSHEET_PCBIREADONLY, 0);

		EnableWindow(_hBtnEdit, bEnabled);
		EnableWindow(_hBtnDel, bEnabled);
		EnableWindow(_hwndDate, bEnabled);
	}
}
Esempio n. 4
0
/**
 * name:	DeleteDate
 * class:	CAnnivEditCtrl
 * desc:	Delete the item on the position identified by wIndex
 * param:	pDateCtrl	- pointer to the date control's data structure
 *			wIndex		- index of the item to delete
 * return:	0 on success 1 otherwise
 **/
INT_PTR CAnnivEditCtrl::DeleteDate(WORD wIndex)
{
	if (!ItemValid(wIndex)) return 1;
	
	// only delete values, but not the item
	if (_pDates[wIndex]->Id() == ANID_BIRTHDAY) {
		MCONTACT hContact;
		LPCSTR pszProto;

		PSGetContact(_hwndDlg, hContact);
		PSGetBaseProto(_hwndDlg, pszProto);

		// protocol value exists?
		if (_pDates[wIndex]->DBGetDate(hContact, pszProto, SET_CONTACT_BIRTHDAY, SET_CONTACT_BIRTHMONTH, SET_CONTACT_BIRTHYEAR)) {
			_pDates[wIndex]->SetFlags(MAnnivDate::MADF_HASPROTO);
		}
		else {
			_pDates[wIndex]->ZeroDate();
		}

		_pDates[wIndex]->RemindOption(BST_INDETERMINATE);
		_pDates[wIndex]->RemindOffset((WORD)-1);

		_pDates[wIndex]->RemoveFlags(MAnnivDate::MADF_HASCUSTOM);
		_pDates[wIndex]->SetFlags(MAnnivDate::MADF_CHANGED|MAnnivDate::MADF_REMINDER_CHANGED);
	}
	else {
		delete _pDates[wIndex];
		_numDates--;
		if (wIndex < _numDates)
			memmove(_pDates + wIndex, _pDates + wIndex + 1, (_numDates - wIndex) * sizeof(*_pDates));
		memset((_pDates + _numDates), 0, sizeof(*_pDates)); // XXX: check me: sizeof(*_pDates) -> (sizeof(*_pDates) - _numDates)
		if (_curDate >= _numDates)
			_curDate = _numDates - 1;
	}
	SendMessage(GetParent(_hwndDlg), PSM_CHANGED, NULL, NULL);
	SetCurSel(_curDate);
	return 0;
}
Esempio n. 5
0
/**
 * name:	ProfileList_BeginLabelEdit
 * desc:	create an edit control to edit the label of the selected item
 * param:	pList	 - handle to listview control's info structure
 *			iItem	 - item index
 *			iSubItem - subitem (column) index
 * return:	handle to the edit control
 **/
static HWND ProfileList_BeginLabelEdit(LPLISTCTRL pList, INT iItem, INT iSubItem)
{
	LVITEM lvi;
	LPLCITEM pItem;
	HANDLE hContact;
	RECT rcList;
	
	if (!PtrIsValid(pList)) 
		return NULL;
	if (pList->labelEdit.hEdit)
		ProfileList_EndLabelEdit(pList, FALSE);

	lvi.mask = LVIF_PARAM|LVIF_STATE;
	lvi.stateMask = 0xFFFFFFFF;
	lvi.iItem = iItem;
	lvi.iSubItem = iSubItem;

	if (!ListView_GetItem(pList->hList, &lvi))
		return NULL;

	pItem = (LPLCITEM)lvi.lParam;

	PSGetContact(GetParent(pList->hList), hContact);
			
	// do not edit deviders or protocol based contact information
	if (!(lvi.state & LVIS_SELECTED) || !PtrIsValid(pItem) || (hContact && (pItem->wFlags & CTRLF_HASPROTO))) 
		return NULL;

	ListView_EnsureVisible(pList->hList, iItem, FALSE);
	ListView_GetSubItemRect(pList->hList, iItem, iSubItem, LVIR_BOUNDS, &pList->labelEdit.rcCombo);
		
	if (lvi.iSubItem == 0) {
		RECT rc2;
		
		ListView_GetSubItemRect(pList->hList, iItem, 1, LVIR_BOUNDS, &rc2);
		pList->labelEdit.rcCombo.right = rc2.left;
	}
	GetClientRect(pList->hList, &rcList);
	pList->labelEdit.rcCombo.right = min(pList->labelEdit.rcCombo.right, rcList.right);
	pList->labelEdit.rcCombo.left = max(pList->labelEdit.rcCombo.left, rcList.left);
	InflateRect(&pList->labelEdit.rcCombo, -1, -1);

	// create the button control for the combobox
	if (!iSubItem && pItem->idstrList) {
		pList->labelEdit.hBtn = CreateWindowEx(WS_EX_NOPARENTNOTIFY, UINFOBUTTONCLASS, NULL, 
					WS_VISIBLE|WS_CHILD|MBS_DOWNARROW,
					pList->labelEdit.rcCombo.right - (pList->labelEdit.rcCombo.bottom - pList->labelEdit.rcCombo.top), pList->labelEdit.rcCombo.top,
					pList->labelEdit.rcCombo.bottom - pList->labelEdit.rcCombo.top,
					pList->labelEdit.rcCombo.bottom - pList->labelEdit.rcCombo.top,
					pList->hList, NULL, ghInst, NULL);
		if (pList->labelEdit.hBtn) {
			SetWindowLongPtr(pList->labelEdit.hBtn, GWLP_ID, BTN_EDIT);
			pList->labelEdit.rcCombo.right -= pList->labelEdit.rcCombo.bottom - pList->labelEdit.rcCombo.top;
		}
	}
	else {
		pList->labelEdit.rcCombo.bottom = 3 * pList->labelEdit.rcCombo.bottom - 2 * pList->labelEdit.rcCombo.top;
		if (rcList.bottom < pList->labelEdit.rcCombo.bottom) {
			OffsetRect(&pList->labelEdit.rcCombo, 0, rcList.bottom - pList->labelEdit.rcCombo.bottom - 2);
		}
	}
	// create the edit control
	pList->labelEdit.hEdit = CreateWindowEx(WS_EX_NOPARENTNOTIFY|WS_EX_CLIENTEDGE,
				_T("EDIT"),
				(!iSubItem && pItem->idstrList && pItem->iListItem > 0 && pItem->iListItem < pItem->idstrListCount) 
					? pItem->idstrList[pItem->iListItem].ptszTranslated
					: (iSubItem >= 0 && iSubItem < 2 && pItem->pszText[iSubItem] && *pItem->pszText[iSubItem])
						? pItem->pszText[iSubItem] 
						: _T(""), 
						WS_VISIBLE|WS_CHILD|(iSubItem ? (WS_VSCROLL|ES_MULTILINE|ES_AUTOVSCROLL) : ES_AUTOHSCROLL),
				pList->labelEdit.rcCombo.left, pList->labelEdit.rcCombo.top,
				pList->labelEdit.rcCombo.right - pList->labelEdit.rcCombo.left,
				pList->labelEdit.rcCombo.bottom - pList->labelEdit.rcCombo.top,
				pList->hList, NULL, ghInst, NULL);
	if (!pList->labelEdit.hEdit)
		return NULL;
	SendMessage(pList->labelEdit.hEdit, WM_SETFONT, (WPARAM)(pList->hFont), 0);
	SendMessage(pList->labelEdit.hEdit, EM_SETSEL, 0, (LPARAM)-1);
	SetUserData(pList->labelEdit.hEdit, pList);
	pList->labelEdit.dropDown.iItem = pItem->iListItem;
	pList->labelEdit.iItem = iItem;
	pList->labelEdit.iSubItem = iSubItem;
	pList->labelEdit.iTopIndex = ListView_GetTopIndex(pList->hList);
	pList->labelEdit.pItem = pItem;
	SetFocus(pList->labelEdit.hEdit);
	OldEditProc = (WNDPROC)SetWindowLongPtr(pList->labelEdit.hEdit, GWLP_WNDPROC, (LONG_PTR)ProfileList_LabelEditProc);
	return pList->labelEdit.hEdit;
}
Esempio n. 6
0
/**
 * name:	DlgProcPspAbout()
 * desc:	dialog procedure
 *
 * return:	0 or 1
 **/
INT_PTR CALLBACK PSPProcContactProfile(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	HWND hList = GetDlgItem(hDlg, LIST_PROFILE);
	LPLISTCTRL pList;

	switch (uMsg) {
		case WM_INITDIALOG:
		{
			LVCOLUMN lvc;
			RECT rc;
			LOGFONT lf;
			HFONT hFont;
			TOOLINFO ti;

			if (!hList || !(pList = (LPLISTCTRL)mir_alloc(sizeof(LISTCTRL)))) 
				return FALSE;
			ZeroMemory(pList, sizeof(LISTCTRL));

			TranslateDialogDefault(hDlg);
			Ctrl_InitTextColours();

			// init info structure
			pList->hList = hList;
			pList->nType = CTRL_LIST_PROFILE;
			ZeroMemory(&pList->labelEdit, sizeof(pList->labelEdit));
			SetUserData(hList, pList);

			// set new window procedure
			OldListViewProc = (WNDPROC)SetWindowLongPtr(hList, GWLP_WNDPROC, (LONG_PTR)&ProfileList_SubclassProc);
			
			// remove static edge in aero mode
			if (IsAeroMode())
				SetWindowLongPtr(hList, GWL_EXSTYLE, GetWindowLongPtr(hList, GWL_EXSTYLE)&~WS_EX_STATICEDGE);

			// insert columns into the listboxes					
			ListView_SetExtendedListViewStyle(hList, LVS_EX_FULLROWSELECT);


			PSGetBoldFont(hDlg, hFont);
			SendDlgItemMessage(hDlg, IDC_PAGETITLE, WM_SETFONT, (WPARAM)hFont, 0);

			// set listfont
			pList->hFont = (HFONT)SendMessage(hList, WM_GETFONT, 0, 0);
			pList->wFlags |= LVF_EDITLABEL;
			GetObject(pList->hFont, sizeof(lf), &lf);
			lf.lfHeight -= 6;
			hFont = CreateFontIndirect(&lf);
			SendMessage(hList, WM_SETFONT, (WPARAM)hFont, 0);

			GetClientRect(hList, &rc);
			rc.right -= GetSystemMetrics(SM_CXVSCROLL);

			// initiate the tooltips
			pList->hTip = CreateWindowEx(WS_EX_TOPMOST,	TOOLTIPS_CLASS, NULL,
				WS_POPUP|TTS_BALLOON|TTS_NOPREFIX|TTS_ALWAYSTIP,
				CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
				hList, NULL, ghInst, NULL);
			if (pList->hTip) {
				SetWindowPos(pList->hTip, HWND_TOPMOST,
					CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
					SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

				ZeroMemory(&ti, sizeof(TOOLINFO));
				ti.cbSize = sizeof(TOOLINFO);
				ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS|TTF_TRANSPARENT;
				ti.hinst = ghInst;
				ti.hwnd = hList;
				ti.uId = (UINT_PTR)hList;
				SendMessage(pList->hTip, TTM_ADDTOOL, NULL, (LPARAM)&ti);
				SendMessage(pList->hTip, TTM_ACTIVATE, FALSE, (LPARAM)&ti);
			}		

			// insert columns into the listboxes					
			lvc.mask = LVCF_WIDTH;
			lvc.cx = rc.right / 8 * 3;
			ListView_InsertColumn(hList, 0, &lvc);
			lvc.cx = rc.right / 8 * 5;
			ListView_InsertColumn(hList, 1, &lvc);
			return TRUE;
		}

		case WM_CTLCOLORSTATIC:
		case WM_CTLCOLORDLG:
			if (IsAeroMode())
				return (INT_PTR)GetStockBrush(WHITE_BRUSH);
			break;

		case WM_NOTIFY:
			switch (((LPNMHDR)lParam)->idFrom) {
				case 0:
				{
					HANDLE hContact = (HANDLE)((LPPSHNOTIFY)lParam)->lParam;
					LPCSTR pszProto;
					
					if (!PtrIsValid(pList = (LPLISTCTRL)GetUserData(hList))) break;

					switch (((LPNMHDR)lParam)->code) {
						// some account data may have changed so reread database
						case PSN_INFOCHANGED:
						{
							BYTE msgResult = 0;
							LPIDSTRLIST idList;
							UINT nList;
							BYTE i;
							INT iItem = 0,
								iGrp = 0,
								numProtoItems,
								numUserItems;

							if (!(pList->wFlags & CTRLF_CHANGED) && PSGetBaseProto(hDlg, pszProto) && *pszProto != 0) {
								ProfileList_Clear(hList);

								// insert the past information
								for (i = 0; i < 3; i++) {
									pFmt[i].GetList((WPARAM)&nList, (LPARAM)&idList);
									if ((numProtoItems = ProfileList_AddItemlistFromDB(pList, iItem, idList, nList, hContact, pszProto, pFmt[i].szCatFmt, pFmt[i].szValFmt, CTRLF_HASPROTO)) < 0)
										return FALSE;

									// scan all basic protocols for the subcontacts
									if (DB::Module::IsMetaAndScan(pszProto)) {
										INT iDefault = CallService(MS_MC_GETDEFAULTCONTACTNUM, (WPARAM)hContact, NULL);
										HANDLE hSubContact, hDefContact;
										LPCSTR pszSubBaseProto;
										INT j, numSubs;
										
										if ((hDefContact = (HANDLE)CallService(MS_MC_GETSUBCONTACT, (WPARAM)hContact, iDefault)) &&
											 (pszSubBaseProto = DB::Contact::Proto(hDefContact)))
										{
											if ((numProtoItems += ProfileList_AddItemlistFromDB(pList, iItem, idList, nList, hDefContact, pszSubBaseProto, pFmt[i].szCatFmt, pFmt[i].szValFmt, CTRLF_HASMETA|CTRLF_HASPROTO)) < 0)
												return FALSE;

											// copy the missing settings from the other subcontacts
											numSubs = CallService(MS_MC_GETNUMCONTACTS, (WPARAM)hContact, NULL);
											for (j = 0; j < numSubs; j++) {
												if (j == iDefault) continue;
												if (!(hSubContact = (HANDLE)CallService(MS_MC_GETSUBCONTACT, (WPARAM)hContact, j))) continue;
												if (!(pszSubBaseProto = DB::Contact::Proto(hSubContact))) continue;
												if ((numProtoItems += ProfileList_AddItemlistFromDB(pList, iItem, idList, nList, hSubContact, pszSubBaseProto, pFmt[i].szCatFmt, pFmt[i].szValFmt, CTRLF_HASMETA|CTRLF_HASPROTO)) < 0)
													return FALSE;
												//if ((numUserItems += ProfileList_AddItemlistFromDB(pList, iItem, idList, nList, hSubContact, USERINFO, pFmt[i].szCatFmt, pFmt[i].szValFmt, CTRLF_HASMETA|CTRLF_HASPROTO)) < 0)
												//	return FALSE;
											}
										}
									}
									if ((numUserItems = ProfileList_AddItemlistFromDB(pList, iItem, idList, nList, hContact, USERINFO, pFmt[i].szCatFmt, pFmt[i].szValFmt, CTRLF_HASCUSTOM)) < 0)
										return FALSE;
									if (numUserItems || numProtoItems) {
										msgResult = PSP_CHANGED;
										ProfileList_AddGroup(hList, pFmt[i].szGroup, iGrp);
										iGrp = ++iItem;
									}
								}
							}
							SetWindowLongPtr(hDlg, DWLP_MSGRESULT, msgResult);
							break;
						}
						// user swiches to another propertysheetpage
						case PSN_KILLACTIVE:
							ProfileList_EndLabelEdit(hList, TRUE);
							break;
						// user selected to apply settings to the database
						case PSN_APPLY:
							if (pList->wFlags & CTRLF_CHANGED) {
								BYTE iFmt = -1;
								INT iItem;
								LVITEM lvi;
								TCHAR szGroup[MAX_PATH];
								CHAR pszSetting[MAXSETTING];
								LPLCITEM pItem;
								LPSTR pszModule = USERINFO;

								if (!hContact) PSGetBaseProto(hDlg, pszModule);

								*szGroup = 0;
								lvi.mask = LVIF_TEXT|LVIF_PARAM;
								lvi.pszText = szGroup;
								lvi.cchTextMax = MAX_PATH;

								for (iItem = lvi.iItem = lvi.iSubItem = 0; ListView_GetItem(hList, &lvi); lvi.iItem++) {
									if (!PtrIsValid(pItem = (LPLCITEM)lvi.lParam)) {
										// delete reluctant items
										if (iFmt >= 0 && iFmt < SIZEOF(pFmt)) {
											DB::Setting::DeleteArray(hContact, pszModule, pFmt[iFmt].szCatFmt, iItem);
											DB::Setting::DeleteArray(hContact, pszModule, pFmt[iFmt].szValFmt, iItem);
										}
										// find information about the group
										for (iFmt = 0; iFmt < SIZEOF(pFmt); iFmt++) {
											if (!_tcscmp(szGroup, pFmt[iFmt].szGroup)) {
												break;
											}
										}
										// indicate, no group was found. should not happen!!
										if (iFmt == SIZEOF(pFmt)) {
											*szGroup = 0;
											iFmt = -1;
										}
										iItem = 0;
									}
									else
									if (iFmt >= 0 && iFmt < SIZEOF(pFmt)) {
										// save value
										if (!pItem->pszText[1] || !*pItem->pszText[1])
											continue;
										if (!(pItem->wFlags & (CTRLF_HASPROTO|CTRLF_HASMETA))) {
											mir_snprintf(pszSetting, MAXSETTING, pFmt[iFmt].szValFmt, iItem);
											DB::Setting::WriteTString(hContact, pszModule, pszSetting, pItem->pszText[1]);
											// save category
											mir_snprintf(pszSetting, MAXSETTING, pFmt[iFmt].szCatFmt, iItem);
											if (pItem->idstrList && pItem->iListItem > 0 && pItem->iListItem < pItem->idstrListCount)
												DB::Setting::WriteAString(hContact, pszModule, pszSetting, (LPSTR)pItem->idstrList[pItem->iListItem].pszText);
											else 
											if (pItem->pszText[0] && *pItem->pszText[0])
												DB::Setting::WriteTString(hContact, pszModule, pszSetting, (LPTSTR)pItem->pszText[0]);
											else									
												DB::Setting::Delete(hContact, pszModule, pszSetting);
											// redraw the item if required
											if (pItem->wFlags & CTRLF_CHANGED) {
												pItem->wFlags &= ~CTRLF_CHANGED;
												ListView_RedrawItems(hList, lvi.iItem, lvi.iItem);
											}
											iItem++;
										}
									}
								}
								// delete reluctant items
								if (iFmt >= 0 && iFmt < SIZEOF(pFmt)) {
									DB::Setting::DeleteArray(hContact, pszModule, pFmt[iFmt].szCatFmt, iItem);
									DB::Setting::DeleteArray(hContact, pszModule, pFmt[iFmt].szValFmt, iItem);
								}

								pList->wFlags &= ~CTRLF_CHANGED;
							}
							break;
					}
					break;
				}

				//
				// handle notification messages from the list control
				//
				case LIST_PROFILE:
				{
					LPLISTCTRL pList = (LPLISTCTRL)GetUserData(((LPNMHDR)lParam)->hwndFrom);

					switch (((LPNMHDR)lParam)->code) {
						case NM_RCLICK:
						{
							HMENU hMenu = CreatePopupMenu();
							MENUITEMINFO mii;
							HANDLE hContact;
							LVHITTESTINFO hi;
							LPLCITEM pItem;
							POINT pt;
							
							if (!hMenu) return 1;
							PSGetContact(hDlg, hContact);
							GetCursorPos(&pt);
							hi.pt = pt;
							ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hi.pt);
							ListView_SubItemHitTest(((LPNMHDR)lParam)->hwndFrom, &hi);
							pItem = ProfileList_GetItemData(((LPNMHDR)lParam)->hwndFrom, hi.iItem);

							// insert menuitems
							ZeroMemory(&mii, sizeof(MENUITEMINFO));
							mii.cbSize = sizeof(MENUITEMINFO);
							mii.fMask = MIIM_ID|MIIM_STRING;
							// insert "Add" Menuitem
							mii.wID = BTN_ADD_intEREST;
							mii.dwTypeData = TranslateT("Add Interest");
							InsertMenuItem(hMenu, 0, TRUE, &mii);
							mii.wID = BTN_ADD_AFFLIATION;
							mii.dwTypeData = TranslateT("Add Affliation");
							InsertMenuItem(hMenu, 1, TRUE, &mii);
							mii.wID = BTN_ADD_PAST;
							mii.dwTypeData = TranslateT("Add Past");
							InsertMenuItem(hMenu, 2, TRUE, &mii);

							if (hi.iItem != -1 && PtrIsValid(pItem) && !(hContact && (pItem->wFlags & CTRLF_HASPROTO))) {
								// insert separator
								mii.fMask = MIIM_FTYPE;
								mii.fType = MFT_SEPARATOR;
								InsertMenuItem(hMenu, 3, TRUE, &mii);
								// insert "Delete" Menuitem
								mii.fMask = MIIM_ID|MIIM_STRING;
								mii.wID = BTN_EDIT_CAT;
								mii.dwTypeData = TranslateT("Edit Category");
								InsertMenuItem(hMenu, 4, TRUE, &mii);
								mii.wID = BTN_EDIT_VAL;
								mii.dwTypeData = TranslateT("Edit Value");
								InsertMenuItem(hMenu, 5, TRUE, &mii);
								mii.fMask = MIIM_FTYPE;
								mii.fType = MFT_SEPARATOR;
								InsertMenuItem(hMenu, 6, TRUE, &mii);
								// insert "Delete" Menuitem
								mii.fMask = MIIM_ID|MIIM_STRING;
								mii.wID = BTN_DEL;
								mii.dwTypeData = TranslateT("Delete");
								InsertMenuItem(hMenu, 7, TRUE, &mii);
							}
							TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hDlg, 0);
							DestroyMenu(hMenu);
							return 0;
						}
						/*case LVN_BEGINSCROLL:
							SetFocus(((LPNMHDR)lParam)->hwndFrom);
							break;
							*/
						case LVN_GETDISPINFO:
							if (pList->labelEdit.iTopIndex != ListView_GetTopIndex(hList))
								ProfileList_EndLabelEdit(((LPNMHDR)lParam)->hwndFrom, FALSE);
							break;
						case NM_CUSTOMDRAW:
						{
							LPNMLVCUSTOMDRAW cd = (LPNMLVCUSTOMDRAW)lParam;
							LPLCITEM pItem = (LPLCITEM)cd->nmcd.lItemlParam;
							RECT rc;

							switch (cd->nmcd.dwDrawStage) {
								case CDDS_PREPAINT:
									SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW);
									return TRUE;
								
								case CDDS_ITEMPREPAINT:
									ListView_GetItemRect(cd->nmcd.hdr.hwndFrom, cd->nmcd.dwItemSpec, &rc, LVIR_BOUNDS);
									if (!PtrIsValid(pItem)) {
										HFONT hBold, hFont;
										TCHAR szText[MAX_PATH];
										
										PSGetBoldFont(hDlg, hBold);
										hFont = (HFONT)SelectObject(cd->nmcd.hdc, hBold);
										SetTextColor(cd->nmcd.hdc, GetSysColor(COLOR_3DSHADOW));
										ProfileList_GetItemText(cd->nmcd.hdr.hwndFrom, cd->nmcd.dwItemSpec, 0, szText, MAX_PATH);
										rc.left += 6;
										DrawText(cd->nmcd.hdc, TranslateTS(szText), -1, &rc, DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER);

										rc.bottom -= 2;
										rc.top = rc.bottom - 1;
										rc.left -= 6;
										DrawEdge(cd->nmcd.hdc, &rc, BDR_SUNKENOUTER, BF_RECT);

										SelectObject(cd->nmcd.hdc, hFont);
										SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT);
										return TRUE;
									}
									// draw selected item
									if ((cd->nmcd.uItemState & CDIS_SELECTED) || (pList->labelEdit.iItem == cd->nmcd.dwItemSpec)) {
										SetTextColor(cd->nmcd.hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
										FillRect(cd->nmcd.hdc, &rc, GetSysColorBrush(COLOR_HIGHLIGHT));
									}
									// draw background of unselected item
									else {
										SetTextColor(cd->nmcd.hdc, 
											(pItem->wFlags & CTRLF_CHANGED) 
												? clrChanged : (pItem->wFlags & CTRLF_HASMETA)
													? clrMeta : ((pItem->wFlags & (CTRLF_HASCUSTOM)) && (pItem->wFlags & CTRLF_HASPROTO))
														? clrBoth : (pItem->wFlags & CTRLF_HASCUSTOM)
															? clrCustom	: clrNormal);
										FillRect(cd->nmcd.hdc, &rc, GetSysColorBrush(COLOR_WINDOW));
									}
									SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_NEWFONT|CDRF_NOTIFYSUBITEMDRAW);
									return TRUE;
								
								case CDDS_SUBITEM|CDDS_ITEMPREPAINT:
								{
									HFONT hoFont = (HFONT)SelectObject(cd->nmcd.hdc, pList->hFont);

									ListView_GetSubItemRect(cd->nmcd.hdr.hwndFrom, cd->nmcd.dwItemSpec, cd->iSubItem, LVIR_BOUNDS, &rc);
									if (cd->iSubItem == 0) {
										RECT rc2;
										ListView_GetSubItemRect(cd->nmcd.hdr.hwndFrom, cd->nmcd.dwItemSpec, 1, LVIR_BOUNDS, &rc2);
										rc.right = rc2.left;
									}
									rc.left += 3;
									DrawText(cd->nmcd.hdc,
										pItem->pszText[cd->iSubItem] 
											? pItem->pszText[cd->iSubItem] 
											: (cd->iSubItem == 0 && pItem->idstrList && pItem->iListItem > 0 && pItem->iListItem < pItem->idstrListCount)
												? pItem->idstrList[pItem->iListItem].ptszTranslated
												: TranslateT("<empty>"),
										-1, &rc, DT_END_ELLIPSIS|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER);
									SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT);
									return TRUE;
								}
							} /* switch (cd->nmcd.dwDrawStage) */
							break;
						} /* case NM_CUSTOMDRAW: */
					} /* (((LPNMHDR)lParam)->code) */
					break;
				}
			}
			break; /* case WM_NOTIFY: */

		case WM_COMMAND:
		{
			switch (LOWORD(wParam)) {
				case BTN_ADD_intEREST:
					return ProfileList_AddNewItem(hDlg, (LPLISTCTRL)GetUserData(hList), &pFmt[2]);
				case BTN_ADD_AFFLIATION:
					return ProfileList_AddNewItem(hDlg, (LPLISTCTRL)GetUserData(hList), &pFmt[1]);
				case BTN_ADD_PAST:
					return ProfileList_AddNewItem(hDlg, (LPLISTCTRL)GetUserData(hList), &pFmt[0]);
				case BTN_EDIT_CAT:
					ProfileList_BeginLabelEdit(hList, ListView_GetSelectionMark(hList), 0);
					break;
				case BTN_EDIT_VAL:
					ProfileList_BeginLabelEdit(hList, ListView_GetSelectionMark(hList), 1);
					break;
				case BTN_DEL:
					if (IDYES == MsgBox(hDlg, MB_YESNO|MB_ICON_QUESTION, LPGENT("Question"), LPGENT("Delete an entry"), LPGENT("Do you really want to delete this entry?"))) {
						INT iItem = ListView_GetSelectionMark(hList);
						LPLISTCTRL pList = (LPLISTCTRL)GetUserData(hList);

						ProfileList_DeleteItem(hList, iItem);
						if (PtrIsValid(pList)) pList->wFlags |= CTRLF_CHANGED;
						SendMessage(GetParent(hDlg), PSM_CHANGED, NULL, NULL);
						// check if to delete any devider
						if (!ProfileList_GetItemData(hList, iItem--) && !ProfileList_GetItemData(hList, iItem))
							ListView_DeleteItem(hList, iItem);
					}
					break;
			}
			break;
		}
	}
	return FALSE;
}
Esempio n. 7
0
/**
 * name:	CtrlContactWndProc
 * desc:	window procedure for the extended combobox class
 * param:	hwnd	- handle to a extended combobox window
 *			msg		- message to handle
 *			wParam	- message specific
 *			lParam	- message specific
 * return:	message specific
 **/
static LRESULT CALLBACK CtrlContactWndProc(HWND hwnd, UINT msg,	WPARAM wParam, LPARAM lParam) 
{
	LPCBEX	cbex = (LPCBEX)GetWindowLongPtr(hwnd, 0);

	switch (msg) {

	/**
	* name:	WM_NCCREATE
	* desc:	is called to initiate the window creation
	* param:	wParam - not used
	*			lParam - pointer to a CREATESTRUCT
	*
	* return:	FALSE on error, TRUE if initialisation was ok
	**/
	case WM_NCCREATE:
	{
		LPCREATESTRUCT cs = (LPCREATESTRUCT)lParam;

		if (!(cbex = (LPCBEX)mir_calloc(1*sizeof(CBEX))))
			return FALSE;
		SetWindowLongPtr(hwnd, 0, (LONG_PTR)cbex);
		cbex->bLocked = 1;
		cbex->hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
		cbex->hInstance = cs->hInstance;
		cbex->iSelectedItem = -1;
		cbex->rect.left = cs->x;
		cbex->rect.top = cs->y;
		cbex->rect.right = cs->x + cs->cx;
		cbex->rect.bottom = cs->y + cs->cy;
		return TRUE;
	}

	/**
		* name:	WM_NCCREATE
		* desc:	is called to create all subitems
		* param:	wParam - not used
		*			lParam - not used
		*
		* return:	FALSE on error, TRUE if initialisation was ok
		**/
	case WM_CREATE:
	{
		WORD wHeight = (WORD)(cbex->rect.bottom - cbex->rect.top);
		WORD wWidth = 130;
		WORD x = 0;

		if (!(cbex->hBtnEdit = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
				UINFOBUTTONCLASS, 
				_T("none"),
				WS_VISIBLE|WS_CHILD|WS_TABSTOP, 0, 0,
				wWidth, wHeight,
				hwnd,
				NULL,
				cbex->hInstance, NULL))) {
			cbex->bLocked = 0;
			return FALSE;
		}
		x += wWidth + 2;
		wWidth = wHeight;
		if (!(cbex->hBtnMenu = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
				UINFOBUTTONCLASS,
				NULL,
				WS_VISIBLE|WS_CHILD|WS_TABSTOP|MBS_PUSHBUTTON|MBS_DOWNARROW,
				x, 0,
				wWidth, wHeight,
				hwnd,
				NULL,
				cbex->hInstance, NULL))) {
			DestroyWindow(cbex->hBtnEdit);
			cbex->bLocked = 0;
			return FALSE;
		}
		x += wWidth + 2;
		wWidth = (WORD)(cbex->rect.right - cbex->rect.left - x - (2 * (wHeight + 2)));
		if (!(cbex->hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,
				_T("Edit"), 
				NULL,
				WS_VISIBLE|WS_CHILD|WS_TABSTOP|ES_AUTOHSCROLL,
				x, 1,
				wWidth,	wHeight - 2,
				hwnd,
				NULL,
				cbex->hInstance, NULL))) {
			DestroyWindow(cbex->hBtnEdit);
			DestroyWindow(cbex->hBtnMenu);
			cbex->bLocked = 0;
			return FALSE;
		}
		x += wWidth + 2;
		wWidth = wHeight;
		if (!(cbex->hBtnAdd = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
				UINFOBUTTONCLASS,
				NULL,
				WS_VISIBLE|WS_CHILD|WS_TABSTOP|MBS_FLAT,
				x, 0,
				wWidth, wHeight,
				hwnd,
				NULL,
				cbex->hInstance, NULL))) {
			DestroyWindow(cbex->hBtnEdit);
			DestroyWindow(cbex->hBtnMenu);
			DestroyWindow(cbex->hEdit);
			cbex->bLocked = 0;
			return FALSE;
		}
		x += wWidth + 2;
		if (!(cbex->hBtnDel = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
				UINFOBUTTONCLASS,
				NULL,
				WS_VISIBLE|WS_CHILD|WS_TABSTOP|MBS_FLAT,
				x, 0,
				wWidth, wHeight,
				hwnd,
				NULL,
				cbex->hInstance, NULL))) {
			DestroyWindow(cbex->hBtnEdit);
			DestroyWindow(cbex->hBtnMenu);
			DestroyWindow(cbex->hEdit);
			DestroyWindow(cbex->hBtnAdd);
			cbex->bLocked = 0;
			return FALSE;
		}

		// set ids
		SetWindowLongPtr(cbex->hBtnEdit, GWLP_ID, BTN_EDIT);
		SetWindowLongPtr(cbex->hBtnMenu, GWLP_ID, BTN_MENU);
		SetWindowLongPtr(cbex->hEdit, GWLP_ID, EDIT_VALUE);
		SetWindowLongPtr(cbex->hBtnAdd, GWLP_ID, BTN_ADD);
		SetWindowLongPtr(cbex->hBtnDel, GWLP_ID, BTN_DEL);
		// set fonts & maximum edit control charachters
		SendMessage(cbex->hEdit, WM_SETFONT, (WPARAM)cbex->hFont, NULL);
		SendMessage(cbex->hEdit, EM_LIMITTEXT, (WPARAM)MAXDATASIZE, NULL);
		// add tooltips
		SendMessage(cbex->hBtnMenu, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Choose the item to display"), MBBF_TCHAR);
		SendMessage(cbex->hBtnEdit, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Edit the currently displayed item"), MBBF_TCHAR);
		SendMessage(cbex->hBtnAdd, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Add a new custom item"), MBBF_TCHAR);
		SendMessage(cbex->hBtnDel, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Delete the selected item"), MBBF_TCHAR);
		// reload icons
		CtrlContactWndProc(hwnd, WM_SETICON, NULL, NULL);
		cbex->bLocked = 0;
		return TRUE;
	}

	/**
		* name:	WM_DESTROY
		* desc:	default destroy message, so clear up memory
		* param:	wParam - not used
		*			lParam - not used
		* return:	return value of DefWindowProc
		**/
	case WM_DESTROY:
		CtrlContactWndProc(hwnd, CBEXM_DELALLITEMS, NULL, NULL);
		DestroyWindow(cbex->hBtnEdit);
		DestroyWindow(cbex->hBtnMenu);
		DestroyWindow(cbex->hBtnAdd);
		DestroyWindow(cbex->hBtnDel);
		DestroyWindow(cbex->hEdit);
		MIR_FREE(cbex);
		break;

	/**
		* name:	WM_CTLCOLOREDIT
		* desc:	is called on a paint message for a dialog item to determine its colour scheme
		* param:	wParam - pointer to a HDC
		*			lParam - pointer to a HWND
		* return:	a brush
		**/
	case WM_CTLCOLOREDIT:
		if (!db_get_b(NULL, MODNAME, SET_PROPSHEET_SHOWCOLOURS, 1) || (HWND)lParam != cbex->hEdit || !cbex->pItems || cbex->iSelectedItem < 0) 
			break;
		return Ctrl_SetTextColour((HDC)wParam, cbex->pItems[cbex->iSelectedItem].wFlags);

	case WM_CTLCOLORSTATIC:
		if ((HWND)lParam == cbex->hEdit)
			return (INT_PTR)GetSysColor(COLOR_WINDOW);
		return FALSE;
	/**
		* name:	WM_SETICON
		* desc:	updates the icons of this control
		* param:	wParam - not used
		*			lParam - not used
		* return:	always 0
		**/
	case WM_SETICON:
	{
		HICON hIcon = IcoLib_GetIcon(ICO_BTN_ADD);
		SendMessage(cbex->hBtnAdd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
		SetWindowText(cbex->hBtnAdd, (hIcon ? _T("") : _T("+")));

		hIcon = IcoLib_GetIcon(ICO_BTN_DELETE);
		SendMessage(cbex->hBtnDel, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
		SetWindowText(cbex->hBtnDel, (hIcon ? _T("") : _T("-")));

		if (cbex->pItems && cbex->numItems > 0) {
			for (int i = 0; i < cbex->numItems; i++)
				cbex->pItems[i].hIcon = IcoLib_GetIcon(cbex->pItems[i].pszIcon);

			if (cbex->iSelectedItem >= 0 && cbex->iSelectedItem < cbex->numItems)
				SendMessage(cbex->hBtnEdit, BM_SETIMAGE, IMAGE_ICON, (LPARAM)cbex->pItems[cbex->iSelectedItem].hIcon);
		}
		return 0;
	}

	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		/**
		* name:	BTN_MENU
		* desc:	the button to dropdown the list to show all items is pressed
		**/
		case BTN_MENU:
			if (HIWORD(wParam) == BN_CLICKED) {
				POINT pt = { 0, 0 };
				RECT rc;
				int i, nItems;
				HMENU hMenu;

				if (!(hMenu = CreatePopupMenu())) return 0;
				SetFocus((HWND)lParam);

				MENUITEMINFO mii = { 0 };
				mii.cbSize = sizeof(mii);
				mii.fMask = MIIM_ID|MIIM_STRING|MIIM_FTYPE|MIIM_STATE;
				mii.fType = MFT_STRING;

				// insert the items
				for (i = nItems = 0; i < cbex->numItems; i++) {
					if ((cbex->pItems[i].wFlags & CBEXIF_DELETED) || *cbex->pItems[i].szCat == 0) continue;
					mii.fState = (cbex->pItems[i].pszVal && *cbex->pItems[i].pszVal) ? MFS_CHECKED : MFS_UNCHECKED;
					mii.wID = CBEXM_MENIITEMFIRST + i;
					mii.dwTypeData = cbex->pItems[i].szCat;
					if (!InsertMenuItem(hMenu, i, TRUE, &mii)) {
						DestroyMenu(hMenu);
						return 0;
					}
					nItems++;
				}
				// add separator between default and custom items
				if (nItems > 3) {
					mii.fMask = MIIM_FTYPE;
					mii.fType = MFT_SEPARATOR;
					mii.wID = 0;
					mii.dwItemData = 0;
					InsertMenuItem(hMenu, 3, TRUE, &mii);
				}
				ClientToScreen((HWND)lParam, &pt);
				GetClientRect((HWND)lParam, &rc);
				i = TrackPopupMenuEx(hMenu, TPM_RIGHTALIGN|TPM_RETURNCMD, pt.x + rc.right, pt.y + rc.bottom, hwnd, NULL);
				SendMessage(cbex->hBtnMenu, BM_SETCHECK, NULL, NULL);
				if (i >= CBEXM_MENIITEMFIRST && i < CBEXM_MENIITEMFIRST + cbex->numItems) {
					CtrlContactWndProc(hwnd, CBEXM_SETCURSEL, (WPARAM)i - CBEXM_MENIITEMFIRST, NULL);
				}
				DestroyMenu(hMenu);
				return 0;
			}
			break;

		/**
			* name:	BTN_ADD
			* desc:	the button to add a new entry is pressed
			**/
		case BTN_ADD:
			if (HIWORD(wParam) == BN_CLICKED) {
				DLGPROC dlgProc;
				WORD dlgID;
				TCHAR szCat[MAX_CAT] = { 0 };
				TCHAR szVal[MAXDATASIZE] = { 0 };
				CBEXITEM cbi;
				HWND hDlgDetails;

				SetFocus((HWND)lParam);
				if (!(hDlgDetails = GetParent(GetParent(hwnd)))) return 1;
				if (SendMessage(hDlgDetails, PSM_ISLOCKED, NULL, NULL)) return 0;
						
				switch (GetWindowLongPtr(hwnd, GWLP_ID)) {
					case EDIT_PHONE:
						dlgID = IDD_ADDPHONE;
						dlgProc = DlgProc_Phone;
						cbi.pszIcon = ICO_BTN_CUSTOMPHONE;
						break;
					case EDIT_EMAIL:
						dlgID = IDD_ADDEMAIL;
						dlgProc = DlgProc_EMail;
						cbi.pszIcon = ICO_BTN_EMAIL;
						break;
					default:
						return 1;
				}
							
				cbi.iItem = -1;
				cbi.wMask = CBEXIM_CAT|CBEXIM_VAL|CBEXIM_FLAGS|CBEXIM_ICONTEXT;
				cbi.pszCat = szCat;
				cbi.pszVal = szVal;
				cbi.ccCat = MAX_CAT;
				cbi.ccVal = MAXDATASIZE;
				cbi.wFlags = 0;
				cbi.dwID = 0;

				if (DialogBoxParam(ghInst, MAKEINTRESOURCE(dlgID), GetParent(hwnd), dlgProc, (LPARAM)&cbi) == IDOK) {
					MCONTACT hContact = NULL;
							
					SendMessage(hDlgDetails, PSM_GETCONTACT, NULL, (LPARAM)&hContact);
					if (hContact) cbi.wFlags |= CTRLF_HASCUSTOM;
					cbi.wFlags |= CTRLF_CHANGED;
					if (SendMessage(hwnd, CBEXM_ADDITEM, NULL, (LPARAM)&cbi) > CB_ERR) {
						SendMessage(hDlgDetails, PSM_CHANGED, NULL, NULL);
						cbex->bIsChanged = TRUE;
						SendMessage(hwnd, CBEXM_SETCURSEL, cbex->numItems - 1, NULL);
					}
				}
				return 0;
			}
			break;

		/**
			* name:	BTN_EDIT
			* desc:	the button to edit an existing entry is pressed
			**/
		case BTN_EDIT:
			if (HIWORD(wParam) == BN_CLICKED) {
				DLGPROC dlgProc;
				WORD dlgID;
				TCHAR szCat[MAX_CAT] = { 0 };
				TCHAR szVal[MAXDATASIZE] = { 0 };
				CBEXITEM cbi;
				HWND hDlgDetails;

				SetFocus((HWND)lParam);
				if (!(hDlgDetails = GetParent(GetParent(hwnd)))) return 1;
				if (SendMessage(hDlgDetails, PSM_ISLOCKED, NULL, NULL)) return 0;
				if (!cbex->pItems || cbex->iSelectedItem == -1) return 0;

				switch (GetWindowLongPtr(hwnd, GWLP_ID)) {
					case EDIT_PHONE:
						dlgID = IDD_ADDPHONE;
						dlgProc = DlgProc_Phone;
						break;
					case EDIT_EMAIL:
						dlgID = IDD_ADDEMAIL;
						dlgProc = DlgProc_EMail;
						break;
					default:
						return 1;
				}
				cbi.iItem = cbex->iSelectedItem;
				cbi.dwID = 0;
				cbi.wMask = CBEXIM_CAT|CBEXIM_VAL|CBEXIM_FLAGS;
				cbi.pszCat = szCat;
				cbi.pszVal = szVal;
				cbi.ccCat = MAX_CAT;
				cbi.ccVal = MAXDATASIZE;
				if (!CtrlContactWndProc(hwnd, CBEXM_GETITEM, NULL, (LPARAM)&cbi)) {
					MsgErr(hwnd, LPGENT("CRITICAL: Unable to edit current entry!\nThis should not happen!"));
					return 1;
				}

				if (DialogBoxParam(ghInst, MAKEINTRESOURCE(dlgID), GetParent(hwnd), dlgProc, (LPARAM)&cbi) == IDOK) {
					MCONTACT hContact;

					SendMessage(hDlgDetails, PSM_GETCONTACT, NULL, (LPARAM)&hContact);
					if (hContact) cbi.wFlags |= CTRLF_HASCUSTOM;
					cbi.wFlags |= CTRLF_CHANGED;
					SendMessage(hwnd, CBEXM_SETITEM, NULL, (LPARAM)&cbi);
					SendMessage(hDlgDetails, PSM_CHANGED, NULL, NULL);
					cbex->bIsChanged = TRUE;
				}
				return 0;
			}
			break;

		/**
			* name:	BTN_DEL
			* desc:	the button to delete an existing entry is pressed
			**/
		case BTN_DEL:
			if (HIWORD(wParam) == BN_CLICKED) {
				HWND hDlgDetails;
				MSGBOX mBox;
				TCHAR szMsg[MAXDATASIZE];
					
				SetFocus((HWND)lParam);
				if (!(hDlgDetails = GetParent(GetParent(hwnd))) ||
						SendMessage(hDlgDetails, PSM_ISLOCKED, NULL, NULL) ||
						!cbex->pItems ||
						cbex->iSelectedItem < 0 ||
						cbex->iSelectedItem >= cbex->numItems ||
						FAILED(mir_sntprintf(szMsg, TranslateT("Do you really want to delete the current selected item?\n\t%s\n\t%s"),
						cbex->pItems[cbex->iSelectedItem].szCat, cbex->pItems[cbex->iSelectedItem].pszVal))
			)
				{
						return 1;
				}
				mBox.cbSize = sizeof(MSGBOX);
				mBox.hParent = hDlgDetails;
				mBox.hiLogo = IcoLib_GetIcon(ICO_DLG_PHONE);
				mBox.uType = MB_YESNO|MB_ICON_QUESTION|MB_NOPOPUP;
				mBox.ptszTitle = TranslateT("Delete");
				mBox.ptszMsg = szMsg;
				if (IDYES == MsgBoxService(NULL, (LPARAM)&mBox)) {
					// clear value for standard entry
					if (cbex->pItems[cbex->iSelectedItem].wFlags & CBEXIF_CATREADONLY) {
						MIR_FREE(cbex->pItems[cbex->iSelectedItem].pszVal);
						SetWindowText(cbex->hEdit, _T(""));
						cbex->pItems[cbex->iSelectedItem].wFlags &= ~CBEXIF_SMS;
						cbex->pItems[cbex->iSelectedItem].wFlags |= CTRLF_CHANGED;
					}
					// clear values for customized database entry
					else 
					if (cbex->pItems[cbex->iSelectedItem].dwID != 0) {
						MIR_FREE(cbex->pItems[cbex->iSelectedItem].pszVal);
						*cbex->pItems[cbex->iSelectedItem].szCat = 0;
						cbex->pItems[cbex->iSelectedItem].wFlags |= CTRLF_CHANGED|CBEXIF_DELETED;
						CtrlContactWndProc(hwnd, CBEXM_SETCURSEL, cbex->iSelectedItem - 1, FALSE);
					}
					// delete default entry
					else
						CtrlContactWndProc(hwnd, CBEXM_DELITEM, NULL, cbex->iSelectedItem);

					SendMessage(hDlgDetails, PSM_CHANGED, NULL, NULL);
					cbex->bIsChanged = TRUE;
				}
				return 0;
			}
			break;

		/**
			* name:	EDIT_VALUE
			* desc:	the edit control wants us to act
			**/
		case EDIT_VALUE:
			switch (HIWORD(wParam)) {
				case EN_UPDATE:
				{
					TCHAR szVal[MAXDATASIZE] = { 0 };
					int ccVal;
					MCONTACT hContact;
					HWND hDlgDetails = GetParent(GetParent(hwnd));
							
					EnableWindow(cbex->hBtnDel, GetWindowTextLength(cbex->hEdit) > 0);

					if (SendMessage(hDlgDetails, PSM_ISLOCKED, NULL, NULL) ||
						cbex->bLocked || 
						!cbex->pItems || 
						cbex->iSelectedItem < 0 || 
						cbex->iSelectedItem >= cbex->numItems) return 1;

					// get the edit control's text value and check it for syntax
					switch (GetWindowLongPtr(hwnd, GWLP_ID)) {
						case EDIT_PHONE:
						{
							int errorPos;
							TCHAR szEdit[MAXDATASIZE];

							if (ccVal = GetWindowText(cbex->hEdit, szEdit, _countof(szEdit))) {
								if (!(ccVal = CheckPhoneSyntax(szEdit, szVal, MAXDATASIZE, errorPos)) || errorPos > -1) {
									SetWindowText(cbex->hEdit, szVal);
									SendMessage(cbex->hEdit, EM_SETSEL, errorPos, errorPos);
								}
							}
							break;
						}
						case EDIT_EMAIL:
							ccVal = GetWindowText(cbex->hEdit, szVal, _countof(szVal));
							break;
						default:
							ccVal = GetWindowText(cbex->hEdit, szVal, _countof(szVal));
							break;
					}
							
					SendMessage(hDlgDetails, PSM_GETCONTACT, NULL, (LPARAM)&hContact);
					if ((cbex->pItems[cbex->iSelectedItem].wFlags & CTRLF_CHANGED) && !(hContact && (cbex->pItems[cbex->iSelectedItem].wFlags & CTRLF_HASCUSTOM))) return 0;
							
					if (*szVal == 0 || !cbex->pItems[cbex->iSelectedItem].pszVal || mir_tstrcmp(szVal, cbex->pItems[cbex->iSelectedItem].pszVal)) {
						cbex->pItems[cbex->iSelectedItem].wFlags |= CTRLF_CHANGED;
						cbex->pItems[cbex->iSelectedItem].wFlags |= (hContact ? CTRLF_HASCUSTOM : CTRLF_HASPROTO);
						cbex->bIsChanged = TRUE;
						InvalidateRect((HWND)lParam, NULL, TRUE);
						SendMessage(hDlgDetails, PSM_CHANGED, NULL, NULL);
					}
					return 0;
				}
				case EN_KILLFOCUS:
				{
					int ccText;
							
					if (!cbex->pItems || cbex->iSelectedItem < 0 || cbex->iSelectedItem >= cbex->numItems) return 1;
					if (!(cbex->pItems[cbex->iSelectedItem].wFlags & CTRLF_CHANGED)) return 0;

					if ((ccText = GetWindowTextLength(cbex->hEdit)) <= 0) {
						if (cbex->pItems[cbex->iSelectedItem].wFlags & CBEXIF_CATREADONLY) {
							MIR_FREE(cbex->pItems[cbex->iSelectedItem].pszVal);
							SetWindowText(cbex->hEdit, _T(""));
							cbex->pItems[cbex->iSelectedItem].wFlags &= ~CBEXIF_SMS;
						}
						else
							CtrlContactWndProc(hwnd, CBEXM_DELITEM, NULL, cbex->iSelectedItem);
						SendMessage(GetParent(GetParent(hwnd)), PSM_CHANGED, NULL, NULL);
						cbex->bIsChanged = TRUE;
					}
					else
					if (cbex->pItems[cbex->iSelectedItem].pszVal = (LPTSTR)mir_realloc(cbex->pItems[cbex->iSelectedItem].pszVal, (ccText + 2) * sizeof(TCHAR))) {
						cbex->pItems[cbex->iSelectedItem].pszVal[ccText + 1] = 0;
						GetWindowText(cbex->hEdit, cbex->pItems[cbex->iSelectedItem].pszVal, ccText + 1);
					}
					return 0;
				}
			}
			break;
		}
		break;

	/**
		* name:	CBEXM_ADDITEM
		* desc:	add a item to the control
		* param:	wParam - not used
		*			lParam - (LPCBEXITEM)&item
		* return:	CB_ERR on failure, new item index if successful
		**/
	case CBEXM_ADDITEM:
	{
		LPCBEXITEM	pItem = (LPCBEXITEM)lParam;

		if (!pItem) return FALSE;

		// if an item with the id of pItem exists, change it instead of adding a new one
		// but only if it has not been changed by the user yet.
		if ((pItem->wMask & CBEXIM_ID) && cbex->pItems && pItem->dwID != 0) {
			int iIndex;
				
			for (iIndex = 0; iIndex < cbex->numItems; iIndex++) {
				if (cbex->pItems[iIndex].dwID == pItem->dwID) {
					pItem->iItem = iIndex;
					if (cbex->pItems[iIndex].wFlags & CTRLF_CHANGED)
						pItem->wFlags |= CTRLF_CHANGED;
					else
						CtrlContactWndProc(hwnd, CBEXM_SETITEM, 0, lParam);
					return iIndex;
				}
			}
		}

		// add a new item to the combobox
		if (!(cbex->pItems = (LPCBEXITEMINTERN)mir_realloc(cbex->pItems, (cbex->numItems + 1) * sizeof(CBEXITEMINTERN)))) {
			cbex->numItems = 0;
			return CB_ERR;
		}
		
		// set the ID
		cbex->pItems[cbex->numItems].dwID = (pItem->wMask & CBEXIM_ID) ? pItem->dwID : 0;

		// set category string
		if (!pItem->pszCat || !pItem->pszCat[0] || !mir_tstrncpy(cbex->pItems[cbex->numItems].szCat, pItem->pszCat, MAX_CAT)) {
			mir_sntprintf(cbex->pItems[cbex->numItems].szCat, _T("%s %d"), TranslateT("Other"), ++cbex->numOther);
		}

		// set value string
		if ((pItem->wMask & CBEXIM_VAL) && pItem->pszVal && pItem->pszVal[0])
			cbex->pItems[cbex->numItems].pszVal = mir_tstrdup(pItem->pszVal);
		else
			cbex->pItems[cbex->numItems].pszVal = NULL;
		// set icon
		if ((pItem->wMask & CBEXIM_ICONTEXT) && pItem->pszIcon) {
			cbex->pItems[cbex->numItems].pszIcon = pItem->pszIcon;
			cbex->pItems[cbex->numItems].hIcon = IcoLib_GetIcon(pItem->pszIcon);
		}
		// set flags
		cbex->pItems[cbex->numItems].wFlags = (pItem->wMask & CBEXIM_CAT) ? pItem->wFlags : 0;

		cbex->numItems++;
		return cbex->numItems;
	}

	/**
		* name:	CBEXM_SETITEM
		* desc:	Set an item's information of the control.
		*			If iItem member of CBEXITEM is -1, the currently selected item is changed.
		* param:	wParam - not used
		*			lParam - (LPCBEXITEM)&item
		* return:	CB_ERR on failure, new item index if successful
		**/
	case CBEXM_SETITEM:
	{
		LPCBEXITEM	pItem = (LPCBEXITEM)lParam;

		if (!PtrIsValid(pItem) || !pItem->wMask || !PtrIsValid(cbex->pItems)) return FALSE;
		if (pItem->iItem == -1) pItem->iItem = cbex->iSelectedItem;
		if (pItem->iItem < 0 || pItem->iItem >= cbex->numItems) return FALSE;

		// set new category string
		if (pItem->wMask & CBEXIM_CAT) {
			// set category string
			if (!pItem->pszCat || !pItem->pszCat[0] || !mir_tstrncpy(cbex->pItems[pItem->iItem].szCat, pItem->pszCat, _countof(cbex->pItems[pItem->iItem].szCat))) 
				mir_sntprintf(cbex->pItems[pItem->iItem].szCat, _T("%s %d"), TranslateT("Other"), ++cbex->numOther);
			if (pItem->iItem == cbex->iSelectedItem)
				SetWindowText(cbex->hBtnEdit, cbex->pItems[pItem->iItem].szCat);
		}
		// set new value
		if (pItem->wMask & CBEXIM_VAL) {
			MIR_FREE(cbex->pItems[pItem->iItem].pszVal);
			if (pItem->pszVal && pItem->pszVal[0])
				cbex->pItems[pItem->iItem].pszVal = mir_tstrdup(pItem->pszVal);
			if (pItem->iItem == cbex->iSelectedItem)
				SetWindowText(cbex->hEdit, cbex->pItems[pItem->iItem].pszVal ? cbex->pItems[pItem->iItem].pszVal : _T(""));
		}

		// set icon
		if ((pItem->wMask & CBEXIM_ICONTEXT) && pItem->pszIcon) {
			cbex->pItems[pItem->iItem].pszIcon = pItem->pszIcon;
			cbex->pItems[pItem->iItem].hIcon = IcoLib_GetIcon(pItem->pszIcon);
			if (pItem->iItem == cbex->iSelectedItem)
				SendMessage(cbex->hBtnEdit, BM_SETIMAGE, IMAGE_ICON, (LPARAM)cbex->pItems[pItem->iItem].hIcon);
		}
		if (pItem->wMask & CBEXIM_FLAGS) {
			cbex->pItems[pItem->iItem].wFlags = pItem->wFlags;
			CtrlContactWndProc(hwnd, CBEXM_ENABLEITEM, NULL, NULL);
		}
		return TRUE;
	}

	/**
		* name:	CBEXM_GETITEM
		* desc:	Get an item from the control.
		*			If iItem member of CBEXITEM is -1, the currently selected item is returned.
		* param:	wParam - not used
		*			lParam - (LPCBEXITEM)&item
		* return:	CB_ERR on failure, new item index if successful
		**/
	case CBEXM_GETITEM:
	{
		LPCBEXITEM	pItem = (LPCBEXITEM)lParam;

		if (!pItem || !cbex->pItems) return FALSE;
			
		// try to find item by id
		if ((pItem->wMask & CBEXIM_ID) && pItem->dwID != 0) {
			int i;

			for (i = 0; i < cbex->numItems; i++) {
				if (cbex->pItems[i].dwID == pItem->dwID)
					break;
			}
			pItem->iItem = i;
		}
		else
		if (pItem->iItem == -1) pItem->iItem = cbex->iSelectedItem;
		if (pItem->iItem < 0 || pItem->iItem >= cbex->numItems) return FALSE;
			
		// return only currently selected itemindex
		if (!pItem->wMask) return TRUE;
		// return the unique id
		if (pItem->wMask & CBEXIM_ID) 
			pItem->dwID = cbex->pItems[pItem->iItem].dwID;
		// return category string
		if ((pItem->wMask & CBEXIM_CAT) && pItem->pszCat) {
			if (*cbex->pItems[pItem->iItem].szCat != 0)
				mir_tstrncpy(pItem->pszCat, cbex->pItems[pItem->iItem].szCat, pItem->ccCat - 1);
			else
				*pItem->pszCat = 0;
		}
		// return value string
		if ((pItem->wMask & CBEXIM_VAL) && pItem->pszVal) {
			if (cbex->pItems[pItem->iItem].pszVal)
				mir_tstrncpy(pItem->pszVal, cbex->pItems[pItem->iItem].pszVal, pItem->ccVal - 1);
			else
				*pItem->pszVal = 0;
		}
		// return the icon
		if (pItem->wMask & CBEXIM_ICONTEXT)
			pItem->pszIcon = cbex->pItems[pItem->iItem].pszIcon;
		// return the flags
		if (pItem->wMask & CBEXIM_FLAGS)
			pItem->wFlags = cbex->pItems[pItem->iItem].wFlags;
		return TRUE;
	}

	/**
		* name:	CBEXM_DELITEM
		* desc:	delete an item from the control
		* param:	wParam - not used
		*			lParam - item index
		* return:	CB_ERR on failure, new item index if successful
		**/
	case CBEXM_DELITEM:
	{
		if (!cbex->pItems || (int)lParam < 0 || (int)lParam >= cbex->numItems || (cbex->pItems[lParam].wFlags & CBEXIF_CATREADONLY))
			return FALSE;	
		MIR_FREE(cbex->pItems[(int)lParam].pszVal);
		memmove(cbex->pItems + (int)lParam, 
			cbex->pItems + (int)lParam + 1,
			(cbex->numItems - (int)lParam - 1) * sizeof(CBEXITEMINTERN));
		cbex->numItems--;
		memset((cbex->pItems + cbex->numItems), 0, sizeof(CBEXITEMINTERN));
		CtrlContactWndProc(hwnd, CBEXM_SETCURSEL, lParam - 1, FALSE);
		return TRUE;
	}

	/**
		* name:	CBEXM_DELITEM
		* desc:	delete an item from the control
		* param:	wParam - not used
		*			lParam - item index
		* return:	CB_ERR on failure, new item index if successful
		**/
	case CBEXM_DELALLITEMS:
	{
		int i;

		if (PtrIsValid(cbex)) {
			if (PtrIsValid(cbex->pItems)) {
				for (i = 0; i < cbex->numItems; i++) {
					MIR_FREE(cbex->pItems[i].pszVal);
				}
				MIR_FREE(cbex->pItems);
				cbex->pItems = NULL;
			}
			cbex->numItems = 0;
			cbex->iSelectedItem = -1;
			SetWindowText(cbex->hEdit, _T(""));
			SetWindowText(cbex->hBtnEdit, _T(""));
			SendMessage(cbex->hBtnEdit, WM_SETICON, NULL, NULL);
		}
		return TRUE;
	}

	/**
		* name:	CBEXM_ENABLEITEM
		* desc:	enables or disables the current item
		* param:	wParam - not used
		*			lParam - not used
		* return:	always 0
		**/
	case CBEXM_ENABLEITEM:
		if (cbex->iSelectedItem >= 0 && cbex->iSelectedItem < cbex->numItems) {
			MCONTACT hContact;
			BYTE bEnabled;
				
			PSGetContact(GetParent(hwnd), hContact);

			bEnabled	= !hContact ||
						(cbex->pItems[cbex->iSelectedItem].wFlags & CTRLF_HASCUSTOM) || 
						!(cbex->pItems[cbex->iSelectedItem].wFlags & (CTRLF_HASPROTO|CTRLF_HASMETA)) ||
						!db_get_b(NULL, MODNAME, SET_PROPSHEET_PCBIREADONLY, 0);

			EnableWindow(cbex->hBtnEdit, bEnabled);
			EnableWindow(cbex->hBtnDel, bEnabled && GetWindowTextLength(cbex->hEdit) > 0);
			EnableWindow(cbex->hEdit, bEnabled);
		}
		break;

	/**
		* name:	CBEXM_ISCHANGED
		* desc:	returns whether the control contains changed values or not
		* param:	wParam - not used
		*			lParam - not used
		* return:	TRUE if control was changed, FALSE if nothing was edited
		**/
	case CBEXM_ISCHANGED:
		return cbex->bIsChanged;

	/**
		* name:	CBEXM_RESETCHANGED
		* desc:	resets changed flag to FALSE
		* param:	wParam - not used
		*			lParam - not used
		* return:	always FALSE
		**/
	case CBEXM_RESETCHANGED:
		cbex->bIsChanged = 0;
		return 0;

	/**
		* name:	CBEXM_SETCURSEL
		* desc:	selects a certain item
		* param:	wParam - index of the item to select
		*			lParam - (BYTE)bValid - if TRUE, the next item with a value is selected
		* return:	always FALSE
		**/
	case CBEXM_SETCURSEL:
	{
		int i;

		if (!cbex->pItems) return 1;
		if ((int)wParam < 0 || (int)wParam >= cbex->numItems) wParam = max(cbex->iSelectedItem, 0);
		cbex->bLocked = 1;
			
		if ((BYTE)lParam == TRUE) {
			i = (int)wParam;

			cbex->iSelectedItem = (int)wParam;
			while (i < cbex->numItems) {
				if (cbex->pItems[i].pszVal && *cbex->pItems[i].pszVal) {
					cbex->iSelectedItem = i;
					break;
				}
				i++;
			}
		}
		else {
			// search for the next none deleted item
			for (i = (int)wParam; i < cbex->numItems && *cbex->pItems[i].szCat == 0; i++);
			if (i == cbex->numItems && (int)wParam > 0) {
				for (i = 0; i < (int)wParam && *cbex->pItems[i].szCat == 0; i++);
				cbex->iSelectedItem = i == (int)wParam ? 0 : i;
			}
			else
				cbex->iSelectedItem = i;

		}
		SetWindowText(cbex->hBtnEdit, cbex->pItems[cbex->iSelectedItem].szCat);
		SetWindowText(cbex->hEdit, cbex->pItems[cbex->iSelectedItem].pszVal ? cbex->pItems[cbex->iSelectedItem].pszVal : _T(""));
		SendMessage(cbex->hBtnEdit, BM_SETIMAGE, IMAGE_ICON, (LPARAM)cbex->pItems[cbex->iSelectedItem].hIcon);
		CtrlContactWndProc(hwnd, CBEXM_ENABLEITEM, NULL, NULL);
		cbex->bLocked = 0;
		return 0;
	}
	case CBEXM_SORT:
		if (cbex->numItems > 4) {
			qsort(cbex->pItems + 3, cbex->numItems - 3, sizeof(CBEXITEMINTERN), compareProc);
		}
		return 0;

	case WM_ERASEBKGND:
		return 1;

	case WM_SETFOCUS:
		SetFocus(cbex->hEdit);
		SendMessage(cbex->hEdit, EM_SETSEL, 0, (LPARAM)-1);
		return 0;
	}
	return DefWindowProc(hwnd, msg, wParam, lParam);
}
Esempio n. 8
0
/**
 * Dialog procedure for the contact information propertysheetpage
 *
 * @param	 hDlg	- handle to the dialog window
 * @param	 uMsg	- the message to handle
 * @param	 wParam	- parameter
 * @param	 lParam	- parameter
 *
 * @return	different values
 **/
INT_PTR CALLBACK PSPProcGeneral(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {
	case WM_INITDIALOG:
		{
			CCtrlList *pCtrlList = CCtrlList::CreateObj(hDlg);
			if (pCtrlList) {
				LPIDSTRLIST pList;
				UINT nList;
				HFONT hBoldFont;
				
				PSGetBoldFont(hDlg, hBoldFont);
				SendDlgItemMessage(hDlg, IDC_PAGETITLE, WM_SETFONT, (WPARAM)hBoldFont, 0);
				TranslateDialogDefault(hDlg);

				pCtrlList->insert(CEditCtrl::CreateObj(hDlg, EDIT_TITLE, SET_CONTACT_TITLE, DBVT_TCHAR));
				pCtrlList->insert(CEditCtrl::CreateObj(hDlg, EDIT_FIRSTNAME, SET_CONTACT_FIRSTNAME, DBVT_TCHAR));
				pCtrlList->insert(CEditCtrl::CreateObj(hDlg, EDIT_SECONDNAME, SET_CONTACT_SECONDNAME, DBVT_TCHAR));
				pCtrlList->insert(CEditCtrl::CreateObj(hDlg, EDIT_LASTNAME, SET_CONTACT_LASTNAME, DBVT_TCHAR));
				pCtrlList->insert(CEditCtrl::CreateObj(hDlg, EDIT_NICK, SET_CONTACT_NICK, DBVT_TCHAR));
				pCtrlList->insert(CEditCtrl::CreateObj(hDlg, EDIT_DISPLAYNAME, "CList", SET_CONTACT_MYHANDLE, DBVT_TCHAR));
				pCtrlList->insert(CEditCtrl::CreateObj(hDlg, EDIT_PARTNER, SET_CONTACT_PARTNER, DBVT_TCHAR));

				GetNamePrefixList(&nList, &pList);
				pCtrlList->insert(CCombo::CreateObj(hDlg, EDIT_PREFIX, SET_CONTACT_PREFIX, DBVT_BYTE, pList, nList));

				// marital groupbox
				GetMaritalList(&nList, &pList);
				pCtrlList->insert(CCombo::CreateObj(hDlg, EDIT_MARITAL, SET_CONTACT_MARITAL, DBVT_BYTE, pList, nList));

				GetLanguageList(&nList, &pList);
				pCtrlList->insert(CCombo::CreateObj(hDlg, EDIT_LANG1, SET_CONTACT_LANG1, DBVT_TCHAR, pList, nList));
				pCtrlList->insert(CCombo::CreateObj(hDlg, EDIT_LANG2, SET_CONTACT_LANG2, DBVT_TCHAR, pList, nList));
				pCtrlList->insert(CCombo::CreateObj(hDlg, EDIT_LANG3, SET_CONTACT_LANG3, DBVT_TCHAR, pList, nList));
			}
		}
		break;

	case WM_NOTIFY:
		{
			switch (((LPNMHDR)lParam)->idFrom) {
			case 0:
				{
					MCONTACT hContact = (MCONTACT)((LPPSHNOTIFY)lParam)->lParam;
					char* pszProto;

					switch (((LPNMHDR)lParam)->code) {
					case PSN_INFOCHANGED:
						{
							BYTE bEnable;
							DBVARIANT dbv;
							CCtrlFlags Flags;
		
							if (PSGetBaseProto(hDlg, pszProto) && *pszProto) {
								Flags.W = DB::Setting::GetTStringCtrl(hContact, USERINFO, USERINFO, pszProto, SET_CONTACT_GENDER, &dbv);
								if (Flags.B.hasCustom || Flags.B.hasProto || Flags.B.hasMeta) {
									if (dbv.type == DBVT_BYTE) {
										CheckDlgButton(hDlg, RADIO_FEMALE, (dbv.bVal == 'F'));
										CheckDlgButton(hDlg, RADIO_MALE, (dbv.bVal == 'M'));

										bEnable = !hContact || Flags.B.hasCustom || !db_get_b(NULL, MODNAME, SET_PROPSHEET_PCBIREADONLY, 0);
										EnableWindow(GetDlgItem(hDlg, RADIO_FEMALE), bEnable);
										EnableWindow(GetDlgItem(hDlg, RADIO_MALE), bEnable);
									}
									else
										db_free(&dbv);
								}
							}
						}
						break;

					case PSN_APPLY:
						{
							if (!PSGetBaseProto(hDlg, pszProto) || *pszProto == 0)
								break;

							// gender
							{
								BYTE gender
									= SendDlgItemMessage(hDlg, RADIO_FEMALE, BM_GETCHECK, NULL, NULL)
									? 'F'
									: SendDlgItemMessage(hDlg, RADIO_MALE, BM_GETCHECK, NULL, NULL)
									? 'M'
									: 0;

								if (gender)
									db_set_b(hContact, hContact ? USERINFO : pszProto, SET_CONTACT_GENDER, gender);
								else
									db_unset(hContact, hContact ? USERINFO : pszProto, SET_CONTACT_GENDER);
							}
						}
						break;

					case PSN_ICONCHANGED:
						{
							const ICONCTRL idIcon[] = {
								{ ICO_COMMON_FEMALE,  STM_SETIMAGE, ICO_FEMALE },
								{ ICO_COMMON_MALE,    STM_SETIMAGE, ICO_MALE },
								{ ICO_COMMON_MARITAL, STM_SETIMAGE, ICO_MARITAL },
							};
							IcoLib_SetCtrlIcons(hDlg, idIcon, SIZEOF(idIcon));
						}
					}
				}
			}
		}
		break;

	case WM_COMMAND:
		{
			MCONTACT hContact;
			LPCSTR pszProto;

			switch (LOWORD(wParam)) {
			case RADIO_FEMALE:
				{
					if (!PspIsLocked(hDlg) && HIWORD(wParam) == BN_CLICKED) {
						DBVARIANT dbv;

						PSGetContact(hDlg, hContact);
						PSGetBaseProto(hDlg, pszProto);

						if (!DB::Setting::GetAsIsCtrl(hContact, USERINFO, USERINFO, pszProto, SET_CONTACT_GENDER, &dbv)
							|| dbv.type != DBVT_BYTE
							|| (dbv.bVal != 'F' && SendMessage((HWND)lParam, BM_GETCHECK, NULL, NULL)))
							SendMessage(GetParent(hDlg), PSM_CHANGED, NULL, NULL);
					}
				}
				break;

			case RADIO_MALE:
				{
					if (!PspIsLocked(hDlg) && HIWORD(wParam) == BN_CLICKED) {
						DBVARIANT dbv;

						PSGetContact(hDlg, hContact);
						PSGetBaseProto(hDlg, pszProto);

						if (!DB::Setting::GetAsIsCtrl(hContact, USERINFO, USERINFO, pszProto, SET_CONTACT_GENDER, &dbv)
							|| dbv.type != DBVT_BYTE
							|| (dbv.bVal != 'M' && SendMessage((HWND)lParam, BM_GETCHECK, NULL, NULL)))
							SendMessage(GetParent(hDlg), PSM_CHANGED, NULL, NULL);
					}
				}
			}
		}
	}
	return PSPBaseProc(hDlg, uMsg, wParam, lParam);
}