#include "stdafx.h"
#include "AboutDlg.h"
-#include "Constants.h"
+#include "statlink.h"
#include "Merge.h"
-#include "version.h"
-#include "paths.h"
-#include "Environment.h"
+#include "DDXHelper.h"
++#include "Picture.h"
+#include "resource.h" // IDD_ABOUTBOX
-
-BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
- //{{AFX_MSG_MAP(CAboutDlg)
+/**
+ * @brief About-dialog class.
+ *
+ * Shows About-dialog bitmap and draws version number and other
+ * texts into it.
+ */
+class CAboutDlg::Impl : public CDialog
+{
+public:
+ CAboutDlg::Impl(CAboutDlg *p, CWnd* pParent = NULL);
+
+// Dialog Data
+ //{{AFX_DATA(CAboutDlg::Impl)
+ enum { IDD = IDD_ABOUTBOX };
+ CStaticLink m_ctlWWW;
+ //}}AFX_DATA
+
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CAboutDlg::Impl)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ //{{AFX_MSG(CAboutDlg::Impl)
+ virtual BOOL OnInitDialog();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+public:
+ afx_msg void OnBnClickedOpenContributors();
++ afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);\r
++ afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);\r
+
+private:
+ CAboutDlg *m_p;
++ CPicture m_image;
++ CFont m_font;
+};
+
+BEGIN_MESSAGE_MAP(CAboutDlg::Impl, CDialog)
+ //{{AFX_MSG_MAP(CAboutDlg::Impl)
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_OPEN_CONTRIBUTORS, OnBnClickedOpenContributors)
+ ON_WM_DRAWITEM()
+ ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
-CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
+CAboutDlg::Impl::Impl(CAboutDlg *p, CWnd* pParent /*=NULL*/)
+ : CDialog(CAboutDlg::Impl::IDD)
+ , m_p(p)
{
}
theApp.TranslateDialog(m_hWnd);
CDialog::OnInitDialog();
- // Load application icon
- HICON icon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
- if (icon != NULL) {
- CStatic * pIcon = (CStatic *) GetDlgItem(IDC_ABOUTBOX_ICON);
- pIcon->SetIcon(icon);
- }
+ m_image.Load(IDR_SPLASH);
+
+ CDC *pDC = GetDC();
+ int fontHeight = -MulDiv(10, pDC->GetDeviceCaps(LOGPIXELSY), 72);
+ m_font.CreateFont(fontHeight, 0, 0, 0, FW_MEDIUM, FALSE, FALSE,
+ 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Tahoma"));
+ ReleaseDC(pDC);
+
- String text = LoadResString(IDS_SPLASH_DEVELOPERS);
- string_replace(text, _T(", "), _T("\n"));
- CWnd *sta = GetDlgItem(IDC_STATIC);
- sta->SetWindowTextW(text.c_str());
- sta->SetFont(&m_font);
-
- CVersionInfo version(AfxGetResourceHandle());
- String sVersion = version.GetProductVersion();
- m_strVersion = LangFormatString1(IDS_VERSION_FMT, sVersion.c_str()).c_str();
- if (m_strVersion.Find(_T(" - ")) != -1)
- {
- m_strVersion.Replace(_T(" - "), _T("\n"));
- m_strVersion += _T(" ");
- }
- else
- {
- m_strVersion += _T("\n");
- }
-
-#ifdef _UNICODE
- m_strVersion += theApp.LoadString(IDS_UNICODE).c_str();
-#endif
-
-#if defined _M_IX86
- m_strVersion += _T(" x86");
-#elif defined _M_IA64
- m_strVersion += _T(" IA64");
-#elif defined _M_X64
- m_strVersion += _T(" ");
- m_strVersion += theApp.LoadString(IDS_WINX64).c_str();
-#endif
++ GetDlgItem(IDC_STATIC)->SetWindowText(m_p->m_info.developers.c_str());
++ GetDlgItem(IDC_STATIC)->SetFont(&m_font);
+ GetDlgItem(IDC_VERSION)->SetFont(&m_font);
- String sPrivateBuild = version.GetPrivateBuild();
- if (!sPrivateBuild.empty())
- {
- m_strPrivateBuild = LangFormatString1(IDS_PRIVATEBUILD_FMT,
- sPrivateBuild.c_str()).c_str();
- }
-
- String copyright = LoadResString(IDS_SPLASH_GPLTEXT);
- copyright += _T("\n");
- copyright += version.GetLegalCopyright();
- copyright += _T(" All rights reserved.");
- m_ctlCompany.SetWindowText(copyright.c_str());
- m_ctlWWW.m_link = WinMergeURL;
+ m_ctlWWW.m_link = m_p->m_info.website.c_str();
UpdateData(FALSE);
// EXCEPTION: OCX Property Pages should return FALSE
}
-HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
++HBRUSH CAboutDlg::Impl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+ {
+ if (nCtlColor == CTLCOLOR_STATIC && pWnd != GetDlgItem(IDC_WWW))
+ {
+ pDC->SetBkMode(TRANSPARENT);
+ return (HBRUSH)GetStockObject(NULL_BRUSH);
+ }
+ return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
+ }
+
-void CAboutDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
++void CAboutDlg::Impl::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
+ {
+ CRect rc;
+ GetDlgItem(nIDCtl)->GetClientRect(&rc);
+ m_image.Render(CDC::FromHandle(lpDrawItemStruct->hDC), rc);
+ }
/**
* @brief Show contributors list.
* Opens Contributors.txt into notepad.
* @param [in] bLeft Update left-side info.
* @param [in] bRight Update right-side info.
*/
--void CDiffContext::UpdateStatusFromDisk(uintptr_t diffpos, bool bLeft, bool bRight)
++void CDiffContext::UpdateStatusFromDisk(uintptr_t diffpos, int index)
{
DIFFITEM &di = GetDiffRefAt(diffpos);
- if (bLeft)
- {
- di.diffFileInfo[0].ClearPartial();
- if (!di.diffcode.isSideSecondOnly())
- UpdateInfoFromDiskHalf(di, 0);
- }
- if (bRight)
- {
- di.diffFileInfo[1].ClearPartial();
- if (!di.diffcode.isSideFirstOnly())
- UpdateInfoFromDiskHalf(di, 1);
- }
+ di.diffFileInfo[index].ClearPartial();
+ if (di.diffcode.isExists(index))
+ UpdateInfoFromDiskHalf(di, index);
}
/**
// One idea would be to provide an iterator over them.
//
-#include "stdafx.h"
-#include "Merge.h"
+#include "DirActions.h"
+#include "MergeApp.h"
#include "UnicodeString.h"
-#include "DirView.h"
-#include "DirDoc.h"
-#include "coretools.h"
-#include "paths.h"
#include "7zCommon.h"
#include "ShellFileOperations.h"
-#include "OptionsDef.h"
-#include "WaitStatusCursor.h"
#include "DiffItem.h"
#include "FileActionScript.h"
-#include "LoadSaveCodepageDlg.h"
-#include "IntToIntMap.h"
-#include "FileOrFolderSelect.h"
-#include "ConfirmFolderCopyDlg.h"
+#include "locality.h"
+#include "FileFilterHelper.h"
+#include "coretools.h"
#include "OptionsMgr.h"
- using Poco::UIntPtr;
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-// Flags for checking compare items:
-// Don't check for existence
-#define ALLOW_DONT_CARE 0
-// Allow it being folder
-#define ALLOW_FOLDER 1
-// Allow it being file
-#define ALLOW_FILE 2
-// Allow all types (currently file and folder)
-#define ALLOW_ALL (ALLOW_FOLDER | ALLOW_FILE)
--
-static bool ConfirmCopy(int origin, int destination, int count,
+static void ThrowConfirmCopy(const CDiffContext& ctxt, int origin, int destination, int count,
const String& src, const String& dest, bool destIsSide);
-static bool ConfirmMove(int origin, int destination, int count,
+static void ThrowConfirmMove(const CDiffContext& ctxt, int origin, int destination, int count,
const String& src, const String& dest, bool destIsSide);
-static bool ConfirmDialog(const String &caption, const String &question,
- int origin, int destination, int count,
+static void ThrowConfirmationNeededException(const CDiffContext& ctxt, const String &caption, const String &question,
+ int origin, int destination, size_t count,
const String& src, const String& dest, bool destIsSide);
-static bool CheckPathsExist(const String &orig, const String& dest, int allowOrig,
- int allowDest, String & failedPath);
-
+ContentsChangedException::ContentsChangedException(const String& failpath)
+{
+ m_msg = string_format_string1(
+ _("Operation aborted!\n\nFolder contents at disks has changed, path\n%1\nwas not found.\n\nPlease refresh the compare."),
+ failpath);
+}
/**
* @brief Ask user a confirmation for copying item(s).
}
/**
- * @brief Perform an array of actions
- * @note There can be only COPY or DELETE actions, not both!
- * @sa MergeApp::SaveToVersionControl()
- * @sa MergeApp::SyncFilesToVCS()
+ * @brief Update results for FileActionItem.
+ * This functions is called to update DIFFITEM after FileActionItem.
+ * @param [in] act Action that was done.
+ * @param [in] pos List position for DIFFITEM affected.
*/
-void CDirView::PerformActionList(FileActionScript & actionScript)
+UPDATEITEM_TYPE UpdateDiffAfterOperation(const FileActionItem & act, CDiffContext& ctxt, DIFFITEM &di)
{
- // Reset suppressing VSS dialog for multiple files.
- // Set in CMainFrame::SaveToVersionControl().
- theApp.m_CheckOutMulti = false;
- theApp.m_bVssSuppressPathCheck = false;
-
- // Check option and enable putting deleted items to Recycle Bin
- if (GetOptionsMgr()->GetBool(OPT_USE_RECYCLE_BIN))
- actionScript.UseRecycleBin(true);
- else
- actionScript.UseRecycleBin(false);
+ bool bUpdateSrc = false;
+ bool bUpdateDest = false;
+ bool bRemoveItem = false;
+
+ // Use FileActionItem types for simplicity for now.
+ // Better would be to use FileAction contained, since it is not
+ // UI dependent.
+ switch (act.UIResult)
+ {
+ case FileActionItem::UI_SYNC:
+ bUpdateSrc = true;
+ bUpdateDest = true;
+ di.diffcode.setSideFlag(act.UIDestination);
+ if (act.dirflag)
+ SetDiffCompare(di, DIFFCODE::NOCMP);
+ else
+ SetDiffCompare(di, DIFFCODE::SAME);
+ SetDiffCounts(di, 0, 0);
+ break;
+
+ case FileActionItem::UI_DEL:
+ if (di.diffcode.isSideOnly(act.UIOrigin))
+ {
- ctxt.RemoveDiff(reinterpret_cast<UIntPtr>(&di));
++ ctxt.RemoveDiff(reinterpret_cast<uintptr_t>(&di));
+ bRemoveItem = true;
+ }
+ else
+ {
+ di.diffcode.unsetSideFlag(act.UIOrigin);
+ SetDiffCompare(di, DIFFCODE::NOCMP);
+ bUpdateSrc = true;
+ }
+ break;
+ }
- actionScript.SetParentWindow(this->GetSafeHwnd());
+ if (bUpdateSrc)
- ctxt.UpdateStatusFromDisk(reinterpret_cast<UIntPtr>(&di), act.UIOrigin);
++ ctxt.UpdateStatusFromDisk(reinterpret_cast<uintptr_t>(&di), act.UIOrigin);
+ if (bUpdateDest)
- ctxt.UpdateStatusFromDisk(reinterpret_cast<UIntPtr>(&di), act.UIDestination);
++ ctxt.UpdateStatusFromDisk(reinterpret_cast<uintptr_t>(&di), act.UIDestination);
- theApp.AddOperation();
- if (actionScript.Run())
- UpdateAfterFileScript(actionScript);
- theApp.RemoveOperation();
+ if (bRemoveItem)
+ return UPDATEITEM_REMOVE;
+ if (bUpdateSrc | bUpdateDest)
+ return UPDATEITEM_UPDATE;
+ return UPDATEITEM_NONE;
}
/**
- * @brief Update results after running FileActionScript.
- * This functions is called after script is finished to update
- * results (including UI).
- * @param [in] actionlist Script that was run.
+ * @brief Find the CDiffContext diffpos of an item from its left & right paths
+ * @return POSITION to item, NULL if not found.
+ * @note Filenames must be same, if they differ NULL is returned.
*/
- UIntPtr FindItemFromPaths(const CDiffContext& ctxt, const String& pathLeft, const String& pathRight)
-void CDirView::UpdateAfterFileScript(FileActionScript & actionList)
++uintptr_t FindItemFromPaths(const CDiffContext& ctxt, const String& pathLeft, const String& pathRight)
{
- bool bItemsRemoved = false;
- int curSel = GetFirstSelectedInd();
- CDirDoc *pDoc = GetDocument();
- while (actionList.GetActionItemCount()>0)
+ String file1 = paths_FindFileName(pathLeft);
+ String file2 = paths_FindFileName(pathRight);
+
+ // Filenames must be identical
+ if (string_compare_nocase(file1, file2) != 0)
+ return NULL;
+
+ String path1(pathLeft, 0, pathLeft.length() - file1.length()); // include trailing backslash
+ String path2(pathRight, 0, pathRight.length() - file2.length()); // include trailing backslash
+
+ // Path can contain (because of difftools?) '/' and '\'
+ // so for comparing purposes, convert whole path to use '\\'
+ replace_char(&*path1.begin(), '/', '\\');
+ replace_char(&*path2.begin(), '/', '\\');
+
+ String base1 = ctxt.GetLeftPath(); // include trailing backslash
+ if (path1.compare(0, base1.length(), base1.c_str()) != 0)
+ return NULL;
+ path1.erase(0, base1.length()); // turn into relative path
+ if (String::size_type length = path1.length())
+ path1.resize(length - 1); // remove trailing backslash
+
+ String base2 = ctxt.GetRightPath(); // include trailing backslash
+ if (path2.compare(0, base2.length(), base2.c_str()) != 0)
+ return NULL;
+ path2.erase(0, base2.length()); // turn into relative path
+ if (String::size_type length = path2.length())
+ path2.resize(length - 1); // remove trailing backslash
+
- UIntPtr pos = ctxt.GetFirstDiffPosition();
- while (UIntPtr currentPos = pos) // Save our current pos before getting next
++ uintptr_t pos = ctxt.GetFirstDiffPosition();
++ while (uintptr_t currentPos = pos) // Save our current pos before getting next
{
- // Start handling from tail of list, so removing items
- // doesn't invalidate our item indexes.
- FileActionItem act = actionList.RemoveTailActionItem();
- UINT_PTR diffpos = GetItemKey(act.context);
- DIFFCODE diffcode = pDoc->GetDiffByKey(diffpos).diffcode;
- bool bUpdateLeft = false;
- bool bUpdateRight = false;
-
- // Synchronized items may need VCS operations
- if (act.UIResult == FileActionItem::UI_SYNC)
+ const DIFFITEM &di = ctxt.GetNextDiffPosition(pos);
+ if (di.diffFileInfo[0].path == path1 &&
+ di.diffFileInfo[1].path == path2 &&
+ di.diffFileInfo[0].filename == file1 &&
+ di.diffFileInfo[1].filename == file2)
{
- if (theApp.m_bCheckinVCS)
- theApp.CheckinToClearCase(act.dest);
+ return currentPos;
}
-
- // Update UI
- switch (act.UIResult)
- {
- case FileActionItem::UI_SYNC:
- bUpdateLeft = true;
- bUpdateRight = true;
- break;
-
- case FileActionItem::UI_DESYNC:
- // Cannot happen yet since we have only "simple" operations
- break;
-
- case FileActionItem::UI_DEL_LEFT:
- if (diffcode.isSideFirstOnly())
- {
- if (m_bTreeMode)
- CollapseSubdir(act.context);
- m_pList->DeleteItem(act.context);
- bItemsRemoved = true;
- }
- else
- {
- bUpdateLeft = true;
- }
- break;
-
- case FileActionItem::UI_DEL_RIGHT:
- if (diffcode.isSideSecondOnly())
- {
- if (m_bTreeMode)
- CollapseSubdir(act.context);
- m_pList->DeleteItem(act.context);
- bItemsRemoved = true;
- }
- else
- {
- bUpdateRight = true;
- }
- break;
-
- case FileActionItem::UI_DEL_BOTH:
- if (m_bTreeMode)
- CollapseSubdir(act.context);
- m_pList->DeleteItem(act.context);
- bItemsRemoved = true;
- break;
- }
-
- // Update doc (difflist)
- pDoc->UpdateDiffAfterOperation(act, diffpos);
-
- if (bUpdateLeft || bUpdateRight)
- {
- pDoc->UpdateStatusFromDisk(diffpos, bUpdateLeft, bUpdateRight);
- UpdateDiffItemStatus(act.context);
- }
- }
-
- // Make sure selection is at sensible place if all selected items
- // were removed.
- if (bItemsRemoved == true)
- {
- UINT selected = GetSelectedCount();
- if (selected == 0)
- {
- if (curSel < 1)
- ++curSel;
- MoveFocus(0, curSel - 1, selected);
- }
- }
-}
-
-/// Get directories of first selected item
-bool CDirView::GetSelectedDirNames(String& strLeft, String& strRight) const
-{
- bool bResult = GetSelectedFileNames(strLeft, strRight);
-
- if (bResult)
- {
- strLeft = paths_GetPathOnly(strLeft);
- strRight = paths_GetPathOnly(strRight);
- }
- return bResult;
-}
+ }
+ return 0;
+}
/// is it possible to copy item to left ?
-bool CDirView::IsItemCopyableToLeft(const DIFFITEM & di) const
+bool IsItemCopyable(const DIFFITEM & di, int index)
{
// don't let them mess with error items
if (di.diffcode.isResultError()) return false;
return true;
}
-/// get the file names on both sides for first selected item
-bool CDirView::GetSelectedFileNames(String& strLeft, String& strRight) const
+bool IsItemExistAll(const CDiffContext& ctxt, const DIFFITEM & di)
{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel == -1)
+ // Not a valid diffitem, one of special items (e.g "..")
+ if (di.diffcode.diffcode == 0)
return false;
- GetItemFileNames(sel, strLeft, strRight);
+ if (ctxt.GetCompareDirs() == 2)
+ return di.diffcode.isSideBoth();
+ else
+ return di.diffcode.isSideAll();
+}
+
+
+/**
+ * @brief Determines if the user wants to see given item.
+ * This function determines what items to show and what items to hide. There
+ * are lots of combinations, but basically we check if menuitem is enabled or
+ * disabled and show/hide matching items. For non-recursive compare we never
+ * hide folders as that would disable user browsing into them. And we even
+ * don't really know if folders are identical or different as we haven't
+ * compared them.
+ * @param [in] di Item to check.
+ * @return true if item should be shown, false if not.
+ * @sa CDirDoc::Redisplay()
+ */
+bool IsShowable(const CDiffContext& ctxt, const DIFFITEM & di, const DirViewFilterSettings& filter)
+{
+ if (di.customFlags1 & ViewCustomFlags::HIDDEN)
+ return false;
+
+ if (di.diffcode.isResultFiltered())
+ {
+ // Treat SKIPPED as a 'super'-flag. If item is skipped and user
+ // wants to see skipped items show item regardless of other flags
+ return filter.show_skipped;
+ }
+
+ if (di.diffcode.isDirectory())
+ {
+ // Subfolders in non-recursive compare can only be skipped or unique
+ if (!ctxt.m_bRecursive)
+ {
+ // left/right filters
+ if (di.diffcode.isSideFirstOnly() && !filter.show_unique_left)
+ return false;
+ if (di.diffcode.isSideSecondOnly() && !filter.show_unique_right)
+ return false;
+
+ // result filters
+ if (di.diffcode.isResultError() /*&& !GetMainFrame()->m_bShowErrors FIXME:*/)
+ return false;
+ }
+ else // recursive mode (including tree-mode)
+ {
+ // left/right filters
+ if (di.diffcode.isSideFirstOnly() && !filter.show_unique_left)
+ return false;
+ if (di.diffcode.isSideSecondOnly() && !filter.show_unique_right)
+ return false;
+
+ // ONLY filter folders by result (identical/different) for tree-view.
+ // In the tree-view we show subfolders with identical/different
+ // status. The flat view only shows files inside folders. So if we
+ // filter by status the files inside folder are filtered too and
+ // users see files appearing/disappearing without clear logic.
+ if (filter.tree_mode)
+ {
+ // result filters
+ if (di.diffcode.isResultError()/* && !GetMainFrame()->m_bShowErrors FIXME:*/)
+ return false;
+
+ // result filters
+ if (di.diffcode.isResultSame() && !filter.show_identical)
+ return false;
+ if (di.diffcode.isResultDiff() && !filter.show_different)
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // left/right filters
+ if (di.diffcode.isSideFirstOnly() && !filter.show_unique_left)
+ return false;
+ if (di.diffcode.isSideSecondOnly() && !filter.show_unique_right)
+ return false;
+
+ // file type filters
+ if (di.diffcode.isBin() && !filter.show_binaries)
+ return false;
+
+ // result filters
+ if (di.diffcode.isResultSame() && !filter.show_identical)
+ return false;
+ if (di.diffcode.isResultError() /* && !GetMainFrame()->m_bShowErrors FIXME:*/)
+ return false;
+ if (di.diffcode.isResultDiff() && !filter.show_different)
+ return false;
+ }
return true;
}
-/// get file name on specified side for first selected item
-String CDirView::GetSelectedFileName(SIDE_TYPE stype) const
+
+/**
+ * @brief Open one selected item.
+ * @param [in] pos1 Item position.
+ * @param [in,out] di1 Pointer to first diffitem.
+ * @param [in,out] di2 Pointer to second diffitem.
+ * @param [in,out] di3 Pointer to third diffitem.
+ * @param [out] paths First/Second/Third paths.
+ * @param [out] sel1 Item's selection index in listview.
+ * @param [in,out] isDir Is item folder?
+ * return false if there was error or item was completely processed.
+ */
- bool GetOpenOneItem(const CDiffContext& ctxt, UIntPtr pos1, const DIFFITEM **di1, const DIFFITEM **di2, const DIFFITEM **di3,
++bool GetOpenOneItem(const CDiffContext& ctxt, uintptr_t pos1, const DIFFITEM **di1, const DIFFITEM **di2, const DIFFITEM **di3,
+ PathContext & paths, int & sel1, bool & isdir, String& errmsg)
{
- String left, right;
- if (!GetSelectedFileNames(left, right)) return _T("");
- return stype==SIDE_LEFT ? left : right;
+ *di1 = &ctxt.GetDiffAt(pos1);
+ *di2 = *di1;
+ *di3 = *di1;
+
+ paths = GetItemFileNames(ctxt, **di1);
+
+ if ((*di1)->diffcode.isDirectory())
+ isdir = true;
+
+ if (isdir && ((*di1)->diffcode.isExistsFirst() && (*di1)->diffcode.isExistsSecond() && (*di1)->diffcode.isExistsThird()))
+ {
+ // Check both folders exist. If either folder is missing that means
+ // folder has been changed behind our back, so we just tell user to
+ // refresh the compare.
+ PATH_EXISTENCE path1Exists = paths_DoesPathExist(paths[0]);
+ PATH_EXISTENCE path2Exists = paths_DoesPathExist(paths[1]);
+ if (path1Exists != IS_EXISTING_DIR || path2Exists != IS_EXISTING_DIR)
+ {
+ String invalid = path1Exists == IS_EXISTING_DIR ? paths[0] : paths[1];
+ errmsg = string_format_string1(
+ _("Operation aborted!\n\nFolder contents at disks has changed, path\n%1\nwas not found.\n\nPlease refresh the compare."),
+ invalid);
+ return false;
+ }
+ }
+
+ return true;
}
+
/**
- * @brief Get the file names on both sides for specified item.
- * @note Return empty strings if item is special item.
+ * @brief Open two selected items.
+ * @param [in] pos1 First item position.
+ * @param [in] pos2 Second item position.
+ * @param [in,out] di1 Pointer to first diffitem.
+ * @param [in,out] di2 Pointer to second diffitem.
+ * @param [out] paths First/Second/Third paths.
+ * @param [out] sel1 First item's selection index in listview.
+ * @param [out] sel2 Second item's selection index in listview.
+ * @param [in,out] isDir Is item folder?
+ * return false if there was error or item was completely processed.
*/
- bool GetOpenTwoItems(const CDiffContext& ctxt, SELECTIONTYPE selectionType, UIntPtr pos1, UIntPtr pos2, const DIFFITEM **di1, const DIFFITEM **di2,
-void CDirView::GetItemFileNames(int sel, String& strLeft, String& strRight) const
++bool GetOpenTwoItems(const CDiffContext& ctxt, SELECTIONTYPE selectionType, uintptr_t pos1, uintptr_t pos2, const DIFFITEM **di1, const DIFFITEM **di2,
+ PathContext & paths, int & sel1, int & sel2, bool & isDir, String& errmsg)
{
- UINT_PTR diffpos = GetItemKey(sel);
- if (diffpos == (UINT_PTR)SPECIAL_ITEM_POS)
+ String pathLeft, pathRight;
+
+ // Two items selected, get their info
+ *di1 = &ctxt.GetDiffAt(pos1);
+ *di2 = &ctxt.GetDiffAt(pos2);
+
+ // Check for binary & side compatibility & file/dir compatibility
+ if (!AreItemsOpenable(ctxt, selectionType, **di1, **di2))
{
- strLeft.erase();
- strRight.erase();
+ return false;
}
- else
+
+ String temp;
+ switch (selectionType)
{
- const DIFFITEM & di = GetDocument()->GetDiffByKey(diffpos);
- const String leftrelpath = di.diffFileInfo[0].GetFile();
- const String rightrelpath = di.diffFileInfo[1].GetFile();
- const String & leftpath = GetDocument()->GetBasePath(0);
- const String & rightpath = GetDocument()->GetBasePath(1);
- strLeft = paths_ConcatPath(leftpath, leftrelpath);
- strRight = paths_ConcatPath(rightpath, rightrelpath);
+ case SELECTIONTYPE_NORMAL:
+ // Ensure that di1 is on left (swap if needed)
+ if ((*di1)->diffcode.isSideSecondOnly() || ((*di1)->diffcode.isSideBoth() &&
+ (*di2)->diffcode.isSideFirstOnly()))
+ {
+ const DIFFITEM * temp = *di1;
+ *di1 = *di2;
+ *di2 = temp;
+ int num = sel1;
+ sel1 = sel2;
+ sel2 = num;
+ }
+ // Fill in pathLeft & pathRight
+ GetItemFileNames(ctxt, **di1, pathLeft, temp);
+ GetItemFileNames(ctxt, **di2, temp, pathRight);
+ break;
+ case SELECTIONTYPE_LEFT1LEFT2:
+ GetItemFileNames(ctxt, **di1, pathLeft, temp);
+ GetItemFileNames(ctxt, **di2, pathRight, temp);
+ break;
+ case SELECTIONTYPE_RIGHT1RIGHT2:
+ GetItemFileNames(ctxt, **di1, temp, pathLeft);
+ GetItemFileNames(ctxt, **di2, temp, pathRight);
+ break;
+ case SELECTIONTYPE_LEFT1RIGHT2:
+ GetItemFileNames(ctxt, **di1, pathLeft, temp);
+ GetItemFileNames(ctxt, **di2, temp, pathRight);
+ break;
+ case SELECTIONTYPE_LEFT2RIGHT1:
+ GetItemFileNames(ctxt, **di1, temp, pathRight);
+ GetItemFileNames(ctxt, **di2, pathLeft, temp);
+ break;
+ }
+
+ if ((*di1)->diffcode.isDirectory())
+ {
+ isDir = true;
+ if (GetPairComparability(PathContext(pathLeft, pathRight)) != IS_EXISTING_DIR)
+ {
+ errmsg = _("The selected folder is invalid.");
+ return false;
+ }
}
+
+ paths.SetLeft(pathLeft);
+ paths.SetRight(pathRight);
+
+ return true;
}
/**
- * @brief Get the file names on both sides for specified item.
- * @note Return empty strings if item is special item.
+ * @brief Open three selected items.
+ * @param [in] pos1 First item position.
+ * @param [in] pos2 Second item position.
+ * @param [in] pos3 Third item position.
+ * @param [in,out] di1 Pointer to first diffitem.
+ * @param [in,out] di2 Pointer to second diffitem.
+ * @param [in,out] di3 Pointer to third diffitem.
+ * @param [out] paths First/Second/Third paths.
+ * @param [out] sel1 First item's selection index in listview.
+ * @param [out] sel2 Second item's selection index in listview.
+ * @param [out] sel3 Third item's selection index in listview.
+ * @param [in,out] isDir Is item folder?
+ * return false if there was error or item was completely processed.
*/
- bool GetOpenThreeItems(const CDiffContext& ctxt, UIntPtr pos1, UIntPtr pos2, UIntPtr pos3, const DIFFITEM **di1, const DIFFITEM **di2, const DIFFITEM **di3,
-void CDirView::GetItemFileNames(int sel, PathContext * paths) const
++bool GetOpenThreeItems(const CDiffContext& ctxt, uintptr_t pos1, uintptr_t pos2, uintptr_t pos3, const DIFFITEM **di1, const DIFFITEM **di2, const DIFFITEM **di3,
+ PathContext & paths, int & sel1, int & sel2, int & sel3, bool & isDir, String& errmsg)
{
- String strPath[3];
- UINT_PTR diffpos = GetItemKey(sel);
- if (diffpos == SPECIAL_ITEM_POS)
+ String pathLeft, pathMiddle, pathRight;
+
+ if (!pos3)
{
- for (int nIndex = 0; nIndex < GetDocument()->m_nDirs; nIndex++)
- paths->SetPath(nIndex, _T(""));
+ // Two items selected, get their info
+ *di1 = &ctxt.GetDiffAt(pos1);
+ *di2 = &ctxt.GetDiffAt(pos2);
+
+ // Check for binary & side compatibility & file/dir compatibility
+ if (!::AreItemsOpenable(ctxt, **di1, **di2, **di2) &&
+ !::AreItemsOpenable(ctxt, **di1, **di1, **di2))
+ {
+ return false;
+ }
+ // Ensure that di1 is on left (swap if needed)
+ if ((*di1)->diffcode.isExists(0) && (*di1)->diffcode.isExists(1) && (*di2)->diffcode.isExists(2))
+ {
+ *di3 = *di2;
+ *di2 = *di1;
+ sel3 = sel2;
+ sel2 = sel1;
+ }
+ else if ((*di1)->diffcode.isExists(0) && (*di1)->diffcode.isExists(2) && (*di2)->diffcode.isExists(1))
+ {
+ *di3 = *di1;
+ sel3 = sel1;
+ }
+ else if ((*di1)->diffcode.isExists(1) && (*di1)->diffcode.isExists(2) && (*di2)->diffcode.isExists(0))
+ {
+ std::swap(*di1, *di2);
+ std::swap(sel1, sel2);
+ *di3 = *di2;
+ sel3 = sel2;
+ }
+ else if ((*di2)->diffcode.isExists(0) && (*di2)->diffcode.isExists(1) && (*di1)->diffcode.isExists(2))
+ {
+ std::swap(*di1, *di2);
+ std::swap(sel1, sel2);
+ *di3 = *di2;
+ *di2 = *di1;
+ sel3 = sel2;
+ sel2 = sel1;
+ }
+ else if ((*di2)->diffcode.isExists(0) && (*di2)->diffcode.isExists(2) && (*di1)->diffcode.isExists(1))
+ {
+ std::swap(*di1, *di2);
+ std::swap(sel1, sel2);
+ *di3 = *di1;
+ sel3 = sel1;
+ }
+ else if ((*di2)->diffcode.isExists(1) && (*di2)->diffcode.isExists(2) && (*di1)->diffcode.isExists(0))
+ {
+ *di3 = *di2;
+ sel3 = sel2;
+ }
}
else
{
}
/**
- * @brief Display file encoding dialog to user & handle user's choices
- *
- * This handles DirView invocation, so multiple files may be affected
+ * @brief Set item's view-flag.
+ * @param [in] key Item fow which flag is set.
+ * @param [in] flag Flag value to set.
+ * @param [in] mask Mask for possible flag values.
*/
-void CDirView::DoFileEncodingDialog()
+void SetItemViewFlag(DIFFITEM& di, unsigned flag, unsigned mask)
{
- CLoadSaveCodepageDlg dlg(GetDocument()->m_nDirs);
- // set up labels about what will be affected
- FormatEncodingDialogDisplays(&dlg);
- dlg.EnableSaveCodepage(false); // disallow setting a separate codepage for saving
+ unsigned curFlags = di.customFlags1;
+ curFlags &= ~mask; // Zero bits masked
+ curFlags |= flag;
+ di.customFlags1 = curFlags;
+}
- // Invoke dialog
- if (dlg.DoModal() != IDOK)
- return;
+/**
+ * @brief Set all item's view-flag.
+ * @param [in] flag Flag value to set.
+ * @param [in] mask Mask for possible flag values.
+ */
+void SetItemViewFlag(CDiffContext& ctxt, unsigned flag, unsigned mask)
+{
- UIntPtr pos = ctxt.GetFirstDiffPosition();
++ uintptr_t pos = ctxt.GetFirstDiffPosition();
- int nCodepage = dlg.GetLoadCodepage();
+ while (pos != NULL)
+ {
+ UINT curFlags = ctxt.GetCustomFlags1(pos);
+ curFlags &= ~mask; // Zero bits masked
+ curFlags |= flag;
+ ctxt.SetCustomFlags1(pos, curFlags);
+ ctxt.GetNextDiffPosition(pos);
+ }
+}
- bool doLeft = dlg.DoesAffectLeft();
- bool doRight = dlg.DoesAffectRight();
+/**
+ * @brief Mark selected items as needing for rescan.
+ * @return Count of items to rescan.
+ */
+void MarkForRescan(DIFFITEM &di)
+{
+ SetDiffStatus(di, 0, DIFFCODE::TEXTFLAGS | DIFFCODE::SIDEFLAGS | DIFFCODE::COMPAREFLAGS);
+ SetDiffStatus(di, DIFFCODE::NEEDSCAN, DIFFCODE::SCANFLAGS);
+}
- int i=-1;
- while ((i = m_pList->GetNextItem(i, LVNI_SELECTED)) != -1)
+/**
+ * @brief Return string such as "15 of 30 Files Affected" or "30 Files Affected"
+ */
+String FormatFilesAffectedString(int nFilesAffected, int nFilesTotal)
+{
+ if (nFilesAffected == nFilesTotal)
+ return string_format_string1(_("(%1 Files Affected)"), NumToStr(nFilesTotal));
+ else
+ return string_format_string2(_("(%1 of %2 Files Affected)"), NumToStr(nFilesAffected), NumToStr(nFilesTotal));
+}
+
+String FormatMenuItemString(const String& fmt1, const String& fmt2, int count, int total)
+{
+ if (count == total)
+ return string_format_string1(fmt1, NumToStr(total));
+ else
+ return string_format_string2(fmt2, NumToStr(count), NumToStr(total));
+}
+
+String FormatMenuItemString(SIDE_TYPE src, SIDE_TYPE dst, int count, int total)
+{
+ String fmt1, fmt2;
+ if (src == SIDE_LEFT && dst == SIDE_RIGHT)
{
- DIFFITEM & di = GetDiffItemRef(i);
- if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
- continue;
- if (di.diffcode.isDirectory())
- continue;
+ fmt1 = _("Left to Right (%1)");
+ fmt2 = _("Left to Right (%1 of %2)");
+ }
+ else if (src == SIDE_LEFT && dst == SIDE_MIDDLE)
+ {
+ fmt1 = _("Left to Middle (%1)");
+ fmt2 = _("Left to middle (%1 of %2)");
+ }
+ else if (src == SIDE_MIDDLE && dst == SIDE_LEFT)
+ {
+ fmt1 = _("Middle to Left (%1)");
+ fmt2 = _("Middle to Left (%1 of %2)");
+ }
+ else if (src == SIDE_MIDDLE && dst == SIDE_RIGHT)
+ {
+ fmt1 = _("Middle to Right (%1)");
+ fmt2 = _("Middle to Right (%1 of %2)");
+ }
+ else if (src == SIDE_RIGHT && dst == SIDE_LEFT)
+ {
+ fmt1 = _("Right to Left (%1)");
+ fmt2 = _("Right to Left (%1 of %2)");
+ }
+ else if (src == SIDE_RIGHT && dst == SIDE_MIDDLE)
+ {
+ fmt1 = _("Right to Middle (%1)");
+ fmt2 = _("Right to Middle (%1 of %2)");
+ }
+ return FormatMenuItemString(fmt1, fmt2, count, total);
+}
- // Does it exist on left? (ie, right or both)
- if (doLeft && di.diffcode.isExistsFirst() && di.diffFileInfo[0].IsEditableEncoding())
- {
- di.diffFileInfo[0].encoding.SetCodepage(nCodepage);
- }
- // Does it exist on right (ie, left or both)
- if (doRight && di.diffcode.isExistsSecond() && di.diffFileInfo[1].IsEditableEncoding())
- {
- di.diffFileInfo[1].encoding.SetCodepage(nCodepage);
- }
+String FormatMenuItemString(SIDE_TYPE src, int count, int total)
+{
+ String fmt1, fmt2;
+ if (src == SIDE_LEFT)
+ {
+ fmt1 = _("Left (%1)");
+ fmt2 = _("Left (%1 of %2)");
+ }
+ else if (src == SIDE_MIDDLE)
+ {
+ fmt1 = _("Middle (%1)");
+ fmt2 = _("Middle (%1 of %2)");
+ }
+ else if (src == SIDE_RIGHT)
+ {
+ fmt1 = _("Right (%1)");
+ fmt2 = _("Right (%1 of %2)");
}
- m_pList->InvalidateRect(NULL);
- m_pList->UpdateWindow();
+ return FormatMenuItemString(fmt1, fmt2, count, total);
+}
- // TODO: We could loop through any active merge windows belonging to us
- // and see if any of their files are affected
- // but, if they've been edited, we cannot throw away the user's work?
+String FormatMenuItemStringBoth(int count, int total)
+{
+ return FormatMenuItemString(_("Both (%1)"), _("Both (%1 of %2)"), count, total);
}
-void CDirView::DoUpdateFileEncodingDialog(CCmdUI* pCmdUI)
+String FormatMenuItemStringTo(SIDE_TYPE src, int count, int total)
{
- bool haveSelectedItems = (m_pList->GetNextItem(-1, LVNI_SELECTED) != -1);
- pCmdUI->Enable(haveSelectedItems);
+ String fmt1, fmt2;
+ if (src == SIDE_LEFT)
+ {
+ fmt1 = _("Left to... (%1)");
+ fmt2 = _("Left to... (%1 of %2)");
+ }
+ else if (src == SIDE_MIDDLE)
+ {
+ fmt1 = _("Middle to... (%1)");
+ fmt2 = _("Middle to... (%1 of %2)");
+ }
+ else if (src == SIDE_RIGHT)
+ {
+ fmt1 = _("Right to... (%1)");
+ fmt2 = _("Right to... (%1 of %2)");
+ }
+ return FormatMenuItemString(fmt1, fmt2, count, total);
}
/**
}
/**
- * @brief Rename selected item on both left and right sides.
- *
- * @param szNewItemName [in] New item name.
- *
- * @return true if at least one file was renamed successfully.
- */
-bool CDirView::DoItemRename(const String& szNewItemName)
+ * @brief Convert number to string.
+ * Converts number to string, with commas between digits in
+ * locale-appropriate manner.
+*/
+String NumToStr(int n)
{
- PathContext paths;
- int nDirs = GetDocument()->m_nDirs;
-
- int nSelItem = m_pList->GetNextItem(-1, LVNI_SELECTED);
- ASSERT(-1 != nSelItem);
- GetItemFileNames(nSelItem, &paths);
-
- // We must check that paths still exists
- String failpath;
- DIFFITEM &di = GetDiffItemRef(nSelItem);
- bool succeed = CheckPathsExist(paths.GetLeft(), paths.GetRight(),
- di.diffcode.isExistsFirst() ? ALLOW_FILE | ALLOW_FOLDER : ALLOW_DONT_CARE,
- di.diffcode.isExistsSecond() ? ALLOW_FILE | ALLOW_FOLDER : ALLOW_DONT_CARE,
- failpath);
- if (succeed == false)
+ return locality::NumToLocaleStr(n);
+}
+
+void ExpandSubdirs(CDiffContext& ctxt, DIFFITEM& dip)
+{
+ dip.customFlags1 |= ViewCustomFlags::EXPANDED;
- UIntPtr diffpos = ctxt.GetFirstChildDiffPosition(reinterpret_cast<UIntPtr>(&dip));
++ uintptr_t diffpos = ctxt.GetFirstChildDiffPosition(reinterpret_cast<uintptr_t>(&dip));
+ while (diffpos)
{
- WarnContentsChanged(failpath);
- return false;
+ DIFFITEM &di = ctxt.GetNextDiffRefPosition(diffpos);
+ if (!di.IsAncestor(&dip))
+ break;
+ if (di.HasChildren())
+ di.customFlags1 |= ViewCustomFlags::EXPANDED;
}
+}
- UINT_PTR key = GetItemKey(nSelItem);
- ASSERT(key != SPECIAL_ITEM_POS);
- ASSERT(&di == &GetDocument()->GetDiffRefByKey(key));
-
- bool bRename[3] = {false};
- int index;
- for (index = 0; index < nDirs; index++)
+void ExpandAllSubdirs(CDiffContext& ctxt)
+{
- UIntPtr diffpos = ctxt.GetFirstDiffPosition();
++ uintptr_t diffpos = ctxt.GetFirstDiffPosition();
+ while (diffpos)
{
- if (di.diffcode.isExists(index))
- bRename[index] = RenameOnSameDir(paths[index], szNewItemName);
+ DIFFITEM &di = ctxt.GetNextDiffRefPosition(diffpos);
+ di.customFlags1 |= ViewCustomFlags::EXPANDED;
}
+}
- int nSuccessCount = 0;
- for (index = 0; index < nDirs; index++)
- nSuccessCount += bRename[index] ? 1 : 0;
+void CollapseAllSubdirs(CDiffContext& ctxt)
+{
- UIntPtr diffpos = ctxt.GetFirstDiffPosition();
++ uintptr_t diffpos = ctxt.GetFirstDiffPosition();
+ while (diffpos)
+ {
+ DIFFITEM &di = ctxt.GetNextDiffRefPosition(diffpos);
+ di.customFlags1 &= ~ViewCustomFlags::EXPANDED;
+ }
+}
- if (nSuccessCount > 0)
+DirViewTreeState *SaveTreeState(const CDiffContext& ctxt)
+{
+ DirViewTreeState *pTreeState = new DirViewTreeState();
- UIntPtr diffpos = ctxt.GetFirstDiffPosition();
++ uintptr_t diffpos = ctxt.GetFirstDiffPosition();
+ while (diffpos)
{
- for (index = 0; index < nDirs; index++)
+ const DIFFITEM &di = ctxt.GetNextDiffPosition(diffpos);
+ if (di.HasChildren())
{
- if (bRename[index])
- di.diffFileInfo[index].filename = szNewItemName;
- else
- di.diffFileInfo[index].filename = _T("");
+ String relpath = paths_ConcatPath(di.diffFileInfo[0].path, di.diffFileInfo[0].filename);
+ pTreeState->insert(std::pair<String, bool>(relpath, !!(di.customFlags1 & ViewCustomFlags::EXPANDED)));
}
}
+ return pTreeState;
+}
- return (bRename[0] || bRename[1] || (nDirs > 2 && bRename[2]));
+void RestoreTreeState(CDiffContext& ctxt, DirViewTreeState *pTreeState)
+{
- UIntPtr diffpos = ctxt.GetFirstDiffPosition();
++ uintptr_t diffpos = ctxt.GetFirstDiffPosition();
+ while (diffpos)
+ {
+ DIFFITEM &di = ctxt.GetNextDiffRefPosition(diffpos);
+ if (di.HasChildren())
+ {
+ String relpath = paths_ConcatPath(di.diffFileInfo[0].path, di.diffFileInfo[0].filename);
+ std::map<String, bool>::iterator p = pTreeState->find(relpath);
+ if (p != pTreeState->end())
+ {
+ di.customFlags1 &= ~ViewCustomFlags::EXPANDED;
+ di.customFlags1 |= (p->second ? ViewCustomFlags::EXPANDED : 0);
+ }
+ }
+ }
}
/**
--- /dev/null
- Poco::UIntPtr FindItemFromPaths(const CDiffContext& ctxt, const String& pathLeft, const String& pathRight);
+#pragma once
+
+#include "UnicodeString.h"
+#include "DiffContext.h"
+#include "FileActionScript.h"
+#include "paths.h"
+#include "IntToIntMap.h"
+#include <algorithm>
+
+struct DIFFITEM;
+class CDiffContext;
+class PathContext;
+class PluginManager;
+class FileActionScript;
+class CTempPathContext;
+
+/**
+ * @brief Folder compare icon indexes.
+ * This enum defines indexes for imagelist used for folder compare icons.
+ * Note that this enum must be in synch with code in OnInitialUpdate() and
+ * GetColImage(). Also remember that icons are in resource file...
+ */
+enum
+{
+ DIFFIMG_LUNIQUE,
+ DIFFIMG_MUNIQUE,
+ DIFFIMG_RUNIQUE,
+ DIFFIMG_LMISSING,
+ DIFFIMG_MMISSING,
+ DIFFIMG_RMISSING,
+ DIFFIMG_DIFF,
+ DIFFIMG_SAME,
+ DIFFIMG_BINSAME,
+ DIFFIMG_BINDIFF,
+ DIFFIMG_LDIRUNIQUE,
+ DIFFIMG_MDIRUNIQUE,
+ DIFFIMG_RDIRUNIQUE,
+ DIFFIMG_LDIRMISSING,
+ DIFFIMG_MDIRMISSING,
+ DIFFIMG_RDIRMISSING,
+ DIFFIMG_SKIP,
+ DIFFIMG_DIRSKIP,
+ DIFFIMG_DIRDIFF,
+ DIFFIMG_DIRSAME,
+ DIFFIMG_DIR,
+ DIFFIMG_ERROR,
+ DIFFIMG_DIRUP,
+ DIFFIMG_DIRUP_DISABLE,
+ DIFFIMG_ABORT,
+ DIFFIMG_TEXTDIFF,
+ DIFFIMG_TEXTSAME,
+};
+
+typedef enum {
+ SIDE_LEFT = 1,
+ SIDE_MIDDLE,
+ SIDE_RIGHT
+} SIDE_TYPE;
+
+typedef enum {
+ SELECTIONTYPE_NORMAL,
+ SELECTIONTYPE_LEFT1LEFT2,
+ SELECTIONTYPE_RIGHT1RIGHT2,
+ SELECTIONTYPE_LEFT1RIGHT2,
+ SELECTIONTYPE_LEFT2RIGHT1
+} SELECTIONTYPE;
+
+typedef enum {
+ UPDATEITEM_NONE,
+ UPDATEITEM_UPDATE,
+ UPDATEITEM_REMOVE
+} UPDATEITEM_TYPE;
+
+struct ViewCustomFlags
+{
+ enum
+ {
+ // We use extra bits so that no valid values are 0
+ // and each set of flags is in a different hex digit
+ // to make debugging easier
+ // These can always be packed down in the future
+ INVALID_CODE = 0,
+ VISIBILITY = 0x3, VISIBLE = 0x1, HIDDEN = 0x2, EXPANDED = 0x4
+ };
+};
+
+struct AllowUpwardDirectory
+{
+ enum ReturnCode
+ {
+ Never,
+ No,
+ ParentIsRegularPath,
+ ParentIsTempPath
+ };
+};
+
+
+struct DirViewFilterSettings
+{
+ template<class GetOptionBool>
+ DirViewFilterSettings(GetOptionBool getoptbool)
+ {
+ show_skipped = getoptbool(OPT_SHOW_SKIPPED);
+ show_unique_left = getoptbool(OPT_SHOW_UNIQUE_LEFT);
+ show_unique_right = getoptbool(OPT_SHOW_UNIQUE_RIGHT);
+ show_binaries = getoptbool(OPT_SHOW_BINARIES);
+ show_identical = getoptbool(OPT_SHOW_IDENTICAL);
+ show_different = getoptbool(OPT_SHOW_DIFFERENT);
+ tree_mode = getoptbool(OPT_TREE_MODE);
+ };
+ bool show_skipped;
+ bool show_unique_left;
+ bool show_unique_right;
+ bool show_binaries;
+ bool show_identical;
+ bool show_different;
+ bool tree_mode;
+};
+
+typedef std::map<String, bool> DirViewTreeState;
+
+String NumToStr(int n);
+String FormatFilesAffectedString(int nFilesAffected, int nFilesTotal);
+String FormatMenuItemString(SIDE_TYPE src, int count, int total);
+String FormatMenuItemString(SIDE_TYPE src, SIDE_TYPE dst, int count, int total);
+String FormatMenuItemStringBoth(int count, int total);
+String FormatMenuItemString(const String& fmt1, const String& fmt2, int count, int total);
+String FormatMenuItemStringTo(SIDE_TYPE src, int count, int total);
+
+void ConfirmActionList(const CDiffContext& ctxt, const FileActionScript & actionList);
+UPDATEITEM_TYPE UpdateDiffAfterOperation(const FileActionItem & act, CDiffContext& ctxt, DIFFITEM &di);
+
- bool GetOpenOneItem(const CDiffContext& ctxt, Poco::UIntPtr pos1, const DIFFITEM **di1, const DIFFITEM **di2, const DIFFITEM **di3,
++uintptr_t FindItemFromPaths(const CDiffContext& ctxt, const String& pathLeft, const String& pathRight);
+
+bool IsItemCopyable(const DIFFITEM & di, int index);
+bool IsItemDeletable(const DIFFITEM & di, int index);
+bool IsItemDeletableOnBoth(const CDiffContext& ctxt, const DIFFITEM & di);
+bool IsItemOpenable(const CDiffContext& ctxt, const DIFFITEM & di, bool treemode);
+bool AreItemsOpenable(const CDiffContext& ctxt, SELECTIONTYPE selectionType, const DIFFITEM & di1, const DIFFITEM & di2);
+bool AreItemsOpenable(const CDiffContext& ctxt, const DIFFITEM & di1, const DIFFITEM & di2, const DIFFITEM & di3);
+bool IsItemOpenableOn(const DIFFITEM & di, int index);
+bool IsItemOpenableOnWith(const DIFFITEM & di, int index);
+bool IsItemCopyableToOn(const DIFFITEM & di, int index);
+bool IsItemNavigableDiff(const CDiffContext& ctxt, const DIFFITEM & di);
+bool IsItemExistAll(const CDiffContext& ctxt, const DIFFITEM & di);
+bool IsShowable(const CDiffContext& ctxt, const DIFFITEM & di, const DirViewFilterSettings& filter);
+
- bool GetOpenTwoItems(const CDiffContext& ctxt, SELECTIONTYPE selectionType, Poco::UIntPtr pos1, Poco::UIntPtr pos2, const DIFFITEM **di1, const DIFFITEM **di2,
++bool GetOpenOneItem(const CDiffContext& ctxt, uintptr_t pos1, const DIFFITEM **di1, const DIFFITEM **di2, const DIFFITEM **di3,
+ PathContext &paths, int & sel1, bool & isDir, String& errmsg);
- bool GetOpenThreeItems(const CDiffContext& ctxt, Poco::UIntPtr pos1, Poco::UIntPtr pos2, Poco::UIntPtr pos3, const DIFFITEM **di1, const DIFFITEM **di2, const DIFFITEM **di3,
++bool GetOpenTwoItems(const CDiffContext& ctxt, SELECTIONTYPE selectionType, uintptr_t pos1, uintptr_t pos2, const DIFFITEM **di1, const DIFFITEM **di2,
+ PathContext &paths, int & sel1, int & sel2, bool & isDir, String& errmsg);
++bool GetOpenThreeItems(const CDiffContext& ctxt, uintptr_t pos1, uintptr_t pos2, uintptr_t pos3, const DIFFITEM **di1, const DIFFITEM **di2, const DIFFITEM **di3,
+ PathContext &paths, int & sel1, int & sel2, int & sel3, bool & isDir, String& errmsg);
+
+void GetItemFileNames(const CDiffContext& ctxt, const DIFFITEM& di, String& strLeft, String& strRight);
+PathContext GetItemFileNames(const CDiffContext& ctxt, const DIFFITEM& di);
+String GetItemFileName(const CDiffContext& ctx, const DIFFITEM & di, int index);
+int GetColImage(const CDiffContext&ctxt, const DIFFITEM & di);
+
+void SetDiffStatus(DIFFITEM& di, unsigned diffcode, unsigned mask);
+void SetDiffCompare(DIFFITEM& di, unsigned diffcode);
+void SetDiffSide(DIFFITEM& di, unsigned diffcode);
+void SetDiffCounts(DIFFITEM& di, unsigned diffs, unsigned ignored);
+void SetItemViewFlag(DIFFITEM& di, unsigned flag, unsigned mask);
+void SetItemViewFlag(CDiffContext& ctxt, unsigned flag, unsigned mask);
+void MarkForRescan(DIFFITEM& di);
+
+bool RenameOnSameDir(const String& szOldFileName, const String& szNewFileName);
+
+void ExpandSubdirs(CDiffContext& ctxt, DIFFITEM& dip);
+void ExpandAllSubdirs(CDiffContext &ctxt);
+void CollapseAllSubdirs(CDiffContext &ctxt);
+DirViewTreeState *SaveTreeState(const CDiffContext& ctxt);
+void RestoreTreeState(CDiffContext &ctxt, DirViewTreeState *pTreeState);
+
+AllowUpwardDirectory::ReturnCode
+CheckAllowUpwardDirectory(const CDiffContext& ctxt, const CTempPathContext *pTempPathContext, PathContext &pathsParent);
+
+inline int SideToIndex(const CDiffContext& ctxt, SIDE_TYPE stype)
+{
+ switch (stype)
+ {
+ case SIDE_MIDDLE: return ctxt.GetCompareDirs() == 3 ? 1 : -1;
+ case SIDE_RIGHT: return ctxt.GetCompareDirs() - 1;
+ default: return 0;
+ }
+}
+
+struct ConfirmationNeededException
+{
+ String m_caption;
+ String m_question;
+ String m_fromText;
+ String m_toText;
+ String m_fromPath;
+ String m_toPath;
+};
+
+struct ContentsChangedException
+{
+ ContentsChangedException(const String& failpath);
+ String m_msg;
+};
+
+struct DirActions
+{
+ typedef bool (DirActions::*method_type2)(const DIFFITEM& di) const;
+ typedef FileActionScript *(DirActions::*method_type)(FileActionScript *, const std::pair<int, const DIFFITEM *> it) const;
+
+ DirActions(const CDiffContext& ctxt, const bool RO[], method_type func = NULL, method_type2 func2 = NULL) :
+ m_ctxt(ctxt), m_RO(RO), m_cur_method(func), m_cur_method2(func2) {}
+
+ template <SIDE_TYPE src, SIDE_TYPE dst>
+ bool IsItemCopyableOnTo(const DIFFITEM& di) const
+ {
+ return (di.diffcode.diffcode != 0 && !m_RO[SideToIndex(m_ctxt, dst)] && ::IsItemCopyable(di, SideToIndex(m_ctxt, src)));
+ }
+
+ template <SIDE_TYPE src>
+ bool IsItemCopyableToOn(const DIFFITEM& di) const
+ {
+ return (di.diffcode.diffcode != 0 && ::IsItemCopyableToOn(di, SideToIndex(m_ctxt, src)));
+ }
+
+ template <SIDE_TYPE src>
+ bool IsItemMovableToOn(const DIFFITEM& di) const
+ {
+ const int idx = SideToIndex(m_ctxt, src);
+ return (di.diffcode.diffcode != 0 && !m_RO[idx] && IsItemDeletable(di, idx) && ::IsItemCopyableToOn(di, idx));
+ }
+
+ template <SIDE_TYPE src>
+ bool IsItemDeletableOn(const DIFFITEM& di) const
+ {
+ const int idx = SideToIndex(m_ctxt, src);
+ return (di.diffcode.diffcode != 0 && !m_RO[idx] && IsItemDeletable(di, idx));
+ }
+ bool IsItemDeletableOnBoth(const DIFFITEM& di) const
+ {
+ if (di.diffcode.diffcode != 0)
+ {
+ int i;
+ for (i = 0; i < m_ctxt.GetCompareDirs(); ++i)
+ {
+ if (m_RO[i] || !IsItemDeletable(di, i))
+ break;
+ }
+ return (i == m_ctxt.GetCompareDirs());
+ }
+ return false;
+ }
+ bool IsItemDeletableOnEitherOrBoth(const DIFFITEM& di) const
+ {
+ if (di.diffcode.diffcode != 0)
+ {
+ int i;
+ for (i = 0; i < m_ctxt.GetCompareDirs(); ++i)
+ {
+ if (!m_RO[i] && IsItemDeletable(di, i))
+ break;
+ }
+ return (i < m_ctxt.GetCompareDirs());
+ }
+ return false;
+ }
+
+ template <SIDE_TYPE src>
+ bool IsItemOpenanbleOn(const DIFFITEM& di) const
+ {
+ return (di.diffcode.diffcode != 0 && IsItemOpenableOn(di, SideToIndex(m_ctxt, src)));
+ }
+
+ template <SIDE_TYPE src>
+ bool IsItemOpenanbleOnWith(const DIFFITEM& di) const
+ {
+ return (di.diffcode.diffcode != 0 && IsItemOpenableOnWith(di, SideToIndex(m_ctxt, src)));
+ }
+
+ bool IsItemFile(const DIFFITEM& di) const
+ {
+ return (di.diffcode.diffcode != 0 && di.diffcode.isDirectory());
+ }
+
+ template <SIDE_TYPE src>
+ bool IsItemExist(const DIFFITEM& di) const
+ {
+ return (di.diffcode.diffcode != 0 && di.diffcode.isExists(SideToIndex(m_ctxt, src)));
+ }
+
+ template <SIDE_TYPE src>
+ bool IsItemEditableEncoding(const DIFFITEM& di) const
+ {
+ const int index = SideToIndex(m_ctxt, src);
+ return (di.diffcode.diffcode != 0 && di.diffcode.isExists(index) && di.diffFileInfo[index].IsEditableEncoding());
+ }
+
+ bool IsItemNavigableDiff(const DIFFITEM& di) const
+ {
+ return ::IsItemNavigableDiff(m_ctxt, di);
+ }
+
+ FileActionScript *CopyItem(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, SIDE_TYPE src, SIDE_TYPE dst) const
+ {
+ const DIFFITEM& di = *it.second;
+ const int srcidx = SideToIndex(m_ctxt, src);
+ const int dstidx = SideToIndex(m_ctxt, dst);
+ if (di.diffcode.diffcode != 0 && !m_RO[dstidx] && IsItemCopyable(di, srcidx))
+ {
+ FileActionItem act;
+ act.src = GetItemFileName(m_ctxt, di, srcidx);
+ act.dest = GetItemFileName(m_ctxt, di, dstidx);
+
+ // We must check that paths still exists
+ if (paths_DoesPathExist(act.src) == DOES_NOT_EXIST)
+ throw ContentsChangedException(act.src);
+
+ act.context = it.first;
+ act.dirflag = di.diffcode.isDirectory();
+ act.atype = FileAction::ACT_COPY;
+ act.UIResult = FileActionItem::UI_SYNC;
+ act.UIOrigin = srcidx;
+ act.UIDestination = dstidx;
+ pscript->AddActionItem(act);
+ }
+ return pscript;
+ }
+
+ template<SIDE_TYPE src, SIDE_TYPE to>
+ FileActionScript *Copy(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
+ {
+ return CopyItem(pscript, it, src, to);
+ }
+
+ FileActionScript *DeleteItem(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, SIDE_TYPE src) const
+ {
+ const DIFFITEM& di = *it.second;
+ const int index = SideToIndex(m_ctxt, src);
+ if (di.diffcode.diffcode != 0 && !m_RO[index] && IsItemDeletable(di, index))
+ {
+ FileActionItem act;
+ act.src = GetItemFileName(m_ctxt, di, index);
+
+ // We must check that path still exists
+ if (paths_DoesPathExist(act.src) == DOES_NOT_EXIST)
+ throw ContentsChangedException(act.src);
+
+ act.context = it.first;
+ act.dirflag = di.diffcode.isDirectory();
+ act.atype = FileAction::ACT_DEL;
+ act.UIOrigin = index;
+ act.UIResult = FileActionItem::UI_DEL;
+ pscript->AddActionItem(act);
+ }
+ return pscript;
+ }
+
+ template<SIDE_TYPE src>
+ FileActionScript *DeleteOn(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
+ {
+ return DeleteItem(pscript, it, src);
+ }
+
+ FileActionScript *DeleteOnBoth(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
+ {
+ const DIFFITEM& di = *it.second;
+
+ if (di.diffcode.diffcode != 0 && IsItemDeletableOnBoth(di) &&
+ (std::count(m_RO, m_RO + m_ctxt.GetCompareDirs(), true) == 0))
+ {
+ for (int i = 0; i < m_ctxt.GetCompareDirs(); ++i)
+ {
+ FileActionItem act;
+ act.src = GetItemFileName(m_ctxt, di, i);
+ // We must first check that paths still exists
+ if (paths_DoesPathExist(act.src) == DOES_NOT_EXIST)
+ throw ContentsChangedException(act.src);
+ act.context = it.first;
+ act.dirflag = di.diffcode.isDirectory();
+ act.atype = FileAction::ACT_DEL;
+ act.UIOrigin = i;
+ act.UIResult = FileActionItem::UI_DEL;
+ pscript->AddActionItem(act);
+ }
+ }
+ return pscript;
+ }
+
+ FileActionScript *DeleteOnEitherOrBoth(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
+ {
+ const DIFFITEM& di = *it.second;
+ if (di.diffcode.diffcode != 0)
+ {
+ for (int i = 0; i < m_ctxt.GetCompareDirs(); ++i)
+ {
+ if (IsItemDeletable(di, i) && !m_RO[i])
+ {
+ FileActionItem act;
+ act.src = GetItemFileName(m_ctxt, di, i);
+ act.UIResult = FileActionItem::UI_DEL;
+ act.dirflag = di.diffcode.isDirectory();
+ act.context = it.first;
+ act.UIOrigin = i;
+ act.atype = FileAction::ACT_DEL;
+ pscript->AddActionItem(act);
+ }
+ }
+ }
+ return pscript;
+ }
+
+ FileActionScript *CopyOrMoveItemTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, FileAction::ACT_TYPE atype, SIDE_TYPE src) const
+ {
+ const int index = SideToIndex(m_ctxt, src);
+ const DIFFITEM& di = *it.second;
+
+ if (di.diffcode.diffcode != 0 && IsItemCopyable(di, index) &&
+ (atype == FileAction::ACT_MOVE ? (!m_RO[index] && IsItemDeletable(di, index)) : true))
+ {
+ FileActionItem act;
+ act.src = GetItemFileName(m_ctxt, di, index);
+
+ // We must check that path still exists
+ if (paths_DoesPathExist(act.src) == DOES_NOT_EXIST)
+ throw ContentsChangedException(act.src);
+
+ act.dest = paths_ConcatPath(pscript->m_destBase, di.diffFileInfo[index].filename);
+ act.dirflag = di.diffcode.isDirectory();
+ act.context = it.first;
+ act.atype = atype;
+ act.UIResult = (atype == FileAction::ACT_COPY) ? FileActionItem::UI_DONT_CARE : FileActionItem::UI_DEL;
+ act.UIOrigin = index;
+ pscript->AddActionItem(act);
+ }
+ return pscript;
+ }
+
+ template<SIDE_TYPE src>
+ FileActionScript *CopyTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
+ {
+ return CopyOrMoveItemTo(pscript, it, FileAction::ACT_COPY, src);
+ }
+
+ template<SIDE_TYPE src>
+ FileActionScript *MoveTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
+ {
+ return CopyOrMoveItemTo(pscript, it, FileAction::ACT_MOVE, src);
+ }
+
+ FileActionScript *operator()(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
+ {
+ return ((*this).*m_cur_method)(pscript, it);
+ }
+
+ bool operator()(const DIFFITEM & di) const
+ {
+ return ((*this).*m_cur_method2)(di);
+ }
+
+ method_type m_cur_method;
+ method_type2 m_cur_method2;
+ const CDiffContext& m_ctxt;
+ const bool *m_RO;
+};
+
+struct Counts {
+ Counts() : count(0), total(0) {}
+ Counts(int c, int t): count(c), total(t) {}
+ int count;
+ int total;
+};
+
+template<class InputIterator, class Predicate>
+Counts Count(const InputIterator& begin, const InputIterator& end, const Predicate& pred)
+{
+ int count = 0, total = 0;
+ for (InputIterator it = begin; it != end; ++it)
+ {
+ if (pred(*it))
+ ++count;
+ ++total;
+ }
+ return Counts(count, total);
+}
+
+struct ContextMenuCounts {
+ int nTotal; // total #items (includes files & directories, either side)
+ int nCopyable[3];
+ int nDeletable[3];
+ int nDeletableOnBoth;
+ int nOpenable[3];
+ int nOpenableOnBoth;
+ int nOpenableOnWith[3];
+ int nDiffItems;
+};
+
+template<class InputIterator>
+ContextMenuCounts CountForContextMenu(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt)
+{
+ ContextMenuCounts counts = {0};
+ int nDirs = ctxt.GetCompareDirs();
+ for (InputIterator it = begin; it != end; ++it)
+ {
+ const DIFFITEM& di = *it;
+ if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
+ continue;
+ int nOpenablePerItem = 0;
+ for (int j = 0; j < nDirs; ++j)
+ {
+ if (IsItemCopyable(di, j))
+ ++counts.nCopyable[j];
+ if (IsItemDeletable(di, j))
+ ++counts.nDeletable[j];
+ if (IsItemOpenableOn(di, j))
+ {
+ ++nOpenablePerItem;
+ ++counts.nOpenable[j];
+ }
+ if (IsItemOpenableOnWith(di, j))
+ ++counts.nOpenableOnWith[j];
+ }
+ if (IsItemDeletableOnBoth(ctxt, di))
+ ++counts.nDeletableOnBoth;
+
+ if (IsItemNavigableDiff(ctxt, di))
+ ++counts.nDiffItems;
+
+ if (nOpenablePerItem == nDirs)
+ ++counts.nOpenableOnBoth;
+
+ ++counts.nTotal;
+ }
+ return counts;
+}
+
+
+/**
+ * @brief Rename selected item on both left and right sides.
+ *
+ * @param szNewItemName [in] New item name.
+ *
+ * @return true if at least one file was renamed successfully.
+ */
+template<class InputIterator>
+bool DoItemRename(InputIterator& it, const CDiffContext& ctxt, const String& szNewItemName)
+{
+ PathContext paths;
+ int nDirs = ctxt.GetCompareDirs();
+
+ assert(it != InputIterator());
+
+ // We must check that paths still exists
+ String failpath;
+ DIFFITEM &di = *it;
+ paths = ::GetItemFileNames(ctxt, di);
+ for (int i = 0; i < paths.GetSize(); ++i)
+ {
+ if (paths_DoesPathExist(paths[i]) == DOES_NOT_EXIST)
+ throw ContentsChangedException(failpath);
+ }
+
+ bool bRename[3] = {false};
+ int index;
+ for (index = 0; index < nDirs; index++)
+ {
+ if (di.diffcode.isExists(index))
+ bRename[index] = RenameOnSameDir(paths[index], szNewItemName);
+ }
+
+ int nSuccessCount = 0;
+ for (index = 0; index < nDirs; index++)
+ nSuccessCount += bRename[index] ? 1 : 0;
+
+ if (nSuccessCount > 0)
+ {
+ for (index = 0; index < nDirs; index++)
+ {
+ if (bRename[index])
+ di.diffFileInfo[index].filename = szNewItemName;
+ else
+ di.diffFileInfo[index].filename = _T("");
+ }
+ }
+
+ return (bRename[0] || bRename[1] || (nDirs > 2 && bRename[2]));
+}
+
+template<class InputIterator, class OutputIterator>
+OutputIterator CopyPathnames(const InputIterator& begin, const InputIterator& end, OutputIterator result, SIDE_TYPE stype, const CDiffContext& ctxt)
+{
+ const int index = SideToIndex(ctxt, stype);
+ for (InputIterator it = begin; it != end; ++it)
+ {
+ const DIFFITEM& di = *it;
+ if (di.diffcode.isExists(index))
+ {
+ *result = GetItemFileName(ctxt, di, index);
+ ++result;
+ }
+ }
+ return result;
+}
+
+template<class InputIterator, class OutputIterator>
+OutputIterator CopyBothPathnames(const InputIterator& begin, const InputIterator& end, OutputIterator result, const CDiffContext& ctxt)
+{
+ for (InputIterator it = begin; it != end; ++it)
+ {
+ const DIFFITEM& di = *it;
+ for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
+ {
+ if (di.diffcode.isExists(i))
+ {
+ *result = GetItemFileName(ctxt, di, i);
+ ++result;
+ }
+ }
+ }
+ return result;
+}
+
+template<class InputIterator, class OutputIterator>
+OutputIterator CopyFilenames(const InputIterator& begin, const InputIterator& end, OutputIterator result)
+{
+ for (InputIterator it = begin; it != end; ++it)
+ {
+ const DIFFITEM& di = *it;
+ if (!di.diffcode.isDirectory())
+ {
+ *result = di.diffFileInfo[0].filename;
+ ++result;
+ }
+ }
+ return result;
+}
+
+template<class InputIterator, class OutputIterator>
+OutputIterator CopyPathnamesForDragAndDrop(const InputIterator& begin, const InputIterator& end, OutputIterator result, const CDiffContext& ctxt)
+{
+ for (InputIterator it = begin; it != end; ++it)
+ {
+ const DIFFITEM& di = *it;
+
+ // check for special items (e.g not "..")
+ if (di.diffcode.diffcode == 0)
+ continue;
+
+ if (!IsItemExistAll(ctxt, di) || di.diffcode.isResultDiff())
+ {
+ for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
+ {
+ if (di.diffcode.isExists(i))
+ {
+ *result = GetItemFileName(ctxt, di, i);
+ ++result;
+ }
+ }
+ }
+ else
+ {
+ *result = GetItemFileName(ctxt, di, 0);
+ ++result;
+ }
+ }
+ return result;
+}
+
+template<class InputIterator, class BinaryFunction>
+void ApplyFolderNameAndFileName(const InputIterator& begin, const InputIterator& end, SIDE_TYPE stype,
+ const CDiffContext& ctxt, BinaryFunction func)
+{
+ int index = SideToIndex(ctxt, stype);
+ for (InputIterator it = begin; it != end; ++it)
+ {
+ const DIFFITEM& di = *it;
+ if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
+ continue;
+ String filename = di.diffFileInfo[index].filename;
+ String currentDir = di.getFilepath(index, ctxt.GetNormalizedPath(index));
+ func(currentDir, filename);
+ }
+}
+
+/**
+ * @brief Apply specified setting for prediffing to all selected items
+ */
+template<class InputIterator>
+void ApplyPluginPrediffSetting(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt, int newsetting)
+{
+ // Unlike other group actions, here we don't build an action list
+ // to execute; we just apply this change directly
+ for (InputIterator it = begin; it != end; ++it)
+ {
+ const DIFFITEM& di = *it;
+ if (!di.diffcode.isDirectory())
+ {
+ String filteredFilenames;
+ for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
+ {
+ if (di.diffcode.isExists(i))
+ {
+ if (!filteredFilenames.empty()) filteredFilenames += _T("|");
+ filteredFilenames += ::GetItemFileName(ctxt, di, i);
+ }
+ }
+ PackingInfo * infoUnpacker = 0;
+ PrediffingInfo * infoPrediffer = 0;
+ const_cast<CDiffContext&>(ctxt).FetchPluginInfos(filteredFilenames, &infoUnpacker, &infoPrediffer);
+ infoPrediffer->Initialize(newsetting);
+ }
+ }
+}
+
+/**
+ * @brief Updates just before displaying plugin context view in list
+ */
+template<class InputIterator>
+std::pair<int, int> CountPredifferYesNo(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt)
+{
+ int nPredifferYes = 0;
+ int nPredifferNo = 0;
+
+ for (InputIterator it = begin; it != end; ++it)
+ {
+ const DIFFITEM& di = *it;
+ if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
+ continue;
+
+ // note the prediffer flag for 'files present on both sides and not skipped'
+ if (!di.diffcode.isDirectory() && !di.diffcode.isBin() && IsItemExistAll(ctxt, di)
+ && !di.diffcode.isResultFiltered())
+ {
+ PathContext files = GetItemFileNames(ctxt, di);
+ String filteredFilenames = string_join(files.begin(), files.end(), _T("|"));
+ PackingInfo * unpacker;
+ PrediffingInfo * prediffer;
+ const_cast<CDiffContext&>(ctxt).FetchPluginInfos(filteredFilenames, &unpacker, &prediffer);
+ if (prediffer->bToBeScanned == 1 || prediffer->pluginName.empty() == false)
+ nPredifferYes ++;
+ else
+ nPredifferNo ++;
+ }
+ }
+ return std::make_pair(nPredifferYes, nPredifferNo);
+}
+
+template<class InputIterator>
+IntToIntMap CountCodepages(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt)
+{
+ IntToIntMap map;
+ for (InputIterator it = begin; it != end; ++it)
+ {
+ const DIFFITEM& di = *it;
+ for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
+ {
+ if (di.diffcode.diffcode != 0 && di.diffcode.isExists(i))
+ map.Increment(di.diffFileInfo[i].encoding.m_codepage);
+ }
+ }
+ return map;
+}
+
+template<class InputIterator>
+void ApplyCodepage(const InputIterator& begin, const InputIterator& end, CDiffContext& ctxt, const bool affect[3], int nCodepage)
+{
+ for (InputIterator it = begin; it != end; ++it)
+ {
+ DIFFITEM& di = *it;
+ if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
+ continue;
+ if (di.diffcode.isDirectory())
+ continue;
+
+ for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
+ {
+ // Does it exist on left? (ie, right or both)
+ if (affect[i] && di.diffcode.isExists(i) && di.diffFileInfo[i].IsEditableEncoding())
+ {
+ di.diffFileInfo[i].encoding.SetCodepage(nCodepage);
+ }
+ }
+ }
+}
+
+/// get file name on specified side for first selected item
+template<class InputIterator>
+String GetSelectedFileName(InputIterator& it, SIDE_TYPE stype, const CDiffContext& ctxt)
+{
+ if (it == InputIterator())
+ return _T("");
+ return GetItemFileName(ctxt, *it, SideToIndex(ctxt, stype));
+}
* calls slow DirView functions to get item position and to update GUI.
* Use UpdateStatusFromDisk() function instead.
*/
- void CDirDoc::ReloadItemStatus(uintptr_t_t_t_t diffPos, int index)
-void CDirDoc::ReloadItemStatus(uintptr_t diffPos, bool bLeft, bool bRight)
++void CDirDoc::ReloadItemStatus(uintptr_t diffPos, int index)
{
// in case just copied (into existence) or modified
- UpdateStatusFromDisk(diffPos, bLeft, bRight);
+ m_pCtxt->UpdateStatusFromDisk(diffPos, index);
int nIdx = m_pDirView->GetItemIndex(diffPos);
if (nIdx != -1)
void CDirDoc::UpdateChangedItem(PathContext &paths,
UINT nDiffs, UINT nTrivialDiffs, BOOL bIdentical)
{
- uintptr_t_t_t pos = FindItemFromPaths(*m_pCtxt, paths.GetLeft(), paths.GetRight());
- uintptr_t pos = FindItemFromPaths(paths.GetLeft(), paths.GetRight());
++ uintptr_t pos = FindItemFromPaths(*m_pCtxt, paths.GetLeft(), paths.GetRight());
// If we failed files could have been swapped so lets try again
if (!pos)
- pos = FindItemFromPaths(paths.GetRight(), paths.GetLeft());
+ pos = FindItemFromPaths(*m_pCtxt, paths.GetRight(), paths.GetLeft());
// Update status if paths were found for items.
// Fail means we had unique items compared as 'renamed' items
--- /dev/null
- if (m_pList->GetItemData(m_sel) == reinterpret_cast<void *>((Poco::UIntPtr)-1L))
+/**
+ * @file DirItemIterator.h
+ *
+ * @brief Declaration DirItemIterator classes.
+ */
+// ID line follows -- this is updated by SVN
+// $Id$
+
+#pragma once
+
+#include <iterator>
+#include <utility>
+#include "IListCtrl.h"
+
+struct DIFFITEM;
+
+class DirItemWithIndexIterator : public std::iterator<std::forward_iterator_tag, std::pair<int, DIFFITEM *> >
+{
+public:
+ DirItemWithIndexIterator(IListCtrl *pList, int sel = -1, bool selected = false, bool reverse = false) :
+ m_pList(pList), m_sel(sel), m_selected(selected), m_reverse(reverse)
+ {
+ if (m_sel == -1)
+ {
+ if (m_reverse)
+ {
+ int last = m_pList->GetRowCount() - 1;
+ if (!m_selected || m_pList->IsSelectedItem(last))
+ m_sel = last;
+ else
+ m_sel = m_pList->GetNextItem(last, m_selected, m_reverse);
+ }
+ else
+ m_sel = m_pList->GetNextItem(-1, m_selected, m_reverse);
+ }
+ if (m_sel != -1)
+ {
++ if (m_pList->GetItemData(m_sel) == reinterpret_cast<void *>((uintptr_t)-1L))
+ m_sel = m_pList->GetNextItem(m_sel, m_selected, m_reverse);
+ }
+ }
+
+ DirItemWithIndexIterator() : m_pList(NULL), m_sel(-1)
+ {
+ }
+
+ ~DirItemWithIndexIterator() {}
+
+ DirItemWithIndexIterator& operator=(const DirItemWithIndexIterator& it)
+ {
+ m_sel = it.m_sel;
+ m_pList = it.m_pList;
+ return *this;
+ }
+
+ DirItemWithIndexIterator& operator++()
+ {
+ m_sel = m_pList->GetNextItem(m_sel, m_selected, m_reverse);
+ return *this;
+ }
+
+ std::pair<int, DIFFITEM *> operator*()
+ {
+ return std::make_pair(m_sel, reinterpret_cast<DIFFITEM *>(m_pList->GetItemData(m_sel)));
+ }
+
+ bool operator==(const DirItemWithIndexIterator& it) const
+ {
+ return m_sel == it.m_sel;
+ }
+
+ bool operator!=(const DirItemWithIndexIterator& it) const
+ {
+ return m_sel != it.m_sel;
+ }
+
+ bool m_selected;
+ bool m_reverse;
+ int m_sel;
+
+private:
+ IListCtrl *m_pList;
+};
+
+class DirItemIterator : public std::iterator<std::forward_iterator_tag, DIFFITEM*>
+{
+public:
+ DirItemIterator(IListCtrl *pList, int sel = -1, bool selected = false, bool reverse = false) :
+ m_pList(pList), m_sel(sel), m_selected(selected), m_reverse(reverse), m_pdi(NULL)
+ {
+ if (m_sel == -1)
+ {
+ if (m_reverse)
+ {
+ int last = m_pList->GetRowCount() - 1;
+ if (!m_selected || m_pList->IsSelectedItem(last))
+ m_sel = last;
+ else
+ m_sel = m_pList->GetNextItem(last, m_selected, m_reverse);
+ }
+ else
+ m_sel = m_pList->GetNextItem(-1, m_selected, m_reverse);
+ }
+ if (m_sel != -1)
+ {
+ m_pdi = reinterpret_cast<const DIFFITEM *>(m_pList->GetItemData(m_sel));
+ if (m_pdi == reinterpret_cast<const DIFFITEM *>(-1L))
+ {
+ m_sel = m_pList->GetNextItem(m_sel, m_selected, m_reverse);
+ m_pdi = reinterpret_cast<const DIFFITEM *>(m_pList->GetItemData(m_sel));
+ }
+ }
+ }
+
+ DirItemIterator() : m_pList(NULL), m_sel(-1), m_reverse(false)
+ {
+ }
+
+ ~DirItemIterator() {}
+
+ DirItemIterator& operator=(const DirItemIterator& it)
+ {
+ m_sel = it.m_sel;
+ m_pList = it.m_pList;
+ return *this;
+ }
+
+ DirItemIterator& operator++()
+ {
+ m_sel = m_pList->GetNextItem(m_sel, m_selected, m_reverse);
+ m_pdi = reinterpret_cast<const DIFFITEM *>(m_pList->GetItemData(m_sel));
+ if (m_pdi == reinterpret_cast<const DIFFITEM *>(-1L))
+ m_sel = -1;
+ return *this;
+ }
+
+ DIFFITEM& operator*()
+ {
+ return *const_cast<DIFFITEM *>(m_pdi);
+ }
+
+ const DIFFITEM& operator*() const
+ {
+ return *m_pdi;
+ }
+
+ bool operator==(const DirItemIterator& it) const
+ {
+ return m_sel == it.m_sel;
+ }
+
+ bool operator!=(const DirItemIterator& it) const
+ {
+ return m_sel != it.m_sel;
+ }
+
+ bool m_selected;
+ bool m_reverse;
+ int m_sel;
+ const DIFFITEM *m_pdi;
+
+private:
+ IListCtrl *m_pList;
+};
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>\r
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='UnicodeDebug|x64'">NotUsing</PrecompiledHeader>\r
</ClCompile>\r
- <ClCompile Include="Splash.cpp">\r
- </ClCompile>\r
+ <ClCompile Include="Common\SplitterWndEx.cpp">\r
+ </ClCompile>\r
<ClCompile Include="Common\StatLink.cpp">\r
</ClCompile>\r
<ClCompile Include="StdAfx.cpp">\r
<ClInclude Include="Common\coretools.h" />\r
<ClInclude Include="Common\coretypes.h" />\r
<ClInclude Include="Common\CSubclass.h" />\r
++ <ClInclude Include="DirActions.h" />\r
<ClInclude Include="IMergeDoc.h" />\r
<ClInclude Include="ImgMergeFrm.h" />\r
<ClInclude Include="Merge7zFormatMergePluginImpl.h" />\r
<ClInclude Include="Merge7zFormatRegister.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
+ <ClInclude Include="DirViewColItems.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
++ <ClInclude Include="DirActions.h">\r
++ <Filter>Header Files</Filter>\r
++ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<None Include="res\binarydiff.ico">\r
return theApp.LoadString(id);
}
-/**
- * @brief Lang aware version of AfxFormatStrings()
- */
-String LangFormatStrings(unsigned id, const TCHAR * const *rglpsz, int nString)
+String tr(const std::string &str)
{
- String fmt = theApp.LoadString(id);
- CString str;
- AfxFormatStrings(str, fmt.c_str(), rglpsz, nString);
- return (LPCTSTR)str;
+ String translated_str;
+ theApp.TranslateString(str, translated_str);
+ return translated_str;
}
-/**
- * @brief Lang aware version of AfxFormatString1()
- */
-String LangFormatString1(unsigned id, const TCHAR *lpsz1)
+void AppErrorMessageBox(const String& msg)
{
- return LangFormatStrings(id, &lpsz1, 1);
+ AppMsgBox::error(msg);
}
-/**
- * @brief Lang aware version of AfxFormatString2()
- */
-String LangFormatString2(unsigned id, const TCHAR *lpsz1, const TCHAR *lpsz2)
+namespace AppMsgBox
+{
+
+namespace detail
+{
+ int convert_to_winflags(int flags)
+ {
+ int newflags = 0;
+
+ if ((flags & (YES | NO | CANCEL)) == (YES | NO | CANCEL)) newflags |= MB_YESNOCANCEL;
+ else if ((flags & (YES | NO)) == (YES | NO)) newflags |= MB_YESNO;
+ else if ((flags & (OK | CANCEL)) == (OK | CANCEL)) newflags |= MB_OKCANCEL;
+ else if ((flags & OK) == OK) newflags |= MB_OK;
+
+ if (flags & YES_TO_ALL) newflags |= MB_YES_TO_ALL;
+ if (flags & DONT_DISPLAY_AGAIN) newflags |= MB_DONT_DISPLAY_AGAIN;
+
+ return newflags;
+ }
+
+ int convert_resp(int resp)
+ {
+ switch (resp)
+ {
+ case IDOK:
+ return OK;
+ case IDCANCEL:
+ return CANCEL;
+ case IDNO:
+ return NO;
+ case IDYES:
+ return YES;
+ case IDYESTOALL:
+ return YES_TO_ALL;
+ default:
+ return OK;
+ }
+ }
+}
+
+int error(const String& msg, int type)
{
- const TCHAR *rglpsz[2] = { lpsz1, lpsz2 };
- return LangFormatStrings(id, rglpsz, 2);
+ return detail::convert_resp(AfxMessageBox(msg.c_str(), detail::convert_to_winflags(type) | MB_ICONSTOP));
}
-void AppErrorMessageBox(const String& msg)
+int warning(const String& msg, int type)
{
- AfxMessageBox(msg.c_str(), MB_ICONSTOP);
+ return detail::convert_resp(AfxMessageBox(msg.c_str(), detail::convert_to_winflags(type) | MB_ICONWARNING));
+}
+
+int information(const String& msg, int type)
+{
+ return detail::convert_resp(AfxMessageBox(msg.c_str(), detail::convert_to_winflags(type) | MB_ICONINFORMATION));
+}
+
+}
+
+AboutInfo::AboutInfo()
+{
+ CVersionInfo verinfo;
+ version = string_format_string1(_("Version %1"), verinfo.GetProductVersion());
-
++ if (version.find(_T(" - ")) != String::npos)
++ {
++ string_replace(version, _T(" - "), _T("\n"));
++ version += _T(" ");
++ }
++ else
++ {
++ version += _T("\n");
++ }
+#ifdef _UNICODE
+ version += _T(" ");
+ version += _("Unicode");
+#endif
+
+#if defined _M_IX86
+ version += _T(" x86");
+#elif defined _M_IA64
+ version += _T(" IA64");
+#elif defined _M_X64
+ version += _T(" ");
+ version += _("X64");
+#endif
+
- copyright = verinfo.GetLegalCopyright();
++ copyright = _("WinMerge comes with ABSOLUTELY NO WARRANTY. This is free software and you are welcome to redistribute it under certain circumstances; see the GNU General Public License in the Help menu for details.");\r
++ copyright += _T("\n");\r
++ copyright += verinfo.GetLegalCopyright();
++ copyright += _T(" All rights reserved.");
+
+ private_build = verinfo.GetPrivateBuild();
+ if (!private_build.empty())
+ {
+ private_build = string_format_string1(_("Private Build: %1"), private_build);
+ }
+
+ website = WinMergeURL;
++
++ developers = _("Developers:\nDean Grimm, Christian List, Kimmo Varis, Jochen Tucht, Tim Gerundt, Takashi Sawanaki, Gal Hammer, Alexander Skinner");
++ string_replace(developers, _T(", "), _T("\n"));
}
class COptionsMgr;
class FileFilterHelper;
+struct AboutInfo
+{
+ AboutInfo();
+ String copyright;
+ String version;
++ String developers;
+ String private_build;
+ String website;
+};
+
/** @brief Retrieve error description from Windows; uses FormatMessage */
String GetSysError(int nerr = -1);
*/
PropGeneral::PropGeneral(COptionsMgr *optionsMgr)
: OptionsPanel(optionsMgr, PropGeneral::IDD)
-, m_bScroll(FALSE)
-, m_bSingleInstance(FALSE)
-, m_bVerifyPaths(FALSE)
+, m_bScroll(false)
- , m_bDisableSplash(false)
+, m_bSingleInstance(false)
+, m_bVerifyPaths(false)
, m_bCloseWindowWithEsc(TRUE)
-, m_bAskMultiWindowClose(FALSE)
-, m_bMultipleFileCmp(FALSE)
-, m_bMultipleDirCmp(FALSE)
+, m_bAskMultiWindowClose(false)
+, m_bMultipleFileCmp(false)
+, m_bMultipleDirCmp(false)
, m_nAutoCompleteSource(0)
-, m_bPreserveFiletime(FALSE)
-, m_bShowSelectFolderOnStartup(FALSE)
-, m_bCloseWithOK(TRUE)
+, m_bPreserveFiletime(false)
+, m_bShowSelectFolderOnStartup(false)
+, m_bCloseWithOK(true)
{
}
*/
void PropGeneral::WriteOptions()
{
- GetOptionsMgr()->SaveOption(OPT_SCROLL_TO_FIRST, m_bScroll == TRUE);
- GetOptionsMgr()->SaveOption(OPT_SINGLE_INSTANCE, m_bSingleInstance == TRUE);
- GetOptionsMgr()->SaveOption(OPT_VERIFY_OPEN_PATHS, m_bVerifyPaths == TRUE);
- GetOptionsMgr()->SaveOption(OPT_CLOSE_WITH_ESC, m_bCloseWindowWithEsc == TRUE);
- GetOptionsMgr()->SaveOption(OPT_ASK_MULTIWINDOW_CLOSE, m_bAskMultiWindowClose == TRUE);
- GetOptionsMgr()->SaveOption(OPT_MULTIDOC_MERGEDOCS, m_bMultipleFileCmp == TRUE);
- GetOptionsMgr()->SaveOption(OPT_MULTIDOC_DIRDOCS, m_bMultipleDirCmp == TRUE);
+ GetOptionsMgr()->SaveOption(OPT_SCROLL_TO_FIRST, m_bScroll);
- GetOptionsMgr()->SaveOption(OPT_DISABLE_SPLASH, m_bDisableSplash);
+ GetOptionsMgr()->SaveOption(OPT_SINGLE_INSTANCE, m_bSingleInstance);
+ GetOptionsMgr()->SaveOption(OPT_VERIFY_OPEN_PATHS, m_bVerifyPaths);
+ GetOptionsMgr()->SaveOption(OPT_CLOSE_WITH_ESC, m_bCloseWindowWithEsc);
+ GetOptionsMgr()->SaveOption(OPT_ASK_MULTIWINDOW_CLOSE, m_bAskMultiWindowClose);
+ GetOptionsMgr()->SaveOption(OPT_MULTIDOC_MERGEDOCS, m_bMultipleFileCmp);
+ GetOptionsMgr()->SaveOption(OPT_MULTIDOC_DIRDOCS, m_bMultipleDirCmp);
GetOptionsMgr()->SaveOption(OPT_AUTO_COMPLETE_SOURCE, m_nAutoCompleteSource);
GetOptionsMgr()->SaveOption(OPT_PRESERVE_FILETIMES, m_bPreserveFiletime);
GetOptionsMgr()->SaveOption(OPT_SHOW_SELECT_FILES_AT_STARTUP, m_bShowSelectFolderOnStartup);
// Dialog Data
//{{AFX_DATA(PropGeneral)
enum { IDD = IDD_PROPPAGE_GENERAL };
- BOOL m_bScroll;
- BOOL m_bSingleInstance;
- BOOL m_bVerifyPaths;
- BOOL m_bCloseWindowWithEsc;
- BOOL m_bAskMultiWindowClose;
- BOOL m_bMultipleFileCmp;
- BOOL m_bMultipleDirCmp;
- int m_nAutoCompleteSource;
- BOOL m_bPreserveFiletime;
- BOOL m_bShowSelectFolderOnStartup;
- BOOL m_bCloseWithOK;
+ bool m_bScroll;
- bool m_bDisableSplash;
+ bool m_bSingleInstance;
+ bool m_bVerifyPaths;
+ bool m_bCloseWindowWithEsc;
+ bool m_bAskMultiWindowClose;
+ bool m_bMultipleFileCmp;
+ bool m_bMultipleDirCmp;
+ int m_nAutoCompleteSource;
+ bool m_bPreserveFiletime;
+ bool m_bShowSelectFolderOnStartup;
+ bool m_bCloseWithOK;
//}}AFX_DATA
msgstr ""
"Project-Id-Version: WinMerge\n"
"Report-Msgid-Bugs-To: http://bugs.winmerge.org/\n"
- "POT-Creation-Date: 2014-12-18 22:44+0000\n"
-"POT-Creation-Date: 2014-12-29 17:09+0000\n"
++"POT-Creation-Date: 2014-12-29 23:28+0000\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: English <winmerge-translate@lists.sourceforge.net>\n"