244 lines
6.9 KiB
C++
244 lines
6.9 KiB
C++
// UndoDialog.h : Declaration of the CUndoDialog
|
|
|
|
#ifndef __UNDODIALOG_H_
|
|
#define __UNDODIALOG_H_
|
|
|
|
#include "resource.h" // main symbols
|
|
#include <atlhost.h>
|
|
#include "undolog.h"
|
|
|
|
#ifndef ListView_SetCheckState
|
|
#define ListView_SetCheckState(hwndLV, i, fCheck) \
|
|
ListView_SetItemState(hwndLV, i, \
|
|
INDEXTOSTATEIMAGEMASK((fCheck)+1), LVIS_STATEIMAGEMASK)
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CUndoDialog
|
|
class CUndoDialog :
|
|
public CAxDialogImpl<CUndoDialog>
|
|
{
|
|
public:
|
|
CUndoDialog(CUndoLog * pUndoLog, BOOL fFromUserClick = TRUE)
|
|
{
|
|
ASSERT(pUndoLog);
|
|
m_pUndoLog = pUndoLog;
|
|
m_fFromUserClick = fFromUserClick;
|
|
}
|
|
|
|
~CUndoDialog()
|
|
{
|
|
}
|
|
|
|
enum { IDD = IDD_UNDODIALOG };
|
|
|
|
BEGIN_MSG_MAP(CUndoDialog)
|
|
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
|
|
COMMAND_HANDLER(IDC_CLOSE, BN_CLICKED, OnClickedClose)
|
|
NOTIFY_HANDLER(IDC_LISTCHANGES, LVN_ITEMCHANGED, OnItemChangedListChanges)
|
|
COMMAND_HANDLER(IDC_BUTTONUNDOALL, BN_CLICKED, OnClickedButtonUndoAll)
|
|
COMMAND_HANDLER(IDC_BUTTONUNDOSELECTED, BN_CLICKED, OnClickedButtonUndoSelected)
|
|
COMMAND_HANDLER(IDC_RUNMSCONFIG, BN_CLICKED, OnClickedRunMSConfig)
|
|
END_MSG_MAP()
|
|
// Handler prototypes:
|
|
// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
|
// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
|
|
// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
|
|
|
|
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
m_list.Attach(GetDlgItem(IDC_LISTCHANGES));
|
|
ListView_SetExtendedListViewStyle(m_list.m_hWnd, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
|
|
|
|
// If this is launched by the user clicking on the button, hide the "Run MSConfig"
|
|
// button and resize the dialog.
|
|
|
|
if (m_fFromUserClick)
|
|
{
|
|
CWindow wndRun;
|
|
RECT rectRun, rectWindow;
|
|
|
|
wndRun.Attach(GetDlgItem(IDC_RUNMSCONFIG));
|
|
wndRun.ShowWindow(SW_HIDE);
|
|
wndRun.GetWindowRect(&rectRun);
|
|
GetWindowRect(&rectWindow);
|
|
rectWindow.bottom -= (rectWindow.bottom - rectRun.top);
|
|
MoveWindow(&rectWindow);
|
|
}
|
|
|
|
// Insert the columns.
|
|
|
|
CRect rect;
|
|
m_list.GetClientRect(&rect);
|
|
int cxWidth = rect.Width();
|
|
|
|
LVCOLUMN lvc;
|
|
lvc.mask = LVCF_TEXT | LVCF_WIDTH;
|
|
|
|
::AfxSetResourceHandle(_Module.GetResourceInstance());
|
|
CString strColumn;
|
|
strColumn.LoadString(IDS_DATECAPTION);
|
|
lvc.pszText = (LPTSTR)(LPCTSTR)strColumn;
|
|
lvc.cx = 4 * cxWidth / 10;
|
|
ListView_InsertColumn(m_list.m_hWnd, 0, &lvc);
|
|
|
|
strColumn.LoadString(IDS_CHANGECAPTION);
|
|
lvc.pszText = (LPTSTR)(LPCTSTR)strColumn;
|
|
lvc.cx = 6 * cxWidth / 10;
|
|
ListView_InsertColumn(m_list.m_hWnd, 1, &lvc);
|
|
|
|
FillChangeList();
|
|
|
|
CenterWindow();
|
|
|
|
return 1; // Let the system set the focus
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// When one of the items in the list view changes, we need to check the
|
|
// state of the check boxes. In particular, if there are any boxes checked,
|
|
// we need to enable to Undo Selected button. Also, we can't allow any
|
|
// boxes items to be checked unless all of the more recent items for the
|
|
// tab are also checked.
|
|
//-------------------------------------------------------------------------
|
|
|
|
LRESULT OnItemChangedListChanges(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
|
|
{
|
|
LPNMLISTVIEW pnmv = (LPNMLISTVIEW) pnmh;
|
|
if (!pnmv)
|
|
return 0;
|
|
|
|
CString strTab, strCheckTab;
|
|
m_pUndoLog->GetUndoEntry(pnmv->iItem, &strTab, NULL);
|
|
|
|
BOOL fChecked = ListView_GetCheckState(m_list.m_hWnd, pnmv->iItem);
|
|
if (fChecked)
|
|
{
|
|
// Make sure all previous entries in the list with the same
|
|
// tab name are also checked.
|
|
|
|
for (int i = pnmv->iItem - 1; i >= 0; i--)
|
|
if (m_pUndoLog->GetUndoEntry(i, &strCheckTab, NULL) && strTab.Compare(strCheckTab) == 0)
|
|
ListView_SetCheckState(m_list.m_hWnd, i, TRUE);
|
|
}
|
|
else
|
|
{
|
|
// Make sure all later entries in the list with the same tab
|
|
// name are unchecked.
|
|
|
|
int iCount = ListView_GetItemCount(m_list.m_hWnd);
|
|
for (int i = pnmv->iItem + 1; i < iCount; i++)
|
|
if (m_pUndoLog->GetUndoEntry(i, &strCheckTab, NULL) && strTab.Compare(strCheckTab) == 0)
|
|
ListView_SetCheckState(m_list.m_hWnd, i, FALSE);
|
|
}
|
|
|
|
for (int i = ListView_GetItemCount(m_list.m_hWnd) - 1; i >= 0; i--)
|
|
if (ListView_GetCheckState(m_list.m_hWnd, i))
|
|
{
|
|
::EnableWindow(GetDlgItem(IDC_BUTTONUNDOSELECTED), TRUE);
|
|
return 0;
|
|
}
|
|
|
|
::EnableWindow(GetDlgItem(IDC_BUTTONUNDOSELECTED), FALSE);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT OnClickedClose(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
EndDialog(wID);
|
|
return 0;
|
|
}
|
|
|
|
void FillChangeList()
|
|
{
|
|
ListView_DeleteAllItems(m_list.m_hWnd);
|
|
|
|
ASSERT(m_pUndoLog);
|
|
if (!m_pUndoLog)
|
|
return;
|
|
|
|
LVITEM lvi;
|
|
lvi.mask = LVIF_TEXT;
|
|
|
|
int nEntries = m_pUndoLog->GetUndoEntryCount();
|
|
for (int i = 0; i < nEntries; i++)
|
|
{
|
|
COleDateTime timestamp;
|
|
CString strDescription, strTimestamp;
|
|
|
|
if (m_pUndoLog->GetUndoEntryInfo(i, strDescription, timestamp))
|
|
{
|
|
strTimestamp = timestamp.Format();
|
|
lvi.pszText = (LPTSTR)(LPCTSTR)strTimestamp;
|
|
lvi.iSubItem = 0;
|
|
lvi.iItem = i;
|
|
ListView_InsertItem(m_list.m_hWnd, &lvi);
|
|
|
|
lvi.pszText = (LPTSTR)(LPCTSTR)strDescription;
|
|
lvi.iSubItem = 1;
|
|
ListView_SetItem(m_list.m_hWnd, &lvi);
|
|
}
|
|
}
|
|
|
|
::EnableWindow(GetDlgItem(IDC_BUTTONUNDOALL), (nEntries != 0));
|
|
if (nEntries == 0)
|
|
::EnableWindow(GetDlgItem(IDC_BUTTONUNDOSELECTED), FALSE);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// When the user chooses to undo selected items or all items, we need
|
|
// to locate the tab page for each change and call its undo function.
|
|
//-------------------------------------------------------------------------
|
|
|
|
LRESULT OnClickedButtonUndoAll(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
DoUndo(TRUE);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT OnClickedButtonUndoSelected(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
DoUndo(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
void DoUndo(BOOL fAll)
|
|
{
|
|
CString strTab, strEntry;
|
|
int iUndoIndex = 0, iCount = ListView_GetItemCount(m_list.m_hWnd);
|
|
|
|
// Have to do something a little screwy here. Since the index into the
|
|
// undo log is based on the number of changes into the log (not counting
|
|
// undone entries), we need to keep track of the index into the undo log.
|
|
// This undo index will not be incremented when we undo an entry (undoing
|
|
// it makes it invisible, so the same index will then point to the next
|
|
// undo entry).
|
|
|
|
for (int i = 0; i < iCount; i++)
|
|
if (fAll || ListView_GetCheckState(m_list.m_hWnd, i))
|
|
m_pUndoLog->UndoEntry(iUndoIndex);
|
|
else
|
|
iUndoIndex += 1;
|
|
|
|
FillChangeList();
|
|
}
|
|
|
|
HRESULT ShowDialog()
|
|
{
|
|
return ((DoModal() == IDC_RUNMSCONFIG) ? S_FALSE : S_OK);
|
|
}
|
|
|
|
LRESULT OnClickedRunMSConfig(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
EndDialog(IDC_RUNMSCONFIG);
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
CWindow m_list;
|
|
CUndoLog * m_pUndoLog;
|
|
BOOL m_fFromUserClick;
|
|
};
|
|
|
|
#endif //__UNDODIALOG_H_
|