void SetGroupExpand(HWND hwnd,struct ClcData *dat,struct ClcGroup *group,int newState) { int contentCount; int groupy; int newy; int posy; RECT clRect; NMCLISTCONTROL nm; if(newState==-1) group->expanded^=1; else { if(group->expanded==(newState!=0)) return; group->expanded=newState!=0; } InvalidateRectZ(hwnd,NULL,FALSE); if (group->expanded) contentCount=GetGroupContentsCount(group,1); else contentCount=0; groupy=GetRowsPriorTo(&dat->list,group,-1); if(dat->selection>groupy && dat->selection<groupy+contentCount) dat->selection=groupy; RecalcScrollBar(hwnd,dat); GetClientRect(hwnd,&clRect); newy=dat->yScroll; posy = RowHeights_GetItemBottomY(dat, groupy+contentCount); if(posy>=newy+clRect.bottom) newy=posy-clRect.bottom; posy = RowHeights_GetItemTopY(dat, groupy); if(newy>posy) newy=posy; ScrollTo(hwnd,dat,newy,0); nm.hdr.code=CLN_EXPANDED; nm.hdr.hwndFrom=hwnd; nm.hdr.idFrom=GetDlgCtrlID(hwnd); nm.hItem=(HANDLE)group->groupId; nm.action=group->expanded; SendMessage(GetParent(hwnd),WM_NOTIFY,0,(LPARAM)&nm); }
LRESULT CALLBACK ContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { struct ClcData *dat = (struct ClcData*)GetWindowLongPtr(hwnd,0); if ( msg >= CLM_FIRST && msg < CLM_LAST ) return pcli->pfnProcessExternalMessages(hwnd,dat,msg,wParam,lParam); switch (msg) { case WM_CREATE: dat = (struct ClcData*)mir_calloc( sizeof(struct ClcData)); SetWindowLong(hwnd,0,(LPARAM)dat); InitDisplayNameCache(&dat->lCLCContactsCache); break; case INTM_ICONCHANGED: { struct ClcContact *contact=NULL; struct ClcGroup *group=NULL; int recalcScrollBar=0,shouldShow; HANDLE hSelItem=NULL; struct ClcContact *selcontact=NULL; pdisplayNameCacheEntry cacheEntry = GetContactFullCacheEntry((HANDLE)wParam); WORD status; int NeedResort=0; char *szProto = cacheEntry->szProto; if(szProto==NULL) status=ID_STATUS_OFFLINE; else status=cacheEntry->status; shouldShow=(GetWindowLong(hwnd,GWL_STYLE)&CLS_SHOWHIDDEN || !cacheEntry->Hidden) && (!pcli->pfnIsHiddenMode(dat,status)||cacheEntry->noHiddenOffline || CallService(MS_CLIST_GETCONTACTICON,wParam,0)!=LOWORD(lParam)); //this means an offline msg is flashing, so the contact should be shown if(!FindItem(hwnd,dat,(HANDLE)wParam,&contact,&group,NULL)) { if(shouldShow && CallService(MS_DB_CONTACT_IS, wParam, 0)) { if(dat->selection>=0 && GetRowByIndex(dat,dat->selection,&selcontact,NULL)!=-1) hSelItem=pcli->pfnContactToHItem(selcontact); AddContactToTree(hwnd,dat,(HANDLE)wParam,0,0); NeedResort=1; recalcScrollBar=1; FindItem(hwnd,dat,(HANDLE)wParam,&contact,NULL,NULL); if (contact) { contact->iImage=(WORD)lParam; pcli->pfnNotifyNewContact(hwnd,(HANDLE)wParam); dat->NeedResort=1; } } } else { //item in list already DWORD style=GetWindowLong(hwnd,GWL_STYLE); if(contact->iImage== (WORD)lParam) break; if (sortByStatus) dat->NeedResort=1; if(!shouldShow && !(style&CLS_NOHIDEOFFLINE) && (style&CLS_HIDEOFFLINE || group->hideOffline)) { if(dat->selection>=0 && GetRowByIndex(dat,dat->selection,&selcontact,NULL)!=-1) hSelItem=pcli->pfnContactToHItem(selcontact); RemoveItemFromGroup(hwnd,group,contact,0); recalcScrollBar=1; dat->NeedResort=1; } else { int oldflags; contact->iImage=(WORD)lParam; oldflags=contact->flags; if(!pcli->pfnIsHiddenMode(dat,status)||cacheEntry->noHiddenOffline) contact->flags|=CONTACTF_ONLINE; else contact->flags&=~CONTACTF_ONLINE; if (oldflags!=contact->flags) dat->NeedResort=1; } } if(hSelItem) { struct ClcGroup *selgroup; if(FindItem(hwnd,dat,hSelItem,&selcontact,&selgroup,NULL)) dat->selection=GetRowsPriorTo(&dat->list,selgroup,li.List_IndexOf((SortedList*)&selgroup->cl, selcontact)); else dat->selection=-1; } SortClcByTimer(hwnd); if(recalcScrollBar) RecalcScrollBar(hwnd,dat); goto LBL_Exit; } case INTM_STATUSMSGCHANGED: { struct ClcContact *contact=NULL; struct ClcGroup *group=NULL; DBVARIANT dbv; if (!(dat->style&CLS_SHOWSTATUSMESSAGES)) break; if(FindItem(hwnd,dat,(HANDLE)wParam,&contact,&group,NULL) && contact!=NULL) { contact->flags &= ~CONTACTF_STATUSMSG; if (!DBGetContactSettingTString((HANDLE)wParam, "CList", "StatusMsg", &dbv)) { int j; if (dbv.ptszVal==NULL||_tcslen(dbv.ptszVal)==0) break; lstrcpyn(contact->szStatusMsg, dbv.ptszVal, SIZEOF(contact->szStatusMsg)); for (j=(int)_tcslen(contact->szStatusMsg)-1;j>=0;j--) { if (contact->szStatusMsg[j]=='\r' || contact->szStatusMsg[j]=='\n' || contact->szStatusMsg[j]=='\t') { contact->szStatusMsg[j] = ' '; } } DBFreeVariant(&dbv); if (_tcslen(contact->szStatusMsg)>0) { contact->flags |= CONTACTF_STATUSMSG; dat->NeedResort=TRUE; } } } InvalidateRect(hwnd,NULL,TRUE); SortClcByTimer(hwnd); RecalcScrollBar(hwnd,dat); goto LBL_Exit; } case WM_TIMER: if (wParam==TIMERID_DELAYEDREPAINT) { KillTimer(hwnd,TIMERID_DELAYEDREPAINT); InvalidateRect(hwnd,NULL,FALSE); break; } if ( wParam == TIMERID_SUBEXPAND) { KillTimer(hwnd,TIMERID_SUBEXPAND); if (hitcontact) { if (hitcontact->SubExpanded) hitcontact->SubExpanded=0; else hitcontact->SubExpanded=1; DBWriteContactSettingByte(hitcontact->hContact,"CList","Expanded",hitcontact->SubExpanded); } hitcontact=NULL; dat->NeedResort=1; SortCLC(hwnd,dat,1); RecalcScrollBar(hwnd,dat); break; } break; case WM_DESTROY: FreeDisplayNameCache(&dat->lCLCContactsCache); stopStatusUpdater = 1; break; } { LRESULT res = saveContactListControlWndProc(hwnd, msg, wParam, lParam); switch (msg) { case WM_CREATE: mir_forkthread(StatusUpdaterThread,0); break; } return res; } LBL_Exit: return DefWindowProc(hwnd, msg, wParam, lParam); }
void SortCLC(HWND hwnd,struct ClcData *dat,int useInsertionSort) { struct ClcContact *selcontact; struct ClcGroup *group=&dat->list,*selgroup; int dividers=dat->exStyle&CLS_EX_DIVIDERONOFF; HANDLE hSelItem; int tick=GetTickCount(); if (dat->NeedResort==1 &&1) { if(GetRowByIndex(dat,dat->selection,&selcontact,NULL)==-1) hSelItem=NULL; else hSelItem=ContactToHItem(selcontact); group->scanIndex=0; SortGroup(dat,group,useInsertionSort); for(;;) { if(group->scanIndex==group->contactCount) { group=group->parent; if(group==NULL) break; } else if(group->contact[group->scanIndex].type==CLCIT_GROUP) { group=group->contact[group->scanIndex].group; group->scanIndex=0; SortGroup(dat,group,useInsertionSort); continue; } group->scanIndex++; } ClearClcContactCache(dat,INVALID_HANDLE_VALUE); if(hSelItem) if(FindItem(hwnd,dat,hSelItem,&selcontact,&selgroup,NULL,FALSE)) dat->selection=GetRowsPriorTo(&dat->list,selgroup,selcontact-selgroup->contact); RecalcScrollBar(hwnd,dat); ClearRowByIndexCache(); }else { //TRACE("Not need to sort\r\n"); }; InvalidateRectZ(hwnd,NULL,FALSE); dat->NeedResort=0; // LOCK_IMAGE_UPDATING=1; // RecalcScrollBar(hwnd,dat); #ifdef _DEBUG tick=GetTickCount()-tick; { char buf[255]; //sprintf(buf,"%s %s took %i ms",__FILE__,__LINE__,tick); if (tick>5) { sprintf(buf,"SortCLC %d \r\n",tick); TRACE(buf); DBWriteContactSettingDword((HANDLE)0,"CLUI","PF:Last SortCLC Time:",tick); } } #endif }
void SaveStateAndRebuildList(HWND hwnd,struct ClcData *dat) { NMCLISTCONTROL nm; int i,j; struct SavedGroupState_t *savedGroup=NULL; int savedGroupCount=0,savedGroupAlloced=0; struct SavedContactState_t *savedContact=NULL; int savedContactCount=0,savedContactAlloced=0; struct SavedInfoState_t *savedInfo=NULL; int savedInfoCount=0,savedInfoAlloced=0; struct ClcGroup *group; struct ClcContact *contact; int tick=GetTickCount(); int allocstep=1024; TRACE("SaveStateAndRebuildList\n"); HideInfoTip(hwnd,dat); KillTimer(hwnd,TIMERID_INFOTIP); KillTimer(hwnd,TIMERID_REBUILDAFTER); KillTimer(hwnd,TIMERID_RENAME); EndRename(hwnd,dat,1); group=&dat->list; group->scanIndex=0; for(;;) { if(group->scanIndex==group->contactCount) { group=group->parent; if(group==NULL) break; } else if(group->contact[group->scanIndex].type==CLCIT_GROUP) { group=group->contact[group->scanIndex].group; group->scanIndex=0; if(++savedGroupCount>savedGroupAlloced) { savedGroupAlloced+=allocstep; savedGroup=(struct SavedGroupState_t*)mir_realloc(savedGroup,sizeof(struct SavedGroupState_t)*savedGroupAlloced); } savedGroup[savedGroupCount-1].groupId=group->groupId; savedGroup[savedGroupCount-1].expanded=group->expanded; continue; } else if(group->contact[group->scanIndex].type==CLCIT_CONTACT) { if(++savedContactCount>savedContactAlloced) { savedContactAlloced+=allocstep; savedContact=(struct SavedContactState_t*)mir_realloc(savedContact,sizeof(struct SavedContactState_t)*savedContactAlloced); } savedContact[savedContactCount-1].hContact=group->contact[group->scanIndex].hContact; CopyMemory(savedContact[savedContactCount-1].iExtraImage,group->contact[group->scanIndex].iExtraImage,sizeof(group->contact[group->scanIndex].iExtraImage)); savedContact[savedContactCount-1].checked=group->contact[group->scanIndex].flags&CONTACTF_CHECKED; if (group->contact[group->scanIndex].SubAllocated>0) { int l; for (l=0; l<group->contact[group->scanIndex].SubAllocated; l++) { if(++savedContactCount>savedContactAlloced) { savedContactAlloced+=allocstep; savedContact=(struct SavedContactState_t*)mir_realloc(savedContact,sizeof(struct SavedContactState_t)*savedContactAlloced); } savedContact[savedContactCount-1].hContact=group->contact[group->scanIndex].subcontacts[l].hContact; CopyMemory(savedContact[savedContactCount-1].iExtraImage ,group->contact[group->scanIndex].subcontacts[l].iExtraImage,sizeof(group->contact[group->scanIndex].iExtraImage)); savedContact[savedContactCount-1].checked=group->contact[group->scanIndex].subcontacts[l].flags&CONTACTF_CHECKED; } } } else if(group->contact[group->scanIndex].type==CLCIT_INFO) { if(++savedInfoCount>savedInfoAlloced) { savedInfoAlloced+=allocstep; savedInfo=(struct SavedInfoState_t*)mir_realloc(savedInfo,sizeof(struct SavedInfoState_t)*savedInfoAlloced); } if(group->parent==NULL) savedInfo[savedInfoCount-1].parentId=-1; else savedInfo[savedInfoCount-1].parentId=group->groupId; savedInfo[savedInfoCount-1].contact=group->contact[group->scanIndex]; { TCHAR * name=NULL; if(savedInfo[savedInfoCount-1].contact.szText) { name=mir_strdupT(savedInfo[savedInfoCount-1].contact.szText); mir_free(savedInfo[savedInfoCount-1].contact.szText); savedInfo[savedInfoCount-1].contact.szText=name; group->contact[group->scanIndex].szText=NULL; } } } group->scanIndex++; } FreeGroup(&dat->list); RebuildEntireList(hwnd,dat); group=&dat->list; group->scanIndex=0; for(;;) { if(group->scanIndex==group->contactCount) { group=group->parent; if(group==NULL) break; } else if(group->contact[group->scanIndex].type==CLCIT_GROUP) { group=group->contact[group->scanIndex].group; group->scanIndex=0; for(i=0;i<savedGroupCount;i++) if(savedGroup[i].groupId==group->groupId) { group->expanded=savedGroup[i].expanded; break; } continue; } else if(group->contact[group->scanIndex].type==CLCIT_CONTACT) { for(i=0;i<savedContactCount;i++) if(savedContact[i].hContact==group->contact[group->scanIndex].hContact) { CopyMemory(group->contact[group->scanIndex].iExtraImage,savedContact[i].iExtraImage,sizeof(group->contact[group->scanIndex].iExtraImage)); if(savedContact[i].checked) group->contact[group->scanIndex].flags|=CONTACTF_CHECKED; break; } if (group->contact[group->scanIndex].SubAllocated>0) { int l; for (l=0; l<group->contact[group->scanIndex].SubAllocated; l++) for(i=0;i<savedContactCount;i++) if(savedContact[i].hContact==group->contact[group->scanIndex].subcontacts[l].hContact) { CopyMemory(group->contact[group->scanIndex].subcontacts[l].iExtraImage,savedContact[i].iExtraImage,sizeof(group->contact[group->scanIndex].iExtraImage)); if(savedContact[i].checked) group->contact[group->scanIndex].subcontacts[l].flags|=CONTACTF_CHECKED; group->contact[group->scanIndex].subcontacts[l].subcontacts=&(group->contact[group->scanIndex]); break; } } } group->scanIndex++; } if(savedGroup) mir_free(savedGroup); if(savedContact) mir_free(savedContact); for(i=0;i<savedInfoCount;i++) { if(savedInfo[i].parentId==-1) group=&dat->list; else { if(!FindItem(hwnd,dat,(HANDLE)(savedInfo[i].parentId|HCONTACT_ISGROUP),&contact,NULL,NULL,TRUE)) continue; group=contact->group; } j=AddInfoItemToGroup(group,savedInfo[i].contact.flags,NULL); group->contact[j]=savedInfo[i].contact; } if(savedInfo) mir_free(savedInfo); RecalculateGroupCheckboxes(hwnd,dat); RecalcScrollBar(hwnd,dat); nm.hdr.code=CLN_LISTREBUILT; nm.hdr.hwndFrom=hwnd; nm.hdr.idFrom=GetDlgCtrlID(hwnd); //srand(GetTickCount()); tick=GetTickCount()-tick; #ifdef _DEBUG { char buf[255]; sprintf(buf,"SaveStateAndRebuildList %d \r\n",tick); TRACE(buf); } #endif ClearRowByIndexCache(); // SetAllExtraIcons(hwnd,0); SendMessage(GetParent(hwnd),WM_NOTIFY,0,(LPARAM)&nm); }
void SaveStateAndRebuildList(HWND hwnd,struct ClcData *dat) { NMCLISTCONTROL nm; int i,j; struct SavedGroupState_t *savedGroup = NULL; int savedGroupCount = 0,savedGroupAlloced = 0; struct SavedContactState_t *savedContact = NULL; int savedContactCount = 0,savedContactAlloced = 0; struct SavedInfoState_t *savedInfo = NULL; int savedInfoCount = 0,savedInfoAlloced = 0; ClcGroup *group; struct ClcContact *contact; int tick = GetTickCount(); int allocstep = 1024; pcli->pfnHideInfoTip(hwnd,dat); KillTimer(hwnd,TIMERID_INFOTIP); KillTimer(hwnd,TIMERID_RENAME); pcli->pfnEndRename(hwnd,dat,1); group = &dat->list; group->scanIndex = 0; for (;;) { if (group->scanIndex == group->cl.count) { group = group->parent; if (group == NULL) break; } else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) { group = group->cl.items[group->scanIndex]->group; group->scanIndex = 0; if (++savedGroupCount>savedGroupAlloced) { savedGroupAlloced += allocstep; savedGroup = (struct SavedGroupState_t*)mir_realloc(savedGroup,sizeof(struct SavedGroupState_t)*savedGroupAlloced); } savedGroup[savedGroupCount-1].groupId = group->groupId; savedGroup[savedGroupCount-1].expanded = group->expanded; continue; } else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) { if (++savedContactCount>savedContactAlloced) { savedContactAlloced += allocstep; savedContact = (struct SavedContactState_t*)mir_realloc(savedContact,sizeof(struct SavedContactState_t)*savedContactAlloced); } savedContact[savedContactCount-1].hContact = group->cl.items[group->scanIndex]->hContact; memcpy(savedContact[savedContactCount-1].iExtraImage, group->cl.items[group->scanIndex]->iExtraImage, sizeof(contact->iExtraImage)); savedContact[savedContactCount-1].checked = group->cl.items[group->scanIndex]->flags & CONTACTF_CHECKED; if (group->cl.items[group->scanIndex]->SubAllocated>0) { int l; for (l = 0; l<group->cl.items[group->scanIndex]->SubAllocated; l++) { if (++savedContactCount>savedContactAlloced) { savedContactAlloced += allocstep; savedContact = (struct SavedContactState_t*)mir_realloc(savedContact,sizeof(struct SavedContactState_t)*savedContactAlloced); } savedContact[savedContactCount-1].hContact = group->cl.items[group->scanIndex]->subcontacts[l].hContact; memcpy(savedContact[savedContactCount-1].iExtraImage, group->cl.items[group->scanIndex]->subcontacts[l].iExtraImage, sizeof(contact->iExtraImage)); savedContact[savedContactCount-1].checked = group->cl.items[group->scanIndex]->subcontacts[l].flags&CONTACTF_CHECKED; } } } else if (group->cl.items[group->scanIndex]->type == CLCIT_INFO) { if (++savedInfoCount>savedInfoAlloced) { savedInfoAlloced += allocstep; savedInfo = (struct SavedInfoState_t*)mir_realloc(savedInfo,sizeof(struct SavedInfoState_t)*savedInfoAlloced); } if (group->parent == NULL) savedInfo[savedInfoCount-1].parentId = -1; else savedInfo[savedInfoCount-1].parentId = group->groupId; savedInfo[savedInfoCount-1].contact = *group->cl.items[group->scanIndex]; } group->scanIndex++; } pcli->pfnFreeGroup(&dat->list); RebuildEntireList(hwnd,dat); group = &dat->list; group->scanIndex = 0; for (;;) { if (group->scanIndex == group->cl.count) { group = group->parent; if (group == NULL) break; } else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) { group = group->cl.items[group->scanIndex]->group; group->scanIndex = 0; for (i = 0;i<savedGroupCount;i++) if (savedGroup[i].groupId == group->groupId) { group->expanded = savedGroup[i].expanded; break; } continue; } else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) { for (i = 0;i<savedContactCount;i++) if (savedContact[i].hContact == group->cl.items[group->scanIndex]->hContact) { memcpy(group->cl.items[group->scanIndex]->iExtraImage, savedContact[i].iExtraImage, sizeof(contact->iExtraImage)); if (savedContact[i].checked) group->cl.items[group->scanIndex]->flags |= CONTACTF_CHECKED; break; } if (group->cl.items[group->scanIndex]->SubAllocated>0) { for (int l = 0; l<group->cl.items[group->scanIndex]->SubAllocated; l++) for (i = 0;i<savedContactCount;i++) if (savedContact[i].hContact == group->cl.items[group->scanIndex]->subcontacts[l].hContact) { memcpy(group->cl.items[group->scanIndex]->subcontacts[l].iExtraImage, savedContact[i].iExtraImage, sizeof(contact->iExtraImage)); if (savedContact[i].checked) group->cl.items[group->scanIndex]->subcontacts[l].flags |= CONTACTF_CHECKED; break; } } } group->scanIndex++; } if (savedGroup) mir_free(savedGroup); if (savedContact) mir_free(savedContact); for (i = 0;i<savedInfoCount;i++) { if (savedInfo[i].parentId == -1) group = &dat->list; else { if ( !FindItem(hwnd,dat,(HANDLE)(savedInfo[i].parentId|HCONTACT_ISGROUP),&contact,NULL,NULL)) continue; group = contact->group; } j = AddInfoItemToGroup(group,savedInfo[i].contact.flags,_T("")); *group->cl.items[j] = savedInfo[i].contact; } if (savedInfo) mir_free(savedInfo); pcli->pfnRecalculateGroupCheckboxes(hwnd,dat); RecalcScrollBar(hwnd,dat); nm.hdr.code = CLN_LISTREBUILT; nm.hdr.hwndFrom = hwnd; nm.hdr.idFrom = GetDlgCtrlID(hwnd); //srand(GetTickCount()); tick = GetTickCount()-tick; { char buf[255]; //sprintf(buf,"%s %s took %i ms",__FILE__,__LINE__,tick); mir_snprintf(buf, SIZEOF(buf), "SaveStateAndRebuildList %d \r\n", tick); OutputDebugStringA(buf); } ClearRowByIndexCache(); SendMessage(GetParent(hwnd),WM_NOTIFY,0,(LPARAM)&nm); }