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.
 
 
 
 
 
 

1132 lines
35 KiB

/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1993-1996 Microsoft Corporation. All Rights Reserved.
//
// MODULE: GrpDlg.cpp
//
// PURPOSE: Implements the CGroupListDlg class.
//
#include "pch.hxx"
#include <iert.h>
#include <instance.h>
#include "subscr.h"
#include "resource.h"
#include "strconst.h"
#include "thormsgs.h"
#include "goptions.h"
#include "mailnews.h"
#include "shlwapip.h"
#include "imnact.h"
#include "error.h"
#include "acctutil.h"
#include <ras.h>
#include "imagelst.h"
#include "conman.h"
#include "xpcomm.h"
#include <storutil.h>
#include "demand.h"
#include "menures.h"
#include "storecb.h"
UINT g_rgCtlMap[] = { idcFindText, idcUseDesc, idcGroupList, idcSubscribe,
idcUnsubscribe, idcResetList, idcGoto, IDOK, IDCANCEL, idcServers, idcStaticNewsServers,
idcStaticHorzLine, idcTabs};
const static HELPMAP g_rgCtxMapGrpDlg[] = {
{idcFindText, IDH_NEWS_SEARCH_GROUPS_CONTAINING},
{idcDispText, IDH_NEWS_SEARCH_GROUPS_CONTAINING},
{idcUseDesc, IDH_NEWS_SEARCH_GROUPS_DESC},
{idcGroupList, IDH_NEWS_GROUP_LISTS},
{idcSubscribe, IDH_NEWS_ADD_SELECTED_GROUP},
{idcUnsubscribe, IDH_NEWS_REMOVE_SELECTED_GROUP},
{idcResetList, IDH_NEWS_RESET_NEW_LIST},
{idcGoto, IDH_NEWS_OPEN_SELECTED_GROUP},
{idcServers, IDH_NEWS_SERVER_LIST},
{idcStaticNewsServers, IDH_NEWS_SERVER_LIST},
{idcTabs, IDH_NEWSGROUP_LIST_ALL},
{0, 0}
};
const static HELPMAP g_rgCtxMapGrpDlgIMAP[] = {
{idcFindText, 50505},
{idcDispText, 50505},
{idcGroupList, 50510},
{idcSubscribe, 50520},
{idcUnsubscribe, 50525},
{idcResetList, 50530},
{idcGoto, 50515},
{idcServers, 50500},
{idcStaticNewsServers, 50500},
{0, 0}
};
HRESULT DoSubscriptionDialog(HWND hwnd, BOOL fNews, FOLDERID idFolder, BOOL fShowNew)
{
CGroupListDlg *pDlg;
FOLDERID id, idDefault;
FOLDERINFO info;
HRESULT hr;
FOLDERTYPE type;
#ifdef DEBUG
if (fShowNew)
Assert(fNews);
#endif // DEBUG
type = fNews ? FOLDER_NEWS : FOLDER_IMAP;
pDlg = new CGroupListDlg;
if (pDlg == NULL)
return(E_OUTOFMEMORY);
if (idFolder == FOLDERID_ROOT)
{
idFolder = FOLDERID_INVALID;
}
else if (idFolder != FOLDERID_INVALID)
{
hr = GetFolderStoreInfo(idFolder, &info);
if (SUCCEEDED(hr))
{
if (type == info.tyFolder)
idFolder = info.idFolder;
else
idFolder = FOLDERID_INVALID;
g_pStore->FreeRecord(&info);
}
else
{
idFolder = FOLDERID_INVALID;
}
}
if (idFolder == FOLDERID_INVALID)
{
hr = GetDefaultServerId(fNews ? ACCT_NEWS : ACCT_MAIL, &idDefault);
if (SUCCEEDED(hr))
{
hr = g_pStore->GetFolderInfo(idDefault, &info);
if (SUCCEEDED(hr))
{
if (type == info.tyFolder)
idFolder = idDefault;
g_pStore->FreeRecord(&info);
}
}
if (FAILED(hr))
{
pDlg->Release();
return(hr);
}
}
if (pDlg->FCreate(hwnd, type, &id, fShowNew ? 2 : 0, TRUE, idFolder))
{
if (id != FOLDERID_INVALID)
g_pInstance->BrowseToObject(SW_SHOWNORMAL, id);
}
pDlg->Release();
return(S_OK);
}
CGroupListDlg::CGroupListDlg()
{
m_cRef = 1;
// m_hwnd
// m_hwndFindText
// m_hwndOwner
m_fAllowDesc = TRUE;
m_pszPrevQuery = 0;
m_cchPrevQuery = 0;
m_cxHorzSep = 0;
m_cyVertSep = 0;
m_rgst = 0;
m_sizeDlg.cx = 0;
m_sizeDlg.cy = 0;
m_ptDragMin.x = 0;
m_ptDragMin.y = 0;
m_himlServer = NULL;
m_pGrpList = NULL;
// m_type
// m_iTabSelect
// m_idSel
m_idGoto = FOLDERID_INVALID;
// m_fEnableGoto
m_fServerListInited = FALSE;
m_idCurrent = FOLDERID_INVALID;
m_hIcon = NULL;
m_pColumns = NULL;
}
CGroupListDlg::~CGroupListDlg()
{
SafeMemFree(m_pszPrevQuery);
SafeMemFree(m_rgst);
if (m_pColumns != NULL)
m_pColumns->Release();
if (m_pGrpList != NULL)
m_pGrpList->Release();
if (m_hIcon)
SideAssert(DestroyIcon(m_hIcon));
if (m_himlServer != NULL)
ImageList_Destroy(m_himlServer);
}
HRESULT STDMETHODCALLTYPE CGroupListDlg::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 CGroupListDlg::AddRef()
{
return ++m_cRef;
}
ULONG STDMETHODCALLTYPE CGroupListDlg::Release()
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
//
// FUNCTION: CGroupListDlg::FCreate()
//
// PURPOSE: Handles initialization of the data and creation of the
// Newsgroups dialog.
//
BOOL CGroupListDlg::FCreate(HWND hwndOwner, FOLDERTYPE type, FOLDERID *pGotoId,
UINT iTabSelect, BOOL fEnableGoto, FOLDERID idSel)
{
MSG msg;
HWND hwndDlg;
UINT idd;
HRESULT hr;
Assert(pGotoId != NULL);
m_hwndOwner = hwndOwner;
Assert(type == FOLDER_IMAP || type == FOLDER_NEWS);
m_type = type;
m_iTabSelect = iTabSelect;
m_fEnableGoto = fEnableGoto;
m_idSel = idSel;
m_pGrpList = new CGroupList;
if (m_pGrpList == NULL)
return(FALSE);
idd = type == FOLDER_NEWS ? iddSubscribe : iddSubscribeImap;
if (GetParent(m_hwndOwner))
{
while (GetParent(m_hwndOwner))
m_hwndOwner = GetParent(m_hwndOwner);
}
// Fake this modeless dialog into behaving like a modal dialog
EnableWindow(m_hwndOwner, FALSE);
hwndDlg = CreateDialogParam(g_hLocRes, MAKEINTRESOURCE(idd), hwndOwner,
GroupListDlgProc, (LPARAM) this);
ShowWindow(hwndDlg, SW_SHOW);
while (GetMessage(&msg, NULL, 0, 0))
{
if (IsGrpDialogMessage(msg.hwnd, &msg))
continue;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (IsWindow(m_hwnd))
{
// GetMessage returned FALSE (WM_QUIT), but we still exist. This
// means someone else posted the WM_QUIT, so we should close and
// put the WM_QUIT back in the queue
SendMessage(m_hwnd, WM_COMMAND, IDCANCEL, 0L);
PostQuitMessage((int)(msg.wParam)); // repost quit for next enclosing loop
}
EnableWindow(m_hwndOwner, TRUE);
*pGotoId = m_idGoto;
return(TRUE);
}
//
// FUNCTION: CGroupListDlg::IsGrpDialogMessage()
//
// PURPOSE: Because there are people who think that because we have a tab
// control on this dialog it should behave like a property sheet,
// we need to fake the dialog modeless and filter our own
// keystrokes. I've stolen this function from the comctl32 sources
// so if we get any bugs saying the behavior isn't the same the
// person is full of it.
//
// PARAMETERS:
// hwnd - Handle of the window to check the messages for.
// pMsg - Message to check.
//
// RETURN VALUE:
// Returns TRUE if the message was dispatched, FALSE otherwise.
//
BOOL CGroupListDlg::IsGrpDialogMessage(HWND hwnd, LPMSG pMsg)
{
if ((pMsg->message == WM_KEYDOWN) && (GetAsyncKeyState(VK_CONTROL) < 0))
{
BOOL bBack = FALSE;
switch (pMsg->wParam)
{
case VK_TAB:
bBack = GetAsyncKeyState(VK_SHIFT) < 0;
break;
case VK_PRIOR: // VK_PAGE_UP
case VK_NEXT: // VK_PAGE_DOWN
bBack = (pMsg->wParam == VK_PRIOR);
break;
default:
goto NoKeys;
}
int iCur = TabCtrl_GetCurSel(GetDlgItem(m_hwnd, idcTabs));
// tab in reverse if shift is down
if (bBack)
iCur += (iTabMax - 1);
else
iCur++;
iCur %= iTabMax;
TabCtrl_SetCurSel(GetDlgItem(m_hwnd, idcTabs), iCur);
OnSwitchTabs(hwnd, iCur);
return TRUE;
}
NoKeys:
if (IsWindow(m_hwnd) && IsDialogMessage(m_hwnd, pMsg))
return TRUE;
return (FALSE);
}
INT_PTR CALLBACK CGroupListDlg::GroupListDlgProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
CGroupListDlg* pThis = 0;
pThis = (CGroupListDlg*) GetWindowLongPtr(hwnd, DWLP_USER);
LRESULT lResult;
// Bug #16910 - For some reason we get messages before we set the this
// pointer into the window extra bytes. If this happens
// we should blow the message off.
if (uMsg != WM_INITDIALOG && 0 == pThis)
{
return (FALSE);
}
switch (uMsg)
{
case WM_INITDIALOG:
// Stash the this pointer so we can use it for all the messages.
SetWindowLongPtr(hwnd, DWLP_USER, lParam);
pThis = (CGroupListDlg*) lParam;
return (BOOL)HANDLE_WM_INITDIALOG(hwnd, wParam, lParam,
pThis->OnInitDialog);
case WM_HELP:
case WM_CONTEXTMENU:
return OnContextHelp(hwnd, uMsg, wParam, lParam, (pThis->m_type == FOLDER_IMAP) ? g_rgCtxMapGrpDlgIMAP : g_rgCtxMapGrpDlg);
case WM_COMMAND:
Assert(pThis);
HANDLE_WM_COMMAND(hwnd, wParam, lParam, pThis->OnCommand);
return (TRUE);
case WM_NOTIFY:
Assert(pThis);
lResult = HANDLE_WM_NOTIFY(hwnd, wParam, lParam, pThis->OnNotify);
SetDlgMsgResult(hwnd, WM_NOTIFY, lResult);
return (TRUE);
case WM_TIMER:
Assert(pThis);
HANDLE_WM_TIMER(hwnd, wParam, lParam, pThis->OnTimer);
return (TRUE);
case WM_PAINT:
Assert(pThis);
HANDLE_WM_PAINT(hwnd, wParam, lParam, pThis->OnPaint);
return (FALSE);
case WM_SIZE:
Assert(pThis);
HANDLE_WM_SIZE(hwnd, wParam, lParam, pThis->OnSize);
return (TRUE);
case WM_GETMINMAXINFO:
Assert(pThis);
HANDLE_WM_GETMINMAXINFO(hwnd, wParam, lParam, pThis->OnGetMinMaxInfo);
break;
case WM_CLOSE:
Assert(pThis);
HANDLE_WM_CLOSE(hwnd, wParam, lParam, pThis->OnClose);
return (TRUE);
case WM_DESTROY:
Assert(pThis);
HANDLE_WM_DESTROY(hwnd, wParam, lParam, pThis->OnDestroy);
return (TRUE);
case WM_NCHITTEST:
{
POINT pt = { LOWORD(lParam), HIWORD(lParam) };
RECT rc;
GetWindowRect(hwnd, &rc);
rc.left = rc.right - GetSystemMetrics(SM_CXSMICON);
rc.top = rc.bottom - GetSystemMetrics(SM_CYSMICON);
if (PtInRect(&rc, pt))
{
SetDlgMsgResult(hwnd, WM_NCHITTEST, HTBOTTOMRIGHT);
return (TRUE);
}
else
return (FALSE);
}
case NVM_CHANGESERVERS:
pThis->OnChangeServers(hwnd);
return (TRUE);
}
return (FALSE);
}
static const UINT c_rgNewsSubTab[] =
{
idsTabAll, idsTabSubscribed, idsTabNew
};
static const UINT c_rgImapSubTab[] =
{
idsTabAll, idsTabVisible
};
BOOL CGroupListDlg::OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
HRESULT hr;
HWND hwndT, hwndList;
WINDOWPLACEMENT wp;
TC_ITEM tci;
RECT rcDlg;
UINT i, cTab, *pTab;
char sz[CCHMAX_STRINGRES];
COLUMN_SET_TYPE set;
// It's handy to have these handles available
m_hwnd = hwnd;
m_hwndFindText = GetDlgItem(hwnd, idcFindText);
SetIntlFont(m_hwndFindText);
// Add some tabs to our tab control.
hwndT = GetDlgItem(hwnd, idcTabs);
Assert(IsWindow(hwndT));
if (m_type == FOLDER_NEWS)
{
set = COLUMN_SET_NEWS_SUB;
pTab = (UINT *)c_rgNewsSubTab;
cTab = ARRAYSIZE(c_rgNewsSubTab);
}
else
{
set = COLUMN_SET_IMAP_SUB;
pTab = (UINT *)c_rgImapSubTab;
cTab = ARRAYSIZE(c_rgImapSubTab);
}
tci.mask = TCIF_TEXT;
tci.pszText = sz;
for (i = 0; i < cTab; i++)
{
AthLoadString(*pTab, sz, ARRAYSIZE(sz));
TabCtrl_InsertItem(hwndT, i, &tci);
pTab++;
}
hwndList = GetDlgItem(hwnd, idcGroupList);
m_pColumns = new CColumns;
if (m_pColumns == NULL)
{
EnableWindow(m_hwndOwner, TRUE);
DestroyWindow(m_hwnd);
return (FALSE);
}
m_pColumns->Initialize(hwndList, set);
m_pColumns->ApplyColumns(COLUMN_LOAD_REGISTRY, 0, 0);
// Initialize the extended styles so we get full row select. Just because
// it looks better.
ListView_SetExtendedListViewStyle(hwndList, LVS_EX_FULLROWSELECT);
Assert(m_pGrpList != NULL);
hr = m_pGrpList->Initialize((IGroupListAdvise *)this, m_pColumns, hwndList, m_type);
Assert(SUCCEEDED(hr));
// Add the list of servers to the list view if and only if there is more
// than one server.
hwndT = GetDlgItem(hwnd, idcServers);
FillServerList(hwndT, m_idSel);
// Build the control map array.
if (!MemAlloc((LPVOID*) &m_rgst, sizeof(SIZETABLE) * iCtlMax))
{
EnableWindow(m_hwndOwner, TRUE);
DestroyWindow(m_hwnd);
return (FALSE);
}
ZeroMemory(m_rgst, sizeof(SIZETABLE) * iCtlMax);
// Build a table of the controls on this dialog
for (i = 0; i < iCtlMax; i++)
{
m_rgst[i].hwndCtl = GetDlgItem(hwnd, g_rgCtlMap[i]);
if (m_rgst[i].hwndCtl)
{
m_rgst[i].id = g_rgCtlMap[i];
GetWindowRect(m_rgst[i].hwndCtl, &m_rgst[i].rc);
MapWindowPoints(GetDesktopWindow(), hwnd, (LPPOINT) &m_rgst[i].rc, 2);
}
}
GetWindowRect(hwnd, &rcDlg);
m_ptDragMin.x = rcDlg.right - rcDlg.left;
m_ptDragMin.y = rcDlg.bottom - rcDlg.top;
// Get the distance from the button to the edge of the dialog
GetClientRect(hwnd, &rcDlg);
m_cxHorzSep = rcDlg.right - m_rgst[iCtlCancel].rc.right;
// Get the distance from the "OK" to the "Cancel" button
m_cyVertSep = m_rgst[iCtlCancel].rc.left - m_rgst[iCtlOK].rc.right;
// Position the dialog
wp.length = sizeof(WINDOWPLACEMENT);
if (GetOption(OPT_NEWSDLGPOS, (LPVOID) &wp, sizeof(WINDOWPLACEMENT)))
{
SetWindowPlacement(hwnd, &wp);
// Bug #19258 - If SetWindowPlacement() doesn't actually resize the dialog,
// then a WM_SIZE doesn't happen automatically. We check for
// this now and force the message if this is the case.
GetWindowRect(hwnd, &rcDlg);
if (wp.rcNormalPosition.right == rcDlg.right &&
wp.rcNormalPosition.bottom == rcDlg.bottom)
{
GetClientRect(hwnd, &rcDlg);
SendMessage(hwnd, WM_SIZE, SIZE_RESTORED, MAKELPARAM(rcDlg.right, rcDlg.bottom));
}
}
else
{
CenterDialog(hwnd);
SendMessage(hwnd, WM_SIZE, SIZE_RESTORED, MAKELPARAM(rcDlg.right, rcDlg.bottom));
}
// If the view didn't invoke this dialog, than Goto has no meaning. Hide
// the button if this is the case.
if (!m_fEnableGoto)
ShowWindow(GetDlgItem(hwnd, idcGoto), SW_HIDE);
// Bug 23685: give it the right icon
m_hIcon= (HICON)LoadImage(g_hLocRes, m_type == FOLDER_NEWS ? MAKEINTRESOURCE(idiNewsGroup) : MAKEINTRESOURCE(idiFolder), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
SendMessage(hwnd, WM_SETICON, FALSE, (LPARAM)m_hIcon);
// Initialize the focus
SetFocus(m_hwndFindText);
// Tell ourself to update our group list after the dialog is done
// initializing.
PostMessage(hwnd, NVM_CHANGESERVERS, 0, 0L);
return (FALSE);
}
void CGroupListDlg::OnChangeServers(HWND hwnd)
{
// 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);
TabCtrl_SetCurSel(GetDlgItem(hwnd, idcTabs), m_iTabSelect);
OnSwitchTabs(hwnd, m_iTabSelect);
Assert(m_idCurrent != FOLDERID_INVALID);
ChangeServers(m_idCurrent, TRUE);
}
//
// FUNCTION: CGroupListDlg::OnCommand
//
// PURPOSE: Handles the command messages for the dialog.
//
// PARAMETERS:
// hwnd - Handle of the dialog box.
// id - Command id that needs processing.
// hwndCtl - Handle of the control that generated the command
// codeNotify - Specific notification the control generated
//
void CGroupListDlg::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
HRESULT hr;
FOLDERID fldid;
int iSel;
FOLDERINFO info;
DWORD dw;
BOOL fDesc;
IImnAccount *pAcct;
switch (id)
{
case IDOK:
case IDCANCEL:
if (codeNotify != BN_CLICKED)
break;
hr = S_OK;
if (id == IDOK)
{
hr = m_pGrpList->Commit(hwnd);
Assert(hr != E_PENDING);
if (FAILED(hr))
break;
}
EnableWindow(m_hwndOwner, TRUE);
DestroyWindow(hwnd);
break;
case idcSubscribe:
case idcUnsubscribe:
if (codeNotify != BN_CLICKED)
break;
hr = m_pGrpList->Exec(NULL, id == idcSubscribe ? ID_SUBSCRIBE : ID_UNSUBSCRIBE, 0, NULL, NULL);
Assert(hr == S_OK);
break;
case idcGoto:
if (codeNotify != BN_CLICKED)
break;
hr = m_pGrpList->GetFocused(&fldid);
if (SUCCEEDED(hr))
{
m_idGoto = fldid;
SendMessage(m_hwnd, WM_COMMAND, IDOK, 0);
}
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;
case idcUseDesc:
if (IsDlgButtonChecked(hwnd, idcUseDesc))
{
hr = m_pGrpList->HasDescriptions(&fDesc);
if (SUCCEEDED(hr) && !fDesc)
{
if (IDYES == AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaNews),
MAKEINTRESOURCEW(IDS_NO_DESCRIPTIONS_DOWNLOADED), NULL,
MB_YESNO | MB_ICONEXCLAMATION))
{
// turn on acct desc option
if (SUCCEEDED(g_pStore->GetFolderInfo(m_idCurrent, &info)))
{
if (SUCCEEDED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, info.pszAccountId, &pAcct)))
{
if (SUCCEEDED(pAcct->GetPropDw(AP_NNTP_USE_DESCRIPTIONS, &dw)) && dw == 0)
{
pAcct->SetPropDw(AP_NNTP_USE_DESCRIPTIONS, 1);
pAcct->SaveChanges();
}
pAcct->Release();
}
g_pStore->FreeRecord(&info);
hr = m_pGrpList->Exec(NULL, ID_RESET_LIST, 0, NULL, NULL);
}
}
else
{
SendMessage(hwndCtl, BM_SETCHECK, BST_UNCHECKED, 0);
break;
}
}
}
iSel = TabCtrl_GetCurSel(GetDlgItem(hwnd, idcTabs));
if (iSel != -1)
OnSwitchTabs(hwnd, iSel);
break;
case idcResetList:
hr = m_pGrpList->Exec(NULL, ID_RESET_LIST, 0, NULL, NULL);
break;
}
}
//
// FUNCTION: CGroupListDlg::OnNotify
//
// PURPOSE: Handles notifications from the common controls on the dialog.
//
LRESULT CGroupListDlg::OnNotify(HWND hwnd, int idFrom, LPNMHDR pnmhdr)
{
int iSel;
LRESULT lRes;
HRESULT hr;
NM_LISTVIEW *pnmlv;
hr = m_pGrpList->HandleNotify(hwnd, idFrom, pnmhdr, &lRes);
if (hr == S_OK)
return(lRes);
switch (pnmhdr->code)
{
case TCN_SELCHANGE:
if (idFrom == idcTabs)
{
// Find out which tab is currently active
iSel = TabCtrl_GetCurSel(pnmhdr->hwndFrom);
if (iSel != -1)
OnSwitchTabs(hwnd, iSel);
}
break;
case LVN_ITEMCHANGED:
Assert(idFrom == idcServers);
pnmlv = (NM_LISTVIEW *)pnmhdr;
if (m_fServerListInited &&
!!(pnmlv->uChanged & LVIF_STATE) &&
0 == (pnmlv->uOldState & LVIS_FOCUSED) &&
!!(pnmlv->uNewState & LVIS_FOCUSED))
{
ChangeServers((FOLDERID)pnmlv->lParam, FALSE);
ItemUpdate();
}
break;
}
return (0);
}
void CGroupListDlg::OnClose(HWND hwnd)
{
int iReturn = IDNO;
if (m_pGrpList->Dirty() == S_OK)
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);
}
void CGroupListDlg::OnDestroy(HWND hwnd)
{
// Save the dialog position
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
if (GetWindowPlacement(hwnd, &wp))
SetOption(OPT_NEWSDLGPOS, (LPVOID) &wp, sizeof(WINDOWPLACEMENT), NULL, 0);
Assert(m_pColumns != NULL);
m_pColumns->Save(NULL, NULL);
PostQuitMessage(0);
}
void CGroupListDlg::OnTimer(HWND hwnd, UINT id)
{
DWORD iTab;
KillTimer(hwnd, id);
iTab = TabCtrl_GetCurSel(GetDlgItem(m_hwnd, idcTabs));
OnSwitchTabs(hwnd, iTab);
}
BOOL CGroupListDlg::ChangeServers(FOLDERID id, BOOL fForce)
{
HRESULT hr;
hr = m_pGrpList->SetServer(id);
Assert(SUCCEEDED(hr));
m_idCurrent = id;
ItemUpdate();
return(TRUE);
}
//
// FUNCTION: CGroupListDlg::FillServerList
//
// PURPOSE: If the user has multiple servers configured, then a variant of
// this dialog appears that has a list of servers available. This
// function populates that list.
//
// PARAMETERS:
// hwndList - Handle of the list view that we add server names to.
// pszSelectServer - Name of the server to select in the list view.
//
// RETURN VALUE:
// Returns TRUE if successful, or FALSE otherwise.
//
BOOL CGroupListDlg::FillServerList(HWND hwndList, FOLDERID idSel)
{
HRESULT hr;
FOLDERID id;
char szServer[CCHMAX_ACCOUNT_NAME];
LV_ITEM lvi;
LV_COLUMN lvc;
RECT rc;
DWORD dw;
int iItem, iSelect;
IImnAccount *pAcct;
IImnEnumAccounts *pEnum;
Assert(!m_fServerListInited);
Assert(hwndList != NULL);
Assert(IsWindow(hwndList));
SetIntlFont(hwndList);
// Create the image list and add it to the listview.
Assert(m_himlServer == NULL);
m_himlServer = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbFoldersLarge), 32, 0, RGB(255, 0, 255));
if (m_himlServer == NULL)
return(FALSE);
ListView_SetImageList(hwndList, m_himlServer, LVSIL_NORMAL);
// Add a column to the listview.
GetClientRect(hwndList, &rc);
lvc.mask = LVCF_SUBITEM | LVCF_WIDTH;
lvc.iSubItem = 0;
lvc.cx = rc.right;
dw = ListView_InsertColumn(hwndList, 0, &lvc);
iSelect = -1;
iItem = 0;
if (SUCCEEDED(g_pAcctMan->Enumerate(m_type == FOLDER_NEWS ? SRV_NNTP : SRV_IMAP, &pEnum)))
{
ZeroMemory(&lvi, sizeof(LV_ITEM));
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
lvi.iImage = m_type == FOLDER_NEWS ? iNewsServer : iMailServer;
while (E_EnumFinished != pEnum->GetNext(&pAcct))
{
if (SUCCEEDED(pAcct->GetPropSz(AP_ACCOUNT_ID, szServer, ARRAYSIZE(szServer))) &&
SUCCEEDED(g_pStore->FindServerId(szServer, &id)) &&
SUCCEEDED(pAcct->GetPropSz(AP_ACCOUNT_NAME, szServer, ARRAYSIZE(szServer))))
{
if (idSel == FOLDERID_INVALID ||
id == idSel)
{
Assert(iSelect == -1);
idSel = id;
iSelect = iItem;
lvi.state = LVIS_SELECTED | LVIS_FOCUSED;
lvi.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
}
else
{
lvi.state = 0;
lvi.stateMask = 0;
}
lvi.pszText = szServer;
lvi.iItem = iItem;
lvi.lParam = (LPARAM)id;
dw = ListView_InsertItem(hwndList, &lvi);
iItem++;
}
pAcct->Release();
}
pEnum->Release();
}
Assert(iItem > 0);
Assert(iSelect != -1);
Assert(idSel != FOLDERID_INVALID);
ListView_EnsureVisible(hwndList, iSelect, FALSE);
m_idCurrent = idSel;
m_fServerListInited = TRUE;
return (TRUE);
}
HRESULT CGroupListDlg::ItemUpdate(void)
{
FOLDERID id;
HRESULT hr;
HWND hwndSub, hwndUnsub, hwndFocus;
OLECMD rgCmds[2] = { { ID_SUBSCRIBE, 0 }, { ID_UNSUBSCRIBE, 0 } };
hr = m_pGrpList->GetFocused(&id);
EnableWindow(GetDlgItem(m_hwnd, idcGoto), hr == S_OK);
hr = m_pGrpList->QueryStatus(NULL, ARRAYSIZE(rgCmds), rgCmds, NULL);
if (SUCCEEDED(hr))
{
hwndFocus = GetFocus();
hwndSub = GetDlgItem(m_hwnd, idcSubscribe);
hwndUnsub = GetDlgItem(m_hwnd, idcUnsubscribe);
EnableWindow(hwndSub, !!(rgCmds[0].cmdf & OLECMDF_ENABLED));
EnableWindow(hwndUnsub, !!(rgCmds[1].cmdf & OLECMDF_ENABLED));
if (!IsWindowEnabled(hwndFocus))
SetFocus(!!(rgCmds[0].cmdf & OLECMDF_ENABLED) ? hwndSub : hwndUnsub);
}
return(S_OK);
}
HRESULT CGroupListDlg::ItemActivate(FOLDERID id)
{
m_pGrpList->Exec(NULL, ID_TOGGLE_SUBSCRIBE, 0, NULL, NULL);
return(S_OK);
}
//
// FUNCTION: CGroupListDlg::OnSwitchTabs()
//
// PURPOSE: This function takes care of resetting the list of groups
// appropriately when the user selects a different tab.
//
// PARAMETERS:
// hwnd - Handle of the dialog window.
// iTab - Index of the tab to switch to.
//
// RETURN VALUE:
// Returns TRUE if successful, or FALSE otherwise.
//
BOOL CGroupListDlg::OnSwitchTabs(HWND hwnd, UINT iTab)
{
UINT cch;
LPSTR pszText;
HRESULT hr;
BOOL fUseDesc;
pszText = NULL;
cch = GetWindowTextLength(m_hwndFindText);
if (cch > 0)
{
cch++;
if (!MemAlloc((void **)&pszText, cch + 1))
return(FALSE);
GetWindowText(m_hwndFindText, pszText, cch);
}
fUseDesc = (m_type == FOLDER_NEWS && IsDlgButtonChecked(m_hwnd, idcUseDesc));
hr = m_pGrpList->Filter(pszText, iTab, fUseDesc);
Assert(SUCCEEDED(hr));
if (pszText != NULL)
MemFree(pszText);
return(TRUE);
}
#define WIDTH(_rect) (_rect.right - _rect.left)
#define HEIGHT(_rect) (_rect.bottom - _rect.top)
void CGroupListDlg::OnSize(HWND hwnd, UINT state, int cx, int cy)
{
RECT rc;
rc.left = m_sizeDlg.cx - GetSystemMetrics(SM_CXSMICON);
rc.top = m_sizeDlg.cy - GetSystemMetrics(SM_CYSMICON);
rc.right = m_sizeDlg.cx;
rc.bottom = m_sizeDlg.cy;
InvalidateRect(hwnd, &rc, FALSE);
m_sizeDlg.cx = cx;
m_sizeDlg.cy = cy;
// First move the outside buttons so they are against the edge. These
// buttons only move horizontally.
m_rgst[iCtlSubscribe].rc.left = cx - m_cxHorzSep - WIDTH(m_rgst[iCtlSubscribe].rc);
m_rgst[iCtlSubscribe].rc.right = cx - m_cxHorzSep;
SetWindowPos(m_rgst[iCtlSubscribe].hwndCtl, 0, m_rgst[iCtlSubscribe].rc.left,
m_rgst[iCtlSubscribe].rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
m_rgst[iCtlUnsubscribe].rc.left = cx - m_cxHorzSep - WIDTH(m_rgst[iCtlUnsubscribe].rc);
m_rgst[iCtlUnsubscribe].rc.right = cx - m_cxHorzSep;
SetWindowPos(m_rgst[iCtlUnsubscribe].hwndCtl, 0, m_rgst[iCtlUnsubscribe].rc.left,
m_rgst[iCtlUnsubscribe].rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
m_rgst[iCtlResetList].rc.left = cx - m_cxHorzSep - WIDTH(m_rgst[iCtlResetList].rc);
m_rgst[iCtlResetList].rc.right = cx - m_cxHorzSep;
SetWindowPos(m_rgst[iCtlResetList].hwndCtl, 0, m_rgst[iCtlResetList].rc.left,
m_rgst[iCtlResetList].rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
// The Goto, OK, and Cancel buttons move both horizontally and vertically.
m_rgst[iCtlCancel].rc.left = cx - m_cxHorzSep - WIDTH(m_rgst[iCtlCancel].rc);
m_rgst[iCtlCancel].rc.right = cx - m_cxHorzSep;
m_rgst[iCtlCancel].rc.top = cy - m_cxHorzSep - HEIGHT(m_rgst[iCtlCancel].rc);
m_rgst[iCtlCancel].rc.bottom = cy - m_cxHorzSep;
SetWindowPos(m_rgst[iCtlCancel].hwndCtl, 0, m_rgst[iCtlCancel].rc.left,
m_rgst[iCtlCancel].rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
m_rgst[iCtlOK].rc.left = m_rgst[iCtlCancel].rc.left - m_cxHorzSep - WIDTH(m_rgst[iCtlCancel].rc);
m_rgst[iCtlOK].rc.right = m_rgst[iCtlCancel].rc.left - m_cxHorzSep;
m_rgst[iCtlOK].rc.top = cy - m_cxHorzSep - HEIGHT(m_rgst[iCtlOK].rc);
m_rgst[iCtlOK].rc.bottom = cy - m_cxHorzSep;
SetWindowPos(m_rgst[iCtlOK].hwndCtl, 0, m_rgst[iCtlOK].rc.left,
m_rgst[iCtlOK].rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
m_rgst[iCtlGoto].rc.left = m_rgst[iCtlOK].rc.left - m_cxHorzSep - WIDTH(m_rgst[iCtlGoto].rc);
m_rgst[iCtlGoto].rc.right = m_rgst[iCtlOK].rc.left - m_cxHorzSep;
m_rgst[iCtlGoto].rc.top = cy - m_cxHorzSep - HEIGHT(m_rgst[iCtlGoto].rc);
m_rgst[iCtlGoto].rc.bottom = cy - m_cxHorzSep;
SetWindowPos(m_rgst[iCtlGoto].hwndCtl, 0, m_rgst[iCtlGoto].rc.left,
m_rgst[iCtlGoto].rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
// Update the horizontal static line
m_rgst[iCtlStaticHorzLine].rc.left = m_cxHorzSep;
m_rgst[iCtlStaticHorzLine].rc.right = cx - m_cxHorzSep;
m_rgst[iCtlStaticHorzLine].rc.top = m_rgst[iCtlCancel].rc.top - m_cyVertSep - HEIGHT(m_rgst[iCtlStaticHorzLine].rc);
m_rgst[iCtlStaticHorzLine].rc.bottom = m_rgst[iCtlCancel].rc.top - m_cyVertSep;
SetWindowPos(m_rgst[iCtlStaticHorzLine].hwndCtl, 0, m_rgst[iCtlStaticHorzLine].rc.left,
m_rgst[iCtlStaticHorzLine].rc.top, WIDTH(m_rgst[iCtlStaticHorzLine].rc),
HEIGHT(m_rgst[iCtlStaticHorzLine].rc), SWP_NOZORDER | SWP_NOACTIVATE);
// If we have a server well, then update that and the vertical static line
if (m_rgst[iCtlServers].hwndCtl)
{
m_rgst[iCtlServers].rc.bottom = m_rgst[iCtlStaticHorzLine].rc.top - m_cyVertSep;
SetWindowPos(m_rgst[iCtlServers].hwndCtl, 0, 0, 0, WIDTH(m_rgst[iCtlServers].rc),
HEIGHT(m_rgst[iCtlServers].rc), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
// Finally update the tab control and listview
m_rgst[iCtlTabs].rc.right = m_rgst[iCtlSubscribe].rc.left - m_cxHorzSep;
m_rgst[iCtlTabs].rc.bottom = m_rgst[iCtlStaticHorzLine].rc.top - m_cyVertSep;
SetWindowPos(m_rgst[iCtlTabs].hwndCtl, 0, 0, 0, WIDTH(m_rgst[iCtlTabs].rc),
HEIGHT(m_rgst[iCtlTabs].rc), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
rc = m_rgst[iCtlTabs].rc;
TabCtrl_AdjustRect(m_rgst[iCtlTabs].hwndCtl, FALSE, &rc);
m_rgst[iCtlGroupList].rc.right = rc.right - (m_rgst[iCtlGroupList].rc.left - rc.left);
m_rgst[iCtlGroupList].rc.bottom = rc.bottom - m_cyVertSep; //(m_rgst[iCtlGroupList].rc.top - rc.top);
SetWindowPos(m_rgst[iCtlGroupList].hwndCtl, 0, 0, 0, WIDTH(m_rgst[iCtlGroupList].rc),
HEIGHT(m_rgst[iCtlGroupList].rc), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
rc.top = m_rgst[iCtlGroupList].rc.top;
rc.left = m_rgst[iCtlServers].rc.left;
rc.bottom = cy;
rc.right = cx;
InvalidateRect(hwnd, &rc, TRUE);
}
void CGroupListDlg::OnPaint(HWND hwnd)
{
PAINTSTRUCT ps;
RECT rc;
GetClientRect(hwnd, &rc);
rc.left = rc.right - GetSystemMetrics(SM_CXSMICON);
rc.top = rc.bottom - GetSystemMetrics(SM_CYSMICON);
BeginPaint(hwnd, &ps);
if (!IsZoomed(hwnd))
DrawFrameControl(ps.hdc, &rc, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
EndPaint(hwnd, &ps);
}
void CGroupListDlg::OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpmmi)
{
DefWindowProc(hwnd, WM_GETMINMAXINFO, 0, (LPARAM) lpmmi);
lpmmi->ptMinTrackSize = m_ptDragMin;
}