summaryrefslogtreecommitdiff
path: root/plugins/UserInfoEx/psp_profile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/UserInfoEx/psp_profile.cpp')
-rw-r--r--plugins/UserInfoEx/psp_profile.cpp1464
1 files changed, 1464 insertions, 0 deletions
diff --git a/plugins/UserInfoEx/psp_profile.cpp b/plugins/UserInfoEx/psp_profile.cpp
new file mode 100644
index 0000000000..1395f43d18
--- /dev/null
+++ b/plugins/UserInfoEx/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("<empty>"))
+ );
+ 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("<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;
+}