mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-16 02:54:33 +02:00
Merge branch 'sourcetreepopup'
This commit is contained in:
Binary file not shown.
Before Width: | Height: | Size: 45 KiB |
BIN
data/images/playlist-subscribed.png
Executable file
BIN
data/images/playlist-subscribed.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
@@ -148,5 +148,7 @@
|
|||||||
<file>data/images/jump-link.png</file>
|
<file>data/images/jump-link.png</file>
|
||||||
<file>data/images/scrollbar-vertical-handle.png</file>
|
<file>data/images/scrollbar-vertical-handle.png</file>
|
||||||
<file>data/images/scrollbar-horizontal-handle.png</file>
|
<file>data/images/scrollbar-horizontal-handle.png</file>
|
||||||
|
<file>data/images/subscribe-on.png</file>
|
||||||
|
<file>data/images/subscribe-off.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@@ -139,6 +139,7 @@ set( libGuiSources
|
|||||||
widgets/ToggleButton.cpp
|
widgets/ToggleButton.cpp
|
||||||
widgets/FadingPixmap.cpp
|
widgets/FadingPixmap.cpp
|
||||||
widgets/SocialPlaylistWidget.cpp
|
widgets/SocialPlaylistWidget.cpp
|
||||||
|
widgets/SourceTreePopupDialog.cpp
|
||||||
widgets/infowidgets/SourceInfoWidget.cpp
|
widgets/infowidgets/SourceInfoWidget.cpp
|
||||||
widgets/infowidgets/ArtistInfoWidget.cpp
|
widgets/infowidgets/ArtistInfoWidget.cpp
|
||||||
widgets/infowidgets/AlbumInfoWidget.cpp
|
widgets/infowidgets/AlbumInfoWidget.cpp
|
||||||
@@ -389,7 +390,8 @@ IF( APPLE )
|
|||||||
SET( libSources ${libSources}
|
SET( libSources ${libSources}
|
||||||
utils/TomahawkUtils_Mac.mm
|
utils/TomahawkUtils_Mac.mm
|
||||||
mac/FileHelpers.mm
|
mac/FileHelpers.mm
|
||||||
thirdparty/Qocoa/qsearchfield_mac.mm )
|
thirdparty/Qocoa/qsearchfield_mac.mm
|
||||||
|
widgets/SourceTreePopupDialog_mac.mm )
|
||||||
|
|
||||||
SET_SOURCE_FILES_PROPERTIES(utils/TomahawkUtils_Mac.mm PROPERTIES COMPILE_FLAGS "-fvisibility=default")
|
SET_SOURCE_FILES_PROPERTIES(utils/TomahawkUtils_Mac.mm PROPERTIES COMPILE_FLAGS "-fvisibility=default")
|
||||||
|
|
||||||
|
@@ -37,7 +37,9 @@
|
|||||||
#include "PlaylistPlaylistInterface.h"
|
#include "PlaylistPlaylistInterface.h"
|
||||||
|
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Closure.h"
|
||||||
#include "PlaylistUpdaterInterface.h"
|
#include "PlaylistUpdaterInterface.h"
|
||||||
|
#include "widgets/SourceTreePopupDialog.h"
|
||||||
|
|
||||||
using namespace Tomahawk;
|
using namespace Tomahawk;
|
||||||
|
|
||||||
@@ -189,6 +191,7 @@ Playlist::create( const source_ptr& author,
|
|||||||
}
|
}
|
||||||
|
|
||||||
playlist_ptr playlist( new Playlist( author, guid, title, info, creator, shared, entries ), &QObject::deleteLater );
|
playlist_ptr playlist( new Playlist( author, guid, title, info, creator, shared, entries ), &QObject::deleteLater );
|
||||||
|
playlist->setWeakSelf( playlist.toWeakRef() );
|
||||||
|
|
||||||
// save to DB in the background
|
// save to DB in the background
|
||||||
// Watch for the created() signal if you need to be sure it's written.
|
// Watch for the created() signal if you need to be sure it's written.
|
||||||
@@ -310,6 +313,84 @@ Playlist::removeUpdater( PlaylistUpdaterInterface* updater )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Playlist::hasCustomDeleter() const
|
||||||
|
{
|
||||||
|
foreach ( PlaylistUpdaterInterface* updater, m_updaters )
|
||||||
|
{
|
||||||
|
if ( !updater->deleteQuestions().isEmpty() )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Playlist::customDelete( const QPoint& leftCenter )
|
||||||
|
{
|
||||||
|
if ( !hasCustomDeleter() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Tomahawk::PlaylistDeleteQuestions questions;
|
||||||
|
foreach ( PlaylistUpdaterInterface* updater, m_updaters )
|
||||||
|
{
|
||||||
|
if ( updater->deleteQuestions().isEmpty() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
questions.append( updater->deleteQuestions() );
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT( !questions.isEmpty() );
|
||||||
|
SourceTreePopupDialog* dialog = new SourceTreePopupDialog;
|
||||||
|
NewClosure( dialog, SIGNAL( result( bool ) ), this, SLOT( onDeleteResult( SourceTreePopupDialog* ) ), dialog );
|
||||||
|
|
||||||
|
dialog->setMainText( tr( "Would you like to delete the playlist <b>\"%2\"</b>?", "e.g. Would you like to delete the playlist named Foobar?" )
|
||||||
|
.arg( title() ) );
|
||||||
|
dialog->setOkButtonText( tr( "Delete" ) );
|
||||||
|
dialog->setExtraQuestions( questions );
|
||||||
|
|
||||||
|
dialog->move( leftCenter.x() - dialog->offset(), leftCenter.y() - dialog->sizeHint().height() / 2. );
|
||||||
|
dialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Playlist::onDeleteResult( SourceTreePopupDialog* dialog )
|
||||||
|
{
|
||||||
|
dialog->deleteLater();
|
||||||
|
|
||||||
|
const bool ret = dialog->resultValue();
|
||||||
|
|
||||||
|
if ( !ret )
|
||||||
|
return;
|
||||||
|
|
||||||
|
playlist_ptr p = m_weakSelf.toStrongRef();
|
||||||
|
if ( p.isNull() )
|
||||||
|
{
|
||||||
|
qWarning() << "Got null m_weakSelf weak ref in Playlsit::onDeleteResult!!";
|
||||||
|
Q_ASSERT( false );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QMap< int, bool > questionResults = dialog->questionResults();
|
||||||
|
foreach ( PlaylistUpdaterInterface* updater, m_updaters )
|
||||||
|
{
|
||||||
|
updater->setQuestionResults( questionResults );
|
||||||
|
}
|
||||||
|
|
||||||
|
dynplaylist_ptr dynpl = p.dynamicCast< DynamicPlaylist >();
|
||||||
|
if ( !dynpl.isNull() )
|
||||||
|
{
|
||||||
|
DynamicPlaylist::remove( dynpl );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
remove( p );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Playlist::loadRevision( const QString& rev )
|
Playlist::loadRevision( const QString& rev )
|
||||||
{
|
{
|
||||||
@@ -508,7 +589,7 @@ Playlist::setNewRevision( const QString& rev,
|
|||||||
tDebug() << "m_entries" << m_entries;
|
tDebug() << "m_entries" << m_entries;
|
||||||
|
|
||||||
tLog() << "Playlist error for playlist with guid" << guid() << "from source" << author()->friendlyName();
|
tLog() << "Playlist error for playlist with guid" << guid() << "from source" << author()->friendlyName();
|
||||||
Q_ASSERT( false ); // XXX
|
// Q_ASSERT( false ); // XXX
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -710,6 +791,13 @@ Playlist::checkRevisionQueue()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Playlist::setWeakSelf( QWeakPointer< Playlist > self )
|
||||||
|
{
|
||||||
|
m_weakSelf = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Tomahawk::playlistinterface_ptr
|
Tomahawk::playlistinterface_ptr
|
||||||
Playlist::playlistInterface()
|
Playlist::playlistInterface()
|
||||||
{
|
{
|
||||||
|
@@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
#include "DllMacro.h"
|
#include "DllMacro.h"
|
||||||
|
|
||||||
|
class SourceTreePopupDialog;
|
||||||
class DatabaseCommand_LoadAllPlaylists;
|
class DatabaseCommand_LoadAllPlaylists;
|
||||||
class DatabaseCommand_LoadAllSortedPlaylists;
|
class DatabaseCommand_LoadAllSortedPlaylists;
|
||||||
class DatabaseCommand_SetPlaylistRevision;
|
class DatabaseCommand_SetPlaylistRevision;
|
||||||
@@ -194,6 +195,18 @@ public:
|
|||||||
void removeUpdater( PlaylistUpdaterInterface* updater );
|
void removeUpdater( PlaylistUpdaterInterface* updater );
|
||||||
QList<PlaylistUpdaterInterface*> updaters() const { return m_updaters; }
|
QList<PlaylistUpdaterInterface*> updaters() const { return m_updaters; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some updaters might have custom deleters in order to perform more actions that require
|
||||||
|
* user prompting on delete.
|
||||||
|
*/
|
||||||
|
bool hasCustomDeleter() const;
|
||||||
|
/**
|
||||||
|
* If this playlist has a custom deleter, let it do the deleting itself.
|
||||||
|
*
|
||||||
|
* If it needs user prompting, use the \param customDeleter as the right-most center point.
|
||||||
|
*/
|
||||||
|
void customDelete( const QPoint& rightCenter );
|
||||||
|
|
||||||
Tomahawk::playlistinterface_ptr playlistInterface();
|
Tomahawk::playlistinterface_ptr playlistInterface();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -249,6 +262,7 @@ public slots:
|
|||||||
|
|
||||||
void resolve();
|
void resolve();
|
||||||
|
|
||||||
|
void setWeakSelf( QWeakPointer< Playlist > self );
|
||||||
protected:
|
protected:
|
||||||
// called from loadAllPlaylists DB cmd:
|
// called from loadAllPlaylists DB cmd:
|
||||||
explicit Playlist( const source_ptr& src,
|
explicit Playlist( const source_ptr& src,
|
||||||
@@ -282,6 +296,7 @@ private slots:
|
|||||||
void onResultsFound( const QList<Tomahawk::result_ptr>& results );
|
void onResultsFound( const QList<Tomahawk::result_ptr>& results );
|
||||||
void onResolvingFinished();
|
void onResolvingFinished();
|
||||||
|
|
||||||
|
void onDeleteResult( SourceTreePopupDialog* );
|
||||||
private:
|
private:
|
||||||
Playlist();
|
Playlist();
|
||||||
void init();
|
void init();
|
||||||
@@ -289,6 +304,7 @@ private:
|
|||||||
void setBusy( bool b );
|
void setBusy( bool b );
|
||||||
void checkRevisionQueue();
|
void checkRevisionQueue();
|
||||||
|
|
||||||
|
QWeakPointer< Playlist > m_weakSelf;
|
||||||
source_ptr m_source;
|
source_ptr m_source;
|
||||||
QString m_currentrevision;
|
QString m_currentrevision;
|
||||||
QString m_guid, m_title, m_info, m_creator;
|
QString m_guid, m_title, m_info, m_creator;
|
||||||
|
@@ -98,6 +98,9 @@ namespace Tomahawk
|
|||||||
typedef QMultiHash< QString, SerializedUpdater > SerializedUpdaters;
|
typedef QMultiHash< QString, SerializedUpdater > SerializedUpdaters;
|
||||||
typedef QList< SerializedUpdater > SerializedUpdaterList;
|
typedef QList< SerializedUpdater > SerializedUpdaterList;
|
||||||
|
|
||||||
|
// Yes/no questions with an associated enum value
|
||||||
|
typedef QPair< QString, int > PlaylistDeleteQuestion;
|
||||||
|
typedef QList< PlaylistDeleteQuestion > PlaylistDeleteQuestions;
|
||||||
|
|
||||||
namespace InfoSystem
|
namespace InfoSystem
|
||||||
{
|
{
|
||||||
|
@@ -679,7 +679,7 @@ SpotifyAccount::setSubscribedForPlaylist( const playlist_ptr& playlist, bool sub
|
|||||||
sendMessage( msg, this );
|
sendMessage( msg, this );
|
||||||
|
|
||||||
updater->setSync( subscribed );
|
updater->setSync( subscribed );
|
||||||
updater->setSubscribed( subscribed );
|
updater->setSubscribedStatus( subscribed );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -65,7 +65,7 @@ SpotifyUpdaterFactory::create( const Tomahawk::playlist_ptr& pl, const QVariantH
|
|||||||
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( m_account.data(), latestRev, spotifyId, pl );
|
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( m_account.data(), latestRev, spotifyId, pl );
|
||||||
updater->setSync( sync );
|
updater->setSync( sync );
|
||||||
updater->setCanSubscribe( canSubscribe );
|
updater->setCanSubscribe( canSubscribe );
|
||||||
updater->setSubscribed( isSubscribed );
|
updater->setSubscribedStatus( isSubscribed );
|
||||||
m_account.data()->registerUpdaterForPlaylist( spotifyId, updater );
|
m_account.data()->registerUpdaterForPlaylist( spotifyId, updater );
|
||||||
|
|
||||||
return updater;
|
return updater;
|
||||||
@@ -131,35 +131,18 @@ SpotifyPlaylistUpdater::remove( bool askToDeletePlaylist )
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SpotifyPlaylistUpdater::aboutToDelete()
|
SpotifyPlaylistUpdater::unsyncOrDelete( bool toDelete )
|
||||||
{
|
{
|
||||||
if ( QThread::currentThread() != QApplication::instance()->thread() )
|
if ( QThread::currentThread() != QApplication::instance()->thread() )
|
||||||
QMetaObject::invokeMethod( const_cast<SpotifyPlaylistUpdater*>(this), "aboutToDelete", Qt::BlockingQueuedConnection );
|
QMetaObject::invokeMethod( const_cast<SpotifyPlaylistUpdater*>(this), "unsyncOrDelete", Qt::BlockingQueuedConnection, Q_ARG( bool, toDelete ) );
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( m_subscribed )
|
if ( m_subscribed )
|
||||||
{
|
{
|
||||||
m_spotify.data()->setSubscribedForPlaylist( playlist(), false );
|
m_spotify.data()->setSubscribedForPlaylist( playlist(), false );
|
||||||
}
|
}
|
||||||
else if ( m_sync )
|
else if ( m_sync && toDelete )
|
||||||
{
|
{
|
||||||
checkDeleteDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
SpotifyPlaylistUpdater::checkDeleteDialog() const
|
|
||||||
{
|
|
||||||
// Ask if we should delete the playlist on the spotify side as well
|
|
||||||
QMessageBox askDelete( QMessageBox::Question, tr( "Delete in Spotify?" ), tr( "Would you like to delete the corresponding Spotify playlist as well?" ), QMessageBox::Yes | QMessageBox::No, 0 );
|
|
||||||
int ret = askDelete.exec();
|
|
||||||
if ( ret == QMessageBox::Yes )
|
|
||||||
{
|
|
||||||
if ( m_spotify.isNull() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// User wants to delete it!
|
// User wants to delete it!
|
||||||
QVariantMap msg;
|
QVariantMap msg;
|
||||||
msg[ "_msgtype" ] = "deletePlaylist";
|
msg[ "_msgtype" ] = "deletePlaylist";
|
||||||
@@ -167,6 +150,7 @@ SpotifyPlaylistUpdater::checkDeleteDialog() const
|
|||||||
m_spotify.data()->sendMessage( msg );
|
m_spotify.data()->sendMessage( msg );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -242,8 +226,9 @@ SpotifyPlaylistUpdater::sync() const
|
|||||||
return m_sync;
|
return m_sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SpotifyPlaylistUpdater::setSubscribed( bool subscribed )
|
SpotifyPlaylistUpdater::setSubscribedStatus( bool subscribed )
|
||||||
{
|
{
|
||||||
if ( m_subscribed == subscribed )
|
if ( m_subscribed == subscribed )
|
||||||
return;
|
return;
|
||||||
@@ -255,6 +240,16 @@ SpotifyPlaylistUpdater::setSubscribed( bool subscribed )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SpotifyPlaylistUpdater::setSubscribed( bool subscribed )
|
||||||
|
{
|
||||||
|
if ( !m_spotify.isNull() )
|
||||||
|
m_spotify.data()->setSubscribedForPlaylist( playlist(), subscribed );
|
||||||
|
|
||||||
|
// Spotify account will in turn call setSUbscribedStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SpotifyPlaylistUpdater::subscribed() const
|
SpotifyPlaylistUpdater::subscribed() const
|
||||||
{
|
{
|
||||||
@@ -282,6 +277,25 @@ SpotifyPlaylistUpdater::canSubscribe() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PlaylistDeleteQuestions
|
||||||
|
SpotifyPlaylistUpdater::deleteQuestions() const
|
||||||
|
{
|
||||||
|
// 1234 is our magic key
|
||||||
|
if ( m_sync && !m_subscribed )
|
||||||
|
return Tomahawk::PlaylistDeleteQuestions() << qMakePair<QString, int>( tr( "Delete associated Spotify playlist?" ), 1234 );
|
||||||
|
else
|
||||||
|
return Tomahawk::PlaylistDeleteQuestions();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SpotifyPlaylistUpdater::setQuestionResults( const QMap< int, bool > results )
|
||||||
|
{
|
||||||
|
const bool toDelete = results.value( 1234, false );
|
||||||
|
unsyncOrDelete( toDelete );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SpotifyPlaylistUpdater::spotifyTracksAdded( const QVariantList& tracks, const QString& startPosId, const QString& newRev, const QString& oldRev )
|
SpotifyPlaylistUpdater::spotifyTracksAdded( const QVariantList& tracks, const QString& startPosId, const QString& newRev, const QString& oldRev )
|
||||||
{
|
{
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
#include "playlist/PlaylistUpdaterInterface.h"
|
#include "playlist/PlaylistUpdaterInterface.h"
|
||||||
#include "utils/Closure.h"
|
#include "utils/Closure.h"
|
||||||
#include "DllMacro.h"
|
#include "DllMacro.h"
|
||||||
|
#include "Typedefs.h"
|
||||||
|
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
@@ -55,11 +56,17 @@ public:
|
|||||||
bool sync() const;
|
bool sync() const;
|
||||||
void setSync( bool sync );
|
void setSync( bool sync );
|
||||||
bool subscribed() const;
|
bool subscribed() const;
|
||||||
|
// actually change the subscribed value in spotify
|
||||||
void setSubscribed( bool subscribed );
|
void setSubscribed( bool subscribed );
|
||||||
|
// Just set the subscribed flag
|
||||||
|
void setSubscribedStatus( bool subscribed );
|
||||||
bool canSubscribe() const;
|
bool canSubscribe() const;
|
||||||
void setCanSubscribe( bool canSub );
|
void setCanSubscribe( bool canSub );
|
||||||
QString spotifyId() const { return m_spotifyId; }
|
QString spotifyId() const { return m_spotifyId; }
|
||||||
|
|
||||||
|
virtual Tomahawk::PlaylistDeleteQuestions deleteQuestions() const;
|
||||||
|
virtual void setQuestionResults( const QMap< int, bool > results );
|
||||||
|
|
||||||
void remove( bool askToDeletePlaylist = true );
|
void remove( bool askToDeletePlaylist = true );
|
||||||
public slots:
|
public slots:
|
||||||
/// Spotify callbacks when we are directly instructed from the resolver
|
/// Spotify callbacks when we are directly instructed from the resolver
|
||||||
@@ -73,15 +80,13 @@ public slots:
|
|||||||
void tomahawkTracksMoved( const QList<Tomahawk::plentry_ptr>& ,int );
|
void tomahawkTracksMoved( const QList<Tomahawk::plentry_ptr>& ,int );
|
||||||
void tomahawkPlaylistRenamed( const QString&, const QString& );
|
void tomahawkPlaylistRenamed( const QString&, const QString& );
|
||||||
|
|
||||||
void aboutToDelete();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
// SpotifyResolver message handlers, all take msgtype, msg as argument
|
// SpotifyResolver message handlers, all take msgtype, msg as argument
|
||||||
void onTracksInsertedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
|
void onTracksInsertedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
|
||||||
void onTracksRemovedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
|
void onTracksRemovedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
|
||||||
void onTracksMovedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
|
void onTracksMovedReturn( const QString& msgType, const QVariantMap& msg, const QVariant& extraData );
|
||||||
|
|
||||||
void checkDeleteDialog() const;
|
void unsyncOrDelete( bool toDelete );
|
||||||
|
|
||||||
void playlistRevisionLoaded();
|
void playlistRevisionLoaded();
|
||||||
private:
|
private:
|
||||||
|
@@ -144,6 +144,8 @@ DatabaseCollection::autoPlaylistCreated( const source_ptr& source, const QVarian
|
|||||||
data[7].toBool(), //shared
|
data[7].toBool(), //shared
|
||||||
data[8].toInt(), //lastmod
|
data[8].toInt(), //lastmod
|
||||||
data[9].toString() ), &QObject::deleteLater ); //GUID
|
data[9].toString() ), &QObject::deleteLater ); //GUID
|
||||||
|
p->setWeakSelf( p.toWeakRef() );
|
||||||
|
|
||||||
addAutoPlaylist( p );
|
addAutoPlaylist( p );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +164,8 @@ DatabaseCollection::stationCreated( const source_ptr& source, const QVariantList
|
|||||||
data[7].toBool(), //shared
|
data[7].toBool(), //shared
|
||||||
data[8].toInt(), //lastmod
|
data[8].toInt(), //lastmod
|
||||||
data[9].toString() ), &QObject::deleteLater ); //GUID
|
data[9].toString() ), &QObject::deleteLater ); //GUID
|
||||||
|
p->setWeakSelf( p.toWeakRef() );
|
||||||
|
|
||||||
addStation( p );
|
addStation( p );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -72,6 +72,7 @@ DatabaseCommand_LoadAllPlaylists::exec( DatabaseImpl* dbi )
|
|||||||
query.value(4).toInt(), //lastmod
|
query.value(4).toInt(), //lastmod
|
||||||
query.value(0).toString() //GUID
|
query.value(0).toString() //GUID
|
||||||
), &QObject::deleteLater );
|
), &QObject::deleteLater );
|
||||||
|
p->setWeakSelf( p.toWeakRef() );
|
||||||
plists.append( p );
|
plists.append( p );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -70,38 +70,7 @@ DatabaseCommand_LoadAllSortedPlaylists::exec( DatabaseImpl* dbi )
|
|||||||
while ( query.next() )
|
while ( query.next() )
|
||||||
{
|
{
|
||||||
plists << QPair< int, QString >( query.value(9).toInt(), query.value(0).toString() );
|
plists << QPair< int, QString >( query.value(9).toInt(), query.value(0).toString() );
|
||||||
// playlist_ptr p;
|
|
||||||
// bool dynamic = query.value(8).toBool();
|
|
||||||
// source_ptr s = SourceList::instance()->get( query.value(9).toInt() );
|
|
||||||
//
|
|
||||||
// if ( dynamic )
|
|
||||||
// {
|
|
||||||
// p = dynplaylist_ptr( new DynamicPlaylist( s,
|
|
||||||
// query.value(6).toString(), //current rev
|
|
||||||
// query.value(1).toString(), //title
|
|
||||||
// query.value(2).toString(), //info
|
|
||||||
// query.value(3).toString(), //creator
|
|
||||||
// query.value(7).toInt(), //createdOn
|
|
||||||
// query.value(10).toString(), //type
|
|
||||||
// (GeneratorMode)query.value(11).toInt(), // mode
|
|
||||||
// query.value(5).toBool(), //shared
|
|
||||||
// query.value(4).toInt(), //lastmod
|
|
||||||
// query.value(0).toString() //GUID
|
|
||||||
// ) );
|
|
||||||
// } else
|
|
||||||
// {
|
|
||||||
// p = playlist_ptr( new Playlist( s, //src
|
|
||||||
// query.value(6).toString(), //current rev
|
|
||||||
// query.value(1).toString(), //title
|
|
||||||
// query.value(2).toString(), //info
|
|
||||||
// query.value(3).toString(), //creator
|
|
||||||
// query.value(7).toInt(), //createdOn
|
|
||||||
// query.value(5).toBool(), //shared
|
|
||||||
// query.value(4).toInt(), //lastmod
|
|
||||||
// query.value(0).toString() //GUID
|
|
||||||
// ) );
|
|
||||||
// }
|
|
||||||
// plists.append( p );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emit done( plists );
|
emit done( plists );
|
||||||
|
@@ -60,6 +60,8 @@ Tomahawk::DatabaseCommand_LoadDynamicPlaylist::exec( DatabaseImpl* dbi )
|
|||||||
query.value(5).toInt(), //lastmod
|
query.value(5).toInt(), //lastmod
|
||||||
query.value(0).toString() ) ); //GUID
|
query.value(0).toString() ) ); //GUID
|
||||||
|
|
||||||
|
p->setWeakSelf( p.toWeakRef() );
|
||||||
|
/*
|
||||||
tLog() << "Loaded individual dynamic playlist:" << query.value(7).toString() //current rev
|
tLog() << "Loaded individual dynamic playlist:" << query.value(7).toString() //current rev
|
||||||
<< query.value(1).toString() //title
|
<< query.value(1).toString() //title
|
||||||
<< query.value(2).toString() //info
|
<< query.value(2).toString() //info
|
||||||
@@ -69,7 +71,7 @@ Tomahawk::DatabaseCommand_LoadDynamicPlaylist::exec( DatabaseImpl* dbi )
|
|||||||
<< static_cast<GeneratorMode>(query.value(9).toInt()) // dynamic mode
|
<< static_cast<GeneratorMode>(query.value(9).toInt()) // dynamic mode
|
||||||
<< query.value(6).toBool() //shared
|
<< query.value(6).toBool() //shared
|
||||||
<< query.value(5).toInt() //lastmod
|
<< query.value(5).toInt() //lastmod
|
||||||
<< query.value(0).toString(); //GUID
|
<< query.value(0).toString(); //GUID */
|
||||||
|
|
||||||
emit dynamicPlaylistLoaded( p );
|
emit dynamicPlaylistLoaded( p );
|
||||||
}
|
}
|
||||||
|
@@ -80,7 +80,7 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn
|
|||||||
setReadOnly( !m_playlist->author()->isLocal() );
|
setReadOnly( !m_playlist->author()->isLocal() );
|
||||||
setTitle( playlist->title() );
|
setTitle( playlist->title() );
|
||||||
setDescription( tr( "A playlist by %1, created %2" )
|
setDescription( tr( "A playlist by %1, created %2" )
|
||||||
.arg( playlist->author()->isLocal() ? tr( "you" ) : playlist->author()->friendlyName() )
|
.arg( playlist->creator().isEmpty() ? ( playlist->author()->isLocal() ? tr( "you" ) : playlist->author()->friendlyName() ) : playlist->creator() )
|
||||||
.arg( TomahawkUtils::ageToString( QDateTime::fromTime_t( playlist->createdOn() ), true ) ) );
|
.arg( TomahawkUtils::ageToString( QDateTime::fromTime_t( playlist->createdOn() ), true ) ) );
|
||||||
|
|
||||||
m_isTemporary = false;
|
m_isTemporary = false;
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
|
#include <QPair>
|
||||||
|
|
||||||
#ifndef ENABLE_HEADLESS
|
#ifndef ENABLE_HEADLESS
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
@@ -35,6 +36,12 @@ namespace Tomahawk
|
|||||||
/**
|
/**
|
||||||
* PlaylistUpdaters are attached to playlists. They usually manipulate the playlist in some way
|
* PlaylistUpdaters are attached to playlists. They usually manipulate the playlist in some way
|
||||||
* due to external input (spotify syncing) or timers (xspf updating)
|
* due to external input (spotify syncing) or timers (xspf updating)
|
||||||
|
*
|
||||||
|
* Updaters have 2 modes of operation: syncing and subscribing. Syncing implies two-way sync, that is, this
|
||||||
|
* playlist is reproduced on some other service (e.g. spotify or rdio).
|
||||||
|
*
|
||||||
|
* Subscribing implies the playlist is being updated periodically with changes from some source, and the user
|
||||||
|
* is working with a copy: e.g. an xspf updater or a spotify subscribed playlist.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class PlaylistUpdaterFactory;
|
class PlaylistUpdaterFactory;
|
||||||
@@ -71,7 +78,17 @@ public:
|
|||||||
|
|
||||||
static void registerUpdaterFactory( PlaylistUpdaterFactory* f );
|
static void registerUpdaterFactory( PlaylistUpdaterFactory* f );
|
||||||
|
|
||||||
virtual bool sync() const { return true; }
|
virtual bool sync() const { return false; }
|
||||||
|
virtual void setSync( bool ) {}
|
||||||
|
|
||||||
|
virtual bool canSubscribe() const { return false; }
|
||||||
|
virtual bool subscribed() const { return false; }
|
||||||
|
virtual void setSubscribed( bool ) {}
|
||||||
|
|
||||||
|
// The int data value associated with each question must be unique across *all* playlist updaters,
|
||||||
|
// as setQuestionResults is called with all questions from all updaters.
|
||||||
|
virtual PlaylistDeleteQuestions deleteQuestions() const { return PlaylistDeleteQuestions(); }
|
||||||
|
virtual void setQuestionResults( const QMap< int, bool > results ) {}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void changed();
|
void changed();
|
||||||
|
@@ -144,6 +144,8 @@ XspfUpdater::setAutoUpdate( bool autoUpdate )
|
|||||||
// Update immediately as well
|
// Update immediately as well
|
||||||
if ( m_autoUpdate )
|
if ( m_autoUpdate )
|
||||||
QTimer::singleShot( 0, this, SLOT( updateNow() ) );
|
QTimer::singleShot( 0, this, SLOT( updateNow() ) );
|
||||||
|
|
||||||
|
emit changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -158,3 +160,10 @@ XspfUpdater::setInterval( int intervalMsecs )
|
|||||||
|
|
||||||
m_timer->setInterval( intervalMsecs );
|
m_timer->setInterval( intervalMsecs );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
XspfUpdater::setSubscribed( bool subscribed )
|
||||||
|
{
|
||||||
|
setAutoUpdate( subscribed );
|
||||||
|
}
|
||||||
|
@@ -48,6 +48,10 @@ public:
|
|||||||
void setInterval( int intervalMsecs ) ;
|
void setInterval( int intervalMsecs ) ;
|
||||||
int intervalMsecs() const { return m_timer->interval(); }
|
int intervalMsecs() const { return m_timer->interval(); }
|
||||||
|
|
||||||
|
bool canSubscribe() const { return true; }
|
||||||
|
bool subscribed() const { return m_autoUpdate; }
|
||||||
|
void setSubscribed( bool subscribed );
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateNow();
|
void updateNow();
|
||||||
void setAutoUpdate( bool autoUpdate );
|
void setAutoUpdate( bool autoUpdate );
|
||||||
|
@@ -155,6 +155,7 @@ DynamicPlaylist::create( const Tomahawk::source_ptr& author,
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
dynplaylist_ptr dynplaylist = Tomahawk::dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared, autoLoad ), &QObject::deleteLater );
|
dynplaylist_ptr dynplaylist = Tomahawk::dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared, autoLoad ), &QObject::deleteLater );
|
||||||
|
dynplaylist->setWeakSelf( dynplaylist.toWeakRef() );
|
||||||
|
|
||||||
DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist, autoLoad );
|
DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist, autoLoad );
|
||||||
connect( cmd, SIGNAL(finished()), dynplaylist.data(), SIGNAL(created()) );
|
connect( cmd, SIGNAL(finished()), dynplaylist.data(), SIGNAL(created()) );
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2011, David Sansome <me@davidsansome.com>
|
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||||
|
Copyright 2012, Leo Franchi <lfranchi@kde.org>
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,9 +17,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Closure.h"
|
#include "Closure.h"
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
namespace _detail {
|
namespace _detail {
|
||||||
|
|
||||||
|
static bool on_this_thread(QObject* obj)
|
||||||
|
{
|
||||||
|
return QCoreApplication::instance()->thread() == obj->thread();
|
||||||
|
}
|
||||||
|
|
||||||
Closure::Closure(QObject* sender,
|
Closure::Closure(QObject* sender,
|
||||||
const char* signal,
|
const char* signal,
|
||||||
QObject* receiver,
|
QObject* receiver,
|
||||||
@@ -27,9 +34,10 @@ Closure::Closure(QObject* sender,
|
|||||||
const ClosureArgumentWrapper* val1,
|
const ClosureArgumentWrapper* val1,
|
||||||
const ClosureArgumentWrapper* val2,
|
const ClosureArgumentWrapper* val2,
|
||||||
const ClosureArgumentWrapper* val3)
|
const ClosureArgumentWrapper* val3)
|
||||||
: QObject(receiver),
|
: QObject(on_this_thread(receiver) ? receiver : 0),
|
||||||
callback_(NULL),
|
callback_(NULL),
|
||||||
autoDelete_(true),
|
autoDelete_(true),
|
||||||
|
outOfThreadReceiver_(on_this_thread(receiver) ? 0 : receiver ),
|
||||||
val0_(val0),
|
val0_(val0),
|
||||||
val1_(val1),
|
val1_(val1),
|
||||||
val2_(val2),
|
val2_(val2),
|
||||||
@@ -77,7 +85,7 @@ void Closure::Invoked() {
|
|||||||
callback_();
|
callback_();
|
||||||
} else {
|
} else {
|
||||||
slot_.invoke(
|
slot_.invoke(
|
||||||
parent(),
|
parent() ? parent() : outOfThreadReceiver_,
|
||||||
val0_ ? val0_->arg() : QGenericArgument(),
|
val0_ ? val0_->arg() : QGenericArgument(),
|
||||||
val1_ ? val1_->arg() : QGenericArgument(),
|
val1_ ? val1_->arg() : QGenericArgument(),
|
||||||
val2_ ? val2_->arg() : QGenericArgument(),
|
val2_ ? val2_->arg() : QGenericArgument(),
|
||||||
|
@@ -89,6 +89,7 @@ class DLLEXPORT Closure : public QObject, boost::noncopyable {
|
|||||||
QMetaMethod slot_;
|
QMetaMethod slot_;
|
||||||
std::tr1::function<void()> callback_;
|
std::tr1::function<void()> callback_;
|
||||||
bool autoDelete_;
|
bool autoDelete_;
|
||||||
|
QObject* outOfThreadReceiver_;
|
||||||
|
|
||||||
boost::scoped_ptr<const ClosureArgumentWrapper> val0_;
|
boost::scoped_ptr<const ClosureArgumentWrapper> val0_;
|
||||||
boost::scoped_ptr<const ClosureArgumentWrapper> val1_;
|
boost::scoped_ptr<const ClosureArgumentWrapper> val1_;
|
||||||
|
@@ -358,12 +358,19 @@ SpotifyParser::checkBrowseFinished()
|
|||||||
|
|
||||||
if ( m_createNewPlaylist && !m_tracks.isEmpty() )
|
if ( m_createNewPlaylist && !m_tracks.isEmpty() )
|
||||||
{
|
{
|
||||||
|
QString spotifyUsername;
|
||||||
|
|
||||||
|
if ( Accounts::SpotifyAccount::instance() && Accounts::SpotifyAccount::instance()->loggedIn() )
|
||||||
|
{
|
||||||
|
QVariantHash creds = Accounts::SpotifyAccount::instance()->credentials();
|
||||||
|
spotifyUsername = creds.value( "username" ).toString();
|
||||||
|
}
|
||||||
|
|
||||||
m_playlist = Playlist::create( SourceList::instance()->getLocal(),
|
m_playlist = Playlist::create( SourceList::instance()->getLocal(),
|
||||||
uuid(),
|
uuid(),
|
||||||
m_title,
|
m_title,
|
||||||
m_info,
|
m_info,
|
||||||
m_creator,
|
spotifyUsername == m_creator ? QString() : m_creator,
|
||||||
false,
|
false,
|
||||||
m_tracks );
|
m_tracks );
|
||||||
|
|
||||||
@@ -374,10 +381,9 @@ SpotifyParser::checkBrowseFinished()
|
|||||||
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater(
|
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater(
|
||||||
Accounts::SpotifyAccount::instance(), m_playlist->currentrevision(), m_browseUri, m_playlist );
|
Accounts::SpotifyAccount::instance(), m_playlist->currentrevision(), m_browseUri, m_playlist );
|
||||||
|
|
||||||
QVariantHash creds = Accounts::SpotifyAccount::instance()->credentials();
|
|
||||||
|
|
||||||
// If the user isnt dropping a playlist the he owns, its subscribeable
|
// If the user isnt dropping a playlist the he owns, its subscribeable
|
||||||
if ( !m_browseUri.contains( creds.value( "username" ).toString() ) )
|
if ( !m_browseUri.contains( spotifyUsername ) )
|
||||||
updater->setCanSubscribe( true );
|
updater->setCanSubscribe( true );
|
||||||
|
|
||||||
// Just register the infos
|
// Just register the infos
|
||||||
|
220
src/libtomahawk/widgets/SourceTreePopupDialog.cpp
Normal file
220
src/libtomahawk/widgets/SourceTreePopupDialog.cpp
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk 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.
|
||||||
|
*
|
||||||
|
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SourceTreePopupDialog.h"
|
||||||
|
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#ifdef QT_MAC_USE_COCOA
|
||||||
|
#include "SourceTreePopupDialog_mac.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace Tomahawk;
|
||||||
|
|
||||||
|
SourceTreePopupDialog::SourceTreePopupDialog()
|
||||||
|
: QWidget( 0 )
|
||||||
|
, m_layout( 0 )
|
||||||
|
, m_result( false )
|
||||||
|
, m_label( 0 )
|
||||||
|
, m_buttons( 0 )
|
||||||
|
{
|
||||||
|
setWindowFlags( Qt::FramelessWindowHint );
|
||||||
|
setWindowFlags( Qt::Popup );
|
||||||
|
|
||||||
|
setAutoFillBackground( false );
|
||||||
|
setAttribute( Qt::WA_TranslucentBackground, true );
|
||||||
|
|
||||||
|
setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
|
||||||
|
|
||||||
|
m_label = new QLabel( this );
|
||||||
|
m_buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this );
|
||||||
|
m_buttons->button( QDialogButtonBox::Ok )->setIcon( QIcon() );
|
||||||
|
m_buttons->button( QDialogButtonBox::Cancel )->setIcon( QIcon() );
|
||||||
|
|
||||||
|
connect( m_buttons, SIGNAL( accepted() ), this, SLOT( onAccepted() ) );
|
||||||
|
connect( m_buttons, SIGNAL( rejected() ), this, SLOT( onRejected() ) );
|
||||||
|
|
||||||
|
m_layout = new QVBoxLayout;
|
||||||
|
setLayout( m_layout );
|
||||||
|
|
||||||
|
layout()->addWidget( m_label );
|
||||||
|
layout()->addWidget( m_buttons );
|
||||||
|
setContentsMargins( contentsMargins().left() + 2, contentsMargins().top(), contentsMargins().right(), contentsMargins().bottom() );
|
||||||
|
|
||||||
|
/*
|
||||||
|
m_buttons->button( QDialogButtonBox::Ok )->setStyleSheet(
|
||||||
|
"QPushButton { \
|
||||||
|
background-color: #F15C5E; \
|
||||||
|
border-style: solid; \
|
||||||
|
border-width: 1px; \
|
||||||
|
border-radius: 10px; \
|
||||||
|
border-color: #B64547; \
|
||||||
|
padding: 2px; \
|
||||||
|
} \
|
||||||
|
QPushButton:pressed { \
|
||||||
|
border-style: solid; \
|
||||||
|
border-width: 1px; \
|
||||||
|
border-radius: 10px; \
|
||||||
|
border-color: #B64547; \
|
||||||
|
background-color: #D35052; \
|
||||||
|
border-style: flat; \
|
||||||
|
}" );*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreePopupDialog::setMainText( const QString& text )
|
||||||
|
{
|
||||||
|
m_label->setText( text );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreePopupDialog::setOkButtonText( const QString& text )
|
||||||
|
{
|
||||||
|
if ( m_buttons && m_buttons->button( QDialogButtonBox::Ok ) )
|
||||||
|
m_buttons->button( QDialogButtonBox::Ok )->setText( text );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreePopupDialog::setExtraQuestions( const Tomahawk::PlaylistDeleteQuestions& questions )
|
||||||
|
{
|
||||||
|
m_questions = questions;
|
||||||
|
|
||||||
|
int idx = m_layout->indexOf( m_label ) + 1;
|
||||||
|
foreach ( const Tomahawk::PlaylistDeleteQuestion& question, m_questions )
|
||||||
|
{
|
||||||
|
QCheckBox* cb = new QCheckBox( question.first, this );
|
||||||
|
cb->setLayoutDirection( Qt::RightToLeft );
|
||||||
|
cb->setProperty( "data", question.second );
|
||||||
|
|
||||||
|
QHBoxLayout* h = new QHBoxLayout;
|
||||||
|
h->addStretch( 1 );
|
||||||
|
h->addWidget( cb );
|
||||||
|
// m_layout->insertLayout( h, cb, 0 );
|
||||||
|
m_layout->insertLayout( idx, h, 0 );
|
||||||
|
|
||||||
|
m_questionCheckboxes << cb;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreePopupDialog::paintEvent( QPaintEvent* event )
|
||||||
|
{
|
||||||
|
// Constants for painting
|
||||||
|
const int leftTriangleWidth = 20;
|
||||||
|
const int cornerRounding = 8;
|
||||||
|
const int leftEdgeOffset = offset() - 6;
|
||||||
|
const QRect brect = rect().adjusted( 2, 3, -2, -3 );
|
||||||
|
|
||||||
|
QPainterPath outline;
|
||||||
|
// Left triangle top branch
|
||||||
|
outline.moveTo( brect.left(), brect.top() + brect.height() / 2 );
|
||||||
|
outline.lineTo( leftEdgeOffset, brect.top() + brect.height() / 2 - leftTriangleWidth / 2 );
|
||||||
|
|
||||||
|
// main outline
|
||||||
|
outline.lineTo( leftEdgeOffset, cornerRounding );
|
||||||
|
outline.quadTo( QPoint( leftEdgeOffset, brect.top() ), QPoint( leftEdgeOffset + cornerRounding, brect.top() ) );
|
||||||
|
outline.lineTo( brect.width() - cornerRounding, brect.top() );
|
||||||
|
outline.quadTo( QPoint( brect.width(), brect.top() ), QPoint( brect.width(), cornerRounding ) );
|
||||||
|
outline.lineTo( brect.width(), brect.height() - cornerRounding );
|
||||||
|
outline.quadTo( brect.bottomRight(), QPoint( brect.right() - cornerRounding, brect.height() ) );
|
||||||
|
outline.lineTo( leftEdgeOffset + cornerRounding, brect.height() );
|
||||||
|
outline.quadTo( QPoint( leftEdgeOffset, brect.height() ), QPoint( leftEdgeOffset, brect.height() - cornerRounding ) );
|
||||||
|
|
||||||
|
// Left triangle bottom branch
|
||||||
|
outline.lineTo( leftEdgeOffset, brect.top() + brect.height() / 2 + leftTriangleWidth / 2 );
|
||||||
|
outline.lineTo( brect.left(), brect.top() + brect.height() / 2 );
|
||||||
|
|
||||||
|
QPainter p( this );
|
||||||
|
|
||||||
|
p.setRenderHint( QPainter::Antialiasing );
|
||||||
|
|
||||||
|
QPen pen( QColor( "#3F4247" ) );
|
||||||
|
pen.setWidth( 2 );
|
||||||
|
p.setPen( pen );
|
||||||
|
p.drawPath( outline );
|
||||||
|
|
||||||
|
p.setOpacity( 0.93 );
|
||||||
|
p.fillPath( outline, QColor( "#D6E3F1" ) );
|
||||||
|
|
||||||
|
#ifdef QT_MAC_USE_COCOA
|
||||||
|
// Work around bug in Qt/Mac Cocoa where opening subsequent popups
|
||||||
|
// would incorrectly calculate the background due to it not being
|
||||||
|
// invalidated.
|
||||||
|
SourceTreePopupHelper::clearBackground( this );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreePopupDialog::focusOutEvent( QFocusEvent* )
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreePopupDialog::showEvent( QShowEvent* )
|
||||||
|
{
|
||||||
|
m_result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreePopupDialog::onAccepted()
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
m_result = true;
|
||||||
|
calculateResults();
|
||||||
|
emit result( m_result );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreePopupDialog::onRejected()
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
m_result = false;
|
||||||
|
calculateResults();
|
||||||
|
emit result( m_result );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreePopupDialog::calculateResults()
|
||||||
|
{
|
||||||
|
foreach ( const QCheckBox* b, m_questionCheckboxes )
|
||||||
|
{
|
||||||
|
if ( b->property( "data" ).toInt() != 0 )
|
||||||
|
{
|
||||||
|
m_questionResults[ b->property( "data" ).toInt() ] = ( b->checkState() == Qt::Checked );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
85
src/libtomahawk/widgets/SourceTreePopupDialog.h
Normal file
85
src/libtomahawk/widgets/SourceTreePopupDialog.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk 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.
|
||||||
|
*
|
||||||
|
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOURCETREE_POPUP_DIALOG
|
||||||
|
#define SOURCETREE_POPUP_DIALOG
|
||||||
|
|
||||||
|
#include "DllMacro.h"
|
||||||
|
#include "Typedefs.h"
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QMetaType>
|
||||||
|
|
||||||
|
class QVBoxLayout;
|
||||||
|
class QShowEvent;
|
||||||
|
class QLabel;
|
||||||
|
class QDialogButtonBox;
|
||||||
|
class QPushButton;
|
||||||
|
class QFocusEvent;
|
||||||
|
class QCheckBox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place me at offset() to the left of the right edge of the sourcetree.
|
||||||
|
*/
|
||||||
|
class DLLEXPORT SourceTreePopupDialog : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SourceTreePopupDialog();
|
||||||
|
|
||||||
|
int offset() const { return 16; }
|
||||||
|
|
||||||
|
void setMainText( const QString& text );
|
||||||
|
void setOkButtonText( const QString& text );
|
||||||
|
void setExtraQuestions( const Tomahawk::PlaylistDeleteQuestions& questions );
|
||||||
|
|
||||||
|
bool resultValue() const { return m_result; }
|
||||||
|
QMap< int, bool > questionResults() const { return m_questionResults; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void result( bool accepted );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void paintEvent( QPaintEvent* );
|
||||||
|
virtual void focusOutEvent( QFocusEvent* );
|
||||||
|
virtual void showEvent( QShowEvent* );
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onAccepted();
|
||||||
|
void onRejected();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void calculateResults();
|
||||||
|
|
||||||
|
QVBoxLayout* m_layout;
|
||||||
|
QList< QCheckBox* > m_questionCheckboxes;
|
||||||
|
|
||||||
|
QString m_text;
|
||||||
|
bool m_result;
|
||||||
|
Tomahawk::PlaylistDeleteQuestions m_questions;
|
||||||
|
QMap< int, bool > m_questionResults;
|
||||||
|
|
||||||
|
QLabel* m_label;
|
||||||
|
QDialogButtonBox* m_buttons;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE( SourceTreePopupDialog* )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class QCheckBox;
|
29
src/libtomahawk/widgets/SourceTreePopupDialog_mac.h
Normal file
29
src/libtomahawk/widgets/SourceTreePopupDialog_mac.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk 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.
|
||||||
|
*
|
||||||
|
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOURCETREE_POPUP_DIALOG_MAC_H
|
||||||
|
#define SOURCETREE_POPUP_DIALOG_MAC_H
|
||||||
|
|
||||||
|
class QWidget;
|
||||||
|
|
||||||
|
namespace SourceTreePopupHelper {
|
||||||
|
|
||||||
|
void clearBackground( QWidget* widget );
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
35
src/libtomahawk/widgets/SourceTreePopupDialog_mac.mm
Normal file
35
src/libtomahawk/widgets/SourceTreePopupDialog_mac.mm
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk 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.
|
||||||
|
*
|
||||||
|
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SourceTreePopupDialog_mac.h"
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <AppKit/NSView.h>
|
||||||
|
#import <AppKit/NSWindow.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreePopupHelper::clearBackground( QWidget* widget )
|
||||||
|
{
|
||||||
|
Q_ASSERT( widget );
|
||||||
|
// Workaround from QTBUG-15368
|
||||||
|
NSView* view = reinterpret_cast< NSView* >( widget->winId() );
|
||||||
|
NSWindow* cocoaWindow = [view window];
|
||||||
|
[cocoaWindow invalidateShadow];
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
*
|
*
|
||||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
* Copyright 2011-2012, Leo Franchi <lfranchi@kde.org>
|
||||||
* Copyright 2011, Michael Zanetti <mzanetti@kde.org>
|
* Copyright 2011, Michael Zanetti <mzanetti@kde.org>
|
||||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||||
*
|
*
|
||||||
@@ -549,6 +549,22 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
|
|||||||
else
|
else
|
||||||
QStyledItemDelegate::paint( painter, o, index );
|
QStyledItemDelegate::paint( painter, o, index );
|
||||||
}
|
}
|
||||||
|
else if ( type == SourcesModel::StaticPlaylist )
|
||||||
|
{
|
||||||
|
QStyledItemDelegate::paint( painter, o, index );
|
||||||
|
|
||||||
|
PlaylistItem* plItem = qobject_cast< PlaylistItem* >( item );
|
||||||
|
if ( plItem->canSubscribe() && !plItem->subscribedIcon().isNull() )
|
||||||
|
{
|
||||||
|
const int padding = 2;
|
||||||
|
const int imgWidth = o.rect.height() - 2*padding;
|
||||||
|
|
||||||
|
const QPixmap icon = plItem->subscribedIcon().scaled( imgWidth, imgWidth, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||||
|
|
||||||
|
const QRect subRect( o.rect.right() - padding - imgWidth, o.rect.top() + padding, imgWidth, imgWidth );
|
||||||
|
painter->drawPixmap( subRect, icon );
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
QStyledItemDelegate::paint( painter, o, index );
|
QStyledItemDelegate::paint( painter, o, index );
|
||||||
}
|
}
|
||||||
@@ -639,6 +655,25 @@ SourceDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ( event->type() == QEvent::MouseButtonRelease && type == SourcesModel::StaticPlaylist )
|
||||||
|
{
|
||||||
|
PlaylistItem* plItem = qobject_cast< PlaylistItem* >( index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >() );
|
||||||
|
Q_ASSERT( plItem );
|
||||||
|
|
||||||
|
QMouseEvent* mev = static_cast< QMouseEvent* >( event );
|
||||||
|
if ( plItem->canSubscribe() && !plItem->subscribedIcon().isNull() )
|
||||||
|
{
|
||||||
|
const int padding = 2;
|
||||||
|
const int imgWidth = option.rect.height() - 2*padding;
|
||||||
|
const QRect subRect( option.rect.right() - padding - imgWidth, option.rect.top() + padding, imgWidth, imgWidth );
|
||||||
|
|
||||||
|
if ( subRect.contains( mev->pos() ) )
|
||||||
|
{
|
||||||
|
// Toggle playlist subscription
|
||||||
|
plItem->setSubscribed( !plItem->subscribed() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We emit our own clicked() signal instead of relying on QTreeView's, because that is fired whether or not a delegate accepts
|
// We emit our own clicked() signal instead of relying on QTreeView's, because that is fired whether or not a delegate accepts
|
||||||
|
@@ -51,6 +51,8 @@
|
|||||||
#include "LatchManager.h"
|
#include "LatchManager.h"
|
||||||
#include "utils/TomahawkUtilsGui.h"
|
#include "utils/TomahawkUtilsGui.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Closure.h"
|
||||||
|
#include "widgets/SourceTreePopupDialog.h"
|
||||||
|
|
||||||
using namespace Tomahawk;
|
using namespace Tomahawk;
|
||||||
|
|
||||||
@@ -362,29 +364,59 @@ SourceTreeView::deletePlaylist( const QModelIndex& idxIn )
|
|||||||
Q_ASSERT( false );
|
Q_ASSERT( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
QMessageBox askDelete( QMessageBox::Question, tr( "Delete %1?", "playlist/station/..." ).arg( typeDesc ),
|
PlaylistItem* item = itemFromIndex< PlaylistItem >( idx );
|
||||||
tr( "Would you like to delete the %1 <b>\"%2\"</b>?", "e.g. Would you like to delete the playlist named Foobar?" )
|
playlist_ptr playlist = item->playlist();
|
||||||
.arg( typeDesc ).arg( idx.data().toString() ),
|
|
||||||
QMessageBox::Yes | QMessageBox::No, this );
|
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
const QPoint rightCenter = viewport()->mapToGlobal( visualRect( idx ).topRight() + QPoint( 0, visualRect( idx ).height() / 2 ) );
|
||||||
askDelete.setWindowModality( Qt::WindowModal );
|
if ( playlist->hasCustomDeleter() )
|
||||||
#endif
|
{
|
||||||
|
playlist->customDelete( rightCenter );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( m_popupDialog.isNull() )
|
||||||
|
{
|
||||||
|
m_popupDialog = QWeakPointer< SourceTreePopupDialog >( new SourceTreePopupDialog() );
|
||||||
|
connect( m_popupDialog.data(), SIGNAL( result( bool ) ), this, SLOT( onDeletePlaylistResult( bool ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
int r = askDelete.exec();
|
m_popupDialog.data()->setMainText( tr( "Would you like to delete the %1 <b>\"%2\"</b>?", "e.g. Would you like to delete the playlist named Foobar?" )
|
||||||
if ( r != QMessageBox::Yes )
|
.arg( typeDesc ).arg( idx.data().toString() ) );
|
||||||
|
m_popupDialog.data()->setOkButtonText( tr( "Delete" ) );
|
||||||
|
m_popupDialog.data()->setProperty( "idx", QVariant::fromValue< QModelIndex >( idx ) );
|
||||||
|
|
||||||
|
m_popupDialog.data()->move( rightCenter.x() - m_popupDialog.data()->offset(), rightCenter.y() - m_popupDialog.data()->sizeHint().height() / 2. );
|
||||||
|
m_popupDialog.data()->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreeView::onDeletePlaylistResult( bool result )
|
||||||
|
{
|
||||||
|
Q_ASSERT( !m_popupDialog.isNull() );
|
||||||
|
|
||||||
|
const QModelIndex idx = m_popupDialog.data()->property( "idx" ).value< QModelIndex >();
|
||||||
|
Q_ASSERT( idx.isValid() );
|
||||||
|
|
||||||
|
if ( !result )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( idx, SourcesModel::SourceTreeItemTypeRole ).toInt();
|
||||||
|
|
||||||
if ( type == SourcesModel::StaticPlaylist )
|
if ( type == SourcesModel::StaticPlaylist )
|
||||||
{
|
{
|
||||||
PlaylistItem* item = itemFromIndex< PlaylistItem >( idx );
|
PlaylistItem* item = itemFromIndex< PlaylistItem >( idx );
|
||||||
playlist_ptr playlist = item->playlist();
|
playlist_ptr playlist = item->playlist();
|
||||||
|
qDebug() << "Doing delete of playlist:" << playlist->title();
|
||||||
Playlist::remove( playlist );
|
Playlist::remove( playlist );
|
||||||
}
|
}
|
||||||
else if ( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station )
|
else if ( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station )
|
||||||
{
|
{
|
||||||
DynamicPlaylistItem* item = itemFromIndex< DynamicPlaylistItem >( idx );
|
DynamicPlaylistItem* item = itemFromIndex< DynamicPlaylistItem >( idx );
|
||||||
dynplaylist_ptr playlist = item->dynPlaylist();
|
dynplaylist_ptr playlist = item->dynPlaylist();
|
||||||
|
qDebug() << "Doing delete of playlist:" << playlist->title();
|
||||||
DynamicPlaylist::remove( playlist );
|
DynamicPlaylist::remove( playlist );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#include <QtGui/QTreeView>
|
#include <QtGui/QTreeView>
|
||||||
#include <QtGui/QMenu>
|
#include <QtGui/QMenu>
|
||||||
|
|
||||||
|
class SourceTreePopupDialog;
|
||||||
class CollectionModel;
|
class CollectionModel;
|
||||||
class PlaylistModel;
|
class PlaylistModel;
|
||||||
class SourcesModel;
|
class SourcesModel;
|
||||||
@@ -84,6 +85,8 @@ private slots:
|
|||||||
void onCustomContextMenu( const QPoint& pos );
|
void onCustomContextMenu( const QPoint& pos );
|
||||||
void onSelectionChanged();
|
void onSelectionChanged();
|
||||||
|
|
||||||
|
void onDeletePlaylistResult( bool result );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void drawRow( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
void drawRow( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||||
|
|
||||||
@@ -106,6 +109,7 @@ private:
|
|||||||
QModelIndex m_contextMenuIndex;
|
QModelIndex m_contextMenuIndex;
|
||||||
SourceDelegate* m_delegate;
|
SourceDelegate* m_delegate;
|
||||||
Tomahawk::LatchManager* m_latchManager;
|
Tomahawk::LatchManager* m_latchManager;
|
||||||
|
QWeakPointer<SourceTreePopupDialog> m_popupDialog;
|
||||||
|
|
||||||
QMenu m_playlistMenu;
|
QMenu m_playlistMenu;
|
||||||
QMenu m_roPlaylistMenu;
|
QMenu m_roPlaylistMenu;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -40,6 +40,8 @@ using namespace Tomahawk;
|
|||||||
PlaylistItem::PlaylistItem( SourcesModel* mdl, SourceTreeItem* parent, const playlist_ptr& pl, int index )
|
PlaylistItem::PlaylistItem( SourcesModel* mdl, SourceTreeItem* parent, const playlist_ptr& pl, int index )
|
||||||
: SourceTreeItem( mdl, parent, SourcesModel::StaticPlaylist, index )
|
: SourceTreeItem( mdl, parent, SourcesModel::StaticPlaylist, index )
|
||||||
, m_loaded( false )
|
, m_loaded( false )
|
||||||
|
, m_canSubscribe( false )
|
||||||
|
, m_showSubscribed( false )
|
||||||
, m_playlist( pl )
|
, m_playlist( pl )
|
||||||
{
|
{
|
||||||
connect( pl.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ),
|
connect( pl.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ),
|
||||||
@@ -280,6 +282,7 @@ PlaylistItem::onUpdated()
|
|||||||
if ( !newOverlay && !m_overlaidIcon.isNull() )
|
if ( !newOverlay && !m_overlaidIcon.isNull() )
|
||||||
m_overlaidIcon = QIcon();
|
m_overlaidIcon = QIcon();
|
||||||
|
|
||||||
|
|
||||||
emit updated();
|
emit updated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,6 +295,23 @@ PlaylistItem::createOverlay()
|
|||||||
if ( m_playlist->updaters().isEmpty() )
|
if ( m_playlist->updaters().isEmpty() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
m_showSubscribed = false;
|
||||||
|
m_canSubscribe = false;
|
||||||
|
foreach ( PlaylistUpdaterInterface* updater, m_playlist->updaters() )
|
||||||
|
{
|
||||||
|
if ( updater->canSubscribe() )
|
||||||
|
{
|
||||||
|
m_canSubscribe = true;
|
||||||
|
m_showSubscribed = updater->subscribed();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_canSubscribe && m_showSubscribed && m_subscribedOnIcon.isNull() )
|
||||||
|
m_subscribedOnIcon = QPixmap( RESPATH "images/subscribe-on.png" );
|
||||||
|
else if ( m_canSubscribe && !m_showSubscribed && m_subscribedOffIcon.isNull() )
|
||||||
|
m_subscribedOffIcon = QPixmap( RESPATH "images/subscribe-off.png" );
|
||||||
|
|
||||||
QList< QPixmap > icons;
|
QList< QPixmap > icons;
|
||||||
foreach ( PlaylistUpdaterInterface* updater, m_playlist->updaters() )
|
foreach ( PlaylistUpdaterInterface* updater, m_playlist->updaters() )
|
||||||
{
|
{
|
||||||
@@ -299,6 +319,9 @@ PlaylistItem::createOverlay()
|
|||||||
icons << updater->typeIcon();
|
icons << updater->typeIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_overlaidIcon = QIcon();
|
||||||
|
m_overlaidUpdaters = m_playlist->updaters();
|
||||||
|
|
||||||
if ( icons.isEmpty() )
|
if ( icons.isEmpty() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -307,8 +330,6 @@ PlaylistItem::createOverlay()
|
|||||||
if ( icons.size() > 2 )
|
if ( icons.size() > 2 )
|
||||||
icons = icons.mid( 0, 2 );
|
icons = icons.mid( 0, 2 );
|
||||||
|
|
||||||
m_overlaidIcon = QIcon();
|
|
||||||
m_overlaidUpdaters = m_playlist->updaters();
|
|
||||||
|
|
||||||
QPixmap base = m_icon.pixmap( 48, 48 );
|
QPixmap base = m_icon.pixmap( 48, 48 );
|
||||||
QPainter p( &base );
|
QPainter p( &base );
|
||||||
@@ -370,6 +391,27 @@ PlaylistItem::activateCurrent()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PlaylistItem::setSubscribed( bool subscribed )
|
||||||
|
{
|
||||||
|
Q_ASSERT( !m_overlaidUpdaters.isEmpty() );
|
||||||
|
if ( m_overlaidUpdaters.isEmpty() )
|
||||||
|
{
|
||||||
|
qWarning() << "NO playlist updater but got a toggle subscribed action on the playlist item!?";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ( m_overlaidUpdaters.size() > 1 )
|
||||||
|
{
|
||||||
|
qWarning() << "Got TWO subscribed updaters at the same time? Toggling both... wtf";
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach( PlaylistUpdaterInterface* updater, m_overlaidUpdaters )
|
||||||
|
{
|
||||||
|
updater->setSubscribed( subscribed );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DynamicPlaylistItem::DynamicPlaylistItem( SourcesModel* mdl, SourceTreeItem* parent, const dynplaylist_ptr& pl, int index )
|
DynamicPlaylistItem::DynamicPlaylistItem( SourcesModel* mdl, SourceTreeItem* parent, const dynplaylist_ptr& pl, int index )
|
||||||
: PlaylistItem( mdl, parent, pl.staticCast< Playlist >(), index )
|
: PlaylistItem( mdl, parent, pl.staticCast< Playlist >(), index )
|
||||||
, m_dynplaylist( pl )
|
, m_dynplaylist( pl )
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -42,6 +42,12 @@ public:
|
|||||||
|
|
||||||
virtual SourceTreeItem* activateCurrent();
|
virtual SourceTreeItem* activateCurrent();
|
||||||
|
|
||||||
|
// subscription management
|
||||||
|
bool canSubscribe() const { return m_canSubscribe; }
|
||||||
|
bool subscribed() const { return m_showSubscribed; }
|
||||||
|
QPixmap subscribedIcon() const { return m_showSubscribed ? m_subscribedOnIcon : m_subscribedOffIcon; }
|
||||||
|
void setSubscribed( bool subscribed );
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void activate();
|
virtual void activate();
|
||||||
virtual void doubleClicked();
|
virtual void doubleClicked();
|
||||||
@@ -58,9 +64,10 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
bool createOverlay();
|
bool createOverlay();
|
||||||
|
|
||||||
bool m_loaded;
|
bool m_loaded, m_canSubscribe, m_showSubscribed;
|
||||||
Tomahawk::playlist_ptr m_playlist;
|
Tomahawk::playlist_ptr m_playlist;
|
||||||
QIcon m_icon, m_overlaidIcon;
|
QIcon m_icon, m_overlaidIcon;
|
||||||
|
QPixmap m_subscribedOnIcon, m_subscribedOffIcon;
|
||||||
QList<Tomahawk::PlaylistUpdaterInterface*> m_overlaidUpdaters;
|
QList<Tomahawk::PlaylistUpdaterInterface*> m_overlaidUpdaters;
|
||||||
};
|
};
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(PlaylistItem::DropTypes)
|
Q_DECLARE_OPERATORS_FOR_FLAGS(PlaylistItem::DropTypes)
|
||||||
|
Reference in New Issue
Block a user