diff --git a/include/tomahawk/playlist.h b/include/tomahawk/playlist.h index 1825b358b..88b60dab3 100644 --- a/include/tomahawk/playlist.h +++ b/include/tomahawk/playlist.h @@ -97,6 +97,7 @@ public: bool shared ); static bool remove( const playlist_ptr& playlist ); + bool rename( const QString& title ); virtual void loadRevision( const QString& rev = "" ); @@ -117,14 +118,14 @@ public: // these need to exist and be public for the json serialization stuff // you SHOULD NOT call them. They are used for an alternate CTOR method from json. // maybe friend QObjectHelper and make them private? - Playlist( const source_ptr& author ) : - m_source( author ) - , m_lastmodified( 0 ) + Playlist( const source_ptr& author ) + : m_source( author ) + , m_lastmodified( 0 ) { qDebug() << Q_FUNC_INFO << "JSON"; } void setCurrentrevision( const QString& s ) { m_currentrevision = s; } - void setTitle( const QString& s ) { m_title= s; } + void setTitle( const QString& s ) { m_title = s; } void setInfo( const QString& s ) { m_info = s; } void setCreator( const QString& s ) { m_creator = s; } void setGuid( const QString& s ) { m_guid = s; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3718af5dd..ed62920c5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -73,6 +73,7 @@ SET( tomahawkSources ${tomahawkSources} database/databasecommand_loadallplaylists.cpp database/databasecommand_createplaylist.cpp database/databasecommand_deleteplaylist.cpp + database/databasecommand_renameplaylist.cpp database/databasecommand_loadops.cpp database/databasecommand_updatesearchindex.cpp database/databasecollection.cpp @@ -113,6 +114,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} sourcetree/sourcetreeitem.cpp sourcetree/sourcetreeitemwidget.cpp sourcetree/sourcetreeview.cpp + sourcetree/sourcetreedelegate.cpp topbar/topbar.cpp topbar/clearbutton.cpp @@ -171,6 +173,7 @@ SET( tomahawkHeaders ${tomahawkHeaders} database/databasecommand_loadallplaylists.h database/databasecommand_createplaylist.h database/databasecommand_deleteplaylist.h + database/databasecommand_renameplaylist.h database/databasecommand_loadops.h database/databasecommand_updatesearchindex.h database/databasecollection.h @@ -228,6 +231,7 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui} sourcetree/sourcetreeitem.h sourcetree/sourcetreeitemwidget.h sourcetree/sourcetreeview.h + sourcetree/sourcetreedelegate.h topbar/topbar.h topbar/clearbutton.h diff --git a/src/database/databasecommand_renameplaylist.cpp b/src/database/databasecommand_renameplaylist.cpp new file mode 100644 index 000000000..4f9462943 --- /dev/null +++ b/src/database/databasecommand_renameplaylist.cpp @@ -0,0 +1,56 @@ +#include "databasecommand_renameplaylist.h" + +#include + +#include "tomahawk/tomahawkapp.h" + +using namespace Tomahawk; + + +DatabaseCommand_RenamePlaylist::DatabaseCommand_RenamePlaylist( const source_ptr& source, const QString& playlistguid, const QString& playlistTitle ) + : DatabaseCommandLoggable( source ) +{ + setPlaylistguid( playlistguid ); + setPlaylistTitle( playlistTitle ); +} + + +void +DatabaseCommand_RenamePlaylist::exec( DatabaseImpl* lib ) +{ + qDebug() << Q_FUNC_INFO; + + TomahawkSqlQuery cre = lib->newquery(); + + QString sql = QString( "UPDATE playlist SET title = :title WHERE guid = :id AND source %1" ) + .arg( source()->isLocal() ? "IS NULL" : QString( "= %1" ).arg( source()->id() ) ); + + cre.prepare( sql ); + cre.bindValue( ":id", m_playlistguid ); + cre.bindValue( ":title", m_playlistguid ); + + bool ok = cre.exec(); + if( !ok ) + { + qDebug() << cre.lastError().databaseText() + << cre.lastError().driverText() + << cre.executedQuery() + << cre.boundValues(); + Q_ASSERT( ok ); + } +} + + +void +DatabaseCommand_RenamePlaylist::postCommitHook() +{ + qDebug() << Q_FUNC_INFO << "..reporting.."; + + playlist_ptr playlist = source()->collection()->playlist( m_playlistguid ); + Q_ASSERT( !playlist.isNull() ); + + playlist->setTitle( m_playlistTitle ); + + if( source()->isLocal() ) + APP->servent().triggerDBSync(); +} diff --git a/src/database/databasecommand_renameplaylist.h b/src/database/databasecommand_renameplaylist.h new file mode 100644 index 000000000..a5e3c186e --- /dev/null +++ b/src/database/databasecommand_renameplaylist.h @@ -0,0 +1,39 @@ +#ifndef DATABASECOMMAND_RENAMEPLAYLIST_H +#define DATABASECOMMAND_RENAMEPLAYLIST_H + +#include "databaseimpl.h" +#include "databasecommandloggable.h" +#include "tomahawk/source.h" +#include "tomahawk/typedefs.h" + +class DatabaseCommand_RenamePlaylist : public DatabaseCommandLoggable +{ +Q_OBJECT +Q_PROPERTY( QString playlistguid READ playlistguid WRITE setPlaylistguid ) +Q_PROPERTY( QString playlistTitle READ playlistTitle WRITE setPlaylistTitle ) + +public: + explicit DatabaseCommand_RenamePlaylist( QObject* parent = 0 ) + : DatabaseCommandLoggable( parent ) + {} + + explicit DatabaseCommand_RenamePlaylist( const Tomahawk::source_ptr& source, const QString& playlistguid, const QString& playlistTitle ); + + QString commandname() const { return "renameplaylist"; } + + virtual void exec( DatabaseImpl* lib ); + virtual void postCommitHook(); + virtual bool doesMutates() const { return true; } + + QString playlistguid() const { return m_playlistguid; } + void setPlaylistguid( const QString& s ) { m_playlistguid = s; } + + QString playlistTitle() const { return m_playlistTitle; } + void setPlaylistTitle( const QString& s ) { m_playlistTitle = s; } + +private: + QString m_playlistguid; + QString m_playlistTitle; +}; + +#endif // DATABASECOMMAND_RENAMEPLAYLIST_H diff --git a/src/playlist.cpp b/src/playlist.cpp index 892e3191e..824e34c48 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -9,6 +9,7 @@ #include "databasecommand_setplaylistrevision.h" #include "databasecommand_createplaylist.h" #include "databasecommand_deleteplaylist.h" +#include "databasecommand_renameplaylist.h" using namespace Tomahawk; @@ -108,6 +109,16 @@ Playlist::remove( const playlist_ptr& playlist ) } +bool +Playlist::rename( const QString& title ) +{ + DatabaseCommand_RenamePlaylist* cmd = new DatabaseCommand_RenamePlaylist( author(), guid(), title ); + APP->database()->enqueue( QSharedPointer(cmd) ); + + return true; // FIXME +} + + void Playlist::reportCreated( const playlist_ptr& self ) { diff --git a/src/playlist/playlistitemdelegate.cpp b/src/playlist/playlistitemdelegate.cpp index b21629fbf..c5ca11fb4 100644 --- a/src/playlist/playlistitemdelegate.cpp +++ b/src/playlist/playlistitemdelegate.cpp @@ -34,6 +34,13 @@ PlaylistItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModel } +QWidget* +PlaylistItemDelegate::createEditor ( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + return 0; +} + + void PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { diff --git a/src/playlist/playlistitemdelegate.h b/src/playlist/playlistitemdelegate.h index 1f31ca5f4..f47826f63 100644 --- a/src/playlist/playlistitemdelegate.h +++ b/src/playlist/playlistitemdelegate.h @@ -21,6 +21,8 @@ protected: void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const; + QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const; + private: unsigned int m_removalProgress; QAbstractItemView* m_view; diff --git a/src/sourcetree/sourcesmodel.cpp b/src/sourcetree/sourcesmodel.cpp index da7a015a5..6ed71bf76 100644 --- a/src/sourcetree/sourcesmodel.cpp +++ b/src/sourcetree/sourcesmodel.cpp @@ -52,7 +52,14 @@ SourcesModel::flags( const QModelIndex& index ) const Qt::ItemFlags defaultFlags = QStandardItemModel::flags( index ); if ( index.isValid() ) + { + QModelIndex idx = index.model()->index( index.row(), 0, index.parent() ); + int type = idx.data( Qt::UserRole + 1 ).toInt(); + if ( type == 1 ) + defaultFlags |= Qt::ItemIsEditable; + return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; + } else return defaultFlags; } @@ -198,3 +205,30 @@ SourcesModel::indexToTreeItem( const QModelIndex& index ) return 0; } + + +bool +SourcesModel::setData( const QModelIndex& index, const QVariant& value, int role ) +{ + qDebug() << Q_FUNC_INFO; + + if ( !index.isValid() ) + return false; + + QModelIndex idx = index.model()->index( index.row(), 0, index.parent() ); + int type = idx.data( Qt::UserRole + 1 ).toInt(); + if ( type == 1 ) + { + qlonglong pptr = idx.data( Qt::UserRole + 3 ).toLongLong(); + playlist_ptr* playlist = reinterpret_cast(pptr); + if ( playlist ) + { + playlist->data()->rename( value.toString() ); + QStandardItemModel::setData( index, value, Qt::DisplayRole ); + } + + return true; + } + + return false; +} diff --git a/src/sourcetree/sourcesmodel.h b/src/sourcetree/sourcesmodel.h index c53f40b85..cd5e0cab7 100644 --- a/src/sourcetree/sourcesmodel.h +++ b/src/sourcetree/sourcesmodel.h @@ -29,6 +29,9 @@ public: signals: void clicked( const QModelIndex& ); +protected: + bool setData( const QModelIndex& index, const QVariant& value, int role = Qt::EditRole ); + private slots: void onSourceAdded( const Tomahawk::source_ptr& source ); void onSourceRemoved( const Tomahawk::source_ptr& source ); diff --git a/src/sourcetree/sourcetreedelegate.cpp b/src/sourcetree/sourcetreedelegate.cpp new file mode 100644 index 000000000..e6fae45c6 --- /dev/null +++ b/src/sourcetree/sourcetreedelegate.cpp @@ -0,0 +1,52 @@ +#include "sourcetreedelegate.h" + +#include +#include + + +SourceTreeDelegate::SourceTreeDelegate( QAbstractItemView* parent ) + : QStyledItemDelegate( (QObject*)parent ) + , m_view( parent ) +{ +} + + +QWidget* +SourceTreeDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + QLineEdit* editor = new QLineEdit( parent ); + editor->setFrame( false ); + editor->setObjectName( "playlistEditor" ); + + return editor; +} + + +void +SourceTreeDelegate::updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + if ( editor->objectName() != "playlistEditor" ) + return; + + QRect r = option.rect; + r.adjust( 20, -1, -8, 1 ); + + editor->setGeometry( r ); +} + + +void +SourceTreeDelegate::setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const +{ + QLineEdit* le = static_cast( editor ); + + model->setData( index, le->text(), Qt::EditRole ); +} + + +QSize +SourceTreeDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + QSize size = QStyledItemDelegate::sizeHint( option, index ); + return size; +} diff --git a/src/sourcetree/sourcetreedelegate.h b/src/sourcetree/sourcetreedelegate.h new file mode 100644 index 000000000..0166f2cb3 --- /dev/null +++ b/src/sourcetree/sourcetreedelegate.h @@ -0,0 +1,25 @@ +#ifndef SOURCETREEDELEGATE_H +#define SOURCETREEDELEGATE_H + +#include +#include + +class SourceTreeDelegate : public QStyledItemDelegate +{ +Q_OBJECT + +public: + SourceTreeDelegate( QAbstractItemView* parent = 0 ); + +protected: + QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const; + + QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const; + void updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const; + void setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const; + +private: + QAbstractItemView* m_view; +}; + +#endif // SOURCETREEDELEGATE_H diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp index 8d331f418..16af2a4da 100644 --- a/src/sourcetree/sourcetreeview.cpp +++ b/src/sourcetree/sourcetreeview.cpp @@ -6,6 +6,7 @@ #include "playlistmanager.h" #include "sourcetreeitem.h" #include "sourcesmodel.h" +#include "sourcetreedelegate.h" #include #include @@ -29,11 +30,15 @@ SourceTreeView::SourceTreeView( QWidget* parent ) setDragDropMode( QAbstractItemView::DropOnly ); setAcceptDrops( true ); setDropIndicatorShown( false ); - setAllColumnsShowFocus( false ); + setAllColumnsShowFocus( true ); + setUniformRowHeights( false ); setContextMenuPolicy( Qt::CustomContextMenu ); connect( this, SIGNAL( customContextMenuRequested( const QPoint& ) ), SLOT( onCustomContextMenu( const QPoint& ) ) ); + m_delegate = new SourceTreeDelegate( this ); + setItemDelegate( m_delegate ); + m_model = new SourcesModel( this ); setModel( m_model ); diff --git a/src/sourcetree/sourcetreeview.h b/src/sourcetree/sourcetreeview.h index f4bfd0a45..adc81663a 100644 --- a/src/sourcetree/sourcetreeview.h +++ b/src/sourcetree/sourcetreeview.h @@ -9,6 +9,7 @@ class CollectionModel; class PlaylistModel; class SourcesModel; +class SourceTreeDelegate; class SourceTreeView : public QTreeView { @@ -47,6 +48,7 @@ private: CollectionModel* m_collectionModel; SourcesModel* m_model; + SourceTreeDelegate* m_delegate; QModelIndex m_contextMenuIndex; QMenu m_playlistMenu; diff --git a/src/topbar/topbar.cpp b/src/topbar/topbar.cpp index e21514b63..cf06c18c7 100644 --- a/src/topbar/topbar.cpp +++ b/src/topbar/topbar.cpp @@ -157,7 +157,7 @@ TopBar::setNumSources( unsigned int i ) { fadeOutDude( k ); m_sources--; - } while( k-- > i ); + } while( (unsigned int)k-- > i ); m_sources = i; }