Commit a3120aa5 authored by Jean-Philippe André's avatar Jean-Philippe André Committed by Jean-Philippe André

Extensions/Qt: Use a custom QListView in Plugins & Extensions panel

parent 3990277e
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include "util/customwidgets.hpp" #include "util/customwidgets.hpp"
#include "extensions_manager.hpp" #include "extensions_manager.hpp"
#include <assert.h>
//#include <vlc_modules.h> //#include <vlc_modules.h>
#include <QTreeWidget> #include <QTreeWidget>
...@@ -44,7 +46,13 @@ ...@@ -44,7 +46,13 @@
#include <QComboBox> #include <QComboBox>
#include <QTextBrowser> #include <QTextBrowser>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSpacerItem> #include <QSpacerItem>
#include <QListView>
#include <QPainter>
#include <QStyleOptionViewItem>
#include <QKeyEvent>
PluginDialog::PluginDialog( intf_thread_t *_p_intf ) : QVLCFrame( _p_intf ) PluginDialog::PluginDialog( intf_thread_t *_p_intf ) : QVLCFrame( _p_intf )
{ {
...@@ -168,152 +176,248 @@ ExtensionTab::ExtensionTab( intf_thread_t *p_intf ) ...@@ -168,152 +176,248 @@ ExtensionTab::ExtensionTab( intf_thread_t *p_intf )
: QVLCFrame( p_intf ) : QVLCFrame( p_intf )
{ {
// Layout // Layout
QGridLayout *layout = new QGridLayout( this ); QVBoxLayout *layout = new QVBoxLayout( this );
// ListView
extList = new QListView( this );
layout->addWidget( extList );
// Top: combo // List item delegate
extList = new QComboBox( this ); ExtensionItemDelegate *itemDelegate = new ExtensionItemDelegate( p_intf,
layout->addWidget( extList, 0, 0, 1, -1 ); extList );
extList->setItemDelegate( itemDelegate );
// Center: Description
layout->addWidget( new QLabel( "<b>" + qtr( "Version" ) + "</b>" ), // Extension list look & feeling
1, 0, 1, 1 ); extList->setAlternatingRowColors( true );
layout->addWidget( new QLabel( "<b>" + qtr( "Author" ) + "</b>" ), extList->setSelectionMode( QAbstractItemView::SingleSelection );
2, 0, 1, 1 );
layout->addWidget( new QLabel( "<b>" + qtr( "Description" ) + "</b>" ), // Model
3, 0, 1, 1 ); ExtensionListModel *model = new ExtensionListModel( extList, p_intf );
layout->addWidget( new QLabel( "<b>" + qtr( "Website" ) + "</b>" ), extList->setModel( model );
6, 0, 1, 1 );
layout->addWidget( new QLabel( "<b>" + qtr( "File" ) + "</b>" ), // Buttons' layout
7, 0, 1, 1 );
version = new QLabel( this );
layout->addWidget( version, 1, 1, 1, 1 );
author = new QLabel( this );
layout->addWidget( author, 2, 1, 1, 1 );
description = new QTextBrowser( this );
description->setOpenExternalLinks( true );
layout->addWidget( description, 4, 0, 1, -1 );
url = new QLabel( this );
url->setOpenExternalLinks( true );
url->setTextFormat( Qt::RichText );
layout->addWidget( url, 6, 1, 1, 1 );
name = new QLineEdit( this );
name->setReadOnly( true );
layout->addWidget( name, 7, 1, 1, 1 );
// Bottom: Configuration tools
QHBoxLayout *hbox = new QHBoxLayout; QHBoxLayout *hbox = new QHBoxLayout;
hbox->addItem( new QSpacerItem( 1, 1, QSizePolicy::Expanding,
QSizePolicy::Fixed ) );
// More information button
butMoreInfo = new QPushButton( QIcon( ":/menu/info" ),
qtr( "More information..." ),
this );
CONNECT( butMoreInfo, clicked(),
this, moreInformation() );
hbox->addWidget( butMoreInfo );
// Reload button
ExtensionsManager *EM = ExtensionsManager::getInstance( p_intf );
QPushButton *reload = new QPushButton( QIcon( ":/update" ), QPushButton *reload = new QPushButton( QIcon( ":/update" ),
qtr( "Reload extensions" ), qtr( "Reload extensions" ),
this ); this );
QSpacerItem *spacer = new QSpacerItem( 1, 1, QSizePolicy::Expanding, CONNECT( reload, clicked(),
QSizePolicy::Expanding ); EM, reloadExtensions() );
hbox->addItem( spacer );
hbox->addWidget( reload ); hbox->addWidget( reload );
BUTTONACT( reload, reloadExtensions() );
layout->addItem( hbox, 8, 0, 1, -1 );
// Layout: compact display // Add buttons hbox
layout->setHorizontalSpacing( 15 ); layout->addItem( hbox );
}
fillList(); ExtensionTab::~ExtensionTab()
{
}
CONNECT( extList, currentIndexChanged( int ), // Do not close on ESC or ENTER
this, selectionChanged( int ) ); void ExtensionTab::keyPressEvent( QKeyEvent *keyEvent )
extList->setCurrentIndex( 0 ); {
selectionChanged( 0 ); keyEvent->ignore();
}
/* Safe copy of the extension_t struct */
class ExtensionCopy
{
public:
ExtensionCopy( extension_t *p_ext )
{
name = qfu( p_ext->psz_name );
description = qfu( p_ext->psz_description );
title = qfu( p_ext->psz_title );
author = qfu( p_ext->psz_author );
version = qfu( p_ext->psz_version );
url = qfu( p_ext->psz_url );
}
~ExtensionCopy() {}
QString name, title, description, author, version, url;
};
/* Extensions list model for the QListView */
ExtensionListModel::ExtensionListModel( QListView *view, intf_thread_t *intf )
: QAbstractListModel( view ), p_intf( intf )
{
// Connect to ExtensionsManager::extensionsUpdated() // Connect to ExtensionsManager::extensionsUpdated()
ExtensionsManager* EM = ExtensionsManager::getInstance( p_intf ); ExtensionsManager* EM = ExtensionsManager::getInstance( p_intf );
CONNECT( EM, extensionsUpdated(), this, fillList() ); CONNECT( EM, extensionsUpdated(), this, updateList() );
// Load extensions now if not already loaded
EM->loadExtensions();
} }
ExtensionTab::~ExtensionTab() ExtensionListModel::~ExtensionListModel()
{ {
} }
void ExtensionTab::fillList() void ExtensionListModel::updateList()
{ {
ExtensionsManager* EM = ExtensionsManager::getInstance( p_intf ); ExtensionCopy *ext;
if( !EM->isLoaded() )
EM->loadExtensions();
extensions_manager_t* p_mgr = EM->getManager();
if( !p_mgr )
return;
// Disconnect signal: we don't want to call selectionChanged now // Clear extensions list
disconnect( extList, SIGNAL( currentIndexChanged( int ) ), while( !extensions.isEmpty() )
this, SLOT( selectionChanged( int ) ) ); {
ext = extensions.takeLast();
delete ext;
}
extList->clear(); // Find new extensions
ExtensionsManager *EM = ExtensionsManager::getInstance( p_intf );
extensions_manager_t *p_mgr = EM->getManager();
if( !p_mgr )
return;
vlc_mutex_lock( &p_mgr->lock ); vlc_mutex_lock( &p_mgr->lock );
extension_t *p_ext; extension_t *p_ext;
FOREACH_ARRAY( p_ext, p_mgr->extensions ) FOREACH_ARRAY( p_ext, p_mgr->extensions )
{ {
extList->addItem( p_ext->psz_title, QString( p_ext->psz_name ) ); ext = new ExtensionCopy( p_ext );
extensions.push_back( ext );
} }
FOREACH_END() FOREACH_END()
vlc_mutex_unlock( &p_mgr->lock ); vlc_mutex_unlock( &p_mgr->lock );
vlc_object_release( p_mgr ); vlc_object_release( p_mgr );
// Reconnect signal and update screen emit dataChanged( index( 0 ), index( rowCount() - 1 ) );
connect( extList, SIGNAL( currentIndexChanged( int ) ),
this, SLOT( selectionChanged( int ) ) );
extList->setCurrentIndex( 0 );
selectionChanged( 0 );
} }
void ExtensionTab::selectionChanged( int index ) int ExtensionListModel::rowCount( const QModelIndex& parent ) const
{ {
QString extName = extList->itemData( index ).toString(); int count = 0;
if( extName.isEmpty() ) ExtensionsManager *EM = ExtensionsManager::getInstance( p_intf );
return; extensions_manager_t *p_mgr = EM->getManager();
ExtensionsManager* EM = ExtensionsManager::getInstance( p_intf );
extensions_manager_t* p_mgr = EM->getManager();
if( !p_mgr ) if( !p_mgr )
return; return 0;
vlc_mutex_lock( &p_mgr->lock ); vlc_mutex_lock( &p_mgr->lock );
count = p_mgr->extensions.i_size;
vlc_mutex_unlock( &p_mgr->lock );
vlc_object_release( p_mgr );
const char *psz_name = qtu( extName ); return count;
}
extension_t *p_ext; QVariant ExtensionListModel::data( const QModelIndex& index, int role ) const
FOREACH_ARRAY( p_ext, p_mgr->extensions ) {
{ if( !index.isValid() )
if( !strcmp( p_ext->psz_name, psz_name ) ) return QVariant();
switch( role )
{ {
char *psz_url; default:
if( p_ext->psz_url != NULL return QVariant();
&& asprintf( &psz_url, "<a href=\"%s\">%s</a>", p_ext->psz_url, }
p_ext->psz_url ) != -1 ) }
QModelIndex ExtensionListModel::index( int row, int column,
const QModelIndex& parent ) const
{
if( column != 0 )
return QModelIndex();
if( row < 0 || row >= extensions.size() )
return QModelIndex();
return createIndex( row, 0, extensions.at( row ) );
}
/* Extension List Widget Item */
ExtensionItemDelegate::ExtensionItemDelegate( intf_thread_t *p_intf,
QListView *view )
: QStyledItemDelegate( view ), view( view ), p_intf( p_intf )
{
}
ExtensionItemDelegate::~ExtensionItemDelegate()
{
}
void ExtensionItemDelegate::paint( QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index ) const
{
ExtensionCopy *ext = ( ExtensionCopy* ) index.internalPointer();
assert( ext != NULL );
int width = option.rect.width();
int height = option.rect.height();
// Pixmap: buffer where to draw
QPixmap pix(option.rect.size());
// Draw background
pix.fill( Qt::transparent ); // FIXME
// ItemView primitive style
QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem,
&option,
painter );
// Painter on the pixmap
QPainter *pixpaint = new QPainter(&pix);
// Text font & pen
QFont font = painter->font();
QPen pen = painter->pen();
if( view->selectionModel()->selectedIndexes().contains( index ) )
{ {
url->setText( psz_url ); pen.setBrush( option.palette.highlightedText() );
free( psz_url );
} }
else else
{ {
url->clear(); pen.setBrush( option.palette.text() );
} }
version->setText( qfu( p_ext->psz_version ) ); pixpaint->setPen( pen );
description->setHtml( qfu( p_ext->psz_description ) );
author->setText( qfu( p_ext->psz_author ) ); // Title: bold
name->setText( qfu( p_ext->psz_name ) ); font.setBold( true );
break; pixpaint->setFont( font );
} pixpaint->drawText( QRect( 10, 5, width - 70, 20 ),
} Qt::AlignLeft, ext->title );
FOREACH_END()
// Short description: normal
vlc_mutex_unlock( &p_mgr->lock ); font.setBold( false );
vlc_object_release( p_mgr ); pixpaint->setFont( font );
pixpaint->drawText( QRect( 10, 30, width - 40, 20 ),
Qt::AlignLeft, ext->description );
// Version: italic
font.setItalic( true );
pixpaint->setFont( font );
pixpaint->drawText( QRect( width - 50, 5, 20, 20 ),
Qt::AlignLeft, ext->version );
// Flush paint operations
delete pixpaint;
// Draw it on the screen!
painter->drawPixmap( option.rect, pix );
} }
void ExtensionTab::reloadExtensions() QSize ExtensionItemDelegate::sizeHint( const QStyleOptionViewItem &option,
const QModelIndex &index ) const
{ {
ExtensionsManager* EM = ExtensionsManager::getInstance( p_intf ); if (index.isValid() && index.column() == 0)
EM->reloadExtensions(); {
fillList(); QFontMetrics metrics = option.fontMetrics;
return QSize( 200, 20 + 2 * metrics.height() );
}
else
return QSize();
} }
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
#include <QStringList> #include <QStringList>
#include <QTreeWidgetItem> #include <QTreeWidgetItem>
#include <QListWidgetItem> #include <QAbstractListModel>
#include <QStyledItemDelegate>
class QLabel; class QLabel;
class QTabWidget; class QTabWidget;
...@@ -39,10 +40,16 @@ class QComboBox; ...@@ -39,10 +40,16 @@ class QComboBox;
class QTreeWidget; class QTreeWidget;
class QLineEdit; class QLineEdit;
class QTextBrowser; class QTextBrowser;
class QListView;
class QStyleOptionViewItem;
class QPainter;
class QKeyEvent;
class PluginTab; class PluginTab;
class ExtensionTab; class ExtensionTab;
class ExtensionListItem; class ExtensionListItem;
class SearchLineEdit; class SearchLineEdit;
class ExtensionCopy;
class PluginDialog : public QVLCFrame, public Singleton<PluginDialog> class PluginDialog : public QVLCFrame, public Singleton<PluginDialog>
{ {
...@@ -81,19 +88,15 @@ class ExtensionTab : public QVLCFrame ...@@ -81,19 +88,15 @@ class ExtensionTab : public QVLCFrame
{ {
Q_OBJECT; Q_OBJECT;
protected:
virtual void keyPressEvent( QKeyEvent *keyEvent );
private: private:
ExtensionTab( intf_thread_t *p_intf ); ExtensionTab( intf_thread_t *p_intf );
virtual ~ExtensionTab(); virtual ~ExtensionTab();
QComboBox *extList; QListView *extList;
QLabel *author, *version, *url; QPushButton *butMoreInfo;
QTextBrowser *description;
QLineEdit *name;
private slots:
void fillList();
void selectionChanged( int index );
void reloadExtensions();
friend class PluginDialog; friend class PluginDialog;
}; };
...@@ -108,5 +111,44 @@ public: ...@@ -108,5 +111,44 @@ public:
virtual bool operator< ( const QTreeWidgetItem & other ) const; virtual bool operator< ( const QTreeWidgetItem & other ) const;
}; };
class ExtensionListModel : public QAbstractListModel
{
Q_OBJECT
public:
ExtensionListModel( QListView *view, intf_thread_t *p_intf );
virtual ~ExtensionListModel();
virtual QVariant data( const QModelIndex& index, int role ) const;
virtual QModelIndex index( int row, int column = 0,
const QModelIndex& = QModelIndex() ) const;
virtual int rowCount( const QModelIndex& = QModelIndex() ) const;
private slots:
void updateList();
private:
intf_thread_t *p_intf;
QList<ExtensionCopy*> extensions;
};
class ExtensionItemDelegate : public QStyledItemDelegate
{
public:
ExtensionItemDelegate( intf_thread_t *p_intf, QListView *view );
virtual ~ExtensionItemDelegate();
virtual void paint( QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index ) const;
virtual QSize sizeHint( const QStyleOptionViewItem &option,
const QModelIndex &index ) const;
private:
QListView *view;
intf_thread_t *p_intf;
};
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment