///////////////////////////////////////////////////////////////////////////// // Copyright (C) 1993-1996 Microsoft Corporation. All Rights Reserved. // // MODULE: PickGrp.cpp // // PURPOSE: Dialog to allow the user to select groups to post to in the // send note window. // #include "pch.hxx" #include #include "pickgrp.h" #include "grplist2.h" #include "shlwapip.h" #include "resource.h" #include "strconst.h" #include "demand.h" CPickGroupDlg::CPickGroupDlg() { m_cRef = 1; m_ppszGroups = 0; m_hwndPostTo = 0; m_fPoster = FALSE; m_hIcon = NULL; m_pGrpList = NULL; m_pszAcct = NULL; m_idAcct = FOLDERID_INVALID; } CPickGroupDlg::~CPickGroupDlg() { if (m_hIcon) SideAssert(DestroyIcon(m_hIcon)); if (m_pGrpList != NULL) m_pGrpList->Release(); } HRESULT STDMETHODCALLTYPE CPickGroupDlg::QueryInterface(REFIID riid, void **ppvObj) { if (IsEqualIID(riid, IID_IUnknown)) *ppvObj = (void*) (IUnknown *)(IGroupListAdvise *)this; else if (IsEqualIID(riid, IID_IGroupListAdvise)) *ppvObj = (void*) (IGroupListAdvise *) this; else { *ppvObj = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } ULONG STDMETHODCALLTYPE CPickGroupDlg::AddRef() { return ++m_cRef; } ULONG STDMETHODCALLTYPE CPickGroupDlg::Release() { if (--m_cRef == 0) { delete this; return 0; } return m_cRef; } // // FUNCTION: CPickGroupsDlg::FCreate() // // PURPOSE: Handles initialization of the data and creation of the pick // groups dialog. // // PARAMETERS: // hwndOwner - Window that will own this dialog. // pszAccount - account to use initially. // ppszGroups - This is where we return the last selected group // // RETURN VALUE: // Returns TRUE if successful, or FALSE otherwise. // BOOL CPickGroupDlg::FCreate(HWND hwndOwner, FOLDERID idServer, LPSTR *ppszGroups, BOOL fPoster) { int iret; HRESULT hr; FOLDERID idAcct; FOLDERINFO info; char szAcct[CCHMAX_ACCOUNT_NAME]; Assert(ppszGroups != NULL); m_pGrpList = new CGroupList; if (m_pGrpList == NULL) return(FALSE); m_ppszGroups = ppszGroups; m_fPoster = fPoster; hr = g_pStore->GetFolderInfo(idServer, &info); if (FAILED(hr)) return(FALSE); StrCpyN(szAcct, info.pszName, ARRAYSIZE(szAcct)); g_pStore->FreeRecord(&info); m_pszAcct = szAcct; m_idAcct = idServer; // Now create the dialog. iret = (int) DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddPickGroup), hwndOwner, PickGrpDlgProc, (LPARAM)this); return(iret == IDOK); } INT_PTR CALLBACK CPickGroupDlg::PickGrpDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL fRet; CPickGroupDlg *pThis; fRet = TRUE; pThis = (CPickGroupDlg *)GetWindowLongPtr(hwnd, DWLP_USER); switch (msg) { case WM_INITDIALOG: Assert(pThis == NULL); Assert(lParam != NULL); pThis = (CPickGroupDlg *)lParam; SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)pThis); fRet = pThis->_OnInitDialog(hwnd); break; case WM_CLOSE: pThis->_OnClose(hwnd); break; case WM_COMMAND: pThis->_OnCommand(hwnd, LOWORD(wParam), (HWND)lParam, HIWORD(wParam)); break; case WM_NOTIFY: pThis->_OnNotify(hwnd, (int)wParam, (LPNMHDR)lParam); break; case WM_TIMER: pThis->_OnTimer(hwnd, (UINT)wParam); break; case WM_PAINT: pThis->_OnPaint(hwnd); break; case NVM_CHANGESERVERS: pThis->_OnChangeServers(hwnd); break; default: fRet = FALSE; break; } return(fRet); } // // FUNCTION: CPickGroupDlg::OnInitDialog() // // PURPOSE: Handles initializing the PickGroup dialog. Initializes the // dependant classes, list view, buttons, etc. // // PARAMETERS: // hwnd - Handle of the dialog box. // hwndFocus - Handle of the control that will get focus if TRUE is returned. // lParam - Contains a pointer to a string of newsgroups the user has // already selected. // // RETURN VALUE: // Returns TRUE to set the focus to hwndFocus, or FALSE otherwise. // BOOL CPickGroupDlg::_OnInitDialog(HWND hwnd) { char szTitle[256]; LV_COLUMN lvc; RECT rc; LONG cx; HDC hdc; TEXTMETRIC tm; HIMAGELIST himl; HRESULT hr; HWND hwndList; CColumns *pColumns; m_hwnd = hwnd; m_hwndPostTo = GetDlgItem(hwnd, idcPostTo); hwndList = GetDlgItem(hwnd, idcGroupList); pColumns = new CColumns; if (pColumns == NULL) { EndDialog(hwnd, IDCANCEL); return(FALSE); } pColumns->Initialize(hwndList, COLUMN_SET_PICKGRP); pColumns->ApplyColumns(COLUMN_LOAD_DEFAULT, 0, 0); Assert(m_pGrpList != NULL); hr = m_pGrpList->Initialize((IGroupListAdvise *)this, pColumns, hwndList, FOLDER_NEWS); Assert(SUCCEEDED(hr)); pColumns->Release(); // Bug #21471 - Add the server name to the dialog box title GetWindowText(hwnd, szTitle, ARRAYSIZE(szTitle)); Assert(m_pszAcct); StrCatBuff(szTitle, m_pszAcct, ARRAYSIZE(szTitle)); SetWindowText(hwnd, szTitle); GetClientRect(m_hwndPostTo, &rc); // Set the image lists for the listview himl = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbFolders), 16, 0, RGB(255, 0, 255)); Assert(himl); // Group name column lvc.mask = LVCF_SUBITEM | LVCF_WIDTH; lvc.cx = rc.right; lvc.iSubItem = 0; ListView_InsertColumn(m_hwndPostTo, 0, &lvc); // Make the second listview have images too ListView_SetImageList(m_hwndPostTo, himl, LVSIL_SMALL); hdc = GetDC(hwndList); if (GetTextMetrics(hdc, &tm)) { cx = tm.tmAveCharWidth * 150; ListView_SetColumnWidth(hwndList, 0, cx); ListView_SetColumnWidth(m_hwndPostTo, 0, cx); } ReleaseDC(hwndList, hdc); SendDlgItemMessage(hwnd, idcShowFavorites, BM_SETCHECK, TRUE, 0L); if (!m_fPoster) ShowWindow(GetDlgItem(hwnd, idcEmailAuthor), SW_HIDE); m_hIcon = (HICON)LoadImage(g_hLocRes, MAKEINTRESOURCE(idiNewsGroup), IMAGE_ICON, 16, 16, 0); SendDlgItemMessage(hwnd, idcShowFavorites, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_hIcon); PostMessage(hwnd, NVM_CHANGESERVERS, 0, 0L); return(FALSE); } BOOL CPickGroupDlg::_OnFilter(HWND hwnd) { UINT cch; LPSTR pszText; HRESULT hr; BOOL fSub; HWND hwndEdit; pszText = NULL; hwndEdit = GetDlgItem(hwnd, idcFindText); cch = GetWindowTextLength(hwndEdit); if (cch > 0) { cch++; if (!MemAlloc((void **)&pszText, cch + 1)) return(FALSE); GetWindowText(hwndEdit, pszText, cch); } fSub = (IsDlgButtonChecked(hwnd, idcShowFavorites)); hr = m_pGrpList->Filter(pszText, fSub ? SUB_TAB_SUBSCRIBED : SUB_TAB_ALL, FALSE); Assert(SUCCEEDED(hr)); if (pszText != NULL) MemFree(pszText); return(TRUE); } void CPickGroupDlg::_OnChangeServers(HWND hwnd) { LPSTR pszTok, pszToken; UINT index; HRESULT hr; FOLDERINFO Folder; // TODO: we need to fix the initialization so the filtering is only performed // once (we should call IGroupList::Filter once and then IGroupList::SetServer once // during creation of the dialog) UpdateWindow(hwnd); _OnFilter(hwnd); hr = m_pGrpList->SetServer(m_idAcct); Assert(SUCCEEDED(hr)); if (m_ppszGroups) { pszTok = *m_ppszGroups; pszToken = StrTokEx(&pszTok, c_szDelimiters); while (pszToken != NULL) { if (m_fPoster && 0 == lstrcmpi(pszToken, c_szPosterKeyword)) CheckDlgButton(hwnd, idcEmailAuthor, TRUE); ZeroMemory(&Folder, sizeof(FOLDERINFO)); Folder.idParent = m_idAcct; Folder.pszName = pszToken; if (DB_S_FOUND == g_pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL)) { _InsertList(Folder.idFolder); g_pStore->FreeRecord(&Folder); } pszToken = StrTokEx(&pszTok, c_szDelimiters); } MemFree(*m_ppszGroups); *m_ppszGroups = 0; } // Bug #17674 - Make sure the post-to listview has an initial selection. ListView_SetItemState(m_hwndPostTo, 0, LVIS_SELECTED, LVIS_SELECTED); _UpdateStateUI(hwnd); } // // FUNCTION: CPickGroupDlg::OnCommand() // // PURPOSE: Processes the WM_COMMAND messages for the pick group dialog. // // PARAMETERS: // hwnd - Handle of the dialog window. // id - ID of the control which sent the message. // hwndCtl - Handle of the control sending the message. // codeNotify - Notification code being sent. // void CPickGroupDlg::_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { switch (id) { case idcAddGroup: _AddGroup(); break; case idcRemoveGroup: _RemoveGroup(); break; case IDOK: if (_OnOK(hwnd)) EndDialog(hwnd, IDOK); break; case IDCANCEL: EndDialog(hwnd, IDCANCEL); break; case idcShowFavorites: _OnFilter(hwnd); _UpdateStateUI(hwnd); break; case idcFindText: // This is generated when someone types in the find text edit box. // We set a timer and when that timer expires we assume the user is // done typing and go ahead and perform the query. if (EN_CHANGE == codeNotify) { KillTimer(hwnd, idtFindDelay); SetTimer(hwnd, idtFindDelay, dtFindDelay, NULL); } break; } } HRESULT CPickGroupDlg::ItemUpdate(void) { _UpdateStateUI(m_hwnd); return(S_OK); } HRESULT CPickGroupDlg::ItemActivate(FOLDERID id) { _AddGroup(); return(S_OK); } // // FUNCTION: CPickGroupDlg::OnNotify() // // PURPOSE: Handles notification messages from the group list listview. // // PARAMETERS: // hwnd - Handle of the pick group dialog. // idFrom - ID of the control sending the notification. // pnmhdr - Pointer to the NMHDR struct with the notification info. // // RETURN VALUE: // Dependent on the notification. // LRESULT CPickGroupDlg::_OnNotify(HWND hwnd, int idFrom, LPNMHDR pnmhdr) { HRESULT hr; LRESULT lRes; hr = m_pGrpList->HandleNotify(hwnd, idFrom, pnmhdr, &lRes); if (hr == S_OK) return(lRes); switch (pnmhdr->code) { case NM_DBLCLK: if (pnmhdr->hwndFrom == m_hwndPostTo) _RemoveGroup(); break; case LVN_ITEMCHANGED: _UpdateStateUI(hwnd); break; } return(0); } void CPickGroupDlg::_OnTimer(HWND hwnd, UINT id) { KillTimer(hwnd, id); _OnFilter(hwnd); _UpdateStateUI(hwnd); } void CPickGroupDlg::_OnClose(HWND hwnd) { int iReturn; iReturn = AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaNews), MAKEINTRESOURCEW(idsDoYouWantToSave), 0, MB_YESNOCANCEL | MB_ICONEXCLAMATION ); if (iReturn == IDYES) _OnCommand(hwnd, IDOK, 0, 0); else if (iReturn == IDNO) _OnCommand(hwnd, IDCANCEL, 0, 0); } // // FUNCTION: CPickGroupDlg::OnOK() // // PURPOSE: This function copies the group names from the dialog that // the user has selected and returns them in the pointer the // caller provided. // // RETURN VALUE: // Returns TRUE if the copy was successful, or FALSE otherwise. // // COMMENTS: // Note - 1000 characters is a good maximum line length (specified by the // Son-of-RFC 1036 doc) so we limit the number of groups based on // this line limit. // // BOOL CPickGroupDlg::_OnOK(HWND hwnd) { // OK, we've got the entire sorted list. Create a string with all the groups // and put it in the edit control. char szGroups[c_cchLineMax], szGroup[256]; int cGroups; LPSTR psz; LV_ITEM lvi; int cchGroups = 0, cch; szGroups[0] = 0; if (m_fPoster && IsDlgButtonChecked(hwnd, idcEmailAuthor)) { StrCatBuff(szGroups, c_szPosterKeyword, ARRAYSIZE(szGroups)); cchGroups += lstrlen(c_szPosterKeyword); } if (cGroups = ListView_GetItemCount(m_hwndPostTo)) { lvi.mask = LVIF_TEXT; lvi.iSubItem = 0; lvi.pszText = szGroup; lvi.cchTextMax = ARRAYSIZE(szGroup); for (lvi.iItem = 0; lvi.iItem < cGroups; lvi.iItem++) { // Get the item ListView_GetItem(m_hwndPostTo, &lvi); // Make sure the length of this next group doesn't push us over // the max line length. cch = lstrlen(lvi.pszText); if ((cch + cchGroups + 2) > c_cchLineMax) { // Bug #24156 - If we have to truncate, then let the user know. AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaNews), MAKEINTRESOURCEW(idsErrNewsgroupLineTooLong), 0, MB_OK | MB_ICONINFORMATION); return (FALSE); } if (cchGroups) { StrCatBuff(szGroups, ", ", ARRAYSIZE(szGroups)); } StrCatBuff(szGroups, lvi.pszText, ARRAYSIZE(szGroups)); cchGroups += (cch + 2); } } // Now that we're done building this marvelous string, copy it to // the buffer for returning. if (!MemAlloc((LPVOID *)&psz, cchGroups + 1)) return(FALSE); StrCpyN(psz, szGroups, cchGroups + 1); *m_ppszGroups = psz; return(TRUE); } // // FUNCTION: CPickGroupDlg::AddGroup() // // PURPOSE: Takes the group names selected in the ListView and adds them // to the selected groups Post To list. // void CPickGroupDlg::_AddGroup(void) { FOLDERID *pid; DWORD cid, i; HCURSOR hcur; HRESULT hr; hcur = SetCursor(LoadCursor(NULL, IDC_WAIT)); SetWindowRedraw(m_hwndPostTo, FALSE); hr = m_pGrpList->GetSelectedCount(&cid); if (SUCCEEDED(hr) && cid > 0) { if (MemAlloc((void **)&pid, cid * sizeof(FOLDERID))) { hr = m_pGrpList->GetSelected(pid, &cid); if (SUCCEEDED(hr)) { for (i = 0; i < cid; i++) { _InsertList(pid[i]); } } MemFree(pid); } } if (-1 == ListView_GetNextItem(m_hwndPostTo, -1, LVNI_ALL | LVNI_SELECTED)) ListView_SetItemState(m_hwndPostTo, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); SetWindowRedraw(m_hwndPostTo, TRUE); InvalidateRect(m_hwndPostTo, NULL, TRUE); SetCursor(hcur); } // // FUNCTION: CPickGroupDlg::InsertList() // // PURPOSE: Given a index into the CGroupList's newsgroup list, that group // is inserted into the Post To list. // // PARAMETERS: // index - Index of a newsgroup in the CGroupList newsgroup list. // void CPickGroupDlg::_InsertList(FOLDERID id) { LV_ITEM lvi; int count; FOLDERINFO info; HRESULT hr; count = ListView_GetItemCount(m_hwndPostTo); // First make sure this isn't a duplicate. lvi.mask = LVIF_PARAM; lvi.iSubItem = 0; for (lvi.iItem = 0; lvi.iItem < count; lvi.iItem++) { ListView_GetItem(m_hwndPostTo, &lvi); if (id == (FOLDERID)lvi.lParam) return; } hr = g_pStore->GetFolderInfo(id, &info); if (SUCCEEDED(hr)) { lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.iItem = 0; lvi.iSubItem = 0; lvi.pszText = info.pszName; if (!!(info.dwFlags & FOLDER_SUBSCRIBED)) { lvi.iImage = iNewsGroup; lvi.mask |= LVIF_IMAGE; } lvi.lParam = (LPARAM)id; ListView_InsertItem(m_hwndPostTo, &lvi); g_pStore->FreeRecord(&info); } } void CPickGroupDlg::_RemoveGroup(void) { int index, count, iItemFocus; HCURSOR hcur; hcur = SetCursor(LoadCursor(NULL, IDC_WAIT)); SetWindowRedraw(m_hwndPostTo, FALSE); count = ListView_GetItemCount(m_hwndPostTo); iItemFocus = ListView_GetNextItem(m_hwndPostTo, -1, LVNI_FOCUSED); // Loop through all the selected items and remove them from the ListView for (index = count; index >= 0; index--) { if (ListView_GetItemState(m_hwndPostTo, index, LVIS_SELECTED)) ListView_DeleteItem(m_hwndPostTo, index); } // Bug #22189 - Make sure the focus/selection goes somewhere after we delete. iItemFocus--; if (iItemFocus < 0 || ListView_GetItemCount(m_hwndPostTo) < iItemFocus) iItemFocus = 0; ListView_SetItemState(m_hwndPostTo, iItemFocus, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); SetWindowRedraw(m_hwndPostTo, TRUE); InvalidateRect(m_hwndPostTo, NULL, TRUE); SetCursor(hcur); } void CPickGroupDlg::_UpdateStateUI(HWND hwnd) { DWORD cid; HRESULT hr; hr = m_pGrpList->GetSelectedCount(&cid); if (FAILED(hr)) return; EnableWindow(GetDlgItem(hwnd, idcAddGroup), cid > 0); EnableWindow(GetDlgItem(hwnd, idcRemoveGroup), ListView_GetSelectedCount(m_hwndPostTo)); } void CPickGroupDlg::_OnPaint(HWND hwnd) { RECT rc; HDC hdc; PAINTSTRUCT ps; HFONT hf; char szBuffer[CCHMAX_STRINGRES]; hdc = BeginPaint(hwnd, &ps); // Only do this if the button is available if (IsWindow(GetDlgItem(hwnd, idcShowFavorites))) { // Get the position of the toggle button GetClientRect(GetDlgItem(hwnd, idcShowFavorites), &rc); MapWindowPoints(GetDlgItem(hwnd, idcShowFavorites), hwnd, (LPPOINT) &rc, 1); rc.left += (rc.right + 4); rc.right = rc.left + 300; rc.top += 1; rc.bottom += rc.top; AthLoadString(idsShowFavorites, szBuffer, ARRAYSIZE(szBuffer)); hf = (HFONT) SelectObject(hdc, (HFONT) SendMessage(hwnd, WM_GETFONT, 0, 0)); SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); DrawText(hdc, szBuffer, lstrlen(szBuffer), &rc, DT_SINGLELINE | DT_VCENTER | DT_NOCLIP); SelectObject(hdc, hf); } EndPaint(hwnd, &ps); }