Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

707 lines
19 KiB

/////////////////////////////////////////////////////////////////////////////
// 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 <iert.h>
#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);
}