- Killed a bunch of really unnecessary, complicated path management

logic in the Indexer.
- Created a new IKeyHandler for windows that want to receive keyboard
  events but aren't necessarily input fields.
- Added some hacked up code to get playback working in the
  TrackListView. This functionality will be extracted to LibraryLayout
  in the near future.
This commit is contained in:
casey 2016-05-16 22:00:45 -07:00
parent 1c13ac278d
commit fc86bacaaf
19 changed files with 151 additions and 267 deletions

View File

@ -215,7 +215,7 @@ void Indexer::SynchronizeInternal() {
for(std::size_t i = 0; i < paths.size(); ++i) {
std::string path = paths[i];
this->SyncDirectory(path, path ,0, pathIds[i]);
this->SyncDirectory(path, path, pathIds[i]);
}
/* remove undesired entries from db (files themselves will remain) */
@ -228,7 +228,7 @@ void Indexer::SynchronizeInternal() {
}
if (!this->Restarted() && !this->Exited()) {
this->SyncDelete(pathIds);
this->SyncDelete();
}
/* cleanup -- remove stale artists, albums, genres, etc */
@ -270,26 +270,9 @@ void Indexer::SynchronizeInternal() {
musik::debug::info(TAG, "done!");
}
//////////////////////////////////////////
///\brief
///Reads all tracks in a folder
///
///\param dir
///Folder to check files in
///
///\param parentDirId
///Database ID of the parent folder (folders table)
///
///\param pathId
///Database ID of the current path (paths table)
///
///Read all tracks in a folder. All folders in that folder is recursively called.
//////////////////////////////////////////
void Indexer::SyncDirectory(
const std::string &syncRoot,
const std::string &currentPath,
DBID parentDirId,
DBID pathId)
{
if (this->Exited() || this->Restarted()) {
@ -300,39 +283,6 @@ void Indexer::SyncDirectory(
std::string normalizedCurrentPath = normalizeDir(currentPath);
std::string leaf = boost::filesystem::path(currentPath).leaf().string(); /* trailing subdir in currentPath */
DBID dirId = 0;
/* get relative folder id */
{
db::CachedStatement stmt("SELECT id FROM folders WHERE name=? AND path_id=? AND parent_id=?", this->dbConnection);
stmt.BindText(0, leaf);
stmt.BindInt(1, pathId);
stmt.BindInt(2, parentDirId);
if (stmt.Step() == db::Row) {
dirId = stmt.ColumnInt(0);
}
}
/* no ID yet? needs to be inserted... */
if (dirId == 0) {
std::string relativePath(normalizedCurrentPath.substr(normalizedSyncRoot.size()));
db::CachedStatement stmt("INSERT INTO folders (name, path_id, parent_id, relative_path) VALUES(?,?,?,?)", this->dbConnection);
stmt.BindText(0, leaf);
stmt.BindInt(1, pathId);
stmt.BindInt(2, parentDirId);
stmt.BindText(3, relativePath);
if (stmt.Step() != db::Done) {
return; /* ugh, failed? */
}
dirId = this->dbConnection.LastInsertedId();
}
/* start recursive filesystem scan */
try { /* boost::filesystem may throw */
@ -343,11 +293,13 @@ void Indexer::SyncDirectory(
boost::filesystem::directory_iterator end;
boost::filesystem::directory_iterator file(path);
std::string pathIdStr = boost::lexical_cast<std::string>(pathId);
for( ; file != end && !this->Exited() && !this->Restarted(); file++) {
if (is_directory(file->status())) {
/* recursion here */
musik::debug::info(TAG, "scanning " + file->path().string());
this->SyncDirectory(syncRoot, file->path().string(), dirId, pathId);
this->SyncDirectory(syncRoot, file->path().string(), pathId);
}
else {
++this->filesIndexed;
@ -355,7 +307,7 @@ void Indexer::SyncDirectory(
musik::core::IndexerTrack track(0);
/* get cached filesize, parts, size, etc */
if (track.NeedsToBeIndexed(file->path(), this->dbConnection, dirId)) {
if (track.NeedsToBeIndexed(file->path(), this->dbConnection)) {
bool saveToDb = false;
/* read the tag from the plugin */
@ -373,7 +325,8 @@ void Indexer::SyncDirectory(
/* write it to the db, if read successfully */
if (saveToDb) {
track.Save(this->dbConnection, this->libraryPath, dirId);
track.SetValue("path_id", pathIdStr.c_str());
track.Save(this->dbConnection, this->libraryPath);
this->filesSaved++;
if (this->filesSaved % 100 == 0) {
@ -443,133 +396,38 @@ void Indexer::ThreadLoop() {
}
}
//////////////////////////////////////////
///\brief
///Part of the synchronizer to delete removed files.
///
///\param paths
///Vector of path-id to check for deletion
///
///This method will first check for removed folders and automaticaly
///delete all tracks in the removed folders.
///Secondly it will check all files it they are removed.
///
///\remarks
///This method will not delete related information (meta-data, albums, etc)
//////////////////////////////////////////
void Indexer::SyncDelete(const std::vector<DBID>& paths) {
/* delete pruned paths from path table */
this->dbConnection.Execute("DELETE FROM folders WHERE path_id NOT IN (SELECT id FROM paths)");
void Indexer::SyncDelete() {
/* remove all tracks that no longer reference a valid path entry */
db::Statement stmtSyncPath("SELECT p.path FROM paths p WHERE p.id=?", this->dbConnection);
this->dbConnection.Execute("DELETE FROM tracks WHERE path_id NOT IN (SELECT id FROM paths)");
{
db::Statement stmt(
"SELECT f.id, p.path || f.relative_path "
"FROM folders f, paths p "
"WHERE f.path_id=p.id AND p.id=?", this->dbConnection);
db::Statement stmtRemove("DELETE FROM folders WHERE id=?",this->dbConnection);
for (std::size_t i = 0; i < paths.size(); ++i) {
stmt.BindInt(0, paths[i]);
stmtSyncPath.BindInt(0, paths[i]);
stmtSyncPath.Step();
std::string syncPathString(stmtSyncPath.ColumnText(0));
stmtSyncPath.Reset();
while (stmt.Step() == db::Row && !this->Exited() && !this->Restarted()) {
bool remove = true;
std::string dir = stmt.ColumnText(1);
try {
boost::filesystem::path path(dir);
if (boost::filesystem::exists(path)) {
remove = false;
}
else {
boost::filesystem::path syncPath(syncPathString);
if (!boost::filesystem::exists(syncPath)) {
remove = false;
}
}
}
catch (...){
remove = false;
}
if (remove) {
stmtRemove.BindInt(0, stmt.ColumnInt(0));
stmtRemove.Step();
stmtRemove.Reset();
}
}
stmt.Reset();
}
}
/* we deleted folders above. remove all tracks that were in those dirs*/
this->dbConnection.Execute("DELETE FROM tracks WHERE folder_id NOT IN (SELECT id FROM folders)");
// Remove tracks
db::Statement stmtCount("SELECT count(*) FROM tracks", this->dbConnection);
DBID songs = 0, count = 0;
if (stmtCount.Step() == db::Row) {
songs = stmtCount.ColumnInt(0);
}
db::Statement stmt(
"SELECT t.id, p.path || f.relative_path || '/' || t.filename "
"FROM tracks t, folders f, paths p "
"WHERE t.folder_id=f.id AND f.path_id=p.id AND p.id=?", this->dbConnection);
/* remove files that are no longer on the filesystem. */
db::Statement stmtRemove("DELETE FROM tracks WHERE id=?", this->dbConnection);
for (std::size_t i = 0; i < paths.size(); ++i) {
stmt.BindInt(0, paths[i]);
db::Statement allTracks(
"SELECT t.id, t.filename "
"FROM tracks t "
"WHERE p.id=?", this->dbConnection);
stmtSyncPath.BindInt(0,paths[i]);
stmtSyncPath.Step();
std::string syncPathString = stmtSyncPath.ColumnText(0);
while(allTracks.Step() == db::Row && !this->Exited() && !this->Restarted()) {
bool remove = false;
std::string file = allTracks.ColumnText(1);
stmtSyncPath.Reset();
while(stmt.Step() == db::Row && !this->Exited() && !this->Restarted()) {
bool remove = true;
std::string file = stmt.ColumnText(1);
try{
boost::filesystem::path file(file);
if (boost::filesystem::exists(file)) {
remove = false;
}
else {
boost::filesystem::path syncPath(syncPathString);
if (!boost::filesystem::exists(syncPath)) {
remove = false;
}
}
try {
boost::filesystem::path file(file);
if (!boost::filesystem::exists(file)) {
remove = true;
}
catch(...) {
remove = false;
}
if (remove) {
stmtRemove.BindInt(0, stmt.ColumnInt(0));
stmtRemove.Step();
stmtRemove.Reset();
}
++count;
}
stmt.Reset();
catch(...) {
}
if (remove) {
stmtRemove.BindInt(0, allTracks.ColumnInt(0));
stmtRemove.Step();
stmtRemove.Reset();
}
}
}
@ -694,8 +552,7 @@ void Indexer::SyncOptimize() {
db::Statement outer("SELECT t.id FROM tracks t " \
"LEFT OUTER JOIN artists ar ON ar.id=t.visual_artist_id " \
"LEFT OUTER JOIN albums al ON al.id=t.album_id " \
"LEFT OUTER JOIN folders f ON f.id=t.folder_id " \
"ORDER BY ar.sort_order, al.sort_order, t.track, f.relative_path, t.filename",
"ORDER BY ar.sort_order, al.sort_order, t.track, t.filename",
this->dbConnection);
db::Statement inner("UPDATE tracks SET sort_order1=? WHERE id=?",this->dbConnection);
@ -745,8 +602,6 @@ void Indexer::ProcessAddRemoveQueue() {
this->addRemoveQueue.pop_front();
}
this->dbConnection.Execute("DELETE FROM folders WHERE path_id NOT IN (SELECT id FROM paths)");
this->PathsUpdated();
}
@ -775,17 +630,15 @@ void Indexer::RunAnalyzers() {
/* for each track... */
DBID trackId = 0;
DBID folderId = 0;
db::Statement getNextTrack(
"SELECT id, folder_id FROM tracks WHERE id>? ORDER BY id LIMIT 1",
"SELECT id FROM tracks WHERE id>? ORDER BY id LIMIT 1",
this->dbConnection);
getNextTrack.BindInt(0, trackId);
while(getNextTrack.Step() == db::Row ) {
trackId = getNextTrack.ColumnInt(0);
folderId = getNextTrack.ColumnInt(1);
getNextTrack.Reset();
getNextTrack.UnBindAll();
@ -838,7 +691,7 @@ void Indexer::RunAnalyzers() {
completed successfully, then save the track. */
if(successPlugins>0) {
track.Save(this->dbConnection, this->libraryPath,folderId);
track.Save(this->dbConnection, this->libraryPath);
}
}
}

View File

@ -76,7 +76,7 @@ namespace musik { namespace core {
bool Restarted();
void SyncDelete(const std::vector<DBID>& paths);
void SyncDelete();
void SyncCleanup();
void ProcessAddRemoveQueue();
void SyncOptimize();
@ -87,7 +87,6 @@ namespace musik { namespace core {
void SyncDirectory(
const std::string& syncRoot,
const std::string& currentPath,
DBID parentDirId,
DBID pathId);
db::Connection dbConnection;

View File

@ -234,7 +234,6 @@ bool LocalLibrary::IsSpecialMTOMetaKey(std::string &metakey){
specialMTOMetaKeys.insert("album");
specialMTOMetaKeys.insert("visual_genre");
specialMTOMetaKeys.insert("visual_artist");
specialMTOMetaKeys.insert("folder");
}
return specialMTOMetaKeys.find(metakey)!=specialMTOMetaKeys.end();
@ -272,8 +271,8 @@ void LocalLibrary::CreateDatabase(db::Connection &db){
"year INTEGER DEFAULT 0,"
"visual_genre_id INTEGER DEFAULT 0,"
"visual_artist_id INTEGER DEFAULT 0,"
"path_id INTEGER,"
"album_id INTEGER DEFAULT 0,"
"folder_id INTEGER DEFAULT 0,"
"title TEXT default '',"
"filename TEXT default '',"
"filetime INTEGER DEFAULT 0,"
@ -333,16 +332,7 @@ void LocalLibrary::CreateDatabase(db::Connection &db){
"path TEXT default ''"
")");
// Create the folders-table
db.Execute("CREATE TABLE IF NOT EXISTS folders ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"name TEXT default '',"
"relative_path TEXT default '',"
"parent_id INTEGER DEFAULT 0,"
"path_id INTEGER DEFAULT 0"
")");
// Create the folders-table
// Create the thumbnails table
db.Execute("CREATE TABLE IF NOT EXISTS thumbnails ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"filename TEXT default '',"
@ -350,13 +340,14 @@ void LocalLibrary::CreateDatabase(db::Connection &db){
"checksum INTEGER DEFAULT 0"
")");
// Create the playlists-table
// Create the playlists
db.Execute("CREATE TABLE IF NOT EXISTS playlists ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"name TEXT default '',"
"user_id INTEGER default 0"
")");
// Create the playlists-table
// Create the playlist_tracks table
db.Execute("CREATE TABLE IF NOT EXISTS playlist_tracks ("
"track_id INTEGER DEFAULT 0,"
"playlist_id INTEGER DEFAULT 0,"
@ -365,13 +356,11 @@ void LocalLibrary::CreateDatabase(db::Connection &db){
// INDEXES
db.Execute("CREATE UNIQUE INDEX IF NOT EXISTS users_index ON users (login)");
db.Execute("CREATE UNIQUE INDEX IF NOT EXISTS folders_index ON folders (name,parent_id,path_id)");
db.Execute("CREATE UNIQUE INDEX IF NOT EXISTS paths_index ON paths (path)");
db.Execute("CREATE INDEX IF NOT EXISTS genre_index ON genres (sort_order)");
db.Execute("CREATE INDEX IF NOT EXISTS artist_index ON artists (sort_order)");
db.Execute("CREATE INDEX IF NOT EXISTS album_index ON albums (sort_order)");
db.Execute("CREATE INDEX IF NOT EXISTS track_index1 ON tracks (album_id,sort_order1)");
db.Execute("CREATE INDEX IF NOT EXISTS track_index7 ON tracks (folder_id)");
db.Execute("CREATE INDEX IF NOT EXISTS thumbnail_index ON thumbnails (filesize)");
db.Execute("CREATE INDEX IF NOT EXISTS trackgenre_index1 ON track_genres (track_id,genre_id)");

View File

@ -49,13 +49,13 @@ namespace musik { namespace core { namespace library { namespace constants {
static const char* DISPLAY_GENRE_ID = "visual_genre_id";
static const char* DISPLAY_ARTIST_ID = "visual_artist_id";
static const char* ALBUM_ID = "album_id";
static const char* RELATIVE_PATH_ID = "folder_id";
static const char* PATH_ID = "path_id";
static const char* TITLE = "title";
static const char* FILENAME = "filename";
static const char* FILETIME = "filetime";
static const char* THUMBNAIL_ID = "thumbnail_id";
static const char* SORT_ORDER = "sort_order1";
static const char* PATH = "path"; /* not in DB; synthesized */
static const char* PATH = "path";
}
namespace Genres {
@ -123,15 +123,6 @@ namespace musik { namespace core { namespace library { namespace constants {
static const char* PATH = "path";
}
namespace RelativePaths {
static const char* TABLE_NAME = "folders";
static const char* ID = "id";
static const char* NAME = "name";
static const char* RELATIVE_PATH = "relative_path";
static const char* PARENT_ID = "parent_id";
static const char* PATH_ID = "path_id";
}
namespace Thumbnails {
static const char* TABLE_NAME = "thumbnails";
static const char* ID = "id";

View File

@ -137,12 +137,11 @@ DBID IndexerTrack::Id() {
bool IndexerTrack::NeedsToBeIndexed(
const boost::filesystem::path &file,
db::Connection &dbConnection,
DBID currentFolderId)
db::Connection &dbConnection)
{
try {
this->SetValue("path", file.string().c_str());
this->SetValue("filename", file.leaf().string().c_str());
this->SetValue("filename", file.string().c_str());
size_t lastDot = file.leaf().string().find_last_of(".");
if (lastDot != std::string::npos){
@ -158,10 +157,9 @@ bool IndexerTrack::NeedsToBeIndexed(
db::CachedStatement stmt(
"SELECT id, filename, filesize, filetime " \
"FROM tracks t " \
"WHERE folder_id=? AND filename=?", dbConnection);
"WHERE filename=?", dbConnection);
stmt.BindInt(0, currentFolderId);
stmt.BindText(1, this->GetValue("filename"));
stmt.BindText(0, this->GetValue("filename"));
bool fileDifferent = true;
@ -184,11 +182,10 @@ bool IndexerTrack::NeedsToBeIndexed(
static DBID writeToTracksTable(
db::Connection &dbConnection,
IndexerTrack& track,
DBID folderId,
DBID tempSortOrder)
{
db::CachedStatement stmt("INSERT OR REPLACE INTO tracks " \
"(id, track, bpm, duration, filesize, year, folder_id, title, filename, filetime, sort_order1) " \
"(id, track, bpm, duration, filesize, year, title, filename, filetime, path_id, sort_order1) " \
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", dbConnection);
stmt.BindText(1, track.GetValue("track"));
@ -196,10 +193,10 @@ static DBID writeToTracksTable(
stmt.BindText(3, track.GetValue("duration"));
stmt.BindText(4, track.GetValue("filesize"));
stmt.BindText(5, track.GetValue("year"));
stmt.BindInt(6, folderId);
stmt.BindText(7, track.GetValue("title"));
stmt.BindText(8, track.GetValue("filename"));
stmt.BindText(9, track.GetValue("filetime"));
stmt.BindText(6, track.GetValue("title"));
stmt.BindText(7, track.GetValue("filename"));
stmt.BindText(8, track.GetValue("filetime"));
stmt.BindText(9, track.GetValue("path_id"));
stmt.BindInt(10, tempSortOrder);
if (track.Id() != 0) {
@ -448,7 +445,7 @@ DBID IndexerTrack::ExtractArtist(db::Connection& dbConnection) {
ARTIST_TRACK_FOREIGN_KEY);
}
bool IndexerTrack::Save(db::Connection &dbConnection, std::string libraryDirectory, DBID folderId) {
bool IndexerTrack::Save(db::Connection &dbConnection, std::string libraryDirectory) {
db::ScopedTransaction transaction(dbConnection);
/* remove existing relations -- we're going to update them with fresh data */
@ -461,7 +458,7 @@ bool IndexerTrack::Save(db::Connection &dbConnection, std::string libraryDirecto
/* write generic info to the tracks table */
this->id = writeToTracksTable(dbConnection, *this, folderId, tempSortOrder);
this->id = writeToTracksTable(dbConnection, *this, tempSortOrder);
DBID albumId = this->ExtractAlbum(dbConnection);
DBID genreId = this->ExtractGenre(dbConnection);
@ -567,9 +564,9 @@ bool IndexerTrack::Reload(db::Connection &db) {
"ORDER BY tm.id", db);
db::Statement track(
"SELECT t.track, t.bpm, t.duration, t.filesize, t.year, t.title, t.filename, t.thumbnail_id, p.path|| f.relative_path || '/' || t.filename, al.name, t.filetime, t.sort_order1 " \
"FROM tracks t, folders f, paths p, albums al " \
"WHERE t.id=? AND t.folder_id=f.id AND f.path_id=p.id AND t.album_id=al.id", db);
"SELECT t.track, t.bpm, t.duration, t.filesize, t.year, t.title, t.filename, t.thumbnail_id, al.name, t.filetime, t.sort_order1 " \
"FROM tracks t, paths p, albums al " \
"WHERE t.id=? AND t.album_id=al.id", db);
track.BindInt(0, this->id);
if(track.Step() == db::Row) {
@ -581,10 +578,9 @@ bool IndexerTrack::Reload(db::Connection &db) {
this->SetValue("title", track.ColumnText(5));
this->SetValue("filename", track.ColumnText(6));
this->SetValue("thumbnail_id", track.ColumnText(7));
this->SetValue("path", track.ColumnText(8));
this->SetValue("album", track.ColumnText(9));
this->SetValue("filetime", track.ColumnText(10));
this->tempSortOrder = track.ColumnInt(11);
this->SetValue("album", track.ColumnText(8));
this->SetValue("filetime", track.ColumnText(9));
this->tempSortOrder = track.ColumnInt(10);
genres.BindInt(0, this->id);
while (genres.Step() == db::Row) {
@ -592,7 +588,7 @@ bool IndexerTrack::Reload(db::Connection &db) {
}
artists.BindInt(0, this->id);
while (artists.Step()==db::Row) {
while (artists.Step() == db::Row) {
this->SetValue("artist", artists.ColumnText(0));
}

View File

@ -66,13 +66,11 @@ namespace musik { namespace core {
bool NeedsToBeIndexed(
const boost::filesystem::path &file,
db::Connection &dbConnection,
DBID currentFolderId);
db::Connection &dbConnection);
bool Save(
db::Connection &dbConnection,
std::string libraryDirectory,
DBID folderId);
std::string libraryDirectory);
bool Reload(db::Connection &db);

View File

@ -197,5 +197,4 @@ LibraryTrack::MetaData::MetaData()
LibraryTrack::MetaData::~MetaData() {
delete this->thumbnailData;
}
}

View File

@ -39,6 +39,7 @@
#include <core/config.h>
#include <core/library/track/Track.h>
#include <core/library/LocalLibrary.h>
#include <core/db/Connection.h>
namespace musik { namespace core { namespace http {
class Responder;
@ -63,9 +64,9 @@ namespace musik { namespace core {
virtual DBID Id();
virtual std::string GetValue(const char* metakey);
virtual void SetValue(const char* metakey,const char* value);
virtual void SetValue(const char* metakey, const char* value);
virtual void ClearValue(const char* metakey);
virtual void SetThumbnail(const char *data,long size);
virtual void SetThumbnail(const char *data, long size);
virtual std::string URI();
virtual std::string URL();

8
src/musikbox/IKeyHandler.h Executable file
View File

@ -0,0 +1,8 @@
#pragma once
#include "stdafx.h"
class IKeyHandler {
public:
virtual void KeyPress(int64 ch) = 0;
};

View File

@ -1,7 +1,6 @@
#pragma once
#include "stdafx.h"
#include <boost/shared_ptr.hpp>
class IScrollAdapter {
public:

View File

@ -3,8 +3,11 @@
#include "Screen.h"
#include "LibraryLayout.h"
LibraryLayout::LibraryLayout(LibraryPtr library)
#define CATEGORY_WIDTH 25
LibraryLayout::LibraryLayout(Transport& transport, LibraryPtr library)
: LayoutBase() {
this->transport = &transport;
this->library = library;
this->InitializeWindows();
}
@ -18,17 +21,17 @@ void LibraryLayout::Layout() {
this->SetPosition(0, 0);
this->albumList->SetPosition(0, 0);
this->albumList->SetSize(20, this->GetHeight());
this->albumList->SetSize(CATEGORY_WIDTH, this->GetHeight());
this->albumList->SetFocusOrder(0);
this->trackList->SetPosition(20, 0);
this->trackList->SetSize(this->GetWidth() - 20, this->GetHeight());
this->trackList->SetPosition(CATEGORY_WIDTH, 0);
this->trackList->SetSize(this->GetWidth() - CATEGORY_WIDTH, this->GetHeight());
this->trackList->SetFocusOrder(1);
}
void LibraryLayout::InitializeWindows() {
this->albumList.reset(new CategoryListView(library));
this->trackList.reset(new TrackListView(library));
this->albumList.reset(new CategoryListView(this->library));
this->trackList.reset(new TrackListView(*this->transport, this->library));
this->AddWindow(this->albumList);
this->AddWindow(this->trackList);

View File

@ -4,15 +4,17 @@
#include "CategoryListView.h"
#include "TrackListView.h"
#include <core/playback/Transport.h>
#include <core/library/ILibrary.h>
#include <sigslot/sigslot.h>
using musik::core::LibraryPtr;
using musik::core::audio::Transport;
class LibraryLayout : public LayoutBase, public sigslot::has_slots<> {
public:
LibraryLayout(LibraryPtr library);
LibraryLayout(Transport& transport, LibraryPtr library);
virtual ~LibraryLayout();
virtual void Layout();
@ -24,6 +26,7 @@ class LibraryLayout : public LayoutBase, public sigslot::has_slots<> {
void OnCategoryViewSelectionChanged(
ListWindow *view, size_t newIndex, size_t oldIndex);
Transport* transport;
LibraryPtr library;
std::shared_ptr<CategoryListView> albumList;
std::shared_ptr<TrackListView> trackList;

View File

@ -42,6 +42,7 @@
#include "MainLayout.h"
#include "LibraryLayout.h"
#include "IInput.h"
#include "IKeyHandler.h"
#include "WindowMessageQueue.h"
#include <boost/locale.hpp>
@ -60,6 +61,7 @@ struct WindowState {
ILayout* layout;
IWindow* focused;
IInput* input;
IKeyHandler* keyHandler;
IScrollable* scrollable;
};
@ -85,6 +87,7 @@ void changeLayout(WindowState& current, ILayout* newLayout) {
current.focused = current.layout->GetFocus();
current.input = dynamic_cast<IInput*>(current.focused);
current.scrollable = dynamic_cast<IScrollable*>(current.focused);
current.keyHandler = dynamic_cast<IKeyHandler*>(current.focused);
}
if (current.input) {
@ -102,8 +105,9 @@ void focusNextInLayout(WindowState& current) {
}
current.focused = current.layout->FocusNext();
current.scrollable = dynamic_cast<IScrollable*>(current.focused);
current.input = dynamic_cast<IInput*>(current.focused);
current.scrollable = dynamic_cast<IScrollable*>(current.focused);
current.keyHandler = dynamic_cast<IKeyHandler*>(current.focused);
if (current.input != NULL) {
curs_set(1);
@ -164,7 +168,7 @@ int main(int argc, char* argv[])
LibraryPtr library = LibraryFactory::Libraries().at(0);
MainLayout mainLayout(tp, library);
LibraryLayout libraryLayout(library);
LibraryLayout libraryLayout(tp, library);
mainLayout.Hide();
libraryLayout.Hide();
@ -234,6 +238,9 @@ int main(int argc, char* argv[])
else if (state.input) {
state.input->WriteChar(ch);
}
else if (state.keyHandler) {
state.keyHandler->KeyPress(ch);
}
Window::WriteToScreen();
WindowMessageQueue::Instance().Dispatch();

View File

@ -6,17 +6,23 @@
#include "TrackListView.h"
#include "IWindowMessage.h"
#include <core/library/LocalLibraryConstants.h>
#include <boost/format.hpp>
#include <boost/format/group.hpp>
#include <iomanip>
#define WINDOW_MESSAGE_QUERY_COMPLETED 1002
using musik::core::IQuery;
using musik::core::audio::Transport;
using namespace musik::core::library::constants;
TrackListView::TrackListView(LibraryPtr library, IWindow *parent)
TrackListView::TrackListView(Transport& transport, LibraryPtr library, IWindow *parent)
: ListWindow(parent) {
this->SetContentColor(BOX_COLOR_WHITE_ON_BLACK);
this->transport = &transport;
this->library = library;
this->library->QueryCompleted.connect(this, &TrackListView::OnQueryCompleted);
this->adapter = new Adapter(*this);
@ -37,6 +43,18 @@ void TrackListView::OnQueryCompleted(QueryPtr query) {
}
}
void TrackListView::KeyPress(int64 ch) {
if (ch == 10) { /* return */
size_t selected = this->GetSelectedIndex();
if (this->metadata->size() > selected) {
TrackPtr track = this->metadata->at(selected);
std::string fn = track->GetValue(Track::FILENAME);
this->transport->Stop();
this->transport->Start(fn);
}
}
}
void TrackListView::ProcessMessage(IWindowMessage &message) {
if (message.MessageType() == WINDOW_MESSAGE_QUERY_COMPLETED) {
if (this->query && this->query->GetStatus() == IQuery::Finished) {

View File

@ -5,18 +5,23 @@
#include "ListWindow.h"
#include "TrackListViewQuery.h"
#include "ScrollAdapterBase.h"
#include "IKeyHandler.h"
#include <core/playback/Transport.h>
#include <core/library/ILibrary.h>
using musik::core::QueryPtr;
using musik::core::LibraryPtr;
using musik::core::audio::Transport;
class TrackListView : public ListWindow, public sigslot::has_slots<> {
class TrackListView : public ListWindow, public IKeyHandler, public sigslot::has_slots<> {
public:
TrackListView(LibraryPtr library, IWindow *parent = NULL);
TrackListView(Transport& transport, LibraryPtr library, IWindow *parent = NULL);
~TrackListView();
virtual void ProcessMessage(IWindowMessage &message);
virtual void KeyPress(int64 ch);
void Requery(const std::string& column, DBID id);
protected:
@ -39,5 +44,6 @@ class TrackListView : public ListWindow, public sigslot::has_slots<> {
std::shared_ptr<TrackListViewQuery> query;
std::shared_ptr<std::vector<TrackPtr>> metadata;
Adapter* adapter;
Transport* transport;
LibraryPtr library;
};

View File

@ -4,12 +4,14 @@
#include "TrackListViewQuery.h"
#include <core/library/track/LibraryTrack.h>
#include <core/library/LocalLibraryConstants.h>
#include <core/db/Statement.h>
using musik::core::db::Statement;
using musik::core::db::Row;
using musik::core::TrackPtr;
using musik::core::LibraryTrack;
using namespace musik::core::library::constants;
TrackListViewQuery::TrackListViewQuery(LibraryPtr library, const std::string& column, DBID id) {
this->library = library;
@ -31,21 +33,30 @@ bool TrackListViewQuery::OnRun(Connection& db) {
result.reset(new std::vector<TrackPtr>());
}
std::string query = boost::str(
boost::format(
"SELECT DISTINCT tracks.id, tracks.track, tracks.title "
"FROM tracks "
"WHERE %1%=? "
"ORDER BY tracks.track;") % this->column);
std::string query = boost::str(boost::format(
"SELECT DISTINCT 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, t.sort_order1 " \
"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") % this->column);
Statement trackQuery(query.c_str(), db);
Statement stmt(query.c_str(), db);
stmt.BindInt(0, this->id);
trackQuery.BindInt(0, this->id);
while (trackQuery.Step() == Row) {
TrackPtr track = TrackPtr(new LibraryTrack(this->id, this->library));
track->SetValue(Track::TRACK_NUM, trackQuery.ColumnText(0));
track->SetValue(Track::BPM, trackQuery.ColumnText(1));
track->SetValue(Track::DURATION, trackQuery.ColumnText(2));
track->SetValue(Track::FILESIZE, trackQuery.ColumnText(3));
track->SetValue(Track::YEAR, trackQuery.ColumnText(4));
track->SetValue(Track::TITLE, trackQuery.ColumnText(5));
track->SetValue(Track::FILENAME, trackQuery.ColumnText(6));
track->SetValue(Track::THUMBNAIL_ID, trackQuery.ColumnText(7));
track->SetValue(Track::ALBUM_ID, trackQuery.ColumnText(8));
track->SetValue(Track::DISPLAY_GENRE_ID, trackQuery.ColumnText(9));
track->SetValue(Track::DISPLAY_ARTIST_ID, trackQuery.ColumnText(10));
track->SetValue(Track::FILETIME, trackQuery.ColumnText(11));
while (stmt.Step() == Row) {
DBID id = stmt.ColumnInt64(0);
TrackPtr track = TrackPtr(new LibraryTrack(id, this->library));
track->SetValue("track", boost::lexical_cast<std::string>(stmt.ColumnInt(1)).c_str());
track->SetValue("title", stmt.ColumnText(2));
result->push_back(track);
}

View File

@ -16,7 +16,6 @@ class TrackListViewQuery : public QueryBase {
TrackListViewQuery(LibraryPtr library, const std::string& column, DBID id);
~TrackListViewQuery();
std::string Name() {
return "TrackListViewQuery";
}

View File

@ -151,6 +151,7 @@
<ClInclude Include="CategoryListViewQuery.h" />
<ClInclude Include="CategoryListView.h" />
<ClInclude Include="IDisplayable.h" />
<ClInclude Include="IKeyHandler.h" />
<ClInclude Include="IWindowGroup.h" />
<ClInclude Include="IWindowMessage.h" />
<ClInclude Include="LayoutBase.h" />

View File

@ -177,6 +177,9 @@
<ClInclude Include="Window.h">
<Filter>curses\window</Filter>
</ClInclude>
<ClInclude Include="IKeyHandler.h">
<Filter>curses</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="curses">