mirror of https://github.com/stella-emu/stella.git
More reworking of the file selection mechanism.
- removed GameList, and integrated functionality directly into 'FSList' (which was mostly doing the same thing) - have FSNode::getChildren() relabel directories, instead of Browser and Launcher dialogs - MD5 calculations in ROM launcher are now cached, instead of being recalculated each time a directory is left and re-entered Windows and macOS likely broken for a moment; this will be fixed next.
This commit is contained in:
parent
786f3b2a49
commit
bcca945951
|
@ -134,8 +134,8 @@ void FilesystemNodeZIP::setFlags(const string& zipfile,
|
|||
{
|
||||
_path += ("/" + _virtualPath);
|
||||
_shortPath += ("/" + _virtualPath);
|
||||
_name = lastPathComponent(_path);
|
||||
}
|
||||
_name = lastPathComponent(_path);
|
||||
|
||||
_error = zip_error::NONE;
|
||||
if(!_realNode->isFile())
|
||||
|
@ -145,8 +145,7 @@ void FilesystemNodeZIP::setFlags(const string& zipfile,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode,
|
||||
bool hidden) const
|
||||
bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const
|
||||
{
|
||||
// Files within ZIP archives don't contain children
|
||||
if(!isDirectory() || _error != zip_error::NONE)
|
||||
|
|
|
@ -48,9 +48,11 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
explicit FilesystemNodeZIP(const string& path);
|
||||
|
||||
bool exists() const override { return _realNode && _realNode->exists(); }
|
||||
const string& getName() const override { return _name; }
|
||||
const string& getName() const override { return _name; }
|
||||
void setName(const string& name) override { _name = name; }
|
||||
const string& getPath() const override { return _path; }
|
||||
string getShortPath() const override { return _shortPath; }
|
||||
bool hasParent() const override { return true; }
|
||||
bool isDirectory() const override { return _isDirectory; }
|
||||
bool isFile() const override { return _isFile; }
|
||||
bool isReadable() const override { return _realNode && _realNode->isReadable(); }
|
||||
|
@ -62,7 +64,7 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
bool rename(const string& newfile) override { return false; }
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const override;
|
||||
bool getChildren(AbstractFSList& list, ListMode mode) const override;
|
||||
AbstractFSNodePtr getParent() const override;
|
||||
|
||||
uInt32 read(ByteBuffer& image) const override;
|
||||
|
|
|
@ -37,7 +37,7 @@ FilesystemNode::FilesystemNode(const string& p)
|
|||
{
|
||||
// Is this potentially a ZIP archive?
|
||||
#if defined(ZIP_SUPPORT)
|
||||
if(BSPF::containsIgnoreCase(p, ".zip"))
|
||||
if (BSPF::containsIgnoreCase(p, ".zip"))
|
||||
_realNode = FilesystemNodeFactory::create(p, FilesystemNodeFactory::Type::ZIP);
|
||||
else
|
||||
#endif
|
||||
|
@ -51,7 +51,7 @@ bool FilesystemNode::exists() const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FilesystemNode::getChildren(FSList& fslist, ListMode mode, bool hidden) const
|
||||
bool FilesystemNode::getChildren(FSList& fslist, ListMode mode) const
|
||||
{
|
||||
if (!_realNode || !_realNode->isDirectory())
|
||||
return false;
|
||||
|
@ -59,11 +59,48 @@ bool FilesystemNode::getChildren(FSList& fslist, ListMode mode, bool hidden) con
|
|||
AbstractFSList tmp;
|
||||
tmp.reserve(fslist.capacity());
|
||||
|
||||
if (!_realNode->getChildren(tmp, mode, hidden))
|
||||
if (!_realNode->getChildren(tmp, mode))
|
||||
return false;
|
||||
|
||||
std::sort(tmp.begin(), tmp.end(),
|
||||
[](const AbstractFSNodePtr& node1, const AbstractFSNodePtr& node2)
|
||||
{
|
||||
if (node1->isDirectory() != node2->isDirectory())
|
||||
return node1->isDirectory();
|
||||
else
|
||||
return BSPF::compareIgnoreCase(node1->getName(), node2->getName()) < 0;
|
||||
}
|
||||
);
|
||||
|
||||
// Add parent node, if it is valid to do so
|
||||
if (hasParent())
|
||||
{
|
||||
FilesystemNode parent = getParent();
|
||||
parent.setName(" [..]");
|
||||
fslist.emplace_back(parent);
|
||||
}
|
||||
|
||||
// And now add the rest of the entries
|
||||
for (const auto& i: tmp)
|
||||
fslist.emplace_back(FilesystemNode(i));
|
||||
{
|
||||
#if defined(ZIP_SUPPORT)
|
||||
// Force ZIP c'tor to be called
|
||||
if (BSPF::endsWithIgnoreCase(i->getPath(), ".zip"))
|
||||
{
|
||||
AbstractFSNodePtr ptr = FilesystemNodeFactory::create(i->getPath(),
|
||||
FilesystemNodeFactory::Type::ZIP);
|
||||
fslist.emplace_back(FilesystemNode(ptr));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Make directories stand out
|
||||
if (i->isDirectory())
|
||||
i->setName(" [" + i->getName() + "]");
|
||||
|
||||
fslist.emplace_back(FilesystemNode(i));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -74,6 +111,13 @@ const string& FilesystemNode::getName() const
|
|||
return _realNode->getName();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FilesystemNode::setName(const string& name)
|
||||
{
|
||||
_realNode->setName(name);
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string& FilesystemNode::getPath() const
|
||||
{
|
||||
|
@ -109,7 +153,7 @@ string FilesystemNode::getPathWithExt(const string& ext) const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FilesystemNode::hasParent() const
|
||||
{
|
||||
return _realNode ? (_realNode->getParent() != nullptr) : false;
|
||||
return _realNode ? _realNode->hasParent() : false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -164,23 +208,23 @@ uInt32 FilesystemNode::read(ByteBuffer& image) const
|
|||
uInt32 size = 0;
|
||||
|
||||
// File must actually exist
|
||||
if(!(exists() && isReadable()))
|
||||
if (!(exists() && isReadable()))
|
||||
throw runtime_error("File not found/readable");
|
||||
|
||||
// First let the private subclass attempt to open the file
|
||||
if((size = _realNode->read(image)) > 0)
|
||||
if ((size = _realNode->read(image)) > 0)
|
||||
return size;
|
||||
|
||||
// Otherwise, the default behaviour is to read from a normal C++ ifstream
|
||||
image = make_unique<uInt8[]>(512 * 1024);
|
||||
ifstream in(getPath(), std::ios::binary);
|
||||
if(in)
|
||||
if (in)
|
||||
{
|
||||
in.seekg(0, std::ios::end);
|
||||
std::streampos length = in.tellg();
|
||||
in.seekg(0, std::ios::beg);
|
||||
|
||||
if(length == 0)
|
||||
if (length == 0)
|
||||
throw runtime_error("Zero-byte file");
|
||||
|
||||
size = std::min(uInt32(length), 512u * 1024u);
|
||||
|
|
|
@ -94,18 +94,6 @@ class FilesystemNode
|
|||
FilesystemNode(const FilesystemNode&) = default;
|
||||
FilesystemNode& operator=(const FilesystemNode&) = default;
|
||||
|
||||
/**
|
||||
* Compare the name of this node to the name of another. Directories
|
||||
* go before normal files.
|
||||
*/
|
||||
inline bool operator<(const FilesystemNode& node) const
|
||||
{
|
||||
if (isDirectory() != node.isDirectory())
|
||||
return isDirectory();
|
||||
|
||||
return BSPF::compareIgnoreCase(getName(), node.getName()) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the name of this node to the name of another, testing for
|
||||
* equality,
|
||||
|
@ -139,11 +127,10 @@ class FilesystemNode
|
|||
* @return true if successful, false otherwise (e.g. when the directory
|
||||
* does not exist).
|
||||
*/
|
||||
bool getChildren(FSList& fslist, ListMode mode = ListMode::DirectoriesOnly,
|
||||
bool hidden = false) const;
|
||||
bool getChildren(FSList& fslist, ListMode mode = ListMode::DirectoriesOnly) const;
|
||||
|
||||
/**
|
||||
* Return a string representation of the name of the file. This is can be
|
||||
* Set/get a string representation of the name of the file. This is can be
|
||||
* used e.g. by detection code that relies on matching the name of a given
|
||||
* file. But it is *not* suitable for use with fopen / File::open, nor
|
||||
* should it be archived.
|
||||
|
@ -151,6 +138,7 @@ class FilesystemNode
|
|||
* @return the file name
|
||||
*/
|
||||
const string& getName() const;
|
||||
void setName(const string& name);
|
||||
|
||||
/**
|
||||
* Return a string representation of the file which can be passed to fopen().
|
||||
|
@ -300,12 +288,11 @@ class AbstractFSNode
|
|||
*
|
||||
* @param list List to put the contents of the directory in.
|
||||
* @param mode Mode to use while listing the directory.
|
||||
* @param hidden Whether to include hidden files or not in the results.
|
||||
*
|
||||
* @return true if successful, false otherwise (e.g. when the directory
|
||||
* does not exist).
|
||||
*/
|
||||
virtual bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const = 0;
|
||||
virtual bool getChildren(AbstractFSList& list, ListMode mode) const = 0;
|
||||
|
||||
/**
|
||||
* Returns the last component of the path pointed by this FilesystemNode.
|
||||
|
@ -318,6 +305,7 @@ class AbstractFSNode
|
|||
* implementation for more information.
|
||||
*/
|
||||
virtual const string& getName() const = 0;
|
||||
virtual void setName(const string& name) = 0;
|
||||
|
||||
/**
|
||||
* Returns the 'path' of the current node, usable in fopen().
|
||||
|
@ -330,6 +318,17 @@ class AbstractFSNode
|
|||
|
||||
virtual string getShortPath() const = 0;
|
||||
|
||||
/**
|
||||
* Determine whether this node has a parent.
|
||||
*/
|
||||
virtual bool hasParent() const = 0;
|
||||
|
||||
/**
|
||||
* The parent node of this directory.
|
||||
* The parent of the root is 'nullptr'.
|
||||
*/
|
||||
virtual AbstractFSNodePtr getParent() const = 0;
|
||||
|
||||
/**
|
||||
* Indicates whether this path refers to a directory or not.
|
||||
*/
|
||||
|
@ -392,12 +391,6 @@ class AbstractFSNode
|
|||
* a try-catch block.
|
||||
*/
|
||||
virtual uInt32 read(ByteBuffer& buffer) const { return 0; }
|
||||
|
||||
/**
|
||||
* The parent node of this directory.
|
||||
* The parent of the root is the root itself.
|
||||
*/
|
||||
virtual AbstractFSNodePtr getParent() const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,16 +18,21 @@
|
|||
#include "ScrollBarWidget.hxx"
|
||||
#include "FileListWidget.hxx"
|
||||
|
||||
#include "Bankswitch.hxx"
|
||||
#include "MD5.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
TODO:
|
||||
- extension handling not handled
|
||||
- add lambda filter to selectively choose files based on pattern
|
||||
- history of selected folders/files
|
||||
*/
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FileListWidget::FileListWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int w, int h)
|
||||
: StringListWidget(boss, font, x, y, w, h),
|
||||
_fsmode(FilesystemNode::ListMode::All),
|
||||
_selectedPos(0)
|
||||
_selected(0)
|
||||
{
|
||||
// This widget is special, in that it catches signals and redirects them
|
||||
setTarget(this);
|
||||
|
@ -45,36 +50,15 @@ void FileListWidget::setLocation(const FilesystemNode& node, string select)
|
|||
_node = _node.getParent();
|
||||
}
|
||||
|
||||
// Start with empty list
|
||||
_gameList.clear();
|
||||
|
||||
// Read in the data from the file system
|
||||
FSList content;
|
||||
content.reserve(512);
|
||||
_node.getChildren(content, _fsmode);
|
||||
|
||||
// Add '[..]' to indicate previous folder
|
||||
if(_node.hasParent())
|
||||
_gameList.appendGame(" [..]", _node.getParent().getPath(), "", true);
|
||||
|
||||
// Now add the directory entries
|
||||
for(const auto& file: content)
|
||||
{
|
||||
string name = file.getName();
|
||||
bool isDir = file.isDirectory();
|
||||
if(isDir)
|
||||
name = " [" + name + "]";
|
||||
else if(!BSPF::endsWithIgnoreCase(name, _extension))
|
||||
continue;
|
||||
|
||||
_gameList.appendGame(name, file.getPath(), "", isDir);
|
||||
}
|
||||
_gameList.sortByName();
|
||||
// Read in the data from the file system (start with an empty list)
|
||||
_fileList.clear();
|
||||
_fileList.reserve(512);
|
||||
_node.getChildren(_fileList, _fsmode);
|
||||
|
||||
// Now fill the list widget with the contents of the GameList
|
||||
StringList l;
|
||||
for(uInt32 i = 0; i < _gameList.size(); ++i)
|
||||
l.push_back(_gameList.name(i));
|
||||
for(const auto& file: _fileList)
|
||||
l.push_back(file.getName());
|
||||
|
||||
setList(l);
|
||||
setSelected(select);
|
||||
|
@ -96,20 +80,7 @@ void FileListWidget::selectParent()
|
|||
void FileListWidget::reload()
|
||||
{
|
||||
if(_node.exists())
|
||||
setLocation(_node, _gameList.name(_selectedPos));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string& FileListWidget::selectedMD5()
|
||||
{
|
||||
if(_selected.isDirectory() || !Bankswitch::isValidRomName(_selected))
|
||||
return EmptyString;
|
||||
|
||||
// Make sure we have a valid md5 for this ROM
|
||||
if(_gameList.md5(_selectedPos) == "")
|
||||
_gameList.setMd5(_selectedPos, MD5::hash(_selected));
|
||||
|
||||
return _gameList.md5(_selectedPos);
|
||||
setLocation(_node, selected().getName());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -123,19 +94,16 @@ void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int
|
|||
|
||||
case ListWidget::kSelectionChangedCmd:
|
||||
cmd = ItemChanged;
|
||||
_selected = FilesystemNode(_gameList.path(data));
|
||||
_selectedPos = data;
|
||||
_selected = data;
|
||||
break;
|
||||
|
||||
case ListWidget::kActivatedCmd:
|
||||
case ListWidget::kDoubleClickedCmd:
|
||||
if(_gameList.isDir(data))
|
||||
_selected = data;
|
||||
if(selected().isDirectory())
|
||||
{
|
||||
cmd = ItemChanged;
|
||||
if(_gameList.name(data) == " [..]")
|
||||
selectParent();
|
||||
else
|
||||
setLocation(FilesystemNode(_gameList.path(data)));
|
||||
setLocation(selected());
|
||||
}
|
||||
else
|
||||
cmd = ItemActivated;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
class CommandSender;
|
||||
|
||||
#include "FSNode.hxx"
|
||||
#include "GameList.hxx"
|
||||
#include "StringListWidget.hxx"
|
||||
|
||||
/**
|
||||
|
@ -64,26 +63,19 @@ class FileListWidget : public StringListWidget
|
|||
void reload();
|
||||
|
||||
/** Gets current node(s) */
|
||||
const FilesystemNode& selected() const { return _selected; }
|
||||
const FilesystemNode& currentDir() const { return _node; }
|
||||
|
||||
/** Gets MD5sum of the current node, if it is a file, and caches the result.
|
||||
Otherwise, does nothing.
|
||||
|
||||
@return MD5sum of selected file, else EmptyString
|
||||
*/
|
||||
const string& selectedMD5();
|
||||
const FilesystemNode& selected() const { return _fileList[_selected]; }
|
||||
const FilesystemNode& currentDir() const { return _node; }
|
||||
|
||||
private:
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
||||
private:
|
||||
FilesystemNode::ListMode _fsmode;
|
||||
FilesystemNode _node, _selected;
|
||||
GameList _gameList;
|
||||
FilesystemNode _node;
|
||||
FSList _fileList;
|
||||
|
||||
string _extension;
|
||||
uInt32 _selectedPos;
|
||||
uInt32 _selected;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// Based on code from KStella - Stella frontend
|
||||
// Copyright (C) 2003-2005 Stephen Anthony
|
||||
//============================================================================
|
||||
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
#include "GameList.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void GameList::sortByName()
|
||||
{
|
||||
if(myArray.size() < 2)
|
||||
return;
|
||||
|
||||
auto cmp = [](const Entry& a, const Entry& b)
|
||||
{
|
||||
// directories always first
|
||||
if(a._isdir != b._isdir)
|
||||
return a._isdir;
|
||||
|
||||
auto it1 = a._name.cbegin(), it2 = b._name.cbegin();
|
||||
|
||||
// Account for ending ']' character in directory entries
|
||||
auto end1 = a._isdir ? a._name.cend() - 1 : a._name.cend();
|
||||
auto end2 = b._isdir ? b._name.cend() - 1 : b._name.cend();
|
||||
|
||||
// Stop when either string's end has been reached
|
||||
while((it1 != end1) && (it2 != end2))
|
||||
{
|
||||
if(toupper(*it1) != toupper(*it2)) // letters differ?
|
||||
return toupper(*it1) < toupper(*it2);
|
||||
|
||||
// proceed to the next character in each string
|
||||
++it1;
|
||||
++it2;
|
||||
}
|
||||
return a._name.size() < b._name.size();
|
||||
};
|
||||
|
||||
sort(myArray.begin(), myArray.end(), cmp);
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// Based on code from KStella - Stella frontend
|
||||
// Copyright (C) 2003-2005 Stephen Anthony
|
||||
//============================================================================
|
||||
|
||||
#ifndef GAME_LIST_HXX
|
||||
#define GAME_LIST_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
Holds the list of game info for the ROM launcher.
|
||||
*/
|
||||
class GameList
|
||||
{
|
||||
public:
|
||||
GameList() = default;
|
||||
|
||||
const string& name(uInt32 i) const
|
||||
{ return i < myArray.size() ? myArray[i]._name : EmptyString; }
|
||||
const string& path(uInt32 i) const
|
||||
{ return i < myArray.size() ? myArray[i]._path : EmptyString; }
|
||||
const string& md5(uInt32 i) const
|
||||
{ return i < myArray.size() ? myArray[i]._md5 : EmptyString; }
|
||||
bool isDir(uInt32 i) const
|
||||
{ return i < myArray.size() ? myArray[i]._isdir: false; }
|
||||
|
||||
void setMd5(uInt32 i, const string& md5)
|
||||
{ myArray[i]._md5 = md5; }
|
||||
|
||||
uInt32 size() const { return uInt32(myArray.size()); }
|
||||
void clear() { myArray.clear(); }
|
||||
|
||||
void appendGame(const string& name, const string& path, const string& md5,
|
||||
bool isDir = false) {
|
||||
myArray.emplace_back(name, path, md5, isDir);
|
||||
}
|
||||
void sortByName();
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
string _name;
|
||||
string _path;
|
||||
string _md5;
|
||||
bool _isdir;
|
||||
|
||||
Entry(string name, string path, string md5, bool isdir)
|
||||
: _name(name), _path(path), _md5(md5), _isdir(isdir) { }
|
||||
};
|
||||
vector<Entry> myArray;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
GameList(const GameList&) = delete;
|
||||
GameList(GameList&&) = delete;
|
||||
GameList& operator=(const GameList&) = delete;
|
||||
GameList& operator=(GameList&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -16,6 +16,7 @@
|
|||
//============================================================================
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Bankswitch.hxx"
|
||||
#include "BrowserDialog.hxx"
|
||||
#include "ContextMenu.hxx"
|
||||
#include "DialogContainer.hxx"
|
||||
|
@ -23,7 +24,7 @@
|
|||
#include "EditTextWidget.hxx"
|
||||
#include "FileListWidget.hxx"
|
||||
#include "FSNode.hxx"
|
||||
#include "GameList.hxx"
|
||||
#include "MD5.hxx"
|
||||
#include "OptionsDialog.hxx"
|
||||
#include "GlobalPropsDialog.hxx"
|
||||
#include "StellaSettingsDialog.hxx"
|
||||
|
@ -46,7 +47,7 @@
|
|||
TODO:
|
||||
- show all files / only ROMs
|
||||
- connect to 'matchPattern'
|
||||
- history of selected folders/files
|
||||
- create lambda filter to pass these to FileListWidget
|
||||
*/
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -246,7 +247,19 @@ const string& LauncherDialog::selectedRom() const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string& LauncherDialog::selectedRomMD5()
|
||||
{
|
||||
return myList->selectedMD5();
|
||||
if(currentNode().isDirectory() || !Bankswitch::isValidRomName(currentNode()))
|
||||
return EmptyString;
|
||||
|
||||
// Attempt to conserve memory
|
||||
if(myMD5List.size() > 500)
|
||||
myMD5List.clear();
|
||||
|
||||
// Lookup MD5, and if not present, cache it
|
||||
auto iter = myMD5List.find(currentNode().getPath());
|
||||
if(iter == myMD5List.end())
|
||||
myMD5List[currentNode().getPath()] = MD5::hash(currentNode());
|
||||
|
||||
return myMD5List[currentNode().getPath()];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -612,7 +625,7 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd,
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void LauncherDialog::loadRom()
|
||||
{
|
||||
const string& result = instance().createConsole(currentNode(), myList->selectedMD5());
|
||||
const string& result = instance().createConsole(currentNode(), selectedRomMD5());
|
||||
if(result == EmptyString)
|
||||
{
|
||||
instance().settings().setValue("lastrom", myList->getSelectedString());
|
||||
|
|
|
@ -36,6 +36,8 @@ namespace GUI {
|
|||
class MessageBox;
|
||||
}
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Dialog.hxx"
|
||||
#include "FSNode.hxx"
|
||||
|
@ -122,6 +124,7 @@ class LauncherDialog : public Dialog
|
|||
CheckboxWidget* myAllFiles;
|
||||
|
||||
RomInfoWidget* myRomInfoWidget;
|
||||
std::unordered_map<string,string> myMD5List;
|
||||
|
||||
int mySelectedItem;
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ MODULE_OBJS := \
|
|||
src/gui/FileListWidget.o \
|
||||
src/gui/Font.o \
|
||||
src/gui/GameInfoDialog.o \
|
||||
src/gui/GameList.o \
|
||||
src/gui/GlobalPropsDialog.o \
|
||||
src/gui/HelpDialog.o \
|
||||
src/gui/InputDialog.o \
|
||||
|
|
|
@ -19,14 +19,11 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FilesystemNodeLIBRETRO::FilesystemNodeLIBRETRO()
|
||||
: _name("rom"),
|
||||
_isDirectory(false),
|
||||
_isFile(true),
|
||||
_isValid(true)
|
||||
{
|
||||
_displayName = "rom";
|
||||
_path = "";
|
||||
|
||||
_isDirectory = false;
|
||||
_isFile = true;
|
||||
_isPseudoRoot = false;
|
||||
_isValid = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -60,7 +57,7 @@ string FilesystemNodeLIBRETRO::getShortPath() const
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FilesystemNodeLIBRETRO::
|
||||
getChildren(AbstractFSList& myList, ListMode mode, bool hidden) const
|
||||
getChildren(AbstractFSList& myList, ListMode mode) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
|
||||
#include "FSNode.hxx"
|
||||
|
||||
// TODO - fix isFile() functionality so that it actually determines if something
|
||||
// is a file; for now, it assumes a file if it isn't a directory
|
||||
|
||||
/*
|
||||
* Implementation of the Stella file system API based on LIBRETRO API.
|
||||
*
|
||||
|
@ -37,9 +34,11 @@ class FilesystemNodeLIBRETRO : public AbstractFSNode
|
|||
explicit FilesystemNodeLIBRETRO(const string& path);
|
||||
|
||||
bool exists() const override;
|
||||
const string& getName() const override { return _displayName; }
|
||||
const string& getPath() const override { return _path; }
|
||||
const string& getName() const override { return _name; }
|
||||
void setName(const string& name) override { _name = name; }
|
||||
const string& getPath() const override { return _path; }
|
||||
string getShortPath() const override;
|
||||
bool hasParent() const override { return false; }
|
||||
bool isDirectory() const override { return _isDirectory; }
|
||||
bool isFile() const override { return _isFile; }
|
||||
bool isReadable() const override;
|
||||
|
@ -47,13 +46,13 @@ class FilesystemNodeLIBRETRO : public AbstractFSNode
|
|||
bool makeDir() override;
|
||||
bool rename(const string& newfile) override;
|
||||
|
||||
bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const override;
|
||||
bool getChildren(AbstractFSList& list, ListMode mode) const override;
|
||||
AbstractFSNodePtr getParent() const override;
|
||||
|
||||
uInt32 read(ByteBuffer& image) const override;
|
||||
|
||||
protected:
|
||||
string _displayName;
|
||||
string _name;
|
||||
string _path;
|
||||
bool _isDirectory;
|
||||
bool _isFile;
|
||||
|
|
|
@ -53,13 +53,13 @@ FilesystemNodePOSIX::FilesystemNodePOSIX()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FilesystemNodePOSIX::FilesystemNodePOSIX(const string& p, bool verify)
|
||||
FilesystemNodePOSIX::FilesystemNodePOSIX(const string& path, bool verify)
|
||||
: _isValid(true),
|
||||
_isFile(false),
|
||||
_isDirectory(true)
|
||||
{
|
||||
// Default to home directory
|
||||
_path = p.length() > 0 ? p : "~";
|
||||
_path = path.length() > 0 ? path : "~";
|
||||
|
||||
// Expand '~' to the HOME environment variable
|
||||
if(_path[0] == '~')
|
||||
|
@ -99,8 +99,13 @@ string FilesystemNodePOSIX::getShortPath() const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FilesystemNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode,
|
||||
bool hidden) const
|
||||
bool FilesystemNodePOSIX::hasParent() const
|
||||
{
|
||||
return _path != "" && _path != ROOT_DIR;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FilesystemNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode) const
|
||||
{
|
||||
assert(_isDirectory);
|
||||
|
||||
|
@ -112,12 +117,8 @@ bool FilesystemNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode,
|
|||
struct dirent* dp;
|
||||
while ((dp = readdir(dirp)) != nullptr)
|
||||
{
|
||||
// Skip 'invisible' files if necessary
|
||||
if (dp->d_name[0] == '.' && !hidden)
|
||||
continue;
|
||||
|
||||
// Skip '.' and '..' to avoid cycles
|
||||
if ((dp->d_name[0] == '.' && dp->d_name[1] == 0) || (dp->d_name[0] == '.' && dp->d_name[1] == '.'))
|
||||
// Ignore all hidden files
|
||||
if (dp->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
string newPath(_path);
|
||||
|
|
|
@ -61,9 +61,11 @@ class FilesystemNodePOSIX : public AbstractFSNode
|
|||
FilesystemNodePOSIX(const string& path, bool verify = true);
|
||||
|
||||
bool exists() const override { return access(_path.c_str(), F_OK) == 0; }
|
||||
const string& getName() const override { return _displayName; }
|
||||
const string& getName() const override { return _displayName; }
|
||||
void setName(const string& name) override { _displayName = name; }
|
||||
const string& getPath() const override { return _path; }
|
||||
string getShortPath() const override;
|
||||
bool hasParent() const override;
|
||||
bool isDirectory() const override { return _isDirectory; }
|
||||
bool isFile() const override { return _isFile; }
|
||||
bool isReadable() const override { return access(_path.c_str(), R_OK) == 0; }
|
||||
|
@ -71,7 +73,7 @@ class FilesystemNodePOSIX : public AbstractFSNode
|
|||
bool makeDir() override;
|
||||
bool rename(const string& newfile) override;
|
||||
|
||||
bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const override;
|
||||
bool getChildren(AbstractFSList& list, ListMode mode) const override;
|
||||
AbstractFSNodePtr getParent() const override;
|
||||
|
||||
protected:
|
||||
|
|
Loading…
Reference in New Issue