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.
2198 lines
62 KiB
2198 lines
62 KiB
/////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 1993-1998 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// MODULE: outbar.cpp
|
|
//
|
|
// PURPOSE: Implements the Outlook Bar
|
|
//
|
|
|
|
#include "pch.hxx"
|
|
#include "resource.h"
|
|
#include "outbar.h"
|
|
#include "goptions.h"
|
|
#include "ourguid.h"
|
|
#include <inpobj.h>
|
|
#include <browser.h>
|
|
#include <notify.h>
|
|
#include <strconst.h>
|
|
#include <thormsgs.h>
|
|
#include <shlwapi.h>
|
|
#include "shlwapip.h"
|
|
#include "storutil.h"
|
|
#include "menures.h"
|
|
#include "menuutil.h"
|
|
#include "dragdrop.h"
|
|
#include "newfldr.h"
|
|
#include "finder.h"
|
|
#include "instance.h"
|
|
|
|
ASSERTDATA
|
|
|
|
#define IDC_FRAME 100
|
|
#define IDC_PAGER 101
|
|
#define IDC_TOOLBAR 102
|
|
|
|
|
|
#define HT_ENTER 1
|
|
#define HT_OVER 2
|
|
#define HT_LEAVE 3
|
|
|
|
// Special HitTest results
|
|
#define IBHT_SOURCE (-32768)
|
|
#define IBHT_BACKGROUND (-32767)
|
|
#define IBHT_PAGER (-32766)
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Prototypes
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT OutlookBar_LoadSettings(BAR_PERSIST_INFO **ppPersist);
|
|
HRESULT OutlookBar_SaveSettings(BAR_PERSIST_INFO *pPersist, DWORD cbData);
|
|
|
|
extern DWORD CUnread(FOLDERINFO *pfi);
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Module Data
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static const TCHAR s_szOutBarWndClass[] = TEXT("Outlook Express Outlook Bar");
|
|
static const TCHAR s_szOutBarFrameClass[] = TEXT("Outlook Express Outlook Bar Frame");
|
|
static const TCHAR c_szOutBarNotifyName[] = TEXT("Outlook Express Outlook Bar Notify");
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Constructors, Destructors, and other initialization stuff
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
COutBar::COutBar()
|
|
{
|
|
m_cRef = 1;
|
|
m_hwndParent = NULL;
|
|
m_hwnd = NULL;
|
|
m_hwndFrame = NULL;
|
|
m_hwndPager = NULL;
|
|
m_hwndTools = NULL;
|
|
m_ptbSite = NULL;
|
|
m_fShow = FALSE;
|
|
m_pBrowser = NULL;
|
|
m_pStNotify = NULL;
|
|
m_idCommand = 0;
|
|
m_fResizing = FALSE;
|
|
m_idSel = -1;
|
|
|
|
// load the width from resource
|
|
m_cxWidth = 70;
|
|
TCHAR szBuffer[64];
|
|
if (AthLoadString(idsMaxOutbarBtnWidth, szBuffer, ARRAYSIZE(szBuffer)))
|
|
{
|
|
m_cxWidth = StrToInt(szBuffer);
|
|
if (m_cxWidth == 0)
|
|
m_cxWidth = 70;
|
|
}
|
|
|
|
m_fLarge = TRUE;
|
|
m_himlLarge = NULL;
|
|
m_himlSmall = NULL;
|
|
m_pOutBarNotify = NULL;
|
|
|
|
m_pDataObject = NULL;
|
|
m_grfKeyState = 0;
|
|
m_dwEffectCur = DROPEFFECT_NONE;
|
|
m_idCur = -1;
|
|
m_pTargetCur = NULL;
|
|
m_idDropHilite = 0;
|
|
m_fInsertMark = FALSE;
|
|
m_fOnce = TRUE;
|
|
}
|
|
|
|
COutBar::~COutBar()
|
|
{
|
|
Assert(NULL == m_pStNotify);
|
|
if (m_hwnd)
|
|
DestroyWindow(m_hwnd);
|
|
|
|
if (m_himlLarge)
|
|
ImageList_Destroy(m_himlLarge);
|
|
|
|
if (m_himlSmall)
|
|
ImageList_Destroy(m_himlSmall);
|
|
|
|
SafeRelease(m_pDataObject);
|
|
}
|
|
|
|
HRESULT COutBar::HrInit(LPSHELLFOLDER psf, IAthenaBrowser *psb)
|
|
{
|
|
HRESULT hr;
|
|
|
|
m_pBrowser = psb;
|
|
|
|
hr = CreateNotify(&m_pStNotify);
|
|
if (FAILED(hr))
|
|
return(hr);
|
|
return m_pStNotify->Initialize((TCHAR *)c_szMailFolderNotify);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IUnknown
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT COutBar::QueryInterface(REFIID riid, LPVOID * ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_IOleWindow) ||
|
|
IsEqualIID(riid, IID_IDockingWindow) ||
|
|
IsEqualIID(riid, IID_IDatabaseNotify))
|
|
{
|
|
*ppvObj = (void*)(IDockingWindow*)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IObjectWithSite))
|
|
{
|
|
*ppvObj = (void*)(IObjectWithSite*)this;
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
ULONG COutBar::AddRef()
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
ULONG COutBar::Release()
|
|
{
|
|
if (--m_cRef == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return m_cRef;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IOleWindow
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
HRESULT COutBar::GetWindow(HWND * lphwnd)
|
|
{
|
|
*lphwnd = m_hwnd;
|
|
return (*lphwnd ? S_OK : E_FAIL);
|
|
}
|
|
|
|
HRESULT COutBar::ContextSensitiveHelp(BOOL fEnterMode)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: COutBar::ShowDW()
|
|
//
|
|
// PURPOSE: Causes the bar to be displayed. If it has not yet been
|
|
// created, we do that here too.
|
|
//
|
|
// PARAMETERS:
|
|
// [in] fShow - TRUE to make the bar visible, FALSE to hide.
|
|
//
|
|
// RETURN VALUE:
|
|
// HRESULT
|
|
//
|
|
HRESULT COutBar::ShowDW(BOOL fShow)
|
|
{
|
|
// Make sure we have a site pointer first
|
|
if (!m_ptbSite)
|
|
{
|
|
AssertSz(0, _T("COutBar::ShowDW() - Can't show without calling SetSite() first."));
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Decide if we need to create a new window or show a currently existing
|
|
// window
|
|
if (!m_hwnd)
|
|
{
|
|
WNDCLASSEX wc;
|
|
|
|
wc.cbSize = sizeof(WNDCLASSEX);
|
|
if (!GetClassInfoEx(g_hInst, s_szOutBarWndClass, &wc))
|
|
{
|
|
// We need to register the outlook bar class
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = COutBar::OutBarWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = g_hInst;
|
|
wc.hCursor = LoadCursor(NULL, IDC_SIZEWE);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = s_szOutBarWndClass;
|
|
wc.hIcon = NULL;
|
|
wc.hIconSm = NULL;
|
|
|
|
if (RegisterClassEx(&wc) == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
|
|
return E_FAIL;
|
|
|
|
// Also need to register the frame class
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.lpfnWndProc = COutBar::ExtFrameWndProc;
|
|
wc.lpszClassName = s_szOutBarFrameClass;
|
|
wc.hbrBackground = (HBRUSH)(COLOR_3DSHADOW + 1);
|
|
|
|
if (RegisterClassEx(&wc) == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Get the handle of the parent window
|
|
if (FAILED(m_ptbSite->GetWindow(&m_hwndParent)))
|
|
return E_FAIL;
|
|
|
|
// Create the window
|
|
m_hwnd = CreateWindowEx(0, s_szOutBarWndClass, NULL, WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
|
0, 0, 0, 0, m_hwndParent, NULL, g_hInst, (LPVOID) this);
|
|
if (!m_hwnd)
|
|
{
|
|
AssertSz(0, _T("COutBar::ShowDW() - Failed to create window."));
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (FAILED(_CreateToolbar()))
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Show or hide the window and resize the parent windows accordingly
|
|
m_fShow = fShow;
|
|
ResizeBorderDW(NULL, NULL, FALSE);
|
|
ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE);
|
|
|
|
// Do notifications
|
|
if (SUCCEEDED(CreateNotify(&m_pOutBarNotify)))
|
|
{
|
|
if (SUCCEEDED(m_pOutBarNotify->Initialize(c_szOutBarNotifyName)))
|
|
{
|
|
m_pOutBarNotify->Register(m_hwnd, g_hwndInit, FALSE);
|
|
}
|
|
}
|
|
|
|
// Drag Drop
|
|
RegisterDragDrop(m_hwndTools, this);
|
|
|
|
g_pStore->RegisterNotify(IINDEX_SUBSCRIBED, REGISTER_NOTIFY_NOADDREF, 0, (IDatabaseNotify *)this);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: COutBar::CloseDW()
|
|
//
|
|
// PURPOSE: Destroys the bar and cleans up.
|
|
//
|
|
HRESULT COutBar::CloseDW(DWORD dwReserved)
|
|
{
|
|
// Save our settings
|
|
_SaveSettings();
|
|
|
|
RevokeDragDrop(m_hwndTools);
|
|
|
|
g_pStore->UnregisterNotify((IDatabaseNotify *) this);
|
|
|
|
// Release
|
|
if (m_pOutBarNotify != NULL)
|
|
{
|
|
if (m_hwnd != NULL)
|
|
m_pOutBarNotify->Unregister(m_hwnd);
|
|
m_pOutBarNotify->Release();
|
|
m_pOutBarNotify = NULL;
|
|
}
|
|
|
|
// Release our notification interface
|
|
if (m_pStNotify != NULL)
|
|
{
|
|
if (m_hwnd != NULL)
|
|
m_pStNotify->Unregister(m_hwnd);
|
|
m_pStNotify->Release();
|
|
m_pStNotify = NULL;
|
|
}
|
|
|
|
// Clean up the toolbar and other child windows
|
|
if (m_hwnd)
|
|
{
|
|
if (m_hwndTools)
|
|
_EmptyToolbar(FALSE);
|
|
DestroyWindow(m_hwnd);
|
|
m_hwnd = NULL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: COutBar::ResizeBorderDW()
|
|
//
|
|
// PURPOSE:
|
|
//
|
|
// PARAMETERS:
|
|
// LPCRECT prcBorder
|
|
// IUnknown *punkToolbarSite
|
|
// BOOL fReserved
|
|
//
|
|
// RETURN VALUE:
|
|
// HRESULT
|
|
//
|
|
HRESULT COutBar::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
|
|
{
|
|
RECT rcRequest = { 0, 0, 0, 0 };
|
|
RECT rcFrame;
|
|
|
|
if (!m_ptbSite)
|
|
{
|
|
AssertSz(0, _T("COutBar::ResizeBorderDW() - Can't resize without calling SetSite() first."));
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (m_fShow)
|
|
{
|
|
RECT rcBorder;
|
|
|
|
if (!prcBorder)
|
|
{
|
|
// Find out how big our parent's border space is
|
|
m_ptbSite->GetBorderDW((IDockingWindow*) this, &rcBorder);
|
|
prcBorder = &rcBorder;
|
|
}
|
|
|
|
// Figure out how much border space to ask the site for
|
|
GetWindowRect(m_hwndFrame, &rcFrame);
|
|
rcFrame.right = min(m_cxWidth - GetSystemMetrics(SM_CXFRAME) + 1,
|
|
prcBorder->right - prcBorder->left);
|
|
rcRequest.left = min(m_cxWidth, prcBorder->right - prcBorder->left - 32);
|
|
|
|
|
|
// Set our new window position
|
|
SetWindowPos(m_hwndFrame, NULL, 0, 0,
|
|
rcFrame.right, prcBorder->bottom - prcBorder->top,
|
|
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
|
|
SetWindowPos(m_hwnd, NULL, prcBorder->left, prcBorder->top,
|
|
rcRequest.left, prcBorder->bottom - prcBorder->top,
|
|
SWP_NOACTIVATE | SWP_NOZORDER);
|
|
}
|
|
|
|
m_ptbSite->SetBorderSpaceDW((IDockingWindow*) this, &rcRequest);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: COutBar::SetSite()
|
|
//
|
|
// PURPOSE: Set's a site pointer for the class
|
|
//
|
|
HRESULT COutBar::SetSite(IUnknown* punkSite)
|
|
{
|
|
// If we already have a site pointer, release it now
|
|
if (m_ptbSite)
|
|
{
|
|
m_ptbSite->Release();
|
|
m_ptbSite = NULL;
|
|
}
|
|
|
|
// If the caller provided a new site interface, get the IDockingWindowSite
|
|
// and keep a pointer to it.
|
|
if (punkSite)
|
|
{
|
|
if (FAILED(punkSite->QueryInterface(IID_IDockingWindowSite, (void **)&m_ptbSite)))
|
|
return E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT COutBar::GetSite(REFIID riid, LPVOID *ppvSite)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//
|
|
// FUNCTION: COutBar::DragEnter()
|
|
//
|
|
// PURPOSE: This get's called when the user starts dragging an object
|
|
// over our target area.
|
|
//
|
|
// PARAMETERS:
|
|
// <in> pDataObject - Pointer to the data object being dragged
|
|
// <in> grfKeyState - Pointer to the current key states
|
|
// <in> pt - Point in screen coordinates of the mouse
|
|
// <out> pdwEffect - Where we return whether this is a valid place for
|
|
// pDataObject to be dropped and if so what type of
|
|
// drop.
|
|
//
|
|
// RETURN VALUE:
|
|
// S_OK - The function succeeded.
|
|
//
|
|
HRESULT STDMETHODCALLTYPE COutBar::DragEnter(IDataObject* pDataObject,
|
|
DWORD grfKeyState,
|
|
POINTL pt, DWORD* pdwEffect)
|
|
{
|
|
FORMATETC fe;
|
|
POINT ptTemp = {pt.x, pt.y};
|
|
|
|
// Initialize our state
|
|
SafeRelease(m_pDataObject);
|
|
|
|
// Hold on to this new object
|
|
m_pDataObject = pDataObject;
|
|
m_pDataObject->AddRef();
|
|
|
|
// The big question here is whether or not this data object is an OE folder
|
|
// or is it something else.
|
|
SETDefFormatEtc(fe, CF_OEFOLDER, TYMED_HGLOBAL);
|
|
m_fDropShortcut = SUCCEEDED(m_pDataObject->QueryGetData(&fe));
|
|
|
|
if (!m_fDropShortcut)
|
|
{
|
|
SETDefFormatEtc(fe, CF_OESHORTCUT, TYMED_HGLOBAL);
|
|
m_fDropShortcut = SUCCEEDED(m_pDataObject->QueryGetData(&fe));
|
|
}
|
|
|
|
if (m_fDropShortcut)
|
|
{
|
|
m_fDropShortcut = _IsTempNewsgroup(m_pDataObject);
|
|
}
|
|
|
|
DOUTL(32, "COutBar::DragEnter() - Data is %s shortcut", m_fDropShortcut ? "a" : "not a");
|
|
|
|
// Hang on to this little gem
|
|
m_grfKeyState = grfKeyState;
|
|
|
|
// Initialize some other stuff
|
|
m_idCur = -1;
|
|
Assert(m_pTargetCur == NULL);
|
|
m_tbim.iButton = -1;
|
|
m_tbim.dwFlags = 0;
|
|
|
|
// Set the default return value here
|
|
m_dwEffectCur = *pdwEffect = DROPEFFECT_NONE;
|
|
|
|
// Update the highlight point
|
|
_UpdateDragDropHilite(&ptTemp);
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
int COutBar::_GetItemFromPoint(POINT pt)
|
|
{
|
|
int iPos;
|
|
TBBUTTON tb;
|
|
|
|
// Figure out which button this is over
|
|
ScreenToClient(m_hwndTools, &pt);
|
|
iPos = ToolBar_HitTest(m_hwndTools, &pt);
|
|
|
|
// If this is over a button, convert that button position to a command
|
|
if (iPos >= 0)
|
|
{
|
|
ToolBar_GetButton(m_hwndTools, iPos, &tb);
|
|
|
|
return (tb.idCommand);
|
|
}
|
|
|
|
return (-1);
|
|
}
|
|
|
|
|
|
void COutBar::_UpdateDragDropHilite(LPPOINT ppt)
|
|
{
|
|
TBINSERTMARK tbim;
|
|
int iPos;
|
|
|
|
// If this is a shortcut we do one thing, if it's anything else we do another
|
|
if (m_fDropShortcut)
|
|
{
|
|
if (m_fInsertMark)
|
|
{
|
|
tbim.iButton = -1;
|
|
tbim.dwFlags = 0;
|
|
ToolBar_SetInsertMark(m_hwndTools, &tbim);
|
|
m_fInsertMark = FALSE;
|
|
}
|
|
|
|
if (ppt)
|
|
{
|
|
ScreenToClient(m_hwndTools, ppt);
|
|
ToolBar_InsertMarkHitTest(m_hwndTools, ppt, &tbim);
|
|
ToolBar_SetInsertMark(m_hwndTools, &tbim);
|
|
m_fInsertMark = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Remove any previous marks
|
|
if (m_idDropHilite)
|
|
{
|
|
ToolBar_MarkButton(m_hwndTools, m_idDropHilite, FALSE);
|
|
m_idDropHilite = 0;
|
|
}
|
|
|
|
// Hilite the new button
|
|
if (ppt)
|
|
{
|
|
// First check to see if we're over a button or in between
|
|
m_idDropHilite = _GetItemFromPoint(*ppt);
|
|
ToolBar_MarkButton(m_hwndTools, m_idDropHilite, TRUE);
|
|
|
|
#ifdef DEBUG
|
|
FOLDERINFO rInfo;
|
|
FOLDERID idFolder;
|
|
|
|
idFolder = _FolderIdFromCmd(m_idDropHilite);
|
|
if (SUCCEEDED(g_pStore->GetFolderInfo(idFolder, &rInfo)))
|
|
{
|
|
DOUTL(32, "COutBar::_UpdateDragDropHilite() - Hiliting %s", rInfo.pszName);
|
|
g_pStore->FreeRecord(&rInfo);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
FOLDERID COutBar::_FolderIdFromCmd(int idCmd)
|
|
{
|
|
TBBUTTON tbb;
|
|
int iPos;
|
|
|
|
iPos = (int) SendMessage(m_hwndTools, TB_COMMANDTOINDEX, idCmd, 0);
|
|
ToolBar_GetButton(m_hwndTools, iPos, &tbb);
|
|
return ((FOLDERID) tbb.dwData);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: COutBar::DragOver()
|
|
//
|
|
// PURPOSE: This is called as the user drags an object over our target.
|
|
// If we allow this object to be dropped on us, then we will have
|
|
// a pointer in m_pDataObject.
|
|
//
|
|
// PARAMETERS:
|
|
// <in> grfKeyState - Pointer to the current key states
|
|
// <in> pt - Point in screen coordinates of the mouse
|
|
// <out> pdwEffect - Where we return whether this is a valid place for
|
|
// pDataObject to be dropped and if so what type of
|
|
// drop.
|
|
//
|
|
// RETURN VALUE:
|
|
// S_OK - The function succeeded.
|
|
//
|
|
HRESULT STDMETHODCALLTYPE COutBar::DragOver(DWORD grfKeyState, POINTL pt,
|
|
DWORD* pdwEffect)
|
|
{
|
|
DWORD idCur;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// If we don't have a data object from DragEnter, bail
|
|
if (NULL == m_pDataObject)
|
|
return (S_OK);
|
|
|
|
// If this is a shortcut we do one thing, if it's anything else we do another
|
|
if (m_fDropShortcut)
|
|
{
|
|
|
|
TBINSERTMARK tbim;
|
|
POINT ptTemp = {pt.x, pt.y};
|
|
ScreenToClient(m_hwndTools, &ptTemp);
|
|
ToolBar_InsertMarkHitTest(m_hwndTools, &ptTemp, &tbim);
|
|
|
|
if (tbim.iButton != m_tbim.iButton || tbim.dwFlags != m_tbim.dwFlags)
|
|
{
|
|
m_tbim = tbim;
|
|
ptTemp.x = pt.x;
|
|
ptTemp.y = pt.y;
|
|
_UpdateDragDropHilite(&ptTemp);
|
|
|
|
}
|
|
|
|
if (DROPEFFECT_LINK & *pdwEffect)
|
|
*pdwEffect = DROPEFFECT_LINK;
|
|
else
|
|
*pdwEffect = DROPEFFECT_MOVE;
|
|
|
|
return (S_OK);
|
|
}
|
|
else
|
|
{
|
|
// Figure out which item we're over
|
|
POINT ptTemp = {pt.x, pt.y};
|
|
if (-1 == (idCur = _GetItemFromPoint(ptTemp)))
|
|
{
|
|
DOUTL(32, "COutBar::DragOver() - _GetItemFromPoint() returns -1.");
|
|
}
|
|
|
|
DOUTL(32, "COutBar::DragOver() - m_idCur = %d, id = %d", m_idCur, idCur);
|
|
|
|
// If we're over a new button, then get the drop target for that button
|
|
if (m_idCur != idCur)
|
|
{
|
|
// Release any previous drop target, if any.
|
|
SafeRelease(m_pTargetCur);
|
|
|
|
// Update our current object marker
|
|
m_idCur = idCur;
|
|
|
|
// Assume error
|
|
m_dwEffectCur = DROPEFFECT_NONE;
|
|
|
|
// Update the UI
|
|
_UpdateDragDropHilite(&ptTemp);
|
|
|
|
// If we're over a button
|
|
if (m_idCur != -1)
|
|
{
|
|
FOLDERID id = _FolderIdFromCmd(m_idCur);
|
|
|
|
// Create the drop target object
|
|
m_pTargetCur = new CDropTarget();
|
|
if (m_pTargetCur)
|
|
{
|
|
hr = m_pTargetCur->Initialize(m_hwnd, id);
|
|
}
|
|
|
|
// If we have an initialized drop target, call DragEnter()
|
|
if (SUCCEEDED(hr) && m_pTargetCur)
|
|
{
|
|
hr = m_pTargetCur->DragEnter(m_pDataObject, grfKeyState, pt, pdwEffect);
|
|
m_dwEffectCur = *pdwEffect;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_dwEffectCur = DROPEFFECT_NONE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No target change, but did the key state change?
|
|
if ((m_grfKeyState != grfKeyState) && m_pTargetCur)
|
|
{
|
|
m_dwEffectCur = *pdwEffect;
|
|
hr = m_pTargetCur->DragOver(grfKeyState, pt, &m_dwEffectCur);
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
*pdwEffect = m_dwEffectCur;
|
|
m_grfKeyState = grfKeyState;
|
|
}
|
|
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: COutBar::DragLeave()
|
|
//
|
|
// PURPOSE: Allows us to release any stored data we have from a successful
|
|
// DragEnter()
|
|
//
|
|
// RETURN VALUE:
|
|
// S_OK - Everything is groovy
|
|
//
|
|
HRESULT STDMETHODCALLTYPE COutBar::DragLeave(void)
|
|
{
|
|
SafeRelease(m_pDataObject);
|
|
SafeRelease(m_pTargetCur);
|
|
|
|
_UpdateDragDropHilite(NULL);
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: COutBar::Drop()
|
|
//
|
|
// PURPOSE: The user has let go of the object over our target. If we
|
|
// can accept this object we will already have the pDataObject
|
|
// stored in m_pDataObject. If this is a copy or move, then
|
|
// we go ahead and update the store. Otherwise, we bring up
|
|
// a send note with the object attached.
|
|
//
|
|
// PARAMETERS:
|
|
// <in> pDataObject - Pointer to the data object being dragged
|
|
// <in> grfKeyState - Pointer to the current key states
|
|
// <in> pt - Point in screen coordinates of the mouse
|
|
// <out> pdwEffect - Where we return whether this is a valid place for
|
|
// pDataObject to be dropped and if so what type of
|
|
// drop.
|
|
//
|
|
// RETURN VALUE:
|
|
// S_OK - Everything worked OK
|
|
//
|
|
HRESULT STDMETHODCALLTYPE COutBar::Drop(IDataObject* pDataObject,
|
|
DWORD grfKeyState, POINTL pt,
|
|
DWORD* pdwEffect)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
Assert(m_pDataObject == pDataObject);
|
|
|
|
if (m_fDropShortcut)
|
|
{
|
|
hr = _AddShortcut(pDataObject);
|
|
}
|
|
else
|
|
{
|
|
if (m_pTargetCur)
|
|
{
|
|
hr = m_pTargetCur->Drop(pDataObject, grfKeyState, pt, pdwEffect);
|
|
}
|
|
else
|
|
{
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
_UpdateDragDropHilite(NULL);
|
|
|
|
SafeRelease(m_pTargetCur);
|
|
SafeRelease(m_pDataObject);
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
HRESULT COutBar::_AddShortcut(IDataObject *pObject)
|
|
{
|
|
FORMATETC fe;
|
|
STGMEDIUM stm;
|
|
FOLDERID *pidFolder;
|
|
HRESULT hr = E_UNEXPECTED;
|
|
TBINSERTMARK tbim;
|
|
|
|
if (!pObject)
|
|
return (E_INVALIDARG);
|
|
|
|
// Get the data from the data object
|
|
SETDefFormatEtc(fe, CF_OEFOLDER, TYMED_HGLOBAL);
|
|
if (SUCCEEDED(pObject->GetData(&fe, &stm)))
|
|
{
|
|
pidFolder = (FOLDERID *) GlobalLock(stm.hGlobal);
|
|
|
|
ToolBar_GetInsertMark(m_hwndTools, &tbim);
|
|
_InsertButton(tbim.iButton + tbim.dwFlags, *pidFolder);
|
|
_SaveSettings();
|
|
_EmptyToolbar(TRUE);
|
|
_FillToolbar();
|
|
|
|
m_pOutBarNotify->Lock(m_hwnd);
|
|
m_pOutBarNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG);
|
|
m_pOutBarNotify->Unlock();
|
|
|
|
GlobalUnlock(stm.hGlobal);
|
|
ReleaseStgMedium(&stm);
|
|
}
|
|
else
|
|
{
|
|
SETDefFormatEtc(fe, CF_OESHORTCUT, TYMED_HGLOBAL);
|
|
if (SUCCEEDED(pObject->GetData(&fe, &stm)))
|
|
{
|
|
UINT *piPosOld = (UINT *) GlobalLock(stm.hGlobal);
|
|
UINT iPosNew;
|
|
ToolBar_GetInsertMark(m_hwndTools, &tbim);
|
|
|
|
iPosNew = tbim.iButton;
|
|
if (tbim.dwFlags & TBIMHT_AFTER)
|
|
iPosNew++;
|
|
|
|
TBBUTTON tbb;
|
|
ToolBar_GetButton(m_hwndTools, *piPosOld, &tbb);
|
|
SendMessage(m_hwndTools, TB_INSERTBUTTON, iPosNew, (LPARAM)&tbb);
|
|
|
|
if (iPosNew < *piPosOld)
|
|
(*piPosOld)++;
|
|
SendMessage(m_hwndTools, TB_DELETEBUTTON, *piPosOld, 0);
|
|
|
|
_SaveSettings();
|
|
_EmptyToolbar(TRUE);
|
|
_FillToolbar();
|
|
|
|
m_pOutBarNotify->Lock(m_hwnd);
|
|
m_pOutBarNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG);
|
|
m_pOutBarNotify->Unlock();
|
|
|
|
GlobalUnlock(stm.hGlobal);
|
|
ReleaseStgMedium(&stm);
|
|
}
|
|
}
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE COutBar::QueryContinueDrag(BOOL fEscapePressed,
|
|
DWORD grfKeyState)
|
|
{
|
|
if (fEscapePressed)
|
|
return (DRAGDROP_S_CANCEL);
|
|
|
|
if (grfKeyState & MK_RBUTTON)
|
|
return (DRAGDROP_S_CANCEL);
|
|
|
|
if (!(grfKeyState & MK_LBUTTON))
|
|
return (DRAGDROP_S_DROP);
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE COutBar::GiveFeedback(DWORD dwEffect)
|
|
{
|
|
return (DRAGDROP_S_USEDEFAULTCURSORS);
|
|
}
|
|
|
|
LRESULT CALLBACK COutBar::OutBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
COutBar *pThis;
|
|
|
|
if (uMsg == WM_NCCREATE)
|
|
{
|
|
pThis = (COutBar *) LPCREATESTRUCT(lParam)->lpCreateParams;
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis);
|
|
}
|
|
else
|
|
{
|
|
pThis = (COutBar *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
}
|
|
|
|
Assert(pThis);
|
|
return pThis->WndProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
|
|
LRESULT CALLBACK COutBar::ExtFrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
COutBar *pThis;
|
|
|
|
if (uMsg == WM_NCCREATE)
|
|
{
|
|
pThis = (COutBar *) LPCREATESTRUCT(lParam)->lpCreateParams;
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis);
|
|
}
|
|
else
|
|
{
|
|
pThis = (COutBar *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
}
|
|
|
|
Assert(pThis);
|
|
return pThis->FrameWndProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
|
|
LRESULT COutBar::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (msg)
|
|
{
|
|
HANDLE_MSG(hwnd, WM_MOUSEMOVE, OnMouseMove);
|
|
HANDLE_MSG(hwnd, WM_LBUTTONDOWN, OnLButtonDown);
|
|
HANDLE_MSG(hwnd, WM_LBUTTONUP, OnLButtonUp);
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
case WM_WININICHANGE:
|
|
case WM_FONTCHANGE:
|
|
{
|
|
SendMessage(m_hwndPager, msg, wParam, lParam);
|
|
SendMessage(m_hwndTools, msg, wParam, lParam);
|
|
ResizeBorderDW(NULL, NULL, FALSE);
|
|
return (0);
|
|
}
|
|
|
|
case WM_RELOADSHORTCUTS:
|
|
{
|
|
_EmptyToolbar(TRUE);
|
|
_FillToolbar();
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
}
|
|
|
|
|
|
LRESULT COutBar::FrameWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (msg)
|
|
{
|
|
HANDLE_MSG(hwnd, WM_NOTIFY, Frame_OnNotify);
|
|
HANDLE_MSG(hwnd, WM_SIZE, Frame_OnSize);
|
|
HANDLE_MSG(hwnd, WM_COMMAND, Frame_OnCommand);
|
|
HANDLE_MSG(hwnd, WM_NCDESTROY, Frame_OnNCDestroy);
|
|
}
|
|
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
}
|
|
|
|
void COutBar::OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
|
|
{
|
|
if (!m_fResizing)
|
|
{
|
|
SetCapture(hwnd);
|
|
m_fResizing = TRUE;
|
|
}
|
|
}
|
|
|
|
void COutBar::OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
|
|
{
|
|
POINT pt = { x, y };
|
|
RECT rcClient;
|
|
|
|
if (m_fResizing)
|
|
{
|
|
if (pt.x > 32)
|
|
{
|
|
GetClientRect(m_hwndParent, &rcClient);
|
|
m_cxWidth = min(pt.x, rcClient.right - 32);
|
|
ResizeBorderDW(0, 0, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void COutBar::OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
|
|
{
|
|
if (m_fResizing)
|
|
{
|
|
ReleaseCapture();
|
|
m_fResizing = FALSE;
|
|
}
|
|
}
|
|
|
|
void COutBar::Frame_OnNCDestroy(HWND hwnd)
|
|
{
|
|
SetWindowLong(hwnd, GWLP_USERDATA, NULL);
|
|
m_hwndFrame = m_hwndPager = m_hwndTools = NULL;
|
|
}
|
|
|
|
void COutBar::Frame_OnSize(HWND hwnd, UINT state, int cx, int cy)
|
|
{
|
|
// When we get resized, we resize our children and update the toolbar button width
|
|
if (m_hwndPager)
|
|
{
|
|
SetWindowPos(m_hwndPager, NULL, 0, 0, cx, cy, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
|
|
SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(cx, cx));
|
|
}
|
|
}
|
|
|
|
void COutBar::Frame_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
|
|
{
|
|
int iPos;
|
|
TBBUTTONINFO tbbi;
|
|
|
|
if (id < ID_FIRST)
|
|
{
|
|
tbbi.cbSize = sizeof(tbbi);
|
|
tbbi.dwMask = TBIF_LPARAM;
|
|
iPos = (int) SendMessage(m_hwndTools, TB_GETBUTTONINFO, (WPARAM) id, (LPARAM)&tbbi);
|
|
|
|
if (iPos >= 0)
|
|
m_pBrowser->BrowseObject((FOLDERID) tbbi.lParam, 0);
|
|
}
|
|
}
|
|
|
|
LRESULT COutBar::Frame_OnNotify(HWND hwnd, int idFrom, NMHDR *pnmhdr)
|
|
{
|
|
if (pnmhdr->code <= PGN_FIRST && pnmhdr->code >= PGN_LAST)
|
|
return SendMessage(m_hwndTools, WM_NOTIFY, 0, (LPARAM) pnmhdr);
|
|
|
|
switch (pnmhdr->code)
|
|
{
|
|
case NM_CUSTOMDRAW:
|
|
{
|
|
NMCUSTOMDRAW *pnmcd = (NMCUSTOMDRAW*) pnmhdr;
|
|
|
|
if (pnmcd->dwDrawStage == CDDS_PREPAINT)
|
|
return CDRF_NOTIFYITEMDRAW;
|
|
|
|
if (pnmcd->dwDrawStage == CDDS_ITEMPREPAINT)
|
|
{
|
|
NMTBCUSTOMDRAW * ptbcd = (NMTBCUSTOMDRAW *)pnmcd;
|
|
ptbcd->clrText = GetSysColor(COLOR_WINDOW);
|
|
return CDRF_NEWFONT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NM_RCLICK:
|
|
{
|
|
if (pnmhdr->hwndFrom == m_hwndTools)
|
|
{
|
|
DWORD dwPos = GetMessagePos();
|
|
_OnContextMenu(GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
case TBN_DRAGOUT:
|
|
{
|
|
NMTOOLBAR *pnmtb = (NMTOOLBAR *) pnmhdr;
|
|
DWORD dwEffect = DROPEFFECT_NONE;
|
|
UINT id = ToolBar_CommandToIndex(m_hwndTools, pnmtb->iItem);
|
|
|
|
// Create a new data object
|
|
CShortcutDataObject *pDataObj = new CShortcutDataObject(id);
|
|
if (pDataObj)
|
|
{
|
|
DoDragDrop(pDataObj, (IDropSource *) this, DROPEFFECT_MOVE, &dwEffect);
|
|
pDataObj->Release();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
HRESULT COutBar::_CreateToolbar()
|
|
{
|
|
HIMAGELIST himl, himlOld;
|
|
LRESULT lButtonSize;
|
|
RECT rc;
|
|
int iButtonWidth = 70;
|
|
TCHAR szName[CCHMAX_STRINGRES];
|
|
|
|
// Create the frame window
|
|
m_hwndFrame = CreateWindowEx(WS_EX_CLIENTEDGE, s_szOutBarFrameClass, NULL,
|
|
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
|
0, 0, 0, 0, m_hwnd, (HMENU) IDC_FRAME, g_hInst, this);
|
|
if (!m_hwndFrame)
|
|
return E_FAIL;
|
|
|
|
// Create the pager
|
|
m_hwndPager = CreateWindowEx(0, WC_PAGESCROLLER, NULL,
|
|
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | PGS_VERT | PGS_DRAGNDROP,
|
|
0, 0, 0, 0, m_hwndFrame, (HMENU) IDC_PAGER, g_hInst, NULL);
|
|
if (!m_hwndPager)
|
|
return E_FAIL;
|
|
|
|
ZeroMemory(szName, ARRAYSIZE(szName));
|
|
LoadString(g_hLocRes, idsOutlookBar, szName, ARRAYSIZE(szName));
|
|
|
|
// Create the toolbar
|
|
m_hwndTools = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, szName,
|
|
WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
|
|
TBSTYLE_FLAT | TBSTYLE_TOOLTIPS |
|
|
CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | CCS_VERT,
|
|
0, 0, 0, 0, m_hwndPager, (HMENU) IDC_TOOLBAR, g_hInst, NULL);
|
|
if (!m_hwndTools)
|
|
return E_FAIL;
|
|
|
|
// This tells the toolbar what version we are
|
|
SendMessage(m_hwndTools, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
|
|
|
|
_FillToolbar();
|
|
_SetButtonStyle(!m_fLarge);
|
|
|
|
SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(0, m_cxWidth));
|
|
|
|
m_pStNotify->Register(m_hwnd, g_hwndInit, FALSE);
|
|
SendMessage(m_hwndPager, PGM_SETCHILD, 0, (LPARAM)m_hwndTools);
|
|
|
|
// Let's try this
|
|
COLORSCHEME cs;
|
|
cs.dwSize = sizeof(COLORSCHEME);
|
|
cs.clrBtnHighlight = GetSysColor(COLOR_3DFACE);
|
|
cs.clrBtnShadow = GetSysColor(COLOR_WINDOWFRAME);
|
|
|
|
SendMessage(m_hwndTools, TB_SETCOLORSCHEME, 0, (LPARAM) &cs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void COutBar::_FillToolbar()
|
|
{
|
|
if (FAILED(_LoadSettings()))
|
|
_CreateDefaultButtons();
|
|
SendMessage(m_hwndPager, PGM_RECALCSIZE, 0, 0L);
|
|
}
|
|
|
|
void COutBar::_EmptyToolbar(BOOL fDelete)
|
|
{
|
|
if (fDelete)
|
|
while (SendMessage(m_hwndTools, TB_DELETEBUTTON, 0, 0))
|
|
;
|
|
}
|
|
|
|
BOOL COutBar::_FindButton(int *piBtn, LPITEMIDLIST pidl)
|
|
{
|
|
BOOL fFound = FALSE;
|
|
#if 0
|
|
int iBtn, cBtn, iCmp;
|
|
TBBUTTON tbb;
|
|
|
|
Assert(pidl);
|
|
|
|
cBtn = (int)SendMessage(m_hwndTools, TB_BUTTONCOUNT, 0, 0L);
|
|
|
|
// skip the root, so start at index 1
|
|
for (iBtn = 1; iBtn < cBtn; iBtn++)
|
|
{
|
|
if (SendMessage(m_hwndTools, TB_GETBUTTON, iBtn, (LPARAM)&tbb))
|
|
{
|
|
Assert(tbb.dwData);
|
|
iCmp = ShortFromResult(m_pShellFolder->CompareIDs(0, pidl, (LPITEMIDLIST)(tbb.dwData)));
|
|
if (iCmp <= 0)
|
|
{
|
|
fFound = (iCmp == 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
*piBtn = iBtn;
|
|
#endif
|
|
return fFound;
|
|
}
|
|
|
|
BOOL COutBar::_InsertButton(int index, FOLDERINFO *pInfo)
|
|
{
|
|
TBBUTTON tbb;
|
|
TCHAR szName[2 * MAX_PATH];
|
|
LPTSTR pszFree = NULL;
|
|
BOOL fRet;
|
|
|
|
tbb.fsState = TBSTATE_ENABLED | TBSTATE_WRAP;
|
|
tbb.fsStyle = TBSTYLE_BUTTON | TBSTYLE_NOPREFIX;
|
|
tbb.idCommand = m_idCommand++;
|
|
tbb.dwData = (DWORD_PTR) pInfo->idFolder;
|
|
tbb.iBitmap = GetFolderIcon(pInfo);
|
|
tbb.iString = (INT_PTR) pInfo->pszName;
|
|
|
|
if (pInfo->cUnread)
|
|
{
|
|
DWORD cchSize = ARRAYSIZE(szName);;
|
|
|
|
if (lstrlen(pInfo->pszName) + 13 < ARRAYSIZE(szName))
|
|
tbb.iString = (INT_PTR)szName;
|
|
else
|
|
{
|
|
cchSize = (lstrlen(pInfo->pszName) + 14);
|
|
if (!MemAlloc((LPVOID*) &pszFree, cchSize * sizeof(TCHAR)))
|
|
return FALSE;
|
|
tbb.iString = (INT_PTR)pszFree;
|
|
}
|
|
wnsprintf((LPTSTR)tbb.iString, cchSize, "%s (%d)", pInfo->pszName, CUnread(pInfo));
|
|
}
|
|
|
|
// Check to see if we're inserting at the end
|
|
if (index == -1)
|
|
{
|
|
index = ToolBar_ButtonCount(m_hwndTools);
|
|
}
|
|
|
|
// insert the root
|
|
fRet = (BOOL)SendMessage(m_hwndTools, TB_INSERTBUTTON, index, (LPARAM)&tbb);
|
|
SafeMemFree(pszFree);
|
|
return fRet;
|
|
}
|
|
|
|
BOOL COutBar::_InsertButton(int iIndex, FOLDERID id)
|
|
{
|
|
FOLDERINFO rInfo = {0};
|
|
|
|
if (SUCCEEDED(g_pStore->GetFolderInfo(id, &rInfo)))
|
|
{
|
|
_InsertButton(iIndex, &rInfo);
|
|
g_pStore->FreeRecord(&rInfo);
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
BOOL COutBar::_DeleteButton(int iBtn)
|
|
{
|
|
TBBUTTON tbb;
|
|
|
|
if (SendMessage(m_hwndTools, TB_GETBUTTON, iBtn, (LPARAM)&tbb))
|
|
{
|
|
if (SendMessage(m_hwndTools, TB_DELETEBUTTON, iBtn, 0L))
|
|
{
|
|
_SaveSettings();
|
|
m_pOutBarNotify->Lock(m_hwnd);
|
|
m_pOutBarNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG);
|
|
m_pOutBarNotify->Unlock();
|
|
return (TRUE);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL COutBar::_UpdateButton(int iBtn, LPITEMIDLIST pidl)
|
|
{
|
|
#if 0
|
|
TBBUTTON tbb;
|
|
TBBUTTONINFO tbbi;
|
|
TCHAR szName[2 * MAX_PATH];
|
|
LPTSTR pszFree = NULL;
|
|
BOOL fRet = FALSE;
|
|
|
|
if (SendMessage(m_hwndTools, TB_GETBUTTON, iBtn, (LPARAM)&tbb))
|
|
{
|
|
tbbi.cbSize = sizeof(tbbi);
|
|
tbbi.dwMask = TBIF_TEXT | TBIF_IMAGE | TBIF_LPARAM;
|
|
tbbi.iImage = FIDL_ICONID(pidl);
|
|
tbbi.lParam = (DWORD)pidl;
|
|
if (FIDL_UNREAD(pidl))
|
|
{
|
|
DWORD cchSize = ARRAYSIZE(szName);
|
|
|
|
if (lstrlen(FIDL_NAME(pidl)) + 13 < ARRAYSIZE(szName))
|
|
tbbi.pszText = szName;
|
|
else
|
|
{
|
|
cchSize = (lstrlen(FIDL_NAME(pidl)) + 14);
|
|
if (!MemAlloc((LPVOID*)&pszFree, (cchSize * sizeof(TCHAR))))
|
|
return FALSE;
|
|
tbbi.pszText = pszFree;
|
|
}
|
|
wnsprintf(tbbi.pszText, cchSize, "%s (%d)", FIDL_NAME(pidl), FIDL_UNREAD(pidl));
|
|
}
|
|
else
|
|
tbbi.pszText = FIDL_NAME(pidl);
|
|
fRet = SendMessage(m_hwndTools, TB_SETBUTTONINFO, (WPARAM)tbb.idCommand, (LPARAM)&tbbi);
|
|
if (tbb.dwData)
|
|
PidlFree((LPITEMIDLIST)(tbb.dwData));
|
|
if (pszFree)
|
|
MemFree(pszFree);
|
|
}
|
|
return fRet;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
void COutBar::_OnFolderNotify(FOLDERNOTIFY *pnotify)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
int iBtn;
|
|
BOOL fRecalc = FALSE;
|
|
|
|
Assert(pnotify != NULL);
|
|
Assert(pnotify->pidlNew != NULL);
|
|
|
|
switch (pnotify->msg)
|
|
{
|
|
case NEW_FOLDER:
|
|
// only insert if it is a root level pidl
|
|
if (0 == NEXTID(pnotify->pidlNew)->mkid.cb)
|
|
{
|
|
// check for dups and figure out where to insert
|
|
if (!FindButton(&iBtn, pnotify->pidlNew))
|
|
{
|
|
if (pidl = PidlDupIdList(pnotify->pidlNew))
|
|
fRecalc = InsertButton(iBtn, pidl);
|
|
}
|
|
}
|
|
break ;
|
|
|
|
case DELETE_FOLDER:
|
|
// only look for it if it is a root level pidl
|
|
if (0 == NEXTID(pnotify->pidlNew)->mkid.cb)
|
|
{
|
|
if (FindButton(&iBtn, pnotify->pidlNew))
|
|
fRecalc = DeleteButton(iBtn);
|
|
}
|
|
break ;
|
|
|
|
case RENAME_FOLDER:
|
|
case MOVE_FOLDER:
|
|
// only look for it if it is a root level pidl
|
|
if (0 == NEXTID(pnotify->pidlOld)->mkid.cb)
|
|
{
|
|
if (FindButton(&iBtn, pnotify->pidlOld))
|
|
fRecalc = DeleteButton(iBtn);
|
|
}
|
|
// only insert if it is a root level pidl
|
|
if (0 == NEXTID(pnotify->pidlNew)->mkid.cb)
|
|
{
|
|
// check for dups and figure out where to insert
|
|
if (!FindButton(&iBtn, pnotify->pidlNew))
|
|
{
|
|
if (pidl = PidlDupIdList(pnotify->pidlNew))
|
|
fRecalc = InsertButton(iBtn, pidl);
|
|
}
|
|
}
|
|
break ;
|
|
|
|
case UNREAD_CHANGE:
|
|
case UPDATEFLAG_CHANGE:
|
|
// only look for it if it is a root level pidl
|
|
if (0 == NEXTID(pnotify->pidlNew)->mkid.cb)
|
|
{
|
|
// check for dups and figure out where to insert
|
|
if (FindButton(&iBtn, pnotify->pidlNew))
|
|
{
|
|
if (pidl = PidlDupIdList(pnotify->pidlNew))
|
|
UpdateButton(iBtn, pidl);
|
|
}
|
|
}
|
|
break ;
|
|
|
|
case IMAPFLAG_CHANGE:
|
|
// don't care
|
|
break ;
|
|
|
|
case FOLDER_PROPS_CHANGED:
|
|
//Don't care
|
|
break ;
|
|
default:
|
|
AssertSz(FALSE, "Unhandled CFolderCache notification!");
|
|
break;
|
|
}
|
|
|
|
if (fRecalc)
|
|
SendMessage(m_hwndPager, PGM_RECALCSIZE, 0, 0L);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// FUNCTION: COutBar::_OnContextMenu
|
|
//
|
|
// PURPOSE: If the WM_CONTEXTMENU message is generated from the keyboard
|
|
// then figure out a pos to invoke the menu. Then dispatch the
|
|
// request to the handler.
|
|
//
|
|
// PARAMETERS:
|
|
// hwnd - Handle of the view window.
|
|
// hwndClick - Handle of the window the user clicked in.
|
|
// x, y - Position of the mouse click in screen coordinates.
|
|
//
|
|
void COutBar::_OnContextMenu(int x, int y)
|
|
{
|
|
HRESULT hr;
|
|
HMENU hMenu;
|
|
int id = 0;
|
|
int i;
|
|
POINT pt = { x, y };
|
|
TBBUTTON tbb;
|
|
|
|
// Figure out where the click was
|
|
ScreenToClient(m_hwndTools, &pt);
|
|
i = ToolBar_HitTest(m_hwndTools, &pt);
|
|
|
|
// If the click was on a button, then bring up the item context menu
|
|
if (i >= 0)
|
|
{
|
|
// Get the button info
|
|
SendMessage(m_hwndTools, TB_GETBUTTON, i, (LPARAM) &tbb);
|
|
|
|
// Load the context menu
|
|
hMenu = LoadPopupMenu(IDR_OUTLOOKBAR_ITEM_POPUP);
|
|
if (!hMenu)
|
|
return;
|
|
|
|
// Mark the button
|
|
SendMessage(m_hwndTools, TB_SETSTATE, (WPARAM)tbb.idCommand, (LPARAM)(TBSTATE_ENABLED | TBSTATE_WRAP | TBSTATE_MARKED));
|
|
m_idSel = tbb.idCommand;
|
|
|
|
// If this is the deleted items folder, add the "empty" menu item
|
|
TBBUTTONINFO tbbi;
|
|
|
|
tbbi.cbSize = sizeof(tbbi);
|
|
tbbi.dwMask = TBIF_LPARAM;
|
|
if (-1 != SendMessage(m_hwndTools, TB_GETBUTTONINFO, (WPARAM) m_idSel, (LPARAM)&tbbi))
|
|
{
|
|
FOLDERINFO rInfo;
|
|
|
|
if (SUCCEEDED(g_pStore->GetFolderInfo((FOLDERID) tbbi.lParam, &rInfo)))
|
|
{
|
|
if (rInfo.tySpecial != FOLDER_DELETED)
|
|
{
|
|
DeleteMenu(hMenu, ID_EMPTY_WASTEBASKET, MF_BYCOMMAND);
|
|
}
|
|
|
|
g_pStore->FreeRecord(&rInfo);
|
|
}
|
|
}
|
|
|
|
// Do the enable-disable thing
|
|
MenuUtil_EnablePopupMenu(hMenu, this);
|
|
|
|
// Display the context menu
|
|
id = TrackPopupMenuEx(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
|
|
x, y, m_hwnd, NULL);
|
|
|
|
// Unmark the button
|
|
SendMessage(m_hwndTools, TB_SETSTATE, (WPARAM)tbb.idCommand, (LPARAM)(TBSTATE_ENABLED | TBSTATE_WRAP));
|
|
|
|
// See if the user chose a menu item
|
|
if (id != 0)
|
|
{
|
|
Exec(NULL, id, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
|
|
}
|
|
|
|
m_idSel = -1;
|
|
|
|
// Clean this up
|
|
DestroyMenu(hMenu);
|
|
}
|
|
|
|
// Else if the click was in the empty space, show the bar context menu
|
|
else
|
|
{
|
|
// Load the context menu
|
|
hMenu = LoadPopupMenu(IDR_OUTLOOKBAR_POPUP);
|
|
if (!hMenu)
|
|
return;
|
|
|
|
// Do the enable-disable thing
|
|
MenuUtil_EnablePopupMenu(hMenu, this);
|
|
|
|
// Display the context menu
|
|
id = TrackPopupMenuEx(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
|
|
x, y, m_hwnd, NULL);
|
|
|
|
// See if the user chose a menu item
|
|
if (id != 0)
|
|
{
|
|
Exec(NULL, id, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
|
|
}
|
|
|
|
// Clean this up
|
|
DestroyMenu(hMenu);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
HRESULT COutBar::_CreateDefaultButtons()
|
|
{
|
|
IEnumerateFolders *pEnum = NULL;
|
|
FOLDERINFO rFolder;
|
|
UINT iIndex = 0;
|
|
FOLDERID idFolderDefault;
|
|
|
|
// Figure out the default server first
|
|
if (FAILED(GetDefaultServerId(ACCT_MAIL, &idFolderDefault)))
|
|
idFolderDefault = FOLDERID_LOCAL_STORE;
|
|
|
|
|
|
if (!(g_dwAthenaMode & MODE_NEWSONLY))
|
|
{
|
|
// Inbox first
|
|
if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(idFolderDefault, FOLDER_INBOX, &rFolder)))
|
|
{
|
|
_InsertButton(iIndex++, &rFolder);
|
|
g_pStore->FreeRecord(&rFolder);
|
|
}
|
|
}
|
|
// Outbox
|
|
if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, FOLDER_OUTBOX, &rFolder)))
|
|
{
|
|
_InsertButton(iIndex++, &rFolder);
|
|
g_pStore->FreeRecord(&rFolder);
|
|
}
|
|
|
|
// Sent Items
|
|
if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(idFolderDefault, FOLDER_SENT, &rFolder)))
|
|
{
|
|
_InsertButton(iIndex++, &rFolder);
|
|
g_pStore->FreeRecord(&rFolder);
|
|
}
|
|
|
|
// Deleted
|
|
if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, FOLDER_DELETED, &rFolder)))
|
|
{
|
|
_InsertButton(iIndex++, &rFolder);
|
|
g_pStore->FreeRecord(&rFolder);
|
|
}
|
|
|
|
// Drafts
|
|
if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(idFolderDefault, FOLDER_DRAFT, &rFolder)))
|
|
{
|
|
_InsertButton(iIndex++, &rFolder);
|
|
g_pStore->FreeRecord(&rFolder);
|
|
}
|
|
|
|
// Save at this point so everyone will be in sync
|
|
_SaveSettings();
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
HRESULT COutBar::_LoadSettings(void)
|
|
{
|
|
BAR_PERSIST_INFO *pPersist = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
DWORD iIndex = 0;
|
|
FOLDERINFO rInfo;
|
|
UINT i;
|
|
|
|
// Load the settings
|
|
if (FAILED(hr = OutlookBar_LoadSettings(&pPersist)))
|
|
goto exit;
|
|
|
|
// Load the bar from the saved folder ID's
|
|
for (i = 0; i < pPersist->cItems; i++)
|
|
{
|
|
// Get the folder info for this folder
|
|
if (SUCCEEDED(g_pStore->GetFolderInfo(pPersist->rgFolders[i], &rInfo)))
|
|
{
|
|
if (_InsertButton(iIndex, &rInfo))
|
|
iIndex++;
|
|
|
|
g_pStore->FreeRecord(&rInfo);
|
|
}
|
|
}
|
|
|
|
// If the bar is empty, and the user didn't save it empty, use the defaults
|
|
if (iIndex == 0 && pPersist->cItems)
|
|
hr = E_FAIL;
|
|
else
|
|
hr = S_OK;
|
|
|
|
// Also restore the width while we're at it
|
|
if (pPersist->cxWidth >= 28)
|
|
{
|
|
m_cxWidth = pPersist->cxWidth;
|
|
}
|
|
|
|
if (m_fOnce)
|
|
{
|
|
m_fLarge = !pPersist->fSmall;
|
|
m_fOnce = FALSE;
|
|
}
|
|
|
|
exit:
|
|
SafeMemFree(pPersist);
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
HRESULT COutBar::_SaveSettings(void)
|
|
{
|
|
BAR_PERSIST_INFO *pPersist = NULL;
|
|
DWORD cbData;
|
|
DWORD iIndex = 0;
|
|
FOLDERINFO rInfo;
|
|
UINT i;
|
|
DWORD cButtons;
|
|
TBBUTTON tbb;
|
|
RECT rcClient;
|
|
|
|
// Get the count of buttons from the outlook bar
|
|
cButtons = (DWORD) SendMessage(m_hwndTools, TB_BUTTONCOUNT, 0, 0);
|
|
|
|
// Allocate a persist info struct big enough for everything
|
|
cbData = sizeof(BAR_PERSIST_INFO) + ((cButtons - 1) * sizeof(FOLDERID));
|
|
if (!MemAlloc((LPVOID *) &pPersist, cbData))
|
|
return (E_OUTOFMEMORY);
|
|
|
|
// Fill in the persist info
|
|
pPersist->dwVersion = GetOutlookBarVersion();
|
|
pPersist->cItems = cButtons;
|
|
pPersist->fSmall = !m_fLarge;
|
|
pPersist->ftSaved.dwHighDateTime = 0;
|
|
pPersist->ftSaved.dwLowDateTime = 0;
|
|
|
|
GetClientRect(m_hwnd, &rcClient);
|
|
pPersist->cxWidth = rcClient.right;
|
|
|
|
// Loop through the buttons on the toolbar and get the info from each
|
|
for (i = 0; i < cButtons; i++)
|
|
{
|
|
SendMessage(m_hwndTools, TB_GETBUTTON, i, (LPARAM) &tbb);
|
|
pPersist->rgFolders[i] = (FOLDERID) tbb.dwData;
|
|
}
|
|
|
|
// Now open the registry and save the blob
|
|
AthUserSetValue(NULL, GetRegKey(), REG_BINARY, (const LPBYTE) pPersist, cbData);
|
|
|
|
// Free up the struct
|
|
SafeMemFree(pPersist);
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
HRESULT COutBar::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
|
|
{
|
|
BOOL fSpecial = FALSE;
|
|
BOOL fServer = FALSE;
|
|
BOOL fRoot = FALSE;
|
|
BOOL fNews = FALSE;
|
|
BOOL fIMAP = FALSE;
|
|
FOLDERINFO rFolder = {0};
|
|
FOLDERID idFolder = FOLDERID_INVALID;
|
|
|
|
if (m_idSel != -1)
|
|
{
|
|
// Get the ID of the folder that is selected
|
|
TBBUTTONINFO tbbi;
|
|
|
|
tbbi.cbSize = sizeof(tbbi);
|
|
tbbi.dwMask = TBIF_LPARAM;
|
|
if (-1 == SendMessage(m_hwndTools, TB_GETBUTTONINFO, (WPARAM) m_idSel, (LPARAM)&tbbi))
|
|
return (E_UNEXPECTED);
|
|
|
|
// Get the Folder Info
|
|
idFolder = (FOLDERID) tbbi.lParam;
|
|
if (FAILED(g_pStore->GetFolderInfo(idFolder, &rFolder)))
|
|
return (E_UNEXPECTED);
|
|
|
|
// Break some of this down for readability
|
|
fSpecial = rFolder.tySpecial != FOLDER_NOTSPECIAL;
|
|
fServer = rFolder.dwFlags & FOLDER_SERVER;
|
|
fRoot = FOLDERID_ROOT == idFolder;
|
|
fNews = rFolder.tyFolder == FOLDER_NEWS;
|
|
fIMAP = rFolder.tyFolder == FOLDER_IMAP;
|
|
}
|
|
|
|
// Loop through the commands in the prgCmds array looking for ones that haven't been handled
|
|
for (UINT i = 0; i < cCmds; i++)
|
|
{
|
|
if (prgCmds[i].cmdf == 0)
|
|
{
|
|
switch (prgCmds[i].cmdID)
|
|
{
|
|
case ID_OPEN_FOLDER:
|
|
case ID_REMOVE_SHORTCUT:
|
|
case ID_NEW_SHORTCUT:
|
|
case ID_HIDE:
|
|
case ID_FIND_MESSAGE:
|
|
prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
|
|
break;
|
|
|
|
case ID_LARGE_ICONS:
|
|
prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
|
|
if (m_fLarge)
|
|
prgCmds[i].cmdf |= OLECMDF_NINCHED;
|
|
break;
|
|
|
|
case ID_SMALL_ICONS:
|
|
prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
|
|
if (!m_fLarge)
|
|
prgCmds[i].cmdf |= OLECMDF_NINCHED;
|
|
break;
|
|
|
|
case ID_RENAME_SHORTCUT:
|
|
prgCmds[i].cmdf = OLECMDF_SUPPORTED;
|
|
break;
|
|
|
|
case ID_PROPERTIES:
|
|
{
|
|
Assert(idFolder != FOLDERID_INVALID);
|
|
|
|
prgCmds[i].cmdf |= OLECMDF_SUPPORTED;
|
|
|
|
// Everything except the root and the personal folders node
|
|
if (!fRoot && ((fServer && (fNews || fIMAP)) || !fServer))
|
|
prgCmds[i].cmdf |= OLECMDF_SUPPORTED | OLECMDF_ENABLED;
|
|
|
|
break;
|
|
}
|
|
|
|
case ID_EMPTY_WASTEBASKET:
|
|
{
|
|
if (rFolder.cMessages > 0 || FHasChildren(&rFolder, SUBSCRIBED))
|
|
prgCmds[i].cmdf = OLECMDF_ENABLED | OLECMDF_SUPPORTED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
g_pStore->FreeRecord(&rFolder);
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
HRESULT COutBar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
|
|
{
|
|
TBBUTTONINFO tbbi = { 0 };
|
|
FOLDERID id = FOLDERID_INVALID;
|
|
int iPos = -1;
|
|
|
|
// Get the ID of the folder that was selected
|
|
tbbi.cbSize = sizeof(tbbi);
|
|
tbbi.dwMask = TBIF_LPARAM;
|
|
tbbi.lParam = 0;
|
|
if (-1 != (iPos = (int) SendMessage(m_hwndTools, TB_GETBUTTONINFO, m_idSel, (LPARAM) &tbbi)))
|
|
{
|
|
id = (FOLDERID) tbbi.lParam;
|
|
}
|
|
|
|
switch (nCmdID)
|
|
{
|
|
case ID_OPEN_FOLDER:
|
|
{
|
|
if (id != FOLDERID_INVALID)
|
|
m_pBrowser->BrowseObject((FOLDERID) tbbi.lParam, 0);
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
case ID_REMOVE_SHORTCUT:
|
|
{
|
|
_DeleteButton(iPos);
|
|
return (S_OK);
|
|
}
|
|
|
|
case ID_RENAME_SHORTCUT:
|
|
break;
|
|
|
|
case ID_PROPERTIES:
|
|
{
|
|
if (id != FOLDERID_INVALID)
|
|
MenuUtil_OnProperties(m_hwndParent, id);
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
case ID_LARGE_ICONS:
|
|
case ID_SMALL_ICONS:
|
|
{
|
|
_SetButtonStyle(nCmdID == ID_SMALL_ICONS);
|
|
return (S_OK);
|
|
}
|
|
|
|
case ID_NEW_SHORTCUT:
|
|
{
|
|
FOLDERID idFolderDest;
|
|
HRESULT hr;
|
|
|
|
hr = SelectFolderDialog(m_hwnd, SFD_SELECTFOLDER, FOLDERID_ROOT,
|
|
FD_NONEWFOLDERS, (LPCTSTR) idsNewShortcutTitle,
|
|
(LPCTSTR) idsNewShortcutCaption, &idFolderDest);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
OutlookBar_AddShortcut(idFolderDest);
|
|
}
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
case ID_HIDE:
|
|
{
|
|
if (m_pBrowser)
|
|
{
|
|
m_pBrowser->SetViewLayout(DISPID_MSGVIEW_OUTLOOK_BAR, LAYOUT_POS_NA, FALSE, 0, 0);
|
|
}
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
case ID_EMPTY_WASTEBASKET:
|
|
{
|
|
if (AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsWarnEmptyDeletedItems),
|
|
NULL, MB_YESNO | MB_DEFBUTTON2) == IDYES)
|
|
{
|
|
EmptyFolder(m_hwnd, id);
|
|
}
|
|
return (S_OK);
|
|
}
|
|
|
|
case ID_FIND_MESSAGE:
|
|
{
|
|
DoFindMsg(id, 0);
|
|
return (S_OK);
|
|
}
|
|
}
|
|
|
|
return (OLECMDERR_E_NOTSUPPORTED);
|
|
}
|
|
|
|
|
|
BOOL COutBar::_SetButtonStyle(BOOL fSmall)
|
|
{
|
|
LONG lStyle;
|
|
SIZE s1, s2;
|
|
|
|
// Get the current style
|
|
lStyle = (LONG) SendMessage(m_hwndTools, TB_GETSTYLE, 0, 0);
|
|
|
|
// Make sure we have the right image list loaded
|
|
if (fSmall && !m_himlSmall)
|
|
{
|
|
// Load the image list for the toolbar
|
|
m_himlSmall = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbFolders), 16, 0, RGB(255, 0, 255));
|
|
if (!m_himlSmall)
|
|
return FALSE;
|
|
}
|
|
|
|
if (!fSmall && !m_himlLarge)
|
|
{
|
|
// Load the image list for the toolbar
|
|
m_himlLarge = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbFoldersLarge), 32, 0, RGB(255, 0, 255));
|
|
if (!m_himlLarge)
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the size
|
|
RECT rc;
|
|
GetClientRect(m_hwndTools, &rc);
|
|
|
|
NMPGCALCSIZE nm;
|
|
nm.hdr.code = PGN_CALCSIZE;
|
|
nm.dwFlag = PGF_CALCHEIGHT;
|
|
nm.iWidth = 0;
|
|
nm.iHeight = 0;
|
|
|
|
SendMessage(m_hwndTools, WM_NOTIFY, 0, (LPARAM) &nm);
|
|
|
|
// Now swap styles
|
|
if (fSmall)
|
|
{
|
|
lStyle |= TBSTYLE_LIST;
|
|
SendMessage(m_hwndTools, TB_SETSTYLE, 0, lStyle);
|
|
SendMessage(m_hwndTools, TB_SETBITMAPSIZE, 0, MAKELONG(16, 16));
|
|
SendMessage(m_hwndTools, TB_SETIMAGELIST, 0, (LPARAM) m_himlSmall);
|
|
SendMessage(m_hwndTools, TB_SETMAXTEXTROWS, 1, 0L);
|
|
SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(rc.right, rc.right));
|
|
}
|
|
else
|
|
{
|
|
lStyle &= ~TBSTYLE_LIST;
|
|
SendMessage(m_hwndTools, TB_SETSTYLE, 0, lStyle);
|
|
SendMessage(m_hwndTools, TB_SETIMAGELIST, 0, (LPARAM) m_himlLarge);
|
|
SendMessage(m_hwndTools, TB_SETBITMAPSIZE, 0, MAKELONG(32, 32));
|
|
SendMessage(m_hwndTools, TB_SETMAXTEXTROWS, 2, 0L);
|
|
SendMessage(m_hwndTools, TB_SETBUTTONWIDTH, 0, MAKELONG(rc.right, rc.right));
|
|
}
|
|
|
|
PostMessage(m_hwndPager, PGM_RECALCSIZE, 0, 0L);
|
|
InvalidateRect(m_hwndTools, NULL, TRUE);
|
|
m_fLarge = !fSmall;
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
HRESULT OutlookBar_AddShortcut(FOLDERID idFolder)
|
|
{
|
|
HRESULT hr;
|
|
BAR_PERSIST_INFO *pPersist = NULL;
|
|
DWORD cbData = 0;
|
|
INotify *pNotify = NULL;
|
|
|
|
// Load the current settings out of the registry. If it fails, that means
|
|
// we've never saved our settings before.
|
|
if (SUCCEEDED(hr = OutlookBar_LoadSettings(&pPersist)))
|
|
{
|
|
// Get the size of the current struct and add room for a new folder
|
|
cbData = sizeof(BAR_PERSIST_INFO) + (pPersist->cItems * sizeof(FOLDERID));
|
|
|
|
// Realloc the structure
|
|
if (MemRealloc((LPVOID *) &pPersist, cbData))
|
|
{
|
|
// Add our new button to the end
|
|
pPersist->rgFolders[pPersist->cItems] = idFolder;
|
|
pPersist->cItems++;
|
|
|
|
// Save the new settings out
|
|
if (SUCCEEDED(OutlookBar_SaveSettings(pPersist, cbData)))
|
|
{
|
|
// Send notifications
|
|
if (SUCCEEDED(CreateNotify(&pNotify)))
|
|
{
|
|
if (SUCCEEDED(pNotify->Initialize(c_szOutBarNotifyName)))
|
|
{
|
|
pNotify->Lock(NULL);
|
|
pNotify->DoNotification(WM_RELOADSHORTCUTS, 0, 0, SNF_POSTMSG);
|
|
pNotify->Unlock();
|
|
}
|
|
|
|
pNotify->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
SafeMemFree(pPersist);
|
|
}
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
HRESULT OutlookBar_LoadSettings(BAR_PERSIST_INFO **ppPersist)
|
|
{
|
|
HKEY hKey = 0;
|
|
LONG lResult;
|
|
DWORD dwType;
|
|
BAR_PERSIST_INFO *pPersist = NULL;
|
|
DWORD cbData;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (!ppPersist)
|
|
return (E_INVALIDARG);
|
|
|
|
// Get the reg key for this user
|
|
if (ERROR_SUCCESS != AthUserOpenKey(NULL, KEY_READ, &hKey))
|
|
return (hr);
|
|
|
|
// Get the size of the blob in the registry
|
|
lResult = RegQueryValueEx(hKey, COutBar::GetRegKey(), 0, &dwType, NULL, &cbData);
|
|
if (ERROR_SUCCESS != lResult)
|
|
goto exit;
|
|
|
|
// Allocate a buffer for the blob in the registry
|
|
if (!MemAlloc((LPVOID *) &pPersist, cbData + 1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
// Now get the data from the registry
|
|
lResult = RegQueryValueEx(hKey, COutBar::GetRegKey(), 0, &dwType, (LPBYTE) pPersist, &cbData);
|
|
if (ERROR_SUCCESS != lResult)
|
|
goto exit;
|
|
|
|
// Check to see if this version matches our version
|
|
if (pPersist->dwVersion != COutBar::GetOutlookBarVersion())
|
|
goto exit;
|
|
|
|
// Check to see if the saved time is valid
|
|
// $REVIEW - How?
|
|
|
|
// Double check that the size is correct
|
|
if (cbData != (sizeof(BAR_PERSIST_INFO) + ((pPersist->cItems - 1) * sizeof(FOLDERID))))
|
|
goto exit;
|
|
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
if (FAILED(hr))
|
|
SafeMemFree(pPersist);
|
|
|
|
*ppPersist = pPersist;
|
|
return (hr);
|
|
}
|
|
|
|
|
|
HRESULT OutlookBar_SaveSettings(BAR_PERSIST_INFO *pPersist, DWORD cbData)
|
|
{
|
|
// Open the registry and save the blob
|
|
AthUserSetValue(NULL, COutBar::GetRegKey(), REG_BINARY, (const LPBYTE) pPersist, cbData);
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
HRESULT COutBar::OnTransaction(HTRANSACTION hTransaction, DWORD_PTR dwCookie, IDatabase *pDB)
|
|
{
|
|
TRANSACTIONTYPE tyTransaction;
|
|
ORDINALLIST Ordinals;
|
|
FOLDERINFO Folder1={0};
|
|
FOLDERINFO Folder2={0};
|
|
DWORD cButtons;
|
|
TBBUTTON tbb;
|
|
TCHAR szName[2 * MAX_PATH];
|
|
LPTSTR pszFree = NULL;
|
|
BOOL fChanged;
|
|
INDEXORDINAL iIndex;
|
|
TBBUTTONINFO tbbi;
|
|
int iButton;
|
|
|
|
if (!IsWindow(m_hwnd))
|
|
return (S_OK);
|
|
|
|
// Get the number of buttons on our bar
|
|
cButtons = (DWORD) SendMessage(m_hwndTools, TB_BUTTONCOUNT, 0, 0);
|
|
|
|
// Walk through the notifications
|
|
while (hTransaction)
|
|
{
|
|
// Get Transact
|
|
if (FAILED(pDB->GetTransaction(&hTransaction, &tyTransaction, &Folder1, &Folder2, &iIndex, &Ordinals)))
|
|
break;
|
|
|
|
// Delete
|
|
if (TRANSACTION_DELETE == tyTransaction)
|
|
{
|
|
for (iButton = cButtons - 1; iButton >= 0; iButton--)
|
|
{
|
|
// Get the button information
|
|
ToolBar_GetButton(m_hwndTools, iButton, &tbb);
|
|
|
|
// If the ID of this button matches the ID that changed
|
|
if ((FOLDERID) tbb.dwData == Folder1.idFolder)
|
|
{
|
|
// Blow it away
|
|
SendMessage(m_hwndTools, TB_DELETEBUTTON, iButton, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update
|
|
else if (TRANSACTION_UPDATE == tyTransaction)
|
|
{
|
|
// Loop through all our buttons since we might have dupes
|
|
for (iButton = cButtons - 1; iButton >= 0; iButton--)
|
|
{
|
|
fChanged = FALSE;
|
|
|
|
// Get the button information
|
|
ToolBar_GetButton(m_hwndTools, iButton, &tbb);
|
|
|
|
// If the ID of this button matches the ID that changed
|
|
if ((FOLDERID) tbb.dwData == Folder1.idFolder)
|
|
{
|
|
tbbi.cbSize = sizeof(TBBUTTONINFO);
|
|
tbbi.dwMask = TBIF_TEXT | TBIF_IMAGE;
|
|
tbbi.pszText = szName;
|
|
tbbi.cchText = ARRAYSIZE(szName);
|
|
|
|
ToolBar_GetButtonInfo(m_hwndTools, tbb.idCommand, &tbbi);
|
|
|
|
// Unread Change || Folder Renamed
|
|
if (Folder1.cUnread != Folder2.cUnread ||
|
|
lstrcmp(Folder1.pszName, Folder2.pszName) != 0)
|
|
{
|
|
if (Folder2.cUnread)
|
|
{
|
|
DWORD cchSize = ARRAYSIZE(szName);
|
|
|
|
if (lstrlen(Folder2.pszName) + 13 < ARRAYSIZE(szName))
|
|
tbbi.pszText = szName;
|
|
else
|
|
{
|
|
cchSize = (lstrlen(Folder2.pszName) + 14);
|
|
if (!MemAlloc((LPVOID*) &pszFree, cchSize * sizeof(TCHAR)))
|
|
return FALSE;
|
|
tbbi.pszText = pszFree;
|
|
}
|
|
wnsprintf(tbbi.pszText, cchSize, "%s (%d)", Folder2.pszName, CUnread(&Folder2));
|
|
}
|
|
else
|
|
{
|
|
tbbi.pszText = Folder2.pszName;
|
|
}
|
|
|
|
fChanged = TRUE;
|
|
}
|
|
|
|
// synchronize state changed ?
|
|
if ((0 == (Folder1.dwFlags & (FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL))) ^
|
|
(0 == (Folder2.dwFlags & (FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL))))
|
|
{
|
|
tbbi.iImage = GetFolderIcon(&Folder2);
|
|
fChanged = TRUE;
|
|
}
|
|
|
|
if (ISFLAGSET(Folder1.dwFlags, FOLDER_SUBSCRIBED) != ISFLAGSET(Folder2.dwFlags, FOLDER_SUBSCRIBED))
|
|
{
|
|
if (ISFLAGSET(Folder2.dwFlags, FOLDER_SUBSCRIBED))
|
|
{
|
|
tbbi.iImage = GetFolderIcon(&Folder2);
|
|
fChanged = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SendMessage(m_hwndTools, TB_DELETEBUTTON, iButton, 0);
|
|
fChanged = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fChanged)
|
|
{
|
|
ToolBar_SetButtonInfo(m_hwndTools, tbb.idCommand, &tbbi);
|
|
}
|
|
SafeMemFree(pszFree);
|
|
}
|
|
}
|
|
}
|
|
|
|
pDB->FreeRecord(&Folder1);
|
|
pDB->FreeRecord(&Folder2);
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
BOOL COutBar::_IsTempNewsgroup(IDataObject *pObject)
|
|
{
|
|
FORMATETC fe;
|
|
STGMEDIUM stm;
|
|
FOLDERID *pidFolder;
|
|
FOLDERINFO rInfo;
|
|
BOOL fReturn = TRUE;
|
|
|
|
SETDefFormatEtc(fe, CF_OEFOLDER, TYMED_HGLOBAL);
|
|
if (SUCCEEDED(pObject->GetData(&fe, &stm)))
|
|
{
|
|
pidFolder = (FOLDERID *) GlobalLock(stm.hGlobal);
|
|
|
|
if (SUCCEEDED(g_pStore->GetFolderInfo(*pidFolder, &rInfo)))
|
|
{
|
|
if ((rInfo.tySpecial == FOLDER_NOTSPECIAL) &&
|
|
(rInfo.tyFolder == FOLDER_NEWS) &&
|
|
(0 == (rInfo.dwFlags & FOLDER_SUBSCRIBED)))
|
|
{
|
|
fReturn = FALSE;
|
|
}
|
|
|
|
g_pStore->FreeRecord(&rInfo);
|
|
}
|
|
|
|
GlobalUnlock(stm.hGlobal);
|
|
ReleaseStgMedium(&stm);
|
|
}
|
|
|
|
return (fReturn);
|
|
}
|
|
|
|
LPCTSTR COutBar::GetRegKey()
|
|
{
|
|
LPCTSTR retval;
|
|
|
|
if (g_dwAthenaMode & MODE_NEWSONLY)
|
|
{
|
|
retval = c_szRegOutlookBarNewsOnly;
|
|
}
|
|
else
|
|
{
|
|
retval = c_szRegOutlookBar;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
DWORD COutBar::GetOutlookBarVersion()
|
|
{
|
|
DWORD retval;
|
|
|
|
if (g_dwAthenaMode & MODE_NEWSONLY)
|
|
{
|
|
retval = OUTLOOK_BAR_NEWSONLY_VERSION;
|
|
}
|
|
else
|
|
{
|
|
retval = OUTLOOK_BAR_VERSION;
|
|
}
|
|
|
|
return retval;
|
|
}
|