#include "FileZilla.h" #include "RemoteTreeView.h" #include "commandqueue.h" #include #include "dndobjects.h" #include "chmoddialog.h" #include "recursive_operation.h" #include "inputdialog.h" #ifdef _DEBUG #define new DEBUG_NEW #endif class CItemData : public wxTreeItemData { public: CItemData(CServerPath path) : m_path(path) {} CServerPath m_path; }; class CRemoteTreeViewDropTarget : public wxDropTarget { public: CRemoteTreeViewDropTarget(CRemoteTreeView* pRemoteTreeView) : m_pRemoteTreeView(pRemoteTreeView), m_pFileDataObject(new wxFileDataObject()), m_pRemoteDataObject(new CRemoteDataObject()) { m_pDataObject = new wxDataObjectComposite; m_pDataObject->Add(m_pRemoteDataObject, true); m_pDataObject->Add(m_pFileDataObject, false); SetDataObject(m_pDataObject); } void ClearDropHighlight() { const wxTreeItemId dropHighlight = m_pRemoteTreeView->m_dropHighlight; if (dropHighlight != wxTreeItemId()) { m_pRemoteTreeView->SetItemDropHighlight(dropHighlight, false); m_pRemoteTreeView->m_dropHighlight = wxTreeItemId(); } } wxTreeItemId GetHit(const wxPoint& point) { int flags = 0; wxTreeItemId hit = m_pRemoteTreeView->HitTest(point, flags); if (flags & (wxTREE_HITTEST_ABOVE | wxTREE_HITTEST_BELOW | wxTREE_HITTEST_NOWHERE | wxTREE_HITTEST_TOLEFT | wxTREE_HITTEST_TORIGHT)) return wxTreeItemId(); return hit; } virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def) { if (def == wxDragError || def == wxDragNone || def == wxDragCancel) return def; wxTreeItemId hit = GetHit(wxPoint(x, y)); if (!hit) return wxDragNone; CServerPath path = m_pRemoteTreeView->GetPathFromItem(hit); if (path.IsEmpty()) return wxDragNone; if (!GetData()) return wxDragError; if (m_pDataObject->GetReceivedFormat() == m_pFileDataObject->GetFormat()) m_pRemoteTreeView->m_pState->UploadDroppedFiles(m_pFileDataObject, path, false); else { if (m_pRemoteDataObject->GetProcessId() != (int)wxGetProcessId()) { wxMessageBox(_("Drag&drop between different instances of FileZilla has not been implemented yet.")); return wxDragNone; } if (!m_pRemoteTreeView->m_pState->GetServer() || m_pRemoteDataObject->GetServer() != *m_pRemoteTreeView->m_pState->GetServer()) { wxMessageBox(_("Drag&drop between different servers has not been implemented yet.")); return wxDragNone; } // Make sure path path is valid if (path == m_pRemoteDataObject->GetServerPath()) { wxMessageBox(_("Source and path of the drop operation are identical")); return wxDragNone; } const std::list& files = m_pRemoteDataObject->GetFiles(); for (std::list::const_iterator iter = files.begin(); iter != files.end(); iter++) { const CRemoteDataObject::t_fileInfo& info = *iter; if (info.dir) { CServerPath dir = m_pRemoteDataObject->GetServerPath(); dir.AddSegment(info.name); if (dir == path || dir.IsParentOf(path, false)) { wxMessageBox(_("A directory cannot be dragged into one if its subdirectories.")); return wxDragNone; } } } for (std::list::const_iterator iter = files.begin(); iter != files.end(); iter++) { const CRemoteDataObject::t_fileInfo& info = *iter; m_pRemoteTreeView->m_pState->m_pCommandQueue->ProcessCommand( new CRenameCommand(m_pRemoteDataObject->GetServerPath(), info.name, path, info.name) ); } return wxDragNone; } return def; } virtual bool OnDrop(wxCoord x, wxCoord y) { ClearDropHighlight(); wxTreeItemId hit = GetHit(wxPoint(x, y)); if (!hit) return false; const CServerPath& path = m_pRemoteTreeView->GetPathFromItem(hit); if (path.IsEmpty()) return false; return true; } CServerPath DisplayDropHighlight(wxPoint point) { wxTreeItemId hit = GetHit(point); if (!hit) { ClearDropHighlight(); return CServerPath(); } const CServerPath& path = m_pRemoteTreeView->GetPathFromItem(hit); if (path.IsEmpty()) { ClearDropHighlight(); return CServerPath(); } const wxTreeItemId dropHighlight = m_pRemoteTreeView->m_dropHighlight; if (dropHighlight != wxTreeItemId()) m_pRemoteTreeView->SetItemDropHighlight(dropHighlight, false); m_pRemoteTreeView->SetItemDropHighlight(hit, true); m_pRemoteTreeView->m_dropHighlight = hit; return path; } virtual wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult def) { if (def == wxDragError || def == wxDragNone || def == wxDragCancel) { ClearDropHighlight(); return def; } const CServerPath& path = DisplayDropHighlight(wxPoint(x, y)); if (path.IsEmpty()) return wxDragNone; if (def == wxDragLink) def = wxDragCopy; return def; } virtual void OnLeave() { ClearDropHighlight(); } virtual wxDragResult OnEnter(wxCoord x, wxCoord y, wxDragResult def) { return OnDragOver(x, y, def); } protected: CRemoteTreeView *m_pRemoteTreeView; wxFileDataObject* m_pFileDataObject; CRemoteDataObject* m_pRemoteDataObject; wxDataObjectComposite* m_pDataObject; }; IMPLEMENT_CLASS(CRemoteTreeView, wxTreeCtrl) BEGIN_EVENT_TABLE(CRemoteTreeView, wxTreeCtrl) EVT_TREE_ITEM_EXPANDING(wxID_ANY, CRemoteTreeView::OnItemExpanding) EVT_TREE_SEL_CHANGED(wxID_ANY, CRemoteTreeView::OnSelectionChanged) EVT_TREE_ITEM_ACTIVATED(wxID_ANY, CRemoteTreeView::OnItemActivated) EVT_TREE_BEGIN_DRAG(wxID_ANY, CRemoteTreeView::OnBeginDrag) #ifndef __WXMSW__ EVT_KEY_DOWN(CRemoteTreeView::OnKeyDown) #endif //__WXMSW__ EVT_TREE_ITEM_MENU(wxID_ANY, CRemoteTreeView::OnContextMenu) EVT_MENU(XRCID("ID_CHMOD"), CRemoteTreeView::OnMenuChmod) EVT_MENU(XRCID("ID_DOWNLOAD"), CRemoteTreeView::OnMenuDownload) EVT_MENU(XRCID("ID_ADDTOQUEUE"), CRemoteTreeView::OnMenuDownload) EVT_MENU(XRCID("ID_DELETE"), CRemoteTreeView::OnMenuDelete) EVT_MENU(XRCID("ID_RENAME"), CRemoteTreeView::OnMenuRename) EVT_TREE_BEGIN_LABEL_EDIT(wxID_ANY, CRemoteTreeView::OnBeginLabelEdit) EVT_TREE_END_LABEL_EDIT(wxID_ANY, CRemoteTreeView::OnEndLabelEdit) EVT_MENU(XRCID("ID_MKDIR"), CRemoteTreeView::OnMkdir) END_EVENT_TABLE() CRemoteTreeView::CRemoteTreeView(wxWindow* parent, wxWindowID id, CState* pState, CQueueView* pQueue) : wxTreeCtrl(parent, id, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTR_EDIT_LABELS | wxTR_LINES_AT_ROOT | wxTR_HAS_BUTTONS | wxNO_BORDER | wxTR_HIDE_ROOT), CSystemImageList(16), CStateEventHandler(pState, STATECHANGE_REMOTE_DIR | STATECHANGE_REMOTE_DIR_MODIFIED | STATECHANGE_APPLYFILTER) { m_busy = false; m_pQueue = pQueue; AddRoot(_T("")); m_ExpandAfterList = wxTreeItemId(); CreateImageList(); SetDropTarget(new CRemoteTreeViewDropTarget(this)); Enable(false); } CRemoteTreeView::~CRemoteTreeView() { delete m_pImageList; } void CRemoteTreeView::OnStateChange(unsigned int event, const wxString& data) { if (event == STATECHANGE_REMOTE_DIR) SetDirectoryListing(m_pState->GetRemoteDir(), false); else if (event == STATECHANGE_REMOTE_DIR_MODIFIED) SetDirectoryListing(m_pState->GetRemoteDir(), true); } void CRemoteTreeView::SetDirectoryListing(const CDirectoryListing* pListing, bool modified) { m_busy = true; m_pDirectoryListing = pListing; if (!pListing) { m_ExpandAfterList = wxTreeItemId(); DeleteAllItems(); AddRoot(_T("")); m_busy = false; if (FindFocus() == this) { wxNavigationKeyEvent evt; evt.SetFromTab(true); evt.SetEventObject(this); evt.SetDirection(true); AddPendingEvent(evt); } Enable(false); m_contextMenuItem = wxTreeItemId(); return; } Enable(true); wxTreeItemId parent = MakeParent(pListing->path, !modified); if (!parent) { m_busy = false; return; } if (!IsExpanded(parent) && parent != m_ExpandAfterList) { DeleteChildren(parent); CFilterDialog filter; if (HasSubdirs(*pListing, filter)) AppendItem(parent, _T(""), -1, -1); } else { RefreshItem(parent, *pListing); if (m_ExpandAfterList == parent) Expand(parent); } m_ExpandAfterList = wxTreeItemId(); SetItemImages(parent, false); Refresh(false); m_busy = false; } wxTreeItemId CRemoteTreeView::MakeParent(CServerPath path, bool select) { std::list pieces; while (path.HasParent()) { pieces.push_front(path.GetLastSegment()); path = path.GetParent(); } wxASSERT(path.GetPath() != _T("")); pieces.push_front(path.GetPath()); wxTreeItemId parent = GetRootItem(); for (std::list::const_iterator iter = pieces.begin(); iter != pieces.end(); iter++) { if (iter != pieces.begin()) path.AddSegment(*iter); wxTreeItemIdValue cookie; wxTreeItemId child; for (child = GetFirstChild(parent, cookie); child; child = GetNextSibling(child)) { const wxString& text = GetItemText(child); if (text == *iter) break; if (text == _T("")) { Delete(child); child = wxTreeItemId(); break; } } if (!child) { CDirectoryListing listing; if (m_pState->m_pEngine->CacheLookup(path, listing) == FZ_REPLY_OK) { child = AppendItem(parent, *iter, 0, 2, new CItemData(path)); SetItemImages(child, false); } else { child = AppendItem(parent, *iter, 1, 3, new CItemData(path)); SetItemImages(child, true); } SortChildren(parent); std::list::const_iterator nextIter = iter; nextIter++; if (nextIter != pieces.end()) DisplayItem(child, listing); } if (select && iter != pieces.begin()) Expand(parent); parent = child; } if (select) SelectItem(parent); return parent; } wxBitmap CRemoteTreeView::CreateIcon(int index, const wxString& overlay /*=_T("")*/) { // Create memory DC #ifdef __WXMSW__ wxBitmap bmp(16, 16, 32); #else wxBitmap bmp(16, 16, 24); #endif wxMemoryDC dc; dc.SelectObject(bmp); // Make sure the background is set correctly dc.SetBrush(wxBrush(GetBackgroundColour())); dc.SetPen(wxPen(GetBackgroundColour())); dc.DrawRectangle(0, 0, 16, 16); // Draw item from system image list GetSystemImageList()->Draw(index, dc, 0, 0, wxIMAGELIST_DRAW_TRANSPARENT); // Load overlay if (overlay != _T("")) { wxImage unknownIcon = wxArtProvider::GetBitmap(overlay, wxART_OTHER, wxSize(16,16)).ConvertToImage(); // Convert mask into alpha channel if (!unknownIcon.HasAlpha()) { wxASSERT(unknownIcon.HasMask()); unknownIcon.InitAlpha(); } // Draw overlay dc.DrawBitmap(unknownIcon, 0, 0, true); } dc.SelectObject(wxNullBitmap); return bmp; } void CRemoteTreeView::CreateImageList() { m_pImageList = new wxImageList(16, 16, true, 4); // Normal directory int index = GetIconIndex(dir, _T("{78013B9C-3532-4fe1-A418-5CD1955127CC}"), false); m_pImageList->Add(CreateIcon(index)); m_pImageList->Add(CreateIcon(index, _T("ART_UNKNOWN"))); // Opened directory index = GetIconIndex(opened_dir, _T("{78013B9C-3532-4fe1-A418-5CD1955127CC}"), false); m_pImageList->Add(CreateIcon(index)); m_pImageList->Add(CreateIcon(index, _T("ART_UNKNOWN"))); SetImageList(m_pImageList); } bool CRemoteTreeView::HasSubdirs(const CDirectoryListing& listing, const CFilterDialog& filter) { if (!listing.m_hasDirs) return false; for (unsigned int i = 0; i < listing.GetCount(); i++) { if (!listing[i].dir) continue; if (filter.FilenameFiltered(listing[i].name, true, -1, false)) continue; return true; } return false; } void CRemoteTreeView::DisplayItem(wxTreeItemId parent, const CDirectoryListing& listing) { DeleteChildren(parent); CFilterDialog filter; for (unsigned int i = 0; i < listing.GetCount(); i++) { if (!listing[i].dir) continue; if (filter.FilenameFiltered(listing[i].name, true, -1, false)) continue; const wxString& name = listing[i].name; CServerPath subdir = listing.path; subdir.AddSegment(name); CDirectoryListing subListing; if (m_pState->m_pEngine->CacheLookup(subdir, subListing) == FZ_REPLY_OK) { wxTreeItemId child = AppendItem(parent, name, 0, 2, new CItemData(subdir)); SetItemImages(child, false); if (HasSubdirs(subListing, filter)) AppendItem(child, _T(""), -1, -1); } else { wxTreeItemId child = AppendItem(parent, name, 1, 3, new CItemData(subdir)); SetItemImages(child, true); } } SortChildren(parent); } static bool sortfunc(const wxString& a, const wxString& b) { int cmp = a.CmpNoCase(b); if (!cmp) cmp = a.Cmp(b); return cmp < 0; } void CRemoteTreeView::RefreshItem(wxTreeItemId parent, const CDirectoryListing& listing) { SetItemImages(parent, false); wxTreeItemIdValue cookie; wxTreeItemId child = GetFirstChild(parent, cookie); if (!child || GetItemText(child) == _T("")) { DisplayItem(parent, listing); return; } CFilterDialog filter; std::list dirs; for (unsigned int i = 0; i < listing.GetCount(); i++) { if (!listing[i].dir) continue; if (!filter.FilenameFiltered(listing[i].name, true, -1, false)) dirs.push_back(listing[i].name); } dirs.sort(sortfunc); bool inserted = false; child = GetLastChild(parent); std::list::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) { wxTreeItemId sel = GetSelection(); if (sel) { do { sel = GetItemParent(sel); if (sel == parent) break; } while (sel); } if (!sel) { wxTreeItemId prev = GetPrevSibling(child); Delete(child); child = prev; } } else if (cmp < 0) { 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, new CItemData(path)); SetItemImages(child, false); if (HasSubdirs(subListing, filter)) AppendItem(child, _T(""), -1, -1); } else { wxTreeItemId child = AppendItem(parent, *iter, 1, 3, new CItemData(path)); if (child) SetItemImages(child, true); } iter++; inserted = true; } } while (child) { wxTreeItemId sel = GetSelection(); if (sel) { do { sel = GetItemParent(sel); if (sel == parent) break; } while (sel); } if (!sel) { wxTreeItemId prev = GetPrevSibling(child); 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, new CItemData(path)); SetItemImages(child, false); if (HasSubdirs(subListing, filter)) AppendItem(child, _T(""), -1, -1); } else { wxTreeItemId child = AppendItem(parent, *iter, 1, 3, new CItemData(path)); SetItemImages(child, true); } iter++; inserted = true; } if (inserted) SortChildren(parent); } int CRemoteTreeView::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2) { wxString label1 = GetItemText(item1); wxString label2 = GetItemText(item2); int cmp = label1.CmpNoCase(label2); if (cmp) return cmp; return label1.Cmp(label2); } void CRemoteTreeView::OnItemExpanding(wxTreeEvent& event) { if (m_busy) return; wxTreeItemId item = event.GetItem(); if (!item) return; const CItemData* data = (CItemData*)GetItemData(item); wxASSERT(data); if (!data) return; CDirectoryListing listing; if (m_pState->m_pEngine->CacheLookup(data->m_path, listing) == FZ_REPLY_OK) RefreshItem(item, listing); else { SetItemImages(item, true); wxTreeItemId child = GetLastChild(item); if (!child) { event.Veto(); return; } if (GetItemText(child) == _T("")) { DeleteChildren(item); event.Veto(); } } Refresh(false); } void CRemoteTreeView::SetItemImages(wxTreeItemId item, bool unknown) { if (!unknown) { SetItemImage(item, 0, wxTreeItemIcon_Normal); SetItemImage(item, 2, wxTreeItemIcon_Selected); SetItemImage(item, 0, wxTreeItemIcon_Expanded); SetItemImage(item, 2, wxTreeItemIcon_SelectedExpanded); } else { SetItemImage(item, 1, wxTreeItemIcon_Normal); SetItemImage(item, 3, wxTreeItemIcon_Selected); SetItemImage(item, 1, wxTreeItemIcon_Expanded); SetItemImage(item, 3, wxTreeItemIcon_SelectedExpanded); } } void CRemoteTreeView::OnSelectionChanged(wxTreeEvent& event) { if (event.GetItem() != m_ExpandAfterList) m_ExpandAfterList = wxTreeItemId(); if (m_busy) return; if (!m_pState->IsRemoteIdle()) { wxBell(); return; } wxTreeItemId item = event.GetItem(); if (!item) return; const CItemData* data = (CItemData*)GetItemData(item); wxASSERT(data); if (!data) return; m_pState->m_pCommandQueue->ProcessCommand(new CListCommand(data->m_path)); } void CRemoteTreeView::OnItemActivated(wxTreeEvent& event) { m_ExpandAfterList = GetSelection(); event.Skip(); } CServerPath CRemoteTreeView::GetPathFromItem(const wxTreeItemId& item) const { const CItemData* const pData = (const CItemData*)GetItemData(item); if (!pData) return CServerPath(); return pData->m_path; } void CRemoteTreeView::OnBeginDrag(wxTreeEvent& event) { // Drag could result in recursive operation, don't allow at this point if (!m_pState->IsRemoteIdle()) { wxBell(); return; } const wxTreeItemId& item = event.GetItem(); if (!item) return; const CServerPath& path = GetPathFromItem(item); if (path.IsEmpty() || !path.HasParent()) return; const CServerPath& parent = path.GetParent(); const wxString& lastSegment = path.GetLastSegment(); if (lastSegment == _T("")) return; wxDataObjectComposite object; const CServer* const pServer = m_pState->GetServer(); if (!pServer) return; CRemoteDataObject *pRemoteDataObject = new CRemoteDataObject(*pServer, parent); pRemoteDataObject->AddFile(lastSegment, true, -1); pRemoteDataObject->Finalize(); object.Add(pRemoteDataObject, true); #if FZ3_USESHELLEXT CShellExtensionInterface* ext = CShellExtensionInterface::CreateInitialized(); if (ext) { const wxString& file = ext->GetDragDirectory(); wxASSERT(file != _T("")); wxFileDataObject *pFileDataObject = new wxFileDataObject; pFileDataObject->AddFile(file); object.Add(pFileDataObject); } #endif wxDropSource source(this); source.SetData(object); if (source.DoDragDrop() != wxDragCopy) { #if FZ3_USESHELLEXT delete ext; ext = 0; #endif return; } const wxDataFormat fmt = object.GetReceivedFormat(); #if FZ3_USESHELLEXT if (ext) { if (!pRemoteDataObject->DidSendData()) { const CServer* const pServer = m_pState->GetServer(); if (!pServer || !m_pState->IsRemoteIdle()) { wxBell(); delete ext; ext = 0; return; } wxString target = ext->GetTarget(); if (target == _T("")) { delete ext; ext = 0; wxMessageBox(_("Could not determine the target of the Drag&Drop operation.\nEither the shell extension is not installed properly or you didn't drop the files into an Explorer window.")); return; } m_pState->DownloadDroppedFiles(pRemoteDataObject, target); delete ext; ext = 0; return; } delete ext; ext = 0; } #endif } #ifndef __WXMSW__ void CRemoteTreeView::OnKeyDown(wxKeyEvent& event) { if (event.GetKeyCode() != WXK_TAB) { event.Skip(); return; } wxNavigationKeyEvent navEvent; navEvent.SetEventObject(this); navEvent.SetDirection(!event.ShiftDown()); navEvent.SetFromTab(true); navEvent.ResumePropagation(1); ProcessEvent(navEvent); } #endif void CRemoteTreeView::OnContextMenu(wxTreeEvent& event) { m_contextMenuItem = event.GetItem(); wxMenu* pMenu = wxXmlResource::Get()->LoadMenu(_T("ID_MENU_REMOTETREE")); if (!pMenu) return; const CServerPath& path = GetPathFromItem(m_contextMenuItem); if (!m_pState->IsRemoteIdle() || path.IsEmpty()) { pMenu->Enable(XRCID("ID_DOWNLOAD"), false); pMenu->Enable(XRCID("ID_ADDTOQUEUE"), false); pMenu->Enable(XRCID("ID_MKDIR"), false); pMenu->Enable(XRCID("ID_DELETE"), false); pMenu->Enable(XRCID("ID_CHMOD"), false); pMenu->Enable(XRCID("ID_MKDIR"), false); pMenu->Enable(XRCID("ID_RENAME"), false); } else if (!path.HasParent()) { pMenu->Enable(XRCID("ID_RENAME"), false); } PopupMenu(pMenu); delete pMenu; } void CRemoteTreeView::OnMenuChmod(wxCommandEvent& event) { if (!m_pState->IsRemoteIdle()) return; if (!m_contextMenuItem) return; const CServerPath& path = GetPathFromItem(m_contextMenuItem); if (path.IsEmpty()) return; const bool hasParent = path.HasParent(); CChmodDialog* pChmodDlg = new CChmodDialog; // Get current permissions of directory const wxString& name = GetItemText(m_contextMenuItem); char permissions[9] = {0}; bool cached = false; // Obviously item needs to have a parent directory... if (hasParent) { const CServerPath& parentPath = path.GetParent(); CDirectoryListing listing; // ... and it needs to be cached cached = m_pState->m_pEngine->CacheLookup(parentPath, listing) == FZ_REPLY_OK; if (cached) { for (unsigned int i = 0; i < listing.GetCount(); i++) { if (listing[i].name != name) continue; pChmodDlg->ConvertPermissions(listing[i].permissions, permissions); } } } if (!pChmodDlg->Create(this, 0, 1, name, permissions)) { pChmodDlg->Destroy(); pChmodDlg = 0; return; } if (pChmodDlg->ShowModal() != wxID_OK) { pChmodDlg->Destroy(); pChmodDlg = 0; return; } // State may have changed while chmod dialog was shown if (!m_contextMenuItem || !m_pState->IsRemoteConnected() || !m_pState->IsRemoteIdle()) { pChmodDlg->Destroy(); pChmodDlg = 0; return; } const int applyType = pChmodDlg->GetApplyType(); CRecursiveOperation* pRecursiveOperation = m_pState->GetRecursiveOperationHandler(); if (cached) // Implies hasParent { // Change directory permissions if (!applyType || applyType == 2) { wxString newPerms = pChmodDlg->GetPermissions(permissions); m_pState->m_pCommandQueue->ProcessCommand(new CChmodCommand(path.GetParent(), name, newPerms)); } if (pChmodDlg->Recursive()) // Start recursion pRecursiveOperation->AddDirectoryToVisit(path, _T(""), _T("")); } else { if (hasParent) pRecursiveOperation->AddDirectoryToVisitRestricted(path.GetParent(), name, pChmodDlg->Recursive()); else pRecursiveOperation->AddDirectoryToVisitRestricted(path, _T(""), pChmodDlg->Recursive()); } if (!cached || pChmodDlg->Recursive()) { pRecursiveOperation->SetChmodDialog(pChmodDlg); CServerPath currentPath; const wxTreeItemId selected = GetSelection(); if (selected) currentPath = GetPathFromItem(selected); pRecursiveOperation->StartRecursiveOperation(CRecursiveOperation::recursive_chmod, hasParent ? path.GetParent() : path, !cached, currentPath); } else pChmodDlg->Destroy(); } void CRemoteTreeView::OnMenuDownload(wxCommandEvent& event) { if (!m_pState->IsRemoteIdle()) return; if (!m_contextMenuItem) return; const CServerPath& path = GetPathFromItem(m_contextMenuItem); if (path.IsEmpty()) return; const bool hasParent = path.HasParent(); const wxString localDir = m_pState->GetLocalDir(); const wxString& name = GetItemText(m_contextMenuItem); wxFileName fn = wxFileName(localDir, _T("")); if (hasParent) fn.AppendDir(name); CRecursiveOperation* pRecursiveOperation = m_pState->GetRecursiveOperationHandler(); pRecursiveOperation->AddDirectoryToVisit(path, _T(""), fn.GetFullPath()); CServerPath currentPath; const wxTreeItemId selected = GetSelection(); if (selected) currentPath = GetPathFromItem(selected); const bool addOnly = event.GetId() == XRCID("ID_ADDTOQUEUE"); pRecursiveOperation->StartRecursiveOperation(addOnly ? CRecursiveOperation::recursive_addtoqueue : CRecursiveOperation::recursive_download, path, true, currentPath); } void CRemoteTreeView::OnMenuDelete(wxCommandEvent& event) { if (!m_pState->IsRemoteIdle()) return; if (!m_contextMenuItem) return; const CServerPath& path = GetPathFromItem(m_contextMenuItem); if (path.IsEmpty()) return; const bool hasParent = path.HasParent(); CRecursiveOperation* pRecursiveOperation = m_pState->GetRecursiveOperationHandler(); CServerPath startDir; if (hasParent) { const wxString& name = GetItemText(m_contextMenuItem); startDir = path.GetParent(); pRecursiveOperation->AddDirectoryToVisit(startDir, name); } else { startDir = path; pRecursiveOperation->AddDirectoryToVisit(startDir, _T("")); } CServerPath currentPath; const wxTreeItemId selected = GetSelection(); if (selected) currentPath = GetPathFromItem(selected); if (!currentPath.IsEmpty() && path.IsParentOf(currentPath, false)) currentPath = startDir; pRecursiveOperation->StartRecursiveOperation(CRecursiveOperation::recursive_delete, startDir, !hasParent, currentPath); } void CRemoteTreeView::OnMenuRename(wxCommandEvent& event) { if (!m_pState->IsRemoteIdle()) return; if (!m_contextMenuItem) return; const CServerPath& path = GetPathFromItem(m_contextMenuItem); if (path.IsEmpty()) return; if (!path.HasParent()) return; EditLabel(m_contextMenuItem); } void CRemoteTreeView::OnBeginLabelEdit(wxTreeEvent& event) { if (!m_pState->IsRemoteIdle()) { event.Veto(); return; } const CServerPath& path = GetPathFromItem(event.GetItem()); if (path.IsEmpty()) { event.Veto(); return; } if (!path.HasParent()) { event.Veto(); return; } } void CRemoteTreeView::OnEndLabelEdit(wxTreeEvent& event) { if (event.IsEditCancelled()) { event.Veto(); return; } if (!m_pState->IsRemoteIdle()) { event.Veto(); return; } const CServerPath& path = GetPathFromItem(event.GetItem()); if (path.IsEmpty()) { event.Veto(); return; } if (!path.HasParent()) { event.Veto(); return; } CServerPath parent = path.GetParent(); const wxString& oldName = GetItemText(event.GetItem()); const wxString& newName = event.GetLabel(); if (oldName == newName) { event.Veto(); return; } m_pState->m_pCommandQueue->ProcessCommand(new CRenameCommand(parent, oldName, parent, newName)); m_pState->m_pCommandQueue->ProcessCommand(new CListCommand(parent)); CServerPath currentPath; const wxTreeItemId selected = GetSelection(); if (selected) currentPath = GetPathFromItem(selected); if (currentPath.IsEmpty()) return; if (currentPath == path || currentPath.IsSubdirOf(path, false)) { // Previously selected path was below renamed one, list the new one std::list subdirs; while (currentPath != path) { if (!currentPath.HasParent()) { // Abort just in case return; } subdirs.push_front(currentPath.GetLastSegment()); currentPath = currentPath.GetParent(); } currentPath = parent; currentPath.AddSegment(newName); for (std::list::const_iterator iter = subdirs.begin(); iter != subdirs.end(); iter++) currentPath.AddSegment(*iter); m_pState->m_pCommandQueue->ProcessCommand(new CListCommand(currentPath)); } else if (currentPath != parent) m_pState->m_pCommandQueue->ProcessCommand(new CListCommand(currentPath)); } void CRemoteTreeView::OnMkdir(wxCommandEvent& event) { if (!m_pState->IsRemoteIdle()) return; if (!m_contextMenuItem) return; const CServerPath& path = GetPathFromItem(m_contextMenuItem); if (path.IsEmpty()) return; CInputDialog dlg; if (!dlg.Create(this, _("Create directory"), _("Please enter the name of the directory which should be created:"))) return; CServerPath newPath = path; // Append a long segment which does (most likely) not exist in the path and // replace it with "New folder" later. This way we get the exact position of // "New folder" and can preselect it in the dialog. wxString tmpName = _T("25CF809E56B343b5A12D1F0466E3B37A49A9087FDCF8412AA9AF8D1E849D01CF"); if (newPath.AddSegment(tmpName)) { wxString pathName = newPath.GetPath(); int pos = pathName.Find(tmpName); wxASSERT(pos != -1); wxString newName = _("New folder"); pathName.Replace(tmpName, newName); dlg.SetValue(pathName); dlg.SelectText(pos, pos + newName.Length()); } if (dlg.ShowModal() != wxID_OK) return; newPath = path; if (!newPath.ChangePath(dlg.GetValue())) { wxBell(); return; } m_pState->m_pCommandQueue->ProcessCommand(new CMkdirCommand(newPath)); CServerPath listed; if (newPath.HasParent()) { listed = newPath.GetParent(); m_pState->m_pCommandQueue->ProcessCommand(new CListCommand(listed)); } CServerPath currentPath; const wxTreeItemId selected = GetSelection(); if (selected) currentPath = GetPathFromItem(selected); if (!currentPath.IsEmpty() && currentPath != listed) m_pState->m_pCommandQueue->ProcessCommand(new CListCommand(currentPath)); }