493 lines
16 KiB
C++
493 lines
16 KiB
C++
#include "shellprv.h"
|
|
#include "defviewp.h"
|
|
#include "ids.h"
|
|
|
|
CColumnDlg::CColumnDlg(CDefView *pdsv) :
|
|
_pdsv(pdsv), _bChanged(FALSE), _pdwOrder(NULL), _pWidths(NULL), _bLoaded(FALSE), _bUpdating(FALSE), _ppui(NULL)
|
|
{
|
|
_cColumns = _pdsv->_vs.GetColumnCount();
|
|
}
|
|
|
|
CColumnDlg::~CColumnDlg()
|
|
{
|
|
if (_pdwOrder)
|
|
LocalFree(_pdwOrder);
|
|
if (_pWidths)
|
|
LocalFree(_pWidths);
|
|
|
|
if (_ppui)
|
|
_ppui->Release();
|
|
}
|
|
|
|
HRESULT CColumnDlg::ShowDialog(HWND hwnd)
|
|
{
|
|
_bChanged = FALSE; // We are on the stack, so no zero allocator
|
|
|
|
_pdwOrder = (UINT *) LocalAlloc(LPTR, sizeof(*_pdwOrder) * _cColumns); // total columns
|
|
_pWidths = (int *) LocalAlloc(LPTR, sizeof(*_pWidths) * _cColumns); // total columns
|
|
if (_pdwOrder && _pWidths)
|
|
{
|
|
DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_COLUMN_SETTINGS), hwnd, s_DlgProc, (LPARAM)this);
|
|
return S_OK;
|
|
}
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Remember, each column is identified in 3 ways...
|
|
// 1. A 'real' column number, the ordinal out of all possible columns
|
|
// 2. A 'visible' column number, the index to this column in the listview
|
|
// 3. A 'column order #', the position in the header's columnorderarray
|
|
|
|
void CColumnDlg::_OnInitDlg()
|
|
{
|
|
// Fill in order array with visible columns, and set up inverse table
|
|
UINT cVisible = _pdsv->_RealToVisibleCol(-1) + 1; // count
|
|
|
|
ListView_GetColumnOrderArray(_pdsv->_hwndListview, cVisible, _pdwOrder);
|
|
UINT *pOrderInverse = (UINT *)LocalAlloc(LPTR, sizeof(*pOrderInverse) * cVisible);
|
|
if (pOrderInverse)
|
|
{
|
|
for (UINT i = 0; i < cVisible; i++)
|
|
pOrderInverse[_pdwOrder[i]] = i;
|
|
|
|
_hwndLVAll = GetDlgItem(_hdlg, IDC_COL_LVALL);
|
|
|
|
ListView_SetExtendedListViewStyle(_hwndLVAll, LVS_EX_CHECKBOXES);
|
|
|
|
LV_COLUMN lvc = {0};
|
|
lvc.mask = (LVCF_FMT | LVCF_SUBITEM);
|
|
lvc.fmt = LVCFMT_LEFT;
|
|
ListView_InsertColumn(_hwndLVAll, 0, &lvc);
|
|
|
|
LV_ITEM lvi = {0};
|
|
lvi.mask = LVIF_TEXT;
|
|
|
|
// Add entry for each column (except non-UI columns)
|
|
for (i = 0; i < (int)_cColumns; i++)
|
|
{
|
|
if (!_pdsv->_IsColumnHidden(i)) // Don't put in entries for hidden columns
|
|
{
|
|
lvi.iItem = i;
|
|
lvi.pszText = LPSTR_TEXTCALLBACK;
|
|
ListView_InsertItem(_hwndLVAll, &lvi);
|
|
}
|
|
}
|
|
|
|
lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
|
|
// set the visible columns
|
|
for (i = 0; i < (int) cVisible; i++)
|
|
{
|
|
UINT iReal = _pdsv->_VisibleToRealCol(i);
|
|
|
|
lvi.pszText = _pdsv->_vs.GetColumnName(iReal);
|
|
lvi.state = INDEXTOSTATEIMAGEMASK(_pdsv->_IsDetailsColumn(iReal) ? 2 : 1); // on check mark (or off for tileview columns)
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
lvi.lParam = iReal; // store the real col index in the lParam
|
|
lvi.iItem = pOrderInverse[i];
|
|
ListView_SetItem(_hwndLVAll, &lvi);
|
|
|
|
// Get the column width from the view's listview
|
|
_pWidths[iReal] = ListView_GetColumnWidth(_pdsv->_hwndListview, i);
|
|
}
|
|
|
|
UINT iItem = cVisible;
|
|
for (i = 0; i < (int)_cColumns; i++)
|
|
{
|
|
if (!_pdsv->_IsColumnInListView(i) && !_pdsv->_IsColumnHidden(i))
|
|
{
|
|
lvi.pszText = _pdsv->_vs.GetColumnName(i);
|
|
lvi.state = INDEXTOSTATEIMAGEMASK(1); // off check mark
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
lvi.lParam = i;
|
|
lvi.iItem = iItem;
|
|
ListView_SetItem(_hwndLVAll, &lvi);
|
|
|
|
iItem++;
|
|
|
|
// get the default width we've got saved away
|
|
_pWidths[i] = _pdsv->_vs.GetColumnCharCount(i) * _pdsv->_cxChar;
|
|
}
|
|
}
|
|
|
|
// set the size properly
|
|
ListView_SetColumnWidth(_hwndLVAll, 0, LVSCW_AUTOSIZE);
|
|
|
|
ListView_SetItemState(_hwndLVAll, 0, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
|
|
LocalFree(pOrderInverse);
|
|
|
|
_bLoaded = TRUE;
|
|
}
|
|
SendDlgItemMessage(_hdlg, IDC_COL_WIDTH, EM_LIMITTEXT, 3, 0); // 3 digits
|
|
}
|
|
|
|
#define SWAP(x,y) {(x) ^= (y); (y) ^= (x); (x) ^= (y);}
|
|
|
|
void CColumnDlg::_MoveItem(int iDelta)
|
|
{
|
|
int i = ListView_GetSelectionMark(_hwndLVAll);
|
|
if (i != -1)
|
|
{
|
|
int iNew = i + iDelta;
|
|
if (iNew >= 0 && iNew <= (ListView_GetItemCount(_hwndLVAll) - 1))
|
|
{
|
|
LV_ITEM lvi = {0}, lvi2 = {0};
|
|
TCHAR szTmp1[MAX_COLUMN_NAME_LEN], szTmp2[MAX_COLUMN_NAME_LEN];
|
|
|
|
_bChanged = TRUE;
|
|
_bUpdating = TRUE;
|
|
|
|
lvi.iItem = i;
|
|
lvi.pszText = szTmp1;
|
|
lvi.cchTextMax = ARRAYSIZE(szTmp1);
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
|
|
|
|
lvi2.iItem = iNew;
|
|
lvi2.pszText = szTmp2;
|
|
lvi2.cchTextMax = ARRAYSIZE(szTmp2);
|
|
lvi2.stateMask = LVIS_STATEIMAGEMASK;
|
|
lvi2.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
|
|
|
|
ListView_GetItem(_hwndLVAll, &lvi);
|
|
ListView_GetItem(_hwndLVAll, &lvi2);
|
|
|
|
SWAP(lvi.iItem, lvi2.iItem);
|
|
|
|
ListView_SetItem(_hwndLVAll, &lvi);
|
|
ListView_SetItem(_hwndLVAll, &lvi2);
|
|
|
|
_bUpdating = FALSE;
|
|
|
|
// update selection
|
|
ListView_SetSelectionMark(_hwndLVAll, iNew);
|
|
ListView_SetItemState(_hwndLVAll, iNew , LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
|
|
// HACK: SetItemState sends notifications for i, iNew, then i again.
|
|
// we need to call it twice in a row, so _UpdateDlgButtons will get the right item
|
|
ListView_SetItemState(_hwndLVAll, iNew , LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
|
|
|
|
return;
|
|
}
|
|
}
|
|
TraceMsg(TF_WARNING, "ccd.mi couldn't move %d to %d",i, i+iDelta);
|
|
MessageBeep(MB_ICONEXCLAMATION);
|
|
}
|
|
|
|
BOOL CColumnDlg::_SaveState()
|
|
{
|
|
// Check order
|
|
if (_bChanged)
|
|
{
|
|
int iOrderIndex = 0;
|
|
LV_ITEM lvi = {0};
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
lvi.mask = LVIF_PARAM | LVIF_STATE;
|
|
|
|
int cItems = ListView_GetItemCount(_hwndLVAll);
|
|
for (int i = 0; i < cItems; i++)
|
|
{
|
|
lvi.iItem = i;
|
|
ListView_GetItem(_hwndLVAll, &lvi);
|
|
|
|
// toggle it, if the state in the dialog doesn't match the listview state
|
|
if (BOOLIFY(ListView_GetCheckState(_hwndLVAll, i)) != BOOLIFY(_pdsv->_IsDetailsColumn((UINT)lvi.lParam)))
|
|
{
|
|
_pdsv->_HandleColumnToggle((UINT)lvi.lParam, FALSE);
|
|
}
|
|
|
|
if (_pdsv->_IsColumnInListView((UINT)lvi.lParam))
|
|
_pdwOrder[iOrderIndex++] = (UINT)lvi.lParam; // incorrectly store real (not vis) col #, fix up below
|
|
}
|
|
|
|
// must be in a separate loop. (can't map real to visible, if we aren't done setting visible)
|
|
for (i = 0; i < iOrderIndex; i++)
|
|
{
|
|
UINT iReal = _pdwOrder[i];
|
|
_pdwOrder[i] = _pdsv->_RealToVisibleCol(iReal);
|
|
|
|
if (_pWidths[iReal] < 0) // negative width means they edited it
|
|
ListView_SetColumnWidth(_pdsv->_hwndListview, _pdwOrder[i], -_pWidths[iReal]);
|
|
}
|
|
|
|
ListView_SetColumnOrderArray(_pdsv->_hwndListview, iOrderIndex, _pdwOrder);
|
|
|
|
// kick the listview into repainting everything
|
|
InvalidateRect(_pdsv->_hwndListview, NULL, TRUE);
|
|
|
|
_bChanged = FALSE;
|
|
}
|
|
return !_bChanged;
|
|
}
|
|
|
|
BOOL EnableDlgItem(HWND hdlg, UINT idc, BOOL f)
|
|
{
|
|
return EnableWindow(GetDlgItem(hdlg, idc), f);
|
|
}
|
|
|
|
void CColumnDlg::_UpdateDlgButtons(NMLISTVIEW *pnmlv)
|
|
{
|
|
BOOL bChecked, bOldUpdateState = _bUpdating;
|
|
int iItem = ListView_GetSelectionMark(_hwndLVAll);
|
|
|
|
// to disable checking
|
|
_bUpdating = TRUE;
|
|
if (pnmlv->uNewState & LVIS_STATEIMAGEMASK)
|
|
bChecked = (pnmlv->uNewState & LVIS_STATEIMAGEMASK) == (UINT)INDEXTOSTATEIMAGEMASK(2);
|
|
else
|
|
bChecked = ListView_GetCheckState(_hwndLVAll, pnmlv->iItem);
|
|
|
|
EnableDlgItem(_hdlg, IDC_COL_UP, pnmlv->iItem > 0);
|
|
EnableDlgItem(_hdlg, IDC_COL_DOWN, pnmlv->iItem < (int)_cColumns - 1);
|
|
EnableDlgItem(_hdlg, IDC_COL_SHOW, !bChecked && (pnmlv->lParam != 0));
|
|
EnableDlgItem(_hdlg, IDC_COL_HIDE, bChecked && (pnmlv->lParam != 0));
|
|
|
|
// update the width edit box
|
|
int iWidth = _pWidths[pnmlv->lParam];
|
|
if (iWidth < 0)
|
|
iWidth = -iWidth; // we store negative values to track if it changed or not
|
|
SetDlgItemInt(_hdlg, IDC_COL_WIDTH, iWidth, TRUE);
|
|
|
|
_bUpdating = bOldUpdateState;
|
|
}
|
|
|
|
BOOL_PTR CALLBACK CColumnDlg::s_DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CColumnDlg *pcd = (CColumnDlg*) GetWindowLongPtr(hdlg, DWLP_USER);
|
|
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
pcd = (CColumnDlg *) lParam;
|
|
pcd->_hdlg = hdlg;
|
|
SetWindowLongPtr(hdlg, DWLP_USER, (LONG_PTR) pcd);
|
|
}
|
|
|
|
return pcd ? pcd->DlgProc(uMsg, wParam, lParam) : FALSE;
|
|
}
|
|
|
|
HRESULT CColumnDlg::_GetPropertyUI(IPropertyUI **pppui)
|
|
{
|
|
if (!_ppui)
|
|
SHCoCreateInstance(NULL, &CLSID_PropertiesUI, NULL, IID_PPV_ARG(IPropertyUI, &_ppui));
|
|
|
|
return _ppui ? _ppui->QueryInterface(IID_PPV_ARG(IPropertyUI, pppui)) : E_NOTIMPL;
|
|
}
|
|
|
|
UINT CColumnDlg::_HelpIDForItem(int iItem, LPTSTR pszHelpFile, UINT cch)
|
|
{
|
|
UINT uHelpID = 0;
|
|
*pszHelpFile = 0;
|
|
|
|
LV_ITEM lvi = {0};
|
|
lvi.iItem = iItem;
|
|
lvi.mask = LVIF_PARAM;
|
|
if (ListView_GetItem(_hwndLVAll, &lvi))
|
|
{
|
|
IShellFolder2 *psf;
|
|
if (SUCCEEDED(_pdsv->GetFolder(IID_PPV_ARG(IShellFolder2, &psf))))
|
|
{
|
|
SHCOLUMNID scid;
|
|
if (SUCCEEDED(psf->MapColumnToSCID(lvi.lParam, &scid)))
|
|
{
|
|
IPropertyUI *ppui;
|
|
if (SUCCEEDED(_GetPropertyUI(&ppui)))
|
|
{
|
|
ppui->GetHelpInfo(scid.fmtid, scid.pid, pszHelpFile, cch, &uHelpID);
|
|
ppui->Release();
|
|
}
|
|
}
|
|
psf->Release();
|
|
}
|
|
}
|
|
return uHelpID; // IDH_ values
|
|
}
|
|
|
|
|
|
const static DWORD c_rgColumnDlgHelpIDs[] =
|
|
{
|
|
IDC_COL_UP, 1,
|
|
IDC_COL_DOWN, 1,
|
|
IDC_COL_SHOW, 1,
|
|
IDC_COL_HIDE, 1,
|
|
IDC_COL_WIDTH, 10055,
|
|
IDC_COL_WIDTH_TEXT, 10055,
|
|
0, 0
|
|
};
|
|
|
|
BOOL_PTR CColumnDlg::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
_OnInitDlg();
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_COL_UP:
|
|
_MoveItem(- 1);
|
|
SetFocus(_hwndLVAll);
|
|
break;
|
|
|
|
case IDC_COL_DOWN:
|
|
_MoveItem(+ 1);
|
|
SetFocus(_hwndLVAll);
|
|
break;
|
|
|
|
case IDC_COL_SHOW:
|
|
case IDC_COL_HIDE:
|
|
{
|
|
UINT iItem = ListView_GetSelectionMark(_hwndLVAll);
|
|
ListView_SetCheckState(_hwndLVAll, iItem, LOWORD(wParam) == IDC_COL_SHOW);
|
|
SetFocus(_hwndLVAll);
|
|
break;
|
|
}
|
|
|
|
case IDC_COL_WIDTH:
|
|
if (HIWORD(wParam) == EN_CHANGE && !_bUpdating)
|
|
{
|
|
LV_ITEM lvi = {0};
|
|
lvi.iItem = ListView_GetSelectionMark(_hwndLVAll);
|
|
lvi.mask = LVIF_PARAM;
|
|
ListView_GetItem(_hwndLVAll, &lvi);
|
|
|
|
_pWidths[lvi.lParam] = - (int)GetDlgItemInt(_hdlg, IDC_COL_WIDTH, NULL, FALSE);
|
|
_bChanged = TRUE;
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
_SaveState();
|
|
|
|
// fall through
|
|
|
|
case IDCANCEL:
|
|
return EndDialog(_hdlg, TRUE);
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
if (_bLoaded && !_bUpdating)
|
|
{
|
|
NMLISTVIEW * pnmlv = (NMLISTVIEW *)lParam;
|
|
switch (((NMHDR *)lParam)->code)
|
|
{
|
|
case LVN_ITEMCHANGING:
|
|
|
|
// fix up the buttons & such here
|
|
if (pnmlv->uChanged & LVIF_STATE)
|
|
_UpdateDlgButtons(pnmlv);
|
|
|
|
// We want to reject turning off the name column
|
|
// it both doesn't make sense to have no name column, and defview assumes there will be one
|
|
if (pnmlv->lParam == 0 &&
|
|
(pnmlv->uNewState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(1))
|
|
{
|
|
MessageBeep(MB_ICONEXCLAMATION);
|
|
SetWindowLongPtr(_hdlg, DWLP_MSGRESULT, TRUE);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// if something besides focus changed
|
|
if ((pnmlv->uChanged & ~LVIF_STATE) ||
|
|
((pnmlv->uNewState & LVIS_STATEIMAGEMASK) != (pnmlv->uOldState & LVIS_STATEIMAGEMASK)))
|
|
_bChanged = TRUE;
|
|
}
|
|
break;
|
|
|
|
case NM_DBLCLK:
|
|
{
|
|
BOOL bCheck = ListView_GetCheckState(_hwndLVAll, pnmlv->iItem);
|
|
ListView_SetCheckState(_hwndLVAll, pnmlv->iItem, !bCheck);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
SendMessage(_hwndLVAll, uMsg, wParam, lParam);
|
|
break;
|
|
|
|
case WM_HELP: // F1
|
|
{
|
|
HELPINFO *phi = (HELPINFO *)lParam;
|
|
|
|
//if the help is for one of the command buttons then call winhelp
|
|
if (phi->iCtrlId == IDC_COL_LVALL)
|
|
{
|
|
//Help is for the tree item so we need to do some special processing
|
|
|
|
int iItem;
|
|
|
|
// Is this help invoked throught F1 key
|
|
if (GetAsyncKeyState(VK_F1) < 0)
|
|
{
|
|
iItem = ListView_GetSelectionMark(_hwndLVAll);
|
|
}
|
|
else
|
|
{
|
|
LV_HITTESTINFO info;
|
|
info.pt = phi->MousePos;
|
|
ScreenToClient(_hwndLVAll, &info.pt);
|
|
iItem = ListView_HitTest(_hwndLVAll, &info);
|
|
}
|
|
|
|
if (iItem >= 0)
|
|
{
|
|
DWORD mapIDCToIDH[4] = {0};
|
|
TCHAR szFile[MAX_PATH];
|
|
|
|
mapIDCToIDH[0] = phi->iCtrlId;
|
|
mapIDCToIDH[1] = _HelpIDForItem(iItem, szFile, ARRAYSIZE(szFile));
|
|
|
|
WinHelp((HWND)((HELPINFO *)lParam)->hItemHandle, szFile[0] ? szFile : NULL,
|
|
HELP_WM_HELP, (DWORD_PTR)(LPSTR)mapIDCToIDH);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WinHelp((HWND)((HELPINFO *)lParam)->hItemHandle, TEXT(SHELL_HLP),
|
|
HELP_WM_HELP, (DWORD_PTR)(LPSTR)c_rgColumnDlgHelpIDs);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_CONTEXTMENU:
|
|
{
|
|
int iItem;
|
|
|
|
if ((LPARAM)-1 == lParam)
|
|
{
|
|
iItem = ListView_GetSelectionMark(_hwndLVAll);
|
|
}
|
|
else
|
|
{
|
|
LV_HITTESTINFO info;
|
|
info.pt.x = GET_X_LPARAM(lParam);
|
|
info.pt.y = GET_Y_LPARAM(lParam);
|
|
ScreenToClient(_hwndLVAll, &info.pt);
|
|
iItem = ListView_HitTest(_hwndLVAll, &info);
|
|
}
|
|
|
|
if (iItem >= 0)
|
|
{
|
|
DWORD mapIDCToIDH[4] = {0};
|
|
|
|
TCHAR szFile[MAX_PATH];
|
|
mapIDCToIDH[0] = IDC_COL_LVALL;
|
|
mapIDCToIDH[1] = _HelpIDForItem(iItem, szFile, ARRAYSIZE(szFile)); // IDH_ values
|
|
|
|
WinHelp((HWND)wParam, szFile[0] ? szFile : NULL, HELP_CONTEXTMENU, (DWORD_PTR)(LPSTR)mapIDCToIDH);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|