From: sdottaka Date: Thu, 22 Jan 2015 06:50:31 +0000 (+0900) Subject: Merge with stable X-Git-Tag: 2.16.5~1481 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=621b4eb7710d5b8a7df2a543d8f123060d932eee;p=winmerge-jp%2Fwinmerge-jp.git Merge with stable --- 621b4eb7710d5b8a7df2a543d8f123060d932eee diff --cc Src/DirActions.cpp index 49c9c148f,6f5a6fb24..0df2243fa --- a/Src/DirActions.cpp +++ b/Src/DirActions.cpp @@@ -543,373 -1356,69 +543,373 @@@ bool IsItemNavigableDiff(const CDiffCon 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() && FALSE/* !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() && FALSE/* !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_t pos1, const DIFFITEM **di1, const DIFFITEM **di2, const DIFFITEM **di3, - PathContext & paths, int & sel1, bool & isdir, String& errmsg) ++bool GetOpenOneItem(const CDiffContext& ctxt, uintptr_t pos1, const DIFFITEM *pdi[3], ++ PathContext & paths, int & sel1, bool & isdir, int nPane[3], String& errmsg) { - *di1 = &ctxt.GetDiffAt(pos1); - *di2 = *di1; - *di3 = *di1; - String left, right; - if (!GetSelectedFileNames(left, right)) return _T(""); - return stype==SIDE_LEFT ? left : right; ++ pdi[0] = &ctxt.GetDiffAt(pos1); ++ pdi[1] = pdi[0]; ++ pdi[2] = pdi[0]; + - paths = GetItemFileNames(ctxt, **di1); ++ paths = GetItemFileNames(ctxt, *pdi[0]); + - if ((*di1)->diffcode.isDirectory()) ++ for (int nIndex = 0; nIndex < paths.GetSize(); ++nIndex) ++ nPane[nIndex] = nIndex; ++ ++ if (pdi[0]->diffcode.isDirectory()) + isdir = true; + - if (isdir && ((*di1)->diffcode.isExistsFirst() && (*di1)->diffcode.isExistsSecond() && (*di1)->diffcode.isExistsThird())) ++ if (isdir && (pdi[0]->diffcode.isExistsFirst() && pdi[1]->diffcode.isExistsSecond() && pdi[2]->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_t pos1, uintptr_t pos2, const DIFFITEM **di1, const DIFFITEM **di2, - PathContext & paths, int & sel1, int & sel2, bool & isDir, String& errmsg) -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 *pdi[3], ++ PathContext & paths, int & sel1, int & sel2, bool & isDir, int nPane[3], 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); ++ pdi[0] = &ctxt.GetDiffAt(pos1); ++ pdi[1] = &ctxt.GetDiffAt(pos2); ++ nPane[0] = 0; ++ nPane[1] = 1; + + // Check for binary & side compatibility & file/dir compatibility - if (!AreItemsOpenable(ctxt, selectionType, **di1, **di2)) ++ if (!AreItemsOpenable(ctxt, selectionType, *pdi[0], *pdi[1])) { - 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())) ++ if (pdi[0]->diffcode.isSideSecondOnly() || (pdi[0]->diffcode.isSideBoth() && ++ pdi[1]->diffcode.isSideFirstOnly())) + { - const DIFFITEM * temp = *di1; - *di1 = *di2; - *di2 = temp; - int num = sel1; - sel1 = sel2; - sel2 = num; ++ std::swap(pdi[0], pdi[1]); ++ std::swap(sel1, sel2); + } - // 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); ++ nPane[0] = nPane[1] = 0; + break; + case SELECTIONTYPE_RIGHT1RIGHT2: - GetItemFileNames(ctxt, **di1, temp, pathLeft); - GetItemFileNames(ctxt, **di2, temp, pathRight); ++ nPane[0] = nPane[1] = 1; + 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); ++ std::swap(pdi[0], pdi[1]); ++ std::swap(sel1, sel2); + break; + } + - if ((*di1)->diffcode.isDirectory()) ++ if (pdi[0]->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); ++ PathContext files1, files2; ++ files1 = GetItemFileNames(ctxt, *pdi[0]); ++ files2 = GetItemFileNames(ctxt, *pdi[1]); ++ paths.SetLeft(files1[nPane[0]]); ++ paths.SetRight(files2[nPane[1]]); + + 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_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 CDirView::GetItemFileNames(int sel, PathContext * paths) const ++bool GetOpenThreeItems(const CDiffContext& ctxt, uintptr_t pos1, uintptr_t pos2, uintptr_t pos3, const DIFFITEM *pdi[3], ++ PathContext & paths, int & sel1, int & sel2, int & sel3, bool & isDir, int nPane[3], String& errmsg) { - String strPath[3]; - UINT_PTR diffpos = GetItemKey(sel); - if (diffpos == SPECIAL_ITEM_POS) + String pathLeft, pathMiddle, pathRight; + ++ // FIXME: ++ for (int nIndex = 0; nIndex < 3; ++nIndex) ++ nPane[nIndex] = nIndex; + 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); ++ pdi[0] = &ctxt.GetDiffAt(pos1); ++ pdi[1] = &ctxt.GetDiffAt(pos2); + + // Check for binary & side compatibility & file/dir compatibility - if (!::AreItemsOpenable(ctxt, **di1, **di2, **di2) && - !::AreItemsOpenable(ctxt, **di1, **di1, **di2)) ++ if (!::AreItemsOpenable(ctxt, *pdi[0], *pdi[1], *pdi[1]) && ++ !::AreItemsOpenable(ctxt, *pdi[0], *pdi[0], *pdi[1])) + { + return false; + } - // Ensure that di1 is on left (swap if needed) - if ((*di1)->diffcode.isExists(0) && (*di1)->diffcode.isExists(1) && (*di2)->diffcode.isExists(2)) ++ // Ensure that pdi[0] is on left (swap if needed) ++ if (pdi[0]->diffcode.isExists(0) && pdi[0]->diffcode.isExists(1) && pdi[1]->diffcode.isExists(2)) + { - *di3 = *di2; - *di2 = *di1; ++ pdi[2] = pdi[1]; ++ pdi[1] = pdi[0]; + sel3 = sel2; + sel2 = sel1; + } - else if ((*di1)->diffcode.isExists(0) && (*di1)->diffcode.isExists(2) && (*di2)->diffcode.isExists(1)) ++ else if (pdi[0]->diffcode.isExists(0) && pdi[0]->diffcode.isExists(2) && pdi[1]->diffcode.isExists(1)) + { - *di3 = *di1; ++ pdi[2] = pdi[0]; + sel3 = sel1; + } - else if ((*di1)->diffcode.isExists(1) && (*di1)->diffcode.isExists(2) && (*di2)->diffcode.isExists(0)) ++ else if (pdi[0]->diffcode.isExists(1) && pdi[0]->diffcode.isExists(2) && pdi[1]->diffcode.isExists(0)) + { - std::swap(*di1, *di2); ++ std::swap(pdi[0], pdi[1]); + std::swap(sel1, sel2); - *di3 = *di2; ++ pdi[2] = pdi[1]; + sel3 = sel2; + } - else if ((*di2)->diffcode.isExists(0) && (*di2)->diffcode.isExists(1) && (*di1)->diffcode.isExists(2)) ++ else if (pdi[1]->diffcode.isExists(0) && pdi[1]->diffcode.isExists(1) && pdi[0]->diffcode.isExists(2)) + { - std::swap(*di1, *di2); ++ std::swap(pdi[0], pdi[1]); + std::swap(sel1, sel2); - *di3 = *di2; - *di2 = *di1; ++ pdi[2] = pdi[1]; ++ pdi[1] = pdi[0]; + sel3 = sel2; + sel2 = sel1; + } - else if ((*di2)->diffcode.isExists(0) && (*di2)->diffcode.isExists(2) && (*di1)->diffcode.isExists(1)) ++ else if (pdi[1]->diffcode.isExists(0) && pdi[1]->diffcode.isExists(2) && pdi[0]->diffcode.isExists(1)) + { - std::swap(*di1, *di2); ++ std::swap(pdi[0], pdi[1]); + std::swap(sel1, sel2); - *di3 = *di1; ++ pdi[2] = pdi[0]; + sel3 = sel1; + } - else if ((*di2)->diffcode.isExists(1) && (*di2)->diffcode.isExists(2) && (*di1)->diffcode.isExists(0)) ++ else if (pdi[1]->diffcode.isExists(1) && pdi[1]->diffcode.isExists(2) && pdi[0]->diffcode.isExists(0)) + { - *di3 = *di2; ++ pdi[2] = pdi[1]; + sel3 = sel2; + } } else { - const DIFFITEM & di = GetDocument()->GetDiffByKey(diffpos); - for (int nIndex = 0; nIndex < GetDocument()->m_nDirs; nIndex++) + // Three items selected, get their info - *di1 = &ctxt.GetDiffAt(pos1); - *di2 = &ctxt.GetDiffAt(pos2); - *di3 = &ctxt.GetDiffAt(pos3); ++ pdi[0] = &ctxt.GetDiffAt(pos1); ++ pdi[1] = &ctxt.GetDiffAt(pos2); ++ pdi[2] = &ctxt.GetDiffAt(pos3); + + // Check for binary & side compatibility & file/dir compatibility - if (!::AreItemsOpenable(ctxt, **di1, **di2, **di3)) ++ if (!::AreItemsOpenable(ctxt, *pdi[0], *pdi[1], *pdi[2])) + { + return false; + } - // Ensure that di1 is on left (swap if needed) - if ((*di1)->diffcode.isExists(0) && (*di2)->diffcode.isExists(1) && (*di3)->diffcode.isExists(2)) ++ // Ensure that pdi[0] is on left (swap if needed) ++ if (pdi[0]->diffcode.isExists(0) && pdi[1]->diffcode.isExists(1) && pdi[2]->diffcode.isExists(2)) + { + } - else if ((*di1)->diffcode.isExists(0) && (*di2)->diffcode.isExists(2) && (*di3)->diffcode.isExists(1)) ++ else if (pdi[0]->diffcode.isExists(0) && pdi[1]->diffcode.isExists(2) && pdi[2]->diffcode.isExists(1)) { - std::swap(*di2, *di3); - const String relpath = di.diffFileInfo[nIndex].GetFile(); - const String & path = GetDocument()->GetBasePath(nIndex); - paths->SetPath(nIndex, paths_ConcatPath(path, relpath)); ++ std::swap(pdi[1], pdi[2]); + std::swap(sel2, sel3); } - else if ((*di1)->diffcode.isExists(1) && (*di2)->diffcode.isExists(0) && (*di3)->diffcode.isExists(2)) ++ else if (pdi[0]->diffcode.isExists(1) && pdi[1]->diffcode.isExists(0) && pdi[2]->diffcode.isExists(2)) + { - std::swap(*di1, *di2); ++ std::swap(pdi[0], pdi[1]); + std::swap(sel1, sel2); + } - else if ((*di1)->diffcode.isExists(1) && (*di2)->diffcode.isExists(2) && (*di3)->diffcode.isExists(0)) ++ else if (pdi[0]->diffcode.isExists(1) && pdi[1]->diffcode.isExists(2) && pdi[2]->diffcode.isExists(0)) + { - std::swap(*di1, *di3); ++ std::swap(pdi[0], pdi[2]); + std::swap(sel1, sel3); - std::swap(*di2, *di3); ++ std::swap(pdi[1], pdi[2]); + std::swap(sel2, sel3); + } - else if ((*di1)->diffcode.isExists(2) && (*di2)->diffcode.isExists(0) && (*di3)->diffcode.isExists(1)) ++ else if (pdi[0]->diffcode.isExists(2) && pdi[1]->diffcode.isExists(0) && pdi[2]->diffcode.isExists(1)) + { - std::swap(*di1, *di2); ++ std::swap(pdi[0], pdi[1]); + std::swap(sel1, sel2); - std::swap(*di2, *di3); ++ std::swap(pdi[1], pdi[2]); + std::swap(sel2, sel3); + } - else if ((*di1)->diffcode.isExists(2) && (*di2)->diffcode.isExists(1) && (*di3)->diffcode.isExists(0)) ++ else if (pdi[0]->diffcode.isExists(2) && pdi[1]->diffcode.isExists(1) && pdi[2]->diffcode.isExists(0)) + { - std::swap(*di1, *di3); ++ std::swap(pdi[0], pdi[2]); + std::swap(sel1, sel3); + } + } + + // Fill in pathLeft & & pathMiddle & pathRight - PathContext pathsTemp = GetItemFileNames(ctxt, **di1); ++ PathContext pathsTemp = GetItemFileNames(ctxt, *pdi[0]); + pathLeft = pathsTemp[0]; - pathsTemp = GetItemFileNames(ctxt, **di2); ++ pathsTemp = GetItemFileNames(ctxt, *pdi[1]); + pathMiddle = pathsTemp[1]; - pathsTemp = GetItemFileNames(ctxt, **di3); ++ pathsTemp = GetItemFileNames(ctxt, *pdi[2]); + pathRight = pathsTemp[2]; + - if ((*di1)->diffcode.isDirectory()) ++ if (pdi[0]->diffcode.isDirectory()) + { + isDir = true; + if (GetPairComparability(PathContext(pathLeft, pathMiddle, pathRight)) != IS_EXISTING_DIR) + { + errmsg = _("The selected folder is invalid."); + return false; + } } + + paths.SetLeft(pathLeft.c_str()); + paths.SetRight(pathRight.c_str()); + + return true; } /** diff --cc Src/DirActions.h index 4c52a2a82,000000000..1f6e73279 mode 100644,000000..100644 --- a/Src/DirActions.h +++ b/Src/DirActions.h @@@ -1,792 -1,0 +1,792 @@@ +#pragma once + +#include "UnicodeString.h" +#include "DiffContext.h" +#include "FileActionScript.h" +#include "paths.h" +#include "IntToIntMap.h" +#include + +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 + 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 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); + +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 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 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); ++bool GetOpenOneItem(const CDiffContext& ctxt, uintptr_t pos1, const DIFFITEM *pdi[3], ++ PathContext &paths, int & sel1, bool & isDir, int nPane[3], String& errmsg); ++bool GetOpenTwoItems(const CDiffContext& ctxt, SELECTIONTYPE selectionType, uintptr_t pos1, uintptr_t pos2, const DIFFITEM *pdi[3], ++ PathContext &paths, int & sel1, int & sel2, bool & isDir, int nPane[3], String& errmsg); ++bool GetOpenThreeItems(const CDiffContext& ctxt, uintptr_t pos1, uintptr_t pos2, uintptr_t pos3, const DIFFITEM *pdi[3], ++ PathContext &paths, int & sel1, int & sel2, int & sel3, bool & isDir, int nPane[3], 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 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 + bool IsItemCopyableOnTo(const DIFFITEM& di) const + { + return (di.diffcode.diffcode != 0 && !m_RO[SideToIndex(m_ctxt, dst)] && ::IsItemCopyable(di, SideToIndex(m_ctxt, src))); + } + + template + bool IsItemCopyableToOn(const DIFFITEM& di) const + { + return (di.diffcode.diffcode != 0 && ::IsItemCopyableToOn(di, SideToIndex(m_ctxt, src))); + } + + template + 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 + 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 + bool IsItemOpenanbleOn(const DIFFITEM& di) const + { + return (di.diffcode.diffcode != 0 && IsItemOpenableOn(di, SideToIndex(m_ctxt, src))); + } + + template + 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 + bool IsItemExist(const DIFFITEM& di) const + { + return (di.diffcode.diffcode != 0 && di.diffcode.isExists(SideToIndex(m_ctxt, src))); + } + + template + 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& 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 + FileActionScript *Copy(FileActionScript *pscript, const std::pair it) const + { + return CopyItem(pscript, it, src, to); + } + + FileActionScript *DeleteItem(FileActionScript *pscript, const std::pair& 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 + FileActionScript *DeleteOn(FileActionScript *pscript, const std::pair it) const + { + return DeleteItem(pscript, it, src); + } + + FileActionScript *DeleteOnBoth(FileActionScript *pscript, const std::pair 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 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& 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 + FileActionScript *CopyTo(FileActionScript *pscript, const std::pair it) const + { + return CopyOrMoveItemTo(pscript, it, FileAction::ACT_COPY, src); + } + + template + FileActionScript *MoveTo(FileActionScript *pscript, const std::pair it) const + { + return CopyOrMoveItemTo(pscript, it, FileAction::ACT_MOVE, src); + } + + FileActionScript *operator()(FileActionScript *pscript, const std::pair 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 +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 +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 +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 +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 +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 +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 +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 +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 +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(ctxt).FetchPluginInfos(filteredFilenames, &infoUnpacker, &infoPrediffer); + infoPrediffer->Initialize(newsetting); + } + } +} + +/** + * @brief Updates just before displaying plugin context view in list + */ +template +std::pair 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(ctxt).FetchPluginInfos(filteredFilenames, &unpacker, &prediffer); + if (prediffer->bToBeScanned == 1 || prediffer->pluginName.empty() == false) + nPredifferYes ++; + else + nPredifferNo ++; + } + } + return std::make_pair(nPredifferYes, nPredifferNo); +} + +template +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 +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 +String GetSelectedFileName(InputIterator& it, SIDE_TYPE stype, const CDiffContext& ctxt) +{ + if (it == InputIterator()) + return _T(""); + return GetItemFileName(ctxt, *it, SideToIndex(ctxt, stype)); +} diff --cc Src/DirView.cpp index a643c0220,552ff269d..e3e36d44d --- a/Src/DirView.cpp +++ b/Src/DirView.cpp @@@ -1167,18 -1279,20 +1167,20 @@@ void CDirView::OpenParentDirectory( { CDirDoc *pDoc = GetDocument(); PathContext pathsParent; - switch (pDoc->AllowUpwardDirectory(pathsParent)) + switch (CheckAllowUpwardDirectory(GetDiffContext(), pDoc->m_pTempPathContext, pathsParent)) { - case CDirDoc::AllowUpwardDirectory::ParentIsTempPath: + case AllowUpwardDirectory::ParentIsTempPath: pDoc->m_pTempPathContext = pDoc->m_pTempPathContext->DeleteHead(); // fall through (no break!) - case CDirDoc::AllowUpwardDirectory::ParentIsRegularPath: + case AllowUpwardDirectory::ParentIsRegularPath: { - DWORD dwFlags[3] = {FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, FFILEOPEN_NOMRU}; + DWORD dwFlags[3]; + for (int nIndex = 0; nIndex < pathsParent.GetSize(); ++nIndex) + dwFlags[nIndex] = FFILEOPEN_NOMRU | (pDoc->GetReadOnly(nIndex) ? FFILEOPEN_READONLY : 0); - GetMainFrame()->DoFileOpen(&pathsParent, dwFlags, pDoc->GetRecursive(), (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? NULL : pDoc); + GetMainFrame()->DoFileOpen(&pathsParent, dwFlags, GetDiffContext().m_bRecursive, (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? NULL : pDoc); } // fall through (no break!) - case CDirDoc::AllowUpwardDirectory::No: + case AllowUpwardDirectory::No: break; default: LangMessageBox(IDS_INVALID_DIRECTORY, MB_ICONSTOP); @@@ -1276,26 -1735,31 +1278,27 @@@ void CDirView::OpenSelection(SELECTIONT // Common variables which both code paths below are responsible for setting PathContext paths; - const DIFFITEM *di1 = NULL, *di2 = NULL, *di3 = NULL; // left & right items (di1==di2 if single selection) - DIFFITEM *pdi[3] = {0}; // left & right items (di1==di2 if single selection) ++ const DIFFITEM *pdi[3] = {0}; // left & right items (di1==di2 if single selection) bool isdir = false; // set if we're comparing directories - bool bRO[3] = { false, false, false }; + int nPane[3]; - + String errmsg; + bool success; if (pDoc->m_nDirs < 3 && pos2) - success = GetOpenTwoItems(ctxt, selectionType, pos1, pos2, &di1, &di2, - paths, sel1, sel2, isdir, errmsg); - { - bool success = OpenTwoItems(selectionType, pos1, pos2, pdi, - paths, sel1, sel2, isdir, nPane); - if (!success) - return; - } ++ success = GetOpenTwoItems(ctxt, selectionType, pos1, pos2, pdi, ++ paths, sel1, sel2, isdir, nPane, errmsg); else if (pDoc->m_nDirs == 3 && pos2) - success = GetOpenThreeItems(ctxt, pos1, pos2, pos3, &di1, &di2, &di3, - paths, sel1, sel2, sel3, isdir, errmsg); - { - bool success = OpenThreeItems(pos1, pos2, pos3, pdi, - paths, sel1, sel2, sel3, isdir, nPane); - if (!success) - return; - } ++ success = GetOpenThreeItems(ctxt, pos1, pos2, pos3, pdi, ++ paths, sel1, sel2, sel3, isdir, nPane, errmsg); else - { // Only one item selected, so perform diff on its sides - success = GetOpenOneItem(ctxt, pos1, &di1, &di2, &di3, - paths, sel1, isdir, errmsg); - bool success = OpenOneItem(pos1, pdi, paths, sel1, isdir, nPane); ++ success = GetOpenOneItem(ctxt, pos1, pdi, ++ paths, sel1, isdir, nPane, errmsg); if (!success) - return; + if (!success) + { + if (!errmsg.empty()) + AfxMessageBox(errmsg.c_str(), MB_ICONSTOP); + return; } // Now pathLeft, pathRight, di1, di2, and isdir are all set @@@ -1335,15 -1801,15 +1340,15 @@@ { theApp.m_strDescriptions[0].erase(); theApp.m_strDescriptions[1].erase(); - if (di1 == di2 && !di1->diffcode.isExists(0)) + if (pdi[0] == pdi[1] && !pdi[0]->diffcode.isExists(0)) { paths[0] = _T(""); - theApp.m_strDescriptions[0] = theApp.LoadString(IDS_EMPTY_LEFT_FILE); + theApp.m_strDescriptions[0] = _("Untitled left"); } - if (di1 == di2 && !di1->diffcode.isExists(1)) + if (pdi[0] == pdi[1] && !pdi[0]->diffcode.isExists(1)) { paths[1] = _T(""); - theApp.m_strDescriptions[1] = theApp.LoadString(IDS_EMPTY_RIGHT_FILE); + theApp.m_strDescriptions[1] = _("Untitled right"); } } else @@@ -1351,20 -1817,20 +1356,20 @@@ theApp.m_strDescriptions[0].erase(); theApp.m_strDescriptions[1].erase(); theApp.m_strDescriptions[2].erase(); - if (di1 == di2 && di1 == di3 && !di1->diffcode.isExists(0)) + if (pdi[0] == pdi[1] && pdi[0] == pdi[2] && !pdi[0]->diffcode.isExists(0)) { paths[0] = _T(""); - theApp.m_strDescriptions[0] = theApp.LoadString(IDS_EMPTY_LEFT_FILE); + theApp.m_strDescriptions[0] = _("Untitled left"); } - if (di1 == di2 && di1 == di3 && !di1->diffcode.isExists(1)) + if (pdi[0] == pdi[1] && pdi[0] == pdi[2] && !pdi[0]->diffcode.isExists(1)) { paths[1] = _T(""); - theApp.m_strDescriptions[1] = theApp.LoadString(IDS_EMPTY_MIDDLE_FILE); + theApp.m_strDescriptions[1] = _("Untitled middle"); } - if (di1 == di2 && di1 == di3 && !di1->diffcode.isExists(2)) + if (pdi[0] == pdi[1] && pdi[0] == pdi[2] && !pdi[0]->diffcode.isExists(2)) { paths[2] = _T(""); - theApp.m_strDescriptions[2] = theApp.LoadString(IDS_EMPTY_RIGHT_FILE); + theApp.m_strDescriptions[2] = _("Untitled right"); } } @@@ -1409,22 -1873,22 +1413,23 @@@ void CDirView::OpenSelectionHex( // Common variables which both code paths below are responsible for setting PathContext paths; - const DIFFITEM *di1 = NULL, *di2 = NULL, *di3 = NULL; // left & right items (di1==di2 if single selection) - DIFFITEM *pdi[3] = { 0 }; // left & right items (di1==di2 if single selection) ++ const DIFFITEM *pdi[3]; // left & right items (di1==di2 if single selection) bool isdir = false; // set if we're comparing directories + int nPane[3]; + String errmsg; + bool success; if (pos2) - success = GetOpenTwoItems(ctxt, SELECTIONTYPE_NORMAL, pos1, pos2, &di1, &di2, - paths, sel1, sel2, isdir, errmsg); ++ success = GetOpenTwoItems(ctxt, SELECTIONTYPE_NORMAL, pos1, pos2, pdi, ++ paths, sel1, sel2, isdir, nPane, errmsg); + else + // Only one item selected, so perform diff on its sides - success = GetOpenOneItem(ctxt, pos1, &di1, &di2, &di3, - paths, sel1, isdir, errmsg); ++ success = GetOpenOneItem(ctxt, pos1, pdi, ++ paths, sel1, isdir, nPane, errmsg); + if (!success) { - bool success = OpenTwoItems(SELECTIONTYPE_NORMAL, pos1, pos2, pdi, - paths, sel1, sel2, isdir, nPane); - if (!success) - return; - } - else - { - // Only one item selected, so perform diff on its sides - bool success = OpenOneItem(pos1, pdi, paths, sel1, isdir, nPane); - if (!success) - return; + if (!errmsg.empty()) + AfxMessageBox(errmsg.c_str(), MB_ICONSTOP); + return; } // Need to consider only regular file case here