/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-12 Miranda IM, 2012-13 Miranda NG project, all portions of this codebase are copyrighted to the people listed in contributors.txt. 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. */ #include "..\..\core\commonheaders.h" #include "clc.h" extern HANDLE hContactIconChangedEvent; extern HANDLE hGroupChangeEvent; int sortByStatus; int sortByProto; static const struct { int status, order; } statusModeOrder[] = { {ID_STATUS_OFFLINE, 500}, {ID_STATUS_ONLINE, 10}, {ID_STATUS_AWAY, 200}, {ID_STATUS_DND, 110}, {ID_STATUS_NA, 450}, {ID_STATUS_OCCUPIED, 100}, {ID_STATUS_FREECHAT, 0}, {ID_STATUS_INVISIBLE, 20}, {ID_STATUS_ONTHEPHONE, 150}, {ID_STATUS_OUTTOLUNCH, 425}}; static int GetContactStatus(HANDLE hContact) { char* szProto = GetContactProto(hContact); if (szProto == NULL) return ID_STATUS_OFFLINE; return db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE); } void fnChangeContactIcon(HANDLE hContact, int iIcon, int add) { CallService(add ? MS_CLUI_CONTACTADDED : MS_CLUI_CONTACTSETICON, (WPARAM) hContact, iIcon); NotifyEventHooks(hContactIconChangedEvent, (WPARAM) hContact, iIcon); } int GetStatusModeOrdering(int statusMode) { int i; for (i=0; i < SIZEOF(statusModeOrder); i++) if (statusModeOrder[i].status == statusMode) return statusModeOrder[i].order; return 1000; } void fnLoadContactTree(void) { HANDLE hContact; int i, status, hideOffline; CallService(MS_CLUI_LISTBEGINREBUILD, 0, 0); for (i = 1;; i++) { if (cli.pfnGetGroupName(i, NULL) == NULL) break; CallService(MS_CLUI_GROUPADDED, i, 0); } hideOffline = db_get_b(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT); hContact = db_find_first(); while (hContact != NULL) { status = GetContactStatus(hContact); if (( !hideOffline || status != ID_STATUS_OFFLINE) && !db_get_b(hContact, "CList", "Hidden", 0)) cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(GetContactProto(hContact), status, hContact), 1); hContact = db_find_next(hContact); } sortByStatus = db_get_b(NULL, "CList", "SortByStatus", SETTING_SORTBYSTATUS_DEFAULT); sortByProto = db_get_b(NULL, "CList", "SortByProto", SETTING_SORTBYPROTO_DEFAULT); CallService(MS_CLUI_SORTLIST, 0, 0); CallService(MS_CLUI_LISTENDREBUILD, 0, 0); } int fnCompareContacts(const ClcContact* c1, const ClcContact* c2) { HANDLE a = c1->hContact, b = c2->hContact; TCHAR namea[128], *nameb; int statusa, statusb; int rc; statusa = db_get_w((HANDLE) a, c1->proto, "Status", ID_STATUS_OFFLINE); statusb = db_get_w((HANDLE) b, c2->proto, "Status", ID_STATUS_OFFLINE); if (sortByProto) { /* deal with statuses, online contacts have to go above offline */ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) { return 2 * (statusa == ID_STATUS_OFFLINE) - 1; } /* both are online, now check protocols */ rc = lstrcmpA(c1->proto, c2->proto); if (rc != 0 && (c1->proto != NULL && c2->proto != NULL)) return rc; /* protocols are the same, order by display name */ } if (sortByStatus) { int ordera, orderb; ordera = GetStatusModeOrdering(statusa); orderb = GetStatusModeOrdering(statusb); if (ordera != orderb) return ordera - orderb; } else { //one is offline: offline goes below online if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) { return 2 * (statusa == ID_STATUS_OFFLINE) - 1; } } nameb = cli.pfnGetContactDisplayName(a, 0); _tcsncpy(namea, nameb, SIZEOF(namea)); namea[ SIZEOF(namea)-1 ] = 0; nameb = cli.pfnGetContactDisplayName(b, 0); //otherwise just compare names return _tcsicmp(namea, nameb); } static UINT_PTR resortTimerId = 0; static VOID CALLBACK SortContactsTimer(HWND, UINT, UINT_PTR, DWORD) { KillTimer(NULL, resortTimerId); resortTimerId = 0; CallService(MS_CLUI_SORTLIST, 0, 0); } void fnSortContacts(void) { //avoid doing lots of resorts in quick succession sortByStatus = db_get_b(NULL, "CList", "SortByStatus", SETTING_SORTBYSTATUS_DEFAULT); sortByProto = db_get_b(NULL, "CList", "SortByProto", SETTING_SORTBYPROTO_DEFAULT); if (resortTimerId) KillTimer(NULL, resortTimerId); // setting this to a higher delay causes shutdown waits. resortTimerId = SetTimer(NULL, 0, 500, SortContactsTimer); } INT_PTR ContactChangeGroup(WPARAM wParam, LPARAM lParam) { CLISTGROUPCHANGE grpChg = { sizeof(CLISTGROUPCHANGE), NULL, NULL }; CallService(MS_CLUI_CONTACTDELETED, wParam, 0); if ((HANDLE) lParam == NULL) db_unset((HANDLE)wParam, "CList", "Group"); else { grpChg.pszNewName = cli.pfnGetGroupName(lParam, NULL); db_set_ts((HANDLE)wParam, "CList", "Group", grpChg.pszNewName); } CallService(MS_CLUI_CONTACTADDED, wParam, cli.pfnIconFromStatusMode(GetContactProto((HANDLE)wParam), GetContactStatus((HANDLE)wParam), (HANDLE)wParam)); NotifyEventHooks(hGroupChangeEvent, wParam, (LPARAM)&grpChg); return 0; } int fnSetHideOffline(WPARAM wParam, LPARAM) { switch((int)wParam) { case 0: db_set_b(NULL, "CList", "HideOffline", 0); break; case 1: db_set_b(NULL, "CList", "HideOffline", 1); break; case -1: db_set_b(NULL, "CList", "HideOffline", !db_get_b(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT)); break; } cli.pfnLoadContactTree(); return 0; }