bool CLocalTreeView::CheckSubdirStatus(wxTreeItemId& item, const wxString& path) { wxTreeItemIdValue value; wxTreeItemId child = GetFirstChild(item, value); static const wxLongLong size(-1); #ifdef __WXMAC__ // By default, OS X has a list of servers mounted into /net, // listing that directory is slow. if (GetItemParent(item) == GetRootItem() && (path == _T("/net") || path == _T("/net/"))) { CFilterManager filter; const int attributes = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; if (!filter.FilenameFiltered(_T("localhost"), path, true, size, true, attributes)) { if (!child) AppendItem(item, _T("")); return true; } } #endif if (child) { if (GetItemText(child) != _T("")) return false; CTreeItemData* pData = (CTreeItemData*)GetItemData(child); if (pData) { bool wasLink; int attributes; enum CLocalFileSystem::local_fileType type; if (path.Last() == CLocalFileSystem::path_separator) type = CLocalFileSystem::GetFileInfo(path + pData->m_known_subdir, wasLink, 0, 0, &attributes); else type = CLocalFileSystem::GetFileInfo(path + CLocalFileSystem::path_separator + pData->m_known_subdir, wasLink, 0, 0, &attributes); if (type == CLocalFileSystem::dir) { CFilterManager filter; if (!filter.FilenameFiltered(pData->m_known_subdir, path, true, size, true, attributes)) return true; } } } wxString sub = HasSubdir(path); if (sub != _T("")) { wxTreeItemId subItem = AppendItem(item, _T("")); SetItemData(subItem, new CTreeItemData(sub)); } else if (child) Delete(child); return true; }
wxString CLocalTreeView::HasSubdir(const wxString& dirname) { wxLogNull nullLog; CFilterManager filter; CLocalFileSystem local_filesystem; if (!local_filesystem.BeginFindFiles(dirname, true)) return _T(""); wxString file; bool wasLink; int attributes; bool is_dir; const wxLongLong size(-1); wxDateTime date; while (local_filesystem.GetNextFile(file, wasLink, is_dir, 0, &date, &attributes)) { wxASSERT(is_dir); if (file == _T("")) { wxGetApp().DisplayEncodingWarning(); continue; } if (filter.FilenameFiltered(file, dirname, true, size, true, attributes, date.IsValid() ? &date : 0)) continue; return file; } return _T(""); }
wxString CLocalTreeView::HasSubdir(const wxString& dirname) { wxLogNull nullLog; CFilterManager filter; fz::local_filesys local_filesys; if (!local_filesys.begin_find_files(fz::to_native(dirname), true)) return wxString(); fz::native_string file; bool wasLink; int attributes; bool is_dir; static int64_t const size(-1); fz::datetime date; while (local_filesys.get_next_file(file, wasLink, is_dir, 0, &date, &attributes)) { wxASSERT(is_dir); if (file.empty()) { wxGetApp().DisplayEncodingWarning(); continue; } wxString file_wx = file; if (filter.FilenameFiltered(file_wx, dirname, true, size, true, attributes, date)) continue; return file_wx; } return wxString(); }
bool CRemoteTreeView::HasSubdirs(const CDirectoryListing& listing, const CFilterManager& filter) { if (!listing.has_dirs()) return false; if (!filter.HasActiveFilters()) return true; const wxString path = listing.path.GetPath(); for (unsigned int i = 0; i < listing.GetCount(); i++) { if (!listing[i].is_dir()) continue; if (filter.FilenameFiltered(listing[i].name, path, true, -1, false, 0, listing[i].time)) continue; return true; } return false; }
void CRemoteRecursiveOperation::ProcessDirectoryListing(const CDirectoryListing* pDirectoryListing) { if (!pDirectoryListing) { StopRecursiveOperation(); return; } if (m_operationMode == recursive_none || recursion_roots_.empty()) return; if (pDirectoryListing->failed()) { // Ignore this. // It will get handled by the failed command in ListingFailed return; } auto & root = recursion_roots_.front(); wxASSERT(!root.m_dirsToVisit.empty()); if (!m_state.IsRemoteConnected() || root.m_dirsToVisit.empty()) { StopRecursiveOperation(); return; } recursion_root::new_dir dir = root.m_dirsToVisit.front(); root.m_dirsToVisit.pop_front(); if (!BelowRecursionRoot(pDirectoryListing->path, dir)) { NextOperation(); return; } if (m_operationMode == recursive_delete && dir.doVisit && !dir.subdir.empty()) { // After recursing into directory to delete its contents, delete directory itself // Gets handled in NextOperation recursion_root::new_dir dir2 = dir; dir2.doVisit = false; root.m_dirsToVisit.push_front(dir2); } if (dir.link && !dir.recurse) { NextOperation(); return; } // Check if we have already visited the directory if (!root.m_visitedDirs.insert(pDirectoryListing->path).second) { NextOperation(); return; } ++m_processedDirectories; const CServer* pServer = m_state.GetServer(); wxASSERT(pServer); if (!pDirectoryListing->GetCount()) { if (m_operationMode == recursive_transfer) { wxFileName::Mkdir(dir.localDir.GetPath(), 0777, wxPATH_MKDIR_FULL); m_state.RefreshLocalFile(dir.localDir.GetPath()); } else if (m_operationMode == recursive_addtoqueue) { m_pQueue->QueueFile(true, true, _T(""), _T(""), dir.localDir, CServerPath(), *pServer, -1); m_pQueue->QueueFile_Finish(false); } } CFilterManager filter; // Is operation restricted to a single child? bool const restrict = static_cast<bool>(dir.restrict); std::deque<wxString> filesToDelete; const wxString path = pDirectoryListing->path.GetPath(); bool added = false; for (int i = pDirectoryListing->GetCount() - 1; i >= 0; --i) { const CDirentry& entry = (*pDirectoryListing)[i]; if (restrict) { if (entry.name != *dir.restrict) continue; } else if (filter.FilenameFiltered(m_filters, entry.name, path, entry.is_dir(), entry.size, 0, entry.time)) continue; if (!entry.is_dir()) { ++m_processedFiles; } if (entry.is_dir() && (!entry.is_link() || m_operationMode != recursive_delete)) { if (dir.recurse) { recursion_root::new_dir dirToVisit; dirToVisit.parent = pDirectoryListing->path; dirToVisit.subdir = entry.name; dirToVisit.localDir = dir.localDir; dirToVisit.start_dir = dir.start_dir; if (m_operationMode == recursive_transfer || m_operationMode == recursive_addtoqueue) { // Non-flatten case dirToVisit.localDir.AddSegment(CQueueView::ReplaceInvalidCharacters(entry.name)); } if (entry.is_link()) { dirToVisit.link = 1; dirToVisit.recurse = false; } root.m_dirsToVisit.push_front(dirToVisit); } } else { switch (m_operationMode) { case recursive_transfer: case recursive_transfer_flatten: { wxString localFile = CQueueView::ReplaceInvalidCharacters(entry.name); if (pDirectoryListing->path.GetType() == VMS && COptions::Get()->GetOptionVal(OPTION_STRIP_VMS_REVISION)) localFile = StripVMSRevision(localFile); m_pQueue->QueueFile(m_operationMode == recursive_addtoqueue, true, entry.name, (entry.name == localFile) ? wxString() : localFile, dir.localDir, pDirectoryListing->path, *pServer, entry.size); added = true; } break; case recursive_addtoqueue: case recursive_addtoqueue_flatten: { wxString localFile = CQueueView::ReplaceInvalidCharacters(entry.name); if (pDirectoryListing->path.GetType() == VMS && COptions::Get()->GetOptionVal(OPTION_STRIP_VMS_REVISION)) localFile = StripVMSRevision(localFile); m_pQueue->QueueFile(true, true, entry.name, (entry.name == localFile) ? wxString() : localFile, dir.localDir, pDirectoryListing->path, *pServer, entry.size); added = true; } break; case recursive_delete: filesToDelete.push_back(entry.name); break; default: break; } } if (m_operationMode == recursive_chmod && m_pChmodDlg) { const int applyType = m_pChmodDlg->GetApplyType(); if (!applyType || (!entry.is_dir() && applyType == 1) || (entry.is_dir() && applyType == 2)) { char permissions[9]; bool res = m_pChmodDlg->ConvertPermissions(*entry.permissions, permissions); wxString newPerms = m_pChmodDlg->GetPermissions(res ? permissions : 0, entry.is_dir()); m_state.m_pCommandQueue->ProcessCommand(new CChmodCommand(pDirectoryListing->path, entry.name, newPerms), CCommandQueue::recursiveOperation); } } } if (added) m_pQueue->QueueFile_Finish(m_operationMode != recursive_addtoqueue && m_operationMode != recursive_addtoqueue_flatten); if (m_operationMode == recursive_delete && !filesToDelete.empty()) m_state.m_pCommandQueue->ProcessCommand(new CDeleteCommand(pDirectoryListing->path, std::move(filesToDelete)), CCommandQueue::recursiveOperation); m_state.NotifyHandlers(STATECHANGE_REMOTE_RECURSION_STATUS); NextOperation(); }
void CLocalTreeView::Refresh() { wxLogNull nullLog; const wxString separator = wxFileName::GetPathSeparator(); std::list<t_dir> dirsToCheck; #ifdef __WXMSW__ int prevErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); wxTreeItemIdValue tmp; wxTreeItemId child = GetFirstChild(m_drives, tmp); while (child) { if (IsExpanded(child)) { wxString drive = GetItemText(child); int pos = drive.Find(_T(" ")); if (pos != -1) drive = drive.Left(pos); t_dir dir; dir.dir = drive + separator; dir.item = child; dirsToCheck.push_back(dir); } child = GetNextSibling(child); } #else t_dir dir; dir.dir = separator; dir.item = GetRootItem(); dirsToCheck.push_back(dir); #endif CFilterManager filter; while (!dirsToCheck.empty()) { t_dir dir = dirsToCheck.front(); dirsToCheck.pop_front(); // Step 1: Check if directory exists CLocalFileSystem local_filesystem; if (!local_filesystem.BeginFindFiles(dir.dir, true)) { // Dir does exist (listed in parent) but may not be accessible. // Recurse into children anyhow, they might be accessible again. wxTreeItemIdValue value; wxTreeItemId child = GetFirstChild(dir.item, value); while (child) { t_dir subdir; subdir.dir = dir.dir + GetItemText(child) + separator; subdir.item = child; dirsToCheck.push_back(subdir); child = GetNextSibling(child); } continue; } // Step 2: Enumerate subdirectories on disk and sort them std::list<wxString> dirs; wxString file; const wxLongLong size(-1); bool was_link; bool is_dir; int attributes; wxDateTime date; while (local_filesystem.GetNextFile(file, was_link, is_dir, 0, &date, &attributes)) { if (file == _T("")) { wxGetApp().DisplayEncodingWarning(); continue; } if (filter.FilenameFiltered(file, dir.dir, true, size, true, attributes, date.IsValid() ? &date : 0)) continue; dirs.push_back(file); } dirs.sort(sortfunc); bool inserted = false; // Step 3: Merge list of subdirectories with subtree. wxTreeItemId child = GetLastChild(dir.item); std::list<wxString>::reverse_iterator iter = dirs.rbegin(); while (child || iter != dirs.rend()) { int cmp; if (child && iter != dirs.rend()) #ifdef __WXMSW__ cmp = GetItemText(child).CmpNoCase(*iter); #else cmp = GetItemText(child).Cmp(*iter); #endif else if (child) cmp = 1; else cmp = -1; if (!cmp) { // Found item with same name. Mark it for further processing if (!IsExpanded(child)) { wxString path = dir.dir + *iter + separator; if (!CheckSubdirStatus(child, path)) { t_dir subdir; subdir.dir = path; subdir.item = child; dirsToCheck.push_front(subdir); } } else { t_dir subdir; subdir.dir = dir.dir + *iter + separator; subdir.item = child; dirsToCheck.push_front(subdir); } child = GetPrevSibling(child); ++iter; } else if (cmp > 0) { // Subdirectory currently in tree no longer exists. // Delete child from tree, unless current selection // is in the subtree. wxTreeItemId sel = GetSelection(); while (sel && sel != child) sel = GetItemParent(sel); wxTreeItemId prev = GetPrevSibling(child); if (!sel) Delete(child); child = prev; } else if (cmp < 0) { // New subdirectory, add treeitem wxString fullname = dir.dir + *iter + separator; wxTreeItemId newItem = AppendItem(dir.item, *iter, GetIconIndex(::dir, fullname), #ifdef __WXMSW__ -1 #else GetIconIndex(opened_dir, fullname) #endif ); CheckSubdirStatus(newItem, fullname); ++iter; inserted = true; } } if (inserted) SortChildren(dir.item); }
void CLocalTreeView::DisplayDir(wxTreeItemId parent, const wxString& dirname, const wxString& knownSubdir /*=_T("")*/) { CLocalFileSystem local_filesystem; { wxLogNull log; if (!local_filesystem.BeginFindFiles(dirname, true)) { if (knownSubdir != _T("")) { wxTreeItemId item = GetSubdir(parent, knownSubdir); if (item != wxTreeItemId()) return; const wxString fullName = dirname + knownSubdir; item = AppendItem(parent, knownSubdir, GetIconIndex(::dir, fullName), #ifdef __WXMSW__ -1 #else GetIconIndex(opened_dir, fullName) #endif ); CheckSubdirStatus(item, fullName); } else { m_setSelection = true; DeleteChildren(parent); m_setSelection = false; } return; } } wxASSERT(parent); m_setSelection = true; DeleteChildren(parent); m_setSelection = false; CFilterManager filter; bool matchedKnown = false; wxString file; bool wasLink; int attributes; bool is_dir; const wxLongLong size(-1); wxDateTime date; while (local_filesystem.GetNextFile(file, wasLink, is_dir, 0, &date, &attributes)) { wxASSERT(is_dir); if (file == _T("")) { wxGetApp().DisplayEncodingWarning(); continue; } wxString fullName = dirname + file; #ifdef __WXMSW__ if (file.CmpNoCase(knownSubdir)) #else if (file != knownSubdir) #endif { if (filter.FilenameFiltered(file, dirname, true, size, true, attributes, date.IsValid() ? &date : 0)) continue; } else matchedKnown = true; wxTreeItemId item = AppendItem(parent, file, GetIconIndex(::dir, fullName), #ifdef __WXMSW__ -1 #else GetIconIndex(opened_dir, fullName) #endif ); CheckSubdirStatus(item, fullName); } if (!matchedKnown && knownSubdir != _T("")) { const wxString fullName = dirname + knownSubdir; wxTreeItemId item = AppendItem(parent, knownSubdir, GetIconIndex(::dir, fullName), #ifdef __WXMSW__ -1 #else GetIconIndex(opened_dir, fullName) #endif ); CheckSubdirStatus(item, fullName); } SortChildren(parent); }
void CRemoteTreeView::RefreshItem(wxTreeItemId parent, const CDirectoryListing& listing, bool will_select_parent) { SetItemImages(parent, false); wxTreeItemIdValue cookie; wxTreeItemId child = GetFirstChild(parent, cookie); if (!child || GetItemText(child).empty()) { DisplayItem(parent, listing); return; } CFilterManager filter; wxString const path = listing.path.GetPath(); wxArrayString dirs; for (unsigned int i = 0; i < listing.GetCount(); ++i) { if (!listing[i].is_dir()) continue; if (!filter.FilenameFiltered(listing[i].name, path, true, -1, false, 0, listing[i].time)) dirs.push_back(listing[i].name); } auto const& sortFunc = CFileListCtrlSortBase::GetCmpFunction(m_nameSortMode); dirs.Sort(sortFunc); bool inserted = false; child = GetLastChild(parent); wxArrayString::reverse_iterator iter = dirs.rbegin(); while (child && iter != dirs.rend()) { int cmp = sortFunc(GetItemText(child), *iter); if (!cmp) { CServerPath childPath = listing.path; childPath.AddSegment(*iter); CDirectoryListing subListing; if (m_pState->m_pEngine->CacheLookup(childPath, subListing) == FZ_REPLY_OK) { if (!GetLastChild(child) && HasSubdirs(subListing, filter)) AppendItem(child, _T(""), -1, -1); SetItemImages(child, false); } else SetItemImages(child, true); child = GetPrevSibling(child); ++iter; } else if (cmp > 0) { // Child no longer exists wxTreeItemId sel = GetSelection(); while (sel && sel != child) sel = GetItemParent(sel); wxTreeItemId prev = GetPrevSibling(child); if (!sel || will_select_parent) Delete(child); child = prev; } else if (cmp < 0) { // New directory CServerPath childPath = listing.path; childPath.AddSegment(*iter); CDirectoryListing subListing; if (m_pState->m_pEngine->CacheLookup(childPath, subListing) == FZ_REPLY_OK) { wxTreeItemId childItem = AppendItem(parent, *iter, 0, 2, 0); if (childItem) { SetItemImages(childItem, false); if (HasSubdirs(subListing, filter)) { AppendItem(childItem, _T(""), -1, -1); } } } else { wxTreeItemId childItem = AppendItem(parent, *iter, 1, 3, 0); if (childItem) { SetItemImages(childItem, true); } } ++iter; inserted = true; } } while (child) { // Child no longer exists wxTreeItemId sel = GetSelection(); while (sel && sel != child) sel = GetItemParent(sel); wxTreeItemId prev = GetPrevSibling(child); if (!sel || will_select_parent) Delete(child); child = prev; } while (iter != dirs.rend()) { CServerPath childPath = listing.path; childPath.AddSegment(*iter); CDirectoryListing subListing; if (m_pState->m_pEngine->CacheLookup(childPath, subListing) == FZ_REPLY_OK) { wxTreeItemId childItem = AppendItem(parent, *iter, 0, 2, 0); if (childItem) { SetItemImages(childItem, false); if (HasSubdirs(subListing, filter)) { AppendItem(childItem, _T(""), -1, -1); } } } else { wxTreeItemId childItem = AppendItem(parent, *iter, 1, 3, 0); if (childItem) { SetItemImages(childItem, true); } } ++iter; inserted = true; } if (inserted) SortChildren(parent); }
void CRemoteTreeView::ApplyFilters(bool resort) { std::list<struct _parents> parents; const wxTreeItemId root = GetRootItem(); wxTreeItemIdValue cookie; for (wxTreeItemId child = GetFirstChild(root, cookie); child; child = GetNextSibling(child)) { CServerPath path = GetPathFromItem(child); if (path.empty()) continue; struct _parents dir; dir.item = child; dir.path = path; parents.push_back(dir); } CFilterManager filter; while (!parents.empty()) { struct _parents parent = parents.back(); parents.pop_back(); if (resort) { SortChildren(parent.item); } CDirectoryListing listing; if (m_pState->m_pEngine->CacheLookup(parent.path, listing) == FZ_REPLY_OK) RefreshItem(parent.item, listing, false); else if (filter.HasActiveFilters()) { for (wxTreeItemId child = GetFirstChild(parent.item, cookie); child; child = GetNextSibling(child)) { CServerPath path = GetPathFromItem(child); if (path.empty()) continue; if (filter.FilenameFiltered(GetItemText(child), path.GetPath(), true, -1, false, 0, CDateTime())) { wxTreeItemId sel = GetSelection(); while (sel && sel != child) sel = GetItemParent(sel); if (!sel) { Delete(child); continue; } } struct _parents dir; dir.item = child; dir.path = path; parents.push_back(dir); } // The stuff below has already been done above in this one case continue; } for (wxTreeItemId child = GetFirstChild(parent.item, cookie); child; child = GetNextSibling(child)) { CServerPath path = GetPathFromItem(child); if (path.empty()) continue; struct _parents dir; dir.item = child; dir.path = path; parents.push_back(dir); } } }
bool CLocalListView::DisplayDir(wxString dirname) { CancelLabelEdit(); wxString focused; std::list<wxString> selectedNames; bool ensureVisible = false; if (m_dir != dirname) { ResetSearchPrefix(); if (IsComparing()) ExitComparisonMode(); ClearSelection(); focused = m_pState->GetPreviouslyVisitedLocalSubdir(); ensureVisible = !focused.IsEmpty(); if (focused.IsEmpty()) focused = _T(".."); if (GetItemCount()) EnsureVisible(0); m_dir = dirname; } else { // Remember which items were selected selectedNames = RememberSelectedItems(focused); } if (m_pFilelistStatusBar) m_pFilelistStatusBar->UnselectAll(); const int oldItemCount = m_indexMapping.size(); m_fileData.clear(); m_indexMapping.clear(); m_hasParent = CLocalPath(dirname).HasLogicalParent(); if (m_hasParent) { CLocalFileData data; data.flags = normal; data.dir = true; data.icon = -2; data.name = _T(".."); #ifdef __WXMSW__ data.label = _T(".."); #endif data.size = -1; m_fileData.push_back(data); m_indexMapping.push_back(0); } #ifdef __WXMSW__ if (dirname == _T("\\")) { DisplayDrives(); } else if (dirname.Left(2) == _T("\\\\")) { int pos = dirname.Mid(2).Find('\\'); if (pos != -1 && pos + 3 != (int)dirname.Len()) goto regular_dir; // UNC path without shares DisplayShares(dirname); } else #endif { #ifdef __WXMSW__ regular_dir: #endif CFilterManager filter; CLocalFileSystem local_filesystem; if (!local_filesystem.BeginFindFiles(dirname, false)) { SetItemCount(1); return false; } wxLongLong totalSize; int unknown_sizes = 0; int totalFileCount = 0; int totalDirCount = 0; int hidden = 0; int num = m_fileData.size(); CLocalFileData data; data.flags = normal; data.icon = -2; bool wasLink; while (local_filesystem.GetNextFile(data.name, wasLink, data.dir, &data.size, &data.lastModified, &data.attributes)) { if (data.name.IsEmpty()) { wxGetApp().DisplayEncodingWarning(); continue; } #ifdef __WXMSW__ data.label = data.name; #endif m_fileData.push_back(data); if (!filter.FilenameFiltered(data.name, dirname, data.dir, data.size, true, data.attributes, data.lastModified)) { if (data.dir) totalDirCount++; else { if (data.size != -1) totalSize += data.size; else unknown_sizes++; totalFileCount++; } m_indexMapping.push_back(num); } else hidden++; num++; } if (m_pFilelistStatusBar) m_pFilelistStatusBar->SetDirectoryContents(totalFileCount, totalDirCount, totalSize, unknown_sizes, hidden); } if (m_dropTarget != -1) { CLocalFileData* data = GetData(m_dropTarget); if (!data || !data->dir) { SetItemState(m_dropTarget, 0, wxLIST_STATE_DROPHILITED); m_dropTarget = -1; } } const int count = m_indexMapping.size(); if (oldItemCount != count) SetItemCount(count); SortList(-1, -1, false); if (IsComparing()) { m_originalIndexMapping.clear(); RefreshComparison(); } ReselectItems(selectedNames, focused, ensureVisible); RefreshListOnly(); return true; }
void CLocalListView::RefreshFile(const wxString& file) { CLocalFileData data; bool wasLink; enum CLocalFileSystem::local_fileType type = CLocalFileSystem::GetFileInfo(m_dir + file, wasLink, &data.size, &data.lastModified, &data.attributes); if (type == CLocalFileSystem::unknown) return; data.flags = normal; data.icon = -2; data.name = file; #ifdef __WXMSW__ data.label = file; #endif data.dir = type == CLocalFileSystem::dir; CFilterManager filter; if (filter.FilenameFiltered(data.name, m_dir, data.dir, data.size, true, data.attributes, data.lastModified)) return; CancelLabelEdit(); // Look if file data already exists unsigned int i = 0; for (std::vector<CLocalFileData>::iterator iter = m_fileData.begin(); iter != m_fileData.end(); ++iter, ++i) { const CLocalFileData& oldData = *iter; if (oldData.name != file) continue; // Update file list status bar if (m_pFilelistStatusBar) { #ifndef __WXMSW__ // GetNextItem is O(n) if nothing is selected, GetSelectedItemCount() is O(1) if (GetSelectedItemCount()) #endif { int item = -1; for (;;) { item = GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if (item == -1) break; if (m_indexMapping[item] != i) continue; if (oldData.dir) m_pFilelistStatusBar->UnselectDirectory(); else m_pFilelistStatusBar->UnselectFile(oldData.size); if (data.dir) m_pFilelistStatusBar->SelectDirectory(); else m_pFilelistStatusBar->SelectFile(data.size); break; } } if (oldData.dir) m_pFilelistStatusBar->RemoveDirectory(); else m_pFilelistStatusBar->RemoveFile(oldData.size); if (data.dir) m_pFilelistStatusBar->AddDirectory(); else m_pFilelistStatusBar->AddFile(data.size); } // Update the data data.fileType = oldData.fileType; *iter = data; if (IsComparing()) { // Sort order doesn't change RefreshComparison(); } else { if (m_sortColumn) SortList(); RefreshListOnly(false); } return; } if (data.dir) m_pFilelistStatusBar->AddDirectory(); else m_pFilelistStatusBar->AddFile(data.size); wxString focused; std::list<wxString> selectedNames; if (IsComparing()) { wxASSERT(!m_originalIndexMapping.empty()); selectedNames = RememberSelectedItems(focused); m_indexMapping.clear(); m_originalIndexMapping.swap(m_indexMapping); } // Insert new entry int index = m_fileData.size(); m_fileData.push_back(data); // Find correct position in index mapping std::vector<unsigned int>::iterator start = m_indexMapping.begin(); if (m_hasParent) ++start; CFileListCtrl<CLocalFileData>::CSortComparisonObject compare = GetSortComparisonObject(); std::vector<unsigned int>::iterator insertPos = std::lower_bound(start, m_indexMapping.end(), index, compare); compare.Destroy(); const int item = insertPos - m_indexMapping.begin(); m_indexMapping.insert(insertPos, index); if (!IsComparing()) { SetItemCount(m_indexMapping.size()); // Move selections int prevState = 0; for (unsigned int i = item; i < m_indexMapping.size(); i++) { int state = GetItemState(i, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); if (state != prevState) { SetItemState(i, prevState, wxLIST_STATE_FOCUSED); SetSelection(i, (prevState & wxLIST_STATE_SELECTED) != 0); prevState = state; } } RefreshListOnly(); } else { RefreshComparison(); if (m_pFilelistStatusBar) m_pFilelistStatusBar->UnselectAll(); ReselectItems(selectedNames, focused); } }
void CLocalListView::ApplyCurrentFilter() { CFilterManager filter; if (!filter.HasSameLocalAndRemoteFilters() && IsComparing()) ExitComparisonMode(); unsigned int min = m_hasParent ? 1 : 0; if (m_fileData.size() <= min) return; wxString focused; const std::list<wxString>& selectedNames = RememberSelectedItems(focused); if (m_pFilelistStatusBar) m_pFilelistStatusBar->UnselectAll(); wxLongLong totalSize; int unknown_sizes = 0; int totalFileCount = 0; int totalDirCount = 0; int hidden = 0; m_indexMapping.clear(); if (m_hasParent) m_indexMapping.push_back(0); for (unsigned int i = min; i < m_fileData.size(); i++) { const CLocalFileData& data = m_fileData[i]; if (data.flags == fill) continue; if (filter.FilenameFiltered(data.name, m_dir, data.dir, data.size, true, data.attributes, data.lastModified)) { hidden++; continue; } if (data.dir) totalDirCount++; else { if (data.size != -1) totalSize += data.size; else unknown_sizes++; totalFileCount++; } m_indexMapping.push_back(i); } SetItemCount(m_indexMapping.size()); if (m_pFilelistStatusBar) m_pFilelistStatusBar->SetDirectoryContents(totalFileCount, totalDirCount, totalSize, unknown_sizes, hidden); SortList(-1, -1, false); if (IsComparing()) { m_originalIndexMapping.clear(); RefreshComparison(); } ReselectItems(selectedNames, focused); if (!IsComparing()) RefreshListOnly(); }
void CRemoteTreeView::RefreshItem(wxTreeItemId parent, const CDirectoryListing& listing, bool will_select_parent) { SetItemImages(parent, false); wxTreeItemIdValue cookie; wxTreeItemId child = GetFirstChild(parent, cookie); if (!child || GetItemText(child) == _T("")) { DisplayItem(parent, listing); return; } CFilterManager filter; const wxString path = listing.path.GetPath(); std::list<wxString> dirs; for (unsigned int i = 0; i < listing.GetCount(); i++) { if (!listing[i].is_dir()) continue; if (!filter.FilenameFiltered(listing[i].name, path, true, -1, false, 0, listing[i].has_date() ? &listing[i].time : 0)) dirs.push_back(listing[i].name); } dirs.sort(sortfunc); bool inserted = false; child = GetLastChild(parent); std::list<wxString>::reverse_iterator iter = dirs.rbegin(); while (child && iter != dirs.rend()) { int cmp = GetItemText(child).CmpNoCase(*iter); if (!cmp) cmp = GetItemText(child).Cmp(*iter); if (!cmp) { CServerPath path = listing.path; path.AddSegment(*iter); CDirectoryListing subListing; if (m_pState->m_pEngine->CacheLookup(path, subListing) == FZ_REPLY_OK) { if (!GetLastChild(child) && HasSubdirs(subListing, filter)) AppendItem(child, _T(""), -1, -1); SetItemImages(child, false); } else SetItemImages(child, true); child = GetPrevSibling(child); iter++; } else if (cmp > 0) { // Child no longer exists wxTreeItemId sel = GetSelection(); while (sel && sel != child) sel = GetItemParent(sel); wxTreeItemId prev = GetPrevSibling(child); if (!sel || will_select_parent) Delete(child); child = prev; } else if (cmp < 0) { // New directory CServerPath path = listing.path; path.AddSegment(*iter); CDirectoryListing subListing; if (m_pState->m_pEngine->CacheLookup(path, subListing) == FZ_REPLY_OK) { wxTreeItemId child = AppendItem(parent, *iter, 0, 2, 0); SetItemImages(child, false); if (HasSubdirs(subListing, filter)) AppendItem(child, _T(""), -1, -1); } else { wxTreeItemId child = AppendItem(parent, *iter, 1, 3, 0); if (child) SetItemImages(child, true); } iter++; inserted = true; } } while (child) { // Child no longer exists wxTreeItemId sel = GetSelection(); while (sel && sel != child) sel = GetItemParent(sel); wxTreeItemId prev = GetPrevSibling(child); if (!sel || will_select_parent) Delete(child); child = prev; } while (iter != dirs.rend()) { CServerPath path = listing.path; path.AddSegment(*iter); CDirectoryListing subListing; if (m_pState->m_pEngine->CacheLookup(path, subListing) == FZ_REPLY_OK) { wxTreeItemId child = AppendItem(parent, *iter, 0, 2, 0); SetItemImages(child, false); if (HasSubdirs(subListing, filter)) AppendItem(child, _T(""), -1, -1); } else { wxTreeItemId child = AppendItem(parent, *iter, 1, 3, 0); SetItemImages(child, true); } iter++; inserted = true; } if (inserted) SortChildren(parent); }
void CLocalTreeView::DisplayDir(wxTreeItemId parent, const wxString& dirname, const wxString& knownSubdir /*=_T("")*/) { fz::local_filesys local_filesys; { wxLogNull log; if (!local_filesys.begin_find_files(fz::to_native(dirname), true)) { if (!knownSubdir.empty()) { wxTreeItemId item = GetSubdir(parent, knownSubdir); if (item != wxTreeItemId()) return; const wxString fullName = dirname + knownSubdir; item = AppendItem(parent, knownSubdir, GetIconIndex(iconType::dir, fullName), #ifdef __WXMSW__ -1 #else GetIconIndex(iconType::opened_dir, fullName) #endif ); CheckSubdirStatus(item, fullName); } else { m_setSelection = true; DeleteChildren(parent); m_setSelection = false; } return; } } wxASSERT(parent); m_setSelection = true; DeleteChildren(parent); m_setSelection = false; CFilterManager filter; bool matchedKnown = false; fz::native_string file; bool wasLink; int attributes; bool is_dir; static int64_t const size(-1); fz::datetime date; while (local_filesys.get_next_file(file, wasLink, is_dir, 0, &date, &attributes)) { wxASSERT(is_dir); if (file.empty()) { wxGetApp().DisplayEncodingWarning(); continue; } wxString file_wx = file; wxString fullName = dirname + file_wx; #ifdef __WXMSW__ if (file_wx.CmpNoCase(knownSubdir)) #else if (file_wx != knownSubdir) #endif { if (filter.FilenameFiltered(file_wx, dirname, true, size, true, attributes, date)) continue; } else matchedKnown = true; wxTreeItemId item = AppendItem(parent, file_wx, GetIconIndex(iconType::dir, fullName), #ifdef __WXMSW__ -1 #else GetIconIndex(iconType::opened_dir, fullName) #endif ); CheckSubdirStatus(item, fullName); } if (!matchedKnown && !knownSubdir.empty()) { const wxString fullName = dirname + knownSubdir; wxTreeItemId item = AppendItem(parent, knownSubdir, GetIconIndex(iconType::dir, fullName), #ifdef __WXMSW__ -1 #else GetIconIndex(iconType::opened_dir, fullName) #endif ); CheckSubdirStatus(item, fullName); } SortChildren(parent); }
void CRemoteRecursiveOperation::ProcessDirectoryListing(const CDirectoryListing* pDirectoryListing) { if (!pDirectoryListing) { StopRecursiveOperation(); return; } if (m_operationMode == recursive_none || recursion_roots_.empty()) return; if (pDirectoryListing->failed()) { // Ignore this. // It will get handled by the failed command in ListingFailed return; } auto & root = recursion_roots_.front(); wxASSERT(!root.m_dirsToVisit.empty()); if (!m_state.IsRemoteConnected() || root.m_dirsToVisit.empty()) { StopRecursiveOperation(); return; } recursion_root::new_dir dir = root.m_dirsToVisit.front(); root.m_dirsToVisit.pop_front(); if (!BelowRecursionRoot(pDirectoryListing->path, dir)) { NextOperation(); return; } if (m_operationMode == recursive_delete && dir.doVisit && !dir.subdir.empty()) { // After recursing into directory to delete its contents, delete directory itself // Gets handled in NextOperation recursion_root::new_dir dir2 = dir; dir2.doVisit = false; root.m_dirsToVisit.push_front(dir2); } if (dir.link && !dir.recurse) { NextOperation(); return; } // Check if we have already visited the directory if (!root.m_visitedDirs.insert(pDirectoryListing->path).second) { NextOperation(); return; } ++m_processedDirectories; const CServer* pServer = m_state.GetServer(); wxASSERT(pServer); if (!pDirectoryListing->GetCount() && m_operationMode == recursive_transfer) { if (m_immediate) { wxFileName::Mkdir(dir.localDir.GetPath(), 0777, wxPATH_MKDIR_FULL); m_state.RefreshLocalFile(dir.localDir.GetPath()); } else { m_pQueue->QueueFile(true, true, _T(""), _T(""), dir.localDir, CServerPath(), *pServer, -1); m_pQueue->QueueFile_Finish(false); } } CFilterManager filter; // Is operation restricted to a single child? bool const restrict = static_cast<bool>(dir.restrict); std::deque<std::wstring> filesToDelete; std::wstring const remotePath = pDirectoryListing->path.GetPath(); if (m_operationMode == recursive_synchronize_download && !dir.localDir.empty()) { // Step one in synchronization: Delete local files not on the server fz::local_filesys fs; if (fs.begin_find_files(fz::to_native(dir.localDir.GetPath()))) { std::list<fz::native_string> paths_to_delete; bool isLink{}; fz::native_string name; bool isDir{}; int64_t size{}; fz::datetime time; int attributes{}; while (fs.get_next_file(name, isLink, isDir, &size, &time, &attributes)) { if (isLink) { continue; } auto const wname = fz::to_wstring(name); if (filter.FilenameFiltered(m_filters.first, wname, dir.localDir.GetPath(), isDir, size, attributes, time)) { continue; } // Local item isn't filtered int remoteIndex = pDirectoryListing->FindFile_CmpCase(fz::to_wstring(name)); if (remoteIndex != -1) { CDirentry const& entry = (*pDirectoryListing)[remoteIndex]; if (!filter.FilenameFiltered(m_filters.second, entry.name, remotePath, entry.is_dir(), entry.size, 0, entry.time)) { // Both local and remote items exist if (isDir == entry.is_dir() || entry.is_link()) { // Normal item, nothing we should do continue; } } } // Local item should be deleted if reaching this point paths_to_delete.push_back(fz::to_native(dir.localDir.GetPath()) + name); } fz::recursive_remove r; r.remove(paths_to_delete); } } bool added = false; for (int i = pDirectoryListing->GetCount() - 1; i >= 0; --i) { const CDirentry& entry = (*pDirectoryListing)[i]; if (restrict) { if (entry.name != *dir.restrict) continue; } else if (filter.FilenameFiltered(m_filters.second, entry.name, remotePath, entry.is_dir(), entry.size, 0, entry.time)) continue; if (!entry.is_dir()) { ++m_processedFiles; } if (entry.is_dir() && (!entry.is_link() || m_operationMode != recursive_delete)) { if (dir.recurse) { recursion_root::new_dir dirToVisit; dirToVisit.parent = pDirectoryListing->path; dirToVisit.subdir = entry.name; dirToVisit.localDir = dir.localDir; dirToVisit.start_dir = dir.start_dir; if (m_operationMode == recursive_transfer || m_operationMode == recursive_synchronize_download) { // Non-flatten case dirToVisit.localDir.AddSegment(CQueueView::ReplaceInvalidCharacters(entry.name)); } if (entry.is_link()) { dirToVisit.link = 1; dirToVisit.recurse = false; } root.m_dirsToVisit.push_front(dirToVisit); } } else { switch (m_operationMode) { case recursive_transfer: case recursive_transfer_flatten: case recursive_synchronize_download: { std::wstring localFile = CQueueView::ReplaceInvalidCharacters(entry.name); if (pDirectoryListing->path.GetType() == VMS && COptions::Get()->GetOptionVal(OPTION_STRIP_VMS_REVISION)) { localFile = StripVMSRevision(localFile); } m_pQueue->QueueFile(!m_immediate, true, entry.name, (entry.name == localFile) ? std::wstring() : localFile, dir.localDir, pDirectoryListing->path, *pServer, entry.size); added = true; } break; case recursive_delete: filesToDelete.push_back(entry.name); break; default: break; } } if (m_operationMode == recursive_chmod && m_pChmodDlg) { const int applyType = m_pChmodDlg->GetApplyType(); if (!applyType || (!entry.is_dir() && applyType == 1) || (entry.is_dir() && applyType == 2)) { char permissions[9]; bool res = m_pChmodDlg->ConvertPermissions(*entry.permissions, permissions); std::wstring newPerms = m_pChmodDlg->GetPermissions(res ? permissions : 0, entry.is_dir()).ToStdWstring(); m_state.m_pCommandQueue->ProcessCommand(new CChmodCommand(pDirectoryListing->path, entry.name, newPerms), CCommandQueue::recursiveOperation); } } } if (added) { m_pQueue->QueueFile_Finish(m_immediate); } if (m_operationMode == recursive_delete && !filesToDelete.empty()) { m_state.m_pCommandQueue->ProcessCommand(new CDeleteCommand(pDirectoryListing->path, std::move(filesToDelete)), CCommandQueue::recursiveOperation); } m_state.NotifyHandlers(STATECHANGE_REMOTE_RECURSION_STATUS); NextOperation(); }
void CLocalTreeView::Refresh() { wxLogNull nullLog; const wxString separator = wxFileName::GetPathSeparator(); std::list<t_dir> dirsToCheck; #ifdef __WXMSW__ int prevErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); wxTreeItemIdValue tmp; wxTreeItemId child = GetFirstChild(m_drives, tmp); while (child) { if (IsExpanded(child)) { wxString drive = GetItemText(child); int pos = drive.Find(_T(" ")); if (pos != -1) drive = drive.Left(pos); t_dir dir; dir.dir = drive + separator; dir.item = child; dirsToCheck.push_back(dir); } child = GetNextSibling(child); } #else t_dir dir; dir.dir = separator; dir.item = GetRootItem(); dirsToCheck.push_back(dir); #endif CFilterManager filter; while (!dirsToCheck.empty()) { t_dir dir = dirsToCheck.front(); dirsToCheck.pop_front(); CLocalFileSystem local_filesystem; if (!local_filesystem.BeginFindFiles(dir.dir, true)) { // Dir does exist (listed in parent) but may not be accessible. // Recurse into children anyhow, they might be accessible again. wxTreeItemIdValue value; wxTreeItemId child = GetFirstChild(dir.item, value); while (child) { t_dir subdir; subdir.dir = dir.dir + GetItemText(child) + separator; subdir.item = child; dirsToCheck.push_back(subdir); child = GetNextSibling(child); } continue; } std::list<wxString> dirs; wxString file; const wxLongLong size(-1); bool was_link; bool is_dir; int attributes; while (local_filesystem.GetNextFile(file, was_link, is_dir, 0, 0, &attributes)) { if (file == _T("")) { wxGetApp().DisplayEncodingWarning(); continue; } if (filter.FilenameFiltered(file, dir.dir, true, size, true, attributes)) continue; dirs.push_back(file); } dirs.sort(sortfunc); bool inserted = false; wxTreeItemId child = GetLastChild(dir.item); std::list<wxString>::reverse_iterator iter = dirs.rbegin(); while (child && iter != dirs.rend()) { #ifdef __WXMSW__ int cmp = GetItemText(child).CmpNoCase(*iter); #else int cmp = GetItemText(child).Cmp(*iter); #endif if (!cmp) { if (!IsExpanded(child)) { wxString path = dir.dir + *iter + separator; if (!CheckSubdirStatus(child, path)) { t_dir subdir; subdir.dir = path; subdir.item = child; dirsToCheck.push_front(subdir); } } else { t_dir subdir; subdir.dir = dir.dir + *iter + separator; subdir.item = child; dirsToCheck.push_front(subdir); } child = GetPrevSibling(child); iter++; } else if (cmp > 0) { wxTreeItemId sel = GetSelection(); while (sel && sel != child) sel = GetItemParent(sel); wxTreeItemId prev = GetPrevSibling(child); if (!sel) Delete(child); child = prev; } else if (cmp < 0) { wxString fullname = dir.dir + *iter + separator; wxTreeItemId newItem = AppendItem(dir.item, *iter, GetIconIndex(::dir, fullname), #ifdef __WXMSW__ -1 #else GetIconIndex(opened_dir, fullname) #endif ); CheckSubdirStatus(newItem, fullname); iter++; inserted = true; } } while (child) { wxTreeItemId sel = GetSelection(); while (sel && sel != child) sel = GetItemParent(sel); wxTreeItemId prev = GetPrevSibling(child); if (!sel) Delete(child); child = prev; } while (iter != dirs.rend()) { wxString fullname = dir.dir + *iter + separator; wxTreeItemId newItem = AppendItem(dir.item, *iter, GetIconIndex(::dir, fullname), #ifdef __WXMSW__ -1 #else GetIconIndex(opened_dir, fullname) #endif ); CheckSubdirStatus(newItem, fullname); iter++; inserted = true; } if (inserted) SortChildren(dir.item); } #ifdef __WXMSW__ SetErrorMode(prevErrorMode); #endif }