Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1195 lines
43 KiB

//+----------------------------------------------------------------------------
//
// File: listview.cpp
//
// Module: CMAK.EXE
//
// Synopsis: Implemenation of the helper functions used by CMAK to deal with the
// custom action list view control.
//
// Copyright (c) 2000 Microsoft Corporation
//
// Author: quintinb Created 02/26/00
//
//+----------------------------------------------------------------------------
#include "cmmaster.h"
//+----------------------------------------------------------------------------
//
// Function: UpdateListViewColumnHeadings
//
// Synopsis: This function sets the column heading text specified by the given
// column index and list view control window handle to the string
// resource specified by the given instance handle and string Id.
//
// Arguments: HINSTANCE hInstance - instance handle to load string resources
// HWND hListView - window handle of the list view control
// UINT uStringID - string id of the desired text
// int iColumnIndex - desired column to update the text of
//
// Returns: BOOL - TRUE on success, FALSE otherwise
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
BOOL UpdateListViewColumnHeadings(HINSTANCE hInstance, HWND hListView, UINT uStringID, int iColumnIndex)
{
BOOL bReturn = FALSE;
MYDBGASSERT(hInstance);
MYDBGASSERT(hListView);
MYDBGASSERT(uStringID);
if (hInstance && hListView && uStringID)
{
//
// First get the requested string
//
LVCOLUMN lvColumn = {0};
lvColumn.mask = LVCF_TEXT;
lvColumn.pszText = CmLoadString(hInstance, uStringID);
MYDBGASSERT(lvColumn.pszText);
if (lvColumn.pszText)
{
bReturn = ListView_SetColumn(hListView, iColumnIndex, &lvColumn);
CmFree(lvColumn.pszText);
}
}
return bReturn;
}
//+----------------------------------------------------------------------------
//
// Function: AddListViewColumnHeadings
//
// Synopsis: This function creates the description and type columns
// used by the default view of the custom action page. Once this
// function has been called, UpdateListViewColumnHeadings should
// be used to change the column headings as necessary. This function
// will need to be modified if more columns are deemed necessary.
//
// Arguments: HINSTANCE hInstance - instance handle to load string resources
// HWND hListView - window handle of the list view control
//
// Returns: BOOL - TRUE on success, FALSE otherwise
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
BOOL AddListViewColumnHeadings(HINSTANCE hInstance, HWND hListView)
{
//
// Add the column headings
//
LVCOLUMN lvColumn = {0};
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.pszText = CmLoadString(hInstance, IDS_DESC_COL_TITLE);
lvColumn.iSubItem = 0;
MYDBGASSERT(lvColumn.pszText);
if (lvColumn.pszText)
{
ListView_InsertColumn(hListView, 0, &lvColumn);
CmFree(lvColumn.pszText);
}
else
{
return FALSE;
}
lvColumn.pszText = CmLoadString(hInstance, IDS_TYPE_COL_TITLE);
lvColumn.iSubItem = 1;
MYDBGASSERT(lvColumn.pszText);
if (lvColumn.pszText)
{
ListView_InsertColumn(hListView, 1, &lvColumn);
CmFree(lvColumn.pszText);
}
else
{
return FALSE;
}
//
// Now lets size the columns so that the text is visible. Since we
// only have two columns of text, lets call GetWindowRect on the
// list view control and then set the column widths to each take
// up about half of the space available.
//
RECT Rect = {0};
LONG lColumnWidth;
if (GetWindowRect(hListView, &Rect))
{
//
// Subtract 5 from each to keep a scroll bar from appearing
//
lColumnWidth = (Rect.right - Rect.left)/2 - 5;
if (0 < lColumnWidth)
{
for (int i=0; i < 2; i++)
{
MYVERIFY(ListView_SetColumnWidth(hListView, i, lColumnWidth));
}
}
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: MapComboSelectionToType
//
// Synopsis: This function gets the current selection from the given
// combobox and maps the index to a custom action type.
//
// Arguments: HWND hDlg - window handle to the dialog that contains the combobox
// UINT uCtrlID - control id of the combobox
// BOOL bIncludesAll - when TRUE
// BOOL bUseTunneling - whether this is a tunneling profile or not
// CustomActionTypes* pType
//
// Returns: HRESULT - Standard COM error codes
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
HRESULT MapComboSelectionToType(HWND hDlg, UINT uCtrlID, BOOL bIncludesAll, BOOL bUseTunneling, CustomActionTypes* pType)
{
//
// Check Params
//
if ((NULL == hDlg) || (0 == uCtrlID) || (NULL == pType))
{
CMASSERTMSG(FALSE, TEXT("MapComboSelectionToType -- invalid parameter passed"));
return E_INVALIDARG;
}
HRESULT hr = S_OK;
INT_PTR nResult = SendDlgItemMessage(hDlg, uCtrlID, CB_GETCURSEL, 0, (LPARAM)0);
if (nResult != LB_ERR)
{
//
// If the combobox contains the All choice, we need to correct
// the type depending on what the user chose.
//
if (bIncludesAll)
{
if (0 == nResult)
{
*pType = ALL;
goto exit;
}
else
{
nResult--;
}
}
//
// We need to make a correction if we aren't Tunneling because the
// tunneling type won't be in the combobox
//
if (FALSE == bUseTunneling)
{
if (PRETUNNEL <= (CustomActionTypes)nResult)
{
nResult++;
}
}
*pType = (CustomActionTypes)nResult;
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
exit:
return hr;
}
//+----------------------------------------------------------------------------
//
// Function: GetItemTypeByListViewIndex
//
// Synopsis: This function gets the current selection index of the list view
// control and gets the type string. The type string is then
// converted into a numeric type and returned via the pType
// pointer.
//
// Arguments: HINSTANCE hInstance - instance handle for string resources
// HWND hListView - window handle of the list view control
// CustomActionTypes* pType - pointer to hold the type of the item
//
// Returns: HRESULT - Standard COM error codes
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
HRESULT GetItemTypeByListViewIndex(HINSTANCE hInstance, HWND hListView, CustomActionTypes* pType, int *piIndex)
{
//
// Check params
//
if ((NULL == hListView) || (NULL == pType) || (NULL == g_pCustomActionList))
{
CMASSERTMSG(FALSE, TEXT("GetItemTypeByListViewIndex -- invalid parameter passed"));
return E_INVALIDARG;
}
//
// The user has the All view selected, further work is needed to select the
// appropriate type.
//
HRESULT hr = S_OK;
if (-1 == *piIndex)
{
*piIndex = ListView_GetSelectionMark(hListView);
}
int iTemp = *piIndex;
if (-1 != iTemp)
{
LVITEM lvItem = {0};
TCHAR szTemp[MAX_PATH+1];
szTemp[0] = TEXT('\0');
lvItem.mask = LVIF_TEXT;
lvItem.pszText = szTemp;
lvItem.cchTextMax = MAX_PATH;
lvItem.iItem = iTemp;
lvItem.iSubItem = 1;
if (ListView_GetItem(hListView, &lvItem))
{
hr = g_pCustomActionList->GetTypeFromTypeString(hInstance, lvItem.pszText, pType);
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
return hr;
}
//+----------------------------------------------------------------------------
//
// Function: GetDescriptionAndTypeOfItem
//
// Synopsis: This function gets the type and description of the item specified
// by the passed in item index. If the caller passes -1 for this index,
// the currently selected item is used and the actual index is passed
// back via this in/out pointer.
//
// Arguments: HINSTANCE hInstance - instance handle to load string resources
// HWND hDlg - window handle of the dialog containing the type combo
// HWND hListView - window handle to the list view control
// UINT uComboBoxId - combo box id containing the type info
// CustomActionListItem* pItem - pointer to a custom action struct to
// hold the returned type and description
// int* piItemIndex - index of the item to get the description and
// type of. If -1, then the current selection mark
// is used and the actual index is returned in *piItemIndex
// BOOL bUseTunneling - whether this profile uses tunneling or not
//
// Returns: HRESULT - Standard COM error codes
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
HRESULT GetDescriptionAndTypeOfItem(HINSTANCE hInstance, HWND hDlg, HWND hListView, UINT uComboBoxId,
CustomActionListItem* pItem, int* piItemIndex, BOOL bUseTunneling)
{
//
// Check Params
//
if (NULL == hDlg || NULL == hListView || 0 == uComboBoxId || NULL == pItem || NULL == piItemIndex)
{
CMASSERTMSG(FALSE, TEXT("GetDescriptionAndTypeOfSelection -- Invalid parameter passed."));
return E_INVALIDARG;
}
HRESULT hr = E_UNEXPECTED;
//
// If the user passed us a -1 in *piItemIndex then they want the Description and Type of the
// selected item. Otherwise, they gave us a specific item index that they want data on.
//
int iTemp;
if (-1 == *piItemIndex)
{
iTemp = ListView_GetSelectionMark(hListView);
}
else
{
iTemp = ListView_GetItemCount(hListView);
if ((0 > *piItemIndex) || (iTemp <= *piItemIndex))
{
iTemp = -1;
}
else
{
iTemp = *piItemIndex;
}
}
if (-1 != iTemp)
{
//
// Figure out the type of the item
//
ZeroMemory(pItem, sizeof(CustomActionListItem));
hr = MapComboSelectionToType(hDlg, uComboBoxId, TRUE, bUseTunneling, &(pItem->Type)); //bIncludesAll == TRUE
if (SUCCEEDED(hr))
{
if (ALL == pItem->Type)
{
hr = GetItemTypeByListViewIndex(hInstance, hListView, &(pItem->Type), &iTemp);
}
}
//
// Now Figure out the description of the item
//
if (SUCCEEDED(hr))
{
ListView_GetItemText(hListView, iTemp, 0, pItem->szDescription, CELEMS(pItem->szDescription));
}
*piItemIndex = iTemp;
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
return hr;
}
//+----------------------------------------------------------------------------
//
// Function: RefreshEditDeleteMoveButtonStates
//
// Synopsis: This function sets the enabled/disabled state of the Edit, Delete,
// Move up and Move Down buttons based on the custom action specified by
// the list view index passed in through the piIndex param. If this
// parameter is -1 then the currently selected item is used and
// the actual index is returned through the int pointer.
//
// Arguments: HINSTANCE hInstance - instance handle to load string resources
// HWND hDlg - window handle of the dialog containing the type combo
// HWND hListView - window handle to the list view control
// UINT uComboBoxId - combo box id containing the type info
// int* piIndex - index of the list view item to base the move up
// and move down button state on. Again -1 will use
// the currently selected item.
// BOOl bUseTunneling - whether this profile uses tunneling or not
//
// Returns: Nothing
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
void RefreshEditDeleteMoveButtonStates(HINSTANCE hInstance, HWND hDlg, HWND hListView, UINT uComboCtrlId, int* piIndex, BOOL bUseTunneling)
{
if ((NULL == hInstance) || (NULL == hDlg) || (NULL == hListView) ||
(0 == uComboCtrlId) || (NULL == piIndex) || (NULL == g_pCustomActionList))
{
CMASSERTMSG(FALSE, TEXT("RefreshEditDeleteMoveButtonStates -- invalid parameter passed."));
return;
}
int iDisableMoveUp = -1; // -1 is the true value for GetListPositionAndBuiltInState
int iDisableMoveDown = -1;
int iDisableDeleteAndEdit = -1;
CustomActionListItem Item;
if (ListView_GetItemCount(hListView))
{
//
// Get the description and type of the item *piIndex (if -1 then the currently selected item)
//
//
ZeroMemory(&Item, sizeof(Item));
HRESULT hr = GetDescriptionAndTypeOfItem(hInstance, hDlg, hListView, uComboCtrlId, &Item, piIndex, bUseTunneling);
if (SUCCEEDED(hr))
{
hr = g_pCustomActionList->GetListPositionAndBuiltInState(hInstance, &Item, &iDisableMoveUp, &iDisableMoveDown, &iDisableDeleteAndEdit);
MYDBGASSERT(SUCCEEDED(hr));
}
}
HWND hCurrentFocus = GetFocus();
HWND hEditButton = GetDlgItem(hDlg, IDC_BUTTON2);
HWND hDeleteButton = GetDlgItem(hDlg, IDC_BUTTON3);
HWND hMoveUpButton = GetDlgItem(hDlg, IDC_BUTTON4);
HWND hMoveDownButton = GetDlgItem(hDlg, IDC_BUTTON5);
if (hEditButton)
{
EnableWindow(hEditButton, (iDisableDeleteAndEdit ? 0 : 1));
}
if (hDeleteButton)
{
EnableWindow(hDeleteButton, (iDisableDeleteAndEdit ? 0 : 1));
}
if (hMoveUpButton)
{
EnableWindow(hMoveUpButton, (iDisableMoveUp ? 0 : 1));
}
if (hMoveDownButton)
{
EnableWindow(hMoveDownButton, (iDisableMoveDown ? 0 : 1));
}
if (hCurrentFocus && (FALSE == IsWindowEnabled(hCurrentFocus)))
{
if (hDeleteButton == hCurrentFocus)
{
//
// If delete is disabled and contained the focus, shift it to the Add button
//
SendMessage(hDlg, DM_SETDEFID, IDC_BUTTON1, (LPARAM)0L); //lint !e534 DM_SETDEFID doesn't return error info
HWND hControl = GetDlgItem(hDlg, IDC_BUTTON1);
if (hControl)
{
SetFocus(hControl);
}
}
else if ((hMoveUpButton == hCurrentFocus) && IsWindowEnabled(hMoveDownButton))
{
SendMessage(hDlg, DM_SETDEFID, IDC_BUTTON5, (LPARAM)0L); //lint !e534 DM_SETDEFID doesn't return error info
SetFocus(hMoveDownButton);
}
else if ((hMoveDownButton == hCurrentFocus) && IsWindowEnabled(hMoveUpButton))
{
SendMessage(hDlg, DM_SETDEFID, IDC_BUTTON4, (LPARAM)0L); //lint !e534 DM_SETDEFID doesn't return error info
SetFocus(hMoveUpButton);
}
else
{
//
// If all else fails set the focus to the listview control
//
SetFocus(hListView);
}
}
}
//+----------------------------------------------------------------------------
//
// Function: SelectListViewItem
//
// Synopsis: This function trys to select a list view item with the given
// type and description in the given listview control. If the listview
// doesn't contain the item we are looking for it returns FALSE and
// doesn't change the selection.
//
// Arguments: HINSTANCE hInstance - instance handle for resources
// HWND hDlg - window handle of the dialog containing the type combo
// UINT uComboBoxId - combo box id containing the type info
// HWND hListView - window handle to the list view control
// BOOL bUseTunneling - whether this is a tunneling profile or not,
// affects whether Pre-Tunnel actions are displayed
// or not.
// CustomActionTypes TypeToSelect - type of the item to select
// LPCTSTR pszDescription - description of the item to select
//
// Returns: TRUE if the required item was found and selected
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
/*
BOOL SelectListViewItem(HWND hDlg, UINT uComboCtrlId, HWND hListView, BOOL bUseTunneling, CustomActionTypes TypeToSelect, LPCTSTR pszDescription)
{
CustomActionTypes Type;
BOOL bReturn = FALSE;
HRESULT hr = MapComboSelectionToType(hDlg, uComboCtrlId, TRUE, bUseTunneling, &Type); //bIncludesAll == TRUE
if ((ALL == Type) || (TypeToSelect == Type))
{
LVFINDINFO lvFindInfo = {0};
LVITEM lvItem = {0};
lvFindInfo.flags = LVFI_STRING;
lvFindInfo.psz = pszDescription;
int iIndex = ListView_FindItem(hListView, -1, &lvFindInfo);
if (-1 != iIndex)
{
//
// Select the item
//
ListView_SetSelectionMark(hListView, iIndex);
//
// Now set the selection state so it shows up as selected in the UI.
//
lvItem.mask = LVIF_STATE;
lvItem.state = LVIS_SELECTED;
lvItem.stateMask = LVIS_SELECTED;
lvItem.iItem = iIndex;
lvItem.iSubItem = 0;
MYVERIFY(ListView_SetItem(hListView, &lvItem));
//
// Now Verify that the selection is visible
//
MYVERIFY(ListView_EnsureVisible(hListView, iIndex, FALSE)); // FALSE = fPartialOK, we want full visibility
bReturn = TRUE;
}
}
return bReturn;
}
*/
void SetListViewSelection(HWND hListView, int iIndex)
{
ListView_SetSelectionMark(hListView, iIndex);
//
// Now set the selection state so it shows up as selected in the UI.
//
LVITEM lvItem = {0};
lvItem.mask = LVIF_STATE;
lvItem.state = LVIS_SELECTED;
lvItem.stateMask = LVIS_SELECTED;
lvItem.iItem = iIndex;
lvItem.iSubItem = 0;
MYVERIFY(ListView_SetItem(hListView, &lvItem));
//
// Now Verify that the selection is visible
//
MYVERIFY(ListView_EnsureVisible(hListView, iIndex, FALSE)); // FALSE = fPartialOK, we want full visibility
}
BOOL SelectListViewItem(HINSTANCE hInstance, HWND hDlg, UINT uComboCtrlId, HWND hListView, BOOL bUseTunneling, CustomActionTypes TypeToSelect, LPCTSTR pszDescription)
{
if ((NULL == pszDescription) || (TEXT('\0') == pszDescription[0]) || (0 == uComboCtrlId) || (NULL == hDlg))
{
CMASSERTMSG(FALSE, TEXT("SelectListViewItem -- Invalid parameter passed."));
return FALSE;
}
CustomActionTypes Type;
CustomActionTypes TypeSelectedInCombo;
BOOL bReturn = FALSE;
//
// If the current view is ALL, then we may have multiple items with the same name but different types. Thus
// we must check the type string of the item and search again if it isn't the correct item. If we are viewing
// items only of the TypeToSelect then we are guarenteed that there is only one item of that name. Finally if
// we are viewing a different item type we don't want to do anything to the selection as the item we want to
// select won't be visible.
//
HRESULT hr = MapComboSelectionToType(hDlg, uComboCtrlId, TRUE, bUseTunneling, &TypeSelectedInCombo); //bIncludesAll == TRUE
if (SUCCEEDED(hr) && ((TypeToSelect == TypeSelectedInCombo) || (ALL == TypeSelectedInCombo)))
{
//
// Setup the find structure
//
LVFINDINFO lvFindInfo = {0};
lvFindInfo.flags = LVFI_STRING;
lvFindInfo.psz = pszDescription;
//
// Setup the Item structure
//
LVITEM lvItem = {0};
TCHAR szTemp[MAX_PATH+1];
lvItem.mask = LVIF_TEXT;
lvItem.pszText = szTemp;
lvItem.cchTextMax = MAX_PATH;
lvItem.iSubItem = 1;
BOOL bExitLoop;
int iIndex = -1;
do
{
bExitLoop = TRUE;
iIndex = ListView_FindItem(hListView, iIndex, &lvFindInfo);
if ((-1 != iIndex) && (ALL == TypeSelectedInCombo))
{
//
// Now check to see if this has the type we are looking for
//
szTemp[0] = TEXT('\0');
lvItem.iItem = iIndex;
if (ListView_GetItem(hListView, &lvItem))
{
hr = g_pCustomActionList->GetTypeFromTypeString(hInstance, lvItem.pszText, &Type);
if (SUCCEEDED(hr))
{
bExitLoop = (TypeToSelect == Type);
}
}
}
} while(!bExitLoop);
if (-1 != iIndex)
{
SetListViewSelection(hListView, iIndex);
bReturn = TRUE;
}
}
return bReturn;
}
//+----------------------------------------------------------------------------
//
// Function: RefreshListView
//
// Synopsis: This function refreshes the list view data from that contained
// in the global CustomActionList class. Gets the type of data to
// display from the combo box specified by the hDlg and uComboCtrlId
// parameters
//
// Arguments: HINSTANCE hInstance - instance handle to load string resources
// HWND hDlg - window handle of the dialog containing the type combo
// UINT uComboBoxId - combo box id containing the type info
// HWND hListView - window handle to the list view control
// int iItemToSelect - item the caller wants selected after the refresh
// BOOL bUseTunneling - whether this is a tunneling profile or not,
// affects whether Pre-Tunnel actions are displayed
// or not.
//
// Returns: Nothing
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
void RefreshListView(HINSTANCE hInstance, HWND hDlg, UINT uComboCtrlId, HWND hListView,
int iItemToSelect, BOOL bUseTunneling)
{
//
// Refresh the list view
//
CustomActionTypes Type;
BOOL bEnableDeleteAndEdit = FALSE;
CMASSERTMSG(hInstance && hDlg && uComboCtrlId && hListView && g_pCustomActionList, TEXT("RefreshListView -- Invalid Parameters passed, skipping refresh"));
if (hDlg && uComboCtrlId && hListView && g_pCustomActionList)
{
HRESULT hr = MapComboSelectionToType(hDlg, uComboCtrlId, TRUE, bUseTunneling, &Type); //bIncludesAll == TRUE
//
// Add the items to the list view and set the selection to iItemToSelect
//
if (SUCCEEDED(hr))
{
hr = g_pCustomActionList->AddCustomActionsToListView(hListView, hInstance, Type, bUseTunneling, iItemToSelect, (ALL == Type));
MYDBGASSERT(SUCCEEDED(hr));
}
//
// If the caller asked for an item that we couldn't select, then the item selected would be the first item. To avoid
// confusion we will just use the currently selected item by passing -1;
//
int iIndex = -1;
RefreshEditDeleteMoveButtonStates(hInstance, hDlg, hListView, uComboCtrlId, &iIndex, bUseTunneling);
}
}
//+----------------------------------------------------------------------------
//
// Function: OnProcessCustomActionsAdd
//
// Synopsis: This function is called when the user presses the Add button
// on the custom action pane of CMAK. This function is basically a
// wrapper for the add functionality so that context menus and other
// commands can also call it with duplicate code.
//
// Arguments: HINSTANCE hInstance - instance handle to load string resources
// HWND hDlg - window handle of the dialog containing the type combo
// HWND hListView - window handle to the list view control
// BOOL bUseTunneling - whether this profile uses tunneling or not
//
// Returns: Nothing
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
void OnProcessCustomActionsAdd(HINSTANCE hInstance, HWND hDlg, HWND hListView, BOOL bUseTunneling)
{
MYDBGASSERT(hInstance);
MYDBGASSERT(hDlg);
MYDBGASSERT(hListView);
if (hInstance && hDlg && hListView)
{
CustomActionListItem ListItem;
CustomActionTypes Type;
INT_PTR nResult = -1; // get info on currently selected item
//
// First figure out what type of connect action the list view is showing. We
// want to preset the combo box on the add/edit dialog to the correct type
// of custom action, unless it is showing all and then just set it to the first
// item in the list.
//
HRESULT hr = MapComboSelectionToType(hDlg, IDC_COMBO1, TRUE, bUseTunneling, &Type); //bIncludesAll == TRUE
ZeroMemory(&ListItem, sizeof(CustomActionListItem));
if (SUCCEEDED(hr))
{
if (ALL != Type)
{
ListItem.Type = Type;
}
}
//
// Still call the Add dialog even if we couldn't determine the type
//
nResult = DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_CUSTOM_ACTIONS_POPUP), hDlg,
ProcessCustomActionPopup,(LPARAM)&ListItem);
if (IDOK == nResult)
{
RefreshListView(hInstance, hDlg, IDC_COMBO1, hListView, 0, bUseTunneling);
SelectListViewItem(hInstance, hDlg, IDC_COMBO1, hListView, bUseTunneling, ListItem.Type, ListItem.szDescription);
}
}
}
//+----------------------------------------------------------------------------
//
// Function: OnProcessCustomActionsDelete
//
// Synopsis: This function is called when the user presses the Delete button
// on the custom action pane of CMAK. This function is basically a
// wrapper for the delete functionality so that context menus and other
// commands can also call it with duplicate code.
//
// Arguments: HINSTANCE hInstance - instance handle to load string resources
// HWND hDlg - window handle of the dialog containing the type combo
// HWND hListView - window handle to the list view control
// BOOL bUseTunneling - whether this profile uses tunneling or not
//
// Returns: Nothing
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
void OnProcessCustomActionsDelete(HINSTANCE hInstance, HWND hDlg, HWND hListView, BOOL bUseTunneling)
{
MYDBGASSERT(hInstance);
MYDBGASSERT(hDlg);
MYDBGASSERT(hListView);
MYDBGASSERT(g_pCustomActionList);
if (hInstance && hDlg && hListView && g_pCustomActionList)
{
CustomActionListItem ListItem;
int iTemp = -1; // get info on currently selected item
HRESULT hr = GetDescriptionAndTypeOfItem(hInstance, hDlg, hListView, IDC_COMBO1, &ListItem, &iTemp, bUseTunneling);
if (SUCCEEDED(hr))
{
hr = g_pCustomActionList->Delete(hInstance, ListItem.szDescription, ListItem.Type);
if (SUCCEEDED(hr))
{
RefreshListView(hInstance, hDlg, IDC_COMBO1, hListView, 0, bUseTunneling);
}
}
else
{
MYVERIFY(IDOK == ShowMessage(hDlg, IDS_NOSELECTION, MB_OK));
}
}
}
//+----------------------------------------------------------------------------
//
// Function: OnProcessCustomActionsEdit
//
// Synopsis: This function is called when the user presses the Edit button
// on the custom action pane of CMAK. This function is basically a
// wrapper for the edit functionality so that context menus and other
// commands can also call it with duplicate code.
//
// Arguments: HINSTANCE hInstance - instance handle to load string resources
// HWND hDlg - window handle of the dialog containing the type combo
// HWND hListView - window handle to the list view control
// BOOL bUseTunneling - whether this profile uses tunneling or not
//
// Returns: Nothing
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
void OnProcessCustomActionsEdit(HINSTANCE hInstance, HWND hDlg, HWND hListView, BOOL bUseTunneling)
{
MYDBGASSERT(hInstance);
MYDBGASSERT(hDlg);
MYDBGASSERT(hListView);
MYDBGASSERT(g_pCustomActionList);
if (hInstance && hDlg && hListView && g_pCustomActionList)
{
//
// First find the name and type of the Connect Action to edit
//
CustomActionListItem ListItem;
int iTemp = -1; // get info on currently selected item
HRESULT hr = GetDescriptionAndTypeOfItem(hInstance, hDlg, hListView, IDC_COMBO1, &ListItem, &iTemp, bUseTunneling);
if (SUCCEEDED(hr))
{
int iFirstInList;
int iLastInList;
int iBuiltIn;
//
// Screen out the built in custom actions
//
hr = g_pCustomActionList->GetListPositionAndBuiltInState(hInstance, &ListItem, &iFirstInList, &iLastInList, &iBuiltIn);
if (SUCCEEDED(hr))
{
if (0 == iBuiltIn)
{
INT_PTR nResult = DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_CUSTOM_ACTIONS_POPUP), hDlg,
ProcessCustomActionPopup,(LPARAM)&ListItem);
if (IDOK == nResult)
{
RefreshListView(hInstance, hDlg, IDC_COMBO1, hListView, 0, bUseTunneling);
SelectListViewItem(hInstance, hDlg, IDC_COMBO1, hListView, bUseTunneling, ListItem.Type, ListItem.szDescription);
}
}
}
else
{
MYVERIFY(IDOK == ShowMessage(hDlg, IDS_NOSELECTION, MB_OK));
}
}
}
}
//+----------------------------------------------------------------------------
//
// Function: OnProcessCustomActionsMoveUp
//
// Synopsis: This function is called when the user presses the Move Up button
// on the custom action pane of CMAK. This function is basically a
// wrapper for the move up functionality so that context menus and other
// commands can also call it with duplicate code.
//
// Arguments: HINSTANCE hInstance - instance handle to load string resources
// HWND hDlg - window handle of the dialog containing the type combo
// HWND hListView - window handle to the list view control
// BOOL bUseTunneling - whether this profile uses tunneling or not
//
// Returns: Nothing
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
void OnProcessCustomActionsMoveUp(HINSTANCE hInstance, HWND hDlg, HWND hListView, BOOL bUseTunneling)
{
MYDBGASSERT(hInstance);
MYDBGASSERT(hDlg);
MYDBGASSERT(hListView);
MYDBGASSERT(g_pCustomActionList);
if (hInstance && hDlg && hListView && g_pCustomActionList)
{
//
// First find the name and type of the Connect Action to edit
//
CustomActionListItem ListItem;
int iTemp = -1; // get info on currently selected item
HRESULT hr = GetDescriptionAndTypeOfItem(hInstance, hDlg, hListView, IDC_COMBO1, &ListItem, &iTemp, bUseTunneling);
if (SUCCEEDED(hr))
{
hr = g_pCustomActionList->MoveUp(hInstance, ListItem.szDescription, ListItem.Type);
if (SUCCEEDED(hr) && (S_FALSE != hr)) // S_FALSE means it is already first in the list
{
RefreshListView(hInstance, hDlg, IDC_COMBO1, hListView, (iTemp - 1), bUseTunneling);
}
}
else
{
MYVERIFY(IDOK == ShowMessage(hDlg, IDS_NOSELECTION, MB_OK));
}
}
}
//+----------------------------------------------------------------------------
//
// Function: OnProcessCustomActionsMoveDown
//
// Synopsis: This function is called when the user presses the Move Down button
// on the custom action pane of CMAK. This function is basically a
// wrapper for the move down functionality so that context menus and other
// commands can also call it with duplicate code.
//
// Arguments: HINSTANCE hInstance - instance handle to load string resources
// HWND hDlg - window handle of the dialog containing the type combo
// HWND hListView - window handle to the list view control
// BOOL bUseTunneling - whether this profile uses tunneling or not
//
// Returns: Nothing
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
void OnProcessCustomActionsMoveDown(HINSTANCE hInstance, HWND hDlg, HWND hListView, BOOL bUseTunneling)
{
MYDBGASSERT(hInstance);
MYDBGASSERT(hDlg);
MYDBGASSERT(hListView);
MYDBGASSERT(g_pCustomActionList);
if (hInstance && hDlg && hListView && g_pCustomActionList)
{
//
// First find the name and type of the Connect Action to edit
//
CustomActionListItem ListItem;
int iTemp = -1; // get info on currently selected item
HRESULT hr = GetDescriptionAndTypeOfItem(hInstance, hDlg, hListView, IDC_COMBO1, &ListItem, &iTemp, bUseTunneling);
if (SUCCEEDED(hr))
{
hr = g_pCustomActionList->MoveDown(hInstance, ListItem.szDescription, ListItem.Type);
if (SUCCEEDED(hr) && (S_FALSE != hr)) // S_FALSE means it is already last in the list
{
RefreshListView(hInstance, hDlg, IDC_COMBO1, hListView, (iTemp + 1), bUseTunneling);
}
}
else
{
MYVERIFY(IDOK == ShowMessage(hDlg, IDS_NOSELECTION, MB_OK));
}
}
}
//+----------------------------------------------------------------------------
//
// Function: OnProcessCustomActionsContextMenu
//
// Synopsis: This function is called when the user right clicks on the list view
// control or invokes the context menu via the keyboard (shift+F10 or
// the context menu key). The function displays the context menu at
// the coordinates specified by the NMITEMACTIVATE structure and
// determines which context menu to display based on whether the
// NMITEMACTIVATE struct contains an item identifier (it will be
// -1 if the user doesn't click on an item specifically) and the
// position in the custom action list of the item selected. The
// function will also call the appropriate command function
// as necessary once the user has made a context menu selection.
//
// Arguments: HINSTANCE hInstance - instance handle to load string resources
// HWND hDlg - window handle of the dialog containing the type combo
// HWND hListView - window handle to the list view control
// NMITEMACTIVATE* pItemActivate - contains item and location information
// used to display the context menu.
// BOOL bUseTunneling - whether this profile uses tunneling or not
// UINT uComboCtrlId - control id of the combo box containing
// the custom action type selection
//
// Returns: Nothing
//
// History: quintinb Created Header 02/26/00
//
//+----------------------------------------------------------------------------
void OnProcessCustomActionsContextMenu(HINSTANCE hInstance, HWND hDlg, HWND hListView,
NMITEMACTIVATE* pItemActivate, BOOL bUseTunneling, UINT uComboCtrlId)
{
MYDBGASSERT(hInstance);
MYDBGASSERT(hDlg);
MYDBGASSERT(hListView);
MYDBGASSERT(pItemActivate);
MYDBGASSERT(g_pCustomActionList);
UINT uMenuIdToDisplay = IDM_CA_ADD_ONLY;
int iDisableMoveUp;
int iDisableMoveDown;
int iDisableDeleteAndEdit;
if (hInstance && hDlg && hListView && pItemActivate && g_pCustomActionList)
{
//
// If we aren't directly on an item, then we will only
// display the Add item, set as default. If we are on
// an item then we will display Edit (default), add, delete,
// and the appropriate choices for moveup and movedown (one,
// both, none). We will add a separator between the moveup/movedown
// choices and the regular options if we have moveup or movedown.
//
if (-1 == pItemActivate->iItem)
{
//
// Then the user right clicked in the area of the control and not on a specific item.
// Thus we only need to show a menu with Add as the default item.
//
uMenuIdToDisplay = IDM_CA_ADD_ONLY;
}
else if (0 == pItemActivate->ptAction.y)
{
//
// When the user clicks on the column headers we always get back a y value of zero and
// a really large (probably meant to be negative) x value. Since this throws off where
// the menu shows up, lets just disable the context menu here.
//
return;
}
else
{
//
// The user actually right clicked on an item and we need to figure out which menu
// to display.
//
MYDBGASSERT(0 != ListView_GetItemCount(hListView));
//
// Get the description and type of the item
//
int iIndex = pItemActivate->iItem;
CustomActionListItem Item;
ZeroMemory(&Item, sizeof(Item));
HRESULT hr = GetDescriptionAndTypeOfItem(hInstance, hDlg, hListView, uComboCtrlId, &Item, &iIndex, bUseTunneling);
if (SUCCEEDED(hr))
{
//
// Note that GetListPositionAndBuiltInState returns either -1 (0xFFFFFFF) or 0, thus making the
// bitwise ANDs below work out to the correct index.
//
hr = g_pCustomActionList->GetListPositionAndBuiltInState(hInstance, &Item, &iDisableMoveUp, &iDisableMoveDown, &iDisableDeleteAndEdit);
if (SUCCEEDED(hr))
{
const UINT c_ArrayOfContextMenuIds[8] = {IDM_CA_FULL, IDM_CA_ADD_MOVEUPORDOWN, IDM_CA_NO_DOWN, IDM_CA_ADD_MOVEUP,
IDM_CA_NO_UP, IDM_CA_ADD_MOVEDOWN, IDM_CA_NO_MOVE, IDM_CA_ADD_ONLY};
DWORD dwIndex = (iDisableMoveUp & 0x4) + (iDisableMoveDown & 0x2) + (iDisableDeleteAndEdit & 0x1);
uMenuIdToDisplay = c_ArrayOfContextMenuIds[dwIndex];
}
}
}
//
// Now that we have figured out what menu to use, go add and display it
//
HMENU hLoadedMenu;
HMENU hContextMenu;
POINT ptClientToScreen;
hLoadedMenu = LoadMenu(hInstance, MAKEINTRESOURCE(uMenuIdToDisplay));
if (hLoadedMenu)
{
hContextMenu = GetSubMenu(hLoadedMenu, 0);
if (hContextMenu)
{
CopyMemory(&ptClientToScreen, &(pItemActivate->ptAction), sizeof(POINT));
if (ClientToScreen(hListView, &ptClientToScreen))
{
int iMenuSelection = TrackPopupMenu(hContextMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
ptClientToScreen.x , ptClientToScreen.y, 0, hDlg, NULL);
switch(iMenuSelection)
{
case IDM_CA_ADD:
OnProcessCustomActionsAdd(hInstance, hDlg, hListView, bUseTunneling);
break;
case IDM_CA_EDIT:
OnProcessCustomActionsEdit(hInstance, hDlg, hListView, bUseTunneling);
break;
case IDM_CA_DELETE:
OnProcessCustomActionsDelete(hInstance, hDlg, hListView, bUseTunneling);
break;
case IDM_CA_MOVE_UP:
OnProcessCustomActionsMoveUp(hInstance, hDlg, hListView, bUseTunneling);
break;
case IDM_CA_MOVE_DOWN:
OnProcessCustomActionsMoveDown(hInstance, hDlg, hListView, bUseTunneling);
break;
default:
//
// Do nothing the user canceled the menu or an error occurred.
//
break;
}
}
}
DestroyMenu(hLoadedMenu);
}
}
}