P4ListBrowse.cpp. #1

  • //
  • guest/
  • YourUncleBob/
  • p4win/
  • main/
  • gui/
  • P4ListBrowse.cpp.
  • View
  • Commits
  • Open Download .zip Download (14 KB)
// P4ListBrowse.cpp : implementation file
//

#include "stdafx.h"
#include "p4win.h"
#include "MainFrm.h"
#include "P4Object.h"
#include "P4ListBrowse.h"
#include "StringUtil.h"
#include "RegKeyEx.h"
#include "cmd_describe.h"
#include "hlp\p4win.hh"
#include "P4ImageList.h"

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


static LPCTSTR sRegKey = _T("Software\\Perforce\\P4Win\\Layout\\");
static LPCTSTR sRegValue_ColumnWidths = _T("Column Widths");
static LPCTSTR sRegValue_SortColumns = _T("Sort Columns");

#define UPDATE_STATUS(x) ((CMainFrame *)AfxGetMainWnd())->UpdateStatus(x)
int CALLBACK P4ListBrowseSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
#define IMG_INDEX(x) (x-IDB_PERFORCE)


// Module global for use in sort callback
CP4ListBrowse *pDlg;
int viewType;


/////////////////////////////////////////////////////////////////////////////
// CP4ListBrowse dialog


CP4ListBrowse::CP4ListBrowse(CWnd* pParent, BOOL bWiz/*=FALSE*/, BOOL bBranchInteg/*=FALSE*/)
	: CDialog(CP4ListBrowse::IDD, pParent)
{
	//{{AFX_DATA_INIT(CP4ListBrowse)
	//}}AFX_DATA_INIT
	viewType = m_viewType;
	m_pParent = pParent;
	m_Wiz = bWiz;
	m_BranchInteg = bBranchInteg;
	m_SortAscending = m_FilterByHost = m_IsFiltered = FALSE;
	m_LastSortColumn= 0;
	pDlg=this;
	m_InitRect.SetRect(0,0,100,100);
	m_WinPos.SetWindow( this, bBranchInteg ? _T("IntegDlg") : _T("P4ListBrowse") );
	for (int i = -1; ++i < MAX_SORT_COLUMNS; )
		m_SortColumns[i] = 0;
}


void CP4ListBrowse::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CP4ListBrowse)
	DDX_Control(pDX, IDC_P4LIST, m_P4ListCtrl);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CP4ListBrowse, CDialog)
	//{{AFX_MSG_MAP(CP4ListBrowse)
	ON_WM_SIZE()
	ON_WM_GETMINMAXINFO()
	ON_NOTIFY(LVN_COLUMNCLICK, IDC_P4LIST, OnColumnclickP4list)
	ON_NOTIFY(NM_DBLCLK, IDC_P4LIST, OnDblclickP4list)
	ON_BN_CLICKED(IDC_REFRESH, OnRefresh)
	ON_BN_CLICKED(IDC_DESCRIBE, OnDescribe)
	ON_BN_CLICKED(IDC_BACK, OnBack)
//	ON_BN_CLICKED(IDHELP, OnHelp)
//	ON_WM_HELPINFO()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CP4ListBrowse message handlers

BOOL CP4ListBrowse::OnInitDialog() 
{
	CDialog::OnInitDialog();
	// Record the initial window size, then see if there is a registry preference
	GetWindowRect(&m_InitRect);
	m_LastRect = m_InitRect;
	if (!m_Wiz)
		m_WinPos.RestoreWindowPosition();

	CString str;

	SetWindowText(m_caption);
	SetFont(m_Font);
	
	// Modify the list control style so that the entire selected row is highlighted
	DWORD dwStyle = ::SendMessage(m_P4ListCtrl.m_hWnd,LVM_GETEXTENDEDLISTVIEWSTYLE,0,0);
	dwStyle |= LVS_EX_FULLROWSELECT;
	::SendMessage(m_P4ListCtrl.m_hWnd,LVM_SETEXTENDEDLISTVIEWSTYLE,0,dwStyle);

	// Make sure list control shows selection when not the focused control
	m_P4ListCtrl.ModifyStyle(0, LVS_SHOWSELALWAYS, 0);

	// Set the imagelist
	m_P4ListCtrl.SetImageList(TheApp()->GetImageList(), LVSIL_SMALL);

	if (m_Wiz)
	{
		GetDlgItem(IDC_BACK)->ShowWindow(SW_SHOW);
		GetDlgItem(IDC_BACK)->EnableWindow(TRUE);
		GetDlgItem(IDOK)->SetWindowText(LoadStringResource(IDS_FINISH));
		m_Hostname = GET_P4REGPTR()->GetHostname();
		m_FilterByHost = TRUE;
		if (!m_IsFiltered)
		{
			GetDlgItem(IDC_REFRESH)->EnableWindow(FALSE);
			GetDlgItem(IDC_REFRESH)->ShowWindow(SW_HIDE);
		}
	}
	else if (m_BranchInteg)
	{
		GetDlgItem(IDC_BACK)->ShowWindow(SW_SHOW);
		GetDlgItem(IDC_BACK)->EnableWindow(FALSE);
		GetDlgItem(IDOK)->SetWindowText(LoadStringResource(IDS_NEXT));
	}

	if (m_IsFiltered)
		GetDlgItem(IDC_REFRESH)->SetWindowText(LoadStringResource(IDS_CLEARFILTERR));

	// Get original size of control
	CRect rect;
	m_P4ListCtrl.GetWindowRect(&rect);

	int colwidth[MAX_P4OBJECTS_COLUMNS]={90,90,90,90,90,90,90,90,90,90};

	// make sure OnSize gets called to reposition controls
	// if restored position is default, this won't happen unless
	// we force it
	GetClientRect(&rect);
	SendMessage(WM_SIZE, 0, MAKELONG(rect.Width(), rect.Height()));

	// Get new size of control after resized as specified in the registry
	m_P4ListCtrl.GetWindowRect(&rect);

	// Get any saved column widths from registry
	RestoreSavedWidths(colwidth, MAX_P4OBJECTS_COLUMNS);

	// Make sure no column completely disappeared (because you can't get it back then)
	for (int i=-1; ++i < MAX_P4OBJECTS_COLUMNS; )
	{
		if (colwidth[i] < 5)
			colwidth[i] = 5;
	}
	// Use the same font as the calling window
	m_P4ListCtrl.SetFont(m_Font);

	// Insert the columns 
	int maxcols = m_ColNames->GetSize();
	int width=GetSystemMetrics(SM_CXVSCROLL);;
	int retval;
	LV_COLUMN lvCol;
	for(int subItem=0; subItem < maxcols; subItem++)
	{
		lvCol.mask= LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT |LVCF_WIDTH;
		lvCol.fmt=LVCFMT_LEFT;
		lvCol.pszText=( LPTSTR )( LPCTSTR ) m_ColNames->GetAt( subItem );
		lvCol.iSubItem=subItem;
		if(subItem < maxcols-1)
		{
			lvCol.cx=colwidth[subItem];
			width+=lvCol.cx;
		}
		else
			lvCol.cx=max(colwidth[subItem], rect.Width() - width - 4);  // expand last column to fill window
		retval=m_P4ListCtrl.InsertColumn(subItem, &lvCol);
	}
 
	AddTheListData();

	EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE);
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CP4ListBrowse::AddTheListData()
{
	// Add the data
	int maxcols = m_ColNames->GetSize();
	CP4Object *p4Object;
	LV_ITEM lvItem;
	int iActualItem = -1;
	CString txt;
	POSITION pos= m_pP4List->GetHeadPosition();
	int iItem;
	for(iItem=0; iItem < m_pP4List->GetCount(); iItem++)
	{
		p4Object= (CP4Object *) m_pP4List->GetNext(pos);

		if (m_FilterByHost)
		{
			txt = p4Object->GetField(2);
			if (!txt.IsEmpty() && txt.CompareNoCase(m_Hostname))
				continue;
		}
		
		for(int subItem=0; subItem < maxcols; subItem++)
		{
			lvItem.mask=LVIF_TEXT | 
					((subItem==0) ? LVIF_IMAGE : 0) |
					((subItem==0) ? LVIF_PARAM : 0);
			lvItem.iItem= (subItem==0) ? iItem : iActualItem;
            ASSERT(lvItem.iItem != -1);
			lvItem.iSubItem= subItem;
			lvItem.iImage = m_iImage;
			lvItem.lParam=(LPARAM) p4Object;
			txt=PadCRs(p4Object->GetField(subItem));
			lvItem.pszText = const_cast<LPTSTR>( (LPCTSTR ) txt);

			if(subItem==0)
				iActualItem=m_P4ListCtrl.InsertItem(&lvItem);
			else
				m_P4ListCtrl.SetItem(&lvItem);
		}
	}

	if(m_pP4List->GetCount())
	{
		// Sort the P4Objects list the same way the P4ListView is sorted
		viewType = m_viewType;
		m_P4ListCtrl.SortItems( P4ListBrowseSort, m_LastSortColumn );

		// Find the p4Object currently selected in the P4Objects pane
		iItem=0;
		if (!m_CurrP4Object->IsEmpty())
		{
			TCHAR cur[ LISTVIEWNAMEBUFSIZE + 1 ];
			TCHAR str[ LISTVIEWNAMEBUFSIZE + 1 ];

			lstrcpy(cur, m_CurrP4Object->GetBuffer(m_CurrP4Object->GetLength()+1));
			m_CurrP4Object->ReleaseBuffer(-1);
			for (int cnt = ListView_GetItemCount( m_P4ListCtrl.m_hWnd ); iItem < cnt; iItem++ )
			{
				ListView_GetItemText( m_P4ListCtrl.m_hWnd, iItem, 0, str, LISTVIEWNAMEBUFSIZE );
				if( !Compare(cur, str) )
					break;
			}
			if (iItem >= ListView_GetItemCount( m_P4ListCtrl.m_hWnd ))
				iItem = 0;
		}

		// Make sure the same p4Object is selected and visible
		m_P4ListCtrl.SetItemState(iItem, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
		m_P4ListCtrl.EnsureVisible( iItem, FALSE );
	}

	// And finally, set focus to the list control so that the first 'down'
	// keystroke can be used to scroll down
	m_P4ListCtrl.SetFocus();
}

void CP4ListBrowse::SetP4ObjectList(CObList *P4list)
{
	ASSERT_KINDOF(CObList,P4list);
	m_pP4List= P4list;
}

void CP4ListBrowse::SetP4ObjectCols(CStringArray *P4Cols)
{
	m_ColNames= P4Cols;
}

void CP4ListBrowse::SetP4ObjectCurr(CString *P4Name)
{
	m_CurrP4Object= P4Name;
}

void CP4ListBrowse::OnOK() 
{
	if (!m_Wiz)
		m_WinPos.SaveWindowPosition();

	int nItem=m_P4ListCtrl.GetNextItem( -1, LVNI_ALL | LVNI_SELECTED );
	if (nItem != -1)
	{
		TCHAR str[ LISTVIEWNAMEBUFSIZE + 1 ];
		ListView_GetItemText( m_P4ListCtrl.m_hWnd, nItem, 0, str, LISTVIEWNAMEBUFSIZE );
		m_SelectedP4Object = str;
	}
	else
		m_SelectedP4Object.Empty();
	
	EndDialog(IDOK);
}

void CP4ListBrowse::OnCancel() 
{
	if (!m_Wiz)
		m_WinPos.SaveWindowPosition();	
	CDialog::OnCancel();
}

void CP4ListBrowse::OnBack() 
{
	EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, FALSE);
	EndDialog(IDC_BACK);
}

void CP4ListBrowse::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);
	
	// Slide the OK and Cancel buttons to the bottom of dlg
	CWnd *pRefresh = GetDlgItem(IDC_REFRESH);
	CWnd *pBack = GetDlgItem(IDC_BACK);
	CWnd *pOK   = GetDlgItem(IDOK);
	CWnd *pCancel = GetDlgItem(IDCANCEL);
	CWnd *pDescribe = GetDlgItem(IDC_DESCRIBE);

	if(!pOK)
		return;

	CRect rect;
	GetWindowRect(&rect);
	int dx = rect.Width() - m_LastRect.Width();
	int dy = rect.Height() - m_LastRect.Height();
	// Save the new size
	m_LastRect = rect;

	// Move down
	pRefresh->GetWindowRect(&rect);
	ScreenToClient(rect);
	pRefresh->SetWindowPos(NULL, rect.left, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

	// Move down and slide right
	pBack->GetWindowRect(&rect);
	ScreenToClient(rect);
	pBack->SetWindowPos(NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

	pOK->GetWindowRect(&rect);
	ScreenToClient(rect);
	pOK->SetWindowPos(NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

	pCancel->GetWindowRect(&rect);
	ScreenToClient(rect);
	pCancel->SetWindowPos(NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

	pDescribe->GetWindowRect(&rect);
	ScreenToClient(rect);
	pDescribe->SetWindowPos(NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

	// Increase the size of the list both horiz and vert
	CWnd *pList = GetDlgItem(IDC_P4LIST);
	pList->GetWindowRect(&rect);
	pList->SetWindowPos(NULL, 0, 0, rect.right - rect.left + dx, 
								    rect.bottom - rect.top + dy, SWP_NOMOVE | SWP_NOZORDER);
	RedrawWindow();
}

void CP4ListBrowse::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) 
{
	lpMMI->ptMinTrackSize.x= m_InitRect.Width();
	lpMMI->ptMinTrackSize.y= m_InitRect.Height();
}

void CP4ListBrowse::OnColumnclickP4list(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	
    if(pNMListView->iSubItem != m_LastSortColumn)
		m_LastSortColumn=pNMListView->iSubItem;
	else
		m_SortAscending= !m_SortAscending;

	viewType = m_viewType;
	if(pNMListView->iItem == -1)
		m_P4ListCtrl.SortItems( P4ListBrowseSort,(DWORD)pNMListView->iSubItem);
	
	*pResult = 0;
}

// Since a sort column can only appear once in our saved column array,
// given the current column, we can determine the next column.
// Note that incoming 'colnbr' is a non-negative 0-relative number and must be incremented
// The return value is a signed 1-relative number; negative for descending, positive for ascending
int CP4ListBrowse::NextSortColumn(int lastcol)
{
	if (lastcol == 0)
		return 0;		// 0 => no next column
	lastcol++;
	for (int i = -1; ++i < (MAX_SORT_COLUMNS-1); )
	{
		if (abs(m_SortColumns[i]) == lastcol)
			return m_SortColumns[i+1];
	}
	return 0;			// 0 => no next column
}

int CALLBACK P4ListBrowseSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	int rc;
	int nextcol;
	CString txt1;
	CString txt2;

	if (viewType == P4CHANGE_SPEC && !lParamSort)
	{
		txt1.Format(_T("%09d"), _tstoi(((CP4Object const *)lParam1)->GetField(lParamSort)));
		txt2.Format(_T("%09d"), _tstoi(((CP4Object const *)lParam2)->GetField(lParamSort)));
	}
	else
	{
		txt1= ((CP4Object const *)lParam1)->GetField(lParamSort);
		txt2= ((CP4Object const *)lParam2)->GetField(lParamSort);
	}

	if(pDlg->IsSortAscending())
		rc = txt1.CompareNoCase(txt2);
	else
		rc = txt2.CompareNoCase(txt1);

	// check for duplicate keys; if so, sort on next sort columns
	if (!rc && lParamSort && ((nextcol = pDlg->NextSortColumn(lParamSort)) != 0))
	{
		// nextcol now contains a value like 1 for col-0-ascending or like -1 for col-0-decending
		BOOL saveSortAscending = pDlg->IsSortAscending();
		if (nextcol < 0)
		{
			nextcol = 0 - nextcol;
			pDlg->SetSortAscending(FALSE);
		}
		else
			pDlg->SetSortAscending(TRUE);
		rc = P4ListBrowseSort(lParam1, lParam2, (LPARAM)(nextcol-1));
		pDlg->SetSortAscending(saveSortAscending);
	}
	return rc;
}

// Check the registry to see if we have recorded the
// column widths lastused for the p4Object pane's list view.
void CP4ListBrowse::RestoreSavedWidths(int *width, int numcols)
{
    CRegKeyEx key;

    CString theKey = sRegKey + m_SubKey;
    if(ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, theKey, KEY_READ))
    {
        CString result = key.QueryValueString(sRegValue_ColumnWidths);
		CString sortCols = key.QueryValueString(sRegValue_SortColumns);
        if(!result.IsEmpty())
        {
			//		things can go wrong with the registry setting of the 
			//		widths. Use the defaults if the entry is all zeroes.
			//
			if ( result != _T("0,0,0,0,0,0,0,0,0,0") )
				for(int i=0; i< numcols; i++)
					width[i]= GetPositiveNumber(result);
        }
        if(!sortCols.IsEmpty())
        {
			for(int i=0; i< MAX_SORT_COLUMNS; i++)
            {
				m_SortColumns[i]= GetANumber(sortCols);
                if(!i && !m_SortColumns[i])
                    m_SortColumns[i] = 1;
            }
			m_LastSortColumn= abs(m_SortColumns[0]) - 1; // SortColumns are signed & 1-relative
			m_SortAscending = m_SortColumns[0] >= 0 ? TRUE : FALSE;
        }
    }
}

void CP4ListBrowse::OnRefresh() 
{
	EndDialog(IDC_REFRESH);
}

void CP4ListBrowse::OnDblclickP4list(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;
	OnOK();
}

void CP4ListBrowse::OnDescribe( void )
{
	int nItem=m_P4ListCtrl.GetNextItem( -1, LVNI_ALL | LVNI_SELECTED );
	if (nItem != -1)
	{
		TCHAR str[ LISTVIEWNAMEBUFSIZE + 1 ];
		ListView_GetItemText( m_P4ListCtrl.m_hWnd, nItem, 0, str, LISTVIEWNAMEBUFSIZE );
		m_SelectedP4Object = str;
		if ( m_SelectedP4Object.IsEmpty( ) )
			return;
	}
	else
		return;

	CCmd_Describe *pCmd = new CCmd_Describe;
	pCmd->Init( m_pParent->m_hWnd, RUN_ASYNC );
	pCmd->SetCaller(this);
	pCmd->SetListCtrl(&m_P4ListCtrl);
	if( pCmd->Run( m_viewType, m_SelectedP4Object ) )
	{
		MainFrame()->UpdateStatus( LoadStringResource(IDS_FETCHING_SPEC) );	
		return;
	}
	else
	{
		delete pCmd;
		return;
	}
}

#ifdef	WANTTOFILTERCLIENTSBYHOSTNAME
void CP4ListBrowse::OnFilter() 
{
	m_FilterByHost = !m_FilterByHost;
	m_P4ListCtrl.DeleteAllItems();
	AddTheListData();
}
#endif

#ifdef	HELPWANTEDFORP4LISTBROPWSE
void CP4ListBrowse::OnHelp() 
{
	AfxGetApp()->WinHelp(0);
}

BOOL CP4ListBrowse::OnHelpInfo(HELPINFO* pHelpInfo) 
{
	OnHelp();
	return TRUE;
}
#endif
# Change User Description Committed
#1 19924 YourUncleBob Populate -o //guest/perforce_software/p4win/...
//guest/YourUncleBob/p4win/.....
//guest/perforce_software/p4win/main/gui/P4ListBrowse.cpp
#1 16169 perforce_software Move files to follow new path scheme for branches.
//guest/perforce_software/p4win/gui/P4ListBrowse.cpp
#1 8562 Matt Attaway These feet never stop running.

Initial commit of the P4Win source code.  To the best of our knowledge this
compiles and runs using the 2013.3 P4 API and VS 2010. Expect a few changes
as we refine the build process. Please post any build issues to the forums.