From ecccf879923966a2a9550f094366c123e123b6a0 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 9 Feb 2012 23:16:18 -0500 Subject: [PATCH] Add multi-account config widget and hook things up --- src/AccountDelegate.cpp | 36 +++-- src/AccountDelegate.h | 2 +- src/AccountFactoryWrapper.cpp | 137 ++++++++++++++++++ src/AccountFactoryWrapper.h | 67 +++++++++ src/AccountFactoryWrapper.ui | 110 ++++++++++++++ src/AccountFactoryWrapperDelegate.cpp | 166 ++++++++++++++++++++++ src/AccountFactoryWrapperDelegate.h | 58 ++++++++ src/CMakeLists.txt | 6 + src/delegateconfigwrapper.h | 30 +++- src/libtomahawk/accounts/AccountModel.cpp | 56 +++++++- src/settingsdialog.cpp | 117 +++++++-------- src/settingsdialog.h | 10 +- 12 files changed, 709 insertions(+), 86 deletions(-) create mode 100644 src/AccountFactoryWrapper.cpp create mode 100644 src/AccountFactoryWrapper.h create mode 100644 src/AccountFactoryWrapper.ui create mode 100644 src/AccountFactoryWrapperDelegate.cpp create mode 100644 src/AccountFactoryWrapperDelegate.h diff --git a/src/AccountDelegate.cpp b/src/AccountDelegate.cpp index 5a2fdc55d..71e76c786 100644 --- a/src/AccountDelegate.cpp +++ b/src/AccountDelegate.cpp @@ -71,8 +71,6 @@ AccountDelegate::AccountDelegate( QObject* parent ) m_defaultCover = m_defaultCover.scaled( ICONSIZE, ICONSIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation ); - m_cachedIcons[ "sipplugin-online" ] = QPixmap( RESPATH "images/sipplugin-online.png" ).scaled( STATUS_ICON_SIZE, STATUS_ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation ); - m_cachedIcons[ "sipplugin-offline" ] = QPixmap( RESPATH "images/sipplugin-offline.png" ).scaled( STATUS_ICON_SIZE, STATUS_ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation ); } @@ -381,9 +379,28 @@ AccountDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QS { m_configPressed = index; - Account* acct = qobject_cast< Account* >( index.data( AccountModel::AccountData ).value< QObject* >() ); - Q_ASSERT( acct ); // Should not be showing a config wrench if there is no account! - emit openConfig( acct ); + const AccountModel::RowType rowType = static_cast< AccountModel::RowType >( index.data( AccountModel::RowTypeRole ).toInt() ); + if ( rowType == AccountModel::TopLevelAccount ) + { + Account* acct = qobject_cast< Account* >( index.data( AccountModel::AccountData ).value< QObject* >() ); + Q_ASSERT( acct ); // Should not be showing a config wrench if there is no account! + + emit openConfig( acct ); + } + else if ( rowType == AccountModel::TopLevelFactory ) + { + AccountFactory* fac = qobject_cast< AccountFactory* >( index.data( AccountModel::AccountData ).value< QObject* >() ); + Q_ASSERT( fac ); // Should not be showing a config wrench if there is no account! + emit openConfig( fac ); + } + else if ( rowType == AccountModel::UniqueFactory ) + { + const QList< Account* > accts = index.data( AccountModel::ChildrenOfFactoryRole ).value< QList< Tomahawk::Accounts::Account* > >(); + + Q_ASSERT( !accts.isEmpty() ); // If there's no account, why is there a config widget for this factory? + Q_ASSERT( accts.size() == 1 ); + emit openConfig( accts.first() ); + } return true; } } else if ( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick ) @@ -395,13 +412,7 @@ AccountDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QS m_configPressed = QModelIndex(); const AccountModel::ItemState state = static_cast< AccountModel::ItemState >( index.data( AccountModel::StateRole ).toInt() ); - const bool canCheck = ( state == AccountModel::Installed || state == AccountModel::ShippedWithTomahawk ); - if ( !canCheck ) - return false; - // A few options. First, could be the checkbox on/off. - // second, could be the install/uninstall/create button - // third could be the config button if ( checkRectForIndex( option, index ).contains( me->pos() ) ) { // Check box for this row @@ -525,7 +536,6 @@ AccountDelegate::drawStatus( QPainter* painter, const QPointF& rightTopEdge, Acc painter->drawPixmap( connectIconRect, p ); int leftEdge = connectIconRect.x(); - // For now, disable text next to icon if ( drawText ) { int width = painter->fontMetrics().width( statusText ); @@ -557,7 +567,7 @@ AccountDelegate::drawConfigWrench ( QPainter* painter, QStyleOptionViewItemV4& o // draw it the same size as the check belox topt.font = opt.font; topt.icon = QIcon( RESPATH "images/configure.png" ); - topt.iconSize = QSize( 16, 16 ); + topt.iconSize = QSize( 14, 14 ); topt.subControls = QStyle::SC_ToolButton; topt.activeSubControls = QStyle::SC_None; topt.features = QStyleOptionToolButton::None; diff --git a/src/AccountDelegate.h b/src/AccountDelegate.h index 6a1378403..4cadd38c8 100644 --- a/src/AccountDelegate.h +++ b/src/AccountDelegate.h @@ -44,6 +44,7 @@ protected: signals: void update( const QModelIndex& idx ); void openConfig( Tomahawk::Accounts::Account* ); + void openConfig( Tomahawk::Accounts::AccountFactory* ); private: void drawRoundedButton( QPainter* painter, const QRect& buttonRect ) const; @@ -56,7 +57,6 @@ private: QRect checkRectForIndex( const QStyleOptionViewItem &option, const QModelIndex &idx ) const; - QMap< QString, QPixmap > m_cachedIcons; QPixmap m_offlineIcon, m_onlineIcon, m_defaultCover, m_onHoverStar, m_ratingStarPositive, m_ratingStarNegative, m_removeIcon; int m_hoveringOver; QPersistentModelIndex m_hoveringItem, m_configPressed; diff --git a/src/AccountFactoryWrapper.cpp b/src/AccountFactoryWrapper.cpp new file mode 100644 index 000000000..86e824512 --- /dev/null +++ b/src/AccountFactoryWrapper.cpp @@ -0,0 +1,137 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk 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. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#include "AccountFactoryWrapper.h" + +#include "accounts/Account.h" +#include +#include "AccountFactoryWrapperDelegate.h" +#include "delegateconfigwrapper.h" +#include "ui_AccountFactoryWrapper.h" + +using namespace Tomahawk::Accounts; +AccountFactoryWrapper::AccountFactoryWrapper( AccountFactory* factory, QWidget* parent ) + : QDialog( parent, Qt::Sheet ) + , m_factory( factory ) + , m_ui( new Ui_AccountFactoryWrapper ) + , m_createAccount( false ) +{ + m_ui->setupUi( this ); + + setWindowTitle( factory->prettyName() ); + + m_ui->factoryIcon->setPixmap( factory->icon() ); + m_ui->factoryDescription->setText( factory->description() ); + + m_addButton = m_ui->buttonBox->addButton( tr( "Add Account" ), QDialogButtonBox::ActionRole ); + + AccountFactoryWrapperDelegate* del = new AccountFactoryWrapperDelegate( m_ui->accountsList ); + m_ui->accountsList->setItemDelegate( del ); + + connect( del, SIGNAL( openConfig( Tomahawk::Accounts::Account* ) ), this, SLOT( openAccountConfig( Tomahawk::Accounts::Account* ) ) ); + connect( del, SIGNAL( removeAccount( Tomahawk::Accounts::Account* ) ), this, SLOT( removeAccount( Tomahawk::Accounts::Account* ) ) ); + + load(); + + + connect( m_ui->buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) ); + connect( m_ui->buttonBox, SIGNAL( accepted() ), this, SLOT( accept() ) ); + connect( m_ui->buttonBox, SIGNAL( clicked( QAbstractButton*) ), this, SLOT( buttonClicked() ) ); +#ifdef Q_OS_MAC + setContentsMargins( 0, 0, 0, 0 ); + m_ui->verticalLayout->setSpacing( 4 ); +#endif +} + +void +AccountFactoryWrapper::load() +{ + m_ui->accountsList->clear(); + foreach ( Account* acc, AccountManager::instance()->accounts() ) + { + if ( AccountManager::instance()->factoryForAccount( acc ) == m_factory ) + { + QTreeWidgetItem* item = new QTreeWidgetItem( m_ui->accountsList ); + item->setData( 0, AccountRole, QVariant::fromValue< QObject *>( acc ) ); + } + } + + const int height = m_ui->accountsList->model()->rowCount( QModelIndex() ) * ACCOUNT_ROW_HEIGHT + 7; + m_ui->accountsList->setFixedHeight( height ); +} + + +void +AccountFactoryWrapper::openAccountConfig( Account* account ) +{ + if( account->configurationWidget() ) + { +#ifndef Q_WS_MAC + DelegateConfigWrapper dialog( account->configurationWidget(), QString("%1 Configuration" ).arg( account->accountFriendlyName() ), this ); + QWeakPointer< DelegateConfigWrapper > watcher( &dialog ); + int ret = dialog.exec(); + if( !watcher.isNull() && ret == QDialog::Accepted ) + { + // send changed config to resolver + account->saveConfig(); + } +#else + // on osx a sheet needs to be non-modal + DelegateConfigWrapper* dialog = new DelegateConfigWrapper( account->configurationWidget(), QString("%1 Configuration" ).arg( account->accountFriendlyName() ), this, Qt::Sheet ); + dialog->setProperty( "accountplugin", QVariant::fromValue< QObject* >( account ) ); + connect( dialog, SIGNAL( finished( int ) ), this, SLOT( accountConfigClosed( int ) ) ); + + dialog->show(); +#endif + } +} + + +void +AccountFactoryWrapper::accountConfigClosed( int value ) +{ + if( value == QDialog::Accepted ) + { + DelegateConfigWrapper* dialog = qobject_cast< DelegateConfigWrapper* >( sender() ); + Account* account = qobject_cast< Account* >( dialog->property( "accountplugin" ).value< QObject* >() ); + account->saveConfig(); + } +} + +void +AccountFactoryWrapper::removeAccount( Tomahawk::Accounts::Account* acct ) +{ + AccountManager::instance()->removeAccount( acct ); + + load(); +} + +void +AccountFactoryWrapper::buttonClicked( QAbstractButton* button ) +{ + if ( button == m_addButton ) + { + m_createAccount = true; + emit createAccount( m_factory ); + accept(); + return; + } + else + reject(); +} + diff --git a/src/AccountFactoryWrapper.h b/src/AccountFactoryWrapper.h new file mode 100644 index 000000000..62fa9a23d --- /dev/null +++ b/src/AccountFactoryWrapper.h @@ -0,0 +1,67 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk 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. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#ifndef ACCOUNTFACTORYWRAPPER_H +#define ACCOUNTFACTORYWRAPPER_H + +#include + +class QAbstractButton; +namespace Tomahawk { +namespace Accounts { + class AccountFactory; +class Account; +} +} + +class Ui_AccountFactoryWrapper; + +// class AccountFactoryWrapper_ +class AccountFactoryWrapper : public QDialog +{ + Q_OBJECT +public: + enum ExtraRoles { + AccountRole = Qt::UserRole + 140 + }; + + explicit AccountFactoryWrapper( Tomahawk::Accounts::AccountFactory* factory, QWidget* parent = 0 ); + + bool doCreateAccount() const { return m_createAccount; } + +signals: + void createAccount( Tomahawk::Accounts::AccountFactory* factory ); + +public slots: + void openAccountConfig( Tomahawk::Accounts::Account* ); + void accountConfigClosed( int value ); + void removeAccount( Tomahawk::Accounts::Account* ); + +private slots: + void buttonClicked( QAbstractButton* ); + +private: + void load(); + + Tomahawk::Accounts::AccountFactory* m_factory; + Ui_AccountFactoryWrapper* m_ui; + QPushButton* m_addButton; + bool m_createAccount; +}; + +#endif // ACCOUNTFACTORYWRAPPER_H diff --git a/src/AccountFactoryWrapper.ui b/src/AccountFactoryWrapper.ui new file mode 100644 index 000000000..9a119015e --- /dev/null +++ b/src/AccountFactoryWrapper.ui @@ -0,0 +1,110 @@ + + + AccountFactoryWrapper + + + + 0 + 0 + 507 + 298 + + + + Dialog + + + + + + + + + Qt::AlignCenter + + + + + + + Description goes here + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + false + + + QAbstractItemView::NoSelection + + + QAbstractItemView::ScrollPerItem + + + false + + + true + + + false + + + + 1 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + diff --git a/src/AccountFactoryWrapperDelegate.cpp b/src/AccountFactoryWrapperDelegate.cpp new file mode 100644 index 000000000..fcd89701b --- /dev/null +++ b/src/AccountFactoryWrapperDelegate.cpp @@ -0,0 +1,166 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk 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. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#include "AccountFactoryWrapperDelegate.h" +#include "accounts/Account.h" +#include "AccountFactoryWrapper.h" +#include "utils/tomahawkutils.h" + +#include +#include +#include + +using namespace Tomahawk::Accounts; + +#define ICON_SIZE 15 +#define CONFIG_WRENCH_SIZE 20 +#define PADDING 4 + +AccountFactoryWrapperDelegate::AccountFactoryWrapperDelegate( QObject* parent ) + : QStyledItemDelegate( parent ) +{ + m_removePixmap.load( RESPATH "images/list-remove.png" ); + m_onlineIcon.load( RESPATH "images/sipplugin-online.png" ); + m_offlineIcon.load( RESPATH "images/sipplugin-offline.png" ); + + m_removePixmap = m_removePixmap.scaled( ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation ); + m_onlineIcon = m_onlineIcon.scaled( ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation ); + m_offlineIcon = m_offlineIcon.scaled( ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation ); + + m_configIcon.addFile( RESPATH "images/configure.png", QSize( CONFIG_WRENCH_SIZE - 8, CONFIG_WRENCH_SIZE - 8 ) ); +} + +void +AccountFactoryWrapperDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + QStyleOptionViewItemV4 opt = option; + initStyleOption( &opt, index ); + + const int center = opt.rect.height() / 2 + opt.rect.top(); + const int topIcon = center - ICON_SIZE/2; + + // draw the background + const QWidget* w = opt.widget; + QStyle* style = w ? w->style() : QApplication::style(); + style->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, w ); + + Account* acc = qobject_cast< Account* >( index.data( AccountFactoryWrapper::AccountRole ).value< QObject* >() ); + Q_ASSERT( acc ); + + // name on left + painter->drawText( opt.rect.adjusted( PADDING, PADDING, -PADDING, -PADDING ), Qt::AlignLeft | Qt::AlignVCenter, acc->accountFriendlyName() ); + + // remove, config, status on right + const QRect pmRect( opt.rect.right() - PADDING - m_removePixmap.width(), topIcon, ICON_SIZE, ICON_SIZE ); + painter->drawPixmap( pmRect, m_removePixmap ); + m_cachedButtonRects[ index ] = pmRect; + + const QRect confRect( pmRect.left() - PADDING - CONFIG_WRENCH_SIZE, center - CONFIG_WRENCH_SIZE/2, CONFIG_WRENCH_SIZE, CONFIG_WRENCH_SIZE ); + + QStyleOptionToolButton topt; + topt.rect = confRect; + topt.pos = confRect.topLeft(); + topt.font = opt.font; + topt.icon = m_configIcon; + topt.iconSize = QSize( CONFIG_WRENCH_SIZE - 8, CONFIG_WRENCH_SIZE - 8 ); + topt.subControls = QStyle::SC_ToolButton; + topt.activeSubControls = QStyle::SC_None; + topt.features = QStyleOptionToolButton::None; + bool pressed = ( m_configPressed == opt.index ); + topt.state = pressed ? QStyle::State_On : QStyle::State_Raised; + if( opt.state & QStyle::State_MouseOver || pressed ) + topt.state |= QStyle::State_HasFocus; + style->drawComplexControl( QStyle::CC_ToolButton, &topt, painter, w ); + m_cachedConfigRects[ index ] = confRect; + + QPixmap p; + QString statusText; + Account::ConnectionState state = acc->connectionState(); + if ( state == Account::Connected ) + { + p = m_onlineIcon; + statusText = tr( "Online" ); + } + else if ( state == Account::Connecting ) + { + p = m_offlineIcon; + statusText = tr( "Connecting..." ); + } + else + { + p = m_offlineIcon; + statusText = tr( "Offline" ); + } + + const QRect connectIconRect( confRect.left() - PADDING - ICON_SIZE, topIcon, ICON_SIZE, ICON_SIZE ); + painter->drawPixmap( connectIconRect, p ); + + int width = painter->fontMetrics().width( statusText ); + painter->drawText( QRect( connectIconRect.left() - PADDING - width, center - painter->fontMetrics().height()/2, width, painter->fontMetrics().height() ), statusText ); + +} + +QSize +AccountFactoryWrapperDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const +{ + return QSize( 200, ACCOUNT_ROW_HEIGHT ); +} + + +bool +AccountFactoryWrapperDelegate::editorEvent( QEvent* event, QAbstractItemModel*, const QStyleOptionViewItem&, const QModelIndex& index ) +{ + if ( event->type() != QEvent::MouseButtonPress && + event->type() != QEvent::MouseButtonRelease && + event->type() != QEvent::MouseButtonDblClick && + event->type() != QEvent::MouseMove ) + return false; + + if ( event->type() == QEvent::MouseButtonPress ) + { + // Show the config wrench as depressed on click + QMouseEvent* me = static_cast< QMouseEvent* >( event ); + if ( me->button() == Qt::LeftButton && m_cachedConfigRects.contains( index ) && m_cachedConfigRects[ index ].contains( me->pos() ) ) + { + m_configPressed = index; + Account* acct = qobject_cast< Account* >( index.data( AccountFactoryWrapper::AccountRole ).value< QObject* >() ); + Q_ASSERT( acct ); // Should not be showing a config wrench if there is no account! + + emit openConfig( acct ); + + return true; + } + } else if ( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick ) + { + QMouseEvent* me = static_cast< QMouseEvent* >( event ); + if ( m_configPressed.isValid() ) + emit update( m_configPressed ); + + m_configPressed = QModelIndex(); + + if ( m_cachedButtonRects.contains( index ) && m_cachedButtonRects[ index ].contains( me->pos() ) ) + { + Account* acct = qobject_cast< Account* >( index.data( AccountFactoryWrapper::AccountRole ).value< QObject* >() ); + emit removeAccount( acct ); + + return true; + } + } + return false; +} + diff --git a/src/AccountFactoryWrapperDelegate.h b/src/AccountFactoryWrapperDelegate.h new file mode 100644 index 000000000..699ed22f8 --- /dev/null +++ b/src/AccountFactoryWrapperDelegate.h @@ -0,0 +1,58 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2012, Leo Franchi + * + * Tomahawk 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. + * + * Tomahawk 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 Tomahawk. If not, see . + */ + +#ifndef ACCOUNTFACTORYWRAPPERDELEGATE_H +#define ACCOUNTFACTORYWRAPPERDELEGATE_H + +#include + +#define ACCOUNT_ROW_HEIGHT 20 + +namespace Tomahawk { +namespace Accounts { +class Account; +} +} + +class AccountFactoryWrapperDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + explicit AccountFactoryWrapperDelegate( QObject* parent = 0 ); + + virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; + + virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const; + virtual bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index); + +signals: + void update( const QModelIndex& ); + + void openConfig( Tomahawk::Accounts::Account* ); + void removeAccount( Tomahawk::Accounts::Account* ); + +private: + QPixmap m_removePixmap, m_offlineIcon, m_onlineIcon; + QIcon m_configIcon; + QModelIndex m_configPressed; + + mutable QHash< QPersistentModelIndex, QRect > m_cachedButtonRects; + mutable QHash< QPersistentModelIndex, QRect > m_cachedConfigRects; +}; + +#endif // ACCOUNTFACTORYWRAPPERDELEGATE_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 72de137ed..ee8ac9b0b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -78,6 +78,8 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} settingslistdelegate.cpp tomahawkwindow.cpp LoadXSPFDialog.cpp + AccountFactoryWrapper.cpp + AccountFactoryWrapperDelegate.cpp ) SET( tomahawkHeaders ${tomahawkHeaders} @@ -121,6 +123,8 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui} delegateconfigwrapper.h tomahawkwindow.h LoadXSPFDialog.h + AccountFactoryWrapper.h + AccountFactoryWrapperDelegate.h ) SET( tomahawkUI ${tomahawkUI} @@ -132,6 +136,8 @@ SET( tomahawkUI ${tomahawkUI} audiocontrols.ui LoadXSPFDialog.ui + + AccountFactoryWrapper.ui ) INCLUDE_DIRECTORIES( diff --git a/src/delegateconfigwrapper.h b/src/delegateconfigwrapper.h index 5e71bdcac..4ff15313b 100644 --- a/src/delegateconfigwrapper.h +++ b/src/delegateconfigwrapper.h @@ -28,7 +28,7 @@ class DelegateConfigWrapper : public QDialog { Q_OBJECT public: - DelegateConfigWrapper( QWidget* conf, const QString& title, QWidget* parent, Qt::WindowFlags flags = 0 ) : QDialog( parent, flags ), m_widget( conf ) + DelegateConfigWrapper( QWidget* conf, const QString& title, QWidget* parent, Qt::WindowFlags flags = 0 ) : QDialog( parent, flags ), m_widget( conf ), m_deleted( false ) { m_widget->setWindowFlags( Qt::Sheet ); #ifdef Q_WS_MAC @@ -39,11 +39,11 @@ public: v->setContentsMargins( 0, 0, 0, 0 ); v->addWidget( m_widget ); - QDialogButtonBox* buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this ); - m_okButton = buttons->button( QDialogButtonBox::Ok ); - connect( buttons, SIGNAL( clicked( QAbstractButton*) ), this, SLOT( closed( QAbstractButton* ) ) ); + m_buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this ); + m_okButton = m_buttons->button( QDialogButtonBox::Ok ); + connect( m_buttons, SIGNAL( clicked( QAbstractButton*) ), this, SLOT( closed( QAbstractButton* ) ) ); connect( this, SIGNAL( rejected() ), this, SLOT( rejected() ) ); - v->addWidget( buttons ); + v->addWidget( m_buttons ); setLayout( v ); @@ -62,6 +62,14 @@ public: ~DelegateConfigWrapper() {} + void setShowDelete( bool del ) + { + if ( del ) + m_deleteButton = m_buttons->addButton( tr( "Delete Account" ), QDialogButtonBox::DestructiveRole ); + } + + bool deleted() const { return m_deleted; } + public slots: void toggleOkButton( bool dataError ) { @@ -78,6 +86,11 @@ public slots: QDialogButtonBox* buttons = qobject_cast< QDialogButtonBox* >( sender() ); if( buttons->standardButton( b ) == QDialogButtonBox::Ok ) done( QDialog::Accepted ); + else if ( b == m_deleteButton ) + { + m_deleted = true; + emit deleted(); + } else done( QDialog::Rejected ); } @@ -100,9 +113,14 @@ public slots: show(); } +signals: + void closedWithDelete(); + private: + QDialogButtonBox* m_buttons; QWidget* m_widget; - QPushButton* m_okButton; + QPushButton *m_okButton, *m_deleteButton; + bool m_deleted; }; #endif diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index e98c93f38..44a16919b 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -72,6 +72,7 @@ AccountModel::loadData() connect ( AccountManager::instance(), SIGNAL( removed( Tomahawk::Accounts::Account* ) ), this, SLOT( accountRemoved( Tomahawk::Accounts::Account* ) ) ); connect ( AccountManager::instance(), SIGNAL( stateChanged( Account* ,Accounts::Account::ConnectionState ) ), this, SLOT( accountStateChanged( Account*, Accounts::Account::ConnectionState ) ) ); + connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( atticaInstalled( QString ) ) ); } @@ -175,7 +176,12 @@ AccountModel::data( const QModelIndex& index, int role ) const case AccountModelNode::UniqueFactoryType: { if ( role == RowTypeRole ) - return UniqueFactory; + { + if ( node->type == AccountModelNode::ManualResolverType ) + return TopLevelAccount; + else + return UniqueFactory; + } Account* acct = 0; if ( node->type == AccountModelNode::ManualResolverType ) @@ -270,7 +276,6 @@ AccountModel::setData( const QModelIndex& index, const QVariant& value, int role } else { - connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( atticaInstalled( QString ) ) ); m_waitingForAtticaInstall.insert( resolver.id() ); AtticaManager::instance()->installResolver( resolver ); @@ -461,7 +466,54 @@ AccountModel::accountRemoved( Account* account ) void AccountModel::atticaInstalled( const QString& atticaId ) { + if ( !m_waitingForAtticaInstall.contains( atticaId ) ) + return; + m_waitingForAtticaInstall.remove( atticaId ); + + // find associated Account*, set on to the saved resolver, and update state + AccountModelNode* node = 0; + AtticaResolverAccount* acct = 0; + + foreach ( AccountModelNode* n, m_accounts ) + { + if ( n->type == AccountModelNode::AtticaType && + n->atticaContent.id() == atticaId ) + { + node = n; + break; + } + } + + if ( !node ) + { + Q_ASSERT( false ); + return; // Couldn't find it?? + } + + foreach ( Account* acc, AccountManager::instance()->accounts( ResolverType ) ) + { + if ( AtticaResolverAccount* ra = qobject_cast< AtticaResolverAccount* >( acc ) ) + { + if ( ra->atticaId() == atticaId ) + { + acct = ra; + break; + } + } + } + + if ( !acct ) + { + qWarning() << "Got installed attica resolver but couldnt' find a resolver account for it??"; + return; + } + + AccountManager::instance()->enableAccount( acct ); + + node->atticaAccount = acct; + const QModelIndex idx = index( m_accounts.indexOf( node ), 0, QModelIndex() ); + emit dataChanged( idx, idx ); } diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index d015aabd7..1e089eac4 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -53,6 +53,7 @@ #include "accounts/Account.h" #include "accounts/AccountManager.h" #include "utils/logger.h" +#include "AccountFactoryWrapper.h" #include "ui_proxydialog.h" #include "ui_stackedsettingsdialog.h" @@ -105,8 +106,10 @@ SettingsDialog::SettingsDialog( QWidget *parent ) ui->accountsView->setItemDelegate( accountDelegate ); ui->accountsView->setContextMenuPolicy( Qt::CustomContextMenu ); ui->accountsView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); + ui->accountsView->setMouseTracking( true ); connect( accountDelegate, SIGNAL( openConfig( Tomahawk::Accounts::Account* ) ), this, SLOT( openAccountConfig( Tomahawk::Accounts::Account* ) ) ); + connect( accountDelegate, SIGNAL( openConfig( Tomahawk::Accounts::AccountFactory* ) ), this, SLOT( openAccountFactoryConfig( Tomahawk::Accounts::AccountFactory* ) ) ); connect( accountDelegate, SIGNAL( update( QModelIndex ) ), ui->accountsView, SLOT( update( QModelIndex ) ) ); connect( ui->accountsView, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( accountContextMenuRequest( QPoint ) ) ); @@ -425,20 +428,6 @@ SettingsDialog::onLastFmFinished() } -void -SettingsDialog::accountInstalled(Account* account) -{ -// m_resolversModel->atticaResolverInstalled( resolverId ); -} - - -void -SettingsDialog::accountUninstalled(const QString& acct) -{ -// m_resolversModel->removeResolver( AtticaManager::instance()->pathFromId( resolverId ) ); -} - - void SettingsDialog::accountsSelectionChanged() { @@ -454,15 +443,20 @@ SettingsDialog::accountsSelectionChanged() void -SettingsDialog::openAccountConfig( Account* account ) +SettingsDialog::openAccountConfig( Account* account, bool showDelete ) { if( account->configurationWidget() ) { #ifndef Q_WS_MAC DelegateConfigWrapper dialog( account->configurationWidget(), QString("%1 Configuration" ).arg( account->accountFriendlyName() ), this ); + dialog.setShowDelete( showDelete ); QWeakPointer< DelegateConfigWrapper > watcher( &dialog ); int ret = dialog.exec(); - if( !watcher.isNull() && ret == QDialog::Accepted ) + if ( !watcher.isNull() && dialog.deleted() ) + { + AccountManager::instance()->removeAccount( account ); + } + else if( !watcher.isNull() && ret == QDialog::Accepted ) { // send changed config to resolver account->saveConfig(); @@ -470,8 +464,10 @@ SettingsDialog::openAccountConfig( Account* account ) #else // on osx a sheet needs to be non-modal DelegateConfigWrapper* dialog = new DelegateConfigWrapper( account->configurationWidget(), QString("%1 Configuration" ).arg( account->accountFriendlyName() ), this, Qt::Sheet ); + dialog->setShowDelete( showDelete ); dialog->setProperty( "accountplugin", QVariant::fromValue< QObject* >( account ) ); connect( dialog, SIGNAL( finished( int ) ), this, SLOT( accountConfigClosed( int ) ) ); + connect( dialog, SIGNAL( closedWithDelete() ), this, SLOT( accountConfigDelete() ) ); dialog->show(); #endif @@ -491,6 +487,54 @@ SettingsDialog::accountConfigClosed( int value ) } +void +SettingsDialog::accountConfigDelete() +{ + DelegateConfigWrapper* dialog = qobject_cast< DelegateConfigWrapper* >( sender() ); + Account* account = qobject_cast< Account* >( dialog->property( "accountplugin" ).value< QObject* >() ); + Q_ASSERT( account ); + AccountManager::instance()->removeAccount( account ); + + sender()->deleteLater(); +} + + +void +SettingsDialog::openAccountFactoryConfig( AccountFactory* factory ) +{ + QList< Account* > accts; + foreach ( Account* acct, AccountManager::instance()->accounts() ) + { + if ( AccountManager::instance()->factoryForAccount( acct ) == factory ) + accts << acct; + if ( accts.size() > 1 ) + break; + } + Q_ASSERT( accts.size() > 0 ); // Shouldn't have a config wrench if there are no accounts! + if ( accts.size() == 1 ) + { + // If there's just one, open the config directly w/ the delete button. Otherwise open the multi dialog + openAccountConfig( accts.first() ); + return; + } + +#ifndef Q_WS_MAC + AccountFactoryWrapper dialog( factory, this ); + QWeakPointer< AccountFactoryWrapper > watcher( &dialog ); + + int ret = dialog.exec(); + if ( !watcher.isNull() && dialog.doCreateAccount() ) + createAccountFromFactory( factory ); +#else + // on osx a sheet needs to be non-modal + AccountFactoryWrapper* dialog = new AccountFactoryWrapper( factory, this ); + connect( dialog, SIGNAL( createAccount( Tomahawk::Accounts::AccountFactory ) ), this, SLOT( createAccountFromFactory( Tomahawk::Accounts::AccountFactory* ) ) ); + + dialog->show(); +#endif +} + + void SettingsDialog::createAccountFromFactory( AccountFactory* factory ) { @@ -568,47 +612,6 @@ SettingsDialog::handleAccountAdded( Account* account, bool added ) } -void -SettingsDialog::accountContextMenuRequest( const QPoint& p ) -{ - QModelIndex idx = ui->accountsView->indexAt( p ); - // if it's an account, allow to delete - if( idx.isValid() ) - { -// QList< QAction* > acts; -// acts << new QAction( tr( "Delete Service" ), this ); -// acts.first()->setProperty( "accountplugin", idx.data( AccountModel::AccountData ) ); -// connect( acts.first(), SIGNAL( triggered( bool ) ), this, SLOT( onAccountRowDeleted( bool ) ) ); -// QMenu::exec( acts, ui->accountsView->mapToGlobal( p ) ); - } -} - - -void -SettingsDialog::onAccountRowDeleted( bool ) -{ - Account* account = qobject_cast< Account* >( qobject_cast< QAction* >( sender() )->property( "accountplugin" ).value< QObject* >() ); - - AccountManager::instance()->removeAccount( account ); -} - - -void -SettingsDialog::accountDeleted( bool ) -{ - QModelIndexList indexes = ui->accountsView->selectionModel()->selectedIndexes(); - // if it's an account, allow to delete - foreach( const QModelIndex& idx, indexes ) - { - if( idx.isValid() ) - { -// Account* account = qobject_cast< Account* >( idx.data( AccountModel::AccountData ).value< QObject* >() ); -// AccountManager::instance()->removeAccount( account ); - } - } -} - - void SettingsDialog::requiresRestart() { diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 5f8300171..6be871778 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -88,18 +88,14 @@ private slots: void testLastFmLogin(); void onLastFmFinished(); - void openAccountConfig( Tomahawk::Accounts::Account* ); void createAccountFromFactory( Tomahawk::Accounts::AccountFactory* ); - void accountContextMenuRequest( const QPoint& ); - void accountDeleted( bool ); - void onAccountRowDeleted( bool ); void accountsSelectionChanged(); - void accountInstalled( Tomahawk::Accounts::Account* account ); - void accountUninstalled( const QString& acct ); - + void openAccountConfig( Tomahawk::Accounts::Account*, bool showDelete = false ); + void openAccountFactoryConfig( Tomahawk::Accounts::AccountFactory* ); void accountConfigClosed( int value ); + void accountConfigDelete(); void accountCreateConfigClosed( int value ); void updateScanOptionsView();