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 *pdi[3],
+ PathContext & paths, int & sel1, bool & isdir, int nPane[3], String& errmsg)
{
- 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, *pdi[0]);
+
+ for (int nIndex = 0; nIndex < paths.GetSize(); ++nIndex)
+ nPane[nIndex] = nIndex;
+
+ if (pdi[0]->diffcode.isDirectory())
+ isdir = true;
+
+ 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.
*/
-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
+ 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, *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 (pdi[0]->diffcode.isSideSecondOnly() || (pdi[0]->diffcode.isSideBoth() &&
+ pdi[1]->diffcode.isSideFirstOnly()))
+ {
+ std::swap(pdi[0], pdi[1]);
+ std::swap(sel1, sel2);
+ }
+ break;
+ case SELECTIONTYPE_LEFT1LEFT2:
+ nPane[0] = nPane[1] = 0;
+ break;
+ case SELECTIONTYPE_RIGHT1RIGHT2:
+ nPane[0] = nPane[1] = 1;
+ break;
+ case SELECTIONTYPE_LEFT1RIGHT2:
+ break;
+ case SELECTIONTYPE_LEFT2RIGHT1:
+ std::swap(pdi[0], pdi[1]);
+ std::swap(sel1, sel2);
+ break;
+ }
+
++ PathContext files1, files2;
++ files1 = GetItemFileNames(ctxt, *pdi[0]);
++ files2 = GetItemFileNames(ctxt, *pdi[1]);
++ paths.SetLeft(files1[nPane[0]]);
++ paths.SetRight(files2[nPane[1]]);
++
+ if (pdi[0]->diffcode.isDirectory())
+ {
+ isDir = true;
- if (GetPairComparability(PathContext(pathLeft, pathRight)) != IS_EXISTING_DIR)
++ if (GetPairComparability(paths) != IS_EXISTING_DIR)
+ {
+ errmsg = _("The selected folder is invalid.");
+ return false;
+ }
}
- 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;
}
/**
}
else
{
- const DIFFITEM & di = GetDocument()->GetDiffByKey(diffpos);
- for (int nIndex = 0; nIndex < GetDocument()->m_nDirs; nIndex++)
+ // Three items selected, get their info
+ 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, *pdi[0], *pdi[1], *pdi[2]))
+ {
+ return false;
+ }
+ // 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 (pdi[0]->diffcode.isExists(0) && pdi[1]->diffcode.isExists(2) && pdi[2]->diffcode.isExists(1))
{
- 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);
}
- if (GetPairComparability(PathContext(pathLeft, pathMiddle, pathRight)) != IS_EXISTING_DIR)
+ else if (pdi[0]->diffcode.isExists(1) && pdi[1]->diffcode.isExists(0) && pdi[2]->diffcode.isExists(2))
+ {
+ std::swap(pdi[0], pdi[1]);
+ std::swap(sel1, sel2);
+ }
+ else if (pdi[0]->diffcode.isExists(1) && pdi[1]->diffcode.isExists(2) && pdi[2]->diffcode.isExists(0))
+ {
+ std::swap(pdi[0], pdi[2]);
+ std::swap(sel1, sel3);
+ std::swap(pdi[1], pdi[2]);
+ std::swap(sel2, sel3);
+ }
+ else if (pdi[0]->diffcode.isExists(2) && pdi[1]->diffcode.isExists(0) && pdi[2]->diffcode.isExists(1))
+ {
+ std::swap(pdi[0], pdi[1]);
+ std::swap(sel1, sel2);
+ std::swap(pdi[1], pdi[2]);
+ std::swap(sel2, sel3);
+ }
+ else if (pdi[0]->diffcode.isExists(2) && pdi[1]->diffcode.isExists(1) && pdi[2]->diffcode.isExists(0))
+ {
+ std::swap(pdi[0], pdi[2]);
+ std::swap(sel1, sel3);
+ }
+ }
+
+ // Fill in pathLeft & & pathMiddle & pathRight
+ PathContext pathsTemp = GetItemFileNames(ctxt, *pdi[0]);
+ pathLeft = pathsTemp[0];
+ pathsTemp = GetItemFileNames(ctxt, *pdi[1]);
+ pathMiddle = pathsTemp[1];
+ pathsTemp = GetItemFileNames(ctxt, *pdi[2]);
+ pathRight = pathsTemp[2];
+
++ paths.SetLeft(pathLeft.c_str());
++ paths.SetMiddle(pathMiddle.c_str());
++ paths.SetRight(pathRight.c_str());
++
+ if (pdi[0]->diffcode.isDirectory())
+ {
+ isDir = true;
++ if (GetPairComparability(paths) != IS_EXISTING_DIR)
+ {
+ errmsg = _("The selected folder is invalid.");
+ return false;
+ }
}
- paths.SetLeft(pathLeft.c_str());
- paths.SetRight(pathRight.c_str());
-
+
+ return true;
}
/**
// Common variables which both code paths below are responsible for setting
PathContext paths;
- 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)
+ if (pos2 && !pos3)
- {
- 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)
+ else if (pos2 && pos3)
- {
- 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
- 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
{
// Open subfolders
// Don't add folders to MRU
- GetMainFrame()->DoFileOpen(&paths, dwFlags, pDoc->GetRecursive(), (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? NULL : pDoc);
+ GetMainFrame()->DoFileOpen(&paths, dwFlags, GetDiffContext().m_bRecursive, (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? NULL : pDoc);
}
- else if (HasZipSupport() && std::count_if(paths.begin(), paths.end(), ArchiveGuessFormat) == pDoc->m_nDirs)
+ else if (HasZipSupport() && std::count_if(paths.begin(), paths.end(), ArchiveGuessFormat) == paths.GetSize())
{
// Open archives, not adding paths to MRU
- GetMainFrame()->DoFileOpen(&paths, dwFlags, pDoc->GetRecursive(), NULL, _T(""), infoUnpacker);
+ GetMainFrame()->DoFileOpen(&paths, dwFlags, GetDiffContext().m_bRecursive, NULL, _T(""), infoUnpacker);
}
else
{
const DIFFITEM& di1 = GetDiffItem(sel1);
const DIFFITEM& di2 = GetDiffItem(sel2);
const DIFFITEM& di3 = GetDiffItem(sel3);
- if (!::AreItemsOpenable(GetDiffContext(), di1, di2, di3))
- if (selectionType != SELECTIONTYPE_NORMAL || !AreItemsOpenable(di1, di2, di3))
++ if (selectionType != SELECTIONTYPE_NORMAL || !::AreItemsOpenable(GetDiffContext(), di1, di2, di3))
{
pCmdUI->Enable(FALSE);
return;