StatusView.cpp. #1

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

#include "stdafx.h"
#include "p4win.h"
#include "StatusView.h"
#include "MainFrm.h"
#include "MsgBox.h"
#include "ImageList.h"
#include "cmd_where.h"

#pragma warning (push)
#pragma warning (disable: 4201)
#include <mmsystem.h>
#pragma warning (pop)

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


/////////////////////////////////////////////////////////////////////////////
// CStatusView

IMPLEMENT_DYNCREATE(CStatusView, CListView)

CStatusView::CStatusView()
{
	m_HeadIndex=0;
	m_ErrFound = m_RowAdded = FALSE;
	m_ShowStatusMsgs = GET_P4REGPTR()->GetShowStatusMsgs();
	OnMaxStatusLines();

    CString tempPath= GET_P4REGPTR()->GetTempDir();
	CreateDirectory(tempPath, NULL);	// make sure the directory exists
	for (int i = -1; ++i < 256; )
	{
		m_ErrFile.Format(_T("%s\\P4Werr%02x.txt"), tempPath, i);
		if ((m_hErrFile=CreateFile(m_ErrFile, GENERIC_READ | GENERIC_WRITE, 
					FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0)) != INVALID_HANDLE_VALUE)
		{
#ifdef UNICODE
			TCHAR msg[] = {0xFEFF};
			DWORD NumberOfBytesWritten;
			WriteFile(m_hErrFile, msg, 2, &NumberOfBytesWritten, NULL);
#endif
			break;
		}
	}
	EnableToolTips();
}

CStatusView::~CStatusView()
{
	CloseHandle(m_hErrFile);
}


BEGIN_MESSAGE_MAP(CStatusView, CListView)
	//{{AFX_MSG_MAP(CStatusView)
	ON_WM_SIZE()
	ON_WM_SETCURSOR()
	ON_WM_KEYDOWN()
	ON_WM_CONTEXTMENU()
	ON_NOTIFY_EX( TTN_NEEDTEXTW, 0, OnToolTipText )
	ON_NOTIFY_EX( TTN_NEEDTEXTA, 0, OnToolTipText )
	ON_COMMAND(ID_WINDOW_CLEAR, OnWindowClear)
	ON_COMMAND(ID_SHOW_COMMAND_TRACE, OnShowCommandTrace )
	ON_COMMAND(ID_SHOW_TIMESTAMP, OnShowTimestamp)
	ON_COMMAND(ID_SHOW_STATUSMSGS, OnShowStatusMsgs)
	ON_UPDATE_COMMAND_UI(ID_VIEW_WARNANDERR, OnUpdateViewWarnAndErrs)
	ON_COMMAND(ID_VIEW_WARNANDERR, OnViewWarnAndErrs)
	ON_UPDATE_COMMAND_UI(ID_WINDOW_COPYSELECTED, OnUpdateWindowCopyselected)
	ON_COMMAND(ID_EDIT_COPY, OnWindowCopyselected)
	ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateEditSelectAll)
	ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
	ON_UPDATE_COMMAND_UI(ID_POSITIONDEPOT, OnUpdateFindInDepot)
	ON_COMMAND(ID_POSITIONDEPOT, OnFindInDepot)
	ON_UPDATE_COMMAND_UI(ID_POSITIONCHGS, OnUpdateFindInChgs)
	ON_COMMAND(ID_POSITIONCHGS, OnFindInChgs)
	ON_COMMAND(ID_PERFORCE_OPTIONS, OnPerforceOptions)
	//}}AFX_MSG_MAP
	ON_MESSAGE( WM_FINDPATTERN, OnFindPattern )
	ON_WM_SYSCOLORCHANGE()
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CStatusView diagnostics

#ifdef _DEBUG
void CStatusView::AssertValid() const
{
	CListView::AssertValid();
}

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

/////////////////////////////////////////////////////////////////////////////
// CStatusView message handlers

void CStatusView::Clear()
{
	ListView_DeleteAllItems(m_hWnd);
	m_HeadIndex=0;
}


void CStatusView::OnInitialUpdate() 
{
	CListView::OnInitialUpdate();
	
	// Set image shared list
	CListCtrl& list= (CListCtrl&) GetListCtrl();
	list.SetImageList(TheApp()->GetImageList(), LVSIL_SMALL);
	
	LV_COLUMN lvCol;
	lvCol.mask= LVCF_FMT | LVCF_SUBITEM | LVCF_WIDTH;
	lvCol.fmt=LVCFMT_LEFT;
	lvCol.iSubItem=0;
	lvCol.cx=1800;  
			
	list.InsertColumn(0, &lvCol);
}

void CStatusView::AddItem(LPCTSTR text, StatusView level, bool showDialog, BOOL ensureVisible /*=TRUE */) 
{
	ASSERT(	text != NULL);
	ASSERT( level >= SV_MSG && level < SV_MAX);

	int len= lstrlen(text);
	BOOL didFirstRow= FALSE;
	BOOL write2file = (showDialog==true	|| level==SV_WARNING
		|| level==SV_ERROR || level==SV_WARNSUMMARY) ? TRUE : FALSE;

	if (write2file && TheApp()->m_RunClientWizOnly)
		showDialog = TRUE;

	// Alloc a large enough buffer and initialize cleanText
	CString cleanText(_T(' '), len + 10);   
	cleanText.Empty();
	if (GET_P4REGPTR()->ShowStatusTime())
	{
		SYSTEMTIME	st;

		GetLocalTime(&st);
		if (GET_P4REGPTR()->Use24hourClock())
		{
			cleanText.Format(_T("%02d:%02d:%02d "), st.wHour, st.wMinute, st.wSecond);
		}
		else
		{
			cleanText.Format(_T("%d:%02d:%02d "), 
				(st.wHour > 12) ? st.wHour - 12 : st.wHour, 
				st.wMinute, st.wSecond);
		}
	}

	for(int i=0; i < len; i++)
	{
		// Split out multiple rows as required
		if(text[i] == _T('\n') && cleanText.GetLength() > 0)
		{
			if(!didFirstRow)
			{
				AddOneRow(cleanText, level, ensureVisible, write2file);
				didFirstRow= TRUE;
			}
			else
			{
				// Dont show bitmap for continuation lines
				AddOneRow(cleanText, SV_BLANK, ensureVisible, write2file);
			}

			cleanText.Empty();
		}

		// Get rid of misc control chars
		else if(text[i] != _T('\r') && text[i] != _T('\t') && text[i] != _T('\n'))	
			cleanText+= text[i];
	}

	if(cleanText.GetLength() > 0)
	{
		if(!didFirstRow)
		{
			AddOneRow(cleanText, level, ensureVisible, write2file);
			didFirstRow=TRUE;
		}
		else
		{
			// Dont show bitmap for continuation lines
			AddOneRow(cleanText, SV_BLANK, ensureVisible, write2file);
		}
	}

	if(didFirstRow)
	{
		// Play a sound.  The nodefault flag is used so PlaySound is silent when the
		// sound is not defined.  
		if(level== SV_WARNING)
			PlaySound(_T("PerforceWarning"), NULL, SND_ALIAS | SND_ASYNC | SND_NOWAIT | SND_NODEFAULT);
			
		else if(level== SV_COMPLETION)
			PlaySound(_T("PerforceCompleted"), NULL, SND_ALIAS | SND_ASYNC | SND_NOWAIT | SND_NODEFAULT);
	
		else if(level== SV_ERROR)
		{
			// Check to see if the main menu or Status pane context menu is open
			BOOL bMenuOpen = FALSE;
			MENUBARINFO mbi;
			mbi.cbSize = sizeof(MENUBARINFO);
			if (MainFrame()->m_InPopUpMenu
			 || (MainFrame()->GetMenuBarInfo(OBJID_MENU, 0, &mbi) && mbi.fBarFocused))
				bMenuOpen = TRUE;
			// If the mouse is captured - release it and pump the message loop.
			// This can happen if the user is dragging the toolbar to a new
			// location when we get here. We only do this however if all menus
			// are closed - if one is open and we mess with the Capture, it
			// makes another mess.  Things are still a mess cuz MS still doesn't
			// clean up from the drag and leaves the main window on top with the
			// upcoming messagebox hidden.  Yuck - and I still can't figure a way
			// out of that mess.
			while (!bMenuOpen && ::GetCapture())
			{
				MSG msg;

				::ReleaseCapture();
				if (!MainFrame()->IsQuitting())
				{
					while ( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) 
					{ 
						if (!::GetMessage(&msg, NULL, NULL, NULL))
						{ 
							::PostQuitMessage(0); 
							break; 
						} 
						if (!(TheApp( )->PreTranslateMessage(&msg)))
						{
							::TranslateMessage(&msg);
							::DispatchMessage(&msg);
						}
					} 
				}
    		}
			// Note: there is no real app modal message box, so set a flag to
			// kill the autopoll timer, thus preventing a billion error boxes
			// if the machine is unattended
			if (!showDialog)
			{
				SET_APP_HALTED(TRUE);
				PlaySound(_T("PerforceError"), NULL, SND_ALIAS | SND_SYNC | SND_NOWAIT | SND_NODEFAULT);
				AfxMessageBox(text, MB_ICONSTOP | MB_SYSTEMMODAL); 
				SET_APP_HALTED(FALSE);
			}
		}
	}

	if(didFirstRow && showDialog)
	{
		CString str = CString(_T("OK\t")) + text;
		str.Replace('\t', ' ');
		str.SetAt(2, '\t');
		int i, j;
		for (i = j = 0; (i = str.Find('\n', i)) != -1; i++)
			j++;
		BOOL b = (j > 5 || str.GetLength() > 200) ? TRUE : FALSE;
		switch(level)
		{
		case SV_WARNING:
			MsgBox( str, MB_ICONEXCLAMATION, IDC_BUTTON2, this, NULL, b );
			break;
		default:
			MsgBox( str, MB_ICONSTOP, IDC_BUTTON2, this, NULL, b );
			break;
		}
		MainFrame()->SetStatusBarLevel(level);
	}
}

void CStatusView::AddOneRow(LPCTSTR text, StatusView level, BOOL ensureVisible, BOOL write2file, BOOL bSave/*=TRUE*/) 
{
	DWORD NumberOfBytesWritten;

	ASSERT(	text != NULL);
	ASSERT( level >= SV_MSG && level < SV_MAX);

	// Add the image and text
	LV_ITEM lvItem;
			
	lvItem.mask=LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
	lvItem.iItem= m_HeadIndex;
	lvItem.iSubItem= 0;
	lvItem.iImage = CP4ViewImageList::VI_STATUS_MSG + level;
	lvItem.pszText= const_cast<LPTSTR>(text); 
	lvItem.lParam= level;

	if (write2file || m_ShowStatusMsgs 
	 || level== SV_COMPLETION || level== SV_WARNING || level== SV_ERROR || level== SV_WARNSUMMARY)
	{
		// If the output window has too many rows, delete oldest row
		if(ListView_GetItemCount(m_hWnd) >= m_MaxStatusLines)
			ListView_DeleteItem(m_hWnd, 0);
		// Add the item to the status listview
		m_HeadIndex=ListView_InsertItem(m_hWnd, &lvItem);
		if( ensureVisible )
			ListView_EnsureVisible(m_hWnd, m_HeadIndex, FALSE);
		m_HeadIndex++;
		m_RowAdded = TRUE;
	}

	CString msg;
	msg.Format(_T("%d %s\r\n"), level, text);
	if (bSave)
	{
		if (m_StatusRows.GetCount() > m_MaxSaveLines)
			m_StatusRows.RemoveHead();
		m_StatusRows.AddTail(msg);
	}

	if (write2file)
	{
		m_ErrFound = TRUE;
		WriteFile(m_hErrFile, msg, msg.GetLength()*sizeof(TCHAR), &NumberOfBytesWritten, NULL);
		MainFrame()->SetStatusBarLevel(level);
	}
	if (GET_P4REGPTR()->GetStatusUpdateInterval() && m_ShowStatusMsgs)
		SendMessage(WM_SETREDRAW, FALSE, 0);
}

BOOL CStatusView::PreCreateWindow(CREATESTRUCT& cs) 
{
	cs.style|= LVS_NOCOLUMNHEADER | LVS_SHAREIMAGELISTS | LVS_ALIGNLEFT | LVS_REPORT;
	return CListView::PreCreateWindow(cs);
}

void CStatusView::OnSize(UINT nType, int cx, int cy) 
{
	CListView::OnSize(nType, cx, cy);
}


BOOL CStatusView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	if(SERVER_BUSY())
		return SET_BUSYCURSOR();
	else
		return CListView::OnSetCursor(pWnd, nHitTest, message);
}

void CStatusView::OnWindowClear() 
{
	Clear();
}

void CStatusView::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	CMenu popMenu;
	MainFrame()->m_InPopUpMenu = TRUE;

	if (point.x <= 0 && point.y <= 0)	// Position NOT actually in status window?
	{
		point.x = point.y = 0;
		ClientToScreen(&point);			// re-position to upper left corner of status window
	}

    popMenu.LoadMenu(IDR_STATUS);
    popMenu.GetSubMenu(0)->CheckMenuItem(ID_SHOW_COMMAND_TRACE, MF_BYCOMMAND | 
        (GET_P4REGPTR()->ShowCommandTrace( ) ? MF_CHECKED : MF_UNCHECKED));
    popMenu.GetSubMenu(0)->CheckMenuItem(ID_SHOW_TIMESTAMP, MF_BYCOMMAND | 
        (GET_P4REGPTR()->ShowStatusTime( ) ? MF_CHECKED : MF_UNCHECKED));
    popMenu.GetSubMenu(0)->CheckMenuItem(ID_SHOW_STATUSMSGS, MF_BYCOMMAND | 
        (GET_P4REGPTR()->GetShowStatusMsgs( ) ? MF_CHECKED : MF_UNCHECKED));

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


/*
	_________________________________________________________________

	toggle the show command trace flag in the registry.
	_________________________________________________________________
*/

void CStatusView::OnShowCommandTrace() 
{
	GET_P4REGPTR()->SetShowCommandTrace( ! GET_P4REGPTR()->ShowCommandTrace() );
}

void CStatusView::OnUpdateViewWarnAndErrs(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( m_ErrFound );	
}

void CStatusView::CallOnUpdateViewWarnAndErrs(CCmdUI* pCmdUI)
{
	OnUpdateViewWarnAndErrs(pCmdUI);
}

void CStatusView::OnMaxStatusLines() 
{
	m_MaxStatusLines = GET_P4REGPTR()->GetMaxStatusLines();
	m_MaxSaveLines = min(2000, max(m_MaxStatusLines >> 4, 250));
	if (m_MaxSaveLines > m_MaxStatusLines)
		m_MaxSaveLines = m_MaxStatusLines;
}

void CStatusView::OnViewWarnAndErrs() 
{
	if (GET_P4REGPTR()->UseNotepad4WarnAndErr())
	{
#ifdef UNICODE
		DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT; 
#else
		DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS;
#endif
		PROCESS_INFORMATION procInfo;
		STARTUPINFO startInfo;
		GetStartupInfo(&startInfo);
		startInfo.lpReserved= startInfo.lpDesktop= NULL; 
		startInfo.dwFlags |= STARTF_USESHOWWINDOW;
		startInfo.wShowWindow = SW_SHOWNORMAL;
		TCHAR commandLine[_MAX_PATH+1];
		CString cmdline = _T("notepad.exe ") + m_ErrFile;
		lstrcpy(commandLine, cmdline);
		CreateProcess( NULL,	// pointer to name of executable module 
						commandLine,	// pointer to command line string
						NULL, NULL,  // default security rot
						FALSE,	// handle inheritance flag 
						dwCreationFlags,	// creation flags 
						NULL, // env
						NULL, //default dir
						&startInfo, &procInfo);					
	}
	else
		ShellExecute( AfxGetApp( )->m_pMainWnd->m_hWnd, _T("open"), m_ErrFile, NULL, NULL, SW_SHOWNORMAL);
	MainFrame()->SetStatusBarLevel(SV_MSG);
}

void CStatusView::CallOnViewWarnAndErrs() 
{
	OnViewWarnAndErrs();
}

void CStatusView::OnUpdateWindowCopyselected(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( GetSelectedCount() > 0 );	
}

void CStatusView::OnWindowCopyselected() 
{
	CString text;  

	GetPaneText( text, TRUE );
	CopyTextToClipboard( text );
}

void CStatusView::GetPaneText( CString &txt, BOOL onlySelectedText) 
{
	TCHAR buf[1024];
	txt.Empty();
	
	for( int i = 0;  i < ListView_GetItemCount( m_hWnd ); i++ )
	{
		if( !onlySelectedText || 
			ListView_GetItemState( m_hWnd, i, LVIS_SELECTED ) == LVIS_SELECTED )
		{
			ListView_GetItemText( m_hWnd, i, 0, buf, 1023 );

			switch( GetListCtrl().GetItemData( i ) )
			{
			case SV_TOOL:
				txt+= LoadStringResource(IDS_STATUS_TOOL); break;
			case SV_DEBUG:
				txt+= LoadStringResource(IDS_STATUS_DEBUG); break;
			case SV_WARNING:
				txt+= LoadStringResource(IDS_STATUS_WARNING); break;
			case SV_ERROR:
				txt+= LoadStringResource(IDS_STATUS_ERROR); break;
			case SV_MSG:
				txt+= LoadStringResource(IDS_STATUS_STATUS); break;
			case SV_COMPLETION:
			case SV_WARNSUMMARY:
				txt+= LoadStringResource(IDS_STATUS_COMPLETION); break;
			case SV_BLANK:
				// Indent rows following lead row
				txt+= _T("    "); break;
			default:
				break;
			}
			
			txt+= buf;
			txt+= _T("\r\n");
		}
	}
}


int CStatusView::GetSelectedCount()
{
	int selected= 0;
	for( int i = 0;  i < ListView_GetItemCount( m_hWnd ); i++ )
		if( ListView_GetItemState( m_hWnd, i, LVIS_SELECTED ) == LVIS_SELECTED )
			selected++;
	
	return selected;
}

void CStatusView::OnUpdateEditSelectAll(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(TRUE);	
}

void CStatusView::OnEditSelectAll() 
{
	for( int i = 0;  i < ListView_GetItemCount( m_hWnd ); i++ )
		ListView_SetItemState( m_hWnd, i, LVIS_SELECTED, LVIS_SELECTED );
	
}

void CStatusView::OnShowTimestamp() 
{
	BOOL showStatusTime = !GET_P4REGPTR()->ShowStatusTime( );
	GET_P4REGPTR()->SetShowStatusTime( showStatusTime );
}

void CStatusView::OnShowStatusMsgs() 
{
	m_ShowStatusMsgs = !GET_P4REGPTR()->GetShowStatusMsgs( );
	GET_P4REGPTR()->SetShowStatusMsgs( m_ShowStatusMsgs );

	int i;
	LPTSTR p, q;
	OnWindowClear();
	if (m_ShowStatusMsgs)
	{
		CString row;
		for (POSITION pos = m_StatusRows.GetHeadPosition(); pos != NULL; )
		{
			row = m_StatusRows.GetNext(pos);
			p = row.GetBuffer(row.GetLength()+1);
			i = _tstoi(p);
			while (*++p != _T(' '))
				;
			q = p++;
			while(*++q != _T('\r'))
				;
			*q = _T('\0');
			AddOneRow(p, (StatusView)i, TRUE, FALSE, FALSE);
		}
	}
	else
	{
		DWORD dw = GetFileSize(m_hErrFile, 0);
		CString buf(_T('\0'), dw+1);
		if (dw)
		{
			SetFilePointer(m_hErrFile, 0, 0, FILE_BEGIN);
			if (ReadFile(m_hErrFile, p = buf.GetBuffer(dw+1), dw, &dw, 0))
			{
				while(*p)
				{
					i = _tstoi(p);
					while (*++p != _T(' '))
						;
					q = p++;
					while(*++q != _T('\r'))
						;
					*q = _T('\0');
					AddOneRow(p, (StatusView)i, TRUE, FALSE, FALSE);
					for (p = q; *++p && *p < _T(' '); )
						;
				}
			}
			SetFilePointer(m_hErrFile, 0, 0, FILE_END);
		}
	}
}

CString CStatusView::Extract1stFilename(CString &str) 
{
	int i;
	CString itemStr = str;
	if (itemStr.GetAt(0) != _T('/') && itemStr.GetAt(1) != _T(':'))
	{
		if ((i = itemStr.Find(_T("//"))) > 0)
		{
			// we have something like "STATUS: 3:33:26 Sync preview: //depot/main/www/perforce/customers/bycountry.html#16 - updating c:\workspac\main\www\perforce\customers\bycountry.html"
			// so throw away everything before the "//"
			itemStr = itemStr.Right(itemStr.GetLength() - i);
		}
		else if ((i = itemStr.Find(_T(":\\"))) > 0)
		{
			// we have something like "STATUS: 11:48:04 Executing p4 where c:\workspac\P4CONFIG"
			// so throw away everything before the "c:\"
			itemStr = itemStr.Right(itemStr.GetLength() - i + 1);
		}
		itemStr.TrimRight();
	}
	// if we find a 2nd "//", throw it and the following chars away
	if ((i = itemStr.Find(_T("//"), 2)) > 0)
		itemStr = itemStr.Left(i);
	// if we find a 2nd "c:\", throw it and the following chars away
	if ((i = itemStr.Find(_T(":\\"), 3)) > 0)
		itemStr = itemStr.Left(i-1);
	return itemStr;
}

void CStatusView::OnUpdateFindInDepot(CCmdUI* pCmdUI) 
{
	BOOL b = FALSE;
	CString text;

	GetPaneText( text, TRUE );

	if ((GetSelectedCount() == 1)
	 && ((text.Find(_T("//")) != -1) || (text.Find(_T(":\\")) != -1)))
	{
		b = TRUE;
	}
	pCmdUI->Enable(b);	
	if (pCmdUI->m_pParentMenu == MainFrame()->GetMenu())
		pCmdUI->SetText(LoadStringResource(IDS_FINDSELFILEINDEPOT));
}

void CStatusView::OnFindInDepot() 
{
	CString itemStr;

	GetPaneText( itemStr, TRUE );
	itemStr = Extract1stFilename(itemStr);
	itemStr.TrimRight(_T("*/\\"));
	((CMainFrame *)AfxGetMainWnd())->ExpandDepotString( itemStr, TRUE );
}

void CStatusView::OnUpdateFindInChgs(CCmdUI* pCmdUI) 
{
	CString text;
	GetPaneText( text, TRUE );
	BOOL b = ((GetSelectedCount() == 1)
		   && ((text.Find(_T("//")) != -1) || (text.Find(_T(":\\")) != -1)));
	if (b)
	{
		text = Extract1stFilename(text);
		b = ((text.Find(_T("...")) == -1) && (text.Find(_T("*")) == -1));
	}
	pCmdUI->Enable(b);	
}

void CStatusView::OnFindInChgs() 
{
	int i;
	CString itemStr;

	GetPaneText( itemStr, TRUE );
	itemStr = Extract1stFilename(itemStr);
	if ((itemStr.Find(_T("...")) == -1) && (itemStr.Find(_T("*")) == -1))
	{
		if ((i = itemStr.FindOneOf(_T("#@"))) != -1)
			itemStr = itemStr.Left(i);
		itemStr.TrimRight(_T("*/\\ "));
		if (itemStr.GetAt(0) != _T('/'))
		{
			// have to convert to depot syntax
			CCmd_Where *pCmd1 = new CCmd_Where;
			pCmd1->Init(NULL, RUN_SYNC);
			if ( pCmd1->Run(itemStr) && !pCmd1->GetError() 
				&& pCmd1->GetDepotFiles()->GetCount() )
			{
				itemStr = pCmd1->GetDepotSyntax();
				itemStr.TrimRight();
			}
			delete pCmd1;
		}
		if (((CMainFrame *)AfxGetMainWnd())->PositionChgs( itemStr, TRUE, TRUE ) != -1)
			return;	// found it
	}
	MainFrame()->SetMessageText(LoadStringResource(SERVER_BUSY() ? IDS_FILE_NOT_FOUND_YOUR_CHGS 
																 : IDS_FILE_NOT_FOUND_IN_CHGS));
}

void CStatusView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView) 
{
	int i;

	if (bActivate)
	{
		SendMessage(WM_SETREDRAW, TRUE, 0);
		((CMainFrame *)AfxGetMainWnd())->SetStatusBarLevel(SV_MSG);
		if (m_RowAdded || (ListView_GetSelectedCount( m_hWnd ) == 0))
		{
			m_RowAdded = FALSE;
			i = ListView_GetItemCount( m_hWnd );
			if (i--)
			{
				ListView_SetItemState( m_hWnd, i, LVIS_SELECTED, LVIS_SELECTED );
				ListView_EnsureVisible( m_hWnd, i, FALSE );
			}
		}
		else
		{
			for( i =  ListView_GetItemCount( m_hWnd ); i--; )
				if( ListView_GetItemState( m_hWnd, i, LVIS_SELECTED ) == LVIS_SELECTED )
					break;
			ListView_EnsureVisible( m_hWnd, i, FALSE );
		}
	}
	
	CListView::OnActivateView(bActivate, pActivateView, pDeactiveView);
}

void CStatusView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	switch ( nChar )
	{
	case VK_TAB:
		if ( ::GetKeyState(VK_CONTROL) & 0x8000 )	// Ctrl+TAB switches to depot pane
			MainFrame()->SwitchPanes((CView *)this, FALSE);
		break;
	}
	
	CListView::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CStatusView::OnSysColorChange()
{
	CListView::OnSysColorChange();

	CListCtrl& list= (CListCtrl&) GetListCtrl();
	list.SetImageList(TheApp()->GetImageList(), LVSIL_SMALL);
}

void CStatusView::OnPerforceOptions()
{
	MainFrame()->OnPerforceOptions(TRUE, FALSE, IDS_PAGE_STATUS);
}

LRESULT CStatusView::OnFindPattern(WPARAM wParam, LPARAM lParam)
{
	TCHAR str[ 1024 ];
	CString text;
	CString what = (TCHAR *)lParam;
	int flags = (int)wParam;
	int prev = -1;

	if (!(flags & FR_MATCHCASE))
		what.MakeLower();

	int i, j;
	CListCtrl& list= (CListCtrl&) GetListCtrl();
	int columns = list.GetHeaderCtrl()->GetItemCount();

	if (flags & FR_DOWN)
	{
		for( i = 0;  i < ListView_GetItemCount(m_hWnd); i++ )
		{
			if( ListView_GetItemState( m_hWnd, i, LVIS_SELECTED ) == LVIS_SELECTED )
			{
				ListView_SetItemState( m_hWnd, prev = i, 0, LVIS_SELECTED|LVIS_FOCUSED );
				while (ListView_GetSelectedCount(m_hWnd))	// clear remaining selections
				{
					if( ListView_GetItemState( m_hWnd, ++i, LVIS_SELECTED ) == LVIS_SELECTED )
						ListView_SetItemState( m_hWnd, i, 0, LVIS_SELECTED|LVIS_FOCUSED );
				}
				i = prev;
				break;
			}
		}
		if (flags < 0)
			i++;
		while( i < ListView_GetItemCount(m_hWnd) )
		{
			for (j =-1; ++j < columns; )
			{
				ListView_GetItemText( m_hWnd, i, j, str, sizeof(str)/sizeof(TCHAR) );
				text = _T("");
				switch( GetListCtrl().GetItemData( i ) )
				{
				case SV_ERROR:
					text = LoadStringResource(IDS_STATUS_ERROR);
				case SV_WARNING:
				case SV_WARNSUMMARY:
					text+= LoadStringResource(IDS_STATUS_WARNING) + str;
					break;
				case SV_COMPLETION:
					text = LoadStringResource(IDS_STATUS_COMPLETION) + str;
					break;
				case SV_TOOL:
					text = LoadStringResource(IDS_STATUS_TOOL) + str;
					break;
				default:
					text = str;
					break;
				}
				if (!(flags & FR_MATCHCASE))
					text.MakeLower();
				if (text.Find(what) != -1)
				{
					ListView_SetItemState( m_hWnd, i, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED );
					list.EnsureVisible(i, FALSE);
					MainFrame()->SetMessageText(LoadStringResource(IDS_FOUND));
					return 0;
				}
			}
			i++;
		}
	}
	else
	{
		for( i = ListView_GetItemCount(m_hWnd); --i >= 0; )
		{
			if( ListView_GetItemState( m_hWnd, i, LVIS_SELECTED ) == LVIS_SELECTED )
			{
				ListView_SetItemState( m_hWnd, prev = i, 0, LVIS_SELECTED|LVIS_FOCUSED );
				while (ListView_GetSelectedCount(m_hWnd))	// clear remaining selections
				{
					if( ListView_GetItemState( m_hWnd, --i, LVIS_SELECTED ) == LVIS_SELECTED )
						ListView_SetItemState( m_hWnd, i, 0, LVIS_SELECTED|LVIS_FOCUSED );
				}
				i = prev;
				break;
			}
		}
		if (flags < 0)
			i--;
		while( i >= 0 )
		{
			for (j =-1; ++j < columns; )
			{
				ListView_GetItemText( m_hWnd, i, j, str, sizeof(str)/sizeof(TCHAR) );
				text = _T("");
				switch( GetListCtrl().GetItemData( i ) )
				{
				case SV_ERROR:
					text = LoadStringResource(IDS_STATUS_ERROR);
				case SV_WARNING:
				case SV_WARNSUMMARY:
					text+= LoadStringResource(IDS_STATUS_WARNING) + str;
					break;
				case SV_COMPLETION:
					text = LoadStringResource(IDS_STATUS_COMPLETION) + str;
					break;
				case SV_TOOL:
					text = LoadStringResource(IDS_STATUS_TOOL) + str;
					break;
				default:
					text = str;
					break;
				}
				if (!(flags & FR_MATCHCASE))
					text.MakeLower();
				if (text.Find(what) != -1)
				{
					ListView_SetItemState( m_hWnd, i, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED );
					list.EnsureVisible(i, FALSE);
					MainFrame()->SetMessageText(LoadStringResource(IDS_FOUND));
					return 0;
				}
			}
			i--;
		}
	}

	MessageBeep(0);
	MainFrame()->SetMessageText(LoadStringResource(IDS_NOT_FOUND));
	if (prev != -1)
		ListView_SetItemState( m_hWnd, prev, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED );
	return 0;
}

static	int	indexNbr = -1;

int CStatusView::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
	// CWnd implementation won't do us any good, so we have to handle this.
	// watch out!  sometimes get called with null pointer
	if (pTI == 0 || !GET_P4REGPTR()->GetShowTruncTooltip( ))
		return -1;

	// don't want to show tooltip if nothing is hidden
	// the tooltip is only there to show truncated text
	int index;
	LVHITTESTINFO info;
	info.pt = point;
	ListView_HitTest(m_hWnd, &info);
	if ((index = info.iItem) == -1)
		return -1;	// retun because not on a line with text
	TCHAR buf[1024];
	ListView_GetItemText( m_hWnd, index, 0, buf, 1023 );
	int lgth = lstrlen(buf);
	if (lgth < 50)
		return -1;	// return - line has less than 50 characters
	CRect rect;
	GetWindowRect(&rect);
	HDC hDC = ::GetDC(m_hWnd);
	SIZE size;
	GetTextExtentPoint32(hDC, buf, lgth, &size);
	::ReleaseDC(m_hWnd, hDC);
	if ((size.cx < rect.Width()) && (size.cx < 1700))
		return -1;	// return - line is fully visible

	if (indexNbr != index)
	{
		// If this is the 1st time for this line, just return
		// in order to remove any current tooltip; we will be
		// called again and will put up the tooltip then.
		indexNbr = index;
		return -1;
	}

	// we want to show a tooltip, so set up for the normal callback
	pTI->hwnd = m_hWnd;					// us
	pTI->uId = (UINT_PTR)m_hWnd;		// us
	pTI->uFlags |= TTF_IDISHWND;		// uId is HWND, not ID
	pTI->lpszText = LPSTR_TEXTCALLBACK;
	indexNbr = index;					// save in a static since this function Must be const!
	return (int)pTI->uId;
}

BOOL CStatusView::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
	// first, check for my tooltip text request
	// and handle it here
    TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;    
    UINT nID =pNMHDR->idFrom;
    if (pTTT->uFlags & TTF_IDISHWND)    
    {
		if(nID == (UINT)m_hWnd)
		{
			TCHAR buf[1024];
			CRect rect;
			GetClientRect(&rect);
			::SendMessage(pTTT->hdr.hwndFrom, TTM_SETMAXTIPWIDTH, 0, max(480, 2*rect.Width()/3));
			ListView_GetItemText( m_hWnd, indexNbr, 0, buf, 1023 );
			m_ToolTipText = buf;
			pTTT->lpszText = (LPTSTR)(LPCTSTR)m_ToolTipText;
            pTTT->hinst = NULL;
			return TRUE;
		}
	}
	// for other cases, just pass it along to mainframe
    return MainFrame()->OnToolTipText(id, pNMHDR, pResult);
}
# Change User Description Committed
#1 19924 YourUncleBob Populate -o //guest/perforce_software/p4win/...
//guest/YourUncleBob/p4win/.....
//guest/perforce_software/p4win/main/gui/StatusView.cpp
#1 16169 perforce_software Move files to follow new path scheme for branches.
//guest/perforce_software/p4win/gui/StatusView.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.