Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

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,
......
This diff is collapsed.
......@@ -22,7 +22,6 @@
#include <kshortcut.h>
#include "playermanager.h"
#include "playlistsplitter.h"
#include "jukIface.h"
class QTimer;
......@@ -37,8 +36,9 @@ class SliderAction;
class StatusLabel;
class SystemTray;
class PlayerManager;
class PlaylistSplitter;
class JuK : public KMainWindow, public CollectionIface
class JuK : public KMainWindow
{
Q_OBJECT
......@@ -47,26 +47,13 @@ public:
virtual ~JuK();
virtual KActionCollection *actionCollection() const;
/**
* This forwards on the request to enable or disable directory scanning for
* new files being added or removed.
*/
void setDirWatchEnabled(bool enabled) { m_splitter->setDirWatchEnabled(enabled); }
private:
void setupLayout();
void setupActions();
/**
* Solves the problem of the splitter needing to use some of the actions from
* this class and as such them needing to be created before the
* PlaylistSplitter, but also needing to connect to the playlist splitter.
*
* @see createSplitterAction();
*/
void setupSplitterConnections();
void setupSystemTray();
void setupGlobalAccels();
void processArgs();
void keyPressEvent(QKeyEvent *);
/**
......@@ -80,33 +67,13 @@ private:
virtual bool queryExit();
virtual bool queryClose();
void openFile(const QString &file);
void openFile(const QStringList &files);
/**
* Because we want to be able to reuse these actions in the main GUI classes,
* which are created by the PlaylistSplitter, it is useful to create them
* before creating the splitter. This however creates a problem in that we
* also need to connect them to the splitter. This method builds creates
* actions and builds a list of connections that can be set up after the
* splitter is created.
*/
KAction *createSplitterAction(const QString &text,
const char *slot,
const char *name,
const QString &pix = QString::null,
const KShortcut &shortcut = KShortcut());
private slots:
void slotShowHide();
void slotPlaylistChanged();
void slotQuit();
void slotToggleSystemTray(bool enabled);
void slotEditKeys();
void slotConfigureTagGuesser();
void slotConfigureFileRenamer();
void slotGuessTagInfoFromFile();
void slotGuessTagInfoFromInternet();
private:
PlaylistSplitter *m_splitter;
......@@ -117,8 +84,6 @@ private:
QValueList<SplitterConnection> m_splitterConnections;
SliderAction *m_sliderAction;
KToggleAction *m_showSearchAction;
KToggleAction *m_showEditorAction;
KToggleAction *m_showHistoryAction;
KToggleAction *m_randomPlayAction;
KToggleAction *m_toggleSystemTrayAction;
......
......@@ -19,6 +19,8 @@
#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <dcopclient.h>
#include <kconfigbase.h>
#include <kconfig.h>
#include "juk.h"
......@@ -37,9 +39,6 @@ static const char antonio[] = I18N_NOOP("DCOP interface");
static KCmdLineOptions options[] =
{
#ifndef NO_DEBUG
{ "norestore", I18N_NOOP("Restore playlists. Use --norestore for debugging."), 0 },
#endif
{ "+[file(s)]", I18N_NOOP("File(s) to open"), 0 },
KCmdLineLastOption
};
......@@ -81,11 +80,9 @@ int main(int argc, char *argv[])
bool startDocked;
KConfig *config = KGlobal::config();
{
KConfigGroupSaver saver(config, "Settings");
startDocked = config->readBoolEntry("StartDocked", false);
}
KConfigGroup config(KGlobal::config(), "Settings");
startDocked = config.readBoolEntry("StartDocked", false);
if(!startDocked)
juk->show();
......
/***************************************************************************
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 "painteater.h"
#include "playlist.h"
PaintEater::PaintEater(Playlist *list) :
QObject(list),
m_list(list),
m_allowOne(false),
m_previousHeight(0)
{
// We want to catch paint events for both the contents and the frame of
// our listview.
list->installEventFilter(this);
list->viewport()->installEventFilter(this);
}
bool PaintEater::eventFilter(QObject *o, QEvent *e)
{
if(e->type() == QEvent::Paint) {
// There are two cases where we want to let our viewport repaint
// itself -- if the actual contents have changed as indicated by
// m_allowOne being true, or if the height has changed indicating
// that we've either scrolled or resized the widget.
if(o == m_list->viewport()) {
if(m_allowOne) {
m_allowOne = false;
return false;
}
int newHeight = static_cast<QPaintEvent *>(e)->rect().top();