mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-28 18:19:42 +01:00
Merge branch 'master' into drive
Conflicts: data/data.qrc
This commit is contained in:
commit
517252ccc1
1
3rdparty/qocoa/CMakeLists.txt
vendored
1
3rdparty/qocoa/CMakeLists.txt
vendored
@ -21,7 +21,6 @@ else()
|
||||
qprogressindicatorspinning_nonmac.cpp
|
||||
)
|
||||
set(RESOURCES
|
||||
qsearchfield_nonmac.qrc
|
||||
qprogressindicatorspinning_nonmac.qrc
|
||||
)
|
||||
qt4_add_resources(RESOURCES_SOURCES ${RESOURCES})
|
||||
|
16
3rdparty/qocoa/qsearchfield.h
vendored
16
3rdparty/qocoa/qsearchfield.h
vendored
@ -3,18 +3,6 @@
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPointer>
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
|
||||
// Currently the old LineEdit is better than the current qsearchfield_nonmac
|
||||
// IMHO: add this (ugly) hack to force non Mac systems to use the old LineEdit.
|
||||
// TODO: Fix this in a better way (improve qsearchfield_nonmac definitely?)
|
||||
|
||||
class LineEdit;
|
||||
typedef LineEdit QSearchField;
|
||||
|
||||
#else // Q_OS_MAC
|
||||
|
||||
class QSearchFieldPrivate;
|
||||
class QSearchField : public QWidget
|
||||
@ -25,12 +13,14 @@ public:
|
||||
|
||||
QString text() const;
|
||||
QString placeholderText() const;
|
||||
void setFocus(Qt::FocusReason reason);
|
||||
|
||||
public slots:
|
||||
void setText(const QString &text);
|
||||
void setPlaceholderText(const QString &text);
|
||||
void clear();
|
||||
void selectAll();
|
||||
void setFocus();
|
||||
|
||||
signals:
|
||||
void textChanged(const QString &text);
|
||||
@ -48,6 +38,4 @@ private:
|
||||
Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText);
|
||||
};
|
||||
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
#endif // QSEARCHFIELD_H
|
||||
|
68
3rdparty/qocoa/qsearchfield_mac.mm
vendored
68
3rdparty/qocoa/qsearchfield_mac.mm
vendored
@ -28,6 +28,9 @@ THE SOFTWARE.
|
||||
#import "Foundation/NSNotification.h"
|
||||
#import "AppKit/NSSearchField.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
|
||||
class QSearchFieldPrivate : public QObject
|
||||
{
|
||||
public:
|
||||
@ -82,11 +85,59 @@ public:
|
||||
}
|
||||
@end
|
||||
|
||||
namespace {
|
||||
|
||||
static const unsigned short kKeycodeA = 0;
|
||||
static const unsigned short kKeycodeX = 7;
|
||||
static const unsigned short kKeycodeC = 8;
|
||||
static const unsigned short kKeycodeV = 9;
|
||||
|
||||
} // namespace
|
||||
|
||||
@interface QocoaSearchField : NSSearchField
|
||||
-(BOOL)performKeyEquivalent:(NSEvent*)event;
|
||||
@end
|
||||
|
||||
@implementation QocoaSearchField
|
||||
-(BOOL)performKeyEquivalent:(NSEvent*)event {
|
||||
if ([event type] == NSKeyDown && [event modifierFlags] & NSCommandKeyMask)
|
||||
{
|
||||
const unsigned short keyCode = [event keyCode];
|
||||
if (keyCode == kKeycodeA) // Cmd+a
|
||||
{
|
||||
[self performSelector:@selector(selectText:)];
|
||||
return YES;
|
||||
}
|
||||
else if (keyCode == kKeycodeC) // Cmd+c
|
||||
{
|
||||
QClipboard* clipboard = QApplication::clipboard();
|
||||
clipboard->setText(toQString([self stringValue]));
|
||||
return YES;
|
||||
}
|
||||
else if (keyCode == kKeycodeV) // Cmd+v
|
||||
{
|
||||
QClipboard* clipboard = QApplication::clipboard();
|
||||
[self setStringValue:fromQString(clipboard->text())];
|
||||
return YES;
|
||||
}
|
||||
else if (keyCode == kKeycodeX) // Cmd+x
|
||||
{
|
||||
QClipboard* clipboard = QApplication::clipboard();
|
||||
clipboard->setText(toQString([self stringValue]));
|
||||
[self setStringValue:@""];
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
@end
|
||||
|
||||
QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
NSSearchField *search = [[NSSearchField alloc] init];
|
||||
NSSearchField *search = [[QocoaSearchField alloc] init];
|
||||
|
||||
QSearchFieldDelegate *delegate = [[QSearchFieldDelegate alloc] init];
|
||||
pimpl = delegate->pimpl = new QSearchFieldPrivate(this, search);
|
||||
@ -130,6 +181,21 @@ QString QSearchField::placeholderText() const {
|
||||
return toQString(placeholder);
|
||||
}
|
||||
|
||||
void QSearchField::setFocus(Qt::FocusReason reason)
|
||||
{
|
||||
Q_ASSERT(pimpl);
|
||||
if (!pimpl)
|
||||
return;
|
||||
|
||||
if ([pimpl->nsSearchField acceptsFirstResponder])
|
||||
[[pimpl->nsSearchField window] makeFirstResponder: pimpl->nsSearchField];
|
||||
}
|
||||
|
||||
void QSearchField::setFocus()
|
||||
{
|
||||
setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
|
||||
void QSearchField::clear()
|
||||
{
|
||||
Q_ASSERT(pimpl);
|
||||
|
42
3rdparty/qocoa/qsearchfield_nonmac.cpp
vendored
42
3rdparty/qocoa/qsearchfield_nonmac.cpp
vendored
@ -21,6 +21,7 @@ THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qsearchfield.h"
|
||||
#include "../../src/ui/iconloader.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QEvent>
|
||||
@ -32,9 +33,6 @@ THE SOFTWARE.
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#if 0
|
||||
// All the code below isn't used currently (see qsearchfield.h)
|
||||
|
||||
class QSearchFieldPrivate : public QObject
|
||||
{
|
||||
public:
|
||||
@ -65,20 +63,22 @@ QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
|
||||
connect(lineEdit, SIGNAL(textChanged(QString)),
|
||||
this, SLOT(setText(QString)));
|
||||
|
||||
QIcon clearIcon(IconLoader::Load("edit-clear-locationbar-ltr"));
|
||||
|
||||
QToolButton *clearButton = new QToolButton(this);
|
||||
QPixmap clearIcon(QString(":/Qocoa/qsearchfield_nonmac.png"));
|
||||
clearButton->setIcon(QIcon(clearIcon));
|
||||
clearButton->setIconSize(clearIcon.size());
|
||||
clearButton->setFixedSize(clearIcon.size());
|
||||
clearButton->setStyleSheet("border: none;");
|
||||
clearButton->hide();
|
||||
clearButton->setIcon(clearIcon);
|
||||
clearButton->setIconSize(QSize(16, 16));
|
||||
clearButton->setStyleSheet("border: none; padding: 0px;");
|
||||
clearButton->resize(clearButton->sizeHint());
|
||||
connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
|
||||
|
||||
pimpl = new QSearchFieldPrivate(this, lineEdit, clearButton);
|
||||
|
||||
lineEdit->setStyleSheet(QString("QLineEdit { padding-right: %1px; } ").arg(pimpl->clearButtonPaddedWidth()));
|
||||
const int width = qMax(lineEdit->minimumSizeHint().width(), pimpl->clearButtonPaddedWidth());
|
||||
const int height = qMax(lineEdit->minimumSizeHint().height(), pimpl->clearButtonPaddedHeight());
|
||||
const int frame_width = lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||
|
||||
lineEdit->setStyleSheet(QString("QLineEdit { padding-left: %1px; } ").arg(clearButton->width()));
|
||||
const int width = frame_width + qMax(lineEdit->minimumSizeHint().width(), pimpl->clearButtonPaddedWidth());
|
||||
const int height = frame_width + qMax(lineEdit->minimumSizeHint().height(), pimpl->clearButtonPaddedHeight());
|
||||
lineEdit->setMinimumSize(width, height);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
@ -94,8 +94,6 @@ void QSearchField::setText(const QString &text)
|
||||
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit))
|
||||
return;
|
||||
|
||||
pimpl->clearButton->setVisible(!text.isEmpty());
|
||||
|
||||
if (text != this->text())
|
||||
pimpl->lineEdit->setText(text);
|
||||
}
|
||||
@ -119,6 +117,18 @@ QString QSearchField::placeholderText() const {
|
||||
#endif
|
||||
}
|
||||
|
||||
void QSearchField::setFocus(Qt::FocusReason reason)
|
||||
{
|
||||
Q_ASSERT(pimpl && pimpl->lineEdit);
|
||||
if (pimpl && pimpl->lineEdit)
|
||||
pimpl->lineEdit->setFocus(reason);
|
||||
}
|
||||
|
||||
void QSearchField::setFocus()
|
||||
{
|
||||
setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
|
||||
void QSearchField::clear()
|
||||
{
|
||||
Q_ASSERT(pimpl && pimpl->lineEdit);
|
||||
@ -153,7 +163,7 @@ void QSearchField::resizeEvent(QResizeEvent *resizeEvent)
|
||||
return;
|
||||
|
||||
QWidget::resizeEvent(resizeEvent);
|
||||
const int x = width() - pimpl->clearButtonPaddedWidth();
|
||||
const int x = pimpl->lineEditFrameWidth();
|
||||
const int y = (height() - pimpl->clearButton->height())/2;
|
||||
pimpl->clearButton->move(x, y);
|
||||
}
|
||||
@ -172,5 +182,3 @@ bool QSearchField::eventFilter(QObject *o, QEvent *e)
|
||||
}
|
||||
return QWidget::eventFilter(o, e);
|
||||
}
|
||||
|
||||
#endif // 0
|
||||
|
BIN
3rdparty/qocoa/qsearchfield_nonmac.png
vendored
BIN
3rdparty/qocoa/qsearchfield_nonmac.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 644 B |
5
3rdparty/qocoa/qsearchfield_nonmac.qrc
vendored
5
3rdparty/qocoa/qsearchfield_nonmac.qrc
vendored
@ -1,5 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/Qocoa">
|
||||
<file>qsearchfield_nonmac.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
372
data/data.qrc
372
data/data.qrc
@ -1,73 +1,42 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>mainwindow.css</file>
|
||||
<file>songinfo.css</file>
|
||||
<file>now_playing_tooltip.txt</file>
|
||||
<file>schema/schema.sql</file>
|
||||
<file>volumeslider-handle_glow.png</file>
|
||||
<file>volumeslider-handle.png</file>
|
||||
<file>volumeslider-inset.png</file>
|
||||
<file>volumeslider-gradient.png</file>
|
||||
<file>logo.png</file>
|
||||
<file>icon.png</file>
|
||||
<file>icon_large.png</file>
|
||||
<file>icon_large_grey.png</file>
|
||||
<file>blank.ttf</file>
|
||||
<file>clementine-spotify-public.pem</file>
|
||||
<file>currenttrack_bar_left.png</file>
|
||||
<file>currenttrack_bar_mid.png</file>
|
||||
<file>currenttrack_bar_right.png</file>
|
||||
<file>currenttrack_pause.png</file>
|
||||
<file>currenttrack_play.png</file>
|
||||
<file>nomusic.png</file>
|
||||
<file>last.fm/as.png</file>
|
||||
<file>last.fm/lastfm.png</file>
|
||||
<file>last.fm/loved_radio.png</file>
|
||||
<file>last.fm/neighbour_radio.png</file>
|
||||
<file>last.fm/personal_radio.png</file>
|
||||
<file>last.fm/recommended_radio.png</file>
|
||||
<file>spinner.gif</file>
|
||||
<file>last.fm/ban.png</file>
|
||||
<file>last.fm/love.png</file>
|
||||
<file>last.fm/icon_radio.png</file>
|
||||
<file>last.fm/icon_tag.png</file>
|
||||
<file>last.fm/icon_user.png</file>
|
||||
<file>last.fm/my_friends.png</file>
|
||||
<file>last.fm/my_neighbours.png</file>
|
||||
<file>last.fm/user_purple.png</file>
|
||||
<file>providers/somafm.png</file>
|
||||
<file>schema/schema-1.sql</file>
|
||||
<file>schema/schema-2.sql</file>
|
||||
<file>nocover.png</file>
|
||||
<file>schema/schema-3.sql</file>
|
||||
<file>schema/schema-4.sql</file>
|
||||
<file>schema/schema-5.sql</file>
|
||||
<file>osd_shadow_corner.png</file>
|
||||
<file>osd_shadow_edge.png</file>
|
||||
<file>schema/schema-6.sql</file>
|
||||
<file>schema/schema-7.sql</file>
|
||||
<file>tiny-pause.png</file>
|
||||
<file>tiny-start.png</file>
|
||||
<file>providers/magnatune.png</file>
|
||||
<file>schema/schema-8.sql</file>
|
||||
<file>schema/schema-9.sql</file>
|
||||
<file>icons/22x22/spotify.png</file>
|
||||
<file>icons/32x32/spotify.png</file>
|
||||
<file>icons/48x48/spotify.png</file>
|
||||
<file>globalsearch.css</file>
|
||||
<file>grooveshark-valicert-ca.pem</file>
|
||||
<file>hypnotoad.gif</file>
|
||||
<file>icon_large_grey.png</file>
|
||||
<file>icon_large.png</file>
|
||||
<file>icon.png</file>
|
||||
<file>icons/22x22/application-exit.png</file>
|
||||
<file>icons/22x22/applications-internet.png</file>
|
||||
<file>icons/22x22/configure.png</file>
|
||||
<file>icons/22x22/document-open.png</file>
|
||||
<file>icons/22x22/dialog-ok-apply.png</file>
|
||||
<file>icons/22x22/dialog-warning.png</file>
|
||||
<file>icons/22x22/document-new.png</file>
|
||||
<file>icons/22x22/document-open-folder.png</file>
|
||||
<file>icons/22x22/document-open.png</file>
|
||||
<file>icons/22x22/document-open-remote.png</file>
|
||||
<file>icons/22x22/document-save.png</file>
|
||||
<file>icons/22x22/download.png</file>
|
||||
<file>icons/22x22/drive-removable-media-usb-pendrive.png</file>
|
||||
<file>icons/22x22/edit-clear-list.png</file>
|
||||
<file>icons/22x22/edit-clear-locationbar-ltr.png</file>
|
||||
<file>icons/22x22/edit-copy.png</file>
|
||||
<file>icons/22x22/edit-delete.png</file>
|
||||
<file>icons/22x22/edit-find.png</file>
|
||||
<file>icons/22x22/edit-redo.png</file>
|
||||
<file>icons/22x22/edit-rename.png</file>
|
||||
<file>icons/22x22/edit-undo.png</file>
|
||||
<file>icons/22x22/folder-new.png</file>
|
||||
<file>icons/22x22/folder.png</file>
|
||||
<file>icons/22x22/folder-sound.png</file>
|
||||
<file>icons/22x22/go-down.png</file>
|
||||
<file>icons/22x22/go-home.png</file>
|
||||
<file>icons/22x22/go-jump.png</file>
|
||||
<file>icons/22x22/go-next.png</file>
|
||||
@ -75,8 +44,12 @@
|
||||
<file>icons/22x22/go-up.png</file>
|
||||
<file>icons/22x22/help-about.png</file>
|
||||
<file>icons/22x22/help-hint.png</file>
|
||||
<file>icons/22x22/input-keyboard.png</file>
|
||||
<file>icons/22x22/ipodtouchicon.png</file>
|
||||
<file>icons/22x22/list-add.png</file>
|
||||
<file>icons/22x22/list-remove.png</file>
|
||||
<file>icons/22x22/mail-message.png</file>
|
||||
<file>icons/22x22/media-eject.png</file>
|
||||
<file>icons/22x22/media-playback-pause.png</file>
|
||||
<file>icons/22x22/media-playback-start.png</file>
|
||||
<file>icons/22x22/media-playback-stop.png</file>
|
||||
@ -84,31 +57,62 @@
|
||||
<file>icons/22x22/media-playlist-shuffle.png</file>
|
||||
<file>icons/22x22/media-skip-backward.png</file>
|
||||
<file>icons/22x22/media-skip-forward.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-mini-blue.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-mini-gold.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-mini-green.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-mini-pink.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-mini-silver.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-nano-black.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-nano-green.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-nano-white.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-shuffle.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-standard-color.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-standard-monochrome.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-U2-color.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-U2-monochrome.png</file>
|
||||
<file>icons/22x22/network-server.png</file>
|
||||
<file>icons/22x22/phone-google-nexus-one.png</file>
|
||||
<file>icons/22x22/phone-htc-g1-white.png</file>
|
||||
<file>icons/22x22/phone-nokia-n900.png</file>
|
||||
<file>icons/22x22/phone-palm-pre.png</file>
|
||||
<file>icons/22x22/phone.png</file>
|
||||
<file>icons/22x22/spotify.png</file>
|
||||
<file>icons/22x22/user-away.png</file>
|
||||
<file>icons/22x22/view-choose.png</file>
|
||||
<file>icons/22x22/view-fullscreen.png</file>
|
||||
<file>icons/22x22/view-media-equalizer.png</file>
|
||||
<file>icons/22x22/view-media-lyrics.png</file>
|
||||
<file>icons/22x22/view-media-playlist.png</file>
|
||||
<file>icons/22x22/view-media-visualization.png</file>
|
||||
<file>icons/22x22/view-refresh.png</file>
|
||||
<file>icons/22x22/weather-showers-scattered.png</file>
|
||||
<file>icons/22x22/x-clementine-album.png</file>
|
||||
<file>icons/22x22/x-clementine-albums.png</file>
|
||||
<file>icons/22x22/x-clementine-artist.png</file>
|
||||
<file>icons/22x22/x-clementine-shuffle.png</file>
|
||||
<file>icons/22x22/zoom-in.png</file>
|
||||
<file>icons/32x32/application-exit.png</file>
|
||||
<file>icons/32x32/applications-internet.png</file>
|
||||
<file>icons/32x32/configure.png</file>
|
||||
<file>icons/32x32/document-open.png</file>
|
||||
<file>icons/32x32/document-new.png</file>
|
||||
<file>icons/32x32/document-open-folder.png</file>
|
||||
<file>icons/32x32/document-open.png</file>
|
||||
<file>icons/32x32/document-open-remote.png</file>
|
||||
<file>icons/32x32/document-save.png</file>
|
||||
<file>icons/32x32/download.png</file>
|
||||
<file>icons/32x32/drive-removable-media-usb-pendrive.png</file>
|
||||
<file>icons/32x32/edit-clear-list.png</file>
|
||||
<file>icons/32x32/edit-clear-locationbar-ltr.png</file>
|
||||
<file>icons/32x32/edit-copy.png</file>
|
||||
<file>icons/32x32/edit-delete.png</file>
|
||||
<file>icons/32x32/edit-find.png</file>
|
||||
<file>icons/32x32/edit-redo.png</file>
|
||||
<file>icons/32x32/edit-rename.png</file>
|
||||
<file>icons/32x32/edit-undo.png</file>
|
||||
<file>icons/32x32/folder-new.png</file>
|
||||
<file>icons/32x32/folder.png</file>
|
||||
<file>icons/32x32/folder-sound.png</file>
|
||||
<file>icons/32x32/go-down.png</file>
|
||||
<file>icons/32x32/go-home.png</file>
|
||||
<file>icons/32x32/go-jump.png</file>
|
||||
<file>icons/32x32/go-next.png</file>
|
||||
@ -116,8 +120,12 @@
|
||||
<file>icons/32x32/go-up.png</file>
|
||||
<file>icons/32x32/help-about.png</file>
|
||||
<file>icons/32x32/help-hint.png</file>
|
||||
<file>icons/32x32/input-keyboard.png</file>
|
||||
<file>icons/32x32/ipodtouchicon.png</file>
|
||||
<file>icons/32x32/list-add.png</file>
|
||||
<file>icons/32x32/list-remove.png</file>
|
||||
<file>icons/32x32/mail-message.png</file>
|
||||
<file>icons/32x32/media-eject.png</file>
|
||||
<file>icons/32x32/media-playback-pause.png</file>
|
||||
<file>icons/32x32/media-playback-start.png</file>
|
||||
<file>icons/32x32/media-playback-stop.png</file>
|
||||
@ -125,31 +133,62 @@
|
||||
<file>icons/32x32/media-playlist-shuffle.png</file>
|
||||
<file>icons/32x32/media-skip-backward.png</file>
|
||||
<file>icons/32x32/media-skip-forward.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-mini-blue.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-mini-gold.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-mini-green.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-mini-pink.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-mini-silver.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-nano-black.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-nano-green.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-nano-white.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-shuffle.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-standard-color.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-standard-monochrome.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-U2-color.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-U2-monochrome.png</file>
|
||||
<file>icons/32x32/network-server.png</file>
|
||||
<file>icons/32x32/phone-google-nexus-one.png</file>
|
||||
<file>icons/32x32/phone-htc-g1-white.png</file>
|
||||
<file>icons/32x32/phone-nokia-n900.png</file>
|
||||
<file>icons/32x32/phone-palm-pre.png</file>
|
||||
<file>icons/32x32/phone.png</file>
|
||||
<file>icons/32x32/search.png</file>
|
||||
<file>icons/32x32/spotify.png</file>
|
||||
<file>icons/32x32/tools-wizard.png</file>
|
||||
<file>icons/32x32/view-choose.png</file>
|
||||
<file>icons/32x32/view-fullscreen.png</file>
|
||||
<file>icons/32x32/view-media-equalizer.png</file>
|
||||
<file>icons/32x32/view-media-lyrics.png</file>
|
||||
<file>icons/32x32/view-media-playlist.png</file>
|
||||
<file>icons/32x32/view-media-visualization.png</file>
|
||||
<file>icons/32x32/view-refresh.png</file>
|
||||
<file>icons/32x32/weather-showers-scattered.png</file>
|
||||
<file>icons/32x32/wiimotedev.png</file>
|
||||
<file>icons/32x32/x-clementine-artist.png</file>
|
||||
<file>icons/32x32/x-clementine-shuffle.png</file>
|
||||
<file>icons/32x32/zoom-in.png</file>
|
||||
<file>icons/48x48/application-exit.png</file>
|
||||
<file>icons/48x48/applications-internet.png</file>
|
||||
<file>icons/48x48/configure.png</file>
|
||||
<file>icons/48x48/document-open.png</file>
|
||||
<file>icons/48x48/document-new.png</file>
|
||||
<file>icons/48x48/document-open-folder.png</file>
|
||||
<file>icons/48x48/document-open.png</file>
|
||||
<file>icons/48x48/document-open-remote.png</file>
|
||||
<file>icons/48x48/document-save.png</file>
|
||||
<file>icons/48x48/download.png</file>
|
||||
<file>icons/48x48/drive-removable-media-usb-pendrive.png</file>
|
||||
<file>icons/48x48/edit-clear-list.png</file>
|
||||
<file>icons/48x48/edit-clear-locationbar-ltr.png</file>
|
||||
<file>icons/48x48/edit-copy.png</file>
|
||||
<file>icons/48x48/edit-delete.png</file>
|
||||
<file>icons/48x48/edit-find.png</file>
|
||||
<file>icons/48x48/edit-redo.png</file>
|
||||
<file>icons/48x48/edit-rename.png</file>
|
||||
<file>icons/48x48/edit-undo.png</file>
|
||||
<file>icons/48x48/folder-new.png</file>
|
||||
<file>icons/48x48/folder.png</file>
|
||||
<file>icons/48x48/folder-sound.png</file>
|
||||
<file>icons/48x48/go-down.png</file>
|
||||
<file>icons/48x48/go-home.png</file>
|
||||
<file>icons/48x48/go-jump.png</file>
|
||||
<file>icons/48x48/go-next.png</file>
|
||||
@ -157,8 +196,12 @@
|
||||
<file>icons/48x48/go-up.png</file>
|
||||
<file>icons/48x48/help-about.png</file>
|
||||
<file>icons/48x48/help-hint.png</file>
|
||||
<file>icons/48x48/input-keyboard.png</file>
|
||||
<file>icons/48x48/ipodtouchicon.png</file>
|
||||
<file>icons/48x48/list-add.png</file>
|
||||
<file>icons/48x48/list-remove.png</file>
|
||||
<file>icons/48x48/mail-message.png</file>
|
||||
<file>icons/48x48/media-eject.png</file>
|
||||
<file>icons/48x48/media-optical.png</file>
|
||||
<file>icons/48x48/media-playback-pause.png</file>
|
||||
<file>icons/48x48/media-playback-start.png</file>
|
||||
@ -167,185 +210,142 @@
|
||||
<file>icons/48x48/media-playlist-shuffle.png</file>
|
||||
<file>icons/48x48/media-skip-backward.png</file>
|
||||
<file>icons/48x48/media-skip-forward.png</file>
|
||||
<file>icons/48x48/view-choose.png</file>
|
||||
<file>icons/48x48/view-media-equalizer.png</file>
|
||||
<file>icons/48x48/view-media-lyrics.png</file>
|
||||
<file>icons/48x48/view-media-playlist.png</file>
|
||||
<file>icons/48x48/view-media-visualization.png</file>
|
||||
<file>icons/48x48/view-refresh.png</file>
|
||||
<file>icons/48x48/weather-showers-scattered.png</file>
|
||||
<file>icons/48x48/x-clementine-shuffle.png</file>
|
||||
<file>icons/48x48/zoom-in.png</file>
|
||||
<file>icons/22x22/x-clementine-album.png</file>
|
||||
<file>icons/22x22/x-clementine-albums.png</file>
|
||||
<file>icons/22x22/x-clementine-artist.png</file>
|
||||
<file>icons/32x32/x-clementine-artist.png</file>
|
||||
<file>icons/48x48/x-clementine-artist.png</file>
|
||||
<file>icons/22x22/document-new.png</file>
|
||||
<file>icons/32x32/document-new.png</file>
|
||||
<file>icons/48x48/document-new.png</file>
|
||||
<file>schema/schema-10.sql</file>
|
||||
<file>schema/schema-11.sql</file>
|
||||
<file>osd_background.png</file>
|
||||
<file>icons/22x22/view-fullscreen.png</file>
|
||||
<file>icons/32x32/view-fullscreen.png</file>
|
||||
<file>icons/48x48/view-fullscreen.png</file>
|
||||
<file>schema/schema-12.sql</file>
|
||||
<file>schema/schema-13.sql</file>
|
||||
<file>icons/22x22/input-keyboard.png</file>
|
||||
<file>icons/32x32/input-keyboard.png</file>
|
||||
<file>icons/48x48/input-keyboard.png</file>
|
||||
<file>icons/22x22/edit-delete.png</file>
|
||||
<file>icons/32x32/edit-delete.png</file>
|
||||
<file>icons/48x48/edit-delete.png</file>
|
||||
<file>schema/schema-14.sql</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-mini-blue.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-mini-gold.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-mini-green.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-mini-pink.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-mini-silver.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-nano-black.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-nano-white.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-nano-green.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-shuffle.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-standard-color.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-standard-monochrome.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-U2-color.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-U2-monochrome.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-mini-blue.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-mini-gold.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-mini-green.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-mini-pink.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-mini-silver.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-nano-black.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-nano-white.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-nano-green.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-shuffle.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-standard-color.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-standard-monochrome.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-U2-color.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-U2-monochrome.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-mini-blue.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-mini-gold.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-mini-green.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-mini-pink.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-mini-silver.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-nano-black.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-nano-white.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-nano-green.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-nano-white.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-shuffle.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-standard-color.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-standard-monochrome.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-U2-color.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-U2-monochrome.png</file>
|
||||
<file>icons/22x22/phone-google-nexus-one.png</file>
|
||||
<file>icons/22x22/phone-htc-g1-white.png</file>
|
||||
<file>icons/22x22/phone-nokia-n900.png</file>
|
||||
<file>icons/22x22/phone-palm-pre.png</file>
|
||||
<file>icons/32x32/phone-google-nexus-one.png</file>
|
||||
<file>icons/32x32/phone-htc-g1-white.png</file>
|
||||
<file>icons/32x32/phone-nokia-n900.png</file>
|
||||
<file>icons/32x32/phone-palm-pre.png</file>
|
||||
<file>icons/48x48/network-server.png</file>
|
||||
<file>icons/48x48/phone-google-nexus-one.png</file>
|
||||
<file>icons/48x48/phone-htc-g1-white.png</file>
|
||||
<file>icons/48x48/phone-nokia-n900.png</file>
|
||||
<file>icons/48x48/phone-palm-pre.png</file>
|
||||
<file>icons/22x22/phone.png</file>
|
||||
<file>icons/32x32/phone.png</file>
|
||||
<file>icons/48x48/phone.png</file>
|
||||
<file>icons/22x22/drive-removable-media-usb-pendrive.png</file>
|
||||
<file>icons/32x32/drive-removable-media-usb-pendrive.png</file>
|
||||
<file>icons/48x48/drive-removable-media-usb-pendrive.png</file>
|
||||
<file>schema/schema-15.sql</file>
|
||||
<file>schema/device-schema.sql</file>
|
||||
<file>icons/22x22/go-down.png</file>
|
||||
<file>icons/32x32/go-down.png</file>
|
||||
<file>icons/48x48/go-down.png</file>
|
||||
<file>hypnotoad.gif</file>
|
||||
<file>blank.ttf</file>
|
||||
<file>schema/schema-16.sql</file>
|
||||
<file>icons/22x22/media-eject.png</file>
|
||||
<file>icons/32x32/media-eject.png</file>
|
||||
<file>icons/48x48/media-eject.png</file>
|
||||
<file>icons/22x22/ipodtouchicon.png</file>
|
||||
<file>icons/32x32/ipodtouchicon.png</file>
|
||||
<file>icons/48x48/ipodtouchicon.png</file>
|
||||
<file>icons/32x32/wiimotedev.png</file>
|
||||
<file>schema/schema-17.sql</file>
|
||||
<file>icons/48x48/spotify.png</file>
|
||||
<file>icons/48x48/view-choose.png</file>
|
||||
<file>icons/48x48/view-fullscreen.png</file>
|
||||
<file>icons/48x48/view-media-equalizer.png</file>
|
||||
<file>icons/48x48/view-media-lyrics.png</file>
|
||||
<file>icons/48x48/view-media-playlist.png</file>
|
||||
<file>icons/48x48/view-media-visualization.png</file>
|
||||
<file>icons/48x48/view-refresh.png</file>
|
||||
<file>icons/48x48/weather-showers-scattered.png</file>
|
||||
<file>icons/48x48/x-clementine-artist.png</file>
|
||||
<file>icons/48x48/x-clementine-shuffle.png</file>
|
||||
<file>icons/48x48/zoom-in.png</file>
|
||||
<file>last.fm/as_disabled.png</file>
|
||||
<file>last.fm/as_light.png</file>
|
||||
<file>last.fm/as.png</file>
|
||||
<file>last.fm/ban.png</file>
|
||||
<file>last.fm/icon_radio.png</file>
|
||||
<file>last.fm/icon_tag.png</file>
|
||||
<file>last.fm/icon_user.png</file>
|
||||
<file>last.fm/lastfm.png</file>
|
||||
<file>last.fm/loved_radio.png</file>
|
||||
<file>last.fm/love.png</file>
|
||||
<file>last.fm/my_friends.png</file>
|
||||
<file>last.fm/my_neighbours.png</file>
|
||||
<file>last.fm/neighbour_radio.png</file>
|
||||
<file>last.fm/personal_radio.png</file>
|
||||
<file>last.fm/recommended_radio.png</file>
|
||||
<file>last.fm/user_purple.png</file>
|
||||
<file>logo.png</file>
|
||||
<file>lumberjacksong.txt</file>
|
||||
<file>lyrics/ultimate_providers.xml</file>
|
||||
<file>sidebar_background.png</file>
|
||||
<file>providers/wikipedia.png</file>
|
||||
<file>providers/aol.png</file>
|
||||
<file>mainwindow.css</file>
|
||||
<file>nocover.png</file>
|
||||
<file>nomusic.png</file>
|
||||
<file>now_playing_tooltip.txt</file>
|
||||
<file>nyancat.png</file>
|
||||
<file>osd_background.png</file>
|
||||
<file>osd_shadow_corner.png</file>
|
||||
<file>osd_shadow_edge.png</file>
|
||||
<file>providers/amazon.png</file>
|
||||
<file>providers/myspace.png</file>
|
||||
<file>providers/aol.png</file>
|
||||
<file>providers/bbc.png</file>
|
||||
<file>providers/cdbaby.png</file>
|
||||
<file>providers/digitallyimported-32.png</file>
|
||||
<file>providers/digitallyimported.png</file>
|
||||
<file>providers/echonest.png</file>
|
||||
<file>providers/googledrive.png</file>
|
||||
<file>providers/grooveshark.png</file>
|
||||
<file>providers/itunes.png</file>
|
||||
<file>providers/jamendo.png</file>
|
||||
<file>providers/magnatune.png</file>
|
||||
<file>providers/mog.png</file>
|
||||
<file>providers/mtvmusic.png</file>
|
||||
<file>providers/cdbaby.png</file>
|
||||
<file>providers/echonest.png</file>
|
||||
<file>providers/musicbrainz.png</file>
|
||||
<file>providers/mygpo32.png</file>
|
||||
<file>providers/myspace.png</file>
|
||||
<file>providers/podcast16.png</file>
|
||||
<file>providers/podcast32.png</file>
|
||||
<file>providers/skyfm.png</file>
|
||||
<file>providers/somafm.png</file>
|
||||
<file>providers/songkick.png</file>
|
||||
<file>providers/twitter.png</file>
|
||||
<file>providers/googledrive.png</file>
|
||||
<file>lumberjacksong.txt</file>
|
||||
<file>providers/wikipedia.png</file>
|
||||
<file>sample.mood</file>
|
||||
<file>schema/device-schema.sql</file>
|
||||
<file>schema/jamendo.sql</file>
|
||||
<file>schema/schema-10.sql</file>
|
||||
<file>schema/schema-11.sql</file>
|
||||
<file>schema/schema-12.sql</file>
|
||||
<file>schema/schema-13.sql</file>
|
||||
<file>schema/schema-14.sql</file>
|
||||
<file>schema/schema-15.sql</file>
|
||||
<file>schema/schema-16.sql</file>
|
||||
<file>schema/schema-17.sql</file>
|
||||
<file>schema/schema-18.sql</file>
|
||||
<file>star-off.png</file>
|
||||
<file>star-on.png</file>
|
||||
<file>icons/22x22/folder.png</file>
|
||||
<file>icons/32x32/folder.png</file>
|
||||
<file>icons/48x48/folder.png</file>
|
||||
<file>smartplaylistsearchterm.css</file>
|
||||
<file>schema/schema-19.sql</file>
|
||||
<file>schema/schema-1.sql</file>
|
||||
<file>schema/schema-20.sql</file>
|
||||
<file>schema/schema-21.sql</file>
|
||||
<file>providers/jamendo.png</file>
|
||||
<file>schema/schema-22.sql</file>
|
||||
<file>schema/jamendo.sql</file>
|
||||
<file>schema/schema-23.sql</file>
|
||||
<file>schema/schema-24.sql</file>
|
||||
<file>schema/schema-25.sql</file>
|
||||
<file>schema/schema-26.sql</file>
|
||||
<file>schema/schema-27.sql</file>
|
||||
<file>schema/schema-28.sql</file>
|
||||
<file>icons/22x22/network-server.png</file>
|
||||
<file>icons/32x32/network-server.png</file>
|
||||
<file>icons/48x48/network-server.png</file>
|
||||
<file>providers/musicbrainz.png</file>
|
||||
<file>last.fm/as_disabled.png</file>
|
||||
<file>last.fm/as_light.png</file>
|
||||
<file>icons/32x32/tools-wizard.png</file>
|
||||
<file>icons/22x22/mail-message.png</file>
|
||||
<file>icons/32x32/mail-message.png</file>
|
||||
<file>icons/48x48/mail-message.png</file>
|
||||
<file>schema/schema-29.sql</file>
|
||||
<file>schema/schema-2.sql</file>
|
||||
<file>schema/schema-30.sql</file>
|
||||
<file>schema/schema-31.sql</file>
|
||||
<file>schema/schema-32.sql</file>
|
||||
<file>icons/22x22/edit-find.png</file>
|
||||
<file>icons/32x32/edit-find.png</file>
|
||||
<file>icons/48x48/edit-find.png</file>
|
||||
<file>schema/schema-33.sql</file>
|
||||
<file>spotify-core-logo-128x128.png</file>
|
||||
<file>icons/22x22/dialog-warning.png</file>
|
||||
<file>icons/22x22/dialog-ok-apply.png</file>
|
||||
<file>schema/schema-34.sql</file>
|
||||
<file>nyancat.png</file>
|
||||
<file>providers/digitallyimported.png</file>
|
||||
<file>providers/skyfm.png</file>
|
||||
<file>providers/digitallyimported-32.png</file>
|
||||
<file>providers/grooveshark.png</file>
|
||||
<file>globalsearch.css</file>
|
||||
<file>clementine-spotify-public.pem</file>
|
||||
<file>icons/22x22/user-away.png</file>
|
||||
<file>icons/32x32/search.png</file>
|
||||
<file>schema/schema-35.sql</file>
|
||||
<file>schema/schema-36.sql</file>
|
||||
<file>grooveshark-valicert-ca.pem</file>
|
||||
<file>schema/schema-37.sql</file>
|
||||
<file>providers/podcast16.png</file>
|
||||
<file>providers/podcast32.png</file>
|
||||
<file>providers/mygpo32.png</file>
|
||||
<file>providers/itunes.png</file>
|
||||
<file>providers/bbc.png</file>
|
||||
<file>sample.mood</file>
|
||||
<file>schema/schema-3.sql</file>
|
||||
<file>schema/schema-4.sql</file>
|
||||
<file>schema/schema-5.sql</file>
|
||||
<file>schema/schema-6.sql</file>
|
||||
<file>schema/schema-7.sql</file>
|
||||
<file>schema/schema-8.sql</file>
|
||||
<file>schema/schema-9.sql</file>
|
||||
<file>schema/schema.sql</file>
|
||||
<file>sidebar_background.png</file>
|
||||
<file>smartplaylistsearchterm.css</file>
|
||||
<file>songinfo.css</file>
|
||||
<file>spinner.gif</file>
|
||||
<file>spotify-core-logo-128x128.png</file>
|
||||
<file>star-off.png</file>
|
||||
<file>star-on.png</file>
|
||||
<file>tiny-pause.png</file>
|
||||
<file>tiny-start.png</file>
|
||||
<file>twitter.css</file>
|
||||
<file>volumeslider-gradient.png</file>
|
||||
<file>volumeslider-handle_glow.png</file>
|
||||
<file>volumeslider-handle.png</file>
|
||||
<file>volumeslider-inset.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -21,8 +21,9 @@ darwin QMenu {
|
||||
}
|
||||
|
||||
QToolButton {
|
||||
border: none;
|
||||
padding: 2px;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 3px;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
QToolButton::menu-button {
|
||||
@ -37,8 +38,6 @@ QToolButton[popupMode="1"] {
|
||||
QToolButton:hover {
|
||||
border: 2px solid %palette-highlight;
|
||||
background-color: %palette-highlight-lighter;
|
||||
border-radius: 3px;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
QToolButton:hover[popupMode="1"] {
|
||||
@ -48,8 +47,6 @@ QToolButton:hover[popupMode="1"] {
|
||||
QToolButton:pressed {
|
||||
border: 2px solid %palette-highlight-darker;
|
||||
background-color: %palette-highlight-lighter;
|
||||
border-radius: 3px;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
QToolButton:pressed[popupMode="1"] {
|
||||
|
@ -5,7 +5,6 @@ include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||
|
||||
set(SOURCES
|
||||
core/closure.cpp
|
||||
core/concurrentrun.cpp
|
||||
core/encoding.cpp
|
||||
core/logging.cpp
|
||||
core/messagehandler.cpp
|
||||
|
@ -1,11 +0,0 @@
|
||||
#include "concurrentrun.h"
|
||||
|
||||
namespace ConcurrentRun {
|
||||
|
||||
void Run(
|
||||
QThreadPool* threadpool,
|
||||
std::tr1::function<void ()> function) {
|
||||
(new ThreadFunctorVoid(function))->Start(threadpool);
|
||||
}
|
||||
|
||||
} // namespace ConcurrentRun
|
@ -20,6 +20,9 @@
|
||||
|
||||
#include <tr1/functional>
|
||||
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include <QFuture>
|
||||
#include <QRunnable>
|
||||
#include <QThreadPool>
|
||||
@ -40,11 +43,18 @@
|
||||
Run() functions are used for convenience: to directly create a new
|
||||
ThreadFunctor object and start it.
|
||||
|
||||
Currently, only functions with one or two arguments and a return value are
|
||||
Currently, only functions with zero, one, two or three arguments are
|
||||
supported, but other might be added easily for X arguments by defining a new
|
||||
ThreadFunctorBasX class, and add new Run() function.
|
||||
ThreadFunctorX class (and eventually a second class for handling functions
|
||||
which return void: see existing classes for examples), and add new Run()
|
||||
function.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Base abstract classes ThreadFunctorBase and ThreadFunctor (for void and
|
||||
non-void result):
|
||||
*/
|
||||
template<typename ReturnType>
|
||||
class ThreadFunctorBase : public QFutureInterface<ReturnType>, public QRunnable {
|
||||
public:
|
||||
@ -62,6 +72,15 @@ class ThreadFunctorBase : public QFutureInterface<ReturnType>, public QRunnable
|
||||
}
|
||||
|
||||
virtual void run() = 0;
|
||||
};
|
||||
|
||||
// Base implemenation for functions having a result to be returned
|
||||
template<typename ReturnType, class Enabled = void>
|
||||
class ThreadFunctor : public ThreadFunctorBase<ReturnType> {
|
||||
public:
|
||||
ThreadFunctor() {}
|
||||
|
||||
virtual void run() = 0;
|
||||
|
||||
void End() {
|
||||
this->reportResult(result_);
|
||||
@ -72,24 +91,64 @@ class ThreadFunctorBase : public QFutureInterface<ReturnType>, public QRunnable
|
||||
ReturnType result_;
|
||||
};
|
||||
|
||||
// Use bool as a placeholder result.
|
||||
class ThreadFunctorVoid : public ThreadFunctorBase<bool> {
|
||||
// Base implementation for functions with void result
|
||||
template<typename ReturnType>
|
||||
class ThreadFunctor<ReturnType, typename boost::enable_if<boost::is_void<ReturnType> >::type>
|
||||
: public ThreadFunctorBase<ReturnType> {
|
||||
public:
|
||||
ThreadFunctorVoid(std::tr1::function<void ()> function)
|
||||
ThreadFunctor() {}
|
||||
|
||||
virtual void run() = 0;
|
||||
|
||||
void End() {
|
||||
this->reportFinished();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
ThreadFunctor with no arguments:
|
||||
*/
|
||||
// Non-void result
|
||||
template<typename ReturnType, class Enabled = void>
|
||||
class ThreadFunctor0 : public ThreadFunctor<ReturnType> {
|
||||
public:
|
||||
ThreadFunctor0(std::tr1::function<ReturnType ()> function)
|
||||
: function_(function)
|
||||
{ }
|
||||
|
||||
void run() {
|
||||
this->result_ = function_();
|
||||
ThreadFunctor<ReturnType>::End();
|
||||
}
|
||||
|
||||
private:
|
||||
std::tr1::function<ReturnType ()> function_;
|
||||
};
|
||||
|
||||
// Void result
|
||||
template<typename ReturnType>
|
||||
class ThreadFunctor0<ReturnType, typename boost::enable_if<boost::is_void<ReturnType> >::type>
|
||||
: public ThreadFunctor<ReturnType> {
|
||||
public:
|
||||
ThreadFunctor0(std::tr1::function<ReturnType ()> function)
|
||||
: function_(function)
|
||||
{ }
|
||||
|
||||
void run() {
|
||||
function_();
|
||||
ThreadFunctorBase<bool>::End();
|
||||
ThreadFunctor<ReturnType>::End();
|
||||
}
|
||||
|
||||
private:
|
||||
std::tr1::function<void ()> function_;
|
||||
private:
|
||||
std::tr1::function<ReturnType ()> function_;
|
||||
};
|
||||
|
||||
template<typename ReturnType, typename Arg>
|
||||
class ThreadFunctor1 : public ThreadFunctorBase<ReturnType> {
|
||||
/*
|
||||
ThreadFunctor with one argument:
|
||||
*/
|
||||
// Non-void result
|
||||
template<typename ReturnType, typename Arg, class Enabled = void>
|
||||
class ThreadFunctor1 : public ThreadFunctor<ReturnType> {
|
||||
public:
|
||||
ThreadFunctor1(std::tr1::function<ReturnType (Arg)> function,
|
||||
const Arg& arg)
|
||||
@ -99,7 +158,7 @@ public:
|
||||
|
||||
void run() {
|
||||
this->result_ = function_(arg_);
|
||||
ThreadFunctorBase<ReturnType>::End();
|
||||
ThreadFunctor<ReturnType>::End();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -107,8 +166,33 @@ private:
|
||||
Arg arg_;
|
||||
};
|
||||
|
||||
template<typename ReturnType, typename Arg1, typename Arg2>
|
||||
class ThreadFunctor2 : public ThreadFunctorBase<ReturnType> {
|
||||
// Void result
|
||||
template<typename ReturnType, typename Arg>
|
||||
class ThreadFunctor1<ReturnType, Arg, typename boost::enable_if<boost::is_void<ReturnType> >::type>
|
||||
: public ThreadFunctor<ReturnType> {
|
||||
public:
|
||||
ThreadFunctor1(std::tr1::function<ReturnType (Arg)> function,
|
||||
const Arg& arg)
|
||||
: function_(function),
|
||||
arg_(arg)
|
||||
{ }
|
||||
|
||||
void run() {
|
||||
function_(arg_);
|
||||
ThreadFunctor<ReturnType>::End();
|
||||
}
|
||||
|
||||
private:
|
||||
std::tr1::function<ReturnType (Arg)> function_;
|
||||
Arg arg_;
|
||||
};
|
||||
|
||||
/*
|
||||
ThreadFunctor with two arguments:
|
||||
*/
|
||||
// Non-void result
|
||||
template<typename ReturnType, typename Arg1, typename Arg2, class Enabled = void>
|
||||
class ThreadFunctor2 : public ThreadFunctor<ReturnType> {
|
||||
public:
|
||||
ThreadFunctor2(std::tr1::function<ReturnType (Arg1, Arg2)> function,
|
||||
const Arg1& arg1, const Arg2& arg2)
|
||||
@ -119,7 +203,7 @@ public:
|
||||
|
||||
void run() {
|
||||
this->result_ = function_(arg1_, arg2_);
|
||||
ThreadFunctorBase<ReturnType>::End();
|
||||
ThreadFunctor<ReturnType>::End();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -128,10 +212,94 @@ private:
|
||||
Arg2 arg2_;
|
||||
};
|
||||
|
||||
// Void result
|
||||
template<typename ReturnType, typename Arg1, typename Arg2>
|
||||
class ThreadFunctor2<ReturnType, Arg1, Arg2, typename boost::enable_if<boost::is_void<ReturnType> >::type>
|
||||
: public ThreadFunctor<ReturnType> {
|
||||
public:
|
||||
ThreadFunctor2(std::tr1::function<ReturnType (Arg1, Arg2)> function,
|
||||
const Arg1& arg1, const Arg2& arg2)
|
||||
: function_(function),
|
||||
arg1_(arg1),
|
||||
arg2_(arg2)
|
||||
{ }
|
||||
|
||||
void run() {
|
||||
function_(arg1_, arg2_);
|
||||
ThreadFunctor<ReturnType>::End();
|
||||
}
|
||||
|
||||
private:
|
||||
std::tr1::function<ReturnType (Arg1, Arg2)> function_;
|
||||
Arg1 arg1_;
|
||||
Arg2 arg2_;
|
||||
};
|
||||
|
||||
/*
|
||||
ThreadFunctor with three arguments:
|
||||
*/
|
||||
// Non-void result
|
||||
template<typename ReturnType, typename Arg1, typename Arg2, typename Arg3, class Enabled = void>
|
||||
class ThreadFunctor3 : public ThreadFunctor<ReturnType> {
|
||||
public:
|
||||
ThreadFunctor3(std::tr1::function<ReturnType (Arg1, Arg2, Arg3)> function,
|
||||
const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
|
||||
: function_(function),
|
||||
arg1_(arg1),
|
||||
arg2_(arg2),
|
||||
arg3_(arg3)
|
||||
{ }
|
||||
|
||||
void run() {
|
||||
this->result_ = function_(arg1_, arg2_, arg3_);
|
||||
ThreadFunctor<ReturnType>::End();
|
||||
}
|
||||
|
||||
private:
|
||||
std::tr1::function<ReturnType (Arg1, Arg2, Arg3)> function_;
|
||||
Arg1 arg1_;
|
||||
Arg2 arg2_;
|
||||
Arg3 arg3_;
|
||||
};
|
||||
|
||||
// Void result
|
||||
template<typename ReturnType, typename Arg1, typename Arg2, typename Arg3>
|
||||
class ThreadFunctor3<ReturnType, Arg1, Arg2, Arg3, typename boost::enable_if<boost::is_void<ReturnType> >::type>
|
||||
: public ThreadFunctor<ReturnType> {
|
||||
public:
|
||||
ThreadFunctor3(std::tr1::function<ReturnType (Arg1, Arg2, Arg3)> function,
|
||||
const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
|
||||
: function_(function),
|
||||
arg1_(arg1),
|
||||
arg2_(arg2),
|
||||
arg3_(arg3)
|
||||
{ }
|
||||
|
||||
void run() {
|
||||
function_(arg1_, arg2_, arg3_);
|
||||
ThreadFunctor<ReturnType>::End();
|
||||
}
|
||||
|
||||
private:
|
||||
std::tr1::function<ReturnType (Arg1, Arg2, Arg3)> function_;
|
||||
Arg1 arg1_;
|
||||
Arg2 arg2_;
|
||||
Arg3 arg3_;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Run functions
|
||||
*/
|
||||
namespace ConcurrentRun {
|
||||
void Run(
|
||||
|
||||
template<typename ReturnType>
|
||||
QFuture<ReturnType> Run(
|
||||
QThreadPool* threadpool,
|
||||
std::tr1::function<void ()> function);
|
||||
std::tr1::function<ReturnType ()> function) {
|
||||
|
||||
return (new ThreadFunctor0<ReturnType>(function))->Start(threadpool);
|
||||
}
|
||||
|
||||
template<typename ReturnType, typename Arg>
|
||||
QFuture<ReturnType> Run(
|
||||
@ -150,6 +318,15 @@ namespace ConcurrentRun {
|
||||
|
||||
return (new ThreadFunctor2<ReturnType, Arg1, Arg2>(function, arg1, arg2))->Start(threadpool);
|
||||
}
|
||||
|
||||
template<typename ReturnType, typename Arg1, typename Arg2, typename Arg3>
|
||||
QFuture<ReturnType> Run(
|
||||
QThreadPool* threadpool,
|
||||
std::tr1::function<ReturnType (Arg1, Arg2, Arg3)> function,
|
||||
const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) {
|
||||
|
||||
return (new ThreadFunctor3<ReturnType, Arg1, Arg2, Arg3>(function, arg1, arg2, arg3))->Start(threadpool);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONCURRENTRUN_H
|
||||
|
@ -162,7 +162,6 @@ set(SOURCES
|
||||
internet/geolocator.cpp
|
||||
internet/googledriveservice.cpp
|
||||
internet/groovesharkradio.cpp
|
||||
internet/groovesharksearchplaylisttype.cpp
|
||||
internet/groovesharkservice.cpp
|
||||
internet/groovesharksettingspage.cpp
|
||||
internet/groovesharkurlhandler.cpp
|
||||
@ -776,7 +775,6 @@ optional_source(HAVE_SPOTIFY
|
||||
SOURCES
|
||||
globalsearch/spotifysearchprovider.cpp
|
||||
internet/spotifyblobdownloader.cpp
|
||||
internet/spotifysearchplaylisttype.cpp
|
||||
internet/spotifyserver.cpp
|
||||
internet/spotifyservice.cpp
|
||||
internet/spotifysettingspage.cpp
|
||||
|
@ -349,7 +349,7 @@ void Player::SeekTo(int seconds) {
|
||||
|
||||
// If the length is 0 then either there is no song playing, or the song isn't
|
||||
// seekable.
|
||||
if (length_nanosec == 0) {
|
||||
if (length_nanosec <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "songloader.h"
|
||||
#include "core/concurrentrun.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/song.h"
|
||||
#include "core/signalchecker.h"
|
||||
@ -38,7 +39,6 @@
|
||||
#include <QFileInfo>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QtDebug>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
@ -229,7 +229,8 @@ SongLoader::Result SongLoader::LoadLocal(const QString& filename, bool block,
|
||||
// inside right away.
|
||||
if (QFileInfo(filename).isDir()) {
|
||||
if (!block) {
|
||||
QtConcurrent::run(this, &SongLoader::LoadLocalDirectoryAndEmit, filename);
|
||||
ConcurrentRun::Run<void>(&thread_pool_,
|
||||
boost::bind(&SongLoader::LoadLocalDirectoryAndEmit, this, filename));
|
||||
return WillLoadAsync;
|
||||
} else {
|
||||
LoadLocalDirectory(filename);
|
||||
@ -261,7 +262,8 @@ SongLoader::Result SongLoader::LoadLocal(const QString& filename, bool block,
|
||||
|
||||
// It's a playlist!
|
||||
if (!block) {
|
||||
QtConcurrent::run(this, &SongLoader::LoadPlaylistAndEmit, parser, filename);
|
||||
ConcurrentRun::Run<void>(&thread_pool_,
|
||||
boost::bind(&SongLoader::LoadPlaylistAndEmit, this, parser, filename));
|
||||
return WillLoadAsync;
|
||||
} else {
|
||||
LoadPlaylist(parser, filename);
|
||||
@ -315,22 +317,27 @@ SongLoader::Result SongLoader::LoadLocal(const QString& filename, bool block,
|
||||
|
||||
void SongLoader::EffectiveSongsLoad() {
|
||||
for (int i = 0; i < songs_.size(); i++) {
|
||||
Song& song = songs_[i];
|
||||
EffectiveSongLoad(&songs_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (song.filetype() != Song::Type_Unknown) {
|
||||
// Maybe we loaded the metadata already, for example from a cuesheet.
|
||||
continue;
|
||||
}
|
||||
void SongLoader::EffectiveSongLoad(Song* song) {
|
||||
if (!song)
|
||||
return;
|
||||
|
||||
// First, try to get the song from the library
|
||||
Song library_song = library_->GetSongByUrl(song.url());
|
||||
if (library_song.is_valid()) {
|
||||
song = library_song;
|
||||
} else {
|
||||
// it's a normal media file
|
||||
QString filename = song.url().toLocalFile();
|
||||
TagReaderClient::Instance()->ReadFileBlocking(filename, &song);
|
||||
}
|
||||
if (song->filetype() != Song::Type_Unknown) {
|
||||
// Maybe we loaded the metadata already, for example from a cuesheet.
|
||||
return;
|
||||
}
|
||||
|
||||
// First, try to get the song from the library
|
||||
Song library_song = library_->GetSongByUrl(song->url());
|
||||
if (library_song.is_valid()) {
|
||||
*song = library_song;
|
||||
} else {
|
||||
// it's a normal media file
|
||||
QString filename = song->url().toLocalFile();
|
||||
TagReaderClient::Instance()->ReadFileBlocking(filename, song);
|
||||
}
|
||||
}
|
||||
|
||||
@ -372,6 +379,13 @@ void SongLoader::LoadLocalDirectory(const QString& filename) {
|
||||
}
|
||||
|
||||
qStableSort(songs_.begin(), songs_.end(), CompareSongs);
|
||||
|
||||
// Load the first song: all songs will be loaded async, but we want the first
|
||||
// one in our list to be fully loaded, so if the user has the "Start playing
|
||||
// when adding to playlist" preference behaviour set, it can enjoy the first
|
||||
// song being played (seek it, have moodbar, etc.)
|
||||
if (!songs_.isEmpty())
|
||||
EffectiveSongLoad(&(*songs_.begin()));
|
||||
}
|
||||
|
||||
void SongLoader::AddAsRawStream() {
|
||||
|
@ -19,6 +19,7 @@
|
||||
#define SONGLOADER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QThreadPool>
|
||||
#include <QUrl>
|
||||
|
||||
#include "song.h"
|
||||
@ -64,6 +65,7 @@ public:
|
||||
// playlist and replace the partially-loaded items by the new ones, fully
|
||||
// loaded.
|
||||
void EffectiveSongsLoad();
|
||||
void EffectiveSongLoad(Song* song);
|
||||
Result LoadAudioCD();
|
||||
|
||||
signals:
|
||||
@ -128,6 +130,8 @@ private:
|
||||
LibraryBackendInterface* library_;
|
||||
|
||||
boost::shared_ptr<GstElement> pipeline_;
|
||||
|
||||
QThreadPool thread_pool_;
|
||||
};
|
||||
|
||||
#endif // SONGLOADER_H
|
||||
|
@ -187,7 +187,7 @@ DeviceManager::DeviceManager(Application* app, QObject *parent)
|
||||
|
||||
// This reads from the database and contends on the database mutex, which can
|
||||
// be very slow on startup.
|
||||
ConcurrentRun::Run(&thread_pool_, bind(&DeviceManager::LoadAllDevices, this));
|
||||
ConcurrentRun::Run<void>(&thread_pool_, bind(&DeviceManager::LoadAllDevices, this));
|
||||
|
||||
// This proxy model only shows connected devices
|
||||
connected_devices_model_ = new DeviceStateFilterModel(this);
|
||||
|
@ -33,8 +33,6 @@
|
||||
# include "internet/spotifyservice.h"
|
||||
#endif
|
||||
|
||||
#include <QtConcurrentRun>
|
||||
|
||||
const int GstEnginePipeline::kGstStateTimeoutNanosecs = 10000000;
|
||||
const int GstEnginePipeline::kFaderFudgeMsec = 2000;
|
||||
|
||||
|
@ -16,6 +16,12 @@
|
||||
*/
|
||||
|
||||
#include "spotifysearchprovider.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
#include <boost/random/uniform_int.hpp>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "internet/internetmodel.h"
|
||||
#include "internet/spotifyserver.h"
|
||||
@ -29,7 +35,7 @@ SpotifySearchProvider::SpotifySearchProvider(Application* app, QObject* parent)
|
||||
{
|
||||
Init("Spotify", "spotify", QIcon(":icons/32x32/spotify.png"),
|
||||
WantsDelayedQueries | WantsSerialisedArtQueries | ArtIsProbablyRemote |
|
||||
CanShowConfig);
|
||||
CanShowConfig | CanGiveSuggestions);
|
||||
}
|
||||
|
||||
SpotifyServer* SpotifySearchProvider::server() {
|
||||
@ -48,6 +54,10 @@ SpotifyServer* SpotifySearchProvider::server() {
|
||||
connect(server_, SIGNAL(ImageLoaded(QString,QImage)),
|
||||
SLOT(ArtLoadedSlot(QString,QImage)));
|
||||
connect(server_, SIGNAL(destroyed()), SLOT(ServerDestroyed()));
|
||||
connect(server_, SIGNAL(StarredLoaded(pb::spotify::LoadPlaylistResponse)),
|
||||
SLOT(SuggestionsLoaded(pb::spotify::LoadPlaylistResponse)));
|
||||
connect(server_, SIGNAL(ToplistBrowseResults(pb::spotify::BrowseToplistResponse)),
|
||||
SLOT(SuggestionsLoaded(pb::spotify::BrowseToplistResponse)));
|
||||
|
||||
return server_;
|
||||
}
|
||||
@ -143,3 +153,72 @@ void SpotifySearchProvider::ShowConfig() {
|
||||
return service_->ShowConfig();
|
||||
}
|
||||
}
|
||||
|
||||
void SpotifySearchProvider::AddSuggestionFromTrack(
|
||||
const pb::spotify::Track& track) {
|
||||
if (!track.title().empty()) {
|
||||
suggestions_.insert(QString::fromUtf8(track.title().c_str()));
|
||||
}
|
||||
for (int j = 0; j < track.artist_size(); ++j) {
|
||||
if (!track.artist(j).empty()) {
|
||||
suggestions_.insert(QString::fromUtf8(track.artist(j).c_str()));
|
||||
}
|
||||
}
|
||||
if (!track.album().empty()) {
|
||||
suggestions_.insert(QString::fromUtf8(track.album().c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void SpotifySearchProvider::AddSuggestionFromAlbum(
|
||||
const pb::spotify::Album& album) {
|
||||
AddSuggestionFromTrack(album.metadata());
|
||||
for (int i = 0; i < album.track_size(); ++i) {
|
||||
AddSuggestionFromTrack(album.track(i));
|
||||
}
|
||||
}
|
||||
|
||||
void SpotifySearchProvider::SuggestionsLoaded(
|
||||
const pb::spotify::LoadPlaylistResponse& playlist) {
|
||||
for (int i = 0; i < playlist.track_size(); ++i) {
|
||||
AddSuggestionFromTrack(playlist.track(i));
|
||||
}
|
||||
}
|
||||
|
||||
void SpotifySearchProvider::SuggestionsLoaded(
|
||||
const pb::spotify::BrowseToplistResponse& response) {
|
||||
for (int i = 0; i < response.track_size(); ++i) {
|
||||
AddSuggestionFromTrack(response.track(i));
|
||||
}
|
||||
for (int i = 0; i < response.album_size(); ++i) {
|
||||
AddSuggestionFromAlbum(response.album(i));
|
||||
}
|
||||
}
|
||||
|
||||
void SpotifySearchProvider::LoadSuggestions() {
|
||||
if (!server()) {
|
||||
return;
|
||||
}
|
||||
server()->LoadStarred();
|
||||
server()->LoadToplist();
|
||||
}
|
||||
|
||||
QStringList SpotifySearchProvider::GetSuggestions(int count) {
|
||||
if (suggestions_.empty()) {
|
||||
LoadSuggestions();
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QStringList all_suggestions = suggestions_.toList();
|
||||
|
||||
boost::mt19937 gen(std::time(0));
|
||||
boost::uniform_int<> random(0, all_suggestions.size() - 1);
|
||||
|
||||
QSet<QString> candidates;
|
||||
|
||||
const int max = qMin(count, all_suggestions.size());
|
||||
while (candidates.size() < max) {
|
||||
const int index = random(gen);
|
||||
candidates.insert(all_suggestions[index]);
|
||||
}
|
||||
return candidates.toList();
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
|
||||
void SearchAsync(int id, const QString& query);
|
||||
void LoadArtAsync(int id, const Result& result);
|
||||
QStringList GetSuggestions(int count);
|
||||
|
||||
bool IsLoggedIn();
|
||||
void ShowConfig();
|
||||
@ -41,10 +42,16 @@ private slots:
|
||||
void ServerDestroyed();
|
||||
void SearchFinishedSlot(const pb::spotify::SearchResponse& response);
|
||||
void ArtLoadedSlot(const QString& id, const QImage& image);
|
||||
void SuggestionsLoaded(const pb::spotify::LoadPlaylistResponse& response);
|
||||
void SuggestionsLoaded(const pb::spotify::BrowseToplistResponse& response);
|
||||
|
||||
private:
|
||||
SpotifyServer* server();
|
||||
|
||||
void LoadSuggestions();
|
||||
void AddSuggestionFromTrack(const pb::spotify::Track& track);
|
||||
void AddSuggestionFromAlbum(const pb::spotify::Album& album);
|
||||
|
||||
private:
|
||||
SpotifyServer* server_;
|
||||
SpotifyService* service_;
|
||||
@ -52,6 +59,8 @@ private:
|
||||
QMap<QString, PendingState> queries_;
|
||||
QMap<QString, int> pending_art_;
|
||||
QMap<QString, int> pending_tracks_;
|
||||
|
||||
QSet<QString> suggestions_;
|
||||
};
|
||||
|
||||
#endif // SPOTIFYSEARCHPROVIDER_H
|
||||
|
@ -1,46 +0,0 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "groovesharksearchplaylisttype.h"
|
||||
#include "groovesharkservice.h"
|
||||
|
||||
const char* GroovesharkSearchPlaylistType::kName = "grooveshark-search";
|
||||
|
||||
GroovesharkSearchPlaylistType::GroovesharkSearchPlaylistType(GroovesharkService* service)
|
||||
: service_(service) {
|
||||
}
|
||||
|
||||
QIcon GroovesharkSearchPlaylistType::icon(Playlist* playlist) const {
|
||||
return QIcon(":providers/grooveshark.png");
|
||||
}
|
||||
|
||||
QString GroovesharkSearchPlaylistType::search_hint_text(Playlist* playlist) const {
|
||||
return QObject::tr("Search Grooveshark");
|
||||
}
|
||||
|
||||
QString GroovesharkSearchPlaylistType::empty_playlist_text(Playlist* playlist) const {
|
||||
return QObject::tr("Start typing in the search box above to find music on %1.").arg("Grooveshark");
|
||||
}
|
||||
|
||||
bool GroovesharkSearchPlaylistType::has_special_search_behaviour(Playlist* playlist) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GroovesharkSearchPlaylistType::Search(const QString& text, Playlist* playlist) {
|
||||
service_->Search(text, playlist);
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GROOVESHARKSEARCHPLAYLISTTYPE_H
|
||||
#define GROOVESHARKSEARCHPLAYLISTTYPE_H
|
||||
|
||||
#include "playlist/specialplaylisttype.h"
|
||||
|
||||
class GroovesharkService;
|
||||
|
||||
class GroovesharkSearchPlaylistType : public SpecialPlaylistType {
|
||||
public:
|
||||
GroovesharkSearchPlaylistType(GroovesharkService* service);
|
||||
|
||||
static const char* kName;
|
||||
virtual QString name() const { return kName; }
|
||||
|
||||
virtual QIcon icon(Playlist* playlist) const;
|
||||
virtual QString search_hint_text(Playlist* playlist) const;
|
||||
virtual QString empty_playlist_text(Playlist* playlist) const;
|
||||
|
||||
virtual bool has_special_search_behaviour(Playlist* playlist) const;
|
||||
virtual void Search(const QString& text, Playlist* playlist);
|
||||
|
||||
private:
|
||||
GroovesharkService* service_;
|
||||
};
|
||||
|
||||
#endif // GROOVESHARKSEARCHPLAYLISTTYPE_H
|
@ -38,7 +38,6 @@
|
||||
|
||||
#include "internetmodel.h"
|
||||
#include "groovesharkradio.h"
|
||||
#include "groovesharksearchplaylisttype.h"
|
||||
#include "groovesharkurlhandler.h"
|
||||
#include "searchboxwidget.h"
|
||||
|
||||
@ -93,6 +92,7 @@ GroovesharkService::GroovesharkService(Application* app, InternetModel *parent)
|
||||
stations_(NULL),
|
||||
grooveshark_radio_(NULL),
|
||||
favorites_(NULL),
|
||||
library_(NULL),
|
||||
playlists_parent_(NULL),
|
||||
subscribed_playlists_parent_(NULL),
|
||||
network_(new NetworkAccessManager(this)),
|
||||
@ -102,6 +102,7 @@ GroovesharkService::GroovesharkService(Application* app, InternetModel *parent)
|
||||
rename_playlist_(NULL),
|
||||
remove_from_playlist_(NULL),
|
||||
remove_from_favorites_(NULL),
|
||||
remove_from_library_(NULL),
|
||||
get_url_to_share_song_(NULL),
|
||||
get_url_to_share_playlist_(NULL),
|
||||
search_box_(new SearchBoxWidget(this)),
|
||||
@ -114,7 +115,6 @@ GroovesharkService::GroovesharkService(Application* app, InternetModel *parent)
|
||||
task_search_id_(0) {
|
||||
|
||||
app_->player()->RegisterUrlHandler(url_handler_);
|
||||
app_->playlist_manager()->RegisterSpecialPlaylistType(new GroovesharkSearchPlaylistType(this));
|
||||
|
||||
search_delay_->setInterval(kSearchDelayMsec);
|
||||
search_delay_->setSingleShot(true);
|
||||
@ -166,7 +166,9 @@ void GroovesharkService::ShowConfig() {
|
||||
}
|
||||
|
||||
QWidget* GroovesharkService::HeaderWidget() const {
|
||||
return search_box_;
|
||||
if (IsLoggedIn())
|
||||
return search_box_;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GroovesharkService::Search(const QString& text, bool now) {
|
||||
@ -440,6 +442,7 @@ void GroovesharkService::RemoveItems() {
|
||||
search_ = NULL;
|
||||
popular_month_ = NULL;
|
||||
popular_today_ = NULL;
|
||||
library_ = NULL;
|
||||
favorites_ = NULL;
|
||||
subscribed_playlists_parent_ = NULL;
|
||||
stations_ = NULL;
|
||||
@ -465,6 +468,7 @@ void GroovesharkService::ShowContextMenu(const QPoint& global_pos) {
|
||||
bool display_delete_playlist_action = false,
|
||||
display_remove_from_playlist_action = false,
|
||||
display_remove_from_favorites_action = false,
|
||||
display_remove_from_library_action = false,
|
||||
display_share_song_url = false,
|
||||
display_share_playlist_url = false;
|
||||
|
||||
@ -481,6 +485,8 @@ void GroovesharkService::ShowContextMenu(const QPoint& global_pos) {
|
||||
int parent_playlist_type = index.parent().data(Role_PlaylistType).toInt();
|
||||
if (parent_playlist_type == UserFavorites)
|
||||
display_remove_from_favorites_action = true;
|
||||
else if (parent_playlist_type == UserLibrary)
|
||||
display_remove_from_library_action = true;
|
||||
else if (parent_playlist_type == UserPlaylist)
|
||||
display_remove_from_playlist_action = true;
|
||||
}
|
||||
@ -489,6 +495,7 @@ void GroovesharkService::ShowContextMenu(const QPoint& global_pos) {
|
||||
rename_playlist_->setVisible(display_delete_playlist_action);
|
||||
remove_from_playlist_->setVisible(display_remove_from_playlist_action);
|
||||
remove_from_favorites_->setVisible(display_remove_from_favorites_action);
|
||||
remove_from_library_->setVisible(display_remove_from_library_action);
|
||||
|
||||
// Check if we can display actions to get URL for sharing songs/playlists:
|
||||
// - share song
|
||||
@ -536,6 +543,9 @@ void GroovesharkService::EnsureMenuCreated() {
|
||||
remove_from_favorites_ = context_menu_->addAction(
|
||||
IconLoader::Load("list-remove"), tr("Remove from favorites"),
|
||||
this, SLOT(RemoveCurrentFromFavorites()));
|
||||
remove_from_library_ = context_menu_->addAction(
|
||||
IconLoader::Load("list-remove"), tr("Remove from My Music"),
|
||||
this, SLOT(RemoveCurrentFromLibrary()));
|
||||
get_url_to_share_song_ = context_menu_->addAction(
|
||||
tr("Get a URL to share this Grooveshark song"),
|
||||
this, SLOT(GetCurrentSongUrlToShare()));
|
||||
@ -606,6 +616,15 @@ void GroovesharkService::EnsureItemsCreated() {
|
||||
grooveshark_radio_->setData(InternetModel::Type_SmartPlaylist, InternetModel::Role_Type);
|
||||
radios_divider->appendRow(grooveshark_radio_);
|
||||
|
||||
library_ = new QStandardItem(IconLoader::Load("folder-sound"), tr("My Music"));
|
||||
library_->setData(InternetModel::Type_UserPlaylist, InternetModel::Role_Type);
|
||||
library_->setData(UserLibrary, Role_PlaylistType);
|
||||
library_->setData(true, InternetModel::Role_CanLazyLoad);
|
||||
library_->setData(true, InternetModel::Role_CanBeModified);
|
||||
library_->setData(InternetModel::PlayBehaviour_SingleItem,
|
||||
InternetModel::Role_PlayBehaviour);
|
||||
root_->appendRow(library_);
|
||||
|
||||
favorites_ = new QStandardItem(QIcon(":/last.fm/love.png"), tr("Favorites"));
|
||||
favorites_->setData(InternetModel::Type_UserPlaylist, InternetModel::Role_Type);
|
||||
favorites_->setData(UserFavorites, Role_PlaylistType);
|
||||
@ -622,6 +641,7 @@ void GroovesharkService::EnsureItemsCreated() {
|
||||
root_->appendRow(subscribed_playlists_parent_);
|
||||
|
||||
RetrieveUserFavorites();
|
||||
RetrieveUserLibrarySongs();
|
||||
RetrieveUserPlaylists();
|
||||
RetrieveSubscribedPlaylists();
|
||||
RetrieveAutoplayTags();
|
||||
@ -731,6 +751,7 @@ void GroovesharkService::RetrieveUserFavorites() {
|
||||
|
||||
void GroovesharkService::UserFavoritesRetrieved(QNetworkReply* reply, int task_id) {
|
||||
reply->deleteLater();
|
||||
app_->task_manager()->SetTaskFinished(task_id);
|
||||
|
||||
if (!favorites_) {
|
||||
// The use probably logged out before the response arrived.
|
||||
@ -749,7 +770,38 @@ void GroovesharkService::UserFavoritesRetrieved(QNetworkReply* reply, int task_i
|
||||
|
||||
favorites_->appendRow(child);
|
||||
}
|
||||
}
|
||||
|
||||
void GroovesharkService::RetrieveUserLibrarySongs() {
|
||||
int task_id =
|
||||
app_->task_manager()->StartTask(tr("Retrieving Grooveshark My Music songs"));
|
||||
QNetworkReply* reply = CreateRequest("getUserLibrarySongs", QList<Param>());
|
||||
|
||||
NewClosure(reply, SIGNAL(finished()),
|
||||
this, SLOT(UserLibrarySongsRetrieved(QNetworkReply*, int)), reply, task_id);
|
||||
}
|
||||
|
||||
void GroovesharkService::UserLibrarySongsRetrieved(QNetworkReply* reply, int task_id) {
|
||||
reply->deleteLater();
|
||||
app_->task_manager()->SetTaskFinished(task_id);
|
||||
|
||||
if (!library_) {
|
||||
// The use probably logged out before the response arrived.
|
||||
return;
|
||||
}
|
||||
|
||||
library_->removeRows(0, library_->rowCount());
|
||||
|
||||
QVariantMap result = ExtractResult(reply);
|
||||
SongList songs = ExtractSongs(result);
|
||||
Song::SortSongsListAlphabetically(&songs);
|
||||
|
||||
foreach (const Song& song, songs) {
|
||||
QStandardItem* child = CreateSongItem(song);
|
||||
child->setData(true, InternetModel::Role_CanBeModified);
|
||||
|
||||
library_->appendRow(child);
|
||||
}
|
||||
}
|
||||
|
||||
void GroovesharkService::RetrievePopularSongs() {
|
||||
@ -1023,6 +1075,12 @@ void GroovesharkService::DropMimeData(const QMimeData* data, const QModelIndex&
|
||||
foreach (int song_id, data_songs_ids) {
|
||||
AddUserFavoriteSong(song_id);
|
||||
}
|
||||
} else if (playlist_type == UserLibrary || parent_playlist_type == UserLibrary) {
|
||||
// FIXME: Adding songs to user libray doesn't work atm, but the problem
|
||||
// seems to be on Grooveshark server side, as it returns success=true
|
||||
// when calling addUserLibrarySongs with a valid song id.
|
||||
// So this code is deactivated for now to not mislead user
|
||||
//AddUserLibrarySongs(data_songs_ids);
|
||||
} else { // Dropped on a normal playlist
|
||||
// Get the playlist
|
||||
int playlist_id = index.data(Role_UserPlaylistId).toInt();
|
||||
@ -1055,6 +1113,12 @@ QList<QAction*> GroovesharkService::playlistitem_actions(const Song& song) {
|
||||
connect(add_to_favorites, SIGNAL(triggered()), SLOT(AddCurrentSongToUserFavorites()));
|
||||
playlistitem_actions_.append(add_to_favorites);
|
||||
|
||||
// FIXME: as explained above, adding songs to library doesn't work currently
|
||||
//QAction* add_to_library = new QAction(IconLoader::Load("folder-sound"),
|
||||
// tr("Add to Grooveshark My Music"), this);
|
||||
//connect(add_to_library, SIGNAL(triggered()), SLOT(AddCurrentSongToUserLibrary()));
|
||||
//playlistitem_actions_.append(add_to_library);
|
||||
|
||||
// Create a menu with 'add to playlist' actions for each Grooveshark playlist
|
||||
QAction* add_to_playlists = new QAction(IconLoader::Load("list-add"),
|
||||
tr("Add to Grooveshark playlists"), this);
|
||||
@ -1352,6 +1416,42 @@ void GroovesharkService::UserFavoriteSongAdded(QNetworkReply* reply, int task_id
|
||||
RetrieveUserFavorites();
|
||||
}
|
||||
|
||||
void GroovesharkService::AddUserLibrarySongs(const QList<int>& songs_ids) {
|
||||
int task_id = app_->task_manager()->StartTask(tr("Adding song to My Music"));
|
||||
QList<Param> parameters;
|
||||
|
||||
// Convert songs ids to QVariant
|
||||
QVariantList songs_ids_qvariant;
|
||||
foreach (int song_id, songs_ids) {
|
||||
songs_ids_qvariant << QVariant(song_id);
|
||||
}
|
||||
QVariantList albums_ids_qvariant;
|
||||
QVariantList artists_ids_qvariant;
|
||||
|
||||
parameters << Param("songIDs", songs_ids_qvariant);
|
||||
// We do not support albums and artist parameters for now, but they are
|
||||
// required
|
||||
parameters << Param("albumIDs", albums_ids_qvariant);
|
||||
parameters << Param("artistIDs", artists_ids_qvariant);
|
||||
QNetworkReply* reply = CreateRequest("addUserLibrarySongs", parameters);
|
||||
NewClosure(reply, SIGNAL(finished()),
|
||||
this, SLOT(UserLibrarySongAdded(QNetworkReply*, int)),
|
||||
reply, task_id);
|
||||
}
|
||||
|
||||
void GroovesharkService::UserLibrarySongAdded(QNetworkReply* reply, int task_id) {
|
||||
reply->deleteLater();
|
||||
app_->task_manager()->SetTaskFinished(task_id);
|
||||
|
||||
QVariantMap result = ExtractResult(reply);
|
||||
if (!result["success"].toBool()) {
|
||||
qLog(Warning) << "Grooveshark addUserLibrarySongs failed";
|
||||
return;
|
||||
}
|
||||
// Refresh user's library list
|
||||
RetrieveUserLibrarySongs();
|
||||
}
|
||||
|
||||
void GroovesharkService::RemoveCurrentFromPlaylist() {
|
||||
const QModelIndexList& indexes(model()->selected_indexes());
|
||||
QMap<int, QList<int> > playlists_songs_ids;
|
||||
@ -1412,7 +1512,7 @@ void GroovesharkService::RemoveFromFavorites(const QList<int>& songs_ids_to_remo
|
||||
if (songs_ids_to_remove.isEmpty())
|
||||
return;
|
||||
|
||||
int task_id = app_->task_manager()->StartTask(tr("Removing song from favorites"));
|
||||
int task_id = app_->task_manager()->StartTask(tr("Removing songs from favorites"));
|
||||
QList<Param> parameters;
|
||||
|
||||
// Convert song ids to QVariant
|
||||
@ -1424,10 +1524,10 @@ void GroovesharkService::RemoveFromFavorites(const QList<int>& songs_ids_to_remo
|
||||
parameters << Param("songIDs", songs_ids_qvariant);
|
||||
QNetworkReply* reply = CreateRequest("removeUserFavoriteSongs", parameters);
|
||||
NewClosure(reply, SIGNAL(finished()), this,
|
||||
SLOT(SongRemovedFromFavorites(QNetworkReply*, int)), reply, task_id);
|
||||
SLOT(SongsRemovedFromFavorites(QNetworkReply*, int)), reply, task_id);
|
||||
}
|
||||
|
||||
void GroovesharkService::SongRemovedFromFavorites(QNetworkReply* reply, int task_id) {
|
||||
void GroovesharkService::SongsRemovedFromFavorites(QNetworkReply* reply, int task_id) {
|
||||
app_->task_manager()->SetTaskFinished(task_id);
|
||||
reply->deleteLater();
|
||||
|
||||
@ -1439,8 +1539,68 @@ void GroovesharkService::SongRemovedFromFavorites(QNetworkReply* reply, int task
|
||||
RetrieveUserFavorites();
|
||||
}
|
||||
|
||||
QNetworkReply* GroovesharkService::CreateRequest(const QString& method_name, QList<Param> params,
|
||||
bool use_https) {
|
||||
void GroovesharkService::RemoveCurrentFromLibrary() {
|
||||
const QModelIndexList& indexes(model()->selected_indexes());
|
||||
QList<int> songs_ids;
|
||||
|
||||
foreach (const QModelIndex& index, indexes) {
|
||||
|
||||
if (index.parent().data(Role_PlaylistType).toInt() != UserLibrary) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int song_id = ExtractSongId(index.data(InternetModel::Role_Url).toUrl());
|
||||
if (song_id) {
|
||||
songs_ids << song_id;
|
||||
}
|
||||
}
|
||||
|
||||
RemoveFromLibrary(songs_ids);
|
||||
}
|
||||
|
||||
void GroovesharkService::RemoveFromLibrary(const QList<int>& songs_ids_to_remove) {
|
||||
if (songs_ids_to_remove.isEmpty())
|
||||
return;
|
||||
|
||||
int task_id = app_->task_manager()->StartTask(tr("Removing songs from My Music"));
|
||||
QList<Param> parameters;
|
||||
|
||||
// Convert song ids to QVariant
|
||||
QVariantList songs_ids_qvariant;
|
||||
foreach (const int song_id, songs_ids_to_remove) {
|
||||
songs_ids_qvariant << QVariant(song_id);
|
||||
}
|
||||
QVariantList albums_ids_qvariant;
|
||||
QVariantList artists_ids_qvariant;
|
||||
|
||||
parameters << Param("songIDs", songs_ids_qvariant);
|
||||
// We do not support albums and artist parameters for now, but they are
|
||||
// required
|
||||
parameters << Param("albumIDs", albums_ids_qvariant);
|
||||
parameters << Param("artistIDs", artists_ids_qvariant);
|
||||
|
||||
QNetworkReply* reply = CreateRequest("removeUserLibrarySongs", parameters);
|
||||
NewClosure(reply, SIGNAL(finished()), this,
|
||||
SLOT(SongsRemovedFromLibrary(QNetworkReply*, int)), reply, task_id);
|
||||
}
|
||||
|
||||
void GroovesharkService::SongsRemovedFromLibrary(QNetworkReply* reply, int task_id) {
|
||||
app_->task_manager()->SetTaskFinished(task_id);
|
||||
reply->deleteLater();
|
||||
|
||||
QVariantMap result = ExtractResult(reply);
|
||||
if (!result["success"].toBool()) {
|
||||
qLog(Warning) << "Grooveshark removeUserLibrarySongs failed";
|
||||
return;
|
||||
}
|
||||
RetrieveUserLibrarySongs();
|
||||
}
|
||||
|
||||
QNetworkReply* GroovesharkService::CreateRequest(
|
||||
const QString& method_name,
|
||||
const QList<Param>& params,
|
||||
bool use_https) {
|
||||
|
||||
QVariantMap request_params;
|
||||
request_params.insert("method", method_name);
|
||||
|
||||
|
@ -46,9 +46,10 @@ class GroovesharkService : public InternetService {
|
||||
|
||||
enum PlaylistType {
|
||||
UserPlaylist = Qt::UserRole,
|
||||
// Favorites list is like a playlist, but we want to do special treatments
|
||||
// in some cases
|
||||
// Favorites and Library list are like playlists, but we want to do special
|
||||
// treatments in some cases
|
||||
UserFavorites,
|
||||
UserLibrary,
|
||||
SubscribedPlaylist
|
||||
};
|
||||
|
||||
@ -80,6 +81,7 @@ class GroovesharkService : public InternetService {
|
||||
bool IsLoggedIn() const { return !session_id_.isEmpty(); }
|
||||
void RetrieveUserPlaylists();
|
||||
void RetrieveUserFavorites();
|
||||
void RetrieveUserLibrarySongs();
|
||||
void RetrievePopularSongs();
|
||||
void RetrievePopularSongsMonth();
|
||||
void RetrievePopularSongsToday();
|
||||
@ -93,6 +95,8 @@ class GroovesharkService : public InternetService {
|
||||
void RenamePlaylist(int playlist_id);
|
||||
void AddUserFavoriteSong(int song_id);
|
||||
void RemoveFromFavorites(const QList<int>& songs_ids_to_remove);
|
||||
void AddUserLibrarySongs(const QList<int>& songs_ids);
|
||||
void RemoveFromLibrary(const QList<int>& songs_ids_to_remove);
|
||||
void GetSongUrlToShare(int song_id);
|
||||
void GetPlaylistUrlToShare(int playlist_id);
|
||||
// Start autoplay for the given tag_id, fill the autoplay_state, returns a
|
||||
@ -156,6 +160,7 @@ class GroovesharkService : public InternetService {
|
||||
void Authenticated();
|
||||
void UserPlaylistsRetrieved();
|
||||
void UserFavoritesRetrieved(QNetworkReply* reply, int task_id);
|
||||
void UserLibrarySongsRetrieved(QNetworkReply* reply, int task_id);
|
||||
void PopularSongsMonthRetrieved(QNetworkReply* reply);
|
||||
void PopularSongsTodayRetrieved(QNetworkReply* reply);
|
||||
void SubscribedPlaylistsRetrieved(QNetworkReply* reply);
|
||||
@ -168,16 +173,20 @@ class GroovesharkService : public InternetService {
|
||||
void RenameCurrentPlaylist();
|
||||
void PlaylistDeleted(QNetworkReply* reply, int playlist_id);
|
||||
void PlaylistRenamed(QNetworkReply* reply, int playlist_id, const QString& new_name);
|
||||
void AddCurrentSongToUserFavorites() { AddUserFavoriteSong(current_song_id_); }
|
||||
void AddCurrentSongToUserFavorites() { AddUserFavoriteSong(current_song_id_); }
|
||||
void AddCurrentSongToUserLibrary() { AddUserLibrarySongs(QList<int>() << current_song_id_); }
|
||||
void AddCurrentSongToPlaylist(QAction* action);
|
||||
void UserFavoriteSongAdded(QNetworkReply* reply, int task_id);
|
||||
void UserLibrarySongAdded(QNetworkReply* reply, int task_id);
|
||||
void GetCurrentSongUrlToShare();
|
||||
void SongUrlToShareReceived(QNetworkReply* reply);
|
||||
void GetCurrentPlaylistUrlToShare();
|
||||
void PlaylistUrlToShareReceived(QNetworkReply* reply);
|
||||
void RemoveCurrentFromPlaylist();
|
||||
void RemoveCurrentFromFavorites();
|
||||
void SongRemovedFromFavorites(QNetworkReply* reply, int task_id);
|
||||
void RemoveCurrentFromLibrary();
|
||||
void SongsRemovedFromFavorites(QNetworkReply* reply, int task_id);
|
||||
void SongsRemovedFromLibrary(QNetworkReply* reply, int task_id);
|
||||
void StreamMarked();
|
||||
void SongMarkedAsComplete();
|
||||
|
||||
@ -204,8 +213,10 @@ class GroovesharkService : public InternetService {
|
||||
// Create a request for the given method, with the given params.
|
||||
// If need_authentication is true, add session_id to params.
|
||||
// Returns the reply object created
|
||||
QNetworkReply* CreateRequest(const QString& method_name, const QList<QPair<QString, QVariant> > params,
|
||||
bool use_https = false);
|
||||
QNetworkReply* CreateRequest(
|
||||
const QString& method_name,
|
||||
const QList<QPair<QString, QVariant> >& params,
|
||||
bool use_https = false);
|
||||
// Convenient function which block until 'reply' replies, or timeout after 10
|
||||
// seconds. Returns false if reply has timeouted
|
||||
bool WaitForReply(QNetworkReply* reply);
|
||||
@ -249,6 +260,10 @@ class GroovesharkService : public InternetService {
|
||||
QStandardItem* stations_;
|
||||
QStandardItem* grooveshark_radio_;
|
||||
QStandardItem* favorites_;
|
||||
// Grooveshark Library (corresponds to Grooveshark 'MyMusic' actually, but
|
||||
// called 'Library' in the API).
|
||||
// Nothing to do with Clementine's local library
|
||||
QStandardItem* library_;
|
||||
QStandardItem* playlists_parent_;
|
||||
QStandardItem* subscribed_playlists_parent_;
|
||||
|
||||
@ -265,6 +280,7 @@ class GroovesharkService : public InternetService {
|
||||
QAction* rename_playlist_;
|
||||
QAction* remove_from_playlist_;
|
||||
QAction* remove_from_favorites_;
|
||||
QAction* remove_from_library_;
|
||||
QAction* get_url_to_share_song_;
|
||||
QAction* get_url_to_share_playlist_;
|
||||
QList<QAction*> playlistitem_actions_;
|
||||
|
@ -22,8 +22,6 @@
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "widgets/lineedit.h"
|
||||
|
||||
class LineEditInterface;
|
||||
class Ui_IcecastFilterWidget;
|
||||
|
||||
|
@ -20,8 +20,6 @@
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "widgets/lineedit.h"
|
||||
|
||||
class InternetService;
|
||||
class DidYouMean;
|
||||
class Ui_SearchBoxWidget;
|
||||
|
@ -1,51 +0,0 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "spotifysearchplaylisttype.h"
|
||||
#include "spotifyservice.h"
|
||||
|
||||
const char* SpotifySearchPlaylistType::kName = "spotify-search";
|
||||
|
||||
SpotifySearchPlaylistType::SpotifySearchPlaylistType(SpotifyService* service)
|
||||
: service_(service) {
|
||||
}
|
||||
|
||||
QIcon SpotifySearchPlaylistType::icon(Playlist* playlist) const {
|
||||
return QIcon(":icons/32x32/spotify.png");
|
||||
}
|
||||
|
||||
QString SpotifySearchPlaylistType::search_hint_text(Playlist* playlist) const {
|
||||
return QObject::tr("Search Spotify");
|
||||
}
|
||||
|
||||
QString SpotifySearchPlaylistType::empty_playlist_text(Playlist* playlist) const {
|
||||
return QObject::tr("Start typing in the search box above to find music on %1.").arg("Spotify");
|
||||
}
|
||||
|
||||
bool SpotifySearchPlaylistType::has_special_search_behaviour(Playlist* playlist) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpotifySearchPlaylistType::Search(const QString& text, Playlist* playlist) {
|
||||
service_->Search(text, playlist);
|
||||
}
|
||||
|
||||
void SpotifySearchPlaylistType::DidYouMeanClicked(const QString& text, Playlist* playlist) {
|
||||
// TODO Dead-code now: we will probably remove the entire class later, if the
|
||||
// new search looks pretty enough for everyone
|
||||
//service_->Search(text, playlist, true);
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SPOTIFYSEARCHPLAYLISTTYPE_H
|
||||
#define SPOTIFYSEARCHPLAYLISTTYPE_H
|
||||
|
||||
#include "playlist/specialplaylisttype.h"
|
||||
|
||||
class SpotifyService;
|
||||
|
||||
class SpotifySearchPlaylistType : public SpecialPlaylistType {
|
||||
public:
|
||||
SpotifySearchPlaylistType(SpotifyService* service);
|
||||
|
||||
static const char* kName;
|
||||
virtual QString name() const { return kName; }
|
||||
|
||||
virtual QIcon icon(Playlist* playlist) const;
|
||||
virtual QString search_hint_text(Playlist* playlist) const;
|
||||
virtual QString empty_playlist_text(Playlist* playlist) const;
|
||||
|
||||
virtual bool has_special_search_behaviour(Playlist* playlist) const;
|
||||
virtual void Search(const QString& text, Playlist* playlist);
|
||||
virtual void DidYouMeanClicked(const QString& text, Playlist* playlist);
|
||||
|
||||
private:
|
||||
SpotifyService* service_;
|
||||
};
|
||||
|
||||
#endif // SPOTIFYSEARCHPLAYLISTTYPE_H
|
@ -4,7 +4,6 @@
|
||||
#include "spotifyblobdownloader.h"
|
||||
#include "spotifyserver.h"
|
||||
#include "spotifyservice.h"
|
||||
#include "spotifysearchplaylisttype.h"
|
||||
#include "core/application.h"
|
||||
#include "core/database.h"
|
||||
#include "core/logging.h"
|
||||
@ -75,9 +74,6 @@ SpotifyService::SpotifyService(Application* app, InternetModel* parent)
|
||||
qLog(Debug) << "Spotify system blob path:" << system_blob_path_;
|
||||
qLog(Debug) << "Spotify local blob path:" << local_blob_path_;
|
||||
|
||||
app_->playlist_manager()->RegisterSpecialPlaylistType(
|
||||
new SpotifySearchPlaylistType(this));
|
||||
|
||||
app_->global_search()->AddProvider(new SpotifySearchProvider(app_, this));
|
||||
|
||||
search_delay_->setInterval(kSearchDelayMsec);
|
||||
@ -420,15 +416,21 @@ bool SpotifyService::DoPlaylistsDiffer(const pb::spotify::Playlists& response) c
|
||||
}
|
||||
|
||||
void SpotifyService::InboxLoaded(const pb::spotify::LoadPlaylistResponse& response) {
|
||||
FillPlaylist(inbox_, response);
|
||||
if (inbox_) {
|
||||
FillPlaylist(inbox_, response);
|
||||
}
|
||||
}
|
||||
|
||||
void SpotifyService::StarredLoaded(const pb::spotify::LoadPlaylistResponse& response) {
|
||||
FillPlaylist(starred_, response);
|
||||
if (starred_) {
|
||||
FillPlaylist(starred_, response);
|
||||
}
|
||||
}
|
||||
|
||||
void SpotifyService::ToplistLoaded(const pb::spotify::BrowseToplistResponse& response) {
|
||||
FillPlaylist(toplist_, response.track());
|
||||
if (toplist_) {
|
||||
FillPlaylist(toplist_, response.track());
|
||||
}
|
||||
}
|
||||
|
||||
QStandardItem* SpotifyService::PlaylistBySpotifyIndex(int index) const {
|
||||
@ -501,7 +503,9 @@ PlaylistItem::Options SpotifyService::playlistitem_options() const {
|
||||
}
|
||||
|
||||
QWidget* SpotifyService::HeaderWidget() const {
|
||||
return search_box_;
|
||||
if (IsLoggedIn())
|
||||
return search_box_;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SpotifyService::EnsureMenuCreated() {
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#include "librarymodel.h"
|
||||
#include "widgets/lineedit.h"
|
||||
|
||||
class GroupByDialog;
|
||||
class SettingsDialog;
|
||||
|
@ -40,7 +40,7 @@ MoodbarLoader::MoodbarLoader(Application* app, QObject* parent)
|
||||
save_alongside_originals_(false)
|
||||
{
|
||||
cache_->setCacheDirectory(Utilities::GetConfigPath(Utilities::Path_MoodbarCache));
|
||||
cache_->setMaximumCacheSize(10 * 1024 * 1024); // 10MB - enough for 3333 moodbars
|
||||
cache_->setMaximumCacheSize(60 * 1024 * 1024); // 60MB - enough for 20,000 moodbars
|
||||
|
||||
connect(app, SIGNAL(SettingsChanged()), SLOT(ReloadSettings()));
|
||||
ReloadSettings();
|
||||
|
@ -296,6 +296,12 @@ QVariant Playlist::data(const QModelIndex& index, int role) const {
|
||||
return QVariant(column_alignments_.value(index.column(), (Qt::AlignLeft | Qt::AlignVCenter)));
|
||||
|
||||
case Qt::ForegroundRole:
|
||||
if (data(index, Role_IsCurrent).toBool()) {
|
||||
// Ignore any custom colours for the currently playing item - they might
|
||||
// clash with the glowing current track indicator.
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (items_[index.row()]->HasCurrentForegroundColor()) {
|
||||
return QBrush(items_[index.row()]->GetCurrentForegroundColor());
|
||||
}
|
||||
@ -305,6 +311,12 @@ QVariant Playlist::data(const QModelIndex& index, int role) const {
|
||||
return QVariant();
|
||||
|
||||
case Qt::BackgroundRole:
|
||||
if (data(index, Role_IsCurrent).toBool()) {
|
||||
// Ignore any custom colours for the currently playing item - they might
|
||||
// clash with the glowing current track indicator.
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (items_[index.row()]->HasCurrentBackgroundColor()) {
|
||||
return QBrush(items_[index.row()]->GetCurrentBackgroundColor());
|
||||
}
|
||||
@ -695,9 +707,9 @@ bool Playlist::dropMimeData(const QMimeData* data, Qt::DropAction action, int ro
|
||||
stream.readRawData(reinterpret_cast<char*>(&source_playlist), sizeof(source_playlist));
|
||||
stream >> source_rows;
|
||||
if (!stream.atEnd()) {
|
||||
stream.readRawData((char*)&pid, sizeof(pid));
|
||||
stream.readRawData((char*)&pid, sizeof(pid));
|
||||
} else {
|
||||
pid = ! own_pid;
|
||||
pid = ! own_pid;
|
||||
}
|
||||
|
||||
qStableSort(source_rows); // Make sure we take them in order
|
||||
@ -779,6 +791,10 @@ void Playlist::MoveItemsWithoutUndo(const QList<int>& source_rows, int pos) {
|
||||
layoutAboutToBeChanged();
|
||||
PlaylistItemList moved_items;
|
||||
|
||||
if (pos < 0) {
|
||||
pos = items_.count();
|
||||
}
|
||||
|
||||
// Take the items out of the list first, keeping track of whether the
|
||||
// insertion point changes
|
||||
int offset = 0;
|
||||
@ -790,10 +806,6 @@ void Playlist::MoveItemsWithoutUndo(const QList<int>& source_rows, int pos) {
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
if (pos < 0) {
|
||||
pos = items_.count();
|
||||
}
|
||||
|
||||
// Put the items back in
|
||||
for (int i=start ; i<start+moved_items.count() ; ++i) {
|
||||
|
@ -421,7 +421,11 @@ void PlaylistContainer::resizeEvent(QResizeEvent* e) {
|
||||
|
||||
void PlaylistContainer::FocusOnFilter(QKeyEvent *event) {
|
||||
ui_->filter->setFocus();
|
||||
QApplication::sendEvent(ui_->filter, event);
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
ui_->filter->clear();
|
||||
} else {
|
||||
ui_->filter->setText(ui_->filter->text() + event->text());
|
||||
}
|
||||
}
|
||||
|
||||
void PlaylistContainer::RepositionNoMatchesLabel(bool force) {
|
||||
|
@ -21,8 +21,6 @@
|
||||
#include <QWidget>
|
||||
#include <QSettings>
|
||||
|
||||
#include "widgets/lineedit.h"
|
||||
|
||||
class Ui_PlaylistContainer;
|
||||
|
||||
class DidYouMean;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,6 @@
|
||||
#include "core/song.h"
|
||||
#include "covers/albumcoverloaderoptions.h"
|
||||
#include "covers/coversearchstatistics.h"
|
||||
#include "widgets/lineedit.h"
|
||||
|
||||
class AlbumCoverChoiceController;
|
||||
class AlbumCoverFetcher;
|
||||
|
@ -20,7 +20,6 @@
|
||||
|
||||
#include "covers/albumcoverfetcher.h"
|
||||
#include "covers/albumcoverloaderoptions.h"
|
||||
#include "widgets/lineedit.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QIcon>
|
||||
|
@ -32,7 +32,8 @@ ForceScrollPerPixel::ForceScrollPerPixel(QAbstractItemView* item_view, QObject*
|
||||
bool ForceScrollPerPixel::eventFilter(QObject* object, QEvent* event) {
|
||||
if (object == item_view_ &&
|
||||
event->type() != QEvent::Destroy &&
|
||||
event->type() != QEvent::WinIdChange) {
|
||||
event->type() != QEvent::WinIdChange &&
|
||||
event->type() != QEvent::AccessibilityPrepare) {
|
||||
item_view_->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
item_view_->verticalScrollBar()->setSingleStep(20);
|
||||
}
|
||||
|
@ -104,8 +104,6 @@ public:
|
||||
QString text() const { return QLineEdit::text(); }
|
||||
void set_text(const QString& text) { QLineEdit::setText(text); }
|
||||
void set_enabled(bool enabled) { QLineEdit::setEnabled(enabled); }
|
||||
void clear() { LineEditInterface::clear(); }
|
||||
void setPlaceholderText(const QString& text) { set_hint(text); }
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent*);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user