{
/* Both exist and neither is a directory. */
int o_binary = always_text_flag ? O_BINARY : 0;
+ o_binary = O_BINARY; // Perry 2002-12-08 CTRL-Z screws things up in text mode
if (!ignore_eol_diff) o_binary = O_BINARY;
/* Open the files and record their descriptors. */
CDiffContext::CDiffContext(LPCTSTR pszLeft, LPCTSTR pszRight, CDiffContext& src)
{
+ // This is used somehow in recursive comparisons
+ // I think that it is only used during rescan to copy into temporaries
+ // which modify the original (because pointers are copied below)
+ // and then the temporary goes away
+ // so the temporary never exists while the user is interacting with the GUI
+
m_bRecurse=src.m_bRecurse;
m_strLeft = pszLeft;
m_strRight = pszRight;
di.ltime = ltime;
di.rtime = rtime;
di.code = code;
+ AddDiff(di);
+}
- // BSP - Capture the extension; from the end of the file name to the last '.'
+void CDiffContext::AddDiff(DIFFITEM di)
+{
+ // BSP - Capture the extension; from the end of the file name to the last '.'
int j = 0;
- TCHAR *pDest = _tcsrchr(pszFilename, _T('.') );
+ TCHAR *pDest = _tcsrchr(di.filename, _T('.') );
if(pDest) // handle no extensions case.
{
m_pList->AddTail(di);
if (m_piStatus)
- m_piStatus->rptFile(code);
+ m_piStatus->rptFile(di.code);
+}
+
+void CDiffContext::RemoveDiff(POSITION diffpos)
+{
+ m_pList->RemoveAt(diffpos);
}
void CDiffContext::SetRegExp(LPCTSTR pszExp)
m_strRegExp = pszExp;
m_rgx.RegComp( pszExp );
}
+
+void CDiffContext::RemoveAll()
+{
+ m_pList->RemoveAll();
+}
+
+POSITION CDiffContext::GetFirstDiffPosition()
+{
+ return m_pList->GetHeadPosition();
+}
+
+DIFFITEM CDiffContext::GetNextDiffPosition(POSITION & diffpos)
+{
+ return m_pList->GetNext(diffpos);
+}
+
+DIFFITEM CDiffContext::GetDiffAt(POSITION diffpos)
+{
+ return m_pList->GetAt(diffpos);
+}
+
+BYTE CDiffContext::GetDiffStatus(POSITION diffpos)
+{
+ return m_pList->GetAt(diffpos).code;
+}
+
+
+void CDiffContext::UpdateStatusCode(POSITION diffpos, BYTE status)
+{
+ DIFFITEM & di = m_pList->GetAt(diffpos);
+ di.code = status;
+}
+
class CDiffContext
{
public:
- void SetRegExp(LPCTSTR pszExp);
- void AddDiff(LPCTSTR pszFilename, LPCTSTR pszLeftDir, LPCTSTR pszRightDir, long ltime, long rtime, BYTE code);
CDiffContext(LPCTSTR pszLeft, LPCTSTR pszRight, IDiffStatus * piStatus);
CDiffContext(LPCTSTR pszLeft, LPCTSTR pszRight, CDiffContext& src);
virtual ~CDiffContext();
- CList<DIFFITEM,DIFFITEM> m_dirlist, *m_pList;
+ void SetRegExp(LPCTSTR pszExp);
+
+ // add & remove differences
+ void AddDiff(LPCTSTR pszFilename, LPCTSTR pszLeftDir, LPCTSTR pszRightDir, long ltime, long rtime, BYTE code);
+ void AddDiff(DIFFITEM di);
+ void RemoveDiff(POSITION diffpos);
+ void RemoveAll();
+
+ // to iterate over all differences on list
+ POSITION GetFirstDiffPosition();
+ DIFFITEM GetNextDiffPosition(POSITION & diffpos);
+ DIFFITEM GetDiffAt(POSITION diffpos);
+ BYTE GetDiffStatus(POSITION diffpos);
+
+ // change an existing difference
+ void UpdateStatusCode(POSITION diffpos, BYTE status);
+ void ClearStatus() { m_piStatus=0; }
+
+
BOOL m_bRecurse;
CString m_strLeft;
CString m_strRight;
struct dirdata ddLeft, ddRight;
char *pNamesLeft;
char *pNamesRight;
+
+private:
+ CList<DIFFITEM,DIFFITEM> m_dirlist, *m_pList; // master list of differences
};
#endif // !defined(AFX_DIFFCONTEXT_H__D3CC86BE_F11E_11D2_826C_00A024706EDC__INCLUDED_)
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// see Merge.cpp for license (GPLv2+) statement
+//
+/////////////////////////////////////////////////////////////////////////////
+// DirActions.cpp : implementation file
+// It would be nice to make this independent of the UI (CDirView)
+// but it needs access to the list of selected items.
+// One idea would be to provide an iterator over them.
+//
+
+#include "stdafx.h"
+#include "Merge.h"
+#include "DirView.h"
+#include "DirDoc.h"
+#include "MainFrm.h"
+#include "coretools.h"
+#include "OutputDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+// Prompt user to confirm a multiple item copy
+static BOOL ConfirmMultipleCopy(int count, int total)
+{
+ CString s;
+ ASSERT(count>1);
+ AfxFormatString2(s, IDS_CONFIRM_COPY2DIR, NumToStr(count), NumToStr(total));
+ int rtn = AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION);
+ return (rtn==IDYES);
+}
+
+// Prompt user to confirm a single item copy
+static BOOL ConfirmSingleCopy(LPCTSTR src, LPCTSTR dest)
+{
+ CString s;
+ AfxFormatString2(s, IDS_CONFIRM_COPY_SINGLE, src, dest);
+ int rtn = AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION);
+ return (rtn==IDYES);
+}
+
+// Prompt user to confirm a multiple item delete
+static BOOL ConfirmMultipleDelete(int count, int total)
+{
+ CString s;
+ AfxFormatString2(s, IDS_CONFIRM_DELETE_ITEMS, NumToStr(count), NumToStr(total));
+ int rtn = AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION);
+ return (rtn==IDYES);
+}
+
+// Prompt user to confirm a single item delete
+static BOOL ConfirmSingleDelete(LPCTSTR filepath)
+{
+ CString s;
+ AfxFormatString1(s, IDS_CONFIRM_DELETE_SINGLE, filepath);
+ int rtn = AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION);
+ return (rtn==IDYES);
+}
+
+static BOOL
+IsItemCodeDir(int code)
+{
+ return code==FILE_LDIRUNIQUE || code==FILE_RDIRUNIQUE;
+}
+
+// Prompt & copy item from right to left, if legal
+void CDirView::DoCopyFileToLeft()
+{
+ ActionList actionList(ACT_COPY);
+ int sel=-1;
+ CString slFile, srFile;
+ while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
+ {
+ const DIFFITEM& di = GetDiffItem(sel);
+ if (IsItemCopyableToLeft(di.code))
+ {
+ GetItemFileNames(sel, slFile, srFile);
+ action act;
+ act.src = srFile;
+ act.dest = slFile;
+ act.idx = sel;
+ act.dirflag = IsItemCodeDir(di.code);
+ actionList.actions.AddTail(act);
+ }
+ ++actionList.selcount;
+ }
+
+ ConfirmAndPerformActions(actionList);
+}
+// Prompt & copy item from left to right, if legal
+void CDirView::DoCopyFileToRight()
+{
+ ActionList actionList(ACT_COPY);
+ int sel=-1;
+ CString slFile, srFile;
+ while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
+ {
+ const DIFFITEM& di = GetDiffItem(sel);
+ if (IsItemCopyableToRight(di.code))
+ {
+ GetItemFileNames(sel, slFile, srFile);
+ action act;
+ act.src = slFile;
+ act.dest = srFile;
+ act.dirflag = IsItemCodeDir(di.code);
+ act.idx = sel;
+ actionList.actions.AddTail(act);
+ }
+ ++actionList.selcount;
+ }
+
+ ConfirmAndPerformActions(actionList);
+}
+
+// Prompt & delete left, if legal
+void CDirView::DoDelLeft()
+{
+ ActionList actionList(ACT_DEL_LEFT);
+ int sel=-1;
+ CString slFile, srFile;
+ while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
+ {
+ const DIFFITEM& di = GetDiffItem(sel);
+ if (IsItemDeletableOnLeft(di.code))
+ {
+ GetItemFileNames(sel, slFile, srFile);
+ action act;
+ act.src = slFile;
+ act.dirflag = IsItemCodeDir(di.code);
+ act.idx = sel;
+ actionList.actions.AddTail(act);
+ }
+ ++actionList.selcount;
+ }
+
+ ConfirmAndPerformActions(actionList);
+}
+// Prompt & delete right, if legal
+void CDirView::DoDelRight()
+{
+ ActionList actionList(ACT_DEL_RIGHT);
+ int sel=-1;
+ CString slFile, srFile;
+ while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
+ {
+ const DIFFITEM& di = GetDiffItem(sel);
+
+ if (IsItemDeletableOnRight(di.code))
+ {
+ GetItemFileNames(sel, slFile, srFile);
+ action act;
+ act.src = srFile;
+ act.dirflag = IsItemCodeDir(di.code);
+ act.idx = sel;
+ actionList.actions.AddTail(act);
+ }
+ ++actionList.selcount;
+ }
+
+ ConfirmAndPerformActions(actionList);
+}
+// Prompt & delete both, if legal
+void CDirView::DoDelBoth()
+{
+ ActionList actionList(ACT_DEL_BOTH);
+ int sel=-1;
+ CString slFile, srFile;
+ while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
+ {
+ const DIFFITEM& di = GetDiffItem(sel);
+
+ if (IsItemDeletableOnBoth(di.code))
+ {
+ GetItemFileNames(sel, slFile, srFile);
+ action act;
+ act.src = srFile;
+ act.dest = slFile;
+ act.dirflag = IsItemCodeDir(di.code);
+ act.idx = sel;
+ actionList.actions.AddTail(act);
+ }
+ ++actionList.selcount;
+ }
+
+ ConfirmAndPerformActions(actionList);
+}
+
+// Confirm with user, then perform the action list
+void CDirView::ConfirmAndPerformActions(ActionList & actionList)
+{
+ if (!actionList.selcount) // Not sure it is possible to get right-click menu without
+ return; // any selected items, but may as well be safe
+
+ ASSERT(actionList.actions.GetCount()>0); // Or else the update handler got it wrong
+
+ if (!ConfirmActionList(actionList))
+ return;
+
+ PerformActionList(actionList);
+}
+
+// Confirm actions with user as appropriate (type, whether single or multiple)
+BOOL CDirView::ConfirmActionList(const ActionList & actionList)
+{
+ // special handling for the single item case, because it is probably the most common,
+ // and we can give the user exact details easily for it
+ switch(actionList.atype)
+ {
+ case ACT_COPY:
+ if (actionList.GetCount()==1)
+ {
+ action & act = actionList.actions.GetHead();
+ if (!ConfirmSingleCopy(act.src, act.dest))
+ return FALSE;
+ }
+ else
+ {
+ if (!ConfirmMultipleCopy(actionList.GetCount(), actionList.selcount))
+ return FALSE;
+ }
+ break;
+ default: // deletes
+ if (actionList.GetCount()==1 && actionList.atype!=ACT_DEL_BOTH)
+ {
+ action & act = actionList.actions.GetHead();
+ if (!ConfirmSingleDelete(act.src))
+ return FALSE;
+ }
+ else
+ {
+ if (!ConfirmMultipleDelete(actionList.GetCount(), actionList.selcount))
+ return FALSE;
+ }
+ break;
+ }
+ return TRUE;
+}
+
+// Perform an array of actions
+void CDirView::PerformActionList(ActionList & actionList)
+{
+ while (actionList.GetCount()>0)
+ {
+ PerformAndRemoveTopAction(actionList);
+ }
+
+ // must process deleted items in reverse order
+ // ie, work our way *up* the display list
+ // so we don't invalidate indices of items not done yet
+ while (!actionList.deletedItems.IsEmpty())
+ {
+ int idx = actionList.deletedItems.RemoveTail();
+ POSITION diffpos = GetItemKey(idx);
+ GetDiffContext()->RemoveDiff(diffpos);
+ m_pList->DeleteItem(idx);
+ }
+
+ if (!actionList.errors.IsEmpty())
+ {
+ CString sTitle, sText;
+ AfxFormatString1(sTitle, IDS_ERRORS_TITLE, NumToStr(actionList.errors.GetCount()));
+ while (!actionList.errors.IsEmpty())
+ {
+ sText += actionList.errors.RemoveHead() + _T("\r\n\r\n");
+ }
+ OutputBox(sTitle, sText);
+ }
+}
+
+static void NormalizeFilepath(CString * pstr)
+{
+ pstr->Replace('/', '\\');
+}
+
+void CDirView::PerformAndRemoveTopAction(ActionList & actionList)
+{
+ action act = actionList.actions.RemoveHead();
+ if (actionList.atype == ACT_COPY)
+ {
+ // copy
+ if (act.dirflag)
+ {
+ // TODO: copy directory
+ // add new entries to an append list to be added to list at end
+ }
+ else
+ {
+ CString s;
+ // copy single file, and update status immediately
+ if (mf->SyncFiles(act.src, act.dest, &s))
+ {
+ mf->UpdateCurrentFileStatus(FILE_SAME, act.idx);
+ }
+ else
+ {
+ actionList.errors.AddTail(s);
+ }
+ }
+ }
+ else
+ {
+ // delete
+ if (act.dirflag)
+ {
+ // delete directory
+ CString s;
+ if (DeleteDirSilently(act.src, &s))
+ {
+ ASSERT(actionList.atype != ACT_DEL_BOTH); // directories are all unique
+ actionList.deletedItems.AddTail(act.idx);
+ }
+ else
+ {
+ actionList.errors.AddTail(s);
+ }
+ }
+ else
+ {
+ // delete file
+ CString s;
+ if (actionList.atype==ACT_DEL_LEFT || actionList.atype==ACT_DEL_BOTH)
+ {
+ CString sFile = act.src;
+ if (DeleteFileSilently(sFile, &s))
+ {
+ // figure out if copy on right
+ POSITION diffpos = GetItemKey(act.idx);
+ BYTE code = GetDiffContext()->GetDiffStatus(diffpos);
+ if (IsItemLeftOnly(code))
+ actionList.deletedItems.AddTail(act.idx);
+ else
+ mf->UpdateCurrentFileStatus(FILE_RUNIQUE, act.idx);
+ }
+ else
+ {
+ actionList.errors.AddTail(s);
+ }
+ }
+ s=_T("");
+ if (actionList.atype==ACT_DEL_RIGHT || actionList.atype==ACT_DEL_BOTH)
+ {
+ CString sFile = act.dest.IsEmpty() ? act.src : act.dest;
+ if (DeleteFileSilently(sFile, &s))
+ {
+ // figure out if copy on right
+ POSITION diffpos = GetItemKey(act.idx);
+ BYTE code = GetDiffContext()->GetDiffStatus(diffpos);
+ if (IsItemRightOnly(code))
+ actionList.deletedItems.AddTail(act.idx);
+ else
+ mf->UpdateCurrentFileStatus(FILE_LUNIQUE, act.idx);
+ }
+ else
+ {
+ actionList.errors.AddTail(s);
+ }
+ }
+ }
+ }
+}
+
+// Get directories of first selected item
+BOOL CDirView::GetSelectedDirNames(CString& strLeft, CString& strRight) const
+{
+ BOOL bResult = GetSelectedFileNames(strLeft, strRight);
+
+ if (bResult)
+ {
+ TCHAR path[MAX_PATH];
+ split_filename(strLeft, path, NULL, NULL);
+ strLeft = path;
+
+ split_filename(strRight, path, NULL, NULL);
+ strRight = path;
+ }
+ return bResult;
+}
+
+// Does item exist only on the left ?
+BOOL CDirView::IsItemLeftOnly(int code)
+{
+ return code==FILE_LUNIQUE || code==FILE_LDIRUNIQUE;
+}
+// Does item exist only on the right ?
+BOOL CDirView::IsItemRightOnly(int code)
+{
+ return code==FILE_RUNIQUE || code==FILE_RDIRUNIQUE;
+}
+
+// is it possible to copy item to left ?
+BOOL CDirView::IsItemCopyableToLeft(int code)
+{
+ switch(code)
+ {
+ case FILE_RUNIQUE:
+ case FILE_DIFF:
+ case FILE_BINDIFF:
+ return TRUE;
+ // no point in allowing FILE_SAME
+ // TODO: FILE_RDIRUNIQUE: add code for directory copy
+ }
+ return FALSE;
+}
+// is it possible to copy item to right ?
+BOOL CDirView::IsItemCopyableToRight(int code)
+{
+ switch(code)
+ {
+ case FILE_LUNIQUE:
+ case FILE_DIFF:
+ case FILE_BINDIFF:
+ return TRUE;
+ // no point in allowing FILE_SAME
+ // TODO: FILE_LDIRUNIQUE: add code for directory copy
+ }
+ return FALSE;
+}
+// is it possible to delete left item ?
+BOOL CDirView::IsItemDeletableOnLeft(int code)
+{
+ switch(code)
+ {
+ case FILE_LUNIQUE:
+ case FILE_DIFF:
+ case FILE_BINDIFF:
+ case FILE_SAME:
+ case FILE_LDIRUNIQUE:
+ return TRUE;
+ }
+ return FALSE;
+}
+// is it possible to delete right item ?
+BOOL CDirView::IsItemDeletableOnRight(int code)
+{
+ switch(code)
+ {
+ case FILE_RUNIQUE:
+ case FILE_DIFF:
+ case FILE_BINDIFF:
+ case FILE_SAME:
+ case FILE_RDIRUNIQUE:
+ return TRUE;
+ }
+ return FALSE;
+}
+// is it possible to delete both items ?
+BOOL CDirView::IsItemDeletableOnBoth(int code)
+{
+ switch(code)
+ {
+ case FILE_DIFF:
+ case FILE_BINDIFF:
+ case FILE_SAME:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// is it possible to open left item ?
+BOOL CDirView::IsItemOpenableOnLeft(int code)
+{
+ switch(code)
+ {
+ case FILE_LUNIQUE:
+ case FILE_DIFF:
+ case FILE_BINDIFF:
+ case FILE_SAME:
+ return TRUE;
+ }
+ return FALSE;
+}
+// is it possible to open right item ?
+BOOL CDirView::IsItemOpenableOnRight(int code)
+{
+ switch(code)
+ {
+ case FILE_RUNIQUE:
+ case FILE_DIFF:
+ case FILE_BINDIFF:
+ case FILE_SAME:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// get the file names on both sides for first selected item
+BOOL CDirView::GetSelectedFileNames(CString& strLeft, CString& strRight) const
+{
+ int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
+ if (sel == -1)
+ return FALSE;
+ GetItemFileNames(sel, strLeft, strRight);
+ return TRUE;
+}
+// get file name on specified side for first selected item
+CString CDirView::GetSelectedFileName(SIDE_TYPE stype) const
+{
+ CString left, right;
+ if (!GetSelectedFileNames(left, right)) return _T("");
+ return stype==SIDE_LEFT ? left : right;
+}
+
+// get the file names on both sides for specified item
+void CDirView::GetItemFileNames(int sel, CString& strLeft, CString& strRight) const
+{
+ const CDirDoc *pd = GetDocument();
+ CString name, pathex;
+ name = m_pList->GetItemText(sel, DV_NAME);
+ pathex = m_pList->GetItemText(sel, DV_PATH);
+ if (pathex.Left(2) == _T(".\\") || pathex.Left(2) == _T("./"))
+ {
+ strLeft.Format(_T("%s\\%s\\%s"), pd->m_pCtxt->m_strLeft, pathex.Right(pathex.GetLength()-2), name);
+ strRight.Format(_T("%s\\%s\\%s"), pd->m_pCtxt->m_strRight, pathex.Right(pathex.GetLength()-2), name);
+ }
+ else
+ {
+ strLeft.Format(_T("%s\\%s"), pd->m_pCtxt->m_strLeft, name);
+ strRight.Format(_T("%s\\%s"), pd->m_pCtxt->m_strRight, name);
+ }
+}
+
+// Open selected file on specified side
+void CDirView::DoOpen(SIDE_TYPE stype)
+{
+ int sel = GetSingleSelectedItem();
+ if (sel == -1) return;
+ CString file = GetSelectedFileName(stype);
+ if (file.IsEmpty()) return;
+ int rtn = (int)ShellExecute(::GetDesktopWindow(), _T("open"), file, 0, 0, SW_SHOWNORMAL);
+ if (rtn==SE_ERR_NOASSOC)
+ DoOpenWith(stype);
+
+}
+
+// Open with dialog for file on selected side
+void CDirView::DoOpenWith(SIDE_TYPE stype)
+{
+ int sel = GetSingleSelectedItem();
+ if (sel == -1) return;
+ CString file = GetSelectedFileName(stype);
+ if (file.IsEmpty()) return;
+ CString sysdir;
+ if (!GetSystemDirectory(sysdir.GetBuffer(MAX_PATH), MAX_PATH)) return;
+ sysdir.ReleaseBuffer();
+ CString arg = (CString)_T("shell32.dll,OpenAs_RunDLL ") + file;
+ ShellExecute(::GetDesktopWindow(), 0, _T("RUNDLL32.EXE"), arg, sysdir, SW_SHOWNORMAL);
+}
if (gWriteLog) gLog.Write(_T("Starting directory scan:\r\n\tLeft: %s\r\n\tRight: %s\r\n"),
m_pCtxt->m_strLeft, m_pCtxt->m_strRight);
- m_pCtxt->m_dirlist.RemoveAll();
+ m_pCtxt->RemoveAll();
compare_files (0, (char const *)(LPCTSTR)m_pCtxt->m_strLeft,
0, (char const *)(LPCTSTR)m_pCtxt->m_strRight, m_pCtxt, 0);
CString s,s2;
UINT cnt=0;
- LPCTSTR p=NULL;
int llen = m_pCtxt->m_strLeft.GetLength();
int rlen = m_pCtxt->m_strRight.GetLength();
- m_pView->m_pList->DeleteAllItems();
- POSITION pos = m_pCtxt->m_dirlist.GetHeadPosition(), curpos;
- while (pos != NULL)
+ m_pView->DeleteAllDisplayItems();
+
+ POSITION diffpos = m_pCtxt->GetFirstDiffPosition();
+ while (diffpos)
{
- curpos = pos;
- DIFFITEM di = m_pCtxt->m_dirlist.GetNext(pos);
+ POSITION curdiffpos = diffpos;
+ DIFFITEM di = m_pCtxt->GetNextDiffPosition(diffpos);
+
+ LPCTSTR p=NULL;
+
BOOL leftside = (di.code==FILE_LUNIQUE || di.code==FILE_LDIRUNIQUE);
BOOL rightside = (di.code==FILE_RUNIQUE || di.code==FILE_RDIRUNIQUE);
switch (di.code)
if (mf->m_bShowDiff
&& (!mf->m_bHideBak || !FileExtMatches(di.filename,BACKUP_FILE_EXT)))
{
- m_pView->AddItem(cnt, DV_NAME, di.filename);
- m_pView->AddItem(cnt, DV_EXT, di.extension); // BSP - Add the current file extension
-
p = _tcsninc(di.lpath, llen);
- s = _T(".");
- s += p;
- m_pView->AddItem(cnt, DV_PATH, s);
-
- m_pView->m_pList->SetItemData(cnt, (DWORD)curpos);
- UpdateItemStatus(cnt);
- cnt++;
}
break;
case FILE_BINDIFF:
if (mf->m_bShowDiff
&& (!mf->m_bHideBak || !FileExtMatches(di.filename,BACKUP_FILE_EXT)))
{
- m_pView->AddItem(cnt, DV_NAME, di.filename);
- m_pView->AddItem(cnt, DV_EXT, di.extension); // BSP - Add the current file extension
p = _tcsninc(di.lpath, llen);
- s = _T(".");
- s += p;
- m_pView->AddItem(cnt, DV_PATH, s);
- m_pView->m_pList->SetItemData(cnt, (DWORD)curpos);
- UpdateItemStatus(cnt);
- cnt++;
}
break;
case FILE_LUNIQUE:
if (((mf->m_bShowUniqueLeft && leftside) || (mf->m_bShowUniqueRight && rightside))
&& (!mf->m_bHideBak || !FileExtMatches(di.filename,BACKUP_FILE_EXT)))
{
- m_pView->AddItem(cnt, DV_NAME, di.filename);
- m_pView->AddItem(cnt, DV_EXT, di.extension); // BSP - Add the current file extension
-
if (di.code==FILE_LUNIQUE || di.code==FILE_LDIRUNIQUE)
p = _tcsninc(di.lpath, llen);
else
p = _tcsninc(di.rpath, rlen);
- s2 = _T(".");
- s2 += p;
- m_pView->AddItem(cnt, DV_PATH, s2);
- m_pView->m_pList->SetItemData(cnt, (DWORD)curpos);
- UpdateItemStatus(cnt);
- cnt++;
}
break;
case FILE_SAME:
if (mf->m_bShowIdent
&& (!mf->m_bHideBak || !FileExtMatches(di.filename,BACKUP_FILE_EXT)))
{
- m_pView->AddItem(cnt, DV_NAME, di.filename);
- m_pView->AddItem(cnt, DV_EXT, di.extension); // BSP - Add the current file extension
p = _tcsninc(di.lpath, llen);
- s = _T(".");
- s += p;
- m_pView->AddItem(cnt, DV_PATH, s);
- m_pView->m_pList->SetItemData(cnt, (DWORD)curpos);
- UpdateItemStatus(cnt);
- cnt++;
}
break;
default: // error
+ p = _tcsninc(di.lpath, llen);
+ break;
+ }
+ if (p)
+ {
m_pView->AddItem(cnt, DV_NAME, di.filename);
m_pView->AddItem(cnt, DV_EXT, di.extension); // BSP - Add the current file extension
- p = _tcsninc(di.lpath, llen);
s = _T(".");
s += p;
m_pView->AddItem(cnt, DV_PATH, s);
- m_pView->m_pList->SetItemData(cnt, (DWORD)curpos);
+ m_pView->SetItemKey(cnt, curdiffpos);
+ // This is inefficient, as we have the di in hand right now
+ // But to improve this, have to figure out the intricacies of UpdateItemStatus
UpdateItemStatus(cnt);
cnt++;
- break;
}
}
return (CDirView*)GetNextView(ps2);
}
+static long GetModTime(LPCTSTR szPath)
+{
+ struct stat mystats;
+ bzero(&mystats, sizeof(mystats));
+ int stat_result = stat(szPath, &mystats);
+ if (stat_result!=0)
+ return 0;
+ return mystats.st_mtime;
+}
+
+static void UpdateTimes(DIFFITEM * pdi)
+{
+ CString sLeft = (CString)pdi->lpath + _T("\\") + pdi->filename;
+ pdi->ltime = GetModTime(sLeft);
+
+ CString sRight = (CString)pdi->rpath + _T("\\") + pdi->filename;
+ pdi->rtime = GetModTime(sRight);
+}
+
void CDirDoc::UpdateItemStatus(UINT nIdx)
{
CString s,s2;
UINT cnt=0;
int llen = m_pCtxt->m_strLeft.GetLength();
int rlen = m_pCtxt->m_strRight.GetLength();
- POSITION pos = (POSITION)m_pView->m_pList->GetItemData(nIdx);
- DIFFITEM di = m_pCtxt->m_dirlist.GetAt(pos);
+ POSITION diffpos = m_pView->GetItemKey(nIdx);
+ DIFFITEM di = m_pCtxt->GetDiffAt(diffpos);
TCHAR sTime[80];
+
+ UpdateTimes(&di); // in case just copied (into existence) or modified
+
switch (di.code)
{
case FILE_DIFF:
ON_UPDATE_COMMAND_UI(ID_DIR_DEL_LEFT, OnUpdateCtxtDirDelLeft)
ON_COMMAND(ID_DIR_DEL_RIGHT, OnCtxtDirDelRight)
ON_UPDATE_COMMAND_UI(ID_DIR_DEL_RIGHT, OnUpdateCtxtDirDelRight)
+ ON_COMMAND(ID_DIR_DEL_BOTH, OnCtxtDirDelBoth)
+ ON_UPDATE_COMMAND_UI(ID_DIR_DEL_BOTH, OnUpdateCtxtDirDelBoth)
+ ON_COMMAND(ID_DIR_OPEN_LEFT, OnCtxtDirOpenLeft)
+ ON_UPDATE_COMMAND_UI(ID_DIR_OPEN_LEFT, OnUpdateCtxtDirOpenLeft)
+ ON_COMMAND(ID_DIR_OPEN_LEFT_WITH, OnCtxtDirOpenLeftWith)
+ ON_UPDATE_COMMAND_UI(ID_DIR_OPEN_LEFT_WITH, OnUpdateCtxtDirOpenLeftWith)
+ ON_COMMAND(ID_DIR_OPEN_RIGHT, OnCtxtDirOpenRight)
+ ON_UPDATE_COMMAND_UI(ID_DIR_OPEN_RIGHT, OnUpdateCtxtDirOpenRight)
+ ON_COMMAND(ID_DIR_OPEN_RIGHT_WITH, OnCtxtDirOpenRightWith)
+ ON_UPDATE_COMMAND_UI(ID_DIR_OPEN_RIGHT_WITH, OnUpdateCtxtDirOpenRightWith)
ON_WM_DESTROY()
ON_WM_CHAR()
//}}AFX_MSG_MAP
}
#endif //_DEBUG
+CDiffContext * CDirView::GetDiffContext()
+{
+ return GetDocument()->m_pCtxt;
+}
+
/////////////////////////////////////////////////////////////////////////////
// CDirView message handlers
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
- CWnd* pWndPopupOwner = this;
// set the menu items with the proper directory names
CString s, sl, sr;
GetSelectedDirNames(sl, sr);
-
- ModifyPopup(pPopup, IDS_COPY2DIR_LEFT_FMT, ID_DIR_COPY_FILE_TO_LEFT, sl);
- ModifyPopup(pPopup, IDS_COPY2DIR_RIGHT_FMT, ID_DIR_COPY_FILE_TO_RIGHT, sr);
- ModifyPopup(pPopup, IDS_DEL_LEFT_FMT, ID_DIR_DEL_LEFT, sl);
- ModifyPopup(pPopup, IDS_DEL_RIGHT_FMT, ID_DIR_DEL_RIGHT, sr);
- //
-
+ // find non-child ancestor to use as menu parent
+ CWnd* pWndPopupOwner = this;
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
+ // TODO: It would be more efficient to set
+ // all the popup items now with one traverse over selected items
+ // instead of using updates, in which we make a traverse for every item
+ // Perry, 2002-12-04
+ //
+
+
// invoke context menu
// this will invoke all the OnUpdate methods to enable/disable the individual items
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
}
}
+// Make a string out of a number
+// TODO: Ought to introduce commas every three digits, except this is locale-specific
+// How to do this with locale sensitivity ?
+CString
+NumToStr(int n)
+{
+ CString s;
+ s.Format(_T("%d"), n);
+ return s;
+}
+
// Change menu item by using string resource
// (Question: Why don't we just remove it from the menu resource entirely & do an Add here ?)
void CDirView::ModifyPopup(CMenu * pPopup, int nStringResource, int nMenuId, LPCTSTR szPath)
pPopup->ModifyMenu(nMenuId, MF_BYCOMMAND|MF_STRING, nMenuId, s);
}
-// given index in list control, get position & DIFFITEM reference to its data
-const DIFFITEM& CDirView::GetDiffItem(int sel, POSITION & pos)
-{
- pos = reinterpret_cast<POSITION>(m_pList->GetItemData(sel));
- const DIFFITEM& di = GetDocument()->m_pCtxt->m_dirlist.GetAt(pos);
- return di;
-}
// User chose (main menu) Copy from right to left
void CDirView::OnDirCopyFileToLeft()
DoCopyFileToRight();
}
-// Prompt & copy item from right to left, if legal
-void CDirView::DoCopyFileToLeft()
-{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel == -1) return;
-
- CString sl, sr, slFile, srFile;
- if (!GetSelectedDirNames(sl, sr) || !GetSelectedFileNames(slFile, srFile))
- return;
-
- CDirDoc *pd = GetDocument();
- CString s;
- // find item from document
- POSITION pos;
- const DIFFITEM& di = GetDiffItem(sel, pos);
- // what we do depends on comparison result for this item
- switch(di.code)
- {
- case FILE_LUNIQUE:
- break;
- case FILE_RUNIQUE:
- case FILE_DIFF:
- case FILE_BINDIFF:
- AfxFormatString1(s, IDS_CONFIRM_COPY2DIR, sl);
- if (AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION)==IDYES)
- {
- if (mf->SyncFiles(srFile, slFile))
- {
- mf->UpdateCurrentFileStatus(FILE_SAME);
- }
- }
- break;
- case FILE_LDIRUNIQUE:
- case FILE_RDIRUNIQUE:
- // TODO: Would be nice to allow copying directory
- // but must write code for recursive copy
- // and worse, this will make the item display invalid (new items not on it)
- // Perry 2002-11-26
- case FILE_SAME:
- default:
- // Not allowed, and should have been disabled choices anyway
- break;
- }
-}
-// Prompt & copy item from left to right, if legal
-void CDirView::DoCopyFileToRight()
-{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel == -1) return;
-
- CString sl, sr, slFile, srFile;
- if (!GetSelectedDirNames(sl, sr) || !GetSelectedFileNames(slFile, srFile))
- return;
-
- CDirDoc *pd = GetDocument();
- CString s;
- // find item from document
- POSITION pos;
- const DIFFITEM& di = GetDiffItem(sel, pos);
- // what we do depends on comparison result for this item
- switch(di.code)
- {
- case FILE_RUNIQUE:
- break;
- case FILE_LUNIQUE:
- case FILE_DIFF:
- case FILE_BINDIFF:
- AfxFormatString1(s, IDS_CONFIRM_COPY2DIR, sr);
- if (AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION)==IDYES)
- {
- CString left, right;
- if (mf->SyncFiles(slFile, srFile))
- {
- mf->UpdateCurrentFileStatus(FILE_SAME);
- }
- }
- break;
- case FILE_LDIRUNIQUE:
- case FILE_RDIRUNIQUE:
- // see comments in DoCopyFileToLeft
- case FILE_SAME:
- default:
- // Not allowed, and should have been disabled choices anyway
- break;
- }
-}
-
// Update context menu Copy Right to Left item
void CDirView::OnUpdateCtxtDirCopyFileToLeft(CCmdUI* pCmdUI)
{
- DoUpdateDirCopyFileToLeft(pCmdUI);
+ DoUpdateDirCopyFileToLeft(pCmdUI, eContext);
}
// Update context menu Copy Left to Right item
void CDirView::OnUpdateCtxtDirCopyFileToRight(CCmdUI* pCmdUI)
{
- DoUpdateDirCopyFileToRight(pCmdUI);
+ DoUpdateDirCopyFileToRight(pCmdUI, eContext);
}
// Update main menu Copy Right to Left item
void CDirView::OnUpdateDirCopyFileToLeft(CCmdUI* pCmdUI)
{
- DoUpdateDirCopyFileToLeft(pCmdUI);
+ DoUpdateDirCopyFileToLeft(pCmdUI, eMain);
}
// Update main menu Copy Left to Right item
void CDirView::OnUpdateDirCopyFileToRight(CCmdUI* pCmdUI)
{
- DoUpdateDirCopyFileToRight(pCmdUI);
+ DoUpdateDirCopyFileToRight(pCmdUI, eMain);
}
// Should Copy to Left be enabled or disabled ? (both main menu & context menu use this)
-void CDirView::DoUpdateDirCopyFileToLeft(CCmdUI* pCmdUI)
+void CDirView::DoUpdateDirCopyFileToLeft(CCmdUI* pCmdUI, eMenuType menuType)
{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel == -1)
+ int sel=-1;
+ int legalcount=0, selcount=0;
+ while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
{
- // no item there
- pCmdUI->Enable(FALSE);
- return;
+ const DIFFITEM& di = GetDiffItem(sel);
+ if (IsItemCopyableToLeft(di.code))
+ ++legalcount;
+ ++selcount;
}
- // found item (normal case)
- // find item from document
- POSITION pos;
- const DIFFITEM& di = GetDiffItem(sel, pos);
- // what we do depends on comparison result for this item
- switch(di.code)
+ pCmdUI->Enable(legalcount>0);
+ if (menuType==eContext)
{
- case FILE_LUNIQUE:
- pCmdUI->Enable(FALSE); // no right item, so can't copy to left
- break;
- case FILE_RUNIQUE:
- case FILE_DIFF:
- case FILE_BINDIFF:
- pCmdUI->Enable(TRUE);
- break;
- case FILE_SAME:
- pCmdUI->Enable(FALSE);
- break;
- case FILE_LDIRUNIQUE:
- pCmdUI->Enable(FALSE); // no right item, so can't copy to left
- break;
- case FILE_RDIRUNIQUE:
- // TODO 2002-11-22: Enable unique also, but must write code to do recursive copy
- pCmdUI->Enable(TRUE);
- break;
- default:
- pCmdUI->Enable(FALSE);
- break;
+ CString s;
+ AfxFormatString2(s, IDS_COPY_TO_LEFT, NumToStr(legalcount), NumToStr(selcount));
+ pCmdUI->SetText(s);
}
}
// Should Copy to Right be enabled or disabled ? (both main menu & context menu use this)
-void CDirView::DoUpdateDirCopyFileToRight(CCmdUI* pCmdUI)
+void CDirView::DoUpdateDirCopyFileToRight(CCmdUI* pCmdUI, eMenuType menuType)
{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel == -1)
+ int sel=-1;
+ int legalcount=0, selcount=0;
+ while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
{
- // no item there
- pCmdUI->Enable(FALSE);
- return;
+ const DIFFITEM& di = GetDiffItem(sel);
+ if (IsItemCopyableToRight(di.code))
+ ++legalcount;
+ ++selcount;
}
- // found item (normal case)
- // find item from document
- POSITION pos;
- const DIFFITEM& di = GetDiffItem(sel, pos);
- switch(di.code)
+ pCmdUI->Enable(legalcount>0);
+ if (menuType==eContext)
{
- case FILE_LUNIQUE:
- pCmdUI->Enable(TRUE);
- break;
- case FILE_RUNIQUE:
- pCmdUI->Enable(FALSE); // no left item, so can't copy to right
- break;
- case FILE_DIFF:
- case FILE_BINDIFF:
- pCmdUI->Enable(TRUE);
- break;
- case FILE_LDIRUNIQUE:
- // TODO 2002-11-22: Enable unique also, but must write code to do recursive copy
- pCmdUI->Enable(FALSE);
- break;
- case FILE_RDIRUNIQUE:
- pCmdUI->Enable(FALSE); // no left item, so can't copy to right
- break;
- case FILE_SAME:
- default:
- pCmdUI->Enable(FALSE);
- break;
+ CString s;
+ AfxFormatString2(s, IDS_COPY_TO_RIGHT, NumToStr(legalcount), NumToStr(selcount));
+ pCmdUI->SetText(s);
}
}
-BOOL CDirView::GetSelectedFileNames(CString& strLeft, CString& strRight)
-{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel != -1)
- {
- CDirDoc *pd = GetDocument();
- CString name, pathex;
- name = m_pList->GetItemText(sel, DV_NAME);
- pathex = m_pList->GetItemText(sel, DV_PATH);
- if (pathex.Left(2) == _T(".\\") || pathex.Left(2) == _T("./"))
- {
- strLeft.Format(_T("%s\\%s\\%s"), pd->m_pCtxt->m_strLeft, pathex.Right(pathex.GetLength()-2), name);
- strRight.Format(_T("%s\\%s\\%s"), pd->m_pCtxt->m_strRight, pathex.Right(pathex.GetLength()-2), name);
- }
- else
- {
- strLeft.Format(_T("%s\\%s"), pd->m_pCtxt->m_strLeft, name);
- strRight.Format(_T("%s\\%s"), pd->m_pCtxt->m_strRight, name);
- }
- return TRUE;
- }
- return FALSE;
-}
void CDirView::UpdateResources()
m_pList->SetColumn(DV_RTIME, &lvc);
}
-BOOL CDirView::GetSelectedDirNames(CString& strLeft, CString& strRight)
-{
- BOOL bResult = GetSelectedFileNames(strLeft, strRight);
-
- if (bResult)
- {
- TCHAR path[MAX_PATH];
- split_filename(strLeft, path, NULL, NULL);
- strLeft = path;
-
- split_filename(strRight, path, NULL, NULL);
- strRight = path;
- }
- return bResult;
-}
-
int CALLBACK CDirView::CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
// initialize structures to obtain required information
CDirView* pView = reinterpret_cast<CDirView*>(lParamSort);
- DIFFITEM lDi = pView->GetDocument()->m_pCtxt->m_dirlist.GetAt( reinterpret_cast<POSITION>(lParam1) );
- DIFFITEM rDi = pView->GetDocument()->m_pCtxt->m_dirlist.GetAt( reinterpret_cast<POSITION>(lParam2) );
+ 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 = 0; // initialize for default case
void CDirView::OnDestroy()
{
+ DeleteAllDisplayItems();
+
// save the column widths
CListCtrl& ctl = GetListCtrl();
CListViewEx::OnChar(nChar, nRepCnt, nFlags);
}
+// TODO: This just opens first selected item
+// should it do something different when multiple items are selected ?
+// (Perry, 2002-12-04)
void CDirView::OpenSelection()
{
int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
if (sel != -1)
{
- CDirDoc *pd = GetDocument();
- POSITION pos = reinterpret_cast<POSITION>(m_pList->GetItemData(sel));
- DIFFITEM di = pd->m_pCtxt->m_dirlist.GetAt(pos);
+ POSITION diffpos = GetItemKey(sel);
+ DIFFITEM di = GetDiffContext()->GetDiffAt(diffpos);
switch(di.code)
{
case FILE_DIFF:
{
DoDelRight();
}
-
-// Prompt & delete left, if legal
-void CDirView::DoDelLeft()
+// User chose (context menu) delete both
+void CDirView::OnCtxtDirDelBoth()
{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel == -1) return;
-
- CString sl, sr, slFile, srFile;
- if (!GetSelectedDirNames(sl, sr) || !GetSelectedFileNames(slFile, srFile))
- return;
-
- // find item from document
- POSITION pos;
- const DIFFITEM& di = GetDiffItem(sel, pos);
-
- // need to know if file or directory
- switch(di.code)
- {
- case FILE_LUNIQUE:
- case FILE_DIFF:
- case FILE_BINDIFF:
- ConfirmAndDeleteFileAndUpdate(slFile, pos, sel);
- break;
- case FILE_LDIRUNIQUE:
- ConfirmAndDeleteDirAndUpdate(slFile, pos, sel);
- break;
- }
+ DoDelBoth();
}
-// Prompt & delete right, if legal
-void CDirView::DoDelRight()
-{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel == -1) return;
-
- CString sl, sr, slFile, srFile;
- if (!GetSelectedDirNames(sl, sr) || !GetSelectedFileNames(slFile, srFile))
- return;
- // find item from document
- POSITION pos;
- const DIFFITEM& di = GetDiffItem(sel, pos);
-
- // need to know if file or directory
- switch(di.code)
- {
- case FILE_RUNIQUE:
- case FILE_DIFF:
- case FILE_BINDIFF:
- ConfirmAndDeleteFileAndUpdate(srFile, pos, sel);
- break;
- case FILE_RDIRUNIQUE:
- ConfirmAndDeleteDirAndUpdate(srFile, pos, sel);
- break;
- }
-}
// Enable/disable Delete Left menu choice on context menu
void CDirView::OnUpdateCtxtDirDelLeft(CCmdUI* pCmdUI)
{
DoUpdateCtxtDirDelRight(pCmdUI);
}
+// Enable/disable Delete Both menu choice on context menu
+void CDirView::OnUpdateCtxtDirDelBoth(CCmdUI* pCmdUI)
+{
+ DoUpdateCtxtDirDelBoth(pCmdUI);
+}
// Should Delete left be enabled or disabled ?
-void CDirView::DoUpdateCtxtDirDelLeft(CCmdUI* pCmdUI)
+void CDirView::DoUpdateCtxtDirDelLeft(CCmdUI* pCmdUI)
{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel == -1)
+ int sel=-1;
+ int count=0, total=0;
+ while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
{
- // no item there
- pCmdUI->Enable(FALSE);
- return;
- }
- // found item (normal case)
- // find item from document
- POSITION pos;
- const DIFFITEM& di = GetDiffItem(sel, pos);
- // what we do depends on comparison result for this item
- switch(di.code)
- {
- case FILE_LUNIQUE:
- pCmdUI->Enable(TRUE);
- break;
- case FILE_RUNIQUE:
- pCmdUI->Enable(FALSE); // no left item, so can't delete left
- break;
- case FILE_DIFF:
- case FILE_BINDIFF:
- pCmdUI->Enable(TRUE);
- break;
- case FILE_SAME:
- pCmdUI->Enable(FALSE);
- break;
- case FILE_LDIRUNIQUE:
- pCmdUI->Enable(TRUE);
- break;
- case FILE_RDIRUNIQUE:
- pCmdUI->Enable(FALSE); // no left item, so can't delete left
- break;
- default:
- pCmdUI->Enable(FALSE);
- break;
+ const DIFFITEM& di = GetDiffItem(sel);
+ if (IsItemDeletableOnLeft(di.code))
+ ++count;
+ ++total;
}
+ pCmdUI->Enable(count>0);
+ CString s;
+ AfxFormatString2(s, IDS_DEL_LEFT_FMT, NumToStr(count), NumToStr(total));
+ pCmdUI->SetText(s);
}
// Should Delete right be enabled or disabled ?
void CDirView::DoUpdateCtxtDirDelRight(CCmdUI* pCmdUI)
{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel == -1)
+ int sel=-1;
+ int count=0, total=0;
+ while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
{
- // no item there
- pCmdUI->Enable(FALSE);
- return;
+ const DIFFITEM& di = GetDiffItem(sel);
+ if (IsItemDeletableOnRight(di.code))
+ ++count;
+ ++total;
}
- // found item (normal case)
- // find item from document
- POSITION pos;
- const DIFFITEM& di = GetDiffItem(sel, pos);
- // what we do depends on comparison result for this item
- switch(di.code)
+ pCmdUI->Enable(count>0);
+ CString s;
+ AfxFormatString2(s, IDS_DEL_RIGHT_FMT, NumToStr(count), NumToStr(total));
+ pCmdUI->SetText(s);
+}
+// Should Delete both be enabled or disabled ?
+void CDirView::DoUpdateCtxtDirDelBoth(CCmdUI* pCmdUI)
+{
+ int sel=-1;
+ int count=0, total=0;
+ while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
{
- case FILE_LUNIQUE:
- pCmdUI->Enable(FALSE); // no right item, so can't delete right
- break;
- case FILE_RUNIQUE:
- pCmdUI->Enable(TRUE);
- break;
- case FILE_DIFF:
- case FILE_BINDIFF:
- pCmdUI->Enable(TRUE);
- break;
- case FILE_SAME:
- pCmdUI->Enable(FALSE);
- break;
- case FILE_LDIRUNIQUE:
- pCmdUI->Enable(FALSE); // no right item, so can't delete right
- break;
- case FILE_RDIRUNIQUE:
- pCmdUI->Enable(TRUE);
- break;
- default:
- pCmdUI->Enable(FALSE);
- break;
+ const DIFFITEM& di = GetDiffItem(sel);
+ if (IsItemDeletableOnBoth(di.code))
+ ++count;
+ ++total;
}
+ pCmdUI->Enable(count>0);
+ CString s;
+ AfxFormatString2(s, IDS_DEL_BOTH_FMT, NumToStr(count), NumToStr(total));
+ pCmdUI->SetText(s);
}
-// Prompt & delete file, & remove its data entries
-void CDirView::ConfirmAndDeleteFileAndUpdate(LPCTSTR szFile, POSITION pos, int sel)
+
+POSITION CDirView::GetItemKey(int idx)
{
- // May want an option to suppress these message boxes
+ return GetItemKeyFromData(m_pList->GetItemData(idx));
+}
- if (!mf->ConfirmAndDeleteFile(szFile))
- return;
- // remove item data from document & screen
- GetDocument()->m_pCtxt->m_dirlist.RemoveAt(pos);
- GetListCtrl().DeleteItem(sel);
+// SetItemKey & GetItemKey encapsulate how the display list items
+// are mapped to DiffItems, which in turn are DiffContext keys to the actual DIFFITEM data
+POSITION CDirView::GetItemKeyFromData(DWORD dw)
+{
+ return (POSITION)dw;
+}
+void CDirView::SetItemKey(int idx, POSITION diffpos)
+{
+ m_pList->SetItemData(idx, (DWORD)diffpos);
}
-// Prompt & delete directory, & remove its data entries
-void CDirView::ConfirmAndDeleteDirAndUpdate(LPCTSTR szDir, POSITION pos, int sel)
+// given index in list control, get its associated DIFFITEM data
+DIFFITEM CDirView::GetDiffItem(int sel)
{
- // May want an option to suppress these message boxes
+ POSITION diffpos = GetItemKey(sel);
+ return GetDiffContext()->GetDiffAt(diffpos);
+}
- if (!mf->ConfirmAndDeleteDir(szDir))
- return;
- // remove item data from document & screen
- // so, this assumes it is a unique entry (has no children listed)
- GetDocument()->m_pCtxt->m_dirlist.RemoveAt(pos);
- GetListCtrl().DeleteItem(sel);
+void CDirView::DeleteAllDisplayItems()
+{
+ // item data are just positions (diffposes)
+ // that is, they contain no memory needing to be freed
+ m_pList->DeleteAllItems();
+}
+
+// User chose (context menu) open left
+void CDirView::OnCtxtDirOpenLeft()
+{
+ DoOpen(SIDE_LEFT);
+}
+// User chose (context menu) open right
+void CDirView::OnCtxtDirOpenRight()
+{
+ DoOpen(SIDE_RIGHT);
+}
+
+// User chose (context menu) open left with
+void CDirView::OnCtxtDirOpenLeftWith()
+{
+ DoOpenWith(SIDE_LEFT);
+}
+// User chose (context menu) open right with
+void CDirView::OnCtxtDirOpenRightWith()
+{
+ DoOpenWith(SIDE_RIGHT);
+}
+// return selected item index, or -1 if none or multiple
+int CDirView::GetSingleSelectedItem() const
+{
+ int sel=-1, sel2=-1;
+ sel = m_pList->GetNextItem(sel, LVNI_SELECTED);
+ if (sel == -1) return -1;
+ sel2 = m_pList->GetNextItem(sel, LVNI_SELECTED);
+ if (sel2 != -1) return -1;
+ return sel;
+}
+// Enable/disable Open Left menu choice on context menu
+void CDirView::OnUpdateCtxtDirOpenLeft(CCmdUI* pCmdUI)
+{
+ DoUpdateOpenLeft(pCmdUI);
+}
+// Enable/disable Open Right menu choice on context menu
+void CDirView::OnUpdateCtxtDirOpenRight(CCmdUI* pCmdUI)
+{
+ DoUpdateOpenRight(pCmdUI);
}
+
+// Enable/disable Open Left With menu choice on context menu
+void CDirView::OnUpdateCtxtDirOpenLeftWith(CCmdUI* pCmdUI)
+{
+ DoUpdateOpenLeft(pCmdUI);
+}
+// Enable/disable Open Right With menu choice on context menu
+void CDirView::OnUpdateCtxtDirOpenRightWith(CCmdUI* pCmdUI)
+{
+ DoUpdateOpenRight(pCmdUI);
+}
+
+// used for both OpenLeft and OpenLeftWith
+void CDirView::DoUpdateOpenLeft(CCmdUI* pCmdUI)
+{
+ int sel = GetSingleSelectedItem();
+ if (sel != -1)
+ {
+ const DIFFITEM& di = GetDiffItem(sel);
+ if (!IsItemOpenableOnLeft(di.code))
+ sel = -1;
+ }
+
+ pCmdUI->Enable(sel>=0);
+}
+// used for both OpenRight and OpenRightWith
+void CDirView::DoUpdateOpenRight(CCmdUI* pCmdUI)
+{
+ int sel = GetSingleSelectedItem();
+ if (sel != -1)
+ {
+ const DIFFITEM& di = GetDiffItem(sel);
+ if (!IsItemOpenableOnRight(di.code))
+ sel = -1;
+ }
+
+ pCmdUI->Enable(sel>=0);
+}
+
+
struct tagDIFFITEM;
typedef struct tagDIFFITEM DIFFITEM;
+class CDiffContext;
+
+typedef enum { eMain, eContext } eMenuType;
class CDirDoc;
DECLARE_DYNCREATE(CDirView)
// Attributes
- CImageList m_imageList;
public:
CDirDoc* GetDocument(); // non-debug version is inline
- CSortHeaderCtrl m_ctlSortHeader;
+ const CDirDoc * GetDocument() const { return const_cast<CDirView *>(this)->GetDocument(); }
+private:
+ CDiffContext * GetDiffContext();
// Operations
public:
static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
- BOOL GetSelectedDirNames(CString& strLeft, CString& strRight);
void UpdateResources();
- BOOL GetSelectedFileNames(CString& strLeft, CString& strRight);
- CListCtrl * m_pList;
+ POSITION GetItemKey(int idx);
+ void SetItemKey(int idx, POSITION diffpos);
+ void DeleteAllDisplayItems();
+
+
+// Implementation types
+private:
+ typedef enum { ACT_COPY=1, ACT_DEL_LEFT, ACT_DEL_RIGHT, ACT_DEL_BOTH } ACT_TYPE;
+ struct action { CString src; CString dest; BOOL dirflag; int idx; };
+ typedef CList<int, int> DeletedItemList; // indices into display list control
+ struct ActionList
+ {
+ int selcount; // #items in full selection (not all may be affected)
+ ACT_TYPE atype;
+ CList<action, action&> actions;
+ CStringList errors;
+ DeletedItemList deletedItems;
+ ActionList(ACT_TYPE at) : selcount(0), atype(at) { }
+ int GetCount() const { return actions.GetCount(); }
+ };
+ typedef enum { SIDE_LEFT=1, SIDE_RIGHT } SIDE_TYPE;
+
+// Implementation in DirActions.cpp
+private:
+ BOOL GetSelectedDirNames(CString& strLeft, CString& strRight) const;
+ BOOL GetSelectedFileNames(CString& strLeft, CString& strRight) const;
+ CString GetSelectedFileName(SIDE_TYPE stype) const;
+ void GetItemFileNames(int sel, CString& strLeft, CString& strRight) const;
+ BOOL IsItemLeftOnly(int code);
+ BOOL IsItemRightOnly(int code);
+ BOOL IsItemCopyableToLeft(int code);
+ BOOL IsItemCopyableToRight(int code);
+ BOOL IsItemDeletableOnLeft(int code);
+ BOOL IsItemDeletableOnRight(int code);
+ BOOL IsItemDeletableOnBoth(int code);
+ BOOL IsItemOpenableOnLeft(int code);
+ BOOL IsItemOpenableOnRight(int code);
+ void DoCopyFileToRight();
+ void DoCopyFileToLeft();
+ void DoDelLeft();
+ void DoDelRight();
+ void DoDelBoth();
+ void DoOpen(SIDE_TYPE stype);
+ void DoOpenWith(SIDE_TYPE stype);
+ void ConfirmAndPerformActions(ActionList & actions);
+ BOOL ConfirmActionList(const ActionList & actions);
+ void PerformActionList(ActionList & actions);
+ void PerformAndRemoveTopAction(ActionList & actions);
+// End DirActions.cpp
+
// Overrides
// ClassWizard generated virtual function overrides
virtual void Dump(CDumpContext& dc) const;
#endif
- // Generated message map functions
+// Implementation data
protected:
+ CSortHeaderCtrl m_ctlSortHeader;
+ CImageList m_imageList;
bool m_bSortAscending; // is currently sorted ascending.
int m_sortColumn; // index to column which is sorted
+ CListCtrl * m_pList;
+
+
+ // Generated message map functions
afx_msg void OnColumnClick(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnContextMenu(CWnd*, CPoint point);
//{{AFX_MSG(CDirView)
afx_msg void OnUpdateCtxtDirDelLeft(CCmdUI* pCmdUI);
afx_msg void OnCtxtDirDelRight();
afx_msg void OnUpdateCtxtDirDelRight(CCmdUI* pCmdUI);
+ afx_msg void OnCtxtDirDelBoth();
+ afx_msg void OnUpdateCtxtDirDelBoth(CCmdUI* pCmdUI);
+ afx_msg void OnCtxtDirOpenLeft();
+ afx_msg void OnUpdateCtxtDirOpenLeft(CCmdUI* pCmdUI);
+ afx_msg void OnCtxtDirOpenLeftWith();
+ afx_msg void OnUpdateCtxtDirOpenLeftWith(CCmdUI* pCmdUI);
+ afx_msg void OnCtxtDirOpenRight();
+ afx_msg void OnUpdateCtxtDirOpenRight(CCmdUI* pCmdUI);
+ afx_msg void OnCtxtDirOpenRightWith();
+ afx_msg void OnUpdateCtxtDirOpenRightWith(CCmdUI* pCmdUI);
afx_msg void OnDestroy();
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
void OpenSelection();
- const DIFFITEM& CDirView::GetDiffItem(int sel, POSITION & pos);
- void DoCopyFileToRight();
- void DoCopyFileToLeft();
- void DoUpdateDirCopyFileToLeft(CCmdUI* pCmdUI);
- void DoUpdateDirCopyFileToRight(CCmdUI* pCmdUI);
+ void DoUpdateDirCopyFileToLeft(CCmdUI* pCmdUI, eMenuType menuType);
+ void DoUpdateDirCopyFileToRight(CCmdUI* pCmdUI, eMenuType menuType);
void ModifyPopup(CMenu * pPopup, int nStringResource, int nMenuId, LPCTSTR szPath);
- void DoDelLeft();
- void DoDelRight();
void DoUpdateCtxtDirDelLeft(CCmdUI* pCmdUI);
void DoUpdateCtxtDirDelRight(CCmdUI* pCmdUI);
- void ConfirmAndDeleteFileAndUpdate(LPCTSTR szFile, POSITION pos, int sel);
- void ConfirmAndDeleteDirAndUpdate(LPCTSTR szDir, POSITION pos, int sel);
-
+ void DoUpdateCtxtDirDelBoth(CCmdUI* pCmdUI);
+ void DoUpdateOpenLeft(CCmdUI* pCmdUI);
+ void DoUpdateOpenRight(CCmdUI* pCmdUI);
+ POSITION GetItemKeyFromData(DWORD dw);
+ DIFFITEM GetDiffItem(int sel);
+ int GetSingleSelectedItem() const;
};
+
#ifndef _DEBUG // debug version in DirView.cpp
inline CDirDoc* CDirView::GetDocument()
{ return (CDirDoc*)m_pDocument; }
#endif
+
+CString NumToStr(int n);
+
+
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
break;
}
CString s;
- // AfxFormatString4 doesn't exist
- s.Format(_T("s:%d d:%d lf:%d ld:%d rf:%d rd:%d bd:%d e:%d")
- , m_nStatusFileSame, m_nStatusFileDiff, m_nStatusFileBinDiff, m_nStatusFileError
- , m_nStatusLeftFileOnly, m_nStatusLeftDirOnly, m_nStatusRightFileOnly, m_nStatusRightDirOnly);
+ // TODO: Load the format string from resource
+ s.Format(_T("s:%d d:%d bd:%d lf:%d ld:%d rf:%d rd:%d e:%d")
+ , m_nStatusFileSame, m_nStatusFileDiff, m_nStatusFileBinDiff
+ , m_nStatusLeftFileOnly, m_nStatusLeftDirOnly, m_nStatusRightFileOnly, m_nStatusRightDirOnly
+ , m_nStatusFileError);
m_wndStatusBar.SetPaneText(2, s);
}
pCtxt->SetRegExp(strExt);
m_pDirDoc->Rescan();
}
+ pCtxt->ClearStatus();
}
}
else
}
// Get user language description of error, if available
-CString CMainFrame::GetSystemErrorDesc(int nerr)
+CString GetSystemErrorDesc(int nerr)
{
LPVOID lpMsgBuf;
CString str = _T("?");
}
// trim trailing line returns
-void CMainFrame::RemoveLineReturns(CString & str)
+static void RemoveLineReturns(CString & str)
{
str.Replace(_T("\n"), _T(""));
str.Replace(_T("\r"), _T(""));
}
+// TODO: Can we move this into DirActions.cpp ?
// Delete file (return TRUE if deleted, else put up error & return FALSE)
BOOL CMainFrame::DeleteFileOrError(LPCTSTR szFile)
{
return TRUE;
}
-// Prompt & delete file (return TRUE if deleted)
-BOOL CMainFrame::ConfirmAndDeleteFile(LPCTSTR szFile)
+// Delete file (return TRUE if successful, else sets error string & returns FALSE)
+BOOL DeleteFileSilently(LPCTSTR szFile, CString * psError)
{
- CString s;
- AfxFormatString1(s, IDS_CONFIRM_DELETE_FILE, szFile);
- if (AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION)!=IDYES)
+ if (!DeleteFile(szFile))
+ {
+ CString sError = GetSystemErrorDesc(GetLastError());
+ RemoveLineReturns(sError);
+ AfxFormatString2(*psError, IDS_DELETE_FILE_FAILED, szFile, sError);
return FALSE;
- return DeleteFileOrError(szFile);
+ }
+ return TRUE;
}
-// Prompt & delete directory (return TRUE if deleted)
-BOOL CMainFrame::ConfirmAndDeleteDir(LPCTSTR szDir)
-{
- CString s;
- AfxFormatString1(s, IDS_CONFIRM_DELETE_DIR, szDir);
- if (AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION)!=IDYES)
- return FALSE;
- return DeleteRecurseDir(szDir);
-}
// delete directory by recursively deleting all contents
// gives up on first error
-BOOL CMainFrame::DeleteRecurseDir(LPCTSTR szDir)
+BOOL DeleteDirSilently(LPCTSTR szDir, CString * psError)
{
CFileFind finder;
CString sSpec = szDir;
if (finder.IsDots()) continue;
if (finder.IsDirectory())
{
- if (!DeleteRecurseDir(finder.GetFilePath()))
+ if (!DeleteDirSilently(finder.GetFilePath(), psError))
return FALSE;
}
else
{
- if (!DeleteFileOrError(finder.GetFilePath()))
+ if (!DeleteFileSilently(finder.GetFilePath(), psError))
return FALSE;
}
}
{
CString sError = GetSystemErrorDesc(GetLastError());
RemoveLineReturns(sError);
- sError += (CString)_T(" [") + szDir + _T("]");
- CString s;
- AfxFormatString1(s, IDS_DELETE_FILE_FAILED, sError);
- AfxMessageBox(s, MB_OK|MB_ICONSTOP);
+ AfxFormatString2(*psError, IDS_DELETE_FILE_FAILED, szDir, sError);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// wrapper for DoSyncFiles which adds filename to error string reported
+BOOL CMainFrame::SyncFiles(LPCTSTR pszSrc, LPCTSTR pszDest, CString * psError)
+{
+ if (!DoSyncFiles(pszSrc, pszDest, psError))
+ {
+ AfxFormatString2(*psError, IDS_COPY_FILE_FAILED, *psError, pszSrc);
return FALSE;
}
return TRUE;
}
-BOOL CMainFrame::SyncFiles(LPCTSTR pszSrc, LPCTSTR pszDest)
+// (error string reported does not include filename
+BOOL CMainFrame::DoSyncFiles(LPCTSTR pszSrc, LPCTSTR pszDest, CString * psError)
{
+ CString sActionError;
CString strSavePath(pszDest);
if (!CheckSavePath(strSavePath))
+ {
+ psError->LoadString(IDS_ERROR_FILE_WRITEABLE);
return FALSE;
+ }
if (!CreateBackup(strSavePath))
+ {
+ psError->LoadString(IDS_ERROR_BACKUP);
return FALSE;
+ }
// Now it's just a matter of copying the right file to the left
DeleteFile(strSavePath); // (errors are handled from CopyFile below)
if (!CopyFile(pszSrc, strSavePath, FALSE))
{
-
+ *psError = GetSystemErrorDesc(GetLastError());
return FALSE;
}
return TRUE;
}
-void CMainFrame::UpdateCurrentFileStatus(UINT nStatus)
+void CMainFrame::UpdateCurrentFileStatus(UINT nStatus, int idx)
{
- if (NULL != m_pDirDoc)
- {
- CDirView *pv = m_pDirDoc->GetMainView();
- if (NULL != pv)
- {
- CListCtrl& lc = pv->GetListCtrl();
- int sel = lc.GetNextItem(-1, LVNI_SELECTED);
- if (sel != -1)
- {
- // first change it in the dirlist
- POSITION pos = reinterpret_cast<POSITION>(lc.GetItemData(sel));
- DIFFITEM di = m_pDirDoc->m_pCtxt->m_dirlist.GetAt(pos);
- di.code = (BYTE)nStatus;
- m_pDirDoc->m_pCtxt->m_dirlist.SetAt(pos, di);
- m_pDirDoc->UpdateItemStatus(sel);
- //m_pDirDoc->Redisplay();
- }
- }
- }
+ ASSERT(m_pDirDoc);
+ CDirView *pv = m_pDirDoc->GetMainView();
+ ASSERT(pv);
+ // first change it in the dirlist
+ POSITION diffpos = pv->GetItemKey(idx);
+
+ // TODO: Why is the update broken into these pieces ?
+ // Someone could figure out these pieces and probably simplify this.
+
+ // update DIFFITEM code
+ m_pDirDoc->m_pCtxt->UpdateStatusCode(diffpos, (BYTE)nStatus);
+ // update DIFFITEM time, and also tell views
+ m_pDirDoc->UpdateItemStatus(idx);
+ //m_pDirDoc->Redisplay();
}
void CMainFrame::OnViewSelectfont()
// Operations
public:
- CString GetSystemErrorDesc(int nerr);
- void RemoveLineReturns(CString & str);
BOOL DeleteFileOrError(LPCTSTR szFile);
- BOOL DeleteRecurseDir(LPCTSTR szDir);
- BOOL ConfirmAndDeleteFile(LPCTSTR szFile);
- BOOL ConfirmAndDeleteDir(LPCTSTR szDir);
void rptStatus(BYTE code);
void clearStatus();
- BOOL SyncFiles(LPCTSTR pszSrc, LPCTSTR pszDest);
- void UpdateCurrentFileStatus(UINT nStatus);
+ BOOL SyncFiles(LPCTSTR pszSrc, LPCTSTR pszDest, CString * psError);
+ BOOL DoSyncFiles(LPCTSTR pszSrc, LPCTSTR pszDest, CString * psError);
+ void UpdateCurrentFileStatus(UINT nStatus, int idx);
BOOL DoFileOpen(LPCTSTR pszLeft = NULL, LPCTSTR pszRight = NULL, BOOL bRecurse = FALSE);
void ShowMergeDoc(LPCTSTR szLeft, LPCTSTR szRight);
void UpdateResources();
extern CMainFrame *mf;
+BOOL DeleteFileSilently(LPCTSTR szFile, CString * psError);
+BOOL DeleteDirSilently(LPCTSTR szDir, CString * psError);
+CString GetSystemErrorDesc(int nerr);
+
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
# End Source File
# Begin Source File
+SOURCE=.\DirActions.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\DirDoc.cpp
!IF "$(CFG)" == "Merge - Win32 Release"
# End Source File
# Begin Source File
+SOURCE=.\OutputDlg.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\PropColors.cpp
# End Source File
# Begin Source File
# End Source File
# Begin Source File
+SOURCE=.\OutputDlg.h
+# End Source File
+# Begin Source File
+
SOURCE=.\PropColors.h
# End Source File
# Begin Source File
MENUITEM "Copy file to right", ID_DIR_COPY_FILE_TO_RIGHT
MENUITEM "Delete left", ID_DIR_DEL_LEFT
MENUITEM "Delete right", ID_DIR_DEL_RIGHT
+ MENUITEM "Delete both", ID_DIR_DEL_BOTH
+ MENUITEM SEPARATOR
+ MENUITEM "Open left", ID_DIR_OPEN_LEFT
+ MENUITEM "Open left with...", ID_DIR_OPEN_LEFT_WITH
+ MENUITEM "Open right", ID_DIR_OPEN_RIGHT
+ MENUITEM "Open right with...", ID_DIR_OPEN_RIGHT_WITH
END
END
WS_EX_CLIENTEDGE
END
+IDD_OUTPUT DIALOG DISCARDABLE 0, 0, 278, 157
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Dialog"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,106,136,50,14
+ EDITTEXT IDC_EDIT1,7,7,264,123,ES_MULTILINE | ES_READONLY |
+ WS_VSCROLL
+END
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
IDS_ALLFILES "All Files (*.*)|*.*||"
IDS_CONFIRM_ALL_LEFT "Are you sure you want to copy all differences to the left file?"
IDS_CONFIRM_ALL_RIGHT "Are you sure you want to copy all differences to the right file?"
- IDS_COPY2DIR_LEFT_FMT "Copy file to left: %1"
- IDS_CONFIRM_COPY2DIR "Are you sure you want to copy the selected file to %1?"
+ IDS_ERRORS_TITLE "%1 Error(s)"
+ IDS_CONFIRM_COPY2DIR "Are you sure you want to copy %1 of %2 selected item(s)"
IDS_FONT_CHANGE "The selected font change will not be applied to any currently visible difference windows."
IDS_DIRECTORY_WINDOW_TITLE "Directory Comparison Results"
IDS_DIRECTORY_WINDOW_STATUS_FMT "Results for %1 and %2"
ID_CURDIFF "Scroll to the current difference\nCurrent Diff (Alt+Enter)"
ID_LASTDIFF "Scroll to the last difference\nLast Diff (Alt+End)"
ID_DIFFNUM "placeholder"
- ID_DIR_DEL_LEFT "Delete selected file on left"
- ID_DIR_DEL_RIGHT "Delete selected file on right"
+ ID_DIR_DEL_LEFT "Delete selected item on left"
+ ID_DIR_DEL_RIGHT "Delete selected item on right"
ID_DIFFSTATUS "placeholder for status count"
ID_OPTIONS_SHOWUNIQUELEFT "Displays files that exist in only on left side"
ID_OPTIONS_SHOWUNIQUERIGHT
"Displays files that exist in only on right side"
+ ID_DIR_DEL_BOTH "Delete selected item(s) on both sides"
+ ID_DIR_OPEN_LEFT "Open left file"
+ ID_DIR_OPEN_LEFT_WITH "Open left file with ..."
+ ID_DIR_OPEN_RIGHT "Open right file"
END
STRINGTABLE DISCARDABLE
IDS_LTIME_HEADER "Left Date"
IDS_RTIME_HEADER "Right Date"
IDS_EXTENSION_HEADER "Extension"
- IDS_COPY2DIR_RIGHT_FMT "Copy file to right: %1"
- IDS_DEL_LEFT_FMT "Delete left: %1"
+ IDS_CONFIRM_DELETE_ITEMS
+ "Are you sure you want to delete %1 of %2 selected item(s) ?"
+ IDS_DEL_LEFT_FMT "Delete left side %1 of %2 selected item(s)"
END
STRINGTABLE DISCARDABLE
BEGIN
- IDS_DEL_RIGHT_FMT "Delete right: %1"
- IDS_DELETE_FILE_FAILED "Delete file failed: %1"
+ IDS_DEL_RIGHT_FMT "Delete right side %1 of %2 selected item(s)"
+ IDS_DELETE_FILE_FAILED "Delete file %1 failed: %2"
IDS_CONFIRM_DELETE_DIR "Delete directory %1?"
IDS_REMOVE_DIR_FAILED "Remove directory failed: %1"
+ IDS_COPY_TO_LEFT "Copy to left side %1 of %2 selected item(s)"
+ IDS_DEL_BOTH_FMT "Delete both sides %1 of %2 selected item(s)"
+ IDS_COPY_TO_RIGHT "Copy to right side %1 of %2 selected item(s)"
+ IDS_DELETE_DIR_FAILED "Delete directory %1 failed: %s"
+ IDS_COPY_FILE_FAILED "Copying file %1 failed: %2"
+ IDS_COPY_DIR_FAILED "Copying directory %1 failed: %2"
+ IDS_ERROR_FILE_WRITEABLE "Error checking destination writeability"
+ IDS_ERROR_BACKUP "Error backing up file"
+ IDS_CONFIRM_COPY_SINGLE "Are you sure you want to copy %1 to %2?"
+ IDS_CONFIRM_DELETE_SINGLE "Are you sure you want to delete %1?"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_DIR_OPEN_RIGHT_WITH "Open right file with..."
END
#endif // English (U.S.) resources
--- /dev/null
+// OutputDlg.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "merge.h"
+#include "OutputDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// COutputDlg dialog
+
+
+COutputDlg::COutputDlg(const CString & sTitle, const CString & sText)
+: CDialog(COutputDlg::IDD)
+, m_sTitle(sTitle)
+, m_sText(sText)
+{
+ //{{AFX_DATA_INIT(COutputDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+}
+
+
+void COutputDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(COutputDlg)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(COutputDlg, CDialog)
+ //{{AFX_MSG_MAP(COutputDlg)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// COutputDlg message handlers
+
+BOOL COutputDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ SetWindowText(m_sTitle);
+ SetDlgItemText(IDC_EDIT1, m_sText);
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void OutputBox(LPCTSTR szTitle, LPCTSTR szText)
+{
+ COutputDlg dlg(szTitle, szText);
+ dlg.DoModal();
+}
--- /dev/null
+#if !defined(AFX_OUTPUTDLG_H__7F99AF10_24E5_49AF_8D97_9A86A80BAD48__INCLUDED_)
+#define AFX_OUTPUTDLG_H__7F99AF10_24E5_49AF_8D97_9A86A80BAD48__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+// OutputDlg.h : header file
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// COutputDlg dialog
+
+void OutputBox(LPCTSTR szTitle, LPCTSTR szText);
+
+class COutputDlg : public CDialog
+{
+// Construction
+public:
+ COutputDlg(const CString & sTitle, const CString & sText);
+
+// Dialog Data
+ //{{AFX_DATA(COutputDlg)
+ enum { IDD = IDD_OUTPUT };
+ // NOTE: the ClassWizard will add data members here
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(COutputDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(COutputDlg)
+ virtual BOOL OnInitDialog();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+private:
+ CString m_sTitle;
+ CString m_sText;
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_OUTPUTDLG_H__7F99AF10_24E5_49AF_8D97_9A86A80BAD48__INCLUDED_)
// Used by Merge.rc
//
#define IDC_CUT 3
-#define IDSAVEAS 3
#define IDC_COPY 4
#define IDC_PASTE 5
#define IDC_UNDO 6
+#define IDSAVEAS 7
#define IDD_ABOUTBOX 100
-#define IDR_POPUP_DIFFVIEW 102
-#define IDB_SPLASH 103
-#define IDR_POPUP_DIRVIEW 104
-#define IDD_PROP_VSS 107
-#define IDR_MAINFRAME 128
-#define IDR_MERGETYPE 129
-#define IDD_OPEN 130
-#define IDB_WINMERGE 130
+#define IDR_POPUP_DIFFVIEW 101
+#define IDR_POPUP_DIRVIEW 102
+
+#define IDD_PROP_VSS 103
+#define IDR_MAINFRAME 104
+#define IDR_MERGETYPE 105
+#define IDD_OPEN 106
+#define IDD_EDITFILE 107
+#define IDD_VSS 108
+#define IDD_PROPPAGE_LARGE 109
+#define IDD_CLEARCASE 110
+#define IDD_PROPPAGE_FILTER 111
+#define IDD_OUTPUT 112
#define IDS_VERSION_FMT 130
-#define IDD_EDITFILE 131
-#define IDB_OLDSPLASH 131
+
#define IDS_ALLFILES 131
-#define IDD_VSS 132
#define IDS_CONFIRM_ALL_LEFT 132
-#define IDD_PROPPAGE_LARGE 133
#define IDS_CONFIRM_ALL_RIGHT 133
-#define IDS_COPY2DIR_LEFT_FMT 134
-#define IDD_CLEARCASE 134
+#define IDS_ERRORS_TITLE 134
#define IDS_CONFIRM_COPY2DIR 135
-#define IDD_PROPPAGE_FILTER 135
#define IDS_FONT_CHANGE 136
#define IDS_DIRECTORY_WINDOW_TITLE 137
#define IDS_DIRECTORY_WINDOW_STATUS_FMT 138
#define IDS_FILES_ARE_DIFFERENT 139
-#define IDB_LFOLDER 140
#define IDS_BIN_FILES_DIFF 140
#define IDS_ONLY_IN_FMT 141
#define IDS_IDENTICAL 142
#define IDS_LTIME_HEADER 171
#define IDS_RTIME_HEADER 172
#define IDS_EXTENSION_HEADER 173
-#define IDS_COPY2DIR_RIGHT_FMT 174
+#define IDS_CONFIRM_DELETE_ITEMS 174
#define IDS_DEL_LEFT_FMT 175
#define IDS_DEL_RIGHT_FMT 176
#define IDS_DELETE_FAILED 177
#define IDS_DELETE_FILE_FAILED 177
#define IDS_CONFIRM_DELETE_DIR 178
#define IDS_REMOVE_DIR_FAILED 179
+#define IDS_COPY_TO_LEFT 180
+#define IDS_COPY_TO_LEFT_MAIN 181
+#define IDS_DEL_BOTH_FMT 181
+#define IDS_COPY_TO_RIGHT 182
+#define IDS_COPY_TO_RIGHT_MAIN 183
+#define IDS_DELETE_DIR_FAILED 184
+#define IDS_COPY_FILE_FAILED 185
+#define IDS_COPY_DIR_FAILED 186
+#define IDS_ERROR_FILE_WRITEABLE 187
+#define IDS_ERROR_BACKUP 188
+#define IDS_CONFIRM_COPY_SINGLE 189
+#define IDS_CONFIRM_DELETE_SINGLE 190
#define IDB_EQUAL 213
#define IDB_NOTEQUAL 214
#define IDB_RFOLDER 215
#define IDB_BINARY 217
#define IDB_LFILE 218
#define IDB_RFILE 219
+#define IDB_SPLASH 220
+#define IDB_WINMERGE 221
+#define IDB_OLDSPLASH 222
+#define IDB_LFOLDER 223
+
#define IDC_LEFT_EDIT 1000
#define IDC_FILE_EDIT 1000
#define IDC_LEFT_BUTTON 1001
#define IDC_PASSWORD 1028
#define IDC_DIFFERENCE_COLOR 1031
#define IDC_SEL_DIFFERENCE_COLOR 1032
+#define IDC_EDIT1 1033
#define IDR_MARGIN_CURSOR 22900
#define IDD_LANGUAGE_SELECT 30000
#define IDD_PROPSYNTAX 30001
#define ID_DIFFSTATUS 32809
#define ID_OPTIONS_SHOWUNIQUELEFT 32810
#define ID_OPTIONS_SHOWUNIQUERIGHT 32811
+#define ID_DIR_DEL_BOTH 32812
+#define ID_DIR_OPEN_LEFT 32813
+#define ID_DIR_OPEN_LEFT_WITH 32814
+#define ID_DIR_OPEN_RIGHT 32815
+#define ID_DIR_OPEN_RIGHT_WITH 32816
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1
-#define _APS_NEXT_RESOURCE_VALUE 135
-#define _APS_NEXT_COMMAND_VALUE 32812
-#define _APS_NEXT_CONTROL_VALUE 1032
-#define _APS_NEXT_SYMED_VALUE 106
+#define _APS_NEXT_RESOURCE_VALUE 113
+#define _APS_NEXT_COMMAND_VALUE 32817
+#define _APS_NEXT_CONTROL_VALUE 1034
+#define _APS_NEXT_SYMED_VALUE 108
#endif
#endif