UserListCtrl.cpp. #1

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

#include "stdafx.h"
#include "p4win.h"
#include "UserView.h"
#include "MainFrm.h"
#include "cmd_editspec.h"
#include "cmd_describe.h"
#include "cmd_delete.h"
#include "cmd_users.h"
#include "newclientdlg.h"
#include "setpwddlg.h"
#include "ImageList.h"
#include <afxpriv.h>

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


static LPCTSTR sRegValue_UserList = _T("User List");

enum UserSubItem
{
    USER_NAME,
    USER_EMAIL,
    USER_FULLNAME,
    USER_DATEACCESS,
    USER_MAXCOL
};

/////////////////////////////////////////////////////////////////////////////
// CUserListCtrl

BEGIN_MESSAGE_MAP(CUserListCtrl, CP4ListCtrl)
	ON_COMMAND(ID_USER_DELETE, OnUserDelete)
	ON_UPDATE_COMMAND_UI(ID_USER_DELETE, OnUpdateUserDelete)
	ON_UPDATE_COMMAND_UI(ID_VIEW_UPDATE_RIGHT, OnUpdateViewUpdate)
	ON_WM_CONTEXTMENU()
	ON_UPDATE_COMMAND_UI(ID_USER_DESCRIBE, OnUpdateUserDescribe)
	ON_WM_LBUTTONDBLCLK()
	ON_COMMAND(ID_USER_CREATENEWUSER, OnUserCreatenewuser)
	ON_UPDATE_COMMAND_UI(ID_USER_SWITCHTOUSER, OnUpdateUserSwitchtouser)
	ON_COMMAND(ID_USER_SWITCHTOUSER, OnUserSwitchtouser)
	ON_UPDATE_COMMAND_UI(ID_SETDEFUSER, OnUpdateSetDefUser)
	ON_COMMAND(ID_SETDEFUSER, OnSetDefUser)
	ON_UPDATE_COMMAND_UI(ID_USER_PASSWORD, OnUpdateUserPassword)
	ON_WM_CREATE()
	ON_COMMAND(ID_USER_DESCRIBE, OnDescribe)
	ON_COMMAND(ID_VIEW_UPDATE_RIGHT, OnViewUpdate)
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
	ON_NOTIFY_REFLECT(LVN_DELETEITEM, OnDeleteitem)
	ON_COMMAND(ID_USER_PASSWORD, OnUserPassword)
	ON_UPDATE_COMMAND_UI(ID_ADD_REVIEWS, OnUpdateAddReviews)
	ON_COMMAND(ID_ADD_REVIEWS, OnAddReviews)
	ON_MESSAGE(WM_P4USERS, OnP4UserList )
	ON_MESSAGE(WM_P4EDITSPEC, OnP4UserSpec )
	ON_MESSAGE(WM_P4ENDSPECEDIT, OnP4EndSpecEdit )
	ON_MESSAGE(WM_P4DELETE, OnP4Delete )
    ON_MESSAGE(WM_P4DESCRIBE, OnP4Describe )
    ON_MESSAGE(WM_P4ENDDESCRIBE, OnP4EndDescribe )
END_MESSAGE_MAP()

IMPLEMENT_DYNCREATE(CUserListCtrl, CP4ListCtrl)

CUserListCtrl::CUserListCtrl()
{
    m_SortAscending=TRUE;
    m_viewType = P4USER_SPEC;
	m_OldDefUser = m_OldCurUser = _T("@");

    m_CF_DEPOT = static_cast<CLIPFORMAT>(RegisterClipboardFormat(LoadStringResource(IDS_DRAGFROMDEPOT)));
	m_CF_USER  = static_cast<CLIPFORMAT>(RegisterClipboardFormat(LoadStringResource(IDS_DRAGFROMUSER)));
	m_caption  = m_captionplain = LoadStringResource(IDS_PERFORCE_USERS);
}

CUserListCtrl::~CUserListCtrl()
{
}

/////////////////////////////////////////////////////////////////////////////
// CUserListCtrl diagnostics

#ifdef _DEBUG
void CUserListCtrl::AssertValid() const
{
	CP4ListCtrl::AssertValid();
}

void CUserListCtrl::Dump(CDumpContext& dc) const
{
	CP4ListCtrl::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CUserListCtrl message handlers

void CUserListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	int index = GetHitItem ( point );
	if( index > -1 )
	{
		SetItemState(index, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
		OnDescribe( );
	}
	else
		CP4ListCtrl::OnLButtonDblClk(nFlags, point);
}


void CUserListCtrl::Clear() 
{
    SetRedraw(FALSE);
	DeleteAllItems();
	SetRedraw(TRUE);

	CP4ListCtrl::Clear();
}


void CUserListCtrl::OnDeleteitem(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	
	delete (CP4User *) GetItemData(pNMListView->iItem);
			
	*pResult = 0;
}


/*
	_________________________________________________________________

	everything you need for a delete, the cmd ui, the first part of
	the delete, that sends a window message to this window, that comes
	right back and calls the second function for a delete.
	_________________________________________________________________
*/

void CUserListCtrl::OnUpdateUserDelete(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( OnUpdateShowMenuItem( pCmdUI, IDS_DELETE_s )
			&& GetSelectedItemText() == GET_P4REGPTR()->GetP4User()
			&& !MainFrame()->IsModlessUp() );
}

BOOL CUserListCtrl::OKToDelete( ) 
{
	if ( GetSelectedItemText() == GET_P4REGPTR()->GetP4User() )
		return TRUE;	
	else
	{
		AfxMessageBox(IDS_YOU_DO_NOT_HAVE_PERMISSION_TO_DELETE_OTHER_USERS, MB_ICONINFORMATION);
		return FALSE;
	}
}

void CUserListCtrl::OnUserDelete() 
{
	OnDelete( P4USER_DEL );
}

void CUserListCtrl::EditTheSpec(CString *name)
{
	if ( *name == GET_P4REGPTR( )->GetP4User( ) )
		OnUserEditmy();
}

void CUserListCtrl::OnUserEditmy() 
{
	m_Active = GET_P4REGPTR()->GetP4User();
	
	int index = FindInList(GET_P4REGPTR()->GetP4User());
	if(index > -1)
	{
		SetItemState(index, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
		EnsureVisible(index, FALSE);
	}

    m_olduser= m_Active;
	OnEditSpec( m_Active );
}


void CUserListCtrl::OnUpdateUserDescribe(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( OnUpdateShowMenuItem( pCmdUI, IDS_DESCRIBEIT_s )
					&& !MainFrame()->IsModlessUp() );	
}

void CUserListCtrl::OnUserDescribe() 
{
	OnDescribe();
}

void CUserListCtrl::OnUpdateViewUpdate(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(!SERVER_BUSY() && !MainFrame()->IsModlessUp());
}

void CUserListCtrl::OnViewUpdate() 
{	
	m_Active = GetSelectedItemText();
	CCmd_Users *pCmd= new CCmd_Users;
	pCmd->Init( m_hWnd, RUN_ASYNC);
	if( pCmd->Run( ) )
	{
        MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_USER_LISTING) );
		MainFrame()->SetUserUpdateTime(GetTickCount());
		Clear();
		CP4ListCtrl::OnViewUpdate();
	}
	else
		delete pCmd;
}


void CUserListCtrl::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	//		make sure window is active
	//
	GetParentFrame()->ActivateFrame();


	///////////////////////////////
	// See ContextMenuRules.txt for order of menu commands!

	//		create an empty context menu
	//
	CP4Menu popMenu;
    popMenu.LoadMenu(IDR_USER);

	int	index;
    SetIndexAndPoint( index, point );

	if( index != -1 )
	{
		// Can only edit or delete my user
		if ( GetSelectedItemText( ) == GET_P4REGPTR( )->GetP4User( ) )
		{
            // can't switch if already there
            popMenu.GetSubMenu(0)->DeleteMenu(ID_USER_SWITCHTOUSER,MF_BYCOMMAND);
        }
        else
        {
            // can't edit, delete, set password or set as default if not current
            popMenu.GetSubMenu(0)->DeleteMenu(ID_USER_EDITMY,MF_BYCOMMAND);
            popMenu.GetSubMenu(0)->DeleteMenu(ID_USER_DELETE,MF_BYCOMMAND);
            popMenu.GetSubMenu(0)->DeleteMenu(ID_USER_PASSWORD,MF_BYCOMMAND);
            popMenu.GetSubMenu(0)->DeleteMenu(ID_SETDEFUSER,MF_BYCOMMAND);
        }
	}
    else
    {
        // can't do much if no user selected
        popMenu.GetSubMenu(0)->DeleteMenu(ID_USER_EDITMY,MF_BYCOMMAND);
        popMenu.GetSubMenu(0)->DeleteMenu(ID_USER_DESCRIBE,MF_BYCOMMAND);
        popMenu.GetSubMenu(0)->DeleteMenu(ID_USER_DELETE,MF_BYCOMMAND);
        popMenu.GetSubMenu(0)->DeleteMenu(ID_USER_SWITCHTOUSER,MF_BYCOMMAND);
        popMenu.GetSubMenu(0)->DeleteMenu(ID_USER_PASSWORD,MF_BYCOMMAND);
        popMenu.GetSubMenu(0)->DeleteMenu(ID_SETDEFUSER,MF_BYCOMMAND);
        // clobber extra separator
        popMenu.GetSubMenu(0)->DeleteMenu(1,MF_BYPOSITION);

    }

	MainFrame()->AddToolsToContextMenu((CP4Menu *)(popMenu.GetSubMenu(0)));

	popMenu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,	point.x, point.y, AfxGetMainWnd());
}


/////////////////////////////////////////////////////////////////////////////
// CUserListCtrl message handlers

void CUserListCtrl::InsertUser(CP4User *user, int index)
{
	ASSERT(user != NULL);
	m_iImage = CP4ViewImageList::VI_USER;

	LV_ITEM lvItem;
	int iActualItem = -1;
	CString curuser = GET_P4REGPTR()->GetP4User();
	CString defuser = GET_P4REGPTR()->GetP4User(TRUE);

	for(int subItem=USER_NAME; subItem < USER_MAXCOL; subItem++)
	{
        lvItem.mask=LVIF_TEXT | 
                    ((subItem==USER_NAME) ? LVIF_IMAGE : 0) |
                    ((subItem==USER_NAME) ? LVIF_PARAM : 0);

        lvItem.iItem= (subItem==USER_NAME) ? index : iActualItem;
        ASSERT(lvItem.iItem != -1);

        lvItem.iSubItem= subItem;

		switch(subItem)
		{
		case USER_NAME: 
			{
			lvItem.pszText= const_cast<LPTSTR>(user->GetUserName());
			bool isCurrent = curuser.Compare(lvItem.pszText) == 0;
			bool isDefault = defuser.Compare(lvItem.pszText) == 0;
			lvItem.iImage = CP4ViewImageList::GetUserIndex(isCurrent, isDefault);
			if(isDefault)
				m_OldDefUser = lvItem.pszText;
			if(isCurrent)
				m_OldCurUser = lvItem.pszText;
	        lvItem.lParam=(LPARAM) user;
			}
			break;
		case USER_EMAIL: 
			lvItem.pszText= const_cast<LPTSTR>(user->GetEmail()); break;
		case USER_FULLNAME: 
			lvItem.pszText= const_cast<LPTSTR>(user->GetFullName()); break;
		case USER_DATEACCESS: 
			lvItem.pszText= const_cast<LPTSTR>(user->GetLastAccess()); break;
		}
			
		if(subItem==0)
			iActualItem = InsertItem(&lvItem);
		else
			SetItem(&lvItem);
	}
}


void CUserListCtrl::UpdateUser(CP4User *user, int index)
{
	// After a spec edit, update the appropriate list item

	// First, switch the user data
	CP4User *oldUser= (CP4User *) GetItemData(index);
	delete oldUser;
	SetItemData(index, (LPARAM) user);

	// Then update the text
	SetItemText(index, USER_NAME, const_cast<LPTSTR>(user->GetUserName()));
	SetItemText(index, USER_EMAIL, const_cast<LPTSTR>(user->GetEmail()));
	SetItemText(index, USER_FULLNAME, const_cast<LPTSTR>(user->GetFullName()));
	SetItemText(index, USER_DATEACCESS, const_cast<LPTSTR>(user->GetLastAccess()));
}


// Receives ak for user spec update
LRESULT CUserListCtrl::OnP4UserSpec(WPARAM wParam, LPARAM lParam)
{
	CCmd_EditSpec *pCmd= (CCmd_EditSpec *) wParam;

	BOOL newUser;				        // Save whether an edit operation refer to a new user
	pCmd->SetIsRequestingNew(newUser = pCmd->GetIsNewUser());
	pCmd->SetCaller(DYNAMIC_DOWNCAST(CView, GetParent()));

	int i, j;

    CString specIn(pCmd->GetSpecIn());
    if (m_ReviewsList.GetCount() > 0)	// We have files to add to the Reviews list
	{
		if ((i = specIn.Find(_T("\n\nReviews:\n"))) == -1)
		{
			i = specIn.GetLength();
			specIn += _T("\n\nReviews:\n");
		}
		else
			specIn += _T("\t#\n");	//	A review that is a single # means
										//	put a blank line in the list here.
		POSITION pos;
		for(pos = m_ReviewsList.GetHeadPosition(); pos != NULL; )
		{
		    CString filename = m_ReviewsList.GetNext(pos);
			if ((i = filename.Find(_T("<contains no files or folders>"))) != -1)
				filename = filename.Left(i-1) + _T("/...");
			if (filename.Find(_T(' ')) != -1)
				filename = _T('\"') + filename + _T('\"');
			if (specIn.Find(filename) == -1)
				specIn += _T('\t') + filename + _T('\n');
		}
		m_ReviewsList.RemoveAll();		// this info is no longer needed
        pCmd->SetSpecIn(specIn);
	}
	m_oldJobView = _T("");
	if ((i = specIn.Find(_T("\n\nJobView:\t"))) != -1)
	{
		i += lstrlen(_T("\n\nJobView:\n"));
		if ((j = specIn.Find(_T('\n'),i)) != -1)
			m_oldJobView = specIn.Mid(i, j-i);
	}
	if(!pCmd->GetError() && !m_EditInProgress && pCmd->DoSpecDlg(this))
	{
		m_EditInProgress = TRUE;
		m_EditInProgressWnd = pCmd->GetSpecSheet();
	}
	else
	{
		delete m_pNewSpec;
		CString txt;
		txt.FormatMessage(IDS_A_USER_HAS_BEEN_CREATED_DELETE_IT_s, m_Active);
		if (newUser && (FindInList(m_Active) == -1) 
					&& (CString(pCmd->GetErrorText()).Find(_T(" - over license quota")) == -1)
			        && (pCmd->GetError() || (IDYES == AfxMessageBox(txt, 
												MB_YESNO | MB_DEFBUTTON1 | MB_ICONQUESTION))))
		{
			CCmd_Delete *pCmd2 = new CCmd_Delete;
			pCmd2->Init( NULL, RUN_SYNC, TRUE, pCmd->GetServerKey() );
			if (pCmd2->Run( P4USER_DEL, m_Active ))
			{
				// nothing to do
			}
			else
			{
				::PostMessage(MainFrame()->m_hWnd, WM_COMMAND, ID_VIEW_UPDATE, 0);
			}
			delete pCmd2;
		}
		else
			::PostMessage(MainFrame()->m_hWnd, WM_COMMAND, ID_VIEW_UPDATE, 0);
		if (GET_P4REGPTR()->GetExpandFlag() == 1)
			GET_P4REGPTR()->AddMRUPcuPath(MainFrame()->GetCurrentItemPath());
		m_Active = m_olduser;
		GET_P4REGPTR()->SetP4User( m_olduser, TRUE, FALSE, FALSE );
		MainFrame()->UpdateCaption( ) ;	

		if (pCmd->HaveServerLock())
			pCmd->ReleaseServerLock();
		delete pCmd;
	}
	
	MainFrame()->ClearStatus();
	return 0;
}

LRESULT CUserListCtrl::OnP4EndSpecEdit( WPARAM wParam, LPARAM lParam )
{
	CCmd_EditSpec *pCmd= (CCmd_EditSpec *) wParam;
	int i, j;

	if (lParam != IDCANCEL && lParam != IDABORT)
	{
		if (m_UpdateState == LIST_UPDATED)
		{
			// we have to set 'index' again in case user's name got changed
			int index = FindInList(m_pNewSpec->GetUserName());
			if(index > -1 )
				UpdateUser(m_pNewSpec, index);
			else
			{
				InsertUser(m_pNewSpec, GetItemCount());
				ReSort();

				if( m_Active != m_olduser )
				{
					if (GET_P4REGPTR()->GetExpandFlag() == 1)
						GET_P4REGPTR()->AddMRUPcuPath(MainFrame()->GetCurrentItemPath());
					m_Active = m_olduser;
					GET_P4REGPTR()->SetP4User( m_olduser, TRUE, FALSE, FALSE );
					MainFrame()->UpdateCaption( ) ;	
				}
			}
		}
		else
			if ( m_pNewSpec ) delete m_pNewSpec;

	    CString specOut(pCmd->GetSpecOut());
		if ((i = specOut.Find(_T("\n\nJobView:\t"))) != -1)
		{
			i += lstrlen(_T("\n\nJobView:\n"));
			if ((j = specOut.Find(_T('\n'),i)) != -1)
			{
				// if JobView has changed, we have to refresh the changelists (and depot)
				if (m_oldJobView != specOut.Mid(i, j-i))
					MainFrame()->UpdateDepotandChangeViews(TRUE);
			}
		}
	}
	else
		if ( m_pNewSpec ) delete m_pNewSpec;

	if (lParam != IDABORT)
	{
		MainFrame()->ClearStatus();
		if (pCmd->HaveServerLock())
			pCmd->ReleaseServerLock();
		CDialog *dlg = (CDialog *)pCmd->GetSpecSheet();
		dlg->DestroyWindow();
	}

	if ((lParam == IDCANCEL) && pCmd->GetIsNewUser())	// if canceled, cleanup newly created user
	{
		m_Active = pCmd->GetItemName();
		CString msg;
		msg.FormatMessage ( IDS_DELETENEWUSER_s, m_Active );
		// ask if they want to delete the newly created user
		if( AfxMessageBox( msg, MB_YESNO|MB_ICONQUESTION ) == IDYES)
		{
			// fire off the delete of the newly created user
			CCmd_Delete *pCmdDel = new CCmd_Delete;
			pCmdDel->Init( m_hWnd, RUN_ASYNC );
			pCmdDel->SetSwitch2User( m_olduser );
			if( pCmdDel->Run( P4USER_DEL, m_Active ) )
				MainFrame()->UpdateStatus( LoadStringResource(IDS_DELETING) );
			else
				delete pCmdDel;
		}
		else
		{
			OnViewUpdate();
		}
	}

	delete pCmd;
	m_EditInProgress = FALSE;
	return 0;
}

LRESULT CUserListCtrl::OnP4UserList(WPARAM wParam, LPARAM lParam)
{
	CCmd_Users *pCmd= (CCmd_Users *) wParam;

	if(!pCmd->GetError())
	{
	    CObList const *users = pCmd->GetList();

        SetRedraw(FALSE);
    	int index = 0;
		for(POSITION pos= users->GetHeadPosition(); pos != NULL; index++)
		{
        	CP4User *user = (CP4User *) users->GetNext(pos);
			InsertUser(user, index);
		}
        SetRedraw(TRUE);
		
		CString msg;
		msg.FormatMessage( IDS_NUMBER_OF_USERS_n, index );
		AddToStatus( msg, SV_COMPLETION );

		ReSort();

		// Make sure previous item is re-selected
		if(users->GetCount() > 0)
		{
			int i = FindInList(m_Active.IsEmpty() 
				? GET_P4REGPTR()->GetP4User() : m_Active);
			if (i < 0)	
				i=0;
			SetItemState(i, LVIS_SELECTED|LVIS_FOCUSED, 
				LVIS_SELECTED|LVIS_FOCUSED);
			EnsureVisible(i, FALSE);
			// If m_Active is empty but we found the current user in the list,
			// then set m_Active to the correct value
			if (m_Active.IsEmpty() && i >= 0)
				m_Active = GET_P4REGPTR()->GetP4User();
		}

		CP4ListCtrl::SetUpdateDone();
		// Notify the mainframe that we have finished getting the users,
		// hence the entire set of async command have finished.
		MainFrame()->ExpandDepotIfNeedBe();
		if (m_PostViewUpdateMsg)
			PostMessage(m_PostViewUpdateMsg, m_PostViewUpdateWParam, m_PostViewUpdateLParam);
	}
	else
		CP4ListCtrl::SetUpdateFailed();
	
		
	delete pCmd;
	m_PostViewUpdateMsg = 0;
	MainFrame()->ClearStatus();
	return 0;
}

//////////////////////////////////////////////////////////////////////////
// Sort callback


int CUserListCtrl::OnCompareItems(LPARAM lParam1, LPARAM lParam2, int subItem)
{
    ASSERT(lParam1 && lParam2);
    CP4User const *user1 = (CP4User const*)lParam1;
    CP4User const *user2 = (CP4User const*)lParam2;

	CString txt1, txt2;
	switch(subItem)
	{
	case USER_NAME:	
		txt1= user1->GetUserName();
		txt2= user2->GetUserName();
		break;

	case USER_EMAIL:
		txt1= user1->GetEmail();
		txt2= user2->GetEmail();
		break;

	case USER_FULLNAME:
		txt1= user1->GetFullName();
		txt2= user2->GetFullName();
		break;

	case USER_DATEACCESS:
		txt1= user1->GetLastAccess();
		txt2= user2->GetLastAccess();
		ConvertDates( txt1, txt2 );
		break;

	default:
		ASSERT(0);
		return 0;
	}
	txt1.MakeUpper();
	txt2.MakeUpper();

	int rc;

	if(m_SortAscending)
		rc = txt1.Compare(txt2);
	else
		rc = txt2.Compare(txt1);

	return rc;
}

void CUserListCtrl::OnUserCreatenewuser() 
{
	if (m_EditInProgress)
	{
		CantEditRightNow(IDS_USER);
		return;
	}

	MainFrame()->ViewUsers();
	m_olduser = GET_P4REGPTR()->GetP4User( );

	//		let user type in the new name. if it's blank the user bailed.
	//

	CNewClientDlg newdlg;
	newdlg.SetNew( NEWUSER );
	if (FindInList(m_Active) != -1)
		newdlg.m_Active = m_Active;
	if( newdlg.DoModal( ) == IDCANCEL )
		return;

	CString saveActive = m_Active;
	m_Active = newdlg.GetName( ) ;
	if ( m_Active.IsEmpty( ) )
	{
		m_Active = saveActive;
		return;
	}
	if (FindInListNoCase(m_Active) != -1)
	{
		CString msg;
		UINT nType;
		if (FindInList(m_Active) != -1)
		{
			msg.FormatMessage ( IDS_USER_s_ALREADY_EXIST, m_Active );
			nType = MB_OK;
		}
		else
		{
			msg.FormatMessage ( IDS_USER_s_DIFFCASE_EXIST, m_Active );
			nType = MB_YESNO;
		}
		if (IDYES != AfxMessageBox( msg, nType ))
		{
			m_Active = saveActive;
			return;
		}
	}

    if ( SetP4User( ) ) 
		OnEditSpec( m_Active, TRUE );
}


BOOL CUserListCtrl::SetP4User( )
{
	//		not that we'd ever get here... but if they are the same, there 
	//		is nothing to do, so bail.
	//
	if ( m_Active == GET_P4REGPTR()->GetP4User() ) 
		return FALSE;

	if (GET_P4REGPTR()->GetExpandFlag() == 1)
		GET_P4REGPTR()->AddMRUPcuPath(MainFrame()->GetCurrentItemPath());

	//		okay, change the session's user. 
	//		(either we're setting the active user back to the registered one 
	//		after using another user, or we are officially resetting 
	//		the registered user to the new active one.)
	//

	if( !GET_P4REGPTR()->SetP4User( m_Active, TRUE, FALSE, FALSE ) )
	{
		AfxMessageBox( IDS_UNABLE_TO_WRITE_P4USER_TO_THE_REGISTRY, MB_ICONEXCLAMATION);
		m_Active  = GET_P4REGPTR()->GetP4User();
		return FALSE;
	}

    MainFrame()->UpdateCaption( ) ;	

	return TRUE;
}


void CUserListCtrl::OnUpdateUserSwitchtouser(CCmdUI* pCmdUI) 
{
	CString selUser = GetSelectedItemText();
    CString prompt;
    prompt.FormatMessage(IDS_SWITCH_TO_s, TruncateString(selUser, 50));
	pCmdUI->SetText ( prompt );
	pCmdUI->Enable( !SERVER_BUSY() 
					&& !selUser.IsEmpty() 
					&& selUser != GET_P4REGPTR()->GetP4User( )
					&& !MainFrame()->IsModlessUp() );
}

void CUserListCtrl::OnUserSwitchtouser() 
{
	m_Active = GetSelectedItemText();

	if ( SetP4User( ) )
		// We just added a user, so make sure the depot and changes
		// lists are updated
		MainFrame()->OnPerforceOptions( FALSE ) ;
}

void CUserListCtrl::OnUpdateSetDefUser(CCmdUI* pCmdUI) 
{
	CString selUser = GetSelectedItemText();
	pCmdUI->SetText ( LoadStringResource(IDS_SET_DEFAULT_USER_TO) + TruncateString(selUser, 50) );
	pCmdUI->Enable( !SERVER_BUSY() 
					&& !selUser.IsEmpty()
					&& selUser == GET_P4REGPTR()->GetP4User( FALSE )
					&& selUser != GET_P4REGPTR()->GetP4User( TRUE )
					&& !MainFrame()->IsModlessUp() );
}

void CUserListCtrl::OnSetDefUser() 
{
	if (m_Active != GetSelectedItemText())
	{
		ASSERT(0);
		return;
	}

	if (GET_P4REGPTR()->GetExpandFlag() == 1)
		GET_P4REGPTR()->AddMRUPcuPath(MainFrame()->GetCurrentItemPath());

	if( !GET_P4REGPTR()->SetP4User( m_Active, TRUE, TRUE, TRUE ) )
	{
		AfxMessageBox( IDS_UNABLE_TO_WRITE_P4USER_TO_THE_REGISTRY, MB_ICONEXCLAMATION);
		m_Active = GetSelectedItemText();
	}
	else
    {
        CString txt;
        txt.FormatMessage(IDS_DEFAULT_USER_SET_TO_s, m_Active);
		AddToStatus( txt );  
    }
}

void CUserListCtrl::OnEditSpec( LPCTSTR sItem, BOOL bNew/*=FALSE*/ )
{
	if (m_EditInProgress)
	{
		CantEditRightNow(IDS_USER);
		return;
	}

	m_pNewSpec = new CP4User;
	
	CCmd_EditSpec *pCmd = new CCmd_EditSpec;
	pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK );
	pCmd->SetIsNewUser(bNew);
	if( pCmd->Run( P4USER_SPEC, sItem, m_pNewSpec ) )
		MainFrame()->UpdateStatus( LoadStringResource(IDS_EDITING_USER_SPEC) ) ;
	else
	{
		delete pCmd;
		delete m_pNewSpec;
	}
}

void CUserListCtrl::OnUpdateUserPassword(CCmdUI* pCmdUI) 
{
	OnUpdateUserPassword( pCmdUI, TruncateString(GET_P4REGPTR()->GetP4User(), 50) );
}

void CUserListCtrl::OnUpdateUserPassword(CCmdUI* pCmdUI, LPCTSTR userName) 
{
    CString txt;
    txt.FormatMessage(IDS_SET_PASSWORD_FOR_s, TruncateString(userName, 50));
	pCmdUI->SetText ( txt );
	pCmdUI->Enable( !SERVER_BUSY() && GET_SERVERLEVEL() >= 6 
					&& lstrlen(userName)
					&& !MainFrame()->IsModlessUp());
}

void CUserListCtrl::OnUserPassword() 
{
	if(	GET_SERVERLEVEL() < 6 || !lstrlen(GET_P4REGPTR()->GetP4User()) )
		{ ASSERT(0); return; }
	
	OnUserPasswordDlg(FALSE, NULL);
}

int CUserListCtrl::OnUserPasswordDlg(BOOL bLogin, int key) 
{
	CSetPwdDlg dlg;
	dlg.m_bLogin = bLogin;
	dlg.m_Key = key;
	if (bLogin)
		dlg.m_Caption = LoadStringResource(IDS_MUST_SET_PASSWORD);
	return dlg.DoModal();
}


/////////////////////////////////////////////////////////////////////
// OLE drag-drop support, to accept depot files or folders
// which will define a view to be used to filter the submitted
// changes that this window displays
/////////////////////////////////////////////////////////////////////

DROPEFFECT CUserListCtrl::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) 
{
	m_DropEffect=DROPEFFECT_NONE;
	m_DragDataFormat=0;

	// Dont allow a drop if the server is busy, since a drop immediately attempts to
	// invoke a server command
	// Also don't allow a drop if we are in local syntax because
	// the reviews should be specified in depot syntax
	if(SERVER_BUSY() || m_EditInProgress || GET_P4REGPTR( )->ShowEntireDepot( ) > SDF_DEPOT)
		return DROPEFFECT_NONE;
		
	if(pDataObject->IsDataAvailable( m_CF_DEPOT))
	{
		m_DropEffect=DROPEFFECT_COPY;
		m_DragDataFormat=m_CF_DEPOT;
	}
	
	return m_DropEffect;
}

DROPEFFECT CUserListCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) 
{
	// Dont allow a drop if the server is busy, since a drop immediately attempts to
	// invoke a server command
	if(SERVER_BUSY() || m_EditInProgress)
		m_DropEffect= DROPEFFECT_NONE;
		
	return m_DropEffect;
}

BOOL CUserListCtrl::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) 
{
	if(SERVER_BUSY() || m_EditInProgress)
	{
		// OnDragEnter() and OnDragOver() should avoid a drop at 
		// the wrong time!
		ASSERT(0);
		return FALSE;
	}
	
	if(m_DragDataFormat == m_CF_DEPOT)
	{
		ClientToScreen(&point);
		::SendMessage(m_depotWnd, WM_DROPTARGET, USERVIEW, MAKELPARAM(point.x,point.y));
		return TRUE;
	}
	// Return false, so depot window doesnt start a file-open operation
	return FALSE;
}

int CUserListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CP4ListCtrl::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	CStringArray colnames;
	colnames.Add ( LoadStringResource(IDS_NAME) );
	colnames.Add ( LoadStringResource(IDS_E_MAIL) );
	colnames.Add ( LoadStringResource(IDS_FULL_NAME) );
	colnames.Add ( LoadStringResource(IDS_ACCESS) );
	ASSERT( USER_MAXCOL == colnames.GetSize( ) );
	int width[ USER_MAXCOL ]={90,150,150,90};
	RestoreSavedWidths( width, colnames.GetSize( ), sRegValue_UserList );
	InsertColumnHeaders( colnames, width );

	return 0;
}

void CUserListCtrl::OnUpdateAddReviews(CCmdUI* pCmdUI) 
{
	CString txt;
    txt.FormatMessage(IDS_ADD_FILES_TO_USER_s_REVIEWS, GET_P4REGPTR()->GetP4User());
	pCmdUI->SetText ( txt );
	pCmdUI->Enable( !SERVER_BUSY() && !m_EditInProgress
								   && GET_P4REGPTR()->ShowEntireDepot() <= SDF_DEPOT );
}

void CUserListCtrl::OnAddReviews() 
{
    if( ! SERVER_BUSY() )
    {
	    ::SendMessage(m_depotWnd, WM_GETSELLIST, (WPARAM) &m_ReviewsList, 0);
	    if(m_ReviewsList.GetCount() > 0)
		{
			OnUserEditmy();
		}
	}
}

BOOL CUserListCtrl::TryDragDrop( )
{
	// Store the job this is from
	m_DragFromItemName = GetSelectedItemText();

	m_OLESource.DelayRenderData( (unsigned short) m_CF_USER);

	return m_OLESource.DoDragDrop(DROPEFFECT_COPY, &m_DragSourceRect, NULL)
			== DROPEFFECT_NONE ? FALSE : TRUE;
}

void CUserListCtrl::OnNewUser(WPARAM wParam, LPARAM lParam)
{
	if (!IsClear())
	{
		CString olduser = wParam ? m_OldDefUser : m_OldCurUser;
		CString newuser = GET_P4REGPTR()->GetP4User((BOOL)wParam);
		CString defuser = GET_P4REGPTR()->GetP4User(TRUE);
		LV_ITEM lvItem;
		lvItem.mask = LVIF_IMAGE;
		lvItem.iSubItem = 0;
		lvItem.state = lvItem.stateMask = 0;

		lvItem.iItem = FindInList(olduser);
		if(lvItem.iItem > -1)
		{
			lvItem.iImage = CP4ViewImageList::GetUserIndex(false,
				olduser == defuser);
			SetItem(&lvItem);
		}

		lvItem.iItem = FindInList(newuser);
		if(lvItem.iItem > -1)
		{
			lvItem.iImage = CP4ViewImageList::GetUserIndex(true,
				newuser == defuser);
			SetItem(&lvItem);
		}
		if (wParam)
			m_OldDefUser = newuser;
		else
			m_OldCurUser = newuser;
	}
	::PostMessage(m_clientWnd, WM_NEWUSER, 0, 0);
	::PostMessage(m_branchWnd, WM_NEWUSER, 0, 0);
	::PostMessage(m_labelWnd,  WM_NEWUSER, 0, 0);
}
# Change User Description Committed
#1 19924 YourUncleBob Populate -o //guest/perforce_software/p4win/...
//guest/YourUncleBob/p4win/.....
//guest/perforce_software/p4win/main/gui/UserListCtrl.cpp
#1 16169 perforce_software Move files to follow new path scheme for branches.
//guest/perforce_software/p4win/gui/UserListCtrl.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.