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 @@
#include "util/customwidgets.hpp"
#include "extensions_manager.hpp"
#include <assert.h>
//#include <vlc_modules.h>
#include <QTreeWidget>
......@@ -44,7 +46,13 @@
#include <QComboBox>
#include <QTextBrowser>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSpacerItem>
#include <QListView>
#include <QPainter>
#include <QStyleOptionViewItem>
#include <QKeyEvent>
PluginDialog::PluginDialog( intf_thread_t *_p_intf ) : QVLCFrame( _p_intf )
{
......@@ -168,152 +176,248 @@ ExtensionTab::ExtensionTab( intf_thread_t *p_intf )
: QVLCFrame( p_intf )
{
// Layout
QGridLayout *layout = new QGridLayout( this );
QVBoxLayout *layout = new QVBoxLayout( this );
// Top: combo
extList = new QComboBox( this );
layout->addWidget( extList, 0, 0, 1, -1 );
// Center: Description
layout->addWidget( new QLabel( "<b>" + qtr( "Version" ) + "</b>" ),
1, 0, 1, 1 );
layout->addWidget( new QLabel( "<b>" + qtr( "Author" ) + "</b>" ),
2, 0, 1, 1 );
layout->addWidget( new QLabel( "<b>" + qtr( "Description" ) + "</b>" ),
3, 0, 1, 1 );
layout->addWidget( new QLabel( "<b>" + qtr( "Website" ) + "</b>" ),
6, 0, 1, 1 );
layout->addWidget( new QLabel( "<b>" + qtr( "File" ) + "</b>" ),
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
// ListView
extList = new QListView( this );
layout->addWidget( extList );
// List item delegate
ExtensionItemDelegate *itemDelegate = new ExtensionItemDelegate( p_intf,
extList );
extList->setItemDelegate( itemDelegate );
// Extension list look & feeling
extList->setAlternatingRowColors( true );
extList->setSelectionMode( QAbstractItemView::SingleSelection );
// Model
ExtensionListModel *model = new ExtensionListModel( extList, p_intf );
extList->setModel( model );
// Buttons' layout
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" ),
qtr( "Reload extensions" ),
this );
QSpacerItem *spacer = new QSpacerItem( 1, 1, QSizePolicy::Expanding,
QSizePolicy::Expanding );
hbox->addItem( spacer );
CONNECT( reload, clicked(),
EM, reloadExtensions() );
hbox->addWidget( reload );
BUTTONACT( reload, reloadExtensions() );
layout->addItem( hbox, 8, 0, 1, -1 );
// Layout: compact display
layout->setHorizontalSpacing( 15 );
// Add buttons hbox
layout->addItem( hbox );
}
fillList();
ExtensionTab::~ExtensionTab()
{
}
CONNECT( extList, currentIndexChanged( int ),
this, selectionChanged( int ) );
extList->setCurrentIndex( 0 );
selectionChanged( 0 );
// Do not close on ESC or ENTER
void ExtensionTab::keyPressEvent( QKeyEvent *keyEvent )
{
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()
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 );
if( !EM->isLoaded() )
EM->loadExtensions();
extensions_manager_t* p_mgr = EM->getManager();
if( !p_mgr )
return;
ExtensionCopy *ext;
// Disconnect signal: we don't want to call selectionChanged now
disconnect( extList, SIGNAL( currentIndexChanged( int ) ),
this, SLOT( selectionChanged( int ) ) );
// Clear extensions list
while( !extensions.isEmpty() )
{
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 );
extension_t *p_ext;
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()
vlc_mutex_unlock( &p_mgr->lock );
vlc_object_release( p_mgr );
// Reconnect signal and update screen
connect( extList, SIGNAL( currentIndexChanged( int ) ),
this, SLOT( selectionChanged( int ) ) );
extList->setCurrentIndex( 0 );
selectionChanged( 0 );
emit dataChanged( index( 0 ), index( rowCount() - 1 ) );
}
void ExtensionTab::selectionChanged( int index )
int ExtensionListModel::rowCount( const QModelIndex& parent ) const
{
QString extName = extList->itemData( index ).toString();
if( extName.isEmpty() )
return;
ExtensionsManager* EM = ExtensionsManager::getInstance( p_intf );
extensions_manager_t* p_mgr = EM->getManager();
int count = 0;
ExtensionsManager *EM = ExtensionsManager::getInstance( p_intf );
extensions_manager_t *p_mgr = EM->getManager();
if( !p_mgr )
return;
return 0;
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;
FOREACH_ARRAY( p_ext, p_mgr->extensions )
QVariant ExtensionListModel::data( const QModelIndex& index, int role ) const
{
if( !index.isValid() )
return QVariant();
switch( role )
{
if( !strcmp( p_ext->psz_name, psz_name ) )
{
char *psz_url;
if( p_ext->psz_url != NULL
&& asprintf( &psz_url, "<a href=\"%s\">%s</a>", p_ext->psz_url,
p_ext->psz_url ) != -1 )
{
url->setText( psz_url );
free( psz_url );
}
else
{
url->clear();
}
version->setText( qfu( p_ext->psz_version ) );
description->setHtml( qfu( p_ext->psz_description ) );
author->setText( qfu( p_ext->psz_author ) );
name->setText( qfu( p_ext->psz_name ) );
break;
}
default:
return QVariant();
}
FOREACH_END()
}
vlc_mutex_unlock( &p_mgr->lock );
vlc_object_release( p_mgr );
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 ) );
}
void ExtensionTab::reloadExtensions()
/* Extension List Widget Item */
ExtensionItemDelegate::ExtensionItemDelegate( intf_thread_t *p_intf,
QListView *view )
: QStyledItemDelegate( view ), view( view ), p_intf( p_intf )
{
ExtensionsManager* EM = ExtensionsManager::getInstance( p_intf );
EM->reloadExtensions();
fillList();
}
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 ) )
{
pen.setBrush( option.palette.highlightedText() );
}
else
{
pen.setBrush( option.palette.text() );
}
pixpaint->setPen( pen );
// Title: bold
font.setBold( true );
pixpaint->setFont( font );
pixpaint->drawText( QRect( 10, 5, width - 70, 20 ),
Qt::AlignLeft, ext->title );
// Short description: normal
font.setBold( false );
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 );
}
QSize ExtensionItemDelegate::sizeHint( const QStyleOptionViewItem &option,
const QModelIndex &index ) const
{
if (index.isValid() && index.column() == 0)
{
QFontMetrics metrics = option.fontMetrics;
return QSize( 200, 20 + 2 * metrics.height() );
}
else
return QSize();
}
......@@ -31,7 +31,8 @@
#include <QStringList>
#include <QTreeWidgetItem>
#include <QListWidgetItem>
#include <QAbstractListModel>
#include <QStyledItemDelegate>
class QLabel;
class QTabWidget;
......@@ -39,10 +40,16 @@ class QComboBox;
class QTreeWidget;
class QLineEdit;
class QTextBrowser;
class QListView;
class QStyleOptionViewItem;
class QPainter;
class QKeyEvent;
class PluginTab;
class ExtensionTab;
class ExtensionListItem;
class SearchLineEdit;
class ExtensionCopy;
class PluginDialog : public QVLCFrame, public Singleton<PluginDialog>
{
......@@ -81,19 +88,15 @@ class ExtensionTab : public QVLCFrame
{
Q_OBJECT;
protected:
virtual void keyPressEvent( QKeyEvent *keyEvent );
private:
ExtensionTab( intf_thread_t *p_intf );
virtual ~ExtensionTab();
QComboBox *extList;
QLabel *author, *version, *url;
QTextBrowser *description;
QLineEdit *name;
private slots:
void fillList();
void selectionChanged( int index );
void reloadExtensions();
QListView *extList;
QPushButton *butMoreInfo;
friend class PluginDialog;
};
......@@ -108,5 +111,44 @@ public:
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
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