mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-01 03:40:16 +02:00
initial work on a menu for drag and drop
This commit is contained in:
@@ -57,6 +57,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
|
|||||||
sourcetree/sourcesmodel.cpp
|
sourcetree/sourcesmodel.cpp
|
||||||
sourcetree/sourcesproxymodel.cpp
|
sourcetree/sourcesproxymodel.cpp
|
||||||
sourcetree/sourcetreeview.cpp
|
sourcetree/sourcetreeview.cpp
|
||||||
|
sourcetree/sourcedelegate.cpp
|
||||||
sourcetree/items/sourcetreeitem.cpp
|
sourcetree/items/sourcetreeitem.cpp
|
||||||
sourcetree/items/collectionitem.cpp
|
sourcetree/items/collectionitem.cpp
|
||||||
sourcetree/items/playlistitems.cpp
|
sourcetree/items/playlistitems.cpp
|
||||||
|
@@ -138,6 +138,12 @@ PlaylistItem::willAcceptDrag( const QMimeData* data ) const
|
|||||||
return !m_playlist.isNull() && m_playlist->author()->isLocal();
|
return !m_playlist.isNull() && m_playlist->author()->isLocal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlaylistItem::DropTypes
|
||||||
|
PlaylistItem::supportedDropTypes() const
|
||||||
|
{
|
||||||
|
return DropTypeAllItems | DropTypeLocalItems | DropTypeTop10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PlaylistItem::dropMimeData( const QMimeData* data, Qt::DropAction action )
|
PlaylistItem::dropMimeData( const QMimeData* data, Qt::DropAction action )
|
||||||
|
@@ -34,6 +34,7 @@ public:
|
|||||||
virtual Qt::ItemFlags flags() const;
|
virtual Qt::ItemFlags flags() const;
|
||||||
virtual void activate();
|
virtual void activate();
|
||||||
virtual bool willAcceptDrag( const QMimeData* data ) const;
|
virtual bool willAcceptDrag( const QMimeData* data ) const;
|
||||||
|
virtual DropTypes supportedDropTypes() const;
|
||||||
virtual bool dropMimeData( const QMimeData* data, Qt::DropAction action );
|
virtual bool dropMimeData( const QMimeData* data, Qt::DropAction action );
|
||||||
virtual QIcon icon() const;
|
virtual QIcon icon() const;
|
||||||
virtual bool setData(const QVariant& v, bool role);
|
virtual bool setData(const QVariant& v, bool role);
|
||||||
@@ -54,6 +55,7 @@ private:
|
|||||||
bool m_loaded;
|
bool m_loaded;
|
||||||
Tomahawk::playlist_ptr m_playlist;
|
Tomahawk::playlist_ptr m_playlist;
|
||||||
};
|
};
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(PlaylistItem::DropTypes)
|
||||||
|
|
||||||
// can be a station or an auto playlist
|
// can be a station or an auto playlist
|
||||||
class DynamicPlaylistItem : public PlaylistItem
|
class DynamicPlaylistItem : public PlaylistItem
|
||||||
|
@@ -28,6 +28,7 @@ SourceTreeItem::SourceTreeItem( SourcesModel* model, SourceTreeItem* parent, Sou
|
|||||||
, m_type( thisType )
|
, m_type( thisType )
|
||||||
, m_parent( parent )
|
, m_parent( parent )
|
||||||
, m_model( model )
|
, m_model( model )
|
||||||
|
//, m_dropHovering( false )
|
||||||
{
|
{
|
||||||
connect( this, SIGNAL( beginChildRowsAdded( int,int ) ), m_model, SLOT( onItemRowsAddedBegin( int,int ) ) );
|
connect( this, SIGNAL( beginChildRowsAdded( int,int ) ), m_model, SLOT( onItemRowsAddedBegin( int,int ) ) );
|
||||||
connect( this, SIGNAL( beginChildRowsRemoved( int,int ) ), m_model, SLOT( onItemRowsRemovedBegin( int,int ) ) );
|
connect( this, SIGNAL( beginChildRowsRemoved( int,int ) ), m_model, SLOT( onItemRowsRemovedBegin( int,int ) ) );
|
||||||
|
@@ -32,6 +32,16 @@ class SourceTreeItem : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
enum DropType
|
||||||
|
{
|
||||||
|
DropTypesNone = 0x00,
|
||||||
|
DropTypeAllItems = 0x01,
|
||||||
|
DropTypeLocalItems = 0x02,
|
||||||
|
DropTypeTop10 = 0x04,
|
||||||
|
DropTypesAllTypes = 0xff
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS( DropTypes, DropType )
|
||||||
|
|
||||||
SourceTreeItem() : m_type( SourcesModel::Invalid ), m_parent( 0 ), m_model( 0 ) {}
|
SourceTreeItem() : m_type( SourcesModel::Invalid ), m_parent( 0 ), m_model( 0 ) {}
|
||||||
SourceTreeItem( SourcesModel* model, SourceTreeItem* parent, SourcesModel::RowType thisType, int index = -1 ); // if index is -1, append at end of parent's child list
|
SourceTreeItem( SourcesModel* model, SourceTreeItem* parent, SourcesModel::RowType thisType, int index = -1 ); // if index is -1, append at end of parent's child list
|
||||||
virtual ~SourceTreeItem();
|
virtual ~SourceTreeItem();
|
||||||
@@ -56,6 +66,10 @@ public:
|
|||||||
virtual bool setData( const QVariant&, bool ) { return false; }
|
virtual bool setData( const QVariant&, bool ) { return false; }
|
||||||
virtual int peerSortValue() const { return 0; } // How to sort relative to peers in the tree.
|
virtual int peerSortValue() const { return 0; } // How to sort relative to peers in the tree.
|
||||||
virtual int IDValue() const { return 0; }
|
virtual int IDValue() const { return 0; }
|
||||||
|
// virtual bool dropHovering() const { return m_dropHovering; }
|
||||||
|
// virtual void setDropHovering( bool dropHovering ) { m_dropHovering = dropHovering; emit updated(); }
|
||||||
|
virtual DropTypes supportedDropTypes() const { return DropTypesNone; }
|
||||||
|
virtual void setDropType( DropType type ) { m_dropType = type; }
|
||||||
|
|
||||||
/// don't call me unless you are a sourcetreeitem. i prefer this to making everyone a friend
|
/// don't call me unless you are a sourcetreeitem. i prefer this to making everyone a friend
|
||||||
void beginRowsAdded( int from, int to ) { emit beginChildRowsAdded( from, to ); }
|
void beginRowsAdded( int from, int to ) { emit beginChildRowsAdded( from, to ); }
|
||||||
@@ -83,6 +97,8 @@ private:
|
|||||||
SourceTreeItem* m_parent;
|
SourceTreeItem* m_parent;
|
||||||
QList< SourceTreeItem* > m_children;
|
QList< SourceTreeItem* > m_children;
|
||||||
SourcesModel* m_model;
|
SourcesModel* m_model;
|
||||||
|
|
||||||
|
DropType m_dropType;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE( SourceTreeItem* );
|
Q_DECLARE_METATYPE( SourceTreeItem* );
|
||||||
|
314
src/sourcetree/sourcedelegate.cpp
Normal file
314
src/sourcetree/sourcedelegate.cpp
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
#include "sourcedelegate.h"
|
||||||
|
|
||||||
|
#include "items/sourcetreeitem.h"
|
||||||
|
#include "items/collectionitem.h"
|
||||||
|
#include "items/playlistitems.h"
|
||||||
|
|
||||||
|
#include "utils/tomahawkutils.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
#define TREEVIEW_INDENT_ADD -7
|
||||||
|
|
||||||
|
QSize
|
||||||
|
SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||||
|
{
|
||||||
|
SourceTreeItem *item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
|
||||||
|
|
||||||
|
if ( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() == SourcesModel::Collection )
|
||||||
|
return QSize( option.rect.width(), 44 );
|
||||||
|
else if ( index == m_dropHoverIndex )
|
||||||
|
{
|
||||||
|
QSize originalSize = QStyledItemDelegate::sizeHint( option, index );
|
||||||
|
return originalSize + QSize( 0, originalSize.height() * dropTypeCount( item ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return QStyledItemDelegate::sizeHint( option, index );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||||
|
{
|
||||||
|
QStyleOptionViewItem o = option;
|
||||||
|
|
||||||
|
#ifdef Q_WS_MAC
|
||||||
|
QFont savedFont = painter->font();
|
||||||
|
QFont smaller = savedFont;
|
||||||
|
smaller.setPointSize( smaller.pointSize() - 2 );
|
||||||
|
painter->setFont( smaller );
|
||||||
|
o.font = smaller;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( ( option.state & QStyle::State_Enabled ) == QStyle::State_Enabled )
|
||||||
|
{
|
||||||
|
o.state = QStyle::State_Enabled;
|
||||||
|
|
||||||
|
if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
|
||||||
|
{
|
||||||
|
o.palette.setColor( QPalette::Text, o.palette.color( QPalette::HighlightedText ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
|
||||||
|
SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
|
||||||
|
Q_ASSERT( item );
|
||||||
|
|
||||||
|
QStyleOptionViewItemV4 o3 = option;
|
||||||
|
if ( type != SourcesModel::Collection && type != SourcesModel::Category )
|
||||||
|
o3.rect.setX( 0 );
|
||||||
|
|
||||||
|
QApplication::style()->drawControl( QStyle::CE_ItemViewItem, &o3, painter );
|
||||||
|
|
||||||
|
if ( type == SourcesModel::Collection )
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
QFont normal = painter->font();
|
||||||
|
QFont bold = painter->font();
|
||||||
|
bold.setBold( true );
|
||||||
|
|
||||||
|
CollectionItem* colItem = qobject_cast< CollectionItem* >( item );
|
||||||
|
Q_ASSERT( colItem );
|
||||||
|
bool status = !( !colItem || colItem->source().isNull() || !colItem->source()->isOnline() );
|
||||||
|
|
||||||
|
QString tracks;
|
||||||
|
QString name = index.data().toString();
|
||||||
|
int figWidth = 0;
|
||||||
|
|
||||||
|
if ( status && colItem && !colItem->source().isNull() )
|
||||||
|
{
|
||||||
|
tracks = QString::number( colItem->source()->trackCount() );
|
||||||
|
figWidth = painter->fontMetrics().width( tracks );
|
||||||
|
name = colItem->source()->friendlyName();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect iconRect = option.rect.adjusted( 4, 6, -option.rect.width() + option.rect.height() - 12 + 4, -6 );
|
||||||
|
|
||||||
|
QPixmap avatar = colItem->icon().pixmap( iconRect.size() );
|
||||||
|
painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) );
|
||||||
|
|
||||||
|
if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
|
||||||
|
{
|
||||||
|
painter->setPen( o.palette.color( QPalette::HighlightedText ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect textRect = option.rect.adjusted( iconRect.width() + 8, 6, -figWidth - 24, 0 );
|
||||||
|
if ( status || colItem->source().isNull() )
|
||||||
|
painter->setFont( bold );
|
||||||
|
QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() );
|
||||||
|
painter->drawText( textRect, text );
|
||||||
|
|
||||||
|
QString desc = status ? colItem->source()->textStatus() : tr( "Offline" );
|
||||||
|
if ( colItem->source().isNull() )
|
||||||
|
desc = tr( "All available tracks" );
|
||||||
|
if ( status && desc.isEmpty() && !colItem->source()->currentTrack().isNull() )
|
||||||
|
desc = colItem->source()->currentTrack()->artist() + " - " + colItem->source()->currentTrack()->track();
|
||||||
|
if ( desc.isEmpty() )
|
||||||
|
desc = tr( "Online" );
|
||||||
|
|
||||||
|
textRect = option.rect.adjusted( iconRect.width() + 8, painter->fontMetrics().height() + 6, -figWidth - 24, -4 );
|
||||||
|
painter->setFont( normal );
|
||||||
|
text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() );
|
||||||
|
QTextOption to( Qt::AlignBottom );
|
||||||
|
painter->drawText( textRect, text, to );
|
||||||
|
|
||||||
|
if ( status )
|
||||||
|
{
|
||||||
|
painter->setRenderHint( QPainter::Antialiasing );
|
||||||
|
|
||||||
|
QRect figRect = o.rect.adjusted( o.rect.width() - figWidth - 8, 0, -13, -o.rect.height() + 16 );
|
||||||
|
int hd = ( option.rect.height() - figRect.height() ) / 2;
|
||||||
|
figRect.adjust( 0, hd, 0, hd );
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
figRect.adjust( -3, 0, 3, 0 );
|
||||||
|
#endif
|
||||||
|
painter->setFont( bold );
|
||||||
|
|
||||||
|
QColor figColor( 167, 183, 211 );
|
||||||
|
painter->setPen( figColor );
|
||||||
|
painter->setBrush( figColor );
|
||||||
|
|
||||||
|
TomahawkUtils::drawBackgroundAndNumbers( painter, tracks, figRect );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
else if ( type == SourcesModel::StaticPlaylist )
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
QFont normal = painter->font();
|
||||||
|
QFont bold = painter->font();
|
||||||
|
bold.setBold( true );
|
||||||
|
|
||||||
|
PlaylistItem* plItem = qobject_cast< PlaylistItem* >( item );
|
||||||
|
Q_ASSERT( plItem );
|
||||||
|
|
||||||
|
// QString tracks;
|
||||||
|
QString name = index.data().toString();
|
||||||
|
// int figWidth = 0;
|
||||||
|
|
||||||
|
if ( plItem && !plItem->playlist().isNull() )
|
||||||
|
{
|
||||||
|
// tracks = QString::number( plItem->source()->trackCount() );
|
||||||
|
// figWidth = painter->fontMetrics().width( tracks );
|
||||||
|
name = plItem->playlist()->title();
|
||||||
|
}
|
||||||
|
|
||||||
|
int height = option.rect.height();
|
||||||
|
if ( index == m_dropHoverIndex )
|
||||||
|
height /= ( dropTypeCount( item ) + 1 );
|
||||||
|
|
||||||
|
QRect iconRect = option.rect.adjusted( 4, 1, -option.rect.width() + height - 2 + 4, -option.rect.height() + height -1 );
|
||||||
|
|
||||||
|
QPixmap avatar = index.data( Qt::DecorationRole ).value< QIcon >().pixmap( iconRect.width(), iconRect.height() );
|
||||||
|
painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) );
|
||||||
|
|
||||||
|
if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
|
||||||
|
{
|
||||||
|
painter->setPen( o.palette.color( QPalette::HighlightedText ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect textRect = option.rect.adjusted( iconRect.width() + 8, 2, /*-figWidth - 24*/ 0, 0 );
|
||||||
|
QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() );
|
||||||
|
painter->drawText( textRect, text );
|
||||||
|
|
||||||
|
if ( index == m_dropHoverIndex )
|
||||||
|
{
|
||||||
|
QPoint cursorPos = m_parent->mapFromGlobal( QCursor::pos() );
|
||||||
|
qDebug() << "cursorpos is" << cursorPos;
|
||||||
|
|
||||||
|
int hoveredDropTypeIndex = ( cursorPos.y() - o.rect.y() ) / height;
|
||||||
|
int verticalOffset = height * hoveredDropTypeIndex;
|
||||||
|
QRect selectionRect = o.rect.adjusted( 0, verticalOffset, 0, -o.rect.height() + height + verticalOffset );
|
||||||
|
painter->drawRoundedRect( selectionRect, 5, 5 );
|
||||||
|
|
||||||
|
int count = 1;
|
||||||
|
if ( item->supportedDropTypes().testFlag( SourceTreeItem::DropTypeAllItems ) )
|
||||||
|
{
|
||||||
|
text = "All items";
|
||||||
|
textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 );
|
||||||
|
painter->drawText( textRect, text );
|
||||||
|
if ( count == hoveredDropTypeIndex )
|
||||||
|
m_hoveredDropType = SourceTreeItem::DropTypeAllItems;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if ( item->supportedDropTypes().testFlag( SourceTreeItem::DropTypeLocalItems ) )
|
||||||
|
{
|
||||||
|
text = "Local items";
|
||||||
|
textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 );
|
||||||
|
painter->drawText( textRect, text );
|
||||||
|
if ( count == hoveredDropTypeIndex )
|
||||||
|
m_hoveredDropType = SourceTreeItem::DropTypeLocalItems;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if ( item->supportedDropTypes().testFlag( SourceTreeItem::DropTypeTop10 ) )
|
||||||
|
{
|
||||||
|
text = "Top 10";
|
||||||
|
textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 );
|
||||||
|
painter->drawText( textRect, text );
|
||||||
|
if ( count == hoveredDropTypeIndex )
|
||||||
|
m_hoveredDropType = SourceTreeItem::DropTypeTop10;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "***************+ verticaloffset:" << hoveredDropTypeIndex << count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// QString desc = status ? colItem->source()->textStatus() : tr( "Offline" );
|
||||||
|
// if ( colItem->source().isNull() )
|
||||||
|
// desc = tr( "All available tracks" );
|
||||||
|
// if ( status && desc.isEmpty() && !colItem->source()->currentTrack().isNull() )
|
||||||
|
// desc = colItem->source()->currentTrack()->artist() + " - " + colItem->source()->currentTrack()->track();
|
||||||
|
// if ( desc.isEmpty() )
|
||||||
|
// desc = tr( "Online" );
|
||||||
|
|
||||||
|
// textRect = option.rect.adjusted( iconRect.width() + 8, painter->fontMetrics().height() + 6, -figWidth - 24, -4 );
|
||||||
|
// painter->setFont( normal );
|
||||||
|
// text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() );
|
||||||
|
// QTextOption to( Qt::AlignBottom );
|
||||||
|
// painter->drawText( textRect, text, to );
|
||||||
|
|
||||||
|
// if ( status )
|
||||||
|
// {
|
||||||
|
// painter->setRenderHint( QPainter::Antialiasing );
|
||||||
|
|
||||||
|
// QRect figRect = o.rect.adjusted( o.rect.width() - figWidth - 8, 0, -13, -o.rect.height() + 16 );
|
||||||
|
// int hd = ( option.rect.height() - figRect.height() ) / 2;
|
||||||
|
// figRect.adjust( 0, hd, 0, hd );
|
||||||
|
//#ifdef Q_OS_WIN
|
||||||
|
// figRect.adjust( -3, 0, 3, 0 );
|
||||||
|
//#endif
|
||||||
|
// painter->setFont( bold );
|
||||||
|
|
||||||
|
// QColor figColor( 167, 183, 211 );
|
||||||
|
// painter->setPen( figColor );
|
||||||
|
// painter->setBrush( figColor );
|
||||||
|
|
||||||
|
// TomahawkUtils::drawBackgroundAndNumbers( painter, tracks, figRect );
|
||||||
|
// }
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QStyledItemDelegate::paint( painter, o, index );
|
||||||
|
/*QStyleOptionViewItemV4 opt = o;
|
||||||
|
initStyleOption( &opt, index );
|
||||||
|
|
||||||
|
// shrink the indentations. count how indented this item is and remove it
|
||||||
|
int indentMult = 0;
|
||||||
|
QModelIndex counter = index;
|
||||||
|
while ( counter.parent().isValid() )
|
||||||
|
{
|
||||||
|
indentMult++;
|
||||||
|
counter = counter.parent();
|
||||||
|
}
|
||||||
|
int realX = opt.rect.x() + indentMult * TREEVIEW_INDENT_ADD;
|
||||||
|
|
||||||
|
opt.rect.setX( realX );
|
||||||
|
const QWidget *widget = opt.widget;
|
||||||
|
QStyle *style = widget ? widget->style() : QApplication::style();
|
||||||
|
style->drawControl( QStyle::CE_ItemViewItem, &opt, painter, widget ); */
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef Q_WS_MAC
|
||||||
|
painter->setFont( savedFont );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceDelegate::updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||||
|
{
|
||||||
|
if ( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() == SourcesModel::StaticPlaylist )
|
||||||
|
editor->setGeometry( option.rect.adjusted( 20, 0, 0, 0 ) );
|
||||||
|
else
|
||||||
|
QStyledItemDelegate::updateEditorGeometry( editor, option, index );
|
||||||
|
|
||||||
|
editor->setGeometry( editor->geometry().adjusted( 2*TREEVIEW_INDENT_ADD, 0, 0, 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SourceDelegate::dropTypeCount( SourceTreeItem* item ) const
|
||||||
|
{
|
||||||
|
int menuCount = 0;
|
||||||
|
if ( item->supportedDropTypes().testFlag( SourceTreeItem::DropTypeAllItems ) )
|
||||||
|
menuCount++;
|
||||||
|
|
||||||
|
if ( item->supportedDropTypes().testFlag( SourceTreeItem::DropTypeLocalItems ) )
|
||||||
|
menuCount++;
|
||||||
|
|
||||||
|
if ( item->supportedDropTypes().testFlag( SourceTreeItem::DropTypeTop10 ) )
|
||||||
|
menuCount++;
|
||||||
|
|
||||||
|
return menuCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceTreeItem::DropType
|
||||||
|
SourceDelegate::hoveredDropType() const
|
||||||
|
{
|
||||||
|
return m_hoveredDropType;
|
||||||
|
}
|
30
src/sourcetree/sourcedelegate.h
Normal file
30
src/sourcetree/sourcedelegate.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef SOURCEDELEGATE_H
|
||||||
|
#define SOURCEDELEGATE_H
|
||||||
|
|
||||||
|
#include "sourcetreeview.h"
|
||||||
|
#include "items/sourcetreeitem.h"
|
||||||
|
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
|
||||||
|
class SourceDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SourceDelegate( QAbstractItemView* parent = 0 ) : QStyledItemDelegate( parent ), m_parent( parent ) {}
|
||||||
|
|
||||||
|
void setDropHoverIndex( const QModelIndex &index ) { m_dropHoverIndex = index; }
|
||||||
|
|
||||||
|
SourceTreeItem::DropType hoveredDropType() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||||
|
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||||
|
virtual void updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||||
|
virtual int dropTypeCount( SourceTreeItem* item ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QAbstractItemView* m_parent;
|
||||||
|
QModelIndex m_dropHoverIndex;
|
||||||
|
mutable SourceTreeItem::DropType m_hoveredDropType; // Hack to keep easily track of the current highlighted DropType in paint()
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SOURCEDELEGATE_H
|
@@ -32,6 +32,7 @@
|
|||||||
#include "viewmanager.h"
|
#include "viewmanager.h"
|
||||||
#include "sourcesproxymodel.h"
|
#include "sourcesproxymodel.h"
|
||||||
#include "sourcelist.h"
|
#include "sourcelist.h"
|
||||||
|
#include "sourcedelegate.h"
|
||||||
#include "sourcetree/items/playlistitems.h"
|
#include "sourcetree/items/playlistitems.h"
|
||||||
#include "sourcetree/items/collectionitem.h"
|
#include "sourcetree/items/collectionitem.h"
|
||||||
#include "audio/audioengine.h"
|
#include "audio/audioengine.h"
|
||||||
@@ -46,33 +47,6 @@
|
|||||||
|
|
||||||
using namespace Tomahawk;
|
using namespace Tomahawk;
|
||||||
|
|
||||||
#define TREEVIEW_INDENT_ADD -7
|
|
||||||
|
|
||||||
|
|
||||||
class SourceDelegate : public QStyledItemDelegate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SourceDelegate( QAbstractItemView* parent = 0 ) : QStyledItemDelegate( parent ), m_parent( parent ) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
|
||||||
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
|
||||||
virtual void updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
|
||||||
{
|
|
||||||
if ( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() == SourcesModel::StaticPlaylist )
|
|
||||||
editor->setGeometry( option.rect.adjusted( 20, 0, 0, 0 ) );
|
|
||||||
else
|
|
||||||
QStyledItemDelegate::updateEditorGeometry( editor, option, index );
|
|
||||||
|
|
||||||
editor->setGeometry( editor->geometry().adjusted( 2*TREEVIEW_INDENT_ADD, 0, 0, 0 ) );
|
|
||||||
}
|
|
||||||
virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
|
|
||||||
|
|
||||||
private:
|
|
||||||
QAbstractItemView* m_parent;
|
|
||||||
mutable int m_iconHeight;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
SourceTreeView::SourceTreeView( QWidget* parent )
|
SourceTreeView::SourceTreeView( QWidget* parent )
|
||||||
: QTreeView( parent )
|
: QTreeView( parent )
|
||||||
@@ -105,7 +79,8 @@ SourceTreeView::SourceTreeView( QWidget* parent )
|
|||||||
// so investigate
|
// so investigate
|
||||||
// setAnimated( true );
|
// setAnimated( true );
|
||||||
|
|
||||||
setItemDelegate( new SourceDelegate( this ) );
|
m_delegate = new SourceDelegate( this );
|
||||||
|
setItemDelegate( m_delegate );
|
||||||
|
|
||||||
setContextMenuPolicy( Qt::CustomContextMenu );
|
setContextMenuPolicy( Qt::CustomContextMenu );
|
||||||
connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) );
|
connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) );
|
||||||
@@ -464,6 +439,13 @@ SourceTreeView::dragLeaveEvent( QDragLeaveEvent* event )
|
|||||||
m_dragging = false;
|
m_dragging = false;
|
||||||
setDirtyRegion( m_dropRect );
|
setDirtyRegion( m_dropRect );
|
||||||
|
|
||||||
|
// SourceTreeItem* oldItem = m_dropIndex.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
|
||||||
|
// if ( oldItem )
|
||||||
|
// {
|
||||||
|
// oldItem->setDropHovering( false );
|
||||||
|
// }
|
||||||
|
m_delegate->setDropHoverIndex( QModelIndex() );
|
||||||
|
dataChanged(m_dropIndex, m_dropIndex);
|
||||||
m_dropIndex = QPersistentModelIndex();
|
m_dropIndex = QPersistentModelIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,6 +461,13 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event )
|
|||||||
setDirtyRegion( m_dropRect );
|
setDirtyRegion( m_dropRect );
|
||||||
const QPoint pos = event->pos();
|
const QPoint pos = event->pos();
|
||||||
const QModelIndex index = indexAt( pos );
|
const QModelIndex index = indexAt( pos );
|
||||||
|
// SourceTreeItem* oldItem = m_dropIndex.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
|
||||||
|
// if ( oldItem )
|
||||||
|
// {
|
||||||
|
// oldItem->setDropHovering( false );
|
||||||
|
// }
|
||||||
|
m_delegate->setDropHoverIndex( QModelIndex() );
|
||||||
|
dataChanged(m_dropIndex, m_dropIndex);
|
||||||
m_dropIndex = QPersistentModelIndex( index );
|
m_dropIndex = QPersistentModelIndex( index );
|
||||||
|
|
||||||
if ( index.isValid() )
|
if ( index.isValid() )
|
||||||
@@ -486,9 +475,14 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event )
|
|||||||
const QRect rect = visualRect( index );
|
const QRect rect = visualRect( index );
|
||||||
m_dropRect = rect;
|
m_dropRect = rect;
|
||||||
|
|
||||||
const SourceTreeItem* item = itemFromIndex< SourceTreeItem >( index );
|
SourceTreeItem* item = itemFromIndex< SourceTreeItem >( index );
|
||||||
if( item->willAcceptDrag( event->mimeData() ) )
|
if( item->willAcceptDrag( event->mimeData() ) )
|
||||||
|
{
|
||||||
accept = true;
|
accept = true;
|
||||||
|
// item->setDropHovering( true );
|
||||||
|
m_delegate->setDropHoverIndex( index );
|
||||||
|
dataChanged(index, index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -511,6 +505,15 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event )
|
|||||||
void
|
void
|
||||||
SourceTreeView::dropEvent( QDropEvent* event )
|
SourceTreeView::dropEvent( QDropEvent* event )
|
||||||
{
|
{
|
||||||
|
const QPoint pos = event->pos();
|
||||||
|
const QModelIndex index = indexAt( pos );
|
||||||
|
PlaylistItem* item = itemFromIndex< PlaylistItem >( index );
|
||||||
|
Q_ASSERT( item );
|
||||||
|
|
||||||
|
item->setDropType( m_delegate->hoveredDropType() );
|
||||||
|
qDebug() << "dropType is " << m_delegate->hoveredDropType();
|
||||||
|
m_delegate->setDropHoverIndex( QModelIndex() );
|
||||||
|
dataChanged( index, index );
|
||||||
QTreeView::dropEvent( event );
|
QTreeView::dropEvent( event );
|
||||||
m_dragging = false;
|
m_dragging = false;
|
||||||
m_dropIndex = QPersistentModelIndex();
|
m_dropIndex = QPersistentModelIndex();
|
||||||
@@ -576,190 +579,3 @@ SourceTreeView::itemFromIndex( const QModelIndex& index ) const
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QSize
|
|
||||||
SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
|
||||||
{
|
|
||||||
if ( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() == SourcesModel::Collection )
|
|
||||||
return QSize( option.rect.width(), 44 );
|
|
||||||
else
|
|
||||||
return QStyledItemDelegate::sizeHint( option, index );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
|
||||||
{
|
|
||||||
QStyleOptionViewItem o = option;
|
|
||||||
|
|
||||||
#ifdef Q_WS_MAC
|
|
||||||
QFont savedFont = painter->font();
|
|
||||||
QFont smaller = savedFont;
|
|
||||||
smaller.setPointSize( smaller.pointSize() - 2 );
|
|
||||||
painter->setFont( smaller );
|
|
||||||
o.font = smaller;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ( ( option.state & QStyle::State_Enabled ) == QStyle::State_Enabled )
|
|
||||||
{
|
|
||||||
o.state = QStyle::State_Enabled;
|
|
||||||
|
|
||||||
if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
|
|
||||||
{
|
|
||||||
o.palette.setColor( QPalette::Text, o.palette.color( QPalette::HighlightedText ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
|
|
||||||
SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
|
|
||||||
Q_ASSERT( item );
|
|
||||||
|
|
||||||
QStyleOptionViewItemV4 o3 = option;
|
|
||||||
if ( type != SourcesModel::Collection && type != SourcesModel::Category )
|
|
||||||
o3.rect.setX( 0 );
|
|
||||||
|
|
||||||
QApplication::style()->drawControl( QStyle::CE_ItemViewItem, &o3, painter );
|
|
||||||
|
|
||||||
if ( type == SourcesModel::Collection )
|
|
||||||
{
|
|
||||||
painter->save();
|
|
||||||
|
|
||||||
QFont normal = painter->font();
|
|
||||||
QFont bold = painter->font();
|
|
||||||
bold.setBold( true );
|
|
||||||
|
|
||||||
CollectionItem* colItem = qobject_cast< CollectionItem* >( item );
|
|
||||||
Q_ASSERT( colItem );
|
|
||||||
bool status = !( !colItem || colItem->source().isNull() || !colItem->source()->isOnline() );
|
|
||||||
|
|
||||||
QString tracks;
|
|
||||||
QString name = index.data().toString();
|
|
||||||
int figWidth = 0;
|
|
||||||
|
|
||||||
if ( status && colItem && !colItem->source().isNull() )
|
|
||||||
{
|
|
||||||
tracks = QString::number( colItem->source()->trackCount() );
|
|
||||||
figWidth = painter->fontMetrics().width( tracks );
|
|
||||||
name = colItem->source()->friendlyName();
|
|
||||||
}
|
|
||||||
|
|
||||||
QRect iconRect = option.rect.adjusted( 4, 6, -option.rect.width() + option.rect.height() - 12 + 4, -6 );
|
|
||||||
|
|
||||||
QPixmap avatar = colItem->icon().pixmap( iconRect.size() );
|
|
||||||
painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) );
|
|
||||||
|
|
||||||
if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
|
|
||||||
{
|
|
||||||
painter->setPen( o.palette.color( QPalette::HighlightedText ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
QRect textRect = option.rect.adjusted( iconRect.width() + 8, 6, -figWidth - 24, 0 );
|
|
||||||
if ( status || colItem->source().isNull() )
|
|
||||||
painter->setFont( bold );
|
|
||||||
QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() );
|
|
||||||
painter->drawText( textRect, text );
|
|
||||||
|
|
||||||
QString desc = status ? colItem->source()->textStatus() : tr( "Offline" );
|
|
||||||
if ( colItem->source().isNull() )
|
|
||||||
desc = tr( "All available tracks" );
|
|
||||||
if ( status && desc.isEmpty() && !colItem->source()->currentTrack().isNull() )
|
|
||||||
desc = colItem->source()->currentTrack()->artist() + " - " + colItem->source()->currentTrack()->track();
|
|
||||||
if ( desc.isEmpty() )
|
|
||||||
desc = tr( "Online" );
|
|
||||||
|
|
||||||
textRect = option.rect.adjusted( iconRect.width() + 8, painter->fontMetrics().height() + 6, -figWidth - 24, -4 );
|
|
||||||
painter->setFont( normal );
|
|
||||||
text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() );
|
|
||||||
QTextOption to( Qt::AlignBottom );
|
|
||||||
painter->drawText( textRect, text, to );
|
|
||||||
|
|
||||||
if ( status )
|
|
||||||
{
|
|
||||||
painter->setRenderHint( QPainter::Antialiasing );
|
|
||||||
|
|
||||||
QRect figRect = o.rect.adjusted( o.rect.width() - figWidth - 8, 0, -13, -o.rect.height() + 16 );
|
|
||||||
int hd = ( option.rect.height() - figRect.height() ) / 2;
|
|
||||||
figRect.adjust( 0, hd, 0, hd );
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
figRect.adjust( -3, 0, 3, 0 );
|
|
||||||
#endif
|
|
||||||
painter->setFont( bold );
|
|
||||||
|
|
||||||
QColor figColor( 167, 183, 211 );
|
|
||||||
painter->setPen( figColor );
|
|
||||||
painter->setBrush( figColor );
|
|
||||||
|
|
||||||
TomahawkUtils::drawBackgroundAndNumbers( painter, tracks, figRect );
|
|
||||||
}
|
|
||||||
|
|
||||||
painter->restore();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QStyledItemDelegate::paint( painter, o, index );
|
|
||||||
|
|
||||||
if ( type == SourcesModel::TemporaryPage )
|
|
||||||
{
|
|
||||||
TemporaryPageItem* gpi = qobject_cast< TemporaryPageItem* >( item );
|
|
||||||
Q_ASSERT( gpi );
|
|
||||||
|
|
||||||
if ( gpi && o3.state & QStyle::State_MouseOver )
|
|
||||||
{
|
|
||||||
// draw close icon
|
|
||||||
int padding = 3;
|
|
||||||
m_iconHeight = ( o3.rect.height() - 2*padding );
|
|
||||||
QPixmap p( RESPATH "images/list-remove.png" );
|
|
||||||
p = p.scaledToHeight( m_iconHeight, Qt::SmoothTransformation );
|
|
||||||
|
|
||||||
QRect r ( o3.rect.right() - padding - m_iconHeight, padding + o3.rect.y(), m_iconHeight, m_iconHeight );
|
|
||||||
painter->drawPixmap( r, p );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*QStyleOptionViewItemV4 opt = o;
|
|
||||||
|
|
||||||
// shrink the indentations. count how indented this item is and remove it
|
|
||||||
int indentMult = 0;
|
|
||||||
QModelIndex counter = index;
|
|
||||||
while ( counter.parent().isValid() )
|
|
||||||
{
|
|
||||||
indentMult++;
|
|
||||||
counter = counter.parent();
|
|
||||||
}
|
|
||||||
int realX = opt.rect.x() + indentMult * TREEVIEW_INDENT_ADD;
|
|
||||||
|
|
||||||
opt.rect.setX( realX );
|
|
||||||
const QWidget *widget = opt.widget;
|
|
||||||
QStyle *style = widget ? widget->style() : QApplication::style();
|
|
||||||
style->drawControl( QStyle::CE_ItemViewItem, &opt, painter, widget ); */
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef Q_WS_MAC
|
|
||||||
painter->setFont( savedFont );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
SourceDelegate::editorEvent ( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
|
|
||||||
{
|
|
||||||
|
|
||||||
if ( event->type() == QEvent::MouseButtonRelease )
|
|
||||||
{
|
|
||||||
SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
|
|
||||||
if ( type == SourcesModel::TemporaryPage )
|
|
||||||
{
|
|
||||||
TemporaryPageItem* gpi = qobject_cast< TemporaryPageItem* >( index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >() );
|
|
||||||
Q_ASSERT( gpi );
|
|
||||||
QMouseEvent* ev = static_cast< QMouseEvent* >( event );
|
|
||||||
|
|
||||||
QStyleOptionViewItemV4 o = option;
|
|
||||||
initStyleOption( &o, index );
|
|
||||||
int padding = 3;
|
|
||||||
QRect r ( o.rect.right() - padding - m_iconHeight, padding + o.rect.y(), m_iconHeight, m_iconHeight );
|
|
||||||
|
|
||||||
if ( r.contains( ev->pos() ) )
|
|
||||||
gpi->removeFromList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return QStyledItemDelegate::editorEvent ( event, model, option, index );
|
|
||||||
}
|
|
||||||
|
@@ -29,6 +29,7 @@ class CollectionModel;
|
|||||||
class PlaylistModel;
|
class PlaylistModel;
|
||||||
class SourcesModel;
|
class SourcesModel;
|
||||||
class SourcesProxyModel;
|
class SourcesProxyModel;
|
||||||
|
class SourceDelegate;
|
||||||
|
|
||||||
class SourceTreeView : public QTreeView
|
class SourceTreeView : public QTreeView
|
||||||
{
|
{
|
||||||
@@ -81,6 +82,7 @@ private:
|
|||||||
SourcesModel* m_model;
|
SourcesModel* m_model;
|
||||||
SourcesProxyModel* m_proxyModel;
|
SourcesProxyModel* m_proxyModel;
|
||||||
QModelIndex m_contextMenuIndex;
|
QModelIndex m_contextMenuIndex;
|
||||||
|
SourceDelegate* m_delegate;
|
||||||
|
|
||||||
QMenu m_playlistMenu;
|
QMenu m_playlistMenu;
|
||||||
QMenu m_roPlaylistMenu;
|
QMenu m_roPlaylistMenu;
|
||||||
|
Reference in New Issue
Block a user