// P4ListBrowse.cpp : implementation file // #include "stdafx.h" #include "p4win.h" #include "MainFrm.h" #include "P4Object.h" #include "P4ListBrowse.h" #include "StringUtil.h" #include "RegKeyEx.h" #include "cmd_describe.h" #include "hlp\p4win.hh" #include "P4ImageList.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif static LPCTSTR sRegKey = _T("Software\\Perforce\\P4Win\\Layout\\"); static LPCTSTR sRegValue_ColumnWidths = _T("Column Widths"); static LPCTSTR sRegValue_SortColumns = _T("Sort Columns"); #define UPDATE_STATUS(x) ((CMainFrame *)AfxGetMainWnd())->UpdateStatus(x) int CALLBACK P4ListBrowseSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort); #define IMG_INDEX(x) (x-IDB_PERFORCE) // Module global for use in sort callback CP4ListBrowse *pDlg; int viewType; ///////////////////////////////////////////////////////////////////////////// // CP4ListBrowse dialog CP4ListBrowse::CP4ListBrowse(CWnd* pParent, BOOL bWiz/*=FALSE*/, BOOL bBranchInteg/*=FALSE*/) : CDialog(CP4ListBrowse::IDD, pParent) { //{{AFX_DATA_INIT(CP4ListBrowse) //}}AFX_DATA_INIT viewType = m_viewType; m_pParent = pParent; m_Wiz = bWiz; m_BranchInteg = bBranchInteg; m_SortAscending = m_FilterByHost = m_IsFiltered = FALSE; m_LastSortColumn= 0; pDlg=this; m_InitRect.SetRect(0,0,100,100); m_WinPos.SetWindow( this, bBranchInteg ? _T("IntegDlg") : _T("P4ListBrowse") ); for (int i = -1; ++i < MAX_SORT_COLUMNS; ) m_SortColumns[i] = 0; } void CP4ListBrowse::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CP4ListBrowse) DDX_Control(pDX, IDC_P4LIST, m_P4ListCtrl); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CP4ListBrowse, CDialog) //{{AFX_MSG_MAP(CP4ListBrowse) ON_WM_SIZE() ON_WM_GETMINMAXINFO() ON_NOTIFY(LVN_COLUMNCLICK, IDC_P4LIST, OnColumnclickP4list) ON_NOTIFY(NM_DBLCLK, IDC_P4LIST, OnDblclickP4list) ON_BN_CLICKED(IDC_REFRESH, OnRefresh) ON_BN_CLICKED(IDC_DESCRIBE, OnDescribe) ON_BN_CLICKED(IDC_BACK, OnBack) // ON_BN_CLICKED(IDHELP, OnHelp) // ON_WM_HELPINFO() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CP4ListBrowse message handlers BOOL CP4ListBrowse::OnInitDialog() { CDialog::OnInitDialog(); // Record the initial window size, then see if there is a registry preference GetWindowRect(&m_InitRect); m_LastRect = m_InitRect; if (!m_Wiz) 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_P4ListCtrl.m_hWnd,LVM_GETEXTENDEDLISTVIEWSTYLE,0,0); dwStyle |= LVS_EX_FULLROWSELECT; ::SendMessage(m_P4ListCtrl.m_hWnd,LVM_SETEXTENDEDLISTVIEWSTYLE,0,dwStyle); // Make sure list control shows selection when not the focused control m_P4ListCtrl.ModifyStyle(0, LVS_SHOWSELALWAYS, 0); // Set the imagelist m_P4ListCtrl.SetImageList(TheApp()->GetImageList(), LVSIL_SMALL); if (m_Wiz) { GetDlgItem(IDC_BACK)->ShowWindow(SW_SHOW); GetDlgItem(IDC_BACK)->EnableWindow(TRUE); GetDlgItem(IDOK)->SetWindowText(LoadStringResource(IDS_FINISH)); m_Hostname = GET_P4REGPTR()->GetHostname(); m_FilterByHost = TRUE; if (!m_IsFiltered) { GetDlgItem(IDC_REFRESH)->EnableWindow(FALSE); GetDlgItem(IDC_REFRESH)->ShowWindow(SW_HIDE); } } else if (m_BranchInteg) { GetDlgItem(IDC_BACK)->ShowWindow(SW_SHOW); GetDlgItem(IDC_BACK)->EnableWindow(FALSE); GetDlgItem(IDOK)->SetWindowText(LoadStringResource(IDS_NEXT)); } if (m_IsFiltered) GetDlgItem(IDC_REFRESH)->SetWindowText(LoadStringResource(IDS_CLEARFILTERR)); // Get original size of control CRect rect; m_P4ListCtrl.GetWindowRect(&rect); int colwidth[MAX_P4OBJECTS_COLUMNS]={90,90,90,90,90,90,90,90,90,90}; // 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_P4ListCtrl.GetWindowRect(&rect); // Get any saved column widths from registry RestoreSavedWidths(colwidth, MAX_P4OBJECTS_COLUMNS); // Make sure no column completely disappeared (because you can't get it back then) for (int i=-1; ++i < MAX_P4OBJECTS_COLUMNS; ) { if (colwidth[i] < 5) colwidth[i] = 5; } // Use the same font as the calling window m_P4ListCtrl.SetFont(m_Font); // Insert the columns int maxcols = m_ColNames->GetSize(); 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_P4ListCtrl.InsertColumn(subItem, &lvCol); } AddTheListData(); 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 CP4ListBrowse::AddTheListData() { // Add the data int maxcols = m_ColNames->GetSize(); CP4Object *p4Object; LV_ITEM lvItem; int iActualItem = -1; CString txt; POSITION pos= m_pP4List->GetHeadPosition(); int iItem; for(iItem=0; iItem < m_pP4List->GetCount(); iItem++) { p4Object= (CP4Object *) m_pP4List->GetNext(pos); if (m_FilterByHost) { txt = p4Object->GetField(2); if (!txt.IsEmpty() && txt.CompareNoCase(m_Hostname)) continue; } for(int subItem=0; subItem < maxcols; 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.iImage = m_iImage; lvItem.lParam=(LPARAM) p4Object; txt=PadCRs(p4Object->GetField(subItem)); lvItem.pszText = const_cast<LPTSTR>( (LPCTSTR ) txt); if(subItem==0) iActualItem=m_P4ListCtrl.InsertItem(&lvItem); else m_P4ListCtrl.SetItem(&lvItem); } } if(m_pP4List->GetCount()) { // Sort the P4Objects list the same way the P4ListView is sorted viewType = m_viewType; m_P4ListCtrl.SortItems( P4ListBrowseSort, m_LastSortColumn ); // Find the p4Object currently selected in the P4Objects pane iItem=0; if (!m_CurrP4Object->IsEmpty()) { TCHAR cur[ LISTVIEWNAMEBUFSIZE + 1 ]; TCHAR str[ LISTVIEWNAMEBUFSIZE + 1 ]; lstrcpy(cur, m_CurrP4Object->GetBuffer(m_CurrP4Object->GetLength()+1)); m_CurrP4Object->ReleaseBuffer(-1); for (int cnt = ListView_GetItemCount( m_P4ListCtrl.m_hWnd ); iItem < cnt; iItem++ ) { ListView_GetItemText( m_P4ListCtrl.m_hWnd, iItem, 0, str, LISTVIEWNAMEBUFSIZE ); if( !Compare(cur, str) ) break; } if (iItem >= ListView_GetItemCount( m_P4ListCtrl.m_hWnd )) iItem = 0; } // Make sure the same p4Object is selected and visible m_P4ListCtrl.SetItemState(iItem, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED); m_P4ListCtrl.EnsureVisible( iItem, FALSE ); } // And finally, set focus to the list control so that the first 'down' // keystroke can be used to scroll down m_P4ListCtrl.SetFocus(); } void CP4ListBrowse::SetP4ObjectList(CObList *P4list) { ASSERT_KINDOF(CObList,P4list); m_pP4List= P4list; } void CP4ListBrowse::SetP4ObjectCols(CStringArray *P4Cols) { m_ColNames= P4Cols; } void CP4ListBrowse::SetP4ObjectCurr(CString *P4Name) { m_CurrP4Object= P4Name; } void CP4ListBrowse::OnOK() { if (!m_Wiz) m_WinPos.SaveWindowPosition(); int nItem=m_P4ListCtrl.GetNextItem( -1, LVNI_ALL | LVNI_SELECTED ); if (nItem != -1) { TCHAR str[ LISTVIEWNAMEBUFSIZE + 1 ]; ListView_GetItemText( m_P4ListCtrl.m_hWnd, nItem, 0, str, LISTVIEWNAMEBUFSIZE ); m_SelectedP4Object = str; } else m_SelectedP4Object.Empty(); EndDialog(IDOK); } void CP4ListBrowse::OnCancel() { if (!m_Wiz) m_WinPos.SaveWindowPosition(); CDialog::OnCancel(); } void CP4ListBrowse::OnBack() { EnumChildWindows(AfxGetMainWnd()->m_hWnd, ChildSetRedraw, FALSE); EndDialog(IDC_BACK); } void CP4ListBrowse::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); // Slide the OK and Cancel buttons to the bottom of dlg CWnd *pRefresh = GetDlgItem(IDC_REFRESH); CWnd *pBack = GetDlgItem(IDC_BACK); CWnd *pOK = GetDlgItem(IDOK); CWnd *pCancel = GetDlgItem(IDCANCEL); CWnd *pDescribe = GetDlgItem(IDC_DESCRIBE); if(!pOK) return; 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; // Move down pRefresh->GetWindowRect(&rect); ScreenToClient(rect); pRefresh->SetWindowPos(NULL, rect.left, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER); // Move down and slide right pBack->GetWindowRect(&rect); ScreenToClient(rect); pBack->SetWindowPos(NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER); pOK->GetWindowRect(&rect); ScreenToClient(rect); pOK->SetWindowPos(NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER); pCancel->GetWindowRect(&rect); ScreenToClient(rect); pCancel->SetWindowPos(NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER); pDescribe->GetWindowRect(&rect); ScreenToClient(rect); pDescribe->SetWindowPos(NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER); // Increase the size of the list both horiz and vert CWnd *pList = GetDlgItem(IDC_P4LIST); pList->GetWindowRect(&rect); pList->SetWindowPos(NULL, 0, 0, rect.right - rect.left + dx, rect.bottom - rect.top + dy, SWP_NOMOVE | SWP_NOZORDER); RedrawWindow(); } void CP4ListBrowse::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { lpMMI->ptMinTrackSize.x= m_InitRect.Width(); lpMMI->ptMinTrackSize.y= m_InitRect.Height(); } void CP4ListBrowse::OnColumnclickP4list(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; if(pNMListView->iSubItem != m_LastSortColumn) m_LastSortColumn=pNMListView->iSubItem; else m_SortAscending= !m_SortAscending; viewType = m_viewType; if(pNMListView->iItem == -1) m_P4ListCtrl.SortItems( P4ListBrowseSort,(DWORD)pNMListView->iSubItem); *pResult = 0; } // Since a sort column can only appear once in our saved column array, // given the current column, we can determine the next column. // Note that incoming 'colnbr' is a non-negative 0-relative number and must be incremented // The return value is a signed 1-relative number; negative for descending, positive for ascending int CP4ListBrowse::NextSortColumn(int lastcol) { if (lastcol == 0) return 0; // 0 => no next column lastcol++; for (int i = -1; ++i < (MAX_SORT_COLUMNS-1); ) { if (abs(m_SortColumns[i]) == lastcol) return m_SortColumns[i+1]; } return 0; // 0 => no next column } int CALLBACK P4ListBrowseSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int rc; int nextcol; CString txt1; CString txt2; if (viewType == P4CHANGE_SPEC && !lParamSort) { txt1.Format(_T("%09d"), _tstoi(((CP4Object const *)lParam1)->GetField(lParamSort))); txt2.Format(_T("%09d"), _tstoi(((CP4Object const *)lParam2)->GetField(lParamSort))); } else { txt1= ((CP4Object const *)lParam1)->GetField(lParamSort); txt2= ((CP4Object const *)lParam2)->GetField(lParamSort); } if(pDlg->IsSortAscending()) rc = txt1.CompareNoCase(txt2); else rc = txt2.CompareNoCase(txt1); // check for duplicate keys; if so, sort on next sort columns if (!rc && lParamSort && ((nextcol = pDlg->NextSortColumn(lParamSort)) != 0)) { // nextcol now contains a value like 1 for col-0-ascending or like -1 for col-0-decending BOOL saveSortAscending = pDlg->IsSortAscending(); if (nextcol < 0) { nextcol = 0 - nextcol; pDlg->SetSortAscending(FALSE); } else pDlg->SetSortAscending(TRUE); rc = P4ListBrowseSort(lParam1, lParam2, (LPARAM)(nextcol-1)); pDlg->SetSortAscending(saveSortAscending); } return rc; } // Check the registry to see if we have recorded the // column widths lastused for the p4Object pane's list view. void CP4ListBrowse::RestoreSavedWidths(int *width, int numcols) { CRegKeyEx key; CString theKey = sRegKey + m_SubKey; 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); } if(!sortCols.IsEmpty()) { for(int i=0; i< MAX_SORT_COLUMNS; i++) { m_SortColumns[i]= GetANumber(sortCols); if(!i && !m_SortColumns[i]) m_SortColumns[i] = 1; } m_LastSortColumn= abs(m_SortColumns[0]) - 1; // SortColumns are signed & 1-relative m_SortAscending = m_SortColumns[0] >= 0 ? TRUE : FALSE; } } } void CP4ListBrowse::OnRefresh() { EndDialog(IDC_REFRESH); } void CP4ListBrowse::OnDblclickP4list(NMHDR* pNMHDR, LRESULT* pResult) { *pResult = 0; OnOK(); } void CP4ListBrowse::OnDescribe( void ) { int nItem=m_P4ListCtrl.GetNextItem( -1, LVNI_ALL | LVNI_SELECTED ); if (nItem != -1) { TCHAR str[ LISTVIEWNAMEBUFSIZE + 1 ]; ListView_GetItemText( m_P4ListCtrl.m_hWnd, nItem, 0, str, LISTVIEWNAMEBUFSIZE ); m_SelectedP4Object = str; if ( m_SelectedP4Object.IsEmpty( ) ) return; } else return; CCmd_Describe *pCmd = new CCmd_Describe; pCmd->Init( m_pParent->m_hWnd, RUN_ASYNC ); pCmd->SetCaller(this); pCmd->SetListCtrl(&m_P4ListCtrl); if( pCmd->Run( m_viewType, m_SelectedP4Object ) ) { MainFrame()->UpdateStatus( LoadStringResource(IDS_FETCHING_SPEC) ); return; } else { delete pCmd; return; } } #ifdef WANTTOFILTERCLIENTSBYHOSTNAME void CP4ListBrowse::OnFilter() { m_FilterByHost = !m_FilterByHost; m_P4ListCtrl.DeleteAllItems(); AddTheListData(); } #endif #ifdef HELPWANTEDFORP4LISTBROPWSE void CP4ListBrowse::OnHelp() { AfxGetApp()->WinHelp(0); } BOOL CP4ListBrowse::OnHelpInfo(HELPINFO* pHelpInfo) { OnHelp(); return TRUE; } #endif
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 11099 | brkarpala | Integrate p4win from //guest/perforce_software/p4win/...@8562 | ||
//guest/perforce_software/p4win/gui/P4ListBrowse.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. |