/* * Copyright 1997, 1999 Perforce Software. All rights reserved. * * This file is part of Perforce - the FAST SCM System. */ // SpecDescDlg.cpp : implementation file // #include "stdafx.h" // don't really need mfc 7 for this. just need platform sdk installed // but this will prevent breaking the build for right now #if _MFC_VER >= 0x0700 #define USE_THEMES #include <uxtheme.h> #endif #include "p4win.h" #include "WinPos.h" #include "SpecDescDlg.h" #include "MainFrm.h" #include "FileInfoDlg.h" #include "Historydlg.h" #include "ViewerDlg.h" #include "P4Fix.h" #include "cmd_diff2.h" #include "cmd_get.h" #include "cmd_fixes.h" #include "cmd_fstat.h" #include "cmd_history.h" #include "cmd_opened.h" #include "cmd_prepbrowse.h" #include "hlp\p4win.hh" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define HOLD_LOCK_IF_HAVE_KEY (m_Key ? HOLD_LOCK : LOSE_LOCK) #define UPDATE_STATUS(x) ((CMainFrame *)AfxGetMainWnd())->UpdateStatus(x) #define ID_EMAIL ID_EMAIL_PERFORCE #define ID_URL ID_WWW_PERFORCE_COM static bool sbHasWingDings = false; ///////////////////////////////////////////////////////////////////////////// // a subclass of CButton to pass Ctrl+F, F3 and Shift F3 to the parent window BEGIN_MESSAGE_MAP(CKeyDownButton, CButton) //{{AFX_MSG_MAP(CMainFrame) //}}AFX_MSG_MAP ON_WM_KEYDOWN() END_MESSAGE_MAP() CKeyDownButton::CKeyDownButton(CWnd* pParent) : CButton() { } CKeyDownButton::~CKeyDownButton() { } void CKeyDownButton::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (nChar == 'F' && GetKeyState(VK_CONTROL) & 0x8000) // ^F == Find GetParent()->PostMessage(WM_COMMAND, ID_POSITIONTOPATTERN, 0); else if (nChar == VK_F3) GetParent()->PostMessage(WM_COMMAND, GetKeyState(VK_SHIFT) & 0x8000 ? ID_FINDPREV : ID_FINDNEXT, 0); else CButton::OnChar(nChar, nRepCnt, nFlags); } ///////////////////////////////////////////////////////////////////////////// // a subclass of CButton to draw arrows to the left of the text BEGIN_MESSAGE_MAP(CArrowButton, CButton) //{{AFX_MSG_MAP(CMainFrame) //}}AFX_MSG_MAP ON_WM_KEYDOWN() ON_WM_MOUSEMOVE() ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover ) ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave ) ON_WM_GETDLGCODE() ON_MESSAGE(BM_SETSTYLE, OnSetStyle) END_MESSAGE_MAP() CArrowButton::CArrowButton() : CButton() , m_bUp(false) , m_bOverControl(false) , m_bTracking(false) , m_bDefault(false) { m_il.Create(IDB_UPDOWNARROWS, 16, 1, RGB(0xff, 0xff, 0xff)); m_themeLib = LoadLibrary(_T("UxTheme.dll")); } CArrowButton::~CArrowButton() { if(m_themeLib) FreeLibrary(m_themeLib); } void CArrowButton::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (nChar == 'F' && GetKeyState(VK_CONTROL) & 0x8000) // ^F == Find GetParent()->PostMessage(WM_COMMAND, ID_POSITIONTOPATTERN, 0); else if (nChar == VK_F3) GetParent()->PostMessage(WM_COMMAND, GetKeyState(VK_SHIFT) & 0x8000 ? ID_FINDPREV : ID_FINDNEXT, 0); else CButton::OnChar(nChar, nRepCnt, nFlags); } void CArrowButton::OnMouseMove(UINT nFlags, CPoint point) { if (!m_bTracking) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.hwndTrack = m_hWnd; tme.dwFlags = TME_LEAVE|TME_HOVER; tme.dwHoverTime = 1; m_bTracking = _TrackMouseEvent(&tme) != FALSE; } CButton::OnMouseMove(nFlags, point); } LRESULT CArrowButton::OnMouseHover(WPARAM wparam, LPARAM lparam) { m_bOverControl=TRUE; Invalidate(); return 1; } LRESULT CArrowButton::OnMouseLeave(WPARAM wparam, LPARAM lparam) { m_bTracking = FALSE; m_bOverControl = FALSE; Invalidate(FALSE); return 0; } UINT CArrowButton::OnGetDlgCode() { UINT nCode = CButton::OnGetDlgCode(); nCode |= (m_bDefault ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON); return nCode; } // mask for control's type #undef BS_TYPEMASK #define BS_TYPEMASK SS_TYPEMASK LRESULT CArrowButton::OnSetStyle(WPARAM wParam, LPARAM lParam) { m_bDefault = wParam & BS_DEFPUSHBUTTON; // can't change control type after owner-draw is set. // let the system process changes to other style bits // and redrawing, while keeping owner-draw style return DefWindowProc(BM_SETSTYLE, (wParam & ~BS_TYPEMASK) | BS_OWNERDRAW, lParam); } #ifdef USE_THEMES typedef HTHEME(__stdcall *PFNOPENTHEMEDATA)(HWND hwnd, LPCWSTR pszClassList); typedef HRESULT(__stdcall *PFNCLOSETHEMEDATA)(HTHEME hTheme); typedef HRESULT(__stdcall *PFNDRAWTHEMEBACKGROUND)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect); typedef HRESULT(__stdcall *PFNGETTHEMEBACKGROUNDCONTENTRECT)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, RECT *pContentRect); #endif void CArrowButton::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct ) { #ifdef USE_THEMES HTHEME hTheme = 0; if(m_themeLib) { PFNOPENTHEMEDATA pOpenThemeData = (PFNOPENTHEMEDATA) GetProcAddress(m_themeLib, "OpenThemeData"); if(pOpenThemeData) hTheme = (pOpenThemeData)(m_hWnd, L"Button"); } if(hTheme) { // attempt to map owner draw states to theme pushbutton states int iState = PBS_NORMAL; if(m_bOverControl)//lpDrawItemStruct->itemState & ODS_HOTLIGHT) iState = PBS_HOT; else if(m_bDefault)//lpDrawItemStruct->itemState & ODS_DEFAULT) iState = PBS_DEFAULTED; else if(lpDrawItemStruct->itemState & ODS_SELECTED) iState = PBS_PRESSED; HRESULT hr; HDC hDC = lpDrawItemStruct->hDC; RECT rc = lpDrawItemStruct->rcItem; // let theme draw background PFNDRAWTHEMEBACKGROUND pDrawThemeBackground = (PFNDRAWTHEMEBACKGROUND) GetProcAddress(m_themeLib, "DrawThemeBackground"); if(!pDrawThemeBackground) return; hr = (pDrawThemeBackground)(hTheme, hDC, BP_PUSHBUTTON, iState, &rc, 0); if(hr != S_OK) return; // get rect to put content in RECT rcContent; PFNGETTHEMEBACKGROUNDCONTENTRECT pGetThemeBackgroundContentRect = (PFNGETTHEMEBACKGROUNDCONTENTRECT) GetProcAddress(m_themeLib, "GetThemeBackgroundContentRect"); if(!pGetThemeBackgroundContentRect) return; hr = (pGetThemeBackgroundContentRect)(hTheme, hDC, BP_PUSHBUTTON, iState, &rc, &rcContent); if(hr != S_OK) return; // draw arrow as content CDC dc; dc.Attach(hDC); CPoint pos; pos.x = (rcContent.left + rcContent.right)/2 - 8; pos.y = (rcContent.top + rcContent.bottom)/2 - 8; m_il.Draw(&dc, m_bUp ? 0 : 1, pos, ILD_NORMAL); if (lpDrawItemStruct->itemState & ODS_FOCUS) { ::DrawFocusRect(lpDrawItemStruct->hDC, &rcContent); } PFNCLOSETHEMEDATA pCloseThemeData = (PFNCLOSETHEMEDATA)GetProcAddress(m_themeLib, "CloseThemeData"); if(!pCloseThemeData) return; (pCloseThemeData)(hTheme); return; } else #endif { // if the button is defaulted, draw a black frame first // and then shring the rect by 1 pixel all around CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); if (m_bDefault)//lpDrawItemStruct->itemState & ODS_DEFAULT) { CRect r(lpDrawItemStruct->rcItem); CPen *pOldPen = (CPen*)pDC->SelectStockObject(BLACK_PEN); CBrush *pOldBrush= (CBrush*)pDC->SelectStockObject(NULL_BRUSH); pDC->Rectangle(&lpDrawItemStruct->rcItem); pDC->SelectObject( pOldPen ); pDC->SelectObject( pOldBrush ); r.DeflateRect(1,1); lpDrawItemStruct->rcItem = r; } // This code only works with buttons. ASSERT(lpDrawItemStruct->CtlType == ODT_BUTTON); // If drawing selected, add the pushed style to DrawFrameControl. UINT uStyle = DFCS_BUTTONPUSH; if (lpDrawItemStruct->itemState & ODS_SELECTED) uStyle |= DFCS_PUSHED; // Make DrawFrameControl give back the content rect uStyle |= DFCS_ADJUSTRECT; // Draw the button frame. ::DrawFrameControl(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, DFC_BUTTON, uStyle); // Draw the button's bitmap CDC dc; dc.Attach(lpDrawItemStruct->hDC); CPoint pos; pos.x = (lpDrawItemStruct->rcItem.right + lpDrawItemStruct->rcItem.left) / 2 - 8; pos.y = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top) / 2 - 8; m_il.Draw(&dc, m_bUp ? 0 : 1, pos, ILD_NORMAL); // draw a focus rect if we have focus if (lpDrawItemStruct->itemState & ODS_FOCUS) { CRect focusRect = lpDrawItemStruct->rcItem; focusRect.DeflateRect(1, 1); ::DrawFocusRect(lpDrawItemStruct->hDC, focusRect); } } } ///////////////////////////////////////////////////////////////////////////// // CSpecDescDlg dialog CSpecDescDlg::CSpecDescDlg(CWnd* pParent /*=NULL*/) : CDialog(CSpecDescDlg::IDD, pParent) , m_SkipLines(0) , m_ScrollPastComments(false) , m_numHotSpots(0) , m_DescriptionW(0) { //{{AFX_DATA_INIT(CSpecDescDlg) //}}AFX_DATA_INIT MainFrame()->WaitAWhileToPoll( ); m_pParent = pParent; m_Caption=LoadStringResource(IDS_PERFORCE_SPECIFICATION); m_ReportedByTitle = ""; m_Grey= RGB(200,200,200); m_GreyBrush.CreateSolidBrush( m_Grey ); m_WinPos.SetWindow( this, _T("BrowseDlg") ); m_Modeless = FALSE; m_ShowNextPrev = FALSE; m_ShowShowDiffs= FALSE; m_ShowShowFixes= FALSE; m_ShowShowFiles= FALSE; m_ShowEditBtn = FALSE; m_TurnOnReDraw = FALSE; m_DoNotActivate= FALSE; m_HasBeenMinimized= FALSE; m_LButtonDownTime = 0; m_MoreThan256Colors = FALSE; m_viewType = m_DiffFlag = 0; m_pToolTip = NULL; // Are we running as a Rev Hist dialog only? m_RevHistEnable = (TheApp()->m_RevHistPath.IsEmpty()) ? TRUE : FALSE; CString temp = LoadStringResource(IDS_RENAME_TO); #ifndef UNICODE int numChars = MultiByteToWideChar(CP_ACP, 0, temp, -1, 0, 0); m_TO_ = new WCHAR[numChars]; MultiByteToWideChar(CP_ACP, 0, temp, -1, const_cast<LPWCH>(m_TO_), numChars); #else m_TO_ = new WCHAR[temp.GetLength() + 1]; lstrcpy(const_cast<WCHAR*>(m_TO_), temp); #endif m_NextBtn.m_bUp = false; m_PrevBtn.m_bUp = true; m_InitRect.SetRect(0,0,0,0); m_ChkServerBusy = !SERVER_BUSY(); // if busy at init, it'll always be busy m_Key = 0; m_pFRDlg = NULL; m_FindWhatStr = MainFrame()->GetFindWhatStr(); m_FindWhatFlags = (MainFrame()->GetFindWhatFlags() | FR_DOWN) & ~FR_HIDEWHOLEWORD; } CSpecDescDlg::~CSpecDescDlg() { // can't use MainFrame()-> construct // because mainfram might have closed. CMainFrame * mainWnd = MainFrame(); if (mainWnd) { mainWnd->SetGotUserInput( ); mainWnd->WaitAWhileToPoll( ); } #ifndef UNICODE // for UNICODE build, m_DescriptionW just points at m_Description delete const_cast<LPWCH>(m_DescriptionW); #endif delete const_cast<LPWCH>(m_TO_); if (m_pToolTip) delete m_pToolTip; } void CSpecDescDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CSpecDescDlg) DDX_Control(pDX, IDC_DESCRIPTION, m_Text); DDX_Control(pDX, IDC_PREVITEM, m_PrevBtn); DDX_Control(pDX, IDC_NEXTITEM, m_NextBtn); DDX_Control(pDX, IDC_SHOWDIFFS, m_btShowDiffs); DDX_Control(pDX, IDOK, m_CloseBtn); DDX_Control(pDX, IDC_PRINT, m_PrintBtn); DDX_Control(pDX, IDC_EDITIT, m_EditBtn); DDX_Control(pDX, IDC_SHOWFIXES, m_ShowFixesBtn); DDX_Control(pDX, IDC_SHOWFILES, m_ShowFilesBtn); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CSpecDescDlg, CDialog) ON_NOTIFY(EN_MSGFILTER, IDC_DESCRIPTION, OnMsgfilterDescription) //{{AFX_MSG_MAP(CSpecDescDlg) ON_WM_SIZE() ON_WM_CLOSE() ON_WM_DESTROY() ON_WM_SHOWWINDOW() ON_WM_GETMINMAXINFO() ON_BN_CLICKED(IDC_NEXTITEM, OnNextitem) ON_BN_CLICKED(IDC_PREVITEM, OnPrevitem) ON_BN_CLICKED(IDC_SHOWDIFFS, OnShowDiffsNormal) ON_BN_CLICKED(IDC_SHOWDIFFSMENU, OnShowDiffsBtn) ON_COMMAND(ID_SHOWDIFFS_NORMAL, OnShowDiffsNormal) ON_COMMAND(ID_SHOWDIFFS_SUMMARY, OnShowDiffsSummary) ON_COMMAND(ID_SHOWDIFFS_UNIFIED, OnShowDiffsUnified) ON_COMMAND(ID_SHOWDIFFS_CONTEXT, OnShowDiffsContext) ON_COMMAND(ID_SHOWDIFFS_RCS, OnShowDiffsRCS) ON_COMMAND(ID_SHOWDIFFS_NONE, OnShowDiffsNone) ON_UPDATE_COMMAND_UI(ID_SHOWDIFFS_NORMAL, OnUpdateShowDiffsNormal) ON_UPDATE_COMMAND_UI(ID_SHOWDIFFS_SUMMARY, OnUpdateShowDiffsSummary) ON_UPDATE_COMMAND_UI(ID_SHOWDIFFS_UNIFIED, OnUpdateShowDiffsUnified) ON_UPDATE_COMMAND_UI(ID_SHOWDIFFS_CONTEXT, OnUpdateShowDiffsContext) ON_UPDATE_COMMAND_UI(ID_SHOWDIFFS_RCS, OnUpdateShowDiffsRCS) ON_UPDATE_COMMAND_UI(ID_SHOWDIFFS_NONE, OnUpdateShowDiffsNone) ON_BN_CLICKED(IDC_PRINT, OnPrint) ON_WM_SYSCOMMAND() ON_COMMAND(ID_FILE_GETCUSTOM, OnSync) ON_UPDATE_COMMAND_UI(ID_FILE_GETCUSTOM, OnUpdateSync) ON_COMMAND(ID_POSITIONDEPOT, OnPositionDepot) ON_UPDATE_COMMAND_UI(ID_POSITIONDEPOT, OnUpdatePositionDepot) ON_COMMAND(ID_FILE_DIFFHEAD, OnDiffHead) ON_UPDATE_COMMAND_UI(ID_FILE_DIFFHEAD, OnUpdateDiffHead) ON_COMMAND(IDB_DIFFREVISIONS, OnDiffPrev) ON_UPDATE_COMMAND_UI(IDB_DIFFREVISIONS, OnUpdateDiffPrev) ON_COMMAND(IDB_DIFFCLIFILE, OnDiffCliFile) ON_UPDATE_COMMAND_UI(IDB_DIFFCLIFILE, OnUpdateDiffCliFile) ON_COMMAND(IDB_BROWSE, OnFileAutobrowse) ON_UPDATE_COMMAND_UI(IDB_BROWSE, OnUpdateFileAutobrowse) ON_COMMAND(ID_FILE_ANNOTATE, OnFileAnnotate) ON_UPDATE_COMMAND_UI(ID_FILE_ANNOTATE, OnUpdateFileAnnotate) ON_COMMAND(ID_FILE_PROPERTIES, OnFileInformation) ON_UPDATE_COMMAND_UI(ID_FILE_PROPERTIES, OnUpdateFileInformation) ON_COMMAND(ID_FILE_REVISIONHISTORY, OnFileRevisionhistory) ON_UPDATE_COMMAND_UI(ID_FILE_REVISIONHISTORY, OnUpdateFileRevisionhistory) ON_COMMAND(ID_FILE_REVISIONTREE, OnFileRevisionTree) ON_UPDATE_COMMAND_UI(ID_FILE_REVISIONTREE, OnUpdateFileInformation) ON_COMMAND(ID_EDIT_COPY, OnEditCopy) ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy) ON_COMMAND(ID_PERFORCE_OPTIONS, OnOptions) ON_UPDATE_COMMAND_UI(ID_PERFORCE_OPTIONS, OnUpdateOptions) ON_COMMAND(ID_CHANGE_DESCRIBE, OnDescChg) ON_UPDATE_COMMAND_UI(ID_CHANGE_DESCRIBE, OnUpdateDescChg) ON_COMMAND(ID_BRANCH_DESCRIBE, OnDescBranch) ON_UPDATE_COMMAND_UI(ID_BRANCH_DESCRIBE, OnUpdateDescBranch) ON_COMMAND(ID_LABEL_DESCRIBE, OnDescLabel) ON_UPDATE_COMMAND_UI(ID_LABEL_DESCRIBE, OnUpdateDescLabel) ON_COMMAND(ID_CLIENT_DESCRIBE, OnDescClient) ON_UPDATE_COMMAND_UI(ID_CLIENT_DESCRIBE, OnUpdateDescClient) ON_COMMAND(ID_USER_DESCRIBE, OnDescUser) ON_UPDATE_COMMAND_UI(ID_USER_DESCRIBE, OnUpdateDescUser) ON_COMMAND(ID_JOB_DESCRIBE, OnDescJob) ON_UPDATE_COMMAND_UI(ID_JOB_DESCRIBE, OnUpdateDescJob) ON_COMMAND(ID_EMAIL, OnEmail) ON_UPDATE_COMMAND_UI(ID_EMAIL, OnUpdateEmail) ON_COMMAND(ID_URL, OnURL) ON_UPDATE_COMMAND_UI(ID_URL, OnUpdateURL) ON_COMMAND(ID_DIFF2, OnDiff2) ON_UPDATE_COMMAND_UI(ID_DIFF2, OnUpdateDiff2) ON_COMMAND(ID_CURRENTTASK, OnCallTrack) ON_UPDATE_COMMAND_UI(ID_CURRENTTASK, OnUpdateCallTrack) ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll) ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateEditSelectAll) ON_UPDATE_COMMAND_UI(ID_POSITIONTOPATTERN, OnUpdatePositionToPattern) ON_COMMAND(ID_POSITIONTOPATTERN, OnPositionToPattern) ON_UPDATE_COMMAND_UI(ID_FINDNEXT, OnUpdatePositionToNext) ON_COMMAND(ID_FINDNEXT, OnPositionToNext) ON_UPDATE_COMMAND_UI(ID_FINDPREV, OnUpdatePositionToPrev) ON_COMMAND(ID_FINDPREV, OnPositionToPrev) ON_BN_CLICKED(IDC_SHOWFIXES, OnShowfixes) ON_BN_CLICKED(IDC_SHOWFILES, OnShowfiles) ON_WM_HELPINFO() ON_COMMAND(ID_HELPNOTES, OnQuickHelp) ON_COMMAND(ID_HELP, OnHelp) ON_COMMAND(IDCANCEL, OnClose) ON_BN_CLICKED(IDC_EDITIT, OnEditButton) ON_WM_CONTEXTMENU() //}}AFX_MSG_MAP ON_MESSAGE(WM_P4DIFF2, OnP4Diff2 ) ON_MESSAGE(WM_P4PREPBROWSE, OnP4ViewFile ) ON_MESSAGE(WM_P4FIXES, OnP4Fixes ) ON_MESSAGE(WM_P4DESCRIBE, OnP4Describe ) ON_MESSAGE(WM_P4FILEINFORMATION, OnP4FileInformation ) ON_MESSAGE(WM_P4ENDFILEINFORMATION, OnP4EndFileInformation ) ON_MESSAGE(WM_P4FSTAT, OnP4LabelContents ) ON_MESSAGE(WM_P4ENDDESCRIBE, OnP4EndDescribe ) ON_MESSAGE(WM_NEWCLIENT, OnNewClient ) ON_MESSAGE(WM_NEWUSER, OnNewUser ) ON_MESSAGE(WM_QUITTING, OnQuitting ) ON_MESSAGE(WM_FINDPATTERN, OnFindPattern ) ON_WM_INITMENUPOPUP() ON_REGISTERED_MESSAGE( WM_FINDREPLACE, OnFindReplace ) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CSpecDescDlg message handlers BOOL CSpecDescDlg::OnInitDialog() { CDialog::OnInitDialog(); if (m_Modeless) { DWORD dwStyle = GetWindowLong(m_hWnd, GWL_STYLE); SetWindowLong(m_hWnd, GWL_STYLE, dwStyle | WS_MINIMIZEBOX); MainFrame()->SetModelessWnd(this); } m_bDiffOutput = m_Caption.Find(_T(" <> ")) > 0; GetWindowRect(&m_InitRect); if (m_ShowNextPrev) { GetDlgItem(IDC_PREVITEM)->ShowWindow(SW_SHOWNORMAL); GetDlgItem(IDC_NEXTITEM)->ShowWindow(SW_SHOWNORMAL); } if (m_ShowEditBtn) GetDlgItem(IDC_EDITIT)->ShowWindow(SW_SHOWNORMAL); if (m_ShowShowDiffs && !m_Key) { m_btShowDiffs.ShowWindow(SW_SHOWNORMAL); m_btShowDiffs.EnableWindow(TRUE); // Set the 2 IDs for the Diff button m_btShowDiffs.SetIDs(IDC_SHOWDIFFS, IDC_SHOWDIFFSMENU); m_btShowDiffs.SetSplit(m_DiffFlag != ID_SHOWDIFFS_NORMAL); //Set up the tooltip m_pToolTip = new CToolTipCtrl; if (!m_pToolTip->Create(this)) { TRACE("Unable To create ToolTip\n"); } else if (!m_pToolTip->AddTool(&m_btShowDiffs, LoadStringResource(IDS_SHOWDIFFS_BTN_TOOLTIP))) { TRACE("Unable to add Show Diffs button to the tooltip\n"); } m_pToolTip->Activate(TRUE); } else { GetMenu()->DeleteMenu(3, MF_BYPOSITION); } if (m_ShowShowFixes) { GetDlgItem(IDC_SHOWFIXES)->ShowWindow(SW_SHOWNORMAL); GetDlgItem(IDC_SHOWFIXES)->EnableWindow(TRUE); } if (m_ShowShowFiles) { GetDlgItem(IDC_SHOWFILES)->ShowWindow(SW_SHOWNORMAL); GetDlgItem(IDC_SHOWFILES)->EnableWindow(TRUE); } if (!MainFrame()->HaveP4QTree()) GetMenu()->DeleteMenu(ID_FILE_REVISIONTREE, MF_BYCOMMAND); // Set the font to the fixed dialog font CreateTheFont(); // And then initialize the window position and edit control m_WinPos.RestoreWindowPosition(); SetEditText(); m_Text.SetEventMask(ENM_KEYEVENTS|ENM_LINK); m_Text.SetBackgroundColor(FALSE, GetSysColor(COLOR_BTNFACE)); // set background color to gray CHARFORMAT cf; cf.cbSize = sizeof(cf); cf.dwMask = CFM_COLOR; cf.crTextColor = GetSysColor(COLOR_BTNTEXT); m_Text.SetSel(0, m_Description.GetLength()); m_Text.SetSelectionCharFormat(cf); m_Text.SetSel(0, 0); if( m_ScrollPastComments ) ScrollPastComments(); SetHotSpots(); SetWindowText(m_Caption); CMenu* hSysMenu = GetSystemMenu( FALSE ); UINT uWhere = hSysMenu->GetMenuItemCount() - 2; // insert new items in reverse order hSysMenu->InsertMenu( uWhere, MF_STRING | MF_BYPOSITION, ID_HELP, LoadStringResource(IDS_SPECDESC_HELP) ); hSysMenu->InsertMenu( uWhere, MF_STRING | MF_BYPOSITION, IDC_COMMAND, LoadStringResource(IDS_SPECDESC_MORECOMMANDS) ); hSysMenu->InsertMenu( uWhere, MF_SEPARATOR | MF_BYPOSITION ); hSysMenu->InsertMenu( uWhere, MF_STRING | MF_BYPOSITION, IDC_PRINT, LoadStringResource(IDS_SPECDESC_PRINT) ); hSysMenu->InsertMenu( uWhere, MF_STRING | MF_BYPOSITION, ID_PAGE_SETUP, LoadStringResource(IDS_SPECDESC_PAGESETUP) ); hSysMenu->InsertMenu( uWhere, MF_SEPARATOR | MF_BYPOSITION ); // remove the calltrack menu item if the super-secret reg setting isn't present: if (!AfxGetApp()->GetProfileInt(_T("Settings"), _T("CallTrack"), 0)) GetMenu()->DeleteMenu(ID_CURRENTTASK,MF_BYCOMMAND); m_TurnOnReDraw = TRUE; // Always turn repainting back on - it might still be off and we currently can't // reliably detect those cases when we don't have to turn it back on. EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CSpecDescDlg::OnShowWindow(BOOL bShow, UINT nStatus) { CDialog::OnShowWindow(bShow, nStatus); if (bShow) SetWindowPos(&wndTop, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); } void CSpecDescDlg::CreateTheFont() { CString face= GET_P4REGPTR()->GetFontFace(); int size= GET_P4REGPTR()->GetFontSize(); int weight= GET_P4REGPTR()->GetFontWeight(); BOOL isItalic= GET_P4REGPTR()->GetFontItalic(); LOGFONT logFont; CWindowDC dc(this); int i = GetDeviceCaps(dc.m_hDC, NUMCOLORS); m_MoreThan256Colors = ((i < 0) || (i > 256)) ? TRUE : FALSE; memset( &logFont, 0, sizeof(LOGFONT) ); // create the regular dialog font logFont.lfCharSet = DEFAULT_CHARSET; logFont.lfPitchAndFamily= FIXED_PITCH | FF_DONTCARE; lstrcpy(logFont.lfFaceName, face.GetBuffer(face.GetLength())); logFont.lfHeight= -abs(size); logFont.lfWeight = weight; //Regular logFont.lfItalic = (BYTE) isItalic; logFont.lfCharSet = DEFAULT_CHARSET; m_Font.CreateFontIndirect( &logFont ); m_Text.SetFont(&m_Font); } void CSpecDescDlg::SetEditText() { #ifndef UNICODE int numChars = MultiByteToWideChar(CP_ACP, 0, m_Description, -1, 0, 0); delete const_cast<LPWCH>(m_DescriptionW); m_DescriptionW = new WCHAR[numChars]; MultiByteToWideChar(CP_ACP, 0, m_Description, -1, const_cast<LPWCH>(m_DescriptionW), numChars); #else m_DescriptionW = m_Description; #endif m_Text.SetWindowText(m_Description); } void CSpecDescDlg::ScrollPastComments() { if(m_ScrollPastComments) { if(m_SkipLines == 0) { CString line; // Most specification output begins with a huge block of comment text // scroll past all that rot for( int i=0; i < m_Text.GetLineCount(); i++ ) { const int MAX_LINE_LEN = 1024; LPTSTR buf= line.GetBuffer( MAX_LINE_LEN + 1); int size = m_Text.GetLine( i, buf, MAX_LINE_LEN ); buf[size] = 0; line.ReleaseBuffer(); line.TrimLeft(_T(" \t")); if( line.GetLength() > 0 && line[0] == _T('#') ) m_SkipLines++; } } m_Text.LineScroll(m_SkipLines); m_Text.SetSel(m_Text.LineIndex(m_SkipLines), m_Text.LineIndex(m_SkipLines)); } } void CSpecDescDlg::SetDescription(LPCTSTR txt, BOOL scrollPastComments /*=TRUE*/) { // copy to m_Description, replacing "\r\n" with "\n" // equivalent to but much, much faster than: // m_Description = txt; // m_Description.Replace(_T("\r\n"), _T("\n")); LPTSTR pDesc = m_Description.GetBufferSetLength(lstrlen(txt)+1); while(*txt) { if(*txt == _T('\r') && txt[1] == _T('\n')) { txt++; *pDesc++ = *txt++; } else { #ifdef UNICODE *pDesc++ = *txt++; #else _tccpy(pDesc, txt); pDesc = CharNext(pDesc); txt = CharNext(txt); #endif } } *pDesc = 0; m_Description.ReleaseBuffer(); m_ScrollPastComments= scrollPastComments; m_SkipLines = 0; int lgth = m_Description.GetLength(); if(lgth > 32000) { // Find out if we're running NT or win95 OSVERSIONINFO osVer; osVer.dwOSVersionInfoSize= sizeof(OSVERSIONINFO); GetVersionEx(&osVer); BOOL brittleWare= (osVer.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); int trunc = 0; if(brittleWare) trunc = 32000; else if (lgth > 60020) { if (osVer.dwMajorVersion < 5) trunc = 60000; else if (lgth > 256000) trunc = 256000; } if (trunc) { CString txt; txt.FormatMessage(IDS_DESCRIPTION_TRUNCATED_n, trunc); m_Description = m_Description.Left(trunc) + txt; } } } void CSpecDescDlg::OnSize(UINT nType, int cx, int cy) { CRect rect; CDialog::OnSize(nType, cx, cy); if (nType == SIZE_MINIMIZED) { if (!m_Item.IsEmpty()) SetWindowText(m_Item); } else if (m_HasBeenMinimized) SetWindowText(m_Caption); GetClientRect(&rect); int x=rect.Width(); int y=rect.Height(); // Slide the OK button to the right of dlg CWnd *pOK=GetDlgItem(IDOK); if(pOK != NULL && IsWindow(pOK->m_hWnd)) { pOK->GetWindowRect(&rect); ScreenToClient(&rect); pOK->MoveWindow(x-rect.Width()-4, y-rect.Height()-4, rect.Width(), rect.Height(), TRUE); pOK->RedrawWindow(); CWnd *pBtn = GetDlgItem(IDC_PRINT); pBtn->MoveWindow(4, y-rect.Height()-4, rect.Width(), rect.Height(), TRUE); pBtn->RedrawWindow(); if (m_ShowNextPrev) { pBtn = GetDlgItem(IDC_PREVITEM); pBtn->MoveWindow(4+rect.Width()+4, y-rect.Height()-4, rect.Width(), rect.Height(), TRUE); pBtn->RedrawWindow(); pBtn = GetDlgItem(IDC_NEXTITEM); pBtn->MoveWindow(4+rect.Width()+4+rect.Width()+4, y-rect.Height()-4, rect.Width(), rect.Height(), TRUE); pBtn->RedrawWindow(); } if (m_ShowEditBtn) { pBtn = GetDlgItem(IDC_EDITIT); pBtn->MoveWindow(4+rect.Width()+4+rect.Width()+4+rect.Width()+4, y-rect.Height()-4, rect.Width(), rect.Height(), TRUE); pBtn->RedrawWindow(); } if (m_ShowShowDiffs) { pBtn = GetDlgItem(IDC_SHOWDIFFS); pBtn->MoveWindow(4+rect.Width()+4+rect.Width()+4+rect.Width()+4+rect.Width()+4, y-rect.Height()-4, rect.Width()+18, rect.Height(), TRUE); pBtn->RedrawWindow(); } if (m_ShowShowFixes) { pBtn = GetDlgItem(IDC_SHOWFIXES); pBtn->MoveWindow(4+rect.Width()+4+rect.Width()+4+rect.Width()+4+rect.Width()+4, y-rect.Height()-4, rect.Width(), rect.Height(), TRUE); pBtn->RedrawWindow(); } if (m_ShowShowFiles) { pBtn = GetDlgItem(IDC_SHOWFILES); pBtn->MoveWindow(4+rect.Width()+4+rect.Width()+4+rect.Width()+4+rect.Width()+4, y-rect.Height()-4, rect.Width(), rect.Height(), TRUE); pBtn->RedrawWindow(); } // Increase the size of the edit control above the button m_Text.MoveWindow(4, 4, x-8, y-rect.Height()-14, TRUE); } } LRESULT CSpecDescDlg::OnQuitting(WPARAM wParam, LPARAM lParam) { // P4Win is terminating, so close this dialog. CDialog::OnOK(); return 0; } void CSpecDescDlg::OnClose() { if (m_pParent && m_Modeless) m_pParent->PostMessage(WM_P4ENDDESCRIBE, 0, (LPARAM)this); CDialog::OnOK(); } void CSpecDescDlg::OnOK() { // If server is busy, wait a bit before exiting if( m_ChkServerBusy && SERVER_BUSY() ) { Sleep(0); SET_BUSYCURSOR(); // wait a bit in 1/10 sec intervals to see if the server request finishes int t=GET_P4REGPTR()->BusyWaitTime(); do { Sleep(50); t -= 50; } while (SERVER_BUSY() && t > 0); if( SERVER_BUSY() ) { ::PostMessage(MainFrame()->m_hWnd, WM_COMMAND, ID_CANCEL_BUTTON, 0); return; } } m_WinPos.SaveWindowPosition(); if (m_pParent && m_Modeless) m_pParent->PostMessage(WM_P4ENDDESCRIBE, 0, (LPARAM)this); CDialog::OnOK(); } // These 2 routines handle the Next and Prev buttons. // // Note that we have to turn off the painting for all child windows of the main P4Win window // to prevent flashing. This works because the describe dialogbox is not a child of the // P4win main window - it's a top level window of its own. // We turn the painting back on in the caller of this dialogbox when they pess OK, Enter or ESC void CSpecDescDlg::OnNextitem() { if ((!m_Key && SERVER_BUSY()) || !m_ShowNextPrev) { MessageBeep(0); return; } m_WinPos.SaveWindowPosition(); SetWindowText( LoadStringResource(IDS_PERFORCE_DESCRIPTION) ); m_Text.SetWindowText( LoadStringResource(IDS_LOADING) ); UpdateWindow( ); // Turn off all painting in children of main window to prevent flashing EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, FALSE); if (m_pParent && m_Modeless) m_pParent->PostMessage(WM_P4ENDDESCRIBE, IDC_NEXTITEM, (LPARAM)this); CDialog::EndDialog(IDC_NEXTITEM); } void CSpecDescDlg::OnPrevitem() { if ((!m_Key && SERVER_BUSY()) || !m_ShowNextPrev) { MessageBeep(0); return; } m_WinPos.SaveWindowPosition(); SetWindowText( LoadStringResource(IDS_PERFORCE_DESCRIPTION) ); m_Text.SetWindowText( LoadStringResource(IDS_LOADING) ); UpdateWindow( ); // Turn off all painting in children of main window to prevent flashing EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, FALSE); if (m_pParent && m_Modeless) m_pParent->PostMessage(WM_P4ENDDESCRIBE, IDC_PREVITEM, (LPARAM)this); CDialog::EndDialog(IDC_PREVITEM); } void CSpecDescDlg::OnUpdateShowDiffsNormal(CCmdUI* pCmdUI) { pCmdUI->Enable(m_ShowShowDiffs && m_DiffFlag != ID_SHOWDIFFS_NORMAL); } void CSpecDescDlg::OnUpdateShowDiffsSummary(CCmdUI* pCmdUI) { pCmdUI->Enable(m_ShowShowDiffs && m_DiffFlag != ID_SHOWDIFFS_SUMMARY); } void CSpecDescDlg::OnUpdateShowDiffsUnified(CCmdUI* pCmdUI) { pCmdUI->Enable(m_ShowShowDiffs && m_DiffFlag != ID_SHOWDIFFS_UNIFIED); } void CSpecDescDlg::OnUpdateShowDiffsContext(CCmdUI* pCmdUI) { pCmdUI->Enable(m_ShowShowDiffs && m_DiffFlag != ID_SHOWDIFFS_CONTEXT); } void CSpecDescDlg::OnUpdateShowDiffsRCS(CCmdUI* pCmdUI) { pCmdUI->Enable(m_ShowShowDiffs && m_DiffFlag != ID_SHOWDIFFS_RCS); } void CSpecDescDlg::OnUpdateShowDiffsNone(CCmdUI* pCmdUI) { pCmdUI->Enable(m_ShowShowDiffs && m_DiffFlag); } void CSpecDescDlg::OnShowDiffsBtn() { CPoint point; CRect rect; GetDlgItem(IDC_SHOWDIFFS)->GetWindowRect(&rect); point.x = rect.left; point.y = rect.bottom + 1; OnContextMenu(GetDlgItem(IDC_SHOWDIFFS), point); m_btShowDiffs.ClearButtonPushed(); } void CSpecDescDlg::OnShowDiffsNormal() { if (m_DiffFlag == ID_SHOWDIFFS_NORMAL) OnShowDiffsBtn(); else OnShowDiffs(ID_SHOWDIFFS_NORMAL); } void CSpecDescDlg::OnShowDiffsSummary() { OnShowDiffs(ID_SHOWDIFFS_SUMMARY); } void CSpecDescDlg::OnShowDiffsUnified() { OnShowDiffs(ID_SHOWDIFFS_UNIFIED); } void CSpecDescDlg::OnShowDiffsContext() { OnShowDiffs(ID_SHOWDIFFS_CONTEXT); } void CSpecDescDlg::OnShowDiffsRCS() { OnShowDiffs(ID_SHOWDIFFS_RCS); } void CSpecDescDlg::OnShowDiffsNone() { OnShowDiffs(ID_SHOWDIFFS_NONE); } void CSpecDescDlg::OnShowDiffs(int flag) { if ((!m_Key && SERVER_BUSY()) || !m_ShowShowDiffs) { MessageBeep(0); return; } m_WinPos.SaveWindowPosition(); SetWindowText( LoadStringResource(IDS_LOADING_DIFFS) ); UpdateWindow( ); // Turn off all painting in children of main window to prevent flashing EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, FALSE); if (m_pParent && m_Modeless) m_pParent->PostMessage(WM_P4ENDDESCRIBE, flag, (LPARAM)this); CDialog::EndDialog(flag); } void CSpecDescDlg::OnEditButton() { if (SERVER_BUSY() || !m_ShowEditBtn) { MessageBeep(0); return; } m_WinPos.SaveWindowPosition(); if (m_pParent && m_Modeless) m_pParent->PostMessage(WM_P4ENDDESCRIBE, IDC_EDITIT, (LPARAM)this); CDialog::EndDialog(IDC_EDITIT); } void CSpecDescDlg::OnPrint() { CString outBuf = m_Description; // remove comments from description int i; while (outBuf.GetAt(0) == _T('#')) { if ((i = outBuf.Find(_T('\n'))) == -1) break; outBuf = outBuf.Right(outBuf.GetLength() - i - 1); } outBuf.TrimLeft(_T("\r\n")); outBuf.TrimRight(_T("\r\n\t ")); // if the whole spec is comments, they must be printing the spec def itself. if (outBuf.IsEmpty()) outBuf = m_Description; MainFrame()->PrintString(outBuf, m_Caption); } void CSpecDescDlg::OnPageSetup() { MainFrame()->PageSetup(); } void CSpecDescDlg::OnSysCommand(UINT nID, LPARAM lParam) { switch(nID) { case ID_PAGE_SETUP: OnPageSetup(); return; case IDC_PRINT: OnPrint(); return; case ID_HELP: OnHelp(); return; case SC_MINIMIZE: GetDesktopWindow()->ArrangeIconicWindows(); break; } CDialog::OnSysCommand(nID, lParam); } void CSpecDescDlg::SetMenuFlags() { long nStartChar; long nEndChar; m_fPopup = MF_GRAYED | MF_DISABLED | MF_POPUP; m_fMarked= MF_GRAYED | MF_STRING; m_fFile = MF_GRAYED | MF_STRING; m_fHist = MF_GRAYED | MF_STRING; m_fRev = MF_GRAYED | MF_STRING; m_fProp = MF_GRAYED | MF_STRING; m_fChg = MF_GRAYED | MF_STRING; m_fClTk = MF_GRAYED | MF_STRING; m_fItem = MF_GRAYED | MF_STRING; m_fCli = MF_GRAYED | MF_STRING; m_fUser = MF_GRAYED | MF_STRING; m_fJob = MF_GRAYED | MF_STRING; m_fEmail= MF_GRAYED | MF_STRING; m_fURL = MF_GRAYED | MF_STRING; m_fDiff2= MF_GRAYED | MF_STRING; m_Text.GetSel( nStartChar, nEndChar ); if ( nStartChar < nEndChar ) { int i = IsItaHotSpot(nStartChar, nEndChar); UINT fHotSpot = (i == -1) ? 0 : m_HotSpotType.GetAt(i); BOOL b1line = m_Text.LineFromChar(nStartChar) == m_Text.LineFromChar(nEndChar); m_fMarked= MF_ENABLED | MF_STRING; CString selText = m_Text.GetSelText(); selText.TrimRight(); selText.TrimLeft(); switch(fHotSpot) { case HS_ISAFILE: m_fFile = MF_ENABLED | MF_STRING; break; case HS_ISACHG: m_fChg = MF_ENABLED | MF_STRING; break; case HS_ISAUSER: m_fUser = MF_ENABLED | MF_STRING; break; case HS_ISACLIENT: m_fCli = MF_ENABLED | MF_STRING; break; case HS_ISAJOB: m_fJob = MF_ENABLED | MF_STRING; break; case HS_ISAEMAIL: m_fEmail = MF_ENABLED | MF_STRING; break; case HS_ISAURL: m_fURL = MF_ENABLED | MF_STRING; break; case HS_ISDIFF2: m_fDiff2 = MF_ENABLED | MF_STRING; break; default: m_fFile = ((((selText.GetAt(0) == _T('/')) && (selText.GetAt(1) == _T('/'))) || ((selText.GetAt(0) == _T('"')) && (selText.GetAt(1) == _T('/')) && (selText.GetAt(2) == _T('/')))) && (selText.Find(_T("//"), 2) == -1)) ? MF_ENABLED | MF_STRING : MF_GRAYED | MF_STRING; if (m_fFile == (MF_ENABLED | MF_STRING)) break; if ((i = selText.Find(_T('@'))) != -1) { if (b1line && (selText.Find(_T(' ')) == -1)) { if (selText.Find(_T('.'), i) != -1) m_fEmail = MF_ENABLED | MF_STRING; else { m_fPopup = MF_POPUP; m_fCli = m_fUser = MF_ENABLED | MF_STRING; } } } else if (b1line && (selText.Find(_T(' ')) == -1)) { m_fPopup = MF_POPUP; if (_istdigit(selText.GetAt(0))) { m_fChg = m_fClTk = MF_ENABLED | MF_STRING; for (int i = 0; ++i < selText.GetLength(); ) { if (!_istdigit(selText.GetAt(i))) { m_fChg = m_fClTk = MF_GRAYED | MF_STRING; break; } } } m_fItem = m_fCli = m_fUser = m_fJob = (m_fChg == (MF_GRAYED | MF_STRING)) ? MF_ENABLED | MF_STRING : MF_GRAYED | MF_STRING; } break; } if (m_fFile == (MF_ENABLED | MF_STRING)) { m_fRev = selText.Find(_T('#')) > 2 ? MF_ENABLED | MF_STRING : MF_GRAYED | MF_STRING; if ((selText.Find(_T("...")) == -1) && (selText.FindOneOf(_T("*?")) == -1)) { m_fProp = MF_ENABLED | MF_STRING; if (m_RevHistEnable) m_fHist = MF_ENABLED | MF_STRING; } } } } int CSpecDescDlg::IsItaHotSpot(int nStartChar, int nEndChar) { int i; for (i = -1; ++i < m_numHotSpots; ) { int b = m_HotSpotBgn.GetAt(i); int e = m_HotSpotEnd.GetAt(i); if ((nStartChar == b) && (nEndChar == e)) return i; else if (nStartChar < b) break; } return -1; } void CSpecDescDlg::OnMsgfilterDescription(NMHDR* pNMHDR, LRESULT* pResult) { MSGFILTER *pMsgFilter = reinterpret_cast<MSGFILTER *>(pNMHDR); *pResult = 0; if(pMsgFilter->nmhdr.idFrom == IDC_DESCRIPTION) { if(pMsgFilter->msg == WM_KEYDOWN) { // trap ctrl-c keydown message if(GetKeyState(VK_CONTROL) & 0x8000) { if (pMsgFilter->wParam == 0x43) // ^C { // richedit should not process this message *pResult = 1; // translate to a copy command so we can modify the copy process PostMessage(WM_COMMAND, ID_EDIT_COPY, 0); } else if (pMsgFilter->wParam == 0x46) // ^F { // richedit should not process this message *pResult = 1; // translate to a find command PostMessage(WM_COMMAND, ID_POSITIONTOPATTERN, 0); } else if (pMsgFilter->wParam == 0x54) // ^T { // richedit should not process this message *pResult = 1; OnOptions(); } } else if(GetKeyState(VK_SHIFT) & 0x8000) { if (pMsgFilter->wParam == VK_F3) // Shift+F3 { // richedit should not process this message *pResult = 1; // translate to a find previous command PostMessage(WM_COMMAND, ID_FINDPREV, 0); } } else { if (pMsgFilter->wParam == VK_F3) // F3 { // richedit should not process this message *pResult = 1; // translate to a find next command PostMessage(WM_COMMAND, ID_FINDNEXT, 0); } } } else if(pMsgFilter->msg == WM_KEYUP) { if (pMsgFilter->wParam == VK_TAB) // TAB key coming up == Desc got focus MakeSmartSelection(); } } } void CSpecDescDlg::MakeSmartSelection() { CHARRANGE cr, crtmp; m_Text.GetSel(cr); if (!cr.cpMin) { m_Text.LineScroll(0 - m_Text.GetFirstVisibleLine() + m_SkipLines); int nFirstVisChar = m_Text.LineIndex(m_SkipLines); crtmp.cpMin = 0; crtmp.cpMax = -1; m_Text.GetSel(crtmp); if (cr.cpMax >= crtmp.cpMax) { CPoint pt; pt.x = pt.y = 0; cr.cpMin = cr.cpMax = nFirstVisChar; } m_Text.SetSel(cr); } } void CSpecDescDlg::OnEditCopy() { CString selText= MakeLFs(m_Text.GetSelText()); CopyTextToClipboard(selText); } void CSpecDescDlg::OnUpdateEditSelectAll(CCmdUI* pCmdUI) { // this should always be enabled pCmdUI->Enable(TRUE); } void CSpecDescDlg::OnEditSelectAll() { m_Text.SetSel( 0, -1 ); } void CSpecDescDlg::OnUpdateOptions(CCmdUI* pCmdUI) { // this should always be enabled pCmdUI->Enable(TRUE); } void CSpecDescDlg::OnOptions() { CString face = GET_P4REGPTR()->GetFontFace(); int size = GET_P4REGPTR()->GetFontSize(); int weight = GET_P4REGPTR()->GetFontWeight(); BOOL isItalic= GET_P4REGPTR()->GetFontItalic(); MainFrame()->OnPerforceOptions(TRUE, FALSE, 0, IDS_PAGE_SPECIFICATIONS); if (face != GET_P4REGPTR()->GetFontFace() || size != GET_P4REGPTR()->GetFontSize() || weight != GET_P4REGPTR()->GetFontWeight() || isItalic != GET_P4REGPTR()->GetFontItalic()) { m_Font.DeleteObject(); CreateTheFont(); } } void CSpecDescDlg::OnFileRevisionhistory() { int i; int rev = -1; CString itemStr= m_Text.GetSelText(); if ((i = itemStr.Find(_T('#'))) != -1) { rev = _ttoi(itemStr.Right(itemStr.GetLength() - i - 1)); if (!rev) rev = -1; itemStr = itemStr.Left(i); } 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 CSpecDescDlg::OnFileRevisionTree() { int i; int rev = -1; CString itemStr= m_Text.GetSelText(); if ((i = itemStr.Find(_T('#'))) != -1) { rev = _ttoi(itemStr.Right(itemStr.GetLength() - i - 1)); if (!rev) rev = -1; itemStr = itemStr.Left(i); } TheApp()->CallP4RevisionTree(itemStr); } void CSpecDescDlg::OnFileInformation() { int i; CString itemStr= m_Text.GetSelText(); if ((i = itemStr.Find(_T('#'))) != -1) itemStr = itemStr.Left(i); 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 CSpecDescDlg::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, TRUE, 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 CSpecDescDlg::OnP4EndFileInformation( WPARAM wParam, LPARAM lParam ) { CFileInfoDlg *dlg = (CFileInfoDlg *)lParam; dlg->DestroyWindow(); return TRUE; } void CSpecDescDlg::OnPositionDepot() { int i; CString itemStr = m_Text.GetSelText(); if ((i = itemStr.Find(_T('#'))) != -1) itemStr = itemStr.Left( i ); // trim off rev# info else if ((i = itemStr.Find(_T("/..."))) != -1) itemStr = itemStr.Left( i ); // trim off "/..." ((CMainFrame *) AfxGetMainWnd())->ExpandDepotString( itemStr, TRUE ); } void CSpecDescDlg::OnDiffHead() { int i; int rev = -1; int headRev = -1; CString fileType = _T("text"); CString name = m_Text.GetSelText(); if ((i = name.Find(_T('#'))) != -1) { rev = _ttoi(name.Right(name.GetLength() - i - 1)); if (!rev) rev = -1; name = name.Left( i ); // trim off rev# info } if ( !PumpMessages( ) ) return; // 0 -> quitting CCmd_Fstat *pCmd2= new CCmd_Fstat; pCmd2->Init(NULL, RUN_SYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key); pCmd2->SetIncludeAddedFiles( TRUE ); if( pCmd2->Run( FALSE, name, TRUE, 0 ) && !pCmd2->GetError() ) { CObList *coblist2 = pCmd2->GetFileList( ); ASSERT_KINDOF( CObList, coblist2 ); ASSERT( coblist2->GetCount() <= 1 ); POSITION pos = coblist2->GetHeadPosition( ); if( pos != NULL ) { CP4FileStats *stats = ( CP4FileStats * )coblist2->GetNext( pos ); ASSERT_KINDOF( CP4FileStats, stats ); fileType= stats->GetHeadType(); headRev = stats->GetHeadRev(); delete stats; } } delete pCmd2; if ((rev == -1) || (headRev == -1)) { CString txt = LoadStringResource(IDS_UNABLE_TO_DETERMINE_REV_NUMBERS_DIFF_FAILS); if (headRev == -1) txt += LoadStringResource(IDS_SPECDESC_FILE_NOT_IN_CLIENT_VIEW); AfxMessageBox(txt, MB_OK | MB_ICONHAND); return; } if (rev == headRev) { AfxMessageBox(IDS_THIS_IS_THE_HEAD_REV, MB_OK); return; } CCmd_Diff2 *pCmd= new CCmd_Diff2; pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key); if( pCmd->Run( name, name, rev, headRev, fileType, fileType) ) { UPDATE_STATUS( LoadStringResource(IDS_DIFFING_FILES) ); } else delete pCmd; } void CSpecDescDlg::OnDiffPrev() { int i; int rev = -1; int prevRev = -1; CString fileType = _T("text"); CString name = m_Text.GetSelText(); if ((i = name.Find(_T('#'))) != -1) { rev = _ttoi(name.Right(name.GetLength() - i - 1)); if (!rev) rev = -1; name = name.Left( i ); // trim off rev# info } if (rev < 2) { AfxMessageBox(rev == 1 ? IDS_THERE_IS_NO_PREVIOUS_REV : IDS_UNABLE_TO_DETERMINE_REV_NUMBER_DIFF_FAILS, MB_OK); return; } prevRev = rev - 1; if ( !PumpMessages( ) ) return; // 0 -> quitting CCmd_Fstat *pCmd2= new CCmd_Fstat; pCmd2->Init(NULL, RUN_SYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key); pCmd2->SetIncludeAddedFiles( TRUE ); if( pCmd2->Run( FALSE, name, TRUE, 0 ) && !pCmd2->GetError() ) { CObList *coblist2 = pCmd2->GetFileList( ); ASSERT_KINDOF( CObList, coblist2 ); ASSERT( coblist2->GetCount() <= 1 ); POSITION pos = coblist2->GetHeadPosition( ); if( pos != NULL ) { CP4FileStats *stats = ( CP4FileStats * )coblist2->GetNext( pos ); ASSERT_KINDOF( CP4FileStats, stats ); fileType= stats->GetHeadType(); delete stats; } } delete pCmd2; CCmd_Diff2 *pCmd= new CCmd_Diff2; pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key); if( pCmd->Run( name, name, prevRev, rev, fileType, fileType) ) { UPDATE_STATUS( LoadStringResource(IDS_DIFFING_FILES) ); } else delete pCmd; } void CSpecDescDlg::OnDiffCliFile() { int i; int rev = -1; CString fileType = _T("text"); CString name = m_Text.GetSelText(); CString clifile; if ((i = name.Find(_T('#'))) != -1) { rev = _ttoi(name.Right(name.GetLength() - i - 1)); if (!rev) rev = -1; name = name.Left( i ); // trim off rev# info } if ( !PumpMessages( ) ) return; // 0 -> quitting CCmd_Fstat *pCmd2= new CCmd_Fstat; pCmd2->Init(NULL, RUN_SYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key); pCmd2->SetIncludeAddedFiles( TRUE ); if( pCmd2->Run( FALSE, name, 0 ) && !pCmd2->GetError() ) { CObList *coblist2 = pCmd2->GetFileList( ); ASSERT_KINDOF( CObList, coblist2 ); ASSERT( coblist2->GetCount() <= 1 ); POSITION pos = coblist2->GetHeadPosition( ); if( pos != NULL ) { CP4FileStats *stats = ( CP4FileStats * )coblist2->GetNext( pos ); ASSERT_KINDOF( CP4FileStats, stats ); fileType= stats->GetHeadType(); clifile = stats->GetFullClientPath(); delete stats; } } delete pCmd2; if (clifile.IsEmpty()) { CString msg = name + _T(" ") + LoadStringResource(IDS_NOT_IN_CLIENT_VIEW); AfxMessageBox(msg, MB_ICONINFORMATION); return; } CCmd_Diff2 *pCmd= new CCmd_Diff2; pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key); if( pCmd->Run( name, clifile, rev, rev, fileType, fileType, FALSE, TRUE) ) { UPDATE_STATUS( LoadStringResource(IDS_DIFFING_FILES) ); } else delete pCmd; } LRESULT CSpecDescDlg::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 CSpecDescDlg::OnUpdateSync(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fRev & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdatePositionDepot(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fFile & (MF_GRAYED|MF_DISABLED)) && !m_Key); } void CSpecDescDlg::OnUpdateDiffHead(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fRev & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateDiffPrev(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fRev & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateDiffCliFile(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fRev & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateFileAutobrowse(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fRev & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateFileAnnotate(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(GET_SERVERLEVEL() >= 14 && !(m_fRev & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateFileInformation(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fProp & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateFileRevisionhistory(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fHist & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateDescChg(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fChg & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateDescBranch(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fItem & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateDescLabel(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fItem & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateDescClient(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fCli & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateDescUser(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fUser & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateDescJob(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fJob & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateCallTrack(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fClTk & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateEmail(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fEmail & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateURL(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fURL & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnUpdateEditCopy(CCmdUI* pCmdUI) { long nStartChar, nEndChar; m_Text.GetSel(nStartChar, nEndChar); pCmdUI->Enable(nStartChar < nEndChar); } void CSpecDescDlg::OnSync() { int i; CString rev; CString itemStr= m_Text.GetSelText(); if ((i = itemStr.Find(_T('#'))) != -1) { rev = itemStr.Right(itemStr.GetLength() - i - 1); itemStr = itemStr.Left(i); } if (rev.GetLength() == 0) { AfxMessageBox(IDS_UNABLE_TO_DETERMINE_REV_NUMBER_SYNC_FAILS, MB_ICONSTOP); return; } itemStr += _T("#") + rev; m_StringList.RemoveAll(); m_StringList.AddHead(itemStr); CCmd_Get *pCmd= new CCmd_Get; pCmd->Init( MainFrame()->GetDepotWnd(), RUN_ASYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key); if( pCmd->Run( &m_StringList, FALSE ) ) UPDATE_STATUS( LoadStringResource(IDS_FILE_SYNC) ); else delete pCmd; } void CSpecDescDlg::OnFileAutobrowse() { int i; int rev = -1; CString fileType = _T("text"); CString name = m_Text.GetSelText(); if ((i = name.Find(_T('#'))) != -1) { rev = _ttoi(name.Right(name.GetLength() - i - 1)); if (!rev) rev = -1; name = name.Left( i ); // trim off rev# info } if ( !PumpMessages( ) ) return; // 0 -> quitting CCmd_Fstat *pCmd2= new CCmd_Fstat; pCmd2->Init(NULL, RUN_SYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key); pCmd2->SetIncludeAddedFiles( TRUE ); if( pCmd2->Run( FALSE, name, TRUE, 0 ) && !pCmd2->GetError() ) { CObList *coblist2 = pCmd2->GetFileList( ); ASSERT_KINDOF( CObList, coblist2 ); ASSERT( coblist2->GetCount() <= 1 ); POSITION pos = coblist2->GetHeadPosition( ); if( pos != NULL ) { CP4FileStats *stats = ( CP4FileStats * )coblist2->GetNext( pos ); ASSERT_KINDOF( CP4FileStats, stats ); fileType= stats->GetHeadType(); delete stats; } else { AfxMessageBox(IDS_UNABLE_TO_DETERMINE_FILE_TYPE_VIEW_FAILS, MB_ICONSTOP); rev = -2; } } else { AfxMessageBox(IDS_UNABLE_TO_DETERMINE_FILE_TYPE_VIEW_FAILS, MB_ICONSTOP); rev = -2; } delete pCmd2; if (rev == -2) return; if (rev == -1) { AfxMessageBox(IDS_UNABLE_TO_DETERMINE_REV_NUMBER_VIEW_FAILS, MB_ICONSTOP); return; } // 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; } void CSpecDescDlg::OnFileAnnotate() { int i; int rev = -1; CString fileType = _T("text"); CString name = m_Text.GetSelText(); if ((i = name.Find(_T('#'))) != -1) { rev = _ttoi(name.Right(name.GetLength() - i - 1)); if (!rev) rev = -1; name = name.Left( i ); // trim off rev# info } if ( !PumpMessages( ) ) return; // 0 -> quitting if (MainFrame()->HaveTLV()) { TheApp()->CallP4A(name, _T(""), 0); // use p4v.exe for annotate return; } CCmd_Fstat *pCmd2= new CCmd_Fstat; pCmd2->Init(NULL, RUN_SYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key); pCmd2->SetIncludeAddedFiles( TRUE ); if( pCmd2->Run( FALSE, name, TRUE, 0 ) && !pCmd2->GetError() ) { CObList *coblist2 = pCmd2->GetFileList( ); ASSERT_KINDOF( CObList, coblist2 ); ASSERT( coblist2->GetCount() <= 1 ); POSITION pos = coblist2->GetHeadPosition( ); if( pos != NULL ) { CP4FileStats *stats = ( CP4FileStats * )coblist2->GetNext( pos ); ASSERT_KINDOF( CP4FileStats, stats ); fileType= stats->GetHeadType(); delete stats; } else { AfxMessageBox(IDS_UNABLE_TO_DETERMINE_FILE_TYPE_VIEW_FAILS, MB_ICONSTOP); rev = -2; } } else { AfxMessageBox(IDS_UNABLE_TO_DETERMINE_FILE_TYPE_VIEW_FAILS, MB_ICONSTOP); rev = -2; } delete pCmd2; if (rev == -2) return; if (rev == -1) { AfxMessageBox(IDS_UNABLE_TO_DETERMINE_REV_NUMBER_VIEW_FAILS, MB_ICONSTOP); return; } m_ViewFileIsText = ((fileType.Find(_T("text")) != -1) || (fileType.Find(_T("symlink")) != -1)) ? TRUE : FALSE; // Fetch the annotated 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( FALSE, name, fileType, FALSE, FALSE, FALSE, rev, GET_P4REGPTR()->GetAnnotateWhtSpace()) ) { UPDATE_STATUS( LoadStringResource(IDS_FETCHING_FILE) ); m_Viewer=GET_P4REGPTR()->GetEditApp(); } 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 CSpecDescDlg::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 CSpecDescDlg::OnDescItem(HWND hWnd, int viewType, int flag /*=0*/) { m_SelItem.TrimRight(); m_SelItem.TrimLeft(); CCmd_Describe *pCmd = new CCmd_Describe; // if a command is in progress, the new dialogs are modeless but their parent // needs to be this dialog for proper cleanup if the user does something stupid. pCmd->Init( SERVER_BUSY() ? m_hWnd : hWnd, RUN_ASYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key ); if( pCmd->Run( m_SelType = viewType, m_SelItem, NULL, FALSE, flag ) ) { UPDATE_STATUS( LoadStringResource(IDS_FETCHING_SPEC) ); return; } else { delete pCmd; return; } } void CSpecDescDlg::OnDescChg() { m_SelItem = m_Text.GetSelText(); OnDescItem(MainFrame()->OldChgsWnd(), P4DESCRIBE); } void CSpecDescDlg::OnDescChgLong(int flag) { OnDescItem(MainFrame()->OldChgsWnd(), P4DESCRIBELONG, flag); } void CSpecDescDlg::OnDescBranch() { m_SelItem = m_Text.GetSelText(); OnDescItem(MainFrame()->BranchWnd(), P4BRANCH_SPEC); } void CSpecDescDlg::OnDescLabel() { m_SelItem = m_Text.GetSelText(); OnDescItem(MainFrame()->LabelWnd(), P4LABEL_SPEC); } void CSpecDescDlg::OnDescClient() { int i; m_SelItem = m_Text.GetSelText(); if ((i = m_SelItem.Find(_T('@'))) != -1) m_SelItem = m_SelItem.Right(m_SelItem.GetLength() - i - 1); OnDescItem(MainFrame()->ClientWnd(), P4CLIENT_SPEC); } void CSpecDescDlg::OnDescUser() { int i; m_SelItem = m_Text.GetSelText(); if ((i = m_SelItem.Find(_T('@'))) != -1) m_SelItem = m_SelItem.Left(i); OnDescItem(MainFrame()->UserWnd(), P4USER_SPEC); } void CSpecDescDlg::OnDescJob() { m_SelItem = m_Text.GetSelText(); OnDescItem(MainFrame()->JobWnd(), P4JOB_SPEC); } void CSpecDescDlg::OnUpdateDiff2(CCmdUI* pCmdUI) { SetMenuFlags(); pCmdUI->Enable(!(m_fDiff2 & (MF_GRAYED|MF_DISABLED))); } void CSpecDescDlg::OnDiff2() { TCHAR szBuffer[4096]; LPTSTR lpszBuffer = szBuffer; CString curLine; long nStartChar; long nEndChar; m_Text.GetSel(nStartChar, nEndChar); long lineNbr = m_Text.LineFromChar(-1); int lgth = m_Text.GetLine(lineNbr, lpszBuffer, sizeof(szBuffer)/sizeof(TCHAR) - 6); szBuffer[lgth] = _T('\0'); curLine = &szBuffer[0]; while (curLine && curLine.GetAt(0) != _T('=') || curLine.Find(_T("//")) == -1) { CString tempLine = curLine; // temp variable needed becuase of MFC bug lgth = m_Text.GetLine(--lineNbr, lpszBuffer, sizeof(szBuffer)/sizeof(TCHAR) - 6); szBuffer[lgth] = _T('\0'); curLine = &szBuffer[0] + tempLine; } curLine.TrimLeft(_T(" =")); ASSERT(curLine.GetAt(0) == _T('/')); int i; if ((i = curLine.Find(_T('#'))) > 0) { CString file1 = curLine.Left(i); curLine = curLine.Mid(i+1); int rev1 = _tstoi(curLine); if ((i = curLine.Find(_T('('))) > 0) { CString ft1 = curLine = curLine.Mid(i+1); if ((i = ft1.Find(_T(')'))) > 0) { ft1 = ft1.Left(i); if ((i = curLine.Find(_T('/'))) > 0) { curLine = curLine.Mid(i); if ((i = curLine.Find(_T('#'))) > 0) { CString file2 = curLine.Left(i); curLine = curLine.Mid(i+1); int rev2 = _tstoi(curLine); if ((i = curLine.Find(_T('('))) > 0) { CString ft2 = curLine.Mid(i+1); if ((i = ft2.Find(_T(')'))) > 0) { ft2 = ft2.Left(i); CCmd_Diff2 *pCmd= new CCmd_Diff2; pCmd->Init( MainFrame()->GetDepotWnd(), RUN_ASYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key ); if( pCmd->Run( file1, file2, rev1, rev2, ft1, ft2, FALSE, FALSE) ) MainFrame()->UpdateStatus( LoadStringResource(IDS_DIFFING_FILES) ); else delete pCmd; return; } } } } } } } AfxMessageBox(_T("Error parsing line\nUnable to determine files to diff"), MB_ICONSTOP); } LRESULT CSpecDescDlg::OnP4Describe( WPARAM wParam, LPARAM lParam ) { // Modal SpecDescDlgs are only called when the server is busy if (!SERVER_BUSY()) ASSERT(0); MSG msg; BOOL ret = FALSE; BOOL bOK = TRUE; CString txt; CCmd_Describe *pCmd = ( CCmd_Describe * )wParam; if(!pCmd->GetError() && !MainFrame()->IsQuitting()) { CString desc = MakeCRs( pCmd->GetDescription( ) ); if (m_SelType == P4JOB_SPEC) { int i, j = -2; CString specblankdesc = _T("<enter description here>"); if ((i = desc.Find(specblankdesc)) > 0) { j = lstrlen(_T("\r\nDescription:\r\n\t")); j = desc.Find(_T("\r\nDescription:\r\n\t"), i - j*2) + j; } if ((i == j) && (desc.GetAt(i-1) == _T('\t')) && ((i+specblankdesc.GetLength() >= desc.GetLength()) || (desc.GetAt(i+specblankdesc.GetLength()) < _T(' ')))) { txt.FormatMessage(IDS_THERE_IS_NO_s_TO_DESCRIBE, m_SelItem); bOK = FALSE; } } else if (((m_SelType == P4BRANCH_SPEC) || (m_SelType == P4LABEL_SPEC) || (m_SelType == P4CLIENT_SPEC) || (m_SelType == P4USER_SPEC)) && (desc.Find(_T("\nUpdate:")) == -1)) { txt = m_SelItem + _T(" - no such "); switch(m_SelType) { case P4BRANCH_SPEC: txt += _T("branch"); break; case P4LABEL_SPEC: txt += _T("label"); break; case P4CLIENT_SPEC: txt += _T("client"); break; case P4USER_SPEC: txt += _T("user"); break; } bOK = FALSE; } if (bOK) { CSpecDescDlg *dlg = new CSpecDescDlg(this); dlg->SetIsModeless(TRUE); dlg->SetKey(m_Key); dlg->SetDescription( desc ); dlg->SetItemName( m_SelItem ); CString caption; caption.FormatMessage(IDS_PERFORCE_DESCRIPTION_FOR_s, m_SelItem); dlg->SetCaption( caption ); dlg->SetShowNextPrev(FALSE); dlg->SetShowShowDiffs(m_SelType == P4DESCRIBE || m_SelType == P4DESCRIBELONG); dlg->SetDiffFlag(pCmd->GetFlag()); dlg->SetShowEditBtn(m_SelType == P4JOB_SPEC); dlg->SetShowShowFixes(m_SelType == P4JOB_SPEC); dlg->SetShowShowFiles(m_SelType == P4LABEL_SPEC); dlg->SetFindStrFlags(&m_FindWhatStr, m_FindWhatFlags); dlg->SetViewType(m_SelType); while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) // clear the message queue { if ( msg.message == WM_QUIT ) // get out if app is terminating break; TranslateMessage(&msg); DispatchMessage(&msg); } if (!dlg->Create(IDD_SPECDESC, this)) // display the description dialog box { dlg->DestroyWindow(); // some error! clean up delete dlg; } } else { EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE); AfxMessageBox(txt, MB_ICONWARNING); } } else // had an error - need to turn painting back on { EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE); ::InvalidateRect(NULL, NULL, TRUE); // Make sure ALL windows get updated. } delete pCmd; UPDATE_STATUS( _T("") ); return ret; } LRESULT CSpecDescDlg::OnP4EndDescribe(WPARAM wParam, LPARAM lParam) { CSpecDescDlg *dlg = (CSpecDescDlg *)lParam; switch(wParam) // which button did they click to close the box? { case ID_SHOWDIFFS_NORMAL: case ID_SHOWDIFFS_SUMMARY: case ID_SHOWDIFFS_UNIFIED: case ID_SHOWDIFFS_CONTEXT: case ID_SHOWDIFFS_RCS: case ID_SHOWDIFFS_NONE: { OnDescChgLong(wParam); break; } case IDC_EDITIT: if (!m_Key && wParam == IDC_EDITIT) { if (m_SelType == P4JOB_SPEC) MainFrame()->EditJobSpec(&m_SelItem); else ASSERT(0); } default: // clicked OK, pressed ESC or ENTER - need to turn painting back on EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, TRUE); break; } dlg->DestroyWindow(); return TRUE; } void CSpecDescDlg::OnEmail() { CString seltxt = m_Text.GetSelText(); seltxt.TrimRight(_T('>')); seltxt.TrimLeft(_T('<')); seltxt.TrimLeft(); CString txt = _T("mailto:") + seltxt; int s = (int)ShellExecute(m_hWnd,_T("open"), txt,NULL,NULL,SW_SHOWNORMAL); if (s <= 32) { txt.FormatMessage(IDS_UNABLE_TO_SEND_EMAIL_TO_s, m_Text.GetSelText()); AfxMessageBox(txt, MB_ICONSTOP); } } void CSpecDescDlg::OnURL() { CString seltxt = m_Text.GetSelText(); seltxt.TrimRight(_T(">\"")); seltxt.TrimLeft(_T("<\"")); seltxt.TrimLeft(); int s = (int)ShellExecute(m_hWnd, _T("open"), seltxt,NULL,NULL,SW_SHOWNORMAL); if (s <= 32) { seltxt.FormatMessage(IDS_UNABLE_TO_BROWSE_s, m_Text.GetSelText()); AfxMessageBox(seltxt, MB_ICONSTOP); } } void CSpecDescDlg::OnCallTrack() { CString host = AfxGetApp()->GetProfileString(_T("Settings"), _T("CallTrackHost"), _T("calltrack")); CString txt = "http://" + host + _T("/cgi-bin/detail?call=") + m_Text.GetSelText(); int s = (int)ShellExecute(m_hWnd,_T("open"), txt,NULL,NULL,SW_SHOWNORMAL); if (s <= 32) { txt = _T("Unable to display CallTrack number ") + m_Text.GetSelText(); AfxMessageBox(txt, MB_ICONSTOP); } } void CSpecDescDlg::OnShowfixes() { CCmd_Fixes *pCmdFixes= new CCmd_Fixes; pCmdFixes->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key); if( pCmdFixes->Run(0, 0, TRUE, m_Item) ) { UPDATE_STATUS( LoadStringResource(IDS_UPDATING_JOB_FIXES) ); } else { delete pCmdFixes; RedrawWindow(); UPDATE_STATUS(_T("")); } } LRESULT CSpecDescDlg::OnP4Fixes(WPARAM wParam, LPARAM lParam) { CCmd_Fixes *pCmd= (CCmd_Fixes *) wParam; if(!pCmd->GetError()) { CObList *fixes = pCmd->GetList(); CString theFixes; if (fixes->IsEmpty()) { theFixes = LoadStringResource(IDS_EMPTY_FIXLIST); } else { CP4Fix *fix; CString buf; UpdateData(TRUE); theFixes = LoadStringResource(IDS_FIXLIST_HEADER); POSITION pos; for(pos= fixes->GetHeadPosition(); pos != NULL; ) { fix=(CP4Fix *) fixes->GetNext(pos); ASSERT(fix->IsKindOf(RUNTIME_CLASS(CP4Fix))); buf.FormatMessage(IDS_FIXLIST_ITEM_n_ON_s_BY_s, fix->GetChangeNum(), fix->GetFixDate(), fix->GetUser()); theFixes += buf; delete fix; } //for } theFixes.Replace(_T("\r\n"), _T("\n")); m_Description += theFixes; SetEditText(); m_Text.LineScroll(0 - m_Text.GetFirstVisibleLine()); if( m_ScrollPastComments ) ScrollPastComments(); SetHotSpots(); UpdateData(FALSE); GetDlgItem(IDC_SHOWFIXES)->ShowWindow(SW_HIDE); GetDlgItem(IDC_SHOWFIXES)->EnableWindow(FALSE); } UPDATE_STATUS(_T("")); delete pCmd; return 0; } void CSpecDescDlg::OnShowfiles() { if (SERVER_BUSY()) { MessageBeep(0); return; } m_LabelFileCount=0; m_LabelFiles.Empty(); CString spec; spec.Format(_T("//...@%s"), m_Item); // Call Fstat, w/ suppress==FALSE CCmd_Fstat *pCmd= new CCmd_Fstat; pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK_IF_HAVE_KEY, m_Key); // okay, this is weird, but let's set show entire depot // to true, since we want this command to // read 'p4 fstat //...@mynumber WITHOUT the -C // that would run otherwise. // after all, we all the files to show, not just // the ones on the client view. // BOOL bshowEntireDepot = TRUE; if( pCmd->Run( FALSE, spec, bshowEntireDepot, 0 ) ) { MainFrame()->UpdateStatus( LoadStringResource(IDS_REQUESTING_LABEL_CONTENTS) ); } else { delete pCmd; MainFrame()->ClearStatus(); } } LRESULT CSpecDescDlg::OnP4LabelContents(WPARAM wParam, LPARAM lParam) { CString tmp; CCmd_Fstat *pCmd; if(lParam == 0) // completion { pCmd= (CCmd_Fstat *) wParam; ASSERT_KINDOF(CCmd_Fstat,pCmd); if(!pCmd->GetError()) { tmp.FormatMessage(IDS_LABEL_s_POINTS_TO_n_FILES, m_Item, m_LabelFileCount); AddToStatus(tmp, SV_COMPLETION); MainFrame()->ClearStatus(); delete pCmd; if (m_LabelFileCount) { m_LabelFiles += _T('\n') + tmp; CSpecDescDlg *dlg = new CSpecDescDlg(this); dlg->SetIsModeless(TRUE); dlg->SetKey(m_Key); dlg->SetDescription( m_LabelFiles ); dlg->SetItemName( m_Item ); CString caption; caption.FormatMessage(IDS_FILE_LIST_FOR_LABEL_s, m_Item); dlg->SetCaption( caption ); dlg->SetFindStrFlags(&m_FindWhatStr, m_FindWhatFlags); dlg->SetViewType(P4LABEL_SPEC); if (!dlg->Create(IDD_SPECDESC, this)) // display the description dialog box { dlg->DestroyWindow(); // some error! clean up delete dlg; } m_LabelFiles.Empty(); } } return 0; } else { // Pull a ptr to the command, as well as a batch of CP4FileStats // out of the wrapper CFstatWrapper *pWrap= (CFstatWrapper *) wParam; pCmd= (CCmd_Fstat *) pWrap->pCmd; ASSERT_KINDOF(CCmd_Fstat, pCmd); CObList *list= (CObList *) pWrap->pList; ASSERT_KINDOF(CObList, list); POSITION pos= list->GetHeadPosition(); while(pos != NULL) { // Get the filestats CP4FileStats *stats= (CP4FileStats *) list->GetNext(pos); ASSERT_KINDOF(CP4FileStats, stats); // Increment the counter m_LabelFileCount++; // Format the file, rev and type tmp.FormatMessage(IDS_s_n_s_CHANGELIST_n_s, stats->GetFullDepotPath(), stats->GetHeadRev(), stats->GetHeadType(), stats->GetHeadChangeNum(), stats->GetActionStr(stats->GetHeadAction())); // And add to Description m_LabelFiles += tmp; delete stats; } // while row batch not done delete list; delete pWrap; return 0; } // a batch of rows, we'll be called again so dont delete pCmd } BOOL CSpecDescDlg::OnHelpInfo(HELPINFO* pHelpInfo) { OnHelp(); return(FALSE); } void CSpecDescDlg::OnQuickHelp() { AfxMessageBox(IDS_SPECDESC_QUICKHELP, MB_ICONINFORMATION); } void CSpecDescDlg::OnHelp() { AfxGetApp()->WinHelp(TASK_GETTING_INFORMATION_ABOUT_FORMS); } int CSpecDescDlg::AddHotSpotWord(int idx, int offset, int lineStart, int lgth, BOOL bAtSign) { LPCWSTR line = m_DescriptionW + lineStart; // scan backwards from offset until a space or line ending is found LPCWSTR pBegin = line + offset - lineStart; while(*pBegin > ' ' && pBegin > line) { if (bAtSign && ((*pBegin == '\\') || (*pBegin == '/') || (*pBegin == ':'))) return offset; // bail because users, clients and email addrs don't have /, \ or : if (bAtSign && (*pBegin == '<')) break; // because '<' terminates email and can't appear in users & clients pBegin--; } if(*pBegin <= ' ') pBegin++; // scan forwards from offset until space of line ending is found LPCWSTR pEnd = line + offset - lineStart; while(*pEnd > ' ') { if (bAtSign && ((*pEnd == '\\') || (*pEnd == '/') || (*pEnd == ':'))) return offset; // bail because users, clients and email addrs don't have /, \ or : if (bAtSign && (*pEnd == '>')) break; // because '>' terminates email and can't appear in users & clients pEnd++; } // strip off angle brackets, if present if(*pBegin == '<') { pBegin++; if(*(pEnd-1) == '>') pEnd--; } // strip off parens, even if only left or right is present if(*pBegin == '(') pBegin++; if(*(pEnd-1) == ')') pEnd--; // calculate indexes, and add hotspot int b = pBegin - line + lineStart; int e = pEnd - line + lineStart; m_HotSpotBgn.InsertAt(idx, b); m_HotSpotEnd.InsertAt(idx, e); return(e); } int CSpecDescDlg::AddHotSpotFile(int idx, int offset, int lineStart, int lgth, BOOL bQuoted) { // b points to either "// or -// or // int b = offset; int n = wcslen(m_TO_); if(m_DescriptionW[b] != '/') b++; LPCWSTR pEnd; if(bQuoted) { // scan forwards until first of: end of buffer, ending quote, or newline pEnd = m_DescriptionW + b + 2; while(*pEnd && *pEnd != '\"' && *pEnd >= ' ') pEnd++; } else { BOOL bGotStop = FALSE; // start with pEnd after slashes for(pEnd = m_DescriptionW + b + 2; *pEnd; pEnd++) { LPCWSTR pPrev = pEnd - 1; if (*pEnd == '#') bGotStop = TRUE; else if (*pEnd < ' ') { while(*pPrev == ' ' && pPrev >= m_DescriptionW + lineStart) pEnd = pPrev--; break; } else if ((pEnd[0] == '.') && (pEnd[1] == '.') && (pEnd[2] == '.')) { bGotStop = TRUE; pEnd += 2; } else if ((pEnd[0] == '/') && (pEnd[1] == '/')) { while(*pPrev == ' ' && pPrev >= m_DescriptionW + lineStart) pEnd = pPrev--; break; } else if ((*pEnd == ' ') && !wcsncmp( pEnd, m_TO_, n ) && ((pEnd[n] == '/') || (pEnd[n] <= ' '))) { while(*pPrev == ' ' && pPrev >= m_DescriptionW + lineStart) pEnd = pPrev--; break; } else if (bGotStop && (*pEnd == ' ')) break; } } int e = pEnd - m_DescriptionW; m_HotSpotBgn.InsertAt(idx, b); m_HotSpotEnd.InsertAt(idx, e); return(e); } #define STRLENW(s) (sizeof(s)/sizeof(WCHAR)-1) void CSpecDescDlg::SetHotSpots() { int lgth = wcslen(m_DescriptionW); LPCWSTR pLastMinus1 = m_DescriptionW + (lgth ? lgth - 1 : 0); BOOL bInJobs = FALSE; BOOL bInFixes = FALSE; BOOL bInDiffs = FALSE; // preallocate arrays, and set grow-by size m_HotSpotBgn.RemoveAll(); m_HotSpotEnd.RemoveAll(); m_HotSpotType.RemoveAll(); m_HotSpotBgn.SetSize(m_Text.GetLineCount() - m_Text.GetFirstVisibleLine(), 10); m_HotSpotEnd.SetSize(m_Text.GetLineCount() - m_Text.GetFirstVisibleLine(), 10); m_HotSpotType.SetSize(m_Text.GetLineCount() - m_Text.GetFirstVisibleLine(), 10); m_numHotSpots = 0; int beginChar = m_Text.LineIndex(); for (LPCWSTR pAt = m_DescriptionW + beginChar; *pAt; pAt++ ) { // some strings we look for: static const WCHAR strModifiedBy[] = L"ModifiedBy:\t"; static const WCHAR strUser[] = L"User:\t"; static const WCHAR strJobsFixed[] = L"Jobs fixed ..."; static const WCHAR strAffectedFilesEnglish[] = L"Affected files ..."; static WCHAR strAffectedFiles[100] = L""; static WCHAR strFixes[100] = L""; static WCHAR strChange[100] = L""; static WCHAR strReportedBy[100] = L""; static const WCHAR strDifferences[] = L"Differences ..."; static const WCHAR strChangelist[] = L"Changelist "; static const WCHAR strEqContent[] = L"==== content"; static const int strModifiedByLen = STRLENW(strModifiedBy); static const int strUserLen = STRLENW(strUser); static const int strJobsFixedLen = STRLENW(strJobsFixed); static const int strAffectedFilesEnglishLen = STRLENW(strAffectedFilesEnglish); static int strAffectedFilesLen = STRLENW(strAffectedFiles) + 1; static int strFixesLen = STRLENW(strFixes) + 1; static int strChangeLen = STRLENW(strChange) + 1; static int strReportedByLen = STRLENW(strReportedBy) + 1; static const int strDifferencesLen = STRLENW(strDifferences); static const int strChangelistLen = STRLENW(strChangelist); static const int strEqContentLen = STRLENW(strEqContent); // load resource dependent tags first time through: static bool bResStringsLoaded = false; if(!bResStringsLoaded) { bResStringsLoaded = true; CString strAffectedFilesR = LoadStringResource(IDS_AFFECTEDFILES); strAffectedFilesR.TrimLeft(_T("\r\n")); strAffectedFilesR.TrimRight(_T("\r\n")); CString strFixesR = LoadStringResource(IDS_FIXLIST_HEADER); strFixesR.TrimLeft(_T('\n')); strFixesR.TrimRight(_T('\n')); CString strChangeR = LoadStringResource(IDS_FIXLIST_ITEM_CHANGE_TAG); CString strReportedByR; if (m_ReportedByTitle.IsEmpty()) strReportedByR = _T("Owner:\t"); else strReportedByR = m_ReportedByTitle + _T(":\t"); #ifdef UNICODE lstrcpy(strAffectedFiles, strAffectedFilesR); lstrcpy(strFixes, strFixesR); lstrcpy(strChange, strChangeR); lstrcpy(strReportedBy, strReportedByR); #else ASSERT(strAffectedFilesR.GetLength() < strAffectedFilesLen); MultiByteToWideChar(CP_ACP, 0, strAffectedFilesR, -1, strAffectedFiles, strAffectedFilesLen); ASSERT(strFixesR.GetLength() < strFixesLen); MultiByteToWideChar(CP_ACP, 0, strFixesR, -1, strFixes, strFixesLen); ASSERT(strChangeR.GetLength() < strChangeLen); MultiByteToWideChar(CP_ACP, 0, strChangeR, -1, strChange, strChangeLen); ASSERT(strReportedByR.GetLength() < strReportedByLen); MultiByteToWideChar(CP_ACP, 0, strReportedByR, -1, strReportedBy, strReportedByLen); #endif strAffectedFilesLen = wcslen(strAffectedFiles); strFixesLen = wcslen(strFixes); strChangeLen = wcslen(strChange); strReportedByLen = wcslen(strReportedBy); } // if at end of line, skip to start of next line if(*pAt == '\n') { while(*pAt == '\n') pAt++; if(!*pAt) break; beginChar = pAt - m_DescriptionW; } int i = pAt - m_DescriptionW; if(bInDiffs && i == beginChar) { if(wcsncmp(pAt, L"==== ", 5)) { // skip line if not starting a diff LPCWSTR pChar = pAt; while ((++pChar < pLastMinus1) && (*pChar != '\n')) ; pAt = pChar - 1; continue; } i += 4; pAt += 4; } // an '@' that's not at the start of a line? if (i > beginChar && (*pAt == '@')) { // Don't put hotspots on @@ if (*(pAt+1) == '@') { pAt++; continue; } // make sure there's something before the '@' LPCWSTR pBeforeAt = pAt-1; if(*pBeforeAt <= ' ') continue; int newi = AddHotSpotWord(m_numHotSpots, i, beginChar, lgth, TRUE); if (newi == i) pAt++; // word contained a / \ or : which is not in a user, client or email addr - so skip it else { LPCWSTR pDot = wcschr(m_DescriptionW+i+1, '.'); if(pDot && pDot < m_DescriptionW+newi) { // found '.' following '@', so assume email address m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISAEMAIL); } else { // no '.' following '@', so assume user@client m_HotSpotEnd.SetAt(m_numHotSpots, i); m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISAUSER); m_HotSpotBgn.InsertAt(m_numHotSpots, i+1); m_HotSpotEnd.InsertAt(m_numHotSpots, newi); m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISACLIENT); } pAt += newi - i - 1; } } else if(!wcsncmp(pAt, L"-//", 3) || !wcsncmp(pAt, L"\"//", 3) || !wcsncmp(pAt, L" //", 3) || !wcsncmp(pAt, L"\t//", 3) || ((i == beginChar) && !wcsncmp(pAt, L"//", 2))) { if (*(pAt+3) <= ' ') // depot names don't have a white space after the // continue; bool bQuoted = *pAt == L'\"'; int newi = AddHotSpotFile(m_numHotSpots, i, beginChar, lgth, bQuoted); m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISAFILE); // don't lose trailing delimiter pAt += newi - i - 1; } else if(!wcsncmp(pAt, L"http://", 7) || !wcsncmp(pAt, L"https://", 8)) { int newi = AddHotSpotWord(m_numHotSpots, i, beginChar, lgth, FALSE) - 1; m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISAURL); pAt += newi - i; } else if(i == beginChar) { int newi = i; if(!wcsncmp(pAt, strReportedBy, strReportedByLen)) { newi = AddHotSpotWord(m_numHotSpots, i + strReportedByLen, beginChar, lgth, FALSE); m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISAUSER); } else if(!wcsncmp(pAt, strModifiedBy, strModifiedByLen)) { newi = AddHotSpotWord(m_numHotSpots, i + strModifiedByLen, beginChar, lgth, FALSE); m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISAUSER); } else if((m_viewType != P4USER_SPEC) && !wcsncmp(pAt, strUser, strUserLen)) { newi = AddHotSpotWord(m_numHotSpots, i + strUserLen, beginChar, lgth, FALSE); m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISAUSER); } else if(!wcsncmp(pAt, strJobsFixed, strJobsFixedLen)) { bInJobs = TRUE; newi = i + strJobsFixedLen; } // note: depending on whether a submitted or unsubmitted change is // being described, the 'Affected files...' string comes either // from the server (always English) or from our resource // stringtable. We don't know which it is here, so try both. else if(!wcsncmp(pAt, strAffectedFiles, strAffectedFilesLen)) { bInJobs = FALSE; newi = i + strAffectedFilesLen; } else if(!wcsncmp(pAt, strAffectedFilesEnglish, strAffectedFilesEnglishLen)) { bInJobs = FALSE; newi = i + strAffectedFilesEnglishLen; } else if (bInJobs && (*pAt > ' ')) { newi = AddHotSpotWord(m_numHotSpots, i, beginChar, lgth, FALSE); m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISAJOB); pAt += newi - i; i = newi; static const WCHAR strBy[] = L" by "; static const WCHAR strDate[] = L" on yyyy/mm/dd"; static const int strByLen = STRLENW(strBy); static const int strDateLen = STRLENW(strDate); if (!wcsncmp(pAt + strDateLen, strBy, strByLen)) { newi = AddHotSpotWord(m_numHotSpots, i + strDateLen + strByLen, beginChar, lgth, FALSE); m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISAUSER); } } else if(!wcsncmp(pAt, strFixes, strFixesLen)) { bInFixes = TRUE; newi = i + strFixesLen; if(pAt[strFixesLen] == '\n') { // if there are fixes, make sure we don't miss the newline newi--; } } else if (bInFixes && !wcsncmp(pAt, strChange, strChangeLen)) { newi = AddHotSpotWord(m_numHotSpots, i + strChangeLen, beginChar, lgth, FALSE); m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISACHG); } else if (!wcsncmp(pAt, strDifferences, strDifferencesLen)) { bInDiffs = TRUE; newi = i + strDifferencesLen; } pAt += newi - i; } else if (!wcsncmp(pAt, strChangelist, strChangelistLen)) { pAt += strChangelistLen + 1; i += strChangelistLen + 1; LPCWSTR pChar = pAt; while(iswdigit(*pChar)) pChar++; if(pChar > pAt) { i = AddHotSpotWord(m_numHotSpots, i, beginChar, pChar - pAt, FALSE); pAt = pChar; m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISACHG); } } else if (m_bDiffOutput && !wcsncmp(pAt, strEqContent, strEqContentLen)) { i = AddHotSpotWord(m_numHotSpots, i+5, beginChar, strEqContentLen-5, FALSE); pAt += strChangelistLen; m_HotSpotType.InsertAt(m_numHotSpots++, HS_ISDIFF2); } // if at end of line, note start of next line if(*pAt == '\n') beginChar = (pAt + 1) - m_DescriptionW; } if (m_numHotSpots == 0) return; CHARFORMAT cf; cf.cbSize = sizeof(cf); cf.dwMask = CFM_COLOR | CFM_UNDERLINE | CFM_LINK; cf.dwEffects = CFE_UNDERLINE|CFE_LINK; DWORD txtcolor = GetSysColor(COLOR_BTNTEXT); if (!txtcolor) cf.crTextColor = m_MoreThan256Colors ? RGB(0,0,0xFF) : RGB(0,128,0); else if (txtcolor == 0xFFFFFF) cf.crTextColor = RGB(0xFF,0,0xFF); else { if (GetBValue(txtcolor) + 0xFF > 0xFF) txtcolor ^= 0xFFFF00; cf.crTextColor = txtcolor; } long orgb, orge; m_Text.GetSel(orgb, orge); for (int i = -1; ++i < m_numHotSpots; ) { int b = m_HotSpotBgn.GetAt(i); int e = m_HotSpotEnd.GetAt(i); m_Text.SetSel(b, e); m_Text.SetSelectionCharFormat(cf); } m_Text.SetSel(orgb, orge); } /* _________________________________________________________________ for commands that will run synchronously. _________________________________________________________________ */ BOOL CSpecDescDlg::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; } ///////////////////////////////////////////////////////////////////////// // CDialog doesn't support UI updating the way CFrameWnd does, so we have to // handle WM_INITPOPOPMENU here. See MSDN article Q242577. void CSpecDescDlg::OnInitMenuPopup(CMenu *pPopupMenu, UINT nIndex,BOOL bSysMenu) { ASSERT(pPopupMenu != NULL); // Check the enabled state of various menu items. CCmdUI state; state.m_pMenu = pPopupMenu; ASSERT(state.m_pOther == NULL); ASSERT(state.m_pParentMenu == NULL); // Determine if menu is popup in top-level menu and set m_pOther to // it if so (m_pParentMenu == NULL indicates that it is secondary popup). HMENU hParentMenu; if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu) state.m_pParentMenu = pPopupMenu; // Parent == child for tracking popup. else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL) { CWnd* pParent = this; // Child windows don't have menus--need to go to the top! if (pParent != NULL && (hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL) { int nIndexMax = ::GetMenuItemCount(hParentMenu); for (int nIndex = 0; nIndex < nIndexMax; nIndex++) { if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu) { // When popup is found, m_pParentMenu is containing menu. state.m_pParentMenu = CMenu::FromHandle(hParentMenu); break; } } } } state.m_nIndexMax = pPopupMenu->GetMenuItemCount(); for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++) { state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex); if (state.m_nID == 0) continue; // Menu separator or invalid cmd - ignore it. ASSERT(state.m_pOther == NULL); ASSERT(state.m_pMenu != NULL); if (state.m_nID == (UINT)-1) { // Possibly a popup menu, route to first item of that popup. state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex); if (state.m_pSubMenu == NULL || (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 || state.m_nID == (UINT)-1) { continue; // First item of popup can't be routed to. } state.DoUpdate(this, TRUE); // Popups are never auto disabled. } else { // Normal menu item. // Auto enable/disable if frame window has m_bAutoMenuEnable // set and command is _not_ a system command. state.m_pSubMenu = NULL; state.DoUpdate(this, FALSE); } // Adjust for menu deletions and additions. UINT nCount = pPopupMenu->GetMenuItemCount(); if (nCount < state.m_nIndexMax) { state.m_nIndex -= (state.m_nIndexMax - nCount); while (state.m_nIndex < nCount && pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID) { state.m_nIndex++; } } state.m_nIndexMax = nCount; } } BOOL CSpecDescDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { NMHDR* pNMHDR = (NMHDR*)lParam; if(pNMHDR->idFrom == IDC_DESCRIPTION && pNMHDR->code == EN_LINK) { ENLINK *link = (ENLINK*)lParam; if(link->msg == WM_LBUTTONUP) { int i = IsItaHotSpot(link->chrg.cpMin, link->chrg.cpMax); if (i != -1) { { switch (m_HotSpotType.GetAt(i)) { case HS_ISACHG: m_Text.SetSel(link->chrg); OnDescChg(); break; case HS_ISAUSER: m_Text.SetSel(link->chrg); OnDescUser(); break; case HS_ISACLIENT: m_Text.SetSel(link->chrg); OnDescClient(); break; case HS_ISAJOB: m_Text.SetSel(link->chrg); OnDescJob(); break; case HS_ISAEMAIL: m_Text.SetSel(link->chrg); OnEmail(); break; case HS_ISAURL: m_Text.SetSel(link->chrg); OnURL(); break; case HS_ISDIFF2: m_Text.SetSel(link->chrg); OnDiff2(); break; } } } *pResult = 0; return TRUE; } else if(link->msg == WM_LBUTTONUP || link->msg == WM_RBUTTONUP) { m_Text.SetSel(link->chrg); *pResult = 0; return TRUE; } } return CDialog::OnNotify(wParam, lParam, pResult); } void CSpecDescDlg::OnContextMenu(CWnd* pWnd, CPoint point) { CP4Menu popMenu; SetMenuFlags(); if(point.x == -1 && point.y == -1) { GetCursorPos(&point); } if (pWnd == GetDlgItem(IDC_SHOWDIFFS)) { CRect rect; pWnd->GetWindowRect(&rect); point.x = rect.left; point.y = rect.bottom + 1; popMenu.LoadMenu(IDR_SPECDESC_DIFF); } else { popMenu.LoadMenu(IDR_SPECDESC_RICH); if (!MainFrame()->HaveP4QTree()) popMenu.DeleteMenu(ID_FILE_REVISIONTREE, MF_BYCOMMAND); if (!AfxGetApp()->GetProfileInt(_T("Settings"), _T("CallTrack"), 0)) popMenu.DeleteMenu(ID_CURRENTTASK,MF_BYCOMMAND); if (m_bDiffOutput && !(m_fDiff2 & (MF_GRAYED|MF_DISABLED))) popMenu.InsertMenu(IDB_BROWSE, MF_BYCOMMAND, ID_DIFF2, LoadStringResource(IDS_DIFFTHE2FILES)); } popMenu.GetSubMenu(0)->TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this); if (pWnd == GetDlgItem(IDC_SHOWDIFFS)) m_btShowDiffs.ClearButtonPushed(); } BOOL CSpecDescDlg::PreTranslateMessage(MSG* pMsg) { if (NULL != m_pToolTip) m_pToolTip->RelayEvent(pMsg); return CDialog::PreTranslateMessage(pMsg); } void CSpecDescDlg::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { if (m_InitRect.Height()) { lpMMI->ptMinTrackSize.x= m_InitRect.Width(); lpMMI->ptMinTrackSize.y= m_InitRect.Height(); } } // This signals the closing of a modeless dialog to // MainFrame which will delete the 'this' object void CSpecDescDlg::OnDestroy() { if (m_Modeless) ::PostMessage(MainFrame()->m_hWnd, WM_P4DLGDESTROY, 0, (LPARAM)this); } LRESULT CSpecDescDlg::OnNewClient(WPARAM wParam, LPARAM lParam) { switch(m_viewType) { case P4CHANGE_SPEC: case P4CLIENT_SPEC: if (m_ShowEditBtn) { GetDlgItem(IDC_EDITIT)->EnableWindow(FALSE); GetDlgItem(IDC_EDITIT)->ShowWindow(SW_HIDE); } break; } return TRUE; } LRESULT CSpecDescDlg::OnNewUser(WPARAM wParam, LPARAM lParam) { switch(m_viewType) { case P4CHANGE_SPEC: case P4USER_SPEC: if (m_ShowEditBtn) { GetDlgItem(IDC_EDITIT)->EnableWindow(FALSE); GetDlgItem(IDC_EDITIT)->ShowWindow(SW_HIDE); } break; } return TRUE; } void CSpecDescDlg::OnUpdatePositionToPattern(CCmdUI* pCmdUI) { pCmdUI->Enable( NULL == m_pFRDlg ); } void CSpecDescDlg::OnPositionToPattern() { if (GetFocus()->m_hWnd != m_Text.m_hWnd) { MakeSmartSelection(); CHARRANGE cr; m_Text.GetSel(cr); GotoDlgCtrl(GetDlgItem(IDC_DESCRIPTION)); m_Text.SetSel(cr); } if ( NULL == m_pFRDlg ) { m_pFRDlg = new CFindReplaceDialog(); // Must be created on the heap m_pFRDlg->m_fr.lStructSize = sizeof(FINDREPLACE); m_pFRDlg->m_fr.hwndOwner = this->m_hWnd; m_pFRDlg->Create( TRUE, m_FindWhatStr, _T(""), m_FindWhatFlags, this ); } } void CSpecDescDlg::OnUpdatePositionToNext(CCmdUI* pCmdUI) { pCmdUI->Enable(!m_FindWhatStr.IsEmpty()); } void CSpecDescDlg::OnPositionToNext() { if (GetFocus()->m_hWnd != m_Text.m_hWnd) { MakeSmartSelection(); CHARRANGE cr; m_Text.GetSel(cr); GotoDlgCtrl(GetDlgItem(IDC_DESCRIPTION)); m_Text.SetSel(cr); } if (!m_FindWhatStr.IsEmpty()) { PostMessage(WM_FINDPATTERN, (WPARAM)m_FindWhatFlags | 0x80000000, (LPARAM)m_FindWhatStr.GetBuffer(0)); } } void CSpecDescDlg::OnUpdatePositionToPrev(CCmdUI* pCmdUI) { pCmdUI->Enable(!m_FindWhatStr.IsEmpty()); } void CSpecDescDlg::OnPositionToPrev() { if (GetFocus()->m_hWnd != m_Text.m_hWnd) { MakeSmartSelection(); CHARRANGE cr; m_Text.GetSel(cr); GotoDlgCtrl(GetDlgItem(IDC_DESCRIPTION)); m_Text.SetSel(cr); } if (!m_FindWhatStr.IsEmpty()) { PostMessage(WM_FINDPATTERN, ((WPARAM)m_FindWhatFlags | 0x80000000) ^ FR_DOWN, (LPARAM)m_FindWhatStr.GetBuffer(0)); } } LONG CSpecDescDlg::OnFindReplace(WPARAM wParam, LPARAM lParam) { LPFINDREPLACE lpfp = (LPFINDREPLACE)lParam; if (m_pFRDlg->FindNext() || m_pFRDlg->IsTerminating()) { m_FindWhatStr = lpfp->lpstrFindWhat; m_FindWhatFlags = lpfp->Flags; if (m_pFRDlg->FindNext()) { PostMessage(WM_FINDPATTERN, (WPARAM)(lpfp->Flags), (LPARAM)m_FindWhatStr.GetBuffer(0)); delete m_pFRDlg; } m_pFRDlg = NULL; } return 0; } LRESULT CSpecDescDlg::OnFindPattern(WPARAM wParam, LPARAM lParam) { FINDTEXTEX ft; CHARRANGE cr; int flags = (int)wParam; CString what = (TCHAR *)lParam; m_Text.GetSel(cr); if (flags & FR_DOWN) { ft.chrg.cpMin = cr.cpMax; ft.chrg.cpMax = -1; } else { ft.chrg.cpMax = 0; ft.chrg.cpMin = cr.cpMin; } ft.lpstrText = what.GetBuffer(); if (-1 != m_Text.FindText(flags, &ft)) m_Text.SetSel(ft.chrgText); return 0; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 11099 | brkarpala | Integrate p4win from //guest/perforce_software/p4win/...@8562 | ||
//guest/perforce_software/p4win/gui/SpecDescDlg.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. |