diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6466f60e7..a5e859bf4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/accountdelegate.cpp b/src/accountdelegate.cpp new file mode 100644 index 000000000..e2de7bbc1 --- /dev/null +++ b/src/accountdelegate.cpp @@ -0,0 +1,235 @@ +/* + Copyright (C) 2011 Leo Franchi + + 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 . +*/ + + +#include "accountdelegate.h" + +#include +#include + +#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* >() ) ); +} + + diff --git a/src/sipconfigdelegate.h b/src/accountdelegate.h similarity index 80% rename from src/sipconfigdelegate.h rename to src/accountdelegate.h index cccc82a61..e1fba2092 100644 --- a/src/sipconfigdelegate.h +++ b/src/accountdelegate.h @@ -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 extraCheckRoles() const { return QList() << (int)AccountModel::BasicCapabilityRole; } private slots: void askedForEdit( const QModelIndex& idx ); signals: - void sipFactoryClicked( SipPluginFactory* ); - void openConfig( SipPlugin* ); + void openConfig( Account* ); }; +} +} + #endif // SIPCONFIGDELEGATE_H diff --git a/src/configdelegatebase.cpp b/src/configdelegatebase.cpp index ce6f2baae..bdf826bfc 100644 --- a/src/configdelegatebase.cpp +++ b/src/configdelegatebase.cpp @@ -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 roles = QList() << (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 ); diff --git a/src/configdelegatebase.h b/src/configdelegatebase.h index d86baad1a..929467a00 100644 --- a/src/configdelegatebase.h +++ b/src/configdelegatebase.h @@ -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 extraCheckRoles() const { return QList(); } signals: void configPressed( const QModelIndex& idx ); diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 9be5e79e7..72e56e0d2 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -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 diff --git a/src/libtomahawk/accounts/accountmanager.cpp b/src/libtomahawk/accounts/accountmanager.cpp index b340ec4ab..9e33b782c 100644 --- a/src/libtomahawk/accounts/accountmanager.cpp +++ b/src/libtomahawk/accounts/accountmanager.cpp @@ -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 ); } diff --git a/src/libtomahawk/accounts/accountmanager.h b/src/libtomahawk/accounts/accountmanager.h index 8020c5759..3cb914042 100644 --- a/src/libtomahawk/accounts/accountmanager.h +++ b/src/libtomahawk/accounts/accountmanager.h @@ -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 \ No newline at end of file +#endif diff --git a/src/libtomahawk/accounts/accountmodel.cpp b/src/libtomahawk/accounts/accountmodel.cpp new file mode 100644 index 000000000..e4254a1c1 --- /dev/null +++ b/src/libtomahawk/accounts/accountmodel.cpp @@ -0,0 +1,155 @@ +/* + Copyright (C) 2011 Leo Franchi + + 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 . +*/ + + +#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; + } + } +} + diff --git a/src/libtomahawk/sip/SipModel.h b/src/libtomahawk/accounts/accountmodel.h similarity index 56% rename from src/libtomahawk/sip/SipModel.h rename to src/libtomahawk/accounts/accountmodel.h index 7f4901032..9f02363d2 100644 --- a/src/libtomahawk/sip/SipModel.h +++ b/src/libtomahawk/accounts/accountmodel.h @@ -1,5 +1,4 @@ /* - Copyright (C) 2011 Leo Franchi 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 #include -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 diff --git a/src/libtomahawk/sip/SipHandler.cpp b/src/libtomahawk/sip/SipHandler.cpp index 5c9c4d496..7254eb229 100644 --- a/src/libtomahawk/sip/SipHandler.cpp +++ b/src/libtomahawk/sip/SipHandler.cpp @@ -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(); diff --git a/src/libtomahawk/sip/SipModel.cpp b/src/libtomahawk/sip/SipModel.cpp deleted file mode 100644 index 093d81c88..000000000 --- a/src/libtomahawk/sip/SipModel.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - Copyright (C) 2011 Leo Franchi - - 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 . -*/ - - -#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 ); -} - diff --git a/src/sipconfigdelegate.cpp b/src/sipconfigdelegate.cpp deleted file mode 100644 index 20cfcb891..000000000 --- a/src/sipconfigdelegate.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/* - Copyright (C) 2011 Leo Franchi - - 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 . -*/ - - -#include "sipconfigdelegate.h" - -#include -#include - -#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* >() ) ); -} - - diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 6e48af576..18194dff8 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -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() )