|
|
#include "priv.h"
#include "sccls.h"
#include "nscband.h"
#include "nsc.h"
#include "resource.h"
#include "dhuihand.h"
#include <varutil.h>
#include <mluisupp.h>
#define DM_HISTBAND 0x0000000
#define DM_GUIPAINS 0x40000000
#define REGKEY_HISTORY_VIEW TEXT("HistoryViewType")
#define REGKEY_DEFAULT_SIZE 0x10
#define VIEWTYPE_MAX 0x4 // A "guess" at how many viewtypes thare will be
#define VIEWTYPE_REALLOC 0x4 // How many to realloc at a time
// these are temporary
#define MENUID_SEARCH 0x4e4e
// Distance between history search go and stop buttons
#define HISTSRCH_BUTTONDIST 6
extern HINSTANCE g_hinst;
#define WM_SEARCH_STATE (WM_USER + 314)
class CHistBand : public CNSCBand, public IShellFolderSearchableCallback { friend HRESULT CHistBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi); public: // *** IUnknown methods ***
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj); STDMETHODIMP_(ULONG) AddRef (void) { return CNSCBand::AddRef(); }; STDMETHODIMP_(ULONG) Release(void) { return CNSCBand::Release(); }; // *** IOleCommandTarget methods ***
STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut);
// *** IOleWindow methods ***
// (overriding CNSCBand implementation
STDMETHODIMP GetWindow(HWND *phwnd);
// *** IInputObject methods ***
// (overriding CNSCBand/CToolBand's implementation)
STDMETHODIMP TranslateAcceleratorIO(LPMSG lpMsg);
// *** IDockingWindow methods ***
STDMETHODIMP ShowDW(BOOL fShow);
// *** IShellFolderSearchableCallback methods ***
STDMETHODIMP RunBegin(DWORD dwReserved); STDMETHODIMP RunEnd(DWORD dwReserved); protected: virtual void _AddButtons(BOOL fAdd); virtual HRESULT _OnRegisterBand(IOleCommandTarget *poctProxy); virtual BOOL _ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib); virtual HRESULT _NavigateRightPane(IShellBrowser *psb, LPCITEMIDLIST pidl);
~CHistBand();
HRESULT _InitViewPopup(); HRESULT _DoViewPopup(int x, int y); HRESULT _ViewPopupSelect(UINT idCmd);
#ifdef SPLIT_HISTORY_VIEW_BUTTON
UINT _NextMenuItem(); #endif
HRESULT _ChangePidl(LPITEMIDLIST); HRESULT _SelectPidl(LPCITEMIDLIST pidlSelect, BOOL fCreate, LPCITEMIDLIST pidlViewType = NULL, BOOL fReinsert = FALSE);
virtual HRESULT _InitializeNsc(); LPITEMIDLIST _GetCurrentSelectPidl(IOleCommandTarget *poctProxy = NULL); HRESULT _SetRegistryPersistView(int iMenuID); int _GetRegistryPersistView(); LPCITEMIDLIST _MenuIDToPIDL(UINT uMenuID); int _PIDLToMenuID(LPITEMIDLIST pidl); IShellFolderViewType* _GetViewTypeInfo(); HRESULT _GetHistoryViews(); HRESULT _FreeViewInfo();
void _ResizeChildWindows(LONG width, LONG height, BOOL fRepaint); HRESULT _DoSearchUIStuff(); HRESULT _ExecuteSearch(LPTSTR pszSearchString); HRESULT _ClearSearch(); IShellFolderSearchable *_EnsureSearch(); static LRESULT CALLBACK s_EditWndSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK s_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); static BOOL_PTR CALLBACK s_HistSearchDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL _fStrsAdded; // Strings from resource have been added as buttons on the toolbar
LONG_PTR _lStrOffset;
HMENU _hViewMenu; // an instance var so we can cache it
UINT _uViewCheckedItem; // which menuitem in the View menu is checked?
LPITEMIDLIST *_ppidlViewTypes; LPTSTR *_ppszStrViewNames; UINT _nViews; int _iMaxMenuID;
HWND _hwndNSC; HWND _hwndSearchDlg; LONG _lSearchDlgHeight; LPITEMIDLIST _pidlSearch; // current search
IShellFolderSearchable *_psfSearch; LPITEMIDLIST _pidlHistory; // cache the history pidl from SHGetHistoryPIDL
IShellFolder *_psfHistory; // cache the history shell folder
IShellFolderViewType *_psfvtCache; // view type information
LPITEMIDLIST _pidlLastSelect; };
CHistBand::~CHistBand() { DestroyMenu(_hViewMenu); if (_pidlLastSelect) ILFree(_pidlLastSelect); if (_pidlHistory) ILFree(_pidlHistory); if (_psfHistory) _psfHistory->Release(); if (_psfvtCache) _psfvtCache->Release(); _ClearSearch(); // Frees _pidlSearch
if (_psfSearch) _psfSearch->Release(); _FreeViewInfo(); }
HRESULT CHistBand::QueryInterface(REFIID riid, void **ppvObj) { static const QITAB qit[] = { QITABENT(CHistBand, IShellFolderSearchableCallback), // IID_IShellFolderSearchableCallback
{ 0 }, }; HRESULT hr = QISearch(this, qit, riid, ppvObj); if (FAILED(hr)) hr = CNSCBand::QueryInterface(riid, ppvObj); return hr; }
// *** IOleCommandTarget methods ***
HRESULT CHistBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { HRESULT hRes = S_OK; if (pguidCmdGroup) { if (IsEqualGUID(CLSID_HistBand, *pguidCmdGroup)) { switch(nCmdID) { case FCIDM_HISTBAND_VIEW: if (pvarargIn && (pvarargIn->vt == VT_I4)) { #ifdef SPLIT_HISTORY_VIEW_BUTTON
if (nCmdexecopt == OLECMDEXECOPT_PROMPTUSER) hRes = _DoViewPopup(GET_X_LPARAM(pvarargIn->lVal), GET_Y_LPARAM(pvarargIn->lVal)); else hRes = _ViewPopupSelect(_NextMenuItem()); #else
ASSERT(nCmdexecopt == OLECMDEXECOPT_PROMPTUSER); hRes = _DoViewPopup(GET_X_LPARAM(pvarargIn->lVal), GET_Y_LPARAM(pvarargIn->lVal)); #endif
} else ASSERT(0); break; case FCIDM_HISTBAND_SEARCH: _ViewPopupSelect(MENUID_SEARCH); break; } } else if ((IsEqualGUID(CGID_Explorer, *pguidCmdGroup))) { switch (nCmdID) { case SBCMDID_SELECTHISTPIDL: #ifdef ANNOYING_HISTORY_AUTOSELECT
if (_uViewCheckedItem != MENUID_SEARCH) { LPCITEMIDLIST pidlSelect = VariantToIDList(pvarargIn);
// Get the current view information
LPCITEMIDLIST pidlView = _MenuIDToPIDL(_uViewCheckedItem); DWORD dwViewFlags = SFVTFLAG_NOTIFY_CREATE; IShellFolderViewType* psfvtInfo = _GetViewTypeInfo();
if (psfvtInfo) { // query for view type properties -- this will tell us how to
// select the item...
hRes = psfvtInfo->GetViewTypeProperties(pidlView, &dwViewFlags); psfvtInfo->Release(); } if (SUCCEEDED(hRes)) { hRes = _SelectPidl(pidlSelect, dwViewFlags & SFVTFLAG_NOTIFY_CREATE, pidlView, dwViewFlags & SFVTFLAG_NOTIFY_RESORT); } ILFree(pidlSelect); } else //eat it, so that nsc doesn't get it
hRes = S_OK; #endif //ANNOYING_HISTORY_AUTOSELECT
hRes = S_OK; break; case SBCMDID_FILEDELETE: hRes = _InvokeCommandOnItem(TEXT("delete")); break; } } else hRes = CNSCBand::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } else hRes = CNSCBand::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); return hRes; }
// *** IInputObject methods ***
HRESULT CHistBand::TranslateAcceleratorIO(LPMSG pmsg) { #ifdef DEBUG
if (pmsg->message == WM_KEYDOWN) TraceMsg(DM_GUIPAINS, "CHistBand -- TranslateAcceleratorIO called and _hwndSearchDlg is %x", _hwndSearchDlg); #endif
HWND hwndFocus = GetFocus(); // Translate accelerator messages for dialog
if ( (_hwndSearchDlg) && (hwndFocus != _hwndNSC) && (!hwndFocus || !IsChild(_hwndNSC, hwndFocus)) ) { if (pmsg->message == WM_KEYDOWN) { if (IsVK_TABCycler(pmsg)) { BOOL fBackwards = (GetAsyncKeyState(VK_SHIFT) < 0); HWND hwndCur = pmsg->hwnd; if (GetParent(pmsg->hwnd) != _hwndSearchDlg) hwndCur = NULL; HWND hwndNext = GetNextDlgTabItem(_hwndSearchDlg, hwndCur, fBackwards); // Get the First dialog item in this searching order
HWND hwndFirst; if (!fBackwards) { hwndFirst = GetNextDlgTabItem(_hwndSearchDlg, NULL, FALSE); } else // passing NULL for the 2nd parameter returned NULL with ERROR_SUCCESS,
// so this is a workaround
hwndFirst = GetNextDlgTabItem(_hwndSearchDlg, GetNextDlgTabItem(_hwndSearchDlg, NULL, FALSE), TRUE); // If the next dialog tabstop is the first dialog tabstop, then
// let someone else get focus
if ((!hwndCur) || (hwndNext != hwndFirst)) { SetFocus(hwndNext); return S_OK; } else if (!fBackwards) { SetFocus(_hwndNSC); return S_OK; } } else if ( (pmsg->wParam == VK_RETURN) ) SendMessage(_hwndSearchDlg, WM_COMMAND, MAKELONG(GetDlgCtrlID(pmsg->hwnd), 0), 0L); } // The History Search Edit Box is activated
if (pmsg->hwnd == GetDlgItem(_hwndSearchDlg, IDC_EDITHISTSEARCH)) { // If the user pressed tab within the dialog
return EditBox_TranslateAcceleratorST(pmsg); } } return CNSCBand::TranslateAcceleratorIO(pmsg); }
// sends appropriate resize messages to our children windows
void CHistBand::_ResizeChildWindows(LONG width, LONG height, BOOL fRepaint) { if (_hwndNSC) { int y1 = _hwndSearchDlg ? _lSearchDlgHeight : 0; int y2 = _hwndSearchDlg ? height - _lSearchDlgHeight : height;
MoveWindow(_hwndNSC, 0, y1, width, y2, fRepaint); }
if (_hwndSearchDlg) { MoveWindow(_hwndSearchDlg, 0, 0, width, _lSearchDlgHeight, fRepaint); } }
HRESULT CHistBand::_DoSearchUIStuff() { HRESULT hr;
// host the search dialog inside my window:
_hwndSearchDlg = CreateDialogParam(MLGetHinst(), MAKEINTRESOURCE(DLG_HISTSEARCH2), _hwnd, s_HistSearchDlgProc, reinterpret_cast<LPARAM>(this));
if (_hwndSearchDlg) { RECT rcSelf; GetClientRect(_hwnd, &rcSelf); RECT rcDlg; GetClientRect(_hwndSearchDlg, &rcDlg);
_lSearchDlgHeight = rcDlg.bottom;
_ResizeChildWindows(rcSelf.right, rcSelf.bottom, TRUE); ShowWindow(_hwndSearchDlg, SW_SHOWDEFAULT);
hr = S_OK; } else { hr = E_FAIL; }
return hr; }
// WndProc for main window to go in rebar
LRESULT CALLBACK CHistBand::s_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { CHistBand* phb = reinterpret_cast<CHistBand *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
switch (msg) { case WM_SETFOCUS: { TraceMsg(DM_GUIPAINS, "Histband Parent -- SETFOCUS"); // The only way this should be called is via a RB_CYCLEFOCUS->...->UIActivateIO->SetFocus
// therefore, we can assume that we're being tabbed into or something with equally good.
// If we tab into the outer dummy window, transfer the focus to
// our appropriate child:
BOOL fBackwards = (GetAsyncKeyState(VK_SHIFT) < 0); if (phb->_hwndSearchDlg) { // Select either the first or the last item in the dialog depending on
// whether we're shifting in or shifting out
SetFocus(GetNextDlgTabItem(phb->_hwndSearchDlg, (NULL), fBackwards)); } else { TraceMsg(DM_GUIPAINS, "NSC is being given focus!"); SetFocus(phb->_hwndNSC); } } return 0; case WM_CREATE: SetWindowLongPtr(hWnd, GWLP_USERDATA, (reinterpret_cast<LONG_PTR>((reinterpret_cast<CREATESTRUCT *>(lParam))->lpCreateParams))); return 0; case WM_SIZE: if (phb) phb->_ResizeChildWindows(LOWORD(lParam), HIWORD(lParam), TRUE); return 0; case WM_NCDESTROY: //make sure the search object gets freed when the view/window is destroyed, because it holds a ref to us
phb->_ClearSearch(); break; case WM_NOTIFY: { if (phb) { // We proxy the notification messages to our own parent who thinks that we
// are the namespace control
LPNMHDR pnmh = (LPNMHDR)lParam; // Notification message coming from NSC
if (pnmh->hwndFrom == phb->_hwndNSC) return SendMessage(phb->_hwndParent, msg, wParam, lParam); } } // INTENTIONAL FALLTHROUGH
} return DefWindowProc(hWnd, msg, wParam, lParam); }
// *** IOleWindow methods ***
HRESULT CHistBand::GetWindow(HWND *phwnd) { if (!_hwnd) { // we want to wrap a window around the namespace control so
// that we can add siblings later
// Get our parent's dimensions
RECT rcParent; GetClientRect(_hwndParent, &rcParent);
static LPTSTR pszClassName = TEXT("History Pane");
WNDCLASSEX wndclass = { 0 }; wndclass.cbSize = sizeof(wndclass); wndclass.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = s_WndProc; wndclass.hInstance = g_hinst; wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.lpszClassName = pszClassName;
RegisterClassEx(&wndclass); _hwnd = CreateWindow(pszClassName, TEXT("History Window"), WS_CHILD | WS_TABSTOP, 0, 0, rcParent.right, rcParent.bottom, _hwndParent, NULL, g_hinst, (LPVOID)this); } if (_hwnd) // Host NSC
_pns->CreateTree(_hwnd, _GetTVStyle(), &_hwndNSC);
return CToolBand::GetWindow(phwnd); }
// *** IDockingWindow methods ***
HRESULT CHistBand::ShowDW(BOOL fShow) { HRESULT hr = CNSCBand::ShowDW(fShow); _AddButtons(fShow); return hr; }
static const TBBUTTON c_tbHistory[] = { { I_IMAGENONE, FCIDM_HISTBAND_VIEW, TBSTATE_ENABLED, BTNS_AUTOSIZE | BTNS_WHOLEDROPDOWN | BTNS_SHOWTEXT, {0,0}, 0, 0 }, { 2, FCIDM_HISTBAND_SEARCH, TBSTATE_ENABLED, BTNS_AUTOSIZE | BTNS_SHOWTEXT, {0,0}, 0, 1 }, };
// Adds buttons from the above table to the Explorer
void CHistBand::_AddButtons(BOOL fAdd) { // don't add button if we have no menu
if (!_hViewMenu) return;
IExplorerToolbar* piet;
if (SUCCEEDED(_punkSite->QueryInterface(IID_IExplorerToolbar, (void**)&piet))) { if (fAdd) { piet->SetCommandTarget((IUnknown*)SAFECAST(this, IOleCommandTarget*), &CLSID_HistBand, 0);
if (!_fStrsAdded) { piet->AddString(&CLSID_HistBand, MLGetHinst(), IDS_HIST_BAR_LABELS, &_lStrOffset); _fStrsAdded = TRUE; }
_EnsureImageListsLoaded(); piet->SetImageList(&CLSID_HistBand, _himlNormal, _himlHot, NULL);
TBBUTTON tbHistory[ARRAYSIZE(c_tbHistory)]; memcpy(tbHistory, c_tbHistory, SIZEOF(TBBUTTON) * ARRAYSIZE(c_tbHistory)); for (int i = 0; i < ARRAYSIZE(c_tbHistory); i++) tbHistory[i].iString += (long) _lStrOffset;
piet->AddButtons(&CLSID_HistBand, ARRAYSIZE(tbHistory), tbHistory); } else piet->SetCommandTarget(NULL, NULL, 0);
piet->Release(); } }
// *** IShellFolderSearchableCallback methods ***
// enable and disable cancel buttons
HRESULT CHistBand::RunBegin(DWORD dwReserved) { HRESULT hr = E_FAIL; if (_hwndSearchDlg) { SendMessage(_hwndSearchDlg, WM_SEARCH_STATE, (WPARAM)TRUE, NULL); hr = S_OK; } return hr; }
HRESULT CHistBand::RunEnd(DWORD dwReserved) { HRESULT hr = E_FAIL; if (_hwndSearchDlg) { SendMessage(_hwndSearchDlg, WM_SEARCH_STATE, (WPARAM)FALSE, NULL); hr = S_OK; } return hr; }
// A utility function used in the WM_SIZE handling below...
inline HWND _GetHwndAndRect(HWND hwndDlg, int item, BOOL fClient, RECT &rc) { HWND hwnd = GetDlgItem(hwndDlg, item); if (fClient) GetClientRect(hwnd, &rc); else { GetWindowRect(hwnd, &rc); MapWindowPoints(NULL, hwndDlg, ((LPPOINT)&rc), 2); } return hwnd; }
LRESULT CALLBACK CHistBand::s_EditWndSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_KEYDOWN: if ((GetAsyncKeyState(VK_CONTROL) < 0) && (wParam == TEXT('U'))) { uMsg = WM_SETTEXT; wParam = 0; lParam = ((LPARAM)(LPCTSTR)TEXT("")); } break;
case WM_CHAR: if (wParam == VK_RETURN) { PostMessage(GetParent(hwnd), WM_COMMAND, MAKELONG(IDB_HISTSRCH_GO, 0), 0L); return 0L; } break; } return CallWindowProc((WNDPROC)(GetWindowLongPtr(hwnd, GWLP_USERDATA)), hwnd, uMsg, wParam, lParam); }
// Please see note at top of file for explanation...
INT_PTR CALLBACK CHistBand::s_HistSearchDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_PAINT: { // paint a little separator bar on the bottom
PAINTSTRUCT ps; RECT rcSelf; HDC hdc = BeginPaint(hwndDlg, &ps); GetClientRect(hwndDlg, &rcSelf); RECT rcFill = { 0, rcSelf.bottom - 2, rcSelf.right, rcSelf.bottom }; FillRect(hdc, &rcFill, GetSysColorBrush(COLOR_BTNFACE)); EndPaint(hwndDlg, &ps); break; }
// Supply child controls with correct bkgd color
case WM_CTLCOLORSTATIC: if ((HWND)lParam == GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION)) { SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); return (INT_PTR) GetSysColorBrush(COLOR_WINDOW); } else { SetBkMode((HDC)wParam, TRANSPARENT); return (INT_PTR) GetSysColorBrush(COLOR_WINDOW); } case WM_CTLCOLORDLG: //SetBkColor((HDC)HIWORD(lParam), GetSysColor(COLOR_WINDOW));
return (INT_PTR) GetSysColorBrush(COLOR_WINDOW); case WM_INITDIALOG: { HWND hwndEdit = GetDlgItem(hwndDlg, IDC_EDITHISTSEARCH); WNDPROC pfnOldEditProc = (WNDPROC)(GetWindowLongPtr(hwndEdit, GWLP_WNDPROC));
// subclass the editbox
SetWindowLongPtr(hwndEdit, GWLP_USERDATA, (LPARAM)pfnOldEditProc); SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LPARAM)s_EditWndSubclassProc); SetWindowLongPtr(hwndDlg, DWLP_USER, lParam); Animate_Open(GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION), MAKEINTRESOURCE(IDA_HISTSEARCHAVI));
// limit the edit control to MAX_PATH-1 characters
Edit_LimitText(hwndEdit, MAX_PATH-1);
break; } case WM_DESTROY: Animate_Close(GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION)); break; case WM_SIZE: { if (wParam == SIZE_RESTORED) { UINT uWidth = LOWORD(lParam); UINT uHeight = HIWORD(lParam);
RECT rcAnimSize, rcCancel, rcSearch, rcEdit, rcStatic; HWND hwndAnim = _GetHwndAndRect(hwndDlg, IDD_HISTSRCH_ANIMATION, TRUE, rcAnimSize); HWND hwndCancel = _GetHwndAndRect(hwndDlg, IDCANCEL, FALSE, rcCancel); HWND hwndSearch = _GetHwndAndRect(hwndDlg, IDB_HISTSRCH_GO, FALSE, rcSearch); HWND hwndEdit = _GetHwndAndRect(hwndDlg, IDC_EDITHISTSEARCH, FALSE, rcEdit); // calculate the minimum tolerable width
UINT uMinWidth = ((rcCancel.right - rcCancel.left) + (rcSearch.right - rcSearch.left) + HISTSRCH_BUTTONDIST + rcEdit.left + rcAnimSize.right + 1);
if (uWidth < uMinWidth) uWidth = uMinWidth;
HDWP hdwp = BeginDeferWindowPos(5);
if (hdwp) { // align the animation box with the upper-right corner
DeferWindowPos(hdwp, hwndAnim, HWND_TOP, uWidth - rcAnimSize.right, 0, rcAnimSize.right, rcAnimSize.bottom, SWP_NOZORDER); // stretch the textbox as wide as possible
UINT uNewTextWidth = uWidth - rcAnimSize.right - 1 - rcEdit.left; DeferWindowPos(hdwp, hwndEdit, HWND_TOP, rcEdit.left, rcEdit.top, uNewTextWidth, rcEdit.bottom - rcEdit.top, SWP_NOZORDER); // static text should not be longer than edit textbox
HWND hwndStatic = _GetHwndAndRect(hwndDlg, IDC_HISTSRCH_STATIC, FALSE, rcStatic); DeferWindowPos(hdwp, hwndStatic, HWND_TOP, rcEdit.left, rcStatic.top, uNewTextWidth, rcStatic.bottom - rcStatic.top, SWP_NOZORDER); // align the cancel button with the right of the edit box
UINT uCancelLeft = uWidth - rcAnimSize.right - 1 - (rcCancel.right - rcCancel.left); DeferWindowPos(hdwp, hwndCancel, HWND_TOP, uCancelLeft, rcCancel.top, rcCancel.right - rcCancel.left, rcCancel.bottom - rcCancel.top, SWP_NOZORDER); // align the search button so that it ends six pixels (HISTSRCH_BUTTONDIST)
// to the left of the cancel button
DeferWindowPos(hdwp, hwndSearch, HWND_TOP, uCancelLeft - HISTSRCH_BUTTONDIST - (rcSearch.right - rcSearch.left), rcSearch.top, rcSearch.right - rcSearch.left, rcSearch.bottom - rcSearch.top, SWP_NOZORDER);
EndDeferWindowPos(hdwp); } } else return FALSE; break; } case WM_COMMAND: { CHistBand *phb = reinterpret_cast<CHistBand *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
switch (LOWORD(wParam)) { case IDC_EDITHISTSEARCH: switch (HIWORD(wParam)) { case EN_SETFOCUS: // This guy allows us to intercept TranslateAccelerator messages
// like backspace. This is the same as calling UIActivateIO(TRUE), but
// doesn't cause an infinite setfocus loop in Win95
IUnknown_OnFocusChangeIS(phb->_punkSite, SAFECAST(phb, IInputObject*), TRUE); SetFocus((HWND)lParam); break; case EN_CHANGE: // Enable 'Go Fish' button iff there is text in the edit box
EnableWindow(GetDlgItem(hwndDlg, IDB_HISTSRCH_GO), (bool) SendDlgItemMessage(hwndDlg, IDC_EDITHISTSEARCH, EM_LINELENGTH, 0, 0)); break; } break; case IDB_HISTSRCH_GO: { TCHAR szSearchString[MAX_PATH]; if (GetDlgItemText(hwndDlg, IDC_EDITHISTSEARCH, szSearchString, ARRAYSIZE(szSearchString))) { IServiceProvider *pServiceProvider; HRESULT hr = IUnknown_QueryService(phb->_punkSite, SID_SProxyBrowser, IID_IServiceProvider, (void **)&pServiceProvider);
if (SUCCEEDED(hr)) { IWebBrowser2 *pWebBrowser2; hr = pServiceProvider->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (void **)&pWebBrowser2); if (SUCCEEDED(hr)) { ::PutFindText(pWebBrowser2, szSearchString); pWebBrowser2->Release(); }
pServiceProvider->Release(); }
phb->_ExecuteSearch(szSearchString); } } break; case IDCANCEL: { if (phb->_EnsureSearch()) { phb->_psfSearch->CancelAsyncSearch(phb->_pidlSearch, NULL); } break; } default: return FALSE; } } return FALSE;
case WM_SEARCH_STATE: { BOOL fStart = (BOOL)wParam; if (fStart) Animate_Play(GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION), 0, -1, -1); else { HWND hwndAnim = GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION); Animate_Stop(hwndAnim); Animate_Seek(hwndAnim, 0); // reset the animation
//HACK for IE5 ship
//if there's only one item found in history search, the item doesn't display
//because someone (comctl32?) set redraw to false.
//so, manually force it to true when the search stops
CHistBand *phb = reinterpret_cast<CHistBand *>(GetWindowLongPtr(hwndDlg, DWLP_USER)); if (phb) SendMessage(phb->_hwndNSC, WM_SETREDRAW, TRUE, 0); } HWND hwndFocus = GetFocus();
EnableWindow(GetDlgItem(hwndDlg, IDC_EDITHISTSEARCH), !fStart); EnableWindow(GetDlgItem(hwndDlg, IDB_HISTSRCH_GO), !fStart); EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), fStart);
//make sure the focus goes to the right place
if ((NULL != hwndFocus) && (hwndFocus == GetDlgItem(hwndDlg, IDC_EDITHISTSEARCH) || (hwndFocus == GetDlgItem(hwndDlg, IDCANCEL)))) SetFocus(GetDlgItem(hwndDlg, fStart ? IDCANCEL : IDC_EDITHISTSEARCH)); break; }
default: return FALSE; } return TRUE; }
IShellFolderSearchable *CHistBand::_EnsureSearch() { ASSERT(_psfHistory); if (!_pidlSearch) { _psfHistory->QueryInterface(IID_IShellFolderSearchable, (LPVOID *)&_psfSearch); } return _psfSearch; }
HRESULT CHistBand::_ClearSearch() { HRESULT hr = S_FALSE;
if (_pidlSearch) { if (_EnsureSearch()) { EVAL(SUCCEEDED(_psfSearch->CancelAsyncSearch(_pidlSearch, NULL))); hr = _psfSearch->InvalidateSearch(_pidlSearch, NULL); } ILFree(_pidlSearch); _pidlSearch = NULL; } return hr; } HRESULT CHistBand::_ExecuteSearch(LPTSTR pszSearchString) { HRESULT hr = E_FAIL; if (_EnsureSearch()) { _ClearSearch(); hr = _psfSearch->FindString(pszSearchString, NULL, reinterpret_cast<IUnknown *> (static_cast<IShellFolderSearchableCallback *> (this)), &_pidlSearch); if (SUCCEEDED(hr)) { _ChangePidl(ILCombine(_pidlHistory, _pidlSearch)); } } return hr; }
#ifdef SPLIT_HISTORY_VIEW_BUTTON
UINT CHistBand::_NextMenuItem() { if (_uViewCheckedItem + 1 > _nViews) return 1; else return _uViewCheckedItem + 1; } #endif
HRESULT CHistBand::_ViewPopupSelect(UINT idCmd) { HRESULT hr = E_FAIL;
if (idCmd == MENUID_SEARCH) { if (_uViewCheckedItem != MENUID_SEARCH) { // display the dialog box
if (SUCCEEDED(hr = _DoSearchUIStuff())) { _ChangePidl((LPITEMIDLIST)INVALID_HANDLE_VALUE); // blank out NSC
_uViewCheckedItem = MENUID_SEARCH; CheckMenuRadioItem(_hViewMenu, 1, _iMaxMenuID, _uViewCheckedItem, MF_BYCOMMAND); } } if (_hwndSearchDlg) SetFocus(GetDlgItem(_hwndSearchDlg, IDC_EDITHISTSEARCH)); } else { LPCITEMIDLIST pidlNewSelect = _MenuIDToPIDL(idCmd); if (pidlNewSelect) { if (ILIsEmpty(pidlNewSelect)) hr = _ChangePidl(ILClone(_pidlHistory)); else hr = _ChangePidl(ILCombine(_pidlHistory, pidlNewSelect));
if (SUCCEEDED(hr)) hr = _SelectPidl(NULL, TRUE, pidlNewSelect);
// deleted "&& _uViewCheckedItem >= 0" from test below
// because UINTs are by definition always >= 0
if (SUCCEEDED(hr)) { // get rid of search dialog -- its no longer needed
if (_hwndSearchDlg) { EndDialog(_hwndSearchDlg, 0); DestroyWindow(_hwndSearchDlg); _hwndSearchDlg = NULL; // invalidate the previous search and prepare for the next
_ClearSearch(); RECT rcSelf; GetClientRect(_hwnd, &rcSelf); _ResizeChildWindows(rcSelf.right, rcSelf.bottom, TRUE); } _uViewCheckedItem = idCmd; CheckMenuRadioItem(_hViewMenu, 1, _iMaxMenuID, _uViewCheckedItem, MF_BYCOMMAND); // write out the new selection to registry
EVAL(SUCCEEDED(_SetRegistryPersistView(_uViewCheckedItem))); hr = S_OK; } } } return hr; }
HRESULT CHistBand::_DoViewPopup(int x, int y) { if (!_hViewMenu) return E_FAIL;
HRESULT hr = E_FAIL;
UINT idCmd = TrackPopupMenu(_hViewMenu, TPM_RETURNCMD, x, y, 0, _hwnd, NULL); // Currently, re-selecting the menu item will cause the item to be refreshed
// This makes sense to me, but it can be prevented by
// testing idCmd != _uViewCheckedItem
if ( (idCmd > 0) ) { return _ViewPopupSelect(idCmd); } else hr = S_FALSE;
return hr; }
// Change the current select NSC pidl
// WARNING: The pidl passed in will be assimilated by us...
// We will deallocate it.
HRESULT CHistBand::_ChangePidl(LPITEMIDLIST pidl) { if (_pidl) ILFree(_pidl);
_pidl = pidl; if ((LPITEMIDLIST)INVALID_HANDLE_VALUE == pidl) _pidl = NULL; _pns->Initialize(pidl, (SHCONTF_FOLDERS | SHCONTF_NONFOLDERS), (NSS_DROPTARGET | NSS_BROWSERSELECT)); return S_OK; }
// _SelectPidl - Have NSC change the current selected pidl
//
// passing NULL for pidlSelect will select the current select pidl
HRESULT CHistBand::_SelectPidl(LPCITEMIDLIST pidlSelect, // <-Standard Hist-type pidl to select
BOOL fCreate, // <-create NSC item if not there?
LPCITEMIDLIST pidlView,/*=NULL*/ // <-special history view type or NULL
BOOL fReinsert /*=0*/) // <-reinsert pidl into NSC and re-sort
{ HRESULT hRes = S_OK; BOOL fFreePidlSelect = FALSE;
if ( (!pidlSelect) && ((pidlSelect = _GetCurrentSelectPidl())) ) fFreePidlSelect = TRUE;
if (pidlSelect) { LPITEMIDLIST pidlNewSelect = NULL;
// cache the last selected pidl
if (_pidlLastSelect != pidlSelect) { if (_pidlLastSelect) ILFree(_pidlLastSelect); _pidlLastSelect = ILClone(pidlSelect); }
if (pidlView && !ILIsEmpty(pidlView)) { IShellFolderViewType *psfvtInfo = _GetViewTypeInfo();
if (psfvtInfo) { LPITEMIDLIST pidlFromRoot = ILFindChild(_pidlHistory, pidlSelect); if (pidlFromRoot && !ILIsEmpty(pidlFromRoot)) { LPITEMIDLIST pidlNewFromRoot; if (SUCCEEDED(psfvtInfo->TranslateViewPidl(pidlFromRoot, pidlView, &pidlNewFromRoot))) { if (pidlNewFromRoot) { pidlNewSelect = ILCombine(_pidlHistory, pidlNewFromRoot); if (pidlNewSelect) { _pns->SetSelectedItem(pidlNewSelect, fCreate, fReinsert, 0); ILFree(pidlNewSelect); } ILFree(pidlNewFromRoot); } } } psfvtInfo->Release(); } } else _pns->SetSelectedItem(pidlSelect, fCreate, fReinsert, 0);
if (fFreePidlSelect) ILFree(const_cast<LPITEMIDLIST>(pidlSelect)); } return hRes; }
HRESULT CHistBand::_SetRegistryPersistView(int iMenuID) { LPCITEMIDLIST pidlReg = _MenuIDToPIDL(iMenuID);
if (!pidlReg) return E_FAIL;
LONG lRet = (SHRegSetUSValue(REGSTR_PATH_MAIN, REGKEY_HISTORY_VIEW, REG_BINARY, (LPVOID)pidlReg, ILGetSize(pidlReg), SHREGSET_HKCU | SHREGSET_FORCE_HKCU)); return HRESULT_FROM_WIN32(lRet); }
// Get the default view from the registry as a menu item
int CHistBand::_GetRegistryPersistView() { int iRegMenu = -1; DWORD dwType = REG_BINARY;
ITEMIDLIST pidlDefault = { 0 };
// make a preliminary call to find out the size of the data
DWORD cbData = 0; LONG error = SHRegGetUSValue(REGSTR_PATH_MAIN, REGKEY_HISTORY_VIEW, &dwType, NULL, &cbData, FALSE, &pidlDefault, sizeof(pidlDefault)); if (cbData) { LPITEMIDLIST pidlReg = ((LPITEMIDLIST)SHAlloc(cbData));
if (pidlReg) { error = SHRegGetUSValue(REGSTR_PATH_MAIN, REGKEY_HISTORY_VIEW, &dwType, (LPVOID)pidlReg, &cbData, FALSE, &pidlDefault, sizeof(pidlDefault));
if (error == ERROR_SUCCESS) iRegMenu = _PIDLToMenuID(pidlReg);
SHFree(pidlReg); } }
return iRegMenu; }
LPCITEMIDLIST CHistBand::_MenuIDToPIDL(UINT uMenuID) { ASSERT(_ppidlViewTypes); if ((uMenuID > 0) && (uMenuID <= _nViews)) return _ppidlViewTypes[uMenuID - 1]; return NULL; }
int CHistBand::_PIDLToMenuID(LPITEMIDLIST pidl) { ASSERT(_psfHistory && _ppidlViewTypes);
int iMenuID = -1;
// handle the empty pidl, which designates the
// default view, separately
if (ILIsEmpty(pidl)) iMenuID = 1; else { for (UINT u = 0; u < _nViews; ++u) { if (_psfHistory->CompareIDs(0, pidl, _ppidlViewTypes[u]) == 0) iMenuID = u + 1; } } return iMenuID; }
// remember to release return value
IShellFolderViewType* CHistBand::_GetViewTypeInfo() { IShellFolderViewType* psfvRet = NULL;
if (_psfvtCache) { _psfvtCache->AddRef(); psfvRet = _psfvtCache; } else if (_psfHistory) { // QI For the views
// We set the pointer because of a bad QI somewhere...
if (SUCCEEDED(_psfHistory->QueryInterface(IID_IShellFolderViewType, ((void**)&psfvRet)))) { _psfvtCache = psfvRet; psfvRet->AddRef(); // one released in destructor, another by caller
} else psfvRet = NULL; } return psfvRet; }
HRESULT CHistBand::_FreeViewInfo() { if (_ppidlViewTypes) { // the first pidl in this list is NULL, the default view
for (UINT u = 0; u < _nViews; ++u) if (EVAL(_ppidlViewTypes[u])) ILFree(_ppidlViewTypes[u]); LocalFree(_ppidlViewTypes); _ppidlViewTypes = NULL; } if (_ppszStrViewNames) { for (UINT u = 0; u < _nViews; ++u) if (EVAL(_ppszStrViewNames[u])) CoTaskMemFree(_ppszStrViewNames[u]); LocalFree(_ppszStrViewNames); _ppszStrViewNames = NULL; } return S_OK; }
// Load the popup menu (if there are views to be had)
HRESULT CHistBand::_InitViewPopup() { HRESULT hRes = E_FAIL;
_iMaxMenuID = 0;
if (SUCCEEDED((hRes = _GetHistoryViews()))) { if ((_hViewMenu = CreatePopupMenu())) { // the IDCMD for the view menu will always be
// one more than the index into the view tables
for (UINT u = 0; u < _nViews; ++u) { int iMenuID = _PIDLToMenuID(_ppidlViewTypes[u]); if (iMenuID >= 0) AppendMenu(_hViewMenu, MF_STRING, iMenuID, _ppszStrViewNames[u]); if (iMenuID > _iMaxMenuID) _iMaxMenuID = iMenuID; }
// retrieve the persisted view information
// and check the corresponding menu item
int iSelectMenuID = _GetRegistryPersistView(); if (iSelectMenuID < 0 || ((UINT)iSelectMenuID) > _nViews) iSelectMenuID = 1; //bogus menuid
_uViewCheckedItem = iSelectMenuID; CheckMenuRadioItem(_hViewMenu, 1, _nViews, _uViewCheckedItem, MF_BYCOMMAND); } }
#ifdef HISTORY_VIEWSEARCHMENU
// if this is a searchable shell folder, then add the search menu item
if (_EnsureSearch()) { hRes = S_OK;
// only add separator if there is a menu already!
if (!_hViewMenu) _hViewMenu = CreatePopupMenu(); else AppendMenu(_hViewMenu, MF_SEPARATOR, 0, NULL);
if (_hViewMenu) { TCHAR szSearchMenuText[MAX_PATH]; LoadString(MLGetHinst(), IDS_SEARCH_MENUOPT, szSearchMenuText, ARRAYSIZE(szSearchMenuText)); AppendMenu(_hViewMenu, MF_STRING, MENUID_SEARCH, szSearchMenuText); _iMaxMenuID = MENUID_SEARCH; } else hRes = E_FAIL; } #endif
return hRes; }
// This guy calls the enumerator
HRESULT CHistBand::_GetHistoryViews() { ASSERT(_psfHistory); HRESULT hRes = E_FAIL;
UINT cbViews; // how many views are allocated
ASSERT(VIEWTYPE_MAX > 0);
EVAL(SUCCEEDED(_FreeViewInfo()));
IShellFolderViewType *psfViewType = _GetViewTypeInfo();
if (psfViewType) { // allocate buffers to store the view information
_ppidlViewTypes = ((LPITEMIDLIST *)LocalAlloc(LPTR, VIEWTYPE_MAX * sizeof(LPITEMIDLIST))); if (_ppidlViewTypes) { _ppszStrViewNames = ((LPTSTR *)LocalAlloc(LPTR, VIEWTYPE_MAX * sizeof(LPTSTR))); if (_ppszStrViewNames) { IEnumIDList *penum = NULL; cbViews = VIEWTYPE_MAX; _nViews = 1; // get the default view information
_ppidlViewTypes[0] = IEILCreate(sizeof(ITEMIDLIST)); if (_ppidlViewTypes[0] && SUCCEEDED((hRes = psfViewType->GetDefaultViewName(0, &(_ppszStrViewNames[0]))))) { // empty pidl will be the default
ASSERT(ILIsEmpty(_ppidlViewTypes[0])); // get the iterator for the other views
if (SUCCEEDED((hRes = psfViewType->EnumViews(0, &penum)))) { ULONG cFetched = 0; // iterate to get other view information
while(SUCCEEDED(hRes) && SUCCEEDED(penum->Next(1, &(_ppidlViewTypes[_nViews]), &cFetched)) && cFetched) { // get the name of this view
if (SUCCEEDED(DisplayNameOfAsOLESTR(_psfHistory, _ppidlViewTypes[_nViews], 0, &(_ppszStrViewNames[_nViews])))) { // prepare for next iteration by reallocating the buffer if necessary
if (_nViews > cbViews - 1) { LPITEMIDLIST *ppidlViewTypes = ((LPITEMIDLIST *)LocalReAlloc(_ppidlViewTypes, (cbViews + VIEWTYPE_REALLOC) * sizeof(LPITEMIDLIST), LMEM_MOVEABLE | LMEM_ZEROINIT)); if (ppidlViewTypes) { _ppidlViewTypes = ppidlViewTypes; LPTSTR * ppszStrViewNames = ((LPTSTR *)LocalReAlloc(_ppszStrViewNames, (cbViews + VIEWTYPE_REALLOC) * sizeof(LPTSTR), LMEM_MOVEABLE | LMEM_ZEROINIT)); if (ppszStrViewNames) { _ppszStrViewNames = ppszStrViewNames; cbViews += VIEWTYPE_REALLOC; } else { hRes = E_OUTOFMEMORY; break; } } else { hRes = E_OUTOFMEMORY; break; } } ++_nViews; } } penum->Release(); } } } } psfViewType->Release(); } return hRes; }
HRESULT CHistBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { // aggregation checking is handled in class factory
CHistBand * phb = new CHistBand();
if (!phb) return E_OUTOFMEMORY;
ASSERT(phb->_pidlHistory == NULL && phb->_pidlLastSelect == NULL && phb->_pidl == NULL && phb->_psfvtCache == NULL);
if (SUCCEEDED(SHGetHistoryPIDL(&(phb->_pidlHistory))) && SUCCEEDED(IEBindToObject(phb->_pidlHistory, &(phb->_psfHistory)))) { HRESULT hResLocal = E_FAIL;
// if we can get different views, then init with the persisted
// view type, otherwise, init with the top-level history type
if (SUCCEEDED(phb->_InitViewPopup())) { LPCITEMIDLIST pidlInit = phb->_MenuIDToPIDL(phb->_uViewCheckedItem); if (pidlInit) { LPITEMIDLIST pidlFullInit = ILCombine(phb->_pidlHistory, pidlInit); if (pidlFullInit) { hResLocal = phb->_Init(pidlFullInit); ILFree(pidlFullInit); } } } else hResLocal = phb->_Init(phb->_pidlHistory);
// From old favband code: // if (SUCCEEDED(phb->_Init((LPCITEMIDLIST)CSIDL_FAVORITES)))
if (SUCCEEDED(hResLocal)) { phb->_pns = CNscTree_CreateInstance(); if (phb->_pns) { ASSERT(poi); phb->_poi = poi; // if you change this cast, fix up CChannelBand_CreateInstance
*ppunk = SAFECAST(phb, IDeskBand *);
IUnknown_SetSite(phb->_pns, *ppunk); phb->_SetNscMode(MODE_HISTORY); return S_OK; } } }
phb->Release();
return E_FAIL; }
// Ask the powers that be which pidl is selected...
LPITEMIDLIST CHistBand::_GetCurrentSelectPidl(IOleCommandTarget *poctProxy/* = NULL*/) { LPITEMIDLIST pidlRet = NULL; VARIANT var; BOOL fReleaseProxy = FALSE; VariantInit(&var); var.vt = VT_EMPTY;
if (poctProxy == NULL) { IBrowserService *pswProxy; if (SUCCEEDED(QueryService(SID_SProxyBrowser, IID_PPV_ARG(IBrowserService, &pswProxy)))) { ASSERT(pswProxy); if (FAILED(pswProxy->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &poctProxy)))) { pswProxy->Release(); return NULL; } else fReleaseProxy = TRUE;
pswProxy->Release(); } }
// Inquire the current select pidl
if ((SUCCEEDED(poctProxy->Exec(&CGID_Explorer, SBCMDID_GETHISTPIDL, OLECMDEXECOPT_PROMPTUSER, NULL, &var))) && (var.vt != VT_EMPTY)) { pidlRet = VariantToIDList(&var); VariantClearLazy(&var); } if (fReleaseProxy) poctProxy->Release(); return pidlRet; }
// gets called by CNSCBand::ShowDW every time history band is shown
HRESULT CHistBand::_OnRegisterBand(IOleCommandTarget *poctProxy) { HRESULT hRes = E_FAIL; if (_uViewCheckedItem != MENUID_SEARCH) { LPITEMIDLIST pidlSelect = _GetCurrentSelectPidl(poctProxy); if (pidlSelect) { _SelectPidl(pidlSelect, TRUE); ILFree(pidlSelect); hRes = S_OK; } } return hRes; }
HRESULT CHistBand::_InitializeNsc() { return _pns->Initialize(_pidl, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, NSS_NOHISTSELECT | NSS_DROPTARGET | NSS_BROWSERSELECT); }
BOOL CHistBand::_ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib) { return !(ulAttrib & SFGAO_FOLDER); }
HRESULT CHistBand::_NavigateRightPane(IShellBrowser *psb, LPCITEMIDLIST pidl) { HRESULT hr = psb->BrowseObject(pidl, SBSP_SAMEBROWSER | SBSP_NOAUTOSELECT); if (SUCCEEDED(hr)) { IOleCommandTarget *poctProxy; if (SUCCEEDED(QueryService(SID_SProxyBrowser, IID_PPV_ARG(IOleCommandTarget, &poctProxy)))) { VARIANTARG var; InitVariantFromIDList(&var, pidl); poctProxy->Exec(&CGID_Explorer, SBCMDID_SELECTHISTPIDL, OLECMDEXECOPT_PROMPTUSER, &var, NULL); VariantClear(&var); poctProxy->Release(); } UEMFireEvent(&UEMIID_BROWSER, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_NAVIGATE, UIBL_NAVHIST); } return hr; }
|