// 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( 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; } }