From 18f7e9261c885e953f220ba6836e8bca43a6fc88 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Fri, 15 Apr 2016 13:40:58 +0000 Subject: contact list groups: - finally database is not used anymore (only as a settings' storage); - MGROUP type introduced to replace HANDLE for group ids; - MS_CLIST_GROUP* services became Clist_Group* functions; - CLIST_INTERFACE members pfnGetGroupName & pfnRenameGroup also transformed into static Clist_Group* functions git-svn-id: http://svn.miranda-ng.org/main/trunk@16659 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/mir_app/src/addcontact.cpp | 20 +- src/mir_app/src/chat_clist.cpp | 6 +- src/mir_app/src/clc.cpp | 70 +---- src/mir_app/src/clc.h | 4 +- src/mir_app/src/clcitems.cpp | 6 +- src/mir_app/src/clcmsgs.cpp | 2 +- src/mir_app/src/clcutils.cpp | 8 +- src/mir_app/src/clistcore.cpp | 3 - src/mir_app/src/clistgroups.cpp | 530 ++++++++++++++++++++++++++++++++++ src/mir_app/src/clui.cpp | 4 +- src/mir_app/src/contact.cpp | 4 +- src/mir_app/src/groups.cpp | 608 ---------------------------------------- src/mir_app/src/menu_groups.cpp | 2 +- src/mir_app/src/mir_app.def | 9 + src/mir_app/src/mir_app64.def | 9 + 15 files changed, 584 insertions(+), 701 deletions(-) create mode 100644 src/mir_app/src/clistgroups.cpp delete mode 100644 src/mir_app/src/groups.cpp (limited to 'src/mir_app') diff --git a/src/mir_app/src/addcontact.cpp b/src/mir_app/src/addcontact.cpp index eeaf7620ef..24aff743ff 100644 --- a/src/mir_app/src/addcontact.cpp +++ b/src/mir_app/src/addcontact.cpp @@ -24,15 +24,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "stdafx.h" -static TCHAR* sttDecodeString(DWORD dwFlags, MAllStrings &src) -{ - if (dwFlags & PSR_UNICODE) - return mir_u2t(src.w); - - if (dwFlags & PSR_UTF8) - return mir_utf8decodeT(src.a); - - return mir_a2t(src.a); +static TCHAR* sttDecodeString(DWORD dwFlags, MAllStrings &src) +{ + if (dwFlags & PSR_UNICODE) + return mir_u2t(src.w); + + if (dwFlags & PSR_UTF8) + return mir_utf8decodeT(src.a); + + return mir_a2t(src.a); } class CAddContactDlg : public CDlgBase @@ -122,7 +122,7 @@ public: int groupSel = 0; ptrT tszGroup(db_get_tsa(hContact, "CList", "Group")); TCHAR *grpName; - for (int groupId = 1; (grpName = cli.pfnGetGroupName(groupId, NULL)) != NULL; groupId++) { + for (int groupId = 1; (grpName = Clist_GroupGetName(groupId, NULL)) != NULL; groupId++) { int id = m_group.AddString(grpName, groupId); if (!mir_tstrcmpi(tszGroup, grpName)) groupSel = id; diff --git a/src/mir_app/src/chat_clist.cpp b/src/mir_app/src/chat_clist.cpp index 62c313c8b2..767368d911 100644 --- a/src/mir_app/src/chat_clist.cpp +++ b/src/mir_app/src/chat_clist.cpp @@ -32,12 +32,12 @@ MCONTACT AddRoom(const char *pszModule, const TCHAR *pszRoom, const TCHAR *pszDi mir_tstrcpy(pszGroup, _T("Chat rooms")); if (pszGroup[0]) { - HANDLE hGroup = Clist_GroupExists(pszGroup); + MGROUP hGroup = Clist_GroupExists(pszGroup); if (hGroup == 0) { - hGroup = Clist_CreateGroup(0, pszGroup); + hGroup = Clist_GroupCreate(0, pszGroup); if (hGroup) { CallService(MS_CLUI_GROUPADDED, (WPARAM)hGroup, 0); - CallService(MS_CLIST_GROUPSETEXPANDED, (WPARAM)hGroup, 1); + Clist_GroupSetExpanded(hGroup, 1); } } } diff --git a/src/mir_app/src/clc.cpp b/src/mir_app/src/clc.cpp index 0a0d5edd0b..8ea5f48ef4 100644 --- a/src/mir_app/src/clc.cpp +++ b/src/mir_app/src/clc.cpp @@ -65,11 +65,6 @@ void fnClcOptionsChanged(void) static int ClcSettingChanged(WPARAM hContact, LPARAM lParam) { DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam; - if (hContact == NULL) { - if (!strcmp(cws->szModule, "CListGroups")) - cli.pfnClcBroadcast(INTM_GROUPSCHANGED, hContact, lParam); - return 0; - } if (!strcmp(cws->szModule, "CList")) { if (!strcmp(cws->szSetting, "MyHandle")) { @@ -387,55 +382,6 @@ LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT uMsg, WPARAM wParam case WM_GETFONT: return (LRESULT)dat->fontInfo[FONTID_CONTACTS].hFont; - case INTM_GROUPSCHANGED: - { - DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *)lParam; - if (dbcws->value.type == DBVT_ASCIIZ || dbcws->value.type == DBVT_UTF8) { - int groupId = atoi(dbcws->szSetting) + 1; - TCHAR szFullName[512]; - int i, eq; - //check name of group and ignore message if just being expanded/collapsed - if (cli.pfnFindItem(hwnd, dat, groupId | HCONTACT_ISGROUP, &contact, &group, NULL)) { - mir_tstrcpy(szFullName, contact->szText); - while (group->parent) { - for (i = 0; i < group->parent->cl.count; i++) - if (group->parent->cl.items[i]->group == group) - break; - if (i == group->parent->cl.count) { - szFullName[0] = '\0'; - break; - } - group = group->parent; - size_t nameLen = mir_tstrlen(group->cl.items[i]->szText); - if (mir_tstrlen(szFullName) + 1 + nameLen > _countof(szFullName)) { - szFullName[0] = '\0'; - break; - } - memmove(szFullName + 1 + nameLen, szFullName, sizeof(TCHAR)*(mir_tstrlen(szFullName) + 1)); - memcpy(szFullName, group->cl.items[i]->szText, sizeof(TCHAR)*nameLen); - szFullName[nameLen] = '\\'; - } - - if (dbcws->value.type == DBVT_ASCIIZ) { - WCHAR* wszGrpName = mir_a2u(dbcws->value.pszVal + 1); - eq = !mir_tstrcmp(szFullName, wszGrpName); - mir_free(wszGrpName); - } - else { - char* szGrpName = NEWSTR_ALLOCA(dbcws->value.pszVal + 1); - WCHAR* wszGrpName; - Utf8Decode(szGrpName, &wszGrpName); - eq = !mir_tstrcmp(szFullName, wszGrpName); - mir_free(wszGrpName); - } - if (eq && (contact->group->hideOffline != 0) == ((dbcws->value.pszVal[0] & GROUPF_HIDEOFFLINE) != 0)) - break; //only expanded has changed: no action reqd - } - } - cli.pfnSaveStateAndRebuildList(hwnd, dat); - } - break; - case INTM_NAMEORDERCHANGED: cli.pfnInitAutoRebuild(hwnd); break; @@ -1130,8 +1076,8 @@ LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT uMsg, WPARAM wParam CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)contacto->hContact, contactn->groupId); else if (contacto->type == CLCIT_GROUP) { //dropee is a group TCHAR szNewName[120]; - mir_sntprintf(szNewName, _T("%s\\%s"), cli.pfnGetGroupName(contactn->groupId, NULL), contacto->szText); - cli.pfnRenameGroup(contacto->groupId, szNewName); + mir_sntprintf(szNewName, _T("%s\\%s"), Clist_GroupGetName(contactn->groupId, NULL), contacto->szText); + Clist_GroupRename(contacto->groupId, szNewName); } } break; @@ -1142,11 +1088,11 @@ LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT uMsg, WPARAM wParam ClcContact *destcontact; ClcGroup *destgroup; if (cli.pfnGetRowByIndex(dat, dat->iInsertionMark, &destcontact, &destgroup) == -1 || destgroup != contact->group->parent) - CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, 0); + Clist_GroupMoveBefore(contact->groupId, 0); else { if (destcontact->type == CLCIT_GROUP) destgroup = destcontact->group; - CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, destgroup->groupId); + Clist_GroupMoveBefore(contact->groupId, destgroup->groupId); } } break; @@ -1170,7 +1116,7 @@ LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT uMsg, WPARAM wParam if (contact->type == CLCIT_GROUP) { //dropee is a group TCHAR szNewName[120]; mir_tstrncpy(szNewName, contact->szText, _countof(szNewName)); - cli.pfnRenameGroup(contact->groupId, szNewName); + Clist_GroupRename(contact->groupId, szNewName); } else if (contact->type == CLCIT_CONTACT) //dropee is a contact CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)contact->hContact, 0); @@ -1270,18 +1216,18 @@ LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT uMsg, WPARAM wParam if (contact->type != CLCIT_GROUP) break; SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS); - CallService(MS_CLIST_GROUPCREATE, contact->groupId, 0); + Clist_GroupCreate(contact->groupId, 0); break; case POPUP_RENAMEGROUP: cli.pfnBeginRenameSelection(hwnd, dat); break; case POPUP_DELETEGROUP: if (contact->type == CLCIT_GROUP) - CallService(MS_CLIST_GROUPDELETE, contact->groupId, 0); + Clist_GroupDelete(contact->groupId); break; case POPUP_GROUPHIDEOFFLINE: if (contact->type == CLCIT_GROUP) - CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId, MAKELPARAM(contact->group->hideOffline ? 0 : GROUPF_HIDEOFFLINE, GROUPF_HIDEOFFLINE)); + Clist_GroupSetFlags(contact->groupId, MAKELPARAM(contact->group->hideOffline ? 0 : GROUPF_HIDEOFFLINE, GROUPF_HIDEOFFLINE)); break; } diff --git a/src/mir_app/src/clc.h b/src/mir_app/src/clc.h index 19f64a5762..bebef650b7 100644 --- a/src/mir_app/src/clc.h +++ b/src/mir_app/src/clc.h @@ -191,8 +191,8 @@ int fnSetHideOffline(WPARAM wParam, LPARAM lParam); int fnDocking_ProcessWindowMessage(WPARAM wParam, LPARAM lParam); /* group.c */ -TCHAR* fnGetGroupName(int idx, DWORD* pdwFlags); -int fnRenameGroup(int groupID, TCHAR* newName); +TCHAR* fnGetGroupName(MGROUP idx, DWORD *pdwFlags); +int fnRenameGroup(MGROUP groupID, const TCHAR *newName); /* keyboard.c */ int fnHotKeysRegister(HWND hwnd); diff --git a/src/mir_app/src/clcitems.cpp b/src/mir_app/src/clcitems.cpp index c1de101a5f..7933b9ef52 100644 --- a/src/mir_app/src/clcitems.cpp +++ b/src/mir_app/src/clcitems.cpp @@ -243,7 +243,7 @@ void fnAddContactToTree(HWND hwnd, struct ClcData *dat, MCONTACT hContact, int u } if (checkHideOffline && cli.pfnIsHiddenMode(dat, status)) { for (i = 1;; i++) { - szGroupName = cli.pfnGetGroupName(i, &groupFlags); + szGroupName = Clist_GroupGetName(i, &groupFlags); if (szGroupName == NULL) { mir_free(dbv.ptszVal); return; @@ -257,7 +257,7 @@ void fnAddContactToTree(HWND hwnd, struct ClcData *dat, MCONTACT hContact, int u } } for (i = 1;; i++) { - szGroupName = cli.pfnGetGroupName(i, &groupFlags); + szGroupName = Clist_GroupGetName(i, &groupFlags); if (szGroupName == NULL) { mir_free(dbv.ptszVal); return; @@ -359,7 +359,7 @@ void fnRebuildEntireList(HWND hwnd, struct ClcData *dat) for (int i = 1;; i++) { DWORD groupFlags; - TCHAR *szGroupName = cli.pfnGetGroupName(i, &groupFlags); + TCHAR *szGroupName = Clist_GroupGetName(i, &groupFlags); if (szGroupName == NULL) break; cli.pfnAddGroup(hwnd, dat, szGroupName, groupFlags, i, 0); diff --git a/src/mir_app/src/clcmsgs.cpp b/src/mir_app/src/clcmsgs.cpp index d448ce91e8..80d3e47f19 100644 --- a/src/mir_app/src/clcmsgs.cpp +++ b/src/mir_app/src/clcmsgs.cpp @@ -43,7 +43,7 @@ LRESULT fnProcessExternalMessages(HWND hwnd, struct ClcData *dat, UINT msg, WPAR case CLM_ADDGROUP: { DWORD groupFlags; - TCHAR *szName = cli.pfnGetGroupName(wParam, &groupFlags); + TCHAR *szName = Clist_GroupGetName(wParam, &groupFlags); if (szName == NULL) break; cli.pfnAddGroup(hwnd, dat, szName, groupFlags, wParam, 0); diff --git a/src/mir_app/src/clcutils.cpp b/src/mir_app/src/clcutils.cpp index 67148b1ac4..41231fc40d 100644 --- a/src/mir_app/src/clcutils.cpp +++ b/src/mir_app/src/clcutils.cpp @@ -411,11 +411,11 @@ void fnEndRename(HWND, struct ClcData *dat, int save) if (contact->group->parent && contact->group->parent->parent) { TCHAR szFullName[256]; mir_sntprintf(szFullName, _T("%s\\%s"), - cli.pfnGetGroupName(contact->group->parent->groupId, NULL), text); - cli.pfnRenameGroup(contact->groupId, szFullName); + Clist_GroupGetName(contact->group->parent->groupId, NULL), text); + Clist_GroupRename(contact->groupId, szFullName); } else - cli.pfnRenameGroup(contact->groupId, text); + Clist_GroupRename(contact->groupId, text); } else if (contact->type == CLCIT_CONTACT) { cli.pfnInvalidateDisplayNameCacheEntry(contact->hContact); @@ -442,7 +442,7 @@ void fnDeleteFromContactList(HWND hwnd, struct ClcData *dat) return; switch (contact->type) { case CLCIT_GROUP: - CallService(MS_CLIST_GROUPDELETE, (WPARAM)contact->groupId, 0); + Clist_GroupDelete(contact->groupId); break; case CLCIT_CONTACT: CallService("CList/DeleteContactCommand", (WPARAM)contact->hContact, (LPARAM)hwnd); diff --git a/src/mir_app/src/clistcore.cpp b/src/mir_app/src/clistcore.cpp index 50ea19f515..70b8ef420c 100644 --- a/src/mir_app/src/clistcore.cpp +++ b/src/mir_app/src/clistcore.cpp @@ -189,9 +189,6 @@ static INT_PTR srvRetrieveInterface(WPARAM, LPARAM) cli.pfnShowHide = fnShowHide; cli.pfnGetStatusModeDescription = fnGetStatusModeDescription; - cli.pfnGetGroupName = fnGetGroupName; - cli.pfnRenameGroup = fnRenameGroup; - cli.pfnHotKeysRegister = fnHotKeysRegister; cli.pfnHotKeysUnregister = fnHotKeysUnregister; cli.pfnHotKeysProcess = fnHotKeysProcess; diff --git a/src/mir_app/src/clistgroups.cpp b/src/mir_app/src/clistgroups.cpp new file mode 100644 index 0000000000..a1eef33b00 --- /dev/null +++ b/src/mir_app/src/clistgroups.cpp @@ -0,0 +1,530 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (ñ) 2012-16 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM 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 "stdafx.h" +#include "clc.h" + +struct CGroupInternal +{ + CGroupInternal(int _id, const TCHAR *_name) : + groupId(_id), + groupName(mir_tstrdup(_name)) + {} + + int groupId; + TCHAR *groupName; + + void save() + { + char idstr[33]; + itoa(groupId, idstr, 10); + db_set_ts(NULL, "CListGroups", idstr, groupName); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +static int CompareGrpByName(const CGroupInternal *p1, const CGroupInternal *p2) +{ return mir_tstrcmp(p1->groupName+1, p2->groupName+1); +} + +static LIST arByName(20, CompareGrpByName); + +///////////////////////////////////////////////////////////////////////////////////////// + +struct CGroupList : public LIST +{ + CGroupList() : + LIST(20, NumericKeySortT) + {} + + __inline CGroupInternal* find(int key) + { return LIST::find((CGroupInternal*)&key); + } +}; + +static CGroupList arByIds; + +///////////////////////////////////////////////////////////////////////////////////////// + +HANDLE hGroupChangeEvent; + +static mir_cs csGroups; + +///////////////////////////////////////////////////////////////////////////////////////// + +static int GroupNameExists(const TCHAR *ptszGroupName, int skipGroup) +{ + if (ptszGroupName == 0) + return 0; + + TCHAR str[256]; + _tcsncpy_s(str + 1, _countof(str) - 1, ptszGroupName, _TRUNCATE); + + CGroupInternal *tmp = (CGroupInternal*)_alloca(sizeof(CGroupInternal)); + tmp->groupName = (TCHAR*)str; + if (tmp = arByName.find(tmp)) + return (skipGroup == tmp->groupId) ? 0 : tmp->groupId + 1; + return 0; +} + +MIR_APP_DLL(MGROUP) Clist_GroupExists(LPCTSTR ptszGroupName) +{ + return GroupNameExists(ptszGroupName, -1); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static INT_PTR CreateGroupInternal(MGROUP hParent, const TCHAR *ptszName) +{ + TCHAR newBaseName[127], newName[128]; + + const TCHAR *grpName = ptszName ? ptszName : TranslateT("New group"); + if (hParent) { + CGroupInternal *tmp = arByIds.find(hParent-1); + if (tmp == NULL) + return NULL; + + mir_sntprintf(newBaseName, _T("%s\\%s"), tmp->groupName+1, grpName); + } + else _tcsncpy_s(newBaseName, grpName, _TRUNCATE); + + mir_tstrncpy(newName + 1, newBaseName, _countof(newName) - 1); + if (ptszName) { + int id = GroupNameExists(newBaseName, -1); + if (id) + return id; + } + else { + for (int idCopy = 1; GroupNameExists(newName + 1, -1); idCopy++) + mir_sntprintf(newName + 1, _countof(newName) - 1, _T("%s (%d)"), newBaseName, idCopy); + } + + int newId = arByIds.getCount(); + newName[0] = 1 | GROUPF_EXPANDED; // 1 is required so we never get '\0' + CGroupInternal *pNew = new CGroupInternal(newId, newName); + pNew->save(); + arByIds.insert(pNew); + arByName.insert(pNew); + + CallService(MS_CLUI_GROUPADDED, newId + 1, 1); + + CLISTGROUPCHANGE grpChg = { sizeof(grpChg), NULL, newName }; + NotifyEventHooks(hGroupChangeEvent, 0, (LPARAM)&grpChg); + + return newId + 1; +} + +MIR_APP_DLL(MGROUP) Clist_GroupCreate(MGROUP hParent, LPCTSTR ptszGroupName) +{ + // no name specified. just create a new group with a default name + if (ptszGroupName == 0) + return CreateGroupInternal(hParent, NULL); + + if (ptszGroupName == NULL || ptszGroupName[0] == '\0' || ptszGroupName[0] == '\\') + return 0; + + TCHAR *tszName = NEWTSTR_ALLOCA(ptszGroupName); + for (TCHAR *p = tszName; *p; p++) { + if (*p == '\\') { + *p = '\0'; + CreateGroupInternal(hParent, tszName); + *p = '\\'; + } + } + return CreateGroupInternal(hParent, tszName); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(TCHAR*) Clist_GroupGetName(MGROUP hGroup, DWORD *pdwFlags) +{ + CGroupInternal *p = arByIds.find(hGroup-1); + if (p == NULL) + return NULL; + + if (pdwFlags != NULL) + *pdwFlags = p->groupName[0] & ~1; + return p->groupName+1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(int) Clist_GroupDelete(MGROUP hGroup) +{ + // get the name + CGroupInternal *pGroup = arByIds.find(hGroup-1); + if (pGroup == NULL) + return 1; + + if (db_get_b(NULL, "CList", "ConfirmDelete", SETTING_CONFIRMDELETE_DEFAULT)) { + TCHAR szQuestion[256 + 100]; + mir_sntprintf(szQuestion, TranslateT("Are you sure you want to delete group '%s'? This operation cannot be undone."), pGroup->groupName+1); + if (MessageBox(cli.hwndContactList, szQuestion, TranslateT("Delete group"), MB_YESNO | MB_ICONQUESTION) == IDNO) + return 1; + } + + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + // must remove setting from all child contacts too + // children are demoted to the next group up, not deleted. + TCHAR *szNewParent = NEWTSTR_ALLOCA(pGroup->groupName+1); + { + TCHAR *pszLastBackslash = _tcsrchr(szNewParent, '\\'); + if (pszLastBackslash) + pszLastBackslash[0] = '\0'; + else + szNewParent[0] = '\0'; + } + + for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { + ptrT tszGroupName(db_get_tsa(hContact, "CList", "Group")); + if (mir_tstrcmp(tszGroupName, pGroup->groupName+1)) + continue; + + CLISTGROUPCHANGE grpChg = { sizeof(grpChg), NULL, NULL }; + grpChg.pszOldName = pGroup->groupName+1; + if (szNewParent[0]) { + db_set_ts(hContact, "CList", "Group", szNewParent); + grpChg.pszNewName = szNewParent; + } + else { + db_unset(hContact, "CList", "Group"); + grpChg.pszNewName = NULL; + } + + NotifyEventHooks(hGroupChangeEvent, hContact, (LPARAM)&grpChg); + } + + // shuffle list of groups up to fill gap + arByIds.remove(pGroup); + arByName.remove(pGroup); + + for (int i = hGroup-1; i < arByIds.getCount(); i++) { + CGroupInternal *p = arByIds[i]; + p->groupId--; + p->save(); + } + + char idstr[33]; + _itoa(arByIds.getCount(), idstr, 10); + db_unset(NULL, "CListGroups", idstr); + + // rename subgroups + TCHAR szNewName[256]; + size_t len = mir_tstrlen(pGroup->groupName+1); + for (int i = 0; i < arByIds.getCount(); i++) { + CGroupInternal *p = arByIds[i]; + + if (!_tcsncmp(pGroup->groupName+1, p->groupName+1, len) && p->groupName[len+1] == '\\' && _tcschr(p->groupName + len + 2, '\\') == NULL) { + if (szNewParent[0]) + mir_sntprintf(szNewName, _T("%s\\%s"), szNewParent, p->groupName + len + 2); + else + mir_tstrncpy(szNewName, p->groupName + len + 2, _countof(szNewName)); + Clist_GroupRename(i + 1, szNewName); + } + } + + SetCursor(LoadCursor(NULL, IDC_ARROW)); + cli.pfnLoadContactTree(); + + const CLISTGROUPCHANGE grpChg = { sizeof(grpChg), pGroup->groupName+1, NULL }; + NotifyEventHooks(hGroupChangeEvent, 0, (LPARAM)&grpChg); + + mir_free(pGroup->groupName); + delete(pGroup); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(int) Clist_GroupMoveBefore(MGROUP hGroup, MGROUP hGroupBefore) +{ + if (hGroup == 0 || hGroup == hGroupBefore) + return 0; + + CGroupInternal *pGroup = arByIds.find(hGroup - 1); + if (pGroup == NULL) + return 0; + + // shuffle list of groups up to fill gap + int shuffleFrom, shuffleTo, shuffleStep; + if (hGroupBefore == 0) { + shuffleFrom = hGroup - 1; + shuffleTo = -1; + shuffleStep = 1; + } + else { + CGroupInternal *pDest = arByIds.find(hGroupBefore - 1); + if (pDest == NULL) + return 0; + + if (hGroup < hGroupBefore) { + shuffleFrom = hGroup - 1; + shuffleTo = hGroupBefore - 2; + shuffleStep = 1; + } + else { + shuffleFrom = hGroup - 1; + shuffleTo = hGroupBefore - 1; + shuffleStep = -1; + } + } + + arByIds.remove(pGroup); + + for (int i = shuffleFrom; i != shuffleTo; i += shuffleStep) { + CGroupInternal *p = arByIds[i + shuffleStep]; + p->groupId -= shuffleStep; + p->save(); + } + + pGroup->groupId = shuffleTo; // reinsert group back + pGroup->save(); + + arByIds.insert(pGroup); + return shuffleTo + 1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int RenameGroupWithMove(int groupId, const TCHAR *szName, int move) +{ + if (GroupNameExists(szName, groupId)) { + MessageBox(NULL, TranslateT("You already have a group with that name. Please enter a unique name for the group."), TranslateT("Rename group"), MB_ICONERROR | MB_OK); + return 1; + } + + CGroupInternal *pGroup = arByIds.find(groupId); + if (pGroup == NULL) + return 0; + + // do the change + TCHAR *oldName = NEWTSTR_ALLOCA(pGroup->groupName+1); + + TCHAR str[256]; + str[0] = pGroup->groupName[0]; + mir_tstrncpy(str + 1, szName, _countof(str) - 1); + + pGroup->groupName = mir_tstrdup(str); + pGroup->save(); + + // must rename setting in all child contacts too + for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { + ClcCacheEntry *cache = cli.pfnGetCacheEntry(hContact); + if (!mir_tstrcmp(cache->tszGroup, oldName)) { + db_set_ts(hContact, "CList", "Group", szName); + replaceStrT(cache->tszGroup, szName); + } + } + + // rename subgroups + size_t len = mir_tstrlen(oldName); + for (int i = 0; i < arByIds.getCount(); i++) { + if (i == groupId) + continue; + + CGroupInternal *p = arByIds[i]; + if (!_tcsncmp(p->groupName+1, oldName, len) && p->groupName[len+1] == '\\' && _tcschr(p->groupName + len + 2, '\\') == NULL) { + TCHAR szNewName[256]; + mir_sntprintf(szNewName, _T("%s\\%s"), szName, p->groupName + len + 2); + RenameGroupWithMove(i, szNewName, 0); // luckily, child groups will never need reordering + } + } + + // finally must make sure it's after any parent items + if (move) { + _tcsncpy_s(str, szName, _TRUNCATE); + TCHAR *pszLastBackslash = _tcsrchr(str, '\\'); + if (pszLastBackslash != NULL) { + *pszLastBackslash = '\0'; + for (int i = 0; i < arByIds.getCount(); i++) { + CGroupInternal *p = arByIds[i]; + if (!mir_tstrcmp(p->groupName+1, str)) { + if (i >= groupId) + Clist_GroupMoveBefore(groupId + 1, i + 2); + break; + } + } + } + cli.pfnInitAutoRebuild(cli.hwndContactTree); + } + + const CLISTGROUPCHANGE grpChg = { sizeof(grpChg), oldName, (TCHAR*)szName }; + NotifyEventHooks(hGroupChangeEvent, 0, (LPARAM)&grpChg); + return 0; +} + +MIR_APP_DLL(int) Clist_GroupRename(MGROUP hGroup, const TCHAR *ptszNewName) +{ + return 0 != RenameGroupWithMove(hGroup-1, ptszNewName, 1); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(int) Clist_GroupSetExpanded(MGROUP hGroup, int iNewState) +{ + CGroupInternal *pGroup = arByIds.find(hGroup-1); + if (pGroup == NULL) + return 1; + + if (iNewState) + pGroup->groupName[0] |= GROUPF_EXPANDED; + else + pGroup->groupName[0] &= ~GROUPF_EXPANDED; + pGroup->save(); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(int) Clist_GroupSetFlags(MGROUP hGroup, LPARAM iNewFlags) +{ + CGroupInternal *pGroup = arByIds.find(hGroup-1); + if (pGroup == NULL) + return 1; + + int flags = LOWORD(iNewFlags) & HIWORD(iNewFlags); + int oldval = pGroup->groupName[0]; + pGroup->groupName[0] = ((oldval & ~HIWORD(iNewFlags)) | flags) & 0x7f; + pGroup->save(); + + if ((oldval & GROUPF_HIDEOFFLINE) != (pGroup->groupName[0] & GROUPF_HIDEOFFLINE)) + cli.pfnLoadContactTree(); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(HMENU) Clist_GroupBuildMenu() +{ + if (arByIds.getCount() == 0) + return NULL; + + int nextMenuId = 100; + + HMENU hRootMenu = CreateMenu(); + for (int i = 0; i < arByIds.getCount(); i++) { + const TCHAR *pNextField = arByIds[i]->groupName + 1; + HMENU hThisMenu = hRootMenu; + + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + + TCHAR szThisField[128], szThisMenuItem[128]; + do { + const TCHAR *pBackslash = _tcschr(pNextField, '\\'); + if (pBackslash == NULL) { + mir_tstrncpy(szThisField, pNextField, _countof(szThisField)); + pNextField = NULL; + } + else { + mir_tstrncpy(szThisField, pNextField, min(_countof(szThisField), pBackslash - pNextField + 1)); + pNextField = pBackslash + 1; + } + int compareResult = 1; + int menuId, menuItemCount = GetMenuItemCount(hThisMenu); + for (menuId = 0; menuId < menuItemCount; menuId++) { + mii.fMask = MIIM_TYPE | MIIM_SUBMENU | MIIM_DATA; + mii.cch = _countof(szThisMenuItem); + mii.dwTypeData = szThisMenuItem; + GetMenuItemInfo(hThisMenu, menuId, TRUE, &mii); + compareResult = mir_tstrcmp(szThisField, szThisMenuItem); + if (compareResult == 0) { + if (pNextField == NULL) { + mii.fMask = MIIM_DATA; + mii.dwItemData = i + 1; + SetMenuItemInfo(hThisMenu, menuId, TRUE, &mii); + } + else { + if (mii.hSubMenu == NULL) { + mii.fMask = MIIM_SUBMENU; + mii.hSubMenu = CreateMenu(); + SetMenuItemInfo(hThisMenu, menuId, TRUE, &mii); + mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID; + //dwItemData doesn't change + mii.fType = MFT_STRING; + mii.dwTypeData = TranslateT("This group"); + mii.wID = nextMenuId++; + InsertMenuItem(mii.hSubMenu, 0, TRUE, &mii); + mii.fMask = MIIM_TYPE; + mii.fType = MFT_SEPARATOR; + InsertMenuItem(mii.hSubMenu, 1, TRUE, &mii); + } + hThisMenu = mii.hSubMenu; + } + break; + } + if ((int)mii.dwItemData - 1 > i) + break; + } + if (compareResult) { + mii.fMask = MIIM_TYPE | MIIM_ID; + mii.wID = nextMenuId++; + mii.dwTypeData = szThisField; + mii.fType = MFT_STRING; + if (pNextField) { + mii.fMask |= MIIM_SUBMENU; + mii.hSubMenu = CreateMenu(); + } + else { + mii.fMask |= MIIM_DATA; + mii.dwItemData = i + 1; + } + InsertMenuItem(hThisMenu, menuId, TRUE, &mii); + if (pNextField) + hThisMenu = mii.hSubMenu; + } + } while (pNextField); + } + return hRootMenu; +} + +int InitGroupServices(void) +{ + for (int i = 0;; i++) { + char str[32]; + _itoa(i, str, 10); + ptrT tszGroup(db_get_tsa(NULL, "CListGroups", str)); + if (tszGroup == NULL) + break; + + CGroupInternal *p = new CGroupInternal(i, tszGroup); + arByIds.insert(p); + arByName.insert(p); + } + + hGroupChangeEvent = CreateHookableEvent(ME_CLIST_GROUPCHANGE); + return 0; +} + +void UninitGroupServices(void) +{ + for (int i = 0; i < arByIds.getCount(); i++) { + mir_free(arByIds[i]->groupName); + delete arByIds[i]; + } + arByIds.destroy(); + arByName.destroy(); +} diff --git a/src/mir_app/src/clui.cpp b/src/mir_app/src/clui.cpp index 468b57b905..d3f19c7a5c 100644 --- a/src/mir_app/src/clui.cpp +++ b/src/mir_app/src/clui.cpp @@ -700,7 +700,7 @@ CLS_HIDEEMPTYGROUPS : 0), 0, 0, 0, 0, hwnd, NULL, cli.hInst, NULL); case POPUP_NEWGROUP: SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, 0, 0); - CallService(MS_CLIST_GROUPCREATE, 0, 0); + Clist_GroupCreate(0, 0); break; case POPUP_HIDEOFFLINE: @@ -764,7 +764,7 @@ CLS_HIDEEMPTYGROUPS : 0), 0, 0, 0, 0, hwnd, NULL, cli.hInst, NULL); NMCLISTCONTROL *nmc = (NMCLISTCONTROL*)lParam; switch (((LPNMHDR)lParam)->code) { case CLN_EXPANDED: - CallService(MS_CLIST_GROUPSETEXPANDED, (WPARAM)nmc->hItem, nmc->action); + Clist_GroupSetExpanded((MGROUP)nmc->hItem, nmc->action); return FALSE; case CLN_DRAGGING: diff --git a/src/mir_app/src/contact.cpp b/src/mir_app/src/contact.cpp index ad96790d5e..fb57f3a9e9 100644 --- a/src/mir_app/src/contact.cpp +++ b/src/mir_app/src/contact.cpp @@ -46,7 +46,7 @@ void fnLoadContactTree(void) { CallService(MS_CLUI_LISTBEGINREBUILD, 0, 0); for (int i = 1;; i++) { - if (cli.pfnGetGroupName(i, NULL) == NULL) + if (Clist_GroupGetName(i, NULL) == NULL) break; CallService(MS_CLUI_GROUPADDED, i, 0); } @@ -68,7 +68,7 @@ INT_PTR ContactChangeGroup(WPARAM wParam, LPARAM lParam) if ((HANDLE) lParam == NULL) db_unset(wParam, "CList", "Group"); else { - grpChg.pszNewName = cli.pfnGetGroupName(lParam, NULL); + grpChg.pszNewName = Clist_GroupGetName(lParam, NULL); db_set_ts(wParam, "CList", "Group", grpChg.pszNewName); } CallService(MS_CLUI_CONTACTADDED, wParam, diff --git a/src/mir_app/src/groups.cpp b/src/mir_app/src/groups.cpp deleted file mode 100644 index d01bcb8074..0000000000 --- a/src/mir_app/src/groups.cpp +++ /dev/null @@ -1,608 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (ñ) 2012-16 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM 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 "stdafx.h" -#include "clc.h" - -HANDLE hGroupChangeEvent; - -struct CGroupInternal -{ - CGroupInternal(const TCHAR *_name, int _id) : - groupId(_id), - groupName(mir_tstrdup(_name)) - {} - - int groupId; - TCHAR *groupName; -}; - -static int CompareGrpByName(const CGroupInternal *p1, const CGroupInternal *p2) -{ return mir_tstrcmp(p1->groupName, p2->groupName); -} -static LIST arByName(20, CompareGrpByName); - -static LIST arByIds(20, NumericKeySortT); - -static void BuildGroupList() -{ - for (int i = 0;; i++) { - char str[32]; - _itoa(i, str, 10); - ptrT tszGroup(db_get_tsa(NULL, "CListGroups", str)); - if (tszGroup == NULL) - break; - - if (tszGroup[0] & 0x80) { - tszGroup[0] &= 0x7f; - db_set_ts(NULL, "CListGroups", str, tszGroup); - } - - CGroupInternal *p = new CGroupInternal((TCHAR*)tszGroup + 1, i); - arByIds.insert(p); - arByName.insert(p); - } -} - -static void WipeGroupList() -{ - for (int i = 0; i < arByIds.getCount(); i++) { - mir_free(arByIds[i]->groupName); - delete arByIds[i]; - } - arByIds.destroy(); - arByName.destroy(); -} - -static int CountGroups(void) -{ - return arByIds.getCount(); -} - -static int GroupNameExists(const TCHAR *name, int skipGroup) -{ - CGroupInternal *tmp = (CGroupInternal*)_alloca(sizeof(CGroupInternal)); - tmp->groupName = (TCHAR*)name; - if (tmp = arByName.find(tmp)) - return (skipGroup == tmp->groupId) ? 0 : tmp->groupId + 1; - return 0; -} - -static INT_PTR GroupExists(WPARAM, LPARAM lParam) -{ - if (lParam == 0) - return FALSE; - - return GroupNameExists((LPCTSTR)lParam, -1); -} - -static INT_PTR CreateGroupInternal(INT_PTR iParent, const TCHAR *ptszName) -{ - TCHAR newBaseName[127], newName[128]; - char str[33]; - int i; - - const TCHAR *grpName = ptszName ? ptszName : TranslateT("New group"); - if (iParent) { - _itoa(iParent - 1, str, 10); - DBVARIANT dbv; - if (db_get_ts(NULL, "CListGroups", str, &dbv)) - return 0; - - mir_sntprintf(newBaseName, _T("%s\\%s"), dbv.ptszVal + 1, grpName); - mir_free(dbv.pszVal); - } - else mir_tstrncpy(newBaseName, grpName, _countof(newBaseName)); - - int newId = CountGroups(); - _itoa(newId, str, 10); - mir_tstrncpy(newName + 1, newBaseName, _countof(newName) - 1); - if (ptszName) { - i = GroupNameExists(newBaseName, -1); - if (i) newId = i - 1; - i = !i; - } - else { - i = 1; - while (GroupNameExists(newName + 1, -1)) - mir_sntprintf(newName + 1, _countof(newName) - 1, _T("%s (%d)"), newBaseName, i++); - } - if (i) { - CLISTGROUPCHANGE grpChg = { sizeof(grpChg), NULL, newName }; - - newName[0] = 1 | GROUPF_EXPANDED; //1 is required so we never get '\0' - db_set_ts(NULL, "CListGroups", str, newName); - CallService(MS_CLUI_GROUPADDED, newId + 1, 1); - - NotifyEventHooks(hGroupChangeEvent, 0, (LPARAM)&grpChg); - } - - return newId + 1; -} - -static INT_PTR CreateGroup(WPARAM wParam, LPARAM lParam) -{ - if (lParam == 0) - return CreateGroupInternal(wParam, NULL); - - LPCTSTR ptszName = (LPCTSTR)lParam; - if (ptszName == NULL || ptszName[0] == '\0' || ptszName[0] == '\\') - return 0; - - TCHAR *tszName = NEWTSTR_ALLOCA(ptszName); - for (TCHAR *p = tszName; *p; p++) { - if (*p == '\\') { - *p = '\0'; - CreateGroupInternal(wParam, tszName); - *p = '\\'; - } - } - return CreateGroupInternal(wParam, tszName); -} - -static INT_PTR GetGroupName2(WPARAM wParam, LPARAM lParam) -{ - char idstr[33]; - DBVARIANT dbv; - static char name[128]; - - _itoa(wParam - 1, idstr, 10); - if (db_get_s(NULL, "CListGroups", idstr, &dbv)) - return (INT_PTR)(char *)NULL; - mir_strncpy(name, dbv.pszVal + 1, _countof(name)); - if ((DWORD *)lParam != NULL) - *(DWORD *)lParam = dbv.pszVal[0]; - db_free(&dbv); - return (INT_PTR)name; -} - -TCHAR* fnGetGroupName(int idx, DWORD* pdwFlags) -{ - char idstr[33]; - DBVARIANT dbv; - static TCHAR name[128]; - - _itoa(idx - 1, idstr, 10); - if (db_get_ts(NULL, "CListGroups", idstr, &dbv)) - return NULL; - - mir_tstrncpy(name, dbv.ptszVal + 1, _countof(name)); - if (pdwFlags != NULL) - *pdwFlags = dbv.ptszVal[0]; - db_free(&dbv); - return name; -} - -static INT_PTR GetGroupName(WPARAM wParam, LPARAM lParam) -{ - INT_PTR ret; - ret = GetGroupName2(wParam, lParam); - if ((int *)lParam) - *(int *)lParam = 0 != (*(int *)lParam & GROUPF_EXPANDED); - return ret; -} - -static INT_PTR DeleteGroup(WPARAM wParam, LPARAM) -{ - int i; - char str[33]; - DBVARIANT dbv; - MCONTACT hContact; - TCHAR name[256], szNewParent[256], *pszLastBackslash; - - //get the name - _itoa(wParam - 1, str, 10); - if (db_get_ts(NULL, "CListGroups", str, &dbv)) - return 1; - - mir_tstrncpy(name, dbv.ptszVal + 1, _countof(name)); - db_free(&dbv); - if (db_get_b(NULL, "CList", "ConfirmDelete", SETTING_CONFIRMDELETE_DEFAULT)) { - TCHAR szQuestion[256 + 100]; - mir_sntprintf(szQuestion, TranslateT("Are you sure you want to delete group '%s'? This operation cannot be undone."), name); - if (MessageBox(cli.hwndContactList, szQuestion, TranslateT("Delete group"), MB_YESNO | MB_ICONQUESTION) == IDNO) - return 1; - } - SetCursor(LoadCursor(NULL, IDC_WAIT)); - - // must remove setting from all child contacts too - // children are demoted to the next group up, not deleted. - mir_tstrcpy(szNewParent, name); - pszLastBackslash = _tcsrchr(szNewParent, '\\'); - if (pszLastBackslash) - pszLastBackslash[0] = '\0'; - else - szNewParent[0] = '\0'; - - for (hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { - if (db_get_ts(hContact, "CList", "Group", &dbv)) - continue; - - if (mir_tstrcmp(dbv.ptszVal, name)) { - db_free(&dbv); - continue; - } - db_free(&dbv); - - CLISTGROUPCHANGE grpChg = { sizeof(grpChg), NULL, NULL }; - if (szNewParent[0]) { - db_set_ts(hContact, "CList", "Group", szNewParent); - grpChg.pszNewName = szNewParent; - } - else db_unset(hContact, "CList", "Group"); - - NotifyEventHooks(hGroupChangeEvent, hContact, (LPARAM)&grpChg); - } - - // shuffle list of groups up to fill gap - for (i = wParam - 1;; i++) { - _itoa(i + 1, str, 10); - if (db_get_utf(NULL, "CListGroups", str, &dbv)) - break; - _itoa(i, str, 10); - db_set_utf(NULL, "CListGroups", str, dbv.pszVal); - db_free(&dbv); - } - _itoa(i, str, 10); - db_unset(NULL, "CListGroups", str); - - // rename subgroups - { - TCHAR szNewName[256]; - size_t len = mir_tstrlen(name); - for (i = 0;; i++) { - _itoa(i, str, 10); - if (db_get_ts(NULL, "CListGroups", str, &dbv)) - break; - if (!_tcsncmp(dbv.ptszVal + 1, name, len) && dbv.pszVal[len + 1] == '\\' && _tcschr(dbv.ptszVal + len + 2, '\\') == NULL) { - if (szNewParent[0]) - mir_sntprintf(szNewName, _T("%s\\%s"), szNewParent, dbv.ptszVal + len + 2); - else - mir_tstrncpy(szNewName, dbv.ptszVal + len + 2, _countof(szNewName)); - cli.pfnRenameGroup(i + 1, szNewName); - } - db_free(&dbv); - } - } - - WipeGroupList(); - BuildGroupList(); - - SetCursor(LoadCursor(NULL, IDC_ARROW)); - cli.pfnLoadContactTree(); - - const CLISTGROUPCHANGE grpChg = { sizeof(grpChg), name, NULL }; - NotifyEventHooks(hGroupChangeEvent, 0, (LPARAM)&grpChg); - return 0; -} - -static INT_PTR MoveGroupBefore(WPARAM wParam, LPARAM lParam) -{ - int i, shuffleFrom, shuffleTo, shuffleDir; - char str[33]; - TCHAR *szMoveName; - DBVARIANT dbv; - - if (wParam == 0 || (LPARAM)wParam == lParam) - return 0; - _itoa(wParam - 1, str, 10); - if (db_get_ts(NULL, "CListGroups", str, &dbv)) - return 0; - szMoveName = dbv.ptszVal; - //shuffle list of groups up to fill gap - if (lParam == 0) { - shuffleFrom = wParam - 1; - shuffleTo = -1; - shuffleDir = -1; - } - else { - if ((LPARAM)wParam < lParam) { - shuffleFrom = wParam - 1; - shuffleTo = lParam - 2; - shuffleDir = -1; - } - else { - shuffleFrom = wParam - 1; - shuffleTo = lParam - 1; - shuffleDir = 1; - } - } - if (shuffleDir == -1) { - for (i = shuffleFrom; i != shuffleTo; i++) { - _itoa(i + 1, str, 10); - if (db_get_utf(NULL, "CListGroups", str, &dbv)) { - shuffleTo = i; - break; - } - _itoa(i, str, 10); - db_set_utf(NULL, "CListGroups", str, dbv.pszVal); - db_free(&dbv); - } - } - else { - for (i = shuffleFrom; i != shuffleTo; i--) { - _itoa(i - 1, str, 10); - if (db_get_utf(NULL, "CListGroups", str, &dbv)) { - mir_free(szMoveName); - return 1; - } //never happens - _itoa(i, str, 10); - db_set_utf(NULL, "CListGroups", str, dbv.pszVal); - db_free(&dbv); - } - } - _itoa(shuffleTo, str, 10); - db_set_ts(NULL, "CListGroups", str, szMoveName); - mir_free(szMoveName); - - WipeGroupList(); - BuildGroupList(); - - return shuffleTo + 1; -} - -static int RenameGroupWithMove(int groupId, const TCHAR *szName, int move) -{ - char idstr[33]; - TCHAR str[256], oldName[256]; - DBVARIANT dbv; - - if (GroupNameExists(szName, groupId)) { - MessageBox(NULL, TranslateT("You already have a group with that name. Please enter a unique name for the group."), TranslateT("Rename group"), MB_ICONERROR | MB_OK); - return 1; - } - - //do the change - _itoa(groupId, idstr, 10); - if (db_get_ts(NULL, "CListGroups", idstr, &dbv)) - return 1; - str[0] = dbv.pszVal[0] & 0x7F; - mir_tstrncpy(oldName, dbv.ptszVal + 1, _countof(oldName)); - db_free(&dbv); - mir_tstrncpy(str + 1, szName, _countof(str) - 1); - db_set_ts(NULL, "CListGroups", idstr, str); - - //must rename setting in all child contacts too - for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { - ClcCacheEntry *cache = cli.pfnGetCacheEntry(hContact); - if (!mir_tstrcmp(cache->tszGroup, oldName)) { - db_set_ts(hContact, "CList", "Group", szName); - mir_free(cache->tszGroup); - cache->tszGroup = 0; - cli.pfnCheckCacheItem(cache); - } - } - - // rename subgroups - { - TCHAR szNewName[256]; - size_t len = mir_tstrlen(oldName); - for (int i = 0;; i++) { - if (i == groupId) - continue; - _itoa(i, idstr, 10); - if (db_get_ts(NULL, "CListGroups", idstr, &dbv)) - break; - if (!_tcsncmp(dbv.ptszVal + 1, oldName, len) && dbv.ptszVal[len + 1] == '\\' && _tcschr(dbv.ptszVal + len + 2, '\\') == NULL) { - mir_sntprintf(szNewName, _T("%s\\%s"), szName, dbv.ptszVal + len + 2); - RenameGroupWithMove(i, szNewName, 0); //luckily, child groups will never need reordering - } - db_free(&dbv); - } - } - - // finally must make sure it's after any parent items - if (move) { - mir_tstrncpy(str, szName, _countof(str)); - TCHAR *pszLastBackslash = _tcsrchr(str, '\\'); - if (pszLastBackslash != NULL) { - *pszLastBackslash = '\0'; - for (int i = 0;; i++) { - _itoa(i, idstr, 10); - if (db_get_ts(NULL, "CListGroups", idstr, &dbv)) - break; - if (!mir_tstrcmp(dbv.ptszVal + 1, str)) { - if (i < groupId) - break; //is OK - MoveGroupBefore(groupId + 1, i + 2); - break; - } - db_free(&dbv); - } - } - - WipeGroupList(); - BuildGroupList(); - } - - const CLISTGROUPCHANGE grpChg = { sizeof(grpChg), oldName, (TCHAR*)szName }; - NotifyEventHooks(hGroupChangeEvent, 0, (LPARAM)&grpChg); - return 0; -} - -int fnRenameGroup(int groupID, TCHAR* newName) -{ - return -1 != RenameGroupWithMove(groupID - 1, newName, 1); -} - -static INT_PTR RenameGroup(WPARAM wParam, LPARAM lParam) -{ - WCHAR* temp = mir_a2u((char*)lParam); - int result = (-1 != RenameGroupWithMove(wParam - 1, temp, 1)); - mir_free(temp); - return result; -} - -static INT_PTR SetGroupExpandedState(WPARAM wParam, LPARAM lParam) -{ - char idstr[33]; - DBVARIANT dbv; - - _itoa(wParam - 1, idstr, 10); - if (db_get_utf(NULL, "CListGroups", idstr, &dbv)) - return 1; - if (lParam) - dbv.pszVal[0] |= GROUPF_EXPANDED; - else - dbv.pszVal[0] = dbv.pszVal[0] & ~GROUPF_EXPANDED; - db_set_utf(NULL, "CListGroups", idstr, dbv.pszVal); - db_free(&dbv); - return 0; -} - -static INT_PTR SetGroupFlags(WPARAM wParam, LPARAM lParam) -{ - char idstr[33]; - DBVARIANT dbv; - int flags, oldval, newval; - - _itoa(wParam - 1, idstr, 10); - if (db_get_utf(NULL, "CListGroups", idstr, &dbv)) - return 1; - flags = LOWORD(lParam) & HIWORD(lParam); - oldval = dbv.pszVal[0]; - newval = dbv.pszVal[0] = ((oldval & ~HIWORD(lParam)) | flags) & 0x7f; - db_set_utf(NULL, "CListGroups", idstr, dbv.pszVal); - db_free(&dbv); - if ((oldval & GROUPF_HIDEOFFLINE) != (newval & GROUPF_HIDEOFFLINE)) - cli.pfnLoadContactTree(); - return 0; -} - -static INT_PTR BuildGroupMenu(WPARAM, LPARAM) -{ - char idstr[33]; - DBVARIANT dbv; - int groupId; - HMENU hRootMenu, hThisMenu; - int nextMenuId = 100; - TCHAR *pBackslash, *pNextField, szThisField[128], szThisMenuItem[128]; - int menuId, compareResult, menuItemCount; - - if (db_get_utf(NULL, "CListGroups", "0", &dbv)) - return (INT_PTR)(HMENU)NULL; - db_free(&dbv); - hRootMenu = CreateMenu(); - for (groupId = 0;; groupId++) { - _itoa(groupId, idstr, 10); - if (db_get_ts(NULL, "CListGroups", idstr, &dbv)) - break; - - pNextField = dbv.ptszVal + 1; - hThisMenu = hRootMenu; - - MENUITEMINFO mii = { 0 }; - mii.cbSize = sizeof(mii); - do { - pBackslash = _tcschr(pNextField, '\\'); - if (pBackslash == NULL) { - mir_tstrncpy(szThisField, pNextField, _countof(szThisField)); - pNextField = NULL; - } - else { - mir_tstrncpy(szThisField, pNextField, min(_countof(szThisField), pBackslash - pNextField + 1)); - pNextField = pBackslash + 1; - } - compareResult = 1; - menuItemCount = GetMenuItemCount(hThisMenu); - for (menuId = 0; menuId < menuItemCount; menuId++) { - mii.fMask = MIIM_TYPE | MIIM_SUBMENU | MIIM_DATA; - mii.cch = _countof(szThisMenuItem); - mii.dwTypeData = szThisMenuItem; - GetMenuItemInfo(hThisMenu, menuId, TRUE, &mii); - compareResult = mir_tstrcmp(szThisField, szThisMenuItem); - if (compareResult == 0) { - if (pNextField == NULL) { - mii.fMask = MIIM_DATA; - mii.dwItemData = groupId + 1; - SetMenuItemInfo(hThisMenu, menuId, TRUE, &mii); - } - else { - if (mii.hSubMenu == NULL) { - mii.fMask = MIIM_SUBMENU; - mii.hSubMenu = CreateMenu(); - SetMenuItemInfo(hThisMenu, menuId, TRUE, &mii); - mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID; - //dwItemData doesn't change - mii.fType = MFT_STRING; - mii.dwTypeData = TranslateT("This group"); - mii.wID = nextMenuId++; - InsertMenuItem(mii.hSubMenu, 0, TRUE, &mii); - mii.fMask = MIIM_TYPE; - mii.fType = MFT_SEPARATOR; - InsertMenuItem(mii.hSubMenu, 1, TRUE, &mii); - } - hThisMenu = mii.hSubMenu; - } - break; - } - if ((int)mii.dwItemData - 1 > groupId) - break; - } - if (compareResult) { - mii.fMask = MIIM_TYPE | MIIM_ID; - mii.wID = nextMenuId++; - mii.dwTypeData = szThisField; - mii.fType = MFT_STRING; - if (pNextField) { - mii.fMask |= MIIM_SUBMENU; - mii.hSubMenu = CreateMenu(); - } - else { - mii.fMask |= MIIM_DATA; - mii.dwItemData = groupId + 1; - } - InsertMenuItem(hThisMenu, menuId, TRUE, &mii); - if (pNextField) - hThisMenu = mii.hSubMenu; - } - } while (pNextField); - - db_free(&dbv); - } - return (INT_PTR)hRootMenu; -} - -int InitGroupServices(void) -{ - BuildGroupList(); - - CreateServiceFunction(MS_CLIST_GROUPEXISTS, GroupExists); - CreateServiceFunction(MS_CLIST_GROUPCREATE, CreateGroup); - CreateServiceFunction(MS_CLIST_GROUPDELETE, DeleteGroup); - CreateServiceFunction(MS_CLIST_GROUPRENAME, RenameGroup); - CreateServiceFunction(MS_CLIST_GROUPGETNAME, GetGroupName); - CreateServiceFunction(MS_CLIST_GROUPSETEXPANDED, SetGroupExpandedState); - CreateServiceFunction(MS_CLIST_GROUPSETFLAGS, SetGroupFlags); - CreateServiceFunction(MS_CLIST_GROUPMOVEBEFORE, MoveGroupBefore); - CreateServiceFunction(MS_CLIST_GROUPBUILDMENU, BuildGroupMenu); - - hGroupChangeEvent = CreateHookableEvent(ME_CLIST_GROUPCHANGE); - return 0; -} - -void UninitGroupServices(void) -{ - WipeGroupList(); -} diff --git a/src/mir_app/src/menu_groups.cpp b/src/mir_app/src/menu_groups.cpp index 051dc2d569..58efbff0b7 100644 --- a/src/mir_app/src/menu_groups.cpp +++ b/src/mir_app/src/menu_groups.cpp @@ -131,7 +131,7 @@ INT_PTR CreateGroupHelper(WPARAM, LPARAM) { SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, 0, 0); SendMessage(cli.hwndContactTree, CLM_SETUSEGROUPS, 1, 0); - Clist_CreateGroup(0, 0); + Clist_GroupCreate(0, 0); return 0; } diff --git a/src/mir_app/src/mir_app.def b/src/mir_app/src/mir_app.def index d82042dec2..7461945320 100644 --- a/src/mir_app/src/mir_app.def +++ b/src/mir_app/src/mir_app.def @@ -248,3 +248,12 @@ KillModuleFonts @246 KillModuleHotkeys @247 KillModuleSounds @248 IsPluginLoaded @249 +Clist_GroupBuildMenu @250 +Clist_GroupCreate @251 +Clist_GroupDelete @252 +Clist_GroupExists @253 +Clist_GroupMoveBefore @254 +Clist_GroupSetExpanded @255 +Clist_GroupSetFlags @256 +Clist_GroupGetName @257 +Clist_GroupRename @258 diff --git a/src/mir_app/src/mir_app64.def b/src/mir_app/src/mir_app64.def index 9cfc6c404d..70c2db00b7 100644 --- a/src/mir_app/src/mir_app64.def +++ b/src/mir_app/src/mir_app64.def @@ -248,3 +248,12 @@ KillModuleFonts @246 KillModuleHotkeys @247 KillModuleSounds @248 IsPluginLoaded @249 +Clist_GroupBuildMenu @250 +Clist_GroupCreate @251 +Clist_GroupDelete @252 +Clist_GroupExists @253 +Clist_GroupMoveBefore @254 +Clist_GroupSetExpanded @255 +Clist_GroupSetFlags @256 +Clist_GroupGetName @257 +Clist_GroupRename @258 -- cgit v1.2.3