// PropertiesList.cpp : implementation file
//

#include "stdafx.h"
#include "xkeymacs.h"
#include "Profile.h"
#include "Properties.h"
#include "PropertiesList.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CPropertiesList property page

BOOL CPropertiesList::m_bSortAscending = TRUE;

IMPLEMENT_DYNCREATE(CPropertiesList, CPropertyPage)

CPropertiesList::CPropertiesList() : CPropertyPage(CPropertiesList::IDD)
{
	//{{AFX_DATA_INIT(CPropertiesList)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
}

CPropertiesList::~CPropertiesList()
{
}

void CPropertiesList::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CPropertiesList)
	DDX_Control(pDX, IDC_PROPERTIES_LIST, m_cPropertiesList);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CPropertiesList, CPropertyPage)
	//{{AFX_MSG_MAP(CPropertiesList)
	ON_WM_CREATE()
	ON_NOTIFY(LVN_COLUMNCLICK, IDC_PROPERTIES_LIST, OnColumnclickPropertiesList)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPropertiesList message handlers

BOOL CPropertiesList::OnSetActive() 
{
	// TODO: Add your specialized code here and/or call the base class
	m_pProperties->EnableControl(LIST_TAB);
	SetDialogData(m_pProperties->GetCurrentApplication());

	return CPropertyPage::OnSetActive();
}

void CPropertiesList::SetDialogData(CString szApplicationName)
{
	UpdateDialogData(szApplicationName, FALSE);
}

void CPropertiesList::UpdateDialogData(CString szApplicationName, BOOL bSaveAndValidate)
{
	if (bSaveAndValidate) {	// GetDialogData
		UpdateData();
	}

	if (!bSaveAndValidate) {	// SetDialogData
		m_cPropertiesList.DeleteAllItems();
		m_nCategoryWidth = 0;
		m_nCommandWidth = 0;
		m_nKeyWidth = 0;

		for (int nCommandID = 1; nCommandID < sizeof(Commands) / sizeof(Commands[0]); ++nCommandID) {
			CString szCommandName = CXkeymacsData::GetCommandName(nCommandID);
			if (szCommandName.IsEmpty()) {
				break;
			}

			CString szCategory(MAKEINTRESOURCE(CXkeymacsData::GetCategoryID(nCommandID)));
			if (szCategory.IsEmpty()) {
				continue;
			}

			BOOL bInserted = FALSE;
			for (int nCommandType = 0; nCommandType < MAX_COMMAND_TYPE; ++nCommandType) {
				for (int nKey = 0; nKey < MAX_KEY; ++nKey) {
					if (nCommandID == CProfile::GetCommandID(m_pProperties->GetApplicationID(), nCommandType, nKey)) {
						CString szKey;
						szKey.Format("%s%s", CProfile::CommandType2String(nCommandType), CProfile::Key2String(nKey));

						InsertItem(szCategory, szCommandName, szKey);

						bInserted = TRUE;
					}
				}
			}
			if (!bInserted) {
				InsertItem(szCategory, szCommandName, "");
			}
		}

		SortItem(m_nSelectedColumn);
		m_cPropertiesList.SetColumnWidth(0, m_nCategoryWidth + 0x20);
		m_cPropertiesList.SetColumnWidth(1, m_nCommandWidth + 0x20);
		m_cPropertiesList.SetColumnWidth(2, m_nKeyWidth + 0x20);
	}

	if (!bSaveAndValidate) {	// SetDialogData
		UpdateData(FALSE);
	}
}

void CPropertiesList::GetDialogData()
{
	UpdateDialogData(m_pProperties->GetCurrentApplication(), TRUE);
}

int CPropertiesList::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CPropertyPage::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO: Add your specialized creation code here
	m_pProperties = (CProperties *)GetParent()->GetParent();

	return 0;
}

BOOL CPropertiesList::OnKillActive() 
{
	// TODO: Add your specialized code here and/or call the base class
	GetDialogData();

	return CPropertyPage::OnKillActive();
}

void CPropertiesList::EnableControl()
{
	BOOL bEnable = m_pProperties->IsEnableControl();

	m_cPropertiesList.EnableWindow(bEnable);
}

BOOL CPropertiesList::OnInitDialog() 
{
	CPropertyPage::OnInitDialog();

	// TODO: Add extra initialization here
	DWORD dwStyle = m_cPropertiesList.GetExtendedStyle();
	dwStyle |= LVS_EX_FULLROWSELECT;
	m_cPropertiesList.SetExtendedStyle(dwStyle);

	m_nSelectedColumn = 0;
	m_bSortAscending = TRUE;

	m_cPropertiesList.InsertColumn(0, CString(MAKEINTRESOURCE(IDS_CATEGORY)), LVCFMT_LEFT);
	m_cPropertiesList.InsertColumn(1, CString(MAKEINTRESOURCE(IDS_COMMAND)), LVCFMT_LEFT);
	m_cPropertiesList.InsertColumn(2, CString(MAKEINTRESOURCE(IDS_KEY)), LVCFMT_LEFT);

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

int CALLBACK CPropertiesList::SortCategory(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	return Sort(lParam1, lParam2, lParamSort, SORT_CATEGORY);
}

int CALLBACK CPropertiesList::SortCommand(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	return Sort(lParam1, lParam2, lParamSort, SORT_COMMAND);
}

int CALLBACK CPropertiesList::SortKey(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	return Sort(lParam1, lParam2, lParamSort, SORT_KEY);
}

void CPropertiesList::OnColumnclickPropertiesList(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	if (m_nSelectedColumn == pNMListView->iSubItem) {
		m_bSortAscending = !m_bSortAscending;
	} else {
		m_nSelectedColumn = pNMListView->iSubItem;
		m_bSortAscending = TRUE;
	}

	for (int nItem = 0; nItem < m_cPropertiesList.GetItemCount(); ++nItem) {
		m_cPropertiesList.SetItemData(nItem, nItem);
	}

	SortItem(pNMListView->iSubItem);

	*pResult = 0;
}

void CPropertiesList::DisplayIndicator()
{
	CHeaderCtrl *pHeaderCtrl = m_cPropertiesList.GetHeaderCtrl();

	for (int nItemCount = 0; nItemCount < pHeaderCtrl->GetItemCount(); ++nItemCount) {
		HDITEM hditem;
		pHeaderCtrl->GetItem(nItemCount, &hditem);

		if (nItemCount == m_nSelectedColumn) {
			hditem.mask = HDI_FORMAT | HDI_BITMAP;
			hditem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT;
			const int IDB_SORT = m_bSortAscending ? IDB_SORT_ASCENDING : IDB_SORT_DESCENDING;
			hditem.hbm = (HBITMAP)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_SORT), IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);
			pHeaderCtrl->SetItem(nItemCount, &hditem);
		} else {
			hditem.mask = HDI_FORMAT;
			hditem.fmt = HDF_STRING;
			hditem.hbm = NULL;
			pHeaderCtrl->SetItem(nItemCount, &hditem);
		}
	}
}

void CPropertiesList::SortItem(int nColumn)
{
	switch (nColumn) {
	case 0:
		m_cPropertiesList.SortItems(CPropertiesList::SortCategory, (LPARAM) &m_cPropertiesList);
		break;
	case 1:
		m_cPropertiesList.SortItems(CPropertiesList::SortCommand, (LPARAM) &m_cPropertiesList);
		break;
	case 2:
		m_cPropertiesList.SortItems(CPropertiesList::SortKey, (LPARAM) &m_cPropertiesList);
		break;
	default:
		m_cPropertiesList.SortItems(CPropertiesList::SortCategory, (LPARAM) &m_cPropertiesList);
		break;
	}

	DisplayIndicator();
}

void CPropertiesList::InsertItem(LPCTSTR szCategory, LPCTSTR szCommandName, LPCTSTR szKey)
{
	int nItem = m_cPropertiesList.InsertItem(m_cPropertiesList.GetItemCount(), szCategory);
	m_cPropertiesList.SetItemData(nItem, nItem);
	m_cPropertiesList.SetItemText(nItem, 1, szCommandName);
	m_cPropertiesList.SetItemText(nItem, 2, szKey);

	m_nCategoryWidth = __max(m_nCategoryWidth, m_cPropertiesList.GetStringWidth(szCategory));
	m_nCommandWidth = __max(m_nCommandWidth, m_cPropertiesList.GetStringWidth(szCommandName));
	m_nKeyWidth = __max(m_nKeyWidth, m_cPropertiesList.GetStringWidth(szKey));
}

int CPropertiesList::Sort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort, SORT_TYPE sortType)
{
	CListCtrl *pListCtrl = (CListCtrl *) lParamSort;

	CString szCategory1 = pListCtrl->GetItemText(lParam1, 0);
	CString szCommand1 = pListCtrl->GetItemText(lParam1, 1);
	CString szKey1 = pListCtrl->GetItemText(lParam1, 2);

	CString szCategory2 = pListCtrl->GetItemText(lParam2, 0);
	CString szCommand2 = pListCtrl->GetItemText(lParam2, 1);
	CString szKey2 = pListCtrl->GetItemText(lParam2, 2);

	int rc = 0;
	switch (sortType) {
	case SORT_CATEGORY:
		rc = rc ? rc : strcmp(szCategory1, szCategory2);
		// Do NOT write break; here.
	case SORT_COMMAND:
		rc = rc ? rc : strcmp(szCommand1, szCommand2);
		// Do NOT write break; here.
	case SORT_KEY:
		if (!rc) {
			rc = rc ? rc : strcmp(szKey1, szKey2);
			if (szKey1.IsEmpty() && !szKey2.IsEmpty()) {
				rc = 1;
			} else if (!szKey1.IsEmpty() && szKey2.IsEmpty()) {
				rc = -1;
			}
		}
		break;
	default:
		break;
	}
	return m_bSortAscending ? rc : rc * -1;
}

(C) 2001-2005 oishi@cam.hi-ho.ne.jp