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;
}
/**
--- /dev/null
- 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);
+#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);
+
+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 *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<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));
+}
{
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);
// 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
{
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
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");
}
}
// 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