|
|
/**************************************************************************
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
Copyright 1998 Microsoft Corporation. All Rights Reserved. **************************************************************************/
/**************************************************************************
File: ShlView.cpp Description: Implements IShellView.
**************************************************************************/
/**************************************************************************
#include statements
**************************************************************************/
#include "ShlView.h"
#include "Guid.h"
#include "Commands.h"
#include "resource.h"
#include "Tools.h"
#include "ViewList.h"
#include "DropSrc.h"
/**************************************************************************
global variables **************************************************************************/
MYTOOLINFO g_Tools[] = { IDB_VIEW_SMALL_COLOR, IDM_NEW_FOLDER, VIEW_NEWFOLDER, IDS_NEW_FOLDER, TBSTATE_ENABLED, TBSTYLE_BUTTON, IDB_STD_SMALL_COLOR, IDM_NEW_ITEM, STD_FILENEW, IDS_NEW_ITEM, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, IDM_SEPARATOR, 0, 0, 0, TBSTYLE_SEP, IDB_VIEW_SMALL_COLOR, IDM_VIEW_LARGE, VIEW_LARGEICONS, IDS_VIEW_LARGE, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, IDB_VIEW_SMALL_COLOR, IDM_VIEW_SMALL, VIEW_SMALLICONS, IDS_VIEW_SMALL, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, IDB_VIEW_SMALL_COLOR, IDM_VIEW_LIST, VIEW_LIST, IDS_VIEW_LIST, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, IDB_VIEW_SMALL_COLOR, IDM_VIEW_DETAILS, VIEW_DETAILS, IDS_VIEW_DETAILS, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, 0, -1, 0, 0, 0, 0, };
extern CViewList *g_pViewList;
/**************************************************************************
CShellView::CShellView()
**************************************************************************/
CShellView::CShellView(CShellFolder *pFolder, LPCITEMIDLIST pidl) { g_DllRefCount++;
#ifdef INITCOMMONCONTROLSEX
INITCOMMONCONTROLSEX iccex; iccex.dwSize = sizeof(INITCOMMONCONTROLSEX); iccex.dwICC = ICC_LISTVIEW_CLASSES; InitCommonControlsEx(&iccex);
#else
InitCommonControls();
#endif //INITCOMMONCONTROLSEX
m_hMenu = NULL; m_fInEdit = FALSE; m_hAccels = LoadAccelerators(g_hInst, MAKEINTRESOURCE(IDR_ACCELS));
m_pPidlMgr = new CPidlMgr(); if(!m_pPidlMgr) { delete this; return; }
m_psfParent = pFolder; if(m_psfParent) m_psfParent->AddRef();
//get the shell's IMalloc pointer
//we'll keep this until we get destroyed
if(FAILED(SHGetMalloc(&m_pMalloc))) { delete this; return; }
m_pidl = m_pPidlMgr->Copy(pidl);
m_uState = SVUIA_DEACTIVATE;
if(g_pViewList) g_pViewList->AddToList(this);
m_ObjRefCount = 1; }
/**************************************************************************
CShellView::~CShellView()
**************************************************************************/
CShellView::~CShellView() { if(g_pViewList) g_pViewList->RemoveFromList(this);
if(m_pidl) { m_pPidlMgr->Delete(m_pidl); m_pidl = NULL; }
if(m_psfParent) m_psfParent->Release();
if(m_pMalloc) { m_pMalloc->Release(); }
if(m_pPidlMgr) { delete m_pPidlMgr; }
g_DllRefCount--; }
///////////////////////////////////////////////////////////////////////////
//
// IUnknown Implementation
//
/**************************************************************************
CShellView::QueryInterface
**************************************************************************/
STDMETHODIMP CShellView::QueryInterface(REFIID riid, LPVOID *ppReturn) { *ppReturn = NULL;
//IUnknown
if(IsEqualIID(riid, IID_IUnknown)) { *ppReturn = this; }
//IOleWindow
else if(IsEqualIID(riid, IID_IOleWindow)) { *ppReturn = (IOleWindow*)this; }
//IShellView
else if(IsEqualIID(riid, IID_IShellView)) { *ppReturn = (IShellView*)this; }
if(*ppReturn) { (*(LPUNKNOWN*)ppReturn)->AddRef(); return S_OK; }
return E_NOINTERFACE; }
/**************************************************************************
CShellView::AddRef
**************************************************************************/
STDMETHODIMP_(DWORD) CShellView::AddRef() { return ++m_ObjRefCount; }
/**************************************************************************
CShellView::Release
**************************************************************************/
STDMETHODIMP_(DWORD) CShellView::Release() { if(--m_ObjRefCount == 0) { delete this; return 0; } return m_ObjRefCount; }
///////////////////////////////////////////////////////////////////////////
//
// IOleWindow Implementation
//
/**************************************************************************
CShellView::GetWindow() **************************************************************************/
STDMETHODIMP CShellView::GetWindow(HWND *phWnd) { *phWnd = m_hWnd;
return S_OK; }
/**************************************************************************
CShellView::ContextSensitiveHelp() **************************************************************************/
STDMETHODIMP CShellView::ContextSensitiveHelp(BOOL fEnterMode) { return E_NOTIMPL; }
///////////////////////////////////////////////////////////////////////////
//
// IShellView Implementation
//
/**************************************************************************
CShellView::TranslateAccelerator() **************************************************************************/
STDMETHODIMP CShellView::TranslateAccelerator(LPMSG pmsg) { if(m_fInEdit) { if((pmsg->message >= WM_KEYFIRST) && (pmsg->message <= WM_KEYLAST)) { TranslateMessage(pmsg); DispatchMessage(pmsg); return S_OK; } } else if(::TranslateAccelerator(m_hWnd, m_hAccels, pmsg)) return S_OK;
return S_FALSE; }
/**************************************************************************
CShellView::EnableModeless() **************************************************************************/
STDMETHODIMP CShellView::EnableModeless(BOOL fEnable) { return E_NOTIMPL; }
/**************************************************************************
CShellView::OnActivate() **************************************************************************/
LRESULT CShellView::OnActivate(UINT uState) { //don't do anything if the state isn't really changing
if(m_uState == uState) return S_OK;
OnDeactivate();
//only do this if we are active
if(uState != SVUIA_DEACTIVATE) { //merge the menus
m_hMenu = CreateMenu(); if(m_hMenu) { OLEMENUGROUPWIDTHS omw = {0, 0, 0, 0, 0, 0}; MENUITEMINFO mii;
m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
//add your top level sub-menu here, if desired
//get the view menu so we can merge with it
ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_SUBMENU; //merge our items into the File menu
if(GetMenuItemInfo(m_hMenu, FCIDM_MENU_FILE, FALSE, &mii)) { MergeFileMenu(mii.hSubMenu, (BOOL)(SVUIA_ACTIVATE_FOCUS == uState)); }
//merge our items into the Edit menu
if(GetMenuItemInfo(m_hMenu, FCIDM_MENU_EDIT, FALSE, &mii)) { MergeEditMenu(mii.hSubMenu, (BOOL)(SVUIA_ACTIVATE_FOCUS == uState)); }
//merge our items into the View menu
if(GetMenuItemInfo(m_hMenu, FCIDM_MENU_VIEW, FALSE, &mii)) { MergeViewMenu(mii.hSubMenu); }
//add the items that should only be added if we have the focus
if(SVUIA_ACTIVATE_FOCUS == uState) { }
m_pShellBrowser->SetMenuSB(m_hMenu, NULL, m_hWnd); } }
m_uState = uState;
UpdateToolbar();
return 0; }
/**************************************************************************
CShellView::OnDeactivate() **************************************************************************/
VOID CShellView::OnDeactivate(VOID) { if(m_uState != SVUIA_DEACTIVATE) { if(m_hMenu) { m_pShellBrowser->SetMenuSB(NULL, NULL, NULL);
m_pShellBrowser->RemoveMenusSB(m_hMenu);
DestroyMenu(m_hMenu);
m_hMenu = NULL; }
m_uState = SVUIA_DEACTIVATE; } }
/**************************************************************************
CShellView::UIActivate()
This function activates the view window. Note that activating it will not change the focus, while setting the focus will activate it.
**************************************************************************/
STDMETHODIMP CShellView::UIActivate(UINT uState) { //don't do anything if the state isn't really changing
if(m_uState == uState) return S_OK;
//OnActivate handles the menu merging and internal state
OnActivate(uState);
//only do this if we are active
if(uState != SVUIA_DEACTIVATE) { TCHAR szName[MAX_PATH] = TEXT(""); LRESULT lResult; int nPartArray[1] = {-1}; //update the status bar
//set the number of parts
m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
//set the text for the parts
m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 0, (LPARAM)g_szExtTitle, &lResult); }
return S_OK; }
/**************************************************************************
CShellView::MergeFileMenu() **************************************************************************/
VOID CShellView::MergeFileMenu(HMENU hMenu, BOOL fFocus) { MENUITEMINFO mii; UINT uPos = 0;
ZeroMemory(&mii, sizeof(mii));
//uPos += AddFileMenuItems(hMenu, 0, IDM_SEPARATOR, FALSE);
uPos += AddFileMenuItems(hMenu, 0, 0, TRUE);
//add a separator
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; mii.fType = MFT_SEPARATOR; mii.wID = IDM_SEPARATOR; mii.fState = MFS_ENABLED;
//insert this item at the beginning of the menu
InsertMenuItem(hMenu, uPos, TRUE, &mii); uPos++;
if(fFocus) { TCHAR szText[MAX_PATH];
//add the Delete item
LoadString(g_hInst, IDS_DELETE, szText, sizeof(szText)); mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED; mii.dwTypeData = szText; mii.wID = IDM_DELETE; InsertMenuItem(hMenu, uPos, TRUE, &mii); uPos++;
//add the Rename item
LoadString(g_hInst, IDS_RENAME, szText, sizeof(szText)); mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED; mii.dwTypeData = szText; mii.wID = IDM_RENAME; InsertMenuItem(hMenu, uPos, TRUE, &mii); uPos++;
//add a separator
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; mii.fType = MFT_SEPARATOR; mii.wID = IDM_SEPARATOR; mii.fState = MFS_ENABLED; InsertMenuItem(hMenu, uPos, TRUE, &mii); uPos++; } }
/**************************************************************************
CShellView::MergeViewMenu() **************************************************************************/
VOID CShellView::MergeViewMenu(HMENU hMenu) { MENUITEMINFO mii;
ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii);
//add a separator at the correct position in the menu
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; mii.fType = MFT_SEPARATOR; mii.wID = IDM_SEPARATOR; mii.fState = MFS_ENABLED; InsertMenuItem(hMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, &mii);
AddViewMenuItems(hMenu, 0, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE); }
/**************************************************************************
CShellView::MergeEditMenu()
**************************************************************************/
VOID CShellView::MergeEditMenu(HMENU hMenu, BOOL fFocus) { if(hMenu) { MENUITEMINFO mii; TCHAR szText[MAX_PATH];
ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii);
if(fFocus) { LoadString(g_hInst, IDS_CUT, szText, sizeof(szText)); mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED; mii.dwTypeData = szText; mii.wID = IDM_CUT; InsertMenuItem(hMenu, -1, TRUE, &mii);
LoadString(g_hInst, IDS_COPY, szText, sizeof(szText)); mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED; mii.dwTypeData = szText; mii.wID = IDM_COPY; InsertMenuItem(hMenu, -1, TRUE, &mii); }
//add the paste menu items at the correct position in the menu
LoadString(g_hInst, IDS_PASTE, szText, sizeof(szText)); mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED; mii.dwTypeData = szText; mii.wID = IDM_PASTE; InsertMenuItem(hMenu, -1, TRUE, &mii); } }
/**************************************************************************
CShellView::MergeToolbar() **************************************************************************/
VOID CShellView::MergeToolbar(VOID) { int i; TBADDBITMAP tbab; LRESULT lStdOffset; LRESULT lViewOffset;
m_pShellBrowser->SetToolbarItems(NULL, 0, FCT_MERGE); tbab.hInst = HINST_COMMCTRL; tbab.nID = (int)IDB_STD_SMALL_COLOR; m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 0, (LPARAM)&tbab, &lStdOffset);
tbab.hInst = HINST_COMMCTRL; tbab.nID = (int)IDB_VIEW_SMALL_COLOR; m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 0, (LPARAM)&tbab, &lViewOffset);
//get the number of items in tool array
for(i = 0; -1 != g_Tools[i].idCommand; i++) { }
LPTBBUTTON ptbb = (LPTBBUTTON)GlobalAlloc(GPTR, sizeof(TBBUTTON) * i);
if(ptbb) { for(i = 0; -1 != g_Tools[i].idCommand; i++) { (ptbb + i)->iBitmap = 0; switch(g_Tools[i].uImageSet) { case IDB_STD_SMALL_COLOR: (ptbb + i)->iBitmap = lStdOffset + g_Tools[i].iImage; break;
case IDB_VIEW_SMALL_COLOR: (ptbb + i)->iBitmap = lViewOffset + g_Tools[i].iImage; break; }
(ptbb + i)->idCommand = g_Tools[i].idCommand; (ptbb + i)->fsState = g_Tools[i].bState; (ptbb + i)->fsStyle = g_Tools[i].bStyle; (ptbb + i)->dwData = 0; (ptbb + i)->iString = 0; } m_pShellBrowser->SetToolbarItems(ptbb, i, FCT_MERGE); GlobalFree((HGLOBAL)ptbb); }
UpdateToolbar(); }
/**************************************************************************
CShellView::Refresh() **************************************************************************/
STDMETHODIMP CShellView::Refresh(VOID) { //empty the list
ListView_DeleteAllItems(m_hwndList);
//refill the list
FillList();
return S_OK; }
/**************************************************************************
CShellView::CreateViewWindow() **************************************************************************/
STDMETHODIMP CShellView::CreateViewWindow( LPSHELLVIEW pPrevView, LPCFOLDERSETTINGS lpfs, LPSHELLBROWSER psb, LPRECT prcView, HWND *phWnd) { WNDCLASS wc;
*phWnd = NULL;
//if our window class has not been registered, then do so
if(!GetClassInfo(g_hInst, NS_CLASS_NAME, &wc)) { ZeroMemory(&wc, sizeof(wc)); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = g_hInst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = NS_CLASS_NAME; if(!RegisterClass(&wc)) return E_FAIL; }
//set up the member variables
m_pShellBrowser = psb; m_FolderSettings = *lpfs;
//get our parent window
m_pShellBrowser->GetWindow(&m_hwndParent);
*phWnd = CreateWindowEx( 0, NS_CLASS_NAME, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, prcView->left, prcView->top, prcView->right - prcView->left, prcView->bottom - prcView->top, m_hwndParent, NULL, g_hInst, (LPVOID)this); if(!*phWnd) return E_FAIL;
MergeToolbar();
m_pShellBrowser->AddRef();
return S_OK; }
/**************************************************************************
CShellView::DestroyViewWindow() **************************************************************************/
STDMETHODIMP CShellView::DestroyViewWindow(VOID) { //Make absolutely sure all our UI is cleaned up.
UIActivate(SVUIA_DEACTIVATE);
if(m_hMenu) DestroyMenu(m_hMenu);
DestroyWindow(m_hWnd);
//release the shell browser object
m_pShellBrowser->Release();
return S_OK; }
/**************************************************************************
CShellView::GetCurrentInfo() **************************************************************************/
STDMETHODIMP CShellView::GetCurrentInfo(LPFOLDERSETTINGS lpfs) { *lpfs = m_FolderSettings;
return S_OK; }
/**************************************************************************
CShellView::AddPropertySheetPages() **************************************************************************/
STDMETHODIMP CShellView::AddPropertySheetPages( DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lParam) { return E_NOTIMPL; }
/**************************************************************************
CShellView::SaveViewState() **************************************************************************/
STDMETHODIMP CShellView::SaveViewState(VOID) { return S_OK; }
/**************************************************************************
CShellView::SelectItem() **************************************************************************/
STDMETHODIMP CShellView::SelectItem(LPCITEMIDLIST pidlItem, UINT uFlags) { return E_NOTIMPL; }
/**************************************************************************
CShellView::GetItemObject() **************************************************************************/
STDMETHODIMP CShellView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut) { *ppvOut = NULL;
return E_NOTIMPL; }
/**************************************************************************
CShellView::WndProc() **************************************************************************/
LRESULT CALLBACK CShellView::WndProc( HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { CShellView *pThis = (CShellView*)GetWindowLong(hWnd, VIEW_POINTER_OFFSET);
switch (uMessage) { case WM_NCCREATE: { LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam; pThis = (CShellView*)(lpcs->lpCreateParams); SetWindowLong(hWnd, VIEW_POINTER_OFFSET, (LONG)pThis);
//set the window handle
pThis->m_hWnd = hWnd; } break; case WM_SIZE: return pThis->OnSize(LOWORD(lParam), HIWORD(lParam)); case WM_CREATE: return pThis->OnCreate(); case WM_DESTROY: return pThis->OnDestroy(); case WM_SETFOCUS: return pThis->OnSetFocus(); case WM_KILLFOCUS: return pThis->OnKillFocus();
case WM_ACTIVATE: return pThis->OnActivate(SVUIA_ACTIVATE_FOCUS); case WM_COMMAND: return pThis->OnCommand( GET_WM_COMMAND_ID(wParam, lParam), GET_WM_COMMAND_CMD(wParam, lParam), GET_WM_COMMAND_HWND(wParam, lParam)); case WM_INITMENUPOPUP: return pThis->UpdateMenu((HMENU)wParam); case WM_NOTIFY: return pThis->OnNotify((UINT)wParam, (LPNMHDR)lParam); case WM_SETTINGCHANGE: return pThis->OnSettingChange((LPCTSTR)lParam);
case WM_CONTEXTMENU: { pThis->DoContextMenu(LOWORD(lParam), HIWORD(lParam), FALSE, (UINT)-1); return 0; } }
return DefWindowProc(hWnd, uMessage, wParam, lParam); }
/**************************************************************************
CShellView::OnSetFocus() **************************************************************************/
LRESULT CShellView::OnSetFocus(VOID) { /*
Tell the browser one of our windows has received the focus. This should always be done before merging menus (OnActivate merges the menus) if one of our windows has the focus. */ m_pShellBrowser->OnViewWindowActive(this);
OnActivate(SVUIA_ACTIVATE_FOCUS);
return 0; }
/**************************************************************************
CShellView::OnKillFocus() **************************************************************************/
LRESULT CShellView::OnKillFocus(VOID) { OnActivate(SVUIA_ACTIVATE_NOFOCUS);
return 0; }
/**************************************************************************
CShellView::OnCommand() **************************************************************************/
LRESULT CShellView::OnCommand(DWORD dwCmdID, DWORD dwCmd, HWND hwndCmd) { //ignore command messages while in edit mode
if(m_fInEdit) return 0;
DoContextMenu(0, 0, FALSE, dwCmdID);
return 0; }
/**************************************************************************
CShellView::UpdateMenu() **************************************************************************/
LRESULT CShellView::UpdateMenu(HMENU hMenu) { UINT uCommand;
//enable/disable your menu items here
OpenClipboard(NULL); HGLOBAL hClip = GetClipboardData(RegisterClipboardFormat(CFSTR_SAMPVIEWDATA)); CloseClipboard();
EnableMenuItem(hMenu, IDM_PASTE, MF_BYCOMMAND | (hClip ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
uCommand = ListView_GetSelectedCount(m_hwndList); EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | (uCommand ? MF_ENABLED : MF_DISABLED | MF_GRAYED)); EnableMenuItem(hMenu, IDM_COPY, MF_BYCOMMAND | (uCommand ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
switch(m_FolderSettings.ViewMode) { case FVM_ICON: uCommand = IDM_VIEW_LARGE; break;
case FVM_SMALLICON: uCommand = IDM_VIEW_SMALL; break;
case FVM_LIST: uCommand = IDM_VIEW_LIST; break;
case FVM_DETAILS: default: uCommand = IDM_VIEW_DETAILS; break; }
CheckMenuRadioItem(hMenu, IDM_VIEW_LARGE, IDM_VIEW_DETAILS, uCommand, MF_BYCOMMAND);
return 0; }
/**************************************************************************
CShellView::UpdateToolbar()
**************************************************************************/
LRESULT CShellView::UpdateToolbar(VOID) { LRESULT lResult; UINT uCommand;
//enable/disable/check the toolbar items here
switch(m_FolderSettings.ViewMode) { case FVM_ICON: uCommand = IDM_VIEW_LARGE; break;
case FVM_SMALLICON: uCommand = IDM_VIEW_SMALL; break;
case FVM_LIST: uCommand = IDM_VIEW_LIST; break;
case FVM_DETAILS: default: uCommand = IDM_VIEW_DETAILS; break; }
m_pShellBrowser->SendControlMsg( FCW_TOOLBAR, TB_CHECKBUTTON, uCommand, MAKELPARAM(TRUE, 0), &lResult);
return 0; }
/**************************************************************************
CShellView::OnNotify() **************************************************************************/
#define MENU_MAX 100
LRESULT CShellView::OnNotify(UINT CtlID, LPNMHDR lpnmh) { switch(lpnmh->code) { /*
The original shell on NT will always send TTN_NEEDTEXTW, so handle the cases separately. */ case TTN_NEEDTEXTA: { LPNMTTDISPINFOA pttt = (LPNMTTDISPINFOA)lpnmh; int i;
for(i = 0; -1 != g_Tools[i].idCommand; i++) { if(g_Tools[i].idCommand == pttt->hdr.idFrom) { LoadStringA(g_hInst, g_Tools[i].idString, pttt->szText, sizeof(pttt->szText)); return TRUE; } } } break;
case TTN_NEEDTEXTW: { LPNMTTDISPINFOW pttt = (LPNMTTDISPINFOW)lpnmh; int i;
for(i = 0; -1 != g_Tools[i].idCommand; i++) { if(g_Tools[i].idCommand == pttt->hdr.idFrom) { LoadStringW(g_hInst, g_Tools[i].idString, pttt->szText, sizeof(pttt->szText)); return TRUE; } } } break;
case NM_SETFOCUS: OnSetFocus(); break;
case NM_KILLFOCUS: OnDeactivate(); break;
case HDN_ENDTRACK: { g_nColumn = ListView_GetColumnWidth(m_hwndList, 0); ListView_SetColumnWidth(m_hwndList, 1, LVSCW_AUTOSIZE_USEHEADER); } return 0; case LVN_DELETEITEM: { NM_LISTVIEW *lpnmlv = (NM_LISTVIEW*)lpnmh; //delete the pidl because we made a copy of it
m_pPidlMgr->Delete((LPITEMIDLIST)lpnmlv->lParam); } break; #ifdef LVN_ITEMACTIVATE
case LVN_ITEMACTIVATE:
#else //LVN_ITEMACTIVATE
case NM_DBLCLK: case NM_RETURN:
#endif //LVN_ITEMACTIVATE
DoContextMenu(0, 0, TRUE, (DWORD)-1); return 0; case LVN_GETDISPINFO: { NMLVDISPINFO *lpdi = (NMLVDISPINFO*)lpnmh; LPITEMIDLIST pidl = (LPITEMIDLIST)lpdi->item.lParam;
//is the sub-item information being requested?
if(lpdi->item.iSubItem) { //is the text being requested?
if(lpdi->item.mask & LVIF_TEXT) { //is this a folder or a value?
if(m_pPidlMgr->IsFolder(pidl)) { LoadString(g_hInst, IDS_FOLDER_DATA, lpdi->item.pszText, lpdi->item.cchTextMax); } //its an item
else { m_pPidlMgr->GetData(pidl, lpdi->item.pszText, lpdi->item.cchTextMax); } } } //the item text is being requested
else { //is the text being requested?
if(lpdi->item.mask & LVIF_TEXT) { STRRET str;
if(SUCCEEDED(m_psfParent->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &str))) { GetTextFromSTRRET(m_pMalloc, &str, pidl, lpdi->item.pszText, lpdi->item.cchTextMax); } }
//is the image being requested?
if(lpdi->item.mask & LVIF_IMAGE) { IExtractIcon *pei;
if(SUCCEEDED(m_psfParent->GetUIObjectOf(m_hWnd, 1, (LPCITEMIDLIST*)&pidl, IID_IExtractIcon, NULL, (LPVOID*)&pei))) { UINT uFlags;
//GetIconLocation will give us the index into our image list
pei->GetIconLocation(GIL_FORSHELL, NULL, 0, &lpdi->item.iImage, &uFlags);
pei->Release(); } } } } return 0; case LVN_BEGINLABELEDIT: { NMLVDISPINFO *lpdi = (NMLVDISPINFO*)lpnmh; LPITEMIDLIST pidl = (LPITEMIDLIST)lpdi->item.lParam; DWORD dwAttr = SFGAO_CANRENAME;
m_psfParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &dwAttr); if(SFGAO_CANRENAME & dwAttr) { m_fInEdit = TRUE; return FALSE; } } return TRUE; case LVN_ENDLABELEDIT: { LRESULT lResult = 0; NMLVDISPINFO *pdi = (NMLVDISPINFO*)lpnmh;
if(pdi->item.pszText) { //the user wants to keep the change
LVITEM lvItem; LPITEMIDLIST pidl; WCHAR wszNewName[MAX_PATH];
ZeroMemory(&lvItem, sizeof(lvItem)); lvItem.mask = LVIF_PARAM; lvItem.iItem = pdi->item.iItem; ListView_GetItem(m_hwndList, &lvItem);
LocalToWideChar(wszNewName, pdi->item.pszText, MAX_PATH); /*
This will cause this class' RenameItem function to be called. This can cause problems, so the m_fInEdit flag will prevent RenameItem from being called on this object. SetNameOf will also free the old PIDL, so we don't have to do it again. */ HRESULT hr = m_psfParent->SetNameOf(NULL, (LPITEMIDLIST)lvItem.lParam, wszNewName, 0, &pidl);
if(SUCCEEDED(hr) && pidl) { lvItem.mask = LVIF_PARAM; lvItem.lParam = (LPARAM)pidl; ListView_SetItem(m_hwndList, &lvItem); lResult = TRUE; } } m_fInEdit = FALSE; return lResult; } case LVN_BEGINDRAG: { HRESULT hr; IDataObject *pDataObject = NULL; UINT uItemCount; LPITEMIDLIST *aPidls;
//get the number of selected items
uItemCount = ListView_GetSelectedCount(m_hwndList); if(!uItemCount) return 0; aPidls = (LPITEMIDLIST*)m_pMalloc->Alloc(uItemCount * sizeof(LPITEMIDLIST)); if(aPidls) { int i; UINT x;
for(i = 0, x = 0; x < uItemCount && i < ListView_GetItemCount(m_hwndList); i++) { if(ListView_GetItemState(m_hwndList, i, LVIS_SELECTED)) { LVITEM lvItem;
lvItem.mask = LVIF_PARAM; lvItem.iItem = i;
ListView_GetItem(m_hwndList, &lvItem); aPidls[x] = (LPITEMIDLIST)lvItem.lParam; x++; } }
hr = m_psfParent->GetUIObjectOf( m_hWnd, uItemCount, (LPCITEMIDLIST*)aPidls, IID_IDataObject, NULL, (LPVOID*)&pDataObject); if(SUCCEEDED(hr) && pDataObject) { IDropSource *pDropSource = new CDropSource; DWORD dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE; DWORD dwAttributes = SFGAO_CANLINK;
hr = m_psfParent->GetAttributesOf( uItemCount, (LPCITEMIDLIST*)aPidls, &dwAttributes); if(SUCCEEDED(hr) && (dwAttributes & SFGAO_CANLINK)) { dwEffect |= DROPEFFECT_LINK; }
DoDragDrop( pDataObject, pDropSource, dwEffect, &dwEffect);
pDataObject->Release(); pDropSource->Release(); }
m_pMalloc->Free(aPidls); } } break; case LVN_ITEMCHANGED: { UpdateToolbar(); } break; }
return 0; }
/**************************************************************************
CShellView::OnSize() **************************************************************************/
LRESULT CShellView::OnSize(WORD wWidth, WORD wHeight) { //resize the ListView to fit our window
if(m_hwndList) { MoveWindow(m_hwndList, 0, 0, wWidth, wHeight, TRUE);
ListView_SetColumnWidth(m_hwndList, 0, g_nColumn); ListView_SetColumnWidth(m_hwndList, 1, LVSCW_AUTOSIZE_USEHEADER); }
return 0; }
/**************************************************************************
CShellView::OnCreate() **************************************************************************/
LRESULT CShellView::OnCreate(VOID) { //create the ListView
if(CreateList()) { if(InitList()) { FillList(); } }
HRESULT hr; IDropTarget *pdt;
//get the IDropTarget for this folder
hr = m_psfParent->CreateViewObject( m_hWnd, IID_IDropTarget, (LPVOID*)&pdt);
if(SUCCEEDED(hr)) { //register the window as a drop target
RegisterDragDrop(m_hWnd, pdt);
pdt->Release(); }
return 0; }
/**************************************************************************
CShellView::OnDestroy() **************************************************************************/
LRESULT CShellView::OnDestroy(VOID) { //unregister the window as a drop target
RevokeDragDrop(m_hWnd);
return 0; }
/**************************************************************************
CShellView::CreateList() **************************************************************************/
BOOL CShellView::CreateList(VOID) { DWORD dwStyle;
dwStyle = WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_NOSORTHEADER | LVS_SHAREIMAGELISTS | LVS_EDITLABELS;
switch(m_FolderSettings.ViewMode) { default: case FVM_ICON: dwStyle |= LVS_ICON; break;
case FVM_SMALLICON: dwStyle |= LVS_SMALLICON; break;
case FVM_LIST: dwStyle |= LVS_LIST; break;
case FVM_DETAILS: dwStyle |= LVS_REPORT; break;
}
if(FWF_AUTOARRANGE & m_FolderSettings.fFlags) dwStyle |= LVS_AUTOARRANGE;
m_hwndList = CreateWindowEx( WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL, dwStyle, 0, 0, 0, 0, m_hWnd, (HMENU)ID_LISTVIEW, g_hInst, NULL);
if(!m_hwndList) return FALSE;
GetShellSettings();
return TRUE; }
/**************************************************************************
CShellView::InitList() **************************************************************************/
BOOL CShellView::InitList(VOID) { LVCOLUMN lvColumn; TCHAR szString[MAX_PATH];
//empty the list
ListView_DeleteAllItems(m_hwndList);
//initialize the columns
lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvColumn.fmt = LVCFMT_LEFT; lvColumn.pszText = szString;
lvColumn.cx = g_nColumn; LoadString(g_hInst, IDS_COLUMN1, szString, sizeof(szString)); ListView_InsertColumn(m_hwndList, 0, &lvColumn);
lvColumn.cx = g_nColumn; LoadString(g_hInst, IDS_COLUMN2, szString, sizeof(szString)); ListView_InsertColumn(m_hwndList, 1, &lvColumn);
ListView_SetImageList(m_hwndList, g_himlLarge, LVSIL_NORMAL); ListView_SetImageList(m_hwndList, g_himlSmall, LVSIL_SMALL);
return TRUE; }
/**************************************************************************
CShellView::FillList() **************************************************************************/
VOID CShellView::FillList(VOID) { LPENUMIDLIST pEnumIDList;
if(SUCCEEDED(m_psfParent->EnumObjects(m_hWnd, SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, &pEnumIDList))) { LPITEMIDLIST pidl; DWORD dwFetched;
//turn the listview's redrawing off
SendMessage(m_hwndList, WM_SETREDRAW, FALSE, 0);
while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched) { AddItem(pidl); /*
*/ }
//sort the items
ListView_SortItems(m_hwndList, CompareItems, (LPARAM)m_psfParent); //turn the listview's redrawing back on and force it to draw
SendMessage(m_hwndList, WM_SETREDRAW, TRUE, 0); InvalidateRect(m_hwndList, NULL, TRUE); UpdateWindow(m_hwndList);
pEnumIDList->Release(); } }
/**************************************************************************
CShellView::GetShellSettings() **************************************************************************/
#if (_WIN32_IE >= 0x0400)
typedef VOID (WINAPI *PFNSHGETSETTINGSPROC)(LPSHELLFLAGSTATE lpsfs, DWORD dwMask);
VOID CShellView::GetShellSettings(VOID) { SHELLFLAGSTATE sfs; HINSTANCE hinstShell32;
/*
Since SHGetSettings is not implemented in all versions of the shell, get the function address manually at run time. This allows the extension to run on all platforms. */
ZeroMemory(&sfs, sizeof(sfs));
/*
The default, in case any of the following steps fails, is classic Windows 95 style. */ sfs.fWin95Classic = TRUE;
hinstShell32 = LoadLibrary(TEXT("shell32.dll")); if(hinstShell32) { PFNSHGETSETTINGSPROC pfnSHGetSettings;
pfnSHGetSettings = (PFNSHGETSETTINGSPROC)GetProcAddress(hinstShell32, "SHGetSettings"); if(pfnSHGetSettings) { (*pfnSHGetSettings)(&sfs, SSF_DOUBLECLICKINWEBVIEW | SSF_WIN95CLASSIC); } FreeLibrary(hinstShell32); }
DWORD dwExStyles = 0;
if(!sfs.fWin95Classic && !sfs.fDoubleClickInWebView) { dwExStyles |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT | LVS_EX_UNDERLINEHOT; }
ListView_SetExtendedListViewStyle(m_hwndList, dwExStyles); } #else
VOID CShellView::GetShellSettings(VOID) { } #endif
/**************************************************************************
CShellView::OnSettingChange() **************************************************************************/
LRESULT CShellView::OnSettingChange(LPCTSTR lpszSection) { if(0 == lstrcmpi(lpszSection, TEXT("ShellState"))) { GetShellSettings(); return 0; }
return 0; }
/**************************************************************************
CShellView::DoContextMenu() **************************************************************************/
VOID CShellView::DoContextMenu(WORD x, WORD y, BOOL fDefault, DWORD dwCmdIn) { UINT uSelected = 0; LPITEMIDLIST *aSelectedItems = NULL; LPCONTEXTMENU pContextMenu = NULL;
if(m_uState != SVUIA_ACTIVATE_NOFOCUS) { uSelected = ListView_GetSelectedCount(m_hwndList); }
if(uSelected) { aSelectedItems = (LPITEMIDLIST*)m_pMalloc->Alloc((uSelected + 1) * sizeof(LPITEMIDLIST));
if(aSelectedItems) { UINT i; LVITEM lvItem;
ZeroMemory(&lvItem, sizeof(lvItem)); lvItem.mask = LVIF_STATE | LVIF_PARAM; lvItem.stateMask = LVIS_SELECTED; lvItem.iItem = 0;
i = 0;
while(ListView_GetItem(m_hwndList, &lvItem) && (i < uSelected)) { if(lvItem.state & LVIS_SELECTED) { aSelectedItems[i] = (LPITEMIDLIST)lvItem.lParam; i++; } lvItem.iItem++; } m_psfParent->GetUIObjectOf( m_hwndParent, uSelected, (LPCITEMIDLIST*)aSelectedItems, IID_IContextMenu, NULL, (LPVOID*)&pContextMenu);
} } else { m_psfParent->CreateViewObject( m_hwndParent, IID_IContextMenu, (LPVOID*)&pContextMenu); }
if(pContextMenu) { HMENU hMenu = CreatePopupMenu();
/*
See if we are in Explore or Open mode. If the browser's tree is present, then we are in Explore mode. */ BOOL fExplore = FALSE; HWND hwndTree = NULL; if(SUCCEEDED(m_pShellBrowser->GetControlWindow(FCW_TREE, &hwndTree)) && hwndTree) { fExplore = TRUE; }
if(hMenu && SUCCEEDED(pContextMenu->QueryContextMenu( hMenu, 0, 0, MENU_MAX, CMF_NORMAL | (fExplore ? CMF_EXPLORE : 0) | ((uSelected > 1) ? MYCMF_MULTISELECT: 0)))) { UINT uCommand;
if(fDefault) { MENUITEMINFO mii; int nMenuIndex;
uCommand = 0; ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_STATE | MIIM_ID;
nMenuIndex = 0;
//find the default item in the menu
while(GetMenuItemInfo(hMenu, nMenuIndex, TRUE, &mii)) { if(mii.fState & MFS_DEFAULT) { uCommand = mii.wID; break; }
nMenuIndex++; } } else if(-1 != dwCmdIn) { //this command will get sent directly without bringing up the menu
uCommand = dwCmdIn; } else { uCommand = TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_RETURNCMD, x, y, 0, m_hWnd, NULL); } if(uCommand > 0) { //some commands need to be handled by the view itself
switch(uCommand) { case IDM_VIEW_LARGE: OnViewLarge(); break;
case IDM_VIEW_SMALL: OnViewSmall(); break;
case IDM_VIEW_LIST: OnViewList(); break;
case IDM_VIEW_DETAILS: OnViewDetails(); break;
default: { CMINVOKECOMMANDINFO cmi;
ZeroMemory(&cmi, sizeof(cmi)); cmi.cbSize = sizeof(cmi); cmi.hwnd = m_hWnd; cmi.lpVerb = (LPCSTR)MAKEINTRESOURCE(uCommand);
pContextMenu->InvokeCommand(&cmi); } break; }
}
DestroyMenu(hMenu); } pContextMenu->Release(); }
if(aSelectedItems) m_pMalloc->Free(aSelectedItems);
UpdateToolbar(); }
/**************************************************************************
CShellView::AddItem()
**************************************************************************/
BOOL CShellView::AddItem(LPCITEMIDLIST pidl) { LVITEM lvItem;
ZeroMemory(&lvItem, sizeof(lvItem));
//set the mask
lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
//add the item to the end of the list
lvItem.iItem = ListView_GetItemCount(m_hwndList);
//set the item's data
lvItem.lParam = (LPARAM)m_pPidlMgr->Copy(pidl);
//get text on a callback basis
lvItem.pszText = LPSTR_TEXTCALLBACK;
//get the image on a callback basis
lvItem.iImage = I_IMAGECALLBACK;
//add the item
if(-1 == ListView_InsertItem(m_hwndList, &lvItem)) return FALSE;
return TRUE; }
/**************************************************************************
CShellView::DeleteItem()
**************************************************************************/
BOOL CShellView::DeleteItem(LPCITEMIDLIST pidl) { //delete the item from the list
int nIndex = FindItemPidl(pidl);
if(-1 != nIndex) { return ListView_DeleteItem(m_hwndList, nIndex); }
return FALSE; }
/**************************************************************************
CShellView::RenameItem()
**************************************************************************/
BOOL CShellView::RenameItem(LPCITEMIDLIST pidlOld, LPCITEMIDLIST pidlNew) { //don't allow this to be called if this object is the being edited
if(m_fInEdit) return TRUE;
//find the item in the list
int nIndex = FindItemPidl(pidlOld);
if(-1 != nIndex) { BOOL fReturn; LVITEM lvItem;
ZeroMemory(&lvItem, sizeof(lvItem)); lvItem.mask = LVIF_PARAM; lvItem.iItem = nIndex; ListView_GetItem(m_hwndList, &lvItem); m_pPidlMgr->Delete((LPITEMIDLIST)lvItem.lParam);
ZeroMemory(&lvItem, sizeof(lvItem)); lvItem.mask = LVIF_PARAM; lvItem.iItem = nIndex; lvItem.lParam = (LPARAM)m_pPidlMgr->Copy(pidlNew); fReturn = ListView_SetItem(m_hwndList, &lvItem); ListView_Update(m_hwndList, nIndex); return fReturn; }
return FALSE; }
/**************************************************************************
CShellView::GetPidl()
**************************************************************************/
LPITEMIDLIST CShellView::GetPidl() { return m_psfParent->CreateFQPidl(NULL); }
/**************************************************************************
CShellView::GetFQPidl()
**************************************************************************/
LPITEMIDLIST CShellView::GetFQPidl() { return m_psfParent->CreateFQPidl(NULL); }
/**************************************************************************
CShellView::FindItemPidl()
**************************************************************************/
int CShellView::FindItemPidl(LPCITEMIDLIST pidl) { LVITEM lvItem;
ZeroMemory(&lvItem, sizeof(lvItem)); lvItem.mask = LVIF_PARAM;
for(lvItem.iItem = 0; ListView_GetItem(m_hwndList, &lvItem); lvItem.iItem++) { LPITEMIDLIST pidlFound = (LPITEMIDLIST)lvItem.lParam; HRESULT hr = m_psfParent->CompareIDs(0, pidl, pidlFound); if(SUCCEEDED(hr) && 0 == HRESULT_CODE(hr)) { //we found the item
return lvItem.iItem; } }
return -1; }
/**************************************************************************
CShellView::MarkItemsAsCut()
Marks the items as cut.
**************************************************************************/
VOID CShellView::MarkItemsAsCut(LPCITEMIDLIST *aPidls, UINT uItemCount) { UINT i;
for(i = 0; i < uItemCount; i++) { LPITEMIDLIST pidlTemp = m_pPidlMgr->GetLastItem(aPidls[i]); int nIndex = FindItemPidl(pidlTemp);
if(nIndex != -1) { ListView_SetItemState(m_hwndList, nIndex, LVIS_CUT, LVIS_CUT); } } }
/**************************************************************************
CShellView::EditItem()
**************************************************************************/
VOID CShellView::EditItem(LPCITEMIDLIST pidl) { int i;
i = FindItemPidl(pidl);
if(-1 != i) { SetFocus(m_hwndList);
//put the ListView into edit mode
ListView_EditLabel(m_hwndList, i); } }
/**************************************************************************
CShellView::UpdateData()
**************************************************************************/
VOID CShellView::UpdateData(LPCITEMIDLIST pidl) { int i;
i = FindItemPidl(pidl);
if(-1 != i) { LVITEM lvItem;
ZeroMemory(&lvItem, sizeof(lvItem)); lvItem.mask = LVIF_PARAM; lvItem.iItem = i; ListView_GetItem(m_hwndList, &lvItem); m_pPidlMgr->Delete((LPITEMIDLIST)lvItem.lParam);
ZeroMemory(&lvItem, sizeof(lvItem)); lvItem.mask = LVIF_PARAM; lvItem.iItem = i; lvItem.lParam = (LPARAM)m_pPidlMgr->Copy(pidl); ListView_SetItem(m_hwndList, &lvItem); ListView_Update(m_hwndList, i); } }
/**************************************************************************
CShellView::OnViewLarge()
**************************************************************************/
LRESULT CShellView::OnViewLarge(VOID) { m_FolderSettings.ViewMode = FVM_ICON;
DWORD dwStyle = GetWindowLong(m_hwndList, GWL_STYLE); dwStyle &= ~LVS_TYPEMASK; dwStyle |= LVS_ICON; SetWindowLong(m_hwndList, GWL_STYLE, dwStyle);
return 0; }
/**************************************************************************
CShellView::OnViewSmall()
**************************************************************************/
LRESULT CShellView::OnViewSmall(VOID) { m_FolderSettings.ViewMode = FVM_SMALLICON;
DWORD dwStyle = GetWindowLong(m_hwndList, GWL_STYLE); dwStyle &= ~LVS_TYPEMASK; dwStyle |= LVS_SMALLICON; SetWindowLong(m_hwndList, GWL_STYLE, dwStyle);
return 0; }
/**************************************************************************
CShellView::OnViewList()
**************************************************************************/
LRESULT CShellView::OnViewList(VOID) { m_FolderSettings.ViewMode = FVM_LIST;
DWORD dwStyle = GetWindowLong(m_hwndList, GWL_STYLE); dwStyle &= ~LVS_TYPEMASK; dwStyle |= LVS_LIST; SetWindowLong(m_hwndList, GWL_STYLE, dwStyle);
return 0; }
/**************************************************************************
CShellView::OnViewDetails()
**************************************************************************/
LRESULT CShellView::OnViewDetails(VOID) { m_FolderSettings.ViewMode = FVM_DETAILS;
DWORD dwStyle = GetWindowLong(m_hwndList, GWL_STYLE); dwStyle &= ~LVS_TYPEMASK; dwStyle |= LVS_REPORT; SetWindowLong(m_hwndList, GWL_STYLE, dwStyle);
return 0; }
|