Commit 08f5d033 authored by Scott Wheeler's avatar Scott Wheeler

Ok, big cleanups essentially implimenting the stuff that has been in the

TODO for a while:

*) Ditch the PlaylistSplitter class mostly in favor of the PlaylistCollection
*) Move to a more linear class interaction path rather than having PlaylistSplitter
   as an ugly thing trying to mediate between a bunch of unrelated classes
*) Rely more heavily on the global action collection and try to instantiate actions
   in the classes that they're related to
*) Remove a few dozen dirty hacks
*) Got rid of about 250 lines of code in the process

There are still a couple of outstanding issues but since my home internet connection
has decided that it doesn't like me at the moment and people are waiting on these
changes for further work I'm committing.  Stuff that still needs to be done (I'll
likely finish this tonight and commit it at work tomorrow):

*) Create the Artist / Album / Genre playlists in the Tree View Mode.  This is
   essentially easy, it just requires sticking a new constructor in and making sure
   that it works.
*) Make it so that the HistoryPlaylist is properly instantiated and shown when its
   asked for
*) Make sure that the status bar is updated with the current playlist information
*) Create dynamic playlists on multiple select

While that sounds like quite a bit that's really just a little bit of work, but
managing such a huge patch set off-line is getting rather tedious and most stuff
works now.  I should have a patch for the rest tomorrow.

svn path=/trunk/kdemultimedia/juk/; revision=316735
parent ab47921f
......@@ -10,6 +10,7 @@ juk_SOURCES = \
directorylist.cpp \
directorylistbase.ui \
dynamicplaylist.cpp \
folderplaylist.cpp \
filehandle.cpp \
filerenamer.cpp \
filerenamerconfigdlg.cpp \
......@@ -23,9 +24,11 @@ juk_SOURCES = \
mediafiles.cpp \
musicbrainzitem.cpp \
musicbrainzquery.cpp \
painteater.cpp \
playermanager.cpp \
playlist.cpp \
playlistbox.cpp \
playlistcollection.cpp \
playlistitem.cpp \
playlistsearch.cpp \
playlistsplitter.cpp \
......
......@@ -16,6 +16,7 @@
***************************************************************************/
#include <kactioncollection.h>
#include <kdebug.h>
#include "actioncollection.h"
......@@ -30,6 +31,13 @@ namespace ActionCollection
KAction *action(const char *key)
{
#ifndef NO_DEBUG
KAction *a = actions()->action(key);
if(!a)
kdWarning(65432) << "KAction \"" << key << "\" is not defined yet." << endl;
return a;
#else
return actions()->action(key);
#endif
}
}
......@@ -26,8 +26,12 @@
#include "cache.h"
#include "tag.h"
#include "searchplaylist.h"
#include "historyplaylist.h"
Cache *Cache::m_cache = 0;
static const int playlistCacheVersion = 2;
enum PlaylistType { Normal = 0, Search = 1, History = 2 };
////////////////////////////////////////////////////////////////////////////////
// public methods
......@@ -36,8 +40,8 @@ Cache *Cache::m_cache = 0;
Cache *Cache::instance()
{
if(m_cache == 0) {
m_cache = new Cache;
m_cache->load();
m_cache = new Cache;
m_cache->load();
}
return m_cache;
}
......@@ -50,14 +54,14 @@ void Cache::save()
QFile f(cacheFileName);
if(!f.open(IO_WriteOnly))
return;
return;
QByteArray data;
QDataStream s(data, IO_WriteOnly);
for(Iterator it = begin(); it != end(); ++it) {
s << (*it).absFilePath();
s << *it;
s << (*it).absFilePath();
s << *it;
}
QDataStream fs(&f);
......@@ -73,6 +77,136 @@ void Cache::save()
QDir(dirName).rename("cache.new", "cache");
}
void Cache::loadPlaylists(PlaylistCollection *collection) // static
{
QString playlistsFile = KGlobal::dirs()->saveLocation("appdata") + "playlists";
QFile f(playlistsFile);
if(!f.open(IO_ReadOnly))
return;
QDataStream fs(&f);
Q_INT32 version;
fs >> version;
switch(version) {
case 1:
case 2:
{
// Our checksum is only for the values after the version and checksum so
// we want to get a byte array with just the checksummed data.
QByteArray data;
Q_UINT16 checksum;
fs >> checksum >> data;
if(checksum != qChecksum(data.data(), data.size()))
return;
// Create a new stream just based on the data.
QDataStream s(data, IO_ReadOnly);
while(!s.atEnd()) {
Q_INT32 playlistType;
s >> playlistType;
Playlist *playlist;
switch(playlistType) {
case Search:
{
SearchPlaylist *p = new SearchPlaylist(collection);
s >> *p;
playlist = p;
break;
}
case History:
{
// slotSetHistoryVisible(true);
HistoryPlaylist *p = new HistoryPlaylist(collection);
s >> *p;
playlist = p;
break;
}
default:
Playlist *p = new Playlist(collection, true);
s >> *p;
playlist = p;
break;
}
if(version == 2) {
Q_INT32 sortColumn;
s >> sortColumn;
if(playlist)
playlist->setSorting(sortColumn);
}
}
break;
}
default:
{
// Because the original version of the playlist cache did not contain a
// version number, we want to revert to the beginning of the file before
// reading the data.
f.reset();
while(!fs.atEnd()) {
Playlist *p = new Playlist(collection);
fs >> *p;
}
break;
}
}
f.close();
}
void Cache::savePlaylists(const PlaylistList &playlists)
{
QString dirName = KGlobal::dirs()->saveLocation("appdata");
QString playlistsFile = dirName + "playlists.new";
QFile f(playlistsFile);
if(!f.open(IO_WriteOnly))
return;
QByteArray data;
QDataStream s(data, IO_WriteOnly);
for(PlaylistList::ConstIterator it = playlists.begin(); it != playlists.end(); it++) {
if(*it) {
if(dynamic_cast<HistoryPlaylist *>(*it)) {
s << Q_INT32(History)
<< *static_cast<HistoryPlaylist *>(*it);
}
else if(dynamic_cast<SearchPlaylist *>(*it)) {
s << Q_INT32(Search)
<< *static_cast<SearchPlaylist *>(*it);
}
else {
s << Q_INT32(Normal)
<< *(*it);
}
s << Q_INT32((*it)->sortColumn());
}
}
QDataStream fs(&f);
fs << Q_INT32(playlistCacheVersion);
fs << qChecksum(data.data(), data.size());
fs << data;
f.close();
QDir(dirName).rename("playlists.new", "playlists");
}
////////////////////////////////////////////////////////////////////////////////
// protected methods
////////////////////////////////////////////////////////////////////////////////
......@@ -89,7 +223,7 @@ void Cache::load()
QFile f(cacheFileName);
if(!f.open(IO_ReadOnly))
return;
return;
CacheDataStream s(&f);
......@@ -102,40 +236,40 @@ void Cache::load()
switch(version) {
case 1: {
s.setCacheVersion(1);
Q_INT32 checksum;
QByteArray data;
s >> checksum
>> data;
buffer.setBuffer(data);
buffer.open(IO_ReadOnly);
s.setDevice(&buffer);
if(checksum != qChecksum(data.data(), data.size())) {
KMessageBox::sorry(0, i18n("The music data cache has been corrupted. JuK "
"needs to rescan it now. This may take some time."));
return;
}
break;
s.setCacheVersion(1);
Q_INT32 checksum;
QByteArray data;
s >> checksum
>> data;
buffer.setBuffer(data);
buffer.open(IO_ReadOnly);
s.setDevice(&buffer);
if(checksum != qChecksum(data.data(), data.size())) {
KMessageBox::sorry(0, i18n("The music data cache has been corrupted. JuK "
"needs to rescan it now. This may take some time."));
return;
}
break;
}
default: {
s.device()->reset();
s.setCacheVersion(0);
break;
s.device()->reset();
s.setCacheVersion(0);
break;
}
}
// Read the cached tags.
while(!s.atEnd()) {
QString fileName;
s >> fileName;
fileName.squeeze();
QString fileName;
s >> fileName;
fileName.squeeze();
FileHandle f(fileName);
s >> f;
// f.setFile(fileName);
FileHandle f(fileName);
s >> f;
// f.setFile(fileName);
}
}
......@@ -23,6 +23,10 @@
#include "stringhash.h"
class Tag;
class Playlist;
class PlaylistCollection;
typedef QValueList<Playlist *> PlaylistList;
class Cache : public FileHandleHash
{
......@@ -30,6 +34,9 @@ public:
static Cache *instance();
void save();
static void loadPlaylists(PlaylistCollection *collection);
static void savePlaylists(const PlaylistList &playlists);
protected:
Cache();
void load();
......
......@@ -21,11 +21,17 @@
#include <kdebug.h>
#include <kpopupmenu.h>
#include <kiconloader.h>
#include <kconfig.h>
#include <kaction.h>
#include "collectionlist.h"
#include "playlistcollection.h"
#include "splashscreen.h"
#include "stringshare.h"
#include "cache.h"
#include "actioncollection.h"
using namespace ActionCollection;
////////////////////////////////////////////////////////////////////////////////
// static methods
......@@ -38,9 +44,18 @@ CollectionList *CollectionList::instance()
return m_list;
}
void CollectionList::initialize(QWidget *parent, bool restoreOnLoad)
void CollectionList::initialize(PlaylistCollection *collection, bool restoreOnLoad)
{
m_list = new CollectionList(parent);
if(m_list)
return;
// We have to delay initilaization here because dynamic_cast or comparing to
// the collection instance won't work in the PlaylistBox::Item initialization
// won't work until the CollectionList is fully constructed.
m_list = new CollectionList(collection);
m_list->setName(i18n("Collection List"));
collection->setupPlaylist(m_list, "folder_sound");
// TODO: don't fetch the fileInfo from the tag, but rather from the FileHandle
......@@ -131,8 +146,8 @@ void CollectionList::slotRefreshItem(const QString &file)
// protected methods
////////////////////////////////////////////////////////////////////////////////
CollectionList::CollectionList(QWidget *parent) :
Playlist(parent, i18n("Collection List")),
CollectionList::CollectionList(PlaylistCollection *collection) :
Playlist(collection, true),
m_itemsDict(5003),
m_uniqueSets(m_uniqueSetCount, SortedStringList()),
m_uniqueSetLast(m_uniqueSetCount, QString::null)
......@@ -140,13 +155,20 @@ CollectionList::CollectionList(QWidget *parent) :
m_dirWatch = new KDirWatch;
connect(m_dirWatch, SIGNAL(deleted(const QString &)), this, SLOT(slotRemoveItem(const QString &)));
connect(m_dirWatch, SIGNAL(dirty(const QString &)), this, SLOT(slotRefreshItem(const QString &)));
connect(action("showPlaying"), SIGNAL(activated()), this, SLOT(slotShowPlaying()));
m_dirWatch->startScan();
KConfigGroup config(KGlobal::config(), "Playlists");
setSortColumn(config.readNumEntry("CollectionListSortColumn", 1));
polish();
}
CollectionList::~CollectionList()
{
KConfigGroup config(KGlobal::config(), "Playlists");
config.writeEntry("CollectionListSortColumn", sortColumn());
delete m_dirWatch;
}
......
......@@ -55,7 +55,7 @@ public:
enum UniqueSetType { Artists = 0, Albums = 1, Genres = 2 };
static CollectionList *instance();
static void initialize(QWidget *parent, bool restoreOnLoad = true);
static void initialize(PlaylistCollection *collection, bool restoreOnLoad = true);
/**
* Returns a unique set of values associated with the type specified.
......@@ -81,7 +81,7 @@ public slots:
void slotRefreshItem(const QString &file);
protected:
CollectionList(QWidget *parent);
CollectionList(PlaylistCollection *collection);
virtual ~CollectionList();
virtual void contentsDropEvent(QDropEvent *e);
......
......@@ -18,7 +18,7 @@
#ifndef DIRECTORYLIST_H
#define DIRECTORYLIST_H
#include <kdialogbase.h>
class DirectoryListBase;
......
......@@ -24,8 +24,11 @@
// public methods
////////////////////////////////////////////////////////////////////////////////
DynamicPlaylist::DynamicPlaylist(const PlaylistList &playlists, QWidget *parent, const QString &name) :
Playlist(parent, name),
DynamicPlaylist::DynamicPlaylist(const PlaylistList &playlists,
PlaylistCollection *collection,
const QString &name,
const QString &iconName) :
Playlist(collection, name, iconName),
m_playlists(playlists),
m_dirty(true)
{
......
......@@ -31,7 +31,10 @@ public:
/**
* Creates a dynamic playlist based on lists.
*/
DynamicPlaylist(const PlaylistList &lists, QWidget *parent, const QString &name = QString::null);
DynamicPlaylist(const PlaylistList &lists,
PlaylistCollection *collection,
const QString &name = QString::null,
const QString &iconName = "midi");
public slots:
/**
......
/***************************************************************************
copyright : (C) 2004 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "folderplaylist.h"
#include "collectionlist.h"
////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////
FolderPlaylist::FolderPlaylist(PlaylistCollection *collection, const QString &folder,
const QString &name) :
Playlist(collection, name),
m_folder(folder)
{
addFiles(folder, false);
}
FolderPlaylist::~FolderPlaylist()
{
}
#include "folderplaylist.moc"
/***************************************************************************
copyright : (C) 2004 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef FOLDERPLAYLIST_H
#define FOLDERPLAYLIST_H
#include "playlist.h"
class FolderPlaylist : public Playlist
{
Q_OBJECT
public:
FolderPlaylist(PlaylistCollection *collection, const QString &folder,
const QString &name = QString::null);
virtual ~FolderPlaylist();
private:
QString m_folder;
};
#endif
......@@ -26,7 +26,8 @@
// HistoryPlayList public members
////////////////////////////////////////////////////////////////////////////////
HistoryPlaylist::HistoryPlaylist(QWidget *parent) : Playlist(parent, i18n("History"))
HistoryPlaylist::HistoryPlaylist(PlaylistCollection *collection) :
Playlist(collection, i18n("History"))
{
setAllowDuplicates(true);
}
......
......@@ -40,7 +40,7 @@ class HistoryPlaylist : public Playlist
Q_OBJECT
public:
HistoryPlaylist(QWidget *parent);
HistoryPlaylist(PlaylistCollection *collection);
virtual ~HistoryPlaylist();
virtual HistoryPlaylistItem *createItem(const FileHandle &file, QListViewItem *after = 0,
......
......@@ -22,6 +22,7 @@
#include <kdebug.h>
#include <kmessagebox.h>
#include <kiconloader.h>
#include <kapplication.h>
#include <qslider.h>
......@@ -35,6 +36,8 @@
#include "filerenamerconfigdlg.h"
#include "actioncollection.h"
#include "cache.h"
#include "playlistsplitter.h"
#include "collectionlist.h"
using namespace ActionCollection;
......@@ -43,7 +46,6 @@ using namespace ActionCollection;
////////////////////////////////////////////////////////////////////////////////
JuK::JuK(QWidget *parent, const char *name) :
DCOPObject("Collection"),
KMainWindow(parent, name, WDestructiveClose),
m_player(PlayerManager::instance()),
m_shuttingDown(false)
......@@ -59,15 +61,12 @@ JuK::JuK(QWidget *parent, const char *name) :
setupActions();
setupLayout();
setupSplitterConnections();
slotPlaylistChanged();
createGUI();
readConfig();
setupSystemTray();
setupGlobalAccels();
processArgs();
m_player->setPlaylistInterface(m_splitter);
SplashScreen::finishedLoading();
QTimer::singleShot(0, CollectionList::instance(), SLOT(slotCheckCache()));
......@@ -84,140 +83,44 @@ KActionCollection *JuK::actionCollection() const
return ActionCollection::actions();
}
////////////////////////////////////////////////////////////////////////////////
// public slots
////////////////////////////////////////////////////////////////////////////////
void JuK::slotGuessTagInfoFromFile()
{
m_splitter->slotGuessTagInfo(TagGuesser::FileName);
}
void JuK::slotGuessTagInfoFromInternet()
{
m_splitter->slotGuessTagInfo(TagGuesser::MusicBrainz);
}
void JuK::openFile(const QString &file)
{
m_splitter->open(file);
}
void JuK::openFile(const QStringList &files)
{
for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it)
openFile(*it);
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void JuK::setupLayout()
{
m_splitter = new PlaylistSplitter(this, "playlistSplitter");
setCentralWidget(m_splitter);
// create status bar
m_statusLabel = new StatusLabel(statusBar());
statusBar()->addWidget(m_statusLabel, 1);
connect(m_statusLabel, SIGNAL(jumpButtonClicked()),
m_splitter, SLOT(slotSelectPlaying()));
m_splitter = new PlaylistSplitter(this, "playlistSplitter");
setCentralWidget(m_splitter);
PlayerManager::instance()->setStatusLabel(m_statusLabel);
// Needs to be here because m_splitter is not called before setupActions
// (because PlaylistSplitter itself accesses the actionCollection)
new KAction(i18n("&Rename File"), "filesaveas", "CTRL+r", m_splitter,
SLOT(slotRenameFile()), actions(), "renameFile");
m_splitter->setFocus();
resize(750, 500);
}
void JuK::setupActions()
{
//////////////////////////////////////////////////
// file menu
//////////////////////////////////////////////////
KActionMenu *newMenu = new KActionMenu(i18n("&New"), "filenew",
actions(), "file_new");
// This connection will call the
// PlaylistSplitter::slotCreatePlaylist(const QString &) slot - this is
// possible because the QString parameter has a default value, so the
// slot can be called without arguments (as required by the signal's
// signature).
newMenu->insert(createSplitterAction(
i18n("&Empty Playlist..."), SLOT(slotCreatePlaylist()),