diff --git a/lib/vfs/amigaffs.cc b/lib/vfs/amigaffs.cc index d44b8a84..fb59caa1 100644 --- a/lib/vfs/amigaffs.cc +++ b/lib/vfs/amigaffs.cc @@ -60,7 +60,7 @@ public: uint32_t capabilities() const { return OP_GETFSDATA | OP_CREATE | OP_LIST | OP_GETFILE | OP_PUTFILE | - OP_GETDIRENT | OP_DELETE; + OP_GETDIRENT | OP_DELETE | OP_MOVE; } std::map getMetadata() override @@ -208,6 +208,29 @@ public: throw CannotWriteException(); } + void moveFile(const Path& oldPath, const Path& newPath) override + { + AdfMount m(this); + if ((oldPath.size() == 0) || (newPath.size() == 0)) + throw BadPathException(); + + auto* vol = m.mount(); + + changeDirButOne(vol, oldPath); + auto oldDir = vol->curDirPtr; + + changeDirButOne(vol, newPath); + auto newDir = vol->curDirPtr; + + int res = adfRenameEntry(vol, + oldDir, + (char*)oldPath.back().c_str(), + newDir, + (char*)newPath.back().c_str()); + if (res != RC_OK) + throw CannotWriteException(); + } + private: std::shared_ptr toDirent(struct Entry* entry, const Path& container) { diff --git a/lib/vfs/fatfs.cc b/lib/vfs/fatfs.cc index 45b79a68..f040c011 100644 --- a/lib/vfs/fatfs.cc +++ b/lib/vfs/fatfs.cc @@ -39,7 +39,7 @@ public: uint32_t capabilities() const { return OP_GETFSDATA | OP_CREATE | OP_LIST | OP_GETFILE | OP_PUTFILE | - OP_GETDIRENT; + OP_GETDIRENT | OP_MOVE; } std::map getMetadata() override @@ -188,6 +188,15 @@ public: throwError(res); } + void moveFile(const Path& oldPath, const Path& newPath) override + { + mount(); + auto oldPathStr = oldPath.to_str(); + auto newPathStr = newPath.to_str(); + FRESULT res = f_rename(oldPathStr.c_str(), newPathStr.c_str()); + throwError(res); + } + private: std::shared_ptr toDirent(FILINFO& filinfo, const Path& parent) { diff --git a/lib/vfs/machfs.cc b/lib/vfs/machfs.cc index 82e4067d..a0db2023 100644 --- a/lib/vfs/machfs.cc +++ b/lib/vfs/machfs.cc @@ -27,7 +27,7 @@ public: uint32_t capabilities() const { return OP_GETFSDATA | OP_CREATE | OP_LIST | OP_GETFILE | OP_PUTFILE | - OP_GETDIRENT; + OP_GETDIRENT | OP_MOVE; } std::map getMetadata() override @@ -169,6 +169,18 @@ public: throw CannotWriteException(); } + void moveFile(const Path& oldPath, const Path& newPath) override + { + HfsMount m(this); + if (oldPath.empty() || newPath.empty()) + throw BadPathException(); + + auto oldPathStr = ":" + oldPath.to_str(":"); + auto newPathStr = ":" + newPath.to_str(":"); + if (!hfs_rename(_vol, oldPathStr.c_str(), newPathStr.c_str())) + throw CannotWriteException(); + } + private: std::shared_ptr toDirent(hfsdirent& de, const Path& parent) { diff --git a/src/gui/filesystemmodel.cc b/src/gui/filesystemmodel.cc index 2aed930f..6c464271 100644 --- a/src/gui/filesystemmodel.cc +++ b/src/gui/filesystemmodel.cc @@ -129,7 +129,19 @@ public: const wxDataViewItem& item, unsigned column) override { - fmt::print("{}\n", __LINE__); + auto node = Find(item); + if (!node || node->stub) + return false; + + if ((column == 0) && (value.GetType() == "wxDataViewIconText")) + { + wxDataViewIconText dvit; + dvit << value; + node->newname = dvit.GetText(); + return true; + } + + return false; } unsigned GetChildren(const wxDataViewItem& item, diff --git a/src/gui/filesystemmodel.h b/src/gui/filesystemmodel.h index 476dea0d..4bda99d0 100644 --- a/src/gui/filesystemmodel.h +++ b/src/gui/filesystemmodel.h @@ -16,6 +16,8 @@ public: bool stub = false; std::shared_ptr dirent; std::map> children; + + std::string newname; /* used for inline renames */ }; class FilesystemModel : public wxDataViewModel diff --git a/src/gui/layout.cpp b/src/gui/layout.cpp index fafa8791..556af269 100644 --- a/src/gui/layout.cpp +++ b/src/gui/layout.cpp @@ -325,7 +325,7 @@ MainWindowGen::MainWindowGen( wxWindow* parent, wxWindowID id, const wxString& t fgSizer23->Add( browserToolbar, 0, wxEXPAND, 5 ); browserTree = new wxDataViewCtrl( browsePanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_SINGLE ); - m_dataViewColumn1 = browserTree->AppendIconTextColumn( wxT("Filename"), 0, wxDATAVIEW_CELL_INERT, 250, static_cast(wxALIGN_LEFT), wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE ); + m_dataViewColumn1 = browserTree->AppendIconTextColumn( wxT("Filename"), 0, wxDATAVIEW_CELL_EDITABLE, 250, static_cast(wxALIGN_LEFT), wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE ); m_dataViewColumn2 = browserTree->AppendTextColumn( wxT("Size"), 1, wxDATAVIEW_CELL_INERT, 100, static_cast(wxALIGN_RIGHT), wxDATAVIEW_COL_RESIZABLE ); m_dataViewColumn3 = browserTree->AppendTextColumn( wxT("Mode"), 2, wxDATAVIEW_CELL_INERT, -1, static_cast(wxALIGN_LEFT), wxDATAVIEW_COL_RESIZABLE ); fgSizer23->Add( browserTree, 0, wxALL|wxEXPAND, 5 ); @@ -400,6 +400,7 @@ MainWindowGen::MainWindowGen( wxWindow* parent, wxWindowID id, const wxString& t browserMoreMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainWindowGen::OnBrowserRenameMenuItem ), this, browserRenameMenuItem->GetId()); browserMoreMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainWindowGen::OnBrowserDeleteMenuItem ), this, browserDeleteMenuItem->GetId()); this->Connect( browserFormatTool->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( MainWindowGen::OnBrowserFormatButton ) ); + browserTree->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE, wxDataViewEventHandler( MainWindowGen::OnBrowserFilenameChanged ), NULL, this ); browserTree->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING, wxDataViewEventHandler( MainWindowGen::OnBrowserDirectoryExpanding ), NULL, this ); browserTree->Connect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( MainWindowGen::OnBrowserSelectionChanged ), NULL, this ); browserDiscardButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnBrowserDiscardButton ), NULL, this ); @@ -432,6 +433,7 @@ MainWindowGen::~MainWindowGen() this->Disconnect( browserViewTool->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( MainWindowGen::OnBrowserViewButton ) ); this->Disconnect( browserSaveTool->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( MainWindowGen::OnBrowserSaveButton ) ); this->Disconnect( browserFormatTool->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( MainWindowGen::OnBrowserFormatButton ) ); + browserTree->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE, wxDataViewEventHandler( MainWindowGen::OnBrowserFilenameChanged ), NULL, this ); browserTree->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING, wxDataViewEventHandler( MainWindowGen::OnBrowserDirectoryExpanding ), NULL, this ); browserTree->Disconnect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( MainWindowGen::OnBrowserSelectionChanged ), NULL, this ); browserDiscardButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnBrowserDiscardButton ), NULL, this ); diff --git a/src/gui/layout.fbp b/src/gui/layout.fbp index 97f7f4c9..3206b23b 100644 --- a/src/gui/layout.fbp +++ b/src/gui/layout.fbp @@ -2505,6 +2505,7 @@ + OnBrowserFilenameChanged OnBrowserDirectoryExpanding OnBrowserSelectionChanged @@ -2512,7 +2513,7 @@ wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE Filename - wxDATAVIEW_CELL_INERT + wxDATAVIEW_CELL_EDITABLE 0 m_dataViewColumn1 protected diff --git a/src/gui/layout.h b/src/gui/layout.h index 24a29051..f63af025 100644 --- a/src/gui/layout.h +++ b/src/gui/layout.h @@ -132,6 +132,7 @@ class MainWindowGen : public wxFrame virtual void OnBrowserRenameMenuItem( wxCommandEvent& event ) { event.Skip(); } virtual void OnBrowserDeleteMenuItem( wxCommandEvent& event ) { event.Skip(); } virtual void OnBrowserFormatButton( wxCommandEvent& event ) { event.Skip(); } + virtual void OnBrowserFilenameChanged( wxDataViewEvent& event ) { event.Skip(); } virtual void OnBrowserDirectoryExpanding( wxDataViewEvent& event ) { event.Skip(); } virtual void OnBrowserSelectionChanged( wxDataViewEvent& event ) { event.Skip(); } virtual void OnBrowserDiscardButton( wxCommandEvent& event ) { event.Skip(); } diff --git a/src/gui/mainwindow.cc b/src/gui/mainwindow.cc index ecf6eb6c..e8b446d3 100644 --- a/src/gui/mainwindow.cc +++ b/src/gui/mainwindow.cc @@ -578,6 +578,35 @@ public: }); } + /* Called from worker thread only! */ + Path ResolveFileConflicts_WT(Path path) + { + do + { + try + { + _filesystem->getDirent(path); + } + catch (const FileNotFoundException& e) + { + break; + } + + runOnUiThread( + [&]() + { + FileConflictDialog d(this, wxID_ANY); + d.oldNameText->SetValue(path.to_str()); + d.newNameText->SetValue(path.to_str()); + if (d.ShowModal() == wxID_OK) + path = Path(d.newNameText->GetValue().ToStdString()); + else + path = Path(""); + }); + } while (!path.empty()); + return path; + } + void OnBrowserAddMenuItem(wxCommandEvent&) override { Path dirPath; @@ -616,37 +645,7 @@ public: QueueBrowserOperation( [this, path, localPath, item]() mutable { - /* Check that the file exists. */ - - for (;;) - { - try - { - _filesystem->getDirent(path); - } - catch (const FileNotFoundException& e) - { - break; - } - - runOnUiThread( - [&]() - { - FileConflictDialog d(this, wxID_ANY); - d.oldNameText->SetValue(path.to_str()); - d.newNameText->SetValue(path.to_str()); - if (d.ShowModal() == wxID_OK) - path = Path( - d.newNameText->GetValue().ToStdString()); - else - path = Path(""); - }); - - if (path.empty()) - return; - } - - /* Now actually write the data. */ + path = ResolveFileConflicts_WT(path); auto bytes = Bytes::readFromFile(localPath); _filesystem->putFile(path, bytes); @@ -701,6 +700,38 @@ public: }); } + void OnBrowserFilenameChanged(wxDataViewEvent& event) + { + if (!(_filesystem->capabilities() & Filesystem::OP_MOVE)) + return; + + auto node = _filesystemModel->Find(event.GetItem()); + if (!node) + return; + + if (node->newname.empty()) + return; + + QueueBrowserOperation( + [this, node]() mutable + { + auto oldpath = node->dirent->path; + auto newpath = oldpath.parent(); + newpath.push_back(node->newname); + + newpath = ResolveFileConflicts_WT(newpath); + _filesystem->moveFile(oldpath, newpath); + + auto dirent = _filesystem->getDirent(newpath); + runOnUiThread( + [&]() + { + _filesystemModel->Delete(oldpath); + _filesystemModel->Add(dirent); + }); + }); + } + void OnBrowserCommitButton(wxCommandEvent&) override { QueueBrowserOperation(