1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-03-21 16:29:43 +01:00

Some work on accounts

This commit is contained in:
Leo Franchi 2011-11-06 18:58:58 -05:00
parent aae400bea9
commit e3785e50f2
14 changed files with 475 additions and 574 deletions

View File

@ -71,7 +71,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
settingsdialog.cpp
diagnosticsdialog.cpp
configdelegatebase.cpp
sipconfigdelegate.cpp
accountdelegate.cpp
resolverconfigdelegate.cpp
settingslistdelegate.cpp
resolversmodel.cpp
@ -122,7 +122,7 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
diagnosticsdialog.h
configdelegatebase.h
resolverconfigdelegate.h
sipconfigdelegate.h
accountdelegate.h
settingslistdelegate.h
resolversmodel.h
delegateconfigwrapper.h

235
src/accountdelegate.cpp Normal file
View File

@ -0,0 +1,235 @@
/*
Copyright (C) 2011 Leo Franchi <leo.franchi@kdab.com>
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "accountdelegate.h"
#include <QApplication>
#include <QPainter>
#include "accounts/accountmodel.h"
#include "accounts/account.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#define ICONSIZE 36
#define WRENCH_SIZE 24
#define STATUS_ICON_SIZE 18
#define CHECK_LEFT_EDGE 8
using namespace Tomahawk;
using namespace Accounts;
AccountDelegate::AccountDelegate( QObject* parent )
: ConfigDelegateBase ( parent )
{
connect( this, SIGNAL( configPressed( QModelIndex ) ), this, SLOT( askedForEdit( QModelIndex ) ) );
}
bool
AccountDelegate::editorEvent ( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
{
return ConfigDelegateBase::editorEvent( event, model, option, index );
}
void
AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index );
const QRect itemRect = opt.rect;
const int top = itemRect.top();
const int mid = itemRect.height() / 2;
// one line bold for account name
// space below it for account description
// checkbox, icon, name, online/offline status, config icon
QFont name = opt.font;
name.setPointSize( name.pointSize() + 2 );
name.setBold( true );
QFont desc = opt.font;
desc.setItalic( true );
desc.setPointSize( error.pointSize() - 2 );
// draw the background
const QWidget* w = opt.widget;
QStyle* style = w ? w->style() : QApplication::style();
style->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, w );
int iconLeftEdge = CHECK_LEFT_EDGE + ICONSIZE + PADDING;
int textLeftEdge = iconLeftEdge + ICONSIZE + PADDING;
// draw checkbox first
int pos = ( mid ) - ( WRENCH_SIZE / 2 );
QRect checkRect = QRect( CHECK_LEFT_EDGE, pos + top, WRENCH_SIZE, WRENCH_SIZE );
opt.rect = checkRect;
drawCheckBox( opt, painter, w );
// draw the icon if it exists
pos = mid - ( ICONSIZE / 2 );
if( !index.data( Qt::DecorationRole ).value< QIcon >().isNull() ) {
QRect prect = QRect( iconLeftEdge, pos + top, ICONSIZE, ICONSIZE );
painter->save();
painter->drawPixmap( prect, index.data( Qt::DecorationRole ).value< QIcon >().pixmap( prect.size() ) );
painter->restore();
}
// from the right edge--config status and online/offline
QRect confRect = QRect( itemRect.width() - WRENCH_SIZE - 2 * PADDING, mid - WRENCH_SIZE / 2 + top, WRENCH_SIZE, WRENCH_SIZE );
if( index.data( SipModel::HasConfig ).toBool() ) {
QStyleOptionToolButton topt;
topt.rect = confRect;
topt.pos = confRect.topLeft();
drawConfigWrench( painter, opt, topt );
}
// draw the online/offline status
const bool hasCapability = ( static_cast< AccountModel::BasicCapabilities >( index.data( AccountModel::BasicCapabilityRole ).toInt() ) != AccountModel::NoCapabilities );
const int quarter = mid - ( itemRect.height() / 4 );
const int statusY = hasCapability ? quarter : mid;
const int statusX = confRect.left() - 2*PADDING - STATUS_ICON_SIZE;
QFont statusF = opt.font;
statusF.setPointSize( statusF.pointSize() - 2 );
QFontMetrics statusFM( statusF );
QPixmap p;
QString statusText;
Account::ConnectionState state = static_cast< Account::ConnectionState >( index.data( AccountModel::ConnectionStateRole ).toInt() );
if( state == SipPlugin::Connected ) {
p = QPixmap( RESPATH "images/sipplugin-online.png" );
statusText = tr( "Online" );
} else if( state == SipPlugin::Connecting ) {
p = QPixmap( RESPATH "images/sipplugin-offline.png" );
statusText = tr( "Connecting..." );
} else {
p = QPixmap( RESPATH "images/sipplugin-offline.png" );
statusText = tr( "Offline" );
}
p = p.scaled( STATUS_ICON_SIZE, STATUS_ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
painter->drawPixmap( statusX, statusY - STATUS_ICON_SIZE / 2 + top, STATUS_ICON_SIZE, STATUS_ICON_SIZE, p );
const int width = statusFM.width( statusText );
int statusTextX = statusX - PADDING - width;
painter->save();
painter->setFont( statusF );
painter->drawText( QRect( statusTextX, statusY - statusFM.height() / 2 + top, width, statusFM.height() ), statusText );
// draw optional capability text if it exists
if ( hasCapability )
{
QString capString;
AccountModel::BasicCapabilities cap = static_cast< AccountModel::BasicCapabilities >( index.data( AccountModel::BasicCapabilityRole ).toInt() );
if ( ( cap & AccountModel::SipCapability ) && ( cap & AccountModel::ResolverCapability ) )
capString = tr( "Connect to and play from friends" );
else if ( cap & AccountModel::SipCapability )
capString = tr( "Connect to friends" );
else if ( cap & AccountModel::ResolverCapability )
capString = tr( "Find Music");
// checkbox for capability
const int capY = statusY + ( itemRect.height() / 2 );
QRect capCheckRect( statusX, capY - STATUS_ICON_SIZE / 2 + top, STATUS_ICON_SIZE, STATUS_ICON_SIZE );
opt.rect = capCheckRect;
drawCheckBox( opt, painter, w );
// text to accompany checkbox
const int capW = statusFM.width( capString );
const int capTextX = statusX - PADDING - capW;
painter->drawText( QRect( capTextX, capY - statusFM.height() / 2 + top, capW, statusFM.height() ) );
if ( capTextX < statusTextX )
statusTextX = capTextX;
}
painter->restore();
// name
painter->save();
painter->setFont( name );
QFontMetrics namefm( name );
// pos will the top-left point of the text rect
pos = mid - ( nameHeight / 2 ) + top;
// TODO bound with config icon and offline/online status
width = itemRect.width() - statusTextX;
QRect nameRect( textLeftEdge, pos, width, namefm.height() );
painter->drawText( nameRect, index.data( AccountModel::AccountName ).toString() );
nameRect.translate( mid, 0 ); // move down by half the hight
painter->drawText( nameRect, index.data( AccountModel::DescText ).toString() );
painter->restore();
}
QRect
AccountDelegate::checkRectForIndex( const QStyleOptionViewItem &option, const QModelIndex &idx, int role ) const
{
if ( role == Qt::CheckStateRole )
{
// the whole resolver checkbox
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, idx );
const int mid = opt.rect.height() / 2;
const int pos = mid - ( ICONSIZE / 2 );
QRect checkRect( CHECK_LEFT_EDGE, pos + opt.rect.top(), ICONSIZE, ICONSIZE );
return checkRect;
} else if ( role == AccountModel::BasicCapabilityRole )
{
// The capabilities checkbox
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, idx );
const int quarter = opt.rect.height() / 4 + opt.rect.height() / 2;
const int leftEdge = opt.rect.width() - PADDING - WRENCH_SIZE - PADDING - WRENCH_SIZE;
QRect checkRect( leftEdge, quarter, WRENCH_SIZE, WRENCH_SIZE );
return checkRect;
}
return QRect();
}
QRect
AccountDelegate::configRectForIndex( const QStyleOptionViewItem& option, const QModelIndex& idx ) const
{
if( !idx.data( SipModel::FactoryItemRole ).toBool() && !idx.data( SipModel::FactoryRole ).toBool() )
{
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, idx );
QRect itemRect = opt.rect;
QRect confRect = QRect( itemRect.width() - ICONSIZE - 2 * PADDING, (opt.rect.height() / 2) - ICONSIZE / 2 + opt.rect.top(), ICONSIZE, ICONSIZE );
return confRect;
}
return QRect();
}
QSize
AccountDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
return ConfigDelegateBase::sizeHint( option, index );
}
void
AccountDelegate::askedForEdit( const QModelIndex& idx )
{
emit openConfig( qobject_cast< SipPlugin* >( idx.data( SipModel::SipPluginData ).value< QObject* >() ) );
}

View File

@ -21,26 +21,35 @@
#include "configdelegatebase.h"
class SipPlugin;
class SipPluginFactory;
class SipConfigDelegate : public ConfigDelegateBase
namespace Tomahawk
{
namespace Accounts
{
class Account;
class AccountDelegate : public ConfigDelegateBase
{
Q_OBJECT
public:
SipConfigDelegate( QObject* parent = 0);
AccountDelegate( QObject* parent = 0);
virtual void paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual bool editorEvent ( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
virtual QSize sizeHint ( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual QRect checkRectForIndex( const QStyleOptionViewItem &option, const QModelIndex &idx ) const;
virtual QRect checkRectForIndex( const QStyleOptionViewItem &option, const QModelIndex &idx, int role ) const;
virtual QRect configRectForIndex( const QStyleOptionViewItem& option, const QModelIndex& idx ) const;
virtual QList<int> extraCheckRoles() const { return QList<int>() << (int)AccountModel::BasicCapabilityRole; }
private slots:
void askedForEdit( const QModelIndex& idx );
signals:
void sipFactoryClicked( SipPluginFactory* );
void openConfig( SipPlugin* );
void openConfig( Account* );
};
}
}
#endif // SIPCONFIGDELEGATE_H

View File

@ -25,6 +25,8 @@
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#define ROW_HEIGHT 50
ConfigDelegateBase::ConfigDelegateBase ( QObject* parent )
: QStyledItemDelegate ( parent )
{
@ -36,23 +38,7 @@ QSize
ConfigDelegateBase::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
int width = QStyledItemDelegate::sizeHint( option, index ).width();
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index );
QFont name = opt.font;
name.setPointSize( name.pointSize() + 2 );
name.setBold( true );
QFont path = opt.font;
path.setItalic( true );
path.setPointSize( path.pointSize() - 1 );
QFontMetrics bfm( name );
QFontMetrics sfm( path );
return QSize( width, 2 * PADDING + bfm.height() + sfm.height() );
return QSize( width, ROW_HEIGHT );
}
void
@ -94,17 +80,24 @@ ConfigDelegateBase::editorEvent ( QEvent* event, QAbstractItemModel* model, cons
m_configPressed = QModelIndex();
QMouseEvent* me = static_cast< QMouseEvent* >( event );
if( me->button() != Qt::LeftButton || !checkRectForIndex( option, index ).contains( me->pos() ) )
return false;
QList<int> roles = QList<int>() << (int)Qt::CheckStateRole;
roles.append( extraCheckRoles() );
// eat the double click events inside the check rect
if( event->type() == QEvent::MouseButtonDblClick ) {
return true;
foreach ( int role, roles )
{
if( me->button() != Qt::LeftButton || !checkRectForIndex( option, index, role ).contains( me->pos() ) )
return false;
// eat the double click events inside the check rect
if( event->type() == QEvent::MouseButtonDblClick ) {
return true;
}
Qt::CheckState curState = static_cast< Qt::CheckState >( index.data( role ).toInt() );
Qt::CheckState newState = curState == Qt::Checked ? Qt::Unchecked : Qt::Checked;
return model->setData( index, newState, role );
}
Qt::CheckState curState = static_cast< Qt::CheckState >( index.data( Qt::CheckStateRole ).toInt() );
Qt::CheckState newState = curState == Qt::Checked ? Qt::Unchecked : Qt::Checked;
return model->setData( index, newState, Qt::CheckStateRole );
} else if( event->type() == QEvent::MouseButtonPress ) {
QMouseEvent* me = static_cast< QMouseEvent* >( event );

View File

@ -36,10 +36,11 @@ public:
virtual bool editorEvent ( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
// if you want to use a checkbox, you need to have this say where to paint it
virtual QRect checkRectForIndex( const QStyleOptionViewItem& option, const QModelIndex& idx ) const = 0;
virtual QRect checkRectForIndex( const QStyleOptionViewItem& option, const QModelIndex& idx, int role ) const = 0;
// if you want to use a config wrench, you need to have this say where to paint it
virtual QRect configRectForIndex( const QStyleOptionViewItem& option, const QModelIndex& idx ) const = 0;
virtual QList<int> extraCheckRoles() const { return QList<int>(); }
signals:
void configPressed( const QModelIndex& idx );

View File

@ -61,10 +61,10 @@ set( libSources
accounts/accountmanager.cpp
accounts/account.cpp
accounts/accountmodel.cpp
sip/SipPlugin.cpp
sip/SipHandler.cpp
sip/SipModel.cpp
sip/sipinfo.cpp
audio/audioengine.cpp
@ -286,12 +286,12 @@ set( libHeaders
accounts/account.h
accounts/accountmanager.h
accounts/accountmodel.h
EchonestCatalogSynchronizer.h
sip/SipPlugin.h
sip/SipHandler.h
sip/SipModel.h
sip/sipinfo.h
audio/audioengine.h

View File

@ -187,8 +187,8 @@ AccountManager::addAccountPlugin( Account* account )
foreach( AccountType type, account->types() )
m_accountsByAccountType[ type ].append( account );
//TODO:?
//emit pluginAdded( account );
emit accountAdded( account );
}

View File

@ -52,8 +52,12 @@ public:
Account* loadPlugin( const QString &accountId );
QString factoryFromId( const QString& accountId ) const;
QList< Account* > getAccounts() { return m_accounts; };
QList< Account* > getAccounts( Tomahawk::Accounts::AccountType type ) { return m_accountsByAccountType[ type ]; }
QList< Account* > accounts() const { return m_accounts; };
QList< Account* > accounts( Tomahawk::Accounts::AccountType type ) const { return m_accountsByAccountType[ type ]; }
signals:
void accountAdded( Tomahawk::Accounts::Account* );
void accountRemoved( Tomahawk::Accounts::Account* );
private:
QList< Account* > m_accounts;
@ -67,4 +71,4 @@ private:
};
#endif
#endif

View File

@ -0,0 +1,155 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "accountmodel.h"
#include "tomahawksettings.h"
#include "accounts/accountmanager.h"
#include "accounts/account.h"
#include "utils/logger.h"
using namespace Tomahawk;
using namespace Accounts;
AccountModel::AccountModel( QObject* parent )
: QAbstractListModel( parent )
{
connect( AccountManager::instance(), SIGNAL( accountAdded( Tomahawk::Accounts::Account* ) ), this, SLOT( accountAdded( Tomahawk::Accounts::Account* ) ) );
connect( AccountManager::instance(), SIGNAL( accountRemoved( Tomahawk::Accounts::Account* ) ), this, SLOT( accountRemoved( Tomahawk::Accounts::Account* ) ) );
}
AccountModel::~AccountModel()
{
}
QVariant
AccountModel::data( const QModelIndex& index, int role ) const
{
if( !index.isValid() )
return QVariant();
QList< Account* > accounts = AccountManager::instance()->accounts();
Q_ASSERT( index.row() <= accounts.size() );
Account* account = accounts[ index.row() ];
switch( role )
{
case Qt::DisplayRole:
case AccountModel::AccountName:
return account->accountServiceName();
case AccountModel::ConnectionStateRole:
return account->connectionState();
case AccountModel::HasConfig:
return ( account->configurationWidget() != 0 );
case Qt::DecorationRole:
return account->icon();
case AccountModel::AccountData:
return QVariant::fromValue< QObject* >( account );
case Qt::CheckStateRole:
return account->enabled() ? Qt::Checked : Qt::Unchecked;
default:
return QVariant();
}
return QVariant();
}
bool
AccountModel::setData( const QModelIndex& index, const QVariant& value, int role )
{
Q_ASSERT( index.isValid() && index.row() <= AccountManager::instance()->accounts().count() );
if ( role == Qt::CheckStateRole ) {
Qt::CheckState state = static_cast< Qt::CheckState >( value.toInt() );
QList< Account* > accounts = AccountManager::instance()->accounts();
Account* account = accounts[ index.row() ];
if( state == Qt::Checked && !account->enabled() ) {
account->setEnabled( true );
} else if( state == Qt::Unchecked ) {
account->setEnabled( false );
}
dataChanged( index, index );
return true;
}
else if ( role == BasicCapabilityRole )
{
// TODO
}
return false;
}
int
AccountModel::rowCount( const QModelIndex& parent ) const
{
return AccountManager::instance()->accounts().size();
}
Qt::ItemFlags
AccountModel::flags( const QModelIndex& index ) const
{
return QAbstractListModel::flags( index ) | Qt::ItemIsUserCheckable;
}
void
AccountModel::accountAdded( Account* account )
{
Q_UNUSED( p );
// we assume account plugins are added at the end of the list.
Q_ASSERT( AccountManager::instance()->accounts().last() == account );
if ( account->types().contains( SipType ) )
connect( account->sipPlugin(), SIGNAL( stateChanged( SipPlugin::ConnectionState ) ), this, SLOT( sipStateChanged( SipPlugin::ConnectionState ) ) );
int size = AccountManager::instance()->accounts().count() - 1;
beginInsertRows( QModelIndex(), size, size );
endInsertRows();
}
void
AccountModel::accountRemoved( Account* account )
{
int idx = AccountManager::instance()->allPlugins().indexOf( account );
beginRemoveRows( QModelIndex(), idx, idx );
endRemoveRows();
}
void
AccountModel::sipStateChanged( SipPlugin::ConnectionState state )
{
SipPlugin* p = qobject_cast< SipPlugin* >( sender() );
Q_ASSERT( a );
for ( int i = 0; i < AccountManager::instance()->accounts().size(); i++ )
{
if ( AccountManager::instance()->accounts()[i] &&
AccountManager::instance()->accounts()[i]->sipPlugin() &&
AccountManager::instance()->accounts()[i]->sipPlugin() == p )
{
QModelIndex idx = index( i, 0, QModelIndex() );
emit dataChanged( idx, idx );
return;
}
}
}

View File

@ -1,5 +1,4 @@
/*
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
This program is free software: you can redistribute it and/or modify
@ -21,43 +20,57 @@
#define SIPMODEL_H
#include "dllmacro.h"
#include "sip/SipPlugin.h"
#include <QModelIndex>
#include <QStringList>
class SipPlugin;
namespace Tomahawk
{
namespace Accounts
{
class DLLEXPORT SipModel : public QAbstractItemModel
class Account;
class DLLEXPORT AccountModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
PluginName = Qt::UserRole + 15,
ConnectionStateRole = Qt::UserRole + 17,
HasConfig = Qt::UserRole + 18,
FactoryRole = Qt::UserRole + 19,
ErrorString = Qt::UserRole + 20,
FactoryItemRole = Qt::UserRole + 21,
FactoryItemIcon = Qt::UserRole + 22,
SipPluginData = Qt::UserRole + 23,
SipPluginFactoryData = Qt::UserRole + 24
enum BasicCapabilities
{
NoCapabilities = 0,
SipCapability = 0x1,
ResolverCapability = 0x2
};
explicit SipModel( QObject* parent = 0 );
virtual ~SipModel();
enum Roles {
AccountName = Qt::UserRole + 15,
AccountIcon = Qt::UserRole + 16,
HeadlineText = Qt::UserRole + 17,
DescText = Qt::UserRole + 18,
BasicCapabilityRole = Qt::UserRole + 19,
ConnectionStateRole = Qt::UserRole + 20,
HasConfig = Qt::UserRole + 21,
ErrorString = Qt::UserRole + 22,
AccountData = Qt::UserRole + 23 // raw plugin
};
explicit AccountModel( QObject* parent = 0 );
virtual ~AccountModel();
virtual QModelIndex index ( int row, int column, const QModelIndex& parent = QModelIndex() ) const;
virtual QModelIndex parent ( const QModelIndex& child ) const;
virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;
virtual int columnCount( const QModelIndex& parent ) const;
virtual Qt::ItemFlags flags(const QModelIndex& index) const;
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
private slots:
void pluginAdded( SipPlugin* p );
void pluginRemoved( SipPlugin* p );
void pluginStateChanged( SipPlugin* p );
void accountAdded( Tomahawk::Accounts::Account* p );
void accountRemoved( Tomahawk::Accounts::Account* p );
void sipStateChanged( SipPlugin::ConnectionState state );
};
}
}
#endif // SIPMODEL_H

View File

@ -174,7 +174,7 @@ void
SipHandler::loadFromAccountManager()
{
tDebug() << Q_FUNC_INFO;
QList< Tomahawk::Accounts::Account* > accountList = Tomahawk::Accounts::AccountManager::instance()->getAccounts( Tomahawk::Accounts::SipType );
QList< Tomahawk::Accounts::Account* > accountList = Tomahawk::Accounts::AccountManager::instance()->accounts( Tomahawk::Accounts::SipType );
foreach( Tomahawk::Accounts::Account* account, accountList )
{
tDebug() << Q_FUNC_INFO << "adding plugin " << account->accountId();

View File

@ -1,227 +0,0 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SipModel.h"
#include "tomahawksettings.h"
#include "sip/SipHandler.h"
#include "sip/SipPlugin.h"
#include "utils/logger.h"
SipModel::SipModel( QObject* parent )
: QAbstractItemModel( parent )
{
connect( SipHandler::instance(), SIGNAL( stateChanged( SipPlugin*, SipPlugin::ConnectionState ) ), this, SLOT( pluginStateChanged( SipPlugin* ) ) );
connect( SipHandler::instance(), SIGNAL( pluginAdded( SipPlugin* ) ), this, SLOT( pluginAdded( SipPlugin* ) ) );
connect( SipHandler::instance(), SIGNAL( pluginRemoved( SipPlugin* ) ), this, SLOT( pluginRemoved( SipPlugin* ) ) );
// TODO disable inline factories for now
/*
foreach( SipPluginFactory* f, SipHandler::instance()->pluginFactories() ) {
if( f->isCreatable() )
m_factories << f;
} */
}
SipModel::~SipModel()
{
}
QVariant
SipModel::data( const QModelIndex& index, int role ) const
{
if( !index.isValid() )
return QVariant();
if( !index.parent().isValid() && index.row() == SipHandler::instance()->allPlugins().count() ) { // last row, this is the factory
if( role == Qt::DisplayRole )
return tr( "Add New Account..." );
else if( role == FactoryRole )
return true;
else
return QVariant();
}
if( !index.parent().isValid() ) { // account
QList< SipPlugin* > plugins = SipHandler::instance()->allPlugins();
Q_ASSERT( index.row() <= plugins.size() );
SipPlugin* p = plugins[ index.row() ];
switch( role )
{
case Qt::DisplayRole:
case SipModel::PluginName:
return p->account()->accountServiceName();
case SipModel::ConnectionStateRole:
return p->connectionState();
case SipModel::HasConfig:
return ( p->account()->configurationWidget() != 0 );
case SipModel::FactoryRole:
return false;
case Qt::DecorationRole:
return p->icon();
case SipModel::SipPluginData:
return QVariant::fromValue< QObject* >( p );
case Qt::CheckStateRole:
return p->account()->enabled() ? Qt::Checked : Qt::Unchecked;
default:
return QVariant();
}
}
/*
* m_factories never actually populated yet, so just disable
if( index.parent().isValid() ) { // this is a factory type
SipPluginFactory* p = m_factories.at( index.row() );
switch( role )
{
case Qt::DisplayRole:
return p->prettyName();
case SipModel::FactoryItemRole:
return true;
case SipModel::FactoryItemIcon:
return p->icon();
case SipModel::SipPluginFactoryData:
return QVariant::fromValue< QObject* >( p );
default:
return QVariant();
}
}
*/
return QVariant();
}
bool
SipModel::setData( const QModelIndex& index, const QVariant& value, int role )
{
Q_ASSERT( index.isValid() && index.row() <= SipHandler::instance()->allPlugins().count() );
if( role == Qt::CheckStateRole ) {
Qt::CheckState state = static_cast< Qt::CheckState >( value.toInt() );
QList< SipPlugin* > plugins = SipHandler::instance()->allPlugins();
SipPlugin* p = plugins[ index.row() ];
if( state == Qt::Checked && !p->account()->enabled() ) {
p->account()->setEnabled( true );
} else if( state == Qt::Unchecked ) {
p->account()->setEnabled( false );
}
dataChanged( index, index );
return true;
}
return false;
}
QModelIndex
SipModel::index( int row, int column, const QModelIndex& parent ) const
{
if( !parent.isValid() )
return hasIndex( row, column, parent ) ? createIndex( row, column, 0 ) : QModelIndex();
// qDebug() << "Creating index for non-top level row!";
// it's a child of the Add Account, e.g. a factory
if( hasIndex( row, column, parent ) ) {
return createIndex( row, column, 1 /* magic */ );
}
return QModelIndex();
}
QModelIndex
SipModel::parent( const QModelIndex& child ) const
{
if( !child.isValid() )
return QModelIndex();
if( child.internalId() == 1 ) {
return index( SipHandler::instance()->allPlugins().size(), 0, QModelIndex() );
}
return QModelIndex();
}
int
SipModel::rowCount( const QModelIndex& parent ) const
{
if( !parent.isValid() ) // invalid root node
return SipHandler::instance()->allPlugins().size() /* TODO inline factories disabled + 1*/;
if( parent.isValid() && !parent.parent().isValid() ) { // top level item
if( parent.row() == SipHandler::instance()->allPlugins().count() ) {// last row, this is the factory
//return m_factories.count();
}
}
return 0;
}
int
SipModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED( parent );
return 1;
}
Qt::ItemFlags
SipModel::flags( const QModelIndex& index ) const
{
if( index.data( SipModel::FactoryRole ).toBool() || index.data( SipModel::FactoryItemRole ).toBool() )
return QAbstractItemModel::flags( index ) & ~Qt::ItemIsSelectable;
return QAbstractItemModel::flags( index ) | Qt::ItemIsUserCheckable;
}
void
SipModel::pluginAdded( SipPlugin* p )
{
Q_UNUSED( p );
// we assume sip plugins are added at the end of the list.
Q_ASSERT( SipHandler::instance()->allPlugins().last() == p );
int size = SipHandler::instance()->allPlugins().count() - 1;
beginInsertRows( QModelIndex(), size, size );
endInsertRows();
}
void
SipModel::pluginRemoved( SipPlugin* p )
{
int idx = SipHandler::instance()->allPlugins().indexOf( p );
beginRemoveRows( QModelIndex(), idx, idx );
endRemoveRows();
}
void
SipModel::pluginStateChanged( SipPlugin* p )
{
int at = SipHandler::instance()->allPlugins().indexOf( p );
QModelIndex idx = index( at, 0, QModelIndex() );
emit dataChanged( idx, idx );
}

View File

@ -1,282 +0,0 @@
/*
Copyright (C) 2011 Leo Franchi <leo.franchi@kdab.com>
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "sipconfigdelegate.h"
#include <QApplication>
#include <QPainter>
#include "sip/SipModel.h"
#include "sip/SipPlugin.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#define ICONSIZE 24
#define CHECK_LEFT_EDGE 8
SipConfigDelegate::SipConfigDelegate( QObject* parent )
: ConfigDelegateBase ( parent )
{
connect( this, SIGNAL( configPressed( QModelIndex ) ), this, SLOT( askedForEdit( QModelIndex ) ) );
}
bool
SipConfigDelegate::editorEvent ( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
{
return ConfigDelegateBase::editorEvent( event, model, option, index );
}
void
SipConfigDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index );
QRect itemRect = opt.rect;
int top = itemRect.top();
int mid = itemRect.height() / 2;
// one line bold for account name
// space below it fro an error
// checkbox, icon, name, online/offline status, config icon
QFont name = opt.font;
name.setPointSize( name.pointSize() + 2 );
name.setBold( true );
QFont error = opt.font;
error.setItalic( true );
error.setPointSize( error.pointSize() - 2 );
// draw the background
const QWidget* w = opt.widget;
QStyle* style = w ? w->style() : QApplication::style();
style->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, w );
int iconLeftEdge = CHECK_LEFT_EDGE + ICONSIZE + PADDING;
int textLeftEdge = iconLeftEdge + ICONSIZE + PADDING;
if( index.data( SipModel::FactoryRole ).toBool() ) { // this is the "add new account" row
// draw a border and background
painter->save();
painter->setRenderHints( QPainter::Antialiasing );
painter->setBrush( QApplication::palette().color( QPalette::Active, QPalette::Highlight ).lighter( 150 ) );
QPainterPath roundedRect;
roundedRect.addRoundedRect( itemRect.adjusted( 1, 1, -1, -1 ), 3, 3 );
painter->drawPath( roundedRect );
painter->setBrush( QApplication::palette().color( QPalette::Active, QPalette::Highlight ).lighter( 170 ) );
painter->fillPath( roundedRect, painter->brush() );
painter->restore();
// draw "+" icon in checkbox column
int rectW = 18;
int diff = ( ICONSIZE/ 2 ) - ( rectW / 2) ;
int pos = ( mid ) - ( rectW / 2 );
QRect plusRect = QRect( CHECK_LEFT_EDGE + diff, pos + top, rectW, rectW );
QPixmap p( RESPATH "images/list-add.png" );
painter->drawPixmap( plusRect, p );
// draw text
QFont f = opt.font;
f.setPointSize( f.pointSize() );
f.setBold( true );
QFontMetrics fm( f );
QString text = index.data( Qt::DisplayRole ).toString();
QRect textR = fm.boundingRect( text );
textR.moveLeft( textLeftEdge );
textR.moveTop( mid - ( textR.height() / 2 ) + top );
textR.setRight( itemRect.right() );
painter->setFont( f );
painter->drawText( textR, text );
} else if( index.data( SipModel::FactoryItemRole ).toBool() ) { // this is an account type
// ConfigDelegateBase::paint( painter, opt, index );
// int indent = 10;
// draw a border and background
painter->save();
painter->setRenderHints( QPainter::Antialiasing );
painter->setBrush( QApplication::palette().color( QPalette::Active, QPalette::Highlight ).lighter( 170 ) );
QPainterPath roundedRect;
roundedRect.addRoundedRect( itemRect.adjusted( 1, 1, -1, -1 ), 3, 3 );
painter->drawPath( roundedRect );
painter->setBrush( QApplication::palette().color( QPalette::Active, QPalette::Highlight ).lighter( 180 ) );
painter->fillPath( roundedRect, painter->brush() );
painter->restore();
QIcon icon = index.data( SipModel::FactoryItemIcon ).value< QIcon >();
if( !icon.isNull() ) {
int rectW = 18;
int diff = ( ICONSIZE/ 2 ) - ( rectW / 2) ;
int pos = ( mid ) - ( rectW / 2 );
QRect rect = QRect( CHECK_LEFT_EDGE + diff, pos + top, rectW, rectW );
QPixmap p( icon.pixmap( rect.size() ) );
painter->drawPixmap( rect, p );
}
// draw text
QFont f = opt.font;
f.setPointSize( f.pointSize() );
f.setBold( true );
QFontMetrics fm( f );
QString text = index.data( Qt::DisplayRole ).toString();
QRect textR = fm.boundingRect( text );
textR.moveLeft( textLeftEdge );
textR.moveTop( mid - ( textR.height() / 2 ) + top );
textR.setRight( itemRect.right() );
painter->setFont( f );
painter->drawText( textR, text );
} else { // this is an existing account to show
// draw checkbox first
int pos = ( mid ) - ( ICONSIZE / 2 );
QRect checkRect = QRect( CHECK_LEFT_EDGE, pos + top, ICONSIZE, ICONSIZE );
opt.rect = checkRect;
drawCheckBox( opt, painter, w );
// draw the icon if it exists
pos = ( mid ) - ( ICONSIZE / 2 );
if( !index.data( Qt::DecorationRole ).value< QIcon >().isNull() ) {
QRect prect = QRect( iconLeftEdge, pos + top, ICONSIZE, ICONSIZE );
painter->save();
painter->drawPixmap( prect, index.data( Qt::DecorationRole ).value< QIcon >().pixmap( prect.size() ) );
painter->restore();
}
// from the right edge--config status and online/offline
QRect confRect = QRect( itemRect.width() - ICONSIZE - 2 * PADDING, mid - ICONSIZE / 2 + top, ICONSIZE, ICONSIZE );
if( index.data( SipModel::HasConfig ).toBool() ) {
QStyleOptionToolButton topt;
topt.rect = confRect;
topt.pos = confRect.topLeft();
drawConfigWrench( painter, opt, topt );
}
// draw the online/offline status
int statusIconSize = 18;
int statusX = confRect.left() - 2*PADDING - statusIconSize;
QFont statusF = opt.font;
statusF.setPointSize( statusF.pointSize() - 2 );
QFontMetrics statusFM( statusF );
QPixmap p;
QString statusText;
SipPlugin::ConnectionState state = static_cast< SipPlugin::ConnectionState >( index.data( SipModel::ConnectionStateRole ).toInt() );
if( state == SipPlugin::Connected ) {
p = QPixmap( RESPATH "images/sipplugin-online.png" );
statusText = tr( "Online" );
} else if( state == SipPlugin::Connecting ) {
p = QPixmap( RESPATH "images/sipplugin-offline.png" );
statusText = tr( "Connecting..." );
} else {
p = QPixmap( RESPATH "images/sipplugin-offline.png" );
statusText = tr( "Offline" );
}
p = p.scaled( statusIconSize, statusIconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation );
painter->drawPixmap( statusX, mid - statusIconSize / 2 + top, statusIconSize, statusIconSize, p );
int width = statusFM.width( statusText );
statusX = statusX - PADDING - width;
painter->save();
painter->setFont( statusF );
painter->drawText( QRect( statusX, mid - statusFM.height() / 2 + top, width, statusFM.height() ), statusText );
painter->restore();
// name
painter->save();
QFontMetrics namefm( name );
int nameHeight = namefm.boundingRect( "test" ).height();
// pos will the top-left point of the text rect
pos = mid - ( nameHeight / 2 );
// TODO bound with config icon and offline/online status
width = itemRect.width() - textLeftEdge;
if( !index.data( SipModel::ErrorString ).toString().isEmpty() ) { // error, show that too
QRect errorRect( textLeftEdge, mid + top, width, mid - PADDING + 1 );
QFontMetrics errorFm( error );
QString str = errorFm.elidedText( index.data( SipModel::ErrorString ).toString(), Qt::ElideRight, errorRect.width() );
painter->setFont( error );
painter->drawText( errorRect, str );
pos = mid - errorRect.height() - 2; // move the name rect up
}
QString nameStr = namefm.elidedText( index.data( Qt::DisplayRole ).toString(), Qt::ElideRight, width );
painter->setFont( name );
painter->drawText( QRect( textLeftEdge, pos + top, width, nameHeight + 1 ), nameStr );
painter->restore();
}
}
QRect
SipConfigDelegate::checkRectForIndex( const QStyleOptionViewItem &option, const QModelIndex &idx ) const
{
if( !idx.data( SipModel::FactoryItemRole ).toBool() && !idx.data( SipModel::FactoryRole ).toBool() )
{
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, idx );
int mid = opt.rect.height() / 2;
int pos = ( mid ) - ( ICONSIZE / 2 );
QRect checkRect = QRect( CHECK_LEFT_EDGE, pos + opt.rect.top(), ICONSIZE, ICONSIZE );
return checkRect;
}
return QRect();
}
QRect
SipConfigDelegate::configRectForIndex( const QStyleOptionViewItem& option, const QModelIndex& idx ) const
{
if( !idx.data( SipModel::FactoryItemRole ).toBool() && !idx.data( SipModel::FactoryRole ).toBool() )
{
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, idx );
QRect itemRect = opt.rect;
QRect confRect = QRect( itemRect.width() - ICONSIZE - 2 * PADDING, (opt.rect.height() / 2) - ICONSIZE / 2 + opt.rect.top(), ICONSIZE, ICONSIZE );
return confRect;
}
return QRect();
}
QSize
SipConfigDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
if( index.data( SipModel::FactoryRole ).toBool() || index.data( SipModel::FactoryItemRole ).toBool() ) { // this is the "add new account" row
// enough space for one line of text
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index );
int width = QStyledItemDelegate::sizeHint( option, index ).width();
QFont name = opt.font;
name.setPointSize( name.pointSize() + 1 );
name.setBold( true );
QFontMetrics sfm( name );
return QSize( width, 3 * PADDING + sfm.height() );
} else { // this is an existing account to show
return ConfigDelegateBase::sizeHint( option, index );
}
}
void
SipConfigDelegate::askedForEdit( const QModelIndex& idx )
{
emit openConfig( qobject_cast< SipPlugin* >( idx.data( SipModel::SipPluginData ).value< QObject* >() ) );
}

View File

@ -505,7 +505,7 @@ void
TomahawkApp::initSIP()
{
tDebug() << Q_FUNC_INFO;
foreach ( Tomahawk::Accounts::Account* account, Tomahawk::Accounts::AccountManager::instance()->getAccounts() )
foreach ( Tomahawk::Accounts::Account* account, Tomahawk::Accounts::AccountManager::instance()->accounts() )
{
tDebug() << Q_FUNC_INFO << "testing account with name " << account->accountServiceName();
if ( account->configurationWidget() && account->configuration().isEmpty() )