#include "stdafx.h" #include "CContactList.h" #include "CConfig.h" #include "CAppletManager.h" const int aiStatusPriority[] = { 0, // ID_STATUS_OFFLINE 40071 9, // ID_STATUS_ONLINE 40072 8, // ID_STATUS_AWAY 40073 1, // ID_STATUS_DND 40074 7, // ID_STATUS_NA 40075 6, // ID_STATUS_OCCUPIED 40076 10, // ID_STATUS_FREECHAT 40077 9 // ID_STATUS_INVISIBLE 40078 }; //************************************************************************ // constructor //************************************************************************ CContactList::CContactList() { } //************************************************************************ // destructor //************************************************************************ CContactList::~CContactList() { } //************************************************************************ // initializes the list //************************************************************************ bool CContactList::Initialize() { if (!CLCDList::Initialize()) return false; InitializeGroupObjects(); RefreshList(); return true; } //************************************************************************ // deinitializes the list //************************************************************************ bool CContactList::Shutdown() { if (!CLCDList::Shutdown()) return false; UninitializeGroupObjects(); return false; } //************************************************************************ // returns the contacts ccontactlistentry class //************************************************************************ CContactListEntry *CContactList::GetContactData(CListEntry *pEntry) { if (pEntry->GetType() == ITEM) return ((CListItem*)pEntry)->GetItemData(); else return ((CListContainer*)pEntry)->GetGroupData()->pContactListEntry; } //************************************************************************ // returns the contacts group path //************************************************************************ tstring CContactList::GetContactGroupPath(MCONTACT hContact) { tstring strGroup = L""; if (db_get_b(0, "MetaContacts", "Enabled", 1) && db_mc_isSub(hContact)) { MCONTACT hMetaContact = db_mc_getMeta(hContact); if (CConfig::GetBoolSetting(CLIST_USEGROUPS)) strGroup = CAppletManager::GetContactGroup(hMetaContact); tstring strMetaName = CAppletManager::GetContactDisplayname(hMetaContact); strGroup += (strGroup.empty() ? L"" : L"\\") + strMetaName; } else strGroup = CAppletManager::GetContactGroup(hContact); return strGroup; } //************************************************************************ // adds a contact to the list //************************************************************************ void CContactList::AddContact(MCONTACT hContact) { CListContainer *pGroup = nullptr; tstring strName = CAppletManager::GetContactDisplayname(hContact); char *szProto = Proto_GetBaseAccountName(hContact); tstring strGroup = GetContactGroupPath(hContact); // ignore contacts without a valid protocoll if (szProto == nullptr) return; int iStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE); wchar_t *szStatus = Clist_GetStatusModeDescription(iStatus, 0); CContactListEntry *psContact = new CContactListEntry(); psContact->strName = strName; psContact->iMessages = 0; psContact->hHandle = hContact; psContact->iStatus = iStatus; if (szStatus != nullptr) psContact->strStatus = toTstring(szStatus); psContact->strProto = toTstring(szProto); // check wether the contact should be listed if (!IsVisible(psContact)) { delete psContact; return; } // Don't add metacontacts as contacts if (!mir_strcmpi(szProto, "MetaContacts")) { if (!CConfig::GetBoolSetting(CLIST_USEGROUPS)) strGroup = L""; strGroup += (strGroup.empty() ? L"" : L"\\") + psContact->strName; pGroup = GetGroupByString(strGroup); if (pGroup == nullptr) pGroup = AddGroupByString(strGroup); pGroup->GetGroupData()->hMetaContact = hContact; pGroup->GetGroupData()->pContactListEntry = psContact; pGroup = (CListContainer*)pGroup->GetParent(); if (pGroup->GetType() != ROOT && iStatus != ID_STATUS_OFFLINE) ChangeGroupObjectCounters(pGroup->GetGroupData()->strPath, 0, 1); pGroup->sort(CContactList::CompareEntries); // check that all subcontacts exist int numContacts = db_mc_getSubCount(hContact); MCONTACT hSubContact = NULL; for (int i = 0; i < numContacts; i++) { hSubContact = db_mc_getSub(hContact, i); RemoveContact(hSubContact); AddContact(hSubContact); } return; } else if (db_mc_isSub(hContact)) { MCONTACT hMetaContact = db_mc_getMeta(hContact); // check that the metacontact exists if (!FindContact(hMetaContact)) AddContact(hMetaContact); } CListItem *pItem = nullptr; if ((!db_mc_isSub(hContact) && !CConfig::GetBoolSetting(CLIST_USEGROUPS)) || strGroup.empty()) { pItem = AddItem(psContact); ((CListContainer*)this)->sort(CContactList::CompareEntries); } else { pGroup = GetGroupByString(strGroup); if (pGroup == nullptr) { pGroup = AddGroupByString(strGroup); } pItem = pGroup->AddItem(psContact); if (!db_mc_isSub(hContact) && iStatus != ID_STATUS_OFFLINE) ChangeGroupObjectCounters(pGroup->GetGroupData()->strPath, 0, 1); pGroup->sort(CContactList::CompareEntries); } UpdateMessageCounter((CListEntry*)pItem); } //************************************************************************ // returns wether a contact should be listed or not //************************************************************************ bool CContactList::IsVisible(CContactListEntry *pEntry) { if (!pEntry) return false; if (pEntry->strProto != L"MetaContacts") { if (pEntry->iStatus == ID_STATUS_OFFLINE && CConfig::GetBoolSetting(CLIST_HIDEOFFLINE)) return false; } else { if (pEntry->iStatus == ID_STATUS_OFFLINE) { int dwNumContacts = db_mc_getSubCount(pEntry->hHandle); for (int i = 0; i < dwNumContacts; i++) { MCONTACT hSubContact = db_mc_getSub(pEntry->hHandle, i); char *szProto = Proto_GetBaseAccountName(hSubContact); if (db_get_w(hSubContact, szProto, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) return true; } } } if (pEntry->iMessages > 0) return true; if (CConfig::GetBoolSetting(CLIST_USEIGNORE)) { if (Contact::IsHidden(pEntry->hHandle)) return false; if (db_mc_isSub(pEntry->hHandle)) { MCONTACT hMetaContact = db_mc_getMeta(pEntry->hHandle); if (Contact::IsHidden(hMetaContact)) return false; } } if (!CConfig::GetProtocolContactlistFilter(pEntry->strProto)) return false; if (CConfig::GetBoolSetting(CLIST_HIDEOFFLINE) && pEntry->iStatus == ID_STATUS_OFFLINE) return false; return true; } //************************************************************************ // removes a contact from the list //************************************************************************ void CContactList::RemoveContact(MCONTACT hContact) { CListContainer *pGroup = nullptr; CListEntry *pContactEntry = FindContact(hContact); if (!pContactEntry) return; if (!CConfig::GetBoolSetting(CLIST_USEGROUPS)) { if (pContactEntry->GetType() == ITEM) RemoveItem(((CListItem*)pContactEntry)->GetItemData()); else RemoveGroup(((CListContainer*)pContactEntry)->GetGroupData()); } else { pGroup = (CListContainer*)pContactEntry->GetParent(); ASSERT(pGroup != nullptr); CContactListEntry *pEntry = GetContactData(pContactEntry); if (!pEntry) return; // Update the contacts group if it has one if (pGroup->GetType() != ROOT) { if (!db_mc_isSub(hContact) && pEntry->iStatus != ID_STATUS_OFFLINE) ChangeGroupObjectCounters(pGroup->GetGroupData()->strPath, 0, -1); if (!db_mc_isSub(hContact) && pEntry->iMessages > 0) ChangeGroupObjectCounters(pGroup->GetGroupData()->strPath, 0, 0, -pEntry->iMessages); } if (pContactEntry->GetType() == ITEM) pGroup->RemoveItem(((CListItem*)pContactEntry)->GetItemData()); else { pGroup->RemoveGroup(((CListContainer*)pContactEntry)->GetGroupData()); // Reenumerate all subcontacts (maybe MetaContacts was disabled int numContacts = db_mc_getSubCount(hContact); for (int i = 0; i < numContacts; i++) { MCONTACT hSubContact = db_mc_getSub(hContact, i); if (!FindContact(hSubContact)) AddContact(hSubContact); } } CListContainer *pParent = (CListContainer*)pGroup->GetParent(); while (pParent != nullptr && pGroup->IsEmpty() && !pGroup->GetGroupData()->hMetaContact) { pParent->RemoveGroup(pGroup->GetGroupData()); pGroup = pParent; pParent = (CListContainer*)pGroup->GetParent(); } } } //************************************************************************ // get group by string //************************************************************************ CListContainer *CContactList::GetGroupByString(tstring strGroup) { tstring strParse = strGroup; CListContainer *pGroup = (CListContainer*)this; tstring::size_type pos; while ((pos = strParse.find('\\')) != tstring::npos) { strGroup = strParse.substr(0, pos); strParse = strParse.substr(pos + 1); pGroup = FindGroupInGroup(strGroup, pGroup); if (pGroup == nullptr) return nullptr; } pGroup = FindGroupInGroup(strParse, pGroup); return pGroup; } //************************************************************************ // Adds a group //************************************************************************ CListContainer *CContactList::AddGroupByString(tstring strGroup) { tstring strParse = strGroup; tstring strPath = L""; CListContainer *pGroup = (CListContainer*)this; CListContainer *pGroup2 = nullptr; tstring::size_type pos; while ((pos = strParse.find('\\')) != tstring::npos) { strGroup = strParse.substr(0, pos); strParse = strParse.substr(pos + 1); strPath += strGroup; if (pGroup2 = FindGroupInGroup(strGroup, pGroup)) pGroup = pGroup2; else { CContactListGroup *pGroupObject = GetGroupObjectByPath(strPath); if (!pGroupObject) pGroupObject = CreateGroupObjectByPath(strPath); pGroup2 = pGroup->InsertGroup(pGroup->begin(), pGroupObject); pGroup->sort(CContactList::CompareEntries); pGroup = pGroup2; } ASSERT(pGroup != nullptr); strPath += L"\\"; } strPath += strParse; if (pGroup2 = FindGroupInGroup(strParse, pGroup)) return pGroup2; CContactListGroup *pGroupObject = GetGroupObjectByPath(strPath); if (!pGroupObject) pGroupObject = CreateGroupObjectByPath(strPath); pGroup2 = pGroup->InsertGroup(pGroup->begin(), pGroupObject); pGroup->sort(CContactList::CompareEntries); return pGroup2; } //************************************************************************ // returns the contact's status //************************************************************************ int CContactList::GetContactStatus(MCONTACT hContact) { CListEntry *pContactEntry = FindContact(hContact); if (!pContactEntry) return ID_STATUS_OFFLINE; CContactListEntry *pEntry = GetContactData(pContactEntry); if (!pEntry) return ID_STATUS_OFFLINE; return pEntry->iStatus; } //************************************************************************ // Called to delete the specified item //************************************************************************ void CContactList::DeleteItem(CContactListEntry *pEntry) { delete pEntry; } //************************************************************************ // Called to delete the specified group //************************************************************************ void CContactList::DeleteGroup(CContactListGroup*) { } //************************************************************************ // Called to draw the specified entry //************************************************************************ void CContactList::DrawEntry(CLCDGfx *pGfx, CContactListEntry *pEntry, bool bSelected) { if (pEntry == nullptr) return; tstring strText = L""; if (pEntry->iMessages > 0) { strText = L"["; strText += pEntry->strMessages; strText += L"]"; } strText += pEntry->strName; if (CConfig::GetBoolSetting(CLIST_SHOWPROTO) && !CConfig::GetBoolSetting(CLIST_COLUMNS)) { int w = pGfx->GetClipWidth(); pGfx->DrawText(w - w * 0.3, 0, w*0.3, pEntry->strProto); pGfx->DrawText(8, 0, w*0.7 - 8, strText); } else pGfx->DrawText(8, 0, pGfx->GetClipWidth() - 8, strText); pGfx->DrawBitmap(1, ceil((pGfx->GetClipHeight() - 5) / 2.0f), 5, 5, CAppletManager::GetInstance()->GetStatusBitmap(pEntry->iStatus)); if (bSelected && (GetTickCount() - m_dwLastScroll < 1000 || !CConfig::GetBoolSetting(CLIST_SELECTION))) { RECT invert = {0,0,GetWidth(),m_iFontHeight}; InvertRect(pGfx->GetHDC(), &invert); } } //************************************************************************ // Called to draw the specified group //************************************************************************ void CContactList::DrawGroup(CLCDGfx *pGfx, CContactListGroup *pGroup, bool bOpen, bool bSelected) { if (pGroup == nullptr || (pGroup->hMetaContact && pGroup->pContactListEntry == nullptr)) return; char num[10], num2[10]; itoa(pGroup->iMembers, num, 10); itoa(pGroup->iOnline, num2, 10); int iEvents = pGroup->iEvents; tstring strText = pGroup->strName; if (!pGroup->hMetaContact) { if (CConfig::GetBoolSetting(CLIST_COUNTERS)) strText = strText + L" (" + toTstring(num2).c_str() + L"/" + toTstring(num).c_str() + L")"; } else { pGfx->DrawBitmap(8, ceil((pGfx->GetClipHeight() - 5) / 2.0f), 5, 5, CAppletManager::GetInstance()->GetStatusBitmap(pGroup->pContactListEntry->iStatus)); iEvents += pGroup->pContactListEntry->iMessages; } if (iEvents != 0) { itoa(iEvents, num, 10); strText = L"[" + toTstring(num) + L"]" + strText; } int iOffset = !pGroup->hMetaContact ? m_iFontHeight * 0.8 : m_iFontHeight * 0.8 + 8; pGfx->DrawText(iOffset, 0, pGfx->GetClipWidth() - iOffset, strText.c_str()); if (bOpen) pGfx->DrawText(1, 0, L"-"); else pGfx->DrawText(1, 0, L"+"); if (bSelected && (GetTickCount() - m_dwLastScroll < 1000 || !CConfig::GetBoolSetting(CLIST_SELECTION))) { RECT invert2 = {0,0,GetWidth(),m_iFontHeight}; InvertRect(pGfx->GetHDC(), &invert2); } } //************************************************************************ // Called to compare two entrys //************************************************************************ bool CContactList::CompareEntries(CListEntry *pLeft, CListEntry *pRight) { CContactListEntry *pLeftEntry = GetContactData(pLeft); CContactListEntry *pRightEntry = GetContactData(pRight); if (pLeftEntry && pRightEntry) { int iLeftMessages = pLeftEntry->iMessages; int iRightMessages = pRightEntry->iMessages; if (pLeft->GetType() == CONTAINER) iLeftMessages += ((CListContainer*)pLeft)->GetGroupData()->iEvents; if (pRight->GetType() == CONTAINER) iRightMessages += ((CListContainer*)pRight)->GetGroupData()->iEvents; if (!iRightMessages && iLeftMessages) return true; else if (iRightMessages && !iLeftMessages) return false; else if (iLeftMessages && iRightMessages) return (iLeftMessages > iRightMessages); else if (pLeftEntry->iStatus != pRightEntry->iStatus) return (aiStatusPriority[pLeftEntry->iStatus - ID_STATUS_OFFLINE] > aiStatusPriority[pRightEntry->iStatus - ID_STATUS_OFFLINE]); else return mir_wstrcmpi(pLeftEntry->strName.c_str(), pRightEntry->strName.c_str()) < 0; } else if (pLeft->GetType() == ITEM && pRight->GetType() == CONTAINER) return false; else if (pLeft->GetType() == CONTAINER && pRight->GetType() == ITEM) return true; else if (pLeft->GetType() == CONTAINER && pRight->GetType() == CONTAINER) { CContactListGroup *pGroup1 = ((CListContainer*)pLeft)->GetGroupData(); CContactListGroup *pGroup2 = ((CListContainer*)pRight)->GetGroupData(); if (!pGroup2->iEvents && pGroup1->iEvents) return true; else if (pGroup2->iEvents && !pGroup1->iEvents) return false; else if (pGroup1->iEvents && pGroup2->iEvents) return (pGroup1->iEvents > pGroup2->iEvents); else return mir_wstrcmpi(pGroup1->strName.c_str(), pGroup2->strName.c_str()) < 0; } return false; } //************************************************************************ // refreshes the list //************************************************************************ void CContactList::RefreshList() { if ((db_get_b(0, "MetaContacts", "Enabled", 1) != 0) != m_bUseMetaContacts || CConfig::GetBoolSetting(CLIST_USEGROUPS) != m_bUseGroups) { InitializeGroupObjects(); Clear(); } m_bUseGroups = CConfig::GetBoolSetting(CLIST_USEGROUPS); m_bUseMetaContacts = db_get_b(0, "MetaContacts", "Enabled", 1) != 0; for (auto &hContact: Contacts()) { auto *pContactEntry = FindContact(hContact); if (!pContactEntry) AddContact(hContact); else if (pContactEntry && !IsVisible(GetContactData(pContactEntry))) RemoveContact(hContact); } } //************************************************************************ // set the contactlists font //************************************************************************ bool CContactList::SetFont(LOGFONT &lf) { if (!CLCDList::SetFont(lf)) return false; SetEntryHeight(m_iFontHeight < 5 ? 5 : m_iFontHeight); return true; } //************************************************************************ // called when the configuration has changed //************************************************************************ void CContactList::OnConfigChanged() { RefreshList(); } //************************************************************************ // returns the entry for the specified group name //************************************************************************ CListContainer *CContactList::FindGroup(tstring strGroup) { return FindGroupInGroup(strGroup, (CListContainer*)this); } //************************************************************************ // returns the entry for the specified group name //************************************************************************ CListContainer *CContactList::FindGroupInGroup(tstring strGroup, CListContainer *pGroup) { CListContainer::iterator iter = pGroup->begin(); CListContainer *pItem = nullptr; while (!pGroup->empty() && iter != pGroup->end()) { if ((*iter)->GetType() == CONTAINER) { pItem = (CListContainer*)*iter; if (pItem->GetGroupData()->strName == strGroup) return pItem; //pItem = FindGroupInGroup(strGroup,(CListContainer *)*iter); //if(pItem) // return pItem; } iter++; } return nullptr; } //************************************************************************ // returns the entry for the specified handle //************************************************************************ CListEntry *CContactList::FindContact(MCONTACT hContact) { if (hContact == NULL) return nullptr; return FindContactInGroup(hContact, (CListContainer*)this); } //************************************************************************ // returns the entry for the specified handle //************************************************************************ CListEntry *CContactList::FindContactInGroup(MCONTACT hContact, CListContainer *pGroup) { if (hContact == NULL) return nullptr; CListItem *pItemEntry = nullptr; CListEntry *pEntry = nullptr; CListContainer *pGroupEntry = nullptr; CListContainer::iterator iter = pGroup->begin(); while (iter != pGroup->end()) { if ((*iter)->GetType() == ITEM) { pItemEntry = (CListItem*)*iter; if (pItemEntry->GetItemData()->hHandle == hContact) return *iter; } else { pGroupEntry = (CListContainer *)*iter; if (pGroupEntry->GetGroupData()->hMetaContact == hContact) return *iter; pEntry = FindContactInGroup(hContact, pGroupEntry); if (pEntry) return pEntry; } iter++; } return nullptr; } //************************************************************************ // called when a contacts hidden flag has changed //************************************************************************ void CContactList::OnContactHiddenChanged(MCONTACT hContact, bool bHidden) { CListEntry *pContactEntry = FindContact(hContact); if (!pContactEntry && !bHidden) { AddContact(hContact); return; } else if (!pContactEntry) return; if (!IsVisible(GetContactData(pContactEntry))) RemoveContact(hContact); } //************************************************************************ // called when a contacts nickname has changed //************************************************************************ void CContactList::OnContactNickChanged(MCONTACT hContact, tstring strNick) { CListEntry *pContactEntry = FindContact(hContact); if (!pContactEntry) return; if (pContactEntry->GetType() == CONTAINER) { CListContainer *pGroup = ((CListContainer*)pContactEntry); pGroup->GetGroupData()->strName = strNick; tstring strPath = GetContactGroupPath(hContact); pGroup->GetGroupData()->strPath = strPath + (strPath.empty() ? L"" : L"\\") + strNick; } CContactListEntry* pEntry = GetContactData(pContactEntry); if (!pEntry) { return; } pEntry->strName = strNick; ((CListContainer*)pContactEntry->GetParent())->sort(CContactList::CompareEntries); } //************************************************************************ // called when a contacts status has changed //************************************************************************ void CContactList::OnStatusChange(MCONTACT hContact, int iStatus) { // find the entry in the list CListEntry *pContactEntry = FindContact(hContact); if (!pContactEntry) { AddContact(hContact); return; } CContactListEntry *pItemData = GetContactData(pContactEntry); if (!pItemData) { return; } // get the old status int iOldStatus = pItemData->iStatus; // Update the list entry wchar_t *szStatus = Clist_GetStatusModeDescription(iStatus, 0); if (szStatus != nullptr) pItemData->strStatus = toTstring(szStatus); pItemData->iStatus = iStatus; // update the contacts group CListContainer* pGroup = ((CListContainer*)pContactEntry->GetParent()); if (pGroup->GetType() != ROOT) { if (!db_mc_isSub(hContact) && iStatus == ID_STATUS_OFFLINE && iOldStatus != ID_STATUS_OFFLINE) ChangeGroupObjectCounters(pGroup->GetGroupData()->strPath, 0, -1); else if (!db_mc_isSub(hContact) && iStatus != ID_STATUS_OFFLINE && iOldStatus == ID_STATUS_OFFLINE) ChangeGroupObjectCounters(pGroup->GetGroupData()->strPath, 0, 1); } // check if the entry is still visible if (!IsVisible(pItemData)) { RemoveContact(hContact); return; } // sort the list pGroup->sort(CContactList::CompareEntries); } //************************************************************************ // called when the contacts message count has changed //************************************************************************ void CContactList::OnMessageCountChanged(MCONTACT hContact) { CListEntry *pContactEntry = FindContact(hContact); if (!pContactEntry) { AddContact(hContact); return; } UpdateMessageCounter(pContactEntry); if (!IsVisible(GetContactData(pContactEntry))) RemoveContact(hContact); ((CListContainer*)pContactEntry->GetParent())->sort(CContactList::CompareEntries); } //************************************************************************ // called when a contact has been added //************************************************************************ void CContactList::OnContactAdded(MCONTACT hContact) { // Update the list AddContact(hContact); // increase the membercount of the new group, and check if it needs to be created tstring strGroup = GetContactGroupPath(hContact); if (!strGroup.empty()) { CContactListGroup *pGroup = GetGroupObjectByPath(strGroup); if (!pGroup) pGroup = CreateGroupObjectByPath(strGroup); if (!db_mc_isSub(hContact)) ChangeGroupObjectCounters(strGroup, 1); } } //************************************************************************ // called when a contact has been deleted //************************************************************************ void CContactList::OnContactDeleted(MCONTACT hContact) { // Update the list RemoveContact(hContact); // Decrease the membercount of the old group, and check if it needs to be deleted tstring strGroup = GetContactGroupPath(hContact); if (!strGroup.empty()) { CContactListGroup *pGroup = GetGroupObjectByPath(strGroup); if (!db_mc_isSub(hContact)) ChangeGroupObjectCounters(strGroup, -1); if (pGroup && pGroup->iMembers <= 0) DeleteGroupObjectByPath(pGroup->strPath); } } //************************************************************************ // called when a contacts group has changed //************************************************************************ void CContactList::OnContactGroupChanged(MCONTACT hContact, tstring strGroup) { bool bMetaContact = false; strGroup = GetContactGroupPath(hContact); // Decrease the membercount of the old group CListEntry *pContactEntry = FindContact(hContact); CContactListGroup *pOldGroup = nullptr; // If the contactentry was not found, try adding the contact (metacontacts fix) if (!pContactEntry) { return; } if (pContactEntry->GetType() == CONTAINER) bMetaContact = true; CListContainer* pContainer = ((CListContainer*)pContactEntry->GetParent()); // Update the contacts group if it has one if (pContainer->GetType() != ROOT) { pOldGroup = pContainer->GetGroupData(); if (!db_mc_isSub(hContact)) ChangeGroupObjectCounters(pOldGroup->strPath, -1); } // increase the membercount of the new group, and check if it needs to be created if (!strGroup.empty()) { CContactListGroup *pGroup = GetGroupObjectByPath(strGroup); if (!pGroup) pGroup = CreateGroupObjectByPath(strGroup); if (!db_mc_isSub(hContact)) ChangeGroupObjectCounters(strGroup, 1); } // move subcontacts if (pContactEntry->GetType() == CONTAINER) { CListContainer *pGroup = (CListContainer*)pContactEntry; CListContainer::iterator iter = pGroup->begin(); while (!pGroup->empty()) { iter = pGroup->begin(); if ((*iter)->GetType() == ITEM) OnContactGroupChanged(GetContactData(*iter)->hHandle, L""); Sleep(1); } } // update the list RemoveContact(hContact); AddContact(hContact); if (bMetaContact) { tstring strName = CAppletManager::GetContactDisplayname(hContact); tstring strPath = L""; if (pOldGroup) strPath += pOldGroup->strPath; strPath += (strPath.empty() ? L"" : L"\\") + strName; DeleteGroupObjectByPath(strPath); } // check if the old group ( if it exists ) needs to be deleted if (pOldGroup && !pOldGroup->hMetaContact && pOldGroup->iMembers <= 0 && pOldGroup->iGroups <= 0) DeleteGroupObjectByPath(pOldGroup->strPath); } //************************************************************************ // updates the message count for the specified contact //************************************************************************ void CContactList::UpdateMessageCounter(CListEntry *pContactEntry) { CContactListEntry *pEntry = GetContactData(pContactEntry); if (!pEntry) { return; } int iOldMessages = pEntry->iMessages; bool bSort = false; MEVENT hEvent = db_event_firstUnread(pEntry->hHandle); if (CAppletManager::IsMessageWindowOpen(pEntry->hHandle) || (hEvent == NULL && pEntry->iMessages > 0)) { pEntry->iMessages = 0; bSort = true; } else { pEntry->iMessages = 0; MEVENT hLastEvent = db_event_last(pEntry->hHandle); while (hLastEvent != NULL && hEvent != NULL) { pEntry->iMessages++; if (hLastEvent == hEvent) break; hLastEvent = db_event_prev(pEntry->hHandle, hLastEvent); } } if (pEntry->iMessages >= 100) pEntry->strMessages = L">99"; else { char buffer[8]; buffer[0] = 0; itoa(pEntry->iMessages, buffer, 10); pEntry->strMessages = toTstring(buffer); } CListContainer* pContainer = ((CListContainer*)pContactEntry->GetParent()); // Update the contacts group if it has one if (pContainer->GetType() != ROOT) { // Update the groups event count if (iOldMessages != 0 && pEntry->iMessages == 0) ChangeGroupObjectCounters(pContainer->GetGroupData()->strPath, 0, 0, -1); else if (iOldMessages == 0 && pEntry->iMessages != 0) ChangeGroupObjectCounters(pContainer->GetGroupData()->strPath, 0, 0, 1); else return; // sort the groups parent ((CListContainer*)pContainer->GetParent())->sort(CContactList::CompareEntries); } } //************************************************************************ // changes the groups membercount //************************************************************************ void CContactList::ChangeGroupObjectCounters(tstring strGroup, int iMembers, int iOnline, int iEvents) { CContactListGroup* pGroup = GetGroupObjectByPath(strGroup); if (!pGroup) return; pGroup->iMembers += iMembers; pGroup->iOnline += iOnline; pGroup->iEvents += iEvents; tstring strParse = pGroup->strPath; tstring::size_type pos; while ((pos = strParse.rfind('\\')) != tstring::npos) { strParse = strParse.substr(0, pos); pGroup = GetGroupObjectByPath(strParse); if (!pGroup) break; pGroup->iMembers += iMembers; pGroup->iOnline += iOnline; pGroup->iEvents += iEvents; } } //************************************************************************ // uninitializes the group objects //************************************************************************ void CContactList::UninitializeGroupObjects() { vector::iterator iter = m_Groups.begin(); while (iter != m_Groups.end()) { delete (*iter); iter++; } m_Groups.clear(); } //************************************************************************ // initializes the group objects //************************************************************************ void CContactList::InitializeGroupObjects() { UninitializeGroupObjects(); for (auto &hContact: Contacts()) { tstring strGroup = GetContactGroupPath(hContact); char *szProto = Proto_GetBaseAccountName(hContact); if (szProto && db_get_b(0, META_PROTO, "Enabled", 1) && !mir_strcmpi(szProto, META_PROTO)) { tstring strName = CAppletManager::GetContactDisplayname(hContact); tstring strPath = L""; if (CConfig::GetBoolSetting(CLIST_USEGROUPS)) strPath += strGroup; strPath += (strPath.empty() ? L"" : L"\\") + strName; CContactListGroup *pGroup = CreateGroupObjectByPath(strPath); pGroup->hMetaContact = hContact; if (!strGroup.empty()) ChangeGroupObjectCounters(strGroup, 1); } // If the contact has no group, continue else if (!strGroup.empty() && CConfig::GetBoolSetting(CLIST_USEGROUPS)) { CContactListGroup *pGroup = GetGroupObjectByPath(strGroup); // create the group if (!pGroup) CreateGroupObjectByPath(strGroup); // update it's counters if (!db_mc_isSub(hContact)) ChangeGroupObjectCounters(strGroup, 1); } } } //************************************************************************ // get group object by string //************************************************************************ CContactListGroup *CContactList::GetGroupObjectByPath(tstring strPath) { ASSERT(!strPath.empty()); CContactListGroup *pGroup = nullptr; vector::iterator iter = m_Groups.begin(); for (; iter != m_Groups.end(); iter++) { if ((*iter)->strPath == strPath) { pGroup = *iter; break; } } return pGroup; } //************************************************************************ // creates a group object by string //************************************************************************ CContactListGroup *CContactList::CreateGroupObjectByPath(tstring strPath) { ASSERT(!strPath.empty()); CContactListGroup *pNewGroup = new CContactListGroup(); CContactListGroup *pParentGroup = nullptr; tstring strParsePath = L""; tstring strName = strPath; tstring::size_type pos; while ((pos = strName.find('\\')) != tstring::npos) { strParsePath += strName.substr(0, pos); strName = strName.substr(pos + 1); pParentGroup = GetGroupObjectByPath(strParsePath); if (!pParentGroup) pParentGroup = CreateGroupObjectByPath(strParsePath); strParsePath += L"\\"; } if (pParentGroup) pParentGroup->iGroups++; pNewGroup->strName = strName; pNewGroup->strPath = strPath; pNewGroup->iMembers = 0; pNewGroup->iOnline = 0; pNewGroup->iGroups = 0; pNewGroup->iEvents = 0; pNewGroup->hMetaContact = NULL; pNewGroup->pContactListEntry = nullptr; m_Groups.push_back(pNewGroup); return pNewGroup; } //************************************************************************ // deletes a group object by string //************************************************************************ void CContactList::DeleteGroupObjectByPath(tstring strPath) { ASSERT(!strPath.empty()); for (vector::iterator iter = m_Groups.begin(); iter != m_Groups.end(); iter++) { if ((*iter)->strPath == strPath) { CContactListGroup *pGroup = *iter; m_Groups.erase(iter); if (pGroup->pContactListEntry) DeleteEntry(pGroup->pContactListEntry); delete pGroup; tstring strParse = strPath; tstring::size_type pos = strParse.rfind('\\'); if (pos != tstring::npos) { strParse = strParse.substr(0, pos); CContactListGroup *pParentGroup = GetGroupObjectByPath(strParse); if (pParentGroup) { pParentGroup->iGroups--; if (pParentGroup->iMembers <= 0 && pParentGroup->iGroups <= 0) DeleteGroupObjectByPath(strParse); } } return; } } } void CContactList::SetPosition(CListEntry *pEntry) { CLCDList::SetPosition(pEntry); } bool CContactList::ScrollUp() { m_dwLastScroll = GetTickCount(); return CLCDList::ScrollUp(); } bool CContactList::ScrollDown() { m_dwLastScroll = GetTickCount(); return CLCDList::ScrollDown(); } void CContactList::ShowSelection() { m_dwLastScroll = GetTickCount(); }