summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2016-04-15 13:40:58 +0000
committerGeorge Hazan <george.hazan@gmail.com>2016-04-15 13:40:58 +0000
commit18f7e9261c885e953f220ba6836e8bca43a6fc88 (patch)
tree67cb94186914b97f1c0e8e815afffea7666b2510 /src
parentd2dd1c6dddd3e690ad13d2b355de60d3724e8ec6 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/mir_app/src/addcontact.cpp20
-rw-r--r--src/mir_app/src/chat_clist.cpp6
-rw-r--r--src/mir_app/src/clc.cpp70
-rw-r--r--src/mir_app/src/clc.h4
-rw-r--r--src/mir_app/src/clcitems.cpp6
-rw-r--r--src/mir_app/src/clcmsgs.cpp2
-rw-r--r--src/mir_app/src/clcutils.cpp8
-rw-r--r--src/mir_app/src/clistcore.cpp3
-rw-r--r--src/mir_app/src/clistgroups.cpp530
-rw-r--r--src/mir_app/src/clui.cpp4
-rw-r--r--src/mir_app/src/contact.cpp4
-rw-r--r--src/mir_app/src/groups.cpp608
-rw-r--r--src/mir_app/src/menu_groups.cpp2
-rw-r--r--src/mir_app/src/mir_app.def9
-rw-r--r--src/mir_app/src/mir_app64.def9
-rw-r--r--src/mir_core/src/mir_core.def2
-rw-r--r--src/mir_core/src/mir_core64.def2
-rw-r--r--src/mir_core/src/ui_utils.cpp4
18 files changed, 588 insertions, 705 deletions
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<CGroupInternal> arByName(20, CompareGrpByName);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct CGroupList : public LIST<CGroupInternal>
+{
+ CGroupList() :
+ LIST<CGroupInternal>(20, NumericKeySortT)
+ {}
+
+ __inline CGroupInternal* find(int key)
+ { return LIST<CGroupInternal>::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<CGroupInternal> arByName(20, CompareGrpByName);
-
-static LIST<CGroupInternal> 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
diff --git a/src/mir_core/src/mir_core.def b/src/mir_core/src/mir_core.def
index dedd3f240e..08474a3565 100644
--- a/src/mir_core/src/mir_core.def
+++ b/src/mir_core/src/mir_core.def
@@ -611,7 +611,7 @@ mir_wstrcmpi @280
?Expand@CCtrlTreeView@@QAEXPAU_TREEITEM@@K@Z @753 NONAME
?FindContact@CCtrlClc@@QAEPAXI@Z @754 NONAME
?FindControl@CDlgBase@@AAEPAVCCtrlBase@@H@Z @755 NONAME
-?FindGroup@CCtrlClc@@QAEPAXPAX@Z @756 NONAME
+?FindGroup@CCtrlClc@@QAEPAXH@Z @756 NONAME
?FindItem@CCtrlListView@@QAEHHPBUtagLVFINDINFOW@@@Z @757 NONAME
?FindNamedItem@CCtrlTreeView@@QAEPAU_TREEITEM@@PAU2@PB_W@Z @758 NONAME
?FindString@CCtrlCombo@@QAEHPB_WH_N@Z @759 NONAME
diff --git a/src/mir_core/src/mir_core64.def b/src/mir_core/src/mir_core64.def
index f81f27fc19..8f80acc931 100644
--- a/src/mir_core/src/mir_core64.def
+++ b/src/mir_core/src/mir_core64.def
@@ -611,7 +611,7 @@ mir_wstrcmpi @280
?Expand@CCtrlTreeView@@QEAAXPEAU_TREEITEM@@K@Z @753 NONAME
?FindContact@CCtrlClc@@QEAAPEAXI@Z @754 NONAME
?FindControl@CDlgBase@@AEAAPEAVCCtrlBase@@H@Z @755 NONAME
-?FindGroup@CCtrlClc@@QEAAPEAXPEAX@Z @756 NONAME
+?FindGroup@CCtrlClc@@QEAAPEAXH@Z @756 NONAME
?FindItem@CCtrlListView@@QEAAHHPEBUtagLVFINDINFOW@@@Z @757 NONAME
?FindNamedItem@CCtrlTreeView@@QEAAPEAU_TREEITEM@@PEAU2@PEB_W@Z @758 NONAME
?FindString@CCtrlCombo@@QEAAHPEB_WH_N@Z @759 NONAME
diff --git a/src/mir_core/src/ui_utils.cpp b/src/mir_core/src/ui_utils.cpp
index 00db886616..f9dec18581 100644
--- a/src/mir_core/src/ui_utils.cpp
+++ b/src/mir_core/src/ui_utils.cpp
@@ -751,8 +751,8 @@ HANDLE CCtrlClc::FindContact(MCONTACT hContact)
{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDCONTACT, hContact, 0);
}
-HANDLE CCtrlClc::FindGroup(HANDLE hGroup)
-{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDGROUP, (WPARAM)hGroup, 0);
+HANDLE CCtrlClc::FindGroup(MGROUP hGroup)
+{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDGROUP, hGroup, 0);
}
COLORREF CCtrlClc::GetBkColor()