mpd: add OutputIterator
This commit is contained in:
@@ -31,62 +31,6 @@ MPD::Connection Mpd;
|
|||||||
|
|
||||||
namespace MPD {
|
namespace MPD {
|
||||||
|
|
||||||
SongIterator::~SongIterator()
|
|
||||||
{
|
|
||||||
if (m_connection)
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SongIterator::finish()
|
|
||||||
{
|
|
||||||
// clean up
|
|
||||||
assert(m_connection);
|
|
||||||
mpd_response_finish(m_connection.get());
|
|
||||||
m_song = Song();
|
|
||||||
m_connection = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Song &SongIterator::operator*() const
|
|
||||||
{
|
|
||||||
assert(m_connection);
|
|
||||||
assert(!m_song.empty());
|
|
||||||
// we could make m_song a pointer to a Song and dereference here,
|
|
||||||
// but it's retarded as Song itself is essentially wrapper to
|
|
||||||
// std::shared_ptr. on the other hand, we need constness for the
|
|
||||||
// iterator to be able to play along with std::move_iterator.
|
|
||||||
return const_cast<Song &>(m_song);
|
|
||||||
}
|
|
||||||
|
|
||||||
Song *SongIterator::operator->() const
|
|
||||||
{
|
|
||||||
return &**this;
|
|
||||||
}
|
|
||||||
|
|
||||||
SongIterator &SongIterator::operator++()
|
|
||||||
{
|
|
||||||
assert(m_connection);
|
|
||||||
mpd_song *s = mpd_recv_song(m_connection.get());
|
|
||||||
if (s != nullptr)
|
|
||||||
m_song = Song(s);
|
|
||||||
else
|
|
||||||
finish();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
SongIterator SongIterator::operator++(int)
|
|
||||||
{
|
|
||||||
SongIterator it(*this);
|
|
||||||
++*this;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
SongIterator::SongIterator(std::shared_ptr<mpd_connection> conn)
|
|
||||||
: m_connection(std::move(conn))
|
|
||||||
{
|
|
||||||
// get the first element
|
|
||||||
++*this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Connection::Connection() : m_connection(nullptr),
|
Connection::Connection() : m_connection(nullptr),
|
||||||
m_command_list_active(false),
|
m_command_list_active(false),
|
||||||
m_idle(false),
|
m_idle(false),
|
||||||
@@ -354,7 +298,7 @@ SongIterator Connection::GetPlaylistChanges(unsigned version)
|
|||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_queue_changes_meta(m_connection.get(), version);
|
mpd_send_queue_changes_meta(m_connection.get(), version);
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return SongIterator(m_connection);
|
return SongIterator(m_connection, mpd_recv_song);
|
||||||
}
|
}
|
||||||
|
|
||||||
Song Connection::GetCurrentSong()
|
Song Connection::GetCurrentSong()
|
||||||
@@ -381,7 +325,7 @@ SongIterator Connection::GetPlaylistContent(const std::string &path)
|
|||||||
{
|
{
|
||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_list_playlist_meta(m_connection.get(), path.c_str());
|
mpd_send_list_playlist_meta(m_connection.get(), path.c_str());
|
||||||
SongIterator result(m_connection);
|
SongIterator result(m_connection, mpd_recv_song);
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -390,7 +334,7 @@ SongIterator Connection::GetPlaylistContentNoInfo(const std::string &path)
|
|||||||
{
|
{
|
||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_list_playlist(m_connection.get(), path.c_str());
|
mpd_send_list_playlist(m_connection.get(), path.c_str());
|
||||||
SongIterator result(m_connection);
|
SongIterator result(m_connection, mpd_recv_song);
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -720,7 +664,7 @@ SongIterator Connection::CommitSearchSongs()
|
|||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_search_commit(m_connection.get());
|
mpd_search_commit(m_connection.get());
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return SongIterator(m_connection);
|
return SongIterator(m_connection, mpd_recv_song);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::CommitSearchTags(StringConsumer f)
|
void Connection::CommitSearchTags(StringConsumer f)
|
||||||
@@ -798,20 +742,15 @@ SongIterator Connection::GetSongs(const std::string &directory)
|
|||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_list_meta(m_connection.get(), directory.c_str());
|
mpd_send_list_meta(m_connection.get(), directory.c_str());
|
||||||
checkErrors();
|
checkErrors();
|
||||||
return SongIterator(m_connection);
|
return SongIterator(m_connection, mpd_recv_song);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::GetOutputs(OutputConsumer f)
|
OutputIterator Connection::GetOutputs()
|
||||||
{
|
{
|
||||||
prechecksNoCommandsList();
|
prechecksNoCommandsList();
|
||||||
mpd_send_outputs(m_connection.get());
|
mpd_send_outputs(m_connection.get());
|
||||||
while (mpd_output *output = mpd_recv_output(m_connection.get()))
|
|
||||||
{
|
|
||||||
f(Output(mpd_output_get_name(output), mpd_output_get_enabled(output)));
|
|
||||||
mpd_output_free(output);
|
|
||||||
}
|
|
||||||
mpd_response_finish(m_connection.get());
|
|
||||||
checkErrors();
|
checkErrors();
|
||||||
|
return OutputIterator(m_connection, mpd_recv_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::EnableOutput(int id)
|
void Connection::EnableOutput(int id)
|
||||||
|
|||||||
146
src/mpdpp.h
146
src/mpdpp.h
@@ -131,50 +131,144 @@ struct Item
|
|||||||
|
|
||||||
struct Output
|
struct Output
|
||||||
{
|
{
|
||||||
Output(const std::string &name_, bool enabled) : m_name(name_), m_enabled(enabled) { }
|
Output() { }
|
||||||
|
Output(mpd_output *output) : m_output(output, mpd_output_free) { }
|
||||||
const std::string &name() const { return m_name; }
|
|
||||||
bool isEnabled() const { return m_enabled; }
|
Output(const Output &rhs) : m_output(rhs.m_output) { }
|
||||||
|
Output(Output &&rhs) : m_output(std::move(rhs.m_output)) { }
|
||||||
|
Output &operator=(Output rhs)
|
||||||
|
{
|
||||||
|
m_output = std::move(rhs.m_output);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Output &rhs) const
|
||||||
|
{
|
||||||
|
if (empty() && rhs.empty())
|
||||||
|
return true;
|
||||||
|
else if (!empty() && !rhs.empty())
|
||||||
|
return id() == rhs.id()
|
||||||
|
&& std::strcmp(name(), rhs.name()) == 0
|
||||||
|
&& enabled() == rhs.enabled();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool operator!=(const Output &rhs) const
|
||||||
|
{
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned id() const
|
||||||
|
{
|
||||||
|
checkNonEmpty();
|
||||||
|
return mpd_output_get_id(m_output.get());
|
||||||
|
}
|
||||||
|
const char *name() const
|
||||||
|
{
|
||||||
|
checkNonEmpty();
|
||||||
|
return mpd_output_get_name(m_output.get());
|
||||||
|
}
|
||||||
|
bool enabled() const
|
||||||
|
{
|
||||||
|
checkNonEmpty();
|
||||||
|
return mpd_output_get_enabled(m_output.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const { return m_output.get() == nullptr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_name;
|
void checkNonEmpty() const
|
||||||
bool m_enabled;
|
{
|
||||||
|
if (empty())
|
||||||
|
throw std::runtime_error("No associated mpd_output object");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<mpd_output> m_output;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Item> ItemList;
|
typedef std::vector<Item> ItemList;
|
||||||
typedef std::vector<std::string> StringList;
|
typedef std::vector<std::string> StringList;
|
||||||
typedef std::vector<Output> OutputList;
|
typedef std::vector<Output> OutputList;
|
||||||
|
|
||||||
struct SongIterator : std::iterator<std::forward_iterator_tag, Song>
|
template <typename DestT, typename SourceT>
|
||||||
|
struct Iterator : std::iterator<std::forward_iterator_tag, DestT>
|
||||||
{
|
{
|
||||||
|
typedef SourceT *(*SourceFetcher)(mpd_connection *);
|
||||||
|
|
||||||
friend class Connection;
|
friend class Connection;
|
||||||
|
|
||||||
SongIterator() : m_connection(nullptr) { }
|
Iterator() : m_connection(nullptr), m_fetch_source(nullptr) { }
|
||||||
~SongIterator();
|
~Iterator()
|
||||||
|
{
|
||||||
void finish();
|
if (m_connection)
|
||||||
|
finish();
|
||||||
Song &operator*() const;
|
|
||||||
Song *operator->() const;
|
|
||||||
|
|
||||||
SongIterator &operator++();
|
|
||||||
SongIterator operator++(int);
|
|
||||||
|
|
||||||
bool operator==(const SongIterator &rhs) {
|
|
||||||
return m_connection == rhs.m_connection
|
|
||||||
&& m_song == rhs.m_song;
|
|
||||||
}
|
}
|
||||||
bool operator!=(const SongIterator &rhs) {
|
|
||||||
|
void finish()
|
||||||
|
{
|
||||||
|
// clean up
|
||||||
|
assert(m_connection);
|
||||||
|
mpd_response_finish(m_connection.get());
|
||||||
|
m_object = DestT();
|
||||||
|
m_connection = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DestT &operator*() const
|
||||||
|
{
|
||||||
|
assert(m_connection);
|
||||||
|
if (m_object.empty())
|
||||||
|
throw std::runtime_error("empty object");
|
||||||
|
return const_cast<DestT &>(m_object);
|
||||||
|
}
|
||||||
|
DestT *operator->() const
|
||||||
|
{
|
||||||
|
return &**this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator &operator++()
|
||||||
|
{
|
||||||
|
assert(m_connection);
|
||||||
|
assert(m_fetch_source != nullptr);
|
||||||
|
auto src = m_fetch_source(m_connection.get());
|
||||||
|
if (src != nullptr)
|
||||||
|
m_object = DestT(src);
|
||||||
|
else
|
||||||
|
finish();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Iterator operator++(int)
|
||||||
|
{
|
||||||
|
Iterator it(*this);
|
||||||
|
++*this;
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Iterator &rhs)
|
||||||
|
{
|
||||||
|
return m_connection == rhs.m_connection
|
||||||
|
&& m_object == rhs.m_object;
|
||||||
|
}
|
||||||
|
bool operator!=(const Iterator &rhs)
|
||||||
|
{
|
||||||
return !(*this == rhs);
|
return !(*this == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SongIterator(std::shared_ptr<mpd_connection> conn);
|
Iterator(std::shared_ptr<mpd_connection> conn, SourceFetcher fetch_source)
|
||||||
|
: m_connection(std::move(conn)), m_fetch_source(fetch_source)
|
||||||
|
{
|
||||||
|
// get the first element
|
||||||
|
++*this;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<mpd_connection> m_connection;
|
std::shared_ptr<mpd_connection> m_connection;
|
||||||
Song m_song;
|
SourceFetcher m_fetch_source;
|
||||||
|
DestT m_object;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef Iterator<Song, mpd_song> SongIterator;
|
||||||
|
typedef Iterator<Output, mpd_output> OutputIterator;
|
||||||
|
|
||||||
class Connection : private boost::noncopyable
|
class Connection : private boost::noncopyable
|
||||||
{
|
{
|
||||||
typedef std::function<void(Item)> ItemConsumer;
|
typedef std::function<void(Item)> ItemConsumer;
|
||||||
@@ -276,7 +370,7 @@ public:
|
|||||||
SongIterator GetSongs(const std::string &directory);
|
SongIterator GetSongs(const std::string &directory);
|
||||||
void GetDirectories(const std::string &directory, StringConsumer f);
|
void GetDirectories(const std::string &directory, StringConsumer f);
|
||||||
|
|
||||||
void GetOutputs(OutputConsumer f);
|
OutputIterator GetOutputs();
|
||||||
void EnableOutput(int id);
|
void EnableOutput(int id);
|
||||||
void DisableOutput(int id);
|
void DisableOutput(int id);
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ std::wstring Outputs::title()
|
|||||||
|
|
||||||
void Outputs::enterPressed()
|
void Outputs::enterPressed()
|
||||||
{
|
{
|
||||||
if (w.current().value().isEnabled())
|
if (w.current().value().enabled())
|
||||||
{
|
{
|
||||||
Mpd.DisableOutput(w.choice());
|
Mpd.DisableOutput(w.choice());
|
||||||
Statusbar::printf("Output \"%s\" disabled", w.current().value().name());
|
Statusbar::printf("Output \"%s\" disabled", w.current().value().name());
|
||||||
@@ -99,9 +99,11 @@ void Outputs::mouseButtonPressed(MEVENT me)
|
|||||||
void Outputs::FetchList()
|
void Outputs::FetchList()
|
||||||
{
|
{
|
||||||
w.clear();
|
w.clear();
|
||||||
Mpd.GetOutputs([this](MPD::Output output) {
|
for (MPD::OutputIterator out = Mpd.GetOutputs(), end; out != end; ++out)
|
||||||
w.addItem(output, output.isEnabled());
|
{
|
||||||
});
|
bool enabled = out->enabled();
|
||||||
|
w.addItem(std::move(*out), enabled);
|
||||||
|
}
|
||||||
if (myScreen == this)
|
if (myScreen == this)
|
||||||
w.refresh();
|
w.refresh();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -458,12 +458,14 @@ void Visualizer::FindOutputID()
|
|||||||
m_output_id = -1;
|
m_output_id = -1;
|
||||||
if (!Config.visualizer_output_name.empty())
|
if (!Config.visualizer_output_name.empty())
|
||||||
{
|
{
|
||||||
size_t idx = 0;
|
for (MPD::OutputIterator out = Mpd.GetOutputs(), end; out != end; ++out)
|
||||||
Mpd.GetOutputs([this, &idx](MPD::Output output) {
|
{
|
||||||
if (output.name() == Config.visualizer_output_name)
|
if (out->name() == Config.visualizer_output_name)
|
||||||
m_output_id = idx;
|
{
|
||||||
++idx;
|
m_output_id = out->id();
|
||||||
});
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (m_output_id == -1)
|
if (m_output_id == -1)
|
||||||
Statusbar::printf("There is no output named \"%s\"", Config.visualizer_output_name);
|
Statusbar::printf("There is no output named \"%s\"", Config.visualizer_output_name);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user