A couple small but important fixes:

- Don't adjust scroll position in TrackListView after a requery if the
  query contents haven't actually changed
- Ensure resizing doesn't lose the selected item in ListWindow
- Added the concept of query hashes and generalized TrackListQueryBase
  so different types of queries can be supplied to a TrackListView.
This commit is contained in:
casey 2016-06-02 18:45:16 -07:00
parent 32965dd2af
commit 8b14ddb5e8
13 changed files with 95 additions and 27 deletions

View File

@ -75,7 +75,6 @@ namespace musik { namespace core { namespace audio {
BufferPtr GetEmptyBuffer(); BufferPtr GetEmptyBuffer();
void LoadDecoderPlugins(); void LoadDecoderPlugins();
private:
typedef std::list<BufferPtr> BufferList; typedef std::list<BufferPtr> BufferList;
typedef std::shared_ptr<IDecoderFactory> DecoderFactoryPtr; typedef std::shared_ptr<IDecoderFactory> DecoderFactoryPtr;
typedef std::vector<DecoderFactoryPtr> DecoderFactoryList; typedef std::vector<DecoderFactoryPtr> DecoderFactoryList;

View File

@ -17,7 +17,7 @@ using namespace musik::core::library::constants;
#define TRANSPORT_HEIGHT 2 #define TRANSPORT_HEIGHT 2
#endif #endif
#define DEFAULT_CATEGORY constants::Track::ALBUM_ID #define DEFAULT_CATEGORY constants::Track::ARTIST_ID
using namespace musik::core; using namespace musik::core;
using namespace musik::core::audio; using namespace musik::core::audio;

View File

@ -0,0 +1,24 @@
#pragma once
#include <core/library/query/QueryBase.h>
#include <core/db/Connection.h>
#include <core/library/track/Track.h>
#include "CategoryListViewQuery.h"
namespace musik {
namespace box {
class TrackListQueryBase : public musik::core::query::QueryBase {
public:
typedef std::shared_ptr<
std::vector<musik::core::TrackPtr> > Result;
typedef std::shared_ptr<std::set<size_t> > Headers;
virtual ~TrackListQueryBase() { };
virtual std::string Name() = 0;
virtual Result GetResult() = 0;
virtual Headers GetHeaders() = 0;
virtual size_t GetQueryHash() = 0;
};
}
}

View File

@ -21,6 +21,9 @@ TrackListViewQuery::TrackListViewQuery(LibraryPtr library, const std::string& co
this->id = id; this->id = id;
this->result.reset(new std::vector<TrackPtr>()); this->result.reset(new std::vector<TrackPtr>());
this->headers.reset(new std::set<size_t>()); this->headers.reset(new std::set<size_t>());
this->hash = 0;
this->GetQueryHash();
} }
TrackListViewQuery::~TrackListViewQuery() { TrackListViewQuery::~TrackListViewQuery() {
@ -35,13 +38,24 @@ TrackListViewQuery::Headers TrackListViewQuery::GetHeaders() {
return this->headers; return this->headers;
} }
size_t TrackListViewQuery::GetQueryHash() {
if (this->hash == 0) {
std::string parts = boost::str(
boost::format("%s-%s") % this->column % this->id);
this->hash = std::hash<std::string>()(parts);
}
return this->hash;
}
bool TrackListViewQuery::OnRun(Connection& db) { bool TrackListViewQuery::OnRun(Connection& db) {
if (result) { if (result) {
result.reset(new std::vector<TrackPtr>()); result.reset(new std::vector<TrackPtr>());
headers.reset(new std::set<size_t>()); headers.reset(new std::set<size_t>());
} }
std::string query = boost::str(boost::format( this->query = boost::str(boost::format(
"SELECT DISTINCT t.id, t.track, t.bpm, t.duration, t.filesize, t.year, t.title, t.filename, t.thumbnail_id, al.name AS album, gn.name AS genre, ar.name AS artist, t.filetime " \ "SELECT DISTINCT t.id, t.track, t.bpm, t.duration, t.filesize, t.year, t.title, t.filename, t.thumbnail_id, al.name AS album, gn.name AS genre, ar.name AS artist, t.filetime " \
"FROM tracks t, paths p, albums al, artists ar, genres gn " \ "FROM tracks t, paths p, albums al, artists ar, genres gn " \
"WHERE t.%s=? AND t.album_id=al.id AND t.visual_genre_id=gn.id AND t.visual_artist_id=ar.id " "WHERE t.%s=? AND t.album_id=al.id AND t.visual_genre_id=gn.id AND t.visual_artist_id=ar.id "
@ -50,7 +64,7 @@ bool TrackListViewQuery::OnRun(Connection& db) {
std::string lastAlbum; std::string lastAlbum;
size_t index = 0; size_t index = 0;
Statement trackQuery(query.c_str(), db); Statement trackQuery(this->query.c_str(), db);
trackQuery.BindInt(0, this->id); trackQuery.BindInt(0, this->id);
while (trackQuery.Step() == Row) { while (trackQuery.Step() == Row) {

View File

@ -3,38 +3,37 @@
#include <core/library/query/QueryBase.h> #include <core/library/query/QueryBase.h>
#include <core/db/Connection.h> #include <core/db/Connection.h>
#include <core/library/track/Track.h> #include <core/library/track/Track.h>
#include "CategoryListViewQuery.h"
#include "TrackListQueryBase.h"
namespace musik { namespace musik {
namespace box { namespace box {
class TrackListViewQuery : public musik::core::query::QueryBase { class TrackListViewQuery : public TrackListQueryBase {
public: public:
typedef std::shared_ptr<
std::vector<musik::core::TrackPtr> > Result;
typedef std::shared_ptr<std::set<size_t> > Headers;
TrackListViewQuery( TrackListViewQuery(
musik::core::LibraryPtr library, musik::core::LibraryPtr library,
const std::string& column, DBID id); const std::string& column,
DBID id);
virtual ~TrackListViewQuery(); virtual ~TrackListViewQuery();
std::string Name() { return "TrackListViewQuery"; } virtual std::string Name() { return "TrackListViewQuery"; }
virtual Result GetResult(); virtual Result GetResult();
virtual Headers GetHeaders(); virtual Headers GetHeaders();
virtual size_t GetQueryHash();
protected: protected:
virtual bool OnRun(musik::core::db::Connection &db); virtual bool OnRun(musik::core::db::Connection &db);
Result result;
Headers headers;
private: private:
musik::core::LibraryPtr library; musik::core::LibraryPtr library;
Result result;
Headers headers;
std::string column; std::string column;
DBID id; DBID id;
std::string query;
size_t hash;
}; };
} }
} }

View File

@ -140,16 +140,18 @@ void CommandWindow::Help() {
this->output->WriteLine(" <F1> console view", s); this->output->WriteLine(" <F1> console view", s);
this->output->WriteLine(" <F2> library view", s); this->output->WriteLine(" <F2> library view", s);
this->output->WriteLine("\n", s); this->output->WriteLine("\n", s);
this->output->WriteLine(" play <uri>: play audio at location", s); this->output->WriteLine(" addir <dir>: add a music directory", s);
this->output->WriteLine(" rmdir <dir>: remove a music directory", s);
this->output->WriteLine(" lsdirs: list scanned directories", s);
this->output->WriteLine(" rescan: rescan paths for new metadata", s);
this->output->WriteLine("\n", s);
this->output->WriteLine(" play <uri>: play audio at <uri>", s);
this->output->WriteLine(" pause: pause/resume", s); this->output->WriteLine(" pause: pause/resume", s);
this->output->WriteLine(" stop: stop all playback", s); this->output->WriteLine(" stop: stop and clean up everything", s);
this->output->WriteLine(" volume: <0 - 100>: set % volume", s); this->output->WriteLine(" volume: <0 - 100>: set % volume", s);
this->output->WriteLine(" clear: clear the log window", s); this->output->WriteLine(" clear: clear the log window", s);
this->output->WriteLine(" seek <seconds>: seek to <seconds> into track", s); this->output->WriteLine(" seek <seconds>: seek to <seconds> into track", s);
this->output->WriteLine(" addir <dir>: add a directory to be indexed", s); this->output->WriteLine("\n", s);
this->output->WriteLine(" rmdir <dir>: remove indexed directory path", s);
this->output->WriteLine(" lsdirs: list scanned directories", s);
this->output->WriteLine(" rescan: rescan paths for new metadata", s);
this->output->WriteLine(" plugins: list loaded plugins", s); this->output->WriteLine(" plugins: list loaded plugins", s);
this->output->WriteLine("\n <ctrl+d>: quit\n", s); this->output->WriteLine("\n <ctrl+d>: quit\n", s);
} }
@ -254,10 +256,9 @@ void CommandWindow::ListPlugins() const {
PluginList::iterator it = plugins.begin(); PluginList::iterator it = plugins.begin();
for (; it != plugins.end(); it++) { for (; it != plugins.end(); it++) {
std::string format = std::string format =
"plugin:\n" " " + std::string((*it)->Name()) + " "
" name: " + std::string((*it)->Name()) + " "
"v" + std::string((*it)->Version()) + "\n" "v" + std::string((*it)->Version()) + "\n"
" author: " + std::string((*it)->Author()) + "\n"; " by " + std::string((*it)->Author()) + "\n";
this->output->WriteLine(format, BOX_COLOR_RED_ON_BLUE); this->output->WriteLine(format, BOX_COLOR_RED_ON_BLUE);
} }

View File

@ -37,6 +37,7 @@ TrackListView::TrackListView(PlaybackService& playback, LibraryPtr library)
this->library->QueryCompleted.connect(this, &TrackListView::OnQueryCompleted); this->library->QueryCompleted.connect(this, &TrackListView::OnQueryCompleted);
this->playback.TrackChanged.connect(this, &TrackListView::OnTrackChanged); this->playback.TrackChanged.connect(this, &TrackListView::OnTrackChanged);
this->adapter = new Adapter(*this); this->adapter = new Adapter(*this);
this->lastQueryHash = 0;
} }
TrackListView::~TrackListView() { TrackListView::~TrackListView() {
@ -71,8 +72,16 @@ void TrackListView::ProcessMessage(IMessage &message) {
if (this->query && this->query->GetStatus() == IQuery::Finished) { if (this->query && this->query->GetStatus() == IQuery::Finished) {
this->metadata = this->query->GetResult(); this->metadata = this->query->GetResult();
this->headers = this->query->GetHeaders(); this->headers = this->query->GetHeaders();
this->query.reset();
/* if the query was functionally the same as the last query, don't
mess with the selected index */
if (this->lastQueryHash != query->GetQueryHash()) {
this->SetSelectedIndex(0); this->SetSelectedIndex(0);
}
this->lastQueryHash = this->query->GetQueryHash();
this->query.reset();
this->OnAdapterChanged(); this->OnAdapterChanged();
} }
} }

View File

@ -58,6 +58,8 @@ namespace musik {
PlaybackService& playback; PlaybackService& playback;
musik::core::TrackPtr playing; musik::core::TrackPtr playing;
musik::core::LibraryPtr library; musik::core::LibraryPtr library;
size_t lastQueryHash;
}; };
} }
} }

View File

@ -152,6 +152,15 @@ void ListWindow::OnAdapterChanged() {
this->Repaint(); this->Repaint();
} }
void ListWindow::OnSizeChanged() {
ScrollableWindow::OnSizeChanged();
this->GetScrollAdapter().DrawPage(
this->GetContent(),
this->selectedIndex,
&this->GetScrollPosition());
}
IScrollAdapter::ScrollPosition& ListWindow::GetScrollPosition() { IScrollAdapter::ScrollPosition& ListWindow::GetScrollPosition() {
return this->scrollPosition; return this->scrollPosition;
} }

View File

@ -30,6 +30,7 @@ namespace cursespp {
virtual void OnAdapterChanged(); virtual void OnAdapterChanged();
virtual void OnSelectionChanged(size_t newIndex, size_t oldIndex); virtual void OnSelectionChanged(size_t newIndex, size_t oldIndex);
virtual void OnInvalidated(); virtual void OnInvalidated();
virtual void OnSizeChanged();
virtual IScrollAdapter::ScrollPosition& GetScrollPosition(); virtual IScrollAdapter::ScrollPosition& GetScrollPosition();

View File

@ -29,7 +29,13 @@ ScrollableWindow::~ScrollableWindow() {
void ScrollableWindow::OnSizeChanged() { void ScrollableWindow::OnSizeChanged() {
Window::OnSizeChanged(); Window::OnSizeChanged();
GetScrollAdapter().SetDisplaySize(GetContentWidth(), GetContentHeight());
IScrollAdapter& adapter = this->GetScrollAdapter();
ScrollPos& pos = this->GetScrollPosition();
adapter.SetDisplaySize(
this->GetContentWidth(),
this->GetContentHeight());
} }
ScrollPos& ScrollableWindow::GetScrollPosition() { ScrollPos& ScrollableWindow::GetScrollPosition() {

View File

@ -156,6 +156,7 @@
<ClInclude Include="app\layout\LibraryLayout.h" /> <ClInclude Include="app\layout\LibraryLayout.h" />
<ClInclude Include="app\layout\MainLayout.h" /> <ClInclude Include="app\layout\MainLayout.h" />
<ClInclude Include="app\query\CategoryListViewQuery.h" /> <ClInclude Include="app\query\CategoryListViewQuery.h" />
<ClInclude Include="app\query\TrackListQueryBase.h" />
<ClInclude Include="app\query\SingleTrackQuery.h" /> <ClInclude Include="app\query\SingleTrackQuery.h" />
<ClInclude Include="app\query\TrackListViewQuery.h" /> <ClInclude Include="app\query\TrackListViewQuery.h" />
<ClInclude Include="app\service\PlaybackService.h" /> <ClInclude Include="app\service\PlaybackService.h" />

View File

@ -231,6 +231,9 @@
<ClInclude Include="app\window\EntryWithHeader.h"> <ClInclude Include="app\window\EntryWithHeader.h">
<Filter>app\window</Filter> <Filter>app\window</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="app\query\TrackListQueryBase.h">
<Filter>app\query</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="cursespp"> <Filter Include="cursespp">