...
 
Commits (49)
......@@ -42,6 +42,25 @@ if(TUNEPIMP_FOUND)
endif(TUNEPIMP_FOUND)
set(juk_SRCS ${tunepimp_SRCS}
# Playlist classes
playlist/playlists/playlist.cpp
playlist/playlists/dynamicplaylist.cpp
playlist/playlists/folderplaylist.cpp
playlist/playlists/historyplaylist.cpp
playlist/playlists/searchplaylist.cpp
playlist/playlists/treeviewitemplaylist.cpp
playlist/playlists/upcomingplaylist.cpp
playlist/playlistcollection.cpp
playlist/playlistinterface.cpp
playlist/playlistexporter.cpp
playlist/playlistsearch.cpp
playlist/playlistview.cpp
playlist/playlistheaderview.cpp
playlist/playlistsortfilterproxymodel.cpp
playlistbox.cpp
playlistsplitter.cpp
advancedsearchdialog.cpp
slider.cpp
svghandler.cpp
......@@ -58,15 +77,12 @@ set(juk_SRCS ${tunepimp_SRCS}
dbuscollectionproxy.cpp
deletedialog.cpp
directorylist.cpp
dynamicplaylist.cpp
exampleoptions.cpp
folderplaylist.cpp
filehandle.cpp
filerenamer.cpp
filerenameroptions.cpp
filerenamerconfigdlg.cpp
webimagefetcher.cpp
historyplaylist.cpp
juk.cpp
k3bexporter.cpp
keydialog.cpp
......@@ -78,17 +94,8 @@ set(juk_SRCS ${tunepimp_SRCS}
musicbrainzquery.cpp
nowplaying.cpp
playermanager.cpp
playlist.cpp
playlistbox.cpp
playlistcollection.cpp
playlistexporter.cpp
playlistinterface.cpp
playlistitem.cpp
playlistsearch.cpp
playlistsplitter.cpp
scrobbler.cpp
scrobbleconfigdlg.cpp
searchplaylist.cpp
searchwidget.cpp
slideraction.cpp
sortedstringlist.cpp
......@@ -104,8 +111,6 @@ set(juk_SRCS ${tunepimp_SRCS}
tagtransactionmanager.cpp
tracksequenceiterator.cpp
tracksequencemanager.cpp
treeviewitemplaylist.cpp
upcomingplaylist.cpp
ktrm.cpp
viewmode.cpp )
......
......@@ -19,7 +19,7 @@
#include <kdialog.h>
#include <QList>
#include "playlistsearch.h"
#include "playlist/playlistsearch.h"
class KLineEdit;
class KPushButton;
......
......@@ -31,11 +31,11 @@
#include <QBuffer>
#include "tag.h"
#include "searchplaylist.h"
#include "historyplaylist.h"
#include "upcomingplaylist.h"
#include "folderplaylist.h"
#include "playlistcollection.h"
#include "playlist/playlists/searchplaylist.h"
#include "playlist/playlists/historyplaylist.h"
#include "playlist/playlists/upcomingplaylist.h"
#include "playlist/playlists/folderplaylist.h"
#include "playlist/playlistcollection.h"
#include "actioncollection.h"
using namespace ActionCollection;
......@@ -215,8 +215,10 @@ void Cache::loadPlaylists(PlaylistCollection *collection) // static
if(version >= 2) {
qint32 sortColumn;
s >> sortColumn;
if(playlist)
playlist->setSorting(sortColumn);
if(playlist) {
// ### TODO: View
// playlist->setSorting(sortColumn);
}
}
} // while !s.atEnd()
......@@ -313,7 +315,8 @@ void Cache::savePlaylists(const PlaylistList &playlists)
s << qint32(Normal)
<< *(*it);
}
s << qint32((*it)->sortColumn());
// ### TODO: View
s << qint32(0);//qint32((*it)->sortColumn());
}
}
......
......@@ -32,7 +32,7 @@
#include <QClipboard>
#include <QFileInfo>
#include "playlistcollection.h"
#include "playlist/playlistcollection.h"
#include "splashscreen.h"
#include "stringshare.h"
#include "cache.h"
......@@ -61,24 +61,29 @@ void CollectionList::loadCachedItems()
FileHandleHash::ConstIterator end = Cache::instance()->constEnd();
for(FileHandleHash::ConstIterator it = Cache::instance()->constBegin(); it != end; ++it) {
// This may have already been created via a loaded playlist.
if(!m_itemsDict.contains(it.key()))
new CollectionListItem(this, *it);
if(!m_itemsDict.contains(it.key())) {
insertFile(*it);
m_itemsDict.insert(it.key(), *it);
}
}
SplashScreen::update();
// The CollectionList is created with sorting disabled for speed. Re-enable
// it here, and perform the sort.
KConfigGroup config(KGlobal::config(), "Playlists");
Qt::SortOrder order = Qt::DescendingOrder;
if(config.readEntry("CollectionListSortAscending", true))
order = Qt::AscendingOrder;
m_list->setSortOrder(order);
m_list->setSortColumn(config.readEntry("CollectionListSortColumn", 1));
m_list->sort();
// KConfigGroup config(KGlobal::config(), "Playlists");
//
// Qt::SortOrder order = Qt::DescendingOrder;
// if(config.readEntry("CollectionListSortAscending", true))
// order = Qt::AscendingOrder;
// ### TODO: View
// m_list->setSortOrder(order);
// m_list->setSortColumn(config.readEntry("CollectionListSortColumn", 1));
// m_list->sort();
emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
SplashScreen::finishedLoading();
}
......@@ -102,38 +107,6 @@ void CollectionList::initialize(PlaylistCollection *collection)
// public methods
////////////////////////////////////////////////////////////////////////////////
CollectionListItem *CollectionList::createItem(const FileHandle &file, Q3ListViewItem *, bool)
{
// It's probably possible to optimize the line below away, but, well, right
// now it's more important to not load duplicate items.
if(m_itemsDict.contains(file.absFilePath()))
return 0;
CollectionListItem *item = new CollectionListItem(this, file);
if(!item->isValid()) {
kError() << "CollectionList::createItem() -- A valid tag was not created for \""
<< file.absFilePath() << "\"" << endl;
delete item;
return 0;
}
setupItem(item);
return item;
}
void CollectionList::clearItems(const PlaylistItemList &items)
{
foreach(PlaylistItem *item, items) {
Cache::instance()->remove(item->file());
delete item;
}
dataChanged();
}
void CollectionList::setupTreeViewEntries(ViewMode *viewMode) const
{
TreeViewMode *treeViewMode = dynamic_cast<TreeViewMode *>(viewMode);
......@@ -143,9 +116,9 @@ void CollectionList::setupTreeViewEntries(ViewMode *viewMode) const
}
QList<int> columnList;
columnList << PlaylistItem::ArtistColumn;
columnList << PlaylistItem::GenreColumn;
columnList << PlaylistItem::AlbumColumn;
columnList << ArtistColumn;
columnList << GenreColumn;
columnList << AlbumColumn;
foreach(int column, columnList)
treeViewMode->addItems(m_columnTags[column]->keys(), column);
......@@ -159,33 +132,27 @@ void CollectionList::slotNewItems(const KFileItemList &items)
files.append((*it).url().path());
addFiles(files);
update();
// update();
}
void CollectionList::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> > &items)
{
for(int i = 0; i < items.count(); ++i) {
const KFileItem fileItem = items[i].second;
CollectionListItem *item = lookup(fileItem.url().path());
FileHandle file = lookup(fileItem.url().path());
if(item) {
item->refreshFromDisk();
if(!file.isNull()) {
file.refresh();
// If the item is no longer on disk, remove it from the collection.
if(item->file().fileInfo().exists())
item->repaint();
else
delete item;
if(!file.fileInfo().exists()) {
removeFile(file);
}
}
}
update();
}
void CollectionList::slotDeleteItem(const KFileItem &item)
{
delete lookup(item.url().path());
// update();
}
////////////////////////////////////////////////////////////////////////////////
......@@ -194,12 +161,14 @@ void CollectionList::slotDeleteItem(const KFileItem &item)
void CollectionList::paste()
{
decode(QApplication::clipboard()->mimeData());
// ### TODO: View
// decode(QApplication::clipboard()->mimeData());
}
void CollectionList::clear()
{
int result = KMessageBox::warningContinueCancel(this,
// ### TODO: View
int result = KMessageBox::warningContinueCancel(/*this*/0,
i18n("Removing an item from the collection will also remove it from "
"all of your playlists. Are you sure you want to continue?\n\n"
"Note, however, that if the directory that these files are in is in "
......@@ -214,27 +183,24 @@ void CollectionList::clear()
void CollectionList::slotCheckCache()
{
loadCachedItems();
PlaylistItemList invalidItems;
foreach(CollectionListItem *item, m_itemsDict) {
if(!item->checkCurrent())
invalidItems.append(item);
foreach(const FileHandle &file, m_itemsDict) {
if(!file.fileInfo().exists()) {
removeFile(file);
}
processEvents();
}
clearItems(invalidItems);
}
void CollectionList::slotRemoveItem(const QString &file)
{
delete m_itemsDict[file];
removeFile(m_itemsDict[file]);
}
void CollectionList::slotRefreshItem(const QString &file)
{
if(m_itemsDict[file])
m_itemsDict[file]->refresh();
if(!m_itemsDict[file].isNull())
m_itemsDict[file].refresh();
}
////////////////////////////////////////////////////////////////////////////////
......@@ -253,18 +219,19 @@ CollectionList::CollectionList(PlaylistCollection *collection) :
this, SLOT(slotPopulateBackMenu()));
connect(action<KToolBarPopupAction>("back")->menu(), SIGNAL(triggered(QAction*)),
this, SLOT(slotPlayFromBackMenu(QAction*)));
setSorting(-1); // Temporarily disable sorting to add items faster.
// setSorting(-1); // Temporarily disable sorting to add items faster.
m_columnTags[PlaylistItem::ArtistColumn] = new TagCountDict;
m_columnTags[PlaylistItem::AlbumColumn] = new TagCountDict;
m_columnTags[PlaylistItem::GenreColumn] = new TagCountDict;
m_columnTags[ArtistColumn] = new TagCountDict;
m_columnTags[AlbumColumn] = new TagCountDict;
m_columnTags[GenreColumn] = new TagCountDict;
}
CollectionList::~CollectionList()
{
KConfigGroup config(KGlobal::config(), "Playlists");
config.writeEntry("CollectionListSortColumn", sortColumn());
config.writeEntry("CollectionListSortAscending", sortOrder() == Qt::AscendingOrder);
// ### TODO: View
// config.writeEntry("CollectionListSortColumn", sortColumn());
// config.writeEntry("CollectionListSortAscending", sortOrder() == Qt::AscendingOrder);
// In some situations the dataChanged signal from clearItems will cause observers to
// subsequently try to access a deleted item. Since we're going away just remove all
......@@ -276,27 +243,28 @@ CollectionList::~CollectionList()
// m_columnTags member, so we must make sure they're gone before we
// are.
clearItems(items());
clear();
qDeleteAll(m_columnTags);
m_columnTags.clear();
}
void CollectionList::contentsDropEvent(QDropEvent *e)
{
if(e->source() == this)
return; // Don't rearrange in the CollectionList.
else
Playlist::contentsDropEvent(e);
}
void CollectionList::contentsDragMoveEvent(QDragMoveEvent *e)
{
if(e->source() != this)
Playlist::contentsDragMoveEvent(e);
else
e->setAccepted(false);
}
// ### TODO: View
// void CollectionList::contentsDropEvent(QDropEvent *e)
// {
// if(e->source() == this)
// return; // Don't rearrange in the CollectionList.
// else
// Playlist::contentsDropEvent(e);
// }
//
// void CollectionList::contentsDragMoveEvent(QDragMoveEvent *e)
// {
// if(e->source() != this)
// Playlist::contentsDragMoveEvent(e);
// else
// e->setAccepted(false);
// }
QString CollectionList::addStringToDict(const QString &value, int column)
{
......@@ -320,15 +288,15 @@ QStringList CollectionList::uniqueSet(UniqueSetType t) const
switch(t)
{
case Artists:
column = PlaylistItem::ArtistColumn;
column = ArtistColumn;
break;
case Albums:
column = PlaylistItem::AlbumColumn;
column = AlbumColumn;
break;
case Genres:
column = PlaylistItem::GenreColumn;
column = GenreColumn;
break;
default:
......@@ -338,9 +306,9 @@ QStringList CollectionList::uniqueSet(UniqueSetType t) const
return m_columnTags[column]->keys();
}
CollectionListItem *CollectionList::lookup(const QString &file) const
const FileHandle &CollectionList::lookup(const QString& file) const
{
return m_itemsDict.value(file, 0);
return m_itemsDict.value(file);
}
void CollectionList::removeStringFromDict(const QString &value, int column)
......@@ -366,155 +334,15 @@ void CollectionList::removeWatched(const QString &file)
m_dirWatch->removeFile(file);
}
////////////////////////////////////////////////////////////////////////////////
// CollectionListItem public methods
////////////////////////////////////////////////////////////////////////////////
void CollectionListItem::refresh()
{
int offset = CollectionList::instance()->columnOffset();
int columns = lastColumn() + offset + 1;
data()->metadata.resize(columns);
data()->cachedWidths.resize(columns);
for(int i = offset; i < columns; i++) {
int id = i - offset;
if(id != TrackNumberColumn && id != LengthColumn) {
// All columns other than track num and length need local-encoded data for sorting
QString toLower = text(i).toLower();
// For some columns, we may be able to share some strings
if((id == ArtistColumn) || (id == AlbumColumn) ||
(id == GenreColumn) || (id == YearColumn) ||
(id == CommentColumn))
{
toLower = StringShare::tryShare(toLower);
if(id != YearColumn && id != CommentColumn && data()->metadata[id] != toLower) {
CollectionList::instance()->removeStringFromDict(data()->metadata[id], id);
CollectionList::instance()->addStringToDict(text(i), id);
}
}
data()->metadata[id] = toLower;
}
int newWidth = width(listView()->fontMetrics(), listView(), i);
if(newWidth != data()->cachedWidths[i])
playlist()->slotWeightDirty(i);
data()->cachedWidths[i] = newWidth;
}
if(listView()->isVisible())
repaint();
for(PlaylistItemList::Iterator it = m_children.begin(); it != m_children.end(); ++it) {
(*it)->playlist()->update();
(*it)->playlist()->dataChanged();
if((*it)->listView()->isVisible())
(*it)->repaint();
}
CollectionList::instance()->dataChanged();
emit CollectionList::instance()->signalCollectionChanged();
}
PlaylistItem *CollectionListItem::itemForPlaylist(const Playlist *playlist)
{
if(playlist == CollectionList::instance())
return this;
PlaylistItemList::ConstIterator it;
for(it = m_children.constBegin(); it != m_children.constEnd(); ++it)
if((*it)->playlist() == playlist)
return *it;
return 0;
}
void CollectionListItem::updateCollectionDict(const QString &oldPath, const QString &newPath)
{
CollectionList *collection = CollectionList::instance();
if(!collection)
return;
collection->removeFromDict(oldPath);
collection->addToDict(newPath, this);
}
void CollectionListItem::repaint() const
{
Q3ListViewItem::repaint();
for(PlaylistItemList::ConstIterator it = m_children.constBegin(); it != m_children.constEnd(); ++it)
(*it)->repaint();
}
////////////////////////////////////////////////////////////////////////////////
// CollectionListItem protected methods
////////////////////////////////////////////////////////////////////////////////
CollectionListItem::CollectionListItem(CollectionList *parent, const FileHandle &file) :
PlaylistItem(parent),
m_shuttingDown(false)
{
parent->addToDict(file.absFilePath(), this);
data()->fileHandle = file;
if(file.tag()) {
refresh();
parent->dataChanged();
}
else {
kError() << "CollectionListItem::CollectionListItem() -- Tag() could not be created." << endl;
}
SplashScreen::increment();
}
CollectionListItem::~CollectionListItem()
void CollectionList::removeFile(const FileHandle& file)
{
m_shuttingDown = true;
foreach(PlaylistItem *item, m_children)
delete item;
CollectionList *l = CollectionList::instance();
if(l) {
l->removeFromDict(file().absFilePath());
l->removeStringFromDict(file().tag()->album(), AlbumColumn);
l->removeStringFromDict(file().tag()->artist(), ArtistColumn);
l->removeStringFromDict(file().tag()->genre(), GenreColumn);
}
removeFromDict(file.absFilePath());
removeStringFromDict(file.tag()->album(), Playlist::AlbumColumn);
removeStringFromDict(file.tag()->artist(), Playlist::ArtistColumn);
removeStringFromDict(file.tag()->genre(), Playlist::GenreColumn);
Playlist::removeFile(file);
}
void CollectionListItem::addChildItem(PlaylistItem *child)
{
m_children.append(child);
}
void CollectionListItem::removeChildItem(PlaylistItem *child)
{
if(!m_shuttingDown)
m_children.removeAll(child);
}
bool CollectionListItem::checkCurrent()
{
if(!file().fileInfo().exists() || !file().fileInfo().isFile())
return false;
if(!file().current()) {
file().refresh();
refresh();
}
return true;
}
#include "collectionlist.moc"
......
......@@ -19,8 +19,7 @@
#include <QHash>
#include <QVector>
#include "playlist.h"
#include "playlistitem.h"
#include "playlist/playlists/playlist.h"
class ViewMode;
class KFileItem;
......@@ -44,53 +43,9 @@ typedef QHashIterator<QString, int> TagCountDictIterator;
typedef QVector<TagCountDict *> TagCountDicts;
/**
* This is the "collection", or all of the music files that have been opened
* in any playlist and not explicitly removed from the collection.
*
* It is being implemented as a "semi-singleton" because I need universal access
* to just one instance. However, because the collection needs initialization
* parameters (that will not always be available when an instance is needed).
* Hence there will be the familiar singleton "instance()" method allong with an
* "initialize()" method.
*/
class CollectionListItem : public PlaylistItem
{
friend class Playlist;
friend class CollectionList;
friend class PlaylistItem;
public:
virtual void refresh();
PlaylistItem *itemForPlaylist(const Playlist *playlist);
void updateCollectionDict(const QString &oldPath, const QString &newPath);
void repaint() const;
PlaylistItemList children() const { return m_children; }
protected:
CollectionListItem(CollectionList *parent, const FileHandle &file);
virtual ~CollectionListItem();
void addChildItem(PlaylistItem *child);
void removeChildItem(PlaylistItem *child);
/**
* Returns true if the item is now up to date (even if this required a refresh) or
* false if the item is invalid.
*/
bool checkCurrent();
virtual CollectionListItem *collectionItem() { return this; }
private:
bool m_shuttingDown;
PlaylistItemList m_children;
};
class CollectionList : public Playlist
{
friend class CollectionListItem;
// friend class CollectionListItem;
Q_OBJECT
......@@ -109,19 +64,15 @@ public:
*/
QStringList uniqueSet(UniqueSetType t) const;
CollectionListItem *lookup(const QString &file) const;
virtual CollectionListItem *createItem(const FileHandle &file,
Q3ListViewItem * = 0,
bool = false);
const FileHandle &lookup(const QString& file) const;
void emitVisibleColumnsChanged() { emit signalVisibleColumnsChanged(); }
virtual void clearItems(const PlaylistItemList &items);
void setupTreeViewEntries(ViewMode *viewMode) const;
virtual bool canReload() const { return true; }
virtual void removeFile(const FileHandle& file);
public slots:
virtual void paste();
......@@ -133,18 +84,17 @@ public slots:
void slotNewItems(const KFileItemList &items);
void slotRefreshItems(const QList<QPair<KFileItem, KFileItem> > &items);
void slotDeleteItem(const KFileItem &item);
protected:
CollectionList(PlaylistCollection *collection);
virtual ~CollectionList();
virtual void contentsDropEvent(QDropEvent *e);
virtual void contentsDragMoveEvent(QDragMoveEvent *e);
// virtual void contentsDropEvent(QDropEvent *e);
// virtual void contentsDragMoveEvent(QDragMoveEvent *e);
// These methods are used by CollectionListItem, which is a friend class.
void addToDict(const QString &file, CollectionListItem *item) { m_itemsDict.insert(file, item); }
void addToDict(const QString &file, const FileHandle &item) { m_itemsDict.insert(file, item); }
void removeFromDict(const QString &file) { m_itemsDict.remove(file); }
// These methods are also used by CollectionListItem, to manage the
......@@ -187,7 +137,7 @@ private:
static const int m_uniqueSetCount = 3;
static CollectionList *m_list;
QHash<QString, CollectionListItem *> m_itemsDict;
QHash<QString, FileHandle> m_itemsDict;
KDirWatch *m_dirWatch;
TagCountDicts m_columnTags;
};
......
/***************************************************************************
begin : Sun May 15 2005
copyright : (C) 2005 by Michael Pyne
: (C) 2014 by Arnold Dumas <contact@arnolddumas.fr>
email : michael.pyne@kdemail.net
***************************************************************************/
......@@ -15,9 +16,6 @@
#include "coverdialog.h"
#include <k3listview.h>
#include <k3iconview.h>
#include <k3iconviewsearchline.h>
#include <kiconloader.h>
#include <kapplication.h>
#include <kmenu.h>
......@@ -31,32 +29,32 @@
using CoverUtility::CoverIconViewItem;
class AllArtistsListViewItem : public K3ListViewItem
class AllArtistsListViewItem : public QListWidgetItem
{
public:
AllArtistsListViewItem(Q3ListView *parent) :
K3ListViewItem(parent, i18n("&lt;All Artists&gt;"))
AllArtistsListViewItem(KListWidget *parent) :
QListWidgetItem(i18n("&lt;All Artists&gt;"), parent)
{
}
int compare(Q3ListViewItem *, int, bool) const
bool operator< (const QListWidgetItem& other) const
{
return -1; // Always be at the top.
Q_UNUSED(other);
return true; // Always be at the top.
}
};
class CaseInsensitiveItem : public K3ListViewItem
class CaseInsensitiveItem : public QListWidgetItem
{
public:
CaseInsensitiveItem(Q3ListView *parent, const QString &text) :
K3ListViewItem(parent, text)
CaseInsensitiveItem(KListWidget *parent, const QString &text) :
QListWidgetItem(text, parent)
{
}
int compare(Q3ListViewItem *item, int column, bool ascending) const
bool operator< (const QListWidgetItem& other) const
{
Q_UNUSED(ascending);
return text(column).toLower().localeAwareCompare(item->text(column).toLower());
return text().toLower().localeAwareCompare(other.text().toLower());
}
};
......@@ -67,11 +65,16 @@ CoverDialog::CoverDialog(QWidget *parent) :
setObjectName( QLatin1String("juk_cover_dialog" ));
m_covers->setResizeMode(Q3IconView::Adjust);
m_covers->setGridX(140);
m_covers->setGridY(150);
m_searchLine->setClearButtonShown(true);
m_searchLine->setIconView(m_covers);
connect(m_artists, SIGNAL(itemClicked(QListWidgetItem*)),
this, SLOT(slotArtistClicked(QListWidgetItem*)));
connect(m_covers, SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(slotContextRequested(QPoint)));
connect(m_searchLine, SIGNAL(textChanged(QString)),
this, SLOT(slotSearchPatternChanged(QString)));
}
CoverDialog::~CoverDialog()
......@@ -85,13 +88,10 @@ void CoverDialog::show()
QStringList artists = CollectionList::instance()->uniqueSet(CollectionList::Artists);
m_artists->setSorting(-1);
new AllArtistsListViewItem(m_artists);
for(QStringList::ConstIterator it = artists.constBegin(); it != artists.constEnd(); ++it)
new CaseInsensitiveItem(m_artists, *it);
m_artists->setSorting(0);
QTimer::singleShot(0, this, SLOT(loadCovers()));
QWidget::show();
}
......@@ -118,7 +118,7 @@ void CoverDialog::loadCovers()
}
// TODO: Add a way to show cover art for tracks with no artist.
void CoverDialog::slotArtistClicked(Q3ListViewItem *item)
void CoverDialog::slotArtistClicked(QListWidgetItem *item)
{
m_covers->clear();
......@@ -127,7 +127,7 @@ void CoverDialog::slotArtistClicked(Q3ListViewItem *item)
loadCovers();
}
else {
QString artist = item->text(0).toLower();
QString artist = item->text().toLower();
CoverDataMapIterator it, end;
......@@ -141,10 +141,12 @@ void CoverDialog::slotArtistClicked(Q3ListViewItem *item)
}
}
void CoverDialog::slotContextRequested(Q3IconViewItem *item, const QPoint &pt)
void CoverDialog::slotContextRequested(const QPoint &pt)
{
static KMenu *menu = 0;
QListWidgetItem* item = m_covers->currentItem();
if(!item)
return;
......@@ -153,7 +155,55 @@ void CoverDialog::slotContextRequested(Q3IconViewItem *item, const QPoint &pt)
menu->addAction(i18n("Remove Cover"), this, SLOT(removeSelectedCover()));
}
menu->popup(pt);
QPoint globalPt = m_covers->mapToGlobal(pt);
menu->popup(globalPt);
}
void CoverDialog::slotSearchPatternChanged(const QString& pattern)
{
m_covers->clear();
QListWidgetItem* item = m_artists->currentItem();
// If the expression is cleared, then use slotArtistClicked.
if (pattern.isEmpty()) {
slotArtistClicked(item);
}
else {
QRegExp filter(pattern, Qt::CaseInsensitive, QRegExp::Wildcard);
QString artist = item->text().toLower();
CoverDataMapIterator it, end;
it = CoverManager::begin();
end = CoverManager::end();
// Here, only show cover that match the search pattern.
if (dynamic_cast<AllArtistsListViewItem *>(item)) {
for(; it != end; ++it) {
if (filter.indexIn(it.value()->artist) != -1) {
(void) new CoverIconViewItem(it.key(), m_covers);
}
}
}
// Here, only show the covers that match the search pattern and
// that have the same artist as the currently selected one.
else {
for(; it != end; ++it) {
if (it.value()->artist == artist
&& (filter.indexIn(it.value()->artist) != -1)
|| (filter.indexIn(it.value()->album) != -1)) {
(void) new CoverIconViewItem(it.key(), m_covers);
}
}
}
}
}
void CoverDialog::removeSelectedCover()
......
/***************************************************************************
begin : Sun May 15 2005
copyright : (C) 2005 by Michael Pyne
: (C) 2014 by Arnold Dumas <contact@arnolddumas.fr>
email : michael.pyne@kdemail.net
***************************************************************************/
......@@ -20,6 +21,8 @@
#include <QWidget>
class QListWidgetItem;
class CoverDialog : public QWidget, public Ui::CoverDialogBase
{
Q_OBJECT
......@@ -30,8 +33,9 @@ public:
virtual void show();
public slots:
void slotArtistClicked(Q3ListViewItem *item);
void slotContextRequested(Q3IconViewItem *item, const QPoint &pt);
void slotArtistClicked(QListWidgetItem *item);
void slotContextRequested(const QPoint &pt);
void slotSearchPatternChanged(const QString& pattern);
private slots:
void loadCovers();
......
......@@ -20,7 +20,7 @@
<number>6</number>
</property>
<item>
<widget class="K3ListView" name="m_artists" >
<widget class="KListWidget" name="m_artists" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
......@@ -35,12 +35,6 @@
<height>0</height>
</size>
</property>
<property name="resizeMode" >
<enum>Q3ListView::LastColumn</enum>
</property>
<property name="shadeSortColumn" >
<bool>false</bool>
</property>
<column>
<property name="text" >
<string>Artist</string>
......@@ -65,7 +59,7 @@
<number>6</number>
</property>
<item>
<widget class="K3IconViewSearchLine" native="1" name="m_searchLine" >
<widget class="KLineEdit" native="1" name="m_searchLine" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
......@@ -96,14 +90,14 @@
</widget>
<customwidgets>
<customwidget>
<class>K3ListView</class>
<extends>Q3ListView</extends>
<header>k3listview.h</header>
<class>KListWidget</class>
<extends>QListWidget</extends>
<header>klistwidget.h</header>
</customwidget>
<customwidget>
<class>K3IconViewSearchLine</class>
<class>KLineEdit</class>
<extends>QWidget</extends>
<header>k3iconviewsearchline.h</header>
<header>klineedit.h</header>
</customwidget>
<customwidget>
<class>CoverIconView</class>
......@@ -114,42 +108,10 @@
</customwidgets>
<includes>
<include location="local" >k3listview.h</include>
<include location="local" >k3iconviewsearchline.h</include>
<include location="local" >klineedit.h</include>
<include location="local" >covericonview.h</include>
</includes>
<resources/>
<connections>
<connection>
<sender>m_artists</sender>
<signal>clicked(Q3ListViewItem*)</signal>
<receiver>CoverDialogBase</receiver>
<slot>slotArtistClicked(Q3ListViewItem*)</slot>
<hints>
<hint type="sourcelabel" >
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel" >
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_covers</sender>
<signal>contextMenuRequested(Q3IconViewItem*,QPoint)</signal>
<receiver>CoverDialogBase</receiver>
<slot>slotContextRequested(Q3IconViewItem*,QPoint)</slot>
<hints>
<hint type="sourcelabel" >
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel" >
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
</connections>
</ui>
/***************************************************************************
begin : Sat Jul 9 2005
copyright : (C) 2005 by Michael Pyne
: (C) 2014 by Arnold Dumas <contact@arnolddumas.fr>
email : michael.pyne@kdemail.net
***************************************************************************/
......@@ -18,34 +19,41 @@
using CoverUtility::CoverIconViewItem;
CoverIconViewItem::CoverIconViewItem(coverKey id, Q3IconView *parent) :
K3IconViewItem(parent), m_id(id)
CoverIconViewItem::CoverIconViewItem(coverKey id, KListWidget *parent) :
QListWidgetItem(parent), m_id(id)
{
CoverDataPtr data = CoverManager::coverInfo(id);
setText(QString("%1 - %2").arg(data->artist, data->album));
setPixmap(data->thumbnail());
setIcon(data->thumbnail());
setSizeHint(QSize(140, 150));
}
CoverIconView::CoverIconView(QWidget *parent, const char *name) : K3IconView(parent, name)
CoverIconView::CoverIconView(QWidget *parent, const char *name) : KListWidget(parent)
{
setResizeMode(Adjust);
setObjectName(name);
setResizeMode(KListWidget::Adjust);
setViewMode(KListWidget::IconMode);
setIconSize(QSize(130, 140));
setMovement(KListWidget::Static);
setContextMenuPolicy(Qt::CustomContextMenu);
}
CoverIconViewItem *CoverIconView::currentItem() const
{
return static_cast<CoverIconViewItem *>(K3IconView::currentItem());
return static_cast<CoverIconViewItem *>(KListWidget::currentItem());
}
// TODO: port to Qt4
#if 0
Q3DragObject *CoverIconView::dragObject()
{
#if 0
// Temporarily disabled pending conversion of the cover manager icon view
// to Qt 4 ish stuff.
CoverIconViewItem *item = currentItem();
if(item)
return new CoverDrag(item->id(), this);
#endif
return 0;
}
#endif
// vim: set et sw=4 tw=0 sta:
/***************************************************************************
begin : Sat Jul 9 2005
copyright : (C) 2005 by Michael Pyne
: (C) 2014 by Arnold Dumas <contact@arnolddumas.fr>
email : michael.pyne@kdemail.net
***************************************************************************/
......@@ -16,7 +17,7 @@
#ifndef COVERICONVIEW_H
#define COVERICONVIEW_H
#include <k3iconview.h>
#include <klistwidget.h>
#include "covermanager.h"
......@@ -27,10 +28,10 @@
namespace CoverUtility
{
class CoverIconViewItem : public K3IconViewItem
class CoverIconViewItem : public QListWidgetItem
{
public:
CoverIconViewItem(coverKey id, Q3IconView *parent);
CoverIconViewItem(coverKey id, KListWidget *parent);
coverKey id() const { return m_id; }
......@@ -42,12 +43,12 @@ namespace CoverUtility
using CoverUtility::CoverIconViewItem;
/**
* This class subclasses K3IconView in order to provide cover drag-and-drop
* This class subclasses KListWidget in order to provide cover drag-and-drop
* support.
*
* @author Michael Pyne <michael.pyne@kdemail.net>
*/
class CoverIconView : public K3IconView
class CoverIconView : public KListWidget
{
public:
explicit CoverIconView(QWidget *parent, const char *name = 0);
......@@ -55,7 +56,7 @@ public:
CoverIconViewItem *currentItem() const;
protected:
virtual Q3DragObject *dragObject();
// virtual Q3DragObject *dragObject();
};
#endif /* COVERICONVIEW_H */
......
......@@ -47,8 +47,7 @@
#include "mediafiles.h"
#include "collectionlist.h"
#include "playlistsearch.h"
#include "playlistitem.h"
#include "playlist/playlistsearch.h"
#include "tag.h"
struct CoverPopup : public QWidget
......@@ -171,11 +170,11 @@ void CoverInfo::applyCoverToWholeAlbum(bool overwriteExistingCovers) const
PlaylistSearch::ComponentList components;
ColumnList columns;
columns.append(PlaylistItem::ArtistColumn);
columns.append(Playlist::ArtistColumn);
components.append(PlaylistSearch::Component(artist, false, columns, PlaylistSearch::Component::Exact));
columns.clear();
columns.append(PlaylistItem::AlbumColumn);
columns.append(Playlist::AlbumColumn);
components.append(PlaylistSearch::Component(album, false, columns, PlaylistSearch::Component::Exact));
PlaylistList playlists;
......@@ -185,16 +184,18 @@ void CoverInfo::applyCoverToWholeAlbum(bool overwriteExistingCovers) const
// Search done, iterate through results.
PlaylistItemList results = search.matchedItems();
PlaylistItemList::ConstIterator it = results.constBegin();
QModelIndexList results = search.matchedItems();
QModelIndexList::ConstIterator it = results.constBegin();
for(; it != results.constEnd(); ++it) {
// Don't worry about files that somehow already have a tag,
// unless the conversion is forced.
if(!overwriteExistingCovers && (*it)->file().coverInfo()->coverId() != CoverManager::NoMatch)
const Playlist *playlist= qobject_cast<const Playlist*>(it->model());
const FileHandle &file = playlist->data(*it, Qt::UserRole).value<FileHandle>();
if(!overwriteExistingCovers && file.coverInfo()->coverId() != CoverManager::NoMatch)
continue;
(*it)->file().coverInfo()->setCoverId(m_coverKey);
file.coverInfo()->setCoverId(m_coverKey);
}
}
......
......@@ -23,7 +23,7 @@
#include <kdebug.h>
#include "collectionadaptor.h"
#include "playlistcollection.h"
#include "playlist/playlistcollection.h"
#include "covermanager.h"
#include "collectionlist.h"
#include "coverinfo.h"
......@@ -119,12 +119,12 @@ QString DBusCollectionProxy::trackCover(const QString &track)
}
// No cover, let's see if one is embedded.
CollectionListItem *collectionItem = CollectionList::instance()->lookup(track);
const FileHandle &file = CollectionList::instance()->lookup(track);
if(!collectionItem)
if(file.isNull())
return QString();
CoverInfo *coverInfo = collectionItem->file().coverInfo();
CoverInfo *coverInfo = file.coverInfo();
if(!coverInfo)
return QString();
......
......@@ -27,6 +27,12 @@
#include "cache.h"
#include "coverinfo.h"
/**
* Used to give every track added in the program a unique identifier. See
* PlaylistItem
*/
quint32 g_trackID = 0;
AddProperty(Title, tag()->title())
AddProperty(Artist, tag()->artist())
AddProperty(Album, tag()->album())
......@@ -70,7 +76,10 @@ class FileHandle::FileHandlePrivate : public RefCounter
public:
FileHandlePrivate() :
tag(0),
coverInfo(0) {}
coverInfo(0),
id(g_trackID++)
{
}
~FileHandlePrivate()
{
......@@ -84,6 +93,7 @@ public:
QFileInfo fileInfo;
QDateTime modificationTime;
QDateTime lastModified;
quint32 id;
};
////////////////////////////////////////////////////////////////////////////////
......@@ -214,6 +224,11 @@ const QDateTime &FileHandle::lastModified() const
return d->lastModified;
}
quint32 FileHandle::id() const
{
return d->id;
}
void FileHandle::read(CacheDataStream &s)
{
switch(s.cacheVersion()) {
......
......@@ -17,6 +17,7 @@
#define FILEHANDLE_H
#include <QString>
#include <QMetaType>
class QFileInfo;
class QDateTime;
......@@ -70,6 +71,8 @@ public:
QString property(const QString &name) const;
static const FileHandle &null();
quint32 id() const;
private:
class FileHandlePrivate;
......@@ -78,6 +81,8 @@ private:
void setup(const QFileInfo &info, const QString &path);
};
Q_DECLARE_METATYPE(FileHandle);
typedef QList<FileHandle> FileHandleList;
QDataStream &operator<<(QDataStream &s, const FileHandle &f);
......
......@@ -2,6 +2,7 @@
begin : Thu Oct 28 2004
copyright : (C) 2004, 2007, 2009 by Michael Pyne
: (c) 2003 Frerich Raabe <raabe@kde.org>
: (C) 2014 Arnold Dumas <contact@arnolddumas.fr>
email : mpyne@kde.org
***************************************************************************/
......@@ -44,14 +45,14 @@
#include <QSignalMapper>
#include <QPixmap>
#include <QFrame>
#include <Q3Header>
#include <QScrollBar>
#include <QTreeWidget>
#include "tag.h"
#include "filerenameroptions.h"
#include "filehandle.h"
#include "exampleoptions.h"
#include "playlistitem.h"
#include "playlist.h" // processEvents()
#include "playlist/playlists/playlist.h" // processEvents()
#include "coverinfo.h"
class ConfirmationDialog : public KDialog
......@@ -77,24 +78,38 @@ public:
"Are you sure you want to continue?"), hbox);
hbox->setStretchFactor(l, 1);
K3ListView *lv = new K3ListView(vbox);
QTreeWidget *lv = new QTreeWidget(vbox);
lv->addColumn(i18n("Original Name"));
lv->addColumn(i18n("New Name"));
QStringList headers;
headers << i18n("Original Name");
headers << i18n("New Name");
lv->setHeaderLabels(headers);
lv->setRootIsDecorated(false);
int lvHeight = 0;
QMap<QString, QString>::ConstIterator it = files.constBegin();
for(; it != files.constEnd(); ++it) {
K3ListViewItem *i = it.key() != it.value()
? new K3ListViewItem(lv, it.key(), it.value())
: new K3ListViewItem(lv, it.key(), i18n("No Change"));
lvHeight += i->height();
QTreeWidgetItem *item = new QTreeWidgetItem(lv);
item->setText(0, it.key());
if (it.key() != it.value()) {
item->setText(1, it.value());
}
else {
item->setText(1, i18n("No Change"));
}
lvHeight += lv->visualItemRect(item).height();
}
lvHeight += lv->horizontalScrollBar()->height() + lv->header()->height();
lv->setMinimumHeight(qMin(lvHeight, 400));
resize(qMin(width(), 500), qMin(minimumHeight(), 400));
show();
}
};
......@@ -142,10 +157,10 @@ ConfigCategoryReader::ConfigCategoryReader() : CategoryReaderInterface(),
QString ConfigCategoryReader::categoryValue(TagType type) const
{
if(!m_currentItem)
if(m_currentItem.isNull())
return QString();
Tag *tag = m_currentItem->file().tag();
Tag *tag = m_currentItem.tag();
switch(type) {
case Track:
......@@ -853,30 +868,30 @@ FileRenamer::FileRenamer()
{
}
void FileRenamer::rename(PlaylistItem *item)
void FileRenamer::rename(const FileHandle& file)
{
PlaylistItemList list;
list.append(item);
FileHandleList list;
list.append(file);
rename(list);
}
void FileRenamer::rename(const PlaylistItemList &items)
void FileRenamer::rename(const FileHandleList& files)
{
ConfigCategoryReader reader;
QStringList errorFiles;
QMap<QString, QString> map;
QMap<QString, PlaylistItem *> itemMap;
QMap<QString, FileHandle> itemMap;
for(PlaylistItemList::ConstIterator it = items.constBegin(); it != items.constEnd(); ++it) {
reader.setPlaylistItem(*it);
QString oldFile = (*it)->file().absFilePath();
QString extension = (*it)->file().fileInfo().suffix();
foreach(const FileHandle &file, files) {
reader.setPlaylistItem(file);
QString oldFile = file.absFilePath();
QString extension = file.fileInfo().suffix();
QString newFile = fileName(reader) + '.' + extension;
if(oldFile != newFile) {
map[oldFile] = newFile;
itemMap[oldFile] = *it;
itemMap[oldFile] = file;
}
}
......@@ -888,8 +903,8 @@ void FileRenamer::rename(const PlaylistItemList &items)
it != map.constEnd(); ++it)
{
if(moveFile(it.key(), it.value())) {
itemMap[it.key()]->setFile(it.value());
itemMap[it.key()]->refresh();
itemMap[it.key()].setFile(it.value());
itemMap[it.key()].refresh();
setFolderIcon(it.value(), itemMap[it.key()]);
}
......@@ -939,10 +954,10 @@ bool FileRenamer::moveFile(const QString &src, const QString &dest)
return KIO::NetAccess::synchronousRun(job, 0);
}
void FileRenamer::setFolderIcon(const KUrl &dst, const PlaylistItem *item)
void FileRenamer::setFolderIcon(const KUrl& dst, const FileHandle& file)
{
if(item->file().tag()->album().isEmpty() ||
!item->file().coverInfo()->hasCover())
if(file.tag()->album().isEmpty() ||
!file.coverInfo()->hasCover())
{
return;
}
......@@ -959,13 +974,13 @@ void FileRenamer::setFolderIcon(const KUrl &dst, const PlaylistItem *item)
path.append('/' + (*it));
kDebug() << "Checking path: " << path;
if((*it).contains(item->file().tag()->album() ) &&
if((*it).contains(file.tag()->album() ) &&
!QFile::exists(path + "/.directory"))