diff --git a/Makefile b/Makefile index a9775335..885b8185 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ AR ?= $(CCPREFIX)ar PKG_CONFIG ?= pkg-config WX_CONFIG ?= wx-config PROTOC ?= protoc -CFLAGS ?= -g -O3 +CFLAGS ?= -g -O0 CXXFLAGS += -std=c++17 LDFLAGS ?= PLATFORM ?= UNIX diff --git a/lib/vfs/acorndfs.cc b/lib/vfs/acorndfs.cc index ca90b798..3c72cd07 100644 --- a/lib/vfs/acorndfs.cc +++ b/lib/vfs/acorndfs.cc @@ -18,6 +18,7 @@ public: filename = filename.substr(0, filename.find(' ')); this->inode = inode; + path = { filename }; start_sector = ((bytes1[6] & 0x03) << 8) | bytes1[7]; load_address = ((bytes1[6] & 0x0c) << 14) | (bytes1[1] << 8) | bytes1[0]; diff --git a/lib/vfs/amigaffs.cc b/lib/vfs/amigaffs.cc index 534d97fd..91010027 100644 --- a/lib/vfs/amigaffs.cc +++ b/lib/vfs/amigaffs.cc @@ -114,6 +114,8 @@ public: cell = cell->next; auto dirent = std::make_shared(); + dirent->path = path; + dirent->path.push_back(entry->name); dirent->filename = entry->name; dirent->length = entry->size; dirent->file_type = diff --git a/lib/vfs/brother120fs.cc b/lib/vfs/brother120fs.cc index 1471f635..c06fbf7a 100644 --- a/lib/vfs/brother120fs.cc +++ b/lib/vfs/brother120fs.cc @@ -32,6 +32,7 @@ public: ByteReader br(bytes); filename = br.read(8); filename = filename.substr(0, filename.find(' ')); + path = { filename }; this->inode = inode; brother_type = br.read_8(); diff --git a/lib/vfs/cbmfs.cc b/lib/vfs/cbmfs.cc index 00ef7e6a..59434354 100644 --- a/lib/vfs/cbmfs.cc +++ b/lib/vfs/cbmfs.cc @@ -74,6 +74,7 @@ class CbmfsFilesystem : public Filesystem auto filenameBytes = br.read(16).split(0xa0)[0]; filename = fromPetscii(filenameBytes); + path = { filename }; side_track = br.read_8(); side_sector = br.read_8(); recordlen = br.read_8(); diff --git a/lib/vfs/cpmfs.cc b/lib/vfs/cpmfs.cc index 7bffc12d..a95d687f 100644 --- a/lib/vfs/cpmfs.cc +++ b/lib/vfs/cpmfs.cc @@ -130,6 +130,7 @@ public: if (!dirent) { dirent = std::make_unique(); + dirent->path = { entry->filename }; dirent->filename = entry->filename; dirent->mode = entry->mode; dirent->length = 0; diff --git a/lib/vfs/fatfs.cc b/lib/vfs/fatfs.cc index bfbb4c86..414fd69d 100644 --- a/lib/vfs/fatfs.cc +++ b/lib/vfs/fatfs.cc @@ -102,6 +102,8 @@ public: break; auto dirent = std::make_shared(); + dirent->path = path; + dirent->path.push_back(filinfo.fname); dirent->filename = filinfo.fname; dirent->length = filinfo.fsize; dirent->file_type = diff --git a/lib/vfs/machfs.cc b/lib/vfs/machfs.cc index 531d98fa..4c9b60d8 100644 --- a/lib/vfs/machfs.cc +++ b/lib/vfs/machfs.cc @@ -75,6 +75,8 @@ public: auto dirent = std::make_shared(); dirent->filename = de.name; + dirent->path = path; + dirent->path.push_back(de.name); if (de.flags & HFS_ISDIR) { diff --git a/lib/vfs/vfs.cc b/lib/vfs/vfs.cc index ba7d47ea..e03df346 100644 --- a/lib/vfs/vfs.cc +++ b/lib/vfs/vfs.cc @@ -6,9 +6,19 @@ #include "lib/image.h" #include "lib/sector.h" #include "lib/vfs/sectorinterface.h" +#include "lib/imagereader/imagereader.h" +#include "lib/fluxsource/fluxsource.h" +#include "lib/fluxsink/fluxsink.h" +#include "lib/decoders/decoders.h" +#include "lib/encoders/encoders.h" #include "lib/config.pb.h" #include "lib/utils.h" +Path::Path(const std::vector other): + std::vector(other) +{ +} + Path::Path(const std::string& path) { if (path == "") @@ -153,6 +163,38 @@ std::unique_ptr Filesystem::createFilesystem( } } +std::unique_ptr Filesystem::createFilesystemFromConfig() +{ + std::shared_ptr sectorInterface; + if (config.has_flux_source()) + { + std::shared_ptr fluxSource( + FluxSource::create(config.flux_source())); + std::shared_ptr decoder( + AbstractDecoder::create(config.decoder())); + if (config.flux_sink().has_drive()) + { + std::shared_ptr fluxSink( + FluxSink::create(config.flux_sink())); + std::shared_ptr encoder( + AbstractEncoder::create(config.encoder())); + sectorInterface = SectorInterface::createFluxSectorInterface( + fluxSource, fluxSink, encoder, decoder); + } + else + sectorInterface = SectorInterface::createFluxSectorInterface( + fluxSource, nullptr, nullptr, decoder); + } + else + { + auto reader = ImageReader::create(config.image_reader()); + std::shared_ptr image(std::move(reader->readImage())); + sectorInterface = SectorInterface::createImageSectorInterface(image); + } + + return createFilesystem(config.filesystem(), sectorInterface); +} + Bytes Filesystem::getSector(unsigned track, unsigned side, unsigned sector) { auto s = _sectors->get(track, side, sector); diff --git a/lib/vfs/vfs.h b/lib/vfs/vfs.h index d8dcd8e8..d154e593 100644 --- a/lib/vfs/vfs.h +++ b/lib/vfs/vfs.h @@ -10,6 +10,17 @@ class DfsProto; class FilesystemProto; class SectorInterface; +class Path : public std::vector +{ +public: + Path() {} + Path(const std::vector other); + Path(const std::string& text); + +public: + std::string to_str(const std::string sep = "/") const; +}; + enum FileType { TYPE_FILE, @@ -18,6 +29,7 @@ enum FileType struct Dirent { + Path path; std::string filename; FileType file_type; uint32_t length; @@ -88,16 +100,6 @@ public: } }; -class Path : public std::vector -{ -public: - Path() {} - Path(const std::string& text); - -public: - std::string to_str(const std::string sep = "/") const; -}; - class Filesystem { public: @@ -188,6 +190,7 @@ public: static std::unique_ptr createFilesystem( const FilesystemProto& config, std::shared_ptr image); + static std::unique_ptr createFilesystemFromConfig(); }; #endif diff --git a/src/fe-format.cc b/src/fe-format.cc index 7b7a6550..02c774c5 100644 --- a/src/fe-format.cc +++ b/src/fe-format.cc @@ -30,7 +30,7 @@ int mainFormat(int argc, const char* argv[]) try { - auto filesystem = createFilesystemFromConfig(); + auto filesystem = Filesystem::createFilesystemFromConfig(); filesystem->create(quick, volumeName); filesystem->flush(); } diff --git a/src/fe-getdiskinfo.cc b/src/fe-getdiskinfo.cc index 4ed95da3..48cde0ef 100644 --- a/src/fe-getdiskinfo.cc +++ b/src/fe-getdiskinfo.cc @@ -27,7 +27,7 @@ int mainGetDiskInfo(int argc, const char* argv[]) try { - auto filesystem = createFilesystemFromConfig(); + auto filesystem = Filesystem::createFilesystemFromConfig(); auto attributes = filesystem->getMetadata(); for (const auto& e : attributes) diff --git a/src/fe-getfile.cc b/src/fe-getfile.cc index d2e9012c..bfdc4dd1 100644 --- a/src/fe-getfile.cc +++ b/src/fe-getfile.cc @@ -37,7 +37,7 @@ int mainGetFile(int argc, const char* argv[]) if (outputFilename.empty()) outputFilename = inputFilename.back(); - auto filesystem = createFilesystemFromConfig(); + auto filesystem = Filesystem::createFilesystemFromConfig(); auto data = filesystem->getFile(inputFilename); data.writeToFile(outputFilename); } diff --git a/src/fe-getfileinfo.cc b/src/fe-getfileinfo.cc index 535520db..058a5d61 100644 --- a/src/fe-getfileinfo.cc +++ b/src/fe-getfileinfo.cc @@ -29,7 +29,7 @@ int mainGetFileInfo(int argc, const char* argv[]) try { - auto filesystem = createFilesystemFromConfig(); + auto filesystem = Filesystem::createFilesystemFromConfig(); auto attributes = filesystem->getMetadata(Path(directory)); for (const auto& e : attributes) diff --git a/src/fe-ls.cc b/src/fe-ls.cc index 052ca8c0..b8b3b89a 100644 --- a/src/fe-ls.cc +++ b/src/fe-ls.cc @@ -43,7 +43,7 @@ int mainLs(int argc, const char* argv[]) try { - auto filesystem = createFilesystemFromConfig(); + auto filesystem = Filesystem::createFilesystemFromConfig(); auto files = filesystem->list(Path(directory)); int maxlen = 0; diff --git a/src/fe-putfile.cc b/src/fe-putfile.cc index 49b34ac2..2d29ba17 100644 --- a/src/fe-putfile.cc +++ b/src/fe-putfile.cc @@ -38,7 +38,7 @@ int mainPutFile(int argc, const char* argv[]) Error() << "you must supply a destination path to write to"; auto data = Bytes::readFromFile(inputFilename); - auto filesystem = createFilesystemFromConfig(); + auto filesystem = Filesystem::createFilesystemFromConfig(); filesystem->putFile(outputFilename, data); filesystem->flush(); } diff --git a/src/fileutils.cc b/src/fileutils.cc index 049c6299..7f28545c 100644 --- a/src/fileutils.cc +++ b/src/fileutils.cc @@ -4,8 +4,6 @@ #include "sector.h" #include "proto.h" #include "readerwriter.h" -#include "lib/decoders/decoders.h" -#include "lib/encoders/encoders.h" #include "lib/fluxsource/fluxsource.h" #include "lib/fluxsink/fluxsink.h" #include "lib/imagereader/imagereader.h" @@ -38,24 +36,3 @@ static StringFlag flux({"-f", "--flux"}, config.mutable_flux_sink(), value); }); -std::unique_ptr createFilesystemFromConfig() -{ - std::shared_ptr sectorInterface; - if (config.has_flux_source()) - { - std::shared_ptr fluxSource(FluxSource::create(config.flux_source())); - std::shared_ptr fluxSink(FluxSink::create(config.flux_sink())); - std::shared_ptr encoder(AbstractEncoder::create(config.encoder())); - std::shared_ptr decoder(AbstractDecoder::create(config.decoder())); - sectorInterface = SectorInterface::createFluxSectorInterface(fluxSource, fluxSink, encoder, decoder); - } - else - { - auto reader = ImageReader::create(config.image_reader()); - std::shared_ptr image(std::move(reader->readImage())); - sectorInterface = SectorInterface::createImageSectorInterface(image); - } - - return Filesystem::createFilesystem(config.filesystem(), sectorInterface); -} - diff --git a/src/fileutils.h b/src/fileutils.h index 609c3291..39471195 100644 --- a/src/fileutils.h +++ b/src/fileutils.h @@ -3,7 +3,5 @@ extern FlagGroup fileFlags; -extern std::unique_ptr createFilesystemFromConfig(); - #endif diff --git a/src/gui/build.mk b/src/gui/build.mk index 42e62acc..3d3ad5de 100644 --- a/src/gui/build.mk +++ b/src/gui/build.mk @@ -2,6 +2,7 @@ ifneq ($(shell $(WX_CONFIG) --version),) FLUXENGINE_GUI_SRCS = \ src/gui/customstatusbar.cc \ + src/gui/filesystemmodel.cc \ src/gui/fluxviewercontrol.cc \ src/gui/fluxviewerwindow.cc \ src/gui/layout.cpp \ @@ -28,6 +29,9 @@ $(call use-library, $(FLUXENGINE_GUI_BIN), $(FLUXENGINE_GUI_OBJS), LIBFLUXENGINE $(call use-library, $(FLUXENGINE_GUI_BIN), $(FLUXENGINE_GUI_OBJS), LIBFORMATS) $(call use-library, $(FLUXENGINE_GUI_BIN), $(FLUXENGINE_GUI_OBJS), LIBUSBP) $(call use-library, $(FLUXENGINE_GUI_BIN), $(FLUXENGINE_GUI_OBJS), PROTO) +$(call use-library, $(FLUXENGINE_GUI_BIN), $(FLUXENGINE_GUI_OBJS), FATFS) +$(call use-library, $(FLUXENGINE_GUI_BIN), $(FLUXENGINE_GUI_OBJS), ADFLIB) +$(call use-library, $(FLUXENGINE_GUI_BIN), $(FLUXENGINE_GUI_OBJS), HFSUTILS) binaries: fluxengine-gui$(EXT) diff --git a/src/gui/filesystemmodel.cc b/src/gui/filesystemmodel.cc new file mode 100644 index 00000000..8a5e08ec --- /dev/null +++ b/src/gui/filesystemmodel.cc @@ -0,0 +1,150 @@ +#include "lib/globals.h" +#include "gui.h" +#include "filesystemmodel.h" +#include "lib/vfs/vfs.h" +#include +#include + +class FilesystemModelImpl : public FilesystemModel +{ +public: + FilesystemModelImpl(): + _fileIcon(wxArtProvider::GetIcon(wxART_NORMAL_FILE, wxART_BUTTON)), + _folderOpenIcon( + wxArtProvider::GetIcon(wxART_FOLDER_OPEN, wxART_BUTTON)), + _folderClosedIcon(wxArtProvider::GetIcon(wxART_FOLDER, wxART_BUTTON)) + { + } + +public: + unsigned int GetColumnCount() const override + { + return 3; + } + + wxString GetColumnType(unsigned int column) const override + { + switch (column) + { + case 1: + case 2: + return "string"; + + default: + return FilesystemModel::GetColumnType(column); + } + } + + void GetValue(wxVariant& value, + const wxDataViewItem& item, + unsigned int column) const override + { + auto* data = (DirentContainer*)GetItemData(item); + switch (column) + { + case 1: + value = (data && data->dirent) + ? std::to_string(data->dirent->length) + : ""; + break; + + case 2: + value = (data && data->dirent) ? data->dirent->mode : ""; + break; + + default: + FilesystemModel::GetValue(value, item, column); + } + } + + #if 0 + int Compare(const wxDataViewItem& item1, + const wxDataViewItem& item2, + unsigned int column, + bool ascending) const override + { + auto* data1 = (DirentContainer*)GetItemData(item1); + auto* data2 = (DirentContainer*)GetItemData(item2); + if (data1 && data1->dirent && data2 && data2->dirent) + { + int r; + + switch (column) + { + case 0: + r = data1->dirent->filename.compare( + data2->dirent->filename); + break; + + case 1: + r = data2->dirent->length - data1->dirent->length; + break; + + case 2: + r = data1->dirent->mode.compare(data2->dirent->mode); + break; + } + + if (ascending) + r = -r; + return r; + } + + return 0; + } + #endif + +public: + wxDataViewItem GetRootItem() const + { + return wxDataViewItem(); + } + + void SetFiles(const wxDataViewItem& parent, + std::vector>& files) + { + for (int i = 0; i < GetChildCount(parent); i++) + ItemDeleted(parent, GetNthChild(parent, i)); + DeleteChildren(parent); + + for (auto& dirent : files) + { + if (dirent->file_type == TYPE_FILE) + { + auto item = AppendItem(parent, + dirent->filename, + _fileIcon, + new DirentContainer(dirent)); + ItemAdded(parent, item); + } + else + { + auto item = AppendContainer(parent, + dirent->filename, + _folderOpenIcon, + _folderClosedIcon, + new DirentContainer(dirent)); + + auto child = AppendItem(item, "...loading..."); + ItemAdded(parent, item); + ItemAdded(item, child); + } + } + + ItemChanged(parent); + } + +private: + wxIcon _fileIcon; + wxIcon _folderOpenIcon; + wxIcon _folderClosedIcon; +}; + +FilesystemModel* FilesystemModel::Associate(wxDataViewCtrl* control) +{ + auto model = new FilesystemModelImpl(); + control->AssociateModel(model); + return model; +} + +// vim: sw=4 ts=4 et diff --git a/src/gui/filesystemmodel.h b/src/gui/filesystemmodel.h new file mode 100644 index 00000000..39548576 --- /dev/null +++ b/src/gui/filesystemmodel.h @@ -0,0 +1,28 @@ +#ifndef FILESYSTEMMODEL_H +#define FILESYSTEMMODEL_H + +#include +class Dirent; + +class DirentContainer : public wxClientData +{ +public: + DirentContainer(std::shared_ptr dirent): dirent(dirent) {} + + bool populated = false; + bool populating = false; + std::shared_ptr dirent; +}; + +class FilesystemModel : public wxDataViewTreeStore +{ +public: + virtual wxDataViewItem GetRootItem() const = 0; + virtual void SetFiles(const wxDataViewItem& item, + std::vector>& files) = 0; + +public: + static FilesystemModel* Associate(wxDataViewCtrl* control); +}; + +#endif diff --git a/src/gui/layout.cpp b/src/gui/layout.cpp index 0fce4f0f..993c37e6 100644 --- a/src/gui/layout.cpp +++ b/src/gui/layout.cpp @@ -186,7 +186,6 @@ MainWindowGen::MainWindowGen( wxWindow* parent, wxWindowID id, const wxString& t browseButton = new wxButton( idlePanel, wxID_ANY, wxT("Browse disk"), wxDefaultPosition, wxDefaultSize, 0 ); browseButton->SetBitmap( wxArtProvider::GetBitmap( wxART_FOLDER_OPEN, wxART_TOOLBAR ) ); - browseButton->Enable( false ); browseButton->SetToolTip( wxT("Access the files on the disk directly without needing to image it.") ); gSizer9->Add( browseButton, 0, wxALL|wxEXPAND, 5 ); @@ -275,27 +274,27 @@ MainWindowGen::MainWindowGen( wxWindow* parent, wxWindowID id, const wxString& t browserToolbar = new wxToolBar( browsePanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTB_FLAT|wxTB_HORIZONTAL|wxTB_TEXT ); browserBackTool = browserToolbar->AddTool( wxID_ANY, wxT("Back"), wxArtProvider::GetBitmap( wxART_GO_BACK, wxART_TOOLBAR ), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString, NULL ); + browserToolbar->AddSeparator(); + + m_tool3 = browserToolbar->AddTool( wxID_ANY, wxT("Info"), wxArtProvider::GetBitmap( wxART_INFORMATION, wxART_TOOLBAR ), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString, NULL ); + + m_tool4 = browserToolbar->AddTool( wxID_ANY, wxT("Open"), wxArtProvider::GetBitmap( wxART_FILE_OPEN, wxART_TOOLBAR ), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString, NULL ); + + m_tool5 = browserToolbar->AddTool( wxID_ANY, wxT("Save"), wxArtProvider::GetBitmap( wxART_FILE_SAVE_AS, wxART_TOOLBAR ), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString, NULL ); + + m_tool6 = browserToolbar->AddTool( wxID_ANY, wxT("New"), wxArtProvider::GetBitmap( wxART_NEW, wxART_TOOLBAR ), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString, NULL ); + + m_tool7 = browserToolbar->AddTool( wxID_ANY, wxT("Delete"), wxArtProvider::GetBitmap( wxART_DELETE, wxART_TOOLBAR ), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString, NULL ); + browserToolbar->Realize(); fgSizer23->Add( browserToolbar, 0, wxEXPAND, 5 ); - m_scrolledWindow1 = new wxScrolledWindow( browsePanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxVSCROLL ); - m_scrolledWindow1->SetScrollRate( 5, 5 ); - wxGridSizer* gSizer13; - gSizer13 = new wxGridSizer( 1, 1, 0, 0 ); - - browserView = new wxDataViewCtrl( m_scrolledWindow1, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); - browserFilenameColumn = browserView->AppendTextColumn( wxT("Filename"), 0, wxDATAVIEW_CELL_INERT, -1, static_cast(wxALIGN_LEFT), wxDATAVIEW_COL_RESIZABLE ); - browserModeColumn = browserView->AppendTextColumn( wxT("Mode"), 1, wxDATAVIEW_CELL_INERT, -1, static_cast(wxALIGN_LEFT), wxDATAVIEW_COL_RESIZABLE ); - browserLengthColumn = browserView->AppendTextColumn( wxT("Length"), 2, wxDATAVIEW_CELL_INERT, -1, static_cast(wxALIGN_LEFT), wxDATAVIEW_COL_RESIZABLE ); - browserExtraColumn = browserView->AppendTextColumn( wxT("Additional properties"), 0, wxDATAVIEW_CELL_INERT, -1, static_cast(wxALIGN_LEFT), wxDATAVIEW_COL_RESIZABLE ); - gSizer13->Add( browserView, 0, wxEXPAND, 5 ); - - - m_scrolledWindow1->SetSizer( gSizer13 ); - m_scrolledWindow1->Layout(); - gSizer13->Fit( m_scrolledWindow1 ); - fgSizer23->Add( m_scrolledWindow1, 1, wxEXPAND | wxALL, 5 ); + browserTree = new wxDataViewCtrl( browsePanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_MULTIPLE ); + m_dataViewColumn1 = browserTree->AppendIconTextColumn( wxT("Filename"), 0, wxDATAVIEW_CELL_INERT, 250, static_cast(wxALIGN_LEFT), wxDATAVIEW_COL_RESIZABLE ); + m_dataViewColumn2 = browserTree->AppendTextColumn( wxT("Size"), 1, wxDATAVIEW_CELL_INERT, -1, 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 ); wxGridSizer* gSizer12; gSizer12 = new wxGridSizer( 0, 2, 0, 0 ); @@ -345,11 +344,13 @@ MainWindowGen::MainWindowGen( wxWindow* parent, wxWindowID id, const wxString& t customConfigurationButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnCustomConfigurationButton ), NULL, this ); readButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnReadButton ), NULL, this ); writeButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnWriteButton ), NULL, this ); + browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnBrowseButton ), NULL, this ); this->Connect( imagerBackTool->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( MainWindowGen::OnBackButton ) ); imagerSaveImageButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnSaveImageButton ), NULL, this ); imagerSaveFluxButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnSaveFluxButton ), NULL, this ); imagerGoAgainButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnImagerGoAgainButton ), NULL, this ); this->Connect( browserBackTool->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( MainWindowGen::OnBackButton ) ); + browserTree->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING, wxDataViewEventHandler( MainWindowGen::OnBrowserDirectoryExpanding ), NULL, this ); } MainWindowGen::~MainWindowGen() @@ -368,11 +369,13 @@ MainWindowGen::~MainWindowGen() customConfigurationButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnCustomConfigurationButton ), NULL, this ); readButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnReadButton ), NULL, this ); writeButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnWriteButton ), NULL, this ); + browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnBrowseButton ), NULL, this ); this->Disconnect( imagerBackTool->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( MainWindowGen::OnBackButton ) ); imagerSaveImageButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnSaveImageButton ), NULL, this ); imagerSaveFluxButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnSaveFluxButton ), NULL, this ); imagerGoAgainButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnImagerGoAgainButton ), NULL, this ); this->Disconnect( browserBackTool->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( MainWindowGen::OnBackButton ) ); + browserTree->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING, wxDataViewEventHandler( MainWindowGen::OnBrowserDirectoryExpanding ), NULL, this ); } diff --git a/src/gui/layout.fbp b/src/gui/layout.fbp index 78ab9636..7f0b18eb 100644 --- a/src/gui/layout.fbp +++ b/src/gui/layout.fbp @@ -47,7 +47,7 @@ MainWindowGen - 819,607 + 570,607 wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER ; ; forward_declare FluxEngine @@ -1586,7 +1586,7 @@ Dock 0 Left - 0 + 1 1 @@ -1627,6 +1627,7 @@ + OnBrowseButton @@ -2311,148 +2312,127 @@ OnBackButton + + protected + + + Load From Art Provider; wxART_INFORMATION; wxART_TOOLBAR + 0 + wxID_ANY + wxITEM_NORMAL + Info + m_tool3 + protected + + + + + Load From Art Provider; wxART_FILE_OPEN; wxART_TOOLBAR + 0 + wxID_ANY + wxITEM_NORMAL + Open + m_tool4 + protected + + + + + Load From Art Provider; wxART_FILE_SAVE_AS; wxART_TOOLBAR + 0 + wxID_ANY + wxITEM_NORMAL + Save + m_tool5 + protected + + + + + Load From Art Provider; wxART_NEW; wxART_TOOLBAR + 0 + wxID_ANY + wxITEM_NORMAL + New + m_tool6 + protected + + + + + Load From Art Provider; wxART_DELETE; wxART_TOOLBAR + 0 + wxID_ANY + wxITEM_NORMAL + Delete + m_tool7 + protected + + + - + 5 - wxEXPAND | wxALL - 1 - - 1 - 1 - 1 - 1 - - - - - + wxALL|wxEXPAND + 0 + - - 1 - 0 - 1 1 - 0 - Dock - 0 - Left 1 - 1 - 0 0 wxID_ANY - - 0 - - 0 - 1 - m_scrolledWindow1 - 1 - - + browserTree protected - 1 - Resizable - 5 - 5 - 1 + wxDV_MULTIPLE ; ; forward_declare - 0 - wxHSCROLL|wxVSCROLL - - 1 - 0 - - gSizer13 - none - 1 - 0 - - 5 - wxEXPAND - 0 - - - - 1 - 1 - - - 0 - wxID_ANY - - - browserView - protected - - - - ; ; forward_declare - - - - - - wxALIGN_LEFT - - wxDATAVIEW_COL_RESIZABLE - Filename - wxDATAVIEW_CELL_INERT - 0 - browserFilenameColumn - protected - Text - -1 - - - wxALIGN_LEFT - - wxDATAVIEW_COL_RESIZABLE - Mode - wxDATAVIEW_CELL_INERT - 1 - browserModeColumn - protected - Text - -1 - - - wxALIGN_LEFT - - wxDATAVIEW_COL_RESIZABLE - Length - wxDATAVIEW_CELL_INERT - 2 - browserLengthColumn - protected - Text - -1 - - - wxALIGN_LEFT - - wxDATAVIEW_COL_RESIZABLE - Additional properties - wxDATAVIEW_CELL_INERT - 0 - browserExtraColumn - protected - Text - -1 - - - + + OnBrowserDirectoryExpanding + + wxALIGN_LEFT + + wxDATAVIEW_COL_RESIZABLE + Filename + wxDATAVIEW_CELL_INERT + 0 + m_dataViewColumn1 + protected + IconText + 250 + + + wxALIGN_RIGHT + + wxDATAVIEW_COL_RESIZABLE + Size + wxDATAVIEW_CELL_INERT + 1 + m_dataViewColumn2 + protected + Text + -1 + + + wxALIGN_LEFT + + wxDATAVIEW_COL_RESIZABLE + Mode + wxDATAVIEW_CELL_INERT + 2 + m_dataViewColumn3 + protected + Text + -1 diff --git a/src/gui/layout.h b/src/gui/layout.h index 9720ca1d..87170456 100644 --- a/src/gui/layout.h +++ b/src/gui/layout.h @@ -84,12 +84,15 @@ class MainWindowGen : public wxFrame wxPanel* browsePanel; wxToolBar* browserToolbar; wxToolBarToolBase* browserBackTool; - wxScrolledWindow* m_scrolledWindow1; - wxDataViewCtrl* browserView; - wxDataViewColumn* browserFilenameColumn; - wxDataViewColumn* browserModeColumn; - wxDataViewColumn* browserLengthColumn; - wxDataViewColumn* browserExtraColumn; + wxToolBarToolBase* m_tool3; + wxToolBarToolBase* m_tool4; + wxToolBarToolBase* m_tool5; + wxToolBarToolBase* m_tool6; + wxToolBarToolBase* m_tool7; + wxDataViewCtrl* browserTree; + wxDataViewColumn* m_dataViewColumn1; + wxDataViewColumn* m_dataViewColumn2; + wxDataViewColumn* m_dataViewColumn3; wxButton* browserDiscardButton; wxButton* browserCommitButton; @@ -105,15 +108,17 @@ class MainWindowGen : public wxFrame virtual void OnCustomConfigurationButton( wxCommandEvent& event ) { event.Skip(); } virtual void OnReadButton( wxCommandEvent& event ) { event.Skip(); } virtual void OnWriteButton( wxCommandEvent& event ) { event.Skip(); } + virtual void OnBrowseButton( wxCommandEvent& event ) { event.Skip(); } virtual void OnBackButton( wxCommandEvent& event ) { event.Skip(); } virtual void OnSaveImageButton( wxCommandEvent& event ) { event.Skip(); } virtual void OnSaveFluxButton( wxCommandEvent& event ) { event.Skip(); } virtual void OnImagerGoAgainButton( wxCommandEvent& event ) { event.Skip(); } + virtual void OnBrowserDirectoryExpanding( wxDataViewEvent& event ) { event.Skip(); } public: - MainWindowGen( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("FluxEngine"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 819,607 ), long style = wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER|wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL ); + MainWindowGen( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("FluxEngine"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 570,607 ), long style = wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER|wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL ); ~MainWindowGen(); diff --git a/src/gui/mainwindow.cc b/src/gui/mainwindow.cc index 9eb8e96f..53ae3fc0 100644 --- a/src/gui/mainwindow.cc +++ b/src/gui/mainwindow.cc @@ -16,7 +16,9 @@ #include "fluxviewerwindow.h" #include "textviewerwindow.h" #include "texteditorwindow.h" +#include "filesystemmodel.h" #include "customstatusbar.h" +#include "lib/vfs/vfs.h" #include #include #include @@ -394,6 +396,83 @@ public: UpdateState(); } + /* --- Browser ---------------------------------------------------------- */ + + void OnBrowseButton(wxCommandEvent& event) override + { + try + { + PrepareConfig(); + + visualiser->Clear(); + _currentDisk = nullptr; + + _state = STATE_BROWSING_WORKING; + UpdateState(); + ShowConfig(); + + _filesystemModel = FilesystemModel::Associate(browserTree); + + _errorState = STATE_BROWSING_IDLE; + runOnWorkerThread( + [this]() + { + _filesystem = Filesystem::createFilesystemFromConfig(); + auto files = _filesystem->list(Path()); + + runOnUiThread( + [&]() + { + _filesystemModel->SetFiles( + _filesystemModel->GetRootItem(), files); + + _state = STATE_BROWSING_IDLE; + UpdateState(); + }); + }); + } + catch (const ErrorException& e) + { + wxMessageBox(e.message, "Error", wxOK | wxICON_ERROR); + _state = STATE_IDLE; + } + } + + void OnBrowserDirectoryExpanding(wxDataViewEvent& event) + { + auto item = event.GetItem(); + auto dc = (DirentContainer*)_filesystemModel->GetItemData(item); + + if (!dc->populated && !dc->populating) + { + dc->populating = true; + bool running = wxGetApp().IsWorkerThreadRunning(); + auto path = dc->dirent->path; + if (!running) + { + _state = STATE_BROWSING_WORKING; + UpdateState(); + runOnWorkerThread( + [this, path, item]() + { + auto files = _filesystem->list(path); + + runOnUiThread( + [&]() + { + _filesystemModel->SetFiles(item, files); + browserTree->Expand(item); + + _state = STATE_BROWSING_IDLE; + UpdateState(); + }); + }); + } + } + } + + /* --- Config management ------------------------------------------------ */ + /* This sets the *global* config object. That's safe provided the worker * thread isn't running, otherwise you'll get a race. */ void PrepareConfig() @@ -789,7 +868,7 @@ private: std::vector>> _formats; std::vector> _devices; - int _state; + int _state = STATE_IDLE; int _errorState; int _selectedSource; bool _dontSaveConfig = false; @@ -799,6 +878,8 @@ private: std::unique_ptr _logWindow; std::unique_ptr _configWindow; std::string _extraConfiguration; + std::unique_ptr _filesystem; + FilesystemModel* _filesystemModel; }; wxWindow* FluxEngineApp::CreateMainWindow() diff --git a/tests/build.mk b/tests/build.mk index a6d218be..d82bb7d0 100644 --- a/tests/build.mk +++ b/tests/build.mk @@ -17,6 +17,7 @@ $(call use-library, $(OBJDIR)/tests/$1.exe, $(OBJDIR)/tests/$1.o, PROTO) $(call use-library, $(OBJDIR)/tests/$1.exe, $(OBJDIR)/tests/$1.o, FATFS) $(call use-library, $(OBJDIR)/tests/$1.exe, $(OBJDIR)/tests/$1.o, ADFLIB) $(call use-library, $(OBJDIR)/tests/$1.exe, $(OBJDIR)/tests/$1.o, HFSUTILS) +$(call use-library, $(OBJDIR)/tests/$1.exe, $(OBJDIR)/tests/$1.o, LIBUSBP) endef