From 171e81205e357e0d54283a63997ed58ff97d54a9 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 24 Jul 2012 11:48:31 +0000 Subject: UserInfoEx, Variables: changed folder structure git-svn-id: http://svn.miranda-ng.org/main/trunk@1160 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/UserInfoEx/src/psp_profile.cpp | 1464 ++++++++++++++++++++++++++++++++ 1 file changed, 1464 insertions(+) create mode 100644 plugins/UserInfoEx/src/psp_profile.cpp (limited to 'plugins/UserInfoEx/src/psp_profile.cpp') diff --git a/plugins/UserInfoEx/src/psp_profile.cpp b/plugins/UserInfoEx/src/psp_profile.cpp new file mode 100644 index 0000000000..e964db40f6 --- /dev/null +++ b/plugins/UserInfoEx/src/psp_profile.cpp @@ -0,0 +1,1464 @@ +/* +UserinfoEx plugin for Miranda IM + +Copyright: +ฉ 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +=============================================================================== + +File name : $HeadURL: https://userinfoex.googlecode.com/svn/trunk/psp_profile.cpp $ +Revision : $Revision: 187 $ +Last change on : $Date: 2010-09-08 16:05:54 +0400 (ะกั€, 08 ัะตะฝ 2010) $ +Last change by : $Author: ing.u.horn $ + +=============================================================================== +*/ + +/** + * system & local includes + **/ +#include "commonheaders.h" +#include "ctrl_base.h" + +#define LVF_EDITLABEL 8 + +#define CELIF_CUSTOM 8 // entry is userdefined (e.g. MyPhoneXX) +#define CELIF_SMS 16 // phone with ability to receive sms +#define LIF_TIPVISIBLE 32 // set if infotip is visible + +typedef struct TCECListItem : CTRL { + LPIDSTRLIST idstrList; + INT idstrListCount; + INT iListItem; + LPTSTR pszText[2]; +} LCITEM, *LPLCITEM; + +typedef struct TListCtrl : CTRL { + HWND hList; + HWND hTip; + POINT ptTip; + INT iHotItem; + INT iHotSubItem; + HFONT hFont; + + struct { + HWND hEdit; // handle to edit window + HWND hBtn; // button to open dropdown list + RECT rcCombo; + struct { + HWND hDrop; // dropdown list + INT iItem; // currently selected item of the dropdown + } dropDown; + LPLCITEM pItem; // the item beiing edited + INT iItem; // zero based index to item in the listview + INT iSubItem; // zero based index to subitem + INT iTopIndex; // zero based index to first visible item on list + } labelEdit; +} LISTCTRL, *LPLISTCTRL; + +typedef INT (*MISERVICE)(WPARAM wParam, LPARAM lParam); + +typedef struct TProfileEntries { + LPTSTR szGroup; + LPCSTR szCatFmt; + LPCSTR szValFmt; + MIRANDASERVICE GetList; +} PROFILEENTRY, *LPPROFILEENTRY; + +static const PROFILEENTRY pFmt[3] = { + { LPGENT("Past"), "Past%d", "Past%dText", (MIRANDASERVICE)GetPastList }, + { LPGENT("Affiliation"),"Affiliation%d", "Affiliation%dText", (MIRANDASERVICE)GetAffiliationsList }, + { LPGENT("Interest"), "Interest%dCat", "Interest%dText", (MIRANDASERVICE)GetInterestsList } +}; + +static WNDPROC OldListViewProc = NULL; // listview control's default window procedure +static WNDPROC OldEditProc = NULL; // edit control's default window procedure +static WNDPROC OldDropdownProc = NULL; // listbox control's default window procedure + +static INT_PTR CALLBACK ProfileList_LabelEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +extern COLORREF clrBoth; +extern COLORREF clrChanged; +extern COLORREF clrCustom; +extern COLORREF clrNormal; +extern COLORREF clrMeta; + + +/** + * name: ProfileList_AddGroup + * desc: add a group to the listview + * param: hList - handle to listview control + * pszText - text of new group + * return: index the where group was added + **/ +static INT ProfileList_AddGroup(HWND hList, LPTSTR pszText, INT iItem) +{ + LVITEM lvi; + lvi.mask = LVIF_TEXT|LVIF_PARAM; + lvi.iItem = iItem; + lvi.iSubItem = 0; + lvi.pszText = pszText; + lvi.lParam = NULL; + return ListView_InsertItem(hList, &lvi); +} + +/** + * name: ProfileList_GetItemText + * desc: returns the text of a listview item + * param: hList - handle to listview control + * iItem - item index + * iSubItem - subitem (column) index + * pszText - pointer of a buffer to retrieve the text + * ccText - number of maximal characters pszText can take + * return: number of read characters + **/ +static INT ProfileList_GetItemText(HWND hList, INT iItem, INT iSubItem, LPTSTR pszText, INT ccText) +{ + LVITEM lvi; + TCHAR szNull[2]; + + lvi.mask = LVIF_TEXT; + lvi.iItem = iItem; + lvi.iSubItem = iSubItem; + lvi.cchTextMax = ccText ? ccText : 2; + lvi.pszText = pszText ? pszText : szNull; + return SNDMSG(hList, LVM_GETITEMTEXT, iItem, (LPARAM)&lvi); +} + +/** + * name: ProfileList_GetItemData + * desc: return the infostructure associated with the desired item + * param: hList - handle to listview control + * iItem - item index + * return: LPLCITEM structure + **/ +static LPLCITEM ProfileList_GetItemData(HWND hList, INT iItem) +{ + LVITEM lvi; + + if (iItem < 0) return NULL; + lvi.mask = LVIF_PARAM; + lvi.iSubItem = 0; + lvi.iItem = iItem; + return (SendMessage(hList, LVM_GETITEM, NULL, (LPARAM)&lvi)) ? (LPLCITEM)lvi.lParam : NULL; +} + +/** + * name: ProfileList_DeleteItem + * desc: delete an item from the listview + * param: hList - handle to listview control + * iItem - item index + * + * return: nothing + **/ +static VOID ProfileList_DeleteItem(HWND hList, INT iItem) +{ + LPLCITEM pItem = ProfileList_GetItemData(hList, iItem); + + if (PtrIsValid(pItem)) { + if (pItem->pszText[0]) + mir_free(pItem->pszText[0]); + if (pItem->pszText[1]) + mir_free(pItem->pszText[1]); + mir_free(pItem); + } + ListView_DeleteItem(hList, iItem); +} + +/** + * name: ProfileList_Clear + * desc: delete all list items and their data + * + **/ +static VOID ProfileList_Clear(HWND hList) +{ + LVITEM lvi; + + lvi.iItem = 0; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + while (ListView_GetItem(hList, &lvi)) { + if (PtrIsValid(lvi.lParam)) { + if (((LPLCITEM)lvi.lParam)->pszText[0]) + mir_free(((LPLCITEM)lvi.lParam)->pszText[0]); + if (((LPLCITEM)lvi.lParam)->pszText[1]) + mir_free(((LPLCITEM)lvi.lParam)->pszText[1]); + mir_free((LPVOID)lvi.lParam); + } + lvi.iItem++; + } + ListView_DeleteAllItems(hList); +} + +/** + * name: ProfileList_EndLabelEdit + * desc: destroys the edit control and saves the text to the list control if desired + * param: hList - handle to listview control + * bSave - tells, whether to save changes (TRUE) or not (FALSE) + * return: returns 0 on success or nonzero + **/ +static INT ProfileList_EndLabelEdit(LPLISTCTRL pList, BOOLEAN bSave) +{ + HWND hEdit; + + // check if labeledit is enabled + if (!PtrIsValid(pList) || !pList->hList || !pList->labelEdit.hEdit) + return 1; + // set hEdit NULL to indicate the endlabeledit call and prevent other calls + hEdit = pList->labelEdit.hEdit; + pList->labelEdit.hEdit = NULL; + + if (bSave != FALSE && pList->labelEdit.pItem) { + WORD ccText; + LPTSTR szEdit = NULL; + BOOLEAN bChanged = FALSE; + + // an list element was selected + if (pList->labelEdit.iSubItem && pList->labelEdit.dropDown.iItem != pList->labelEdit.pItem->iListItem && pList->labelEdit.dropDown.iItem >= 0 && pList->labelEdit.dropDown.iItem < pList->labelEdit.pItem->idstrListCount) { + pList->labelEdit.pItem->iListItem = pList->labelEdit.dropDown.iItem; + if (pList->labelEdit.pItem->pszText[0]) { + mir_free(pList->labelEdit.pItem->pszText[0]); + pList->labelEdit.pItem->pszText[0] = NULL; + } + bChanged = TRUE; + } + // value was edited + else { + if ((ccText = GetWindowTextLength(hEdit)) > 0 && (szEdit = (LPTSTR)mir_alloc((ccText + 2) * sizeof(TCHAR)))) { + GetWindowText(hEdit, szEdit, ccText + 1); + szEdit[ccText + 1] = 0; + + if (!pList->labelEdit.pItem->pszText[pList->labelEdit.iSubItem]) { + pList->labelEdit.pItem->pszText[pList->labelEdit.iSubItem] = szEdit; + bChanged = TRUE; + } + else + if (_tcscmp(pList->labelEdit.pItem->pszText[pList->labelEdit.iSubItem], szEdit)) { + mir_free(pList->labelEdit.pItem->pszText[pList->labelEdit.iSubItem]); + pList->labelEdit.pItem->pszText[pList->labelEdit.iSubItem] = szEdit; + bChanged = TRUE; + } + else + mir_free(szEdit); + } + } + if (bChanged) { + pList->labelEdit.pItem->wFlags |= CTRLF_CHANGED; + pList->wFlags |= CTRLF_CHANGED; + SendMessage(GetParent(GetParent(pList->hList)), PSM_CHANGED, 0, 0); + } + } + if (pList->labelEdit.hBtn) DestroyWindow(pList->labelEdit.hBtn); + if (pList->labelEdit.dropDown.hDrop) DestroyWindow(pList->labelEdit.dropDown.hDrop); + DestroyWindow(hEdit); + ListView_RedrawItems(pList->hList, pList->labelEdit.iItem, pList->labelEdit.iItem); + ZeroMemory(&pList->labelEdit, sizeof(pList->labelEdit)); + SetFocus(pList->hList); + return 0; +} + +static INT ProfileList_EndLabelEdit(HWND hList, BOOLEAN bSave) +{ + return ProfileList_EndLabelEdit((LPLISTCTRL)GetUserData(hList), bSave); +} + +/** + * 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; +} + +/** + * name: ProfileList_BeginLabelEdit + * desc: create an edit control to edit the label of the selected item + * param: hList - handle to listview control + * iItem - item index + * iSubItem - subitem (column) index + * return: handle to the edit control + **/ +static HWND ProfileList_BeginLabelEdit(HWND hList, INT iItem, INT iSubItem) +{ + return ProfileList_BeginLabelEdit((LPLISTCTRL)GetUserData(hList), iItem, iSubItem); +} + +/** + * name: ProfileList_GetInsertIndex + * desc: finds index to add the new item to and adds an devider if necessary + * param: hList - handle to listcontrol to search for the index in + * pszList - database settings string, that identifies this category + * + * return: zero based index for the new item or -1 on failure + **/ +static INT ProfileList_GetInsertIndex(HWND hList, LPTSTR pszGroup) +{ + LVFINDINFO lfi; + INT iDevider, + iItem; + + // search for the devider to add the new item under + lfi.flags = LVFI_STRING; + lfi.psz = pszGroup; + iDevider = SendMessage(hList, LVM_FINDITEM, (WPARAM)-1, (LPARAM)&lfi); + + // devider does not exist yet, add it! + if (iDevider == -1) { + LVITEM lvi; + + lvi.mask = LVIF_PARAM|LVIF_TEXT; + lvi.iSubItem = 0; + lvi.iItem = 0xFFFF; + lvi.lParam = NULL; + lvi.pszText = (LPTSTR)lfi.psz; + if ((iItem = ListView_InsertItem(hList, &lvi)) == -1) { + return -1; + } + iItem++; + } + else { + // search next devider to add new item just before + lfi.flags = LVFI_PARAM; + lfi.lParam = NULL; + if ((iItem = ListView_FindItem(hList, iDevider, &lfi)) == -1) + iItem = 0xFFFF; + } + return iItem; +} + +/** + * 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; +} + +/** + * name: ProfileList_AddItemlistFromDB + * desc: reads an zero based indexed szList from the database of hContacts pszModule and fills a hList + * param: hList - HANDLE to the list to fill with two columns + * iItem - index of new listviewitem + * iImage - image to draw from a imagelist associated with the listview + * hContact - handle to the contact, whose information are read + * pszModule - the module the information are stored in + * szCatFormat - name of a database setting that holds the categorytext + * szValFormat - name of a database setting that holds the valuetext + * wFlags - flags to set for a new allocated item + * + * return number of added rows or -1 if listview's changed flag is set + **/ +static INT ProfileList_AddItemlistFromDB( + LPLISTCTRL pList, + INT &iItem, + LPIDSTRLIST idList, + UINT nList, + HANDLE hContact, + LPCSTR pszModule, + LPCSTR szCatFormat, + LPCSTR szValFormat, + WORD wFlags) +{ + DBVARIANT dbvVal, dbvCat; + LPLCITEM pItem; + LVITEM lvi; + UINT i, j = 0; + CHAR pszSetting[MAXSETTING]; + + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + for (i = 0, lvi.iItem = iItem; ; i++) { + // read the setting from db + mir_snprintf(pszSetting, MAXSETTING, szValFormat, i); + if (DB::Setting::GetTString(hContact, pszModule, pszSetting, &dbvVal)) break; + if (dbvVal.type != DBVT_TCHAR) continue; + mir_snprintf(pszSetting, MAXSETTING, szCatFormat, i); + DB::Setting::GetAString(hContact, pszModule, pszSetting, &dbvCat); + // create the itemobject + if (!(pItem = (LPLCITEM)mir_alloc(sizeof(LCITEM)))) { + DB::Variant::Free(&dbvCat); + DB::Variant::Free(&dbvVal); + break; + } + // fill item struct + pItem->nType = CTRL_LIST_ITEM; + pItem->idstrList = idList; + pItem->idstrListCount = nList; + pItem->iListItem = 0; + pItem->pszText[0] = NULL; + pItem->pszText[1] = dbvVal.ptszVal; + pItem->wFlags = wFlags; + lvi.lParam = (LPARAM)pItem; + + // get id-str-list-item for the category string + if (idList != NULL) { + for (j = 0; j < nList; j++) { + switch (dbvCat.type) { + case DBVT_BYTE: + if (dbvCat.bVal != (BYTE)idList[j].nID) + continue; + break; + case DBVT_WORD: + if (dbvCat.wVal != (WORD)idList[j].nID) + continue; + break; + case DBVT_DWORD: + if (dbvCat.dVal != (DWORD)idList[j].nID) + continue; + break; + case DBVT_ASCIIZ: + if (strcmp(dbvCat.pszVal, idList[j].pszText)) + continue; + break; + } + pItem->iListItem = j; + break; + } + } + // item not found in the predefined category list? + if ((idList == NULL || j == nList) && dbvCat.type == DBVT_ASCIIZ) { + pItem->pszText[0] = mir_a2t(dbvCat.pszVal); + DB::Variant::Free(&dbvCat); + } + if ((lvi.iItem = ListView_InsertItem(pList->hList, &lvi)) < 0) { + mir_free(pItem); + DB::Variant::Free(&dbvCat); + DB::Variant::Free(&dbvVal); + break; + } + lvi.iItem++; + dbvCat.type = dbvVal.type = DBVT_DELETED; + } + iItem = lvi.iItem; + return i; +} + +/** + * name: ProfileList_DropdownProc + * desc: procedure to catch messages for a listbox control for my own combobox + * param: hwnd - handle to the listview control's window + * msg - message sent to the control + * wParam - message specific parameter + * lParam - message specific parameter + * return: message specific + **/ +static INT_PTR CALLBACK ProfileList_DropdownProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LPLISTCTRL pList; + + switch (msg) { + case WM_KEYDOWN: + switch (wParam) { + case VK_ESCAPE: + SetFocus(GetParent(hwnd)); + return 0; + + case VK_RETURN: + case VK_F4: + { + LPIDSTRLIST pItem; + + if (!PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd))) return CB_ERR; + pList->labelEdit.dropDown.iItem = ListBox_GetCurSel(hwnd); + if (pList->labelEdit.dropDown.iItem >= 0 && PtrIsValid(pItem = (LPIDSTRLIST)ListBox_GetItemData(hwnd, pList->labelEdit.dropDown.iItem))) + SetWindowText(pList->labelEdit.hEdit, pItem->ptszTranslated); + else + pList->labelEdit.dropDown.iItem = -1; + SetFocus(pList->labelEdit.hEdit); + return 0; + } + } + break; + case WM_LBUTTONUP: + { + POINT pt; + LPIDSTRLIST pItem; + + if (!PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd))) return CB_ERR; + CallWindowProc(OldDropdownProc, hwnd, msg, wParam, lParam); + + pt.x = (short)LOWORD(lParam); + pt.y = (short)HIWORD(lParam); + ClientToScreen(hwnd, &pt); + + if (SendMessage(hwnd, WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y)) == HTVSCROLL) + return CB_ERR; + + pList->labelEdit.dropDown.iItem = SendMessage(hwnd, LB_GETCURSEL, 0, 0); + + if (pList->labelEdit.dropDown.iItem >= 0 && PtrIsValid(pItem = (LPIDSTRLIST)ListBox_GetItemData(hwnd, pList->labelEdit.dropDown.iItem))) { + SetWindowText(pList->labelEdit.hEdit, pItem->ptszTranslated); + } + else + pList->labelEdit.dropDown.iItem = -1; + + ProfileList_EndLabelEdit(pList->hList, TRUE); + return 0; + } + case WM_KILLFOCUS: + if (PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd))) { + if (GetFocus() == pList->labelEdit.hEdit) { + ShowWindow(hwnd, SW_HIDE); + return 0; + } + ProfileList_EndLabelEdit(pList, FALSE); + } + return 0; + } + return CallWindowProc(OldDropdownProc, hwnd, msg, wParam, lParam); +} + +/** + * name: ProfileList_LabelEditProc + * desc: procedure to catch messages for an edit control for my own combobox + * param: hwnd - handle to the listview control's window + * msg - message sent to the control + * wParam - message specific parameter + * lParam - message specific parameter + * return: message specific + **/ +static INT_PTR CALLBACK ProfileList_LabelEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LPLISTCTRL pList; + + switch (msg) { + case WM_KEYDOWN: + switch (wParam) { + case VK_ESCAPE: + if (PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd))) + ProfileList_EndLabelEdit(pList, FALSE); + return 0; + case VK_F3: + if (PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd)) && pList->labelEdit.hBtn) + SendMessage(pList->hList, WM_COMMAND, MAKEWPARAM(BTN_EDIT, BN_CLICKED), (LPARAM)pList->labelEdit.hBtn); + return 0; + case VK_RETURN: + { + BOOLEAN bEditNext; + INT iItem; + + if (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_WANTRETURN && !(GetKeyState(VK_CONTROL) & 0x8000)) + break; + if (PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd))) { + bEditNext = !pList->labelEdit.iSubItem && !ProfileList_GetItemText(pList->hList, pList->labelEdit.iItem, 1, NULL, NULL); + iItem = pList->labelEdit.iItem; + ProfileList_EndLabelEdit(pList->hList, TRUE); + if (bEditNext) ProfileList_BeginLabelEdit(pList->hList, pList->labelEdit.iItem, 1); + } + return 0; + } + case VK_TAB: + if (PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd))) { + LVITEM lvi; + + lvi.mask = LVIF_STATE; + lvi.stateMask = LVIS_FOCUSED|LVIS_SELECTED; + lvi.iItem = pList->labelEdit.iItem; + + if (wParam == VK_TAB && !pList->labelEdit.iSubItem) { + lvi.iSubItem = 1; + lvi.state = LVIS_FOCUSED|LVIS_SELECTED; + ProfileList_EndLabelEdit(pList->hList, TRUE); + } + else { + UINT iSubItem = (wParam == VK_TAB) ? 0 : pList->labelEdit.iSubItem; + + lvi.iSubItem = 0; + lvi.state = 0; + + ProfileList_EndLabelEdit(pList, TRUE); + + // unselect current list item + if (!ListView_SetItem(pList->hList, &lvi)) + return 0; + + // search for next valid list item (skip deviders) + lvi.iSubItem = iSubItem; + lvi.mask = LVIF_PARAM; + do { + if (wParam == VK_UP) + lvi.iItem--; + else + lvi.iItem++; + + if (lvi.iItem == -1 || !ListView_GetItem(pList->hList, &lvi)) { + return 0; + } + } while (!lvi.lParam); + + // select new list item + lvi.mask = LVIF_STATE; + lvi.state = LVIS_FOCUSED|LVIS_SELECTED; + if (!ListView_SetItem(pList->hList, &lvi)) { + return 0; + } + } + ProfileList_BeginLabelEdit(pList->hList, lvi.iItem, lvi.iSubItem); + return 0; + } + return 1; + } + break; + case WM_GETDLGCODE: + return DLGC_WANTALLKEYS | CallWindowProc(OldEditProc, hwnd, msg, wParam, lParam); + case WM_KILLFOCUS: + { + HWND hwndFocus = GetFocus(); + + if (PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd)) && + hwndFocus != pList->labelEdit.dropDown.hDrop && + hwndFocus != pList->labelEdit.hEdit && + hwndFocus != pList->labelEdit.hBtn) + ProfileList_EndLabelEdit(pList, hwndFocus == pList->hList); + return 0; + } + } + return CallWindowProc(OldEditProc, hwnd, msg, wParam, lParam); +} + +/** + * name: ListSubclassProc + * desc: procedure to catch messages for a listview control, to handle tooltips + * param: hwnd - handle to the listview control's window + * msg - message sent to the control + * wParam - message specific parameter + * lParam - message specific parameter + * return: message specific + **/ +static INT_PTR CALLBACK ProfileList_SubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LPLISTCTRL pList; + + switch (msg) { + case WM_KEYDOWN: + { + INT nCurSel, newSel; + LVITEM lvi; + + switch (wParam) { + case VK_F2: + nCurSel = ListView_GetSelectionMark(hwnd); + if (nCurSel == -1) break; + ProfileList_BeginLabelEdit(hwnd, nCurSel, 0); + return 0; + case VK_F3: + nCurSel = ListView_GetSelectionMark(hwnd); + if (nCurSel == -1) break; + ProfileList_BeginLabelEdit(hwnd, nCurSel, 1); + return 0; + case VK_UP: + case VK_DOWN: + lvi.iItem = nCurSel = ListView_GetSelectionMark(hwnd); + lvi.iSubItem = 0; + + // find next valid item to select + lvi.mask = LVIF_PARAM; + do { + if (wParam == VK_UP) lvi.iItem--; + else lvi.iItem++; + if (lvi.iItem == -1 || !ListView_GetItem(hwnd, &lvi)) { + return 0; + } + } while (!lvi.lParam); + + ListView_EnsureVisible(hwnd, lvi.iItem, FALSE); + newSel = lvi.iItem; + lvi.iItem = nCurSel; + lvi.mask = LVIF_STATE; + lvi.stateMask = LVIS_FOCUSED|LVIS_SELECTED; + lvi.state = 0; + ListView_SetItem(hwnd, &lvi); + lvi.iItem = newSel; + lvi.state = LVIS_FOCUSED|LVIS_SELECTED; + ListView_SetItem(hwnd, &lvi); + ListView_SetSelectionMark(hwnd, lvi.iItem); + return 0; + } + break; + } + case WM_MOUSEMOVE: + if (PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd))) { + HDC hDC; + RECT rchWnd, rcItem; + SIZE textSize; + LVHITTESTINFO hi; + TOOLINFO ti; + BOOLEAN bReposition; + LPLCITEM pItem; + + hi.pt.x = GET_X_LPARAM(lParam); + hi.pt.y = GET_Y_LPARAM(lParam); + ListView_SubItemHitTest(hwnd, &hi); + + // show tip only if pointer is over an item + if (pList->iHotItem != hi.iItem || pList->iHotSubItem != hi.iSubItem) { + bReposition = pList->iHotItem != -1 || pList->iHotSubItem != -1; + pList->iHotItem = hi.iItem; + pList->iHotSubItem = hi.iSubItem; + + if ((hi.flags & LVHT_ONITEMLABEL) && PtrIsValid(pItem = ProfileList_GetItemData(hwnd, hi.iItem))) { + GetWindowRect(hwnd, &rchWnd); + ListView_GetSubItemRect(hwnd, hi.iItem, hi.iSubItem, LVIR_BOUNDS, &rcItem); + // calculate size of text on the screen + if ((hDC = GetDC(GetParent(hwnd)))) { + SelectObject(hDC, (HFONT)SendMessage(GetParent(hwnd), WM_GETFONT, NULL, NULL)); + GetTextExtentPoint32(hDC, pItem->pszText[hi.iSubItem], lstrlen(pItem->pszText[hi.iSubItem]), &textSize); + ReleaseDC(GetParent(hwnd), hDC); + } + // show tip only for text that is larger than te listview can display + if (textSize.cx > rchWnd.right - rchWnd.left || textSize.cx > rcItem.right - rcItem.left) { + ZeroMemory(&ti, sizeof(TOOLINFO)); + ti.cbSize = sizeof(TOOLINFO); + ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS|TTF_TRANSPARENT; + ti.hinst = ghInst; + ti.hwnd = hwnd; + ti.uId = (UINT_PTR)hwnd; + ti.lpszText = pItem->pszText[hi.iSubItem]; + ti.rect = rcItem; + SendMessage(pList->hTip, TTM_SETMAXTIPWIDTH, 0, 300); + SendMessage(pList->hTip, TTM_SETTOOLINFO, NULL, (LPARAM)&ti); + if (pList->iHotSubItem > 0) { + SendMessage(pList->hTip, TTM_SETTITLE, 1, (LPARAM) + ((pItem->idstrList && pItem->iListItem > 0 && pItem->iListItem < pItem->idstrListCount) + ? pItem->idstrList[pItem->iListItem].ptszTranslated + : (pItem->pszText[0] && *pItem->pszText[0]) + ? pItem->pszText[0] + : TranslateT("")) + ); + InvalidateRect(pList->hTip, NULL, TRUE); + } + else + SendMessage(pList->hTip, TTM_SETTITLE, 0, (LPARAM)""); + SendMessage(pList->hTip, TTM_ACTIVATE, TRUE, (LPARAM)&ti); + pList->ptTip.x = rchWnd.left + GET_X_LPARAM(lParam) - 16; + pList->ptTip.y = rchWnd.top + rcItem.top; + // no TTN_SHOW is called if bReposition is TRUE, so repose here! + if (bReposition) { + RECT rcTip; + GetClientRect(pList->hTip, &rcTip); + SetWindowPos(pList->hTip, hwnd, pList->ptTip.x, pList->ptTip.y - rcTip.bottom, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + } + pList->wFlags |= LIF_TIPVISIBLE; + return 0; + } + } + if (pList->wFlags & LIF_TIPVISIBLE) { + SendMessage(pList->hTip, TTM_ACTIVATE, FALSE, (LPARAM)&ti); + pList->wFlags &= ~LIF_TIPVISIBLE; + } + } + } + return 0; + + // begin label edit + case WM_LBUTTONDBLCLK: + { + LVHITTESTINFO hi; + + hi.pt.x = GET_X_LPARAM(lParam); + hi.pt.y = GET_Y_LPARAM(lParam); + if (ListView_SubItemHitTest(hwnd, &hi)) { + ProfileList_BeginLabelEdit(hwnd, hi.iItem, hi.iSubItem); + } + return TRUE; + } + + case WM_NOTIFY: + if (!PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd))) + break; + + // ensure position of tooltip is on the topline of the item + if (((LPNMHDR)lParam)->hwndFrom == pList->hTip) { + RECT rcTip; + GetClientRect(pList->hTip, &rcTip); + + switch (((LPNMHDR)lParam)->code) { + case TTN_SHOW: + SetWindowPos(pList->hTip, hwnd, pList->ptTip.x, pList->ptTip.y - rcTip.bottom, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + return TRUE; + } + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) { + + // show dropdown menu for category list + case BTN_EDIT: + { + INT i; + TCHAR szEdit[MAX_PATH]; + + if (!PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd))) break; + GetWindowText(pList->labelEdit.hEdit, szEdit, MAX_PATH); + + // need to create the dropdown list? + if (pList->labelEdit.dropDown.hDrop == NULL) { + const INT listHeight = 120; + RECT rc, rcList; + INT add; + + // dropdown rect + GetClientRect(pList->hList, &rcList); + rc.left = pList->labelEdit.rcCombo.left; + rc.right = pList->labelEdit.rcCombo.right + pList->labelEdit.rcCombo.bottom - pList->labelEdit.rcCombo.top; + + if (rcList.bottom < pList->labelEdit.rcCombo.bottom + listHeight) { + rc.bottom = pList->labelEdit.rcCombo.bottom - 7; // don't ask me why! + rc.top = rc.bottom - listHeight; + } + else { + rc.top = pList->labelEdit.rcCombo.bottom; + rc.bottom = rc.top + listHeight; + } + + pList->labelEdit.dropDown.hDrop = CreateWindowEx(0, + _T("LISTBOX"), NULL, WS_CHILD|WS_BORDER|WS_VSCROLL|LBS_COMBOBOX|LBS_HASSTRINGS, + rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, + hwnd, NULL, ghInst, NULL); + if (!pList->labelEdit.dropDown.hDrop) return FALSE; + SetUserData(pList->labelEdit.dropDown.hDrop, pList); + OldDropdownProc = (WNDPROC)SetWindowLongPtr(pList->labelEdit.dropDown.hDrop, GWLP_WNDPROC, (LONG_PTR)ProfileList_DropdownProc); + SetWindowLongPtr(pList->labelEdit.dropDown.hDrop, GWLP_ID, LIST_DROPDOWN); + SendMessage(pList->labelEdit.dropDown.hDrop, WM_SETFONT, (WPARAM)SendMessage(GetParent(pList->hList), WM_GETFONT, 0, 0), 0); + + // add items + for (i = 0; i < pList->labelEdit.pItem->idstrListCount; i++) { + add = ListBox_AddString(pList->labelEdit.dropDown.hDrop, pList->labelEdit.pItem->idstrList[i].ptszTranslated); + ListBox_SetItemData(pList->labelEdit.dropDown.hDrop, add, pList->labelEdit.pItem->idstrList + i); + if (!_tcscmp(szEdit, pList->labelEdit.pItem->idstrList[i].ptszTranslated)) + ListBox_SetCurSel(pList->labelEdit.dropDown.hDrop, add); + } + } + else { + LPIDSTRLIST lpidList; + + i = 0; + while (PtrIsValid(lpidList = (LPIDSTRLIST)ListBox_GetItemData(pList->labelEdit.dropDown.hDrop, i))) { + if (!_tcscmp(szEdit, lpidList->ptszTranslated)) { + ListBox_SetCurSel(pList->labelEdit.dropDown.hDrop, i); + break; + } + i++; + } + if (i == pList->labelEdit.pItem->idstrListCount) + ListBox_SetCurSel(pList->labelEdit.dropDown.hDrop, -1); + } + if (IsWindowVisible(pList->labelEdit.dropDown.hDrop)) { + SetFocus(pList->labelEdit.hEdit); + } + else { + ShowWindow(pList->labelEdit.dropDown.hDrop, SW_SHOW); + //SetFocus(pList->labelEdit.dropDown.hDrop); + } + break; + } + } + break; + } + case WM_MOUSEWHEEL: + case WM_VSCROLL: + case WM_HSCROLL: + { + if (PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd))) + ProfileList_EndLabelEdit(pList, FALSE); + break; + } + + case WM_KILLFOCUS: + { + HWND hwndFocus = GetFocus(); + + if (PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd)) && + pList->labelEdit.hEdit != hwndFocus && + pList->labelEdit.dropDown.hDrop != hwndFocus && + pList->labelEdit.hBtn != hwndFocus) + ProfileList_EndLabelEdit(pList, FALSE); + break; + } + + case WM_DESTROY: + if (PtrIsValid(pList = (LPLISTCTRL)GetUserData(hwnd))) { + HFONT hFont; + + ProfileList_EndLabelEdit(pList, FALSE); + ProfileList_Clear(hwnd); + if (PtrIsValid(hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0)) && hFont != pList->hFont) + DeleteObject(hFont); + DestroyWindow(pList->hTip); + mir_free(pList); + } + break; + } + return CallWindowProc(OldListViewProc, hwnd, msg, wParam, lParam); +} + +/** + * 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(""), + -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; +} -- cgit v1.2.3