// CDiff2Output.cpp : implementation file
//
#include "stdafx.h"
#include "p4win.h"
#include "MainFrm.h"
#include "Diff2Output.h"
#include "StringUtil.h"
#include "RegKeyEx.h"
#include "FileInfoDlg.h"
#include "ViewerDlg.h"
#include "SpecDescDlg.h"
#include "cmd_diff2.h"
#include "cmd_fstat.h"
#include "cmd_history.h"
#include "cmd_opened.h"
#include "cmd_prepbrowse.h"
#include "cmd_where.h"
//#include "hlp\p4win.hh"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static LPCTSTR sRegKey = _T("Software\\Perforce\\P4Win\\Layout\\Diff2Output");
static LPCTSTR sRegValue_ColumnWidths = _T("Column Widths");
static LPCTSTR sRegValue_SortColumns = _T("Sort Columns");
#define UPDATE_STATUS(x) ((CMainFrame *)AfxGetMainWnd())->UpdateStatus(x)
#define HOLD_LOCK_IF_HAVE_KEY (m_Key ? HOLD_LOCK : LOSE_LOCK)
/////////////////////////////////////////////////////////////////////////////
// CDiff2Output dialog
CDiff2Output::CDiff2Output(CWnd* pParent)
: CDialog(CDiff2Output::IDD, pParent)
{
//{{AFX_DATA_INIT(CDiff2Output)
//}}AFX_DATA_INIT
m_pParent = pParent;
if (m_pParent)
MainFrame()->SetModelessWnd(this);
m_InitRect.SetRect(0,0,100,100);
m_WinPos.SetWindow( this, _T("Diff2Output") );
}
CDiff2Output::~CDiff2Output()
{
// can't use MainFrame()-> construct
// because mainfram might have closed.
CMainFrame * mainWnd = MainFrame();
if (mainWnd)
mainWnd->SetGotUserInput( );
}
void CDiff2Output::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDiff2Output)
DDX_Control(pDX, IDC_LIST, m_ListCtrl);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDiff2Output, CDialog)
//{{AFX_MSG_MAP(CDiff2Output)
ON_WM_CONTEXTMENU()
ON_WM_SIZE()
ON_WM_GETMINMAXINFO()
ON_NOTIFY(NM_DBLCLK, IDC_LIST, OnDblclickP4list)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST, OnItemchangedP4List)
ON_BN_CLICKED(ID_DIFF2, OnDiff2)
ON_WM_CLOSE()
ON_WM_DESTROY()
ON_WM_SYSCOMMAND()
// ON_BN_CLICKED(IDHELP, OnHelp)
// ON_WM_HELPINFO()
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_COMMAND(ID_POSITIONDEPOT, OnPositionDepot)
ON_COMMAND(IDB_BROWSE, OnFileAutobrowse)
ON_COMMAND((UINT)(ID_FILE_PROPERTIES-30000), OnFileInformation) // should be ID_FILE_PROPERTIES - but bug in M$ complier(!)
ON_COMMAND((UINT)(ID_FILE_REVISIONTREE-30000), OnFileRevisionTree)
ON_COMMAND(ID_FILE_ANNOTATE, OnFileAnnotate)
ON_COMMAND(ID_FILE_REVISIONHISTORY, OnFileRevisionhistory)
ON_COMMAND(ID_SINGLEPANEVIEW, OnSinglePaneView)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_P4DIFF2, OnP4Diff2 )
ON_MESSAGE(WM_P4PREPBROWSE, OnP4ViewFile )
ON_MESSAGE(WM_P4FILEINFORMATION, OnP4FileInformation )
ON_MESSAGE(WM_P4ENDFILEINFORMATION, OnP4EndFileInformation )
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDiff2Output message handlers
BOOL CDiff2Output::OnInitDialog()
{
int i;
CDialog::OnInitDialog();
// Record the initial window size, then see if there is a registry preference
GetWindowRect(&m_InitRect);
m_LastRect = m_InitRect;
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_ListCtrl.m_hWnd,LVM_GETEXTENDEDLISTVIEWSTYLE,0,0);
dwStyle |= LVS_EX_FULLROWSELECT;
::SendMessage(m_ListCtrl.m_hWnd,LVM_SETEXTENDEDLISTVIEWSTYLE,0,dwStyle);
// Make sure list control shows selection when not the focused control
m_ListCtrl.ModifyStyle(0, LVS_SHOWSELALWAYS, 0);
// Get original size of control
CRect rect;
m_ListCtrl.GetWindowRect(&rect);
int colwidth[2]={120,3000};
// 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_ListCtrl.GetWindowRect(&rect);
// Get any saved column widths from registry
RestoreSavedWidths(colwidth, 2);
// Make sure no column completely disappeared (because you can't get it back then)
for (i=-1; ++i < 2; )
{
if (colwidth[i] < 5)
colwidth[i] = 5;
}
// Use the same font as the calling window
m_ListCtrl.SetFont(m_Font);
// Figure out the headers
int lgthHdr1;
int lgthHdr2;
CString txt;
txt = m_ColNames->GetAt(0);
if ((i = txt.Find(_T("/..."))) > -1)
lgthHdr1 = i + 1;
else
{
lgthHdr1 = 0;
}
txt = m_ColNames->GetAt(1);
if ((i = txt.Find(_T("/..."))) > -1)
lgthHdr2 = i + 1;
else
{
lgthHdr2 = 0;
}
if (!lgthHdr1) // local syntax?
{
txt = m_ColNames->GetAt(0);
int i1 = txt.Find(_T("\\..."));
if (i1 != -1) // local syntax!
{
m_OrigHdr1 = txt.Left(i1);
CCmd_Where *pCmd1 = new CCmd_Where;
pCmd1->Init(NULL, RUN_SYNC);
if ( pCmd1->Run(m_OrigHdr1) && !pCmd1->GetError()
&& pCmd1->GetDepotFiles()->GetCount() )
{
CString txt1 = pCmd1->GetDepotSyntax() + _T('/');
lgthHdr1 = txt1.GetLength();
txt1 += txt.Mid(i1+1);
m_ColNames->SetAt(0, txt1);
}
else
ASSERT(0);
delete pCmd1;
m_OrigHdr1 += _T('\\');
}
}
if (!lgthHdr2) // local syntax?
{
txt = m_ColNames->GetAt(1);
int i2 = txt.Find(_T("\\..."));
if (i2 != -1) // local syntax!
{
m_OrigHdr2 = txt.Left(i2);
CCmd_Where *pCmd1 = new CCmd_Where;
pCmd1->Init(NULL, RUN_SYNC);
if ( pCmd1->Run(m_OrigHdr2) && !pCmd1->GetError()
&& pCmd1->GetDepotFiles()->GetCount() )
{
CString txt2 = pCmd1->GetDepotSyntax() + _T('/');
lgthHdr2 = txt2.GetLength();
txt2 += txt.Mid(i2+1);
m_ColNames->SetAt(1, txt2);
}
else
ASSERT(0);
delete pCmd1;
m_OrigHdr2 += _T('\\');
}
}
// these contain the folders including the last / but chop off the ... and following
m_Hdr1 = m_ColNames->GetAt(0).Left(lgthHdr1);
m_Hdr2 = m_ColNames->GetAt(1).Left(lgthHdr2);
if (m_OrigHdr1.IsEmpty())
m_OrigHdr1 = m_Hdr1;
if (m_OrigHdr2.IsEmpty())
m_OrigHdr2 = m_Hdr1;
// Insert the columns
int maxcols = 2;
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_ListCtrl.InsertColumn(subItem, &lvCol);
}
AddTheListData(lgthHdr1, lgthHdr2);
ShowWindow(SW_SHOW);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CDiff2Output::AddTheListData(int lgthHdr1, int lgthHdr2)
{
// Add the data
int i;
LV_ITEM lvItem;
LPARAM lParam;
int iActualItem = -1;
int maxwcol2 = m_ListCtrl.GetStringWidth(m_ColNames->GetAt(1)) + 20;
int iItem = 0;
CString msg = m_Msg;
while ((i = msg.Find(_T('\n'))) != -1)
{
CString line = msg.Left(i);
line.TrimLeft(_T(" =\t\r\n"));
msg = msg.Mid(i+1);
if (line.GetAt(0) == _T('/'))
{
i = line.Find(_T('#'));
if (i > 0)
i = line.Find(_T(" - "), i);
}
else
i = line.Find(_T(" - "));
ASSERT(i != -1);
CString col1txt = line.Left(i);
CString col2txt = line.Mid(i+3);
col2txt.TrimLeft();
if (col2txt.GetAt(0) == _T('/'))
{
i = col2txt.Find(_T('#'));
if (i > 0)
{
if ((i = col2txt.Find(_T(" content"), i)) != -1)
col2txt = col2txt.Left(i);
}
}
col2txt.TrimRight(_T(" =\t\r\n"));
lParam = 1; // 1 -> can diff 2 files
if (col1txt.GetAt(0) == _T('/'))
{
if (col1txt.Find(m_Hdr1) == 0)
col1txt = col1txt.Mid(lgthHdr1);
}
else
{
col1txt = _T(" ") + col1txt;
lParam = 0; // 0 -> cannot diff 2 files
}
if (col2txt.GetAt(0) == _T('/'))
{
if (col2txt.Find(m_Hdr2) == 0)
col2txt = col2txt.Mid(lgthHdr2);
}
else
{
col2txt = _T(" ") + col2txt;
lParam = 0; // 0 -> cannot diff 2 files
}
maxwcol2 = max(maxwcol2, m_ListCtrl.GetStringWidth(col2txt)+20);
for(int subItem=0; subItem < 2; 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.lParam = lParam;
lvItem.pszText = const_cast<LPTSTR>( subItem==0 ? (LPCTSTR)col1txt : (LPCTSTR)col2txt);
if(subItem==0)
iActualItem=m_ListCtrl.InsertItem(&lvItem);
else
m_ListCtrl.SetItem(&lvItem);
}
iItem++;
}
int w = GetSystemMetrics(SM_CXVSCROLL);
CRect rect;
m_ListCtrl.GetWindowRect(&rect);
m_ListCtrl.SetColumnWidth(1, max(maxwcol2 + w,
rect.Width() - m_ListCtrl.GetColumnWidth(0) - 8 - w));
// finally, set focus to the list control so that the first 'down'
// keystroke can be used to scroll down
m_ListCtrl.SetFocus();
}
void CDiff2Output::OnOK()
{
OnCancel();
}
void CDiff2Output::OnCancel()
{
m_WinPos.SaveWindowPosition();
SaveColumnWidths();
if (m_pParent)
m_pParent->PostMessage(WM_P4ENDDIFF2OUTPUT, 0, (LPARAM)this);
CDialog::OnCancel();
}
// This signals the closing of a modeless dialog
// to MainFrame which will delete the 'this' object
void CDiff2Output::OnDestroy()
{
if (m_pParent)
::PostMessage(MainFrame()->m_hWnd, WM_P4DLGDESTROY, 0, (LPARAM)this);
}
void CDiff2Output::OnSysCommand(UINT nID, LPARAM lParam)
{
switch(nID)
{
case SC_MINIMIZE:
GetDesktopWindow()->ArrangeIconicWindows();
break;
}
CDialog::OnSysCommand(nID, lParam);
}
void CDiff2Output::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
// Slide the buttons to the bottom of dlg
CWnd *pOldV = GetDlgItem(ID_SINGLEPANEVIEW);
CWnd *pDiff = GetDlgItem(ID_DIFF2);
CWnd *pCancel = GetDlgItem(IDCANCEL);
if(!pCancel)
return;
int h, y;
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;
pOldV->GetWindowRect(&rect);
ScreenToClient(rect);
pOldV->SetWindowPos(NULL, rect.left, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
pDiff->GetWindowRect(&rect);
ScreenToClient(rect);
pDiff->SetWindowPos(NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
pCancel->GetWindowRect(&rect);
ScreenToClient(rect);
h = rect.Height();
pCancel->SetWindowPos(NULL, rect.left + dx, y = rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
// Increase the size of the list both horiz and vert
CWnd *pList = GetDlgItem(IDC_LIST);
pList->GetWindowRect(&rect);
pList->SetWindowPos(NULL, 0, 0, rect.right - rect.left + dx,
y - h, SWP_NOMOVE | SWP_NOZORDER);
RedrawWindow();
}
void CDiff2Output::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
lpMMI->ptMinTrackSize.x= m_InitRect.Width();
lpMMI->ptMinTrackSize.y= m_InitRect.Height();
}
// Check the registry to see if we have recorded the
// column widths lastused for the Diff2Output dialog
void CDiff2Output::RestoreSavedWidths(int *width, int numcols)
{
CRegKeyEx key;
CString theKey = CString(sRegKey);
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);
}
}
}
void CDiff2Output::SaveColumnWidths()
{
// Save the column widths
CString str;
for(int i=0; i < 10; i++)
{
// Note that GetColumnWidth returns zero if i > numcols
CString num;
num.Format(_T("%d"), m_ListCtrl.GetColumnWidth(i));
if(i)
str+=_T(",");
str+=num;
}
CRegKeyEx key;
if(ERROR_SUCCESS == key.Create(HKEY_CURRENT_USER, sRegKey))
key.SetValueString(str, sRegValue_ColumnWidths);
}
#ifdef HELPWANTEDFORCDiff2Output
void CDiff2Output::OnHelp()
{
AfxGetApp()->WinHelp(0);
}
BOOL CDiff2Output::OnHelpInfo(HELPINFO* pHelpInfo)
{
OnHelp();
return TRUE;
}
#endif
/* _________________________________________________________________
for commands that will run synchronously.
_________________________________________________________________
*/
BOOL CDiff2Output::PumpMessages( )
{
if (MainFrame()->IsQuitting())
return FALSE;
MSG msg;
while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
// get out if app is terminating
//
if ( msg.message == WM_QUIT )
return FALSE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;
}
/* _________________________________________________________________
Parse //depot/folder/filename#rev (type) from a column into its parts
_________________________________________________________________
*/
CString CDiff2Output::ParseFileInfo(CString *itemStr, int *rev, CString *filetype)
{
CString filename = *itemStr;
int i;
if ((i = filename.ReverseFind(_T('('))) != -1)
{
if (filetype)
{
*filetype = filename.Mid(i);
filetype->TrimLeft(_T('('));
filetype->TrimRight(_T(')'));
}
filename = filename.Left(i-1);
}
if ((i = filename.Find(_T('#'))) != -1)
{
if (rev)
{
*rev = _ttoi(filename.Right(filename.GetLength() - i - 1));
if (!*rev)
*rev = -1;
}
filename = filename.Left( i ); // trim off rev# info
}
return filename;
}
void CDiff2Output::OnItemchangedP4List(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
POSITION pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (!pos)
return;
int index = m_ListCtrl.GetNextSelectedItem(pos);
CWnd *ctl = GetDlgItem(ID_DIFF2);
ctl->UpdateWindow();
BOOL enable = m_ListCtrl.GetItemData(index);
if(enable != ctl->IsWindowEnabled())
ctl->EnableWindow(enable); // 0 -> cannot diff; 1 -> can diff
}
void CDiff2Output::OnDblclickP4list(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
OnDiff2();
}
void CDiff2Output::OnDiff2()
{
POSITION pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (!pos)
return;
int index = m_ListCtrl.GetNextSelectedItem(pos);
if (!m_ListCtrl.GetItemData(index)) // 0 -> cannot diff; 1 -> can diff
{
MessageBeep(0);
return;
}
CString col1txt = m_ListCtrl.GetItemText(index, 0);
CString col2txt = m_ListCtrl.GetItemText(index, 1);
if (col1txt.GetAt(0) != _T('/'))
col1txt = m_Hdr1 + col1txt;
if (col2txt.GetAt(0) != _T('/'))
col2txt = m_Hdr2 + col2txt;
int rev1 = -1;
int rev2 = -1;
CString filetype1 = _T("text");
CString filetype2 = _T("text");
col1txt = ParseFileInfo(&col1txt, &rev1, &filetype1);
col2txt = ParseFileInfo(&col2txt, &rev2, &filetype2);
CCmd_Diff2 *pCmd= new CCmd_Diff2;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key);
if( pCmd->Run( col1txt, col2txt, rev1, rev2, filetype1, filetype2) )
{
UPDATE_STATUS( LoadStringResource(IDS_DIFFING_FILES) );
}
else
delete pCmd;
}
LRESULT CDiff2Output::OnP4Diff2(WPARAM wParam, LPARAM lParam)
{
CCmd_Diff2 *pCmd= (CCmd_Diff2 *) wParam;
CString msg= pCmd->GetInfoText();
if( ! msg.IsEmpty() )
{
AfxMessageBox( msg, MB_ICONINFORMATION);
}
UPDATE_STATUS(_T(""));
delete pCmd;
return 0;
}
void CDiff2Output::OnContextMenu(CWnd* pWnd, CPoint point)
{
if (SERVER_BUSY())
return;
// create an empty context menu
CMenu popMenu;
popMenu.CreatePopupMenu();
CString itemStr;
RECT rect;
POSITION pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (!pos)
{
m_ListCtrl.GetWindowRect(&rect);
if (point.x < rect.left)
{
point.x = rect.left + 8;
point.y = rect.top + 32;
}
goto singlepaneview;
}
int index = m_ListCtrl.GetNextSelectedItem(pos);
// make a new selection new if reqd
if(m_ListCtrl.GetItemState(index,LVIS_SELECTED) != LVIS_SELECTED)
{
for(int i=m_ListCtrl.GetItemCount(); i>=0; i-- )
m_ListCtrl.SetItemState(i, 0, LVIS_SELECTED);
m_ListCtrl.SetItemState(index, LVIS_SELECTED, LVIS_SELECTED);
}
LPARAM b;
if ((b = m_ListCtrl.GetItemData(index)) > 0) // 0 -> cannot diff; 1 -> can diff
{
popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_DIFF2, LoadStringResource(IDS_DIFFTHE2FILES));
popMenu.AppendMenu(MF_SEPARATOR);
}
// convert the screen coords in point to m_ListCtrl coords
POINT clipoint;
rect.left = rect.top = 0;
rect.right = point.x;
rect.bottom = point.y;
m_ListCtrl.ScreenToClient(&rect);
clipoint.x = rect.right;
clipoint.y = rect.bottom;
// find which column was clicked
LVHITTESTINFO lvhti;
lvhti.pt = clipoint;
int i = m_ListCtrl.SubItemHitTest(&lvhti);
m_SubItem = (i == index) ? lvhti.iSubItem : 0;
if (i != index)
{
POINT pt;
m_ListCtrl.GetItemPosition(index, &pt);
m_ListCtrl.GetWindowRect(&rect);
point.x = rect.left + pt.x + 8;
point.y = rect.top + pt.y + 8;
}
itemStr = m_ListCtrl.GetItemText(index, m_SubItem);
if (!b && (itemStr.Find(_T('<')) != -1))
goto singlepaneview;
popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_EDIT_COPY, LoadStringResource(IDS_EDIT_COPY));
popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_POSITIONDEPOT, LoadStringResource(IDS_POSITIONDEPOT) );
popMenu.AppendMenu(MF_ENABLED | MF_STRING, IDB_BROWSE, LoadStringResource(IDS_VIEWUSING3DOTS));
popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_FILE_PROPERTIES-30000, LoadStringResource(IDS_PROPERTIES)); // should be ID_FILE_PROPERTIES - but bug in M$ complier(!)
if (MainFrame()->HaveP4QTree())
popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_FILE_REVISIONTREE-30000,LoadStringResource(IDS_REVISIONTREE));
if (MainFrame()->HaveTLV())
popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_FILE_ANNOTATE, LoadStringResource(IDS_ANNOTATIONS));
popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_FILE_REVISIONHISTORY, LoadStringResource(IDS_REVISIONHISTORY));
popMenu.AppendMenu(MF_SEPARATOR);
singlepaneview:
popMenu.AppendMenu(MF_ENABLED | MF_STRING, ID_SINGLEPANEVIEW, LoadStringResource(IDS_SINGLEPANEVIEW));
// Finally blast the menu onto the screen
if (popMenu.GetMenuItemCount() > 0)
popMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
}
void CDiff2Output::OnEditCopy()
{
POSITION pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (!pos)
return;
int index = m_ListCtrl.GetNextSelectedItem(pos);
CString itemStr = m_ListCtrl.GetItemText(index, m_SubItem);
if (itemStr.GetAt(0) != _T('/'))
itemStr = CString(m_SubItem == 0 ? m_Hdr1 : m_Hdr2) + itemStr;
int rev;
itemStr = ParseFileInfo(&itemStr, &rev);
CString selText;
selText.Format(_T("%s#%d"), itemStr, rev);
CopyTextToClipboard(selText);
}
void CDiff2Output::OnPositionDepot()
{
POSITION pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (!pos)
return;
int index = m_ListCtrl.GetNextSelectedItem(pos);
CString itemStr = m_ListCtrl.GetItemText(index, m_SubItem);
if (itemStr.GetAt(0) != _T('/'))
itemStr = CString(m_SubItem == 0 ? m_Hdr1 : m_Hdr2) + itemStr;
itemStr = ParseFileInfo(&itemStr);
((CMainFrame *) AfxGetMainWnd())->ExpandDepotString( itemStr, TRUE );
}
void CDiff2Output::OnFileAutobrowse()
{
POSITION pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (!pos)
return;
int index = m_ListCtrl.GetNextSelectedItem(pos);
CString name = m_ListCtrl.GetItemText(index, m_SubItem);
if (name.GetAt(0) != _T('/'))
name = CString(m_SubItem == 0 ? m_Hdr1 : m_Hdr2) + name;
int rev = -1;
CString fileType = _T("text");
name = ParseFileInfo(&name, &rev, &fileType);
// Ask the user to pick a viewer
CViewerDlg dlg;
SET_APP_HALTED(TRUE);
if(dlg.DoModal() == IDCANCEL)
{
SET_APP_HALTED(FALSE);
return;
}
SET_APP_HALTED(FALSE);
m_Viewer=dlg.GetViewer();
if(m_Viewer != _T("SHELLEXEC"))
GET_P4REGPTR()->AddMRUViewer(m_Viewer);
m_ViewFileIsText = ((fileType.Find(_T("text")) != -1)
|| (fileType.Find(_T("symlink")) != -1)) ? TRUE : FALSE;
// Fetch the selected revision of the file to a temp filename
CCmd_PrepBrowse *pCmd= new CCmd_PrepBrowse;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key);
if( pCmd->Run( name, fileType, rev ) )
{
UPDATE_STATUS( LoadStringResource(IDS_FETCHING_FILE) );
}
else
delete pCmd;
}
// TODO: This code is pretty much a copy of the code in CDepotView::RunViewer()
// Might want to craft a single file viewing class that can be instantiated from
// anywhere, or perhaps make CMainFrame be responsible for all file viewing.
LRESULT CDiff2Output::OnP4ViewFile(WPARAM wParam, LPARAM lParam)
{
UPDATE_STATUS(_T(""));
CString tempName;
CString msg;
CCmd_PrepBrowse *pCmd= (CCmd_PrepBrowse *) wParam;
if(!pCmd->GetError())
{
CString viewFilePath= pCmd->GetTempName();
// First, get the file extension, if any, and find out if
// its a text file
CString extension;
int slash= viewFilePath.ReverseFind(_T('\\'));
if(slash != -1)
extension=viewFilePath.Mid(slash+1);
else
extension=viewFilePath;
int dot= extension.ReverseFind(_T('.'));
if(dot == -1)
extension.Empty();
else
extension=extension.Mid(dot+1);
// We have the file, viewFilePath, try to display it
while(1)
{
if(m_Viewer == _T("SHELLEXEC"))
{
CString assocViewer;
// First, see if there a P4win file association
if(!extension.IsEmpty())
assocViewer= GET_P4REGPTR()->GetAssociatedApp(extension);
// If we still havent found a viewer, set viewer to default text app
// if user wishes to ignore windows associations
if(assocViewer.IsEmpty() && m_ViewFileIsText && GET_P4REGPTR()->GetIgnoreWinAssoc())
assocViewer= GET_P4REGPTR()->GetEditApp();
// Let windows take a crack at finding a viewer
if(assocViewer.IsEmpty() && !extension.IsEmpty())
{
// Quick check for executeable extension, which will make ShellExec try to run the file
HINSTANCE hinst=0;
if( extension.CompareNoCase(_T("com")) != 0 && extension.CompareNoCase(_T("exe")) != 0 &&
extension.CompareNoCase(_T("bat")) != 0 && extension.CompareNoCase(_T("cmd")) != 0)
{ // give VS .NET 7.1 (non-standard!) a try
hinst= ShellExecute( m_hWnd, _T("Open.VisualStudio.7.1"), viewFilePath, NULL, NULL, SW_SHOWNORMAL);
if( (int) hinst > 32)
{
break; // successfull viewer launch
}
if( (int) hinst == SE_ERR_NOASSOC) // give MSDEV (non-standard!) a try
{
hinst= ShellExecute( m_hWnd, _T("&Open with MSDEV"), viewFilePath, NULL, NULL, SW_SHOWNORMAL);
if( (int) hinst > 32 )
break; // successfull MSDEV viewer launch
}
if( (int) hinst == SE_ERR_NOASSOC) // give standard "open" a try
{
hinst= ShellExecute( m_hWnd, _T("open"), viewFilePath, NULL, NULL, SW_SHOWNORMAL);
if( (int) hinst > 32 )
break; // successfull MSDEV viewer launch
}
}
}
// If windows doesnt have an associated viewer for a text file, we use the
// default text editor
if(assocViewer.IsEmpty() && m_ViewFileIsText)
assocViewer= GET_P4REGPTR()->GetEditApp();
if ( TheApp()->RunViewerApp( assocViewer, viewFilePath ) )
break; // successfull viewer launch
}
else
{
if ( TheApp()->RunViewerApp( m_Viewer, viewFilePath ) )
break; // successfull viewer launch
}
CString msg;
msg.FormatMessage(IDS_UNABLE_TO_LAUNCH_VIEWER_s, viewFilePath);
if(AfxMessageBox(msg, MB_YESNO | MB_ICONEXCLAMATION) == IDNO)
break;
// Try to find an alternate viewer
CViewerDlg dlg;
SET_APP_HALTED(TRUE);
if(dlg.DoModal() == IDCANCEL)
{
SET_APP_HALTED(FALSE);
break;
}
SET_APP_HALTED(FALSE);
m_Viewer=dlg.GetViewer();
if(m_Viewer != _T("SHELLEXEC"))
GET_P4REGPTR()->AddMRUViewer(m_Viewer);
} // while
} // no command error
delete pCmd;
UPDATE_STATUS(_T(""));
return 0;
}
void CDiff2Output::OnFileInformation()
{
POSITION pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (!pos)
return;
int index = m_ListCtrl.GetNextSelectedItem(pos);
CString itemStr = m_ListCtrl.GetItemText(index, m_SubItem);
if (itemStr.GetAt(0) != _T('/'))
itemStr = CString(m_SubItem == 0 ? m_Hdr1 : m_Hdr2) + itemStr;
itemStr = ParseFileInfo(&itemStr);
m_StringList.RemoveAll();
m_StringList.AddHead(m_ItemStr = itemStr);
CCmd_Opened *pCmd= new CCmd_Opened;
pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, m_Key);
pCmd->SetAlternateReplyMsg( WM_P4FILEINFORMATION );
if( pCmd->Run( TRUE, FALSE, -1, &m_StringList ) )
UPDATE_STATUS( LoadStringResource(IDS_REQUESTING_FILE_INFORMATION) );
else
delete pCmd;
}
LRESULT CDiff2Output::OnP4FileInformation( WPARAM wParam, LPARAM lParam )
{
CCmd_Opened *pCmd= (CCmd_Opened *) wParam;
m_StringList.RemoveAll();
if(!pCmd->GetError())
{
CString thisuser=GET_P4REGPTR()->GetMyID();
// Initialize the file info dialog
CFileInfoDlg *dlg = new CFileInfoDlg(this);
dlg->m_DepotPath = m_ItemStr;
int key= pCmd->GetServerKey();
CCmd_Fstat *pCmd2= new CCmd_Fstat;
pCmd2->Init(NULL, RUN_SYNC, HOLD_LOCK, key);
if ( !PumpMessages( ) )
goto CantGetFStat;
pCmd2->SetIncludeAddedFiles( TRUE );
if( pCmd2->Run( FALSE, m_ItemStr, 0 ) && !pCmd2->GetError() )
{
CObList *list = pCmd2->GetFileList ( );
ASSERT_KINDOF( CObList, list );
ASSERT( list->GetCount() <= 1 );
POSITION pos = list->GetHeadPosition( );
if( pos != NULL )
{
CP4FileStats *stats = ( CP4FileStats * )list->GetNext( pos );
ASSERT_KINDOF( CP4FileStats, stats );
dlg->m_ClientPath = stats->GetFullClientPath( );
if(dlg->m_ClientPath.GetLength() == 0)
dlg->m_ClientPath= LoadStringResource(IDS_NOT_IN_CLIENT_VIEW);
dlg->m_HeadRev.Format(_T("%ld"), stats->GetHeadRev());
dlg->m_HaveRev.Format(_T("%ld"), stats->GetHaveRev());
dlg->m_HeadAction= stats->GetActionStr(stats->GetHeadAction());
dlg->m_HeadChange.Format(_T("%ld"), stats->GetHeadChangeNum());
dlg->m_HeadType= stats->GetHeadType();
dlg->m_ModTime= stats->GetFormattedHeadTime();
dlg->m_FileSize= stats->GetFileSize();
// Check for open/lock by this user
if(stats->IsMyLock())
dlg->m_LockedBy= thisuser;
delete stats;
}
else dlg->m_ClientPath= LoadStringResource(IDS_NOT_IN_CLIENT_VIEW);
}
CantGetFStat:
if (!m_Key)
RELEASE_SERVER_LOCK(key);
delete pCmd2;
CObList *list= pCmd->GetList();
ASSERT_KINDOF(CObList, list);
POSITION pos= list->GetHeadPosition();
while(pos != NULL)
{
CP4FileStats *fs= (CP4FileStats *) list->GetNext(pos);
CString str;
CString strUser;
CString strChange;
CString strAction;
if( fs->GetOpenChangeNum() == 0 )
strChange= LoadStringResource(IDS_DEFAULT_CHANGE);
else
strChange.FormatMessage(IDS_CHANGE_n, fs->GetOpenChangeNum());
strUser= fs->GetOtherUsers();
if( fs->IsMyOpen() && strUser.IsEmpty() )
{
strUser= thisuser;
strAction= fs->GetActionStr(fs->GetMyOpenAction());
}
else
strAction= fs->GetActionStr(fs->GetOtherOpenAction());
str.Format(_T("%s - %s (%s)"), strUser, strChange, strAction);
if( fs->IsOtherLock() )
str += " " + LoadStringResource(IDS_STAR_LOCKED);
dlg->m_StrList.AddHead( str );
delete fs;
}
delete pCmd; // no longer needed - delete it now before the dialog goes up
// Display the info
if (!dlg->Create(IDD_FILE_INFORMATION, this)) // display the description dialog box
{
dlg->DestroyWindow(); // some error! clean up
delete dlg;
}
}
else
delete pCmd;
UPDATE_STATUS(_T(""));
return 0;
}
LRESULT CDiff2Output::OnP4EndFileInformation( WPARAM wParam, LPARAM lParam )
{
CFileInfoDlg *dlg = (CFileInfoDlg *)lParam;
dlg->DestroyWindow();
return TRUE;
}
void CDiff2Output::OnFileRevisionTree()
{
POSITION pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (!pos)
return;
int index = m_ListCtrl.GetNextSelectedItem(pos);
CString itemStr = m_ListCtrl.GetItemText(index, m_SubItem);
if (itemStr.GetAt(0) != _T('/'))
itemStr = CString(m_SubItem == 0 ? m_Hdr1 : m_Hdr2) + itemStr;
itemStr = ParseFileInfo(&itemStr);
TheApp()->CallP4RevisionTree(itemStr); // use p4v.exe for tree
}
void CDiff2Output::OnFileAnnotate()
{
POSITION pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (!pos)
return;
int index = m_ListCtrl.GetNextSelectedItem(pos);
CString itemStr = m_ListCtrl.GetItemText(index, m_SubItem);
if (itemStr.GetAt(0) != _T('/'))
itemStr = CString(m_SubItem == 0 ? m_Hdr1 : m_Hdr2) + itemStr;
itemStr = ParseFileInfo(&itemStr);
TheApp()->CallP4A(itemStr, _T(""), 0); // use p4v.exe for annotate
}
void CDiff2Output::OnFileRevisionhistory()
{
int rev = -1;
POSITION pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (!pos)
return;
int index = m_ListCtrl.GetNextSelectedItem(pos);
CString itemStr = m_ListCtrl.GetItemText(index, m_SubItem);
if (itemStr.GetAt(0) != _T('/'))
itemStr = CString(m_SubItem == 0 ? m_Hdr1 : m_Hdr2) + itemStr;
itemStr = ParseFileInfo(&itemStr, &rev);
CCmd_History *pCmd= new CCmd_History;
pCmd->Init( MainFrame()->GetDepotWnd(), RUN_ASYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key);
pCmd->SetCallingWnd(m_hWnd);
pCmd->SetInitialRev(rev, itemStr);
if( pCmd->Run( LPCTSTR(itemStr)) )
{
UPDATE_STATUS( LoadStringResource(IDS_REQUESTING_HISTORY) );
}
else
delete pCmd;
}
void CDiff2Output::OnSinglePaneView()
{
// Do this first to trigger a repaint of the buttons
// and before the new dialog is created (so it gets the focus)
GotoDlgCtrl(GetDlgItem(IDC_LIST));
CSpecDescDlg *dlg = new CSpecDescDlg(m_pParent);
dlg->SetIsModeless(TRUE);
dlg->SetKey(m_Key);
dlg->SetDescription( m_Msg );
dlg->SetItemName( m_OrigHdr1 + _T("... <> ") + m_OrigHdr2 + _T("...") );
dlg->SetCaption( m_caption );
dlg->SetViewType(P4DESCRIBE);
if (!dlg->Create(IDD_SPECDESC, m_pParent)) // display the description dialog box
{
dlg->DestroyWindow(); // some error! clean up
delete dlg;
}
}
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #1 | 19924 | YourUncleBob |
Populate -o //guest/perforce_software/p4win/... //guest/YourUncleBob/p4win/..... |
||
| //guest/perforce_software/p4win/main/gui/Diff2Output.cpp | |||||
| #1 | 16169 | perforce_software | Move files to follow new path scheme for branches. | ||
| //guest/perforce_software/p4win/gui/Diff2Output.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. |
||