--- /dev/null
+/**
+ * @file DirColsDlg.cpp
+ *
+ * @brief Implementation file for CDirColsDlg
+ *
+ * @date Created: 2003-08-19
+ */
+// RCS ID line follows -- this is updated by CVS
+// $Id$
+
+
+#include "stdafx.h"
+#include "merge.h"
+#include "DirColsDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CDirColsDlg dialog
+
+
+CDirColsDlg::CDirColsDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CDirColsDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CDirColsDlg)
+ //}}AFX_DATA_INIT
+}
+
+
+void CDirColsDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CDirColsDlg)
+ DDX_Control(pDX, IDC_LIST_SHOW, m_list_show);
+ DDX_Control(pDX, IDC_LIST_HIDE, m_list_hide);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CDirColsDlg, CDialog)
+ //{{AFX_MSG_MAP(CDirColsDlg)
+ ON_BN_CLICKED(IDC_UP, OnUp)
+ ON_BN_CLICKED(IDC_DOWN, OnDown)
+ ON_BN_CLICKED(IDC_ADD, OnAdd)
+ ON_BN_CLICKED(IDC_REMOVE, OnRemove)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CDirColsDlg message handlers
+
+BOOL CDirColsDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ LoadLists();
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+/**
+ * @brief Load listboxes on screen from column array
+ */
+void CDirColsDlg::LoadLists()
+{
+ for (int i=0; i<m_cols.GetSize(); ++i)
+ {
+ const column & c = m_cols[i];
+ CListBox * list = (c.phy_col >= 0) ? &m_list_show : &m_list_hide;
+ int x = list->AddString(m_cols[i].name);
+ list->SetItemData(x, c.log_col);
+ }
+ SortArrayToLogicalOrder();
+ UpdateEnables();
+}
+
+/**
+ * @brief Sort m_cols so that it is in logical column order.
+ */
+void CDirColsDlg::SortArrayToLogicalOrder()
+{
+ qsort(m_cols.GetData(), m_cols.GetSize(), sizeof(m_cols[0]), &cmpcols);
+}
+
+int __cdecl CDirColsDlg::cmpcols(const void * el1, const void * el2)
+{
+ const column * col1 = reinterpret_cast<const column *>(el1);
+ const column * col2 = reinterpret_cast<const column *>(el2);
+ return col1->log_col - col2->log_col;
+}
+
+/**
+ * @brief Move selected items up (in show list)
+ */
+void CDirColsDlg::OnUp()
+{
+ CListBox * list = &m_list_show;
+ // find the first item not selected
+ for (int i=0; i<list->GetCount(); ++i)
+ {
+ if (!list->GetSel(i))
+ break;
+ }
+ // continue down, moving up all selected items
+ for (++i; i<list->GetCount(); ++i)
+ {
+ if (list->GetSel(i))
+ {
+ int data = list->GetItemData(i);
+ CString str;
+ list->GetText(i, str);
+ list->DeleteString(i);
+ int inew = i-1;
+ list->InsertString(inew, str);
+ list->SetItemData(inew, data);
+ list->SetSel(inew);
+ }
+ }
+}
+
+/**
+ * @brief Move selected items down (in show list)
+ */
+void CDirColsDlg::OnDown()
+{
+ CListBox * list = &m_list_show;
+ // find the lst item not selected
+ for (int i=list->GetCount()-1; i>=0; --i)
+ {
+ if (!list->GetSel(i))
+ break;
+ }
+ // continue down, moving up all selected items
+ for (--i; i>=0; --i)
+ {
+ if (list->GetSel(i))
+ {
+ int data = list->GetItemData(i);
+ CString str;
+ list->GetText(i, str);
+ list->DeleteString(i);
+ int inew = i+1;
+ list->InsertString(inew, str);
+ list->SetItemData(inew, data);
+ list->SetSel(inew);
+ }
+ }
+}
+
+/**
+ * @brief Move selected items from hide list to show list
+ */
+void CDirColsDlg::OnAdd()
+{
+ MoveItems(&m_list_hide, &m_list_show, false);
+}
+
+/**
+ * @brief Move selected items from show list to hide list
+ */
+void CDirColsDlg::OnRemove()
+{
+ MoveItems(&m_list_show, &m_list_hide, true);
+}
+
+/**
+ * @brief Move selected items from list1 to list2, putting at top if top==true
+ */
+void CDirColsDlg::MoveItems(CListBox * list1, CListBox * list2, bool top)
+{
+ for (int i=0; i<list1->GetCount(); ++i)
+ {
+ if (list1->GetSel(i))
+ {
+ int data = list1->GetItemData(i);
+ CString str;
+ list1->GetText(i, str);
+ list1->DeleteString(i);
+ --i; // new item promoted to slot#i in list1, we need to check it next
+ int inew = top ? 0 : list2->GetCount();
+ list2->InsertString(inew, str);
+ list2->SetItemData(inew, data);
+ list2->SetSel(inew);
+ }
+ }
+ UpdateEnables();
+}
+
+/**
+ * @brief Enable/disable the Add/Remove buttons appropriately
+ */
+void CDirColsDlg::UpdateEnables()
+{
+ // TODO: We could enable/disable Up/Down buttons also, but
+ // we'd have to trap selection events
+
+ GetDlgItem(IDC_ADD)->EnableWindow(m_list_hide.GetCount() > 0);
+ GetDlgItem(IDC_REMOVE)->EnableWindow(m_list_show.GetCount() > 0);
+}
+
+/**
+ * @brief User clicked ok, so we update m_cols and close
+ */
+void CDirColsDlg::OnOK()
+{
+ // Update all the data in m_cols according to layout on screen
+ for (int i=0; i<m_list_show.GetCount(); ++i)
+ {
+ column * col1 = &m_cols[m_list_show.GetItemData(i)];
+ col1->phy_col = i;
+ }
+ for (i=0; i<m_list_hide.GetCount(); ++i)
+ {
+ column * col1 = &m_cols[m_list_hide.GetItemData(i)];
+ col1->phy_col = -1;
+ }
+
+ CDialog::OnOK();
+}
--- /dev/null
+/**
+ * @file DirColsDlg.h
+ *
+ * @brief Declaration file for CDirColsDlg
+ *
+ * @date Created: 2003-08-19
+ */
+// RCS ID line follows -- this is updated by CVS
+// $Id$
+
+
+#if !defined(AFX_DIRCOLSDLG_H__2FCB576C_C609_4623_8C55_F3870F22CA0B__INCLUDED_)
+#define AFX_DIRCOLSDLG_H__2FCB576C_C609_4623_8C55_F3870F22CA0B__INCLUDED_
+#pragma once
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CDirColsDlg dialog
+
+/**
+ * @brief Dialog to choose & order columns to be shown in dirview of differing files
+ */
+class CDirColsDlg : public CDialog
+{
+// Public types
+public:
+ struct column {
+ CString name;
+ int log_col;
+ int phy_col;
+ column() : log_col(-1), phy_col(-1) { } /**< default constructor for use in CArray */
+ column(LPCTSTR sz, int log, int phy) : name(sz), log_col(log), phy_col(phy) { }
+ };
+ typedef CArray<column, column> ColumnArray;
+
+// Construction
+public:
+ CDirColsDlg(CWnd* pParent = NULL); // standard constructor
+ void AddColumn(CString name, int log, int phy=-1)
+ { column c(name, log, phy); m_cols.Add(c); }
+ const ColumnArray & GetColumns() const { return m_cols; }
+
+// Dialog Data
+ //{{AFX_DATA(CDirColsDlg)
+ enum { IDD = IDD_DIRCOLS };
+ CListBox m_list_show;
+ CListBox m_list_hide;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CDirColsDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation methods
+protected:
+ void LoadLists();
+ void MoveItems(CListBox * list1, CListBox * list2, bool top);
+ void UpdateEnables();
+ void SortArrayToLogicalOrder();
+ static int cmpcols(const void * el1, const void * el2);
+
+// Implementation data
+private:
+ ColumnArray m_cols;
+
+ // Generated message map functions
+ //{{AFX_MSG(CDirColsDlg)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnUp();
+ afx_msg void OnDown();
+ afx_msg void OnAdd();
+ afx_msg void OnRemove();
+ virtual void OnOK();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_DIRCOLSDLG_H__2FCB576C_C609_4623_8C55_F3870F22CA0B__INCLUDED_)
--- /dev/null
+/**
+ * @file DirViewColHandler.cpp
+ *
+ * @brief Methods of CDirView dealing with the listview (of file results)
+ *
+ * @date Created: 2003-08-19
+ */
+// RCS ID line follows -- this is updated by CVS
+// $Id$
+
+
+#include "stdafx.h"
+#include "Merge.h"
+#include "DirView.h"
+#include "DirDoc.h"
+#include "MainFrm.h"
+#include "resource.h"
+#include "coretools.h"
+#include "dllver.h"
+#include "DirViewColItems.h"
+#include "DirColsDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+/**
+ * @brief Get text for specified column (forwards to specific column handler)
+ */
+static CString ColGet(int col, const DIFFITEM & di)
+{
+ return (*g_cols[col].getfnc)(di);
+}
+
+/**
+ * @brief Sort two items on specified column (forwards to specific column handler)
+ */
+static int ColSort(int col, const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return (*g_cols[col].sortfnc)(ldi, rdi);
+}
+
+/**
+ * @brief return whether column normally sorts ascending (dates do not)
+ */
+bool CDirView::IsDefaultSortAscending(int col) const
+{
+ return g_cols[col].defSortUp;
+}
+
+/// Assign column name, using string resource & current column ordering
+void CDirView::NameColumn(int id, int subitem)
+{
+ int phys = ColLogToPhys(subitem);
+ if (phys>=0)
+ {
+ CString s;
+ VERIFY(s.LoadString(id));
+ LV_COLUMN lvc;
+ lvc.mask = LVCF_TEXT;
+ lvc.pszText = (LPTSTR)((LPCTSTR)s);
+ m_pList->SetColumn(m_colorder[subitem], &lvc);
+ }
+}
+
+/// Load column names from string table
+void CDirView::UpdateColumnNames()
+{
+ for (int i=0; i<g_ncols; ++i)
+ {
+ const DirColInfo & col = g_cols[i];
+ NameColumn(col.idName, i);
+ }
+}
+
+/// Compare two specified rows during a sort operation (windows callback)
+int CALLBACK CDirView::CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ // initialize structures to obtain required information
+ CDirView* pView = reinterpret_cast<CDirView*>(lParamSort);
+ POSITION diffposl = pView->GetItemKeyFromData(lParam1);
+ POSITION diffposr = pView->GetItemKeyFromData(lParam2);
+ DIFFITEM ldi = pView->GetDiffContext()->GetDiffAt(diffposl);
+ DIFFITEM rdi = pView->GetDiffContext()->GetDiffAt(diffposr);
+
+ // compare 'left' and 'right' parameters as appropriate
+ int retVal = ColSort(pView->m_sortColumn, ldi, rdi);
+
+ // return compare result, considering sort direction
+ return (pView->m_bSortAscending)?retVal:-retVal;
+}
+
+// Add new item to list view
+int CDirView::AddNewItem(int i)
+{
+ LV_ITEM lvItem;
+ memset(&lvItem, 0, sizeof(lvItem));
+ lvItem.iItem = i;
+ return GetListCtrl().InsertItem(&lvItem);
+
+}
+
+// Set a subitem on an existing item
+void CDirView::SetSubitem(int item, int phy, LPCTSTR sz)
+{
+ LV_ITEM lvItem;
+ memset(&lvItem, 0, sizeof(lvItem));
+ lvItem.mask = LVIF_TEXT;
+ lvItem.iItem = item;
+ lvItem.iSubItem = phy;
+ lvItem.pszText = const_cast<LPTSTR>(sz);
+ GetListCtrl().SetItem(&lvItem);
+}
+
+
+// Add a new diff item to dir view
+int CDirView::AddDiffItem(int index, const DIFFITEM & di, LPCTSTR szPath, POSITION curdiffpos)
+{
+ int i = AddNewItem(index);
+ SetItemKey(i, curdiffpos);
+ SetImage(i, FILE_ERROR);
+ return i;
+}
+
+/**
+ * @brief Return image index appropriate for this row
+ */
+static int GetColImage(const DIFFITEM & di)
+{
+ switch (di.code)
+ {
+ case FILE_DIFF: return FILE_DIFF;
+ case FILE_BINDIFF: return FILE_BINDIFF;
+ case FILE_BINSAME: return FILE_BINSAME;
+ case FILE_LUNIQUE:
+ case FILE_LDIRUNIQUE:
+ return di.code;
+ case FILE_RUNIQUE:
+ case FILE_RDIRUNIQUE:
+ return di.code;
+ break;
+ case FILE_SAME: return FILE_SAME;
+ default: return FILE_ERROR;
+ }
+}
+
+// Update listview display of details for specified row
+void CDirView::UpdateDiffItemStatus(UINT nIdx, const DIFFITEM & di)
+{
+ for (int i=0; i<g_ncols; ++i)
+ {
+ const DirColInfo & col = g_cols[i];
+ int phy = ColLogToPhys(i);
+ if (phy>=0)
+ SetSubitem(nIdx, phy, ColGet(i, di));
+ }
+ SetImage(nIdx, GetColImage(di));
+}
+
+/// store current column orders into registry
+void CDirView::SaveColumnOrders()
+{
+ ASSERT(m_colorder.GetSize() == m_numcols);
+ ASSERT(m_invcolorder.GetSize() == m_numcols);
+ int cols = GetListCtrl().GetHeaderCtrl()->GetItemCount();
+ for (int i=0; i < m_numcols; i++)
+ {
+ CString RegName = GetColRegValueNameBase(i) + _T("_Order");
+ int ord = m_colorder[i];
+ theApp.WriteProfileInt(_T("DirView"), RegName, ord);
+ }
+}
+
+
+/**
+ * @brief Load column orders from registry
+ */
+void CDirView::LoadColumnOrders()
+{
+ ASSERT(m_numcols == -1);
+ m_numcols = GetColLogCount();
+ ClearColumnOrders();
+ m_dispcols = 0;
+
+ // Load column orders
+ // Break out if one is missing
+ // Break out & mark failure (m_dispcols == -1) if one is invalid
+ for (int i=0; i<m_numcols; ++i)
+ {
+ CString RegName = GetColRegValueNameBase(i) + _T("_Order");
+ int ord = theApp.GetProfileInt(_T("DirView"), RegName, -2);
+ if (ord<-1 || ord >= m_numcols)
+ break;
+ m_colorder[i] = ord;
+ if (ord>=0)
+ {
+ ++m_dispcols;
+ if (m_invcolorder[ord] != -1)
+ {
+ m_dispcols = -1;
+ break;
+ }
+ m_invcolorder[ord] = i;
+ }
+ }
+ // Check that a contiguous range was set
+ for (i=0; i<m_dispcols; ++i)
+ {
+ if (m_invcolorder[i] < 0)
+ {
+ m_dispcols = -1;
+ break;
+ }
+ }
+ // Must have at least one column
+ if (m_dispcols<=1)
+ {
+ ResetColumnOrdering();
+ }
+
+ ValidateColumnOrdering();
+}
+
+/**
+ * @brief Sanity check column ordering
+ */
+void CDirView::ValidateColumnOrdering()
+{
+TRACE(" <%s>\n", COleDateTime::GetCurrentTime().Format());
+for (int k=0; k<m_invcolorder.GetSize();++k)
+ TRACE("invcolorder[%d]=%d\n", k, m_invcolorder[k]);
+for (k=0; k<m_colorder.GetSize();++k)
+ TRACE("colorder[%d]=%d\n", k, m_colorder[k]);
+
+#if _DEBUG
+ ASSERT(m_invcolorder[0]>=0);
+ ASSERT(m_numcols == GetColLogCount());
+ // Check that any logical->physical mapping is reversible
+ for (int i=0; i<m_numcols; ++i)
+ {
+ int phy = m_colorder[i];
+ if (phy >= 0)
+ {
+ int log = m_invcolorder[phy];
+ ASSERT(i == log);
+ }
+ }
+ // Bail out if header doesn't exist yet
+ int hdrcnt = GetListCtrl().GetHeaderCtrl()->GetItemCount();
+ if (hdrcnt)
+ {
+ ASSERT(hdrcnt == m_dispcols);
+ }
+ return;
+ // Check that all physical columns map to logical columns
+ for (i=0; i<m_dispcols; ++i)
+ {
+ ASSERT(m_invcolorder[i]>=0);
+ }
+ // Check that no columns beyond end have physical mappings
+ for ( /* existing i */; i<m_numcols; ++i)
+ {
+ ASSERT(m_invcolorder[i]==-1);
+ }
+#endif
+}
+
+/**
+ * @brief Set column ordering to default initial order
+ */
+void CDirView::ResetColumnOrdering()
+{
+ ClearColumnOrders();
+ m_dispcols = 0;
+ for (int i=0; i<m_numcols; ++i)
+ {
+ int phy = GetColDefaultOrder(i);
+ m_colorder[i] = phy;
+ if (phy>=0)
+ {
+ m_invcolorder[phy] = i;
+ ++m_dispcols;
+ }
+ }
+ ValidateColumnOrdering();
+}
+
+/**
+ * @brief Reset all current column ordering information
+ */
+void CDirView::ClearColumnOrders()
+{
+ m_colorder.SetSize(m_numcols);
+ m_invcolorder.SetSize(m_numcols);
+ for (int i=0; i<m_numcols; ++i)
+ {
+ m_colorder[i] = -1;
+ m_invcolorder[i] = -1;
+ }
+}
+
+/**
+ * @brief Return display name of column
+ */
+CString CDirView::GetColDisplayName(int col) const
+{
+ const DirColInfo & colinfo = g_cols[col];
+ CString s;
+ s.LoadString(colinfo.idName);
+ return s;
+}
+
+/**
+ * @brief Return total number of known columns
+ */
+int CDirView::GetColLogCount() const
+{
+ return g_ncols;
+}
+
+/**
+ * @brief Remove any windows reordering of columns (params are physical columns)
+ */
+void CDirView::MoveColumn(int psrc, int pdest)
+{
+ // actually moved column
+ m_colorder[m_invcolorder[psrc]] = pdest;
+ // shift all other affected columns
+ int dir = psrc > pdest ? +1 : -1;
+ for (int i=pdest; i!=psrc; i += dir)
+ {
+ m_colorder[m_invcolorder[i]] = i+dir;
+ }
+ // fix inverse mapping
+ for (i=0; i<m_numcols; ++i)
+ {
+ if (m_colorder[i] >= 0)
+ m_invcolorder[m_colorder[i]] = i;
+ }
+ ValidateColumnOrdering();
+ InitiateSort();
+ ValidateColumnOrdering();
+}
+
+/**
+ * @brief User examines & edits which columns are displayed in dirview, and in which order
+ */
+void CDirView::OnEditColumns()
+{
+ToDoDeleteThisValidateColumnOrdering();
+ CDirColsDlg dlg;
+ // List all the currently displayed columns
+ for (int col=0; col<GetListCtrl().GetHeaderCtrl()->GetItemCount(); ++col)
+ {
+ int l = ColPhysToLog(col);
+ dlg.AddColumn(GetColDisplayName(l), l, col);
+ }
+ // Now add all the columns not currently displayed
+ for (int l=0; l<GetColLogCount(); ++l)
+ {
+ if (ColLogToPhys(l)==-1)
+ {
+ dlg.AddColumn(GetColDisplayName(l), l);
+ }
+ }
+ if (dlg.DoModal() != IDOK)
+ return;
+
+ // Reset our data to reflect the new data from the dialog
+ const CDirColsDlg::ColumnArray & cols = dlg.GetColumns();
+ ClearColumnOrders();
+ m_dispcols = 0;
+ for (int i=0; i<cols.GetSize(); ++i)
+ {
+ int log = cols[i].log_col;
+ int phy = cols[i].phy_col;
+ m_colorder[log] = phy;
+ if (phy>=0)
+ {
+ ++m_dispcols;
+ m_invcolorder[phy] = log;
+ }
+ }
+ if (m_dispcols < 1)
+ {
+ // Ignore them if they didn't leave a column showing
+ ResetColumnOrdering();
+ }
+ else
+ {
+ ReloadColumns();
+ GetDocument()->Redisplay();
+ }
+ ValidateColumnOrdering();
+}
--- /dev/null
+/**
+ * @file DirViewColItems.cpp
+ *
+ * @brief Code for individual columns in the DirView
+ *
+ * @date Created: 2003-08-19
+ */
+// RCS ID line follows -- this is updated by CVS
+// $Id$
+
+
+#include "stdafx.h"
+#include "Merge.h"
+#include "DirView.h"
+#include "DirDoc.h"
+#include "MainFrm.h"
+#include "resource.h"
+//#include "coretools.h"
+//#include "dllver.h"
+#include "DirViewColItems.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/**
+ * @brief Return time displayed appropriately, as string
+ */
+static CString
+TimeString(const time_t * tim)
+{
+ if (!tim) return _T("---");
+ // _tcsftime does not respect user date customizations from
+ // Regional Options/Configuration Regional; COleDateTime::Format does so.
+ COleDateTime odt = *tim;
+ return odt.Format();
+}
+
+/**
+ * @{ Functions to display each type of column info
+ */
+static CString ColNameGet(const DIFFITEM & di)
+{
+ return di.sfilename;
+}
+static CString ColPathGet(const DIFFITEM & di)
+{
+ CString s = _T(".");
+ s += di.sSubdir;
+ return s;
+}
+static CString ColStatusGet(const DIFFITEM & di)
+{
+ CString s;
+ switch (di.code)
+ {
+ case FILE_DIFF:
+ VERIFY(s.LoadString(IDS_FILES_ARE_DIFFERENT));
+ break;
+ case FILE_BINDIFF:
+ VERIFY(s.LoadString(IDS_BIN_FILES_DIFF));
+ break;
+ case FILE_BINSAME:
+ VERIFY(s.LoadString(IDS_BIN_FILES_SAME));
+ break;
+ case FILE_LUNIQUE:
+ case FILE_LDIRUNIQUE:
+ AfxFormatString1(s, IDS_ONLY_IN_FMT, di.getLeftFilepath());
+ break;
+ case FILE_RUNIQUE:
+ case FILE_RDIRUNIQUE:
+ AfxFormatString1(s, IDS_ONLY_IN_FMT, di.getRightFilepath());
+ break;
+ case FILE_SAME:
+ VERIFY(s.LoadString(IDS_IDENTICAL));
+ break;
+ default: // error
+ VERIFY(s.LoadString(IDS_CANT_COMPARE_FILES));
+ break;
+ }
+ return s;
+}
+static CString ColLmtimeGet(const DIFFITEM & di)
+{
+ if (di.left.mtime)
+ return TimeString(&di.left.mtime);
+ else
+ return _T("");
+}
+static CString ColRmtimeGet(const DIFFITEM & di)
+{
+ if (di.right.mtime)
+ return TimeString(&di.right.mtime);
+ else
+ return _T("");
+}
+static CString ColLctimeGet(const DIFFITEM & di)
+{
+ if (di.left.ctime)
+ return TimeString(&di.left.ctime);
+ else
+ return _T("");
+}
+static CString ColRctimeGet(const DIFFITEM & di)
+{
+ if (di.right.ctime)
+ return TimeString(&di.right.ctime);
+ else
+ return _T("");
+}
+static CString ColExtGet(const DIFFITEM & di)
+{
+ return di.sext;
+}
+static CString ColLsizeGet(const DIFFITEM & di)
+{
+ CString s;
+ s.Format(_T("%I64d"), di.left.size);
+ return s;
+}
+static CString ColRsizeGet(const DIFFITEM & di)
+{
+ CString s;
+ s.Format(_T("%I64d"), di.right.size);
+ return s;
+}
+static CString ColNewerGet(const DIFFITEM & di)
+{
+ if (di.left.mtime && di.right.mtime)
+ {
+ if (di.left.mtime > di.right.mtime)
+ return _T("<<<");
+ if (di.left.mtime < di.right.mtime)
+ return _T(">>>");
+ return _T("===");
+ }
+ else if (di.left.mtime)
+ {
+ return _T("<*<");
+ }
+ else if (di.right.mtime)
+ {
+ return _T(">*>");
+ }
+ else
+ {
+ return _T("***");
+ }
+}
+static CString ColLverGet(const DIFFITEM & di)
+{
+ return di.left.version;
+}
+static CString ColRverGet(const DIFFITEM & di)
+{
+ return di.right.version;
+}
+static CString ColStatusAbbrGet(const DIFFITEM & di)
+{
+ int id;
+ switch (di.code)
+ {
+ case FILE_DIFF: id = IDS_FILES_ARE_DIFFERENT; break;
+ case FILE_BINDIFF: id = IDS_BIN_FILES_DIFF; break;
+ case FILE_BINSAME: id = IDS_BIN_FILES_SAME; break;
+ case FILE_LUNIQUE:
+ case FILE_LDIRUNIQUE:
+ id = IDS_LEFTONLY; break;
+ case FILE_RUNIQUE:
+ case FILE_RDIRUNIQUE:
+ id = IDS_RIGHTONLY; break;
+ case FILE_SAME: id = IDS_IDENTICAL; break;
+ default: id = IDS_CANT_COMPARE_FILES;
+ }
+ CString s;
+ VERIFY(s.LoadString(id));
+ return s;
+}
+static CString ColLattrGet(const DIFFITEM & di)
+{
+ return di.left.flags.toString();
+}
+static CString ColRattrGet(const DIFFITEM & di)
+{
+ return di.right.flags.toString();
+}
+/**
+ * @}
+ */
+
+/**
+ * @{ Functions to sort each type of column info
+ */
+static int ColNameSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return ldi.sfilename.CompareNoCase(rdi.sfilename);
+}
+static int ColPathSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return ldi.sSubdir.CompareNoCase(rdi.sSubdir);
+}
+static int ColStatusSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return rdi.code-ldi.code;
+}
+static int ColLmtimeSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return rdi.left.mtime-ldi.left.mtime;
+}
+static int ColRmtimeSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return rdi.right.mtime-ldi.right.mtime;
+}
+static int ColLctimeSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return rdi.left.ctime-ldi.left.ctime;
+}
+static int ColRctimeSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return rdi.right.ctime-ldi.right.ctime;
+}
+static int ColExtSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return ldi.sext.CompareNoCase(rdi.sext);
+}
+static int ColLsizeSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return rdi.left.size - ldi.left.size;
+}
+static int ColRsizeSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return rdi.right.size - ldi.right.size;
+}
+static int ColNewerSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return ColNewerGet(ldi).Compare(ColNewerGet(rdi));
+}
+static int ColLverSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return ldi.left.version.Compare(rdi.left.version);
+}
+static int ColRverSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return ldi.right.version.Compare(rdi.right.version);
+}
+static int ColLattrSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return ldi.left.flags.toString().Compare(rdi.left.flags.toString());
+}
+static int ColRattrSort(const DIFFITEM & ldi, const DIFFITEM &rdi)
+{
+ return ldi.right.flags.toString().Compare(rdi.right.flags.toString());
+}
+/**
+ * @}
+ */
+
+/**
+ * @brief All existing columns
+ */
+DirColInfo g_cols[] =
+{
+ { _T("Name"), IDS_COLHDR_FILENAME, -1, &ColNameGet, &ColNameSort, 0, true }
+ , { _T("Path"), IDS_COLHDR_DIR, -1, &ColPathGet, &ColPathSort, 1, true }
+ , { _T("Status"), IDS_COLHDR_RESULT, -1, &ColStatusGet, &ColStatusSort, 2, true}
+ , { _T("Lmtime"), IDS_COLHDR_LTIMEM, -1, &ColLmtimeGet, &ColLmtimeSort, 3, false }
+ , { _T("Rmtime"), IDS_COLHDR_RTIMEM, -1, &ColRmtimeGet, &ColRmtimeSort, 4, false }
+ , { _T("Lctime"), IDS_COLHDR_LTIMEC, -1, &ColLctimeGet, &ColLctimeSort, -1, false }
+ , { _T("Rctime"), IDS_COLHDR_RTIMEC, -1, &ColRctimeGet, &ColRctimeSort, -1, false }
+ , { _T("Ext"), IDS_COLHDR_EXTENSION, -1, &ColExtGet, &ColExtSort, 5, true }
+ , { _T("Lsize"), IDS_COLHDR_LSIZE, -1, &ColLsizeGet, &ColLsizeSort, -1, true }
+ , { _T("Rsize"), IDS_COLHDR_RSIZE, -1, &ColRsizeGet, &ColRsizeSort, -1, true }
+ , { _T("Newer"), IDS_COLHDR_NEWER, -1, &ColNewerGet, &ColNewerSort, -1, true }
+ , { _T("Lversion"), IDS_COLHDR_LVERSION, -1, &ColLverGet, &ColLverSort, -1, true }
+ , { _T("Rversion"), IDS_COLHDR_RVERSION, -1, &ColRverGet, &ColRverSort, -1, true }
+ , { _T("StatusAbbr"), IDS_COLHDR_RESULT_ABBR, -1, &ColStatusAbbrGet, &ColStatusSort, -1, true }
+ , { _T("Lattr"), IDS_COLHDR_LATTRIBUTES, -1, &ColLattrGet, &ColLattrSort, -1, true }
+ , { _T("Rattr"), IDS_COLHDR_RATTRIBUTES, -1, &ColRattrGet, &ColRattrSort, -1, true }
+};
+
+/**
+ * @brief Count of all known columns
+ */
+int g_ncols = countof(g_cols);
+
+/**
+ * @brief Registry base value name for saving/loading info for this column
+ */
+CString CDirView::GetColRegValueNameBase(int col) const
+{
+ ASSERT(col>=0 && col<countof(g_cols));
+ CString regName;
+ regName.Format(_T("WDirHdr_%s"), g_cols[col].regName);
+ return regName;
+}
+
+/**
+ * @brief Get default physical order for specified logical column
+ */
+int CDirView::GetColDefaultOrder(int col) const
+{
+ ASSERT(col>=0 && col<countof(g_cols));
+ return g_cols[col].physicalIndex;
+}
--- /dev/null
+/**
+ * @file DirViewColItems.h
+ *
+ * @brief Declaration file for DirColInfo
+ *
+ * @date Created: 2003-08-19
+ */
+// RCS ID line follows -- this is updated by CVS
+// $Id$
+
+#ifndef DirViewColItems_h
+#define DirViewColItems_h
+
+
+typedef CString (*ColGetFnc)(const DIFFITEM & di);
+typedef int (*ColSortFnc)(const DIFFITEM & ldi, const DIFFITEM &rdi);
+
+/**
+ * @brief Information about one column of dirview list info
+ */
+struct DirColInfo
+{
+ LPCTSTR regName;
+ // localized string resources
+ int idName;
+ int idDesc;
+ ColGetFnc getfnc; /**< Handler giving display string */
+ ColSortFnc sortfnc; /**< Handler for sorting this column */
+ int physicalIndex; /**< Current physical index, -1 if not displayed */
+ bool defSortUp; /**< Does column start with ascending sort (most do) */
+};
+
+extern DirColInfo g_cols[];
+extern int g_ncols;
+
+
+#endif // DirViewColItems_h